status_t AudioPolicyManagerALSA::setDeviceConnectionState(AudioSystem::audio_devices device,
                                                  AudioSystem::device_connection_state state,
                                                  const char *device_address)
{

    LOGV("setDeviceConnectionState() device: %x, state %d, address %s", device, state, device_address);

    // connect/disconnect only 1 device at a time
    if (AudioSystem::popCount(device) != 1) return BAD_VALUE;

    if (strlen(device_address) >= MAX_DEVICE_ADDRESS_LEN) {
        LOGE("setDeviceConnectionState() invalid address: %s", device_address);
        return BAD_VALUE;
    }

    // handle output devices
    if (AudioSystem::isOutputDevice(device)) {

#ifndef WITH_A2DP
        if (AudioSystem::isA2dpDevice(device)) {
            LOGE("setDeviceConnectionState() invalid device: %x", device);
            return BAD_VALUE;
        }
#endif

        switch (state)
        {
        // handle output device connection
        case AudioSystem::DEVICE_STATE_AVAILABLE:
            if (mAvailableOutputDevices & device) {
                LOGW("setDeviceConnectionState() device already connected: %x", device);
                return INVALID_OPERATION;
            }
            LOGV("setDeviceConnectionState() connecting device %x", device);

            // register new device as available
            mAvailableOutputDevices |= device;

#ifdef WITH_A2DP
            // handle A2DP device connection
            if (AudioSystem::isA2dpDevice(device)) {
                status_t status = handleA2dpConnection(device, device_address);
                if (status != NO_ERROR) {
                    mAvailableOutputDevices &= ~device;
                    return status;
                }
            } else
#endif
            {
                if (AudioSystem::isBluetoothScoDevice(device)) {
                    LOGV("setDeviceConnectionState() BT SCO  device, address %s", device_address);
                    // keep track of SCO device address
                    mScoDeviceAddress = String8(device_address, MAX_DEVICE_ADDRESS_LEN);
#ifdef WITH_A2DP
                    if (mA2dpOutput != 0 &&
                        mPhoneState != AudioSystem::MODE_NORMAL) {
                        mpClientInterface->suspendOutput(mA2dpOutput);
                    }
#endif
                }
            }
            break;
        // handle output device disconnection
        case AudioSystem::DEVICE_STATE_UNAVAILABLE: {
            if (!(mAvailableOutputDevices & device)) {
                LOGW("setDeviceConnectionState() device not connected: %x", device);
                return INVALID_OPERATION;
            }


            LOGV("setDeviceConnectionState() disconnecting device %x", device);
            // remove device from available output devices
            mAvailableOutputDevices &= ~device;

#ifdef WITH_A2DP
            // handle A2DP device disconnection
            if (AudioSystem::isA2dpDevice(device)) {
                status_t status = handleA2dpDisconnection(device, device_address);
                if (status != NO_ERROR) {
                    mAvailableOutputDevices |= device;
                    return status;
                }
            } else
#endif
            {
                if (AudioSystem::isBluetoothScoDevice(device)) {
                    mScoDeviceAddress = "";
#ifdef WITH_A2DP
                    if (mA2dpOutput != 0 &&
                        mPhoneState != AudioSystem::MODE_NORMAL) {
                        mpClientInterface->restoreOutput(mA2dpOutput);
                    }
#endif
                }
            }
            } break;

        default:
            LOGE("setDeviceConnectionState() invalid state: %x", state);
            return BAD_VALUE;
        }

        // request routing change if necessary
        uint32_t newDevice = getNewDevice(mHardwareOutput, false);

        // force routing if device disconnection occurs when stream is stopped
        if ((newDevice == 0) && (state == AudioSystem::DEVICE_STATE_UNAVAILABLE))
            newDevice = getDeviceForStrategy(STRATEGY_MEDIA, false);

#ifdef WITH_A2DP
		//+++ KBNAM_PORTING
		/* org
        checkOutputForAllStrategies(newDevice);
		*/
        checkOutputForAllStrategies();
		//---

        // A2DP outputs must be closed after checkOutputForAllStrategies() is executed
        if (state == AudioSystem::DEVICE_STATE_UNAVAILABLE && AudioSystem::isA2dpDevice(device)) {
            closeA2dpOutputs();
        }
#endif
        updateDeviceForStrategy();
        setOutputDevice(mHardwareOutput, newDevice);

        if (device == AudioSystem::DEVICE_OUT_WIRED_HEADSET) {
            device = AudioSystem::DEVICE_IN_WIRED_HEADSET;
        } else if (device == AudioSystem::DEVICE_OUT_BLUETOOTH_SCO ||
                   device == AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET ||
                   device == AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT) {
            device = AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET;
        } else {
            return NO_ERROR;
        }
    }
    // handle input devices
    if (AudioSystem::isInputDevice(device)) {

        switch (state)
        {
        // handle input device connection
        case AudioSystem::DEVICE_STATE_AVAILABLE: {
            if (mAvailableInputDevices & device) {
                LOGW("setDeviceConnectionState() device already connected: %d", device);
                return INVALID_OPERATION;
            }
            mAvailableInputDevices |= device;
            }
            break;

        // handle input device disconnection
        case AudioSystem::DEVICE_STATE_UNAVAILABLE: {
            if (!(mAvailableInputDevices & device)) {
                LOGW("setDeviceConnectionState() device not connected: %d", device);
                return INVALID_OPERATION;
            }
            mAvailableInputDevices &= ~device;
            } break;

        default:
            LOGE("setDeviceConnectionState() invalid state: %x", state);
            return BAD_VALUE;
        }

        audio_io_handle_t activeInput = getActiveInput();
        if (activeInput != 0) {
            AudioInputDescriptor *inputDesc = mInputs.valueFor(activeInput);
            uint32_t newDevice = getDeviceForInputSource(inputDesc->mInputSource);
            if (newDevice != inputDesc->mDevice) {
                LOGV("setDeviceConnectionState() changing device from %x to %x for input %d",
                        inputDesc->mDevice, newDevice, activeInput);
                inputDesc->mDevice = newDevice;
                AudioParameter param = AudioParameter();
                param.addInt(String8(AudioParameter::keyRouting), (int)newDevice);
                mpClientInterface->setParameters(activeInput, param.toString());
            }
        }
        else {
/* LGE_CHANGE_S [email protected] 2010.01.27 */        	
#ifdef SUPPORT_FM_ANALOG
           if (device == AudioSystem::DEVICE_IN_FM_ANALOG) {
               routing_strategy strategy = getStrategy((AudioSystem::stream_type)3);
               uint32_t curOutdevice = getDeviceForStrategy(strategy);
               /* If A2DP headset is connected then route FM to Headset */
               if (curOutdevice == AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP ||
                     curOutdevice == AudioSystem::DEVICE_OUT_BLUETOOTH_SCO) {
                  curOutdevice = AudioSystem::DEVICE_OUT_WIRED_HEADSET;
               }

               if (state) {
                   // routing_strategy strategy = getStrategy((AudioSystem::stream_type)3);
                   // uint32_t curOutdevice = getDeviceForStrategy(strategy);

                   /* Get the new input descriptor for FM Rx In */
                    mfmInput = getFMInput(AUDIO_SOURCE_FM_ANALOG,8000,1,
                           AudioSystem::CHANNEL_IN_MONO,(AudioSystem::audio_in_acoustics)7);

                   /* Forcely open the current output device again for
                    * FM Rx playback path to open
                    */
                    LOGV("curOutdevice = %x",curOutdevice);
                    setOutputDevice(mHardwareOutput, curOutdevice, true);

                   /* Tell the audio flinger playback thread that
                    * FM Rx is active
                    */
                    mpClientInterface->setFMRxActive(true);
               } else {
                    int newDevice=0;
                    AudioParameter param = AudioParameter();
                    param.addInt(String8(AudioParameter::keyRouting), (int)newDevice);

                   /* Change the input device from FM to default before releasing Input */
                    mpClientInterface->setParameters(mfmInput, param.toString());
                    param.addInt(String8("fm_off"), (int)newDevice);

                   /* Close the capture handle */
                    mpClientInterface->setParameters(mfmInput, param.toString());

                   /* Release the input descriptor for FM Rx In */
                    releaseInput(mfmInput);

                   /* Close the playback handle */
                    mpClientInterface->setParameters(mHardwareOutput, param.toString());

                   /* Tell the audio flinger playback thread that
                    * FM Rx is not active now.
                    */
                    mpClientInterface->setFMRxActive(false);
                }
             }
#endif // SUPPORT_FM_ANALOG
/* LGE_CHANGE_E [email protected] 2010.01.27 */   
      }
        return NO_ERROR;
    }

    LOGW("setDeviceConnectionState() invalid device: %x", device);
    return BAD_VALUE;
}
status_t AudioPolicyManager::setDeviceConnectionState(AudioSystem::audio_devices device,
                                                  AudioSystem::device_connection_state state,
                                                  const char *device_address)
{

    LOGV("setDeviceConnectionState() device: %x, state %d, address %s", device, state, device_address);

    // connect/disconnect only 1 device at a time
    if (AudioSystem::popCount(device) != 1) return BAD_VALUE;

    if (strlen(device_address) >= MAX_DEVICE_ADDRESS_LEN) {
        LOGE("setDeviceConnectionState() invalid address: %s", device_address);
        return BAD_VALUE;
    }

    // handle output devices
    if (AudioSystem::isOutputDevice(device)) {

#ifndef WITH_A2DP
        if (AudioSystem::isA2dpDevice(device)) {
            LOGE("setDeviceConnectionState() invalid device: %x", device);
            return BAD_VALUE;
        }
#endif

        switch (state)
        {
        // handle output device connection
        case AudioSystem::DEVICE_STATE_AVAILABLE:
            if (mAvailableOutputDevices & device) {
                LOGW("setDeviceConnectionState() device already connected: %x", device);
                return INVALID_OPERATION;
            }
            LOGV("setDeviceConnectionState() connecting device %x", device);

            // register new device as available
            mAvailableOutputDevices |= device;

#ifdef WITH_A2DP
            // handle A2DP device connection
            if (AudioSystem::isA2dpDevice(device)) {
                status_t status = handleA2dpConnection(device, device_address);
                if (status != NO_ERROR) {
                    mAvailableOutputDevices &= ~device;
                    return status;
                }
            } else
#endif
            {
                if (AudioSystem::isBluetoothScoDevice(device)) {
                    LOGV("setDeviceConnectionState() BT SCO  device, address %s", device_address);
                    // keep track of SCO device address
                    mScoDeviceAddress = String8(device_address, MAX_DEVICE_ADDRESS_LEN);
                }
            }
            break;
        // handle output device disconnection
        case AudioSystem::DEVICE_STATE_UNAVAILABLE: {
            if (!(mAvailableOutputDevices & device)) {
                LOGW("setDeviceConnectionState() device not connected: %x", device);
                return INVALID_OPERATION;
            }


            LOGV("setDeviceConnectionState() disconnecting device %x", device);
            // remove device from available output devices
            mAvailableOutputDevices &= ~device;

#ifdef WITH_A2DP
            // handle A2DP device disconnection
            if (AudioSystem::isA2dpDevice(device)) {
                status_t status = handleA2dpDisconnection(device, device_address);
                if (status != NO_ERROR) {
                    mAvailableOutputDevices |= device;
                    return status;
                }
            } else
#endif
            {
                if (AudioSystem::isBluetoothScoDevice(device)) {
                    mScoDeviceAddress = "";
                }
            }
            } break;

        default:
            LOGE("setDeviceConnectionState() invalid state: %x", state);
            return BAD_VALUE;
        }

#ifdef HAVE_FM_RADIO
        if (device == AudioSystem::DEVICE_OUT_FM) {
            AudioOutputDescriptor *out = mOutputs.valueFor(mHardwareOutput);
            if (state == AudioSystem::DEVICE_STATE_AVAILABLE) {
                out->changeRefCount(AudioSystem::FM, 1);
                if (out->mRefCount[AudioSystem::FM] > 0)
                    mpClientInterface->setParameters(0, String8("fm_on=1"));
            }
            else {
                out->changeRefCount(AudioSystem::FM, -1);
                if (out->mRefCount[AudioSystem::FM] <= 0)
                    mpClientInterface->setParameters(0, String8("fm_off=1"));
            }
        }
#endif

        // request routing change if necessary
        uint32_t newDevice = getNewDevice(mHardwareOutput, false);
#ifdef WITH_A2DP
        checkA2dpSuspend();
        checkOutputForAllStrategies();
        // A2DP outputs must be closed after checkOutputForAllStrategies() is executed
        if (state == AudioSystem::DEVICE_STATE_UNAVAILABLE && AudioSystem::isA2dpDevice(device)) {
            closeA2dpOutputs();
        }
#endif
        updateDeviceForStrategy();
        setOutputDevice(mHardwareOutput, newDevice);

        if (device == AudioSystem::DEVICE_OUT_WIRED_HEADSET) {
            device = AudioSystem::DEVICE_IN_WIRED_HEADSET;
        } else if (device == AudioSystem::DEVICE_OUT_BLUETOOTH_SCO ||
                   device == AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET ||
                   device == AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT) {
            device = AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET;
        } else {
            return NO_ERROR;
        }
    }
    // handle input devices
    if (AudioSystem::isInputDevice(device)) {

        switch (state)
        {
        // handle input device connection
        case AudioSystem::DEVICE_STATE_AVAILABLE: {
            if (mAvailableInputDevices & device) {
                LOGW("setDeviceConnectionState() device already connected: %d", device);
                return INVALID_OPERATION;
            }
            mAvailableInputDevices |= device;
            }
            break;

        // handle input device disconnection
        case AudioSystem::DEVICE_STATE_UNAVAILABLE: {
            if (!(mAvailableInputDevices & device)) {
                LOGW("setDeviceConnectionState() device not connected: %d", device);
                return INVALID_OPERATION;
            }
            mAvailableInputDevices &= ~device;
            } break;

        default:
            LOGE("setDeviceConnectionState() invalid state: %x", state);
            return BAD_VALUE;
        }

        audio_io_handle_t activeInput = getActiveInput();
        if (activeInput != 0) {
            AudioInputDescriptor *inputDesc = mInputs.valueFor(activeInput);
            uint32_t newDevice = getDeviceForInputSource(inputDesc->mInputSource);
            if (newDevice != inputDesc->mDevice) {
                LOGV("setDeviceConnectionState() changing device from %x to %x for input %d",
                        inputDesc->mDevice, newDevice, activeInput);
                inputDesc->mDevice = newDevice;
                AudioParameter param = AudioParameter();
                param.addInt(String8(AudioParameter::keyRouting), (int)newDevice);
                mpClientInterface->setParameters(activeInput, param.toString());
            }
        }

        return NO_ERROR;
    }

    LOGW("setDeviceConnectionState() invalid device: %x", device);
    return BAD_VALUE;
}
Example #3
0
status_t AudioPolicyManager::checkAndSetVolume(int stream, int index, audio_io_handle_t output, uint32_t device, int delayMs, bool force)
{
#ifdef WITH_QCOM_LPA
    // do not change actual stream volume if the stream is muted
    if ((mOutputs.valueFor(output)->mMuteCount[stream] != 0 && output != mLPADecodeOutput) ||
        (output == mLPADecodeOutput && stream == mLPAStreamType && mLPAMuted == true)) {
#else
    if (mOutputs.valueFor(output)->mMuteCount[stream] != 0) {
#endif
        LOGV("checkAndSetVolume() stream %d muted count %d", stream, mOutputs.valueFor(output)->mMuteCount[stream]);
        return NO_ERROR;
    }

    // do not change in call volume if bluetooth is connected and vice versa
    if ((stream == AudioSystem::VOICE_CALL && mForceUse[AudioSystem::FOR_COMMUNICATION] == AudioSystem::FORCE_BT_SCO) ||
        (stream == AudioSystem::BLUETOOTH_SCO && mForceUse[AudioSystem::FOR_COMMUNICATION] != AudioSystem::FORCE_BT_SCO)) {
        LOGV("checkAndSetVolume() cannot set stream %d volume with force use = %d for comm",
             stream, mForceUse[AudioSystem::FOR_COMMUNICATION]);
        return INVALID_OPERATION;
    }

    float volume = computeVolume(stream, index, output, device);
    // do not set volume if the float value did not change
    if ((volume != mOutputs.valueFor(output)->mCurVolume[stream]) || (stream == AudioSystem::VOICE_CALL)
#ifdef FM_RADIO
        || (stream == AudioSystem::FM)
#endif
        || force) {
        mOutputs.valueFor(output)->mCurVolume[stream] = volume;
        LOGD("setStreamVolume() for output %d stream %d, volume %f, delay %d", output, stream, volume, delayMs);
        if (stream == AudioSystem::VOICE_CALL ||
            stream == AudioSystem::DTMF ||
            stream == AudioSystem::BLUETOOTH_SCO) {
            float voiceVolume = -1.0;
            // offset value to reflect actual hardware volume that never reaches 0
            // 1% corresponds roughly to first step in VOICE_CALL stream volume setting (see AudioService.java)
            volume = 0.01 + 0.99 * volume;
            if (stream == AudioSystem::VOICE_CALL) {
                voiceVolume = (float)index/(float)mStreams[stream].mIndexMax;
            } else if (stream == AudioSystem::BLUETOOTH_SCO) {
                voiceVolume = 1.0;
            }
            if (voiceVolume >= 0 && output == mHardwareOutput) {
                mpClientInterface->setVoiceVolume(voiceVolume, delayMs);
            }
#ifdef FM_RADIO
        } else if (stream == AudioSystem::FM) {
            float fmVolume = -1.0;
            fmVolume = computeVolume(stream, index, output, device);
            if (fmVolume >= 0) {
                if(output == mHardwareOutput)
                    mpClientInterface->setFmVolume(fmVolume, delayMs);
                else if(output == mA2dpOutput)
                    mpClientInterface->setStreamVolume((AudioSystem::stream_type)stream, volume, output, delayMs);
            }
            return NO_ERROR;
#endif
        }
        mpClientInterface->setStreamVolume((AudioSystem::stream_type)stream, volume, output, delayMs);
    }

    return NO_ERROR;
}

void AudioPolicyManager::setStreamMute(int stream, bool on, audio_io_handle_t output, int delayMs)
{
    StreamDescriptor &streamDesc = mStreams[stream];
    AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output);

    LOGV("setStreamMute() stream %d, mute %d, output %d, mMuteCount %d", stream, on, output, outputDesc->mMuteCount[stream]);

    if (on) {
#ifdef WITH_QCOM_LPA
        if ((outputDesc->mMuteCount[stream] == 0 && output != mLPADecodeOutput) ||
            (output == mLPADecodeOutput && stream == mLPAStreamType && false == mLPAMuted)) {
#else
       if (outputDesc->mMuteCount[stream] == 0) {
#endif
            if (streamDesc.mCanBeMuted) {
                checkAndSetVolume(stream, 0, output, outputDesc->device(), delayMs);
            }
        }
#ifdef WITH_QCOM_LPA
        // increment mMuteCount after calling checkAndSetVolume() so that volume change is not ignored
        if(output == mLPADecodeOutput) {
            if(stream == mLPAStreamType && false == mLPAMuted) {
                mLPAMuted = true;
            }
        } else {
#endif
            outputDesc->mMuteCount[stream]++;
#ifdef WITH_QCOM_LPA
        }
#endif
    } else {
#ifdef WITH_QCOM_LPA
        if ((outputDesc->mMuteCount[stream] == 0 && output != mLPADecodeOutput) ||
            (output == mLPADecodeOutput && stream == mLPAStreamType && false == mLPAMuted)) {
#else
        if (outputDesc->mMuteCount[stream] == 0) {
#endif
            LOGW("setStreamMute() unmuting non muted stream!");
            return;
        }
#ifdef WITH_QCOM_LPA
        if(output == mLPADecodeOutput) {
            if(stream == mLPAStreamType && true == mLPAMuted) {
                mLPAMuted = false;
                checkAndSetVolume(stream, streamDesc.mIndexCur, output, outputDesc->device(), delayMs);
            }
        } else {
            if(--outputDesc->mMuteCount[stream] == 0){
                checkAndSetVolume(stream, streamDesc.mIndexCur, output, outputDesc->device(), delayMs);
            }
        }
#else
        if(--outputDesc->mMuteCount[stream] == 0){
            checkAndSetVolume(stream, streamDesc.mIndexCur, output, outputDesc->device(), delayMs);
        }
#endif
    }
}

void AudioPolicyManager::setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config)
{
    LOGD("setForceUse() usage %d, config %d, mPhoneState %d", usage, config, mPhoneState);

    bool forceVolumeReeval = false;
    switch(usage) {
    case AudioSystem::FOR_COMMUNICATION:
        if (config != AudioSystem::FORCE_SPEAKER && config != AudioSystem::FORCE_BT_SCO &&
            config != AudioSystem::FORCE_NONE) {
            LOGW("setForceUse() invalid config %d for FOR_COMMUNICATION", config);
            return;
        }
        mForceUse[usage] = config;
        break;
    case AudioSystem::FOR_MEDIA:
        if (config != AudioSystem::FORCE_HEADPHONES && config != AudioSystem::FORCE_BT_A2DP &&
            config != AudioSystem::FORCE_WIRED_ACCESSORY && config != AudioSystem::FORCE_NONE &&
            config != AudioSystem::FORCE_SPEAKER) {
            LOGW("setForceUse() invalid config %d for FOR_MEDIA", config);
            return;
        }
        mForceUse[usage] = config;
        {
            uint32_t device = getDeviceForStrategy(STRATEGY_MEDIA);
            setOutputDevice(mHardwareOutput, device);
        }
        break;
    case AudioSystem::FOR_RECORD:
        if (config != AudioSystem::FORCE_BT_SCO && config != AudioSystem::FORCE_WIRED_ACCESSORY &&
            config != AudioSystem::FORCE_NONE) {
            LOGW("setForceUse() invalid config %d for FOR_RECORD", config);
            return;
        }
        mForceUse[usage] = config;
        break;
    case AudioSystem::FOR_DOCK:
        if (config != AudioSystem::FORCE_NONE && config != AudioSystem::FORCE_BT_CAR_DOCK &&
            config != AudioSystem::FORCE_BT_DESK_DOCK && config != AudioSystem::FORCE_WIRED_ACCESSORY) {
            LOGW("setForceUse() invalid config %d for FOR_DOCK", config);
        }
        forceVolumeReeval = true;
        mForceUse[usage] = config;
        break;
    default:
        LOGW("setForceUse() invalid usage %d", usage);
        break;
    }

    // check for device and output changes triggered by new phone state
    uint32_t newDevice = getNewDevice(mHardwareOutput, false);
#ifdef WITH_A2DP
    checkOutputForAllStrategies();
#endif
    updateDeviceForStrategy();
    setOutputDevice(mHardwareOutput, newDevice);
    if (forceVolumeReeval) {
        applyStreamVolumes(mHardwareOutput, newDevice);
    }
}

uint32_t AudioPolicyManager::getDeviceForInputSource(int inputSource)
{
    uint32_t device;

    switch(inputSource) {
    case AUDIO_SOURCE_DEFAULT:
    case AUDIO_SOURCE_MIC:
    case AUDIO_SOURCE_VOICE_RECOGNITION:
        if (mForceUse[AudioSystem::FOR_RECORD] == AudioSystem::FORCE_BT_SCO &&
            mAvailableInputDevices & AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
            device = AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET;
        } else if (mAvailableInputDevices & AudioSystem::DEVICE_IN_WIRED_HEADSET) {
            device = AudioSystem::DEVICE_IN_WIRED_HEADSET;
#ifdef QCOM_ANC
        } else if (mAvailableInputDevices & AudioSystem::DEVICE_IN_ANC_HEADSET) {
            device = AudioSystem::DEVICE_IN_ANC_HEADSET;
#endif
        } else {
            device = AudioSystem::DEVICE_IN_BUILTIN_MIC;
        }
        break;
    case AUDIO_SOURCE_VOICE_COMMUNICATION:
        device = AudioSystem::DEVICE_IN_COMMUNICATION;
        break;
    case AUDIO_SOURCE_CAMCORDER:
        if (hasBackMicrophone()) {
            device = AudioSystem::DEVICE_IN_BACK_MIC;
        } else {
            device = AudioSystem::DEVICE_IN_BUILTIN_MIC;
        }
        break;
    case AUDIO_SOURCE_VOICE_UPLINK:
    case AUDIO_SOURCE_VOICE_DOWNLINK:
    case AUDIO_SOURCE_VOICE_CALL:
        device = AudioSystem::DEVICE_IN_VOICE_CALL;
        break;
#ifdef FM_RADIO
   case AUDIO_SOURCE_FM_RX:
        device = AudioSystem::DEVICE_IN_FM_RX;
        break;
    case AUDIO_SOURCE_FM_RX_A2DP:
        device = AudioSystem::DEVICE_IN_FM_RX_A2DP;
        break;
#endif
    default:
        LOGW("getInput() invalid input source %d", inputSource);
        device = 0;
        break;
    }
    LOGV("getDeviceForInputSource()input source %d, device %08x", inputSource, device);
    return device;
}