From: David Turner <digit@google.com>
To: Anthony Liguori <anthony@codemonkey.ws>
Cc: qemu-devel@nongnu.org
Subject: Re: [Qemu-devel] [PATCH] Add WinWave-based audio backend to Windows QEMU builds
Date: Thu, 11 Jun 2009 02:49:53 +0200 [thread overview]
Message-ID: <60cad3f0906101749n7fcb11efvaf7e0979ee4b6ae1@mail.gmail.com> (raw)
In-Reply-To: <4A3052DA.1010308@codemonkey.ws>
[-- Attachment #1: Type: text/plain, Size: 22700 bytes --]
Sorry, here's the patch inlined:
>From 4e061a312b5f6575462e3fa50c7df20788e5f95c Mon Sep 17 00:00:00 2001
From: digit <digit@google.com>
Date: Wed, 10 Jun 2009 14:11:28 +0200
Subject: [PATCH] Add a Windows Wave audio backend to QEMU.
This backend provides both playback and record. It doesn't depend
on any external library like SDL or FMOD, or any non-distributable
headers like the DirectSound ones.
For this reason, it is made the default for Cygwin and Mingw builds
Tested on both Cygwin and MSys builds.
Signed-off-by: David Turner <digit@google.com>
---
Makefile | 3 +
audio/audio_int.h | 1 +
audio/winaudio.c | 663
+++++++++++++++++++++++++++++++++++++++++++++++++++++
configure | 8 +-
4 files changed, 672 insertions(+), 3 deletions(-)
create mode 100644 audio/winaudio.c
diff --git a/Makefile b/Makefile
index 3177616..8f7894a 100644
--- a/Makefile
+++ b/Makefile
@@ -137,6 +137,9 @@ endif
ifdef CONFIG_DSOUND
AUDIO_OBJS += dsoundaudio.o
endif
+ifdef CONFIG_WINAUDIO
+AUDIO_OBJS += winaudio.o
+endif
ifdef CONFIG_FMOD
AUDIO_OBJS += fmodaudio.o
audio/audio.o audio/fmodaudio.o: CPPFLAGS := -I$(CONFIG_FMOD_INC)
$(CPPFLAGS)
diff --git a/audio/audio_int.h b/audio/audio_int.h
index 0abed38..f2c08ac 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -207,6 +207,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 winaudio_audio_driver;
extern struct mixeng_volume nominal_volume;
void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings
*as);
diff --git a/audio/winaudio.c b/audio/winaudio.c
new file mode 100644
index 0000000..5000f7b
--- /dev/null
+++ b/audio/winaudio.c
@@ -0,0 +1,663 @@
+/*
+ * QEMU "simple" Windows audio driver
+ *
+ * Copyright (c) 2007 The Android Open Source Project
+ *
+ * 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 <windows.h>
+#include <mmsystem.h>
+
+#include "qemu-common.h"
+#include "audio.h"
+
+#define AUDIO_CAP "winaudio"
+#include "audio_int.h"
+
+/* define DEBUG to 1 to dump audio debugging info at runtime to stderr */
+#define DEBUG 0
+
+/* define DEBUG_TIMING to 1 to dump timing debugging messages */
+#define DEBUG_TIMING 0
+
+#if DEBUG
+# define D(...) printf(__VA_ARGS__)
+#else
+# define D(...) ((void)0)
+#endif
+
+static struct {
+ int nb_samples;
+} conf = {
+ 1024
+};
+
+#if DEBUG_TIMING
+int64_t start_time;
+int64_t last_time;
+#endif
+
+/* XP works well with 4, but Vista struggles with anything less than 8 */
+#define NUM_OUT_BUFFERS 8 /* must be at least 2 */
+
+/** COMMON UTILITIES
+ **/
+
+#if DEBUG
+static void
+dump_mmerror( const char* func, MMRESULT error )
+{
+ const char* reason = NULL;
+
+ fprintf(stderr, "%s returned error: ", func);
+ switch (error) {
+ case MMSYSERR_ALLOCATED: reason="specified resource is already
allocated"; break;
+ case MMSYSERR_BADDEVICEID: reason="bad device id"; break;
+ case MMSYSERR_NODRIVER: reason="no driver is present"; break;
+ case MMSYSERR_NOMEM: reason="unable to allocate or lock
memory"; break;
+ case WAVERR_BADFORMAT: reason="unsupported waveform-audio
format"; break;
+ case WAVERR_SYNC: reason="device is synchronous"; break;
+ default:
+ fprintf(stderr, "unknown(%d)\n", error);
+ }
+ if (reason)
+ fprintf(stderr, "%s\n", reason);
+}
+#else
+# define dump_mmerror(func,error) ((void)0)
+#endif
+
+
+/** AUDIO OUT
+ **/
+
+typedef struct WinAudioOut {
+ HWVoiceOut hw;
+ HWAVEOUT waveout;
+ int silence;
+ CRITICAL_SECTION lock;
+ unsigned char* buffer_bytes;
+ WAVEHDR buffers[ NUM_OUT_BUFFERS ];
+ int write_index; /* starting first writable buffer
*/
+ int write_count; /* available writable buffers count
*/
+ int write_pos; /* position in current writable buffer
*/
+ int write_size; /* size in bytes of each buffer
*/
+} WinAudioOut;
+
+/* The callback that is called when Windows has finished playing a buffer
*/
+static void CALLBACK
+winaudio_out_buffer_done (HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance,
+ DWORD dwParam1, DWORD dwParam2)
+{
+ WinAudioOut* s = (WinAudioOut*) dwInstance;
+
+ /* Only service "buffer done playing" messages */
+ if ( uMsg != WOM_DONE )
+ return;
+
+ /* Signal that we are done playing a buffer */
+ EnterCriticalSection( &s->lock );
+ if (s->write_count < NUM_OUT_BUFFERS)
+ s->write_count += 1;
+ LeaveCriticalSection( &s->lock );
+}
+
+static int
+winaudio_out_write (SWVoiceOut *sw, void *buf, int len)
+{
+ return audio_pcm_sw_write (sw, buf, len);
+}
+
+static void
+winaudio_out_fini (HWVoiceOut *hw)
+{
+ WinAudioOut* s = (WinAudioOut*) hw;
+ int i;
+
+ if (s->waveout) {
+ waveOutReset(s->waveout);
+ s->waveout = 0;
+ }
+
+ for ( i=0; i<NUM_OUT_BUFFERS; ++i ) {
+ if ( s->buffers[i].dwUser != 0xFFFF ) {
+ waveOutUnprepareHeader(
+ s->waveout, &s->buffers[i], sizeof(s->buffers[i]) );
+ s->buffers[i].dwUser = 0xFFFF;
+ }
+ }
+
+ if (s->buffer_bytes != NULL) {
+ qemu_free(s->buffer_bytes);
+ s->buffer_bytes = NULL;
+ }
+
+ if (s->waveout) {
+ waveOutClose(s->waveout);
+ s->waveout = NULL;
+ }
+}
+
+
+static int
+winaudio_out_init (HWVoiceOut *hw, struct audsettings *as)
+{
+ WinAudioOut* s = (WinAudioOut*) hw;
+ MMRESULT result;
+ WAVEFORMATEX format;
+ int shift, i, samples_size;
+
+ s->waveout = NULL;
+ InitializeCriticalSection( &s->lock );
+ for (i = 0; i < NUM_OUT_BUFFERS; i++) {
+ s->buffers[i].dwUser = 0xFFFF;
+ }
+ s->buffer_bytes = NULL;
+
+ /* compute desired wave output format */
+ format.wFormatTag = WAVE_FORMAT_PCM;
+ format.nChannels = as->nchannels;
+ format.nSamplesPerSec = as->freq;
+ format.nAvgBytesPerSec = as->freq*as->nchannels;
+
+ s->silence = 0;
+
+ switch (as->fmt) {
+ case AUD_FMT_S8: shift = 0; break;
+ case AUD_FMT_U8: shift = 0; s->silence = 0x80; break;
+ case AUD_FMT_S16: shift = 1; break;
+ case AUD_FMT_U16: shift = 1; s->silence = 0x8000; break;
+ case AUD_FMT_S32: shift = 2; break;
+ case AUD_FMT_U32: shift = 2; s->silence = 0x80000000; break;
+ default:
+ fprintf(stderr, "qemu: winaudio: Bad output audio format:
%d\n",
+ as->fmt);
+ return -1;
+ }
+
+ format.nAvgBytesPerSec = (format.nSamplesPerSec & format.nChannels) <<
shift;
+ format.nBlockAlign = format.nChannels << shift;
+ format.wBitsPerSample = 8 << shift;
+ format.cbSize = 0;
+
+ /* open the wave out device */
+ result = waveOutOpen( &s->waveout, WAVE_MAPPER, &format,
+ (DWORD_PTR) winaudio_out_buffer_done,
+ (DWORD_PTR) hw, CALLBACK_FUNCTION);
+ if ( result != MMSYSERR_NOERROR ) {
+ dump_mmerror( "qemu: winaudio: waveOutOpen()", result);
+ return -1;
+ }
+
+ samples_size = format.nBlockAlign * conf.nb_samples;
+ s->buffer_bytes = qemu_malloc( NUM_OUT_BUFFERS * samples_size );
+ if (s->buffer_bytes == NULL) {
+ waveOutClose( s->waveout );
+ s->waveout = NULL;
+ fprintf(stderr, "not enough memory for Windows audio
buffers\n");
+ return -1;
+ }
+
+ for (i = 0; i < NUM_OUT_BUFFERS; i++) {
+ memset( &s->buffers[i], 0, sizeof(s->buffers[i]) );
+ s->buffers[i].lpData = (LPSTR)(s->buffer_bytes +
i*samples_size);
+ s->buffers[i].dwBufferLength = samples_size;
+ s->buffers[i].dwFlags = WHDR_DONE;
+
+ result = waveOutPrepareHeader( s->waveout, &s->buffers[i],
+ sizeof(s->buffers[i]) );
+ if ( result != MMSYSERR_NOERROR ) {
+ dump_mmerror("waveOutPrepareHeader()", result);
+ return -1;
+ }
+ }
+
+#if DEBUG
+ /* Check the sound device we retrieved */
+ {
+ WAVEOUTCAPS caps;
+
+ result = waveOutGetDevCaps((UINT) s->waveout, &caps, sizeof(caps));
+ if ( result != MMSYSERR_NOERROR ) {
+ dump_mmerror("waveOutGetDevCaps()", result);
+ } else
+ printf("Audio out device: %s\n", caps.szPname);
+ }
+#endif
+
+ audio_pcm_init_info (&hw->info, as);
+ hw->samples = conf.nb_samples*2;
+
+ s->write_index = 0;
+ s->write_count = NUM_OUT_BUFFERS;
+ s->write_pos = 0;
+ s->write_size = samples_size;
+ return 0;
+}
+
+
+static int
+winaudio_out_run (HWVoiceOut *hw)
+{
+ WinAudioOut* s = (WinAudioOut*) hw;
+ int played = 0;
+ int has_buffer;
+ int live = audio_pcm_hw_get_live_out (hw);
+
+ if (!live) {
+ return 0;
+ }
+
+ EnterCriticalSection( &s->lock );
+ has_buffer = (s->write_count > 0);
+ LeaveCriticalSection( &s->lock );
+
+ if (!has_buffer)
+ return 0;
+
+ while (live > 0) {
+ WAVEHDR* wav_buffer = s->buffers + s->write_index;
+ int wav_bytes = (s->write_size - s->write_pos);
+ int wav_samples = audio_MIN(wav_bytes >> hw->info.shift,
live);
+ int hw_samples = audio_MIN(hw->samples - hw->rpos,
live);
+ struct st_sample* src = hw->mix_buf + hw->rpos;
+ uint8_t* dst = (uint8_t*)wav_buffer->lpData +
s->write_pos;
+
+ if (wav_samples > hw_samples) {
+ wav_samples = hw_samples;
+ }
+
+ wav_bytes = wav_samples << hw->info.shift;
+
+ //D("run_out: buffer:%d pos:%d size:%d wsamples:%d wbytes:%d
live:%d rpos:%d hwsamples:%d\n", s->write_index,
+ // s->write_pos, s->write_size, wav_samples, wav_bytes, live,
hw->rpos, hw->samples);
+ hw->clip (dst, src, wav_samples);
+ hw->rpos += wav_samples;
+ if (hw->rpos >= hw->samples)
+ hw->rpos -= hw->samples;
+
+ live -= wav_samples;
+ played += wav_samples;
+ s->write_pos += wav_bytes;
+ if (s->write_pos == s->write_size) {
+#if DEBUG_TIMING
+ int64_t now = qemu_get_clock(vm_clock) - start_time;
+ int64_t diff = now - last_time;
+
+ D("run_out: (%7.3f:%7d):waveOutWrite buffer:%d\n",
+ now/1e9, (now-last_time)/1e9, s->write_index);
+ last_time = now;
+#endif
+ waveOutWrite( s->waveout, wav_buffer, sizeof(*wav_buffer) );
+ s->write_pos = 0;
+ s->write_index += 1;
+ if (s->write_index == NUM_OUT_BUFFERS)
+ s->write_index = 0;
+
+ EnterCriticalSection( &s->lock );
+ if (--s->write_count == 0) {
+ live = 0;
+ }
+ LeaveCriticalSection( &s->lock );
+ }
+ }
+ return played;
+}
+
+static int
+winaudio_out_ctl (HWVoiceOut *hw, int cmd, ...)
+{
+ WinAudioOut* s = (WinAudioOut*) hw;
+
+ switch (cmd) {
+ case VOICE_ENABLE:
+ waveOutRestart( s->waveout );
+ break;
+
+ case VOICE_DISABLE:
+ waveOutPause( s->waveout );
+ break;
+ }
+ return 0;
+}
+
+/** AUDIO IN
+ **/
+
+#define NUM_IN_BUFFERS 2
+
+typedef struct WinAudioIn {
+ HWVoiceIn hw;
+ HWAVEIN wavein;
+ CRITICAL_SECTION lock;
+ unsigned char* buffer_bytes;
+ WAVEHDR buffers[ NUM_IN_BUFFERS ];
+ int read_index;
+ int read_count;
+ int read_pos;
+ int read_size;
+} WinAudioIn;
+
+/* The callback that is called when Windows has finished filling a buffer
*/
+static void CALLBACK
+winaudio_in_buffer_done (HWAVEIN hwi, UINT uMsg, DWORD_PTR dwInstance,
+ DWORD dwParam1, DWORD dwParam2)
+{
+ WinAudioIn* s = (WinAudioIn*) dwInstance;
+
+ /* Only service "buffer filled" messages */
+ if ( uMsg != WIM_DATA )
+ return;
+
+ /* Signal that we are done playing a buffer */
+ EnterCriticalSection( &s->lock );
+ if (s->read_count < NUM_IN_BUFFERS)
+ s->read_count += 1;
+ LeaveCriticalSection( &s->lock );
+}
+
+static void
+winaudio_in_fini (HWVoiceIn *hw)
+{
+ WinAudioIn* s = (WinAudioIn*) hw;
+ int i;
+
+ if (s->wavein) {
+ waveInReset(s->wavein);
+ s->wavein = 0;
+ }
+
+ for ( i=0; i<NUM_OUT_BUFFERS; ++i ) {
+ if ( s->buffers[i].dwUser != 0xFFFF ) {
+ waveInUnprepareHeader(
+ s->wavein, &s->buffers[i], sizeof(s->buffers[i]) );
+ s->buffers[i].dwUser = 0xFFFF;
+ }
+ }
+
+ if (s->buffer_bytes != NULL) {
+ qemu_free(s->buffer_bytes);
+ s->buffer_bytes = NULL;
+ }
+
+ if (s->wavein) {
+ waveInClose(s->wavein);
+ s->wavein = NULL;
+ }
+}
+
+
+static int
+winaudio_in_init (HWVoiceIn *hw, struct audsettings *as)
+{
+ WinAudioIn* s = (WinAudioIn*) hw;
+ MMRESULT result;
+ WAVEFORMATEX format;
+ int shift, i, samples_size;
+
+ s->wavein = NULL;
+ InitializeCriticalSection( &s->lock );
+ for (i = 0; i < NUM_OUT_BUFFERS; i++) {
+ s->buffers[i].dwUser = 0xFFFF;
+ }
+ s->buffer_bytes = NULL;
+
+ /* compute desired wave input format */
+ format.wFormatTag = WAVE_FORMAT_PCM;
+ format.nChannels = as->nchannels;
+ format.nSamplesPerSec = as->freq;
+ format.nAvgBytesPerSec = as->freq*as->nchannels;
+
+ switch (as->fmt) {
+ case AUD_FMT_S8: shift = 0; break;
+ case AUD_FMT_U8: shift = 0; break;
+ case AUD_FMT_S16: shift = 1; break;
+ case AUD_FMT_U16: shift = 1; break;
+ case AUD_FMT_S32: shift = 2; break;
+ case AUD_FMT_U32: shift = 2; break;
+ default:
+ fprintf(stderr, "qemu: winaudio: Bad input audio format: %d\n",
+ as->fmt);
+ return -1;
+ }
+
+ format.nAvgBytesPerSec = (format.nSamplesPerSec * format.nChannels) <<
shift;
+ format.nBlockAlign = format.nChannels << shift;
+ format.wBitsPerSample = 8 << shift;
+ format.cbSize = 0;
+
+ /* open the wave in device */
+ result = waveInOpen( &s->wavein, WAVE_MAPPER, &format,
+ (DWORD_PTR)winaudio_in_buffer_done, (DWORD_PTR)
hw,
+ CALLBACK_FUNCTION);
+ if ( result != MMSYSERR_NOERROR ) {
+ dump_mmerror( "qemu: winaudio: waveInOpen()", result);
+ return -1;
+ }
+
+ samples_size = format.nBlockAlign * conf.nb_samples;
+ s->buffer_bytes = qemu_malloc( NUM_IN_BUFFERS * samples_size );
+ if (s->buffer_bytes == NULL) {
+ waveInClose( s->wavein );
+ s->wavein = NULL;
+ fprintf(stderr, "not enough memory for Windows audio buffers\n");
+ return -1;
+ }
+
+ for (i = 0; i < NUM_IN_BUFFERS; i++) {
+ memset( &s->buffers[i], 0, sizeof(s->buffers[i]) );
+ s->buffers[i].lpData = (LPSTR)(s->buffer_bytes +
i*samples_size);
+ s->buffers[i].dwBufferLength = samples_size;
+ s->buffers[i].dwFlags = WHDR_DONE;
+
+ result = waveInPrepareHeader( s->wavein, &s->buffers[i],
+ sizeof(s->buffers[i]) );
+ if ( result != MMSYSERR_NOERROR ) {
+ dump_mmerror("waveInPrepareHeader()", result);
+ return -1;
+ }
+
+ result = waveInAddBuffer( s->wavein, &s->buffers[i],
+ sizeof(s->buffers[i]) );
+ if ( result != MMSYSERR_NOERROR ) {
+ dump_mmerror("waveInAddBuffer()", result);
+ return -1;
+ }
+ }
+
+#if DEBUG
+ /* Check the sound device we retrieved */
+ {
+ WAVEINCAPS caps;
+
+ result = waveInGetDevCaps((UINT) s->wavein, &caps, sizeof(caps));
+ if ( result != MMSYSERR_NOERROR ) {
+ dump_mmerror("waveInGetDevCaps()", result);
+ } else
+ printf("Audio in device: %s\n", caps.szPname);
+ }
+#endif
+
+ audio_pcm_init_info (&hw->info, as);
+ hw->samples = conf.nb_samples*2;
+
+ s->read_index = 0;
+ s->read_count = 0;
+ s->read_pos = 0;
+ s->read_size = samples_size;
+ return 0;
+}
+
+
+/* report the number of captured samples to the audio subsystem */
+static int
+winaudio_in_run (HWVoiceIn *hw)
+{
+ WinAudioIn* s = (WinAudioIn*) hw;
+ int captured = 0;
+ int has_buffer;
+ int live = hw->samples - hw->total_samples_captured;
+
+ if (!live) {
+ return 0;
+ }
+
+ EnterCriticalSection( &s->lock );
+ has_buffer = (s->read_count > 0);
+ LeaveCriticalSection( &s->lock );
+
+ if (!has_buffer)
+ return 0;
+
+ while (live > 0) {
+ WAVEHDR* wav_buffer = s->buffers + s->read_index;
+ int wav_bytes = (s->read_size - s->read_pos);
+ int wav_samples = audio_MIN(wav_bytes >> hw->info.shift,
live);
+ int hw_samples = audio_MIN(hw->samples - hw->wpos,
live);
+ struct st_sample* dst = hw->conv_buf + hw->wpos;
+ uint8_t* src = (uint8_t*)wav_buffer->lpData +
s->read_pos;
+
+ if (wav_samples > hw_samples) {
+ wav_samples = hw_samples;
+ }
+
+ wav_bytes = wav_samples << hw->info.shift;
+
+ D("%s: buffer:%d pos:%d size:%d wsamples:%d wbytes:%d live:%d
wpos:%d hwsamples:%d\n",
+ __FUNCTION__, s->read_index, s->read_pos, s->read_size,
wav_samples, wav_bytes, live,
+ hw->wpos, hw->samples);
+
+ hw->conv(dst, src, wav_samples, &nominal_volume);
+
+ hw->wpos += wav_samples;
+ if (hw->wpos >= hw->samples)
+ hw->wpos -= hw->samples;
+
+ live -= wav_samples;
+ captured += wav_samples;
+ s->read_pos += wav_bytes;
+ if (s->read_pos == s->read_size) {
+ s->read_pos = 0;
+ s->read_index += 1;
+ if (s->read_index == NUM_IN_BUFFERS)
+ s->read_index = 0;
+
+ waveInAddBuffer( s->wavein, wav_buffer, sizeof(*wav_buffer) );
+
+ EnterCriticalSection( &s->lock );
+ if (--s->read_count == 0) {
+ live = 0;
+ }
+ LeaveCriticalSection( &s->lock );
+ }
+ }
+ return captured;
+}
+
+
+static int
+winaudio_in_read (SWVoiceIn *sw, void *buf, int len)
+{
+ int ret = audio_pcm_sw_read (sw, buf, len);
+ if (ret > 0)
+ D("%s: (%d) returned %d\n", __FUNCTION__, len, ret);
+ return ret;
+}
+
+
+static int
+winaudio_in_ctl (HWVoiceIn *hw, int cmd, ...)
+{
+ WinAudioIn* s = (WinAudioIn*) hw;
+
+ switch (cmd) {
+ case VOICE_ENABLE:
+ D("%s: enable audio in\n", __FUNCTION__);
+ waveInStart( s->wavein );
+ break;
+
+ case VOICE_DISABLE:
+ D("%s: disable audio in\n", __FUNCTION__);
+ waveInStop( s->wavein );
+ break;
+ }
+ return 0;
+}
+
+/** AUDIO STATE
+ **/
+
+typedef struct WinAudioState {
+ int dummy;
+} WinAudioState;
+
+static WinAudioState g_winaudio;
+
+static void*
+winaudio_init(void)
+{
+ WinAudioState* s = &g_winaudio;
+
+#if DEBUG_TIMING
+ start_time = qemu_get_clock(vm_clock);
+ last_time = 0;
+#endif
+
+ return s;
+}
+
+
+static void
+winaudio_fini (void *opaque)
+{
+}
+
+static struct audio_option winaudio_options[] = {
+ {"SAMPLES", AUD_OPT_INT, &conf.nb_samples,
+ "Size of Windows audio buffer in samples", NULL, 0},
+ {NULL, 0, NULL, NULL, NULL, 0}
+};
+
+static struct audio_pcm_ops winaudio_pcm_ops = {
+ winaudio_out_init,
+ winaudio_out_fini,
+ winaudio_out_run,
+ winaudio_out_write,
+ winaudio_out_ctl,
+
+ winaudio_in_init,
+ winaudio_in_fini,
+ winaudio_in_run,
+ winaudio_in_read,
+ winaudio_in_ctl
+};
+
+struct audio_driver winaudio_audio_driver = {
+ INIT_FIELD (name = ) "winaudio",
+ INIT_FIELD (descr = ) "Windows wave audio",
+ INIT_FIELD (options = ) winaudio_options,
+ INIT_FIELD (init = ) winaudio_init,
+ INIT_FIELD (fini = ) winaudio_fini,
+ INIT_FIELD (pcm_ops = ) &winaudio_pcm_ops,
+ INIT_FIELD (can_be_default = ) 1,
+ INIT_FIELD (max_voices_out = ) 1,
+ INIT_FIELD (max_voices_in = ) 1,
+ INIT_FIELD (voice_size_out = ) sizeof (WinAudioOut),
+ INIT_FIELD (voice_size_in = ) sizeof (WinAudioIn)
+};
diff --git a/configure b/configure
index 89e7f53..3ddb138 100755
--- a/configure
+++ b/configure
@@ -219,14 +219,16 @@ OS_CFLAGS="-mno-cygwin"
if [ "$cpu" = "i386" ] ; then
kqemu="yes"
fi
-audio_possible_drivers="sdl"
+audio_drv_list="winaudio"
+audio_possible_drivers="winaudio sdl"
;;
MINGW32*)
mingw32="yes"
if [ "$cpu" = "i386" ] ; then
kqemu="yes"
fi
-audio_possible_drivers="dsound sdl fmod"
+audio_drv_list=winaudio
+audio_possible_drivers="dsound winaudio sdl fmod"
;;
GNU/kFreeBSD)
audio_drv_list="oss"
@@ -1033,7 +1035,7 @@ for drv in $audio_drv_list; do
"pa_simple *s = NULL; pa_simple_free(s); return 0;"
;;
- oss|sdl|core|wav|dsound)
+ oss|sdl|core|wav|dsound|winaudio)
# XXX: Probes for CoreAudio, DirectSound, SDL(?)
;;
--
1.5.4.3
[-- Attachment #2: Type: text/html, Size: 26673 bytes --]
next prev parent reply other threads:[~2009-06-11 0:50 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-06-11 0:15 [Qemu-devel] [PATCH] Add WinWave-based audio backend to Windows QEMU builds David Turner
2009-06-11 0:42 ` Anthony Liguori
2009-06-11 0:49 ` David Turner [this message]
2009-06-11 1:35 ` malc
2009-06-12 9:03 ` David Turner
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=60cad3f0906101749n7fcb11efvaf7e0979ee4b6ae1@mail.gmail.com \
--to=digit@google.com \
--cc=anthony@codemonkey.ws \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).