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

Thomas Guillem thomas at gllm.fr
Thu Jul 6 11:29:02 CEST 2017



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 */

>      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


More information about the vlc-devel mailing list