audio/sysvad/APO/SwapAPO/swapapomfx.cpp
HRESULT CSwapAPOMFX::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(APOInitSystemEffects3))
    {
        APOInitSystemEffects3* papoSysFxInit3 = (APOInitSystemEffects3*)pbyData;

        // Try to get the logging service, but ignore errors as failure to do logging it is not fatal.
        hr = papoSysFxInit3->pServiceProvider->QueryService(SID_AudioProcessingObjectLoggingService, IID_PPV_ARGS(&m_apoLoggingService));
        IF_FAILED_JUMP(hr, Exit);

        wil::com_ptr_nothrow<IAudioProcessingObjectRTQueueService> apoRtQueueService;
        hr = papoSysFxInit3->pServiceProvider->QueryService(SID_AudioProcessingObjectRTQueue, IID_PPV_ARGS(&apoRtQueueService));
        IF_FAILED_JUMP(hr, Exit);

        // Call the GetRealTimeWorkQueue to get the ID of a work queue that can be used for scheduling tasks
        // that need to run at a real-time priority. The work queue ID is used with the Rtwq APIs.
        hr = apoRtQueueService->GetRealTimeWorkQueue(&m_queueId);
        IF_FAILED_JUMP(hr, Exit);
       
        // Windows should pass a valid collection.
        ATLASSERT(papoSysFxInit3->pDeviceCollection != nullptr);
        IF_TRUE_ACTION_JUMP(papoSysFxInit3->pDeviceCollection == nullptr, hr = E_INVALIDARG, Exit);

        // Save the processing mode being initialized.
        processingMode = papoSysFxInit3->AudioProcessingMode;

        ProprietaryCommunicationWithDriver(papoSysFxInit3->pDeviceCollection, papoSysFxInit3->nSoftwareIoDeviceInCollection, papoSysFxInit3->nSoftwareIoConnectorIndex);
    }
    else 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->pDeviceCollection, papoSysFxInit2->nSoftwareIoDeviceInCollection, papoSysFxInit2->nSoftwareIoConnectorIndex);
    }
    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            &&
                         processingMode != AUDIO_SIGNALPROCESSINGMODE_COMMUNICATIONS &&
                         processingMode != AUDIO_SIGNALPROCESSINGMODE_SPEECH         &&
                         processingMode != AUDIO_SIGNALPROCESSINGMODE_MEDIA          &&
                         processingMode != AUDIO_SIGNALPROCESSINGMODE_MOVIE), 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_userStore != nullptr)
    {
        m_fEnableSwapMFX = GetCurrentEffectsSetting(m_userStore.get(), PKEY_Endpoint_Enable_Channel_Swap_MFX, m_AudioProcessingMode);
    }

    if (m_spAPOSystemEffectsProperties != NULL)
    {
        m_fEnableSwapMFX = GetCurrentEffectsSetting(m_spAPOSystemEffectsProperties, PKEY_Endpoint_Enable_Channel_Swap_MFX, m_AudioProcessingMode);
    }

    RtlZeroMemory(m_effectInfos, sizeof(m_effectInfos));
    m_effectInfos[0] = { SwapEffectId, FALSE, m_fEnableSwapMFX ? AUDIO_SYSTEMEFFECT_STATE_ON : AUDIO_SYSTEMEFFECT_STATE_OFF };

    if (cbDataSize != sizeof(APOInitSystemEffects3))
    {
        //
        //  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_bRegisteredEndpointNotificationCallback = TRUE;
    }

    m_bIsInitialized = true;
Exit:
    return hr;
}
// The method that this long comment refers to is "Initialize()"
//-------------------------------------------------------------------------
// Description:
//
//  Generic initialization routine for APOs.
//
// Parameters:
//
//     cbDataSize - [in] the size in bytes of the initialization data.
//     pbyData - [in] initialization data specific to this APO
//
// Return values:
//
//     S_OK                         Successful completion.
//     E_POINTER                    Invalid pointer passed to this function.
//     E_INVALIDARG                 Invalid argument
//     AEERR_ALREADY_INITIALIZED    APO is already initialized
//
// Remarks:
//
//  This method initializes the APO.  The data is variable length and
//  should have the form of:
//
//    struct MyAPOInitializationData
//    {
//        APOInitBaseStruct APOInit;
//        ... // add additional fields here
//    };
//
//  If the APO needs no initialization or needs no data to initialize
//  itself, it is valid to pass NULL as the pbyData parameter and 0 as
//  the cbDataSize parameter.
//
//  As part of designing an APO, decide which parameters should be
//  immutable (set once during initialization) and which mutable (changeable
//  during the lifetime of the APO instance).  Immutable parameters must
//  only be specifiable in the Initialize call; mutable parameters must be
//  settable via methods on whichever parameter control interface(s) your
//  APO provides. Mutable values should either be set in the initialize
//  method (if they are required for proper operation of the APO prior to
//  LockForProcess) or default to reasonable values upon initialize and not
//  be required to be set before LockForProcess.
//
//  Within the mutable parameters, you must also decide which can be changed
//  while the APO is locked for processing and which cannot.
//
//  All parameters should be considered immutable as a first choice, unless
//  there is a specific scenario which requires them to be mutable; similarly,
//  no mutable parameters should be changeable while the APO is locked, unless
//  a specific scenario requires them to be.  Following this guideline will
//  simplify the APO's state diagram and implementation and prevent certain
//  types of bug.
//
//  If a parameter changes the APOs latency or MaxXXXFrames values, it must be
//  immutable.
//
//  The default version of this function uses no initialization data, but does verify
//  the passed parameters and set the m_bIsInitialized member to true.
//
//  Note: This method may not be called from a real-time processing thread.
//

The method that this long comment refers to is "Initialize()"
Description.

Generic initialization routine for APOs.



[in] the size in bytes of the initialization data.
pbyData - [in] initialization data specific to this APO

Return values.







struct MyAPOInitializationData
{
APOInitBaseStruct APOInit;
add additional fields here
}.

If the APO needs no initialization or needs no data to initialize
itself, it is valid to pass NULL as the pbyData parameter and 0 as
the cbDataSize parameter.

As part of designing an APO, decide which parameters should be
immutable (set once during initialization) and which mutable (changeable
during the lifetime of the APO instance).  Immutable parameters must
only be specifiable in the Initialize call; mutable parameters must be
settable via methods on whichever parameter control interface(s) your
APO provides. Mutable values should either be set in the initialize
method (if they are required for proper operation of the APO prior to
LockForProcess) or default to reasonable values upon initialize and not
be required to be set before LockForProcess.

Within the mutable parameters, you must also decide which can be changed
while the APO is locked for processing and which cannot.

All parameters should be considered immutable as a first choice, unless
there is a specific scenario which requires them to be mutable; similarly,
no mutable parameters should be changeable while the APO is locked, unless
a specific scenario requires them to be.  Following this guideline will
simplify the APO's state diagram and implementation and prevent certain
types of bug.

If a parameter changes the APOs latency or MaxXXXFrames values, it must be
immutable.

The default version of this function uses no initialization data, but does verify
the passed parameters and set the m_bIsInitialized member to true.

This method may not be called from a real-time processing thread.
The method that this long comment refers to is " Initialize () " Description . Generic initialization routine for APOs . [ in ] the size in bytes of the initialization data . pbyData - [ in ] initialization data specific to this APO Return values . struct MyAPOInitializationData { APOInitBaseStruct APOInit ; add additional fields here } . If the APO needs no initialization or needs no data to initialize itself it is valid to pass NULL as the pbyData parameter and 0 as the cbDataSize parameter . As part of designing an APO decide which parameters should be immutable ( set once during initialization ) and which mutable ( changeable during the lifetime of the APO instance ) . Immutable parameters must only be specifiable in the Initialize call ; mutable parameters must be settable via methods on whichever parameter control interface ( s ) your APO provides . Mutable values should either be set in the initialize method ( if they are required for proper operation of the APO prior to LockForProcess ) or default to reasonable values upon initialize and not be required to be set before LockForProcess . Within the mutable parameters you must also decide which can be changed while the APO is locked for processing and which cannot . All parameters should be considered immutable as a first choice unless there is a specific scenario which requires them to be mutable ; similarly no mutable parameters should be changeable while the APO is locked unless a specific scenario requires them to be . Following this guideline will simplify the APO ' s state diagram and implementation and prevent certain types of bug . If a parameter changes the APOs latency or MaxXXXFrames values it must be immutable . The default version of this function uses no initialization data but does verify the passed parameters and set the m_bIsInitialized member to true . This method may not be called from a real - time processing thread .
HRESULT CSwapAPOMFX::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(APOInitSystemEffects3))
    {
        APOInitSystemEffects3* papoSysFxInit3 = (APOInitSystemEffects3*)pbyData;
        hr = papoSysFxInit3->pServiceProvider->QueryService(SID_AudioProcessingObjectLoggingService, IID_PPV_ARGS(&m_apoLoggingService));
        IF_FAILED_JUMP(hr, Exit);
        wil::com_ptr_nothrow<IAudioProcessingObjectRTQueueService> apoRtQueueService;
        hr = papoSysFxInit3->pServiceProvider->QueryService(SID_AudioProcessingObjectRTQueue, IID_PPV_ARGS(&apoRtQueueService));
        IF_FAILED_JUMP(hr, Exit);
        hr = apoRtQueueService->GetRealTimeWorkQueue(&m_queueId);
        IF_FAILED_JUMP(hr, Exit);
        ATLASSERT(papoSysFxInit3->pDeviceCollection != nullptr);
        IF_TRUE_ACTION_JUMP(papoSysFxInit3->pDeviceCollection == nullptr, hr = E_INVALIDARG, Exit);
        processingMode = papoSysFxInit3->AudioProcessingMode;
        ProprietaryCommunicationWithDriver(papoSysFxInit3->pDeviceCollection, papoSysFxInit3->nSoftwareIoDeviceInCollection, papoSysFxInit3->nSoftwareIoConnectorIndex);
    }
    else if (cbDataSize == sizeof(APOInitSystemEffects2))
    {
        APOInitSystemEffects2* papoSysFxInit2 = (APOInitSystemEffects2*)pbyData;
        m_spAPOSystemEffectsProperties = papoSysFxInit2->pAPOSystemEffectsProperties;
        ATLASSERT(papoSysFxInit2->pDeviceCollection != nullptr);
        IF_TRUE_ACTION_JUMP(papoSysFxInit2->pDeviceCollection == nullptr, hr = E_INVALIDARG, Exit);
        processingMode = papoSysFxInit2->AudioProcessingMode;
        ProprietaryCommunicationWithDriver(papoSysFxInit2->pDeviceCollection, papoSysFxInit2->nSoftwareIoDeviceInCollection, papoSysFxInit2->nSoftwareIoConnectorIndex);
    }
    else if (cbDataSize == sizeof(APOInitSystemEffects))
    {
        APOInitSystemEffects* papoSysFxInit = (APOInitSystemEffects*)pbyData;
        m_spAPOSystemEffectsProperties = papoSysFxInit->pAPOSystemEffectsProperties;
        processingMode = AUDIO_SIGNALPROCESSINGMODE_DEFAULT;
    }
    else
    {
        hr = E_INVALIDARG;
        goto Exit;
    }
    IF_TRUE_ACTION_JUMP((processingMode != AUDIO_SIGNALPROCESSINGMODE_DEFAULT        &&
                         processingMode != AUDIO_SIGNALPROCESSINGMODE_RAW            &&
                         processingMode != AUDIO_SIGNALPROCESSINGMODE_COMMUNICATIONS &&
                         processingMode != AUDIO_SIGNALPROCESSINGMODE_SPEECH         &&
                         processingMode != AUDIO_SIGNALPROCESSINGMODE_MEDIA          &&
                         processingMode != AUDIO_SIGNALPROCESSINGMODE_MOVIE), hr = E_INVALIDARG, Exit);
    m_AudioProcessingMode = processingMode;
    if (m_userStore != nullptr)
    {
        m_fEnableSwapMFX = GetCurrentEffectsSetting(m_userStore.get(), PKEY_Endpoint_Enable_Channel_Swap_MFX, m_AudioProcessingMode);
    }
    if (m_spAPOSystemEffectsProperties != NULL)
    {
        m_fEnableSwapMFX = GetCurrentEffectsSetting(m_spAPOSystemEffectsProperties, PKEY_Endpoint_Enable_Channel_Swap_MFX, m_AudioProcessingMode);
    }
    RtlZeroMemory(m_effectInfos, sizeof(m_effectInfos));
    m_effectInfos[0] = { SwapEffectId, FALSE, m_fEnableSwapMFX ? AUDIO_SYSTEMEFFECT_STATE_ON : AUDIO_SYSTEMEFFECT_STATE_OFF };
    if (cbDataSize != sizeof(APOInitSystemEffects3))
    {
        hr = m_spEnumerator.CoCreateInstance(__uuidof(MMDeviceEnumerator));
        IF_FAILED_JUMP(hr, Exit);
        hr = m_spEnumerator->RegisterEndpointNotificationCallback(this);
        IF_FAILED_JUMP(hr, Exit);
        m_bRegisteredEndpointNotificationCallback = TRUE;
    }
    m_bIsInitialized = true;
Exit:
    return hr;
}
HRESULT CSwapAPOMFX :: 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 ( APOInitSystemEffects3 ) ) { APOInitSystemEffects3 * papoSysFxInit3 = ( APOInitSystemEffects3 * ) pbyData ; hr = papoSysFxInit3 -> pServiceProvider -> QueryService ( SID_AudioProcessingObjectLoggingService , IID_PPV_ARGS ( & m_apoLoggingService ) ) ; IF_FAILED_JUMP ( hr , Exit ) ; wil :: com_ptr_nothrow < IAudioProcessingObjectRTQueueService > apoRtQueueService ; hr = papoSysFxInit3 -> pServiceProvider -> QueryService ( SID_AudioProcessingObjectRTQueue , IID_PPV_ARGS ( & apoRtQueueService ) ) ; IF_FAILED_JUMP ( hr , Exit ) ; hr = apoRtQueueService -> GetRealTimeWorkQueue ( & m_queueId ) ; IF_FAILED_JUMP ( hr , Exit ) ; ATLASSERT ( papoSysFxInit3 -> pDeviceCollection != nullptr ) ; IF_TRUE_ACTION_JUMP ( papoSysFxInit3 -> pDeviceCollection == nullptr , hr = E_INVALIDARG , Exit ) ; processingMode = papoSysFxInit3 -> AudioProcessingMode ; ProprietaryCommunicationWithDriver ( papoSysFxInit3 -> pDeviceCollection , papoSysFxInit3 -> nSoftwareIoDeviceInCollection , papoSysFxInit3 -> nSoftwareIoConnectorIndex ) ; } else if ( cbDataSize == sizeof ( APOInitSystemEffects2 ) ) { APOInitSystemEffects2 * papoSysFxInit2 = ( APOInitSystemEffects2 * ) pbyData ; m_spAPOSystemEffectsProperties = papoSysFxInit2 -> pAPOSystemEffectsProperties ; ATLASSERT ( papoSysFxInit2 -> pDeviceCollection != nullptr ) ; IF_TRUE_ACTION_JUMP ( papoSysFxInit2 -> pDeviceCollection == nullptr , hr = E_INVALIDARG , Exit ) ; processingMode = papoSysFxInit2 -> AudioProcessingMode ; ProprietaryCommunicationWithDriver ( papoSysFxInit2 -> pDeviceCollection , papoSysFxInit2 -> nSoftwareIoDeviceInCollection , papoSysFxInit2 -> nSoftwareIoConnectorIndex ) ; } else if ( cbDataSize == sizeof ( APOInitSystemEffects ) ) { APOInitSystemEffects * papoSysFxInit = ( APOInitSystemEffects * ) pbyData ; m_spAPOSystemEffectsProperties = papoSysFxInit -> pAPOSystemEffectsProperties ; processingMode = AUDIO_SIGNALPROCESSINGMODE_DEFAULT ; } else { hr = E_INVALIDARG ; goto Exit ; } IF_TRUE_ACTION_JUMP ( ( processingMode != AUDIO_SIGNALPROCESSINGMODE_DEFAULT && processingMode != AUDIO_SIGNALPROCESSINGMODE_RAW && processingMode != AUDIO_SIGNALPROCESSINGMODE_COMMUNICATIONS && processingMode != AUDIO_SIGNALPROCESSINGMODE_SPEECH && processingMode != AUDIO_SIGNALPROCESSINGMODE_MEDIA && processingMode != AUDIO_SIGNALPROCESSINGMODE_MOVIE ) , hr = E_INVALIDARG , Exit ) ; m_AudioProcessingMode = processingMode ; if ( m_userStore != nullptr ) { m_fEnableSwapMFX = GetCurrentEffectsSetting ( m_userStore . get ( ) , PKEY_Endpoint_Enable_Channel_Swap_MFX , m_AudioProcessingMode ) ; } if ( m_spAPOSystemEffectsProperties != NULL ) { m_fEnableSwapMFX = GetCurrentEffectsSetting ( m_spAPOSystemEffectsProperties , PKEY_Endpoint_Enable_Channel_Swap_MFX , m_AudioProcessingMode ) ; } RtlZeroMemory ( m_effectInfos , sizeof ( m_effectInfos ) ) ; m_effectInfos [ 0 ] = { SwapEffectId , FALSE , m_fEnableSwapMFX ? AUDIO_SYSTEMEFFECT_STATE_ON : AUDIO_SYSTEMEFFECT_STATE_OFF } ; if ( cbDataSize != sizeof ( APOInitSystemEffects3 ) ) { hr = m_spEnumerator . CoCreateInstance ( __uuidof ( MMDeviceEnumerator ) ) ; IF_FAILED_JUMP ( hr , Exit ) ; hr = m_spEnumerator -> RegisterEndpointNotificationCallback ( this ) ; IF_FAILED_JUMP ( hr , Exit ) ; m_bRegisteredEndpointNotificationCallback = TRUE ; } m_bIsInitialized = true ; Exit : return hr ; }
The method that this long comment refers to is "Initialize()"
Description:
The method that this long comment refers to is " Initialize () " Description :
// Try to get the logging service, but ignore errors as failure to do logging it is not fatal.
 // Call the GetRealTimeWorkQueue to get the ID of a work queue that can be used for scheduling tasks
 // that need to run at a real-time priority. The work queue ID is used with the Rtwq APIs.
 // Windows should pass a valid collection.
 // Save the processing mode being initialized.
 //
 // Initialize for mode-specific signal processing
 //
 // Save reference to the effects property store. This saves effects settings
 // and is the communication medium between this APO and any associated UI.
 // Windows should pass a valid collection.
 // Save the processing mode being initialized.
 // 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.
 //
 // Initialize for default signal processing
 //
 // Save reference to the effects property store. This saves effects settings
 // and is the communication medium between this APO and any associated UI.
 // Assume default processing mode
 // Invalid initialization size
 // 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.
 //
 // 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
 //
 //
 //  Register for notification of registry updates
 //
