sammhicks / internet-radio-rs

MIT License
1 stars 0 forks source link

The player always uses HDMI audio #21

Open sammhicks opened 4 years ago

BCMM commented 4 years ago

I'd be fine with the program just using the first available audio device - if HDMI output is not desired, it can be disabled in the Pi's config.txt.

BCMM commented 4 years ago

Actually, if I recall correctly, HDMI and analogue do not actually exist as separate ALSA devices - I think they're just two outputs of the same card (like front and back audio on a desktop). There may be multiple devices present if an external sound device is connected, but I can't currently think of any reason to do that and not just disable the internal audio.

So selecting between multiple sound cards would be a reasonable feature, but not one that I think is actually needed.

Selecting between the built-in raspberrypi outputs is probably out of scope since, again IIRC, this would involve some very Pi-specific code that toggles a Pi-specific mixer option. The Pi provides other ways of configuring this, and I can't currently think of any reason to change outputs at runtime.

BCMM commented 4 years ago

Looks like there are some module parameters that don't seem to be mentioned much in the docs:

# modinfo snd_bcm2835
filename:       /lib/modules/4.19.126/kernel/drivers/staging/vc04_services/bcm2835-audio/snd-bcm2835.ko
license:        GPL
description:    Alsa driver for BCM2835 chip
author:         Dom Cobley
srcversion:     7AA1377144CA37D54C9971C
alias:          of:N*T*Cbrcm,bcm2835-audioC*
alias:          of:N*T*Cbrcm,bcm2835-audio
depends:        snd-pcm,snd
staging:        Y
intree:         Y
name:           snd_bcm2835
vermagic:       4.19.126 mod_unload modversions ARMv6 p2v8 
parm:           force_bulk:Force use of vchiq bulk for audio (bool)
parm:           enable_hdmi:Enables HDMI virtual audio device (bool)
parm:           enable_headphones:Enables Headphones virtual audio device (bool)
parm:           enable_compat_alsa:Enables ALSA compatibility virtual audio device (bool)

enable_compat_alsa=1 (i.e. the default as of 4.19) creates an ALSA device that seems to behave in a way that corresponds to documentation on the Raspberry Pi website (and to my previous comment). enable_hdmi=1 and enable_headphones=1 create separate ALSA devices that only work with their respective outputs. It appears that enable_compat_alsa=0 forces the creation of both separate devices regardless of the values of other parameters.

As of 4.19, the default values seem to be 0, 0, 0, 1, respectively. You can check these at runtime by reading the files in /sys/module/snd_bcm2835/parameters/. From what you and Richard have said, it sounds like Raspbian may now have 0, 1, 1, 0 by default, but I don't know why. This could be the result of the kernel default changing, or it could be being set on the kernel command line, or in /etc/modules/, or /etc/modules-load.d/. I would be interested to know if you can track down where it is getting set on your system.

BCMM commented 4 years ago

If you set enable_compat_alsa=1 enable_hdmi=0 enable_headphones=0, then you can still use the method suggested on the website to switch outputs: amixer cset numid=3 1.

(You can also use hdmi_ignore_edid_audio=1 in /boot/config.txt to influence ALSA's defaults as documented here. That's all well and good on an embedded distro that doesn't remember anything, but I'm not sure if that would do anything on a Raspbian install that has already been booted, since it probably stores mixer settings at shutdown.)

While I do not personally have any use for such a feature, it might be useful to you for internet-radio-rs to have an option in the config file allowing you to specify which audio device to use by name. Providing this option should be optional, and it should use the system default device if unspecified. I have no idea how to do this portably; the relevant option might be specific to each GStreamer sink plugin.

It may be necessary to replace playbin with a slightly more detailed pipeline in order to allow the audio sink's options to be controlled. Examples in gst-launch form:

gst-launch-1.0 uridecodebin uri=file:///example.mp3 ! audioconvert ! alsasink device=default:CARD=b1
gst-launch-1.0 uridecodebin uri=http://example.com/ ! audioconvert ! alsasink device=default:CARD=Headphones
BCMM commented 4 years ago

Well, I've dumped a lot of red herrings in here now...

All of what I've said above about the introduction of separate audio devices and how to turn it on and off stands, but it turns out that none of them are actually why sound keeps coming out of the HDMI port on Richard's Pi.

The problem was that it wasn't actually using ALSA at all. It turns out that Raspbian includes a package called gstreamer1.0-omx-rpi, which amongst other things contains a pair of GStreamer sinks called omxanalogaudiosink and omxhdmiaudiosink. The former has the same rank as alsasink, and the latter outranks it, so playbin (or, more immediately, playsink) has been automatically selecting omxhdmiaudiosink as the best available audio output.

This sink outputs audio using the OpenMAX API, and so ignores any configuration one might have made using ALSA, including the output switcher widget in Raspbians's desktop environment. In fact, it is totally separate from what I had been thinking of as "the sound driver", in that it doesn't even need the snd_bcm2835 kernel module to play audio.

For now at least, the fix is to uninstall gstreamer1.0-omx-rpi.

This was discovered using gst-launch-1.0 and this debugging method. I'll have a look at whether such debugging can be included in the program when I've got more of a clue what's going on.