1
0
Fork 0

Add DTMF detection via telephone-event payload

This commit is contained in:
Andreas Eversberg 2021-02-27 12:07:32 +01:00
parent 2017066db5
commit d5face6404
4 changed files with 164 additions and 25 deletions

View File

@ -127,6 +127,12 @@ void receive_originator(struct osmo_cc_session_codec *codec, uint16_t __attribut
len = len / 2;
sample_t samples[len];
if (codec->decoder == decode_te) {
struct telephone_event *te = (struct telephone_event *)data;
telephone_event(relation, te);
return;
}
/* convert int16 to samples */
int16_to_samples(samples, (int16_t *)data, len);
@ -169,6 +175,11 @@ void receive_terminator(struct osmo_cc_session_codec *codec, uint16_t __attribut
len = len / 2;
sample_t samples[len];
if (codec->decoder == decode_te) {
PDEBUG(DROUTER, DEBUG_NOTICE, "Ignoring received telephony-events from terminator.\n");
return;
}
int16_to_samples(samples, (int16_t *)data, len);
/* forward to originator, if not a forking call */
@ -284,3 +295,29 @@ void decode_l16(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len
*dst_len = len * 2;
}
void encode_te(uint8_t __attribute__((unused)) *src_data, int __attribute__((unused)) src_len, uint8_t **dst_data, int *dst_len)
{
/* FIXME: TBD... */
*dst_data = NULL;
*dst_len = 0;
}
void decode_te(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len)
{
uint8_t *src = src_data;
struct telephone_event *te;
if (src_len < 4)
return;
te = calloc(1, sizeof(*te));
if (!te)
return;
te->event = src[0];
te->e = src[1] >> 7;
te->r = (src[1] >> 6) & 0x1;
te->volume = src[1] & 0x3f;
te->duration = (src[2] << 16) | src[3];
*dst_data = (uint8_t *)te;
*dst_len = sizeof(*te);
}

View File

@ -1,6 +1,10 @@
void receive_originator(struct osmo_cc_session_codec *codec, uint16_t sequence_number, uint32_t timestamp, uint8_t *data, int len);
void receive_terminator(struct osmo_cc_session_codec *codec, uint16_t sequence_number, uint32_t timestamp, uint8_t *data, int len);
void call_media_handle(void);
void call_clock(int len);
void encode_l16(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len);
void decode_l16(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len);
void encode_te(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len);
void decode_te(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len);

View File

@ -81,10 +81,11 @@ struct timer status_timer;
static osmo_cc_endpoint_t *cc_ep;
static const char *routing_script, *routing_shell;
static struct osmo_cc_helper_audio_codecs codecs[] = {
// { "L16", 8000, 1, encode_l16, decode_l16 }, FIXME: make codecs selectable, if more codecs are supported in the future
static struct osmo_cc_helper_audio_codecs codecs_def[] = {
{ "PCMA", 8000, 1, g711_encode_alaw, g711_decode_alaw },
{ "PCMU", 8000, 1, g711_encode_ulaw, g711_decode_ulaw },
{ "telephone-event", 8000, 1, encode_te, decode_te },
{ "L16", 8000, 1, encode_l16, decode_l16 },
{ NULL, 0, 0, NULL, NULL},
};
@ -386,7 +387,7 @@ static void proxy_send_sdp_answer(call_relation_t *relation, osmo_cc_msg_t *msg)
// if (!relation->codec_negotiated || msg->type == OSMO_CC_MSG_SETUP_CNF) { gibt einen crash, da codec vor der antwort schon gesetzt ist. warum sollten wir nach einer antwort denn nochmal den codec schicken?
if (!relation->codec_negotiated) {
sdp = osmo_cc_helper_audio_accept(relation, codecs, receive_originator, relation->call->setup_msg, &relation->cc_session, &relation->codec, 0);
sdp = osmo_cc_helper_audio_accept(relation, relation->orig_codecs, receive_originator, relation->call->setup_msg, &relation->cc_session, &relation->codec, 0);
if (sdp) {
relation->codec_negotiated = 1;
PDEBUG(DROUTER, DEBUG_DEBUG, "Sending SDP answer to originator with supported codecs.\n");
@ -1119,7 +1120,7 @@ void cc_message(osmo_cc_endpoint_t __attribute__((unused)) *ep, uint32_t callref
* process message from routing
*/
static const char *value_of_param(const char *arg, const char *param, const char **value_p)
static const char *value_of_param(char *arg, char *param, char **value_p)
{
if (!!strncmp(arg, param, strlen(param)))
return NULL;
@ -1140,10 +1141,39 @@ static const char *value_of_param(const char *arg, const char *param, const char
return arg;
}
static void add_codecs_by_names(struct osmo_cc_helper_audio_codecs *codecs, char *names)
{
int c = 0, i;
const char *name;
while ((name = strsep(&names, ","))) {
printf("name='%s'\n", name);
for (i = 0; codecs_def[i].payload_name; i++) {
if (!strcasecmp(name, codecs_def[i].payload_name)) {
if (c == MAX_CODECS) {
PDEBUG(DROUTER, DEBUG_ERROR, "Maximum of %d codecs are reached. Ignoring codec '%s'.\n", c, name);
break;
}
memcpy(&codecs[c], &codecs_def[i], sizeof(*codecs));
PDEBUG(DROUTER, DEBUG_INFO, "Adding given codec '%s'.\n", codecs[c].payload_name);
c++;
break;
}
}
if (!codecs_def[i].payload_name) {
PDEBUG(DROUTER, DEBUG_ERROR, "Given codec '%s' not supported!\n", name);
}
}
memset(&codecs[c], 0, sizeof(*codecs));
}
/* routing orders us to activate rtp proxy */
static void routing_rtp_proxy(call_t *call)
static void routing_rtp_proxy(call_t *call, int argc, char *argv[])
{
call_relation_t *relation = call->relation_list;
int orig_given = 0, term_given = 0;
int i;
char *value;
/* ignore, if already enabled */
if (relation->rtp_proxy) {
@ -1151,6 +1181,37 @@ static void routing_rtp_proxy(call_t *call)
return;
}
/* loop through all arguments and stop if there is a ':' */
for (i = 0; i < argc ; i++) {
if (value_of_param(argv[i], "orig-codecs", &value)) {
PDEBUG(DROUTER, DEBUG_INFO, "Originating codecs given: '%s'.\n", value);
add_codecs_by_names(relation->orig_codecs, value);
if (relation->orig_codecs[0].payload_name)
orig_given = 1;
} else if (value_of_param(argv[i], "term-codecs", &value)) {
PDEBUG(DROUTER, DEBUG_INFO, "Terminating codecs given: '%s'.\n", value);
add_codecs_by_names(relation->term_codecs, value);
if (relation->term_codecs[0].payload_name)
term_given = 1;
} else
PDEBUG(DROUTER, DEBUG_ERROR, "Unknown 'rtp-proxy' parameter '%s' from routing.\n", argv[i]);
}
if (!orig_given) {
memcpy(&relation->orig_codecs[0], &codecs_def[0], sizeof(relation->orig_codecs[0]));
memcpy(&relation->orig_codecs[1], &codecs_def[1], sizeof(relation->orig_codecs[1]));
memcpy(&relation->orig_codecs[2], &codecs_def[2], sizeof(relation->orig_codecs[2]));
memset(&relation->orig_codecs[3], 0, sizeof(relation->orig_codecs[3]));
PDEBUG(DROUTER, DEBUG_INFO, "No originating codeds given, using default '%s' and '%s' and '%s'.\n", relation->orig_codecs[0].payload_name, relation->orig_codecs[1].payload_name, relation->orig_codecs[2].payload_name);
}
if (!term_given) {
memcpy(&relation->term_codecs[0], &codecs_def[0], sizeof(relation->term_codecs[0]));
memcpy(&relation->term_codecs[1], &codecs_def[1], sizeof(relation->term_codecs[1]));
memset(&relation->term_codecs[2], 0, sizeof(relation->term_codecs[2]));
PDEBUG(DROUTER, DEBUG_INFO, "No terminating codeds given, using default '%s' and '%s'.\n", relation->term_codecs[0].payload_name, relation->term_codecs[1].payload_name);
}
/* error, if we already negotiated */
if (call->sdp_forwarded) {
PDEBUG(DROUTER, DEBUG_ERROR, "RTP-Proxy cannot be enabled now, because we already forwarded a call.\n");
@ -1167,10 +1228,10 @@ static void routing_rtp_proxy(call_t *call)
}
/* routing orders us to play a wave file */
static void routing_play(call_t *call, int argc, const char *argv[])
static void routing_play(call_t *call, int argc, char *argv[])
{
call_relation_t *relation = call->relation_list;
const char *filename = NULL, *volume = "1.0", *loop = NULL;
char *filename = NULL, *volume = "1.0", *loop = NULL;
int i;
int samplerate = 8000, channels = 0;
double deviation;
@ -1228,10 +1289,10 @@ static void routing_play_stop(call_t *call)
}
/* routing orders us to record a wave file */
static void routing_record(call_t *call, int argc, const char *argv[])
static void routing_record(call_t *call, int argc, char *argv[])
{
call_relation_t *relation = call->relation_list;
const char *filename = NULL, *volume = "1.0";
char *filename = NULL, *volume = "1.0";
int i;
int samplerate = 8000, channels = 2;
int rc;
@ -1274,10 +1335,10 @@ static void routing_record_stop(call_t *call)
}
/* routing orders us to set local gain */
static void routing_gain(call_t *call, int argc, const char *argv[], int tx)
static void routing_gain(call_t *call, int argc, char *argv[], int tx)
{
int i;
const char *gain = NULL;
char *gain = NULL;
if (!call->relation_list->rtp_proxy) {
PDEBUG(DROUTER, DEBUG_ERROR, "RTP-Proxy must be enabled to record a file!\n");
@ -1306,15 +1367,15 @@ static void routing_gain(call_t *call, int argc, const char *argv[], int tx)
}
/* routing orders us to call remote end */
static void routing_call(call_t *call, int argc, const char *argv[])
static void routing_call(call_t *call, int argc, char *argv[])
{
const char *interface;
const char *bearer_coding, *bearer_capability, *bearer_mode;
const char *calling, *calling_type, *calling_plan, *calling_present, *calling_screen, *no_calling;
const char *calling2, *calling2_type, *calling2_plan, *calling2_present, *calling2_screen, *no_calling2;
const char *redirecting, *redirecting_type, *redirecting_plan, *redirecting_present, *redirecting_screen, *redirecting_reason, *no_redirecting;
const char *dialing, *dialing_type, *dialing_plan;
const char *keypad;
char *interface;
char *bearer_coding, *bearer_capability, *bearer_mode;
char *calling, *calling_type, *calling_plan, *calling_present, *calling_screen, *no_calling;
char *calling2, *calling2_type, *calling2_plan, *calling2_present, *calling2_screen, *no_calling2;
char *redirecting, *redirecting_type, *redirecting_plan, *redirecting_present, *redirecting_screen, *redirecting_reason, *no_redirecting;
char *dialing, *dialing_type, *dialing_plan;
char *keypad;
uint8_t coding, capability, mode;
uint8_t type, plan, present, screen, reason;
char number[256];
@ -1528,7 +1589,7 @@ next_call:
/* only if RTP-Proxy is used */
if (call->relation_list->rtp_proxy) {
PDEBUG(DROUTER, DEBUG_DEBUG, "Sending our codecs to the terminator.\n");
relation->cc_session = osmo_cc_helper_audio_offer(relation, codecs, receive_terminator, new_msg, 1);
relation->cc_session = osmo_cc_helper_audio_offer(relation, call->relation_list->term_codecs, receive_terminator, new_msg, 1);
} else
/* sdp from originator's setup message */
if (call->relation_list->sdp)
@ -1666,7 +1727,7 @@ static void routing_answer(call_t *call)
}
/* routing orders us to dsiconnect/release the call */
static void routing_disc_rel(call_t *call, int argc, const char *argv[], int disconnect)
static void routing_disc_rel(call_t *call, int argc, char *argv[], int disconnect)
{
call_relation_t *relation = call->relation_list;
uint8_t cause = 0;
@ -1746,7 +1807,7 @@ static void routing_dtmf_stop(call_t *call)
}
/* routing failed, release the call */
static void routing_error(call_t *call, const char *error)
static void routing_error(call_t *call, char *error)
{
osmo_cc_msg_t *new_msg;
call_relation_t *relation;
@ -1768,7 +1829,7 @@ static void routing_error(call_t *call, const char *error)
#if 0
/* routing script says something */
static void routing_say(call_t *call, const char *error)
static void routing_say(call_t *call, char *error)
{
char text[1024] = "";
fuer alle argv
@ -1782,7 +1843,7 @@ void routing_receive_stdout(routing_t *routing, const char *string)
{
call_t *call = routing->call;
int argc = 0;
const char *argv[256], *token;
char *argv[256], *token;
/* convert string into tokens */
while ((token = osmo_cc_strtok_quotes(&string)))
@ -1791,7 +1852,7 @@ void routing_receive_stdout(routing_t *routing, const char *string)
return;
if (!strcasecmp(argv[0], "rtp-proxy"))
routing_rtp_proxy(call);
routing_rtp_proxy(call, argc - 1, argv + 1);
else
if (!strcasecmp(argv[0], "play"))
routing_play(call, argc - 1, argv + 1);
@ -1899,6 +1960,30 @@ void routing_close(routing_t *routing)
call_destroy(call);
}
void telephone_event(call_relation_t *relation, struct telephone_event *te)
{
char digit_string[7] = "dtmf x";
if (te->event < 16) {
if (!relation->te_started && !te->e && te->volume <= 36) {
PDEBUG(DROUTER, DEBUG_INFO, "Received start of Telephone-Event '%d'\n", te->event);
relation->te_started = 1;
digit_string[5] = "0123456789*#ABCD"[te->event];
}
if (relation->te_started && te->e) {
PDEBUG(DROUTER, DEBUG_INFO, "Received end of Telephone-Event '%d'\n", te->event);
relation->te_started = 0;
}
} else
PDEBUG(DROUTER, DEBUG_INFO, "Received unsupported Telephone-Event '%d'\n", te->event);
if (!relation->call->routing.routing)
return;
if (digit_string[5] != 'x')
routing_send(&relation->call->routing, digit_string);
}
#warning add progress, if terminating call sends sdp but call state already reached
#warning beim disc muss progress geprueft werden und damit entschieden ob wir audio mitsenden sollen

View File

@ -21,6 +21,8 @@ enum call_state {
#include "routing.h"
#define MAX_CODECS 8
/* relation to upper layer */
typedef struct call_relation {
struct call_relation *next;
@ -39,6 +41,8 @@ typedef struct call_relation {
int rtp_proxy;
osmo_cc_session_t *cc_session;
int codec_negotiated;
struct osmo_cc_helper_audio_codecs orig_codecs[MAX_CODECS + 1]; /* codecs for originator */
struct osmo_cc_helper_audio_codecs term_codecs[MAX_CODECS + 1]; /* codecs for terminator, stored at relation of originator */
osmo_cc_session_codec_t *codec;
wave_play_t play; /* play a wave file */
@ -48,6 +52,7 @@ typedef struct call_relation {
wave_rec_t rec; /* record a wave file */
dtmf_dec_t dtmf_dec; /* dtmf decoder */
int dtmf_dec_enable;/* feed decoder with data */
int te_started; /* we got a digit via telephone-event */
} call_relation_t;
/* call instance */
@ -77,8 +82,16 @@ typedef struct call {
extern call_t *call_list;
struct telephone_event {
uint8_t event;
uint8_t e, r;
uint8_t volume;
uint16_t duration;
};
int call_init(osmo_cc_endpoint_t *ep, const char *_routing_script, const char *_routing_shell);
void call_exit(void);
int call_handle(void);
void cc_message(osmo_cc_endpoint_t *ep, uint32_t callref, osmo_cc_msg_t *msg);
void telephone_event(call_relation_t *relation, struct telephone_event *te);