blob: 5fa6bdb56d5d26a83661703f1808533e2b9640a0 [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 Maierc66ab2c2020-06-02 20:55:34 +020028#include <osmocom/mgcp/mgcp_trunk.h>
Philipp Maierbc0346e2018-06-07 09:52:16 +020029#include <osmocom/mgcp/mgcp_codec.h>
Philipp Maier7e37ce62019-03-05 14:00:11 +010030#include <osmocom/mgcp/mgcp_sdp.h>
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020031
32#include <errno.h>
Pau Espin Pedrolc5c14302019-07-23 16:19:41 +020033#include <stdlib.h>
34#include <limits.h>
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020035
Philipp Maier228e5912019-03-05 13:56:59 +010036/* Two structs to store intermediate parsing results. The function
37 * mgcp_parse_sdp_data() is using the following two structs as temporary
38 * storage for parsing the SDP codec information. */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020039struct sdp_rtp_map {
40 /* the type */
41 int payload_type;
42 /* null, static or later dynamic codec name */
43 char *codec_name;
44 /* A pointer to the original line for later parsing */
45 char *map_line;
46
47 int rate;
48 int channels;
49};
Philipp Maier228e5912019-03-05 13:56:59 +010050struct sdp_fmtp_param {
51 int payload_type;
52 struct mgcp_codec_param param;
53};
54
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020055
Philipp Maierbc0346e2018-06-07 09:52:16 +020056/* Helper function to extrapolate missing codec parameters in a codec mao from
57 * an already filled in payload_type, called from: mgcp_parse_sdp_data() */
Philipp Maier8970c492017-10-11 13:33:42 +020058static void codecs_initialize(void *ctx, struct sdp_rtp_map *codecs, int used)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020059{
60 int i;
61
62 for (i = 0; i < used; ++i) {
63 switch (codecs[i].payload_type) {
64 case 0:
65 codecs[i].codec_name = "PCMU";
66 codecs[i].rate = 8000;
67 codecs[i].channels = 1;
68 break;
69 case 3:
70 codecs[i].codec_name = "GSM";
71 codecs[i].rate = 8000;
72 codecs[i].channels = 1;
73 break;
74 case 8:
75 codecs[i].codec_name = "PCMA";
76 codecs[i].rate = 8000;
77 codecs[i].channels = 1;
78 break;
79 case 18:
80 codecs[i].codec_name = "G729";
81 codecs[i].rate = 8000;
82 codecs[i].channels = 1;
83 break;
Philipp Maierbc0346e2018-06-07 09:52:16 +020084 default:
85 codecs[i].codec_name = NULL;
86 codecs[i].rate = 0;
87 codecs[i].channels = 0;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020088 }
89 }
90}
91
Philipp Maierbc0346e2018-06-07 09:52:16 +020092/* Helper function to update codec map information with additional data from
93 * SDP, called from: mgcp_parse_sdp_data() */
Philipp Maier8970c492017-10-11 13:33:42 +020094static void codecs_update(void *ctx, struct sdp_rtp_map *codecs, int used,
95 int payload, const char *audio_name)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020096{
97 int i;
98
99 for (i = 0; i < used; ++i) {
100 char audio_codec[64];
101 int rate = -1;
102 int channels = -1;
Philipp Maierbc0346e2018-06-07 09:52:16 +0200103
104 /* Note: We can only update payload codecs that already exist
105 * in our codec list. If we get an unexpected payload type,
106 * we just drop it */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200107 if (codecs[i].payload_type != payload)
108 continue;
Philipp Maierbc0346e2018-06-07 09:52:16 +0200109
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200110 if (sscanf(audio_name, "%63[^/]/%d/%d",
Philipp Maierd8d7b4b2017-10-18 11:45:35 +0200111 audio_codec, &rate, &channels) < 1) {
112 LOGP(DLMGCP, LOGL_ERROR, "Failed to parse '%s'\n",
113 audio_name);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200114 continue;
115 }
116
117 codecs[i].map_line = talloc_strdup(ctx, audio_name);
118 codecs[i].codec_name = talloc_strdup(ctx, audio_codec);
119 codecs[i].rate = rate;
120 codecs[i].channels = channels;
121 return;
122 }
123
Philipp Maierd8d7b4b2017-10-18 11:45:35 +0200124 LOGP(DLMGCP, LOGL_ERROR, "Unconfigured PT(%d) with %s\n", payload,
125 audio_name);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200126}
127
Philipp Maierbc0346e2018-06-07 09:52:16 +0200128/* Extract payload types from SDP, also check for duplicates */
129static int pt_from_sdp(void *ctx, struct sdp_rtp_map *codecs,
130 unsigned int codecs_len, char *sdp)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200131{
Philipp Maierbc0346e2018-06-07 09:52:16 +0200132 char *str;
133 char *str_ptr;
134 char *pt_str;
Pau Espin Pedrolc5c14302019-07-23 16:19:41 +0200135 char *pt_end;
Pau Espin Pedrola2b1c5e2019-07-26 14:13:14 +0200136 unsigned long int pt;
Philipp Maierbc0346e2018-06-07 09:52:16 +0200137 unsigned int count = 0;
138 unsigned int i;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200139
Philipp Maierbc0346e2018-06-07 09:52:16 +0200140 str = talloc_zero_size(ctx, strlen(sdp) + 1);
141 str_ptr = str;
142 strcpy(str_ptr, sdp);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200143
Philipp Maierbc0346e2018-06-07 09:52:16 +0200144 str_ptr = strstr(str_ptr, "RTP/AVP ");
145 if (!str_ptr)
146 goto exit;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200147
Philipp Maierbc0346e2018-06-07 09:52:16 +0200148 pt_str = strtok(str_ptr, " ");
149 if (!pt_str)
150 goto exit;
151
152 while (1) {
153 /* Do not allow excessive payload types */
154 if (count > codecs_len)
155 goto error;
156
157 pt_str = strtok(NULL, " ");
158 if (!pt_str)
159 break;
160
Pau Espin Pedrolc5c14302019-07-23 16:19:41 +0200161 errno = 0;
162 pt = strtoul(pt_str, &pt_end, 0);
163 if ((errno == ERANGE && pt == ULONG_MAX) || (errno && !pt) ||
164 pt_str == pt_end)
165 goto error;
Philipp Maierbc0346e2018-06-07 09:52:16 +0200166
Pau Espin Pedrola2b1c5e2019-07-26 14:13:14 +0200167 if (pt >> 7) /* PT is 7 bit field, higher values not allowed */
168 goto error;
169
Philipp Maierbc0346e2018-06-07 09:52:16 +0200170 /* Do not allow duplicate payload types */
171 for (i = 0; i < count; i++)
172 if (codecs[i].payload_type == pt)
173 goto error;
174
175 codecs[count].payload_type = pt;
176 count++;
177 }
178
179exit:
180 talloc_free(str);
181 return count;
182error:
183 talloc_free(str);
184 return -EINVAL;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200185}
186
Philipp Maier228e5912019-03-05 13:56:59 +0100187/* Extract fmtp parameters from SDP, called from: mgcp_parse_sdp_data() */
188static int fmtp_from_sdp(void *ctx, struct sdp_fmtp_param *fmtp_param, char *sdp)
189{
190 char *str;
191 char *str_ptr;
192 char *param_str;
193 unsigned int pt;
194 unsigned int count = 0;
195 char delimiter;
196 unsigned int amr_octet_aligned;
197
198 memset(fmtp_param, 0, sizeof(*fmtp_param));
199
200 str = talloc_zero_size(ctx, strlen(sdp) + 1);
201 str_ptr = str;
202 strcpy(str_ptr, sdp);
203
204 /* Check if the input string begins with an fmtp token */
205 str_ptr = strstr(str_ptr, "fmtp:");
206 if (!str_ptr)
207 goto exit;
208 str_ptr += 5;
209
210 /* Extract payload type */
211 if (sscanf(str_ptr, "%u ", &pt) != 1)
212 goto error;
213 fmtp_param->payload_type = pt;
214
215 /* Advance pointer to the beginning of the parameter section and
216 * tokenize string */
217 str_ptr = strstr(str_ptr, " ");
218 if (!str_ptr)
219 goto error;
220 str_ptr++;
221
222 param_str = strtok(str_ptr, " ");
223 if (!param_str)
224 goto exit;
225
226 while (1) {
227 /* Make sure that we don't get trapped in an endless loop */
228 if (count > 256)
229 goto error;
230
231 /* Chop off delimiters ';' at the end */
232 delimiter = str_ptr[strlen(str_ptr) - 1];
233 if (delimiter == ';' || delimiter == ',')
234 str_ptr[strlen(str_ptr) - 1] = '\0';
235
236 /* AMR octet aligned parameter */
237 if (sscanf(param_str, "octet-align=%d", &amr_octet_aligned) == 1) {
238 fmtp_param->param.amr_octet_aligned_present = true;
239 fmtp_param->param.amr_octet_aligned = false;
240 if (amr_octet_aligned == 1)
241 fmtp_param->param.amr_octet_aligned = true;
242
243 }
244
245 param_str = strtok(NULL, " ");
246 if (!param_str)
247 break;
248 count++;
249 }
250
251exit:
252 talloc_free(str);
253 return 0;
254error:
255 talloc_free(str);
256 return -EINVAL;
257}
258
259/* Pick optional fmtp parameters by payload type, if there are no fmtp
260 * parameters, a nullpointer is returned */
261static struct mgcp_codec_param *param_by_pt(int pt, struct sdp_fmtp_param *fmtp_params, unsigned int fmtp_params_len)
262{
263 unsigned int i;
264
265 for (i = 0; i < fmtp_params_len; i++) {
266 if (fmtp_params[i].payload_type == pt)
267 return &fmtp_params[i].param;
268 }
269
270 return NULL;
271}
272
Philipp Maier8970c492017-10-11 13:33:42 +0200273/*! Analyze SDP input string.
274 * \param[in] endp trunk endpoint.
275 * \param[out] conn associated rtp connection.
276 * \param[out] caller provided memory to store the parsing results.
Philipp Maier8970c492017-10-11 13:33:42 +0200277 *
278 * Note: In conn (conn->end) the function returns the packet duration,
Philipp Maierbc0346e2018-06-07 09:52:16 +0200279 * rtp port, rtcp port and the codec information.
280 * \returns 0 on success, -1 on failure. */
Philipp Maier8970c492017-10-11 13:33:42 +0200281int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
Philipp Maierbc0346e2018-06-07 09:52:16 +0200282 struct mgcp_conn_rtp *conn, struct mgcp_parse_data *p)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200283{
Philipp Maierbc0346e2018-06-07 09:52:16 +0200284 struct sdp_rtp_map codecs[MGCP_MAX_CODECS];
285 unsigned int codecs_used = 0;
Philipp Maier228e5912019-03-05 13:56:59 +0100286 struct sdp_fmtp_param fmtp_params[MGCP_MAX_CODECS];
287 unsigned int fmtp_used = 0;
288 struct mgcp_codec_param *codec_param;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200289 char *line;
Philipp Maierbc0346e2018-06-07 09:52:16 +0200290 unsigned int i;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200291 void *tmp_ctx = talloc_new(NULL);
Philipp Maier8970c492017-10-11 13:33:42 +0200292 struct mgcp_rtp_end *rtp;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200293
Philipp Maierc7a228a2017-10-18 11:42:25 +0200294 int payload;
295 int ptime, ptime2 = 0;
296 char audio_name[64];
297 int port, rc;
298 char ipv4[16];
299
Philipp Maier8970c492017-10-11 13:33:42 +0200300 OSMO_ASSERT(endp);
301 OSMO_ASSERT(conn);
302 OSMO_ASSERT(p);
303
304 rtp = &conn->end;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200305 memset(&codecs, 0, sizeof(codecs));
306
307 for_each_line(line, p->save) {
308 switch (line[0]) {
309 case 'o':
310 case 's':
311 case 't':
312 case 'v':
313 /* skip these SDP attributes */
314 break;
Philipp Maierc7a228a2017-10-18 11:42:25 +0200315 case 'a':
Philipp Maiere7ae69a2019-03-05 15:17:36 +0100316 if (sscanf(line, "a=rtpmap:%d %63s", &payload, audio_name) == 2) {
317 codecs_update(tmp_ctx, codecs, codecs_used, payload, audio_name);
318 break;
319 }
320
321 if (sscanf(line, "a=ptime:%d-%d", &ptime, &ptime2) >= 1) {
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200322 if (ptime2 > 0 && ptime2 != ptime)
323 rtp->packet_duration_ms = 0;
324 else
325 rtp->packet_duration_ms = ptime;
Philipp Maiere7ae69a2019-03-05 15:17:36 +0100326 break;
327 }
328
329 if (sscanf(line, "a=maxptime:%d", &ptime2) == 1) {
Philipp Maierbc0346e2018-06-07 09:52:16 +0200330 rtp->maximum_packet_time = ptime2;
Philipp Maiere7ae69a2019-03-05 15:17:36 +0100331 break;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200332 }
Philipp Maier228e5912019-03-05 13:56:59 +0100333
334 if (strncmp("a=fmtp:", line, 6) == 0) {
335 rc = fmtp_from_sdp(conn->conn, &fmtp_params[fmtp_used], line);
336 if (rc >= 0)
337 fmtp_used++;
338 break;
339 }
340
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200341 break;
Philipp Maierc7a228a2017-10-18 11:42:25 +0200342 case 'm':
Philipp Maierbc0346e2018-06-07 09:52:16 +0200343 rc = sscanf(line, "m=audio %d RTP/AVP", &port);
344 if (rc == 1) {
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200345 rtp->rtp_port = htons(port);
346 rtp->rtcp_port = htons(port + 1);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200347 }
Philipp Maierbc0346e2018-06-07 09:52:16 +0200348
349 rc = pt_from_sdp(conn->conn, codecs,
350 ARRAY_SIZE(codecs), line);
351 if (rc > 0)
352 codecs_used = rc;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200353 break;
Philipp Maierc7a228a2017-10-18 11:42:25 +0200354 case 'c':
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200355
356 if (sscanf(line, "c=IN IP4 %15s", ipv4) == 1) {
357 inet_aton(ipv4, &rtp->addr);
358 }
359 break;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200360 default:
361 if (p->endp)
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200362 /* TODO: Check spec: We used the bare endpoint number before,
363 * now we use the endpoint name as a whole? Is this allowed? */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200364 LOGP(DLMGCP, LOGL_NOTICE,
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200365 "Unhandled SDP option: '%c'/%d on %s\n",
366 line[0], line[0], endp->name);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200367 else
368 LOGP(DLMGCP, LOGL_NOTICE,
369 "Unhandled SDP option: '%c'/%d\n",
370 line[0], line[0]);
371 break;
372 }
373 }
Philipp Maierbc0346e2018-06-07 09:52:16 +0200374 OSMO_ASSERT(codecs_used <= MGCP_MAX_CODECS);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200375
Philipp Maierbc0346e2018-06-07 09:52:16 +0200376 /* So far we have only set the payload type in the codec struct. Now we
377 * fill up the remaining fields of the codec description with some default
378 * information */
379 codecs_initialize(tmp_ctx, codecs, codecs_used);
380
381 /* Store parsed codec information */
Philipp Maierdbd70c72018-05-25 11:07:31 +0200382 for (i = 0; i < codecs_used; i++) {
Philipp Maier228e5912019-03-05 13:56:59 +0100383 codec_param = param_by_pt(codecs[i].payload_type, fmtp_params, fmtp_used);
384 rc = mgcp_codec_add(conn, codecs[i].payload_type, codecs[i].map_line, codec_param);
Philipp Maierbc0346e2018-06-07 09:52:16 +0200385 if (rc < 0)
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200386 LOGPENDP(endp, DLMGCP, LOGL_NOTICE, "failed to add codec\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200387 }
388
389 talloc_free(tmp_ctx);
Philipp Maierdbd70c72018-05-25 11:07:31 +0200390
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200391 LOGPCONN(conn->conn, DLMGCP, LOGL_NOTICE,
Philipp Maierbc0346e2018-06-07 09:52:16 +0200392 "Got media info via SDP: port:%d, addr:%s, duration:%d, payload-types:",
393 ntohs(rtp->rtp_port), inet_ntoa(rtp->addr),
394 rtp->packet_duration_ms);
395 if (codecs_used == 0)
396 LOGPC(DLMGCP, LOGL_NOTICE, "none");
397 for (i = 0; i < codecs_used; i++) {
398 LOGPC(DLMGCP, LOGL_NOTICE, "%d=%s",
399 rtp->codecs[i].payload_type,
400 rtp->codecs[i].subtype_name ? rtp-> codecs[i].subtype_name : "unknown");
401 LOGPC(DLMGCP, LOGL_NOTICE, " ");
402 }
403 LOGPC(DLMGCP, LOGL_NOTICE, "\n");
404
Philipp Maierdbd70c72018-05-25 11:07:31 +0200405 return 0;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200406}
407
Philipp Maier8482e832018-08-02 17:22:40 +0200408
409/* Add rtpmap string to the sdp payload, but only when the payload type falls
410 * into the dynamic payload type range */
411static int add_rtpmap(struct msgb *sdp, int payload_type, const char *audio_name)
412{
413 int rc;
414
415 if (payload_type >= 96 && payload_type <= 127) {
416 if (!audio_name)
417 return -EINVAL;
418 rc = msgb_printf(sdp, "a=rtpmap:%d %s\r\n", payload_type, audio_name);
419 if (rc < 0)
420 return -EINVAL;
421 }
422
423 return 0;
424}
425
Philipp Maier217d31d2019-03-05 14:48:56 +0100426/* Add audio strings to sdp payload */
Philipp Maier910189d2018-08-02 17:45:42 +0200427static int add_audio(struct msgb *sdp, int *payload_types, unsigned int payload_types_len, int local_port)
428{
429 int rc;
430 unsigned int i;
431
Philipp Maier910189d2018-08-02 17:45:42 +0200432 rc = msgb_printf(sdp, "m=audio %d RTP/AVP", local_port);
433 if (rc < 0)
434 return -EINVAL;
435
436 for (i = 0; i < payload_types_len; i++) {
437 rc = msgb_printf(sdp, " %d", payload_types[i]);
438 if (rc < 0)
439 return -EINVAL;
440 }
441
442 rc = msgb_printf(sdp, "\r\n");
443 if (rc < 0)
444 return -EINVAL;
445
446 return 0;
447}
448
Philipp Maier228e5912019-03-05 13:56:59 +0100449/* Add fmtp strings to sdp payload */
450static int add_fmtp(struct msgb *sdp, struct sdp_fmtp_param *fmtp_params, unsigned int fmtp_params_len,
451 const char *fmtp_extra)
452{
453 unsigned int i;
454 int rc;
455 int fmtp_extra_pt = -1;
456 char *fmtp_extra_pars = "";
457
458 /* When no fmtp parameters ara available but an fmtp extra string
459 * is configured, just add the fmtp extra string */
460 if (fmtp_params_len == 0 && fmtp_extra) {
461 return msgb_printf(sdp, "%s\r\n", fmtp_extra);
462 }
463
464 /* When there is fmtp extra configured we dissect it in order to drop
465 * in the configured extra parameters at the right place when
466 * generating the fmtp strings. */
467 if (fmtp_extra) {
468 if (sscanf(fmtp_extra, "a=fmtp:%d ", &fmtp_extra_pt) != 1)
469 fmtp_extra_pt = -1;
470
471 fmtp_extra_pars = strstr(fmtp_extra, " ");
472
473 if (!fmtp_extra_pars)
474 fmtp_extra_pars = "";
475 else
476 fmtp_extra_pars++;
477 }
478
479 for (i = 0; i < fmtp_params_len; i++) {
480 rc = msgb_printf(sdp, "a=fmtp:%u", fmtp_params[i].payload_type);
Vadim Yanitskiy13fae782020-07-07 14:12:26 +0700481 if (rc < 0)
482 return -EINVAL;
Philipp Maier228e5912019-03-05 13:56:59 +0100483
484 /* Add amr octet align parameter */
485 if (fmtp_params[i].param.amr_octet_aligned_present) {
486 if (fmtp_params[i].param.amr_octet_aligned)
487 rc = msgb_printf(sdp, " octet-align=1");
488 else
489 rc = msgb_printf(sdp, " octet-align=0");
490 if (rc < 0)
491 return -EINVAL;
492 }
493
494 /* Append extra parameters from fmtp extra */
495 if (fmtp_params[i].payload_type == fmtp_extra_pt) {
496 rc = msgb_printf(sdp, " %s", fmtp_extra_pars);
497 if (rc < 0)
498 return -EINVAL;
499 }
500
Vadim Yanitskiyb7d395d2020-07-07 14:09:45 +0700501 rc = msgb_printf(sdp, "\r\n");
Philipp Maier228e5912019-03-05 13:56:59 +0100502 if (rc < 0)
503 return -EINVAL;
504 }
505
506 return 0;
507}
508
Philipp Maier8970c492017-10-11 13:33:42 +0200509/*! Generate SDP response string.
510 * \param[in] endp trunk endpoint.
511 * \param[in] conn associated rtp connection.
512 * \param[out] sdp msg buffer to append resulting SDP string data.
513 * \param[in] addr IPV4 address string (e.g. 192.168.100.1).
514 * \returns 0 on success, -1 on failure. */
515int mgcp_write_response_sdp(const struct mgcp_endpoint *endp,
516 const struct mgcp_conn_rtp *conn, struct msgb *sdp,
517 const char *addr)
518{
Philipp Maier58128252019-03-06 11:28:18 +0100519 const struct mgcp_rtp_codec *codec;
Philipp Maier8970c492017-10-11 13:33:42 +0200520 const char *fmtp_extra;
521 const char *audio_name;
522 int payload_type;
Philipp Maier228e5912019-03-05 13:56:59 +0100523 struct sdp_fmtp_param fmtp_param;
Philipp Maier8970c492017-10-11 13:33:42 +0200524 int rc;
Philipp Maier910189d2018-08-02 17:45:42 +0200525 int payload_types[1];
Pau Espin Pedrola93c6e92019-05-06 15:23:57 +0200526 int local_port;
Philipp Maier228e5912019-03-05 13:56:59 +0100527 struct sdp_fmtp_param fmtp_params[1];
528 unsigned int fmtp_params_len = 0;
Philipp Maier8970c492017-10-11 13:33:42 +0200529
530 OSMO_ASSERT(endp);
531 OSMO_ASSERT(conn);
532 OSMO_ASSERT(sdp);
533 OSMO_ASSERT(addr);
534
535 /* FIXME: constify endp and conn args in get_net_donwlink_format_cb() */
536 endp->cfg->get_net_downlink_format_cb((struct mgcp_endpoint *)endp,
Philipp Maier58128252019-03-06 11:28:18 +0100537 &codec, &fmtp_extra,
Philipp Maier8970c492017-10-11 13:33:42 +0200538 (struct mgcp_conn_rtp *)conn);
539
Philipp Maier58128252019-03-06 11:28:18 +0100540 audio_name = codec->audio_name;
541 payload_type = codec->payload_type;
542
Philipp Maier8970c492017-10-11 13:33:42 +0200543 rc = msgb_printf(sdp,
544 "v=0\r\n"
Philipp Maier01d24a32017-11-21 17:26:09 +0100545 "o=- %s 23 IN IP4 %s\r\n"
Philipp Maier8970c492017-10-11 13:33:42 +0200546 "s=-\r\n"
547 "c=IN IP4 %s\r\n"
548 "t=0 0\r\n", conn->conn->id, addr, addr);
549
550 if (rc < 0)
551 goto buffer_too_small;
552
553 if (payload_type >= 0) {
Philipp Maier910189d2018-08-02 17:45:42 +0200554
555 payload_types[0] = payload_type;
Pau Espin Pedrola93c6e92019-05-06 15:23:57 +0200556 if (mgcp_conn_rtp_is_osmux(conn))
557 local_port = endp->cfg->osmux_port;
558 else
559 local_port = conn->end.local_port;
560 rc = add_audio(sdp, payload_types, 1, local_port);
Philipp Maier8970c492017-10-11 13:33:42 +0200561 if (rc < 0)
562 goto buffer_too_small;
563
Philipp Maier14b27a82020-06-02 20:15:30 +0200564 if (endp->trunk->audio_send_name) {
Philipp Maier8482e832018-08-02 17:22:40 +0200565 rc = add_rtpmap(sdp, payload_type, audio_name);
Philipp Maier8970c492017-10-11 13:33:42 +0200566 if (rc < 0)
567 goto buffer_too_small;
568 }
569
Philipp Maier228e5912019-03-05 13:56:59 +0100570 if (codec->param_present) {
571 fmtp_param.payload_type = payload_type;
572 fmtp_param.param = codec->param;
573 fmtp_params[0] = fmtp_param;
574 fmtp_params_len = 1;
Philipp Maier8970c492017-10-11 13:33:42 +0200575 }
Philipp Maier228e5912019-03-05 13:56:59 +0100576 rc = add_fmtp(sdp, fmtp_params, fmtp_params_len, fmtp_extra);
577 if (rc < 0)
578 goto buffer_too_small;
Philipp Maier8970c492017-10-11 13:33:42 +0200579 }
Philipp Maier14b27a82020-06-02 20:15:30 +0200580 if (conn->end.packet_duration_ms > 0 && endp->trunk->audio_send_ptime) {
Philipp Maier8970c492017-10-11 13:33:42 +0200581 rc = msgb_printf(sdp, "a=ptime:%u\r\n",
582 conn->end.packet_duration_ms);
583 if (rc < 0)
584 goto buffer_too_small;
585 }
586
587 return 0;
588
589buffer_too_small:
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200590 LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR, "SDP messagebuffer too small\n");
Philipp Maier8970c492017-10-11 13:33:42 +0200591 return -1;
592}