[pulseaudio-discuss] [PATCH] switch-on-port-available: check and change default sink or source
Suppose your machine has two sound cards as below: Card#0(HDA INTEL HDMI)-> Sink#0(hdmi-stereo)->hdmi-output(priority: 5900) Card#1(HDA INTEL PCH)->Sink#1(analog-stereo)->headphones(priority: 9000) If neither hdmi cable nor headphone plug into the machine, the default sink will randomly be Sink#0 or Sink#1, let us assume it is Sink#1, then users plug hdmi cable into the machine, the port hdmi-output will change to the state PA_AVAILABLE_YES, so the Sink#0 has a port with state YES, while the Sink#1 still has a port with state NO, in this situation it is reasonable to change the default_sink to Sink#0, but current code can't do that. Let us suppose another situation, both hdmi cable and headphone are plugged into the machine, and the Sink#0 is the default sink, if users unplug the hdmi cable, the port hdmi-output is changed to NO while the port headphone is still kept YES, in this situation it is reasonable to switch the default_sink to Sink#1, but current code can't do that. This issue also applies to the pa_source as well. If there is only one sound card and both Sink#0 and Sink#1 belong to this card (latest Intel platform like skylake or kabylake only has one sound card), there is no issue. It looks like the current switch-on-port-available can't handle multiple sound cards well. To fix it, adding a function to check and change default sink or source after executing switch_to_port() or switch_from_port(). Signed-off-by: Hui Wang --- src/modules/module-switch-on-port-available.c | 145 ++ 1 file changed, 145 insertions(+) diff --git a/src/modules/module-switch-on-port-available.c b/src/modules/module-switch-on-port-available.c index b9a0f3b..e1113ea 100644 --- a/src/modules/module-switch-on-port-available.c +++ b/src/modules/module-switch-on-port-available.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "module-switch-on-port-available-symdef.h" @@ -272,6 +273,148 @@ static bool switch_from_port(pa_device_port *port) { return false; } +/* This function refers to sink_put_hook_callback() in the module-switch-on-connect.c */ +static void move_to_new_default_sink(pa_core *c, pa_sink *ori_sink, pa_sink *new_sink) +{ +pa_sink_input *i; +uint32_t idx; + +pa_namereg_set_default_sink(c, new_sink); +/* Now move all old inputs over */ +if (pa_idxset_size(ori_sink->inputs) <= 0) { + pa_log_debug("No sink inputs to move away."); + return; +} + +PA_IDXSET_FOREACH(i, ori_sink->inputs, idx) { + if (i->save_sink || !PA_SINK_INPUT_IS_LINKED(i->state)) + continue; + + if (pa_sink_input_move_to(i, new_sink, false) < 0) + pa_log_info("Failed to move sink input %u \"%s\" to %s.", i->index, + pa_strnull(pa_proplist_gets(i->proplist, PA_PROP_APPLICATION_NAME)), new_sink->name); + else + pa_log_info("Successfully moved sink input %u \"%s\" to %s.", i->index, + pa_strnull(pa_proplist_gets(i->proplist, PA_PROP_APPLICATION_NAME)), new_sink->name); +} +} + +/* This function refers to source_put_hook_callback() in the module-switch-on-connect.c */ +static void move_to_new_default_source(pa_core *c, pa_source *ori_src, pa_source *new_src) +{ +pa_source_output *o; +uint32_t idx; + +pa_namereg_set_default_source(c, new_src); + +/* Now move all old outputs over */ +if (pa_idxset_size(ori_src->outputs) <= 0) { + pa_log_debug("No source outputs to move away."); + return; +} + +PA_IDXSET_FOREACH(o, ori_src->outputs, idx) { +if (o->save_source || !PA_SOURCE_OUTPUT_IS_LINKED(o->state)) +continue; + +if (pa_source_output_move_to(o, new_src, false) < 0) +pa_log_info("Failed to move source output %u \"%s\" to %s.", o->index, +pa_strnull(pa_proplist_gets(o->proplist, PA_PROP_APPLICATION_NAME)), new_src->name); +else +pa_log_info("Successfully moved source output %u \"%s\" to %s.", o->index, +pa_strnull(pa_proplist_gets(o->proplist, PA_PROP_APPLICATION_NAME)), new_src->name); +} +} + +/* + When a port changes to PA_AVAILABLE_YES, the original code tries to set it to + be the active_port in its own sink/source. After that we also need to check if + its sink/source is the default_sink/source or not, if it is not, it is possible + that all ports in the default_sink/source are in the state PA_AVAILABLE_NO, + in that case it is reasonable to replace the default_sink/source with this sink/source. + To do so, we will check the conditions as below: + - the default_sink/source doesn't have active_port + - the active_port of default_sink/source is in the s
[pulseaudio-discuss] [PATCH] switch-on-port-available: check and change default sink or source
Suppose your machine has two sound cards as below: Card#0(HDA INTEL HDMI)-> Sink#0(hdmi-stereo)->hdmi-output(priority: 5900) Card#1(HDA INTEL PCH)->Sink#1(analog-stereo)->headphones(priority: 9000) If neither hdmi cable nor headphone plug into the machine, the default sink will randomly be Sink#0 or Sink#1, let us assume it is Sink#1, then users plug hdmi cable into the machine, the port hdmi-output will change to the state PA_AVAILABLE_YES, so the Sink#0 has a port with state YES, while the Sink#1 still has a port with state NO, in this situation it is reasonable to change the default_sink to Sink#0, but current code can't do that. Let us suppose another situation, both hdmi cable and headphone are plugged into the machine, and the Sink#0 is the default sink, if users unplug the hdmi cable, the port hdmi-output is changed to NO while the port headphone is still kept YES, in this situation it is reasonable to switch the default_sink to Sink#1, but current code can't do that. This issue also applies to the pa_source as well. If there is only one sound card and both Sink#0 and Sink#1 belong to this card (latest Intel platform like skylake or kabylake only has one sound card), there is no issue. It looks like the current switch-on-port-available can't handle multiple sound cards well. To fix it, adding a function to check and change default sink or source after executing switch_to_port() or switch_from_port(). Signed-off-by: Hui Wang --- src/modules/module-switch-on-port-available.c | 145 ++ 1 file changed, 145 insertions(+) diff --git a/src/modules/module-switch-on-port-available.c b/src/modules/module-switch-on-port-available.c index b9a0f3b..e1113ea 100644 --- a/src/modules/module-switch-on-port-available.c +++ b/src/modules/module-switch-on-port-available.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "module-switch-on-port-available-symdef.h" @@ -272,6 +273,148 @@ static bool switch_from_port(pa_device_port *port) { return false; } +/* This function refers to sink_put_hook_callback() in the module-switch-on-connect.c */ +static void move_to_new_default_sink(pa_core *c, pa_sink *ori_sink, pa_sink *new_sink) +{ +pa_sink_input *i; +uint32_t idx; + +pa_namereg_set_default_sink(c, new_sink); +/* Now move all old inputs over */ +if (pa_idxset_size(ori_sink->inputs) <= 0) { + pa_log_debug("No sink inputs to move away."); + return; +} + +PA_IDXSET_FOREACH(i, ori_sink->inputs, idx) { + if (i->save_sink || !PA_SINK_INPUT_IS_LINKED(i->state)) + continue; + + if (pa_sink_input_move_to(i, new_sink, false) < 0) + pa_log_info("Failed to move sink input %u \"%s\" to %s.", i->index, + pa_strnull(pa_proplist_gets(i->proplist, PA_PROP_APPLICATION_NAME)), new_sink->name); + else + pa_log_info("Successfully moved sink input %u \"%s\" to %s.", i->index, + pa_strnull(pa_proplist_gets(i->proplist, PA_PROP_APPLICATION_NAME)), new_sink->name); +} +} + +/* This function refers to source_put_hook_callback() in the module-switch-on-connect.c */ +static void move_to_new_default_source(pa_core *c, pa_source *ori_src, pa_source *new_src) +{ +pa_source_output *o; +uint32_t idx; + +pa_namereg_set_default_source(c, new_src); + +/* Now move all old outputs over */ +if (pa_idxset_size(ori_src->outputs) <= 0) { + pa_log_debug("No source outputs to move away."); + return; +} + +PA_IDXSET_FOREACH(o, ori_src->outputs, idx) { +if (o->save_source || !PA_SOURCE_OUTPUT_IS_LINKED(o->state)) +continue; + +if (pa_source_output_move_to(o, new_src, false) < 0) +pa_log_info("Failed to move source output %u \"%s\" to %s.", o->index, +pa_strnull(pa_proplist_gets(o->proplist, PA_PROP_APPLICATION_NAME)), new_src->name); +else +pa_log_info("Successfully moved source output %u \"%s\" to %s.", o->index, +pa_strnull(pa_proplist_gets(o->proplist, PA_PROP_APPLICATION_NAME)), new_src->name); +} +} + +/* + When a port changes to PA_AVAILABLE_YES, the original code tries to set it to + be the active_port in its own sink/source. After that we also need to check if + its sink/source is the default_sink/source or not, if it is not, it is possible + that all ports in the default_sink/source are in the state PA_AVAILABLE_NO, + in that case it is reasonable to replace the default_sink/source with this sink/source. + To do so, we will check the conditions as below: + - the default_sink/source doesn't have active_port + - the active_port of default_sink/source is in the s
Re: [pulseaudio-discuss] [PATCH] switch-on-port-available: check and change default sink or source
Hello Tanu, Could you please take a look at this patch, you are the maintainer and recently contributed couple of commits to module-switch-on-port-available.c. :-) Thanks in advance. Hui. On 04/27/2017 11:20 AM, Hui Wang wrote: Suppose your machine has two sound cards as below: Card#0(HDA INTEL HDMI)-> Sink#0(hdmi-stereo)->hdmi-output(priority: 5900) Card#1(HDA INTEL PCH)->Sink#1(analog-stereo)->headphones(priority: 9000) If neither hdmi cable nor headphone plug into the machine, the default sink will randomly be Sink#0 or Sink#1, let us assume it is Sink#1, then users plug hdmi cable into the machine, the port hdmi-output will change to the state PA_AVAILABLE_YES, so the Sink#0 has a port with state YES, while the Sink#1 still has a port with state NO, in this situation it is reasonable to change the default_sink to Sink#0, but current code can't do that. Let us suppose another situation, both hdmi cable and headphone are plugged into the machine, and the Sink#0 is the default sink, if users unplug the hdmi cable, the port hdmi-output is changed to NO while the port headphone is still kept YES, in this situation it is reasonable to switch the default_sink to Sink#1, but current code can't do that. This issue also applies to the pa_source as well. If there is only one sound card and both Sink#0 and Sink#1 belong to this card (latest Intel platform like skylake or kabylake only has one sound card), there is no issue. It looks like the current switch-on-port-available can't handle multiple sound cards well. To fix it, adding a function to check and change default sink or source after executing switch_to_port() or switch_from_port(). Signed-off-by: Hui Wang --- src/modules/module-switch-on-port-available.c | 145 ++ 1 file changed, 145 insertions(+) diff --git a/src/modules/module-switch-on-port-available.c b/src/modules/module-switch-on-port-available.c index b9a0f3b..e1113ea 100644 --- a/src/modules/module-switch-on-port-available.c +++ b/src/modules/module-switch-on-port-available.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "module-switch-on-port-available-symdef.h" @@ -272,6 +273,148 @@ static bool switch_from_port(pa_device_port *port) { return false; } +/* This function refers to sink_put_hook_callback() in the module-switch-on-connect.c */ +static void move_to_new_default_sink(pa_core *c, pa_sink *ori_sink, pa_sink *new_sink) +{ +pa_sink_input *i; +uint32_t idx; + +pa_namereg_set_default_sink(c, new_sink); +/* Now move all old inputs over */ +if (pa_idxset_size(ori_sink->inputs) <= 0) { + pa_log_debug("No sink inputs to move away."); + return; +} + +PA_IDXSET_FOREACH(i, ori_sink->inputs, idx) { + if (i->save_sink || !PA_SINK_INPUT_IS_LINKED(i->state)) + continue; + + if (pa_sink_input_move_to(i, new_sink, false) < 0) + pa_log_info("Failed to move sink input %u \"%s\" to %s.", i->index, + pa_strnull(pa_proplist_gets(i->proplist, PA_PROP_APPLICATION_NAME)), new_sink->name); + else + pa_log_info("Successfully moved sink input %u \"%s\" to %s.", i->index, + pa_strnull(pa_proplist_gets(i->proplist, PA_PROP_APPLICATION_NAME)), new_sink->name); +} +} + +/* This function refers to source_put_hook_callback() in the module-switch-on-connect.c */ +static void move_to_new_default_source(pa_core *c, pa_source *ori_src, pa_source *new_src) +{ +pa_source_output *o; +uint32_t idx; + +pa_namereg_set_default_source(c, new_src); + +/* Now move all old outputs over */ +if (pa_idxset_size(ori_src->outputs) <= 0) { + pa_log_debug("No source outputs to move away."); + return; +} + +PA_IDXSET_FOREACH(o, ori_src->outputs, idx) { +if (o->save_source || !PA_SOURCE_OUTPUT_IS_LINKED(o->state)) +continue; + +if (pa_source_output_move_to(o, new_src, false) < 0) +pa_log_info("Failed to move source output %u \"%s\" to %s.", o->index, +pa_strnull(pa_proplist_gets(o->proplist, PA_PROP_APPLICATION_NAME)), new_src->name); +else +pa_log_info("Successfully moved source output %u \"%s\" to %s.", o->index, +pa_strnull(pa_proplist_gets(o->proplist, PA_PROP_APPLICATION_NAME)), new_src->name); +} +} + +/* + When a port changes to PA_AVAILABLE_YES, the original code tries to set it to + be the active_port in its own sink/source. After that we also need to check if + its sink/source is the default_sink/source or not, if it is not, it is possible + that all ports in the default_sink/source are in the state PA_AVAILABLE_NO, + in that cas
Re: [pulseaudio-discuss] [PATCH] switch-on-port-available: check and change default sink or source
On 04/29/2017 09:04 PM, Tanu Kaskinen wrote: On Fri, 2017-04-28 at 12:21 +0800, Hui Wang wrote: Hello Tanu, Could you please take a look at this patch, you are the maintainer and recently contributed couple of commits to module-switch-on-port-available.c. :-) Well, I'm trying to concentrate on preparing for the release, so I don't do patch reviews much at the moment. Now that I read the commit message, I have some comments, though. On 04/27/2017 11:20 AM, Hui Wang wrote: Suppose your machine has two sound cards as below: Card#0(HDA INTEL HDMI)-> Sink#0(hdmi-stereo)->hdmi-output(priority: 5900) Card#1(HDA INTEL PCH)->Sink#1(analog-stereo)->headphones(priority: 9000) If neither hdmi cable nor headphone plug into the machine, the default sink will randomly be Sink#0 or Sink#1, let us assume it is Sink#1, then users plug hdmi cable into the machine, the port hdmi-output will change to the state PA_AVAILABLE_YES, so the Sink#0 has a port with state YES, while the Sink#1 still has a port with state NO, in this situation it is reasonable to change the default_sink to Sink#0, but current code can't do that. This problem should be fixed by these two patches: https://patchwork.freedesktop.org/patch/139179/ https://patchwork.freedesktop.org/patch/139178/ The patches have been reviewed, but I haven't yet pushed them. I'm not sure if they'll be in the next release or not (I need to ask Georg and Arun if they want to grant a freeze exception for these patches). Let us suppose another situation, both hdmi cable and headphone are plugged into the machine, and the Sink#0 is the default sink, if users unplug the hdmi cable, the port hdmi-output is changed to NO while the port headphone is still kept YES, in this situation it is reasonable to switch the default_sink to Sink#1, but current code can't do that. This should be fixed too by those two patches mentioned above. Good to know that, look forward to those patches being merged to the mainline. :-) Thank you for your comment and thank you for your patches. Cheers, Hui. ___ pulseaudio-discuss mailing list pulseaudio-discuss@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
Re: [pulseaudio-discuss] [PATCH] switch-on-port-available: check and change default sink or source
On 05/02/2017 09:27 PM, Tanu Kaskinen wrote: On Tue, 2017-05-02 at 08:55 +0800, Hui Wang wrote: On 04/29/2017 09:04 PM, Tanu Kaskinen wrote: On Fri, 2017-04-28 at 12:21 +0800, Hui Wang wrote: Hello Tanu, Could you please take a look at this patch, you are the maintainer and recently contributed couple of commits to module-switch-on-port-available.c. :-) Well, I'm trying to concentrate on preparing for the release, so I don't do patch reviews much at the moment. Now that I read the commit message, I have some comments, though. On 04/27/2017 11:20 AM, Hui Wang wrote: Suppose your machine has two sound cards as below: Card#0(HDA INTEL HDMI)-> Sink#0(hdmi-stereo)->hdmi-output(priority: 5900) Card#1(HDA INTEL PCH)->Sink#1(analog-stereo)->headphones(priority: 9000) If neither hdmi cable nor headphone plug into the machine, the default sink will randomly be Sink#0 or Sink#1, let us assume it is Sink#1, then users plug hdmi cable into the machine, the port hdmi-output will change to the state PA_AVAILABLE_YES, so the Sink#0 has a port with state YES, while the Sink#1 still has a port with state NO, in this situation it is reasonable to change the default_sink to Sink#0, but current code can't do that. This problem should be fixed by these two patches: https://patchwork.freedesktop.org/patch/139179/ https://patchwork.freedesktop.org/patch/139178/ The patches have been reviewed, but I haven't yet pushed them. I'm not sure if they'll be in the next release or not (I need to ask Georg and Arun if they want to grant a freeze exception for these patches). Let us suppose another situation, both hdmi cable and headphone are plugged into the machine, and the Sink#0 is the default sink, if users unplug the hdmi cable, the port hdmi-output is changed to NO while the port headphone is still kept YES, in this situation it is reasonable to switch the default_sink to Sink#1, but current code can't do that. This should be fixed too by those two patches mentioned above. Good to know that, look forward to those patches being merged to the mainline. :-) Thank you for your comment and thank you for your patches. I pushed the patches to master now. I hope they solve your problems! Today I tested the latest master branch (already including your two patches), seems it did not fix the problem. Below is my testing detail: Install ubuntu 16.04 on my laptop. clone the latest pulseaudio source code, checkout master branch build the source code: ./autogen.sh;make kill the existing pulseaudio and run the latest pulseaudio: pulseaudio --kill && ./src/pulseaudio -vvvnF ./src/default.pa -p $(pwd)/src On this machine, we have sound cards, sinks and ports like below: Card#0(HDA INTEL HDMI)-> Sink#0(hdmi-stereo)->hdmi-output(priority: 5900) Card#1(HDA INTEL PCH)->Sink#1(analog-stereo)->headphones(priority: 9000) with the new pulseaudio, I can only see one sink (analog-stereo) through pactl list sinks at the beginning. After I plug the HDMI cable (headphone is not plugged), I can see two sinks via pactl list sinks, but the default sink is still the analog-stereo, here I expect the default sink is hdmi-stereo since the headphone is not plugged yet. Then I plug the headphone, and I select the hdmi (hdmi is also plugged in) as the default sink, after a while I unplug the hdmi cable, here I expect the default sink is back to analog-stereo since headphone is still plugged, but the default sink did not switch to analog-stereo. BTW after I unplug the hdmi cable, I can still see two sinks. Cheers, Hui. ___ pulseaudio-discuss mailing list pulseaudio-discuss@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
[pulseaudio-discuss] [PATCH] alsa: make headset-mic scanned earlier than headphone-mic
On some Dell machines with realtek codec, they have a headset audio jack which supports headphone, headset and pure microphone, but this audio jack can only detect something is plugged in but doesn't have capabilites to distinguish what is plugged in. So we need to apply the fixup similar to ALC298_FIXUP_DELL1_MIC_NO_PRESENCE to the kernel driver. When something is plugged in, a pop-up dialogue shows up and users can select what is plugged in. On some Dell machines (especially desktop computers), they have no internal microphone, if users plug a headphone and select the headphone, the headphone is supposed to work, but there is no sound can be played via headphone. Through debugging, I found the root cause has something to do with the active_port of pa-source, since there is no internal microphone, and there is no other available input devices, the headphone-mic and headset-mic will be the candidates to be the active_port, and they have the same priority and headphone-mic is scanned earlier than headset-mic, so the headphone-mic is set to be the active_port. After users select the headphone, the function alc_update_headset_mode() in the kernel driver will be called, in this function it will check what is the default input device for that jack, if it is headphone-mic, that means users want this jack to work as a pure microphone jack, then it will configure the codec and the jack is changed to be a mic-in jack. As a result even users plug and select the headphone, but this jack can't work with headphone. A simple fix for this issue is to exchange the position of headphone-mic and headset-mic, then the headset-mic will be the active_port of pa-source if there is no internal microphone and no other available input devices. Signed-off-by: Hui Wang --- src/modules/alsa/mixer/profile-sets/default.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/alsa/mixer/profile-sets/default.conf b/src/modules/alsa/mixer/profile-sets/default.conf index f412058..16ee567 100644 --- a/src/modules/alsa/mixer/profile-sets/default.conf +++ b/src/modules/alsa/mixer/profile-sets/default.conf @@ -112,7 +112,7 @@ priority = 2 device-strings = front:%f channel-map = left,right paths-output = analog-output analog-output-lineout analog-output-speaker analog-output-headphones analog-output-headphones-2 -paths-input = analog-input-front-mic analog-input-rear-mic analog-input-internal-mic analog-input-dock-mic analog-input analog-input-mic analog-input-linein analog-input-aux analog-input-video analog-input-tvtuner analog-input-fm analog-input-mic-line analog-input-headphone-mic analog-input-headset-mic +paths-input = analog-input-front-mic analog-input-rear-mic analog-input-internal-mic analog-input-dock-mic analog-input analog-input-mic analog-input-linein analog-input-aux analog-input-video analog-input-tvtuner analog-input-fm analog-input-mic-line analog-input-headset-mic analog-input-headphone-mic priority = 10 [Mapping analog-surround-21] -- 1.9.1 ___ pulseaudio-discuss mailing list pulseaudio-discuss@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
Re: [pulseaudio-discuss] [PATCH] switch-on-port-available: check and change default sink or source
On 05/03/2017 06:51 PM, Tanu Kaskinen wrote: On Wed, 2017-05-03 at 11:23 +0800, Hui Wang wrote: Today I tested the latest master branch (already including your two patches), seems it did not fix the problem. Below is my testing detail: Install ubuntu 16.04 on my laptop. clone the latest pulseaudio source code, checkout master branch build the source code: ./autogen.sh;make kill the existing pulseaudio and run the latest pulseaudio: pulseaudio --kill && ./src/pulseaudio -vvvnF ./src/default.pa -p $(pwd)/src On this machine, we have sound cards, sinks and ports like below: Card#0(HDA INTEL HDMI)-> Sink#0(hdmi-stereo)->hdmi-output(priority: 5900) Card#1(HDA INTEL PCH)->Sink#1(analog-stereo)->headphones(priority: 9000) No speaker port at all on the PCH card? Sorry for late response, just came back from a vacation. I removed the speaker from the kernel driver intentionally for debugging another audio bug. But it does not matter, if I don't remove the speaker, the Sink#1 has the speaker on it, and the default sink is Sink#1, after plugging the HDMI cable, the default sink is still Sink#1, it is expected since Sink#1 has an available port which has higher priority than HDMI port, then I select the HDMI to be the default sink manually, now the default sink is Sink#0. After that I unplug the HDMI cable, the Sink#1 is expected to be the default sink since the Sink#0 has no available ports on it, but the default sink doesn't switch back to Sink#1. with the new pulseaudio, I can only see one sink (analog-stereo) through pactl list sinks at the beginning. After I plug the HDMI cable (headphone is not plugged), I can see two sinks via pactl list sinks, but the default sink is still the analog- stereo, here I expect the default sink is hdmi-stereo since the headphone is not plugged yet. That's what I'd expect too. Is the headphone port marked as unavailable as it should? Yes, it is marked "not available". Then I plug the headphone, and I select the hdmi (hdmi is also plugged in) as the default sink, after a while I unplug the hdmi cable, here I expect the default sink is back to analog-stereo since headphone is still plugged, but the default sink did not switch to analog-stereo. BTW after I unplug the hdmi cable, I can still see two sinks. The default sink is set in pa_core_update_default_sink() in src/pulsecore/core.c. That function uses the compare_sinks() function, and the first thing compare_sinks() does is to check if one of the compared sinks has an unavailable port active. Can you figure out what goes wrong? Is pa_core_update_default_sink() not called when you plug in or unplug things, or does pa_core_update_default_sink() really choose a sink whose active port is unavailable? Through debugging, I found the function pa_core_update_default_sink() is not called when unplug the HDMI cable in the situation above. The good news is after applying your new patch "[PATCH] sink, source: update the default sink/source on port switches", the issue is fixed. The function pa_core_update_default_sink() is called when plugging/unplugging some audio output devices, and the default_sink is changed as expected. Thank you for your patches. :-) Thanks, Hui. ___ pulseaudio-discuss mailing list pulseaudio-discuss@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
Re: [pulseaudio-discuss] [PATCH] alsa: make headset-mic scanned earlier than headphone-mic
Hello Tanu, Could you please help take a look at this patch? This patch really fix an issue on some Dell machines (with realtek codec and has no internal microphone on them), And I think this minor change will not introduce regression, it is pretty safe. Thanks in advance. Hui. On 05/16/2017 11:21 AM, Hui Wang wrote: On some Dell machines with realtek codec, they have a headset audio jack which supports headphone, headset and pure microphone, but this audio jack can only detect something is plugged in but doesn't have capabilites to distinguish what is plugged in. So we need to apply the fixup similar to ALC298_FIXUP_DELL1_MIC_NO_PRESENCE to the kernel driver. When something is plugged in, a pop-up dialogue shows up and users can select what is plugged in. On some Dell machines (especially desktop computers), they have no internal microphone, if users plug a headphone and select the headphone, the headphone is supposed to work, but there is no sound can be played via headphone. Through debugging, I found the root cause has something to do with the active_port of pa-source, since there is no internal microphone, and there is no other available input devices, the headphone-mic and headset-mic will be the candidates to be the active_port, and they have the same priority and headphone-mic is scanned earlier than headset-mic, so the headphone-mic is set to be the active_port. After users select the headphone, the function alc_update_headset_mode() in the kernel driver will be called, in this function it will check what is the default input device for that jack, if it is headphone-mic, that means users want this jack to work as a pure microphone jack, then it will configure the codec and the jack is changed to be a mic-in jack. As a result even users plug and select the headphone, but this jack can't work with headphone. A simple fix for this issue is to exchange the position of headphone-mic and headset-mic, then the headset-mic will be the active_port of pa-source if there is no internal microphone and no other available input devices. Signed-off-by: Hui Wang --- src/modules/alsa/mixer/profile-sets/default.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/alsa/mixer/profile-sets/default.conf b/src/modules/alsa/mixer/profile-sets/default.conf index f412058..16ee567 100644 --- a/src/modules/alsa/mixer/profile-sets/default.conf +++ b/src/modules/alsa/mixer/profile-sets/default.conf @@ -112,7 +112,7 @@ priority = 2 device-strings = front:%f channel-map = left,right paths-output = analog-output analog-output-lineout analog-output-speaker analog-output-headphones analog-output-headphones-2 -paths-input = analog-input-front-mic analog-input-rear-mic analog-input-internal-mic analog-input-dock-mic analog-input analog-input-mic analog-input-linein analog-input-aux analog-input-video analog-input-tvtuner analog-input-fm analog-input-mic-line analog-input-headphone-mic analog-input-headset-mic +paths-input = analog-input-front-mic analog-input-rear-mic analog-input-internal-mic analog-input-dock-mic analog-input analog-input-mic analog-input-linein analog-input-aux analog-input-video analog-input-tvtuner analog-input-fm analog-input-mic-line analog-input-headset-mic analog-input-headphone-mic priority = 10 [Mapping analog-surround-21] ___ pulseaudio-discuss mailing list pulseaudio-discuss@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
Re: [pulseaudio-discuss] [PATCH] alsa: make headset-mic scanned earlier than headphone-mic
On 05/20/2017 10:51 PM, Tanu Kaskinen wrote: On Fri, 2017-05-19 at 09:29 +0800, Hui Wang wrote: Hello Tanu, Could you please help take a look at this patch? This patch really fix an issue on some Dell machines (with realtek codec and has no internal microphone on them), And I think this minor change will not introduce regression, it is pretty safe. The patch only changes the order in which headset-mic and headphone-mic are listed, and that order should not have any real impact on anything. There's clearly a bug somewhere, but the bug can't be that the paths are listed in the wrong order, since the order should not matter. Yes, you are right. In theory, the headset-mic and headphone-mic have the same priority, so exchanging their order should not have any real impact on anything. But in practice, this bug exposes that in some situation( when there are only headphone-mic and headset-mic, and neither of them is plugged in.), the headphone-mic is not suitable to be the default active_port. So do you think if it is acceptable that I don't exchange their order, I just adjust their priorities to make the headset-mic's priority a bit higher than headphone-mic's? If the port must not be headphone-mic when the user chooses headphones in the UI, couldn't the UI program tell pulseaudio to switch to headset-mic? Yes, the UI program could do that. If it is not allowed to adjust their priorities, we have to change the UI program. Thanks, Hui. ___ pulseaudio-discuss mailing list pulseaudio-discuss@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
Re: [pulseaudio-discuss] [PATCH] alsa: make headset-mic scanned earlier than headphone-mic
On 05/23/2017 04:20 PM, Tanu Kaskinen wrote: On Tue, 2017-05-23 at 11:04 +0800, Hui Wang wrote: On 05/20/2017 10:51 PM, Tanu Kaskinen wrote: On Fri, 2017-05-19 at 09:29 +0800, Hui Wang wrote: Hello Tanu, Could you please help take a look at this patch? This patch really fix an issue on some Dell machines (with realtek codec and has no internal microphone on them), And I think this minor change will not introduce regression, it is pretty safe. The patch only changes the order in which headset-mic and headphone-mic are listed, and that order should not have any real impact on anything. There's clearly a bug somewhere, but the bug can't be that the paths are listed in the wrong order, since the order should not matter. Yes, you are right. In theory, the headset-mic and headphone-mic have the same priority, so exchanging their order should not have any real impact on anything. But in practice, this bug exposes that in some situation( when there are only headphone-mic and headset-mic, and neither of them is plugged in.), the headphone-mic is not suitable to be the default active_port. So do you think if it is acceptable that I don't exchange their order, I just adjust their priorities to make the headset-mic's priority a bit higher than headphone-mic's? If I understand correctly, headphones and headsets only work with the headset-mic port, and microphones only work with the headphone-mic port. Since it's more likely that a user plugs in headphones or a headset than a microphone, I think it's ok to make the headset-mic priority a bit higher than headphone-mic. There is only one audio jack, users can plug headphone, headset or microphone into it. On some Dell machines which has realtek codec, the codec/audio jack can't distinguish from hardware perspective what devices the user plugged in, so users need to do a choice from UI program: When user plug in a headphone and select the headphone, the UI program will set the headphone to be the active_port of pa_sink, and kernel audio driver (patch_reaktek) will configure the codec to make that audio jack work as a headphone jack When user plug in a headset and select the headset-mic, the UI program will set the headphone to be the active_port of pa_sink and set the headset-mic to be the active_port of pa_source, and kernel driver will configure the audio jack to be the headset jack When user plug in a microphone and select the headphone-mic, the UI program will set the headphone-mic to be the active_port of pa_source, and kernel driver will configure the audio jack to be the microphone jack, then this jack can't work with headphone. However, that still doesn't fix the bug properly, I think. What if the user plugs in a microphone and selects it in the UI? What will make pulseaudio switch to the headphone-mic? The UI program will do that. The UI program will call pa_context_set_source_port_by_index() to do that. What will make pulseaudio switch to the headset-mic port if headphones or a headset is plugged in later? This problem does not exist, since there is only one physical jack, if user want to plug headset or headphone, he need to unplug the microphone first. After user plug in the headphone or headset, the UI program will call pa_context_set_source/sink_port_by_index() to set active port according to user's choice. It sounds like the kernel might be buggy too. Why does it have to disable headphone output if pulseaudio's active source port happens to be headphone-mic? It is not a bug, some realtek codec can configure a port (pins) to be input or output, that means a physical jack can be configured as headphone jack or microphone jack. When headphone-mic is active source port, the audio driver only disable the headphone shared the same port with this headphone-mic, the kernel driver doesn't disable other headphones. The kernel seems to select from two mic modes: headset or microphone, but I don't understand why it doesn't have a mode for no mic input at all, which could be used when headphones are plugged in. For most cases (almost 99.999% cases), the output choice and input choice doesn't impact each other. This problem only happens on some dell machines, which has realtek codec, and has a physical audio jack to support headphone, headset or microphone, and the codec has no hardware ability to distinguish devices. ___ pulseaudio-discuss mailing list pulseaudio-discuss@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
Re: [pulseaudio-discuss] [PATCH] alsa: make headset-mic scanned earlier than headphone-mic
On 05/23/2017 07:35 PM, Tanu Kaskinen wrote: On Tue, 2017-05-23 at 17:36 +0800, Hui Wang wrote: On 05/23/2017 04:20 PM, Tanu Kaskinen wrote: On Tue, 2017-05-23 at 11:04 +0800, Hui Wang wrote: On 05/20/2017 10:51 PM, Tanu Kaskinen wrote: On Fri, 2017-05-19 at 09:29 +0800, Hui Wang wrote: Hello Tanu, Could you please help take a look at this patch? This patch really fix an issue on some Dell machines (with realtek codec and has no internal microphone on them), And I think this minor change will not introduce regression, it is pretty safe. The patch only changes the order in which headset-mic and headphone-mic are listed, and that order should not have any real impact on anything. There's clearly a bug somewhere, but the bug can't be that the paths are listed in the wrong order, since the order should not matter. Yes, you are right. In theory, the headset-mic and headphone-mic have the same priority, so exchanging their order should not have any real impact on anything. But in practice, this bug exposes that in some situation( when there are only headphone-mic and headset-mic, and neither of them is plugged in.), the headphone-mic is not suitable to be the default active_port. So do you think if it is acceptable that I don't exchange their order, I just adjust their priorities to make the headset-mic's priority a bit higher than headphone-mic's? If I understand correctly, headphones and headsets only work with the headset-mic port, and microphones only work with the headphone-mic port. Since it's more likely that a user plugs in headphones or a headset than a microphone, I think it's ok to make the headset-mic priority a bit higher than headphone-mic. There is only one audio jack, users can plug headphone, headset or microphone into it. On some Dell machines which has realtek codec, the codec/audio jack can't distinguish from hardware perspective what devices the user plugged in, so users need to do a choice from UI program: When user plug in a headphone and select the headphone, the UI program will set the headphone to be the active_port of pa_sink, and kernel audio driver (patch_reaktek) will configure the codec to make that audio jack work as a headphone jack What makes the kernel do that? Does the kernel rely only on the mixer settings set by pulseaudio to figure out how to configure the jack? Which mixer elements affect the kernel's decision? It depends on the mixer "Capture Source". In the kernel, the function alc_update_headset_mode() in the $kernel_dir/sound/pci/hda/patch_realtek.c will handle it. When user plug in a headset and select the headset-mic, the UI program will set the headphone to be the active_port of pa_sink and set the headset-mic to be the active_port of pa_source, and kernel driver will configure the audio jack to be the headset jack When user plug in a microphone and select the headphone-mic, the UI program will set the headphone-mic to be the active_port of pa_source, and kernel driver will configure the audio jack to be the microphone jack, then this jack can't work with headphone. However, that still doesn't fix the bug properly, I think. What if the user plugs in a microphone and selects it in the UI? What will make pulseaudio switch to the headphone-mic? The UI program will do that. The UI program will call pa_context_set_source_port_by_index() to do that. What will make pulseaudio switch to the headset-mic port if headphones or a headset is plugged in later? This problem does not exist, since there is only one physical jack, if user want to plug headset or headphone, he need to unplug the microphone first. After user plug in the headphone or headset, the UI program will call pa_context_set_source/sink_port_by_index() to set active port according to user's choice. But isn't it so that if the user selects headphones, the UI program won't change the source port? So if the user first had a microphone plugged in, and then unplugged that and plugged in headphones instead, the headphones won't work, because the headphone-mic port is still active. Yes, you are right, this is another issue I did not think about before. Because most of the machines (laptop) have internal microphone, and after the headphone-mic is unplugged, the input source will switch to internal microphone automatically, so this issue has not exposed. I admit that UI program has some problems, it should not only take care of output devices when users select headphone. The UI program needs to be improved. BTW, I just did a test, increased the headset-mic's priority to 88, and keep the headphone-mic's priority to 87, after booting up, the default input active_port is headset-mic (that is expected), I plug a microphone and select "headphone-mic" from UI program, the input active_port is headphone-mic now, then I unplug the headphone-mic, the
Re: [pulseaudio-discuss] [PATCH] alsa: make headset-mic scanned earlier than headphone-mic
keep the headphone-mic's priority to 87, after booting up, the default input active_port is headset-mic (that is expected), I plug a microphone and select "headphone-mic" from UI program, the input active_port is headphone-mic now, then I unplug the headphone-mic, the input active_port is changed back to headset-mic. So changing priority really can fix these two issues. Do both ports change availability status from "no" to "unknown" when anything is plugged in? That would explain why increasing the headset- mic priority fixes both issues. Yes, it works in the way as you guess. I guess you'll write a patch for increasing the port priority. I would strongly recommend changing the UI program as well, but that's up to you. I will write a patch to increase port priority first, later I will improve the UI program. Thanks, Hui. ___ pulseaudio-discuss mailing list pulseaudio-discuss@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
[pulseaudio-discuss] [PATCH] alsa: make priority of the port headset-mic higher than headphone-mic
There are two reasons for this change: 1. If it is a Dell desktop machine with the realtek codec, and there is no internal microphone on it, there is one physical audio jack which can support headphone, headset and microphone, but this audio jack does not have hardware capability to distinguish what is plugged in, after users plug in a headphone and select headphone from UI program, the headphone can't output any sound. There are many reasons for this issue, one of them is the active_port of pa_source is set to headphone-mic, that means the kernel audio driver will configure this audio jack to be a microphone jack instead of headphone jack. If we make the priority of headset-mic a bit higher than headphone-mic, the headset-mic will be the active_port of pa_source unless users select the headphone-mic on purpose, then this issue will be fixed. 2. Nowadays, the headset is more popular than traditional microphone, It is highly possible that users plug in a headset instead of microphone, it makes sense to make the headset-mic's priority higher than headphone-mic's. Signed-off-by: Hui Wang --- src/modules/alsa/mixer/paths/analog-input-headset-mic.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/alsa/mixer/paths/analog-input-headset-mic.conf b/src/modules/alsa/mixer/paths/analog-input-headset-mic.conf index b669bc4..579db6b 100644 --- a/src/modules/alsa/mixer/paths/analog-input-headset-mic.conf +++ b/src/modules/alsa/mixer/paths/analog-input-headset-mic.conf @@ -18,7 +18,7 @@ ; See analog-output.conf.common for an explanation on the directives [General] -priority = 87 +priority = 88 description-key = analog-input-microphone-headset [Jack Headset Mic] -- 1.9.1 ___ pulseaudio-discuss mailing list pulseaudio-discuss@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
[pulseaudio-discuss] [PATCH] alsa-mixer: Add support for usb audio in the Dell dock TB16
There are one headset jack on the front panel of TB16, through this jack, we have one stereo headphone output (hw:%f,0,0) and one mono headset-mic input (hw:%f,0,0); and there is one speaker output jack (hw:%f,1,0) on the rear panel of TB16. The detail information of the Dell dock TB16: http://www.dell.com/support/article/sg/en/sgbsdt1/SLN301105 Signed-off-by: Hui Wang --- .../alsa/mixer/profile-sets/90-pulseaudio.rules| 1 + .../profile-sets/dell-dock-tb16-usb-audio.conf | 55 ++ 2 files changed, 56 insertions(+) create mode 100644 src/modules/alsa/mixer/profile-sets/dell-dock-tb16-usb-audio.conf diff --git a/src/modules/alsa/mixer/profile-sets/90-pulseaudio.rules b/src/modules/alsa/mixer/profile-sets/90-pulseaudio.rules index 70e34e6..805a05b 100644 --- a/src/modules/alsa/mixer/profile-sets/90-pulseaudio.rules +++ b/src/modules/alsa/mixer/profile-sets/90-pulseaudio.rules @@ -98,5 +98,6 @@ ATTRS{idVendor}=="17cc", ATTRS{idProduct}=="1021", ENV{PULSE_PROFILE_SET}="nativ ATTRS{idVendor}=="0763", ATTRS{idProduct}=="2012", ENV{PULSE_PROFILE_SET}="maudio-fasttrack-pro.conf" ATTRS{idVendor}=="045e", ATTRS{idProduct}=="02bb", ENV{PULSE_PROFILE_SET}="kinect-audio.conf" ATTRS{idVendor}=="041e", ATTRS{idProduct}=="322c", ENV{PULSE_PROFILE_SET}="sb-omni-surround-5.1.conf" +ATTRS{idVendor}=="0bda", ATTRS{idProduct}=="4014", ENV{PULSE_PROFILE_SET}="dell-dock-tb16-usb-audio.conf" LABEL="pulseaudio_end" diff --git a/src/modules/alsa/mixer/profile-sets/dell-dock-tb16-usb-audio.conf b/src/modules/alsa/mixer/profile-sets/dell-dock-tb16-usb-audio.conf new file mode 100644 index 000..1186552 --- /dev/null +++ b/src/modules/alsa/mixer/profile-sets/dell-dock-tb16-usb-audio.conf @@ -0,0 +1,55 @@ +# This file is part of PulseAudio. +# +# PulseAudio is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 2.1 of the +# License, or (at your option) any later version. +# +# PulseAudio is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. + +; Dell Dock TB16 USB audio +; +; This card has two stereo pairs of output, One Mono input. +; +; See default.conf for an explanation on the directives used here. + +[General] +auto-profiles = no + +[Mapping analog-stereo-headphone] +description = Headphone +device-strings = hw:%f,0,0 +channel-map = left,right +direction = output + +[Mapping analog-stereo-speaker] +description = Speaker +device-strings = hw:%f,1,0 +channel-map = left,right +direction = output + +[Mapping analog-stereo-mic] +description = Headset-Mic +device-strings = hw:%f,0,0 +channel-map = left,right +direction = input + + +[Profile output:analog-stereo-speaker] +description = Speaker +output-mappings = analog-stereo-speaker +priority = 60 +skip-probe = yes + +[Profile output:analog-stereo-headphone+input:analog-stereo-mic] +description = Headset +output-mappings = analog-stereo-headphone +input-mappings = analog-stereo-mic +priority = 80 +skip-probe = yes -- 2.7.4 ___ pulseaudio-discuss mailing list pulseaudio-discuss@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
[pulseaudio-discuss] [PATCH] rescue-streams: try to find best one using availability and priority
Recently met a problem: when I disconnect the bluetooth headset, the pulseaudio automatically switch the sound to sink of HDMI output instead of the sink of internal speaker even though there is no HDMI cable connected. To fix this problem, I want to change the rule of selecting the target sink(same rules apply to the source selecting): If the sinks have the port with PA_AVAILABLE_YES, we will choose the one from them with a highest priority port. If all sinks don't have the port with PA_AVAILABLE_YES, we will choose the one with a highest priority port. Signed-off-by: Hui Wang --- src/modules/module-rescue-streams.c | 80 + 1 file changed, 54 insertions(+), 26 deletions(-) diff --git a/src/modules/module-rescue-streams.c b/src/modules/module-rescue-streams.c index 7035a35..8a4c8d6 100644 --- a/src/modules/module-rescue-streams.c +++ b/src/modules/module-rescue-streams.c @@ -53,33 +53,47 @@ struct userdata { }; static pa_sink* find_evacuation_sink(pa_core *c, pa_sink_input *i, pa_sink *skip) { -pa_sink *target, *def; +pa_sink *target, *best_target = NULL; +pa_device_port *port, *best_port = NULL; uint32_t idx; pa_assert(c); pa_assert(i); -def = pa_namereg_get_default_sink(c); - -if (def && def != skip && pa_sink_input_may_move_to(i, def)) -return def; - PA_IDXSET_FOREACH(target, c->sinks, idx) { -if (target == def) -continue; - if (target == skip) continue; if (!PA_SINK_IS_LINKED(pa_sink_get_state(target))) continue; -if (pa_sink_input_may_move_to(i, target)) -return target; +if (!pa_sink_input_may_move_to(i, target)) +continue; + +port = pa_device_port_find_best(target->ports); +if (!port) + continue; + + if (!best_target) { + best_target = target; +best_port = port; +continue; + } + + if (best_port->available != port->available && best_port->available == PA_AVAILABLE_YES) + continue; + + if (best_port->available == port->available && best_port->priority > port->priority) + continue; + +best_target = target; +best_port = port; } -pa_log_debug("No evacuation sink found."); -return NULL; +if(!best_target) +pa_log_debug("No evacuation sink found."); + +return best_target; } static pa_hook_result_t sink_unlink_hook_callback(pa_core *c, pa_sink *sink, void* userdata) { @@ -141,21 +155,14 @@ static pa_hook_result_t sink_input_move_fail_hook_callback(pa_core *c, pa_sink_i } static pa_source* find_evacuation_source(pa_core *c, pa_source_output *o, pa_source *skip) { -pa_source *target, *def; +pa_source *target, *best_target = NULL; +pa_device_port *port, *best_port = NULL; uint32_t idx; pa_assert(c); pa_assert(o); -def = pa_namereg_get_default_source(c); - -if (def && def != skip && pa_source_output_may_move_to(o, def)) -return def; - PA_IDXSET_FOREACH(target, c->sources, idx) { -if (target == def) -continue; - if (target == skip) continue; @@ -165,12 +172,33 @@ static pa_source* find_evacuation_source(pa_core *c, pa_source_output *o, pa_sou if (!PA_SOURCE_IS_LINKED(pa_source_get_state(target))) continue; -if (pa_source_output_may_move_to(o, target)) -return target; +if (!pa_source_output_may_move_to(o, target)) +continue; + +port = pa_device_port_find_best(target->ports); +if (!port) + continue; + + if (!best_target) { + best_target = target; +best_port = port; +continue; + } + + if (best_port->available != port->available && best_port->available == PA_AVAILABLE_YES) + continue; + + if (best_port->available == port->available && best_port->priority > port->priority) + continue; + +best_target = target; +best_port = port; } -pa_log_debug("No evacuation source found."); -return NULL; +if (!best_target) +pa_log_debug("No evacuation source found."); + +return best_target; } static pa_hook_result_t source_unlink_hook_callback(pa_core *c, pa_source *source, void* userdata) { -- 1.8.1.2 ___ pulseaudio-discuss mailing list pulseaudio-discuss@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
[pulseaudio-discuss] [V2 PATCH] rescue-streams: try to find best one using availability and priority
Recently met a problem: when I disconnect the bluetooth headset, the pulseaudio automatically switch the sound to sink of HDMI output instead of the sink of internal speaker even though there is no HDMI cable connected. To fix this problem, I want to change the rule of selecting the target sink(same rules apply to the source selecting): construct a new hashmap with all ports (of all relevant sinks) and then call find_best on the new hashmap to find the best port, finally find the corresponding sink using the best port. Signed-off-by: Hui Wang --- src/modules/module-rescue-streams.c | 95 +++-- 1 file changed, 71 insertions(+), 24 deletions(-) diff --git a/src/modules/module-rescue-streams.c b/src/modules/module-rescue-streams.c index 7035a35..eb40f90 100644 --- a/src/modules/module-rescue-streams.c +++ b/src/modules/module-rescue-streams.c @@ -52,34 +52,77 @@ struct userdata { *source_output_move_fail_slot; }; +static pa_source* find_source_from_port(pa_core *c, pa_device_port *port) { +pa_source *target; +uint32_t idx; + +if (!port) +return NULL; + +PA_IDXSET_FOREACH(target, c->sources, idx) + if (port == pa_hashmap_get(target->ports, port->name)) + return target; + +return NULL; +} + +static pa_sink* find_sink_from_port(pa_core *c, pa_device_port *port) { +pa_sink *target; +uint32_t idx; + +if (!port) +return NULL; + +PA_IDXSET_FOREACH(target, c->sinks, idx) + if (port == pa_hashmap_get(target->ports, port->name)) + return target; + +return NULL; +} + +static void build_group_ports(pa_hashmap *g_ports, pa_hashmap *s_ports) { +void *state; +pa_device_port *p; + +if (!g_ports || !s_ports) +return; + +PA_HASHMAP_FOREACH(p, s_ports, state) +pa_hashmap_put(g_ports, p->name, p); +} + static pa_sink* find_evacuation_sink(pa_core *c, pa_sink_input *i, pa_sink *skip) { -pa_sink *target, *def; +pa_sink *target; uint32_t idx; +pa_hashmap *all_ports; +pa_device_port *best_port; pa_assert(c); pa_assert(i); -def = pa_namereg_get_default_sink(c); - -if (def && def != skip && pa_sink_input_may_move_to(i, def)) -return def; +all_ports = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); PA_IDXSET_FOREACH(target, c->sinks, idx) { -if (target == def) -continue; - if (target == skip) continue; if (!PA_SINK_IS_LINKED(pa_sink_get_state(target))) continue; -if (pa_sink_input_may_move_to(i, target)) -return target; +if (!pa_sink_input_may_move_to(i, target)) +continue; + + build_group_ports(all_ports, target->ports); } -pa_log_debug("No evacuation sink found."); -return NULL; +best_port = pa_device_port_find_best(all_ports); +if(!best_port) + pa_log_debug("No evacuation sink found."); + +pa_hashmap_free(all_ports); + +target = find_sink_from_port(c, best_port); +return target; } static pa_hook_result_t sink_unlink_hook_callback(pa_core *c, pa_sink *sink, void* userdata) { @@ -141,21 +184,17 @@ static pa_hook_result_t sink_input_move_fail_hook_callback(pa_core *c, pa_sink_i } static pa_source* find_evacuation_source(pa_core *c, pa_source_output *o, pa_source *skip) { -pa_source *target, *def; +pa_source *target; uint32_t idx; +pa_hashmap *all_ports; +pa_device_port *best_port; pa_assert(c); pa_assert(o); -def = pa_namereg_get_default_source(c); - -if (def && def != skip && pa_source_output_may_move_to(o, def)) -return def; +all_ports = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); PA_IDXSET_FOREACH(target, c->sources, idx) { -if (target == def) -continue; - if (target == skip) continue; @@ -165,12 +204,20 @@ static pa_source* find_evacuation_source(pa_core *c, pa_source_output *o, pa_sou if (!PA_SOURCE_IS_LINKED(pa_source_get_state(target))) continue; -if (pa_source_output_may_move_to(o, target)) -return target; +if (!pa_source_output_may_move_to(o, target)) +continue; + + build_group_ports(all_ports, target->ports); } -pa_log_debug("No evacuation source found."); -return NULL; +best_port = pa_device_port_find_best(all_ports); +if(!best_port) +pa_log_debug("No evacuation source found."); + +pa_hashmap_free(all_ports); + +target = find_source_from_port(c, best_port); +return target; } static pa_hook_result_t source_unlink_hook_callback(pa_core *c, pa_source *source, void* userdata) { -- 1.8.1.2 ___ pulseaudio-di
[pulseaudio-discuss] [V3 PATCH] rescue-streams: try to find best one using availability and priority
Recently met a problem: when I disconnect the bluetooth headset, the pulseaudio automatically switch the sound to sink of HDMI output instead of the sink of internal speaker even though there is no HDMI cable connected. To fix this problem, I want to change the rule of selecting the target sink if the default sink is not available. (same rules apply to the source selecting): construct a new hashmap with all ports (of all relevant sinks) and then call find_best on the new hashmap to find the best port, finally find the corresponding sink using the best port. Signed-off-by: Hui Wang --- diff Vs V2: 1) The default sink is not the root cause for this problem, so i don't remove it in this version. 2) Use pa_idxset_trivial_* funcs to replace pa_idxset_string_* funcs and use port pointers as key rather than the name 3) fix the wrong indentation 4) add a fallback sink in case the sink has no ports. src/modules/module-rescue-streams.c | 99 + 1 file changed, 89 insertions(+), 10 deletions(-) diff --git a/src/modules/module-rescue-streams.c b/src/modules/module-rescue-streams.c index 7035a35..265711c 100644 --- a/src/modules/module-rescue-streams.c +++ b/src/modules/module-rescue-streams.c @@ -52,9 +52,56 @@ struct userdata { *source_output_move_fail_slot; }; +static pa_source* find_source_from_port(pa_core *c, pa_device_port *port) { +pa_source *target; +uint32_t idx; +void *state; +pa_device_port *p; + +if (!port) +return NULL; + +PA_IDXSET_FOREACH(target, c->sources, idx) +PA_HASHMAP_FOREACH(p, target->ports, state) +if (port == p) +return target; + +return NULL; +} + +static pa_sink* find_sink_from_port(pa_core *c, pa_device_port *port) { +pa_sink *target; +uint32_t idx; +void *state; +pa_device_port *p; + +if (!port) +return NULL; + +PA_IDXSET_FOREACH(target, c->sinks, idx) +PA_HASHMAP_FOREACH(p, target->ports, state) +if (port == p) +return target; + +return NULL; +} + +static void build_group_ports(pa_hashmap *g_ports, pa_hashmap *s_ports) { +void *state; +pa_device_port *p; + +if (!g_ports || !s_ports) +return; + +PA_HASHMAP_FOREACH(p, s_ports, state) +pa_hashmap_put(g_ports, p, p); +} + static pa_sink* find_evacuation_sink(pa_core *c, pa_sink_input *i, pa_sink *skip) { -pa_sink *target, *def; +pa_sink *target, *def, *fb_sink = NULL; uint32_t idx; +pa_hashmap *all_ports; +pa_device_port *best_port; pa_assert(c); pa_assert(i); @@ -64,6 +111,8 @@ static pa_sink* find_evacuation_sink(pa_core *c, pa_sink_input *i, pa_sink *skip if (def && def != skip && pa_sink_input_may_move_to(i, def)) return def; +all_ports = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); + PA_IDXSET_FOREACH(target, c->sinks, idx) { if (target == def) continue; @@ -74,12 +123,25 @@ static pa_sink* find_evacuation_sink(pa_core *c, pa_sink_input *i, pa_sink *skip if (!PA_SINK_IS_LINKED(pa_sink_get_state(target))) continue; -if (pa_sink_input_may_move_to(i, target)) -return target; +if (!pa_sink_input_may_move_to(i, target)) +continue; + +fb_sink = target; + +build_group_ports(all_ports, target->ports); } -pa_log_debug("No evacuation sink found."); -return NULL; +best_port = pa_device_port_find_best(all_ports); + +pa_hashmap_free(all_ports); + +if(!best_port) { + pa_log_debug("No evacuation sink found."); +target = fb_sink; +} else + target = find_sink_from_port(c, best_port); + +return target; } static pa_hook_result_t sink_unlink_hook_callback(pa_core *c, pa_sink *sink, void* userdata) { @@ -141,8 +203,10 @@ static pa_hook_result_t sink_input_move_fail_hook_callback(pa_core *c, pa_sink_i } static pa_source* find_evacuation_source(pa_core *c, pa_source_output *o, pa_source *skip) { -pa_source *target, *def; +pa_source *target, *def, *fb_source = NULL; uint32_t idx; +pa_hashmap *all_ports; +pa_device_port *best_port; pa_assert(c); pa_assert(o); @@ -152,6 +216,8 @@ static pa_source* find_evacuation_source(pa_core *c, pa_source_output *o, pa_sou if (def && def != skip && pa_source_output_may_move_to(o, def)) return def; +all_ports = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); + PA_IDXSET_FOREACH(target, c->sources, idx) { if (target == def) continue; @@ -165,12 +231,25 @@ static pa_source* find_evacuation_source(pa_core *c, pa_source_output *o, pa_sou if (!PA_SOURCE_IS_LINKED(pa_source_get_state(target))) continue; -if (pa
[pulseaudio-discuss] [PATCH] module-switch-on-connect: add an argument for conditionally connecting
On a machine without fixed connecting audio devices like internal microphone or internal speaker, and when there is no external audio devices plugging in, the default source/sink is alsa_input/alsa_output and there is no input devices/output devices listed in the gnome sound-setting. Under this situation, if we connect a bluetooth headset, the gnome sound-setting will list bluez input/output devices, but they are not active devices by default. This looks very weird that sound-setting lists only one input device and one output device, but they are not active. To change this situation, we add an argument, the policy is if a new source/sink is connected and current default source/sink's active_port is AVAILABLE_NO, we let the new added one switch to default one. BugLink: http://bugs.launchpad.net/bugs/1369476 Signed-off-by: Hui Wang --- src/modules/module-switch-on-connect.c | 21 - 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/modules/module-switch-on-connect.c b/src/modules/module-switch-on-connect.c index d9275d3..658f0141 100644 --- a/src/modules/module-switch-on-connect.c +++ b/src/modules/module-switch-on-connect.c @@ -38,11 +38,15 @@ #include "module-switch-on-connect-symdef.h" PA_MODULE_AUTHOR("Michael Terry"); -PA_MODULE_DESCRIPTION("When a sink/source is added, switch to it"); +PA_MODULE_DESCRIPTION("When a sink/source is added, switch to it or conditionally switch to it"); PA_MODULE_VERSION(PACKAGE_VERSION); PA_MODULE_LOAD_ONCE(true); +PA_MODULE_USAGE( +"switch_on_unavailable= " +); static const char* const valid_modargs[] = { +"switch_on_unavailable", NULL, }; @@ -50,6 +54,7 @@ struct userdata { pa_hook_slot *sink_put_slot, *source_put_slot; +bool switch_on_unavailable; }; static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, void* userdata) { @@ -57,9 +62,11 @@ static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, void* uint32_t idx; pa_sink *def; const char *s; +struct userdata *u = userdata; pa_assert(c); pa_assert(sink); +pa_assert(userdata); /* Don't want to run during startup or shutdown */ if (c->state != PA_CORE_RUNNING) @@ -77,6 +84,10 @@ static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, void* if (def == sink) return PA_HOOK_OK; +if (u->switch_on_unavailable) +if (def->active_port && def->active_port->available != PA_AVAILABLE_NO) +return PA_HOOK_OK; + /* Actually do the switch to the new sink */ pa_namereg_set_default_sink(c, sink); @@ -106,9 +117,11 @@ static pa_hook_result_t source_put_hook_callback(pa_core *c, pa_source *source, uint32_t idx; pa_source *def; const char *s; +struct userdata *u = userdata; pa_assert(c); pa_assert(source); +pa_assert(userdata); /* Don't want to run during startup or shutdown */ if (c->state != PA_CORE_RUNNING) @@ -130,6 +143,10 @@ static pa_hook_result_t source_put_hook_callback(pa_core *c, pa_source *source, if (def == source) return PA_HOOK_OK; +if (u->switch_on_unavailable) +if (def->active_port && def->active_port->available != PA_AVAILABLE_NO) +return PA_HOOK_OK; + /* Actually do the switch to the new source */ pa_namereg_set_default_source(c, source); @@ -171,6 +188,8 @@ int pa__init(pa_module*m) { u->sink_put_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_PUT], PA_HOOK_LATE+30, (pa_hook_cb_t) sink_put_hook_callback, u); u->source_put_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_PUT], PA_HOOK_LATE+20, (pa_hook_cb_t) source_put_hook_callback, u); +pa_modargs_get_value_boolean(ma, "switch_on_unavailable", &u->switch_on_unavailable); + pa_modargs_free(ma); return 0; } -- 1.9.1 ___ pulseaudio-discuss mailing list pulseaudio-discuss@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
[pulseaudio-discuss] [V2 PATCH] module-switch-on-connect: add an argument for conditionally connecting
On a machine without fixed connecting audio devices like internal microphone or internal speaker, and when there is no external audio devices plugging in, the default source/sink is alsa_input/alsa_output and there is no input devices/output devices listed in the gnome sound-setting. Under this situation, if we connect a bluetooth headset, the gnome sound-setting will list bluez input/output devices, but they are not active devices by default. This looks very weird that sound-setting lists only one input device and one output device, but they are not active. To change this situation, we add an argument, the policy is if a new source/sink is connected and current default source/sink's active_port is AVAILABLE_NO, we let the new added one switch to default one. BugLink: http://bugs.launchpad.net/bugs/1369476 Signed-off-by: Hui Wang --- Diff vs v1: 1. change the argument name to only_from_unavailable 2. fix the logic to if no active_port, it will not switch 3. add return value check for pa_modargs_get_value_boolean() src/modules/module-switch-on-connect.c | 22 +- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/modules/module-switch-on-connect.c b/src/modules/module-switch-on-connect.c index d9275d3..3f1b0a4 100644 --- a/src/modules/module-switch-on-connect.c +++ b/src/modules/module-switch-on-connect.c @@ -38,11 +38,15 @@ #include "module-switch-on-connect-symdef.h" PA_MODULE_AUTHOR("Michael Terry"); -PA_MODULE_DESCRIPTION("When a sink/source is added, switch to it"); +PA_MODULE_DESCRIPTION("When a sink/source is added, switch to it or conditionally switch to it"); PA_MODULE_VERSION(PACKAGE_VERSION); PA_MODULE_LOAD_ONCE(true); +PA_MODULE_USAGE( +"only_from_unavailable= " +); static const char* const valid_modargs[] = { +"only_from_unavailable", NULL, }; @@ -50,6 +54,7 @@ struct userdata { pa_hook_slot *sink_put_slot, *source_put_slot; +bool only_from_unavailable; }; static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, void* userdata) { @@ -57,9 +62,11 @@ static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, void* uint32_t idx; pa_sink *def; const char *s; +struct userdata *u = userdata; pa_assert(c); pa_assert(sink); +pa_assert(userdata); /* Don't want to run during startup or shutdown */ if (c->state != PA_CORE_RUNNING) @@ -77,6 +84,10 @@ static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, void* if (def == sink) return PA_HOOK_OK; +if (u->only_from_unavailable) +if (!def->active_port || def->active_port->available != PA_AVAILABLE_NO) +return PA_HOOK_OK; + /* Actually do the switch to the new sink */ pa_namereg_set_default_sink(c, sink); @@ -106,9 +117,11 @@ static pa_hook_result_t source_put_hook_callback(pa_core *c, pa_source *source, uint32_t idx; pa_source *def; const char *s; +struct userdata *u = userdata; pa_assert(c); pa_assert(source); +pa_assert(userdata); /* Don't want to run during startup or shutdown */ if (c->state != PA_CORE_RUNNING) @@ -130,6 +143,10 @@ static pa_hook_result_t source_put_hook_callback(pa_core *c, pa_source *source, if (def == source) return PA_HOOK_OK; +if (u->only_from_unavailable) +if (!def->active_port || def->active_port->available != PA_AVAILABLE_NO) +return PA_HOOK_OK; + /* Actually do the switch to the new source */ pa_namereg_set_default_source(c, source); @@ -171,6 +188,9 @@ int pa__init(pa_module*m) { u->sink_put_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_PUT], PA_HOOK_LATE+30, (pa_hook_cb_t) sink_put_hook_callback, u); u->source_put_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_PUT], PA_HOOK_LATE+20, (pa_hook_cb_t) source_put_hook_callback, u); +if (pa_modargs_get_value_boolean(ma, "only_from_unavailable", &u->only_from_unavailable) < 0) + pa_log_warn("Fail to get a boolean value for only_from_unavailable, then regard only_from_unvailable=false"); + pa_modargs_free(ma); return 0; } -- 1.9.1 ___ pulseaudio-discuss mailing list pulseaudio-discuss@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
[pulseaudio-discuss] [V3 PATCH] module-switch-on-connect: add an argument for conditionally connecting
On a machine without fixed connecting audio devices like internal microphone or internal speaker, and when there is no external audio devices plugging in, the default source/sink is alsa_input/alsa_output and there is no input devices/output devices listed in the gnome sound-setting. Under this situation, if we connect a bluetooth headset, the gnome sound-setting will list bluez input/output devices, but they are not active devices by default. This looks very weird that sound-setting lists only one input device and one output device, but they are not active. To change this situation, we add an argument, the policy is if a new source/sink is connected and current default source/sink's active_port is AVAILABLE_NO, we let the new added one switch to default one. BugLink: http://bugs.launchpad.net/bugs/1369476 Signed-off-by: Hui Wang --- In the V3: if the get_value_boolean fails, release the resource and return -1 src/modules/module-switch-on-connect.c | 32 +++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/src/modules/module-switch-on-connect.c b/src/modules/module-switch-on-connect.c index d9275d3..66f3f9b 100644 --- a/src/modules/module-switch-on-connect.c +++ b/src/modules/module-switch-on-connect.c @@ -38,11 +38,15 @@ #include "module-switch-on-connect-symdef.h" PA_MODULE_AUTHOR("Michael Terry"); -PA_MODULE_DESCRIPTION("When a sink/source is added, switch to it"); +PA_MODULE_DESCRIPTION("When a sink/source is added, switch to it or conditionally switch to it"); PA_MODULE_VERSION(PACKAGE_VERSION); PA_MODULE_LOAD_ONCE(true); +PA_MODULE_USAGE( +"only_from_unavailable= " +); static const char* const valid_modargs[] = { +"only_from_unavailable", NULL, }; @@ -50,6 +54,7 @@ struct userdata { pa_hook_slot *sink_put_slot, *source_put_slot; +bool only_from_unavailable; }; static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, void* userdata) { @@ -57,9 +62,11 @@ static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, void* uint32_t idx; pa_sink *def; const char *s; +struct userdata *u = userdata; pa_assert(c); pa_assert(sink); +pa_assert(userdata); /* Don't want to run during startup or shutdown */ if (c->state != PA_CORE_RUNNING) @@ -77,6 +84,10 @@ static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, void* if (def == sink) return PA_HOOK_OK; +if (u->only_from_unavailable) +if (!def->active_port || def->active_port->available != PA_AVAILABLE_NO) +return PA_HOOK_OK; + /* Actually do the switch to the new sink */ pa_namereg_set_default_sink(c, sink); @@ -106,9 +117,11 @@ static pa_hook_result_t source_put_hook_callback(pa_core *c, pa_source *source, uint32_t idx; pa_source *def; const char *s; +struct userdata *u = userdata; pa_assert(c); pa_assert(source); +pa_assert(userdata); /* Don't want to run during startup or shutdown */ if (c->state != PA_CORE_RUNNING) @@ -130,6 +143,10 @@ static pa_hook_result_t source_put_hook_callback(pa_core *c, pa_source *source, if (def == source) return PA_HOOK_OK; +if (u->only_from_unavailable) +if (!def->active_port || def->active_port->available != PA_AVAILABLE_NO) +return PA_HOOK_OK; + /* Actually do the switch to the new source */ pa_namereg_set_default_source(c, source); @@ -171,8 +188,21 @@ int pa__init(pa_module*m) { u->sink_put_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_PUT], PA_HOOK_LATE+30, (pa_hook_cb_t) sink_put_hook_callback, u); u->source_put_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_PUT], PA_HOOK_LATE+20, (pa_hook_cb_t) source_put_hook_callback, u); +if (pa_modargs_get_value_boolean(ma, "only_from_unavailable", &u->only_from_unavailable) < 0) { + pa_log ("Failed to get a boolean value for only_from_unavailable."); + goto fail; +} + pa_modargs_free(ma); return 0; + +fail: +if (ma) +pa_modargs_free(ma); + +pa__done(m); + +return -1; } void pa__done(pa_module*m) { -- 1.9.1 ___ pulseaudio-discuss mailing list pulseaudio-discuss@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
[pulseaudio-discuss] [V4 PATCH] module-switch-on-connect: add an argument for conditionally connecting
On a machine without fixed connecting audio devices like internal microphone or internal speaker, and when there is no external audio devices plugging in, the default source/sink is alsa_input/alsa_output and there is no input devices/output devices listed in the gnome sound-setting. Under this situation, if we connect a bluetooth headset, the gnome sound-setting will list bluez input/output devices, but they are not active devices by default. This looks very weird that sound-setting lists only one input device and one output device, but they are not active. To change this situation, we add an argument, the policy is if a new source/sink is connected and current default source/sink's active_port is AVAILABLE_NO, we let the new added one switch to default one. BugLink: http://bugs.launchpad.net/bugs/1369476 Signed-off-by: Hui Wang --- In the V3: if the get_value_boolean fails, release the resource and return -1 src/modules/module-switch-on-connect.c | 32 +++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/src/modules/module-switch-on-connect.c b/src/modules/module-switch-on-connect.c index d9275d3..90b86d1 100644 --- a/src/modules/module-switch-on-connect.c +++ b/src/modules/module-switch-on-connect.c @@ -38,11 +38,15 @@ #include "module-switch-on-connect-symdef.h" PA_MODULE_AUTHOR("Michael Terry"); -PA_MODULE_DESCRIPTION("When a sink/source is added, switch to it"); +PA_MODULE_DESCRIPTION("When a sink/source is added, switch to it or conditionally switch to it"); PA_MODULE_VERSION(PACKAGE_VERSION); PA_MODULE_LOAD_ONCE(true); +PA_MODULE_USAGE( +"only_from_unavailable= " +); static const char* const valid_modargs[] = { +"only_from_unavailable", NULL, }; @@ -50,6 +54,7 @@ struct userdata { pa_hook_slot *sink_put_slot, *source_put_slot; +bool only_from_unavailable; }; static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, void* userdata) { @@ -57,9 +62,11 @@ static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, void* uint32_t idx; pa_sink *def; const char *s; +struct userdata *u = userdata; pa_assert(c); pa_assert(sink); +pa_assert(userdata); /* Don't want to run during startup or shutdown */ if (c->state != PA_CORE_RUNNING) @@ -77,6 +84,10 @@ static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, void* if (def == sink) return PA_HOOK_OK; +if (u->only_from_unavailable) +if (!def->active_port || def->active_port->available != PA_AVAILABLE_NO) +return PA_HOOK_OK; + /* Actually do the switch to the new sink */ pa_namereg_set_default_sink(c, sink); @@ -106,9 +117,11 @@ static pa_hook_result_t source_put_hook_callback(pa_core *c, pa_source *source, uint32_t idx; pa_source *def; const char *s; +struct userdata *u = userdata; pa_assert(c); pa_assert(source); +pa_assert(userdata); /* Don't want to run during startup or shutdown */ if (c->state != PA_CORE_RUNNING) @@ -130,6 +143,10 @@ static pa_hook_result_t source_put_hook_callback(pa_core *c, pa_source *source, if (def == source) return PA_HOOK_OK; +if (u->only_from_unavailable) +if (!def->active_port || def->active_port->available != PA_AVAILABLE_NO) +return PA_HOOK_OK; + /* Actually do the switch to the new source */ pa_namereg_set_default_source(c, source); @@ -171,8 +188,21 @@ int pa__init(pa_module*m) { u->sink_put_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_PUT], PA_HOOK_LATE+30, (pa_hook_cb_t) sink_put_hook_callback, u); u->source_put_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_PUT], PA_HOOK_LATE+20, (pa_hook_cb_t) source_put_hook_callback, u); +if (pa_modargs_get_value_boolean(ma, "only_from_unavailable", &u->only_from_unavailable) < 0) { + pa_log("Failed to get a boolean value for only_from_unavailable."); + goto fail; +} + pa_modargs_free(ma); return 0; + +fail: +if (ma) +pa_modargs_free(ma); + +pa__done(m); + +return -1; } void pa__done(pa_module*m) { -- 1.9.1 ___ pulseaudio-discuss mailing list pulseaudio-discuss@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
Re: [pulseaudio-discuss] [V4 PATCH] module-switch-on-connect: add an argument for conditionally connecting
On 09/26/2014 12:13 AM, Raymond Yau wrote: >> >> > >> > On a machine without fixed connecting audio devices like internal >> > microphone or internal speaker, and when there is no external audio >> > devices plugging in, the default source/sink is alsa_input/alsa_output >> > and there is no input devices/output devices listed in the gnome >> > sound-setting. https://launchpadlibrarian.net/184055917/PulseList.txt Seem line in is active port when all ports are not available Pulseaudio won't switch away from line in but gnome won't show line in since it is not plugged ports: analog-input-microphone-front: Front Microphone (priority 8500, latency offset 0 usec, available: no) properties: device.icon_name = "audio-input-microphone" analog-input-microphone-rear: Rear Microphone (priority 8200, latency offset 0 usec, available: no) properties: device.icon_name = "audio-input-microphone" analog-input-linein: Line In (priority 8100, latency offset 0 usec, available: no) properties: active port: Yes, in this situation, the default-source->active_port->available=no, if you use this module and pass "only_from_unavailable=yes", when connect bluetooth headset, the default source will automatically switch to bluez-source. In this situation, if you plug something in the line-in jack, the default-source->active_port-available=yes, and if you pass "only_from_unavailable=yes", the default source will not switch. https://launchpadlibrarian.net/184417469/alsa2.txt ___ pulseaudio-discuss mailing list pulseaudio-discuss@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss ___ pulseaudio-discuss mailing list pulseaudio-discuss@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
[pulseaudio-discuss] [PATCH] module-switch-on-port-available: make the output more accurate
It is possible that the chosen active_port doesn't equal new_data->active_port, using p->name is more accurate. Please refer to sink_new_hook_callback() Signed-off-by: Hui Wang --- src/modules/module-switch-on-port-available.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/modules/module-switch-on-port-available.c b/src/modules/module-switch-on-port-available.c index b0938d5..7397bcc 100644 --- a/src/modules/module-switch-on-port-available.c +++ b/src/modules/module-switch-on-port-available.c @@ -264,8 +264,7 @@ static pa_hook_result_t source_new_hook_callback(pa_core *c, pa_source_new_data pa_device_port *p = new_sink_source(new_data->ports, new_data->active_port); if (p) { -pa_log_debug("Switching initial port for source '%s' to '%s'", new_data->name, - new_data->active_port); +pa_log_debug("Switching initial port for source '%s' to '%s'", new_data->name, p->name); pa_source_new_data_set_port(new_data, p->name); } return PA_HOOK_OK; -- 1.9.1 ___ pulseaudio-discuss mailing list pulseaudio-discuss@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
Re: [pulseaudio-discuss] [V4 PATCH] module-switch-on-connect: add an argument for conditionally connecting
On 09/28/2014 05:50 PM, Tanu Kaskinen wrote: On Sun, 2014-09-28 at 12:41 +0300, Tanu Kaskinen wrote: On Mon, 2014-09-22 at 11:50 +0800, Hui Wang wrote: On a machine without fixed connecting audio devices like internal microphone or internal speaker, and when there is no external audio devices plugging in, the default source/sink is alsa_input/alsa_output and there is no input devices/output devices listed in the gnome sound-setting. How can the default source/sink be alsa_input/alsa_output if there are no alsa devices? Answering myself: probably you meant that there are alsa devices, but they are currently all unavailable. Yes, and below is an example: * index: 2 name: driver: flags: HARDWARE HW_MUTE_CTRL HW_VOLUME_CTRL DECIBEL_VOLUME LATENCY DYNAMIC_LATENCY state: SUSPENDED suspend cause: IDLE priority: 9959 volume: 0: 21% 1: 21% 0: -40.50 dB 1: -40.50 dB balance 0.00 base volume: 13% -52.50 dB volume steps: 65537 muted: no current latency: 0.00 ms max rewind: 0 KiB sample spec: s16le 2ch 44100Hz channel map: front-left,front-right Stereo used by: 0 linked by: 0 configured latency: 0.00 ms; range is 0.50 .. 371.52 ms card: 1 module: 6 properties: alsa.resolution_bits = "16" device.api = "alsa" device.class = "sound" alsa.class = "generic" alsa.subclass = "generic-mix" alsa.name = "92HD89E2 Analog" alsa.id = "92HD89E2 Analog" alsa.subdevice = "0" alsa.subdevice_name = "subdevice #0" alsa.device = "0" alsa.card = "1" alsa.card_name = "HD-Audio Generic" alsa.long_card_name = "HD-Audio Generic at 0xfeb4 irq 16" alsa.driver_name = "snd_hda_intel" device.bus_path = "pci-:00:14.2" sysfs.path = "/devices/pci:00/:00:14.2/sound/card1" device.bus = "pci" device.vendor.id = "1022" device.vendor.name = "Advanced Micro Devices, Inc. [AMD]" device.product.id = "780d" device.product.name = "FCH Azalia Controller" device.form_factor = "internal" device.string = "front:1" device.buffering.buffer_size = "65536" device.buffering.fragment_size = "32768" device.access_mode = "mmap+timer" device.profile.name = "analog-stereo" device.profile.description = "Analog Stereo" device.description = "Built-in Audio Analog Stereo" alsa.mixer_name = "IDT 92HD89E2" alsa.components = "HDA:111d76c7,103c2b17,00100102" module-udev-detect.discovered = "1" device.icon_name = "audio-card-pci" ports: analog-input-microphone-front: Front Microphone (priority 8500, latency offset 0 usec, available: no) properties: device.icon_name = "audio-input-microphone" analog-input-microphone-rear: Rear Microphone (priority 8200, latency offset 0 usec, available: no) properties: device.icon_name = "audio-input-microphone" analog-input-linein: Line In (priority 8100, latency offset 0 usec, available: no) properties: active port: Under this situation, if we connect a bluetooth headset, the gnome sound-setting will list bluez input/output devices, but they are not active devices by default. This looks very weird that sound-setting lists only one input device and one output device, but they are not active. To change this situation, we add an argument, the policy is if a new source/sink is connected and current default source/sink's active_port is AVAILABLE_NO, we let the new added one switch to default one. Surely it doesn't make any sense to have the default sink/source point to non-existing devices if there are other devices available. To me this seems like something to fix in the core than working around in modules. I happen to have some code that improves the core default device tracking. I can submit a patch next week. It might fix your issue too. My code doesn't take the port availability into account (perhaps it should, I'm not sure), so probably it won't fix your problem. ___ pulseaudio-discuss mailing list pulseaudio-discuss@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
Re: [pulseaudio-discuss] ThinkPad T-510 audio output mute LED non-workingness
On 03/31/2015 05:54 AM, Glenn Golden wrote: HW: ThinkPad T-510, x86_64 SW: Arch Linux (synched within a week) kernel = 3.19.2, PA 6.0 On the above setup, the mic mute function (invoked via pavucontrol) works as expected: Click the mute icon, it mutes the mic input, indicates the muted state by greying out the pavucontrol mic gain control, and illuminates the little LED on the mic mute button. But the analogous functionality for muting audio output only does the first two things, and has no effect on the mute LED. (The LED is always off.) From googling around, I'm pretty sure that these two particular LEDs are not directly under user control (e.g. via ACPI) but are somehow bound to the mute/unmute functionality in the snd-hda-intel driver. This understanding is based on kernel posts like this: https://bugzilla.kernel.org/show_bug.cgi?id=49391 and other similar ones. Before filing a ticket with the kernel guys, wanted to ask if this function-LED binding is in any way under control of pulseaudio itself? In other words, I guess what I'm asking is whether pulseaudio just tells the driver to "mute the audio", and the driver sets the LED state accordingly, or whether pulse tells the driver separately to "mute the audio" and also "turn on the LED". According to my understanding, it should be the former one, PA tells the driver to "mute the audio", and the driver sets the LED accordingly. Knowing the answer to this, I can post a more informative ticket to the kernel guys. (Or maybe the fix is even in pulseaudio itself?) ___ pulseaudio-discuss mailing list pulseaudio-discuss@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss ___ pulseaudio-discuss mailing list pulseaudio-discuss@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
[pulseaudio-discuss] [PATCH] tests: add tolerant variation for comparing the rewind result
On 32bits OS, this test case fails. The reason is when rewinding to the middle of a block, some of float parameters in the saved_state are stored in the memory from FPU registers, and those parameters will be used for next time to process data with lfe. Here if FPU register is over 32bits, the storing from FPU register to memory will introduce some variation, and this small variation will introduce small variation to the rewinding result. So adding the tolerant variation for comparing the rewind result, make this test case can work on both 64bits OS and 32bits OS. Signed-off-by: Hui Wang --- I wrote a simple testcase to show the variation exists on 32bits OS. When compile this test case on 64bits OS, it will not fail when running it; while on 32bits OS if you just compile it without "-O2", this testcase still pass without any variation, but if you add "-O2" when compiling it, you will see variation when you running it. http://pastebin.ubuntu.com/11342537/ src/tests/lfe-filter-test.c | 24 ++-- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/tests/lfe-filter-test.c b/src/tests/lfe-filter-test.c index 2c6d597..50636a9 100644 --- a/src/tests/lfe-filter-test.c +++ b/src/tests/lfe-filter-test.c @@ -37,6 +37,7 @@ static uint8_t *ori_sample_ptr; #define ONE_BLOCK_SAMPLES 4096 #define TOTAL_SAMPLES 8192 +#define TOLERANT_VARIATION 1 static void save_data_block(struct lfe_filter_test *lft, void *d, pa_memblock *blk) { uint8_t *dst = d, *src; @@ -63,15 +64,26 @@ static pa_memblock* generate_data_block(struct lfe_filter_test *lft, int start) static int compare_data_block(struct lfe_filter_test *lft, void *a, void *b) { int ret = 0; uint32_t i; -uint32_t fz = pa_frame_size(lft->ss); -uint8_t *r = a, *u = b; -for (i = 0; i < ONE_BLOCK_SAMPLES * fz; i++) { -if (*r++ != *u++) { -pa_log_error("lfe-filter-test: test failed, the output data in the position 0x%x of a block does not equal!\n", i); -ret = -1; +switch (lft->ss->format) { +case PA_SAMPLE_S16NE: +case PA_SAMPLE_S16RE: { +uint16_t *r = a, *u = b; +for (i = 0; i < ONE_BLOCK_SAMPLES; i++) { +uint16_t va = *r++, vb = *u++; +uint16_t var = (va >= vb) ? (va - vb) : (vb - va); +if (var > TOLERANT_VARIATION) { +pa_log_error("lfe-filter-test: test failed, the output data in the position 0x%x of a block does not equal!\n", i); +ret = -1; +break; +} +} break; } +default: +pa_log_error("lfe-filter-test: not a suppported sample format yet in this testcase!\n"); +ret = -1; +break; } return ret; } -- 1.9.1 ___ pulseaudio-discuss mailing list pulseaudio-discuss@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
[pulseaudio-discuss] [PATCH] tests: Remove a redundant mempool_new from resampler-test
Signed-off-by: Hui Wang --- src/tests/resampler-test.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/tests/resampler-test.c b/src/tests/resampler-test.c index 751d2dc..9832a31 100644 --- a/src/tests/resampler-test.c +++ b/src/tests/resampler-test.c @@ -330,8 +330,6 @@ int main(int argc, char *argv[]) { if (!getenv("MAKE_CHECK")) pa_log_set_level(PA_LOG_INFO); -pa_assert_se(pool = pa_mempool_new(false, 0)); - a.channels = b.channels = 1; a.rate = b.rate = 44100; a.format = b.format = PA_SAMPLE_S16LE; -- 1.9.1 ___ pulseaudio-discuss mailing list pulseaudio-discuss@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
[pulseaudio-discuss] [V2 PATCH] tests: add tolerant variation for comparing the rewind result
On 32bits OS, this test case fails. The reason is when rewinding to the middle of a block, some of float parameters in the saved_state are stored in the memory from FPU registers, and those parameters will be used for next time to process data with lfe. Here if FPU register is over 32bits, the storing from FPU register to memory will introduce some variation, and this small variation will introduce small variation to the rewinding result. So adding the tolerant variation for comparing the rewind result, make this test case can work on both 64bits OS and 32bits OS. Signed-off-by: Hui Wang --- src/tests/lfe-filter-test.c | 10 ++ 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/tests/lfe-filter-test.c b/src/tests/lfe-filter-test.c index 2c6d597..81682cb 100644 --- a/src/tests/lfe-filter-test.c +++ b/src/tests/lfe-filter-test.c @@ -37,6 +37,7 @@ static uint8_t *ori_sample_ptr; #define ONE_BLOCK_SAMPLES 4096 #define TOTAL_SAMPLES 8192 +#define TOLERANT_VARIATION 1 static void save_data_block(struct lfe_filter_test *lft, void *d, pa_memblock *blk) { uint8_t *dst = d, *src; @@ -63,11 +64,12 @@ static pa_memblock* generate_data_block(struct lfe_filter_test *lft, int start) static int compare_data_block(struct lfe_filter_test *lft, void *a, void *b) { int ret = 0; uint32_t i; -uint32_t fz = pa_frame_size(lft->ss); -uint8_t *r = a, *u = b; +uint16_t *r = a, *u = b; + +pa_assert_se(lft->ss->format == PA_SAMPLE_S16NE); -for (i = 0; i < ONE_BLOCK_SAMPLES * fz; i++) { -if (*r++ != *u++) { +for (i = 0; i < ONE_BLOCK_SAMPLES; i++) { +if (abs(*r++ - *u++) > TOLERANT_VARIATION) { pa_log_error("lfe-filter-test: test failed, the output data in the position 0x%x of a block does not equal!\n", i); ret = -1; break; -- 1.9.1 ___ pulseaudio-discuss mailing list pulseaudio-discuss@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
[pulseaudio-discuss] [PATCH] build-sys: add the Dell dock TB16 configuration
Signed-off-by: Hui Wang --- Forgot to add this to build sys with the commit 60c0edd5. src/Makefile.am | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Makefile.am b/src/Makefile.am index e610db7..0348250 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1312,7 +1312,8 @@ dist_alsaprofilesets_DATA = \ modules/alsa/mixer/profile-sets/native-instruments-korecontroller.conf \ modules/alsa/mixer/profile-sets/kinect-audio.conf \ modules/alsa/mixer/profile-sets/sb-omni-surround-5.1.conf \ - modules/alsa/mixer/profile-sets/steelseries-arctis-usb-audio.conf + modules/alsa/mixer/profile-sets/steelseries-arctis-usb-audio.conf \ + modules/alsa/mixer/profile-sets/dell-dock-tb16-usb-audio.conf if HAVE_UDEV dist_udevrules_DATA = \ -- 2.7.4 ___ pulseaudio-discuss mailing list pulseaudio-discuss@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
[pulseaudio-discuss] Audio APP (sink-input) bind to the sink with only unplugged hdmi-audio ports on it
This issue is also reported to: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/issues/579 Recently we found a weird issue on many laptops with the ubuntu 18.04, it uses the pulseaudio-11.1 (I guess the PA of the latest version also has this problem). The issue is like this: 1. boot the system up without plugging a hdmi monitor 2. run an audio app to play sound (e.g. $speaker-test) 3. the sound outputs from analog-speaker 4. plug a monitor with audio capability (through DP or HDMI port) 5. the sound still outputs from analog-speaker 6. open sound-setting (gnome-control-center --> choose sound), you will see two output devies: speaker and HDMI audio 7. choose HDMI audio, the sound will switch to HDIM audio from speaker (pa will remember speaker-test prefer to use hdmi-audio sink) 8. unplug the monitor, the default-sink is switching to analog-speaker, but the sound of speaker-test still route to hdmi-audio sink 9. run other sound apps, they all route sound to default sink (analog-speaker), but speaker-test always routes to hdmi-audio sink, as a result, speaker-test can't output sound anymore unless we replug a monitor with audio capability then the speaker-test output from hdmi-audio again. 10. if we want the speaker-test to route to analog-speaker, two ways: run pacmd move-sink-input or plug a monitor, after two audio devices (hdmi audio and speaker) show up in the sound-setting, select analog-speaker manually. This issue only happens on the laptops with 2 audio cards, analog devices on one card, hdmi audio on the other card. This kind of laptops are very common, like I+A (Intel graphic + Amd Graphic), I+N(Intel + Nvidia), and A AMD. This issue will not happen on the laptops with only Intel graphic card, since both analog and hdmi audio belong to one sound card. When hdmi monitor is unplugged, the hdmi sink will be removed from PA, then all sink-inputs will route to the only left sink: analog-sink. This issue will not happen on BT or USB audio. Unlike hdmi audio, BT and USB audio cards will be removed totally from PA when they are unpluged/unconnected, so they don't have this issue as well. The root cause of this issue is although the hdmi monitor is unplugged, the hdmi-sink still exists, and sink-input is selected by user to bind to this sink, so the pa doesn't care about if this sink has valid port or not, it bind the sink-input to this sink unconditionally. Maybe we could improve it like this: if the user selected sink only has available_no ports, the pa will switch all sink-inputs of this sink to other sinks (like default_sink) temporarily, once the selected sink has availble ports, all sink-inputs switch back to this sink. Any good ideas? Thanks, Hui. ___ pulseaudio-discuss mailing list pulseaudio-discuss@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
Re: [pulseaudio-discuss] Audio APP (sink-input) bind to the sink with only unplugged hdmi-audio ports on it
port_available_hook_callback(pa_core *c, pa_device_port break; case PA_AVAILABLE_NO: switch_from_port(port); + check_and_move_sink_inputs_to_default_sink(c, port); break; default: break; On 2018年09月30日 15:03, Hui Wang wrote: This issue is also reported to: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/issues/579 Recently we found a weird issue on many laptops with the ubuntu 18.04, it uses the pulseaudio-11.1 (I guess the PA of the latest version also has this problem). The issue is like this: 1. boot the system up without plugging a hdmi monitor 2. run an audio app to play sound (e.g. $speaker-test) 3. the sound outputs from analog-speaker 4. plug a monitor with audio capability (through DP or HDMI port) 5. the sound still outputs from analog-speaker 6. open sound-setting (gnome-control-center --> choose sound), you will see two output devies: speaker and HDMI audio 7. choose HDMI audio, the sound will switch to HDIM audio from speaker (pa will remember speaker-test prefer to use hdmi-audio sink) 8. unplug the monitor, the default-sink is switching to analog-speaker, but the sound of speaker-test still route to hdmi-audio sink 9. run other sound apps, they all route sound to default sink (analog-speaker), but speaker-test always routes to hdmi-audio sink, as a result, speaker-test can't output sound anymore unless we replug a monitor with audio capability then the speaker-test output from hdmi-audio again. 10. if we want the speaker-test to route to analog-speaker, two ways: run pacmd move-sink-input or plug a monitor, after two audio devices (hdmi audio and speaker) show up in the sound-setting, select analog-speaker manually. This issue only happens on the laptops with 2 audio cards, analog devices on one card, hdmi audio on the other card. This kind of laptops are very common, like I+A (Intel graphic + Amd Graphic), I+N(Intel + Nvidia), and A AMD. This issue will not happen on the laptops with only Intel graphic card, since both analog and hdmi audio belong to one sound card. When hdmi monitor is unplugged, the hdmi sink will be removed from PA, then all sink-inputs will route to the only left sink: analog-sink. This issue will not happen on BT or USB audio. Unlike hdmi audio, BT and USB audio cards will be removed totally from PA when they are unpluged/unconnected, so they don't have this issue as well. The root cause of this issue is although the hdmi monitor is unplugged, the hdmi-sink still exists, and sink-input is selected by user to bind to this sink, so the pa doesn't care about if this sink has valid port or not, it bind the sink-input to this sink unconditionally. Maybe we could improve it like this: if the user selected sink only has available_no ports, the pa will switch all sink-inputs of this sink to other sinks (like default_sink) temporarily, once the selected sink has availble ports, all sink-inputs switch back to this sink. Any good ideas? Thanks, Hui. ___ pulseaudio-discuss mailing list pulseaudio-discuss@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss ___ pulseaudio-discuss mailing list pulseaudio-discuss@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
Re: [pulseaudio-discuss] Audio APP (sink-input) bind to the sink with only unplugged hdmi-audio ports on it
On 2018年09月30日 18:30, Tanu Kaskinen wrote: On Sun, 2018-09-30 at 15:03 +0800, Hui Wang wrote: This issue is also reported to: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/issues/579 Recently we found a weird issue on many laptops with the ubuntu 18.04, it uses the pulseaudio-11.1 (I guess the PA of the latest version also has this problem). The issue is like this: 1. boot the system up without plugging a hdmi monitor 2. run an audio app to play sound (e.g. $speaker-test) 3. the sound outputs from analog-speaker 4. plug a monitor with audio capability (through DP or HDMI port) 5. the sound still outputs from analog-speaker 6. open sound-setting (gnome-control-center --> choose sound), you will see two output devies: speaker and HDMI audio 7. choose HDMI audio, the sound will switch to HDIM audio from speaker (pa will remember speaker-test prefer to use hdmi-audio sink) 8. unplug the monitor, the default-sink is switching to analog-speaker, but the sound of speaker-test still route to hdmi-audio sink 9. run other sound apps, they all route sound to default sink (analog-speaker), but speaker-test always routes to hdmi-audio sink, as a result, speaker-test can't output sound anymore unless we replug a monitor with audio capability then the speaker-test output from hdmi-audio again. 10. if we want the speaker-test to route to analog-speaker, two ways: run pacmd move-sink-input or plug a monitor, after two audio devices (hdmi audio and speaker) show up in the sound-setting, select analog-speaker manually. This issue only happens on the laptops with 2 audio cards, analog devices on one card, hdmi audio on the other card. This kind of laptops are very common, like I+A (Intel graphic + Amd Graphic), I+N(Intel + Nvidia), and A AMD. This issue will not happen on the laptops with only Intel graphic card, since both analog and hdmi audio belong to one sound card. When hdmi monitor is unplugged, the hdmi sink will be removed from PA, then all sink-inputs will route to the only left sink: analog-sink. This issue will not happen on BT or USB audio. Unlike hdmi audio, BT and USB audio cards will be removed totally from PA when they are unpluged/unconnected, so they don't have this issue as well. The root cause of this issue is although the hdmi monitor is unplugged, the hdmi-sink still exists, and sink-input is selected by user to bind to this sink, so the pa doesn't care about if this sink has valid port or not, it bind the sink-input to this sink unconditionally. Maybe we could improve it like this: if the user selected sink only has available_no ports, the pa will switch all sink-inputs of this sink to other sinks (like default_sink) temporarily, once the selected sink has availble ports, all sink-inputs switch back to this sink. Any good ideas? The plan has been to do the following (but I haven't found the time to implement it): Streams currently have a "save_sink" flag that tells whether the current sink should be remembered and restored by module-stream- restore. That flag should be replaced with a "preferred_sink" string that is set when the user moves the stream. module-stream-restore should remember and restore that string. When the user moves a stream to the current default sink, the "preferred_sink" string should be set to NULL and module-stream-restore should clear the routing for that stream in the stream database. From that point on the stream will be always routed to the default sink. When a stream is created, module-stream-restore should set the "preferred_sink" string and if that sink exists, the core should set that sink as the initial routing for the new stream. When the default sink changes, the streams from the old default sink should be moved to the new default sink, unless the "preferred_sink" string is set to the old default sink and the active port of the old default sink is not unavailable. This should be done by the core. When the active port of a sink becomes unavailable, all streams from that sink should be moved to the default sink. This should be done by the core. When a new sink appears or the active port of an existing sink changes state from unavailable, all streams that have their "preferred_sink" set to the new sink should be moved to the new sink. This should be done by the core. As a result, module-stream-restore doesn't need to move streams any more, it only needs to manage the "preferred_sink" variables. Some other modules can perhaps be simplified as well. The same logic should of course be implemented for capture streams as well. Would you be willing to implement this? Got it, I will take some time to understand your plan first, then have a try to implement it. Thanks, Hui. ___ pulseaudio-discuss mailing list pulseaudio-discuss@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
Re: [pulseaudio-discuss] Audio APP (sink-input) bind to the sink with only unplugged hdmi-audio ports on it
On 2018年10月02日 18:50, Georg Chini wrote: On 02.10.2018 11:49, Tanu Kaskinen wrote: On Mon, 2018-10-01 at 10:18 +0800, Hui Wang wrote: On 2018年09月30日 18:30, Tanu Kaskinen wrote: On Sun, 2018-09-30 at 15:03 +0800, Hui Wang wrote: This issue is also reported to: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/issues/579 Recently we found a weird issue on many laptops with the ubuntu 18.04, it uses the pulseaudio-11.1 (I guess the PA of the latest version also has this problem). The issue is like this: 1. boot the system up without plugging a hdmi monitor 2. run an audio app to play sound (e.g. $speaker-test) 3. the sound outputs from analog-speaker 4. plug a monitor with audio capability (through DP or HDMI port) 5. the sound still outputs from analog-speaker 6. open sound-setting (gnome-control-center --> choose sound), you will see two output devies: speaker and HDMI audio 7. choose HDMI audio, the sound will switch to HDIM audio from speaker (pa will remember speaker-test prefer to use hdmi-audio sink) 8. unplug the monitor, the default-sink is switching to analog-speaker, but the sound of speaker-test still route to hdmi-audio sink 9. run other sound apps, they all route sound to default sink (analog-speaker), but speaker-test always routes to hdmi-audio sink, as a result, speaker-test can't output sound anymore unless we replug a monitor with audio capability then the speaker-test output from hdmi-audio again. 10. if we want the speaker-test to route to analog-speaker, two ways: run pacmd move-sink-input or plug a monitor, after two audio devices (hdmi audio and speaker) show up in the sound-setting, select analog-speaker manually. This issue only happens on the laptops with 2 audio cards, analog devices on one card, hdmi audio on the other card. This kind of laptops are very common, like I+A (Intel graphic + Amd Graphic), I+N(Intel + Nvidia), and A AMD. This issue will not happen on the laptops with only Intel graphic card, since both analog and hdmi audio belong to one sound card. When hdmi monitor is unplugged, the hdmi sink will be removed from PA, then all sink-inputs will route to the only left sink: analog-sink. This issue will not happen on BT or USB audio. Unlike hdmi audio, BT and USB audio cards will be removed totally from PA when they are unpluged/unconnected, so they don't have this issue as well. The root cause of this issue is although the hdmi monitor is unplugged, the hdmi-sink still exists, and sink-input is selected by user to bind to this sink, so the pa doesn't care about if this sink has valid port or not, it bind the sink-input to this sink unconditionally. Maybe we could improve it like this: if the user selected sink only has available_no ports, the pa will switch all sink-inputs of this sink to other sinks (like default_sink) temporarily, once the selected sink has availble ports, all sink-inputs switch back to this sink. Any good ideas? The plan has been to do the following (but I haven't found the time to implement it): Streams currently have a "save_sink" flag that tells whether the current sink should be remembered and restored by module-stream- restore. That flag should be replaced with a "preferred_sink" string that is set when the user moves the stream. module-stream-restore should remember and restore that string. When the user moves a stream to the current default sink, the "preferred_sink" string should be set to NULL and module-stream-restore should clear the routing for that stream in the stream database. From that point on the stream will be always routed to the default sink. When a stream is created, module-stream-restore should set the "preferred_sink" string and if that sink exists, the core should set that sink as the initial routing for the new stream. When the default sink changes, the streams from the old default sink should be moved to the new default sink, unless the "preferred_sink" string is set to the old default sink and the active port of the old default sink is not unavailable. This should be done by the core. When the active port of a sink becomes unavailable, all streams from that sink should be moved to the default sink. This should be done by the core. When a new sink appears or the active port of an existing sink changes state from unavailable, all streams that have their "preferred_sink" set to the new sink should be moved to the new sink. This should be done by the core. As a result, module-stream-restore doesn't need to move streams any more, it only needs to manage the "preferred_sink" variables. Some other modules can perhaps be simplified as well. The same logic should of course be implemented for capture streams as well. Would you be willing to implement this? Got it, I will take some time to un
[pulseaudio-discuss] [PATCH 0/4] The tentative fix of the issue #185
This is a tentative fix of https://gitlab.freedesktop.org/pulseaudio/pulseaudio/issues/185 The patch is implemented based on Tanu's design: https://lists.freedesktop.org/archives/pulseaudio-discuss/2018-October/030531.html So far, the patches only cover the sink and sink_input, don't touch the source and source_output yet. Based on these patches, I tested the switch between HDMI output and speaker, it worked as expected. If the way of changing sink/sink_input is basically correct and is worth to apply to the source/source_output, I will continue to write patches for them too. Hui Wang (4): change bool save_sink to char *preferred_sink move stream after default sink is changed. move streams to new appeared sinks if they prefer these sinks move stream when the active_port changes src/modules/dbus/iface-core.c | 2 +- src/modules/module-default-device-restore.c | 2 +- src/modules/module-device-manager.c | 2 +- src/modules/module-intended-roles.c | 2 +- src/modules/module-stream-restore.c | 47 src/modules/module-switch-on-connect.c | 28 +-- src/pulsecore/cli-command.c | 2 +- src/pulsecore/core.c| 9 ++- src/pulsecore/core.h| 4 +- src/pulsecore/device-port.c | 18 - src/pulsecore/protocol-native.c | 2 +- src/pulsecore/sink-input.c | 25 +-- src/pulsecore/sink-input.h | 7 +- src/pulsecore/sink.c| 83 - src/pulsecore/sink.h| 3 + 15 files changed, 172 insertions(+), 64 deletions(-) -- 2.17.1 ___ pulseaudio-discuss mailing list pulseaudio-discuss@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
[pulseaudio-discuss] [PATCH 3/4] move streams to new appeared sinks if they prefer these sinks
When a new sink appears, all streams that have their "preferred_sink" set to the new sink should be moved to the new sink. Signed-off-by: Hui Wang --- src/pulsecore/sink.c | 31 +++ src/pulsecore/sink.h | 1 + 2 files changed, 32 insertions(+) diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index 63a3456e7..a2a390beb 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -722,6 +722,8 @@ void pa_sink_put(pa_sink* s) { /* This function must be called after the PA_CORE_HOOK_SINK_PUT hook, * because module-switch-on-connect needs to know the old default sink */ pa_core_update_default_sink(s->core, false); + +pa_sink_bind_preferred_stream_to_a_sink(s); } /* Called from main context */ @@ -3919,3 +3921,32 @@ void pa_sink_move_streams_from_oldsink_to_newsink(pa_sink *old_sink, pa_sink *ne return; } + +void pa_sink_bind_preferred_stream_to_a_sink(pa_sink *s) { +pa_sink_input *si; +uint32_t idx; +pa_core *c; + +if (!s) + return; + +c = s->core; +PA_IDXSET_FOREACH(si, c->sink_inputs, idx) { +if (si->sink == s) +continue; + +/* Skip this sink input if it is connecting a filter sink to + * the master */ +if (si->origin_sink) +continue; + +/* It might happen that a stream and a sink are set up at the + same time, in which case we want to make sure we don't + interfere with that */ + if (!PA_SINK_INPUT_IS_LINKED(si->state)) +continue; + +if (si->preferred_sink != NULL && pa_streq(si->preferred_sink, s->name)) + pa_sink_input_move_to(si, s, false); +} +} diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h index f207a094c..24e4678b1 100644 --- a/src/pulsecore/sink.h +++ b/src/pulsecore/sink.h @@ -562,4 +562,5 @@ void pa_sink_set_reference_volume_direct(pa_sink *s, const pa_cvolume *volume); pa_assert(pa_thread_mq_get() || !PA_SINK_IS_LINKED((s)->state)) void pa_sink_move_streams_from_oldsink_to_newsink(pa_sink *old_sink, pa_sink *new_sink, bool from_user); +void pa_sink_bind_preferred_stream_to_a_sink(pa_sink *s); #endif -- 2.17.1 ___ pulseaudio-discuss mailing list pulseaudio-discuss@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
[pulseaudio-discuss] [PATCH 1/4] change bool save_sink to char *preferred_sink
And don't move the stream in the module-stream-restore anymore, And the preferred_sink is only set when user is calling the move_to() and the module-stream-restore maintains the saving and deleting of preferred_sink. If the target of move_to() is default_sink, preferred_sink will be cleared and the entry->device will be cleared too from database. Signed-off-by: Hui Wang --- src/modules/module-device-manager.c| 2 +- src/modules/module-intended-roles.c| 2 +- src/modules/module-stream-restore.c| 47 +- src/modules/module-switch-on-connect.c | 2 +- src/pulsecore/sink-input.c | 25 +++--- src/pulsecore/sink-input.h | 7 ++-- 6 files changed, 59 insertions(+), 26 deletions(-) diff --git a/src/modules/module-device-manager.c b/src/modules/module-device-manager.c index 15fd2..36e71584e 100644 --- a/src/modules/module-device-manager.c +++ b/src/modules/module-device-manager.c @@ -657,7 +657,7 @@ static void route_sink_input(struct userdata *u, pa_sink_input *si) { pa_assert(u->do_routing); /* Don't override user or application routing requests. */ -if (si->save_sink || si->sink_requested_by_application) +if (si->preferred_sink != NULL || si->sink_requested_by_application) return; /* Skip this if it is already in the process of being moved anyway */ diff --git a/src/modules/module-intended-roles.c b/src/modules/module-intended-roles.c index adee51c20..98e4c241f 100644 --- a/src/modules/module-intended-roles.c +++ b/src/modules/module-intended-roles.c @@ -175,7 +175,7 @@ static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, struct if (si->sink == sink) continue; -if (si->save_sink) +if (si->preferred_sink != NULL) continue; /* Skip this if it is already in the process of being moved diff --git a/src/modules/module-stream-restore.c b/src/modules/module-stream-restore.c index 228e9e447..276957c25 100644 --- a/src/modules/module-stream-restore.c +++ b/src/modules/module-stream-restore.c @@ -1311,19 +1311,29 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint3 mute_updated = !created_new_entry && (!old->muted_valid || entry->muted != old->muted); } -if (sink_input->save_sink) { +if (sink_input->preferred_sink != NULL || !created_new_entry) { pa_xfree(entry->device); -entry->device = pa_xstrdup(sink_input->sink->name); -entry->device_valid = true; -device_updated = !created_new_entry && (!old->device_valid || !pa_streq(entry->device, old->device)); -if (sink_input->sink->card) { + if (sink_input->preferred_sink != NULL) { + entry->device = pa_xstrdup(sink_input->preferred_sink); + entry->device_valid = true; + } else { + entry->device = NULL; + entry->device_valid = false; + } + +device_updated = !created_new_entry && (!old->device_valid || !entry->device_valid || !pa_streq(entry->device, old->device)); + + if (entry->device_valid == false) { +pa_xfree(entry->card); +entry->card = NULL; +entry->card_valid = false; + } else if (sink_input->sink->card) { pa_xfree(entry->card); entry->card = pa_xstrdup(sink_input->sink->card->name); entry->card_valid = true; } } - } else { pa_source_output *source_output; @@ -1641,7 +1651,7 @@ static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, struct if (si->sink == sink) continue; -if (si->save_sink) +if (si->preferred_sink != NULL) continue; /* Skip this if it is already in the process of being moved @@ -1665,7 +1675,7 @@ static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, struct if ((e = entry_read(u, name))) { if (e->device_valid && pa_streq(e->device, sink->name)) -pa_sink_input_move_to(si, sink, true); + si->preferred_sink = pa_xstrdup(sink->name); entry_free(e); } @@ -1764,8 +1774,10 @@ static pa_hook_result_t sink_unlink_hook_callback(pa_core *c, pa_sink *sink, str if ((d = pa_namereg_get(c, e->device, PA_NAMEREG_SINK)) && d != sink && -PA_SINK_IS_LINKED(d->state)) -pa_sink_input_move_to(si, d, true); +PA_SINK_IS_LINKED(d->state)) { + pa_xfree(si->preferred_si
[pulseaudio-discuss] [PATCH 2/4] move stream after default sink is changed.
When default sink changes, the stream should be moved to new default_sink too. If it is user to call change default function, all stream will move to new default sink unconditionally; if it is not, will check if stream binds to old_default_sink and the active_port staus of old_default_sink, then it will move the stream conditionally. Signed-off-by: Hui Wang --- src/modules/dbus/iface-core.c | 2 +- src/modules/module-default-device-restore.c | 2 +- src/modules/module-switch-on-connect.c | 28 ++- src/pulsecore/cli-command.c | 2 +- src/pulsecore/core.c| 9 +++-- src/pulsecore/core.h| 4 +-- src/pulsecore/device-port.c | 2 +- src/pulsecore/protocol-native.c | 2 +- src/pulsecore/sink.c| 39 +++-- src/pulsecore/sink.h| 1 + 10 files changed, 52 insertions(+), 39 deletions(-) diff --git a/src/modules/dbus/iface-core.c b/src/modules/dbus/iface-core.c index 5229c0467..9763480d2 100644 --- a/src/modules/dbus/iface-core.c +++ b/src/modules/dbus/iface-core.c @@ -721,7 +721,7 @@ static void handle_set_fallback_sink(DBusConnection *conn, DBusMessage *msg, DBu return; } -pa_core_set_configured_default_sink(c->core, pa_dbusiface_device_get_sink(fallback_sink)->name); +pa_core_set_configured_default_sink(c->core, pa_dbusiface_device_get_sink(fallback_sink)->name, true); pa_dbus_send_empty_reply(conn, msg); } diff --git a/src/modules/module-default-device-restore.c b/src/modules/module-default-device-restore.c index c4dbad99f..33e74c071 100644 --- a/src/modules/module-default-device-restore.c +++ b/src/modules/module-default-device-restore.c @@ -69,7 +69,7 @@ static void load(struct userdata *u) { pa_log_warn("Invalid sink name: %s", ln); else { pa_log_info("Restoring default sink '%s'.", ln); -pa_core_set_configured_default_sink(u->core, ln); +pa_core_set_configured_default_sink(u->core, ln, false); } } else if (errno != ENOENT) diff --git a/src/modules/module-switch-on-connect.c b/src/modules/module-switch-on-connect.c index faa0f289f..4f01c701f 100644 --- a/src/modules/module-switch-on-connect.c +++ b/src/modules/module-switch-on-connect.c @@ -54,9 +54,6 @@ struct userdata { }; static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, void* userdata) { -pa_sink_input *i; -uint32_t idx; -pa_sink *old_default_sink; const char *s; struct userdata *u = userdata; @@ -85,7 +82,7 @@ static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, void* /* No default sink, nothing to move away, just set the new default */ if (!c->default_sink) { -pa_core_set_configured_default_sink(c, sink->name); +pa_core_set_configured_default_sink(c, sink->name, false); return PA_HOOK_OK; } @@ -100,29 +97,8 @@ static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, void* return PA_HOOK_OK; } -old_default_sink = c->default_sink; - /* Actually do the switch to the new sink */ -pa_core_set_configured_default_sink(c, sink->name); - -/* Now move all old inputs over */ -if (pa_idxset_size(old_default_sink->inputs) <= 0) { -pa_log_debug("No sink inputs to move away."); -return PA_HOOK_OK; -} - -PA_IDXSET_FOREACH(i, old_default_sink->inputs, idx) { -if (i->preferred_sink != NULL || !PA_SINK_INPUT_IS_LINKED(i->state)) -continue; - -if (pa_sink_input_move_to(i, sink, false) < 0) -pa_log_info("Failed to move sink input %u \"%s\" to %s.", i->index, -pa_strnull(pa_proplist_gets(i->proplist, PA_PROP_APPLICATION_NAME)), sink->name); -else -pa_log_info("Successfully moved sink input %u \"%s\" to %s.", i->index, -pa_strnull(pa_proplist_gets(i->proplist, PA_PROP_APPLICATION_NAME)), sink->name); -} - +pa_core_set_configured_default_sink(c, sink->name, false); return PA_HOOK_OK; } diff --git a/src/pulsecore/cli-command.c b/src/pulsecore/cli-command.c index 5205349bd..cc7addaa1 100644 --- a/src/pulsecore/cli-command.c +++ b/src/pulsecore/cli-command.c @@ -1036,7 +1036,7 @@ static int pa_cli_command_sink_default(pa_core *c, pa_tokenizer *t, pa_strbuf *b } if ((s = pa_namereg_get(c, n, PA_NAMEREG_SINK))) -pa_core_set_configured_default_sink(c, s->name); +pa_core_set_configured_default_sink(c, s->name, true); else pa_strbuf_printf(buf, "Sink %s does not exist.\n", n); diff --git a/src/pulsecore/core.c b/src/pulsecore/core.c index
[pulseaudio-discuss] [PATCH 4/4] move stream when the active_port changes
When the active port of a sink becomes unavailable, all streams from that sink should be moved to the default sink. When the active port of an existing sink changes state from unavailable, all streams that have their "preferred_sink" set to the new sink should be moved to the new sink. Signed-off-by: Hui Wang --- src/pulsecore/device-port.c | 16 src/pulsecore/sink.c| 13 + src/pulsecore/sink.h| 1 + 3 files changed, 30 insertions(+) diff --git a/src/pulsecore/device-port.c b/src/pulsecore/device-port.c index 464c3f8a2..2604c9051 100644 --- a/src/pulsecore/device-port.c +++ b/src/pulsecore/device-port.c @@ -92,6 +92,7 @@ void pa_device_port_set_available(pa_device_port *p, pa_available_t status) { * be created before port objects, and then p->card could be non-NULL for * the whole lifecycle of pa_device_port. */ if (p->card && p->card->linked) { + pa_sink *sink; /* A sink or source whose active port is unavailable can't be the * default sink/source, so port availability changes may affect the * default sink/source choice. */ @@ -102,6 +103,21 @@ void pa_device_port_set_available(pa_device_port *p, pa_available_t status) { pa_subscription_post(p->core, PA_SUBSCRIPTION_EVENT_CARD|PA_SUBSCRIPTION_EVENT_CHANGE, p->card->index); pa_hook_fire(&p->core->hooks[PA_CORE_HOOK_PORT_AVAILABLE_CHANGED], p); + + sink = pa_sink_get_sink_from_device_port(p); + if (!sink) + return; + switch (p->direction) { +case PA_DIRECTION_OUTPUT: + if (sink->active_port->available == PA_AVAILABLE_NO) + pa_sink_move_streams_from_oldsink_to_newsink(sink, p->core->default_sink, false); + else + pa_sink_bind_preferred_stream_to_a_sink(sink); + +break; +case PA_DIRECTION_INPUT: + break; + } } } diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index a2a390beb..9ebc18fa1 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -3950,3 +3950,16 @@ void pa_sink_bind_preferred_stream_to_a_sink(pa_sink *s) { pa_sink_input_move_to(si, s, false); } } + +pa_sink *pa_sink_get_sink_from_device_port(pa_device_port *p) { +pa_sink *rs = NULL; +pa_sink *sink; +uint32_t state; + +PA_IDXSET_FOREACH(sink, p->card->sinks, state) + if (p == pa_hashmap_get(sink->ports, p->name)) { + rs = sink; + break; + } +return rs; +} diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h index 24e4678b1..693344ac3 100644 --- a/src/pulsecore/sink.h +++ b/src/pulsecore/sink.h @@ -563,4 +563,5 @@ void pa_sink_set_reference_volume_direct(pa_sink *s, const pa_cvolume *volume); void pa_sink_move_streams_from_oldsink_to_newsink(pa_sink *old_sink, pa_sink *new_sink, bool from_user); void pa_sink_bind_preferred_stream_to_a_sink(pa_sink *s); +pa_sink *pa_sink_get_sink_from_device_port(pa_device_port *p); #endif -- 2.17.1 ___ pulseaudio-discuss mailing list pulseaudio-discuss@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
Re: [pulseaudio-discuss] [PATCH 2/4] move stream after default sink is changed.
On 2018/12/13 下午5:16, Tanu Kaskinen wrote: On Mon, 2018-11-05 at 09:47 +0800, Hui Wang wrote: When default sink changes, the stream should be moved to new default_sink too. Except if the stream's preferred sink is the old default sink. If it is user to call change default function, all stream will move to new default sink unconditionally; if it is not, will check if stream binds to old_default_sink and the active_port staus of old_default_sink, then it will move the stream conditionally. Why does it matter if the default sink changed due to user request or some other reason? I don't think streams should be moved unconditionally when the user changes the default sink. Supposing the sink0 is hdmi, sink1 is analog-speaker, and a music is playing on sink0 (default_sink is sink0), if users select the analog-speaker from UI (gnome-sound-setting), the sink1 is default_sink now, and the music should be played on sink1. If the streams don't move to new default_sink unconditionally, I have no idea how to let music be played on sink1 here. For the rest comments, I will fix them as suggested. Thanks. I think it would be logical to not care about the port unavailability in this patch, because there's a separate patch for handling that. diff --git a/src/modules/module-switch-on-connect.c b/src/modules/module-switch-on-connect.c index faa0f289f..4f01c701f 100644 --- a/src/modules/module-switch-on-connect.c +++ b/src/modules/module-switch-on-connect.c @@ -100,29 +97,8 @@ static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, void* return PA_HOOK_OK; } -old_default_sink = c->default_sink; - /* Actually do the switch to the new sink */ This comment isn't very helpful any more (not sure how helpful it was before either), I'd remove it. -pa_core_set_configured_default_sink(c, sink->name); - -/* Now move all old inputs over */ -if (pa_idxset_size(old_default_sink->inputs) <= 0) { -pa_log_debug("No sink inputs to move away."); -return PA_HOOK_OK; -} - -PA_IDXSET_FOREACH(i, old_default_sink->inputs, idx) { -if (i->preferred_sink != NULL || !PA_SINK_INPUT_IS_LINKED(i->state)) -continue; - -if (pa_sink_input_move_to(i, sink, false) < 0) -pa_log_info("Failed to move sink input %u \"%s\" to %s.", i->index, -pa_strnull(pa_proplist_gets(i->proplist, PA_PROP_APPLICATION_NAME)), sink->name); -else -pa_log_info("Successfully moved sink input %u \"%s\" to %s.", i->index, -pa_strnull(pa_proplist_gets(i->proplist, PA_PROP_APPLICATION_NAME)), sink->name); -} - +pa_core_set_configured_default_sink(c, sink->name, false); return PA_HOOK_OK; } diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index 566367f9e..63a3456e7 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -3886,3 +3886,36 @@ void pa_sink_set_reference_volume_direct(pa_sink *s, const pa_cvolume *volume) { pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_VOLUME_CHANGED], s); } + +void pa_sink_move_streams_from_oldsink_to_newsink(pa_sink *old_sink, pa_sink *new_sink, bool from_user) { I think "pa_sink_move_streams_to_default_sink" would be a better name for the function. It would also be good to have a comment explaining when the function is used and which streams are not moved (that could go to the header file). +pa_sink_input *i; +uint32_t idx; +pa_device_port *o_active_p; + +if (old_sink == new_sink) + return; + +if (old_sink == NULL) + return; It doesn't make sense to call this function with NULL, so this check should be an assertion instead. + +o_active_p = old_sink->active_port; Note that not all sinks have ports, so this can be NULL. Since we only care about the availability of the active port, I'd add a "old_sink_is_unavailable" boolean to be used inside the loop. +if (pa_idxset_size(old_sink->inputs) > 0) { + PA_IDXSET_FOREACH(i, old_sink->inputs, idx) { + if (!PA_SINK_INPUT_IS_LINKED(i->state)) + continue; + + if (!from_user && i->preferred_sink != NULL && pa_safe_streq(old_sink->name, i->preferred_sink)) No need to check if i->preferred_sink is NULL, because pa_safe_streq() checks that anyway. + if (o_active_p->available != PA_AVAILABLE_NO) + continue; + + if (pa_sink_input_move_to(i, new_sink, from_user) < 0) + pa_log_info("Failed to move sink input %u \"%s\" to %s.", i
Re: [pulseaudio-discuss] [PATCH 1/4] change bool save_sink to char *preferred_sink
On 2018/12/12 下午9:39, Tanu Kaskinen wrote: Thanks for working on this! Sorry for slow review, I hope I'll be much quicker to comment on subsequent iterations. On Mon, 2018-11-05 at 09:47 +0800, Hui Wang wrote: And don't move the stream in the module-stream-restore anymore, And the preferred_sink is only set when user is calling the move_to() and the module-stream-restore maintains the saving and deleting of preferred_sink. If the target of move_to() is default_sink, preferred_sink will be cleared and the entry->device will be cleared too from database. Can you split this so that the first patch only changes save_sink to preferred_sink, without any changes in behaviour? That is, put the "don't move the stream in the module-stream-restore" and "if the target of move_to() is default_sink" logic into separate patches. Also replace tabs with spaces. OK, got it, will addressed all comments. Signed-off-by: Hui Wang [...] } } @@ -2176,9 +2190,10 @@ static int extension_cb(pa_native_protocol *p, pa_module *m, pa_native_connectio entry->muted = muted; entry->muted_valid = true; - -entry->device = pa_xstrdup(device); -entry->device_valid = device && !!entry->device[0]; + if (device && !pa_streq(device, m->core->default_sink->name) && !pa_streq(device, m->core->default_source->name)) { + entry->device = pa_xstrdup(device); + entry->device_valid = device && !!entry->device[0]; + } What's the goal here? The client tries to change an entry in the stream-restore database, why should that change be ignored if the current default sink happens to be the same as the new device? Maybe you intended to set entry->device to NULL in this case. But I don't think that's necessary either - if the client wants to unset the device, it can just give NULL as the device name. I don't think you need to change anything here. By the way, m->core->default_sink can be NULL, so that would have to be checked if this code was kept. Actually I didn't change this part first, but I remember the stream bond did not work as expected, after changed as above, it worked as expected. Supposing sink0 is hdmi, and is playing a music over sink0, sink1 is speaker, after I unplugged the hdmi cable, the music is switched to speaker, but music->preferred_sink is still sink0-hdmi, after I plug the hdmi cable again, the music should be switched back to sink0-hdmi. I remember after I unplugged the cable, a user-space app call extension_cb to set the music->preferred_sink to be sink1-speaker (default_sink), then the music can't be switched back to hdmi anymore. I will test it again, if it is really not needed, I will drop these code. Thanks, Hui. if (entry->device_valid && !pa_namereg_is_valid_name(entry->device)) { entry_free(entry); ___ pulseaudio-discuss mailing list pulseaudio-discuss@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
[pulseaudio-discuss] [PATCH] alsa-mixer: Adding Jack of Front Headphone Front and Surround
We have 2 HP desktop models which have one front headphone Jack and one front headset Jack, in the Linux kernel, these two jacks are named "Front Headphone Front Jack" and "Front Headphone Surround Jack", now adding them into the pathes conf file. Without this change, if users plug a headset or headphone, the path of headphone will not be activated, and users can't see headphones from UI like gnome-control-center. Signed-off-by: Hui Wang --- For alsa-info.txt of one of machines, please access: https://pastebin.ubuntu.com/p/CjCGySMpM5/ .../alsa/mixer/paths/analog-input-headset-mic.conf| 6 ++ .../alsa/mixer/paths/analog-output-headphones.conf| 6 ++ .../alsa/mixer/paths/analog-output-speaker-always.conf| 8 src/modules/alsa/mixer/paths/analog-output-speaker.conf | 8 4 files changed, 28 insertions(+) diff --git a/src/modules/alsa/mixer/paths/analog-input-headset-mic.conf b/src/modules/alsa/mixer/paths/analog-input-headset-mic.conf index 579db6bb7..bc687b6e4 100644 --- a/src/modules/alsa/mixer/paths/analog-input-headset-mic.conf +++ b/src/modules/alsa/mixer/paths/analog-input-headset-mic.conf @@ -35,6 +35,12 @@ state.plugged = unknown [Jack Front Headphone] state.plugged = unknown +[Jack Front Headphone Front] +state.plugged = unknown + +[Jack Front Headphone Surround] +state.plugged = unknown + [Jack Headphone Mic] state.plugged = unknown diff --git a/src/modules/alsa/mixer/paths/analog-output-headphones.conf b/src/modules/alsa/mixer/paths/analog-output-headphones.conf index d2147c50f..2d751607c 100644 --- a/src/modules/alsa/mixer/paths/analog-output-headphones.conf +++ b/src/modules/alsa/mixer/paths/analog-output-headphones.conf @@ -40,6 +40,12 @@ required-any = any state.plugged = unknown state.unplugged = unknown +[Jack Front Headphone Front] +required-any = any + +[Jack Front Headphone Surround] +required-any = any + [Jack Headphone] required-any = any diff --git a/src/modules/alsa/mixer/paths/analog-output-speaker-always.conf b/src/modules/alsa/mixer/paths/analog-output-speaker-always.conf index 71f356dce..c9374e471 100644 --- a/src/modules/alsa/mixer/paths/analog-output-speaker-always.conf +++ b/src/modules/alsa/mixer/paths/analog-output-speaker-always.conf @@ -33,6 +33,14 @@ state.unplugged = unknown state.plugged = no state.unplugged = unknown +[Jack Front Headphone Front] +state.plugged = no +state.unplugged = unknown + +[Jack Front Headphone Surround] +state.plugged = no +state.unplugged = unknown + [Jack Line Out] state.plugged = no state.unplugged = unknown diff --git a/src/modules/alsa/mixer/paths/analog-output-speaker.conf b/src/modules/alsa/mixer/paths/analog-output-speaker.conf index 9f4dac414..536630d0a 100644 --- a/src/modules/alsa/mixer/paths/analog-output-speaker.conf +++ b/src/modules/alsa/mixer/paths/analog-output-speaker.conf @@ -36,6 +36,14 @@ state.unplugged = unknown state.plugged = no state.unplugged = unknown +[Jack Front Headphone Front] +state.plugged = no +state.unplugged = unknown + +[Jack Front Headphone Surround] +state.plugged = no +state.unplugged = unknown + [Jack Line Out] state.plugged = no state.unplugged = unknown -- 2.17.1 ___ pulseaudio-discuss mailing list pulseaudio-discuss@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
Re: [pulseaudio-discuss] [PATCH 1/4] change bool save_sink to char *preferred_sink
On 2018/12/23 上午3:06, Tanu Kaskinen wrote: On Sat, 2018-12-15 at 16:47 +0800, Hui Wang wrote: On 2018/12/12 下午9:39, Tanu Kaskinen wrote: Thanks for working on this! Sorry for slow review, I hope I'll be much quicker to comment on subsequent iterations. On Mon, 2018-11-05 at 09:47 +0800, Hui Wang wrote: And don't move the stream in the module-stream-restore anymore, And the preferred_sink is only set when user is calling the move_to() and the module-stream-restore maintains the saving and deleting of preferred_sink. If the target of move_to() is default_sink, preferred_sink will be cleared and the entry->device will be cleared too from database. Can you split this so that the first patch only changes save_sink to preferred_sink, without any changes in behaviour? That is, put the "don't move the stream in the module-stream-restore" and "if the target of move_to() is default_sink" logic into separate patches. Also replace tabs with spaces. OK, got it, will addressed all comments. Signed-off-by: Hui Wang [...] } } @@ -2176,9 +2190,10 @@ static int extension_cb(pa_native_protocol *p, pa_module *m, pa_native_connectio entry->muted = muted; entry->muted_valid = true; - -entry->device = pa_xstrdup(device); -entry->device_valid = device && !!entry->device[0]; + if (device && !pa_streq(device, m->core->default_sink->name) && !pa_streq(device, m->core->default_source->name)) { + entry->device = pa_xstrdup(device); + entry->device_valid = device && !!entry->device[0]; + } What's the goal here? The client tries to change an entry in the stream-restore database, why should that change be ignored if the current default sink happens to be the same as the new device? Maybe you intended to set entry->device to NULL in this case. But I don't think that's necessary either - if the client wants to unset the device, it can just give NULL as the device name. I don't think you need to change anything here. By the way, m->core->default_sink can be NULL, so that would have to be checked if this code was kept. Actually I didn't change this part first, but I remember the stream bond did not work as expected, after changed as above, it worked as expected. Supposing sink0 is hdmi, and is playing a music over sink0, sink1 is speaker, after I unplugged the hdmi cable, the music is switched to speaker, but music->preferred_sink is still sink0-hdmi, after I plug the hdmi cable again, the music should be switched back to sink0-hdmi. I remember after I unplugged the cable, a user-space app call extension_cb to set the music->preferred_sink to be sink1-speaker (default_sink), then the music can't be switched back to hdmi anymore. I will test it again, if it is really not needed, I will drop these code. I would guess that it's gnome-control-center that sets the device to speakers when you select speakers as the output. gnome-control-center updates the routing in all stream-restore entries. Once these patches are merged (and once a new release is made), gnome-control-center can be fixed to not mess with the stream-restore database any more. I believe the current gnome-control-center behaviour is a workaround for the fact that PulseAudio hasn't so far automatically moved streams when the default sink changes. Yes, it is gnome-control-center. OK, will drop this part. ___ pulseaudio-discuss mailing list pulseaudio-discuss@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
Re: [pulseaudio-discuss] [PATCH 2/4] move stream after default sink is changed.
On 2018/12/23 上午2:57, Tanu Kaskinen wrote: On Sat, 2018-12-15 at 14:48 +0800, Hui Wang wrote: On 2018/12/13 下午5:16, Tanu Kaskinen wrote: On Mon, 2018-11-05 at 09:47 +0800, Hui Wang wrote: When default sink changes, the stream should be moved to new default_sink too. Except if the stream's preferred sink is the old default sink. If it is user to call change default function, all stream will move to new default sink unconditionally; if it is not, will check if stream binds to old_default_sink and the active_port staus of old_default_sink, then it will move the stream conditionally. Why does it matter if the default sink changed due to user request or some other reason? I don't think streams should be moved unconditionally when the user changes the default sink. Supposing the sink0 is hdmi, sink1 is analog-speaker, and a music is playing on sink0 (default_sink is sink0), if users select the analog-speaker from UI (gnome-sound-setting), the sink1 is default_sink now, and the music should be played on sink1. If the streams don't move to new default_sink unconditionally, I have no idea how to let music be played on sink1 here. I don't see what the problem is - streams should by default move to the new default sink, but if the user has at some point manually moved a stream to sink0, making sink0 the preferred sink, then that stream shouldn't be moved automatically. If the user doesn't want to keep that old setting any more, they can move the stream manually to sink1, and since sink1 is the default sink at this point, the preferred_sink will be unset, so that stream will from then on behave like all other streams. OK, got it. thanks. ___ pulseaudio-discuss mailing list pulseaudio-discuss@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
Re: [pulseaudio-discuss] [PATCH] alsa-mixer: Adding Jack of Front Headphone Front and Surround
On 2018/12/31 下午9:46, Tanu Kaskinen wrote: On Fri, 2018-12-21 at 11:05 +0800, Hui Wang wrote: We have 2 HP desktop models which have one front headphone Jack and one front headset Jack, in the Linux kernel, these two jacks are named "Front Headphone Front Jack" and "Front Headphone Surround Jack", now adding them into the pathes conf file. How do the kcontrols map to physical connectors? Is there only one physical connector or two? How do different kinds of devices (headphones, headsets, stand-alone mics) change the state of the two kcontrols? There are 2 physical connectors/jacks, one is the pure headphone jack, the other is the headset jack (headphone + mic). For the headphone jack, the kcontrols are: 'Front Headphone Surround Jack' and 'Headphone Playback Volume' index 1 For the headset jack, the kcontrols are: 'Front Headphone Front Jack', 'Headphone Playback Volume' index 0, 'Mic Jack' and 'Mic Boost Volume' If we plug a headphone in either of the two jacks, the 'Surround Jack' or 'Front Jack' will be true. If we plug a headset in the headset jack, the 'Front Jack' and 'Mic Jack' will be true. This is not the Dell machine, most Dell machines can't detect mic of headset, so we add headset-mic, headphone-mic for them. This HP machine can detect mic of headset jack, and it doesn't support stand-alone mics too. I think at least the headset-mic path configuration in your patch is incorrect, but I don't know how it should be configured before knowing how the two kcontrols behave. After reading your comments above, I think you are right. And I think I shouldn't touch analog-input-headset-mic.conf in the patch, since this is a HP machine, and the headset jack of this machine has capability to detect the mic on the headset and the kcontrols are "Mic Jack" and "Headphone Front Jack". It is different from the Dell machines. (A sidenote: it would be awesome to have some documentation that explains what combinations of headphone/headset/mic jacks exist in the wild and how those combinations map to physical connectors. The details of the headphone/headset/mic jack detection mess are impossible to remember.) It is not easy to fully understand this part, need to study it bit by bit. :-) Without this change, if users plug a headset or headphone, the path of headphone will not be activated, and users can't see headphones from UI like gnome-control-center. Signed-off-by: Hui Wang --- For alsa-info.txt of one of machines, please access: https://pastebin.ubuntu.com/p/CjCGySMpM5/ .../alsa/mixer/paths/analog-input-headset-mic.conf| 6 ++ .../alsa/mixer/paths/analog-output-headphones.conf| 6 ++ .../alsa/mixer/paths/analog-output-speaker-always.conf| 8 src/modules/alsa/mixer/paths/analog-output-speaker.conf | 8 4 files changed, 28 insertions(+) diff --git a/src/modules/alsa/mixer/paths/analog-input-headset-mic.conf b/src/modules/alsa/mixer/paths/analog-input-headset-mic.conf index 579db6bb7..bc687b6e4 100644 --- a/src/modules/alsa/mixer/paths/analog-input-headset-mic.conf +++ b/src/modules/alsa/mixer/paths/analog-input-headset-mic.conf @@ -35,6 +35,12 @@ state.plugged = unknown [Jack Front Headphone] state.plugged = unknown +[Jack Front Headphone Front] +state.plugged = unknown + +[Jack Front Headphone Surround] +state.plugged = unknown + [Jack Headphone Mic] state.plugged = unknown diff --git a/src/modules/alsa/mixer/paths/analog-output-headphones.conf b/src/modules/alsa/mixer/paths/analog-output-headphones.conf index d2147c50f..2d751607c 100644 --- a/src/modules/alsa/mixer/paths/analog-output-headphones.conf +++ b/src/modules/alsa/mixer/paths/analog-output-headphones.conf @@ -40,6 +40,12 @@ required-any = any state.plugged = unknown state.unplugged = unknown +[Jack Front Headphone Front] +required-any = any + +[Jack Front Headphone Surround] +required-any = any + [Jack Headphone] required-any = any diff --git a/src/modules/alsa/mixer/paths/analog-output-speaker-always.conf b/src/modules/alsa/mixer/paths/analog-output-speaker-always.conf index 71f356dce..c9374e471 100644 --- a/src/modules/alsa/mixer/paths/analog-output-speaker-always.conf +++ b/src/modules/alsa/mixer/paths/analog-output-speaker-always.conf @@ -33,6 +33,14 @@ state.unplugged = unknown state.plugged = no state.unplugged = unknown +[Jack Front Headphone Front] +state.plugged = no +state.unplugged = unknown + +[Jack Front Headphone Surround] +state.plugged = no +state.unplugged = unknown + [Jack Line Out] state.plugged = no state.unplugged = unknown diff --git a/src/modules/alsa/mixer/paths/analog-output-speaker.conf b/src/modules/alsa/mixer/paths/analog-output-speaker.conf index 9f4dac414..536630d0a 100644 --- a/src/modules/alsa/m
Re: [pulseaudio-discuss] [PATCH 3/4] move streams to new appeared sinks if they prefer these sinks
On 2019/1/1 上午2:10, Tanu Kaskinen wrote: On Mon, 2018-12-31 at 20:01 +0200, Tanu Kaskinen wrote: On Mon, 2018-11-05 at 09:47 +0800, Hui Wang wrote: diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index 63a3456e7..a2a390beb 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -722,6 +722,8 @@ void pa_sink_put(pa_sink* s) { /* This function must be called after the PA_CORE_HOOK_SINK_PUT hook, * because module-switch-on-connect needs to know the old default sink */ pa_core_update_default_sink(s->core, false); + +pa_sink_bind_preferred_stream_to_a_sink(s); } /* Called from main context */ @@ -3919,3 +3921,32 @@ void pa_sink_move_streams_from_oldsink_to_newsink(pa_sink *old_sink, pa_sink *ne return; } + +void pa_sink_bind_preferred_stream_to_a_sink(pa_sink *s) { "Bind" is new terminology, and I'd like to avoid introducing new terminology if possible. Also, "preferred stream" as a term doesn't really make sense. So some better name for the function would be desirable, but I can't immediately think of any obvious names... The function is about moving streams to a sink that just became available. "Move" and "streams" should be included in the name... Maybe "pa_sink_move_streams_to_newly_available_sink()"? I also suggest moving it away from the pa_sink namespace, because the function operates on streams, not on a sink. That last sentence can be objected to - the function takes the sink as an argument, so it can be said to operate on the sink. But then the verb should be something that the sink does, like "take" ("move" is something that streams do). So pa_sink_take_streams()? Or pa_sink_take_streams_that_prefer_it()? I don't know. My weak preference at this point is pa_core_move_streams_to_newly_available_sink(). It's quite descriptive, but unfortunately lacks the distinction that only those streams that prefer the newly available sink are moved. Understand what you mean here, will have a try to provide a new function name and address the rest comments of this patch. Thanks. ___ pulseaudio-discuss mailing list pulseaudio-discuss@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
Re: [pulseaudio-discuss] [PATCH 4/4] move stream when the active_port changes
On 2019/1/1 上午2:33, Tanu Kaskinen wrote: On Mon, 2018-11-05 at 09:47 +0800, Hui Wang wrote: When the active port of a sink becomes unavailable, all streams from that sink should be moved to the default sink. When the active port of an existing sink changes state from unavailable, all streams that have their "preferred_sink" set to the new sink should be moved to the new sink. Signed-off-by: Hui Wang --- src/pulsecore/device-port.c | 16 src/pulsecore/sink.c| 13 + src/pulsecore/sink.h| 1 + 3 files changed, 30 insertions(+) diff --git a/src/pulsecore/device-port.c b/src/pulsecore/device-port.c index 464c3f8a2..2604c9051 100644 --- a/src/pulsecore/device-port.c +++ b/src/pulsecore/device-port.c @@ -92,6 +92,7 @@ void pa_device_port_set_available(pa_device_port *p, pa_available_t status) { * be created before port objects, and then p->card could be non-NULL for * the whole lifecycle of pa_device_port. */ if (p->card && p->card->linked) { + pa_sink *sink; /* A sink or source whose active port is unavailable can't be the * default sink/source, so port availability changes may affect the * default sink/source choice. */ @@ -102,6 +103,21 @@ void pa_device_port_set_available(pa_device_port *p, pa_available_t status) { pa_subscription_post(p->core, PA_SUBSCRIPTION_EVENT_CARD|PA_SUBSCRIPTION_EVENT_CHANGE, p->card->index); pa_hook_fire(&p->core->hooks[PA_CORE_HOOK_PORT_AVAILABLE_CHANGED], p); + + sink = pa_sink_get_sink_from_device_port(p); + if (!sink) + return; + switch (p->direction) { +case PA_DIRECTION_OUTPUT: + if (sink->active_port->available == PA_AVAILABLE_NO) + pa_sink_move_streams_from_oldsink_to_newsink(sink, p->core->default_sink, false); This logic isn't quite right. We should move streams away from the sink only if the active port is the same that just changed its availability status. If the current port is something other than the port that changed, then we should ignore the change event. I will change this part and make it follow the correct logic. + else + pa_sink_bind_preferred_stream_to_a_sink(sink); + +break; +case PA_DIRECTION_INPUT: + break; + } } } diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index a2a390beb..9ebc18fa1 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -3950,3 +3950,16 @@ void pa_sink_bind_preferred_stream_to_a_sink(pa_sink *s) { pa_sink_input_move_to(si, s, false); } } + +pa_sink *pa_sink_get_sink_from_device_port(pa_device_port *p) { This is a good helper function, but I think it would fit slightly better in the pa_device_port namespace. So I'd rename it to pa_device_port_get_sink(). OK, got it. +pa_sink *rs = NULL; +pa_sink *sink; +uint32_t state; + +PA_IDXSET_FOREACH(sink, p->card->sinks, state) + if (p == pa_hashmap_get(sink->ports, p->name)) { + rs = sink; + break; + } +return rs; +} diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h index 24e4678b1..693344ac3 100644 --- a/src/pulsecore/sink.h +++ b/src/pulsecore/sink.h @@ -563,4 +563,5 @@ void pa_sink_set_reference_volume_direct(pa_sink *s, const pa_cvolume *volume); void pa_sink_move_streams_from_oldsink_to_newsink(pa_sink *old_sink, pa_sink *new_sink, bool from_user); void pa_sink_bind_preferred_stream_to_a_sink(pa_sink *s); +pa_sink *pa_sink_get_sink_from_device_port(pa_device_port *p); #endif ___ pulseaudio-discuss mailing list pulseaudio-discuss@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
[pulseaudio-discuss] [PATCH v2 0/2] Handle two Headphone Jacks with the same name
Although the patchset tries to add index support, the objective is 100% compatible with the past. If there is no kcontrols with "index != 0", we don't need to change any conf files, the pulseaudio will work as before. The name of "Front Headphone Surround" and "Front Headphone Front" are not good, I plan to submit a patch to the kernel to change the name to "Front Headphone" with index 0 and "Front Headphone" with index 1, since the patch for the kernel is not submitted yet, here I don't send the patch to change ${path}.conf, but to be easy to review, I paste an example of changing the ${path}.conf after the kernel patch is merged: --- a/src/modules/alsa/mixer/paths/analog-output-headphones-2.conf +++ b/src/modules/alsa/mixer/paths/analog-output-headphones-2.conf @@ -40,6 +40,18 @@ override-map.2 = all-left,all-right switch = off volume = off +[Jack Front Headphone@1] +required-any = any +index = 1 + +[Element Headphone@1] +required-any = any +index = 1 +switch = mute +volume = merge +override-map.1 = all +override-map.2 = all-left,all-right + ; This profile path is intended to control the second headphones, not ; the first headphones. But it should not hurt if we leave the ; headphone jack enabled nonetheless. @@ -56,7 +68,7 @@ switch = off volume = off [Element Headphone2] -required = any +required-any = any switch = mute volume = merge override-map.1 = all --- a/src/modules/alsa/mixer/paths/analog-output-speaker.conf +++ b/src/modules/alsa/mixer/paths/analog-output-speaker.conf @@ -32,6 +32,11 @@ state.unplugged = unknown state.plugged = no state.unplugged = unknown +[Jack Front Headphone@1] +index = 1 +state.plugged = no +state.unplugged = unknown + [Jack Front Headphone] state.plugged = no state.unplugged = unknown Hui Wang (2): alsa-mixer: Add alsa index number support for Element and Jack alsa-mixer: set different strings to name and alsa-name for jack and element src/modules/alsa/alsa-mixer.c | 99 +++ src/modules/alsa/alsa-mixer.h | 6 +- src/modules/alsa/alsa-ucm.c | 2 +- src/modules/alsa/alsa-util.c | 4 +- src/modules/alsa/alsa-util.h | 2 +- .../mixer/paths/analog-output.conf.common | 6 ++ src/modules/alsa/module-alsa-card.c | 4 +- 7 files changed, 95 insertions(+), 28 deletions(-) -- 2.17.1 ___ pulseaudio-discuss mailing list pulseaudio-discuss@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
[pulseaudio-discuss] [PATCH v2 1/2] alsa-mixer: Add alsa index number support for Element and Jack
We have met a couple of machines which have two Kcontrols with the exact same names and with the different index numbers, for example: (1 physical headphone jack + 1 physical headset jack on front panel) - Simple mixer control 'Headphone',0 (volume and switch) - Simple mixer control 'Headphone',1 (volume and switch) (1 physical mic jack + 1 physical headset jack on front panel) - iface=CARD,name='Mic Jack' index 0 - iface=CARD,name='Mic Jack' index 1 To let pulseaudio treat them as different Jacks or differnt Elements, we introduce index to the pa_alsa_jack and pa_alsa_element. When probing jacks or elements, we add index as a parameter. Signed-off-by: Hui Wang --- src/modules/alsa/alsa-mixer.c | 59 ++- src/modules/alsa/alsa-mixer.h | 2 + src/modules/alsa/alsa-ucm.c | 2 +- src/modules/alsa/alsa-util.c | 4 +- src/modules/alsa/alsa-util.h | 2 +- .../mixer/paths/analog-output.conf.common | 5 ++ src/modules/alsa/module-alsa-card.c | 4 +- 7 files changed, 59 insertions(+), 19 deletions(-) diff --git a/src/modules/alsa/alsa-mixer.c b/src/modules/alsa/alsa-mixer.c index 91dfc66ee..e32ec5cd7 100644 --- a/src/modules/alsa/alsa-mixer.c +++ b/src/modules/alsa/alsa-mixer.c @@ -718,11 +718,11 @@ static pa_volume_t from_alsa_volume(long v, long min, long max) { return (pa_volume_t) round(((double) (v - min) * PA_VOLUME_NORM) / (double) (max - min)); } -#define SELEM_INIT(sid, name) \ +#define SELEM_INIT(sid, name, index) \ do {\ snd_mixer_selem_id_alloca(&(sid)); \ snd_mixer_selem_id_set_name((sid), (name)); \ -snd_mixer_selem_id_set_index((sid), 0); \ +snd_mixer_selem_id_set_index((sid), index); \ } while(false) static int element_get_volume(pa_alsa_element *e, snd_mixer_t *m, const pa_channel_map *cm, pa_cvolume *v) { @@ -737,7 +737,7 @@ static int element_get_volume(pa_alsa_element *e, snd_mixer_t *m, const pa_chann pa_assert(cm); pa_assert(v); -SELEM_INIT(sid, e->alsa_name); +SELEM_INIT(sid, e->alsa_name, e->index); if (!(me = snd_mixer_find_selem(m, sid))) { pa_log_warn("Element %s seems to have disappeared.", e->alsa_name); return -1; @@ -902,7 +902,7 @@ static int element_get_switch(pa_alsa_element *e, snd_mixer_t *m, bool *b) { pa_assert(e); pa_assert(b); -SELEM_INIT(sid, e->alsa_name); +SELEM_INIT(sid, e->alsa_name, e->index); if (!(me = snd_mixer_find_selem(m, sid))) { pa_log_warn("Element %s seems to have disappeared.", e->alsa_name); return -1; @@ -1066,7 +1066,7 @@ static int element_set_volume(pa_alsa_element *e, snd_mixer_t *m, const pa_chann pa_assert(v); pa_assert(pa_cvolume_compatible_with_channel_map(v, cm)); -SELEM_INIT(sid, e->alsa_name); +SELEM_INIT(sid, e->alsa_name, e->index); if (!(me = snd_mixer_find_selem(m, sid))) { pa_log_warn("Element %s seems to have disappeared.", e->alsa_name); return -1; @@ -1256,7 +1256,7 @@ static int element_set_switch(pa_alsa_element *e, snd_mixer_t *m, bool b) { pa_assert(m); pa_assert(e); -SELEM_INIT(sid, e->alsa_name); +SELEM_INIT(sid, e->alsa_name, e->index); if (!(me = snd_mixer_find_selem(m, sid))) { pa_log_warn("Element %s seems to have disappeared.", e->alsa_name); return -1; @@ -1307,7 +1307,7 @@ static int element_set_constant_volume(pa_alsa_element *e, snd_mixer_t *m) { pa_assert(m); pa_assert(e); -SELEM_INIT(sid, e->alsa_name); +SELEM_INIT(sid, e->alsa_name, e->index); if (!(me = snd_mixer_find_selem(m, sid))) { pa_log_warn("Element %s seems to have disappeared.", e->alsa_name); return -1; @@ -1734,7 +1734,7 @@ static int element_probe(pa_alsa_element *e, snd_mixer_t *m) { pa_assert(e); pa_assert(e->path); -SELEM_INIT(sid, e->alsa_name); +SELEM_INIT(sid, e->alsa_name, e->index); if (!(me = snd_mixer_find_selem(m, sid))) { @@ -1837,7 +1837,7 @@ static int jack_probe(pa_alsa_jack *j, pa_alsa_mapping *mapping, snd_mixer_t *m) j->append_pcm_to_name = false; } -has_control = pa_alsa_mixer_find(m, j->alsa_name, 0) != NULL; +has_control = pa_alsa_mixer_find(m, j->alsa_name, 0, j->index) != NULL; pa_alsa_jack_set_has_control(j, has_control); if (j->has_control) { @@ -1959,6 +1959,36 @@ finish: return o; } +static int element_parse_index(pa_config_parser_state *state) { +pa_alsa_path *p; +pa_alsa_element *e; +pa_alsa_jack *j; +uint32_t ind; + +pa_assert
[pulseaudio-discuss] [PATCH v2 2/2] alsa-mixer: set different strings to name and alsa-name for jack and element
It is possible that we set more than one jacks or elements with the same name and different index in a {path}.conf, the current code will only generate one pa_alsa_jack or pa_alsa_element for them regardless of the difference of index number. To fix it, we change the rule of naming an element or a jack, let us use the element as an example, if the index of this element is 0, we don't set index for it in the {path}.conf and set the element name to as before, if the index number is 1, we should set the "index = 1" for this element in the {path}.conf and set the element name to @1, then in the alsa-mixer.c, the "@1" will be set to the element->name, and the "" will be set to the element->alsa_name, we generated the new element based on the element->name, then this issue is fixed. Signed-off-by: Hui Wang --- src/modules/alsa/alsa-mixer.c | 40 +++ src/modules/alsa/alsa-mixer.h | 4 +- .../mixer/paths/analog-output.conf.common | 3 +- 3 files changed, 37 insertions(+), 10 deletions(-) diff --git a/src/modules/alsa/alsa-mixer.c b/src/modules/alsa/alsa-mixer.c index e32ec5cd7..b4933e07f 100644 --- a/src/modules/alsa/alsa-mixer.c +++ b/src/modules/alsa/alsa-mixer.c @@ -100,6 +100,8 @@ static inline int vgfix_get_playback_dB_range(snd_mixer_elem_t *a, long *b, long #endif +#define SEC_NAME_INDEX_DELIMITER "@" + static int setting_select(pa_alsa_setting *s, snd_mixer_t *m); struct description_map { @@ -109,13 +111,17 @@ struct description_map { pa_alsa_jack *pa_alsa_jack_new(pa_alsa_path *path, const char *name) { pa_alsa_jack *jack; +char *tmp_name; +const char *split_state = NULL; pa_assert(name); jack = pa_xnew0(pa_alsa_jack, 1); jack->path = path; jack->name = pa_xstrdup(name); -jack->alsa_name = pa_sprintf_malloc("%s Jack", name); +tmp_name = pa_split(name, SEC_NAME_INDEX_DELIMITER, &split_state); +jack->alsa_name = pa_sprintf_malloc("%s Jack", tmp_name); +pa_xfree(tmp_name); jack->state_unplugged = PA_AVAILABLE_NO; jack->state_plugged = PA_AVAILABLE_YES; jack->ucm_devices = pa_dynarray_new(NULL); @@ -657,6 +663,7 @@ static void element_free(pa_alsa_element *e) { if (e->db_fix) decibel_fix_free(e->db_fix); +pa_xfree(e->name); pa_xfree(e->alsa_name); pa_xfree(e); } @@ -1820,6 +1827,8 @@ static int jack_probe(pa_alsa_jack *j, pa_alsa_mapping *mapping, snd_mixer_t *m) if (j->append_pcm_to_name) { char *new_name; +char *tmp_name; +const char *split_state = NULL; if (!mapping) { /* This could also be an assertion, because this should never @@ -1831,7 +1840,9 @@ static int jack_probe(pa_alsa_jack *j, pa_alsa_mapping *mapping, snd_mixer_t *m) return -1; } -new_name = pa_sprintf_malloc("%s,pcm=%i Jack", j->name, mapping->hw_device_index); +tmp_name = pa_split(j->name, SEC_NAME_INDEX_DELIMITER, &split_state); +new_name = pa_sprintf_malloc("%s,pcm=%i Jack", tmp_name, mapping->hw_device_index); +pa_xfree(tmp_name); pa_xfree(j->alsa_name); j->alsa_name = new_name; j->append_pcm_to_name = false; @@ -1855,6 +1866,8 @@ static int jack_probe(pa_alsa_jack *j, pa_alsa_mapping *mapping, snd_mixer_t *m) static pa_alsa_element* element_get(pa_alsa_path *p, const char *section, bool prefixed) { pa_alsa_element *e; +char *tmp_name; +const char *split_state = NULL; pa_assert(p); pa_assert(section); @@ -1870,16 +1883,19 @@ static pa_alsa_element* element_get(pa_alsa_path *p, const char *section, bool p if (strchr(section, ':')) return NULL; -if (p->last_element && pa_streq(p->last_element->alsa_name, section)) +if (p->last_element && pa_streq(p->last_element->name, section)) return p->last_element; PA_LLIST_FOREACH(e, p->elements) -if (pa_streq(e->alsa_name, section)) +if (pa_streq(e->name, section)) goto finish; e = pa_xnew0(pa_alsa_element, 1); e->path = p; -e->alsa_name = pa_xstrdup(section); +e->name = pa_xstrdup(section); +tmp_name = pa_split(section, SEC_NAME_INDEX_DELIMITER, &split_state); +e->alsa_name = pa_xstrdup(tmp_name); +pa_xfree(tmp_name); e->direction = p->direction; e->volume_limit = -1; @@ -2692,6 +2708,8 @@ fail: pa_alsa_path *pa_alsa_path_synthesize(const char *element, pa_alsa_direction_t direction) { pa_alsa_path *p; pa_alsa_element *e; +char *tmp_name; +const char *split_state = NULL; pa_assert(element); @@ -2702,7 +2720,10 @@ pa_alsa_path *pa_alsa_path_synthesize(const char
[pulseaudio-discuss] [PATCH v2 0/8] Change the bool sink_save to char *preferred_sink
This is based on Tanu's design: https://lists.freedesktop.org/archives/pulseaudio-discuss/2018-October/030531.html And this is only for sink-input and sink, not for source-output and source. In the V2, I addressed all comments of V1 and split the big patch into small patches as suggested by Tanu. It will be easy to review in the future. The 0007 and 0008 are not in the design of the above, I guess the 0007 is needed but am not sure. The 0008 is a workaround for current gnome-control-center. Hui Wang (8): sink-input: change bool save_sink to char *preferred_sink sink-input: add a new API pa_sink_input_set_preferred_sink sink-input: clear the preferred_sink if it is default_sink core: move sink-inputs conditionally when update default_sink sink: move streams to new appeared sinks if they prefer these sinks device-port: moving streams due to changing the status of active_port sink: move the streams to the default_sink when the sink is unlinked stream-restore: skip entries setting action from gnome-control-center src/modules/dbus/iface-core.c | 2 +- src/modules/module-default-device-restore.c | 2 +- src/modules/module-device-manager.c | 8 +- src/modules/module-intended-roles.c | 2 +- src/modules/module-stream-restore.c | 151 +--- src/modules/module-switch-on-connect.c | 27 +--- src/pulsecore/cli-command.c | 2 +- src/pulsecore/core.c| 38 - src/pulsecore/core.h| 6 +- src/pulsecore/device-port.c | 32 - src/pulsecore/device-port.h | 2 + src/pulsecore/protocol-native.c | 2 +- src/pulsecore/sink-input.c | 42 +- src/pulsecore/sink-input.h | 19 ++- src/pulsecore/sink.c| 40 +- src/pulsecore/sink.h| 6 + 16 files changed, 209 insertions(+), 172 deletions(-) -- 2.17.1 ___ pulseaudio-discuss mailing list pulseaudio-discuss@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
[pulseaudio-discuss] [PATCH v2 2/8] sink-input: add a new API pa_sink_input_set_preferred_sink
If the sink here is NULL, that means users want to clear the preferred_sink and move the sink-input to the default_sink, otherwise set the preferred_sink to the sink->name and move the sink-input to the sink. After that fire the sink_input_change event. After adding this API, we can use this API to simplify the entry_apply in the module-stream-restore.c. Signed-off-by: Hui Wang --- src/modules/module-stream-restore.c | 10 ++ src/pulsecore/sink-input.c | 14 ++ src/pulsecore/sink-input.h | 2 ++ 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/modules/module-stream-restore.c b/src/modules/module-stream-restore.c index a8c6a42c5..366f1a5a8 100644 --- a/src/modules/module-stream-restore.c +++ b/src/modules/module-stream-restore.c @@ -1953,18 +1953,12 @@ static void entry_apply(struct userdata *u, const char *name, struct entry *e) { preferred_sink is cleared as the user may have specifically removed the sink element from the rule. */ pa_xfree(si->preferred_sink); -si->preferred_sink = NULL; -/* This is cheating a bit. The sink input itself has not changed - but the rules governing its routing have, so we fire this event - such that other routing modules (e.g. module-device-manager) - will pick up the change and reapply their routing */ -pa_subscription_post(si->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, si->index); +pa_sink_input_set_preferred_sink(si, NULL); } } else if ((s = pa_namereg_get(u->core, e->device, PA_NAMEREG_SINK))) { pa_log_info("Restoring device for stream %s.", name); -pa_sink_input_move_to(si, s, true); pa_xfree(si->preferred_sink); -si->preferred_sink = pa_xstrdup(s->name); +pa_sink_input_set_preferred_sink(si, s); } } } diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index f41eacf07..4dbc0cdef 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -2416,3 +2416,17 @@ void pa_sink_input_set_reference_ratio(pa_sink_input *i, const pa_cvolume *ratio pa_cvolume_snprint_verbose(old_ratio_str, sizeof(old_ratio_str), &old_ratio, &i->channel_map, true), pa_cvolume_snprint_verbose(new_ratio_str, sizeof(new_ratio_str), ratio, &i->channel_map, true)); } + +/* Called from the main thread. */ +void pa_sink_input_set_preferred_sink(pa_sink_input *i, pa_sink *s) { +pa_assert(i); + +if (s) { +i->preferred_sink = pa_xstrdup(s->name); +pa_sink_input_move_to(i, s, true); +} else { +i->preferred_sink = NULL; +pa_sink_input_move_to(i, i->core->default_sink, true); +} +pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index); +} diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h index 76140a2db..b67d3c1c3 100644 --- a/src/pulsecore/sink-input.h +++ b/src/pulsecore/sink-input.h @@ -460,6 +460,8 @@ void pa_sink_input_set_volume_direct(pa_sink_input *i, const pa_cvolume *volume) * i->reference_ratio and logs a message if the value changes. */ void pa_sink_input_set_reference_ratio(pa_sink_input *i, const pa_cvolume *ratio); +void pa_sink_input_set_preferred_sink(pa_sink_input *i, pa_sink *s); + #define pa_sink_input_assert_io_context(s) \ pa_assert(pa_thread_mq_get() || !PA_SINK_INPUT_IS_LINKED((s)->state)) -- 2.17.1 ___ pulseaudio-discuss mailing list pulseaudio-discuss@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
[pulseaudio-discuss] [PATCH v2 1/8] sink-input: change bool save_sink to char *preferred_sink
The finial objective is to store the preferred sink name in the sink-input struct, and use module-stream-restore to save and restore it. This patch just replaces the save_sink with preferred_sink, and tries to keep the original logic. Signed-off-by: Hui Wang --- src/modules/module-device-manager.c| 8 src/modules/module-intended-roles.c| 2 +- src/modules/module-stream-restore.c| 15 +-- src/modules/module-switch-on-connect.c | 2 +- src/pulsecore/sink-input.c | 24 +++- src/pulsecore/sink-input.h | 17 - 6 files changed, 46 insertions(+), 22 deletions(-) diff --git a/src/modules/module-device-manager.c b/src/modules/module-device-manager.c index 15fd2..cba3a4ebc 100644 --- a/src/modules/module-device-manager.c +++ b/src/modules/module-device-manager.c @@ -656,14 +656,14 @@ static void route_sink_input(struct userdata *u, pa_sink_input *si) { pa_assert(u); pa_assert(u->do_routing); -/* Don't override user or application routing requests. */ -if (si->save_sink || si->sink_requested_by_application) -return; - /* Skip this if it is already in the process of being moved anyway */ if (!si->sink) return; +/* Don't override user or application routing requests. */ +if (pa_safe_streq(si->sink->name, si->preferred_sink) || si->sink_requested_by_application) +return; + auto_filtered_prop = pa_proplist_gets(si->proplist, "module-device-manager.auto_filtered"); if (auto_filtered_prop) auto_filtered = (pa_parse_boolean(auto_filtered_prop) == 1); diff --git a/src/modules/module-intended-roles.c b/src/modules/module-intended-roles.c index adee51c20..5596faf1f 100644 --- a/src/modules/module-intended-roles.c +++ b/src/modules/module-intended-roles.c @@ -175,7 +175,7 @@ static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, struct if (si->sink == sink) continue; -if (si->save_sink) +if (pa_safe_streq(si->sink->name, si->preferred_sink)) continue; /* Skip this if it is already in the process of being moved diff --git a/src/modules/module-stream-restore.c b/src/modules/module-stream-restore.c index 6c7b4c75b..a8c6a42c5 100644 --- a/src/modules/module-stream-restore.c +++ b/src/modules/module-stream-restore.c @@ -1311,9 +1311,9 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint3 mute_updated = !created_new_entry && (!old->muted_valid || entry->muted != old->muted); } -if (sink_input->save_sink) { +if (sink_input->preferred_sink != NULL) { pa_xfree(entry->device); -entry->device = pa_xstrdup(sink_input->sink->name); +entry->device = pa_xstrdup(sink_input->preferred_sink); entry->device_valid = true; device_updated = !created_new_entry && (!old->device_valid || !pa_streq(entry->device, old->device)); @@ -1646,7 +1646,7 @@ static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, struct if (si->sink == sink) continue; -if (si->save_sink) +if (pa_safe_streq(si->sink->name, si->preferred_sink)) continue; /* Skip this if it is already in the process of being moved @@ -1947,12 +1947,13 @@ static void entry_apply(struct userdata *u, const char *name, struct entry *e) { if (u->restore_device) { if (!e->device_valid) { -if (si->save_sink) { +if (si->preferred_sink != NULL) { pa_log_info("Ensuring device is not saved for stream %s.", name); /* If the device is not valid we should make sure the - save flag is cleared as the user may have specifically + preferred_sink is cleared as the user may have specifically removed the sink element from the rule. */ -si->save_sink = false; +pa_xfree(si->preferred_sink); +si->preferred_sink = NULL; /* This is cheating a bit. The sink input itself has not changed but the rules governing its routing have, so we fire this event such that other routing modules (e.g. module-device-manager) @@ -1962,6 +1963,8 @@ static void entry_apply(struct userdata *u, const char *name, struct entry *e) { } else if ((s = pa_namereg_get(u->core, e->device, PA_NAMEREG_SINK))) { pa_log_info("Restoring device for stream %s.", name); pa_sink_input_move_to(si, s, true); +pa_xfree(si->pref
[pulseaudio-discuss] [PATCH v2 4/8] core: move sink-inputs conditionally when update default_sink
When the default sink changes, the streams from the old default sink should be moved to the new default sink, unless the preferred_sink string is set to the old default sink and the active port of the old default sink is not unavailable Signed-off-by: Hui Wang --- src/modules/dbus/iface-core.c | 2 +- src/modules/module-default-device-restore.c | 2 +- src/modules/module-switch-on-connect.c | 27 ++-- src/pulsecore/cli-command.c | 2 +- src/pulsecore/core.c| 10 -- src/pulsecore/core.h| 4 +-- src/pulsecore/device-port.c | 2 +- src/pulsecore/protocol-native.c | 2 +- src/pulsecore/sink.c| 35 +++-- src/pulsecore/sink.h| 6 10 files changed, 54 insertions(+), 38 deletions(-) diff --git a/src/modules/dbus/iface-core.c b/src/modules/dbus/iface-core.c index 5229c0467..9763480d2 100644 --- a/src/modules/dbus/iface-core.c +++ b/src/modules/dbus/iface-core.c @@ -721,7 +721,7 @@ static void handle_set_fallback_sink(DBusConnection *conn, DBusMessage *msg, DBu return; } -pa_core_set_configured_default_sink(c->core, pa_dbusiface_device_get_sink(fallback_sink)->name); +pa_core_set_configured_default_sink(c->core, pa_dbusiface_device_get_sink(fallback_sink)->name, true); pa_dbus_send_empty_reply(conn, msg); } diff --git a/src/modules/module-default-device-restore.c b/src/modules/module-default-device-restore.c index c4dbad99f..33e74c071 100644 --- a/src/modules/module-default-device-restore.c +++ b/src/modules/module-default-device-restore.c @@ -69,7 +69,7 @@ static void load(struct userdata *u) { pa_log_warn("Invalid sink name: %s", ln); else { pa_log_info("Restoring default sink '%s'.", ln); -pa_core_set_configured_default_sink(u->core, ln); +pa_core_set_configured_default_sink(u->core, ln, false); } } else if (errno != ENOENT) diff --git a/src/modules/module-switch-on-connect.c b/src/modules/module-switch-on-connect.c index f0cb29a7c..3ceac8b4f 100644 --- a/src/modules/module-switch-on-connect.c +++ b/src/modules/module-switch-on-connect.c @@ -54,9 +54,6 @@ struct userdata { }; static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, void* userdata) { -pa_sink_input *i; -uint32_t idx; -pa_sink *old_default_sink; const char *s; struct userdata *u = userdata; @@ -88,7 +85,7 @@ static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, void* /* No default sink, nothing to move away, just set the new default */ if (!c->default_sink) { -pa_core_set_configured_default_sink(c, sink->name); +pa_core_set_configured_default_sink(c, sink->name, false); return PA_HOOK_OK; } @@ -103,28 +100,8 @@ static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, void* return PA_HOOK_OK; } -old_default_sink = c->default_sink; - /* Actually do the switch to the new sink */ -pa_core_set_configured_default_sink(c, sink->name); - -/* Now move all old inputs over */ -if (pa_idxset_size(old_default_sink->inputs) <= 0) { -pa_log_debug("No sink inputs to move away."); -return PA_HOOK_OK; -} - -PA_IDXSET_FOREACH(i, old_default_sink->inputs, idx) { -if (pa_safe_streq(i->sink->name, i->preferred_sink) || !PA_SINK_INPUT_IS_LINKED(i->state)) -continue; - -if (pa_sink_input_move_to(i, sink, false) < 0) -pa_log_info("Failed to move sink input %u \"%s\" to %s.", i->index, -pa_strnull(pa_proplist_gets(i->proplist, PA_PROP_APPLICATION_NAME)), sink->name); -else -pa_log_info("Successfully moved sink input %u \"%s\" to %s.", i->index, -pa_strnull(pa_proplist_gets(i->proplist, PA_PROP_APPLICATION_NAME)), sink->name); -} +pa_core_set_configured_default_sink(c, sink->name, false); return PA_HOOK_OK; } diff --git a/src/pulsecore/cli-command.c b/src/pulsecore/cli-command.c index 5205349bd..cc7addaa1 100644 --- a/src/pulsecore/cli-command.c +++ b/src/pulsecore/cli-command.c @@ -1036,7 +1036,7 @@ static int pa_cli_command_sink_default(pa_core *c, pa_tokenizer *t, pa_strbuf *b } if ((s = pa_namereg_get(c, n, PA_NAMEREG_SINK))) -pa_core_set_configured_default_sink(c, s->name); +pa_core_set_configured_default_sink(c, s->name, true); else pa_strbuf_printf(buf, "Sink %s does not exist.\n", n); diff --git a/src/pulsecore/core.c b/src/pulsecore/core.c index cc4a6f38b..084a9f54b 100644 --- a/src/pulsecore/core.c +++ b/src/pulsec
[pulseaudio-discuss] [PATCH v2 3/8] sink-input: clear the preferred_sink if it is default_sink
When the user moves a stream to the current default sink, the preferred_sink should be set to NULL and module-stream-restore should clear the routing for that stream in the stream database. From that point on the stream will be always routed to the default sink. Signed-off-by: Hui Wang --- src/modules/module-stream-restore.c | 19 ++- src/pulsecore/sink-input.c | 6 +- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/modules/module-stream-restore.c b/src/modules/module-stream-restore.c index 366f1a5a8..142d1e3b4 100644 --- a/src/modules/module-stream-restore.c +++ b/src/modules/module-stream-restore.c @@ -1311,13 +1311,22 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint3 mute_updated = !created_new_entry && (!old->muted_valid || entry->muted != old->muted); } -if (sink_input->preferred_sink != NULL) { +if (sink_input->preferred_sink != NULL || !created_new_entry) { pa_xfree(entry->device); -entry->device = pa_xstrdup(sink_input->preferred_sink); -entry->device_valid = true; +if (sink_input->preferred_sink != NULL) { +entry->device = pa_xstrdup(sink_input->preferred_sink); +entry->device_valid = true; +} else { +entry->device = NULL; +entry->device_valid = false; +} -device_updated = !created_new_entry && (!old->device_valid || !pa_streq(entry->device, old->device)); -if (sink_input->sink->card) { +device_updated = !created_new_entry && !pa_safe_streq(entry->device, old->device); +if (entry->device_valid == false) { +pa_xfree(entry->card); +entry->card = NULL; +entry->card_valid = false; +} else { pa_xfree(entry->card); entry->card = pa_xstrdup(sink_input->sink->card->name); entry->card_valid = true; diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index 4dbc0cdef..f87c1f49f 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -1925,8 +1925,12 @@ int pa_sink_input_finish_move(pa_sink_input *i, pa_sink *dest, bool save) { save the preferred_sink */ if (save) { pa_xfree(i->preferred_sink); -i->preferred_sink = pa_xstrdup(dest->name); +if (dest == dest->core->default_sink) +i->preferred_sink = NULL; +else +i->preferred_sink = pa_xstrdup(dest->name); } + pa_idxset_put(dest->inputs, pa_sink_input_ref(i), NULL); PA_HASHMAP_FOREACH(v, i->volume_factor_sink_items, state) -- 2.17.1 ___ pulseaudio-discuss mailing list pulseaudio-discuss@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
[pulseaudio-discuss] [PATCH v2 5/8] sink: move streams to new appeared sinks if they prefer these sinks
When a new sink appears, all streams that have their preferred_sink set to the new sink should be moved to the new sink. Signed-off-by: Hui Wang --- src/modules/module-stream-restore.c | 53 - src/pulsecore/core.c| 28 +++ src/pulsecore/core.h| 2 ++ src/pulsecore/sink.c| 2 ++ 4 files changed, 32 insertions(+), 53 deletions(-) diff --git a/src/modules/module-stream-restore.c b/src/modules/module-stream-restore.c index 142d1e3b4..c7a5f228a 100644 --- a/src/modules/module-stream-restore.c +++ b/src/modules/module-stream-restore.c @@ -95,7 +95,6 @@ struct userdata { *sink_input_fixate_hook_slot, *source_output_new_hook_slot, *source_output_fixate_hook_slot, -*sink_put_hook_slot, *source_put_hook_slot, *sink_unlink_hook_slot, *source_unlink_hook_slot, @@ -1639,57 +1638,6 @@ static pa_hook_result_t source_output_fixate_hook_callback(pa_core *c, pa_source return PA_HOOK_OK; } -static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, struct userdata *u) { -pa_sink_input *si; -uint32_t idx; - -pa_assert(c); -pa_assert(sink); -pa_assert(u); -pa_assert(u->on_hotplug && u->restore_device); - -PA_IDXSET_FOREACH(si, c->sink_inputs, idx) { -char *name; -struct entry *e; - -if (si->sink == sink) -continue; - -if (pa_safe_streq(si->sink->name, si->preferred_sink)) -continue; - -/* Skip this if it is already in the process of being moved - * anyway */ -if (!si->sink) -continue; - -/* Skip this sink input if it is connecting a filter sink to - * the master */ -if (si->origin_sink) -continue; - -/* It might happen that a stream and a sink are set up at the - same time, in which case we want to make sure we don't - interfere with that */ -if (!PA_SINK_INPUT_IS_LINKED(si->state)) -continue; - -if (!(name = pa_proplist_get_stream_group(si->proplist, "sink-input", IDENTIFICATION_PROPERTY))) -continue; - -if ((e = entry_read(u, name))) { -if (e->device_valid && pa_streq(e->device, sink->name)) -pa_sink_input_move_to(si, sink, true); - -entry_free(e); -} - -pa_xfree(name); -} - -return PA_HOOK_OK; -} - static pa_hook_result_t source_put_hook_callback(pa_core *c, pa_source *source, struct userdata *u) { pa_source_output *so; uint32_t idx; @@ -2467,7 +2415,6 @@ int pa__init(pa_module*m) { if (restore_device && on_hotplug) { /* A little bit earlier than module-intended-roles ... */ -pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SINK_PUT], PA_HOOK_LATE, (pa_hook_cb_t) sink_put_hook_callback, u); pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SOURCE_PUT], PA_HOOK_LATE, (pa_hook_cb_t) source_put_hook_callback, u); } diff --git a/src/pulsecore/core.c b/src/pulsecore/core.c index 084a9f54b..a66f3212f 100644 --- a/src/pulsecore/core.c +++ b/src/pulsecore/core.c @@ -517,6 +517,34 @@ void pa_core_rttime_restart(pa_core *c, pa_time_event *e, pa_usec_t usec) { c->mainloop->time_restart(e, pa_timeval_rtstore(&tv, usec, true)); } +void pa_core_move_streams_to_newly_available_preferred_sink(pa_core *c, pa_sink *s) { +pa_sink_input *si; +uint32_t idx; + +pa_assert(c); +pa_assert(s); + +PA_IDXSET_FOREACH(si, c->sink_inputs, idx) { +if (si->sink == s) +continue; + +/* Skip this sink input if it is connecting a filter sink to + * the master */ +if (si->origin_sink) +continue; + +/* It might happen that a stream and a sink are set up at the + same time, in which case we want to make sure we don't + interfere with that */ +if (!PA_SINK_INPUT_IS_LINKED(si->state)) +continue; + +if (pa_safe_streq(si->preferred_sink, s->name)) +pa_sink_input_move_to(si, s, false); +} + +} + /* Helper macro to reduce repetition in pa_suspend_cause_to_string(). * Parameters: * char *p: the current position in the write buffer diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h index 82573f001..b61124854 100644 --- a/src/pulsecore/core.h +++ b/src/pulsecore/core.h @@ -278,4 +278,6 @@ static const size_t PA_SUSPEND_CAUSE_TO_STRING_BUF_SIZE = * provided buffer. The same buffer is the return value of this function. */ const char *pa_suspend_cause_to_string(pa_suspend_cause_t cause, char buf[PA_SUSPEND_CAUSE_TO_STRING_BUF_SIZE]); +void pa_core_move_streams_to_newly_available_preferred_sink(pa_core *c, pa_sink *s); + #endif dif
[pulseaudio-discuss] [PATCH v2 6/8] device-port: moving streams due to changing the status of active_port
When the active port of a sink becomes unavailable, all streams from that sink should be moved to the default sink. When the active port of a sink changes state from unavailable, all streams that have their preferred_sink set to this sink should be moved to this sink. Signed-off-by: Hui Wang --- src/pulsecore/device-port.c | 30 ++ src/pulsecore/device-port.h | 2 ++ 2 files changed, 32 insertions(+) diff --git a/src/pulsecore/device-port.c b/src/pulsecore/device-port.c index 464c3f8a2..49de33b9e 100644 --- a/src/pulsecore/device-port.c +++ b/src/pulsecore/device-port.c @@ -92,6 +92,7 @@ void pa_device_port_set_available(pa_device_port *p, pa_available_t status) { * be created before port objects, and then p->card could be non-NULL for * the whole lifecycle of pa_device_port. */ if (p->card && p->card->linked) { +pa_sink *sink; /* A sink or source whose active port is unavailable can't be the * default sink/source, so port availability changes may affect the * default sink/source choice. */ @@ -102,6 +103,22 @@ void pa_device_port_set_available(pa_device_port *p, pa_available_t status) { pa_subscription_post(p->core, PA_SUBSCRIPTION_EVENT_CARD|PA_SUBSCRIPTION_EVENT_CHANGE, p->card->index); pa_hook_fire(&p->core->hooks[PA_CORE_HOOK_PORT_AVAILABLE_CHANGED], p); + +sink = pa_device_port_get_sink(p); +if (!sink) +return; +if (p != sink->active_port) +return; +switch (p->direction) { +case PA_DIRECTION_OUTPUT: +if (sink->active_port->available == PA_AVAILABLE_NO) +pa_sink_move_streams_to_default_sink(p->core, sink, false); +else + pa_core_move_streams_to_newly_available_preferred_sink(p->core, sink); +break; +case PA_DIRECTION_INPUT: +break; +} } } @@ -224,3 +241,16 @@ pa_device_port *pa_device_port_find_best(pa_hashmap *ports) return best; } + +pa_sink *pa_device_port_get_sink(pa_device_port *p) { +pa_sink *rs = NULL; +pa_sink *sink; +uint32_t state; + +PA_IDXSET_FOREACH(sink, p->card->sinks, state) + if (p == pa_hashmap_get(sink->ports, p->name)) { + rs = sink; + break; + } +return rs; +} diff --git a/src/pulsecore/device-port.h b/src/pulsecore/device-port.h index fbdce1aa0..41988e5bb 100644 --- a/src/pulsecore/device-port.h +++ b/src/pulsecore/device-port.h @@ -87,4 +87,6 @@ void pa_device_port_set_preferred_profile(pa_device_port *p, const char *new_pp) pa_device_port *pa_device_port_find_best(pa_hashmap *ports); +pa_sink *pa_device_port_get_sink(pa_device_port *p); + #endif -- 2.17.1 ___ pulseaudio-discuss mailing list pulseaudio-discuss@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
[pulseaudio-discuss] [PATCH v2 8/8] stream-restore: skip entries setting action from gnome-control-center
When users select an output device from gnome-control-center UI, the sink of this output device will be set to the configured_default_sink and the default_sink, these actions are expected, but after these actions, the gnome-control-center will call extension_cb() to modify the entries in the database, let all stream entries to bind the sink users select, this is not correct since the sink is default_sink now. This is a temp fix for this issue, after gnome-control-center fixes this problem, this patch should be reverted. Signed-off-by: Hui Wang --- src/modules/module-stream-restore.c | 14 -- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/modules/module-stream-restore.c b/src/modules/module-stream-restore.c index fd3acb5bd..b2691d384 100644 --- a/src/modules/module-stream-restore.c +++ b/src/modules/module-stream-restore.c @@ -2053,7 +2053,7 @@ static int extension_cb(pa_native_protocol *p, pa_module *m, pa_native_connectio } while (!pa_tagstruct_eof(t)) { -const char *name, *device; +const char *name, *device, *client_name; bool muted; struct entry *entry; #ifdef HAVE_DBUS @@ -2094,7 +2094,17 @@ static int extension_cb(pa_native_protocol *p, pa_module *m, pa_native_connectio entry_free(entry); goto fail; } - +/* When users select an output device from gnome-control-center UI, the gnome-control-center will change all entries + * in the database to bind the sink of this output device, this is not correct since at this moment, the sink is + * default_sink and we shouldn't bind a stream to default_sink via preferred_sink or database. + * After gnome-control-center fix the issue, let us remove this code */ +client_name = pa_strnull(pa_proplist_gets(pa_native_connection_get_client(c)->proplist, PA_PROP_APPLICATION_PROCESS_BINARY)); +if (pa_safe_streq(client_name, "gnome-control-center")) { +if (entry->device_valid && m->core->default_sink && pa_safe_streq(device, m->core->default_sink->name)) { +entry_free(entry); +goto fail; +} +} #ifdef HAVE_DBUS old = entry_read(u, name); #endif -- 2.17.1 ___ pulseaudio-discuss mailing list pulseaudio-discuss@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
[pulseaudio-discuss] [PATCH v2 7/8] sink: move the streams to the default_sink when the sink is unlinked
When a sink is unlinked, all streams of this sink are moved to default_sink, this action is implemented in the core rather than modules now. Signed-off-by: Hui Wang --- src/modules/module-stream-restore.c | 50 - src/pulsecore/sink.c| 3 ++ 2 files changed, 3 insertions(+), 50 deletions(-) diff --git a/src/modules/module-stream-restore.c b/src/modules/module-stream-restore.c index c7a5f228a..fd3acb5bd 100644 --- a/src/modules/module-stream-restore.c +++ b/src/modules/module-stream-restore.c @@ -96,7 +96,6 @@ struct userdata { *source_output_new_hook_slot, *source_output_fixate_hook_slot, *source_put_hook_slot, -*sink_unlink_hook_slot, *source_unlink_hook_slot, *connection_unlink_hook_slot; pa_time_event *save_time_event; @@ -1691,54 +1690,6 @@ static pa_hook_result_t source_put_hook_callback(pa_core *c, pa_source *source, return PA_HOOK_OK; } -static pa_hook_result_t sink_unlink_hook_callback(pa_core *c, pa_sink *sink, struct userdata *u) { -pa_sink_input *si; -uint32_t idx; - -pa_assert(c); -pa_assert(sink); -pa_assert(u); -pa_assert(u->on_rescue && u->restore_device); - -/* There's no point in doing anything if the core is shut down anyway */ -if (c->state == PA_CORE_SHUTDOWN) -return PA_HOOK_OK; - -PA_IDXSET_FOREACH(si, sink->inputs, idx) { -char *name; -struct entry *e; - -if (!si->sink) -continue; - -/* Skip this sink input if it is connecting a filter sink to - * the master */ -if (si->origin_sink) -continue; - -if (!(name = pa_proplist_get_stream_group(si->proplist, "sink-input", IDENTIFICATION_PROPERTY))) -continue; - -if ((e = entry_read(u, name))) { - -if (e->device_valid) { -pa_sink *d; - -if ((d = pa_namereg_get(c, e->device, PA_NAMEREG_SINK)) && -d != sink && -PA_SINK_IS_LINKED(d->state)) -pa_sink_input_move_to(si, d, true); -} - -entry_free(e); -} - -pa_xfree(name); -} - -return PA_HOOK_OK; -} - static pa_hook_result_t source_unlink_hook_callback(pa_core *c, pa_source *source, struct userdata *u) { pa_source_output *so; uint32_t idx; @@ -2420,7 +2371,6 @@ int pa__init(pa_module*m) { if (restore_device && on_rescue) { /* A little bit earlier than module-intended-roles, module-rescue-streams, ... */ -pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SINK_UNLINK], PA_HOOK_LATE, (pa_hook_cb_t) sink_unlink_hook_callback, u); pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK], PA_HOOK_LATE, (pa_hook_cb_t) source_unlink_hook_callback, u); } diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index cf43a78e8..d7973b7c9 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -745,6 +745,9 @@ void pa_sink_unlink(pa_sink* s) { linked = PA_SINK_IS_LINKED(s->state); +if (linked) +pa_sink_move_streams_to_default_sink(s->core, s, false); + if (linked) pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_UNLINK], s); -- 2.17.1 ___ pulseaudio-discuss mailing list pulseaudio-discuss@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
Re: [pulseaudio-discuss] [alsa-devel] [PATCH] ALSA: hda: set the 2nd headphone's name to be Headphone2
On 2019/3/6 下午4:10, Jaroslav Kysela wrote: > Dne 06. 03. 19 v 1:23 Hui Wang napsal(a): >> On 2019/3/6 上午4:00, Jaroslav Kysela wrote: >>> Dne 05. 03. 19 v 15:09 Hui Wang napsal(a): >>>> Recently I saw two Headphones on some HP machines, the 1st Headphone >>>> comes from the Front Headphone Jack, the 2nd one comes from the Front >>>> Headset Jack, and the current HDA driver will set the same name to >>>> them and with different index, just like below: >>>> 'Headphone Playback Volume' >>>> 'Headphone Playback Switch' >>>> 'Headphone Playback Volume' index 1 >>>> 'Headphone Playback Switch' index 1 >>>> 'Front Headphone Jack' >>>> 'Front Headphone Jack' index 1 >>>> >>>> This can't be handled by pulseaudio, and pulseaduio already has a >>>> path analog-output-headphones-2.conf to handle the 2nd headphone, now >>>> we set the 2nd headphone's name to "Headphone2", leave the other >>>> headphones unchanged. >>>> >>>> The change of hda_auto_parser.c will change the name of Jack. >>>> >>>> The change of hda_generic.c will change the name of Volume and Switch. >>> NAK. I'm afraid, but you're trying to revert the change from 2009: >>> >>> commit 668b9652be33510a2a42b290dd335d34d38e2068 >>> Author: Takashi Iwai >>> Date: Fri Mar 6 10:13:24 2009 +0100 >>> >>> ALSA: hda - Create multiple HP / speaker controls with index >>> >>> Create multiple "Headphone" and "Speaker" controls with non-zero index >>> numbers instead of "Headphone2", etc. >>> >>> Signed-off-by: Takashi Iwai >>> >>> I think that PA should be fixed instead try to fix the drivers. The >>> indexes are exactly designed to distinguish the multiple similar I/O. >>> >>> I cannot find any other driver which uses the Headphone2 control name. >>> >>> Jaroslav >>> >> OK, got it. I tried to add the index to the pulseaudio in Jan, but not >> finish yet. If you have time, please take a look at my patches and make >> a comment on them. >> >> https://lists.freedesktop.org/archives/pulseaudio-discuss/2019-January/030761.html > Your changes seem as a good start. Unfortunately, I don't know PA > internals, so it would be better, if a PA developer can review those > patches. > > Jaroslav OK, Thanks. ___ pulseaudio-discuss mailing list pulseaudio-discuss@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
Re: [pulseaudio-discuss] [PATCH 1/3] alsa: fix infinite loop with Intel HDMI LPE
On 2017/12/28 下午6:09, Tanu Kaskinen wrote: > The Intel HDMI LPE driver works in a peculiar way when the HDMI cable is > not plugged in: any written audio is immediately discarded and underrun > is reported. That resulted in an infinite loop, because PulseAudio tried > to keep the buffer filled, which was futile since the written audio was > immediately consumed/discarded. > > This patch adds special handling for the LPE driver: if the active port > of the sink is unavailable, the sink suspends itself. A new suspend > cause is added: PA_SUSPEND_UNAVAILABLE. > > BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=100488 > --- > src/modules/alsa/alsa-mixer.h | 1 + > src/modules/alsa/alsa-sink.c| 22 ++ > src/modules/alsa/module-alsa-card.c | 34 ++ > src/pulsecore/core.h| 1 + > 4 files changed, 58 insertions(+) > > diff --git a/src/modules/alsa/alsa-mixer.h b/src/modules/alsa/alsa-mixer.h > index 4ebf1922b..3577f435f 100644 > --- a/src/modules/alsa/alsa-mixer.h > +++ b/src/modules/alsa/alsa-mixer.h > @@ -364,6 +364,7 @@ int pa_alsa_set_mixer_rtpoll(struct pa_alsa_mixer_pdata > *pd, snd_mixer_t *mixer, > struct pa_alsa_port_data { > pa_alsa_path *path; > pa_alsa_setting *setting; > +bool suspend_when_unavailable; > }; > > void pa_alsa_add_ports(void *sink_or_source_new_data, pa_alsa_path_set *ps, > pa_card *card); > diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c > index 7936cfaca..a80caab2e 100644 > --- a/src/modules/alsa/alsa-sink.c > +++ b/src/modules/alsa/alsa-sink.c > @@ -1527,6 +1527,11 @@ static int sink_set_port_cb(pa_sink *s, pa_device_port > *p) { > s->set_volume(s); > } > > +if (data->suspend_when_unavailable && p->available == PA_AVAILABLE_NO) > +pa_sink_suspend(s, true, PA_SUSPEND_UNAVAILABLE); > +else Hi Tanu, We tried to backport this patch to pulseaudio-8.0 (for ubuntu linux 16.04), but after applying this patch, all audio jacks (like headphone, line-in/line-out) can't work anymore. If we change the above line as below, the problem will disappear. else (data->suspend_when_unavailable) In theory, if a port is not set suspend_when_unavailable, the port should not be changed by this patch. I don't know if it is correct or not, could you please take a look at it? Thanks, Hui. > +pa_sink_suspend(s, false, PA_SUSPEND_UNAVAILABLE); > + > return 0; > } > > @@ -2460,6 +2465,23 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs > *ma, const char*driver, pa_ca > if (profile_set) > pa_alsa_profile_set_free(profile_set); > > +/* Suspend if necessary. FIXME: It would be better to start suspended, > but > + * that would require some core changes. It's possible to set > + * pa_sink_new_data.suspend_cause, but that has to be done before the > + * pa_sink_new() call, and we know if we need to suspend only after the > + * pa_sink_new() call when the initial port has been chosen. Calling > + * pa_sink_suspend() between pa_sink_new() and pa_sink_put() would > + * otherwise work, but currently pa_sink_suspend() will crash if > + * pa_sink_put() hasn't been called. */ > +if (u->sink->active_port) { > +pa_alsa_port_data *port_data; > + > +port_data = PA_DEVICE_PORT_DATA(u->sink->active_port); > + > +if (port_data->suspend_when_unavailable && > u->sink->active_port->available == PA_AVAILABLE_NO) > +pa_sink_suspend(u->sink, true, PA_SUSPEND_UNAVAILABLE); > +} > + > return u->sink; > > fail: > diff --git a/src/modules/alsa/module-alsa-card.c > b/src/modules/alsa/module-alsa-card.c > index 804b4f872..b193d40cc 100644 > --- a/src/modules/alsa/module-alsa-card.c > +++ b/src/modules/alsa/module-alsa-card.c > @@ -426,6 +426,22 @@ static int report_jack_state(snd_mixer_elem_t *melem, > unsigned int mask) { > if (tp->avail == PA_AVAILABLE_NO) > pa_device_port_set_available(tp->port, tp->avail); > > +for (tp = tports; tp->port; tp++) { > +pa_alsa_port_data *data; > +pa_sink *sink; > +uint32_t idx; > + > +data = PA_DEVICE_PORT_DATA(tp->port); > + > +if (!data->suspend_when_unavailable) > +continue; > + > +PA_IDXSET_FOREACH(sink, u->core->sinks, idx) { > +if (sink->active_port == tp->port) > +pa_sink_suspend(sink, tp->avail == PA_AVAILABLE_NO, > PA_SUSPEND_UNAVAILABLE); > +} > +} > + > /* Update profile availabilities. The logic could be improved; for now we > * only set obviously unavailable profiles (those that contain only > * unavailable ports) to PA_AVAILABLE_NO and all others to > @@ -836,6 +852,24 @@ int pa__init(pa_module *m) { > goto fail; > } > > +/* The Intel HDMI LPE driver needs some special handling. When the HDMI > + * cable is not plugged in, tryi
Re: [pulseaudio-discuss] [PATCH 1/3] alsa: fix infinite loop with Intel HDMI LPE
On 2019/3/27 上午1:44, Tanu Kaskinen wrote: > On Tue, 2019-03-26 at 13:17 +0800, Hui Wang wrote: >> On 2017/12/28 下午6:09, Tanu Kaskinen wrote: >>> The Intel HDMI LPE driver works in a peculiar way when the HDMI cable is >>> not plugged in: any written audio is immediately discarded and underrun >>> is reported. That resulted in an infinite loop, because PulseAudio tried >>> to keep the buffer filled, which was futile since the written audio was >>> immediately consumed/discarded. >>> >>> This patch adds special handling for the LPE driver: if the active port >>> of the sink is unavailable, the sink suspends itself. A new suspend >>> cause is added: PA_SUSPEND_UNAVAILABLE. >>> >>> BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=100488 >>> --- >>> src/modules/alsa/alsa-mixer.h | 1 + >>> src/modules/alsa/alsa-sink.c| 22 ++ >>> src/modules/alsa/module-alsa-card.c | 34 ++ >>> src/pulsecore/core.h| 1 + >>> 4 files changed, 58 insertions(+) >>> >>> diff --git a/src/modules/alsa/alsa-mixer.h b/src/modules/alsa/alsa-mixer.h >>> index 4ebf1922b..3577f435f 100644 >>> --- a/src/modules/alsa/alsa-mixer.h >>> +++ b/src/modules/alsa/alsa-mixer.h >>> @@ -364,6 +364,7 @@ int pa_alsa_set_mixer_rtpoll(struct pa_alsa_mixer_pdata >>> *pd, snd_mixer_t *mixer, >>> struct pa_alsa_port_data { >>> pa_alsa_path *path; >>> pa_alsa_setting *setting; >>> +bool suspend_when_unavailable; >>> }; >>> >>> void pa_alsa_add_ports(void *sink_or_source_new_data, pa_alsa_path_set >>> *ps, pa_card *card); >>> diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c >>> index 7936cfaca..a80caab2e 100644 >>> --- a/src/modules/alsa/alsa-sink.c >>> +++ b/src/modules/alsa/alsa-sink.c >>> @@ -1527,6 +1527,11 @@ static int sink_set_port_cb(pa_sink *s, >>> pa_device_port *p) { >>> s->set_volume(s); >>> } >>> >>> +if (data->suspend_when_unavailable && p->available == PA_AVAILABLE_NO) >>> +pa_sink_suspend(s, true, PA_SUSPEND_UNAVAILABLE); >>> +else >> Hi Tanu, >> >> We tried to backport this patch to pulseaudio-8.0 (for ubuntu linux >> 16.04), but after applying this patch, all audio jacks (like headphone, >> line-in/line-out) can't work anymore. If we change the above line as >> below, the problem will disappear. >> >> else (data->suspend_when_unavailable) >> >> In theory, if a port is not set suspend_when_unavailable, the port >> should not be changed by this patch. I don't know if it is correct or >> not, could you please take a look at it? > I don't think your change is correct. This code is run when the sink > changes its port, so there are two ports involved: the old port and the > new one. If the old port caused the sink to be suspended with the > UNAVAILABLE cause, and the new port doesn't require suspending when > it's unavailable, then with your change the sink doesn't get > unsuspended when it should. > > In practice your change should be harmless, though, because all ports > on a Intel HDMI LPE card will have the suspend_when_unavailable flag > set, and on other cards the flag is never set. > > You didn't specify what the exact problem with headphones etc. is. Is > there an assertion error? I would guess that you're running into this > bug that was introduced by the HDMI LPE fixes: > https://bugs.freedesktop.org/show_bug.cgi?id=104761 > > Fixing that bug involved rewriting much of the device suspending and > state changing code. I don't know if you want to backport those patches > if your small change seems to make things work well enough, but here's > a list of relevant commits (oldest first, I'm not 100% that this is a > complete list): > > 3da0de5418b29c90974d0d3e2198c471c39d229f > 6ed37aeef28708f8da34a16c7035fa1331fa13cb > d6e39b5e891c767dd42c369d9f118560b8bb24ae > 7f201b1fd419b91a226d23ee1e216661ae082dcf > 2dff0d6a6a4df2aab6f36212b705489d5af42835 > 7f09164ed7979210adcdb7674b9d6217fd44ed66 > f6fe411b32c0cf5932fb4f169f5288c76bc6923d > 0fad369ceb18a8e275e8f74f10f784e0d7476dfb > 73b8a57078b94033edf84de2fc0cfbe344c10dcd > b2537a8f38ad71e4dee57263310235abdf2b95a4 > ad0616d4c91de52b7cb69e6222efe96961755482 > ad15e6e50e737fb55a87bb7def22332f774abce9 Ok, got it. I will investigate these commits. Thanks, Hui. ___ pulseaudio-discuss mailing list pulseaudio-discuss@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
[pulseaudio-discuss] [PATCH] stream-restore: Don't restore if the active_port is PA_AVAILABLE_NO
We met two problems recently, one happened on a Lenovo machine with dual analogue codecs, the other happened on a Dell machine with a digital mic directly connected to PCH. The two problems are basically same, there is an internal mic and an external mic, the internal mic always shows up in the gnome-control-center, the external mic only shows up when it is plugged. After the external mic is plugged and users select it from gnome-control-center, the gnome-control-center will read all saved streams through extension_cb, and bind the source of external mic to all streams, after that the apps only record sound via the source of external mic, after the external mic is unplugged, the internal mic will automatically be selected since it is the only left input device in the gnome-control-center, since users don't select it, all streams are still bond the source of external mic. When users record sound via apps, they can't record any sound even the default_source is the source of internal mic and the internal mic is selected in the UI. It is very common that a machine has internal mic and external mic, but this problem didn't expose before, that is because both internal mic and external mic belong to one source, but for those two machines, the internal mic belongs to one source, while the external mic belongs to another source (they are in differnt codecs or one is in the codec and the other is from PCH), To fix it with a mininal change, we just check if the active_port is PA_AVAILABLE_NO or not when building a new stream, if it is, don't restore the device to the new built stream, let pa_source_output_new() decide the source device for this stream. And we also do the same change to sink_input. This change only affects the new built streams, it will not change the database, so the users' preference is still saved in the database, after the active_port is not PA_AVAILABLE_NO, the new streams will still restore to the preferred device. Signed-off-by: Hui Wang --- src/modules/module-stream-restore.c | 12 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/modules/module-stream-restore.c b/src/modules/module-stream-restore.c index 6c7b4c75b..cbef4782d 100644 --- a/src/modules/module-stream-restore.c +++ b/src/modules/module-stream-restore.c @@ -1459,8 +1459,10 @@ static pa_hook_result_t sink_input_new_hook_callback(pa_core *c, pa_sink_input_n same time, in which case we want to make sure we don't interfere with that */ if (s && PA_SINK_IS_LINKED(s->state)) -if (pa_sink_input_new_data_set_sink(new_data, s, true, false)) -pa_log_info("Restoring device for stream %s.", name); +if (!s->active_port || s->active_port->available != PA_AVAILABLE_NO) { +if (pa_sink_input_new_data_set_sink(new_data, s, true, false)) +pa_log_info("Restoring device for stream %s.", name); + } entry_free(e); } @@ -1562,8 +1564,10 @@ static pa_hook_result_t source_output_new_hook_callback(pa_core *c, pa_source_ou same time, in which case we want to make sure we don't interfere with that */ if (s && PA_SOURCE_IS_LINKED(s->state)) { -pa_log_info("Restoring device for stream %s.", name); -pa_source_output_new_data_set_source(new_data, s, true, false); +if (!s->active_port || s->active_port->available != PA_AVAILABLE_NO) { +pa_log_info("Restoring device for stream %s.", name); +pa_source_output_new_data_set_source(new_data, s, true, false); + } } entry_free(e); -- 2.17.1 ___ pulseaudio-discuss mailing list pulseaudio-discuss@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
Re: [pulseaudio-discuss] [PATCH v2 2/8] sink-input: add a new API pa_sink_input_set_preferred_sink
On 2019/6/30 下午6:44, Georg Chini wrote: Sorry for the late feedback. On 17.01.19 07:53, Hui Wang wrote: If the sink here is NULL, that means users want to clear the preferred_sink and move the sink-input to the default_sink, otherwise set the preferred_sink to the sink->name and move the sink-input to the sink. After that fire the sink_input_change event. After adding this API, we can use this API to simplify the entry_apply in the module-stream-restore.c. Signed-off-by: Hui Wang --- src/modules/module-stream-restore.c | 10 ++ src/pulsecore/sink-input.c | 14 ++ src/pulsecore/sink-input.h | 2 ++ 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/modules/module-stream-restore.c b/src/modules/module-stream-restore.c index a8c6a42c5..366f1a5a8 100644 --- a/src/modules/module-stream-restore.c +++ b/src/modules/module-stream-restore.c @@ -1953,18 +1953,12 @@ static void entry_apply(struct userdata *u, const char *name, struct entry *e) { preferred_sink is cleared as the user may have specifically removed the sink element from the rule. */ pa_xfree(si->preferred_sink); - si->preferred_sink = NULL; - /* This is cheating a bit. The sink input itself has not changed - but the rules governing its routing have, so we fire this event - such that other routing modules (e.g. module-device-manager) - will pick up the change and reapply their routing */ - pa_subscription_post(si->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, si->index); + pa_sink_input_set_preferred_sink(si, NULL); } } else if ((s = pa_namereg_get(u->core, e->device, PA_NAMEREG_SINK))) { pa_log_info("Restoring device for stream %s.", name); - pa_sink_input_move_to(si, s, true); pa_xfree(si->preferred_sink); - si->preferred_sink = pa_xstrdup(s->name); + pa_sink_input_set_preferred_sink(si, s); } } } diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index f41eacf07..4dbc0cdef 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -2416,3 +2416,17 @@ void pa_sink_input_set_reference_ratio(pa_sink_input *i, const pa_cvolume *ratio pa_cvolume_snprint_verbose(old_ratio_str, sizeof(old_ratio_str), &old_ratio, &i->channel_map, true), pa_cvolume_snprint_verbose(new_ratio_str, sizeof(new_ratio_str), ratio, &i->channel_map, true)); } + +/* Called from the main thread. */ +void pa_sink_input_set_preferred_sink(pa_sink_input *i, pa_sink *s) { + pa_assert(i); + + if (s) { + i->preferred_sink = pa_xstrdup(s->name); + pa_sink_input_move_to(i, s, true); + } else { + i->preferred_sink = NULL; + pa_sink_input_move_to(i, i->core->default_sink, true); + } + pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index); +} You do not have to send the subscription event here, pa_sink_input_finish_move() will already send the event. OK, got it. Thanks, ___ pulseaudio-discuss mailing list pulseaudio-discuss@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
Re: [pulseaudio-discuss] [PATCH v2 3/8] sink-input: clear the preferred_sink if it is default_sink
On 2019/6/30 下午6:47, Georg Chini wrote: On 17.01.19 07:53, Hui Wang wrote: When the user moves a stream to the current default sink, the preferred_sink should be set to NULL and module-stream-restore should clear the routing for that stream in the stream database. From that point on the stream will be always routed to the default sink. Signed-off-by: Hui Wang --- src/modules/module-stream-restore.c | 19 ++- src/pulsecore/sink-input.c | 6 +- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/modules/module-stream-restore.c b/src/modules/module-stream-restore.c index 366f1a5a8..142d1e3b4 100644 --- a/src/modules/module-stream-restore.c +++ b/src/modules/module-stream-restore.c @@ -1311,13 +1311,22 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint3 mute_updated = !created_new_entry && (!old->muted_valid || entry->muted != old->muted); } - if (sink_input->preferred_sink != NULL) { + if (sink_input->preferred_sink != NULL || !created_new_entry) { pa_xfree(entry->device); - entry->device = pa_xstrdup(sink_input->preferred_sink); - entry->device_valid = true; + if (sink_input->preferred_sink != NULL) { + entry->device = pa_xstrdup(sink_input->preferred_sink); + entry->device_valid = true; + } else { + entry->device = NULL; + entry->device_valid = false; + } - device_updated = !created_new_entry && (!old->device_valid || !pa_streq(entry->device, old->device)); - if (sink_input->sink->card) { + device_updated = !created_new_entry && !pa_safe_streq(entry->device, old->device); + if (entry->device_valid == false) { + pa_xfree(entry->card); + entry->card = NULL; + entry->card_valid = false; + } else { pa_xfree(entry->card); entry->card = pa_xstrdup(sink_input->sink->card->name); entry->card_valid = true; You still need to check sink_input->sink->card. The virtual sinks don't have a card, so it may well be that the device is valid but there is no card. Ok, will add it. Thanks. ___ pulseaudio-discuss mailing list pulseaudio-discuss@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
Re: [pulseaudio-discuss] [PATCH v2 7/8] sink: move the streams to the default_sink when the sink is unlinked
On 2019/6/30 下午8:15, Georg Chini wrote: On 17.01.19 07:53, Hui Wang wrote: When a sink is unlinked, all streams of this sink are moved to default_sink, this action is implemented in the core rather than modules now. Signed-off-by: Hui Wang --- src/modules/module-stream-restore.c | 50 - src/pulsecore/sink.c | 3 ++ 2 files changed, 3 insertions(+), 50 deletions(-) diff --git a/src/modules/module-stream-restore.c b/src/modules/module-stream-restore.c index c7a5f228a..fd3acb5bd 100644 --- a/src/modules/module-stream-restore.c +++ b/src/modules/module-stream-restore.c @@ -96,7 +96,6 @@ struct userdata { *source_output_new_hook_slot, *source_output_fixate_hook_slot, *source_put_hook_slot, - *sink_unlink_hook_slot, *source_unlink_hook_slot, *connection_unlink_hook_slot; pa_time_event *save_time_event; @@ -1691,54 +1690,6 @@ static pa_hook_result_t source_put_hook_callback(pa_core *c, pa_source *source, return PA_HOOK_OK; } -static pa_hook_result_t sink_unlink_hook_callback(pa_core *c, pa_sink *sink, struct userdata *u) { - pa_sink_input *si; - uint32_t idx; - - pa_assert(c); - pa_assert(sink); - pa_assert(u); - pa_assert(u->on_rescue && u->restore_device); - - /* There's no point in doing anything if the core is shut down anyway */ - if (c->state == PA_CORE_SHUTDOWN) - return PA_HOOK_OK; - - PA_IDXSET_FOREACH(si, sink->inputs, idx) { - char *name; - struct entry *e; - - if (!si->sink) - continue; - - /* Skip this sink input if it is connecting a filter sink to - * the master */ - if (si->origin_sink) - continue; - - if (!(name = pa_proplist_get_stream_group(si->proplist, "sink-input", IDENTIFICATION_PROPERTY))) - continue; - - if ((e = entry_read(u, name))) { - - if (e->device_valid) { - pa_sink *d; - - if ((d = pa_namereg_get(c, e->device, PA_NAMEREG_SINK)) && - d != sink && - PA_SINK_IS_LINKED(d->state)) - pa_sink_input_move_to(si, d, true); - } - - entry_free(e); - } - - pa_xfree(name); - } - - return PA_HOOK_OK; -} - static pa_hook_result_t source_unlink_hook_callback(pa_core *c, pa_source *source, struct userdata *u) { pa_source_output *so; uint32_t idx; @@ -2420,7 +2371,6 @@ int pa__init(pa_module*m) { if (restore_device && on_rescue) { /* A little bit earlier than module-intended-roles, module-rescue-streams, ... */ - pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SINK_UNLINK], PA_HOOK_LATE, (pa_hook_cb_t) sink_unlink_hook_callback, u); pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK], PA_HOOK_LATE, (pa_hook_cb_t) source_unlink_hook_callback, u); } diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index cf43a78e8..d7973b7c9 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -745,6 +745,9 @@ void pa_sink_unlink(pa_sink* s) { linked = PA_SINK_IS_LINKED(s->state); + if (linked) + pa_sink_move_streams_to_default_sink(s->core, s, false); + This is called too early. It might be the current default sink that we are unlinking. Right, will move it after the: pa_core_update_default_sink(s->core); if (linked) pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_UNLINK], s); ___ pulseaudio-discuss mailing list pulseaudio-discuss@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
[pulseaudio-discuss] [PATCH v3 3/8] sink-input: clear the preferred_sink if it is default_sink
When the user moves a stream to the current default sink, the preferred_sink should be set to NULL and module-stream-restore should clear the routing for that stream in the stream database. From that point on the stream will be always routed to the default sink. Signed-off-by: Hui Wang --- src/modules/module-stream-restore.c | 19 ++- src/pulsecore/sink-input.c | 6 +- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/modules/module-stream-restore.c b/src/modules/module-stream-restore.c index c8bc02ecd..0d3f9d8ac 100644 --- a/src/modules/module-stream-restore.c +++ b/src/modules/module-stream-restore.c @@ -1311,13 +1311,22 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint3 mute_updated = !created_new_entry && (!old->muted_valid || entry->muted != old->muted); } -if (sink_input->preferred_sink != NULL) { +if (sink_input->preferred_sink != NULL || !created_new_entry) { pa_xfree(entry->device); -entry->device = pa_xstrdup(sink_input->preferred_sink); -entry->device_valid = true; +if (sink_input->preferred_sink != NULL) { +entry->device = pa_xstrdup(sink_input->preferred_sink); +entry->device_valid = true; +} else { +entry->device = NULL; +entry->device_valid = false; +} -device_updated = !created_new_entry && (!old->device_valid || !pa_streq(entry->device, old->device)); -if (sink_input->sink->card) { +device_updated = !created_new_entry && !pa_safe_streq(entry->device, old->device); +if (entry->device_valid == false) { +pa_xfree(entry->card); +entry->card = NULL; +entry->card_valid = false; +} else if (sink_input->sink->card) { pa_xfree(entry->card); entry->card = pa_xstrdup(sink_input->sink->card->name); entry->card_valid = true; diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index 7521bed08..ee3083041 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -1927,8 +1927,12 @@ int pa_sink_input_finish_move(pa_sink_input *i, pa_sink *dest, bool save) { save the preferred_sink */ if (save) { pa_xfree(i->preferred_sink); -i->preferred_sink = pa_xstrdup(dest->name); +if (dest == dest->core->default_sink) +i->preferred_sink = NULL; +else +i->preferred_sink = pa_xstrdup(dest->name); } + pa_idxset_put(dest->inputs, pa_sink_input_ref(i), NULL); PA_HASHMAP_FOREACH(v, i->volume_factor_sink_items, state) -- 2.17.1 ___ pulseaudio-discuss mailing list pulseaudio-discuss@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
[pulseaudio-discuss] [PATCH v3 5/8] sink: move streams to new appeared sinks if they prefer these sinks
When a new sink appears, all streams that have their preferred_sink set to the new sink should be moved to the new sink. Signed-off-by: Hui Wang --- src/modules/module-stream-restore.c | 53 - src/pulsecore/core.c| 28 +++ src/pulsecore/core.h| 2 ++ src/pulsecore/sink.c| 2 ++ 4 files changed, 32 insertions(+), 53 deletions(-) diff --git a/src/modules/module-stream-restore.c b/src/modules/module-stream-restore.c index 0d3f9d8ac..aa7bd38dc 100644 --- a/src/modules/module-stream-restore.c +++ b/src/modules/module-stream-restore.c @@ -95,7 +95,6 @@ struct userdata { *sink_input_fixate_hook_slot, *source_output_new_hook_slot, *source_output_fixate_hook_slot, -*sink_put_hook_slot, *source_put_hook_slot, *sink_unlink_hook_slot, *source_unlink_hook_slot, @@ -1643,57 +1642,6 @@ static pa_hook_result_t source_output_fixate_hook_callback(pa_core *c, pa_source return PA_HOOK_OK; } -static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, struct userdata *u) { -pa_sink_input *si; -uint32_t idx; - -pa_assert(c); -pa_assert(sink); -pa_assert(u); -pa_assert(u->on_hotplug && u->restore_device); - -PA_IDXSET_FOREACH(si, c->sink_inputs, idx) { -char *name; -struct entry *e; - -if (si->sink == sink) -continue; - -if (pa_safe_streq(si->sink->name, si->preferred_sink)) -continue; - -/* Skip this if it is already in the process of being moved - * anyway */ -if (!si->sink) -continue; - -/* Skip this sink input if it is connecting a filter sink to - * the master */ -if (si->origin_sink) -continue; - -/* It might happen that a stream and a sink are set up at the - same time, in which case we want to make sure we don't - interfere with that */ -if (!PA_SINK_INPUT_IS_LINKED(si->state)) -continue; - -if (!(name = pa_proplist_get_stream_group(si->proplist, "sink-input", IDENTIFICATION_PROPERTY))) -continue; - -if ((e = entry_read(u, name))) { -if (e->device_valid && pa_streq(e->device, sink->name)) -pa_sink_input_move_to(si, sink, true); - -entry_free(e); -} - -pa_xfree(name); -} - -return PA_HOOK_OK; -} - static pa_hook_result_t source_put_hook_callback(pa_core *c, pa_source *source, struct userdata *u) { pa_source_output *so; uint32_t idx; @@ -2471,7 +2419,6 @@ int pa__init(pa_module*m) { if (restore_device && on_hotplug) { /* A little bit earlier than module-intended-roles ... */ -pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SINK_PUT], PA_HOOK_LATE, (pa_hook_cb_t) sink_put_hook_callback, u); pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SOURCE_PUT], PA_HOOK_LATE, (pa_hook_cb_t) source_put_hook_callback, u); } diff --git a/src/pulsecore/core.c b/src/pulsecore/core.c index a112ff753..e761a9934 100644 --- a/src/pulsecore/core.c +++ b/src/pulsecore/core.c @@ -523,6 +523,34 @@ void pa_core_rttime_restart(pa_core *c, pa_time_event *e, pa_usec_t usec) { c->mainloop->time_restart(e, pa_timeval_rtstore(&tv, usec, true)); } +void pa_core_move_streams_to_newly_available_preferred_sink(pa_core *c, pa_sink *s) { +pa_sink_input *si; +uint32_t idx; + +pa_assert(c); +pa_assert(s); + +PA_IDXSET_FOREACH(si, c->sink_inputs, idx) { +if (si->sink == s) +continue; + +/* Skip this sink input if it is connecting a filter sink to + * the master */ +if (si->origin_sink) +continue; + +/* It might happen that a stream and a sink are set up at the + same time, in which case we want to make sure we don't + interfere with that */ +if (!PA_SINK_INPUT_IS_LINKED(si->state)) +continue; + +if (pa_safe_streq(si->preferred_sink, s->name)) +pa_sink_input_move_to(si, s, false); +} + +} + /* Helper macro to reduce repetition in pa_suspend_cause_to_string(). * Parameters: * char *p: the current position in the write buffer diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h index 04f11f8e9..255fae4ae 100644 --- a/src/pulsecore/core.h +++ b/src/pulsecore/core.h @@ -278,4 +278,6 @@ static const size_t PA_SUSPEND_CAUSE_TO_STRING_BUF_SIZE = * provided buffer. The same buffer is the return value of this function. */ const char *pa_suspend_cause_to_string(pa_suspend_cause_t cause, char buf[PA_SUSPEND_CAUSE_TO_STRING_BUF_SIZE]); +void pa_core_move_streams_to_newly_available_preferred_sink(pa_core *c, pa_sink *s); + #endif dif
[pulseaudio-discuss] [PATCH v3 6/8] device-port: moving streams due to changing the status of active_port
When the active port of a sink becomes unavailable, all streams from that sink should be moved to the default sink. When the active port of a sink changes state from unavailable, all streams that have their preferred_sink set to this sink should be moved to this sink. Signed-off-by: Hui Wang --- src/pulsecore/device-port.c | 30 ++ src/pulsecore/device-port.h | 2 ++ 2 files changed, 32 insertions(+) diff --git a/src/pulsecore/device-port.c b/src/pulsecore/device-port.c index 464c3f8a2..49de33b9e 100644 --- a/src/pulsecore/device-port.c +++ b/src/pulsecore/device-port.c @@ -92,6 +92,7 @@ void pa_device_port_set_available(pa_device_port *p, pa_available_t status) { * be created before port objects, and then p->card could be non-NULL for * the whole lifecycle of pa_device_port. */ if (p->card && p->card->linked) { +pa_sink *sink; /* A sink or source whose active port is unavailable can't be the * default sink/source, so port availability changes may affect the * default sink/source choice. */ @@ -102,6 +103,22 @@ void pa_device_port_set_available(pa_device_port *p, pa_available_t status) { pa_subscription_post(p->core, PA_SUBSCRIPTION_EVENT_CARD|PA_SUBSCRIPTION_EVENT_CHANGE, p->card->index); pa_hook_fire(&p->core->hooks[PA_CORE_HOOK_PORT_AVAILABLE_CHANGED], p); + +sink = pa_device_port_get_sink(p); +if (!sink) +return; +if (p != sink->active_port) +return; +switch (p->direction) { +case PA_DIRECTION_OUTPUT: +if (sink->active_port->available == PA_AVAILABLE_NO) +pa_sink_move_streams_to_default_sink(p->core, sink, false); +else + pa_core_move_streams_to_newly_available_preferred_sink(p->core, sink); +break; +case PA_DIRECTION_INPUT: +break; +} } } @@ -224,3 +241,16 @@ pa_device_port *pa_device_port_find_best(pa_hashmap *ports) return best; } + +pa_sink *pa_device_port_get_sink(pa_device_port *p) { +pa_sink *rs = NULL; +pa_sink *sink; +uint32_t state; + +PA_IDXSET_FOREACH(sink, p->card->sinks, state) + if (p == pa_hashmap_get(sink->ports, p->name)) { + rs = sink; + break; + } +return rs; +} diff --git a/src/pulsecore/device-port.h b/src/pulsecore/device-port.h index fbdce1aa0..41988e5bb 100644 --- a/src/pulsecore/device-port.h +++ b/src/pulsecore/device-port.h @@ -87,4 +87,6 @@ void pa_device_port_set_preferred_profile(pa_device_port *p, const char *new_pp) pa_device_port *pa_device_port_find_best(pa_hashmap *ports); +pa_sink *pa_device_port_get_sink(pa_device_port *p); + #endif -- 2.17.1 ___ pulseaudio-discuss mailing list pulseaudio-discuss@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
[pulseaudio-discuss] [PATCH v3 0/8] Change the bool sink_save to char *preferred_sink
In the V3, I addressed all Tanu's and Georg's comments: 0002-xxx.patch: remove the pa_subscription_post() in the pa_sink_input_set_preferred_sink() 0003-xxx.patch: Add the check of sink_input->sink->card in the subscribe_callback() 0004-xxx.patch: Initialize the varible old_sink_is_unavailable Add the check of core->default_sink == NULL || core->default_sink->unlink_requested in the pa_sink_move_streams_to_default_sink() 0007-xxx.patch: Move the calling of pa_sink_move_streams_to_default_sink() after the pa_core_update_default_sink() in the pa_sink_unlink() Add shutdown check in the pa_sink_move_streams_to_default_sink() Change the logging message in the pa_sink_move_streams_to_default_sink() Remove the sink and sink_input parts in the module-rescue-streams.c This is based on Tanu's design: https://lists.freedesktop.org/archives/pulseaudio-discuss/2018-October/030531.html And this is only for sink-input and sink, not for source-output and source. In the V2, I addressed all comments of V1 and split the big patch into small patches as suggested by Tanu. It will be easy to review in the future. Hui Wang (8): sink-input: change bool save_sink to char *preferred_sink sink-input: add a new API pa_sink_input_set_preferred_sink sink-input: clear the preferred_sink if it is default_sink core: move sink-inputs conditionally when update default_sink sink: move streams to new appeared sinks if they prefer these sinks device-port: moving streams due to changing the status of active_port sink: move the streams to the default_sink when the sink is unlinked stream-restore: skip entries setting action from gnome-control-center src/modules/dbus/iface-core.c | 2 +- src/modules/module-default-device-restore.c | 2 +- src/modules/module-device-manager.c | 8 +- src/modules/module-intended-roles.c | 2 +- src/modules/module-rescue-streams.c | 134 + src/modules/module-stream-restore.c | 151 +--- src/modules/module-switch-on-connect.c | 27 +--- src/pulsecore/cli-command.c | 2 +- src/pulsecore/core.c| 38 - src/pulsecore/core.h| 6 +- src/pulsecore/device-port.c | 32 - src/pulsecore/device-port.h | 2 + src/pulsecore/protocol-native.c | 2 +- src/pulsecore/sink-input.c | 41 +- src/pulsecore/sink-input.h | 19 ++- src/pulsecore/sink.c| 46 +- src/pulsecore/sink.h| 6 + 17 files changed, 215 insertions(+), 305 deletions(-) -- 2.17.1 ___ pulseaudio-discuss mailing list pulseaudio-discuss@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
[pulseaudio-discuss] [PATCH v3 1/8] sink-input: change bool save_sink to char *preferred_sink
The finial objective is to store the preferred sink name in the sink-input struct, and use module-stream-restore to save and restore it. This patch just replaces the save_sink with preferred_sink, and tries to keep the original logic. Signed-off-by: Hui Wang --- src/modules/module-device-manager.c| 8 src/modules/module-intended-roles.c| 2 +- src/modules/module-stream-restore.c| 15 +-- src/modules/module-switch-on-connect.c | 2 +- src/pulsecore/sink-input.c | 24 +++- src/pulsecore/sink-input.h | 17 - 6 files changed, 46 insertions(+), 22 deletions(-) diff --git a/src/modules/module-device-manager.c b/src/modules/module-device-manager.c index 15fd2..cba3a4ebc 100644 --- a/src/modules/module-device-manager.c +++ b/src/modules/module-device-manager.c @@ -656,14 +656,14 @@ static void route_sink_input(struct userdata *u, pa_sink_input *si) { pa_assert(u); pa_assert(u->do_routing); -/* Don't override user or application routing requests. */ -if (si->save_sink || si->sink_requested_by_application) -return; - /* Skip this if it is already in the process of being moved anyway */ if (!si->sink) return; +/* Don't override user or application routing requests. */ +if (pa_safe_streq(si->sink->name, si->preferred_sink) || si->sink_requested_by_application) +return; + auto_filtered_prop = pa_proplist_gets(si->proplist, "module-device-manager.auto_filtered"); if (auto_filtered_prop) auto_filtered = (pa_parse_boolean(auto_filtered_prop) == 1); diff --git a/src/modules/module-intended-roles.c b/src/modules/module-intended-roles.c index adee51c20..5596faf1f 100644 --- a/src/modules/module-intended-roles.c +++ b/src/modules/module-intended-roles.c @@ -175,7 +175,7 @@ static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, struct if (si->sink == sink) continue; -if (si->save_sink) +if (pa_safe_streq(si->sink->name, si->preferred_sink)) continue; /* Skip this if it is already in the process of being moved diff --git a/src/modules/module-stream-restore.c b/src/modules/module-stream-restore.c index cbef4782d..3c50fda1e 100644 --- a/src/modules/module-stream-restore.c +++ b/src/modules/module-stream-restore.c @@ -1311,9 +1311,9 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint3 mute_updated = !created_new_entry && (!old->muted_valid || entry->muted != old->muted); } -if (sink_input->save_sink) { +if (sink_input->preferred_sink != NULL) { pa_xfree(entry->device); -entry->device = pa_xstrdup(sink_input->sink->name); +entry->device = pa_xstrdup(sink_input->preferred_sink); entry->device_valid = true; device_updated = !created_new_entry && (!old->device_valid || !pa_streq(entry->device, old->device)); @@ -1650,7 +1650,7 @@ static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, struct if (si->sink == sink) continue; -if (si->save_sink) +if (pa_safe_streq(si->sink->name, si->preferred_sink)) continue; /* Skip this if it is already in the process of being moved @@ -1951,12 +1951,13 @@ static void entry_apply(struct userdata *u, const char *name, struct entry *e) { if (u->restore_device) { if (!e->device_valid) { -if (si->save_sink) { +if (si->preferred_sink != NULL) { pa_log_info("Ensuring device is not saved for stream %s.", name); /* If the device is not valid we should make sure the - save flag is cleared as the user may have specifically + preferred_sink is cleared as the user may have specifically removed the sink element from the rule. */ -si->save_sink = false; +pa_xfree(si->preferred_sink); +si->preferred_sink = NULL; /* This is cheating a bit. The sink input itself has not changed but the rules governing its routing have, so we fire this event such that other routing modules (e.g. module-device-manager) @@ -1966,6 +1967,8 @@ static void entry_apply(struct userdata *u, const char *name, struct entry *e) { } else if ((s = pa_namereg_get(u->core, e->device, PA_NAMEREG_SINK))) { pa_log_info("Restoring device for stream %s.", name); pa_sink_input_move_to(si, s, true); +pa_xfree(si->pref
[pulseaudio-discuss] [PATCH v3 8/8] stream-restore: skip entries setting action from gnome-control-center
When users select an output device from gnome-control-center UI, the sink of this output device will be set to the configured_default_sink and the default_sink, these actions are expected, but after these actions, the gnome-control-center will call extension_cb() to modify the entries in the database, let all stream entries to bind the sink users select, this is not correct since the sink is default_sink now. This is a temp fix for this issue, after gnome-control-center fixes this problem, this patch should be reverted. Signed-off-by: Hui Wang --- src/modules/module-stream-restore.c | 14 -- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/modules/module-stream-restore.c b/src/modules/module-stream-restore.c index 838b7fcaa..161f47fdb 100644 --- a/src/modules/module-stream-restore.c +++ b/src/modules/module-stream-restore.c @@ -2057,7 +2057,7 @@ static int extension_cb(pa_native_protocol *p, pa_module *m, pa_native_connectio } while (!pa_tagstruct_eof(t)) { -const char *name, *device; +const char *name, *device, *client_name; bool muted; struct entry *entry; #ifdef HAVE_DBUS @@ -2098,7 +2098,17 @@ static int extension_cb(pa_native_protocol *p, pa_module *m, pa_native_connectio entry_free(entry); goto fail; } - +/* When users select an output device from gnome-control-center UI, the gnome-control-center will change all entries + * in the database to bind the sink of this output device, this is not correct since at this moment, the sink is + * default_sink and we shouldn't bind a stream to default_sink via preferred_sink or database. + * After gnome-control-center fix the issue, let us remove this code */ +client_name = pa_strnull(pa_proplist_gets(pa_native_connection_get_client(c)->proplist, PA_PROP_APPLICATION_PROCESS_BINARY)); +if (pa_safe_streq(client_name, "gnome-control-center")) { +if (entry->device_valid && m->core->default_sink && pa_safe_streq(device, m->core->default_sink->name)) { +entry_free(entry); +goto fail; +} +} #ifdef HAVE_DBUS old = entry_read(u, name); #endif -- 2.17.1 ___ pulseaudio-discuss mailing list pulseaudio-discuss@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
[pulseaudio-discuss] [PATCH v3 4/8] core: move sink-inputs conditionally when update default_sink
When the default sink changes, the streams from the old default sink should be moved to the new default sink, unless the preferred_sink string is set to the old default sink and the active port of the old default sink is not unavailable Signed-off-by: Hui Wang --- src/modules/dbus/iface-core.c | 2 +- src/modules/module-default-device-restore.c | 2 +- src/modules/module-switch-on-connect.c | 27 ++- src/pulsecore/cli-command.c | 2 +- src/pulsecore/core.c| 10 -- src/pulsecore/core.h| 4 +-- src/pulsecore/device-port.c | 2 +- src/pulsecore/protocol-native.c | 2 +- src/pulsecore/sink.c| 38 +++-- src/pulsecore/sink.h| 6 10 files changed, 57 insertions(+), 38 deletions(-) diff --git a/src/modules/dbus/iface-core.c b/src/modules/dbus/iface-core.c index 5229c0467..9763480d2 100644 --- a/src/modules/dbus/iface-core.c +++ b/src/modules/dbus/iface-core.c @@ -721,7 +721,7 @@ static void handle_set_fallback_sink(DBusConnection *conn, DBusMessage *msg, DBu return; } -pa_core_set_configured_default_sink(c->core, pa_dbusiface_device_get_sink(fallback_sink)->name); +pa_core_set_configured_default_sink(c->core, pa_dbusiface_device_get_sink(fallback_sink)->name, true); pa_dbus_send_empty_reply(conn, msg); } diff --git a/src/modules/module-default-device-restore.c b/src/modules/module-default-device-restore.c index c4dbad99f..33e74c071 100644 --- a/src/modules/module-default-device-restore.c +++ b/src/modules/module-default-device-restore.c @@ -69,7 +69,7 @@ static void load(struct userdata *u) { pa_log_warn("Invalid sink name: %s", ln); else { pa_log_info("Restoring default sink '%s'.", ln); -pa_core_set_configured_default_sink(u->core, ln); +pa_core_set_configured_default_sink(u->core, ln, false); } } else if (errno != ENOENT) diff --git a/src/modules/module-switch-on-connect.c b/src/modules/module-switch-on-connect.c index f0cb29a7c..3ceac8b4f 100644 --- a/src/modules/module-switch-on-connect.c +++ b/src/modules/module-switch-on-connect.c @@ -54,9 +54,6 @@ struct userdata { }; static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, void* userdata) { -pa_sink_input *i; -uint32_t idx; -pa_sink *old_default_sink; const char *s; struct userdata *u = userdata; @@ -88,7 +85,7 @@ static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, void* /* No default sink, nothing to move away, just set the new default */ if (!c->default_sink) { -pa_core_set_configured_default_sink(c, sink->name); +pa_core_set_configured_default_sink(c, sink->name, false); return PA_HOOK_OK; } @@ -103,28 +100,8 @@ static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, void* return PA_HOOK_OK; } -old_default_sink = c->default_sink; - /* Actually do the switch to the new sink */ -pa_core_set_configured_default_sink(c, sink->name); - -/* Now move all old inputs over */ -if (pa_idxset_size(old_default_sink->inputs) <= 0) { -pa_log_debug("No sink inputs to move away."); -return PA_HOOK_OK; -} - -PA_IDXSET_FOREACH(i, old_default_sink->inputs, idx) { -if (pa_safe_streq(i->sink->name, i->preferred_sink) || !PA_SINK_INPUT_IS_LINKED(i->state)) -continue; - -if (pa_sink_input_move_to(i, sink, false) < 0) -pa_log_info("Failed to move sink input %u \"%s\" to %s.", i->index, -pa_strnull(pa_proplist_gets(i->proplist, PA_PROP_APPLICATION_NAME)), sink->name); -else -pa_log_info("Successfully moved sink input %u \"%s\" to %s.", i->index, -pa_strnull(pa_proplist_gets(i->proplist, PA_PROP_APPLICATION_NAME)), sink->name); -} +pa_core_set_configured_default_sink(c, sink->name, false); return PA_HOOK_OK; } diff --git a/src/pulsecore/cli-command.c b/src/pulsecore/cli-command.c index 5205349bd..cc7addaa1 100644 --- a/src/pulsecore/cli-command.c +++ b/src/pulsecore/cli-command.c @@ -1036,7 +1036,7 @@ static int pa_cli_command_sink_default(pa_core *c, pa_tokenizer *t, pa_strbuf *b } if ((s = pa_namereg_get(c, n, PA_NAMEREG_SINK))) -pa_core_set_configured_default_sink(c, s->name); +pa_core_set_configured_default_sink(c, s->name, true); else pa_strbuf_printf(buf, "Sink %s does not exist.\n", n); diff --git a/src/pulsecore/core.c b/src/pulsecore/core.c index e5bb2e47b..a112ff753 100644 --- a/src/pulsecore/core.c +++ b/src/pulsec
[pulseaudio-discuss] [PATCH v3 7/8] sink: move the streams to the default_sink when the sink is unlinked
When a sink is unlinked, all streams of this sink are moved to default_sink, this action is implemented in the core rather than modules now. Signed-off-by: Hui Wang --- src/modules/module-rescue-streams.c | 134 +--- src/modules/module-stream-restore.c | 50 --- src/pulsecore/sink.c| 8 +- 3 files changed, 8 insertions(+), 184 deletions(-) diff --git a/src/modules/module-rescue-streams.c b/src/modules/module-rescue-streams.c index 0d8b1be8b..a21b95a96 100644 --- a/src/modules/module-rescue-streams.c +++ b/src/modules/module-rescue-streams.c @@ -24,7 +24,6 @@ #include #include -#include #include #include #include @@ -32,7 +31,7 @@ #include PA_MODULE_AUTHOR("Lennart Poettering"); -PA_MODULE_DESCRIPTION("When a sink/source is removed, try to move its streams to the default sink/source"); +PA_MODULE_DESCRIPTION("When a source is removed, try to move its streams to the default source"); PA_MODULE_VERSION(PACKAGE_VERSION); PA_MODULE_LOAD_ONCE(true); @@ -42,9 +41,7 @@ static const char* const valid_modargs[] = { struct userdata { pa_hook_slot -*sink_unlink_slot, *source_unlink_slot, -*sink_input_move_fail_slot, *source_output_move_fail_slot; }; @@ -65,23 +62,6 @@ static pa_source* find_source_from_port(pa_core *c, pa_device_port *port) { return NULL; } -static pa_sink* find_sink_from_port(pa_core *c, pa_device_port *port) { -pa_sink *target; -uint32_t idx; -void *state; -pa_device_port *p; - -if (!port) -return NULL; - -PA_IDXSET_FOREACH(target, c->sinks, idx) -PA_HASHMAP_FOREACH(p, target->ports, state) -if (port == p) -return target; - -return NULL; -} - static void build_group_ports(pa_hashmap *g_ports, pa_hashmap *s_ports) { void *state; pa_device_port *p; @@ -93,112 +73,6 @@ static void build_group_ports(pa_hashmap *g_ports, pa_hashmap *s_ports) { pa_hashmap_put(g_ports, p, p); } -static pa_sink* find_evacuation_sink(pa_core *c, pa_sink_input *i, pa_sink *skip) { -pa_sink *target, *fb_sink = NULL; -uint32_t idx; -pa_hashmap *all_ports; -pa_device_port *best_port; - -pa_assert(c); -pa_assert(i); - -if (c->default_sink && c->default_sink != skip && pa_sink_input_may_move_to(i, c->default_sink)) -return c->default_sink; - -all_ports = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); - -PA_IDXSET_FOREACH(target, c->sinks, idx) { -if (target == c->default_sink) -continue; - -if (target == skip) -continue; - -if (!PA_SINK_IS_LINKED(target->state)) -continue; - -if (!pa_sink_input_may_move_to(i, target)) -continue; - -if (!fb_sink) -fb_sink = target; - -build_group_ports(all_ports, target->ports); -} - -best_port = pa_device_port_find_best(all_ports); - -pa_hashmap_free(all_ports); - -if (best_port) -target = find_sink_from_port(c, best_port); -else -target = fb_sink; - -if (!target) -pa_log_debug("No evacuation sink found."); - -return target; -} - -static pa_hook_result_t sink_unlink_hook_callback(pa_core *c, pa_sink *sink, void* userdata) { -pa_sink_input *i; -uint32_t idx; - -pa_assert(c); -pa_assert(sink); - -/* There's no point in doing anything if the core is shut down anyway */ -if (c->state == PA_CORE_SHUTDOWN) -return PA_HOOK_OK; - -if (pa_idxset_size(sink->inputs) <= 0) { -pa_log_debug("No sink inputs to move away."); -return PA_HOOK_OK; -} - -PA_IDXSET_FOREACH(i, sink->inputs, idx) { -pa_sink *target; - -if (!(target = find_evacuation_sink(c, i, sink))) -continue; - -if (pa_sink_input_move_to(i, target, false) < 0) -pa_log_info("Failed to move sink input %u \"%s\" to %s.", i->index, -pa_strnull(pa_proplist_gets(i->proplist, PA_PROP_APPLICATION_NAME)), target->name); -else -pa_log_info("Successfully moved sink input %u \"%s\" to %s.", i->index, -pa_strnull(pa_proplist_gets(i->proplist, PA_PROP_APPLICATION_NAME)), target->name); -} - -return PA_HOOK_OK; -} - -static pa_hook_result_t sink_input_move_fail_hook_callback(pa_core *c, pa_sink_input *i, void *userdata) { -pa_sink *target; - -pa_assert(c); -pa_assert(i); - -/* There's no point in doing anything if the core is shut down anyway */ -if (c->state == PA_CORE_SHUTDOWN) -return PA_HOOK_OK; - -if (!(target = find_evacuation_sink(c, i, NULL))) -return PA_HOOK_OK; - -if (pa_sink_in
[pulseaudio-discuss] [PATCH v3 2/8] sink-input: add a new API pa_sink_input_set_preferred_sink
If the sink here is NULL, that means users want to clear the preferred_sink and move the sink-input to the default_sink, otherwise set the preferred_sink to the sink->name and move the sink-input to the sink. After that fire the sink_input_change event. After adding this API, we can use this API to simplify the entry_apply in the module-stream-restore.c. Signed-off-by: Hui Wang --- src/modules/module-stream-restore.c | 10 ++ src/pulsecore/sink-input.c | 13 + src/pulsecore/sink-input.h | 2 ++ 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/modules/module-stream-restore.c b/src/modules/module-stream-restore.c index 3c50fda1e..c8bc02ecd 100644 --- a/src/modules/module-stream-restore.c +++ b/src/modules/module-stream-restore.c @@ -1957,18 +1957,12 @@ static void entry_apply(struct userdata *u, const char *name, struct entry *e) { preferred_sink is cleared as the user may have specifically removed the sink element from the rule. */ pa_xfree(si->preferred_sink); -si->preferred_sink = NULL; -/* This is cheating a bit. The sink input itself has not changed - but the rules governing its routing have, so we fire this event - such that other routing modules (e.g. module-device-manager) - will pick up the change and reapply their routing */ -pa_subscription_post(si->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, si->index); +pa_sink_input_set_preferred_sink(si, NULL); } } else if ((s = pa_namereg_get(u->core, e->device, PA_NAMEREG_SINK))) { pa_log_info("Restoring device for stream %s.", name); -pa_sink_input_move_to(si, s, true); pa_xfree(si->preferred_sink); -si->preferred_sink = pa_xstrdup(s->name); +pa_sink_input_set_preferred_sink(si, s); } } } diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index 18766019e..7521bed08 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -2418,3 +2418,16 @@ void pa_sink_input_set_reference_ratio(pa_sink_input *i, const pa_cvolume *ratio pa_cvolume_snprint_verbose(old_ratio_str, sizeof(old_ratio_str), &old_ratio, &i->channel_map, true), pa_cvolume_snprint_verbose(new_ratio_str, sizeof(new_ratio_str), ratio, &i->channel_map, true)); } + +/* Called from the main thread. */ +void pa_sink_input_set_preferred_sink(pa_sink_input *i, pa_sink *s) { +pa_assert(i); + +if (s) { +i->preferred_sink = pa_xstrdup(s->name); +pa_sink_input_move_to(i, s, true); +} else { +i->preferred_sink = NULL; +pa_sink_input_move_to(i, i->core->default_sink, true); +} +} diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h index 16b6bf8eb..d3de6e3f8 100644 --- a/src/pulsecore/sink-input.h +++ b/src/pulsecore/sink-input.h @@ -461,6 +461,8 @@ void pa_sink_input_set_volume_direct(pa_sink_input *i, const pa_cvolume *volume) * i->reference_ratio and logs a message if the value changes. */ void pa_sink_input_set_reference_ratio(pa_sink_input *i, const pa_cvolume *ratio); +void pa_sink_input_set_preferred_sink(pa_sink_input *i, pa_sink *s); + #define pa_sink_input_assert_io_context(s) \ pa_assert(pa_thread_mq_get() || !PA_SINK_INPUT_IS_LINKED((s)->state)) -- 2.17.1 ___ pulseaudio-discuss mailing list pulseaudio-discuss@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
Re: [pulseaudio-discuss] [PATCH v3 0/8] Change the bool sink_save to char *preferred_sink
OK, I will create a merge request. Thanks, Hui. On 2019/8/23 下午3:48, Georg Chini wrote: On 18.08.19 07:32, Hui Wang wrote: In the V3, I addressed all Tanu's and Georg's comments: 0002-xxx.patch: remove the pa_subscription_post() in the pa_sink_input_set_preferred_sink() 0003-xxx.patch: Add the check of sink_input->sink->card in the subscribe_callback() 0004-xxx.patch: Initialize the varible old_sink_is_unavailable Add the check of core->default_sink == NULL || core->default_sink->unlink_requested in the pa_sink_move_streams_to_default_sink() 0007-xxx.patch: Move the calling of pa_sink_move_streams_to_default_sink() after the pa_core_update_default_sink() in the pa_sink_unlink() Add shutdown check in the pa_sink_move_streams_to_default_sink() Change the logging message in the pa_sink_move_streams_to_default_sink() Remove the sink and sink_input parts in the module-rescue-streams.c This is based on Tanu's design: https://lists.freedesktop.org/archives/pulseaudio-discuss/2018-October/030531.html And this is only for sink-input and sink, not for source-output and source. In the V2, I addressed all comments of V1 and split the big patch into small patches as suggested by Tanu. It will be easy to review in the future. Thanks for the updated patches. I will be on vacation starting end of next week, so I will not find the time for a review before end of September. Is it possible that you open a merge request on Gitlab for this? https://gitlab.freedesktop.org/pulseaudio/pulseaudio/ If not, I will open the merge request for you once the review is complete because we changed our policy so that all changes have to go through a merge request. ___ pulseaudio-discuss mailing list pulseaudio-discuss@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
Re: [pulseaudio-discuss] [PATCH v3 0/8] Change the bool sink_save to char *preferred_sink
Done. https://gitlab.freedesktop.org/pulseaudio/pulseaudio/merge_requests/158 On 2019/8/24 上午9:25, Hui Wang wrote: OK, I will create a merge request. Thanks, Hui. On 2019/8/23 下午3:48, Georg Chini wrote: On 18.08.19 07:32, Hui Wang wrote: In the V3, I addressed all Tanu's and Georg's comments: 0002-xxx.patch: remove the pa_subscription_post() in the pa_sink_input_set_preferred_sink() 0003-xxx.patch: Add the check of sink_input->sink->card in the subscribe_callback() 0004-xxx.patch: Initialize the varible old_sink_is_unavailable Add the check of core->default_sink == NULL || core->default_sink->unlink_requested in the pa_sink_move_streams_to_default_sink() 0007-xxx.patch: Move the calling of pa_sink_move_streams_to_default_sink() after the pa_core_update_default_sink() in the pa_sink_unlink() Add shutdown check in the pa_sink_move_streams_to_default_sink() Change the logging message in the pa_sink_move_streams_to_default_sink() Remove the sink and sink_input parts in the module-rescue-streams.c This is based on Tanu's design: https://lists.freedesktop.org/archives/pulseaudio-discuss/2018-October/030531.html And this is only for sink-input and sink, not for source-output and source. In the V2, I addressed all comments of V1 and split the big patch into small patches as suggested by Tanu. It will be easy to review in the future. Thanks for the updated patches. I will be on vacation starting end of next week, so I will not find the time for a review before end of September. Is it possible that you open a merge request on Gitlab for this? https://gitlab.freedesktop.org/pulseaudio/pulseaudio/ If not, I will open the merge request for you once the review is complete because we changed our policy so that all changes have to go through a merge request. ___ pulseaudio-discuss mailing list pulseaudio-discuss@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss