[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