230
PaWinWasapiSubStream in;
227
PaWinWasapiSubStream in;
231
228
IAudioCaptureClient *cclient;
232
229
IAudioEndpointVolume *inVol;
234
PaWinWasapiSubStream out;
231
PaWinWasapiSubStream out;
235
232
IAudioRenderClient *rclient;
236
IAudioEndpointVolume *outVol;
233
IAudioEndpointVolume *outVol;
239
236
bool closeRequest;
241
238
DWORD dwThreadId;
243
HANDLE hNotificationEvent;
240
HANDLE hNotificationEvent;
249
246
#define PRINT(x) PA_DEBUG(x);
252
logAUDCLNT_E(HRESULT res){
249
logAUDCLNT_E (HRESULT res)
256
case S_OK: return; break;
257
case E_POINTER :text ="E_POINTER"; break;
258
case E_INVALIDARG :text ="E_INVALIDARG"; break;
260
case AUDCLNT_E_NOT_INITIALIZED :text ="AUDCLNT_E_NOT_INITIALIZED"; break;
261
case AUDCLNT_E_ALREADY_INITIALIZED :text ="AUDCLNT_E_ALREADY_INITIALIZED"; break;
262
case AUDCLNT_E_WRONG_ENDPOINT_TYPE :text ="AUDCLNT_E_WRONG_ENDPOINT_TYPE"; break;
263
case AUDCLNT_E_DEVICE_INVALIDATED :text ="AUDCLNT_E_DEVICE_INVALIDATED"; break;
264
case AUDCLNT_E_NOT_STOPPED :text ="AUDCLNT_E_NOT_STOPPED"; break;
265
case AUDCLNT_E_BUFFER_TOO_LARGE :text ="AUDCLNT_E_BUFFER_TOO_LARGE"; break;
266
case AUDCLNT_E_OUT_OF_ORDER :text ="AUDCLNT_E_OUT_OF_ORDER"; break;
267
case AUDCLNT_E_UNSUPPORTED_FORMAT :text ="AUDCLNT_E_UNSUPPORTED_FORMAT"; break;
268
case AUDCLNT_E_INVALID_SIZE :text ="AUDCLNT_E_INVALID_SIZE"; break;
269
case AUDCLNT_E_DEVICE_IN_USE :text ="AUDCLNT_E_DEVICE_IN_USE"; break;
270
case AUDCLNT_E_BUFFER_OPERATION_PENDING :text ="AUDCLNT_E_BUFFER_OPERATION_PENDING"; break;
271
case AUDCLNT_E_THREAD_NOT_REGISTERED :text ="AUDCLNT_E_THREAD_NOT_REGISTERED"; break;
272
case AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED :text ="AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED"; break;
273
case AUDCLNT_E_ENDPOINT_CREATE_FAILED :text ="AUDCLNT_E_ENDPOINT_CREATE_FAILED"; break;
274
case AUDCLNT_E_SERVICE_NOT_RUNNING :text ="AUDCLNT_E_SERVICE_NOT_RUNNING"; break;
275
// case AUDCLNT_E_CPUUSAGE_EXCEEDED :text ="AUDCLNT_E_CPUUSAGE_EXCEEDED"; break;
277
case AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED :text ="AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED"; break;
278
case AUDCLNT_E_EXCLUSIVE_MODE_ONLY :text ="AUDCLNT_E_EXCLUSIVE_MODE_ONLY"; break;
279
case AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL :text ="AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL"; break;
280
case AUDCLNT_E_EVENTHANDLE_NOT_SET :text ="AUDCLNT_E_EVENTHANDLE_NOT_SET"; break;
281
case AUDCLNT_E_INCORRECT_BUFFER_SIZE :text ="AUDCLNT_E_INCORRECT_BUFFER_SIZE"; break;
282
case AUDCLNT_E_BUFFER_SIZE_ERROR :text ="AUDCLNT_E_BUFFER_SIZE_ERROR"; break;
283
case AUDCLNT_S_BUFFER_EMPTY :text ="AUDCLNT_S_BUFFER_EMPTY"; break;
284
case AUDCLNT_S_THREAD_ALREADY_REGISTERED :text ="AUDCLNT_S_THREAD_ALREADY_REGISTERED"; break;
262
text ="E_INVALIDARG";
265
case AUDCLNT_E_NOT_INITIALIZED :
266
text ="AUDCLNT_E_NOT_INITIALIZED";
268
case AUDCLNT_E_ALREADY_INITIALIZED :
269
text ="AUDCLNT_E_ALREADY_INITIALIZED";
271
case AUDCLNT_E_WRONG_ENDPOINT_TYPE :
272
text ="AUDCLNT_E_WRONG_ENDPOINT_TYPE";
274
case AUDCLNT_E_DEVICE_INVALIDATED :
275
text ="AUDCLNT_E_DEVICE_INVALIDATED";
277
case AUDCLNT_E_NOT_STOPPED :
278
text ="AUDCLNT_E_NOT_STOPPED";
280
case AUDCLNT_E_BUFFER_TOO_LARGE :
281
text ="AUDCLNT_E_BUFFER_TOO_LARGE";
283
case AUDCLNT_E_OUT_OF_ORDER :
284
text ="AUDCLNT_E_OUT_OF_ORDER";
286
case AUDCLNT_E_UNSUPPORTED_FORMAT :
287
text ="AUDCLNT_E_UNSUPPORTED_FORMAT";
289
case AUDCLNT_E_INVALID_SIZE :
290
text ="AUDCLNT_E_INVALID_SIZE";
292
case AUDCLNT_E_DEVICE_IN_USE :
293
text ="AUDCLNT_E_DEVICE_IN_USE";
295
case AUDCLNT_E_BUFFER_OPERATION_PENDING :
296
text ="AUDCLNT_E_BUFFER_OPERATION_PENDING";
298
case AUDCLNT_E_THREAD_NOT_REGISTERED :
299
text ="AUDCLNT_E_THREAD_NOT_REGISTERED";
301
case AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED :
302
text ="AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED";
304
case AUDCLNT_E_ENDPOINT_CREATE_FAILED :
305
text ="AUDCLNT_E_ENDPOINT_CREATE_FAILED";
307
case AUDCLNT_E_SERVICE_NOT_RUNNING :
308
text ="AUDCLNT_E_SERVICE_NOT_RUNNING";
310
// case AUDCLNT_E_CPUUSAGE_EXCEEDED :text ="AUDCLNT_E_CPUUSAGE_EXCEEDED"; break;
312
case AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED :
313
text ="AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED";
315
case AUDCLNT_E_EXCLUSIVE_MODE_ONLY :
316
text ="AUDCLNT_E_EXCLUSIVE_MODE_ONLY";
318
case AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL :
319
text ="AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL";
321
case AUDCLNT_E_EVENTHANDLE_NOT_SET :
322
text ="AUDCLNT_E_EVENTHANDLE_NOT_SET";
324
case AUDCLNT_E_INCORRECT_BUFFER_SIZE :
325
text ="AUDCLNT_E_INCORRECT_BUFFER_SIZE";
327
case AUDCLNT_E_BUFFER_SIZE_ERROR :
328
text ="AUDCLNT_E_BUFFER_SIZE_ERROR";
330
case AUDCLNT_S_BUFFER_EMPTY :
331
text ="AUDCLNT_S_BUFFER_EMPTY";
333
case AUDCLNT_S_THREAD_ALREADY_REGISTERED :
334
text ="AUDCLNT_S_THREAD_ALREADY_REGISTERED";
291
PRINT(("WASAPI ERROR HRESULT: 0x%X : %s\n",res,text));
295
nano100ToMillis(const REFERENCE_TIME &ref){
296
// 1 nano = 0.000000001 seconds
297
//100 nano = 0.0000001 seconds
298
//100 nano = 0.0001 milliseconds
299
return ((double)ref)*0.0001;
303
nano100ToSeconds(const REFERENCE_TIME &ref){
304
// 1 nano = 0.000000001 seconds
305
//100 nano = 0.0000001 seconds
306
//100 nano = 0.0001 milliseconds
307
return ((double)ref)*0.0000001;
343
PRINT ( ("WASAPI ERROR HRESULT: 0x%X : %s\n",res,text));
347
nano100ToMillis (const REFERENCE_TIME &ref)
349
// 1 nano = 0.000000001 seconds
350
//100 nano = 0.0000001 seconds
351
//100 nano = 0.0001 milliseconds
352
return ( (double) ref) *0.0001;
356
nano100ToSeconds (const REFERENCE_TIME &ref)
358
// 1 nano = 0.000000001 seconds
359
//100 nano = 0.0000001 seconds
360
//100 nano = 0.0001 milliseconds
361
return ( (double) ref) *0.0000001;
310
364
#ifndef IF_FAILED_JUMP
394
452
IMMDeviceCollection* spEndpoints=0;
395
453
paWasapi->enumerator = 0;
397
hResult = CoCreateInstance(
398
__uuidof(MMDeviceEnumerator), NULL,CLSCTX_INPROC_SERVER,
399
__uuidof(IMMDeviceEnumerator),
400
(void**)&paWasapi->enumerator);
455
hResult = CoCreateInstance (
456
__uuidof (MMDeviceEnumerator), NULL,CLSCTX_INPROC_SERVER,
457
__uuidof (IMMDeviceEnumerator),
458
(void**) &paWasapi->enumerator);
402
IF_FAILED_JUMP(hResult, error);
460
IF_FAILED_JUMP (hResult, error);
404
462
//getting default device ids in the eMultimedia "role"
407
465
IMMDevice* defaultRenderer=0;
408
hResult = paWasapi->enumerator->GetDefaultAudioEndpoint(eRender, eMultimedia, &defaultRenderer);
409
IF_FAILED_JUMP(hResult, error);
466
hResult = paWasapi->enumerator->GetDefaultAudioEndpoint (eRender, eMultimedia, &defaultRenderer);
467
IF_FAILED_JUMP (hResult, error);
410
468
WCHAR* pszDeviceId = NULL;
411
hResult = defaultRenderer->GetId(&pszDeviceId);
412
IF_FAILED_JUMP(hResult, error);
413
StringCchCopyW(paWasapi->defaultRenderer, MAX_STR_LEN-1, pszDeviceId);
414
CoTaskMemFree(pszDeviceId);
469
hResult = defaultRenderer->GetId (&pszDeviceId);
470
IF_FAILED_JUMP (hResult, error);
471
StringCchCopyW (paWasapi->defaultRenderer, MAX_STR_LEN-1, pszDeviceId);
472
CoTaskMemFree (pszDeviceId);
415
473
defaultRenderer->Release();
419
477
IMMDevice* defaultCapturer=0;
420
hResult = paWasapi->enumerator->GetDefaultAudioEndpoint(eCapture, eMultimedia, &defaultCapturer);
421
IF_FAILED_JUMP(hResult, error);
478
hResult = paWasapi->enumerator->GetDefaultAudioEndpoint (eCapture, eMultimedia, &defaultCapturer);
479
IF_FAILED_JUMP (hResult, error);
422
480
WCHAR* pszDeviceId = NULL;
423
hResult = defaultCapturer->GetId(&pszDeviceId);
424
IF_FAILED_JUMP(hResult, error);
425
StringCchCopyW(paWasapi->defaultCapturer, MAX_STR_LEN-1, pszDeviceId);
426
CoTaskMemFree(pszDeviceId);
481
hResult = defaultCapturer->GetId (&pszDeviceId);
482
IF_FAILED_JUMP (hResult, error);
483
StringCchCopyW (paWasapi->defaultCapturer, MAX_STR_LEN-1, pszDeviceId);
484
CoTaskMemFree (pszDeviceId);
427
485
defaultCapturer->Release();
432
hResult = paWasapi->enumerator->EnumAudioEndpoints(eAll, DEVICE_STATE_ACTIVE, &spEndpoints);
433
IF_FAILED_JUMP(hResult, error);
490
hResult = paWasapi->enumerator->EnumAudioEndpoints (eAll, DEVICE_STATE_ACTIVE, &spEndpoints);
491
IF_FAILED_JUMP (hResult, error);
435
hResult = spEndpoints->GetCount(&paWasapi->deviceCount);
436
IF_FAILED_JUMP(hResult, error);
493
hResult = spEndpoints->GetCount (&paWasapi->deviceCount);
494
IF_FAILED_JUMP (hResult, error);
438
496
paWasapi->devInfo = new PaWinWasapiDeviceInfo[paWasapi->deviceCount];
440
for (size_t step=0;step<paWasapi->deviceCount;++step)
441
memset(&paWasapi->devInfo[step],0,sizeof(PaWinWasapiDeviceInfo));
498
for (size_t step=0; step<paWasapi->deviceCount; ++step)
499
memset (&paWasapi->devInfo[step],0,sizeof (PaWinWasapiDeviceInfo));
446
if( paWasapi->deviceCount > 0 )
448
(*hostApi)->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
449
paWasapi->allocations, sizeof(PaDeviceInfo*) * paWasapi->deviceCount );
450
if( !(*hostApi)->deviceInfos ){
504
if (paWasapi->deviceCount > 0) {
505
(*hostApi)->deviceInfos = (PaDeviceInfo**) PaUtil_GroupAllocateMemory (
506
paWasapi->allocations, sizeof (PaDeviceInfo*) * paWasapi->deviceCount);
508
if (! (*hostApi)->deviceInfos) {
451
509
result = paInsufficientMemory;
455
513
/* allocate all device info structs in a contiguous block */
456
deviceInfoArray = (PaDeviceInfo*)PaUtil_GroupAllocateMemory(
457
paWasapi->allocations, sizeof(PaDeviceInfo) * paWasapi->deviceCount );
458
if( !deviceInfoArray ){
514
deviceInfoArray = (PaDeviceInfo*) PaUtil_GroupAllocateMemory (
515
paWasapi->allocations, sizeof (PaDeviceInfo) * paWasapi->deviceCount);
517
if (!deviceInfoArray) {
459
518
result = paInsufficientMemory;
463
for( UINT i=0; i < paWasapi->deviceCount; ++i ){
522
for (UINT i=0; i < paWasapi->deviceCount; ++i) {
465
PA_DEBUG(("i:%d\n",i));
524
PA_DEBUG ( ("i:%d\n",i));
466
525
PaDeviceInfo *deviceInfo = &deviceInfoArray[i];
467
526
deviceInfo->structVersion = 2;
468
527
deviceInfo->hostApi = hostApiIndex;
470
hResult = spEndpoints->Item(i, &paWasapi->devInfo[i].device);
471
IF_FAILED_JUMP(hResult, error);
529
hResult = spEndpoints->Item (i, &paWasapi->devInfo[i].device);
530
IF_FAILED_JUMP (hResult, error);
475
534
WCHAR* pszDeviceId = NULL;
476
hResult = paWasapi->devInfo[i].device->GetId(&pszDeviceId);
477
IF_FAILED_JUMP(hResult, error);
478
StringCchCopyW(paWasapi->devInfo[i].szDeviceID, MAX_STR_LEN-1, pszDeviceId);
479
CoTaskMemFree(pszDeviceId);
535
hResult = paWasapi->devInfo[i].device->GetId (&pszDeviceId);
536
IF_FAILED_JUMP (hResult, error);
537
StringCchCopyW (paWasapi->devInfo[i].szDeviceID, MAX_STR_LEN-1, pszDeviceId);
538
CoTaskMemFree (pszDeviceId);
481
if (lstrcmpW(paWasapi->devInfo[i].szDeviceID, paWasapi->defaultCapturer)==0){
540
if (lstrcmpW (paWasapi->devInfo[i].szDeviceID, paWasapi->defaultCapturer) ==0) {
482
541
//we found the default input!
483
542
(*hostApi)->info.defaultInputDevice = (*hostApi)->info.deviceCount;
485
if (lstrcmpW(paWasapi->devInfo[i].szDeviceID, paWasapi->defaultRenderer)==0){
545
if (lstrcmpW (paWasapi->devInfo[i].szDeviceID, paWasapi->defaultRenderer) ==0) {
486
546
//we found the default output!
487
547
(*hostApi)->info.defaultOutputDevice = (*hostApi)->info.deviceCount;
492
hResult = paWasapi->devInfo[i].device->GetState(&paWasapi->devInfo[i].state);
493
IF_FAILED_JUMP(hResult, error);
552
hResult = paWasapi->devInfo[i].device->GetState (&paWasapi->devInfo[i].state);
553
IF_FAILED_JUMP (hResult, error);
495
if (paWasapi->devInfo[i].state != DEVICE_STATE_ACTIVE){
496
PRINT(("WASAPI device:%d is not currently available (state:%d)\n",i,state));
555
if (paWasapi->devInfo[i].state != DEVICE_STATE_ACTIVE) {
556
PRINT ( ("WASAPI device:%d is not currently available (state:%d)\n",i,state));
497
557
//spDevice->Release();
502
562
IPropertyStore* spProperties;
503
hResult = paWasapi->devInfo[i].device->OpenPropertyStore(STGM_READ, &spProperties);
504
IF_FAILED_JUMP(hResult, error);
563
hResult = paWasapi->devInfo[i].device->OpenPropertyStore (STGM_READ, &spProperties);
564
IF_FAILED_JUMP (hResult, error);
506
566
//getting "Friendly" Name
508
568
PROPVARIANT value;
509
PropVariantInit(&value);
510
hResult = spProperties->GetValue(PKEY_Device_FriendlyName, &value);
511
IF_FAILED_JUMP(hResult, error);
569
PropVariantInit (&value);
570
hResult = spProperties->GetValue (PKEY_Device_FriendlyName, &value);
571
IF_FAILED_JUMP (hResult, error);
512
572
deviceInfo->name = 0;
513
char* deviceName = (char*)PaUtil_GroupAllocateMemory( paWasapi->allocations, MAX_STR_LEN + 1 );
573
char* deviceName = (char*) PaUtil_GroupAllocateMemory (paWasapi->allocations, MAX_STR_LEN + 1);
515
576
result = paInsufficientMemory;
519
wcstombs(deviceName, value.pwszVal,MAX_STR_LEN-1); //todo proper size
521
_snprintf_s(deviceName,MAX_STR_LEN-1,MAX_STR_LEN-1,"baddev%d",i);
581
wcstombs (deviceName, value.pwszVal,MAX_STR_LEN-1); //todo proper size
583
_snprintf_s (deviceName,MAX_STR_LEN-1,MAX_STR_LEN-1,"baddev%d",i);
524
586
deviceInfo->name = deviceName;
525
PropVariantClear(&value);
587
PropVariantClear (&value);
529
591
DWORD numProps = 0;
530
hResult = spProperties->GetCount(&numProps);
531
IF_FAILED_JUMP(hResult, error);
592
hResult = spProperties->GetCount (&numProps);
593
IF_FAILED_JUMP (hResult, error);
533
for (DWORD i=0;i<numProps;++i){
595
for (DWORD i=0; i<numProps; ++i) {
534
596
PROPERTYKEY pkey;
535
hResult = spProperties->GetAt(i,&pkey);
597
hResult = spProperties->GetAt (i,&pkey);
537
599
PROPVARIANT value;
538
PropVariantInit(&value);
539
hResult = spProperties->GetValue(pkey, &value);
600
PropVariantInit (&value);
601
hResult = spProperties->GetValue (pkey, &value);
543
PRINT(("property*%u*\n",value.ulVal));
605
PRINT ( ("property*%u*\n",value.ulVal));
546
PRINT(("property*%d*\n",value.boolVal));
608
PRINT ( ("property*%d*\n",value.boolVal));
551
wcstombs(temp, value.pwszVal,MAX_STR_LEN-1);
552
PRINT(("property*%s*\n",temp));
612
wcstombs (temp, value.pwszVal,MAX_STR_LEN-1);
613
PRINT ( ("property*%s*\n",temp));
558
PropVariantClear(&value);
620
PropVariantClear (&value);
666
729
if (paWasapi->enumerator)
667
730
paWasapi->enumerator->Release();
671
if( paWasapi->allocations )
673
PaUtil_FreeAllAllocations( paWasapi->allocations );
674
PaUtil_DestroyAllocationGroup( paWasapi->allocations );
733
if (paWasapi->allocations) {
734
PaUtil_FreeAllAllocations (paWasapi->allocations);
735
PaUtil_DestroyAllocationGroup (paWasapi->allocations);
677
PaUtil_FreeMemory( paWasapi );
738
PaUtil_FreeMemory (paWasapi);
683
static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
745
static void Terminate (struct PaUtilHostApiRepresentation *hostApi)
685
PaWinWasapiHostApiRepresentation *paWasapi = (PaWinWasapiHostApiRepresentation*)hostApi;
747
PaWinWasapiHostApiRepresentation *paWasapi = (PaWinWasapiHostApiRepresentation*) hostApi;
687
749
paWasapi->enumerator->Release();
689
for (UINT i=0;i<paWasapi->deviceCount;++i){
751
for (UINT i=0; i<paWasapi->deviceCount; ++i) {
690
752
PaWinWasapiDeviceInfo *info = &paWasapi->devInfo[i];
692
754
if (info->device)
693
755
info->device->Release();
695
757
if (info->MixFormat)
696
CoTaskMemFree(info->MixFormat);
758
CoTaskMemFree (info->MixFormat);
698
761
delete [] paWasapi->devInfo;
700
763
CoUninitialize();
702
if( paWasapi->allocations ){
703
PaUtil_FreeAllAllocations( paWasapi->allocations );
704
PaUtil_DestroyAllocationGroup( paWasapi->allocations );
765
if (paWasapi->allocations) {
766
PaUtil_FreeAllAllocations (paWasapi->allocations);
767
PaUtil_DestroyAllocationGroup (paWasapi->allocations);
707
PaUtil_FreeMemory( paWasapi );
770
PaUtil_FreeMemory (paWasapi);
711
LogWAVEFORMATEXTENSIBLE(const WAVEFORMATEXTENSIBLE *in){
713
const WAVEFORMATEX *old = (WAVEFORMATEX *)in;
715
switch (old->wFormatTag){
716
case WAVE_FORMAT_EXTENSIBLE:{
718
PRINT(("wFormatTag=WAVE_FORMAT_EXTENSIBLE\n"));
720
if (in->SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT){
721
PRINT(("SubFormat=KSDATAFORMAT_SUBTYPE_IEEE_FLOAT\n"));
723
else if (in->SubFormat == KSDATAFORMAT_SUBTYPE_PCM){
724
PRINT(("SubFormat=KSDATAFORMAT_SUBTYPE_PCM\n"));
727
PRINT(("SubFormat=CUSTOM GUID{%d:%d:%d:%d%d%d%d%d%d%d%d}\n",
731
(int)in->SubFormat.Data4[0],
732
(int)in->SubFormat.Data4[1],
733
(int)in->SubFormat.Data4[2],
734
(int)in->SubFormat.Data4[3],
735
(int)in->SubFormat.Data4[4],
736
(int)in->SubFormat.Data4[5],
737
(int)in->SubFormat.Data4[6],
738
(int)in->SubFormat.Data4[7]));
740
PRINT(("Samples.wValidBitsPerSample=%d\n", in->Samples.wValidBitsPerSample));
741
PRINT(("dwChannelMask=0x%X\n",in->dwChannelMask));
744
case WAVE_FORMAT_PCM: PRINT(("wFormatTag=WAVE_FORMAT_PCM\n")); break;
745
case WAVE_FORMAT_IEEE_FLOAT: PRINT(("wFormatTag=WAVE_FORMAT_IEEE_FLOAT\n")); break;
746
default : PRINT(("wFormatTag=UNKNOWN(%d)\n",old->wFormatTag)); break;
749
PRINT(("nChannels =%d\n",old->nChannels));
750
PRINT(("nSamplesPerSec =%d\n",old->nSamplesPerSec));
751
PRINT(("nAvgBytesPerSec=%d\n",old->nAvgBytesPerSec));
752
PRINT(("nBlockAlign =%d\n",old->nBlockAlign));
753
PRINT(("wBitsPerSample =%d\n",old->wBitsPerSample));
754
PRINT(("cbSize =%d\n",old->cbSize));
774
LogWAVEFORMATEXTENSIBLE (const WAVEFORMATEXTENSIBLE *in)
777
const WAVEFORMATEX *old = (WAVEFORMATEX *) in;
779
switch (old->wFormatTag) {
780
case WAVE_FORMAT_EXTENSIBLE: {
782
PRINT ( ("wFormatTag=WAVE_FORMAT_EXTENSIBLE\n"));
784
if (in->SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT) {
785
PRINT ( ("SubFormat=KSDATAFORMAT_SUBTYPE_IEEE_FLOAT\n"));
786
} else if (in->SubFormat == KSDATAFORMAT_SUBTYPE_PCM) {
787
PRINT ( ("SubFormat=KSDATAFORMAT_SUBTYPE_PCM\n"));
789
PRINT ( ("SubFormat=CUSTOM GUID{%d:%d:%d:%d%d%d%d%d%d%d%d}\n",
793
(int) in->SubFormat.Data4[0],
794
(int) in->SubFormat.Data4[1],
795
(int) in->SubFormat.Data4[2],
796
(int) in->SubFormat.Data4[3],
797
(int) in->SubFormat.Data4[4],
798
(int) in->SubFormat.Data4[5],
799
(int) in->SubFormat.Data4[6],
800
(int) in->SubFormat.Data4[7]));
803
PRINT ( ("Samples.wValidBitsPerSample=%d\n", in->Samples.wValidBitsPerSample));
804
PRINT ( ("dwChannelMask=0x%X\n",in->dwChannelMask));
808
case WAVE_FORMAT_PCM:
809
PRINT ( ("wFormatTag=WAVE_FORMAT_PCM\n"));
811
case WAVE_FORMAT_IEEE_FLOAT:
812
PRINT ( ("wFormatTag=WAVE_FORMAT_IEEE_FLOAT\n"));
815
PRINT ( ("wFormatTag=UNKNOWN(%d)\n",old->wFormatTag));
819
PRINT ( ("nChannels =%d\n",old->nChannels));
820
PRINT ( ("nSamplesPerSec =%d\n",old->nSamplesPerSec));
821
PRINT ( ("nAvgBytesPerSec=%d\n",old->nAvgBytesPerSec));
822
PRINT ( ("nBlockAlign =%d\n",old->nBlockAlign));
823
PRINT ( ("wBitsPerSample =%d\n",old->wBitsPerSample));
824
PRINT ( ("cbSize =%d\n",old->cbSize));
818
waveformatFromParams(WAVEFORMATEXTENSIBLE*wavex,
819
const PaStreamParameters * params,
905
waveformatFromParams (WAVEFORMATEXTENSIBLE*wavex,
906
const PaStreamParameters * params,
822
910
size_t bytesPerSample = 0;
823
switch( params->sampleFormat & ~paNonInterleaved ){
912
switch (params->sampleFormat & ~paNonInterleaved) {
825
case paInt32: bytesPerSample=4;break;
826
case paInt16: bytesPerSample=2;break;
827
case paInt24: bytesPerSample=3;break;
829
case paUInt8: bytesPerSample=1;break;
830
927
case paCustomFormat:
831
default: return paSampleFormatNotSupported;break;
929
return paSampleFormatNotSupported;
834
memset(wavex,0,sizeof(WAVEFORMATEXTENSIBLE));
933
memset (wavex,0,sizeof (WAVEFORMATEXTENSIBLE));
836
WAVEFORMATEX *old = (WAVEFORMATEX *)wavex;
837
old->nChannels = (WORD)params->channelCount;
838
old->nSamplesPerSec = (DWORD)sampleRate;
839
old->wBitsPerSample = (WORD)(bytesPerSample*8);
840
old->nAvgBytesPerSec = (DWORD)(old->nSamplesPerSec * old->nChannels * bytesPerSample);
841
old->nBlockAlign = (WORD)(old->nChannels * bytesPerSample);
935
WAVEFORMATEX *old = (WAVEFORMATEX *) wavex;
936
old->nChannels = (WORD) params->channelCount;
937
old->nSamplesPerSec = (DWORD) sampleRate;
938
old->wBitsPerSample = (WORD) (bytesPerSample*8);
939
old->nAvgBytesPerSec = (DWORD) (old->nSamplesPerSec * old->nChannels * bytesPerSample);
940
old->nBlockAlign = (WORD) (old->nChannels * bytesPerSample);
844
if (params->channelCount <=2 && (bytesPerSample == 2 || bytesPerSample == 1)){
943
if (params->channelCount <=2 && (bytesPerSample == 2 || bytesPerSample == 1)) {
846
945
old->wFormatTag = WAVE_FORMAT_PCM;
848
947
//WAVEFORMATEXTENSIBLE
850
949
old->wFormatTag = WAVE_FORMAT_EXTENSIBLE;
852
951
old->cbSize = sizeof (WAVEFORMATEXTENSIBLE) - sizeof (WAVEFORMATEX);
854
if ((params->sampleFormat & ~paNonInterleaved) == paFloat32)
953
if ( (params->sampleFormat & ~paNonInterleaved) == paFloat32)
855
954
wavex->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
857
956
wavex->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
859
958
wavex->Samples.wValidBitsPerSample = old->wBitsPerSample; //no extra padding!
861
switch(params->channelCount){
862
case 1: wavex->dwChannelMask = SPEAKER_FRONT_CENTER; break;
863
case 2: wavex->dwChannelMask = 0x1 | 0x2; break;
864
case 4: wavex->dwChannelMask = 0x1 | 0x2 | 0x10 | 0x20; break;
865
case 6: wavex->dwChannelMask = 0x1 | 0x2 | 0x4 | 0x8 | 0x10 | 0x20; break;
866
case 8: wavex->dwChannelMask = 0x1 | 0x2 | 0x4 | 0x8 | 0x10 | 0x20 | 0x40 | 0x80; break;
867
default: wavex->dwChannelMask = 0; break;
960
switch (params->channelCount) {
962
wavex->dwChannelMask = SPEAKER_FRONT_CENTER;
965
wavex->dwChannelMask = 0x1 | 0x2;
968
wavex->dwChannelMask = 0x1 | 0x2 | 0x10 | 0x20;
971
wavex->dwChannelMask = 0x1 | 0x2 | 0x4 | 0x8 | 0x10 | 0x20;
974
wavex->dwChannelMask = 0x1 | 0x2 | 0x4 | 0x8 | 0x10 | 0x20 | 0x40 | 0x80;
977
wavex->dwChannelMask = 0;
883
994
#define paInt16 ((PaSampleFormat) 0x00000008)
885
996
//lifted from pa_wdmks
886
static void wasapiFillWFEXT( WAVEFORMATEXTENSIBLE* pwfext, PaSampleFormat sampleFormat, double sampleRate, int channelCount)
997
static void wasapiFillWFEXT (WAVEFORMATEXTENSIBLE* pwfext, PaSampleFormat sampleFormat, double sampleRate, int channelCount)
888
PA_DEBUG(( "sampleFormat = %lx\n" , sampleFormat ));
889
PA_DEBUG(( "sampleRate = %f\n" , sampleRate ));
890
PA_DEBUG(( "chanelCount = %d\n", channelCount ));
999
PA_DEBUG ( ("sampleFormat = %lx\n" , sampleFormat));
1000
PA_DEBUG ( ("sampleRate = %f\n" , sampleRate));
1001
PA_DEBUG ( ("chanelCount = %d\n", channelCount));
892
1003
pwfext->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
893
1004
pwfext->Format.nChannels = channelCount;
894
pwfext->Format.nSamplesPerSec = (int)sampleRate;
895
if(channelCount == 1)
1005
pwfext->Format.nSamplesPerSec = (int) sampleRate;
1007
if (channelCount == 1)
896
1008
pwfext->dwChannelMask = KSAUDIO_SPEAKER_DIRECTOUT;
898
1010
pwfext->dwChannelMask = KSAUDIO_SPEAKER_STEREO;
899
if(sampleFormat == paFloat32)
1012
if (sampleFormat == paFloat32) {
901
1013
pwfext->Format.nBlockAlign = channelCount * 4;
902
1014
pwfext->Format.wBitsPerSample = 32;
903
pwfext->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX);
1015
pwfext->Format.cbSize = sizeof (WAVEFORMATEXTENSIBLE)-sizeof (WAVEFORMATEX);
904
1016
pwfext->Samples.wValidBitsPerSample = 32;
905
1017
pwfext->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
907
else if(sampleFormat == paInt32)
1018
} else if (sampleFormat == paInt32) {
909
1019
pwfext->Format.nBlockAlign = channelCount * 4;
910
1020
pwfext->Format.wBitsPerSample = 32;
911
pwfext->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX);
1021
pwfext->Format.cbSize = sizeof (WAVEFORMATEXTENSIBLE)-sizeof (WAVEFORMATEX);
912
1022
pwfext->Samples.wValidBitsPerSample = 32;
913
1023
pwfext->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
915
else if(sampleFormat == paInt24)
1024
} else if (sampleFormat == paInt24) {
917
1025
pwfext->Format.nBlockAlign = channelCount * 3;
918
1026
pwfext->Format.wBitsPerSample = 24;
919
pwfext->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX);
1027
pwfext->Format.cbSize = sizeof (WAVEFORMATEXTENSIBLE)-sizeof (WAVEFORMATEX);
920
1028
pwfext->Samples.wValidBitsPerSample = 24;
921
1029
pwfext->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
923
else if(sampleFormat == paInt16)
1030
} else if (sampleFormat == paInt16) {
925
1031
pwfext->Format.nBlockAlign = channelCount * 2;
926
1032
pwfext->Format.wBitsPerSample = 16;
927
pwfext->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX);
1033
pwfext->Format.cbSize = sizeof (WAVEFORMATEXTENSIBLE)-sizeof (WAVEFORMATEX);
928
1034
pwfext->Samples.wValidBitsPerSample = 16;
929
1035
pwfext->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
931
1038
pwfext->Format.nAvgBytesPerSec = pwfext->Format.nSamplesPerSec * pwfext->Format.nBlockAlign;
946
GetClosestFormat(IAudioClient * myClient, double sampleRate,const PaStreamParameters * params,
947
AUDCLNT_SHAREMODE *shareMode, WAVEFORMATEXTENSIBLE *outWavex)
1053
GetClosestFormat (IAudioClient * myClient, double sampleRate,const PaStreamParameters * params,
1054
AUDCLNT_SHAREMODE *shareMode, WAVEFORMATEXTENSIBLE *outWavex)
949
//TODO we should try exclusive first and shared after
950
*shareMode = PORTAUDIO_SHAREMODE;
952
PaError answer = paInvalidSampleRate;
954
waveformatFromParams(outWavex,params,sampleRate);
955
WAVEFORMATEX *sharedClosestMatch=0;
956
HRESULT hResult=!S_OK;
958
if (*shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE)
959
hResult = myClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE,&outWavex->Format,NULL);
961
hResult = myClient->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED, &outWavex->Format,&sharedClosestMatch);
964
answer = paFormatIsSupported;
965
else if (sharedClosestMatch){
966
WAVEFORMATEXTENSIBLE* ext = (WAVEFORMATEXTENSIBLE*)sharedClosestMatch;
968
int closestMatchSR = (int)sharedClosestMatch->nSamplesPerSec;
970
if (sharedClosestMatch->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
971
memcpy(outWavex,sharedClosestMatch,sizeof(WAVEFORMATEXTENSIBLE));
973
memcpy(outWavex,sharedClosestMatch,sizeof(WAVEFORMATEX));
975
CoTaskMemFree(sharedClosestMatch);
977
if ((int)sampleRate == closestMatchSR)
978
answer = paFormatIsSupported;
980
answer = paInvalidSampleRate;
984
//it doesnt suggest anything?? ok lets show it the MENU!
986
//ok fun time as with pa_win_mme, we know only a refusal of the user-requested
987
//sampleRate+num Channel is disastrous, as the portaudio buffer processor converts between anything
988
//so lets only use the number
989
for (int i=0;i<FORMATTESTS;++i){
990
WAVEFORMATEXTENSIBLE ext;
991
wasapiFillWFEXT(&ext,BestToWorst[i],sampleRate,params->channelCount);
992
if (*shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE)
993
hResult = myClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE,&ext.Format,NULL);
995
hResult = myClient->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED, &ext.Format,&sharedClosestMatch);
997
if (hResult == S_OK){
998
memcpy(outWavex,&ext,sizeof(WAVEFORMATEXTENSIBLE));
999
answer = paFormatIsSupported;
1004
if (answer!=paFormatIsSupported) {
1006
//why did it HAVE to come to this ....
1007
WAVEFORMATEX pcm16WaveFormat;
1008
memset(&pcm16WaveFormat,0,sizeof(WAVEFORMATEX));
1009
pcm16WaveFormat.wFormatTag = WAVE_FORMAT_PCM;
1010
pcm16WaveFormat.nChannels = 2;
1011
pcm16WaveFormat.nSamplesPerSec = (DWORD)sampleRate;
1012
pcm16WaveFormat.nBlockAlign = 4;
1013
pcm16WaveFormat.nAvgBytesPerSec = pcm16WaveFormat.nSamplesPerSec*pcm16WaveFormat.nBlockAlign;
1014
pcm16WaveFormat.wBitsPerSample = 16;
1015
pcm16WaveFormat.cbSize = 0;
1017
if (*shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE)
1018
hResult = myClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE,&pcm16WaveFormat,NULL);
1020
hResult = myClient->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED, &pcm16WaveFormat,&sharedClosestMatch);
1022
if (hResult == S_OK){
1023
memcpy(outWavex,&pcm16WaveFormat,sizeof(WAVEFORMATEX));
1024
answer = paFormatIsSupported;
1028
logAUDCLNT_E(hResult);
1056
//TODO we should try exclusive first and shared after
1057
*shareMode = PORTAUDIO_SHAREMODE;
1059
PaError answer = paInvalidSampleRate;
1061
waveformatFromParams (outWavex,params,sampleRate);
1062
WAVEFORMATEX *sharedClosestMatch=0;
1063
HRESULT hResult=!S_OK;
1065
if (*shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE)
1066
hResult = myClient->IsFormatSupported (AUDCLNT_SHAREMODE_EXCLUSIVE,&outWavex->Format,NULL);
1068
hResult = myClient->IsFormatSupported (AUDCLNT_SHAREMODE_SHARED, &outWavex->Format,&sharedClosestMatch);
1070
if (hResult == S_OK)
1071
answer = paFormatIsSupported;
1072
else if (sharedClosestMatch) {
1073
WAVEFORMATEXTENSIBLE* ext = (WAVEFORMATEXTENSIBLE*) sharedClosestMatch;
1075
int closestMatchSR = (int) sharedClosestMatch->nSamplesPerSec;
1077
if (sharedClosestMatch->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
1078
memcpy (outWavex,sharedClosestMatch,sizeof (WAVEFORMATEXTENSIBLE));
1080
memcpy (outWavex,sharedClosestMatch,sizeof (WAVEFORMATEX));
1082
CoTaskMemFree (sharedClosestMatch);
1084
if ( (int) sampleRate == closestMatchSR)
1085
answer = paFormatIsSupported;
1087
answer = paInvalidSampleRate;
1091
//it doesnt suggest anything?? ok lets show it the MENU!
1093
//ok fun time as with pa_win_mme, we know only a refusal of the user-requested
1094
//sampleRate+num Channel is disastrous, as the portaudio buffer processor converts between anything
1095
//so lets only use the number
1096
for (int i=0; i<FORMATTESTS; ++i) {
1097
WAVEFORMATEXTENSIBLE ext;
1098
wasapiFillWFEXT (&ext,BestToWorst[i],sampleRate,params->channelCount);
1100
if (*shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE)
1101
hResult = myClient->IsFormatSupported (AUDCLNT_SHAREMODE_EXCLUSIVE,&ext.Format,NULL);
1103
hResult = myClient->IsFormatSupported (AUDCLNT_SHAREMODE_SHARED, &ext.Format,&sharedClosestMatch);
1105
if (hResult == S_OK) {
1106
memcpy (outWavex,&ext,sizeof (WAVEFORMATEXTENSIBLE));
1107
answer = paFormatIsSupported;
1112
if (answer!=paFormatIsSupported) {
1114
//why did it HAVE to come to this ....
1115
WAVEFORMATEX pcm16WaveFormat;
1116
memset (&pcm16WaveFormat,0,sizeof (WAVEFORMATEX));
1117
pcm16WaveFormat.wFormatTag = WAVE_FORMAT_PCM;
1118
pcm16WaveFormat.nChannels = 2;
1119
pcm16WaveFormat.nSamplesPerSec = (DWORD) sampleRate;
1120
pcm16WaveFormat.nBlockAlign = 4;
1121
pcm16WaveFormat.nAvgBytesPerSec = pcm16WaveFormat.nSamplesPerSec*pcm16WaveFormat.nBlockAlign;
1122
pcm16WaveFormat.wBitsPerSample = 16;
1123
pcm16WaveFormat.cbSize = 0;
1125
if (*shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE)
1126
hResult = myClient->IsFormatSupported (AUDCLNT_SHAREMODE_EXCLUSIVE,&pcm16WaveFormat,NULL);
1128
hResult = myClient->IsFormatSupported (AUDCLNT_SHAREMODE_SHARED, &pcm16WaveFormat,&sharedClosestMatch);
1130
if (hResult == S_OK) {
1131
memcpy (outWavex,&pcm16WaveFormat,sizeof (WAVEFORMATEX));
1132
answer = paFormatIsSupported;
1136
logAUDCLNT_E (hResult);
1035
static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
1143
static PaError IsFormatSupported (struct PaUtilHostApiRepresentation *hostApi,
1036
1144
const PaStreamParameters *inputParameters,
1037
1145
const PaStreamParameters *outputParameters,
1041
1149
int inputChannelCount, outputChannelCount;
1042
1150
PaSampleFormat inputSampleFormat, outputSampleFormat;
1044
if( inputParameters )
1152
if (inputParameters) {
1046
1153
inputChannelCount = inputParameters->channelCount;
1047
1154
inputSampleFormat = inputParameters->sampleFormat;
1049
1156
/* all standard sample formats are supported by the buffer adapter,
1050
1157
this implementation doesn't support any custom sample formats */
1051
if( inputSampleFormat & paCustomFormat )
1158
if (inputSampleFormat & paCustomFormat)
1052
1159
return paSampleFormatNotSupported;
1054
1161
/* unless alternate device specification is supported, reject the use of
1055
1162
paUseHostApiSpecificDeviceSpecification */
1057
if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
1164
if (inputParameters->device == paUseHostApiSpecificDeviceSpecification)
1058
1165
return paInvalidDevice;
1060
1167
/* check that input device can support inputChannelCount */
1061
if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
1168
if (inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels)
1062
1169
return paInvalidChannelCount;
1064
1171
/* validate inputStreamInfo */
1065
if( inputParameters->hostApiSpecificStreamInfo )
1172
if (inputParameters->hostApiSpecificStreamInfo)
1066
1173
return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
1069
PaWinWasapiHostApiRepresentation *paWasapi = (PaWinWasapiHostApiRepresentation*)hostApi;
1072
IAudioClient *myClient=0;
1073
HRESULT hResult = paWasapi->devInfo[inputParameters->device].device->Activate(
1074
__uuidof(IAudioClient), CLSCTX_INPROC_SERVER, NULL, (void**)&myClient);
1075
if (hResult != S_OK){
1076
logAUDCLNT_E(hResult);
1077
return paInvalidDevice;
1176
PaWinWasapiHostApiRepresentation *paWasapi = (PaWinWasapiHostApiRepresentation*) hostApi;
1179
IAudioClient *myClient=0;
1180
HRESULT hResult = paWasapi->devInfo[inputParameters->device].device->Activate (
1181
__uuidof (IAudioClient), CLSCTX_INPROC_SERVER, NULL, (void**) &myClient);
1183
if (hResult != S_OK) {
1184
logAUDCLNT_E (hResult);
1185
return paInvalidDevice;
1080
1188
WAVEFORMATEXTENSIBLE wavex;
1081
AUDCLNT_SHAREMODE shareMode;
1082
PaError answer = GetClosestFormat(myClient,sampleRate,inputParameters,&shareMode,&wavex);
1083
myClient->Release();
1189
AUDCLNT_SHAREMODE shareMode;
1190
PaError answer = GetClosestFormat (myClient,sampleRate,inputParameters,&shareMode,&wavex);
1191
myClient->Release();
1085
if (answer !=paFormatIsSupported)
1193
if (answer !=paFormatIsSupported)
1090
1196
inputChannelCount = 0;
1093
if( outputParameters )
1199
if (outputParameters) {
1095
1200
outputChannelCount = outputParameters->channelCount;
1096
1201
outputSampleFormat = outputParameters->sampleFormat;
1098
1203
/* all standard sample formats are supported by the buffer adapter,
1099
1204
this implementation doesn't support any custom sample formats */
1100
if( outputSampleFormat & paCustomFormat )
1205
if (outputSampleFormat & paCustomFormat)
1101
1206
return paSampleFormatNotSupported;
1103
1208
/* unless alternate device specification is supported, reject the use of
1104
1209
paUseHostApiSpecificDeviceSpecification */
1106
if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
1211
if (outputParameters->device == paUseHostApiSpecificDeviceSpecification)
1107
1212
return paInvalidDevice;
1109
1214
/* check that output device can support outputChannelCount */
1110
if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
1215
if (outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels)
1111
1216
return paInvalidChannelCount;
1113
1218
/* validate outputStreamInfo */
1114
if( outputParameters->hostApiSpecificStreamInfo )
1219
if (outputParameters->hostApiSpecificStreamInfo)
1115
1220
return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
1118
PaWinWasapiHostApiRepresentation *paWasapi = (PaWinWasapiHostApiRepresentation*)hostApi;
1120
IAudioClient *myClient=0;
1121
HRESULT hResult = paWasapi->devInfo[outputParameters->device].device->Activate(
1122
__uuidof(IAudioClient), CLSCTX_INPROC_SERVER, NULL, (void**)&myClient);
1123
if (hResult != S_OK){
1124
logAUDCLNT_E(hResult);
1125
return paInvalidDevice;
1223
PaWinWasapiHostApiRepresentation *paWasapi = (PaWinWasapiHostApiRepresentation*) hostApi;
1225
IAudioClient *myClient=0;
1226
HRESULT hResult = paWasapi->devInfo[outputParameters->device].device->Activate (
1227
__uuidof (IAudioClient), CLSCTX_INPROC_SERVER, NULL, (void**) &myClient);
1229
if (hResult != S_OK) {
1230
logAUDCLNT_E (hResult);
1231
return paInvalidDevice;
1128
1234
WAVEFORMATEXTENSIBLE wavex;
1129
AUDCLNT_SHAREMODE shareMode;
1130
PaError answer = GetClosestFormat(myClient,sampleRate,outputParameters,&shareMode,&wavex);
1131
myClient->Release();
1235
AUDCLNT_SHAREMODE shareMode;
1236
PaError answer = GetClosestFormat (myClient,sampleRate,outputParameters,&shareMode,&wavex);
1237
myClient->Release();
1133
if (answer !=paFormatIsSupported)
1239
if (answer !=paFormatIsSupported)
1138
1242
outputChannelCount = 0;
1154
1258
unsigned long framesPerBuffer,
1155
1259
PaStreamFlags streamFlags,
1156
1260
PaStreamCallback *streamCallback,
1159
1263
PaError result = paNoError;
1160
PaWinWasapiHostApiRepresentation *paWasapi = (PaWinWasapiHostApiRepresentation*)hostApi;
1264
PaWinWasapiHostApiRepresentation *paWasapi = (PaWinWasapiHostApiRepresentation*) hostApi;
1161
1265
PaWinWasapiStream *stream = 0;
1162
1266
int inputChannelCount, outputChannelCount;
1163
1267
PaSampleFormat inputSampleFormat, outputSampleFormat;
1164
1268
PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat;
1167
stream = (PaWinWasapiStream*)PaUtil_AllocateMemory( sizeof(PaWinWasapiStream) );
1271
stream = (PaWinWasapiStream*) PaUtil_AllocateMemory (sizeof (PaWinWasapiStream));
1169
1274
result = paInsufficientMemory;
1173
if( inputParameters )
1278
if (inputParameters) {
1175
1279
inputChannelCount = inputParameters->channelCount;
1176
1280
inputSampleFormat = inputParameters->sampleFormat;
1178
1282
/* unless alternate device specification is supported, reject the use of
1179
1283
paUseHostApiSpecificDeviceSpecification */
1181
if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
1285
if (inputParameters->device == paUseHostApiSpecificDeviceSpecification)
1182
1286
return paInvalidDevice;
1184
1288
/* check that input device can support inputChannelCount */
1185
if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
1289
if (inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels)
1186
1290
return paInvalidChannelCount;
1188
1292
/* validate inputStreamInfo */
1189
if( inputParameters->hostApiSpecificStreamInfo )
1293
if (inputParameters->hostApiSpecificStreamInfo)
1190
1294
return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
1193
1297
PaWinWasapiDeviceInfo &info = paWasapi->devInfo[inputParameters->device];
1195
HRESULT hResult = info.device->Activate(
1196
__uuidof(IAudioClient), CLSCTX_INPROC_SERVER, NULL,
1197
(void**)&stream->in.client);
1199
if (hResult != S_OK)
1200
return paInvalidDevice;
1202
hResult = info.device->Activate(
1203
__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL,
1204
(void**)&stream->inVol);
1206
if (hResult != S_OK)
1207
return paInvalidDevice;
1209
AUDCLNT_SHAREMODE shareMode;
1210
PaError answer = GetClosestFormat(stream->in.client,sampleRate,inputParameters,&shareMode,&stream->in.wavex);
1212
if (answer !=paFormatIsSupported)
1299
HRESULT hResult = info.device->Activate (
1300
__uuidof (IAudioClient), CLSCTX_INPROC_SERVER, NULL,
1301
(void**) &stream->in.client);
1303
if (hResult != S_OK)
1304
return paInvalidDevice;
1306
hResult = info.device->Activate (
1307
__uuidof (IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL,
1308
(void**) &stream->inVol);
1310
if (hResult != S_OK)
1311
return paInvalidDevice;
1313
AUDCLNT_SHAREMODE shareMode;
1314
PaError answer = GetClosestFormat (stream->in.client,sampleRate,inputParameters,&shareMode,&stream->in.wavex);
1316
if (answer !=paFormatIsSupported)
1215
1319
//stream->out.period = info.DefaultDevicePeriod;
1216
1320
stream->in.period = info.MinimumDevicePeriod;
1218
hResult = stream->in.client->Initialize(
1222
0,//stream->out.period,
1223
(WAVEFORMATEX*)&stream->in.wavex,
1322
hResult = stream->in.client->Initialize (
1326
0,//stream->out.period,
1327
(WAVEFORMATEX*) &stream->in.wavex,
1227
if (hResult != S_OK){
1228
logAUDCLNT_E(hResult);
1331
if (hResult != S_OK) {
1332
logAUDCLNT_E (hResult);
1229
1333
return paInvalidDevice;
1232
hResult = stream->in.client->GetBufferSize(&stream->in.bufferSize);
1233
if (hResult != S_OK)
1234
return paInvalidDevice;
1236
hResult = stream->in.client->GetStreamLatency(&stream->in.latency);
1237
if (hResult != S_OK)
1238
return paInvalidDevice;
1240
double periodsPerSecond = 1.0/nano100ToSeconds(stream->in.period);
1241
double samplesPerPeriod = (double)(stream->in.wavex.Format.nSamplesPerSec)/periodsPerSecond;
1336
hResult = stream->in.client->GetBufferSize (&stream->in.bufferSize);
1338
if (hResult != S_OK)
1339
return paInvalidDevice;
1341
hResult = stream->in.client->GetStreamLatency (&stream->in.latency);
1343
if (hResult != S_OK)
1344
return paInvalidDevice;
1346
double periodsPerSecond = 1.0/nano100ToSeconds (stream->in.period);
1347
double samplesPerPeriod = (double) (stream->in.wavex.Format.nSamplesPerSec) /periodsPerSecond;
1243
1349
//this is the number of samples that are required at each period
1244
stream->in.framesPerHostCallback = (unsigned long)samplesPerPeriod;//unrelated to channels
1350
stream->in.framesPerHostCallback = (unsigned long) samplesPerPeriod;//unrelated to channels
1246
1352
/* IMPLEMENT ME - establish which host formats are available */
1247
1353
hostInputSampleFormat =
1248
PaUtil_SelectClosestAvailableFormat( waveformatToPaFormat(&stream->in.wavex), inputSampleFormat );
1354
PaUtil_SelectClosestAvailableFormat (waveformatToPaFormat (&stream->in.wavex), inputSampleFormat);
1252
1356
inputChannelCount = 0;
1253
1357
inputSampleFormat = hostInputSampleFormat = paInt16; /* Surpress 'uninitialised var' warnings. */
1256
if( outputParameters )
1360
if (outputParameters) {
1258
1361
outputChannelCount = outputParameters->channelCount;
1259
1362
outputSampleFormat = outputParameters->sampleFormat;
1261
1364
/* unless alternate device specification is supported, reject the use of
1262
1365
paUseHostApiSpecificDeviceSpecification */
1264
if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
1367
if (outputParameters->device == paUseHostApiSpecificDeviceSpecification)
1265
1368
return paInvalidDevice;
1267
1370
/* check that output device can support inputChannelCount */
1268
if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
1371
if (outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels)
1269
1372
return paInvalidChannelCount;
1271
1374
/* validate outputStreamInfo */
1272
if( outputParameters->hostApiSpecificStreamInfo )
1375
if (outputParameters->hostApiSpecificStreamInfo)
1273
1376
return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
1276
1379
PaWinWasapiDeviceInfo &info = paWasapi->devInfo[outputParameters->device];
1278
HRESULT hResult = info.device->Activate(
1279
__uuidof(IAudioClient), CLSCTX_INPROC_SERVER, NULL,
1280
(void**)&stream->out.client);
1381
HRESULT hResult = info.device->Activate (
1382
__uuidof (IAudioClient), CLSCTX_INPROC_SERVER, NULL,
1383
(void**) &stream->out.client);
1282
1385
if (hResult != S_OK)
1283
1386
return paInvalidDevice;
1285
AUDCLNT_SHAREMODE shareMode;
1286
PaError answer = GetClosestFormat(stream->out.client,sampleRate,outputParameters,&shareMode,&stream->out.wavex);
1288
if (answer !=paFormatIsSupported)
1290
LogWAVEFORMATEXTENSIBLE(&stream->out.wavex);
1292
// stream->out.period = info.DefaultDevicePeriod;
1388
AUDCLNT_SHAREMODE shareMode;
1389
PaError answer = GetClosestFormat (stream->out.client,sampleRate,outputParameters,&shareMode,&stream->out.wavex);
1391
if (answer !=paFormatIsSupported)
1394
LogWAVEFORMATEXTENSIBLE (&stream->out.wavex);
1396
// stream->out.period = info.DefaultDevicePeriod;
1293
1397
stream->out.period = info.MinimumDevicePeriod;
1295
/*For an exclusive-mode stream that uses event-driven buffering,
1296
the caller must specify nonzero values for hnsPeriodicity and hnsBufferDuration,
1297
and the values of these two parameters must be equal */
1298
if (shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE){
1299
hResult = stream->out.client->Initialize(
1301
AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
1304
(WAVEFORMATEX*)&stream->out.wavex,
1309
hResult = stream->out.client->Initialize(
1311
AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
1314
(WAVEFORMATEX*)&stream->out.wavex,
1320
if (hResult != S_OK){
1321
logAUDCLNT_E(hResult);
1322
return paInvalidDevice;
1325
hResult = info.device->Activate(
1326
__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL,
1327
(void**)&stream->outVol);
1329
if (hResult != S_OK)
1330
return paInvalidDevice;
1332
hResult = stream->out.client->GetBufferSize(&stream->out.bufferSize);
1333
if (hResult != S_OK)
1334
return paInvalidDevice;
1336
hResult = stream->out.client->GetStreamLatency(&stream->out.latency);
1337
if (hResult != S_OK)
1338
return paInvalidDevice;
1340
double periodsPerSecond = 1.0/nano100ToSeconds(stream->out.period);
1341
double samplesPerPeriod = (double)(stream->out.wavex.Format.nSamplesPerSec)/periodsPerSecond;
1399
/*For an exclusive-mode stream that uses event-driven buffering,
1400
the caller must specify nonzero values for hnsPeriodicity and hnsBufferDuration,
1401
and the values of these two parameters must be equal */
1402
if (shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE) {
1403
hResult = stream->out.client->Initialize (
1405
AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
1408
(WAVEFORMATEX*) &stream->out.wavex,
1412
hResult = stream->out.client->Initialize (
1414
AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
1417
(WAVEFORMATEX*) &stream->out.wavex,
1423
if (hResult != S_OK) {
1424
logAUDCLNT_E (hResult);
1425
return paInvalidDevice;
1428
hResult = info.device->Activate (
1429
__uuidof (IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL,
1430
(void**) &stream->outVol);
1432
if (hResult != S_OK)
1433
return paInvalidDevice;
1435
hResult = stream->out.client->GetBufferSize (&stream->out.bufferSize);
1437
if (hResult != S_OK)
1438
return paInvalidDevice;
1440
hResult = stream->out.client->GetStreamLatency (&stream->out.latency);
1442
if (hResult != S_OK)
1443
return paInvalidDevice;
1445
double periodsPerSecond = 1.0/nano100ToSeconds (stream->out.period);
1446
double samplesPerPeriod = (double) (stream->out.wavex.Format.nSamplesPerSec) /periodsPerSecond;
1343
1448
//this is the number of samples that are required at each period
1344
1449
stream->out.framesPerHostCallback = stream->out.bufferSize; //(unsigned long)samplesPerPeriod;//unrelated to channels
1346
1451
/* IMPLEMENT ME - establish which host formats are available */
1347
hostOutputSampleFormat = PaUtil_SelectClosestAvailableFormat( waveformatToPaFormat(&stream->out.wavex), outputSampleFormat );
1452
hostOutputSampleFormat = PaUtil_SelectClosestAvailableFormat (waveformatToPaFormat (&stream->out.wavex), outputSampleFormat);
1351
1454
outputChannelCount = 0;
1352
1455
outputSampleFormat = hostOutputSampleFormat = paInt16; /* Surpress 'uninitialized var' warnings. */
1383
1486
/* validate platform specific flags */
1384
if( (streamFlags & paPlatformSpecificFlags) != 0 )
1487
if ( (streamFlags & paPlatformSpecificFlags) != 0)
1385
1488
return paInvalidFlag; /* unexpected platform specific flag */
1389
if( streamCallback )
1391
PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
1392
&paWasapi->callbackStreamInterface, streamCallback, userData );
1396
PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
1397
&paWasapi->blockingStreamInterface, streamCallback, userData );
1400
PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );
1403
if (outputParameters && inputParameters){
1405
//serious problem #1
1406
if (stream->in.period != stream->out.period){
1407
PRINT(("OpenStream: period discrepancy\n"));
1411
//serious problem #2
1412
if (stream->out.framesPerHostCallback != stream->in.framesPerHostCallback){
1413
PRINT(("OpenStream: framesPerHostCallback discrepancy\n"));
1418
unsigned long framesPerHostCallback = (outputParameters)?
1419
stream->out.framesPerHostCallback:
1420
stream->in.framesPerHostCallback;
1492
if (streamCallback) {
1493
PaUtil_InitializeStreamRepresentation (&stream->streamRepresentation,
1494
&paWasapi->callbackStreamInterface, streamCallback, userData);
1496
PaUtil_InitializeStreamRepresentation (&stream->streamRepresentation,
1497
&paWasapi->blockingStreamInterface, streamCallback, userData);
1500
PaUtil_InitializeCpuLoadMeasurer (&stream->cpuLoadMeasurer, sampleRate);
1503
if (outputParameters && inputParameters) {
1505
//serious problem #1
1506
if (stream->in.period != stream->out.period) {
1507
PRINT ( ("OpenStream: period discrepancy\n"));
1511
//serious problem #2
1512
if (stream->out.framesPerHostCallback != stream->in.framesPerHostCallback) {
1513
PRINT ( ("OpenStream: framesPerHostCallback discrepancy\n"));
1518
unsigned long framesPerHostCallback = (outputParameters) ?
1519
stream->out.framesPerHostCallback:
1520
stream->in.framesPerHostCallback;
1422
1522
/* we assume a fixed host buffer size in this example, but the buffer processor
1423
1523
can also support bounded and unknown host buffer sizes by passing
1424
1524
paUtilBoundedHostBufferSize or paUtilUnknownHostBufferSize instead of
1425
1525
paUtilFixedHostBufferSize below. */
1427
result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor,
1527
result = PaUtil_InitializeBufferProcessor (&stream->bufferProcessor,
1428
1528
inputChannelCount, inputSampleFormat, hostInputSampleFormat,
1429
1529
outputChannelCount, outputSampleFormat, hostOutputSampleFormat,
1430
1530
sampleRate, streamFlags, framesPerBuffer,
1431
1531
framesPerHostCallback, paUtilFixedHostBufferSize,
1432
streamCallback, userData );
1433
if( result != paNoError )
1532
streamCallback, userData);
1534
if (result != paNoError)
1472
1574
if ((punk) != NULL) \
1473
1575
{ (punk)->Release(); (punk) = NULL; }
1475
static PaError CloseStream( PaStream* s )
1577
static PaError CloseStream (PaStream* s)
1477
1579
PaError result = paNoError;
1478
PaWinWasapiStream *stream = (PaWinWasapiStream*)s;
1580
PaWinWasapiStream *stream = (PaWinWasapiStream*) s;
1482
1584
- additional stream closing + cleanup
1485
SAFE_RELEASE(stream->out.client);
1486
SAFE_RELEASE(stream->in.client);
1487
SAFE_RELEASE(stream->cclient);
1488
SAFE_RELEASE(stream->rclient);
1489
SAFE_RELEASE(stream->inVol);
1490
SAFE_RELEASE(stream->outVol);
1491
CloseHandle(stream->hThread);
1492
CloseHandle(stream->hNotificationEvent);
1587
SAFE_RELEASE (stream->out.client);
1588
SAFE_RELEASE (stream->in.client);
1589
SAFE_RELEASE (stream->cclient);
1590
SAFE_RELEASE (stream->rclient);
1591
SAFE_RELEASE (stream->inVol);
1592
SAFE_RELEASE (stream->outVol);
1593
CloseHandle (stream->hThread);
1594
CloseHandle (stream->hNotificationEvent);
1494
PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
1495
PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
1496
PaUtil_FreeMemory( stream );
1596
PaUtil_TerminateBufferProcessor (&stream->bufferProcessor);
1597
PaUtil_TerminateStreamRepresentation (&stream->streamRepresentation);
1598
PaUtil_FreeMemory (stream);
1501
DWORD WINAPI ProcThread(void *client);
1603
DWORD WINAPI ProcThread (void *client);
1503
static PaError StartStream( PaStream *s )
1605
static PaError StartStream (PaStream *s)
1505
1607
PaError result = paNoError;
1506
PaWinWasapiStream *stream = (PaWinWasapiStream*)s;
1508
PaUtil_ResetBufferProcessor( &stream->bufferProcessor );
1510
HRESULT hResult=S_OK;
1512
if (stream->out.client){
1513
hResult = stream->out.client->GetService(__uuidof(IAudioRenderClient),(void**)&stream->rclient);
1514
logAUDCLNT_E(hResult);
1516
return paUnanticipatedHostError;
1519
if (stream->in.client){
1520
hResult = stream->in.client->GetService(__uuidof(IAudioCaptureClient),(void**)&stream->cclient);
1521
logAUDCLNT_E(hResult);
1523
return paUnanticipatedHostError;
1608
PaWinWasapiStream *stream = (PaWinWasapiStream*) s;
1610
PaUtil_ResetBufferProcessor (&stream->bufferProcessor);
1612
HRESULT hResult=S_OK;
1614
if (stream->out.client) {
1615
hResult = stream->out.client->GetService (__uuidof (IAudioRenderClient), (void**) &stream->rclient);
1616
logAUDCLNT_E (hResult);
1619
return paUnanticipatedHostError;
1622
if (stream->in.client) {
1623
hResult = stream->in.client->GetService (__uuidof (IAudioCaptureClient), (void**) &stream->cclient);
1624
logAUDCLNT_E (hResult);
1627
return paUnanticipatedHostError;
1526
1630
// Create a thread for this client.
1527
1631
stream->hThread = CREATE_THREAD;
1529
1633
if (stream->hThread == NULL)
1530
1634
return paUnanticipatedHostError;
1746
1850
host format, do it here.
1749
PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed );
1752
if( callbackResult == paContinue )
1853
PaUtil_EndCpuLoadMeasurement (&stream->cpuLoadMeasurer, framesProcessed);
1856
if (callbackResult == paContinue) {
1754
1857
/* nothing special to do */
1756
else if( callbackResult == paAbort )
1858
} else if (callbackResult == paAbort) {
1758
1859
/* IMPLEMENT ME - finish playback immediately */
1760
1861
/* once finished, call the finished callback */
1761
if( stream->streamRepresentation.streamFinishedCallback != 0 )
1762
stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
1862
if (stream->streamRepresentation.streamFinishedCallback != 0)
1863
stream->streamRepresentation.streamFinishedCallback (stream->streamRepresentation.userData);
1766
1865
/* User callback has asked us to stop with paComplete or other non-zero value */
1768
1867
/* IMPLEMENT ME - finish playback once currently queued audio has completed */
1770
1869
/* once finished, call the finished callback */
1771
if( stream->streamRepresentation.streamFinishedCallback != 0 )
1772
stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
1870
if (stream->streamRepresentation.streamFinishedCallback != 0)
1871
stream->streamRepresentation.streamFinishedCallback (stream->streamRepresentation.userData);
1781
HANDLE thCarac = pAvSetMmThreadCharacteristics("Pro Audio",&stuff);
1783
PRINT(("AvSetMmThreadCharacteristics failed!\n"));
1786
BOOL prio = pAvSetMmThreadPriority(thCarac,AVRT_PRIORITY_NORMAL);
1788
PRINT(("AvSetMmThreadPriority failed!\n"));
1881
HANDLE thCarac = pAvSetMmThreadCharacteristics ("Pro Audio",&stuff);
1884
PRINT ( ("AvSetMmThreadCharacteristics failed!\n"));
1887
BOOL prio = pAvSetMmThreadPriority (thCarac,AVRT_PRIORITY_NORMAL);
1890
PRINT ( ("AvSetMmThreadPriority failed!\n"));
1793
1895
HANDLE hh = GetCurrentThread();
1794
int currprio = GetThreadPriority(hh);
1795
DWORD currclass = GetPriorityClass(GetCurrentProcess());
1796
PRINT(("currprio 0x%X currclass 0x%X\n",currprio,currclass));
1896
int currprio = GetThreadPriority (hh);
1897
DWORD currclass = GetPriorityClass (GetCurrentProcess());
1898
PRINT ( ("currprio 0x%X currclass 0x%X\n",currprio,currclass));
1802
ProcThread(void* param){
1806
PaWinWasapiStream *stream = (PaWinWasapiStream*)param;
1808
stream->hNotificationEvent = CreateEvent(NULL,
1809
FALSE, //bManualReset are we sure??
1812
hResult = stream->out.client->SetEventHandle(stream->hNotificationEvent);
1813
if (hResult != S_OK)
1814
logAUDCLNT_E(hResult);
1816
if (stream->out.client){
1817
hResult = stream->out.client->Start();
1818
if (hResult != S_OK)
1819
logAUDCLNT_E(hResult);
1822
stream->running = true;
1825
while( !stream->closeRequest )
1827
//lets wait but have a 1 second timeout
1828
DWORD dwResult = WaitForSingleObject(stream->hNotificationEvent, 1000);
1829
switch( dwResult ) {
1830
case WAIT_OBJECT_0: {
1832
unsigned long usingBS = stream->out.framesPerHostCallback;
1837
hResult = stream->rclient->GetBuffer(usingBS, &outdata);
1839
if (hResult != S_OK || !outdata) {
1840
//logAUDCLNT_E(hResult);
1841
//most probably shared mode and hResult=AUDCLNT_E_BUFFER_TOO_LARGE
1843
hResult = stream->out.client->GetCurrentPadding(&padding);
1846
usingBS = usingBS-padding;
1849
hResult = stream->rclient->GetBuffer(usingBS, &outdata);
1850
if (hResult != S_OK)//what can we do NOW??
1852
//logAUDCLNT_E(hResult);
1855
WaspiHostProcessingLoop(indata, usingBS ,outdata, usingBS, stream);
1857
hResult = stream->rclient->ReleaseBuffer(usingBS, 0);
1858
if (hResult != S_OK)
1859
logAUDCLNT_E(hResult);
1861
/* This was suggested, but in my tests it doesnt seem to improve the
1862
locking behaviour some drivers have running in exclusive mode.
1863
if(!ResetEvent(stream->hNotificationEvent)){
1864
logAUDCLNT_E(hResult);
1904
ProcThread (void* param)
1909
PaWinWasapiStream *stream = (PaWinWasapiStream*) param;
1911
stream->hNotificationEvent = CreateEvent (NULL,
1912
FALSE, //bManualReset are we sure??
1915
hResult = stream->out.client->SetEventHandle (stream->hNotificationEvent);
1917
if (hResult != S_OK)
1918
logAUDCLNT_E (hResult);
1920
if (stream->out.client) {
1921
hResult = stream->out.client->Start();
1923
if (hResult != S_OK)
1924
logAUDCLNT_E (hResult);
1927
stream->running = true;
1930
while (!stream->closeRequest) {
1931
//lets wait but have a 1 second timeout
1932
DWORD dwResult = WaitForSingleObject (stream->hNotificationEvent, 1000);
1935
case WAIT_OBJECT_0: {
1937
unsigned long usingBS = stream->out.framesPerHostCallback;
1942
hResult = stream->rclient->GetBuffer (usingBS, &outdata);
1944
if (hResult != S_OK || !outdata) {
1945
//logAUDCLNT_E(hResult);
1946
//most probably shared mode and hResult=AUDCLNT_E_BUFFER_TOO_LARGE
1948
hResult = stream->out.client->GetCurrentPadding (&padding);
1953
usingBS = usingBS-padding;
1958
hResult = stream->rclient->GetBuffer (usingBS, &outdata);
1960
if (hResult != S_OK) //what can we do NOW??
1963
//logAUDCLNT_E(hResult);
1966
WaspiHostProcessingLoop (indata, usingBS ,outdata, usingBS, stream);
1968
hResult = stream->rclient->ReleaseBuffer (usingBS, 0);
1970
if (hResult != S_OK)
1971
logAUDCLNT_E (hResult);
1973
/* This was suggested, but in my tests it doesnt seem to improve the
1974
locking behaviour some drivers have running in exclusive mode.
1975
if(!ResetEvent(stream->hNotificationEvent)){
1976
logAUDCLNT_E(hResult);
1873
stream->out.client->Stop();
1986
stream->out.client->Stop();
1874
1987
stream->closeRequest = false;