summaryrefslogtreecommitdiff
path: root/pjmedia
diff options
context:
space:
mode:
authorNanang Izzuddin <nanang@teluu.com>2008-08-25 13:58:25 +0000
committerNanang Izzuddin <nanang@teluu.com>2008-08-25 13:58:25 +0000
commit920d97341f9c044fd012f6b41fff01e4c9563a16 (patch)
treed34b163083b56edc8c7196667a05000da4091358 /pjmedia
parent6ddea349e453f1a4147ab10f55726079c1bc4d96 (diff)
Ticket #599:
- Added "dec_fmtp" and "enc_fmtp" fields to pjmedia_codec_param.setting. - Codec factory puts its default parameters in "dec_fmtp" field. - pjmedia_stream_info_from_sdp() puts the "fmtp" attribute in SDP to pjmedia_codec_param. - Special treatment for fmtp "bitrate" parameter (of G722.1) during SDP negotiation - Added maxptime field in stream_info. - Replaced iLBC's fmtp "mode" implementation to use general fmtp mechanism. - Added some test scripts for G722.1 bitrate negotiation. git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@2236 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjmedia')
-rw-r--r--pjmedia/include/pjmedia-codec/types.h4
-rw-r--r--pjmedia/include/pjmedia/codec.h19
-rw-r--r--pjmedia/include/pjmedia/stream.h1
-rw-r--r--pjmedia/src/pjmedia-codec/ilbc.c60
-rw-r--r--pjmedia/src/pjmedia-codec/ipp_codecs.c86
-rw-r--r--pjmedia/src/pjmedia/endpoint.c57
-rw-r--r--pjmedia/src/pjmedia/sdp_neg.c67
-rw-r--r--pjmedia/src/pjmedia/session.c121
8 files changed, 316 insertions, 99 deletions
diff --git a/pjmedia/include/pjmedia-codec/types.h b/pjmedia/include/pjmedia-codec/types.h
index 32f55250..a749b576 100644
--- a/pjmedia/include/pjmedia-codec/types.h
+++ b/pjmedia/include/pjmedia-codec/types.h
@@ -61,7 +61,9 @@ enum
PJMEDIA_RTP_PT_G726_24, /**< G726 @ 24Kbps */
/* PJMEDIA_RTP_PT_G726_32,*/ /**< G726 @ 32Kbps, static? */
PJMEDIA_RTP_PT_G726_40, /**< G726 @ 40Kbps */
- PJMEDIA_RTP_PT_G722_1, /**< G722.1 (16-32Kbps) */
+ PJMEDIA_RTP_PT_G722_1_16, /**< G722.1 (16Kbps) */
+ PJMEDIA_RTP_PT_G722_1_24, /**< G722.1 (24Kbps) */
+ PJMEDIA_RTP_PT_G722_1_32, /**< G722.1 (32Kbps) */
};
diff --git a/pjmedia/include/pjmedia/codec.h b/pjmedia/include/pjmedia/codec.h
index 55459f41..0241e229 100644
--- a/pjmedia/include/pjmedia/codec.h
+++ b/pjmedia/include/pjmedia/codec.h
@@ -238,6 +238,21 @@ typedef struct pjmedia_codec_info
unsigned channel_cnt; /**< Channel count. */
} pjmedia_codec_info;
+#define PJMEDIA_CODEC_MAX_FMTP_CNT 8
+
+/**
+ * Structure of codec specific parameters which contains name=value pairs.
+ * The codec specific parameters are to be used with SDP according to
+ * the standards (e.g: RFC 3555).
+ */
+typedef struct pjmedia_codec_fmtp
+{
+ pj_uint8_t cnt;
+ struct param {
+ pj_str_t name;
+ pj_str_t val;
+ } param [PJMEDIA_CODEC_MAX_FMTP_CNT];
+} pjmedia_codec_fmtp;
/**
* Detailed codec attributes used both to configure a codec and to query
@@ -277,8 +292,8 @@ typedef struct pjmedia_codec_param
unsigned penh:1; /**< Perceptual Enhancement */
unsigned plc:1; /**< Packet loss concealment */
unsigned reserved:1; /**< Reserved, must be zero. */
- pj_uint8_t enc_fmtp_mode; /**< Mode param in fmtp (def:0) */
- pj_uint8_t dec_fmtp_mode; /**< Mode param in fmtp (def:0) */
+ pjmedia_codec_fmtp enc_fmtp;/**< Encoder's fmtp params. */
+ pjmedia_codec_fmtp dec_fmtp;/**< Decoder's fmtp params. */
} setting;
} pjmedia_codec_param;
diff --git a/pjmedia/include/pjmedia/stream.h b/pjmedia/include/pjmedia/stream.h
index 59ae0749..b14ef377 100644
--- a/pjmedia/include/pjmedia/stream.h
+++ b/pjmedia/include/pjmedia/stream.h
@@ -108,6 +108,7 @@ struct pjmedia_stream_info
pjmedia_codec_info fmt; /**< Incoming codec format info. */
pjmedia_codec_param *param; /**< Optional codec param. */
unsigned tx_pt; /**< Outgoing codec paylaod type. */
+ unsigned tx_maxptime;/**< Outgoing codec max ptime. */
int tx_event_pt;/**< Outgoing pt for telephone-events. */
int rx_event_pt;/**< Incoming pt for telephone-events. */
pj_uint32_t ssrc; /**< RTP SSRC. */
diff --git a/pjmedia/src/pjmedia-codec/ilbc.c b/pjmedia/src/pjmedia-codec/ilbc.c
index 2b8e5fb6..65063167 100644
--- a/pjmedia/src/pjmedia-codec/ilbc.c
+++ b/pjmedia/src/pjmedia-codec/ilbc.c
@@ -143,7 +143,7 @@ struct ilbc_codec
float dec_block[BLOCKL_MAX];
};
-
+static pj_str_t STR_MODE = {"mode", 4};
/*
* Initialize and register iLBC codec factory to pjmedia endpoint.
@@ -273,7 +273,12 @@ static pj_status_t ilbc_default_attr (pjmedia_codec_factory *factory,
attr->setting.vad = 1;
attr->setting.plc = 1;
attr->setting.penh = 1;
- attr->setting.dec_fmtp_mode = (pj_uint8_t)ilbc_factory.mode;
+ attr->setting.dec_fmtp.cnt = 1;
+ attr->setting.dec_fmtp.param[0].name = STR_MODE;
+ if (ilbc_factory.mode == 30)
+ attr->setting.dec_fmtp.param[0].val = pj_str("30");
+ else
+ attr->setting.dec_fmtp.param[0].val = pj_str("20");
return PJ_SUCCESS;
}
@@ -370,46 +375,65 @@ static pj_status_t ilbc_codec_open(pjmedia_codec *codec,
{
struct ilbc_codec *ilbc_codec = (struct ilbc_codec*)codec;
pj_status_t status;
+ unsigned i, dec_fmtp_mode = 0, enc_fmtp_mode = 0;
pj_assert(ilbc_codec != NULL);
pj_assert(ilbc_codec->enc_ready == PJ_FALSE &&
ilbc_codec->dec_ready == PJ_FALSE);
+ /* Get decoder mode */
+ for (i = 0; i < attr->setting.dec_fmtp.cnt; ++i) {
+ if (pj_stricmp(&attr->setting.dec_fmtp.param[i].name, &STR_MODE) == 0)
+ {
+ dec_fmtp_mode = (unsigned)
+ pj_strtoul(&attr->setting.dec_fmtp.param[i].val);
+ break;
+ }
+ }
+
/* Decoder mode must be set */
- PJ_ASSERT_RETURN(attr->setting.dec_fmtp_mode==20 ||
- attr->setting.dec_fmtp_mode==30, PJMEDIA_CODEC_EINMODE);
+ PJ_ASSERT_RETURN(dec_fmtp_mode == 20 || dec_fmtp_mode == 30,
+ PJMEDIA_CODEC_EINMODE);
+
+ /* Get encoder mode */
+ for (i = 0; i < attr->setting.enc_fmtp.cnt; ++i) {
+ if (pj_stricmp(&attr->setting.enc_fmtp.param[i].name, &STR_MODE) == 0)
+ {
+ enc_fmtp_mode = (unsigned)
+ pj_strtoul(&attr->setting.enc_fmtp.param[i].val);
+ break;
+ }
+ }
/* The enc mode must be set in the attribute
* (from the mode parameter in fmtp attribute in the SDP
* received from remote)
*/
- if (attr->setting.enc_fmtp_mode == 0)
- attr->setting.enc_fmtp_mode = attr->setting.dec_fmtp_mode;
+ if (enc_fmtp_mode == 0)
+ enc_fmtp_mode = dec_fmtp_mode;
- PJ_ASSERT_RETURN(attr->setting.enc_fmtp_mode==20 ||
- attr->setting.enc_fmtp_mode==30, PJMEDIA_CODEC_EINMODE);
+ PJ_ASSERT_RETURN(enc_fmtp_mode==20 ||
+ enc_fmtp_mode==30, PJMEDIA_CODEC_EINMODE);
/* Update enc_ptime in the param */
- if (attr->setting.enc_fmtp_mode != attr->setting.dec_fmtp_mode) {
- attr->info.enc_ptime = attr->setting.enc_fmtp_mode;
+ if (enc_fmtp_mode != dec_fmtp_mode) {
+ attr->info.enc_ptime = (pj_uint16_t)enc_fmtp_mode;
} else {
attr->info.enc_ptime = 0;
}
/* Create enc */
- ilbc_codec->enc_frame_size = initEncode(&ilbc_codec->enc,
- attr->setting.enc_fmtp_mode);
- ilbc_codec->enc_samples_per_frame = CLOCK_RATE*attr->setting.enc_fmtp_mode/
- 1000;
+ ilbc_codec->enc_frame_size = initEncode(&ilbc_codec->enc, enc_fmtp_mode);
+ ilbc_codec->enc_samples_per_frame = CLOCK_RATE * enc_fmtp_mode / 1000;
ilbc_codec->enc_ready = PJ_TRUE;
/* Create decoder */
ilbc_codec->dec_samples_per_frame = initDecode(&ilbc_codec->dec,
- attr->setting.dec_fmtp_mode,
+ dec_fmtp_mode,
attr->setting.penh);
- if (attr->setting.dec_fmtp_mode == 20)
+ if (dec_fmtp_mode == 20)
ilbc_codec->dec_frame_size = 38;
- else if (attr->setting.dec_fmtp_mode == 30)
+ else if (dec_fmtp_mode == 30)
ilbc_codec->dec_frame_size = 50;
else {
pj_assert(!"Invalid iLBC mode");
@@ -435,7 +459,7 @@ static pj_status_t ilbc_codec_open(pjmedia_codec *codec,
PJ_LOG(5,(ilbc_codec->obj_name,
"iLBC codec opened, encoder mode=%d, decoder mode=%d",
- attr->setting.enc_fmtp_mode, attr->setting.dec_fmtp_mode));
+ enc_fmtp_mode, dec_fmtp_mode));
return PJ_SUCCESS;
}
diff --git a/pjmedia/src/pjmedia-codec/ipp_codecs.c b/pjmedia/src/pjmedia-codec/ipp_codecs.c
index 1521b7c8..50926173 100644
--- a/pjmedia/src/pjmedia-codec/ipp_codecs.c
+++ b/pjmedia/src/pjmedia-codec/ipp_codecs.c
@@ -29,6 +29,7 @@
#include <pj/string.h>
#include <pj/os.h>
+
/*
* Only build this file if PJMEDIA_HAS_INTEL_IPP != 0
*/
@@ -210,10 +211,12 @@ static struct ipp_codec {
int has_native_plc; /* Codec has internal PLC? */
predecode_cb predecode; /* Callback to translate RTP frame
- into USC frame */
- parse_cb parse; /* Callback to parse bitstream */
- pack_cb pack; /* Callback to pack bitstream */
-}
+ into USC frame. */
+ parse_cb parse; /* Callback to parse bitstream. */
+ pack_cb pack; /* Callback to pack bitstream. */
+
+ pjmedia_codec_fmtp dec_fmtp; /* Decoder's fmtp params. */
+}
ipp_codec[] =
{
@@ -232,14 +235,8 @@ ipp_codec[] =
# endif
# if PJMEDIA_HAS_INTEL_IPP_CODEC_G729
- /* G.729 actually has internal VAD, but for now we need to disable it,
- * since its RTP packaging (multiple frames per packet) requires
- * SID frame to only be occured in the last frame, while controling
- * encoder on each loop (to enable/disable VAD) is considered inefficient.
- * This should still be interoperable with other implementations.
- */
{1, "G729", PJMEDIA_RTP_PT_G729, &USC_G729AFP_Fxns, 8000, 1, 80,
- 8000, 11800, 2, 0, 1,
+ 8000, 11800, 2, 1, 1,
&predecode_g729, NULL, NULL
},
# endif
@@ -279,9 +276,20 @@ ipp_codec[] =
# endif
# if PJMEDIA_HAS_INTEL_IPP_CODEC_G722_1
- {0, "G7221", PJMEDIA_RTP_PT_G722_1, &USC_G722_Fxns, 16000, 1, 320,
- 16000, 32000, 1, 0, 1,
- NULL, NULL, NULL
+ {0, "G7221", PJMEDIA_RTP_PT_G722_1_16, &USC_G722_Fxns, 16000, 1, 320,
+ 16000, 16000, 1, 0, 1,
+ NULL, NULL, NULL,
+ {1, {{{"bitrate", 7}, {"16000", 5}}} }
+ },
+ {1, "G7221", PJMEDIA_RTP_PT_G722_1_24, &USC_G722_Fxns, 16000, 1, 320,
+ 24000, 24000, 1, 0, 1,
+ NULL, NULL, NULL,
+ {1, {{{"bitrate", 7}, {"24000", 5}}} }
+ },
+ {1, "G7221", PJMEDIA_RTP_PT_G722_1_32, &USC_G722_Fxns, 16000, 1, 320,
+ 32000, 32000, 1, 0, 1,
+ NULL, NULL, NULL,
+ {1, {{{"bitrate", 7}, {"32000", 5}}} }
},
# endif
};
@@ -422,7 +430,8 @@ static pj_status_t ipp_default_attr (pjmedia_codec_factory *factory,
pj_str_t name = pj_str((char*)ipp_codec[i].name);
if ((pj_stricmp(&id->encoding_name, &name) == 0) &&
(id->clock_rate == (unsigned)ipp_codec[i].clock_rate) &&
- (id->channel_cnt == (unsigned)ipp_codec[i].channel_count))
+ (id->channel_cnt == (unsigned)ipp_codec[i].channel_count) &&
+ (id->pt == (unsigned)ipp_codec[i].pt))
{
attr->info.pt = (pj_uint8_t)id->pt;
attr->info.channel_cnt = ipp_codec[i].channel_count;
@@ -437,10 +446,22 @@ static pj_status_t ipp_default_attr (pjmedia_codec_factory *factory,
attr->setting.frm_per_pkt = ipp_codec[i].frm_per_pkt;
/* Default flags. */
- attr->setting.cng = 0;
attr->setting.plc = 1;
attr->setting.penh= 0;
- attr->setting.vad = 1; /* Always disable for now */
+ attr->setting.vad = 1;
+ attr->setting.cng = attr->setting.vad;
+ attr->setting.dec_fmtp = ipp_codec[i].dec_fmtp;
+
+ if (attr->setting.vad == 0) {
+#if PJMEDIA_HAS_INTEL_IPP_CODEC_G729
+ if (id->pt == PJMEDIA_RTP_PT_G729) {
+ /* Signal G729 Annex B is being disabled */
+ attr->setting.dec_fmtp.cnt = 1;
+ pj_strset2(&attr->setting.dec_fmtp.param[0].name, "annexb");
+ pj_strset2(&attr->setting.dec_fmtp.param[0].val, "no");
+ }
+#endif
+ }
return PJ_SUCCESS;
}
@@ -631,10 +652,24 @@ static pj_status_t ipp_codec_open( pjmedia_codec *codec,
/* Setting the encoder params */
codec_data->info->params.direction = USC_ENCODE;
codec_data->info->params.modes.vad = attr->setting.vad &&
- ippc->has_native_vad;
+ ippc->has_native_vad;
codec_data->info->params.modes.bitrate = attr->info.avg_bps;
codec_data->info->params.law = 0; /* Linear PCM input */
+#if PJMEDIA_HAS_INTEL_IPP_CODEC_G729
+ if (ippc->pt == PJMEDIA_RTP_PT_G729) {
+ /* Check if G729 Annex B is signaled to be disabled */
+ for (i = 0; i < attr->setting.enc_fmtp.cnt; ++i) {
+ if (pj_stricmp2(&attr->setting.enc_fmtp.param[i].name, "annexb")==0)
+ {
+ if (pj_stricmp2(&attr->setting.enc_fmtp.param[i].val, "no")==0)
+ codec_data->info->params.modes.vad = 0;
+ break;
+ }
+ }
+ }
+#endif
+
/* Get number of memory blocks needed by the encoder */
if (USC_NoError != ippc->fxns->std.NumAlloc(&codec_data->info->params,
&nb_membanks))
@@ -673,6 +708,9 @@ static pj_status_t ipp_codec_open( pjmedia_codec *codec,
/* Setting the decoder params */
codec_data->info->params.direction = USC_DECODE;
+ /* Not sure if VAD affects decoder, just try to be safe */
+ codec_data->info->params.modes.vad = ippc->has_native_vad;
+
/* Get number of memory blocks needed by the decoder */
if (USC_NoError != ippc->fxns->std.NumAlloc(&codec_data->info->params,
&nb_membanks))
@@ -925,6 +963,18 @@ static pj_status_t ipp_codec_encode( pjmedia_codec *codec,
nsamples -= samples_per_frame;
tx += out.nbytes;
bits_out += out.nbytes;
+
+#if PJMEDIA_HAS_INTEL_IPP_CODEC_G729
+ if (out.frametype == 1) {
+ /* SID */
+ break;
+ } else if (out.frametype == 0) {
+ /* Untransmitted */
+ tx -= out.nbytes;
+ break;
+ }
+#endif
+
}
if (ippc->pack != NULL) {
diff --git a/pjmedia/src/pjmedia/endpoint.c b/pjmedia/src/pjmedia/endpoint.c
index cac91e62..4f3388b2 100644
--- a/pjmedia/src/pjmedia/endpoint.c
+++ b/pjmedia/src/pjmedia/endpoint.c
@@ -424,18 +424,55 @@ PJ_DEF(pj_status_t) pjmedia_endpt_create_sdp( pjmedia_endpt *endpt,
m->attr[m->attr_count++] = attr;
}
- /* Add fmtp mode where applicable */
- if (codec_param.setting.dec_fmtp_mode != 0) {
- const pj_str_t fmtp = { "fmtp", 4 };
+ /* Add fmtp params */
+ if (codec_param.setting.dec_fmtp.cnt > 0) {
+ enum { MAX_FMTP_STR_LEN = 160 };
+ char buf[MAX_FMTP_STR_LEN];
+ unsigned buf_len = 0, i;
+ pjmedia_codec_fmtp *dec_fmtp = &codec_param.setting.dec_fmtp;
+
+ /* Print codec PT */
+ buf_len += pj_ansi_snprintf(buf,
+ MAX_FMTP_STR_LEN - buf_len,
+ "%d",
+ codec_info->pt);
+
+ for (i = 0; i < dec_fmtp->cnt; ++i) {
+ unsigned test_len = 2;
+
+ /* Check if buf still available */
+ test_len = dec_fmtp->param[i].val.slen +
+ dec_fmtp->param[i].name.slen;
+ if (test_len + buf_len >= MAX_FMTP_STR_LEN)
+ return PJ_ETOOBIG;
+
+ /* Print delimiter */
+ buf_len += pj_ansi_snprintf(&buf[buf_len],
+ MAX_FMTP_STR_LEN - buf_len,
+ (i == 0?" ":";"));
+
+ /* Print an fmtp param */
+ if (dec_fmtp->param[i].name.slen)
+ buf_len += pj_ansi_snprintf(
+ &buf[buf_len],
+ MAX_FMTP_STR_LEN - buf_len,
+ "%.*s=%.*s",
+ (int)dec_fmtp->param[i].name.slen,
+ dec_fmtp->param[i].name.ptr,
+ (int)dec_fmtp->param[i].val.slen,
+ dec_fmtp->param[i].val.ptr);
+ else
+ buf_len += pj_ansi_snprintf(&buf[buf_len],
+ MAX_FMTP_STR_LEN - buf_len,
+ "%.*s",
+ (int)dec_fmtp->param[i].val.slen,
+ dec_fmtp->param[i].val.ptr);
+ }
+
attr = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_attr);
- attr->name = fmtp;
- attr->value.ptr = (char*) pj_pool_alloc(pool, 32);
- attr->value.slen =
- pj_ansi_snprintf( attr->value.ptr, 32,
- "%d mode=%d",
- codec_info->pt,
- codec_param.setting.dec_fmtp_mode);
+ attr->name = pj_str("fmtp");
+ attr->value = pj_strdup3(pool, buf);
m->attr[m->attr_count++] = attr;
}
}
diff --git a/pjmedia/src/pjmedia/sdp_neg.c b/pjmedia/src/pjmedia/sdp_neg.c
index 6753e943..ef7815d4 100644
--- a/pjmedia/src/pjmedia/sdp_neg.c
+++ b/pjmedia/src/pjmedia/sdp_neg.c
@@ -533,6 +533,51 @@ static void update_media_direction(pj_pool_t *pool,
}
}
+/* Matching G722.1 bitrates between offer and answer.
+ */
+static pj_bool_t match_g7221( const pjmedia_sdp_media *offer,
+ unsigned o_fmt_idx,
+ const pjmedia_sdp_media *answer,
+ unsigned a_fmt_idx)
+{
+ const pjmedia_sdp_attr *a_ans;
+ const pjmedia_sdp_attr *a_off;
+ pjmedia_sdp_fmtp fmtp;
+ unsigned a_bitrate = 0, o_bitrate = 0;
+ const pj_str_t bitrate = {"bitrate=", 8};
+ const char *p;
+
+ a_ans = pjmedia_sdp_media_find_attr2(answer, "fmtp",
+ &answer->desc.fmt[a_fmt_idx]);
+ if (!a_ans)
+ return PJ_FALSE;
+
+ if (pjmedia_sdp_attr_get_fmtp(a_ans, &fmtp) != PJ_SUCCESS)
+ return PJ_FALSE;
+
+ p = pj_stristr(&fmtp.fmt_param, &bitrate);
+ if (p == NULL)
+ return PJ_FALSE;
+
+ a_bitrate = atoi(p + bitrate.slen);
+
+ a_off = pjmedia_sdp_media_find_attr2(offer, "fmtp",
+ &offer->desc.fmt[o_fmt_idx]);
+ if (!a_off)
+ return PJ_FALSE;
+
+ if (pjmedia_sdp_attr_get_fmtp(a_off, &fmtp) != PJ_SUCCESS)
+ return PJ_FALSE;
+
+ p = pj_stristr(&fmtp.fmt_param, &bitrate);
+ if (p == NULL)
+ return PJ_FALSE;
+
+ o_bitrate = atoi(p + bitrate.slen);
+
+ return (a_bitrate == o_bitrate);
+}
+
/* Update single local media description to after receiving answer
* from remote.
*/
@@ -657,8 +702,14 @@ static pj_status_t process_m_answer( pj_pool_t *pool,
(pj_stricmp(&or_.param, &ar.param)==0 ||
(ar.param.slen==1 && *ar.param.ptr=='1')))
{
- /* Match! */
- break;
+ /* Further check for G7221, negotiate bitrate. */
+ if (pj_strcmp2(&or_.enc_name, "G7221") == 0) {
+ if (match_g7221(offer, i, answer, j))
+ break;
+ } else {
+ /* Match! */
+ break;
+ }
}
}
}
@@ -871,10 +922,18 @@ static pj_status_t match_offer(pj_pool_t *pool,
(or_.param.slen==1 && *or_.param.ptr=='1')))
{
/* Match! */
- if (is_codec)
+ if (is_codec) {
+ /* Further check for G7221, negotiate bitrate. */
+ if (pj_strcmp2(&or_.enc_name, "G7221") == 0 &&
+ match_g7221(offer, i, preanswer, j) == 0)
+ {
+ continue;
+ }
found_matching_codec = 1;
- else
+ } else {
found_matching_telephone_event = 1;
+ }
+
pt_answer[pt_answer_count++] = preanswer->desc.fmt[j];
break;
}
diff --git a/pjmedia/src/pjmedia/session.c b/pjmedia/src/pjmedia/session.c
index 2b2a3fbd..3ca91078 100644
--- a/pjmedia/src/pjmedia/session.c
+++ b/pjmedia/src/pjmedia/session.c
@@ -67,51 +67,76 @@ static const pj_str_t STR_RECVONLY = { "recvonly", 8 };
/*
- * Get fmtp mode parameter associated with the codec.
+ * Parse fmtp for specified format/payload type.
*/
-static pj_status_t get_fmtp_mode(const pjmedia_sdp_media *m,
- const pj_str_t *fmt,
- int *p_mode)
+static void parse_fmtp( pj_pool_t *pool,
+ const pjmedia_sdp_media *m,
+ unsigned pt,
+ pjmedia_codec_fmtp *fmtp)
{
const pjmedia_sdp_attr *attr;
- pjmedia_sdp_fmtp fmtp;
- const pj_str_t str_mode = { "mode=", 5 };
- char *pos;
+ pjmedia_sdp_fmtp sdp_fmtp;
+ char *p, *p_end, fmt_buf[8];
+ pj_str_t fmt;
+
+ pj_assert(m && fmtp);
+
+ pj_bzero(fmtp, sizeof(pjmedia_codec_fmtp));
/* Get "fmtp" attribute for the format */
- attr = pjmedia_sdp_media_find_attr2(m, "fmtp", fmt);
+ pj_ansi_sprintf(fmt_buf, "%d", pt);
+ fmt = pj_str(fmt_buf);
+ attr = pjmedia_sdp_media_find_attr2(m, "fmtp", &fmt);
if (attr == NULL)
- return -1;
+ return;
/* Parse "fmtp" attribute */
- if (pjmedia_sdp_attr_get_fmtp(attr, &fmtp) != PJ_SUCCESS)
- return -1;
+ if (pjmedia_sdp_attr_get_fmtp(attr, &sdp_fmtp) != PJ_SUCCESS)
+ return;
- /* Look for "mode=" string in the fmtp */
- while (fmtp.fmt_param.slen >= str_mode.slen + 1) {
- if (pj_strnicmp(&fmtp.fmt_param, &str_mode, str_mode.slen)==0) {
- /* Found "mode=" string */
- break;
- }
+ /* Prepare parsing */
+ p = sdp_fmtp.fmt_param.ptr;
+ p_end = p + sdp_fmtp.fmt_param.slen;
- fmtp.fmt_param.ptr++;
- fmtp.fmt_param.slen--;
- }
+ /* Parse */
+ while (p < p_end) {
+ char *token, *start, *end;
- if (fmtp.fmt_param.slen < str_mode.slen + 1) {
- /* "mode=" param not found */
- return -1;
- }
+ /* Skip whitespaces */
+ while (p < p_end && (*p == ' ' || *p == '\t')) ++p;
+ if (p == p_end)
+ break;
- /* Get the mode */
- pos = fmtp.fmt_param.ptr + str_mode.slen;
- *p_mode = 0;
- while (pj_isdigit(*pos)) {
- *p_mode = *p_mode * 10 + (*pos - '0');
- ++pos;
- }
+ /* Get token */
+ start = p;
+ while (p < p_end && *p != ';' && *p != '=') ++p;
+ end = p - 1;
+
+ /* Right trim */
+ while (end >= start && (*end == ' ' || *end == '\t' ||
+ *end == '\r' || *end == '\n' ))
+ --end;
+
+ /* Forward a char after trimming */
+ ++end;
+
+ /* Store token */
+ if (end > start) {
+ token = (char*)pj_pool_alloc(pool, end - start);
+ pj_ansi_strncpy(token, start, end - start);
+ if (*p == '=')
+ /* Got param name */
+ pj_strset(&fmtp->param[fmtp->cnt].name, token, end - start);
+ else
+ /* Got param value */
+ pj_strset(&fmtp->param[fmtp->cnt++].val, token, end - start);
+ } else if (*p != '=') {
+ ++fmtp->cnt;
+ }
- return PJ_SUCCESS;
+ /* Next */
+ ++p;
+ }
}
@@ -135,7 +160,6 @@ PJ_DEF(pj_status_t) pjmedia_stream_info_from_sdp(
int rem_af, local_af;
pj_sockaddr local_addr;
pjmedia_sdp_rtpmap *rtpmap;
- int local_fmtp_mode = 0, rem_fmtp_mode = 0;
unsigned i, pt, fmti;
pj_status_t status;
@@ -400,7 +424,8 @@ PJ_DEF(pj_status_t) pjmedia_stream_info_from_sdp(
#if defined(PJMEDIA_HANDLE_G722_MPEG_BUG) && (PJMEDIA_HANDLE_G722_MPEG_BUG != 0)
/* The session info should have the actual clock rate, because
- * this info is used for calculationg buffer size, etc in stream */
+ * this info is used for calculationg buffer size, etc in stream
+ */
if (si->fmt.pt == PJMEDIA_RTP_PT_G722)
si->fmt.clock_rate = 16000;
#endif
@@ -463,9 +488,6 @@ PJ_DEF(pj_status_t) pjmedia_stream_info_from_sdp(
si->fmt.channel_cnt = 1;
}
- /* Get fmtp mode= param in local SDP, if any */
- get_fmtp_mode(local_m, &local_m->desc.fmt[fmti], &local_fmtp_mode);
-
/* Determine payload type for outgoing channel, by finding
* dynamic payload type in remote SDP that matches the answer.
*/
@@ -493,9 +515,6 @@ PJ_DEF(pj_status_t) pjmedia_stream_info_from_sdp(
/* Found matched codec. */
si->tx_pt = rpt;
- /* Get fmtp mode param in remote SDP, if any */
- get_fmtp_mode(rem_m, &rtpmap->pt, &rem_fmtp_mode);
-
break;
}
}
@@ -509,6 +528,22 @@ PJ_DEF(pj_status_t) pjmedia_stream_info_from_sdp(
si->param = PJ_POOL_ALLOC_T(pool, pjmedia_codec_param);
status = pjmedia_codec_mgr_get_default_param(mgr, &si->fmt, si->param);
+ /* Get remote fmtp for our encoder. */
+ parse_fmtp(pool, rem_m, si->tx_pt, &si->param->setting.enc_fmtp);
+
+ /* Get local fmtp for our decoder. */
+ parse_fmtp(pool, local_m, si->fmt.pt, &si->param->setting.dec_fmtp);
+
+ /* Get remote maxptime for our encoder. */
+ attr = pjmedia_sdp_attr_find2(rem_m->attr_count, rem_m->attr,
+ "maxptime", NULL);
+ if (attr) {
+ pj_str_t tmp_val = attr->value;
+
+ pj_strltrim(&tmp_val);
+ si->tx_maxptime = pj_strtoul(&tmp_val);
+ }
+
/* When direction is NONE (it means SDP negotiation has failed) we don't
* need to return a failure here, as returning failure will cause
* the whole SDP to be rejected. See ticket #:
@@ -519,12 +554,6 @@ PJ_DEF(pj_status_t) pjmedia_stream_info_from_sdp(
if (status != PJ_SUCCESS && si->dir != PJMEDIA_DIR_NONE)
return status;
- /* Set fmtp mode for both local and remote */
- if (local_fmtp_mode != 0)
- si->param->setting.dec_fmtp_mode = (pj_int8_t)local_fmtp_mode;
- if (rem_fmtp_mode != 0)
- si->param->setting.enc_fmtp_mode = (pj_int8_t)rem_fmtp_mode;
-
/* Get incomming payload type for telephone-events */
si->rx_event_pt = -1;