status_t SpeechPhoneCallController::ChangeDeviceForModemSpeechControlFlow(const audio_mode_t audio_mode, const audio_devices_t new_device)
{
    Mutex::Autolock _l(mLock);

    ALOGD("+%s(), audio_mode = %d, new_device = 0x%x", __FUNCTION__, audio_mode, new_device);

    const modem_index_t modem_index = mSpeechDriverFactory->GetActiveModemIndex();
    ASSERT((modem_index == MODEM_1 && audio_mode == AUDIO_MODE_IN_CALL) ||
           (modem_index == MODEM_2 && audio_mode == AUDIO_MODE_IN_CALL_2));

    // Get current active speech driver
    SpeechDriverInterface *pSpeechDriver = mSpeechDriverFactory->GetSpeechDriver();


    // Mute during device change.
    pSpeechDriver->SetDownlinkMute(true);
    pSpeechDriver->SetUplinkMute(true);


    // Stop PMIC digital/analog part - downlink
    mAudioResourceManager->StopOutputDevice();

    // Stop Side Tone Filter
    mAudioDigitalInstance->EnableSideToneFilter(false);

    // Stop MODEM_PCM
    mAudioDigitalInstance->SetModemPcmEnable(modem_index, false);

    // Stop PMIC digital/analog part - uplink
    mAudioResourceManager->StopInputDevice();

    // Stop AP side digital part
    CloseModemSpeechDigitalPart(modem_index, (audio_devices_t)mAudioResourceManager->getDlOutputDevice());



    // Set new device
    if (CheckTtyNeedOn() == true)
    {
        SetTtyInOutDevice(GetRoutingForTty(), mTty_Ctm, audio_mode);
    }
    else
    {
        mAudioResourceManager->setDlOutputDevice(new_device);
    }

    // Get new device
    const audio_devices_t output_device = (audio_devices_t)mAudioResourceManager->getDlOutputDevice();
    const audio_devices_t input_device  = (audio_devices_t)mAudioResourceManager->getUlInputDevice();
    ALOGD("%s(), output_device = 0x%x, input_device = 0x%x", __FUNCTION__, output_device, input_device);



    // Check BT device
    const bool bt_device_on = android_audio_legacy::AudioSystem::isBluetoothScoDevice((android_audio_legacy::AudioSystem::audio_devices)output_device);
#if 1
    int sample_rate;
    if (bt_device_on == true)
    {
        if (mBTMode == 0) //NB BTSCO
        {
            sample_rate = 8000;
        }
        else
        {
            sample_rate = 16000;
        }
    }
    else
    {
        sample_rate = 16000;
    }
    ALOGD("+%s(), bt_device_on = %d, sample_rate = %d", __FUNCTION__, bt_device_on, sample_rate);
#else
    const int  sample_rate  = (bt_device_on == true) ? 8000 : 16000; // TODO: MT6628 BT only use NB
#endif

    // Set sampling rate
    mAudioAnalogInstance->SetFrequency(AudioAnalogType::DEVICE_OUT_DAC, sample_rate);
    mAudioAnalogInstance->SetFrequency(AudioAnalogType::DEVICE_IN_ADC,  sample_rate);

    // Open ADC/DAC I2S, or DAIBT
    OpenModemSpeechDigitalPart(modem_index, output_device);



    // Clean Side Tone Filter gain
    pSpeechDriver->SetSidetoneGain(0);

    // Set PMIC digital/analog part - uplink has pop, open first
    mAudioResourceManager->StartInputDevice();
    if (bt_device_on == false) { usleep(kDelayForUplinkPulseMs * 1000); } // PMIC HW pulse
    // Set PMIC digital/analog part - DL need trim code.
    mAudioResourceManager->StartOutputDevice(); // also set volume here

    // start Side Tone Filter
    if (CheckSideToneFilterNeedOn(output_device) == true)
    {
        mAudioDigitalInstance->EnableSideToneFilter(true);
    }



    // Set MODEM_PCM - open modem pcm here s.t. modem/DSP can learn the uplink background noise, but not zero
    SetModemPcmAttribute(modem_index, sample_rate);
    mAudioDigitalInstance->SetModemPcmEnable(modem_index, true);


    // Set MD side sampling rate
    pSpeechDriver->SetModemSideSamplingRate(sample_rate);

    // Set speech mode
    pSpeechDriver->SetSpeechMode(input_device, output_device);

    // Need recover mute state
    pSpeechDriver->SetUplinkMute(mMicMute);
    pSpeechDriver->SetDownlinkMute(false);

    ALOGD("-%s(), audio_mode = %d", __FUNCTION__, audio_mode);
    return NO_ERROR;
}
status_t SpeechPhoneCallController::OpenModemSpeechControlFlow(const audio_mode_t audio_mode)
{
    Mutex::Autolock _l(mLock);

    ALOGD("+%s(), audio_mode = %d", __FUNCTION__, audio_mode);

    if (IsModeIncall(audio_mode) == false)
    {
        ALOGE("-%s() new_mode(%d) != MODE_IN_CALL / MODE_IN_CALL_2", __FUNCTION__, audio_mode);
        return INVALID_OPERATION;
    }

    // get speech driver instance
    mSpeechDriverFactory->SetActiveModemIndexByAudioMode(audio_mode);
    const modem_index_t    modem_index   = mSpeechDriverFactory->GetActiveModemIndex();
    SpeechDriverInterface *pSpeechDriver = mSpeechDriverFactory->GetSpeechDriver();

    // check BT device
    const bool bt_device_on = android_audio_legacy::AudioSystem::isBluetoothScoDevice((android_audio_legacy::AudioSystem::audio_devices)mAudioResourceManager->getDlOutputDevice());

#if 1
    int sample_rate;
    if (bt_device_on == true)
    {
        if (mBTMode == 0) //NB BTSCO
        {
            sample_rate = 8000;
        }
        else
        {
            sample_rate = 16000;
        }
    }
    else
    {
        sample_rate = 16000;
    }
    ALOGD("+%s(), bt_device_on = %d, sample_rate = %d", __FUNCTION__, bt_device_on, sample_rate);
#else
    const int  sample_rate  = (bt_device_on == true) ? 8000 : 16000; // TODO: MT6628 BT only use NB
#endif

    // enable clock
    SetAfeAnalogClock(true);

    // set sampling rate
    mAudioAnalogInstance->SetFrequency(AudioAnalogType::DEVICE_OUT_DAC, sample_rate);
    mAudioAnalogInstance->SetFrequency(AudioAnalogType::DEVICE_IN_ADC,  sample_rate);

    // set device
    if (CheckTtyNeedOn() == true)
    {
        SetTtyInOutDevice(GetRoutingForTty(), mTty_Ctm, audio_mode);
    }
    else
    {
        // Note: set output device in phone call will also assign input device
        mAudioResourceManager->setDlOutputDevice(mAudioResourceManager->getDlOutputDevice());
    }

    // get device
    const audio_devices_t output_device = (audio_devices_t)mAudioResourceManager->getDlOutputDevice();
    const audio_devices_t input_device  = (audio_devices_t)mAudioResourceManager->getUlInputDevice();
    ALOGD("%s(), output_device = 0x%x, input_device = 0x%x", __FUNCTION__, output_device, input_device);

    // Open ADC/DAC I2S, or DAIBT
    OpenModemSpeechDigitalPart(modem_index, output_device);

    // AFE_ON
    mAudioDigitalInstance->SetAfeEnable(true);



    // Clean Side Tone Filter gain
    pSpeechDriver->SetSidetoneGain(0);

    // Set PMIC digital/analog part - uplink has pop, open first
    mAudioResourceManager->StartInputDevice();
    if (bt_device_on == false) { usleep(kDelayForUplinkPulseMs * 1000); } // PMIC HW pulse

    // set MODEM_PCM - open modem pcm here s.t. modem/DSP can learn the uplink background noise, but not zero
    SetModemPcmAttribute(modem_index, sample_rate);
    mAudioDigitalInstance->SetModemPcmEnable(modem_index, true);

    // Set MD side sampling rate
    pSpeechDriver->SetModemSideSamplingRate(sample_rate);

    // Set speech mode
    pSpeechDriver->SetSpeechMode(input_device, output_device);

    // Speech/VT on
    if (mVtNeedOn == true)
    {
        pSpeechDriver->VideoTelephonyOn();

        // trun on P2W for Video Telephony
        bool wideband_on = false; // VT default use Narrow Band (8k), modem side will SRC to 16K
        pSpeechDriver->PCM2WayOn(wideband_on);
    }
    else
    {
        pSpeechDriver->SpeechOn();

        // turn on TTY
        if (CheckTtyNeedOn() == true)
        {
            pSpeechDriver->TtyCtmOn(BAUDOT_MODE);
        }
    }

    // Set PMIC digital/analog part - DL need trim code.
    mAudioResourceManager->StartOutputDevice();

    // start Side Tone Filter
    if (CheckSideToneFilterNeedOn(output_device) == true)
    {
        mAudioDigitalInstance->EnableSideToneFilter(true);
    }

    // check VM need open
    SpeechVMRecorder *pSpeechVMRecorder = SpeechVMRecorder::GetInstance();
    if (pSpeechVMRecorder->GetVMRecordCapability() == true)
    {
        ALOGD("%s(), Open VM/EPL record", __FUNCTION__);
        pSpeechVMRecorder->Open();
    }

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