aboutsummaryrefslogtreecommitdiffstats
path: root/audio/winaudio.c
diff options
context:
space:
mode:
Diffstat (limited to 'audio/winaudio.c')
-rw-r--r--audio/winaudio.c666
1 files changed, 0 insertions, 666 deletions
diff --git a/audio/winaudio.c b/audio/winaudio.c
deleted file mode 100644
index 6e8daef..0000000
--- a/audio/winaudio.c
+++ /dev/null
@@ -1,666 +0,0 @@
-/*
- * 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.
- */
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#include <mmsystem.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
-
-#if 1
-# define D_ACTIVE 1
-#else
-# define D_ACTIVE DEBUG
-#endif
-
-#if DEBUG
-# define D(...) do{ if (D_ACTIVE) printf(__VA_ARGS__); } while(0)
-#else
-# define D(...) ((void)0)
-#endif
-
-static struct {
- int nb_samples;
-} conf = {
- 1024
-};
-
-#if DEBUG
-int64_t start_time;
-int64_t last_time;
-#endif
-
-#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 Win32 callback that is called when a buffer has finished playing */
-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, audsettings_t *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;
- 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) {
- 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);
- st_sample_t* 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 xxDEBUG
- 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 Win32 callback that is called when a buffer has finished playing */
-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 done playing" 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;
- //D(".%c",s->read_count + '0'); fflush(stdout);
- 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, audsettings_t *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;
- 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) {
-#if 0
- static int counter;
- if (++counter == 100) {
- D("0"); fflush(stdout);
- counter = 0;
- }
-#endif
- return 0;
- }
-
- EnterCriticalSection( &s->lock );
- has_buffer = (s->read_count > 0);
- LeaveCriticalSection( &s->lock );
-
- if (has_buffer > 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);
- st_sample_t* 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
- 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 win_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)
-};