balena-io-experimental / audio Goto Github PK
View Code? Open in Web Editor NEWAudio building block for balenaOS, based on pulseaudio.
Home Page: https://hub.balena.io/blocks
Audio building block for balenaOS, based on pulseaudio.
Home Page: https://hub.balena.io/blocks
Pin package version to avoid updating to an untested release.
I'm trying to run the examples on Rpi 4 but I get Cannot find card '0'
.
To reproduce:
I start the audio service:
balena-engine run --privileged -d -p 4317:4317 -v pulse:/run/pulse balenablocks/audio
On my dev machine, I cd into the respective example directory and execute balena push <local-address>
I start the bash to play the audio in a container:
balena-engine exec -it <uuid> bash
root@d3f4184:/usr/src# mplayer test.wav
Creating config file: /root/.mplayer/config
MPlayer 1.4 (Debian), built with gcc-10 (C) 2000-2019 MPlayer Team
do_connect: could not connect to socket
connect: No such file or directory
Failed to open LIRC support. You will not be able to use your remote control.
Playing test.wav.
libavformat version 58.45.100 (external)
Audio only file format detected.
Load subtitles in ./
==========================================================================
Opening audio decoder: [pcm] Uncompressed PCM audio decoder
AUDIO: 48000 Hz, 2 ch, s16le, 1536.0 kbit/100.00% (ratio: 192000->192000)
Selected audio codec: [pcm] afm: pcm (Uncompressed PCM)
==========================================================================
AO: [pulse] Init failed: Connection refused
Failed to initialize audio driver 'pulse'
[AO_ALSA] alsa-lib: confmisc.c:767:(parse_card) cannot find card '0'
[AO_ALSA] alsa-lib: conf.c:4745:(_snd_config_evaluate) function snd_func_card_driver returned error: No such file or directory
[AO_ALSA] alsa-lib: confmisc.c:392:(snd_func_concat) error evaluating strings
[AO_ALSA] alsa-lib: conf.c:4745:(_snd_config_evaluate) function snd_func_concat returned error: No such file or directory
[AO_ALSA] alsa-lib: confmisc.c:1246:(snd_func_refer) error evaluating name
[AO_ALSA] alsa-lib: conf.c:4745:(_snd_config_evaluate) function snd_func_refer returned error: No such file or directory
[AO_ALSA] alsa-lib: conf.c:5233:(snd_config_expand) Evaluate error: No such file or directory
[AO_ALSA] alsa-lib: pcm.c:2660:(snd_pcm_open_noupdate) Unknown PCM default
[AO_ALSA] Playback open error: No such file or directory
Failed to initialize audio driver 'alsa'
[AO SDL] Samplerate: 48000Hz Channels: Stereo Format s16le
[AO SDL] using aalib audio driver.
[AO SDL] Unable to open audio: No available audio device
Failed to initialize audio driver 'sdl:aalib'
Could not open/initialize audio device -> no sound.
Audio: no sound
Video: no video
root@d3f4184:/usr/src# python play.py
ALSA lib confmisc.c:767:(parse_card) cannot find card '0'
ALSA lib conf.c:4568:(_snd_config_evaluate) function snd_func_card_driver returned error: No such file or directory
ALSA lib confmisc.c:392:(snd_func_concat) error evaluating strings
ALSA lib conf.c:4568:(_snd_config_evaluate) function snd_func_concat returned error: No such file or directory
ALSA lib confmisc.c:1246:(snd_func_refer) error evaluating name
ALSA lib conf.c:4568:(_snd_config_evaluate) function snd_func_refer returned error: No such file or directory
ALSA lib conf.c:5047:(snd_config_expand) Evaluate error: No such file or directory
ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM default
Traceback (most recent call last):
File "play.py", line 4, in <module>
play_obj = wave_obj.play()
File "/usr/local/lib/python3.5/site-packages/simpleaudio/shiny.py", line 20, in play
self.bytes_per_sample, self.sample_rate)
File "/usr/local/lib/python3.5/site-packages/simpleaudio/shiny.py", line 61, in play_buffer
sample_rate)
_simpleaudio.SimpleaudioError: Error opening PCM device. -- CODE: -2 -- MSG: No such file or directory
root@d3f4184:/usr/src# node play.js
Running PLAY script with the following configuration:
PULSE_SERVER: unix:/run/pulse/pulseaudio.socket
PULSE_SINK: undefined
This script will grab a wav file and output audio to PULSE_SINK (if undefined sink will be default for PULSE_SERVER).
context: connecting
context: failed
events.js:291
^
Error: Access denied
at /usr/src/node_modules/pulseaudio2/lib/pulse.js:121:21
at processTicksAndRejections (internal/process/task_queues.js:79:11)
Emitted 'error' event on Context instance at:
at /usr/src/node_modules/pulseaudio2/lib/pulse.js:123:22
at processTicksAndRejections (internal/process/task_queues.js:79:11)
root@d3f4184:/usr/src# play test.wav
play FAIL sox: Sorry, there is no default audio device configured
After adding libsox-fmt-all to install_packages in examples/sox/Dockerfile.template
root@d3f4184:/usr/src# play test.wav
ALSA lib confmisc.c:767:(parse_card) cannot find card '0'
ALSA lib conf.c:4745:(_snd_config_evaluate) function snd_func_card_driver returned error: No such file or directory
ALSA lib confmisc.c:392:(snd_func_concat) error evaluating strings
ALSA lib conf.c:4745:(_snd_config_evaluate) function snd_func_concat returned error: No such file or directory
ALSA lib confmisc.c:1246:(snd_func_refer) error evaluating name
ALSA lib conf.c:4745:(_snd_config_evaluate) function snd_func_refer returned error: No such file or directory
ALSA lib conf.c:5233:(snd_config_expand) Evaluate error: No such file or directory
ALSA lib pcm.c:2660:(snd_pcm_open_noupdate) Unknown PCM default
play FAIL ao: Could not open device: error 5
play FAIL sox: Sorry, there is no default audio device configured
the pulseaudio2
library from the nodjes example does not compile, but gives the error:
[Build] > [email protected] install /usr/src/node_modules/pulseaudio2
[Build] > node-gyp configure build
[Build] [nodejs] make: Entering directory '/usr/src/node_modules/pulseaudio2/build'
[Build] [nodejs] CXX(target) Release/obj.target/pulse/src/context.o
[Build] [nodejs] In file included from ../src/common.hh:28,
[Build] from ../src/context.hh:23,
[Build] from ../src/context.cc:20:
[Build] ../../nan/nan.h: In function ‘void Nan::AsyncQueueWorker(Nan::AsyncWorker*)’:
[Build] ../../nan/nan.h:2294:62: warning: cast between incompatible function types from ‘void (*)(uv_work_t*)’ {aka ‘void (*)(uv_work_s*)’} to ‘uv_after_work_cb’ {aka ‘void (*)(uv_work_s*, int)’} [-Wcast-function-type]
[Build] , reinterpret_cast<uv_after_work_cb>(AsyncExecuteComplete)
[Build] ^
[Build]
[Build] [nodejs] In file included from ../src/common.hh:27,
[Build] from ../src/context.hh:23,
[Build] from ../src/context.cc:20:
[Build] /root/.cache/node-gyp/10.22.0/include/node/v8.h: In instantiation of ‘void v8::PersistentBase<T>::SetWeak(P*, typename v8::WeakCallbackInfo<P>::Callback, v8::WeakCallbackType) [with P = node::ObjectWrap; T = v8::Object; typename v8::WeakCallbackInfo<P>::Callback = void (*)(const v8::WeakCallbackInfo<node::ObjectWrap>&)]’:
[Build] /root/.cache/node-gyp/10.22.0/include/node/node_object_wrap.h:84:78: required from here
[Build] /root/.cache/node-gyp/10.22.0/include/node/v8.h:9502:16: warning: cast between incompatible function types from ‘v8::WeakCallbackInfo<node::ObjectWrap>::Callback’ {aka ‘void (*)(const v8::WeakCallbackInfo<node::ObjectWrap>&)’} to ‘Callback’ {aka ‘void (*)(const v8::WeakCallbackInfo<void>&)’} [-Wcast-function-type]
[Build] reinterpret_cast<Callback>(callback), type);
[Build] ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[Build]
[Build] [nodejs] /root/.cache/node-gyp/10.22.0/include/node/v8.h: In instantiation of ‘void v8::PersistentBase<T>::SetWeak(P*, typename v8::WeakCallbackInfo<P>::Callback, v8::WeakCallbackType) [with P = Nan::ObjectWrap; T = v8::Object; typename v8::WeakCallbackInfo<P>::Callback = void (*)(const v8::WeakCallbackInfo<Nan::ObjectWrap>&)]’:
[Build] ../../nan/nan_object_wrap.h:65:61: required from here
[Build] /root/.cache/node-gyp/10.22.0/include/node/v8.h:9502:16: warning: cast between incompatible function types from ‘v8::WeakCallbackInfo<Nan::ObjectWrap>::Callback’ {aka ‘void (*)(const v8::WeakCallbackInfo<Nan::ObjectWrap>&)’} to ‘Callback’ {aka ‘void (*)(const v8::WeakCallbackInfo<void>&)’} [-Wcast-function-type]
[Build]
[Build] [nodejs] CXX(target) Release/obj.target/pulse/src/stream.o
[Build] [nodejs] In file included from ../src/common.hh:28,
[Build] from ../src/stream.hh:23,
[Build] from ../src/stream.cc:20:
[Build] ../../nan/nan.h: In function ‘void Nan::AsyncQueueWorker(Nan::AsyncWorker*)’:
[Build] ../../nan/nan.h:2294:62: warning: cast between incompatible function types from ‘void (*)(uv_work_t*)’ {aka ‘void (*)(uv_work_s*)’} to ‘uv_after_work_cb’ {aka ‘void (*)(uv_work_s*, int)’} [-Wcast-function-type]
[Build] , reinterpret_cast<uv_after_work_cb>(AsyncExecuteComplete)
[Build] ^
[Build]
[Build] [nodejs] In file included from ../src/common.hh:27,
[Build] from ../src/stream.hh:23,
[Build] from ../src/stream.cc:20:
[Build] /root/.cache/node-gyp/10.22.0/include/node/v8.h: In instantiation of ‘void v8::PersistentBase<T>::SetWeak(P*, typename v8::WeakCallbackInfo<P>::Callback, v8::WeakCallbackType) [with P = node::ObjectWrap; T = v8::Object; typename v8::WeakCallbackInfo<P>::Callback = void (*)(const v8::WeakCallbackInfo<node::ObjectWrap>&)]’:
[Build] /root/.cache/node-gyp/10.22.0/include/node/node_object_wrap.h:84:78: required from here
[Build] /root/.cache/node-gyp/10.22.0/include/node/v8.h:9502:16: warning: cast between incompatible function types from ‘v8::WeakCallbackInfo<node::ObjectWrap>::Callback’ {aka ‘void (*)(const v8::WeakCallbackInfo<node::ObjectWrap>&)’} to ‘Callback’ {aka ‘void (*)(const v8::WeakCallbackInfo<void>&)’} [-Wcast-function-type]
[Build] reinterpret_cast<Callback>(callback), type);
[Build] ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[Build]
[Build] [nodejs] /root/.cache/node-gyp/10.22.0/include/node/v8.h: In instantiation of ‘void v8::PersistentBase<T>::SetWeak(P*, typename v8::WeakCallbackInfo<P>::Callback, v8::WeakCallbackType) [with P = Nan::ObjectWrap; T = v8::Object; typename v8::WeakCallbackInfo<P>::Callback = void (*)(const v8::WeakCallbackInfo<Nan::ObjectWrap>&)]’:
[Build] ../../nan/nan_object_wrap.h:65:61: required from here
[Build] /root/.cache/node-gyp/10.22.0/include/node/v8.h:9502:16: warning: cast between incompatible function types from ‘v8::WeakCallbackInfo<Nan::ObjectWrap>::Callback’ {aka ‘void (*)(const v8::WeakCallbackInfo<Nan::ObjectWrap>&)’} to ‘Callback’ {aka ‘void (*)(const v8::WeakCallbackInfo<void>&)’} [-Wcast-function-type]
[Build]
[Build] [nodejs] CXX(target) Release/obj.target/pulse/src/uv-mainloop.o
[Build] [nodejs] In file included from ../src/common.hh:28,
[Build] from ../src/context.hh:23,
[Build] from ../src/uv-mainloop.cc:20:
[Build] ../../nan/nan.h: In function ‘void Nan::AsyncQueueWorker(Nan::AsyncWorker*)’:
[Build] ../../nan/nan.h:2294:62: warning: cast between incompatible function types from ‘void (*)(uv_work_t*)’ {aka ‘void (*)(uv_work_s*)’} to ‘uv_after_work_cb’ {aka ‘void (*)(uv_work_s*, int)’} [-Wcast-function-type]
[Build] , reinterpret_cast<uv_after_work_cb>(AsyncExecuteComplete)
[Build] ^
[Build]
[Build] [nodejs] In file included from ../src/common.hh:27,
[Build] from ../src/context.hh:23,
[Build] from ../src/uv-mainloop.cc:20:
[Build] /root/.cache/node-gyp/10.22.0/include/node/v8.h: In instantiation of ‘void v8::PersistentBase<T>::SetWeak(P*, typename v8::WeakCallbackInfo<P>::Callback, v8::WeakCallbackType) [with P = node::ObjectWrap; T = v8::Object; typename v8::WeakCallbackInfo<P>::Callback = void (*)(const v8::WeakCallbackInfo<node::ObjectWrap>&)]’:
[Build] /root/.cache/node-gyp/10.22.0/include/node/node_object_wrap.h:84:78: required from here
[Build] /root/.cache/node-gyp/10.22.0/include/node/v8.h:9502:16: warning: cast between incompatible function types from ‘v8::WeakCallbackInfo<node::ObjectWrap>::Callback’ {aka ‘void (*)(const v8::WeakCallbackInfo<node::ObjectWrap>&)’} to ‘Callback’ {aka ‘void (*)(const v8::WeakCallbackInfo<void>&)’} [-Wcast-function-type]
[Build] reinterpret_cast<Callback>(callback), type);
[Build] ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[Build]
[Build] [nodejs] /root/.cache/node-gyp/10.22.0/include/node/v8.h: In instantiation of ‘void v8::PersistentBase<T>::SetWeak(P*, typename v8::WeakCallbackInfo<P>::Callback, v8::WeakCallbackType) [with P = Nan::ObjectWrap; T = v8::Object; typename v8::WeakCallbackInfo<P>::Callback = void (*)(const v8::WeakCallbackInfo<Nan::ObjectWrap>&)]’:
[Build] ../../nan/nan_object_wrap.h:65:61: required from here
[Build] /root/.cache/node-gyp/10.22.0/include/node/v8.h:9502:16: warning: cast between incompatible function types from ‘v8::WeakCallbackInfo<Nan::ObjectWrap>::Callback’ {aka ‘void (*)(const v8::WeakCallbackInfo<Nan::ObjectWrap>&)’} to ‘Callback’ {aka ‘void (*)(const v8::WeakCallbackInfo<void>&)’} [-Wcast-function-type]
[Build]
[Build] [nodejs] CXX(target) Release/obj.target/pulse/src/addon.o
[Build] [nodejs] In file included from ../src/common.hh:28,
[Build] from ../src/addon.cc:20:
[Build] ../../nan/nan.h: In function ‘void Nan::AsyncQueueWorker(Nan::AsyncWorker*)’:
[Build] ../../nan/nan.h:2294:62: warning: cast between incompatible function types from ‘void (*)(uv_work_t*)’ {aka ‘void (*)(uv_work_s*)’} to ‘uv_after_work_cb’ {aka ‘void (*)(uv_work_s*, int)’} [-Wcast-function-type]
[Build] , reinterpret_cast<uv_after_work_cb>(AsyncExecuteComplete)
[Build] ^
[Build]
[Build] [nodejs] In file included from ../../nan/nan.h:56,
[Build] from ../src/common.hh:28,
[Build] from ../src/addon.cc:20:
[Build] ../src/addon.cc: At global scope:
[Build] /root/.cache/node-gyp/10.22.0/include/node/node.h:573:43: warning: cast between incompatible function types from ‘void (*)(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE)’ {aka ‘void (*)(v8::Local<v8::Object>)’} to ‘node::addon_register_func’ {aka ‘void (*)(v8::Local<v8::Object>, v8::Local<v8::Value>, void*)’} [-Wcast-function-type]
[Build] (node::addon_register_func) (regfunc), \
[Build] ^
[Build] /root/.cache/node-gyp/10.22.0/include/node/node.h:607:3: note: in expansion of macro ‘NODE_MODULE_X’
[Build] NODE_MODULE_X(modname, regfunc, NULL, 0) // NOLINT (readability/null_usage)
[Build] ^~~~~~~~~~~~~
[Build] ../src/addon.cc:30:1: note: in expansion of macro ‘NODE_MODULE’
[Build] NODE_MODULE(NODE_GYP_MODULE_NAME, node_pulseaudio_init)
[Build] ^~~~~~~~~~~
[Build]
[Build] [nodejs] In file included from ../src/common.hh:27,
[Build] from ../src/addon.cc:20:
[Build] /root/.cache/node-gyp/10.22.0/include/node/v8.h: In instantiation of ‘void v8::PersistentBase<T>::SetWeak(P*, typename v8::WeakCallbackInfo<P>::Callback, v8::WeakCallbackType) [with P = node::ObjectWrap; T = v8::Object; typename v8::WeakCallbackInfo<P>::Callback = void (*)(const v8::WeakCallbackInfo<node::ObjectWrap>&)]’:
[Build] /root/.cache/node-gyp/10.22.0/include/node/node_object_wrap.h:84:78: required from here
[Build] /root/.cache/node-gyp/10.22.0/include/node/v8.h:9502:16: warning: cast between incompatible function types from ‘v8::WeakCallbackInfo<node::ObjectWrap>::Callback’ {aka ‘void (*)(const v8::WeakCallbackInfo<node::ObjectWrap>&)’} to ‘Callback’ {aka ‘void (*)(const v8::WeakCallbackInfo<void>&)’} [-Wcast-function-type]
[Build] reinterpret_cast<Callback>(callback), type);
[Build] ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[Build]
[Build] [nodejs] /root/.cache/node-gyp/10.22.0/include/node/v8.h: In instantiation of ‘void v8::PersistentBase<T>::SetWeak(P*, typename v8::WeakCallbackInfo<P>::Callback, v8::WeakCallbackType) [with P = Nan::ObjectWrap; T = v8::Object; typename v8::WeakCallbackInfo<P>::Callback = void (*)(const v8::WeakCallbackInfo<Nan::ObjectWrap>&)]’:
[Build] ../../nan/nan_object_wrap.h:65:61: required from here
[Build] /root/.cache/node-gyp/10.22.0/include/node/v8.h:9502:16: warning: cast between incompatible function types from ‘v8::WeakCallbackInfo<Nan::ObjectWrap>::Callback’ {aka ‘void (*)(const v8::WeakCallbackInfo<Nan::ObjectWrap>&)’} to ‘Callback’ {aka ‘void (*)(const v8::WeakCallbackInfo<void>&)’} [-Wcast-function-type]
[Build]
[Build] [nodejs] SOLINK_MODULE(target) Release/obj.target/pulse.node
[Build] [nodejs] COPY Release/pulse.node
[Build] [nodejs] make: Leaving directory '/usr/src/node_modules/pulseaudio2/build'
[Build] [nodejs] npm notice
[Build] [nodejs] created a lockfile as package-lock.json. You should commit this file.
[Build]
[Build] [nodejs] npm WARN
[Build] [nodejs] [email protected] No repository field.
[Build]
[Build] [nodejs]
[Build]
[Build] [nodejs] updated 17 packages and audited 17 packages in 30.861s
[Build] [nodejs] found 0 vulnerabilities
[Build] [nodejs] Removing intermediate container e5c2898dd987
[Build] [nodejs] ---> 2a30e1f8fe2a
[Build] [nodejs] Step 8/11 : RUN curl https://www.kozco.com/tech/LRMonoPhase4.wav --silent --output test.wav
[Build] [nodejs] ---> Running in 73e09e54b1cb
[Build] [nodejs] Removing intermediate container 73e09e54b1cb
[Build] [nodejs] ---> 91a0804abef8
[Build] [nodejs] Step 9/11 : CMD [ "balena-idle" ]
[Build] [nodejs] ---> Running in 164f59e18237
[Build] [nodejs] Removing intermediate container 164f59e18237
[Build] [nodejs] ---> 5ae28e96056a
[Build] [nodejs] Step 10/11 : LABEL io.resin.local.image=1
[Build] [nodejs] ---> Running in 9951b344c36c
[Build] [nodejs] Removing intermediate container 9951b344c36c
[Build] [nodejs] ---> bb766cd1cffc
[Build] [nodejs] Step 11/11 : LABEL io.resin.local.service=nodejs
[Build] [nodejs] ---> Running in 38ec633f7378
[Build] [nodejs] Removing intermediate container 38ec633f7378
[Build] [nodejs] ---> e971a503f64a
[Build] [nodejs] Successfully built e971a503f64a
[Build] [nodejs] Successfully tagged local_image_nodejs:latest
[Live] Waiting for device state to settle...
This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason:
Error: No native build was found for platform=linux arch=x64 runtime=node abi=64 uv=1 libc=glibc node=10.21.0
loaded from: /usr/bin/ref-napi
at Function.load.path (/snapshot/versioned-source/node_modules/node-gyp-build/index.js:62:9)
at load (/snapshot/versioned-source/node_modules/node-gyp-build/index.js:21:30)
at Object.<anonymous> (/snapshot/versioned-source/node_modules/ref-napi/lib/ref.js:8:53)
at Module._compile (pkg/prelude/bootstrap.js:1325:22)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:787:10)
at Module.load (internal/modules/cjs/loader.js:651:32)
at tryModuleLoad (internal/modules/cjs/loader.js:591:12)
at Function.Module._load (internal/modules/cjs/loader.js:583:3)
at Module.require (internal/modules/cjs/loader.js:690:17)
at Module.require (pkg/prelude/bootstrap.js:1230:31)
at require (internal/modules/cjs/helpers.js:25:18)
at Object.<anonymous> (/snapshot/versioned-source/node_modules/net-keepalive/lib/index.js:24:9)
at Module._compile (pkg/prelude/bootstrap.js:1325:22)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:787:10)
at Module.load (internal/modules/cjs/loader.js:651:32)
at tryModuleLoad (internal/modules/cjs/loader.js:591:12)
Have tried downgrading to node version 10 (from 12), downgrading pulseaudio
to 0.3.1
(from 0.3.3
), and tested on ARM 32-bit and 64-bit on the raspberry pi.
For primitive use only.
C library:
TCP socket based with js:
JS library with C bindings:
DBUS (see #3):
Add scripts users can run to troubleshoot different scenarios.
Also useful to gather system data for support cases.
See: https://github.com/alexa-pi/AlexaPi/wiki/Audio-setup-&-debugging
A user has asked about adding support for this container on the nano pi air in the docker registry for the balena sound project
Device sound cards will be preconfigured and exposed to pulseaudio for supported devices with no extra configuration needed.
Raspberry Pi 3:
Raspberry Pi 4:
Create a minimal dockerfile capable of running pulseaudio daemon
Expose events such as “audio started/stopped playing” to allow other containers to react
Events:
start
: A pulseaudio source started streamingstop
: A pulseaudio source stopped streamingSystem mode for pulseaudio daemon is meant to be used in embedded setups where the concept of users doesn't make much sense. There are some drawbacks of using system mode, most notably that pacmd
doesn't work (and devs seem to not give system mode much attention).
https://www.freedesktop.org/wiki/Software/PulseAudio/Documentation/User/SystemWide/
Use module-udev-detect
instead of manually loading alsa modules.
Need to add UDEV=1
to enable udev in balenaOS container.
Expose EQ functionality via API
DBus communication with PulseAudio won’t work as it’s not currently supported in the hostOS. We could spin a local dbus instance so that other containers can connect to it via DBUS.
The audio
block takes a few seconds to startup so adding a few retries to the connect
method would allow it enough time to initialise for applications that rely on it during startup. Example: connect
requires /run/pulse/pulseaudio.cookie
file to extist.
Currently we are running PulseAudio v13
Alpine version | PulseAudio version | Release Date |
---|---|---|
3.12 | 13.0-r10 | Sept 2019 |
3.13 | 14.1-r0 | Jan 2021 |
3.14 | 14.2-r5 | Jan 2021 |
3.15 | 15.0-r2 | Jul 2021 |
References:
Using this issue to track the underruns investigation. The warning that gets logged:
W: [pulseaudio] module-loopback.c: Too many underruns, increasing latency to 320.00 ms
Related links:
Expose means to manipulate volume. Could be via an API or GUI.
setVolume
getVolume
Make it clear how to use the block and what differs between alsa bridge, regular usage, etc.
Description
Choppy audio and it lags when starting playback. Same symptoms as #17.
Affected devices
All.
Steps to reproduce
Doesn't happen every time, but:
After a while it solves itself (or after stopping and playing a few times). Looks to be related to how PA handles buffered audio in high latency scenarios.
When running for example pactl list cards
in pulsetest
container the daemon gets shutdown with:
[pulseaudio] core.c: We are idle, quitting...
[pulseaudio] main.c: Daemon shutdown initiated.
As per this bug report, adding the flag --exit-idle-time=-1
prevents this from happening.
Description
Steps to reproduce
Could not isolate a reproducible scenario but encountered this a few times with my Android phone. I suspect it's related to one of the following:
headset_head_unit: Headset Head Unit (HSP/HFP)
present in this phone but not in other devicesDescription
Affected devices
This is likely related to headset_audio_gateway
profiles getting in the way, or at least I haven't seen this problem with a2dp
only devices.
Steps to reproduce
It happens occasionally when starting playback, specially after at least 5 seconds of not streaming audio (5 seconds is the default time where PA sources go from RUNNING to IDLE).
Logs
[pulseaudio] backend-native.c: Lost RFCOMM connection.
[pulseaudio] bluez5-util.c: Transport /org/bluez/hci0/dev_40_4E_36_42_9A_36/fd30 state: idle -> disconnected
[pulseaudio] card.c: Setting card bluez_card.40_4E_36_42_9A_36 profile headset_audio_gateway to availability status no
[pulseaudio] device-port.c: Setting port phone-output to status no
[pulseaudio] core-subscribe.c: Dropped redundant event due to change event.
[pulseaudio] bluez5-util.c: Properties changed in device /org/bluez/hci0/dev_40_4E_36_42_9A_36
[pulseaudio] bluez5-util.c: dbus: path=/MediaEndpoint/A2DPSink/sbc, interface=org.bluez.MediaEndpoint1, member=ClearConfiguration
[pulseaudio] bluez5-util.c: Clearing transport /org/bluez/hci0/dev_40_4E_36_42_9A_36/fd153 profile a2dp_source
[pulseaudio] bluez5-util.c: Transport /org/bluez/hci0/dev_40_4E_36_42_9A_36/fd153 state: idle -> disconnected
[pulseaudio] card.c: Setting card bluez_card.40_4E_36_42_9A_36 profile a2dp_source to availability status no
[pulseaudio] device-port.c: Setting port phone-input to status no
[pulseaudio] core-subscribe.c: Dropped redundant event due to change event.
[pulseaudio] module-bluez5-discover.c: Unregistering module for /org/bluez/hci0/dev_40_4E_36_42_9A_36
[pulseaudio] module-bluez5-device.c: Unloading module for device /org/bluez/hci0/dev_40_4E_36_42_9A_36
[pulseaudio] card.c: Freed 2 "bluez_card.40_4E_36_42_9A_36"
[pulseaudio] core-subscribe.c: Dropped redundant event due to remove event.
[pulseaudio] module.c: Unloaded "module-bluez5-device" (index: #28).
[pulseaudio] bluez5-util.c: Properties changed in device /org/bluez/hci0/dev_40_4E_36_42_9A_36
[pulseaudio] bluez5-util.c: dbus: path=/MediaEndpoint/A2DPSink/sbc, interface=org.bluez.MediaEndpoint1, member=SelectConfiguration
[pulseaudio] bluez5-util.c: Unknown interface org.freedesktop.DBus.Introspectable found, skipping
[pulseaudio] bluez5-util.c: Unknown interface org.bluez.MediaTransport1 found, skipping
[pulseaudio] bluez5-util.c: Unknown interface org.freedesktop.DBus.Properties found, skipping
[pulseaudio] bluez5-util.c: dbus: path=/MediaEndpoint/A2DPSink/sbc, interface=org.bluez.MediaEndpoint1, member=SetConfiguration
[pulseaudio] bluez5-util.c: Transport /org/bluez/hci0/dev_40_4E_36_42_9A_36/fd154 state: disconnected -> idle
An alpine based image would need a few packages to be installed so before committing to migrating to alpine we need to make sure the image size gains are worth it.
These endpoints don't seem to work currently?
bh.cr/balenablocks/audio-<arch> or bhcr.io/balenablocks/audio-<arch> where <arch> is one of: rpi, armv7hf, aarch64 or amd64.
Building for machine name raspberrypi4-64, platform linux/arm64, pushing to dynamicdevices/balenablock-darkice
docker buildx build --no-cache -t dynamicdevices/balenablock-darkice:raspberrypi4-64 --load --platform linux/arm64 --file Dockerfile.raspberrypi4-64 .
[+] Building 1.1s (3/3) FINISHED
=> [internal] load build definition from Dockerfile.raspberrypi4-64 0.0s
=> => transferring dockerfile: 165B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> ERROR [internal] load metadata for bh.cr/balenablocks/audio-aarch64:latest 1.1s
------
> [internal] load metadata for bh.cr/balenablocks/audio-aarch64:latest:
------
error: failed to solve: rpc error: code = Unknown desc = failed to solve with frontend dockerfile.v0: failed to create LLB definition: unexpected status code [manifests latest]: 403 Forbidden
On the main blocks page icons next to audio and bluetooth blocks look larger compared to other blocks.
Here's the logo file as defined in balena.yml:
https://raw.githubusercontent.com/balenablocks/audio/master/logo.png
And here's correctly looking one from fbcp:
https://raw.githubusercontent.com/balenablocks/fbcp/master/logo.png
The logos have different size and proportions. Fbcp could be used as a reference.
I am working on a flutter app "block" using balenalib/intel-nuc-ubuntu-node:14-focal-run
and I have been unable to get ANY audio to play via alsa
or pulse
without first running alsactl restore
.
Adding the following to my flutter container's Dockerfile seems to have fixed the audio and allows the audio block to work:
...
# Reload sound card drivers
RUN alsactl restore
...
CMD ["bash", "/usr/src/app/docker/start.sh"]
FYI, here's the whole working Dockerfile to running a native flutter app (MUCH better performance than using a web build with the browser block)...
# BUILD STEP
FROM balenalib/intel-nuc-ubuntu-node:14-focal-build as build
ARG FLUTTER_LOCATION=/usr/src/flutter
# Move to app dir
WORKDIR /usr/src/app
# Install build dependencies
RUN install_packages \
# Flutter
git \
unzip \
clang \
cmake \
ninja-build \
pkg-config \
libgtk-3-dev \
libblkid-dev \
liblzma-dev \
# Flutter pub dependencies
vlc \
libvlc-dev
RUN git clone https://github.com/flutter/flutter.git -b stable ${FLUTTER_LOCATION}
ENV PATH="${PATH}:${FLUTTER_LOCATION}/bin"
RUN flutter config --enable-linux-desktop
RUN flutter doctor --verbose
COPY . .
RUN flutter build linux
# RUN STEP
FROM balenalib/intel-nuc-ubuntu-node:14-focal-run
# Move to app dir
WORKDIR /usr/src/app
# Install run dependencies
RUN install_packages \
# Flutter
libgtk-3-dev \
vlc \
libvlc-dev \
# X Window System
xserver-xorg \
xserver-xorg-video-intel \
x11-xserver-utils \
xinit \
# Audio Utilities
alsa-utils \
# Touchscreen
xinput \
# VNC Server
x11vnc
# Reload sound card drivers
RUN alsactl restore
COPY --from=build /usr/src/app/build/linux build/linux
COPY --from=build /usr/src/app/docker docker
CMD ["bash", "/usr/src/app/docker/start.sh"]
Add script to add and configure the alsa bridge for alpine based images.
For debian see: https://github.com/balena-io-playground/audio-primitive/blob/master/scripts/alsa-bridge/debian-setup.sh
Support PulseAudio native protocols with anonymous authentication: https://www.freedesktop.org/wiki/Software/PulseAudio/Documentation/User/Modules/#module-native-protocol-unixtcp
Should be able to route audio using PULSE_SERVER
, PULSE_SINK
, PULSE_SOURCE
:
To replicate
Running udev monitor
or aplay -l
will show that both udev and ALSA are picking up the sound card. However running pactl list sinks
will yield no result. PulseAudio is ignoring the udev events it seems.
If you invert the order of operations however hotplugging works as intended:
This might be related to how systemd ALSA rules are handled, and how PulseAudio interacts with that (seems a bit sketchy?). Some references here for further investigation:
See: balena-io-experimental/balena-sound#296
Some examples:
If there are no additional outputs (USB or DAC) plugged in, the block crashes.
Soundcard:
root@f539fa0399cc:/usr/src# cat /proc/asound/cards
0 [tegrahda ]: tegra-hda - tegra-hda
tegra-hda at 0x70038000 irq 83
Error:
E: [pulseaudio] module-alsa-card.c: Failed to find a working profile.
audio E: [pulseaudio] module.c: Failed to load module "module-alsa-card" (argument: "device_id="0" name="0" card_name="alsa_card.0" namereg_fail=false tsched=yes fixed_latency_range=no ignore_dB=no deferred_volume=yes use_ucm=yes avoid_resampling=yes card_properties="module-udev-detect.discovered=1""): initialization failed.
Amixer output:
root@f539fa0399cc:/usr/src# amixer --card tegrahda
Simple mixer control 'd HDA Comfort Noise',0
Capabilities: pswitch pswitch-joined
Playback channels: Mono
Mono: Playback [off]
Simple mixer control 'd HDA Decode Capability',0
Capabilities: volume volume-joined
Playback channels: Mono
Capture channels: Mono
Limits: 0 - 4294967295
Mono: 0 [0%]
Simple mixer control 'd HDA Maximum PCM Channels',0
Capabilities: volume volume-joined
Playback channels: Mono
Capture channels: Mono
Limits: 0 - 4294967295
Mono: 2 [0%]
Simple mixer control 'd IEC958',0
Capabilities: pswitch pswitch-joined
Playback channels: Mono
Mono: Playback [on]
Mimic AUDIO_OUTPUT
behaviour.
The default sink can be referred as @DEFAULT_SINK@
in commands, for example:
$ pactl set-sink-volume @DEFAULT_SINK@ +5%
I'm trying to get this image working with the Adafruit I2S amp -> https://learn.adafruit.com/adafruit-max98357-i2s-class-d-mono-amp
Supposedly it is supported as mentioned here: https://github.com/balenalabs/balena-sound/blob/master/docs/05-audio-interfaces.md#dtoverlay-values
I've managed to get it working on the host machine. (I'm using RaspbianLite and not balenaOS btw)
When I run this image for raspberrypi3 (docker run --privileged -d -p 4317:4317 balenablocks/audio:raspberrypi3
) and exec inside it I can run the alsa debug commands:
aplay -l
:
**** List of PLAYBACK Hardware Devices ****
card 0: dac [snd_rpi_hifiberry_dac], device 0: HifiBerry DAC HiFi pcm5102a-hifi-0 [HifiBerry DAC HiFi pcm5102a-hifi-0]
Subdevices: 0/1
Subdevice #0: subdevice #0
So it seems to recognize the speaker. However running the speaker-test command produces no sound (although the command runs successfully). The command I use is speaker-test -c2 --test=wav -w /usr/share/sounds/alsa/Front_Center.wav
. The same command works (e.g. produces sound) if I run it outside the container (although I have to run it with sudo).
What can I try to make this work? Do I need to use the balenaOS host image?
Currently they won't work unless they are ran on a balenalib base image.
19.06.21 09:40:40 (+0000) audio W: [pulseaudio] server-lookup.c: Unable to contact D-Bus: org.freedesktop.DBus.Error.NotSupported: Unable to autolaunch a dbus-daemon without a $DISPLAY for X11
19.06.21 09:40:40 (+0000) audio W: [pulseaudio] main.c: Unable to contact D-Bus: org.freedesktop.DBus.Error.NotSupported: Unable to autolaunch a dbus-daemon without a $DISPLAY for X11
We should suppress this error if it's not relevant (which I presume since it's about X11 and this is an audio block). It's probably alarming for users trying to root cause "no audio" issues.
Remove bluetooth container into a primitive of it's own.
They are not necessary and produce errors below since we don't have pulseaudio dbus interface in balenaOS.
console-kit
:
02.06.20 16:35:21 (-0300) pulseaudio E: [pulseaudio] module-console-kit.c: GetSessionsForUnixUser() call failed: org.freedesktop.DBus.Error.ServiceUnknown: The name org.freedesktop.ConsoleKit was not provided by any .service files
02.06.20 16:35:21 (-0300) pulseaudio E: [pulseaudio] module.c: Failed to load module "module-console-kit" (argument: ""): initialization failed.
ofono
:
02.06.20 16:35:21 (-0300) pulseaudio E: [pulseaudio] backend-ofono.c: Failed to register as a handsfree audio agent with ofono: org.freedesktop.DBus.Error.ServiceUnknown: The name org.ofono was not provided by any .service files
Can't use that prefix as the dashboard thinks it's a host config var.
Devices using raspberry-pi
based images fail to start with error:
Illegal instruction (core dumped)
Related-to: balena-io-experimental/balena-sound#429
Document PulseAudio env vars: PULSE_SINK
, PULSE_SOURCE
, PULSE_SERVER
. (see https://gavv.github.io/articles/pulseaudio-under-the-hood/#x11-publishing)
Document library (hooks, commands)
Document supported devices
Setting AUDIO_OUTPUT
to any RPI_
option like RPI_HEADPHONES
produces the following error:
02.11.20 16:50:26 (-0800) audio Invalid card number.
02.11.20 16:50:26 (-0800) audio Usage: amixer <options> [command]
02.11.20 16:50:26 (-0800) audio
This happens on a Pi4 running balenaOS 2.58.6+rev1
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.