blob: 0bb1197f6a52892754cb5c15505a3daa8c2e6f60 [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
97static void my_ortp_logfn(OrtpLogLevel lev, const char *fmt,
98 va_list args)
99{
100 osmo_vlogp(DLMIB, ortp_to_osmo_lvl(lev), __FILE__, 0,
101 0, fmt, args);
102}
103
104/* ORTP signal callbacks */
105
106static void ortp_sig_cb_ssrc(RtpSession *rs, void *data)
107{
Harald Weltee7a3f432013-02-19 13:35:22 +0100108 int port = rtp_session_get_local_port(rs);
109#if 0 /* post 0.20.0 ORTP has this function */
110 uint32_t ssrc = rtp_session_get_recv_ssrc(rs);
111#else
112 uint32_t ssrc = rs->rcv.ssrc;
113#endif
114
115 LOGP(DLMIB, LOGL_INFO,
116 "osmo-ortp(%d): ssrc_changed to 0x%08x\n", port, ssrc);
Harald Welte41d0d842011-09-03 15:33:24 +0200117}
118
119static void ortp_sig_cb_pt(RtpSession *rs, void *data)
120{
Harald Weltee7a3f432013-02-19 13:35:22 +0100121 int port = rtp_session_get_local_port(rs);
122 int pt = rtp_session_get_recv_payload_type(rs);
123
124 LOGP(DLMIB, LOGL_NOTICE,
125 "osmo-ortp(%d): payload_type_changed to 0x%02x\n", port, pt);
Harald Welte41d0d842011-09-03 15:33:24 +0200126}
127
128static void ortp_sig_cb_net(RtpSession *rs, void *data)
129{
Harald Weltee7a3f432013-02-19 13:35:22 +0100130 int port = rtp_session_get_local_port(rs);
131
132 LOGP(DLMIB, LOGL_ERROR,
133 "osmo-ortp(%d): network_error\n", port);
Harald Welte41d0d842011-09-03 15:33:24 +0200134}
135
136static void ortp_sig_cb_ts(RtpSession *rs, void *data)
137{
Harald Weltee7a3f432013-02-19 13:35:22 +0100138 int port = rtp_session_get_local_port(rs);
139 uint32_t ts = rtp_session_get_current_recv_ts(rs);
140
141 LOGP(DLMIB, LOGL_NOTICE,
142 "osmo-ortp(%d): timestamp_jump, new TS %d\n", port, ts);
Harald Welte41d0d842011-09-03 15:33:24 +0200143}
144
145
Harald Welte9b737df2011-09-07 00:59:11 +0200146/*! \brief poll the socket for incoming data
147 * \param[in] rs the socket to be polled
148 * \returns number of packets received + handed to the rx_cb
149 */
150int osmo_rtp_socket_poll(struct osmo_rtp_socket *rs)
151{
152 mblk_t *mblk;
Maxe54d7bc2016-04-29 12:39:33 +0200153 if (rs->flags & OSMO_RTP_F_DISABLED)
154 return 0;
Harald Welte9b737df2011-09-07 00:59:11 +0200155
156 mblk = rtp_session_recvm_with_ts(rs->sess, rs->rx_user_ts);
157 if (mblk) {
158 rtp_get_payload(mblk, &mblk->b_rptr);
159 /* hand into receiver */
160 if (rs->rx_cb)
161 rs->rx_cb(rs, mblk->b_rptr,
Max6dab90f2016-08-12 12:27:22 +0200162 mblk->b_wptr - mblk->b_rptr,
163 rtp_get_markbit(mblk));
Harald Welte9b737df2011-09-07 00:59:11 +0200164 //rs->rx_user_ts += 160;
165 freemsg(mblk);
166 return 1;
167 } else {
168 LOGP(DLMIB, LOGL_INFO, "osmo_rtp_poll(%u): ERROR!\n",
169 rs->rx_user_ts);
170 return 0;
171 }
172}
173
Harald Welte41d0d842011-09-03 15:33:24 +0200174/* Osmo FD callbacks */
175
176static int osmo_rtp_fd_cb(struct osmo_fd *fd, unsigned int what)
177{
178 struct osmo_rtp_socket *rs = fd->data;
179 mblk_t *mblk;
180
181 if (what & BSC_FD_READ) {
Harald Welte9b737df2011-09-07 00:59:11 +0200182 /* in polling mode, we don't want to be called here */
183 if (rs->flags & OSMO_RTP_F_POLL) {
184 fd->when &= ~BSC_FD_READ;
185 return 0;
186 }
Harald Welte41d0d842011-09-03 15:33:24 +0200187 mblk = rtp_session_recvm_with_ts(rs->sess, rs->rx_user_ts);
188 if (mblk) {
189 rtp_get_payload(mblk, &mblk->b_rptr);
190 /* hand into receiver */
191 if (rs->rx_cb)
192 rs->rx_cb(rs, mblk->b_rptr,
Max6dab90f2016-08-12 12:27:22 +0200193 mblk->b_wptr - mblk->b_rptr,
194 rtp_get_markbit(mblk));
Harald Welte41d0d842011-09-03 15:33:24 +0200195 freemsg(mblk);
Harald Welte9b737df2011-09-07 00:59:11 +0200196 } else
197 LOGP(DLMIB, LOGL_INFO, "recvm_with_ts(%u): ERROR!\n",
198 rs->rx_user_ts);
Harald Welte41d0d842011-09-03 15:33:24 +0200199 rs->rx_user_ts += 160;
200 }
201 /* writing is not queued at the moment, so BSC_FD_WRITE
202 * shouldn't occur */
203 return 0;
204}
205
206static 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{
218 rs->rtp_bfd.fd = rtp_session_get_rtp_socket(rs->sess);
219 rs->rtcp_bfd.fd = rtp_session_get_rtcp_socket(rs->sess);
220 rs->rtp_bfd.when = rs->rtcp_bfd.when = BSC_FD_READ;
221 rs->rtp_bfd.data = rs->rtcp_bfd.data = rs;
222 rs->rtp_bfd.cb = osmo_rtp_fd_cb;
223 rs->rtcp_bfd.cb = osmo_rtcp_fd_cb;
224
225 osmo_fd_register(&rs->rtp_bfd);
226 osmo_fd_register(&rs->rtcp_bfd);
227
228 return 0;
229}
230
231static void create_payload_types()
232{
233 PayloadType *pt;
234
235 /* EFR */
236 pt = payload_type_new();
237 pt->type = PAYLOAD_AUDIO_PACKETIZED;
238 pt->clock_rate = 8000;
239 pt->mime_type = "EFR";
240 pt->normal_bitrate = 12200;
241 pt->channels = 1;
242 payload_type_efr = pt;
243
244 /* HR */
245 pt = payload_type_new();
246 pt->type = PAYLOAD_AUDIO_PACKETIZED;
247 pt->clock_rate = 8000;
248 pt->mime_type = "HR";
249 pt->normal_bitrate = 6750; /* FIXME */
250 pt->channels = 1;
251 payload_type_hr = pt;
252
253 /* create a new RTP profile as clone of AV profile */
254 osmo_pt_profile = rtp_profile_clone(&av_profile);
255
256 /* add the GSM specific payload types. They are all dynamically
257 * assigned, but in the Osmocom GSM system we have allocated
258 * them as follows: */
259 rtp_profile_set_payload(osmo_pt_profile, RTP_PT_GSM_EFR, payload_type_efr);
260 rtp_profile_set_payload(osmo_pt_profile, RTP_PT_GSM_HALF, payload_type_hr);
261 rtp_profile_set_payload(osmo_pt_profile, RTP_PT_AMR, &payload_type_amr);
262}
263
264/* public functions */
265
266/*! \brief initialize Osmocom RTP code
Harald Weltefcb1fe82011-09-07 11:51:52 +0200267 * \param[in] ctx default talloc context for library-internal allocations
Harald Welte41d0d842011-09-03 15:33:24 +0200268 */
269void osmo_rtp_init(void *ctx)
270{
271 tall_rtp_ctx = ctx;
272 ortp_set_memory_functions(&osmo_ortp_memfn);
273 ortp_init();
274 ortp_set_log_level_mask(0xffff);
275 ortp_set_log_handler(my_ortp_logfn);
276 create_payload_types();
277}
278
Harald Welte65a50892011-09-08 14:42:58 +0200279int osmo_rtp_socket_set_param(struct osmo_rtp_socket *rs,
280 enum osmo_rtp_param param, int val)
281{
282 int rc = 0;
283
284 switch (param) {
285 case OSMO_RTP_P_JITBUF:
Andreas Eversberg41bc6152013-02-14 11:03:26 +0100286 rtp_session_enable_jitter_buffer(rs->sess,
287 (val) ? TRUE : FALSE);
288 if (val)
289 rtp_session_set_jitter_compensation(rs->sess, val);
Harald Welte65a50892011-09-08 14:42:58 +0200290 break;
291#if 0
292 case OSMO_RTP_P_JIT_ADAP:
293 rc = jitter_control_enable_adaptive(rs->sess, val);
294 break;
295#endif
296 default:
297 return -EINVAL;
298 }
299
300 return rc;
301}
302
Harald Weltefcb1fe82011-09-07 11:51:52 +0200303/*! \brief Create a new RTP socket
304 * \param[in] talloc_cxt talloc context for this allocation. NULL for
305 * dafault context
306 * \param[in] flags Flags like OSMO_RTP_F_POLL
307 * \returns pointer to library-allocated \a struct osmo_rtp_socket
308 */
Harald Welte9b737df2011-09-07 00:59:11 +0200309struct osmo_rtp_socket *osmo_rtp_socket_create(void *talloc_ctx, unsigned int flags)
Harald Welte41d0d842011-09-03 15:33:24 +0200310{
311 struct osmo_rtp_socket *rs;
312
313 if (!talloc_ctx)
314 talloc_ctx = tall_rtp_ctx;
315
316 rs = talloc_zero(talloc_ctx, struct osmo_rtp_socket);
317 if (!rs)
318 return NULL;
319
Maxe54d7bc2016-04-29 12:39:33 +0200320 rs->flags = OSMO_RTP_F_DISABLED | flags;
Harald Welte41d0d842011-09-03 15:33:24 +0200321 rs->sess = rtp_session_new(RTP_SESSION_SENDRECV);
322 if (!rs->sess) {
323 talloc_free(rs);
324 return NULL;
325 }
326 rtp_session_set_data(rs->sess, rs);
327 rtp_session_set_profile(rs->sess, osmo_pt_profile);
Harald Welte9b737df2011-09-07 00:59:11 +0200328 rtp_session_set_jitter_compensation(rs->sess, 100);
329 //jitter_control_enable_adaptive(rs->sess, 0);
Harald Welte41d0d842011-09-03 15:33:24 +0200330
331 rtp_session_signal_connect(rs->sess, "ssrc_changed",
332 (RtpCallback) ortp_sig_cb_ssrc,
333 (unsigned long) rs);
334 rtp_session_signal_connect(rs->sess, "payload_type_changed",
335 (RtpCallback) ortp_sig_cb_pt,
336 (unsigned long) rs);
337 rtp_session_signal_connect(rs->sess, "network_error",
338 (RtpCallback) ortp_sig_cb_net,
339 (unsigned long) rs);
340 rtp_session_signal_connect(rs->sess, "timestamp_jump",
341 (RtpCallback) ortp_sig_cb_ts,
342 (unsigned long) rs);
343
Holger Hans Peter Freytherbf6f1f42014-06-24 10:57:35 +0200344 /* initialize according to the RFC */
345 rtp_session_set_seq_number(rs->sess, random());
Holger Hans Peter Freytherfb6e1e92014-06-24 11:02:01 +0200346 rs->tx_timestamp = random();
Holger Hans Peter Freytherbf6f1f42014-06-24 10:57:35 +0200347
348
Harald Welte41d0d842011-09-03 15:33:24 +0200349 return rs;
350}
351
Harald Weltefcb1fe82011-09-07 11:51:52 +0200352/*! \brief bind a RTP socket to a local port
353 * \param[in] rs OsmoRTP socket
354 * \param[in] ip hostname/ip as string
355 * \param[in] port UDP port number, -1 for random selection
356 * \returns 0 on success, <0 on error
357 */
Harald Welte41d0d842011-09-03 15:33:24 +0200358int osmo_rtp_socket_bind(struct osmo_rtp_socket *rs, const char *ip, int port)
359{
360 int rc;
Holger Hans Peter Freythere58d3312013-10-06 13:34:43 +0200361#if HAVE_ORTP_021
Max80f7c042016-04-29 12:39:34 +0200362 int rtcp = (-1 != port) ? port + 1 : -1;
363 rc = rtp_session_set_local_addr(rs->sess, ip, port, rtcp);
Harald Welte2bfc01d2013-10-06 12:23:35 +0200364#else
Harald Welte41d0d842011-09-03 15:33:24 +0200365 rc = rtp_session_set_local_addr(rs->sess, ip, port);
Harald Welte2bfc01d2013-10-06 12:23:35 +0200366#endif
Harald Welte41d0d842011-09-03 15:33:24 +0200367 if (rc < 0)
368 return rc;
369
370 rs->rtp_bfd.fd = rtp_session_get_rtp_socket(rs->sess);
371 rs->rtcp_bfd.fd = rtp_session_get_rtcp_socket(rs->sess);
372
373 return 0;
374}
375
Harald Weltefcb1fe82011-09-07 11:51:52 +0200376/*! \brief connect a OsmoRTP socket to a remote port
377 * \param[in] rs OsmoRTP socket
378 * \param[in] ip String representation of remote hostname or IP address
379 * \param[in] port UDP port number to connect to
380 *
381 * If the OsmoRTP socket is not in POLL mode, this function will also
382 * cause the RTP and RTCP file descriptors to be registred with the
383 * libosmocore select() loop integration.
384 *
385 * \returns 0 on success, <0 in case of error
386 */
Harald Welte41d0d842011-09-03 15:33:24 +0200387int osmo_rtp_socket_connect(struct osmo_rtp_socket *rs, const char *ip, uint16_t port)
388{
389 int rc;
Maxe54d7bc2016-04-29 12:39:33 +0200390 if (!port) {
391 LOGP(DLMIB, LOGL_INFO, "osmo_rtp_socket_connect() refused to "
392 "set remote %s:%u\n", ip, port);
393 return 0;
394 }
Max8c119f72016-04-29 12:39:35 +0200395
Harald Welted426d452013-02-09 11:01:19 +0100396 /* enable the use of connect() so later getsockname() will
397 * actually return the IP address that was chosen for the local
398 * sid of the connection */
399 rtp_session_set_connected_mode(rs->sess, 1);
Maxe54d7bc2016-04-29 12:39:33 +0200400 rs->flags &= ~OSMO_RTP_F_DISABLED;
Harald Welted426d452013-02-09 11:01:19 +0100401
Neels Hofmeyrc77c2a62016-09-05 14:09:56 +0200402 /* This call attempts to connect to the remote address, so make sure to
403 * set all other rtp session configuration before this call. */
404 rc = rtp_session_set_remote_addr(rs->sess, ip, port);
405 if (rc < 0)
406 return rc;
407
Harald Welte9b737df2011-09-07 00:59:11 +0200408 if (rs->flags & OSMO_RTP_F_POLL)
409 return rc;
410 else
411 return osmo_rtp_socket_fdreg(rs);
Harald Welte41d0d842011-09-03 15:33:24 +0200412}
413
Harald Weltefcb1fe82011-09-07 11:51:52 +0200414/*! \brief Send one RTP frame via a RTP socket
415 * \param[in] rs OsmoRTP socket
416 * \param[in] payload pointer to buffer with RTP payload data
417 * \param[in] payload_len length of \a payload in bytes
418 * \param[in] duration duration in number of RTP clock ticks
419 * \returns 0 on success, <0 in case of error.
420 */
Harald Welte41d0d842011-09-03 15:33:24 +0200421int osmo_rtp_send_frame(struct osmo_rtp_socket *rs, const uint8_t *payload,
422 unsigned int payload_len, unsigned int duration)
423{
Max73b9bc72016-05-18 15:52:37 +0200424 return osmo_rtp_send_frame_ext(rs, payload, payload_len, duration,
425 false);
426}
427
428/*! \brief Send one RTP frame via a RTP socket
429 * \param[in] rs OsmoRTP socket
430 * \param[in] payload pointer to buffer with RTP payload data
431 * \param[in] payload_len length of \a payload in bytes
432 * \param[in] duration duration in number of RTP clock ticks
433 * \param[in] marker the status of Marker bit in RTP header
434 * \returns 0 on success, <0 in case of error.
435 */
436int osmo_rtp_send_frame_ext(struct osmo_rtp_socket *rs, const uint8_t *payload,
437 unsigned int payload_len, unsigned int duration,
438 bool marker)
439{
Harald Welte41d0d842011-09-03 15:33:24 +0200440 mblk_t *mblk;
441 int rc;
442
Maxe54d7bc2016-04-29 12:39:33 +0200443 if (rs->flags & OSMO_RTP_F_DISABLED)
444 return 0;
445
Harald Welte41d0d842011-09-03 15:33:24 +0200446 mblk = rtp_session_create_packet(rs->sess, RTP_FIXED_HEADER_SIZE,
447 payload, payload_len);
448 if (!mblk)
449 return -ENOMEM;
450
Max73b9bc72016-05-18 15:52:37 +0200451 rtp_set_markbit(mblk, marker);
Harald Welte41d0d842011-09-03 15:33:24 +0200452 rc = rtp_session_sendm_with_ts(rs->sess, mblk,
453 rs->tx_timestamp);
454 rs->tx_timestamp += duration;
455 if (rc < 0) {
456 /* no need to free() the mblk, as rtp_session_rtp_send()
457 * unconditionally free()s the mblk even in case of
458 * error */
459 return rc;
460 }
461
462 return rc;
463}
464
Harald Weltefcb1fe82011-09-07 11:51:52 +0200465/*! \brief Set the payload type of a RTP socket
466 * \param[in] rs OsmoRTP socket
467 * \param[in] payload_type RTP payload type
468 * \returns 0 on success, < 0 otherwise
469 */
Harald Welte41d0d842011-09-03 15:33:24 +0200470int osmo_rtp_socket_set_pt(struct osmo_rtp_socket *rs, int payload_type)
471{
472 int rc;
473
474 rc = rtp_session_set_payload_type(rs->sess, payload_type);
475 //rtp_session_set_rtcp_report_interval(rs->sess, 5*1000);
476
477 return rc;
478}
479
Harald Weltefcb1fe82011-09-07 11:51:52 +0200480/*! \brief completely close the RTP socket and release all resources
481 * \param[in] rs OsmoRTP socket to be released
482 * \returns 0 on success
483 */
Harald Welte41d0d842011-09-03 15:33:24 +0200484int osmo_rtp_socket_free(struct osmo_rtp_socket *rs)
485{
486 if (rs->rtp_bfd.list.next && rs->rtp_bfd.list.next != LLIST_POISON1)
487 osmo_fd_unregister(&rs->rtp_bfd);
488
489 if (rs->rtcp_bfd.list.next && rs->rtcp_bfd.list.next != LLIST_POISON1)
490 osmo_fd_unregister(&rs->rtcp_bfd);
491
492 if (rs->sess) {
493 rtp_session_release_sockets(rs->sess);
494 rtp_session_destroy(rs->sess);
495 rs->sess = NULL;
496 }
497
498 talloc_free(rs);
499
500 return 0;
501}
502
Harald Weltefcb1fe82011-09-07 11:51:52 +0200503/*! \brief obtain the locally bound IPv4 address and UDP port
504 * \param[in] rs OsmoRTP socket
505 * \param[out] ip Pointer to caller-allocated uint32_t for IPv4 address
506 * \oaram[out] port Pointer to caller-allocated int for UDP port number
507 * \returns 0 on success, <0 on error, -EIO in case of IPv6 socket
508 */
Harald Welte41d0d842011-09-03 15:33:24 +0200509int osmo_rtp_get_bound_ip_port(struct osmo_rtp_socket *rs,
510 uint32_t *ip, int *port)
511{
512 int rc;
513 struct sockaddr_storage ss;
514 struct sockaddr_in *sin = (struct sockaddr_in *) &ss;
515 socklen_t alen = sizeof(ss);
516
517 rc = getsockname(rs->rtp_bfd.fd, (struct sockaddr *)&ss, &alen);
518 if (rc < 0)
519 return rc;
520
521 if (ss.ss_family != AF_INET)
522 return -EIO;
523
524 *ip = ntohl(sin->sin_addr.s_addr);
525 *port = rtp_session_get_local_port(rs->sess);
526
527 return 0;
528}
529
Harald Weltefcb1fe82011-09-07 11:51:52 +0200530/*! \brief obtain the locally bound address and port
531 * \param[in] rs OsmoRTP socket
532 * \param[out] addr caller-allocated char ** to which the string pointer for
533 * the address is stored
534 * \param[out] port caller-allocated int * to which the port number is
535 * stored
536 * \returns 0 on success, <0 in case of error
537 */
Harald Welte41d0d842011-09-03 15:33:24 +0200538int osmo_rtp_get_bound_addr(struct osmo_rtp_socket *rs,
539 const char **addr, int *port)
540{
541 int rc;
542 struct sockaddr_storage ss;
543 socklen_t alen = sizeof(ss);
544 static char hostbuf[256];
545
546 memset(hostbuf, 0, sizeof(hostbuf));
547
548 rc = getsockname(rs->rtp_bfd.fd, (struct sockaddr *)&ss, &alen);
549 if (rc < 0)
550 return rc;
551
552 rc = getnameinfo((struct sockaddr *)&ss, alen,
553 hostbuf, sizeof(hostbuf), NULL, 0,
554 NI_NUMERICHOST);
555 if (rc < 0)
556 return rc;
557
558 *port = rtp_session_get_local_port(rs->sess);
559 *addr = hostbuf;
560
561 return 0;
562}
Harald Welte65a50892011-09-08 14:42:58 +0200563
564
565void osmo_rtp_socket_log_stats(struct osmo_rtp_socket *rs,
566 int subsys, int level,
567 const char *pfx)
568{
569 const rtp_stats_t *stats;
570
571 stats = rtp_session_get_stats(rs->sess);
572 if (!stats)
573 return;
574
575 LOGP(subsys, level, "%sRTP Tx(%"PRIu64" pkts, %"PRIu64" bytes) "
576 "Rx(%"PRIu64" pkts, %"PRIu64" bytes, %"PRIu64" late, "
577 "%"PRIu64" loss, %"PRIu64" qmax)\n",
578 pfx, stats->packet_sent, stats->sent,
579 stats->packet_recv, stats->hw_recv, stats->outoftime,
580 stats->cum_packet_loss, stats->discarded);
581}
Holger Hans Peter Freytherfe019082015-09-21 10:52:52 +0200582
583void osmo_rtp_socket_stats(struct osmo_rtp_socket *rs,
584 uint32_t *sent_packets, uint32_t *sent_octets,
585 uint32_t *recv_packets, uint32_t *recv_octets,
586 uint32_t *recv_lost, uint32_t *last_jitter)
587{
588 const rtp_stats_t *stats;
Holger Hans Peter Freytherfe019082015-09-21 10:52:52 +0200589
590 *sent_packets = *sent_octets = *recv_packets = *recv_octets = 0;
591 *recv_lost = *last_jitter = 0;
592
593 stats = rtp_session_get_stats(rs->sess);
594 if (stats) {
595 /* truncate from 64bit to 32bit here */
596 *sent_packets = stats->packet_sent;
597 *sent_octets = stats->sent;
598 *recv_packets = stats->packet_recv;
599 *recv_octets = stats->recv;
600 *recv_lost = stats->cum_packet_loss;
601 }
602
Holger Hans Peter Freyther71bc9e22015-09-21 12:18:37 +0200603#if HAVE_ORTP_021
604 const jitter_stats_t *jitter;
605
Holger Hans Peter Freytherfe019082015-09-21 10:52:52 +0200606 jitter = rtp_session_get_jitter_stats(rs->sess);
607 if (jitter)
608 *last_jitter = jitter->jitter;
Holger Hans Peter Freyther71bc9e22015-09-21 12:18:37 +0200609#endif
Holger Hans Peter Freytherfe019082015-09-21 10:52:52 +0200610}