blob: d105ca8d1ff8c07f7c18e034912929a6022c5b6d [file] [log] [blame]
Harald Welte41d0d842011-09-03 15:33:24 +02001/* (C) 2011 by Harald Welte <laforge@gnumonks.org>
2 * (C) 2011 by On-Waves e.h.f
3 * All Rights Reserved
4 *
Harald Welte323d39d2017-11-13 01:09:21 +09005 * SPDX-License-Identifier: GPL-2.0+
6 *
Harald Welte41d0d842011-09-03 15:33:24 +02007 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 */
22
23/*! \file osmo_ortp.c
24 * \brief Integration of libortp into osmocom framework (select, logging)
25 */
26
27#include <stdint.h>
Max73b9bc72016-05-18 15:52:37 +020028#include <stdbool.h>
Harald Welte65a50892011-09-08 14:42:58 +020029#include <inttypes.h>
Harald Welte41d0d842011-09-03 15:33:24 +020030#include <netdb.h>
31
32#include <osmocom/core/logging.h>
33#include <osmocom/core/talloc.h>
34#include <osmocom/core/utils.h>
35#include <osmocom/core/select.h>
36#include <osmocom/trau/osmo_ortp.h>
37
38#include <ortp/ortp.h>
Harald Welte65a50892011-09-08 14:42:58 +020039#include <ortp/rtp.h>
Harald Welte0b5ffc12011-10-22 15:58:02 +020040#include <ortp/port.h>
Harald Weltee7a3f432013-02-19 13:35:22 +010041#include <ortp/rtpsession.h>
Harald Welte41d0d842011-09-03 15:33:24 +020042
Harald Welte2bfc01d2013-10-06 12:23:35 +020043#include "config.h"
Harald Welte41d0d842011-09-03 15:33:24 +020044
45static PayloadType *payload_type_efr;
46static PayloadType *payload_type_hr;
47static RtpProfile *osmo_pt_profile;
48
49static void *tall_rtp_ctx;
50
51/* malloc integration */
52
53static void *osmo_ortp_malloc(size_t sz)
54{
55 return talloc_size(tall_rtp_ctx, sz);
56}
57
58static void *osmo_ortp_realloc(void *ptr, size_t sz)
59{
60 return talloc_realloc_size(tall_rtp_ctx, ptr, sz);
61}
62
63static void osmo_ortp_free(void *ptr)
64{
65 talloc_free(ptr);
66}
67
68static OrtpMemoryFunctions osmo_ortp_memfn = {
69 .malloc_fun = osmo_ortp_malloc,
70 .realloc_fun = osmo_ortp_realloc,
71 .free_fun = osmo_ortp_free
72};
73
74/* logging */
75
76struct level_map {
77 OrtpLogLevel ortp;
78 int osmo_level;
79};
80static const struct level_map level_map[] = {
81 { ORTP_DEBUG, LOGL_DEBUG },
82 { ORTP_MESSAGE, LOGL_INFO },
83 { ORTP_WARNING, LOGL_NOTICE },
84 { ORTP_ERROR, LOGL_ERROR },
85 { ORTP_FATAL, LOGL_FATAL },
86};
87static int ortp_to_osmo_lvl(OrtpLogLevel lev)
88{
89 int i;
90
91 for (i = 0; i < ARRAY_SIZE(level_map); i++) {
92 if (level_map[i].ortp == lev)
93 return level_map[i].osmo_level;
94 }
95 /* default */
96 return LOGL_ERROR;
97}
98
Pau Espin Pedrolc42bf192017-03-24 17:26:49 +010099static void my_ortp_logfn(
100#if HAVE_ORTP_LOG_DOMAIN
101 const char *domain,
102#endif
103 OrtpLogLevel lev, const char *fmt, va_list args)
Harald Welte41d0d842011-09-03 15:33:24 +0200104{
Pau Espin Pedrolde5758d2018-11-12 17:00:22 +0100105 /* Some strings coming from ortp are not endline terminated and mangle
106 * the output. Make sure all strings are endl terminated before
107 * printing.
108 */
109 int needs_endl;
110 const char *domain_str;
111 char *str;
112 size_t fmt_len = strlen(fmt);
113#if HAVE_ORTP_LOG_DOMAIN
114 /* domain can be NULL, found experimentally */
115 domain_str = domain ? : "";
116#else
117 domain_str = "";
118#endif
119 size_t domain_len = strlen(domain_str);
120
121 if (fmt_len == 0)
122 return;
123
124 needs_endl = fmt[fmt_len - 1] != '\n' ? 1 : 0;
125
126 str = osmo_ortp_malloc(domain_len + 2 /*": "*/ + fmt_len + needs_endl + 1);
127 sprintf(str, "%s%s%s%s", domain_str, domain_len ? ": " : "", fmt, needs_endl ? "\n" : "");
128
Harald Welte41d0d842011-09-03 15:33:24 +0200129 osmo_vlogp(DLMIB, ortp_to_osmo_lvl(lev), __FILE__, 0,
Pau Espin Pedrolde5758d2018-11-12 17:00:22 +0100130 0, str, args);
131
132 osmo_ortp_free(str);
133
Harald Welte41d0d842011-09-03 15:33:24 +0200134}
135
136/* ORTP signal callbacks */
137
138static void ortp_sig_cb_ssrc(RtpSession *rs, void *data)
139{
Harald Weltee7a3f432013-02-19 13:35:22 +0100140 int port = rtp_session_get_local_port(rs);
Harald Weltee7a3f432013-02-19 13:35:22 +0100141 uint32_t ssrc = rtp_session_get_recv_ssrc(rs);
Harald Weltee7a3f432013-02-19 13:35:22 +0100142
143 LOGP(DLMIB, LOGL_INFO,
Philipp Maier28eeb6b2018-05-30 10:52:41 +0200144 "osmo-ortp(%d): ssrc_changed to 0x%08x, resetting\n", port, ssrc);
145 rtp_session_reset(rs);
Harald Welte41d0d842011-09-03 15:33:24 +0200146}
147
148static void ortp_sig_cb_pt(RtpSession *rs, void *data)
149{
Harald Weltee7a3f432013-02-19 13:35:22 +0100150 int port = rtp_session_get_local_port(rs);
151 int pt = rtp_session_get_recv_payload_type(rs);
152
153 LOGP(DLMIB, LOGL_NOTICE,
154 "osmo-ortp(%d): payload_type_changed to 0x%02x\n", port, pt);
Harald Welte41d0d842011-09-03 15:33:24 +0200155}
156
157static void ortp_sig_cb_net(RtpSession *rs, void *data)
158{
Harald Weltee7a3f432013-02-19 13:35:22 +0100159 int port = rtp_session_get_local_port(rs);
160
161 LOGP(DLMIB, LOGL_ERROR,
Max7c840be2016-12-05 16:13:53 +0100162 "osmo-ortp(%d): network_error %s\n", port, (char *)data);
Harald Welte41d0d842011-09-03 15:33:24 +0200163}
164
165static void ortp_sig_cb_ts(RtpSession *rs, void *data)
166{
Harald Weltee7a3f432013-02-19 13:35:22 +0100167 int port = rtp_session_get_local_port(rs);
168 uint32_t ts = rtp_session_get_current_recv_ts(rs);
169
170 LOGP(DLMIB, LOGL_NOTICE,
Yves Godin2c32f0a2016-10-06 15:55:06 +0200171 "osmo-ortp(%d): timestamp_jump, new TS %d, resyncing\n", port, ts);
172 rtp_session_resync(rs);
Harald Welte41d0d842011-09-03 15:33:24 +0200173}
174
Maxf6906002016-10-24 14:10:10 +0200175static inline bool recv_with_cb(struct osmo_rtp_socket *rs)
176{
Harald Welte7895e042016-10-28 10:40:24 +0200177 uint8_t *payload;
Maxf6906002016-10-24 14:10:10 +0200178 mblk_t *mblk = rtp_session_recvm_with_ts(rs->sess, rs->rx_user_ts);
179 if (!mblk)
180 return false;
181
Harald Welte7895e042016-10-28 10:40:24 +0200182 int plen = rtp_get_payload(mblk, &payload);
Maxf6906002016-10-24 14:10:10 +0200183 /* hand into receiver */
184 if (rs->rx_cb && plen > 0)
Harald Welte7895e042016-10-28 10:40:24 +0200185 rs->rx_cb(rs, payload, plen, rtp_get_seqnumber(mblk),
Maxf6906002016-10-24 14:10:10 +0200186 rtp_get_timestamp(mblk), rtp_get_markbit(mblk));
187 freemsg(mblk);
188 if (plen > 0)
189 return true;
190 return false;
191}
Harald Welte41d0d842011-09-03 15:33:24 +0200192
Harald Welte9b737df2011-09-07 00:59:11 +0200193/*! \brief poll the socket for incoming data
194 * \param[in] rs the socket to be polled
195 * \returns number of packets received + handed to the rx_cb
196 */
197int osmo_rtp_socket_poll(struct osmo_rtp_socket *rs)
198{
Maxe54d7bc2016-04-29 12:39:33 +0200199 if (rs->flags & OSMO_RTP_F_DISABLED)
200 return 0;
Harald Welte9b737df2011-09-07 00:59:11 +0200201
Maxf6906002016-10-24 14:10:10 +0200202 if (recv_with_cb(rs))
Harald Welte9b737df2011-09-07 00:59:11 +0200203 return 1;
Maxf6906002016-10-24 14:10:10 +0200204
Harald Welte8c724c02021-02-06 15:25:39 +0100205 /* this happens every time we miss an incoming RTP frame, which is quite common
206 * when a voice channel is first activated, or also in case of packet loss.
207 * See also https://osmocom.org/issues/4464 */
208 LOGP(DLMIB, LOGL_DEBUG, "osmo_rtp_socket_poll(%u): No message received\n", rs->rx_user_ts);
Maxf6906002016-10-24 14:10:10 +0200209 return 0;
Harald Welte9b737df2011-09-07 00:59:11 +0200210}
211
Harald Welte41d0d842011-09-03 15:33:24 +0200212/* Osmo FD callbacks */
213
214static int osmo_rtp_fd_cb(struct osmo_fd *fd, unsigned int what)
215{
216 struct osmo_rtp_socket *rs = fd->data;
Harald Welte41d0d842011-09-03 15:33:24 +0200217
Harald Weltede3959e2020-10-18 22:28:50 +0200218 if (what & OSMO_FD_READ) {
Harald Welte9b737df2011-09-07 00:59:11 +0200219 /* in polling mode, we don't want to be called here */
220 if (rs->flags & OSMO_RTP_F_POLL) {
Harald Welte949b8a22020-10-18 23:01:53 +0200221 osmo_fd_read_disable(fd);
Harald Welte9b737df2011-09-07 00:59:11 +0200222 return 0;
223 }
Maxf6906002016-10-24 14:10:10 +0200224 if (!recv_with_cb(rs))
Harald Welte9b737df2011-09-07 00:59:11 +0200225 LOGP(DLMIB, LOGL_INFO, "recvm_with_ts(%u): ERROR!\n",
226 rs->rx_user_ts);
Harald Welte41d0d842011-09-03 15:33:24 +0200227 rs->rx_user_ts += 160;
228 }
Harald Weltede3959e2020-10-18 22:28:50 +0200229 /* writing is not queued at the moment, so OSMO_FD_WRITE
Harald Welte41d0d842011-09-03 15:33:24 +0200230 * shouldn't occur */
231 return 0;
232}
233
Pau Espin Pedrolb0c3a4a2017-06-21 07:25:18 +0200234/* Internal API coming from rtpsession_priv.h, used in osmo_rtcp_fd_cb */
235#pragma message ("Using internal ortp API: rtp_session_rtcp_rec")
236int rtp_session_rtcp_recv(RtpSession * session);
237
Harald Welte41d0d842011-09-03 15:33:24 +0200238static int osmo_rtcp_fd_cb(struct osmo_fd *fd, unsigned int what)
239{
240 struct osmo_rtp_socket *rs = fd->data;
241
242 /* We probably don't need this at all, as
243 * rtp_session_recvm_with_ts() will alway also poll the RTCP
244 * file descriptor for new data */
245 return rtp_session_rtcp_recv(rs->sess);
246}
247
248static int osmo_rtp_socket_fdreg(struct osmo_rtp_socket *rs)
249{
Harald Welte34260c82016-11-26 09:27:04 +0100250 int rc;
251
Harald Welte6e831b72020-10-18 22:59:58 +0200252 osmo_fd_setup(&rs->rtp_bfd, rtp_session_get_rtp_socket(rs->sess), OSMO_FD_READ, osmo_rtp_fd_cb, rs, 0);
253 osmo_fd_setup(&rs->rtcp_bfd, rtp_session_get_rtcp_socket(rs->sess), OSMO_FD_READ, osmo_rtcp_fd_cb, rs, 0);
Harald Welte41d0d842011-09-03 15:33:24 +0200254
Harald Welte34260c82016-11-26 09:27:04 +0100255 rc = osmo_fd_register(&rs->rtp_bfd);
256 if (rc < 0)
257 return rc;
258
259 rc = osmo_fd_register(&rs->rtcp_bfd);
260 if (rc < 0) {
261 osmo_fd_unregister(&rs->rtp_bfd);
262 return rc;
263 }
Harald Welte41d0d842011-09-03 15:33:24 +0200264
265 return 0;
266}
267
268static void create_payload_types()
269{
270 PayloadType *pt;
271
272 /* EFR */
273 pt = payload_type_new();
274 pt->type = PAYLOAD_AUDIO_PACKETIZED;
275 pt->clock_rate = 8000;
276 pt->mime_type = "EFR";
277 pt->normal_bitrate = 12200;
278 pt->channels = 1;
279 payload_type_efr = pt;
280
281 /* HR */
282 pt = payload_type_new();
283 pt->type = PAYLOAD_AUDIO_PACKETIZED;
284 pt->clock_rate = 8000;
285 pt->mime_type = "HR";
286 pt->normal_bitrate = 6750; /* FIXME */
287 pt->channels = 1;
288 payload_type_hr = pt;
289
290 /* create a new RTP profile as clone of AV profile */
291 osmo_pt_profile = rtp_profile_clone(&av_profile);
292
293 /* add the GSM specific payload types. They are all dynamically
294 * assigned, but in the Osmocom GSM system we have allocated
295 * them as follows: */
296 rtp_profile_set_payload(osmo_pt_profile, RTP_PT_GSM_EFR, payload_type_efr);
297 rtp_profile_set_payload(osmo_pt_profile, RTP_PT_GSM_HALF, payload_type_hr);
298 rtp_profile_set_payload(osmo_pt_profile, RTP_PT_AMR, &payload_type_amr);
299}
300
301/* public functions */
302
303/*! \brief initialize Osmocom RTP code
Harald Weltefcb1fe82011-09-07 11:51:52 +0200304 * \param[in] ctx default talloc context for library-internal allocations
Harald Welte41d0d842011-09-03 15:33:24 +0200305 */
306void osmo_rtp_init(void *ctx)
307{
308 tall_rtp_ctx = ctx;
309 ortp_set_memory_functions(&osmo_ortp_memfn);
310 ortp_init();
Pau Espin Pedrolc42bf192017-03-24 17:26:49 +0100311 ortp_set_log_level_mask(
312#if HAVE_ORTP_LOG_DOMAIN
313 ORTP_LOG_DOMAIN,
314#endif
315 0xffff);
316
Harald Welte41d0d842011-09-03 15:33:24 +0200317 ortp_set_log_handler(my_ortp_logfn);
318 create_payload_types();
319}
320
Maxbf42e0a2016-12-15 19:57:57 +0100321/*! \brief Set Osmocom RTP socket parameters
322 * \param[in] rs OsmoRTP socket
323 * \param[in] param defined which parameter to set
324 OSMO_RTP_P_JITBUF - enables regular jitter buffering
325 OSMO_RTP_P_JIT_ADAP - enables adaptive jitter buffering
326 * \param[in] val Size of jitter buffer (in ms), 0 means disable buffering
327 * \returns negative value on error, 0 or 1 otherwise
328 (depending on whether given jitter buffering is enabled)
329 */
Harald Welte65a50892011-09-08 14:42:58 +0200330int osmo_rtp_socket_set_param(struct osmo_rtp_socket *rs,
331 enum osmo_rtp_param param, int val)
332{
Harald Welte65a50892011-09-08 14:42:58 +0200333 switch (param) {
Maxbf42e0a2016-12-15 19:57:57 +0100334 case OSMO_RTP_P_JIT_ADAP:
335 rtp_session_enable_adaptive_jitter_compensation(rs->sess,
336 (bool)val);
337 /* fall-through on-purpose - we have to set val anyway */
Harald Welte65a50892011-09-08 14:42:58 +0200338 case OSMO_RTP_P_JITBUF:
Andreas Eversberg41bc6152013-02-14 11:03:26 +0100339 rtp_session_enable_jitter_buffer(rs->sess,
340 (val) ? TRUE : FALSE);
341 if (val)
342 rtp_session_set_jitter_compensation(rs->sess, val);
Harald Welte65a50892011-09-08 14:42:58 +0200343 break;
Harald Welte65a50892011-09-08 14:42:58 +0200344 default:
345 return -EINVAL;
346 }
Maxbf42e0a2016-12-15 19:57:57 +0100347 if (param == OSMO_RTP_P_JIT_ADAP)
348 return rtp_session_adaptive_jitter_compensation_enabled(rs->sess);
349 return rtp_session_jitter_buffer_enabled(rs->sess);
Harald Welte65a50892011-09-08 14:42:58 +0200350}
351
Harald Weltefcb1fe82011-09-07 11:51:52 +0200352/*! \brief Create a new RTP socket
353 * \param[in] talloc_cxt talloc context for this allocation. NULL for
354 * dafault context
355 * \param[in] flags Flags like OSMO_RTP_F_POLL
356 * \returns pointer to library-allocated \a struct osmo_rtp_socket
357 */
Harald Welte9b737df2011-09-07 00:59:11 +0200358struct osmo_rtp_socket *osmo_rtp_socket_create(void *talloc_ctx, unsigned int flags)
Harald Welte41d0d842011-09-03 15:33:24 +0200359{
360 struct osmo_rtp_socket *rs;
361
362 if (!talloc_ctx)
363 talloc_ctx = tall_rtp_ctx;
364
365 rs = talloc_zero(talloc_ctx, struct osmo_rtp_socket);
366 if (!rs)
367 return NULL;
368
Maxe54d7bc2016-04-29 12:39:33 +0200369 rs->flags = OSMO_RTP_F_DISABLED | flags;
Harald Welte41d0d842011-09-03 15:33:24 +0200370 rs->sess = rtp_session_new(RTP_SESSION_SENDRECV);
371 if (!rs->sess) {
372 talloc_free(rs);
373 return NULL;
374 }
375 rtp_session_set_data(rs->sess, rs);
376 rtp_session_set_profile(rs->sess, osmo_pt_profile);
Harald Welte9b737df2011-09-07 00:59:11 +0200377 rtp_session_set_jitter_compensation(rs->sess, 100);
Harald Welte41d0d842011-09-03 15:33:24 +0200378
Harald Welte54c919e2020-03-08 21:50:01 +0100379 /* ortp >= 0.24.0 doesn't differentiate between SO_REUSEADDR and
380 * SO_REUSEPORT, and has both enabled by default. The latter means that
381 * we can end up with non-unique port bindings as we will not fail to
382 * bind the same port twice */
383 rtp_session_set_reuseaddr(rs->sess, false);
384
Harald Welte41d0d842011-09-03 15:33:24 +0200385 rtp_session_signal_connect(rs->sess, "ssrc_changed",
386 (RtpCallback) ortp_sig_cb_ssrc,
Pau Espin Pedrol05df2d62017-06-21 07:37:45 +0200387 RTP_SIGNAL_PTR_CAST(rs));
388
Harald Welte41d0d842011-09-03 15:33:24 +0200389 rtp_session_signal_connect(rs->sess, "payload_type_changed",
390 (RtpCallback) ortp_sig_cb_pt,
Pau Espin Pedrol05df2d62017-06-21 07:37:45 +0200391 RTP_SIGNAL_PTR_CAST(rs));
392
Harald Welte41d0d842011-09-03 15:33:24 +0200393 rtp_session_signal_connect(rs->sess, "network_error",
394 (RtpCallback) ortp_sig_cb_net,
Pau Espin Pedrol05df2d62017-06-21 07:37:45 +0200395 RTP_SIGNAL_PTR_CAST(rs));
396
Harald Welte41d0d842011-09-03 15:33:24 +0200397 rtp_session_signal_connect(rs->sess, "timestamp_jump",
398 (RtpCallback) ortp_sig_cb_ts,
Pau Espin Pedrol05df2d62017-06-21 07:37:45 +0200399 RTP_SIGNAL_PTR_CAST(rs));
Harald Welte41d0d842011-09-03 15:33:24 +0200400
Holger Hans Peter Freytherbf6f1f42014-06-24 10:57:35 +0200401 /* initialize according to the RFC */
402 rtp_session_set_seq_number(rs->sess, random());
Holger Hans Peter Freytherfb6e1e92014-06-24 11:02:01 +0200403 rs->tx_timestamp = random();
Pau Espin Pedrolb0c3a4a2017-06-21 07:25:18 +0200404
Philipp Maierc81b68f2018-05-30 11:00:21 +0200405 /* Make sure ssrc changes are detected immediately */
406 rtp_session_set_ssrc_changed_threshold(rs->sess, 0);
Holger Hans Peter Freytherbf6f1f42014-06-24 10:57:35 +0200407
Harald Welte41d0d842011-09-03 15:33:24 +0200408 return rs;
409}
410
Harald Weltefcb1fe82011-09-07 11:51:52 +0200411/*! \brief bind a RTP socket to a local port
412 * \param[in] rs OsmoRTP socket
413 * \param[in] ip hostname/ip as string
414 * \param[in] port UDP port number, -1 for random selection
415 * \returns 0 on success, <0 on error
416 */
Harald Welte41d0d842011-09-03 15:33:24 +0200417int osmo_rtp_socket_bind(struct osmo_rtp_socket *rs, const char *ip, int port)
418{
Max15d9b792016-04-28 12:05:27 +0200419 int rc, rtcp = (-1 != port) ? port + 1 : -1;
Max80f7c042016-04-29 12:39:34 +0200420 rc = rtp_session_set_local_addr(rs->sess, ip, port, rtcp);
Max15d9b792016-04-28 12:05:27 +0200421
Harald Welte41d0d842011-09-03 15:33:24 +0200422 if (rc < 0)
423 return rc;
424
425 rs->rtp_bfd.fd = rtp_session_get_rtp_socket(rs->sess);
426 rs->rtcp_bfd.fd = rtp_session_get_rtcp_socket(rs->sess);
427
428 return 0;
429}
430
Harald Weltefcb1fe82011-09-07 11:51:52 +0200431/*! \brief connect a OsmoRTP socket to a remote port
432 * \param[in] rs OsmoRTP socket
433 * \param[in] ip String representation of remote hostname or IP address
434 * \param[in] port UDP port number to connect to
435 *
436 * If the OsmoRTP socket is not in POLL mode, this function will also
437 * cause the RTP and RTCP file descriptors to be registred with the
438 * libosmocore select() loop integration.
439 *
440 * \returns 0 on success, <0 in case of error
441 */
Harald Welte41d0d842011-09-03 15:33:24 +0200442int osmo_rtp_socket_connect(struct osmo_rtp_socket *rs, const char *ip, uint16_t port)
443{
444 int rc;
Maxe54d7bc2016-04-29 12:39:33 +0200445 if (!port) {
446 LOGP(DLMIB, LOGL_INFO, "osmo_rtp_socket_connect() refused to "
447 "set remote %s:%u\n", ip, port);
448 return 0;
449 }
Max8c119f72016-04-29 12:39:35 +0200450
Neels Hofmeyra0ff9422016-10-06 15:43:38 +0200451 /* We don't want the connected mode enabled during
452 * rtp_session_set_remote_addr(), because that will already setup a
453 * connection and updating the remote address will no longer have an
454 * effect. Contrary to what one may expect, this must be 0 at first,
455 * and we're setting to 1 further down to establish a connection once
456 * the first RTP packet is received (OS#1661). */
457 rtp_session_set_connected_mode(rs->sess, 0);
458
459 rc = rtp_session_set_remote_addr(rs->sess, ip, port);
460 if (rc < 0)
461 return rc;
462
Harald Welted426d452013-02-09 11:01:19 +0100463 /* enable the use of connect() so later getsockname() will
464 * actually return the IP address that was chosen for the local
465 * sid of the connection */
466 rtp_session_set_connected_mode(rs->sess, 1);
Maxe54d7bc2016-04-29 12:39:33 +0200467 rs->flags &= ~OSMO_RTP_F_DISABLED;
Harald Welted426d452013-02-09 11:01:19 +0100468
Harald Welte9b737df2011-09-07 00:59:11 +0200469 if (rs->flags & OSMO_RTP_F_POLL)
470 return rc;
471 else
472 return osmo_rtp_socket_fdreg(rs);
Harald Welte41d0d842011-09-03 15:33:24 +0200473}
474
Sylvain Munautbab7ae72019-03-11 15:36:13 +0100475/*! \brief Automatically associates a RTP socket with the first incoming UDP packet
476 * \param[in] rs OsmoRTP socket
477 *
478 * The bound RTP socket will wait for incoming RTP packets and as soon as it
479 * sees one, will 'connect' to it, so all replies will go to that sources and
480 * incoming messages from other sources will be discarded. This obviously only
481 * works once.
482 *
483 * \returns 0 on success, <0 in case of error.
484 */
485int osmo_rtp_socket_autoconnect(struct osmo_rtp_socket *rs)
486{
487 rtp_session_set_symmetric_rtp(rs->sess, 1);
488 rtp_session_set_connected_mode(rs->sess, 1);
489 rs->flags &= ~OSMO_RTP_F_DISABLED;
490
491 if (rs->flags & OSMO_RTP_F_POLL)
492 return 0;
493 else
494 return osmo_rtp_socket_fdreg(rs);
495}
496
Pau Espin Pedrol524923a2017-06-28 15:31:46 +0200497/*! \brief Increment timestamp on a RTP socket without sending any packet
498 * \param[in] rs OsmoRTP socket
499 * \param[in] duration duration in number of RTP clock ticks
500 *
501 * Useful to keep the RTP internal clock up to date if an RTP frame should be
502 * send at a given time but no audio content is available. When next packet is
503 * sent, the receiver will see a different increase on the sequence number and
504 * the timestamp, and it should then take it as a synchronization point. For
505 * that same reason, it is advisable to enable the marker bit on the next RTP
506 * packet to be sent after calling this function.
507 *
508 * \returns 0 on success, <0 in case of error.
509 */
510int osmo_rtp_skipped_frame(struct osmo_rtp_socket *rs, unsigned int duration)
511{
512 if (rs->flags & OSMO_RTP_F_DISABLED)
513 return 0;
514
515 rs->tx_timestamp += duration;
516 return 0;
517}
518
Harald Weltefcb1fe82011-09-07 11:51:52 +0200519/*! \brief Send one RTP frame via a RTP socket
520 * \param[in] rs OsmoRTP socket
521 * \param[in] payload pointer to buffer with RTP payload data
522 * \param[in] payload_len length of \a payload in bytes
523 * \param[in] duration duration in number of RTP clock ticks
524 * \returns 0 on success, <0 in case of error.
525 */
Harald Welte41d0d842011-09-03 15:33:24 +0200526int osmo_rtp_send_frame(struct osmo_rtp_socket *rs, const uint8_t *payload,
527 unsigned int payload_len, unsigned int duration)
528{
Max73b9bc72016-05-18 15:52:37 +0200529 return osmo_rtp_send_frame_ext(rs, payload, payload_len, duration,
530 false);
531}
532
533/*! \brief Send one RTP frame via a RTP socket
534 * \param[in] rs OsmoRTP socket
535 * \param[in] payload pointer to buffer with RTP payload data
536 * \param[in] payload_len length of \a payload in bytes
537 * \param[in] duration duration in number of RTP clock ticks
538 * \param[in] marker the status of Marker bit in RTP header
539 * \returns 0 on success, <0 in case of error.
540 */
541int osmo_rtp_send_frame_ext(struct osmo_rtp_socket *rs, const uint8_t *payload,
542 unsigned int payload_len, unsigned int duration,
543 bool marker)
544{
Harald Welte41d0d842011-09-03 15:33:24 +0200545 mblk_t *mblk;
546 int rc;
547
Maxe54d7bc2016-04-29 12:39:33 +0200548 if (rs->flags & OSMO_RTP_F_DISABLED)
549 return 0;
550
Harald Welte41d0d842011-09-03 15:33:24 +0200551 mblk = rtp_session_create_packet(rs->sess, RTP_FIXED_HEADER_SIZE,
552 payload, payload_len);
553 if (!mblk)
554 return -ENOMEM;
555
Max73b9bc72016-05-18 15:52:37 +0200556 rtp_set_markbit(mblk, marker);
Harald Welte41d0d842011-09-03 15:33:24 +0200557 rc = rtp_session_sendm_with_ts(rs->sess, mblk,
558 rs->tx_timestamp);
Pau Espin Pedrol9e992c22017-06-29 18:04:18 +0200559 rs->tx_timestamp += duration;
Harald Welte41d0d842011-09-03 15:33:24 +0200560 if (rc < 0) {
561 /* no need to free() the mblk, as rtp_session_rtp_send()
562 * unconditionally free()s the mblk even in case of
563 * error */
564 return rc;
565 }
566
567 return rc;
568}
569
Harald Weltefcb1fe82011-09-07 11:51:52 +0200570/*! \brief Set the payload type of a RTP socket
571 * \param[in] rs OsmoRTP socket
572 * \param[in] payload_type RTP payload type
573 * \returns 0 on success, < 0 otherwise
574 */
Harald Welte41d0d842011-09-03 15:33:24 +0200575int osmo_rtp_socket_set_pt(struct osmo_rtp_socket *rs, int payload_type)
576{
577 int rc;
578
579 rc = rtp_session_set_payload_type(rs->sess, payload_type);
580 //rtp_session_set_rtcp_report_interval(rs->sess, 5*1000);
581
582 return rc;
583}
584
Oliver Smith3c514822020-03-06 14:31:47 +0100585/*! \brief Set the DSCP (Differentiated Services Code Point) for outgoing RTP packets
586 * \param[in] rs OsmoRTP socket
587 * \param[in] dscp DSCP value
588 * \returns 0 on success, < 0 otherwise
589 */
590int osmo_rtp_socket_set_dscp(struct osmo_rtp_socket *rs, int dscp)
591{
592 return rtp_session_set_dscp(rs->sess, dscp);
593}
594
Harald Weltefcb1fe82011-09-07 11:51:52 +0200595/*! \brief completely close the RTP socket and release all resources
596 * \param[in] rs OsmoRTP socket to be released
597 * \returns 0 on success
598 */
Harald Welte41d0d842011-09-03 15:33:24 +0200599int osmo_rtp_socket_free(struct osmo_rtp_socket *rs)
600{
601 if (rs->rtp_bfd.list.next && rs->rtp_bfd.list.next != LLIST_POISON1)
602 osmo_fd_unregister(&rs->rtp_bfd);
603
604 if (rs->rtcp_bfd.list.next && rs->rtcp_bfd.list.next != LLIST_POISON1)
605 osmo_fd_unregister(&rs->rtcp_bfd);
606
607 if (rs->sess) {
608 rtp_session_release_sockets(rs->sess);
609 rtp_session_destroy(rs->sess);
610 rs->sess = NULL;
611 }
612
613 talloc_free(rs);
614
615 return 0;
616}
617
Harald Weltefcb1fe82011-09-07 11:51:52 +0200618/*! \brief obtain the locally bound IPv4 address and UDP port
619 * \param[in] rs OsmoRTP socket
620 * \param[out] ip Pointer to caller-allocated uint32_t for IPv4 address
621 * \oaram[out] port Pointer to caller-allocated int for UDP port number
622 * \returns 0 on success, <0 on error, -EIO in case of IPv6 socket
623 */
Harald Welte41d0d842011-09-03 15:33:24 +0200624int osmo_rtp_get_bound_ip_port(struct osmo_rtp_socket *rs,
625 uint32_t *ip, int *port)
626{
627 int rc;
628 struct sockaddr_storage ss;
629 struct sockaddr_in *sin = (struct sockaddr_in *) &ss;
630 socklen_t alen = sizeof(ss);
631
632 rc = getsockname(rs->rtp_bfd.fd, (struct sockaddr *)&ss, &alen);
633 if (rc < 0)
634 return rc;
635
636 if (ss.ss_family != AF_INET)
637 return -EIO;
638
639 *ip = ntohl(sin->sin_addr.s_addr);
640 *port = rtp_session_get_local_port(rs->sess);
641
642 return 0;
643}
644
Harald Weltefcb1fe82011-09-07 11:51:52 +0200645/*! \brief obtain the locally bound address and port
646 * \param[in] rs OsmoRTP socket
647 * \param[out] addr caller-allocated char ** to which the string pointer for
648 * the address is stored
649 * \param[out] port caller-allocated int * to which the port number is
650 * stored
651 * \returns 0 on success, <0 in case of error
652 */
Harald Welte41d0d842011-09-03 15:33:24 +0200653int osmo_rtp_get_bound_addr(struct osmo_rtp_socket *rs,
654 const char **addr, int *port)
655{
656 int rc;
657 struct sockaddr_storage ss;
658 socklen_t alen = sizeof(ss);
659 static char hostbuf[256];
660
661 memset(hostbuf, 0, sizeof(hostbuf));
662
663 rc = getsockname(rs->rtp_bfd.fd, (struct sockaddr *)&ss, &alen);
664 if (rc < 0)
665 return rc;
666
667 rc = getnameinfo((struct sockaddr *)&ss, alen,
668 hostbuf, sizeof(hostbuf), NULL, 0,
669 NI_NUMERICHOST);
670 if (rc < 0)
671 return rc;
672
673 *port = rtp_session_get_local_port(rs->sess);
674 *addr = hostbuf;
675
676 return 0;
677}
Harald Welte65a50892011-09-08 14:42:58 +0200678
679
680void osmo_rtp_socket_log_stats(struct osmo_rtp_socket *rs,
681 int subsys, int level,
682 const char *pfx)
683{
684 const rtp_stats_t *stats;
685
686 stats = rtp_session_get_stats(rs->sess);
687 if (!stats)
688 return;
689
690 LOGP(subsys, level, "%sRTP Tx(%"PRIu64" pkts, %"PRIu64" bytes) "
691 "Rx(%"PRIu64" pkts, %"PRIu64" bytes, %"PRIu64" late, "
692 "%"PRIu64" loss, %"PRIu64" qmax)\n",
693 pfx, stats->packet_sent, stats->sent,
694 stats->packet_recv, stats->hw_recv, stats->outoftime,
695 stats->cum_packet_loss, stats->discarded);
696}
Holger Hans Peter Freytherfe019082015-09-21 10:52:52 +0200697
698void osmo_rtp_socket_stats(struct osmo_rtp_socket *rs,
699 uint32_t *sent_packets, uint32_t *sent_octets,
700 uint32_t *recv_packets, uint32_t *recv_octets,
701 uint32_t *recv_lost, uint32_t *last_jitter)
702{
703 const rtp_stats_t *stats;
Holger Hans Peter Freytherfe019082015-09-21 10:52:52 +0200704
705 *sent_packets = *sent_octets = *recv_packets = *recv_octets = 0;
706 *recv_lost = *last_jitter = 0;
707
708 stats = rtp_session_get_stats(rs->sess);
709 if (stats) {
710 /* truncate from 64bit to 32bit here */
711 *sent_packets = stats->packet_sent;
712 *sent_octets = stats->sent;
713 *recv_packets = stats->packet_recv;
714 *recv_octets = stats->recv;
715 *recv_lost = stats->cum_packet_loss;
716 }
717
Holger Hans Peter Freyther71bc9e22015-09-21 12:18:37 +0200718 const jitter_stats_t *jitter;
719
Holger Hans Peter Freytherfe019082015-09-21 10:52:52 +0200720 jitter = rtp_session_get_jitter_stats(rs->sess);
721 if (jitter)
722 *last_jitter = jitter->jitter;
723}
Harald Welted1dd22c2017-12-03 10:00:16 +0100724
725void osmo_rtp_set_source_desc(struct osmo_rtp_socket *rs, const char *cname,
726 const char *name, const char *email, const char *phone,
727 const char *loc, const char *tool, const char *note)
728{
729 rtp_session_set_source_description(rs->sess, cname, name, email, phone, loc, tool, note);
730}