From d611bbbb7477cb68d29feff0df30e239d603e714 Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Tue, 31 Mar 2020 13:59:28 -0400 Subject: [PATCH] TT#78501 add T.38 options Change-Id: I4f173f384db18e832c1d24a7015a836ec4215a96 --- README.md | 29 +++++++++++++++++ daemon/call_interfaces.c | 67 +++++++++++++++++++++++++++++++++++++++ daemon/codec.c | 35 +++++++++++++------- daemon/t38.c | 10 ++++-- include/call_interfaces.h | 7 ++++ include/t38.h | 7 ++++ t/auto-daemon-tests.pl | 32 +++++++++++++++++++ 7 files changed, 173 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 4330e7a33..13d40b8c8 100644 --- a/README.md +++ b/README.md @@ -1122,6 +1122,35 @@ Optionally included keys are: or `force` flags. This is useful to handle a rejected T.38 offer and revert the session back to media passthrough. + - `no-ECM` + + Disable support for ECM. Support is enabled by default. + + - `no-V.17` + + Disable support for V.17. Support is enabled by default. + + - `no-V.27ter` + + Disable support for V.27ter. Support is enabled by default. + + - `no-V.29` + + Disable support for V.29. Support is enabled by default. + + - `no-V.34` + + Disable support for V.34. Support is enabled by default. + + - `no-IAF` + + Disable support for IAF. Support is enabled by default. + + - `FEC` + + Use UDPTL FEC instead of redundancy. Only useful with `T.38=force` as + it's a negotiated parameter. + * `supports` Contains a list of strings. Each string indicates support for an additional feature diff --git a/daemon/call_interfaces.c b/daemon/call_interfaces.c index 869486c93..7a0395b8e 100644 --- a/daemon/call_interfaces.c +++ b/daemon/call_interfaces.c @@ -550,6 +550,7 @@ INLINE void ng_sdes_option(struct sdp_ng_flags *out, str *s, void *dummy) { #ifdef WITH_TRANSCODING INLINE void ng_t38_option(struct sdp_ng_flags *out, str *s, void *dummy) { + str_hyphenate(s); switch (__csh_lookup(s)) { case CSH_LOOKUP("decode"): out->t38_decode = 1; @@ -560,6 +561,72 @@ INLINE void ng_t38_option(struct sdp_ng_flags *out, str *s, void *dummy) { case CSH_LOOKUP("stop"): out->t38_stop = 1; break; + case CSH_LOOKUP("no-ECM"): + out->t38_no_ecm = 1; + break; + case CSH_LOOKUP("no-V17"): + out->t38_no_v17 = 1; + break; + case CSH_LOOKUP("no-V.17"): + out->t38_no_v17 = 1; + break; + case CSH_LOOKUP("no-V.27ter"): + out->t38_no_v27ter = 1; + break; + case CSH_LOOKUP("no-V27ter"): + out->t38_no_v27ter = 1; + break; + case CSH_LOOKUP("no-V29"): + out->t38_no_v29 = 1; + break; + case CSH_LOOKUP("no-V.29"): + out->t38_no_v29 = 1; + break; + case CSH_LOOKUP("no-V34"): + out->t38_no_v34 = 1; + break; + case CSH_LOOKUP("no-V.34"): + out->t38_no_v34 = 1; + break; + case CSH_LOOKUP("no-IAF"): + out->t38_no_iaf = 1; + break; + case CSH_LOOKUP("no-ecm"): + out->t38_no_ecm = 1; + break; + case CSH_LOOKUP("no-v17"): + out->t38_no_v17 = 1; + break; + case CSH_LOOKUP("no-v.17"): + out->t38_no_v17 = 1; + break; + case CSH_LOOKUP("no-v.27ter"): + out->t38_no_v27ter = 1; + break; + case CSH_LOOKUP("no-v27ter"): + out->t38_no_v27ter = 1; + break; + case CSH_LOOKUP("no-v29"): + out->t38_no_v29 = 1; + break; + case CSH_LOOKUP("no-v.29"): + out->t38_no_v29 = 1; + break; + case CSH_LOOKUP("no-v34"): + out->t38_no_v34 = 1; + break; + case CSH_LOOKUP("no-v.34"): + out->t38_no_v34 = 1; + break; + case CSH_LOOKUP("no-iaf"): + out->t38_no_iaf = 1; + break; + case CSH_LOOKUP("FEC"): + out->t38_fec = 1; + break; + case CSH_LOOKUP("fec"): + out->t38_fec = 1; + break; default: ilog(LOG_WARN, "Unknown 'T.38' flag encountered: '" STR_FORMAT "'", STR_FMT(s)); diff --git a/daemon/codec.c b/daemon/codec.c index 55ef5c480..dc047186e 100644 --- a/daemon/codec.c +++ b/daemon/codec.c @@ -697,26 +697,37 @@ static void __generator_stop(struct call_media *media) { } } +static void __t38_options_from_flags(struct t38_options *t_opts, const struct sdp_ng_flags *flags) { +#define t38_opt(name) t_opts->name = flags->t38_ ## name + t38_opt(no_ecm); + t38_opt(no_v17); + t38_opt(no_v27ter); + t38_opt(no_v29); + t38_opt(no_v34); + t38_opt(no_iaf); +} + static void __check_t38_gateway(struct call_media *pcm_media, struct call_media *t38_media, - const struct stream_params *sp) + const struct stream_params *sp, const struct sdp_ng_flags *flags) { - const struct t38_options *t_opts; - struct t38_options t_opts_stor = {0,}; + struct t38_options t_opts = {0,}; if (sp) - t_opts = &sp->t38_options; + t_opts = sp->t38_options; else { // create our own options - t_opts_stor.max_ec_entries = 3; - t_opts = &t_opts_stor; + if (flags->t38_fec) + t_opts.fec_span = 3; + t_opts.max_ec_entries = 3; } + __t38_options_from_flags(&t_opts, flags); MEDIA_SET(pcm_media, TRANSCODE); MEDIA_SET(pcm_media, GENERATOR); MEDIA_SET(t38_media, TRANSCODE); MEDIA_SET(t38_media, GENERATOR); - if (t38_gateway_pair(t38_media, pcm_media, t_opts)) + if (t38_gateway_pair(t38_media, pcm_media, &t_opts)) return; // need a packet handler on the T.38 side @@ -745,14 +756,16 @@ static void __check_t38_gateway(struct call_media *pcm_media, struct call_media } // call must be locked in W -static int codec_handler_udptl_update(struct call_media *receiver, struct call_media *sink) { +static int codec_handler_udptl_update(struct call_media *receiver, struct call_media *sink, + const struct sdp_ng_flags *flags) +{ // anything to do? if (proto_is(sink->protocol, PROTO_UDPTL)) return 0; if (sink->type_id == MT_AUDIO && proto_is_rtp(sink->protocol) && receiver->type_id == MT_IMAGE) { if (!str_cmp(&receiver->format_str, "t38")) { - __check_t38_gateway(sink, receiver, NULL); + __check_t38_gateway(sink, receiver, NULL, flags); return 1; } } @@ -769,7 +782,7 @@ static int codec_handler_non_rtp_update(struct call_media *receiver, struct call const struct sdp_ng_flags *flags, const struct stream_params *sp) { if (proto_is(sink->protocol, PROTO_UDPTL) && !str_cmp(&sink->format_str, "t38")) { - __check_t38_gateway(receiver, sink, sp); + __check_t38_gateway(receiver, sink, sp, flags); return 1; } ilog(LOG_WARN, "Unsupported non-RTP protocol: " STR_FORMAT "/" STR_FORMAT @@ -790,7 +803,7 @@ void codec_handlers_update(struct call_media *receiver, struct call_media *sink, // non-RTP protocol? if (proto_is(receiver->protocol, PROTO_UDPTL)) { - if (codec_handler_udptl_update(receiver, sink)) + if (codec_handler_udptl_update(receiver, sink, flags)) return; } // everything else is unsupported: pass through diff --git a/daemon/t38.c b/daemon/t38.c index 9a1a12cce..e1a26bae6 100644 --- a/daemon/t38.c +++ b/daemon/t38.c @@ -390,10 +390,14 @@ int t38_gateway_pair(struct call_media *t38_media, struct call_media *pcm_media, // set options t38_core_state_t *t38 = t38_gateway_get_t38_core_state(tg->gw); - t38_gateway_set_ecm_capability(tg->gw, TRUE); + t38_gateway_set_ecm_capability(tg->gw, opts.no_ecm ? FALSE : TRUE); t38_gateway_set_transmit_on_idle(tg->gw, TRUE); - t38_gateway_set_supported_modems(tg->gw, T30_SUPPORT_V17 | T30_SUPPORT_V27TER | T30_SUPPORT_V29 - | T30_SUPPORT_V34HDX | T30_SUPPORT_IAF); + t38_gateway_set_supported_modems(tg->gw, + (opts.no_v17 ? 0 : T30_SUPPORT_V17) + | (opts.no_v27ter ? 0 : T30_SUPPORT_V27TER) + | (opts.no_v29 ? 0 : T30_SUPPORT_V29) + | (opts.no_v34 ? 0 : T30_SUPPORT_V34HDX) + | (opts.no_iaf ? 0 : T30_SUPPORT_IAF)); t38_set_t38_version(t38, opts.version); t38_set_data_rate_management_method(t38, opts.local_tcf ? 1 : 2); diff --git a/include/call_interfaces.h b/include/call_interfaces.h index d744fd72e..2b60b023c 100644 --- a/include/call_interfaces.h +++ b/include/call_interfaces.h @@ -80,6 +80,13 @@ struct sdp_ng_flags { t38_decode:1, t38_force:1, t38_stop:1, + t38_no_ecm:1, + t38_no_v17:1, + t38_no_v27ter:1, + t38_no_v29:1, + t38_no_v34:1, + t38_no_iaf:1, + t38_fec:1, supports_load_limit:1, dtls_off:1, sdes_off:1, diff --git a/include/t38.h b/include/t38.h index 19d8b73cc..a36dab418 100644 --- a/include/t38.h +++ b/include/t38.h @@ -16,6 +16,13 @@ struct t38_options { int fill_bit_removal:1; int transcoding_mmr:1; int transcoding_jbig:1; + + int no_ecm:1; + int no_v17:1; + int no_v27ter:1; + int no_v29:1; + int no_v34:1; + int no_iaf:1; }; diff --git a/t/auto-daemon-tests.pl b/t/auto-daemon-tests.pl index 42f4c98bb..37e780c9d 100755 --- a/t/auto-daemon-tests.pl +++ b/t/auto-daemon-tests.pl @@ -917,7 +917,39 @@ rtpe_req('delete', "delete", { 'from-tag' => ft() }); +new_call; +offer('T.38 FEC invite', { ICE => 'remove', 'T.38' => [ 'force', 'FEC' ], + }, < ft() }); + + + +done_testing(); +exit; # github issue 850