status_t AudioALSACaptureDataProviderEchoRefExt::close()
{
    ALOGD("%s()", __FUNCTION__);
    ASSERT(mClientLock.tryLock() != 0); // lock by base class detach

    mEnable = false;
    AudioAutoTimeoutLock _l(mEnableLock);
    ClosePCMDump();

    pcm_stop(mPcm);
    pcm_close(mPcm);
    mPcm = NULL;

    AudioALSASampleRateController *pAudioALSASampleRateController = AudioALSASampleRateController::getInstance();
    pAudioALSASampleRateController->resetScenarioStatus(PLAYBACK_SCENARIO_ECHO_REF_EXT);

    return NO_ERROR;
}
status_t AudioALSAFMController::setFmEnable(const bool enable, const audio_devices_t output_device)
{
    // Lock to Protect HW Registers & AudioMode
    // TODO(Harvey): get stream manager lock here?

    AudioAutoTimeoutLock _l(mLock);

    ALOGD("+%s(), mFmEnable = %d => enable = %d", __FUNCTION__, mFmEnable, enable);

    // Check Current Status
    if (enable == mFmEnable)
    {
        ALOGW("-%s(), enable == mFmEnable, return.", __FUNCTION__);
        return INVALID_OPERATION;
    }

    // Update Enable Status
    mFmEnable = enable;

    // get current device
    ALOGD("%s(), output_device = 0x%x", __FUNCTION__, output_device);

    AudioALSASampleRateController *pAudioALSASampleRateController = AudioALSASampleRateController::getInstance();

    if (mFmEnable == true) // Open
    {
#if 0 // local print only
        ALOGD("IsFMMergeInterfaceSupported = %d", WCNChipController::GetInstance()->IsFMMergeInterfaceSupported());
        ALOGD("IsFmChipPadSelConnSys = %d", WCNChipController::GetInstance()->IsFmChipPadSelConnSys());
        ALOGD("IsFmChipUseSlaveMode = %d", WCNChipController::GetInstance()->IsFmChipUseSlaveMode());
        ALOGD("GetFmChipSamplingRate = %d", WCNChipController::GetInstance()->GetFmChipSamplingRate());
    
        ALOGD("IsBTMergeInterfaceSupported = %d", WCNChipController::GetInstance()->IsBTMergeInterfaceSupported());
        ALOGD("BTChipHWInterface = %d", WCNChipController::GetInstance()->BTChipHWInterface());   
        ALOGD("BTUseCVSDRemoval = %d", WCNChipController::GetInstance()->BTUseCVSDRemoval());
        ALOGD("BTChipSamplingRate = %d", WCNChipController::GetInstance()->BTChipSamplingRate());
        ALOGD("BTChipSamplingRateNumber = %d", WCNChipController::GetInstance()->BTChipSamplingRateNumber());
        ALOGD("BTChipSyncFormat = %d", WCNChipController::GetInstance()->BTChipSyncFormat());
        ALOGD("BTChipSyncLength = %d", WCNChipController::GetInstance()->BTChipSyncLength());
        ALOGD("BTChipSecurityHiLo = %d", WCNChipController::GetInstance()->BTChipSecurityHiLo());

        ALOGD("GetBTCurrentSamplingRateNumber = %d", WCNChipController::GetInstance()->GetBTCurrentSamplingRateNumber());
#endif


        // set default 44100 Hz
        pAudioALSASampleRateController->setPrimaryStreamOutSampleRate(44100);
        pAudioALSASampleRateController->setScenarioStatus(PLAYBACK_SCENARIO_FM);

        WCNChipController::GetInstance()->SetFmChipSampleRate(getFmDownlinkSamplingRate());


        // Set Audio Digital/Analog HW Register
        if (checkFmNeedUseDirectConnectionMode(output_device) == true)
        {
            setFmDirectConnection(true, true);
            mHardwareResourceManager->startOutputDevice(output_device, getFmDownlinkSamplingRate());
        }
        else
        {
            mIsFmDirectConnectionMode = false;
        }

        // Set Direct/Indirect Mode to FMAudioPlayer
        doDeviceChangeCallback();
    }
    else // Close
    {
        // Disable Audio Digital/Analog HW Register
        if (mIsFmDirectConnectionMode == true)
        {
            mHardwareResourceManager->stopOutputDevice();
        }
        setFmDirectConnection(false, true);

        // reset FM playback status
        pAudioALSASampleRateController->resetScenarioStatus(PLAYBACK_SCENARIO_FM);
    }

    ALOGD("-%s()", __FUNCTION__);
    return NO_ERROR;
}