rtpsource: Modularize generation of RTP frames
Change-Id: Iad98e1753fef1927c0e8a7493372141372a38224laforge/rtpsource
parent
7cb125d895
commit
9389188621
|
@ -4,7 +4,7 @@ OSMO_LIBS:=$(shell pkg-config --libs libosmocore libosmoctrl libosmotrau)
|
|||
CFLAGS:= -g -Wall $(OSMO_CFLAGS)
|
||||
LIBS:= $(OSMO_LIBS)
|
||||
|
||||
rtpsource: rtpsource.o ctrl_if.o
|
||||
rtpsource: rtpsource.o ctrl_if.o rtp_provider.o rtp_provider_static.o
|
||||
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
|
||||
|
||||
|
|
|
@ -8,6 +8,8 @@ enum {
|
|||
DMAIN,
|
||||
};
|
||||
|
||||
struct rtp_provider_instance;
|
||||
|
||||
struct rtp_connection {
|
||||
struct llist_head list;
|
||||
|
||||
|
@ -21,6 +23,7 @@ struct rtp_connection {
|
|||
uint16_t remote_port;
|
||||
|
||||
uint8_t rtp_pt;
|
||||
struct rtp_provider_instance *rtp_prov_inst;
|
||||
};
|
||||
|
||||
struct rtpsource_state {
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
#include <osmocom/core/talloc.h>
|
||||
#include <osmocom/core/utils.h>
|
||||
#include <osmocom/core/linuxlist.h>
|
||||
|
||||
#include "rtp_provider.h"
|
||||
#include "internal.h"
|
||||
|
||||
|
||||
static LLIST_HEAD(g_providers);
|
||||
static LLIST_HEAD(g_prov_instances);
|
||||
|
||||
void rtp_provider_register(struct rtp_provider *prov)
|
||||
{
|
||||
llist_add_tail(&prov->list, &g_providers);
|
||||
}
|
||||
|
||||
const struct rtp_provider *rtp_provider_find(const char *name)
|
||||
{
|
||||
struct rtp_provider *p;
|
||||
llist_for_each_entry(p, &g_providers, list) {
|
||||
if (!strcmp(name, p->name))
|
||||
return p;
|
||||
}
|
||||
LOGP(DMAIN, LOGL_ERROR, "Couldn't find RTP provider '%s'\n", name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct rtp_provider_instance *
|
||||
rtp_provider_instance_alloc(void *ctx, const struct rtp_provider *provider, enum codec_type codec)
|
||||
{
|
||||
struct rtp_provider_instance *pi;
|
||||
|
||||
pi = talloc_zero(ctx, struct rtp_provider_instance);
|
||||
if (!pi)
|
||||
return NULL;
|
||||
|
||||
pi->provider = provider;
|
||||
pi->codec = codec;
|
||||
llist_add_tail(&pi->list, &g_prov_instances);
|
||||
|
||||
return pi;
|
||||
}
|
||||
|
||||
void rtp_provider_instance_free(struct rtp_provider_instance *pi)
|
||||
{
|
||||
llist_del(&pi->list);
|
||||
talloc_free(pi);
|
||||
}
|
||||
|
||||
int rtp_provider_instance_gen_frame(struct rtp_provider_instance *pi, uint8_t *out, size_t out_size)
|
||||
{
|
||||
OSMO_ASSERT(pi->provider);
|
||||
return pi->provider->rtp_gen(pi, out, out_size);
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <osmocom/core/linuxlist.h>
|
||||
|
||||
enum codec_type {
|
||||
CODEC_ULAW,
|
||||
CODEC_ALAW,
|
||||
CODEC_GSM_FR,
|
||||
CODEC_GSM_EFR,
|
||||
CODEC_GSM_HR,
|
||||
CODEC_AMR_4_75,
|
||||
CODEC_AMR_5_15,
|
||||
CODEC_AMR_5_90,
|
||||
CODEC_AMR_6_70,
|
||||
CODEC_AMR_7_40,
|
||||
CODEC_AMR_7_95,
|
||||
CODEC_AMR_10_2,
|
||||
CODEC_AMR_12_2,
|
||||
CODEC_AMR_SID,
|
||||
_NUM_CODECS
|
||||
};
|
||||
|
||||
struct rtp_provider_instance;
|
||||
|
||||
struct rtp_provider {
|
||||
/* global list of RTP providers */
|
||||
struct llist_head list;
|
||||
const char *name;
|
||||
|
||||
/* generate the next RTP packet; return length in octests or negative on error */
|
||||
int (*rtp_gen)(struct rtp_provider_instance *inst, uint8_t *out, size_t out_size);
|
||||
};
|
||||
|
||||
struct rtp_provider_instance {
|
||||
/* entry in global list of RTP provider instances */
|
||||
struct llist_head list;
|
||||
/* pointer to provider of which we are an instance */
|
||||
const struct rtp_provider *provider;
|
||||
/* codec payload we are to generate */
|
||||
enum codec_type codec;
|
||||
|
||||
/* private user data */
|
||||
void *priv;
|
||||
};
|
||||
|
||||
void rtp_provider_register(struct rtp_provider *prov);
|
||||
const struct rtp_provider *rtp_provider_find(const char *name);
|
||||
|
||||
struct rtp_provider_instance *rtp_provider_instance_alloc(void *ctx, const struct rtp_provider *provider, enum codec_type codec);
|
||||
void rtp_provider_instance_free(struct rtp_provider_instance *pi);
|
||||
int rtp_provider_instance_gen_frame(struct rtp_provider_instance *pi, uint8_t *out, size_t out_size);
|
|
@ -0,0 +1,107 @@
|
|||
|
||||
#include <errno.h>
|
||||
#include <osmocom/codec/codec.h>
|
||||
#include <osmocom/core/utils.h>
|
||||
|
||||
#include "rtp_provider.h"
|
||||
#include "internal.h"
|
||||
|
||||
static struct rtp_provider static_provider;
|
||||
|
||||
static const uint8_t len4codec[_NUM_CODECS] = {
|
||||
[CODEC_ULAW] = 160,
|
||||
[CODEC_ALAW] = 160,
|
||||
[CODEC_GSM_FR] = GSM_FR_BYTES,
|
||||
[CODEC_GSM_EFR] = GSM_EFR_BYTES,
|
||||
[CODEC_GSM_HR] = GSM_HR_BYTES,
|
||||
[CODEC_AMR_4_75] = 12,
|
||||
[CODEC_AMR_5_15] = 13,
|
||||
[CODEC_AMR_5_90] = 15,
|
||||
[CODEC_AMR_6_70] = 17,
|
||||
[CODEC_AMR_7_40] = 19,
|
||||
[CODEC_AMR_7_95] = 20,
|
||||
[CODEC_AMR_10_2] = 26,
|
||||
[CODEC_AMR_12_2] = 31,
|
||||
[CODEC_AMR_SID] = 5,
|
||||
};
|
||||
|
||||
/* generate a static / fixed RTP payload of matching codec/mode */
|
||||
static int rtp_gen_static(struct rtp_provider_instance *pi, uint8_t *out, size_t out_size)
|
||||
{
|
||||
uint8_t len;
|
||||
|
||||
OSMO_ASSERT(pi->provider == &static_provider);
|
||||
|
||||
len = len4codec[pi->codec];
|
||||
if (out_size < len) {
|
||||
LOGP(DMAIN, LOGL_ERROR, "out_size %zu < %u\n", out_size, len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memset(out, 0, len);
|
||||
|
||||
switch (pi->codec) {
|
||||
case CODEC_ULAW:
|
||||
case CODEC_ALAW:
|
||||
break;
|
||||
case CODEC_GSM_FR:
|
||||
out[0] = (out[0] & 0x0f) | 0xD0; /* mask in first four bit for FR */
|
||||
break;
|
||||
case CODEC_GSM_EFR:
|
||||
out[0] = (out[0] & 0x0f) | 0xC0; /* mask in first four bit for EFR */
|
||||
break;
|
||||
case CODEC_GSM_HR:
|
||||
break;
|
||||
case CODEC_AMR_4_75:
|
||||
out[0] = 0 << 4;
|
||||
out[1] = 0 << 3;
|
||||
break;
|
||||
case CODEC_AMR_5_15:
|
||||
out[0] = 1 << 4;
|
||||
out[1] = 1 << 3;
|
||||
break;
|
||||
case CODEC_AMR_5_90:
|
||||
out[0] = 2 << 4;
|
||||
out[1] = 2 << 3;
|
||||
break;
|
||||
case CODEC_AMR_6_70:
|
||||
out[0] = 3 << 4;
|
||||
out[1] = 3 << 3;
|
||||
break;
|
||||
case CODEC_AMR_7_40:
|
||||
out[0] = 4 << 4;
|
||||
out[1] = 4 << 3;
|
||||
break;
|
||||
case CODEC_AMR_7_95:
|
||||
out[0] = 5 << 4;
|
||||
out[1] = 5 << 3;
|
||||
break;
|
||||
case CODEC_AMR_10_2:
|
||||
out[0] = 6 << 4;
|
||||
out[1] = 6 << 3;
|
||||
break;
|
||||
case CODEC_AMR_12_2:
|
||||
out[0] = 7 << 4;
|
||||
out[1] = 7 << 3;
|
||||
break;
|
||||
case CODEC_AMR_SID:
|
||||
out[0] = 2 << 4; /* CMR: 5.90 */
|
||||
out[0] = 8 << 3;
|
||||
break;
|
||||
default:
|
||||
OSMO_ASSERT(0);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
static struct rtp_provider static_provider = {
|
||||
.name = "static",
|
||||
.rtp_gen = &rtp_gen_static,
|
||||
};
|
||||
|
||||
static void __attribute__((constructor)) rtp_provider_static_constr(void)
|
||||
{
|
||||
rtp_provider_register(&static_provider);
|
||||
}
|
|
@ -48,6 +48,7 @@
|
|||
#include <osmocom/trau/osmo_ortp.h>
|
||||
|
||||
#include "internal.h"
|
||||
#include "rtp_provider.h"
|
||||
|
||||
|
||||
/* find a connection based on its CNAME */
|
||||
|
@ -64,13 +65,18 @@ struct rtp_connection *find_connection_by_cname(struct rtpsource_state *rss, con
|
|||
/* create a new RTP connection for given CNAME; includes binding of local RTP port */
|
||||
struct rtp_connection *create_connection(struct rtpsource_state *rss, const char *cname)
|
||||
{
|
||||
const struct rtp_provider *rtp_prov;
|
||||
struct rtp_connection *conn;
|
||||
enum codec_type codec = CODEC_GSM_FR; // TODO: configurable
|
||||
const char *host;
|
||||
int port;
|
||||
int rc;
|
||||
|
||||
OSMO_ASSERT(!find_connection_by_cname(rss, cname));
|
||||
|
||||
rtp_prov = rtp_provider_find("static"); // TODO: configurable
|
||||
OSMO_ASSERT(rtp_prov);
|
||||
|
||||
conn = talloc_zero(rss, struct rtp_connection);
|
||||
OSMO_ASSERT(conn);
|
||||
conn->cname = talloc_strdup(conn, cname);
|
||||
|
@ -90,6 +96,9 @@ struct rtp_connection *create_connection(struct rtpsource_state *rss, const char
|
|||
osmo_rtp_set_source_desc(conn->rtp_sock, conn->cname, "rtpsource", NULL, NULL,
|
||||
NULL, "osmo-rtpsource", NULL);
|
||||
|
||||
conn->rtp_prov_inst = rtp_provider_instance_alloc(conn, rtp_prov, codec);
|
||||
OSMO_ASSERT(conn->rtp_prov_inst);
|
||||
|
||||
llist_add_tail(&conn->list, &rss->connections);
|
||||
|
||||
CLOGP(conn, DMAIN, LOGL_INFO, "Created RTP connection; local=%s:%u\n",
|
||||
|
@ -156,12 +165,11 @@ static int timerfd_cb(struct osmo_fd *ofd, unsigned int priv_nr)
|
|||
|
||||
/* iterate over all RTP connections and send one frame each */
|
||||
llist_for_each_entry(conn, &rss->connections, list) {
|
||||
int i;
|
||||
/* TODO: have different sources (file+name, ...) */
|
||||
uint8_t payload[33];
|
||||
memset(payload, 0, sizeof(payload));
|
||||
payload[0] = (payload[0] & 0x0f) | 0xD0; /* mask in first four bit for FR */
|
||||
osmo_rtp_send_frame_ext(conn->rtp_sock, payload, sizeof(payload), 160, false);
|
||||
uint8_t payload[256];
|
||||
int i, len;
|
||||
|
||||
len = rtp_provider_instance_gen_frame(conn->rtp_prov_inst, payload, sizeof(payload));
|
||||
osmo_rtp_send_frame_ext(conn->rtp_sock, payload, len, 160, false);
|
||||
/* make sure RTP clock advances correctly, even if we missed transmit of some */
|
||||
for (i = 1; i < expire_count; i++)
|
||||
osmo_rtp_skipped_frame(conn->rtp_sock, 160);
|
||||
|
|
Loading…
Reference in New Issue