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        qemu_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 = qemu_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)
255{
256    WinAudioOut*  s      = (WinAudioOut*) hw;
257    int           played = 0;
258    int           has_buffer;
259    int           live = audio_pcm_hw_get_live_out (hw);
260
261    if (!live) {
262        return 0;
263    }
264
265    EnterCriticalSection( &s->lock );
266    has_buffer = (s->write_count > 0);
267    LeaveCriticalSection( &s->lock );
268
269    if (has_buffer) {
270        while (live > 0) {
271            WAVEHDR*      wav_buffer  = s->buffers + s->write_index;
272            int           wav_bytes   = (s->write_size - s->write_pos);
273            int           wav_samples = audio_MIN(wav_bytes >> hw->info.shift, live);
274            int           hw_samples  = audio_MIN(hw->samples - hw->rpos, live);
275            struct st_sample*  src         = hw->mix_buf + hw->rpos;
276            uint8_t*      dst         = (uint8_t*)wav_buffer->lpData + s->write_pos;
277
278            if (wav_samples > hw_samples) {
279                    wav_samples = hw_samples;
280            }
281
282            wav_bytes = wav_samples << hw->info.shift;
283
284            //D("run_out: buffer:%d pos:%d size:%d wsamples:%d wbytes:%d live:%d rpos:%d hwsamples:%d\n", s->write_index,
285            //   s->write_pos, s->write_size, wav_samples, wav_bytes, live, hw->rpos, hw->samples);
286            hw->clip (dst, src, wav_samples);
287            hw->rpos += wav_samples;
288            if (hw->rpos >= hw->samples)
289                    hw->rpos -= hw->samples;
290
291            live         -= wav_samples;
292            played       += wav_samples;
293            s->write_pos += wav_bytes;
294            if (s->write_pos == s->write_size) {
295#if xxDEBUG
296                int64_t  now  = qemu_get_clock(vm_clock) - start_time;
297                int64_t  diff = now - last_time;
298
299                D("run_out: (%7.3f:%7d):waveOutWrite buffer:%d\n",
300                   now/1e9, (now-last_time)/1e9, s->write_index);
301                last_time = now;
302#endif
303                waveOutWrite( s->waveout, wav_buffer, sizeof(*wav_buffer) );
304                s->write_pos    = 0;
305                s->write_index += 1;
306                if (s->write_index == NUM_OUT_BUFFERS)
307                    s->write_index = 0;
308
309                EnterCriticalSection( &s->lock );
310                if (--s->write_count == 0) {
311                        live = 0;
312                }
313                LeaveCriticalSection( &s->lock );
314            }
315        }
316
317    }
318    return played;
319}
320
321static int
322winaudio_out_ctl (HWVoiceOut *hw, int cmd, ...)
323{
324    WinAudioOut*  s = (WinAudioOut*) hw;
325
326    switch (cmd) {
327    case VOICE_ENABLE:
328        waveOutRestart( s->waveout );
329        break;
330
331    case VOICE_DISABLE:
332        waveOutPause( s->waveout );
333        break;
334    }
335    return 0;
336}
337
338/** AUDIO IN
339 **/
340
341#define  NUM_IN_BUFFERS  2
342
343typedef struct WinAudioIn {
344    HWVoiceIn         hw;
345    HWAVEIN           wavein;
346    CRITICAL_SECTION  lock;
347    unsigned char*    buffer_bytes;
348    WAVEHDR           buffers[ NUM_IN_BUFFERS ];
349    int               read_index;
350    int               read_count;
351    int               read_pos;
352    int               read_size;
353} WinAudioIn;
354
355/* The Win32 callback that is called when a buffer has finished playing */
356static void CALLBACK
357winaudio_in_buffer_done (HWAVEIN hwi, UINT uMsg, DWORD_PTR dwInstance,
358                         DWORD dwParam1, DWORD dwParam2)
359{
360    WinAudioIn*  s = (WinAudioIn*) dwInstance;
361
362    /* Only service "buffer done playing" messages */
363    if ( uMsg != WIM_DATA )
364        return;
365
366    /* Signal that we are done playing a buffer */
367    EnterCriticalSection( &s->lock );
368    if (s->read_count < NUM_IN_BUFFERS)
369        s->read_count += 1;
370        //D(".%c",s->read_count + '0'); fflush(stdout);
371    LeaveCriticalSection( &s->lock );
372}
373
374static void
375winaudio_in_fini (HWVoiceIn *hw)
376{
377    WinAudioIn*  s = (WinAudioIn*) hw;
378    int           i;
379
380    if (s->wavein) {
381        waveInReset(s->wavein);
382            s->wavein = 0;
383    }
384
385    for ( i=0; i<NUM_OUT_BUFFERS; ++i ) {
386        if ( s->buffers[i].dwUser != 0xFFFF ) {
387            waveInUnprepareHeader(
388                s->wavein, &s->buffers[i], sizeof(s->buffers[i]) );
389                s->buffers[i].dwUser = 0xFFFF;
390        }
391    }
392
393    if (s->buffer_bytes != NULL) {
394        qemu_free(s->buffer_bytes);
395        s->buffer_bytes = NULL;
396    }
397
398    if (s->wavein) {
399        waveInClose(s->wavein);
400        s->wavein = NULL;
401    }
402}
403
404
405static int
406winaudio_in_init (HWVoiceIn *hw, struct audsettings *as)
407{
408    WinAudioIn*   s = (WinAudioIn*) hw;
409    MMRESULT       result;
410    WAVEFORMATEX   format;
411    int            shift, i, samples_size;
412
413    s->wavein = NULL;
414    InitializeCriticalSection( &s->lock );
415    for (i = 0; i < NUM_OUT_BUFFERS; i++) {
416            s->buffers[i].dwUser = 0xFFFF;
417    }
418    s->buffer_bytes = NULL;
419
420    /* compute desired wave input format */
421    format.wFormatTag      = WAVE_FORMAT_PCM;
422    format.nChannels       = as->nchannels;
423    format.nSamplesPerSec  = as->freq;
424    format.nAvgBytesPerSec = as->freq*as->nchannels;
425
426    switch (as->fmt) {
427        case AUD_FMT_S8:   shift = 0; break;
428        case AUD_FMT_U8:   shift = 0; break;
429        case AUD_FMT_S16:  shift = 1; break;
430        case AUD_FMT_U16:  shift = 1; break;
431        default:
432            fprintf(stderr, "qemu: winaudio: Bad input audio format: %d\n",
433                    as->fmt);
434                return -1;
435    }
436
437    format.nAvgBytesPerSec = (format.nSamplesPerSec * format.nChannels) << shift;
438    format.nBlockAlign     = format.nChannels << shift;
439    format.wBitsPerSample  = 8 << shift;
440    format.cbSize          = 0;
441
442    /* open the wave in device */
443    result = waveInOpen( &s->wavein, WAVE_MAPPER, &format,
444                         (DWORD_PTR)winaudio_in_buffer_done, (DWORD_PTR) hw,
445                         CALLBACK_FUNCTION);
446    if ( result != MMSYSERR_NOERROR ) {
447        dump_mmerror( "qemu: winaudio: waveInOpen()", result);
448            return -1;
449    }
450
451    samples_size    = format.nBlockAlign * conf.nb_samples;
452    s->buffer_bytes = qemu_malloc( NUM_IN_BUFFERS * samples_size );
453    if (s->buffer_bytes == NULL) {
454            waveInClose( s->wavein );
455            s->wavein = NULL;
456            fprintf(stderr, "not enough memory for Windows audio buffers\n");
457            return -1;
458    }
459
460    for (i = 0; i < NUM_IN_BUFFERS; i++) {
461        memset( &s->buffers[i], 0, sizeof(s->buffers[i]) );
462        s->buffers[i].lpData         = (LPSTR)(s->buffer_bytes + i*samples_size);
463        s->buffers[i].dwBufferLength = samples_size;
464        s->buffers[i].dwFlags        = WHDR_DONE;
465
466        result = waveInPrepareHeader( s->wavein, &s->buffers[i],
467                               sizeof(s->buffers[i]) );
468        if ( result != MMSYSERR_NOERROR ) {
469                dump_mmerror("waveInPrepareHeader()", result);
470                return -1;
471        }
472
473        result = waveInAddBuffer( s->wavein, &s->buffers[i],
474                              sizeof(s->buffers[i]) );
475        if ( result != MMSYSERR_NOERROR ) {
476            dump_mmerror("waveInAddBuffer()", result);
477            return -1;
478        }
479    }
480
481#if DEBUG
482    /* Check the sound device we retrieved */
483    {
484        WAVEINCAPS caps;
485
486        result = waveInGetDevCaps((UINT) s->wavein, &caps, sizeof(caps));
487        if ( result != MMSYSERR_NOERROR ) {
488            dump_mmerror("waveInGetDevCaps()", result);
489        } else
490            printf("Audio in device: %s\n", caps.szPname);
491    }
492#endif
493
494    audio_pcm_init_info (&hw->info, as);
495    hw->samples = conf.nb_samples*2;
496
497    s->read_index = 0;
498    s->read_count = 0;
499    s->read_pos   = 0;
500    s->read_size  = samples_size;
501    return 0;
502}
503
504
505/* report the number of captured samples to the audio subsystem */
506static int
507winaudio_in_run (HWVoiceIn *hw)
508{
509    WinAudioIn*  s        = (WinAudioIn*) hw;
510    int          captured = 0;
511    int          has_buffer;
512    int          live = hw->samples - hw->total_samples_captured;
513
514    if (!live) {
515#if 0
516        static int  counter;
517        if (++counter == 100) {
518            D("0"); fflush(stdout);
519            counter = 0;
520        }
521#endif
522            return 0;
523    }
524
525    EnterCriticalSection( &s->lock );
526    has_buffer = (s->read_count > 0);
527    LeaveCriticalSection( &s->lock );
528
529    if (has_buffer > 0) {
530        while (live > 0) {
531            WAVEHDR*      wav_buffer  = s->buffers + s->read_index;
532            int           wav_bytes   = (s->read_size - s->read_pos);
533            int           wav_samples = audio_MIN(wav_bytes >> hw->info.shift, live);
534            int           hw_samples  = audio_MIN(hw->samples - hw->wpos, live);
535            struct st_sample*  dst    = hw->conv_buf + hw->wpos;
536            uint8_t*      src         = (uint8_t*)wav_buffer->lpData + s->read_pos;
537
538            if (wav_samples > hw_samples) {
539                wav_samples = hw_samples;
540            }
541
542            wav_bytes = wav_samples << hw->info.shift;
543
544            D("%s: buffer:%d pos:%d size:%d wsamples:%d wbytes:%d live:%d wpos:%d hwsamples:%d\n",
545               __FUNCTION__, s->read_index, s->read_pos, s->read_size, wav_samples, wav_bytes, live,
546               hw->wpos, hw->samples);
547
548            hw->conv(dst, src, wav_samples, &nominal_volume);
549
550            hw->wpos += wav_samples;
551            if (hw->wpos >= hw->samples)
552                hw->wpos -= hw->samples;
553
554            live        -= wav_samples;
555            captured    += wav_samples;
556            s->read_pos += wav_bytes;
557            if (s->read_pos == s->read_size) {
558                s->read_pos    = 0;
559                s->read_index += 1;
560                if (s->read_index == NUM_IN_BUFFERS)
561                    s->read_index = 0;
562
563                waveInAddBuffer( s->wavein, wav_buffer, sizeof(*wav_buffer) );
564
565                EnterCriticalSection( &s->lock );
566                if (--s->read_count == 0) {
567                    live = 0;
568                }
569                LeaveCriticalSection( &s->lock );
570            }
571        }
572    }
573    return  captured;
574}
575
576
577static int
578winaudio_in_read (SWVoiceIn *sw, void *buf, int len)
579{
580    int  ret = audio_pcm_sw_read (sw, buf, len);
581    if (ret > 0)
582        D("%s: (%d) returned %d\n", __FUNCTION__, len, ret);
583    return ret;
584}
585
586
587static int
588winaudio_in_ctl (HWVoiceIn *hw, int cmd, ...)
589{
590	WinAudioIn*  s = (WinAudioIn*) hw;
591
592    switch (cmd) {
593    case VOICE_ENABLE:
594        D("%s: enable audio in\n", __FUNCTION__);
595        waveInStart( s->wavein );
596        break;
597
598    case VOICE_DISABLE:
599        D("%s: disable audio in\n", __FUNCTION__);
600        waveInStop( s->wavein );
601        break;
602    }
603    return 0;
604}
605
606/** AUDIO STATE
607 **/
608
609typedef struct WinAudioState {
610    int  dummy;
611} WinAudioState;
612
613static WinAudioState  g_winaudio;
614
615static void*
616winaudio_init(void)
617{
618    WinAudioState*  s = &g_winaudio;
619
620#if DEBUG
621    start_time = qemu_get_clock(vm_clock);
622    last_time  = 0;
623#endif
624
625    return s;
626}
627
628
629static void
630winaudio_fini (void *opaque)
631{
632}
633
634static struct audio_option winaudio_options[] = {
635    {"SAMPLES", AUD_OPT_INT, &conf.nb_samples,
636     "Size of Windows audio buffer in samples", NULL, 0},
637    {NULL, 0, NULL, NULL, NULL, 0}
638};
639
640static struct audio_pcm_ops winaudio_pcm_ops = {
641    winaudio_out_init,
642    winaudio_out_fini,
643    winaudio_out_run,
644    winaudio_out_write,
645    winaudio_out_ctl,
646
647    winaudio_in_init,
648    winaudio_in_fini,
649    winaudio_in_run,
650    winaudio_in_read,
651    winaudio_in_ctl
652};
653
654struct audio_driver win_audio_driver = {
655    INIT_FIELD (name           = ) "winaudio",
656    INIT_FIELD (descr          = ) "Windows wave audio",
657    INIT_FIELD (options        = ) winaudio_options,
658    INIT_FIELD (init           = ) winaudio_init,
659    INIT_FIELD (fini           = ) winaudio_fini,
660    INIT_FIELD (pcm_ops        = ) &winaudio_pcm_ops,
661    INIT_FIELD (can_be_default = ) 1,
662    INIT_FIELD (max_voices_out = ) 1,
663    INIT_FIELD (max_voices_in  = ) 1,
664    INIT_FIELD (voice_size_out = ) sizeof (WinAudioOut),
665    INIT_FIELD (voice_size_in  = ) sizeof (WinAudioIn)
666};
667