blob: b2ee040970e592d0583885dc8e645200f83fe060 [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 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 */
20
21/*! \file osmo_ortp.c
22 * \brief Integration of libortp into osmocom framework (select, logging)
23 */
24
25#include <stdint.h>
Max73b9bc72016-05-18 15:52:37 +020026#include <stdbool.h>
Harald Welte65a50892011-09-08 14:42:58 +020027#include <inttypes.h>
Harald Welte41d0d842011-09-03 15:33:24 +020028#include <netdb.h>
29
30#include <osmocom/core/logging.h>
31#include <osmocom/core/talloc.h>
32#include <osmocom/core/utils.h>
33#include <osmocom/core/select.h>
34#include <osmocom/trau/osmo_ortp.h>
35
36#include <ortp/ortp.h>
Harald Welte65a50892011-09-08 14:42:58 +020037#include <ortp/rtp.h>
Harald Welte0b5ffc12011-10-22 15:58:02 +020038#include <ortp/port.h>
Harald Weltee7a3f432013-02-19 13:35:22 +010039#include <ortp/rtpsession.h>
Harald Welte41d0d842011-09-03 15:33:24 +020040
Harald Welte2bfc01d2013-10-06 12:23:35 +020041#include "config.h"
Harald Welte41d0d842011-09-03 15:33:24 +020042
43static PayloadType *payload_type_efr;
44static PayloadType *payload_type_hr;
45static RtpProfile *osmo_pt_profile;
46
47static void *tall_rtp_ctx;
48
49/* malloc integration */
50
51static void *osmo_ortp_malloc(size_t sz)
52{
53 return talloc_size(tall_rtp_ctx, sz);
54}
55
56static void *osmo_ortp_realloc(void *ptr, size_t sz)
57{
58 return talloc_realloc_size(tall_rtp_ctx, ptr, sz);
59}
60
61static void osmo_ortp_free(void *ptr)
62{
63 talloc_free(ptr);
64}
65
66static OrtpMemoryFunctions osmo_ortp_memfn = {
67 .malloc_fun = osmo_ortp_malloc,
68 .realloc_fun = osmo_ortp_realloc,
69 .free_fun = osmo_ortp_free
70};
71
72/* logging */
73
74struct level_map {
75 OrtpLogLevel ortp;
76 int osmo_level;
77};
78static const struct level_map level_map[] = {
79 { ORTP_DEBUG, LOGL_DEBUG },
80 { ORTP_MESSAGE, LOGL_INFO },
81 { ORTP_WARNING, LOGL_NOTICE },
82 { ORTP_ERROR, LOGL_ERROR },
83 { ORTP_FATAL, LOGL_FATAL },
84};
85static int ortp_to_osmo_lvl(OrtpLogLevel lev)
86{
87 int i;
88
89 for (i = 0; i < ARRAY_SIZE(level_map); i++) {
90 if (level_map[i].ortp == lev)
91 return level_map[i].osmo_level;
92 }
93 /* default */
94 return LOGL_ERROR;
95}
96
Pau Espin Pedrolc42bf192017-03-24 17:26:49 +010097static void my_ortp_logfn(
98#if HAVE_ORTP_LOG_DOMAIN
99 const char *domain,
100#endif
101 OrtpLogLevel lev, const char *fmt, va_list args)
Harald Welte41d0d842011-09-03 15:33:24 +0200102{
103 osmo_vlogp(DLMIB, ortp_to_osmo_lvl(lev), __FILE__, 0,
104 0, fmt, args);
105}
106
107/* ORTP signal callbacks */
108
109static void ortp_sig_cb_ssrc(RtpSession *rs, void *data)
110{
Harald Weltee7a3f432013-02-19 13:35:22 +0100111 int port = rtp_session_get_local_port(rs);
Harald Weltee7a3f432013-02-19 13:35:22 +0100112 uint32_t ssrc = rtp_session_get_recv_ssrc(rs);
Harald Weltee7a3f432013-02-19 13:35:22 +0100113
114 LOGP(DLMIB, LOGL_INFO,
115 "osmo-ortp(%d): ssrc_changed to 0x%08x\n", port, ssrc);
Harald Welte41d0d842011-09-03 15:33:24 +0200116}
117
118static void ortp_sig_cb_pt(RtpSession *rs, void *data)
119{
Harald Weltee7a3f432013-02-19 13:35:22 +0100120 int port = rtp_session_get_local_port(rs);
121 int pt = rtp_session_get_recv_payload_type(rs);
122
123 LOGP(DLMIB, LOGL_NOTICE,
124 "osmo-ortp(%d): payload_type_changed to 0x%02x\n", port, pt);
Harald Welte41d0d842011-09-03 15:33:24 +0200125}
126
127static void ortp_sig_cb_net(RtpSession *rs, void *data)
128{
Harald Weltee7a3f432013-02-19 13:35:22 +0100129 int port = rtp_session_get_local_port(rs);
130
131 LOGP(DLMIB, LOGL_ERROR,
Max7c840be2016-12-05 16:13:53 +0100132 "osmo-ortp(%d): network_error %s\n", port, (char *)data);
Harald Welte41d0d842011-09-03 15:33:24 +0200133}
134
135static void ortp_sig_cb_ts(RtpSession *rs, void *data)
136{
Harald Weltee7a3f432013-02-19 13:35:22 +0100137 int port = rtp_session_get_local_port(rs);
138 uint32_t ts = rtp_session_get_current_recv_ts(rs);
139
140 LOGP(DLMIB, LOGL_NOTICE,
Yves Godin2c32f0a2016-10-06 15:55:06 +0200141 "osmo-ortp(%d): timestamp_jump, new TS %d, resyncing\n", port, ts);
142 rtp_session_resync(rs);
Harald Welte41d0d842011-09-03 15:33:24 +0200143}
144
Maxf6906002016-10-24 14:10:10 +0200145static inline bool recv_with_cb(struct osmo_rtp_socket *rs)
146{
Harald Welte7895e042016-10-28 10:40:24 +0200147 uint8_t *payload;
Maxf6906002016-10-24 14:10:10 +0200148 mblk_t *mblk = rtp_session_recvm_with_ts(rs->sess, rs->rx_user_ts);
149 if (!mblk)
150 return false;
151
Harald Welte7895e042016-10-28 10:40:24 +0200152 int plen = rtp_get_payload(mblk, &payload);
Maxf6906002016-10-24 14:10:10 +0200153 /* hand into receiver */
154 if (rs->rx_cb && plen > 0)
Harald Welte7895e042016-10-28 10:40:24 +0200155 rs->rx_cb(rs, payload, plen, rtp_get_seqnumber(mblk),
Maxf6906002016-10-24 14:10:10 +0200156 rtp_get_timestamp(mblk), rtp_get_markbit(mblk));
157 freemsg(mblk);
158 if (plen > 0)
159 return true;
160 return false;
161}
Harald Welte41d0d842011-09-03 15:33:24 +0200162
Harald Welte9b737df2011-09-07 00:59:11 +0200163/*! \brief poll the socket for incoming data
164 * \param[in] rs the socket to be polled
165 * \returns number of packets received + handed to the rx_cb
166 */
167int osmo_rtp_socket_poll(struct osmo_rtp_socket *rs)
168{
Maxe54d7bc2016-04-29 12:39:33 +0200169 if (rs->flags & OSMO_RTP_F_DISABLED)
170 return 0;
Harald Welte9b737df2011-09-07 00:59:11 +0200171
Maxf6906002016-10-24 14:10:10 +0200172 if (recv_with_cb(rs))
Harald Welte9b737df2011-09-07 00:59:11 +0200173 return 1;
Maxf6906002016-10-24 14:10:10 +0200174
Max78d04862016-12-05 16:02:52 +0100175 LOGP(DLMIB, LOGL_INFO, "osmo_rtp_socket_poll(%u): ERROR!\n",
176 rs->rx_user_ts);
Maxf6906002016-10-24 14:10:10 +0200177 return 0;
Harald Welte9b737df2011-09-07 00:59:11 +0200178}
179
Harald Welte41d0d842011-09-03 15:33:24 +0200180/* Osmo FD callbacks */
181
182static int osmo_rtp_fd_cb(struct osmo_fd *fd, unsigned int what)
183{
184 struct osmo_rtp_socket *rs = fd->data;
Harald Welte41d0d842011-09-03 15:33:24 +0200185
186 if (what & BSC_FD_READ) {
Harald Welte9b737df2011-09-07 00:59:11 +0200187 /* in polling mode, we don't want to be called here */
188 if (rs->flags & OSMO_RTP_F_POLL) {
189 fd->when &= ~BSC_FD_READ;
190 return 0;
191 }
Maxf6906002016-10-24 14:10:10 +0200192 if (!recv_with_cb(rs))
Harald Welte9b737df2011-09-07 00:59:11 +0200193 LOGP(DLMIB, LOGL_INFO, "recvm_with_ts(%u): ERROR!\n",
194 rs->rx_user_ts);
Harald Welte41d0d842011-09-03 15:33:24 +0200195 rs->rx_user_ts += 160;
196 }
197 /* writing is not queued at the moment, so BSC_FD_WRITE
198 * shouldn't occur */
199 return 0;
200}
201
Pau Espin Pedrolb0c3a4a2017-06-21 07:25:18 +0200202/* Internal API coming from rtpsession_priv.h, used in osmo_rtcp_fd_cb */
203#pragma message ("Using internal ortp API: rtp_session_rtcp_rec")
204int rtp_session_rtcp_recv(RtpSession * session);
205
Harald Welte41d0d842011-09-03 15:33:24 +0200206static int osmo_rtcp_fd_cb(struct osmo_fd *fd, unsigned int what)
207{
208 struct osmo_rtp_socket *rs = fd->data;
209
210 /* We probably don't need this at all, as
211 * rtp_session_recvm_with_ts() will alway also poll the RTCP
212 * file descriptor for new data */
213 return rtp_session_rtcp_recv(rs->sess);
214}
215
216static int osmo_rtp_socket_fdreg(struct osmo_rtp_socket *rs)
217{
Harald Welte34260c82016-11-26 09:27:04 +0100218 int rc;
219
Harald Welte41d0d842011-09-03 15:33:24 +0200220 rs->rtp_bfd.fd = rtp_session_get_rtp_socket(rs->sess);
221 rs->rtcp_bfd.fd = rtp_session_get_rtcp_socket(rs->sess);
222 rs->rtp_bfd.when = rs->rtcp_bfd.when = BSC_FD_READ;
223 rs->rtp_bfd.data = rs->rtcp_bfd.data = rs;
224 rs->rtp_bfd.cb = osmo_rtp_fd_cb;
225 rs->rtcp_bfd.cb = osmo_rtcp_fd_cb;
226
Harald Welte34260c82016-11-26 09:27:04 +0100227 rc = osmo_fd_register(&rs->rtp_bfd);
228 if (rc < 0)
229 return rc;
230
231 rc = osmo_fd_register(&rs->rtcp_bfd);
232 if (rc < 0) {
233 osmo_fd_unregister(&rs->rtp_bfd);
234 return rc;
235 }
Harald Welte41d0d842011-09-03 15:33:24 +0200236
237 return 0;
238}
239
240static void create_payload_types()
241{
242 PayloadType *pt;
243
244 /* EFR */
245 pt = payload_type_new();
246 pt->type = PAYLOAD_AUDIO_PACKETIZED;
247 pt->clock_rate = 8000;
248 pt->mime_type = "EFR";
249 pt->normal_bitrate = 12200;
250 pt->channels = 1;
251 payload_type_efr = pt;
252
253 /* HR */
254 pt = payload_type_new();
255 pt->type = PAYLOAD_AUDIO_PACKETIZED;
256 pt->clock_rate = 8000;
257 pt->mime_type = "HR";
258 pt->normal_bitrate = 6750; /* FIXME */
259 pt->channels = 1;
260 payload_type_hr = pt;
261
262 /* create a new RTP profile as clone of AV profile */
263 osmo_pt_profile = rtp_profile_clone(&av_profile);
264
265 /* add the GSM specific payload types. They are all dynamically
266 * assigned, but in the Osmocom GSM system we have allocated
267 * them as follows: */
268 rtp_profile_set_payload(osmo_pt_profile, RTP_PT_GSM_EFR, payload_type_efr);
269 rtp_profile_set_payload(osmo_pt_profile, RTP_PT_GSM_HALF, payload_type_hr);
270 rtp_profile_set_payload(osmo_pt_profile, RTP_PT_AMR, &payload_type_amr);
271}
272
273/* public functions */
274
275/*! \brief initialize Osmocom RTP code
Harald Weltefcb1fe82011-09-07 11:51:52 +0200276 * \param[in] ctx default talloc context for library-internal allocations
Harald Welte41d0d842011-09-03 15:33:24 +0200277 */
278void osmo_rtp_init(void *ctx)
279{
280 tall_rtp_ctx = ctx;
281 ortp_set_memory_functions(&osmo_ortp_memfn);
282 ortp_init();
Pau Espin Pedrolc42bf192017-03-24 17:26:49 +0100283 ortp_set_log_level_mask(
284#if HAVE_ORTP_LOG_DOMAIN
285 ORTP_LOG_DOMAIN,
286#endif
287 0xffff);
288
Harald Welte41d0d842011-09-03 15:33:24 +0200289 ortp_set_log_handler(my_ortp_logfn);
290 create_payload_types();
291}
292
Maxbf42e0a2016-12-15 19:57:57 +0100293/*! \brief Set Osmocom RTP socket parameters
294 * \param[in] rs OsmoRTP socket
295 * \param[in] param defined which parameter to set
296 OSMO_RTP_P_JITBUF - enables regular jitter buffering
297 OSMO_RTP_P_JIT_ADAP - enables adaptive jitter buffering
298 * \param[in] val Size of jitter buffer (in ms), 0 means disable buffering
299 * \returns negative value on error, 0 or 1 otherwise
300 (depending on whether given jitter buffering is enabled)
301 */
Harald Welte65a50892011-09-08 14:42:58 +0200302int osmo_rtp_socket_set_param(struct osmo_rtp_socket *rs,
303 enum osmo_rtp_param param, int val)
304{
Harald Welte65a50892011-09-08 14:42:58 +0200305 switch (param) {
Maxbf42e0a2016-12-15 19:57:57 +0100306 case OSMO_RTP_P_JIT_ADAP:
307 rtp_session_enable_adaptive_jitter_compensation(rs->sess,
308 (bool)val);
309 /* fall-through on-purpose - we have to set val anyway */
Harald Welte65a50892011-09-08 14:42:58 +0200310 case OSMO_RTP_P_JITBUF:
Andreas Eversberg41bc6152013-02-14 11:03:26 +0100311 rtp_session_enable_jitter_buffer(rs->sess,
312 (val) ? TRUE : FALSE);
313 if (val)
314 rtp_session_set_jitter_compensation(rs->sess, val);
Harald Welte65a50892011-09-08 14:42:58 +0200315 break;
Harald Welte65a50892011-09-08 14:42:58 +0200316 default:
317 return -EINVAL;
318 }
Maxbf42e0a2016-12-15 19:57:57 +0100319 if (param == OSMO_RTP_P_JIT_ADAP)
320 return rtp_session_adaptive_jitter_compensation_enabled(rs->sess);
321 return rtp_session_jitter_buffer_enabled(rs->sess);
Harald Welte65a50892011-09-08 14:42:58 +0200322}
323
Harald Weltefcb1fe82011-09-07 11:51:52 +0200324/*! \brief Create a new RTP socket
325 * \param[in] talloc_cxt talloc context for this allocation. NULL for
326 * dafault context
327 * \param[in] flags Flags like OSMO_RTP_F_POLL
328 * \returns pointer to library-allocated \a struct osmo_rtp_socket
329 */
Harald Welte9b737df2011-09-07 00:59:11 +0200330struct osmo_rtp_socket *osmo_rtp_socket_create(void *talloc_ctx, unsigned int flags)
Harald Welte41d0d842011-09-03 15:33:24 +0200331{
332 struct osmo_rtp_socket *rs;
333
334 if (!talloc_ctx)
335 talloc_ctx = tall_rtp_ctx;
336
337 rs = talloc_zero(talloc_ctx, struct osmo_rtp_socket);
338 if (!rs)
339 return NULL;
340
Maxe54d7bc2016-04-29 12:39:33 +0200341 rs->flags = OSMO_RTP_F_DISABLED | flags;
Harald Welte41d0d842011-09-03 15:33:24 +0200342 rs->sess = rtp_session_new(RTP_SESSION_SENDRECV);
343 if (!rs->sess) {
344 talloc_free(rs);
345 return NULL;
346 }
347 rtp_session_set_data(rs->sess, rs);
348 rtp_session_set_profile(rs->sess, osmo_pt_profile);
Harald Welte9b737df2011-09-07 00:59:11 +0200349 rtp_session_set_jitter_compensation(rs->sess, 100);
Harald Welte41d0d842011-09-03 15:33:24 +0200350
351 rtp_session_signal_connect(rs->sess, "ssrc_changed",
352 (RtpCallback) ortp_sig_cb_ssrc,
Pau Espin Pedrol05df2d62017-06-21 07:37:45 +0200353 RTP_SIGNAL_PTR_CAST(rs));
354
Harald Welte41d0d842011-09-03 15:33:24 +0200355 rtp_session_signal_connect(rs->sess, "payload_type_changed",
356 (RtpCallback) ortp_sig_cb_pt,
Pau Espin Pedrol05df2d62017-06-21 07:37:45 +0200357 RTP_SIGNAL_PTR_CAST(rs));
358
Harald Welte41d0d842011-09-03 15:33:24 +0200359 rtp_session_signal_connect(rs->sess, "network_error",
360 (RtpCallback) ortp_sig_cb_net,
Pau Espin Pedrol05df2d62017-06-21 07:37:45 +0200361 RTP_SIGNAL_PTR_CAST(rs));
362
Harald Welte41d0d842011-09-03 15:33:24 +0200363 rtp_session_signal_connect(rs->sess, "timestamp_jump",
364 (RtpCallback) ortp_sig_cb_ts,
Pau Espin Pedrol05df2d62017-06-21 07:37:45 +0200365 RTP_SIGNAL_PTR_CAST(rs));
Harald Welte41d0d842011-09-03 15:33:24 +0200366
Holger Hans Peter Freytherbf6f1f42014-06-24 10:57:35 +0200367 /* initialize according to the RFC */
368 rtp_session_set_seq_number(rs->sess, random());
Holger Hans Peter Freytherfb6e1e92014-06-24 11:02:01 +0200369 rs->tx_timestamp = random();
Pau Espin Pedrolb0c3a4a2017-06-21 07:25:18 +0200370
Holger Hans Peter Freytherbf6f1f42014-06-24 10:57:35 +0200371
Harald Welte41d0d842011-09-03 15:33:24 +0200372 return rs;
373}
374
Harald Weltefcb1fe82011-09-07 11:51:52 +0200375/*! \brief bind a RTP socket to a local port
376 * \param[in] rs OsmoRTP socket
377 * \param[in] ip hostname/ip as string
378 * \param[in] port UDP port number, -1 for random selection
379 * \returns 0 on success, <0 on error
380 */
Harald Welte41d0d842011-09-03 15:33:24 +0200381int osmo_rtp_socket_bind(struct osmo_rtp_socket *rs, const char *ip, int port)
382{
Max15d9b792016-04-28 12:05:27 +0200383 int rc, rtcp = (-1 != port) ? port + 1 : -1;
Max80f7c042016-04-29 12:39:34 +0200384 rc = rtp_session_set_local_addr(rs->sess, ip, port, rtcp);
Max15d9b792016-04-28 12:05:27 +0200385
Harald Welte41d0d842011-09-03 15:33:24 +0200386 if (rc < 0)
387 return rc;
388
389 rs->rtp_bfd.fd = rtp_session_get_rtp_socket(rs->sess);
390 rs->rtcp_bfd.fd = rtp_session_get_rtcp_socket(rs->sess);
391
392 return 0;
393}
394
Harald Weltefcb1fe82011-09-07 11:51:52 +0200395/*! \brief connect a OsmoRTP socket to a remote port
396 * \param[in] rs OsmoRTP socket
397 * \param[in] ip String representation of remote hostname or IP address
398 * \param[in] port UDP port number to connect to
399 *
400 * If the OsmoRTP socket is not in POLL mode, this function will also
401 * cause the RTP and RTCP file descriptors to be registred with the
402 * libosmocore select() loop integration.
403 *
404 * \returns 0 on success, <0 in case of error
405 */
Harald Welte41d0d842011-09-03 15:33:24 +0200406int osmo_rtp_socket_connect(struct osmo_rtp_socket *rs, const char *ip, uint16_t port)
407{
408 int rc;
Maxe54d7bc2016-04-29 12:39:33 +0200409 if (!port) {
410 LOGP(DLMIB, LOGL_INFO, "osmo_rtp_socket_connect() refused to "
411 "set remote %s:%u\n", ip, port);
412 return 0;
413 }
Max8c119f72016-04-29 12:39:35 +0200414
Neels Hofmeyra0ff9422016-10-06 15:43:38 +0200415 /* We don't want the connected mode enabled during
416 * rtp_session_set_remote_addr(), because that will already setup a
417 * connection and updating the remote address will no longer have an
418 * effect. Contrary to what one may expect, this must be 0 at first,
419 * and we're setting to 1 further down to establish a connection once
420 * the first RTP packet is received (OS#1661). */
421 rtp_session_set_connected_mode(rs->sess, 0);
422
423 rc = rtp_session_set_remote_addr(rs->sess, ip, port);
424 if (rc < 0)
425 return rc;
426
Harald Welted426d452013-02-09 11:01:19 +0100427 /* enable the use of connect() so later getsockname() will
428 * actually return the IP address that was chosen for the local
429 * sid of the connection */
430 rtp_session_set_connected_mode(rs->sess, 1);
Maxe54d7bc2016-04-29 12:39:33 +0200431 rs->flags &= ~OSMO_RTP_F_DISABLED;
Harald Welted426d452013-02-09 11:01:19 +0100432
Harald Welte9b737df2011-09-07 00:59:11 +0200433 if (rs->flags & OSMO_RTP_F_POLL)
434 return rc;
435 else
436 return osmo_rtp_socket_fdreg(rs);
Harald Welte41d0d842011-09-03 15:33:24 +0200437}
438
Harald Weltefcb1fe82011-09-07 11:51:52 +0200439/*! \brief Send one RTP frame via a RTP socket
440 * \param[in] rs OsmoRTP socket
441 * \param[in] payload pointer to buffer with RTP payload data
442 * \param[in] payload_len length of \a payload in bytes
443 * \param[in] duration duration in number of RTP clock ticks
444 * \returns 0 on success, <0 in case of error.
445 */
Harald Welte41d0d842011-09-03 15:33:24 +0200446int osmo_rtp_send_frame(struct osmo_rtp_socket *rs, const uint8_t *payload,
447 unsigned int payload_len, unsigned int duration)
448{
Max73b9bc72016-05-18 15:52:37 +0200449 return osmo_rtp_send_frame_ext(rs, payload, payload_len, duration,
450 false);
451}
452
453/*! \brief Send one RTP frame via a RTP socket
454 * \param[in] rs OsmoRTP socket
455 * \param[in] payload pointer to buffer with RTP payload data
456 * \param[in] payload_len length of \a payload in bytes
457 * \param[in] duration duration in number of RTP clock ticks
458 * \param[in] marker the status of Marker bit in RTP header
459 * \returns 0 on success, <0 in case of error.
460 */
461int osmo_rtp_send_frame_ext(struct osmo_rtp_socket *rs, const uint8_t *payload,
462 unsigned int payload_len, unsigned int duration,
463 bool marker)
464{
Harald Welte41d0d842011-09-03 15:33:24 +0200465 mblk_t *mblk;
466 int rc;
467
Maxe54d7bc2016-04-29 12:39:33 +0200468 if (rs->flags & OSMO_RTP_F_DISABLED)
469 return 0;
470
Harald Welte41d0d842011-09-03 15:33:24 +0200471 mblk = rtp_session_create_packet(rs->sess, RTP_FIXED_HEADER_SIZE,
472 payload, payload_len);
473 if (!mblk)
474 return -ENOMEM;
475
Max73b9bc72016-05-18 15:52:37 +0200476 rtp_set_markbit(mblk, marker);
Jean-Francois Dionne5e87fdf2017-03-06 13:22:37 -0500477 rs->tx_timestamp += duration;
Harald Welte41d0d842011-09-03 15:33:24 +0200478 rc = rtp_session_sendm_with_ts(rs->sess, mblk,
479 rs->tx_timestamp);
Harald Welte41d0d842011-09-03 15:33:24 +0200480 if (rc < 0) {
481 /* no need to free() the mblk, as rtp_session_rtp_send()
482 * unconditionally free()s the mblk even in case of
483 * error */
484 return rc;
485 }
486
487 return rc;
488}
489
Harald Weltefcb1fe82011-09-07 11:51:52 +0200490/*! \brief Set the payload type of a RTP socket
491 * \param[in] rs OsmoRTP socket
492 * \param[in] payload_type RTP payload type
493 * \returns 0 on success, < 0 otherwise
494 */
Harald Welte41d0d842011-09-03 15:33:24 +0200495int osmo_rtp_socket_set_pt(struct osmo_rtp_socket *rs, int payload_type)
496{
497 int rc;
498
499 rc = rtp_session_set_payload_type(rs->sess, payload_type);
500 //rtp_session_set_rtcp_report_interval(rs->sess, 5*1000);
501
502 return rc;
503}
504
Harald Weltefcb1fe82011-09-07 11:51:52 +0200505/*! \brief completely close the RTP socket and release all resources
506 * \param[in] rs OsmoRTP socket to be released
507 * \returns 0 on success
508 */
Harald Welte41d0d842011-09-03 15:33:24 +0200509int osmo_rtp_socket_free(struct osmo_rtp_socket *rs)
510{
511 if (rs->rtp_bfd.list.next && rs->rtp_bfd.list.next != LLIST_POISON1)
512 osmo_fd_unregister(&rs->rtp_bfd);
513
514 if (rs->rtcp_bfd.list.next && rs->rtcp_bfd.list.next != LLIST_POISON1)
515 osmo_fd_unregister(&rs->rtcp_bfd);
516
517 if (rs->sess) {
518 rtp_session_release_sockets(rs->sess);
519 rtp_session_destroy(rs->sess);
520 rs->sess = NULL;
521 }
522
523 talloc_free(rs);
524
525 return 0;
526}
527
Harald Weltefcb1fe82011-09-07 11:51:52 +0200528/*! \brief obtain the locally bound IPv4 address and UDP port
529 * \param[in] rs OsmoRTP socket
530 * \param[out] ip Pointer to caller-allocated uint32_t for IPv4 address
531 * \oaram[out] port Pointer to caller-allocated int for UDP port number
532 * \returns 0 on success, <0 on error, -EIO in case of IPv6 socket
533 */
Harald Welte41d0d842011-09-03 15:33:24 +0200534int osmo_rtp_get_bound_ip_port(struct osmo_rtp_socket *rs,
535 uint32_t *ip, int *port)
536{
537 int rc;
538 struct sockaddr_storage ss;
539 struct sockaddr_in *sin = (struct sockaddr_in *) &ss;
540 socklen_t alen = sizeof(ss);
541
542 rc = getsockname(rs->rtp_bfd.fd, (struct sockaddr *)&ss, &alen);
543 if (rc < 0)
544 return rc;
545
546 if (ss.ss_family != AF_INET)
547 return -EIO;
548
549 *ip = ntohl(sin->sin_addr.s_addr);
550 *port = rtp_session_get_local_port(rs->sess);
551
552 return 0;
553}
554
Harald Weltefcb1fe82011-09-07 11:51:52 +0200555/*! \brief obtain the locally bound address and port
556 * \param[in] rs OsmoRTP socket
557 * \param[out] addr caller-allocated char ** to which the string pointer for
558 * the address is stored
559 * \param[out] port caller-allocated int * to which the port number is
560 * stored
561 * \returns 0 on success, <0 in case of error
562 */
Harald Welte41d0d842011-09-03 15:33:24 +0200563int osmo_rtp_get_bound_addr(struct osmo_rtp_socket *rs,
564 const char **addr, int *port)
565{
566 int rc;
567 struct sockaddr_storage ss;
568 socklen_t alen = sizeof(ss);
569 static char hostbuf[256];
570
571 memset(hostbuf, 0, sizeof(hostbuf));
572
573 rc = getsockname(rs->rtp_bfd.fd, (struct sockaddr *)&ss, &alen);
574 if (rc < 0)
575 return rc;
576
577 rc = getnameinfo((struct sockaddr *)&ss, alen,
578 hostbuf, sizeof(hostbuf), NULL, 0,
579 NI_NUMERICHOST);
580 if (rc < 0)
581 return rc;
582
583 *port = rtp_session_get_local_port(rs->sess);
584 *addr = hostbuf;
585
586 return 0;
587}
Harald Welte65a50892011-09-08 14:42:58 +0200588
589
590void osmo_rtp_socket_log_stats(struct osmo_rtp_socket *rs,
591 int subsys, int level,
592 const char *pfx)
593{
594 const rtp_stats_t *stats;
595
596 stats = rtp_session_get_stats(rs->sess);
597 if (!stats)
598 return;
599
600 LOGP(subsys, level, "%sRTP Tx(%"PRIu64" pkts, %"PRIu64" bytes) "
601 "Rx(%"PRIu64" pkts, %"PRIu64" bytes, %"PRIu64" late, "
602 "%"PRIu64" loss, %"PRIu64" qmax)\n",
603 pfx, stats->packet_sent, stats->sent,
604 stats->packet_recv, stats->hw_recv, stats->outoftime,
605 stats->cum_packet_loss, stats->discarded);
606}
Holger Hans Peter Freytherfe019082015-09-21 10:52:52 +0200607
608void osmo_rtp_socket_stats(struct osmo_rtp_socket *rs,
609 uint32_t *sent_packets, uint32_t *sent_octets,
610 uint32_t *recv_packets, uint32_t *recv_octets,
611 uint32_t *recv_lost, uint32_t *last_jitter)
612{
613 const rtp_stats_t *stats;
Holger Hans Peter Freytherfe019082015-09-21 10:52:52 +0200614
615 *sent_packets = *sent_octets = *recv_packets = *recv_octets = 0;
616 *recv_lost = *last_jitter = 0;
617
618 stats = rtp_session_get_stats(rs->sess);
619 if (stats) {
620 /* truncate from 64bit to 32bit here */
621 *sent_packets = stats->packet_sent;
622 *sent_octets = stats->sent;
623 *recv_packets = stats->packet_recv;
624 *recv_octets = stats->recv;
625 *recv_lost = stats->cum_packet_loss;
626 }
627
Holger Hans Peter Freyther71bc9e22015-09-21 12:18:37 +0200628 const jitter_stats_t *jitter;
629
Holger Hans Peter Freytherfe019082015-09-21 10:52:52 +0200630 jitter = rtp_session_get_jitter_stats(rs->sess);
631 if (jitter)
632 *last_jitter = jitter->jitter;
633}