[vlc-devel] [PATCHv2 2/3] mmdevice: handle AUDCLNT_E_ALREADY_INITIALIZED

Steve Lhomme robux4 at gmail.com
Thu Jul 6 13:30:59 CEST 2017


On Thu, Jul 6, 2017 at 11:29 AM, Thomas Guillem <thomas at gllm.fr> wrote:
>
>
> On Thu, Jul 6, 2017, at 11:25, Thomas Guillem wrote:
>> Sadly, this error can happen even if the "aout stream" was well stopped.
>> See
>> MSDN comments in the commit.
>>
>> Add DeviceRestartLocked() that fetch a new instance of the current
>> IMMDevice.
>> ---
>>  modules/audio_output/mmdevice.c | 77
>>  ++++++++++++++++++++++++++++++++---------
>>  1 file changed, 61 insertions(+), 16 deletions(-)
>>
>> diff --git a/modules/audio_output/mmdevice.c
>> b/modules/audio_output/mmdevice.c
>> index 8446c1cab3..194a8bf91b 100644
>> --- a/modules/audio_output/mmdevice.c
>> +++ b/modules/audio_output/mmdevice.c
>> @@ -94,6 +94,7 @@ struct aout_sys_t
>>      float gain; /**< Current software gain volume */
>>
>>      wchar_t *selecting_device; /**< Requesting device identifier, NULL
>>      if none */
>> +    wchar_t *selected_device; /**< Requested device identifier, NULL if
>> none */
>
> Maybe a better naming would be:
> wchar_t *acquired_device; /**< Acquired device identifier, NULL if
>> none */

Yes

>>      float volume; /**< Requested volume, negative if none */
>>      signed char mute; /**< Requested mute, negative if none */
>>      CRITICAL_SECTION lock;
>> @@ -718,22 +719,10 @@ static int DevicesEnum(audio_output_t *aout,
>> IMMDeviceEnumerator *it)
>>      return n;
>>  }
>>
>> -static int DeviceSelectLocked(audio_output_t *aout, const char *id)
>> +static int DeviceRequestLocked(audio_output_t *aout)
>>  {
>>      aout_sys_t *sys = aout->sys;
>> -    wchar_t *device;
>> -
>> -    if (id != NULL)
>> -    {
>> -        device = ToWide(id);
>> -        if (unlikely(device == NULL))
>> -            return -1;
>> -    }
>> -    else
>> -        device = default_device;
>> -
>> -    assert(sys->selecting_device == NULL);
>> -    sys->selecting_device = device;
>> +    assert(sys->selecting_device);
>>
>>      WakeConditionVariable(&sys->work);
>>      while (sys->selecting_device != NULL)
>> @@ -745,6 +734,32 @@ static int DeviceSelectLocked(audio_output_t *aout,
>> const char *id)
>>      return (sys->dev != NULL) ? 0 : -1;
>>  }
>>
>> +static int DeviceSelectLocked(audio_output_t *aout, const char *id)
>> +{
>> +    aout_sys_t *sys = aout->sys;
>> +    assert(sys->selecting_device == NULL);
>> +
>> +    if (id != NULL)
>> +    {
>> +        sys->selecting_device = ToWide(id);
>> +        if (unlikely(sys->selecting_device == NULL))
>> +            return -1;
>> +    }
>> +    else
>> +        sys->selecting_device = default_device;
>> +
>> +    return DeviceRequestLocked(aout);
>> +}
>> +
>> +static int DeviceRestartLocked(audio_output_t *aout)
>> +{
>> +    aout_sys_t *sys = aout->sys;
>> +    assert(sys->selecting_device == NULL);
>> +    assert(sys->selected_device != NULL);
>> +    sys->selecting_device = sys->selected_device;
>> +    return DeviceRequestLocked(aout);
>> +}
>> +
>>  static int DeviceSelect(audio_output_t *aout, const char *id)
>>  {
>>      EnterCriticalSection(&aout->sys->lock);
>> @@ -790,6 +805,11 @@ static HRESULT MMSession(audio_output_t *aout,
>> IMMDeviceEnumerator *it)
>>      assert(sys->selecting_device != NULL);
>>      assert(sys->dev == NULL);
>>
>> +    /* Yes, it's perfectly valid to request the same device, see Start()
>> +     * comments. */
>> +    if (sys->selected_device != sys->selecting_device
>> +     && sys->selected_device != default_device)
>> +        free(sys->selected_device);
>>      if (sys->selecting_device != default_device) /* Device selected
>>      explicitly */
>>      {
>>          msg_Dbg(aout, "using selected device %ls",
>>          sys->selecting_device);
>> @@ -797,7 +817,7 @@ static HRESULT MMSession(audio_output_t *aout,
>> IMMDeviceEnumerator *it)
>>          if (FAILED(hr))
>>              msg_Err(aout, "cannot get selected device %ls (error
>>              0x%lx)",
>>                      sys->selecting_device, hr);
>> -        free(sys->selecting_device);
>> +        sys->selected_device = sys->selecting_device;
>>      }
>>      else
>>          hr = AUDCLNT_E_DEVICE_INVALIDATED;
>> @@ -810,6 +830,8 @@ static HRESULT MMSession(audio_output_t *aout,
>> IMMDeviceEnumerator *it)
>>                                                           eConsole,
>>                                                           &sys->dev);
>>          if (FAILED(hr))
>>              msg_Err(aout, "cannot get default device (error 0x%lx)",
>>              hr);
>> +        else
>> +            sys->selected_device = default_device;
>>      }
>>
>>      sys->selecting_device = NULL;
>> @@ -1083,7 +1105,29 @@ static int Start(audio_output_t *aout,
>> audio_sample_format_t *restrict fmt)
>>
>>          sys->module = vlc_module_load(s, "aout stream",
>>          "$mmdevice-backend",
>>                                        false, aout_stream_Start, s, fmt,
>>                                        &hr);
>> -        if (hr != AUDCLNT_E_DEVICE_INVALIDATED ||
>> DeviceSelectLocked(aout, NULL))
>> +
>> +        int ret = -1;
>> +        if (hr == AUDCLNT_E_ALREADY_INITIALIZED)
>> +        {
>> +            /* From MSDN: "If the initial call to Initialize fails,
>> subsequent
>> +             * Initialize calls might fail and return error code
>> +             * E_ALREADY_INITIALIZED, even though the interface has not
>> been
>> +             * initialized. If this occurs, release the IAudioClient
>> interface
>> +             * and obtain a new IAudioClient interface from the MMDevice
>> API
>> +             * before calling Initialize again."
>> +             *
>> +             * Therefore, request to MMThread the same device and try
>> again. */
>> +
>> +            ret = DeviceRestartLocked(aout);
>> +        }
>> +        else if (hr == AUDCLNT_E_DEVICE_INVALIDATED)
>> +        {
>> +            /* The audio endpoint device has been unplugged, request to
>> +             * MMThread the default device and try again. */
>> +
>> +            ret = DeviceSelectLocked(aout, NULL);
>> +        }
>> +        if (ret != 0)
>>              break;
>>      }
>>      LeaveCriticalSection(&sys->lock);
>> @@ -1135,6 +1179,7 @@ static int Open(vlc_object_t *obj)
>>      sys->ducks = 0;
>>
>>      sys->selecting_device = default_device;
>> +    sys->selected_device = NULL;
>>      sys->gain = 1.f;
>>      sys->volume = -1.f;
>>      sys->mute = -1;
>> --
>> 2.11.0
>>
>> _______________________________________________
>> vlc-devel mailing list
>> To unsubscribe or modify your subscription options:
>> https://mailman.videolan.org/listinfo/vlc-devel
> _______________________________________________
> vlc-devel mailing list
> To unsubscribe or modify your subscription options:
> https://mailman.videolan.org/listinfo/vlc-devel


More information about the vlc-devel mailing list