From 503217f04964e60ef451f5c526bc5edd398e0989 Mon Sep 17 00:00:00 2001 From: Naveen Albert Date: Thu, 25 May 2023 23:58:41 +0000 Subject: [PATCH] res_musiconhold: Add option to loop last file. Adds the loop_last option to res_musiconhold, which allows the last audio file in the directory to be looped perpetually once reached, rather than circling back to the beginning again. Resolves: #122 ASTERISK-30462 UserNote: The loop_last option in musiconhold.conf now allows the last file in the directory to be looped once reached. (cherry picked from commit 2b302e30e4ddc1230d3b76654833f236bac87896) --- configs/samples/musiconhold.conf.sample | 8 ++++++ ...427449_add_loop_last_to_res_musiconhold.py | 27 +++++++++++++++++++ res/res_musiconhold.c | 14 +++++++++- 3 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 contrib/ast-db-manage/config/versions/f5b0e7427449_add_loop_last_to_res_musiconhold.py diff --git a/configs/samples/musiconhold.conf.sample b/configs/samples/musiconhold.conf.sample index 1737c7a170..ca1d2fce6e 100644 --- a/configs/samples/musiconhold.conf.sample +++ b/configs/samples/musiconhold.conf.sample @@ -82,6 +82,14 @@ directory=moh ; ; in alphabetical order. If 'randstart', the files are sorted ; ; in alphabetical order as well, but the first file is chosen ; ; at random. If unspecified, the sort order is undefined. +;loop_last=no ; If enabled, once the end of the directory is reached, + ; the last file played will be looped perpetually, rather than + ; starting over at the beginning again. + ; Can be used with sort=alpha or randstart so you can control + ; which file gets looped (the last one sorted alphabetically). + ; (If sort=alpha, all files will be played at least once, but + ; this may not be true with sort=randstart.) + ; Default is no. ;answeredonly=yes ; Only allow answered channels to have music on hold. ; Enabling this will prevent MOH on unanswered channels. ; (default: "no") diff --git a/contrib/ast-db-manage/config/versions/f5b0e7427449_add_loop_last_to_res_musiconhold.py b/contrib/ast-db-manage/config/versions/f5b0e7427449_add_loop_last_to_res_musiconhold.py new file mode 100644 index 0000000000..8d49404dfc --- /dev/null +++ b/contrib/ast-db-manage/config/versions/f5b0e7427449_add_loop_last_to_res_musiconhold.py @@ -0,0 +1,27 @@ +"""Add loop_last to res_musiconhold + +Revision ID: f5b0e7427449 +Revises: f261363a857f +Create Date: 2023-03-13 23:59:00.835055 + +""" + +# revision identifiers, used by Alembic. +revision = 'f5b0e7427449' +down_revision = 'f261363a857f' + +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects.postgresql import ENUM + +YESNO_NAME = 'yesno_values' +YESNO_VALUES = ['yes', 'no'] + +def upgrade(): + yesno_values = ENUM(*YESNO_VALUES, name=YESNO_NAME, create_type=False) + op.add_column('musiconhold', sa.Column('loop_last', yesno_values)) + +def downgrade(): + if op.get_context().bind.dialect.name == 'mssql': + op.drop_constraint('musiconhold','loop_last') + op.drop_column('musiconhold', 'loop_last') diff --git a/res/res_musiconhold.c b/res/res_musiconhold.c index 6196211265..469a8b322f 100644 --- a/res/res_musiconhold.c +++ b/res/res_musiconhold.c @@ -153,6 +153,8 @@ struct moh_files_state { #define MOH_ANNOUNCEMENT (1 << 6) /*!< Do we play announcement files between songs on this channel? */ #define MOH_PREFERCHANNELCLASS (1 << 7) /*!< Should queue moh override channel moh */ +#define MOH_LOOPLAST (1 << 8) /*!< Whether to loop the last file in the music class when we reach the end, rather than starting over */ + /* Custom astobj2 flag */ #define MOH_NOTDELETED (1 << 30) /*!< Find only records that aren't deleted? */ #define MOH_REALTIME (1 << 31) /*!< Find only records that are realtime */ @@ -366,7 +368,11 @@ static int ast_moh_files_next(struct ast_channel *chan) } else { /* This is easy, just increment our position and make sure we don't exceed the total file count */ state->pos++; - state->pos %= file_count; + if (ast_test_flag(state->class, MOH_LOOPLAST)) { + state->pos = MIN(file_count - 1, state->pos); + } else { + state->pos %= file_count; + } state->save_pos = -1; state->samples = 0; } @@ -1172,6 +1178,12 @@ static void moh_parse_options(struct ast_variable *var, struct mohclass *mohclas } else if (!strcasecmp(var->value, "randstart")) { ast_set_flag(mohclass, MOH_RANDSTART); } + } else if (!strcasecmp(var->name, "loop_last")) { + if (ast_true(var->value)) { + ast_set_flag(mohclass, MOH_LOOPLAST); + } else { + ast_clear_flag(mohclass, MOH_LOOPLAST); + } } else if (!strcasecmp(var->name, "format") && !ast_strlen_zero(var->value)) { ao2_cleanup(mohclass->format); mohclass->format = ast_format_cache_get(var->value);