opensles: Work around race condition in Android < 4.2 that leads to deadlocks on...
authorSebastian Dröge <sebastian@centricular.com>
Fri, 16 May 2014 07:10:48 +0000 (09:10 +0200)
committerSebastian Dröge <sebastian@centricular.com>
Fri, 16 May 2014 07:10:48 +0000 (09:10 +0200)
commitc842df1c3dd8bb76d139b9808dc4ed00a53eb62e
tree33d903247c40cfd31a82a6de63758a6e9b8836c9
parent43f3f837fa9b3219787cf5b0646b7803d071a681
opensles: Work around race condition in Android < 4.2 that leads to deadlocks on shutdown

We need to sleep a bit before destroying the player object
because of a bug in Android in versions < 4.2.

OpenSLES is using AudioTrack for rendering the sound. AudioTrack
has a thread that pulls raw audio from the buffer queue and then
passes it forward to AudioFlinger (AudioTrack::processAudioBuffer()).
This thread is calling various callbacks on events, e.g. when
an underrun happens or to request data. OpenSLES sets this callback
on AudioTrack (audioTrack_callBack_pullFromBuffQueue() from
android_AudioPlayer.cpp). Among other things this is taking a lock
on the player interface.

Now if we destroy the player interface object, it will first of all
take the player interface lock (IObject_Destroy()). Then it destroys
the audio player instance (android_audioPlayer_destroy()) which then
calls stop() on the AudioTrack and deletes it. Now the destructor of
AudioTrack will wait until the rendering thread (AudioTrack::processAudioBuffer())
has finished.

If all this happens with bad timing it can happen that the rendering
thread is currently e.g. handling underrun but did not lock the player
interface object yet. Then destroying happens and takes the lock and waits
for the thread to finish. Then the thread tries to take the lock and waits
forever.

We wait a bit before destroying the player object to make sure that
the rendering thread finished whatever it was doing, and then stops
(note: we called gst_opensles_ringbuffer_stop() before this already).
sys/opensles/openslesringbuffer.c