diff options
author | Nirbheek Chauhan <nirbheek@centricular.com> | 2019-01-15 02:03:23 +0530 |
---|---|---|
committer | Tim-Philipp Müller <tim@centricular.com> | 2019-05-02 10:03:17 +0100 |
commit | ee169f14f42734aa444d2da884d84873e917cc95 (patch) | |
tree | 2548d000d7f6813b13b96b0925653b4dec7d4898 | |
parent | d93d62e287113a9f1fe6e4dde35c810dbf04a239 (diff) | |
download | gstreamer-plugins-bad-ee169f14f42734aa444d2da884d84873e917cc95.tar.gz |
wasapi: Fix infinite loop when the device disappears
When the audio device goes away during playback or capture, we were
going into an infinite loop of AUDCLNT_E_DEVICE_INVALIDATED. Return -1
and post an error message so the ringbuffer thread exits with an error.
-rw-r--r-- | sys/wasapi/gstwasapisink.c | 38 | ||||
-rw-r--r-- | sys/wasapi/gstwasapisrc.c | 32 | ||||
-rw-r--r-- | sys/wasapi/gstwasapiutil.h | 24 |
3 files changed, 67 insertions, 27 deletions
diff --git a/sys/wasapi/gstwasapisink.c b/sys/wasapi/gstwasapisink.c index 0a5f85d81..47c456422 100644 --- a/sys/wasapi/gstwasapisink.c +++ b/sys/wasapi/gstwasapisink.c @@ -458,7 +458,7 @@ gst_wasapi_sink_get_can_frames (GstWasapiSink * self) /* Frames the card hasn't rendered yet */ hr = IAudioClient_GetCurrentPadding (self->client, &n_frames_padding); - HR_FAILED_RET (hr, IAudioClient::GetCurrentPadding, -1); + HR_FAILED_ELEMENT_ERROR_RET (hr, IAudioClient::GetCurrentPadding, self, -1); GST_DEBUG_OBJECT (self, "%i unread frames (padding)", n_frames_padding); @@ -603,8 +603,8 @@ gst_wasapi_sink_write (GstAudioSink * asink, gpointer data, guint length) GST_OBJECT_LOCK (self); if (self->client_needs_restart) { hr = IAudioClient_Start (self->client); - HR_FAILED_AND (hr, IAudioClient::Start, GST_OBJECT_UNLOCK (self); - goto beach); + HR_FAILED_ELEMENT_ERROR_AND (hr, IAudioClient::Start, self, + GST_OBJECT_UNLOCK (self); goto err); self->client_needs_restart = FALSE; } GST_OBJECT_UNLOCK (self); @@ -618,32 +618,43 @@ gst_wasapi_sink_write (GstAudioSink * asink, gpointer data, guint length) if (dwWaitResult != WAIT_OBJECT_0) { GST_ERROR_OBJECT (self, "Error waiting for event handle: %x", (guint) dwWaitResult); - goto beach; + goto err; } can_frames = gst_wasapi_sink_get_can_frames (self); + if (can_frames < 0) { + GST_ERROR_OBJECT (self, "Error getting frames to write to"); + goto err; + } /* In exclusive mode we need to fill the whole buffer in one go or * GetBuffer will error out */ if (can_frames != have_frames) { GST_ERROR_OBJECT (self, "Need at %i frames to write for exclusive mode, but got %i", can_frames, have_frames); - written_len = -1; - goto beach; + goto err; } } else { /* In shared mode we can write parts of the buffer, so only wait * in case we can't write anything */ can_frames = gst_wasapi_sink_get_can_frames (self); + if (can_frames < 0) { + GST_ERROR_OBJECT (self, "Error getting frames to write to"); + goto err; + } if (can_frames == 0) { dwWaitResult = WaitForSingleObject (self->event_handle, INFINITE); if (dwWaitResult != WAIT_OBJECT_0) { GST_ERROR_OBJECT (self, "Error waiting for event handle: %x", (guint) dwWaitResult); - goto beach; + goto err; } can_frames = gst_wasapi_sink_get_can_frames (self); + if (can_frames < 0) { + GST_ERROR_OBJECT (self, "Error getting frames to write to"); + goto err; + } } } @@ -657,19 +668,24 @@ gst_wasapi_sink_write (GstAudioSink * asink, gpointer data, guint length) hr = IAudioRenderClient_GetBuffer (self->render_client, n_frames, (BYTE **) & dst); - HR_FAILED_AND (hr, IAudioRenderClient::GetBuffer, goto beach); + HR_FAILED_ELEMENT_ERROR_AND (hr, IAudioRenderClient::GetBuffer, self, + goto err); memcpy (dst, data, write_len); hr = IAudioRenderClient_ReleaseBuffer (self->render_client, n_frames, self->mute ? AUDCLNT_BUFFERFLAGS_SILENT : 0); - HR_FAILED_AND (hr, IAudioRenderClient::ReleaseBuffer, goto beach); + HR_FAILED_ELEMENT_ERROR_AND (hr, IAudioRenderClient::ReleaseBuffer, self, + goto err); written_len = write_len; -beach: - +out: return written_len; + +err: + written_len = -1; + goto out; } static guint diff --git a/sys/wasapi/gstwasapisrc.c b/sys/wasapi/gstwasapisrc.c index 07f51aa89..71de12cd2 100644 --- a/sys/wasapi/gstwasapisrc.c +++ b/sys/wasapi/gstwasapisrc.c @@ -545,7 +545,8 @@ gst_wasapi_src_read (GstAudioSrc * asrc, gpointer data, guint length, GST_OBJECT_LOCK (self); if (self->client_needs_restart) { hr = IAudioClient_Start (self->client); - HR_FAILED_AND (hr, IAudioClient::Start, length = 0; goto beach); + HR_FAILED_ELEMENT_ERROR_AND (hr, IAudioClient::Start, self, + GST_OBJECT_UNLOCK (self); goto err); self->client_needs_restart = FALSE; } GST_OBJECT_UNLOCK (self); @@ -559,23 +560,22 @@ gst_wasapi_src_read (GstAudioSrc * asrc, gpointer data, guint length, if (dwWaitResult != WAIT_OBJECT_0) { GST_ERROR_OBJECT (self, "Error waiting for event handle: %x", (guint) dwWaitResult); - length = 0; - goto beach; + goto err; } hr = IAudioCaptureClient_GetBuffer (self->capture_client, (BYTE **) & from, &have_frames, &flags, NULL, NULL); if (hr != S_OK) { - gchar *msg = gst_wasapi_util_hresult_to_string (hr); - if (hr == AUDCLNT_S_BUFFER_EMPTY) + if (hr == AUDCLNT_S_BUFFER_EMPTY) { + gchar *msg = gst_wasapi_util_hresult_to_string (hr); GST_WARNING_OBJECT (self, "IAudioCaptureClient::GetBuffer failed: %s" ", retrying", msg); - else - GST_ERROR_OBJECT (self, "IAudioCaptureClient::GetBuffer failed: %s", - msg); - g_free (msg); - length = 0; - goto beach; + g_free (msg); + length = 0; + goto out; + } + HR_FAILED_ELEMENT_ERROR_AND (hr, IAudioCaptureClient::GetBuffer, self, + goto err); } if (flags != 0) @@ -612,13 +612,17 @@ gst_wasapi_src_read (GstAudioSrc * asrc, gpointer data, guint length, /* Always release all captured buffers if we've captured any at all */ hr = IAudioCaptureClient_ReleaseBuffer (self->capture_client, have_frames); - HR_FAILED_AND (hr, IAudioClock::ReleaseBuffer, goto beach); + HR_FAILED_ELEMENT_ERROR_AND (hr, IAudioCaptureClient::ReleaseBuffer, self, + goto err); } -beach: - +out: return length; + +err: + length = -1; + goto out; } static guint diff --git a/sys/wasapi/gstwasapiutil.h b/sys/wasapi/gstwasapiutil.h index b11d92b30..3f7ed6d6e 100644 --- a/sys/wasapi/gstwasapiutil.h +++ b/sys/wasapi/gstwasapiutil.h @@ -42,19 +42,39 @@ /* Standard error path */ #define HR_FAILED_AND(hr,func,and) \ - do { \ + G_STMT_START { \ if (FAILED (hr)) { \ gchar *msg = gst_wasapi_util_hresult_to_string (hr); \ GST_ERROR_OBJECT (self, #func " failed (%x): %s", (guint) hr, msg); \ g_free (msg); \ and; \ } \ - } while (0) + } G_STMT_END #define HR_FAILED_RET(hr,func,ret) HR_FAILED_AND(hr,func,return ret) #define HR_FAILED_GOTO(hr,func,where) HR_FAILED_AND(hr,func,res = FALSE; goto where) +#define HR_FAILED_ELEMENT_ERROR_AND(hr,func,el,and) \ + G_STMT_START { \ + if (FAILED (hr)) { \ + gchar *msg = gst_wasapi_util_hresult_to_string (hr); \ + GST_ERROR_OBJECT (el, #func " failed (%x): %s", (guint) hr, msg); \ + if (GST_IS_AUDIO_SRC (el)) \ + GST_ELEMENT_ERROR(el, RESOURCE, READ, \ + (#func " failed (%x): %s", (guint) hr, msg), (NULL)); \ + else \ + GST_ELEMENT_ERROR(el, RESOURCE, WRITE, \ + (#func " failed (%x): %s", (guint) hr, msg), (NULL)); \ + g_free (msg); \ + and; \ + } \ + } G_STMT_END + +#define HR_FAILED_ELEMENT_ERROR_RET(hr,func,el,ret) \ + HR_FAILED_ELEMENT_ERROR_AND(hr,func,el,return ret) + + /* Device role enum property */ typedef enum { |