diff --git a/daemon/call.c b/daemon/call.c index a99c54d28..559eece1d 100644 --- a/daemon/call.c +++ b/daemon/call.c @@ -2765,6 +2765,7 @@ static void __call_monologue_init_from_flags(struct call_monologue *ml, struct c media_player_new(&ml->rec_player, ml); media_player_opts_t opts = MPO( .repeat = flags->repeat_times, + .duration_spent = flags->repeat_duration, .start_pos = flags->start_pos, .block_egress = !!flags->block_egress, .codec_set = flags->codec_set, diff --git a/daemon/call_interfaces.c b/daemon/call_interfaces.c index 33e62eaf6..a8738cfab 100644 --- a/daemon/call_interfaces.c +++ b/daemon/call_interfaces.c @@ -1351,6 +1351,7 @@ void call_ng_flags_init(sdp_ng_flags *out, enum ng_opmode opmode) { out->delete_delay = -1; out->volume = 9999; out->digit = -1; + out->repeat_duration = -1; out->frequencies = g_array_new(false, false, sizeof(int)); for (int i = 0; i < __MT_MAX; ++i) out->sdp_media_remove[i] = false; @@ -1929,6 +1930,9 @@ void call_ng_main_flags(const ng_parser_t *parser, str *key, parser_arg value, h case CSH_LOOKUP("repeat-times"): out->repeat_times = parser->get_int_str(value, out->repeat_times); break; + case CSH_LOOKUP("repeat-duration"): + out->repeat_duration = parser->get_int_str(value, out->repeat_duration); + break; case CSH_LOOKUP("replace"): call_ng_flags_str_list(parser, value, call_ng_flags_replace, out); break; @@ -3634,6 +3638,7 @@ const char *call_play_media_ng(ng_command_ctx_t *ctx) { media_player_opts_t opts = MPO( .repeat = flags.repeat_times, + .duration_spent = flags.repeat_duration, .start_pos = flags.start_pos, .block_egress = !!flags.block_egress, .codec_set = flags.codec_set, diff --git a/daemon/main.c b/daemon/main.c index 3982df710..5d193d73e 100644 --- a/daemon/main.c +++ b/daemon/main.c @@ -112,7 +112,7 @@ struct rtpengine_config rtpe_config = { .mqtt_publish_interval = 5000, .dtmf_digit_delay = 2500, .rtcp_interval = 5000, - .moh_max_duration = 1800000, // in ms + .moh_max_duration = -1, // disabled by default .common = { .log_levels = { [log_level_index_internals] = -1, @@ -697,7 +697,7 @@ static void options(int *argc, char ***argv, GHashTable *templates) { #endif { "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"}, - { "moh-max-duration", 0,0, G_OPTION_ARG_INT, &rtpe_config.moh_max_duration, "Music-on-hold max possible duration (in milliseconds). If set to 0 then will be ignored.", "INT"}, + { "moh-max-duration", 0,0, G_OPTION_ARG_INT, &rtpe_config.moh_max_duration, "Max possible duration (in milliseconds) that can be spent on playing a file. If set to 0 then will be ignored.", "INT"}, { "max-recv-iters", 0, 0, G_OPTION_ARG_INT, &rtpe_config.max_recv_iters, "Maximum 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"}, @@ -867,6 +867,10 @@ static void options(int *argc, char ***argv, GHashTable *templates) { if (rtpe_config.max_recv_iters < 1) die("Invalid max-recv-iters value"); + /* if not set, define by default to half an hour */ + if (rtpe_config.moh_max_duration <= 0) + rtpe_config.moh_max_duration = 1800000; + if (rtpe_config.timeout <= 0) rtpe_config.timeout = 60; diff --git a/daemon/media_player.c b/daemon/media_player.c index 0d3f6d255..3271d16c7 100644 --- a/daemon/media_player.c +++ b/daemon/media_player.c @@ -1013,27 +1013,39 @@ static bool media_player_read_packet(struct media_player *mp) { int ret = av_read_frame(mp->coder.fmtctx, mp->coder.pkt); if (ret < 0) { if (ret == AVERROR_EOF) { - /* for moh: count based on duration */ - if (mp->moh && mp->opts.duration_spent > 0) { - ilog(LOG_DEBUG, "EOF reading from media stream but will be played further for duration of '%lld' ms", - mp->opts.duration_spent); - /* moh counter for the max spent duration (in milliseconds) */ - mp->opts.duration_spent = mp->opts.duration_spent - mp->coder.duration; - ret = media_player_find_file_begin(mp); - - /* for play media: count based on repeats */ - } else if (!mp->moh && mp->opts.repeat > 1) { - ilog(LOG_DEBUG, "EOF reading from media stream but will repeat '%i' time", - mp->opts.repeat); - mp->opts.repeat = mp->opts.repeat - 1; - ret = media_player_find_file_begin(mp); - - } else { + /* Duration counter cannot underflow and is always aligned to 0 when used. + * By default is -1. + * If either a duration or repeats counter are done, then the reading process + * is considered EOF. + */ + if (mp->opts.duration_spent == 0 || + mp->opts.repeat <= 1) + { ilog(LOG_DEBUG, "EOF reading from media stream"); return true; + } + + ret = media_player_find_file_begin(mp); + /* counter for the max spent duration (in milliseconds) + * duration takes precedence over repeats, if used together + */ + if (mp->opts.duration_spent > 0) { + ilog(LOG_DEBUG, "EOF reading from stream but will be played further due to available duration '%lld'", + mp->opts.duration_spent); + mp->opts.duration_spent = mp->opts.duration_spent - mp->coder.duration; + /* don't let the duration counter to underflow */ + if (mp->opts.duration_spent < 0) + mp->opts.duration_spent = 0; } + /* counter for the max repeats + * still count down each time, even if we are based on max duration in milliseconds */ + if (mp->opts.repeat > 1) { + ilog(LOG_DEBUG, "EOF reading from stream but will be played further due to available repeats '%d'", + mp->opts.repeat); + mp->opts.repeat--; + } } if (ret < 0 && ret != AVERROR_EOF) { ilog(LOG_ERR, "Error while reading from media stream"); @@ -1282,6 +1294,7 @@ const char * call_check_moh(struct call_monologue *from_ml, struct call_monologu const char *errstr = NULL; media_player_opts_t opts = MPO( .repeat = 999, + /* MoH always has duration set (even if not defined) */ .duration_spent = rtpe_config.moh_max_duration, .start_pos = 0, .block_egress = 1, diff --git a/docs/ng_control_protocol.md b/docs/ng_control_protocol.md index 75f0fe06a..3489db4e9 100644 --- a/docs/ng_control_protocol.md +++ b/docs/ng_control_protocol.md @@ -2095,6 +2095,17 @@ Media files can be provided through one of these keys: Contains an integer. How many times to repeat playback of the media. Default is 1. +* `repeat-duration` + + Contains an integer. How much time in milliseconds is a playback of the media to be minimally iterated. + E.g. if set to 10000ms and the playback's length is 1000ms, then this playback will be iterated + 10 times due to limitation set to 10000ms. + If used together with `repeat-times` then the following logic takes place: + if `repeat-duration` hits the trigger earlier, then this playback will be stopped, + otherwise if the `repeat-duration` is still positive, but the `repeat-times` counter went down to 1, + then still the playback is to be stopped. + By default is disabled. + * `start-pos` Contains an integer. The start frame position to begin the playback from. diff --git a/etc/rtpengine.conf b/etc/rtpengine.conf index 6e4adfe77..9556f6296 100644 --- a/etc/rtpengine.conf +++ b/etc/rtpengine.conf @@ -152,7 +152,8 @@ recording-method = proc # socket-cpu-affinity = -1 # rtcp-interval = 5000 -# music-on-hold max possible duration (in ms), if set 0 then will be ignored +# music-on-hold max possible duration (in ms). +# When not defined (set to 0), it takes 1800000ms default value. # moh-max-duration = 1800000 # signalling templates (see key `templates` above) diff --git a/include/call_interfaces.h b/include/call_interfaces.h index c6246bd53..14aa06b1d 100644 --- a/include/call_interfaces.h +++ b/include/call_interfaces.h @@ -133,6 +133,7 @@ struct sdp_ng_flags { int media_rec_slot_answer; int media_rec_slots; int repeat_times; + long long repeat_duration; int delete_delay; str file; str moh_file; diff --git a/include/media_player.h b/include/media_player.h index 1b91cd889..36fd77434 100644 --- a/include/media_player.h +++ b/include/media_player.h @@ -34,7 +34,6 @@ typedef struct { #include #include - struct media_player_cache_entry; struct media_player_content_index {