1/*
2 * QEMU "simple" Windows audio driver
3 *
4 * Copyright (c) 2007 The Android Open Source Project
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24#define WIN32_LEAN_AND_MEAN
25#include <windows.h>
26#include <mmsystem.h>
27
28#define AUDIO_CAP "winaudio"
29#include "audio_int.h"
30
31/* define DEBUG to 1 to dump audio debugging info at runtime to stderr */
32#define  DEBUG  0
33
34#if 1
35#  define  D_ACTIVE    1
36#else
37#  define  D_ACTIVE  DEBUG
38#endif
39
40#if DEBUG
41#  define  D(...)   do{ if (D_ACTIVE) printf(__VA_ARGS__); } while(0)
42#else
43#  define  D(...)   ((void)0)
44#endif
45
46static struct {
47    int nb_samples;
48} conf = {
49    1024
50};
51
52#if DEBUG
53int64_t  start_time;
54int64_t  last_time;
55#endif
56
57#define  NUM_OUT_BUFFERS  8  /* must be at least 2 */
58
59/** COMMON UTILITIES
60 **/
61
62#if DEBUG
63static void
64dump_mmerror( const char*  func, MMRESULT  error )
65{
66    const char*  reason = NULL;
67
68    fprintf(stderr, "%s returned error: ", func);
69    switch (error) {
70            case MMSYSERR_ALLOCATED:   reason="specified resource is already allocated"; break;
71            case MMSYSERR_BADDEVICEID: reason="bad device id"; break;
72            case MMSYSERR_NODRIVER:    reason="no driver is present"; break;
73            case MMSYSERR_NOMEM:       reason="unable to allocate or lock memory"; break;
74            case WAVERR_BADFORMAT:     reason="unsupported waveform-audio format"; break;
75            case WAVERR_SYNC:          reason="device is synchronous"; break;
76            default:
77                    fprintf(stderr, "unknown(%d)\n", error);
78    }
79    if (reason)
80            fprintf(stderr, "%s\n", reason);
81}
82#else
83#  define  dump_mmerror(func,error)  ((void)0)
84#endif
85
86
87/** AUDIO OUT
88 **/
89
90typedef struct WinAudioOut {
91    HWVoiceOut        hw;
92    HWAVEOUT          waveout;
93    int               silence;
94    CRITICAL_SECTION  lock;
95    unsigned char*    buffer_bytes;
96    WAVEHDR           buffers[ NUM_OUT_BUFFERS ];
97    int               write_index;   /* starting first writable buffer      */
98    int               write_count;   /* available writable buffers count    */
99    int               write_pos;     /* position in current writable buffer */
100    int               write_size;    /* size in bytes of each buffer        */
101} WinAudioOut;
102
103/* The Win32 callback that is called when a buffer has finished playing */
104static void CALLBACK
105winaudio_out_buffer_done (HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance,
106			              DWORD dwParam1, DWORD dwParam2)
107{
108    WinAudioOut*  s = (WinAudioOut*) dwInstance;
109
110    /* Only service "buffer done playing" messages */
111    if ( uMsg != WOM_DONE )
112            return;
113
114    /* Signal that we are done playing a buffer */
115    EnterCriticalSection( &s->lock );
116    if (s->write_count < NUM_OUT_BUFFERS)
117        s->write_count += 1;
118    LeaveCriticalSection( &s->lock );
119}
120
121static int
122winaudio_out_write (SWVoiceOut *sw, void *buf, int len)
123{
124    return audio_pcm_sw_write (sw, buf, len);
125}
126
127static void
128winaudio_out_fini (HWVoiceOut *hw)
129{
130    WinAudioOut*  s = (WinAudioOut*) hw;
131    int           i;
132
133    if (s->waveout) {
134        waveOutReset(s->waveout);
135        s->waveout = 0;
136    }
137
138    for ( i=0; i<NUM_OUT_BUFFERS; ++i ) {
139        if ( s->buffers[i].dwUser != 0xFFFF ) {
140            waveOutUnprepareHeader(
141                s->waveout, &s->buffers[i], sizeof(s->buffers[i]) );
142                s->buffers[i].dwUser = 0xFFFF;
143        }
144    }
145
146    if (s->buffer_bytes != NULL) {
147        g_free(s->buffer_bytes);
148        s->buffer_bytes = NULL;
149    }
150
151    if (s->waveout) {
152        waveOutClose(s->waveout);
153        s->waveout = NULL;
154    }
155}
156
157
158static int
159winaudio_out_init (HWVoiceOut *hw, struct audsettings *as)
160{
161    WinAudioOut*   s = (WinAudioOut*) hw;
162    MMRESULT       result;
163    WAVEFORMATEX   format;
164    int            shift, i, samples_size;
165
166    s->waveout = NULL;
167    InitializeCriticalSection( &s->lock );
168    for (i = 0; i < NUM_OUT_BUFFERS; i++) {
169            s->buffers[i].dwUser = 0xFFFF;
170    }
171    s->buffer_bytes = NULL;
172
173    /* compute desired wave output format */
174    format.wFormatTag      = WAVE_FORMAT_PCM;
175    format.nChannels       = as->nchannels;
176    format.nSamplesPerSec  = as->freq;
177    format.nAvgBytesPerSec = as->freq*as->nchannels;
178
179    s->silence = 0;
180
181    switch (as->fmt) {
182        case AUD_FMT_S8:   shift = 0; break;
183        case AUD_FMT_U8:   shift = 0; s->silence = 0x80; break;
184        case AUD_FMT_S16:  shift = 1; break;
185        case AUD_FMT_U16:  shift = 1; s->silence = 0x8000; break;
186        default:
187            fprintf(stderr, "qemu: winaudio: Bad output audio format: %d\n",
188                    as->fmt);
189                return -1;
190    }
191
192    format.nAvgBytesPerSec = (format.nSamplesPerSec & format.nChannels) << shift;
193    format.nBlockAlign     = format.nChannels << shift;
194    format.wBitsPerSample  = 8 << shift;
195    format.cbSize          = 0;
196
197    /* open the wave out device */
198    result = waveOutOpen( &s->waveout, WAVE_MAPPER, &format,
199                                  (DWORD_PTR)winaudio_out_buffer_done, (DWORD_PTR) hw,
200                                              CALLBACK_FUNCTION);
201    if ( result != MMSYSERR_NOERROR ) {
202        dump_mmerror( "qemu: winaudio: waveOutOpen()", result);
203            return -1;
204    }
205
206    samples_size    = format.nBlockAlign * conf.nb_samples;
207    s->buffer_bytes = g_malloc( NUM_OUT_BUFFERS * samples_size );
208    if (s->buffer_bytes == NULL) {
209            waveOutClose( s->waveout );
210            s->waveout = NULL;
211            fprintf(stderr, "not enough memory for Windows audio buffers\n");
212            return -1;
213    }
214
215    for (i = 0; i < NUM_OUT_BUFFERS; i++) {
216        memset( &s->buffers[i], 0, sizeof(s->buffers[i]) );
217        s->buffers[i].lpData         = (LPSTR)(s->buffer_bytes + i*samples_size);
218        s->buffers[i].dwBufferLength = samples_size;
219        s->buffers[i].dwFlags        = WHDR_DONE;
220
221        result = waveOutPrepareHeader( s->waveout, &s->buffers[i],
222                               sizeof(s->buffers[i]) );
223        if ( result != MMSYSERR_NOERROR ) {
224            dump_mmerror("waveOutPrepareHeader()", result);
225            return -1;
226        }
227    }
228
229#if DEBUG
230    /* Check the sound device we retrieved */
231    {
232        WAVEOUTCAPS caps;
233
234        result = waveOutGetDevCaps((UINT) s->waveout, &caps, sizeof(caps));
235        if ( result != MMSYSERR_NOERROR ) {
236            dump_mmerror("waveOutGetDevCaps()", result);
237        } else
238            printf("Audio out device: %s\n", caps.szPname);
239    }
240#endif
241
242    audio_pcm_init_info (&hw->info, as);
243    hw->samples = conf.nb_samples*2;
244
245    s->write_index = 0;
246    s->write_count = NUM_OUT_BUFFERS;
247    s->write_pos   = 0;
248    s->write_size  = samples_size;
249    return 0;
250}
251
252
253static int
254winaudio_out_run (HWVoiceOut *hw, int live)
255{
256    WinAudioOut*  s      = (WinAudioOut*) hw;
257    int           played = 0;
258    int           has_buffer;
259
260    if (!live) {
261        return 0;
262    }
263
264    EnterCriticalSection( &s->lock );
265    has_buffer = (s->write_count > 0);
266    LeaveCriticalSection( &s->lock );
267
268    if (has_buffer) {
269        while (live > 0) {
270            WAVEHDR*      wav_buffer  = s->buffers + s->write_index;
271            int           wav_bytes   = (s->write_size - s->write_pos);
272            int           wav_samples = audio_MIN(wav_bytes >> hw->info.shift, live);
273            int           hw_samples  = audio_MIN(hw->samples - hw->rpos, live);
274            struct st_sample*  src         = hw->mix_buf + hw->rpos;
275            uint8_t*      dst         = (uint8_t*)wav_buffer->lpData + s->write_pos;
276
277            if (wav_samples > hw_samples) {
278                    wav_samples = hw_samples;
279            }
280
281            wav_bytes = wav_samples << hw->info.shift;
282
283            //D("run_out: buffer:%d pos:%d size:%d wsamples:%d wbytes:%d live:%d rpos:%d hwsamples:%d\n", s->write_index,
284            //   s->write_pos, s->write_size, wav_samples, wav_bytes, live, hw->rpos, hw->samples);
285            hw->clip (dst, src, wav_samples);
286            hw->rpos += wav_samples;
287            if (hw->rpos >= hw->samples)
288                    hw->rpos -= hw->samples;
289
290            live         -= wav_samples;
291            played       += wav_samples;
292            s->write_pos += wav_bytes;
293            if (s->write_pos == s->write_size) {
294#if xxDEBUG
295                int64_t  now  = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - start_time;
296                int64_t  diff = now - last_time;
297
298                D("run_out: (%7.3f:%7d):waveOutWrite buffer:%d\n",
299                   now/1e9, (now-last_time)/1e9, s->write_index);
300                last_time = now;
301#endif
302                waveOutWrite( s->waveout, wav_buffer, sizeof(*wav_buffer) );
303                s->write_pos    = 0;
304                s->write_index += 1;
305                if (s->write_index == NUM_OUT_BUFFERS)
306                    s->write_index = 0;
307
308                EnterCriticalSection( &s->lock );
309                if (--s->write_count == 0) {
310                        live = 0;
311                }
312                LeaveCriticalSection( &s->lock );
313            }
314        }
315
316    }
317    return played;
318}
319
320static int
321winaudio_out_ctl (HWVoiceOut *hw, int cmd, ...)
322{
323    WinAudioOut*  s = (WinAudioOut*) hw;
324
325    switch (cmd) {
326    case VOICE_ENABLE:
327        waveOutRestart( s->waveout );
328        break;
329
330    case VOICE_DISABLE:
331        waveOutPause( s->waveout );
332        break;
333    }
334    return 0;
335}
336
337/** AUDIO IN
338 **/
339
340#define  NUM_IN_BUFFERS  2
341
342typedef struct WinAudioIn {
343    HWVoiceIn         hw;
344    HWAVEIN           wavein;
345    CRITICAL_SECTION  lock;
346    unsigned char*    buffer_bytes;
347    WAVEHDR           buffers[ NUM_IN_BUFFERS ];
348    int               read_index;
349    int               read_count;
350    int               read_pos;
351    int               read_size;
352} WinAudioIn;
353
354/* The Win32 callback that is called when a buffer has finished playing */
355static void CALLBACK
356winaudio_in_buffer_done (HWAVEIN hwi, UINT uMsg, DWORD_PTR dwInstance,
357                         DWORD dwParam1, DWORD dwParam2)
358{
359    WinAudioIn*  s = (WinAudioIn*) dwInstance;
360
361    /* Only service "buffer done playing" messages */
362    if ( uMsg != WIM_DATA )
363        return;
364
365    /* Signal that we are done playing a buffer */
366    EnterCriticalSection( &s->lock );
367    if (s->read_count < NUM_IN_BUFFERS)
368        s->read_count += 1;
369        //D(".%c",s->read_count + '0'); fflush(stdout);
370    LeaveCriticalSection( &s->lock );
371}
372
373static void
374winaudio_in_fini (HWVoiceIn *hw)
375{
376    WinAudioIn*  s = (WinAudioIn*) hw;
377    int           i;
378
379    if (s->wavein) {
380        waveInReset(s->wavein);
381            s->wavein = 0;
382    }
383
384    for ( i=0; i<NUM_IN_BUFFERS; ++i ) {
385        if ( s->buffers[i].dwUser != 0xFFFF ) {
386            waveInUnprepareHeader(
387                s->wavein, &s->buffers[i], sizeof(s->buffers[i]) );
388                s->buffers[i].dwUser = 0xFFFF;
389        }
390    }
391
392    if (s->buffer_bytes != NULL) {
393        g_free(s->buffer_bytes);
394        s->buffer_bytes = NULL;
395    }
396
397    if (s->wavein) {
398        waveInClose(s->wavein);
399        s->wavein = NULL;
400    }
401}
402
403
404static int
405winaudio_in_init (HWVoiceIn *hw, struct audsettings *as)
406{
407    WinAudioIn*   s = (WinAudioIn*) hw;
408    MMRESULT       result;
409    WAVEFORMATEX   format;
410    int            shift, i, samples_size;
411
412    s->wavein = NULL;
413    InitializeCriticalSection( &s->lock );
414    for (i = 0; i < NUM_IN_BUFFERS; i++) {
415            s->buffers[i].dwUser = 0xFFFF;
416    }
417    s->buffer_bytes = NULL;
418
419    /* compute desired wave input format */
420    format.wFormatTag      = WAVE_FORMAT_PCM;
421    format.nChannels       = as->nchannels;
422    format.nSamplesPerSec  = as->freq;
423    format.nAvgBytesPerSec = as->freq*as->nchannels;
424
425    switch (as->fmt) {
426        case AUD_FMT_S8:   shift = 0; break;
427        case AUD_FMT_U8:   shift = 0; break;
428        case AUD_FMT_S16:  shift = 1; break;
429        case AUD_FMT_U16:  shift = 1; break;
430        default:
431            fprintf(stderr, "qemu: winaudio: Bad input audio format: %d\n",
432                    as->fmt);
433                return -1;
434    }
435
436    format.nAvgBytesPerSec = (format.nSamplesPerSec * format.nChannels) << shift;
437    format.nBlockAlign     = format.nChannels << shift;
438    format.wBitsPerSample  = 8 << shift;
439    format.cbSize          = 0;
440
441    /* open the wave in device */
442    result = waveInOpen( &s->wavein, WAVE_MAPPER, &format,
443                         (DWORD_PTR)winaudio_in_buffer_done, (DWORD_PTR) hw,
444                         CALLBACK_FUNCTION);
445    if ( result != MMSYSERR_NOERROR ) {
446        dump_mmerror( "qemu: winaudio: waveInOpen()", result);
447            return -1;
448    }
449
450    samples_size    = format.nBlockAlign * conf.nb_samples;
451    s->buffer_bytes = g_malloc( NUM_IN_BUFFERS * samples_size );
452    if (s->buffer_bytes == NULL) {
453            waveInClose( s->wavein );
454            s->wavein = NULL;
455            fprintf(stderr, "not enough memory for Windows audio buffers\n");
456            return -1;
457    }
458
459    for (i = 0; i < NUM_IN_BUFFERS; i++) {
460        memset( &s->buffers[i], 0, sizeof(s->buffers[i]) );
461        s->buffers[i].lpData         = (LPSTR)(s->buffer_bytes + i*samples_size);
462        s->buffers[i].dwBufferLength = samples_size;
463        s->buffers[i].dwFlags        = WHDR_DONE;
464
465        result = waveInPrepareHeader( s->wavein, &s->buffers[i],
466                               sizeof(s->buffers[i]) );
467        if ( result != MMSYSERR_NOERROR ) {
468                dump_mmerror("waveInPrepareHeader()", result);
469                return -1;
470        }
471
472        result = waveInAddBuffer( s->wavein, &s->buffers[i],
473                              sizeof(s->buffers[i]) );
474        if ( result != MMSYSERR_NOERROR ) {
475            dump_mmerror("waveInAddBuffer()", result);
476            return -1;
477        }
478    }
479
480#if DEBUG
481    /* Check the sound device we retrieved */
482    {
483        WAVEINCAPS caps;
484
485        result = waveInGetDevCaps((UINT) s->wavein, &caps, sizeof(caps));
486        if ( result != MMSYSERR_NOERROR ) {
487            dump_mmerror("waveInGetDevCaps()", result);
488        } else
489            printf("Audio in device: %s\n", caps.szPname);
490    }
491#endif
492
493    audio_pcm_init_info (&hw->info, as);
494    hw->samples = conf.nb_samples*2;
495
496    s->read_index = 0;
497    s->read_count = 0;
498    s->read_pos   = 0;
499    s->read_size  = samples_size;
500    return 0;
501}
502
503
504/* report the number of captured samples to the audio subsystem */
505static int
506winaudio_in_run (HWVoiceIn *hw)
507{
508    WinAudioIn*  s        = (WinAudioIn*) hw;
509    int          captured = 0;
510    int          has_buffer;
511    int          live = hw->samples - hw->total_samples_captured;
512
513    if (!live) {
514#if 0
515        static int  counter;
516        if (++counter == 100) {
517            D("0"); fflush(stdout);
518            counter = 0;
519        }
520#endif
521            return 0;
522    }
523
524    EnterCriticalSection( &s->lock );
525    has_buffer = (s->read_count > 0);
526    LeaveCriticalSection( &s->lock );
527
528    if (has_buffer > 0) {
529        while (live > 0) {
530            WAVEHDR*      wav_buffer  = s->buffers + s->read_index;
531            int           wav_bytes   = (s->read_size - s->read_pos);
532            int           wav_samples = audio_MIN(wav_bytes >> hw->info.shift, live);
533            int           hw_samples  = audio_MIN(hw->samples - hw->wpos, live);
534            struct st_sample*  dst    = hw->conv_buf + hw->wpos;
535            uint8_t*      src         = (uint8_t*)wav_buffer->lpData + s->read_pos;
536
537            if (wav_samples > hw_samples) {
538                wav_samples = hw_samples;
539            }
540
541            wav_bytes = wav_samples << hw->info.shift;
542
543            D("%s: buffer:%d pos:%d size:%d wsamples:%d wbytes:%d live:%d wpos:%d hwsamples:%d\n",
544               __FUNCTION__, s->read_index, s->read_pos, s->read_size, wav_samples, wav_bytes, live,
545               hw->wpos, hw->samples);
546
547            hw->conv(dst, src, wav_samples, &nominal_volume);
548
549            hw->wpos += wav_samples;
550            if (hw->wpos >= hw->samples)
551                hw->wpos -= hw->samples;
552
553            live        -= wav_samples;
554            captured    += wav_samples;
555            s->read_pos += wav_bytes;
556            if (s->read_pos == s->read_size) {
557                s->read_pos    = 0;
558                s->read_index += 1;
559                if (s->read_index == NUM_IN_BUFFERS)
560                    s->read_index = 0;
561
562                waveInAddBuffer( s->wavein, wav_buffer, sizeof(*wav_buffer) );
563
564                EnterCriticalSection( &s->lock );
565                if (--s->read_count == 0) {
566                    live = 0;
567                }
568                LeaveCriticalSection( &s->lock );
569            }
570        }
571    }
572    return  captured;
573}
574
575
576static int
577winaudio_in_read (SWVoiceIn *sw, void *buf, int len)
578{
579    int  ret = audio_pcm_sw_read (sw, buf, len);
580    if (ret > 0)
581        D("%s: (%d) returned %d\n", __FUNCTION__, len, ret);
582    return ret;
583}
584
585
586static int
587winaudio_in_ctl (HWVoiceIn *hw, int cmd, ...)
588{
589	WinAudioIn*  s = (WinAudioIn*) hw;
590
591    switch (cmd) {
592    case VOICE_ENABLE:
593        D("%s: enable audio in\n", __FUNCTION__);
594        waveInStart( s->wavein );
595        break;
596
597    case VOICE_DISABLE:
598        D("%s: disable audio in\n", __FUNCTION__);
599        waveInStop( s->wavein );
600        break;
601    }
602    return 0;
603}
604
605/** AUDIO STATE
606 **/
607
608typedef struct WinAudioState {
609    int  dummy;
610} WinAudioState;
611
612static WinAudioState  g_winaudio;
613
614static void*
615winaudio_init(void)
616{
617    WinAudioState*  s = &g_winaudio;
618
619#if DEBUG
620    start_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
621    last_time  = 0;
622#endif
623
624    return s;
625}
626
627
628static void
629winaudio_fini (void *opaque)
630{
631}
632
633static struct audio_option winaudio_options[] = {
634    {"SAMPLES", AUD_OPT_INT, &conf.nb_samples,
635     "Size of Windows audio buffer in samples", NULL, 0},
636    {NULL, 0, NULL, NULL, NULL, 0}
637};
638
639static struct audio_pcm_ops winaudio_pcm_ops = {
640    winaudio_out_init,
641    winaudio_out_fini,
642    winaudio_out_run,
643    winaudio_out_write,
644    winaudio_out_ctl,
645
646    winaudio_in_init,
647    winaudio_in_fini,
648    winaudio_in_run,
649    winaudio_in_read,
650    winaudio_in_ctl
651};
652
653struct audio_driver win_audio_driver = {
654    INIT_FIELD (name           = ) "winaudio",
655    INIT_FIELD (descr          = ) "Windows wave audio",
656    INIT_FIELD (options        = ) winaudio_options,
657    INIT_FIELD (init           = ) winaudio_init,
658    INIT_FIELD (fini           = ) winaudio_fini,
659    INIT_FIELD (pcm_ops        = ) &winaudio_pcm_ops,
660    INIT_FIELD (can_be_default = ) 1,
661    INIT_FIELD (max_voices_out = ) 1,
662    INIT_FIELD (max_voices_in  = ) 1,
663    INIT_FIELD (voice_size_out = ) sizeof (WinAudioOut),
664    INIT_FIELD (voice_size_in  = ) sizeof (WinAudioIn)
665};
666