This made my head hurt.

master
Jay 2 years ago
commit 95046e1fd4

@ -0,0 +1,114 @@
Asterisk MusicOnHold Stuff For Custom
The way custom applications work with Asterisk, from my very very basic functional perspective is it expects 8khz PCM on stdin. So if you had a binary called "audioplayer" that played audio to stdout as raw 8khz PCM samples; then you'd just have to call that binary as a custom application in your musiconhold configuration:
```
[default]
mode = custom
application = /path/to/imaginary/binary
```
That's it. Provided it only literally sent data to stdout; this would work. But as I alluded to in the example; such a thing doesn't exist. Thankfully shell scripts count as applications and as long as we ultimately get some audio to stdout; it will work.
Icecast/Shoutcast Source Streams
This would be a lot easier if mplayer supported stdout; but it doesn't. So in order to make this work we need to make a named pipe, write to that pipe, and then somehow pipe the pipe to stdout.
```
#!/bin/bash
PIPE="/tmp/asterisk-pipe.$$"
mknod $PIPE p
mplayer -playlist http://host:port/playlist.m3u -really-quiet -quiet -ao pcm:file=$PIPE -af resample=8000,pan=1:0.5:0.5,channels=1,format=mulaw 2>/dev/null | cat $PIPE 2>/dev/null
rm $PIPE
```
Translating it in to a step-by-step list:
Define the path and name of our pipe using a pre-determined prefix and random number suffix.
Create this named pipe with mknod.
Play back the stream using mplayer; outputting PCM to the named pipe, resampled to 8khz, and downmixed.
CAT this pipe to stdout.
Delete the named pipe.
Originally this script had things to find existing pipes and delete them. Storing them in /tmp means they'll disappear on reboot. If things go right you won't need to constantly start and stop anything. You can however always look at running processes and see which pipes are being used.
The original version of my Classic Hold used this, in combination with icecast2 and ices2.
But surely we can do this without getting icecast ivolved....directly with applications.
Oh...sure...we can...but holy cow.
Classic Hold Version 2: Less Complex, More Headache
Let me start by saying this: getting this to work started out as medium-hard; before going full fledged pull-my-hair-out. This is because there's a number of additional steps we have to do that are much more involved than setting up and configuring icecast and ices2. Most of these steps were documented and I had to piece them together. This was on top of the fact that debugging on a headless machine for sound problems posed limitations. I had to test things on a local VM before attempting to implement them on the remote machine.
The concept sounds simple; just play some files from a playlist to a pipe; pipe it around; pipe it in to Asterisk. Okay, hold up. It sounds easy; but is it? There's a little issue in that if you tell most players you want to play back to a file and not a sound device; they decode, not play. We don't want, need, or can handle this. We need to simulate real-time playback. The only way to get this done effectively...was pulseaudio. I tried ALSA but this broke on ubuntu; they don't actually include the stuff to configure it. So you'll have a working alsa system; install alsa-utils, and lose it all.
But while we can create null sinks in PulseAudio stupid easily; there's a major drawback. It usually runs at the userlevel. Why does this matter? The asterisk user never actually logs in to the system...and therefore pulseaudio server never gets executed. So log in and activate? I tried that. So what you have to do...is run pulseaudio as system-wide and then configure it so the non-authenticated asterisk account can actually use it.
Install pulseaudio - `sudo apt install pulseaudio`
Create /etc/systemd/system/pulseaudio.service and fill it with this:
```
[Unit]
Description=PulseAudio Daemon
[Install]
WantedBy=multi-user.target
[Service]
Type=simple
PrivateTmp=true
ExecStart=/usr/bin/pulseaudio --system --realtime --disallow-exit --no-cpu-limit
```
Open `/etc/pulse/system.pa` in an edior and modify the `load-module module-native-protocol-unix` line:
```
load-module module-native-protocol-unix auth-anonymous=1
```
(Yes, you are just adding auth-anonymous=1 to it)
Now you'll want the null-sinks to persist; so add this line to the bottom of system.pa:
`load-module module-null-sink sink_name=moh1`
You can duplicate this line for as many null-sinks as you want. You don't need a sink for each stream.
Now refresh services and boot everything up.
```
sudo systemctl daemon reload
sudo systemctl enable pulseaudio
sudo systemctl start pulseaudio
```
Got it? Good. That's it. That took me forever to figure out. You're welcome.
For the rest of the stuff we're using ogg123 and sox; so install `vorbis-tools` and `sox`.
Create a shell script, somewhere asterisk can read it:
```
#!/bin/bash
ogg123 -qZ -d pulse -o sink:moh1 -d au -f - -@ /etc/asterisk/list.m3u 2>/dev/null | sox -r 16000 -t au - -r 8000 -c 1 -t raw - 2>/dev/null
```
That's it. It's a one-liner; but since it's piped we can't just stick it in musiconold.conf. We don't need named pipes beause ogg123 and sox both support stdin/stdout.
ogg123 randomly plays from the playlist to sink:moh as well as stdout. The playback to the sink is just to limit the thing to realtime playback. It's literally the only reason we need Pulse.
After that we pipe it in to sox, which resamples it from it's 16khz to 8khz and spits it to stdout. You can totally do this with just mplayer in a similar manner as above, just swapping your icecast playlist for the local one; keeping the same named pipe method. The problem I had with this (and went down this cliff of a different method); really nasty clicks between tracks. It was something between one player and the pipe.
Now I cannot say which method is "better". Ultimately I'm going to judge this by which method uses fewer cpu cycles. I'll run one method for a week, document how much CPU time it used; switch to the other for a week and compare. There may be a lot of additional overhead with pulseaudio, or ogg123 and sox may not be the most efficient way. I will update this later with my findings.
Your MOH streams may "skip" or have other minor defects for the first few minutes. Mine cleared up after a few minutes and sounded like they had less buffer issues than the icecast.
Loading…
Cancel
Save