Hi all, It looks like in the future the ALSA drivers for some Intel hardware will dynamically create a new PCM device when a DisplayPort monitor is plugged in. This is being discussed in this thread (part of the thread is also cross-posted to pulseaudio-discuss): http://thread.gmane.org/gmane.comp.freedesktop.xorg.drivers.intel/62703/focus=63002 PulseAudio doesn't currently support dynamic PCM devices, so work is needed to add that support. I may work on that, or it may be someone else from Intel. I'll describe here what code changes I think we should make. That serves two purposes: to get feedback about the plan before any code gets written, and to help with the implementation work if someone else than me is going to write the code. This is a long mail, but I'm sure I still didn't think of every issue that will arise when implementing this... Event: monitor gets plugged in ------------------------------ The first thing that happens should be that PulseAudio gets a wakeup from the alsa mixer, when a new ELD control for the monitor is added. This is important, because the mixer should be ready when PulseAudio starts to use the new PCM device. It's up to the driver developer to do this right. This wakeup can be ignored, so no code changes are needed in PulseAudio to handle this. The second thing that happens is that udev notifies PulseAudio about a new PCM device. Interfacing with udev is done in src/modules/module-udev-detect.c. Currently PulseAudio only cares about new and removed cards, so module-udev-detect has to be modified to also keep track of what PCM devices each card has, so that new devices can be noticed. When module-udev-detect sees a new PCM device, it needs to notify module-alsa-card about it. module-udev-detect's only interface with module-alsa-card is pa_module, which is not useful for adding the notification. I think we should move the bulk of the code in module-alsa-card.c to a new class: pa_alsa_card. module-udev-detect would then create pa_alsa_card objects instead of loading module-alsa-card instances. module-alsa-card would still exist as a wrapper around pa_alsa_card, but the module would not be used by module-udev-detect. With pa_alsa_card in place, we can add a pa_alsa_card_pcm_added() function to its API. pa_alsa_card should be defined in src/modules/alsa/alsa-card.[ch] and included in the libalsa-util.la helper library. When moving the code from module-alsa-card to pa_alsa_card, some changes to the sink and source error handling is needed. Currently, if something fails in the IO thread of an alsa sink or source, the sink/source unloads the module that owns the sink/source (see the end of thread_func() in alsa-sink.c and alsa-source.c). Now the owner module of alsa sinks and sources becomes module-udev-detect, and we certainly don't want to unload that if a single sink or source fails. The sink/source should notify the pa_alsa_card object of the failure (new functions pa_alsa_card_sink_failed() and pa_alsa_card_source_failed()), and pa_alsa_card should free the failed pa_alsa_sink or pa_alsa_source object. Let's get back to the pa_alsa_card_pcm_added() function. What should it do? We shouldn't support dynamic PCMs for arbitrary hw PCMs, because that's not compatible with relying on logical device names like "front", "surround51" etc. At this point we only need to support dynamic PCMs that are dedicated to hotplugged HDMI/DisplayPort/Thunderbolt devices. The current proposal to detect such PCMs is to add a new HDMI class to snd_pcm_class_t, which can be queried with snd_pcm_info_get_class(). Currently when opening HDMI devices, we use "hdmi:x,y" as the device string, where x is the card index and y is the device index. The device index may be different than the hw device index, but the mapping between "hdmi:x,y" to "hw:x,z" is static. The mapping can be different with different drivers, AFAIK. We currently blindly try all device indexes from 0 to 7 when probing the card. Takashi Iwai told that such behaviour won't be compatible with drivers that create dynamic PCMs for HDMI. I guess the reason is that the dynamically allocated hw device indexes can (and usually do) fall outside the index range that is used in "hdmi:x,y". Since the new HDMI PCM class is new, old kernels and old alsa-lib won't use that class even with PCMs that are actually dedicated to HDMI. We need to tell apart drivers that use the new HDMI PCM class and drivers that don't. With drivers that never use the HDMI class, we should keep using the "hdmi:x,y" device strings. With drivers that use the HDMI class, we should use "hdmi:CARD=x,SYSDEV=z", where z is the hw device index (the SYSDEV parameter doesn't currently exist, so alsa-lib needs to be updated to support it). How do we tell the two kinds of drivers apart? The current proposal is to add a version field to the PCM info. Version 0 would mean that the driver is unaware of the HDMI PCM class, and version 1 would mean that the driver will set the PCM class to HDMI when appropriate. I assume that the PCM info version will be provided separately for each PCM device, but I expect the version to be always the same for every device that belongs to the same card. We definitely need to make the decision between the two models at the card level in any case, because we can't really mix the "hdmi:x,y" model with the "hdmi:CARD=x,SYSDEV=z" model within the same card. When probing a new card, we should check the PCM info version of the first device that we probe, and choose the HDMI model for the card based on that. If the first device has PCM info version 0, then we won't support dynamic HDMI devices for that card, even if subsequent devices would somehow have version 1. The "mapping" concept in our alsa-mixer code corresponds to the PCM devices. What mappings exist is configured in src/modules/alsa/mixer/profile-sets/default.conf. We have many HDMI entries, here are a couple of examples: [Mapping hdmi-stereo] description = Digital Stereo (HDMI) device-strings = hdmi:%f paths-output = hdmi-output-0 channel-map = left,right priority = 4 direction = output [Mapping hdmi-stereo-extra1] description = Digital Stereo (HDMI 2) device-strings = hdmi:%f,1 paths-output = hdmi-output-1 channel-map = left,right priority = 2 direction = output The "device-strings" option doesn't suit the HDMI case very well, if we sometimes have to use "hdmi:x,y" and sometimes "hdmi:CARD=x,SYSDEV=z". Also, the path configuration files assume a particular mapping from "hdmi:x,y" to "hw:x,z" when dealing with ELD information and jack detection, and that assumed mapping is incorrect with dynamic HDMI devices. (This assumption probably also means that our HDMI ELD and jack detection functionality is currently broken on non-HDA cards.) I propose that we add a new boolean option for mappings, which would indicate that the mapping represents more than one PCM device, and that the PCM and mixer handling is performed according to the complex HDMI specific rules that I've explained above. The option name could be e.g. "dynamic-hdmi". When "dynamic-hdmi" is be set for a mapping, the "description", "device-strings", "paths-output" and "direction" options in the configuration file would be ignored, and the appropriate values for those would be hardcoded. That would allow us to shorten default.conf quite a bit, and also remove all the hdmi-output-N.conf path files (the generated paths would be hardcoded too). All that hardcoding isn't nice from flexibility point of view, but I don't think the lost flexibility is very important in this case. I believe that any alternative solution that would keep everything in the configuration files would introduce a significant amount of complexity to deal with the variance in the "hdmi:x,y" -> "hw:x,z" mapping (and I'm not sure it's even possible to have non-HDA-specific ELD information and jack detection support with the old-style "hdmi:x,y" device strings, since we don't have a reliable method to figure out what hw PCM device index y corresponds to). In case of dynamic HDMI mappings, the HDMI profiles need to become dynamic too. So, if a profile definition in a configuration file references a mapping that has the "dynamic-hdmi" flag set, that profile definition will then represent multiple profiles, one for each HDMI device. I'm not sure how to deal with the "description" option. Should it be ignored, or should we append a number to the description when there are multiple HDMI devices? When profiles are autogenerated (which is the common case), then the existing profile description logic should work fine. So, when pa_alsa_card_pcm_added() sees that a new HDMI PCM device appeared, it should create a new mapping for the device, a new path for the mapping, and a new profile containing the mapping. Then pa_alsa_card_pcm_added() needs to call pa_card_add_profile(), and hopefully it will just work. Event: monitor gets unplugged ----------------------------- When a monitor gets unplugged, module-udev-detect gets a notified, and it should figure out that a PCM device has disappeared. It should then call pa_alsa_card_pcm_removed(), which is a new function that needs to be implemented. pa_alsa_card_pcm_removed() should mirror pa_alsa_card_pcm_added(), just undoing the things that _added() did, in reverse order. So, first it should call pa_card_remove_profile(). That function doesn't exist currently, so it needs to be implemented. Next pa_alsa_card_pcm_removed() should free the pa_alsa_profile, pa_alsa_mapping and pa_alsa_path objects corresponding to the removed device. I think that's it for pa_alsa_card_pcm_removed(). If the profile that is being removed is active, pa_card_remove_profile() should change the card profile to something else. I suppose it should use the same logic as what pa_card_new() uses when choosing the default profile. -- Tanu