add sdp_msg API: SDP parsing/composition
Rationale: in order to add full SDP to the MNCC protocol (upcoming patch I8c3b2de53ffae4ec3a66b9dabf308c290a2c999f), we need to parse and compose SDP messages. Obviously, libosmo-mgcp-client already contains similar code, but that is unfortunately heavily glued to the actual MGCP implementation. The simplest solution is to create this separate implementation, copy-pasting from the existing libosmo-mgcp-client code as is convenient. This API is added here to probe whether it works well. When it does, the intention is to "move it up" to osmo-mgw and overhaul the SDP parsing in our MGCP client and MGCP server APIs using this same API. Change-Id: If3ce23cd5bab15e2ab4c52ef3e4c75979dffe931
This commit is contained in:
parent
bde605dfc5
commit
eef4578102
|
@ -254,6 +254,7 @@ AC_OUTPUT(
|
||||||
tests/db_sms/Makefile
|
tests/db_sms/Makefile
|
||||||
tests/sms_queue/Makefile
|
tests/sms_queue/Makefile
|
||||||
tests/msc_vlr/Makefile
|
tests/msc_vlr/Makefile
|
||||||
|
tests/sdp_msg/Makefile
|
||||||
doc/Makefile
|
doc/Makefile
|
||||||
doc/examples/Makefile
|
doc/examples/Makefile
|
||||||
doc/manuals/Makefile
|
doc/manuals/Makefile
|
||||||
|
|
|
@ -39,6 +39,7 @@ noinst_HEADERS = \
|
||||||
rrlp.h \
|
rrlp.h \
|
||||||
rtp_stream.h \
|
rtp_stream.h \
|
||||||
sccp_ran.h \
|
sccp_ran.h \
|
||||||
|
sdp_msg.h \
|
||||||
sgs_iface.h \
|
sgs_iface.h \
|
||||||
sgs_server.h \
|
sgs_server.h \
|
||||||
sgs_vty.h \
|
sgs_vty.h \
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
/* Minimalistic SDP parse/compose API, focused on GSM audio codecs */
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <osmocom/core/utils.h>
|
||||||
|
#include <osmocom/core/sockaddr_str.h>
|
||||||
|
|
||||||
|
extern const struct value_string sdp_msg_payload_type_names[];
|
||||||
|
static inline const char *sdp_msg_payload_type_name(unsigned int payload_type)
|
||||||
|
{ return get_value_string(sdp_msg_payload_type_names, payload_type); }
|
||||||
|
int sdp_subtype_name_to_payload_type(const char *subtype_name);
|
||||||
|
|
||||||
|
struct sdp_audio_codec {
|
||||||
|
unsigned int payload_type;
|
||||||
|
/* Like "GSM", "AMR", "EFR", ... */
|
||||||
|
char subtype_name[16];
|
||||||
|
unsigned int rate;
|
||||||
|
char fmtp[64];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sdp_audio_codecs {
|
||||||
|
unsigned int count;
|
||||||
|
struct sdp_audio_codec codec[16];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sdp_msg {
|
||||||
|
struct osmo_sockaddr_str rtp;
|
||||||
|
unsigned int ptime;
|
||||||
|
struct sdp_audio_codecs audio_codecs;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define foreach_sdp_audio_codec(/* struct sdp_audio_codec* */ CODEC, \
|
||||||
|
/* struct sdp_audio_codecs* */ AC) \
|
||||||
|
for (CODEC = (AC)->codec; \
|
||||||
|
(CODEC - (AC)->codec) < OSMO_MIN((AC)->count, ARRAY_SIZE((AC)->codec)); \
|
||||||
|
CODEC++)
|
||||||
|
|
||||||
|
const char *sdp_msg_line_end(const char *src);
|
||||||
|
|
||||||
|
int sdp_audio_codec_cmp(const struct sdp_audio_codec *a, const struct sdp_audio_codec *b);
|
||||||
|
|
||||||
|
struct sdp_audio_codec *sdp_audio_codec_add(struct sdp_audio_codecs *ac, unsigned int payload_type,
|
||||||
|
const char *subtype_name, unsigned int rate, const char *fmtp);
|
||||||
|
struct sdp_audio_codec *sdp_audio_codec_add_copy(struct sdp_audio_codecs *ac,
|
||||||
|
const struct sdp_audio_codec *codec);
|
||||||
|
int sdp_audio_codec_remove(struct sdp_audio_codecs *ac, const struct sdp_audio_codec *codec);
|
||||||
|
struct sdp_audio_codec *sdp_audio_codec_by_payload_type(struct sdp_audio_codecs *ac,
|
||||||
|
unsigned int payload_type, bool create);
|
||||||
|
struct sdp_audio_codec *sdp_audio_codec_by_descr(struct sdp_audio_codecs *ac,
|
||||||
|
const struct sdp_audio_codec *codec);
|
||||||
|
|
||||||
|
void sdp_audio_codecs_intersection(struct sdp_audio_codecs *ac_dest, const struct sdp_audio_codecs *ac_other,
|
||||||
|
bool translate_payload_type_numbers);
|
||||||
|
void sdp_audio_codecs_select(struct sdp_audio_codecs *ac, struct sdp_audio_codec *codec);
|
||||||
|
|
||||||
|
int sdp_msg_to_str(char *dst, size_t dst_size, const struct sdp_msg *sdp);
|
||||||
|
int sdp_msg_from_str(struct sdp_msg *sdp, const char *src);
|
||||||
|
|
||||||
|
int sdp_audio_codec_name_buf(char *buf, size_t buflen, const struct sdp_audio_codec *codec);
|
||||||
|
char *sdp_audio_codec_name_c(void *ctx, const struct sdp_audio_codec *codec);
|
||||||
|
const char *sdp_audio_codec_name(const struct sdp_audio_codec *codec);
|
||||||
|
|
||||||
|
int sdp_audio_codecs_name_buf(char *buf, size_t buflen, const struct sdp_audio_codecs *ac);
|
||||||
|
char *sdp_audio_codecs_name_c(void *ctx, const struct sdp_audio_codecs *ac);
|
||||||
|
const char *sdp_audio_codecs_name(const struct sdp_audio_codecs *ac);
|
||||||
|
|
||||||
|
int sdp_msg_name_buf(char *buf, size_t buflen, const struct sdp_msg *sdp);
|
||||||
|
char *sdp_msg_name_c(void *ctx, const struct sdp_msg *sdp);
|
||||||
|
const char *sdp_msg_name(const struct sdp_msg *sdp);
|
|
@ -64,6 +64,7 @@ libmsc_a_SOURCES = \
|
||||||
ran_peer.c \
|
ran_peer.c \
|
||||||
rrlp.c \
|
rrlp.c \
|
||||||
rtp_stream.c \
|
rtp_stream.c \
|
||||||
|
sdp_msg.c \
|
||||||
silent_call.c \
|
silent_call.c \
|
||||||
sms_queue.c \
|
sms_queue.c \
|
||||||
transaction.c \
|
transaction.c \
|
||||||
|
|
|
@ -0,0 +1,576 @@
|
||||||
|
/* Minimalistic SDP parse/compose implementation, focused on GSM audio codecs */
|
||||||
|
/*
|
||||||
|
* (C) 2019 by sysmocom - s.m.f.c. GmbH <info@sysmocom.de>
|
||||||
|
* All Rights Reserved
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0+
|
||||||
|
*
|
||||||
|
* Author: Neels Hofmeyr
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <osmocom/core/utils.h>
|
||||||
|
#include <osmocom/core/logging.h>
|
||||||
|
|
||||||
|
#include <osmocom/msc/debug.h>
|
||||||
|
#include <osmocom/msc/sdp_msg.h>
|
||||||
|
|
||||||
|
/* Compare name, rate and fmtp, returning typical cmp result: 0 on match, and -1 / 1 on mismatch.
|
||||||
|
* Do *not* compare the payload_type number.
|
||||||
|
* The fmtp is only string-compared -- e.g. if AMR parameters appear in a different order, it amounts to a mismatch even
|
||||||
|
* though all parameters are the same. */
|
||||||
|
int sdp_audio_codec_cmp(const struct sdp_audio_codec *a, const struct sdp_audio_codec *b)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
if (a == b)
|
||||||
|
return 0;
|
||||||
|
if (!a)
|
||||||
|
return -1;
|
||||||
|
if (!b)
|
||||||
|
return 1;
|
||||||
|
rc = strncmp(a->subtype_name, b->subtype_name, sizeof(a->subtype_name));
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
if (a->rate < b->rate)
|
||||||
|
return -1;
|
||||||
|
if (a->rate > b->rate)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
rc = strncmp(a->fmtp, b->fmtp, sizeof(a->fmtp));
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Given a predefined fixed payload_type number, add an SDP audio codec entry, if not present yet.
|
||||||
|
* The payload_type must exist in sdp_msg_payload_type_names.
|
||||||
|
* Return the audio codec created or already existing for this payload type number.
|
||||||
|
*/
|
||||||
|
struct sdp_audio_codec *sdp_audio_codec_add(struct sdp_audio_codecs *ac, unsigned int payload_type,
|
||||||
|
const char *subtype_name, unsigned int rate, const char *fmtp)
|
||||||
|
{
|
||||||
|
struct sdp_audio_codec *codec;
|
||||||
|
|
||||||
|
/* Does an entry already exist? */
|
||||||
|
codec = sdp_audio_codec_by_payload_type(ac, payload_type, false);
|
||||||
|
if (codec) {
|
||||||
|
/* Already exists, sanity check */
|
||||||
|
if (!codec->subtype_name[0])
|
||||||
|
OSMO_STRLCPY_ARRAY(codec->subtype_name, subtype_name);
|
||||||
|
else if (strcmp(codec->subtype_name, subtype_name)) {
|
||||||
|
/* There already is an entry with this payload_type number but a mismatching subtype_name. That is
|
||||||
|
* weird, rather abort. */
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (codec->rate != rate
|
||||||
|
|| (fmtp && strcmp(fmtp, codec->fmtp))) {
|
||||||
|
/* Mismatching details. Rather abort */
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return codec;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* None exists, create codec entry for this payload type number */
|
||||||
|
codec = sdp_audio_codec_by_payload_type(ac, payload_type, true);
|
||||||
|
/* NULL means unable to add an entry */
|
||||||
|
if (!codec)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
OSMO_STRLCPY_ARRAY(codec->subtype_name, subtype_name);
|
||||||
|
if (fmtp)
|
||||||
|
OSMO_STRLCPY_ARRAY(codec->fmtp, fmtp);
|
||||||
|
return codec;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sdp_audio_codec *sdp_audio_codec_add_copy(struct sdp_audio_codecs *ac, const struct sdp_audio_codec *codec)
|
||||||
|
{
|
||||||
|
return sdp_audio_codec_add(ac, codec->payload_type, codec->subtype_name, codec->rate,
|
||||||
|
codec->fmtp[0] ? codec->fmtp : NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sdp_audio_codec *sdp_audio_codec_by_payload_type(struct sdp_audio_codecs *ac, unsigned int payload_type,
|
||||||
|
bool create)
|
||||||
|
{
|
||||||
|
struct sdp_audio_codec *codec;
|
||||||
|
foreach_sdp_audio_codec(codec, ac) {
|
||||||
|
if (codec->payload_type == payload_type)
|
||||||
|
return codec;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!create)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Not found; codec points after the last entry now. */
|
||||||
|
if ((codec - ac->codec) >= ARRAY_SIZE(ac->codec))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
*codec = (struct sdp_audio_codec){
|
||||||
|
.payload_type = payload_type,
|
||||||
|
.rate = 8000,
|
||||||
|
};
|
||||||
|
|
||||||
|
ac->count = (codec - ac->codec) + 1;
|
||||||
|
return codec;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return a given sdp_msg's codec entry that matches the subtype_name, rate and fmtp of the given codec, or NULL if no
|
||||||
|
* match is found. Comparison is made by sdp_audio_codec_cmp(). */
|
||||||
|
struct sdp_audio_codec *sdp_audio_codec_by_descr(struct sdp_audio_codecs *ac, const struct sdp_audio_codec *codec)
|
||||||
|
{
|
||||||
|
struct sdp_audio_codec *i;
|
||||||
|
foreach_sdp_audio_codec(i, ac) {
|
||||||
|
if (!sdp_audio_codec_cmp(i, codec))
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove the codec entry pointed at by 'codec'. 'codec' must point at an entry of 'sdp' (to use an external codec
|
||||||
|
* instance, use sdp_audio_codec_by_descr()).
|
||||||
|
* Return 0 on success, -ENOENT if codec does not point at the sdp->codec array. */
|
||||||
|
int sdp_audio_codec_remove(struct sdp_audio_codecs *ac, const struct sdp_audio_codec *codec)
|
||||||
|
{
|
||||||
|
struct sdp_audio_codec *i;
|
||||||
|
if ((codec < ac->codec)
|
||||||
|
|| ((codec - ac->codec) >= OSMO_MIN(ac->count, ARRAY_SIZE(ac->codec))))
|
||||||
|
return -ENOENT;
|
||||||
|
|
||||||
|
/* Move all following entries one up */
|
||||||
|
ac->count--;
|
||||||
|
foreach_sdp_audio_codec(i, ac) {
|
||||||
|
if (i < codec)
|
||||||
|
continue;
|
||||||
|
*i = *(i+1);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert struct sdp_msg to the actual SDP protocol representation */
|
||||||
|
int sdp_msg_to_str(char *dst, size_t dst_size, const struct sdp_msg *sdp)
|
||||||
|
{
|
||||||
|
const struct sdp_audio_codec *codec;
|
||||||
|
struct osmo_strbuf sb = { .buf = dst, .len = dst_size };
|
||||||
|
const char *ip = sdp->rtp.ip[0] ? sdp->rtp.ip : "0.0.0.0";
|
||||||
|
|
||||||
|
OSMO_STRBUF_PRINTF(sb,
|
||||||
|
"v=0\r\n"
|
||||||
|
"o=OsmoMSC 0 0 IN IP4 %s\r\n"
|
||||||
|
"s=GSM Call\r\n"
|
||||||
|
"c=IN IP4 %s\r\n"
|
||||||
|
"t=0 0\r\n"
|
||||||
|
"m=audio %d RTP/AVP",
|
||||||
|
ip, ip,
|
||||||
|
sdp->rtp.port);
|
||||||
|
|
||||||
|
/* Append all payload type numbers to 'm=audio <port> RTP/AVP 3 4 112' line */
|
||||||
|
foreach_sdp_audio_codec(codec, &sdp->audio_codecs)
|
||||||
|
OSMO_STRBUF_PRINTF(sb, " %d", codec->payload_type);
|
||||||
|
OSMO_STRBUF_PRINTF(sb, "\r\n");
|
||||||
|
|
||||||
|
/* Add details for all codecs */
|
||||||
|
foreach_sdp_audio_codec(codec, &sdp->audio_codecs) {
|
||||||
|
if (codec->subtype_name[0]) {
|
||||||
|
OSMO_STRBUF_PRINTF(sb, "a=rtpmap:%d %s/%d\r\n", codec->payload_type, codec->subtype_name,
|
||||||
|
codec->rate > 0? codec->rate : 8000);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (codec->fmtp[0])
|
||||||
|
OSMO_STRBUF_PRINTF(sb, "a=fmtp:%d %s\r\n", codec->payload_type, codec->fmtp);
|
||||||
|
}
|
||||||
|
|
||||||
|
OSMO_STRBUF_PRINTF(sb, "a=ptime:%d\r\n", sdp->ptime > 0? sdp->ptime : 20);
|
||||||
|
|
||||||
|
return sb.chars_needed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return the first line ending (or the end of the string) at or after the given string position. */
|
||||||
|
const char *sdp_msg_line_end(const char *src)
|
||||||
|
{
|
||||||
|
const char *line_end = strchr(src, '\r');
|
||||||
|
if (!line_end)
|
||||||
|
line_end = strchr(src, '\n');
|
||||||
|
if (!line_end)
|
||||||
|
line_end = src + strlen(src);
|
||||||
|
return line_end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* parse a line like 'a=rtpmap:0 PCMU/8000', 'a=fmtp:112 octet-align=1; mode-set=4', 'a=ptime:20'.
|
||||||
|
* The src should point at the character after 'a=', e.g. at the start of 'rtpmap', 'fmtp', 'ptime'
|
||||||
|
*/
|
||||||
|
int sdp_parse_attrib(struct sdp_msg *sdp, const char *src)
|
||||||
|
{
|
||||||
|
unsigned int payload_type;
|
||||||
|
struct sdp_audio_codec *codec;
|
||||||
|
#define A_RTPMAP "rtpmap:"
|
||||||
|
#define A_FMTP "fmtp:"
|
||||||
|
#define A_PTIME "ptime:"
|
||||||
|
#define A_RTCP "rtcp:"
|
||||||
|
#define A_SENDRECV "sendrecv"
|
||||||
|
#define A_SENDONLY "sendonly"
|
||||||
|
#define A_RECVONLY "recvonly"
|
||||||
|
|
||||||
|
if (osmo_str_startswith(src, A_RTPMAP)) {
|
||||||
|
char *audio_name;
|
||||||
|
unsigned int channels = 1;
|
||||||
|
if (sscanf(src, A_RTPMAP "%u", &payload_type) != 1)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
audio_name = strchr(src, ' ');
|
||||||
|
if (!audio_name || audio_name >= sdp_msg_line_end(src))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
codec = sdp_audio_codec_by_payload_type(&sdp->audio_codecs, payload_type, true);
|
||||||
|
if (!codec)
|
||||||
|
return -ENOSPC;
|
||||||
|
|
||||||
|
if (sscanf(audio_name, " %31[^/]/%u/%u", codec->subtype_name, &codec->rate, &channels) < 1)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (channels != 1)
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (osmo_str_startswith(src, A_FMTP)) {
|
||||||
|
char *fmtp_str;
|
||||||
|
const char *line_end = sdp_msg_line_end(src);
|
||||||
|
if (sscanf(src, A_FMTP "%u", &payload_type) != 1)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
fmtp_str = strchr(src, ' ');
|
||||||
|
if (!fmtp_str)
|
||||||
|
return -EINVAL;
|
||||||
|
fmtp_str++;
|
||||||
|
if (fmtp_str >= line_end)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
codec = sdp_audio_codec_by_payload_type(&sdp->audio_codecs, payload_type, true);
|
||||||
|
if (!codec)
|
||||||
|
return -ENOSPC;
|
||||||
|
|
||||||
|
/* (+1 because osmo_strlcpy() interprets it as size including the '\0') */
|
||||||
|
osmo_strlcpy(codec->fmtp, fmtp_str, line_end - fmtp_str + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (osmo_str_startswith(src, A_PTIME)) {
|
||||||
|
if (sscanf(src, A_PTIME "%u", &sdp->ptime) != 1)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (osmo_str_startswith(src, A_RTCP)) {
|
||||||
|
/* TODO? */
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (osmo_str_startswith(src, A_SENDRECV)) {
|
||||||
|
/* TODO? */
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (osmo_str_startswith(src, A_SENDONLY)) {
|
||||||
|
/* TODO? */
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (osmo_str_startswith(src, A_RECVONLY)) {
|
||||||
|
/* TODO? */
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct value_string sdp_msg_payload_type_names[] = {
|
||||||
|
{ 0, "PCMU" },
|
||||||
|
{ 3, "GSM" },
|
||||||
|
{ 8, "PCMA" },
|
||||||
|
{ 18, "G729" },
|
||||||
|
{ 110, "GSM-EFR" },
|
||||||
|
{ 111, "GSM-HR-08" },
|
||||||
|
{ 112, "AMR" },
|
||||||
|
{ 113, "AMR-WB" },
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Return payload type number matching given string ("AMR", "GSM", ...) or negative if not found. */
|
||||||
|
int sdp_subtype_name_to_payload_type(const char *subtype_name)
|
||||||
|
{
|
||||||
|
return get_string_value(sdp_msg_payload_type_names, subtype_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse a line like 'm=audio 16398 RTP/AVP 0 3 8 96 112', starting after the '=' */
|
||||||
|
static int sdp_parse_media_description(struct sdp_msg *sdp, const char *src)
|
||||||
|
{
|
||||||
|
unsigned int port;
|
||||||
|
int i;
|
||||||
|
const char *payload_type_str;
|
||||||
|
const char *line_end = sdp_msg_line_end(src);
|
||||||
|
if (sscanf(src, "audio %u RTP/AVP", &port) < 1)
|
||||||
|
return -ENOTSUP;
|
||||||
|
|
||||||
|
if (port < 0 || port > 0xffff)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
sdp->rtp.port = port;
|
||||||
|
|
||||||
|
/* skip "audio 12345 RTP/AVP ", i.e. 3 spaces on */
|
||||||
|
payload_type_str = src;
|
||||||
|
for (i = 0; i < 3; i++) {
|
||||||
|
payload_type_str = strchr(payload_type_str, ' ');
|
||||||
|
if (!payload_type_str)
|
||||||
|
return -EINVAL;
|
||||||
|
while (*payload_type_str == ' ')
|
||||||
|
payload_type_str++;
|
||||||
|
if (payload_type_str >= line_end)
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse listing of payload type numbers after "RTP/AVP" */
|
||||||
|
while (payload_type_str < line_end) {
|
||||||
|
unsigned int payload_type;
|
||||||
|
struct sdp_audio_codec *codec;
|
||||||
|
const char *subtype_name;
|
||||||
|
if (sscanf(payload_type_str, "%u", &payload_type) < 1)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
codec = sdp_audio_codec_by_payload_type(&sdp->audio_codecs, payload_type, true);
|
||||||
|
if (!codec)
|
||||||
|
return -ENOSPC;
|
||||||
|
|
||||||
|
/* Fill in subtype name for fixed payload types */
|
||||||
|
subtype_name = get_value_string_or_null(sdp_msg_payload_type_names, codec->payload_type);
|
||||||
|
if (subtype_name)
|
||||||
|
OSMO_STRLCPY_ARRAY(codec->subtype_name, subtype_name);
|
||||||
|
|
||||||
|
payload_type_str = strchr(payload_type_str, ' ');
|
||||||
|
if (!payload_type_str)
|
||||||
|
payload_type_str = line_end;
|
||||||
|
while (*payload_type_str == ' ')
|
||||||
|
payload_type_str++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* parse a line like 'c=IN IP4 192.168.11.151' starting after the '=' */
|
||||||
|
static int sdp_parse_connection_info(struct sdp_msg *sdp, const char *src)
|
||||||
|
{
|
||||||
|
char ipv[10];
|
||||||
|
char addr_str[INET6_ADDRSTRLEN];
|
||||||
|
if (sscanf(src, "IN %s %s", ipv, addr_str) < 2)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
/* supporting only IPv4 */
|
||||||
|
if (strcmp(ipv, "IP4"))
|
||||||
|
return -ENOTSUP;
|
||||||
|
|
||||||
|
osmo_sockaddr_str_from_str(&sdp->rtp, addr_str, sdp->rtp.port);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse SDP string into struct sdp_msg. Return 0 on success, negative on error. */
|
||||||
|
int sdp_msg_from_str(struct sdp_msg *sdp, const char *src)
|
||||||
|
{
|
||||||
|
const char *pos;
|
||||||
|
*sdp = (struct sdp_msg){};
|
||||||
|
|
||||||
|
for (pos = src; pos && *pos; pos++) {
|
||||||
|
char attrib;
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
if (*pos == '\r' || *pos == '\n')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Expecting only lines starting with 'X='. Not being too strict about it is probably alright. */
|
||||||
|
if (pos[1] != '=')
|
||||||
|
goto next_line;
|
||||||
|
|
||||||
|
attrib = *pos;
|
||||||
|
pos += 2;
|
||||||
|
switch (attrib) {
|
||||||
|
/* a=... */
|
||||||
|
case 'a':
|
||||||
|
rc = sdp_parse_attrib(sdp, pos);
|
||||||
|
break;
|
||||||
|
case 'm':
|
||||||
|
rc = sdp_parse_media_description(sdp, pos);
|
||||||
|
break;
|
||||||
|
case 'c':
|
||||||
|
rc = sdp_parse_connection_info(sdp, pos);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* ignore any other parameters */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rc) {
|
||||||
|
size_t line_len;
|
||||||
|
const char *line_end = sdp_msg_line_end(pos);
|
||||||
|
pos -= 2;
|
||||||
|
line_len = line_end - pos;
|
||||||
|
switch (rc) {
|
||||||
|
case -EINVAL:
|
||||||
|
LOGP(DMNCC, LOGL_ERROR,
|
||||||
|
"Failed to parse SDP: invalid line: %s\n", osmo_quote_str(pos, line_len));
|
||||||
|
break;
|
||||||
|
case -ENOSPC:
|
||||||
|
LOGP(DMNCC, LOGL_ERROR,
|
||||||
|
"Failed to parse SDP: no more space for: %s\n", osmo_quote_str(pos, line_len));
|
||||||
|
break;
|
||||||
|
case -ENOTSUP:
|
||||||
|
LOGP(DMNCC, LOGL_ERROR,
|
||||||
|
"Failed to parse SDP: not supported: %s\n", osmo_quote_str(pos, line_len));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOGP(DMNCC, LOGL_ERROR,
|
||||||
|
"Failed to parse SDP: %s\n", osmo_quote_str(pos, line_len));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
next_line:
|
||||||
|
pos = strstr(pos, "\r\n");
|
||||||
|
if (!pos)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Leave only those codecs in 'ac_dest' that are also present in 'ac_other'.
|
||||||
|
* The matching is made by sdp_audio_codec_cmp(), i.e. payload_type numbers are not compared and fmtp parameters are
|
||||||
|
* compared 1:1 as plain strings.
|
||||||
|
* If translate_payload_type_numbers has an effect if ac_dest and ac_other have mismatching payload_type numbers for the
|
||||||
|
* same SDP codec descriptions. If translate_payload_type_numbers is true, take the payload_type numbers from ac_other.
|
||||||
|
* If false, keep payload_type numbers in ac_dest unchanged. */
|
||||||
|
void sdp_audio_codecs_intersection(struct sdp_audio_codecs *ac_dest, const struct sdp_audio_codecs *ac_other,
|
||||||
|
bool translate_payload_type_numbers)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < ac_dest->count; i++) {
|
||||||
|
struct sdp_audio_codec *codec = &ac_dest->codec[i];
|
||||||
|
struct sdp_audio_codec *other;
|
||||||
|
OSMO_ASSERT(i < ARRAY_SIZE(ac_dest->codec));
|
||||||
|
|
||||||
|
other = sdp_audio_codec_by_descr((struct sdp_audio_codecs*)ac_other, codec);
|
||||||
|
|
||||||
|
if (!other) {
|
||||||
|
OSMO_ASSERT(sdp_audio_codec_remove(ac_dest, codec) == 0);
|
||||||
|
i--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Doing payload_type number translation of part of the intersection because it makes the algorithm
|
||||||
|
* simpler: we already know ac_dest is a subset of ac_other, and there is no need to resolve payload
|
||||||
|
* type number conflicts. */
|
||||||
|
if (translate_payload_type_numbers)
|
||||||
|
codec->payload_type = other->payload_type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure the given codec is listed as the first codec. 'codec' must be an actual codec entry of the given audio
|
||||||
|
* codecs list. */
|
||||||
|
void sdp_audio_codecs_select(struct sdp_audio_codecs *ac, struct sdp_audio_codec *codec)
|
||||||
|
{
|
||||||
|
struct sdp_audio_codec tmp;
|
||||||
|
struct sdp_audio_codec *pos;
|
||||||
|
OSMO_ASSERT((codec >= ac->codec)
|
||||||
|
&& ((codec - ac->codec) < OSMO_MIN(ac->count, ARRAY_SIZE(ac->codec))));
|
||||||
|
|
||||||
|
/* Already the first? */
|
||||||
|
if (codec == ac->codec)
|
||||||
|
return;
|
||||||
|
|
||||||
|
tmp = *codec;
|
||||||
|
for (pos = codec - 1; pos >= ac->codec; pos--)
|
||||||
|
pos[1] = pos[0];
|
||||||
|
|
||||||
|
ac->codec[0] = tmp;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Short single-line representation of an SDP audio codec, convenient for logging.
|
||||||
|
* Like "AMR/8000:octet-align=1#122" */
|
||||||
|
int sdp_audio_codec_name_buf(char *buf, size_t buflen, const struct sdp_audio_codec *codec)
|
||||||
|
{
|
||||||
|
struct osmo_strbuf sb = { .buf = buf, .len = buflen };
|
||||||
|
OSMO_STRBUF_PRINTF(sb, "%s", codec->subtype_name);
|
||||||
|
if (codec->fmtp[0])
|
||||||
|
OSMO_STRBUF_PRINTF(sb, ":%s", codec->fmtp);
|
||||||
|
return sb.chars_needed;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *sdp_audio_codec_name_c(void *ctx, const struct sdp_audio_codec *codec)
|
||||||
|
{
|
||||||
|
OSMO_NAME_C_IMPL(ctx, 32, "sdp_audio_codec_name_c-ERROR", sdp_audio_codec_name_buf, codec)
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *sdp_audio_codec_name(const struct sdp_audio_codec *codec)
|
||||||
|
{
|
||||||
|
return sdp_audio_codec_name_c(OTC_SELECT, codec);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Short single-line representation of a list of SDP audio codecs, convenient for logging */
|
||||||
|
int sdp_audio_codecs_name_buf(char *buf, size_t buflen, const struct sdp_audio_codecs *ac)
|
||||||
|
{
|
||||||
|
struct osmo_strbuf sb = { .buf = buf, .len = buflen };
|
||||||
|
const struct sdp_audio_codec *codec;
|
||||||
|
if (!ac->count)
|
||||||
|
OSMO_STRBUF_PRINTF(sb, "(no-codecs)");
|
||||||
|
foreach_sdp_audio_codec(codec, ac) {
|
||||||
|
bool first = (codec == ac->codec);
|
||||||
|
if (!first)
|
||||||
|
OSMO_STRBUF_PRINTF(sb, ",");
|
||||||
|
OSMO_STRBUF_APPEND(sb, sdp_audio_codec_name_buf, codec);
|
||||||
|
}
|
||||||
|
return sb.chars_needed;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *sdp_audio_codecs_name_c(void *ctx, const struct sdp_audio_codecs *ac)
|
||||||
|
{
|
||||||
|
OSMO_NAME_C_IMPL(ctx, 128, "sdp_audio_codecs_name_c-ERROR", sdp_audio_codecs_name_buf, ac)
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *sdp_audio_codecs_name(const struct sdp_audio_codecs *ac)
|
||||||
|
{
|
||||||
|
return sdp_audio_codecs_name_c(OTC_SELECT, ac);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Short single-line representation of an SDP message, convenient for logging */
|
||||||
|
int sdp_msg_name_buf(char *buf, size_t buflen, const struct sdp_msg *sdp)
|
||||||
|
{
|
||||||
|
struct osmo_strbuf sb = { .buf = buf, .len = buflen };
|
||||||
|
if (!sdp) {
|
||||||
|
OSMO_STRBUF_PRINTF(sb, "NULL");
|
||||||
|
return sb.chars_needed;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSMO_STRBUF_PRINTF(sb, OSMO_SOCKADDR_STR_FMT, OSMO_SOCKADDR_STR_FMT_ARGS(&sdp->rtp));
|
||||||
|
OSMO_STRBUF_PRINTF(sb, "{");
|
||||||
|
OSMO_STRBUF_APPEND(sb, sdp_audio_codecs_name_buf, &sdp->audio_codecs);
|
||||||
|
OSMO_STRBUF_PRINTF(sb, "}");
|
||||||
|
return sb.chars_needed;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *sdp_msg_name_c(void *ctx, const struct sdp_msg *sdp)
|
||||||
|
{
|
||||||
|
OSMO_NAME_C_IMPL(ctx, 128, "sdp_msg_name_c-ERROR", sdp_msg_name_buf, sdp)
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *sdp_msg_name(const struct sdp_msg *sdp)
|
||||||
|
{
|
||||||
|
return sdp_msg_name_c(OTC_SELECT, sdp);
|
||||||
|
}
|
|
@ -2,6 +2,7 @@ SUBDIRS = \
|
||||||
sms_queue \
|
sms_queue \
|
||||||
msc_vlr \
|
msc_vlr \
|
||||||
db_sms \
|
db_sms \
|
||||||
|
sdp_msg \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
if BUILD_SMPP
|
if BUILD_SMPP
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
AM_CPPFLAGS = \
|
||||||
|
$(all_includes) \
|
||||||
|
-I$(top_srcdir)/include \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
|
AM_CFLAGS = \
|
||||||
|
-Wall \
|
||||||
|
-ggdb3 \
|
||||||
|
$(LIBOSMOCORE_CFLAGS) \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
|
LDADD = \
|
||||||
|
$(top_builddir)/src/libmsc/libmsc.a \
|
||||||
|
$(LIBOSMOCORE_LIBS) \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
|
EXTRA_DIST = \
|
||||||
|
sdp_msg_test.ok \
|
||||||
|
sdp_msg_test.err \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
|
noinst_PROGRAMS = \
|
||||||
|
sdp_msg_test \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
|
sdp_msg_test_SOURCES = \
|
||||||
|
sdp_msg_test.c \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
|
.PHONY: update_exp
|
||||||
|
update_exp:
|
||||||
|
$(builddir)/sdp_msg_test >$(srcdir)/sdp_msg_test.ok 2>$(srcdir)/sdp_msg_test.err
|
|
@ -0,0 +1,569 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <osmocom/core/utils.h>
|
||||||
|
#include <osmocom/msc/sdp_msg.h>
|
||||||
|
|
||||||
|
struct sdp_test_data {
|
||||||
|
const char *sdp_input;
|
||||||
|
const char *expect_sdp_str;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void dump_sdp(const char *str, const char *prefix)
|
||||||
|
{
|
||||||
|
while (str && *str) {
|
||||||
|
const char *line_end = sdp_msg_line_end(str);
|
||||||
|
while (*line_end == '\r' || *line_end == '\n')
|
||||||
|
line_end++;
|
||||||
|
printf("%s%s\n", prefix, osmo_escape_str(str, line_end - str));
|
||||||
|
str = line_end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sdp_test_data sdp_tests[] = {
|
||||||
|
{
|
||||||
|
"v=0\r\n"
|
||||||
|
"o=- 5628250 5628250 IN IP4 192.168.11.121\r\n"
|
||||||
|
"s=-\r\n"
|
||||||
|
"c=IN IP4 192.168.11.121\r\n"
|
||||||
|
"t=0 0\r\n"
|
||||||
|
"m=audio 10020 RTP/AVP 18 0 2 4 8 96 97 98 100 101\r\n"
|
||||||
|
"a=rtpmap:18 G729/8000\r\n"
|
||||||
|
"a=rtpmap:0 PCMU/8000\r\n"
|
||||||
|
"a=rtpmap:2 G726-32/8000\r\n"
|
||||||
|
"a=rtpmap:4 G723/8000\r\n"
|
||||||
|
"a=rtpmap:8 PCMA/8000\r\n"
|
||||||
|
"a=rtpmap:96 G726-40/8000\r\n"
|
||||||
|
"a=rtpmap:97 G726-24/8000\r\n"
|
||||||
|
"a=rtpmap:98 G726-16/8000\r\n"
|
||||||
|
"a=rtpmap:100 NSE/8000\r\n"
|
||||||
|
"a=fmtp:100 192-193\r\n"
|
||||||
|
"a=rtpmap:101 telephone-event/8000\r\n"
|
||||||
|
"a=fmtp:101 0-15\r\n"
|
||||||
|
"a=ptime:20\r\n"
|
||||||
|
"a=sendrecv\r\n"
|
||||||
|
,
|
||||||
|
"v=0\r\n"
|
||||||
|
"o=OsmoMSC 0 0 IN IP4 192.168.11.121\r\n"
|
||||||
|
"s=GSM Call\r\n"
|
||||||
|
"c=IN IP4 192.168.11.121\r\n"
|
||||||
|
"t=0 0\r\n"
|
||||||
|
"m=audio 10020 RTP/AVP 18 0 2 4 8 96 97 98 100 101\r\n"
|
||||||
|
"a=rtpmap:18 G729/8000\r\n"
|
||||||
|
"a=rtpmap:0 PCMU/8000\r\n"
|
||||||
|
"a=rtpmap:2 G726-32/8000\r\n"
|
||||||
|
"a=rtpmap:4 G723/8000\r\n"
|
||||||
|
"a=rtpmap:8 PCMA/8000\r\n"
|
||||||
|
"a=rtpmap:96 G726-40/8000\r\n"
|
||||||
|
"a=rtpmap:97 G726-24/8000\r\n"
|
||||||
|
"a=rtpmap:98 G726-16/8000\r\n"
|
||||||
|
"a=rtpmap:100 NSE/8000\r\n"
|
||||||
|
"a=fmtp:100 192-193\r\n"
|
||||||
|
"a=rtpmap:101 telephone-event/8000\r\n"
|
||||||
|
"a=fmtp:101 0-15\r\n"
|
||||||
|
"a=ptime:20\r\n"
|
||||||
|
,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"v=0\r\n"
|
||||||
|
"o=FooBar 1565090289 1565090290 IN IP4 192.168.11.151\r\n"
|
||||||
|
"s=FooBar\r\n"
|
||||||
|
"c=IN IP4 192.168.11.151\r\n"
|
||||||
|
"t=0 0\r\n"
|
||||||
|
"m=audio 16398 RTP/AVP 98\r\n"
|
||||||
|
"a=rtpmap:98 AMR/8000\r\n"
|
||||||
|
"a=fmtp:98 octet-align=1; mode-set=4\r\n"
|
||||||
|
"a=ptime:20\r\n"
|
||||||
|
"a=rtcp:16399 IN IP4 192.168.11.151\r\n"
|
||||||
|
,
|
||||||
|
"v=0\r\n"
|
||||||
|
"o=OsmoMSC 0 0 IN IP4 192.168.11.151\r\n"
|
||||||
|
"s=GSM Call\r\n"
|
||||||
|
"c=IN IP4 192.168.11.151\r\n"
|
||||||
|
"t=0 0\r\n"
|
||||||
|
"m=audio 16398 RTP/AVP 98\r\n"
|
||||||
|
"a=rtpmap:98 AMR/8000\r\n"
|
||||||
|
"a=fmtp:98 octet-align=1; mode-set=4\r\n"
|
||||||
|
"a=ptime:20\r\n"
|
||||||
|
,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"v=0\r\n"
|
||||||
|
"o=FooBar 1565090289 1565090290 IN IP4 192.168.11.151\r\n"
|
||||||
|
"s=FooBar\r\n"
|
||||||
|
"c=IN IP4 192.168.11.140\r\n"
|
||||||
|
"t=0 0\r\n"
|
||||||
|
"m=audio 30436 RTP/AVP 18 0 4 8 101\r\n"
|
||||||
|
"a=rtpmap:18 G729/8000\r\n"
|
||||||
|
"a=rtpmap:0 PCMU/8000\r\n"
|
||||||
|
"a=rtpmap:4 G723/8000\r\n"
|
||||||
|
"a=rtpmap:8 PCMA/8000\r\n"
|
||||||
|
"a=rtpmap:101 telephone-event/8000\r\n"
|
||||||
|
"a=fmtp:101 0-15\r\n"
|
||||||
|
"a=sendrecv\r\n"
|
||||||
|
"a=rtcp:30437\r\n"
|
||||||
|
"a=ptime:20\r\n"
|
||||||
|
,
|
||||||
|
"v=0\r\n"
|
||||||
|
"o=OsmoMSC 0 0 IN IP4 192.168.11.140\r\n" /* <- NOTE: loses the 'o=' address, uses only 'c=' */
|
||||||
|
"s=GSM Call\r\n"
|
||||||
|
"c=IN IP4 192.168.11.140\r\n"
|
||||||
|
"t=0 0\r\n"
|
||||||
|
"m=audio 30436 RTP/AVP 18 0 4 8 101\r\n"
|
||||||
|
"a=rtpmap:18 G729/8000\r\n"
|
||||||
|
"a=rtpmap:0 PCMU/8000\r\n"
|
||||||
|
"a=rtpmap:4 G723/8000\r\n"
|
||||||
|
"a=rtpmap:8 PCMA/8000\r\n"
|
||||||
|
"a=rtpmap:101 telephone-event/8000\r\n"
|
||||||
|
"a=fmtp:101 0-15\r\n"
|
||||||
|
"a=ptime:20\r\n"
|
||||||
|
,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
void test_parse_and_compose()
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
bool ok = true;
|
||||||
|
|
||||||
|
printf("\n\n%s\n", __func__);
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(sdp_tests); i++) {
|
||||||
|
struct sdp_test_data *t = &sdp_tests[i];
|
||||||
|
struct sdp_msg sdp = {};
|
||||||
|
char str[1024];
|
||||||
|
printf("\n[%d]\n", i);
|
||||||
|
dump_sdp(t->sdp_input, "sdp input: ");
|
||||||
|
|
||||||
|
sdp_msg_from_str(&sdp, t->sdp_input);
|
||||||
|
sdp_msg_to_str(str, sizeof(str), &sdp);
|
||||||
|
|
||||||
|
dump_sdp(str, "sdp_msg_to_str: ");
|
||||||
|
if (strcmp(str, t->expect_sdp_str)) {
|
||||||
|
int j;
|
||||||
|
ok = false;
|
||||||
|
printf("ERROR:\n");
|
||||||
|
dump_sdp(t->expect_sdp_str, "expect_sdp_str: ");
|
||||||
|
for (j = 0; t->expect_sdp_str[j]; j++) {
|
||||||
|
if (t->expect_sdp_str[j] != str[j]) {
|
||||||
|
printf("ERROR at position %d, at:\n", j);
|
||||||
|
dump_sdp(str + j, " mismatch: ");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
printf("[%d] ok\n", i);
|
||||||
|
}
|
||||||
|
|
||||||
|
OSMO_ASSERT(ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sdp_intersect_test_data {
|
||||||
|
const char *descr;
|
||||||
|
const char *sdp_a;
|
||||||
|
const char *sdp_b;
|
||||||
|
const char *expect_intersection;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define SDP_1 \
|
||||||
|
"v=0\r\n" \
|
||||||
|
"o=OsmoMSC 0 0 IN IP4 23.42.23.42\r\n" \
|
||||||
|
"s=GSM Call\r\n" \
|
||||||
|
"c=IN IP4 23.42.23.42\r\n" \
|
||||||
|
"t=0 0\r\n" \
|
||||||
|
"m=audio 30436 RTP/AVP 112 3 111 110\r\n" \
|
||||||
|
"a=rtpmap:112 AMR/8000\r\n" \
|
||||||
|
"a=fmtp:112 octet-align=1\r\n" \
|
||||||
|
"a=rtpmap:3 GSM/8000\r\n" \
|
||||||
|
"a=rtpmap:111 GSM-HR-08/8000\r\n" \
|
||||||
|
"a=rtpmap:110 GSM-EFR/8000\r\n" \
|
||||||
|
"a=ptime:20\r\n"
|
||||||
|
|
||||||
|
#define SDP_2 \
|
||||||
|
"v=0\r\n" \
|
||||||
|
"o=OsmoMSC 0 0 IN IP4 23.42.23.42\r\n" \
|
||||||
|
"s=GSM Call\r\n" \
|
||||||
|
"c=IN IP4 23.42.23.42\r\n" \
|
||||||
|
"t=0 0\r\n" \
|
||||||
|
"m=audio 30436 RTP/AVP 112 110\r\n" \
|
||||||
|
"a=rtpmap:112 AMR/8000\r\n" \
|
||||||
|
"a=fmtp:112 octet-align=1\r\n" \
|
||||||
|
"a=rtpmap:110 GSM-EFR/8000\r\n" \
|
||||||
|
"a=ptime:20\r\n"
|
||||||
|
|
||||||
|
#define SDP_3 \
|
||||||
|
"v=0\r\n" \
|
||||||
|
"o=OsmoMSC 0 0 IN IP4 23.42.23.42\r\n" \
|
||||||
|
"s=GSM Call\r\n" \
|
||||||
|
"c=IN IP4 23.42.23.42\r\n" \
|
||||||
|
"t=0 0\r\n" \
|
||||||
|
"m=audio 30436 RTP/AVP 3 111\r\n" \
|
||||||
|
"a=rtpmap:3 GSM/8000\r\n" \
|
||||||
|
"a=rtpmap:111 GSM-HR-08/8000\r\n" \
|
||||||
|
"a=ptime:20\r\n"
|
||||||
|
|
||||||
|
|
||||||
|
struct sdp_intersect_test_data sdp_intersect_tests[] = {
|
||||||
|
{
|
||||||
|
"identical codecs lead to no change"
|
||||||
|
,
|
||||||
|
SDP_1
|
||||||
|
,
|
||||||
|
"c=IN IP4 5.6.7.8\r\n" \
|
||||||
|
"m=audio 12345 RTP/AVP 112 3 111 110\r\n"
|
||||||
|
"a=rtpmap:112 AMR/8000\r\n"
|
||||||
|
"a=fmtp:112 octet-align=1\r\n"
|
||||||
|
"a=rtpmap:3 GSM/8000\r\n"
|
||||||
|
"a=rtpmap:111 GSM-HR-08/8000\r\n"
|
||||||
|
"a=rtpmap:110 GSM-EFR/8000\r\n"
|
||||||
|
,
|
||||||
|
SDP_1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identical codecs in different order also lead to no change"
|
||||||
|
,
|
||||||
|
SDP_1
|
||||||
|
,
|
||||||
|
"c=IN IP4 5.6.7.8\r\n" \
|
||||||
|
"m=audio 12345 RTP/AVP 3 110 111 112\r\n"
|
||||||
|
"a=rtpmap:3 GSM/8000\r\n"
|
||||||
|
"a=rtpmap:110 GSM-EFR/8000\r\n"
|
||||||
|
"a=rtpmap:111 GSM-HR-08/8000\r\n"
|
||||||
|
"a=rtpmap:112 AMR/8000\r\n"
|
||||||
|
"a=fmtp:112 octet-align=1\r\n"
|
||||||
|
,
|
||||||
|
SDP_1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identical codecs with mismatching payload type numbers also lead to no change"
|
||||||
|
,
|
||||||
|
SDP_1
|
||||||
|
,
|
||||||
|
"c=IN IP4 5.6.7.8\r\n" \
|
||||||
|
"m=audio 12345 RTP/AVP 96 97 98 99\r\n"
|
||||||
|
"a=rtpmap:96 GSM/8000\r\n"
|
||||||
|
"a=rtpmap:97 GSM-EFR/8000\r\n"
|
||||||
|
"a=rtpmap:98 GSM-HR-08/8000\r\n"
|
||||||
|
"a=rtpmap:99 AMR/8000\r\n"
|
||||||
|
"a=fmtp:99 octet-align=1\r\n"
|
||||||
|
,
|
||||||
|
SDP_1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identical codecs plus some extra codecs also lead to no change"
|
||||||
|
,
|
||||||
|
SDP_1
|
||||||
|
,
|
||||||
|
"c=IN IP4 5.6.7.8\r\n" \
|
||||||
|
"m=audio 12345 RTP/AVP 8 0 96 97 98 99\r\n"
|
||||||
|
"a=rtpmap:8 PCMA/8000\r\n"
|
||||||
|
"a=rtpmap:0 PCMU/8000\r\n"
|
||||||
|
"a=rtpmap:96 GSM/8000\r\n"
|
||||||
|
"a=rtpmap:97 GSM-EFR/8000\r\n"
|
||||||
|
"a=rtpmap:98 GSM-HR-08/8000\r\n"
|
||||||
|
"a=rtpmap:99 AMR/8000\r\n"
|
||||||
|
"a=fmtp:99 octet-align=1\r\n"
|
||||||
|
,
|
||||||
|
SDP_1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"some codecs removed",
|
||||||
|
SDP_1,
|
||||||
|
SDP_2,
|
||||||
|
SDP_2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"other codecs removed",
|
||||||
|
SDP_1,
|
||||||
|
SDP_3,
|
||||||
|
SDP_3,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"all codecs removed",
|
||||||
|
SDP_1
|
||||||
|
,
|
||||||
|
"s=empty"
|
||||||
|
,
|
||||||
|
"v=0\r\n" \
|
||||||
|
"o=OsmoMSC 0 0 IN IP4 23.42.23.42\r\n" \
|
||||||
|
"s=GSM Call\r\n" \
|
||||||
|
"c=IN IP4 23.42.23.42\r\n" \
|
||||||
|
"t=0 0\r\n" \
|
||||||
|
"m=audio 30436 RTP/AVP\r\n" \
|
||||||
|
"a=ptime:20\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"some real world test case"
|
||||||
|
,
|
||||||
|
"v=0\r\n"
|
||||||
|
"o=OsmoMSC 0 0 IN IP4 0.0.0.0\r\n"
|
||||||
|
"s=GSM Call\r\n"
|
||||||
|
"c=IN IP4 0.0.0.0\r\n"
|
||||||
|
"t=0 0\r\n"
|
||||||
|
"m=audio 0 RTP/AVP 112 113 110 3 111\r\n"
|
||||||
|
"a=rtpmap:112 AMR/8000\r\n"
|
||||||
|
"a=fmtp:112 octet-align=1;mode-set=0,1,2,3\r\n"
|
||||||
|
"a=rtpmap:113 AMR-WB/8000\r\n"
|
||||||
|
"a=fmtp:113 octet-align=1\r\n"
|
||||||
|
"a=rtpmap:110 GSM-EFR/8000\r\n"
|
||||||
|
"a=rtpmap:3 GSM/8000\r\n"
|
||||||
|
"a=rtpmap:111 GSM-HR-08/8000\r\n"
|
||||||
|
"a=ptime:20\r\n"
|
||||||
|
,
|
||||||
|
"v=0\r\n"
|
||||||
|
"o=OsmoMSC 0 0 IN IP4 0.0.0.0\r\n"
|
||||||
|
"s=GSM Call\r\n"
|
||||||
|
"c=IN IP4 0.0.0.0\r\n"
|
||||||
|
"t=0 0\r\n"
|
||||||
|
"m=audio 0 RTP/AVP 112 113 110 3 111\r\n"
|
||||||
|
"a=rtpmap:112 AMR/8000\r\n"
|
||||||
|
"a=fmtp:112 octet-align=1;mode-set=0,1,2,3\r\n"
|
||||||
|
"a=rtpmap:113 AMR-WB/8000\r\n"
|
||||||
|
"a=fmtp:113 octet-align=1\r\n"
|
||||||
|
"a=rtpmap:110 GSM-EFR/8000\r\n"
|
||||||
|
"a=rtpmap:3 GSM/8000\r\n"
|
||||||
|
"a=rtpmap:111 GSM-HR-08/8000\r\n"
|
||||||
|
"a=ptime:20\r\n"
|
||||||
|
,
|
||||||
|
"v=0\r\n"
|
||||||
|
"o=OsmoMSC 0 0 IN IP4 0.0.0.0\r\n"
|
||||||
|
"s=GSM Call\r\n"
|
||||||
|
"c=IN IP4 0.0.0.0\r\n"
|
||||||
|
"t=0 0\r\n"
|
||||||
|
"m=audio 0 RTP/AVP 112 113 110 3 111\r\n"
|
||||||
|
"a=rtpmap:112 AMR/8000\r\n"
|
||||||
|
"a=fmtp:112 octet-align=1;mode-set=0,1,2,3\r\n"
|
||||||
|
"a=rtpmap:113 AMR-WB/8000\r\n"
|
||||||
|
"a=fmtp:113 octet-align=1\r\n"
|
||||||
|
"a=rtpmap:110 GSM-EFR/8000\r\n"
|
||||||
|
"a=rtpmap:3 GSM/8000\r\n"
|
||||||
|
"a=rtpmap:111 GSM-HR-08/8000\r\n"
|
||||||
|
"a=ptime:20\r\n"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *sdp_msg_logstr(const struct sdp_msg *sdp)
|
||||||
|
{
|
||||||
|
static char buf[1024];
|
||||||
|
sdp_msg_to_str(buf, sizeof(buf), sdp);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_intersect()
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
bool ok = true;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
printf("\n\n%s\n", __func__);
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(sdp_intersect_tests); i++) {
|
||||||
|
struct sdp_intersect_test_data *t = &sdp_intersect_tests[i];
|
||||||
|
struct sdp_msg sdp_a = {};
|
||||||
|
struct sdp_msg sdp_b = {};
|
||||||
|
char str[1024];
|
||||||
|
printf("\n[%d] %s\n", i, t->descr);
|
||||||
|
dump_sdp(t->sdp_a, "SDP A: ");
|
||||||
|
dump_sdp(t->sdp_b, " SDP B: ");
|
||||||
|
|
||||||
|
rc = sdp_msg_from_str(&sdp_a, t->sdp_a);
|
||||||
|
if (rc) {
|
||||||
|
printf("ERROR parsing SDP A: %d\n", rc);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
dump_sdp(sdp_msg_logstr(&sdp_a), "parsed SDP A: ");
|
||||||
|
rc = sdp_msg_from_str(&sdp_b, t->sdp_b);
|
||||||
|
if (rc) {
|
||||||
|
printf("ERROR parsing SDP A: %d\n", rc);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
dump_sdp(sdp_msg_logstr(&sdp_b), "parsed SDP B: ");
|
||||||
|
sdp_audio_codecs_intersection(&sdp_a.audio_codecs, &sdp_b.audio_codecs, false);
|
||||||
|
sdp_msg_to_str(str, sizeof(str), &sdp_a);
|
||||||
|
|
||||||
|
dump_sdp(str, "sdp_msg_intersection(a,b): ");
|
||||||
|
if (strcmp(str, t->expect_intersection)) {
|
||||||
|
int j;
|
||||||
|
ok = false;
|
||||||
|
printf("ERROR:\n");
|
||||||
|
dump_sdp(t->expect_intersection, "expect_intersection: ");
|
||||||
|
for (j = 0; t->expect_intersection[j]; j++) {
|
||||||
|
if (t->expect_intersection[j] != str[j]) {
|
||||||
|
printf("ERROR at position %d, at:\n", j);
|
||||||
|
dump_sdp(str + j, " mismatch: ");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
printf("[%d] ok\n", i);
|
||||||
|
}
|
||||||
|
|
||||||
|
OSMO_ASSERT(ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sdp_select_test_data {
|
||||||
|
const char *sdp;
|
||||||
|
unsigned int select_payload_type;
|
||||||
|
const char *expect_sdp;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sdp_select_test_data sdp_select_tests[] = {
|
||||||
|
{
|
||||||
|
"v=0\r\n"
|
||||||
|
"o=OsmoMSC 0 0 IN IP4 23.42.23.42\r\n"
|
||||||
|
"s=GSM Call\r\n"
|
||||||
|
"c=IN IP4 23.42.23.42\r\n"
|
||||||
|
"t=0 0\r\n"
|
||||||
|
"m=audio 30436 RTP/AVP 112 3 111 110\r\n"
|
||||||
|
"a=rtpmap:112 AMR/8000\r\n"
|
||||||
|
"a=fmtp:112 octet-align=1\r\n"
|
||||||
|
"a=rtpmap:3 GSM/8000\r\n"
|
||||||
|
"a=rtpmap:111 GSM-HR-08/8000\r\n"
|
||||||
|
"a=rtpmap:110 GSM-EFR/8000\r\n"
|
||||||
|
"a=ptime:20\r\n"
|
||||||
|
,
|
||||||
|
112,
|
||||||
|
NULL
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"v=0\r\n"
|
||||||
|
"o=OsmoMSC 0 0 IN IP4 23.42.23.42\r\n"
|
||||||
|
"s=GSM Call\r\n"
|
||||||
|
"c=IN IP4 23.42.23.42\r\n"
|
||||||
|
"t=0 0\r\n"
|
||||||
|
"m=audio 30436 RTP/AVP 112 3 111 110\r\n"
|
||||||
|
"a=rtpmap:112 AMR/8000\r\n"
|
||||||
|
"a=fmtp:112 octet-align=1\r\n"
|
||||||
|
"a=rtpmap:3 GSM/8000\r\n"
|
||||||
|
"a=rtpmap:111 GSM-HR-08/8000\r\n"
|
||||||
|
"a=rtpmap:110 GSM-EFR/8000\r\n"
|
||||||
|
"a=ptime:20\r\n"
|
||||||
|
,
|
||||||
|
3,
|
||||||
|
"v=0\r\n"
|
||||||
|
"o=OsmoMSC 0 0 IN IP4 23.42.23.42\r\n"
|
||||||
|
"s=GSM Call\r\n"
|
||||||
|
"c=IN IP4 23.42.23.42\r\n"
|
||||||
|
"t=0 0\r\n"
|
||||||
|
"m=audio 30436 RTP/AVP 3 112 111 110\r\n"
|
||||||
|
"a=rtpmap:3 GSM/8000\r\n"
|
||||||
|
"a=rtpmap:112 AMR/8000\r\n"
|
||||||
|
"a=fmtp:112 octet-align=1\r\n"
|
||||||
|
"a=rtpmap:111 GSM-HR-08/8000\r\n"
|
||||||
|
"a=rtpmap:110 GSM-EFR/8000\r\n"
|
||||||
|
"a=ptime:20\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"v=0\r\n"
|
||||||
|
"o=OsmoMSC 0 0 IN IP4 23.42.23.42\r\n"
|
||||||
|
"s=GSM Call\r\n"
|
||||||
|
"c=IN IP4 23.42.23.42\r\n"
|
||||||
|
"t=0 0\r\n"
|
||||||
|
"m=audio 30436 RTP/AVP 112 3 111 110\r\n"
|
||||||
|
"a=rtpmap:112 AMR/8000\r\n"
|
||||||
|
"a=fmtp:112 octet-align=1\r\n"
|
||||||
|
"a=rtpmap:3 GSM/8000\r\n"
|
||||||
|
"a=rtpmap:111 GSM-HR-08/8000\r\n"
|
||||||
|
"a=rtpmap:110 GSM-EFR/8000\r\n"
|
||||||
|
"a=ptime:20\r\n"
|
||||||
|
,
|
||||||
|
111,
|
||||||
|
"v=0\r\n"
|
||||||
|
"o=OsmoMSC 0 0 IN IP4 23.42.23.42\r\n"
|
||||||
|
"s=GSM Call\r\n"
|
||||||
|
"c=IN IP4 23.42.23.42\r\n"
|
||||||
|
"t=0 0\r\n"
|
||||||
|
"m=audio 30436 RTP/AVP 111 112 3 110\r\n"
|
||||||
|
"a=rtpmap:111 GSM-HR-08/8000\r\n"
|
||||||
|
"a=rtpmap:112 AMR/8000\r\n"
|
||||||
|
"a=fmtp:112 octet-align=1\r\n"
|
||||||
|
"a=rtpmap:3 GSM/8000\r\n"
|
||||||
|
"a=rtpmap:110 GSM-EFR/8000\r\n"
|
||||||
|
"a=ptime:20\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"v=0\r\n"
|
||||||
|
"o=OsmoMSC 0 0 IN IP4 23.42.23.42\r\n"
|
||||||
|
"s=GSM Call\r\n"
|
||||||
|
"c=IN IP4 23.42.23.42\r\n"
|
||||||
|
"t=0 0\r\n"
|
||||||
|
"m=audio 30436 RTP/AVP 112 3 111 110\r\n"
|
||||||
|
"a=rtpmap:112 AMR/8000\r\n"
|
||||||
|
"a=fmtp:112 octet-align=1\r\n"
|
||||||
|
"a=rtpmap:3 GSM/8000\r\n"
|
||||||
|
"a=rtpmap:111 GSM-HR-08/8000\r\n"
|
||||||
|
"a=rtpmap:110 GSM-EFR/8000\r\n"
|
||||||
|
"a=ptime:20\r\n"
|
||||||
|
,
|
||||||
|
110,
|
||||||
|
"v=0\r\n"
|
||||||
|
"o=OsmoMSC 0 0 IN IP4 23.42.23.42\r\n"
|
||||||
|
"s=GSM Call\r\n"
|
||||||
|
"c=IN IP4 23.42.23.42\r\n"
|
||||||
|
"t=0 0\r\n"
|
||||||
|
"m=audio 30436 RTP/AVP 110 112 3 111\r\n"
|
||||||
|
"a=rtpmap:110 GSM-EFR/8000\r\n"
|
||||||
|
"a=rtpmap:112 AMR/8000\r\n"
|
||||||
|
"a=fmtp:112 octet-align=1\r\n"
|
||||||
|
"a=rtpmap:3 GSM/8000\r\n"
|
||||||
|
"a=rtpmap:111 GSM-HR-08/8000\r\n"
|
||||||
|
"a=ptime:20\r\n"
|
||||||
|
},
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
static void test_select()
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
bool ok = true;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
printf("\n\n%s\n", __func__);
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(sdp_select_tests); i++) {
|
||||||
|
struct sdp_select_test_data *t = &sdp_select_tests[i];
|
||||||
|
struct sdp_msg sdp = {};
|
||||||
|
struct sdp_audio_codec *codec;
|
||||||
|
char buf[1024];
|
||||||
|
printf("\n[%d]\n", i);
|
||||||
|
rc = sdp_msg_from_str(&sdp, t->sdp);
|
||||||
|
if (rc) {
|
||||||
|
printf("ERROR parsing SDP: %d\n", rc);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
printf("SDP: %s\n", sdp_audio_codecs_name(&sdp.audio_codecs));
|
||||||
|
codec = sdp_audio_codec_by_payload_type(&sdp.audio_codecs, t->select_payload_type, false);
|
||||||
|
OSMO_ASSERT(codec);
|
||||||
|
printf("Select: %s\n", sdp_audio_codec_name(codec));
|
||||||
|
|
||||||
|
sdp_audio_codecs_select(&sdp.audio_codecs, codec);
|
||||||
|
|
||||||
|
printf("SDP: %s\n", sdp_audio_codecs_name(&sdp.audio_codecs));
|
||||||
|
sdp_msg_to_str(buf, sizeof(buf), &sdp);
|
||||||
|
|
||||||
|
if (strcmp(buf, t->expect_sdp ? : t->sdp)) {
|
||||||
|
int j;
|
||||||
|
ok = false;
|
||||||
|
printf("ERROR:\n");
|
||||||
|
dump_sdp(buf, "selection result: ");
|
||||||
|
dump_sdp(t->expect_sdp, "expect result: ");
|
||||||
|
for (j = 0; t->expect_sdp[j]; j++) {
|
||||||
|
if (t->expect_sdp[j] != buf[j]) {
|
||||||
|
printf("ERROR at position %d, at:\n", j);
|
||||||
|
dump_sdp(buf + j, " mismatch: ");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
printf("[%d] ok\n", i);
|
||||||
|
}
|
||||||
|
|
||||||
|
OSMO_ASSERT(ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
test_parse_and_compose();
|
||||||
|
test_intersect();
|
||||||
|
test_select();
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,590 @@
|
||||||
|
|
||||||
|
|
||||||
|
test_parse_and_compose
|
||||||
|
|
||||||
|
[0]
|
||||||
|
sdp input: v=0\r\n
|
||||||
|
sdp input: o=- 5628250 5628250 IN IP4 192.168.11.121\r\n
|
||||||
|
sdp input: s=-\r\n
|
||||||
|
sdp input: c=IN IP4 192.168.11.121\r\n
|
||||||
|
sdp input: t=0 0\r\n
|
||||||
|
sdp input: m=audio 10020 RTP/AVP 18 0 2 4 8 96 97 98 100 101\r\n
|
||||||
|
sdp input: a=rtpmap:18 G729/8000\r\n
|
||||||
|
sdp input: a=rtpmap:0 PCMU/8000\r\n
|
||||||
|
sdp input: a=rtpmap:2 G726-32/8000\r\n
|
||||||
|
sdp input: a=rtpmap:4 G723/8000\r\n
|
||||||
|
sdp input: a=rtpmap:8 PCMA/8000\r\n
|
||||||
|
sdp input: a=rtpmap:96 G726-40/8000\r\n
|
||||||
|
sdp input: a=rtpmap:97 G726-24/8000\r\n
|
||||||
|
sdp input: a=rtpmap:98 G726-16/8000\r\n
|
||||||
|
sdp input: a=rtpmap:100 NSE/8000\r\n
|
||||||
|
sdp input: a=fmtp:100 192-193\r\n
|
||||||
|
sdp input: a=rtpmap:101 telephone-event/8000\r\n
|
||||||
|
sdp input: a=fmtp:101 0-15\r\n
|
||||||
|
sdp input: a=ptime:20\r\n
|
||||||
|
sdp input: a=sendrecv\r\n
|
||||||
|
sdp_msg_to_str: v=0\r\n
|
||||||
|
sdp_msg_to_str: o=OsmoMSC 0 0 IN IP4 192.168.11.121\r\n
|
||||||
|
sdp_msg_to_str: s=GSM Call\r\n
|
||||||
|
sdp_msg_to_str: c=IN IP4 192.168.11.121\r\n
|
||||||
|
sdp_msg_to_str: t=0 0\r\n
|
||||||
|
sdp_msg_to_str: m=audio 10020 RTP/AVP 18 0 2 4 8 96 97 98 100 101\r\n
|
||||||
|
sdp_msg_to_str: a=rtpmap:18 G729/8000\r\n
|
||||||
|
sdp_msg_to_str: a=rtpmap:0 PCMU/8000\r\n
|
||||||
|
sdp_msg_to_str: a=rtpmap:2 G726-32/8000\r\n
|
||||||
|
sdp_msg_to_str: a=rtpmap:4 G723/8000\r\n
|
||||||
|
sdp_msg_to_str: a=rtpmap:8 PCMA/8000\r\n
|
||||||
|
sdp_msg_to_str: a=rtpmap:96 G726-40/8000\r\n
|
||||||
|
sdp_msg_to_str: a=rtpmap:97 G726-24/8000\r\n
|
||||||
|
sdp_msg_to_str: a=rtpmap:98 G726-16/8000\r\n
|
||||||
|
sdp_msg_to_str: a=rtpmap:100 NSE/8000\r\n
|
||||||
|
sdp_msg_to_str: a=fmtp:100 192-193\r\n
|
||||||
|
sdp_msg_to_str: a=rtpmap:101 telephone-event/8000\r\n
|
||||||
|
sdp_msg_to_str: a=fmtp:101 0-15\r\n
|
||||||
|
sdp_msg_to_str: a=ptime:20\r\n
|
||||||
|
[0] ok
|
||||||
|
|
||||||
|
[1]
|
||||||
|
sdp input: v=0\r\n
|
||||||
|
sdp input: o=FooBar 1565090289 1565090290 IN IP4 192.168.11.151\r\n
|
||||||
|
sdp input: s=FooBar\r\n
|
||||||
|
sdp input: c=IN IP4 192.168.11.151\r\n
|
||||||
|
sdp input: t=0 0\r\n
|
||||||
|
sdp input: m=audio 16398 RTP/AVP 98\r\n
|
||||||
|
sdp input: a=rtpmap:98 AMR/8000\r\n
|
||||||
|
sdp input: a=fmtp:98 octet-align=1; mode-set=4\r\n
|
||||||
|
sdp input: a=ptime:20\r\n
|
||||||
|
sdp input: a=rtcp:16399 IN IP4 192.168.11.151\r\n
|
||||||
|
sdp_msg_to_str: v=0\r\n
|
||||||
|
sdp_msg_to_str: o=OsmoMSC 0 0 IN IP4 192.168.11.151\r\n
|
||||||
|
sdp_msg_to_str: s=GSM Call\r\n
|
||||||
|
sdp_msg_to_str: c=IN IP4 192.168.11.151\r\n
|
||||||
|
sdp_msg_to_str: t=0 0\r\n
|
||||||
|
sdp_msg_to_str: m=audio 16398 RTP/AVP 98\r\n
|
||||||
|
sdp_msg_to_str: a=rtpmap:98 AMR/8000\r\n
|
||||||
|
sdp_msg_to_str: a=fmtp:98 octet-align=1; mode-set=4\r\n
|
||||||
|
sdp_msg_to_str: a=ptime:20\r\n
|
||||||
|
[1] ok
|
||||||
|
|
||||||
|
[2]
|
||||||
|
sdp input: v=0\r\n
|
||||||
|
sdp input: o=FooBar 1565090289 1565090290 IN IP4 192.168.11.151\r\n
|
||||||
|
sdp input: s=FooBar\r\n
|
||||||
|
sdp input: c=IN IP4 192.168.11.140\r\n
|
||||||
|
sdp input: t=0 0\r\n
|
||||||
|
sdp input: m=audio 30436 RTP/AVP 18 0 4 8 101\r\n
|
||||||
|
sdp input: a=rtpmap:18 G729/8000\r\n
|
||||||
|
sdp input: a=rtpmap:0 PCMU/8000\r\n
|
||||||
|
sdp input: a=rtpmap:4 G723/8000\r\n
|
||||||
|
sdp input: a=rtpmap:8 PCMA/8000\r\n
|
||||||
|
sdp input: a=rtpmap:101 telephone-event/8000\r\n
|
||||||
|
sdp input: a=fmtp:101 0-15\r\n
|
||||||
|
sdp input: a=sendrecv\r\n
|
||||||
|
sdp input: a=rtcp:30437\r\n
|
||||||
|
sdp input: a=ptime:20\r\n
|
||||||
|
sdp_msg_to_str: v=0\r\n
|
||||||
|
sdp_msg_to_str: o=OsmoMSC 0 0 IN IP4 192.168.11.140\r\n
|
||||||
|
sdp_msg_to_str: s=GSM Call\r\n
|
||||||
|
sdp_msg_to_str: c=IN IP4 192.168.11.140\r\n
|
||||||
|
sdp_msg_to_str: t=0 0\r\n
|
||||||
|
sdp_msg_to_str: m=audio 30436 RTP/AVP 18 0 4 8 101\r\n
|
||||||
|
sdp_msg_to_str: a=rtpmap:18 G729/8000\r\n
|
||||||
|
sdp_msg_to_str: a=rtpmap:0 PCMU/8000\r\n
|
||||||
|
sdp_msg_to_str: a=rtpmap:4 G723/8000\r\n
|
||||||
|
sdp_msg_to_str: a=rtpmap:8 PCMA/8000\r\n
|
||||||
|
sdp_msg_to_str: a=rtpmap:101 telephone-event/8000\r\n
|
||||||
|
sdp_msg_to_str: a=fmtp:101 0-15\r\n
|
||||||
|
sdp_msg_to_str: a=ptime:20\r\n
|
||||||
|
[2] ok
|
||||||
|
|
||||||
|
|
||||||
|
test_intersect
|
||||||
|
|
||||||
|
[0] identical codecs lead to no change
|
||||||
|
SDP A: v=0\r\n
|
||||||
|
SDP A: o=OsmoMSC 0 0 IN IP4 23.42.23.42\r\n
|
||||||
|
SDP A: s=GSM Call\r\n
|
||||||
|
SDP A: c=IN IP4 23.42.23.42\r\n
|
||||||
|
SDP A: t=0 0\r\n
|
||||||
|
SDP A: m=audio 30436 RTP/AVP 112 3 111 110\r\n
|
||||||
|
SDP A: a=rtpmap:112 AMR/8000\r\n
|
||||||
|
SDP A: a=fmtp:112 octet-align=1\r\n
|
||||||
|
SDP A: a=rtpmap:3 GSM/8000\r\n
|
||||||
|
SDP A: a=rtpmap:111 GSM-HR-08/8000\r\n
|
||||||
|
SDP A: a=rtpmap:110 GSM-EFR/8000\r\n
|
||||||
|
SDP A: a=ptime:20\r\n
|
||||||
|
SDP B: c=IN IP4 5.6.7.8\r\n
|
||||||
|
SDP B: m=audio 12345 RTP/AVP 112 3 111 110\r\n
|
||||||
|
SDP B: a=rtpmap:112 AMR/8000\r\n
|
||||||
|
SDP B: a=fmtp:112 octet-align=1\r\n
|
||||||
|
SDP B: a=rtpmap:3 GSM/8000\r\n
|
||||||
|
SDP B: a=rtpmap:111 GSM-HR-08/8000\r\n
|
||||||
|
SDP B: a=rtpmap:110 GSM-EFR/8000\r\n
|
||||||
|
parsed SDP A: v=0\r\n
|
||||||
|
parsed SDP A: o=OsmoMSC 0 0 IN IP4 23.42.23.42\r\n
|
||||||
|
parsed SDP A: s=GSM Call\r\n
|
||||||
|
parsed SDP A: c=IN IP4 23.42.23.42\r\n
|
||||||
|
parsed SDP A: t=0 0\r\n
|
||||||
|
parsed SDP A: m=audio 30436 RTP/AVP 112 3 111 110\r\n
|
||||||
|
parsed SDP A: a=rtpmap:112 AMR/8000\r\n
|
||||||
|
parsed SDP A: a=fmtp:112 octet-align=1\r\n
|
||||||
|
parsed SDP A: a=rtpmap:3 GSM/8000\r\n
|
||||||
|
parsed SDP A: a=rtpmap:111 GSM-HR-08/8000\r\n
|
||||||
|
parsed SDP A: a=rtpmap:110 GSM-EFR/8000\r\n
|
||||||
|
parsed SDP A: a=ptime:20\r\n
|
||||||
|
parsed SDP B: v=0\r\n
|
||||||
|
parsed SDP B: o=OsmoMSC 0 0 IN IP4 5.6.7.8\r\n
|
||||||
|
parsed SDP B: s=GSM Call\r\n
|
||||||
|
parsed SDP B: c=IN IP4 5.6.7.8\r\n
|
||||||
|
parsed SDP B: t=0 0\r\n
|
||||||
|
parsed SDP B: m=audio 12345 RTP/AVP 112 3 111 110\r\n
|
||||||
|
parsed SDP B: a=rtpmap:112 AMR/8000\r\n
|
||||||
|
parsed SDP B: a=fmtp:112 octet-align=1\r\n
|
||||||
|
parsed SDP B: a=rtpmap:3 GSM/8000\r\n
|
||||||
|
parsed SDP B: a=rtpmap:111 GSM-HR-08/8000\r\n
|
||||||
|
parsed SDP B: a=rtpmap:110 GSM-EFR/8000\r\n
|
||||||
|
parsed SDP B: a=ptime:20\r\n
|
||||||
|
sdp_msg_intersection(a,b): v=0\r\n
|
||||||
|
sdp_msg_intersection(a,b): o=OsmoMSC 0 0 IN IP4 23.42.23.42\r\n
|
||||||
|
sdp_msg_intersection(a,b): s=GSM Call\r\n
|
||||||
|
sdp_msg_intersection(a,b): c=IN IP4 23.42.23.42\r\n
|
||||||
|
sdp_msg_intersection(a,b): t=0 0\r\n
|
||||||
|
sdp_msg_intersection(a,b): m=audio 30436 RTP/AVP 112 3 111 110\r\n
|
||||||
|
sdp_msg_intersection(a,b): a=rtpmap:112 AMR/8000\r\n
|
||||||
|
sdp_msg_intersection(a,b): a=fmtp:112 octet-align=1\r\n
|
||||||
|
sdp_msg_intersection(a,b): a=rtpmap:3 GSM/8000\r\n
|
||||||
|
sdp_msg_intersection(a,b): a=rtpmap:111 GSM-HR-08/8000\r\n
|
||||||
|
sdp_msg_intersection(a,b): a=rtpmap:110 GSM-EFR/8000\r\n
|
||||||
|
sdp_msg_intersection(a,b): a=ptime:20\r\n
|
||||||
|
[0] ok
|
||||||
|
|
||||||
|
[1] identical codecs in different order also lead to no change
|
||||||
|
SDP A: v=0\r\n
|
||||||
|
SDP A: o=OsmoMSC 0 0 IN IP4 23.42.23.42\r\n
|
||||||
|
SDP A: s=GSM Call\r\n
|
||||||
|
SDP A: c=IN IP4 23.42.23.42\r\n
|
||||||
|
SDP A: t=0 0\r\n
|
||||||
|
SDP A: m=audio 30436 RTP/AVP 112 3 111 110\r\n
|
||||||
|
SDP A: a=rtpmap:112 AMR/8000\r\n
|
||||||
|
SDP A: a=fmtp:112 octet-align=1\r\n
|
||||||
|
SDP A: a=rtpmap:3 GSM/8000\r\n
|
||||||
|
SDP A: a=rtpmap:111 GSM-HR-08/8000\r\n
|
||||||
|
SDP A: a=rtpmap:110 GSM-EFR/8000\r\n
|
||||||
|
SDP A: a=ptime:20\r\n
|
||||||
|
SDP B: c=IN IP4 5.6.7.8\r\n
|
||||||
|
SDP B: m=audio 12345 RTP/AVP 3 110 111 112\r\n
|
||||||
|
SDP B: a=rtpmap:3 GSM/8000\r\n
|
||||||
|
SDP B: a=rtpmap:110 GSM-EFR/8000\r\n
|
||||||
|
SDP B: a=rtpmap:111 GSM-HR-08/8000\r\n
|
||||||
|
SDP B: a=rtpmap:112 AMR/8000\r\n
|
||||||
|
SDP B: a=fmtp:112 octet-align=1\r\n
|
||||||
|
parsed SDP A: v=0\r\n
|
||||||
|
parsed SDP A: o=OsmoMSC 0 0 IN IP4 23.42.23.42\r\n
|
||||||
|
parsed SDP A: s=GSM Call\r\n
|
||||||
|
parsed SDP A: c=IN IP4 23.42.23.42\r\n
|
||||||
|
parsed SDP A: t=0 0\r\n
|
||||||
|
parsed SDP A: m=audio 30436 RTP/AVP 112 3 111 110\r\n
|
||||||
|
parsed SDP A: a=rtpmap:112 AMR/8000\r\n
|
||||||
|
parsed SDP A: a=fmtp:112 octet-align=1\r\n
|
||||||
|
parsed SDP A: a=rtpmap:3 GSM/8000\r\n
|
||||||
|
parsed SDP A: a=rtpmap:111 GSM-HR-08/8000\r\n
|
||||||
|
parsed SDP A: a=rtpmap:110 GSM-EFR/8000\r\n
|
||||||
|
parsed SDP A: a=ptime:20\r\n
|
||||||
|
parsed SDP B: v=0\r\n
|
||||||
|
parsed SDP B: o=OsmoMSC 0 0 IN IP4 5.6.7.8\r\n
|
||||||
|
parsed SDP B: s=GSM Call\r\n
|
||||||
|
parsed SDP B: c=IN IP4 5.6.7.8\r\n
|
||||||
|
parsed SDP B: t=0 0\r\n
|
||||||
|
parsed SDP B: m=audio 12345 RTP/AVP 3 110 111 112\r\n
|
||||||
|
parsed SDP B: a=rtpmap:3 GSM/8000\r\n
|
||||||
|
parsed SDP B: a=rtpmap:110 GSM-EFR/8000\r\n
|
||||||
|
parsed SDP B: a=rtpmap:111 GSM-HR-08/8000\r\n
|
||||||
|
parsed SDP B: a=rtpmap:112 AMR/8000\r\n
|
||||||
|
parsed SDP B: a=fmtp:112 octet-align=1\r\n
|
||||||
|
parsed SDP B: a=ptime:20\r\n
|
||||||
|
sdp_msg_intersection(a,b): v=0\r\n
|
||||||
|
sdp_msg_intersection(a,b): o=OsmoMSC 0 0 IN IP4 23.42.23.42\r\n
|
||||||
|
sdp_msg_intersection(a,b): s=GSM Call\r\n
|
||||||
|
sdp_msg_intersection(a,b): c=IN IP4 23.42.23.42\r\n
|
||||||
|
sdp_msg_intersection(a,b): t=0 0\r\n
|
||||||
|
sdp_msg_intersection(a,b): m=audio 30436 RTP/AVP 112 3 111 110\r\n
|
||||||
|
sdp_msg_intersection(a,b): a=rtpmap:112 AMR/8000\r\n
|
||||||
|
sdp_msg_intersection(a,b): a=fmtp:112 octet-align=1\r\n
|
||||||
|
sdp_msg_intersection(a,b): a=rtpmap:3 GSM/8000\r\n
|
||||||
|
sdp_msg_intersection(a,b): a=rtpmap:111 GSM-HR-08/8000\r\n
|
||||||
|
sdp_msg_intersection(a,b): a=rtpmap:110 GSM-EFR/8000\r\n
|
||||||
|
sdp_msg_intersection(a,b): a=ptime:20\r\n
|
||||||
|
[1] ok
|
||||||
|
|
||||||
|
[2] identical codecs with mismatching payload type numbers also lead to no change
|
||||||
|
SDP A: v=0\r\n
|
||||||
|
SDP A: o=OsmoMSC 0 0 IN IP4 23.42.23.42\r\n
|
||||||
|
SDP A: s=GSM Call\r\n
|
||||||
|
SDP A: c=IN IP4 23.42.23.42\r\n
|
||||||
|
SDP A: t=0 0\r\n
|
||||||
|
SDP A: m=audio 30436 RTP/AVP 112 3 111 110\r\n
|
||||||
|
SDP A: a=rtpmap:112 AMR/8000\r\n
|
||||||
|
SDP A: a=fmtp:112 octet-align=1\r\n
|
||||||
|
SDP A: a=rtpmap:3 GSM/8000\r\n
|
||||||
|
SDP A: a=rtpmap:111 GSM-HR-08/8000\r\n
|
||||||
|
SDP A: a=rtpmap:110 GSM-EFR/8000\r\n
|
||||||
|
SDP A: a=ptime:20\r\n
|
||||||
|
SDP B: c=IN IP4 5.6.7.8\r\n
|
||||||
|
SDP B: m=audio 12345 RTP/AVP 96 97 98 99\r\n
|
||||||
|
SDP B: a=rtpmap:96 GSM/8000\r\n
|
||||||
|
SDP B: a=rtpmap:97 GSM-EFR/8000\r\n
|
||||||
|
SDP B: a=rtpmap:98 GSM-HR-08/8000\r\n
|
||||||
|
SDP B: a=rtpmap:99 AMR/8000\r\n
|
||||||
|
SDP B: a=fmtp:99 octet-align=1\r\n
|
||||||
|
parsed SDP A: v=0\r\n
|
||||||
|
parsed SDP A: o=OsmoMSC 0 0 IN IP4 23.42.23.42\r\n
|
||||||
|
parsed SDP A: s=GSM Call\r\n
|
||||||
|
parsed SDP A: c=IN IP4 23.42.23.42\r\n
|
||||||
|
parsed SDP A: t=0 0\r\n
|
||||||
|
parsed SDP A: m=audio 30436 RTP/AVP 112 3 111 110\r\n
|
||||||
|
parsed SDP A: a=rtpmap:112 AMR/8000\r\n
|
||||||
|
parsed SDP A: a=fmtp:112 octet-align=1\r\n
|
||||||
|
parsed SDP A: a=rtpmap:3 GSM/8000\r\n
|
||||||
|
parsed SDP A: a=rtpmap:111 GSM-HR-08/8000\r\n
|
||||||
|
parsed SDP A: a=rtpmap:110 GSM-EFR/8000\r\n
|
||||||
|
parsed SDP A: a=ptime:20\r\n
|
||||||
|
parsed SDP B: v=0\r\n
|
||||||
|
parsed SDP B: o=OsmoMSC 0 0 IN IP4 5.6.7.8\r\n
|
||||||
|
parsed SDP B: s=GSM Call\r\n
|
||||||
|
parsed SDP B: c=IN IP4 5.6.7.8\r\n
|
||||||
|
parsed SDP B: t=0 0\r\n
|
||||||
|
parsed SDP B: m=audio 12345 RTP/AVP 96 97 98 99\r\n
|
||||||
|
parsed SDP B: a=rtpmap:96 GSM/8000\r\n
|
||||||
|
parsed SDP B: a=rtpmap:97 GSM-EFR/8000\r\n
|
||||||
|
parsed SDP B: a=rtpmap:98 GSM-HR-08/8000\r\n
|
||||||
|
parsed SDP B: a=rtpmap:99 AMR/8000\r\n
|
||||||
|
parsed SDP B: a=fmtp:99 octet-align=1\r\n
|
||||||
|
parsed SDP B: a=ptime:20\r\n
|
||||||
|
sdp_msg_intersection(a,b): v=0\r\n
|
||||||
|
sdp_msg_intersection(a,b): o=OsmoMSC 0 0 IN IP4 23.42.23.42\r\n
|
||||||
|
sdp_msg_intersection(a,b): s=GSM Call\r\n
|
||||||
|
sdp_msg_intersection(a,b): c=IN IP4 23.42.23.42\r\n
|
||||||
|
sdp_msg_intersection(a,b): t=0 0\r\n
|
||||||
|
sdp_msg_intersection(a,b): m=audio 30436 RTP/AVP 112 3 111 110\r\n
|
||||||
|
sdp_msg_intersection(a,b): a=rtpmap:112 AMR/8000\r\n
|
||||||
|
sdp_msg_intersection(a,b): a=fmtp:112 octet-align=1\r\n
|
||||||
|
sdp_msg_intersection(a,b): a=rtpmap:3 GSM/8000\r\n
|
||||||
|
sdp_msg_intersection(a,b): a=rtpmap:111 GSM-HR-08/8000\r\n
|
||||||
|
sdp_msg_intersection(a,b): a=rtpmap:110 GSM-EFR/8000\r\n
|
||||||
|
sdp_msg_intersection(a,b): a=ptime:20\r\n
|
||||||
|
[2] ok
|
||||||
|
|
||||||
|
[3] identical codecs plus some extra codecs also lead to no change
|
||||||
|
SDP A: v=0\r\n
|
||||||
|
SDP A: o=OsmoMSC 0 0 IN IP4 23.42.23.42\r\n
|
||||||
|
SDP A: s=GSM Call\r\n
|
||||||
|
SDP A: c=IN IP4 23.42.23.42\r\n
|
||||||
|
SDP A: t=0 0\r\n
|
||||||
|
SDP A: m=audio 30436 RTP/AVP 112 3 111 110\r\n
|
||||||
|
SDP A: a=rtpmap:112 AMR/8000\r\n
|
||||||
|
SDP A: a=fmtp:112 octet-align=1\r\n
|
||||||
|
SDP A: a=rtpmap:3 GSM/8000\r\n
|
||||||
|
SDP A: a=rtpmap:111 GSM-HR-08/8000\r\n
|
||||||
|
SDP A: a=rtpmap:110 GSM-EFR/8000\r\n
|
||||||
|
SDP A: a=ptime:20\r\n
|
||||||
|
SDP B: c=IN IP4 5.6.7.8\r\n
|
||||||
|
SDP B: m=audio 12345 RTP/AVP 8 0 96 97 98 99\r\n
|
||||||
|
SDP B: a=rtpmap:8 PCMA/8000\r\n
|
||||||
|
SDP B: a=rtpmap:0 PCMU/8000\r\n
|
||||||
|
SDP B: a=rtpmap:96 GSM/8000\r\n
|
||||||
|
SDP B: a=rtpmap:97 GSM-EFR/8000\r\n
|
||||||
|
SDP B: a=rtpmap:98 GSM-HR-08/8000\r\n
|
||||||
|
SDP B: a=rtpmap:99 AMR/8000\r\n
|
||||||
|
SDP B: a=fmtp:99 octet-align=1\r\n
|
||||||
|
parsed SDP A: v=0\r\n
|
||||||
|
parsed SDP A: o=OsmoMSC 0 0 IN IP4 23.42.23.42\r\n
|
||||||
|
parsed SDP A: s=GSM Call\r\n
|
||||||
|
parsed SDP A: c=IN IP4 23.42.23.42\r\n
|
||||||
|
parsed SDP A: t=0 0\r\n
|
||||||
|
parsed SDP A: m=audio 30436 RTP/AVP 112 3 111 110\r\n
|
||||||
|
parsed SDP A: a=rtpmap:112 AMR/8000\r\n
|
||||||
|
parsed SDP A: a=fmtp:112 octet-align=1\r\n
|
||||||
|
parsed SDP A: a=rtpmap:3 GSM/8000\r\n
|
||||||
|
parsed SDP A: a=rtpmap:111 GSM-HR-08/8000\r\n
|
||||||
|
parsed SDP A: a=rtpmap:110 GSM-EFR/8000\r\n
|
||||||
|
parsed SDP A: a=ptime:20\r\n
|
||||||
|
parsed SDP B: v=0\r\n
|
||||||
|
parsed SDP B: o=OsmoMSC 0 0 IN IP4 5.6.7.8\r\n
|
||||||
|
parsed SDP B: s=GSM Call\r\n
|
||||||
|
parsed SDP B: c=IN IP4 5.6.7.8\r\n
|
||||||
|
parsed SDP B: t=0 0\r\n
|
||||||
|
parsed SDP B: m=audio 12345 RTP/AVP 8 0 96 97 98 99\r\n
|
||||||
|
parsed SDP B: a=rtpmap:8 PCMA/8000\r\n
|
||||||
|
parsed SDP B: a=rtpmap:0 PCMU/8000\r\n
|
||||||
|
parsed SDP B: a=rtpmap:96 GSM/8000\r\n
|
||||||
|
parsed SDP B: a=rtpmap:97 GSM-EFR/8000\r\n
|
||||||
|
parsed SDP B: a=rtpmap:98 GSM-HR-08/8000\r\n
|
||||||
|
parsed SDP B: a=rtpmap:99 AMR/8000\r\n
|
||||||
|
parsed SDP B: a=fmtp:99 octet-align=1\r\n
|
||||||
|
parsed SDP B: a=ptime:20\r\n
|
||||||
|
sdp_msg_intersection(a,b): v=0\r\n
|
||||||
|
sdp_msg_intersection(a,b): o=OsmoMSC 0 0 IN IP4 23.42.23.42\r\n
|
||||||
|
sdp_msg_intersection(a,b): s=GSM Call\r\n
|
||||||
|
sdp_msg_intersection(a,b): c=IN IP4 23.42.23.42\r\n
|
||||||
|
sdp_msg_intersection(a,b): t=0 0\r\n
|
||||||
|
sdp_msg_intersection(a,b): m=audio 30436 RTP/AVP 112 3 111 110\r\n
|
||||||
|
sdp_msg_intersection(a,b): a=rtpmap:112 AMR/8000\r\n
|
||||||
|
sdp_msg_intersection(a,b): a=fmtp:112 octet-align=1\r\n
|
||||||
|
sdp_msg_intersection(a,b): a=rtpmap:3 GSM/8000\r\n
|
||||||
|
sdp_msg_intersection(a,b): a=rtpmap:111 GSM-HR-08/8000\r\n
|
||||||
|
sdp_msg_intersection(a,b): a=rtpmap:110 GSM-EFR/8000\r\n
|
||||||
|
sdp_msg_intersection(a,b): a=ptime:20\r\n
|
||||||
|
[3] ok
|
||||||
|
|
||||||
|
[4] some codecs removed
|
||||||
|
SDP A: v=0\r\n
|
||||||
|
SDP A: o=OsmoMSC 0 0 IN IP4 23.42.23.42\r\n
|
||||||
|
SDP A: s=GSM Call\r\n
|
||||||
|
SDP A: c=IN IP4 23.42.23.42\r\n
|
||||||
|
SDP A: t=0 0\r\n
|
||||||
|
SDP A: m=audio 30436 RTP/AVP 112 3 111 110\r\n
|
||||||
|
SDP A: a=rtpmap:112 AMR/8000\r\n
|
||||||
|
SDP A: a=fmtp:112 octet-align=1\r\n
|
||||||
|
SDP A: a=rtpmap:3 GSM/8000\r\n
|
||||||
|
SDP A: a=rtpmap:111 GSM-HR-08/8000\r\n
|
||||||
|
SDP A: a=rtpmap:110 GSM-EFR/8000\r\n
|
||||||
|
SDP A: a=ptime:20\r\n
|
||||||
|
SDP B: v=0\r\n
|
||||||
|
SDP B: o=OsmoMSC 0 0 IN IP4 23.42.23.42\r\n
|
||||||
|
SDP B: s=GSM Call\r\n
|
||||||
|
SDP B: c=IN IP4 23.42.23.42\r\n
|
||||||
|
SDP B: t=0 0\r\n
|
||||||
|
SDP B: m=audio 30436 RTP/AVP 112 110\r\n
|
||||||
|
SDP B: a=rtpmap:112 AMR/8000\r\n
|
||||||
|
SDP B: a=fmtp:112 octet-align=1\r\n
|
||||||
|
SDP B: a=rtpmap:110 GSM-EFR/8000\r\n
|
||||||
|
SDP B: a=ptime:20\r\n
|
||||||
|
parsed SDP A: v=0\r\n
|
||||||
|
parsed SDP A: o=OsmoMSC 0 0 IN IP4 23.42.23.42\r\n
|
||||||
|
parsed SDP A: s=GSM Call\r\n
|
||||||
|
parsed SDP A: c=IN IP4 23.42.23.42\r\n
|
||||||
|
parsed SDP A: t=0 0\r\n
|
||||||
|
parsed SDP A: m=audio 30436 RTP/AVP 112 3 111 110\r\n
|
||||||
|
parsed SDP A: a=rtpmap:112 AMR/8000\r\n
|
||||||
|
parsed SDP A: a=fmtp:112 octet-align=1\r\n
|
||||||
|
parsed SDP A: a=rtpmap:3 GSM/8000\r\n
|
||||||
|
parsed SDP A: a=rtpmap:111 GSM-HR-08/8000\r\n
|
||||||
|
parsed SDP A: a=rtpmap:110 GSM-EFR/8000\r\n
|
||||||
|
parsed SDP A: a=ptime:20\r\n
|
||||||
|
parsed SDP B: v=0\r\n
|
||||||
|
parsed SDP B: o=OsmoMSC 0 0 IN IP4 23.42.23.42\r\n
|
||||||
|
parsed SDP B: s=GSM Call\r\n
|
||||||
|
parsed SDP B: c=IN IP4 23.42.23.42\r\n
|
||||||
|
parsed SDP B: t=0 0\r\n
|
||||||
|
parsed SDP B: m=audio 30436 RTP/AVP 112 110\r\n
|
||||||
|
parsed SDP B: a=rtpmap:112 AMR/8000\r\n
|
||||||
|
parsed SDP B: a=fmtp:112 octet-align=1\r\n
|
||||||
|
parsed SDP B: a=rtpmap:110 GSM-EFR/8000\r\n
|
||||||
|
parsed SDP B: a=ptime:20\r\n
|
||||||
|
sdp_msg_intersection(a,b): v=0\r\n
|
||||||
|
sdp_msg_intersection(a,b): o=OsmoMSC 0 0 IN IP4 23.42.23.42\r\n
|
||||||
|
sdp_msg_intersection(a,b): s=GSM Call\r\n
|
||||||
|
sdp_msg_intersection(a,b): c=IN IP4 23.42.23.42\r\n
|
||||||
|
sdp_msg_intersection(a,b): t=0 0\r\n
|
||||||
|
sdp_msg_intersection(a,b): m=audio 30436 RTP/AVP 112 110\r\n
|
||||||
|
sdp_msg_intersection(a,b): a=rtpmap:112 AMR/8000\r\n
|
||||||
|
sdp_msg_intersection(a,b): a=fmtp:112 octet-align=1\r\n
|
||||||
|
sdp_msg_intersection(a,b): a=rtpmap:110 GSM-EFR/8000\r\n
|
||||||
|
sdp_msg_intersection(a,b): a=ptime:20\r\n
|
||||||
|
[4] ok
|
||||||
|
|
||||||
|
[5] other codecs removed
|
||||||
|
SDP A: v=0\r\n
|
||||||
|
SDP A: o=OsmoMSC 0 0 IN IP4 23.42.23.42\r\n
|
||||||
|
SDP A: s=GSM Call\r\n
|
||||||
|
SDP A: c=IN IP4 23.42.23.42\r\n
|
||||||
|
SDP A: t=0 0\r\n
|
||||||
|
SDP A: m=audio 30436 RTP/AVP 112 3 111 110\r\n
|
||||||
|
SDP A: a=rtpmap:112 AMR/8000\r\n
|
||||||
|
SDP A: a=fmtp:112 octet-align=1\r\n
|
||||||
|
SDP A: a=rtpmap:3 GSM/8000\r\n
|
||||||
|
SDP A: a=rtpmap:111 GSM-HR-08/8000\r\n
|
||||||
|
SDP A: a=rtpmap:110 GSM-EFR/8000\r\n
|
||||||
|
SDP A: a=ptime:20\r\n
|
||||||
|
SDP B: v=0\r\n
|
||||||
|
SDP B: o=OsmoMSC 0 0 IN IP4 23.42.23.42\r\n
|
||||||
|
SDP B: s=GSM Call\r\n
|
||||||
|
SDP B: c=IN IP4 23.42.23.42\r\n
|
||||||
|
SDP B: t=0 0\r\n
|
||||||
|
SDP B: m=audio 30436 RTP/AVP 3 111\r\n
|
||||||
|
SDP B: a=rtpmap:3 GSM/8000\r\n
|
||||||
|
SDP B: a=rtpmap:111 GSM-HR-08/8000\r\n
|
||||||
|
SDP B: a=ptime:20\r\n
|
||||||
|
parsed SDP A: v=0\r\n
|
||||||
|
parsed SDP A: o=OsmoMSC 0 0 IN IP4 23.42.23.42\r\n
|
||||||
|
parsed SDP A: s=GSM Call\r\n
|
||||||
|
parsed SDP A: c=IN IP4 23.42.23.42\r\n
|
||||||
|
parsed SDP A: t=0 0\r\n
|
||||||
|
parsed SDP A: m=audio 30436 RTP/AVP 112 3 111 110\r\n
|
||||||
|
parsed SDP A: a=rtpmap:112 AMR/8000\r\n
|
||||||
|
parsed SDP A: a=fmtp:112 octet-align=1\r\n
|
||||||
|
parsed SDP A: a=rtpmap:3 GSM/8000\r\n
|
||||||
|
parsed SDP A: a=rtpmap:111 GSM-HR-08/8000\r\n
|
||||||
|
parsed SDP A: a=rtpmap:110 GSM-EFR/8000\r\n
|
||||||
|
parsed SDP A: a=ptime:20\r\n
|
||||||
|
parsed SDP B: v=0\r\n
|
||||||
|
parsed SDP B: o=OsmoMSC 0 0 IN IP4 23.42.23.42\r\n
|
||||||
|
parsed SDP B: s=GSM Call\r\n
|
||||||
|
parsed SDP B: c=IN IP4 23.42.23.42\r\n
|
||||||
|
parsed SDP B: t=0 0\r\n
|
||||||
|
parsed SDP B: m=audio 30436 RTP/AVP 3 111\r\n
|
||||||
|
parsed SDP B: a=rtpmap:3 GSM/8000\r\n
|
||||||
|
parsed SDP B: a=rtpmap:111 GSM-HR-08/8000\r\n
|
||||||
|
parsed SDP B: a=ptime:20\r\n
|
||||||
|
sdp_msg_intersection(a,b): v=0\r\n
|
||||||
|
sdp_msg_intersection(a,b): o=OsmoMSC 0 0 IN IP4 23.42.23.42\r\n
|
||||||
|
sdp_msg_intersection(a,b): s=GSM Call\r\n
|
||||||
|
sdp_msg_intersection(a,b): c=IN IP4 23.42.23.42\r\n
|
||||||
|
sdp_msg_intersection(a,b): t=0 0\r\n
|
||||||
|
sdp_msg_intersection(a,b): m=audio 30436 RTP/AVP 3 111\r\n
|
||||||
|
sdp_msg_intersection(a,b): a=rtpmap:3 GSM/8000\r\n
|
||||||
|
sdp_msg_intersection(a,b): a=rtpmap:111 GSM-HR-08/8000\r\n
|
||||||
|
sdp_msg_intersection(a,b): a=ptime:20\r\n
|
||||||
|
[5] ok
|
||||||
|
|
||||||
|
[6] all codecs removed
|
||||||
|
SDP A: v=0\r\n
|
||||||
|
SDP A: o=OsmoMSC 0 0 IN IP4 23.42.23.42\r\n
|
||||||
|
SDP A: s=GSM Call\r\n
|
||||||
|
SDP A: c=IN IP4 23.42.23.42\r\n
|
||||||
|
SDP A: t=0 0\r\n
|
||||||
|
SDP A: m=audio 30436 RTP/AVP 112 3 111 110\r\n
|
||||||
|
SDP A: a=rtpmap:112 AMR/8000\r\n
|
||||||
|
SDP A: a=fmtp:112 octet-align=1\r\n
|
||||||
|
SDP A: a=rtpmap:3 GSM/8000\r\n
|
||||||
|
SDP A: a=rtpmap:111 GSM-HR-08/8000\r\n
|
||||||
|
SDP A: a=rtpmap:110 GSM-EFR/8000\r\n
|
||||||
|
SDP A: a=ptime:20\r\n
|
||||||
|
SDP B: s=empty
|
||||||
|
parsed SDP A: v=0\r\n
|
||||||
|
parsed SDP A: o=OsmoMSC 0 0 IN IP4 23.42.23.42\r\n
|
||||||
|
parsed SDP A: s=GSM Call\r\n
|
||||||
|
parsed SDP A: c=IN IP4 23.42.23.42\r\n
|
||||||
|
parsed SDP A: t=0 0\r\n
|
||||||
|
parsed SDP A: m=audio 30436 RTP/AVP 112 3 111 110\r\n
|
||||||
|
parsed SDP A: a=rtpmap:112 AMR/8000\r\n
|
||||||
|
parsed SDP A: a=fmtp:112 octet-align=1\r\n
|
||||||
|
parsed SDP A: a=rtpmap:3 GSM/8000\r\n
|
||||||
|
parsed SDP A: a=rtpmap:111 GSM-HR-08/8000\r\n
|
||||||
|
parsed SDP A: a=rtpmap:110 GSM-EFR/8000\r\n
|
||||||
|
parsed SDP A: a=ptime:20\r\n
|
||||||
|
parsed SDP B: v=0\r\n
|
||||||
|
parsed SDP B: o=OsmoMSC 0 0 IN IP4 0.0.0.0\r\n
|
||||||
|
parsed SDP B: s=GSM Call\r\n
|
||||||
|
parsed SDP B: c=IN IP4 0.0.0.0\r\n
|
||||||
|
parsed SDP B: t=0 0\r\n
|
||||||
|
parsed SDP B: m=audio 0 RTP/AVP\r\n
|
||||||
|
parsed SDP B: a=ptime:20\r\n
|
||||||
|
sdp_msg_intersection(a,b): v=0\r\n
|
||||||
|
sdp_msg_intersection(a,b): o=OsmoMSC 0 0 IN IP4 23.42.23.42\r\n
|
||||||
|
sdp_msg_intersection(a,b): s=GSM Call\r\n
|
||||||
|
sdp_msg_intersection(a,b): c=IN IP4 23.42.23.42\r\n
|
||||||
|
sdp_msg_intersection(a,b): t=0 0\r\n
|
||||||
|
sdp_msg_intersection(a,b): m=audio 30436 RTP/AVP\r\n
|
||||||
|
sdp_msg_intersection(a,b): a=ptime:20\r\n
|
||||||
|
[6] ok
|
||||||
|
|
||||||
|
[7] some real world test case
|
||||||
|
SDP A: v=0\r\n
|
||||||
|
SDP A: o=OsmoMSC 0 0 IN IP4 0.0.0.0\r\n
|
||||||
|
SDP A: s=GSM Call\r\n
|
||||||
|
SDP A: c=IN IP4 0.0.0.0\r\n
|
||||||
|
SDP A: t=0 0\r\n
|
||||||
|
SDP A: m=audio 0 RTP/AVP 112 113 110 3 111\r\n
|
||||||
|
SDP A: a=rtpmap:112 AMR/8000\r\n
|
||||||
|
SDP A: a=fmtp:112 octet-align=1;mode-set=0,1,2,3\r\n
|
||||||
|
SDP A: a=rtpmap:113 AMR-WB/8000\r\n
|
||||||
|
SDP A: a=fmtp:113 octet-align=1\r\n
|
||||||
|
SDP A: a=rtpmap:110 GSM-EFR/8000\r\n
|
||||||
|
SDP A: a=rtpmap:3 GSM/8000\r\n
|
||||||
|
SDP A: a=rtpmap:111 GSM-HR-08/8000\r\n
|
||||||
|
SDP A: a=ptime:20\r\n
|
||||||
|
SDP B: v=0\r\n
|
||||||
|
SDP B: o=OsmoMSC 0 0 IN IP4 0.0.0.0\r\n
|
||||||
|
SDP B: s=GSM Call\r\n
|
||||||
|
SDP B: c=IN IP4 0.0.0.0\r\n
|
||||||
|
SDP B: t=0 0\r\n
|
||||||
|
SDP B: m=audio 0 RTP/AVP 112 113 110 3 111\r\n
|
||||||
|
SDP B: a=rtpmap:112 AMR/8000\r\n
|
||||||
|
SDP B: a=fmtp:112 octet-align=1;mode-set=0,1,2,3\r\n
|
||||||
|
SDP B: a=rtpmap:113 AMR-WB/8000\r\n
|
||||||
|
SDP B: a=fmtp:113 octet-align=1\r\n
|
||||||
|
SDP B: a=rtpmap:110 GSM-EFR/8000\r\n
|
||||||
|
SDP B: a=rtpmap:3 GSM/8000\r\n
|
||||||
|
SDP B: a=rtpmap:111 GSM-HR-08/8000\r\n
|
||||||
|
SDP B: a=ptime:20\r\n
|
||||||
|
parsed SDP A: v=0\r\n
|
||||||
|
parsed SDP A: o=OsmoMSC 0 0 IN IP4 0.0.0.0\r\n
|
||||||
|
parsed SDP A: s=GSM Call\r\n
|
||||||
|
parsed SDP A: c=IN IP4 0.0.0.0\r\n
|
||||||
|
parsed SDP A: t=0 0\r\n
|
||||||
|
parsed SDP A: m=audio 0 RTP/AVP 112 113 110 3 111\r\n
|
||||||
|
parsed SDP A: a=rtpmap:112 AMR/8000\r\n
|
||||||
|
parsed SDP A: a=fmtp:112 octet-align=1;mode-set=0,1,2,3\r\n
|
||||||
|
parsed SDP A: a=rtpmap:113 AMR-WB/8000\r\n
|
||||||
|
parsed SDP A: a=fmtp:113 octet-align=1\r\n
|
||||||
|
parsed SDP A: a=rtpmap:110 GSM-EFR/8000\r\n
|
||||||
|
parsed SDP A: a=rtpmap:3 GSM/8000\r\n
|
||||||
|
parsed SDP A: a=rtpmap:111 GSM-HR-08/8000\r\n
|
||||||
|
parsed SDP A: a=ptime:20\r\n
|
||||||
|
parsed SDP B: v=0\r\n
|
||||||
|
parsed SDP B: o=OsmoMSC 0 0 IN IP4 0.0.0.0\r\n
|
||||||
|
parsed SDP B: s=GSM Call\r\n
|
||||||
|
parsed SDP B: c=IN IP4 0.0.0.0\r\n
|
||||||
|
parsed SDP B: t=0 0\r\n
|
||||||
|
parsed SDP B: m=audio 0 RTP/AVP 112 113 110 3 111\r\n
|
||||||
|
parsed SDP B: a=rtpmap:112 AMR/8000\r\n
|
||||||
|
parsed SDP B: a=fmtp:112 octet-align=1;mode-set=0,1,2,3\r\n
|
||||||
|
parsed SDP B: a=rtpmap:113 AMR-WB/8000\r\n
|
||||||
|
parsed SDP B: a=fmtp:113 octet-align=1\r\n
|
||||||
|
parsed SDP B: a=rtpmap:110 GSM-EFR/8000\r\n
|
||||||
|
parsed SDP B: a=rtpmap:3 GSM/8000\r\n
|
||||||
|
parsed SDP B: a=rtpmap:111 GSM-HR-08/8000\r\n
|
||||||
|
parsed SDP B: a=ptime:20\r\n
|
||||||
|
sdp_msg_intersection(a,b): v=0\r\n
|
||||||
|
sdp_msg_intersection(a,b): o=OsmoMSC 0 0 IN IP4 0.0.0.0\r\n
|
||||||
|
sdp_msg_intersection(a,b): s=GSM Call\r\n
|
||||||
|
sdp_msg_intersection(a,b): c=IN IP4 0.0.0.0\r\n
|
||||||
|
sdp_msg_intersection(a,b): t=0 0\r\n
|
||||||
|
sdp_msg_intersection(a,b): m=audio 0 RTP/AVP 112 113 110 3 111\r\n
|
||||||
|
sdp_msg_intersection(a,b): a=rtpmap:112 AMR/8000\r\n
|
||||||
|
sdp_msg_intersection(a,b): a=fmtp:112 octet-align=1;mode-set=0,1,2,3\r\n
|
||||||
|
sdp_msg_intersection(a,b): a=rtpmap:113 AMR-WB/8000\r\n
|
||||||
|
sdp_msg_intersection(a,b): a=fmtp:113 octet-align=1\r\n
|
||||||
|
sdp_msg_intersection(a,b): a=rtpmap:110 GSM-EFR/8000\r\n
|
||||||
|
sdp_msg_intersection(a,b): a=rtpmap:3 GSM/8000\r\n
|
||||||
|
sdp_msg_intersection(a,b): a=rtpmap:111 GSM-HR-08/8000\r\n
|
||||||
|
sdp_msg_intersection(a,b): a=ptime:20\r\n
|
||||||
|
[7] ok
|
||||||
|
|
||||||
|
|
||||||
|
test_select
|
||||||
|
|
||||||
|
[0]
|
||||||
|
SDP: AMR:octet-align=1,GSM,GSM-HR-08,GSM-EFR
|
||||||
|
Select: AMR:octet-align=1
|
||||||
|
SDP: AMR:octet-align=1,GSM,GSM-HR-08,GSM-EFR
|
||||||
|
[0] ok
|
||||||
|
|
||||||
|
[1]
|
||||||
|
SDP: AMR:octet-align=1,GSM,GSM-HR-08,GSM-EFR
|
||||||
|
Select: GSM
|
||||||
|
SDP: GSM,AMR:octet-align=1,GSM-HR-08,GSM-EFR
|
||||||
|
[1] ok
|
||||||
|
|
||||||
|
[2]
|
||||||
|
SDP: AMR:octet-align=1,GSM,GSM-HR-08,GSM-EFR
|
||||||
|
Select: GSM-HR-08
|
||||||
|
SDP: GSM-HR-08,AMR:octet-align=1,GSM,GSM-EFR
|
||||||
|
[2] ok
|
||||||
|
|
||||||
|
[3]
|
||||||
|
SDP: AMR:octet-align=1,GSM,GSM-HR-08,GSM-EFR
|
||||||
|
Select: GSM-EFR
|
||||||
|
SDP: GSM-EFR,AMR:octet-align=1,GSM,GSM-HR-08
|
||||||
|
[3] ok
|
|
@ -107,3 +107,10 @@ cat $abs_srcdir/msc_vlr/msc_vlr_test_ss.ok > expout
|
||||||
cat $abs_srcdir/msc_vlr/msc_vlr_test_ss.err > experr
|
cat $abs_srcdir/msc_vlr/msc_vlr_test_ss.err > experr
|
||||||
AT_CHECK([$abs_top_builddir/tests/msc_vlr/msc_vlr_test_ss], [], [expout], [experr])
|
AT_CHECK([$abs_top_builddir/tests/msc_vlr/msc_vlr_test_ss], [], [expout], [experr])
|
||||||
AT_CLEANUP
|
AT_CLEANUP
|
||||||
|
|
||||||
|
AT_SETUP([sdp_msg_test])
|
||||||
|
AT_KEYWORDS([sdp_msg_test])
|
||||||
|
cat $abs_srcdir/sdp_msg/sdp_msg_test.ok > expout
|
||||||
|
cat $abs_srcdir/sdp_msg/sdp_msg_test.err > experr
|
||||||
|
AT_CHECK([$abs_top_builddir/tests/sdp_msg/sdp_msg_test], [], [expout], [experr])
|
||||||
|
AT_CLEANUP
|
||||||
|
|
Loading…
Reference in New Issue