Allow dynamic RTP payload types when bridging between SIP and OpenBSC.
authorAndreas Eversberg <jolly@eversberg.eu>
Fri, 17 Feb 2012 14:38:54 +0000 (15:38 +0100)
committerAndreas Eversberg <jolly@eversberg.eu>
Fri, 17 Feb 2012 14:38:54 +0000 (15:38 +0100)
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
gsm.h
gsm_bs.cpp
gsm_bs.h
message.h
mncc.h
sip.cpp
sip.h

diff --git a/gsm.cpp b/gsm.cpp
index 2c1bace..a4a220e 100644 (file)
--- 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 (file)
--- 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);
index ae763ca..92a2ffc 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
+#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();
index b60c02c..5575daa 100644 (file)
--- 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);
index ce6ed03..82df9d5 100644 (file)
--- 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 (file)
--- a/mncc.h
+++ b/mncc.h
 #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 (file)
--- 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 (file)
--- 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);