1 /* 2 * QEMU "simple" Windows audio driver 3 * 4 * Copyright (c) 2007 The Android Open Source Project 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 #define WIN32_LEAN_AND_MEAN 25 #include <windows.h> 26 #include <mmsystem.h> 27 28 #define AUDIO_CAP "winaudio" 29 #include "audio_int.h" 30 31 /* define DEBUG to 1 to dump audio debugging info at runtime to stderr */ 32 #define DEBUG 0 33 34 #if 1 35 # define D_ACTIVE 1 36 #else 37 # define D_ACTIVE DEBUG 38 #endif 39 40 #if DEBUG 41 # define D(...) do{ if (D_ACTIVE) printf(__VA_ARGS__); } while(0) 42 #else 43 # define D(...) ((void)0) 44 #endif 45 46 static struct { 47 int nb_samples; 48 } conf = { 49 1024 50 }; 51 52 #if DEBUG 53 int64_t start_time; 54 int64_t last_time; 55 #endif 56 57 #define NUM_OUT_BUFFERS 8 /* must be at least 2 */ 58 59 /** COMMON UTILITIES 60 **/ 61 62 #if DEBUG 63 static void 64 dump_mmerror( const char* func, MMRESULT error ) 65 { 66 const char* reason = NULL; 67 68 fprintf(stderr, "%s returned error: ", func); 69 switch (error) { 70 case MMSYSERR_ALLOCATED: reason="specified resource is already allocated"; break; 71 case MMSYSERR_BADDEVICEID: reason="bad device id"; break; 72 case MMSYSERR_NODRIVER: reason="no driver is present"; break; 73 case MMSYSERR_NOMEM: reason="unable to allocate or lock memory"; break; 74 case WAVERR_BADFORMAT: reason="unsupported waveform-audio format"; break; 75 case WAVERR_SYNC: reason="device is synchronous"; break; 76 default: 77 fprintf(stderr, "unknown(%d)\n", error); 78 } 79 if (reason) 80 fprintf(stderr, "%s\n", reason); 81 } 82 #else 83 # define dump_mmerror(func,error) ((void)0) 84 #endif 85 86 87 /** AUDIO OUT 88 **/ 89 90 typedef struct WinAudioOut { 91 HWVoiceOut hw; 92 HWAVEOUT waveout; 93 int silence; 94 CRITICAL_SECTION lock; 95 unsigned char* buffer_bytes; 96 WAVEHDR buffers[ NUM_OUT_BUFFERS ]; 97 int write_index; /* starting first writable buffer */ 98 int write_count; /* available writable buffers count */ 99 int write_pos; /* position in current writable buffer */ 100 int write_size; /* size in bytes of each buffer */ 101 } WinAudioOut; 102 103 /* The Win32 callback that is called when a buffer has finished playing */ 104 static void CALLBACK 105 winaudio_out_buffer_done (HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance, 106 DWORD dwParam1, DWORD dwParam2) 107 { 108 WinAudioOut* s = (WinAudioOut*) dwInstance; 109 110 /* Only service "buffer done playing" messages */ 111 if ( uMsg != WOM_DONE ) 112 return; 113 114 /* Signal that we are done playing a buffer */ 115 EnterCriticalSection( &s->lock ); 116 if (s->write_count < NUM_OUT_BUFFERS) 117 s->write_count += 1; 118 LeaveCriticalSection( &s->lock ); 119 } 120 121 static int 122 winaudio_out_write (SWVoiceOut *sw, void *buf, int len) 123 { 124 return audio_pcm_sw_write (sw, buf, len); 125 } 126 127 static void 128 winaudio_out_fini (HWVoiceOut *hw) 129 { 130 WinAudioOut* s = (WinAudioOut*) hw; 131 int i; 132 133 if (s->waveout) { 134 waveOutReset(s->waveout); 135 s->waveout = 0; 136 } 137 138 for ( i=0; i<NUM_OUT_BUFFERS; ++i ) { 139 if ( s->buffers[i].dwUser != 0xFFFF ) { 140 waveOutUnprepareHeader( 141 s->waveout, &s->buffers[i], sizeof(s->buffers[i]) ); 142 s->buffers[i].dwUser = 0xFFFF; 143 } 144 } 145 146 if (s->buffer_bytes != NULL) { 147 g_free(s->buffer_bytes); 148 s->buffer_bytes = NULL; 149 } 150 151 if (s->waveout) { 152 waveOutClose(s->waveout); 153 s->waveout = NULL; 154 } 155 } 156 157 158 static int 159 winaudio_out_init (HWVoiceOut *hw, struct audsettings *as) 160 { 161 WinAudioOut* s = (WinAudioOut*) hw; 162 MMRESULT result; 163 WAVEFORMATEX format; 164 int shift, i, samples_size; 165 166 s->waveout = NULL; 167 InitializeCriticalSection( &s->lock ); 168 for (i = 0; i < NUM_OUT_BUFFERS; i++) { 169 s->buffers[i].dwUser = 0xFFFF; 170 } 171 s->buffer_bytes = NULL; 172 173 /* compute desired wave output format */ 174 format.wFormatTag = WAVE_FORMAT_PCM; 175 format.nChannels = as->nchannels; 176 format.nSamplesPerSec = as->freq; 177 format.nAvgBytesPerSec = as->freq*as->nchannels; 178 179 s->silence = 0; 180 181 switch (as->fmt) { 182 case AUD_FMT_S8: shift = 0; break; 183 case AUD_FMT_U8: shift = 0; s->silence = 0x80; break; 184 case AUD_FMT_S16: shift = 1; break; 185 case AUD_FMT_U16: shift = 1; s->silence = 0x8000; break; 186 default: 187 fprintf(stderr, "qemu: winaudio: Bad output audio format: %d\n", 188 as->fmt); 189 return -1; 190 } 191 192 format.nAvgBytesPerSec = (format.nSamplesPerSec & format.nChannels) << shift; 193 format.nBlockAlign = format.nChannels << shift; 194 format.wBitsPerSample = 8 << shift; 195 format.cbSize = 0; 196 197 /* open the wave out device */ 198 result = waveOutOpen( &s->waveout, WAVE_MAPPER, &format, 199 (DWORD_PTR)winaudio_out_buffer_done, (DWORD_PTR) hw, 200 CALLBACK_FUNCTION); 201 if ( result != MMSYSERR_NOERROR ) { 202 dump_mmerror( "qemu: winaudio: waveOutOpen()", result); 203 return -1; 204 } 205 206 samples_size = format.nBlockAlign * conf.nb_samples; 207 s->buffer_bytes = g_malloc( NUM_OUT_BUFFERS * samples_size ); 208 if (s->buffer_bytes == NULL) { 209 waveOutClose( s->waveout ); 210 s->waveout = NULL; 211 fprintf(stderr, "not enough memory for Windows audio buffers\n"); 212 return -1; 213 } 214 215 for (i = 0; i < NUM_OUT_BUFFERS; i++) { 216 memset( &s->buffers[i], 0, sizeof(s->buffers[i]) ); 217 s->buffers[i].lpData = (LPSTR)(s->buffer_bytes + i*samples_size); 218 s->buffers[i].dwBufferLength = samples_size; 219 s->buffers[i].dwFlags = WHDR_DONE; 220 221 result = waveOutPrepareHeader( s->waveout, &s->buffers[i], 222 sizeof(s->buffers[i]) ); 223 if ( result != MMSYSERR_NOERROR ) { 224 dump_mmerror("waveOutPrepareHeader()", result); 225 return -1; 226 } 227 } 228 229 #if DEBUG 230 /* Check the sound device we retrieved */ 231 { 232 WAVEOUTCAPS caps; 233 234 result = waveOutGetDevCaps((UINT) s->waveout, &caps, sizeof(caps)); 235 if ( result != MMSYSERR_NOERROR ) { 236 dump_mmerror("waveOutGetDevCaps()", result); 237 } else 238 printf("Audio out device: %s\n", caps.szPname); 239 } 240 #endif 241 242 audio_pcm_init_info (&hw->info, as); 243 hw->samples = conf.nb_samples*2; 244 245 s->write_index = 0; 246 s->write_count = NUM_OUT_BUFFERS; 247 s->write_pos = 0; 248 s->write_size = samples_size; 249 return 0; 250 } 251 252 253 static int 254 winaudio_out_run (HWVoiceOut *hw, int live) 255 { 256 WinAudioOut* s = (WinAudioOut*) hw; 257 int played = 0; 258 int has_buffer; 259 260 if (!live) { 261 return 0; 262 } 263 264 EnterCriticalSection( &s->lock ); 265 has_buffer = (s->write_count > 0); 266 LeaveCriticalSection( &s->lock ); 267 268 if (has_buffer) { 269 while (live > 0) { 270 WAVEHDR* wav_buffer = s->buffers + s->write_index; 271 int wav_bytes = (s->write_size - s->write_pos); 272 int wav_samples = audio_MIN(wav_bytes >> hw->info.shift, live); 273 int hw_samples = audio_MIN(hw->samples - hw->rpos, live); 274 struct st_sample* src = hw->mix_buf + hw->rpos; 275 uint8_t* dst = (uint8_t*)wav_buffer->lpData + s->write_pos; 276 277 if (wav_samples > hw_samples) { 278 wav_samples = hw_samples; 279 } 280 281 wav_bytes = wav_samples << hw->info.shift; 282 283 //D("run_out: buffer:%d pos:%d size:%d wsamples:%d wbytes:%d live:%d rpos:%d hwsamples:%d\n", s->write_index, 284 // s->write_pos, s->write_size, wav_samples, wav_bytes, live, hw->rpos, hw->samples); 285 hw->clip (dst, src, wav_samples); 286 hw->rpos += wav_samples; 287 if (hw->rpos >= hw->samples) 288 hw->rpos -= hw->samples; 289 290 live -= wav_samples; 291 played += wav_samples; 292 s->write_pos += wav_bytes; 293 if (s->write_pos == s->write_size) { 294 #if xxDEBUG 295 int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - start_time; 296 int64_t diff = now - last_time; 297 298 D("run_out: (%7.3f:%7d):waveOutWrite buffer:%d\n", 299 now/1e9, (now-last_time)/1e9, s->write_index); 300 last_time = now; 301 #endif 302 waveOutWrite( s->waveout, wav_buffer, sizeof(*wav_buffer) ); 303 s->write_pos = 0; 304 s->write_index += 1; 305 if (s->write_index == NUM_OUT_BUFFERS) 306 s->write_index = 0; 307 308 EnterCriticalSection( &s->lock ); 309 if (--s->write_count == 0) { 310 live = 0; 311 } 312 LeaveCriticalSection( &s->lock ); 313 } 314 } 315 316 } 317 return played; 318 } 319 320 static int 321 winaudio_out_ctl (HWVoiceOut *hw, int cmd, ...) 322 { 323 WinAudioOut* s = (WinAudioOut*) hw; 324 325 switch (cmd) { 326 case VOICE_ENABLE: 327 waveOutRestart( s->waveout ); 328 break; 329 330 case VOICE_DISABLE: 331 waveOutPause( s->waveout ); 332 break; 333 } 334 return 0; 335 } 336 337 /** AUDIO IN 338 **/ 339 340 #define NUM_IN_BUFFERS 2 341 342 typedef struct WinAudioIn { 343 HWVoiceIn hw; 344 HWAVEIN wavein; 345 CRITICAL_SECTION lock; 346 unsigned char* buffer_bytes; 347 WAVEHDR buffers[ NUM_IN_BUFFERS ]; 348 int read_index; 349 int read_count; 350 int read_pos; 351 int read_size; 352 } WinAudioIn; 353 354 /* The Win32 callback that is called when a buffer has finished playing */ 355 static void CALLBACK 356 winaudio_in_buffer_done (HWAVEIN hwi, UINT uMsg, DWORD_PTR dwInstance, 357 DWORD dwParam1, DWORD dwParam2) 358 { 359 WinAudioIn* s = (WinAudioIn*) dwInstance; 360 361 /* Only service "buffer done playing" messages */ 362 if ( uMsg != WIM_DATA ) 363 return; 364 365 /* Signal that we are done playing a buffer */ 366 EnterCriticalSection( &s->lock ); 367 if (s->read_count < NUM_IN_BUFFERS) 368 s->read_count += 1; 369 //D(".%c",s->read_count + '0'); fflush(stdout); 370 LeaveCriticalSection( &s->lock ); 371 } 372 373 static void 374 winaudio_in_fini (HWVoiceIn *hw) 375 { 376 WinAudioIn* s = (WinAudioIn*) hw; 377 int i; 378 379 if (s->wavein) { 380 waveInReset(s->wavein); 381 s->wavein = 0; 382 } 383 384 for ( i=0; i<NUM_IN_BUFFERS; ++i ) { 385 if ( s->buffers[i].dwUser != 0xFFFF ) { 386 waveInUnprepareHeader( 387 s->wavein, &s->buffers[i], sizeof(s->buffers[i]) ); 388 s->buffers[i].dwUser = 0xFFFF; 389 } 390 } 391 392 if (s->buffer_bytes != NULL) { 393 g_free(s->buffer_bytes); 394 s->buffer_bytes = NULL; 395 } 396 397 if (s->wavein) { 398 waveInClose(s->wavein); 399 s->wavein = NULL; 400 } 401 } 402 403 404 static int 405 winaudio_in_init (HWVoiceIn *hw, struct audsettings *as) 406 { 407 WinAudioIn* s = (WinAudioIn*) hw; 408 MMRESULT result; 409 WAVEFORMATEX format; 410 int shift, i, samples_size; 411 412 s->wavein = NULL; 413 InitializeCriticalSection( &s->lock ); 414 for (i = 0; i < NUM_IN_BUFFERS; i++) { 415 s->buffers[i].dwUser = 0xFFFF; 416 } 417 s->buffer_bytes = NULL; 418 419 /* compute desired wave input format */ 420 format.wFormatTag = WAVE_FORMAT_PCM; 421 format.nChannels = as->nchannels; 422 format.nSamplesPerSec = as->freq; 423 format.nAvgBytesPerSec = as->freq*as->nchannels; 424 425 switch (as->fmt) { 426 case AUD_FMT_S8: shift = 0; break; 427 case AUD_FMT_U8: shift = 0; break; 428 case AUD_FMT_S16: shift = 1; break; 429 case AUD_FMT_U16: shift = 1; break; 430 default: 431 fprintf(stderr, "qemu: winaudio: Bad input audio format: %d\n", 432 as->fmt); 433 return -1; 434 } 435 436 format.nAvgBytesPerSec = (format.nSamplesPerSec * format.nChannels) << shift; 437 format.nBlockAlign = format.nChannels << shift; 438 format.wBitsPerSample = 8 << shift; 439 format.cbSize = 0; 440 441 /* open the wave in device */ 442 result = waveInOpen( &s->wavein, WAVE_MAPPER, &format, 443 (DWORD_PTR)winaudio_in_buffer_done, (DWORD_PTR) hw, 444 CALLBACK_FUNCTION); 445 if ( result != MMSYSERR_NOERROR ) { 446 dump_mmerror( "qemu: winaudio: waveInOpen()", result); 447 return -1; 448 } 449 450 samples_size = format.nBlockAlign * conf.nb_samples; 451 s->buffer_bytes = g_malloc( NUM_IN_BUFFERS * samples_size ); 452 if (s->buffer_bytes == NULL) { 453 waveInClose( s->wavein ); 454 s->wavein = NULL; 455 fprintf(stderr, "not enough memory for Windows audio buffers\n"); 456 return -1; 457 } 458 459 for (i = 0; i < NUM_IN_BUFFERS; i++) { 460 memset( &s->buffers[i], 0, sizeof(s->buffers[i]) ); 461 s->buffers[i].lpData = (LPSTR)(s->buffer_bytes + i*samples_size); 462 s->buffers[i].dwBufferLength = samples_size; 463 s->buffers[i].dwFlags = WHDR_DONE; 464 465 result = waveInPrepareHeader( s->wavein, &s->buffers[i], 466 sizeof(s->buffers[i]) ); 467 if ( result != MMSYSERR_NOERROR ) { 468 dump_mmerror("waveInPrepareHeader()", result); 469 return -1; 470 } 471 472 result = waveInAddBuffer( s->wavein, &s->buffers[i], 473 sizeof(s->buffers[i]) ); 474 if ( result != MMSYSERR_NOERROR ) { 475 dump_mmerror("waveInAddBuffer()", result); 476 return -1; 477 } 478 } 479 480 #if DEBUG 481 /* Check the sound device we retrieved */ 482 { 483 WAVEINCAPS caps; 484 485 result = waveInGetDevCaps((UINT) s->wavein, &caps, sizeof(caps)); 486 if ( result != MMSYSERR_NOERROR ) { 487 dump_mmerror("waveInGetDevCaps()", result); 488 } else 489 printf("Audio in device: %s\n", caps.szPname); 490 } 491 #endif 492 493 audio_pcm_init_info (&hw->info, as); 494 hw->samples = conf.nb_samples*2; 495 496 s->read_index = 0; 497 s->read_count = 0; 498 s->read_pos = 0; 499 s->read_size = samples_size; 500 return 0; 501 } 502 503 504 /* report the number of captured samples to the audio subsystem */ 505 static int 506 winaudio_in_run (HWVoiceIn *hw) 507 { 508 WinAudioIn* s = (WinAudioIn*) hw; 509 int captured = 0; 510 int has_buffer; 511 int live = hw->samples - hw->total_samples_captured; 512 513 if (!live) { 514 #if 0 515 static int counter; 516 if (++counter == 100) { 517 D("0"); fflush(stdout); 518 counter = 0; 519 } 520 #endif 521 return 0; 522 } 523 524 EnterCriticalSection( &s->lock ); 525 has_buffer = (s->read_count > 0); 526 LeaveCriticalSection( &s->lock ); 527 528 if (has_buffer > 0) { 529 while (live > 0) { 530 WAVEHDR* wav_buffer = s->buffers + s->read_index; 531 int wav_bytes = (s->read_size - s->read_pos); 532 int wav_samples = audio_MIN(wav_bytes >> hw->info.shift, live); 533 int hw_samples = audio_MIN(hw->samples - hw->wpos, live); 534 struct st_sample* dst = hw->conv_buf + hw->wpos; 535 uint8_t* src = (uint8_t*)wav_buffer->lpData + s->read_pos; 536 537 if (wav_samples > hw_samples) { 538 wav_samples = hw_samples; 539 } 540 541 wav_bytes = wav_samples << hw->info.shift; 542 543 D("%s: buffer:%d pos:%d size:%d wsamples:%d wbytes:%d live:%d wpos:%d hwsamples:%d\n", 544 __FUNCTION__, s->read_index, s->read_pos, s->read_size, wav_samples, wav_bytes, live, 545 hw->wpos, hw->samples); 546 547 hw->conv(dst, src, wav_samples, &nominal_volume); 548 549 hw->wpos += wav_samples; 550 if (hw->wpos >= hw->samples) 551 hw->wpos -= hw->samples; 552 553 live -= wav_samples; 554 captured += wav_samples; 555 s->read_pos += wav_bytes; 556 if (s->read_pos == s->read_size) { 557 s->read_pos = 0; 558 s->read_index += 1; 559 if (s->read_index == NUM_IN_BUFFERS) 560 s->read_index = 0; 561 562 waveInAddBuffer( s->wavein, wav_buffer, sizeof(*wav_buffer) ); 563 564 EnterCriticalSection( &s->lock ); 565 if (--s->read_count == 0) { 566 live = 0; 567 } 568 LeaveCriticalSection( &s->lock ); 569 } 570 } 571 } 572 return captured; 573 } 574 575 576 static int 577 winaudio_in_read (SWVoiceIn *sw, void *buf, int len) 578 { 579 int ret = audio_pcm_sw_read (sw, buf, len); 580 if (ret > 0) 581 D("%s: (%d) returned %d\n", __FUNCTION__, len, ret); 582 return ret; 583 } 584 585 586 static int 587 winaudio_in_ctl (HWVoiceIn *hw, int cmd, ...) 588 { 589 WinAudioIn* s = (WinAudioIn*) hw; 590 591 switch (cmd) { 592 case VOICE_ENABLE: 593 D("%s: enable audio in\n", __FUNCTION__); 594 waveInStart( s->wavein ); 595 break; 596 597 case VOICE_DISABLE: 598 D("%s: disable audio in\n", __FUNCTION__); 599 waveInStop( s->wavein ); 600 break; 601 } 602 return 0; 603 } 604 605 /** AUDIO STATE 606 **/ 607 608 typedef struct WinAudioState { 609 int dummy; 610 } WinAudioState; 611 612 static WinAudioState g_winaudio; 613 614 static void* 615 winaudio_init(void) 616 { 617 WinAudioState* s = &g_winaudio; 618 619 #if DEBUG 620 start_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 621 last_time = 0; 622 #endif 623 624 return s; 625 } 626 627 628 static void 629 winaudio_fini (void *opaque) 630 { 631 } 632 633 static struct audio_option winaudio_options[] = { 634 {"SAMPLES", AUD_OPT_INT, &conf.nb_samples, 635 "Size of Windows audio buffer in samples", NULL, 0}, 636 {NULL, 0, NULL, NULL, NULL, 0} 637 }; 638 639 static struct audio_pcm_ops winaudio_pcm_ops = { 640 winaudio_out_init, 641 winaudio_out_fini, 642 winaudio_out_run, 643 winaudio_out_write, 644 winaudio_out_ctl, 645 646 winaudio_in_init, 647 winaudio_in_fini, 648 winaudio_in_run, 649 winaudio_in_read, 650 winaudio_in_ctl 651 }; 652 653 struct audio_driver win_audio_driver = { 654 INIT_FIELD (name = ) "winaudio", 655 INIT_FIELD (descr = ) "Windows wave audio", 656 INIT_FIELD (options = ) winaudio_options, 657 INIT_FIELD (init = ) winaudio_init, 658 INIT_FIELD (fini = ) winaudio_fini, 659 INIT_FIELD (pcm_ops = ) &winaudio_pcm_ops, 660 INIT_FIELD (can_be_default = ) 1, 661 INIT_FIELD (max_voices_out = ) 1, 662 INIT_FIELD (max_voices_in = ) 1, 663 INIT_FIELD (voice_size_out = ) sizeof (WinAudioOut), 664 INIT_FIELD (voice_size_in = ) sizeof (WinAudioIn) 665 }; 666