qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH] Add WinWave-based audio backend to Windows QEMU


From: malc
Subject: Re: [Qemu-devel] [PATCH] Add WinWave-based audio backend to Windows QEMU builds
Date: Thu, 11 Jun 2009 05:35:31 +0400 (MSD)

On Thu, 11 Jun 2009, David Turner wrote:

Thanks for submitting this.

> Sorry, here's the patch inlined:

And it was mangled beyond recognition by your mailer, but nevermind that
for now, since the attached version applies cleanly.

Stylistic nit, the thing is terribly inconsistent, it's neither in QEMU
nor in audio/* style. Personally I would have preferred it to look like
the rest of audio, i.e.:

func/controlflow<space>(<no space>...<no space>)

Or if you find it more acceptable, per QEMU coding style:

func<no space>(<no space>...<no space>)
controlflow<space>(<no space>...<no space>)

> 
> >>From 4e061a312b5f6575462e3fa50c7df20788e5f95c Mon Sep 17 00:00:00 2001
> From: digit <address@hidden>
> 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.

[..snip..]

> +/* XP works well with 4, but Vista struggles with anything less than 8 */
> +#define  NUM_OUT_BUFFERS  8  /* must be at least 2 */

I wonder how Vista works with dsound, okayish, struggles?

> +
> +/** 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

1. It should be unconditional
2. switch (error) {
   case ...:
   default: return;
   }
   fprintf (...)
3. The lines are extra long

> +
> +
> +/** 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;
> +    }
> +

It appears that s->silence is never used.

> +    format.nAvgBytesPerSec = (format.nSamplesPerSec & format.nChannels) <<
> shift;

~format.nChannels was meant perhaps?

> +    format.nBlockAlign     = format.nChannels << shift;
> +    format.wBitsPerSample  = 8 << shift;

[Just checking - is wBitsPerSample is really sample or frame? Only ALSA, to the
 best of my knowledge makes clear distinction between the two]

> +    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;
> +    }

Indentation is off here.

> +
> +    samples_size    = format.nBlockAlign * conf.nb_samples;
> +    s->buffer_bytes = qemu_malloc( NUM_OUT_BUFFERS * samples_size );

audio_calloc ought to be used here...

> +    if (s->buffer_bytes == NULL) {
> +            waveOutClose( s->waveout );
> +            s->waveout = NULL;
> +            fprintf(stderr, "not enough memory for Windows audio
> buffers\n");
> +            return -1;
> +    }

Whose return value is indeed ought to be checked for NULL, but no
message is necessary. Checks in audio_calloc once have proven to be
useful when some FreeBSD returned bogus number of fragments(0) and
consequently attempt was made to allocate 0 bytes for oss's pcm_buf.

> +
> +    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;

This one I don't get, why is it unconditionally multiplied by 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;

Asterisks are c++isplaced.

> +
> +        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;

Indentation is off.

> +        }
> +    }
> +
> +    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;

Here too.

> +    }
> +
> +    samples_size    = format.nBlockAlign * conf.nb_samples;
> +    s->buffer_bytes = qemu_malloc( NUM_IN_BUFFERS * samples_size );

audio_calloc

> +    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;

Again.. why?

> +
> +    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(?)
>      ;;
> 
> 

-- 
mailto:address@hidden




reply via email to

[Prev in Thread] Current Thread [Next in Thread]