From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1MEYUW-0005Hk-CC for qemu-devel@nongnu.org; Wed, 10 Jun 2009 20:50:04 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1MEYUR-0005GP-Vn for qemu-devel@nongnu.org; Wed, 10 Jun 2009 20:50:04 -0400 Received: from [199.232.76.173] (port=55615 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1MEYUR-0005GM-Nz for qemu-devel@nongnu.org; Wed, 10 Jun 2009 20:49:59 -0400 Received: from smtp-out.google.com ([216.239.33.17]:22947) by monty-python.gnu.org with esmtps (TLS-1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.60) (envelope-from ) id 1MEYUQ-00049r-2G for qemu-devel@nongnu.org; Wed, 10 Jun 2009 20:49:59 -0400 Received: from spaceape8.eur.corp.google.com (spaceape8.eur.corp.google.com [172.28.16.142]) by smtp-out.google.com with ESMTP id n5B0ntil026171 for ; Thu, 11 Jun 2009 01:49:55 +0100 Received: from bwz5 (bwz5.prod.google.com [10.188.26.5]) by spaceape8.eur.corp.google.com with ESMTP id n5B0nsfS008021 for ; Wed, 10 Jun 2009 17:49:54 -0700 Received: by bwz5 with SMTP id 5so1330116bwz.23 for ; Wed, 10 Jun 2009 17:49:53 -0700 (PDT) MIME-Version: 1.0 In-Reply-To: <4A3052DA.1010308@codemonkey.ws> References: <60cad3f0906101715ufc754d1q339870a9fb8f8107@mail.gmail.com> <4A3052DA.1010308@codemonkey.ws> Date: Thu, 11 Jun 2009 02:49:53 +0200 Message-ID: <60cad3f0906101749n7fcb11efvaf7e0979ee4b6ae1@mail.gmail.com> Subject: Re: [Qemu-devel] [PATCH] Add WinWave-based audio backend to Windows QEMU builds From: David Turner Content-Type: multipart/alternative; boundary=001636c5a435555d34046c07f87e List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Anthony Liguori Cc: qemu-devel@nongnu.org --001636c5a435555d34046c07f87e Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit Sorry, here's the patch inlined: >>From 4e061a312b5f6575462e3fa50c7df20788e5f95c Mon Sep 17 00:00:00 2001 From: digit 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 --- 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 +#include + +#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; ibuffers[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; ibuffers[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 --001636c5a435555d34046c07f87e Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable Sorry, here's the patch inlined:

From 4e061a312b5f6575462e3fa50c= 7df20788e5f95c Mon Sep 17 00:00:00 2001
From: digit <digit@google.com>
Date: Wed, 10 Jun 2009 14:1= 1:28 +0200
Subject: [PATCH] Add a Windows Wave audio backend to QEMU.

This back= end provides both playback and record. It doesn't depend
on any exte= rnal 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 Turn= er <digit@google.com>
---<= br> =A0Makefile=A0=A0=A0=A0=A0=A0=A0=A0=A0 |=A0=A0=A0 3 +
=A0audio/audio_int= .h |=A0=A0=A0 1 +
=A0audio/winaudio.c=A0 |=A0 663 ++++++++++++++++++++++= +++++++++++++++++++++++++++++++
=A0configure=A0=A0=A0=A0=A0=A0=A0=A0 |= =A0=A0=A0 8 +-
=A04 files changed, 672 insertions(+), 3 deletions(-)
=A0create mode 100644 audio/winaudio.c

diff --git a/Makefile b/Makef= ile
index 3177616..8f7894a 100644
--- a/Makefile
+++ b/Makefile@@ -137,6 +137,9 @@ endif
=A0ifdef CONFIG_DSOUND
=A0AUDIO_OBJS +=3D = dsoundaudio.o
=A0endif
+ifdef CONFIG_WINAUDIO
+AUDIO_OBJS +=3D winaudio.o
+endif=
=A0ifdef CONFIG_FMOD
=A0AUDIO_OBJS +=3D fmodaudio.o
=A0audio/audi= o.o audio/fmodaudio.o: CPPFLAGS :=3D -I$(CONFIG_FMOD_INC) $(CPPFLAGS)
di= ff --git a/audio/audio_int.h b/audio/audio_int.h
index 0abed38..f2c08ac 100644
--- a/audio/audio_int.h
+++ b/audio/aud= io_int.h
@@ -207,6 +207,7 @@ extern struct audio_driver coreaudio_audio_= driver;
=A0extern struct audio_driver dsound_audio_driver;
=A0extern = struct audio_driver esd_audio_driver;
=A0extern struct audio_driver pa_audio_driver;
+extern struct audio_driv= er winaudio_audio_driver;
=A0extern struct mixeng_volume nominal_volume;=
=A0
=A0void 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 100644index 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 co= py
+ * of this software and associated documentation files (the "So= ftware"), to deal
+ * in the Software without restriction, including without limitation the r= ights
+ * to use, copy, modify, merge, publish, distribute, sublicense, = and/or sell
+ * copies of the Software, and to permit persons to whom th= e Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * = The above copyright notice and this permission notice shall be included in<= br>+ * all copies or substantial portions of the Software.
+ *
+ * TH= E SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXP= RESS 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, DAMA= GES 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&qu= ot;
+#include "audio_int.h"
+
+/* define DEBUG to 1 to d= ump audio debugging info at runtime to stderr */
+#define=A0 DEBUG=A0 0
+
+/* define DEBUG_TIMING to 1 to dump timing = debugging messages */
+#define=A0 DEBUG_TIMING=A0 0
+
+#if DEBUG+#=A0 define=A0 D(...)=A0=A0 printf(__VA_ARGS__)
+#else
+#=A0 defin= e=A0 D(...)=A0=A0 ((void)0)
+#endif
+
+static struct {
+=A0=A0=A0 int nb_samples;
+} conf = =3D {
+=A0=A0=A0 1024
+};
+
+#if DEBUG_TIMING
+int64_t=A0 st= art_time;
+int64_t=A0 last_time;
+#endif
+
+/* XP works well wi= th 4, but Vista struggles with anything less than 8 */
+#define=A0 NUM_OUT_BUFFERS=A0 8=A0 /* must be at least 2 */
+
+/** C= OMMON UTILITIES
+ **/
+
+#if DEBUG
+static void
+dump_mmerro= r( const char*=A0 func, MMRESULT=A0 error )
+{
+=A0=A0=A0 const char*= =A0 reason =3D NULL;
+
+=A0=A0=A0 fprintf(stderr, "%s returned error: ", func);
= +=A0=A0=A0 switch (error) {
+=A0=A0=A0=A0=A0=A0=A0 case MMSYSERR_ALLOCAT= ED:=A0=A0 reason=3D"specified resource is already allocated"; bre= ak;
+=A0=A0=A0=A0=A0=A0=A0 case MMSYSERR_BADDEVICEID: reason=3D"bad= device id"; break;
+=A0=A0=A0=A0=A0=A0=A0 case MMSYSERR_NODRIVER:=A0=A0=A0 reason=3D"no d= river is present"; break;
+=A0=A0=A0=A0=A0=A0=A0 case MMSYSERR_NOME= M:=A0=A0=A0=A0=A0=A0 reason=3D"unable to allocate or lock memory"= ; break;
+=A0=A0=A0=A0=A0=A0=A0 case WAVERR_BADFORMAT:=A0=A0=A0=A0 reaso= n=3D"unsupported waveform-audio format"; break;
+=A0=A0=A0=A0=A0=A0=A0 case WAVERR_SYNC:=A0=A0=A0=A0=A0=A0=A0=A0=A0 reason= =3D"device is synchronous"; break;
+=A0=A0=A0=A0=A0=A0=A0 defa= ult:
+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 fprintf(stderr, "unknown(%d= )\n", error);
+=A0=A0=A0 }
+=A0=A0=A0 if (reason)
+=A0=A0=A0= =A0=A0=A0=A0 fprintf(stderr, "%s\n", reason);
+}
+#else
+#=A0 define=A0 dump_mmerror(func,error)=A0 ((void)0)
+#= endif
+
+
+/** AUDIO OUT
+ **/
+
+typedef struct WinAudio= Out {
+=A0=A0=A0 HWVoiceOut=A0=A0=A0=A0=A0=A0=A0 hw;
+=A0=A0=A0 HWAVE= OUT=A0=A0=A0=A0=A0=A0=A0=A0=A0 waveout;
+=A0=A0=A0 int=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0 silence;
+=A0=A0=A0 CRITICAL_SECTION=A0 lock;
+=A0=A0=A0 unsigned char*=A0=A0=A0 = buffer_bytes;
+=A0=A0=A0 WAVEHDR=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 buffers[ = NUM_OUT_BUFFERS ];
+=A0=A0=A0 int=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0 write_index;=A0=A0 /* starting first writable buffer=A0=A0=A0=A0=A0 */<= br>+=A0=A0=A0 int=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 write_count;=A0= =A0 /* available writable buffers count=A0=A0=A0 */
+=A0=A0=A0 int=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 write_pos;=A0=A0= =A0=A0 /* position in current writable buffer */
+=A0=A0=A0 int=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 write_size;=A0=A0=A0 /* size in bytes of = each buffer=A0=A0=A0=A0=A0=A0=A0 */
+} WinAudioOut;
+
+/* The call= back that is called when Windows has finished playing a buffer */
+static void CALLBACK
+winaudio_out_buffer_done (HWAVEOUT hwo, UINT uMsg= , DWORD_PTR dwInstance,
+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 DWORD dwParam1, DWORD dwParam2)
+{
+= =A0=A0=A0 WinAudioOut*=A0 s =3D (WinAudioOut*) dwInstance;
+
+=A0=A0=A0 /* Only service "buffer done playing" messages */=
+=A0=A0=A0 if ( uMsg !=3D WOM_DONE )
+=A0=A0=A0=A0=A0=A0=A0 return;<= br>+
+=A0=A0=A0 /* Signal that we are done playing a buffer */
+=A0= =A0=A0 EnterCriticalSection( &s->lock );
+=A0=A0=A0 if (s->write_count < NUM_OUT_BUFFERS)
+=A0=A0=A0=A0=A0= =A0=A0 s->write_count +=3D 1;
+=A0=A0=A0 LeaveCriticalSection( &s= ->lock );
+}
+
+static int
+winaudio_out_write (SWVoiceOut *= sw, void *buf, int len)
+{
+=A0=A0=A0 return audio_pcm_sw_write (sw, buf, len);
+}
+
+s= tatic void
+winaudio_out_fini (HWVoiceOut *hw)
+{
+=A0=A0=A0 WinAu= dioOut*=A0 s =3D (WinAudioOut*) hw;
+=A0=A0=A0 int=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0 i;
+
+=A0=A0=A0 if (s->waveout) {
+=A0=A0=A0=A0=A0=A0=A0 waveOutReset(s->waveout);
+=A0=A0=A0=A0=A0=A0= =A0 s->waveout =3D 0;
+=A0=A0=A0 }
+
+=A0=A0=A0 for ( i=3D0; i&= lt;NUM_OUT_BUFFERS; ++i ) {
+=A0=A0=A0=A0=A0=A0=A0 if ( s->buffers[i]= .dwUser !=3D 0xFFFF ) {
+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 waveOutUnprep= areHeader(
+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 s->waveout, &s->bu= ffers[i], sizeof(s->buffers[i]) );
+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0 s->buffers[i].dwUser =3D 0xFFFF;
+=A0=A0=A0=A0=A0=A0=A0 = }
+=A0=A0=A0 }
+
+=A0=A0=A0 if (s->buffer_bytes !=3D NULL) {+=A0=A0=A0=A0=A0=A0=A0 qemu_free(s->buffer_bytes);
+=A0=A0=A0=A0=A0=A0=A0 s->buffer_bytes =3D NULL;
+=A0=A0=A0 }
++=A0=A0=A0 if (s->waveout) {
+=A0=A0=A0=A0=A0=A0=A0 waveOutClose(s-&= gt;waveout);
+=A0=A0=A0=A0=A0=A0=A0 s->waveout =3D NULL;
+=A0=A0= =A0 }
+}
+
+
+static int
+winaudio_out_init (HWVoiceOut *hw,= struct audsettings *as)
+{
+=A0=A0=A0 WinAudioOut*=A0=A0 s =3D (WinAudioOut*) hw;
+=A0=A0=A0 = MMRESULT=A0=A0=A0=A0=A0=A0 result;
+=A0=A0=A0 WAVEFORMATEX=A0=A0 format;=
+=A0=A0=A0 int=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 shift, i, samples_size;=
+
+=A0=A0=A0 s->waveout =3D NULL;
+=A0=A0=A0 InitializeCritica= lSection( &s->lock );
+=A0=A0=A0 for (i =3D 0; i < NUM_OUT_BUFFERS; i++) {
+=A0=A0=A0=A0=A0= =A0=A0 s->buffers[i].dwUser =3D 0xFFFF;
+=A0=A0=A0 }
+=A0=A0=A0 s-= >buffer_bytes =3D NULL;
+
+=A0=A0=A0 /* compute desired wave outpu= t format */
+=A0=A0=A0 format.wFormatTag=A0=A0=A0=A0=A0 =3D WAVE_FORMAT_= PCM;
+=A0=A0=A0 format.nChannels=A0=A0=A0=A0=A0=A0 =3D as->nchannels;
+=A0= =A0=A0 format.nSamplesPerSec=A0 =3D as->freq;
+=A0=A0=A0 format.nAvgB= ytesPerSec =3D as->freq*as->nchannels;
+
+=A0=A0=A0 s->silen= ce =3D 0;
+
+=A0=A0=A0 switch (as->fmt) {
+=A0=A0=A0=A0=A0=A0=A0 case AUD_FMT_S8:=A0=A0 shift =3D 0; break;
+=A0= =A0=A0=A0=A0=A0=A0 case AUD_FMT_U8:=A0=A0 shift =3D 0; s->silence =3D 0x= 80; break;
+=A0=A0=A0=A0=A0=A0=A0 case AUD_FMT_S16:=A0 shift =3D 1; brea= k;
+=A0=A0=A0=A0=A0=A0=A0 case AUD_FMT_U16:=A0 shift =3D 1; s->silenc= e =3D 0x8000; break;
+=A0=A0=A0=A0=A0=A0=A0 case AUD_FMT_S32:=A0 shift =3D 2; break;
+=A0=A0= =A0=A0=A0=A0=A0 case AUD_FMT_U32:=A0 shift =3D 2; s->silence =3D 0x80000= 000; break;
+=A0=A0=A0=A0=A0=A0=A0 default:
+=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0 fprintf(stderr, "qemu: winaudio: Bad output audio format: %d= \n",
+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 as->fmt);
= +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 return -1;
+=A0=A0=A0 }+
+=A0=A0=A0 format.nAvgBytesPerSec =3D (format.nSamplesPerSec & f= ormat.nChannels) << shift;
+=A0=A0=A0 format.nBlockAlign=A0=A0=A0= =A0 =3D format.nChannels << shift;
+=A0=A0=A0 format.wBitsPerSample=A0 =3D 8 << shift;
+=A0=A0=A0 for= mat.cbSize=A0=A0=A0=A0=A0=A0=A0=A0=A0 =3D 0;
+
+=A0=A0=A0 /* open the= wave out device */
+=A0=A0=A0 result =3D waveOutOpen( &s->waveou= t, WAVE_MAPPER, &format,
+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 (DWORD_PTR) winaudio_out_buffer_done,
+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0 (DWORD_PTR) hw, CALLBACK_FUNCTION);
+=A0=A0=A0 if ( result !=3D MMSY= SERR_NOERROR ) {
+=A0=A0=A0=A0=A0=A0=A0 dump_mmerror( "qemu: winaud= io: waveOutOpen()", result);
+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 ret= urn -1;
+=A0=A0=A0 }
+
+=A0=A0=A0 samples_size=A0=A0=A0 =3D format.nBlockAlign * conf.nb_samp= les;
+=A0=A0=A0 s->buffer_bytes =3D qemu_malloc( NUM_OUT_BUFFERS * sa= mples_size );
+=A0=A0=A0 if (s->buffer_bytes =3D=3D NULL) {
+=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 waveOutClose( s->waveout );
+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 s->waveout =3D NULL;
+=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0 fprintf(stderr, "not enough memory for Windows a= udio buffers\n");
+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 return -1;
= +=A0=A0=A0 }
+
+=A0=A0=A0 for (i =3D 0; i < NUM_OUT_BUFFERS; i++) = {
+=A0=A0=A0=A0=A0=A0=A0 memset( &s->buffers[i], 0, sizeof(s->buffe= rs[i]) );
+=A0=A0=A0=A0=A0=A0=A0 s->buffers[i].lpData=A0=A0=A0=A0=A0= =A0=A0=A0 =3D (LPSTR)(s->buffer_bytes + i*samples_size);
+=A0=A0=A0= =A0=A0=A0=A0 s->buffers[i].dwBufferLength =3D samples_size;
+=A0=A0=A0=A0=A0=A0=A0 s->buffers[i].dwFlags=A0=A0=A0=A0=A0=A0=A0 =3D WH= DR_DONE;
+
+=A0=A0=A0=A0=A0=A0=A0 result =3D waveOutPrepareHeader( s-= >waveout, &s->buffers[i],
+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0 sizeof(s->buffers[i]) );
+=A0=A0=A0=A0=A0=A0=A0 if ( result != =3D MMSYSERR_NOERROR ) {
+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 dump_mmerror("waveOutPrepareHeader(= )", result);
+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 return -1;
+=A0= =A0=A0=A0=A0=A0=A0 }
+=A0=A0=A0 }
+
+#if DEBUG
+=A0=A0=A0 /* Ch= eck the sound device we retrieved */
+=A0=A0=A0 {
+=A0=A0=A0=A0=A0=A0= =A0 WAVEOUTCAPS caps;
+
+=A0=A0=A0=A0=A0=A0=A0 result =3D waveOutGetDevCaps((UINT) s->waveo= ut, &caps, sizeof(caps));
+=A0=A0=A0=A0=A0=A0=A0 if ( result !=3D MM= SYSERR_NOERROR ) {
+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 dump_mmerror("= ;waveOutGetDevCaps()", result);
+=A0=A0=A0=A0=A0=A0=A0 } else
+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 printf("Audio out device: %s\n"= ;, caps.szPname);
+=A0=A0=A0 }
+#endif
+
+=A0=A0=A0 audio_pcm_i= nit_info (&hw->info, as);
+=A0=A0=A0 hw->samples =3D conf.nb_s= amples*2;
+
+=A0=A0=A0 s->write_index =3D 0;
+=A0=A0=A0 s->write_count =3D NUM_OUT_BUFFERS;
+=A0=A0=A0 s->write= _pos=A0=A0 =3D 0;
+=A0=A0=A0 s->write_size=A0 =3D samples_size;
+= =A0=A0=A0 return 0;
+}
+
+
+static int
+winaudio_out_run (HW= VoiceOut *hw)
+{
+=A0=A0=A0 WinAudioOut*=A0 s=A0=A0=A0=A0=A0 =3D (Win= AudioOut*) hw;
+=A0=A0=A0 int=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 played =3D 0;
+=A0=A0=A0 in= t=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 has_buffer;
+=A0=A0=A0 int=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0 live =3D audio_pcm_hw_get_live_out (hw);
+
+=A0=A0= =A0 if (!live) {
+=A0=A0=A0=A0=A0=A0=A0 return 0;
+=A0=A0=A0 }
++=A0=A0=A0 EnterCriticalSection( &s->lock );
+=A0=A0=A0 has_buffer =3D (s->write_count > 0);
+=A0=A0=A0 LeaveCr= iticalSection( &s->lock );
+
+=A0=A0=A0 if (!has_buffer)
+= =A0=A0=A0=A0=A0=A0=A0 return 0;
+
+=A0=A0=A0 while (live > 0) {+=A0=A0=A0=A0=A0=A0=A0 WAVEHDR*=A0=A0=A0=A0=A0 wav_buffer=A0 =3D s->buf= fers + s->write_index;
+=A0=A0=A0=A0=A0=A0=A0 int=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 wav_bytes=A0=A0 = =3D (s->write_size - s->write_pos);
+=A0=A0=A0=A0=A0=A0=A0 int=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0 wav_samples =3D audio_MIN(wav_bytes >> hw= ->info.shift, live);
+=A0=A0=A0=A0=A0=A0=A0 int=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0 hw_samples=A0 =3D audio_MIN(hw->samples - hw->rpos, live);<= br> +=A0=A0=A0=A0=A0=A0=A0 struct st_sample*=A0=A0=A0 src=A0 =3D hw->mix_buf= + hw->rpos;
+=A0=A0=A0=A0=A0=A0=A0 uint8_t*=A0=A0=A0=A0=A0 dst=A0=A0= =A0=A0=A0=A0=A0=A0 =3D (uint8_t*)wav_buffer->lpData + s->write_pos;+
+=A0=A0=A0=A0=A0=A0=A0 if (wav_samples > hw_samples) {
+=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 wav_samples =3D hw_samples;
+=A0=A0=A0=A0=A0=A0=A0 }
+
+=A0=A0=A0=A0=A0=A0=A0 wav_bytes =3D wav_s= amples << hw->info.shift;
+
+=A0=A0=A0=A0=A0=A0=A0 //D("= ;run_out: buffer:%d pos:%d size:%d wsamples:%d wbytes:%d live:%d rpos:%d hw= samples:%d\n", s->write_index,
+=A0=A0=A0=A0=A0=A0=A0 //=A0=A0 s->write_pos, s->write_size, wav_samp= les, wav_bytes, live, hw->rpos, hw->samples);
+=A0=A0=A0=A0=A0=A0= =A0 hw->clip (dst, src, wav_samples);
+=A0=A0=A0=A0=A0=A0=A0 hw->r= pos +=3D wav_samples;
+=A0=A0=A0=A0=A0=A0=A0 if (hw->rpos >=3D hw-= >samples)
+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 hw->rpos -=3D hw->samp= les;
+
+=A0=A0=A0=A0=A0=A0=A0 live=A0=A0=A0=A0=A0=A0=A0=A0 -=3D wav_s= amples;
+=A0=A0=A0=A0=A0=A0=A0 played=A0=A0=A0=A0=A0=A0 +=3D wav_samples= ;
+=A0=A0=A0=A0=A0=A0=A0 s->write_pos +=3D wav_bytes;
+=A0=A0=A0= =A0=A0=A0=A0 if (s->write_pos =3D=3D s->write_size) {
+#if DEBUG_TIMING
+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 int64_t=A0 now=A0 = =3D qemu_get_clock(vm_clock) - start_time;
+=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0 int64_t=A0 diff =3D now - last_time;
+
+=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0 D("run_out: (%7.3f:%7d):waveOutWrite buffer:%d\n", +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 now/1e9, (now-last_time)/1e9, s= ->write_index);
+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 last_time =3D now;=
+#endif
+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 waveOutWrite( s->waveo= ut, wav_buffer, sizeof(*wav_buffer) );
+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0 s->write_pos=A0=A0=A0 =3D 0;
+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 s->write_index +=3D 1;
+=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0 if (s->write_index =3D=3D NUM_OUT_BUFFERS)
+= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 s->write_index =3D 0;
+=
+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 EnterCriticalSection( &s->loc= k );
+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 if (--s->write_count =3D=3D 0= ) {
+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 live =3D 0;
+=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0 }
+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 LeaveCritical= Section( &s->lock );
+=A0=A0=A0=A0=A0=A0=A0 }
+=A0=A0=A0 }
= +=A0=A0=A0 return played;
+}
+
+static int
+winaudio_out_ctl (H= WVoiceOut *hw, int cmd, ...)
+{
+=A0=A0=A0 WinAudioOut*=A0 s =3D (WinAudioOut*) hw;
+
+=A0=A0= =A0 switch (cmd) {
+=A0=A0=A0 case VOICE_ENABLE:
+=A0=A0=A0=A0=A0=A0= =A0 waveOutRestart( s->waveout );
+=A0=A0=A0=A0=A0=A0=A0 break;
+<= br>+=A0=A0=A0 case VOICE_DISABLE:
+=A0=A0=A0=A0=A0=A0=A0 waveOutPause( s= ->waveout );
+=A0=A0=A0=A0=A0=A0=A0 break;
+=A0=A0=A0 }
+=A0=A0=A0 return 0;
+}=
+
+/** AUDIO IN
+ **/
+
+#define=A0 NUM_IN_BUFFERS=A0 2
= +
+typedef struct WinAudioIn {
+=A0=A0=A0 HWVoiceIn=A0=A0=A0=A0=A0=A0= =A0=A0 hw;
+=A0=A0=A0 HWAVEIN=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 wavein;
+=A0=A0=A0 CRITICAL_SECTION=A0 lock;
+=A0=A0=A0 unsigned char*=A0=A0=A0 = buffer_bytes;
+=A0=A0=A0 WAVEHDR=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 buffers[ = NUM_IN_BUFFERS ];
+=A0=A0=A0 int=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0 read_index;
+=A0=A0=A0 int=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= read_count;
+=A0=A0=A0 int=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 re= ad_pos;
+=A0=A0=A0 int=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 read_size;
+} W= inAudioIn;
+
+/* The callback that is called when Windows has finishe= d filling a buffer */
+static void CALLBACK
+winaudio_in_buffer_done = (HWAVEIN hwi, UINT uMsg, DWORD_PTR dwInstance,
+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 D= WORD dwParam1, DWORD dwParam2)
+{
+=A0=A0=A0 WinAudioIn*=A0 s =3D (Wi= nAudioIn*) dwInstance;
+
+=A0=A0=A0 /* Only service "buffer fill= ed" messages */
+=A0=A0=A0 if ( uMsg !=3D WIM_DATA )
+=A0=A0=A0= =A0=A0=A0=A0 return;
+
+=A0=A0=A0 /* Signal that we are done playing a buffer */
+=A0=A0= =A0 EnterCriticalSection( &s->lock );
+=A0=A0=A0 if (s->read_c= ount < NUM_IN_BUFFERS)
+=A0=A0=A0=A0=A0=A0=A0 s->read_count +=3D 1= ;
+=A0=A0=A0 LeaveCriticalSection( &s->lock );
+}
+
+static void
+winaudio_in_fini (HWVoiceIn *hw)
+{
+=A0= =A0=A0 WinAudioIn*=A0 s =3D (WinAudioIn*) hw;
+=A0=A0=A0 int=A0=A0=A0=A0= =A0=A0=A0=A0=A0 i;
+
+=A0=A0=A0 if (s->wavein) {
+=A0=A0=A0=A0= =A0=A0=A0 waveInReset(s->wavein);
+=A0=A0=A0=A0=A0=A0=A0 s->wavein= =3D 0;
+=A0=A0=A0 }
+
+=A0=A0=A0 for ( i=3D0; i<NUM_OUT_BUFFERS; ++i ) {<= br>+=A0=A0=A0=A0=A0=A0=A0 if ( s->buffers[i].dwUser !=3D 0xFFFF ) {
+= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 waveInUnprepareHeader(
+=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 s->wavein, &s->buffers[i], size= of(s->buffers[i]) );
+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 s->buffers[i].dwUser =3D = 0xFFFF;
+=A0=A0=A0=A0=A0=A0=A0 }
+=A0=A0=A0 }
+
+=A0=A0=A0 if (= s->buffer_bytes !=3D NULL) {
+=A0=A0=A0=A0=A0=A0=A0 qemu_free(s->b= uffer_bytes);
+=A0=A0=A0=A0=A0=A0=A0 s->buffer_bytes =3D NULL;
+= =A0=A0=A0 }
+
+=A0=A0=A0 if (s->wavein) {
+=A0=A0=A0=A0=A0=A0=A0 waveInClose(s->= wavein);
+=A0=A0=A0=A0=A0=A0=A0 s->wavein =3D NULL;
+=A0=A0=A0 }+}
+
+
+static int
+winaudio_in_init (HWVoiceIn *hw, struct a= udsettings *as)
+{
+=A0=A0=A0 WinAudioIn*=A0=A0 s =3D (WinAudioIn*) h= w;
+=A0=A0=A0 MMRESULT=A0=A0=A0=A0=A0 result;
+=A0=A0=A0 WAVEFORMATEX=A0 fo= rmat;
+=A0=A0=A0 int=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 shift, i, samples_siz= e;
+
+=A0=A0=A0 s->wavein =3D NULL;
+=A0=A0=A0 InitializeCritic= alSection( &s->lock );
+=A0=A0=A0 for (i =3D 0; i < NUM_OUT_BU= FFERS; i++) {
+=A0=A0=A0=A0=A0=A0=A0 s->buffers[i].dwUser =3D 0xFFFF;
+=A0=A0=A0 }<= br>+=A0=A0=A0 s->buffer_bytes =3D NULL;
+
+=A0=A0=A0 /* compute de= sired wave input format */
+=A0=A0=A0 format.wFormatTag=A0=A0=A0=A0=A0 = =3D WAVE_FORMAT_PCM;
+=A0=A0=A0 format.nChannels=A0=A0=A0=A0=A0=A0 =3D a= s->nchannels;
+=A0=A0=A0 format.nSamplesPerSec=A0 =3D as->freq;
+=A0=A0=A0 format.n= AvgBytesPerSec =3D as->freq*as->nchannels;
+
+=A0=A0=A0 switch = (as->fmt) {
+=A0=A0=A0=A0=A0=A0=A0 case AUD_FMT_S8:=A0=A0 shift =3D 0= ; break;
+=A0=A0=A0=A0=A0=A0=A0 case AUD_FMT_U8:=A0=A0 shift =3D 0; brea= k;
+=A0=A0=A0=A0=A0=A0=A0 case AUD_FMT_S16:=A0 shift =3D 1; break;
+=A0=A0= =A0=A0=A0=A0=A0 case AUD_FMT_U16:=A0 shift =3D 1; break;
+=A0=A0=A0=A0= =A0=A0=A0 case AUD_FMT_S32:=A0 shift =3D 2; break;
+=A0=A0=A0=A0=A0=A0= =A0 case AUD_FMT_U32:=A0 shift =3D 2; break;
+=A0=A0=A0=A0=A0=A0=A0 defa= ult:
+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 fprintf(stderr, "qemu: wina= udio: Bad input audio format: %d\n",
+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 as->fmt);
= +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 return -1;
+=A0=A0=A0 }
+
+=A0= =A0=A0 format.nAvgBytesPerSec =3D (format.nSamplesPerSec * format.nChannels= ) << shift;
+=A0=A0=A0 format.nBlockAlign=A0=A0=A0=A0 =3D format.n= Channels << shift;
+=A0=A0=A0 format.wBitsPerSample=A0 =3D 8 << shift;
+=A0=A0=A0 for= mat.cbSize=A0=A0=A0=A0=A0=A0=A0=A0=A0 =3D 0;
+
+=A0=A0=A0 /* open the= wave in device */
+=A0=A0=A0 result =3D waveInOpen( &s->wavein, = WAVE_MAPPER, &format,
+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0 (DWORD_PTR)winaudio_in_buffer_done, (DWORD_PTR)= hw,
+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 C= ALLBACK_FUNCTION);
+=A0=A0=A0 if ( result !=3D MMSYSERR_NOERROR ) {
+= =A0=A0=A0=A0=A0=A0=A0 dump_mmerror( "qemu: winaudio: waveInOpen()"= ;, result);
+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 return -1;
+=A0=A0=A0 = }
+
+=A0=A0=A0 samples_size=A0=A0=A0 =3D format.nBlockAlign * conf.nb= _samples;
+=A0=A0=A0 s->buffer_bytes =3D qemu_malloc( NUM_IN_BUFFERS * samples_siz= e );
+=A0=A0=A0 if (s->buffer_bytes =3D=3D NULL) {
+=A0=A0=A0=A0= =A0=A0=A0 waveInClose( s->wavein );
+=A0=A0=A0=A0=A0=A0=A0 s->wave= in =3D NULL;
+=A0=A0=A0=A0=A0=A0=A0 fprintf(stderr, "not enough mem= ory for Windows audio buffers\n");
+=A0=A0=A0=A0=A0=A0=A0 return -1;
+=A0=A0=A0 }
+
+=A0=A0=A0 for (i= =3D 0; i < NUM_IN_BUFFERS; i++) {
+=A0=A0=A0=A0=A0=A0=A0 memset( &am= p;s->buffers[i], 0, sizeof(s->buffers[i]) );
+=A0=A0=A0=A0=A0=A0= =A0 s->buffers[i].lpData=A0=A0=A0=A0=A0=A0=A0=A0 =3D (LPSTR)(s->buffe= r_bytes + i*samples_size);
+=A0=A0=A0=A0=A0=A0=A0 s->buffers[i].dwBufferLength =3D samples_size;+=A0=A0=A0=A0=A0=A0=A0 s->buffers[i].dwFlags=A0=A0=A0=A0=A0=A0=A0 =3D W= HDR_DONE;
+
+=A0=A0=A0=A0=A0=A0=A0 result =3D waveInPrepareHeader( s-= >wavein, &s->buffers[i],
+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 sizeof(s->buffers= [i]) );
+=A0=A0=A0=A0=A0=A0=A0 if ( result !=3D MMSYSERR_NOERROR ) {
+=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0 dump_mmerror("waveInPrepareHeader()", re= sult);
+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 return -1;
+=A0=A0=A0=A0=A0= =A0=A0 }
+
+=A0=A0=A0=A0=A0=A0=A0 result =3D waveInAddBuffer( s->w= avein, &s->buffers[i],
+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0 sizeof(s->buffers[i]) );
+=A0=A0=A0=A0=A0= =A0=A0 if ( result !=3D MMSYSERR_NOERROR ) {
+=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0 dump_mmerror("waveInAddBuffer()", result);
+=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0 return -1;
+=A0=A0=A0=A0=A0=A0=A0 }
+=A0=A0=A0 }
+
+#if DEBUG
+=A0=A0=A0 /* Check the sound device we = retrieved */
+=A0=A0=A0 {
+=A0=A0=A0=A0=A0=A0=A0 WAVEINCAPS caps;
= +
+=A0=A0=A0=A0=A0=A0=A0 result =3D waveInGetDevCaps((UINT) s->wavein= , &caps, sizeof(caps));
+=A0=A0=A0=A0=A0=A0=A0 if ( result !=3D MMSY= SERR_NOERROR ) {
+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 dump_mmerror("waveInGetDevCaps()&qu= ot;, result);
+=A0=A0=A0=A0=A0=A0=A0 } else
+=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0 printf("Audio in device: %s\n", caps.szPname);
+=A0= =A0=A0 }
+#endif
+
+=A0=A0=A0 audio_pcm_init_info (&hw->inf= o, as);
+=A0=A0=A0 hw->samples =3D conf.nb_samples*2;
+
+=A0=A0=A0 s->r= ead_index =3D 0;
+=A0=A0=A0 s->read_count =3D 0;
+=A0=A0=A0 s->= read_pos=A0=A0 =3D 0;
+=A0=A0=A0 s->read_size=A0 =3D samples_size;+=A0=A0=A0 return 0;
+}
+
+
+/* report the number of captured = samples to the audio subsystem */
+static int
+winaudio_in_run (HWVoiceIn *hw)
+{
+=A0=A0=A0 WinAudi= oIn*=A0 s=A0=A0=A0=A0=A0=A0=A0 =3D (WinAudioIn*) hw;
+=A0=A0=A0 int=A0= =A0=A0=A0=A0=A0=A0=A0=A0 captured =3D 0;
+=A0=A0=A0 int=A0=A0=A0=A0=A0= =A0=A0=A0=A0 has_buffer;
+=A0=A0=A0 int=A0=A0=A0=A0=A0=A0=A0=A0=A0 live = =3D hw->samples - hw->total_samples_captured;
+
+=A0=A0=A0 if (!live) {
+=A0=A0=A0=A0=A0=A0=A0 return 0;
+=A0=A0= =A0 }
+
+=A0=A0=A0 EnterCriticalSection( &s->lock );
+=A0= =A0=A0 has_buffer =3D (s->read_count > 0);
+=A0=A0=A0 LeaveCritica= lSection( &s->lock );
+
+=A0=A0=A0 if (!has_buffer)
+=A0=A0=A0=A0=A0=A0=A0 return 0;
+
+=A0=A0=A0 while (live > 0) {+=A0=A0=A0=A0=A0=A0=A0 WAVEHDR*=A0=A0=A0=A0=A0 wav_buffer=A0 =3D s->bu= ffers + s->read_index;
+=A0=A0=A0=A0=A0=A0=A0 int=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0 wav_bytes=A0=A0 =3D (s->read_size - s->read_pos);
+= =A0=A0=A0=A0=A0=A0=A0 int=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 wav_samples =3D aud= io_MIN(wav_bytes >> hw->info.shift, live);
+=A0=A0=A0=A0=A0=A0=A0 int=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 hw_samples=A0 =3D = audio_MIN(hw->samples - hw->wpos, live);
+=A0=A0=A0=A0=A0=A0=A0 st= ruct st_sample*=A0 dst=A0=A0=A0 =3D hw->conv_buf + hw->wpos;
+=A0= =A0=A0=A0=A0=A0=A0 uint8_t*=A0=A0=A0=A0=A0 src=A0=A0=A0=A0=A0=A0=A0=A0 =3D = (uint8_t*)wav_buffer->lpData + s->read_pos;
+
+=A0=A0=A0=A0=A0=A0=A0 if (wav_samples > hw_samples) {
+=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0 wav_samples =3D hw_samples;
+=A0=A0=A0=A0=A0= =A0=A0 }
+
+=A0=A0=A0=A0=A0=A0=A0 wav_bytes =3D wav_samples << = hw->info.shift;
+
+=A0=A0=A0=A0=A0=A0=A0 D("%s: buffer:%d pos= :%d size:%d wsamples:%d wbytes:%d live:%d wpos:%d hwsamples:%d\n",
+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 __FUNCTION__, s->read_index, s->read_= pos, s->read_size, wav_samples, wav_bytes, live,
+=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0 hw->wpos, hw->samples);
+
+=A0=A0=A0=A0=A0=A0=A0 h= w->conv(dst, src, wav_samples, &nominal_volume);
+
+=A0=A0=A0=A0=A0=A0=A0 hw->wpos +=3D wav_samples;
+=A0=A0=A0=A0= =A0=A0=A0 if (hw->wpos >=3D hw->samples)
+=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0 hw->wpos -=3D hw->samples;
+
+=A0=A0=A0=A0=A0=A0= =A0 live=A0=A0=A0=A0=A0=A0=A0 -=3D wav_samples;
+=A0=A0=A0=A0=A0=A0=A0 c= aptured=A0=A0=A0 +=3D wav_samples;
+=A0=A0=A0=A0=A0=A0=A0 s->read_pos +=3D wav_bytes;
+=A0=A0=A0=A0=A0= =A0=A0 if (s->read_pos =3D=3D s->read_size) {
+=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0 s->read_pos=A0=A0=A0 =3D 0;
+=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0 s->read_index +=3D 1;
+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 if= (s->read_index =3D=3D NUM_IN_BUFFERS)
+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 s->read_index =3D 0;
+=
+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 waveInAddBuffer( s->wavein, wav_b= uffer, sizeof(*wav_buffer) );
+
+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 En= terCriticalSection( &s->lock );
+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0 if (--s->read_count =3D=3D 0) {
+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 live =3D 0;
+=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0 }
+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 LeaveCritical= Section( &s->lock );
+=A0=A0=A0=A0=A0=A0=A0 }
+=A0=A0=A0 }
= +=A0=A0=A0 return=A0 captured;
+}
+
+
+static int
+winaudio_= in_read (SWVoiceIn *sw, void *buf, int len)
+{
+=A0=A0=A0 int=A0 ret =3D audio_pcm_sw_read (sw, buf, len);
+=A0= =A0=A0 if (ret > 0)
+=A0=A0=A0=A0=A0=A0=A0 D("%s: (%d) returned = %d\n", __FUNCTION__, len, ret);
+=A0=A0=A0 return ret;
+}
++
+static int
+winaudio_in_ctl (HWVoiceIn *hw, int cmd, ...)
+{
+=A0=A0=A0 WinAudioIn*=A0 s =3D (WinAudioIn*) hw;
+
+=A0=A0=A0 = switch (cmd) {
+=A0=A0=A0 case VOICE_ENABLE:
+=A0=A0=A0=A0=A0=A0=A0 D= ("%s: enable audio in\n", __FUNCTION__);
+=A0=A0=A0=A0=A0=A0= =A0 waveInStart( s->wavein );
+=A0=A0=A0=A0=A0=A0=A0 break;
+
+=A0=A0=A0 case VOICE_DISABLE:
+=A0=A0=A0=A0=A0=A0=A0 D("%s: d= isable audio in\n", __FUNCTION__);
+=A0=A0=A0=A0=A0=A0=A0 waveInSto= p( s->wavein );
+=A0=A0=A0=A0=A0=A0=A0 break;
+=A0=A0=A0 }
+=A0= =A0=A0 return 0;
+}
+
+/** AUDIO STATE
+ **/
+
+typedef struct WinAudioState {
+=A0=A0=A0 int=A0 dummy;
+} WinA= udioState;
+
+static WinAudioState=A0 g_winaudio;
+
+static voi= d*
+winaudio_init(void)
+{
+=A0=A0=A0 WinAudioState*=A0 s =3D &= ;g_winaudio;
+
+#if DEBUG_TIMING
+=A0=A0=A0 start_time =3D qemu_get_clock(vm_clock= );
+=A0=A0=A0 last_time=A0 =3D 0;
+#endif
+
+=A0=A0=A0 return s= ;
+}
+
+
+static void
+winaudio_fini (void *opaque)
+{+}
+
+static struct audio_option winaudio_options[] =3D {
+=A0=A0=A0 {"SAMPLES", AUD_OPT_INT, &conf.nb_samples,
+=A0= =A0=A0=A0 "Size of Windows audio buffer in samples", NULL, 0},+=A0=A0=A0 {NULL, 0, NULL, NULL, NULL, 0}
+};
+
+static struct au= dio_pcm_ops winaudio_pcm_ops =3D {
+=A0=A0=A0 winaudio_out_init,
+=A0=A0=A0 winaudio_out_fini,
+=A0=A0= =A0 winaudio_out_run,
+=A0=A0=A0 winaudio_out_write,
+=A0=A0=A0 winau= dio_out_ctl,
+
+=A0=A0=A0 winaudio_in_init,
+=A0=A0=A0 winaudio_in= _fini,
+=A0=A0=A0 winaudio_in_run,
+=A0=A0=A0 winaudio_in_read,
+=A0=A0=A0 winaudio_in_ctl
+};
+
+struct audio_driver winaudio_aud= io_driver =3D {
+=A0=A0=A0 INIT_FIELD (name=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0 =3D ) "winaudio",
+=A0=A0=A0 INIT_FIELD (descr=A0=A0=A0=A0= =A0=A0=A0=A0=A0 =3D ) "Windows wave audio",
+=A0=A0=A0 INIT_FI= ELD (options=A0=A0=A0=A0=A0=A0=A0 =3D ) winaudio_options,
+=A0=A0=A0 INIT_FIELD (init=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 =3D ) winaudio_in= it,
+=A0=A0=A0 INIT_FIELD (fini=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 =3D ) wina= udio_fini,
+=A0=A0=A0 INIT_FIELD (pcm_ops=A0=A0=A0=A0=A0=A0=A0 =3D ) &am= p;winaudio_pcm_ops,
+=A0=A0=A0 INIT_FIELD (can_be_default =3D ) 1,
+= =A0=A0=A0 INIT_FIELD (max_voices_out =3D ) 1,
+=A0=A0=A0 INIT_FIELD (max_voices_in=A0 =3D ) 1,
+=A0=A0=A0 INIT_FIELD (= voice_size_out =3D ) sizeof (WinAudioOut),
+=A0=A0=A0 INIT_FIELD (voice_= size_in=A0 =3D ) sizeof (WinAudioIn)
+};
diff --git a/configure b/con= figure
index 89e7f53..3ddb138 100755
--- a/configure
+++ b/configure
@@ -219,14 +219,16 @@ OS_CFLAGS=3D&qu= ot;-mno-cygwin"
=A0if [ "$cpu" =3D "i386" ] ; t= hen
=A0=A0=A0=A0 kqemu=3D"yes"
=A0fi
-audio_possible_dri= vers=3D"sdl"
+audio_drv_list=3D"winaudio"
+audio_possible_drivers=3D"w= inaudio sdl"
=A0;;
=A0MINGW32*)
=A0mingw32=3D"yes"<= br>=A0if [ "$cpu" =3D "i386" ] ; then
=A0=A0=A0=A0 k= qemu=3D"yes"
=A0fi
-audio_possible_drivers=3D"dsound sdl fmod"
+audio_dr= v_list=3Dwinaudio
+audio_possible_drivers=3D"dsound winaudio sdl fm= od"
=A0;;
=A0GNU/kFreeBSD)
=A0audio_drv_list=3D"oss"= ;
@@ -1033,7 +1035,7 @@ for drv in $audio_drv_list; do
=A0=A0=A0=A0=A0=A0=A0=A0 "pa_simple *s =3D NULL; pa_simple_free(s); re= turn 0;"
=A0=A0=A0=A0 ;;
=A0
-=A0=A0=A0 oss|sdl|core|wav|dsou= nd)
+=A0=A0=A0 oss|sdl|core|wav|dsound|winaudio)
=A0=A0=A0=A0 # XXX: = Probes for CoreAudio, DirectSound, SDL(?)
=A0=A0=A0=A0 ;;
=A0
--
1.5.4.3


--001636c5a435555d34046c07f87e--