// // FormatHelpers.h -- Copyright (c) Microsoft Corporation // // Author: zaneh // // Description: // // Format Helpers for test formats used in APODeviceTest // #pragma once #include #include #include #include #include #include // Consts used for APO format creation static const int cFrameRate = 48000; // 48kHz static const int cProcessingPeriod = 10; // milliseconds static const int cMaxFrameCount = cFrameRate * cProcessingPeriod / 1000; static const int cFrameCountToProcess = cMaxFrameCount / 2; // Returns true if the two IAudioMediaType formats are equal. // False otherwise bool IsEqualFormat ( IAudioMediaType *pIAMTFormat1, IAudioMediaType *pIAMTFormat2 ) { UINT cbBuffer1, cbBuffer2; WAVEFORMATEX const *pwfx1, *pwfx2; UNCOMPRESSEDAUDIOFORMAT format1, format2; pwfx1 = pIAMTFormat1->GetAudioFormat(); pwfx2 = pIAMTFormat2->GetAudioFormat(); cbBuffer1 = ((WAVE_FORMAT_PCM == pwfx1->wFormatTag)?sizeof(PCMWAVEFORMAT):(sizeof(WAVEFORMATEX) + pwfx1->cbSize)); cbBuffer2 = ((WAVE_FORMAT_PCM == pwfx2->wFormatTag)?sizeof(PCMWAVEFORMAT):(sizeof(WAVEFORMATEX) + pwfx2->cbSize)); if (cbBuffer1 != cbBuffer2) { return false; } // Two formats don't compare as WAVEFORMATEX... if (0 != memcmp(pwfx1, pwfx2, cbBuffer1)) { return false; } SecureZeroMemory(&format1, sizeof(format1)); SecureZeroMemory(&format2, sizeof(format2)); if (S_OK != pIAMTFormat1->GetUncompressedAudioFormat(&format1)) { return false; } if (S_OK != pIAMTFormat2->GetUncompressedAudioFormat(&format2)) { return false; } // Two formats don't compare as WAVEFORMATEX... if (0 != memcmp(&format1, &format2, sizeof(UNCOMPRESSEDAUDIOFORMAT))) { return false; } return true; } // Creates a KSData format from the given WaveFormatEx // Returns a struct containing both the KSData format and WaveFormatEx KSDATAFORMAT_WAVEFORMATEX *CreateKSDataFromWFX ( WAVEFORMATEX *pwfx ) { if (nullptr == pwfx) { return nullptr; } UINT cbAlloc; cbAlloc = sizeof(KSDATAFORMAT_WAVEFORMATEX) + pwfx->cbSize; wil::unique_cotaskmem_ptr pKsFormat((KSDATAFORMAT_WAVEFORMATEX*)(CoTaskMemAlloc(cbAlloc))); if (nullptr == pKsFormat) { return nullptr; } pKsFormat->DataFormat.FormatSize = cbAlloc; pKsFormat->DataFormat.Flags = 0; pKsFormat->DataFormat.Reserved = 0; pKsFormat->DataFormat.MajorFormat = KSDATAFORMAT_TYPE_AUDIO; pKsFormat->DataFormat.Specifier = KSDATAFORMAT_SPECIFIER_WAVEFORMATEX; CopyMemory(&(pKsFormat->WaveFormatEx), pwfx, sizeof(WAVEFORMATEX) + pwfx->cbSize); if (WAVE_FORMAT_EXTENSIBLE == pwfx->wFormatTag) { pKsFormat->DataFormat.SubFormat = ((WAVEFORMATEXTENSIBLE*)(pwfx))->SubFormat; } else { INIT_WAVEFORMATEX_GUID(&(pKsFormat->DataFormat.SubFormat), pwfx->wFormatTag); } return (pKsFormat.release()); } // Creates an IAudioMediaType given an uncompressed audio format HRESULT AECreateAudioMediaTypeFromUncompressedAudioFormat(const UNCOMPRESSEDAUDIOFORMAT* pUncompressedAudioFormat,IAudioMediaType** ppIAudioMediaType) { RETURN_IF_FAILED(CTestAudioMediaType::Create(pUncompressedAudioFormat, ppIAudioMediaType)); return S_OK; } // Creates an IAudioMediaType given a WaveFormatEx HRESULT AECreateAudioMediaType(const WAVEFORMATEX* pWfx, IAudioMediaType** ppIAudioMediaType) { UNCOMPRESSEDAUDIOFORMAT audioFormat; audioFormat.dwBytesPerSampleContainer = pWfx->nBlockAlign / pWfx->nChannels; audioFormat.dwSamplesPerFrame = pWfx->nChannels; if (WAVE_FORMAT_EXTENSIBLE == pWfx->wFormatTag) { audioFormat.dwValidBitsPerSample = ((WAVEFORMATEXTENSIBLE*)pWfx)->Samples.wValidBitsPerSample; audioFormat.fFramesPerSecond = (float)(((WAVEFORMATEXTENSIBLE*)pWfx)->Format.nSamplesPerSec); audioFormat.guidFormatType = ((WAVEFORMATEXTENSIBLE*)pWfx)->SubFormat; } else { audioFormat.dwValidBitsPerSample = pWfx->wBitsPerSample; audioFormat.fFramesPerSecond = (float)(pWfx->nSamplesPerSec); INIT_WAVEFORMATEX_GUID(&(audioFormat.guidFormatType), pWfx->wFormatTag); } RETURN_IF_FAILED(CTestAudioMediaType::Create(&audioFormat, ppIAudioMediaType)); return S_OK; } // Fills an APO connection using the provided uncompressed format. // If pBuffer is NULL, the connection will be created with an APO_CONNECTION_BUFFER_TYPE_ALLOCATED. // If pBuffer is not null, APO_CONNECTION_BUFFER_TYPE_EXTERNAL will be used. // Outptr pConnection returns an APO_CONNECTION_DESCRIPTOR HRESULT FillConnection ( UNCOMPRESSEDAUDIOFORMAT* Format, UINT_PTR pBuffer, UINT32 /* u32ExtraFrameCount */, UINT32 u32MaxFrameCount, APO_CONNECTION_DESCRIPTOR* pConnection ) { if (Format == nullptr) { LOG_ERROR(L"FillConnection recieved null format"); return E_INVALIDARG; } if (pConnection == nullptr) { LOG_ERROR(L"FillConnection recieved null APO connection descriptor"); return E_INVALIDARG; } IAudioMediaType *pFormat; // Attempt to create the AudioMediaType using the standard API HRESULT createFormatHr = CreateAudioMediaTypeFromUncompressedAudioFormat( Format, &pFormat); if (FAILED(createFormatHr)) { LOG_OUTPUT(L"Standard AudioMediaType creation failed. Attempting creation using TestMediaType"); RETURN_IF_FAILED(AECreateAudioMediaTypeFromUncompressedAudioFormat(Format, &pFormat)); } // set connection type based on pBuffer // this will get re(set) when the actual allocation occurs if (NULL != pBuffer) { pConnection->Type = APO_CONNECTION_BUFFER_TYPE_EXTERNAL; } else { pConnection->Type = APO_CONNECTION_BUFFER_TYPE_ALLOCATED; } pConnection->pFormat = pFormat; pConnection->pBuffer = pBuffer; pConnection->u32MaxFrameCount = u32MaxFrameCount; pConnection->u32Signature = APO_CONNECTION_DESCRIPTOR_SIGNATURE; return createFormatHr; } // Creates a WaveFormatEx format void FillFormat ( WORD FormatType, DWORD dwSamplesPerFrame, DWORD /* dwBytesPerSampleContainer */, DWORD dwValidBitsPerSample, FLOAT32 fFramesPerSecond, WAVEFORMATEX* pWfx ) { if (pWfx == nullptr) { LOG_ERROR(L"WaveformatEx is null"); } if (dwSamplesPerFrame >= 0xffff) { LOG_ERROR(L"SamplesPerFrame too great"); } if (dwValidBitsPerSample >= 0xffff) { LOG_ERROR(L"ValidBitsPerSample too great"); } pWfx->wFormatTag = FormatType; pWfx->nChannels = (WORD)(dwSamplesPerFrame & 0xffff); pWfx->wBitsPerSample = (WORD)dwValidBitsPerSample; pWfx->nBlockAlign = pWfx->nChannels * (pWfx->wBitsPerSample / 8); pWfx->nSamplesPerSec = (DWORD)fFramesPerSecond; pWfx->nAvgBytesPerSec = pWfx->nSamplesPerSec * pWfx->nBlockAlign; pWfx->cbSize = 0; } // Creates an UncompressedAudioFormat void FillFormat ( GUID FormatType, DWORD dwSamplesPerFrame, DWORD dwBytesPerSampleContainer, DWORD dwValidBitsPerSample, FLOAT32 fFramesPerSecond, DWORD dwChannelMask, UNCOMPRESSEDAUDIOFORMAT* pFormat ) { if (pFormat == nullptr) { LOG_ERROR(L"WaveformatEx is null"); } if (dwSamplesPerFrame >= 0xffff) { LOG_ERROR(L"SamplesPerFrame too great"); } if (dwValidBitsPerSample >= 0xffff) { LOG_ERROR(L"ValidBitsPerSample too great"); } pFormat->guidFormatType = FormatType; pFormat->dwSamplesPerFrame = dwSamplesPerFrame; pFormat->dwBytesPerSampleContainer = dwBytesPerSampleContainer; pFormat->dwValidBitsPerSample = dwValidBitsPerSample; pFormat->fFramesPerSecond = fFramesPerSecond; pFormat->dwChannelMask = dwChannelMask; } HRESULT SetupConnection ( APO_CONNECTION_DESCRIPTOR* pInputConnDesc, APO_CONNECTION_DESCRIPTOR* pOutputConnDesc, APO_CONNECTION_PROPERTY* pInputConnProp, APO_CONNECTION_PROPERTY* pOutputConnProp, UNCOMPRESSEDAUDIOFORMAT* pDefaultFormat ) { if (pInputConnDesc == nullptr) { LOG_ERROR(L"SetupConnection recieved null APO connection descriptor for input"); return E_INVALIDARG; } if (pOutputConnDesc == nullptr) { LOG_ERROR(L"SetupConnection recieved null APO connection descriptor for output"); return E_INVALIDARG; } if (pInputConnProp == nullptr) { LOG_ERROR(L"SetupConnection recieved null APO connection property for input"); return E_INVALIDARG; } if (pOutputConnProp == nullptr) { LOG_ERROR(L"SetupConnection recieved null APO connection property for output"); return E_INVALIDARG; } if (pDefaultFormat == nullptr) { LOG_ERROR(L"SetupConnection received null format"); return E_INVALIDARG; } LOG_RETURN_IF_FAILED(FillConnection(pDefaultFormat, NULL, 0, cMaxFrameCount, pInputConnDesc), L"\tFillConnection for input descriptor failed"); LOG_RETURN_IF_FAILED(CreateConnection(pInputConnDesc, pInputConnProp), L"\tCreateConnection for input descriptor failed"); pInputConnProp->u32ValidFrameCount = cFrameCountToProcess; pInputConnProp->u32BufferFlags = BUFFER_VALID; LOG_RETURN_IF_FAILED(FillConnection(pDefaultFormat, NULL, 0, cMaxFrameCount, pOutputConnDesc), L"\tFillConnection for output descriptor failed"); LOG_RETURN_IF_FAILED(CreateConnection(pOutputConnDesc, pOutputConnProp), L"\tCreateConnection for output descriptor failed"); return S_OK; }