aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc/src/libmgcp/mgcp_sdp.c
diff options
context:
space:
mode:
Diffstat (limited to 'openbsc/src/libmgcp/mgcp_sdp.c')
-rw-r--r--openbsc/src/libmgcp/mgcp_sdp.c136
1 files changed, 108 insertions, 28 deletions
diff --git a/openbsc/src/libmgcp/mgcp_sdp.c b/openbsc/src/libmgcp/mgcp_sdp.c
index a10b3ac02..dc8708934 100644
--- a/openbsc/src/libmgcp/mgcp_sdp.c
+++ b/openbsc/src/libmgcp/mgcp_sdp.c
@@ -25,6 +25,18 @@
#include <errno.h>
+struct sdp_rtp_map {
+ /* the type */
+ int payload_type;
+ /* null, static or later dynamic codec name */
+ char *codec_name;
+ /* A pointer to the original line for later parsing */
+ char *map_line;
+
+ int rate;
+ int channels;
+};
+
int mgcp_set_audio_info(void *ctx, struct mgcp_rtp_codec *codec,
int payload_type, const char *audio_name)
{
@@ -91,14 +103,69 @@ int mgcp_set_audio_info(void *ctx, struct mgcp_rtp_codec *codec,
return 0;
}
+void codecs_initialize(void *ctx, struct sdp_rtp_map *codecs, int used)
+{
+ int i;
+
+ for (i = 0; i < used; ++i) {
+ switch (codecs[i].payload_type) {
+ case 3:
+ codecs[i].codec_name = "GSM";
+ codecs[i].rate = 8000;
+ codecs[i].channels = 1;
+ break;
+ case 8:
+ codecs[i].codec_name = "PCMA";
+ codecs[i].rate = 8000;
+ codecs[i].channels = 1;
+ break;
+ case 18:
+ codecs[i].codec_name = "G729";
+ codecs[i].rate = 8000;
+ codecs[i].channels = 1;
+ break;
+ }
+ }
+}
+
+void codecs_update(void *ctx, struct sdp_rtp_map *codecs, int used, int payload, char *audio_name)
+{
+ int i;
+
+ for (i = 0; i < used; ++i) {
+ char audio_codec[64];
+ int rate = -1;
+ int channels = -1;
+ if (codecs[i].payload_type != payload)
+ continue;
+ if (sscanf(audio_name, "%63[^/]/%d/%d",
+ audio_codec, &rate, &channels) < 1) {
+ LOGP(DMGCP, LOGL_ERROR, "Failed to parse '%s'\n", audio_name);
+ continue;
+ }
+
+ codecs[i].map_line = talloc_strdup(ctx, audio_name);
+ codecs[i].codec_name = talloc_strdup(ctx, audio_codec);
+ codecs[i].rate = rate;
+ codecs[i].channels = channels;
+ return;
+ }
+
+ LOGP(DMGCP, LOGL_ERROR, "Unconfigured PT(%d) with %s\n", payload, audio_name);
+}
+
int mgcp_parse_sdp_data(struct mgcp_rtp_end *rtp, struct mgcp_parse_data *p)
{
+ struct sdp_rtp_map codecs[10];
+ int codecs_used = 0;
char *line;
- int found_media = 0;
- /* TODO/XXX make it more generic */
- int audio_payload = -1;
- int audio_payload_alt = -1;
+ int maxptime = -1;
+ int i;
+ int codecs_assigned = 0;
+ void *tmp_ctx = talloc_new(NULL);
+
+ memset(&codecs, 0, sizeof(codecs));
for_each_line(line, p->save) {
switch (line[0]) {
@@ -113,17 +180,10 @@ int mgcp_parse_sdp_data(struct mgcp_rtp_end *rtp, struct mgcp_parse_data *p)
int ptime, ptime2 = 0;
char audio_name[64];
- if (audio_payload == -1)
- break;
if (sscanf(line, "a=rtpmap:%d %63s",
&payload, audio_name) == 2) {
- if (payload == audio_payload)
- mgcp_set_audio_info(p->cfg, &rtp->codec,
- payload, audio_name);
- else if (payload == audio_payload_alt)
- mgcp_set_audio_info(p->cfg, &rtp->alt_codec,
- payload, audio_name);
+ codecs_update(tmp_ctx, codecs, codecs_used, payload, audio_name);
} else if (sscanf(line, "a=ptime:%d-%d",
&ptime, &ptime2) >= 1) {
if (ptime2 > 0 && ptime2 != ptime)
@@ -131,29 +191,30 @@ int mgcp_parse_sdp_data(struct mgcp_rtp_end *rtp, struct mgcp_parse_data *p)
else
rtp->packet_duration_ms = ptime;
} else if (sscanf(line, "a=maxptime:%d", &ptime2) == 1) {
- /* TODO/XXX: Store this per codec and derive it on use */
- if (ptime2 * rtp->codec.frame_duration_den >
- rtp->codec.frame_duration_num * 1500)
- /* more than 1 frame */
- rtp->packet_duration_ms = 0;
+ maxptime = ptime2;
}
break;
}
case 'm': {
int port, rc;
- audio_payload = -1;
- audio_payload_alt = -1;
- rc = sscanf(line, "m=audio %d RTP/AVP %d %d",
- &port, &audio_payload, &audio_payload_alt);
+ rc = sscanf(line, "m=audio %d RTP/AVP %d %d %d %d %d %d %d %d %d %d",
+ &port,
+ &codecs[0].payload_type,
+ &codecs[1].payload_type,
+ &codecs[2].payload_type,
+ &codecs[3].payload_type,
+ &codecs[4].payload_type,
+ &codecs[5].payload_type,
+ &codecs[6].payload_type,
+ &codecs[7].payload_type,
+ &codecs[8].payload_type,
+ &codecs[9].payload_type);
if (rc >= 2) {
rtp->rtp_port = htons(port);
rtp->rtcp_port = htons(port + 1);
- found_media = 1;
- mgcp_set_audio_info(p->cfg, &rtp->codec, audio_payload, NULL);
- if (rc == 3)
- mgcp_set_audio_info(p->cfg, &rtp->alt_codec,
- audio_payload_alt, NULL);
+ codecs_used = rc - 1;
+ codecs_initialize(tmp_ctx, codecs, codecs_used);
}
break;
}
@@ -178,14 +239,33 @@ int mgcp_parse_sdp_data(struct mgcp_rtp_end *rtp, struct mgcp_parse_data *p)
}
}
- if (found_media)
+ /* Now select the primary and alt_codec */
+ for (i = 0; i < codecs_used && codecs_assigned < 2; ++i) {
+ struct mgcp_rtp_codec *codec = codecs_assigned == 0 ?
+ &rtp->codec : &rtp->alt_codec;
+ mgcp_set_audio_info(p->cfg, codec,
+ codecs[i].payload_type,
+ codecs[i].map_line);
+ codecs_assigned += 1;
+ }
+
+ if (codecs_assigned > 0) {
+ /* TODO/XXX: Store this per codec and derive it on use */
+ if (maxptime >= 0 && maxptime * rtp->codec.frame_duration_den >
+ rtp->codec.frame_duration_num * 1500) {
+ /* more than 1 frame */
+ rtp->packet_duration_ms = 0;
+ }
+
LOGP(DMGCP, LOGL_NOTICE,
"Got media info via SDP: port %d, payload %d (%s), "
"duration %d, addr %s\n",
ntohs(rtp->rtp_port), rtp->codec.payload_type,
rtp->codec.subtype_name ? rtp->codec.subtype_name : "unknown",
rtp->packet_duration_ms, inet_ntoa(rtp->addr));
+ }
- return found_media;
+ talloc_free(tmp_ctx);
+ return codecs_assigned > 0;
}