Audio plays from CLI, script but not from button element

Creating a bug report/issue

Required Information

  • DietPi version | G_DIETPI_VERSION_CORE=8
    G_DIETPI_VERSION_SUB=18
    G_DIETPI_VERSION_RC=2
    G_GITBRANCH=‘master’
    G_GITOWNER=‘MichaIng’
    G_LIVE_PATCH_STATUS[0]=‘not applicable’
  • Distro version | bullseye 1
  • Kernel version | Linux DietPi 6.1.21+ #1642 Mon Apr 3 17:19:14 BST 2023 armv6l GNU/Linux
  • Architecture | armhf
  • SBC model | RPi W0
  • Power supply used | laptop USB
  • SD card used | generic 8G

Additional Information (if applicable)

Steps to reproduce

  1. …install lighttpd
  2. …enable cgi
  3. set up bluetooth
  4. connect to speaker
  5. set up bluealsa
  6. test by playing audio through speaker
  7. ./voice.sh (plays file ok)
  8. upload voicetest.html
  9. push screen button to activate voice.sh

Expected behaviour

  • file playback

Actual behaviour

  • browser downloads file named voice.sh which contains ONLY the word ‘warning’. NO audio

Extra details

  • …playback of an audio file from a webpage:

lighttpd server user/group www-data


<html>
<!-- voicetestPreformatted text.html -->
<FORM ACTION="http://10.0.0.209/cgi-bin/voice.sh" METHOD="GET">
<input type="submit" value="play a sound">
</form>
</html>

#!/bin/bash
#  voice.sh
aplay -D bluealsa /var/www/html/cgi-bin/warning.wav
echo warning
exit 0


webpages in /var/www/html
cgi appears to be setup correctly
all files owned by www-data permission 755

voice.sh works standalone
www-data user member of audio group

lizard@DietPi:/var/www/html/cgi-bin$ aplay -L
null
    Discard all samples (playback) or generate zero samples (capture)
bluealsa
    Bluetooth Audio Hub



alizard@DietPi:/etc$ cat .asoundrc 
# /etc/.asoundrc
defaults.bluealsa.interface "hci0"
defaults.bluealsa.service "org.bluealsa"
defaults.bluealsa.device "C5:61:7C:9C:9C:77"
defaults.bluealsa.profile "a2dp-source"
defaults.bluealsa.delay 10000


defaults.!pcm { type plug; master.pcm "bluealsa"};
alizard@DietPi:/etc$ cat asound.conf 
pcm.!default {
        type plug
        slave.pcm {
                type hw
                card 0
                device 0
        }
}

ctl.!default {
        type hw
        card 0
}

f
alizard@DietPi:~$ 
alizard@DietPi:~$ cat /etc/lighttpd/lighttpd.conf 
server.modules = (
        "mod_indexfile",
        "mod_access",
        "mod_alias",
        "mod_redirect",
)

server.document-root        = "/var/www/html"
server.upload-dirs          = ( "/var/cache/lighttpd/uploads" )
server.errorlog             = "/var/log/lighttpd/error.log"
server.pid-file             = "/run/lighttpd.pid"
server.username             = "www-data"
server.groupname            = "www-data"
server.port                 = 80

# features
#https://redmine.lighttpd.net/projects/lighttpd/wiki/Server_feature-flagsDetails
server.feature-flags       += ("server.h2proto" => "enable")
server.feature-flags       += ("server.h2c"     => "enable")
server.feature-flags       += ("server.graceful-shutdown-timeout" => 5)
#server.feature-flags       += ("server.graceful-restart-bg" => "enable")

# strict parsing and normalization of URL for consistency and security
# https://redmine.lighttpd.net/projects/lighttpd/wiki/Server_http-parseoptsDetails
# (might need to explicitly set "url-path-2f-decode" = "disable"
#  if a specific application is encoding URLs inside url-path)
server.http-parseopts = (
  "header-strict"           => "enable",# default
  "host-strict"             => "enable",# default
  "host-normalize"          => "enable",# default
  "url-normalize-unreserved"=> "enable",# recommended highly
  "url-normalize-required"  => "enable",# recommended
  "url-ctrls-reject"        => "enable",# recommended
  "url-path-2f-decode"      => "enable",# recommended highly (unless breaks app)
 #"url-path-2f-reject"      => "enable",
  "url-path-dotseg-remove"  => "enable",# recommended highly (unless breaks app)
 #"url-path-dotseg-reject"  => "enable",
 #"url-query-20-plus"       => "enable",# consistency in query string
)

index-file.names            = ( "control_panel.html" )
url.access-deny             = ( "~", ".inc" )
static-file.exclude-extensions = ( ".php", ".pl", ".fcgi", ".sh" )

# default listening port for IPv6 falls back to the IPv4 port
include_shell "/usr/share/lighttpd/use-ipv6.pl " + server.port
include_shell "/usr/share/lighttpd/create-mime.conf.pl"
include "/etc/lighttpd/conf-enabled/*.conf"

#server.compat-module-load   = "disable"
server.modules += (
        "mod_dirlisting",
        "mod_staticfile",
)
 
alizard@DietPi:~$ cat /etc/lighttpd/conf-enabled/10-cgi.conf
# /usr/share/doc/lighttpd/cgi.txt

server.modules += ( "mod_cgi" )

$HTTP["url"] =~ "^/cgi-bin/" {
        cgi.assign = ( ".sh" => "/usr/bin/bash" )
        alias.url += ( "/cgi-bin/" => "/var/www/html/cgi-bin/" )
}

## Warning this represents a security risk, as it allow to execute any file
## with a .pl/.py even outside of /usr/lib/cgi-bin.
#
#cgi.assign      = (
#       ".pl"  => "/usr/bin/perl",
#       ".py"  => "/usr/bin/python",
#)

If you do this (and it would work) it would play an audio file on the server, not on the client.
It triggers the script on the server, and then on the server aplay gets executed. Buw how ill the client will hear this? It’s impossible.
You would need something like this:

<!doctype html>
<html>
  <head>
    <title>Audio</title>
  </head>
  <body>

    <script>
      function play() {
        var audio = document.getElementById("audio");
        audio.play();
      }
    </script>

    <input type="button" value="PLAY" onclick="play()">
    <audio id="audio" src="https://interactive-examples.mdn.mozilla.net/media/cc0-audio/t-rex-roar.mp3"></audio>

  </body>
</html>

https://stackoverflow.com/a/18826567

EDIT:

If you really want that somebody clicks the button and then a sound gets played on the server machine, you would need to use the php function shell_exec() or exec(). So somebody clicks the button and then a shell command (aplay -D bluealsa /var/www/html/cgi-bin/warning.wav)is executed on the server.
https://www.php.net/manual/en/function.shell-exec.php

Edit 2:

If you want to execute it in cgi-bin, the script needs a content type header:

#!/bin/sh
printf "Content-Type: text/plain\n\n"
your_commands_here
1 Like

i want the audio file to play back on the speaker connected to the server via bluetooth. for some reason, aplay doesn’t execute. tried adding content header - no change.

#!/bin/bash
printf "Content-Type: text/plain\n\n"
aplay -D bluealsa /var/www/html/cgi-bin/warning.wav
echo warning
exit 0

You need to use the full path to aplay inside .sh scripts.
To get the full path: which aplay

warning displays in browser. otherwise no change
#!/bin/bash
printf “Content-Type: text/plain\n\n”
/usr/bin/aplay -D bluealsa /var/www/html/cgi-bin/warning.wav
echo warning
exit 0

Hm maybe it’s a permission issue. With what user did you try vom CLI?
The webserver uses the user www-data. Maybe the server logs can give you some hints.

all html/cgi owned by www-data. all 755
cli run by me - alizard user

www-data is inaccessible.
i tried changing lighttpd user to www, created earlier as user account with logon. 
www@DietPi:/var/www/html/cgi-bin$ groups www
www : www mail voice audio bluetooth
when i ran voice.sh:
www@DietPi:/var/www/html/cgi-bin$ ./voice.sh 
Content-Type: text/plain

ALSA lib confmisc.c:1281:(snd_func_refer) Unable to find definition 'defaults.bluealsa.device'
ALSA lib conf.c:4745:(_snd_config_evaluate) function snd_func_refer returned error: No such file or directory
ALSA lib conf.c:5222:(snd_config_expand) Args evaluate error: No such file or directory
ALSA lib pcm.c:2660:(snd_pcm_open_noupdate) Unknown PCM bluealsa
aplay: main:830: audio open error: No such file or directory
warning

same thing happens from root

Yes, this is intended, for security reasons. I wonder where the group www comes from, did you create it?
Unfortunately I can not help you with the errors you are facing.

But I did some similiar thing in the past with php, instead of CGI-bin.

I had a webpage to start a game server, when users clicked the button an ssh-connection got invoked to the game server and then executed a bash command. In your case you would not need the ssh part. It could looke something like this:
HTML-Button:

<a href="#" onclick="start();">
do something
</a>

php function start():

function start() {
          $.get("start.php");
          return false;
        }

start.php:

<?php
exec('/usr/bin/aplay -D bluealsa /var/www/html/cgi-bin/warning.wav');
?>

Maybe not the most elegant way, but it worked :smiley:
But you would also to make sure that aplay can be run by the user www-data.

worth a try. do i need php for this? i’ve never used it.

looks like start/get exist in bash