blob: a10b3ac02ee2bffd51173dab55a82304d4a36eb9 [file] [log] [blame]
Holger Hans Peter Freythera611da82015-08-14 09:24:11 +02001/*
2 * Some SDP file parsing...
3 *
4 * (C) 2009-2015 by Holger Hans Peter Freyther <zecke@selfish.org>
5 * (C) 2009-2014 by On-Waves
6 * All Rights Reserved
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Affero General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Affero General Public License for more details.
17 *
18 * You should have received a copy of the GNU Affero General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 *
21 */
22
23#include <openbsc/mgcp.h>
24#include <openbsc/mgcp_internal.h>
25
26#include <errno.h>
27
28int mgcp_set_audio_info(void *ctx, struct mgcp_rtp_codec *codec,
29 int payload_type, const char *audio_name)
30{
31 int rate = codec->rate;
32 int channels = codec->channels;
33 char audio_codec[64];
34
35 talloc_free(codec->subtype_name);
36 codec->subtype_name = NULL;
37 talloc_free(codec->audio_name);
38 codec->audio_name = NULL;
39
40 if (payload_type != PTYPE_UNDEFINED)
41 codec->payload_type = payload_type;
42
43 if (!audio_name) {
44 switch (payload_type) {
45 case 3: audio_name = "GSM/8000/1"; break;
46 case 8: audio_name = "PCMA/8000/1"; break;
47 case 18: audio_name = "G729/8000/1"; break;
48 default:
49 /* Payload type is unknown, don't change rate and
50 * channels. */
51 /* TODO: return value? */
52 return 0;
53 }
54 }
55
56 if (sscanf(audio_name, "%63[^/]/%d/%d",
57 audio_codec, &rate, &channels) < 1)
58 return -EINVAL;
59
60 codec->rate = rate;
61 codec->channels = channels;
62 codec->subtype_name = talloc_strdup(ctx, audio_codec);
63 codec->audio_name = talloc_strdup(ctx, audio_name);
64
65 if (!strcmp(audio_codec, "G729")) {
66 codec->frame_duration_num = 10;
67 codec->frame_duration_den = 1000;
68 } else {
69 codec->frame_duration_num = DEFAULT_RTP_AUDIO_FRAME_DUR_NUM;
70 codec->frame_duration_den = DEFAULT_RTP_AUDIO_FRAME_DUR_DEN;
71 }
72
73 if (payload_type < 0) {
74 payload_type = 96;
75 if (rate == 8000 && channels == 1) {
76 if (!strcmp(audio_codec, "GSM"))
77 payload_type = 3;
78 else if (!strcmp(audio_codec, "PCMA"))
79 payload_type = 8;
80 else if (!strcmp(audio_codec, "G729"))
81 payload_type = 18;
82 }
83
84 codec->payload_type = payload_type;
85 }
86
87 if (channels != 1)
88 LOGP(DMGCP, LOGL_NOTICE,
89 "Channels != 1 in SDP: '%s'\n", audio_name);
90
91 return 0;
92}
93
94
95int mgcp_parse_sdp_data(struct mgcp_rtp_end *rtp, struct mgcp_parse_data *p)
96{
97 char *line;
98 int found_media = 0;
99 /* TODO/XXX make it more generic */
100 int audio_payload = -1;
101 int audio_payload_alt = -1;
102
103 for_each_line(line, p->save) {
104 switch (line[0]) {
105 case 'o':
106 case 's':
107 case 't':
108 case 'v':
109 /* skip these SDP attributes */
110 break;
111 case 'a': {
112 int payload;
113 int ptime, ptime2 = 0;
114 char audio_name[64];
115
116 if (audio_payload == -1)
117 break;
118
119 if (sscanf(line, "a=rtpmap:%d %63s",
120 &payload, audio_name) == 2) {
121 if (payload == audio_payload)
122 mgcp_set_audio_info(p->cfg, &rtp->codec,
123 payload, audio_name);
124 else if (payload == audio_payload_alt)
125 mgcp_set_audio_info(p->cfg, &rtp->alt_codec,
126 payload, audio_name);
127 } else if (sscanf(line, "a=ptime:%d-%d",
128 &ptime, &ptime2) >= 1) {
129 if (ptime2 > 0 && ptime2 != ptime)
130 rtp->packet_duration_ms = 0;
131 else
132 rtp->packet_duration_ms = ptime;
133 } else if (sscanf(line, "a=maxptime:%d", &ptime2) == 1) {
134 /* TODO/XXX: Store this per codec and derive it on use */
135 if (ptime2 * rtp->codec.frame_duration_den >
136 rtp->codec.frame_duration_num * 1500)
137 /* more than 1 frame */
138 rtp->packet_duration_ms = 0;
139 }
140 break;
141 }
142 case 'm': {
143 int port, rc;
144 audio_payload = -1;
145 audio_payload_alt = -1;
146
147 rc = sscanf(line, "m=audio %d RTP/AVP %d %d",
148 &port, &audio_payload, &audio_payload_alt);
149 if (rc >= 2) {
150 rtp->rtp_port = htons(port);
151 rtp->rtcp_port = htons(port + 1);
152 found_media = 1;
153 mgcp_set_audio_info(p->cfg, &rtp->codec, audio_payload, NULL);
154 if (rc == 3)
155 mgcp_set_audio_info(p->cfg, &rtp->alt_codec,
156 audio_payload_alt, NULL);
157 }
158 break;
159 }
160 case 'c': {
161 char ipv4[16];
162
163 if (sscanf(line, "c=IN IP4 %15s", ipv4) == 1) {
164 inet_aton(ipv4, &rtp->addr);
165 }
166 break;
167 }
168 default:
169 if (p->endp)
170 LOGP(DMGCP, LOGL_NOTICE,
171 "Unhandled SDP option: '%c'/%d on 0x%x\n",
172 line[0], line[0], ENDPOINT_NUMBER(p->endp));
173 else
174 LOGP(DMGCP, LOGL_NOTICE,
175 "Unhandled SDP option: '%c'/%d\n",
176 line[0], line[0]);
177 break;
178 }
179 }
180
181 if (found_media)
182 LOGP(DMGCP, LOGL_NOTICE,
183 "Got media info via SDP: port %d, payload %d (%s), "
184 "duration %d, addr %s\n",
185 ntohs(rtp->rtp_port), rtp->codec.payload_type,
186 rtp->codec.subtype_name ? rtp->codec.subtype_name : "unknown",
187 rtp->packet_duration_ms, inet_ntoa(rtp->addr));
188
189 return found_media;
190}
191