From e1e9da7d24ccce07ae54d671cde5e07dfc827e25 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Fri, 17 Feb 2012 15:38:54 +0100 Subject: [PATCH] Allow dynamic RTP payload types when bridging between SIP and OpenBSC. Because EFR/AMR/HR codecs use dynamic RTP payload types, it is essential to forward the actual media types between endpoints too. These media types are used for negotiation of codecs. A dynamic payload type is used as given by remote peer. Locally generated payload types are used when offering codecs to remote peer. --- gsm.cpp | 100 ++++++++++++++++++++++++++++++++++----------------------- gsm.h | 9 ++++-- gsm_bs.cpp | 72 +++++++++++++++++++++++++---------------- gsm_bs.h | 2 +- message.h | 10 ++++++ mncc.h | 8 +++-- sip.cpp | 106 ++++++++++++++++++++++++++++++++++++++++--------------------- sip.h | 3 +- 8 files changed, 200 insertions(+), 110 deletions(-) diff --git a/gsm.cpp b/gsm.cpp index 2c1bace..a4a220e 100644 --- a/gsm.cpp +++ b/gsm.cpp @@ -27,10 +27,6 @@ extern "C" { //struct lcr_gsm *gsm = NULL; -#define RTP_PT_GSM_HALF 96 -#define RTP_PT_GSM_EFR 97 -#define RTP_PT_GSM_AMR 98 - int new_callref = 1; /* names of MNCC-SAP */ @@ -129,6 +125,32 @@ int send_and_free_mncc(struct lcr_gsm *lcr_gsm, unsigned int msg_type, void *dat return ret; } +void Pgsm::send_mncc_rtp_connect(void) +{ + struct gsm_mncc_rtp *nrtp; + + nrtp = (struct gsm_mncc_rtp *) create_mncc(MNCC_RTP_CONNECT, p_g_callref); + nrtp->ip = p_g_rtp_ip_remote; + nrtp->port = p_g_rtp_port_remote; + switch (p_g_media_type) { + case MEDIA_TYPE_GSM: + nrtp->payload_msg_type = GSM_TCHF_FRAME; + break; + case MEDIA_TYPE_GSM_EFR: + nrtp->payload_msg_type = GSM_TCHF_FRAME_EFR; + break; + case MEDIA_TYPE_AMR: + nrtp->payload_msg_type = GSM_TCHF_FRAME_AMR; + break; + case MEDIA_TYPE_GSM_HR: + nrtp->payload_msg_type = GSM_TCHF_FRAME_HR; + break; + } + nrtp->payload_type = p_g_payload_type; + PDEBUG(DEBUG_GSM, "sending MNCC RTP connect with payload_msg_type=%x, payload_type=%d\n", nrtp->payload_msg_type, nrtp->payload_type); + send_and_free_mncc(p_g_lcr_gsm, nrtp->msg_type, nrtp); +} + static int delete_event(struct lcr_work *work, void *instance, int index); /* @@ -168,7 +190,7 @@ Pgsm::Pgsm(int type, char *portname, struct port_settings *settings, struct inte } p_g_rxpos = 0; p_g_tch_connected = 0; - p_g_payload_type = -1; + p_g_media_type = 0; PDEBUG(DEBUG_GSM, "Created new GSMPort(%s).\n", portname); } @@ -334,33 +356,33 @@ void gsm_trace_header(const char *interface_name, class Pgsm *port, unsigned int } /* modify lchan to given payload type */ -void Pgsm::modify_lchan(unsigned char payload_type) +void Pgsm::modify_lchan(int media_type) { struct gsm_mncc *mode; /* already modified to that payload type */ - if (p_g_payload_type == payload_type) + if (p_g_media_type == media_type) return; - p_g_payload_type = payload_type; + p_g_media_type = media_type; gsm_trace_header(p_g_interface_name, this, MNCC_LCHAN_MODIFY, DIRECTION_OUT); mode = create_mncc(MNCC_LCHAN_MODIFY, p_g_callref); - switch (payload_type) { - case RTP_PT_GSM_EFR: + switch (media_type) { + case MEDIA_TYPE_GSM_EFR: add_trace("speech", "version", "EFR given"); mode->lchan_mode = 0x21; /* GSM V2 */ break; - case RTP_PT_GSM_AMR: + case MEDIA_TYPE_AMR: add_trace("speech", "version", "AMR given"); mode->lchan_mode = 0x41; /* GSM V3 */ break; - case RTP_PT_GSM_HALF: + case MEDIA_TYPE_GSM_HR: add_trace("speech", "version", "Half Rate given"); - mode->lchan_mode = 0x05; /* GSM V1 */ + mode->lchan_mode = 0x05; /* GSM V1 HR */ break; default: add_trace("speech", "version", "Full Rate given"); - mode->lchan_mode = 0x01; /* GSM V1 HR */ + mode->lchan_mode = 0x01; /* GSM V1 */ } mode->lchan_type = 0x02; /* FIXME: unused */ add_trace("mode", NULL, "0x%02x", mode->lchan_mode); @@ -458,10 +480,13 @@ void Pgsm::setup_cnf(unsigned int msg_type, unsigned int callref, struct gsm_mnc /* if we have a bridge, but not yet modified, the phone accepts out requested payload. * we force the first in list */ if (p_g_rtp_bridge) { - if (p_g_payload_type < 0) { - /* modify to first given payload */ - modify_lchan(p_g_rtp_payload_types[0]); + if (!p_g_media_type) { + /* modify to first given type */ + modify_lchan(p_g_rtp_media_types[0]); + /* also set payload type */ + p_g_payload_type = p_g_rtp_payload_types[0]; } + message->param.connectinfo.rtpinfo.media_types[0] = p_g_media_type; message->param.connectinfo.rtpinfo.payload_types[0] = p_g_payload_type; message->param.connectinfo.rtpinfo.payloads = 1; } @@ -628,13 +653,8 @@ void Pgsm::rtp_create_ind(unsigned int msg_type, unsigned int callref, struct gs p_g_setup_pending = NULL; } if (p_g_connect_pending) { - struct gsm_mncc_rtp *nrtp; - PDEBUG(DEBUG_GSM, "Got RTP peer info (%08x,%d) connecting RTP... \n", rtp->ip, rtp->port); - nrtp = (struct gsm_mncc_rtp *) create_mncc(MNCC_RTP_CONNECT, p_g_callref); - nrtp->ip = p_g_rtp_ip_remote; - nrtp->port = p_g_rtp_port_remote; - send_and_free_mncc(p_g_lcr_gsm, nrtp->msg_type, nrtp); + send_mncc_rtp_connect(); } } @@ -663,16 +683,17 @@ void Pgsm::message_progress(unsigned int epoint_id, int message_id, union parame } if (param->progressinfo.rtpinfo.port) { - struct gsm_mncc_rtp *rtp; + PDEBUG(DEBUG_GSM, "PROGRESS with RTP peer info, sent to BSC (%08x,%d) with media %d, pt %d\n", param->progressinfo.rtpinfo.ip, param->progressinfo.rtpinfo.port, param->progressinfo.rtpinfo.media_types[0], param->progressinfo.rtpinfo.payload_types[0]); - PDEBUG(DEBUG_GSM, "CONNECT with RTP peer info, sent to BSC (%08x,%d)\n", param->progressinfo.rtpinfo.ip, param->progressinfo.rtpinfo.port); - rtp = (struct gsm_mncc_rtp *) create_mncc(MNCC_RTP_CONNECT, p_g_callref); - rtp->ip = param->progressinfo.rtpinfo.ip; - rtp->port = param->progressinfo.rtpinfo.port; - send_and_free_mncc(p_g_lcr_gsm, rtp->msg_type, rtp); + /* modify channel to givne type, also sets media type */ + modify_lchan(param->progressinfo.rtpinfo.media_types[0]); - /* modify channel to accepted payload type */ - modify_lchan(param->progressinfo.rtpinfo.payload_types[0]); + /* connect RTP */ + p_g_rtp_ip_remote = param->progressinfo.rtpinfo.ip; + p_g_rtp_port_remote = param->progressinfo.rtpinfo.port; + /* p_g_media_type is already set by modify_lchan() */ + p_g_payload_type = param->progressinfo.rtpinfo.payload_types[0]; + send_mncc_rtp_connect(); } } @@ -773,16 +794,17 @@ void Pgsm::message_connect(unsigned int epoint_id, int message_id, union paramet new_state(PORT_STATE_CONNECT_WAITING); if (param->connectinfo.rtpinfo.port) { - struct gsm_mncc_rtp *rtp; - PDEBUG(DEBUG_GSM, "CONNECT with RTP peer info, sent to BSC (%08x,%d)\n", param->connectinfo.rtpinfo.ip, param->connectinfo.rtpinfo.port); - rtp = (struct gsm_mncc_rtp *) create_mncc(MNCC_RTP_CONNECT, p_g_callref); - rtp->ip = param->connectinfo.rtpinfo.ip; - rtp->port = param->connectinfo.rtpinfo.port; - send_and_free_mncc(p_g_lcr_gsm, rtp->msg_type, rtp); - /* modify channel to accepted payload type */ - modify_lchan(param->connectinfo.rtpinfo.payload_types[0]); + /* modify channel to givne type, also sets media type */ + modify_lchan(param->connectinfo.rtpinfo.media_types[0]); + + /* connect RTP */ + p_g_rtp_ip_remote = param->connectinfo.rtpinfo.ip; + p_g_rtp_port_remote = param->connectinfo.rtpinfo.port; + /* p_g_media_type is already set by modify_lchan() */ + p_g_payload_type = param->connectinfo.rtpinfo.payload_types[0]; + send_mncc_rtp_connect(); } } diff --git a/gsm.h b/gsm.h index 421a098..00bb295 100644 --- a/gsm.h +++ b/gsm.h @@ -53,21 +53,24 @@ class Pgsm : public Port signed short p_g_rxdata[160]; /* receive audio buffer */ int p_g_rxpos; /* position in audio buffer 0..159 */ int p_g_tch_connected; /* indicates if audio is connected */ - int p_g_payload_type; /* current payload type or -1 if not set */ + int p_g_media_type; /* current payload type or 0 if not set */ + int p_g_payload_type; /* current payload type */ int p_g_rtp_bridge; /* if we use a bridge */ unsigned int p_g_rtp_ip_remote; /* stores ip */ unsigned short p_g_rtp_port_remote; /* stores port */ int p_g_rtp_payloads; - int p_g_rtp_payload_types[8]; + int p_g_rtp_media_types[8]; + unsigned char p_g_rtp_payload_types[8]; void frame_send(void *_frame); void frame_receive(void *_frame); int audio_send(unsigned char *data, int len); int bridge_rx(unsigned char *data, int len); + void send_mncc_rtp_connect(void); int hunt_bchannel(void); - void modify_lchan(unsigned char payload_type); + void modify_lchan(int media_type); void call_proc_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc); void alert_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc); void setup_cnf(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc); diff --git a/gsm_bs.cpp b/gsm_bs.cpp index ae763ca..92a2ffc 100644 --- a/gsm_bs.cpp +++ b/gsm_bs.cpp @@ -14,10 +14,7 @@ struct lcr_gsm *gsm_bs = NULL; -#define RTP_PT_GSM_FULL 3 -#define RTP_PT_GSM_HALF 96 -#define RTP_PT_GSM_EFR 97 -#define RTP_PT_GSM_AMR 98 +#define PAYLOAD_TYPE_GSM 3 /* * DTMF stuff @@ -70,6 +67,7 @@ Pgsm_bs::~Pgsm_bs() /* PROCEEDING INDICATION (from MS) */ void Pgsm_bs::call_conf_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc) { + int media_types[8]; unsigned char payload_types[8]; int payloads = 0; @@ -85,10 +83,11 @@ void Pgsm_bs::call_conf_ind(unsigned int msg_type, unsigned int callref, struct /* get list of offered payload types * if list ist empty, the FR V1 is selected */ - select_payload_type(mncc, payload_types, &payloads, sizeof(payload_types)); + select_payload_type(mncc, payload_types, media_types, &payloads, sizeof(payload_types)); /* if no given payload type is supported, we assume */ if (!payloads) { - payload_types[0] = RTP_PT_GSM_FULL; + media_types[0] = MEDIA_TYPE_GSM; + payload_types[0] = PAYLOAD_TYPE_GSM; payloads = 1; } @@ -98,7 +97,7 @@ void Pgsm_bs::call_conf_ind(unsigned int msg_type, unsigned int callref, struct for (i = 0; i < p_g_rtp_payloads; i++) { for (j = 0; j < payloads; j++) { - if (p_g_rtp_payload_types[i] == payload_types[j]) + if (p_g_rtp_media_types[i] == media_types[j]) break; } if (j < payloads) @@ -127,11 +126,16 @@ void Pgsm_bs::call_conf_ind(unsigned int msg_type, unsigned int callref, struct send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc); new_state(PORT_STATE_RELEASE); trigger_work(&p_g_delete); + + return; } - modify_lchan(p_g_rtp_payload_types[i]); + modify_lchan(p_g_rtp_media_types[i]); + /* use the payload type from received rtp list, not from locally generated payload types */ + p_g_payload_type = p_g_rtp_payload_types[i]; } else { /* modify to first given payload */ - modify_lchan(payload_types[0]); + modify_lchan(media_types[0]); + p_g_payload_type = payload_types[0]; } } @@ -281,8 +285,9 @@ void Pgsm_bs::retr_ind(unsigned int msg_type, unsigned int callref, struct gsm_m * return the payload type or 0 if not given */ -void Pgsm_bs::select_payload_type(struct gsm_mncc *mncc, unsigned char *payload_types, int *payloads, int max_payloads) +void Pgsm_bs::select_payload_type(struct gsm_mncc *mncc, unsigned char *payload_types, int *media_types, int *payloads, int max_payloads) { + int media_type; unsigned char payload_type; *payloads = 0; @@ -298,36 +303,42 @@ void Pgsm_bs::select_payload_type(struct gsm_mncc *mncc, unsigned char *payload_ switch (mncc->bearer_cap.speech_ver[i]) { case 0: add_trace("speech", "version", "Full Rate given"); - payload_type = RTP_PT_GSM_FULL; + media_type = MEDIA_TYPE_GSM; + payload_type = PAYLOAD_TYPE_GSM; break; case 2: add_trace("speech", "version", "EFR given"); - payload_type = RTP_PT_GSM_EFR; + media_type = MEDIA_TYPE_GSM_EFR; + payload_type = 100 + *payloads; break; case 4: add_trace("speech", "version", "AMR given"); - payload_type = RTP_PT_GSM_AMR; + media_type = MEDIA_TYPE_AMR; + payload_type = 100 + *payloads; break; case 1: add_trace("speech", "version", "Half Rate given"); - payload_type = RTP_PT_GSM_HALF; + media_type = MEDIA_TYPE_GSM_HR; + payload_type = 100 + *payloads; break; default: add_trace("speech", "version", "%d given", mncc->bearer_cap.speech_ver[i]); + media_type = 0; payload_type = 0; } /* wen don't support it, so we check the next */ - if (!payload_type) { + if (!media_type) { add_trace("speech", "ignored", "Not supported by LCR"); continue; } if (!p_g_rtp_bridge) { - if (payload_type != RTP_PT_GSM_FULL) { + if (media_type != MEDIA_TYPE_GSM) { add_trace("speech", "ignored", "Not suitable for LCR"); continue; } } if (*payloads <= max_payloads) { + media_types[*payloads] = media_type; payload_types[*payloads] = payload_type; (*payloads)++; } @@ -335,7 +346,8 @@ void Pgsm_bs::select_payload_type(struct gsm_mncc *mncc, unsigned char *payload_ } else { add_trace("bearer", "capa", "not given by MS"); add_trace("speech", "version", "Full Rate given"); - payload_types[0] = RTP_PT_GSM_FULL; + media_types[0] = MEDIA_TYPE_GSM; + payload_types[0] = PAYLOAD_TYPE_GSM; *payloads = 1; } if (!(*payloads)) @@ -353,6 +365,7 @@ void Pgsm_bs::setup_ind(unsigned int msg_type, unsigned int callref, struct gsm_ struct lcr_msg *message; struct gsm_mncc *proceeding, *frame; struct interface *interface; + int media_types[8]; unsigned char payload_types[8]; int payloads = 0; @@ -432,10 +445,11 @@ void Pgsm_bs::setup_ind(unsigned int msg_type, unsigned int callref, struct gsm_ /* get list of offered payload types * if list ist empty, the FR V1 is selected */ - select_payload_type(mncc, payload_types, &payloads, sizeof(payload_types)); + select_payload_type(mncc, payload_types, media_types, &payloads, sizeof(payload_types)); /* if no given payload type is supported, we assume */ if (!payloads) { - payload_types[0] = RTP_PT_GSM_FULL; + media_types[0] = MEDIA_TYPE_GSM; + payload_types[0] = PAYLOAD_TYPE_GSM; payloads = 1; } #if 0 @@ -481,7 +495,7 @@ void Pgsm_bs::setup_ind(unsigned int msg_type, unsigned int callref, struct gsm_ /* modify lchan in case of no rtp bridge */ if (!p_g_rtp_bridge) - modify_lchan(payload_types[0]); + modify_lchan(media_types[0]); /* send call proceeding */ gsm_trace_header(p_g_interface_name, this, MNCC_CALL_PROC_REQ, DIRECTION_OUT); @@ -528,6 +542,7 @@ void Pgsm_bs::setup_ind(unsigned int msg_type, unsigned int callref, struct gsm_ send_and_free_mncc(p_g_lcr_gsm, rtp->msg_type, rtp); for (i = 0; i < (int)sizeof(message->param.setup.rtpinfo.payload_types) && i < payloads; i++) { + message->param.setup.rtpinfo.media_types[i] = media_types[i]; message->param.setup.rtpinfo.payload_types[i] = payload_types[i]; message->param.setup.rtpinfo.payloads++; } @@ -739,19 +754,20 @@ void Pgsm_bs::message_setup(unsigned int epoint_id, int message_id, union parame p_g_rtp_payloads = 0; gsm_trace_header(p_g_interface_name, this, 1 /* codec negotioation */, DIRECTION_NONE); for (i = 0; i < param->setup.rtpinfo.payloads; i++) { - switch (param->setup.rtpinfo.payload_types[i]) { - case RTP_PT_GSM_FULL: - case RTP_PT_GSM_EFR: - case RTP_PT_GSM_AMR: - case RTP_PT_GSM_HALF: - add_trace("rtp", "payload", "%d supported", param->setup.rtpinfo.payload_types[i]); + switch (param->setup.rtpinfo.media_types[i]) { + case MEDIA_TYPE_GSM: + case MEDIA_TYPE_GSM_EFR: + case MEDIA_TYPE_AMR: + case MEDIA_TYPE_GSM_HR: + add_trace("rtp", "payload", "%s:%d supported", media_type2name(param->setup.rtpinfo.media_types[i]), param->setup.rtpinfo.payload_types[i]); if (p_g_rtp_payloads < (int)sizeof(p_g_rtp_payload_types)) { - p_g_rtp_payload_types[p_g_rtp_payloads++] = param->setup.rtpinfo.payload_types[i]; + p_g_rtp_media_types[p_g_rtp_payloads] = param->setup.rtpinfo.media_types[i]; + p_g_rtp_payload_types[p_g_rtp_payloads] = param->setup.rtpinfo.payload_types[i]; p_g_rtp_payloads++; } break; default: - add_trace("rtp", "payload", "%d unsupported", param->setup.rtpinfo.payload_types[i]); + add_trace("rtp", "payload", "%s:%d unsupported", media_type2name(param->setup.rtpinfo.media_types[i]), param->setup.rtpinfo.payload_types[i]); } } end_trace(); diff --git a/gsm_bs.h b/gsm_bs.h index b60c02c..5575daa 100644 --- a/gsm_bs.h +++ b/gsm_bs.h @@ -9,7 +9,7 @@ class Pgsm_bs : public Pgsm unsigned char *p_g_dtmf; /* DTMF tone generation (MS only) */ int p_g_dtmf_index; /* DTMF tone generation index */ - void select_payload_type(struct gsm_mncc *mncc, unsigned char *payload_types, int *payloads, int max_payloads); + void select_payload_type(struct gsm_mncc *mncc, unsigned char *payload_types, int *media_types, int *payloads, int max_payloads); void setup_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc); void call_conf_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *gsm); void start_dtmf_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc); diff --git a/message.h b/message.h index ce6ed03..82df9d5 100644 --- a/message.h +++ b/message.h @@ -148,10 +148,20 @@ enum { B_MODE_HDLC, /* hdlc data mode */ }; +enum { + MEDIA_TYPE_ALAW = 1, + MEDIA_TYPE_ULAW, + MEDIA_TYPE_GSM, + MEDIA_TYPE_GSM_EFR, + MEDIA_TYPE_AMR, + MEDIA_TYPE_GSM_HR, +}; + /* rtp-info structure */ struct rtp_info { int payloads; /* number of payloads offered */ unsigned char payload_types[32];/* rtp payload types */ + int media_types[32]; /* media type of given payload */ unsigned int ip; /* peer's IP */ unsigned short port; /* peer's port */ }; diff --git a/mncc.h b/mncc.h index 4028b67..dcb8f04 100644 --- a/mncc.h +++ b/mncc.h @@ -56,8 +56,10 @@ #define MNCC_RTP_CONNECT 0x0205 #define MNCC_RTP_FREE 0x0206 -#define GSM_TCHF_FRAME 0x0300 -#define GSM_TCHF_FRAME_EFR 0x0301 +#define GSM_TCHF_FRAME 0x0300 +#define GSM_TCHF_FRAME_EFR 0x0301 +#define GSM_TCHF_FRAME_HR 0x0302 +#define GSM_TCHF_FRAME_AMR 0x0303 #define GSM_TCHF_BAD_FRAME 0x03ff #define GSM_MAX_FACILITY 128 @@ -194,6 +196,8 @@ struct gsm_mncc_rtp { uint32_t callref; uint32_t ip; uint16_t port; + uint32_t payload_type; + uint32_t payload_msg_type; }; diff --git a/sip.cpp b/sip.cpp index c6f36ac..c6ddde3 100644 --- a/sip.cpp +++ b/sip.cpp @@ -77,17 +77,20 @@ Psip::~Psip() rtp_close(); } -const char *payload_type2name(uint8_t payload_type) { - switch (payload_type) { - case 0: +const char *media_type2name(uint8_t media_type) { + switch (media_type) { + case MEDIA_TYPE_ULAW: return "PCMU"; - case 8: + case MEDIA_TYPE_ALAW: return "PCMA"; - case 3: - case 96: - case 97: - case 98: + case MEDIA_TYPE_GSM: return "GSM"; + case MEDIA_TYPE_GSM_HR: + return "GSM-HR"; + case MEDIA_TYPE_GSM_EFR: + return "GSM-EFR"; + case MEDIA_TYPE_AMR: + return "AMR"; } return "UKN"; @@ -139,12 +142,9 @@ struct rtp_x_hdr { #define RTP_VERSION 2 -#define RTP_PT_ULAW 0 -#define RTP_PT_ALAW 8 -#define RTP_PT_GSM_FULL 3 -#define RTP_PT_GSM_HALF 96 -#define RTP_PT_GSM_EFR 97 -#define RTP_PT_GSM_AMR 98 +#define PAYLOAD_TYPE_ULAW 0 +#define PAYLOAD_TYPE_ALAW 8 +#define PAYLOAD_TYPE_GSM 3 /* decode an rtp frame */ static int rtp_decode(class Psip *psip, unsigned char *data, int len) @@ -203,6 +203,8 @@ static int rtp_decode(class Psip *psip, unsigned char *data, int len) } switch (rtph->payload_type) { +#if 0 +we only support alaw and ulaw! case RTP_PT_GSM_FULL: if (payload_len != 33) { PDEBUG(DEBUG_SIP, "received RTP full rate frame with " @@ -227,13 +229,14 @@ static int rtp_decode(class Psip *psip, unsigned char *data, int len) return -EINVAL; } break; - case RTP_PT_ALAW: +#endif + case PAYLOAD_TYPE_ALAW: if (options.law != 'a') { PDEBUG(DEBUG_SIP, "received Alaw, but we don't do Alaw\n"); return -EINVAL; } break; - case RTP_PT_ULAW: + case PAYLOAD_TYPE_ULAW: if (options.law == 'a') { PDEBUG(DEBUG_SIP, "received Ulaw, but we don't do Ulaw\n"); return -EINVAL; @@ -468,6 +471,8 @@ int Psip::rtp_send_frame(unsigned char *data, unsigned int len, uint8_t payload_ } switch (payload_type) { +#if 0 +we only support alaw and ulaw! case RTP_PT_GSM_FULL: payload_len = 33; duration = 160; @@ -480,8 +485,9 @@ int Psip::rtp_send_frame(unsigned char *data, unsigned int len, uint8_t payload_ payload_len = 14; duration = 160; break; - case RTP_PT_ALAW: - case RTP_PT_ULAW: +#endif + case PAYLOAD_TYPE_ALAW: + case PAYLOAD_TYPE_ULAW: payload_len = len; duration = len; break; @@ -548,7 +554,7 @@ int Psip::bridge_rx(unsigned char *data, int len) p_s_rxpos = 0; /* transmit data via rtp */ - rtp_send_frame(p_s_rxdata, 160, (options.law=='a')?RTP_PT_ALAW:RTP_PT_ULAW); + rtp_send_frame(p_s_rxdata, 160, (options.law=='a')?PAYLOAD_TYPE_ALAW:PAYLOAD_TYPE_ULAW); } } @@ -733,11 +739,13 @@ int Psip::message_connect(unsigned int epoint_id, int message_id, union paramete char sdp_str[256]; struct in_addr ia; struct lcr_msg *message; + int media_type; unsigned char payload_type; if (param->connectinfo.rtpinfo.port) { PDEBUG(DEBUG_SIP, "RTP info given by remote, forward that\n"); p_s_rtp_bridge = 1; + media_type = param->connectinfo.rtpinfo.media_types[0]; payload_type = param->connectinfo.rtpinfo.payload_types[0]; p_s_rtp_ip_local = param->connectinfo.rtpinfo.ip; p_s_rtp_port_local = param->connectinfo.rtpinfo.port; @@ -746,7 +754,8 @@ int Psip::message_connect(unsigned int epoint_id, int message_id, union paramete PDEBUG(DEBUG_SIP, "remote ip %08x port %d\n", p_s_rtp_ip_remote, p_s_rtp_port_remote); } else { PDEBUG(DEBUG_SIP, "RTP info not given by remote, so we do our own RTP\n"); - payload_type = (options.law=='a') ? RTP_PT_ALAW : RTP_PT_ULAW; + media_type = (options.law=='a') ? MEDIA_TYPE_ALAW : MEDIA_TYPE_ULAW; + payload_type = (options.law=='a') ? PAYLOAD_TYPE_ALAW : PAYLOAD_TYPE_ULAW; /* open local RTP peer (if not bridging) */ if (!p_s_rtp_is_connected && rtp_connect() < 0) { nua_cancel(p_s_handle, TAG_END()); @@ -775,7 +784,7 @@ int Psip::message_connect(unsigned int epoint_id, int message_id, union paramete "t=0 0\n" "m=audio %d RTP/AVP %d\n" "a=rtpmap:%d %s/8000\n" - , inet_ntoa(ia), inet_ntoa(ia), p_s_rtp_port_local, payload_type, payload_type, payload_type2name(payload_type)); + , inet_ntoa(ia), inet_ntoa(ia), p_s_rtp_port_local, payload_type, payload_type, media_type2name(media_type)); PDEBUG(DEBUG_SIP, "Using SDP response: %s\n", sdp_str); nua_respond(p_s_handle, SIP_200_OK, @@ -788,7 +797,7 @@ int Psip::message_connect(unsigned int epoint_id, int message_id, union paramete add_trace("reason", NULL, "call connected"); add_trace("rtp", "ip", "%s", inet_ntoa(ia)); add_trace("rtp", "port", "%d,%d", p_s_rtp_port_local, p_s_rtp_port_local + 1); - add_trace("rtp", "payload", "%d", payload_type); + add_trace("rtp", "payload", "%s:%d", media_type2name(media_type), payload_type); end_trace(); return 0; @@ -870,7 +879,9 @@ int Psip::message_setup(unsigned int epoint_id, int message_id, union parameter struct epoint_list *epointlist; sip_cseq_t *cseq = NULL; struct lcr_msg *message; - unsigned char lcr_payload = { (options.law=='a') ? RTP_PT_ALAW : RTP_PT_ULAW }; + int lcr_media = { (options.law=='a') ? MEDIA_TYPE_ALAW : MEDIA_TYPE_ULAW }; + unsigned char lcr_payload = { (options.law=='a') ? PAYLOAD_TYPE_ALAW : PAYLOAD_TYPE_ULAW }; + int *media_types; unsigned char *payload_types; int payloads = 0; int i; @@ -884,6 +895,7 @@ int Psip::message_setup(unsigned int epoint_id, int message_id, union parameter if (param->setup.rtpinfo.port) { PDEBUG(DEBUG_SIP, "RTP info given by remote, forward that\n"); p_s_rtp_bridge = 1; + media_types = param->setup.rtpinfo.media_types; payload_types = param->setup.rtpinfo.payload_types; payloads = param->setup.rtpinfo.payloads; p_s_rtp_ip_local = param->setup.rtpinfo.ip; @@ -893,6 +905,7 @@ int Psip::message_setup(unsigned int epoint_id, int message_id, union parameter } else { PDEBUG(DEBUG_SIP, "RTP info not given by remote, so we do our own RTP\n"); p_s_rtp_bridge = 0; + media_types = &lcr_media; payload_types = &lcr_payload; payloads = 1; @@ -947,7 +960,7 @@ int Psip::message_setup(unsigned int epoint_id, int message_id, union parameter } SCAT(sdp_str, "\n"); for (i = 0; i < payloads; i++) { - SPRINT(pt_str, "a=rtpmap:%d %s/8000\n", payload_types[i], payload_type2name(payload_types[i])); + SPRINT(pt_str, "a=rtpmap:%d %s/8000\n", payload_types[i], media_type2name(media_types[i])); SCAT(sdp_str, pt_str); } PDEBUG(DEBUG_SIP, "Using SDP for invite: %s\n", sdp_str); @@ -961,7 +974,7 @@ int Psip::message_setup(unsigned int epoint_id, int message_id, union parameter add_trace("rtp", "ip", "%s", inet_ntoa(ia)); add_trace("rtp", "port", "%d,%d", p_s_rtp_port_local, p_s_rtp_port_local + 1); for (i = 0; i < payloads; i++) - add_trace("rtp", "payload", "%d", payload_types[i]); + add_trace("rtp", "payload", "%s:%d", media_type2name(media_types[i]), payload_types[i]); end_trace(); // cseq = sip_cseq_create(sip_home, 123, SIP_METHOD_INVITE); @@ -1036,7 +1049,7 @@ int Psip::message_notify(unsigned int epoint_id, int message_id, union parameter "t=0 0\n" "m=audio %d RTP/AVP %d\n" "a=rtpmap:%d %s/8000\n" - , inet_ntoa(ia), inet_ntoa(ia), p_s_rtp_port_local, p_s_rtp_payload_type, p_s_rtp_payload_type, payload_type2name(p_s_rtp_payload_type)); + , inet_ntoa(ia), inet_ntoa(ia), p_s_rtp_port_local, p_s_rtp_payload_type, p_s_rtp_payload_type, media_type2name(p_s_rtp_media_type)); PDEBUG(DEBUG_SIP, "Using SDP for rertieve: %s\n", sdp_str); nua_info(p_s_handle, // TAG_IF(from[0], SIPTAG_FROM_STR(from)), @@ -1146,7 +1159,7 @@ int Psip::message_epoint(unsigned int epoint_id, int message_id, union parameter return 0; } -int Psip::parse_sdp(sip_t const *sip, unsigned int *ip, unsigned short *port, uint8_t *payload_types, int *payloads, int max_payloads) +int Psip::parse_sdp(sip_t const *sip, unsigned int *ip, unsigned short *port, uint8_t *payload_types, int *media_types, int *payloads, int max_payloads) { *payloads = 0; @@ -1206,11 +1219,26 @@ int Psip::parse_sdp(sip_t const *sip, unsigned int *ip, unsigned short *port, ui *ip = ntohl(p_s_rtp_ip_remote); } for (map = m->m_rtpmaps; map; map = map->rm_next) { + int media_type = 0; + PDEBUG(DEBUG_SIP, "RTPMAP: coding:'%s' rate='%d' pt='%d'\n", map->rm_encoding, map->rm_rate, map->rm_pt); /* append to payload list, if there is space */ - add_trace("rtp", "payload", "%d", map->rm_pt); - if (*payloads <= max_payloads) { + add_trace("rtp", "payload", "%s:%d", map->rm_encoding, map->rm_pt); + if (map->rm_pt == PAYLOAD_TYPE_ALAW) + media_type = MEDIA_TYPE_ALAW; + else if (map->rm_pt == PAYLOAD_TYPE_ULAW) + media_type = MEDIA_TYPE_ULAW; + else if (map->rm_pt == PAYLOAD_TYPE_GSM) + media_type = MEDIA_TYPE_GSM; + else if (!strcmp(map->rm_encoding, "GSM-EFR")) + media_type = MEDIA_TYPE_GSM_EFR; + else if (!strcmp(map->rm_encoding, "AMR")) + media_type = MEDIA_TYPE_AMR; + else if (!strcmp(map->rm_encoding, "GSM-HR")) + media_type = MEDIA_TYPE_GSM_HR; + if (media_type && *payloads <= max_payloads) { *payload_types++ = map->rm_pt; + *media_types++ = media_type; (*payloads)++; } } @@ -1229,6 +1257,7 @@ void Psip::i_invite(int status, char const *phrase, nua_t *nua, nua_magic_t *mag class Endpoint *epoint; struct lcr_msg *message; struct interface *interface; + int media_types[32]; uint8_t payload_types[32]; int payloads = 0; @@ -1245,7 +1274,7 @@ void Psip::i_invite(int status, char const *phrase, nua_t *nua, nua_magic_t *mag PDEBUG(DEBUG_SIP, "invite received (%s->%s)\n", from, to); sip_trace_header(this, "Payload received", DIRECTION_NONE); - ret = parse_sdp(sip, &p_s_rtp_ip_remote, &p_s_rtp_port_remote, payload_types, &payloads, sizeof(payload_types)); + ret = parse_sdp(sip, &p_s_rtp_ip_remote, &p_s_rtp_port_remote, payload_types, media_types, &payloads, sizeof(payload_types)); if (!ret) { /* if no RTP bridge, we must support LAW codec, otherwise we forward what we have */ if (!p_s_rtp_bridge) { @@ -1253,7 +1282,7 @@ void Psip::i_invite(int status, char const *phrase, nua_t *nua, nua_magic_t *mag /* check if supported payload type exists */ for (i = 0; i < payloads; i++) { - if (payload_types[i] == ((options.law=='a') ? RTP_PT_ALAW : RTP_PT_ULAW)) + if (media_types[i] == ((options.law=='a') ? MEDIA_TYPE_ALAW : MEDIA_TYPE_ULAW)) break; } if (i == payloads) { @@ -1303,7 +1332,7 @@ void Psip::i_invite(int status, char const *phrase, nua_t *nua, nua_magic_t *mag end_trace(); sip_trace_header(this, "INVITE", DIRECTION_IN); - add_trace("RTP", "port", "%d", p_s_rtp_port_remote); + add_trace("rtp", "port", "%d", p_s_rtp_port_remote); /* caller information */ if (!from[0]) { p_callerinfo.present = INFO_PRESENT_NOTAVAIL; @@ -1372,10 +1401,12 @@ void Psip::i_invite(int status, char const *phrase, nua_t *nua, nua_magic_t *mag message->param.setup.rtpinfo.port = p_s_rtp_port_remote; /* add codecs to setup message */ for (i = 0; i < payloads; i++) { - message->param.setup.rtpinfo.payload_types[message->param.setup.rtpinfo.payloads++] = payload_types[i]; - if (message->param.setup.rtpinfo.payloads == sizeof(message->param.setup.rtpinfo.payload_types)) + message->param.setup.rtpinfo.media_types[i] = media_types[i]; + message->param.setup.rtpinfo.payload_types[i] = payload_types[i]; + if (i == sizeof(message->param.setup.rtpinfo.payload_types)) break; } + message->param.setup.rtpinfo.payloads = i; } message_put(message); @@ -1531,6 +1562,7 @@ void Psip::r_invite(int status, char const *phrase, nua_t *nua, nua_magic_t *mag { struct lcr_msg *message; int cause = 0, location = 0; + int media_types[32]; uint8_t payload_types[32]; int payloads = 0; @@ -1545,12 +1577,12 @@ void Psip::r_invite(int status, char const *phrase, nua_t *nua, nua_magic_t *mag int ret; sip_trace_header(this, "Payload received", DIRECTION_NONE); - ret = parse_sdp(sip, &p_s_rtp_ip_remote, &p_s_rtp_port_remote, payload_types, &payloads, sizeof(payload_types)); + ret = parse_sdp(sip, &p_s_rtp_ip_remote, &p_s_rtp_port_remote, payload_types, media_types, &payloads, sizeof(payload_types)); if (!ret) { if (payloads != 1) ret = 415; else if (!p_s_rtp_bridge) { - if (payload_types[0] != ((options.law=='a') ? RTP_PT_ALAW : RTP_PT_ULAW)) { + if (media_types[0] != ((options.law=='a') ? MEDIA_TYPE_ALAW : MEDIA_TYPE_ULAW)) { add_trace("error", NULL, "Expected LAW payload type (not bridged)"); ret = 415; } @@ -1603,6 +1635,7 @@ void Psip::r_invite(int status, char const *phrase, nua_t *nua, nua_magic_t *mag if (p_s_rtp_bridge) { message->param.progressinfo.rtpinfo.ip = p_s_rtp_ip_remote; message->param.progressinfo.rtpinfo.port = p_s_rtp_port_remote; + message->param.progressinfo.rtpinfo.media_types[0] = media_types[0]; message->param.progressinfo.rtpinfo.payload_types[0] = payload_types[0]; message->param.progressinfo.rtpinfo.payloads = 1; } @@ -1625,6 +1658,7 @@ void Psip::r_invite(int status, char const *phrase, nua_t *nua, nua_magic_t *mag if (p_s_rtp_bridge) { message->param.connectinfo.rtpinfo.ip = p_s_rtp_ip_remote; message->param.connectinfo.rtpinfo.port = p_s_rtp_port_remote; + message->param.connectinfo.rtpinfo.media_types[0] = media_types[0]; message->param.connectinfo.rtpinfo.payload_types[0] = payload_types[0]; message->param.connectinfo.rtpinfo.payloads = 1; } diff --git a/sip.h b/sip.h index 9e8194e..6d62cff 100644 --- a/sip.h +++ b/sip.h @@ -62,10 +62,11 @@ class Psip : public Port unsigned char p_s_rxdata[160]; /* receive audio buffer */ int p_s_rxpos; /* position in audio buffer 0..159 */ int bridge_rx(unsigned char *data, int len); - int parse_sdp(sip_t const *sip, unsigned int *ip, unsigned short *port, uint8_t *payload_types, int *payloads, int max_payloads); + int parse_sdp(sip_t const *sip, unsigned int *ip, unsigned short *port, uint8_t *payload_types, int *media_types, int *payloads, int max_payloads); void rtp_shutdown(void); }; +const char *media_type2name(uint8_t media_type); int sip_init_inst(struct interface *interface); void sip_exit_inst(struct interface *interface); int sip_init(void); -- 2.13.6