hw/eeprom93xx.c: substitute structure dump with discrete dump in eeprom_save/load
[qemu] / audio / dsoundaudio.c
1 /*
2  * QEMU DirectSound audio driver
3  *
4  * Copyright (c) 2005 Vassili Karpov (malc)
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
25 /*
26  * SEAL 1.07 by Carlos 'pel' Hasan was used as documentation
27  */
28
29 #include "qemu-common.h"
30 #include "audio.h"
31
32 #define AUDIO_CAP "dsound"
33 #include "audio_int.h"
34
35 #define WIN32_LEAN_AND_MEAN
36 #include <windows.h>
37 #include <mmsystem.h>
38 #include <objbase.h>
39 #include <dsound.h>
40
41 /* #define DEBUG_DSOUND */
42
43 static struct {
44     int lock_retries;
45     int restore_retries;
46     int getstatus_retries;
47     int set_primary;
48     int bufsize_in;
49     int bufsize_out;
50     struct audsettings settings;
51     int latency_millis;
52 } conf = {
53     1,
54     1,
55     1,
56     0,
57     16384,
58     16384,
59     {
60         44100,
61         2,
62         AUD_FMT_S16
63     },
64     10
65 };
66
67 typedef struct {
68     LPDIRECTSOUND dsound;
69     LPDIRECTSOUNDCAPTURE dsound_capture;
70     LPDIRECTSOUNDBUFFER dsound_primary_buffer;
71     struct audsettings settings;
72 } dsound;
73
74 static dsound glob_dsound;
75
76 typedef struct {
77     HWVoiceOut hw;
78     LPDIRECTSOUNDBUFFER dsound_buffer;
79     DWORD old_pos;
80     int first_time;
81 #ifdef DEBUG_DSOUND
82     DWORD old_ppos;
83     DWORD played;
84     DWORD mixed;
85 #endif
86 } DSoundVoiceOut;
87
88 typedef struct {
89     HWVoiceIn hw;
90     int first_time;
91     LPDIRECTSOUNDCAPTUREBUFFER dsound_capture_buffer;
92 } DSoundVoiceIn;
93
94 static void dsound_log_hresult (HRESULT hr)
95 {
96     const char *str = "BUG";
97
98     switch (hr) {
99     case DS_OK:
100         str = "The method succeeded";
101         break;
102 #ifdef DS_NO_VIRTUALIZATION
103     case DS_NO_VIRTUALIZATION:
104         str = "The buffer was created, but another 3D algorithm was substituted";
105         break;
106 #endif
107 #ifdef DS_INCOMPLETE
108     case DS_INCOMPLETE:
109         str = "The method succeeded, but not all the optional effects were obtained";
110         break;
111 #endif
112 #ifdef DSERR_ACCESSDENIED
113     case DSERR_ACCESSDENIED:
114         str = "The request failed because access was denied";
115         break;
116 #endif
117 #ifdef DSERR_ALLOCATED
118     case DSERR_ALLOCATED:
119         str = "The request failed because resources, such as a priority level, were already in use by another caller";
120         break;
121 #endif
122 #ifdef DSERR_ALREADYINITIALIZED
123     case DSERR_ALREADYINITIALIZED:
124         str = "The object is already initialized";
125         break;
126 #endif
127 #ifdef DSERR_BADFORMAT
128     case DSERR_BADFORMAT:
129         str = "The specified wave format is not supported";
130         break;
131 #endif
132 #ifdef DSERR_BADSENDBUFFERGUID
133     case DSERR_BADSENDBUFFERGUID:
134         str = "The GUID specified in an audiopath file does not match a valid mix-in buffer";
135         break;
136 #endif
137 #ifdef DSERR_BUFFERLOST
138     case DSERR_BUFFERLOST:
139         str = "The buffer memory has been lost and must be restored";
140         break;
141 #endif
142 #ifdef DSERR_BUFFERTOOSMALL
143     case DSERR_BUFFERTOOSMALL:
144         str = "The buffer size is not great enough to enable effects processing";
145         break;
146 #endif
147 #ifdef DSERR_CONTROLUNAVAIL
148     case DSERR_CONTROLUNAVAIL:
149         str = "The buffer control (volume, pan, and so on) requested by the caller is not available. Controls must be specified when the buffer is created, using the dwFlags member of DSBUFFERDESC";
150         break;
151 #endif
152 #ifdef DSERR_DS8_REQUIRED
153     case DSERR_DS8_REQUIRED:
154         str = "A DirectSound object of class CLSID_DirectSound8 or later is required for the requested functionality. For more information, see IDirectSound8 Interface";
155         break;
156 #endif
157 #ifdef DSERR_FXUNAVAILABLE
158     case DSERR_FXUNAVAILABLE:
159         str = "The effects requested could not be found on the system, or they are in the wrong order or in the wrong location; for example, an effect expected in hardware was found in software";
160         break;
161 #endif
162 #ifdef DSERR_GENERIC
163     case DSERR_GENERIC :
164         str = "An undetermined error occurred inside the DirectSound subsystem";
165         break;
166 #endif
167 #ifdef DSERR_INVALIDCALL
168     case DSERR_INVALIDCALL:
169         str = "This function is not valid for the current state of this object";
170         break;
171 #endif
172 #ifdef DSERR_INVALIDPARAM
173     case DSERR_INVALIDPARAM:
174         str = "An invalid parameter was passed to the returning function";
175         break;
176 #endif
177 #ifdef DSERR_NOAGGREGATION
178     case DSERR_NOAGGREGATION:
179         str = "The object does not support aggregation";
180         break;
181 #endif
182 #ifdef DSERR_NODRIVER
183     case DSERR_NODRIVER:
184         str = "No sound driver is available for use, or the given GUID is not a valid DirectSound device ID";
185         break;
186 #endif
187 #ifdef DSERR_NOINTERFACE
188     case DSERR_NOINTERFACE:
189         str = "The requested COM interface is not available";
190         break;
191 #endif
192 #ifdef DSERR_OBJECTNOTFOUND
193     case DSERR_OBJECTNOTFOUND:
194         str = "The requested object was not found";
195         break;
196 #endif
197 #ifdef DSERR_OTHERAPPHASPRIO
198     case DSERR_OTHERAPPHASPRIO:
199         str = "Another application has a higher priority level, preventing this call from succeeding";
200         break;
201 #endif
202 #ifdef DSERR_OUTOFMEMORY
203     case DSERR_OUTOFMEMORY:
204         str = "The DirectSound subsystem could not allocate sufficient memory to complete the caller's request";
205         break;
206 #endif
207 #ifdef DSERR_PRIOLEVELNEEDED
208     case DSERR_PRIOLEVELNEEDED:
209         str = "A cooperative level of DSSCL_PRIORITY or higher is required";
210         break;
211 #endif
212 #ifdef DSERR_SENDLOOP
213     case DSERR_SENDLOOP:
214         str = "A circular loop of send effects was detected";
215         break;
216 #endif
217 #ifdef DSERR_UNINITIALIZED
218     case DSERR_UNINITIALIZED:
219         str = "The Initialize method has not been called or has not been called successfully before other methods were called";
220         break;
221 #endif
222 #ifdef DSERR_UNSUPPORTED
223     case DSERR_UNSUPPORTED:
224         str = "The function called is not supported at this time";
225         break;
226 #endif
227     default:
228         AUD_log (AUDIO_CAP, "Reason: Unknown (HRESULT %#lx)\n", hr);
229         return;
230     }
231
232     AUD_log (AUDIO_CAP, "Reason: %s\n", str);
233 }
234
235 static void GCC_FMT_ATTR (2, 3) dsound_logerr (
236     HRESULT hr,
237     const char *fmt,
238     ...
239     )
240 {
241     va_list ap;
242
243     va_start (ap, fmt);
244     AUD_vlog (AUDIO_CAP, fmt, ap);
245     va_end (ap);
246
247     dsound_log_hresult (hr);
248 }
249
250 static void GCC_FMT_ATTR (3, 4) dsound_logerr2 (
251     HRESULT hr,
252     const char *typ,
253     const char *fmt,
254     ...
255     )
256 {
257     va_list ap;
258
259     AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
260     va_start (ap, fmt);
261     AUD_vlog (AUDIO_CAP, fmt, ap);
262     va_end (ap);
263
264     dsound_log_hresult (hr);
265 }
266
267 static DWORD millis_to_bytes (struct audio_pcm_info *info, DWORD millis)
268 {
269     return (millis * info->bytes_per_second) / 1000;
270 }
271
272 #ifdef DEBUG_DSOUND
273 static void print_wave_format (WAVEFORMATEX *wfx)
274 {
275     dolog ("tag             = %d\n", wfx->wFormatTag);
276     dolog ("nChannels       = %d\n", wfx->nChannels);
277     dolog ("nSamplesPerSec  = %ld\n", wfx->nSamplesPerSec);
278     dolog ("nAvgBytesPerSec = %ld\n", wfx->nAvgBytesPerSec);
279     dolog ("nBlockAlign     = %d\n", wfx->nBlockAlign);
280     dolog ("wBitsPerSample  = %d\n", wfx->wBitsPerSample);
281     dolog ("cbSize          = %d\n", wfx->cbSize);
282 }
283 #endif
284
285 static int dsound_restore_out (LPDIRECTSOUNDBUFFER dsb)
286 {
287     HRESULT hr;
288     int i;
289
290     for (i = 0; i < conf.restore_retries; ++i) {
291         hr = IDirectSoundBuffer_Restore (dsb);
292
293         switch (hr) {
294         case DS_OK:
295             return 0;
296
297         case DSERR_BUFFERLOST:
298             continue;
299
300         default:
301             dsound_logerr (hr, "Could not restore playback buffer\n");
302             return -1;
303         }
304     }
305
306     dolog ("%d attempts to restore playback buffer failed\n", i);
307     return -1;
308 }
309
310 static int waveformat_from_audio_settings (WAVEFORMATEX *wfx,
311                                            struct audsettings *as)
312 {
313     memset (wfx, 0, sizeof (*wfx));
314
315     wfx->wFormatTag = WAVE_FORMAT_PCM;
316     wfx->nChannels = as->nchannels;
317     wfx->nSamplesPerSec = as->freq;
318     wfx->nAvgBytesPerSec = as->freq << (as->nchannels == 2);
319     wfx->nBlockAlign = 1 << (as->nchannels == 2);
320     wfx->cbSize = 0;
321
322     switch (as->fmt) {
323     case AUD_FMT_S8:
324     case AUD_FMT_U8:
325         wfx->wBitsPerSample = 8;
326         break;
327
328     case AUD_FMT_S16:
329     case AUD_FMT_U16:
330         wfx->wBitsPerSample = 16;
331         wfx->nAvgBytesPerSec <<= 1;
332         wfx->nBlockAlign <<= 1;
333         break;
334
335     case AUD_FMT_S32:
336     case AUD_FMT_U32:
337         wfx->wBitsPerSample = 32;
338         wfx->nAvgBytesPerSec <<= 2;
339         wfx->nBlockAlign <<= 2;
340         break;
341
342     default:
343         dolog ("Internal logic error: Bad audio format %d\n", as->freq);
344         return -1;
345     }
346
347     return 0;
348 }
349
350 static int waveformat_to_audio_settings (WAVEFORMATEX *wfx,
351                                          struct audsettings *as)
352 {
353     if (wfx->wFormatTag != WAVE_FORMAT_PCM) {
354         dolog ("Invalid wave format, tag is not PCM, but %d\n",
355                wfx->wFormatTag);
356         return -1;
357     }
358
359     if (!wfx->nSamplesPerSec) {
360         dolog ("Invalid wave format, frequency is zero\n");
361         return -1;
362     }
363     as->freq = wfx->nSamplesPerSec;
364
365     switch (wfx->nChannels) {
366     case 1:
367         as->nchannels = 1;
368         break;
369
370     case 2:
371         as->nchannels = 2;
372         break;
373
374     default:
375         dolog (
376             "Invalid wave format, number of channels is not 1 or 2, but %d\n",
377             wfx->nChannels
378             );
379         return -1;
380     }
381
382     switch (wfx->wBitsPerSample) {
383     case 8:
384         as->fmt = AUD_FMT_U8;
385         break;
386
387     case 16:
388         as->fmt = AUD_FMT_S16;
389         break;
390
391     case 32:
392         as->fmt = AUD_FMT_S32;
393         break;
394
395     default:
396         dolog ("Invalid wave format, bits per sample is not "
397                "8, 16 or 32, but %d\n",
398                wfx->wBitsPerSample);
399         return -1;
400     }
401
402     return 0;
403 }
404
405 #include "dsound_template.h"
406 #define DSBTYPE_IN
407 #include "dsound_template.h"
408 #undef DSBTYPE_IN
409
410 static int dsound_get_status_out (LPDIRECTSOUNDBUFFER dsb, DWORD *statusp)
411 {
412     HRESULT hr;
413     int i;
414
415     for (i = 0; i < conf.getstatus_retries; ++i) {
416         hr = IDirectSoundBuffer_GetStatus (dsb, statusp);
417         if (FAILED (hr)) {
418             dsound_logerr (hr, "Could not get playback buffer status\n");
419             return -1;
420         }
421
422         if (*statusp & DSERR_BUFFERLOST) {
423             if (dsound_restore_out (dsb)) {
424                 return -1;
425             }
426             continue;
427         }
428         break;
429     }
430
431     return 0;
432 }
433
434 static int dsound_get_status_in (LPDIRECTSOUNDCAPTUREBUFFER dscb,
435                                  DWORD *statusp)
436 {
437     HRESULT hr;
438
439     hr = IDirectSoundCaptureBuffer_GetStatus (dscb, statusp);
440     if (FAILED (hr)) {
441         dsound_logerr (hr, "Could not get capture buffer status\n");
442         return -1;
443     }
444
445     return 0;
446 }
447
448 static void dsound_write_sample (HWVoiceOut *hw, uint8_t *dst, int dst_len)
449 {
450     int src_len1 = dst_len;
451     int src_len2 = 0;
452     int pos = hw->rpos + dst_len;
453     struct st_sample *src1 = hw->mix_buf + hw->rpos;
454     struct st_sample *src2 = NULL;
455
456     if (pos > hw->samples) {
457         src_len1 = hw->samples - hw->rpos;
458         src2 = hw->mix_buf;
459         src_len2 = dst_len - src_len1;
460         pos = src_len2;
461     }
462
463     if (src_len1) {
464         hw->clip (dst, src1, src_len1);
465     }
466
467     if (src_len2) {
468         dst = advance (dst, src_len1 << hw->info.shift);
469         hw->clip (dst, src2, src_len2);
470     }
471
472     hw->rpos = pos % hw->samples;
473 }
474
475 static void dsound_clear_sample (HWVoiceOut *hw, LPDIRECTSOUNDBUFFER dsb)
476 {
477     int err;
478     LPVOID p1, p2;
479     DWORD blen1, blen2, len1, len2;
480
481     err = dsound_lock_out (
482         dsb,
483         &hw->info,
484         0,
485         hw->samples << hw->info.shift,
486         &p1, &p2,
487         &blen1, &blen2,
488         1
489         );
490     if (err) {
491         return;
492     }
493
494     len1 = blen1 >> hw->info.shift;
495     len2 = blen2 >> hw->info.shift;
496
497 #ifdef DEBUG_DSOUND
498     dolog ("clear %p,%ld,%ld %p,%ld,%ld\n",
499            p1, blen1, len1,
500            p2, blen2, len2);
501 #endif
502
503     if (p1 && len1) {
504         audio_pcm_info_clear_buf (&hw->info, p1, len1);
505     }
506
507     if (p2 && len2) {
508         audio_pcm_info_clear_buf (&hw->info, p2, len2);
509     }
510
511     dsound_unlock_out (dsb, p1, p2, blen1, blen2);
512 }
513
514 static void dsound_close (dsound *s)
515 {
516     HRESULT hr;
517
518     if (s->dsound_primary_buffer) {
519         hr = IDirectSoundBuffer_Release (s->dsound_primary_buffer);
520         if (FAILED (hr)) {
521             dsound_logerr (hr, "Could not release primary buffer\n");
522         }
523         s->dsound_primary_buffer = NULL;
524     }
525 }
526
527 static int dsound_open (dsound *s)
528 {
529     int err;
530     HRESULT hr;
531     WAVEFORMATEX wfx;
532     DSBUFFERDESC dsbd;
533     HWND hwnd;
534
535     hwnd = GetForegroundWindow ();
536     hr = IDirectSound_SetCooperativeLevel (
537         s->dsound,
538         hwnd,
539         DSSCL_PRIORITY
540         );
541
542     if (FAILED (hr)) {
543         dsound_logerr (hr, "Could not set cooperative level for window %p\n",
544                        hwnd);
545         return -1;
546     }
547
548     if (!conf.set_primary) {
549         return 0;
550     }
551
552     err = waveformat_from_audio_settings (&wfx, &conf.settings);
553     if (err) {
554         return -1;
555     }
556
557     memset (&dsbd, 0, sizeof (dsbd));
558     dsbd.dwSize = sizeof (dsbd);
559     dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER;
560     dsbd.dwBufferBytes = 0;
561     dsbd.lpwfxFormat = NULL;
562
563     hr = IDirectSound_CreateSoundBuffer (
564         s->dsound,
565         &dsbd,
566         &s->dsound_primary_buffer,
567         NULL
568         );
569     if (FAILED (hr)) {
570         dsound_logerr (hr, "Could not create primary playback buffer\n");
571         return -1;
572     }
573
574     hr = IDirectSoundBuffer_SetFormat (s->dsound_primary_buffer, &wfx);
575     if (FAILED (hr)) {
576         dsound_logerr (hr, "Could not set primary playback buffer format\n");
577     }
578
579     hr = IDirectSoundBuffer_GetFormat (
580         s->dsound_primary_buffer,
581         &wfx,
582         sizeof (wfx),
583         NULL
584         );
585     if (FAILED (hr)) {
586         dsound_logerr (hr, "Could not get primary playback buffer format\n");
587         goto fail0;
588     }
589
590 #ifdef DEBUG_DSOUND
591     dolog ("Primary\n");
592     print_wave_format (&wfx);
593 #endif
594
595     err = waveformat_to_audio_settings (&wfx, &s->settings);
596     if (err) {
597         goto fail0;
598     }
599
600     return 0;
601
602  fail0:
603     dsound_close (s);
604     return -1;
605 }
606
607 static int dsound_ctl_out (HWVoiceOut *hw, int cmd, ...)
608 {
609     HRESULT hr;
610     DWORD status;
611     DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
612     LPDIRECTSOUNDBUFFER dsb = ds->dsound_buffer;
613
614     if (!dsb) {
615         dolog ("Attempt to control voice without a buffer\n");
616         return 0;
617     }
618
619     switch (cmd) {
620     case VOICE_ENABLE:
621         if (dsound_get_status_out (dsb, &status)) {
622             return -1;
623         }
624
625         if (status & DSBSTATUS_PLAYING) {
626             dolog ("warning: Voice is already playing\n");
627             return 0;
628         }
629
630         dsound_clear_sample (hw, dsb);
631
632         hr = IDirectSoundBuffer_Play (dsb, 0, 0, DSBPLAY_LOOPING);
633         if (FAILED (hr)) {
634             dsound_logerr (hr, "Could not start playing buffer\n");
635             return -1;
636         }
637         break;
638
639     case VOICE_DISABLE:
640         if (dsound_get_status_out (dsb, &status)) {
641             return -1;
642         }
643
644         if (status & DSBSTATUS_PLAYING) {
645             hr = IDirectSoundBuffer_Stop (dsb);
646             if (FAILED (hr)) {
647                 dsound_logerr (hr, "Could not stop playing buffer\n");
648                 return -1;
649             }
650         }
651         else {
652             dolog ("warning: Voice is not playing\n");
653         }
654         break;
655     }
656     return 0;
657 }
658
659 static int dsound_write (SWVoiceOut *sw, void *buf, int len)
660 {
661     return audio_pcm_sw_write (sw, buf, len);
662 }
663
664 static int dsound_run_out (HWVoiceOut *hw)
665 {
666     int err;
667     HRESULT hr;
668     DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
669     LPDIRECTSOUNDBUFFER dsb = ds->dsound_buffer;
670     int live, len, hwshift;
671     DWORD blen1, blen2;
672     DWORD len1, len2;
673     DWORD decr;
674     DWORD wpos, ppos, old_pos;
675     LPVOID p1, p2;
676     int bufsize;
677
678     if (!dsb) {
679         dolog ("Attempt to run empty with playback buffer\n");
680         return 0;
681     }
682
683     hwshift = hw->info.shift;
684     bufsize = hw->samples << hwshift;
685
686     live = audio_pcm_hw_get_live_out (hw);
687
688     hr = IDirectSoundBuffer_GetCurrentPosition (
689         dsb,
690         &ppos,
691         ds->first_time ? &wpos : NULL
692         );
693     if (FAILED (hr)) {
694         dsound_logerr (hr, "Could not get playback buffer position\n");
695         return 0;
696     }
697
698     len = live << hwshift;
699
700     if (ds->first_time) {
701         if (conf.latency_millis) {
702             DWORD cur_blat;
703
704             cur_blat = audio_ring_dist (wpos, ppos, bufsize);
705             ds->first_time = 0;
706             old_pos = wpos;
707             old_pos +=
708                 millis_to_bytes (&hw->info, conf.latency_millis) - cur_blat;
709             old_pos %= bufsize;
710             old_pos &= ~hw->info.align;
711         }
712         else {
713             old_pos = wpos;
714         }
715 #ifdef DEBUG_DSOUND
716         ds->played = 0;
717         ds->mixed = 0;
718 #endif
719     }
720     else {
721         if (ds->old_pos == ppos) {
722 #ifdef DEBUG_DSOUND
723             dolog ("old_pos == ppos\n");
724 #endif
725             return 0;
726         }
727
728 #ifdef DEBUG_DSOUND
729         ds->played += audio_ring_dist (ds->old_pos, ppos, hw->bufsize);
730 #endif
731         old_pos = ds->old_pos;
732     }
733
734     if ((old_pos < ppos) && ((old_pos + len) > ppos)) {
735         len = ppos - old_pos;
736     }
737     else {
738         if ((old_pos > ppos) && ((old_pos + len) > (ppos + bufsize))) {
739             len = bufsize - old_pos + ppos;
740         }
741     }
742
743     if (audio_bug (AUDIO_FUNC, len < 0 || len > bufsize)) {
744         dolog ("len=%d bufsize=%d old_pos=%ld ppos=%ld\n",
745                len, bufsize, old_pos, ppos);
746         return 0;
747     }
748
749     len &= ~hw->info.align;
750     if (!len) {
751         return 0;
752     }
753
754 #ifdef DEBUG_DSOUND
755     ds->old_ppos = ppos;
756 #endif
757     err = dsound_lock_out (
758         dsb,
759         &hw->info,
760         old_pos,
761         len,
762         &p1, &p2,
763         &blen1, &blen2,
764         0
765         );
766     if (err) {
767         return 0;
768     }
769
770     len1 = blen1 >> hwshift;
771     len2 = blen2 >> hwshift;
772     decr = len1 + len2;
773
774     if (p1 && len1) {
775         dsound_write_sample (hw, p1, len1);
776     }
777
778     if (p2 && len2) {
779         dsound_write_sample (hw, p2, len2);
780     }
781
782     dsound_unlock_out (dsb, p1, p2, blen1, blen2);
783     ds->old_pos = (old_pos + (decr << hwshift)) % bufsize;
784
785 #ifdef DEBUG_DSOUND
786     ds->mixed += decr << hwshift;
787
788     dolog ("played %lu mixed %lu diff %ld sec %f\n",
789            ds->played,
790            ds->mixed,
791            ds->mixed - ds->played,
792            abs (ds->mixed - ds->played) / (double) hw->info.bytes_per_second);
793 #endif
794     return decr;
795 }
796
797 static int dsound_ctl_in (HWVoiceIn *hw, int cmd, ...)
798 {
799     HRESULT hr;
800     DWORD status;
801     DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
802     LPDIRECTSOUNDCAPTUREBUFFER dscb = ds->dsound_capture_buffer;
803
804     if (!dscb) {
805         dolog ("Attempt to control capture voice without a buffer\n");
806         return -1;
807     }
808
809     switch (cmd) {
810     case VOICE_ENABLE:
811         if (dsound_get_status_in (dscb, &status)) {
812             return -1;
813         }
814
815         if (status & DSCBSTATUS_CAPTURING) {
816             dolog ("warning: Voice is already capturing\n");
817             return 0;
818         }
819
820         /* clear ?? */
821
822         hr = IDirectSoundCaptureBuffer_Start (dscb, DSCBSTART_LOOPING);
823         if (FAILED (hr)) {
824             dsound_logerr (hr, "Could not start capturing\n");
825             return -1;
826         }
827         break;
828
829     case VOICE_DISABLE:
830         if (dsound_get_status_in (dscb, &status)) {
831             return -1;
832         }
833
834         if (status & DSCBSTATUS_CAPTURING) {
835             hr = IDirectSoundCaptureBuffer_Stop (dscb);
836             if (FAILED (hr)) {
837                 dsound_logerr (hr, "Could not stop capturing\n");
838                 return -1;
839             }
840         }
841         else {
842             dolog ("warning: Voice is not capturing\n");
843         }
844         break;
845     }
846     return 0;
847 }
848
849 static int dsound_read (SWVoiceIn *sw, void *buf, int len)
850 {
851     return audio_pcm_sw_read (sw, buf, len);
852 }
853
854 static int dsound_run_in (HWVoiceIn *hw)
855 {
856     int err;
857     HRESULT hr;
858     DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
859     LPDIRECTSOUNDCAPTUREBUFFER dscb = ds->dsound_capture_buffer;
860     int live, len, dead;
861     DWORD blen1, blen2;
862     DWORD len1, len2;
863     DWORD decr;
864     DWORD cpos, rpos;
865     LPVOID p1, p2;
866     int hwshift;
867
868     if (!dscb) {
869         dolog ("Attempt to run without capture buffer\n");
870         return 0;
871     }
872
873     hwshift = hw->info.shift;
874
875     live = audio_pcm_hw_get_live_in (hw);
876     dead = hw->samples - live;
877     if (!dead) {
878         return 0;
879     }
880
881     hr = IDirectSoundCaptureBuffer_GetCurrentPosition (
882         dscb,
883         &cpos,
884         ds->first_time ? &rpos : NULL
885         );
886     if (FAILED (hr)) {
887         dsound_logerr (hr, "Could not get capture buffer position\n");
888         return 0;
889     }
890
891     if (ds->first_time) {
892         ds->first_time = 0;
893         if (rpos & hw->info.align) {
894             ldebug ("warning: Misaligned capture read position %ld(%d)\n",
895                     rpos, hw->info.align);
896         }
897         hw->wpos = rpos >> hwshift;
898     }
899
900     if (cpos & hw->info.align) {
901         ldebug ("warning: Misaligned capture position %ld(%d)\n",
902                 cpos, hw->info.align);
903     }
904     cpos >>= hwshift;
905
906     len = audio_ring_dist (cpos, hw->wpos, hw->samples);
907     if (!len) {
908         return 0;
909     }
910     len = audio_MIN (len, dead);
911
912     err = dsound_lock_in (
913         dscb,
914         &hw->info,
915         hw->wpos << hwshift,
916         len << hwshift,
917         &p1,
918         &p2,
919         &blen1,
920         &blen2,
921         0
922         );
923     if (err) {
924         return 0;
925     }
926
927     len1 = blen1 >> hwshift;
928     len2 = blen2 >> hwshift;
929     decr = len1 + len2;
930
931     if (p1 && len1) {
932         hw->conv (hw->conv_buf + hw->wpos, p1, len1, &nominal_volume);
933     }
934
935     if (p2 && len2) {
936         hw->conv (hw->conv_buf, p2, len2, &nominal_volume);
937     }
938
939     dsound_unlock_in (dscb, p1, p2, blen1, blen2);
940     hw->wpos = (hw->wpos + decr) % hw->samples;
941     return decr;
942 }
943
944 static void dsound_audio_fini (void *opaque)
945 {
946     HRESULT hr;
947     dsound *s = opaque;
948
949     if (!s->dsound) {
950         return;
951     }
952
953     hr = IDirectSound_Release (s->dsound);
954     if (FAILED (hr)) {
955         dsound_logerr (hr, "Could not release DirectSound\n");
956     }
957     s->dsound = NULL;
958
959     if (!s->dsound_capture) {
960         return;
961     }
962
963     hr = IDirectSoundCapture_Release (s->dsound_capture);
964     if (FAILED (hr)) {
965         dsound_logerr (hr, "Could not release DirectSoundCapture\n");
966     }
967     s->dsound_capture = NULL;
968 }
969
970 static void *dsound_audio_init (void)
971 {
972     int err;
973     HRESULT hr;
974     dsound *s = &glob_dsound;
975
976     hr = CoInitialize (NULL);
977     if (FAILED (hr)) {
978         dsound_logerr (hr, "Could not initialize COM\n");
979         return NULL;
980     }
981
982     hr = CoCreateInstance (
983         &CLSID_DirectSound,
984         NULL,
985         CLSCTX_ALL,
986         &IID_IDirectSound,
987         (void **) &s->dsound
988         );
989     if (FAILED (hr)) {
990         dsound_logerr (hr, "Could not create DirectSound instance\n");
991         return NULL;
992     }
993
994     hr = IDirectSound_Initialize (s->dsound, NULL);
995     if (FAILED (hr)) {
996         dsound_logerr (hr, "Could not initialize DirectSound\n");
997
998         hr = IDirectSound_Release (s->dsound);
999         if (FAILED (hr)) {
1000             dsound_logerr (hr, "Could not release DirectSound\n");
1001         }
1002         s->dsound = NULL;
1003         return NULL;
1004     }
1005
1006     hr = CoCreateInstance (
1007         &CLSID_DirectSoundCapture,
1008         NULL,
1009         CLSCTX_ALL,
1010         &IID_IDirectSoundCapture,
1011         (void **) &s->dsound_capture
1012         );
1013     if (FAILED (hr)) {
1014         dsound_logerr (hr, "Could not create DirectSoundCapture instance\n");
1015     }
1016     else {
1017         hr = IDirectSoundCapture_Initialize (s->dsound_capture, NULL);
1018         if (FAILED (hr)) {
1019             dsound_logerr (hr, "Could not initialize DirectSoundCapture\n");
1020
1021             hr = IDirectSoundCapture_Release (s->dsound_capture);
1022             if (FAILED (hr)) {
1023                 dsound_logerr (hr, "Could not release DirectSoundCapture\n");
1024             }
1025             s->dsound_capture = NULL;
1026         }
1027     }
1028
1029     err = dsound_open (s);
1030     if (err) {
1031         dsound_audio_fini (s);
1032         return NULL;
1033     }
1034
1035     return s;
1036 }
1037
1038 static struct audio_option dsound_options[] = {
1039     {"LOCK_RETRIES", AUD_OPT_INT, &conf.lock_retries,
1040      "Number of times to attempt locking the buffer", NULL, 0},
1041     {"RESTOURE_RETRIES", AUD_OPT_INT, &conf.restore_retries,
1042      "Number of times to attempt restoring the buffer", NULL, 0},
1043     {"GETSTATUS_RETRIES", AUD_OPT_INT, &conf.getstatus_retries,
1044      "Number of times to attempt getting status of the buffer", NULL, 0},
1045     {"SET_PRIMARY", AUD_OPT_BOOL, &conf.set_primary,
1046      "Set the parameters of primary buffer", NULL, 0},
1047     {"LATENCY_MILLIS", AUD_OPT_INT, &conf.latency_millis,
1048      "(undocumented)", NULL, 0},
1049     {"PRIMARY_FREQ", AUD_OPT_INT, &conf.settings.freq,
1050      "Primary buffer frequency", NULL, 0},
1051     {"PRIMARY_CHANNELS", AUD_OPT_INT, &conf.settings.nchannels,
1052      "Primary buffer number of channels (1 - mono, 2 - stereo)", NULL, 0},
1053     {"PRIMARY_FMT", AUD_OPT_FMT, &conf.settings.fmt,
1054      "Primary buffer format", NULL, 0},
1055     {"BUFSIZE_OUT", AUD_OPT_INT, &conf.bufsize_out,
1056      "(undocumented)", NULL, 0},
1057     {"BUFSIZE_IN", AUD_OPT_INT, &conf.bufsize_in,
1058      "(undocumented)", NULL, 0},
1059     {NULL, 0, NULL, NULL, NULL, 0}
1060 };
1061
1062 static struct audio_pcm_ops dsound_pcm_ops = {
1063     dsound_init_out,
1064     dsound_fini_out,
1065     dsound_run_out,
1066     dsound_write,
1067     dsound_ctl_out,
1068
1069     dsound_init_in,
1070     dsound_fini_in,
1071     dsound_run_in,
1072     dsound_read,
1073     dsound_ctl_in
1074 };
1075
1076 struct audio_driver dsound_audio_driver = {
1077     INIT_FIELD (name           = ) "dsound",
1078     INIT_FIELD (descr          = )
1079     "DirectSound http://wikipedia.org/wiki/DirectSound",
1080     INIT_FIELD (options        = ) dsound_options,
1081     INIT_FIELD (init           = ) dsound_audio_init,
1082     INIT_FIELD (fini           = ) dsound_audio_fini,
1083     INIT_FIELD (pcm_ops        = ) &dsound_pcm_ops,
1084     INIT_FIELD (can_be_default = ) 1,
1085     INIT_FIELD (max_voices_out = ) INT_MAX,
1086     INIT_FIELD (max_voices_in  = ) 1,
1087     INIT_FIELD (voice_size_out = ) sizeof (DSoundVoiceOut),
1088     INIT_FIELD (voice_size_in  = ) sizeof (DSoundVoiceIn)
1089 };