From 30dcadab157aa631a676fc4dbbc0688924aca3e7 Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Mon, 21 Nov 2016 13:44:59 -0500 Subject: [PATCH] TT#5566 rudimentary support for multiple audio codecs Change-Id: I7e473f5d17874641253b4b16c3470851743818e1 --- daemon/call.c | 1 + daemon/call_interfaces.c | 1 + daemon/recording.c | 1 + daemon/redis.c | 14 ++++++---- daemon/rtp.c | 49 ++------------------------------ daemon/rtp.h | 8 ------ daemon/sdp.c | 1 + lib/rtplib.c | 53 +++++++++++++++++++++++++++++++++++ lib/rtplib.h | 14 ++++++++++ recording-daemon/decoder.c | 57 ++++++++++++++++++++++++++++++++++++-- recording-daemon/decoder.h | 2 +- recording-daemon/packet.c | 38 ++++++++++++++++++------- 12 files changed, 164 insertions(+), 75 deletions(-) diff --git a/daemon/call.c b/daemon/call.c index 6378d1e7a..bc0eccac9 100644 --- a/daemon/call.c +++ b/daemon/call.c @@ -37,6 +37,7 @@ #include "rtpengine_config.h" #include "log_funcs.h" #include "recording.h" +#include "rtplib.h" diff --git a/daemon/call_interfaces.c b/daemon/call_interfaces.c index fe9b8e6c5..e08e708f4 100644 --- a/daemon/call_interfaces.c +++ b/daemon/call_interfaces.c @@ -19,6 +19,7 @@ #include "rtp.h" #include "ice.h" #include "recording.h" +#include "rtplib.h" diff --git a/daemon/recording.c b/daemon/recording.c index b04064122..7dd2cd5bd 100644 --- a/daemon/recording.c +++ b/daemon/recording.c @@ -18,6 +18,7 @@ #include "call.h" #include "kernel.h" #include "bencode.h" +#include "rtplib.h" diff --git a/daemon/redis.c b/daemon/redis.c index b79be0ede..25715da49 100644 --- a/daemon/redis.c +++ b/daemon/redis.c @@ -1,3 +1,5 @@ +#include "redis.h" + #include #include #include @@ -6,9 +8,12 @@ #include #include #include - #include -#include "redis.h" +#include +#include +#include +#include + #include "compat.h" #include "aux.h" #include "call.h" @@ -18,10 +23,7 @@ #include "crypto.h" #include "dtls.h" #include "recording.h" -#include "hiredis/hiredis.h" -#include "hiredis/async.h" -#include "hiredis/adapters/libevent.h" -#include "event2/thread.h" +#include "rtplib.h" diff --git a/daemon/rtp.c b/daemon/rtp.c index cbe1cef4f..478aaf136 100644 --- a/daemon/rtp.c +++ b/daemon/rtp.c @@ -13,44 +13,6 @@ -#define RFC_TYPE(type, name, c_rate) \ - [type] = { \ - .payload_type = type, \ - .encoding = STR_CONST_INIT(#name), \ - .clock_rate = c_rate, \ - } - -static const struct rtp_payload_type __rfc_types[] = -{ - RFC_TYPE(0, PCMU, 8000), - RFC_TYPE(3, GSM, 8000), - RFC_TYPE(4, G723, 8000), - RFC_TYPE(5, DVI4, 8000), - RFC_TYPE(6, DVI4, 16000), - RFC_TYPE(7, LPC, 8000), - RFC_TYPE(8, PCMA, 8000), - RFC_TYPE(9, G722, 8000), - RFC_TYPE(10, L16, 44100), - RFC_TYPE(11, L16, 44100), - RFC_TYPE(12, QCELP, 8000), - RFC_TYPE(13, CN, 8000), - RFC_TYPE(14, MPA, 90000), - RFC_TYPE(15, G728, 8000), - RFC_TYPE(16, DVI4, 11025), - RFC_TYPE(17, DVI4, 22050), - RFC_TYPE(18, G729, 8000), - RFC_TYPE(25, CelB, 90000), - RFC_TYPE(26, JPEG, 90000), - RFC_TYPE(28, nv, 90000), - RFC_TYPE(31, H261, 90000), - RFC_TYPE(32, MPV, 90000), - RFC_TYPE(33, MP2T, 90000), - RFC_TYPE(34, H263, 90000), -}; - - - - INLINE int check_session_keys(struct crypto_context *c) { str s; const char *err; @@ -299,18 +261,11 @@ const struct rtp_payload_type *rtp_payload_type(unsigned int type, GHashTable *l const struct rtp_payload_type *rtp_pt; if (!lookup) - goto rfc_types; + return rtp_get_rfc_payload_type(type); rtp_pt = g_hash_table_lookup(lookup, &type); if (rtp_pt) return rtp_pt; -rfc_types: - if (type >= G_N_ELEMENTS(__rfc_types)) - return NULL; - rtp_pt = &__rfc_types[type]; - if (!rtp_pt->encoding.s) - return NULL; - return rtp_pt; - + return rtp_get_rfc_payload_type(type); } diff --git a/daemon/rtp.h b/daemon/rtp.h index 86d84006c..659094add 100644 --- a/daemon/rtp.h +++ b/daemon/rtp.h @@ -11,14 +11,6 @@ struct crypto_context; struct rtp_header; -struct rtp_payload_type { - unsigned int payload_type; - str encoding_with_params; - str encoding; - unsigned int clock_rate; - str encoding_parameters; -}; - diff --git a/daemon/sdp.c b/daemon/sdp.c index 2e9dabf22..14c5647a6 100644 --- a/daemon/sdp.c +++ b/daemon/sdp.c @@ -17,6 +17,7 @@ #include "ice.h" #include "socket.h" #include "call_interfaces.h" +#include "rtplib.h" struct network_address { str network_type; diff --git a/lib/rtplib.c b/lib/rtplib.c index 1ee8ea3a7..594f52914 100644 --- a/lib/rtplib.c +++ b/lib/rtplib.c @@ -13,6 +13,47 @@ struct rtp_extension { +#define RFC_TYPE(type, name, c_rate) \ + [type] = { \ + .payload_type = type, \ + .encoding = STR_CONST_INIT(#name), \ + .encoding_with_params = STR_CONST_INIT(#name "/" #c_rate), \ + .clock_rate = c_rate, \ + } + +const struct rtp_payload_type rfc_rtp_payload_types[] = +{ + RFC_TYPE(0, PCMU, 8000), + RFC_TYPE(3, GSM, 8000), + RFC_TYPE(4, G723, 8000), + RFC_TYPE(5, DVI4, 8000), + RFC_TYPE(6, DVI4, 16000), + RFC_TYPE(7, LPC, 8000), + RFC_TYPE(8, PCMA, 8000), + RFC_TYPE(9, G722, 8000), + RFC_TYPE(10, L16, 44100), + RFC_TYPE(11, L16, 44100), + RFC_TYPE(12, QCELP, 8000), + RFC_TYPE(13, CN, 8000), + RFC_TYPE(14, MPA, 90000), + RFC_TYPE(15, G728, 8000), + RFC_TYPE(16, DVI4, 11025), + RFC_TYPE(17, DVI4, 22050), + RFC_TYPE(18, G729, 8000), + RFC_TYPE(25, CelB, 90000), + RFC_TYPE(26, JPEG, 90000), + RFC_TYPE(28, nv, 90000), + RFC_TYPE(31, H261, 90000), + RFC_TYPE(32, MPV, 90000), + RFC_TYPE(33, MP2T, 90000), + RFC_TYPE(34, H263, 90000), +}; +const int num_rfc_rtp_payload_types = G_N_ELEMENTS(rfc_rtp_payload_types); + + + + + int rtp_payload(struct rtp_header **out, str *p, const str *s) { struct rtp_header *rtp; @@ -72,3 +113,15 @@ int rtp_padding(struct rtp_header *header, str *payload) { payload->len -= padding; return 0; } + + +const struct rtp_payload_type *rtp_get_rfc_payload_type(unsigned int type) { + const struct rtp_payload_type *rtp_pt; + + if (type >= num_rfc_rtp_payload_types) + return NULL; + rtp_pt = &rfc_rtp_payload_types[type]; + if (!rtp_pt->encoding.s) + return NULL; + return rtp_pt; +} diff --git a/lib/rtplib.h b/lib/rtplib.h index 54b61df60..3ef82c753 100644 --- a/lib/rtplib.h +++ b/lib/rtplib.h @@ -15,8 +15,22 @@ struct rtp_header { } __attribute__ ((packed)); +struct rtp_payload_type { + unsigned int payload_type; + str encoding_with_params; + str encoding; + unsigned int clock_rate; + str encoding_parameters; +}; + + +extern const struct rtp_payload_type rfc_rtp_payload_types[]; +extern const int num_rfc_rtp_payload_types; + + int rtp_payload(struct rtp_header **out, str *p, const str *s); int rtp_padding(struct rtp_header *header, str *payload); +const struct rtp_payload_type *rtp_get_rfc_payload_type(unsigned int type); #endif diff --git a/recording-daemon/decoder.c b/recording-daemon/decoder.c index c60db29a7..6d5e1e3f9 100644 --- a/recording-daemon/decoder.c +++ b/recording-daemon/decoder.c @@ -5,6 +5,7 @@ #include #include "types.h" #include "log.h" +#include "str.h" struct decoder_s { @@ -24,16 +25,66 @@ struct output_s { }; -decoder_t *decoder_new(unsigned int payload_type, const char *payload_str) { +struct decoder_def_s { + const char *name; + int avcodec_id; +}; + + +#define DECODER_DEF(ref, id) { \ + .name = #ref, \ + .avcodec_id = AV_CODEC_ID_ ## id, \ +} +static const struct decoder_def_s decoders[] = { + DECODER_DEF(PCMA, PCM_ALAW), + DECODER_DEF(PCMU, PCM_MULAW), + DECODER_DEF(G723, G723_1), + DECODER_DEF(G722, ADPCM_G722), + DECODER_DEF(QCELP, QCELP), + DECODER_DEF(G729, G729), + DECODER_DEF(speex, SPEEX), + DECODER_DEF(GSM, GSM), + DECODER_DEF(iLBC, ILBC), + DECODER_DEF(opus, OPUS), +}; +typedef struct decoder_def_s decoder_def_t; + + +static const decoder_def_t *decoder_find(const str *name) { + for (int i = 0; i < G_N_ELEMENTS(decoders); i++) { + if (!str_cmp(name, decoders[i].name)) + return &decoders[i]; + } + return NULL; +} + + +decoder_t *decoder_new(const char *payload_str) { + str name; + char *slash = strchr(payload_str, '/'); + if (!slash) { + ilog(LOG_WARN, "Invalid payload format: %s", payload_str); + return NULL; + } + + str_init_len(&name, (char *) payload_str, slash - payload_str); + int clockrate = atoi(slash + 1); + + const decoder_def_t *def = decoder_find(&name); + if (!def) { + ilog(LOG_WARN, "No decoder for payload %s", payload_str); + return NULL; + } + decoder_t *ret = g_slice_alloc0(sizeof(*ret)); // XXX error reporting - AVCodec *codec = avcodec_find_decoder(AV_CODEC_ID_PCM_ALAW); + AVCodec *codec = avcodec_find_decoder(def->avcodec_id); ret->avcctx = avcodec_alloc_context3(codec); if (!ret->avcctx) goto err; ret->avcctx->channels = 1; - ret->avcctx->sample_rate = 8000; + ret->avcctx->sample_rate = clockrate; int i = avcodec_open2(ret->avcctx, codec, NULL); if (i) goto err; diff --git a/recording-daemon/decoder.h b/recording-daemon/decoder.h index 5ae47dfc4..5c3d516a6 100644 --- a/recording-daemon/decoder.h +++ b/recording-daemon/decoder.h @@ -5,7 +5,7 @@ #include "str.h" -decoder_t *decoder_new(unsigned int payload_type, const char *payload_str); +decoder_t *decoder_new(const char *payload_str); int decoder_input(decoder_t *, const str *, unsigned long ts, output_t *); void decoder_close(decoder_t *); diff --git a/recording-daemon/packet.c b/recording-daemon/packet.c index 7ef8e4560..48e221222 100644 --- a/recording-daemon/packet.c +++ b/recording-daemon/packet.c @@ -93,6 +93,7 @@ static int ssrc_tree_search(const void *testseq_p, const void *ts_p) { // ssrc is locked and must be unlocked when returning +// XXX split up function static void ssrc_run(ssrc_t *ssrc) { while (1) { // see if we have a packet with the correct seq nr in the queue @@ -128,24 +129,41 @@ static void ssrc_run(ssrc_t *ssrc) { } have_packet:; + dbg("processing packet seq %i", packet->seq); + g_tree_steal(ssrc->packets, GINT_TO_POINTER(packet->seq)); + // determine payload type and run decoder unsigned int payload_type = packet->rtp->m_pt & 0x7f; - metafile_t *mf = ssrc->metafile; - pthread_mutex_lock(&mf->payloads_lock); - char *payload_str = mf->payload_types[payload_type]; - pthread_mutex_unlock(&mf->payloads_lock); + // check if we have a decoder for this payload type yet + if (G_UNLIKELY(!ssrc->decoders[payload_type])) { + metafile_t *mf = ssrc->metafile; + pthread_mutex_lock(&mf->payloads_lock); + char *payload_str = mf->payload_types[payload_type]; + pthread_mutex_unlock(&mf->payloads_lock); + + if (!payload_str) { + const struct rtp_payload_type *rpt = rtp_get_rfc_payload_type(payload_type); + if (!rpt) { + ilog(LOG_WARN, "Unknown RTP payload type %u", payload_type); + goto next_packet; + } + payload_str = rpt->encoding_with_params.s; + } - dbg("processing packet seq %i, payload type is %s", packet->seq, payload_str); - g_tree_steal(ssrc->packets, GINT_TO_POINTER(packet->seq)); + dbg("payload type for %u is %s", payload_type, payload_str); - // check if we have a decoder for this payload type yet - if (G_UNLIKELY(!ssrc->decoders[payload_type])) - ssrc->decoders[payload_type] = decoder_new(payload_type, payload_str); - // XXX error handling + ssrc->decoders[payload_type] = decoder_new(payload_str); + if (!ssrc->decoders[payload_type]) { + ilog(LOG_WARN, "Cannot decode RTP payload type %u (%s)", + payload_type, payload_str); + goto next_packet; + } + } decoder_input(ssrc->decoders[payload_type], &packet->payload, ntohl(packet->rtp->timestamp), ssrc->output); +next_packet: ssrc->seq = (packet->seq + 1) & 0xffff; packet_free(packet); dbg("packets left in queue: %i", g_tree_nnodes(ssrc->packets));