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 }; 1090