|
|
1.1 ! root 1: /* public domain */ ! 2: ! 3: #include "qemu-common.h" ! 4: #include "sysemu.h" ! 5: #include "audio.h" ! 6: ! 7: #define AUDIO_CAP "winwave" ! 8: #include "audio_int.h" ! 9: ! 10: #include <windows.h> ! 11: #include <mmsystem.h> ! 12: ! 13: #include "audio_win_int.h" ! 14: ! 15: static struct { ! 16: int dac_headers; ! 17: int dac_samples; ! 18: int adc_headers; ! 19: int adc_samples; ! 20: } conf = { ! 21: .dac_headers = 4, ! 22: .dac_samples = 1024, ! 23: .adc_headers = 4, ! 24: .adc_samples = 1024 ! 25: }; ! 26: ! 27: typedef struct { ! 28: HWVoiceOut hw; ! 29: HWAVEOUT hwo; ! 30: WAVEHDR *hdrs; ! 31: HANDLE event; ! 32: void *pcm_buf; ! 33: int avail; ! 34: int pending; ! 35: int curhdr; ! 36: int paused; ! 37: CRITICAL_SECTION crit_sect; ! 38: } WaveVoiceOut; ! 39: ! 40: typedef struct { ! 41: HWVoiceIn hw; ! 42: HWAVEIN hwi; ! 43: WAVEHDR *hdrs; ! 44: HANDLE event; ! 45: void *pcm_buf; ! 46: int curhdr; ! 47: int paused; ! 48: int rpos; ! 49: int avail; ! 50: CRITICAL_SECTION crit_sect; ! 51: } WaveVoiceIn; ! 52: ! 53: static void winwave_log_mmresult (MMRESULT mr) ! 54: { ! 55: const char *str = "BUG"; ! 56: ! 57: switch (mr) { ! 58: case MMSYSERR_NOERROR: ! 59: str = "Success"; ! 60: break; ! 61: ! 62: case MMSYSERR_INVALHANDLE: ! 63: str = "Specified device handle is invalid"; ! 64: break; ! 65: ! 66: case MMSYSERR_BADDEVICEID: ! 67: str = "Specified device id is out of range"; ! 68: break; ! 69: ! 70: case MMSYSERR_NODRIVER: ! 71: str = "No device driver is present"; ! 72: break; ! 73: ! 74: case MMSYSERR_NOMEM: ! 75: str = "Unable to allocate or locl memory"; ! 76: break; ! 77: ! 78: case WAVERR_SYNC: ! 79: str = "Device is synchronous but waveOutOpen was called " ! 80: "without using the WINWAVE_ALLOWSYNC flag"; ! 81: break; ! 82: ! 83: case WAVERR_UNPREPARED: ! 84: str = "The data block pointed to by the pwh parameter " ! 85: "hasn't been prepared"; ! 86: break; ! 87: ! 88: case WAVERR_STILLPLAYING: ! 89: str = "There are still buffers in the queue"; ! 90: break; ! 91: ! 92: default: ! 93: dolog ("Reason: Unknown (MMRESULT %#x)\n", mr); ! 94: return; ! 95: } ! 96: ! 97: dolog ("Reason: %s\n", str); ! 98: } ! 99: ! 100: static void GCC_FMT_ATTR (2, 3) winwave_logerr ( ! 101: MMRESULT mr, ! 102: const char *fmt, ! 103: ... ! 104: ) ! 105: { ! 106: va_list ap; ! 107: ! 108: va_start (ap, fmt); ! 109: AUD_vlog (AUDIO_CAP, fmt, ap); ! 110: va_end (ap); ! 111: ! 112: AUD_log (NULL, " failed\n"); ! 113: winwave_log_mmresult (mr); ! 114: } ! 115: ! 116: static void winwave_anal_close_out (WaveVoiceOut *wave) ! 117: { ! 118: MMRESULT mr; ! 119: ! 120: mr = waveOutClose (wave->hwo); ! 121: if (mr != MMSYSERR_NOERROR) { ! 122: winwave_logerr (mr, "waveOutClose"); ! 123: } ! 124: wave->hwo = NULL; ! 125: } ! 126: ! 127: static void CALLBACK winwave_callback_out ( ! 128: HWAVEOUT hwo, ! 129: UINT msg, ! 130: DWORD_PTR dwInstance, ! 131: DWORD_PTR dwParam1, ! 132: DWORD_PTR dwParam2 ! 133: ) ! 134: { ! 135: WaveVoiceOut *wave = (WaveVoiceOut *) dwInstance; ! 136: ! 137: switch (msg) { ! 138: case WOM_DONE: ! 139: { ! 140: WAVEHDR *h = (WAVEHDR *) dwParam1; ! 141: if (!h->dwUser) { ! 142: h->dwUser = 1; ! 143: EnterCriticalSection (&wave->crit_sect); ! 144: { ! 145: wave->avail += conf.dac_samples; ! 146: } ! 147: LeaveCriticalSection (&wave->crit_sect); ! 148: if (wave->hw.poll_mode) { ! 149: if (!SetEvent (wave->event)) { ! 150: dolog ("DAC SetEvent failed %lx\n", GetLastError ()); ! 151: } ! 152: } ! 153: } ! 154: } ! 155: break; ! 156: ! 157: case WOM_CLOSE: ! 158: case WOM_OPEN: ! 159: break; ! 160: ! 161: default: ! 162: dolog ("unknown wave out callback msg %x\n", msg); ! 163: } ! 164: } ! 165: ! 166: static int winwave_init_out (HWVoiceOut *hw, struct audsettings *as) ! 167: { ! 168: int i; ! 169: int err; ! 170: MMRESULT mr; ! 171: WAVEFORMATEX wfx; ! 172: WaveVoiceOut *wave; ! 173: ! 174: wave = (WaveVoiceOut *) hw; ! 175: ! 176: InitializeCriticalSection (&wave->crit_sect); ! 177: ! 178: err = waveformat_from_audio_settings (&wfx, as); ! 179: if (err) { ! 180: goto err0; ! 181: } ! 182: ! 183: mr = waveOutOpen (&wave->hwo, WAVE_MAPPER, &wfx, ! 184: (DWORD_PTR) winwave_callback_out, ! 185: (DWORD_PTR) wave, CALLBACK_FUNCTION); ! 186: if (mr != MMSYSERR_NOERROR) { ! 187: winwave_logerr (mr, "waveOutOpen"); ! 188: goto err1; ! 189: } ! 190: ! 191: wave->hdrs = audio_calloc (AUDIO_FUNC, conf.dac_headers, ! 192: sizeof (*wave->hdrs)); ! 193: if (!wave->hdrs) { ! 194: goto err2; ! 195: } ! 196: ! 197: audio_pcm_init_info (&hw->info, as); ! 198: hw->samples = conf.dac_samples * conf.dac_headers; ! 199: wave->avail = hw->samples; ! 200: ! 201: wave->pcm_buf = audio_calloc (AUDIO_FUNC, conf.dac_samples, ! 202: conf.dac_headers << hw->info.shift); ! 203: if (!wave->pcm_buf) { ! 204: goto err3; ! 205: } ! 206: ! 207: for (i = 0; i < conf.dac_headers; ++i) { ! 208: WAVEHDR *h = &wave->hdrs[i]; ! 209: ! 210: h->dwUser = 0; ! 211: h->dwBufferLength = conf.dac_samples << hw->info.shift; ! 212: h->lpData = advance (wave->pcm_buf, i * h->dwBufferLength); ! 213: h->dwFlags = 0; ! 214: ! 215: mr = waveOutPrepareHeader (wave->hwo, h, sizeof (*h)); ! 216: if (mr != MMSYSERR_NOERROR) { ! 217: winwave_logerr (mr, "waveOutPrepareHeader(%d)", i); ! 218: goto err4; ! 219: } ! 220: } ! 221: ! 222: return 0; ! 223: ! 224: err4: ! 225: qemu_free (wave->pcm_buf); ! 226: err3: ! 227: qemu_free (wave->hdrs); ! 228: err2: ! 229: winwave_anal_close_out (wave); ! 230: err1: ! 231: err0: ! 232: return -1; ! 233: } ! 234: ! 235: static int winwave_write (SWVoiceOut *sw, void *buf, int len) ! 236: { ! 237: return audio_pcm_sw_write (sw, buf, len); ! 238: } ! 239: ! 240: static int winwave_run_out (HWVoiceOut *hw, int live) ! 241: { ! 242: WaveVoiceOut *wave = (WaveVoiceOut *) hw; ! 243: int decr; ! 244: int doreset; ! 245: ! 246: EnterCriticalSection (&wave->crit_sect); ! 247: { ! 248: decr = audio_MIN (live, wave->avail); ! 249: decr = audio_pcm_hw_clip_out (hw, wave->pcm_buf, decr, wave->pending); ! 250: wave->pending += decr; ! 251: wave->avail -= decr; ! 252: } ! 253: LeaveCriticalSection (&wave->crit_sect); ! 254: ! 255: doreset = hw->poll_mode && (wave->pending >= conf.dac_samples); ! 256: if (doreset && !ResetEvent (wave->event)) { ! 257: dolog ("DAC ResetEvent failed %lx\n", GetLastError ()); ! 258: } ! 259: ! 260: while (wave->pending >= conf.dac_samples) { ! 261: MMRESULT mr; ! 262: WAVEHDR *h = &wave->hdrs[wave->curhdr]; ! 263: ! 264: h->dwUser = 0; ! 265: mr = waveOutWrite (wave->hwo, h, sizeof (*h)); ! 266: if (mr != MMSYSERR_NOERROR) { ! 267: winwave_logerr (mr, "waveOutWrite(%d)", wave->curhdr); ! 268: break; ! 269: } ! 270: ! 271: wave->pending -= conf.dac_samples; ! 272: wave->curhdr = (wave->curhdr + 1) % conf.dac_headers; ! 273: } ! 274: ! 275: return decr; ! 276: } ! 277: ! 278: static void winwave_poll (void *opaque) ! 279: { ! 280: (void) opaque; ! 281: audio_run ("winwave_poll"); ! 282: } ! 283: ! 284: static void winwave_fini_out (HWVoiceOut *hw) ! 285: { ! 286: int i; ! 287: MMRESULT mr; ! 288: WaveVoiceOut *wave = (WaveVoiceOut *) hw; ! 289: ! 290: mr = waveOutReset (wave->hwo); ! 291: if (mr != MMSYSERR_NOERROR) { ! 292: winwave_logerr (mr, "waveOutReset"); ! 293: } ! 294: ! 295: for (i = 0; i < conf.dac_headers; ++i) { ! 296: mr = waveOutUnprepareHeader (wave->hwo, &wave->hdrs[i], ! 297: sizeof (wave->hdrs[i])); ! 298: if (mr != MMSYSERR_NOERROR) { ! 299: winwave_logerr (mr, "waveOutUnprepareHeader(%d)", i); ! 300: } ! 301: } ! 302: ! 303: winwave_anal_close_out (wave); ! 304: ! 305: if (wave->event) { ! 306: qemu_del_wait_object (wave->event, winwave_poll, wave); ! 307: if (!CloseHandle (wave->event)) { ! 308: dolog ("DAC CloseHandle failed %lx\n", GetLastError ()); ! 309: } ! 310: wave->event = NULL; ! 311: } ! 312: ! 313: qemu_free (wave->pcm_buf); ! 314: wave->pcm_buf = NULL; ! 315: ! 316: qemu_free (wave->hdrs); ! 317: wave->hdrs = NULL; ! 318: } ! 319: ! 320: static int winwave_ctl_out (HWVoiceOut *hw, int cmd, ...) ! 321: { ! 322: MMRESULT mr; ! 323: WaveVoiceOut *wave = (WaveVoiceOut *) hw; ! 324: ! 325: switch (cmd) { ! 326: case VOICE_ENABLE: ! 327: { ! 328: va_list ap; ! 329: int poll_mode; ! 330: ! 331: va_start (ap, cmd); ! 332: poll_mode = va_arg (ap, int); ! 333: va_end (ap); ! 334: ! 335: if (poll_mode && !wave->event) { ! 336: wave->event = CreateEvent (NULL, TRUE, TRUE, NULL); ! 337: if (!wave->event) { ! 338: dolog ("DAC CreateEvent: %lx, poll mode will be disabled\n", ! 339: GetLastError ()); ! 340: } ! 341: } ! 342: ! 343: if (wave->event) { ! 344: int ret; ! 345: ! 346: ret = qemu_add_wait_object (wave->event, winwave_poll, wave); ! 347: hw->poll_mode = (ret == 0); ! 348: } ! 349: else { ! 350: hw->poll_mode = 0; ! 351: } ! 352: if (wave->paused) { ! 353: mr = waveOutRestart (wave->hwo); ! 354: if (mr != MMSYSERR_NOERROR) { ! 355: winwave_logerr (mr, "waveOutRestart"); ! 356: } ! 357: wave->paused = 0; ! 358: } ! 359: } ! 360: return 0; ! 361: ! 362: case VOICE_DISABLE: ! 363: if (!wave->paused) { ! 364: mr = waveOutPause (wave->hwo); ! 365: if (mr != MMSYSERR_NOERROR) { ! 366: winwave_logerr (mr, "waveOutPause"); ! 367: } ! 368: else { ! 369: wave->paused = 1; ! 370: } ! 371: } ! 372: if (wave->event) { ! 373: qemu_del_wait_object (wave->event, winwave_poll, wave); ! 374: } ! 375: return 0; ! 376: } ! 377: return -1; ! 378: } ! 379: ! 380: static void winwave_anal_close_in (WaveVoiceIn *wave) ! 381: { ! 382: MMRESULT mr; ! 383: ! 384: mr = waveInClose (wave->hwi); ! 385: if (mr != MMSYSERR_NOERROR) { ! 386: winwave_logerr (mr, "waveInClose"); ! 387: } ! 388: wave->hwi = NULL; ! 389: } ! 390: ! 391: static void CALLBACK winwave_callback_in ( ! 392: HWAVEIN *hwi, ! 393: UINT msg, ! 394: DWORD_PTR dwInstance, ! 395: DWORD_PTR dwParam1, ! 396: DWORD_PTR dwParam2 ! 397: ) ! 398: { ! 399: WaveVoiceIn *wave = (WaveVoiceIn *) dwInstance; ! 400: ! 401: switch (msg) { ! 402: case WIM_DATA: ! 403: { ! 404: WAVEHDR *h = (WAVEHDR *) dwParam1; ! 405: if (!h->dwUser) { ! 406: h->dwUser = 1; ! 407: EnterCriticalSection (&wave->crit_sect); ! 408: { ! 409: wave->avail += conf.adc_samples; ! 410: } ! 411: LeaveCriticalSection (&wave->crit_sect); ! 412: if (wave->hw.poll_mode) { ! 413: if (!SetEvent (wave->event)) { ! 414: dolog ("ADC SetEvent failed %lx\n", GetLastError ()); ! 415: } ! 416: } ! 417: } ! 418: } ! 419: break; ! 420: ! 421: case WIM_CLOSE: ! 422: case WIM_OPEN: ! 423: break; ! 424: ! 425: default: ! 426: dolog ("unknown wave in callback msg %x\n", msg); ! 427: } ! 428: } ! 429: ! 430: static void winwave_add_buffers (WaveVoiceIn *wave, int samples) ! 431: { ! 432: int doreset; ! 433: ! 434: doreset = wave->hw.poll_mode && (samples >= conf.adc_samples); ! 435: if (doreset && !ResetEvent (wave->event)) { ! 436: dolog ("ADC ResetEvent failed %lx\n", GetLastError ()); ! 437: } ! 438: ! 439: while (samples >= conf.adc_samples) { ! 440: MMRESULT mr; ! 441: WAVEHDR *h = &wave->hdrs[wave->curhdr]; ! 442: ! 443: h->dwUser = 0; ! 444: mr = waveInAddBuffer (wave->hwi, h, sizeof (*h)); ! 445: if (mr != MMSYSERR_NOERROR) { ! 446: winwave_logerr (mr, "waveInAddBuffer(%d)", wave->curhdr); ! 447: } ! 448: wave->curhdr = (wave->curhdr + 1) % conf.adc_headers; ! 449: samples -= conf.adc_samples; ! 450: } ! 451: } ! 452: ! 453: static int winwave_init_in (HWVoiceIn *hw, struct audsettings *as) ! 454: { ! 455: int i; ! 456: int err; ! 457: MMRESULT mr; ! 458: WAVEFORMATEX wfx; ! 459: WaveVoiceIn *wave; ! 460: ! 461: wave = (WaveVoiceIn *) hw; ! 462: ! 463: InitializeCriticalSection (&wave->crit_sect); ! 464: ! 465: err = waveformat_from_audio_settings (&wfx, as); ! 466: if (err) { ! 467: goto err0; ! 468: } ! 469: ! 470: mr = waveInOpen (&wave->hwi, WAVE_MAPPER, &wfx, ! 471: (DWORD_PTR) winwave_callback_in, ! 472: (DWORD_PTR) wave, CALLBACK_FUNCTION); ! 473: if (mr != MMSYSERR_NOERROR) { ! 474: winwave_logerr (mr, "waveInOpen"); ! 475: goto err1; ! 476: } ! 477: ! 478: wave->hdrs = audio_calloc (AUDIO_FUNC, conf.dac_headers, ! 479: sizeof (*wave->hdrs)); ! 480: if (!wave->hdrs) { ! 481: goto err2; ! 482: } ! 483: ! 484: audio_pcm_init_info (&hw->info, as); ! 485: hw->samples = conf.adc_samples * conf.adc_headers; ! 486: wave->avail = 0; ! 487: ! 488: wave->pcm_buf = audio_calloc (AUDIO_FUNC, conf.adc_samples, ! 489: conf.adc_headers << hw->info.shift); ! 490: if (!wave->pcm_buf) { ! 491: goto err3; ! 492: } ! 493: ! 494: for (i = 0; i < conf.adc_headers; ++i) { ! 495: WAVEHDR *h = &wave->hdrs[i]; ! 496: ! 497: h->dwUser = 0; ! 498: h->dwBufferLength = conf.adc_samples << hw->info.shift; ! 499: h->lpData = advance (wave->pcm_buf, i * h->dwBufferLength); ! 500: h->dwFlags = 0; ! 501: ! 502: mr = waveInPrepareHeader (wave->hwi, h, sizeof (*h)); ! 503: if (mr != MMSYSERR_NOERROR) { ! 504: winwave_logerr (mr, "waveInPrepareHeader(%d)", i); ! 505: goto err4; ! 506: } ! 507: } ! 508: ! 509: wave->paused = 1; ! 510: winwave_add_buffers (wave, hw->samples); ! 511: return 0; ! 512: ! 513: err4: ! 514: qemu_free (wave->pcm_buf); ! 515: err3: ! 516: qemu_free (wave->hdrs); ! 517: err2: ! 518: winwave_anal_close_in (wave); ! 519: err1: ! 520: err0: ! 521: return -1; ! 522: } ! 523: ! 524: static void winwave_fini_in (HWVoiceIn *hw) ! 525: { ! 526: int i; ! 527: MMRESULT mr; ! 528: WaveVoiceIn *wave = (WaveVoiceIn *) hw; ! 529: ! 530: mr = waveInReset (wave->hwi); ! 531: if (mr != MMSYSERR_NOERROR) { ! 532: winwave_logerr (mr, "waveInReset"); ! 533: } ! 534: ! 535: for (i = 0; i < conf.adc_headers; ++i) { ! 536: mr = waveInUnprepareHeader (wave->hwi, &wave->hdrs[i], ! 537: sizeof (wave->hdrs[i])); ! 538: if (mr != MMSYSERR_NOERROR) { ! 539: winwave_logerr (mr, "waveInUnprepareHeader(%d)", i); ! 540: } ! 541: } ! 542: ! 543: winwave_anal_close_in (wave); ! 544: ! 545: if (wave->event) { ! 546: qemu_del_wait_object (wave->event, winwave_poll, wave); ! 547: if (!CloseHandle (wave->event)) { ! 548: dolog ("ADC CloseHandle failed %lx\n", GetLastError ()); ! 549: } ! 550: wave->event = NULL; ! 551: } ! 552: ! 553: qemu_free (wave->pcm_buf); ! 554: wave->pcm_buf = NULL; ! 555: ! 556: qemu_free (wave->hdrs); ! 557: wave->hdrs = NULL; ! 558: } ! 559: ! 560: static int winwave_run_in (HWVoiceIn *hw) ! 561: { ! 562: WaveVoiceIn *wave = (WaveVoiceIn *) hw; ! 563: int live = audio_pcm_hw_get_live_in (hw); ! 564: int dead = hw->samples - live; ! 565: int decr, ret; ! 566: ! 567: if (!dead) { ! 568: return 0; ! 569: } ! 570: ! 571: EnterCriticalSection (&wave->crit_sect); ! 572: { ! 573: decr = audio_MIN (dead, wave->avail); ! 574: wave->avail -= decr; ! 575: } ! 576: LeaveCriticalSection (&wave->crit_sect); ! 577: ! 578: ret = decr; ! 579: while (decr) { ! 580: int left = hw->samples - hw->wpos; ! 581: int conv = audio_MIN (left, decr); ! 582: hw->conv (hw->conv_buf + hw->wpos, ! 583: advance (wave->pcm_buf, wave->rpos << hw->info.shift), ! 584: conv, ! 585: &nominal_volume); ! 586: ! 587: wave->rpos = (wave->rpos + conv) % hw->samples; ! 588: hw->wpos = (hw->wpos + conv) % hw->samples; ! 589: decr -= conv; ! 590: } ! 591: ! 592: winwave_add_buffers (wave, ret); ! 593: return ret; ! 594: } ! 595: ! 596: static int winwave_read (SWVoiceIn *sw, void *buf, int size) ! 597: { ! 598: return audio_pcm_sw_read (sw, buf, size); ! 599: } ! 600: ! 601: static int winwave_ctl_in (HWVoiceIn *hw, int cmd, ...) ! 602: { ! 603: MMRESULT mr; ! 604: WaveVoiceIn *wave = (WaveVoiceIn *) hw; ! 605: ! 606: switch (cmd) { ! 607: case VOICE_ENABLE: ! 608: { ! 609: va_list ap; ! 610: int poll_mode; ! 611: ! 612: va_start (ap, cmd); ! 613: poll_mode = va_arg (ap, int); ! 614: va_end (ap); ! 615: ! 616: if (poll_mode && !wave->event) { ! 617: wave->event = CreateEvent (NULL, TRUE, TRUE, NULL); ! 618: if (!wave->event) { ! 619: dolog ("ADC CreateEvent: %lx, poll mode will be disabled\n", ! 620: GetLastError ()); ! 621: } ! 622: } ! 623: ! 624: if (wave->event) { ! 625: int ret; ! 626: ! 627: ret = qemu_add_wait_object (wave->event, winwave_poll, wave); ! 628: hw->poll_mode = (ret == 0); ! 629: } ! 630: else { ! 631: hw->poll_mode = 0; ! 632: } ! 633: if (wave->paused) { ! 634: mr = waveInStart (wave->hwi); ! 635: if (mr != MMSYSERR_NOERROR) { ! 636: winwave_logerr (mr, "waveInStart"); ! 637: } ! 638: wave->paused = 0; ! 639: } ! 640: } ! 641: return 0; ! 642: ! 643: case VOICE_DISABLE: ! 644: if (!wave->paused) { ! 645: mr = waveInStop (wave->hwi); ! 646: if (mr != MMSYSERR_NOERROR) { ! 647: winwave_logerr (mr, "waveInStop"); ! 648: } ! 649: else { ! 650: wave->paused = 1; ! 651: } ! 652: } ! 653: if (wave->event) { ! 654: qemu_del_wait_object (wave->event, winwave_poll, wave); ! 655: } ! 656: return 0; ! 657: } ! 658: return 0; ! 659: } ! 660: ! 661: static void *winwave_audio_init (void) ! 662: { ! 663: return &conf; ! 664: } ! 665: ! 666: static void winwave_audio_fini (void *opaque) ! 667: { ! 668: (void) opaque; ! 669: } ! 670: ! 671: static struct audio_option winwave_options[] = { ! 672: { ! 673: .name = "DAC_HEADERS", ! 674: .tag = AUD_OPT_INT, ! 675: .valp = &conf.dac_headers, ! 676: .descr = "DAC number of headers", ! 677: }, ! 678: { ! 679: .name = "DAC_SAMPLES", ! 680: .tag = AUD_OPT_INT, ! 681: .valp = &conf.dac_samples, ! 682: .descr = "DAC number of samples per header", ! 683: }, ! 684: { ! 685: .name = "ADC_HEADERS", ! 686: .tag = AUD_OPT_INT, ! 687: .valp = &conf.adc_headers, ! 688: .descr = "ADC number of headers", ! 689: }, ! 690: { ! 691: .name = "ADC_SAMPLES", ! 692: .tag = AUD_OPT_INT, ! 693: .valp = &conf.adc_samples, ! 694: .descr = "ADC number of samples per header", ! 695: }, ! 696: { /* End of list */ } ! 697: }; ! 698: ! 699: static struct audio_pcm_ops winwave_pcm_ops = { ! 700: .init_out = winwave_init_out, ! 701: .fini_out = winwave_fini_out, ! 702: .run_out = winwave_run_out, ! 703: .write = winwave_write, ! 704: .ctl_out = winwave_ctl_out, ! 705: .init_in = winwave_init_in, ! 706: .fini_in = winwave_fini_in, ! 707: .run_in = winwave_run_in, ! 708: .read = winwave_read, ! 709: .ctl_in = winwave_ctl_in ! 710: }; ! 711: ! 712: struct audio_driver winwave_audio_driver = { ! 713: .name = "winwave", ! 714: .descr = "Windows Waveform Audio http://msdn.microsoft.com", ! 715: .options = winwave_options, ! 716: .init = winwave_audio_init, ! 717: .fini = winwave_audio_fini, ! 718: .pcm_ops = &winwave_pcm_ops, ! 719: .can_be_default = 1, ! 720: .max_voices_out = INT_MAX, ! 721: .max_voices_in = INT_MAX, ! 722: .voice_size_out = sizeof (WaveVoiceOut), ! 723: .voice_size_in = sizeof (WaveVoiceIn) ! 724: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.