Sunday, April 17, 2011

The perfect linux audio setup - ALSA with late 2010 mac mini (macmini4,1)


One of the greatest additions to the unibody model mac mini is the addition of an HDMI output (through the nvidia MCP89).
Not only does this allow connecting another HD screen, but it marks the inclusion of HD multi channel audio. Not only audio over HDMI is supported but also the mini-DP output received the welcomed update. And when you thought it can't get any better - each has its own audio device (analog = 0, DP = 7, HDMI = 8). Why is this such an improvement over the optical S/PDIF in the previous models? Several reasons:
  1. The obvious - 8ch LPCM > Dolby 5.1
  2. One less cable to the receiver :)
  3. I can now use the dual analog/digital output as an analog output (because I have a multi zone receiver and the second zone can only use analog sources).

First off - getting the HDMI audio to work in linux
Kernel support - need to set SND_HDA_CODEC CIRRUS and SND_HDA_CODEC_HDMI (I'm using 2.6.38, it used to be SND_HDA_CODEC_NVHDMI).
This however is not enough on the mac mini because I get write errors when I try to open the hdmi device. Quite a bit of web research has revealed the following changes are needed:

1. Load the module with the options: snd_hda_intel.enable_msi=0 snd_hda_intel.probe_mask=0xffff,0xfff2 snd_hda_intel.model=mbp55

2. Use /etc/asound.conf and /usr/share/alsa/cards/HDA-Intel.conf from this post. This is supposed to fix the switched channels, but I'm not sure it's really required (looks a bit too complex).

This gets you basic but working setup :)

Now for the fun stuff
A few things are missing in the basic setup. First off, the HDMI output volume is fixed and the mixer doesn't affect it. I haven't figured out how to get the alsa mixer settings right. So, we'll use the alsa softvol plugin (with some degradation of quality I guess...). Also, the output needs to be dmix'ed so multiple applications can use it at the same time. And lastly, I want the audio to be distributed to all outputs simultaneously so I can hear my music on my home theater (HDMI), monitor attached headphones (DP) and in my bedroom (analog). This is done using the alsa multi plugin.

Here is my .asoundrc
# dmix the hdmi output
pcm.!hdmi {
type dmix
ipc_key 1024
ipc_key_add_uid false
ipc_perm 0660
slave {
pcm "hw:0,8"
rate 48000
channels 8
period_time 0
period_size 1024
buffer_time 0
buffer_size 4096
}
}

# dmix the dp output
pcm.dp {
type dmix
ipc_key 1025
ipc_key_add_uid false
ipc_perm 0660
slave {
pcm "hw:0,7"
rate 48000
channels 2
period_time 0
period_size 1024
buffer_time 0
buffer_size 4096
}
}

# dmix the analog output
pcm.analog {
type dmix
ipc_key 1026
ipc_key_add_uid false
ipc_perm 0660
slave {
pcm "hw:0,0"
rate 48000
channels 2
period_time 0
period_size 1024
buffer_time 0
buffer_size 4096
}
}

pcm.softvol {
type softvol
slave {
pcm "all"
}
control {
name "PCM"
card 0
}
}

pcm.!default {
type plug
slave.pcm "softvol"
}

pcm.all {
type plug
slave.pcm "multi"
ttable.0.0 1.0
ttable.1.1 1.0
ttable.2.2 1.0
ttable.3.3 1.0
ttable.4.4 1.0
ttable.5.5 1.0
ttable.6.6 1.0
ttable.7.7 1.0
ttable.0.8 1.0
ttable.1.9 1.0
ttable.0.10 1.0
ttable.1.11 1.0
}

# distribute audio to both analog and hdmi outputs
pcm.multi {
type multi
slaves.a.pcm "hdmi"
slaves.a.channels 8
slaves.b.pcm "analog"
slaves.b.channels 2
slaves.c.pcm "dp"
slaves.c.channels 2
bindings.0.slave a
bindings.0.channel 0
bindings.1.slave a
bindings.1.channel 1
bindings.2.slave a
bindings.2.channel 2
bindings.3.slave a
bindings.3.channel 3
bindings.4.slave a
bindings.4.channel 4
bindings.5.slave a
bindings.5.channel 5
bindings.6.slave a
bindings.6.channel 6
bindings.7.slave a
bindings.7.channel 7
bindings.8.slave b
bindings.8.channel 0
bindings.9.slave b
bindings.9.channel 1
bindings.10.slave c
bindings.10.channel 0
bindings.11.slave c
bindings.11.channel 1
}



Note that the DP output is set to 2ch 48KHz because it is connected to my monitor and it seems that it is limited in its capabilities (it only supports headphones anyway). This also means all other outputs need to be set to 48KHz otherwise you get errors from the multi-device pcm (it seems that all slaves used by the multi pcm need to have the same parameters). If the DP output is disabled I can use 96KHz or even 192KHz...

Next Steps...
I need to try out pulseaudio again. It might reduce the amount of alsa plugins in use. I also need to figure out how to record audio (for icecast).

Sources:
http://wiki.xbmc.org/?title=HOW-TO_set_up_HDMI_audio_on_nVidia_GeForce_G210,_GT220,_or_GT240
http://forum.xbmc.org/showthread.php?t=74778