|
|
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:
1.1.1.3 root 29: #include "qemu-common.h"
30: #include "audio.h"
1.1 root 31:
32: #define AUDIO_CAP "dsound"
33: #include "audio_int.h"
34:
1.1.1.3 root 35: #define WIN32_LEAN_AND_MEAN
1.1 root 36: #include <windows.h>
1.1.1.3 root 37: #include <mmsystem.h>
1.1 root 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;
1.1.1.4 ! root 50: struct audsettings settings;
1.1 root 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;
1.1.1.4 ! root 71: struct audsettings settings;
1.1 root 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:
1.1.1.4 ! root 310: static int waveformat_from_audio_settings (WAVEFORMATEX *wfx,
! 311: struct audsettings *as)
1.1 root 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:
1.1.1.4 ! root 329: case AUD_FMT_U16:
1.1 root 330: wfx->wBitsPerSample = 16;
331: wfx->nAvgBytesPerSec <<= 1;
332: wfx->nBlockAlign <<= 1;
333: break;
334:
1.1.1.4 ! root 335: case AUD_FMT_S32:
! 336: case AUD_FMT_U32:
! 337: wfx->wBitsPerSample = 32;
! 338: wfx->nAvgBytesPerSec <<= 2;
! 339: wfx->nBlockAlign <<= 2;
1.1 root 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:
1.1.1.4 ! root 350: static int waveformat_to_audio_settings (WAVEFORMATEX *wfx,
! 351: struct audsettings *as)
1.1 root 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:
1.1.1.4 ! root 391: case 32:
! 392: as->fmt = AUD_FMT_S32;
! 393: break;
! 394:
1.1 root 395: default:
1.1.1.4 ! root 396: dolog ("Invalid wave format, bits per sample is not "
! 397: "8, 16 or 32, but %d\n",
1.1 root 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;
1.1.1.4 ! root 453: struct st_sample *src1 = hw->mix_buf + hw->rpos;
! 454: struct st_sample *src2 = NULL;
1.1 root 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");
1.1.1.2 root 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;
1.1 root 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: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.