[vlc-commits] [Git][videolan/vlc][master] 13 commits: mmdevice: move owner outside aout_stream_t
Steve Lhomme (@robUx4)
gitlab at videolan.org
Fri Sep 30 07:33:07 UTC 2022
Steve Lhomme pushed to branch master at VideoLAN / VLC
Commits:
3742acc5 by Thomas Guillem at 2022-09-30T06:33:18+00:00
mmdevice: move owner outside aout_stream_t
- - - - -
d09b0a78 by Thomas Guillem at 2022-09-30T06:33:18+00:00
mmdevice: rename owner functions
These functions must be called by the owner, and not by stream modules.
- - - - -
46e37bd9 by Thomas Guillem at 2022-09-30T06:33:18+00:00
mmdevice: move mainloop in a new function
No functional changes.
- - - - -
e0373ddf by Thomas Guillem at 2022-09-30T06:33:18+00:00
mmdevice: report mute after setting it
Use the same behavior than for volume.
- - - - -
d5fe154f by Thomas Guillem at 2022-09-30T06:33:18+00:00
mmdevice: report volume and mute only when necessary
When volume or mute was changed, both volume and mute were reported.
- - - - -
fc3fe81e by Thomas Guillem at 2022-09-30T06:33:18+00:00
mmdevice: replace CS and CV by vlc cond/mutex
- - - - -
e6b41b44 by Thomas Guillem at 2022-09-30T06:33:18+00:00
mmdevice: use an Event instead of a CV
In order to also wait for the Wasapi event.
- - - - -
1b43ce2f by Thomas Guillem at 2022-09-30T06:33:18+00:00
mmdevice: add asynchronous play helpers
- - - - -
4521fb45 by Thomas Guillem at 2022-09-30T06:33:18+00:00
mmdevice: implement nonblocking play
The playback is now done by the MMSession thread.
This thread will wait via the Wasapi Event handle if the audio buffer is
full.
- - - - -
6cd74e1c by Thomas Guillem at 2022-09-30T06:33:18+00:00
winstore: replace CS by vlc mutex
- - - - -
6dc6d7c1 by Thomas Guillem at 2022-09-30T06:33:18+00:00
winstore: implement nonblocking play
- - - - -
9157a849 by Thomas Guillem at 2022-09-30T06:33:18+00:00
wasapi: set play non-blocking
Create a thread from Start() that will do the playback.
- - - - -
02c95ad3 by Thomas Guillem at 2022-09-30T06:33:18+00:00
mmdevice: factorize aout_stream_owner creation/deletion
aout_stream_owner_New() return void * and use a size_t because the "aout
module" might want to allocate extra private data. This will be
necessary with multiple stream playbacks.
- - - - -
4 changed files:
- modules/audio_output/mmdevice.c
- modules/audio_output/mmdevice.h
- modules/audio_output/wasapi.c
- modules/audio_output/winstore.c
Changes:
=====================================
modules/audio_output/mmdevice.c
=====================================
@@ -76,7 +76,7 @@ static char default_device_b[1] = "";
typedef struct
{
- aout_stream_t *stream; /**< Underlying audio output stream */
+ struct aout_stream_owner *stream; /**< Underlying audio output stream */
audio_output_t *aout;
IMMDeviceEnumerator *it; /**< Device enumerator, NULL when exiting */
IMMDevice *dev; /**< Selected output device, NULL if none */
@@ -94,9 +94,9 @@ typedef struct
signed char requested_mute; /**< Requested mute, negative if none */
wchar_t *acquired_device; /**< Acquired device identifier, NULL if none */
bool request_device_restart;
- CRITICAL_SECTION lock;
- CONDITION_VARIABLE work;
- CONDITION_VARIABLE ready;
+ HANDLE work_event;
+ vlc_mutex_t lock;
+ vlc_cond_t ready;
vlc_thread_t thread; /**< Thread for audio session control */
} aout_sys_t;
@@ -129,7 +129,9 @@ static int TimeGet(audio_output_t *aout, vlc_tick_t *restrict delay)
HRESULT hr;
EnterMTA();
- hr = aout_stream_TimeGet(sys->stream, delay);
+ vlc_mutex_lock(&sys->lock);
+ hr = aout_stream_owner_TimeGet(sys->stream, delay);
+ vlc_mutex_unlock(&sys->lock);
LeaveMTA();
return SUCCEEDED(hr) ? 0 : -1;
@@ -138,13 +140,11 @@ static int TimeGet(audio_output_t *aout, vlc_tick_t *restrict delay)
static void Play(audio_output_t *aout, block_t *block, vlc_tick_t date)
{
aout_sys_t *sys = aout->sys;
- HRESULT hr;
-
- EnterMTA();
- hr = aout_stream_Play(sys->stream, block, date);
- LeaveMTA();
- vlc_FromHR(aout, hr);
+ vlc_mutex_lock(&sys->lock);
+ aout_stream_owner_AppendBlock(sys->stream, block, date);
+ vlc_mutex_unlock(&sys->lock);
+ SetEvent(sys->work_event);
}
static void Pause(audio_output_t *aout, bool paused, vlc_tick_t date)
@@ -153,7 +153,9 @@ static void Pause(audio_output_t *aout, bool paused, vlc_tick_t date)
HRESULT hr;
EnterMTA();
- hr = aout_stream_Pause(sys->stream, paused);
+ vlc_mutex_lock(&sys->lock);
+ hr = aout_stream_owner_Pause(sys->stream, paused);
+ vlc_mutex_unlock(&sys->lock);
LeaveMTA();
vlc_FromHR(aout, hr);
@@ -166,7 +168,9 @@ static void Flush(audio_output_t *aout)
HRESULT hr;
EnterMTA();
- hr = aout_stream_Flush(sys->stream);
+ vlc_mutex_lock(&sys->lock);
+ hr = aout_stream_owner_Flush(sys->stream);
+ vlc_mutex_unlock(&sys->lock);
LeaveMTA();
vlc_FromHR(aout, hr);
@@ -194,11 +198,11 @@ static int VolumeSet(audio_output_t *aout, float vol)
{
aout_sys_t *sys = aout->sys;
- EnterCriticalSection(&sys->lock);
+ vlc_mutex_lock(&sys->lock);
int ret = VolumeSetLocked(aout, vol);
aout_GainRequest(aout, sys->gain);
- WakeConditionVariable(&sys->work);
- LeaveCriticalSection(&sys->lock);
+ vlc_mutex_unlock(&sys->lock);
+ SetEvent(sys->work_event);
return ret;
}
@@ -206,10 +210,10 @@ static int MuteSet(audio_output_t *aout, bool mute)
{
aout_sys_t *sys = aout->sys;
- EnterCriticalSection(&sys->lock);
+ vlc_mutex_lock(&sys->lock);
sys->requested_mute = mute;
- WakeConditionVariable(&sys->work);
- LeaveCriticalSection(&sys->lock);
+ vlc_mutex_unlock(&sys->lock);
+ SetEvent(sys->work_event);
return 0;
}
@@ -280,9 +284,7 @@ vlc_AudioSessionEvents_OnSimpleVolumeChanged(IAudioSessionEvents *this,
msg_Dbg(aout, "simple volume changed: %f, muting %sabled", vol,
mute ? "en" : "dis");
- EnterCriticalSection(&sys->lock);
- WakeConditionVariable(&sys->work); /* implicit state: vol & mute */
- LeaveCriticalSection(&sys->lock);
+ SetEvent(sys->work_event); /* implicit state: vol & mute */
(void) ctx;
return S_OK;
}
@@ -582,14 +584,14 @@ vlc_MMNotificationClient_OnDefaultDeviceChange(IMMNotificationClient *this,
if (role != eConsole)
return S_OK;
- EnterCriticalSection(&sys->lock);
+ vlc_mutex_lock(&sys->lock);
if (sys->acquired_device == NULL || sys->acquired_device == default_device)
{
msg_Dbg(aout, "default device changed: %ls", wid);
sys->request_device_restart = true;
aout_RestartRequest(aout, AOUT_RESTART_OUTPUT);
}
- LeaveCriticalSection(&sys->lock);
+ vlc_mutex_unlock(&sys->lock);
return S_OK;
}
@@ -736,9 +738,9 @@ static int DeviceRequestLocked(audio_output_t *aout)
sys->request_device_restart = false;
- WakeConditionVariable(&sys->work);
+ SetEvent(sys->work_event);
while (sys->requested_device != NULL)
- SleepConditionVariableCS(&sys->ready, &sys->lock, INFINITE);
+ vlc_cond_wait(&sys->ready, &sys->lock);
if (sys->stream != NULL && sys->dev != NULL)
/* Request restart of stream with the new device */
@@ -775,12 +777,101 @@ static int DeviceRestartLocked(audio_output_t *aout)
static int DeviceSelect(audio_output_t *aout, const char *id)
{
aout_sys_t *sys = aout->sys;
- EnterCriticalSection(&sys->lock);
+ vlc_mutex_lock(&sys->lock);
int ret = DeviceSelectLocked(aout, id);
- LeaveCriticalSection(&sys->lock);
+ vlc_mutex_unlock(&sys->lock);
return ret;
}
+/**
+ * Main loop
+ *
+ * Adjust volume as long as device is unchanged
+ * */
+static void MMSessionMainloop(audio_output_t *aout, ISimpleAudioVolume *volume)
+{
+ aout_sys_t *sys = aout->sys;
+ HRESULT hr;
+
+ bool report_volume = true;
+ bool report_mute = true;
+
+ while (sys->requested_device == NULL)
+ {
+ if (volume != NULL)
+ {
+ if (sys->requested_volume >= 0.f)
+ {
+ hr = ISimpleAudioVolume_SetMasterVolume(volume, sys->requested_volume, NULL);
+ if (FAILED(hr))
+ msg_Err(aout, "cannot set master volume (error 0x%lX)",
+ hr);
+ report_volume = true;
+ sys->requested_volume = -1.f;
+ }
+
+ if (report_volume)
+ {
+ float level;
+ hr = ISimpleAudioVolume_GetMasterVolume(volume, &level);
+ if (SUCCEEDED(hr))
+ aout_VolumeReport(aout, cbrtf(level * sys->gain));
+ else
+ msg_Err(aout, "cannot get master volume (error 0x%lX)", hr);
+ report_volume = false;
+ }
+
+ if (sys->requested_mute >= 0)
+ {
+ BOOL mute = sys->requested_mute ? TRUE : FALSE;
+
+ hr = ISimpleAudioVolume_SetMute(volume, mute, NULL);
+ if (FAILED(hr))
+ msg_Err(aout, "cannot set mute (error 0x%lX)", hr);
+ report_mute = true;
+ sys->requested_mute = -1;
+ }
+
+ if (report_mute)
+ {
+ BOOL mute;
+ hr = ISimpleAudioVolume_GetMute(volume, &mute);
+ if (SUCCEEDED(hr))
+ aout_MuteReport(aout, mute != FALSE);
+ else
+ msg_Err(aout, "cannot get mute (error 0x%lX)", hr);
+ report_mute = false;
+ }
+ }
+
+ DWORD ev_count = 1;
+ HANDLE events[2] = {
+ sys->work_event,
+ NULL
+ };
+ /* Don't listen to the stream event if the block fifo is empty */
+ if (sys->stream != NULL && sys->stream->chain != NULL)
+ events[ev_count++] = sys->stream->buffer_ready_event;
+
+ vlc_mutex_unlock(&sys->lock);
+ WaitForMultipleObjects(ev_count, events, FALSE, INFINITE);
+ vlc_mutex_lock(&sys->lock);
+
+ if (sys->stream != NULL)
+ {
+ hr = aout_stream_owner_PlayAll(sys->stream);
+ /* Don't call vlc_FromHR here since this function waits for the
+ * current thread */
+ if (unlikely(hr == AUDCLNT_E_DEVICE_INVALIDATED ||
+ hr == AUDCLNT_E_RESOURCES_INVALIDATED))
+ {
+ sys->requested_device = default_device;
+ /* The restart of the stream will be requested asynchronously */
+ }
+ }
+ }
+}
+
/*** Initialization / deinitialization **/
/** MMDevice audio output thread.
* This thread takes cares of the audio session control. Inconveniently enough,
@@ -839,7 +930,7 @@ static HRESULT MMSession(audio_output_t *aout, IMMDeviceEnumerator *it)
}
sys->requested_device = NULL;
- WakeConditionVariable(&sys->ready);
+ vlc_cond_signal(&sys->ready);
if (SUCCEEDED(hr))
{ /* Report actual device */
@@ -961,52 +1052,9 @@ static HRESULT MMSession(audio_output_t *aout, IMMDeviceEnumerator *it)
else
msg_Err(aout, "cannot activate endpoint volume (error 0x%lX)", hr);
- /* Main loop (adjust volume as long as device is unchanged) */
- while (sys->requested_device == NULL)
- {
- if (volume != NULL)
- {
- float level;
-
- level = sys->requested_volume;
- if (level >= 0.f)
- {
- hr = ISimpleAudioVolume_SetMasterVolume(volume, level, NULL);
- if (FAILED(hr))
- msg_Err(aout, "cannot set master volume (error 0x%lX)",
- hr);
- }
- sys->requested_volume = -1.f;
-
- hr = ISimpleAudioVolume_GetMasterVolume(volume, &level);
- if (SUCCEEDED(hr))
- aout_VolumeReport(aout, cbrtf(level * sys->gain));
- else
- msg_Err(aout, "cannot get master volume (error 0x%lX)", hr);
-
- BOOL mute;
-
- hr = ISimpleAudioVolume_GetMute(volume, &mute);
- if (FAILED(hr))
- msg_Err(aout, "cannot get mute (error 0x%lX)", hr);
-
- if (sys->requested_mute >= 0)
- {
- mute = sys->requested_mute ? TRUE : FALSE;
-
- hr = ISimpleAudioVolume_SetMute(volume, mute, NULL);
- if (FAILED(hr))
- msg_Err(aout, "cannot set mute (error 0x%lX)", hr);
- }
- sys->requested_mute = -1;
+ MMSessionMainloop(aout, volume);
- if (SUCCEEDED(hr))
- aout_MuteReport(aout, mute != FALSE);
- }
-
- SleepConditionVariableCS(&sys->work, &sys->lock, INFINITE);
- }
- LeaveCriticalSection(&sys->lock);
+ vlc_mutex_unlock(&sys->lock);
if (endpoint != NULL)
IAudioEndpointVolume_Release(endpoint);
@@ -1036,7 +1084,7 @@ static HRESULT MMSession(audio_output_t *aout, IMMDeviceEnumerator *it)
IAudioSessionManager_Release(manager);
}
- EnterCriticalSection(&sys->lock);
+ vlc_mutex_lock(&sys->lock);
IMMDevice_Release(sys->dev);
sys->dev = NULL;
return S_OK;
@@ -1064,14 +1112,18 @@ static void *MMThread(void *data)
if (FAILED(hr))
msg_Warn(aout, "cannot enumerate audio endpoints (error 0x%lX)", hr);
- EnterCriticalSection(&sys->lock);
+ vlc_mutex_lock(&sys->lock);
do
if (sys->requested_device == NULL || FAILED(MMSession(aout, it)))
- SleepConditionVariableCS(&sys->work, &sys->lock, INFINITE);
+ {
+ vlc_mutex_unlock(&sys->lock);
+ WaitForSingleObject(sys->work_event, INFINITE);
+ vlc_mutex_lock(&sys->lock);
+ }
while (sys->it != NULL);
- LeaveCriticalSection(&sys->lock);
+ vlc_mutex_unlock(&sys->lock);
IMMDeviceEnumerator_UnregisterEndpointNotificationCallback(it,
&sys->device_events);
@@ -1127,23 +1179,23 @@ static int Start(audio_output_t *aout, audio_sample_format_t *restrict fmt)
}
}
- aout_stream_t *s = vlc_object_create(aout, sizeof (*s));
- if (unlikely(s == NULL))
+ struct aout_stream_owner *owner =
+ aout_stream_owner_New(aout, sizeof (*owner), ActivateDevice);
+ if (unlikely(owner == NULL))
return -1;
-
- s->owner.activate = ActivateDevice;
+ aout_stream_t *s = &owner->s;
EnterMTA();
- EnterCriticalSection(&sys->lock);
+ vlc_mutex_lock(&sys->lock);
if ((sys->request_device_restart && DeviceRestartLocked(aout) != 0)
|| sys->dev == NULL)
{
/* Error if the device restart failed or if a request previously
* failed. */
- LeaveCriticalSection(&sys->lock);
+ vlc_mutex_unlock(&sys->lock);
LeaveMTA();
- vlc_object_delete(s);
+ aout_stream_owner_Delete(owner);
return -1;
}
@@ -1153,7 +1205,7 @@ static int Start(audio_output_t *aout, audio_sample_format_t *restrict fmt)
{
char *modlist = var_InheritString(aout, "mmdevice-backend");
HRESULT hr;
- s->owner.device = sys->dev;
+ owner->device = sys->dev;
module = vlc_module_load(s, "aout stream", modlist,
false, aout_stream_Start, s, fmt, &hr);
@@ -1208,17 +1260,20 @@ static int Start(audio_output_t *aout, audio_sample_format_t *restrict fmt)
}
}
- LeaveCriticalSection(&sys->lock);
- LeaveMTA();
-
if (module == NULL)
{
- vlc_object_delete(s);
+ aout_stream_owner_Delete(owner);
+ vlc_mutex_unlock(&sys->lock);
+ LeaveMTA();
return -1;
}
assert (sys->stream == NULL);
- sys->stream = s;
+ sys->stream = owner;
+
+ vlc_mutex_unlock(&sys->lock);
+ LeaveMTA();
+
aout_GainRequest(aout, sys->gain);
return 0;
}
@@ -1230,10 +1285,10 @@ static void Stop(audio_output_t *aout)
assert(sys->stream != NULL);
EnterMTA();
- aout_stream_Stop(sys->stream);
+ aout_stream_owner_Stop(sys->stream);
LeaveMTA();
- vlc_object_delete(sys->stream);
+ aout_stream_owner_Delete(sys->stream);
sys->stream = NULL;
}
@@ -1265,9 +1320,12 @@ static int Open(vlc_object_t *obj)
if (!var_CreateGetBool(aout, "volume-save"))
VolumeSetLocked(aout, var_InheritFloat(aout, "mmdevice-volume"));
- InitializeCriticalSection(&sys->lock);
- InitializeConditionVariable(&sys->work);
- InitializeConditionVariable(&sys->ready);
+ vlc_mutex_init(&sys->lock);
+ vlc_cond_init(&sys->ready);
+
+ sys->work_event = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if (unlikely(sys->work_event == NULL))
+ goto error;
aout_HotplugReport(aout, default_device_b, _("Default"));
@@ -1308,10 +1366,10 @@ static int Open(vlc_object_t *obj)
goto error;
}
- EnterCriticalSection(&sys->lock);
+ vlc_mutex_lock(&sys->lock);
while (sys->requested_device != NULL)
- SleepConditionVariableCS(&sys->ready, &sys->lock, INFINITE);
- LeaveCriticalSection(&sys->lock);
+ vlc_cond_wait(&sys->ready, &sys->lock);
+ vlc_mutex_unlock(&sys->lock);
LeaveMTA(); /* Leave MTA after thread has entered MTA */
aout->start = Start;
@@ -1327,7 +1385,8 @@ static int Open(vlc_object_t *obj)
return VLC_SUCCESS;
error:
- DeleteCriticalSection(&sys->lock);
+ if (sys->work_event != NULL)
+ CloseHandle(sys->work_event);
free(sys);
return VLC_EGENERIC;
}
@@ -1337,14 +1396,15 @@ static void Close(vlc_object_t *obj)
audio_output_t *aout = (audio_output_t *)obj;
aout_sys_t *sys = aout->sys;
- EnterCriticalSection(&sys->lock);
+ vlc_mutex_lock(&sys->lock);
sys->requested_device = default_device; /* break out of MMSession() loop */
sys->it = NULL; /* break out of MMThread() loop */
- WakeConditionVariable(&sys->work);
- LeaveCriticalSection(&sys->lock);
+ vlc_mutex_unlock(&sys->lock);
+
+ SetEvent(sys->work_event);
vlc_join(sys->thread, NULL);
- DeleteCriticalSection(&sys->lock);
+ CloseHandle(sys->work_event);
free(sys);
}
=====================================
modules/audio_output/mmdevice.h
=====================================
@@ -41,14 +41,29 @@ struct aout_stream
HRESULT (*play)(aout_stream_t *, block_t *, vlc_tick_t);
HRESULT (*pause)(aout_stream_t *, bool);
HRESULT (*flush)(aout_stream_t *);
+};
- struct
- {
- void *device;
- HRESULT (*activate)(void *device, REFIID, PROPVARIANT *, void **);
- } owner;
+struct aout_stream_owner
+{
+ aout_stream_t s;
+ void *device;
+ HRESULT (*activate)(void *device, REFIID, PROPVARIANT *, void **);
+ HANDLE buffer_ready_event;
+
+ block_t *chain;
+ block_t **last;
};
+/*
+ * "aout output" helpers
+ */
+
+static inline
+struct aout_stream_owner *aout_stream_owner(aout_stream_t *s)
+{
+ return container_of(s, struct aout_stream_owner, s);
+}
+
/**
* Creates an audio output stream on a given Windows multimedia device.
* \param s audio output stream object to be initialized
@@ -61,36 +76,140 @@ typedef HRESULT (*aout_stream_start_t)(aout_stream_t *s,
/**
* Destroys an audio output stream.
*/
-static inline void aout_stream_Stop(aout_stream_t *s)
+static inline
+void aout_stream_owner_Stop(struct aout_stream_owner *owner)
+{
+ owner->s.stop(&owner->s);
+}
+
+static inline
+HRESULT aout_stream_owner_TimeGet(struct aout_stream_owner *owner,
+ vlc_tick_t *delay)
{
- (s->stop)(s);
+ HRESULT hr = owner->s.time_get(&owner->s, delay);
+
+ if (SUCCEEDED(hr))
+ {
+ /* Add the block chain delay */
+ vlc_tick_t length;
+ block_ChainProperties(owner->chain, NULL, NULL, &length);
+ *delay += length;
+ }
+ return hr;
}
-static inline HRESULT aout_stream_TimeGet(aout_stream_t *s, vlc_tick_t *delay)
+static inline
+HRESULT aout_stream_owner_Play(struct aout_stream_owner *owner,
+ block_t *block, vlc_tick_t date)
{
- return (s->time_get)(s, delay);
+ return owner->s.play(&owner->s, block, date);
}
-static inline HRESULT aout_stream_Play(aout_stream_t *s, block_t *block,
- vlc_tick_t date)
+static inline
+HRESULT aout_stream_owner_Pause(struct aout_stream_owner *owner, bool paused)
{
- return (s->play)(s, block, date);
+ return owner->s.pause(&owner->s, paused);
}
-static inline HRESULT aout_stream_Pause(aout_stream_t *s, bool paused)
+static inline
+HRESULT aout_stream_owner_Flush(struct aout_stream_owner *owner)
{
- return (s->pause)(s, paused);
+ block_ChainRelease(owner->chain);
+ owner->chain = NULL;
+ owner->last = &owner->chain;
+
+ return owner->s.flush(&owner->s);
}
-static inline HRESULT aout_stream_Flush(aout_stream_t *s)
+static inline
+void aout_stream_owner_AppendBlock(struct aout_stream_owner *owner,
+ block_t *block, vlc_tick_t date)
{
- return (s->flush)(s);
+ block->i_dts = date;
+ block_ChainLastAppend(&owner->last, block);
}
+static inline
+HRESULT aout_stream_owner_PlayAll(struct aout_stream_owner *owner)
+{
+ HRESULT hr;
+
+ block_t *block = owner->chain, *next;
+ while (block != NULL)
+ {
+ next = block->p_next;
+
+ vlc_tick_t date = block->i_dts;
+ block->i_dts = VLC_TICK_INVALID;
+
+ hr = aout_stream_owner_Play(owner, block, date);
+
+ if (hr == S_FALSE)
+ return hr;
+ else
+ {
+ block = owner->chain = next;
+ if (FAILED(hr))
+ {
+ if (block == NULL)
+ owner->last = &owner->chain;
+ return hr;
+ }
+ }
+ }
+ owner->last = &owner->chain;
+
+ return S_OK;
+}
+
+static inline
+void *aout_stream_owner_New(audio_output_t *aout, size_t size,
+ HRESULT (*activate)(void *device, REFIID, PROPVARIANT *, void **))
+{
+ assert(size >= sizeof(struct aout_stream_owner));
+
+ void *obj = vlc_object_create(aout, size);
+ if (unlikely(obj == NULL))
+ return NULL;
+ struct aout_stream_owner *owner = obj;
+
+ owner->chain = NULL;
+ owner->last = &owner->chain;
+ owner->activate = activate;
+
+ owner->buffer_ready_event = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if (unlikely(owner->buffer_ready_event == NULL))
+ {
+ vlc_object_delete(&owner->s);
+ return NULL;
+ }
+
+ return obj;
+}
+
+static inline
+void aout_stream_owner_Delete(struct aout_stream_owner *owner)
+{
+ CloseHandle(owner->buffer_ready_event);
+ vlc_object_delete(&owner->s);
+}
+
+/*
+ * "aout stream" helpers
+ */
+
static inline
HRESULT aout_stream_Activate(aout_stream_t *s, REFIID iid,
PROPVARIANT *actparms, void **pv)
{
- return s->owner.activate(s->owner.device, iid, actparms, pv);
+ struct aout_stream_owner *owner = aout_stream_owner(s);
+ return owner->activate(owner->device, iid, actparms, pv);
+}
+
+static inline
+HANDLE aout_stream_GetBufferReadyEvent(aout_stream_t *s)
+{
+ struct aout_stream_owner *owner = aout_stream_owner(s);
+ return owner->buffer_ready_event;
}
#endif
=====================================
modules/audio_output/wasapi.c
=====================================
@@ -313,8 +313,10 @@ static HRESULT Play(aout_stream_t *s, block_t *block, vlc_tick_t date)
if (block->i_nb_samples == 0)
break; /* done */
- /* Out of buffer space, sleep */
- vlc_tick_sleep(sys->frames * VLC_TICK_FROM_MS(500) / sys->rate);
+ block->i_length -= vlc_tick_from_samples(frames, sys->rate);
+ /* Out of buffer space, keep the block and notify the owner */
+ IAudioRenderClient_Release(render);
+ return S_FALSE;
}
IAudioRenderClient_Release(render);
out:
@@ -902,8 +904,9 @@ static HRESULT Start(aout_stream_t *s, audio_sample_format_t *restrict pfmt,
if (sys->s24s32)
msg_Dbg(s, "audio device configured as s24");
- hr = IAudioClient_Initialize(sys->client, shared_mode, 0, buffer_duration,
- 0, pwf, sid);
+ hr = IAudioClient_Initialize(sys->client, shared_mode,
+ AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
+ buffer_duration, 0, pwf, sid);
CoTaskMemFree(pwf_closest);
if (FAILED(hr))
{
@@ -911,6 +914,14 @@ static HRESULT Start(aout_stream_t *s, audio_sample_format_t *restrict pfmt,
goto error;
}
+ hr = IAudioClient_SetEventHandle(sys->client,
+ aout_stream_GetBufferReadyEvent(s));
+ if (FAILED(hr))
+ {
+ msg_Err(s, "cannot set audio client EventHandle (error 0x%lX)", hr);
+ goto error;
+ }
+
hr = IAudioClient_GetBufferSize(sys->client, &sys->frames);
if (FAILED(hr))
{
=====================================
modules/audio_output/winstore.c
=====================================
@@ -55,7 +55,7 @@ static void LeaveMTA(void)
typedef struct
{
- aout_stream_t *stream; /**< Underlying audio output stream */
+ struct aout_stream_owner *stream; /**< Underlying audio output stream */
module_t *module;
IAudioClient *client;
wchar_t* acquired_device;
@@ -68,9 +68,12 @@ typedef struct
IActivateAudioInterfaceCompletionHandler client_locator;
vlc_sem_t async_completed;
LONG refs;
- CRITICAL_SECTION lock;
-} aout_sys_t;
+ vlc_mutex_t lock;
+ vlc_thread_t thread;
+ bool stopping;
+ HANDLE work_event;
+} aout_sys_t;
/* MMDeviceLocator IUnknown methods */
static STDMETHODIMP_(ULONG) MMDeviceLocator_AddRef(IActivateAudioInterfaceCompletionHandler *This)
@@ -257,9 +260,9 @@ static int DeviceSelectLocked(audio_output_t *aout, const char* id)
static int DeviceSelect(audio_output_t *aout, const char* id)
{
aout_sys_t *sys = aout->sys;
- EnterCriticalSection(&sys->lock);
+ vlc_mutex_lock(&sys->lock);
int ret = DeviceSelectLocked(aout, id);
- LeaveCriticalSection(&sys->lock);
+ vlc_mutex_unlock(&sys->lock);
return ret;
}
@@ -355,12 +358,20 @@ done:
static int TimeGet(audio_output_t *aout, vlc_tick_t *restrict delay)
{
aout_sys_t *sys = aout->sys;
- if( unlikely( sys->client == NULL ) )
- return VLC_EGENERIC;
HRESULT hr;
EnterMTA();
- hr = aout_stream_TimeGet(sys->stream, delay);
+ vlc_mutex_lock(&sys->lock);
+ if (unlikely(sys->client == NULL))
+ {
+ vlc_mutex_unlock(&sys->lock);
+ LeaveMTA();
+ return -1;
+ }
+
+ hr = aout_stream_owner_TimeGet(sys->stream, delay);
+
+ vlc_mutex_unlock(&sys->lock);
LeaveMTA();
return SUCCEEDED(hr) ? 0 : -1;
@@ -369,28 +380,37 @@ static int TimeGet(audio_output_t *aout, vlc_tick_t *restrict delay)
static void Play(audio_output_t *aout, block_t *block, vlc_tick_t date)
{
aout_sys_t *sys = aout->sys;
- if( unlikely( sys->client == NULL ) )
+
+ vlc_mutex_lock(&sys->lock);
+ if (unlikely(sys->client == NULL))
{
block_Release(block);
+ vlc_mutex_unlock(&sys->lock);
return;
}
- EnterMTA();
- HRESULT hr = aout_stream_Play(sys->stream, block, date);
- LeaveMTA();
+ aout_stream_owner_AppendBlock(sys->stream, block, date);
- ResetInvalidatedClient(aout, hr);
- (void) date;
+ vlc_mutex_unlock(&sys->lock);
+ SetEvent(sys->work_event);
}
static void Pause(audio_output_t *aout, bool paused, vlc_tick_t date)
{
aout_sys_t *sys = aout->sys;
- if( unlikely( sys->client == NULL ) )
- return;
EnterMTA();
- HRESULT hr = aout_stream_Pause(sys->stream, paused);
+ vlc_mutex_lock(&sys->lock);
+ if (unlikely(sys->client == NULL))
+ {
+ vlc_mutex_unlock(&sys->lock);
+ LeaveMTA();
+ return;
+ }
+
+ HRESULT hr = aout_stream_owner_Pause(sys->stream, paused);
+
+ vlc_mutex_unlock(&sys->lock);
LeaveMTA();
(void) date;
@@ -400,16 +420,81 @@ static void Pause(audio_output_t *aout, bool paused, vlc_tick_t date)
static void Flush(audio_output_t *aout)
{
aout_sys_t *sys = aout->sys;
- if( unlikely( sys->client == NULL ) )
- return;
EnterMTA();
- HRESULT hr = aout_stream_Flush(sys->stream);
+ vlc_mutex_lock(&sys->lock);
+ if (unlikely(sys->client == NULL))
+ {
+ vlc_mutex_unlock(&sys->lock);
+ LeaveMTA();
+ return;
+ }
+
+ HRESULT hr = aout_stream_owner_Flush(sys->stream);
+
+ vlc_mutex_unlock(&sys->lock);
LeaveMTA();
ResetInvalidatedClient(aout, hr);
}
+static void *PlaybackThread(void *data)
+{
+ audio_output_t *aout = data;
+ aout_sys_t *sys = aout->sys;
+ struct aout_stream_owner *owner = sys->stream;
+
+ vlc_thread_set_name("vlc-winstore");
+
+ EnterMTA();
+ vlc_mutex_lock(&sys->lock);
+
+ while (true)
+ {
+ DWORD ev_count = 1;
+ HANDLE events[2] = {
+ sys->work_event,
+ NULL
+ };
+ /* Don't listen to the stream event if the block fifo is empty */
+ if (sys->stream != NULL && sys->stream->chain != NULL)
+ events[ev_count++] = owner->buffer_ready_event;
+
+ vlc_mutex_unlock(&sys->lock);
+ WaitForMultipleObjects(ev_count, events, FALSE, INFINITE);
+ vlc_mutex_lock(&sys->lock);
+
+ if (sys->stopping)
+ break;
+
+ if (likely(sys->client != NULL))
+ {
+ HRESULT hr = aout_stream_owner_PlayAll(sys->stream);
+
+ /* Don't call ResetInvalidatedClient here since this function lock
+ * the current mutex */
+
+ if (unlikely(hr == AUDCLNT_E_DEVICE_INVALIDATED ||
+ hr == AUDCLNT_E_RESOURCES_INVALIDATED))
+ {
+ DeviceSelectLocked(aout, NULL);
+ if (sys->client == NULL)
+ {
+ /* Impossible to recover */
+ block_ChainRelease(owner->chain);
+ owner->chain = NULL;
+ owner->last = &owner->chain;
+ }
+ }
+ }
+ }
+
+ vlc_mutex_unlock(&sys->lock);
+ LeaveMTA();
+
+ return NULL;
+}
+
static HRESULT ActivateDevice(void *opaque, REFIID iid, PROPVARIANT *actparms,
void **restrict pv)
{
@@ -443,13 +528,15 @@ static int Start(audio_output_t *aout, audio_sample_format_t *restrict fmt)
aout_sys_t *sys = aout->sys;
HRESULT hr;
- aout_stream_t *s = vlc_object_create(aout, sizeof (*s));
- if (unlikely(s == NULL))
+ struct aout_stream_owner *owner =
+ aout_stream_owner_New(aout, sizeof (*owner), ActivateDevice);
+ if (unlikely(owner == NULL))
return -1;
+ aout_stream_t *s = &owner->s;
// Load the "out stream" for the requested device
EnterMTA();
- EnterCriticalSection(&sys->lock);
+ vlc_mutex_lock(&sys->lock);
if (sys->requested_device != NULL)
{
@@ -459,18 +546,26 @@ static int Start(audio_output_t *aout, audio_sample_format_t *restrict fmt)
DeviceRestartLocked(aout);
if (sys->client == NULL)
{
- LeaveCriticalSection(&sys->lock);
+ vlc_mutex_unlock(&sys->lock);
LeaveMTA();
- vlc_object_delete(&s->obj);
+ aout_stream_owner_Delete(owner);
return -1;
}
}
}
- s->owner.activate = ActivateDevice;
+ sys->work_event = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if (unlikely(sys->work_event == NULL))
+ {
+ vlc_mutex_unlock(&sys->lock);
+ LeaveMTA();
+ aout_stream_owner_Delete(owner);
+ return -1;
+ }
+
for (;;)
{
- s->owner.device = sys->client;
+ owner->device = sys->client;
sys->module = vlc_module_load(s, "aout stream", NULL, false,
aout_stream_Start, s, fmt, &hr);
@@ -538,15 +633,23 @@ static int Start(audio_output_t *aout, audio_sample_format_t *restrict fmt)
ISimpleAudioVolume_Release(pc_AudioVolume);
}
- LeaveCriticalSection(&sys->lock);
- LeaveMTA();
-
if (sys->module == NULL)
+ goto error;
+
+ assert (sys->stream == NULL);
+ sys->stream = owner;
+ sys->stopping = false;
+
+ if (vlc_clone(&sys->thread, PlaybackThread, aout))
{
- vlc_object_delete(s);
- return -1;
+ aout_stream_owner_Stop(sys->stream);
+ sys->stream = NULL;
+ goto error;
}
+ vlc_mutex_unlock(&sys->lock);
+ LeaveMTA();
+
if (sys->client)
{
// the requested device has been used, reset it
@@ -554,9 +657,14 @@ static int Start(audio_output_t *aout, audio_sample_format_t *restrict fmt)
SetRequestedDevice(aout, NULL);
}
- assert (sys->stream == NULL);
- sys->stream = s;
return 0;
+
+error:
+ CloseHandle(sys->work_event);
+ aout_stream_owner_Delete(owner);
+ vlc_mutex_unlock(&sys->lock);
+ LeaveMTA();
+ return -1;
}
static void Stop(audio_output_t *aout)
@@ -565,11 +673,18 @@ static void Stop(audio_output_t *aout)
assert (sys->stream != NULL);
+ vlc_mutex_lock(&sys->lock);
+ sys->stopping = true;
+ vlc_mutex_unlock(&sys->lock);
+ SetEvent(sys->work_event);
+ vlc_join(sys->thread, NULL);
+
EnterMTA();
- aout_stream_Stop(sys->stream);
+ aout_stream_owner_Stop(sys->stream);
LeaveMTA();
- vlc_object_delete(sys->stream);
+ CloseHandle(sys->work_event);
+ aout_stream_owner_Delete(sys->stream);
sys->stream = NULL;
}
@@ -595,7 +710,7 @@ static int Open(vlc_object_t *obj)
free(psz_default);
}
- InitializeCriticalSection(&sys->lock);
+ vlc_mutex_init(&sys->lock);
vlc_sem_init(&sys->async_completed, 0);
sys->refs = 0;
@@ -633,7 +748,6 @@ static void Close(vlc_object_t *obj)
if (sys->requested_device != sys->default_device)
free(sys->requested_device);
CoTaskMemFree(sys->default_device);
- DeleteCriticalSection(&sys->lock);
free(sys);
}
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/5eb783fd44ed6298db3e38f7765f21c42e4405f9...02c95ad3816366ea2a4da4a599ba7e53545ef4e6
--
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/5eb783fd44ed6298db3e38f7765f21c42e4405f9...02c95ad3816366ea2a4da4a599ba7e53545ef4e6
You're receiving this email because of your account on code.videolan.org.
VideoLAN code repository instance
More information about the vlc-commits
mailing list