From fb046ebc9ef7ed90d3674d1bc4ce9559aa596316 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 15 Mar 2020 19:38:44 +0100 Subject: [PATCH] rtpsource: Modularize generation of RTP frames Change-Id: Iad98e1753fef1927c0e8a7493372141372a38224 --- rtpsource/Makefile | 2 +- rtpsource/internal.h | 3 + rtpsource/rtp_provider.c | 54 ++++++++++++++++ rtpsource/rtp_provider.h | 51 +++++++++++++++ rtpsource/rtp_provider_static.c | 107 ++++++++++++++++++++++++++++++++ rtpsource/rtpsource.c | 20 ++++-- 6 files changed, 230 insertions(+), 7 deletions(-) create mode 100644 rtpsource/rtp_provider.c create mode 100644 rtpsource/rtp_provider.h create mode 100644 rtpsource/rtp_provider_static.c diff --git a/rtpsource/Makefile b/rtpsource/Makefile index 9972325..2ede792 100644 --- a/rtpsource/Makefile +++ b/rtpsource/Makefile @@ -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) diff --git a/rtpsource/internal.h b/rtpsource/internal.h index 13d07aa..a4501a2 100644 --- a/rtpsource/internal.h +++ b/rtpsource/internal.h @@ -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 { diff --git a/rtpsource/rtp_provider.c b/rtpsource/rtp_provider.c new file mode 100644 index 0000000..0d2b9c6 --- /dev/null +++ b/rtpsource/rtp_provider.c @@ -0,0 +1,54 @@ +#include +#include +#include + +#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); +} diff --git a/rtpsource/rtp_provider.h b/rtpsource/rtp_provider.h new file mode 100644 index 0000000..7048a3e --- /dev/null +++ b/rtpsource/rtp_provider.h @@ -0,0 +1,51 @@ +#pragma once +#include +#include + +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); diff --git a/rtpsource/rtp_provider_static.c b/rtpsource/rtp_provider_static.c new file mode 100644 index 0000000..323e686 --- /dev/null +++ b/rtpsource/rtp_provider_static.c @@ -0,0 +1,107 @@ + +#include +#include +#include + +#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); +} diff --git a/rtpsource/rtpsource.c b/rtpsource/rtpsource.c index 569d962..3087262 100644 --- a/rtpsource/rtpsource.c +++ b/rtpsource/rtpsource.c @@ -48,6 +48,7 @@ #include #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);