[Asterisk-code-review] res_musiconhold: Add new 'playlist' mode (...asterisk[17])

George Joseph asteriskteam at digium.com
Fri Sep 27 08:57:25 CDT 2019


George Joseph has submitted this change and it was merged. ( https://gerrit.asterisk.org/c/asterisk/+/12958 )

Change subject: res_musiconhold: Add new 'playlist' mode
......................................................................

res_musiconhold: Add new 'playlist' mode

Allow the list of files to be played to be provided explicitly in the
music class's configuration. The primary driver for this change is to
allow URLs to be used for MoH.

Change-Id: I9f43b80b43880980b18b2bee26ec09429d0b92fa
---
M configs/samples/extconfig.conf.sample
M configs/samples/musiconhold.conf.sample
A contrib/ast-db-manage/config/versions/fbb7766f17bc_add_playlist_to_moh.py
A doc/CHANGES-staging/moh-playlist.txt
M res/res_musiconhold.c
5 files changed, 139 insertions(+), 2 deletions(-)

Approvals:
  Kevin Harwell: Looks good to me, but someone else must approve
  Joshua Colp: Looks good to me, but someone else must approve
  George Joseph: Looks good to me, approved; Approved for Submit



diff --git a/configs/samples/extconfig.conf.sample b/configs/samples/extconfig.conf.sample
index 9e13cac..b633faf 100644
--- a/configs/samples/extconfig.conf.sample
+++ b/configs/samples/extconfig.conf.sample
@@ -95,6 +95,7 @@
 ;queue_rules => odbc,asterisk
 ;acls => odbc,asterisk
 ;musiconhold => mysql,general
+;musiconhold_entry => mysql,general
 ;queue_log => mysql,general
 ;
 ;
diff --git a/configs/samples/musiconhold.conf.sample b/configs/samples/musiconhold.conf.sample
index 741bde6..1090bbe 100644
--- a/configs/samples/musiconhold.conf.sample
+++ b/configs/samples/musiconhold.conf.sample
@@ -13,6 +13,7 @@
 ; valid mode options:
 ; files		-- read files from a directory in any Asterisk supported
 ;		   media format
+; playlist	-- provide a fixed list of filenames or URLs to play
 ; quietmp3 	-- default
 ; mp3 		-- loud
 ; mp3nb		-- unbuffered
@@ -44,6 +45,22 @@
 ; this, res_musiconhold will skip the files it is not able to
 ; understand when it loads.
 ;
+; =========
+; Playlist (native) music on hold
+; =========
+;
+; This mode is similar to 'files' mode in that it plays through a list
+; of files, but instead of scanning a directory the files are
+; explicitly configured using one or more 'entry' options.
+;
+; Each entry must be one of:
+;
+;   * An absolute path to the file to be played, without an extension.
+;   * A URL
+;
+; The entries are played in the order in which they appear in the
+; configuration. The 'sort' option is not used for this mode.
+;
 
 [default]
 mode=files
@@ -71,6 +88,12 @@
 ;directory=moh
 ;sort=alpha     ; Sort the files in alphabetical order.
 
+;[sales-queue-hold]
+;mode=playlist
+;entry=/var/lib/asterisk/sounds/en/yourcallisimportant
+;entry=http://example.local/sales-queue-hold-music.ulaw
+;entry=/var/lib/asterisk/moh/macroform-robot_dity
+
 ; =========
 ; Other (non-native) playback methods
 ; =========
diff --git a/contrib/ast-db-manage/config/versions/fbb7766f17bc_add_playlist_to_moh.py b/contrib/ast-db-manage/config/versions/fbb7766f17bc_add_playlist_to_moh.py
new file mode 100644
index 0000000..0cb5ddb
--- /dev/null
+++ b/contrib/ast-db-manage/config/versions/fbb7766f17bc_add_playlist_to_moh.py
@@ -0,0 +1,54 @@
+"""add playlist to moh
+
+Revision ID: fbb7766f17bc
+Revises: 3a094a18e75b
+Create Date: 2019-09-18 10:24:18.731798
+
+"""
+
+# revision identifiers, used by Alembic.
+revision = 'fbb7766f17bc'
+down_revision = '3a094a18e75b'
+
+from alembic import op
+import sqlalchemy as sa
+
+
+def enum_update(table_name, column_name, enum_name, enum_values):
+    if op.get_context().bind.dialect.name != 'postgresql':
+        if op.get_context().bind.dialect.name == 'mssql':
+            op.drop_constraint('ck_musiconhold_mode_moh_mode_values', 'musiconhold')
+        op.alter_column(table_name, column_name,
+                        type_=sa.Enum(*enum_values, name=enum_name))
+        return
+
+    # Postgres requires a few more steps
+    tmp = enum_name + '_tmp'
+
+    op.execute('ALTER TYPE ' + enum_name + ' RENAME TO ' + tmp)
+
+    updated = sa.Enum(*enum_values, name=enum_name)
+    updated.create(op.get_bind(), checkfirst=False)
+
+    op.execute('ALTER TABLE ' + table_name + ' ALTER COLUMN ' + column_name +
+               ' TYPE ' + enum_name + ' USING mode::text::' + enum_name)
+
+    op.execute('DROP TYPE ' + tmp)
+
+
+def upgrade():
+    op.create_table(
+        'musiconhold_entry',
+        sa.Column('name', sa.String(80), primary_key=True, nullable=False),
+        sa.Column('position', sa.Integer, primary_key=True, nullable=False),
+        sa.Column('entry', sa.String(1024), nullable=False)
+    )
+    op.create_foreign_key('fk_musiconhold_entry_name_musiconhold', 'musiconhold_entry', 'musiconhold', ['name'], ['name'])
+    enum_update('musiconhold', 'mode', 'moh_mode_values',
+                ['custom', 'files', 'mp3nb', 'quietmp3nb', 'quietmp3', 'playlist'])
+
+
+def downgrade():
+    enum_update('musiconhold', 'mode', 'moh_mode_values',
+                ['custom', 'files', 'mp3nb', 'quietmp3nb', 'quietmp3'])
+    op.drop_table('musiconhold_entry')
diff --git a/doc/CHANGES-staging/moh-playlist.txt b/doc/CHANGES-staging/moh-playlist.txt
new file mode 100644
index 0000000..14cb022
--- /dev/null
+++ b/doc/CHANGES-staging/moh-playlist.txt
@@ -0,0 +1,5 @@
+Subject: res_musiconhold
+
+A new mode - playlist - has been added to res_musiconhold. This mode allows the
+user to specify the files (or URLs) to play explicitly by putting them directly
+in musiconhold.conf.
diff --git a/res/res_musiconhold.c b/res/res_musiconhold.c
index f770075..1bacb11 100644
--- a/res/res_musiconhold.c
+++ b/res/res_musiconhold.c
@@ -1081,6 +1081,20 @@
 			ast_copy_string(mohclass->name, var->value, sizeof(mohclass->name));
 		} else if (!strcasecmp(var->name, "mode")) {
 			ast_copy_string(mohclass->mode, var->value, sizeof(mohclass->mode));
+		} else if (!strcasecmp(var->name, "entry")) {
+			if (ast_begins_with(var->value, "/") || ast_begins_with(var->value, "http://") || ast_begins_with(var->value, "https://")) {
+				char *dup = ast_strdup(var->value);
+				if (!dup) {
+					continue;
+				}
+				if (ast_begins_with(dup, "/") && strrchr(dup, '.')) {
+					ast_log(LOG_WARNING, "The playlist entry '%s' may include an extension, which could prevent it from playing.\n",
+						dup);
+				}
+				AST_VECTOR_APPEND(&mohclass->files, dup);
+			} else {
+				ast_log(LOG_ERROR, "Playlist entries must be a URL or absolute path, '%s' provided.\n", var->value);
+			}
 		} else if (!strcasecmp(var->name, "directory")) {
 			ast_copy_string(mohclass->dir, var->value, sizeof(mohclass->dir));
 		} else if (!strcasecmp(var->name, "application")) {
@@ -1130,6 +1144,8 @@
 			}
 		}
 	}
+
+	AST_VECTOR_COMPACT(&mohclass->files);
 }
 
 static int moh_scan_files(struct mohclass *class) {
@@ -1333,6 +1349,13 @@
 			}
 			return -1;
 		}
+	} else if (!strcasecmp(moh->mode, "playlist")) {
+		if (!AST_VECTOR_SIZE(&moh->files)) {
+			if (unref) {
+				moh = mohclass_unref(moh, "unreffing potential new moh class (no playlist entries)");
+			}
+			return -1;
+		}
 	} else if (!strcasecmp(moh->mode, "mp3") || !strcasecmp(moh->mode, "mp3nb") ||
 			!strcasecmp(moh->mode, "quietmp3") || !strcasecmp(moh->mode, "quietmp3nb") ||
 			!strcasecmp(moh->mode, "httpmp3") || !strcasecmp(moh->mode, "custom")) {
@@ -1485,6 +1508,32 @@
 static struct ast_variable *load_realtime_musiconhold(const char *name)
 {
 	struct ast_variable *var = ast_load_realtime("musiconhold", "name", name, SENTINEL);
+
+	if (var) {
+		const char *mode = ast_variable_find_in_list(var, "mode");
+		if (ast_strings_equal(mode, "playlist")) {
+			struct ast_variable *entries = ast_load_realtime("musiconhold_entry", "name", name, SENTINEL);
+			struct ast_variable *cur = entries;
+			size_t entry_count = 0;
+			for (; cur; cur = cur->next) {
+				if (!strcmp(cur->name, "entry")) {
+					struct ast_variable *dup = ast_variable_new(cur->name, cur->value, "");
+					if (dup) {
+						entry_count++;
+						ast_variable_list_append(&var, dup);
+					}
+				}
+			}
+			ast_variables_destroy(entries);
+
+			if (entry_count == 0) {
+				/* Behave as though this class doesn't exist */
+				ast_variables_destroy(var);
+				var = NULL;
+			}
+		}
+	}
+
 	if (!var) {
 		ast_log(LOG_WARNING,
 			"Music on Hold class '%s' not found in memory/database. "
@@ -1551,7 +1600,7 @@
 			ast_variables_destroy(var);
 
 			if (ast_strlen_zero(mohclass->dir)) {
-				if (!strcasecmp(mohclass->mode, "custom")) {
+				if (!strcasecmp(mohclass->mode, "custom") || !strcasecmp(mohclass->mode, "playlist")) {
 					strcpy(mohclass->dir, "nodir");
 				} else {
 					ast_log(LOG_WARNING, "A directory must be specified for class '%s'!\n", mohclass->name);
@@ -1605,6 +1654,11 @@
 						}
 						ast_set_flag(mohclass, MOH_RANDOMIZE);
 					}
+				} else if (!strcasecmp(mohclass->mode, "playlist")) {
+					if (!AST_VECTOR_SIZE(&mohclass->files)) {
+						mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (no playlist entries)");
+						return -1;
+					}
 				} else if (!strcasecmp(mohclass->mode, "mp3") || !strcasecmp(mohclass->mode, "mp3nb") || !strcasecmp(mohclass->mode, "quietmp3") || !strcasecmp(mohclass->mode, "quietmp3nb") || !strcasecmp(mohclass->mode, "httpmp3") || !strcasecmp(mohclass->mode, "custom")) {
 
 					if (!strcasecmp(mohclass->mode, "custom"))
@@ -1846,7 +1900,7 @@
 		ast_copy_string(class->name, cat, sizeof(class->name));
 
 		if (ast_strlen_zero(class->dir)) {
-			if (!strcasecmp(class->mode, "custom")) {
+			if (!strcasecmp(class->mode, "custom") || !strcasecmp(class->mode, "playlist")) {
 				strcpy(class->dir, "nodir");
 			} else {
 				ast_log(LOG_WARNING, "A directory must be specified for class '%s'!\n", class->name);

-- 
To view, visit https://gerrit.asterisk.org/c/asterisk/+/12958
To unsubscribe, or for help writing mail filters, visit https://gerrit.asterisk.org/settings

Gerrit-Project: asterisk
Gerrit-Branch: 17
Gerrit-Change-Id: I9f43b80b43880980b18b2bee26ec09429d0b92fa
Gerrit-Change-Number: 12958
Gerrit-PatchSet: 1
Gerrit-Owner: Sean Bright <sean.bright at gmail.com>
Gerrit-Reviewer: Friendly Automation
Gerrit-Reviewer: George Joseph <gjoseph at digium.com>
Gerrit-Reviewer: Joshua Colp <jcolp at digium.com>
Gerrit-Reviewer: Kevin Harwell <kharwell at digium.com>
Gerrit-MessageType: merged
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.digium.com/pipermail/asterisk-code-review/attachments/20190927/55aa0385/attachment-0001.html>


More information about the asterisk-code-review mailing list