blob: 01e79688f69f7bd11be7fec9a6d0b26181541d39 [file] [log] [blame]
Neels Hofmeyrf83ec562017-09-07 19:18:40 +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
Philipp Maier8970c492017-10-11 13:33:42 +020023#include <osmocom/core/msgb.h>
Philipp Maier87bd9be2017-08-22 16:35:41 +020024#include <osmocom/mgcp/mgcp.h>
25#include <osmocom/mgcp/mgcp_internal.h>
26#include <osmocom/mgcp/mgcp_msg.h>
Philipp Maier37d11c82018-02-01 14:38:12 +010027#include <osmocom/mgcp/mgcp_endp.h>
Philipp Maierbc0346e2018-06-07 09:52:16 +020028#include <osmocom/mgcp/mgcp_codec.h>
Philipp Maier7e37ce62019-03-05 14:00:11 +010029#include <osmocom/mgcp/mgcp_sdp.h>
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020030
31#include <errno.h>
Pau Espin Pedrolc5c14302019-07-23 16:19:41 +020032#include <stdlib.h>
33#include <limits.h>
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020034
Philipp Maier228e5912019-03-05 13:56:59 +010035/* Two structs to store intermediate parsing results. The function
36 * mgcp_parse_sdp_data() is using the following two structs as temporary
37 * storage for parsing the SDP codec information. */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020038struct sdp_rtp_map {
39 /* the type */
40 int payload_type;
41 /* null, static or later dynamic codec name */
42 char *codec_name;
43 /* A pointer to the original line for later parsing */
44 char *map_line;
45
46 int rate;
47 int channels;
48};
Philipp Maier228e5912019-03-05 13:56:59 +010049struct sdp_fmtp_param {
50 int payload_type;
51 struct mgcp_codec_param param;
52};
53
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020054
Philipp Maierbc0346e2018-06-07 09:52:16 +020055/* Helper function to extrapolate missing codec parameters in a codec mao from
56 * an already filled in payload_type, called from: mgcp_parse_sdp_data() */
Philipp Maier8970c492017-10-11 13:33:42 +020057static void codecs_initialize(void *ctx, struct sdp_rtp_map *codecs, int used)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020058{
59 int i;
60
61 for (i = 0; i < used; ++i) {
62 switch (codecs[i].payload_type) {
63 case 0:
64 codecs[i].codec_name = "PCMU";
65 codecs[i].rate = 8000;
66 codecs[i].channels = 1;
67 break;
68 case 3:
69 codecs[i].codec_name = "GSM";
70 codecs[i].rate = 8000;
71 codecs[i].channels = 1;
72 break;
73 case 8:
74 codecs[i].codec_name = "PCMA";
75 codecs[i].rate = 8000;
76 codecs[i].channels = 1;
77 break;
78 case 18:
79 codecs[i].codec_name = "G729";
80 codecs[i].rate = 8000;
81 codecs[i].channels = 1;
82 break;
Philipp Maierbc0346e2018-06-07 09:52:16 +020083 default:
84 codecs[i].codec_name = NULL;
85 codecs[i].rate = 0;
86 codecs[i].channels = 0;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020087 }
88 }
89}
90
Philipp Maierbc0346e2018-06-07 09:52:16 +020091/* Helper function to update codec map information with additional data from
92 * SDP, called from: mgcp_parse_sdp_data() */
Philipp Maier8970c492017-10-11 13:33:42 +020093static void codecs_update(void *ctx, struct sdp_rtp_map *codecs, int used,
94 int payload, const char *audio_name)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020095{
96 int i;
97
98 for (i = 0; i < used; ++i) {
99 char audio_codec[64];
100 int rate = -1;
101 int channels = -1;
Philipp Maierbc0346e2018-06-07 09:52:16 +0200102
103 /* Note: We can only update payload codecs that already exist
104 * in our codec list. If we get an unexpected payload type,
105 * we just drop it */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200106 if (codecs[i].payload_type != payload)
107 continue;
Philipp Maierbc0346e2018-06-07 09:52:16 +0200108
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200109 if (sscanf(audio_name, "%63[^/]/%d/%d",
Philipp Maierd8d7b4b2017-10-18 11:45:35 +0200110 audio_codec, &rate, &channels) < 1) {
111 LOGP(DLMGCP, LOGL_ERROR, "Failed to parse '%s'\n",
112 audio_name);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200113 continue;
114 }
115
116 codecs[i].map_line = talloc_strdup(ctx, audio_name);
117 codecs[i].codec_name = talloc_strdup(ctx, audio_codec);
118 codecs[i].rate = rate;
119 codecs[i].channels = channels;
120 return;
121 }
122
Philipp Maierd8d7b4b2017-10-18 11:45:35 +0200123 LOGP(DLMGCP, LOGL_ERROR, "Unconfigured PT(%d) with %s\n", payload,
124 audio_name);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200125}
126
Philipp Maierbc0346e2018-06-07 09:52:16 +0200127/* Extract payload types from SDP, also check for duplicates */
128static int pt_from_sdp(void *ctx, struct sdp_rtp_map *codecs,
129 unsigned int codecs_len, char *sdp)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200130{
Philipp Maierbc0346e2018-06-07 09:52:16 +0200131 char *str;
132 char *str_ptr;
133 char *pt_str;
Pau Espin Pedrolc5c14302019-07-23 16:19:41 +0200134 char *pt_end;
Pau Espin Pedrola2b1c5e2019-07-26 14:13:14 +0200135 unsigned long int pt;
Philipp Maierbc0346e2018-06-07 09:52:16 +0200136 unsigned int count = 0;
137 unsigned int i;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200138
Philipp Maierbc0346e2018-06-07 09:52:16 +0200139 str = talloc_zero_size(ctx, strlen(sdp) + 1);
140 str_ptr = str;
141 strcpy(str_ptr, sdp);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200142
Philipp Maierbc0346e2018-06-07 09:52:16 +0200143 str_ptr = strstr(str_ptr, "RTP/AVP ");
144 if (!str_ptr)
145 goto exit;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200146
Philipp Maierbc0346e2018-06-07 09:52:16 +0200147 pt_str = strtok(str_ptr, " ");
148 if (!pt_str)
149 goto exit;
150
151 while (1) {
152 /* Do not allow excessive payload types */
153 if (count > codecs_len)
154 goto error;
155
156 pt_str = strtok(NULL, " ");
157 if (!pt_str)
158 break;
159
Pau Espin Pedrolc5c14302019-07-23 16:19:41 +0200160 errno = 0;
161 pt = strtoul(pt_str, &pt_end, 0);
162 if ((errno == ERANGE && pt == ULONG_MAX) || (errno && !pt) ||
163 pt_str == pt_end)
164 goto error;
Philipp Maierbc0346e2018-06-07 09:52:16 +0200165
Pau Espin Pedrola2b1c5e2019-07-26 14:13:14 +0200166 if (pt >> 7) /* PT is 7 bit field, higher values not allowed */
167 goto error;
168
Philipp Maierbc0346e2018-06-07 09:52:16 +0200169 /* Do not allow duplicate payload types */
170 for (i = 0; i < count; i++)
171 if (codecs[i].payload_type == pt)
172 goto error;
173
174 codecs[count].payload_type = pt;
175 count++;
176 }
177
178exit:
179 talloc_free(str);
180 return count;
181error:
182 talloc_free(str);
183 return -EINVAL;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200184}
185
Philipp Maier228e5912019-03-05 13:56:59 +0100186/* Extract fmtp parameters from SDP, called from: mgcp_parse_sdp_data() */
187static int fmtp_from_sdp(void *ctx, struct sdp_fmtp_param *fmtp_param, char *sdp)
188{
189 char *str;
190 char *str_ptr;
191 char *param_str;
192 unsigned int pt;
193 unsigned int count = 0;
194 char delimiter;
195 unsigned int amr_octet_aligned;
196
197 memset(fmtp_param, 0, sizeof(*fmtp_param));
198
199 str = talloc_zero_size(ctx, strlen(sdp) + 1);
200 str_ptr = str;
201 strcpy(str_ptr, sdp);
202
203 /* Check if the input string begins with an fmtp token */
204 str_ptr = strstr(str_ptr, "fmtp:");
205 if (!str_ptr)
206 goto exit;
207 str_ptr += 5;
208
209 /* Extract payload type */
210 if (sscanf(str_ptr, "%u ", &pt) != 1)
211 goto error;
212 fmtp_param->payload_type = pt;
213
214 /* Advance pointer to the beginning of the parameter section and
215 * tokenize string */
216 str_ptr = strstr(str_ptr, " ");
217 if (!str_ptr)
218 goto error;
219 str_ptr++;
220
221 param_str = strtok(str_ptr, " ");
222 if (!param_str)
223 goto exit;
224
225 while (1) {
226 /* Make sure that we don't get trapped in an endless loop */
227 if (count > 256)
228 goto error;
229
230 /* Chop off delimiters ';' at the end */
231 delimiter = str_ptr[strlen(str_ptr) - 1];
232 if (delimiter == ';' || delimiter == ',')
233 str_ptr[strlen(str_ptr) - 1] = '\0';
234
235 /* AMR octet aligned parameter */
236 if (sscanf(param_str, "octet-align=%d", &amr_octet_aligned) == 1) {
237 fmtp_param->param.amr_octet_aligned_present = true;
238 fmtp_param->param.amr_octet_aligned = false;
239 if (amr_octet_aligned == 1)
240 fmtp_param->param.amr_octet_aligned = true;
241
242 }
243
244 param_str = strtok(NULL, " ");
245 if (!param_str)
246 break;
247 count++;
248 }
249
250exit:
251 talloc_free(str);
252 return 0;
253error:
254 talloc_free(str);
255 return -EINVAL;
256}
257
258/* Pick optional fmtp parameters by payload type, if there are no fmtp
259 * parameters, a nullpointer is returned */
260static struct mgcp_codec_param *param_by_pt(int pt, struct sdp_fmtp_param *fmtp_params, unsigned int fmtp_params_len)
261{
262 unsigned int i;
263
264 for (i = 0; i < fmtp_params_len; i++) {
265 if (fmtp_params[i].payload_type == pt)
266 return &fmtp_params[i].param;
267 }
268
269 return NULL;
270}
271
Philipp Maier8970c492017-10-11 13:33:42 +0200272/*! Analyze SDP input string.
273 * \param[in] endp trunk endpoint.
274 * \param[out] conn associated rtp connection.
275 * \param[out] caller provided memory to store the parsing results.
Philipp Maier8970c492017-10-11 13:33:42 +0200276 *
277 * Note: In conn (conn->end) the function returns the packet duration,
Philipp Maierbc0346e2018-06-07 09:52:16 +0200278 * rtp port, rtcp port and the codec information.
279 * \returns 0 on success, -1 on failure. */
Philipp Maier8970c492017-10-11 13:33:42 +0200280int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
Philipp Maierbc0346e2018-06-07 09:52:16 +0200281 struct mgcp_conn_rtp *conn, struct mgcp_parse_data *p)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200282{
Philipp Maierbc0346e2018-06-07 09:52:16 +0200283 struct sdp_rtp_map codecs[MGCP_MAX_CODECS];
284 unsigned int codecs_used = 0;
Philipp Maier228e5912019-03-05 13:56:59 +0100285 struct sdp_fmtp_param fmtp_params[MGCP_MAX_CODECS];
286 unsigned int fmtp_used = 0;
287 struct mgcp_codec_param *codec_param;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200288 char *line;
Philipp Maierbc0346e2018-06-07 09:52:16 +0200289 unsigned int i;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200290 void *tmp_ctx = talloc_new(NULL);
Philipp Maier8970c492017-10-11 13:33:42 +0200291 struct mgcp_rtp_end *rtp;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200292
Philipp Maierc7a228a2017-10-18 11:42:25 +0200293 int payload;
294 int ptime, ptime2 = 0;
295 char audio_name[64];
296 int port, rc;
297 char ipv4[16];
298
Philipp Maier8970c492017-10-11 13:33:42 +0200299 OSMO_ASSERT(endp);
300 OSMO_ASSERT(conn);
301 OSMO_ASSERT(p);
302
303 rtp = &conn->end;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200304 memset(&codecs, 0, sizeof(codecs));
305
306 for_each_line(line, p->save) {
307 switch (line[0]) {
308 case 'o':
309 case 's':
310 case 't':
311 case 'v':
312 /* skip these SDP attributes */
313 break;
Philipp Maierc7a228a2017-10-18 11:42:25 +0200314 case 'a':
Philipp Maiere7ae69a2019-03-05 15:17:36 +0100315 if (sscanf(line, "a=rtpmap:%d %63s", &payload, audio_name) == 2) {
316 codecs_update(tmp_ctx, codecs, codecs_used, payload, audio_name);
317 break;
318 }
319
320 if (sscanf(line, "a=ptime:%d-%d", &ptime, &ptime2) >= 1) {
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200321 if (ptime2 > 0 && ptime2 != ptime)
322 rtp->packet_duration_ms = 0;
323 else
324 rtp->packet_duration_ms = ptime;
Philipp Maiere7ae69a2019-03-05 15:17:36 +0100325 break;
326 }
327
328 if (sscanf(line, "a=maxptime:%d", &ptime2) == 1) {
Philipp Maierbc0346e2018-06-07 09:52:16 +0200329 rtp->maximum_packet_time = ptime2;
Philipp Maiere7ae69a2019-03-05 15:17:36 +0100330 break;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200331 }
Philipp Maier228e5912019-03-05 13:56:59 +0100332
333 if (strncmp("a=fmtp:", line, 6) == 0) {
334 rc = fmtp_from_sdp(conn->conn, &fmtp_params[fmtp_used], line);
335 if (rc >= 0)
336 fmtp_used++;
337 break;
338 }
339
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200340 break;
Philipp Maierc7a228a2017-10-18 11:42:25 +0200341 case 'm':
Philipp Maierbc0346e2018-06-07 09:52:16 +0200342 rc = sscanf(line, "m=audio %d RTP/AVP", &port);
343 if (rc == 1) {
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200344 rtp->rtp_port = htons(port);
345 rtp->rtcp_port = htons(port + 1);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200346 }
Philipp Maierbc0346e2018-06-07 09:52:16 +0200347
348 rc = pt_from_sdp(conn->conn, codecs,
349 ARRAY_SIZE(codecs), line);
350 if (rc > 0)
351 codecs_used = rc;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200352 break;
Philipp Maierc7a228a2017-10-18 11:42:25 +0200353 case 'c':
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200354
355 if (sscanf(line, "c=IN IP4 %15s", ipv4) == 1) {
356 inet_aton(ipv4, &rtp->addr);
357 }
358 break;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200359 default:
360 if (p->endp)
361 LOGP(DLMGCP, LOGL_NOTICE,
362 "Unhandled SDP option: '%c'/%d on 0x%x\n",
Philipp Maierc7a228a2017-10-18 11:42:25 +0200363 line[0], line[0],
364 ENDPOINT_NUMBER(p->endp));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200365 else
366 LOGP(DLMGCP, LOGL_NOTICE,
367 "Unhandled SDP option: '%c'/%d\n",
368 line[0], line[0]);
369 break;
370 }
371 }
Philipp Maierbc0346e2018-06-07 09:52:16 +0200372 OSMO_ASSERT(codecs_used <= MGCP_MAX_CODECS);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200373
Philipp Maierbc0346e2018-06-07 09:52:16 +0200374 /* So far we have only set the payload type in the codec struct. Now we
375 * fill up the remaining fields of the codec description with some default
376 * information */
377 codecs_initialize(tmp_ctx, codecs, codecs_used);
378
379 /* Store parsed codec information */
Philipp Maierdbd70c72018-05-25 11:07:31 +0200380 for (i = 0; i < codecs_used; i++) {
Philipp Maier228e5912019-03-05 13:56:59 +0100381 codec_param = param_by_pt(codecs[i].payload_type, fmtp_params, fmtp_used);
382 rc = mgcp_codec_add(conn, codecs[i].payload_type, codecs[i].map_line, codec_param);
Philipp Maierbc0346e2018-06-07 09:52:16 +0200383 if (rc < 0)
384 LOGP(DLMGCP, LOGL_NOTICE, "endpoint:0x%x, failed to add codec\n", ENDPOINT_NUMBER(p->endp));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200385 }
386
387 talloc_free(tmp_ctx);
Philipp Maierdbd70c72018-05-25 11:07:31 +0200388
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200389 LOGPCONN(conn->conn, DLMGCP, LOGL_NOTICE,
Philipp Maierbc0346e2018-06-07 09:52:16 +0200390 "Got media info via SDP: port:%d, addr:%s, duration:%d, payload-types:",
391 ntohs(rtp->rtp_port), inet_ntoa(rtp->addr),
392 rtp->packet_duration_ms);
393 if (codecs_used == 0)
394 LOGPC(DLMGCP, LOGL_NOTICE, "none");
395 for (i = 0; i < codecs_used; i++) {
396 LOGPC(DLMGCP, LOGL_NOTICE, "%d=%s",
397 rtp->codecs[i].payload_type,
398 rtp->codecs[i].subtype_name ? rtp-> codecs[i].subtype_name : "unknown");
399 LOGPC(DLMGCP, LOGL_NOTICE, " ");
400 }
401 LOGPC(DLMGCP, LOGL_NOTICE, "\n");
402
Philipp Maierdbd70c72018-05-25 11:07:31 +0200403 return 0;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200404}
405
Philipp Maier8482e832018-08-02 17:22:40 +0200406
407/* Add rtpmap string to the sdp payload, but only when the payload type falls
408 * into the dynamic payload type range */
409static int add_rtpmap(struct msgb *sdp, int payload_type, const char *audio_name)
410{
411 int rc;
412
413 if (payload_type >= 96 && payload_type <= 127) {
414 if (!audio_name)
415 return -EINVAL;
416 rc = msgb_printf(sdp, "a=rtpmap:%d %s\r\n", payload_type, audio_name);
417 if (rc < 0)
418 return -EINVAL;
419 }
420
421 return 0;
422}
423
Philipp Maier217d31d2019-03-05 14:48:56 +0100424/* Add audio strings to sdp payload */
Philipp Maier910189d2018-08-02 17:45:42 +0200425static int add_audio(struct msgb *sdp, int *payload_types, unsigned int payload_types_len, int local_port)
426{
427 int rc;
428 unsigned int i;
429
Philipp Maier910189d2018-08-02 17:45:42 +0200430 rc = msgb_printf(sdp, "m=audio %d RTP/AVP", local_port);
431 if (rc < 0)
432 return -EINVAL;
433
434 for (i = 0; i < payload_types_len; i++) {
435 rc = msgb_printf(sdp, " %d", payload_types[i]);
436 if (rc < 0)
437 return -EINVAL;
438 }
439
440 rc = msgb_printf(sdp, "\r\n");
441 if (rc < 0)
442 return -EINVAL;
443
444 return 0;
445}
446
Philipp Maier228e5912019-03-05 13:56:59 +0100447/* Add fmtp strings to sdp payload */
448static int add_fmtp(struct msgb *sdp, struct sdp_fmtp_param *fmtp_params, unsigned int fmtp_params_len,
449 const char *fmtp_extra)
450{
451 unsigned int i;
452 int rc;
453 int fmtp_extra_pt = -1;
454 char *fmtp_extra_pars = "";
455
456 /* When no fmtp parameters ara available but an fmtp extra string
457 * is configured, just add the fmtp extra string */
458 if (fmtp_params_len == 0 && fmtp_extra) {
459 return msgb_printf(sdp, "%s\r\n", fmtp_extra);
460 }
461
462 /* When there is fmtp extra configured we dissect it in order to drop
463 * in the configured extra parameters at the right place when
464 * generating the fmtp strings. */
465 if (fmtp_extra) {
466 if (sscanf(fmtp_extra, "a=fmtp:%d ", &fmtp_extra_pt) != 1)
467 fmtp_extra_pt = -1;
468
469 fmtp_extra_pars = strstr(fmtp_extra, " ");
470
471 if (!fmtp_extra_pars)
472 fmtp_extra_pars = "";
473 else
474 fmtp_extra_pars++;
475 }
476
477 for (i = 0; i < fmtp_params_len; i++) {
478 rc = msgb_printf(sdp, "a=fmtp:%u", fmtp_params[i].payload_type);
479
480 /* Add amr octet align parameter */
481 if (fmtp_params[i].param.amr_octet_aligned_present) {
482 if (fmtp_params[i].param.amr_octet_aligned)
483 rc = msgb_printf(sdp, " octet-align=1");
484 else
485 rc = msgb_printf(sdp, " octet-align=0");
486 if (rc < 0)
487 return -EINVAL;
488 }
489
490 /* Append extra parameters from fmtp extra */
491 if (fmtp_params[i].payload_type == fmtp_extra_pt) {
492 rc = msgb_printf(sdp, " %s", fmtp_extra_pars);
493 if (rc < 0)
494 return -EINVAL;
495 }
496
497 rc = msgb_printf(sdp, "\r\n", fmtp_params[i].payload_type);
498 if (rc < 0)
499 return -EINVAL;
500 }
501
502 return 0;
503}
504
Philipp Maier8970c492017-10-11 13:33:42 +0200505/*! Generate SDP response string.
506 * \param[in] endp trunk endpoint.
507 * \param[in] conn associated rtp connection.
508 * \param[out] sdp msg buffer to append resulting SDP string data.
509 * \param[in] addr IPV4 address string (e.g. 192.168.100.1).
510 * \returns 0 on success, -1 on failure. */
511int mgcp_write_response_sdp(const struct mgcp_endpoint *endp,
512 const struct mgcp_conn_rtp *conn, struct msgb *sdp,
513 const char *addr)
514{
Philipp Maier58128252019-03-06 11:28:18 +0100515 const struct mgcp_rtp_codec *codec;
Philipp Maier8970c492017-10-11 13:33:42 +0200516 const char *fmtp_extra;
517 const char *audio_name;
518 int payload_type;
Philipp Maier228e5912019-03-05 13:56:59 +0100519 struct sdp_fmtp_param fmtp_param;
Philipp Maier8970c492017-10-11 13:33:42 +0200520 int rc;
Philipp Maier910189d2018-08-02 17:45:42 +0200521 int payload_types[1];
Pau Espin Pedrola93c6e92019-05-06 15:23:57 +0200522 int local_port;
Philipp Maier228e5912019-03-05 13:56:59 +0100523 struct sdp_fmtp_param fmtp_params[1];
524 unsigned int fmtp_params_len = 0;
Philipp Maier8970c492017-10-11 13:33:42 +0200525
526 OSMO_ASSERT(endp);
527 OSMO_ASSERT(conn);
528 OSMO_ASSERT(sdp);
529 OSMO_ASSERT(addr);
530
531 /* FIXME: constify endp and conn args in get_net_donwlink_format_cb() */
532 endp->cfg->get_net_downlink_format_cb((struct mgcp_endpoint *)endp,
Philipp Maier58128252019-03-06 11:28:18 +0100533 &codec, &fmtp_extra,
Philipp Maier8970c492017-10-11 13:33:42 +0200534 (struct mgcp_conn_rtp *)conn);
535
Philipp Maier58128252019-03-06 11:28:18 +0100536 audio_name = codec->audio_name;
537 payload_type = codec->payload_type;
538
Philipp Maier8970c492017-10-11 13:33:42 +0200539 rc = msgb_printf(sdp,
540 "v=0\r\n"
Philipp Maier01d24a32017-11-21 17:26:09 +0100541 "o=- %s 23 IN IP4 %s\r\n"
Philipp Maier8970c492017-10-11 13:33:42 +0200542 "s=-\r\n"
543 "c=IN IP4 %s\r\n"
544 "t=0 0\r\n", conn->conn->id, addr, addr);
545
546 if (rc < 0)
547 goto buffer_too_small;
548
549 if (payload_type >= 0) {
Philipp Maier910189d2018-08-02 17:45:42 +0200550
551 payload_types[0] = payload_type;
Pau Espin Pedrola93c6e92019-05-06 15:23:57 +0200552 if (mgcp_conn_rtp_is_osmux(conn))
553 local_port = endp->cfg->osmux_port;
554 else
555 local_port = conn->end.local_port;
556 rc = add_audio(sdp, payload_types, 1, local_port);
Philipp Maier8970c492017-10-11 13:33:42 +0200557 if (rc < 0)
558 goto buffer_too_small;
559
Philipp Maier8482e832018-08-02 17:22:40 +0200560 if (endp->tcfg->audio_send_name) {
561 rc = add_rtpmap(sdp, payload_type, audio_name);
Philipp Maier8970c492017-10-11 13:33:42 +0200562 if (rc < 0)
563 goto buffer_too_small;
564 }
565
Philipp Maier228e5912019-03-05 13:56:59 +0100566 if (codec->param_present) {
567 fmtp_param.payload_type = payload_type;
568 fmtp_param.param = codec->param;
569 fmtp_params[0] = fmtp_param;
570 fmtp_params_len = 1;
Philipp Maier8970c492017-10-11 13:33:42 +0200571 }
Philipp Maier228e5912019-03-05 13:56:59 +0100572 rc = add_fmtp(sdp, fmtp_params, fmtp_params_len, fmtp_extra);
573 if (rc < 0)
574 goto buffer_too_small;
Philipp Maier8970c492017-10-11 13:33:42 +0200575 }
576 if (conn->end.packet_duration_ms > 0 && endp->tcfg->audio_send_ptime) {
577 rc = msgb_printf(sdp, "a=ptime:%u\r\n",
578 conn->end.packet_duration_ms);
579 if (rc < 0)
580 goto buffer_too_small;
581 }
582
583 return 0;
584
585buffer_too_small:
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200586 LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR, "SDP messagebuffer too small\n");
Philipp Maier8970c492017-10-11 13:33:42 +0200587 return -1;
588}