2012-07-09 17:39:55 +00:00
|
|
|
/*
|
2017-11-12 16:21:03 +00:00
|
|
|
* (C) 2012-2017 by Pablo Neira Ayuso <pablo@gnumonks.org>
|
2012-07-09 17:39:55 +00:00
|
|
|
* (C) 2012 by On Waves ehf <http://www.on-waves.com>
|
2017-11-12 16:21:03 +00:00
|
|
|
* (C) 2015-2017 by sysmocom - s.f.m.c. GmbH
|
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: GPL-2.0+
|
2012-07-09 17:39:55 +00:00
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include <osmocom/core/msgb.h>
|
|
|
|
#include <osmocom/core/timer.h>
|
2018-04-18 11:58:46 +00:00
|
|
|
#include <osmocom/core/timer_compat.h>
|
2012-07-09 17:39:55 +00:00
|
|
|
#include <osmocom/core/select.h>
|
2012-07-19 09:08:21 +00:00
|
|
|
#include <osmocom/core/talloc.h>
|
2012-07-19 11:04:39 +00:00
|
|
|
#include <osmocom/core/logging.h>
|
2012-07-09 17:39:55 +00:00
|
|
|
|
|
|
|
#include <osmocom/netif/amr.h>
|
|
|
|
#include <osmocom/netif/rtp.h>
|
|
|
|
#include <osmocom/netif/osmux.h>
|
|
|
|
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
|
2017-04-08 18:00:47 +00:00
|
|
|
/*! \addtogroup osmux Osmocom Multiplex Protocol
|
|
|
|
* @{
|
2017-10-27 17:57:37 +00:00
|
|
|
*
|
|
|
|
* This code implements a variety of utility functions related to the
|
|
|
|
* OSMUX user-plane multiplexing protocol, an efficient alternative to
|
|
|
|
* plain UDP/RTP streams for voice transport in back-haul of cellular
|
|
|
|
* networks.
|
|
|
|
*
|
|
|
|
* For information about the OSMUX protocol design, please see the
|
|
|
|
* OSMUX reference manual at
|
|
|
|
* http://ftp.osmocom.org/docs/latest/osmux-reference.pdf
|
2017-04-08 18:00:47 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
/*! \file osmux.c
|
|
|
|
* \brief Osmocom multiplex protocol helpers
|
|
|
|
*/
|
|
|
|
|
2014-08-28 15:15:44 +00:00
|
|
|
/* This allows you to debug osmux message transformations (spamming) */
|
|
|
|
#if 0
|
|
|
|
#define DEBUG_MSG 0
|
|
|
|
#endif
|
|
|
|
|
2017-04-24 08:09:26 +00:00
|
|
|
/* delta time between two RTP messages (in microseconds) */
|
|
|
|
#define DELTA_RTP_MSG 20000
|
|
|
|
/* delta time between two RTP messages (in samples, 8kHz) */
|
2012-10-15 19:42:00 +00:00
|
|
|
#define DELTA_RTP_TIMESTAMP 160
|
2012-08-04 17:56:47 +00:00
|
|
|
|
2013-02-19 12:16:27 +00:00
|
|
|
static void *osmux_ctx;
|
|
|
|
|
2013-02-19 16:14:33 +00:00
|
|
|
static uint32_t osmux_get_payload_len(struct osmux_hdr *osmuxh)
|
|
|
|
{
|
|
|
|
return osmo_amr_bytes(osmuxh->amr_ft) * (osmuxh->ctr+1);
|
|
|
|
}
|
|
|
|
|
2017-04-25 15:27:13 +00:00
|
|
|
static uint32_t osmux_ft_dummy_size(uint8_t amr_ft, uint8_t batch_factor)
|
2012-07-09 17:39:55 +00:00
|
|
|
{
|
2015-07-17 18:47:04 +00:00
|
|
|
return sizeof(struct osmux_hdr) + (osmo_amr_bytes(amr_ft) * batch_factor);
|
|
|
|
}
|
2012-07-09 17:39:55 +00:00
|
|
|
|
2015-07-17 18:47:04 +00:00
|
|
|
struct osmux_hdr *osmux_xfrm_output_pull(struct msgb *msg)
|
|
|
|
{
|
|
|
|
struct osmux_hdr *osmuxh;
|
|
|
|
next:
|
|
|
|
osmuxh = NULL;
|
2012-07-09 17:39:55 +00:00
|
|
|
if (msg->len > sizeof(struct osmux_hdr)) {
|
2013-05-24 08:47:50 +00:00
|
|
|
size_t len;
|
|
|
|
|
2012-07-09 17:39:55 +00:00
|
|
|
osmuxh = (struct osmux_hdr *)msg->data;
|
2013-05-24 09:56:07 +00:00
|
|
|
|
2015-07-17 18:47:04 +00:00
|
|
|
switch (osmuxh->ft) {
|
|
|
|
case OSMUX_FT_VOICE_AMR:
|
|
|
|
break;
|
|
|
|
case OSMUX_FT_DUMMY:
|
2018-04-12 13:32:18 +00:00
|
|
|
len = osmux_ft_dummy_size(osmuxh->amr_ft, osmuxh->ctr + 1);
|
|
|
|
if (msgb_length(msg) < len) {
|
|
|
|
LOGP(DLMUX, LOGL_ERROR, "Discarding bad Dummy FT: %s\n",
|
|
|
|
osmo_hexdump(msg->data, msgb_length(msg)));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
msgb_pull(msg, len);
|
2015-07-17 18:47:04 +00:00
|
|
|
goto next;
|
|
|
|
default:
|
2018-03-07 12:13:17 +00:00
|
|
|
LOGP(DLMUX, LOGL_ERROR, "Discarding unsupported Osmux FT %d\n",
|
2015-07-17 19:20:43 +00:00
|
|
|
osmuxh->ft);
|
|
|
|
return NULL;
|
|
|
|
}
|
2013-05-24 09:56:07 +00:00
|
|
|
if (!osmo_amr_ft_valid(osmuxh->amr_ft)) {
|
2018-03-07 12:13:17 +00:00
|
|
|
LOGP(DLMUX, LOGL_ERROR, "Discarding bad AMR FT %d\n",
|
2013-05-24 09:56:07 +00:00
|
|
|
osmuxh->amr_ft);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2013-05-24 08:47:50 +00:00
|
|
|
len = osmo_amr_bytes(osmuxh->amr_ft) * (osmuxh->ctr+1) +
|
|
|
|
sizeof(struct osmux_hdr);
|
|
|
|
|
2018-04-12 13:32:18 +00:00
|
|
|
if (msgb_length(msg) < len) {
|
|
|
|
LOGP(DLMUX, LOGL_ERROR,
|
|
|
|
"Discarding malformed OSMUX message: %s\n",
|
|
|
|
osmo_hexdump(msg->data, msgb_length(msg)));
|
2013-05-24 08:47:50 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2012-07-09 17:39:55 +00:00
|
|
|
|
2013-05-24 08:47:50 +00:00
|
|
|
msgb_pull(msg, len);
|
2012-07-09 17:39:55 +00:00
|
|
|
} else if (msg->len > 0) {
|
2018-03-07 12:13:17 +00:00
|
|
|
LOGP(DLMUX, LOGL_ERROR,
|
2012-07-19 11:04:39 +00:00
|
|
|
"remaining %d bytes, broken osmuxhdr?\n", msg->len);
|
2012-07-09 17:39:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return osmuxh;
|
|
|
|
}
|
|
|
|
|
osmux: major rework to reduce batch message size (add counter field)
This patch adds the counter field to the osmux header, so we can
reduce the size of the batch even further, eg.
osmuxhdr (ctr=3)
speech
speech
speech
osmuxhdr (ctr=2)
speech
speech
...
The new header is the following:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| FT | CTR |F|Q| SeqNR | Circuit ID |AMR-FT |AMR-CMR|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
The counter field is 3 bits long, thus, we can batch up to 8
RTP speech frames into one single batch per circuit ID.
I have also removed the RTP marker, since it can be reconstructed
from the AMR information.
Moreover, the entire workflow has been also reworked. Whenever a
packet arrives, we introduce it into the batch list. This batch
list contains a list of RTP messages ordered by RTP SSRC. Then,
once the batch timer expires or the it gets full, we build the
batch from the list of RTP messages.
Note that this allows us to put several speech frame into one
single osmux header without actually worrying about the amount
of messages that we'll receive.
The functions that reconstruct the RTP messages has been also
adjusted. Now, it returns a list of RTP messages per RTP SSRC
that has been extracted from the batch.
2012-08-02 18:24:57 +00:00
|
|
|
static struct msgb *
|
2017-04-25 15:20:38 +00:00
|
|
|
osmux_rebuild_rtp(struct osmux_out_handle *h, struct osmux_hdr *osmuxh,
|
|
|
|
void *payload, int payload_len, bool first_pkt)
|
2012-07-09 17:39:55 +00:00
|
|
|
{
|
2018-04-18 11:58:46 +00:00
|
|
|
struct msgb *prev_msg, *out_msg;
|
|
|
|
struct timespec *prev_ts, *out_ts;
|
2012-07-09 17:39:55 +00:00
|
|
|
struct rtp_hdr *rtph;
|
|
|
|
struct amr_hdr *amrh;
|
2018-04-18 11:58:46 +00:00
|
|
|
struct timespec delta = { .tv_sec = 0, .tv_nsec = DELTA_RTP_MSG*1000 };
|
2022-08-31 16:37:01 +00:00
|
|
|
unsigned int msg_len = sizeof(struct rtp_hdr) +
|
|
|
|
sizeof(struct amr_hdr) +
|
|
|
|
payload_len;
|
2012-07-09 17:39:55 +00:00
|
|
|
|
2022-08-31 16:37:01 +00:00
|
|
|
if (h->rtp_msgb_alloc_cb) {
|
|
|
|
out_msg = h->rtp_msgb_alloc_cb(h->rtp_msgb_alloc_cb_data, msg_len);
|
|
|
|
} else {
|
|
|
|
out_msg = msgb_alloc(msg_len, "osmux-rtp");
|
|
|
|
}
|
2012-07-09 17:39:55 +00:00
|
|
|
if (out_msg == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/* Reconstruct RTP header */
|
|
|
|
rtph = (struct rtp_hdr *)out_msg->data;
|
2012-08-06 16:49:05 +00:00
|
|
|
rtph->csrc_count = 0;
|
2012-07-09 17:39:55 +00:00
|
|
|
rtph->extension = 0;
|
|
|
|
rtph->version = RTP_VERSION;
|
2019-05-17 15:11:02 +00:00
|
|
|
rtph->payload_type = h->rtp_payload_type;
|
2012-07-09 17:39:55 +00:00
|
|
|
/* ... emulate timestamp and ssrc */
|
2013-02-12 16:23:29 +00:00
|
|
|
rtph->timestamp = htonl(h->rtp_timestamp);
|
|
|
|
rtph->sequence = htons(h->rtp_seq);
|
2013-05-12 16:03:50 +00:00
|
|
|
rtph->ssrc = htonl(h->rtp_ssrc);
|
2018-04-18 17:10:20 +00:00
|
|
|
/* rtp packet with the marker bit is always guaranteed to be the first
|
|
|
|
* one. We want to notify with marker in 2 scenarios:
|
|
|
|
* 1- Sender told us through osmux frame rtp_m.
|
|
|
|
* 2- Sntermediate osmux frame lost (seq gap), otherwise rtp receiver only sees
|
|
|
|
* steady increase of delay
|
|
|
|
*/
|
|
|
|
rtph->marker = first_pkt &&
|
|
|
|
(osmuxh->rtp_m || (osmuxh->seq != h->osmux_seq_ack + 1));
|
2012-07-09 17:39:55 +00:00
|
|
|
|
|
|
|
msgb_put(out_msg, sizeof(struct rtp_hdr));
|
|
|
|
|
|
|
|
/* Reconstruct AMR header */
|
|
|
|
amrh = (struct amr_hdr *)out_msg->tail;
|
|
|
|
amrh->cmr = osmuxh->amr_cmr;
|
|
|
|
amrh->f = osmuxh->amr_f;
|
|
|
|
amrh->ft = osmuxh->amr_ft;
|
|
|
|
amrh->q = osmuxh->amr_q;
|
|
|
|
|
|
|
|
msgb_put(out_msg, sizeof(struct amr_hdr));
|
|
|
|
|
|
|
|
/* add AMR speech data */
|
osmux: major rework to reduce batch message size (add counter field)
This patch adds the counter field to the osmux header, so we can
reduce the size of the batch even further, eg.
osmuxhdr (ctr=3)
speech
speech
speech
osmuxhdr (ctr=2)
speech
speech
...
The new header is the following:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| FT | CTR |F|Q| SeqNR | Circuit ID |AMR-FT |AMR-CMR|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
The counter field is 3 bits long, thus, we can batch up to 8
RTP speech frames into one single batch per circuit ID.
I have also removed the RTP marker, since it can be reconstructed
from the AMR information.
Moreover, the entire workflow has been also reworked. Whenever a
packet arrives, we introduce it into the batch list. This batch
list contains a list of RTP messages ordered by RTP SSRC. Then,
once the batch timer expires or the it gets full, we build the
batch from the list of RTP messages.
Note that this allows us to put several speech frame into one
single osmux header without actually worrying about the amount
of messages that we'll receive.
The functions that reconstruct the RTP messages has been also
adjusted. Now, it returns a list of RTP messages per RTP SSRC
that has been extracted from the batch.
2012-08-02 18:24:57 +00:00
|
|
|
memcpy(out_msg->tail, payload, payload_len);
|
|
|
|
msgb_put(out_msg, payload_len);
|
2012-07-09 17:39:55 +00:00
|
|
|
|
|
|
|
/* bump last RTP sequence number and timestamp that has been used */
|
2013-02-12 16:23:29 +00:00
|
|
|
h->rtp_seq++;
|
|
|
|
h->rtp_timestamp += DELTA_RTP_TIMESTAMP;
|
2012-07-09 17:39:55 +00:00
|
|
|
|
2018-04-18 11:58:46 +00:00
|
|
|
out_ts = ((struct timespec *)&((out_msg)->cb[0]));
|
|
|
|
if (first_pkt || llist_empty(&h->list)) {
|
|
|
|
osmo_clock_gettime(CLOCK_MONOTONIC, out_ts);
|
|
|
|
} else {
|
|
|
|
prev_msg = llist_last_entry(&h->list, struct msgb, list);
|
|
|
|
prev_ts = ((struct timespec *)&((prev_msg)->cb[0]));
|
|
|
|
timespecadd(prev_ts, &delta, out_ts);
|
|
|
|
}
|
|
|
|
|
2012-07-09 17:39:55 +00:00
|
|
|
return out_msg;
|
|
|
|
}
|
|
|
|
|
2018-04-18 11:58:46 +00:00
|
|
|
static void osmux_xfrm_output_trigger(void *data)
|
|
|
|
{
|
|
|
|
struct osmux_out_handle *h = data;
|
|
|
|
struct timespec delay_ts, now;
|
|
|
|
struct msgb *msg, *next;
|
|
|
|
|
|
|
|
llist_for_each_entry_safe(msg, next, &h->list, list) {
|
|
|
|
osmo_clock_gettime(CLOCK_MONOTONIC, &now);
|
|
|
|
struct timespec *msg_ts = ((struct timespec *)&((msg)->cb[0]));
|
|
|
|
if (timespeccmp(msg_ts, &now, >)) {
|
|
|
|
timespecsub(msg_ts, &now, &delay_ts);
|
|
|
|
osmo_timer_schedule(&h->timer,
|
|
|
|
delay_ts.tv_sec, delay_ts.tv_nsec / 1000);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Transmit the rtp packet */
|
|
|
|
llist_del(&msg->list);
|
|
|
|
if (h->tx_cb)
|
|
|
|
h->tx_cb(msg, h->data);
|
|
|
|
else
|
|
|
|
msgb_free(msg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*! \brief Generate RTP packets from osmux frame AMR payload set and schedule
|
|
|
|
* them for transmission at appropiate time.
|
|
|
|
* \param[in] h the osmux out handle handling a specific CID
|
|
|
|
* \param[in] osmuxh Buffer pointing to osmux frame header structure and AMR payload
|
|
|
|
* \return Number of generated RTP packets
|
|
|
|
*
|
|
|
|
* The osmux frame passed to this function must be of the type OSMUX_FT_VOICE_AMR.
|
|
|
|
* The generated RTP packets are kept into h's internal list and sent to the
|
|
|
|
* callback configured through osmux_xfrm_output_set_tx_cb when are ready to be
|
|
|
|
* transmitted according to schedule.
|
|
|
|
*/
|
|
|
|
int osmux_xfrm_output_sched(struct osmux_out_handle *h, struct osmux_hdr *osmuxh)
|
|
|
|
{
|
|
|
|
struct timespec now, *msg_ts;
|
|
|
|
struct msgb *msg;
|
|
|
|
int i;
|
|
|
|
bool was_empty = llist_empty(&h->list);
|
|
|
|
|
|
|
|
if (!was_empty) {
|
|
|
|
/* If we received new data it means we are behind schedule and
|
|
|
|
* we should flush all previous quickly */
|
|
|
|
osmo_clock_gettime(CLOCK_MONOTONIC, &now);
|
|
|
|
llist_for_each_entry(msg, &h->list, list) {
|
|
|
|
msg_ts = ((struct timespec *)&((msg)->cb[0]));
|
|
|
|
*msg_ts = now;
|
|
|
|
}
|
|
|
|
osmo_timer_schedule(&h->timer, 0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i=0; i<osmuxh->ctr+1; i++) {
|
|
|
|
struct rtp_hdr *rtph;
|
|
|
|
|
|
|
|
msg = osmux_rebuild_rtp(h, osmuxh,
|
|
|
|
osmux_get_payload(osmuxh) +
|
|
|
|
i * osmo_amr_bytes(osmuxh->amr_ft),
|
|
|
|
osmo_amr_bytes(osmuxh->amr_ft), !i);
|
|
|
|
if (msg == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
rtph = osmo_rtp_get_hdr(msg);
|
|
|
|
if (rtph == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
llist_add_tail(&msg->list, &h->list);
|
|
|
|
}
|
2018-04-18 17:10:20 +00:00
|
|
|
|
|
|
|
/* Update last seen seq number: */
|
|
|
|
h->osmux_seq_ack = osmuxh->seq;
|
|
|
|
|
2018-04-18 11:58:46 +00:00
|
|
|
/* In case list is still empty after parsing messages, no need to rearm */
|
|
|
|
if(was_empty && !llist_empty(&h->list))
|
|
|
|
osmux_xfrm_output_trigger(h);
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*! \brief Flush all scheduled RTP packets still pending to be transmitted
|
|
|
|
* \param[in] h the osmux out handle to flush
|
|
|
|
*
|
|
|
|
* This function will immediately call the transmit callback for all queued RTP
|
|
|
|
* packets, making sure the list ends up empty. It will also stop all internal
|
|
|
|
* timers to make sure the osmux_out_handle can be dropped or re-used by calling
|
|
|
|
* osmux_xfrm_output on it.
|
|
|
|
*/
|
|
|
|
void osmux_xfrm_output_flush(struct osmux_out_handle *h)
|
|
|
|
{
|
|
|
|
struct msgb *msg, *next;
|
|
|
|
|
|
|
|
if (osmo_timer_pending(&h->timer))
|
|
|
|
osmo_timer_del(&h->timer);
|
|
|
|
|
|
|
|
llist_for_each_entry_safe(msg, next, &h->list, list) {
|
|
|
|
llist_del(&msg->list);
|
|
|
|
if (h->tx_cb)
|
|
|
|
h->tx_cb(msg, h->data);
|
|
|
|
else
|
|
|
|
msgb_free(msg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-06 16:41:49 +00:00
|
|
|
struct osmux_batch {
|
osmux: major rework to reduce batch message size (add counter field)
This patch adds the counter field to the osmux header, so we can
reduce the size of the batch even further, eg.
osmuxhdr (ctr=3)
speech
speech
speech
osmuxhdr (ctr=2)
speech
speech
...
The new header is the following:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| FT | CTR |F|Q| SeqNR | Circuit ID |AMR-FT |AMR-CMR|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
The counter field is 3 bits long, thus, we can batch up to 8
RTP speech frames into one single batch per circuit ID.
I have also removed the RTP marker, since it can be reconstructed
from the AMR information.
Moreover, the entire workflow has been also reworked. Whenever a
packet arrives, we introduce it into the batch list. This batch
list contains a list of RTP messages ordered by RTP SSRC. Then,
once the batch timer expires or the it gets full, we build the
batch from the list of RTP messages.
Note that this allows us to put several speech frame into one
single osmux header without actually worrying about the amount
of messages that we'll receive.
The functions that reconstruct the RTP messages has been also
adjusted. Now, it returns a list of RTP messages per RTP SSRC
that has been extracted from the batch.
2012-08-02 18:24:57 +00:00
|
|
|
struct osmo_timer_list timer;
|
|
|
|
struct osmux_hdr *osmuxh;
|
2015-07-17 17:24:49 +00:00
|
|
|
struct llist_head circuit_list;
|
osmux: major rework to reduce batch message size (add counter field)
This patch adds the counter field to the osmux header, so we can
reduce the size of the batch even further, eg.
osmuxhdr (ctr=3)
speech
speech
speech
osmuxhdr (ctr=2)
speech
speech
...
The new header is the following:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| FT | CTR |F|Q| SeqNR | Circuit ID |AMR-FT |AMR-CMR|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
The counter field is 3 bits long, thus, we can batch up to 8
RTP speech frames into one single batch per circuit ID.
I have also removed the RTP marker, since it can be reconstructed
from the AMR information.
Moreover, the entire workflow has been also reworked. Whenever a
packet arrives, we introduce it into the batch list. This batch
list contains a list of RTP messages ordered by RTP SSRC. Then,
once the batch timer expires or the it gets full, we build the
batch from the list of RTP messages.
Note that this allows us to put several speech frame into one
single osmux header without actually worrying about the amount
of messages that we'll receive.
The functions that reconstruct the RTP messages has been also
adjusted. Now, it returns a list of RTP messages per RTP SSRC
that has been extracted from the batch.
2012-08-02 18:24:57 +00:00
|
|
|
unsigned int remaining_bytes;
|
|
|
|
uint8_t seq;
|
2015-07-17 18:23:25 +00:00
|
|
|
uint32_t nmsgs;
|
2015-08-18 22:19:53 +00:00
|
|
|
int ndummy;
|
2012-08-06 16:41:49 +00:00
|
|
|
};
|
2012-07-09 17:39:55 +00:00
|
|
|
|
2015-07-17 17:24:49 +00:00
|
|
|
struct osmux_circuit {
|
2013-12-16 10:44:47 +00:00
|
|
|
struct llist_head head;
|
|
|
|
int ccid;
|
2015-07-17 17:37:28 +00:00
|
|
|
struct llist_head msg_list;
|
2013-12-16 10:44:47 +00:00
|
|
|
int nmsgs;
|
2015-07-17 18:47:04 +00:00
|
|
|
int dummy;
|
2013-12-16 10:44:47 +00:00
|
|
|
};
|
|
|
|
|
2022-09-27 16:20:56 +00:00
|
|
|
/* returns: 1 if batch is full, 0 if batch still not full, negative on error. */
|
2017-04-12 14:11:50 +00:00
|
|
|
static int osmux_batch_enqueue(struct msgb *msg, struct osmux_circuit *circuit,
|
|
|
|
uint8_t batch_factor)
|
2013-12-16 10:44:47 +00:00
|
|
|
{
|
2018-05-15 15:09:17 +00:00
|
|
|
/* Validate amount of messages per batch. The counter field of the
|
2013-12-16 10:44:47 +00:00
|
|
|
* osmux header is just 3 bits long, so make sure it doesn't overflow.
|
|
|
|
*/
|
2022-09-27 16:26:48 +00:00
|
|
|
OSMO_ASSERT(batch_factor <= 8);
|
|
|
|
if (circuit->nmsgs >= batch_factor) {
|
2013-12-16 10:44:47 +00:00
|
|
|
struct rtp_hdr *rtph;
|
|
|
|
|
|
|
|
rtph = osmo_rtp_get_hdr(msg);
|
|
|
|
if (rtph == NULL)
|
2014-08-28 12:26:03 +00:00
|
|
|
return -1;
|
2013-12-16 10:44:47 +00:00
|
|
|
|
2019-10-04 13:59:06 +00:00
|
|
|
LOGP(DLMUX, LOGL_DEBUG, "Batch is full for RTP sssrc=%u\n", rtph->ssrc);
|
2022-09-27 16:20:56 +00:00
|
|
|
return 1;
|
2013-12-16 10:44:47 +00:00
|
|
|
}
|
|
|
|
|
2015-07-17 17:37:28 +00:00
|
|
|
llist_add_tail(&msg->list, &circuit->msg_list);
|
2015-07-17 17:24:49 +00:00
|
|
|
circuit->nmsgs++;
|
2014-08-28 12:26:03 +00:00
|
|
|
return 0;
|
2013-12-16 10:44:47 +00:00
|
|
|
}
|
|
|
|
|
2015-07-17 17:24:49 +00:00
|
|
|
static void osmux_batch_dequeue(struct msgb *msg, struct osmux_circuit *circuit)
|
2013-12-16 10:44:47 +00:00
|
|
|
{
|
|
|
|
llist_del(&msg->list);
|
2015-07-17 17:24:49 +00:00
|
|
|
circuit->nmsgs--;
|
2013-12-16 10:44:47 +00:00
|
|
|
}
|
|
|
|
|
2016-05-25 15:44:39 +00:00
|
|
|
static void osmux_circuit_del_msgs(struct osmux_batch *batch, struct osmux_circuit *circuit)
|
|
|
|
{
|
|
|
|
struct msgb *cur, *tmp;
|
|
|
|
llist_for_each_entry_safe(cur, tmp, &circuit->msg_list, list) {
|
|
|
|
osmux_batch_dequeue(cur, circuit);
|
|
|
|
msgb_free(cur);
|
|
|
|
batch->nmsgs--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-17 14:58:31 +00:00
|
|
|
struct osmux_input_state {
|
|
|
|
struct msgb *out_msg;
|
|
|
|
struct msgb *msg;
|
|
|
|
struct rtp_hdr *rtph;
|
|
|
|
struct amr_hdr *amrh;
|
|
|
|
uint32_t amr_payload_len;
|
|
|
|
int ccid;
|
|
|
|
int add_osmux_hdr;
|
|
|
|
};
|
|
|
|
|
2015-07-17 18:13:16 +00:00
|
|
|
static int osmux_batch_put(struct osmux_batch *batch,
|
2015-07-17 14:58:31 +00:00
|
|
|
struct osmux_input_state *state)
|
osmux: major rework to reduce batch message size (add counter field)
This patch adds the counter field to the osmux header, so we can
reduce the size of the batch even further, eg.
osmuxhdr (ctr=3)
speech
speech
speech
osmuxhdr (ctr=2)
speech
speech
...
The new header is the following:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| FT | CTR |F|Q| SeqNR | Circuit ID |AMR-FT |AMR-CMR|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
The counter field is 3 bits long, thus, we can batch up to 8
RTP speech frames into one single batch per circuit ID.
I have also removed the RTP marker, since it can be reconstructed
from the AMR information.
Moreover, the entire workflow has been also reworked. Whenever a
packet arrives, we introduce it into the batch list. This batch
list contains a list of RTP messages ordered by RTP SSRC. Then,
once the batch timer expires or the it gets full, we build the
batch from the list of RTP messages.
Note that this allows us to put several speech frame into one
single osmux header without actually worrying about the amount
of messages that we'll receive.
The functions that reconstruct the RTP messages has been also
adjusted. Now, it returns a list of RTP messages per RTP SSRC
that has been extracted from the batch.
2012-08-02 18:24:57 +00:00
|
|
|
{
|
|
|
|
struct osmux_hdr *osmuxh;
|
|
|
|
|
2015-07-17 14:58:31 +00:00
|
|
|
if (state->add_osmux_hdr) {
|
|
|
|
osmuxh = (struct osmux_hdr *)state->out_msg->tail;
|
osmux: major rework to reduce batch message size (add counter field)
This patch adds the counter field to the osmux header, so we can
reduce the size of the batch even further, eg.
osmuxhdr (ctr=3)
speech
speech
speech
osmuxhdr (ctr=2)
speech
speech
...
The new header is the following:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| FT | CTR |F|Q| SeqNR | Circuit ID |AMR-FT |AMR-CMR|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
The counter field is 3 bits long, thus, we can batch up to 8
RTP speech frames into one single batch per circuit ID.
I have also removed the RTP marker, since it can be reconstructed
from the AMR information.
Moreover, the entire workflow has been also reworked. Whenever a
packet arrives, we introduce it into the batch list. This batch
list contains a list of RTP messages ordered by RTP SSRC. Then,
once the batch timer expires or the it gets full, we build the
batch from the list of RTP messages.
Note that this allows us to put several speech frame into one
single osmux header without actually worrying about the amount
of messages that we'll receive.
The functions that reconstruct the RTP messages has been also
adjusted. Now, it returns a list of RTP messages per RTP SSRC
that has been extracted from the batch.
2012-08-02 18:24:57 +00:00
|
|
|
osmuxh->ft = OSMUX_FT_VOICE_AMR;
|
|
|
|
osmuxh->ctr = 0;
|
2017-04-25 15:20:38 +00:00
|
|
|
osmuxh->rtp_m = osmuxh->rtp_m || state->rtph->marker;
|
2015-07-17 14:58:31 +00:00
|
|
|
osmuxh->amr_f = state->amrh->f;
|
|
|
|
osmuxh->amr_q= state->amrh->q;
|
2012-08-06 16:41:49 +00:00
|
|
|
osmuxh->seq = batch->seq++;
|
2015-07-17 14:58:31 +00:00
|
|
|
osmuxh->circuit_id = state->ccid;
|
|
|
|
osmuxh->amr_cmr = state->amrh->cmr;
|
|
|
|
osmuxh->amr_ft = state->amrh->ft;
|
|
|
|
msgb_put(state->out_msg, sizeof(struct osmux_hdr));
|
osmux: major rework to reduce batch message size (add counter field)
This patch adds the counter field to the osmux header, so we can
reduce the size of the batch even further, eg.
osmuxhdr (ctr=3)
speech
speech
speech
osmuxhdr (ctr=2)
speech
speech
...
The new header is the following:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| FT | CTR |F|Q| SeqNR | Circuit ID |AMR-FT |AMR-CMR|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
The counter field is 3 bits long, thus, we can batch up to 8
RTP speech frames into one single batch per circuit ID.
I have also removed the RTP marker, since it can be reconstructed
from the AMR information.
Moreover, the entire workflow has been also reworked. Whenever a
packet arrives, we introduce it into the batch list. This batch
list contains a list of RTP messages ordered by RTP SSRC. Then,
once the batch timer expires or the it gets full, we build the
batch from the list of RTP messages.
Note that this allows us to put several speech frame into one
single osmux header without actually worrying about the amount
of messages that we'll receive.
The functions that reconstruct the RTP messages has been also
adjusted. Now, it returns a list of RTP messages per RTP SSRC
that has been extracted from the batch.
2012-08-02 18:24:57 +00:00
|
|
|
|
|
|
|
/* annotate current osmux header */
|
2012-08-06 16:41:49 +00:00
|
|
|
batch->osmuxh = osmuxh;
|
2012-08-04 18:52:45 +00:00
|
|
|
} else {
|
2012-08-06 16:41:49 +00:00
|
|
|
if (batch->osmuxh->ctr == 0x7) {
|
2018-03-07 12:13:17 +00:00
|
|
|
LOGP(DLMUX, LOGL_ERROR, "cannot add msg=%p, "
|
2015-07-17 14:58:31 +00:00
|
|
|
"too many messages for this RTP ssrc=%u\n",
|
|
|
|
state->msg, state->rtph->ssrc);
|
2012-08-04 18:52:45 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2012-08-06 16:41:49 +00:00
|
|
|
batch->osmuxh->ctr++;
|
2012-08-04 18:52:45 +00:00
|
|
|
}
|
osmux: major rework to reduce batch message size (add counter field)
This patch adds the counter field to the osmux header, so we can
reduce the size of the batch even further, eg.
osmuxhdr (ctr=3)
speech
speech
speech
osmuxhdr (ctr=2)
speech
speech
...
The new header is the following:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| FT | CTR |F|Q| SeqNR | Circuit ID |AMR-FT |AMR-CMR|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
The counter field is 3 bits long, thus, we can batch up to 8
RTP speech frames into one single batch per circuit ID.
I have also removed the RTP marker, since it can be reconstructed
from the AMR information.
Moreover, the entire workflow has been also reworked. Whenever a
packet arrives, we introduce it into the batch list. This batch
list contains a list of RTP messages ordered by RTP SSRC. Then,
once the batch timer expires or the it gets full, we build the
batch from the list of RTP messages.
Note that this allows us to put several speech frame into one
single osmux header without actually worrying about the amount
of messages that we'll receive.
The functions that reconstruct the RTP messages has been also
adjusted. Now, it returns a list of RTP messages per RTP SSRC
that has been extracted from the batch.
2012-08-02 18:24:57 +00:00
|
|
|
|
2015-07-17 14:58:31 +00:00
|
|
|
memcpy(state->out_msg->tail, osmo_amr_get_payload(state->amrh),
|
|
|
|
state->amr_payload_len);
|
|
|
|
msgb_put(state->out_msg, state->amr_payload_len);
|
osmux: major rework to reduce batch message size (add counter field)
This patch adds the counter field to the osmux header, so we can
reduce the size of the batch even further, eg.
osmuxhdr (ctr=3)
speech
speech
speech
osmuxhdr (ctr=2)
speech
speech
...
The new header is the following:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| FT | CTR |F|Q| SeqNR | Circuit ID |AMR-FT |AMR-CMR|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
The counter field is 3 bits long, thus, we can batch up to 8
RTP speech frames into one single batch per circuit ID.
I have also removed the RTP marker, since it can be reconstructed
from the AMR information.
Moreover, the entire workflow has been also reworked. Whenever a
packet arrives, we introduce it into the batch list. This batch
list contains a list of RTP messages ordered by RTP SSRC. Then,
once the batch timer expires or the it gets full, we build the
batch from the list of RTP messages.
Note that this allows us to put several speech frame into one
single osmux header without actually worrying about the amount
of messages that we'll receive.
The functions that reconstruct the RTP messages has been also
adjusted. Now, it returns a list of RTP messages per RTP SSRC
that has been extracted from the batch.
2012-08-02 18:24:57 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-07-17 18:13:16 +00:00
|
|
|
static int osmux_xfrm_encode_amr(struct osmux_batch *batch,
|
2015-07-17 14:58:31 +00:00
|
|
|
struct osmux_input_state *state)
|
2012-07-09 17:39:55 +00:00
|
|
|
{
|
osmux: major rework to reduce batch message size (add counter field)
This patch adds the counter field to the osmux header, so we can
reduce the size of the batch even further, eg.
osmuxhdr (ctr=3)
speech
speech
speech
osmuxhdr (ctr=2)
speech
speech
...
The new header is the following:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| FT | CTR |F|Q| SeqNR | Circuit ID |AMR-FT |AMR-CMR|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
The counter field is 3 bits long, thus, we can batch up to 8
RTP speech frames into one single batch per circuit ID.
I have also removed the RTP marker, since it can be reconstructed
from the AMR information.
Moreover, the entire workflow has been also reworked. Whenever a
packet arrives, we introduce it into the batch list. This batch
list contains a list of RTP messages ordered by RTP SSRC. Then,
once the batch timer expires or the it gets full, we build the
batch from the list of RTP messages.
Note that this allows us to put several speech frame into one
single osmux header without actually worrying about the amount
of messages that we'll receive.
The functions that reconstruct the RTP messages has been also
adjusted. Now, it returns a list of RTP messages per RTP SSRC
that has been extracted from the batch.
2012-08-02 18:24:57 +00:00
|
|
|
uint32_t amr_len;
|
|
|
|
|
2015-07-17 14:58:31 +00:00
|
|
|
state->amrh = osmo_rtp_get_payload(state->rtph, state->msg, &amr_len);
|
|
|
|
if (state->amrh == NULL)
|
osmux: major rework to reduce batch message size (add counter field)
This patch adds the counter field to the osmux header, so we can
reduce the size of the batch even further, eg.
osmuxhdr (ctr=3)
speech
speech
speech
osmuxhdr (ctr=2)
speech
speech
...
The new header is the following:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| FT | CTR |F|Q| SeqNR | Circuit ID |AMR-FT |AMR-CMR|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
The counter field is 3 bits long, thus, we can batch up to 8
RTP speech frames into one single batch per circuit ID.
I have also removed the RTP marker, since it can be reconstructed
from the AMR information.
Moreover, the entire workflow has been also reworked. Whenever a
packet arrives, we introduce it into the batch list. This batch
list contains a list of RTP messages ordered by RTP SSRC. Then,
once the batch timer expires or the it gets full, we build the
batch from the list of RTP messages.
Note that this allows us to put several speech frame into one
single osmux header without actually worrying about the amount
of messages that we'll receive.
The functions that reconstruct the RTP messages has been also
adjusted. Now, it returns a list of RTP messages per RTP SSRC
that has been extracted from the batch.
2012-08-02 18:24:57 +00:00
|
|
|
return -1;
|
|
|
|
|
2015-07-17 14:58:31 +00:00
|
|
|
state->amr_payload_len = amr_len - sizeof(struct amr_hdr);
|
osmux: major rework to reduce batch message size (add counter field)
This patch adds the counter field to the osmux header, so we can
reduce the size of the batch even further, eg.
osmuxhdr (ctr=3)
speech
speech
speech
osmuxhdr (ctr=2)
speech
speech
...
The new header is the following:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| FT | CTR |F|Q| SeqNR | Circuit ID |AMR-FT |AMR-CMR|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
The counter field is 3 bits long, thus, we can batch up to 8
RTP speech frames into one single batch per circuit ID.
I have also removed the RTP marker, since it can be reconstructed
from the AMR information.
Moreover, the entire workflow has been also reworked. Whenever a
packet arrives, we introduce it into the batch list. This batch
list contains a list of RTP messages ordered by RTP SSRC. Then,
once the batch timer expires or the it gets full, we build the
batch from the list of RTP messages.
Note that this allows us to put several speech frame into one
single osmux header without actually worrying about the amount
of messages that we'll receive.
The functions that reconstruct the RTP messages has been also
adjusted. Now, it returns a list of RTP messages per RTP SSRC
that has been extracted from the batch.
2012-08-02 18:24:57 +00:00
|
|
|
|
2015-07-17 18:13:16 +00:00
|
|
|
if (osmux_batch_put(batch, state) < 0)
|
osmux: major rework to reduce batch message size (add counter field)
This patch adds the counter field to the osmux header, so we can
reduce the size of the batch even further, eg.
osmuxhdr (ctr=3)
speech
speech
speech
osmuxhdr (ctr=2)
speech
speech
...
The new header is the following:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| FT | CTR |F|Q| SeqNR | Circuit ID |AMR-FT |AMR-CMR|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
The counter field is 3 bits long, thus, we can batch up to 8
RTP speech frames into one single batch per circuit ID.
I have also removed the RTP marker, since it can be reconstructed
from the AMR information.
Moreover, the entire workflow has been also reworked. Whenever a
packet arrives, we introduce it into the batch list. This batch
list contains a list of RTP messages ordered by RTP SSRC. Then,
once the batch timer expires or the it gets full, we build the
batch from the list of RTP messages.
Note that this allows us to put several speech frame into one
single osmux header without actually worrying about the amount
of messages that we'll receive.
The functions that reconstruct the RTP messages has been also
adjusted. Now, it returns a list of RTP messages per RTP SSRC
that has been extracted from the batch.
2012-08-02 18:24:57 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-04-25 15:27:13 +00:00
|
|
|
static void osmux_encode_dummy(struct osmux_batch *batch, uint8_t batch_factor,
|
2015-07-17 18:47:04 +00:00
|
|
|
struct osmux_input_state *state)
|
|
|
|
{
|
|
|
|
struct osmux_hdr *osmuxh;
|
|
|
|
/* TODO: This should be configurable at some point. */
|
|
|
|
uint32_t payload_size = osmux_ft_dummy_size(AMR_FT_3, batch_factor) -
|
|
|
|
sizeof(struct osmux_hdr);
|
|
|
|
|
|
|
|
osmuxh = (struct osmux_hdr *)state->out_msg->tail;
|
|
|
|
osmuxh->ft = OSMUX_FT_DUMMY;
|
|
|
|
osmuxh->ctr = batch_factor - 1;
|
|
|
|
osmuxh->amr_f = 0;
|
|
|
|
osmuxh->amr_q= 0;
|
|
|
|
osmuxh->seq = 0;
|
|
|
|
osmuxh->circuit_id = state->ccid;
|
|
|
|
osmuxh->amr_cmr = 0;
|
|
|
|
osmuxh->amr_ft = AMR_FT_3;
|
|
|
|
msgb_put(state->out_msg, sizeof(struct osmux_hdr));
|
|
|
|
|
|
|
|
memset(state->out_msg->tail, 0xff, payload_size);
|
|
|
|
msgb_put(state->out_msg, payload_size);
|
|
|
|
}
|
|
|
|
|
2015-07-17 18:13:16 +00:00
|
|
|
static struct msgb *osmux_build_batch(struct osmux_batch *batch,
|
2017-04-25 15:27:13 +00:00
|
|
|
uint32_t batch_size, uint8_t batch_factor)
|
osmux: major rework to reduce batch message size (add counter field)
This patch adds the counter field to the osmux header, so we can
reduce the size of the batch even further, eg.
osmuxhdr (ctr=3)
speech
speech
speech
osmuxhdr (ctr=2)
speech
speech
...
The new header is the following:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| FT | CTR |F|Q| SeqNR | Circuit ID |AMR-FT |AMR-CMR|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
The counter field is 3 bits long, thus, we can batch up to 8
RTP speech frames into one single batch per circuit ID.
I have also removed the RTP marker, since it can be reconstructed
from the AMR information.
Moreover, the entire workflow has been also reworked. Whenever a
packet arrives, we introduce it into the batch list. This batch
list contains a list of RTP messages ordered by RTP SSRC. Then,
once the batch timer expires or the it gets full, we build the
batch from the list of RTP messages.
Note that this allows us to put several speech frame into one
single osmux header without actually worrying about the amount
of messages that we'll receive.
The functions that reconstruct the RTP messages has been also
adjusted. Now, it returns a list of RTP messages per RTP SSRC
that has been extracted from the batch.
2012-08-02 18:24:57 +00:00
|
|
|
{
|
2012-10-15 18:33:32 +00:00
|
|
|
struct msgb *batch_msg;
|
2015-07-17 17:55:18 +00:00
|
|
|
struct osmux_circuit *circuit;
|
osmux: major rework to reduce batch message size (add counter field)
This patch adds the counter field to the osmux header, so we can
reduce the size of the batch even further, eg.
osmuxhdr (ctr=3)
speech
speech
speech
osmuxhdr (ctr=2)
speech
speech
...
The new header is the following:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| FT | CTR |F|Q| SeqNR | Circuit ID |AMR-FT |AMR-CMR|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
The counter field is 3 bits long, thus, we can batch up to 8
RTP speech frames into one single batch per circuit ID.
I have also removed the RTP marker, since it can be reconstructed
from the AMR information.
Moreover, the entire workflow has been also reworked. Whenever a
packet arrives, we introduce it into the batch list. This batch
list contains a list of RTP messages ordered by RTP SSRC. Then,
once the batch timer expires or the it gets full, we build the
batch from the list of RTP messages.
Note that this allows us to put several speech frame into one
single osmux header without actually worrying about the amount
of messages that we'll receive.
The functions that reconstruct the RTP messages has been also
adjusted. Now, it returns a list of RTP messages per RTP SSRC
that has been extracted from the batch.
2012-08-02 18:24:57 +00:00
|
|
|
|
2014-08-28 15:30:01 +00:00
|
|
|
#ifdef DEBUG_MSG
|
2018-03-07 12:13:17 +00:00
|
|
|
LOGP(DLMUX, LOGL_DEBUG, "Now building batch\n");
|
2014-08-28 15:30:01 +00:00
|
|
|
#endif
|
2012-10-15 18:33:32 +00:00
|
|
|
|
2015-07-17 18:13:16 +00:00
|
|
|
batch_msg = msgb_alloc(batch_size, "osmux");
|
osmux: major rework to reduce batch message size (add counter field)
This patch adds the counter field to the osmux header, so we can
reduce the size of the batch even further, eg.
osmuxhdr (ctr=3)
speech
speech
speech
osmuxhdr (ctr=2)
speech
speech
...
The new header is the following:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| FT | CTR |F|Q| SeqNR | Circuit ID |AMR-FT |AMR-CMR|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
The counter field is 3 bits long, thus, we can batch up to 8
RTP speech frames into one single batch per circuit ID.
I have also removed the RTP marker, since it can be reconstructed
from the AMR information.
Moreover, the entire workflow has been also reworked. Whenever a
packet arrives, we introduce it into the batch list. This batch
list contains a list of RTP messages ordered by RTP SSRC. Then,
once the batch timer expires or the it gets full, we build the
batch from the list of RTP messages.
Note that this allows us to put several speech frame into one
single osmux header without actually worrying about the amount
of messages that we'll receive.
The functions that reconstruct the RTP messages has been also
adjusted. Now, it returns a list of RTP messages per RTP SSRC
that has been extracted from the batch.
2012-08-02 18:24:57 +00:00
|
|
|
if (batch_msg == NULL) {
|
2018-03-07 12:13:17 +00:00
|
|
|
LOGP(DLMUX, LOGL_ERROR, "Not enough memory\n");
|
osmux: major rework to reduce batch message size (add counter field)
This patch adds the counter field to the osmux header, so we can
reduce the size of the batch even further, eg.
osmuxhdr (ctr=3)
speech
speech
speech
osmuxhdr (ctr=2)
speech
speech
...
The new header is the following:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| FT | CTR |F|Q| SeqNR | Circuit ID |AMR-FT |AMR-CMR|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
The counter field is 3 bits long, thus, we can batch up to 8
RTP speech frames into one single batch per circuit ID.
I have also removed the RTP marker, since it can be reconstructed
from the AMR information.
Moreover, the entire workflow has been also reworked. Whenever a
packet arrives, we introduce it into the batch list. This batch
list contains a list of RTP messages ordered by RTP SSRC. Then,
once the batch timer expires or the it gets full, we build the
batch from the list of RTP messages.
Note that this allows us to put several speech frame into one
single osmux header without actually worrying about the amount
of messages that we'll receive.
The functions that reconstruct the RTP messages has been also
adjusted. Now, it returns a list of RTP messages per RTP SSRC
that has been extracted from the batch.
2012-08-02 18:24:57 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2015-07-17 17:55:18 +00:00
|
|
|
llist_for_each_entry(circuit, &batch->circuit_list, head) {
|
2012-10-15 18:33:32 +00:00
|
|
|
struct msgb *cur, *tmp;
|
|
|
|
int ctr = 0;
|
2012-08-04 18:56:53 +00:00
|
|
|
|
2015-07-17 18:47:04 +00:00
|
|
|
if (circuit->dummy) {
|
|
|
|
struct osmux_input_state state = {
|
|
|
|
.out_msg = batch_msg,
|
|
|
|
.ccid = circuit->ccid,
|
|
|
|
};
|
|
|
|
osmux_encode_dummy(batch, batch_factor, &state);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2015-07-17 17:37:28 +00:00
|
|
|
llist_for_each_entry_safe(cur, tmp, &circuit->msg_list, list) {
|
2015-07-17 14:58:31 +00:00
|
|
|
struct osmux_input_state state = {
|
|
|
|
.msg = cur,
|
|
|
|
.out_msg = batch_msg,
|
2015-07-17 17:24:49 +00:00
|
|
|
.ccid = circuit->ccid,
|
2015-07-17 14:58:31 +00:00
|
|
|
};
|
2014-08-28 15:15:44 +00:00
|
|
|
#ifdef DEBUG_MSG
|
|
|
|
char buf[4096];
|
|
|
|
|
2012-10-15 18:33:32 +00:00
|
|
|
osmo_rtp_snprintf(buf, sizeof(buf), cur);
|
2013-05-24 10:49:52 +00:00
|
|
|
buf[sizeof(buf)-1] = '\0';
|
2018-03-07 12:13:17 +00:00
|
|
|
LOGP(DLMUX, LOGL_DEBUG, "to BSC-NAT: %s\n", buf);
|
2014-08-28 15:15:44 +00:00
|
|
|
#endif
|
osmux: major rework to reduce batch message size (add counter field)
This patch adds the counter field to the osmux header, so we can
reduce the size of the batch even further, eg.
osmuxhdr (ctr=3)
speech
speech
speech
osmuxhdr (ctr=2)
speech
speech
...
The new header is the following:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| FT | CTR |F|Q| SeqNR | Circuit ID |AMR-FT |AMR-CMR|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
The counter field is 3 bits long, thus, we can batch up to 8
RTP speech frames into one single batch per circuit ID.
I have also removed the RTP marker, since it can be reconstructed
from the AMR information.
Moreover, the entire workflow has been also reworked. Whenever a
packet arrives, we introduce it into the batch list. This batch
list contains a list of RTP messages ordered by RTP SSRC. Then,
once the batch timer expires or the it gets full, we build the
batch from the list of RTP messages.
Note that this allows us to put several speech frame into one
single osmux header without actually worrying about the amount
of messages that we'll receive.
The functions that reconstruct the RTP messages has been also
adjusted. Now, it returns a list of RTP messages per RTP SSRC
that has been extracted from the batch.
2012-08-02 18:24:57 +00:00
|
|
|
|
2015-07-17 14:58:31 +00:00
|
|
|
state.rtph = osmo_rtp_get_hdr(cur);
|
|
|
|
if (state.rtph == NULL)
|
2012-10-15 18:33:32 +00:00
|
|
|
return NULL;
|
osmux: major rework to reduce batch message size (add counter field)
This patch adds the counter field to the osmux header, so we can
reduce the size of the batch even further, eg.
osmuxhdr (ctr=3)
speech
speech
speech
osmuxhdr (ctr=2)
speech
speech
...
The new header is the following:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| FT | CTR |F|Q| SeqNR | Circuit ID |AMR-FT |AMR-CMR|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
The counter field is 3 bits long, thus, we can batch up to 8
RTP speech frames into one single batch per circuit ID.
I have also removed the RTP marker, since it can be reconstructed
from the AMR information.
Moreover, the entire workflow has been also reworked. Whenever a
packet arrives, we introduce it into the batch list. This batch
list contains a list of RTP messages ordered by RTP SSRC. Then,
once the batch timer expires or the it gets full, we build the
batch from the list of RTP messages.
Note that this allows us to put several speech frame into one
single osmux header without actually worrying about the amount
of messages that we'll receive.
The functions that reconstruct the RTP messages has been also
adjusted. Now, it returns a list of RTP messages per RTP SSRC
that has been extracted from the batch.
2012-08-02 18:24:57 +00:00
|
|
|
|
2012-10-15 18:33:32 +00:00
|
|
|
if (ctr == 0) {
|
2014-08-28 15:15:44 +00:00
|
|
|
#ifdef DEBUG_MSG
|
2018-03-07 12:13:17 +00:00
|
|
|
LOGP(DLMUX, LOGL_DEBUG, "add osmux header\n");
|
2014-08-28 15:15:44 +00:00
|
|
|
#endif
|
2015-07-17 14:58:31 +00:00
|
|
|
state.add_osmux_hdr = 1;
|
2012-10-15 18:33:32 +00:00
|
|
|
}
|
osmux: major rework to reduce batch message size (add counter field)
This patch adds the counter field to the osmux header, so we can
reduce the size of the batch even further, eg.
osmuxhdr (ctr=3)
speech
speech
speech
osmuxhdr (ctr=2)
speech
speech
...
The new header is the following:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| FT | CTR |F|Q| SeqNR | Circuit ID |AMR-FT |AMR-CMR|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
The counter field is 3 bits long, thus, we can batch up to 8
RTP speech frames into one single batch per circuit ID.
I have also removed the RTP marker, since it can be reconstructed
from the AMR information.
Moreover, the entire workflow has been also reworked. Whenever a
packet arrives, we introduce it into the batch list. This batch
list contains a list of RTP messages ordered by RTP SSRC. Then,
once the batch timer expires or the it gets full, we build the
batch from the list of RTP messages.
Note that this allows us to put several speech frame into one
single osmux header without actually worrying about the amount
of messages that we'll receive.
The functions that reconstruct the RTP messages has been also
adjusted. Now, it returns a list of RTP messages per RTP SSRC
that has been extracted from the batch.
2012-08-02 18:24:57 +00:00
|
|
|
|
2015-07-17 18:13:16 +00:00
|
|
|
osmux_xfrm_encode_amr(batch, &state);
|
2015-07-17 17:24:49 +00:00
|
|
|
osmux_batch_dequeue(cur, circuit);
|
2012-10-15 18:33:32 +00:00
|
|
|
msgb_free(cur);
|
|
|
|
ctr++;
|
2015-07-17 18:23:25 +00:00
|
|
|
batch->nmsgs--;
|
2012-10-15 18:33:32 +00:00
|
|
|
}
|
osmux: major rework to reduce batch message size (add counter field)
This patch adds the counter field to the osmux header, so we can
reduce the size of the batch even further, eg.
osmuxhdr (ctr=3)
speech
speech
speech
osmuxhdr (ctr=2)
speech
speech
...
The new header is the following:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| FT | CTR |F|Q| SeqNR | Circuit ID |AMR-FT |AMR-CMR|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
The counter field is 3 bits long, thus, we can batch up to 8
RTP speech frames into one single batch per circuit ID.
I have also removed the RTP marker, since it can be reconstructed
from the AMR information.
Moreover, the entire workflow has been also reworked. Whenever a
packet arrives, we introduce it into the batch list. This batch
list contains a list of RTP messages ordered by RTP SSRC. Then,
once the batch timer expires or the it gets full, we build the
batch from the list of RTP messages.
Note that this allows us to put several speech frame into one
single osmux header without actually worrying about the amount
of messages that we'll receive.
The functions that reconstruct the RTP messages has been also
adjusted. Now, it returns a list of RTP messages per RTP SSRC
that has been extracted from the batch.
2012-08-02 18:24:57 +00:00
|
|
|
}
|
|
|
|
return batch_msg;
|
2012-07-09 17:39:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void osmux_xfrm_input_deliver(struct osmux_in_handle *h)
|
|
|
|
{
|
osmux: major rework to reduce batch message size (add counter field)
This patch adds the counter field to the osmux header, so we can
reduce the size of the batch even further, eg.
osmuxhdr (ctr=3)
speech
speech
speech
osmuxhdr (ctr=2)
speech
speech
...
The new header is the following:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| FT | CTR |F|Q| SeqNR | Circuit ID |AMR-FT |AMR-CMR|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
The counter field is 3 bits long, thus, we can batch up to 8
RTP speech frames into one single batch per circuit ID.
I have also removed the RTP marker, since it can be reconstructed
from the AMR information.
Moreover, the entire workflow has been also reworked. Whenever a
packet arrives, we introduce it into the batch list. This batch
list contains a list of RTP messages ordered by RTP SSRC. Then,
once the batch timer expires or the it gets full, we build the
batch from the list of RTP messages.
Note that this allows us to put several speech frame into one
single osmux header without actually worrying about the amount
of messages that we'll receive.
The functions that reconstruct the RTP messages has been also
adjusted. Now, it returns a list of RTP messages per RTP SSRC
that has been extracted from the batch.
2012-08-02 18:24:57 +00:00
|
|
|
struct msgb *batch_msg;
|
2013-02-11 21:49:27 +00:00
|
|
|
struct osmux_batch *batch = (struct osmux_batch *)h->internal_data;
|
osmux: major rework to reduce batch message size (add counter field)
This patch adds the counter field to the osmux header, so we can
reduce the size of the batch even further, eg.
osmuxhdr (ctr=3)
speech
speech
speech
osmuxhdr (ctr=2)
speech
speech
...
The new header is the following:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| FT | CTR |F|Q| SeqNR | Circuit ID |AMR-FT |AMR-CMR|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
The counter field is 3 bits long, thus, we can batch up to 8
RTP speech frames into one single batch per circuit ID.
I have also removed the RTP marker, since it can be reconstructed
from the AMR information.
Moreover, the entire workflow has been also reworked. Whenever a
packet arrives, we introduce it into the batch list. This batch
list contains a list of RTP messages ordered by RTP SSRC. Then,
once the batch timer expires or the it gets full, we build the
batch from the list of RTP messages.
Note that this allows us to put several speech frame into one
single osmux header without actually worrying about the amount
of messages that we'll receive.
The functions that reconstruct the RTP messages has been also
adjusted. Now, it returns a list of RTP messages per RTP SSRC
that has been extracted from the batch.
2012-08-02 18:24:57 +00:00
|
|
|
|
2014-08-28 15:15:44 +00:00
|
|
|
#ifdef DEBUG_MSG
|
2018-03-07 12:13:17 +00:00
|
|
|
LOGP(DLMUX, LOGL_DEBUG, "invoking delivery function\n");
|
2014-08-28 15:15:44 +00:00
|
|
|
#endif
|
2015-07-17 18:47:04 +00:00
|
|
|
batch_msg = osmux_build_batch(batch, h->batch_size, h->batch_factor);
|
2017-02-07 10:46:41 +00:00
|
|
|
if (!batch_msg)
|
|
|
|
return;
|
2014-08-28 14:14:16 +00:00
|
|
|
h->stats.output_osmux_msgs++;
|
|
|
|
h->stats.output_osmux_bytes += batch_msg->len;
|
|
|
|
|
2013-02-11 21:49:27 +00:00
|
|
|
h->deliver(batch_msg, h->data);
|
2012-08-06 16:41:49 +00:00
|
|
|
osmo_timer_del(&batch->timer);
|
2014-08-28 13:01:03 +00:00
|
|
|
batch->remaining_bytes = h->batch_size;
|
2015-07-17 18:47:04 +00:00
|
|
|
|
2015-08-18 22:19:53 +00:00
|
|
|
if (batch->ndummy) {
|
2015-07-17 18:47:04 +00:00
|
|
|
osmo_timer_schedule(&batch->timer, 0,
|
|
|
|
h->batch_factor * DELTA_RTP_MSG);
|
|
|
|
}
|
2012-07-09 17:39:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void osmux_batch_timer_expired(void *data)
|
|
|
|
{
|
|
|
|
struct osmux_in_handle *h = data;
|
|
|
|
|
2014-08-28 15:15:44 +00:00
|
|
|
#ifdef DEBUG_MSG
|
2018-03-07 12:13:17 +00:00
|
|
|
LOGP(DLMUX, LOGL_DEBUG, "osmux_batch_timer_expired\n");
|
2014-08-28 15:15:44 +00:00
|
|
|
#endif
|
2012-07-09 17:39:55 +00:00
|
|
|
osmux_xfrm_input_deliver(h);
|
|
|
|
}
|
|
|
|
|
osmux: major rework to reduce batch message size (add counter field)
This patch adds the counter field to the osmux header, so we can
reduce the size of the batch even further, eg.
osmuxhdr (ctr=3)
speech
speech
speech
osmuxhdr (ctr=2)
speech
speech
...
The new header is the following:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| FT | CTR |F|Q| SeqNR | Circuit ID |AMR-FT |AMR-CMR|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
The counter field is 3 bits long, thus, we can batch up to 8
RTP speech frames into one single batch per circuit ID.
I have also removed the RTP marker, since it can be reconstructed
from the AMR information.
Moreover, the entire workflow has been also reworked. Whenever a
packet arrives, we introduce it into the batch list. This batch
list contains a list of RTP messages ordered by RTP SSRC. Then,
once the batch timer expires or the it gets full, we build the
batch from the list of RTP messages.
Note that this allows us to put several speech frame into one
single osmux header without actually worrying about the amount
of messages that we'll receive.
The functions that reconstruct the RTP messages has been also
adjusted. Now, it returns a list of RTP messages per RTP SSRC
that has been extracted from the batch.
2012-08-02 18:24:57 +00:00
|
|
|
static int osmux_rtp_amr_payload_len(struct msgb *msg, struct rtp_hdr *rtph)
|
2012-07-09 17:39:55 +00:00
|
|
|
{
|
osmux: major rework to reduce batch message size (add counter field)
This patch adds the counter field to the osmux header, so we can
reduce the size of the batch even further, eg.
osmuxhdr (ctr=3)
speech
speech
speech
osmuxhdr (ctr=2)
speech
speech
...
The new header is the following:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| FT | CTR |F|Q| SeqNR | Circuit ID |AMR-FT |AMR-CMR|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
The counter field is 3 bits long, thus, we can batch up to 8
RTP speech frames into one single batch per circuit ID.
I have also removed the RTP marker, since it can be reconstructed
from the AMR information.
Moreover, the entire workflow has been also reworked. Whenever a
packet arrives, we introduce it into the batch list. This batch
list contains a list of RTP messages ordered by RTP SSRC. Then,
once the batch timer expires or the it gets full, we build the
batch from the list of RTP messages.
Note that this allows us to put several speech frame into one
single osmux header without actually worrying about the amount
of messages that we'll receive.
The functions that reconstruct the RTP messages has been also
adjusted. Now, it returns a list of RTP messages per RTP SSRC
that has been extracted from the batch.
2012-08-02 18:24:57 +00:00
|
|
|
struct amr_hdr *amrh;
|
|
|
|
unsigned int amr_len;
|
2013-12-16 12:36:13 +00:00
|
|
|
int amr_payload_len;
|
2012-07-09 17:39:55 +00:00
|
|
|
|
osmux: major rework to reduce batch message size (add counter field)
This patch adds the counter field to the osmux header, so we can
reduce the size of the batch even further, eg.
osmuxhdr (ctr=3)
speech
speech
speech
osmuxhdr (ctr=2)
speech
speech
...
The new header is the following:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| FT | CTR |F|Q| SeqNR | Circuit ID |AMR-FT |AMR-CMR|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
The counter field is 3 bits long, thus, we can batch up to 8
RTP speech frames into one single batch per circuit ID.
I have also removed the RTP marker, since it can be reconstructed
from the AMR information.
Moreover, the entire workflow has been also reworked. Whenever a
packet arrives, we introduce it into the batch list. This batch
list contains a list of RTP messages ordered by RTP SSRC. Then,
once the batch timer expires or the it gets full, we build the
batch from the list of RTP messages.
Note that this allows us to put several speech frame into one
single osmux header without actually worrying about the amount
of messages that we'll receive.
The functions that reconstruct the RTP messages has been also
adjusted. Now, it returns a list of RTP messages per RTP SSRC
that has been extracted from the batch.
2012-08-02 18:24:57 +00:00
|
|
|
amrh = osmo_rtp_get_payload(rtph, msg, &amr_len);
|
|
|
|
if (amrh == NULL)
|
|
|
|
return -1;
|
2012-07-09 17:39:55 +00:00
|
|
|
|
2013-05-24 09:56:07 +00:00
|
|
|
if (!osmo_amr_ft_valid(amrh->ft))
|
|
|
|
return -1;
|
|
|
|
|
2013-12-16 12:36:13 +00:00
|
|
|
amr_payload_len = amr_len - sizeof(struct amr_hdr);
|
|
|
|
|
|
|
|
/* The AMR payload does not fit with what we expect */
|
|
|
|
if (osmo_amr_bytes(amrh->ft) != amr_payload_len) {
|
2018-03-07 12:13:17 +00:00
|
|
|
LOGP(DLMUX, LOGL_ERROR,
|
2013-12-16 12:36:13 +00:00
|
|
|
"Bad AMR frame, expected %zd bytes, got %d bytes\n",
|
|
|
|
osmo_amr_bytes(amrh->ft), amr_len);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return amr_payload_len;
|
2012-07-09 17:39:55 +00:00
|
|
|
}
|
|
|
|
|
2022-09-27 16:24:11 +00:00
|
|
|
/* returns: 1 if batch is full, 0 if batch still not full, negative on error. */
|
|
|
|
static int osmux_replay_lost_packets(struct osmux_circuit *circuit,
|
2017-04-12 14:11:50 +00:00
|
|
|
struct rtp_hdr *cur_rtph, int batch_factor)
|
2013-05-20 22:28:13 +00:00
|
|
|
{
|
2013-12-16 11:14:31 +00:00
|
|
|
int16_t diff;
|
2013-05-20 22:28:13 +00:00
|
|
|
struct msgb *last;
|
|
|
|
struct rtp_hdr *rtph;
|
2022-09-27 16:24:11 +00:00
|
|
|
int i, rc;
|
2013-05-20 22:28:13 +00:00
|
|
|
|
2022-09-27 15:35:29 +00:00
|
|
|
/* Have we seen any RTP packet in this batch before? */
|
2015-07-17 17:37:28 +00:00
|
|
|
if (llist_empty(&circuit->msg_list))
|
2022-09-27 16:24:11 +00:00
|
|
|
return 0;
|
2013-05-20 22:28:13 +00:00
|
|
|
|
|
|
|
/* Get last RTP packet seen in this batch */
|
2015-07-17 17:37:28 +00:00
|
|
|
last = llist_entry(circuit->msg_list.prev, struct msgb, list);
|
2013-05-20 22:28:13 +00:00
|
|
|
rtph = osmo_rtp_get_hdr(last);
|
|
|
|
if (rtph == NULL)
|
2022-09-27 16:24:11 +00:00
|
|
|
return -1;
|
2013-05-20 22:28:13 +00:00
|
|
|
|
|
|
|
diff = ntohs(cur_rtph->sequence) - ntohs(rtph->sequence);
|
|
|
|
|
2013-09-12 11:18:19 +00:00
|
|
|
/* Lifesaver: make sure bugs don't spawn lots of clones */
|
|
|
|
if (diff > 16)
|
|
|
|
diff = 16;
|
|
|
|
|
2022-09-27 16:24:11 +00:00
|
|
|
rc = 0;
|
2013-05-20 22:28:13 +00:00
|
|
|
/* If diff between last RTP packet seen and this one is > 1,
|
|
|
|
* then we lost several RTP packets, let's replay them.
|
|
|
|
*/
|
|
|
|
for (i=1; i<diff; i++) {
|
|
|
|
struct msgb *clone;
|
|
|
|
|
|
|
|
/* Clone last RTP packet seen */
|
|
|
|
clone = msgb_alloc(last->data_len, "RTP clone");
|
|
|
|
if (!clone)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
memcpy(clone->data, last->data, last->len);
|
|
|
|
msgb_put(clone, last->len);
|
|
|
|
|
2022-09-27 15:35:29 +00:00
|
|
|
/* The original RTP message has been already sanity checked. */
|
2013-05-20 22:28:13 +00:00
|
|
|
rtph = osmo_rtp_get_hdr(clone);
|
|
|
|
|
|
|
|
/* Adjust sequence number and timestamp */
|
|
|
|
rtph->sequence = htons(ntohs(rtph->sequence) + i);
|
|
|
|
rtph->timestamp = htonl(ntohl(rtph->timestamp) +
|
|
|
|
DELTA_RTP_TIMESTAMP);
|
|
|
|
|
2014-08-28 12:26:03 +00:00
|
|
|
/* No more room in this batch, skip padding with more clones */
|
2022-09-27 16:24:11 +00:00
|
|
|
rc = osmux_batch_enqueue(clone, circuit, batch_factor);
|
|
|
|
if (rc != 0) {
|
2014-08-28 17:24:00 +00:00
|
|
|
msgb_free(clone);
|
2022-09-27 16:24:11 +00:00
|
|
|
return rc;
|
2014-08-28 17:24:00 +00:00
|
|
|
}
|
2014-08-28 12:26:03 +00:00
|
|
|
|
2018-03-07 12:13:17 +00:00
|
|
|
LOGP(DLMUX, LOGL_ERROR, "adding cloned RTP\n");
|
2013-05-20 22:28:13 +00:00
|
|
|
}
|
2022-09-27 16:24:11 +00:00
|
|
|
return rc;
|
2013-05-20 22:28:13 +00:00
|
|
|
}
|
|
|
|
|
2015-07-17 17:24:49 +00:00
|
|
|
static struct osmux_circuit *
|
2015-07-17 17:15:42 +00:00
|
|
|
osmux_batch_find_circuit(struct osmux_batch *batch, int ccid)
|
|
|
|
{
|
2015-07-17 17:24:49 +00:00
|
|
|
struct osmux_circuit *circuit;
|
2015-07-17 17:15:42 +00:00
|
|
|
|
2015-07-17 17:24:49 +00:00
|
|
|
llist_for_each_entry(circuit, &batch->circuit_list, head) {
|
2015-07-17 17:15:42 +00:00
|
|
|
if (circuit->ccid == ccid)
|
|
|
|
return circuit;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2015-07-17 17:24:49 +00:00
|
|
|
static struct osmux_circuit *
|
2015-07-17 18:47:04 +00:00
|
|
|
osmux_batch_add_circuit(struct osmux_batch *batch, int ccid, int dummy,
|
2017-04-25 15:27:13 +00:00
|
|
|
uint8_t batch_factor)
|
2015-07-17 17:15:42 +00:00
|
|
|
{
|
2015-07-17 17:24:49 +00:00
|
|
|
struct osmux_circuit *circuit;
|
2015-07-17 17:15:42 +00:00
|
|
|
|
|
|
|
circuit = osmux_batch_find_circuit(batch, ccid);
|
|
|
|
if (circuit != NULL) {
|
2018-03-07 12:13:17 +00:00
|
|
|
LOGP(DLMUX, LOGL_ERROR, "circuit %u already exists!\n", ccid);
|
2015-07-17 17:15:42 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2015-07-17 17:24:49 +00:00
|
|
|
circuit = talloc_zero(osmux_ctx, struct osmux_circuit);
|
2015-07-17 17:15:42 +00:00
|
|
|
if (circuit == NULL) {
|
2018-03-07 12:13:17 +00:00
|
|
|
LOGP(DLMUX, LOGL_ERROR, "OOM on circuit %u\n", ccid);
|
2015-07-17 17:15:42 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
circuit->ccid = ccid;
|
2015-07-17 17:37:28 +00:00
|
|
|
INIT_LLIST_HEAD(&circuit->msg_list);
|
2015-07-17 17:24:49 +00:00
|
|
|
llist_add_tail(&circuit->head, &batch->circuit_list);
|
2015-07-17 17:15:42 +00:00
|
|
|
|
2015-07-17 18:47:04 +00:00
|
|
|
if (dummy) {
|
|
|
|
circuit->dummy = dummy;
|
2015-08-18 22:19:53 +00:00
|
|
|
batch->ndummy++;
|
2015-07-17 18:47:04 +00:00
|
|
|
if (!osmo_timer_pending(&batch->timer))
|
|
|
|
osmo_timer_schedule(&batch->timer, 0,
|
|
|
|
batch_factor * DELTA_RTP_MSG);
|
|
|
|
}
|
2015-07-17 17:15:42 +00:00
|
|
|
return circuit;
|
|
|
|
}
|
|
|
|
|
2016-05-25 15:44:37 +00:00
|
|
|
static void osmux_batch_del_circuit(struct osmux_batch *batch, struct osmux_circuit *circuit)
|
2015-07-17 17:55:18 +00:00
|
|
|
{
|
2015-07-17 18:47:04 +00:00
|
|
|
if (circuit->dummy)
|
2015-08-18 22:19:53 +00:00
|
|
|
batch->ndummy--;
|
2015-07-17 17:55:18 +00:00
|
|
|
llist_del(&circuit->head);
|
2016-05-25 15:44:39 +00:00
|
|
|
osmux_circuit_del_msgs(batch, circuit);
|
2015-07-17 17:55:18 +00:00
|
|
|
talloc_free(circuit);
|
|
|
|
}
|
|
|
|
|
2022-09-27 16:20:56 +00:00
|
|
|
/* returns: 1 if batch is full, 0 if batch still not full, negative on error. */
|
2012-08-06 16:41:49 +00:00
|
|
|
static int
|
2017-04-25 15:27:13 +00:00
|
|
|
osmux_batch_add(struct osmux_batch *batch, uint32_t batch_factor, struct msgb *msg,
|
2013-12-15 21:35:28 +00:00
|
|
|
struct rtp_hdr *rtph, int ccid)
|
2012-07-09 17:39:55 +00:00
|
|
|
{
|
2015-07-17 17:15:42 +00:00
|
|
|
int bytes = 0, amr_payload_len;
|
2015-07-17 17:24:49 +00:00
|
|
|
struct osmux_circuit *circuit;
|
2015-07-17 18:47:04 +00:00
|
|
|
struct msgb *cur;
|
2022-09-27 16:20:56 +00:00
|
|
|
int rc;
|
2012-07-09 17:39:55 +00:00
|
|
|
|
2015-07-17 17:15:42 +00:00
|
|
|
circuit = osmux_batch_find_circuit(batch, ccid);
|
2015-07-17 18:47:04 +00:00
|
|
|
if (!circuit)
|
|
|
|
return -1;
|
2012-08-04 18:53:57 +00:00
|
|
|
|
2015-07-17 18:47:04 +00:00
|
|
|
/* We've seen the first RTP message, disable dummy padding */
|
|
|
|
if (circuit->dummy) {
|
|
|
|
circuit->dummy = 0;
|
2015-08-18 22:19:53 +00:00
|
|
|
batch->ndummy--;
|
2015-07-17 18:47:04 +00:00
|
|
|
}
|
2013-05-24 09:56:07 +00:00
|
|
|
amr_payload_len = osmux_rtp_amr_payload_len(msg, rtph);
|
2022-09-20 12:49:09 +00:00
|
|
|
if (amr_payload_len < 0) {
|
|
|
|
LOGP(DLMUX, LOGL_NOTICE, "AMR payload invalid\n");
|
2014-08-28 17:24:00 +00:00
|
|
|
return -1;
|
2022-09-20 12:49:09 +00:00
|
|
|
}
|
2013-05-24 09:56:07 +00:00
|
|
|
|
2017-04-25 15:20:38 +00:00
|
|
|
/* Init of talkspurt (RTP M marker bit) needs to be in the first AMR slot
|
|
|
|
* of the OSMUX packet, enforce sending previous batch if required:
|
|
|
|
*/
|
|
|
|
if (rtph->marker && circuit->nmsgs != 0)
|
|
|
|
return 1;
|
|
|
|
|
2015-07-17 18:47:04 +00:00
|
|
|
/* Extra validation: check if this message already exists, should not
|
|
|
|
* happen but make sure we don't propagate duplicated messages.
|
|
|
|
*/
|
|
|
|
llist_for_each_entry(cur, &circuit->msg_list, list) {
|
|
|
|
struct rtp_hdr *rtph2 = osmo_rtp_get_hdr(cur);
|
|
|
|
if (rtph2 == NULL)
|
|
|
|
return -1;
|
2013-05-20 22:28:13 +00:00
|
|
|
|
2015-07-17 18:47:04 +00:00
|
|
|
/* Already exists message with this sequence, skip */
|
|
|
|
if (rtph2->sequence == rtph->sequence) {
|
2018-03-07 12:13:17 +00:00
|
|
|
LOGP(DLMUX, LOGL_ERROR, "already exists "
|
2015-07-17 18:47:04 +00:00
|
|
|
"message with seq=%u, skip it\n",
|
|
|
|
rtph->sequence);
|
2014-08-28 17:24:00 +00:00
|
|
|
return -1;
|
2015-07-17 18:47:04 +00:00
|
|
|
}
|
2012-10-15 18:33:32 +00:00
|
|
|
}
|
2022-09-27 15:26:52 +00:00
|
|
|
|
|
|
|
/* First check if there is room for this message in the batch */
|
|
|
|
if (circuit->nmsgs == 0)
|
|
|
|
bytes += sizeof(struct osmux_hdr);
|
2022-09-27 15:31:49 +00:00
|
|
|
bytes += amr_payload_len;
|
2022-09-27 15:26:52 +00:00
|
|
|
|
|
|
|
/* No room, sorry. You'll have to retry */
|
|
|
|
if (bytes > batch->remaining_bytes)
|
|
|
|
return 1;
|
|
|
|
|
2015-07-17 18:47:04 +00:00
|
|
|
/* Handle RTP packet loss scenario */
|
2022-09-27 16:24:11 +00:00
|
|
|
rc = osmux_replay_lost_packets(circuit, rtph, batch_factor);
|
|
|
|
if (rc != 0)
|
|
|
|
return rc;
|
2012-10-15 18:33:32 +00:00
|
|
|
|
2014-08-28 12:26:03 +00:00
|
|
|
/* This batch is full, force batch delivery */
|
2022-09-27 16:20:56 +00:00
|
|
|
rc = osmux_batch_enqueue(msg, circuit, batch_factor);
|
|
|
|
if (rc != 0)
|
|
|
|
return rc;
|
2014-08-28 12:26:03 +00:00
|
|
|
|
2014-08-28 15:15:44 +00:00
|
|
|
#ifdef DEBUG_MSG
|
2018-03-07 12:13:17 +00:00
|
|
|
LOGP(DLMUX, LOGL_DEBUG, "adding msg with ssrc=%u to batch\n",
|
2012-10-15 18:33:32 +00:00
|
|
|
rtph->ssrc);
|
2014-08-28 15:15:44 +00:00
|
|
|
#endif
|
2012-10-15 18:33:32 +00:00
|
|
|
|
|
|
|
/* Update remaining room in this batch */
|
|
|
|
batch->remaining_bytes -= bytes;
|
2012-07-09 17:39:55 +00:00
|
|
|
|
2015-07-17 18:23:25 +00:00
|
|
|
if (batch->nmsgs == 0) {
|
|
|
|
#ifdef DEBUG_MSG
|
2018-03-07 12:13:17 +00:00
|
|
|
LOGP(DLMUX, LOGL_DEBUG, "osmux start timer batch\n");
|
2015-07-17 18:23:25 +00:00
|
|
|
#endif
|
|
|
|
osmo_timer_schedule(&batch->timer, 0,
|
|
|
|
batch_factor * DELTA_RTP_MSG);
|
|
|
|
}
|
|
|
|
batch->nmsgs++;
|
|
|
|
|
2012-07-09 17:39:55 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* osmux_xfrm_input - add RTP message to OSmux batch
|
|
|
|
* \param msg: RTP message that you want to batch into one OSmux message
|
|
|
|
*
|
2022-09-23 15:42:03 +00:00
|
|
|
* If 0 is returned, this indicates that the message has been batched and the
|
|
|
|
* msgb is now owned by the osmux layer.
|
|
|
|
* If negative value is returned, an error occurred and the message has been
|
|
|
|
* dropped (and freed).
|
|
|
|
* If 1 is returned, you have to invoke osmux_xfrm_input_deliver and try again.
|
2014-08-28 18:18:19 +00:00
|
|
|
*
|
|
|
|
* The function takes care of releasing the messages in case of error and
|
|
|
|
* when building the batch.
|
2012-07-09 17:39:55 +00:00
|
|
|
*/
|
2012-10-20 18:10:31 +00:00
|
|
|
int osmux_xfrm_input(struct osmux_in_handle *h, struct msgb *msg, int ccid)
|
2012-07-09 17:39:55 +00:00
|
|
|
{
|
2015-07-17 18:23:25 +00:00
|
|
|
int ret;
|
2012-07-09 17:39:55 +00:00
|
|
|
struct rtp_hdr *rtph;
|
2013-02-11 21:49:27 +00:00
|
|
|
struct osmux_batch *batch = (struct osmux_batch *)h->internal_data;
|
2012-07-09 17:39:55 +00:00
|
|
|
|
2013-08-27 15:15:27 +00:00
|
|
|
/* Ignore too big RTP/RTCP messages, most likely forged. Sanity check
|
|
|
|
* to avoid a possible forever loop in the caller.
|
|
|
|
*/
|
2014-08-28 18:18:19 +00:00
|
|
|
if (msg->len > h->batch_size - sizeof(struct osmux_hdr)) {
|
2022-09-20 12:49:09 +00:00
|
|
|
LOGP(DLMUX, LOGL_NOTICE, "RTP payload too big (%u) for configured batch size (%u)\n",
|
|
|
|
msg->len, h->batch_size);
|
2014-08-28 18:18:19 +00:00
|
|
|
msgb_free(msg);
|
2022-09-23 15:42:03 +00:00
|
|
|
return -1;
|
2014-08-28 18:18:19 +00:00
|
|
|
}
|
2013-08-27 15:15:27 +00:00
|
|
|
|
2012-07-09 17:39:55 +00:00
|
|
|
rtph = osmo_rtp_get_hdr(msg);
|
2014-08-28 18:18:19 +00:00
|
|
|
if (rtph == NULL) {
|
2022-09-20 12:49:09 +00:00
|
|
|
LOGP(DLMUX, LOGL_NOTICE, "msg not containing an RTP header\n");
|
2014-08-28 18:18:19 +00:00
|
|
|
msgb_free(msg);
|
2022-09-23 15:42:03 +00:00
|
|
|
return -1;
|
2014-08-28 18:18:19 +00:00
|
|
|
}
|
2012-07-09 17:39:55 +00:00
|
|
|
|
|
|
|
switch(rtph->payload_type) {
|
|
|
|
case RTP_PT_RTCP:
|
2022-09-20 12:49:09 +00:00
|
|
|
LOGP(DLMUX, LOGL_INFO, "Dropping RTCP packet\n");
|
2014-08-28 18:18:19 +00:00
|
|
|
msgb_free(msg);
|
2012-07-09 17:39:55 +00:00
|
|
|
return 0;
|
2013-02-19 15:14:32 +00:00
|
|
|
default:
|
|
|
|
/* The RTP payload type is dynamically allocated,
|
|
|
|
* although we use static ones. Assume that we always
|
|
|
|
* receive AMR traffic.
|
|
|
|
*/
|
|
|
|
|
2013-05-24 09:56:07 +00:00
|
|
|
/* Add this RTP to the OSMUX batch */
|
2015-07-17 18:23:25 +00:00
|
|
|
ret = osmux_batch_add(batch, h->batch_factor,
|
|
|
|
msg, rtph, ccid);
|
2014-08-28 17:24:00 +00:00
|
|
|
if (ret < 0) {
|
|
|
|
/* Cannot put this message into the batch.
|
|
|
|
* Malformed, duplicated, OOM. Drop it and tell
|
|
|
|
* the upper layer that we have digest it.
|
|
|
|
*/
|
2022-09-20 12:49:09 +00:00
|
|
|
LOGP(DLMUX, LOGL_DEBUG, "Dropping RTP packet instead of adding to batch\n");
|
2014-08-28 17:24:00 +00:00
|
|
|
msgb_free(msg);
|
2022-09-23 15:42:03 +00:00
|
|
|
return ret;
|
2014-08-28 17:24:00 +00:00
|
|
|
}
|
2013-05-24 09:56:07 +00:00
|
|
|
|
2014-08-28 14:14:16 +00:00
|
|
|
h->stats.input_rtp_msgs++;
|
|
|
|
h->stats.input_rtp_bytes += msg->len;
|
2012-07-09 17:39:55 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
void osmux_xfrm_input_init(struct osmux_in_handle *h)
|
|
|
|
{
|
2012-08-06 16:41:49 +00:00
|
|
|
struct osmux_batch *batch;
|
|
|
|
|
2014-08-28 13:01:03 +00:00
|
|
|
/* Default to osmux packet size if not specified */
|
|
|
|
if (h->batch_size == 0)
|
2014-08-29 13:20:56 +00:00
|
|
|
h->batch_size = OSMUX_BATCH_DEFAULT_MAX;
|
2012-08-06 16:41:49 +00:00
|
|
|
|
2013-02-19 12:16:27 +00:00
|
|
|
batch = talloc_zero(osmux_ctx, struct osmux_batch);
|
2012-08-06 16:41:49 +00:00
|
|
|
if (batch == NULL)
|
|
|
|
return;
|
|
|
|
|
2015-07-17 17:24:49 +00:00
|
|
|
INIT_LLIST_HEAD(&batch->circuit_list);
|
2014-08-28 13:01:03 +00:00
|
|
|
batch->remaining_bytes = h->batch_size;
|
2017-06-07 16:38:21 +00:00
|
|
|
osmo_timer_setup(&batch->timer, osmux_batch_timer_expired, h);
|
2012-08-06 16:41:49 +00:00
|
|
|
|
2013-02-11 21:49:27 +00:00
|
|
|
h->internal_data = (void *)batch;
|
2014-08-28 13:01:03 +00:00
|
|
|
|
2018-03-07 12:13:17 +00:00
|
|
|
LOGP(DLMUX, LOGL_DEBUG, "initialized osmux input converter\n");
|
2012-07-09 17:39:55 +00:00
|
|
|
}
|
2012-07-19 09:08:21 +00:00
|
|
|
|
2015-07-17 18:47:04 +00:00
|
|
|
int osmux_xfrm_input_open_circuit(struct osmux_in_handle *h, int ccid,
|
|
|
|
int dummy)
|
|
|
|
{
|
|
|
|
struct osmux_batch *batch = (struct osmux_batch *)h->internal_data;
|
|
|
|
|
|
|
|
return osmux_batch_add_circuit(batch, ccid, dummy, h->batch_factor) ? 0 : -1;
|
|
|
|
}
|
|
|
|
|
2015-07-17 17:55:18 +00:00
|
|
|
void osmux_xfrm_input_close_circuit(struct osmux_in_handle *h, int ccid)
|
|
|
|
{
|
|
|
|
struct osmux_batch *batch = (struct osmux_batch *)h->internal_data;
|
2016-05-25 15:44:37 +00:00
|
|
|
struct osmux_circuit *circuit;
|
2015-07-17 17:55:18 +00:00
|
|
|
|
2016-05-25 15:44:37 +00:00
|
|
|
circuit = osmux_batch_find_circuit(batch, ccid);
|
2022-09-09 12:49:58 +00:00
|
|
|
if (circuit == NULL) {
|
|
|
|
LOGP(DLMUX, LOGL_NOTICE, "Unable to close circuit %d: Not found\n",
|
|
|
|
ccid);
|
2016-05-25 15:44:37 +00:00
|
|
|
return;
|
2022-09-09 12:49:58 +00:00
|
|
|
}
|
2016-05-25 15:44:37 +00:00
|
|
|
|
|
|
|
osmux_batch_del_circuit(batch, circuit);
|
2015-07-17 17:55:18 +00:00
|
|
|
}
|
|
|
|
|
2014-08-28 10:45:04 +00:00
|
|
|
void osmux_xfrm_input_fini(struct osmux_in_handle *h)
|
|
|
|
{
|
|
|
|
struct osmux_batch *batch = (struct osmux_batch *)h->internal_data;
|
2015-07-17 17:24:49 +00:00
|
|
|
struct osmux_circuit *circuit, *next;
|
2014-08-28 10:45:04 +00:00
|
|
|
|
2016-05-25 15:44:37 +00:00
|
|
|
llist_for_each_entry_safe(circuit, next, &batch->circuit_list, head)
|
|
|
|
osmux_batch_del_circuit(batch, circuit);
|
|
|
|
|
2014-08-28 17:59:15 +00:00
|
|
|
osmo_timer_del(&batch->timer);
|
2014-08-28 10:45:04 +00:00
|
|
|
talloc_free(batch);
|
|
|
|
}
|
|
|
|
|
2012-07-19 09:08:21 +00:00
|
|
|
struct osmux_tx_handle {
|
2012-08-04 17:56:47 +00:00
|
|
|
struct osmo_timer_list timer;
|
|
|
|
struct msgb *msg;
|
|
|
|
void (*tx_cb)(struct msgb *msg, void *data);
|
|
|
|
void *data;
|
2012-07-19 09:08:21 +00:00
|
|
|
};
|
|
|
|
|
2022-08-31 15:28:36 +00:00
|
|
|
static int osmux_xfrm_output_talloc_destructor(struct osmux_out_handle *h)
|
|
|
|
{
|
|
|
|
osmux_xfrm_output_flush(h);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*! \brief Allocate a new osmux out handle
|
|
|
|
* \param[in] ctx talloc context to use when allocating the returned struct
|
|
|
|
* \return Allocated osmux out handle
|
|
|
|
*
|
|
|
|
* This object contains configuration and state to handle a specific CID in
|
|
|
|
* incoming network Osmux messages, repackaging the frames for that CID as RTP
|
|
|
|
* packets and pushing them up the protocol stack.
|
|
|
|
* Returned pointer can be freed with regular talloc_free, queue will be flushed
|
|
|
|
* and all internal data will be freed. */
|
|
|
|
struct osmux_out_handle *osmux_xfrm_output_alloc(void *ctx)
|
|
|
|
{
|
|
|
|
struct osmux_out_handle *h;
|
|
|
|
|
|
|
|
h = talloc_zero(ctx, struct osmux_out_handle);
|
|
|
|
OSMO_ASSERT(h);
|
|
|
|
|
|
|
|
h->rtp_seq = (uint16_t)random();
|
|
|
|
h->rtp_timestamp = (uint32_t)random();
|
|
|
|
h->rtp_ssrc = (uint32_t)random();
|
|
|
|
h->rtp_payload_type = 98;
|
|
|
|
INIT_LLIST_HEAD(&h->list);
|
|
|
|
osmo_timer_setup(&h->timer, osmux_xfrm_output_trigger, h);
|
|
|
|
|
|
|
|
talloc_set_destructor(h, osmux_xfrm_output_talloc_destructor);
|
|
|
|
return h;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* DEPRECATED: Use osmux_xfrm_output_alloc() and osmux_xfrm_output_set_rtp_*() instead */
|
2019-05-17 15:11:02 +00:00
|
|
|
void osmux_xfrm_output_init2(struct osmux_out_handle *h, uint32_t rtp_ssrc, uint8_t rtp_payload_type)
|
2012-08-06 18:15:46 +00:00
|
|
|
{
|
2018-04-28 11:36:40 +00:00
|
|
|
memset(h, 0, sizeof(*h));
|
2013-02-12 16:23:29 +00:00
|
|
|
h->rtp_seq = (uint16_t)random();
|
|
|
|
h->rtp_timestamp = (uint32_t)random();
|
2013-05-12 16:03:50 +00:00
|
|
|
h->rtp_ssrc = rtp_ssrc;
|
2019-05-17 15:11:02 +00:00
|
|
|
h->rtp_payload_type = rtp_payload_type;
|
2018-04-18 11:58:46 +00:00
|
|
|
INIT_LLIST_HEAD(&h->list);
|
|
|
|
osmo_timer_setup(&h->timer, osmux_xfrm_output_trigger, h);
|
2012-08-06 18:15:46 +00:00
|
|
|
}
|
2013-02-19 16:14:33 +00:00
|
|
|
|
2022-08-31 15:28:36 +00:00
|
|
|
/* DEPRECATED: Use osmux_xfrm_output_alloc() and osmux_xfrm_output_set_rtp_*() instead */
|
2019-05-17 15:11:02 +00:00
|
|
|
void osmux_xfrm_output_init(struct osmux_out_handle *h, uint32_t rtp_ssrc)
|
|
|
|
{
|
|
|
|
/* backward compatibility with old users, where 98 was harcoded in osmux_rebuild_rtp() */
|
|
|
|
osmux_xfrm_output_init2(h, rtp_ssrc, 98);
|
|
|
|
}
|
|
|
|
|
2022-08-31 15:11:55 +00:00
|
|
|
/*! \brief Set transmission callback to call when a generated RTP packet is to be transmitted
|
|
|
|
* \param[in] h the osmux out handle handling a specific CID
|
|
|
|
* \param[in] osmuxh Buffer pointing to osmux frame header structure and AMR payload
|
|
|
|
* \return Number of generated RTP packets
|
|
|
|
*
|
|
|
|
* This Function sets the callback called by the interal timer set by
|
|
|
|
* osmux_xfrm_out_sched function.
|
|
|
|
*/
|
|
|
|
void osmux_xfrm_output_set_tx_cb(struct osmux_out_handle *h,
|
|
|
|
void (*tx_cb)(struct msgb *msg, void *data),
|
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
h->tx_cb = tx_cb;
|
|
|
|
h->data = data;
|
|
|
|
}
|
|
|
|
|
2022-08-31 16:37:01 +00:00
|
|
|
/*! \brief Set callback to call when an RTP packet to be generated is to be allocated
|
|
|
|
* \param[in] h the osmux out handle handling a specific CID
|
|
|
|
* \param[in] cb User defined msgb alloc function for generated RTP pkts
|
|
|
|
* \param[in] cb_data Opaque data pointer set by user and passed in \ref cb
|
|
|
|
* \return msgb structure to be used to fill in generated RTP pkt content
|
|
|
|
*/
|
|
|
|
void osmux_xfrm_output_set_rtp_msgb_alloc_cb(struct osmux_out_handle *h,
|
|
|
|
rtp_msgb_alloc_cb_t cb,
|
|
|
|
void *cb_data)
|
|
|
|
{
|
|
|
|
h->rtp_msgb_alloc_cb = cb;
|
|
|
|
h->rtp_msgb_alloc_cb_data = cb_data;
|
|
|
|
}
|
|
|
|
|
2022-08-31 15:28:36 +00:00
|
|
|
/*! \brief Set SSRC of generated RTP packets from Osmux frames
|
|
|
|
* \param[in] h the osmux out handle handling a specific CID
|
|
|
|
* \param[in] rtp_ssrc the RTP SSRC to set
|
|
|
|
*/
|
|
|
|
void osmux_xfrm_output_set_rtp_ssrc(struct osmux_out_handle *h, uint32_t rtp_ssrc)
|
|
|
|
{
|
|
|
|
h->rtp_ssrc = rtp_ssrc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*! \brief Set Payload Type of generated RTP packets from Osmux frames
|
|
|
|
* \param[in] h the osmux out handle handling a specific CID
|
|
|
|
* \param[in] rtp_payload_type the RTP Payload Type to set
|
|
|
|
*/
|
|
|
|
void osmux_xfrm_output_set_rtp_pl_type(struct osmux_out_handle *h, uint32_t rtp_payload_type)
|
|
|
|
{
|
|
|
|
h->rtp_payload_type = rtp_payload_type;
|
|
|
|
}
|
|
|
|
|
osmux: fix buffer management mess in snprintf() calls
SNPRINTF_BUFFER_SIZE() looks too complex, previous version maintains two
different variables to account for the remaining space in the buffer,
one of them is always decremented based on what snprintf() returns,
which may result in underflow. These variables are swapped - not used
consistently - all over this code.
Replace this macro by a simplified version, with one single parameter to
account for remaining space. This macro also deals with two corner
cases:
1) snprintf() fails, actually never happens in practise, but
documentation indicates it may return -1, so let's catch this case
from here to stick to specs.
2) There is not enough space in the buffer, in that case, keep
increasing offset, so we know how much would have been printed, just
like snprintf() does.
Thanks to Pau Espin for reporting, and Holger for clues on this.
I have run osmux_test and, at quick glance, it looks good.
Change-Id: I5b5d6ec57a02f57c23b1ae86dbd894bad28ea797
2017-09-04 18:35:36 +00:00
|
|
|
#define SNPRINTF_BUFFER_SIZE(ret, remain, offset) \
|
|
|
|
if (ret < 0) \
|
|
|
|
ret = 0; \
|
2013-02-19 16:14:33 +00:00
|
|
|
offset += ret; \
|
osmux: fix buffer management mess in snprintf() calls
SNPRINTF_BUFFER_SIZE() looks too complex, previous version maintains two
different variables to account for the remaining space in the buffer,
one of them is always decremented based on what snprintf() returns,
which may result in underflow. These variables are swapped - not used
consistently - all over this code.
Replace this macro by a simplified version, with one single parameter to
account for remaining space. This macro also deals with two corner
cases:
1) snprintf() fails, actually never happens in practise, but
documentation indicates it may return -1, so let's catch this case
from here to stick to specs.
2) There is not enough space in the buffer, in that case, keep
increasing offset, so we know how much would have been printed, just
like snprintf() does.
Thanks to Pau Espin for reporting, and Holger for clues on this.
I have run osmux_test and, at quick glance, it looks good.
Change-Id: I5b5d6ec57a02f57c23b1ae86dbd894bad28ea797
2017-09-04 18:35:36 +00:00
|
|
|
if (ret > remain) \
|
|
|
|
ret = remain; \
|
|
|
|
remain -= ret;
|
2013-02-19 16:14:33 +00:00
|
|
|
|
|
|
|
static int osmux_snprintf_header(char *buf, size_t size, struct osmux_hdr *osmuxh)
|
|
|
|
{
|
osmux: fix buffer management mess in snprintf() calls
SNPRINTF_BUFFER_SIZE() looks too complex, previous version maintains two
different variables to account for the remaining space in the buffer,
one of them is always decremented based on what snprintf() returns,
which may result in underflow. These variables are swapped - not used
consistently - all over this code.
Replace this macro by a simplified version, with one single parameter to
account for remaining space. This macro also deals with two corner
cases:
1) snprintf() fails, actually never happens in practise, but
documentation indicates it may return -1, so let's catch this case
from here to stick to specs.
2) There is not enough space in the buffer, in that case, keep
increasing offset, so we know how much would have been printed, just
like snprintf() does.
Thanks to Pau Espin for reporting, and Holger for clues on this.
I have run osmux_test and, at quick glance, it looks good.
Change-Id: I5b5d6ec57a02f57c23b1ae86dbd894bad28ea797
2017-09-04 18:35:36 +00:00
|
|
|
unsigned int remain = size, offset = 0;
|
2013-02-19 16:14:33 +00:00
|
|
|
int ret;
|
|
|
|
|
osmux: fix buffer management mess in snprintf() calls
SNPRINTF_BUFFER_SIZE() looks too complex, previous version maintains two
different variables to account for the remaining space in the buffer,
one of them is always decremented based on what snprintf() returns,
which may result in underflow. These variables are swapped - not used
consistently - all over this code.
Replace this macro by a simplified version, with one single parameter to
account for remaining space. This macro also deals with two corner
cases:
1) snprintf() fails, actually never happens in practise, but
documentation indicates it may return -1, so let's catch this case
from here to stick to specs.
2) There is not enough space in the buffer, in that case, keep
increasing offset, so we know how much would have been printed, just
like snprintf() does.
Thanks to Pau Espin for reporting, and Holger for clues on this.
I have run osmux_test and, at quick glance, it looks good.
Change-Id: I5b5d6ec57a02f57c23b1ae86dbd894bad28ea797
2017-09-04 18:35:36 +00:00
|
|
|
ret = snprintf(buf, remain, "OSMUX seq=%03u ccid=%03u "
|
2013-02-19 16:14:33 +00:00
|
|
|
"ft=%01u ctr=%01u "
|
|
|
|
"amr_f=%01u amr_q=%01u "
|
2019-10-04 10:42:26 +00:00
|
|
|
"amr_ft=%02u amr_cmr=%02u",
|
2013-02-19 16:14:33 +00:00
|
|
|
osmuxh->seq, osmuxh->circuit_id,
|
|
|
|
osmuxh->ft, osmuxh->ctr,
|
|
|
|
osmuxh->amr_f, osmuxh->amr_q,
|
|
|
|
osmuxh->amr_ft, osmuxh->amr_cmr);
|
osmux: fix buffer management mess in snprintf() calls
SNPRINTF_BUFFER_SIZE() looks too complex, previous version maintains two
different variables to account for the remaining space in the buffer,
one of them is always decremented based on what snprintf() returns,
which may result in underflow. These variables are swapped - not used
consistently - all over this code.
Replace this macro by a simplified version, with one single parameter to
account for remaining space. This macro also deals with two corner
cases:
1) snprintf() fails, actually never happens in practise, but
documentation indicates it may return -1, so let's catch this case
from here to stick to specs.
2) There is not enough space in the buffer, in that case, keep
increasing offset, so we know how much would have been printed, just
like snprintf() does.
Thanks to Pau Espin for reporting, and Holger for clues on this.
I have run osmux_test and, at quick glance, it looks good.
Change-Id: I5b5d6ec57a02f57c23b1ae86dbd894bad28ea797
2017-09-04 18:35:36 +00:00
|
|
|
SNPRINTF_BUFFER_SIZE(ret, remain, offset);
|
2013-02-19 16:14:33 +00:00
|
|
|
|
|
|
|
return offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int osmux_snprintf_payload(char *buf, size_t size,
|
|
|
|
const uint8_t *payload, int payload_len)
|
|
|
|
{
|
osmux: fix buffer management mess in snprintf() calls
SNPRINTF_BUFFER_SIZE() looks too complex, previous version maintains two
different variables to account for the remaining space in the buffer,
one of them is always decremented based on what snprintf() returns,
which may result in underflow. These variables are swapped - not used
consistently - all over this code.
Replace this macro by a simplified version, with one single parameter to
account for remaining space. This macro also deals with two corner
cases:
1) snprintf() fails, actually never happens in practise, but
documentation indicates it may return -1, so let's catch this case
from here to stick to specs.
2) There is not enough space in the buffer, in that case, keep
increasing offset, so we know how much would have been printed, just
like snprintf() does.
Thanks to Pau Espin for reporting, and Holger for clues on this.
I have run osmux_test and, at quick glance, it looks good.
Change-Id: I5b5d6ec57a02f57c23b1ae86dbd894bad28ea797
2017-09-04 18:35:36 +00:00
|
|
|
unsigned int remain = size, offset = 0;
|
2013-02-19 16:14:33 +00:00
|
|
|
int ret, i;
|
|
|
|
|
osmux: fix buffer management mess in snprintf() calls
SNPRINTF_BUFFER_SIZE() looks too complex, previous version maintains two
different variables to account for the remaining space in the buffer,
one of them is always decremented based on what snprintf() returns,
which may result in underflow. These variables are swapped - not used
consistently - all over this code.
Replace this macro by a simplified version, with one single parameter to
account for remaining space. This macro also deals with two corner
cases:
1) snprintf() fails, actually never happens in practise, but
documentation indicates it may return -1, so let's catch this case
from here to stick to specs.
2) There is not enough space in the buffer, in that case, keep
increasing offset, so we know how much would have been printed, just
like snprintf() does.
Thanks to Pau Espin for reporting, and Holger for clues on this.
I have run osmux_test and, at quick glance, it looks good.
Change-Id: I5b5d6ec57a02f57c23b1ae86dbd894bad28ea797
2017-09-04 18:35:36 +00:00
|
|
|
ret = snprintf(buf + offset, remain, "[ ");
|
|
|
|
SNPRINTF_BUFFER_SIZE(ret, remain, offset);
|
2017-08-14 15:23:05 +00:00
|
|
|
|
2013-02-19 16:14:33 +00:00
|
|
|
for (i=0; i<payload_len; i++) {
|
osmux: fix buffer management mess in snprintf() calls
SNPRINTF_BUFFER_SIZE() looks too complex, previous version maintains two
different variables to account for the remaining space in the buffer,
one of them is always decremented based on what snprintf() returns,
which may result in underflow. These variables are swapped - not used
consistently - all over this code.
Replace this macro by a simplified version, with one single parameter to
account for remaining space. This macro also deals with two corner
cases:
1) snprintf() fails, actually never happens in practise, but
documentation indicates it may return -1, so let's catch this case
from here to stick to specs.
2) There is not enough space in the buffer, in that case, keep
increasing offset, so we know how much would have been printed, just
like snprintf() does.
Thanks to Pau Espin for reporting, and Holger for clues on this.
I have run osmux_test and, at quick glance, it looks good.
Change-Id: I5b5d6ec57a02f57c23b1ae86dbd894bad28ea797
2017-09-04 18:35:36 +00:00
|
|
|
ret = snprintf(buf + offset, remain, "%02x ", payload[i]);
|
|
|
|
SNPRINTF_BUFFER_SIZE(ret, remain, offset);
|
2013-02-19 16:14:33 +00:00
|
|
|
}
|
|
|
|
|
osmux: fix buffer management mess in snprintf() calls
SNPRINTF_BUFFER_SIZE() looks too complex, previous version maintains two
different variables to account for the remaining space in the buffer,
one of them is always decremented based on what snprintf() returns,
which may result in underflow. These variables are swapped - not used
consistently - all over this code.
Replace this macro by a simplified version, with one single parameter to
account for remaining space. This macro also deals with two corner
cases:
1) snprintf() fails, actually never happens in practise, but
documentation indicates it may return -1, so let's catch this case
from here to stick to specs.
2) There is not enough space in the buffer, in that case, keep
increasing offset, so we know how much would have been printed, just
like snprintf() does.
Thanks to Pau Espin for reporting, and Holger for clues on this.
I have run osmux_test and, at quick glance, it looks good.
Change-Id: I5b5d6ec57a02f57c23b1ae86dbd894bad28ea797
2017-09-04 18:35:36 +00:00
|
|
|
ret = snprintf(buf + offset, remain, "]");
|
|
|
|
SNPRINTF_BUFFER_SIZE(ret, remain, offset);
|
2013-02-19 16:14:33 +00:00
|
|
|
|
|
|
|
return offset;
|
|
|
|
}
|
|
|
|
|
2017-10-23 15:42:10 +00:00
|
|
|
/*! Print osmux header fields and payload from msg into buffer buf.
|
|
|
|
* \param[out] buf buffer to store the output into
|
|
|
|
* \param[in] len length of buf in bytes
|
|
|
|
* \param[in] msgb message buffer containing one or more osmux frames
|
|
|
|
* \returns the number of characters printed (excluding the null byte used to end output to strings).
|
|
|
|
*
|
|
|
|
* If the output was truncated due to this limit, then the return value is the number of characters
|
|
|
|
* (excluding the terminating null byte) which would have been written to the final string if enough
|
|
|
|
* space had been available.
|
|
|
|
*/
|
2013-02-19 16:14:33 +00:00
|
|
|
int osmux_snprintf(char *buf, size_t size, struct msgb *msg)
|
|
|
|
{
|
osmux: fix buffer management mess in snprintf() calls
SNPRINTF_BUFFER_SIZE() looks too complex, previous version maintains two
different variables to account for the remaining space in the buffer,
one of them is always decremented based on what snprintf() returns,
which may result in underflow. These variables are swapped - not used
consistently - all over this code.
Replace this macro by a simplified version, with one single parameter to
account for remaining space. This macro also deals with two corner
cases:
1) snprintf() fails, actually never happens in practise, but
documentation indicates it may return -1, so let's catch this case
from here to stick to specs.
2) There is not enough space in the buffer, in that case, keep
increasing offset, so we know how much would have been printed, just
like snprintf() does.
Thanks to Pau Espin for reporting, and Holger for clues on this.
I have run osmux_test and, at quick glance, it looks good.
Change-Id: I5b5d6ec57a02f57c23b1ae86dbd894bad28ea797
2017-09-04 18:35:36 +00:00
|
|
|
unsigned int remain = size;
|
2017-10-23 14:27:13 +00:00
|
|
|
unsigned int msg_off = 0;
|
osmux: fix buffer management mess in snprintf() calls
SNPRINTF_BUFFER_SIZE() looks too complex, previous version maintains two
different variables to account for the remaining space in the buffer,
one of them is always decremented based on what snprintf() returns,
which may result in underflow. These variables are swapped - not used
consistently - all over this code.
Replace this macro by a simplified version, with one single parameter to
account for remaining space. This macro also deals with two corner
cases:
1) snprintf() fails, actually never happens in practise, but
documentation indicates it may return -1, so let's catch this case
from here to stick to specs.
2) There is not enough space in the buffer, in that case, keep
increasing offset, so we know how much would have been printed, just
like snprintf() does.
Thanks to Pau Espin for reporting, and Holger for clues on this.
I have run osmux_test and, at quick glance, it looks good.
Change-Id: I5b5d6ec57a02f57c23b1ae86dbd894bad28ea797
2017-09-04 18:35:36 +00:00
|
|
|
struct osmux_hdr *osmuxh;
|
|
|
|
unsigned int offset = 0;
|
|
|
|
int msg_len = msg->len;
|
2017-10-23 14:27:13 +00:00
|
|
|
uint32_t payload_len;
|
osmux: fix buffer management mess in snprintf() calls
SNPRINTF_BUFFER_SIZE() looks too complex, previous version maintains two
different variables to account for the remaining space in the buffer,
one of them is always decremented based on what snprintf() returns,
which may result in underflow. These variables are swapped - not used
consistently - all over this code.
Replace this macro by a simplified version, with one single parameter to
account for remaining space. This macro also deals with two corner
cases:
1) snprintf() fails, actually never happens in practise, but
documentation indicates it may return -1, so let's catch this case
from here to stick to specs.
2) There is not enough space in the buffer, in that case, keep
increasing offset, so we know how much would have been printed, just
like snprintf() does.
Thanks to Pau Espin for reporting, and Holger for clues on this.
I have run osmux_test and, at quick glance, it looks good.
Change-Id: I5b5d6ec57a02f57c23b1ae86dbd894bad28ea797
2017-09-04 18:35:36 +00:00
|
|
|
int ret;
|
2013-02-19 16:14:33 +00:00
|
|
|
|
2017-09-12 10:44:53 +00:00
|
|
|
if (size)
|
|
|
|
buf[0] = '\0';
|
|
|
|
|
2013-02-19 16:14:33 +00:00
|
|
|
while (msg_len > 0) {
|
2013-05-12 18:43:26 +00:00
|
|
|
if (msg_len < sizeof(struct osmux_hdr)) {
|
2018-03-07 12:13:17 +00:00
|
|
|
LOGP(DLMUX, LOGL_ERROR,
|
2013-05-12 18:43:26 +00:00
|
|
|
"No room for OSMUX header: only %d bytes\n",
|
|
|
|
msg_len);
|
|
|
|
return -1;
|
|
|
|
}
|
2013-12-13 14:27:21 +00:00
|
|
|
osmuxh = (struct osmux_hdr *)((uint8_t *)msg->data + msg_off);
|
2019-10-04 10:30:32 +00:00
|
|
|
if (msg_off) {
|
|
|
|
ret = snprintf(buf + offset, remain, ", ");
|
|
|
|
SNPRINTF_BUFFER_SIZE(ret, remain, offset);
|
|
|
|
}
|
2017-10-23 14:27:13 +00:00
|
|
|
ret = osmux_snprintf_header(buf + offset, remain, osmuxh);
|
|
|
|
SNPRINTF_BUFFER_SIZE(ret, remain, offset);
|
|
|
|
|
|
|
|
msg_off += sizeof(struct osmux_hdr);
|
|
|
|
msg_len -= sizeof(struct osmux_hdr);
|
|
|
|
|
2017-10-23 15:29:13 +00:00
|
|
|
switch (osmuxh->ft) {
|
|
|
|
case OSMUX_FT_SIGNAL:
|
|
|
|
ret = snprintf(buf + offset, remain, "[signal]");
|
|
|
|
SNPRINTF_BUFFER_SIZE(ret, remain, offset);
|
2013-12-14 21:32:09 +00:00
|
|
|
return -1;
|
2017-10-23 15:29:13 +00:00
|
|
|
case OSMUX_FT_DUMMY:
|
|
|
|
case OSMUX_FT_VOICE_AMR:
|
|
|
|
if (!osmo_amr_ft_valid(osmuxh->amr_ft)) {
|
2018-03-07 12:13:17 +00:00
|
|
|
LOGP(DLMUX, LOGL_ERROR, "Bad AMR FT %d, skipping\n",
|
2017-10-23 15:29:13 +00:00
|
|
|
osmuxh->amr_ft);
|
|
|
|
return -1;
|
|
|
|
}
|
2013-12-14 21:32:09 +00:00
|
|
|
|
2017-10-23 15:29:13 +00:00
|
|
|
payload_len = osmux_get_payload_len(osmuxh);
|
2013-05-12 18:43:26 +00:00
|
|
|
|
2017-10-23 15:29:13 +00:00
|
|
|
if (msg_len < payload_len) {
|
2018-03-07 12:13:17 +00:00
|
|
|
LOGP(DLMUX, LOGL_ERROR,
|
2017-10-23 15:29:13 +00:00
|
|
|
"No room for OSMUX payload: only %d bytes\n",
|
|
|
|
msg_len);
|
|
|
|
return -1;
|
|
|
|
}
|
2013-05-12 18:43:26 +00:00
|
|
|
|
2017-10-23 15:29:13 +00:00
|
|
|
if (osmuxh->ft == OSMUX_FT_VOICE_AMR) {
|
2019-10-04 10:42:26 +00:00
|
|
|
ret = snprintf(buf + offset, remain, " ");
|
|
|
|
SNPRINTF_BUFFER_SIZE(ret, remain, offset);
|
2017-10-23 15:29:13 +00:00
|
|
|
ret = osmux_snprintf_payload(buf + offset, remain,
|
|
|
|
osmux_get_payload(osmuxh),
|
|
|
|
payload_len);
|
|
|
|
SNPRINTF_BUFFER_SIZE(ret, remain, offset);
|
|
|
|
}
|
2013-02-19 16:14:33 +00:00
|
|
|
|
2017-10-23 15:29:13 +00:00
|
|
|
msg_off += payload_len;
|
|
|
|
msg_len -= payload_len;
|
|
|
|
break;
|
|
|
|
default:
|
2018-03-07 12:13:17 +00:00
|
|
|
LOGP(DLMUX, LOGL_ERROR, "Unknown OSMUX ft value %d\n",
|
2017-10-23 15:29:13 +00:00
|
|
|
osmuxh->ft);
|
|
|
|
return -1;
|
|
|
|
}
|
2013-02-19 16:14:33 +00:00
|
|
|
}
|
|
|
|
return offset;
|
|
|
|
}
|
2017-04-08 18:00:47 +00:00
|
|
|
|
|
|
|
/*! @} */
|