Statistics
| Branch: | Revision:

root / audio / winwaveaudio.c @ 7267c094

History | View | Annotate | Download (17.4 kB)

1
/* public domain */
2

    
3
#include "qemu-common.h"
4
#include "sysemu.h"
5
#include "audio.h"
6

    
7
#define AUDIO_CAP "winwave"
8
#include "audio_int.h"
9

    
10
#include <windows.h>
11
#include <mmsystem.h>
12

    
13
#include "audio_win_int.h"
14

    
15
static struct {
16
    int dac_headers;
17
    int dac_samples;
18
    int adc_headers;
19
    int adc_samples;
20
} conf = {
21
    .dac_headers = 4,
22
    .dac_samples = 1024,
23
    .adc_headers = 4,
24
    .adc_samples = 1024
25
};
26

    
27
typedef struct {
28
    HWVoiceOut hw;
29
    HWAVEOUT hwo;
30
    WAVEHDR *hdrs;
31
    HANDLE event;
32
    void *pcm_buf;
33
    int avail;
34
    int pending;
35
    int curhdr;
36
    int paused;
37
    CRITICAL_SECTION crit_sect;
38
} WaveVoiceOut;
39

    
40
typedef struct {
41
    HWVoiceIn hw;
42
    HWAVEIN hwi;
43
    WAVEHDR *hdrs;
44
    HANDLE event;
45
    void *pcm_buf;
46
    int curhdr;
47
    int paused;
48
    int rpos;
49
    int avail;
50
    CRITICAL_SECTION crit_sect;
51
} WaveVoiceIn;
52

    
53
static void winwave_log_mmresult (MMRESULT mr)
54
{
55
    const char *str = "BUG";
56

    
57
    switch (mr) {
58
    case MMSYSERR_NOERROR:
59
        str = "Success";
60
        break;
61

    
62
    case MMSYSERR_INVALHANDLE:
63
        str = "Specified device handle is invalid";
64
        break;
65

    
66
    case MMSYSERR_BADDEVICEID:
67
        str = "Specified device id is out of range";
68
        break;
69

    
70
    case MMSYSERR_NODRIVER:
71
        str = "No device driver is present";
72
        break;
73

    
74
    case MMSYSERR_NOMEM:
75
        str = "Unable to allocate or locl memory";
76
        break;
77

    
78
    case WAVERR_SYNC:
79
        str = "Device is synchronous but waveOutOpen was called "
80
            "without using the WINWAVE_ALLOWSYNC flag";
81
        break;
82

    
83
    case WAVERR_UNPREPARED:
84
        str = "The data block pointed to by the pwh parameter "
85
            "hasn't been prepared";
86
        break;
87

    
88
    case WAVERR_STILLPLAYING:
89
        str = "There are still buffers in the queue";
90
        break;
91

    
92
    default:
93
        dolog ("Reason: Unknown (MMRESULT %#x)\n", mr);
94
        return;
95
    }
96

    
97
    dolog ("Reason: %s\n", str);
98
}
99

    
100
static void GCC_FMT_ATTR (2, 3) winwave_logerr (
101
    MMRESULT mr,
102
    const char *fmt,
103
    ...
104
    )
105
{
106
    va_list ap;
107

    
108
    va_start (ap, fmt);
109
    AUD_vlog (AUDIO_CAP, fmt, ap);
110
    va_end (ap);
111

    
112
    AUD_log (NULL, " failed\n");
113
    winwave_log_mmresult (mr);
114
}
115

    
116
static void winwave_anal_close_out (WaveVoiceOut *wave)
117
{
118
    MMRESULT mr;
119

    
120
    mr = waveOutClose (wave->hwo);
121
    if (mr != MMSYSERR_NOERROR) {
122
        winwave_logerr (mr, "waveOutClose");
123
    }
124
    wave->hwo = NULL;
125
}
126

    
127
static void CALLBACK winwave_callback_out (
128
    HWAVEOUT hwo,
129
    UINT msg,
130
    DWORD_PTR dwInstance,
131
    DWORD_PTR dwParam1,
132
    DWORD_PTR dwParam2
133
    )
134
{
135
    WaveVoiceOut *wave = (WaveVoiceOut *) dwInstance;
136

    
137
    switch (msg) {
138
    case WOM_DONE:
139
        {
140
            WAVEHDR *h = (WAVEHDR *) dwParam1;
141
            if (!h->dwUser) {
142
                h->dwUser = 1;
143
                EnterCriticalSection (&wave->crit_sect);
144
                {
145
                    wave->avail += conf.dac_samples;
146
                }
147
                LeaveCriticalSection (&wave->crit_sect);
148
                if (wave->hw.poll_mode) {
149
                    if (!SetEvent (wave->event)) {
150
                        dolog ("DAC SetEvent failed %lx\n", GetLastError ());
151
                    }
152
                }
153
            }
154
        }
155
        break;
156

    
157
    case WOM_CLOSE:
158
    case WOM_OPEN:
159
        break;
160

    
161
    default:
162
        dolog ("unknown wave out callback msg %x\n", msg);
163
    }
164
}
165

    
166
static int winwave_init_out (HWVoiceOut *hw, struct audsettings *as)
167
{
168
    int i;
169
    int err;
170
    MMRESULT mr;
171
    WAVEFORMATEX wfx;
172
    WaveVoiceOut *wave;
173

    
174
    wave = (WaveVoiceOut *) hw;
175

    
176
    InitializeCriticalSection (&wave->crit_sect);
177

    
178
    err = waveformat_from_audio_settings (&wfx, as);
179
    if (err) {
180
        goto err0;
181
    }
182

    
183
    mr = waveOutOpen (&wave->hwo, WAVE_MAPPER, &wfx,
184
                      (DWORD_PTR) winwave_callback_out,
185
                      (DWORD_PTR) wave, CALLBACK_FUNCTION);
186
    if (mr != MMSYSERR_NOERROR) {
187
        winwave_logerr (mr, "waveOutOpen");
188
        goto err1;
189
    }
190

    
191
    wave->hdrs = audio_calloc (AUDIO_FUNC, conf.dac_headers,
192
                               sizeof (*wave->hdrs));
193
    if (!wave->hdrs) {
194
        goto err2;
195
    }
196

    
197
    audio_pcm_init_info (&hw->info, as);
198
    hw->samples = conf.dac_samples * conf.dac_headers;
199
    wave->avail = hw->samples;
200

    
201
    wave->pcm_buf = audio_calloc (AUDIO_FUNC, conf.dac_samples,
202
                                  conf.dac_headers << hw->info.shift);
203
    if (!wave->pcm_buf) {
204
        goto err3;
205
    }
206

    
207
    for (i = 0; i < conf.dac_headers; ++i) {
208
        WAVEHDR *h = &wave->hdrs[i];
209

    
210
        h->dwUser = 0;
211
        h->dwBufferLength = conf.dac_samples << hw->info.shift;
212
        h->lpData = advance (wave->pcm_buf, i * h->dwBufferLength);
213
        h->dwFlags = 0;
214

    
215
        mr = waveOutPrepareHeader (wave->hwo, h, sizeof (*h));
216
        if (mr != MMSYSERR_NOERROR) {
217
            winwave_logerr (mr, "waveOutPrepareHeader(%d)", i);
218
            goto err4;
219
        }
220
    }
221

    
222
    return 0;
223

    
224
 err4:
225
    g_free (wave->pcm_buf);
226
 err3:
227
    g_free (wave->hdrs);
228
 err2:
229
    winwave_anal_close_out (wave);
230
 err1:
231
 err0:
232
    return -1;
233
}
234

    
235
static int winwave_write (SWVoiceOut *sw, void *buf, int len)
236
{
237
    return audio_pcm_sw_write (sw, buf, len);
238
}
239

    
240
static int winwave_run_out (HWVoiceOut *hw, int live)
241
{
242
    WaveVoiceOut *wave = (WaveVoiceOut *) hw;
243
    int decr;
244
    int doreset;
245

    
246
    EnterCriticalSection (&wave->crit_sect);
247
    {
248
        decr = audio_MIN (live, wave->avail);
249
        decr = audio_pcm_hw_clip_out (hw, wave->pcm_buf, decr, wave->pending);
250
        wave->pending += decr;
251
        wave->avail -= decr;
252
    }
253
    LeaveCriticalSection (&wave->crit_sect);
254

    
255
    doreset = hw->poll_mode && (wave->pending >= conf.dac_samples);
256
    if (doreset && !ResetEvent (wave->event)) {
257
        dolog ("DAC ResetEvent failed %lx\n", GetLastError ());
258
    }
259

    
260
    while (wave->pending >= conf.dac_samples) {
261
        MMRESULT mr;
262
        WAVEHDR *h = &wave->hdrs[wave->curhdr];
263

    
264
        h->dwUser = 0;
265
        mr = waveOutWrite (wave->hwo, h, sizeof (*h));
266
        if (mr != MMSYSERR_NOERROR) {
267
            winwave_logerr (mr, "waveOutWrite(%d)", wave->curhdr);
268
            break;
269
        }
270

    
271
        wave->pending -= conf.dac_samples;
272
        wave->curhdr = (wave->curhdr + 1) % conf.dac_headers;
273
    }
274

    
275
    return decr;
276
}
277

    
278
static void winwave_poll (void *opaque)
279
{
280
    (void) opaque;
281
    audio_run ("winwave_poll");
282
}
283

    
284
static void winwave_fini_out (HWVoiceOut *hw)
285
{
286
    int i;
287
    MMRESULT mr;
288
    WaveVoiceOut *wave = (WaveVoiceOut *) hw;
289

    
290
    mr = waveOutReset (wave->hwo);
291
    if (mr != MMSYSERR_NOERROR) {
292
        winwave_logerr (mr, "waveOutReset");
293
    }
294

    
295
    for (i = 0; i < conf.dac_headers; ++i) {
296
        mr = waveOutUnprepareHeader (wave->hwo, &wave->hdrs[i],
297
                                     sizeof (wave->hdrs[i]));
298
        if (mr != MMSYSERR_NOERROR) {
299
            winwave_logerr (mr, "waveOutUnprepareHeader(%d)", i);
300
        }
301
    }
302

    
303
    winwave_anal_close_out (wave);
304

    
305
    if (wave->event) {
306
        qemu_del_wait_object (wave->event, winwave_poll, wave);
307
        if (!CloseHandle (wave->event)) {
308
            dolog ("DAC CloseHandle failed %lx\n", GetLastError ());
309
        }
310
        wave->event = NULL;
311
    }
312

    
313
    g_free (wave->pcm_buf);
314
    wave->pcm_buf = NULL;
315

    
316
    g_free (wave->hdrs);
317
    wave->hdrs = NULL;
318
}
319

    
320
static int winwave_ctl_out (HWVoiceOut *hw, int cmd, ...)
321
{
322
    MMRESULT mr;
323
    WaveVoiceOut *wave = (WaveVoiceOut *) hw;
324

    
325
    switch (cmd) {
326
    case VOICE_ENABLE:
327
        {
328
            va_list ap;
329
            int poll_mode;
330

    
331
            va_start (ap, cmd);
332
            poll_mode = va_arg (ap, int);
333
            va_end (ap);
334

    
335
            if (poll_mode && !wave->event) {
336
                wave->event = CreateEvent (NULL, TRUE, TRUE, NULL);
337
                if (!wave->event) {
338
                    dolog ("DAC CreateEvent: %lx, poll mode will be disabled\n",
339
                           GetLastError ());
340
                }
341
            }
342

    
343
            if (wave->event) {
344
                int ret;
345

    
346
                ret = qemu_add_wait_object (wave->event, winwave_poll, wave);
347
                hw->poll_mode = (ret == 0);
348
            }
349
            else {
350
                hw->poll_mode = 0;
351
            }
352
            if (wave->paused) {
353
                mr = waveOutRestart (wave->hwo);
354
                if (mr != MMSYSERR_NOERROR) {
355
                    winwave_logerr (mr, "waveOutRestart");
356
                }
357
                wave->paused = 0;
358
            }
359
        }
360
        return 0;
361

    
362
    case VOICE_DISABLE:
363
        if (!wave->paused) {
364
            mr = waveOutPause (wave->hwo);
365
            if (mr != MMSYSERR_NOERROR) {
366
                winwave_logerr (mr, "waveOutPause");
367
            }
368
            else {
369
                wave->paused = 1;
370
            }
371
        }
372
        if (wave->event) {
373
            qemu_del_wait_object (wave->event, winwave_poll, wave);
374
        }
375
        return 0;
376
    }
377
    return -1;
378
}
379

    
380
static void winwave_anal_close_in (WaveVoiceIn *wave)
381
{
382
    MMRESULT mr;
383

    
384
    mr = waveInClose (wave->hwi);
385
    if (mr != MMSYSERR_NOERROR) {
386
        winwave_logerr (mr, "waveInClose");
387
    }
388
    wave->hwi = NULL;
389
}
390

    
391
static void CALLBACK winwave_callback_in (
392
    HWAVEIN *hwi,
393
    UINT msg,
394
    DWORD_PTR dwInstance,
395
    DWORD_PTR dwParam1,
396
    DWORD_PTR dwParam2
397
    )
398
{
399
    WaveVoiceIn *wave = (WaveVoiceIn *) dwInstance;
400

    
401
    switch (msg) {
402
    case WIM_DATA:
403
        {
404
            WAVEHDR *h = (WAVEHDR *) dwParam1;
405
            if (!h->dwUser) {
406
                h->dwUser = 1;
407
                EnterCriticalSection (&wave->crit_sect);
408
                {
409
                    wave->avail += conf.adc_samples;
410
                }
411
                LeaveCriticalSection (&wave->crit_sect);
412
                if (wave->hw.poll_mode) {
413
                    if (!SetEvent (wave->event)) {
414
                        dolog ("ADC SetEvent failed %lx\n", GetLastError ());
415
                    }
416
                }
417
            }
418
        }
419
        break;
420

    
421
    case WIM_CLOSE:
422
    case WIM_OPEN:
423
        break;
424

    
425
    default:
426
        dolog ("unknown wave in callback msg %x\n", msg);
427
    }
428
}
429

    
430
static void winwave_add_buffers (WaveVoiceIn *wave, int samples)
431
{
432
    int doreset;
433

    
434
    doreset = wave->hw.poll_mode && (samples >= conf.adc_samples);
435
    if (doreset && !ResetEvent (wave->event)) {
436
        dolog ("ADC ResetEvent failed %lx\n", GetLastError ());
437
    }
438

    
439
    while (samples >= conf.adc_samples) {
440
        MMRESULT mr;
441
        WAVEHDR *h = &wave->hdrs[wave->curhdr];
442

    
443
        h->dwUser = 0;
444
        mr = waveInAddBuffer (wave->hwi, h, sizeof (*h));
445
        if (mr != MMSYSERR_NOERROR) {
446
            winwave_logerr (mr, "waveInAddBuffer(%d)", wave->curhdr);
447
        }
448
        wave->curhdr = (wave->curhdr + 1) % conf.adc_headers;
449
        samples -= conf.adc_samples;
450
    }
451
}
452

    
453
static int winwave_init_in (HWVoiceIn *hw, struct audsettings *as)
454
{
455
    int i;
456
    int err;
457
    MMRESULT mr;
458
    WAVEFORMATEX wfx;
459
    WaveVoiceIn *wave;
460

    
461
    wave = (WaveVoiceIn *) hw;
462

    
463
    InitializeCriticalSection (&wave->crit_sect);
464

    
465
    err = waveformat_from_audio_settings (&wfx, as);
466
    if (err) {
467
        goto err0;
468
    }
469

    
470
    mr = waveInOpen (&wave->hwi, WAVE_MAPPER, &wfx,
471
                     (DWORD_PTR) winwave_callback_in,
472
                     (DWORD_PTR) wave, CALLBACK_FUNCTION);
473
    if (mr != MMSYSERR_NOERROR) {
474
        winwave_logerr (mr, "waveInOpen");
475
        goto err1;
476
    }
477

    
478
    wave->hdrs = audio_calloc (AUDIO_FUNC, conf.dac_headers,
479
                               sizeof (*wave->hdrs));
480
    if (!wave->hdrs) {
481
        goto err2;
482
    }
483

    
484
    audio_pcm_init_info (&hw->info, as);
485
    hw->samples = conf.adc_samples * conf.adc_headers;
486
    wave->avail = 0;
487

    
488
    wave->pcm_buf = audio_calloc (AUDIO_FUNC, conf.adc_samples,
489
                                  conf.adc_headers << hw->info.shift);
490
    if (!wave->pcm_buf) {
491
        goto err3;
492
    }
493

    
494
    for (i = 0; i < conf.adc_headers; ++i) {
495
        WAVEHDR *h = &wave->hdrs[i];
496

    
497
        h->dwUser = 0;
498
        h->dwBufferLength = conf.adc_samples << hw->info.shift;
499
        h->lpData = advance (wave->pcm_buf, i * h->dwBufferLength);
500
        h->dwFlags = 0;
501

    
502
        mr = waveInPrepareHeader (wave->hwi, h, sizeof (*h));
503
        if (mr != MMSYSERR_NOERROR) {
504
            winwave_logerr (mr, "waveInPrepareHeader(%d)", i);
505
            goto err4;
506
        }
507
    }
508

    
509
    wave->paused = 1;
510
    winwave_add_buffers (wave, hw->samples);
511
    return 0;
512

    
513
 err4:
514
    g_free (wave->pcm_buf);
515
 err3:
516
    g_free (wave->hdrs);
517
 err2:
518
    winwave_anal_close_in (wave);
519
 err1:
520
 err0:
521
    return -1;
522
}
523

    
524
static void winwave_fini_in (HWVoiceIn *hw)
525
{
526
    int i;
527
    MMRESULT mr;
528
    WaveVoiceIn *wave = (WaveVoiceIn *) hw;
529

    
530
    mr = waveInReset (wave->hwi);
531
    if (mr != MMSYSERR_NOERROR) {
532
        winwave_logerr (mr, "waveInReset");
533
    }
534

    
535
    for (i = 0; i < conf.adc_headers; ++i) {
536
        mr = waveInUnprepareHeader (wave->hwi, &wave->hdrs[i],
537
                                     sizeof (wave->hdrs[i]));
538
        if (mr != MMSYSERR_NOERROR) {
539
            winwave_logerr (mr, "waveInUnprepareHeader(%d)", i);
540
        }
541
    }
542

    
543
    winwave_anal_close_in (wave);
544

    
545
    if (wave->event) {
546
        qemu_del_wait_object (wave->event, winwave_poll, wave);
547
        if (!CloseHandle (wave->event)) {
548
            dolog ("ADC CloseHandle failed %lx\n", GetLastError ());
549
        }
550
        wave->event = NULL;
551
    }
552

    
553
    g_free (wave->pcm_buf);
554
    wave->pcm_buf = NULL;
555

    
556
    g_free (wave->hdrs);
557
    wave->hdrs = NULL;
558
}
559

    
560
static int winwave_run_in (HWVoiceIn *hw)
561
{
562
    WaveVoiceIn *wave = (WaveVoiceIn *) hw;
563
    int live = audio_pcm_hw_get_live_in (hw);
564
    int dead = hw->samples - live;
565
    int decr, ret;
566

    
567
    if (!dead) {
568
        return 0;
569
    }
570

    
571
    EnterCriticalSection (&wave->crit_sect);
572
    {
573
        decr = audio_MIN (dead, wave->avail);
574
        wave->avail -= decr;
575
    }
576
    LeaveCriticalSection (&wave->crit_sect);
577

    
578
    ret = decr;
579
    while (decr) {
580
        int left = hw->samples - hw->wpos;
581
        int conv = audio_MIN (left, decr);
582
        hw->conv (hw->conv_buf + hw->wpos,
583
                  advance (wave->pcm_buf, wave->rpos << hw->info.shift),
584
                  conv);
585

    
586
        wave->rpos = (wave->rpos + conv) % hw->samples;
587
        hw->wpos = (hw->wpos + conv) % hw->samples;
588
        decr -= conv;
589
    }
590

    
591
    winwave_add_buffers (wave, ret);
592
    return ret;
593
}
594

    
595
static int winwave_read (SWVoiceIn *sw, void *buf, int size)
596
{
597
    return audio_pcm_sw_read (sw, buf, size);
598
}
599

    
600
static int winwave_ctl_in (HWVoiceIn *hw, int cmd, ...)
601
{
602
    MMRESULT mr;
603
    WaveVoiceIn *wave = (WaveVoiceIn *) hw;
604

    
605
    switch (cmd) {
606
    case VOICE_ENABLE:
607
        {
608
            va_list ap;
609
            int poll_mode;
610

    
611
            va_start (ap, cmd);
612
            poll_mode = va_arg (ap, int);
613
            va_end (ap);
614

    
615
            if (poll_mode && !wave->event) {
616
                wave->event = CreateEvent (NULL, TRUE, TRUE, NULL);
617
                if (!wave->event) {
618
                    dolog ("ADC CreateEvent: %lx, poll mode will be disabled\n",
619
                           GetLastError ());
620
                }
621
            }
622

    
623
            if (wave->event) {
624
                int ret;
625

    
626
                ret = qemu_add_wait_object (wave->event, winwave_poll, wave);
627
                hw->poll_mode = (ret == 0);
628
            }
629
            else {
630
                hw->poll_mode = 0;
631
            }
632
            if (wave->paused) {
633
                mr = waveInStart (wave->hwi);
634
                if (mr != MMSYSERR_NOERROR) {
635
                    winwave_logerr (mr, "waveInStart");
636
                }
637
                wave->paused = 0;
638
            }
639
        }
640
        return 0;
641

    
642
    case VOICE_DISABLE:
643
        if (!wave->paused) {
644
            mr = waveInStop (wave->hwi);
645
            if (mr != MMSYSERR_NOERROR) {
646
                winwave_logerr (mr, "waveInStop");
647
            }
648
            else {
649
                wave->paused = 1;
650
            }
651
        }
652
        if (wave->event) {
653
            qemu_del_wait_object (wave->event, winwave_poll, wave);
654
        }
655
        return 0;
656
    }
657
    return 0;
658
}
659

    
660
static void *winwave_audio_init (void)
661
{
662
    return &conf;
663
}
664

    
665
static void winwave_audio_fini (void *opaque)
666
{
667
    (void) opaque;
668
}
669

    
670
static struct audio_option winwave_options[] = {
671
    {
672
        .name        = "DAC_HEADERS",
673
        .tag         = AUD_OPT_INT,
674
        .valp        = &conf.dac_headers,
675
        .descr       = "DAC number of headers",
676
    },
677
    {
678
        .name        = "DAC_SAMPLES",
679
        .tag         = AUD_OPT_INT,
680
        .valp        = &conf.dac_samples,
681
        .descr       = "DAC number of samples per header",
682
    },
683
    {
684
        .name        = "ADC_HEADERS",
685
        .tag         = AUD_OPT_INT,
686
        .valp        = &conf.adc_headers,
687
        .descr       = "ADC number of headers",
688
    },
689
    {
690
        .name        = "ADC_SAMPLES",
691
        .tag         = AUD_OPT_INT,
692
        .valp        = &conf.adc_samples,
693
        .descr       = "ADC number of samples per header",
694
    },
695
    { /* End of list */ }
696
};
697

    
698
static struct audio_pcm_ops winwave_pcm_ops = {
699
    .init_out = winwave_init_out,
700
    .fini_out = winwave_fini_out,
701
    .run_out  = winwave_run_out,
702
    .write    = winwave_write,
703
    .ctl_out  = winwave_ctl_out,
704
    .init_in  = winwave_init_in,
705
    .fini_in  = winwave_fini_in,
706
    .run_in   = winwave_run_in,
707
    .read     = winwave_read,
708
    .ctl_in   = winwave_ctl_in
709
};
710

    
711
struct audio_driver winwave_audio_driver = {
712
    .name           = "winwave",
713
    .descr          = "Windows Waveform Audio http://msdn.microsoft.com",
714
    .options        = winwave_options,
715
    .init           = winwave_audio_init,
716
    .fini           = winwave_audio_fini,
717
    .pcm_ops        = &winwave_pcm_ops,
718
    .can_be_default = 1,
719
    .max_voices_out = INT_MAX,
720
    .max_voices_in  = INT_MAX,
721
    .voice_size_out = sizeof (WaveVoiceOut),
722
    .voice_size_in  = sizeof (WaveVoiceIn)
723
};