From 24c09fbacbc93a60dfbb932e1a985931249d4f7b Mon Sep 17 00:00:00 2001 From: Neels Hofmeyr Date: Tue, 20 Feb 2024 06:25:56 +0100 Subject: [PATCH] add libosmo-sdp: add sdp_msg.h,.c Change-Id: Id53c2c6eea3726f63a1399ae985f8aa3344e32c8 --- include/Makefile.am | 1 + include/osmocom/sdp/sdp_msg.h | 98 +++ src/libosmo-sdp/Makefile.am | 1 + src/libosmo-sdp/sdp_msg.c | 448 ++++++++++++ tests/sdp/Makefile.am | 11 + tests/sdp/sdp_msg_test.c | 754 ++++++++++++++++++++ tests/sdp/sdp_msg_test.err | 0 tests/sdp/sdp_msg_test.ok | 1262 +++++++++++++++++++++++++++++++++ tests/testsuite.at | 7 + 9 files changed, 2582 insertions(+) create mode 100644 include/osmocom/sdp/sdp_msg.h create mode 100644 src/libosmo-sdp/sdp_msg.c create mode 100644 tests/sdp/sdp_msg_test.c create mode 100644 tests/sdp/sdp_msg_test.err create mode 100644 tests/sdp/sdp_msg_test.ok diff --git a/include/Makefile.am b/include/Makefile.am index 02b9d8027..3c3baace0 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -11,6 +11,7 @@ nobase_include_HEADERS = \ osmocom/sdp/fmtp.h \ osmocom/sdp/sdp_codec.h \ osmocom/sdp/sdp_codec_list.h \ + osmocom/sdp/sdp_msg.h \ osmocom/sdp/sdp_strings.h \ $(NULL) diff --git a/include/osmocom/sdp/sdp_msg.h b/include/osmocom/sdp/sdp_msg.h new file mode 100644 index 000000000..acb8e3b81 --- /dev/null +++ b/include/osmocom/sdp/sdp_msg.h @@ -0,0 +1,98 @@ +/* Public API for SDP message encoding and decoding */ +/* + * (C) 2024 by sysmocom - s.f.m.c. GmbH + * All Rights Reserved. + * + * Author: Neels Janosch Hofmeyr + * + * SPDX-License-Identifier: GPL-2.0+ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once + +#include + +#include +#include + +/* Media Direction Attributes "a=recvonly", "a=sendrecv", "a=sendonly", "a=inactive" RFC-8866 6.7. */ +enum osmo_sdp_media_direcion_e { + OSMO_SDP_MDIR_UNSET = 0, + OSMO_SDP_MDIR_RECVONLY = 1, + OSMO_SDP_MDIR_SENDRECV = 2, + OSMO_SDP_MDIR_SENDONLY = 3, + OSMO_SDP_MDIR_INACTIVE = 4, +}; + +/* Session Description Protocol (SDP) message, RFC-8866. */ +struct osmo_sdp_msg { + /* 5.2 Origin ("o="). */ + struct { + struct osmo_sockaddr_str addr; + char *username; + int64_t sess_id; + int64_t sess_version; + } origin; + + /* 5.3 Session Name ("s="). */ + char *session_name; + + /* 5.7 Connection Information ("c=") and port from 5.14 Media Descriptions ("m="). */ + struct osmo_sockaddr_str rtp; + + /* 5.9. Time Active ("t="). */ + struct { + int64_t start; + int64_t stop; + } time_active; + + /* 6.4 "a=ptime:". */ + unsigned int ptime; + + /* 6.7 "a=sendrecv"... */ + enum osmo_sdp_media_direcion_e media_direction; + + /* List of codecs defined in the SDP message. + * This should not be NULL -- osmo_sdp_msg_alloc() returns an empty osmo_sdp_codec_list instance, ready for + * adding codecs. + * Combination of: + * - payload_type numbers from 5.14 Media Descriptions ("m="), + * - 6.6 "a=rtpmap", + * - 6.15 Format Parameters "a=fmtp". + */ + struct osmo_sdp_codec_list *codecs; + + /* For future extension, always set to false. */ + bool v2; +}; + +struct osmo_sdp_err { + int rc; + /* Point at the position that caused the error, in the src string. */ + const char *src_str; + /* Nr of characters at *src_str that are relevant to the error. */ + size_t src_str_len; +}; + +struct osmo_sdp_msg *osmo_sdp_msg_alloc(void *ctx); + +struct osmo_sdp_msg *osmo_sdp_msg_decode(void *ctx, const char *src, struct osmo_sdp_err *err); + +int osmo_sdp_msg_encode_buf(char *dst, size_t dst_size, const struct osmo_sdp_msg *sdp); +char *osmo_sdp_msg_encode_c(void *ctx, const struct osmo_sdp_msg *sdp); + +int osmo_sdp_msg_to_str_buf(char *buf, size_t buflen, const struct osmo_sdp_msg *sdp, bool summarize); +char *osmo_sdp_msg_to_str_c(void *ctx, const struct osmo_sdp_msg *sdp, bool summarize); diff --git a/src/libosmo-sdp/Makefile.am b/src/libosmo-sdp/Makefile.am index a78554861..b73b40ca7 100644 --- a/src/libosmo-sdp/Makefile.am +++ b/src/libosmo-sdp/Makefile.am @@ -17,6 +17,7 @@ noinst_LTLIBRARIES = \ libosmo_sdp_la_SOURCES = \ sdp_codec.c \ sdp_codec_list.c \ + sdp_msg.c \ sdp_internal.c \ fmtp.c \ $(NULL) diff --git a/src/libosmo-sdp/sdp_msg.c b/src/libosmo-sdp/sdp_msg.c new file mode 100644 index 000000000..246fa59c7 --- /dev/null +++ b/src/libosmo-sdp/sdp_msg.c @@ -0,0 +1,448 @@ +/* Implementation for SDP message encoding and decoding */ +/* + * (C) 2024 by sysmocom - s.f.m.c. GmbH + * All Rights Reserved. + * + * Author: Neels Janosch Hofmeyr + * + * SPDX-License-Identifier: GPL-2.0+ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include + +#include + +#include +#include +#include + +static const char * const mdir_str[] = { + [OSMO_SDP_MDIR_UNSET] = "-", + [OSMO_SDP_MDIR_SENDONLY] = OSMO_SDP_STR_SENDONLY, + [OSMO_SDP_MDIR_RECVONLY] = OSMO_SDP_STR_RECVONLY, + [OSMO_SDP_MDIR_SENDRECV] = OSMO_SDP_STR_SENDRECV, + [OSMO_SDP_MDIR_INACTIVE] = OSMO_SDP_STR_INACTIVE, +}; + +/*! Convert struct osmo_sdp_msg to the actual SDP protocol representation. */ +int osmo_sdp_msg_encode_buf(char *dst, size_t dst_size, const struct osmo_sdp_msg *sdp) +{ + const struct osmo_sdp_codec *codec; + struct osmo_strbuf sb = { .buf = dst, .len = dst_size }; + const char *oip; + char oipv; + const char *ip; + char ipv; + + if (!sdp) { + OSMO_STRBUF_PRINTF(sb, "%s", ""); + return sb.chars_needed; + } + + oip = sdp->origin.addr.ip[0] ? sdp->origin.addr.ip : "0.0.0.0"; + oipv = (osmo_ip_str_type(oip) == AF_INET6) ? '6' : '4'; + + ip = sdp->rtp.ip[0] ? sdp->rtp.ip : "0.0.0.0"; + ipv = (osmo_ip_str_type(oip) == AF_INET6) ? '6' : '4'; + + OSMO_STRBUF_PRINTF(sb, + "v=0\r\n" + "o=%s %"PRId64" %"PRId64" IN IP%c %s\r\n" + "s=%s\r\n" + "c=IN IP%c %s\r\n" + "t=%"PRId64" %"PRId64"\r\n" + "m=audio %d RTP/AVP", + sdp->origin.username ? : "libosmo-sdp", + sdp->origin.sess_id, sdp->origin.sess_version, + oipv, oip, + sdp->session_name ? : "-", + ipv, ip, + sdp->time_active.start, + sdp->time_active.stop, + sdp->rtp.port); + + /* Append all payload type numbers to 'm=audio RTP/AVP 3 4 112' line */ + osmo_sdp_codec_list_foreach(codec, sdp->codecs) + OSMO_STRBUF_PRINTF(sb, " %d", codec->payload_type); + OSMO_STRBUF_PRINTF(sb, "\r\n"); + + /* Add details for all codecs */ + osmo_sdp_codec_list_foreach(codec, sdp->codecs) { + if (!osmo_sdp_codec_is_set(codec)) + continue; + OSMO_STRBUF_PRINTF(sb, OSMO_SDP_A_PREFIX(OSMO_SDP_STR_RTPMAP) "%d %s/%d\r\n", codec->payload_type, codec->encoding_name, + codec->rate > 0 ? codec->rate : 8000); + if (codec->fmtp && codec->fmtp[0]) + OSMO_STRBUF_PRINTF(sb, OSMO_SDP_A_PREFIX(OSMO_SDP_STR_FMTP) "%d %s\r\n", codec->payload_type, codec->fmtp); + } + + if (sdp->ptime) + OSMO_STRBUF_PRINTF(sb, OSMO_SDP_A_PREFIX(OSMO_SDP_STR_PTIME) "%d\r\n", sdp->ptime); + + if (sdp->media_direction != OSMO_SDP_MDIR_UNSET && sdp->media_direction < ARRAY_SIZE(mdir_str)) + OSMO_STRBUF_PRINTF(sb, "a=%s\r\n", mdir_str[sdp->media_direction]); + + return sb.chars_needed; +} + +char *osmo_sdp_msg_encode_c(void *ctx, const struct osmo_sdp_msg *sdp) +{ + OSMO_NAME_C_IMPL(ctx, 256, "osmo_sdp_msg_to_str_c-ERROR", osmo_sdp_msg_encode_buf, sdp) +} + +/* Return the first line ending (or the end of the string) at or after the given string position. */ +const char *get_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; +} + +static bool str_is_attrib(const char *str, const char *attrib_name, char expect_next_char) +{ + char next_c; + if (!osmo_str_startswith(str, attrib_name)) + return false; + next_c = str[strlen(attrib_name)]; + if (expect_next_char == next_c) + return true; + /* Treat \0 as equivalent with line end */ + if (!expect_next_char && (next_c == '\r' || next_c == '\n')) + return true; + /* It started with the string, but continued otherwise */ + return false; +} + +static enum osmo_sdp_media_direcion_e check_for_media_direction(const char *str) +{ + int i; + for (i = 0; i < ARRAY_SIZE(mdir_str); i++) { + if (i == OSMO_SDP_MDIR_UNSET) + continue; + if (str_is_attrib(str, mdir_str[i], 0)) + return i; + } + return OSMO_SDP_MDIR_UNSET; +} + +static struct osmo_sdp_codec *find_or_create_payload_type(struct osmo_sdp_msg *sdp, unsigned int payload_type) +{ + struct osmo_sdp_codec *codec; + codec = osmo_sdp_codec_list_by_payload_type(sdp->codecs, payload_type); + if (!codec) { + codec = osmo_sdp_codec_list_add_empty(sdp->codecs); + codec->payload_type = payload_type; + codec->rate = 8000; + } + return codec; +} + + +/* 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 osmo_sdp_msg *sdp, const char *src) +{ + unsigned int payload_type; + struct osmo_sdp_codec *codec; + enum osmo_sdp_media_direcion_e mdir; + const char *line_end = get_line_end(src); + + if (str_is_attrib(src, OSMO_SDP_STR_RTPMAP, ':')) { + /* "a=rtpmap:96 AMR/8000" */ + struct token audio_name; + unsigned int channels = 1; + if (sscanf(src, OSMO_SDP_STR_RTPMAP ":%u", &payload_type) != 1) + return -EINVAL; + + codec = find_or_create_payload_type(sdp, payload_type); + + audio_name.start = strchr(src, ' '); + if (!audio_name.start) + return -EINVAL; + audio_name.start++; + if (audio_name.start >= get_line_end(src)) + return -EINVAL; + + audio_name.end = strchr(audio_name.start, '/'); + if (!audio_name.end || audio_name.end > line_end) + audio_name.end = line_end; + token_copy(codec, &codec->encoding_name, &audio_name); + /* '< 1' is enough, the second '/%u' is optional */ + if (sscanf(audio_name.end, "/%u/%u", &codec->rate, &channels) < 1) + return -EINVAL; + + if (channels != 1) + return -ENOTSUP; + } + + else if (str_is_attrib(src, OSMO_SDP_STR_FMTP, ':')) { + /* "a=fmtp:112 octet-align=1;mode-set=0,1,2,3" */ + struct token fmtp_str; + const char *line_end = get_line_end(src); + if (sscanf(src, OSMO_SDP_STR_FMTP ":%u", &payload_type) != 1) + return -EINVAL; + + codec = find_or_create_payload_type(sdp, payload_type); + + fmtp_str.start = strchr(src, ' '); + if (!fmtp_str.start) + return -EINVAL; + fmtp_str.start++; + if (fmtp_str.start >= line_end) + return -EINVAL; + + fmtp_str.end = line_end; + token_copy(codec, &codec->fmtp, &fmtp_str); + } + + else if (str_is_attrib(src, OSMO_SDP_STR_PTIME, ':')) { + /* "a=ptime:20" */ + if (sscanf(src, OSMO_SDP_STR_PTIME ":%u", &sdp->ptime) != 1) + return -EINVAL; + + } + + /* "a=sendrecv" ... */ + else if ((mdir = check_for_media_direction(src)) != OSMO_SDP_MDIR_UNSET) { + sdp->media_direction = mdir; + } + + return 0; +} + +static const struct value_string fixed_payload_types[] = { + { 0, "PCMU" }, + { 3, "GSM" }, + { 8, "PCMA" }, + { 18, "G729" }, + { 110, "GSM-EFR" }, + { 111, "GSM-HR-08" }, + { 112, "AMR" }, + { 113, "AMR-WB" }, + {} +}; + +/* Parse a line like 'm=audio 16398 RTP/AVP 0 3 8 96 112', starting after the '=' */ +static int sdp_parse_media_description(struct osmo_sdp_msg *sdp, const char *src) +{ + unsigned int port; + int i; + const char *payload_type_str; + const char *line_end = get_line_end(src); + if (sscanf(src, "audio %u RTP/AVP", &port) < 1) + return -ENOTSUP; + + if (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 osmo_sdp_codec *codec; + const char *encoding_name; + if (sscanf(payload_type_str, "%u", &payload_type) < 1) + return -EINVAL; + + codec = find_or_create_payload_type(sdp, payload_type); + + /* Fill in encoding name for fixed payload types */ + encoding_name = get_value_string_or_null(fixed_payload_types, codec->payload_type); + if (encoding_name) + osmo_talloc_replace_string(codec, &codec->encoding_name, encoding_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 osmo_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; + + if (strcmp(ipv, "IP4") && strcmp(ipv, "IP6")) + return -ENOTSUP; + + return osmo_sockaddr_str_from_str(&sdp->rtp, addr_str, sdp->rtp.port); +} + +/* parse a line like 'o=jdoe 3724394400 3724394405 IN IP4 198.51.100.1' starting after the '=' */ +static int sdp_parse_origin(struct osmo_sdp_msg *sdp, const char *src) +{ + struct token username; + char ipv[16] = {}; + char addr_str[INET6_ADDRSTRLEN] = {}; + const char *line_end = get_line_end(src); + + username.start = src; + username.end = strchr(src, ' '); + if (!username.end || username.end >= line_end) + return -EINVAL; + token_copy(sdp, &sdp->origin.username, &username); + + if (sscanf(username.end + 1, "%"PRId64" %"PRId64" IN %15s %45s", + &sdp->origin.sess_id, &sdp->origin.sess_version, ipv, addr_str) < 4) + return -EINVAL; + + if (strcmp(ipv, "IP4") && strcmp(ipv, "IP6")) + return -ENOTSUP; + return osmo_sockaddr_str_from_str(&sdp->origin.addr, addr_str, 0); +} + +static int sdp_parse_session_name(struct osmo_sdp_msg *sdp, const char *src) +{ + const char *line_end = get_line_end(src); + if (sdp->session_name) + talloc_free(sdp->session_name); + if (line_end <= src) + sdp->session_name = NULL; + else + sdp->session_name = talloc_strndup(sdp, src, line_end - src); + return 0; +} + +struct osmo_sdp_msg *osmo_sdp_msg_alloc(void *ctx) +{ + struct osmo_sdp_msg *sdp; + sdp = talloc_zero(ctx, struct osmo_sdp_msg); + sdp->codecs = osmo_sdp_codec_list_alloc(sdp); + return sdp; +} + +/* Parse SDP string into struct osmo_sdp_msg. Return 0 on success, negative on error. + * Return a new osmo_sdp_msg instance allocated from ctx, or NULL on error. + * When NULL is returned and if err is non-NULL, details of the error are returned in err->*. + */ +struct osmo_sdp_msg *osmo_sdp_msg_decode(void *ctx, const char *src, struct osmo_sdp_err *err) +{ + struct osmo_sdp_msg *sdp; + const char *pos; + + if (err) + *err = (struct osmo_sdp_err){}; + + sdp = osmo_sdp_msg_alloc(ctx); + + 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; + case 'o': + rc = sdp_parse_origin(sdp, pos); + break; + case 's': + rc = sdp_parse_session_name(sdp, pos); + break; + default: + /* ignore any other parameters */ + break; + } + + if (rc) { + if (err) { + const char *line_end = get_line_end(pos); + /* shift back to include the 'x=' part as well */ + pos -= 2; + *err = (struct osmo_sdp_err){ + .rc = rc, + .src_str = pos, + .src_str_len = line_end - pos, + }; + } + talloc_free(sdp); + return NULL; + } + +next_line: + pos = strstr(pos, "\r\n"); + if (!pos) + break; + } + + return sdp; +} + +/*! Short single-line representation of an SDP message, convenient for logging. + * To obtain a valid SDP message, use osmo_sdp_msg_encode_buf() instead. + */ +int osmo_sdp_msg_to_str_buf(char *buf, size_t buflen, const struct osmo_sdp_msg *sdp, bool summarize) +{ + 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, osmo_sdp_codec_list_to_str_buf, sdp->codecs, summarize); + OSMO_STRBUF_PRINTF(sb, "}"); + return sb.chars_needed; +} + +char *osmo_sdp_msg_to_str_c(void *ctx, const struct osmo_sdp_msg *sdp, bool summarize) +{ + OSMO_NAME_C_IMPL(ctx, 128, "sdp_msg_to_str_c-ERROR", osmo_sdp_msg_to_str_buf, sdp, summarize) +} diff --git a/tests/sdp/Makefile.am b/tests/sdp/Makefile.am index b0b5b0a45..7d072f320 100644 --- a/tests/sdp/Makefile.am +++ b/tests/sdp/Makefile.am @@ -27,6 +27,7 @@ EXTRA_DIST = \ check_PROGRAMS = \ sdp_fmtp_test \ sdp_codec_test \ + sdp_msg_test \ $(NULL) sdp_fmtp_test_SOURCES = \ @@ -46,6 +47,16 @@ sdp_codec_test_LDADD = \ $(LIBOSMOCORE_LIBS) \ $(NULL) +sdp_msg_test_SOURCES = \ + sdp_msg_test.c \ + $(NULL) + +sdp_msg_test_LDADD = \ + $(top_builddir)/src/libosmo-sdp/libosmo-sdp.la \ + $(LIBOSMOCORE_LIBS) \ + $(NULL) + update_exp: $(builddir)/sdp_fmtp_test >$(srcdir)/sdp_fmtp_test.ok 2>$(srcdir)/sdp_fmtp_test.err $(builddir)/sdp_codec_test >$(srcdir)/sdp_codec_test.ok 2>$(srcdir)/sdp_codec_test.err + $(builddir)/sdp_msg_test >$(srcdir)/sdp_msg_test.ok 2>$(srcdir)/sdp_msg_test.err diff --git a/tests/sdp/sdp_msg_test.c b/tests/sdp/sdp_msg_test.c new file mode 100644 index 000000000..61dab6de6 --- /dev/null +++ b/tests/sdp/sdp_msg_test.c @@ -0,0 +1,754 @@ +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +void *test_ctx = NULL; + +static void report_callback(const void *ptr, int depth, int max_depth, int is_ref, void *priv) +{ + const char *name = talloc_get_name(ptr); + printf(" |%*s%3zu %s\n", depth, "", talloc_total_blocks(ptr), name); +} + +/* Print a talloc report that is reproducible for test output verification. It contains no pointer addresses. */ +#define report(CTX) _report(CTX, #CTX) +static void _report(void *ctx, const char *label) +{ + fflush(stdout); + fflush(stderr); + printf("%s\n", label); + talloc_report_depth_cb(ctx, 0, 100, report_callback, NULL); + fflush(stdout); +} + +static void dump_sdp(const char *str, const char *prefix) +{ + while (str && *str) { + const char *line_end = str; + while (*line_end && *line_end != '\r' && *line_end != '\n') + line_end++; + 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_msg_test_data { + const char *sdp_input; + const char *expect_sdp_str; +}; + +static const struct sdp_msg_test_data sdp_msg_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=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=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" + /* The rtcp line is dropped, not supported yet */ + }, + { + "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=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 ends up further below */ + /* The rtcp line is dropped, not supported yet */ + "a=ptime:20\r\n" + "a=sendrecv\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=recvonly\r\n" + "a=rtcp:30437\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=recvonly ends up further below */ + /* The rtcp line is dropped, not supported yet */ + "a=ptime:20\r\n" + "a=recvonly\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=ptime:20\r\n" + "a=sendonly\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=ptime:20\r\n" + "a=inactive\r\n" + , + }, +}; + +static void test_parse_and_compose(void) +{ + void *ctx = talloc_named_const(test_ctx, 0, __func__); + int i; + bool ok = true; + + printf("\n\n%s\n", __func__); + + for (i = 0; i < ARRAY_SIZE(sdp_msg_tests); i++) { + const struct sdp_msg_test_data *t = &sdp_msg_tests[i]; + struct osmo_sdp_msg *sdp_msg; + char str[1024]; + const char *expect; + + printf("\n[%d]\n", i); + dump_sdp(t->sdp_input, "sdp input: "); + + sdp_msg = osmo_sdp_msg_decode(ctx, t->sdp_input, NULL); + + osmo_sdp_msg_encode_buf(str, sizeof(str), sdp_msg); + dump_sdp(str, "osmo_sdp_msg_encode_buf: "); + expect = t->expect_sdp_str ? : t->sdp_input; + if (strcmp(str, expect)) { + int j; + ok = false; + printf("ERROR:\n"); + dump_sdp(expect, "expect: "); + for (j = 0; expect[j]; j++) { + if (expect[j] != str[j]) { + printf("ERROR at position %d, at:\n", j); + dump_sdp(str + j, " mismatch: "); + break; + } + } + } else + printf("[%d] ok\n", i); + + report(ctx); + printf("talloc_free(sdp_msg)\n"); + talloc_free(sdp_msg); + report(ctx); + + if (talloc_total_blocks(ctx) != 1) { + printf("ERROR: memleak\n"); + talloc_free_children(ctx); + } + printf("\n"); + } + + OSMO_ASSERT(ok); + talloc_free(ctx); +} + +struct intersect_test_data { + const char *descr; + const char *sdp_msg_a; + const char *sdp_msg_b; + const char *expect_intersection; +}; + +#define SDP_1 \ + "v=0\r\n" \ + "o=libosmo-sdp 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=libosmo-sdp 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=libosmo-sdp 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 123\r\n" \ + "a=rtpmap:3 GSM/8000\r\n" \ + "a=rtpmap:111 GSM-HR-08/8000\r\n" \ + "a=rtpmap:123 FOO/8000\r\n" \ + "a=ptime:20\r\n" + +#define SDP_4 \ + "v=0\r\n" \ + "o=libosmo-sdp 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" + +#define SDP_5 \ + "v=0\r\n" \ + "o=libosmo-sdp 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" + +static const struct intersect_test_data 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_4, + }, + { + "all codecs removed", + SDP_1 + , + "s=empty" + , + "v=0\r\n" \ + "o=libosmo-sdp 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", + SDP_5, SDP_5, SDP_5, + }, +}; + +static const char *sdp_msg_logstr(const struct osmo_sdp_msg *sdp_msg) +{ + static char buf[1024]; + osmo_sdp_msg_encode_buf(buf, sizeof(buf), sdp_msg); + return buf; +} + +static void test_intersect(void) +{ + int i; + bool ok = true; + void *ctx = talloc_named_const(test_ctx, 0, __func__); + + printf("\n\n%s\n", __func__); + + for (i = 0; i < ARRAY_SIZE(intersect_tests); i++) { + const struct intersect_test_data *t = &intersect_tests[i]; + struct osmo_sdp_msg *sdp_msg_a = NULL; + struct osmo_sdp_msg *sdp_msg_b = NULL; + char str[1024]; + printf("\n[%d] %s\n", i, t->descr); + dump_sdp(t->sdp_msg_a, "SDP A: "); + dump_sdp(t->sdp_msg_b, " SDP B: "); + + sdp_msg_a = osmo_sdp_msg_decode(ctx, t->sdp_msg_a, NULL); + if (!sdp_msg_a) { + printf("ERROR parsing SDP A\n"); + break; + } + dump_sdp(sdp_msg_logstr(sdp_msg_a), "parsed SDP A: "); + + sdp_msg_b = osmo_sdp_msg_decode(ctx, t->sdp_msg_b, NULL); + if (!sdp_msg_b) { + printf("ERROR parsing SDP B\n"); + break; + } + dump_sdp(sdp_msg_logstr(sdp_msg_b), "parsed SDP B: "); + + osmo_sdp_codec_list_intersection(sdp_msg_a->codecs, sdp_msg_b->codecs, + &osmo_sdp_codec_cmp_equivalent, + false); + osmo_sdp_msg_encode_buf(str, sizeof(str), sdp_msg_a); + dump_sdp(str, "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); + + report(ctx); + printf("talloc_free(sdp_msg_a)\n"); + talloc_free(sdp_msg_a); + report(ctx); + printf("talloc_free(sdp_msg_b)\n"); + talloc_free(sdp_msg_b); + report(ctx); + + if (talloc_total_blocks(ctx) != 1) { + printf("ERROR: memleak\n"); + talloc_free_children(ctx); + } + printf("\n"); + } + + OSMO_ASSERT(ok); + talloc_free(ctx); +} + +struct sdp_select_test_data { + const char *sdp; + const struct osmo_sdp_codec_cmp_flags *cmpf; + const struct osmo_sdp_codec select; + const char *expect_sdp; +}; + +static const struct osmo_sdp_codec_cmp_flags pt_only = { .payload_type = true }; + +static const struct sdp_select_test_data sdp_select_tests[] = { + { + "v=0\r\n" + "o=libosmo-sdp 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" + , + &pt_only, + { .payload_type = 112, }, + NULL + }, + { + "v=0\r\n" + "o=libosmo-sdp 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" + , + &pt_only, + { .payload_type = 3, }, + "v=0\r\n" + "o=libosmo-sdp 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=libosmo-sdp 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" + , + &pt_only, + { .payload_type = 111, }, + "v=0\r\n" + "o=libosmo-sdp 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=libosmo-sdp 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" + , + &pt_only, + { .payload_type = 110, }, + "v=0\r\n" + "o=libosmo-sdp 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(void) +{ + int i; + bool ok = true; + void *ctx = talloc_named_const(test_ctx, 0, __func__); + void *print_ctx = talloc_named_const(test_ctx, 0, "print"); + + printf("\n\n%s\n", __func__); + + for (i = 0; i < ARRAY_SIZE(sdp_select_tests); i++) { + const struct sdp_select_test_data *t = &sdp_select_tests[i]; + struct osmo_sdp_msg *sdp_msg; + char buf[1024]; + const char *expect_sdp; + + printf("\n[%d]\n", i); + sdp_msg = osmo_sdp_msg_decode(ctx, t->sdp, NULL); + if (!sdp_msg) { + printf("ERROR parsing SDP\n"); + break; + } + printf("SDP: %s\n", osmo_sdp_codec_list_to_str_c(print_ctx, sdp_msg->codecs, false)); + + printf("Select: %s\n", osmo_sdp_codec_to_str_c(print_ctx, &t->select)); + osmo_sdp_codec_list_move_to_first(sdp_msg->codecs, &t->select, t->cmpf); + + printf("SDP: %s\n", osmo_sdp_codec_list_to_str_c(print_ctx, sdp_msg->codecs, false)); + osmo_sdp_msg_encode_buf(buf, sizeof(buf), sdp_msg); + + expect_sdp = t->expect_sdp ? : t->sdp; + if (strcmp(buf, expect_sdp)) { + int j; + ok = false; + printf("ERROR:\n"); + dump_sdp(buf, "selection result: "); + dump_sdp(expect_sdp, "expect result: "); + for (j = 0; expect_sdp[j]; j++) { + if (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); + + report(ctx); + printf("talloc_free(sdp_msg)\n"); + talloc_free(sdp_msg); + report(ctx); + if (talloc_total_blocks(ctx) != 1) { + printf("ERROR: memleak\n"); + talloc_free_children(ctx); + } + printf("\n"); + talloc_free_children(print_ctx); + } + + OSMO_ASSERT(ok); + talloc_free(ctx); + talloc_free(print_ctx); +} + + +struct my_obj { + struct osmo_sdp_msg *sdp_msg; +}; + +static struct my_obj *my_obj_alloc(void *ctx) +{ + struct my_obj *o = talloc_zero(ctx, struct my_obj); + return o; +} + +static void test_obj_members(void) +{ + void *ctx = talloc_named_const(test_ctx, 0, __func__); + void *print_ctx = talloc_named_const(test_ctx, 0, "print"); + int i; + + struct my_obj *o; + + printf("\n\n--- %s()\n", __func__); + o = my_obj_alloc(ctx); + + o->sdp_msg = osmo_sdp_msg_alloc(o); + + printf("o->sdp_msg = '%s'\n", osmo_sdp_msg_encode_c(print_ctx, o->sdp_msg)); + report(ctx); + + const struct osmo_sdp_codec all_codecs[] = { + { .payload_type = 112, .encoding_name = "AMR", .rate = 8000, .fmtp = "octet-align=1;mode-set=0,2,4" }, + { .payload_type = 3, .encoding_name = "GSM", .rate = 8000 }, + { .payload_type = 111, .encoding_name = "GSM-HR-08", .rate = 8000 }, + }; + + for (i = 0; i < ARRAY_SIZE(all_codecs); i++) + osmo_sdp_codec_list_add(o->sdp_msg->codecs, &all_codecs[i], false, false); + + printf("o->sdp_msg = '%s'\n", osmo_sdp_msg_encode_c(print_ctx, o->sdp_msg)); + + report(ctx); + printf("talloc_free(o)\n"); + talloc_free(o); + report(ctx); + talloc_free(ctx); + talloc_free(print_ctx); +} + +typedef void (*test_func_t)(void); + +static const test_func_t test_func[] = { + test_parse_and_compose, + test_intersect, + test_select, + test_obj_members, +}; + +int main(void) +{ + int i; + test_ctx = talloc_named_const(NULL, 0, "sdp_codec_test"); + + for (i = 0; i < ARRAY_SIZE(test_func); i++) { + + test_func[i](); + + if (talloc_total_blocks(test_ctx) != 1) { + talloc_report_full(test_ctx, stderr); + printf("ERROR after test %d: memory leak\n", i); + return -1; + } + } + + talloc_free(test_ctx); + return 0; +} diff --git a/tests/sdp/sdp_msg_test.err b/tests/sdp/sdp_msg_test.err new file mode 100644 index 000000000..e69de29bb diff --git a/tests/sdp/sdp_msg_test.ok b/tests/sdp/sdp_msg_test.ok new file mode 100644 index 000000000..abfbf5fc1 --- /dev/null +++ b/tests/sdp/sdp_msg_test.ok @@ -0,0 +1,1262 @@ + + +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 +osmo_sdp_msg_encode_buf: v=0\r\n +osmo_sdp_msg_encode_buf: o=- 5628250 5628250 IN IP4 192.168.11.121\r\n +osmo_sdp_msg_encode_buf: s=-\r\n +osmo_sdp_msg_encode_buf: c=IN IP4 192.168.11.121\r\n +osmo_sdp_msg_encode_buf: t=0 0\r\n +osmo_sdp_msg_encode_buf: m=audio 10020 RTP/AVP 18 0 2 4 8 96 97 98 100 101\r\n +osmo_sdp_msg_encode_buf: a=rtpmap:18 G729/8000\r\n +osmo_sdp_msg_encode_buf: a=rtpmap:0 PCMU/8000\r\n +osmo_sdp_msg_encode_buf: a=rtpmap:2 G726-32/8000\r\n +osmo_sdp_msg_encode_buf: a=rtpmap:4 G723/8000\r\n +osmo_sdp_msg_encode_buf: a=rtpmap:8 PCMA/8000\r\n +osmo_sdp_msg_encode_buf: a=rtpmap:96 G726-40/8000\r\n +osmo_sdp_msg_encode_buf: a=rtpmap:97 G726-24/8000\r\n +osmo_sdp_msg_encode_buf: a=rtpmap:98 G726-16/8000\r\n +osmo_sdp_msg_encode_buf: a=rtpmap:100 NSE/8000\r\n +osmo_sdp_msg_encode_buf: a=fmtp:100 192-193\r\n +osmo_sdp_msg_encode_buf: a=rtpmap:101 telephone-event/8000\r\n +osmo_sdp_msg_encode_buf: a=fmtp:101 0-15\r\n +osmo_sdp_msg_encode_buf: a=ptime:20\r\n +osmo_sdp_msg_encode_buf: a=sendrecv\r\n +[0] ok +ctx + | 27 test_parse_and_compose + | 26 struct osmo_sdp_msg + | 1 - + | 1 - + | 23 struct osmo_sdp_codec_list + | 3 struct osmo_sdp_codec + | 1 0-15 + | 1 telephone-event + | 3 struct osmo_sdp_codec + | 1 192-193 + | 1 NSE + | 2 struct osmo_sdp_codec + | 1 G726-16 + | 2 struct osmo_sdp_codec + | 1 G726-24 + | 2 struct osmo_sdp_codec + | 1 G726-40 + | 2 struct osmo_sdp_codec + | 1 PCMA + | 2 struct osmo_sdp_codec + | 1 G723 + | 2 struct osmo_sdp_codec + | 1 G726-32 + | 2 struct osmo_sdp_codec + | 1 PCMU + | 2 struct osmo_sdp_codec + | 1 G729 +talloc_free(sdp_msg) +ctx + | 1 test_parse_and_compose + + +[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 +osmo_sdp_msg_encode_buf: v=0\r\n +osmo_sdp_msg_encode_buf: o=FooBar 1565090289 1565090290 IN IP4 192.168.11.151\r\n +osmo_sdp_msg_encode_buf: s=FooBar\r\n +osmo_sdp_msg_encode_buf: c=IN IP4 192.168.11.151\r\n +osmo_sdp_msg_encode_buf: t=0 0\r\n +osmo_sdp_msg_encode_buf: m=audio 16398 RTP/AVP 98\r\n +osmo_sdp_msg_encode_buf: a=rtpmap:98 AMR/8000\r\n +osmo_sdp_msg_encode_buf: a=fmtp:98 octet-align=1; mode-set=4\r\n +osmo_sdp_msg_encode_buf: a=ptime:20\r\n +[1] ok +ctx + | 8 test_parse_and_compose + | 7 struct osmo_sdp_msg + | 1 FooBar + | 1 FooBar + | 4 struct osmo_sdp_codec_list + | 3 struct osmo_sdp_codec + | 1 octet-align=1; mode-set=4 + | 1 AMR +talloc_free(sdp_msg) +ctx + | 1 test_parse_and_compose + + +[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 +osmo_sdp_msg_encode_buf: v=0\r\n +osmo_sdp_msg_encode_buf: o=FooBar 1565090289 1565090290 IN IP4 192.168.11.151\r\n +osmo_sdp_msg_encode_buf: s=FooBar\r\n +osmo_sdp_msg_encode_buf: c=IN IP4 192.168.11.140\r\n +osmo_sdp_msg_encode_buf: t=0 0\r\n +osmo_sdp_msg_encode_buf: m=audio 30436 RTP/AVP 18 0 4 8 101\r\n +osmo_sdp_msg_encode_buf: a=rtpmap:18 G729/8000\r\n +osmo_sdp_msg_encode_buf: a=rtpmap:0 PCMU/8000\r\n +osmo_sdp_msg_encode_buf: a=rtpmap:4 G723/8000\r\n +osmo_sdp_msg_encode_buf: a=rtpmap:8 PCMA/8000\r\n +osmo_sdp_msg_encode_buf: a=rtpmap:101 telephone-event/8000\r\n +osmo_sdp_msg_encode_buf: a=fmtp:101 0-15\r\n +osmo_sdp_msg_encode_buf: a=ptime:20\r\n +osmo_sdp_msg_encode_buf: a=sendrecv\r\n +[2] ok +ctx + | 16 test_parse_and_compose + | 15 struct osmo_sdp_msg + | 1 FooBar + | 1 FooBar + | 12 struct osmo_sdp_codec_list + | 3 struct osmo_sdp_codec + | 1 0-15 + | 1 telephone-event + | 2 struct osmo_sdp_codec + | 1 PCMA + | 2 struct osmo_sdp_codec + | 1 G723 + | 2 struct osmo_sdp_codec + | 1 PCMU + | 2 struct osmo_sdp_codec + | 1 G729 +talloc_free(sdp_msg) +ctx + | 1 test_parse_and_compose + + +[3] +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=recvonly\r\n +sdp input: a=rtcp:30437\r\n +sdp input: a=ptime:20\r\n +osmo_sdp_msg_encode_buf: v=0\r\n +osmo_sdp_msg_encode_buf: o=FooBar 1565090289 1565090290 IN IP4 192.168.11.151\r\n +osmo_sdp_msg_encode_buf: s=FooBar\r\n +osmo_sdp_msg_encode_buf: c=IN IP4 192.168.11.140\r\n +osmo_sdp_msg_encode_buf: t=0 0\r\n +osmo_sdp_msg_encode_buf: m=audio 30436 RTP/AVP 18 0 4 8 101\r\n +osmo_sdp_msg_encode_buf: a=rtpmap:18 G729/8000\r\n +osmo_sdp_msg_encode_buf: a=rtpmap:0 PCMU/8000\r\n +osmo_sdp_msg_encode_buf: a=rtpmap:4 G723/8000\r\n +osmo_sdp_msg_encode_buf: a=rtpmap:8 PCMA/8000\r\n +osmo_sdp_msg_encode_buf: a=rtpmap:101 telephone-event/8000\r\n +osmo_sdp_msg_encode_buf: a=fmtp:101 0-15\r\n +osmo_sdp_msg_encode_buf: a=ptime:20\r\n +osmo_sdp_msg_encode_buf: a=recvonly\r\n +[3] ok +ctx + | 16 test_parse_and_compose + | 15 struct osmo_sdp_msg + | 1 FooBar + | 1 FooBar + | 12 struct osmo_sdp_codec_list + | 3 struct osmo_sdp_codec + | 1 0-15 + | 1 telephone-event + | 2 struct osmo_sdp_codec + | 1 PCMA + | 2 struct osmo_sdp_codec + | 1 G723 + | 2 struct osmo_sdp_codec + | 1 PCMU + | 2 struct osmo_sdp_codec + | 1 G729 +talloc_free(sdp_msg) +ctx + | 1 test_parse_and_compose + + +[4] +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=ptime:20\r\n +sdp input: a=sendonly\r\n +osmo_sdp_msg_encode_buf: v=0\r\n +osmo_sdp_msg_encode_buf: o=FooBar 1565090289 1565090290 IN IP4 192.168.11.151\r\n +osmo_sdp_msg_encode_buf: s=FooBar\r\n +osmo_sdp_msg_encode_buf: c=IN IP4 192.168.11.140\r\n +osmo_sdp_msg_encode_buf: t=0 0\r\n +osmo_sdp_msg_encode_buf: m=audio 30436 RTP/AVP 18 0 4 8 101\r\n +osmo_sdp_msg_encode_buf: a=rtpmap:18 G729/8000\r\n +osmo_sdp_msg_encode_buf: a=rtpmap:0 PCMU/8000\r\n +osmo_sdp_msg_encode_buf: a=rtpmap:4 G723/8000\r\n +osmo_sdp_msg_encode_buf: a=rtpmap:8 PCMA/8000\r\n +osmo_sdp_msg_encode_buf: a=rtpmap:101 telephone-event/8000\r\n +osmo_sdp_msg_encode_buf: a=fmtp:101 0-15\r\n +osmo_sdp_msg_encode_buf: a=ptime:20\r\n +osmo_sdp_msg_encode_buf: a=sendonly\r\n +[4] ok +ctx + | 16 test_parse_and_compose + | 15 struct osmo_sdp_msg + | 1 FooBar + | 1 FooBar + | 12 struct osmo_sdp_codec_list + | 3 struct osmo_sdp_codec + | 1 0-15 + | 1 telephone-event + | 2 struct osmo_sdp_codec + | 1 PCMA + | 2 struct osmo_sdp_codec + | 1 G723 + | 2 struct osmo_sdp_codec + | 1 PCMU + | 2 struct osmo_sdp_codec + | 1 G729 +talloc_free(sdp_msg) +ctx + | 1 test_parse_and_compose + + +[5] +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=ptime:20\r\n +sdp input: a=inactive\r\n +osmo_sdp_msg_encode_buf: v=0\r\n +osmo_sdp_msg_encode_buf: o=FooBar 1565090289 1565090290 IN IP4 192.168.11.151\r\n +osmo_sdp_msg_encode_buf: s=FooBar\r\n +osmo_sdp_msg_encode_buf: c=IN IP4 192.168.11.140\r\n +osmo_sdp_msg_encode_buf: t=0 0\r\n +osmo_sdp_msg_encode_buf: m=audio 30436 RTP/AVP 18 0 4 8 101\r\n +osmo_sdp_msg_encode_buf: a=rtpmap:18 G729/8000\r\n +osmo_sdp_msg_encode_buf: a=rtpmap:0 PCMU/8000\r\n +osmo_sdp_msg_encode_buf: a=rtpmap:4 G723/8000\r\n +osmo_sdp_msg_encode_buf: a=rtpmap:8 PCMA/8000\r\n +osmo_sdp_msg_encode_buf: a=rtpmap:101 telephone-event/8000\r\n +osmo_sdp_msg_encode_buf: a=fmtp:101 0-15\r\n +osmo_sdp_msg_encode_buf: a=ptime:20\r\n +osmo_sdp_msg_encode_buf: a=inactive\r\n +[5] ok +ctx + | 16 test_parse_and_compose + | 15 struct osmo_sdp_msg + | 1 FooBar + | 1 FooBar + | 12 struct osmo_sdp_codec_list + | 3 struct osmo_sdp_codec + | 1 0-15 + | 1 telephone-event + | 2 struct osmo_sdp_codec + | 1 PCMA + | 2 struct osmo_sdp_codec + | 1 G723 + | 2 struct osmo_sdp_codec + | 1 PCMU + | 2 struct osmo_sdp_codec + | 1 G729 +talloc_free(sdp_msg) +ctx + | 1 test_parse_and_compose + + + +test_intersect + +[0] identical codecs lead to no change +SDP A: v=0\r\n +SDP A: o=libosmo-sdp 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=libosmo-sdp 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=libosmo-sdp 0 0 IN IP4 0.0.0.0\r\n +parsed SDP B: s=-\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 +intersection(a,b): v=0\r\n +intersection(a,b): o=libosmo-sdp 0 0 IN IP4 23.42.23.42\r\n +intersection(a,b): s=GSM Call\r\n +intersection(a,b): c=IN IP4 23.42.23.42\r\n +intersection(a,b): t=0 0\r\n +intersection(a,b): m=audio 30436 RTP/AVP 112 3 111 110\r\n +intersection(a,b): a=rtpmap:112 AMR/8000\r\n +intersection(a,b): a=fmtp:112 octet-align=1\r\n +intersection(a,b): a=rtpmap:3 GSM/8000\r\n +intersection(a,b): a=rtpmap:111 GSM-HR-08/8000\r\n +intersection(a,b): a=rtpmap:110 GSM-EFR/8000\r\n +intersection(a,b): a=ptime:20\r\n +[0] ok +ctx + | 25 test_intersect + | 11 struct osmo_sdp_msg + | 10 struct osmo_sdp_codec_list + | 2 struct osmo_sdp_codec + | 1 GSM-EFR + | 2 struct osmo_sdp_codec + | 1 GSM-HR-08 + | 2 struct osmo_sdp_codec + | 1 GSM + | 3 struct osmo_sdp_codec + | 1 octet-align=1 + | 1 AMR + | 13 struct osmo_sdp_msg + | 1 GSM Call + | 1 libosmo-sdp + | 10 struct osmo_sdp_codec_list + | 2 struct osmo_sdp_codec + | 1 GSM-EFR + | 2 struct osmo_sdp_codec + | 1 GSM-HR-08 + | 2 struct osmo_sdp_codec + | 1 GSM + | 3 struct osmo_sdp_codec + | 1 octet-align=1 + | 1 AMR +talloc_free(sdp_msg_a) +ctx + | 12 test_intersect + | 11 struct osmo_sdp_msg + | 10 struct osmo_sdp_codec_list + | 2 struct osmo_sdp_codec + | 1 GSM-EFR + | 2 struct osmo_sdp_codec + | 1 GSM-HR-08 + | 2 struct osmo_sdp_codec + | 1 GSM + | 3 struct osmo_sdp_codec + | 1 octet-align=1 + | 1 AMR +talloc_free(sdp_msg_b) +ctx + | 1 test_intersect + + +[1] identical codecs in different order also lead to no change +SDP A: v=0\r\n +SDP A: o=libosmo-sdp 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=libosmo-sdp 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=libosmo-sdp 0 0 IN IP4 0.0.0.0\r\n +parsed SDP B: s=-\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 +intersection(a,b): v=0\r\n +intersection(a,b): o=libosmo-sdp 0 0 IN IP4 23.42.23.42\r\n +intersection(a,b): s=GSM Call\r\n +intersection(a,b): c=IN IP4 23.42.23.42\r\n +intersection(a,b): t=0 0\r\n +intersection(a,b): m=audio 30436 RTP/AVP 112 3 111 110\r\n +intersection(a,b): a=rtpmap:112 AMR/8000\r\n +intersection(a,b): a=fmtp:112 octet-align=1\r\n +intersection(a,b): a=rtpmap:3 GSM/8000\r\n +intersection(a,b): a=rtpmap:111 GSM-HR-08/8000\r\n +intersection(a,b): a=rtpmap:110 GSM-EFR/8000\r\n +intersection(a,b): a=ptime:20\r\n +[1] ok +ctx + | 25 test_intersect + | 11 struct osmo_sdp_msg + | 10 struct osmo_sdp_codec_list + | 3 struct osmo_sdp_codec + | 1 octet-align=1 + | 1 AMR + | 2 struct osmo_sdp_codec + | 1 GSM-HR-08 + | 2 struct osmo_sdp_codec + | 1 GSM-EFR + | 2 struct osmo_sdp_codec + | 1 GSM + | 13 struct osmo_sdp_msg + | 1 GSM Call + | 1 libosmo-sdp + | 10 struct osmo_sdp_codec_list + | 2 struct osmo_sdp_codec + | 1 GSM-EFR + | 2 struct osmo_sdp_codec + | 1 GSM-HR-08 + | 2 struct osmo_sdp_codec + | 1 GSM + | 3 struct osmo_sdp_codec + | 1 octet-align=1 + | 1 AMR +talloc_free(sdp_msg_a) +ctx + | 12 test_intersect + | 11 struct osmo_sdp_msg + | 10 struct osmo_sdp_codec_list + | 3 struct osmo_sdp_codec + | 1 octet-align=1 + | 1 AMR + | 2 struct osmo_sdp_codec + | 1 GSM-HR-08 + | 2 struct osmo_sdp_codec + | 1 GSM-EFR + | 2 struct osmo_sdp_codec + | 1 GSM +talloc_free(sdp_msg_b) +ctx + | 1 test_intersect + + +[2] identical codecs with mismatching payload type numbers also lead to no change +SDP A: v=0\r\n +SDP A: o=libosmo-sdp 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=libosmo-sdp 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=libosmo-sdp 0 0 IN IP4 0.0.0.0\r\n +parsed SDP B: s=-\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 +intersection(a,b): v=0\r\n +intersection(a,b): o=libosmo-sdp 0 0 IN IP4 23.42.23.42\r\n +intersection(a,b): s=GSM Call\r\n +intersection(a,b): c=IN IP4 23.42.23.42\r\n +intersection(a,b): t=0 0\r\n +intersection(a,b): m=audio 30436 RTP/AVP 112 3 111 110\r\n +intersection(a,b): a=rtpmap:112 AMR/8000\r\n +intersection(a,b): a=fmtp:112 octet-align=1\r\n +intersection(a,b): a=rtpmap:3 GSM/8000\r\n +intersection(a,b): a=rtpmap:111 GSM-HR-08/8000\r\n +intersection(a,b): a=rtpmap:110 GSM-EFR/8000\r\n +intersection(a,b): a=ptime:20\r\n +[2] ok +ctx + | 25 test_intersect + | 11 struct osmo_sdp_msg + | 10 struct osmo_sdp_codec_list + | 3 struct osmo_sdp_codec + | 1 octet-align=1 + | 1 AMR + | 2 struct osmo_sdp_codec + | 1 GSM-HR-08 + | 2 struct osmo_sdp_codec + | 1 GSM-EFR + | 2 struct osmo_sdp_codec + | 1 GSM + | 13 struct osmo_sdp_msg + | 1 GSM Call + | 1 libosmo-sdp + | 10 struct osmo_sdp_codec_list + | 2 struct osmo_sdp_codec + | 1 GSM-EFR + | 2 struct osmo_sdp_codec + | 1 GSM-HR-08 + | 2 struct osmo_sdp_codec + | 1 GSM + | 3 struct osmo_sdp_codec + | 1 octet-align=1 + | 1 AMR +talloc_free(sdp_msg_a) +ctx + | 12 test_intersect + | 11 struct osmo_sdp_msg + | 10 struct osmo_sdp_codec_list + | 3 struct osmo_sdp_codec + | 1 octet-align=1 + | 1 AMR + | 2 struct osmo_sdp_codec + | 1 GSM-HR-08 + | 2 struct osmo_sdp_codec + | 1 GSM-EFR + | 2 struct osmo_sdp_codec + | 1 GSM +talloc_free(sdp_msg_b) +ctx + | 1 test_intersect + + +[3] identical codecs plus some extra codecs also lead to no change +SDP A: v=0\r\n +SDP A: o=libosmo-sdp 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=libosmo-sdp 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=libosmo-sdp 0 0 IN IP4 0.0.0.0\r\n +parsed SDP B: s=-\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 +intersection(a,b): v=0\r\n +intersection(a,b): o=libosmo-sdp 0 0 IN IP4 23.42.23.42\r\n +intersection(a,b): s=GSM Call\r\n +intersection(a,b): c=IN IP4 23.42.23.42\r\n +intersection(a,b): t=0 0\r\n +intersection(a,b): m=audio 30436 RTP/AVP 112 3 111 110\r\n +intersection(a,b): a=rtpmap:112 AMR/8000\r\n +intersection(a,b): a=fmtp:112 octet-align=1\r\n +intersection(a,b): a=rtpmap:3 GSM/8000\r\n +intersection(a,b): a=rtpmap:111 GSM-HR-08/8000\r\n +intersection(a,b): a=rtpmap:110 GSM-EFR/8000\r\n +intersection(a,b): a=ptime:20\r\n +[3] ok +ctx + | 29 test_intersect + | 15 struct osmo_sdp_msg + | 14 struct osmo_sdp_codec_list + | 3 struct osmo_sdp_codec + | 1 octet-align=1 + | 1 AMR + | 2 struct osmo_sdp_codec + | 1 GSM-HR-08 + | 2 struct osmo_sdp_codec + | 1 GSM-EFR + | 2 struct osmo_sdp_codec + | 1 GSM + | 2 struct osmo_sdp_codec + | 1 PCMU + | 2 struct osmo_sdp_codec + | 1 PCMA + | 13 struct osmo_sdp_msg + | 1 GSM Call + | 1 libosmo-sdp + | 10 struct osmo_sdp_codec_list + | 2 struct osmo_sdp_codec + | 1 GSM-EFR + | 2 struct osmo_sdp_codec + | 1 GSM-HR-08 + | 2 struct osmo_sdp_codec + | 1 GSM + | 3 struct osmo_sdp_codec + | 1 octet-align=1 + | 1 AMR +talloc_free(sdp_msg_a) +ctx + | 16 test_intersect + | 15 struct osmo_sdp_msg + | 14 struct osmo_sdp_codec_list + | 3 struct osmo_sdp_codec + | 1 octet-align=1 + | 1 AMR + | 2 struct osmo_sdp_codec + | 1 GSM-HR-08 + | 2 struct osmo_sdp_codec + | 1 GSM-EFR + | 2 struct osmo_sdp_codec + | 1 GSM + | 2 struct osmo_sdp_codec + | 1 PCMU + | 2 struct osmo_sdp_codec + | 1 PCMA +talloc_free(sdp_msg_b) +ctx + | 1 test_intersect + + +[4] some codecs removed +SDP A: v=0\r\n +SDP A: o=libosmo-sdp 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=libosmo-sdp 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=libosmo-sdp 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=libosmo-sdp 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 +intersection(a,b): v=0\r\n +intersection(a,b): o=libosmo-sdp 0 0 IN IP4 23.42.23.42\r\n +intersection(a,b): s=GSM Call\r\n +intersection(a,b): c=IN IP4 23.42.23.42\r\n +intersection(a,b): t=0 0\r\n +intersection(a,b): m=audio 30436 RTP/AVP 112 110\r\n +intersection(a,b): a=rtpmap:112 AMR/8000\r\n +intersection(a,b): a=fmtp:112 octet-align=1\r\n +intersection(a,b): a=rtpmap:110 GSM-EFR/8000\r\n +intersection(a,b): a=ptime:20\r\n +[4] ok +ctx + | 19 test_intersect + | 9 struct osmo_sdp_msg + | 1 GSM Call + | 1 libosmo-sdp + | 6 struct osmo_sdp_codec_list + | 2 struct osmo_sdp_codec + | 1 GSM-EFR + | 3 struct osmo_sdp_codec + | 1 octet-align=1 + | 1 AMR + | 9 struct osmo_sdp_msg + | 1 GSM Call + | 1 libosmo-sdp + | 6 struct osmo_sdp_codec_list + | 2 struct osmo_sdp_codec + | 1 GSM-EFR + | 3 struct osmo_sdp_codec + | 1 octet-align=1 + | 1 AMR +talloc_free(sdp_msg_a) +ctx + | 10 test_intersect + | 9 struct osmo_sdp_msg + | 1 GSM Call + | 1 libosmo-sdp + | 6 struct osmo_sdp_codec_list + | 2 struct osmo_sdp_codec + | 1 GSM-EFR + | 3 struct osmo_sdp_codec + | 1 octet-align=1 + | 1 AMR +talloc_free(sdp_msg_b) +ctx + | 1 test_intersect + + +[5] other codecs removed +SDP A: v=0\r\n +SDP A: o=libosmo-sdp 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=libosmo-sdp 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 123\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:123 FOO/8000\r\n + SDP B: a=ptime:20\r\n +parsed SDP A: v=0\r\n +parsed SDP A: o=libosmo-sdp 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=libosmo-sdp 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 123\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:123 FOO/8000\r\n +parsed SDP B: a=ptime:20\r\n +intersection(a,b): v=0\r\n +intersection(a,b): o=libosmo-sdp 0 0 IN IP4 23.42.23.42\r\n +intersection(a,b): s=GSM Call\r\n +intersection(a,b): c=IN IP4 23.42.23.42\r\n +intersection(a,b): t=0 0\r\n +intersection(a,b): m=audio 30436 RTP/AVP 3 111\r\n +intersection(a,b): a=rtpmap:3 GSM/8000\r\n +intersection(a,b): a=rtpmap:111 GSM-HR-08/8000\r\n +intersection(a,b): a=ptime:20\r\n +[5] ok +ctx + | 19 test_intersect + | 10 struct osmo_sdp_msg + | 1 GSM Call + | 1 libosmo-sdp + | 7 struct osmo_sdp_codec_list + | 2 struct osmo_sdp_codec + | 1 FOO + | 2 struct osmo_sdp_codec + | 1 GSM-HR-08 + | 2 struct osmo_sdp_codec + | 1 GSM + | 8 struct osmo_sdp_msg + | 1 GSM Call + | 1 libosmo-sdp + | 5 struct osmo_sdp_codec_list + | 2 struct osmo_sdp_codec + | 1 GSM-HR-08 + | 2 struct osmo_sdp_codec + | 1 GSM +talloc_free(sdp_msg_a) +ctx + | 11 test_intersect + | 10 struct osmo_sdp_msg + | 1 GSM Call + | 1 libosmo-sdp + | 7 struct osmo_sdp_codec_list + | 2 struct osmo_sdp_codec + | 1 FOO + | 2 struct osmo_sdp_codec + | 1 GSM-HR-08 + | 2 struct osmo_sdp_codec + | 1 GSM +talloc_free(sdp_msg_b) +ctx + | 1 test_intersect + + +[6] all codecs removed +SDP A: v=0\r\n +SDP A: o=libosmo-sdp 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=libosmo-sdp 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=libosmo-sdp 0 0 IN IP4 0.0.0.0\r\n +parsed SDP B: s=empty\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 +intersection(a,b): v=0\r\n +intersection(a,b): o=libosmo-sdp 0 0 IN IP4 23.42.23.42\r\n +intersection(a,b): s=GSM Call\r\n +intersection(a,b): c=IN IP4 23.42.23.42\r\n +intersection(a,b): t=0 0\r\n +intersection(a,b): m=audio 30436 RTP/AVP\r\n +intersection(a,b): a=ptime:20\r\n +[6] ok +ctx + | 8 test_intersect + | 3 struct osmo_sdp_msg + | 1 empty + | 1 struct osmo_sdp_codec_list + | 4 struct osmo_sdp_msg + | 1 GSM Call + | 1 libosmo-sdp + | 1 struct osmo_sdp_codec_list +talloc_free(sdp_msg_a) +ctx + | 4 test_intersect + | 3 struct osmo_sdp_msg + | 1 empty + | 1 struct osmo_sdp_codec_list +talloc_free(sdp_msg_b) +ctx + | 1 test_intersect + + +[7] some real world test case +SDP A: v=0\r\n +SDP A: o=libosmo-sdp 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=libosmo-sdp 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=libosmo-sdp 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=libosmo-sdp 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 +intersection(a,b): v=0\r\n +intersection(a,b): o=libosmo-sdp 0 0 IN IP4 0.0.0.0\r\n +intersection(a,b): s=GSM Call\r\n +intersection(a,b): c=IN IP4 0.0.0.0\r\n +intersection(a,b): t=0 0\r\n +intersection(a,b): m=audio 0 RTP/AVP 112 113 110 3 111\r\n +intersection(a,b): a=rtpmap:112 AMR/8000\r\n +intersection(a,b): a=fmtp:112 octet-align=1;mode-set=0,1,2,3\r\n +intersection(a,b): a=rtpmap:113 AMR-WB/8000\r\n +intersection(a,b): a=fmtp:113 octet-align=1\r\n +intersection(a,b): a=rtpmap:110 GSM-EFR/8000\r\n +intersection(a,b): a=rtpmap:3 GSM/8000\r\n +intersection(a,b): a=rtpmap:111 GSM-HR-08/8000\r\n +intersection(a,b): a=ptime:20\r\n +[7] ok +ctx + | 33 test_intersect + | 16 struct osmo_sdp_msg + | 1 GSM Call + | 1 libosmo-sdp + | 13 struct osmo_sdp_codec_list + | 2 struct osmo_sdp_codec + | 1 GSM-HR-08 + | 2 struct osmo_sdp_codec + | 1 GSM + | 2 struct osmo_sdp_codec + | 1 GSM-EFR + | 3 struct osmo_sdp_codec + | 1 octet-align=1 + | 1 AMR-WB + | 3 struct osmo_sdp_codec + | 1 octet-align=1;mode-set=0,1,2,3 + | 1 AMR + | 16 struct osmo_sdp_msg + | 1 GSM Call + | 1 libosmo-sdp + | 13 struct osmo_sdp_codec_list + | 2 struct osmo_sdp_codec + | 1 GSM-HR-08 + | 2 struct osmo_sdp_codec + | 1 GSM + | 2 struct osmo_sdp_codec + | 1 GSM-EFR + | 3 struct osmo_sdp_codec + | 1 octet-align=1 + | 1 AMR-WB + | 3 struct osmo_sdp_codec + | 1 octet-align=1;mode-set=0,1,2,3 + | 1 AMR +talloc_free(sdp_msg_a) +ctx + | 17 test_intersect + | 16 struct osmo_sdp_msg + | 1 GSM Call + | 1 libosmo-sdp + | 13 struct osmo_sdp_codec_list + | 2 struct osmo_sdp_codec + | 1 GSM-HR-08 + | 2 struct osmo_sdp_codec + | 1 GSM + | 2 struct osmo_sdp_codec + | 1 GSM-EFR + | 3 struct osmo_sdp_codec + | 1 octet-align=1 + | 1 AMR-WB + | 3 struct osmo_sdp_codec + | 1 octet-align=1;mode-set=0,1,2,3 + | 1 AMR +talloc_free(sdp_msg_b) +ctx + | 1 test_intersect + + + +test_select + +[0] +SDP: AMR:octet-align=1#112 GSM#3 GSM-HR-08#111 GSM-EFR#110 +Select: /0#112 +SDP: AMR:octet-align=1#112 GSM#3 GSM-HR-08#111 GSM-EFR#110 +[0] ok +ctx + | 14 test_select + | 13 struct osmo_sdp_msg + | 1 GSM Call + | 1 libosmo-sdp + | 10 struct osmo_sdp_codec_list + | 2 struct osmo_sdp_codec + | 1 GSM-EFR + | 2 struct osmo_sdp_codec + | 1 GSM-HR-08 + | 2 struct osmo_sdp_codec + | 1 GSM + | 3 struct osmo_sdp_codec + | 1 octet-align=1 + | 1 AMR +talloc_free(sdp_msg) +ctx + | 1 test_select + + +[1] +SDP: AMR:octet-align=1#112 GSM#3 GSM-HR-08#111 GSM-EFR#110 +Select: /0#3 +SDP: GSM#3 AMR:octet-align=1#112 GSM-HR-08#111 GSM-EFR#110 +[1] ok +ctx + | 14 test_select + | 13 struct osmo_sdp_msg + | 1 GSM Call + | 1 libosmo-sdp + | 10 struct osmo_sdp_codec_list + | 2 struct osmo_sdp_codec + | 1 GSM-EFR + | 2 struct osmo_sdp_codec + | 1 GSM-HR-08 + | 2 struct osmo_sdp_codec + | 1 GSM + | 3 struct osmo_sdp_codec + | 1 octet-align=1 + | 1 AMR +talloc_free(sdp_msg) +ctx + | 1 test_select + + +[2] +SDP: AMR:octet-align=1#112 GSM#3 GSM-HR-08#111 GSM-EFR#110 +Select: /0#111 +SDP: GSM-HR-08#111 AMR:octet-align=1#112 GSM#3 GSM-EFR#110 +[2] ok +ctx + | 14 test_select + | 13 struct osmo_sdp_msg + | 1 GSM Call + | 1 libosmo-sdp + | 10 struct osmo_sdp_codec_list + | 2 struct osmo_sdp_codec + | 1 GSM-EFR + | 2 struct osmo_sdp_codec + | 1 GSM-HR-08 + | 2 struct osmo_sdp_codec + | 1 GSM + | 3 struct osmo_sdp_codec + | 1 octet-align=1 + | 1 AMR +talloc_free(sdp_msg) +ctx + | 1 test_select + + +[3] +SDP: AMR:octet-align=1#112 GSM#3 GSM-HR-08#111 GSM-EFR#110 +Select: /0#110 +SDP: GSM-EFR#110 AMR:octet-align=1#112 GSM#3 GSM-HR-08#111 +[3] ok +ctx + | 14 test_select + | 13 struct osmo_sdp_msg + | 1 GSM Call + | 1 libosmo-sdp + | 10 struct osmo_sdp_codec_list + | 2 struct osmo_sdp_codec + | 1 GSM-EFR + | 2 struct osmo_sdp_codec + | 1 GSM-HR-08 + | 2 struct osmo_sdp_codec + | 1 GSM + | 3 struct osmo_sdp_codec + | 1 octet-align=1 + | 1 AMR +talloc_free(sdp_msg) +ctx + | 1 test_select + + + +--- test_obj_members() +o->sdp_msg = 'v=0 +o=libosmo-sdp 0 0 IN IP4 0.0.0.0 +s=- +c=IN IP4 0.0.0.0 +t=0 0 +m=audio 0 RTP/AVP +' +ctx + | 4 test_obj_members + | 3 struct my_obj + | 2 struct osmo_sdp_msg + | 1 struct osmo_sdp_codec_list +o->sdp_msg = 'v=0 +o=libosmo-sdp 0 0 IN IP4 0.0.0.0 +s=- +c=IN IP4 0.0.0.0 +t=0 0 +m=audio 0 RTP/AVP 112 3 111 +a=rtpmap:112 AMR/8000 +a=fmtp:112 octet-align=1;mode-set=0,2,4 +a=rtpmap:3 GSM/8000 +a=rtpmap:111 GSM-HR-08/8000 +' +ctx + | 11 test_obj_members + | 10 struct my_obj + | 9 struct osmo_sdp_msg + | 8 struct osmo_sdp_codec_list + | 2 struct osmo_sdp_codec + | 1 GSM-HR-08 + | 2 struct osmo_sdp_codec + | 1 GSM + | 3 struct osmo_sdp_codec + | 1 octet-align=1;mode-set=0,2,4 + | 1 AMR +talloc_free(o) +ctx + | 1 test_obj_members diff --git a/tests/testsuite.at b/tests/testsuite.at index d5512d478..55340001c 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -27,3 +27,10 @@ cat $abs_srcdir/sdp/sdp_codec_test.ok > expout cat $abs_srcdir/sdp/sdp_codec_test.err > experr AT_CHECK([$abs_top_builddir/tests/sdp/sdp_codec_test], [], [expout], [experr]) AT_CLEANUP + +AT_SETUP([sdp_msg]) +AT_KEYWORDS([sdp_msg]) +cat $abs_srcdir/sdp/sdp_msg_test.ok > expout +cat $abs_srcdir/sdp/sdp_msg_test.err > experr +AT_CHECK([$abs_top_builddir/tests/sdp/sdp_msg_test], [], [expout], [experr]) +AT_CLEANUP