Adding negotiation of speech codecs between GSM and SIP when using rtp-bridge
authorAndreas Eversberg <jolly@eversberg.eu>
Wed, 1 Feb 2012 16:52:36 +0000 (17:52 +0100)
committerAndreas Eversberg <jolly@eversberg.eu>
Wed, 1 Feb 2012 16:52:36 +0000 (17:52 +0100)
Since LCR does not put hands on any RTP frame when directly bridged between
OpenBSC and SIP, it will now allow all speech codecs that are commonly supported
by MS and remote SIP endpoint.

It must be noted that OpenBSC must support forwarding the codec types that
MS and remote SIP endpoints support.

Currently LCR negotiates the following codecs for GSM:
- Full Rate
- EFR
- AMR
- Half Rate

12 files changed:
gsm.cpp
gsm.h
gsm_bs.cpp
gsm_bs.h
gsm_ms.cpp
interface.c
interface.h
macro.h
main.h
message.h
sip.cpp
sip.h

diff --git a/gsm.cpp b/gsm.cpp
index 63f7545..2c1bace 100644 (file)
--- a/gsm.cpp
+++ b/gsm.cpp
@@ -27,6 +27,10 @@ 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 */
@@ -35,6 +39,7 @@ static const struct _value_string {
        const char *name;
 } mncc_names[] = {
        { 0,                    "New call ref" },
+       { 1,                    "Codec negotiation" },
        { MNCC_SETUP_REQ,       "MNCC_SETUP_REQ" },
        { MNCC_SETUP_IND,       "MNCC_SETUP_IND" },
        { MNCC_SETUP_RSP,       "MNCC_SETUP_RSP" },
@@ -82,6 +87,7 @@ static const struct _value_string {
        { MNCC_STOP_DTMF_REQ,   "MNCC_STOP_DTMF_REQ" },
        { MNCC_HOLD_REQ,        "MNCC_HOLD_REQ " },
        { MNCC_RETRIEVE_REQ,    "MNCC_RETRIEVE_REQ" },
+       { MNCC_LCHAN_MODIFY,    "MNCC_LCHAN_MODIFY" },
        { 0,                    NULL }
 };
 
@@ -139,6 +145,7 @@ Pgsm::Pgsm(int type, char *portname, struct port_settings *settings, struct inte
        p_g_rtp_bridge = 0;
        if (interface->rtp_bridge)
                p_g_rtp_bridge = 1;
+       p_g_rtp_payloads = 0;
        memset(&p_g_samples, 0, sizeof(p_g_samples));
        SCPY(p_g_interface_name, interface->name); 
        p_callerinfo.itype = (interface->extension)?INFO_ITYPE_ISDN_EXTENSION:INFO_ITYPE_ISDN;
@@ -161,6 +168,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;
 
        PDEBUG(DEBUG_GSM, "Created new GSMPort(%s).\n", portname);
 }
@@ -315,7 +323,7 @@ void gsm_trace_header(const char *interface_name, class Pgsm *port, unsigned int
                SCAT(msgtext, " ----");
 
        /* init trace with given values */
-       start_trace(0,
+       start_trace(-1,
                    interface,
                    port?numberrize_callerinfo(port->p_callerinfo.id, port->p_callerinfo.ntype, options.national, options.international):NULL,
                    port?port->p_dialinginfo.id:NULL,
@@ -325,31 +333,42 @@ void gsm_trace_header(const char *interface_name, class Pgsm *port, unsigned int
                    msgtext);
 }
 
-/* PROCEEDING INDICATION */
-void Pgsm::call_conf_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
+/* modify lchan to given payload type */
+void Pgsm::modify_lchan(unsigned char payload_type)
 {
        struct gsm_mncc *mode;
 
-       gsm_trace_header(p_g_interface_name, this, msg_type, DIRECTION_IN);
-       if (mncc->fields & MNCC_F_CAUSE) {
-               add_trace("cause", "coding", "%d", mncc->cause.coding);
-               add_trace("cause", "location", "%", mncc->cause.location);
-               add_trace("cause", "value", "%", mncc->cause.value);
-       }
-       end_trace();
+       /* already modified to that payload type */
+       if (p_g_payload_type == payload_type)
+               return;
 
-       /* modify lchan to GSM codec V1 */
+       p_g_payload_type = payload_type;
        gsm_trace_header(p_g_interface_name, this, MNCC_LCHAN_MODIFY, DIRECTION_OUT);
        mode = create_mncc(MNCC_LCHAN_MODIFY, p_g_callref);
-       mode->lchan_mode = 0x01; /* GSM V1 */
-       mode->lchan_type = 0x02;
+       switch (payload_type) {
+       case RTP_PT_GSM_EFR:
+               add_trace("speech", "version", "EFR given");
+               mode->lchan_mode = 0x21; /* GSM V2 */
+               break;
+       case RTP_PT_GSM_AMR:
+               add_trace("speech", "version", "AMR given");
+               mode->lchan_mode = 0x41; /* GSM V3 */
+               break;
+       case RTP_PT_GSM_HALF:
+               add_trace("speech", "version", "Half Rate given");
+               mode->lchan_mode = 0x05; /* GSM V1 */
+               break;
+       default:
+               add_trace("speech", "version", "Full Rate given");
+               mode->lchan_mode = 0x01; /* GSM V1 HR */
+       }
+       mode->lchan_type = 0x02; /* FIXME: unused */
        add_trace("mode", NULL, "0x%02x", mode->lchan_mode);
        end_trace();
        send_and_free_mncc(p_g_lcr_gsm, mode->msg_type, mode);
-
 }
 
-/* CALL PROCEEDING INDICATION */
+/* CALL PROCEEDING INDICATION (from network) */
 void Pgsm::call_proc_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
 {
        struct lcr_msg *message;
@@ -435,7 +454,17 @@ void Pgsm::setup_cnf(unsigned int msg_type, unsigned int callref, struct gsm_mnc
 
        message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_CONNECT);
        memcpy(&message->param.connectinfo, &p_connectinfo, sizeof(struct connect_info));
-       message->param.connectinfo.rtpinfo.payload_type = 3; /* FIXME: receive payload type from peer */
+
+       /* 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]);
+               }
+               message->param.connectinfo.rtpinfo.payload_types[0] = p_g_payload_type;
+               message->param.connectinfo.rtpinfo.payloads = 1;
+       }
 
        if (p_g_rtp_bridge) {
                struct gsm_mncc_rtp *rtp;
@@ -641,6 +670,9 @@ void Pgsm::message_progress(unsigned int epoint_id, int message_id, union parame
                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 accepted payload type */
+               modify_lchan(param->progressinfo.rtpinfo.payload_types[0]);
        }
 }
 
@@ -748,8 +780,10 @@ void Pgsm::message_connect(unsigned int epoint_id, int message_id, union paramet
                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]);
+       }
 }
 
 /* MESSAGE_DISCONNECT */
diff --git a/gsm.h b/gsm.h
index 671aab6..421a098 100644 (file)
--- a/gsm.h
+++ b/gsm.h
@@ -53,10 +53,13 @@ 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_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];
 
        void frame_send(void *_frame);
        void frame_receive(void *_frame);
@@ -64,7 +67,7 @@ class Pgsm : public Port
        int bridge_rx(unsigned char *data, int len);
 
        int hunt_bchannel(void);
-       void call_conf_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *gsm);
+       void modify_lchan(unsigned char payload_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);
index 29888be..ae763ca 100644 (file)
 
 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
+
 /*
  * DTMF stuff
  */
@@ -62,6 +67,74 @@ Pgsm_bs::~Pgsm_bs()
        PDEBUG(DEBUG_GSM, "Destroyed GSM BS process(%s).\n", p_name);
 }
 
+/* PROCEEDING INDICATION (from MS) */
+void Pgsm_bs::call_conf_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
+{
+       unsigned char payload_types[8];
+       int payloads = 0;
+
+       gsm_trace_header(p_g_interface_name, this, msg_type, DIRECTION_IN);
+       if (mncc->fields & MNCC_F_CAUSE) {
+               add_trace("cause", "coding", "%d", mncc->cause.coding);
+               add_trace("cause", "location", "%", mncc->cause.location);
+               add_trace("cause", "value", "%", mncc->cause.value);
+       }
+       end_trace();
+
+       new_state(PORT_STATE_OUT_PROCEEDING);
+
+       /* 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));
+       /* if no given payload type is supported, we assume  */
+       if (!payloads) {
+               payload_types[0] = RTP_PT_GSM_FULL;
+               payloads = 1;
+       }
+
+       /* select first payload type that matches the rtp list */
+       if (p_g_rtp_bridge) {
+               int i, j;
+
+               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])
+                                       break;
+                       }
+                       if (j < payloads)
+                               break;
+               }
+               if (i == p_g_rtp_payloads) {
+                       struct lcr_msg *message;
+
+                       /* payload offered by remote RTP is not supported */
+                       message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_RELEASE);
+                       message->param.disconnectinfo.cause = 65;
+                       message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
+                       message_put(message);
+                       /* send release */
+                       mncc = create_mncc(MNCC_REL_REQ, p_g_callref);
+                       gsm_trace_header(p_g_interface_name, this, MNCC_REL_REQ, DIRECTION_OUT);
+                       mncc->fields |= MNCC_F_CAUSE;
+                       mncc->cause.coding = 3;
+                       mncc->cause.location = LOCATION_PRIVATE_LOCAL;
+                       mncc->cause.value = 65;
+                       add_trace("cause", "coding", "%d", mncc->cause.coding);
+                       add_trace("cause", "location", "%d", mncc->cause.location);
+                       add_trace("cause", "value", "%d", mncc->cause.value);
+                       add_trace("reason", NULL, "None of the payload types are supported by MS");
+                       end_trace();
+                       send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc);
+                       new_state(PORT_STATE_RELEASE);
+                       trigger_work(&p_g_delete);
+               }
+               modify_lchan(p_g_rtp_payload_types[i]);
+       } else {
+               /* modify to first given payload */
+               modify_lchan(payload_types[0]);
+       }
+}
+
 /* DTMF INDICATION */
 void Pgsm_bs::start_dtmf_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
 {
@@ -204,6 +277,73 @@ void Pgsm_bs::retr_ind(unsigned int msg_type, unsigned int callref, struct gsm_m
 }
 
 /*
+ * select payload type by given list or GSM V1 FR 
+ * 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)
+{
+       unsigned char payload_type;
+
+       *payloads = 0;
+
+       gsm_trace_header(p_g_interface_name, this, 1 /* codec negotioation */, DIRECTION_NONE);
+       if ((mncc->fields & MNCC_F_BEARER_CAP)) {
+               /* select preferred payload type from list */
+               int i;
+
+               add_trace("bearer", "capa", "given by MS");
+               for (i = 0; mncc->bearer_cap.speech_ver[i] >= 0; i++) {
+                       /* select payload type we support */
+                       switch (mncc->bearer_cap.speech_ver[i]) {
+                       case 0:
+                               add_trace("speech", "version", "Full Rate given");
+                               payload_type = RTP_PT_GSM_FULL;
+                               break;
+                       case 2:
+                               add_trace("speech", "version", "EFR given");
+                               payload_type = RTP_PT_GSM_EFR;
+                               break;
+                       case 4:
+                               add_trace("speech", "version", "AMR given");
+                               payload_type = RTP_PT_GSM_AMR;
+                               break;
+                       case 1:
+                               add_trace("speech", "version", "Half Rate given");
+                               payload_type = RTP_PT_GSM_HALF;
+                               break;
+                       default:
+                               add_trace("speech", "version", "%d given", mncc->bearer_cap.speech_ver[i]);
+                               payload_type = 0;
+                       }
+                       /* wen don't support it, so we check the next */
+                       if (!payload_type) {
+                               add_trace("speech", "ignored", "Not supported by LCR");
+                               continue;
+                       }
+                       if (!p_g_rtp_bridge) {
+                               if (payload_type != RTP_PT_GSM_FULL) {
+                                       add_trace("speech", "ignored", "Not suitable for LCR");
+                                       continue;
+                               }
+                       }
+                       if (*payloads <= max_payloads) {
+                               payload_types[*payloads] = payload_type;
+                               (*payloads)++;
+                       }
+               }
+       } else {
+               add_trace("bearer", "capa", "not given by MS");
+               add_trace("speech", "version", "Full Rate given");
+               payload_types[0] = RTP_PT_GSM_FULL;
+               *payloads = 1;
+       }
+       if (!(*payloads))
+               add_trace("error", "", "All given payload types unsupported");
+       end_trace();
+}
+
+/*
  * handles all indications
  */
 /* SETUP INDICATION */
@@ -211,8 +351,10 @@ void Pgsm_bs::setup_ind(unsigned int msg_type, unsigned int callref, struct gsm_
 {
        class Endpoint *epoint;
        struct lcr_msg *message;
-       struct gsm_mncc *mode, *proceeding, *frame;
+       struct gsm_mncc *proceeding, *frame;
        struct interface *interface;
+       unsigned char payload_types[8];
+       int payloads = 0;
 
        interface = getinterfacebyname(p_g_interface_name);
        if (!interface) {
@@ -282,13 +424,41 @@ void Pgsm_bs::setup_ind(unsigned int msg_type, unsigned int callref, struct gsm_
        p_dialinginfo.sending_complete = 1;
 
        /* bearer capability */
-       // todo
        p_capainfo.bearer_capa = INFO_BC_SPEECH;
        p_capainfo.bearer_info1 = (options.law=='a')?3:2;
        p_capainfo.bearer_mode = INFO_BMODE_CIRCUIT;
        p_capainfo.source_mode = B_MODE_TRANSPARENT;
        p_g_mode = p_capainfo.source_mode;
 
+       /* 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));
+       /* if no given payload type is supported, we assume  */
+       if (!payloads) {
+               payload_types[0] = RTP_PT_GSM_FULL;
+               payloads = 1;
+       }
+#if 0
+       /* if no given payload type is supported, we reject the call */
+       if (!payloads) {
+               mncc = create_mncc(MNCC_REJ_REQ, callref);
+               gsm_trace_header(p_g_interface_name, this, MNCC_REJ_REQ, DIRECTION_OUT);
+               mncc->fields |= MNCC_F_CAUSE;
+               mncc->cause.coding = 3;
+               mncc->cause.location = 1;
+               mncc->cause.value = 65;
+               add_trace("cause", "coding", "%d", mncc->cause.coding);
+               add_trace("cause", "location", "%d", mncc->cause.location);
+               add_trace("cause", "value", "%d", mncc->cause.value);
+               add_trace("reason", NULL, "Given speech codec(s) not supported");
+               end_trace();
+               send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc);
+               new_state(PORT_STATE_RELEASE);
+               trigger_work(&p_g_delete);
+               return;
+       }
+#endif
+
        /* useruser */
 
        /* what infos did we got ... */
@@ -309,14 +479,9 @@ void Pgsm_bs::setup_ind(unsigned int msg_type, unsigned int callref, struct gsm_
        epoint->ep_app = new_endpointapp(epoint, 0, interface->app); //incoming
        epointlist_new(epoint->ep_serial);
 
-       /* modify lchan to GSM codec V1 */
-       gsm_trace_header(p_g_interface_name, this, MNCC_LCHAN_MODIFY, DIRECTION_OUT);
-       mode = create_mncc(MNCC_LCHAN_MODIFY, p_g_callref);
-       mode->lchan_mode = 0x01; /* GSM V1 */
-       mode->lchan_type = 0x02;
-       add_trace("mode", NULL, "0x%02x", mode->lchan_mode);
-       end_trace();
-       send_and_free_mncc(p_g_lcr_gsm, mode->msg_type, mode);
+       /* modify lchan in case of no rtp bridge */
+       if (!p_g_rtp_bridge)
+               modify_lchan(payload_types[0]);
 
        /* send call proceeding */
        gsm_trace_header(p_g_interface_name, this, MNCC_CALL_PROC_REQ, DIRECTION_OUT);
@@ -353,15 +518,20 @@ void Pgsm_bs::setup_ind(unsigned int msg_type, unsigned int callref, struct gsm_
        SCPY((char *)message->param.setup.useruser.data, (char *)mncc->useruser.info);
        message->param.setup.useruser.len = strlen(mncc->useruser.info);
        message->param.setup.useruser.protocol = mncc->useruser.proto;
-       message->param.setup.rtpinfo.payload_type = 3; /* FIXME: receive payload type from peer */
-
        if (p_g_rtp_bridge) {
                struct gsm_mncc_rtp *rtp;
+               int i;
 
                PDEBUG(DEBUG_GSM, "Request RTP peer info, before forwarding setup\n");
                p_g_setup_pending = message;
                rtp = (struct gsm_mncc_rtp *) create_mncc(MNCC_RTP_CREATE, p_g_callref);
                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.payload_types[i] = payload_types[i];
+                       message->param.setup.rtpinfo.payloads++;
+               }
+
        } else
                message_put(message);
 
@@ -562,6 +732,43 @@ void Pgsm_bs::message_setup(unsigned int epoint_id, int message_id, union parame
                return;
        }
 
+       /* unsupported codec for RTP bridge */
+       if (param->setup.rtpinfo.port) {
+               int i;
+
+               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]);
+                               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_payloads++;
+                               }
+                               break;
+                       default:
+                               add_trace("rtp", "payload", "%d unsupported", param->setup.rtpinfo.payload_types[i]);
+                       }
+               }
+               end_trace();
+               if (!p_g_rtp_payloads) {
+                       gsm_trace_header(p_g_interface_name, this, MNCC_SETUP_REQ, DIRECTION_OUT);
+                       add_trace("failure", NULL, "No payload given that is supported by GSM");
+                       end_trace();
+                       message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
+                       message->param.disconnectinfo.cause = 65;
+                       message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
+                       message_put(message);
+                       new_state(PORT_STATE_RELEASE);
+                       trigger_work(&p_g_delete);
+                       return;
+               }
+       }
+
 //             SCPY(&p_m_tones_dir, param->setup.ext.tones_dir);
        /* screen outgoing caller id */
        do_screen(1, p_callerinfo.id, sizeof(p_callerinfo.id), &p_callerinfo.ntype, &p_callerinfo.present, p_g_interface_name);
@@ -691,8 +898,6 @@ void Pgsm_bs::message_setup(unsigned int epoint_id, int message_id, union parame
                add_trace("redir", "screen", "%d", mncc->redirecting.screen);
                add_trace("redir", "number", "%s", mncc->redirecting.number);
        }
-       /* bearer capability */
-       //todo
 
        end_trace();
        send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc);
@@ -702,8 +907,6 @@ void Pgsm_bs::message_setup(unsigned int epoint_id, int message_id, union parame
        message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_PROCEEDING);
        message_put(message);
 
-       new_state(PORT_STATE_OUT_PROCEEDING);
-
        /* RTP bridge */
        if (param->setup.rtpinfo.port) {
                p_g_rtp_bridge = 1;
index 81e1f13..b60c02c 100644 (file)
--- a/gsm_bs.h
+++ b/gsm_bs.h
@@ -9,7 +9,9 @@ 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 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);
        void stop_dtmf_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc);
        void hold_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc);
index bb2ad67..0cbcca1 100644 (file)
@@ -23,6 +23,8 @@ static int dtmf_timeout(struct lcr_timer *timer, void *instance, int index);
 #define DTMF_ST_STOP           3       /* DTMF stopped, waiting for resp. */
 #define DTMF_ST_SPACE          4       /* wait space between tones */
 
+#define RTP_PT_GSM_FULL                3
+
 /*
  * constructor
  */
@@ -67,7 +69,7 @@ void Pgsm_ms::setup_ind(unsigned int msg_type, unsigned int callref, struct gsm_
 {
        class Endpoint *epoint;
        struct lcr_msg *message;
-       struct gsm_mncc *mode, *proceeding, *frame;
+       struct gsm_mncc *proceeding, *frame;
        struct interface *interface;
 
        interface = getinterfacebyname(p_g_interface_name);
@@ -275,13 +277,7 @@ void Pgsm_ms::setup_ind(unsigned int msg_type, unsigned int callref, struct gsm_
        epointlist_new(epoint->ep_serial);
 
        /* modify lchan to GSM codec V1 */
-       gsm_trace_header(p_g_interface_name, this, MNCC_LCHAN_MODIFY, DIRECTION_OUT);
-       mode = create_mncc(MNCC_LCHAN_MODIFY, p_g_callref);
-       mode->lchan_mode = 0x01; /* GSM V1 */
-       mode->lchan_type = 0x02;
-       add_trace("mode", NULL, "0x%02x", mode->lchan_mode);
-       end_trace();
-       send_and_free_mncc(p_g_lcr_gsm, mode->msg_type, mode);
+       modify_lchan(RTP_PT_GSM_FULL);
 
        /* send call proceeding */
        gsm_trace_header(p_g_interface_name, this, MNCC_CALL_CONF_REQ, DIRECTION_OUT);
index 7a00735..365e843 100644 (file)
@@ -981,10 +981,53 @@ static int inter_sip(struct interface *interface, char *filename, int line, char
 }
 static int inter_rtp_bridge(struct interface *interface, char *filename, int line, char *parameter, char *value)
 {
+       int supported = 0;
+
+#ifdef WITH_GSM_BS
+       if (interface->gsm_bs)
+               supported = 1;
+#endif
+#ifdef WITH_SIP
+       if (interface->sip)
+               supported = 1;
+#endif
+       if (!supported) {
+               SPRINT(interface_error, "Error in %s (line %d): Interface does not support RTP\n", filename, line);
+               return(-1);
+       }
        interface->rtp_bridge = 1;
 
        return(0);
 }
+#if 0
+static int inter_rtp_payload(struct interface *interface, char *filename, int line, char *parameter, char *value)
+{
+#ifndef WITH_GSM_BS
+       SPRINT(interface_error, "Error in %s (line %d): GSM BS side not compiled in.\n", filename, line);
+       return(-1);
+#else
+       if (!interface->gsm_bs) {
+               SPRINT(interface_error, "Error in %s (line %d): This parameter only works for GSM BS side interface\n", filename, line);
+               return(-1);
+       }
+       if (!interface->rtp_bridge) {
+               SPRINT(interface_error, "Error in %s (line %d): This parameter only works here, if RTP bridging is enabled\n", filename, line);
+               return(-1);
+       }
+       if (!value[0]) {
+               SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects one payload type\n", filename, line, parameter);
+               return(-1);
+       }
+       if (interface->gsm_bs_payloads == sizeof(interface->gsm_bs_payload_types)) {
+               SPRINT(interface_error, "Error in %s (line %d): Too many payload types defined\n", filename, line);
+               return(-1);
+       }
+       interface->gsm_bs_payload_types[interface->gsm_bs_payloads++] = atoi(value);
+
+       return(0);
+#endif
+}
+#endif
 static int inter_nonotify(struct interface *interface, char *filename, int line, char *parameter, char *value)
 {
        struct interface_port *ifport;
@@ -1245,8 +1288,15 @@ struct interface_param interface_param[] = {
        "Sets up SIP interface that represents one SIP endpoint.\n"
        "Give SIP configuration file."},
        {"rtp-bridge", &inter_rtp_bridge, "",
-       "Sets up SIP interface that represents one SIP endpoint.\n"
-       "Give SIP configuration file."},
+       "Enables RTP bridging directly from this interface.\n"
+       "This only works, if both ends support RTP. (like gsm-bs and sip)"},
+#if 0
+       not needed, since ms defines what is supports and remote (sip) tells what is selected
+       {"rtp-payload", &inter_rtp_payload, "<codec>",
+       "Define RTP payload to use. Only valid in conjuntion with gsm-bs!\n"
+       "If multiple payloads are defined, the first has highest priority.\n"
+       "If none are defined, GSM fullrate V1 (type 3) is assumed.\n"},
+#endif
        {"nonotify", &inter_nonotify, "",
        "Prevents sending notify messages to this interface. A call placed on hold will\n"
        "Not affect the remote end (phone or telcom switch).\n"
index 93fb1b6..cf1b192 100644 (file)
@@ -108,6 +108,10 @@ struct interface {
        int                     bf_len; /* filter length of blowfish */
 #ifdef WITH_GSM_BS
        int                     gsm_bs; /* interface is an GSM BS interface */
+#if 0
+       int                     gsm_bs_payloads;
+       unsigned char           gsm_bs_payload_types[8];
+#endif
 #endif
 #ifdef WITH_GSM_MS
        int                     gsm_ms; /* interface is an GSM MS interface */
diff --git a/macro.h b/macro.h
index 5d2bce5..e4a2f2e 100644 (file)
--- a/macro.h
+++ b/macro.h
@@ -22,10 +22,10 @@ static inline void scpy(char *dst, const char *src, unsigned int siz)
 
 /* safe strcat/strncat */
 
-#define SCAT(dst, src) scat(dst, src, sizeof(dst)-strlen(dst)-1)
+#define SCAT(dst, src) scat(dst, src, sizeof(dst))
 static inline void scat(char *dst, const char *src, unsigned int siz)
 {
-       strncat(dst, src, siz);
+       strncat(dst, src, siz-strlen(dst)-1);
        dst[siz-1] = '\0';
 }
 
diff --git a/main.h b/main.h
index 5fac1ef..8d8b448 100644 (file)
--- a/main.h
+++ b/main.h
@@ -118,6 +118,8 @@ void debug(const char *file, const char *function, int line, const char *prefix,
  */
 //#define BUDETECT_DEF
 
+/* internal limit of payload type in a message */
+
 #ifdef BUDETECT_DEF
  #define BUDETECT      budetect(__FILE__, __LINE__, __FUNCTION__);
  void budetect(const char *file, int line, const char *function);
index 6330654..ce6ed03 100644 (file)
--- a/message.h
+++ b/message.h
@@ -150,9 +150,10 @@ enum {
 
 /* rtp-info structure */
 struct rtp_info {
-       int payload_type;
-       unsigned int ip;
-       unsigned short port;
+       int payloads;                   /* number of payloads offered */
+       unsigned char payload_types[32];/* rtp payload types */
+       unsigned int ip;                /* peer's IP */
+       unsigned short port;            /* peer's port */
 };
 
 /* call-info structure CALLER */
diff --git a/sip.cpp b/sip.cpp
index cd03566..92f11b2 100644 (file)
--- a/sip.cpp
+++ b/sip.cpp
@@ -51,7 +51,6 @@ Psip::Psip(int type, char *portname, struct port_settings *settings, struct inte
        memset(&p_s_rtcp_sin_local, 0, sizeof(p_s_rtcp_sin_local));
        memset(&p_s_rtp_sin_remote, 0, sizeof(p_s_rtp_sin_remote));
        memset(&p_s_rtcp_sin_remote, 0, sizeof(p_s_rtcp_sin_remote));
-       p_s_rtp_payload_type = 0;
        p_s_rtp_ip_local = 0;
        p_s_rtp_ip_remote = 0;
        p_s_rtp_port_local = 0;
@@ -145,7 +144,7 @@ struct rtp_x_hdr {
 #define RTP_PT_GSM_FULL 3
 #define RTP_PT_GSM_HALF 96
 #define RTP_PT_GSM_EFR 97
-#define RTP_PT_AMR 98
+#define RTP_PT_GSM_AMR 98
 
 /* decode an rtp frame  */
 static int rtp_decode(class Psip *psip, unsigned char *data, int len)
@@ -220,6 +219,14 @@ static int rtp_decode(class Psip *psip, unsigned char *data, int len)
                        return -EINVAL;
                }
                break;
+       case RTP_PT_GSM_HALF:
+               if (payload_len != 14) {
+                       PDEBUG(DEBUG_SIP, "received RTP half rate frame with "
+                               "payload length != 14 (len = %d)\n",
+                               payload_len);
+                       return -EINVAL;
+               }
+               break;
        case RTP_PT_ALAW:
                if (options.law != 'a') {
                        PDEBUG(DEBUG_SIP, "received Alaw, but we don't do Alaw\n");
@@ -469,6 +476,10 @@ int Psip::rtp_send_frame(unsigned char *data, unsigned int len, uint8_t payload_
                payload_len = 31;
                duration = 160;
                break;
+       case RTP_PT_GSM_HALF:
+               payload_len = 14;
+               duration = 160;
+               break;
        case RTP_PT_ALAW:
        case RTP_PT_ULAW:
                payload_len = len;
@@ -722,18 +733,20 @@ 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;
+       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;
-               p_s_rtp_payload_type = param->connectinfo.rtpinfo.payload_type;
+               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;
+               PDEBUG(DEBUG_SIP, "payload type %d\n", payload_type);
                PDEBUG(DEBUG_SIP, "local ip %08x port %d\n", p_s_rtp_ip_local, p_s_rtp_port_local);
                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");
-               p_s_rtp_payload_type = (options.law=='a') ? RTP_PT_ALAW : RTP_PT_ULAW;
+               payload_type = (options.law=='a') ? RTP_PT_ALAW : RTP_PT_ULAW;
                /* open local RTP peer (if not bridging) */
                if (rtp_connect() < 0) {
                        nua_cancel(p_s_handle, TAG_END());
@@ -762,7 +775,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, 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, payload_type, payload_type, payload_type2name(payload_type));
        PDEBUG(DEBUG_SIP, "Using SDP response: %s\n", sdp_str);
 
        nua_respond(p_s_handle, SIP_200_OK,
@@ -773,6 +786,9 @@ int Psip::message_connect(unsigned int epoint_id, int message_id, union paramete
        sip_trace_header(this, "RESPOND", DIRECTION_OUT);
        add_trace("respond", "value", "200 OK");
        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);
        end_trace();
 
        return 0;
@@ -849,11 +865,15 @@ int Psip::message_setup(unsigned int epoint_id, int message_id, union parameter
        char to[128];
        const char *local = inst->local_ip;
        const char *remote = inst->remote_ip;
-       char sdp_str[256];
+       char sdp_str[256], pt_str[32];
        struct in_addr ia;
        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 };
+       unsigned char *payload_types;
+       int payloads = 0;
+       int i;
 
        PDEBUG(DEBUG_SIP, "Doing Setup (inst %p)\n", inst);
 
@@ -864,7 +884,8 @@ 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;
-               p_s_rtp_payload_type = param->setup.rtpinfo.payload_type;
+               payload_types = param->setup.rtpinfo.payload_types;
+               payloads = param->setup.rtpinfo.payloads;
                p_s_rtp_ip_local = param->setup.rtpinfo.ip;
                p_s_rtp_port_local = param->setup.rtpinfo.port;
                PDEBUG(DEBUG_SIP, "local ip %08x port %d\n", p_s_rtp_ip_local, p_s_rtp_port_local);
@@ -872,7 +893,8 @@ 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;
-               p_s_rtp_payload_type = (options.law=='a') ? RTP_PT_ALAW : RTP_PT_ULAW;
+               payload_types = &lcr_payload;
+               payloads = 1;
 
                /* open local RTP peer (if not bridging) */
                if (rtp_open() < 0) {
@@ -887,14 +909,6 @@ int Psip::message_setup(unsigned int epoint_id, int message_id, union parameter
                        return 0;
                }
        }
-       SPRINT(from, "sip:%s@%s", param->setup.callerinfo.id, local);
-       SPRINT(to, "sip:%s@%s", param->setup.dialinginfo.id, remote);
-
-       sip_trace_header(this, "INVITE", DIRECTION_OUT);
-       add_trace("from", "uri", "%s", from);
-       add_trace("to", "uri", "%s", to);
-       add_trace("rtp", "port", "%d,%d", p_s_rtp_port_local, p_s_rtp_port_local + 1);
-       end_trace();
 
        p_s_handle = nua_handle(inst->nua, NULL, TAG_END());
        if (!p_s_handle) {
@@ -925,11 +939,31 @@ int Psip::message_setup(unsigned int epoint_id, int message_id, union parameter
                "s=SIP Call\n"
                "c=IN IP4 %s\n"
                "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));
+               "m=audio %d RTP/AVP"
+               , inet_ntoa(ia), inet_ntoa(ia), p_s_rtp_port_local);
+       for (i = 0; i < payloads; i++) {
+               SPRINT(pt_str, " %d", payload_types[i]);
+               SCAT(sdp_str, pt_str);
+       }
+       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]));
+               SCAT(sdp_str, pt_str);
+       }
        PDEBUG(DEBUG_SIP, "Using SDP for invite: %s\n", sdp_str);
 
+       SPRINT(from, "sip:%s@%s", param->setup.callerinfo.id, local);
+       SPRINT(to, "sip:%s@%s", param->setup.dialinginfo.id, remote);
+
+       sip_trace_header(this, "INVITE", DIRECTION_OUT);
+       add_trace("from", "uri", "%s", from);
+       add_trace("to", "uri", "%s", to);
+       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]);
+       end_trace();
+
 //     cseq = sip_cseq_create(sip_home, 123, SIP_METHOD_INVITE);
 
        nua_invite(p_s_handle,
@@ -947,7 +981,7 @@ int Psip::message_setup(unsigned int epoint_id, int message_id, union parameter
        message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_OVERLAP);
        message_put(message);
 #else
-       PDEBUG(DEBUG_SIP, "do overlap\n");
+       PDEBUG(DEBUG_SIP, "do proceeding\n");
        new_state(PORT_STATE_OUT_PROCEEDING);
        message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_PROCEEDING);
        message_put(message);
@@ -1112,9 +1146,9 @@ 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_type)
+int Psip::parse_sdp(sip_t const *sip, unsigned int *ip, unsigned short *port, uint8_t *payload_types, int *payloads, int max_payloads)
 {
-       int codec_supported = 0;
+       *payloads = 0;
 
        if (!sip->sip_payload) {
                PDEBUG(DEBUG_SIP, "no payload given\n");
@@ -1173,20 +1207,17 @@ int Psip::parse_sdp(sip_t const *sip, unsigned int *ip, unsigned short *port, ui
                }
                for (map = m->m_rtpmaps; map; map = map->rm_next) {
                        PDEBUG(DEBUG_SIP, "RTPMAP: coding:'%s' rate='%d' pt='%d'\n", map->rm_encoding, map->rm_rate, map->rm_pt);
-                       if (map->rm_pt == payload_type) {
-                               PDEBUG(DEBUG_SIP, "supported codec found\n");
-                               codec_supported = 1;
-                               goto done_codec;
+                       /* append to payload list, if there is space */
+                       add_trace("rtp", "payload", "%d", map->rm_pt);
+                       if (*payloads <= max_payloads) {
+                               *payload_types++ = map->rm_pt;
+                               (*payloads)++;
                        }
                }
        }
-       done_codec:
 
        sdp_parser_free(parser);
 
-       if (!codec_supported)
-               return 415;
-
        return 0;
 }
 
@@ -1197,8 +1228,9 @@ void Psip::i_invite(int status, char const *phrase, nua_t *nua, nua_magic_t *mag
        int ret;
        class Endpoint *epoint;
        struct lcr_msg *message;
-       uint8_t payload_type;
        struct interface *interface;
+       uint8_t payload_types[32];
+       int payloads = 0;
 
        interface = getinterfacebyname(inst->interface_name);
        if (!interface) {
@@ -1212,11 +1244,25 @@ void Psip::i_invite(int status, char const *phrase, nua_t *nua, nua_magic_t *mag
                to = sip->sip_to->a_url->url_user;
        PDEBUG(DEBUG_SIP, "invite received (%s->%s)\n", from, to);
 
-       if (p_s_rtp_bridge)
-               payload_type = 3; // FIXME: use list and forward list to remote side
-       else
-               payload_type = (options.law=='a')?RTP_PT_ALAW:RTP_PT_ULAW;
-       ret = parse_sdp(sip, &p_s_rtp_ip_remote, &p_s_rtp_port_remote, payload_type);
+       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));
+       if (!ret) {
+               /* if no RTP bridge, we must support LAW codec, otherwise we forward what we have */
+               if (!p_s_rtp_bridge) {
+                       int i;
+
+                       /* 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))
+                                       break;
+                       }
+                       if (i == payloads) {
+                               add_trace("error", NULL, "Expected LAW payload type (not bridged)");
+                               ret = 415;
+                       }
+               }
+       }
+       end_trace();
        if (ret) {
                if (ret == 400)
                        nua_respond(nh, SIP_400_BAD_REQUEST, TAG_END());
@@ -1317,10 +1363,17 @@ void Psip::i_invite(int status, char const *phrase, nua_t *nua, nua_magic_t *mag
 //     message->param.setup.useruser.len = strlen(mncc->useruser.info);
 //     message->param.setup.useruser.protocol = mncc->useruser.proto;
        if (p_s_rtp_bridge) {
+               int i;
+
                PDEBUG(DEBUG_SIP, "sending setup with RTP info\n");
-               message->param.setup.rtpinfo.payload_type = payload_type;
                message->param.setup.rtpinfo.ip = p_s_rtp_ip_remote;
                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))
+                               break;
+               }
        }
        message_put(message);
 }
@@ -1417,6 +1470,8 @@ 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;
+       uint8_t payload_types[32];
+       int payloads = 0;
 
        PDEBUG(DEBUG_SIP, "response to invite received (status = %d)\n", status);
 
@@ -1427,20 +1482,24 @@ void Psip::r_invite(int status, char const *phrase, nua_t *nua, nua_magic_t *mag
        /* connect audio */
        if (status == 183 || (status >= 200 && status <= 299)) {
                int ret;
-               uint8_t payload_type;
 
-               if (p_s_rtp_bridge)
-                       payload_type = p_s_rtp_payload_type;
-               else
-                       payload_type = (options.law=='a')?RTP_PT_ALAW:RTP_PT_ULAW;
-               ret = parse_sdp(sip, &p_s_rtp_ip_remote, &p_s_rtp_port_remote, payload_type);
+               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));
+               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)) {
+                                       add_trace("error", NULL, "Expected LAW payload type (not bridged)");
+                                       ret = 415;
+                               }
+                       }
+               }
+               end_trace();
                if (ret) {
-                       if (ret == 400)
-                               nua_cancel(nh, TAG_END());
-                       else
-                               nua_cancel(nh, TAG_END());
+                       nua_cancel(nh, TAG_END());
                        sip_trace_header(this, "CANCEL", DIRECTION_OUT);
-                       add_trace("reason", NULL, "offered codec does not match");
+                       add_trace("reason", NULL, "accepted codec does not match");
                        end_trace();
                        cause = 88;
                        location = LOCATION_PRIVATE_LOCAL;
@@ -1481,9 +1540,10 @@ void Psip::r_invite(int status, char const *phrase, nua_t *nua, nua_magic_t *mag
                message->param.progressinfo.progress = 8;
                message->param.progressinfo.location = 10;
                if (p_s_rtp_bridge) {
-                       message->param.progressinfo.rtpinfo.payload_type = p_s_rtp_payload_type;
                        message->param.progressinfo.rtpinfo.ip = p_s_rtp_ip_remote;
                        message->param.progressinfo.rtpinfo.port = p_s_rtp_port_remote;
+                       message->param.progressinfo.rtpinfo.payload_types[0] = payload_types[0];
+                       message->param.progressinfo.rtpinfo.payloads = 1;
                }
                message_put(message);
                return;
@@ -1502,9 +1562,10 @@ void Psip::r_invite(int status, char const *phrase, nua_t *nua, nua_magic_t *mag
                new_state(PORT_STATE_CONNECT);
                message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_CONNECT);
                if (p_s_rtp_bridge) {
-                       message->param.connectinfo.rtpinfo.payload_type = p_s_rtp_payload_type;
                        message->param.connectinfo.rtpinfo.ip = p_s_rtp_ip_remote;
                        message->param.connectinfo.rtpinfo.port = p_s_rtp_port_remote;
+                       message->param.connectinfo.rtpinfo.payload_types[0] = payload_types[0];
+                       message->param.connectinfo.rtpinfo.payloads = 1;
                }
                message_put(message);
                return;
diff --git a/sip.h b/sip.h
index 8fd420b..9e8194e 100644 (file)
--- a/sip.h
+++ b/sip.h
@@ -35,7 +35,6 @@ class Psip : public Port
        nua_handle_t *p_s_handle;
        nua_magic_t *p_s_magic;
        int p_s_rtp_bridge; /* bridge RTP instead of having a local RTP peer */
-       uint8_t p_s_rtp_payload_type;
        unsigned short p_s_rtp_port_local;
        unsigned short p_s_rtp_port_remote;
        unsigned int p_s_rtp_ip_local;
@@ -63,7 +62,7 @@ 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_type);
+       int parse_sdp(sip_t const *sip, unsigned int *ip, unsigned short *port, uint8_t *payload_types, int *payloads, int max_payloads);
        void rtp_shutdown(void);
 };