blob: 33137989aa15f36edf8b3b221e7ea564be10313d [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>
Harald Welte65a50892011-09-08 14:42:58 +020026#include <inttypes.h>
Harald Welte41d0d842011-09-03 15:33:24 +020027#include <netdb.h>
28
29#include <osmocom/core/logging.h>
30#include <osmocom/core/talloc.h>
31#include <osmocom/core/utils.h>
32#include <osmocom/core/select.h>
33#include <osmocom/trau/osmo_ortp.h>
34
35#include <ortp/ortp.h>
Harald Welte65a50892011-09-08 14:42:58 +020036#include <ortp/rtp.h>
Harald Welte0b5ffc12011-10-22 15:58:02 +020037#include <ortp/port.h>
Harald Weltee7a3f432013-02-19 13:35:22 +010038#include <ortp/rtpsession.h>
Harald Welte41d0d842011-09-03 15:33:24 +020039
Harald Welte2bfc01d2013-10-06 12:23:35 +020040#include "config.h"
Harald Welte41d0d842011-09-03 15:33:24 +020041
42static PayloadType *payload_type_efr;
43static PayloadType *payload_type_hr;
44static RtpProfile *osmo_pt_profile;
45
46static void *tall_rtp_ctx;
47
48/* malloc integration */
49
50static void *osmo_ortp_malloc(size_t sz)
51{
52 return talloc_size(tall_rtp_ctx, sz);
53}
54
55static void *osmo_ortp_realloc(void *ptr, size_t sz)
56{
57 return talloc_realloc_size(tall_rtp_ctx, ptr, sz);
58}
59
60static void osmo_ortp_free(void *ptr)
61{
62 talloc_free(ptr);
63}
64
65static OrtpMemoryFunctions osmo_ortp_memfn = {
66 .malloc_fun = osmo_ortp_malloc,
67 .realloc_fun = osmo_ortp_realloc,
68 .free_fun = osmo_ortp_free
69};
70
71/* logging */
72
73struct level_map {
74 OrtpLogLevel ortp;
75 int osmo_level;
76};
77static const struct level_map level_map[] = {
78 { ORTP_DEBUG, LOGL_DEBUG },
79 { ORTP_MESSAGE, LOGL_INFO },
80 { ORTP_WARNING, LOGL_NOTICE },
81 { ORTP_ERROR, LOGL_ERROR },
82 { ORTP_FATAL, LOGL_FATAL },
83};
84static int ortp_to_osmo_lvl(OrtpLogLevel lev)
85{
86 int i;
87
88 for (i = 0; i < ARRAY_SIZE(level_map); i++) {
89 if (level_map[i].ortp == lev)
90 return level_map[i].osmo_level;
91 }
92 /* default */
93 return LOGL_ERROR;
94}
95
96static void my_ortp_logfn(OrtpLogLevel lev, const char *fmt,
97 va_list args)
98{
99 osmo_vlogp(DLMIB, ortp_to_osmo_lvl(lev), __FILE__, 0,
100 0, fmt, args);
101}
102
103/* ORTP signal callbacks */
104
105static void ortp_sig_cb_ssrc(RtpSession *rs, void *data)
106{
Harald Weltee7a3f432013-02-19 13:35:22 +0100107 int port = rtp_session_get_local_port(rs);
108#if 0 /* post 0.20.0 ORTP has this function */
109 uint32_t ssrc = rtp_session_get_recv_ssrc(rs);
110#else
111 uint32_t ssrc = rs->rcv.ssrc;
112#endif
113
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,
132 "osmo-ortp(%d): network_error\n", port);
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,
141 "osmo-ortp(%d): timestamp_jump, new TS %d\n", port, ts);
Harald Welte41d0d842011-09-03 15:33:24 +0200142}
143
144
Harald Welte9b737df2011-09-07 00:59:11 +0200145/*! \brief poll the socket for incoming data
146 * \param[in] rs the socket to be polled
147 * \returns number of packets received + handed to the rx_cb
148 */
149int osmo_rtp_socket_poll(struct osmo_rtp_socket *rs)
150{
151 mblk_t *mblk;
Maxe54d7bc2016-04-29 12:39:33 +0200152 if (rs->flags & OSMO_RTP_F_DISABLED)
153 return 0;
Harald Welte9b737df2011-09-07 00:59:11 +0200154
155 mblk = rtp_session_recvm_with_ts(rs->sess, rs->rx_user_ts);
156 if (mblk) {
157 rtp_get_payload(mblk, &mblk->b_rptr);
158 /* hand into receiver */
159 if (rs->rx_cb)
160 rs->rx_cb(rs, mblk->b_rptr,
161 mblk->b_wptr - mblk->b_rptr);
162 //rs->rx_user_ts += 160;
163 freemsg(mblk);
164 return 1;
165 } else {
166 LOGP(DLMIB, LOGL_INFO, "osmo_rtp_poll(%u): ERROR!\n",
167 rs->rx_user_ts);
168 return 0;
169 }
170}
171
Harald Welte41d0d842011-09-03 15:33:24 +0200172/* Osmo FD callbacks */
173
174static int osmo_rtp_fd_cb(struct osmo_fd *fd, unsigned int what)
175{
176 struct osmo_rtp_socket *rs = fd->data;
177 mblk_t *mblk;
178
179 if (what & BSC_FD_READ) {
Harald Welte9b737df2011-09-07 00:59:11 +0200180 /* in polling mode, we don't want to be called here */
181 if (rs->flags & OSMO_RTP_F_POLL) {
182 fd->when &= ~BSC_FD_READ;
183 return 0;
184 }
Harald Welte41d0d842011-09-03 15:33:24 +0200185 mblk = rtp_session_recvm_with_ts(rs->sess, rs->rx_user_ts);
186 if (mblk) {
187 rtp_get_payload(mblk, &mblk->b_rptr);
188 /* hand into receiver */
189 if (rs->rx_cb)
190 rs->rx_cb(rs, mblk->b_rptr,
191 mblk->b_wptr - mblk->b_rptr);
192 freemsg(mblk);
Harald Welte9b737df2011-09-07 00:59:11 +0200193 } else
194 LOGP(DLMIB, LOGL_INFO, "recvm_with_ts(%u): ERROR!\n",
195 rs->rx_user_ts);
Harald Welte41d0d842011-09-03 15:33:24 +0200196 rs->rx_user_ts += 160;
197 }
198 /* writing is not queued at the moment, so BSC_FD_WRITE
199 * shouldn't occur */
200 return 0;
201}
202
203static int osmo_rtcp_fd_cb(struct osmo_fd *fd, unsigned int what)
204{
205 struct osmo_rtp_socket *rs = fd->data;
206
207 /* We probably don't need this at all, as
208 * rtp_session_recvm_with_ts() will alway also poll the RTCP
209 * file descriptor for new data */
210 return rtp_session_rtcp_recv(rs->sess);
211}
212
213static int osmo_rtp_socket_fdreg(struct osmo_rtp_socket *rs)
214{
215 rs->rtp_bfd.fd = rtp_session_get_rtp_socket(rs->sess);
216 rs->rtcp_bfd.fd = rtp_session_get_rtcp_socket(rs->sess);
217 rs->rtp_bfd.when = rs->rtcp_bfd.when = BSC_FD_READ;
Harald Welte9b737df2011-09-07 00:59:11 +0200218 rs->rtp_bfd.when = rs->rtcp_bfd.when = 0;
Harald Welte41d0d842011-09-03 15:33:24 +0200219 rs->rtp_bfd.data = rs->rtcp_bfd.data = rs;
220 rs->rtp_bfd.cb = osmo_rtp_fd_cb;
221 rs->rtcp_bfd.cb = osmo_rtcp_fd_cb;
222
223 osmo_fd_register(&rs->rtp_bfd);
224 osmo_fd_register(&rs->rtcp_bfd);
225
226 return 0;
227}
228
229static void create_payload_types()
230{
231 PayloadType *pt;
232
233 /* EFR */
234 pt = payload_type_new();
235 pt->type = PAYLOAD_AUDIO_PACKETIZED;
236 pt->clock_rate = 8000;
237 pt->mime_type = "EFR";
238 pt->normal_bitrate = 12200;
239 pt->channels = 1;
240 payload_type_efr = pt;
241
242 /* HR */
243 pt = payload_type_new();
244 pt->type = PAYLOAD_AUDIO_PACKETIZED;
245 pt->clock_rate = 8000;
246 pt->mime_type = "HR";
247 pt->normal_bitrate = 6750; /* FIXME */
248 pt->channels = 1;
249 payload_type_hr = pt;
250
251 /* create a new RTP profile as clone of AV profile */
252 osmo_pt_profile = rtp_profile_clone(&av_profile);
253
254 /* add the GSM specific payload types. They are all dynamically
255 * assigned, but in the Osmocom GSM system we have allocated
256 * them as follows: */
257 rtp_profile_set_payload(osmo_pt_profile, RTP_PT_GSM_EFR, payload_type_efr);
258 rtp_profile_set_payload(osmo_pt_profile, RTP_PT_GSM_HALF, payload_type_hr);
259 rtp_profile_set_payload(osmo_pt_profile, RTP_PT_AMR, &payload_type_amr);
260}
261
262/* public functions */
263
264/*! \brief initialize Osmocom RTP code
Harald Weltefcb1fe82011-09-07 11:51:52 +0200265 * \param[in] ctx default talloc context for library-internal allocations
Harald Welte41d0d842011-09-03 15:33:24 +0200266 */
267void osmo_rtp_init(void *ctx)
268{
269 tall_rtp_ctx = ctx;
270 ortp_set_memory_functions(&osmo_ortp_memfn);
271 ortp_init();
272 ortp_set_log_level_mask(0xffff);
273 ortp_set_log_handler(my_ortp_logfn);
274 create_payload_types();
275}
276
Harald Welte65a50892011-09-08 14:42:58 +0200277int osmo_rtp_socket_set_param(struct osmo_rtp_socket *rs,
278 enum osmo_rtp_param param, int val)
279{
280 int rc = 0;
281
282 switch (param) {
283 case OSMO_RTP_P_JITBUF:
Andreas Eversberg41bc6152013-02-14 11:03:26 +0100284 rtp_session_enable_jitter_buffer(rs->sess,
285 (val) ? TRUE : FALSE);
286 if (val)
287 rtp_session_set_jitter_compensation(rs->sess, val);
Harald Welte65a50892011-09-08 14:42:58 +0200288 break;
289#if 0
290 case OSMO_RTP_P_JIT_ADAP:
291 rc = jitter_control_enable_adaptive(rs->sess, val);
292 break;
293#endif
294 default:
295 return -EINVAL;
296 }
297
298 return rc;
299}
300
Harald Weltefcb1fe82011-09-07 11:51:52 +0200301/*! \brief Create a new RTP socket
302 * \param[in] talloc_cxt talloc context for this allocation. NULL for
303 * dafault context
304 * \param[in] flags Flags like OSMO_RTP_F_POLL
305 * \returns pointer to library-allocated \a struct osmo_rtp_socket
306 */
Harald Welte9b737df2011-09-07 00:59:11 +0200307struct osmo_rtp_socket *osmo_rtp_socket_create(void *talloc_ctx, unsigned int flags)
Harald Welte41d0d842011-09-03 15:33:24 +0200308{
309 struct osmo_rtp_socket *rs;
310
311 if (!talloc_ctx)
312 talloc_ctx = tall_rtp_ctx;
313
314 rs = talloc_zero(talloc_ctx, struct osmo_rtp_socket);
315 if (!rs)
316 return NULL;
317
Maxe54d7bc2016-04-29 12:39:33 +0200318 rs->flags = OSMO_RTP_F_DISABLED | flags;
Harald Welte41d0d842011-09-03 15:33:24 +0200319 rs->sess = rtp_session_new(RTP_SESSION_SENDRECV);
320 if (!rs->sess) {
321 talloc_free(rs);
322 return NULL;
323 }
324 rtp_session_set_data(rs->sess, rs);
325 rtp_session_set_profile(rs->sess, osmo_pt_profile);
Harald Welte9b737df2011-09-07 00:59:11 +0200326 rtp_session_set_jitter_compensation(rs->sess, 100);
327 //jitter_control_enable_adaptive(rs->sess, 0);
Harald Welte41d0d842011-09-03 15:33:24 +0200328
329 rtp_session_signal_connect(rs->sess, "ssrc_changed",
330 (RtpCallback) ortp_sig_cb_ssrc,
331 (unsigned long) rs);
332 rtp_session_signal_connect(rs->sess, "payload_type_changed",
333 (RtpCallback) ortp_sig_cb_pt,
334 (unsigned long) rs);
335 rtp_session_signal_connect(rs->sess, "network_error",
336 (RtpCallback) ortp_sig_cb_net,
337 (unsigned long) rs);
338 rtp_session_signal_connect(rs->sess, "timestamp_jump",
339 (RtpCallback) ortp_sig_cb_ts,
340 (unsigned long) rs);
341
Holger Hans Peter Freytherbf6f1f42014-06-24 10:57:35 +0200342 /* initialize according to the RFC */
343 rtp_session_set_seq_number(rs->sess, random());
Holger Hans Peter Freytherfb6e1e92014-06-24 11:02:01 +0200344 rs->tx_timestamp = random();
Holger Hans Peter Freytherbf6f1f42014-06-24 10:57:35 +0200345
346
Harald Welte41d0d842011-09-03 15:33:24 +0200347 return rs;
348}
349
Harald Weltefcb1fe82011-09-07 11:51:52 +0200350/*! \brief bind a RTP socket to a local port
351 * \param[in] rs OsmoRTP socket
352 * \param[in] ip hostname/ip as string
353 * \param[in] port UDP port number, -1 for random selection
354 * \returns 0 on success, <0 on error
355 */
Harald Welte41d0d842011-09-03 15:33:24 +0200356int osmo_rtp_socket_bind(struct osmo_rtp_socket *rs, const char *ip, int port)
357{
358 int rc;
Holger Hans Peter Freythere58d3312013-10-06 13:34:43 +0200359#if HAVE_ORTP_021
Max80f7c042016-04-29 12:39:34 +0200360 int rtcp = (-1 != port) ? port + 1 : -1;
361 rc = rtp_session_set_local_addr(rs->sess, ip, port, rtcp);
Harald Welte2bfc01d2013-10-06 12:23:35 +0200362#else
Harald Welte41d0d842011-09-03 15:33:24 +0200363 rc = rtp_session_set_local_addr(rs->sess, ip, port);
Harald Welte2bfc01d2013-10-06 12:23:35 +0200364#endif
Harald Welte41d0d842011-09-03 15:33:24 +0200365 if (rc < 0)
366 return rc;
367
368 rs->rtp_bfd.fd = rtp_session_get_rtp_socket(rs->sess);
369 rs->rtcp_bfd.fd = rtp_session_get_rtcp_socket(rs->sess);
370
371 return 0;
372}
373
Harald Weltefcb1fe82011-09-07 11:51:52 +0200374/*! \brief connect a OsmoRTP socket to a remote port
375 * \param[in] rs OsmoRTP socket
376 * \param[in] ip String representation of remote hostname or IP address
377 * \param[in] port UDP port number to connect to
378 *
379 * If the OsmoRTP socket is not in POLL mode, this function will also
380 * cause the RTP and RTCP file descriptors to be registred with the
381 * libosmocore select() loop integration.
382 *
383 * \returns 0 on success, <0 in case of error
384 */
Harald Welte41d0d842011-09-03 15:33:24 +0200385int osmo_rtp_socket_connect(struct osmo_rtp_socket *rs, const char *ip, uint16_t port)
386{
387 int rc;
Maxe54d7bc2016-04-29 12:39:33 +0200388 if (!port) {
389 LOGP(DLMIB, LOGL_INFO, "osmo_rtp_socket_connect() refused to "
390 "set remote %s:%u\n", ip, port);
391 return 0;
392 }
Max8c119f72016-04-29 12:39:35 +0200393
394 rc = rtp_session_set_remote_addr(rs->sess, ip, port);
395 if (rc < 0)
396 return rc;
397
Harald Welted426d452013-02-09 11:01:19 +0100398 /* enable the use of connect() so later getsockname() will
399 * actually return the IP address that was chosen for the local
400 * sid of the connection */
401 rtp_session_set_connected_mode(rs->sess, 1);
Maxe54d7bc2016-04-29 12:39:33 +0200402 rs->flags &= ~OSMO_RTP_F_DISABLED;
Harald Welted426d452013-02-09 11:01:19 +0100403
Harald Welte9b737df2011-09-07 00:59:11 +0200404 if (rs->flags & OSMO_RTP_F_POLL)
405 return rc;
406 else
407 return osmo_rtp_socket_fdreg(rs);
Harald Welte41d0d842011-09-03 15:33:24 +0200408}
409
Harald Weltefcb1fe82011-09-07 11:51:52 +0200410/*! \brief Send one RTP frame via a RTP socket
411 * \param[in] rs OsmoRTP socket
412 * \param[in] payload pointer to buffer with RTP payload data
413 * \param[in] payload_len length of \a payload in bytes
414 * \param[in] duration duration in number of RTP clock ticks
415 * \returns 0 on success, <0 in case of error.
416 */
Harald Welte41d0d842011-09-03 15:33:24 +0200417int osmo_rtp_send_frame(struct osmo_rtp_socket *rs, const uint8_t *payload,
418 unsigned int payload_len, unsigned int duration)
419{
420 mblk_t *mblk;
421 int rc;
422
Maxe54d7bc2016-04-29 12:39:33 +0200423 if (rs->flags & OSMO_RTP_F_DISABLED)
424 return 0;
425
Harald Welte41d0d842011-09-03 15:33:24 +0200426 mblk = rtp_session_create_packet(rs->sess, RTP_FIXED_HEADER_SIZE,
427 payload, payload_len);
428 if (!mblk)
429 return -ENOMEM;
430
431 rc = rtp_session_sendm_with_ts(rs->sess, mblk,
432 rs->tx_timestamp);
433 rs->tx_timestamp += duration;
434 if (rc < 0) {
435 /* no need to free() the mblk, as rtp_session_rtp_send()
436 * unconditionally free()s the mblk even in case of
437 * error */
438 return rc;
439 }
440
441 return rc;
442}
443
Harald Weltefcb1fe82011-09-07 11:51:52 +0200444/*! \brief Set the payload type of a RTP socket
445 * \param[in] rs OsmoRTP socket
446 * \param[in] payload_type RTP payload type
447 * \returns 0 on success, < 0 otherwise
448 */
Harald Welte41d0d842011-09-03 15:33:24 +0200449int osmo_rtp_socket_set_pt(struct osmo_rtp_socket *rs, int payload_type)
450{
451 int rc;
452
453 rc = rtp_session_set_payload_type(rs->sess, payload_type);
454 //rtp_session_set_rtcp_report_interval(rs->sess, 5*1000);
455
456 return rc;
457}
458
Harald Weltefcb1fe82011-09-07 11:51:52 +0200459/*! \brief completely close the RTP socket and release all resources
460 * \param[in] rs OsmoRTP socket to be released
461 * \returns 0 on success
462 */
Harald Welte41d0d842011-09-03 15:33:24 +0200463int osmo_rtp_socket_free(struct osmo_rtp_socket *rs)
464{
465 if (rs->rtp_bfd.list.next && rs->rtp_bfd.list.next != LLIST_POISON1)
466 osmo_fd_unregister(&rs->rtp_bfd);
467
468 if (rs->rtcp_bfd.list.next && rs->rtcp_bfd.list.next != LLIST_POISON1)
469 osmo_fd_unregister(&rs->rtcp_bfd);
470
471 if (rs->sess) {
472 rtp_session_release_sockets(rs->sess);
473 rtp_session_destroy(rs->sess);
474 rs->sess = NULL;
475 }
476
477 talloc_free(rs);
478
479 return 0;
480}
481
Harald Weltefcb1fe82011-09-07 11:51:52 +0200482/*! \brief obtain the locally bound IPv4 address and UDP port
483 * \param[in] rs OsmoRTP socket
484 * \param[out] ip Pointer to caller-allocated uint32_t for IPv4 address
485 * \oaram[out] port Pointer to caller-allocated int for UDP port number
486 * \returns 0 on success, <0 on error, -EIO in case of IPv6 socket
487 */
Harald Welte41d0d842011-09-03 15:33:24 +0200488int osmo_rtp_get_bound_ip_port(struct osmo_rtp_socket *rs,
489 uint32_t *ip, int *port)
490{
491 int rc;
492 struct sockaddr_storage ss;
493 struct sockaddr_in *sin = (struct sockaddr_in *) &ss;
494 socklen_t alen = sizeof(ss);
495
496 rc = getsockname(rs->rtp_bfd.fd, (struct sockaddr *)&ss, &alen);
497 if (rc < 0)
498 return rc;
499
500 if (ss.ss_family != AF_INET)
501 return -EIO;
502
503 *ip = ntohl(sin->sin_addr.s_addr);
504 *port = rtp_session_get_local_port(rs->sess);
505
506 return 0;
507}
508
Harald Weltefcb1fe82011-09-07 11:51:52 +0200509/*! \brief obtain the locally bound address and port
510 * \param[in] rs OsmoRTP socket
511 * \param[out] addr caller-allocated char ** to which the string pointer for
512 * the address is stored
513 * \param[out] port caller-allocated int * to which the port number is
514 * stored
515 * \returns 0 on success, <0 in case of error
516 */
Harald Welte41d0d842011-09-03 15:33:24 +0200517int osmo_rtp_get_bound_addr(struct osmo_rtp_socket *rs,
518 const char **addr, int *port)
519{
520 int rc;
521 struct sockaddr_storage ss;
522 socklen_t alen = sizeof(ss);
523 static char hostbuf[256];
524
525 memset(hostbuf, 0, sizeof(hostbuf));
526
527 rc = getsockname(rs->rtp_bfd.fd, (struct sockaddr *)&ss, &alen);
528 if (rc < 0)
529 return rc;
530
531 rc = getnameinfo((struct sockaddr *)&ss, alen,
532 hostbuf, sizeof(hostbuf), NULL, 0,
533 NI_NUMERICHOST);
534 if (rc < 0)
535 return rc;
536
537 *port = rtp_session_get_local_port(rs->sess);
538 *addr = hostbuf;
539
540 return 0;
541}
Harald Welte65a50892011-09-08 14:42:58 +0200542
543
544void osmo_rtp_socket_log_stats(struct osmo_rtp_socket *rs,
545 int subsys, int level,
546 const char *pfx)
547{
548 const rtp_stats_t *stats;
549
550 stats = rtp_session_get_stats(rs->sess);
551 if (!stats)
552 return;
553
554 LOGP(subsys, level, "%sRTP Tx(%"PRIu64" pkts, %"PRIu64" bytes) "
555 "Rx(%"PRIu64" pkts, %"PRIu64" bytes, %"PRIu64" late, "
556 "%"PRIu64" loss, %"PRIu64" qmax)\n",
557 pfx, stats->packet_sent, stats->sent,
558 stats->packet_recv, stats->hw_recv, stats->outoftime,
559 stats->cum_packet_loss, stats->discarded);
560}
Holger Hans Peter Freytherfe019082015-09-21 10:52:52 +0200561
562void osmo_rtp_socket_stats(struct osmo_rtp_socket *rs,
563 uint32_t *sent_packets, uint32_t *sent_octets,
564 uint32_t *recv_packets, uint32_t *recv_octets,
565 uint32_t *recv_lost, uint32_t *last_jitter)
566{
567 const rtp_stats_t *stats;
Holger Hans Peter Freytherfe019082015-09-21 10:52:52 +0200568
569 *sent_packets = *sent_octets = *recv_packets = *recv_octets = 0;
570 *recv_lost = *last_jitter = 0;
571
572 stats = rtp_session_get_stats(rs->sess);
573 if (stats) {
574 /* truncate from 64bit to 32bit here */
575 *sent_packets = stats->packet_sent;
576 *sent_octets = stats->sent;
577 *recv_packets = stats->packet_recv;
578 *recv_octets = stats->recv;
579 *recv_lost = stats->cum_packet_loss;
580 }
581
Holger Hans Peter Freyther71bc9e22015-09-21 12:18:37 +0200582#if HAVE_ORTP_021
583 const jitter_stats_t *jitter;
584
Holger Hans Peter Freytherfe019082015-09-21 10:52:52 +0200585 jitter = rtp_session_get_jitter_stats(rs->sess);
586 if (jitter)
587 *last_jitter = jitter->jitter;
Holger Hans Peter Freyther71bc9e22015-09-21 12:18:37 +0200588#endif
Holger Hans Peter Freytherfe019082015-09-21 10:52:52 +0200589}