|
|
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: mixeng_clear (src1, src_len1); ! 457: } ! 458: ! 459: if (src_len2) { ! 460: dst = advance (dst, src_len1 << hw->info.shift); ! 461: hw->clip (dst, src2, src_len2); ! 462: mixeng_clear (src2, src_len2); ! 463: } ! 464: ! 465: hw->rpos = pos % hw->samples; ! 466: } ! 467: ! 468: static void dsound_clear_sample (HWVoiceOut *hw, LPDIRECTSOUNDBUFFER dsb) ! 469: { ! 470: int err; ! 471: LPVOID p1, p2; ! 472: DWORD blen1, blen2, len1, len2; ! 473: ! 474: err = dsound_lock_out ( ! 475: dsb, ! 476: &hw->info, ! 477: 0, ! 478: hw->samples << hw->info.shift, ! 479: &p1, &p2, ! 480: &blen1, &blen2, ! 481: 1 ! 482: ); ! 483: if (err) { ! 484: return; ! 485: } ! 486: ! 487: len1 = blen1 >> hw->info.shift; ! 488: len2 = blen2 >> hw->info.shift; ! 489: ! 490: #ifdef DEBUG_DSOUND ! 491: dolog ("clear %p,%ld,%ld %p,%ld,%ld\n", ! 492: p1, blen1, len1, ! 493: p2, blen2, len2); ! 494: #endif ! 495: ! 496: if (p1 && len1) { ! 497: audio_pcm_info_clear_buf (&hw->info, p1, len1); ! 498: } ! 499: ! 500: if (p2 && len2) { ! 501: audio_pcm_info_clear_buf (&hw->info, p2, len2); ! 502: } ! 503: ! 504: dsound_unlock_out (dsb, p1, p2, blen1, blen2); ! 505: } ! 506: ! 507: static void dsound_close (dsound *s) ! 508: { ! 509: HRESULT hr; ! 510: ! 511: if (s->dsound_primary_buffer) { ! 512: hr = IDirectSoundBuffer_Release (s->dsound_primary_buffer); ! 513: if (FAILED (hr)) { ! 514: dsound_logerr (hr, "Could not release primary buffer\n"); ! 515: } ! 516: s->dsound_primary_buffer = NULL; ! 517: } ! 518: } ! 519: ! 520: static int dsound_open (dsound *s) ! 521: { ! 522: int err; ! 523: HRESULT hr; ! 524: WAVEFORMATEX wfx; ! 525: DSBUFFERDESC dsbd; ! 526: HWND hwnd; ! 527: ! 528: hwnd = GetForegroundWindow (); ! 529: hr = IDirectSound_SetCooperativeLevel ( ! 530: s->dsound, ! 531: hwnd, ! 532: DSSCL_PRIORITY ! 533: ); ! 534: ! 535: if (FAILED (hr)) { ! 536: dsound_logerr (hr, "Could not set cooperative level for window %p\n", ! 537: hwnd); ! 538: return -1; ! 539: } ! 540: ! 541: if (!conf.set_primary) { ! 542: return 0; ! 543: } ! 544: ! 545: err = waveformat_from_audio_settings (&wfx, &conf.settings); ! 546: if (err) { ! 547: return -1; ! 548: } ! 549: ! 550: memset (&dsbd, 0, sizeof (dsbd)); ! 551: dsbd.dwSize = sizeof (dsbd); ! 552: dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER; ! 553: dsbd.dwBufferBytes = 0; ! 554: dsbd.lpwfxFormat = NULL; ! 555: ! 556: hr = IDirectSound_CreateSoundBuffer ( ! 557: s->dsound, ! 558: &dsbd, ! 559: &s->dsound_primary_buffer, ! 560: NULL ! 561: ); ! 562: if (FAILED (hr)) { ! 563: dsound_logerr (hr, "Could not create primary playback buffer\n"); ! 564: return -1; ! 565: } ! 566: ! 567: hr = IDirectSoundBuffer_SetFormat (s->dsound_primary_buffer, &wfx); ! 568: if (FAILED (hr)) { ! 569: dsound_logerr (hr, "Could not set primary playback buffer format\n"); ! 570: } ! 571: ! 572: hr = IDirectSoundBuffer_GetFormat ( ! 573: s->dsound_primary_buffer, ! 574: &wfx, ! 575: sizeof (wfx), ! 576: NULL ! 577: ); ! 578: if (FAILED (hr)) { ! 579: dsound_logerr (hr, "Could not get primary playback buffer format\n"); ! 580: goto fail0; ! 581: } ! 582: ! 583: #ifdef DEBUG_DSOUND ! 584: dolog ("Primary\n"); ! 585: print_wave_format (&wfx); ! 586: #endif ! 587: ! 588: err = waveformat_to_audio_settings (&wfx, &s->settings); ! 589: if (err) { ! 590: goto fail0; ! 591: } ! 592: ! 593: return 0; ! 594: ! 595: fail0: ! 596: dsound_close (s); ! 597: return -1; ! 598: } ! 599: ! 600: static int dsound_ctl_out (HWVoiceOut *hw, int cmd, ...) ! 601: { ! 602: HRESULT hr; ! 603: DWORD status; ! 604: DSoundVoiceOut *ds = (DSoundVoiceOut *) hw; ! 605: LPDIRECTSOUNDBUFFER dsb = ds->dsound_buffer; ! 606: ! 607: if (!dsb) { ! 608: dolog ("Attempt to control voice without a buffer\n"); ! 609: return 0; ! 610: } ! 611: ! 612: switch (cmd) { ! 613: case VOICE_ENABLE: ! 614: if (dsound_get_status_out (dsb, &status)) { ! 615: return -1; ! 616: } ! 617: ! 618: if (status & DSBSTATUS_PLAYING) { ! 619: dolog ("warning: Voice is already playing\n"); ! 620: return 0; ! 621: } ! 622: ! 623: dsound_clear_sample (hw, dsb); ! 624: ! 625: hr = IDirectSoundBuffer_Play (dsb, 0, 0, DSBPLAY_LOOPING); ! 626: if (FAILED (hr)) { ! 627: dsound_logerr (hr, "Could not start playing buffer\n"); ! 628: return -1; ! 629: } ! 630: break; ! 631: ! 632: case VOICE_DISABLE: ! 633: if (dsound_get_status_out (dsb, &status)) { ! 634: return -1; ! 635: } ! 636: ! 637: if (status & DSBSTATUS_PLAYING) { ! 638: hr = IDirectSoundBuffer_Stop (dsb); ! 639: if (FAILED (hr)) { ! 640: dsound_logerr (hr, "Could not stop playing buffer\n"); ! 641: return -1; ! 642: } ! 643: } ! 644: else { ! 645: dolog ("warning: Voice is not playing\n"); ! 646: } ! 647: break; ! 648: } ! 649: return 0; ! 650: } ! 651: ! 652: static int dsound_write (SWVoiceOut *sw, void *buf, int len) ! 653: { ! 654: return audio_pcm_sw_write (sw, buf, len); ! 655: } ! 656: ! 657: static int dsound_run_out (HWVoiceOut *hw) ! 658: { ! 659: int err; ! 660: HRESULT hr; ! 661: DSoundVoiceOut *ds = (DSoundVoiceOut *) hw; ! 662: LPDIRECTSOUNDBUFFER dsb = ds->dsound_buffer; ! 663: int live, len, hwshift; ! 664: DWORD blen1, blen2; ! 665: DWORD len1, len2; ! 666: DWORD decr; ! 667: DWORD wpos, ppos, old_pos; ! 668: LPVOID p1, p2; ! 669: int bufsize; ! 670: ! 671: if (!dsb) { ! 672: dolog ("Attempt to run empty with playback buffer\n"); ! 673: return 0; ! 674: } ! 675: ! 676: hwshift = hw->info.shift; ! 677: bufsize = hw->samples << hwshift; ! 678: ! 679: live = audio_pcm_hw_get_live_out (hw); ! 680: ! 681: hr = IDirectSoundBuffer_GetCurrentPosition ( ! 682: dsb, ! 683: &ppos, ! 684: ds->first_time ? &wpos : NULL ! 685: ); ! 686: if (FAILED (hr)) { ! 687: dsound_logerr (hr, "Could not get playback buffer position\n"); ! 688: return 0; ! 689: } ! 690: ! 691: len = live << hwshift; ! 692: ! 693: if (ds->first_time) { ! 694: if (conf.latency_millis) { ! 695: DWORD cur_blat; ! 696: ! 697: cur_blat = audio_ring_dist (wpos, ppos, bufsize); ! 698: ds->first_time = 0; ! 699: old_pos = wpos; ! 700: old_pos += ! 701: millis_to_bytes (&hw->info, conf.latency_millis) - cur_blat; ! 702: old_pos %= bufsize; ! 703: old_pos &= ~hw->info.align; ! 704: } ! 705: else { ! 706: old_pos = wpos; ! 707: } ! 708: #ifdef DEBUG_DSOUND ! 709: ds->played = 0; ! 710: ds->mixed = 0; ! 711: #endif ! 712: } ! 713: else { ! 714: if (ds->old_pos == ppos) { ! 715: #ifdef DEBUG_DSOUND ! 716: dolog ("old_pos == ppos\n"); ! 717: #endif ! 718: return 0; ! 719: } ! 720: ! 721: #ifdef DEBUG_DSOUND ! 722: ds->played += audio_ring_dist (ds->old_pos, ppos, hw->bufsize); ! 723: #endif ! 724: old_pos = ds->old_pos; ! 725: } ! 726: ! 727: if ((old_pos < ppos) && ((old_pos + len) > ppos)) { ! 728: len = ppos - old_pos; ! 729: } ! 730: else { ! 731: if ((old_pos > ppos) && ((old_pos + len) > (ppos + bufsize))) { ! 732: len = bufsize - old_pos + ppos; ! 733: } ! 734: } ! 735: ! 736: if (audio_bug (AUDIO_FUNC, len < 0 || len > bufsize)) { ! 737: dolog ("len=%d bufsize=%d old_pos=%ld ppos=%ld\n", ! 738: len, bufsize, old_pos, ppos); ! 739: return 0; ! 740: } ! 741: ! 742: len &= ~hw->info.align; ! 743: if (!len) { ! 744: return 0; ! 745: } ! 746: ! 747: #ifdef DEBUG_DSOUND ! 748: ds->old_ppos = ppos; ! 749: #endif ! 750: err = dsound_lock_out ( ! 751: dsb, ! 752: &hw->info, ! 753: old_pos, ! 754: len, ! 755: &p1, &p2, ! 756: &blen1, &blen2, ! 757: 0 ! 758: ); ! 759: if (err) { ! 760: return 0; ! 761: } ! 762: ! 763: len1 = blen1 >> hwshift; ! 764: len2 = blen2 >> hwshift; ! 765: decr = len1 + len2; ! 766: ! 767: if (p1 && len1) { ! 768: dsound_write_sample (hw, p1, len1); ! 769: } ! 770: ! 771: if (p2 && len2) { ! 772: dsound_write_sample (hw, p2, len2); ! 773: } ! 774: ! 775: dsound_unlock_out (dsb, p1, p2, blen1, blen2); ! 776: ds->old_pos = (old_pos + (decr << hwshift)) % bufsize; ! 777: ! 778: #ifdef DEBUG_DSOUND ! 779: ds->mixed += decr << hwshift; ! 780: ! 781: dolog ("played %lu mixed %lu diff %ld sec %f\n", ! 782: ds->played, ! 783: ds->mixed, ! 784: ds->mixed - ds->played, ! 785: abs (ds->mixed - ds->played) / (double) hw->info.bytes_per_second); ! 786: #endif ! 787: return decr; ! 788: } ! 789: ! 790: static int dsound_ctl_in (HWVoiceIn *hw, int cmd, ...) ! 791: { ! 792: HRESULT hr; ! 793: DWORD status; ! 794: DSoundVoiceIn *ds = (DSoundVoiceIn *) hw; ! 795: LPDIRECTSOUNDCAPTUREBUFFER dscb = ds->dsound_capture_buffer; ! 796: ! 797: if (!dscb) { ! 798: dolog ("Attempt to control capture voice without a buffer\n"); ! 799: return -1; ! 800: } ! 801: ! 802: switch (cmd) { ! 803: case VOICE_ENABLE: ! 804: if (dsound_get_status_in (dscb, &status)) { ! 805: return -1; ! 806: } ! 807: ! 808: if (status & DSCBSTATUS_CAPTURING) { ! 809: dolog ("warning: Voice is already capturing\n"); ! 810: return 0; ! 811: } ! 812: ! 813: /* clear ?? */ ! 814: ! 815: hr = IDirectSoundCaptureBuffer_Start (dscb, DSCBSTART_LOOPING); ! 816: if (FAILED (hr)) { ! 817: dsound_logerr (hr, "Could not start capturing\n"); ! 818: return -1; ! 819: } ! 820: break; ! 821: ! 822: case VOICE_DISABLE: ! 823: if (dsound_get_status_in (dscb, &status)) { ! 824: return -1; ! 825: } ! 826: ! 827: if (status & DSCBSTATUS_CAPTURING) { ! 828: hr = IDirectSoundCaptureBuffer_Stop (dscb); ! 829: if (FAILED (hr)) { ! 830: dsound_logerr (hr, "Could not stop capturing\n"); ! 831: return -1; ! 832: } ! 833: } ! 834: else { ! 835: dolog ("warning: Voice is not capturing\n"); ! 836: } ! 837: break; ! 838: } ! 839: return 0; ! 840: } ! 841: ! 842: static int dsound_read (SWVoiceIn *sw, void *buf, int len) ! 843: { ! 844: return audio_pcm_sw_read (sw, buf, len); ! 845: } ! 846: ! 847: static int dsound_run_in (HWVoiceIn *hw) ! 848: { ! 849: int err; ! 850: HRESULT hr; ! 851: DSoundVoiceIn *ds = (DSoundVoiceIn *) hw; ! 852: LPDIRECTSOUNDCAPTUREBUFFER dscb = ds->dsound_capture_buffer; ! 853: int live, len, dead; ! 854: DWORD blen1, blen2; ! 855: DWORD len1, len2; ! 856: DWORD decr; ! 857: DWORD cpos, rpos; ! 858: LPVOID p1, p2; ! 859: int hwshift; ! 860: ! 861: if (!dscb) { ! 862: dolog ("Attempt to run without capture buffer\n"); ! 863: return 0; ! 864: } ! 865: ! 866: hwshift = hw->info.shift; ! 867: ! 868: live = audio_pcm_hw_get_live_in (hw); ! 869: dead = hw->samples - live; ! 870: if (!dead) { ! 871: return 0; ! 872: } ! 873: ! 874: hr = IDirectSoundCaptureBuffer_GetCurrentPosition ( ! 875: dscb, ! 876: &cpos, ! 877: ds->first_time ? &rpos : NULL ! 878: ); ! 879: if (FAILED (hr)) { ! 880: dsound_logerr (hr, "Could not get capture buffer position\n"); ! 881: return 0; ! 882: } ! 883: ! 884: if (ds->first_time) { ! 885: ds->first_time = 0; ! 886: if (rpos & hw->info.align) { ! 887: ldebug ("warning: Misaligned capture read position %ld(%d)\n", ! 888: rpos, hw->info.align); ! 889: } ! 890: hw->wpos = rpos >> hwshift; ! 891: } ! 892: ! 893: if (cpos & hw->info.align) { ! 894: ldebug ("warning: Misaligned capture position %ld(%d)\n", ! 895: cpos, hw->info.align); ! 896: } ! 897: cpos >>= hwshift; ! 898: ! 899: len = audio_ring_dist (cpos, hw->wpos, hw->samples); ! 900: if (!len) { ! 901: return 0; ! 902: } ! 903: len = audio_MIN (len, dead); ! 904: ! 905: err = dsound_lock_in ( ! 906: dscb, ! 907: &hw->info, ! 908: hw->wpos << hwshift, ! 909: len << hwshift, ! 910: &p1, ! 911: &p2, ! 912: &blen1, ! 913: &blen2, ! 914: 0 ! 915: ); ! 916: if (err) { ! 917: return 0; ! 918: } ! 919: ! 920: len1 = blen1 >> hwshift; ! 921: len2 = blen2 >> hwshift; ! 922: decr = len1 + len2; ! 923: ! 924: if (p1 && len1) { ! 925: hw->conv (hw->conv_buf + hw->wpos, p1, len1, &nominal_volume); ! 926: } ! 927: ! 928: if (p2 && len2) { ! 929: hw->conv (hw->conv_buf, p2, len2, &nominal_volume); ! 930: } ! 931: ! 932: dsound_unlock_in (dscb, p1, p2, blen1, blen2); ! 933: hw->wpos = (hw->wpos + decr) % hw->samples; ! 934: return decr; ! 935: } ! 936: ! 937: static void dsound_audio_fini (void *opaque) ! 938: { ! 939: HRESULT hr; ! 940: dsound *s = opaque; ! 941: ! 942: if (!s->dsound) { ! 943: return; ! 944: } ! 945: ! 946: hr = IDirectSound_Release (s->dsound); ! 947: if (FAILED (hr)) { ! 948: dsound_logerr (hr, "Could not release DirectSound\n"); ! 949: } ! 950: s->dsound = NULL; ! 951: ! 952: if (!s->dsound_capture) { ! 953: return; ! 954: } ! 955: ! 956: hr = IDirectSoundCapture_Release (s->dsound_capture); ! 957: if (FAILED (hr)) { ! 958: dsound_logerr (hr, "Could not release DirectSoundCapture\n"); ! 959: } ! 960: s->dsound_capture = NULL; ! 961: } ! 962: ! 963: static void *dsound_audio_init (void) ! 964: { ! 965: int err; ! 966: HRESULT hr; ! 967: dsound *s = &glob_dsound; ! 968: ! 969: hr = CoInitialize (NULL); ! 970: if (FAILED (hr)) { ! 971: dsound_logerr (hr, "Could not initialize COM\n"); ! 972: return NULL; ! 973: } ! 974: ! 975: hr = CoCreateInstance ( ! 976: &CLSID_DirectSound, ! 977: NULL, ! 978: CLSCTX_ALL, ! 979: &IID_IDirectSound, ! 980: (void **) &s->dsound ! 981: ); ! 982: if (FAILED (hr)) { ! 983: dsound_logerr (hr, "Could not create DirectSound instance\n"); ! 984: return NULL; ! 985: } ! 986: ! 987: hr = IDirectSound_Initialize (s->dsound, NULL); ! 988: if (FAILED (hr)) { ! 989: dsound_logerr (hr, "Could not initialize DirectSound\n"); ! 990: return NULL; ! 991: } ! 992: ! 993: hr = CoCreateInstance ( ! 994: &CLSID_DirectSoundCapture, ! 995: NULL, ! 996: CLSCTX_ALL, ! 997: &IID_IDirectSoundCapture, ! 998: (void **) &s->dsound_capture ! 999: ); ! 1000: if (FAILED (hr)) { ! 1001: dsound_logerr (hr, "Could not create DirectSoundCapture instance\n"); ! 1002: } ! 1003: else { ! 1004: hr = IDirectSoundCapture_Initialize (s->dsound_capture, NULL); ! 1005: if (FAILED (hr)) { ! 1006: dsound_logerr (hr, "Could not initialize DirectSoundCapture\n"); ! 1007: ! 1008: hr = IDirectSoundCapture_Release (s->dsound_capture); ! 1009: if (FAILED (hr)) { ! 1010: dsound_logerr (hr, "Could not release DirectSoundCapture\n"); ! 1011: } ! 1012: s->dsound_capture = NULL; ! 1013: } ! 1014: } ! 1015: ! 1016: err = dsound_open (s); ! 1017: if (err) { ! 1018: dsound_audio_fini (s); ! 1019: return NULL; ! 1020: } ! 1021: ! 1022: return s; ! 1023: } ! 1024: ! 1025: static struct audio_option dsound_options[] = { ! 1026: {"LOCK_RETRIES", AUD_OPT_INT, &conf.lock_retries, ! 1027: "Number of times to attempt locking the buffer", NULL, 0}, ! 1028: {"RESTOURE_RETRIES", AUD_OPT_INT, &conf.restore_retries, ! 1029: "Number of times to attempt restoring the buffer", NULL, 0}, ! 1030: {"GETSTATUS_RETRIES", AUD_OPT_INT, &conf.getstatus_retries, ! 1031: "Number of times to attempt getting status of the buffer", NULL, 0}, ! 1032: {"SET_PRIMARY", AUD_OPT_BOOL, &conf.set_primary, ! 1033: "Set the parameters of primary buffer", NULL, 0}, ! 1034: {"LATENCY_MILLIS", AUD_OPT_INT, &conf.latency_millis, ! 1035: "(undocumented)", NULL, 0}, ! 1036: {"PRIMARY_FREQ", AUD_OPT_INT, &conf.settings.freq, ! 1037: "Primary buffer frequency", NULL, 0}, ! 1038: {"PRIMARY_CHANNELS", AUD_OPT_INT, &conf.settings.nchannels, ! 1039: "Primary buffer number of channels (1 - mono, 2 - stereo)", NULL, 0}, ! 1040: {"PRIMARY_FMT", AUD_OPT_FMT, &conf.settings.fmt, ! 1041: "Primary buffer format", NULL, 0}, ! 1042: {"BUFSIZE_OUT", AUD_OPT_INT, &conf.bufsize_out, ! 1043: "(undocumented)", NULL, 0}, ! 1044: {"BUFSIZE_IN", AUD_OPT_INT, &conf.bufsize_in, ! 1045: "(undocumented)", NULL, 0}, ! 1046: {NULL, 0, NULL, NULL, NULL, 0} ! 1047: }; ! 1048: ! 1049: static struct audio_pcm_ops dsound_pcm_ops = { ! 1050: dsound_init_out, ! 1051: dsound_fini_out, ! 1052: dsound_run_out, ! 1053: dsound_write, ! 1054: dsound_ctl_out, ! 1055: ! 1056: dsound_init_in, ! 1057: dsound_fini_in, ! 1058: dsound_run_in, ! 1059: dsound_read, ! 1060: dsound_ctl_in ! 1061: }; ! 1062: ! 1063: struct audio_driver dsound_audio_driver = { ! 1064: INIT_FIELD (name = ) "dsound", ! 1065: INIT_FIELD (descr = ) ! 1066: "DirectSound http://wikipedia.org/wiki/DirectSound", ! 1067: INIT_FIELD (options = ) dsound_options, ! 1068: INIT_FIELD (init = ) dsound_audio_init, ! 1069: INIT_FIELD (fini = ) dsound_audio_fini, ! 1070: INIT_FIELD (pcm_ops = ) &dsound_pcm_ops, ! 1071: INIT_FIELD (can_be_default = ) 1, ! 1072: INIT_FIELD (max_voices_out = ) INT_MAX, ! 1073: INIT_FIELD (max_voices_in = ) 1, ! 1074: INIT_FIELD (voice_size_out = ) sizeof (DSoundVoiceOut), ! 1075: INIT_FIELD (voice_size_in = ) sizeof (DSoundVoiceIn) ! 1076: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.