/*----------------------------------------------------------------------------- IMiniportAudioEngineNode::GetSupportedDeviceFormats Decscription: GetSupportedDeviceFormats get the complete format list supported by the hw Audio Engine Parameters: _In_ _ulNodeId: node id for the target audio engine node _Out_ pFormat: a buffer pointer for receiving the supported device formats _In_ ulBufferSize: a pointer to a ULONG variable that has the size of the buffer pointed by pFormat Return Value: Appropriate NTSTATUS code Called at PASSIVE_LEVEL Remarks -------------------------------------------------------------------------------------------------------------------------*/ STDMETHODIMP_(NTSTATUS) CMiniportWaveRT::GetSupportedDeviceFormats(_In_ ULONG _ulNodeId, _Out_ KSMULTIPLE_ITEM* _pFormat, _In_ ULONG _ulBufferSize) { PKSDATAFORMAT_WAVEFORMATEXTENSIBLE pDeviceFormats; ULONG cDeviceFormats; NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST; PAGED_CODE (); ASSERT(_pFormat); DPF_ENTER(("[CMiniportWaveRT::GetSupportedDeviceFormats]")); IF_TRUE_ACTION_JUMP(_ulNodeId != KSNODE_WAVE_AUDIO_ENGINE, ntStatus = STATUS_INVALID_DEVICE_REQUEST, Exit); cDeviceFormats = GetAudioEngineSupportedDeviceFormats(&pDeviceFormats); KSMULTIPLE_ITEM *pKsMulti = static_cast<KSMULTIPLE_ITEM*>(_pFormat); pKsMulti->Size = sizeof(KSMULTIPLE_ITEM) + sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE) * cDeviceFormats; pKsMulti->Count = cDeviceFormats; IF_TRUE_ACTION_JUMP(_ulBufferSize < pKsMulti->Size, ntStatus = STATUS_BUFFER_TOO_SMALL, Exit); RtlCopyMemory((PVOID)(pKsMulti + 1), pDeviceFormats, sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE) * cDeviceFormats); ntStatus = STATUS_SUCCESS; Exit: return ntStatus; }
// ---------------------------------------------------------------------- // Function: // CPartsList::GetPart // // Description: // Returns the nIndex-th item in the list of IParts // // Parameters: // nIndex - [in] index of the part to access // uMsg - [out] the part at the specified index // // Return: // S_OK if successful // // ---------------------------------------------------------------------- _Use_decl_annotations_ STDMETHODIMP CPartsList::GetPart ( UINT nIndex, IPart** ppPart ) { HRESULT hr; IPart* pIPart = NULL; // Protect m_lstParts access m_CritSection.Enter(); IF_TRUE_ACTION_JUMP((ppPart == NULL), hr = E_POINTER, Exit); *ppPart = NULL; IF_TRUE_ACTION_JUMP((nIndex >= m_lstParts.GetCount()), hr = E_INVALIDARG, Exit); IF_TRUE_ACTION_JUMP((!m_lstParts.GetAt(nIndex, &pIPart)), hr = E_NOTFOUND, Exit); // Take care of AddRef and ensure correct interface in one shot hr = pIPart->QueryInterface(__uuidof(IPart), reinterpret_cast<void**>(ppPart)); IF_FAILED_JUMP(hr, Exit); Exit: m_CritSection.Leave(); return hr; }
//------------------------------------------------------------------------- // Description: // // Implementation of IAudioSystemEffectsCustomFormats::GetFormatRepresentation // // Parameters: // // nFormat - [in] which format is being requested // ppwstrFormatRep - [in] address of a variable that will receive a ptr // to a new string description of the requested format // // Return values: // // S_OK Success // E_INVALIDARG nFormat is out of range // E_POINTER Null pointer passed // // Remarks: // STDMETHODIMP CSwapAPOGFX::GetFormatRepresentation ( UINT nFormat, _Outptr_ LPWSTR* ppwstrFormatRep ) { HRESULT hr; size_t cbRep; LPWSTR pwstrLocal; IF_TRUE_ACTION_JUMP((nFormat >= _cCustomFormats), hr = E_INVALIDARG, Exit); IF_TRUE_ACTION_JUMP((ppwstrFormatRep == NULL), hr = E_POINTER, Exit); cbRep = (wcslen(_rgCustomFormats[nFormat].pwszRep) + 1) * sizeof(WCHAR); pwstrLocal = (LPWSTR)CoTaskMemAlloc(cbRep); IF_TRUE_ACTION_JUMP((pwstrLocal == NULL), hr = E_OUTOFMEMORY, Exit); hr = StringCbCopyW(pwstrLocal, cbRep, _rgCustomFormats[nFormat].pwszRep); if (FAILED(hr)) { CoTaskMemFree(pwstrLocal); } else { *ppwstrFormatRep = pwstrLocal; } Exit: return hr; }
HRESULT CSwapAPOLFX::Initialize(UINT32 cbDataSize, BYTE* pbyData) { HRESULT hr = S_OK; PROPVARIANT var; IF_TRUE_ACTION_JUMP( ((NULL == pbyData) && (0 != cbDataSize)), hr = E_INVALIDARG, Exit); IF_TRUE_ACTION_JUMP( ((NULL != pbyData) && (0 == cbDataSize)), hr = E_POINTER, Exit); IF_TRUE_ACTION_JUMP( (cbDataSize != sizeof(APOInitSystemEffects) ), hr = E_INVALIDARG, Exit); APOInitSystemEffects* papoSysFxInit = (APOInitSystemEffects*)pbyData; // // Store locally for later reference // m_spAPOSystemEffectsProperties = papoSysFxInit->pAPOSystemEffectsProperties; // // Get the current value // PropVariantInit(&var); if (m_spAPOSystemEffectsProperties != NULL) { // Get the state of whether channel swap LFX is enabled or not hr = m_spAPOSystemEffectsProperties->GetValue(PKEY_Endpoint_Enable_Channel_Swap_LFX, &var); if (SUCCEEDED(hr) && (var.vt == VT_UI4)) { if (var.ulVal == 0L) { m_fEnableSwapLFX = FALSE; } else { m_fEnableSwapLFX = TRUE; } } else { PropVariantClear(&var); } } // // Register for notification of registry updates // hr = m_spEnumerator.CoCreateInstance(__uuidof(MMDeviceEnumerator)); IF_FAILED_JUMP(hr, Exit); hr = m_spEnumerator->RegisterEndpointNotificationCallback(this); IF_FAILED_JUMP(hr, Exit); m_bIsInitialized = true; Exit: return hr; }
/*----------------------------------------------------------------------------- IMiniportAudioEngineNode::GetDeviceAttributeSteppings Decscription: When handling volume, mute, and meter related KS properties, Portcls calls this method, inside its property handlers, to know the property stepping information for the corresponding KS property. Parameters: _In_ _ulNodeId: node id for the target audio engine node _In_ _targetType: the query target (volume. mute, or peak meter) _Out_ _pKsPropMembHead: a pointer to a PKSPROPERTY_STEPPING_LONG variable for receiving returned channel count information _In_ ulBufferSize: a pointer to a ULONG variable that has the size of the buffer pointed by _pKsPropMembHead Return Value: Appropriate NTSTATUS code Called at PASSIVE_LEVEL Remarks -------------------------------------------------------------------------------------------------------------------------*/ NTSTATUS CMiniportWaveRT::GetDeviceAttributeSteppings(_In_ ULONG _ulNodeId, _In_ eChannelTargetType _targetType, _Out_ PKSPROPERTY_STEPPING_LONG _pKsPropMembHead, _In_ UINT32 _ui32DataSize) { NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST; PAGED_CODE (); DPF_ENTER(("[CMiniportWaveRT::GetDeviceAttributeSteppings]")); IF_TRUE_ACTION_JUMP(_ulNodeId != KSNODE_WAVE_AUDIO_ENGINE, ntStatus = STATUS_INVALID_DEVICE_REQUEST, Exit); switch (_targetType) { case eVolumeAttribute: ntStatus = GetVolumeSteppings(_pKsPropMembHead, _ui32DataSize);; break; case eMuteAttribute: ntStatus = GetMuteSteppings(_pKsPropMembHead, _ui32DataSize);; break; case ePeakMeterAttribute: ntStatus = GetPeakMeterSteppings(_pKsPropMembHead, _ui32DataSize);; break; default: ntStatus = STATUS_INVALID_DEVICE_REQUEST; break; } Exit: return ntStatus; }
// ---------------------------------------------------------------------------- // Function: // CSwapPropPage::SetSwapGFXState // // Description: // Enable or disable channel swap GFX // // Return values: // S_OK if successful // ---------------------------------------------------------------------------- HRESULT CSwapPropPage::SetSwapGFXState() { HRESULT hr = S_OK; PROPVARIANT var; IF_TRUE_ACTION_JUMP((m_pAudioFXExtParams == NULL), hr = E_POINTER, Exit); PropVariantInit(&var); if (m_pAudioFXExtParams->pFxProperties != NULL) { var.vt = VT_UI4; if (m_fEnableSwapGFX) { var.ulVal = 1L; } else { var.ulVal = 0L; } // Enable or disable channel swap GFX hr = m_pAudioFXExtParams->pFxProperties->SetValue(PKEY_Endpoint_Enable_Channel_Swap_GFX, var); } Exit: return(hr); }
NTSTATUS CMiniportWaveRT::GetDeviceChannelCount ( _In_ ULONG _ulNodeId, _In_ eChannelTargetType _targetType, _Out_ UINT32 *_pulChannelCount ) { NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST; PAGED_CODE (); ASSERT(_pulChannelCount); DPF_ENTER(("[CMiniportWaveRT::GetChannelCount]")); IF_TRUE_ACTION_JUMP(_ulNodeId != KSNODE_WAVE_AUDIO_ENGINE, ntStatus = STATUS_INVALID_DEVICE_REQUEST, Exit); switch (_targetType) { case eVolumeAttribute: ntStatus = GetVolumeChannelCount(_pulChannelCount); break; case eMuteAttribute: ntStatus = GetMuteChannelCount(_pulChannelCount); break; case ePeakMeterAttribute: ntStatus = GetPeakMeterChannelCount(_pulChannelCount); break; default: ntStatus = STATUS_INVALID_DEVICE_REQUEST; break; } Exit: return ntStatus; }
/*----------------------------------------------------------------------------- IMiniportAudioEngineNode::SetDeviceFormat Decscription: GetDeviceFormat set the current device format to be used by the HW Audio Engine Parameters: _In_ _ulNodeId: node id for the target audio engine node _Out_ pFormat: a buffer pointer with the device format to be set to the hw Audio Engine _In_ ulBufferSize: a pointer to a ULONG variable that has the size of the buffer pointed by pFormat Return Value: Appropriate NTSTATUS code Called at PASSIVE_LEVEL Remarks Setting the device format of a HW Audio Engine could potential impact the mix format inside the HD Audio Engine. The driver might need to add appropriate src/format converter according or change mix format. -------------------------------------------------------------------------------------------------------------------------*/ STDMETHODIMP_(NTSTATUS) CMiniportWaveRT::SetDeviceFormat(_In_ ULONG _ulNodeId, _In_ KSDATAFORMAT_WAVEFORMATEX *_pFormat, _In_ ULONG _ulBufferSize) { NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST; PAGED_CODE (); ASSERT (_pFormat); DPF_ENTER(("[CMiniportWaveRT::SetDeviceFormat]")); IF_TRUE_ACTION_JUMP(_ulNodeId != KSNODE_WAVE_AUDIO_ENGINE, ntStatus = STATUS_INVALID_DEVICE_REQUEST, Exit); IF_TRUE_ACTION_JUMP(_ulBufferSize < sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE), ntStatus = STATUS_BUFFER_TOO_SMALL, Exit); RtlCopyMemory((PVOID)m_pDeviceFormat, (PVOID)_pFormat, sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE)); ntStatus = STATUS_SUCCESS; Exit: return ntStatus; }
//------------------------------------------------------------------------- // Description: // // Implementation of IAudioSystemEffectsCustomFormats::GetFormat // // Parameters: // // nFormat - [in] which format is being requested // IAudioMediaType - [in] address of a variable that will receive a ptr // to a new IAudioMediaType object // // Return values: // // S_OK Success // E_INVALIDARG nFormat is out of range // E_POINTER Null pointer passed // // Remarks: // STDMETHODIMP CSwapAPOGFX::GetFormat ( UINT nFormat, IAudioMediaType** ppFormat ) { HRESULT hr; IF_TRUE_ACTION_JUMP((nFormat >= _cCustomFormats), hr = E_INVALIDARG, Exit); IF_TRUE_ACTION_JUMP((ppFormat == NULL), hr = E_POINTER, Exit); *ppFormat = NULL; hr = CreateAudioMediaType( (const WAVEFORMATEX*)&_rgCustomFormats[nFormat].wfxFmt, sizeof(_rgCustomFormats[nFormat].wfxFmt), ppFormat); Exit: return hr; }
/*----------------------------------------------------------------------------- IMiniportAudioEngineNode::GetDeviceChannelPeakMeter Decscription: When handling GET peak meter KS property for the device, Portcls calls this method, inside its property handlers, to get the current setting on the specific channel. Parameters: _In_ _ulNodeId: node id for the target audio engine node _In_ _uiChannel: the target channel for this GET volume operation _Out_ _pPeakMeterValue: a pointer to a LONG variable for receiving returned information Return Value: Appropriate NTSTATUS code Called at PASSIVE_LEVEL Remarks -------------------------------------------------------------------------------------------------------------------------*/ STDMETHODIMP_(NTSTATUS) CMiniportWaveRT::GetDeviceChannelPeakMeter(_In_ ULONG _ulNodeId, _In_ UINT32 _uiChannel, _Out_ LONG *_pPeakMeterValue) { NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST; PAGED_CODE (); DPF_ENTER(("[CMiniportWaveRT::GetDeviceChannelPeakMeter]")); IF_TRUE_ACTION_JUMP(_ulNodeId != KSNODE_WAVE_AUDIO_ENGINE, ntStatus = STATUS_INVALID_DEVICE_REQUEST, Exit); ntStatus = GetChannelPeakMeter(_uiChannel, _pPeakMeterValue); Exit: return ntStatus; }
STDMETHODIMP_(NTSTATUS) CMiniportWaveRT::GetDeviceFormat(_In_ ULONG _ulNodeId, _Out_ KSDATAFORMAT_WAVEFORMATEX *_pFormat, _In_ ULONG _ulBufferSize) { NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST; PAGED_CODE (); ASSERT (_pFormat); DPF_ENTER(("[CMiniportWaveRT::GetDeviceFormat]")); IF_TRUE_ACTION_JUMP(_ulNodeId != KSNODE_WAVE_AUDIO_ENGINE, ntStatus = STATUS_INVALID_DEVICE_REQUEST, Exit); IF_TRUE_ACTION_JUMP(_ulBufferSize < sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE), ntStatus = STATUS_BUFFER_TOO_SMALL, Exit); #pragma warning(push) // IMiniportAudioEngineNode::GetDeviceFormat's annotation on _pFormat requires it to be KSDATAFORMAT_WAVEFORMATEX. However, // this implementation here will always be called by our own code with _pFormat to be KSDATAFORMAT_WAVEFORMATEXTENSIBLE, // so there should be no buffer overrun; also the IF_TRUE_ACTION_JUMP above also help to avoid buffer overrun. #pragma warning(disable:6386) RtlCopyMemory((PVOID)_pFormat, (PVOID)m_pDeviceFormat, sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE)); #pragma warning (pop) ntStatus = STATUS_SUCCESS; Exit: return ntStatus; }
/*----------------------------------------------------------------------------- IMiniportAudioEngineNode::SetDeviceChannelMute Decscription: When handling SET mute KS property for the device, Portcls calls this method, inside its property handlers, to set the current setting on the specific channel. Parameters: _In_ _ulNodeId: node id for the target audio engine node _In_ _uiChannel: the target channel for this GET volume operation _In_ _bMute: volume value to set Return Value: Appropriate NTSTATUS code Called at PASSIVE_LEVEL Remarks -------------------------------------------------------------------------------------------------------------------------*/ NTSTATUS CMiniportWaveRT::SetDeviceChannelMute(_In_ ULONG _ulNodeId, _In_ UINT32 _uiChannel, _In_ BOOL _bMute) { NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST; PAGED_CODE (); DPF_ENTER(("[CMiniportWaveRT::SetEndpointChannelMute]")); IF_TRUE_ACTION_JUMP(_ulNodeId != KSNODE_WAVE_AUDIO_ENGINE, ntStatus = STATUS_INVALID_DEVICE_REQUEST, Exit); ntStatus = SetChannelMute(_uiChannel, _bMute); Exit: return ntStatus; }
/*----------------------------------------------------------------------------- IMiniportAudioEngineNode::SetDeviceChannelVolume Decscription: When handling SET volume KS property for the device, Portcls calls this method, inside its property handlers, to set the current setting on the specific channel. Parameters: _In_ _ulNodeId: node id for the target audio engine node _In_ _uiChannel: the target channel for this GET volume operation _In_ _Volume: volume value to set Return Value: Appropriate NTSTATUS code Called at PASSIVE_LEVEL Remarks -------------------------------------------------------------------------------------------------------------------------*/ STDMETHODIMP_(NTSTATUS) CMiniportWaveRT::SetDeviceChannelVolume(_In_ ULONG _ulNodeId, _In_ UINT32 _uiChannel, _In_ LONG _Volume) { NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST; PAGED_CODE (); DPF_ENTER(("[CMiniportWaveRT::SetEndpointChannelVolume]")); IF_TRUE_ACTION_JUMP(_ulNodeId != KSNODE_WAVE_AUDIO_ENGINE, ntStatus = STATUS_INVALID_DEVICE_REQUEST, Exit); // Snap the volume level to our range of steppings. LONG lVolume = VOLUME_NORMALIZE_IN_RANGE(_Volume); ntStatus = SetChannelVolume(_uiChannel, lVolume); Exit: return ntStatus; }
//------------------------------------------------------------------------- // Description: // // Report delay added by the APO between samples given on input // and samples given on output. // // Parameters: // // pTime - [out] hundreds-of-nanoseconds of delay added // // Return values: // // S_OK on success, a failure code on failure STDMETHODIMP CSwapAPOMFX::GetLatency(HNSTIME* pTime) { ASSERT_NONREALTIME(); HRESULT hr = S_OK; IF_TRUE_ACTION_JUMP(NULL == pTime, hr = E_POINTER, Exit); if (IsEqualGUID(m_AudioProcessingMode, AUDIO_SIGNALPROCESSINGMODE_RAW)) { *pTime = 0; } else { *pTime = (m_fEnableDelayMFX ? HNS_DELAY : 0); } Exit: return hr; }
// ---------------------------------------------------------------------------- // Function: // CSwapPropPage::GetDeviceFriendlyName // // Description: // Retrieves the endpoint's friendly name // // Parameters: // ppNameOut - [out] The friendly name of the endpoint // // Return values: // S_OK if successful // ---------------------------------------------------------------------------- HRESULT CSwapPropPage::GetDeviceFriendlyName ( _Outptr_result_maybenull_ LPWSTR* ppNameOut ) { CComPtr<IMMDeviceEnumerator> spEnumerator; CComPtr<IPropertyStore> spProperties; CComPtr<IMMDevice> spMMDevice; HRESULT hr = S_OK; PROPVARIANT var; IF_TRUE_ACTION_JUMP((ppNameOut == NULL), hr = E_POINTER, Exit); *ppNameOut = NULL; // Create device enumerator and get IMMDevice from the device ID hr = spEnumerator.CoCreateInstance(__uuidof(MMDeviceEnumerator)); IF_FAILED_JUMP(hr, Exit); hr = spEnumerator->GetDevice(m_pAudioFXExtParams->pwstrEndpointID, &spMMDevice); IF_FAILED_JUMP(hr, Exit); // Open the PropertyStore for read access hr = spMMDevice->OpenPropertyStore(STGM_READ, &spProperties); IF_FAILED_JUMP(hr, Exit); PropVariantInit(&var); // Retrieve the friendly name of the endpoint hr = spProperties->GetValue(PKEY_Device_FriendlyName, &var); if (SUCCEEDED(hr) && (var.vt == VT_LPWSTR)) { *ppNameOut = var.pwszVal; } else { PropVariantClear(&var); } Exit: return(hr); }
/*----------------------------------------------------------------------------- IMiniportAudioEngineNode::GetEngineFormatSize Decscription: When handling GetMixFormat, DeviceFormat, or SupportDeviceFormatsList, Portcls calls this method to know the correct data size to allocate for the receiving the corresponding format information. Parameters: _In_ _ulNodeId: node id for the target audio engine node _In_ eEngineFormatType: format target to indicate which format size is being asked _Out_ pulFormatSize: a pointer to a ULONG variable for receiving returned szize information Return Value: Appropriate NTSTATUS code Called at PASSIVE_LEVEL Remarks -------------------------------------------------------------------------------------------------------------------------*/ NTSTATUS CMiniportWaveRT::GetEngineFormatSize ( _In_ ULONG _ulNodeId, _In_ eEngineFormatType _formatType, _Out_ ULONG *_pulFormatSize ) { PAGED_CODE (); NTSTATUS ntStatus = STATUS_SUCCESS; DPF_ENTER(("[CMiniportWaveRT::GetEngineFormatSize]")); ASSERT (_pulFormatSize); IF_TRUE_ACTION_JUMP(_ulNodeId != KSNODE_WAVE_AUDIO_ENGINE, ntStatus = STATUS_INVALID_DEVICE_REQUEST, Exit); switch (_formatType) { case eMixFormat: DPF_ENTER(("[eMixFormat]")); *_pulFormatSize = sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE); break; case eDeviceFormat: DPF_ENTER(("[eDeviceFormat]")); *_pulFormatSize = sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE); break; case eSupportedDeviceFormats: DPF_ENTER(("[eSupportedDeviceFormats]")); *_pulFormatSize = sizeof(KSMULTIPLE_ITEM) + sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE) * GetAudioEngineSupportedDeviceFormats(NULL); break; default: ntStatus = STATUS_INVALID_PARAMETER; break; } Exit: return ntStatus; }
HRESULT CSwapAPOGFX::Initialize(UINT32 cbDataSize, BYTE* pbyData) { HRESULT hr = S_OK; GUID processingMode; IF_TRUE_ACTION_JUMP( ((NULL == pbyData) && (0 != cbDataSize)), hr = E_INVALIDARG, Exit); IF_TRUE_ACTION_JUMP( ((NULL != pbyData) && (0 == cbDataSize)), hr = E_INVALIDARG, Exit); if (cbDataSize == sizeof(APOInitSystemEffects2)) { // // Initialize for mode-specific signal processing // APOInitSystemEffects2* papoSysFxInit2 = (APOInitSystemEffects2*)pbyData; // Save reference to the effects property store. This saves effects settings // and is the communication medium between this APO and any associated UI. m_spAPOSystemEffectsProperties = papoSysFxInit2->pAPOSystemEffectsProperties; // Windows should pass a valid collection. ATLASSERT(papoSysFxInit2->pDeviceCollection != nullptr); IF_TRUE_ACTION_JUMP(papoSysFxInit2->pDeviceCollection == nullptr, hr = E_INVALIDARG, Exit); // Save the processing mode being initialized. processingMode = papoSysFxInit2->AudioProcessingMode; // There is information in the APOInitSystemEffects2 structure that could help facilitate // proprietary communication between an APO instance and the KS pin that the APO is initialized on // Eg, in the case that an APO is implemented as an effect proxy for the effect processing hosted inside // an driver (either host CPU based or offload DSP based), the example below uses a combination of // IDeviceTopology, IConnector, and IKsControl interfaces to communicate with the underlying audio driver. // the following following routine demonstrates how to implement how to communicate to an audio driver from a APO. ProprietaryCommunicationWithDriver(papoSysFxInit2); } else if (cbDataSize == sizeof(APOInitSystemEffects)) { // // Initialize for default signal processing // APOInitSystemEffects* papoSysFxInit = (APOInitSystemEffects*)pbyData; // Save reference to the effects property store. This saves effects settings // and is the communication medium between this APO and any associated UI. m_spAPOSystemEffectsProperties = papoSysFxInit->pAPOSystemEffectsProperties; // Assume default processing mode processingMode = AUDIO_SIGNALPROCESSINGMODE_DEFAULT; } else { // Invalid initialization size hr = E_INVALIDARG; goto Exit; } // Validate then save the processing mode. Note an endpoint effects APO // does not depend on the mode. Windows sets the APOInitSystemEffects2 // AudioProcessingMode member to GUID_NULL for an endpoint effects APO. IF_TRUE_ACTION_JUMP( (processingMode != AUDIO_SIGNALPROCESSINGMODE_DEFAULT && processingMode != AUDIO_SIGNALPROCESSINGMODE_RAW), hr = E_INVALIDARG, Exit); m_AudioProcessingMode = processingMode; // // An APO that implements signal processing more complex than this sample // would configure its processing for the processingMode determined above. // If necessary, the APO would also use the IDeviceTopology and IConnector // interfaces retrieved above to communicate with its counterpart audio // driver to configure any additional signal processing in the driver and // associated hardware. // // // Get current effects settings // if (m_spAPOSystemEffectsProperties != NULL) { m_fEnableSwapGFX = GetCurrentEffectsSetting(m_spAPOSystemEffectsProperties, PKEY_Endpoint_Enable_Channel_Swap_GFX, m_AudioProcessingMode); } // // Register for notification of registry updates // hr = m_spEnumerator.CoCreateInstance(__uuidof(MMDeviceEnumerator)); IF_FAILED_JUMP(hr, Exit); hr = m_spEnumerator->RegisterEndpointNotificationCallback(this); IF_FAILED_JUMP(hr, Exit); m_bIsInitialized = true; Exit: return hr; }