summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAndreas Eversberg <jolly@eversberg.eu>2021-02-27 12:07:32 +0100
committerAndreas Eversberg <jolly@eversberg.eu>2021-03-14 11:20:55 +0100
commitd5face6404c604e0baff7aed9a1ba5db18431f51 (patch)
tree873d98421e541327a1ce275213c9e5f1bbfbf14a /src
parent2017066db5d60f017031800c65c3f7dc4bb1c1b0 (diff)
Add DTMF detection via telephone-event payload
Diffstat (limited to 'src')
-rw-r--r--src/router/audio.c37
-rw-r--r--src/router/audio.h4
-rw-r--r--src/router/call.c135
-rw-r--r--src/router/call.h13
4 files changed, 164 insertions, 25 deletions
diff --git a/src/router/audio.c b/src/router/audio.c
index 0c4b6c3..16e83c0 100644
--- a/src/router/audio.c
+++ b/src/router/audio.c
@@ -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);
+}
diff --git a/src/router/audio.h b/src/router/audio.h
index 390e54f..cf2d34c 100644
--- a/src/router/audio.h
+++ b/src/router/audio.h
@@ -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);
+
diff --git a/src/router/call.c b/src/router/call.c
index 5b8c28b..13c2844 100644
--- a/src/router/call.c
+++ b/src/router/call.c
@@ -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
diff --git a/src/router/call.h b/src/router/call.h
index 580f267..e782c26 100644
--- a/src/router/call.h
+++ b/src/router/call.h
@@ -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);