Commit 09c74f56 authored by Pekka Pessi's avatar Pekka Pessi

Added funtions for rtp payload type management.

Added sdp_media_uses_rtp(), sdp_rtpmap_match(), sdp_rtpmap_find_matching()
and sdp_rtpmap_well_known[]. Fixed RTP timestamp rate for G722: it was 16000
but it should be 8000.

darcs-hash:20051113184029-65a35-eb4fa1fb9cd0bc75e93616cb20db1ffaf6cd3405.gz
parent 45bae509
......@@ -1388,7 +1388,7 @@ int sdp_rtpmap_cmp(sdp_rtpmap_t const *a, sdp_rtpmap_t const *b)
return rv;
}
return str0cmp(a->rm_fmtp, b->rm_fmtp);
return str0casecmp(a->rm_fmtp, b->rm_fmtp);
}
/** Compare two lists. */
......@@ -1686,3 +1686,78 @@ unsigned sdp_media_count_with(sdp_session_t const *sdp,
return count;
}
/** Return true if media uses RTP */
int sdp_media_uses_rtp(sdp_media_t const *m)
{
return m &&
(m->m_proto == sdp_proto_rtp ||
m->m_proto == sdp_proto_srtp ||
(m->m_proto == sdp_proto_x && m->m_proto_name &&
strncasecmp(m->m_proto_name, "RTP/", 4) == 0));
}
/** Check if payload type, rtp rate and parameters match in rtpmaps*/
int sdp_rtpmap_match(sdp_rtpmap_t const *a, sdp_rtpmap_t const *b)
{
char const *aparam, *bparam;
if (a == b)
return 1;
if (a == 0 || b == 0)
return 0;
if (a->rm_rate != b->rm_rate)
return 0;
if (strcasecmp(a->rm_encoding, b->rm_encoding))
return 0;
aparam = a->rm_params; bparam = b->rm_params;
if (aparam == bparam)
return 1;
if (!aparam) aparam = "1"; if (!bparam) bparam = "1";
if (strcasecmp(aparam, bparam))
return 0;
return 1;
}
/** Search for matching rtpmap from list.
*
* @note
* The a=fmtp: for the codecs are not compared.
*/
sdp_rtpmap_t *sdp_rtpmap_find_matching(sdp_rtpmap_t const *list,
sdp_rtpmap_t const *rm)
{
char const *lparam, *rparam;
if (rm == NULL)
return NULL;
for (; list; list = list->rm_next) {
if (rm->rm_rate != list->rm_rate)
continue;
if (strcasecmp(rm->rm_encoding, list->rm_encoding))
continue;
lparam = rm->rm_params; rparam = list->rm_params;
if (lparam == rparam)
break;
if (!lparam) lparam = "1"; if (!rparam) rparam = "1";
if (strcasecmp(lparam, rparam))
continue;
break;
}
return (sdp_rtpmap_t *)list;
}
......@@ -319,6 +319,8 @@ struct sdp_rtpmap_s {
sdp_text_t *rm_fmtp; /**< Contents of fmtp */
};
extern sdp_rtpmap_t const * const sdp_rtpmap_well_known[128];
/** Duplicate an SDP session description structure. */
sdp_session_t *sdp_session_dup(su_home_t *home, sdp_session_t const *sdp);
......@@ -445,6 +447,16 @@ unsigned sdp_media_count(sdp_session_t const *sdp,
unsigned sdp_media_count_with(sdp_session_t const *sdp,
sdp_media_t const *m0);
/** Return true if media uses RTP */
int sdp_media_uses_rtp(sdp_media_t const *m);
/** Check if payload type, rtp rate and parameters match in rtpmaps*/
int sdp_rtpmap_match(sdp_rtpmap_t const *a, sdp_rtpmap_t const *b);
/** Search for matching rtpmap from list */
sdp_rtpmap_t *sdp_rtpmap_find_matching(sdp_rtpmap_t const *list,
sdp_rtpmap_t const *rm);
/* ======================================================================== */
/** Flags given to sdp_parse()/sdp_print(). */
......
......@@ -1361,6 +1361,85 @@ int sdp_media_has_rtp(sdp_media_t const *m)
return m && (m->m_proto == sdp_proto_rtp || m->m_proto == sdp_proto_srtp);
}
#define RTPMAP(pt, type, rate, params) \
{ sizeof(sdp_rtpmap_t), NULL, 1, pt, 0, type, rate, (char *)params}
/* rtpmaps for well-known codecs */
static sdp_rtpmap_t const
sdp_rtpmap_pcmu = RTPMAP(0, "PCMU", 8000, 0),
sdp_rtpmap_1016 = RTPMAP(1, "1016", 8000, 0),
sdp_rtpmap_g721 = RTPMAP(2, "G721", 8000, 0),
sdp_rtpmap_gsm = RTPMAP(3, "GSM", 8000, 0),
sdp_rtpmap_g723 = RTPMAP(4, "G723", 8000, 0),
sdp_rtpmap_dvi4_8000 = RTPMAP(5, "DVI4", 8000, 0),
sdp_rtpmap_dvi4_16000 = RTPMAP(6, "DVI4", 16000, 0),
sdp_rtpmap_lpc = RTPMAP(7, "LPC", 8000, 0),
sdp_rtpmap_pcma = RTPMAP(8, "PCMA", 8000, 0),
sdp_rtpmap_g722 = RTPMAP(9, "G722", 8000, 0),
sdp_rtpmap_l16_2 = RTPMAP(10, "L16", 44100, "2"),
sdp_rtpmap_l16 = RTPMAP(11, "L16", 44100, 0),
sdp_rtpmap_qcelp = RTPMAP(12, "QCELP", 8000, 0),
sdp_rtpmap_cn = RTPMAP(13, "CN", 8000, 0),
sdp_rtpmap_mpa = RTPMAP(14, "MPA", 90000, 0),
sdp_rtpmap_g728 = RTPMAP(15, "G728", 8000, 0),
sdp_rtpmap_dvi4_11025 = RTPMAP(16, "DVI4", 11025, 0),
sdp_rtpmap_dvi4_22050 = RTPMAP(17, "DVI4", 22050, 0),
sdp_rtpmap_g729 = RTPMAP(18, "G729", 8000, 0),
sdp_rtpmap_reserved_cn = RTPMAP(19, "CN", 8000, 0),
/* video codecs */
sdp_rtpmap_celb = RTPMAP(25, "CelB", 90000, 0),
sdp_rtpmap_jpeg = RTPMAP(26, "JPEG", 90000, 0),
sdp_rtpmap_nv = RTPMAP(28, "nv", 90000, 0),
sdp_rtpmap_h261 = RTPMAP(31, "H261", 90000, 0),
sdp_rtpmap_mpv = RTPMAP(32, "MPV", 90000, 0),
sdp_rtpmap_mp2t = RTPMAP(33, "MP2T", 90000, 0),
sdp_rtpmap_h263 = RTPMAP(34, "H263", 90000, 0);
/** Table of rtpmap structures by payload type numbers.
*
* The table of reserved payload numbers is constructed from @RFC3551
* and @RFC1891. Note the clock rate of G722.
*/
sdp_rtpmap_t const * const sdp_rtpmap_well_known[128] =
{
&sdp_rtpmap_pcmu, /* 0 */
&sdp_rtpmap_1016, /* 1 */
&sdp_rtpmap_g721, /* 2 */
&sdp_rtpmap_gsm, /* 3 */
&sdp_rtpmap_g723, /* 4 */
&sdp_rtpmap_dvi4_8000, /* 5 */
&sdp_rtpmap_dvi4_16000, /* 6 */
&sdp_rtpmap_lpc, /* 7 */
&sdp_rtpmap_pcma, /* 8 */
&sdp_rtpmap_g722, /* 9 */
&sdp_rtpmap_l16_2, /* 10 */
&sdp_rtpmap_l16, /* 11 */
&sdp_rtpmap_qcelp, /* 12 */
&sdp_rtpmap_cn, /* 13 */
&sdp_rtpmap_mpa, /* 14 */
&sdp_rtpmap_g728, /* 15 */
&sdp_rtpmap_dvi4_11025, /* 16 */
&sdp_rtpmap_dvi4_22050, /* 17 */
&sdp_rtpmap_g729, /* 18 */
&sdp_rtpmap_reserved_cn, /* 19 */
NULL, /* 20 */
NULL, /* 21 */
NULL, /* 22 */
NULL, /* 23 */
NULL, /* 24 */
&sdp_rtpmap_celb, /* 25 */
&sdp_rtpmap_jpeg, /* 26 */
NULL, /* 27 */
&sdp_rtpmap_nv, /* 28 */
NULL, /* 29 */
NULL, /* 30 */
&sdp_rtpmap_h261, /* 31 */
&sdp_rtpmap_mpv, /* 32 */
&sdp_rtpmap_mp2t, /* 33 */
&sdp_rtpmap_h263, /* 34 */
NULL,
};
/**
* The function parse_payload() parses an RTP payload type list, and
* creates an rtpmap structure for each payload type.
......@@ -1371,49 +1450,24 @@ int sdp_media_has_rtp(sdp_media_t const *m)
*/
static void parse_payload(sdp_parser_t *p, char *r, sdp_rtpmap_t **result)
{
#define SETMAP(rm, type, rate) (rm->rm_encoding = type, rm->rm_rate = rate)
while (*r) {
unsigned long value;
if (parse_ul(p, &r, &value, 128) == 0) {
PARSE_ALLOC(p, sdp_rtpmap_t, rm);
assert(0 <= value && value < 128);
*result = rm; result = &rm->rm_next;
rm->rm_predef = 1;
rm->rm_pt = value;
switch (value) {
/* Payload type numbers as per RFC3551 */
case 0: SETMAP(rm, "PCMU", 8000); break;
case 3: SETMAP(rm, "GSM", 8000); break;
case 4: SETMAP(rm, "G723", 8000); break;
case 5: SETMAP(rm, "DVI4", 8000); break;
case 6: SETMAP(rm, "DVI4", 16000); break;
case 7: SETMAP(rm, "LPC", 8000); break;
case 8: SETMAP(rm, "PCMA", 8000); break;
case 9: SETMAP(rm, "G722", 16000); break;
/* in stereo, where available! */
case 10: SETMAP(rm, "L16", 44100); rm->rm_params = "2"; break;
case 11: SETMAP(rm, "L16", 44100); break;
case 12: SETMAP(rm, "QCELP", 8000); break;
case 13: SETMAP(rm, "CN", 8000); break;
case 14: SETMAP(rm, "MPA", 90000); break;
case 15: SETMAP(rm, "G728", 8000); break;
case 16: SETMAP(rm, "DVI4", 11025); break;
case 17: SETMAP(rm, "DVI4", 22050); break;
case 18: SETMAP(rm, "G729", 8000); break;
case 25: SETMAP(rm, "CelB", 90000); break;
case 26: SETMAP(rm, "JPEG", 90000); break;
case 28: SETMAP(rm, "nv", 90000); break;
case 31: SETMAP(rm, "H261", 90000); break;
case 32: SETMAP(rm, "MPV", 90000); break;
case 33: SETMAP(rm, "MP2T", 90000); break;
case 34: SETMAP(rm, "H263", 90000); break;
default: SETMAP(rm, "", 0); break;
if (sdp_rtpmap_well_known[value]) {
*rm = *sdp_rtpmap_well_known[value];
}
else {
rm->rm_predef = 1;
rm->rm_pt = value;
rm->rm_encoding = "";
rm->rm_rate = 0;
}
}
else if (p->pr_config && r[0] == '*' && (r[1] == ' ' || r[1] == '\0')) {
......@@ -1423,12 +1477,15 @@ static void parse_payload(sdp_parser_t *p, char *r, sdp_rtpmap_t **result)
rm->rm_predef = 1;
rm->rm_any = 1;
rm->rm_encoding = "*";
rm->rm_rate = 0;
SETMAP(rm, "*", 0); break;
return;
}
else {
parsing_error(p, "m= invalid format for RTP/AVT");
break;
return;
}
}
}
......
......@@ -229,9 +229,9 @@ static char const s1_msg[] =
"c=IN IP4 172.21.137.44\r\n"
"t=0 0\r\n"
"a=sendonly\r\n"
"m=video 49154 RTP/AVP 96\r\n"
"m=video 49154 RTP/AVP 96 24 25 26 28 31 32 33 34\r\n"
"a=rtpmap:96 H263-1998/90000\r\n"
"m=audio 49152 RTP/AVP 97\r\n"
"m=audio 49152 RTP/AVP 97 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19\r\n"
"a=rtpmap 97 AMR/8000\r\n"
"a=fmtp:97 mode-set=\"0,1,2,3,4\"\r\n"
"a=ptime:400\r\n";
......@@ -260,6 +260,7 @@ static int test_session2(int flags)
sdp_session_t const *sdp = NULL;
sdp_parser_t *parser;
sdp_media_t *m;
sdp_rtpmap_t *rm;
BEGIN();
......@@ -271,20 +272,148 @@ static int test_session2(int flags)
TEST(m->m_mode, sdp_sendonly);
TEST_1(m->m_session);
TEST(m->m_session, sdp);
TEST_1(m->m_rtpmaps);
TEST(m->m_rtpmaps->rm_pt, 96);
TEST_S(m->m_rtpmaps->rm_encoding, "H263-1998");
TEST(m->m_rtpmaps->rm_rate, 90000);
TEST_1(rm = m->m_rtpmaps);
TEST(rm->rm_pt, 96);
TEST_S(rm->rm_encoding, "H263-1998");
TEST(rm->rm_rate, 90000);
{
#define RTPMAP(pt, type, rate, params) \
{ sizeof(sdp_rtpmap_t), NULL, 1, pt, 0, type, rate, (char *)params}
/* rtpmaps for well-known video codecs */
static sdp_rtpmap_t const
sdp_rtpmap_celb = RTPMAP(25, "CelB", 90000, 0),
sdp_rtpmap_jpeg = RTPMAP(26, "JPEG", 90000, 0),
sdp_rtpmap_nv = RTPMAP(28, "nv", 90000, 0),
sdp_rtpmap_h261 = RTPMAP(31, "H261", 90000, 0),
sdp_rtpmap_mpv = RTPMAP(32, "MPV", 90000, 0),
sdp_rtpmap_mp2t = RTPMAP(33, "MP2T", 90000, 0),
sdp_rtpmap_h263 = RTPMAP(34, "H263", 90000, 0);
TEST_1(rm = rm->rm_next);
TEST_S(rm->rm_encoding, ""); TEST(rm->rm_rate, 0);
TEST_1(rm = rm->rm_next);
TEST(sdp_rtpmap_find_matching(&sdp_rtpmap_celb, rm), &sdp_rtpmap_celb);
TEST_1(rm = rm->rm_next);
TEST(sdp_rtpmap_find_matching(&sdp_rtpmap_jpeg, rm), &sdp_rtpmap_jpeg);
TEST_1(rm = rm->rm_next);
TEST(sdp_rtpmap_find_matching(&sdp_rtpmap_nv, rm), &sdp_rtpmap_nv);
TEST_1(rm = rm->rm_next);
TEST(sdp_rtpmap_find_matching(&sdp_rtpmap_h261, rm), &sdp_rtpmap_h261);
TEST_1(rm = rm->rm_next);
TEST(sdp_rtpmap_find_matching(&sdp_rtpmap_mpv, rm), &sdp_rtpmap_mpv);
TEST_1(rm = rm->rm_next);
TEST(sdp_rtpmap_find_matching(&sdp_rtpmap_mp2t, rm), &sdp_rtpmap_mp2t);
TEST_1(rm = rm->rm_next);
TEST(sdp_rtpmap_find_matching(&sdp_rtpmap_h263, rm), &sdp_rtpmap_h263);
TEST_1(!rm->rm_next);
}
TEST_1(m = m->m_next);
TEST(m->m_mode, sdp_sendonly);
TEST_1(m->m_session);
TEST(m->m_session, sdp);
TEST_1(m->m_rtpmaps);
TEST(m->m_rtpmaps->rm_pt, 97);
TEST_S(m->m_rtpmaps->rm_encoding, "AMR");
TEST(m->m_rtpmaps->rm_rate, 8000);
TEST_S(m->m_rtpmaps->rm_fmtp, "mode-set=\"0,1,2,3,4\"");
TEST_1(rm = m->m_rtpmaps);
TEST(rm->rm_pt, 97);
TEST_S(rm->rm_encoding, "AMR");
TEST(rm->rm_rate, 8000);
TEST_S(rm->rm_fmtp, "mode-set=\"0,1,2,3,4\"");
{
/* rtpmaps for well-known audio codecs */
static sdp_rtpmap_t const
sdp_rtpmap_pcmu = RTPMAP(0, "PCMU", 8000, "1"),
sdp_rtpmap_1016 = RTPMAP(1, "1016", 8000, "1"),
sdp_rtpmap_g721 = RTPMAP(2, "G721", 8000, "1"),
sdp_rtpmap_gsm = RTPMAP(3, "GSM", 8000, "1"),
sdp_rtpmap_g723 = RTPMAP(4, "G723", 8000, "1"),
sdp_rtpmap_dvi4_8000 = RTPMAP(5, "DVI4", 8000, "1"),
sdp_rtpmap_dvi4_16000 = RTPMAP(6, "DVI4", 16000, "1"),
sdp_rtpmap_lpc = RTPMAP(7, "LPC", 8000, "1"),
sdp_rtpmap_pcma = RTPMAP(8, "PCMA", 8000, "1"),
sdp_rtpmap_g722 = RTPMAP(9, "G722", 8000, "1"),
sdp_rtpmap_l16 = RTPMAP(10, "L16", 44100, "2"),
sdp_rtpmap_l16_stereo = RTPMAP(11, "L16", 44100, "1"),
sdp_rtpmap_qcelp = RTPMAP(12, "QCELP", 8000, "1"),
sdp_rtpmap_cn = RTPMAP(13, "CN", 8000, "1"),
sdp_rtpmap_mpa = RTPMAP(14, "MPA", 90000, 0),
sdp_rtpmap_g728 = RTPMAP(15, "G728", 8000, "1"),
sdp_rtpmap_dvi4_11025 = RTPMAP(16, "DVI4", 11025, "1"),
sdp_rtpmap_dvi4_22050 = RTPMAP(17, "DVI4", 22050, "1"),
sdp_rtpmap_g729 = RTPMAP(18, "G729", 8000, "1"),
sdp_rtpmap_cn_reserved = RTPMAP(19, "CN", 8000, "1");
TEST_1(rm = rm->rm_next);
TEST_1(sdp_rtpmap_match(&sdp_rtpmap_pcmu, rm));
TEST(sdp_rtpmap_find_matching(&sdp_rtpmap_pcmu, rm), &sdp_rtpmap_pcmu);
TEST_1(rm = rm->rm_next);
TEST_1(sdp_rtpmap_match(&sdp_rtpmap_1016, rm));
TEST(sdp_rtpmap_find_matching(&sdp_rtpmap_1016, rm), &sdp_rtpmap_1016);
TEST_1(rm = rm->rm_next);
TEST_1(sdp_rtpmap_match(&sdp_rtpmap_g721, rm));
TEST(sdp_rtpmap_find_matching(&sdp_rtpmap_g721, rm), &sdp_rtpmap_g721);
TEST_1(rm = rm->rm_next);
TEST_1(sdp_rtpmap_match(&sdp_rtpmap_gsm, rm));
TEST(sdp_rtpmap_find_matching(&sdp_rtpmap_gsm, rm), &sdp_rtpmap_gsm);
TEST_1(rm = rm->rm_next);
TEST_1(sdp_rtpmap_match(&sdp_rtpmap_g723, rm));
TEST(sdp_rtpmap_find_matching(&sdp_rtpmap_g723, rm), &sdp_rtpmap_g723);
TEST_1(rm = rm->rm_next);
TEST_1(sdp_rtpmap_match(&sdp_rtpmap_dvi4_8000, rm));
TEST(sdp_rtpmap_find_matching(&sdp_rtpmap_dvi4_8000, rm),
&sdp_rtpmap_dvi4_8000);
TEST_1(rm = rm->rm_next);
TEST_1(sdp_rtpmap_match(&sdp_rtpmap_dvi4_16000, rm));
TEST(sdp_rtpmap_find_matching(&sdp_rtpmap_dvi4_16000, rm),
&sdp_rtpmap_dvi4_16000);
TEST_1(rm = rm->rm_next);
TEST_1(sdp_rtpmap_match(&sdp_rtpmap_lpc, rm));
TEST(sdp_rtpmap_find_matching(&sdp_rtpmap_lpc, rm), &sdp_rtpmap_lpc);
TEST_1(rm = rm->rm_next);
TEST_1(sdp_rtpmap_match(&sdp_rtpmap_pcma, rm));
TEST(sdp_rtpmap_find_matching(&sdp_rtpmap_pcma, rm), &sdp_rtpmap_pcma);
TEST_1(rm = rm->rm_next);
TEST_1(sdp_rtpmap_match(&sdp_rtpmap_g722, rm));
TEST(sdp_rtpmap_find_matching(&sdp_rtpmap_g722, rm), &sdp_rtpmap_g722);
TEST_1(rm = rm->rm_next);
TEST_1(sdp_rtpmap_match(&sdp_rtpmap_l16, rm));
TEST(sdp_rtpmap_find_matching(&sdp_rtpmap_l16, rm), &sdp_rtpmap_l16);
TEST_1(rm = rm->rm_next);
TEST_1(sdp_rtpmap_match(&sdp_rtpmap_l16_stereo, rm));
TEST(sdp_rtpmap_find_matching(&sdp_rtpmap_l16_stereo, rm),
&sdp_rtpmap_l16_stereo);
TEST_1(rm = rm->rm_next);
TEST_1(sdp_rtpmap_match(&sdp_rtpmap_qcelp, rm));
TEST(sdp_rtpmap_find_matching(&sdp_rtpmap_qcelp, rm), &sdp_rtpmap_qcelp);
TEST_1(rm = rm->rm_next);
TEST_1(sdp_rtpmap_match(&sdp_rtpmap_cn, rm));
TEST(sdp_rtpmap_find_matching(&sdp_rtpmap_cn, rm), &sdp_rtpmap_cn);
TEST_1(rm = rm->rm_next);
TEST_1(sdp_rtpmap_match(&sdp_rtpmap_mpa, rm));
TEST(sdp_rtpmap_find_matching(&sdp_rtpmap_mpa, rm), &sdp_rtpmap_mpa);
TEST_1(rm = rm->rm_next);
TEST_1(sdp_rtpmap_match(&sdp_rtpmap_g728, rm));
TEST(sdp_rtpmap_find_matching(&sdp_rtpmap_g728, rm), &sdp_rtpmap_g728);
TEST_1(rm = rm->rm_next);
TEST_1(sdp_rtpmap_match(&sdp_rtpmap_dvi4_11025, rm));
TEST(sdp_rtpmap_find_matching(&sdp_rtpmap_dvi4_11025, rm),
&sdp_rtpmap_dvi4_11025);
TEST_1(rm = rm->rm_next);
TEST_1(sdp_rtpmap_match(&sdp_rtpmap_dvi4_22050, rm));
TEST(sdp_rtpmap_find_matching(&sdp_rtpmap_dvi4_22050, rm),
&sdp_rtpmap_dvi4_22050);
TEST_1(rm = rm->rm_next);
TEST_1(sdp_rtpmap_match(&sdp_rtpmap_g729, rm));
TEST(sdp_rtpmap_find_matching(&sdp_rtpmap_g729, rm), &sdp_rtpmap_g729);
TEST_1(rm = rm->rm_next);
TEST_1(sdp_rtpmap_match(&sdp_rtpmap_cn_reserved, rm));
TEST(sdp_rtpmap_find_matching(&sdp_rtpmap_cn_reserved, rm),
&sdp_rtpmap_cn_reserved);
TEST_1(!rm->rm_next);
}
TEST_1((parser = sdp_parse(home, s2_msg, sizeof (s2_msg), 0)));
TEST_1((sdp = sdp_session(parser)));
TEST_1(m = sdp->sdp_media);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment