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