Skip to content

Commit

Permalink
MT#61630 Generalize moh-max-duration, add repeat-duration
Browse files Browse the repository at this point in the history
Make `moh-max-duration` available for both
music-on-hold functionality as well as
for the media player.

For that to work, do the following:
- keep `moh-max-duration` config option only for MoH,
  if not set (so 0) by default is 1800000ms (half an hour)
- for the play media functionality introduce flag option
  `repeat-duration`, by default is disabled

Policy changes:
- duration counter can be used in common with repeats
  counter, but then takes a precedence over it.
  Hence if first a duration is underflown, then EOF triggered.
  Otherwise if the duration counter is still positive, but
  repeats are negative, then do EOF based on repeats.
- the repeats counter will always count down during each
  iteration, even when used together with the duration counter
  For MoH to survive, the repeats counter is simple set to 999
  to let the duration counter always win over repeats one
- MoH cannot take duration disabled, since otherwise
  would make no sense for it. Hence always takes internally
  defined value 1800000ms (half an hour) if not defined
  by the configuration option

Backwards compatibility:
- is kept in regards of repeats counter
- is kept in regards of the play media functionality

Change-Id: I48ff3c17c9bed31f80c3106b275b703a9ccb4b26
  • Loading branch information
zenichev committed Jan 4, 2025
1 parent ffa64f4 commit 67bfa5a
Show file tree
Hide file tree
Showing 8 changed files with 55 additions and 20 deletions.
1 change: 1 addition & 0 deletions daemon/call.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
5 changes: 5 additions & 0 deletions daemon/call_interfaces.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down
8 changes: 6 additions & 2 deletions daemon/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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"},
Expand Down Expand Up @@ -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;

Expand Down
45 changes: 29 additions & 16 deletions daemon/media_player.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down Expand Up @@ -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,
Expand Down
11 changes: 11 additions & 0 deletions docs/ng_control_protocol.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
3 changes: 2 additions & 1 deletion etc/rtpengine.conf
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions include/call_interfaces.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
1 change: 0 additions & 1 deletion include/media_player.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ typedef struct {
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>


struct media_player_cache_entry;

struct media_player_content_index {
Expand Down

0 comments on commit 67bfa5a

Please sign in to comment.