diff options
author | David 'Digit' Turner <digit@google.com> | 2009-08-21 03:05:29 +0200 |
---|---|---|
committer | David 'Digit' Turner <digit@google.com> | 2009-08-21 03:05:29 +0200 |
commit | 5ad9febb1c7e08fe24413f9bd04f30d92b4cfa3a (patch) | |
tree | 97cb688ef7727ee37a721596eee3af9b8c98d0cc /audio | |
parent | e4c5bfae9beeb0bbb0e525e4700ae4be9971676f (diff) | |
download | external_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.
Diffstat (limited to 'audio')
-rw-r--r-- | audio/esdaudio.c | 333 |
1 files changed, 82 insertions, 251 deletions
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; } |