|
|
|
@ -193,6 +193,7 @@ static struct ssrc_entry *__ssrc_handler_transcode_new(void *p);
|
|
|
|
|
static struct ssrc_entry *__ssrc_handler_new(void *p);
|
|
|
|
|
static void __ssrc_handler_stop(void *p);
|
|
|
|
|
static void __free_ssrc_handler(void *);
|
|
|
|
|
INLINE struct codec_handler *codec_handler_lookup(GHashTable *ht, int pt, struct call_media *sink);
|
|
|
|
|
|
|
|
|
|
static void __transcode_packet_free(struct transcode_packet *);
|
|
|
|
|
|
|
|
|
@ -263,7 +264,9 @@ void codec_handler_free(struct codec_handler **handler) {
|
|
|
|
|
*handler = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct codec_handler *__handler_new(const struct rtp_payload_type *pt, struct call_media *media) {
|
|
|
|
|
static struct codec_handler *__handler_new(const struct rtp_payload_type *pt, struct call_media *media,
|
|
|
|
|
struct call_media *sink)
|
|
|
|
|
{
|
|
|
|
|
struct codec_handler *handler = g_slice_alloc0(sizeof(*handler));
|
|
|
|
|
handler->source_pt.payload_type = -1;
|
|
|
|
|
if (pt)
|
|
|
|
@ -275,6 +278,7 @@ static struct codec_handler *__handler_new(const struct rtp_payload_type *pt, st
|
|
|
|
|
handler->packet_encoded = packet_encoded_rtp;
|
|
|
|
|
handler->packet_decoded = packet_decoded_fifo;
|
|
|
|
|
handler->media = media;
|
|
|
|
|
handler->sink = sink;
|
|
|
|
|
return handler;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -407,7 +411,7 @@ check_output:;
|
|
|
|
|
struct codec_handler *codec_handler_make_playback(const struct rtp_payload_type *src_pt,
|
|
|
|
|
const struct rtp_payload_type *dst_pt, unsigned long last_ts, struct call_media *media)
|
|
|
|
|
{
|
|
|
|
|
struct codec_handler *handler = __handler_new(src_pt, media);
|
|
|
|
|
struct codec_handler *handler = __handler_new(src_pt, media, NULL);
|
|
|
|
|
rtp_payload_type_copy(&handler->dest_pt, dst_pt);
|
|
|
|
|
handler->func = handler_func_playback;
|
|
|
|
|
handler->ssrc_handler = (void *) __ssrc_handler_transcode_new(handler);
|
|
|
|
@ -591,7 +595,7 @@ static void __check_dtmf_injector(struct call_media *receiver, struct call_media
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
parent->dtmf_injector = __handler_new(&src_pt, receiver);
|
|
|
|
|
parent->dtmf_injector = __handler_new(&src_pt, receiver, sink);
|
|
|
|
|
__make_transcoder(parent->dtmf_injector, &parent->dest_pt, output_transcoders, -1, 0, -1);
|
|
|
|
|
parent->dtmf_injector->func = handler_func_inject_dtmf;
|
|
|
|
|
}
|
|
|
|
@ -599,28 +603,28 @@ static void __check_dtmf_injector(struct call_media *receiver, struct call_media
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static struct codec_handler *__get_pt_handler(struct call_media *receiver, struct rtp_payload_type *pt) {
|
|
|
|
|
static struct codec_handler *__get_pt_handler(struct call_media *receiver, struct rtp_payload_type *pt,
|
|
|
|
|
struct call_media *sink)
|
|
|
|
|
{
|
|
|
|
|
ensure_codec_def(pt, receiver);
|
|
|
|
|
struct codec_handler *handler;
|
|
|
|
|
handler = g_hash_table_lookup(receiver->codec_handlers, GINT_TO_POINTER(pt->payload_type));
|
|
|
|
|
handler = codec_handler_lookup(receiver->codec_handlers, pt->payload_type, sink);
|
|
|
|
|
if (handler) {
|
|
|
|
|
// make sure existing handler matches this PT
|
|
|
|
|
if (rtp_payload_type_cmp(pt, &handler->source_pt)) {
|
|
|
|
|
ilogs(codec, LOG_DEBUG, "Resetting codec handler for PT %i", pt->payload_type);
|
|
|
|
|
g_hash_table_remove(receiver->codec_handlers, handler);
|
|
|
|
|
__handler_shutdown(handler);
|
|
|
|
|
handler = NULL;
|
|
|
|
|
g_atomic_pointer_set(&receiver->codec_handler_cache, NULL);
|
|
|
|
|
g_hash_table_remove(receiver->codec_handlers, GINT_TO_POINTER(pt->payload_type));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!handler) {
|
|
|
|
|
ilogs(codec, LOG_DEBUG, "Creating codec handler for " STR_FORMAT " (%i)",
|
|
|
|
|
STR_FMT(&pt->encoding_with_params),
|
|
|
|
|
pt->payload_type);
|
|
|
|
|
handler = __handler_new(pt, receiver);
|
|
|
|
|
g_hash_table_insert(receiver->codec_handlers,
|
|
|
|
|
GINT_TO_POINTER(handler->source_pt.payload_type),
|
|
|
|
|
handler);
|
|
|
|
|
handler = __handler_new(pt, receiver, sink);
|
|
|
|
|
g_hash_table_insert(receiver->codec_handlers, handler, handler);
|
|
|
|
|
g_queue_push_tail(&receiver->codec_handlers_store, handler);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -640,7 +644,7 @@ static void __check_t38_decoder(struct call_media *t38_media) {
|
|
|
|
|
if (t38_media->t38_handler)
|
|
|
|
|
return;
|
|
|
|
|
ilogs(codec, LOG_DEBUG, "Creating T.38 packet handler");
|
|
|
|
|
t38_media->t38_handler = __handler_new(NULL, t38_media);
|
|
|
|
|
t38_media->t38_handler = __handler_new(NULL, t38_media, NULL);
|
|
|
|
|
t38_media->t38_handler->func = handler_func_t38;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -702,7 +706,7 @@ static void __check_t38_gateway(struct call_media *pcm_media, struct call_media
|
|
|
|
|
// links to the T.38 encoder
|
|
|
|
|
for (GList *l = pcm_media->codecs.codec_prefs.head; l; l = l->next) {
|
|
|
|
|
struct rtp_payload_type *pt = l->data;
|
|
|
|
|
struct codec_handler *handler = __get_pt_handler(pcm_media, pt);
|
|
|
|
|
struct codec_handler *handler = __get_pt_handler(pcm_media, pt, t38_media);
|
|
|
|
|
if (!pt->codec_def) {
|
|
|
|
|
// should not happen
|
|
|
|
|
ilogs(codec, LOG_WARN, "Unsupported codec " STR_FORMAT " for T.38 transcoding",
|
|
|
|
@ -831,6 +835,29 @@ static void __codec_rtcp_timer(struct call_media *receiver) {
|
|
|
|
|
// XXX unify with media player into a generic RTCP player
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static unsigned int __codec_handler_hash(const void *p) {
|
|
|
|
|
const struct codec_handler *h = p;
|
|
|
|
|
return h->source_pt.payload_type ^ GPOINTER_TO_UINT(h->sink);
|
|
|
|
|
}
|
|
|
|
|
static int __codec_handler_eq(const void *a, const void *b) {
|
|
|
|
|
const struct codec_handler *h = a, *j = b;
|
|
|
|
|
return h->source_pt.payload_type == j->source_pt.payload_type
|
|
|
|
|
&& h->sink == j->sink;
|
|
|
|
|
}
|
|
|
|
|
INLINE struct codec_handler __codec_handler_lookup_struct(int pt, struct call_media *sink) {
|
|
|
|
|
struct codec_handler lookup = {
|
|
|
|
|
.source_pt = {
|
|
|
|
|
.payload_type = pt,
|
|
|
|
|
},
|
|
|
|
|
.sink = sink,
|
|
|
|
|
};
|
|
|
|
|
return lookup;
|
|
|
|
|
}
|
|
|
|
|
INLINE struct codec_handler *codec_handler_lookup(GHashTable *ht, int pt, struct call_media *sink) {
|
|
|
|
|
struct codec_handler lookup = __codec_handler_lookup_struct(pt, sink);
|
|
|
|
|
return g_hash_table_lookup(ht, &lookup);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// call must be locked in W
|
|
|
|
|
void codec_handlers_update(struct call_media *receiver, struct call_media *sink,
|
|
|
|
|
const struct sdp_ng_flags *flags, const struct stream_params *sp)
|
|
|
|
@ -855,7 +882,7 @@ void codec_handlers_update(struct call_media *receiver, struct call_media *sink,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!receiver->codec_handlers)
|
|
|
|
|
receiver->codec_handlers = g_hash_table_new(g_direct_hash, g_direct_equal);
|
|
|
|
|
receiver->codec_handlers = g_hash_table_new(__codec_handler_hash, __codec_handler_eq);
|
|
|
|
|
|
|
|
|
|
// should we transcode to a non-RTP protocol?
|
|
|
|
|
if (proto_is_not_rtp(sink->protocol)) {
|
|
|
|
@ -894,7 +921,7 @@ void codec_handlers_update(struct call_media *receiver, struct call_media *sink,
|
|
|
|
|
ilogs(codec, LOG_DEBUG, "Checking receiver codec " STR_FORMAT " (%i)",
|
|
|
|
|
STR_FMT(&pt->encoding_with_full_params), pt->payload_type);
|
|
|
|
|
|
|
|
|
|
struct codec_handler *handler = __get_pt_handler(receiver, pt);
|
|
|
|
|
struct codec_handler *handler = __get_pt_handler(receiver, pt, sink);
|
|
|
|
|
|
|
|
|
|
// check our own support for this codec
|
|
|
|
|
if (!pt->codec_def) {
|
|
|
|
@ -1136,19 +1163,22 @@ next:
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static struct codec_handler *codec_handler_get_rtp(struct call_media *m, int payload_type) {
|
|
|
|
|
static struct codec_handler *codec_handler_get_rtp(struct call_media *m, int payload_type,
|
|
|
|
|
struct call_media *sink)
|
|
|
|
|
{
|
|
|
|
|
struct codec_handler *h;
|
|
|
|
|
|
|
|
|
|
if (payload_type < 0)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
struct codec_handler lookup = __codec_handler_lookup_struct(payload_type, sink);
|
|
|
|
|
h = g_atomic_pointer_get(&m->codec_handler_cache);
|
|
|
|
|
if (G_LIKELY(G_LIKELY(h) && G_LIKELY(h->source_pt.payload_type == payload_type)))
|
|
|
|
|
if (G_LIKELY(G_LIKELY(h) && G_LIKELY(__codec_handler_eq(&lookup, h))))
|
|
|
|
|
return h;
|
|
|
|
|
|
|
|
|
|
if (G_UNLIKELY(!m->codec_handlers))
|
|
|
|
|
return NULL;
|
|
|
|
|
h = g_hash_table_lookup(m->codec_handlers, GINT_TO_POINTER(payload_type));
|
|
|
|
|
h = g_hash_table_lookup(m->codec_handlers, &lookup);
|
|
|
|
|
if (!h)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
@ -1233,7 +1263,7 @@ void mqtt_timer_stop(struct mqtt_timer **mqtp) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// call must be locked in R
|
|
|
|
|
struct codec_handler *codec_handler_get(struct call_media *m, int payload_type) {
|
|
|
|
|
struct codec_handler *codec_handler_get(struct call_media *m, int payload_type, struct call_media *sink) {
|
|
|
|
|
#ifdef WITH_TRANSCODING
|
|
|
|
|
struct codec_handler *ret = NULL;
|
|
|
|
|
|
|
|
|
@ -1241,7 +1271,7 @@ struct codec_handler *codec_handler_get(struct call_media *m, int payload_type)
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
if (m->protocol->rtp)
|
|
|
|
|
ret = codec_handler_get_rtp(m, payload_type);
|
|
|
|
|
ret = codec_handler_get_rtp(m, payload_type, sink);
|
|
|
|
|
else if (m->protocol->index == PROTO_UDPTL)
|
|
|
|
|
ret = codec_handler_get_udptl(m);
|
|
|
|
|
|
|
|
|
@ -1669,7 +1699,7 @@ static struct codec_handler *__input_handler(struct codec_handler *h, struct med
|
|
|
|
|
if (prim_pt == 255)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
struct codec_handler *sequencer_h = codec_handler_get(mp->media, prim_pt);
|
|
|
|
|
struct codec_handler *sequencer_h = codec_handler_get(mp->media, prim_pt, mp->media_out);
|
|
|
|
|
if (sequencer_h == h)
|
|
|
|
|
continue;
|
|
|
|
|
if (sequencer_h->source_pt.codec_def && sequencer_h->source_pt.codec_def->supplemental)
|
|
|
|
@ -3570,7 +3600,7 @@ void codec_store_answer(struct codec_store *dst, struct codec_store *src, struct
|
|
|
|
|
add_codec = 0;
|
|
|
|
|
|
|
|
|
|
struct rtp_payload_type *pt = l->data;
|
|
|
|
|
struct codec_handler *h = codec_handler_get(src_media, pt->payload_type);
|
|
|
|
|
struct codec_handler *h = codec_handler_get(src_media, pt->payload_type, dst_media);
|
|
|
|
|
if (!h || h->dest_pt.payload_type == -1) {
|
|
|
|
|
// passthrough or missing
|
|
|
|
|
if (pt->for_transcoding)
|
|
|
|
|