⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pa_win_wasapi.cpp

📁 一个开源的sip源代码
💻 CPP
📖 第 1 页 / 共 5 页
字号:
        goto error;
    }

    paWasapi->allocations = PaUtil_CreateAllocationGroup();
    if( !paWasapi->allocations ){
        result = paInsufficientMemory;
        goto error;
    }

    *hostApi = &paWasapi->inheritedHostApiRep;
    (*hostApi)->info.structVersion = 1;
    (*hostApi)->info.type = paWASAPI;
    (*hostApi)->info.name = "Windows WASAPI";
    (*hostApi)->info.deviceCount = 0;   //so far, we must investigate each
    (*hostApi)->info.defaultInputDevice  = paNoDevice;  /* IMPLEMENT ME */
    (*hostApi)->info.defaultOutputDevice = paNoDevice; /* IMPLEMENT ME */


    HRESULT hResult = S_OK;
    IMMDeviceCollection* spEndpoints=0;
    paWasapi->enumerator = 0;

    if (!setupAVRT()){
        PRINT(("Windows WASAPI : No AVRT! (not VISTA?)"));
        goto error;
    }

    hResult = CoCreateInstance(
             __uuidof(MMDeviceEnumerator), NULL,CLSCTX_INPROC_SERVER,
             __uuidof(IMMDeviceEnumerator),
             (void**)&paWasapi->enumerator);

    IF_FAILED_JUMP(hResult, error);

    //getting default device ids in the eMultimedia "role"
    {
        {
            IMMDevice* defaultRenderer=0;
            hResult = paWasapi->enumerator->GetDefaultAudioEndpoint(eRender, eMultimedia, &defaultRenderer);
            IF_FAILED_JUMP(hResult, error);
            WCHAR* pszDeviceId = NULL;
            hResult = defaultRenderer->GetId(&pszDeviceId);
            IF_FAILED_JUMP(hResult, error);
            StringCchCopyW(paWasapi->defaultRenderer, MAX_STR_LEN-1, pszDeviceId);
            CoTaskMemFree(pszDeviceId);
            defaultRenderer->Release();
        }

        {
            IMMDevice* defaultCapturer=0;
            hResult = paWasapi->enumerator->GetDefaultAudioEndpoint(eCapture, eMultimedia, &defaultCapturer);
            IF_FAILED_JUMP(hResult, error);
            WCHAR* pszDeviceId = NULL;
            hResult = defaultCapturer->GetId(&pszDeviceId);
            IF_FAILED_JUMP(hResult, error);
            StringCchCopyW(paWasapi->defaultCapturer, MAX_STR_LEN-1, pszDeviceId);
            CoTaskMemFree(pszDeviceId);
            defaultCapturer->Release();
        }
    }


    hResult = paWasapi->enumerator->EnumAudioEndpoints(eAll, DEVICE_STATE_ACTIVE, &spEndpoints);
    IF_FAILED_JUMP(hResult, error);

    hResult = spEndpoints->GetCount(&paWasapi->deviceCount);
    IF_FAILED_JUMP(hResult, error);

    paWasapi->devInfo = new PaWinWasapiDeviceInfo[paWasapi->deviceCount];
    {
        for (size_t step=0;step<paWasapi->deviceCount;++step)
            memset(&paWasapi->devInfo[step],0,sizeof(PaWinWasapiDeviceInfo));
    }



    if( paWasapi->deviceCount > 0 )
    {
        (*hostApi)->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
                paWasapi->allocations, sizeof(PaDeviceInfo*) * paWasapi->deviceCount );
        if( !(*hostApi)->deviceInfos ){
            result = paInsufficientMemory;
            goto error;
        }

        /* allocate all device info structs in a contiguous block */
        deviceInfoArray = (PaDeviceInfo*)PaUtil_GroupAllocateMemory(
                paWasapi->allocations, sizeof(PaDeviceInfo) * paWasapi->deviceCount );
        if( !deviceInfoArray ){
            result = paInsufficientMemory;
            goto error;
        }

        for( UINT i=0; i < paWasapi->deviceCount; ++i ){

            PaDeviceInfo *deviceInfo = &deviceInfoArray[i];
            deviceInfo->structVersion = 2;
            deviceInfo->hostApi = hostApiIndex;

            hResult = spEndpoints->Item(i, &paWasapi->devInfo[i].device);
            IF_FAILED_JUMP(hResult, error);

            //getting ID
            {
                WCHAR* pszDeviceId = NULL;
                hResult = paWasapi->devInfo[i].device->GetId(&pszDeviceId);
                IF_FAILED_JUMP(hResult, error);
                StringCchCopyW(paWasapi->devInfo[i].szDeviceID, MAX_STR_LEN-1, pszDeviceId);
                CoTaskMemFree(pszDeviceId);

                if (lstrcmpW(paWasapi->devInfo[i].szDeviceID, paWasapi->defaultCapturer)==0){
                    //we found the default input!
                    (*hostApi)->info.defaultInputDevice = (*hostApi)->info.deviceCount;
                }
                if (lstrcmpW(paWasapi->devInfo[i].szDeviceID, paWasapi->defaultRenderer)==0){
                    //we found the default output!
                    (*hostApi)->info.defaultOutputDevice = (*hostApi)->info.deviceCount;
                }
            }

            DWORD state=0;
            hResult = paWasapi->devInfo[i].device->GetState(&paWasapi->devInfo[i].state);
            IF_FAILED_JUMP(hResult, error);

            if (paWasapi->devInfo[i].state != DEVICE_STATE_ACTIVE){
                PRINT(("WASAPI device:%d is not currently available (state:%d)\n",i,state));
                //spDevice->Release();
                //continue;
            }

            {
                IPropertyStore* spProperties;
                hResult = paWasapi->devInfo[i].device->OpenPropertyStore(STGM_READ, &spProperties);
                IF_FAILED_JUMP(hResult, error);

                //getting "Friendly" Name
                {
                    PROPVARIANT value;
                    PropVariantInit(&value);
                    hResult = spProperties->GetValue(PKEY_Device_FriendlyName, &value);
                    IF_FAILED_JUMP(hResult, error);
                    deviceInfo->name = 0;
                    char* deviceName = (char*)PaUtil_GroupAllocateMemory( paWasapi->allocations, MAX_STR_LEN + 1 );
                    if( !deviceName ){
                        result = paInsufficientMemory;
                        goto error;
                    }
					if (value.pwszVal)
						wcstombs(deviceName,   value.pwszVal,MAX_STR_LEN-1); //todo proper size	
					else{
						sprintf(deviceName,"baddev%d",i);
					}

                    deviceInfo->name = deviceName;
                    PropVariantClear(&value);
                }

#if 0
                DWORD numProps = 0;
                hResult = spProperties->GetCount(&numProps);
                IF_FAILED_JUMP(hResult, error);
                {
                    for (DWORD i=0;i<numProps;++i){
                        PROPERTYKEY pkey;
                        hResult = spProperties->GetAt(i,&pkey);

                        PROPVARIANT value;
                        PropVariantInit(&value);
                        hResult = spProperties->GetValue(pkey, &value);

                        switch(value.vt){
                            case 11:
                                PRINT(("property*%u*\n",value.ulVal));
                            break;
                            case 19:
                                PRINT(("property*%d*\n",value.boolVal));
                            break;
                            case 31:
                            {
                                char temp[512];
                                wcstombs(temp,    value.pwszVal,MAX_STR_LEN-1);
                                PRINT(("property*%s*\n",temp));
                            }
                            break;
                            default:break;
                        }

                        PropVariantClear(&value);
                    }
                }
#endif

                /*  These look interresting... but they are undocumented
                PKEY_AudioEndpoint_FormFactor
                PKEY_AudioEndpoint_ControlPanelPageProvider
                PKEY_AudioEndpoint_Association
                PKEY_AudioEndpoint_PhysicalSpeakerConfig
                PKEY_AudioEngine_DeviceFormat
                */
                spProperties->Release();
            }


            //getting the Endpoint data
            {
                IMMEndpoint *endpoint=0;
                hResult = paWasapi->devInfo[i].device->QueryInterface(__uuidof(IMMEndpoint),(void **)&endpoint);
                if (SUCCEEDED(hResult)){
                    hResult = endpoint->GetDataFlow(&paWasapi->devInfo[i].flow);
                    endpoint->Release();
                }
            }

            //Getting a temporary IAudioDevice for more fields
            //we make sure NOT to call Initialize yet!
            {
                IAudioClient *myClient=0;

                hResult = paWasapi->devInfo[i].device->Activate(__uuidof(IAudioClient), CLSCTX_INPROC_SERVER, NULL, (void**)&myClient);
                IF_FAILED_JUMP(hResult, error);

                hResult = myClient->GetDevicePeriod(
                    &paWasapi->devInfo[i].DefaultDevicePeriod,
                    &paWasapi->devInfo[i].MinimumDevicePeriod);
                IF_FAILED_JUMP(hResult, error);

                hResult = myClient->GetMixFormat(&paWasapi->devInfo[i].MixFormat);

                IF_FAILED_JUMP(hResult, error);
                myClient->Release();
            }

            //we can now fill in portaudio device data
            deviceInfo->maxInputChannels  = 0;  //for now
            deviceInfo->maxOutputChannels = 0;  //for now

            switch(paWasapi->devInfo[i].flow){
                case eRender:
                    //hum not exaclty maximum, more like "default"
                    deviceInfo->maxOutputChannels = paWasapi->devInfo[i].MixFormat->nChannels;

                    deviceInfo->defaultHighOutputLatency = nano100ToSeconds(paWasapi->devInfo[i].DefaultDevicePeriod);
                    deviceInfo->defaultLowOutputLatency  = nano100ToSeconds(paWasapi->devInfo[i].MinimumDevicePeriod);
                break;
                case eCapture:
                    //hum not exaclty maximum, more like "default"
                    deviceInfo->maxInputChannels  = paWasapi->devInfo[i].MixFormat->nChannels;

                    deviceInfo->defaultHighInputLatency = nano100ToSeconds(paWasapi->devInfo[i].DefaultDevicePeriod);
                    deviceInfo->defaultLowInputLatency  = nano100ToSeconds(paWasapi->devInfo[i].MinimumDevicePeriod);
                break;
                default:
                    PRINT(("WASAPI device:%d bad Data FLow! \n",i));
                    goto error;
                break;
            }

            deviceInfo->defaultSampleRate = (double)paWasapi->devInfo[i].MixFormat->nSamplesPerSec;

            (*hostApi)->deviceInfos[i] = deviceInfo;
            ++(*hostApi)->info.deviceCount;
        }
    }

    spEndpoints->Release();

    (*hostApi)->Terminate = Terminate;
    (*hostApi)->OpenStream = OpenStream;
    (*hostApi)->IsFormatSupported = IsFormatSupported;

    PaUtil_InitializeStreamInterface( &paWasapi->callbackStreamInterface, CloseStream, StartStream,
                                      StopStream, AbortStream, IsStreamStopped, IsStreamActive,
                                      GetStreamTime, GetStreamCpuLoad,
                                      PaUtil_DummyRead, PaUtil_DummyWrite,
                                      PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable );

    PaUtil_InitializeStreamInterface( &paWasapi->blockingStreamInterface, CloseStream, StartStream,
                                      StopStream, AbortStream, IsStreamStopped, IsStreamActive,
                                      GetStreamTime, PaUtil_DummyGetCpuLoad,
                                      ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable );

    return result;

error:

    if (spEndpoints)
        spEndpoints->Release();

    if (paWasapi->enumerator)
        paWasapi->enumerator->Release();

    if( paWasapi )
    {
        if( paWasapi->allocations )
        {
            PaUtil_FreeAllAllocations( paWasapi->allocations );
            PaUtil_DestroyAllocationGroup( paWasapi->allocations );
        }

        PaUtil_FreeMemory( paWasapi );
    }
    return result;
}


static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
{
    PaWinWasapiHostApiRepresentation *paWasapi = (PaWinWasapiHostApiRepresentation*)hostApi;

    paWasapi->enumerator->Release();

    for (UINT i=0;i<paWasapi->deviceCount;++i){
        PaWinWasapiDeviceInfo *info = &paWasapi->devInfo[i];

        if (info->device)
            info->device->Release();

        if (info->MixFormat)
            CoTaskMemFree(info->MixFormat);
    }
    delete [] paWasapi->devInfo;

    CoUninitialize();

    if( paWasapi->allocations ){
        PaUtil_FreeAllAllocations( paWasapi->allocations );
        PaUtil_DestroyAllocationGroup( paWasapi->allocations );
    }

    PaUtil_FreeMemory( paWasapi );
}

static void
LogWAVEFORMATEXTENSIBLE(const WAVEFORMATEXTENSIBLE &in){

    const WAVEFORMATEX *old = (WAVEFORMATEX *)&in;

	switch (old->wFormatTag){
		case WAVE_FORMAT_EXTENSIBLE:{

			PRINT(("wFormatTag=WAVE_FORMAT_EXTENSIBLE\n"));

			if (in.SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT){
				PRINT(("SubFormat=KSDATAFORMAT_SUBTYPE_IEEE_FLOAT\n"));
			}
			else if (in.SubFormat == KSDATAFORMAT_SUBTYPE_PCM){
				PRINT(("SubFormat=KSDATAFORMAT_SUBTYPE_PCM\n"));
			}
			else{
				PRINT(("SubFormat=CUSTOM GUID{%d:%d:%d:%d%d%d%d%d%d%d%d}\n",	
											in.SubFormat.Data1,
											in.SubFormat.Data2,
											in.SubFormat.Data3,
											(int)in.SubFormat.Data4[0],
											(int)in.SubFormat.Data4[1],
											(int)in.SubFormat.Data4[2],
											(int)in.SubFormat.Data4[3],
											(int)in.SubFormat.Data4[4],
											(int)in.SubFormat.Data4[5],

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -