|
|
|
@ -425,6 +425,7 @@ static struct rtp_payload_type *__check_dest_codecs(struct call_media *receiver,
|
|
|
|
const struct sdp_ng_flags *flags, GHashTable *supplemental_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;
|
|
|
|
|
|
|
|
struct rtp_payload_type *first_tc_codec = NULL;
|
|
|
|
|
|
|
|
|
|
|
|
for (GList *l = sink->codecs_prefs_send.head; l; l = l->next) {
|
|
|
|
for (GList *l = sink->codecs_prefs_send.head; l; l = l->next) {
|
|
|
|
struct rtp_payload_type *pt = l->data;
|
|
|
|
struct rtp_payload_type *pt = l->data;
|
|
|
|
@ -438,28 +439,53 @@ static struct rtp_payload_type *__check_dest_codecs(struct call_media *receiver,
|
|
|
|
if (sink->ptime)
|
|
|
|
if (sink->ptime)
|
|
|
|
pt->ptime = sink->ptime;
|
|
|
|
pt->ptime = sink->ptime;
|
|
|
|
|
|
|
|
|
|
|
|
if (!pref_dest_codec && !pt->codec_def->supplemental) {
|
|
|
|
if (!pref_dest_codec && !pt->codec_def->supplemental)
|
|
|
|
ilog(LOG_DEBUG, "Default sink codec is " STR_FORMAT, STR_FMT(&pt->encoding_with_params));
|
|
|
|
|
|
|
|
pref_dest_codec = pt;
|
|
|
|
pref_dest_codec = pt;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// also check if this is a transcoding codec: if we can send a codec to the sink,
|
|
|
|
// also check if this is a transcoding codec: if we can send a codec to the sink,
|
|
|
|
// but can't receive it on the receiver side, then it's transcoding. this is to check
|
|
|
|
// but can't receive it on the receiver side, then it's transcoding. this is to check
|
|
|
|
// whether transcoding on the sink side is actually needed. if transcoding has been
|
|
|
|
// whether transcoding on the sink side is actually needed. if transcoding has been
|
|
|
|
// previously enabled on the sink, but no transcoding codecs are actually present,
|
|
|
|
// previously enabled on the sink, but no transcoding codecs are actually present,
|
|
|
|
// we can disable the transcoding engine.
|
|
|
|
// we can disable the transcoding engine.
|
|
|
|
if (MEDIA_ISSET(sink, TRANSCODE)) {
|
|
|
|
|
|
|
|
struct rtp_payload_type *recv_pt = g_hash_table_lookup(receiver->codecs_send,
|
|
|
|
struct rtp_payload_type *recv_pt = g_hash_table_lookup(receiver->codecs_send,
|
|
|
|
&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))
|
|
|
|
// can the sink receive supplemental codec but the receiver can't send it?
|
|
|
|
recv_pt = NULL;
|
|
|
|
|
|
|
|
//ilog(LOG_DEBUG, "XXXXXXXXXXXX old flag is %i", *sink_transcoding);
|
|
|
|
|
|
|
|
//ilog(LOG_DEBUG, "XXXXXXXXXXXX checking dest codec " STR_FORMAT " is %i",
|
|
|
|
|
|
|
|
//STR_FMT(&pt->encoding_with_params),
|
|
|
|
|
|
|
|
//pt->for_transcoding);
|
|
|
|
|
|
|
|
//if (recv_pt)
|
|
|
|
|
|
|
|
//ilog(LOG_DEBUG, "XXXXXXXXXXXX checking dest codec reverse " STR_FORMAT " is %i",
|
|
|
|
|
|
|
|
//STR_FMT(&recv_pt->encoding_with_params),
|
|
|
|
|
|
|
|
//recv_pt->for_transcoding);
|
|
|
|
|
|
|
|
if (MEDIA_ISSET(sink, TRANSCODE)) {
|
|
|
|
|
|
|
|
if (!recv_pt) {
|
|
|
|
|
|
|
|
// can the sink receive codec but the receiver can't send it?
|
|
|
|
*sink_transcoding |= 0x3;
|
|
|
|
*sink_transcoding |= 0x3;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pt->for_transcoding) {
|
|
|
|
|
|
|
|
// codec is explicitly marked for transcoding. enable transcoding engine
|
|
|
|
|
|
|
|
MEDIA_SET(receiver, TRANSCODE);
|
|
|
|
|
|
|
|
*sink_transcoding |= 0x3;
|
|
|
|
|
|
|
|
if (!first_tc_codec && !pt->codec_def->supplemental)
|
|
|
|
|
|
|
|
first_tc_codec = pt;
|
|
|
|
|
|
|
|
if (pt->codec_def->supplemental)
|
|
|
|
|
|
|
|
*sink_transcoding |= 0x4;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
//ilog(LOG_DEBUG, "XXXXXXXXXXXX new flag is %i", *sink_transcoding);
|
|
|
|
|
|
|
|
|
|
|
|
__track_supp_codec(supplemental_sinks, pt);
|
|
|
|
__track_supp_codec(supplemental_sinks, pt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (first_tc_codec)
|
|
|
|
|
|
|
|
pref_dest_codec = first_tc_codec;
|
|
|
|
|
|
|
|
if (pref_dest_codec)
|
|
|
|
|
|
|
|
ilog(LOG_DEBUG, "Default sink codec is " STR_FORMAT,
|
|
|
|
|
|
|
|
STR_FMT(&pref_dest_codec->encoding_with_params));
|
|
|
|
|
|
|
|
|
|
|
|
return pref_dest_codec;
|
|
|
|
return pref_dest_codec;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@ -474,10 +500,21 @@ static void __check_send_codecs(struct call_media *receiver, struct call_media *
|
|
|
|
struct rtp_payload_type *recv_pt = g_hash_table_lookup(receiver->codecs_send,
|
|
|
|
struct rtp_payload_type *recv_pt = g_hash_table_lookup(receiver->codecs_send,
|
|
|
|
&pt->payload_type);
|
|
|
|
&pt->payload_type);
|
|
|
|
int tc_flag = 0;
|
|
|
|
int tc_flag = 0;
|
|
|
|
|
|
|
|
//ilog(LOG_DEBUG, "XXXXXXXXXXXX old flag is %i", *sink_transcoding);
|
|
|
|
|
|
|
|
//ilog(LOG_DEBUG, "XXXXXXXXXXXX checking send codec " STR_FORMAT " is %i",
|
|
|
|
|
|
|
|
//STR_FMT(&pt->encoding_with_params),
|
|
|
|
|
|
|
|
//pt->for_transcoding);
|
|
|
|
|
|
|
|
//if (recv_pt)
|
|
|
|
|
|
|
|
//ilog(LOG_DEBUG, "XXXXXXXXXXXX checking send codec reverse " STR_FORMAT " is %i",
|
|
|
|
|
|
|
|
//STR_FMT(&recv_pt->encoding_with_params),
|
|
|
|
|
|
|
|
//recv_pt->for_transcoding);
|
|
|
|
if (!recv_pt || rtp_payload_type_cmp(pt, recv_pt))
|
|
|
|
if (!recv_pt || rtp_payload_type_cmp(pt, recv_pt))
|
|
|
|
tc_flag |= 0x3;
|
|
|
|
tc_flag |= 0x3;
|
|
|
|
if (flags && flags->inject_dtmf)
|
|
|
|
if (flags && flags->inject_dtmf)
|
|
|
|
tc_flag |= 0x1;
|
|
|
|
tc_flag |= 0x1;
|
|
|
|
|
|
|
|
if (pt->for_transcoding)
|
|
|
|
|
|
|
|
tc_flag |= 0x3;
|
|
|
|
|
|
|
|
//ilog(LOG_DEBUG, "XXXXXXXXXXXX set flag is %i", *sink_transcoding);
|
|
|
|
if (tc_flag) {
|
|
|
|
if (tc_flag) {
|
|
|
|
// can the sink receive codec but the receiver can't send it?
|
|
|
|
// can the sink receive codec but the receiver can't send it?
|
|
|
|
*sink_transcoding |= tc_flag;
|
|
|
|
*sink_transcoding |= tc_flag;
|
|
|
|
@ -491,6 +528,7 @@ static void __check_send_codecs(struct call_media *receiver, struct call_media *
|
|
|
|
g_hash_table_lookup(sink->codec_handlers, GINT_TO_POINTER(recv_pt->payload_type));
|
|
|
|
g_hash_table_lookup(sink->codec_handlers, GINT_TO_POINTER(recv_pt->payload_type));
|
|
|
|
if (!ch_recv)
|
|
|
|
if (!ch_recv)
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
|
|
|
|
|
//ilog(LOG_DEBUG, "XXXXXXXXXXXX handler transcoder %i", ch_recv->transcoder);
|
|
|
|
if (ch_recv->transcoder)
|
|
|
|
if (ch_recv->transcoder)
|
|
|
|
*sink_transcoding |= 0x3;
|
|
|
|
*sink_transcoding |= 0x3;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@ -591,8 +629,28 @@ static void __single_codec(struct call_media *media, const struct sdp_ng_flags *
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int __check_receiver_codecs(struct call_media *receiver) {
|
|
|
|
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
// if some codecs were explicitly marked for transcoding, then we accept only those.
|
|
|
|
|
|
|
|
// otherwise we accept all that we can.
|
|
|
|
|
|
|
|
for (GList *l = receiver->codecs_prefs_send.head; l; l = l->next) {
|
|
|
|
|
|
|
|
struct rtp_payload_type *pt = l->data;
|
|
|
|
|
|
|
|
ensure_codec_def(pt, receiver);
|
|
|
|
|
|
|
|
if (!pt->codec_def)
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
//ilog(LOG_DEBUG, "XXXXXXXXXXXX checking recv send " STR_FORMAT " %i %i", STR_FMT(&pt->encoding_with_params), pt->for_transcoding, pt->codec_def->supplemental);
|
|
|
|
|
|
|
|
if (pt->for_transcoding) {
|
|
|
|
|
|
|
|
if (pt->codec_def->supplemental)
|
|
|
|
|
|
|
|
ret |= 0x2 | 0x4;
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
ret |= 0x1 | 0x2;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void __accept_transcode_codecs(struct call_media *receiver, struct call_media *sink,
|
|
|
|
static void __accept_transcode_codecs(struct call_media *receiver, struct call_media *sink,
|
|
|
|
const struct sdp_ng_flags *flags)
|
|
|
|
const struct sdp_ng_flags *flags, int accept_only_tc)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
// if the other side is transcoding, we need to accept codecs that were
|
|
|
|
// if the other side is transcoding, we need to accept codecs that were
|
|
|
|
// originally offered (recv->send) if we support them, even if the
|
|
|
|
// originally offered (recv->send) if we support them, even if the
|
|
|
|
@ -603,6 +661,9 @@ static void __accept_transcode_codecs(struct call_media *receiver, struct call_m
|
|
|
|
ensure_codec_def(pt, receiver);
|
|
|
|
ensure_codec_def(pt, receiver);
|
|
|
|
if (!pt->codec_def)
|
|
|
|
if (!pt->codec_def)
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (accept_only_tc && !pt->for_transcoding)
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
//ilog(LOG_DEBUG, "XXXXXXXXXXX accept codec " STR_FORMAT " flag %i", STR_FMT(&pt->encoding_with_params), pt->for_transcoding);
|
|
|
|
struct rtp_payload_type *existing_pt
|
|
|
|
struct rtp_payload_type *existing_pt
|
|
|
|
= g_hash_table_lookup(receiver->codecs_recv, &pt->payload_type);
|
|
|
|
= g_hash_table_lookup(receiver->codecs_recv, &pt->payload_type);
|
|
|
|
if (existing_pt && !rtp_payload_type_cmp_nf(existing_pt, pt)) {
|
|
|
|
if (existing_pt && !rtp_payload_type_cmp_nf(existing_pt, pt)) {
|
|
|
|
@ -645,6 +706,7 @@ static void __accept_transcode_codecs(struct call_media *receiver, struct call_m
|
|
|
|
g_hash_table_insert(receiver->codecs_recv, &existing_pt->payload_type, existing_pt);
|
|
|
|
g_hash_table_insert(receiver->codecs_recv, &existing_pt->payload_type, existing_pt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//ilog(LOG_DEBUG, "XXXXXXXXXXXXX offered codec %i", pt->for_transcoding);
|
|
|
|
ilog(LOG_DEBUG, "Accepting offered codec " STR_FORMAT " due to transcoding",
|
|
|
|
ilog(LOG_DEBUG, "Accepting offered codec " STR_FORMAT " due to transcoding",
|
|
|
|
STR_FMT(&pt->encoding_with_params));
|
|
|
|
STR_FMT(&pt->encoding_with_params));
|
|
|
|
MEDIA_SET(receiver, TRANSCODE);
|
|
|
|
MEDIA_SET(receiver, TRANSCODE);
|
|
|
|
@ -734,6 +796,7 @@ static GHashTable *__payload_type_queue_hash(GQueue *prefs, GQueue *order) {
|
|
|
|
static void __symmetric_codecs(struct call_media *receiver, struct call_media *sink,
|
|
|
|
static void __symmetric_codecs(struct call_media *receiver, struct call_media *sink,
|
|
|
|
int *sink_transcoding)
|
|
|
|
int *sink_transcoding)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
|
|
|
|
//ilog(LOG_DEBUG, "XXXXXXXXXXXXXXX symm codec flags %i %i", MEDIA_ISSET(sink, TRANSCODE), *sink_transcoding);
|
|
|
|
if (!MEDIA_ISSET(sink, TRANSCODE))
|
|
|
|
if (!MEDIA_ISSET(sink, TRANSCODE))
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
if (!*sink_transcoding)
|
|
|
|
if (!*sink_transcoding)
|
|
|
|
@ -755,12 +818,52 @@ static void __symmetric_codecs(struct call_media *receiver, struct call_media *s
|
|
|
|
// reconstruct list based on other side's preference.
|
|
|
|
// reconstruct list based on other side's preference.
|
|
|
|
int transcoding = 0;
|
|
|
|
int transcoding = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// keep track of our reconstruction order. there might be some codecs that have been force accepted
|
|
|
|
|
|
|
|
// that aren't present in sink->codecs_prefs_send. we must add them our output (receiver->send/recv)
|
|
|
|
|
|
|
|
// in order.
|
|
|
|
|
|
|
|
GList *prefix_pt_pos = prefs_send_order.head;
|
|
|
|
|
|
|
|
|
|
|
|
for (GList *l = sink->codecs_prefs_send.head; l; l = l->next) {
|
|
|
|
for (GList *l = sink->codecs_prefs_send.head; l; l = l->next) {
|
|
|
|
struct rtp_payload_type *pt = l->data;
|
|
|
|
struct rtp_payload_type *pt = l->data;
|
|
|
|
|
|
|
|
//ilog(LOG_DEBUG, "XXXXXXXXXXXXXXXX symm codec check " STR_FORMAT, STR_FMT(&pt->encoding_with_params));
|
|
|
|
// do we have a matching output?
|
|
|
|
// do we have a matching output?
|
|
|
|
struct rtp_payload_type *out_pt = g_hash_table_lookup(prefs_recv,
|
|
|
|
struct rtp_payload_type *out_pt = g_hash_table_lookup(prefs_recv,
|
|
|
|
GINT_TO_POINTER(pt->payload_type));
|
|
|
|
GINT_TO_POINTER(pt->payload_type));
|
|
|
|
if (out_pt && g_hash_table_lookup(prefs_send, GINT_TO_POINTER(pt->payload_type))) {
|
|
|
|
struct rtp_payload_type *send_pt;
|
|
|
|
|
|
|
|
if (!out_pt || !(send_pt = g_hash_table_lookup(prefs_send, GINT_TO_POINTER(pt->payload_type)))) {
|
|
|
|
|
|
|
|
// we must transcode after all.
|
|
|
|
|
|
|
|
ilog(LOG_DEBUG, "RTP payload type %i is not symmetric and must be transcoded",
|
|
|
|
|
|
|
|
pt->payload_type);
|
|
|
|
|
|
|
|
transcoding = 1;
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// seek forward in our prefix list and check any PTs to see if they're force accepted
|
|
|
|
|
|
|
|
while (prefix_pt_pos) {
|
|
|
|
|
|
|
|
void *ptype = prefix_pt_pos->data;
|
|
|
|
|
|
|
|
struct rtp_payload_type *prefix_pt = g_hash_table_lookup(prefs_send, ptype);
|
|
|
|
|
|
|
|
prefix_pt_pos = prefix_pt_pos->next;
|
|
|
|
|
|
|
|
if (!prefix_pt)
|
|
|
|
|
|
|
|
continue; // bug?
|
|
|
|
|
|
|
|
if (prefix_pt == send_pt)
|
|
|
|
|
|
|
|
break; // caught up
|
|
|
|
|
|
|
|
//ilog(LOG_DEBUG, "XXXXXXXXXXXXXXXX prefix codec check " STR_FORMAT " %i", STR_FMT(&prefix_pt->encoding_with_params), prefix_pt->for_transcoding);
|
|
|
|
|
|
|
|
if (!prefix_pt->for_transcoding)
|
|
|
|
|
|
|
|
continue; // not interesting
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// add it to the list
|
|
|
|
|
|
|
|
ilog(LOG_DEBUG, "Adding force-accepted RTP payload type %i", prefix_pt->payload_type);
|
|
|
|
|
|
|
|
g_hash_table_steal(prefs_send, ptype);
|
|
|
|
|
|
|
|
__rtp_payload_type_add_send(receiver, prefix_pt);
|
|
|
|
|
|
|
|
// and our receive leg
|
|
|
|
|
|
|
|
struct rtp_payload_type *in_pt = g_hash_table_lookup(prefs_recv, ptype);
|
|
|
|
|
|
|
|
if (in_pt) {
|
|
|
|
|
|
|
|
g_hash_table_steal(prefs_recv, ptype);
|
|
|
|
|
|
|
|
__rtp_payload_type_add_recv(receiver, in_pt, 1);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
transcoding = 1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// add it to the list
|
|
|
|
// add it to the list
|
|
|
|
ilog(LOG_DEBUG, "Adding symmetric RTP payload type %i", pt->payload_type);
|
|
|
|
ilog(LOG_DEBUG, "Adding symmetric RTP payload type %i", pt->payload_type);
|
|
|
|
g_hash_table_steal(prefs_recv, GINT_TO_POINTER(pt->payload_type));
|
|
|
|
g_hash_table_steal(prefs_recv, GINT_TO_POINTER(pt->payload_type));
|
|
|
|
@ -771,12 +874,6 @@ static void __symmetric_codecs(struct call_media *receiver, struct call_media *s
|
|
|
|
g_hash_table_steal(prefs_send, GINT_TO_POINTER(pt->payload_type));
|
|
|
|
g_hash_table_steal(prefs_send, GINT_TO_POINTER(pt->payload_type));
|
|
|
|
__rtp_payload_type_add_send(receiver, out_pt);
|
|
|
|
__rtp_payload_type_add_send(receiver, out_pt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// we must transcode after all.
|
|
|
|
|
|
|
|
ilog(LOG_DEBUG, "RTP payload type %i is not symmetric and must be transcoded",
|
|
|
|
|
|
|
|
pt->payload_type);
|
|
|
|
|
|
|
|
transcoding = 1;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!transcoding)
|
|
|
|
if (!transcoding)
|
|
|
|
@ -1084,6 +1181,7 @@ int __supp_codec_match(struct call_media *receiver, struct call_media *sink, int
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (pt == -1)
|
|
|
|
if (pt == -1)
|
|
|
|
return 0;
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
//ilog(LOG_DEBUG, "XXXXXXXXX checking supp PT match %i", pt);
|
|
|
|
|
|
|
|
|
|
|
|
struct rtp_payload_type *sink_pt_stor = NULL;
|
|
|
|
struct rtp_payload_type *sink_pt_stor = NULL;
|
|
|
|
struct rtp_payload_type *recv_pt_stor = NULL;
|
|
|
|
struct rtp_payload_type *recv_pt_stor = NULL;
|
|
|
|
@ -1096,12 +1194,15 @@ int __supp_codec_match(struct call_media *receiver, struct call_media *sink, int
|
|
|
|
*sink_pt = g_hash_table_lookup(sink->codecs_send, &pt);
|
|
|
|
*sink_pt = g_hash_table_lookup(sink->codecs_send, &pt);
|
|
|
|
if (!*sink_pt)
|
|
|
|
if (!*sink_pt)
|
|
|
|
return 0;
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
//ilog(LOG_DEBUG, "XXXXXXXXX sink has supp PT %i", pt);
|
|
|
|
// XXX should go by codec name/params, not payload type number
|
|
|
|
// XXX should go by codec name/params, not payload type number
|
|
|
|
*recv_pt = g_hash_table_lookup(receiver->codecs_recv, &pt);
|
|
|
|
*recv_pt = g_hash_table_lookup(receiver->codecs_recv, &pt);
|
|
|
|
if (!*recv_pt)
|
|
|
|
if (!*recv_pt)
|
|
|
|
return 1;
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
//ilog(LOG_DEBUG, "XXXXXXXXX recv has supp PT %i", pt);
|
|
|
|
if (rtp_payload_type_cmp(*sink_pt, *recv_pt))
|
|
|
|
if (rtp_payload_type_cmp(*sink_pt, *recv_pt))
|
|
|
|
return 1;
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
//ilog(LOG_DEBUG, "XXXXXXXXX recv has matching supp PT %i", pt);
|
|
|
|
return 2;
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@ -1148,7 +1249,11 @@ void codec_handlers_update(struct call_media *receiver, struct call_media *sink,
|
|
|
|
// if we transcode, we transcode to the highest-preference supported codec
|
|
|
|
// if we transcode, we transcode to the highest-preference supported codec
|
|
|
|
// 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; // 0x1 = any transcoder present, 0x2 = non pseudo transcoder present
|
|
|
|
|
|
|
|
|
|
|
|
// 0x1 = any transcoder present, 0x2 = non pseudo transcoder present,
|
|
|
|
|
|
|
|
// 0x4 = supplemental codec for transcoding
|
|
|
|
|
|
|
|
int sink_transcoding = 0;
|
|
|
|
|
|
|
|
|
|
|
|
// keep track of supplemental 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 supplemental codec must match.
|
|
|
|
// codec and the supplemental codec must match.
|
|
|
|
@ -1165,6 +1270,10 @@ void codec_handlers_update(struct call_media *receiver, struct call_media *sink,
|
|
|
|
// 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, supplemental_sinks, &sink_transcoding);
|
|
|
|
__check_send_codecs(receiver, sink, flags, supplemental_sinks, &sink_transcoding);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 0x1 = accept only codecs marked for transcoding, 0x2 = some codecs marked for transcoding
|
|
|
|
|
|
|
|
// present, 0x4 = supplemental codec for transcoding
|
|
|
|
|
|
|
|
int receiver_transcoding = __check_receiver_codecs(receiver);
|
|
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
|
|
@ -1180,13 +1289,13 @@ void codec_handlers_update(struct call_media *receiver, struct call_media *sink,
|
|
|
|
int cn_pt_match = __supp_codec_match(receiver, sink, cn_payload_type, NULL, NULL);
|
|
|
|
int cn_pt_match = __supp_codec_match(receiver, sink, cn_payload_type, NULL, NULL);
|
|
|
|
|
|
|
|
|
|
|
|
// stop transcoding if we've determined that we don't need it
|
|
|
|
// stop transcoding if we've determined that we don't need it
|
|
|
|
if (MEDIA_ISSET(sink, TRANSCODE) && !sink_transcoding) {
|
|
|
|
if (MEDIA_ISSET(sink, TRANSCODE) && !sink_transcoding && !(receiver_transcoding & 0x2)) {
|
|
|
|
ilog(LOG_DEBUG, "Disabling transcoding engine (not needed)");
|
|
|
|
ilog(LOG_DEBUG, "Disabling transcoding engine (not needed)");
|
|
|
|
MEDIA_CLEAR(sink, TRANSCODE);
|
|
|
|
MEDIA_CLEAR(sink, TRANSCODE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (MEDIA_ISSET(sink, TRANSCODE) && (sink_transcoding & 0x2))
|
|
|
|
if (MEDIA_ISSET(sink, TRANSCODE) && (sink_transcoding & 0x2))
|
|
|
|
__accept_transcode_codecs(receiver, sink, flags);
|
|
|
|
__accept_transcode_codecs(receiver, sink, flags, (receiver_transcoding & 0x1));
|
|
|
|
else
|
|
|
|
else
|
|
|
|
__eliminate_rejected_codecs(receiver, sink, flags);
|
|
|
|
__eliminate_rejected_codecs(receiver, sink, flags);
|
|
|
|
|
|
|
|
|
|
|
|
@ -1196,6 +1305,8 @@ void codec_handlers_update(struct call_media *receiver, struct call_media *sink,
|
|
|
|
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_supplemental = 0; // is one of our source codecs a supplemental one?
|
|
|
|
int transcode_supplemental = 0; // is one of our source codecs a supplemental one?
|
|
|
|
|
|
|
|
if ((sink_transcoding & 0x4))
|
|
|
|
|
|
|
|
transcode_supplemental = 1;
|
|
|
|
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
@ -1245,10 +1356,19 @@ void codec_handlers_update(struct call_media *receiver, struct call_media *sink,
|
|
|
|
goto next;
|
|
|
|
goto next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//ilog(LOG_DEBUG, "XXXXXXXXXXXX pref dest codec " STR_FORMAT " is %i",
|
|
|
|
|
|
|
|
//STR_FMT(&pref_dest_codec->encoding_with_params),
|
|
|
|
|
|
|
|
//pref_dest_codec->for_transcoding);
|
|
|
|
|
|
|
|
|
|
|
|
struct rtp_payload_type *dest_pt; // transcode to this
|
|
|
|
struct rtp_payload_type *dest_pt; // transcode to this
|
|
|
|
|
|
|
|
|
|
|
|
GQueue *dest_codecs = NULL;
|
|
|
|
GQueue *dest_codecs = NULL;
|
|
|
|
if (!flags || !flags->always_transcode) {
|
|
|
|
if (pref_dest_codec->for_transcoding) {
|
|
|
|
|
|
|
|
// with always-transcode, we still accept DTMF payloads if possible
|
|
|
|
|
|
|
|
if (pt->codec_def && pt->codec_def->supplemental)
|
|
|
|
|
|
|
|
dest_codecs = g_hash_table_lookup(sink->codec_names_send, &pt->encoding);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (!flags || !flags->always_transcode) {
|
|
|
|
// we ignore output codec matches if we must transcode supp codecs
|
|
|
|
// we ignore output codec matches if we must transcode supp codecs
|
|
|
|
if ((dtmf_pt_match == 1 || cn_pt_match == 1) && MEDIA_ISSET(sink, TRANSCODE))
|
|
|
|
if ((dtmf_pt_match == 1 || cn_pt_match == 1) && MEDIA_ISSET(sink, TRANSCODE))
|
|
|
|
;
|
|
|
|
;
|
|
|
|
@ -1374,6 +1494,12 @@ 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.
|
|
|
|
|
|
|
|
//ilog(LOG_DEBUG, "XXXXXXXXXXXXX tc supp %i DTMF PT %i DTMF PT match %i PCM detect %i",
|
|
|
|
|
|
|
|
//transcode_supplemental, dtmf_payload_type, dtmf_pt_match, pcm_dtmf_detect);
|
|
|
|
|
|
|
|
//ilog(LOG_DEBUG, "XXXXXXXXXXXXX tc supp %i CN PT %i CN PT match %i",
|
|
|
|
|
|
|
|
//transcode_supplemental, cn_payload_type, cn_pt_match);
|
|
|
|
|
|
|
|
//ilog(LOG_DEBUG, "XXXXXXXXXXXXX %p %p %p",
|
|
|
|
|
|
|
|
//pref_dest_codec, handler->source_pt.codec_def, pref_dest_codec->codec_def);
|
|
|
|
if (!transcode_supplemental && !pcm_dtmf_detect)
|
|
|
|
if (!transcode_supplemental && !pcm_dtmf_detect)
|
|
|
|
__make_passthrough_ssrc(handler);
|
|
|
|
__make_passthrough_ssrc(handler);
|
|
|
|
else if (dtmf_pt_match == 2)
|
|
|
|
else if (dtmf_pt_match == 2)
|
|
|
|
@ -1381,9 +1507,11 @@ next:
|
|
|
|
else if (!pref_dest_codec
|
|
|
|
else if (!pref_dest_codec
|
|
|
|
|| !handler->source_pt.codec_def || !pref_dest_codec->codec_def)
|
|
|
|
|| !handler->source_pt.codec_def || !pref_dest_codec->codec_def)
|
|
|
|
__make_passthrough_ssrc(handler);
|
|
|
|
__make_passthrough_ssrc(handler);
|
|
|
|
else
|
|
|
|
else {
|
|
|
|
__make_transcoder(handler, pref_dest_codec, output_transcoders,
|
|
|
|
__make_transcoder(handler, pref_dest_codec, output_transcoders,
|
|
|
|
dtmf_payload_type, pcm_dtmf_detect);
|
|
|
|
dtmf_payload_type, pcm_dtmf_detect);
|
|
|
|
|
|
|
|
handler->cn_payload_type = cn_payload_type;
|
|
|
|
|
|
|
|
}
|
|
|
|
passthrough_handlers = g_slist_delete_link(passthrough_handlers, passthrough_handlers);
|
|
|
|
passthrough_handlers = g_slist_delete_link(passthrough_handlers, passthrough_handlers);
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@ -2227,6 +2355,7 @@ static void __silence_detect_ ## type(struct codec_ssrc_handler *ch, AVFrame *fr
|
|
|
|
last = NULL; \
|
|
|
|
last = NULL; \
|
|
|
|
\
|
|
|
|
\
|
|
|
|
for (unsigned int i = 0; i < frame->nb_samples; i++) { \
|
|
|
|
for (unsigned int i = 0; i < frame->nb_samples; i++) { \
|
|
|
|
|
|
|
|
/* ilog(LOG_DEBUG, "XXXXXXXXXXXX checking %u %i vs %i", i, (int) s[i], (int) thres); */ \
|
|
|
|
if (s[i] <= thres && s[1] >= -thres) { \
|
|
|
|
if (s[i] <= thres && s[1] >= -thres) { \
|
|
|
|
/* silence */ \
|
|
|
|
/* silence */ \
|
|
|
|
if (!last) { \
|
|
|
|
if (!last) { \
|
|
|
|
@ -2253,6 +2382,7 @@ __silence_detect_type(int32_t)
|
|
|
|
__silence_detect_type(int16_t)
|
|
|
|
__silence_detect_type(int16_t)
|
|
|
|
|
|
|
|
|
|
|
|
static void __silence_detect(struct codec_ssrc_handler *ch, AVFrame *frame) {
|
|
|
|
static void __silence_detect(struct codec_ssrc_handler *ch, AVFrame *frame) {
|
|
|
|
|
|
|
|
//ilog(LOG_DEBUG, "XXXXXXXXXXXXXXXXXXXX silence detect %i %i", rtpe_config.silence_detect_int, ch->handler->cn_payload_type);
|
|
|
|
if (!rtpe_config.silence_detect_int)
|
|
|
|
if (!rtpe_config.silence_detect_int)
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
if (ch->handler->cn_payload_type < 0)
|
|
|
|
if (ch->handler->cn_payload_type < 0)
|
|
|
|
@ -3120,7 +3250,7 @@ int __codec_ht_except(int all_flag, GHashTable *yes_ht, GHashTable *no_ht, struc
|
|
|
|
else if (g_hash_table_lookup(yes_ht, &pt->encoding_with_params))
|
|
|
|
else if (g_hash_table_lookup(yes_ht, &pt->encoding_with_params))
|
|
|
|
do_this = 1;
|
|
|
|
do_this = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (no_ht) {
|
|
|
|
if (no_ht && all_flag) {
|
|
|
|
if (g_hash_table_lookup(no_ht, &pt->encoding))
|
|
|
|
if (g_hash_table_lookup(no_ht, &pt->encoding))
|
|
|
|
do_this = 0;
|
|
|
|
do_this = 0;
|
|
|
|
else if (g_hash_table_lookup(no_ht, &pt->encoding_with_params))
|
|
|
|
else if (g_hash_table_lookup(no_ht, &pt->encoding_with_params))
|
|
|
|
@ -3128,6 +3258,19 @@ int __codec_ht_except(int all_flag, GHashTable *yes_ht, GHashTable *no_ht, struc
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return do_this;
|
|
|
|
return do_this;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void __ht_merge(GHashTable **dst, GHashTable *src) {
|
|
|
|
|
|
|
|
if (!src)
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!*dst)
|
|
|
|
|
|
|
|
*dst = g_hash_table_new_full(str_case_hash, str_case_equal, free, NULL);
|
|
|
|
|
|
|
|
GHashTableIter iter;
|
|
|
|
|
|
|
|
g_hash_table_iter_init(&iter, src);
|
|
|
|
|
|
|
|
void *key;
|
|
|
|
|
|
|
|
while (g_hash_table_iter_next(&iter, &key, NULL)) {
|
|
|
|
|
|
|
|
str *dup = str_dup(key);
|
|
|
|
|
|
|
|
g_hash_table_replace(*dst, dup, dup);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
void codec_rtp_payload_types(struct call_media *media, struct call_media *other_media,
|
|
|
|
void codec_rtp_payload_types(struct call_media *media, struct call_media *other_media,
|
|
|
|
GQueue *types, struct sdp_ng_flags *flags)
|
|
|
|
GQueue *types, struct sdp_ng_flags *flags)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
@ -3141,7 +3284,7 @@ void codec_rtp_payload_types(struct call_media *media, struct call_media *other_
|
|
|
|
static const str str_full = STR_CONST_INIT("full");
|
|
|
|
static const str str_full = STR_CONST_INIT("full");
|
|
|
|
GHashTable *stripped = g_hash_table_new_full(str_case_hash, str_case_equal, free, __payload_queue_free);
|
|
|
|
GHashTable *stripped = g_hash_table_new_full(str_case_hash, str_case_equal, free, __payload_queue_free);
|
|
|
|
GHashTable *masked = g_hash_table_new_full(str_case_hash, str_case_equal, free, __payload_queue_free);
|
|
|
|
GHashTable *masked = g_hash_table_new_full(str_case_hash, str_case_equal, free, __payload_queue_free);
|
|
|
|
int strip_all = 0, mask_all = 0;
|
|
|
|
int strip_all = 0, mask_all = 0, consume_all = 0;
|
|
|
|
|
|
|
|
|
|
|
|
// start fresh
|
|
|
|
// start fresh
|
|
|
|
if (!proto_is_rtp(other_media->protocol) && proto_is_rtp(media->protocol) && flags->opmode == OP_OFFER) {
|
|
|
|
if (!proto_is_rtp(other_media->protocol) && proto_is_rtp(media->protocol) && flags->opmode == OP_OFFER) {
|
|
|
|
@ -3164,12 +3307,21 @@ void codec_rtp_payload_types(struct call_media *media, struct call_media *other_
|
|
|
|
|
|
|
|
|
|
|
|
if (flags->codec_strip && g_hash_table_lookup(flags->codec_strip, &str_all))
|
|
|
|
if (flags->codec_strip && g_hash_table_lookup(flags->codec_strip, &str_all))
|
|
|
|
strip_all = 1;
|
|
|
|
strip_all = 1;
|
|
|
|
if (flags->codec_strip && g_hash_table_lookup(flags->codec_strip, &str_all))
|
|
|
|
else if (flags->codec_strip && g_hash_table_lookup(flags->codec_strip, &str_full))
|
|
|
|
strip_all = 2;
|
|
|
|
strip_all = 2;
|
|
|
|
if (flags->codec_mask && g_hash_table_lookup(flags->codec_mask, &str_all))
|
|
|
|
if (flags->codec_mask && g_hash_table_lookup(flags->codec_mask, &str_all))
|
|
|
|
mask_all = 1;
|
|
|
|
mask_all = 1;
|
|
|
|
else if (flags->codec_mask && g_hash_table_lookup(flags->codec_mask, &str_full))
|
|
|
|
else if (flags->codec_mask && g_hash_table_lookup(flags->codec_mask, &str_full))
|
|
|
|
mask_all = 2;
|
|
|
|
mask_all = 2;
|
|
|
|
|
|
|
|
if (flags->codec_consume && g_hash_table_lookup(flags->codec_consume, &str_all))
|
|
|
|
|
|
|
|
consume_all = 1;
|
|
|
|
|
|
|
|
else if (flags->codec_consume && g_hash_table_lookup(flags->codec_consume, &str_full))
|
|
|
|
|
|
|
|
consume_all = 2;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
__ht_merge(&flags->codec_except, flags->codec_consume);
|
|
|
|
|
|
|
|
__ht_merge(&flags->codec_except, flags->codec_accept);
|
|
|
|
|
|
|
|
__ht_merge(&flags->codec_except, flags->codec_strip);
|
|
|
|
|
|
|
|
__ht_merge(&flags->codec_except, flags->codec_mask);
|
|
|
|
|
|
|
|
|
|
|
|
/* we steal the entire list to avoid duplicate allocs */
|
|
|
|
/* we steal the entire list to avoid duplicate allocs */
|
|
|
|
while ((pt = g_queue_pop_head(types))) {
|
|
|
|
while ((pt = g_queue_pop_head(types))) {
|
|
|
|
@ -3204,6 +3356,28 @@ void codec_rtp_payload_types(struct call_media *media, struct call_media *other_
|
|
|
|
g_queue_push_tail(q, __rtp_payload_type_copy(pt));
|
|
|
|
g_queue_push_tail(q, __rtp_payload_type_copy(pt));
|
|
|
|
__rtp_payload_type_add_send(other_media, pt);
|
|
|
|
__rtp_payload_type_add_send(other_media, pt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (__codec_ht_except(consume_all, flags->codec_consume, flags->codec_except, pt)) {
|
|
|
|
|
|
|
|
ilog(LOG_DEBUG, "Consuming codec '" STR_FORMAT "'",
|
|
|
|
|
|
|
|
STR_FMT(&pt->encoding_with_params));
|
|
|
|
|
|
|
|
#ifdef WITH_TRANSCODING
|
|
|
|
|
|
|
|
codec_touched(pt, media);
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
pt->for_transcoding = 1;
|
|
|
|
|
|
|
|
GQueue *q = g_hash_table_lookup_queue_new(masked, str_dup(&pt->encoding), free);
|
|
|
|
|
|
|
|
g_queue_push_tail(q, __rtp_payload_type_copy(pt));
|
|
|
|
|
|
|
|
q = g_hash_table_lookup_queue_new(masked, str_dup(&pt->encoding_with_params), free);
|
|
|
|
|
|
|
|
g_queue_push_tail(q, __rtp_payload_type_copy(pt));
|
|
|
|
|
|
|
|
__rtp_payload_type_add_send(other_media, pt);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (__codec_ht_except(0, flags->codec_accept, NULL, pt)) {
|
|
|
|
|
|
|
|
ilog(LOG_DEBUG, "Accepting codec '" STR_FORMAT "'",
|
|
|
|
|
|
|
|
STR_FMT(&pt->encoding_with_params));
|
|
|
|
|
|
|
|
#ifdef WITH_TRANSCODING
|
|
|
|
|
|
|
|
codec_touched(pt, media);
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
pt->for_transcoding = 1;
|
|
|
|
|
|
|
|
__rtp_payload_type_add(media, other_media, pt);
|
|
|
|
|
|
|
|
}
|
|
|
|
else
|
|
|
|
else
|
|
|
|
__rtp_payload_type_add(media, other_media, pt);
|
|
|
|
__rtp_payload_type_add(media, other_media, pt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|