+ if (sys->volume != NULL)
+ { /* Get current values (_after_ changes notification registration) */
+ BOOL mute;
+ float level;
+
+ hr = ISimpleAudioVolume_GetMute(sys->volume, &mute);
+ if (FAILED(hr))
+ msg_Err(aout, "cannot get mute (error 0x%lx)", hr);
+ else
+ aout_MuteReport(aout, mute != FALSE);
+
+ hr = ISimpleAudioVolume_GetMasterVolume(sys->volume, &level);
+ if (FAILED(hr))
+ msg_Err(aout, "cannot get mute (error 0x%lx)", hr);
+ else
+ aout_VolumeReport(aout, level);
+ }
+
+ SetEvent(sys->device_ready);
+ /* Wait until device change or exit */
+ WaitForSingleObject(sys->device_changed, INFINITE);
+
+ /* Deregister session control */
+ if (control != NULL)
+ {
+ IAudioSessionControl_UnregisterAudioSessionNotification(control,
+ &sys->session_events);
+ IAudioSessionControl_Release(control);
+ }
+
+ if (sys->volume != NULL)
+ ISimpleAudioVolume_Release(sys->volume);
+}
+
+/** MMDevice audio output thread.
+ * This thread takes cares of the audio session control. Inconveniently enough,
+ * the audio session control interface must:
+ * - be created and destroyed from the same thread, and
+ * - survive across VLC audio output calls.
+ * The only way to reconcile both requirements is a custom thread.
+ * The thread also ensure that the COM Multi-Thread Apartment is continuously
+ * referenced so that MMDevice objects are not destroyed early.
+ */
+static void *MMThread(void *data)
+{
+ audio_output_t *aout = data;
+ aout_sys_t *sys = aout->sys;
+
+ EnterMTA();
+ while (sys->it != NULL)
+ MMSession(aout, sys);
+ LeaveMTA();
+ return NULL;
+}
+
+/*** Audio devices ***/
+static int DevicesEnum(audio_output_t *aout)
+{
+ aout_sys_t *sys = aout->sys;
+ HRESULT hr;
+ IMMDeviceCollection *devs;
+
+ hr = IMMDeviceEnumerator_EnumAudioEndpoints(sys->it, eRender,
+ DEVICE_STATE_ACTIVE, &devs);
+ if (FAILED(hr))
+ {
+ msg_Warn(aout, "cannot enumerate audio endpoints (error 0x%lx)", hr);
+ return -1;
+ }
+
+ UINT count;
+ hr = IMMDeviceCollection_GetCount(devs, &count);