summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNirbheek Chauhan <nirbheek@centricular.com>2019-01-15 02:03:23 +0530
committerTim-Philipp Müller <tim@centricular.com>2019-05-02 10:03:17 +0100
commitee169f14f42734aa444d2da884d84873e917cc95 (patch)
tree2548d000d7f6813b13b96b0925653b4dec7d4898
parentd93d62e287113a9f1fe6e4dde35c810dbf04a239 (diff)
downloadgstreamer-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.c38
-rw-r--r--sys/wasapi/gstwasapisrc.c32
-rw-r--r--sys/wasapi/gstwasapiutil.h24
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
{