Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hifiberry Amp hardware volume control not working #232

Closed
marrem opened this issue Feb 21, 2016 · 28 comments
Closed

Hifiberry Amp hardware volume control not working #232

marrem opened this issue Feb 21, 2016 · 28 comments

Comments

@marrem
Copy link

marrem commented Feb 21, 2016

I have 2 raspi's. One with HifiBerry DAC+, which is working fine. When I open alsamixer, when I change volume on the device (phone, iPad), I see the volume slider in alsamixer move indicating it is using the right control. (with the HifiBerry DAC+, this is " Digital").

Now the other one, is using a HifiBerry Amp.
Alsamixer shows 2 controls: "Master" and "Channels". As per the HifiBerry site, "Master" is the one to use (Mopidy is using Master and works OK).
So I entered "Master" as the mixer control in shairport-sync.conf. But when changing the volume on the device, the volume slider in alsamixer doesn't move, on the device I can't set the volume louder than the setting in alsamixer. I can crank up the volume by setting the alsamixer volume control by hand. But it isn't controlled by shairport.

I tried entering some bogus name for the mixer control in shairport-sync.conf, but it wouldn't start complaining it couldn't find the mixer control. So that indicates that it does use the mixer control name in the config file.

pi@mpk:/etc $ aplay -l
**** List of PLAYBACK Hardware Devices ****
card 0: sndrpihifiberry [snd_rpi_hifiberry_amp], device 0: HifiBerry AMP HiFi tas5713-hifi-0 []
  Subdevices: 1/1
  Subdevice #0: subdevice #0

pi@mpk:/etc $ amixer scontrols
Simple mixer control 'Master',0
Simple mixer control 'Channels',0

https://www.hifiberry.com/guides/mixer-settings/

Amp/Amp+

There are 2 controls: Master and Channels. With the master control you control the overall volume while “Channels” can be used to set different volumes on the left and right channel. Note that excessive volumes can damage your speakers. Therefore we recommend setting the volume not too high on startup.

@marrem
Copy link
Author

marrem commented Feb 21, 2016

I have run -vvv, that did shed some light on the problem:

shairport-sync@mpk:/$ /usr/local/bin/shairport-sync -vvv
Looking for the configuration file "/etc/shairport-sync.conf".
Looking for configuration file at full path "/etc/shairport-sync.conf"
Output device name is "hw:0".
Open Mixer
Mixer device name is "hw:0".
Mixer Control name is "Master".
note: the hardware mixer specified -- "Master" -- does not have a dB volume scale, so it can't be used.
...

So it's because the control doesn't have a db volume scale....
Is there some workaround?

@mikebrady
Copy link
Owner

The built-in software volume control works well, and it is automatically used when you don't specify a mixer name. The only thing you need to do is to separately ensure that the Master volume control is set to maximum before a play session begins. You could write a little script that does that just before Shairport Sync starts playing. (Separately, I'd suggest you ask the HiFiberry guys to consider adding a logarithmic volume control.)

@marrem
Copy link
Author

marrem commented Feb 22, 2016

I'll write a script to set the Master louder / and one to put it back when the shairport stream stops. Pity that I can't use hardware volume control. Is there a way to fiddle around with alsa (asound.conf) to fool shairport-sync into seeing a logarithmic control? I will contact HifiBerry to ask them if they can add a logarithmic volume control.

@mikebrady
Copy link
Owner

Thanks. I'll keep this under review too...

@marrem
Copy link
Author

marrem commented Feb 23, 2016

I changed the "session" section of the shairport-sync.conf:

sessioncontrol = 
{
        run_this_before_play_begins = "/usr/bin/amixer sset Master 200";
        run_this_after_play_ends = "/usr/bin/amixer sset Master 160";
        wait_for_completion = "yes";
        allow_session_interruption = "yes";
//      session_timeout = 120; // wait for this number of seconds after a source disappears before terminating the session and becoming available again.
};

This worked for a while. Then I got "too many open files" in syslog and:

pi@mpk:~ $ sudo ls -l  /proc/25972/fd
total 0
lr-x------ 1 shairport-sync shairport-sync 64 Feb 23 21:24 0 -> /dev/null
lrwx------ 1 shairport-sync shairport-sync 64 Feb 23 21:24 1 -> socket:[51184]
lrwx------ 1 shairport-sync shairport-sync 64 Feb 23 21:24 10 -> socket:[55109]
lrwx------ 1 shairport-sync shairport-sync 64 Feb 23 22:03 100 -> /dev/snd/controlC0
lrwx------ 1 shairport-sync shairport-sync 64 Feb 23 22:03 1000 -> /dev/snd/controlC0
lrwx------ 1 shairport-sync shairport-sync 64 Feb 23 22:03 1001 -> /dev/snd/controlC0
lrwx------ 1 shairport-sync shairport-sync 64 Feb 23 22:03 1002 -> /dev/snd/controlC0
lrwx------ 1 shairport-sync shairport-sync 64 Feb 23 22:03 1003 -> /dev/snd/controlC0
lrwx------ 1 shairport-sync shairport-sync 64 Feb 23 22:03 1004 -> /dev/snd/controlC0
lrwx------ 1 shairport-sync shairport-sync 64 Feb 23 22:03 1005 -> /dev/snd/controlC0
lrwx------ 1 shairport-sync shairport-sync 64 Feb 23 22:03 1006 -> /dev/snd/controlC0
lrwx------ 1 shairport-sync shairport-sync 64 Feb 23 22:03 1007 -> /dev/snd/controlC0
lrwx------ 1 shairport-sync shairport-sync 64 Feb 23 22:03 1008 -> /dev/snd/controlC0
lrwx------ 1 shairport-sync shairport-sync 64 Feb 23 22:03 1009 -> /dev/snd/controlC0
lrwx------ 1 shairport-sync shairport-sync 64 Feb 23 22:03 101 -> /dev/snd/controlC0
lrwx------ 1 shairport-sync shairport-sync 64 Feb 23 22:03 1010 -> /dev/snd/controlC0
lrwx------ 1 shairport-sync shairport-sync 64 Feb 23 22:03 1011 -> /dev/snd/controlC0
...
pi@mpk:~ $ sudo ls -l  /proc/25972/fd | wc -l
1025

What's going on...

@marrem
Copy link
Author

marrem commented Feb 23, 2016

In syslog before this happened:

Feb 23 21:40:18 mpk shairport-sync[25972]: Simple mixer control 'Master',0
Feb 23 21:40:18 mpk shairport-sync[25972]: Capabilities: volume volume-joined
Feb 23 21:40:18 mpk shairport-sync[25972]: Playback channels: Mono
Feb 23 21:40:18 mpk shairport-sync[25972]: Capture channels: Mono
Feb 23 21:40:18 mpk shairport-sync[25972]: Limits: 0 - 248
Feb 23 21:40:18 mpk shairport-sync[25972]: Mono: 200 [81%]
Feb 23 21:40:27 mpk shairport-sync[25972]: ALSA lib pcm_hw.c:1667:(_snd_pcm_hw_open) Invalid value for card
Feb 23 21:40:27 mpk shairport-sync[25972]: Failed to attach mixer
Feb 23 21:41:22 mpk shairport-sync[25972]: failed to accept connection: Too many open files
Feb 23 21:41:22 mpk shairport-sync[25972]: failed to accept connection: Too many open files

Earlier on it went fine:

Feb 23 21:26:47 mpk shairport-sync[25972]: Simple mixer control 'Master',0
Feb 23 21:26:47 mpk shairport-sync[25972]: Capabilities: volume volume-joined
Feb 23 21:26:47 mpk shairport-sync[25972]: Playback channels: Mono
Feb 23 21:26:47 mpk shairport-sync[25972]: Capture channels: Mono
Feb 23 21:26:47 mpk shairport-sync[25972]: Limits: 0 - 248
Feb 23 21:26:47 mpk shairport-sync[25972]: Mono: 200 [81%]
Feb 23 21:27:10 mpk shairport-sync[25972]: Simple mixer control 'Master',0
Feb 23 21:27:10 mpk shairport-sync[25972]: Capabilities: volume volume-joined
Feb 23 21:27:10 mpk shairport-sync[25972]: Playback channels: Mono
Feb 23 21:27:10 mpk shairport-sync[25972]: Capture channels: Mono
Feb 23 21:27:10 mpk shairport-sync[25972]: Limits: 0 - 248
Feb 23 21:27:10 mpk shairport-sync[25972]: Mono: 160 [65%]
Feb 23 21:27:13 mpk shairport-sync[25972]: Simple mixer control 'Master',0
Feb 23 21:27:13 mpk shairport-sync[25972]: Capabilities: volume volume-joined
Feb 23 21:27:13 mpk shairport-sync[25972]: Playback channels: Mono
Feb 23 21:27:13 mpk shairport-sync[25972]: Capture channels: Mono
Feb 23 21:27:13 mpk shairport-sync[25972]: Limits: 0 - 248
Feb 23 21:27:13 mpk shairport-sync[25972]: Mono: 200 [81%]
Feb 23 21:27:26 mpk shairport-sync[25972]: Simple mixer control 'Master',0
Feb 23 21:27:26 mpk shairport-sync[25972]: Capabilities: volume volume-joined
Feb 23 21:27:26 mpk shairport-sync[25972]: Playback channels: Mono
Feb 23 21:27:26 mpk shairport-sync[25972]: Capture channels: Mono
Feb 23 21:27:26 mpk shairport-sync[25972]: Limits: 0 - 248
Feb 23 21:27:26 mpk shairport-sync[25972]: Mono: 160 [65%]

I have this at alsa backend:

{
  output_device = "hw:0"; // the name of the alsa output device. Use "alsamixer" or "aplay" to find out the names of devices, mixers, etc.
  mixer_control_name = "Master"; // the name of the mixer to use to adjust output volume. If not specified, volume in adjusted in software.
  mixer_device = "hw:0"; // the mixer_device default is whatever the output_device is. Normally you wouldn't have to use this.
//  audio_backend_latency_offset = 0; // Set this offset to compensate for a fixed delay in the audio back end. E.g. if the output device delays by 100 ms, set this to -4410.
//  audio_backend_buffer_desired_length = 6615; // If set too small, buffer underflow occurs on low-powered machines. Too long and the response times with software mixer become annoying.
};

I changed "default" to "hw:0" in an attempt to fix the failing hardware volume control, before I saw that it was caused by it not having de dB range/scale. But "default" should also use hw:0, as it is the only device on my raspberry pi (not loading drivers for built-in audio).

@mikebrady
Copy link
Owner

The commands operate in the background, so you need to route the output of those commands somewhere like /dev/null, I'd say. Also, no harm to make the command quiet with -q.

There is no sense in telling Shairport Sync to use the Master mixer, better just comment it out.

@mikebrady
Copy link
Owner

Okay to close this?

@marrem
Copy link
Author

marrem commented Apr 5, 2016

Yes. Fine.

Mike Brady [email protected] schreef op 5 april 2016 14:13:00 CEST:

Okay to close this?


You are receiving this because you authored the thread.
Reply to this email directly or view it on GitHub:
#232 (comment)

Verzonden van mijn Android telefoon met K-9 Mail.

@mikebrady
Copy link
Owner

Thanks.

@jdtsmith
Copy link

jdtsmith commented Dec 3, 2016

Just got an Amp+ and have the same problem. For me though the software mixer is not working well. When I change the volume on the phone while paired to the shairport-sync, I see log items like:

Setting volume db to -3560954.525000.

And other oddly low values. When my phone's volume slider approaches full, it blasts the speakers. I think (though I dare not replicate it), when this happened, shairport-sync reported:

Setting volume db to 2400.000000.

Edit: Forgot to comment out the mixer_control_name as Mike clearly said is necessary. Leaving this comment here in case anyone else comes across the same thing.

@mikebrady
Copy link
Owner

Still intrigued by this. So, the "Amp+" is a HiFiBerry Amp+, right? Can you tell me which version of Shairport Sync you're using please? To get it, enter $ shairport-sync -V and copy the response. Also, assuming it's an iPhone, what app are you sending from? Does commenting out the mixer_control_name fix the problem? Questions, questions...

@jdtsmith
Copy link

jdtsmith commented Dec 3, 2016

Thanks for your comments (and all your work with this tool, really enjoying it!). Indeed, it's a brand new HifiBerry Amp+ 1.0 (which I'm loving). My shp-s version, freshly compiled yesterday:

2.8.6-OpenSSL-Avahi-ALSA-soxr-metadata-sysconfdir:/etc

To attempt volume control, I was using the normal iPhone volume control after having selected the relevant device in the iPhone's Control Panel for output location; same crazy negative volume settings with iTunes or Pandora.

Commenting out mixer_control_name does fix it (along with an aplay call before and after to set/unset the appropriate max volume). But then it's not using the hardware mixer to alter volume (I presume).

I can use alsamixer no problem to interact with the hardware mixer (though I don't actually know where the volume setting actually happens in this device). I can also watch what shp-s tries to do with the mixer volume, when the mixer is still set to "Master", using alsamixer. In that case, shp-s does try to use the hardware mixer, but in a very poor manner... the iPhone output volume level is mapping to such crazy-low dB levels for anything but the max volume setting on the iPhone that it sets the "Master" mixer to zero. Then, in the very last volume step, when you hit the max iPhone volume, shp-s maps it to (db 2400), and "Master" shoots up to full blast (and your kids cover their ears and shout at you).

Not sure if there's a way to map the smooth volume sliding scale onto this particular mixer arrangement, but very happy to help debug and try things if you have any ideas.

Thanks again!

@mikebrady
Copy link
Owner

Thanks. That's all very useful. It supports an idea that there is some silly miscalculation of the transfer function between the volume sliding scale and the range of the Amp+'s mixer. To troubleshoot it, it would be very useful if you could post the upper and lower limits of the "dB gain" for the mixer. You can find that out using alsamixer:

  • Select the correct sound card.
  • Select the correct mixer – "Master" in your case, I believe; "Digital" in the screenshots below.
  • Get the value "db gain" when the mixer is at its max and min-before-mute settings – you don't need to be playing any audio, just use alsamixer's controls to vary the level.

Here are two screenshots showing the max (0.00 dB) and the min-before-mute (-103.00 dB) for an IQaudIO amplifier – the values are near the top left. With those two numbers for the Amp+, some testing could be done.

screen shot 2016-12-04 at 11 30 43

screen shot 2016-12-04 at 11 32 53

@jdtsmith
Copy link

jdtsmith commented Dec 4, 2016

Thanks. Just took a look at alsamixer and there is no reported dB gain, only a percentage range from 0-100. Unlike your case, there is a single mixer channel on Master, and two separately controllable channels on the Channels mixer. Both work together to set the total volume.

Here's what amixer get Master reports:

  Simple mixer control 'Master',0
  Capabilities: volume volume-joined
  Playback channels: Mono
  Capture channels: Mono
  Limits: 0 - 248
  Mono: 100 [40%]

The other mixer looks like:

% /usr/bin/amixer get Channels
  Simple mixer control 'Channels',0
  Capabilities: volume
  Playback channels: Front Left - Front Right
  Capture channels: Front Left - Front Right
  Limits: 0 - 248
  Front Left: 203 [82%]
  Front Right: 203 [82%]

I'd be happy enough if the volume signal sent over airport mapped linearly (or pleasingly non-linearly via some "typical" dB->percentage mapping) to the 0-248 range of Master. Then I could just use the Channels mixer to set a reasonable max volume.

Screenshot:

mixer_max

Thanks again. Fun to debug this since it gives you an excuse to sit and listen to music.

@mikebrady
Copy link
Owner

Many thanks for this. I'm now remembering that the hifiberry amp does not have a logarithmic mixer – see #232. So, that means you must use the built-in software volume control. This is all done in 16 bits, so the noise floor isn't as low as it could be due to the [deliberate] use of dithering. The development version of Shairport Sync allows you to specify 24 or 32 bits output, so the noise floor is much lower, and IMHO it is as good as having a hardware mixer. The documentation is a little behind though...

@jdtsmith
Copy link

jdtsmith commented Dec 4, 2016

OK, wondered if that was the case based on the conversation above. I may contact the HifiBerry people and see why the Amp+ is the only one without a logarithmic mixer exposed. But is it impossible to include a standard "fallback" algorithm for mapping Shairport Sync's desired logarithmic dB scale to a linear "percentage" scale on the HW mixer? I.e. a pseudo-log scale that can map between the two if the mixer itself doesn't present a dB scale to the controller (perhaps with a user-adjustable max_percentage=XXXdB to peg it)? I presume that's all a mixer-provided dB scale does anyway (though perhaps with better vendor domain knowledge of the DAC performance).

Thanks.

@seatrout
Copy link

Could I jump in here? I am having exactly this problem streaming from a macbook air. The Alsa volume controls on the Pi (raspberry Pi 3, running Moode player 3.1) work fine, either through SSH or through the main interface. But there is no sound at all unless I nudge the alsa controls -- or turn the volume control on the mac to full, which blasts the speakers whatever the Alsa volume is set to. Only did that once, mind you ...

Shairport-sync -V gives the result

2.8.6-OpenSSL-Avahi-ALSA-stdout-soxr-metadata-sysconfdir:/usr/local/etc

@jdtsmith
Copy link

It sounds like you have mixer_control_name set. For the amp, you must comment it out, then use an ALSA based tool to set the maximum volume. Shairport-sync receives the volume changes from your Mac, but implements them in software instead of sending a hardware command to the Hifiberry. I think it would be great to have some default mapping between them in case a logarithmic mixer isn't implemented by the driver; might look into it myself.

@mikebrady
Copy link
Owner

Yes indeed. It seems that there is a bug in Shairport Sync in that it should not even be trying to send settings to the mixer once it has discovered that it isn't logarithmic. I'm pretty sure that bug is there because after trying out some ideas to circumvent the problem, the idea was abandoned and some of the code was inadvertently left in place.

One possible solution is to add yet another setting allowing the iTunes/iPhone volume (call it AirPlay Volume), which goes from 0 to -30, to be mapped straight onto the non-logarithmic mixer control. For example, if the mixer values are 0 (min) to 100 (max), they should be mapped onto -30 (min AirPlay Volume) to 0 (max AirPlay volume). Zero sounds like mute though, so not sure about that. Whaddya think? What should the name of the setting be? Maybe volume_use_linear_mixer_control?

@jdtsmith
Copy link

I have asked the Hifiberry people about exposing a dB scale for the Amp. I do know the Amp uses a different driver than the other Hifiberry boards (actually all 4 are different):

% egrep codec_name hifi*.c
hifiberry_amp.c:		.codec_name		= "tas5713.1-001b",
hifiberry_dac.c:	.codec_name	= "pcm5102a-codec",
hifiberry_dacplus.c:	.codec_name	= "pcm512x.1-004d",
hifiberry_digi.c:	.codec_name	= "wm8804.1-003b",

In the raspberry pi linux codec tas5713.c code you can see the mixers being defined:

/*
 *    _   _    ___   _      ___         _           _
 *   /_\ | |  / __| /_\    / __|___ _ _| |_ _ _ ___| |___
 *  / _ \| |__\__ \/ _ \  | (__/ _ \ ' \  _| '_/ _ \ (_-<
 * /_/ \_\____|___/_/ \_\  \___\___/_||_\__|_| \___/_/__/
 *
 */

static const DECLARE_TLV_DB_SCALE(tas5713_vol_tlv, -10000, 50, 1);


static const struct snd_kcontrol_new tas5713_snd_controls[] = {
   SOC_SINGLE_TLV  ("Master"    , TAS5713_VOL_MASTER, 0, 248, 1, tas5713_vol_tlv),
   SOC_DOUBLE_R_TLV("Channels"  , TAS5713_VOL_CH1, TAS5713_VOL_CH2, 0, 248, 1, tas5713_vol_tlv)
};

Not sure why that DB_SCALE doesn't do the trick.

Looking at the audio_alsa.c code, it appears that the only things shairport-sync needs is a min and max dB level for the mixer. So perhaps shairport-sync could just allow hard-coding those in the config file if the mixer doesn't report them itself? Then you can take advantage all the transfer function work you've put in.

@sheltond
Copy link

sheltond commented Sep 2, 2017

In case anyone else comes across this, I just used the "run_this_when_volume_is_set" configuration item to run an external script that sets the volume using amixer. I disabled the software volume control (by telling it to use the Amp+'s hardware volume control, which doesn't work but prevents it doing it in software).

In the "general" section of /etc/shairport-sync.conf I added this:

run_this_when_volume_is_set = "/usr/local/bin/set-volume.sh ";

As the comments in the config file say, the requested volume is passed to this script as a parameter, from -30 (minimum non-muted) to 0 (max), or -144 for mute (which I didn't need to handle because shairport-sync appears to stop outputting when it's muted).

Then it's just a matter of mapping from the requested volume to a value in the 0..100 range that amixer takes. I found that the mapping in the script below worked well and gave a reasonable set of available volume levels, but obviously if you use this technique adjust the formula to your liking.

This is the contents of /usr/local/bin/set-volume.sh:

#!/bin/sh
vol=${1%%.*}                                  # discard the decimal point and everything after it
outvol=$(( (($vol+30) * 2)+30 ))              # calculate the output value
#echo Requested: $1, vol $vol, result $outvol >> /tmp/volume.log
amixer sset Master $outvol%                   # set the volume

@mikebrady
Copy link
Owner

Great, thanks. Just a little thing – to disable the software volume control, you should be able to set the general / ignore_volume_control setting to to "yes". The run_this_when_volume_is_set script should still be called when volume is set or changed – it's just that Shairport Sync doesn't directly use it. If it doesn't work like this, then I've made a mistake.

@mikebrady
Copy link
Owner

@jdtsmith, apologies, I somehow overlooked your comment. Would your idea not be at the mercy of how the 0..100 was mapped to level. If it was linear, then one could do something, but if non-linear, then would we not be in trouble, having a composition of two transfer functions?

@giggywithit
Copy link

Hi Mike,

I am apparently using the same driver that you are and am wondering if I am actually using hardware volume or not..

I have the same entries for the mixer that you do and yet, when I control the volume on my Ubuntu machine, the volume adjusts, yet, there is no movement of the sliders when observing alsamixer. I can change the volume, but no change in the alsamixer panel of either the Analogue or Digital sliders. My source machine uses Pulseaudio and also, the volume seems delayed when adjusting.

// output_device = "IQaudIODAC";
// mixer_control_name = "Digital";
// mixer_device = "default";
// output_rate = "auto";
// output_format = "auto";
// disable_synchronization = "no";
// use_mmap_if_available = "yes"; //
// use_hardware_mute_if_available = "yes";

@mikebrady
Copy link
Owner

mikebrady commented Jan 21, 2020

Thanks for the post. Just looking at the settings as given above, they have the two // marks in front of each, implying they are comments and therefore ignored by Shairport Sync. If that is how they really are, remove those marks from the first two lines above and restart.

I don’t understand what you mean about the source machine using pulseaudio. Could you elaborate, please?

@giggywithit
Copy link

Hilarious, I don't know what I was thinking. This is why I don't code.
OK, but for some reason it doesn't like when I uncomment output_device. The slider works now in alsamixer on the destination machine. I do still experience something akin to 2 volume changes, like there is the initial change, then something that follows a bit slower behind it. When I change it, I have to expect it to end either quieter or louder depending on the direction that I am going.

// output_device = "IQaudIODAC";
mixer_control_name = "Digital";
// mixer_device = "default";
// output_rate = "auto";
// output_format = "auto";
// disable_synchronization = "no";
// use_mmap_if_available = "yes";
use_hardware_mute_if_available = "yes";

On the Pulseaudio side of things, in Ubuntu at least, the master volume control that you would normally use if you were using Ubuntu on a laptop with only the built in speakers, actually controls the volume of shairport sync. In a control panel, I can choose the device that I want to output sound to and the master volume in the panel will control that device. There is no need to have a separate application or panel to control the volume of the desired device. I have a suspicion however that whatever was designed to do this in pulseaudio may also be performing it's own dithering in attempt to control the volume of the shairport device. If you were to try this on a linux machine, you may need to install 'paprefs' which is the program that will give you the options..
Thoughts?

Thanks Mike

paprefs

@mikebrady
Copy link
Owner

mikebrady commented Jan 21, 2020

Good stuff. Actually I didn’t notice that the output device is probably wrong. It probably should be hw:IQaudIODAC. If you do $ shairport-sync -h there will be a list of output device names at the end.

Yeah, PulseAudio can interfere with Shairport Sync alright. It almost certainly does resampling and all kinds of things.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants