osxaudio: Fix lockup in _audio_unit_property_listener

_audio_unit_property_listener is called either from a Core Audio thread
or as a result of a Core Audio API (e.g. AudioUnitInitialize)
from our own thread. In the latter case, osxbuf can be already locked
(GStreamer's mutex is not recursive).

We introduce the flag cached_caps_valid and use it instead of nullifying
cached_caps when we cannot lock on osxbuf.

https://bugzilla.gnome.org/show_bug.cgi?id=743758
This commit is contained in:
Ilya Konstantinov 2015-03-21 20:34:25 +02:00 committed by Arun Raghavan
parent a8b2666aa7
commit f107f7306b
4 changed files with 16 additions and 6 deletions

View file

@ -344,7 +344,7 @@ gst_osx_audio_sink_getcaps (GstBaseSink * sink, GstCaps * filter)
/* protect against cached_caps going away */ /* protect against cached_caps going away */
GST_OBJECT_LOCK (buf); GST_OBJECT_LOCK (buf);
if (osxbuf->core_audio->cached_caps) { if (osxbuf->core_audio->cached_caps_valid) {
GST_LOG_OBJECT (sink, "Returning cached caps"); GST_LOG_OBJECT (sink, "Returning cached caps");
caps = gst_caps_ref (osxbuf->core_audio->cached_caps); caps = gst_caps_ref (osxbuf->core_audio->cached_caps);
} else if (buf->open) { } else if (buf->open) {

View file

@ -265,7 +265,7 @@ gst_osx_audio_src_get_caps (GstBaseSrc * src, GstCaps * filter)
/* protect against cached_caps going away */ /* protect against cached_caps going away */
GST_OBJECT_LOCK (buf); GST_OBJECT_LOCK (buf);
if (osxbuf->core_audio->cached_caps) { if (osxbuf->core_audio->cached_caps_valid) {
GST_LOG_OBJECT (src, "Returning cached caps"); GST_LOG_OBJECT (src, "Returning cached caps");
caps = gst_caps_ref (osxbuf->core_audio->cached_caps); caps = gst_caps_ref (osxbuf->core_audio->cached_caps);
} else if (buf->open) { } else if (buf->open) {

View file

@ -49,6 +49,7 @@ gst_core_audio_init (GstCoreAudio * core_audio)
core_audio->is_src = FALSE; core_audio->is_src = FALSE;
core_audio->audiounit = NULL; core_audio->audiounit = NULL;
core_audio->cached_caps = NULL; core_audio->cached_caps = NULL;
core_audio->cached_caps_valid = FALSE;
#ifndef HAVE_IOS #ifndef HAVE_IOS
core_audio->hog_pid = -1; core_audio->hog_pid = -1;
core_audio->disabled_mixing = FALSE; core_audio->disabled_mixing = FALSE;
@ -83,10 +84,13 @@ _audio_unit_property_listener (void *inRefCon, AudioUnit inUnit,
* as needed. * as needed.
* This merely "refreshes" our PREFERRED caps. */ * This merely "refreshes" our PREFERRED caps. */
/* protect against cached_caps going away */ /* This function is called either from a Core Audio thread
GST_OBJECT_LOCK (core_audio->osxbuf); * or as a result of a Core Audio API (e.g. AudioUnitInitialize)
gst_caps_replace (&core_audio->cached_caps, NULL); * from our own thread. In the latter case, osxbuf can be
GST_OBJECT_UNLOCK (core_audio->osxbuf); * already locked (GStreamer's mutex is not recursive).
* For this reason we use a boolean flag instead of nullifying
* cached_caps. */
core_audio->cached_caps_valid = FALSE;
} }
break; break;
} }
@ -128,6 +132,7 @@ gst_core_audio_close (GstCoreAudio * core_audio)
core_audio); core_audio);
/* core_audio->osxbuf is already locked at this point */ /* core_audio->osxbuf is already locked at this point */
core_audio->cached_caps_valid = FALSE;
gst_caps_replace (&core_audio->cached_caps, NULL); gst_caps_replace (&core_audio->cached_caps, NULL);
AudioComponentInstanceDispose (core_audio->audiounit); AudioComponentInstanceDispose (core_audio->audiounit);
@ -140,6 +145,10 @@ gst_core_audio_open (GstCoreAudio * core_audio)
{ {
OSStatus status; OSStatus status;
/* core_audio->osxbuf is already locked at this point */
core_audio->cached_caps_valid = FALSE;
gst_caps_replace (&core_audio->cached_caps, NULL);
if (!gst_core_audio_open_impl (core_audio)) if (!gst_core_audio_open_impl (core_audio))
return FALSE; return FALSE;

View file

@ -88,6 +88,7 @@ struct _GstCoreAudio
gboolean is_src; gboolean is_src;
gboolean is_passthrough; gboolean is_passthrough;
AudioDeviceID device_id; AudioDeviceID device_id;
gboolean cached_caps_valid; /* thread-safe flag */
GstCaps *cached_caps; GstCaps *cached_caps;
gint stream_idx; gint stream_idx;
gboolean io_proc_active; gboolean io_proc_active;