From 50848552c626b9bd1cc1f975f03eef2e8170d7d6 Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Fri, 19 Jan 2024 08:44:32 -0500 Subject: [PATCH] MT#59038 support DTMF VSC to control recording Change-Id: I57c5bec312419eff90efb06c5b1cee998f1f9466 --- daemon/call.c | 14 +++++ daemon/call_interfaces.c | 39 ++++++++++++ daemon/dtmf.c | 125 ++++++++++++++++++++++++++++++++++++++ daemon/main.c | 15 +++++ include/call_interfaces.h | 8 +++ include/dtmf.h | 8 +++ include/main.h | 6 ++ 7 files changed, 215 insertions(+) diff --git a/daemon/call.c b/daemon/call.c index 28b38e5fb..407cd193d 100644 --- a/daemon/call.c +++ b/daemon/call.c @@ -2597,6 +2597,20 @@ static void __call_monologue_init_from_flags(struct call_monologue *ml, sdp_ng_f t_hash_table_replace(call->labels, &ml->label, ml); } + if (flags->recording_vsc) { +#define SET_VSC(x,t) \ + if (flags->vsc_ ## x ## _rec.len) \ + dtmf_trigger_set(ml, DTMF_TRIGGER_ ## t ## _REC, &flags->vsc_ ## x ## _rec, false); \ + else \ + dtmf_trigger_set(ml, DTMF_TRIGGER_ ## t ## _REC, &rtpe_config.vsc_ ## x ## _rec, false); + SET_VSC(start, START) + SET_VSC(stop, STOP) + SET_VSC(pause, PAUSE) + SET_VSC(start_stop, START_STOP) + SET_VSC(pause_resume, PAUSE_RESUME) + SET_VSC(start_pause_resume, START_PAUSE_RESUME) +#undef SET_VSC + } } __attribute__((nonnull(2, 3))) diff --git a/daemon/call_interfaces.c b/daemon/call_interfaces.c index 79da935eb..c9bbf9fcb 100644 --- a/daemon/call_interfaces.c +++ b/daemon/call_interfaces.c @@ -1125,6 +1125,9 @@ static void call_ng_flags_flags(sdp_ng_flags *out, str *s, helper_arg dummy) { case CSH_LOOKUP("record-call"): out->record_call = 1; break; + case CSH_LOOKUP("recording-vsc"): + out->recording_vsc = 1; + break; case CSH_LOOKUP("reorder-codecs"): ilog(LOG_INFO, "Ignoring obsolete flag `reorder-codecs`"); break; @@ -1883,6 +1886,42 @@ static void call_ng_main_flags(sdp_ng_flags *out, str *key, bencode_item_t *valu case CSH_LOOKUP("volume"): out->volume = bencode_get_integer_str(value, out->volume); break; + case CSH_LOOKUP("vsc-pause-rec"): + case CSH_LOOKUP("VSC-pause-rec"): + case CSH_LOOKUP("vsc-pause-recording"): + case CSH_LOOKUP("VSC-pause-recording"): + out->vsc_pause_rec = s; + break; + case CSH_LOOKUP("vsc-pause-resume-rec"): + case CSH_LOOKUP("VSC-pause-resume-rec"): + case CSH_LOOKUP("vsc-pause-resume-recording"): + case CSH_LOOKUP("VSC-pause-resume-recording"): + out->vsc_pause_resume_rec = s; + break; + case CSH_LOOKUP("vsc-start-pause-resume-rec"): + case CSH_LOOKUP("VSC-start-pause-resume-rec"): + case CSH_LOOKUP("vsc-start-pause-resume-recording"): + case CSH_LOOKUP("VSC-start-pause-resume-recording"): + out->vsc_start_pause_resume_rec = s; + break; + case CSH_LOOKUP("vsc-start-rec"): + case CSH_LOOKUP("VSC-start-rec"): + case CSH_LOOKUP("vsc-start-recording"): + case CSH_LOOKUP("VSC-start-recording"): + out->vsc_start_rec = s; + break; + case CSH_LOOKUP("vsc-start-stop-rec"): + case CSH_LOOKUP("VSC-start-stop-rec"): + case CSH_LOOKUP("vsc-start-stop-recording"): + case CSH_LOOKUP("VSC-start-stop-recording"): + out->vsc_start_stop_rec = s; + break; + case CSH_LOOKUP("vsc-stop-rec"): + case CSH_LOOKUP("VSC-stop-rec"): + case CSH_LOOKUP("vsc-stop-recording"): + case CSH_LOOKUP("VSC-stop-recording"): + out->vsc_stop_rec = s; + break; case CSH_LOOKUP("xmlrpc-callback"): case CSH_LOOKUP("XMLRPC-callback"): if (sockaddr_parse_any_str(&out->xmlrpc_callback, &s)) diff --git a/daemon/dtmf.c b/daemon/dtmf.c index ab44188dd..4fd4afb47 100644 --- a/daemon/dtmf.c +++ b/daemon/dtmf.c @@ -19,6 +19,12 @@ static socket_t dtmf_log_sock; static void dtmf_trigger_block_action(struct call_media *, struct call_monologue *); static void dtmf_trigger_block_digit(struct call_media *, struct call_monologue *); static void dtmf_trigger_unblock_action(struct call_media *, struct call_monologue *); +static void dtmf_trigger_start_rec(struct call_media *, struct call_monologue *); +static void dtmf_trigger_stop_rec(struct call_media *, struct call_monologue *); +static void dtmf_trigger_start_stop_rec(struct call_media *, struct call_monologue *); +static void dtmf_trigger_pause_rec(struct call_media *, struct call_monologue *); +static void dtmf_trigger_pause_resume_rec(struct call_media *, struct call_monologue *); +static void dtmf_trigger_start_pause_resume_rec(struct call_media *, struct call_monologue *); struct dtmf_trigger_action dtmf_trigger_actions[__NUM_DTMF_TRIGGERS] = { [DTMF_TRIGGER_BLOCK] = { @@ -30,6 +36,41 @@ struct dtmf_trigger_action dtmf_trigger_actions[__NUM_DTMF_TRIGGERS] = { .matched = dtmf_trigger_unblock_action, .repeatable = false, }, + [DTMF_TRIGGER_START_REC] = { + .matched = dtmf_trigger_start_rec, + .repeatable = true, + }, + [DTMF_TRIGGER_STOP_REC] = { + .matched = dtmf_trigger_stop_rec, + .repeatable = true, + }, + [DTMF_TRIGGER_START_STOP_REC] = { + .matched = dtmf_trigger_start_stop_rec, + .repeatable = true, + }, + [DTMF_TRIGGER_PAUSE_REC] = { + .matched = dtmf_trigger_pause_rec, + .repeatable = true, + }, + [DTMF_TRIGGER_PAUSE_RESUME_REC] = { + .matched = dtmf_trigger_pause_resume_rec, + .repeatable = true, + }, + [DTMF_TRIGGER_START_PAUSE_RESUME_REC] = { + .matched = dtmf_trigger_start_pause_resume_rec, + .repeatable = true, + }, +}; + +const char *dtmf_trigger_types[__NUM_DTMF_TRIGGERS] = { + [DTMF_TRIGGER_BLOCK] = "block DTMF", + [DTMF_TRIGGER_UNBLOCK] = "unblock DTMF", + [DTMF_TRIGGER_START_REC] = "start recording", + [DTMF_TRIGGER_STOP_REC] = "stop recording", + [DTMF_TRIGGER_START_STOP_REC] = "start/stop recording", + [DTMF_TRIGGER_PAUSE_REC] = "pause recording", + [DTMF_TRIGGER_PAUSE_RESUME_REC] = "pause/resume recording", + [DTMF_TRIGGER_START_PAUSE_RESUME_REC] = "start/pause/resume recording", }; @@ -259,6 +300,10 @@ void dtmf_trigger_set(struct call_monologue *ml, enum dtmf_trigger_type trigger_ // Replace existing trigger below } + ilog(LOG_DEBUG, "Setting DTMF trigger '%s' (at idx %u) to '" STR_FORMAT "'", + dtmf_trigger_types[trigger_type], + (unsigned int) (state - ml->dtmf_trigger_state), STR_FMT(s)); + call_str_cpy(ml->call, &state->trigger, s); state->matched = 0; state->inactive = inactive; @@ -365,6 +410,9 @@ static bool dtmf_check_1_trigger(struct call_media *media, struct call_monologue // trigger is finished state->matched = 0; // reset + ilog(LOG_INFO, "DTMF VSC '%s' ('" STR_FORMAT "') triggered", + dtmf_trigger_types[state->type], STR_FMT(&state->trigger)); + action->matched(media, ml); if (!action->repeatable) @@ -835,3 +883,80 @@ bool is_dtmf_replace_mode(enum block_dtmf_mode mode) { return true; return false; } + +static void dtmf_trigger_do_start_rec(call_t *c, codec_timer_callback_arg_t a) { + rwlock_lock_w(&c->master_lock); + recording_start(c); + rwlock_unlock_w(&c->master_lock); +} + +// dtmf_lock must be held +static void dtmf_trigger_start_rec(struct call_media *media, struct call_monologue *ml) { + codec_timer_callback(ml->call, dtmf_trigger_do_start_rec, ml, 0); +} + +static void dtmf_trigger_do_stop_rec(call_t *c, codec_timer_callback_arg_t a) { + rwlock_lock_w(&c->master_lock); + recording_stop(c); + rwlock_unlock_w(&c->master_lock); +} + +// dtmf_lock must be held +static void dtmf_trigger_stop_rec(struct call_media *media, struct call_monologue *ml) { + codec_timer_callback(ml->call, dtmf_trigger_do_stop_rec, ml, 0); +} + +static void dtmf_trigger_do_start_stop_rec(call_t *c, codec_timer_callback_arg_t a) { + rwlock_lock_w(&c->master_lock); + if (c->recording) + recording_stop(c); + else + recording_start(c); + rwlock_unlock_w(&c->master_lock); +} + +// dtmf_lock must be held +static void dtmf_trigger_start_stop_rec(struct call_media *media, struct call_monologue *ml) { + codec_timer_callback(ml->call, dtmf_trigger_do_start_stop_rec, ml, 0); +} + +static void dtmf_trigger_do_pause_rec(call_t *c, codec_timer_callback_arg_t a) { + rwlock_lock_w(&c->master_lock); + recording_pause(c); + rwlock_unlock_w(&c->master_lock); +} + +// dtmf_lock must be held +static void dtmf_trigger_pause_rec(struct call_media *media, struct call_monologue *ml) { + codec_timer_callback(ml->call, dtmf_trigger_do_pause_rec, ml, 0); +} + +static void dtmf_trigger_do_pause_resume_rec(call_t *c, codec_timer_callback_arg_t a) { + rwlock_lock_w(&c->master_lock); + if (!c->recording) + return; + if (CALL_SET(c, RECORDING_ON)) + recording_pause(c); + else + recording_start(c); + rwlock_unlock_w(&c->master_lock); +} + +// dtmf_lock must be held +static void dtmf_trigger_pause_resume_rec(struct call_media *media, struct call_monologue *ml) { + codec_timer_callback(ml->call, dtmf_trigger_do_pause_resume_rec, ml, 0); +} + +static void dtmf_trigger_do_start_pause_resume_rec(call_t *c, codec_timer_callback_arg_t a) { + rwlock_lock_w(&c->master_lock); + if (CALL_SET(c, RECORDING_ON)) + recording_pause(c); + else + recording_start(c); + rwlock_unlock_w(&c->master_lock); +} + +// dtmf_lock must be held +static void dtmf_trigger_start_pause_resume_rec(struct call_media *media, struct call_monologue *ml) { + codec_timer_callback(ml->call, dtmf_trigger_do_start_pause_resume_rec, ml, 0); +} diff --git a/daemon/main.c b/daemon/main.c index 30d6224dd..94abfb118 100644 --- a/daemon/main.c +++ b/daemon/main.c @@ -648,6 +648,12 @@ static void options(int *argc, char ***argv) { { "janus-secret", 0,0, G_OPTION_ARG_STRING, &rtpe_config.janus_secret,"Admin secret for Janus protocol","STRING"}, { "rtcp-interval", 0,0, G_OPTION_ARG_INT, &rtpe_config.rtcp_interval,"Delay in milliseconds between RTCP packets when generate-rtcp flag is on, where random dispersion < 1 sec is added on top","INT"}, { "max-recv-iters", 0, 0, G_OPTION_ARG_INT, &rtpe_config.max_recv_iters, "Maximun continuous reading cycles in UDP poller loop.", "INT"}, + { "vsc-start-rec",0,0, G_OPTION_ARG_STRING, &rtpe_config.vsc_start_rec.s,"DTMF VSC to start recording.", "STRING"}, + { "vsc-stop-rec",0,0, G_OPTION_ARG_STRING, &rtpe_config.vsc_stop_rec.s,"DTMF VSC to stop recording.", "STRING"}, + { "vsc-start-stop-rec",0,0,G_OPTION_ARG_STRING, &rtpe_config.vsc_start_stop_rec.s,"DTMF VSC to start/stop recording.", "STRING"}, + { "vsc-pause-rec",0,0, G_OPTION_ARG_STRING, &rtpe_config.vsc_pause_rec.s,"DTMF VSC to pause recording.", "STRING"}, + { "vsc-pause-resume-rec",0,0,G_OPTION_ARG_STRING,&rtpe_config.vsc_pause_resume_rec.s,"DTMF VSC to pause/resume recording.", "STRING"}, + { "vsc-start-pause-resume-rec",0,0,G_OPTION_ARG_STRING,&rtpe_config.vsc_start_pause_resume_rec.s,"DTMF VSC to start/pause/resume recording.", "STRING"}, { NULL, } }; @@ -1014,6 +1020,15 @@ static void options(int *argc, char ***argv) { die("Invalid --control-pmtu option ('%s')", control_pmtu); } +#define STR_LEN_INIT(x) if (rtpe_config.x.s) rtpe_config.x.len = strlen(rtpe_config.x.s) + STR_LEN_INIT(vsc_start_rec); + STR_LEN_INIT(vsc_stop_rec); + STR_LEN_INIT(vsc_start_stop_rec); + STR_LEN_INIT(vsc_pause_rec); + STR_LEN_INIT(vsc_pause_resume_rec); + STR_LEN_INIT(vsc_start_pause_resume_rec); +#undef STR_LEN_INIT + rwlock_unlock_w(&rtpe_config.config_lock); } diff --git a/include/call_interfaces.h b/include/call_interfaces.h index 9f5f604dc..0bc299644 100644 --- a/include/call_interfaces.h +++ b/include/call_interfaces.h @@ -118,6 +118,13 @@ struct sdp_ng_flags { AP_TRANSCODING, AP_FORCE, } audio_player:2; + str vsc_start_rec; + str vsc_stop_rec; + str vsc_start_stop_rec; + str vsc_pause_rec; + str vsc_pause_resume_rec; + str vsc_start_pause_resume_rec; + unsigned int asymmetric:1, protocol_accept:1, no_redis_update:1, @@ -162,6 +169,7 @@ struct sdp_ng_flags { discard_recording:1, exclude_recording:1, skip_recording_db:1, + recording_vsc:1, debug:1, inactive:1, loop_protect:1, diff --git a/include/dtmf.h b/include/dtmf.h index c57f01c10..8bc3533e4 100644 --- a/include/dtmf.h +++ b/include/dtmf.h @@ -17,10 +17,18 @@ struct call_monologue; enum dtmf_trigger_type { DTMF_TRIGGER_BLOCK = 0, DTMF_TRIGGER_UNBLOCK, + DTMF_TRIGGER_START_REC, + DTMF_TRIGGER_STOP_REC, + DTMF_TRIGGER_START_STOP_REC, + DTMF_TRIGGER_PAUSE_REC, + DTMF_TRIGGER_PAUSE_RESUME_REC, + DTMF_TRIGGER_START_PAUSE_RESUME_REC, __NUM_DTMF_TRIGGERS, }; +extern const char *dtmf_trigger_types[__NUM_DTMF_TRIGGERS]; + struct dtmf_trigger_state { enum dtmf_trigger_type type; // points to matching action str trigger; // string to look for diff --git a/include/main.h b/include/main.h index bf815b8fc..703fcc3e6 100644 --- a/include/main.h +++ b/include/main.h @@ -187,6 +187,12 @@ struct rtpengine_config { int cpu_affinity; char *janus_secret; int max_recv_iters; + str vsc_start_rec; + str vsc_stop_rec; + str vsc_start_stop_rec; + str vsc_pause_rec; + str vsc_pause_resume_rec; + str vsc_start_pause_resume_rec; };