Asterisk 18 MusicOnHold database structure?


I’m glad to see that asterisk 18 introduced the ability to use URIs for MusicOnHold, the musiconhold.conf sample is straightforward :


But I’m using realtime for everything, and I can’t figure what is the MySQL table structure for realtime MOH and how to use http URIs in realtime mode.



Any help? still can’t figure out


Try this: Asterisk config musiconhold.conf - VoIP-Info

Hi @aabreu ,

Thanks for your feedback, I already have this configuration, but I want to use a list of URIs instead of a directory. ( [ASTERISK-29262] Support of various URL-schemes by MoH - Digium/Asterisk JIRA )

Hi, @Cyril.r

I’ve tried the following in Asterisk 18.1.1 and it works.

I noticed that the database created by the Alembic have two tables regarding MoH:

mysql> describe musiconhold;
| Field       | Type                                                              | Null | Key | Default | Extra |
| name        | varchar(80)                                                       | NO   | PRI | NULL    |       |
| mode        | enum('custom','files','mp3nb','quietmp3nb','quietmp3','playlist') | YES  |     | NULL    |       |
| directory   | varchar(255)                                                      | YES  |     | NULL    |       |
| application | varchar(255)                                                      | YES  |     | NULL    |       |
| digit       | varchar(1)                                                        | YES  |     | NULL    |       |
| sort        | varchar(10)                                                       | YES  |     | NULL    |       |
| format      | varchar(10)                                                       | YES  |     | NULL    |       |
| stamp       | datetime                                                          | YES  |     | NULL    |       |
8 rows in set (0.00 sec)

mysql> describe musiconhold_entry;
| Field    | Type          | Null | Key | Default | Extra |
| name     | varchar(80)   | NO   | PRI | NULL    |       |
| position | int(11)       | NO   | PRI | NULL    |       |
| entry    | varchar(1024) | NO   |     | NULL    |       |
3 rows in set (0.00 sec)

In the /etc/asterisk/extconfig.conf file I added this:

musiconhold => odbc,asterisk
musiconhold_entry => odbc,asterisk

I created a MoH class for testing purposes in the previous tables:

INSERT INTO musiconhold SET name = 'test', mode = 'playlist';

INSERT INTO musiconhold_entry SET name = 'test', position = 1, entry = '';
INSERT INTO musiconhold_entry SET name = 'test', position = 2, entry = '';
INSERT INTO musiconhold_entry SET name = 'test', position = 3, entry = '';

If you place a call that play de MoH test class, the audio files will be fetched from the URL.

Is this what you are looking for?


Hi @aabreu,

That’s exactly what I was looking for, thank you very much :+1:

One last thing, I’m wondering if the musiconHold URIs have any caching mechanism, I read in the documentation that playback uses Cache-Control header inside HTTP reply, but I haven’t found anything regarding MOH.

Most web sites are HTTPS, these days, so Cache-Control is relatively useless, as you cannot cache encrypted contents.

@Cyril.r I think both applications use the same mechanism for file transfers.

I ran a test in Asterisk 18.1.1 with a local HTTP server (Node.js module: http-server) that respond with a Cache-Control header of 30 seconds.

http-server -c 30

At the same time, I have put a ngrok in the middle, so I can also test what @david551 said about HTTPS.

ngrok http -region=eu 8080

Forwarding -> http://localhost:8080

I test in Google Chrome one HTTP request to check the header:


The cache-control header exists with the correct value.

Then I place a call that start music on hold using this URL.

Here is the logs from http-server, as you can see we only have requests with 30 seconds of interval (this music on hold is only the word “hello”, must have 1 ou 2 seconds long):

[2021-07-07T08:18:39.410Z]  "GET /sounds/hello.gsm" "asterisk-libcurl-agent/1.0"
[2021-07-07T08:19:09.279Z]  "HEAD /sounds/hello.gsm" "asterisk-libcurl-agent/1.0"
[2021-07-07T08:19:39.911Z]  "HEAD /sounds/hello.gsm" "asterisk-libcurl-agent/1.0"

I was really referring to shared caches. I’d assumed that Asterisk didn’t fetch to a file, but streamed the the media directly, but it looks as though it uses libcurl for more sophisticated handling.

The HEAD’s aren’t really what I would expect though. I’d expect a conditional GET. Did the server respond as HTTP/1.0?

Hi @aabreu ,

Thanks for your tests, I can confirm that caching works as you described in your previous post (I checked on asterisk side using the console with some debug info)

Hope those informations will help anyone looking for this topic.