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