aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid 'Digit' Turner <digit@android.com>2011-01-02 13:51:44 -0800
committerAndroid Code Review <code-review@android.com>2011-01-02 13:51:44 -0800
commit49186a9370ff139eda36db0b251b9844884ecf7d (patch)
treeed261be80a75ad5c2508a154f27a3101a7752d16
parent1d08551ecbc0e900e87c4508aa65cb2251a2cde3 (diff)
parentca6a2e034bce665a08d9d748ac11d6a7cfcd7c48 (diff)
downloadexternal_qemu-49186a9370ff139eda36db0b251b9844884ecf7d.zip
external_qemu-49186a9370ff139eda36db0b251b9844884ecf7d.tar.gz
external_qemu-49186a9370ff139eda36db0b251b9844884ecf7d.tar.bz2
Merge changes I30b39053,If7896d65,I364390a7,Ibd4321ed,Ifc00b124,I805c1a24,Ie9442676,Ia9496943,Ic3e35ac0,I060300b4,Id6c6c93f,I71c837e4,I37c21672
* changes: qemu-sockets-android.c: Add inet_dgram_opts qemu-sockets-android.c: Add support for socket=<number> option. monitor.h: cleanup upstream: Move bottom-half handlers to async.c sockets.h: Add SOCKET_LIST_DGRAM upstream: qemu-io.c upstream: update hxtool upstream: minor json-lexer.c integration. upstream: minor integration Add -audio-test-out option to the core. Fix upstream audio bug: can't play with two soft voices. Remove obsolete -audio-in and -audio-out options. upstream: audio sub-system improvements.
-rw-r--r--Makefile.android3
-rw-r--r--android/audio-test.c103
-rw-r--r--android/audio-test.h22
-rw-r--r--android/cmdline-options.h2
-rw-r--r--android/help.c60
-rw-r--r--android/main-ui.c9
-rw-r--r--android/main.c9
-rw-r--r--async.c216
-rw-r--r--audio/alsaaudio.c550
-rw-r--r--audio/audio.c602
-rw-r--r--audio/audio_int.h19
-rw-r--r--audio/audio_pt_int.c25
-rw-r--r--audio/audio_template.h17
-rw-r--r--audio/audio_win_int.c108
-rw-r--r--audio/audio_win_int.h10
-rw-r--r--audio/coreaudio.c179
-rw-r--r--audio/dsound_template.h8
-rw-r--r--audio/dsoundaudio.c260
-rw-r--r--audio/esdaudio.c500
-rw-r--r--audio/fmodaudio.c143
-rw-r--r--audio/mixeng.c2
-rw-r--r--audio/noaudio.c53
-rw-r--r--audio/ossaudio.c446
-rw-r--r--audio/paaudio.c8
-rw-r--r--audio/wavaudio.c9
-rw-r--r--audio/winaudio.c3
-rw-r--r--cpu-common.h4
-rw-r--r--exec.c73
-rw-r--r--hw/goldfish_audio.c2
-rwxr-xr-xhxtool62
-rw-r--r--json-lexer.c10
-rw-r--r--monitor.h3
-rw-r--r--qemu-io.c7
-rw-r--r--qemu-options.hx13
-rw-r--r--qemu-sockets-android.c151
-rw-r--r--qemu-sockets.c38
-rw-r--r--sockets.c3
-rw-r--r--sockets.h3
-rw-r--r--vl-android.c161
-rw-r--r--vl.c112
40 files changed, 2464 insertions, 1544 deletions
diff --git a/Makefile.android b/Makefile.android
index 7849775..c995f27 100644
--- a/Makefile.android
+++ b/Makefile.android
@@ -642,6 +642,7 @@ endif
# misc. sources
#
CORE_MISC_SOURCES = vl-android.c \
+ async.c \
console.c \
qemu-malloc.c \
cutils.c \
@@ -735,6 +736,8 @@ CORE_SOURCES = $(CORE_BLOCK_SOURCES) $(CORE_HW_SOURCES)
CORE_SOURCES += $(CORE_MIGRATION_SOURCES) $(CORE_MISC_SOURCES)
CORE_SOURCES += $(CORE_UPSTREAM_SOURCES)
+CORE_SOURCES += android/audio-test.c
+
##############################################################################
# lists of source files used to build the emulator UI
#
diff --git a/android/audio-test.c b/android/audio-test.c
new file mode 100644
index 0000000..e10b987
--- /dev/null
+++ b/android/audio-test.c
@@ -0,0 +1,103 @@
+/* Copyright (C) 2010 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#include "audio/audio.h"
+#include "android/utils/debug.h"
+
+/* This source file contains a small test audio virtual device that
+ * can be used to check that the emulator properly plays sound on
+ * the host system without having to boot a full system.
+ */
+
+#define SAMPLE_SIZE 16384
+
+typedef struct {
+ QEMUSoundCard card;
+ SWVoiceOut *voice;
+ int pos;
+ short sample[SAMPLE_SIZE];
+} TestAudio;
+
+static void
+testAudio_audio_callback(void* opaque, int free)
+{
+ TestAudio* ta = opaque;
+
+ //printf("%s: pos=%d free=%d\n", __FUNCTION__, ta->pos, free);
+
+ while (free > 0) {
+ int avail = SAMPLE_SIZE - ta->pos;
+ if (avail > free)
+ avail = free;
+
+ AUD_write(ta->voice, ta->sample + ta->pos, avail);
+ ta->pos += avail;
+ if (ta->pos >= SAMPLE_SIZE)
+ ta->pos = 0;
+
+ free -= avail;
+ }
+}
+
+static int
+testAudio_init( TestAudio* ta )
+{
+ struct audsettings as;
+
+ AUD_register_card("test_audio", &ta->card);
+
+ as.freq = 16000;
+ as.nchannels = 1;
+ as.fmt = AUD_FMT_S16;
+ as.endianness = AUDIO_HOST_ENDIANNESS;
+
+ ta->voice = AUD_open_out(
+ &ta->card,
+ ta->voice,
+ "test_audio",
+ ta,
+ testAudio_audio_callback,
+ &as);
+
+ if (!ta->voice) {
+ dprint("Cannot open test audio!");
+ return -1;
+ }
+ ta->pos = 0;
+
+ /* Initialize samples */
+ int nn;
+ for (nn = 0; nn < SAMPLE_SIZE; nn++) {
+ ta->sample[nn] = (short)(((nn % (SAMPLE_SIZE/4))*65536/(SAMPLE_SIZE/4)) & 0xffff);
+ }
+
+ AUD_set_active_out(ta->voice, 1);
+ return 0;
+}
+
+static TestAudio* testAudio;
+
+int
+android_audio_test_start_out(void)
+{
+ if (!testAudio) {
+ testAudio = malloc(sizeof(*testAudio));
+ if (testAudio_init(testAudio) < 0) {
+ free(testAudio);
+ testAudio = NULL;
+ fprintf(stderr, "Could not start audio test!\n");
+ return -1;
+ } else {
+ printf("Audio test started!\n");
+ }
+ }
+ return 0;
+}
diff --git a/android/audio-test.h b/android/audio-test.h
new file mode 100644
index 0000000..8113aae
--- /dev/null
+++ b/android/audio-test.h
@@ -0,0 +1,22 @@
+/* Copyright (C) 2010 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#ifndef ANDROID_AUDIO_TEST_H
+#define ANDROID_AUDIO_TEST_H
+
+/* Start the audio test output, this will register a virtual sound
+ * device that sends a saw signal to the audio sub-system. This is
+ * used to test that the audio backend works without having to boot
+ * a full system and launch a music application.
+ */
+extern int android_audio_test_start_out(void);
+
+#endif /* ANDROID_AUDIO_TEST_H */
diff --git a/android/cmdline-options.h b/android/cmdline-options.h
index 3ee5f45..104de7e 100644
--- a/android/cmdline-options.h
+++ b/android/cmdline-options.h
@@ -108,8 +108,6 @@ OPT_PARAM( logcat, "<tags>", "enable logcat output with given tags" )
OPT_FLAG ( no_audio, "disable audio support" )
OPT_FLAG ( noaudio, "same as -no-audio" )
OPT_PARAM( audio, "<backend>", "use specific audio backend" )
-OPT_PARAM( audio_in, "<backend>", "use specific audio input backend" )
-OPT_PARAM( audio_out,"<backend>", "use specific audio output backend" )
OPT_FLAG ( raw_keys, "disable Unicode keyboard reverse-mapping" )
OPT_PARAM( radio, "<device>", "redirect radio modem interface to character device" )
diff --git a/android/help.c b/android/help.c
index f226cf6..c49f3ff 100644
--- a/android/help.c
+++ b/android/help.c
@@ -889,71 +889,11 @@ help_audio(stralloc_t* out)
" the '-audio <backend>' option allows you to select a specific backend\n"
" to be used to both play and record audio in the Android emulator.\n\n"
- " this is equivalent to calling both '-audio-in <backend>' and\n"
- " '-audio-out <backend>' at the same time.\n\n"
-
- " use '-help-audio-out' to see a list of valid output <backend> values.\n"
- " use '-help-audio-in' to see a list of valid input <backend> values.\n"
" use '-audio none' to disable audio completely.\n\n"
);
}
static void
-help_audio_out(stralloc_t* out)
-{
- int nn;
-
- PRINTF(
- " the '-audio-out <backend>' option allows you to select a specific\n"
- " backend to play audio in the Android emulator. this is mostly useful\n"
- " on Linux\n\n"
-
- " on this system, output <backend> can be one of the following:\n\n"
- );
- for ( nn = 0; ; nn++ ) {
- char name[512];
- char descr[4096];
- if (android_core_audio_get_backend_name(0, nn, name, sizeof(name),
- descr, sizeof(descr))) {
- break;
- }
- PRINTF( " %-10s %s\n", name, descr );
- }
- PRINTF( "\n" );
-}
-
-static void
-help_audio_in(stralloc_t* out)
-{
- int nn;
-
- PRINTF(
- " the '-audio-in <backend>' option allows you to select a specific\n"
- " backend to play audio in the Android emulator. this is mostly useful\n"
- " on Linux\n\n"
-
- " IMPORTANT NOTE:\n"
- " on some Linux systems, broken Esd/ALSA/driver implementations will\n"
- " make your emulator freeze and become totally unresponsive when\n"
- " using audio recording. the only way to avoid this is to use\n"
- " '-audio-in none' to disable it\n\n"
-
- " on this system, input <backend> can be one of:\n\n"
- );
- for ( nn = 0; ; nn++ ) {
- char name[512];
- char descr[4096];
- if (android_core_audio_get_backend_name(1, nn, name, sizeof(name),
- descr, sizeof(descr))) {
- break;
- }
- PRINTF( " %-10s %s\n", name, descr );
- }
- PRINTF( "\n" );
-}
-
-
-static void
help_scale(stralloc_t* out)
{
PRINTF(
diff --git a/android/main-ui.c b/android/main-ui.c
index 043a9a8..688c529 100644
--- a/android/main-ui.c
+++ b/android/main-ui.c
@@ -1472,15 +1472,6 @@ int main(int argc, char **argv)
args[n++] = opts->audio;
}
- if (opts->audio_in) {
- args[n++] = "-audio-in";
- args[n++] = opts->audio_in;
- }
- if (opts->audio_out) {
- args[n++] = "-audio-out";
- args[n++] = opts->audio_out;
- }
-
if (opts->cpu_delay) {
args[n++] = "-cpu-delay";
args[n++] = opts->cpu_delay;
diff --git a/android/main.c b/android/main.c
index 0eebffb..1244c13 100644
--- a/android/main.c
+++ b/android/main.c
@@ -1240,15 +1240,6 @@ int main(int argc, char **argv)
args[n++] = opts->audio;
}
- if (opts->audio_in) {
- args[n++] = "-audio-in";
- args[n++] = opts->audio_in;
- }
- if (opts->audio_out) {
- args[n++] = "-audio-out";
- args[n++] = opts->audio_out;
- }
-
if (opts->cpu_delay) {
args[n++] = "-cpu-delay";
args[n++] = opts->cpu_delay;
diff --git a/async.c b/async.c
new file mode 100644
index 0000000..57ac3a8
--- /dev/null
+++ b/async.c
@@ -0,0 +1,216 @@
+/*
+ * QEMU System Emulator
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu-common.h"
+#include "qemu-aio.h"
+
+/*
+ * An AsyncContext protects the callbacks of AIO requests and Bottom Halves
+ * against interfering with each other. A typical example is qcow2 that accepts
+ * asynchronous requests, but relies for manipulation of its metadata on
+ * synchronous bdrv_read/write that doesn't trigger any callbacks.
+ *
+ * However, these functions are often emulated using AIO which means that AIO
+ * callbacks must be run - but at the same time we must not run callbacks of
+ * other requests as they might start to modify metadata and corrupt the
+ * internal state of the caller of bdrv_read/write.
+ *
+ * To achieve the desired semantics we switch into a new AsyncContext.
+ * Callbacks must only be run if they belong to the current AsyncContext.
+ * Otherwise they need to be queued until their own context is active again.
+ * This is how you can make qemu_aio_wait() wait only for your own callbacks.
+ *
+ * The AsyncContexts form a stack. When you leave a AsyncContexts, you always
+ * return to the old ("parent") context.
+ */
+struct AsyncContext {
+ /* Consecutive number of the AsyncContext (position in the stack) */
+ int id;
+
+ /* Anchor of the list of Bottom Halves belonging to the context */
+ struct QEMUBH *first_bh;
+
+ /* Link to parent context */
+ struct AsyncContext *parent;
+};
+
+/* The currently active AsyncContext */
+static struct AsyncContext *async_context = &(struct AsyncContext) { 0 };
+
+/*
+ * Enter a new AsyncContext. Already scheduled Bottom Halves and AIO callbacks
+ * won't be called until this context is left again.
+ */
+void async_context_push(void)
+{
+ struct AsyncContext *new = qemu_mallocz(sizeof(*new));
+ new->parent = async_context;
+ new->id = async_context->id + 1;
+ async_context = new;
+}
+
+/* Run queued AIO completions and destroy Bottom Half */
+static void bh_run_aio_completions(void *opaque)
+{
+ QEMUBH **bh = opaque;
+ qemu_bh_delete(*bh);
+ qemu_free(bh);
+ qemu_aio_process_queue();
+}
+/*
+ * Leave the currently active AsyncContext. All Bottom Halves belonging to the
+ * old context are executed before changing the context.
+ */
+void async_context_pop(void)
+{
+ struct AsyncContext *old = async_context;
+ QEMUBH **bh;
+
+ /* Flush the bottom halves, we don't want to lose them */
+ while (qemu_bh_poll());
+
+ /* Switch back to the parent context */
+ async_context = async_context->parent;
+ qemu_free(old);
+
+ if (async_context == NULL) {
+ abort();
+ }
+
+ /* Schedule BH to run any queued AIO completions as soon as possible */
+ bh = qemu_malloc(sizeof(*bh));
+ *bh = qemu_bh_new(bh_run_aio_completions, bh);
+ qemu_bh_schedule(*bh);
+}
+
+/*
+ * Returns the ID of the currently active AsyncContext
+ */
+int get_async_context_id(void)
+{
+ return async_context->id;
+}
+
+/***********************************************************/
+/* bottom halves (can be seen as timers which expire ASAP) */
+
+struct QEMUBH {
+ QEMUBHFunc *cb;
+ void *opaque;
+ int scheduled;
+ int idle;
+ int deleted;
+ QEMUBH *next;
+};
+
+QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque)
+{
+ QEMUBH *bh;
+ bh = qemu_mallocz(sizeof(QEMUBH));
+ bh->cb = cb;
+ bh->opaque = opaque;
+ bh->next = async_context->first_bh;
+ async_context->first_bh = bh;
+ return bh;
+}
+
+int qemu_bh_poll(void)
+{
+ QEMUBH *bh, **bhp;
+ int ret;
+
+ ret = 0;
+ for (bh = async_context->first_bh; bh; bh = bh->next) {
+ if (!bh->deleted && bh->scheduled) {
+ bh->scheduled = 0;
+ if (!bh->idle)
+ ret = 1;
+ bh->idle = 0;
+ bh->cb(bh->opaque);
+ }
+ }
+
+ /* remove deleted bhs */
+ bhp = &async_context->first_bh;
+ while (*bhp) {
+ bh = *bhp;
+ if (bh->deleted) {
+ *bhp = bh->next;
+ qemu_free(bh);
+ } else
+ bhp = &bh->next;
+ }
+
+ return ret;
+}
+
+void qemu_bh_schedule_idle(QEMUBH *bh)
+{
+ if (bh->scheduled)
+ return;
+ bh->scheduled = 1;
+ bh->idle = 1;
+}
+
+void qemu_bh_schedule(QEMUBH *bh)
+{
+ if (bh->scheduled)
+ return;
+ bh->scheduled = 1;
+ bh->idle = 0;
+ /* stop the currently executing CPU to execute the BH ASAP */
+ qemu_notify_event();
+}
+
+void qemu_bh_cancel(QEMUBH *bh)
+{
+ bh->scheduled = 0;
+}
+
+void qemu_bh_delete(QEMUBH *bh)
+{
+ bh->scheduled = 0;
+ bh->deleted = 1;
+}
+
+void qemu_bh_update_timeout(int *timeout)
+{
+ QEMUBH *bh;
+
+ for (bh = async_context->first_bh; bh; bh = bh->next) {
+ if (!bh->deleted && bh->scheduled) {
+ if (bh->idle) {
+ /* idle bottom halves will be polled at least
+ * every 10ms */
+ *timeout = MIN(10, *timeout);
+ } else {
+ /* non-idle bottom halves will be executed
+ * immediately */
+ *timeout = 0;
+ break;
+ }
+ }
+ }
+}
+
diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c
index 0f5ee9e..1cbbaa4 100644
--- a/audio/alsaaudio.c
+++ b/audio/alsaaudio.c
@@ -1,7 +1,7 @@
/*
* QEMU ALSA audio driver
*
- * Copyright (c) 2008 The Android Open Source Project
+ * Copyright (c) 2008-2010 The Android Open Source Project
* Copyright (c) 2005 Vassili Karpov (malc)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -24,8 +24,13 @@
*/
#include <alsa/asoundlib.h>
#include "qemu-common.h"
+#include "qemu-char.h"
#include "audio.h"
+#if QEMU_GNUC_PREREQ(4, 3)
+#pragma GCC diagnostic ignored "-Waddress"
+#endif
+
#define AUDIO_CAP "alsa"
#include "audio_int.h"
#include <dlfcn.h>
@@ -81,6 +86,10 @@
DYNLINK_FUNC(int,snd_pcm_hw_params_set_buffer_size_near,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val)) \
DYNLINK_FUNC(int,snd_pcm_hw_params_set_period_size_near,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val, int *dir)) \
DYNLINK_FUNC(int,snd_pcm_hw_params_get_format,(const snd_pcm_hw_params_t *params, snd_pcm_format_t *val)) \
+ DYNLINK_FUNC(int,snd_pcm_resume,(snd_pcm_t *pcm)) \
+ DYNLINK_FUNC(int,snd_pcm_poll_descriptors_revents,(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents)) \
+ DYNLINK_FUNC(int,snd_pcm_poll_descriptors_count,(snd_pcm_t *pcm)) \
+ DYNLINK_FUNC(int,snd_pcm_poll_descriptors,(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int space)) \
#define DYNLINK_FUNCTIONS_INIT \
alsa_dynlink_init
@@ -96,16 +105,27 @@
static void* alsa_lib;
+struct pollhlp {
+ snd_pcm_t *handle;
+ struct pollfd *pfds;
+ int count;
+ int mask;
+};
+
typedef struct ALSAVoiceOut {
HWVoiceOut hw;
+ int wpos;
+ int pending;
void *pcm_buf;
snd_pcm_t *handle;
+ struct pollhlp pollhlp;
} ALSAVoiceOut;
typedef struct ALSAVoiceIn {
HWVoiceIn hw;
snd_pcm_t *handle;
void *pcm_buf;
+ struct pollhlp pollhlp;
} ALSAVoiceIn;
static struct {
@@ -126,7 +146,8 @@ static struct {
int period_size_out_overridden;
int verbose;
} conf = {
- .buffer_size_out = 1024,
+ .buffer_size_out = 4096,
+ .period_size_out = 1024,
.pcm_name_out = "default",
.pcm_name_in = "default",
};
@@ -178,7 +199,23 @@ static void GCC_FMT_ATTR (3, 4) alsa_logerr2 (
AUD_log (AUDIO_CAP, "Reason: %s\n", FF(snd_strerror) (err));
}
-static void alsa_anal_close (snd_pcm_t **handlep)
+static void alsa_fini_poll (struct pollhlp *hlp)
+{
+ int i;
+ struct pollfd *pfds = hlp->pfds;
+
+ if (pfds) {
+ for (i = 0; i < hlp->count; ++i) {
+ qemu_set_fd_handler (pfds[i].fd, NULL, NULL, NULL);
+ }
+ qemu_free (pfds);
+ }
+ hlp->pfds = NULL;
+ hlp->count = 0;
+ hlp->handle = NULL;
+}
+
+static void alsa_anal_close1 (snd_pcm_t **handlep)
{
int err = FF(snd_pcm_close) (*handlep);
if (err) {
@@ -187,6 +224,167 @@ static void alsa_anal_close (snd_pcm_t **handlep)
*handlep = NULL;
}
+static void alsa_anal_close (snd_pcm_t **handlep, struct pollhlp *hlp)
+{
+ alsa_fini_poll (hlp);
+ alsa_anal_close1 (handlep);
+}
+
+static int alsa_recover (snd_pcm_t *handle)
+{
+ int err = FF(snd_pcm_prepare) (handle);
+ if (err < 0) {
+ alsa_logerr (err, "Failed to prepare handle %p\n", handle);
+ return -1;
+ }
+ return 0;
+}
+
+static int alsa_resume (snd_pcm_t *handle)
+{
+ int err = FF(snd_pcm_resume) (handle);
+ if (err < 0) {
+ alsa_logerr (err, "Failed to resume handle %p\n", handle);
+ return -1;
+ }
+ return 0;
+}
+
+static void alsa_poll_handler (void *opaque)
+{
+ int err, count;
+ snd_pcm_state_t state;
+ struct pollhlp *hlp = opaque;
+ unsigned short revents;
+
+ count = poll (hlp->pfds, hlp->count, 0);
+ if (count < 0) {
+ dolog ("alsa_poll_handler: poll %s\n", strerror (errno));
+ return;
+ }
+
+ if (!count) {
+ return;
+ }
+
+ /* XXX: ALSA example uses initial count, not the one returned by
+ poll, correct? */
+ err = FF(snd_pcm_poll_descriptors_revents) (hlp->handle, hlp->pfds,
+ hlp->count, &revents);
+ if (err < 0) {
+ alsa_logerr (err, "snd_pcm_poll_descriptors_revents");
+ return;
+ }
+
+ if (!(revents & hlp->mask)) {
+ if (conf.verbose) {
+ dolog ("revents = %d\n", revents);
+ }
+ return;
+ }
+
+ state = FF(snd_pcm_state) (hlp->handle);
+ switch (state) {
+ case SND_PCM_STATE_SETUP:
+ alsa_recover (hlp->handle);
+ break;
+
+ case SND_PCM_STATE_XRUN:
+ alsa_recover (hlp->handle);
+ break;
+
+ case SND_PCM_STATE_SUSPENDED:
+ alsa_resume (hlp->handle);
+ break;
+
+ case SND_PCM_STATE_PREPARED:
+ audio_run ("alsa run (prepared)");
+ break;
+
+ case SND_PCM_STATE_RUNNING:
+ audio_run ("alsa run (running)");
+ break;
+
+ default:
+ dolog ("Unexpected state %d\n", state);
+ }
+}
+
+static int alsa_poll_helper (snd_pcm_t *handle, struct pollhlp *hlp, int mask)
+{
+ int i, count, err;
+ struct pollfd *pfds;
+
+ count = FF(snd_pcm_poll_descriptors_count) (handle);
+ if (count <= 0) {
+ dolog ("Could not initialize poll mode\n"
+ "Invalid number of poll descriptors %d\n", count);
+ return -1;
+ }
+
+ pfds = audio_calloc ("alsa_poll_helper", count, sizeof (*pfds));
+ if (!pfds) {
+ dolog ("Could not initialize poll mode\n");
+ return -1;
+ }
+
+ err = FF(snd_pcm_poll_descriptors) (handle, pfds, count);
+ if (err < 0) {
+ alsa_logerr (err, "Could not initialize poll mode\n"
+ "Could not obtain poll descriptors\n");
+ qemu_free (pfds);
+ return -1;
+ }
+
+ for (i = 0; i < count; ++i) {
+ if (pfds[i].events & POLLIN) {
+ err = qemu_set_fd_handler (pfds[i].fd, alsa_poll_handler,
+ NULL, hlp);
+ }
+ if (pfds[i].events & POLLOUT) {
+ if (conf.verbose) {
+ dolog ("POLLOUT %d %d\n", i, pfds[i].fd);
+ }
+ err = qemu_set_fd_handler (pfds[i].fd, NULL,
+ alsa_poll_handler, hlp);
+ }
+ if (conf.verbose) {
+ dolog ("Set handler events=%#x index=%d fd=%d err=%d\n",
+ pfds[i].events, i, pfds[i].fd, err);
+ }
+
+ if (err) {
+ dolog ("Failed to set handler events=%#x index=%d fd=%d err=%d\n",
+ pfds[i].events, i, pfds[i].fd, err);
+
+ while (i--) {
+ qemu_set_fd_handler (pfds[i].fd, NULL, NULL, NULL);
+ }
+ qemu_free (pfds);
+ return -1;
+ }
+ }
+ hlp->pfds = pfds;
+ hlp->count = count;
+ hlp->handle = handle;
+ hlp->mask = mask;
+ return 0;
+}
+
+static int alsa_poll_out (HWVoiceOut *hw)
+{
+ ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
+
+ return alsa_poll_helper (alsa->handle, &alsa->pollhlp, POLLOUT);
+}
+
+static int alsa_poll_in (HWVoiceIn *hw)
+{
+ ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
+
+ return alsa_poll_helper (alsa->handle, &alsa->pollhlp, POLLIN);
+}
+
static int alsa_write (SWVoiceOut *sw, void *buf, int len)
{
return audio_pcm_sw_write (sw, buf, len);
@@ -285,10 +483,11 @@ static int alsa_to_audfmt (snd_pcm_format_t alsafmt, audfmt_e *fmt,
}
static void alsa_dump_info (struct alsa_params_req *req,
- struct alsa_params_obt *obt)
+ struct alsa_params_obt *obt,
+ snd_pcm_format_t obtfmt)
{
dolog ("parameter | requested value | obtained value\n");
- dolog ("format | %10d | %10d\n", req->fmt, obt->fmt);
+ dolog ("format | %10d | %10d\n", req->fmt, obtfmt);
dolog ("channels | %10d | %10d\n",
req->nchannels, obt->nchannels);
dolog ("frequency | %10d | %10d\n", req->freq, obt->freq);
@@ -474,7 +673,7 @@ static int alsa_open (int in, struct alsa_params_req *req,
goto err;
}
- if ((req->override_mask & 1) && (obt - req->period_size))
+ if (((req->override_mask & 1) && (obt - req->period_size)))
dolog ("Requested period %s %u was rejected, using %lu\n",
size_in_usec ? "time" : "size", req->period_size, obt);
}
@@ -491,7 +690,6 @@ static int alsa_open (int in, struct alsa_params_req *req,
goto err;
}
- err = FF(snd_pcm_hw_params_get_format)(hw_params, &obtfmt);
err = FF(snd_pcm_hw_params_get_format) (hw_params, &obtfmt);
if (err < 0) {
alsa_logerr2 (err, typ, "Failed to get format\n");
@@ -542,33 +740,23 @@ static int alsa_open (int in, struct alsa_params_req *req,
*handlep = handle;
if (conf.verbose &&
- (obt->fmt != req->fmt ||
+ (obtfmt != req->fmt ||
obt->nchannels != req->nchannels ||
obt->freq != req->freq)) {
- dolog ("Audio paramters for %s\n", typ);
- alsa_dump_info (req, obt);
+ dolog ("Audio parameters for %s\n", typ);
+ alsa_dump_info (req, obt, obtfmt);
}
#ifdef DEBUG
- alsa_dump_info (req, obt);
+ alsa_dump_info (req, obt, obtfmt);
#endif
return 0;
err:
- alsa_anal_close (&handle);
+ alsa_anal_close1 (&handle);
return -1;
}
-static int alsa_recover (snd_pcm_t *handle)
-{
- int err = FF(snd_pcm_prepare) (handle);
- if (err < 0) {
- alsa_logerr (err, "Failed to prepare handle %p\n", handle);
- return -1;
- }
- return 0;
-}
-
static snd_pcm_sframes_t alsa_get_avail (snd_pcm_t *handle)
{
snd_pcm_sframes_t avail;
@@ -591,41 +779,19 @@ static snd_pcm_sframes_t alsa_get_avail (snd_pcm_t *handle)
return avail;
}
-static int alsa_run_out (HWVoiceOut *hw)
+static void alsa_write_pending (ALSAVoiceOut *alsa)
{
- ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
- int rpos, live, decr;
- int samples;
- uint8_t *dst;
- struct st_sample *src;
- snd_pcm_sframes_t avail;
-
- live = audio_pcm_hw_get_live_out (hw);
- if (!live) {
- return 0;
- }
-
- avail = alsa_get_avail (alsa->handle);
- if (avail < 0) {
- dolog ("Could not get number of available playback frames\n");
- return 0;
- }
-
- decr = audio_MIN (live, avail);
- samples = decr;
- rpos = hw->rpos;
- while (samples) {
- int left_till_end_samples = hw->samples - rpos;
- int len = audio_MIN (samples, left_till_end_samples);
- snd_pcm_sframes_t written;
-
- src = hw->mix_buf + rpos;
- dst = advance (alsa->pcm_buf, rpos << hw->info.shift);
+ HWVoiceOut *hw = &alsa->hw;
- hw->clip (dst, src, len);
+ while (alsa->pending) {
+ int left_till_end_samples = hw->samples - alsa->wpos;
+ int len = audio_MIN (alsa->pending, left_till_end_samples);
+ char *src = advance (alsa->pcm_buf, alsa->wpos << hw->info.shift);
while (len) {
- written = FF(snd_pcm_writei) (alsa->handle, dst, len);
+ snd_pcm_sframes_t written;
+
+ written = FF(snd_pcm_writei) (alsa->handle, src, len);
if (written <= 0) {
switch (written) {
@@ -633,39 +799,65 @@ static int alsa_run_out (HWVoiceOut *hw)
if (conf.verbose) {
dolog ("Failed to write %d frames (wrote zero)\n", len);
}
- goto exit;
+ return;
case -EPIPE:
if (alsa_recover (alsa->handle)) {
alsa_logerr (written, "Failed to write %d frames\n",
len);
- goto exit;
+ return;
}
if (conf.verbose) {
dolog ("Recovering from playback xrun\n");
}
continue;
+ case -ESTRPIPE:
+ /* stream is suspended and waiting for an
+ application recovery */
+ if (alsa_resume (alsa->handle)) {
+ alsa_logerr (written, "Failed to write %d frames\n",
+ len);
+ return;
+ }
+ if (conf.verbose) {
+ dolog ("Resuming suspended output stream\n");
+ }
+ continue;
+
case -EAGAIN:
- goto exit;
+ return;
default:
- alsa_logerr (written, "Failed to write %d frames to %p\n",
- len, dst);
- goto exit;
+ alsa_logerr (written, "Failed to write %d frames from %p\n",
+ len, src);
+ return;
}
}
- rpos = (rpos + written) % hw->samples;
- samples -= written;
+ alsa->wpos = (alsa->wpos + written) % hw->samples;
+ alsa->pending -= written;
len -= written;
- dst = advance (dst, written << hw->info.shift);
- src += written;
}
}
+}
- exit:
- hw->rpos = rpos;
+static int alsa_run_out (HWVoiceOut *hw, int live)
+{
+ ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
+ int decr;
+ snd_pcm_sframes_t avail;
+
+ avail = alsa_get_avail (alsa->handle);
+ if (avail < 0) {
+ dolog ("Could not get number of available playback frames\n");
+ return 0;
+ }
+
+ decr = audio_MIN (live, avail);
+ decr = audio_pcm_hw_clip_out (hw, alsa->pcm_buf, decr, alsa->pending);
+ alsa->pending += decr;
+ alsa_write_pending (alsa);
return decr;
}
@@ -674,7 +866,7 @@ static void alsa_fini_out (HWVoiceOut *hw)
ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
ldebug ("alsa_fini\n");
- alsa_anal_close (&alsa->handle);
+ alsa_anal_close (&alsa->handle, &alsa->pollhlp);
if (alsa->pcm_buf) {
qemu_free (alsa->pcm_buf);
@@ -701,8 +893,9 @@ static int alsa_init_out (HWVoiceOut *hw, struct audsettings *as)
req.period_size = conf.period_size_out;
req.buffer_size = conf.buffer_size_out;
req.size_in_usec = conf.size_in_usec_out;
- req.override_mask = !!conf.period_size_out_overridden
- | (!!conf.buffer_size_out_overridden << 1);
+ req.override_mask =
+ (conf.period_size_out_overridden ? 1 : 0) |
+ (conf.buffer_size_out_overridden ? 2 : 0);
if (alsa_open (0, &req, &obt, &handle)) {
goto Exit;
@@ -720,7 +913,7 @@ static int alsa_init_out (HWVoiceOut *hw, struct audsettings *as)
if (!alsa->pcm_buf) {
dolog ("Could not allocate DAC buffer (%d samples, each %d bytes)\n",
hw->samples, 1 << hw->info.shift);
- alsa_anal_close (&handle);
+ alsa_anal_close1 (&handle);
goto Exit;
}
@@ -762,8 +955,21 @@ static int alsa_ctl_out (HWVoiceOut *hw, int cmd, ...)
switch (cmd) {
case VOICE_ENABLE:
- ldebug ("enabling voice\n");
- return alsa_voice_ctl (alsa->handle, "playback", 0);
+ {
+ va_list ap;
+ int poll_mode;
+
+ va_start (ap, cmd);
+ poll_mode = va_arg (ap, int);
+ va_end (ap);
+
+ ldebug ("enabling voice\n");
+ if (poll_mode && alsa_poll_out (hw)) {
+ poll_mode = 0;
+ }
+ hw->poll_mode = poll_mode;
+ return alsa_voice_ctl (alsa->handle, "playback", 0);
+ }
case VOICE_DISABLE:
ldebug ("disabling voice\n");
@@ -792,8 +998,9 @@ static int alsa_init_in (HWVoiceIn *hw, struct audsettings *as)
req.period_size = conf.period_size_in;
req.buffer_size = conf.buffer_size_in;
req.size_in_usec = conf.size_in_usec_in;
- req.override_mask = !!conf.period_size_in_overridden
- | (!!conf.buffer_size_in_overridden << 1);
+ req.override_mask =
+ (conf.period_size_in_overridden ? 1 : 0) |
+ (conf.buffer_size_in_overridden ? 2 : 0);
if (alsa_open (1, &req, &obt, &handle)) {
goto Exit;
@@ -811,7 +1018,7 @@ static int alsa_init_in (HWVoiceIn *hw, struct audsettings *as)
if (!alsa->pcm_buf) {
dolog ("Could not allocate ADC buffer (%d samples, each %d bytes)\n",
hw->samples, 1 << hw->info.shift);
- alsa_anal_close (&handle);
+ alsa_anal_close1 (&handle);
goto Exit;
}
@@ -829,7 +1036,7 @@ static void alsa_fini_in (HWVoiceIn *hw)
{
ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
- alsa_anal_close (&alsa->handle);
+ alsa_anal_close (&alsa->handle, &alsa->pollhlp);
if (alsa->pcm_buf) {
qemu_free (alsa->pcm_buf);
@@ -849,8 +1056,8 @@ static int alsa_run_in (HWVoiceIn *hw)
int add;
int len;
} bufs[2] = {
- { hw->wpos, 0 },
- { 0, 0 }
+ { .add = hw->wpos, .len = 0 },
+ { .add = 0, .len = 0 }
};
snd_pcm_sframes_t avail;
snd_pcm_uframes_t read_samples = 0;
@@ -865,8 +1072,30 @@ static int alsa_run_in (HWVoiceIn *hw)
return 0;
}
- if (!avail && (FF(snd_pcm_state) (alsa->handle) == SND_PCM_STATE_PREPARED)) {
- avail = hw->samples;
+ if (!avail) {
+ snd_pcm_state_t state;
+
+ state = FF(snd_pcm_state) (alsa->handle);
+ switch (state) {
+ case SND_PCM_STATE_PREPARED:
+ avail = hw->samples;
+ break;
+ case SND_PCM_STATE_SUSPENDED:
+ /* stream is suspended and waiting for an application recovery */
+ if (alsa_resume (alsa->handle)) {
+ dolog ("Failed to resume suspended input stream\n");
+ return 0;
+ }
+ if (conf.verbose) {
+ dolog ("Resuming suspended input stream\n");
+ }
+ break;
+ default:
+ if (conf.verbose) {
+ dolog ("No frames available and ALSA state is %d\n", state);
+ }
+ return 0;
+ }
}
decr = audio_MIN (dead, avail);
@@ -954,11 +1183,29 @@ static int alsa_ctl_in (HWVoiceIn *hw, int cmd, ...)
switch (cmd) {
case VOICE_ENABLE:
- ldebug ("enabling voice\n");
- return alsa_voice_ctl (alsa->handle, "capture", 0);
+ {
+ va_list ap;
+ int poll_mode;
+
+ va_start (ap, cmd);
+ poll_mode = va_arg (ap, int);
+ va_end (ap);
+
+ ldebug ("enabling voice\n");
+ if (poll_mode && alsa_poll_in (hw)) {
+ poll_mode = 0;
+ }
+ hw->poll_mode = poll_mode;
+
+ return alsa_voice_ctl (alsa->handle, "capture", 0);
+ }
case VOICE_DISABLE:
ldebug ("disabling voice\n");
+ if (hw->poll_mode) {
+ hw->poll_mode = 0;
+ alsa_fini_poll (&alsa->pollhlp);
+ }
return alsa_voice_ctl (alsa->handle, "capture", 1);
}
@@ -1002,63 +1249,98 @@ static void alsa_audio_fini (void *opaque)
}
static struct audio_option alsa_options[] = {
- {"DAC_SIZE_IN_USEC", AUD_OPT_BOOL, &conf.size_in_usec_out,
- "DAC period/buffer size in microseconds (otherwise in frames)", NULL, 0},
- {"DAC_PERIOD_SIZE", AUD_OPT_INT, &conf.period_size_out,
- "DAC period size (0 to go with system default)",
- &conf.period_size_out_overridden, 0},
- {"DAC_BUFFER_SIZE", AUD_OPT_INT, &conf.buffer_size_out,
- "DAC buffer size (0 to go with system default)",
- &conf.buffer_size_out_overridden, 0},
-
- {"ADC_SIZE_IN_USEC", AUD_OPT_BOOL, &conf.size_in_usec_in,
- "ADC period/buffer size in microseconds (otherwise in frames)", NULL, 0},
- {"ADC_PERIOD_SIZE", AUD_OPT_INT, &conf.period_size_in,
- "ADC period size (0 to go with system default)",
- &conf.period_size_in_overridden, 0},
- {"ADC_BUFFER_SIZE", AUD_OPT_INT, &conf.buffer_size_in,
- "ADC buffer size (0 to go with system default)",
- &conf.buffer_size_in_overridden, 0},
-
- {"THRESHOLD", AUD_OPT_INT, &conf.threshold,
- "(undocumented)", NULL, 0},
-
- {"DAC_DEV", AUD_OPT_STR, &conf.pcm_name_out,
- "DAC device name (for instance dmix)", NULL, 0},
-
- {"ADC_DEV", AUD_OPT_STR, &conf.pcm_name_in,
- "ADC device name", NULL, 0},
-
- {"VERBOSE", AUD_OPT_BOOL, &conf.verbose,
- "Behave in a more verbose way", NULL, 0},
-
- {NULL, 0, NULL, NULL, NULL, 0}
+ {
+ .name = "DAC_SIZE_IN_USEC",
+ .tag = AUD_OPT_BOOL,
+ .valp = &conf.size_in_usec_out,
+ .descr = "DAC period/buffer size in microseconds (otherwise in frames)"
+ },
+ {
+ .name = "DAC_PERIOD_SIZE",
+ .tag = AUD_OPT_INT,
+ .valp = &conf.period_size_out,
+ .descr = "DAC period size (0 to go with system default)",
+ .overriddenp = &conf.period_size_out_overridden
+ },
+ {
+ .name = "DAC_BUFFER_SIZE",
+ .tag = AUD_OPT_INT,
+ .valp = &conf.buffer_size_out,
+ .descr = "DAC buffer size (0 to go with system default)",
+ .overriddenp = &conf.buffer_size_out_overridden
+ },
+ {
+ .name = "ADC_SIZE_IN_USEC",
+ .tag = AUD_OPT_BOOL,
+ .valp = &conf.size_in_usec_in,
+ .descr =
+ "ADC period/buffer size in microseconds (otherwise in frames)"
+ },
+ {
+ .name = "ADC_PERIOD_SIZE",
+ .tag = AUD_OPT_INT,
+ .valp = &conf.period_size_in,
+ .descr = "ADC period size (0 to go with system default)",
+ .overriddenp = &conf.period_size_in_overridden
+ },
+ {
+ .name = "ADC_BUFFER_SIZE",
+ .tag = AUD_OPT_INT,
+ .valp = &conf.buffer_size_in,
+ .descr = "ADC buffer size (0 to go with system default)",
+ .overriddenp = &conf.buffer_size_in_overridden
+ },
+ {
+ .name = "THRESHOLD",
+ .tag = AUD_OPT_INT,
+ .valp = &conf.threshold,
+ .descr = "(undocumented)"
+ },
+ {
+ .name = "DAC_DEV",
+ .tag = AUD_OPT_STR,
+ .valp = &conf.pcm_name_out,
+ .descr = "DAC device name (for instance dmix)"
+ },
+ {
+ .name = "ADC_DEV",
+ .tag = AUD_OPT_STR,
+ .valp = &conf.pcm_name_in,
+ .descr = "ADC device name"
+ },
+ {
+ .name = "VERBOSE",
+ .tag = AUD_OPT_BOOL,
+ .valp = &conf.verbose,
+ .descr = "Behave in a more verbose way"
+ },
+ { /* End of list */ }
};
static struct audio_pcm_ops alsa_pcm_ops = {
- alsa_init_out,
- alsa_fini_out,
- alsa_run_out,
- alsa_write,
- alsa_ctl_out,
-
- alsa_init_in,
- alsa_fini_in,
- alsa_run_in,
- alsa_read,
- alsa_ctl_in
+ .init_out = alsa_init_out,
+ .fini_out = alsa_fini_out,
+ .run_out = alsa_run_out,
+ .write = alsa_write,
+ .ctl_out = alsa_ctl_out,
+
+ .init_in = alsa_init_in,
+ .fini_in = alsa_fini_in,
+ .run_in = alsa_run_in,
+ .read = alsa_read,
+ .ctl_in = alsa_ctl_in,
};
struct audio_driver alsa_audio_driver = {
- INIT_FIELD (name = ) "alsa",
- INIT_FIELD (descr = ) "ALSA audio (www.alsa-project.org)",
- INIT_FIELD (options = ) alsa_options,
- INIT_FIELD (init = ) alsa_audio_init,
- INIT_FIELD (fini = ) alsa_audio_fini,
- INIT_FIELD (pcm_ops = ) &alsa_pcm_ops,
- INIT_FIELD (can_be_default = ) 1,
- INIT_FIELD (max_voices_out = ) INT_MAX,
- INIT_FIELD (max_voices_in = ) INT_MAX,
- INIT_FIELD (voice_size_out = ) sizeof (ALSAVoiceOut),
- INIT_FIELD (voice_size_in = ) sizeof (ALSAVoiceIn)
+ .name = "alsa",
+ .descr = "ALSA http://www.alsa-project.org",
+ .options = alsa_options,
+ .init = alsa_audio_init,
+ .fini = alsa_audio_fini,
+ .pcm_ops = &alsa_pcm_ops,
+ .can_be_default = 1,
+ .max_voices_out = INT_MAX,
+ .max_voices_in = INT_MAX,
+ .voice_size_out = sizeof (ALSAVoiceOut),
+ .voice_size_in = sizeof (ALSAVoiceIn)
};
diff --git a/audio/audio.c b/audio/audio.c
index 6f107dc..3e60c12 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -158,71 +158,59 @@ static struct {
} period;
int plive;
int log_to_monitor;
+ int try_poll_in;
+ int try_poll_out;
} conf = {
- { /* DAC fixed settings */
- 1, /* enabled */
- 1, /* nb_voices */
- 1, /* greedy */
- {
- 44100, /* freq */
- 2, /* nchannels */
- AUD_FMT_S16, /* fmt */
- AUDIO_HOST_ENDIANNESS
+ .fixed_out = { /* DAC fixed settings */
+ .enabled = 1,
+ .nb_voices = 1,
+ .greedy = 1,
+ .settings = {
+ .freq = 44100,
+ .nchannels = 2,
+ .fmt = AUD_FMT_S16,
+ .endianness = AUDIO_HOST_ENDIANNESS,
}
},
- { /* ADC fixed settings */
- 1, /* enabled */
- 1, /* nb_voices */
- 1, /* greedy */
- {
- 44100, /* freq */
- 2, /* nchannels */
- AUD_FMT_S16, /* fmt */
- AUDIO_HOST_ENDIANNESS
+ .fixed_in = { /* ADC fixed settings */
+ .enabled = 1,
+ .nb_voices = 1,
+ .greedy = 1,
+ .settings = {
+ .freq = 44100,
+ .nchannels = 2,
+ .fmt = AUD_FMT_S16,
+ .endianness = AUDIO_HOST_ENDIANNESS,
}
},
- { 250 }, /* period */
- 0, /* plive */
- 0 /* log_to_monitor */
+ .period = { .hertz = 250 },
+ .plive = 0,
+ .log_to_monitor = 0,
+ .try_poll_in = 1,
+ .try_poll_out = 1,
};
static AudioState glob_audio_state;
struct mixeng_volume nominal_volume = {
- 0,
+ .mute = 0,
#ifdef FLOAT_MIXENG
- 1.0,
- 1.0
+ .r = 1.0,
+ .l = 1.0,
#else
- 1ULL << 32,
- 1ULL << 32
+ .r = 1ULL << 32,
+ .l = 1ULL << 32,
#endif
};
-#if 0
-/* http://www.df.lth.se/~john_e/gems/gem002d.html */
-/* http://www.multi-platforms.com/Tips/PopCount.htm */
-uint32_t popcount (uint32_t u)
-{
- u = ((u&0x55555555) + ((u>>1)&0x55555555));
- u = ((u&0x33333333) + ((u>>2)&0x33333333));
- u = ((u&0x0f0f0f0f) + ((u>>4)&0x0f0f0f0f));
- u = ((u&0x00ff00ff) + ((u>>8)&0x00ff00ff));
- u = ( u&0x0000ffff) + (u>>16);
- return u;
-}
-
-inline uint32_t lsbindex (uint32_t u)
-{
- return popcount ((u&-u)-1);
-}
-#endif
-
#ifdef AUDIO_IS_FLAWLESS_AND_NO_CHECKS_ARE_REQURIED
#error No its not
#else
+static void audio_print_options (const char *prefix,
+ struct audio_option *opt);
+
int audio_bug (const char *funcname, int cond)
{
if (cond) {
@@ -230,10 +218,16 @@ int audio_bug (const char *funcname, int cond)
AUD_log (NULL, "A bug was just triggered in %s\n", funcname);
if (!shown) {
+ struct audio_driver *d;
+
shown = 1;
AUD_log (NULL, "Save all your work and restart without audio\n");
- AUD_log (NULL, "Please send bug report to malc@pulsesoft.com\n");
+ AUD_log (NULL, "Please send bug report to av1474@comtv.ru\n");
AUD_log (NULL, "I am sorry\n");
+ d = glob_audio_state.drv;
+ if (d) {
+ audio_print_options (d->name, d->options);
+ }
}
AUD_log (NULL, "Context:\n");
@@ -966,6 +960,28 @@ int audio_pcm_hw_get_live_in (HWVoiceIn *hw)
return live;
}
+int audio_pcm_hw_clip_out (HWVoiceOut *hw, void *pcm_buf,
+ int live, int pending)
+{
+ int left = hw->samples - pending;
+ int len = audio_MIN (left, live);
+ int clipped = 0;
+
+ while (len) {
+ struct st_sample *src = hw->mix_buf + hw->rpos;
+ uint8_t *dst = advance (pcm_buf, hw->rpos << hw->info.shift);
+ int samples_till_end_of_buf = hw->samples - hw->rpos;
+ int samples_to_clip = audio_MIN (len, samples_till_end_of_buf);
+
+ hw->clip (dst, src, samples_to_clip);
+
+ hw->rpos = (hw->rpos + samples_to_clip) % hw->samples;
+ len -= samples_to_clip;
+ clipped += samples_to_clip;
+ }
+ return clipped;
+}
+
/*
* Soft voice (capture)
*/
@@ -1052,7 +1068,7 @@ static int audio_pcm_hw_find_min_out (HWVoiceOut *hw, int *nb_livep)
int nb_live = 0;
for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
- if (sw->active || !sw->empty) {
+ if (sw->active && !sw->empty) {
m = audio_MIN (m, sw->total_hw_samples_mixed);
nb_live += 1;
}
@@ -1062,16 +1078,17 @@ static int audio_pcm_hw_find_min_out (HWVoiceOut *hw, int *nb_livep)
return m;
}
-int audio_pcm_hw_get_live_out2 (HWVoiceOut *hw, int *nb_live)
+static int audio_pcm_hw_get_live_out (HWVoiceOut *hw, int *nb_live)
{
int smin;
+ int nb_live1;
- smin = audio_pcm_hw_find_min_out (hw, nb_live);
-
- if (!*nb_live) {
- return 0;
+ smin = audio_pcm_hw_find_min_out (hw, &nb_live1);
+ if (nb_live) {
+ *nb_live = nb_live1;
}
- else {
+
+ if (nb_live1) {
int live = smin;
if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) {
@@ -1080,19 +1097,7 @@ int audio_pcm_hw_get_live_out2 (HWVoiceOut *hw, int *nb_live)
}
return live;
}
-}
-
-int audio_pcm_hw_get_live_out (HWVoiceOut *hw)
-{
- int nb_live;
- int live;
-
- live = audio_pcm_hw_get_live_out2 (hw, &nb_live);
- if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) {
- dolog ("live=%d hw->samples=%d\n", live, hw->samples);
- return 0;
- }
- return live;
+ return 0;
}
/*
@@ -1185,6 +1190,76 @@ static void audio_pcm_print_info (const char *cap, struct audio_pcm_info *info)
#undef DAC
#include "audio_template.h"
+/*
+ * Timer
+ */
+static void audio_timer (void *opaque)
+{
+ AudioState *s = opaque;
+#if 0
+#define MAX_DIFFS 100
+ int64_t now = qemu_get_clock(vm_clock);
+ static int64_t last = 0;
+ static float diffs[MAX_DIFFS];
+ static int num_diffs;
+
+ if (last == 0)
+ last = now;
+ else {
+ diffs[num_diffs] = (float)((now-last)/1e6); /* last diff in ms */
+ if (++num_diffs == MAX_DIFFS) {
+ double min_diff = 1e6, max_diff = -1e6;
+ double all_diff = 0.;
+ int nn;
+
+ for (nn = 0; nn < num_diffs; nn++) {
+ if (diffs[nn] < min_diff) min_diff = diffs[nn];
+ if (diffs[nn] > max_diff) max_diff = diffs[nn];
+ all_diff += diffs[nn];
+ }
+ all_diff *= 1.0/num_diffs;
+ printf("audio timer: min_diff=%6.2g max_diff=%6.2g avg_diff=%6.2g samples=%d\n",
+ min_diff, max_diff, all_diff, num_diffs);
+ num_diffs = 0;
+ }
+ }
+ last = now;
+#endif
+
+ audio_run ("timer");
+ qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + conf.period.ticks);
+}
+
+
+static int audio_is_timer_needed (void)
+{
+ HWVoiceIn *hwi = NULL;
+ HWVoiceOut *hwo = NULL;
+
+ while ((hwo = audio_pcm_hw_find_any_enabled_out (hwo))) {
+ if (!hwo->poll_mode) return 1;
+ }
+ while ((hwi = audio_pcm_hw_find_any_enabled_in (hwi))) {
+ if (!hwi->poll_mode) return 1;
+ }
+ return 0;
+}
+
+static void audio_reset_timer (void)
+{
+ AudioState *s = &glob_audio_state;
+
+ if (audio_is_timer_needed ()) {
+ qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + 1);
+ }
+ else {
+ qemu_del_timer (s->ts);
+ }
+}
+
+/*
+ * Public API
+ */
int AUD_write (SWVoiceOut *sw, void *buf, int size)
{
int bytes;
@@ -1199,9 +1274,7 @@ int AUD_write (SWVoiceOut *sw, void *buf, int size)
return 0;
}
- BEGIN_NOSIGALRM
- bytes = sw->hw->pcm_ops->write (sw, buf, size);
- END_NOSIGALRM
+ bytes = sw->hw->pcm_ops->write (sw, buf, size);
return bytes;
}
@@ -1219,9 +1292,7 @@ int AUD_read (SWVoiceIn *sw, void *buf, int size)
return 0;
}
- BEGIN_NOSIGALRM
- bytes = sw->hw->pcm_ops->read (sw, buf, size);
- END_NOSIGALRM
+ bytes = sw->hw->pcm_ops->read (sw, buf, size);
return bytes;
}
@@ -1249,9 +1320,8 @@ void AUD_set_active_out (SWVoiceOut *sw, int on)
if (!hw->enabled) {
hw->enabled = 1;
if (s->vm_running) {
- BEGIN_NOSIGALRM
- hw->pcm_ops->ctl_out (hw, VOICE_ENABLE);
- END_NOSIGALRM
+ hw->pcm_ops->ctl_out (hw, VOICE_ENABLE, conf.try_poll_out);
+ audio_reset_timer ();
}
}
}
@@ -1295,9 +1365,7 @@ void AUD_set_active_in (SWVoiceIn *sw, int on)
if (!hw->enabled) {
hw->enabled = 1;
if (s->vm_running) {
- BEGIN_NOSIGALRM
- hw->pcm_ops->ctl_in (hw, VOICE_ENABLE);
- END_NOSIGALRM
+ hw->pcm_ops->ctl_in (hw, VOICE_ENABLE, conf.try_poll_in);
}
}
sw->total_hw_samples_acquired = hw->total_samples_captured;
@@ -1313,9 +1381,7 @@ void AUD_set_active_in (SWVoiceIn *sw, int on)
if (nb_active == 1) {
hw->enabled = 0;
- BEGIN_NOSIGALRM
- hw->pcm_ops->ctl_in (hw, VOICE_DISABLE);
- END_NOSIGALRM
+ hw->pcm_ops->ctl_in (hw, VOICE_DISABLE);
}
}
}
@@ -1418,7 +1484,7 @@ static void audio_run_out (AudioState *s)
int played;
int live, free, nb_live, cleanup_required, prev_rpos;
- live = audio_pcm_hw_get_live_out2 (hw, &nb_live);
+ live = audio_pcm_hw_get_live_out (hw, &nb_live);
if (!nb_live) {
live = 0;
}
@@ -1435,9 +1501,7 @@ static void audio_run_out (AudioState *s)
#endif
hw->enabled = 0;
hw->pending_disable = 0;
- BEGIN_NOSIGALRM
- hw->pcm_ops->ctl_out (hw, VOICE_DISABLE);
- END_NOSIGALRM
+ hw->pcm_ops->ctl_out (hw, VOICE_DISABLE);
for (sc = hw->cap_head.lh_first; sc; sc = sc->entries.le_next) {
sc->sw.active = 0;
audio_recalc_and_notify_capture (sc->cap);
@@ -1458,9 +1522,7 @@ static void audio_run_out (AudioState *s)
}
prev_rpos = hw->rpos;
- BEGIN_NOSIGALRM
- played = hw->pcm_ops->run_out (hw);
- END_NOSIGALRM
+ played = hw->pcm_ops->run_out (hw, live);
if (audio_bug (AUDIO_FUNC, hw->rpos >= hw->samples)) {
dolog ("hw->rpos=%d hw->samples=%d played=%d\n",
hw->rpos, hw->samples, played);
@@ -1478,7 +1540,7 @@ static void audio_run_out (AudioState *s)
cleanup_required = 0;
for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
- if (!sw->active && sw->empty) {
+ if (!sw->active || sw->empty) {
continue;
}
@@ -1529,9 +1591,7 @@ static void audio_run_in (AudioState *s)
SWVoiceIn *sw;
int captured, min;
- BEGIN_NOSIGALRM
- captured = hw->pcm_ops->run_in (hw);
- END_NOSIGALRM
+ captured = hw->pcm_ops->run_in (hw);
min = audio_pcm_hw_find_min_in (hw);
hw->total_samples_captured += captured - min;
@@ -1561,7 +1621,7 @@ static void audio_run_capture (AudioState *s)
HWVoiceOut *hw = &cap->hw;
SWVoiceOut *sw;
- captured = live = audio_pcm_hw_get_live_out (hw);
+ captured = live = audio_pcm_hw_get_live_out (hw, NULL);
rpos = hw->rpos;
while (live) {
int left = hw->samples - rpos;
@@ -1599,89 +1659,126 @@ static void audio_run_capture (AudioState *s)
}
}
-static void audio_timer (void *opaque)
+void audio_run (const char *msg)
{
- AudioState *s = opaque;
-#if 0
-#define MAX_DIFFS 1000
- int64_t now = qemu_get_clock(vm_clock);
- static int64_t last = 0;
- static float diffs[MAX_DIFFS];
- static int num_diffs;
+ AudioState *s = &glob_audio_state;
- if (last == 0)
- last = now;
- else {
- diffs[num_diffs] = (float)((now-last)/1e6); /* last diff in ms */
- if (++num_diffs == MAX_DIFFS) {
- double min_diff = 1e6, max_diff = -1e6;
- double all_diff = 0.;
- int nn;
-
- for (nn = 0; nn < num_diffs; nn++) {
- if (diffs[nn] < min_diff) min_diff = diffs[nn];
- if (diffs[nn] > max_diff) max_diff = diffs[nn];
- all_diff += diffs[nn];
- }
- all_diff *= 1.0/num_diffs;
- printf("audio timer: min_diff=%6.2g max_diff=%6.2g avg_diff=%6.2g samples=%d\n",
- min_diff, max_diff, all_diff, num_diffs);
- num_diffs = 0;
- }
- }
- last = now;
-#endif
audio_run_out (s);
audio_run_in (s);
audio_run_capture (s);
+#ifdef DEBUG_POLL
+ {
+ static double prevtime;
+ double currtime;
+ struct timeval tv;
- qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + conf.period.ticks);
+ if (gettimeofday (&tv, NULL)) {
+ perror ("audio_run: gettimeofday");
+ return;
+ }
+
+ currtime = tv.tv_sec + tv.tv_usec * 1e-6;
+ dolog ("Elapsed since last %s: %f\n", msg, currtime - prevtime);
+ prevtime = currtime;
+ }
+#endif
}
static struct audio_option audio_options[] = {
/* DAC */
- {"DAC_FIXED_SETTINGS", AUD_OPT_BOOL, &conf.fixed_out.enabled,
- "Use fixed settings for host DAC", NULL, 0},
-
- {"DAC_FIXED_FREQ", AUD_OPT_INT, &conf.fixed_out.settings.freq,
- "Frequency for fixed host DAC", NULL, 0},
-
- {"DAC_FIXED_FMT", AUD_OPT_FMT, &conf.fixed_out.settings.fmt,
- "Format for fixed host DAC", NULL, 0},
-
- {"DAC_FIXED_CHANNELS", AUD_OPT_INT, &conf.fixed_out.settings.nchannels,
- "Number of channels for fixed DAC (1 - mono, 2 - stereo)", NULL, 0},
-
- {"DAC_VOICES", AUD_OPT_INT, &conf.fixed_out.nb_voices,
- "Number of voices for DAC", NULL, 0},
-
+ {
+ .name = "DAC_FIXED_SETTINGS",
+ .tag = AUD_OPT_BOOL,
+ .valp = &conf.fixed_out.enabled,
+ .descr = "Use fixed settings for host DAC"
+ },
+ {
+ .name = "DAC_FIXED_FREQ",
+ .tag = AUD_OPT_INT,
+ .valp = &conf.fixed_out.settings.freq,
+ .descr = "Frequency for fixed host DAC"
+ },
+ {
+ .name = "DAC_FIXED_FMT",
+ .tag = AUD_OPT_FMT,
+ .valp = &conf.fixed_out.settings.fmt,
+ .descr = "Format for fixed host DAC"
+ },
+ {
+ .name = "DAC_FIXED_CHANNELS",
+ .tag = AUD_OPT_INT,
+ .valp = &conf.fixed_out.settings.nchannels,
+ .descr = "Number of channels for fixed DAC (1 - mono, 2 - stereo)"
+ },
+ {
+ .name = "DAC_VOICES",
+ .tag = AUD_OPT_INT,
+ .valp = &conf.fixed_out.nb_voices,
+ .descr = "Number of voices for DAC"
+ },
+ {
+ .name = "DAC_TRY_POLL",
+ .tag = AUD_OPT_BOOL,
+ .valp = &conf.try_poll_out,
+ .descr = "Attempt using poll mode for DAC"
+ },
/* ADC */
- {"ADC_FIXED_SETTINGS", AUD_OPT_BOOL, &conf.fixed_in.enabled,
- "Use fixed settings for host ADC", NULL, 0},
-
- {"ADC_FIXED_FREQ", AUD_OPT_INT, &conf.fixed_in.settings.freq,
- "Frequency for fixed host ADC", NULL, 0},
-
- {"ADC_FIXED_FMT", AUD_OPT_FMT, &conf.fixed_in.settings.fmt,
- "Format for fixed host ADC", NULL, 0},
-
- {"ADC_FIXED_CHANNELS", AUD_OPT_INT, &conf.fixed_in.settings.nchannels,
- "Number of channels for fixed ADC (1 - mono, 2 - stereo)", NULL, 0},
-
- {"ADC_VOICES", AUD_OPT_INT, &conf.fixed_in.nb_voices,
- "Number of voices for ADC", NULL, 0},
-
+ {
+ .name = "ADC_FIXED_SETTINGS",
+ .tag = AUD_OPT_BOOL,
+ .valp = &conf.fixed_in.enabled,
+ .descr = "Use fixed settings for host ADC"
+ },
+ {
+ .name = "ADC_FIXED_FREQ",
+ .tag = AUD_OPT_INT,
+ .valp = &conf.fixed_in.settings.freq,
+ .descr = "Frequency for fixed host ADC"
+ },
+ {
+ .name = "ADC_FIXED_FMT",
+ .tag = AUD_OPT_FMT,
+ .valp = &conf.fixed_in.settings.fmt,
+ .descr = "Format for fixed host ADC"
+ },
+ {
+ .name = "ADC_FIXED_CHANNELS",
+ .tag = AUD_OPT_INT,
+ .valp = &conf.fixed_in.settings.nchannels,
+ .descr = "Number of channels for fixed ADC (1 - mono, 2 - stereo)"
+ },
+ {
+ .name = "ADC_VOICES",
+ .tag = AUD_OPT_INT,
+ .valp = &conf.fixed_in.nb_voices,
+ .descr = "Number of voices for ADC"
+ },
+ {
+ .name = "ADC_TRY_POLL",
+ .tag = AUD_OPT_BOOL,
+ .valp = &conf.try_poll_in,
+ .descr = "Attempt using poll mode for ADC"
+ },
/* Misc */
- {"TIMER_PERIOD", AUD_OPT_INT, &conf.period.hertz,
- "Timer period in HZ (0 - use lowest possible)", NULL, 0},
-
- {"PLIVE", AUD_OPT_BOOL, &conf.plive,
- "(undocumented)", NULL, 0},
-
- {"LOG_TO_MONITOR", AUD_OPT_BOOL, &conf.log_to_monitor,
- "print logging messages to monitor instead of stderr", NULL, 0},
-
- {NULL, 0, NULL, NULL, NULL, 0}
+ {
+ .name = "TIMER_PERIOD",
+ .tag = AUD_OPT_INT,
+ .valp = &conf.period.hertz,
+ .descr = "Timer period in HZ (0 - use lowest possible)"
+ },
+ {
+ .name = "PLIVE",
+ .tag = AUD_OPT_BOOL,
+ .valp = &conf.plive,
+ .descr = "(undocumented)"
+ },
+ {
+ .name = "LOG_TO_MONITOR",
+ .tag = AUD_OPT_BOOL,
+ .valp = &conf.log_to_monitor,
+ .descr = "Print logging messages to monitor instead of stderr"
+ },
+ { /* End of list */ }
};
static void audio_pp_nb_voices (const char *typ, int nb)
@@ -1755,43 +1852,17 @@ void AUD_help (void)
);
}
-static int audio_driver_init (AudioState *s, struct audio_driver *drv, int out)
+static int audio_driver_init (AudioState *s, struct audio_driver *drv)
{
- void* opaque;
-
if (drv->options) {
audio_process_options (drv->name, drv->options);
}
+ s->drv_opaque = drv->init ();
- /* is the driver already initialized ? */
- if (out) {
- if (drv == s->drv_in) {
- s->drv_out = drv;
- s->drv_out_opaque = s->drv_in_opaque;
- return 0;
- }
- } else {
- if (drv == s->drv_out) {
- s->drv_in = drv;
- s->drv_in_opaque = s->drv_out_opaque;
- return 0;
- }
- }
-
- BEGIN_NOSIGALRM
- opaque = drv->init();
- END_NOSIGALRM
-
- if (opaque != NULL) {
+ if (s->drv_opaque) {
audio_init_nb_voices_out (drv);
audio_init_nb_voices_in (drv);
- if (out) {
- s->drv_out = drv;
- s->drv_out_opaque = opaque;
- } else {
- s->drv_in = drv;
- s->drv_in_opaque = opaque;
- }
+ s->drv = drv;
return 0;
}
else {
@@ -1809,19 +1880,17 @@ static void audio_vm_change_state_handler (void *opaque, int running,
int op = running ? VOICE_ENABLE : VOICE_DISABLE;
s->vm_running = running;
- BEGIN_NOSIGALRM
- while ((hwo = audio_pcm_hw_find_any_enabled_out (hwo))) {
- hwo->pcm_ops->ctl_out (hwo, op);
- }
+ while ((hwo = audio_pcm_hw_find_any_enabled_out (hwo))) {
+ hwo->pcm_ops->ctl_out (hwo, op, conf.try_poll_out);
+ }
- while ((hwi = audio_pcm_hw_find_any_enabled_in (hwi))) {
- hwi->pcm_ops->ctl_in (hwi, op);
- }
- END_NOSIGALRM
+ while ((hwi = audio_pcm_hw_find_any_enabled_in (hwi))) {
+ hwi->pcm_ops->ctl_in (hwi, op, conf.try_poll_in);
+ }
+ audio_reset_timer ();
}
-// to make sure audio_atexit() is only called once
-static int initialized = 0;
+static int initialized;
static void audio_atexit (void)
{
@@ -1832,7 +1901,6 @@ static void audio_atexit (void)
if (!initialized) return;
initialized = 0;
- BEGIN_NOSIGALRM
while ((hwo = audio_pcm_hw_find_any_enabled_out (hwo))) {
SWVoiceCap *sc;
@@ -1854,13 +1922,9 @@ static void audio_atexit (void)
hwi->pcm_ops->fini_in (hwi);
}
- if (s->drv_in) {
- s->drv_in->fini (s->drv_in_opaque);
+ if (s->drv) {
+ s->drv->fini (s->drv_opaque);
}
- if (s->drv_out) {
- s->drv_out->fini (s->drv_out_opaque);
- }
- END_NOSIGALRM
}
static void audio_save (QEMUFile *f, void *opaque)
@@ -1881,73 +1945,17 @@ static int audio_load (QEMUFile *f, void *opaque, int version_id)
return 0;
}
-static int
-find_audio_driver( AudioState* s, int out )
-{
- int i, done = 0, def;
- const char* envname;
- const char* drvname;
- struct audio_driver* drv = NULL;
- const char* drvtype = out ? "output" : "input";
-
- envname = out ? "QEMU_AUDIO_OUT_DRV" : "QEMU_AUDIO_IN_DRV";
- drvname = audio_get_conf_str(envname, NULL, &def);
- if (drvname == NULL) {
- drvname = audio_get_conf_str("QEMU_AUDIO_DRV", NULL, &def);
- }
-
- if (drvname != NULL) { /* look for a specific driver */
- for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
- if (!strcmp (drvname, drvtab[i]->name)) {
- drv = drvtab[i];
- break;
- }
- }
- }
-
- if (drv != NULL) {
- done = !audio_driver_init (s, drv, out);
- if (!done) {
- dolog ("Could not initialize '%s' %s audio backend, trying default one.\n",
- drvname, drvtype);
- dolog ("Run with -qemu -audio-help to list available backends\n");
- drv = NULL;
- }
- }
-
- if (!drv) {
- for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
- if (drvtab[i]->can_be_default) {
- drv = drvtab[i];
- done = !audio_driver_init (s, drv, out);
- if (done)
- break;
- }
- }
- }
-
- if (!done) {
- drv = &no_audio_driver;
- done = !audio_driver_init (s, drv, out);
- if (!done) {
- /* this should never happen */
- dolog ("Could not initialize audio subsystem\n");
- return -1;
- }
- dolog ("warning: Could not find suitable audio %s backend\n", drvtype);
- }
-
- if (VERBOSE_CHECK(init))
- dprint("using '%s' audio %s backend", drv->name, drvtype );
- return 0;
-}
static void audio_init (void)
{
+ size_t i;
+ int done = 0;
+ const char *drvname;
+ VMChangeStateEntry *e;
AudioState *s = &glob_audio_state;
- if (s->drv_out && s->drv_in) {
+ if (s->drv) {
return;
}
@@ -1979,13 +1987,45 @@ static void audio_init (void)
s->nb_hw_voices_in = 0;
}
- if ( find_audio_driver (s, 0) != 0 ||
- find_audio_driver (s, 1) != 0 ) {
- qemu_del_timer (s->ts);
- return;
+ {
+ int def;
+ drvname = audio_get_conf_str ("QEMU_AUDIO_DRV", NULL, &def);
}
- VMChangeStateEntry *e;
+ if (drvname) {
+ int found = 0;
+
+ for (i = 0; i < ARRAY_SIZE (drvtab); i++) {
+ if (!strcmp (drvname, drvtab[i]->name)) {
+ done = !audio_driver_init (s, drvtab[i]);
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ dolog ("Unknown audio driver `%s'\n", drvname);
+ dolog ("Run with -audio-help to list available drivers\n");
+ }
+ }
+
+ if (!done) {
+ for (i = 0; !done && i < ARRAY_SIZE (drvtab); i++) {
+ if (drvtab[i]->can_be_default) {
+ done = !audio_driver_init (s, drvtab[i]);
+ }
+ }
+ }
+
+ if (!done) {
+ done = !audio_driver_init (s, &no_audio_driver);
+ if (!done) {
+ hw_error("Could not initialize audio subsystem\n");
+ }
+ else {
+ dolog ("warning: Using timer based audio emulation\n");
+ }
+ }
if (conf.period.hertz <= 0) {
if (conf.period.hertz < 0) {
@@ -2004,12 +2044,11 @@ static void audio_init (void)
dolog ("warning: Could not register change state handler\n"
"(Audio can continue looping even after stopping the VM)\n");
}
-
initialized = 1;
QLIST_INIT (&s->card_head);
register_savevm ("audio", 0, 1, audio_save, audio_load, s);
- qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + conf.period.ticks);
+ audio_reset_timer();
}
void AUD_register_card (const char *name, QEMUSoundCard *card)
@@ -2026,11 +2065,6 @@ void AUD_remove_card (QEMUSoundCard *card)
qemu_free (card->name);
}
-// this was added to work around a deadlock in SDL when quitting
-void AUD_cleanup()
-{
- audio_atexit();
-}
CaptureVoiceOut *AUD_add_capture (
struct audsettings *as,
diff --git a/audio/audio_int.h b/audio/audio_int.h
index a78f394..c6afe81 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -70,6 +70,7 @@ typedef struct SWVoiceCap SWVoiceCap;
typedef struct HWVoiceOut {
int enabled;
+ int poll_mode;
int pending_disable;
struct audio_pcm_info info;
@@ -89,6 +90,7 @@ typedef struct HWVoiceOut {
typedef struct HWVoiceIn {
int enabled;
+ int poll_mode;
struct audio_pcm_info info;
t_sample *conv;
@@ -155,7 +157,7 @@ struct audio_driver {
struct audio_pcm_ops {
int (*init_out)(HWVoiceOut *hw, struct audsettings *as);
void (*fini_out)(HWVoiceOut *hw);
- int (*run_out) (HWVoiceOut *hw);
+ int (*run_out) (HWVoiceOut *hw, int live);
int (*write) (SWVoiceOut *sw, void *buf, int size);
int (*ctl_out) (HWVoiceOut *hw, int cmd, ...);
@@ -186,10 +188,8 @@ struct SWVoiceCap {
};
struct AudioState {
- struct audio_driver* drv_in;
- void* drv_in_opaque;
- struct audio_driver* drv_out;
- void* drv_out_opaque;
+ struct audio_driver *drv;
+ void *drv_opaque;
QEMUTimer *ts;
QLIST_HEAD (card_listhead, QEMUSoundCard) card_head;
@@ -203,6 +203,7 @@ struct AudioState {
extern struct audio_driver no_audio_driver;
extern struct audio_driver oss_audio_driver;
+extern struct audio_driver sdl_audio_driver;
extern struct audio_driver win_audio_driver;
extern struct audio_driver wav_audio_driver;
extern struct audio_driver fmod_audio_driver;
@@ -211,6 +212,7 @@ extern struct audio_driver coreaudio_audio_driver;
extern struct audio_driver dsound_audio_driver;
extern struct audio_driver esd_audio_driver;
extern struct audio_driver pa_audio_driver;
+extern struct audio_driver winwave_audio_driver;
extern struct mixeng_volume nominal_volume;
void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as);
@@ -220,12 +222,15 @@ int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int len);
int audio_pcm_hw_get_live_in (HWVoiceIn *hw);
int audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int len);
-int audio_pcm_hw_get_live_out (HWVoiceOut *hw);
-int audio_pcm_hw_get_live_out2 (HWVoiceOut *hw, int *nb_live);
+
+int audio_pcm_hw_clip_out (HWVoiceOut *hw, void *pcm_buf,
+ int live, int pending);
int audio_bug (const char *funcname, int cond);
void *audio_calloc (const char *funcname, int nmemb, size_t size);
+void audio_run (const char *msg);
+
#define VOICE_ENABLE 1
#define VOICE_DISABLE 2
diff --git a/audio/audio_pt_int.c b/audio/audio_pt_int.c
index e889a98..f15cc70 100644
--- a/audio/audio_pt_int.c
+++ b/audio/audio_pt_int.c
@@ -6,6 +6,8 @@
#include "audio_int.h"
#include "audio_pt_int.h"
+#include <signal.h>
+
static void logerr (struct audio_pt *pt, int err, const char *fmt, ...)
{
va_list ap;
@@ -23,9 +25,16 @@ int audio_pt_init (struct audio_pt *p, void *(*func) (void *),
{
int err, err2;
const char *efunc;
+ sigset_t set, old_set;
p->drv = drv;
+ err = sigfillset (&set);
+ if (err) {
+ logerr (p, errno, "%s(%s): sigfillset failed", cap, AUDIO_FUNC);
+ return -1;
+ }
+
err = pthread_mutex_init (&p->mutex, NULL);
if (err) {
efunc = "pthread_mutex_init";
@@ -38,7 +47,23 @@ int audio_pt_init (struct audio_pt *p, void *(*func) (void *),
goto err1;
}
+ err = pthread_sigmask (SIG_BLOCK, &set, &old_set);
+ if (err) {
+ efunc = "pthread_sigmask";
+ goto err2;
+ }
+
err = pthread_create (&p->thread, NULL, func, opaque);
+
+ err2 = pthread_sigmask (SIG_SETMASK, &old_set, NULL);
+ if (err2) {
+ logerr (p, err2, "%s(%s): pthread_sigmask (restore) failed",
+ cap, AUDIO_FUNC);
+ /* We have failed to restore original signal mask, all bets are off,
+ so terminate the process */
+ exit (EXIT_FAILURE);
+ }
+
if (err) {
efunc = "pthread_create";
goto err2;
diff --git a/audio/audio_template.h b/audio/audio_template.h
index 9f75f19..c0d07e5 100644
--- a/audio/audio_template.h
+++ b/audio/audio_template.h
@@ -245,8 +245,8 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (struct audsettings *as)
{
HW *hw;
AudioState *s = &glob_audio_state;
- struct audio_driver *drv = glue(s->drv_, TYPE);
- int err;
+ struct audio_driver *drv = s->drv;
+ int err;
if (!glue (s->nb_hw_voices_, TYPE)) {
return NULL;
@@ -433,7 +433,7 @@ SW *glue (AUD_open_, TYPE) (
goto fail;
}
- if (audio_bug (AUDIO_FUNC, !glue (s->drv_, TYPE))) {
+ if (audio_bug (AUDIO_FUNC, !s->drv)) {
dolog ("Can not open `%s' (no host audio driver)\n", name);
goto fail;
}
@@ -452,9 +452,9 @@ SW *glue (AUD_open_, TYPE) (
SW_NAME (sw), sw->info.freq, sw->info.bits, sw->info.nchannels);
dolog ("New %s freq %d, bits %d, channels %d\n",
name,
- freq,
- (fmt == AUD_FMT_S16 || fmt == AUD_FMT_U16) ? 16 : 8,
- nchannels);
+ as->freq,
+ (as->fmt == AUD_FMT_S16 || as->fmt == AUD_FMT_U16) ? 16 : 8,
+ as->nchannels);
#endif
if (live) {
@@ -496,6 +496,9 @@ SW *glue (AUD_open_, TYPE) (
sw->vol = nominal_volume;
sw->callback.fn = callback_fn;
sw->callback.opaque = callback_opaque;
+#ifdef DAC
+ sw->empty = 1;
+#endif
#ifdef DAC
if (live) {
@@ -548,7 +551,7 @@ uint64_t glue (AUD_get_elapsed_usec_, TYPE) (SW *sw, QEMUAudioTimeStamp *ts)
cur_ts = sw->hw->ts_helper;
old_ts = ts->old_ts;
- /* dolog ("cur %lld old %lld\n", cur_ts, old_ts); */
+ /* dolog ("cur %" PRId64 " old %" PRId64 "\n", cur_ts, old_ts); */
if (cur_ts >= old_ts) {
delta = cur_ts - old_ts;
diff --git a/audio/audio_win_int.c b/audio/audio_win_int.c
new file mode 100644
index 0000000..5869052
--- /dev/null
+++ b/audio/audio_win_int.c
@@ -0,0 +1,108 @@
+/* public domain */
+
+#include "qemu-common.h"
+#include "audio.h"
+
+#define AUDIO_CAP "win-int"
+#include <windows.h>
+#include <mmsystem.h>
+
+#include "audio.h"
+#include "audio_int.h"
+#include "audio_win_int.h"
+
+int waveformat_from_audio_settings (WAVEFORMATEX *wfx,
+ struct audsettings *as)
+{
+ memset (wfx, 0, sizeof (*wfx));
+
+ wfx->wFormatTag = WAVE_FORMAT_PCM;
+ wfx->nChannels = as->nchannels;
+ wfx->nSamplesPerSec = as->freq;
+ wfx->nAvgBytesPerSec = as->freq << (as->nchannels == 2);
+ wfx->nBlockAlign = 1 << (as->nchannels == 2);
+ wfx->cbSize = 0;
+
+ switch (as->fmt) {
+ case AUD_FMT_S8:
+ case AUD_FMT_U8:
+ wfx->wBitsPerSample = 8;
+ break;
+
+ case AUD_FMT_S16:
+ case AUD_FMT_U16:
+ wfx->wBitsPerSample = 16;
+ wfx->nAvgBytesPerSec <<= 1;
+ wfx->nBlockAlign <<= 1;
+ break;
+
+ case AUD_FMT_S32:
+ case AUD_FMT_U32:
+ wfx->wBitsPerSample = 32;
+ wfx->nAvgBytesPerSec <<= 2;
+ wfx->nBlockAlign <<= 2;
+ break;
+
+ default:
+ dolog ("Internal logic error: Bad audio format %d\n", as->freq);
+ return -1;
+ }
+
+ return 0;
+}
+
+int waveformat_to_audio_settings (WAVEFORMATEX *wfx,
+ struct audsettings *as)
+{
+ if (wfx->wFormatTag != WAVE_FORMAT_PCM) {
+ dolog ("Invalid wave format, tag is not PCM, but %d\n",
+ wfx->wFormatTag);
+ return -1;
+ }
+
+ if (!wfx->nSamplesPerSec) {
+ dolog ("Invalid wave format, frequency is zero\n");
+ return -1;
+ }
+ as->freq = wfx->nSamplesPerSec;
+
+ switch (wfx->nChannels) {
+ case 1:
+ as->nchannels = 1;
+ break;
+
+ case 2:
+ as->nchannels = 2;
+ break;
+
+ default:
+ dolog (
+ "Invalid wave format, number of channels is not 1 or 2, but %d\n",
+ wfx->nChannels
+ );
+ return -1;
+ }
+
+ switch (wfx->wBitsPerSample) {
+ case 8:
+ as->fmt = AUD_FMT_U8;
+ break;
+
+ case 16:
+ as->fmt = AUD_FMT_S16;
+ break;
+
+ case 32:
+ as->fmt = AUD_FMT_S32;
+ break;
+
+ default:
+ dolog ("Invalid wave format, bits per sample is not "
+ "8, 16 or 32, but %d\n",
+ wfx->wBitsPerSample);
+ return -1;
+ }
+
+ return 0;
+}
+
diff --git a/audio/audio_win_int.h b/audio/audio_win_int.h
new file mode 100644
index 0000000..fa5b3cb
--- /dev/null
+++ b/audio/audio_win_int.h
@@ -0,0 +1,10 @@
+#ifndef AUDIO_WIN_INT_H
+#define AUDIO_WIN_INT_H
+
+int waveformat_from_audio_settings (WAVEFORMATEX *wfx,
+ struct audsettings *as);
+
+int waveformat_to_audio_settings (WAVEFORMATEX *wfx,
+ struct audsettings *as);
+
+#endif /* AUDIO_WIN_INT_H */
diff --git a/audio/coreaudio.c b/audio/coreaudio.c
index 8abe0c4..26631df 100644
--- a/audio/coreaudio.c
+++ b/audio/coreaudio.c
@@ -27,13 +27,12 @@
#include <string.h> /* strerror */
#include <pthread.h> /* pthread_X */
+#include "qemu-common.h"
#include "audio.h"
#define AUDIO_CAP "coreaudio"
#include "audio_int.h"
-#define ENABLE_IN 1
-
#if 0
# define D(...) fprintf(stderr, __VA_ARGS__)
#else
@@ -152,11 +151,6 @@ static void GCC_FMT_ATTR (3, 4) coreaudio_logerr2 (
coreaudio_logstatus (status);
}
-static void coreaudio_atexit (void)
-{
- conf.isAtexit = 1;
-}
-
/***************************************************************************************/
/***************************************************************************************/
/*** ***/
@@ -177,9 +171,8 @@ typedef struct coreAudioVoice {
int pos;
} coreaudioVoice;
-
static inline UInt32
-coreaudio_voice_isPlaying (coreaudioVoice* core)
+coreaudio_voice_isPlaying (coreaudioVoice *core)
{
OSStatus status;
UInt32 result = 0;
@@ -194,8 +187,12 @@ coreaudio_voice_isPlaying (coreaudioVoice* core)
return result;
}
-static int
-coreaudio_voice_lock (coreaudioVoice* core, const char *fn_name)
+static void coreaudio_atexit (void)
+{
+ conf.isAtexit = 1;
+}
+
+static int coreaudio_voice_lock (coreaudioVoice *core, const char *fn_name)
{
int err;
@@ -209,7 +206,7 @@ coreaudio_voice_lock (coreaudioVoice* core, const char *fn_name)
}
static int
-coreaudio_voice_unlock (coreaudioVoice* core, const char *fn_name)
+coreaudio_voice_unlock (coreaudioVoice *core, const char *fn_name)
{
int err;
@@ -465,18 +462,15 @@ typedef struct coreaudioVoiceOut {
#define CORE_OUT(hw) ((coreaudioVoiceOut*)(hw))->core
-static int
-coreaudio_run_out (HWVoiceOut *hw)
+static int coreaudio_run_out (HWVoiceOut *hw, int live)
{
- int live, decr;
- coreaudioVoice *core = CORE_OUT(hw);
+ int decr;
+ coreaudioVoice *core = CORE_OUT(hw);
if (coreaudio_voice_lock (core, "coreaudio_run_out")) {
return 0;
}
- live = audio_pcm_hw_get_live_out (hw);
-
if (core->decr > live) {
ldebug ("core->decr %d live %d core->live %d\n",
core->decr,
@@ -484,19 +478,18 @@ coreaudio_run_out (HWVoiceOut *hw)
core->live);
}
- decr = audio_MIN (core->decr, live);
+ decr = audio_MIN (core->decr, live);
core->decr -= decr;
- core->live = live - decr;
- hw->rpos = core->pos;
+
+ core->live = live - decr;
+ hw->rpos = core->pos;
coreaudio_voice_unlock (core, "coreaudio_run_out");
return decr;
}
-
/* callback to feed audiooutput buffer */
-static OSStatus
-audioOutDeviceIOProc(
+static OSStatus audioOutDeviceIOProc(
AudioDeviceID inDevice,
const AudioTimeStamp* inNow,
const AudioBufferList* inInputData,
@@ -555,27 +548,25 @@ audioOutDeviceIOProc(
rpos = (rpos + frameCount) % hw->samples;
core->decr += frameCount;
- core->pos = rpos;
+ core->pos = rpos;
coreaudio_voice_unlock (core, "audioDeviceIOProc");
return 0;
}
-static int
-coreaudio_write (SWVoiceOut *sw, void *buf, int len)
+static int coreaudio_write (SWVoiceOut *sw, void *buf, int len)
{
return audio_pcm_sw_write (sw, buf, len);
}
-static int
-coreaudio_init_out (HWVoiceOut *hw, struct audsettings *as)
+static int coreaudio_init_out (HWVoiceOut *hw, struct audsettings *as)
{
coreaudioVoice* core = CORE_OUT(hw);
- int err;
+ int err;
audio_pcm_init_info (&hw->info, as);
- err = coreaudio_voice_init( core, as, conf.out_buffer_frames, audioOutDeviceIOProc, hw, 0 );
+ err = coreaudio_voice_init (core, as, conf.out_buffer_frames, audioOutDeviceIOProc, hw, 0);
if (err < 0)
return err;
@@ -583,21 +574,19 @@ coreaudio_init_out (HWVoiceOut *hw, struct audsettings *as)
return 0;
}
-static void
-coreaudio_fini_out (HWVoiceOut *hw)
+static void coreaudio_fini_out (HWVoiceOut *hw)
{
+ coreaudioVoice *core = CORE_OUT(hw);
- coreaudioVoice* core = CORE_OUT(hw);
-
- coreaudio_voice_fini(core);
+ coreaudio_voice_fini (core);
}
static int
coreaudio_ctl_out (HWVoiceOut *hw, int cmd, ...)
{
- coreaudioVoice* core = CORE_OUT(hw);
+ coreaudioVoice *core = CORE_OUT(hw);
- return coreaudio_voice_ctl(core, cmd);
+ return coreaudio_voice_ctl (core, cmd);
}
/***************************************************************************************/
@@ -615,15 +604,14 @@ typedef struct coreaudioVoiceIn {
coreaudioVoice core[1];
} coreaudioVoiceIn;
-#define CORE_IN(hw) ((coreaudioVoiceIn*)(hw))->core
+#define CORE_IN(hw) ((coreaudioVoiceIn *) (hw))->core
-static int
-coreaudio_run_in (HWVoiceIn *hw)
+static int coreaudio_run_in (HWVoiceIn *hw, int live)
{
int decr;
- coreaudioVoice *core = CORE_IN(hw);
+ coreaudioVoice *core = CORE_IN(hw);
if (coreaudio_voice_lock (core, "coreaudio_run_in")) {
return 0;
@@ -639,8 +627,7 @@ coreaudio_run_in (HWVoiceIn *hw)
/* callback to feed audiooutput buffer */
-static OSStatus
-audioInDeviceIOProc(
+static OSStatus audioInDeviceIOProc(
AudioDeviceID inDevice,
const AudioTimeStamp* inNow,
const AudioBufferList* inInputData,
@@ -712,7 +699,7 @@ audioInDeviceIOProc(
static int
coreaudio_read (SWVoiceIn *sw, void *buf, int len)
{
- int result = audio_pcm_sw_read(sw, buf, len);
+ int result = audio_pcm_sw_read (sw, buf, len);
D("%s: audio_pcm_sw_read(%d) returned %d\n", __FUNCTION__, len, result);
return result;
}
@@ -725,7 +712,7 @@ coreaudio_init_in (HWVoiceIn *hw, struct audsettings *as)
audio_pcm_init_info (&hw->info, as);
- err = coreaudio_voice_init( core, as, conf.in_buffer_frames, audioInDeviceIOProc, hw, 1 );
+ err = coreaudio_voice_init (core, as, conf.in_buffer_frames, audioInDeviceIOProc, hw, 1);
if (err < 0) {
return err;
}
@@ -751,71 +738,69 @@ coreaudio_ctl_in (HWVoiceIn *hw, int cmd, ...)
return coreaudio_voice_ctl(core, cmd);
}
-static void*
-coreaudio_audio_init (void)
+static void *coreaudio_audio_init (void)
{
atexit(coreaudio_atexit);
return &coreaudio_audio_init;
}
-static void
-coreaudio_audio_fini (void *opaque)
+static void coreaudio_audio_fini (void *opaque)
{
(void) opaque;
}
static struct audio_option coreaudio_options[] = {
- {"OUT_BUFFER_SIZE", AUD_OPT_INT, &conf.out_buffer_frames,
- "Size of the output buffer in frames", NULL, 0},
- {"OUT_BUFFER_COUNT", AUD_OPT_INT, &conf.out_nbuffers,
- "Number of output buffers", NULL, 0},
- {"IN_BUFFER_SIZE", AUD_OPT_INT, &conf.in_buffer_frames,
- "Size of the input buffer in frames", NULL, 0},
- {"IN_BUFFER_COUNT", AUD_OPT_INT, &conf.in_nbuffers,
- "Number of input buffers", NULL, 0},
- {NULL, 0, NULL, NULL, NULL, 0}
+ {
+ .name = "OUT_BUFFER_SIZE",
+ .tag = AUD_OPT_INT,
+ .valp = &conf.out_buffer_frames,
+ .descr = "Size of the output buffer in frames"
+ },
+ {
+ .name = "OUT_BUFFER_COUNT",
+ .tag = AUD_OPT_INT,
+ .valp = &conf.out_nbuffers,
+ .descr = "Number of output buffers"
+ },
+ {
+ .name = "IN_BUFFER_SIZE",
+ .tag = AUD_OPT_INT,
+ .valp = &conf.in_buffer_frames,
+ .descr = "Size of the input buffer in frames"
+ },
+ {
+ .name = "IN_BUFFER_COUNT",
+ .tag = AUD_OPT_INT,
+ .valp = &conf.in_nbuffers,
+ .descr = "Number of input buffers"
+ },
+ { /* End of list */ }
};
static struct audio_pcm_ops coreaudio_pcm_ops = {
- coreaudio_init_out,
- coreaudio_fini_out,
- coreaudio_run_out,
- coreaudio_write,
- coreaudio_ctl_out,
-
-#if ENABLE_IN
- coreaudio_init_in,
- coreaudio_fini_in,
- coreaudio_run_in,
- coreaudio_read,
- coreaudio_ctl_in
-#else
- NULL,
- NULL,
- NULL,
- NULL,
- NULL
-#endif
+ .init_out = coreaudio_init_out,
+ .fini_out = coreaudio_fini_out,
+ .run_out = coreaudio_run_out,
+ .write = coreaudio_write,
+ .ctl_out = coreaudio_ctl_out
+
+ .init_in = coreaudio_init_in,
+ .fini_in = coreaudio_fini_in,
+ .run_in = coreaudio_run_in,
+ .read = coreaudio_read,
+ .ctl_in = coreaudio_ctl_in
};
struct audio_driver coreaudio_audio_driver = {
- INIT_FIELD (name = ) "coreaudio",
- INIT_FIELD (descr = )
- "CoreAudio (developer.apple.com/audio/coreaudio.html)",
- INIT_FIELD (options = ) coreaudio_options,
- INIT_FIELD (init = ) coreaudio_audio_init,
- INIT_FIELD (fini = ) coreaudio_audio_fini,
- INIT_FIELD (pcm_ops = ) &coreaudio_pcm_ops,
- INIT_FIELD (can_be_default = ) 1,
-#if ENABLE_IN
- INIT_FIELD (max_voices_out = ) 1,
- INIT_FIELD (max_voices_in = ) 1,
- INIT_FIELD (voice_size_out = ) sizeof (coreaudioVoiceOut),
- INIT_FIELD (voice_size_in = ) sizeof (coreaudioVoiceIn),
-#else
- INIT_FIELD (max_voices_out = ) 1,
- INIT_FIELD (max_voices_in = ) 0,
- INIT_FIELD (voice_size_out = ) sizeof (coreaudioVoiceOut),
- INIT_FIELD (voice_size_in = ) 0,
-#endif
+ .name = "coreaudio",
+ .descr = "CoreAudio http://developer.apple.com/audio/coreaudio.html",
+ .options = coreaudio_options,
+ .init = coreaudio_audio_init,
+ .fini = coreaudio_audio_fini,
+ .pcm_ops = &coreaudio_pcm_ops,
+ .can_be_default = 1,
+ .max_voices_out = 1,
+ .max_voices_in = 1,
+ .voice_size_out = sizeof (coreaudioVoiceOut),
+ .voice_size_in = sizeof (coreaudioVoiceIn),
};
diff --git a/audio/dsound_template.h b/audio/dsound_template.h
index 9cc0b9d..8b37d16 100644
--- a/audio/dsound_template.h
+++ b/audio/dsound_template.h
@@ -174,16 +174,16 @@ static void dsound_fini_out (HWVoiceOut *hw)
}
#ifdef DSBTYPE_IN
-static int dsound_init_in (HWVoiceIn *hw, audsettings_t *as)
+static int dsound_init_in (HWVoiceIn *hw, struct audsettings *as)
#else
-static int dsound_init_out (HWVoiceOut *hw, audsettings_t *as)
+static int dsound_init_out (HWVoiceOut *hw, struct audsettings *as)
#endif
{
int err;
HRESULT hr;
dsound *s = &glob_dsound;
WAVEFORMATEX wfx;
- audsettings_t obt_as;
+ struct audsettings obt_as;
#ifdef DSBTYPE_IN
const char *typ = "ADC";
DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
@@ -285,7 +285,9 @@ static int dsound_init_out (HWVoiceOut *hw, audsettings_t *as)
}
#undef NAME
+#undef NAME2
#undef TYPE
#undef IFACE
#undef BUFPTR
#undef FIELD
+#undef FIELD2
diff --git a/audio/dsoundaudio.c b/audio/dsoundaudio.c
index 8284067..e547955 100644
--- a/audio/dsoundaudio.c
+++ b/audio/dsoundaudio.c
@@ -26,17 +26,19 @@
* SEAL 1.07 by Carlos 'pel' Hasan was used as documentation
*/
+#include "qemu-common.h"
#include "audio.h"
#define AUDIO_CAP "dsound"
#include "audio_int.h"
-#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <mmsystem.h>
#include <objbase.h>
#include <dsound.h>
+#include "audio_win_int.h"
+
/* #define DEBUG_DSOUND */
static struct {
@@ -46,28 +48,26 @@ static struct {
int set_primary;
int bufsize_in;
int bufsize_out;
- audsettings_t settings;
+ struct audsettings settings;
int latency_millis;
} conf = {
- 1,
- 1,
- 1,
- 0,
- 16384,
- 16384,
- {
- 44100,
- 2,
- AUD_FMT_S16
- },
- 10
+ .lock_retries = 1,
+ .restore_retries = 1,
+ .getstatus_retries = 1,
+ .set_primary = 0,
+ .bufsize_in = 16384,
+ .bufsize_out = 16384,
+ .settings.freq = 44100,
+ .settings.nchannels = 2,
+ .settings.fmt = AUD_FMT_S16,
+ .latency_millis = 10
};
typedef struct {
LPDIRECTSOUND dsound;
LPDIRECTSOUNDCAPTURE dsound_capture;
LPDIRECTSOUNDBUFFER dsound_primary_buffer;
- audsettings_t settings;
+ struct audsettings settings;
} dsound;
static dsound glob_dsound;
@@ -306,99 +306,6 @@ static int dsound_restore_out (LPDIRECTSOUNDBUFFER dsb)
return -1;
}
-static int waveformat_from_audio_settings (WAVEFORMATEX *wfx, audsettings_t *as)
-{
- memset (wfx, 0, sizeof (*wfx));
-
- wfx->wFormatTag = WAVE_FORMAT_PCM;
- wfx->nChannels = as->nchannels;
- wfx->nSamplesPerSec = as->freq;
- wfx->nAvgBytesPerSec = as->freq << (as->nchannels == 2);
- wfx->nBlockAlign = 1 << (as->nchannels == 2);
- wfx->cbSize = 0;
-
- switch (as->fmt) {
- case AUD_FMT_S8:
- case AUD_FMT_U8:
- wfx->wBitsPerSample = 8;
- break;
-
- case AUD_FMT_S16:
- case AUD_FMT_U16:
- wfx->wBitsPerSample = 16;
- wfx->nAvgBytesPerSec <<= 1;
- wfx->nBlockAlign <<= 1;
- break;
-
- case AUD_FMT_S32:
- case AUD_FMT_U32:
- wfx->wBitsPerSample = 32;
- wfx->nAvgBytesPerSec <<= 2;
- wfx->nBlockAlign <<= 2;
- break;
-
- default:
- dolog ("Internal logic error: Bad audio format %d\n", as->freq);
- return -1;
- }
-
- return 0;
-}
-
-static int waveformat_to_audio_settings (WAVEFORMATEX *wfx, audsettings_t *as)
-{
- if (wfx->wFormatTag != WAVE_FORMAT_PCM) {
- dolog ("Invalid wave format, tag is not PCM, but %d\n",
- wfx->wFormatTag);
- return -1;
- }
-
- if (!wfx->nSamplesPerSec) {
- dolog ("Invalid wave format, frequency is zero\n");
- return -1;
- }
- as->freq = wfx->nSamplesPerSec;
-
- switch (wfx->nChannels) {
- case 1:
- as->nchannels = 1;
- break;
-
- case 2:
- as->nchannels = 2;
- break;
-
- default:
- dolog (
- "Invalid wave format, number of channels is not 1 or 2, but %d\n",
- wfx->nChannels
- );
- return -1;
- }
-
- switch (wfx->wBitsPerSample) {
- case 8:
- as->fmt = AUD_FMT_U8;
- break;
-
- case 16:
- as->fmt = AUD_FMT_S16;
- break;
-
- case 32:
- as->fmt = AUD_FMT_S32;
- break;
-
- default:
- dolog ("Invalid wave format, bits per sample is not "
- "8, 16 or 32, but %d\n",
- wfx->wBitsPerSample);
- return -1;
- }
-
- return 0;
-}
-
#include "dsound_template.h"
#define DSBTYPE_IN
#include "dsound_template.h"
@@ -447,8 +354,8 @@ static void dsound_write_sample (HWVoiceOut *hw, uint8_t *dst, int dst_len)
int src_len1 = dst_len;
int src_len2 = 0;
int pos = hw->rpos + dst_len;
- st_sample_t *src1 = hw->mix_buf + hw->rpos;
- st_sample_t *src2 = NULL;
+ struct st_sample *src1 = hw->mix_buf + hw->rpos;
+ struct st_sample *src2 = NULL;
if (pos > hw->samples) {
src_len1 = hw->samples - hw->rpos;
@@ -658,13 +565,13 @@ static int dsound_write (SWVoiceOut *sw, void *buf, int len)
return audio_pcm_sw_write (sw, buf, len);
}
-static int dsound_run_out (HWVoiceOut *hw)
+static int dsound_run_out (HWVoiceOut *hw, int live)
{
int err;
HRESULT hr;
DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
LPDIRECTSOUNDBUFFER dsb = ds->dsound_buffer;
- int live, len, hwshift;
+ int len, hwshift;
DWORD blen1, blen2;
DWORD len1, len2;
DWORD decr;
@@ -680,8 +587,6 @@ static int dsound_run_out (HWVoiceOut *hw)
hwshift = hw->info.shift;
bufsize = hw->samples << hwshift;
- live = audio_pcm_hw_get_live_out (hw);
-
hr = IDirectSoundBuffer_GetCurrentPosition (
dsb,
&ppos,
@@ -1033,54 +938,93 @@ static void *dsound_audio_init (void)
}
static struct audio_option dsound_options[] = {
- {"LOCK_RETRIES", AUD_OPT_INT, &conf.lock_retries,
- "Number of times to attempt locking the buffer", NULL, 0},
- {"RESTOURE_RETRIES", AUD_OPT_INT, &conf.restore_retries,
- "Number of times to attempt restoring the buffer", NULL, 0},
- {"GETSTATUS_RETRIES", AUD_OPT_INT, &conf.getstatus_retries,
- "Number of times to attempt getting status of the buffer", NULL, 0},
- {"SET_PRIMARY", AUD_OPT_BOOL, &conf.set_primary,
- "Set the parameters of primary buffer", NULL, 0},
- {"LATENCY_MILLIS", AUD_OPT_INT, &conf.latency_millis,
- "(undocumented)", NULL, 0},
- {"PRIMARY_FREQ", AUD_OPT_INT, &conf.settings.freq,
- "Primary buffer frequency", NULL, 0},
- {"PRIMARY_CHANNELS", AUD_OPT_INT, &conf.settings.nchannels,
- "Primary buffer number of channels (1 - mono, 2 - stereo)", NULL, 0},
- {"PRIMARY_FMT", AUD_OPT_FMT, &conf.settings.fmt,
- "Primary buffer format", NULL, 0},
- {"BUFSIZE_OUT", AUD_OPT_INT, &conf.bufsize_out,
- "(undocumented)", NULL, 0},
- {"BUFSIZE_IN", AUD_OPT_INT, &conf.bufsize_in,
- "(undocumented)", NULL, 0},
- {NULL, 0, NULL, NULL, NULL, 0}
+ {
+ .name = "LOCK_RETRIES",
+ .tag = AUD_OPT_INT,
+ .valp = &conf.lock_retries,
+ .descr = "Number of times to attempt locking the buffer"
+ },
+ {
+ .name = "RESTOURE_RETRIES",
+ .tag = AUD_OPT_INT,
+ .valp = &conf.restore_retries,
+ .descr = "Number of times to attempt restoring the buffer"
+ },
+ {
+ .name = "GETSTATUS_RETRIES",
+ .tag = AUD_OPT_INT,
+ .valp = &conf.getstatus_retries,
+ .descr = "Number of times to attempt getting status of the buffer"
+ },
+ {
+ .name = "SET_PRIMARY",
+ .tag = AUD_OPT_BOOL,
+ .valp = &conf.set_primary,
+ .descr = "Set the parameters of primary buffer"
+ },
+ {
+ .name = "LATENCY_MILLIS",
+ .tag = AUD_OPT_INT,
+ .valp = &conf.latency_millis,
+ .descr = "(undocumented)"
+ },
+ {
+ .name = "PRIMARY_FREQ",
+ .tag = AUD_OPT_INT,
+ .valp = &conf.settings.freq,
+ .descr = "Primary buffer frequency"
+ },
+ {
+ .name = "PRIMARY_CHANNELS",
+ .tag = AUD_OPT_INT,
+ .valp = &conf.settings.nchannels,
+ .descr = "Primary buffer number of channels (1 - mono, 2 - stereo)"
+ },
+ {
+ .name = "PRIMARY_FMT",
+ .tag = AUD_OPT_FMT,
+ .valp = &conf.settings.fmt,
+ .descr = "Primary buffer format"
+ },
+ {
+ .name = "BUFSIZE_OUT",
+ .tag = AUD_OPT_INT,
+ .valp = &conf.bufsize_out,
+ .descr = "(undocumented)"
+ },
+ {
+ .name = "BUFSIZE_IN",
+ .tag = AUD_OPT_INT,
+ .valp = &conf.bufsize_in,
+ .descr = "(undocumented)"
+ },
+ { /* End of list */ }
};
static struct audio_pcm_ops dsound_pcm_ops = {
- dsound_init_out,
- dsound_fini_out,
- dsound_run_out,
- dsound_write,
- dsound_ctl_out,
-
- dsound_init_in,
- dsound_fini_in,
- dsound_run_in,
- dsound_read,
- dsound_ctl_in
+ .init_out = dsound_init_out,
+ .fini_out = dsound_fini_out,
+ .run_out = dsound_run_out,
+ .write = dsound_write,
+ .ctl_out = dsound_ctl_out,
+
+ .init_in = dsound_init_in,
+ .fini_in = dsound_fini_in,
+ .run_in = dsound_run_in,
+ .read = dsound_read,
+ .ctl_in = dsound_ctl_in
};
struct audio_driver dsound_audio_driver = {
- INIT_FIELD (name = ) "dsound",
- INIT_FIELD (descr = )
- "DirectSound audio (www.wikipedia.org/wiki/DirectSound)",
- INIT_FIELD (options = ) dsound_options,
- INIT_FIELD (init = ) dsound_audio_init,
- INIT_FIELD (fini = ) dsound_audio_fini,
- INIT_FIELD (pcm_ops = ) &dsound_pcm_ops,
- INIT_FIELD (can_be_default = ) 1,
- INIT_FIELD (max_voices_out = ) INT_MAX,
- INIT_FIELD (max_voices_in = ) 1,
- INIT_FIELD (voice_size_out = ) sizeof (DSoundVoiceOut),
- INIT_FIELD (voice_size_in = ) sizeof (DSoundVoiceIn)
+ .name = "dsound",
+ .descr = "DirectSound http://wikipedia.org/wiki/DirectSound",
+ .options = dsound_options,
+ .init = dsound_audio_init,
+ .fini = dsound_audio_fini,
+ .pcm_ops = &dsound_pcm_ops,
+ .can_be_default = 1,
+ .max_voices_out = INT_MAX,
+ .max_voices_in = 1,
+ .voice_size_out = sizeof (DSoundVoiceOut),
+ .voice_size_in = sizeof (DSoundVoiceIn)
};
diff --git a/audio/esdaudio.c b/audio/esdaudio.c
index 1d72125..84cbcb4 100644
--- a/audio/esdaudio.c
+++ b/audio/esdaudio.c
@@ -25,11 +25,10 @@
#include <esd.h>
#include "qemu-common.h"
#include "audio.h"
-#include <signal.h>
#define AUDIO_CAP "esd"
#include "audio_int.h"
-#include <dlfcn.h>
+#include "audio_pt_int.h"
#include "qemu_debug.h"
@@ -51,6 +50,23 @@
#define STRINGIFY_(x) #x
#define STRINGIFY(x) STRINGIFY_(x)
+#include <dlfcn.h>
+/* link dynamically to the libesd.so */
+
+#define DYNLINK_FUNCTIONS \
+ DYNLINK_FUNC(int,esd_play_stream,(esd_format_t,int,const char*,const char*)) \
+ DYNLINK_FUNC(int,esd_record_stream,(esd_format_t,int,const char*,const char*)) \
+ DYNLINK_FUNC(int,esd_open_sound,( const char *host )) \
+ DYNLINK_FUNC(int,esd_close,(int)) \
+
+#define DYNLINK_FUNCTIONS_INIT \
+ esd_dynlink_init
+
+#include "dynlink.h"
+
+static void* esd_lib;
+
+
typedef struct {
HWVoiceOut hw;
int done;
@@ -59,6 +75,7 @@ typedef struct {
int rpos;
void *pcm_buf;
int fd;
+ struct audio_pt pt;
} ESDVoiceOut;
typedef struct {
@@ -69,6 +86,7 @@ typedef struct {
int wpos;
void *pcm_buf;
int fd;
+ struct audio_pt pt;
} ESDVoiceIn;
static struct {
@@ -77,27 +95,10 @@ static struct {
char *dac_host;
char *adc_host;
} conf = {
- 1024,
- 2,
- NULL,
- NULL
+ .samples = 1024,
+ .divisor = 2,
};
-/* link dynamically to the libesd.so */
-
-#define DYNLINK_FUNCTIONS \
- DYNLINK_FUNC(int,esd_play_stream,(esd_format_t,int,const char*,const char*)) \
- DYNLINK_FUNC(int,esd_record_stream,(esd_format_t,int,const char*,const char*)) \
- DYNLINK_FUNC(int,esd_open_sound,( const char *host )) \
- DYNLINK_FUNC(int,esd_close,(int)) \
-
-#define DYNLINK_FUNCTIONS_INIT \
- esd_dynlink_init
-
-#include "dynlink.h"
-
-static void* esd_lib;
-
static void GCC_FMT_ATTR (2, 3) qesd_logerr (int err, const char *fmt, ...)
{
va_list ap;
@@ -109,50 +110,111 @@ static void GCC_FMT_ATTR (2, 3) qesd_logerr (int err, const char *fmt, ...)
AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err));
}
-static int qesd_run_out (HWVoiceOut *hw)
+/* playback */
+static void *qesd_thread_out (void *arg)
{
- 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;
- struct st_sample *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)
+ ESDVoiceOut *esd = arg;
+ HWVoiceOut *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 decr, to_mix, rpos;
+
+ for (;;) {
+ if (esd->done) {
+ goto exit;
+ }
+
+ if (esd->live > threshold) {
+ break;
+ }
+
+ if (audio_pt_wait (&esd->pt, AUDIO_FUNC)) {
+ goto exit;
+ }
+ }
+
+ decr = to_mix = esd->live;
+ rpos = hw->rpos;
+
+ if (audio_pt_unlock (&esd->pt, AUDIO_FUNC)) {
+ return NULL;
+ }
+
+ while (to_mix) {
+ ssize_t written;
+ int chunk = audio_MIN (to_mix, hw->samples - rpos);
+ struct st_sample *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");
+ 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 %zd), "
+ "alignment %d\n",
+ wbytes, written, hw->info.align + 1);
+ }
+ to_mix -= wsamples;
+ rpos = (rpos + wsamples) % hw->samples;
break;
- qesd_logerr (errno, "write failed: %s\n", strerror(errno));
- O("EsounD output thread write error: %s", strerror(errno));
- break;
+ }
+
+ rpos = (rpos + chunk) % hw->samples;
+ to_mix -= chunk;
}
- if (nwrite == 0)
- break;
-
- writeSamples = nwrite >> hw->info.shift;
- writeBytes = writeSamples << hw->info.shift;
- if (writeBytes != nwrite) {
- dolog ("warning: Misaligned write %d (requested %d), "
- "alignment %d\n",
- nwrite, writeBytes, hw->info.align + 1);
+
+ if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
+ return NULL;
}
- rpos = (rpos + writeSamples) % hw->samples;
- totalSamples += writeSamples;
- liveSamples -= writeSamples;
+
+ esd->rpos = rpos;
+ esd->live -= decr;
+ esd->decr += decr;
+ }
+
+ exit:
+ audio_pt_unlock (&esd->pt, AUDIO_FUNC);
+ return NULL;
+}
+
+static int qesd_run_out (HWVoiceOut *hw, int live)
+{
+ int decr;
+ ESDVoiceOut *esd = (ESDVoiceOut *) hw;
+
+ if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
+ return 0;
+ }
+
+ decr = audio_MIN (live, esd->decr);
+ esd->decr -= decr;
+ esd->live = live - decr;
+ hw->rpos = esd->rpos;
+ if (esd->live > 0) {
+ audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
+ }
+ else {
+ audio_pt_unlock (&esd->pt, AUDIO_FUNC);
}
- hw->rpos = rpos;
- return totalSamples;
+ return decr;
}
static int qesd_write (SWVoiceOut *sw, void *buf, int len)
@@ -165,13 +227,7 @@ static int qesd_init_out (HWVoiceOut *hw, struct audsettings *as)
ESDVoiceOut *esd = (ESDVoiceOut *) hw;
struct audsettings obt_as = *as;
int esdfmt = ESD_STREAM | ESD_PLAY;
- int result = -1;
- /* shut down verbose debug spew */
- if (!D_ACTIVE)
- stdio_disable();
-
- O("initializing EsoundD audio output");
esdfmt |= (as->nchannels == 2) ? ESD_STEREO : ESD_MONO;
switch (as->fmt) {
case AUD_FMT_S8:
@@ -179,11 +235,11 @@ static int qesd_init_out (HWVoiceOut *hw, struct audsettings *as)
esdfmt |= ESD_BITS8;
obt_as.fmt = AUD_FMT_U8;
break;
-#if 0
+
case AUD_FMT_S32:
case AUD_FMT_U32:
dolog ("Will use 16 instead of 32 bit samples\n");
-#endif
+
case AUD_FMT_S16:
case AUD_FMT_U16:
deffmt:
@@ -205,50 +261,53 @@ static int qesd_init_out (HWVoiceOut *hw, struct audsettings *as)
if (!esd->pcm_buf) {
dolog ("Could not allocate buffer (%d bytes)\n",
hw->samples << hw->info.shift);
- goto exit;
+ return -1;
}
esd->fd = FF(esd_play_stream) (esdfmt, as->freq, conf.dac_host, NULL);
if (esd->fd < 0) {
- if (conf.dac_host == NULL) {
- esd->fd = FF(esd_play_stream) (esdfmt, as->freq, "localhost", NULL);
- }
- if (esd->fd < 0) {
- qesd_logerr (errno, "esd_play_stream failed\n");
- goto fail2;
- }
+ qesd_logerr (errno, "esd_play_stream failed\n");
+ goto fail1;
}
- {
- int flags;
- flags = fcntl(esd->fd, F_GETFL);
- fcntl(esd->fd, F_SETFL, flags | O_NONBLOCK);
+ if (audio_pt_init (&esd->pt, qesd_thread_out, esd, AUDIO_CAP, AUDIO_FUNC)) {
+ goto fail2;
}
- result = 0; /* success */
- goto exit;
+ return 0;
fail2:
+ if (close (esd->fd)) {
+ qesd_logerr (errno, "%s: close on esd socket(%d) failed\n",
+ AUDIO_FUNC, esd->fd);
+ }
+ esd->fd = -1;
+
+ fail1:
qemu_free (esd->pcm_buf);
esd->pcm_buf = NULL;
-
- exit:
- if (!D_ACTIVE)
- stdio_enable();
-
- return result;
+ return -1;
}
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;
}
@@ -261,56 +320,112 @@ static int qesd_ctl_out (HWVoiceOut *hw, int cmd, ...)
}
/* capture */
-static int qesd_run_in (HWVoiceIn *hw)
+static void *qesd_thread_in (void *arg)
{
- int wpos, liveSamples, totalSamples;
- int grabSamples;
- ESDVoiceIn *esd = (ESDVoiceIn *) 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;
- 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)
+ for (;;) {
+ if (esd->done) {
+ goto exit;
+ }
+
+ if (esd->dead > threshold) {
break;
+ }
- qesd_logerr (errno, "read failed: %s\n", strerror(errno));
- break;
+ if (audio_pt_wait (&esd->pt, AUDIO_FUNC)) {
+ goto exit;
+ }
}
- if (nread == 0)
- break;
- readSamples = nread >> hw->info.shift;
- readBytes = readSamples << hw->info.shift;
+ incr = to_grab = esd->dead;
+ wpos = hw->wpos;
- if (readBytes != nread) {
- dolog ("warning: Misaligned read %d (requested %d), "
- "alignment %d\n",
- nread, readBytes, hw->info.align + 1);
+ if (audio_pt_unlock (&esd->pt, AUDIO_FUNC)) {
+ return NULL;
}
- hw->conv (hw->conv_buf + wpos, buf, readSamples,
- &nominal_volume);
+ 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 %zd), "
+ "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;
+ }
+
+ if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
+ return NULL;
+ }
- wpos = (wpos + readSamples) % hw->samples;
- grabSamples -= readSamples;
- totalSamples += readSamples;
+ esd->wpos = wpos;
+ esd->dead -= incr;
+ esd->incr += incr;
}
- hw->wpos = wpos;
- return totalSamples;
+
+ exit:
+ audio_pt_unlock (&esd->pt, AUDIO_FUNC);
+ return NULL;
+}
+
+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);
+ }
+ else {
+ audio_pt_unlock (&esd->pt, AUDIO_FUNC);
+ }
+ return incr;
}
static int qesd_read (SWVoiceIn *sw, void *buf, int len)
@@ -323,11 +438,6 @@ static int qesd_init_in (HWVoiceIn *hw, struct audsettings *as)
ESDVoiceIn *esd = (ESDVoiceIn *) hw;
struct audsettings obt_as = *as;
int esdfmt = ESD_STREAM | ESD_RECORD;
- int result = -1;
-
- /* shut down verbose debug spew */
- if (!D_ACTIVE)
- stdio_disable();
esdfmt |= (as->nchannels == 2) ? ESD_STEREO : ESD_MONO;
switch (as->fmt) {
@@ -359,50 +469,53 @@ static int qesd_init_in (HWVoiceIn *hw, struct audsettings *as)
if (!esd->pcm_buf) {
dolog ("Could not allocate buffer (%d bytes)\n",
hw->samples << hw->info.shift);
- goto exit;
+ return -1;
}
esd->fd = FF(esd_record_stream) (esdfmt, as->freq, conf.adc_host, NULL);
if (esd->fd < 0) {
- if (conf.adc_host == NULL) {
- esd->fd = FF(esd_record_stream) (esdfmt, as->freq, "localhost", NULL);
- }
- if (esd->fd < 0) {
- qesd_logerr (errno, "esd_record_stream failed\n");
- goto fail2;
- }
+ qesd_logerr (errno, "esd_record_stream failed\n");
+ goto fail1;
}
- {
- int flags;
- flags = fcntl(esd->fd, F_GETFL);
- fcntl(esd->fd, F_SETFL, flags | O_NONBLOCK);
+ if (audio_pt_init (&esd->pt, qesd_thread_in, esd, AUDIO_CAP, AUDIO_FUNC)) {
+ goto fail2;
}
- result = 0; /* success */
- goto exit;
+ return 0;
fail2:
+ if (close (esd->fd)) {
+ qesd_logerr (errno, "%s: close on esd socket(%d) failed\n",
+ AUDIO_FUNC, esd->fd);
+ }
+ esd->fd = -1;
+
+ fail1:
qemu_free (esd->pcm_buf);
esd->pcm_buf = NULL;
-
- exit:
- if (!D_ACTIVE)
- stdio_enable();
-
- return result;
+ return -1;
}
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;
}
@@ -473,46 +586,57 @@ static void qesd_audio_fini (void *opaque)
}
struct audio_option qesd_options[] = {
- {"SAMPLES", AUD_OPT_INT, &conf.samples,
- "buffer size in samples", NULL, 0},
-
- {"DIVISOR", AUD_OPT_INT, &conf.divisor,
- "threshold divisor", NULL, 0},
-
- {"DAC_HOST", AUD_OPT_STR, &conf.dac_host,
- "playback host", NULL, 0},
-
- {"ADC_HOST", AUD_OPT_STR, &conf.adc_host,
- "capture host", NULL, 0},
-
- {NULL, 0, NULL, NULL, NULL, 0}
+ {
+ .name = "SAMPLES",
+ .tag = AUD_OPT_INT,
+ .valp = &conf.samples,
+ .descr = "buffer size in samples"
+ },
+ {
+ .name = "DIVISOR",
+ .tag = AUD_OPT_INT,
+ .valp = &conf.divisor,
+ .descr = "threshold divisor"
+ },
+ {
+ .name = "DAC_HOST",
+ .tag = AUD_OPT_STR,
+ .valp = &conf.dac_host,
+ .descr = "playback host"
+ },
+ {
+ .name = "ADC_HOST",
+ .tag = AUD_OPT_STR,
+ .valp = &conf.adc_host,
+ .descr = "capture host"
+ },
+ { /* End of list */ }
};
static struct audio_pcm_ops qesd_pcm_ops = {
- qesd_init_out,
- qesd_fini_out,
- qesd_run_out,
- qesd_write,
- qesd_ctl_out,
-
- qesd_init_in,
- qesd_fini_in,
- qesd_run_in,
- qesd_read,
- qesd_ctl_in,
+ .init_out = qesd_init_out,
+ .fini_out = qesd_fini_out,
+ .run_out = qesd_run_out,
+ .write = qesd_write,
+ .ctl_out = qesd_ctl_out,
+
+ .init_in = qesd_init_in,
+ .fini_in = qesd_fini_in,
+ .run_in = qesd_run_in,
+ .read = qesd_read,
+ .ctl_in = qesd_ctl_in,
};
struct audio_driver esd_audio_driver = {
- INIT_FIELD (name = ) "esd",
- INIT_FIELD (descr = )
- "EsounD audio (en.wikipedia.org/wiki/Esound)",
- INIT_FIELD (options = ) qesd_options,
- INIT_FIELD (init = ) qesd_audio_init,
- INIT_FIELD (fini = ) qesd_audio_fini,
- INIT_FIELD (pcm_ops = ) &qesd_pcm_ops,
- INIT_FIELD (can_be_default = ) 1,
- INIT_FIELD (max_voices_out = ) INT_MAX,
- INIT_FIELD (max_voices_in = ) 1,
- INIT_FIELD (voice_size_out = ) sizeof (ESDVoiceOut),
- INIT_FIELD (voice_size_in = ) sizeof (ESDVoiceIn)
+ .name = "esd",
+ .descr = "http://en.wikipedia.org/wiki/Esound",
+ .options = qesd_options,
+ .init = qesd_audio_init,
+ .fini = qesd_audio_fini,
+ .pcm_ops = &qesd_pcm_ops,
+ .can_be_default = 0,
+ .max_voices_out = INT_MAX,
+ .max_voices_in = INT_MAX,
+ .voice_size_out = sizeof (ESDVoiceOut),
+ .voice_size_in = sizeof (ESDVoiceIn)
};
diff --git a/audio/fmodaudio.c b/audio/fmodaudio.c
index 0becd3b..7f08e14 100644
--- a/audio/fmodaudio.c
+++ b/audio/fmodaudio.c
@@ -47,16 +47,11 @@ static struct {
int freq;
int nb_channels;
int bufsize;
- int threshold;
int broken_adc;
} conf = {
- NULL,
- 2048 * 2,
- 44100,
- 2,
- 0,
- 0,
- 0
+ .nb_samples = 2048 * 2,
+ .freq = 44100,
+ .nb_channels = 2,
};
static void GCC_FMT_ATTR (1, 2) fmod_logerr (const char *fmt, ...)
@@ -229,24 +224,15 @@ static int fmod_lock_sample (
return 0;
}
-static int fmod_run_out (HWVoiceOut *hw)
+static int fmod_run_out (HWVoiceOut *hw, int live)
{
FMODVoiceOut *fmd = (FMODVoiceOut *) hw;
- int live, decr;
+ int decr;
void *p1 = 0, *p2 = 0;
unsigned int blen1 = 0, blen2 = 0;
unsigned int len1 = 0, len2 = 0;
- int nb_live;
- live = audio_pcm_hw_get_live_out2 (hw, &nb_live);
- if (!live) {
- return 0;
- }
-
- if (!hw->pending_disable
- && nb_live
- && (conf.threshold && live <= conf.threshold)) {
- ldebug ("live=%d nb_live=%d\n", live, nb_live);
+ if (!hw->pending_disable) {
return 0;
}
@@ -517,27 +503,27 @@ static struct {
const char *name;
int type;
} drvtab[] = {
- {"none", FSOUND_OUTPUT_NOSOUND},
+ { .name = "none", .type = FSOUND_OUTPUT_NOSOUND },
#ifdef _WIN32
- {"winmm", FSOUND_OUTPUT_WINMM},
- {"dsound", FSOUND_OUTPUT_DSOUND},
- {"a3d", FSOUND_OUTPUT_A3D},
- {"asio", FSOUND_OUTPUT_ASIO},
+ { .name = "winmm", .type = FSOUND_OUTPUT_WINMM },
+ { .name = "dsound", .type = FSOUND_OUTPUT_DSOUND },
+ { .name = "a3d", .type = FSOUND_OUTPUT_A3D },
+ { .name = "asio", .type = FSOUND_OUTPUT_ASIO },
#endif
#ifdef __linux__
- {"oss", FSOUND_OUTPUT_OSS},
- {"alsa", FSOUND_OUTPUT_ALSA},
- {"esd", FSOUND_OUTPUT_ESD},
+ { .name = "oss", .type = FSOUND_OUTPUT_OSS },
+ { .name = "alsa", .type = FSOUND_OUTPUT_ALSA },
+ { .name = "esd", .type = FSOUND_OUTPUT_ESD },
#endif
#ifdef __APPLE__
- {"mac", FSOUND_OUTPUT_MAC},
+ { .name = "mac", .type = FSOUND_OUTPUT_MAC },
#endif
#if 0
- {"xbox", FSOUND_OUTPUT_XBOX},
- {"ps2", FSOUND_OUTPUT_PS2},
- {"gcube", FSOUND_OUTPUT_GC},
+ { .name = "xbox", .type = FSOUND_OUTPUT_XBOX },
+ { .name = "ps2", .type = FSOUND_OUTPUT_PS2 },
+ { .name = "gcube", .type = FSOUND_OUTPUT_GC },
#endif
- {"none-realtime", FSOUND_OUTPUT_NOSOUND_NONREALTIME}
+ { .name = "none-realtime", .type = FSOUND_OUTPUT_NOSOUND_NONREALTIME }
};
static void *fmod_audio_init (void)
@@ -639,48 +625,63 @@ static void fmod_audio_fini (void *opaque)
}
static struct audio_option fmod_options[] = {
- {"DRV", AUD_OPT_STR, &conf.drvname,
- "FMOD driver", NULL, 0},
- {"FREQ", AUD_OPT_INT, &conf.freq,
- "Default frequency", NULL, 0},
- {"SAMPLES", AUD_OPT_INT, &conf.nb_samples,
- "Buffer size in samples", NULL, 0},
- {"CHANNELS", AUD_OPT_INT, &conf.nb_channels,
- "Number of default channels (1 - mono, 2 - stereo)", NULL, 0},
- {"BUFSIZE", AUD_OPT_INT, &conf.bufsize,
- "(undocumented)", NULL, 0},
-#if 0
- {"THRESHOLD", AUD_OPT_INT, &conf.threshold,
- "(undocumented)"},
-#endif
-
- {NULL, 0, NULL, NULL, NULL, 0}
+ {
+ .name = "DRV",
+ .tag = AUD_OPT_STR,
+ .valp = &conf.drvname,
+ .descr = "FMOD driver"
+ },
+ {
+ .name = "FREQ",
+ .tag = AUD_OPT_INT,
+ .valp = &conf.freq,
+ .descr = "Default frequency"
+ },
+ {
+ .name = "SAMPLES",
+ .tag = AUD_OPT_INT,
+ .valp = &conf.nb_samples,
+ .descr = "Buffer size in samples"
+ },
+ {
+ .name = "CHANNELS",
+ .tag = AUD_OPT_INT,
+ .valp = &conf.nb_channels,
+ .descr = "Number of default channels (1 - mono, 2 - stereo)"
+ },
+ {
+ .name = "BUFSIZE",
+ .tag = AUD_OPT_INT,
+ .valp = &conf.bufsize,
+ .descr = "(undocumented)"
+ },
+ { /* End of list */ }
};
static struct audio_pcm_ops fmod_pcm_ops = {
- fmod_init_out,
- fmod_fini_out,
- fmod_run_out,
- fmod_write,
- fmod_ctl_out,
-
- fmod_init_in,
- fmod_fini_in,
- fmod_run_in,
- fmod_read,
- fmod_ctl_in
+ .init_out = fmod_init_out,
+ .fini_out = fmod_fini_out,
+ .run_out = fmod_run_out,
+ .write = fmod_write,
+ .ctl_out = fmod_ctl_out,
+
+ .init_in = fmod_init_in,
+ .fini_in = fmod_fini_in,
+ .run_in = fmod_run_in,
+ .read = fmod_read,
+ .ctl_in = fmod_ctl_in
};
struct audio_driver fmod_audio_driver = {
- INIT_FIELD (name = ) "fmod",
- INIT_FIELD (descr = ) "FMOD 3.xx http://www.fmod.org",
- INIT_FIELD (options = ) fmod_options,
- INIT_FIELD (init = ) fmod_audio_init,
- INIT_FIELD (fini = ) fmod_audio_fini,
- INIT_FIELD (pcm_ops = ) &fmod_pcm_ops,
- INIT_FIELD (can_be_default = ) 1,
- INIT_FIELD (max_voices_out = ) INT_MAX,
- INIT_FIELD (max_voices_in = ) INT_MAX,
- INIT_FIELD (voice_size_out = ) sizeof (FMODVoiceOut),
- INIT_FIELD (voice_size_in = ) sizeof (FMODVoiceIn)
+ .name = "fmod",
+ .descr = "FMOD 3.xx http://www.fmod.org",
+ .options = fmod_options,
+ .init = fmod_audio_init,
+ .fini = fmod_audio_fini,
+ .pcm_ops = &fmod_pcm_ops,
+ .can_be_default = 1,
+ .max_voices_out = INT_MAX,
+ .max_voices_in = INT_MAX,
+ .voice_size_out = sizeof (FMODVoiceOut),
+ .voice_size_in = sizeof (FMODVoiceIn)
};
diff --git a/audio/mixeng.c b/audio/mixeng.c
index 8ce942e..9f1d93f 100644
--- a/audio/mixeng.c
+++ b/audio/mixeng.c
@@ -123,7 +123,7 @@
#undef IN_T
#undef SHIFT
-/* Unsigned 16 bit */
+/* Unsigned 32 bit */
#define IN_T uint32_t
#define IN_MIN 0
#define IN_MAX UINT32_MAX
diff --git a/audio/noaudio.c b/audio/noaudio.c
index 0209edb..4925234 100644
--- a/audio/noaudio.c
+++ b/audio/noaudio.c
@@ -38,19 +38,14 @@ typedef struct NoVoiceIn {
int64_t old_ticks;
} NoVoiceIn;
-static int no_run_out (HWVoiceOut *hw)
+static int no_run_out (HWVoiceOut *hw, int live)
{
NoVoiceOut *no = (NoVoiceOut *) hw;
- int live, decr, samples;
+ int decr, samples;
int64_t now;
int64_t ticks;
int64_t bytes;
- live = audio_pcm_hw_get_live_out (&no->hw);
- if (!live) {
- return 0;
- }
-
now = qemu_get_clock (vm_clock);
ticks = now - no->old_ticks;
bytes = muldiv64 (ticks, hw->info.bytes_per_second, get_ticks_per_sec ());
@@ -147,29 +142,29 @@ static void no_audio_fini (void *opaque)
}
static struct audio_pcm_ops no_pcm_ops = {
- no_init_out,
- no_fini_out,
- no_run_out,
- no_write,
- no_ctl_out,
-
- no_init_in,
- no_fini_in,
- no_run_in,
- no_read,
- no_ctl_in
+ .init_out = no_init_out,
+ .fini_out = no_fini_out,
+ .run_out = no_run_out,
+ .write = no_write,
+ .ctl_out = no_ctl_out,
+
+ .init_in = no_init_in,
+ .fini_in = no_fini_in,
+ .run_in = no_run_in,
+ .read = no_read,
+ .ctl_in = no_ctl_in
};
struct audio_driver no_audio_driver = {
- INIT_FIELD (name = ) "none",
- INIT_FIELD (descr = ) "disabled audio",
- INIT_FIELD (options = ) NULL,
- INIT_FIELD (init = ) no_audio_init,
- INIT_FIELD (fini = ) no_audio_fini,
- INIT_FIELD (pcm_ops = ) &no_pcm_ops,
- INIT_FIELD (can_be_default = ) 1,
- INIT_FIELD (max_voices_out = ) INT_MAX,
- INIT_FIELD (max_voices_in = ) INT_MAX,
- INIT_FIELD (voice_size_out = ) sizeof (NoVoiceOut),
- INIT_FIELD (voice_size_in = ) sizeof (NoVoiceIn)
+ .name = "none",
+ .descr = "Timer based audio emulation",
+ .options = NULL,
+ .init = no_audio_init,
+ .fini = no_audio_fini,
+ .pcm_ops = &no_pcm_ops,
+ .can_be_default = 1,
+ .max_voices_out = INT_MAX,
+ .max_voices_in = INT_MAX,
+ .voice_size_out = sizeof (NoVoiceOut),
+ .voice_size_in = sizeof (NoVoiceIn)
};
diff --git a/audio/ossaudio.c b/audio/ossaudio.c
index ceb81ce..42bffae 100644
--- a/audio/ossaudio.c
+++ b/audio/ossaudio.c
@@ -31,36 +31,26 @@
#include <sys/soundcard.h>
#endif
#include "qemu-common.h"
+#include "host-utils.h"
+#include "qemu-char.h"
#include "audio.h"
#define AUDIO_CAP "oss"
#include "audio_int.h"
-/* http://www.df.lth.se/~john_e/gems/gem002d.html */
-/* http://www.multi-platforms.com/Tips/PopCount.htm */
-uint32_t popcount (uint32_t u)
-{
- u = ((u&0x55555555) + ((u>>1)&0x55555555));
- u = ((u&0x33333333) + ((u>>2)&0x33333333));
- u = ((u&0x0f0f0f0f) + ((u>>4)&0x0f0f0f0f));
- u = ((u&0x00ff00ff) + ((u>>8)&0x00ff00ff));
- u = ( u&0x0000ffff) + (u>>16);
- return u;
-}
-
-inline uint32_t lsbindex (uint32_t u)
-{
- return popcount ((u&-u)-1);
-}
+#if defined OSS_GETVERSION && defined SNDCTL_DSP_POLICY
+#define USE_DSP_POLICY
+#endif
typedef struct OSSVoiceOut {
HWVoiceOut hw;
void *pcm_buf;
int fd;
+ int wpos;
int nfrags;
int fragsize;
int mmapped;
- int old_optr;
+ int pending;
} OSSVoiceOut;
typedef struct OSSVoiceIn {
@@ -69,7 +59,6 @@ typedef struct OSSVoiceIn {
int fd;
int nfrags;
int fragsize;
- int old_optr;
} OSSVoiceIn;
static struct {
@@ -79,13 +68,17 @@ static struct {
const char *devpath_out;
const char *devpath_in;
int debug;
+ int exclusive;
+ int policy;
} conf = {
.try_mmap = 0,
.nfrags = 4,
.fragsize = 4096,
.devpath_out = "/dev/dsp",
.devpath_in = "/dev/dsp",
- .debug = 0
+ .debug = 0,
+ .exclusive = 0,
+ .policy = 5
};
struct oss_params {
@@ -127,13 +120,42 @@ static void GCC_FMT_ATTR (3, 4) oss_logerr2 (
static void oss_anal_close (int *fdp)
{
- int err = close (*fdp);
+ int err;
+
+ qemu_set_fd_handler (*fdp, NULL, NULL, NULL);
+ err = close (*fdp);
if (err) {
oss_logerr (errno, "Failed to close file(fd=%d)\n", *fdp);
}
*fdp = -1;
}
+static void oss_helper_poll_out (void *opaque)
+{
+ (void) opaque;
+ audio_run ("oss_poll_out");
+}
+
+static void oss_helper_poll_in (void *opaque)
+{
+ (void) opaque;
+ audio_run ("oss_poll_in");
+}
+
+static int oss_poll_out (HWVoiceOut *hw)
+{
+ OSSVoiceOut *oss = (OSSVoiceOut *) hw;
+
+ return qemu_set_fd_handler (oss->fd, NULL, oss_helper_poll_out, NULL);
+}
+
+static int oss_poll_in (HWVoiceIn *hw)
+{
+ OSSVoiceIn *oss = (OSSVoiceIn *) hw;
+
+ return qemu_set_fd_handler (oss->fd, oss_helper_poll_in, NULL, NULL);
+}
+
static int oss_write (SWVoiceOut *sw, void *buf, int len)
{
return audio_pcm_sw_write (sw, buf, len);
@@ -218,17 +240,46 @@ static void oss_dump_info (struct oss_params *req, struct oss_params *obt)
}
#endif
+#ifdef USE_DSP_POLICY
+static int oss_get_version (int fd, int *version, const char *typ)
+{
+ if (ioctl (fd, OSS_GETVERSION, &version)) {
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+ /*
+ * Looks like atm (20100109) FreeBSD knows OSS_GETVERSION
+ * since 7.x, but currently only on the mixer device (or in
+ * the Linuxolator), and in the native version that part of
+ * the code is in fact never reached so the ioctl fails anyway.
+ * Until this is fixed, just check the errno and if its what
+ * FreeBSD's sound drivers return atm assume they are new enough.
+ */
+ if (errno == EINVAL) {
+ *version = 0x040000;
+ return 0;
+ }
+#endif
+ oss_logerr2 (errno, typ, "Failed to get OSS version\n");
+ return -1;
+ }
+ return 0;
+}
+#endif
+
static int oss_open (int in, struct oss_params *req,
struct oss_params *obt, int *pfd)
{
int fd;
- int mmmmssss;
+ int oflags = conf.exclusive ? O_EXCL : 0;
audio_buf_info abinfo;
int fmt, freq, nchannels;
+ int setfragment = 1;
const char *dspname = in ? conf.devpath_in : conf.devpath_out;
const char *typ = in ? "ADC" : "DAC";
- fd = open (dspname, (in ? O_RDONLY : O_WRONLY) | O_NONBLOCK);
+ /* Kludge needed to have working mmap on Linux */
+ oflags |= conf.try_mmap ? O_RDWR : (in ? O_RDONLY : O_WRONLY);
+
+ fd = open (dspname, oflags | O_NONBLOCK);
if (-1 == fd) {
oss_logerr2 (errno, typ, "Failed to open `%s'\n", dspname);
return -1;
@@ -259,11 +310,36 @@ static int oss_open (int in, struct oss_params *req,
goto err;
}
- mmmmssss = (req->nfrags << 16) | lsbindex (req->fragsize);
- if (ioctl (fd, SNDCTL_DSP_SETFRAGMENT, &mmmmssss)) {
- oss_logerr2 (errno, typ, "Failed to set buffer length (%d, %d)\n",
- req->nfrags, req->fragsize);
- goto err;
+#ifdef USE_DSP_POLICY
+ if (conf.policy >= 0) {
+ int version;
+
+ if (!oss_get_version (fd, &version, typ)) {
+ if (conf.debug) {
+ dolog ("OSS version = %#x\n", version);
+ }
+
+ if (version >= 0x040000) {
+ int policy = conf.policy;
+ if (ioctl (fd, SNDCTL_DSP_POLICY, &policy)) {
+ oss_logerr2 (errno, typ,
+ "Failed to set timing policy to %d\n",
+ conf.policy);
+ goto err;
+ }
+ setfragment = 0;
+ }
+ }
+ }
+#endif
+
+ if (setfragment) {
+ int mmmmssss = (req->nfrags << 16) | ctz32 (req->fragsize);
+ if (ioctl (fd, SNDCTL_DSP_SETFRAGMENT, &mmmmssss)) {
+ oss_logerr2 (errno, typ, "Failed to set buffer length (%d, %d)\n",
+ req->nfrags, req->fragsize);
+ goto err;
+ }
}
if (ioctl (fd, in ? SNDCTL_DSP_GETISPACE : SNDCTL_DSP_GETOSPACE, &abinfo)) {
@@ -305,26 +381,58 @@ static int oss_open (int in, struct oss_params *req,
return -1;
}
-static int oss_run_out (HWVoiceOut *hw)
+static void oss_write_pending (OSSVoiceOut *oss)
+{
+ HWVoiceOut *hw = &oss->hw;
+
+ if (oss->mmapped) {
+ return;
+ }
+
+ while (oss->pending) {
+ int samples_written;
+ ssize_t bytes_written;
+ int samples_till_end = hw->samples - oss->wpos;
+ int samples_to_write = audio_MIN (oss->pending, samples_till_end);
+ int bytes_to_write = samples_to_write << hw->info.shift;
+ void *pcm = advance (oss->pcm_buf, oss->wpos << hw->info.shift);
+
+ bytes_written = write (oss->fd, pcm, bytes_to_write);
+ if (bytes_written < 0) {
+ if (errno != EAGAIN) {
+ oss_logerr (errno, "failed to write %d bytes\n",
+ bytes_to_write);
+ }
+ break;
+ }
+
+ if (bytes_written & hw->info.align) {
+ dolog ("misaligned write asked for %d, but got %zd\n",
+ bytes_to_write, bytes_written);
+ return;
+ }
+
+ samples_written = bytes_written >> hw->info.shift;
+ oss->pending -= samples_written;
+ oss->wpos = (oss->wpos + samples_written) % hw->samples;
+ if (bytes_written - bytes_to_write) {
+ break;
+ }
+ }
+}
+
+static int oss_run_out (HWVoiceOut *hw, int live)
{
OSSVoiceOut *oss = (OSSVoiceOut *) hw;
- int err, rpos, live, decr;
- int samples;
- uint8_t *dst;
- struct st_sample *src;
+ int err, decr;
struct audio_buf_info abinfo;
struct count_info cntinfo;
int bufsize;
- live = audio_pcm_hw_get_live_out (hw);
- if (!live) {
- return 0;
- }
-
bufsize = hw->samples << hw->info.shift;
if (oss->mmapped) {
- int bytes;
+ int bytes, pos;
err = ioctl (oss->fd, SNDCTL_DSP_GETOPTR, &cntinfo);
if (err < 0) {
@@ -332,20 +440,8 @@ static int oss_run_out (HWVoiceOut *hw)
return 0;
}
- if (cntinfo.ptr == oss->old_optr) {
- if (abs (hw->samples - live) < 64) {
- dolog ("warning: Overrun\n");
- }
- return 0;
- }
-
- if (cntinfo.ptr > oss->old_optr) {
- bytes = cntinfo.ptr - oss->old_optr;
- }
- else {
- bytes = bufsize + cntinfo.ptr - oss->old_optr;
- }
-
+ pos = hw->rpos << hw->info.shift;
+ bytes = audio_ring_dist (cntinfo.ptr, pos, bufsize);
decr = audio_MIN (bytes >> hw->info.shift, live);
}
else {
@@ -358,7 +454,7 @@ static int oss_run_out (HWVoiceOut *hw)
if (abinfo.bytes > bufsize) {
if (conf.debug) {
dolog ("warning: Invalid available size, size=%d bufsize=%d\n"
- "please report your OS/audio hw to malc@pulsesoft.com\n",
+ "please report your OS/audio hw to av1474@comtv.ru\n",
abinfo.bytes, bufsize);
}
abinfo.bytes = bufsize;
@@ -378,53 +474,10 @@ static int oss_run_out (HWVoiceOut *hw)
}
}
- samples = decr;
- rpos = hw->rpos;
- while (samples) {
- int left_till_end_samples = hw->samples - rpos;
- int convert_samples = audio_MIN (samples, left_till_end_samples);
-
- src = hw->mix_buf + rpos;
- dst = advance (oss->pcm_buf, rpos << hw->info.shift);
-
- hw->clip (dst, src, convert_samples);
- if (!oss->mmapped) {
- int written;
+ decr = audio_pcm_hw_clip_out (hw, oss->pcm_buf, decr, oss->pending);
+ oss->pending += decr;
+ oss_write_pending (oss);
- written = write (oss->fd, dst, convert_samples << hw->info.shift);
- /* XXX: follow errno recommendations ? */
- if (written == -1) {
- oss_logerr (
- errno,
- "Failed to write %d bytes of audio data from %p\n",
- convert_samples << hw->info.shift,
- dst
- );
- continue;
- }
-
- if (written != convert_samples << 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);
- }
- decr -= wsamples;
- rpos = (rpos + wsamples) % hw->samples;
- break;
- }
- }
-
- rpos = (rpos + convert_samples) % hw->samples;
- samples -= convert_samples;
- }
- if (oss->mmapped) {
- oss->old_optr = cntinfo.ptr;
- }
-
- hw->rpos = rpos;
return decr;
}
@@ -498,7 +551,7 @@ static int oss_init_out (HWVoiceOut *hw, struct audsettings *as)
oss->mmapped = 0;
if (conf.try_mmap) {
oss->pcm_buf = mmap (
- 0,
+ NULL,
hw->samples << hw->info.shift,
PROT_READ | PROT_WRITE,
MAP_SHARED,
@@ -508,7 +561,8 @@ static int oss_init_out (HWVoiceOut *hw, struct audsettings *as)
if (oss->pcm_buf == MAP_FAILED) {
oss_logerr (errno, "Failed to map %d bytes of DAC\n",
hw->samples << hw->info.shift);
- } else {
+ }
+ else {
int err;
int trig = 0;
if (ioctl (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
@@ -563,25 +617,48 @@ static int oss_ctl_out (HWVoiceOut *hw, int cmd, ...)
int trig;
OSSVoiceOut *oss = (OSSVoiceOut *) hw;
- if (!oss->mmapped) {
- return 0;
- }
-
switch (cmd) {
case VOICE_ENABLE:
- ldebug ("enabling voice\n");
- audio_pcm_info_clear_buf (&hw->info, oss->pcm_buf, hw->samples);
- trig = PCM_ENABLE_OUTPUT;
- if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
- oss_logerr (
- errno,
- "SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
- );
- return -1;
+ {
+ va_list ap;
+ int poll_mode;
+
+ va_start (ap, cmd);
+ poll_mode = va_arg (ap, int);
+ va_end (ap);
+
+ ldebug ("enabling voice\n");
+ if (poll_mode && oss_poll_out (hw)) {
+ poll_mode = 0;
+ }
+ hw->poll_mode = poll_mode;
+
+ if (!oss->mmapped) {
+ return 0;
+ }
+
+ audio_pcm_info_clear_buf (&hw->info, oss->pcm_buf, hw->samples);
+ trig = PCM_ENABLE_OUTPUT;
+ if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
+ oss_logerr (
+ errno,
+ "SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
+ );
+ return -1;
+ }
}
break;
case VOICE_DISABLE:
+ if (hw->poll_mode) {
+ qemu_set_fd_handler (oss->fd, NULL, NULL, NULL);
+ hw->poll_mode = 0;
+ }
+
+ if (!oss->mmapped) {
+ return 0;
+ }
+
ldebug ("disabling voice\n");
trig = 0;
if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
@@ -671,8 +748,8 @@ static int oss_run_in (HWVoiceIn *hw)
int add;
int len;
} bufs[2] = {
- { hw->wpos, 0 },
- { 0, 0 }
+ { .add = hw->wpos, .len = 0 },
+ { .add = 0, .len = 0 }
};
if (!dead) {
@@ -687,7 +764,6 @@ static int oss_run_in (HWVoiceIn *hw)
bufs[0].len = dead << hwshift;
}
-
for (i = 0; i < 2; ++i) {
ssize_t nread;
@@ -737,8 +813,32 @@ static int oss_read (SWVoiceIn *sw, void *buf, int size)
static int oss_ctl_in (HWVoiceIn *hw, int cmd, ...)
{
- (void) hw;
- (void) cmd;
+ OSSVoiceIn *oss = (OSSVoiceIn *) hw;
+
+ switch (cmd) {
+ case VOICE_ENABLE:
+ {
+ va_list ap;
+ int poll_mode;
+
+ va_start (ap, cmd);
+ poll_mode = va_arg (ap, int);
+ va_end (ap);
+
+ if (poll_mode && oss_poll_in (hw)) {
+ poll_mode = 0;
+ }
+ hw->poll_mode = poll_mode;
+ }
+ break;
+
+ case VOICE_DISABLE:
+ if (hw->poll_mode) {
+ hw->poll_mode = 0;
+ qemu_set_fd_handler (oss->fd, NULL, NULL, NULL);
+ }
+ break;
+ }
return 0;
}
@@ -753,45 +853,83 @@ static void oss_audio_fini (void *opaque)
}
static struct audio_option oss_options[] = {
- {"FRAGSIZE", AUD_OPT_INT, &conf.fragsize,
- "Fragment size in bytes", NULL, 0},
- {"NFRAGS", AUD_OPT_INT, &conf.nfrags,
- "Number of fragments", NULL, 0},
- {"MMAP", AUD_OPT_BOOL, &conf.try_mmap,
- "Try using memory mapped access", NULL, 0},
- {"DAC_DEV", AUD_OPT_STR, &conf.devpath_out,
- "Path to DAC device", NULL, 0},
- {"ADC_DEV", AUD_OPT_STR, &conf.devpath_in,
- "Path to ADC device", NULL, 0},
- {"DEBUG", AUD_OPT_BOOL, &conf.debug,
- "Turn on some debugging messages", NULL, 0},
- {NULL, 0, NULL, NULL, NULL, 0}
+ {
+ .name = "FRAGSIZE",
+ .tag = AUD_OPT_INT,
+ .valp = &conf.fragsize,
+ .descr = "Fragment size in bytes"
+ },
+ {
+ .name = "NFRAGS",
+ .tag = AUD_OPT_INT,
+ .valp = &conf.nfrags,
+ .descr = "Number of fragments"
+ },
+ {
+ .name = "MMAP",
+ .tag = AUD_OPT_BOOL,
+ .valp = &conf.try_mmap,
+ .descr = "Try using memory mapped access"
+ },
+ {
+ .name = "DAC_DEV",
+ .tag = AUD_OPT_STR,
+ .valp = &conf.devpath_out,
+ .descr = "Path to DAC device"
+ },
+ {
+ .name = "ADC_DEV",
+ .tag = AUD_OPT_STR,
+ .valp = &conf.devpath_in,
+ .descr = "Path to ADC device"
+ },
+ {
+ .name = "EXCLUSIVE",
+ .tag = AUD_OPT_BOOL,
+ .valp = &conf.exclusive,
+ .descr = "Open device in exclusive mode (vmix wont work)"
+ },
+#ifdef USE_DSP_POLICY
+ {
+ .name = "POLICY",
+ .tag = AUD_OPT_INT,
+ .valp = &conf.policy,
+ .descr = "Set the timing policy of the device, -1 to use fragment mode",
+ },
+#endif
+ {
+ .name = "DEBUG",
+ .tag = AUD_OPT_BOOL,
+ .valp = &conf.debug,
+ .descr = "Turn on some debugging messages"
+ },
+ { /* End of list */ }
};
static struct audio_pcm_ops oss_pcm_ops = {
- oss_init_out,
- oss_fini_out,
- oss_run_out,
- oss_write,
- oss_ctl_out,
-
- oss_init_in,
- oss_fini_in,
- oss_run_in,
- oss_read,
- oss_ctl_in
+ .init_out = oss_init_out,
+ .fini_out = oss_fini_out,
+ .run_out = oss_run_out,
+ .write = oss_write,
+ .ctl_out = oss_ctl_out,
+
+ .init_in = oss_init_in,
+ .fini_in = oss_fini_in,
+ .run_in = oss_run_in,
+ .read = oss_read,
+ .ctl_in = oss_ctl_in
};
struct audio_driver oss_audio_driver = {
- INIT_FIELD (name = ) "oss",
- INIT_FIELD (descr = ) "OSS audio (www.opensound.com)",
- INIT_FIELD (options = ) oss_options,
- INIT_FIELD (init = ) oss_audio_init,
- INIT_FIELD (fini = ) oss_audio_fini,
- INIT_FIELD (pcm_ops = ) &oss_pcm_ops,
- INIT_FIELD (can_be_default = ) 1,
- INIT_FIELD (max_voices_out = ) INT_MAX,
- INIT_FIELD (max_voices_in = ) INT_MAX,
- INIT_FIELD (voice_size_out = ) sizeof (OSSVoiceOut),
- INIT_FIELD (voice_size_in = ) sizeof (OSSVoiceIn)
+ .name = "oss",
+ .descr = "OSS http://www.opensound.com",
+ .options = oss_options,
+ .init = oss_audio_init,
+ .fini = oss_audio_fini,
+ .pcm_ops = &oss_pcm_ops,
+ .can_be_default = 1,
+ .max_voices_out = INT_MAX,
+ .max_voices_in = INT_MAX,
+ .voice_size_out = sizeof (OSSVoiceOut),
+ .voice_size_in = sizeof (OSSVoiceIn)
};
diff --git a/audio/paaudio.c b/audio/paaudio.c
index ed2c58c..c78353b 100644
--- a/audio/paaudio.c
+++ b/audio/paaudio.c
@@ -151,17 +151,11 @@ static void *qpa_thread_out (void *arg)
return NULL;
}
-static int qpa_run_out (HWVoiceOut *hw)
+static int qpa_run_out (HWVoiceOut *hw, int live)
{
int decr;
- int live;
PAVoiceOut *pa = (PAVoiceOut *) hw;
- live = audio_pcm_hw_get_live_out (hw);
- if (!live) {
- return 0;
- }
-
if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
return 0;
}
diff --git a/audio/wavaudio.c b/audio/wavaudio.c
index a82997e..62ba42d 100644
--- a/audio/wavaudio.c
+++ b/audio/wavaudio.c
@@ -55,10 +55,10 @@ static struct {
"qemu.wav"
};
-static int wav_out_run (HWVoiceOut *hw)
+static int wav_out_run (HWVoiceOut *hw, int live)
{
WAVVoiceOut *wav = (WAVVoiceOut *) hw;
- int rpos, live, decr, samples;
+ int rpos, decr, samples;
uint8_t *dst;
struct st_sample *src;
int64_t now = qemu_get_clock (vm_clock);
@@ -73,11 +73,6 @@ static int wav_out_run (HWVoiceOut *hw)
samples = bytes >> hw->info.shift;
}
- live = audio_pcm_hw_get_live_out (hw);
- if (!live) {
- return 0;
- }
-
wav->old_ticks = now;
decr = audio_MIN (live, samples);
samples = decr;
diff --git a/audio/winaudio.c b/audio/winaudio.c
index ca6c487..75f6af2 100644
--- a/audio/winaudio.c
+++ b/audio/winaudio.c
@@ -251,12 +251,11 @@ winaudio_out_init (HWVoiceOut *hw, struct audsettings *as)
static int
-winaudio_out_run (HWVoiceOut *hw)
+winaudio_out_run (HWVoiceOut *hw, int live)
{
WinAudioOut* s = (WinAudioOut*) hw;
int played = 0;
int has_buffer;
- int live = audio_pcm_hw_get_live_out (hw);
if (!live) {
return 0;
diff --git a/cpu-common.h b/cpu-common.h
index d48ba5b..a422689 100644
--- a/cpu-common.h
+++ b/cpu-common.h
@@ -47,8 +47,8 @@ void *qemu_get_ram_ptr(ram_addr_t addr);
/* This should not be used by devices. */
ram_addr_t qemu_ram_addr_from_host(void *ptr);
-int cpu_register_io_memory(CPUReadMemoryFunc **mem_read,
- CPUWriteMemoryFunc **mem_write,
+int cpu_register_io_memory(CPUReadMemoryFunc * const *mem_read,
+ CPUWriteMemoryFunc * const *mem_write,
void *opaque);
void cpu_unregister_io_memory(int table_address);
diff --git a/exec.c b/exec.c
index 8786791..003a4cc 100644
--- a/exec.c
+++ b/exec.c
@@ -226,21 +226,21 @@ static void map_exec(void *addr, long size)
DWORD old_protect;
VirtualProtect(addr, size,
PAGE_EXECUTE_READWRITE, &old_protect);
-
+
}
#else
static void map_exec(void *addr, long size)
{
unsigned long start, end, page_size;
-
+
page_size = getpagesize();
start = (unsigned long)addr;
start &= ~(page_size - 1);
-
+
end = (unsigned long)addr + size;
end += page_size - 1;
end &= ~(page_size - 1);
-
+
mprotect((void *)start, end - start,
PROT_READ | PROT_WRITE | PROT_EXEC);
}
@@ -440,7 +440,7 @@ static void code_gen_alloc(unsigned long tb_size)
code_gen_buffer_size = MIN_CODE_GEN_BUFFER_SIZE;
/* The code gen buffer location may have constraints depending on
the host cpu and OS */
-#if defined(__linux__)
+#if defined(__linux__)
{
int flags;
void *start = NULL;
@@ -463,6 +463,13 @@ static void code_gen_alloc(unsigned long tb_size)
start = (void *) 0x01000000UL;
if (code_gen_buffer_size > 16 * 1024 * 1024)
code_gen_buffer_size = 16 * 1024 * 1024;
+#elif defined(__s390x__)
+ /* Map the buffer so that we can use direct calls and branches. */
+ /* We have a +- 4GB range on the branches; leave some slop. */
+ if (code_gen_buffer_size > (3ul * 1024 * 1024 * 1024)) {
+ code_gen_buffer_size = 3ul * 1024 * 1024 * 1024;
+ }
+ start = (void *)0x90000000UL;
#endif
code_gen_buffer = mmap(start, code_gen_buffer_size,
PROT_WRITE | PROT_READ | PROT_EXEC,
@@ -487,7 +494,7 @@ static void code_gen_alloc(unsigned long tb_size)
code_gen_buffer_size = (800 * 1024 * 1024);
#endif
code_gen_buffer = mmap(addr, code_gen_buffer_size,
- PROT_WRITE | PROT_READ | PROT_EXEC,
+ PROT_WRITE | PROT_READ | PROT_EXEC,
flags, -1, 0);
if (code_gen_buffer == MAP_FAILED) {
fprintf(stderr, "Could not allocate dynamic translator buffer\n");
@@ -1712,6 +1719,14 @@ void cpu_abort(CPUState *env, const char *fmt, ...)
}
va_end(ap2);
va_end(ap);
+#if defined(CONFIG_USER_ONLY)
+ {
+ struct sigaction act;
+ sigfillset(&act.sa_mask);
+ act.sa_handler = SIG_DFL;
+ sigaction(SIGABRT, &act, NULL);
+ }
+#endif
abort();
}
@@ -1758,12 +1773,12 @@ static inline void tlb_flush_jmp_cache(CPUState *env, target_ulong addr)
/* Discard jump cache entries for any tb which might potentially
overlap the flushed page. */
i = tb_jmp_cache_hash_page(addr - TARGET_PAGE_SIZE);
- memset (&env->tb_jmp_cache[i], 0,
- TB_JMP_PAGE_SIZE * sizeof(TranslationBlock *));
+ memset (&env->tb_jmp_cache[i], 0,
+ TB_JMP_PAGE_SIZE * sizeof(TranslationBlock *));
i = tb_jmp_cache_hash_page(addr);
- memset (&env->tb_jmp_cache[i], 0,
- TB_JMP_PAGE_SIZE * sizeof(TranslationBlock *));
+ memset (&env->tb_jmp_cache[i], 0,
+ TB_JMP_PAGE_SIZE * sizeof(TranslationBlock *));
}
/* NOTE: if flush_global is true, also flush global entries (not
@@ -2198,9 +2213,9 @@ int page_get_flags(target_ulong address)
return p->flags;
}
-/* modify the flags of a page and invalidate the code if
- necessary. The flag PAGE_WRITE_ORG is positioned automatically
- depending on PAGE_WRITE */
+/* Modify the flags of a page and invalidate the code if necessary.
+ The flag PAGE_WRITE_ORG is positioned automatically depending
+ on PAGE_WRITE. The mmap_lock should already be held. */
void page_set_flags(target_ulong start, target_ulong end, int flags)
{
PageDesc *p;
@@ -2626,13 +2641,13 @@ static void unassigned_mem_writel(void *opaque, target_phys_addr_t addr, uint32_
#endif
}
-static CPUReadMemoryFunc *unassigned_mem_read[3] = {
+static CPUReadMemoryFunc * const unassigned_mem_read[3] = {
unassigned_mem_readb,
unassigned_mem_readw,
unassigned_mem_readl,
};
-static CPUWriteMemoryFunc *unassigned_mem_write[3] = {
+static CPUWriteMemoryFunc * const unassigned_mem_write[3] = {
unassigned_mem_writeb,
unassigned_mem_writew,
unassigned_mem_writel,
@@ -2698,13 +2713,13 @@ static void notdirty_mem_writel(void *opaque, target_phys_addr_t ram_addr,
tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
}
-static CPUReadMemoryFunc *error_mem_read[3] = {
+static CPUReadMemoryFunc * const error_mem_read[3] = {
NULL, /* never used */
NULL, /* never used */
NULL, /* never used */
};
-static CPUWriteMemoryFunc *notdirty_mem_write[3] = {
+static CPUWriteMemoryFunc * const notdirty_mem_write[3] = {
notdirty_mem_writeb,
notdirty_mem_writew,
notdirty_mem_writel,
@@ -2797,13 +2812,13 @@ static void watch_mem_writel(void *opaque, target_phys_addr_t addr,
stl_phys(addr, val);
}
-static CPUReadMemoryFunc *watch_mem_read[3] = {
+static CPUReadMemoryFunc * const watch_mem_read[3] = {
watch_mem_readb,
watch_mem_readw,
watch_mem_readl,
};
-static CPUWriteMemoryFunc *watch_mem_write[3] = {
+static CPUWriteMemoryFunc * const watch_mem_write[3] = {
watch_mem_writeb,
watch_mem_writew,
watch_mem_writel,
@@ -2895,13 +2910,13 @@ static void subpage_writel (void *opaque,
subpage_writelen(opaque, addr, value, 2);
}
-static CPUReadMemoryFunc *subpage_read[] = {
+static CPUReadMemoryFunc * const subpage_read[] = {
&subpage_readb,
&subpage_readw,
&subpage_readl,
};
-static CPUWriteMemoryFunc *subpage_write[] = {
+static CPUWriteMemoryFunc * const subpage_write[] = {
&subpage_writeb,
&subpage_writew,
&subpage_writel,
@@ -2982,8 +2997,8 @@ static int get_free_io_mem_idx(void)
value can be used with cpu_register_physical_memory(). (-1) is
returned if error. */
static int cpu_register_io_memory_fixed(int io_index,
- CPUReadMemoryFunc **mem_read,
- CPUWriteMemoryFunc **mem_write,
+ CPUReadMemoryFunc * const *mem_read,
+ CPUWriteMemoryFunc * const *mem_write,
void *opaque)
{
int i, subwidth = 0;
@@ -3008,8 +3023,8 @@ static int cpu_register_io_memory_fixed(int io_index,
return (io_index << IO_MEM_SHIFT) | subwidth;
}
-int cpu_register_io_memory(CPUReadMemoryFunc **mem_read,
- CPUWriteMemoryFunc **mem_write,
+int cpu_register_io_memory(CPUReadMemoryFunc * const *mem_read,
+ CPUWriteMemoryFunc * const *mem_write,
void *opaque)
{
return cpu_register_io_memory_fixed(0, mem_read, mem_write, opaque);
@@ -3625,7 +3640,7 @@ void cpu_io_recompile(CPUState *env, void *retaddr)
tb = tb_find_pc((unsigned long)retaddr);
if (!tb) {
- cpu_abort(env, "cpu_io_recompile: could not find TB for pc=%p",
+ cpu_abort(env, "cpu_io_recompile: could not find TB for pc=%p",
retaddr);
}
n = env->icount_decr.u16.low + tb->icount;
@@ -3673,6 +3688,8 @@ void cpu_io_recompile(CPUState *env, void *retaddr)
cpu_resume_from_signal(env, NULL);
}
+#if !defined(CONFIG_USER_ONLY)
+
void dump_exec_info(FILE *f,
int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
{
@@ -3703,7 +3720,7 @@ void dump_exec_info(FILE *f,
cpu_fprintf(f, "Translation buffer state:\n");
cpu_fprintf(f, "gen code size %ld/%ld\n",
code_gen_ptr - code_gen_buffer, code_gen_buffer_max_size);
- cpu_fprintf(f, "TB count %d/%d\n",
+ cpu_fprintf(f, "TB count %d/%d\n",
nb_tbs, code_gen_max_blocks);
cpu_fprintf(f, "TB avg target size %d max=%d bytes\n",
nb_tbs ? target_code_size / nb_tbs : 0,
@@ -3726,8 +3743,6 @@ void dump_exec_info(FILE *f,
tcg_dump_info(f, cpu_fprintf);
}
-#if !defined(CONFIG_USER_ONLY)
-
#define MMUSUFFIX _cmmu
#define GETPC() NULL
#define env cpu_single_env
diff --git a/hw/goldfish_audio.c b/hw/goldfish_audio.c
index 37e4c09..434522c 100644
--- a/hw/goldfish_audio.c
+++ b/hw/goldfish_audio.c
@@ -582,7 +582,7 @@ void goldfish_audio_init(uint32_t base, int id, const char* input_source)
if (android_hw->hw_audioOutput) {
s->voice = AUD_open_out (
&s->card,
- s->voice,
+ NULL,
"goldfish_audio",
s,
goldfish_audio_callback,
diff --git a/hxtool b/hxtool
index 0fdbc64..7ca83ed 100755
--- a/hxtool
+++ b/hxtool
@@ -7,7 +7,7 @@ hxtoh()
case $str in
HXCOMM*)
;;
- STEXI*|ETEXI*) flag=$(($flag^1))
+ STEXI*|ETEXI*|SQMP*|EQMP*) flag=$(($flag^1))
;;
*)
test $flag -eq 1 && printf "%s\n" "$str"
@@ -19,11 +19,30 @@ hxtoh()
hxtotexi()
{
flag=0
+ line=1
while read -r str; do
case "$str" in
HXCOMM*)
;;
- STEXI*|ETEXI*) flag=$(($flag^1))
+ STEXI*)
+ if test $flag -eq 1 ; then
+ echo "line $line: syntax error: expected ETEXI, found $str" >&2
+ exit 1
+ fi
+ flag=1
+ ;;
+ ETEXI*)
+ if test $flag -ne 1 ; then
+ echo "line $line: syntax error: expected STEXI, found $str" >&2
+ exit 1
+ fi
+ flag=0
+ ;;
+ SQMP*|EQMP*)
+ if test $flag -eq 1 ; then
+ echo "line $line: syntax error: expected ETEXI, found $str" >&2
+ exit 1
+ fi
;;
DEFHEADING*)
echo "$(expr "$str" : "DEFHEADING(\(.*\))")"
@@ -32,12 +51,51 @@ hxtotexi()
test $flag -eq 1 && echo "$str"
;;
esac
+ line=$((line+1))
+ done
+}
+
+hxtoqmp()
+{
+ IFS=
+ flag=0
+ line=1
+ while read -r str; do
+ case "$str" in
+ HXCOMM*)
+ ;;
+ SQMP*)
+ if test $flag -eq 1 ; then
+ echo "line $line: syntax error: expected EQMP, found $str" >&2
+ exit 1
+ fi
+ flag=1
+ ;;
+ EQMP*)
+ if test $flag -ne 1 ; then
+ echo "line $line: syntax error: expected SQMP, found $str" >&2
+ exit 1
+ fi
+ flag=0
+ ;;
+ STEXI*|ETEXI*)
+ if test $flag -eq 1 ; then
+ echo "line $line: syntax error: expected EQMP, found $str" >&2
+ exit 1
+ fi
+ ;;
+ *)
+ test $flag -eq 1 && echo "$str"
+ ;;
+ esac
+ line=$((line+1))
done
}
case "$1" in
"-h") hxtoh ;;
"-t") hxtotexi ;;
+"-q") hxtoqmp ;;
*) exit 1 ;;
esac
diff --git a/json-lexer.c b/json-lexer.c
index 072ae56..534fcf7 100644
--- a/json-lexer.c
+++ b/json-lexer.c
@@ -27,8 +27,12 @@
*
*/
+/* Building with mingw results in an error because ERROR is defined as a
+ * macro in this environment. Undefined it */
+#undef ERROR
+
enum json_lexer_state {
- JSON_ERROR = 0,
+ ERROR = 0,
IN_DQ_UCODE3,
IN_DQ_UCODE2,
IN_DQ_UCODE1,
@@ -150,7 +154,7 @@ static const uint8_t json_lexer[][256] = {
/* Zero */
[IN_ZERO] = {
TERMINAL(JSON_INTEGER),
- ['0' ... '9'] = JSON_ERROR,
+ ['0' ... '9'] = ERROR,
['.'] = IN_MANTISSA,
},
@@ -302,7 +306,7 @@ static int json_lexer_feed_char(JSONLexer *lexer, char ch)
lexer->token = qstring_new();
new_state = IN_START;
break;
- case JSON_ERROR:
+ case ERROR:
return -EINVAL;
default:
break;
diff --git a/monitor.h b/monitor.h
index fc80bcb..c94a3c8 100644
--- a/monitor.h
+++ b/monitor.h
@@ -11,9 +11,6 @@ extern Monitor *cur_mon;
extern Monitor *default_mon;
/* flags for monitor_init */
-#define MONITOR_IS_DEFAULT 0x01
-#define MONITOR_USE_READLINE 0x02
-
#define MONITOR_IS_DEFAULT 0x01
#define MONITOR_USE_READLINE 0x02
#define MONITOR_USE_CONTROL 0x04
diff --git a/qemu-io.c b/qemu-io.c
index bd3bd16..2dbe20f 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -1427,8 +1427,11 @@ alloc_f(int argc, char **argv)
cvtstr(offset, s1, sizeof(s1));
- printf("%d/%d sectors allocated at offset %s\n",
- sum_alloc, nb_sectors, s1);
+ if (nb_sectors == 1)
+ printf("sector allocated at offset %s\n", s1);
+ else
+ printf("%d/%d sectors allocated at offset %s\n",
+ sum_alloc, nb_sectors, s1);
return 0;
}
diff --git a/qemu-options.hx b/qemu-options.hx
index aee7b6b..db3dfbb 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1598,7 +1598,7 @@ DEF("nand", HAS_ARG, QEMU_OPTION_nand, \
#endif /* CONFIG_TRACE */
-#if 1 /* ANDROID */
+#ifdef CONFIG_ANDROID
DEF("savevm-on-exit", HAS_ARG, QEMU_OPTION_savevm_on_exit, \
"savevm-on-exit [tag|id]\n" \
@@ -1653,12 +1653,6 @@ DEF("gps", HAS_ARG, QEMU_OPTION_gps, \
DEF("audio", HAS_ARG, QEMU_OPTION_audio, \
"-audio <backend> use specific audio backend\n")
-DEF("audio-in", HAS_ARG, QEMU_OPTION_audio_in, \
- "-audio-in <backend> use specific audio input backend\n")
-
-DEF("audio-out", HAS_ARG, QEMU_OPTION_audio_out, \
- "-audio-out <backend> use specific audio output backend\n")
-
DEF("cpu-delay", HAS_ARG, QEMU_OPTION_cpu_delay, \
"-cpu-delay <cpudelay> throttle CPU emulation\n")
@@ -1694,4 +1688,7 @@ DEF("ui-port", HAS_ARG, QEMU_OPTION_ui_port, \
DEF("ui-settings", HAS_ARG, QEMU_OPTION_ui_settings, \
"-ui-settings <string> opaque string containing persitent UI settings\n")
-#endif
+DEF("audio-test-out", 0, QEMU_OPTION_audio_test_out, \
+ "-audio-test-out Test audio output\n")
+
+#endif /* ANDROID */
diff --git a/qemu-sockets-android.c b/qemu-sockets-android.c
index dc64775..b07129b 100644
--- a/qemu-sockets-android.c
+++ b/qemu-sockets-android.c
@@ -26,6 +26,10 @@
# define AI_ADDRCONFIG 0
#endif
+#ifndef INET6_ADDRSTRLEN
+# define INET6_ADDRSTRLEN 46
+#endif
+
static int sockets_debug = 0;
static const int on=1, off=0;
@@ -52,6 +56,11 @@ static QemuOptsList dummy_opts = {
},{
.name = "ipv6",
.type = QEMU_OPT_BOOL,
+#ifdef CONFIG_ANDROID
+ },{
+ .name = "socket",
+ .type = QEMU_OPT_NUMBER,
+#endif
},
{ /* end if list */ }
},
@@ -79,6 +88,13 @@ int inet_listen_opts(QemuOpts *opts, int port_offset)
char uport[33];
int slisten,to,try_next,nn;
+#ifdef CONFIG_ANDROID
+ const char* socket_fd = qemu_opt_get(opts, "socket");
+ if (socket_fd) {
+ return atoi(socket_fd);
+ }
+#endif
+
if ((qemu_opt_get(opts, "host") == NULL) ||
(qemu_opt_get(opts, "port") == NULL)) {
fprintf(stderr, "%s: host and/or port not specified\n", __FUNCTION__);
@@ -177,6 +193,13 @@ int inet_connect_opts(QemuOpts *opts)
const char *port;
int sock, nn;
+#ifdef CONFIG_ANDROID
+ const char* socket_fd = qemu_opt_get(opts, "socket");
+ if (socket_fd) {
+ return atoi(socket_fd);
+ }
+#endif
+
addr = qemu_opt_get(opts, "host");
port = qemu_opt_get(opts, "port");
if (addr == NULL || port == NULL) {
@@ -233,6 +256,115 @@ EXIT:
return sock;
}
+int inet_dgram_opts(QemuOpts *opts)
+{
+ SockAddress** peer_list = NULL;
+ SockAddress** local_list = NULL;
+ SockAddress* e;
+ unsigned flags = 0;
+ const char *addr;
+ const char *port;
+ char uaddr[INET6_ADDRSTRLEN+1];
+ char uport[33];
+ int sock = -1;
+ int nn;
+
+ /* lookup peer addr */
+ addr = qemu_opt_get(opts, "host");
+ port = qemu_opt_get(opts, "port");
+ if (addr == NULL || strlen(addr) == 0) {
+ addr = "localhost";
+ }
+ if (port == NULL || strlen(port) == 0) {
+ fprintf(stderr, "inet_dgram: port not specified\n");
+ return -1;
+ }
+
+ flags = SOCKET_LIST_DGRAM;
+ if (qemu_opt_get_bool(opts, "ipv4", 0)) {
+ flags &= SOCKET_LIST_FORCE_IN6;
+ flags |= SOCKET_LIST_FORCE_INET;
+ }
+ if (qemu_opt_get_bool(opts, "ipv6", 0)) {
+ flags &= SOCKET_LIST_FORCE_INET;
+ flags |= SOCKET_LIST_FORCE_IN6;
+ }
+
+ peer_list = sock_address_list_create(addr, port, flags);
+ if (peer_list == NULL) {
+ fprintf(stderr,"getaddrinfo(%s,%s): %s\n",
+ addr, port, errno_str);
+ return -1;
+ }
+
+ /* lookup local addr */
+ addr = qemu_opt_get(opts, "localaddr");
+ port = qemu_opt_get(opts, "localport");
+ if (addr == NULL || strlen(addr) == 0) {
+ addr = NULL;
+ }
+ if (!port || strlen(port) == 0)
+ port = "0";
+
+ flags = SOCKET_LIST_DGRAM | SOCKET_LIST_PASSIVE;
+ local_list = sock_address_list_create(addr, port, flags);
+ if (local_list == NULL) {
+ fprintf(stderr,"getaddrinfo(%s,%s): %s\n",
+ addr, port, errno_str);
+ goto EXIT;
+ }
+
+ if (sock_address_get_numeric_info(local_list[0],
+ uaddr, INET6_ADDRSTRLEN,
+ uport, 32)) {
+ fprintf(stderr, "%s: getnameinfo: oops\n", __FUNCTION__);
+ goto EXIT;
+ }
+
+ for (nn = 0; peer_list[nn] != NULL; nn++) {
+ SockAddress *local = local_list[0];
+ e = peer_list[nn];
+ sock = socket_create(sock_address_get_family(e), SOCKET_DGRAM);
+ if (sock < 0) {
+ fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__,
+ sock_address_strfamily(e), errno_str);
+ continue;
+ }
+ socket_set_xreuseaddr(sock);
+
+ /* bind socket */
+ if (socket_bind(sock, local) < 0) {
+ fprintf(stderr,"%s: bind(%s,%s,%s): OK\n", __FUNCTION__,
+ sock_address_strfamily(local), addr, port);
+ socket_close(sock);
+ continue;
+ }
+
+ /* connect to peer */
+ if (socket_connect(sock,e) < 0) {
+ if (sockets_debug)
+ fprintf(stderr, "%s: connect(%s,%s,%s,%s): %s\n", __FUNCTION__,
+ sock_address_strfamily(e),
+ sock_address_to_string(e), addr, port, strerror(errno));
+ socket_close(sock);
+ continue;
+ }
+ if (sockets_debug)
+ fprintf(stderr, "%s: connect(%s,%s,%s,%s): OK\n", __FUNCTION__,
+ sock_address_strfamily(e),
+ sock_address_to_string(e), addr, port);
+
+ goto EXIT;
+ }
+ sock = -1;
+EXIT:
+ if (local_list)
+ sock_address_list_free(local_list);
+ if (peer_list)
+ sock_address_list_free(peer_list);
+ return sock;
+}
+
/* compatibility wrapper */
static int inet_parse(QemuOpts *opts, const char *str)
{
@@ -286,6 +418,25 @@ static int inet_parse(QemuOpts *opts, const char *str)
qemu_opt_set(opts, "ipv4", "on");
if (strstr(optstr, ",ipv6"))
qemu_opt_set(opts, "ipv6", "on");
+#ifdef CONFIG_ANDROID
+ h = strstr(optstr, ",socket=");
+ if (h) {
+ int socket_fd;
+ char str_fd[12];
+ if (1 != sscanf(h+7,"%d",&socket_fd)) {
+ fprintf(stderr,"%s: socket fd parse error (%s)\n",
+ __FUNCTION__, h+7);
+ return -1;
+ }
+ if (socket_fd < 0 || socket_fd >= INT_MAX) {
+ fprintf(stderr,"%s: socket fd range error (%d)\n",
+ __FUNCTION__, socket_fd);
+ return -1;
+ }
+ snprintf(str_fd, sizeof str_fd, "%d", socket_fd);
+ qemu_opt_set(opts, "socket", str_fd);
+ }
+#endif
return 0;
}
diff --git a/qemu-sockets.c b/qemu-sockets.c
index c526324..c4c0f65 100644
--- a/qemu-sockets.c
+++ b/qemu-sockets.c
@@ -52,6 +52,11 @@ static QemuOptsList dummy_opts = {
},{
.name = "ipv6",
.type = QEMU_OPT_BOOL,
+#ifdef CONFIG_ANDROID
+ },{
+ .name = "socket",
+ .type = QEMU_OPT_NUMBER,
+#endif
},
{ /* end if list */ }
},
@@ -130,6 +135,13 @@ int inet_listen_opts(QemuOpts *opts, int port_offset)
ai.ai_family = PF_UNSPEC;
ai.ai_socktype = SOCK_STREAM;
+#ifdef CONFIG_ANDROID
+ const char* socket_fd = qemu_opt_get(opts, "socket");
+ if (socket_fd) {
+ return atoi(socket_fd);
+ }
+#endif
+
if ((qemu_opt_get(opts, "host") == NULL) ||
(qemu_opt_get(opts, "port") == NULL)) {
fprintf(stderr, "%s: host and/or port not specified\n", __FUNCTION__);
@@ -226,6 +238,13 @@ int inet_connect_opts(QemuOpts *opts)
char uport[33];
int sock,rc;
+#ifdef CONFIG_ANDROID
+ const char* socket_fd = qemu_opt_get(opts, "socket");
+ if (socket_fd) {
+ return atoi(socket_fd);
+ }
+#endif
+
memset(&ai,0, sizeof(ai));
ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG;
ai.ai_family = PF_UNSPEC;
@@ -454,6 +473,25 @@ static int inet_parse(QemuOpts *opts, const char *str)
qemu_opt_set(opts, "ipv4", "on");
if (strstr(optstr, ",ipv6"))
qemu_opt_set(opts, "ipv6", "on");
+#ifdef CONFIG_ANDROID
+ h = strstr(optstr, ",socket=");
+ if (h) {
+ int socket_fd;
+ char str_fd[12];
+ if (1 != sscanf(h+7,"%d",&socket_fd)) {
+ fprintf(stderr,"%s: socket fd parse error (%s)\n",
+ __FUNCTION__, h+7);
+ return -1;
+ }
+ if (socket_fd < 0 || socket_fd >= INT_MAX) {
+ fprintf(stderr,"%s: socket fd range error (%d)\n",
+ __FUNCTION__, socket_fd);
+ return -1;
+ }
+ snprintf(str_fd, sizeof str_fd, "%d", socket_fd);
+ qemu_opt_set(opts, "socket", str_fd);
+ }
+#endif
return 0;
}
diff --git a/sockets.c b/sockets.c
index ef35220..e1f7ad3 100644
--- a/sockets.c
+++ b/sockets.c
@@ -750,6 +750,9 @@ sock_address_list_create( const char* hostname,
else
ai.ai_flags |= AI_CANONNAME;
+ if (flags & SOCKET_LIST_DGRAM)
+ ai.ai_socktype = SOCK_DGRAM;
+
while (1) {
struct addrinfo hints = ai;
diff --git a/sockets.h b/sockets.h
index 785a37e..6ce3041 100644
--- a/sockets.h
+++ b/sockets.h
@@ -258,7 +258,8 @@ int sock_address_get_numeric_info( SockAddress* a,
enum {
SOCKET_LIST_PASSIVE = (1 << 0),
SOCKET_LIST_FORCE_INET = (1 << 1),
- SOCKET_LIST_FORCE_IN6 = (1 << 2)
+ SOCKET_LIST_FORCE_IN6 = (1 << 2),
+ SOCKET_LIST_DGRAM = (1 << 3),
};
/* resolve a host and service/port name into a list of SockAddress objects.
diff --git a/vl-android.c b/vl-android.c
index 1b79404..dd7a255 100644
--- a/vl-android.c
+++ b/vl-android.c
@@ -191,6 +191,7 @@
#include "android/hw-lcd.h"
#include "android/boot-properties.h"
#include "android/core-init-utils.h"
+#include "android/audio-test.h"
#ifdef CONFIG_STANDALONE_CORE
/* Verbose value used by the standalone emulator core (without UI) */
@@ -350,12 +351,6 @@ char* android_op_gps = NULL;
/* -audio option value. */
char* android_op_audio = NULL;
-/* -audio-in option value. */
-char* android_op_audio_in = NULL;
-
-/* -audio-out option value. */
-char* android_op_audio_out = NULL;
-
/* -cpu-delay option value. */
char* android_op_cpu_delay = NULL;
@@ -2162,110 +2157,6 @@ void qemu_service_io(void)
}
/***********************************************************/
-/* bottom halves (can be seen as timers which expire ASAP) */
-
-struct QEMUBH {
- QEMUBHFunc *cb;
- void *opaque;
- int scheduled;
- int idle;
- int deleted;
- QEMUBH *next;
-};
-
-static QEMUBH *first_bh = NULL;
-
-QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque)
-{
- QEMUBH *bh;
- bh = qemu_mallocz(sizeof(QEMUBH));
- bh->cb = cb;
- bh->opaque = opaque;
- bh->next = first_bh;
- first_bh = bh;
- return bh;
-}
-
-int qemu_bh_poll(void)
-{
- QEMUBH *bh, **bhp;
- int ret;
-
- ret = 0;
- for (bh = first_bh; bh; bh = bh->next) {
- if (!bh->deleted && bh->scheduled) {
- bh->scheduled = 0;
- if (!bh->idle)
- ret = 1;
- bh->idle = 0;
- bh->cb(bh->opaque);
- }
- }
-
- /* remove deleted bhs */
- bhp = &first_bh;
- while (*bhp) {
- bh = *bhp;
- if (bh->deleted) {
- *bhp = bh->next;
- qemu_free(bh);
- } else
- bhp = &bh->next;
- }
-
- return ret;
-}
-
-void qemu_bh_schedule_idle(QEMUBH *bh)
-{
- if (bh->scheduled)
- return;
- bh->scheduled = 1;
- bh->idle = 1;
-}
-
-void qemu_bh_schedule(QEMUBH *bh)
-{
- if (bh->scheduled)
- return;
- bh->scheduled = 1;
- bh->idle = 0;
- /* stop the currently executing CPU to execute the BH ASAP */
- qemu_notify_event();
-}
-
-void qemu_bh_cancel(QEMUBH *bh)
-{
- bh->scheduled = 0;
-}
-
-void qemu_bh_delete(QEMUBH *bh)
-{
- bh->scheduled = 0;
- bh->deleted = 1;
-}
-
-void qemu_bh_update_timeout(int *timeout)
-{
- QEMUBH *bh;
-
- for (bh = first_bh; bh; bh = bh->next) {
- if (!bh->deleted && bh->scheduled) {
- if (bh->idle) {
- /* idle bottom halves will be polled at least
- * every 10ms */
- *timeout = MIN(10, *timeout);
- } else {
- /* non-idle bottom halves will be executed
- * immediately */
- *timeout = 0;
- break;
- }
- }
- }
-}
-
-/***********************************************************/
/* machine registration */
static QEMUMachine *first_machine = NULL;
@@ -4601,14 +4492,6 @@ int main(int argc, char **argv, char **envp)
android_op_audio = (char*)optarg;
break;
- case QEMU_OPTION_audio_in:
- android_op_audio_in = (char*)optarg;
- break;
-
- case QEMU_OPTION_audio_out:
- android_op_audio_out = (char*)optarg;
- break;
-
case QEMU_OPTION_cpu_delay:
android_op_cpu_delay = (char*)optarg;
break;
@@ -4655,6 +4538,10 @@ int main(int argc, char **argv, char **envp)
android_op_ui_settings = (char*)optarg;
break;
+ case QEMU_OPTION_audio_test_out:
+ android_audio_test_start_out();
+ break;
+
#ifdef CONFIG_MEMCHECK
case QEMU_OPTION_android_memcheck:
android_op_memcheck = (char*)optarg;
@@ -4788,48 +4675,10 @@ int main(int argc, char **argv, char **envp)
/* Initialize audio. */
if (android_op_audio) {
- if (android_op_audio_in || android_op_audio_out) {
- PANIC("you can't use -audio with -audio-in or -audio-out");
- }
if ( !audio_check_backend_name( 0, android_op_audio ) ) {
PANIC("'%s' is not a valid audio output backend. see -help-audio-out",
android_op_audio);
}
- android_op_audio_out = android_op_audio;
- android_op_audio_in = android_op_audio;
-
- if ( !audio_check_backend_name( 1, android_op_audio ) ) {
- fprintf(stdout,
- "emulator: warning: '%s' is not a valid audio input backend. audio record disabled\n",
- android_op_audio);
- android_op_audio_in = "none";
- }
- }
-
- if (android_op_audio_in) {
- static char env[64]; /* note: putenv needs a static unique string buffer */
- if ( !audio_check_backend_name( 1, android_op_audio_in ) ) {
- PANIC("'%s' is not a valid audio input backend. see -help-audio-in",
- android_op_audio_in);
- }
- bufprint( env, env+sizeof(env), "QEMU_AUDIO_IN_DRV=%s", android_op_audio_in );
- putenv( env );
-
- if (!android_hw->hw_audioInput) {
- fprintf(stdout, "Emulated hardware doesn't have audio input.\n");
- }
- }
- if (android_op_audio_out) {
- static char env[64]; /* note: putenv needs a static unique string buffer */
- if ( !audio_check_backend_name( 0, android_op_audio_out ) ) {
- PANIC("'%s' is not a valid audio output backend. see -help-audio-out",
- android_op_audio_out);
- }
- bufprint( env, env+sizeof(env), "QEMU_AUDIO_OUT_DRV=%s", android_op_audio_out );
- putenv( env );
- if (!android_hw->hw_audioOutput) {
- fprintf(stdout, "Emulated hardware doesn't have audio output\n");
- }
}
if (android_op_cpu_delay) {
diff --git a/vl.c b/vl.c
index 3069a9c..03cc9ae 100644
--- a/vl.c
+++ b/vl.c
@@ -375,7 +375,7 @@ void hw_error(const char *fmt, ...)
va_end(ap);
abort();
}
-
+
/***************/
/* ballooning */
@@ -2014,7 +2014,7 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
if (ram_load_dead(f, opaque) < 0)
return -EINVAL;
}
-
+
if (flags & RAM_SAVE_FLAG_COMPRESS) {
uint8_t ch = qemu_get_byte(f);
memset(qemu_get_ram_ptr(addr), ch, TARGET_PAGE_SIZE);
@@ -2031,110 +2031,6 @@ void qemu_service_io(void)
}
/***********************************************************/
-/* bottom halves (can be seen as timers which expire ASAP) */
-
-struct QEMUBH {
- QEMUBHFunc *cb;
- void *opaque;
- int scheduled;
- int idle;
- int deleted;
- QEMUBH *next;
-};
-
-static QEMUBH *first_bh = NULL;
-
-QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque)
-{
- QEMUBH *bh;
- bh = qemu_mallocz(sizeof(QEMUBH));
- bh->cb = cb;
- bh->opaque = opaque;
- bh->next = first_bh;
- first_bh = bh;
- return bh;
-}
-
-int qemu_bh_poll(void)
-{
- QEMUBH *bh, **bhp;
- int ret;
-
- ret = 0;
- for (bh = first_bh; bh; bh = bh->next) {
- if (!bh->deleted && bh->scheduled) {
- bh->scheduled = 0;
- if (!bh->idle)
- ret = 1;
- bh->idle = 0;
- bh->cb(bh->opaque);
- }
- }
-
- /* remove deleted bhs */
- bhp = &first_bh;
- while (*bhp) {
- bh = *bhp;
- if (bh->deleted) {
- *bhp = bh->next;
- qemu_free(bh);
- } else
- bhp = &bh->next;
- }
-
- return ret;
-}
-
-void qemu_bh_schedule_idle(QEMUBH *bh)
-{
- if (bh->scheduled)
- return;
- bh->scheduled = 1;
- bh->idle = 1;
-}
-
-void qemu_bh_schedule(QEMUBH *bh)
-{
- if (bh->scheduled)
- return;
- bh->scheduled = 1;
- bh->idle = 0;
- /* stop the currently executing CPU to execute the BH ASAP */
- qemu_notify_event();
-}
-
-void qemu_bh_cancel(QEMUBH *bh)
-{
- bh->scheduled = 0;
-}
-
-void qemu_bh_delete(QEMUBH *bh)
-{
- bh->scheduled = 0;
- bh->deleted = 1;
-}
-
-void qemu_bh_update_timeout(int *timeout)
-{
- QEMUBH *bh;
-
- for (bh = first_bh; bh; bh = bh->next) {
- if (!bh->deleted && bh->scheduled) {
- if (bh->idle) {
- /* idle bottom halves will be polled at least
- * every 10ms */
- *timeout = MIN(10, *timeout);
- } else {
- /* non-idle bottom halves will be executed
- * immediately */
- *timeout = 0;
- break;
- }
- }
- }
-}
-
-/***********************************************************/
/* machine registration */
static QEMUMachine *first_machine = NULL;
@@ -3860,7 +3756,7 @@ int main(int argc, char **argv, char **envp)
{
/* Could easily be extended to 64 devices if needed */
const char *p;
-
+
boot_devices_bitmap = 0;
for (p = boot_devices; *p != '\0'; p++) {
/* Allowed boot devices are:
@@ -4716,7 +4612,7 @@ int main(int argc, char **argv, char **envp)
show_vnc_port = 1;
#endif
}
-
+
switch (display_type) {
case DT_NOGRAPHIC: