aboutsummaryrefslogtreecommitdiffstats
path: root/audio/esdaudio.c
diff options
context:
space:
mode:
Diffstat (limited to 'audio/esdaudio.c')
-rw-r--r--audio/esdaudio.c333
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;
}