blob: 56fc611f532920b3772ab0897b4cf2e9db433254 [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;
Philipp Maierbc0346e2018-06-07 09:52:16 +0200135 unsigned int pt;
136 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
166 /* Do not allow duplicate payload types */
167 for (i = 0; i < count; i++)
168 if (codecs[i].payload_type == pt)
169 goto error;
170
171 codecs[count].payload_type = pt;
172 count++;
173 }
174
175exit:
176 talloc_free(str);
177 return count;
178error:
179 talloc_free(str);
180 return -EINVAL;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200181}
182
Philipp Maier228e5912019-03-05 13:56:59 +0100183/* Extract fmtp parameters from SDP, called from: mgcp_parse_sdp_data() */
184static int fmtp_from_sdp(void *ctx, struct sdp_fmtp_param *fmtp_param, char *sdp)
185{
186 char *str;
187 char *str_ptr;
188 char *param_str;
189 unsigned int pt;
190 unsigned int count = 0;
191 char delimiter;
192 unsigned int amr_octet_aligned;
193
194 memset(fmtp_param, 0, sizeof(*fmtp_param));
195
196 str = talloc_zero_size(ctx, strlen(sdp) + 1);
197 str_ptr = str;
198 strcpy(str_ptr, sdp);
199
200 /* Check if the input string begins with an fmtp token */
201 str_ptr = strstr(str_ptr, "fmtp:");
202 if (!str_ptr)
203 goto exit;
204 str_ptr += 5;
205
206 /* Extract payload type */
207 if (sscanf(str_ptr, "%u ", &pt) != 1)
208 goto error;
209 fmtp_param->payload_type = pt;
210
211 /* Advance pointer to the beginning of the parameter section and
212 * tokenize string */
213 str_ptr = strstr(str_ptr, " ");
214 if (!str_ptr)
215 goto error;
216 str_ptr++;
217
218 param_str = strtok(str_ptr, " ");
219 if (!param_str)
220 goto exit;
221
222 while (1) {
223 /* Make sure that we don't get trapped in an endless loop */
224 if (count > 256)
225 goto error;
226
227 /* Chop off delimiters ';' at the end */
228 delimiter = str_ptr[strlen(str_ptr) - 1];
229 if (delimiter == ';' || delimiter == ',')
230 str_ptr[strlen(str_ptr) - 1] = '\0';
231
232 /* AMR octet aligned parameter */
233 if (sscanf(param_str, "octet-align=%d", &amr_octet_aligned) == 1) {
234 fmtp_param->param.amr_octet_aligned_present = true;
235 fmtp_param->param.amr_octet_aligned = false;
236 if (amr_octet_aligned == 1)
237 fmtp_param->param.amr_octet_aligned = true;
238
239 }
240
241 param_str = strtok(NULL, " ");
242 if (!param_str)
243 break;
244 count++;
245 }
246
247exit:
248 talloc_free(str);
249 return 0;
250error:
251 talloc_free(str);
252 return -EINVAL;
253}
254
255/* Pick optional fmtp parameters by payload type, if there are no fmtp
256 * parameters, a nullpointer is returned */
257static struct mgcp_codec_param *param_by_pt(int pt, struct sdp_fmtp_param *fmtp_params, unsigned int fmtp_params_len)
258{
259 unsigned int i;
260
261 for (i = 0; i < fmtp_params_len; i++) {
262 if (fmtp_params[i].payload_type == pt)
263 return &fmtp_params[i].param;
264 }
265
266 return NULL;
267}
268
Philipp Maier8970c492017-10-11 13:33:42 +0200269/*! Analyze SDP input string.
270 * \param[in] endp trunk endpoint.
271 * \param[out] conn associated rtp connection.
272 * \param[out] caller provided memory to store the parsing results.
Philipp Maier8970c492017-10-11 13:33:42 +0200273 *
274 * Note: In conn (conn->end) the function returns the packet duration,
Philipp Maierbc0346e2018-06-07 09:52:16 +0200275 * rtp port, rtcp port and the codec information.
276 * \returns 0 on success, -1 on failure. */
Philipp Maier8970c492017-10-11 13:33:42 +0200277int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
Philipp Maierbc0346e2018-06-07 09:52:16 +0200278 struct mgcp_conn_rtp *conn, struct mgcp_parse_data *p)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200279{
Philipp Maierbc0346e2018-06-07 09:52:16 +0200280 struct sdp_rtp_map codecs[MGCP_MAX_CODECS];
281 unsigned int codecs_used = 0;
Philipp Maier228e5912019-03-05 13:56:59 +0100282 struct sdp_fmtp_param fmtp_params[MGCP_MAX_CODECS];
283 unsigned int fmtp_used = 0;
284 struct mgcp_codec_param *codec_param;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200285 char *line;
Philipp Maierbc0346e2018-06-07 09:52:16 +0200286 unsigned int i;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200287 void *tmp_ctx = talloc_new(NULL);
Philipp Maier8970c492017-10-11 13:33:42 +0200288 struct mgcp_rtp_end *rtp;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200289
Philipp Maierc7a228a2017-10-18 11:42:25 +0200290 int payload;
291 int ptime, ptime2 = 0;
292 char audio_name[64];
293 int port, rc;
294 char ipv4[16];
295
Philipp Maier8970c492017-10-11 13:33:42 +0200296 OSMO_ASSERT(endp);
297 OSMO_ASSERT(conn);
298 OSMO_ASSERT(p);
299
300 rtp = &conn->end;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200301 memset(&codecs, 0, sizeof(codecs));
302
303 for_each_line(line, p->save) {
304 switch (line[0]) {
305 case 'o':
306 case 's':
307 case 't':
308 case 'v':
309 /* skip these SDP attributes */
310 break;
Philipp Maierc7a228a2017-10-18 11:42:25 +0200311 case 'a':
Philipp Maiere7ae69a2019-03-05 15:17:36 +0100312 if (sscanf(line, "a=rtpmap:%d %63s", &payload, audio_name) == 2) {
313 codecs_update(tmp_ctx, codecs, codecs_used, payload, audio_name);
314 break;
315 }
316
317 if (sscanf(line, "a=ptime:%d-%d", &ptime, &ptime2) >= 1) {
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200318 if (ptime2 > 0 && ptime2 != ptime)
319 rtp->packet_duration_ms = 0;
320 else
321 rtp->packet_duration_ms = ptime;
Philipp Maiere7ae69a2019-03-05 15:17:36 +0100322 break;
323 }
324
325 if (sscanf(line, "a=maxptime:%d", &ptime2) == 1) {
Philipp Maierbc0346e2018-06-07 09:52:16 +0200326 rtp->maximum_packet_time = ptime2;
Philipp Maiere7ae69a2019-03-05 15:17:36 +0100327 break;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200328 }
Philipp Maier228e5912019-03-05 13:56:59 +0100329
330 if (strncmp("a=fmtp:", line, 6) == 0) {
331 rc = fmtp_from_sdp(conn->conn, &fmtp_params[fmtp_used], line);
332 if (rc >= 0)
333 fmtp_used++;
334 break;
335 }
336
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200337 break;
Philipp Maierc7a228a2017-10-18 11:42:25 +0200338 case 'm':
Philipp Maierbc0346e2018-06-07 09:52:16 +0200339 rc = sscanf(line, "m=audio %d RTP/AVP", &port);
340 if (rc == 1) {
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200341 rtp->rtp_port = htons(port);
342 rtp->rtcp_port = htons(port + 1);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200343 }
Philipp Maierbc0346e2018-06-07 09:52:16 +0200344
345 rc = pt_from_sdp(conn->conn, codecs,
346 ARRAY_SIZE(codecs), line);
347 if (rc > 0)
348 codecs_used = rc;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200349 break;
Philipp Maierc7a228a2017-10-18 11:42:25 +0200350 case 'c':
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200351
352 if (sscanf(line, "c=IN IP4 %15s", ipv4) == 1) {
353 inet_aton(ipv4, &rtp->addr);
354 }
355 break;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200356 default:
357 if (p->endp)
358 LOGP(DLMGCP, LOGL_NOTICE,
359 "Unhandled SDP option: '%c'/%d on 0x%x\n",
Philipp Maierc7a228a2017-10-18 11:42:25 +0200360 line[0], line[0],
361 ENDPOINT_NUMBER(p->endp));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200362 else
363 LOGP(DLMGCP, LOGL_NOTICE,
364 "Unhandled SDP option: '%c'/%d\n",
365 line[0], line[0]);
366 break;
367 }
368 }
Philipp Maierbc0346e2018-06-07 09:52:16 +0200369 OSMO_ASSERT(codecs_used <= MGCP_MAX_CODECS);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200370
Philipp Maierbc0346e2018-06-07 09:52:16 +0200371 /* So far we have only set the payload type in the codec struct. Now we
372 * fill up the remaining fields of the codec description with some default
373 * information */
374 codecs_initialize(tmp_ctx, codecs, codecs_used);
375
376 /* Store parsed codec information */
Philipp Maierdbd70c72018-05-25 11:07:31 +0200377 for (i = 0; i < codecs_used; i++) {
Philipp Maier228e5912019-03-05 13:56:59 +0100378 codec_param = param_by_pt(codecs[i].payload_type, fmtp_params, fmtp_used);
379 rc = mgcp_codec_add(conn, codecs[i].payload_type, codecs[i].map_line, codec_param);
Philipp Maierbc0346e2018-06-07 09:52:16 +0200380 if (rc < 0)
381 LOGP(DLMGCP, LOGL_NOTICE, "endpoint:0x%x, failed to add codec\n", ENDPOINT_NUMBER(p->endp));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200382 }
383
384 talloc_free(tmp_ctx);
Philipp Maierdbd70c72018-05-25 11:07:31 +0200385
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200386 LOGPCONN(conn->conn, DLMGCP, LOGL_NOTICE,
Philipp Maierbc0346e2018-06-07 09:52:16 +0200387 "Got media info via SDP: port:%d, addr:%s, duration:%d, payload-types:",
388 ntohs(rtp->rtp_port), inet_ntoa(rtp->addr),
389 rtp->packet_duration_ms);
390 if (codecs_used == 0)
391 LOGPC(DLMGCP, LOGL_NOTICE, "none");
392 for (i = 0; i < codecs_used; i++) {
393 LOGPC(DLMGCP, LOGL_NOTICE, "%d=%s",
394 rtp->codecs[i].payload_type,
395 rtp->codecs[i].subtype_name ? rtp-> codecs[i].subtype_name : "unknown");
396 LOGPC(DLMGCP, LOGL_NOTICE, " ");
397 }
398 LOGPC(DLMGCP, LOGL_NOTICE, "\n");
399
Philipp Maierdbd70c72018-05-25 11:07:31 +0200400 return 0;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200401}
402
Philipp Maier8482e832018-08-02 17:22:40 +0200403
404/* Add rtpmap string to the sdp payload, but only when the payload type falls
405 * into the dynamic payload type range */
406static int add_rtpmap(struct msgb *sdp, int payload_type, const char *audio_name)
407{
408 int rc;
409
410 if (payload_type >= 96 && payload_type <= 127) {
411 if (!audio_name)
412 return -EINVAL;
413 rc = msgb_printf(sdp, "a=rtpmap:%d %s\r\n", payload_type, audio_name);
414 if (rc < 0)
415 return -EINVAL;
416 }
417
418 return 0;
419}
420
Philipp Maier217d31d2019-03-05 14:48:56 +0100421/* Add audio strings to sdp payload */
Philipp Maier910189d2018-08-02 17:45:42 +0200422static int add_audio(struct msgb *sdp, int *payload_types, unsigned int payload_types_len, int local_port)
423{
424 int rc;
425 unsigned int i;
426
Philipp Maier910189d2018-08-02 17:45:42 +0200427 rc = msgb_printf(sdp, "m=audio %d RTP/AVP", local_port);
428 if (rc < 0)
429 return -EINVAL;
430
431 for (i = 0; i < payload_types_len; i++) {
432 rc = msgb_printf(sdp, " %d", payload_types[i]);
433 if (rc < 0)
434 return -EINVAL;
435 }
436
437 rc = msgb_printf(sdp, "\r\n");
438 if (rc < 0)
439 return -EINVAL;
440
441 return 0;
442}
443
Philipp Maier228e5912019-03-05 13:56:59 +0100444/* Add fmtp strings to sdp payload */
445static int add_fmtp(struct msgb *sdp, struct sdp_fmtp_param *fmtp_params, unsigned int fmtp_params_len,
446 const char *fmtp_extra)
447{
448 unsigned int i;
449 int rc;
450 int fmtp_extra_pt = -1;
451 char *fmtp_extra_pars = "";
452
453 /* When no fmtp parameters ara available but an fmtp extra string
454 * is configured, just add the fmtp extra string */
455 if (fmtp_params_len == 0 && fmtp_extra) {
456 return msgb_printf(sdp, "%s\r\n", fmtp_extra);
457 }
458
459 /* When there is fmtp extra configured we dissect it in order to drop
460 * in the configured extra parameters at the right place when
461 * generating the fmtp strings. */
462 if (fmtp_extra) {
463 if (sscanf(fmtp_extra, "a=fmtp:%d ", &fmtp_extra_pt) != 1)
464 fmtp_extra_pt = -1;
465
466 fmtp_extra_pars = strstr(fmtp_extra, " ");
467
468 if (!fmtp_extra_pars)
469 fmtp_extra_pars = "";
470 else
471 fmtp_extra_pars++;
472 }
473
474 for (i = 0; i < fmtp_params_len; i++) {
475 rc = msgb_printf(sdp, "a=fmtp:%u", fmtp_params[i].payload_type);
476
477 /* Add amr octet align parameter */
478 if (fmtp_params[i].param.amr_octet_aligned_present) {
479 if (fmtp_params[i].param.amr_octet_aligned)
480 rc = msgb_printf(sdp, " octet-align=1");
481 else
482 rc = msgb_printf(sdp, " octet-align=0");
483 if (rc < 0)
484 return -EINVAL;
485 }
486
487 /* Append extra parameters from fmtp extra */
488 if (fmtp_params[i].payload_type == fmtp_extra_pt) {
489 rc = msgb_printf(sdp, " %s", fmtp_extra_pars);
490 if (rc < 0)
491 return -EINVAL;
492 }
493
494 rc = msgb_printf(sdp, "\r\n", fmtp_params[i].payload_type);
495 if (rc < 0)
496 return -EINVAL;
497 }
498
499 return 0;
500}
501
Philipp Maier8970c492017-10-11 13:33:42 +0200502/*! Generate SDP response string.
503 * \param[in] endp trunk endpoint.
504 * \param[in] conn associated rtp connection.
505 * \param[out] sdp msg buffer to append resulting SDP string data.
506 * \param[in] addr IPV4 address string (e.g. 192.168.100.1).
507 * \returns 0 on success, -1 on failure. */
508int mgcp_write_response_sdp(const struct mgcp_endpoint *endp,
509 const struct mgcp_conn_rtp *conn, struct msgb *sdp,
510 const char *addr)
511{
Philipp Maier58128252019-03-06 11:28:18 +0100512 const struct mgcp_rtp_codec *codec;
Philipp Maier8970c492017-10-11 13:33:42 +0200513 const char *fmtp_extra;
514 const char *audio_name;
515 int payload_type;
Philipp Maier228e5912019-03-05 13:56:59 +0100516 struct sdp_fmtp_param fmtp_param;
Philipp Maier8970c492017-10-11 13:33:42 +0200517 int rc;
Philipp Maier910189d2018-08-02 17:45:42 +0200518 int payload_types[1];
Pau Espin Pedrola93c6e92019-05-06 15:23:57 +0200519 int local_port;
Philipp Maier228e5912019-03-05 13:56:59 +0100520 struct sdp_fmtp_param fmtp_params[1];
521 unsigned int fmtp_params_len = 0;
Philipp Maier8970c492017-10-11 13:33:42 +0200522
523 OSMO_ASSERT(endp);
524 OSMO_ASSERT(conn);
525 OSMO_ASSERT(sdp);
526 OSMO_ASSERT(addr);
527
528 /* FIXME: constify endp and conn args in get_net_donwlink_format_cb() */
529 endp->cfg->get_net_downlink_format_cb((struct mgcp_endpoint *)endp,
Philipp Maier58128252019-03-06 11:28:18 +0100530 &codec, &fmtp_extra,
Philipp Maier8970c492017-10-11 13:33:42 +0200531 (struct mgcp_conn_rtp *)conn);
532
Philipp Maier58128252019-03-06 11:28:18 +0100533 audio_name = codec->audio_name;
534 payload_type = codec->payload_type;
535
Philipp Maier8970c492017-10-11 13:33:42 +0200536 rc = msgb_printf(sdp,
537 "v=0\r\n"
Philipp Maier01d24a32017-11-21 17:26:09 +0100538 "o=- %s 23 IN IP4 %s\r\n"
Philipp Maier8970c492017-10-11 13:33:42 +0200539 "s=-\r\n"
540 "c=IN IP4 %s\r\n"
541 "t=0 0\r\n", conn->conn->id, addr, addr);
542
543 if (rc < 0)
544 goto buffer_too_small;
545
546 if (payload_type >= 0) {
Philipp Maier910189d2018-08-02 17:45:42 +0200547
548 payload_types[0] = payload_type;
Pau Espin Pedrola93c6e92019-05-06 15:23:57 +0200549 if (mgcp_conn_rtp_is_osmux(conn))
550 local_port = endp->cfg->osmux_port;
551 else
552 local_port = conn->end.local_port;
553 rc = add_audio(sdp, payload_types, 1, local_port);
Philipp Maier8970c492017-10-11 13:33:42 +0200554 if (rc < 0)
555 goto buffer_too_small;
556
Philipp Maier8482e832018-08-02 17:22:40 +0200557 if (endp->tcfg->audio_send_name) {
558 rc = add_rtpmap(sdp, payload_type, audio_name);
Philipp Maier8970c492017-10-11 13:33:42 +0200559 if (rc < 0)
560 goto buffer_too_small;
561 }
562
Philipp Maier228e5912019-03-05 13:56:59 +0100563 if (codec->param_present) {
564 fmtp_param.payload_type = payload_type;
565 fmtp_param.param = codec->param;
566 fmtp_params[0] = fmtp_param;
567 fmtp_params_len = 1;
Philipp Maier8970c492017-10-11 13:33:42 +0200568 }
Philipp Maier228e5912019-03-05 13:56:59 +0100569 rc = add_fmtp(sdp, fmtp_params, fmtp_params_len, fmtp_extra);
570 if (rc < 0)
571 goto buffer_too_small;
Philipp Maier8970c492017-10-11 13:33:42 +0200572 }
573 if (conn->end.packet_duration_ms > 0 && endp->tcfg->audio_send_ptime) {
574 rc = msgb_printf(sdp, "a=ptime:%u\r\n",
575 conn->end.packet_duration_ms);
576 if (rc < 0)
577 goto buffer_too_small;
578 }
579
580 return 0;
581
582buffer_too_small:
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200583 LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR, "SDP messagebuffer too small\n");
Philipp Maier8970c492017-10-11 13:33:42 +0200584 return -1;
585}