[pulseaudio-discuss] [PATCH] sink/source: Initialize port before fixate hook (fixes volume/mute not restored)

David Henningsson david.henningsson at canonical.com
Tue Mar 25 00:10:30 PDT 2014


On 03/24/2014 09:51 AM, Tanu Kaskinen wrote:
> On Sat, 2014-03-22 at 18:39 +0100, David Henningsson wrote:
>> On 03/21/2014 01:51 PM, Tanu Kaskinen wrote:
>>> On Fri, 2014-03-21 at 10:27 +0100, David Henningsson wrote:
>>>> In case a port has not yet been saved, which is e g often the case
>>>> if a sink/source has only one port, reading volume/mute will be done
>>>> without port, whereas writing volume/mute will be done with port.
>>>>
>>>> Work around this by setting a default port before the fixate hook,
>>>> so module-device-restore can read volume/mute for the correct port.
>>>>
>>>> BugLink: https://bugs.launchpad.net/bugs/1289515
>>>> Signed-off-by: David Henningsson <david.henningsson at canonical.com>
>>>
>>> Thanks, this also fixes this bug:
>>> https://bugs.freedesktop.org/show_bug.cgi?id=55262
>>>
>>> A couple of comments below.
>>>
>>>> ---
>>>>  src/pulsecore/sink.c   |   11 +++++++++++
>>>>  src/pulsecore/source.c |   11 +++++++++++
>>>>  2 files changed, 22 insertions(+)
>>>>
>>>> diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c
>>>> index 08143e9..9c4b0c3 100644
>>>> --- a/src/pulsecore/sink.c
>>>> +++ b/src/pulsecore/sink.c
>>>> @@ -235,6 +235,17 @@ pa_sink* pa_sink_new(
>>>>      pa_device_init_icon(data->proplist, true);
>>>>      pa_device_init_intended_roles(data->proplist);
>>>>  
>>>> +    if (!data->active_port && !data->save_port) {
>>>
>>> How is data->save_port relevant here? If active_port is NULL, save_port
>>> should always be false (true wouldn't have any meaning).
>>
>> It just means I haven't thought through the case where active_port is
>> NULL and save_port is true, so better avoid it.
>>
>> I could have done:
>>
>> if (!data->active_port) {
>>    assert(!data->save_port);
>>
>> ...but as you know, I prefer when PulseAudio is not crashing.
> 
> You can just drop the assertion, which will avoid any speculative
> crashes.

Ok, done in v2.

> 
> You said that you hadn't thought through the case where active_port is
> NULL and save_port is true, which I assume means that you're not sure if
> it's a valid operation to set save_port to true while leaving
> active_port to NULL. Are you still unsure? Does it help if I say that I
> am 100% sure that it's not a valid operation?
> 
>>
>>>> +        void *state;
>>>> +        pa_device_port *p, *p2 = NULL;
>>>> +
>>>> +        PA_HASHMAP_FOREACH(p, data->ports, state)
>>>> +            if (!p2 || p->priority > p2->priority) {
>>>> +                p2 = p;
>>>> +                pa_sink_new_data_set_port(data, p2->name);
>>>
>>> I'd prefer calling pa_sink_new_data_set_port() only once, i.e. outside
>>> the loop.
>>
>> Ok, makes sense.
>>
>>>
>>>> +            }
>>>> +    }
>>>
>>> This partially duplicates the code that is run later:
>>>
>>>     if (!s->active_port) {
>>>         void *state;
>>>         pa_device_port *p;
>>>
>>>         PA_HASHMAP_FOREACH(p, s->ports, state) {
>>>             if (p->available == PA_AVAILABLE_NO)
>>>                 continue;
>>>
>>>             if (!s->active_port || p->priority > s->active_port->priority)
>>>                 s->active_port = p;
>>>         }
>>>         if (!s->active_port) {
>>>             PA_HASHMAP_FOREACH(p, s->ports, state)
>>>                 if (!s->active_port || p->priority > s->active_port->priority)
>>>                     s->active_port = p;
>>>         }
>>>     }
>>>
>>> I think we should do the fallback port initialization only once, in the
>>> location where you added the new code. We should use the full logic of
>>> the old fallback initialization code.
>>>
>>
>> How about I take the code above, make a function out of it, and call it
>> in both places? Maybe there's some module hook somewhere in between that
>> can set active port to null. (And I don't like PulseAudio crashing even
>> if a module hook does stupid things.)
> 
> How about introducing hook PA_CORE_HOOK_SINK_SET_INITIAL_PORT? That
> would then be the only valid place to apply initial port policy from
> modules. Having a hook with clearer semantics would lower the
> probability that modules do stupid things.
> 
> If you don't like that idea, then go ahead and make a function that is
> called from two places. Please add a warning to the second call that
> makes it possible to catch broken modules.

I did so but skipped the warning: it's still valid to have sinks without
ports, so the warning would have been printed in cases where it
shouldn't have been printed.

> Apropos SINK_SET_INITIAL_PORT, I plan to gradually replace the various
> NEW and FIXATE hooks with SET_INITIAL_FOO hooks. The NEW and FIXATE
> hooks are mainly used for applying object initialization policies, and
> it's not clearly defined what should be done in NEW and what should be
> done in FIXATE, so I think the SET_INITIAL_FOO pattern is better for
> code clarity. If this sounds like a bad plan to you, please let me know.

I think SET_INITIAL_FOO is okay, but it's difficult to tell for sure
without seeing the full picture.


-- 
David Henningsson, Canonical Ltd.
https://launchpad.net/~diwic


More information about the pulseaudio-discuss mailing list