I'm working on a small application to ring school bells on a schedule, which can be updated from a website. Everything is working great, except the script that is scheduled as a cron job won't play the sound when the script is run. I have added output piping and echo commands to the script to verify that cron is running it, but the part that plays the sound doesn't work. The script works as expected when run manually from CLI.
The script extracts a time and a sound file for each period of the day on the schedule, then compares the time associated to the sound file with the current time - if it's a match, it will
exec("/usr/bin/aplay /var/www/site/".$soundfile);
Cron is then scheduled to run this script every minute during the school day:
* 8-16 * 1-6,9-12 1-5 root /usr/bin/php -f /var/www/site/scripts/playsound.php > /dev/null
Again, if I manually run the script when there is sound scheduled, the sound plays through the attached speakers. When I have test code that will echo to the screen or output to a file entered as well, cron will dump the output to the files, confirming it is running the script as scheduled. It just won't play the darn sound part of the script.
I've checked all my permissions and since everything else works, they seem to be accurate. I can even write a simple BASH script to get Cron to play a sound on a schedule, so it seems the system has the right group memberships to access both script and sound file. I have switched out exec()
for shell_exec()
, tried using just the commands as well as the absolute paths to the commands, and the cron job is scheduled to run as root. Still can't figure out why this one small feature that is unfortunately so critical to this program succeeding won't work.
Any advice is greatly appreciated.
One of the most frequent causes for the crontab job not being correctly executed is that a cronjob does not run under the user's shell environment. Another reason can be – not specifying the absolute path of the commands used in the script.
The cron reads the crontab (cron tables) for running predefined scripts. By using a specific syntax, you can configure a cron job to schedule scripts or other commands to run automatically.
Probably permissions on /dev/snd/pcmC0D0p
are the problem. (That's the device for ALSA Card 0: Device 0: playback.) If there is a desktop session running on the server, it may have a pulseaudio daemon holding the device open.
Setting things up for multiple users to be able to play sound at the same time is a mess, and requires configuring pulseaudio in a low-performance mode that isn't zero-copy, so don't do that. Just make sure the server can exclusively open the sound device when needed.
To see whether an ALSA sound device is open or not (regardless of paused state or w/e):
$ cat /proc/asound/card0/pcm0p/sub0/hw_params
access: MMAP_INTERLEAVED
format: S16_LE
subformat: STD
channels: 2
rate: 44100 (44100/1)
period_size: 8192
buffer_size: 16384
$ cat /proc/asound/card0/pcm1p/sub0/hw_params
closed
So the first playback PCM on my first sound card is open, but the 2nd PCM (the S/PDIF output of my motherboard audio) is closed. Further opens of the sound device only work because the default ALSA setup makes the "default" device a pulseaudio wrapper. hw:0
would fail, because it's busy, and this sound card doesn't have a hardware mixer.
(Fun fact: some old soundcards, e.g. some PCI Soundblaster cards, supported multiple opens of the hardware device. Multiple streams of PCM data could be DMAed to the card, where they would be mixed by its DSP. Unless I'm totally wrong and the kernel driver was mixing >.< But anyway, you didn't need pulseaudio if you had one.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With