aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid 'Digit' Turner <digit@google.com>2009-08-21 03:05:29 +0200
committerDavid 'Digit' Turner <digit@google.com>2009-08-21 03:05:29 +0200
commit5ad9febb1c7e08fe24413f9bd04f30d92b4cfa3a (patch)
tree97cb688ef7727ee37a721596eee3af9b8c98d0cc
parente4c5bfae9beeb0bbb0e525e4700ae4be9971676f (diff)
downloadexternal_qemu-5ad9febb1c7e08fe24413f9bd04f30d92b4cfa3a.zip
external_qemu-5ad9febb1c7e08fe24413f9bd04f30d92b4cfa3a.tar.gz
external_qemu-5ad9febb1c7e08fe24413f9bd04f30d92b4cfa3a.tar.bz2
Fix EsounD audio backend and bump version number.
The original esdaudio.c file from upstream contains a nasty race condition that can be triggered when the emulator exists while the audio record thread is in a blocking read() call. In this case, exit() will end up calling esd_fini_in which will try to pthread_join() the blocked thread, resulting in a dead-lock. This change just gets rid of the helper threads and just performs audio output and input in the main event loop, avoiding blocking i/o completely. I haven't experienced any difference compared to the original one, be it in audio lag or CPU usage when playing a simple MP3 file in the emulated system. The change also updates the update-audio.sh script since we don't store our sources in p4 anymore. A small fix in common.sh deals removes an obsolete special case that is not needed anymore when determining the location of the host prebuilt binaries. The version number is also bumped to 1.12 and CHANGES.TXT updated accordingly.
-rw-r--r--CHANGES.TXT11
-rw-r--r--android/android.h2
-rw-r--r--android/build/common.sh12
-rw-r--r--audio/esdaudio.c333
-rwxr-xr-xdistrib/update-audio.sh23
5 files changed, 104 insertions, 277 deletions
diff --git a/CHANGES.TXT b/CHANGES.TXT
index 8f276d4..d529ce6 100644
--- a/CHANGES.TXT
+++ b/CHANGES.TXT
@@ -14,7 +14,16 @@ Versions:
1.8 => SDK 1.1
1.9 => SDK 1.5_r1 (and SDK 1.5_r2)
1.10 => SDK 1.5_r3
- 1.11 => current
+ 1.11 => SDK 1.6_r1
+ 1.12 => current
+
+==============================================================================
+Changes between 1.12 and 1.11
+
+IMPORTANT BUG FIXES:
+
+- Fixed a nasty race condition in the Linux EsounD audio backend which resulted
+ in rare lockups when stopping the emulator on this platform.
==============================================================================
Changes between 1.11 and 1.10
diff --git a/android/android.h b/android/android.h
index 6d23e6e..6d092fd 100644
--- a/android/android.h
+++ b/android/android.h
@@ -13,7 +13,7 @@
#define _qemu_android_h
#define ANDROID_VERSION_MAJOR 1
-#define ANDROID_VERSION_MINOR 11
+#define ANDROID_VERSION_MINOR 12
#define CONFIG_SHAPER 1
diff --git a/android/build/common.sh b/android/build/common.sh
index b22ef7d..3f2c642 100644
--- a/android/build/common.sh
+++ b/android/build/common.sh
@@ -444,18 +444,6 @@ locate_android_prebuilt ()
{
# locate prebuilt directory
ANDROID_PREBUILT_HOST_TAG=$OS
- case $OS in
- linux-*)
- # Linux is a special case because in the old tree layout
- # we simply used 'Linux' as the prebuilt host tag, but
- # are now using "linux-x86" in the new layout
- # check which one should be used
- #
- if [ -d $ANDROID_TOP/prebuilt/Linux ] ; then
- PREBUILT_HOST_TAG=Linux
- fi
- ;;
- esac
ANDROID_PREBUILT=$ANDROID_TOP/prebuilt/$ANDROID_PREBUILT_HOST_TAG
if [ ! -d $ANDROID_PREBUILT ] ; then
# this can happen when building on x86_64
diff --git a/audio/esdaudio.c b/audio/esdaudio.c
index 2226022..033d3bc 100644
--- a/audio/esdaudio.c
+++ b/audio/esdaudio.c
@@ -1,7 +1,7 @@
/*
* QEMU ESD audio driver
*
- * Copyright (c) 2008 The Android Open Source Project
+ * Copyright (c) 2008-2009 The Android Open Source Project
* Copyright (c) 2006 Frederick Reeve (brushed up by malc)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -29,7 +29,6 @@
#define AUDIO_CAP "esd"
#include "audio_int.h"
-#include "audio_pt_int.h"
#include <dlfcn.h>
#include "qemu_debug.h"
@@ -60,7 +59,6 @@ typedef struct {
int rpos;
void *pcm_buf;
int fd;
- struct audio_pt pt;
} ESDVoiceOut;
typedef struct {
@@ -71,7 +69,6 @@ typedef struct {
int wpos;
void *pcm_buf;
int fd;
- struct audio_pt pt;
} ESDVoiceIn;
static struct {
@@ -112,128 +109,48 @@ static void GCC_FMT_ATTR (2, 3) qesd_logerr (int err, const char *fmt, ...)
AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err));
}
-/* playback */
-static void *qesd_thread_out (void *arg)
+static int qesd_run_out (HWVoiceOut *hw)
{
- ESDVoiceOut* esd = arg;
- HWVoiceOut* hw = &esd->hw;
- int threshold;
- sigset_t set;
-
- threshold = conf.divisor ? hw->samples / conf.divisor : 0;
-
- if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
- return NULL;
- }
-
- /* ignore SIGALRM in this thread */
- sigemptyset(&set);
- sigaddset(&set, SIGALRM);
-
- pthread_sigmask( SIG_BLOCK, &set, NULL);
-
- O("EsounD output thread starting, threshold is %d samples", threshold);
- for (;;) {
- int decr, to_mix, rpos;
-
- for (;;) {
- if (esd->done) {
- goto exit;
- }
-
- if (esd->live > threshold) {
- break;
- }
-
- if (audio_pt_wait (&esd->pt, AUDIO_FUNC)) {
- O("EsounD output thread aborting on wait error");
- goto exit;
- }
- }
-
- decr = to_mix = esd->live;
- rpos = hw->rpos;
-
- if (audio_pt_unlock (&esd->pt, AUDIO_FUNC)) {
- O("EsounD output thread aborting on unlock error");
- return NULL;
- }
-
- while (to_mix) {
- ssize_t written;
- int chunk = audio_MIN (to_mix, hw->samples - rpos);
- st_sample_t *src = hw->mix_buf + rpos;
-
- hw->clip (esd->pcm_buf, src, chunk);
-
- again:
- written = write (esd->fd, esd->pcm_buf, chunk << hw->info.shift);
- if (written == -1) {
- if (errno == EINTR || errno == EAGAIN) {
- goto again;
- }
- qesd_logerr (errno, "write failed\n");
- O("EsounD output thread aborting on write error: %s", strerror(errno));
- return NULL;
- }
-
- if (written != chunk << hw->info.shift) {
- int wsamples = written >> hw->info.shift;
- int wbytes = wsamples << hw->info.shift;
- if (wbytes != written) {
- dolog ("warning: Misaligned write %d (requested %d), "
- "alignment %d\n",
- wbytes, written, hw->info.align + 1);
- }
- to_mix -= wsamples;
- rpos = (rpos + wsamples) % hw->samples;
+ ESDVoiceOut *esd = (ESDVoiceOut *) hw;
+ int liveSamples, totalSamples;
+ int rpos, nwrite, writeSamples, writeBytes;
+
+ liveSamples = audio_pcm_hw_get_live_out (hw);
+ rpos = hw->rpos;
+ totalSamples = 0;
+
+ while (liveSamples > 0) {
+ int chunkSamples = audio_MIN (liveSamples, hw->samples - rpos);
+ int chunkBytes = chunkSamples << hw->info.shift;
+ st_sample_t *src = hw->mix_buf + rpos;
+
+ hw->clip (esd->pcm_buf, src, chunkSamples);
+
+ AGAIN:
+ nwrite = write (esd->fd, esd->pcm_buf, chunkBytes);
+ if (nwrite == -1) {
+ if (errno == EINTR)
+ goto AGAIN;
+ if (errno == EAGAIN || errno == EWOULDBLOCK)
break;
- }
-
- rpos = (rpos + chunk) % hw->samples;
- to_mix -= chunk;
+ qesd_logerr (errno, "write failed: %s\n", strerror(errno));
+ O("EsounD output thread write error: %s", strerror(errno));
+ break;
}
- if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
- O("EsounD output thread aborting on lock error\n");
- return NULL;
+ writeSamples = nwrite >> hw->info.shift;
+ writeBytes = writeSamples << hw->info.shift;
+ if (writeSamples != writeBytes) {
+ dolog ("warning: Misaligned write %d (requested %d), "
+ "alignment %d\n",
+ nwrite, writeBytes, hw->info.align + 1);
}
-
- esd->rpos = rpos;
- esd->live -= decr;
- esd->decr += decr;
+ rpos = (rpos + writeSamples) % hw->samples;
+ totalSamples += writeSamples;
+ liveSamples -= writeSamples;
}
- O("EsounD output thread exiting");
-
- exit:
- audio_pt_unlock (&esd->pt, AUDIO_FUNC);
- return NULL;
-}
-
-static int qesd_run_out (HWVoiceOut *hw)
-{
- int live, decr;
- ESDVoiceOut *esd = (ESDVoiceOut *) hw;
-
- if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
- O("%s: exiting on lock error", __FUNCTION__);
- return 0;
- }
-
- live = audio_pcm_hw_get_live_out (hw);
- decr = audio_MIN (live, esd->decr);
- esd->decr -= decr;
- esd->live = live - decr;
- hw->rpos = esd->rpos;
- if (esd->live > 0) {
- O("%s: signaling %d samples\n", __FUNCTION__, esd->live);
- audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
- }
- else {
- O(".");
- audio_pt_unlock (&esd->pt, AUDIO_FUNC);
- }
- return decr;
+ hw->rpos = rpos;
+ return totalSamples;
}
static int qesd_write (SWVoiceOut *sw, void *buf, int len)
@@ -300,20 +217,15 @@ static int qesd_init_out (HWVoiceOut *hw, audsettings_t *as)
}
}
- if (audio_pt_init (&esd->pt, qesd_thread_out, esd, AUDIO_CAP, AUDIO_FUNC)) {
- goto fail3;
+ {
+ int flags;
+ flags = fcntl(esd->fd, F_GETFL);
+ fcntl(esd->fd, F_SETFL, flags | O_NONBLOCK);
}
result = 0; /* success */
goto exit;
- fail3:
- if (close (esd->fd)) {
- qesd_logerr (errno, "%s: close on esd socket(%d) failed\n",
- AUDIO_FUNC, esd->fd);
- }
- esd->fd = -1;
-
fail2:
qemu_free (esd->pcm_buf);
esd->pcm_buf = NULL;
@@ -327,23 +239,14 @@ static int qesd_init_out (HWVoiceOut *hw, audsettings_t *as)
static void qesd_fini_out (HWVoiceOut *hw)
{
- void *ret;
ESDVoiceOut *esd = (ESDVoiceOut *) hw;
- audio_pt_lock (&esd->pt, AUDIO_FUNC);
- esd->done = 1;
- audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
- audio_pt_join (&esd->pt, &ret, AUDIO_FUNC);
-
if (esd->fd >= 0) {
if (close (esd->fd)) {
qesd_logerr (errno, "failed to close esd socket\n");
}
esd->fd = -1;
}
-
- audio_pt_fini (&esd->pt, AUDIO_FUNC);
-
qemu_free (esd->pcm_buf);
esd->pcm_buf = NULL;
}
@@ -356,112 +259,54 @@ static int qesd_ctl_out (HWVoiceOut *hw, int cmd, ...)
}
/* capture */
-static void *qesd_thread_in (void *arg)
+static int qesd_run_in (HWVoiceIn *hw)
{
- ESDVoiceIn *esd = arg;
- HWVoiceIn *hw = &esd->hw;
- int threshold;
-
- threshold = conf.divisor ? hw->samples / conf.divisor : 0;
-
- if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
- return NULL;
- }
-
- for (;;) {
- int incr, to_grab, wpos;
-
- for (;;) {
- if (esd->done) {
- goto exit;
- }
+ int wpos, liveSamples, totalSamples;
+ int grabSamples;
+ ESDVoiceIn *esd = (ESDVoiceIn *) hw;
- if (esd->dead > threshold) {
+ wpos = hw->wpos;
+ liveSamples = audio_pcm_hw_get_live_in (hw);
+ grabSamples = hw->samples - liveSamples;
+ totalSamples = 0;
+
+ while (grabSamples > 0) {
+ ssize_t nread;
+ int chunkSamples = audio_MIN (grabSamples, hw->samples - wpos);
+ int chunkBytes = chunkSamples << hw->info.shift;
+ int readSamples, readBytes;
+ void* buf = advance (esd->pcm_buf, wpos);
+
+ AGAIN:
+ nread = read (esd->fd, buf, chunkBytes);
+ if (nread == -1) {
+ if (errno == EINTR)
+ goto AGAIN;
+ if (errno == EAGAIN || errno == EWOULDBLOCK)
break;
- }
- if (audio_pt_wait (&esd->pt, AUDIO_FUNC)) {
- goto exit;
- }
+ qesd_logerr (errno, "read failed: %s\n", strerror(errno));
+ break;
}
- incr = to_grab = esd->dead;
- wpos = hw->wpos;
-
- if (audio_pt_unlock (&esd->pt, AUDIO_FUNC)) {
- return NULL;
- }
-
- while (to_grab) {
- ssize_t nread;
- int chunk = audio_MIN (to_grab, hw->samples - wpos);
- void *buf = advance (esd->pcm_buf, wpos);
-
- again:
- nread = read (esd->fd, buf, chunk << hw->info.shift);
- if (nread == -1) {
- if (errno == EINTR || errno == EAGAIN) {
- goto again;
- }
- qesd_logerr (errno, "read failed\n");
- return NULL;
- }
-
- if (nread != chunk << hw->info.shift) {
- int rsamples = nread >> hw->info.shift;
- int rbytes = rsamples << hw->info.shift;
- if (rbytes != nread) {
- dolog ("warning: Misaligned write %d (requested %d), "
- "alignment %d\n",
- rbytes, nread, hw->info.align + 1);
- }
- to_grab -= rsamples;
- wpos = (wpos + rsamples) % hw->samples;
- break;
- }
-
- hw->conv (hw->conv_buf + wpos, buf, nread >> hw->info.shift,
- &nominal_volume);
- wpos = (wpos + chunk) % hw->samples;
- to_grab -= chunk;
- }
+ readSamples = nread >> hw->info.shift;
+ readBytes = readSamples << hw->info.shift;
- if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
- return NULL;
+ if (readBytes != nread) {
+ dolog ("warning: Misaligned read %d (requested %d), "
+ "alignment %d\n",
+ nread, readBytes, hw->info.align + 1);
}
- esd->wpos = wpos;
- esd->dead -= incr;
- esd->incr += incr;
- }
-
- exit:
- audio_pt_unlock (&esd->pt, AUDIO_FUNC);
- return NULL;
-}
+ hw->conv (hw->conv_buf + wpos, buf, readSamples,
+ &nominal_volume);
-static int qesd_run_in (HWVoiceIn *hw)
-{
- int live, incr, dead;
- ESDVoiceIn *esd = (ESDVoiceIn *) hw;
-
- if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
- return 0;
- }
-
- live = audio_pcm_hw_get_live_in (hw);
- dead = hw->samples - live;
- incr = audio_MIN (dead, esd->incr);
- esd->incr -= incr;
- esd->dead = dead - incr;
- hw->wpos = esd->wpos;
- if (esd->dead > 0) {
- audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
+ wpos = (wpos + readSamples) % hw->samples;
+ grabSamples -= readSamples;
+ totalSamples += readSamples;
}
- else {
- audio_pt_unlock (&esd->pt, AUDIO_FUNC);
- }
- return incr;
+ hw->wpos = wpos;
+ return totalSamples;
}
static int qesd_read (SWVoiceIn *sw, void *buf, int len)
@@ -523,20 +368,15 @@ static int qesd_init_in (HWVoiceIn *hw, audsettings_t *as)
}
}
- if (audio_pt_init (&esd->pt, qesd_thread_in, esd, AUDIO_CAP, AUDIO_FUNC)) {
- goto fail3;
+ {
+ int flags;
+ flags = fcntl(esd->fd, F_GETFL);
+ fcntl(esd->fd, F_SETFL, flags | O_NONBLOCK);
}
result = 0; /* success */
goto exit;
- fail3:
- if (close (esd->fd)) {
- qesd_logerr (errno, "%s: close on esd socket(%d) failed\n",
- AUDIO_FUNC, esd->fd);
- }
- esd->fd = -1;
-
fail2:
qemu_free (esd->pcm_buf);
esd->pcm_buf = NULL;
@@ -550,23 +390,14 @@ static int qesd_init_in (HWVoiceIn *hw, audsettings_t *as)
static void qesd_fini_in (HWVoiceIn *hw)
{
- void *ret;
ESDVoiceIn *esd = (ESDVoiceIn *) hw;
- audio_pt_lock (&esd->pt, AUDIO_FUNC);
- esd->done = 1;
- audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
- audio_pt_join (&esd->pt, &ret, AUDIO_FUNC);
-
if (esd->fd >= 0) {
if (close (esd->fd)) {
qesd_logerr (errno, "failed to close esd socket\n");
}
esd->fd = -1;
}
-
- audio_pt_fini (&esd->pt, AUDIO_FUNC);
-
qemu_free (esd->pcm_buf);
esd->pcm_buf = NULL;
}
diff --git a/distrib/update-audio.sh b/distrib/update-audio.sh
index 56bada2..79d1650 100755
--- a/distrib/update-audio.sh
+++ b/distrib/update-audio.sh
@@ -8,16 +8,16 @@
# assumes this script is located in the 'distrib' sub-directory
cd `dirname $0`
cd ..
+. android/build/common.sh
-locate_depot_files ()
-{
- root=$(p4 where $1) || (
- echo "you need to map $1 into your workspace to build an emulator source release package"
- exit 3
- )
- root=$(echo $root | cut -d" " -f3 | sed -e "s%/\.\.\.%%")
- echo $root
-}
+check_android_build
+if [ $IN_ANDROID_BUILD != yes ] ; then
+ echo "Sorry, this script can only be run from a full Android build tree"
+ exit 1
+fi
+
+force_32bit_binaries
+locate_android_prebuilt
# find the prebuilt directory
OS=`uname -s`
@@ -87,9 +87,8 @@ $GNUMAKE $source BUILD_QEMU_AUDIO_LIB=true || (echo "could not build the audio l
# now do a p4 edit, a copy and ask for submission
#
-TARGET=$PREBUILT/emulator/libqemu-audio.a
+TARGET=$ANDROID_PREBUILT/emulator/libqemu-audio.a
-p4 edit $TARGET || (echo "could not p4 edit $TARGET" && exit 3)
cp -f $source $TARGET
-echo "please do: p4 submit $TARGET"
+echo "ok, file copied to $TARGET"