|
|
@ -140,6 +140,7 @@ static codec_handler_func handler_func_passthrough_ssrc; |
|
|
static codec_handler_func handler_func_transcode; |
|
|
static codec_handler_func handler_func_transcode; |
|
|
static codec_handler_func handler_func_playback; |
|
|
static codec_handler_func handler_func_playback; |
|
|
static codec_handler_func handler_func_inject_dtmf; |
|
|
static codec_handler_func handler_func_inject_dtmf; |
|
|
|
|
|
static codec_handler_func handler_func_supplemental; |
|
|
static codec_handler_func handler_func_dtmf; |
|
|
static codec_handler_func handler_func_dtmf; |
|
|
static codec_handler_func handler_func_t38; |
|
|
static codec_handler_func handler_func_t38; |
|
|
|
|
|
|
|
|
@ -149,6 +150,7 @@ static void __free_ssrc_handler(void *); |
|
|
|
|
|
|
|
|
static void __transcode_packet_free(struct transcode_packet *); |
|
|
static void __transcode_packet_free(struct transcode_packet *); |
|
|
|
|
|
|
|
|
|
|
|
static int packet_decode(struct codec_ssrc_handler *, struct transcode_packet *, struct media_packet *); |
|
|
static int packet_encoded_rtp(encoder_t *enc, void *u1, void *u2); |
|
|
static int packet_encoded_rtp(encoder_t *enc, void *u1, void *u2); |
|
|
static int packet_decoded_fifo(decoder_t *decoder, AVFrame *frame, void *u1, void *u2); |
|
|
static int packet_decoded_fifo(decoder_t *decoder, AVFrame *frame, void *u1, void *u2); |
|
|
static int packet_decoded_direct(decoder_t *decoder, AVFrame *frame, void *u1, void *u2); |
|
|
static int packet_decoded_direct(decoder_t *decoder, AVFrame *frame, void *u1, void *u2); |
|
|
@ -213,6 +215,8 @@ static void __make_passthrough(struct codec_handler *handler) { |
|
|
STR_FMT(&handler->source_pt.encoding_with_params)); |
|
|
STR_FMT(&handler->source_pt.encoding_with_params)); |
|
|
if (handler->source_pt.codec_def && handler->source_pt.codec_def->dtmf) |
|
|
if (handler->source_pt.codec_def && handler->source_pt.codec_def->dtmf) |
|
|
handler->func = handler_func_dtmf; |
|
|
handler->func = handler_func_dtmf; |
|
|
|
|
|
else if (handler->source_pt.codec_def && handler->source_pt.codec_def->supplemental) |
|
|
|
|
|
handler->func = handler_func_supplemental; |
|
|
else { |
|
|
else { |
|
|
handler->func = handler_func_passthrough; |
|
|
handler->func = handler_func_passthrough; |
|
|
handler->kernelize = 1; |
|
|
handler->kernelize = 1; |
|
|
@ -226,6 +230,8 @@ static void __make_passthrough_ssrc(struct codec_handler *handler) { |
|
|
STR_FMT(&handler->source_pt.encoding_with_params)); |
|
|
STR_FMT(&handler->source_pt.encoding_with_params)); |
|
|
if (handler->source_pt.codec_def && handler->source_pt.codec_def->dtmf) |
|
|
if (handler->source_pt.codec_def && handler->source_pt.codec_def->dtmf) |
|
|
handler->func = handler_func_dtmf; |
|
|
handler->func = handler_func_dtmf; |
|
|
|
|
|
else if (handler->source_pt.codec_def && handler->source_pt.codec_def->supplemental) |
|
|
|
|
|
handler->func = handler_func_supplemental; |
|
|
else { |
|
|
else { |
|
|
handler->func = handler_func_passthrough_ssrc; |
|
|
handler->func = handler_func_passthrough_ssrc; |
|
|
handler->kernelize = 1; |
|
|
handler->kernelize = 1; |
|
|
@ -384,8 +390,19 @@ static void __dtmf_dsp_shutdown(struct call_media *sink, int payload_type) { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void __track_supp_codec(GHashTable *supplemental_sinks, struct rtp_payload_type *pt) { |
|
|
|
|
|
if (!pt->codec_def || !pt->codec_def->supplemental) |
|
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
|
|
GHashTable *supp_sinks = g_hash_table_lookup(supplemental_sinks, pt->codec_def->rtpname); |
|
|
|
|
|
if (!supp_sinks) |
|
|
|
|
|
return; |
|
|
|
|
|
if (!g_hash_table_lookup(supp_sinks, GUINT_TO_POINTER(pt->clock_rate))) |
|
|
|
|
|
g_hash_table_insert(supp_sinks, GUINT_TO_POINTER(pt->clock_rate), pt); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
static struct rtp_payload_type *__check_dest_codecs(struct call_media *receiver, struct call_media *sink, |
|
|
static struct rtp_payload_type *__check_dest_codecs(struct call_media *receiver, struct call_media *sink, |
|
|
const struct sdp_ng_flags *flags, GHashTable *dtmf_sinks, int *sink_transcoding) |
|
|
|
|
|
|
|
|
const struct sdp_ng_flags *flags, GHashTable *supplemental_sinks, int *sink_transcoding) |
|
|
{ |
|
|
{ |
|
|
struct rtp_payload_type *pref_dest_codec = NULL; |
|
|
struct rtp_payload_type *pref_dest_codec = NULL; |
|
|
|
|
|
|
|
|
@ -416,22 +433,14 @@ static struct rtp_payload_type *__check_dest_codecs(struct call_media *receiver, |
|
|
&pt->payload_type); |
|
|
&pt->payload_type); |
|
|
if (!recv_pt || rtp_payload_type_cmp(pt, recv_pt)) { |
|
|
if (!recv_pt || rtp_payload_type_cmp(pt, recv_pt)) { |
|
|
*sink_transcoding = 1; |
|
|
*sink_transcoding = 1; |
|
|
// can the sink receive RFC DTMF but the receiver can't send it? |
|
|
|
|
|
if (pt->codec_def && pt->codec_def->dtmf) { |
|
|
|
|
|
if (!g_hash_table_lookup(dtmf_sinks, GUINT_TO_POINTER(pt->clock_rate))) |
|
|
|
|
|
g_hash_table_insert(dtmf_sinks, GUINT_TO_POINTER(pt->clock_rate), |
|
|
|
|
|
pt); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
// can the sink receive supplemental codec but the receiver can't send it? |
|
|
|
|
|
__track_supp_codec(supplemental_sinks, pt); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
else if (flags && (flags->always_transcode || flags->inject_dtmf)) { |
|
|
else if (flags && (flags->always_transcode || flags->inject_dtmf)) { |
|
|
// with always-transcode, we must keep track of potential output DTMF payload |
|
|
|
|
|
|
|
|
// with always-transcode, we must keep track of potential output supplemental payload |
|
|
// types as well |
|
|
// types as well |
|
|
if (pt->codec_def && pt->codec_def->dtmf) { |
|
|
|
|
|
if (!g_hash_table_lookup(dtmf_sinks, GUINT_TO_POINTER(pt->clock_rate))) |
|
|
|
|
|
g_hash_table_insert(dtmf_sinks, GUINT_TO_POINTER(pt->clock_rate), |
|
|
|
|
|
pt); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
__track_supp_codec(supplemental_sinks, pt); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@ -439,7 +448,7 @@ static struct rtp_payload_type *__check_dest_codecs(struct call_media *receiver, |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static void __check_send_codecs(struct call_media *receiver, struct call_media *sink, |
|
|
static void __check_send_codecs(struct call_media *receiver, struct call_media *sink, |
|
|
const struct sdp_ng_flags *flags, GHashTable *dtmf_sinks, int *sink_transcoding) |
|
|
|
|
|
|
|
|
const struct sdp_ng_flags *flags, GHashTable *supplemental_sinks, int *sink_transcoding) |
|
|
{ |
|
|
{ |
|
|
if (!MEDIA_ISSET(sink, TRANSCODE)) |
|
|
if (!MEDIA_ISSET(sink, TRANSCODE)) |
|
|
return; |
|
|
return; |
|
|
@ -450,12 +459,8 @@ static void __check_send_codecs(struct call_media *receiver, struct call_media * |
|
|
&pt->payload_type); |
|
|
&pt->payload_type); |
|
|
if (!recv_pt || rtp_payload_type_cmp(pt, recv_pt) || (flags && flags->inject_dtmf)) { |
|
|
if (!recv_pt || rtp_payload_type_cmp(pt, recv_pt) || (flags && flags->inject_dtmf)) { |
|
|
*sink_transcoding = 1; |
|
|
*sink_transcoding = 1; |
|
|
// can the sink receive RFC DTMF but the receiver can't send it? |
|
|
|
|
|
if (pt->codec_def && pt->codec_def->dtmf) { |
|
|
|
|
|
if (!g_hash_table_lookup(dtmf_sinks, GUINT_TO_POINTER(pt->clock_rate))) |
|
|
|
|
|
g_hash_table_insert(dtmf_sinks, GUINT_TO_POINTER(pt->clock_rate), |
|
|
|
|
|
pt); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
// can the sink receive supplemental codec but the receiver can't send it? |
|
|
|
|
|
__track_supp_codec(supplemental_sinks, pt); |
|
|
continue; |
|
|
continue; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@ -473,7 +478,10 @@ static void __check_send_codecs(struct call_media *receiver, struct call_media * |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static int __dtmf_payload_type(GHashTable *dtmf_sinks, struct rtp_payload_type *pref_dest_codec) { |
|
|
|
|
|
|
|
|
static int __dtmf_payload_type(GHashTable *supplemental_sinks, struct rtp_payload_type *pref_dest_codec) { |
|
|
|
|
|
GHashTable *dtmf_sinks = g_hash_table_lookup(supplemental_sinks, "telephone-event"); |
|
|
|
|
|
if (!dtmf_sinks) |
|
|
|
|
|
return -1; |
|
|
if (!g_hash_table_size(dtmf_sinks) || !pref_dest_codec) |
|
|
if (!g_hash_table_size(dtmf_sinks) || !pref_dest_codec) |
|
|
return -1; |
|
|
return -1; |
|
|
|
|
|
|
|
|
@ -986,23 +994,29 @@ void codec_handlers_update(struct call_media *receiver, struct call_media *sink, |
|
|
// that the sink specified. determine this first. |
|
|
// that the sink specified. determine this first. |
|
|
struct rtp_payload_type *pref_dest_codec = NULL; |
|
|
struct rtp_payload_type *pref_dest_codec = NULL; |
|
|
int sink_transcoding = 0; |
|
|
int sink_transcoding = 0; |
|
|
// keep track of telephone-event payload types. we hash them by clock rate |
|
|
|
|
|
|
|
|
// keep track of supplemental payload types. we hash them by clock rate |
|
|
// in case there's several of them. the clock rates of the destination |
|
|
// in case there's several of them. the clock rates of the destination |
|
|
// codec and the telephone-event codec must match. |
|
|
|
|
|
GHashTable *dtmf_sinks = g_hash_table_new(g_direct_hash, g_direct_equal); |
|
|
|
|
|
|
|
|
// codec and the supplemental codec must match. |
|
|
|
|
|
GHashTable *supplemental_sinks = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, |
|
|
|
|
|
(GDestroyNotify) g_hash_table_destroy); |
|
|
|
|
|
for (GList *l = codec_supplemental_codecs->head; l; l = l->next) { |
|
|
|
|
|
codec_def_t *def = l->data; |
|
|
|
|
|
g_hash_table_replace(supplemental_sinks, (void *) def->rtpname, |
|
|
|
|
|
g_hash_table_new(g_direct_hash, g_direct_equal)); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
pref_dest_codec = __check_dest_codecs(receiver, sink, flags, dtmf_sinks, &sink_transcoding); |
|
|
|
|
|
|
|
|
pref_dest_codec = __check_dest_codecs(receiver, sink, flags, supplemental_sinks, &sink_transcoding); |
|
|
|
|
|
|
|
|
// similarly, if the sink can receive a codec that the receiver can't send, it's also transcoding |
|
|
// similarly, if the sink can receive a codec that the receiver can't send, it's also transcoding |
|
|
__check_send_codecs(receiver, sink, flags, dtmf_sinks, &sink_transcoding); |
|
|
|
|
|
|
|
|
__check_send_codecs(receiver, sink, flags, supplemental_sinks, &sink_transcoding); |
|
|
|
|
|
|
|
|
if (flags && flags->opmode == OP_ANSWER && flags->symmetric_codecs) |
|
|
if (flags && flags->opmode == OP_ANSWER && flags->symmetric_codecs) |
|
|
__symmetric_codecs(receiver, sink, &sink_transcoding); |
|
|
__symmetric_codecs(receiver, sink, &sink_transcoding); |
|
|
|
|
|
|
|
|
ilog(LOG_DEBUG, "%i DTMF sink entries", g_hash_table_size(dtmf_sinks)); |
|
|
|
|
|
int dtmf_payload_type = __dtmf_payload_type(dtmf_sinks, pref_dest_codec); |
|
|
|
|
|
|
|
|
int dtmf_payload_type = __dtmf_payload_type(supplemental_sinks, pref_dest_codec); |
|
|
|
|
|
|
|
|
g_hash_table_destroy(dtmf_sinks); |
|
|
|
|
|
|
|
|
g_hash_table_destroy(supplemental_sinks); |
|
|
|
|
|
supplemental_sinks = NULL; |
|
|
|
|
|
|
|
|
struct rtp_payload_type *dtmf_pt = NULL; |
|
|
struct rtp_payload_type *dtmf_pt = NULL; |
|
|
struct rtp_payload_type *reverse_dtmf_pt = NULL; |
|
|
struct rtp_payload_type *reverse_dtmf_pt = NULL; |
|
|
@ -1031,7 +1045,7 @@ void codec_handlers_update(struct call_media *receiver, struct call_media *sink, |
|
|
// payload type to keep track of this. |
|
|
// payload type to keep track of this. |
|
|
GHashTable *output_transcoders = g_hash_table_new(g_direct_hash, g_direct_equal); |
|
|
GHashTable *output_transcoders = g_hash_table_new(g_direct_hash, g_direct_equal); |
|
|
|
|
|
|
|
|
int transcode_dtmf = 0; // is one of our destination codecs DTMF? |
|
|
|
|
|
|
|
|
int transcode_supplemental = 0; // is one of our source codecs a supplemental one? |
|
|
|
|
|
|
|
|
// do we need to detect PCM DTMF tones? |
|
|
// do we need to detect PCM DTMF tones? |
|
|
int pcm_dtmf_detect = 0; |
|
|
int pcm_dtmf_detect = 0; |
|
|
@ -1143,8 +1157,8 @@ unsupported: |
|
|
// the sink does not support this codec -> transcode |
|
|
// the sink does not support this codec -> transcode |
|
|
ilog(LOG_DEBUG, "Sink does not support codec " STR_FORMAT, STR_FMT(&pt->encoding_with_params)); |
|
|
ilog(LOG_DEBUG, "Sink does not support codec " STR_FORMAT, STR_FMT(&pt->encoding_with_params)); |
|
|
dest_pt = pref_dest_codec; |
|
|
dest_pt = pref_dest_codec; |
|
|
if (pt->codec_def->dtmf) |
|
|
|
|
|
transcode_dtmf = 1; |
|
|
|
|
|
|
|
|
if (pt->codec_def->supplemental) |
|
|
|
|
|
transcode_supplemental = 1; |
|
|
transcode:; |
|
|
transcode:; |
|
|
// look up the reverse side of this payload type, which is the decoder to our |
|
|
// look up the reverse side of this payload type, which is the decoder to our |
|
|
// encoder. if any codec options such as bitrate were set during an offer, |
|
|
// encoder. if any codec options such as bitrate were set during an offer, |
|
|
@ -1198,7 +1212,7 @@ next: |
|
|
// if the sink does not support DTMF but we can receive it, we must transcode |
|
|
// if the sink does not support DTMF but we can receive it, we must transcode |
|
|
// DTMF event packets to PCM. this requires all codecs to be transcoded to the |
|
|
// DTMF event packets to PCM. this requires all codecs to be transcoded to the |
|
|
// sink's preferred destination codec. |
|
|
// sink's preferred destination codec. |
|
|
if (!transcode_dtmf && dtmf_payload_type == -1) |
|
|
|
|
|
|
|
|
if (!transcode_supplemental && dtmf_payload_type == -1) |
|
|
__make_passthrough_ssrc(handler); |
|
|
__make_passthrough_ssrc(handler); |
|
|
else if (dtmf_pt && reverse_dtmf_pt) |
|
|
else if (dtmf_pt && reverse_dtmf_pt) |
|
|
__make_passthrough_ssrc(handler); |
|
|
__make_passthrough_ssrc(handler); |
|
|
@ -1602,7 +1616,10 @@ static int packet_dtmf_dup(struct codec_ssrc_handler *ch, struct transcode_packe |
|
|
return 0; |
|
|
return 0; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static int handler_func_dtmf(struct codec_handler *h, struct media_packet *mp) { |
|
|
|
|
|
|
|
|
static int __handler_func_supplemental(struct codec_handler *h, struct media_packet *mp, |
|
|
|
|
|
int (*func)(struct codec_ssrc_handler *, struct transcode_packet *, struct media_packet *), |
|
|
|
|
|
int (*dup_func)(struct codec_ssrc_handler *, struct transcode_packet *, struct media_packet *)) |
|
|
|
|
|
{ |
|
|
if (G_UNLIKELY(!mp->rtp)) |
|
|
if (G_UNLIKELY(!mp->rtp)) |
|
|
return handler_func_passthrough(h, mp); |
|
|
return handler_func_passthrough(h, mp); |
|
|
|
|
|
|
|
|
@ -1610,7 +1627,8 @@ static int handler_func_dtmf(struct codec_handler *h, struct media_packet *mp) { |
|
|
|
|
|
|
|
|
// create new packet and insert it into sequencer queue |
|
|
// create new packet and insert it into sequencer queue |
|
|
|
|
|
|
|
|
ilog(LOG_DEBUG, "Received DTMF RTP packet: SSRC %" PRIx32 ", PT %u, seq %u, TS %u, len %i", |
|
|
|
|
|
|
|
|
ilog(LOG_DEBUG, "Received %s RTP packet: SSRC %" PRIx32 ", PT %u, seq %u, TS %u, len %i", |
|
|
|
|
|
h->source_pt.codec_def->rtpname, |
|
|
ntohl(mp->rtp->ssrc), mp->rtp->m_pt, ntohs(mp->rtp->seq_num), |
|
|
ntohl(mp->rtp->ssrc), mp->rtp->m_pt, ntohs(mp->rtp->seq_num), |
|
|
ntohl(mp->rtp->timestamp), mp->payload.len); |
|
|
ntohl(mp->rtp->timestamp), mp->payload.len); |
|
|
|
|
|
|
|
|
@ -1627,14 +1645,20 @@ static int handler_func_dtmf(struct codec_handler *h, struct media_packet *mp) { |
|
|
sequencer_h = codec_handler_get(mp->media, prim_pt); |
|
|
sequencer_h = codec_handler_get(mp->media, prim_pt); |
|
|
if (sequencer_h == h) |
|
|
if (sequencer_h == h) |
|
|
continue; |
|
|
continue; |
|
|
ilog(LOG_DEBUG, "Primary RTP payload type for handling DTMF event is %i", prim_pt); |
|
|
|
|
|
|
|
|
if (sequencer_h->source_pt.codec_def && sequencer_h->source_pt.codec_def->supplemental) |
|
|
|
|
|
continue; |
|
|
|
|
|
ilog(LOG_DEBUG, "Primary RTP payload type for handling %s is %i", |
|
|
|
|
|
h->source_pt.codec_def->rtpname, |
|
|
|
|
|
prim_pt); |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// XXX ? h->output_handler = sequencer_h->output_handler; // XXX locking? |
|
|
|
|
|
|
|
|
struct transcode_packet *packet = g_slice_alloc0(sizeof(*packet)); |
|
|
struct transcode_packet *packet = g_slice_alloc0(sizeof(*packet)); |
|
|
packet->func = packet_dtmf; |
|
|
|
|
|
packet->dup_func = packet_dtmf_dup; |
|
|
|
|
|
|
|
|
packet->func = func; |
|
|
|
|
|
packet->dup_func = dup_func; |
|
|
packet->handler = h; |
|
|
packet->handler = h; |
|
|
packet->rtp = *mp->rtp; |
|
|
packet->rtp = *mp->rtp; |
|
|
|
|
|
|
|
|
@ -1647,6 +1671,12 @@ static int handler_func_dtmf(struct codec_handler *h, struct media_packet *mp) { |
|
|
|
|
|
|
|
|
return __handler_func_sequencer(mp, packet); |
|
|
return __handler_func_sequencer(mp, packet); |
|
|
} |
|
|
} |
|
|
|
|
|
static int handler_func_supplemental(struct codec_handler *h, struct media_packet *mp) { |
|
|
|
|
|
return __handler_func_supplemental(h, mp, packet_decode, NULL); |
|
|
|
|
|
} |
|
|
|
|
|
static int handler_func_dtmf(struct codec_handler *h, struct media_packet *mp) { |
|
|
|
|
|
return __handler_func_supplemental(h, mp, packet_dtmf, packet_dtmf_dup); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
static int handler_func_t38(struct codec_handler *h, struct media_packet *mp) { |
|
|
static int handler_func_t38(struct codec_handler *h, struct media_packet *mp) { |
|
|
if (!mp->media) |
|
|
if (!mp->media) |
|
|
|