forked from cc/osmo-cc-router
Add DTMF detection via telephone-event payload
This commit is contained in:
parent
2017066db5
commit
d5face6404
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue