diff options
author | Eric Laurent <elaurent@google.com> | 2014-07-20 15:47:07 -0700 |
---|---|---|
committer | Eric Laurent <elaurent@google.com> | 2014-08-06 11:42:07 -0700 |
commit | c2730ba7c5e9559b7499ef5e0d7742deb18c5110 (patch) | |
tree | efa845ec9fd1cb5cc2a2cf20b62538b74668b173 /services | |
parent | 92ce4715315bddd158c7d4028556632f0547e3b9 (diff) | |
download | frameworks_av-c2730ba7c5e9559b7499ef5e0d7742deb18c5110.zip frameworks_av-c2730ba7c5e9559b7499ef5e0d7742deb18c5110.tar.gz frameworks_av-c2730ba7c5e9559b7499ef5e0d7742deb18c5110.tar.bz2 |
audio policy: add support for USB devices for voice call
Add possibility to use sink and source devices not on
the primary HW module for voice calls (e.g. USB headsets).
Bug: 15520724.
Change-Id: Ib27db4ba759b6d91ea1104dc2e35c87733517b30
Diffstat (limited to 'services')
-rw-r--r-- | services/audioflinger/Tracks.cpp | 4 | ||||
-rw-r--r-- | services/audiopolicy/AudioPolicyManager.cpp | 277 | ||||
-rw-r--r-- | services/audiopolicy/AudioPolicyManager.h | 8 |
3 files changed, 259 insertions, 30 deletions
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp index 48093da..c5ab832 100644 --- a/services/audioflinger/Tracks.cpp +++ b/services/audioflinger/Tracks.cpp @@ -1885,10 +1885,10 @@ status_t AudioFlinger::PlaybackThread::PatchTrack::getNextBuffer( buf.mFrameCount = buffer->frameCount; status_t status = mPeerProxy->obtainBuffer(&buf, &mPeerTimeout); ALOGV_IF(status != NO_ERROR, "PatchTrack() %p getNextBuffer status %d", this, status); + buffer->frameCount = buf.mFrameCount; if (buf.mFrameCount == 0) { return WOULD_BLOCK; } - buffer->frameCount = buf.mFrameCount; status = Track::getNextBuffer(buffer, pts); return status; } @@ -2166,10 +2166,10 @@ status_t AudioFlinger::RecordThread::PatchRecord::getNextBuffer( status_t status = mPeerProxy->obtainBuffer(&buf, &mPeerTimeout); ALOGV_IF(status != NO_ERROR, "PatchRecord() %p mPeerProxy->obtainBuffer status %d", this, status); + buffer->frameCount = buf.mFrameCount; if (buf.mFrameCount == 0) { return WOULD_BLOCK; } - buffer->frameCount = buf.mFrameCount; status = RecordTrack::getNextBuffer(buffer, pts); return status; } diff --git a/services/audiopolicy/AudioPolicyManager.cpp b/services/audiopolicy/AudioPolicyManager.cpp index c519593..5c87c5e 100644 --- a/services/audiopolicy/AudioPolicyManager.cpp +++ b/services/audiopolicy/AudioPolicyManager.cpp @@ -95,8 +95,8 @@ const StringToEnum sDeviceNameToEnumTable[] = { STRING_TO_ENUM(AUDIO_DEVICE_IN_WIRED_HEADSET), STRING_TO_ENUM(AUDIO_DEVICE_IN_AUX_DIGITAL), STRING_TO_ENUM(AUDIO_DEVICE_IN_HDMI), - STRING_TO_ENUM(AUDIO_DEVICE_IN_VOICE_CALL), STRING_TO_ENUM(AUDIO_DEVICE_IN_TELEPHONY_RX), + STRING_TO_ENUM(AUDIO_DEVICE_IN_VOICE_CALL), STRING_TO_ENUM(AUDIO_DEVICE_IN_BACK_MIC), STRING_TO_ENUM(AUDIO_DEVICE_IN_REMOTE_SUBMIX), STRING_TO_ENUM(AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET), @@ -303,17 +303,24 @@ status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device, } updateDevicesAndOutputs(); + if (mPhoneState == AUDIO_MODE_IN_CALL) { + audio_devices_t newDevice = getNewOutputDevice(mPrimaryOutput, false /*fromCache*/); + updateCallRouting(newDevice); + } for (size_t i = 0; i < mOutputs.size(); i++) { - // do not force device change on duplicated output because if device is 0, it will - // also force a device 0 for the two outputs it is duplicated to which may override - // a valid device selection on those outputs. - bool force = !mOutputs.valueAt(i)->isDuplicated() - && (!deviceDistinguishesOnAddress(device) - // always force when disconnecting (a non-duplicated device) - || (state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE)); - setOutputDevice(mOutputs.keyAt(i), - getNewOutputDevice(mOutputs.keyAt(i), true /*fromCache*/), - force, 0); + audio_io_handle_t output = mOutputs.keyAt(i); + if ((mPhoneState != AUDIO_MODE_IN_CALL) || (output != mPrimaryOutput)) { + audio_devices_t newDevice = getNewOutputDevice(mOutputs.keyAt(i), + true /*fromCache*/); + // do not force device change on duplicated output because if device is 0, it will + // also force a device 0 for the two outputs it is duplicated to which may override + // a valid device selection on those outputs. + bool force = !mOutputs.valueAt(i)->isDuplicated() + && (!deviceDistinguishesOnAddress(device) + // always force when disconnecting (a non-duplicated device) + || (state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE)); + setOutputDevice(output, newDevice, force, 0); + } } mpClientInterface->onAudioPortListUpdate(); @@ -371,6 +378,11 @@ status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device, closeAllInputs(); + if (mPhoneState == AUDIO_MODE_IN_CALL) { + audio_devices_t newDevice = getNewOutputDevice(mPrimaryOutput, false /*fromCache*/); + updateCallRouting(newDevice); + } + mpClientInterface->onAudioPortListUpdate(); return NO_ERROR; } // end if is input device @@ -405,10 +417,124 @@ audio_policy_dev_state_t AudioPolicyManager::getDeviceConnectionState(audio_devi } } +void AudioPolicyManager::updateCallRouting(audio_devices_t rxDevice, int delayMs) +{ + bool createTxPatch = false; + struct audio_patch patch; + patch.num_sources = 1; + patch.num_sinks = 1; + status_t status; + audio_patch_handle_t afPatchHandle; + DeviceVector deviceList; + + audio_devices_t txDevice = getDeviceForInputSource(AUDIO_SOURCE_VOICE_COMMUNICATION); + ALOGV("updateCallRouting device rxDevice %08x txDevice %08x", rxDevice, txDevice); + + // release existing RX patch if any + if (mCallRxPatch != 0) { + mpClientInterface->releaseAudioPatch(mCallRxPatch->mAfPatchHandle, 0); + mCallRxPatch.clear(); + } + // release TX patch if any + if (mCallTxPatch != 0) { + mpClientInterface->releaseAudioPatch(mCallTxPatch->mAfPatchHandle, 0); + mCallTxPatch.clear(); + } + + // If the RX device is on the primary HW module, then use legacy routing method for voice calls + // via setOutputDevice() on primary output. + // Otherwise, create two audio patches for TX and RX path. + if (availablePrimaryOutputDevices() & rxDevice) { + setOutputDevice(mPrimaryOutput, rxDevice, true, delayMs); + // If the TX device is also on the primary HW module, setOutputDevice() will take care + // of it due to legacy implementation. If not, create a patch. + if ((availablePrimaryInputDevices() & txDevice & ~AUDIO_DEVICE_BIT_IN) + == AUDIO_DEVICE_NONE) { + createTxPatch = true; + } + } else { + // create RX path audio patch + deviceList = mAvailableOutputDevices.getDevicesFromType(rxDevice); + ALOG_ASSERT(!deviceList.isEmpty(), + "updateCallRouting() selected device not in output device list"); + sp<DeviceDescriptor> rxSinkDeviceDesc = deviceList.itemAt(0); + deviceList = mAvailableInputDevices.getDevicesFromType(AUDIO_DEVICE_IN_TELEPHONY_RX); + ALOG_ASSERT(!deviceList.isEmpty(), + "updateCallRouting() no telephony RX device"); + sp<DeviceDescriptor> rxSourceDeviceDesc = deviceList.itemAt(0); + + rxSourceDeviceDesc->toAudioPortConfig(&patch.sources[0]); + rxSinkDeviceDesc->toAudioPortConfig(&patch.sinks[0]); + + // request to reuse existing output stream if one is already opened to reach the RX device + SortedVector<audio_io_handle_t> outputs = + getOutputsForDevice(rxDevice, mOutputs); + audio_io_handle_t output = selectOutput(outputs, AUDIO_OUTPUT_FLAG_NONE); + if (output != AUDIO_IO_HANDLE_NONE) { + sp<AudioOutputDescriptor> outputDesc = mOutputs.valueFor(output); + ALOG_ASSERT(!outputDesc->isDuplicated(), + "updateCallRouting() RX device output is duplicated"); + outputDesc->toAudioPortConfig(&patch.sources[1]); + patch.num_sources = 2; + } + + afPatchHandle = AUDIO_PATCH_HANDLE_NONE; + status = mpClientInterface->createAudioPatch(&patch, &afPatchHandle, 0); + ALOGW_IF(status != NO_ERROR, "updateCallRouting() error %d creating RX audio patch", + status); + if (status == NO_ERROR) { + mCallRxPatch = new AudioPatch((audio_patch_handle_t)nextUniqueId(), + &patch, mUidCached); + mCallRxPatch->mAfPatchHandle = afPatchHandle; + mCallRxPatch->mUid = mUidCached; + } + createTxPatch = true; + } + if (createTxPatch) { + + struct audio_patch patch; + patch.num_sources = 1; + patch.num_sinks = 1; + deviceList = mAvailableInputDevices.getDevicesFromType(txDevice); + ALOG_ASSERT(!deviceList.isEmpty(), + "updateCallRouting() selected device not in input device list"); + sp<DeviceDescriptor> txSourceDeviceDesc = deviceList.itemAt(0); + txSourceDeviceDesc->toAudioPortConfig(&patch.sources[0]); + deviceList = mAvailableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_TELEPHONY_TX); + ALOG_ASSERT(!deviceList.isEmpty(), + "updateCallRouting() no telephony TX device"); + sp<DeviceDescriptor> txSinkDeviceDesc = deviceList.itemAt(0); + txSinkDeviceDesc->toAudioPortConfig(&patch.sinks[0]); + + SortedVector<audio_io_handle_t> outputs = + getOutputsForDevice(AUDIO_DEVICE_OUT_TELEPHONY_TX, mOutputs); + audio_io_handle_t output = selectOutput(outputs, AUDIO_OUTPUT_FLAG_NONE); + // request to reuse existing output stream if one is already opened to reach the TX + // path output device + if (output != AUDIO_IO_HANDLE_NONE) { + sp<AudioOutputDescriptor> outputDesc = mOutputs.valueFor(output); + ALOG_ASSERT(!outputDesc->isDuplicated(), + "updateCallRouting() RX device output is duplicated"); + outputDesc->toAudioPortConfig(&patch.sources[1]); + patch.num_sources = 2; + } + + afPatchHandle = AUDIO_PATCH_HANDLE_NONE; + status = mpClientInterface->createAudioPatch(&patch, &afPatchHandle, 0); + ALOGW_IF(status != NO_ERROR, "setPhoneState() error %d creating TX audio patch", + status); + if (status == NO_ERROR) { + mCallTxPatch = new AudioPatch((audio_patch_handle_t)nextUniqueId(), + &patch, mUidCached); + mCallTxPatch->mAfPatchHandle = afPatchHandle; + mCallTxPatch->mUid = mUidCached; + } + } +} + void AudioPolicyManager::setPhoneState(audio_mode_t state) { ALOGV("setPhoneState() state %d", state); - audio_devices_t newDevice = AUDIO_DEVICE_NONE; if (state < 0 || state >= AUDIO_MODE_CNT) { ALOGW("setPhoneState() invalid state %d", state); return; @@ -460,19 +586,12 @@ void AudioPolicyManager::setPhoneState(audio_mode_t state) } // check for device and output changes triggered by new phone state - newDevice = getNewOutputDevice(mPrimaryOutput, false /*fromCache*/); checkA2dpSuspend(); checkOutputForAllStrategies(); updateDevicesAndOutputs(); sp<AudioOutputDescriptor> hwOutputDesc = mOutputs.valueFor(mPrimaryOutput); - // force routing command to audio hardware when ending call - // even if no device change is needed - if (isStateInCall(oldState) && newDevice == AUDIO_DEVICE_NONE) { - newDevice = hwOutputDesc->device(); - } - int delayMs = 0; if (isStateInCall(state)) { nsecs_t sysTime = systemTime(); @@ -499,9 +618,30 @@ void AudioPolicyManager::setPhoneState(audio_mode_t state) } } - // change routing is necessary - setOutputDevice(mPrimaryOutput, newDevice, force, delayMs); + // Note that despite the fact that getNewOutputDevice() is called on the primary output, + // the device returned is not necessarily reachable via this output + audio_devices_t rxDevice = getNewOutputDevice(mPrimaryOutput, false /*fromCache*/); + // force routing command to audio hardware when ending call + // even if no device change is needed + if (isStateInCall(oldState) && rxDevice == AUDIO_DEVICE_NONE) { + rxDevice = hwOutputDesc->device(); + } + if (state == AUDIO_MODE_IN_CALL) { + updateCallRouting(rxDevice, delayMs); + } else if (oldState == AUDIO_MODE_IN_CALL) { + if (mCallRxPatch != 0) { + mpClientInterface->releaseAudioPatch(mCallRxPatch->mAfPatchHandle, 0); + mCallRxPatch.clear(); + } + if (mCallTxPatch != 0) { + mpClientInterface->releaseAudioPatch(mCallTxPatch->mAfPatchHandle, 0); + mCallTxPatch.clear(); + } + setOutputDevice(mPrimaryOutput, rxDevice, force, 0); + } else { + setOutputDevice(mPrimaryOutput, rxDevice, force, 0); + } // if entering in call state, handle special case of active streams // pertaining to sonification strategy see handleIncallSonification() if (isStateInCall(state)) { @@ -590,10 +730,16 @@ void AudioPolicyManager::setForceUse(audio_policy_force_use_t usage, checkA2dpSuspend(); checkOutputForAllStrategies(); updateDevicesAndOutputs(); + if (mPhoneState == AUDIO_MODE_IN_CALL) { + audio_devices_t newDevice = getNewOutputDevice(mPrimaryOutput, true /*fromCache*/); + updateCallRouting(newDevice); + } for (size_t i = 0; i < mOutputs.size(); i++) { audio_io_handle_t output = mOutputs.keyAt(i); audio_devices_t newDevice = getNewOutputDevice(output, true /*fromCache*/); - setOutputDevice(output, newDevice, (newDevice != AUDIO_DEVICE_NONE)); + if ((mPhoneState != AUDIO_MODE_IN_CALL) || (output != mPrimaryOutput)) { + setOutputDevice(output, newDevice, (newDevice != AUDIO_DEVICE_NONE)); + } if (forceVolumeReeval && (newDevice != AUDIO_DEVICE_NONE)) { applyStreamVolumes(output, newDevice, 0, true); } @@ -1892,6 +2038,25 @@ sp <AudioPolicyManager::HwModule> AudioPolicyManager::getModuleFromName(const ch return module; } +audio_devices_t AudioPolicyManager::availablePrimaryOutputDevices() +{ + sp<AudioOutputDescriptor> outputDesc = mOutputs.valueFor(mPrimaryOutput); + audio_devices_t devices = outputDesc->mProfile->mSupportedDevices.types(); + return devices & mAvailableOutputDevices.types(); +} + +audio_devices_t AudioPolicyManager::availablePrimaryInputDevices() +{ + audio_module_handle_t primaryHandle = + mOutputs.valueFor(mPrimaryOutput)->mProfile->mModule->mHandle; + audio_devices_t devices = AUDIO_DEVICE_NONE; + for (size_t i = 0; i < mAvailableInputDevices.size(); i++) { + if (mAvailableInputDevices[i]->mModule->mHandle == primaryHandle) { + devices |= mAvailableInputDevices[i]->mDeviceType; + } + } + return devices; +} status_t AudioPolicyManager::createAudioPatch(const struct audio_patch *patch, audio_patch_handle_t *handle, @@ -3641,6 +3806,21 @@ audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strate // FALL THROUGH case STRATEGY_PHONE: + // Force use of only devices on primary output if: + // - in call AND + // - cannot route from voice call RX OR + // - audio HAL version is < 3.0 and TX device is on the primary HW module + if (mPhoneState == AUDIO_MODE_IN_CALL) { + audio_devices_t txDevice = getDeviceForInputSource(AUDIO_SOURCE_VOICE_COMMUNICATION); + sp<AudioOutputDescriptor> hwOutputDesc = mOutputs.valueFor(mPrimaryOutput); + if (((mAvailableInputDevices.types() & + AUDIO_DEVICE_IN_TELEPHONY_RX & ~AUDIO_DEVICE_BIT_IN) == 0) || + (((txDevice & availablePrimaryInputDevices() & ~AUDIO_DEVICE_BIT_IN) != 0) && + (hwOutputDesc->mAudioPort->mModule->mHalVersion < + AUDIO_DEVICE_API_VERSION_3_0))) { + availableOutputDeviceTypes = availablePrimaryOutputDevices(); + } + } // for phone strategy, we first consider the forced use and then the available devices by order // of priority switch (mForceUse[AUDIO_POLICY_FORCE_FOR_COMMUNICATION]) { @@ -3670,11 +3850,11 @@ audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strate if (device) break; device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_WIRED_HEADSET; if (device) break; + device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_USB_DEVICE; + if (device) break; if (mPhoneState != AUDIO_MODE_IN_CALL) { device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_USB_ACCESSORY; if (device) break; - device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_USB_DEVICE; - if (device) break; device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET; if (device) break; device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_AUX_DIGITAL; @@ -4178,19 +4358,60 @@ audio_devices_t AudioPolicyManager::getDeviceForInputSource(audio_source_t input device = AUDIO_DEVICE_IN_VOICE_CALL; break; } - // FALL THROUGH + break; case AUDIO_SOURCE_DEFAULT: case AUDIO_SOURCE_MIC: if (availableDeviceTypes & AUDIO_DEVICE_IN_BLUETOOTH_A2DP) { device = AUDIO_DEVICE_IN_BLUETOOTH_A2DP; - break; + } else if (availableDeviceTypes & AUDIO_DEVICE_IN_WIRED_HEADSET) { + device = AUDIO_DEVICE_IN_WIRED_HEADSET; + } else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_DEVICE) { + device = AUDIO_DEVICE_IN_USB_DEVICE; + } else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) { + device = AUDIO_DEVICE_IN_BUILTIN_MIC; } - // FALL THROUGH + break; + + case AUDIO_SOURCE_VOICE_COMMUNICATION: + // Allow only use of devices on primary input if in call and HAL does not support routing + // to voice call path. + if ((mPhoneState == AUDIO_MODE_IN_CALL) && + (mAvailableOutputDevices.types() & AUDIO_DEVICE_OUT_TELEPHONY_TX) == 0) { + availableDeviceTypes = availablePrimaryInputDevices() & ~AUDIO_DEVICE_BIT_IN; + } + + switch (mForceUse[AUDIO_POLICY_FORCE_FOR_COMMUNICATION]) { + case AUDIO_POLICY_FORCE_BT_SCO: + // if SCO device is requested but no SCO device is available, fall back to default case + if (availableDeviceTypes & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) { + device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET; + break; + } + // FALL THROUGH + + default: // FORCE_NONE + if (availableDeviceTypes & AUDIO_DEVICE_IN_WIRED_HEADSET) { + device = AUDIO_DEVICE_IN_WIRED_HEADSET; + } else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_DEVICE) { + device = AUDIO_DEVICE_IN_USB_DEVICE; + } else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) { + device = AUDIO_DEVICE_IN_BUILTIN_MIC; + } + break; + + case AUDIO_POLICY_FORCE_SPEAKER: + if (availableDeviceTypes & AUDIO_DEVICE_IN_BACK_MIC) { + device = AUDIO_DEVICE_IN_BACK_MIC; + } else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) { + device = AUDIO_DEVICE_IN_BUILTIN_MIC; + } + break; + } + break; case AUDIO_SOURCE_VOICE_RECOGNITION: case AUDIO_SOURCE_HOTWORD: - case AUDIO_SOURCE_VOICE_COMMUNICATION: if (mForceUse[AUDIO_POLICY_FORCE_FOR_RECORD] == AUDIO_POLICY_FORCE_BT_SCO && availableDeviceTypes & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) { device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET; diff --git a/services/audiopolicy/AudioPolicyManager.h b/services/audiopolicy/AudioPolicyManager.h index 47235f7..95aab65 100644 --- a/services/audiopolicy/AudioPolicyManager.h +++ b/services/audiopolicy/AudioPolicyManager.h @@ -727,6 +727,11 @@ protected: sp<AudioInputDescriptor> getInputFromId(audio_port_handle_t id) const; sp<HwModule> getModuleForDevice(audio_devices_t device) const; sp<HwModule> getModuleFromName(const char *name) const; + audio_devices_t availablePrimaryOutputDevices(); + audio_devices_t availablePrimaryInputDevices(); + + void updateCallRouting(audio_devices_t rxDevice, int delayMs = 0); + // // Audio policy configuration file parsing (audio_policy.conf) // @@ -785,6 +790,9 @@ protected: DefaultKeyedVector<audio_session_t, audio_io_handle_t> mSoundTriggerSessions; + sp<AudioPatch> mCallTxPatch; + sp<AudioPatch> mCallRxPatch; + #ifdef AUDIO_POLICY_TEST Mutex mLock; Condition mWaitWorkCV; |