blob: 18a61234e797e2c8f75c19809c402aedd832aeae [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{
105 osmo_vlogp(DLMIB, ortp_to_osmo_lvl(lev), __FILE__, 0,
106 0, fmt, args);
107}
108
109/* ORTP signal callbacks */
110
111static void ortp_sig_cb_ssrc(RtpSession *rs, void *data)
112{
Harald Weltee7a3f432013-02-19 13:35:22 +0100113 int port = rtp_session_get_local_port(rs);
Harald Weltee7a3f432013-02-19 13:35:22 +0100114 uint32_t ssrc = rtp_session_get_recv_ssrc(rs);
Harald Weltee7a3f432013-02-19 13:35:22 +0100115
116 LOGP(DLMIB, LOGL_INFO,
117 "osmo-ortp(%d): ssrc_changed to 0x%08x\n", port, ssrc);
Harald Welte41d0d842011-09-03 15:33:24 +0200118}
119
120static void ortp_sig_cb_pt(RtpSession *rs, void *data)
121{
Harald Weltee7a3f432013-02-19 13:35:22 +0100122 int port = rtp_session_get_local_port(rs);
123 int pt = rtp_session_get_recv_payload_type(rs);
124
125 LOGP(DLMIB, LOGL_NOTICE,
126 "osmo-ortp(%d): payload_type_changed to 0x%02x\n", port, pt);
Harald Welte41d0d842011-09-03 15:33:24 +0200127}
128
129static void ortp_sig_cb_net(RtpSession *rs, void *data)
130{
Harald Weltee7a3f432013-02-19 13:35:22 +0100131 int port = rtp_session_get_local_port(rs);
132
133 LOGP(DLMIB, LOGL_ERROR,
Max7c840be2016-12-05 16:13:53 +0100134 "osmo-ortp(%d): network_error %s\n", port, (char *)data);
Harald Welte41d0d842011-09-03 15:33:24 +0200135}
136
137static void ortp_sig_cb_ts(RtpSession *rs, void *data)
138{
Harald Weltee7a3f432013-02-19 13:35:22 +0100139 int port = rtp_session_get_local_port(rs);
140 uint32_t ts = rtp_session_get_current_recv_ts(rs);
141
142 LOGP(DLMIB, LOGL_NOTICE,
Yves Godin2c32f0a2016-10-06 15:55:06 +0200143 "osmo-ortp(%d): timestamp_jump, new TS %d, resyncing\n", port, ts);
144 rtp_session_resync(rs);
Harald Welte41d0d842011-09-03 15:33:24 +0200145}
146
Maxf6906002016-10-24 14:10:10 +0200147static inline bool recv_with_cb(struct osmo_rtp_socket *rs)
148{
Harald Welte7895e042016-10-28 10:40:24 +0200149 uint8_t *payload;
Maxf6906002016-10-24 14:10:10 +0200150 mblk_t *mblk = rtp_session_recvm_with_ts(rs->sess, rs->rx_user_ts);
151 if (!mblk)
152 return false;
153
Harald Welte7895e042016-10-28 10:40:24 +0200154 int plen = rtp_get_payload(mblk, &payload);
Maxf6906002016-10-24 14:10:10 +0200155 /* hand into receiver */
156 if (rs->rx_cb && plen > 0)
Harald Welte7895e042016-10-28 10:40:24 +0200157 rs->rx_cb(rs, payload, plen, rtp_get_seqnumber(mblk),
Maxf6906002016-10-24 14:10:10 +0200158 rtp_get_timestamp(mblk), rtp_get_markbit(mblk));
159 freemsg(mblk);
160 if (plen > 0)
161 return true;
162 return false;
163}
Harald Welte41d0d842011-09-03 15:33:24 +0200164
Harald Welte9b737df2011-09-07 00:59:11 +0200165/*! \brief poll the socket for incoming data
166 * \param[in] rs the socket to be polled
167 * \returns number of packets received + handed to the rx_cb
168 */
169int osmo_rtp_socket_poll(struct osmo_rtp_socket *rs)
170{
Maxe54d7bc2016-04-29 12:39:33 +0200171 if (rs->flags & OSMO_RTP_F_DISABLED)
172 return 0;
Harald Welte9b737df2011-09-07 00:59:11 +0200173
Maxf6906002016-10-24 14:10:10 +0200174 if (recv_with_cb(rs))
Harald Welte9b737df2011-09-07 00:59:11 +0200175 return 1;
Maxf6906002016-10-24 14:10:10 +0200176
Max78d04862016-12-05 16:02:52 +0100177 LOGP(DLMIB, LOGL_INFO, "osmo_rtp_socket_poll(%u): ERROR!\n",
178 rs->rx_user_ts);
Maxf6906002016-10-24 14:10:10 +0200179 return 0;
Harald Welte9b737df2011-09-07 00:59:11 +0200180}
181
Harald Welte41d0d842011-09-03 15:33:24 +0200182/* Osmo FD callbacks */
183
184static int osmo_rtp_fd_cb(struct osmo_fd *fd, unsigned int what)
185{
186 struct osmo_rtp_socket *rs = fd->data;
Harald Welte41d0d842011-09-03 15:33:24 +0200187
188 if (what & BSC_FD_READ) {
Harald Welte9b737df2011-09-07 00:59:11 +0200189 /* in polling mode, we don't want to be called here */
190 if (rs->flags & OSMO_RTP_F_POLL) {
191 fd->when &= ~BSC_FD_READ;
192 return 0;
193 }
Maxf6906002016-10-24 14:10:10 +0200194 if (!recv_with_cb(rs))
Harald Welte9b737df2011-09-07 00:59:11 +0200195 LOGP(DLMIB, LOGL_INFO, "recvm_with_ts(%u): ERROR!\n",
196 rs->rx_user_ts);
Harald Welte41d0d842011-09-03 15:33:24 +0200197 rs->rx_user_ts += 160;
198 }
199 /* writing is not queued at the moment, so BSC_FD_WRITE
200 * shouldn't occur */
201 return 0;
202}
203
Pau Espin Pedrolb0c3a4a2017-06-21 07:25:18 +0200204/* Internal API coming from rtpsession_priv.h, used in osmo_rtcp_fd_cb */
205#pragma message ("Using internal ortp API: rtp_session_rtcp_rec")
206int rtp_session_rtcp_recv(RtpSession * session);
207
Harald Welte41d0d842011-09-03 15:33:24 +0200208static int osmo_rtcp_fd_cb(struct osmo_fd *fd, unsigned int what)
209{
210 struct osmo_rtp_socket *rs = fd->data;
211
212 /* We probably don't need this at all, as
213 * rtp_session_recvm_with_ts() will alway also poll the RTCP
214 * file descriptor for new data */
215 return rtp_session_rtcp_recv(rs->sess);
216}
217
218static int osmo_rtp_socket_fdreg(struct osmo_rtp_socket *rs)
219{
Harald Welte34260c82016-11-26 09:27:04 +0100220 int rc;
221
Harald Welte41d0d842011-09-03 15:33:24 +0200222 rs->rtp_bfd.fd = rtp_session_get_rtp_socket(rs->sess);
223 rs->rtcp_bfd.fd = rtp_session_get_rtcp_socket(rs->sess);
224 rs->rtp_bfd.when = rs->rtcp_bfd.when = BSC_FD_READ;
225 rs->rtp_bfd.data = rs->rtcp_bfd.data = rs;
226 rs->rtp_bfd.cb = osmo_rtp_fd_cb;
227 rs->rtcp_bfd.cb = osmo_rtcp_fd_cb;
228
Harald Welte34260c82016-11-26 09:27:04 +0100229 rc = osmo_fd_register(&rs->rtp_bfd);
230 if (rc < 0)
231 return rc;
232
233 rc = osmo_fd_register(&rs->rtcp_bfd);
234 if (rc < 0) {
235 osmo_fd_unregister(&rs->rtp_bfd);
236 return rc;
237 }
Harald Welte41d0d842011-09-03 15:33:24 +0200238
239 return 0;
240}
241
242static void create_payload_types()
243{
244 PayloadType *pt;
245
246 /* EFR */
247 pt = payload_type_new();
248 pt->type = PAYLOAD_AUDIO_PACKETIZED;
249 pt->clock_rate = 8000;
250 pt->mime_type = "EFR";
251 pt->normal_bitrate = 12200;
252 pt->channels = 1;
253 payload_type_efr = pt;
254
255 /* HR */
256 pt = payload_type_new();
257 pt->type = PAYLOAD_AUDIO_PACKETIZED;
258 pt->clock_rate = 8000;
259 pt->mime_type = "HR";
260 pt->normal_bitrate = 6750; /* FIXME */
261 pt->channels = 1;
262 payload_type_hr = pt;
263
264 /* create a new RTP profile as clone of AV profile */
265 osmo_pt_profile = rtp_profile_clone(&av_profile);
266
267 /* add the GSM specific payload types. They are all dynamically
268 * assigned, but in the Osmocom GSM system we have allocated
269 * them as follows: */
270 rtp_profile_set_payload(osmo_pt_profile, RTP_PT_GSM_EFR, payload_type_efr);
271 rtp_profile_set_payload(osmo_pt_profile, RTP_PT_GSM_HALF, payload_type_hr);
272 rtp_profile_set_payload(osmo_pt_profile, RTP_PT_AMR, &payload_type_amr);
273}
274
275/* public functions */
276
277/*! \brief initialize Osmocom RTP code
Harald Weltefcb1fe82011-09-07 11:51:52 +0200278 * \param[in] ctx default talloc context for library-internal allocations
Harald Welte41d0d842011-09-03 15:33:24 +0200279 */
280void osmo_rtp_init(void *ctx)
281{
282 tall_rtp_ctx = ctx;
283 ortp_set_memory_functions(&osmo_ortp_memfn);
284 ortp_init();
Pau Espin Pedrolc42bf192017-03-24 17:26:49 +0100285 ortp_set_log_level_mask(
286#if HAVE_ORTP_LOG_DOMAIN
287 ORTP_LOG_DOMAIN,
288#endif
289 0xffff);
290
Harald Welte41d0d842011-09-03 15:33:24 +0200291 ortp_set_log_handler(my_ortp_logfn);
292 create_payload_types();
Philipp Maier76322782018-05-29 16:04:41 +0200293 ortp_scheduler_init();
Harald Welte41d0d842011-09-03 15:33:24 +0200294}
295
Maxbf42e0a2016-12-15 19:57:57 +0100296/*! \brief Set Osmocom RTP socket parameters
297 * \param[in] rs OsmoRTP socket
298 * \param[in] param defined which parameter to set
299 OSMO_RTP_P_JITBUF - enables regular jitter buffering
300 OSMO_RTP_P_JIT_ADAP - enables adaptive jitter buffering
301 * \param[in] val Size of jitter buffer (in ms), 0 means disable buffering
302 * \returns negative value on error, 0 or 1 otherwise
303 (depending on whether given jitter buffering is enabled)
304 */
Harald Welte65a50892011-09-08 14:42:58 +0200305int osmo_rtp_socket_set_param(struct osmo_rtp_socket *rs,
306 enum osmo_rtp_param param, int val)
307{
Harald Welte65a50892011-09-08 14:42:58 +0200308 switch (param) {
Maxbf42e0a2016-12-15 19:57:57 +0100309 case OSMO_RTP_P_JIT_ADAP:
310 rtp_session_enable_adaptive_jitter_compensation(rs->sess,
311 (bool)val);
312 /* fall-through on-purpose - we have to set val anyway */
Harald Welte65a50892011-09-08 14:42:58 +0200313 case OSMO_RTP_P_JITBUF:
Andreas Eversberg41bc6152013-02-14 11:03:26 +0100314 rtp_session_enable_jitter_buffer(rs->sess,
315 (val) ? TRUE : FALSE);
316 if (val)
317 rtp_session_set_jitter_compensation(rs->sess, val);
Harald Welte65a50892011-09-08 14:42:58 +0200318 break;
Harald Welte65a50892011-09-08 14:42:58 +0200319 default:
320 return -EINVAL;
321 }
Maxbf42e0a2016-12-15 19:57:57 +0100322 if (param == OSMO_RTP_P_JIT_ADAP)
323 return rtp_session_adaptive_jitter_compensation_enabled(rs->sess);
324 return rtp_session_jitter_buffer_enabled(rs->sess);
Harald Welte65a50892011-09-08 14:42:58 +0200325}
326
Harald Weltefcb1fe82011-09-07 11:51:52 +0200327/*! \brief Create a new RTP socket
328 * \param[in] talloc_cxt talloc context for this allocation. NULL for
329 * dafault context
330 * \param[in] flags Flags like OSMO_RTP_F_POLL
331 * \returns pointer to library-allocated \a struct osmo_rtp_socket
332 */
Harald Welte9b737df2011-09-07 00:59:11 +0200333struct osmo_rtp_socket *osmo_rtp_socket_create(void *talloc_ctx, unsigned int flags)
Harald Welte41d0d842011-09-03 15:33:24 +0200334{
335 struct osmo_rtp_socket *rs;
336
337 if (!talloc_ctx)
338 talloc_ctx = tall_rtp_ctx;
339
340 rs = talloc_zero(talloc_ctx, struct osmo_rtp_socket);
341 if (!rs)
342 return NULL;
343
Maxe54d7bc2016-04-29 12:39:33 +0200344 rs->flags = OSMO_RTP_F_DISABLED | flags;
Harald Welte41d0d842011-09-03 15:33:24 +0200345 rs->sess = rtp_session_new(RTP_SESSION_SENDRECV);
346 if (!rs->sess) {
347 talloc_free(rs);
348 return NULL;
349 }
350 rtp_session_set_data(rs->sess, rs);
351 rtp_session_set_profile(rs->sess, osmo_pt_profile);
Harald Welte9b737df2011-09-07 00:59:11 +0200352 rtp_session_set_jitter_compensation(rs->sess, 100);
Harald Welte41d0d842011-09-03 15:33:24 +0200353
354 rtp_session_signal_connect(rs->sess, "ssrc_changed",
355 (RtpCallback) ortp_sig_cb_ssrc,
Pau Espin Pedrol05df2d62017-06-21 07:37:45 +0200356 RTP_SIGNAL_PTR_CAST(rs));
357
Harald Welte41d0d842011-09-03 15:33:24 +0200358 rtp_session_signal_connect(rs->sess, "payload_type_changed",
359 (RtpCallback) ortp_sig_cb_pt,
Pau Espin Pedrol05df2d62017-06-21 07:37:45 +0200360 RTP_SIGNAL_PTR_CAST(rs));
361
Harald Welte41d0d842011-09-03 15:33:24 +0200362 rtp_session_signal_connect(rs->sess, "network_error",
363 (RtpCallback) ortp_sig_cb_net,
Pau Espin Pedrol05df2d62017-06-21 07:37:45 +0200364 RTP_SIGNAL_PTR_CAST(rs));
365
Harald Welte41d0d842011-09-03 15:33:24 +0200366 rtp_session_signal_connect(rs->sess, "timestamp_jump",
367 (RtpCallback) ortp_sig_cb_ts,
Pau Espin Pedrol05df2d62017-06-21 07:37:45 +0200368 RTP_SIGNAL_PTR_CAST(rs));
Harald Welte41d0d842011-09-03 15:33:24 +0200369
Holger Hans Peter Freytherbf6f1f42014-06-24 10:57:35 +0200370 /* initialize according to the RFC */
371 rtp_session_set_seq_number(rs->sess, random());
Holger Hans Peter Freytherfb6e1e92014-06-24 11:02:01 +0200372 rs->tx_timestamp = random();
Pau Espin Pedrolb0c3a4a2017-06-21 07:25:18 +0200373
Holger Hans Peter Freytherbf6f1f42014-06-24 10:57:35 +0200374
Harald Welte41d0d842011-09-03 15:33:24 +0200375 return rs;
376}
377
Harald Weltefcb1fe82011-09-07 11:51:52 +0200378/*! \brief bind a RTP socket to a local port
379 * \param[in] rs OsmoRTP socket
380 * \param[in] ip hostname/ip as string
381 * \param[in] port UDP port number, -1 for random selection
382 * \returns 0 on success, <0 on error
383 */
Harald Welte41d0d842011-09-03 15:33:24 +0200384int osmo_rtp_socket_bind(struct osmo_rtp_socket *rs, const char *ip, int port)
385{
Max15d9b792016-04-28 12:05:27 +0200386 int rc, rtcp = (-1 != port) ? port + 1 : -1;
Max80f7c042016-04-29 12:39:34 +0200387 rc = rtp_session_set_local_addr(rs->sess, ip, port, rtcp);
Max15d9b792016-04-28 12:05:27 +0200388
Harald Welte41d0d842011-09-03 15:33:24 +0200389 if (rc < 0)
390 return rc;
391
392 rs->rtp_bfd.fd = rtp_session_get_rtp_socket(rs->sess);
393 rs->rtcp_bfd.fd = rtp_session_get_rtcp_socket(rs->sess);
394
395 return 0;
396}
397
Harald Weltefcb1fe82011-09-07 11:51:52 +0200398/*! \brief connect a OsmoRTP socket to a remote port
399 * \param[in] rs OsmoRTP socket
400 * \param[in] ip String representation of remote hostname or IP address
401 * \param[in] port UDP port number to connect to
402 *
403 * If the OsmoRTP socket is not in POLL mode, this function will also
404 * cause the RTP and RTCP file descriptors to be registred with the
405 * libosmocore select() loop integration.
406 *
407 * \returns 0 on success, <0 in case of error
408 */
Harald Welte41d0d842011-09-03 15:33:24 +0200409int osmo_rtp_socket_connect(struct osmo_rtp_socket *rs, const char *ip, uint16_t port)
410{
411 int rc;
Maxe54d7bc2016-04-29 12:39:33 +0200412 if (!port) {
413 LOGP(DLMIB, LOGL_INFO, "osmo_rtp_socket_connect() refused to "
414 "set remote %s:%u\n", ip, port);
415 return 0;
416 }
Max8c119f72016-04-29 12:39:35 +0200417
Neels Hofmeyra0ff9422016-10-06 15:43:38 +0200418 /* We don't want the connected mode enabled during
419 * rtp_session_set_remote_addr(), because that will already setup a
420 * connection and updating the remote address will no longer have an
421 * effect. Contrary to what one may expect, this must be 0 at first,
422 * and we're setting to 1 further down to establish a connection once
423 * the first RTP packet is received (OS#1661). */
424 rtp_session_set_connected_mode(rs->sess, 0);
425
426 rc = rtp_session_set_remote_addr(rs->sess, ip, port);
427 if (rc < 0)
428 return rc;
429
Harald Welted426d452013-02-09 11:01:19 +0100430 /* enable the use of connect() so later getsockname() will
431 * actually return the IP address that was chosen for the local
432 * sid of the connection */
433 rtp_session_set_connected_mode(rs->sess, 1);
Maxe54d7bc2016-04-29 12:39:33 +0200434 rs->flags &= ~OSMO_RTP_F_DISABLED;
Harald Welted426d452013-02-09 11:01:19 +0100435
Harald Welte9b737df2011-09-07 00:59:11 +0200436 if (rs->flags & OSMO_RTP_F_POLL)
437 return rc;
438 else
439 return osmo_rtp_socket_fdreg(rs);
Harald Welte41d0d842011-09-03 15:33:24 +0200440}
441
Pau Espin Pedrol524923a2017-06-28 15:31:46 +0200442/*! \brief Increment timestamp on a RTP socket without sending any packet
443 * \param[in] rs OsmoRTP socket
444 * \param[in] duration duration in number of RTP clock ticks
445 *
446 * Useful to keep the RTP internal clock up to date if an RTP frame should be
447 * send at a given time but no audio content is available. When next packet is
448 * sent, the receiver will see a different increase on the sequence number and
449 * the timestamp, and it should then take it as a synchronization point. For
450 * that same reason, it is advisable to enable the marker bit on the next RTP
451 * packet to be sent after calling this function.
452 *
453 * \returns 0 on success, <0 in case of error.
454 */
455int osmo_rtp_skipped_frame(struct osmo_rtp_socket *rs, unsigned int duration)
456{
457 if (rs->flags & OSMO_RTP_F_DISABLED)
458 return 0;
459
460 rs->tx_timestamp += duration;
461 return 0;
462}
463
Harald Weltefcb1fe82011-09-07 11:51:52 +0200464/*! \brief Send one RTP frame via a RTP socket
465 * \param[in] rs OsmoRTP socket
466 * \param[in] payload pointer to buffer with RTP payload data
467 * \param[in] payload_len length of \a payload in bytes
468 * \param[in] duration duration in number of RTP clock ticks
469 * \returns 0 on success, <0 in case of error.
470 */
Harald Welte41d0d842011-09-03 15:33:24 +0200471int osmo_rtp_send_frame(struct osmo_rtp_socket *rs, const uint8_t *payload,
472 unsigned int payload_len, unsigned int duration)
473{
Max73b9bc72016-05-18 15:52:37 +0200474 return osmo_rtp_send_frame_ext(rs, payload, payload_len, duration,
475 false);
476}
477
478/*! \brief Send one RTP frame via a RTP socket
479 * \param[in] rs OsmoRTP socket
480 * \param[in] payload pointer to buffer with RTP payload data
481 * \param[in] payload_len length of \a payload in bytes
482 * \param[in] duration duration in number of RTP clock ticks
483 * \param[in] marker the status of Marker bit in RTP header
484 * \returns 0 on success, <0 in case of error.
485 */
486int osmo_rtp_send_frame_ext(struct osmo_rtp_socket *rs, const uint8_t *payload,
487 unsigned int payload_len, unsigned int duration,
488 bool marker)
489{
Harald Welte41d0d842011-09-03 15:33:24 +0200490 mblk_t *mblk;
491 int rc;
492
Maxe54d7bc2016-04-29 12:39:33 +0200493 if (rs->flags & OSMO_RTP_F_DISABLED)
494 return 0;
495
Harald Welte41d0d842011-09-03 15:33:24 +0200496 mblk = rtp_session_create_packet(rs->sess, RTP_FIXED_HEADER_SIZE,
497 payload, payload_len);
498 if (!mblk)
499 return -ENOMEM;
500
Max73b9bc72016-05-18 15:52:37 +0200501 rtp_set_markbit(mblk, marker);
Harald Welte41d0d842011-09-03 15:33:24 +0200502 rc = rtp_session_sendm_with_ts(rs->sess, mblk,
503 rs->tx_timestamp);
Pau Espin Pedrol9e992c22017-06-29 18:04:18 +0200504 rs->tx_timestamp += duration;
Harald Welte41d0d842011-09-03 15:33:24 +0200505 if (rc < 0) {
506 /* no need to free() the mblk, as rtp_session_rtp_send()
507 * unconditionally free()s the mblk even in case of
508 * error */
509 return rc;
510 }
511
512 return rc;
513}
514
Harald Weltefcb1fe82011-09-07 11:51:52 +0200515/*! \brief Set the payload type of a RTP socket
516 * \param[in] rs OsmoRTP socket
517 * \param[in] payload_type RTP payload type
518 * \returns 0 on success, < 0 otherwise
519 */
Harald Welte41d0d842011-09-03 15:33:24 +0200520int osmo_rtp_socket_set_pt(struct osmo_rtp_socket *rs, int payload_type)
521{
522 int rc;
523
524 rc = rtp_session_set_payload_type(rs->sess, payload_type);
525 //rtp_session_set_rtcp_report_interval(rs->sess, 5*1000);
526
527 return rc;
528}
529
Harald Weltefcb1fe82011-09-07 11:51:52 +0200530/*! \brief completely close the RTP socket and release all resources
531 * \param[in] rs OsmoRTP socket to be released
532 * \returns 0 on success
533 */
Harald Welte41d0d842011-09-03 15:33:24 +0200534int osmo_rtp_socket_free(struct osmo_rtp_socket *rs)
535{
536 if (rs->rtp_bfd.list.next && rs->rtp_bfd.list.next != LLIST_POISON1)
537 osmo_fd_unregister(&rs->rtp_bfd);
538
539 if (rs->rtcp_bfd.list.next && rs->rtcp_bfd.list.next != LLIST_POISON1)
540 osmo_fd_unregister(&rs->rtcp_bfd);
541
542 if (rs->sess) {
543 rtp_session_release_sockets(rs->sess);
544 rtp_session_destroy(rs->sess);
545 rs->sess = NULL;
546 }
547
548 talloc_free(rs);
549
550 return 0;
551}
552
Harald Weltefcb1fe82011-09-07 11:51:52 +0200553/*! \brief obtain the locally bound IPv4 address and UDP port
554 * \param[in] rs OsmoRTP socket
555 * \param[out] ip Pointer to caller-allocated uint32_t for IPv4 address
556 * \oaram[out] port Pointer to caller-allocated int for UDP port number
557 * \returns 0 on success, <0 on error, -EIO in case of IPv6 socket
558 */
Harald Welte41d0d842011-09-03 15:33:24 +0200559int osmo_rtp_get_bound_ip_port(struct osmo_rtp_socket *rs,
560 uint32_t *ip, int *port)
561{
562 int rc;
563 struct sockaddr_storage ss;
564 struct sockaddr_in *sin = (struct sockaddr_in *) &ss;
565 socklen_t alen = sizeof(ss);
566
567 rc = getsockname(rs->rtp_bfd.fd, (struct sockaddr *)&ss, &alen);
568 if (rc < 0)
569 return rc;
570
571 if (ss.ss_family != AF_INET)
572 return -EIO;
573
574 *ip = ntohl(sin->sin_addr.s_addr);
575 *port = rtp_session_get_local_port(rs->sess);
576
577 return 0;
578}
579
Harald Weltefcb1fe82011-09-07 11:51:52 +0200580/*! \brief obtain the locally bound address and port
581 * \param[in] rs OsmoRTP socket
582 * \param[out] addr caller-allocated char ** to which the string pointer for
583 * the address is stored
584 * \param[out] port caller-allocated int * to which the port number is
585 * stored
586 * \returns 0 on success, <0 in case of error
587 */
Harald Welte41d0d842011-09-03 15:33:24 +0200588int osmo_rtp_get_bound_addr(struct osmo_rtp_socket *rs,
589 const char **addr, int *port)
590{
591 int rc;
592 struct sockaddr_storage ss;
593 socklen_t alen = sizeof(ss);
594 static char hostbuf[256];
595
596 memset(hostbuf, 0, sizeof(hostbuf));
597
598 rc = getsockname(rs->rtp_bfd.fd, (struct sockaddr *)&ss, &alen);
599 if (rc < 0)
600 return rc;
601
602 rc = getnameinfo((struct sockaddr *)&ss, alen,
603 hostbuf, sizeof(hostbuf), NULL, 0,
604 NI_NUMERICHOST);
605 if (rc < 0)
606 return rc;
607
608 *port = rtp_session_get_local_port(rs->sess);
609 *addr = hostbuf;
610
611 return 0;
612}
Harald Welte65a50892011-09-08 14:42:58 +0200613
614
615void osmo_rtp_socket_log_stats(struct osmo_rtp_socket *rs,
616 int subsys, int level,
617 const char *pfx)
618{
619 const rtp_stats_t *stats;
620
621 stats = rtp_session_get_stats(rs->sess);
622 if (!stats)
623 return;
624
625 LOGP(subsys, level, "%sRTP Tx(%"PRIu64" pkts, %"PRIu64" bytes) "
626 "Rx(%"PRIu64" pkts, %"PRIu64" bytes, %"PRIu64" late, "
627 "%"PRIu64" loss, %"PRIu64" qmax)\n",
628 pfx, stats->packet_sent, stats->sent,
629 stats->packet_recv, stats->hw_recv, stats->outoftime,
630 stats->cum_packet_loss, stats->discarded);
631}
Holger Hans Peter Freytherfe019082015-09-21 10:52:52 +0200632
633void osmo_rtp_socket_stats(struct osmo_rtp_socket *rs,
634 uint32_t *sent_packets, uint32_t *sent_octets,
635 uint32_t *recv_packets, uint32_t *recv_octets,
636 uint32_t *recv_lost, uint32_t *last_jitter)
637{
638 const rtp_stats_t *stats;
Holger Hans Peter Freytherfe019082015-09-21 10:52:52 +0200639
640 *sent_packets = *sent_octets = *recv_packets = *recv_octets = 0;
641 *recv_lost = *last_jitter = 0;
642
643 stats = rtp_session_get_stats(rs->sess);
644 if (stats) {
645 /* truncate from 64bit to 32bit here */
646 *sent_packets = stats->packet_sent;
647 *sent_octets = stats->sent;
648 *recv_packets = stats->packet_recv;
649 *recv_octets = stats->recv;
650 *recv_lost = stats->cum_packet_loss;
651 }
652
Holger Hans Peter Freyther71bc9e22015-09-21 12:18:37 +0200653 const jitter_stats_t *jitter;
654
Holger Hans Peter Freytherfe019082015-09-21 10:52:52 +0200655 jitter = rtp_session_get_jitter_stats(rs->sess);
656 if (jitter)
657 *last_jitter = jitter->jitter;
658}
Harald Welted1dd22c2017-12-03 10:00:16 +0100659
660void osmo_rtp_set_source_desc(struct osmo_rtp_socket *rs, const char *cname,
661 const char *name, const char *email, const char *phone,
662 const char *loc, const char *tool, const char *note)
663{
664 rtp_session_set_source_description(rs->sess, cname, name, email, phone, loc, tool, note);
665}