Skip to content

Commit

Permalink
Revised and improved version of the RTP packets resizer. Now supports
Browse files Browse the repository at this point in the history
codecs that can combine several different frames with different sizes
within one RTP packet, such as G.723, which has 3 types of frame and
G.729, which has 2 types.

Sponsored by:	Sippy Software, Inc., http://www.sippysoft.com
  • Loading branch information
sobomax committed Apr 17, 2008
1 parent 1fc33f3 commit 77ab7cb
Show file tree
Hide file tree
Showing 3 changed files with 293 additions and 142 deletions.
204 changes: 168 additions & 36 deletions rtp.c
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2007 Sippy Software, Inc., http://www.sippysoft.com
* Copyright (c) 2007-2008 Sippy Software, Inc., http://www.sippysoft.com
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
Expand All @@ -23,68 +23,191 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: rtp.c,v 1.6 2007/11/19 22:44:31 sobomax Exp $
* $Id: rtp.c,v 1.7 2008/04/17 22:38:00 sobomax Exp $
*
*/

#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <assert.h>

#include "rtp.h"
#include "rtpp_util.h"

/* Linked list of free packets */
static struct rtp_packet *rtp_packet_pool = NULL;

size_t
rtp_samples2bytes(int codec_id, int nsamples)
static int
g723_len(unsigned char ch)
{

switch (codec_id) {
case RTP_PCMU:
case RTP_PCMA:
return nsamples;
case RTP_G729:
return nsamples / 8;
case RTP_GSM:
return (nsamples / 160) * 33;
case RTP_G723:
return (nsamples / 240) * 24;
default:
return RTP_NSAMPLES_UNKNOWN;
switch (ch & 3) {
case 2:
/* Silence Insertion Descriptor (SID) frame */
return 4;

case 0:
/* 6.3 kbit/s frame */
return 24;

case 1:
/* 5.3 kbit/s frame */
return 20;

default:
return RTP_NSAMPLES_UNKNOWN;
}
}

static int
g723_samples(const unsigned char *buf, int maxlen)
{
int pos, samples, n;

for (pos = 0, samples = 0; pos < maxlen; pos += n) {
samples += 240;
n = g723_len(buf[pos]);
if (n == RTP_NSAMPLES_UNKNOWN)
return RTP_NSAMPLES_UNKNOWN;
}
return samples;
}

int
rtp_bytes2samples(int codec_id, size_t nbytes)
static int
rtp_calc_samples(int codec_id, size_t nbytes, const unsigned char *data)
{

switch (codec_id) {
case RTP_PCMU:
case RTP_PCMA:
return nbytes;
case RTP_G729:
return nbytes * 8;
case RTP_GSM:
return 160 * (nbytes / 33);
case RTP_G723:
if (nbytes % 24 == 0)
return 240 * (nbytes / 24);
#if defined(NOTYET)
else if (nbytes % 20 == 0)
return 240 * (nbytes / 20);
#endif
default:
return RTP_NSAMPLES_UNKNOWN;
case RTP_PCMU:
case RTP_PCMA:
return nbytes;

case RTP_G729:
return (nbytes / 10) * 80 + (nbytes % 10 == 0 ? 0 : 80);

case RTP_GSM:
return 160 * (nbytes / 33);

case RTP_G723:
return g723_samples(data, nbytes);

default:
return RTP_NSAMPLES_UNKNOWN;
}
}

static void
rtp_packet_chunk_find_g711(struct rtp_packet *pkt, struct rtp_packet_chunk *ret, int min_nsamples)
{

ret->nsamples = min_nsamples;
ret->bytes = min_nsamples;
}

static void
rtp_packet_chunk_find_g729(struct rtp_packet *pkt, struct rtp_packet_chunk *ret, int min_nsamples)
{
int frames, samples;

frames = min_nsamples / 80 + ((min_nsamples % 80) == 0 ? 0 : 1);
samples = frames * 80;

if (samples >= pkt->nsamples) {
ret->whole_packet_matched = 1;
return;
}
ret->nsamples = samples;
ret->bytes = frames * 10;
}

static void
rtp_packet_chunk_find_gsm(struct rtp_packet *pkt, struct rtp_packet_chunk *ret, int min_nsamples)
{
int frames, samples;

frames = min_nsamples / 160 + ((min_nsamples % 160) == 0 ? 0 : 1);
samples = frames * 160;

if (samples >= pkt->nsamples) {
ret->whole_packet_matched = 1;
return;
}
ret->nsamples = samples;
ret->bytes = frames * 33;
}

static void
rtp_packet_chunk_find_g723(struct rtp_packet *pkt, struct rtp_packet_chunk *ret, int min_nsamples)
{
int frames, samples, pos, found_samples, n;
unsigned char *buf;

frames = min_nsamples / 240 + ((min_nsamples % 240) == 0 ? 0 : 1);
samples = frames * 240;

pos = 0;
found_samples = 0;
if (samples >= pkt->nsamples) {
ret->whole_packet_matched = 1;
return;
}

buf = &pkt->buf[pkt->data_offset];
while (pos < pkt->data_size && samples > found_samples) {
found_samples += 240;
n = g723_len(buf[pos]);
assert(n != RTP_NSAMPLES_UNKNOWN);
pos += n;
}
ret->nsamples = found_samples;
ret->bytes = (pos < pkt->data_size ? pos : pkt->data_size);
}

/*
* Find the head of the packet with the length at least
* of min_nsamples.
*
* Warning! When whole packet has been matched the chunk can be uninitialized.
*/
void
rtp_packet_first_chunk_find(struct rtp_packet *pkt, struct rtp_packet_chunk *ret, int min_nsamples)
{

assert(pkt->nsamples > min_nsamples);
ret->whole_packet_matched = 0;

switch (pkt->header.pt) {
case RTP_PCMU:
case RTP_PCMA:
rtp_packet_chunk_find_g711(pkt, ret, min_nsamples);
break;

case RTP_G729:
rtp_packet_chunk_find_g729(pkt, ret, min_nsamples);
break;

case RTP_GSM:
rtp_packet_chunk_find_gsm(pkt, ret, min_nsamples);
break;

case RTP_G723:
rtp_packet_chunk_find_g723(pkt, ret, min_nsamples);
break;

default:
ret->whole_packet_matched = 1;
break;
}
}

void
rtp_packet_parse(struct rtp_packet *pkt)
{
int padding_size = 0;
int padding_size;

padding_size = 0;

pkt->data_size = 0;
pkt->data_offset = 0;
Expand All @@ -99,9 +222,17 @@ rtp_packet_parse(struct rtp_packet *pkt)
padding_size = ((unsigned char *) pkt)[pkt->size - 1];

pkt->data_size = pkt->size - pkt->data_offset - padding_size;
pkt->nsamples = rtp_bytes2samples(pkt->header.pt, pkt->data_size);
pkt->nsamples = rtp_calc_samples(pkt->header.pt, pkt->data_size, &pkt->buf[pkt->data_offset]);
pkt->ts = ntohl(pkt->header.ts);
pkt->seq = ntohs(pkt->header.seq);

pkt->appendable = 1;
/*
* G.729 comfort noise frame as the last frame causes
* packet to be non-appendable
*/
if (pkt->header.pt == RTP_G729 && (pkt->data_size % 10) != 0)
pkt->appendable = 0;
}

struct rtp_packet *
Expand All @@ -120,6 +251,7 @@ rtp_packet_alloc()
void
rtp_packet_free(struct rtp_packet *pkt)
{

pkt->next = rtp_packet_pool;
pkt->prev = NULL;
rtp_packet_pool = pkt;
Expand Down
12 changes: 9 additions & 3 deletions rtp.h
Expand Up @@ -24,7 +24,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: rtp.h,v 1.7 2008/03/28 23:15:19 sobomax Exp $
* $Id: rtp.h,v 1.8 2008/04/17 22:38:00 sobomax Exp $
*
*/

Expand Down Expand Up @@ -85,7 +85,7 @@ struct rtp_packet {
int nsamples;
uint32_t ts;
uint16_t seq;
int resizeable;
int appendable;
double rtime;

struct rtp_packet *next;
Expand All @@ -102,6 +102,12 @@ struct rtp_packet {
};
};

struct rtp_packet_chunk {
int bytes;
int nsamples;
int whole_packet_matched;
};

#define RTP_HDR_LEN(rhp) (sizeof(*(rhp)) + ((rhp)->cc * sizeof((rhp)->csrc[0])))

void rtp_packet_parse(struct rtp_packet *);
Expand All @@ -112,7 +118,7 @@ void rtp_packet_free(struct rtp_packet *);
void rtp_packet_set_seq(struct rtp_packet *, uint16_t seq);
void rtp_packet_set_ts(struct rtp_packet *, uint32_t ts);

size_t rtp_samples2bytes(int codec_id, int nsamples);
void rtp_packet_first_chunk_find(struct rtp_packet *, struct rtp_packet_chunk *, int min_nsamples);

#define ts_less(ts1, ts2) (((ts1) - (ts2)) > (uint32_t) (1 << 31))

Expand Down

0 comments on commit 77ab7cb

Please sign in to comment.