blob: 99e764bbf5bdf21c39db0894b5fdcf9e306e1e3d [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>
32
Philipp Maier228e5912019-03-05 13:56:59 +010033/* Two structs to store intermediate parsing results. The function
34 * mgcp_parse_sdp_data() is using the following two structs as temporary
35 * storage for parsing the SDP codec information. */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020036struct sdp_rtp_map {
37 /* the type */
38 int payload_type;
39 /* null, static or later dynamic codec name */
40 char *codec_name;
41 /* A pointer to the original line for later parsing */
42 char *map_line;
43
44 int rate;
45 int channels;
46};
Philipp Maier228e5912019-03-05 13:56:59 +010047struct sdp_fmtp_param {
48 int payload_type;
49 struct mgcp_codec_param param;
50};
51
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020052
Philipp Maierbc0346e2018-06-07 09:52:16 +020053/* Helper function to extrapolate missing codec parameters in a codec mao from
54 * an already filled in payload_type, called from: mgcp_parse_sdp_data() */
Philipp Maier8970c492017-10-11 13:33:42 +020055static void codecs_initialize(void *ctx, struct sdp_rtp_map *codecs, int used)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020056{
57 int i;
58
59 for (i = 0; i < used; ++i) {
60 switch (codecs[i].payload_type) {
61 case 0:
62 codecs[i].codec_name = "PCMU";
63 codecs[i].rate = 8000;
64 codecs[i].channels = 1;
65 break;
66 case 3:
67 codecs[i].codec_name = "GSM";
68 codecs[i].rate = 8000;
69 codecs[i].channels = 1;
70 break;
71 case 8:
72 codecs[i].codec_name = "PCMA";
73 codecs[i].rate = 8000;
74 codecs[i].channels = 1;
75 break;
76 case 18:
77 codecs[i].codec_name = "G729";
78 codecs[i].rate = 8000;
79 codecs[i].channels = 1;
80 break;
Philipp Maierbc0346e2018-06-07 09:52:16 +020081 default:
82 codecs[i].codec_name = NULL;
83 codecs[i].rate = 0;
84 codecs[i].channels = 0;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020085 }
86 }
87}
88
Philipp Maierbc0346e2018-06-07 09:52:16 +020089/* Helper function to update codec map information with additional data from
90 * SDP, called from: mgcp_parse_sdp_data() */
Philipp Maier8970c492017-10-11 13:33:42 +020091static void codecs_update(void *ctx, struct sdp_rtp_map *codecs, int used,
92 int payload, const char *audio_name)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020093{
94 int i;
95
96 for (i = 0; i < used; ++i) {
97 char audio_codec[64];
98 int rate = -1;
99 int channels = -1;
Philipp Maierbc0346e2018-06-07 09:52:16 +0200100
101 /* Note: We can only update payload codecs that already exist
102 * in our codec list. If we get an unexpected payload type,
103 * we just drop it */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200104 if (codecs[i].payload_type != payload)
105 continue;
Philipp Maierbc0346e2018-06-07 09:52:16 +0200106
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200107 if (sscanf(audio_name, "%63[^/]/%d/%d",
Philipp Maierd8d7b4b2017-10-18 11:45:35 +0200108 audio_codec, &rate, &channels) < 1) {
109 LOGP(DLMGCP, LOGL_ERROR, "Failed to parse '%s'\n",
110 audio_name);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200111 continue;
112 }
113
114 codecs[i].map_line = talloc_strdup(ctx, audio_name);
115 codecs[i].codec_name = talloc_strdup(ctx, audio_codec);
116 codecs[i].rate = rate;
117 codecs[i].channels = channels;
118 return;
119 }
120
Philipp Maierd8d7b4b2017-10-18 11:45:35 +0200121 LOGP(DLMGCP, LOGL_ERROR, "Unconfigured PT(%d) with %s\n", payload,
122 audio_name);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200123}
124
Philipp Maierbc0346e2018-06-07 09:52:16 +0200125/* Extract payload types from SDP, also check for duplicates */
126static int pt_from_sdp(void *ctx, struct sdp_rtp_map *codecs,
127 unsigned int codecs_len, char *sdp)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200128{
Philipp Maierbc0346e2018-06-07 09:52:16 +0200129 char *str;
130 char *str_ptr;
131 char *pt_str;
132 unsigned int pt;
133 unsigned int count = 0;
134 unsigned int i;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200135
Philipp Maierbc0346e2018-06-07 09:52:16 +0200136 str = talloc_zero_size(ctx, strlen(sdp) + 1);
137 str_ptr = str;
138 strcpy(str_ptr, sdp);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200139
Philipp Maierbc0346e2018-06-07 09:52:16 +0200140 str_ptr = strstr(str_ptr, "RTP/AVP ");
141 if (!str_ptr)
142 goto exit;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200143
Philipp Maierbc0346e2018-06-07 09:52:16 +0200144 pt_str = strtok(str_ptr, " ");
145 if (!pt_str)
146 goto exit;
147
148 while (1) {
149 /* Do not allow excessive payload types */
150 if (count > codecs_len)
151 goto error;
152
153 pt_str = strtok(NULL, " ");
154 if (!pt_str)
155 break;
156
157 pt = atoi(pt_str);
158
159 /* Do not allow duplicate payload types */
160 for (i = 0; i < count; i++)
161 if (codecs[i].payload_type == pt)
162 goto error;
163
164 codecs[count].payload_type = pt;
165 count++;
166 }
167
168exit:
169 talloc_free(str);
170 return count;
171error:
172 talloc_free(str);
173 return -EINVAL;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200174}
175
Philipp Maier228e5912019-03-05 13:56:59 +0100176/* Extract fmtp parameters from SDP, called from: mgcp_parse_sdp_data() */
177static int fmtp_from_sdp(void *ctx, struct sdp_fmtp_param *fmtp_param, char *sdp)
178{
179 char *str;
180 char *str_ptr;
181 char *param_str;
182 unsigned int pt;
183 unsigned int count = 0;
184 char delimiter;
185 unsigned int amr_octet_aligned;
186
187 memset(fmtp_param, 0, sizeof(*fmtp_param));
188
189 str = talloc_zero_size(ctx, strlen(sdp) + 1);
190 str_ptr = str;
191 strcpy(str_ptr, sdp);
192
193 /* Check if the input string begins with an fmtp token */
194 str_ptr = strstr(str_ptr, "fmtp:");
195 if (!str_ptr)
196 goto exit;
197 str_ptr += 5;
198
199 /* Extract payload type */
200 if (sscanf(str_ptr, "%u ", &pt) != 1)
201 goto error;
202 fmtp_param->payload_type = pt;
203
204 /* Advance pointer to the beginning of the parameter section and
205 * tokenize string */
206 str_ptr = strstr(str_ptr, " ");
207 if (!str_ptr)
208 goto error;
209 str_ptr++;
210
211 param_str = strtok(str_ptr, " ");
212 if (!param_str)
213 goto exit;
214
215 while (1) {
216 /* Make sure that we don't get trapped in an endless loop */
217 if (count > 256)
218 goto error;
219
220 /* Chop off delimiters ';' at the end */
221 delimiter = str_ptr[strlen(str_ptr) - 1];
222 if (delimiter == ';' || delimiter == ',')
223 str_ptr[strlen(str_ptr) - 1] = '\0';
224
225 /* AMR octet aligned parameter */
226 if (sscanf(param_str, "octet-align=%d", &amr_octet_aligned) == 1) {
227 fmtp_param->param.amr_octet_aligned_present = true;
228 fmtp_param->param.amr_octet_aligned = false;
229 if (amr_octet_aligned == 1)
230 fmtp_param->param.amr_octet_aligned = true;
231
232 }
233
234 param_str = strtok(NULL, " ");
235 if (!param_str)
236 break;
237 count++;
238 }
239
240exit:
241 talloc_free(str);
242 return 0;
243error:
244 talloc_free(str);
245 return -EINVAL;
246}
247
248/* Pick optional fmtp parameters by payload type, if there are no fmtp
249 * parameters, a nullpointer is returned */
250static struct mgcp_codec_param *param_by_pt(int pt, struct sdp_fmtp_param *fmtp_params, unsigned int fmtp_params_len)
251{
252 unsigned int i;
253
254 for (i = 0; i < fmtp_params_len; i++) {
255 if (fmtp_params[i].payload_type == pt)
256 return &fmtp_params[i].param;
257 }
258
259 return NULL;
260}
261
Philipp Maier8970c492017-10-11 13:33:42 +0200262/*! Analyze SDP input string.
263 * \param[in] endp trunk endpoint.
264 * \param[out] conn associated rtp connection.
265 * \param[out] caller provided memory to store the parsing results.
Philipp Maier8970c492017-10-11 13:33:42 +0200266 *
267 * Note: In conn (conn->end) the function returns the packet duration,
Philipp Maierbc0346e2018-06-07 09:52:16 +0200268 * rtp port, rtcp port and the codec information.
269 * \returns 0 on success, -1 on failure. */
Philipp Maier8970c492017-10-11 13:33:42 +0200270int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
Philipp Maierbc0346e2018-06-07 09:52:16 +0200271 struct mgcp_conn_rtp *conn, struct mgcp_parse_data *p)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200272{
Philipp Maierbc0346e2018-06-07 09:52:16 +0200273 struct sdp_rtp_map codecs[MGCP_MAX_CODECS];
274 unsigned int codecs_used = 0;
Philipp Maier228e5912019-03-05 13:56:59 +0100275 struct sdp_fmtp_param fmtp_params[MGCP_MAX_CODECS];
276 unsigned int fmtp_used = 0;
277 struct mgcp_codec_param *codec_param;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200278 char *line;
Philipp Maierbc0346e2018-06-07 09:52:16 +0200279 unsigned int i;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200280 void *tmp_ctx = talloc_new(NULL);
Philipp Maier8970c492017-10-11 13:33:42 +0200281 struct mgcp_rtp_end *rtp;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200282
Philipp Maierc7a228a2017-10-18 11:42:25 +0200283 int payload;
284 int ptime, ptime2 = 0;
285 char audio_name[64];
286 int port, rc;
287 char ipv4[16];
288
Philipp Maier8970c492017-10-11 13:33:42 +0200289 OSMO_ASSERT(endp);
290 OSMO_ASSERT(conn);
291 OSMO_ASSERT(p);
292
293 rtp = &conn->end;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200294 memset(&codecs, 0, sizeof(codecs));
295
296 for_each_line(line, p->save) {
297 switch (line[0]) {
298 case 'o':
299 case 's':
300 case 't':
301 case 'v':
302 /* skip these SDP attributes */
303 break;
Philipp Maierc7a228a2017-10-18 11:42:25 +0200304 case 'a':
Philipp Maiere7ae69a2019-03-05 15:17:36 +0100305 if (sscanf(line, "a=rtpmap:%d %63s", &payload, audio_name) == 2) {
306 codecs_update(tmp_ctx, codecs, codecs_used, payload, audio_name);
307 break;
308 }
309
310 if (sscanf(line, "a=ptime:%d-%d", &ptime, &ptime2) >= 1) {
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200311 if (ptime2 > 0 && ptime2 != ptime)
312 rtp->packet_duration_ms = 0;
313 else
314 rtp->packet_duration_ms = ptime;
Philipp Maiere7ae69a2019-03-05 15:17:36 +0100315 break;
316 }
317
318 if (sscanf(line, "a=maxptime:%d", &ptime2) == 1) {
Philipp Maierbc0346e2018-06-07 09:52:16 +0200319 rtp->maximum_packet_time = ptime2;
Philipp Maiere7ae69a2019-03-05 15:17:36 +0100320 break;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200321 }
Philipp Maier228e5912019-03-05 13:56:59 +0100322
323 if (strncmp("a=fmtp:", line, 6) == 0) {
324 rc = fmtp_from_sdp(conn->conn, &fmtp_params[fmtp_used], line);
325 if (rc >= 0)
326 fmtp_used++;
327 break;
328 }
329
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200330 break;
Philipp Maierc7a228a2017-10-18 11:42:25 +0200331 case 'm':
Philipp Maierbc0346e2018-06-07 09:52:16 +0200332 rc = sscanf(line, "m=audio %d RTP/AVP", &port);
333 if (rc == 1) {
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200334 rtp->rtp_port = htons(port);
335 rtp->rtcp_port = htons(port + 1);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200336 }
Philipp Maierbc0346e2018-06-07 09:52:16 +0200337
338 rc = pt_from_sdp(conn->conn, codecs,
339 ARRAY_SIZE(codecs), line);
340 if (rc > 0)
341 codecs_used = rc;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200342 break;
Philipp Maierc7a228a2017-10-18 11:42:25 +0200343 case 'c':
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200344
345 if (sscanf(line, "c=IN IP4 %15s", ipv4) == 1) {
346 inet_aton(ipv4, &rtp->addr);
347 }
348 break;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200349 default:
350 if (p->endp)
351 LOGP(DLMGCP, LOGL_NOTICE,
352 "Unhandled SDP option: '%c'/%d on 0x%x\n",
Philipp Maierc7a228a2017-10-18 11:42:25 +0200353 line[0], line[0],
354 ENDPOINT_NUMBER(p->endp));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200355 else
356 LOGP(DLMGCP, LOGL_NOTICE,
357 "Unhandled SDP option: '%c'/%d\n",
358 line[0], line[0]);
359 break;
360 }
361 }
Philipp Maierbc0346e2018-06-07 09:52:16 +0200362 OSMO_ASSERT(codecs_used <= MGCP_MAX_CODECS);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200363
Philipp Maierbc0346e2018-06-07 09:52:16 +0200364 /* So far we have only set the payload type in the codec struct. Now we
365 * fill up the remaining fields of the codec description with some default
366 * information */
367 codecs_initialize(tmp_ctx, codecs, codecs_used);
368
369 /* Store parsed codec information */
Philipp Maierdbd70c72018-05-25 11:07:31 +0200370 for (i = 0; i < codecs_used; i++) {
Philipp Maier228e5912019-03-05 13:56:59 +0100371 codec_param = param_by_pt(codecs[i].payload_type, fmtp_params, fmtp_used);
372 rc = mgcp_codec_add(conn, codecs[i].payload_type, codecs[i].map_line, codec_param);
Philipp Maierbc0346e2018-06-07 09:52:16 +0200373 if (rc < 0)
374 LOGP(DLMGCP, LOGL_NOTICE, "endpoint:0x%x, failed to add codec\n", ENDPOINT_NUMBER(p->endp));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200375 }
376
377 talloc_free(tmp_ctx);
Philipp Maierdbd70c72018-05-25 11:07:31 +0200378
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200379 LOGPCONN(conn->conn, DLMGCP, LOGL_NOTICE,
Philipp Maierbc0346e2018-06-07 09:52:16 +0200380 "Got media info via SDP: port:%d, addr:%s, duration:%d, payload-types:",
381 ntohs(rtp->rtp_port), inet_ntoa(rtp->addr),
382 rtp->packet_duration_ms);
383 if (codecs_used == 0)
384 LOGPC(DLMGCP, LOGL_NOTICE, "none");
385 for (i = 0; i < codecs_used; i++) {
386 LOGPC(DLMGCP, LOGL_NOTICE, "%d=%s",
387 rtp->codecs[i].payload_type,
388 rtp->codecs[i].subtype_name ? rtp-> codecs[i].subtype_name : "unknown");
389 LOGPC(DLMGCP, LOGL_NOTICE, " ");
390 }
391 LOGPC(DLMGCP, LOGL_NOTICE, "\n");
392
Philipp Maierdbd70c72018-05-25 11:07:31 +0200393 return 0;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200394}
395
Philipp Maier8482e832018-08-02 17:22:40 +0200396
397/* Add rtpmap string to the sdp payload, but only when the payload type falls
398 * into the dynamic payload type range */
399static int add_rtpmap(struct msgb *sdp, int payload_type, const char *audio_name)
400{
401 int rc;
402
403 if (payload_type >= 96 && payload_type <= 127) {
404 if (!audio_name)
405 return -EINVAL;
406 rc = msgb_printf(sdp, "a=rtpmap:%d %s\r\n", payload_type, audio_name);
407 if (rc < 0)
408 return -EINVAL;
409 }
410
411 return 0;
412}
413
Philipp Maier217d31d2019-03-05 14:48:56 +0100414/* Add audio strings to sdp payload */
Philipp Maier910189d2018-08-02 17:45:42 +0200415static int add_audio(struct msgb *sdp, int *payload_types, unsigned int payload_types_len, int local_port)
416{
417 int rc;
418 unsigned int i;
419
420 if (payload_types_len < 0)
421 return -EINVAL;
422
423 rc = msgb_printf(sdp, "m=audio %d RTP/AVP", local_port);
424 if (rc < 0)
425 return -EINVAL;
426
427 for (i = 0; i < payload_types_len; i++) {
428 rc = msgb_printf(sdp, " %d", payload_types[i]);
429 if (rc < 0)
430 return -EINVAL;
431 }
432
433 rc = msgb_printf(sdp, "\r\n");
434 if (rc < 0)
435 return -EINVAL;
436
437 return 0;
438}
439
Philipp Maier228e5912019-03-05 13:56:59 +0100440/* Add fmtp strings to sdp payload */
441static int add_fmtp(struct msgb *sdp, struct sdp_fmtp_param *fmtp_params, unsigned int fmtp_params_len,
442 const char *fmtp_extra)
443{
444 unsigned int i;
445 int rc;
446 int fmtp_extra_pt = -1;
447 char *fmtp_extra_pars = "";
448
449 /* When no fmtp parameters ara available but an fmtp extra string
450 * is configured, just add the fmtp extra string */
451 if (fmtp_params_len == 0 && fmtp_extra) {
452 return msgb_printf(sdp, "%s\r\n", fmtp_extra);
453 }
454
455 /* When there is fmtp extra configured we dissect it in order to drop
456 * in the configured extra parameters at the right place when
457 * generating the fmtp strings. */
458 if (fmtp_extra) {
459 if (sscanf(fmtp_extra, "a=fmtp:%d ", &fmtp_extra_pt) != 1)
460 fmtp_extra_pt = -1;
461
462 fmtp_extra_pars = strstr(fmtp_extra, " ");
463
464 if (!fmtp_extra_pars)
465 fmtp_extra_pars = "";
466 else
467 fmtp_extra_pars++;
468 }
469
470 for (i = 0; i < fmtp_params_len; i++) {
471 rc = msgb_printf(sdp, "a=fmtp:%u", fmtp_params[i].payload_type);
472
473 /* Add amr octet align parameter */
474 if (fmtp_params[i].param.amr_octet_aligned_present) {
475 if (fmtp_params[i].param.amr_octet_aligned)
476 rc = msgb_printf(sdp, " octet-align=1");
477 else
478 rc = msgb_printf(sdp, " octet-align=0");
479 if (rc < 0)
480 return -EINVAL;
481 }
482
483 /* Append extra parameters from fmtp extra */
484 if (fmtp_params[i].payload_type == fmtp_extra_pt) {
485 rc = msgb_printf(sdp, " %s", fmtp_extra_pars);
486 if (rc < 0)
487 return -EINVAL;
488 }
489
490 rc = msgb_printf(sdp, "\r\n", fmtp_params[i].payload_type);
491 if (rc < 0)
492 return -EINVAL;
493 }
494
495 return 0;
496}
497
Philipp Maier8970c492017-10-11 13:33:42 +0200498/*! Generate SDP response string.
499 * \param[in] endp trunk endpoint.
500 * \param[in] conn associated rtp connection.
501 * \param[out] sdp msg buffer to append resulting SDP string data.
502 * \param[in] addr IPV4 address string (e.g. 192.168.100.1).
503 * \returns 0 on success, -1 on failure. */
504int mgcp_write_response_sdp(const struct mgcp_endpoint *endp,
505 const struct mgcp_conn_rtp *conn, struct msgb *sdp,
506 const char *addr)
507{
Philipp Maier58128252019-03-06 11:28:18 +0100508 const struct mgcp_rtp_codec *codec;
Philipp Maier8970c492017-10-11 13:33:42 +0200509 const char *fmtp_extra;
510 const char *audio_name;
511 int payload_type;
Philipp Maier228e5912019-03-05 13:56:59 +0100512 struct sdp_fmtp_param fmtp_param;
Philipp Maier8970c492017-10-11 13:33:42 +0200513 int rc;
Philipp Maier910189d2018-08-02 17:45:42 +0200514 int payload_types[1];
Pau Espin Pedrola93c6e92019-05-06 15:23:57 +0200515 int local_port;
Philipp Maier228e5912019-03-05 13:56:59 +0100516 struct sdp_fmtp_param fmtp_params[1];
517 unsigned int fmtp_params_len = 0;
Philipp Maier8970c492017-10-11 13:33:42 +0200518
519 OSMO_ASSERT(endp);
520 OSMO_ASSERT(conn);
521 OSMO_ASSERT(sdp);
522 OSMO_ASSERT(addr);
523
524 /* FIXME: constify endp and conn args in get_net_donwlink_format_cb() */
525 endp->cfg->get_net_downlink_format_cb((struct mgcp_endpoint *)endp,
Philipp Maier58128252019-03-06 11:28:18 +0100526 &codec, &fmtp_extra,
Philipp Maier8970c492017-10-11 13:33:42 +0200527 (struct mgcp_conn_rtp *)conn);
528
Philipp Maier58128252019-03-06 11:28:18 +0100529 audio_name = codec->audio_name;
530 payload_type = codec->payload_type;
531
Philipp Maier8970c492017-10-11 13:33:42 +0200532 rc = msgb_printf(sdp,
533 "v=0\r\n"
Philipp Maier01d24a32017-11-21 17:26:09 +0100534 "o=- %s 23 IN IP4 %s\r\n"
Philipp Maier8970c492017-10-11 13:33:42 +0200535 "s=-\r\n"
536 "c=IN IP4 %s\r\n"
537 "t=0 0\r\n", conn->conn->id, addr, addr);
538
539 if (rc < 0)
540 goto buffer_too_small;
541
542 if (payload_type >= 0) {
Philipp Maier910189d2018-08-02 17:45:42 +0200543
544 payload_types[0] = payload_type;
Pau Espin Pedrola93c6e92019-05-06 15:23:57 +0200545 if (mgcp_conn_rtp_is_osmux(conn))
546 local_port = endp->cfg->osmux_port;
547 else
548 local_port = conn->end.local_port;
549 rc = add_audio(sdp, payload_types, 1, local_port);
Philipp Maier8970c492017-10-11 13:33:42 +0200550 if (rc < 0)
551 goto buffer_too_small;
552
Philipp Maier8482e832018-08-02 17:22:40 +0200553 if (endp->tcfg->audio_send_name) {
554 rc = add_rtpmap(sdp, payload_type, audio_name);
Philipp Maier8970c492017-10-11 13:33:42 +0200555 if (rc < 0)
556 goto buffer_too_small;
557 }
558
Philipp Maier228e5912019-03-05 13:56:59 +0100559 if (codec->param_present) {
560 fmtp_param.payload_type = payload_type;
561 fmtp_param.param = codec->param;
562 fmtp_params[0] = fmtp_param;
563 fmtp_params_len = 1;
Philipp Maier8970c492017-10-11 13:33:42 +0200564 }
Philipp Maier228e5912019-03-05 13:56:59 +0100565 rc = add_fmtp(sdp, fmtp_params, fmtp_params_len, fmtp_extra);
566 if (rc < 0)
567 goto buffer_too_small;
Philipp Maier8970c492017-10-11 13:33:42 +0200568 }
569 if (conn->end.packet_duration_ms > 0 && endp->tcfg->audio_send_ptime) {
570 rc = msgb_printf(sdp, "a=ptime:%u\r\n",
571 conn->end.packet_duration_ms);
572 if (rc < 0)
573 goto buffer_too_small;
574 }
575
576 return 0;
577
578buffer_too_small:
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200579 LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR, "SDP messagebuffer too small\n");
Philipp Maier8970c492017-10-11 13:33:42 +0200580 return -1;
581}