Music on Hold with Native Formats
Music on Hold with Native Formats
The default MOH setup on many Asterisk installs pipes MP3 files through mpg123, an external decoder. It works, but it launches a separate process for every music class, eats CPU for real-time decoding, sometimes fails to loop, and occasionally decides to consume an entire core for no reason.
The fix is simple: convert your MP3s to native audio formats and let Asterisk play them directly. No external process, no decoding overhead, no mysterious CPU spikes.
On this page
Setting up native MOH
Create a directory for your hold music and convert your files:
mkdir -p /var/lib/asterisk/moh-default
# Convert each MP3 to 8kHz mono WAV
for f in /path/to/your/mp3s/*.mp3; do
base=$(basename "${f%.*}")
sox "$f" -r 8000 -c 1 -b 16 "/var/lib/asterisk/moh-default/$base.wav"
done
Back up your configuration files
Before editing any Asterisk configuration file, make a backup copy:
bash
sudo cp /etc/asterisk/musiconhold.conf /etc/asterisk/musiconhold.conf.bak.$(date +%s)
If a typo prevents Asterisk from reloading, you can restore the working version immediately.
Edit /etc/asterisk/musiconhold.conf:
[default]
mode = files
directory = /var/lib/asterisk/moh-default
sort = random
mode = files tells Asterisk to read audio files directly instead of launching an external player. sort = random shuffles the playlist so callers do not always hear the same opening track.
Reload:
asterisk -rx "moh reload"
Verify it loaded:
asterisk -rx "moh show classes"
asterisk -rx "moh show files"
You should see your class listed with the files in it. If the file list is empty, check directory permissions. Asterisk needs read access.
Avoiding transcoding entirely
When Asterisk plays MOH, it checks what codec the caller's channel is using and looks for a file in that format. If it finds song.ulaw and the caller is on G.711 ulaw, it plays the file directly with zero transcoding. If it only finds song.wav, it transcodes from signed linear to whatever the channel needs. That transcoding is cheap, but on a system with 50 concurrent calls on hold, it adds up.
Provide files in multiple formats so Asterisk can skip transcoding:
for f in /var/lib/asterisk/moh-default/*.wav; do
base="${f%.*}"
# GSM (for GSM codec endpoints)
sox "$f" -r 8000 -c 1 "${base}.gsm"
# ULAW (for G.711 ulaw endpoints)
sox "$f" -r 8000 -c 1 -t ul "${base}.ulaw"
# ALAW (for G.711 alaw endpoints)
sox "$f" -r 8000 -c 1 -t al "${base}.alaw"
done
Now Asterisk has four versions of each track and picks the one that matches the channel codec. No transcoding, no CPU cost.
Multiple music classes
Different contexts can play different music. A support queue might get jazz, a sales queue might get upbeat pop:
[default]
mode = files
directory = /var/lib/asterisk/moh-default
sort = random
[support-hold]
mode = files
directory = /var/lib/asterisk/moh-support
sort = random
[sales-hold]
mode = files
directory = /var/lib/asterisk/moh-sales
sort = random
In the dialplan, specify which class to use:
; Set MOH class before entering a queue
exten => s,1,Set(CHANNEL(musicclass)=support-hold)
same => n,Queue(support,t,,,120)
Or in queues.conf:
[support]
musicclass = support-hold
Common problems
No sound plays. Check moh show files. If the class is listed but has no files, the directory path is wrong or Asterisk cannot read it. Run ls -la /var/lib/asterisk/moh-default/ and check ownership.
Sound is garbled or too fast. The source file was not converted to 8kHz mono. Re-convert with sox input.mp3 -r 8000 -c 1 -b 16 output.wav.
MOH works for some phones but not others. If certain endpoints hear silence while others hear music, the issue is codec negotiation. Run pjsip show endpoint <name> to see which codecs the endpoint is configured to allow, then provide files in those formats. To see the actual negotiated codec on a live call, use core show channel <channel>.
What to read next
- Convert Audio Files for Asterisk for batch conversion scripts
User Notes
Know a tip or gotcha for this topic? Share it below and help others.
Contribute a note
Share a tip, gotcha, or practical example. Keep it under 2000 characters. No questions (use the Asterisk community forums for support). Wrap code in backticks.