From c722f30eef03e77054395ae122470cf8dba93937 Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Wed, 10 Dec 2014 11:21:49 -0800 Subject: audio policy: suppport for dynamic source Completed support for dynamic sources: - remote submix input device is dynamically connected/disconnected when corresponding AudioTrack starts/stops. Also do not create a duplicated output for mixes used by dynamic policies. Bug: 16006090. Change-Id: Ib5b5a2159fcac9d9f410a5a2f1c64d7ebad79f72 --- services/audiopolicy/AudioPolicyManager.cpp | 140 +++++++++++++++++++--------- services/audiopolicy/AudioPolicyManager.h | 9 +- 2 files changed, 101 insertions(+), 48 deletions(-) diff --git a/services/audiopolicy/AudioPolicyManager.cpp b/services/audiopolicy/AudioPolicyManager.cpp index 9918b6f..3cd5fb2 100644 --- a/services/audiopolicy/AudioPolicyManager.cpp +++ b/services/audiopolicy/AudioPolicyManager.cpp @@ -899,14 +899,13 @@ status_t AudioPolicyManager::getOutputForAttr(const audio_attributes_t *attr, mPolicyMixes[i]->mMix.mRegistrationId.string(), AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - strlen("addr=") - 1) == 0) { desc = mPolicyMixes[i]->mOutput; - break; } } if (desc != 0) { if (!audio_is_linear_pcm(format)) { return BAD_VALUE; } - desc->mPolicyMixAddress = mPolicyMixes[i]->mMix.mRegistrationId; + desc->mPolicyMix = &mPolicyMixes[i]->mMix; *stream = streamTypefromAttributesInt(&attributes); *output = desc->mIoHandle; ALOGV("getOutputForAttr() returns output %d", *output); @@ -1227,8 +1226,7 @@ status_t AudioPolicyManager::startOutput(audio_io_handle_t output, if (outputDesc->mRefCount[stream] == 1) { // starting an output being rerouted? audio_devices_t newDevice; - if (outputDesc->mPolicyMixAddress != String8("") - && outputDesc->mPolicyMixAddress != String8("0")) { + if (outputDesc->mPolicyMix != NULL) { newDevice = AUDIO_DEVICE_OUT_REMOTE_SUBMIX; } else { newDevice = getNewOutputDevice(output, false /*fromCache*/); @@ -1275,6 +1273,16 @@ status_t AudioPolicyManager::startOutput(audio_io_handle_t output, // update the outputs if starting an output with a stream that can affect notification // routing handleNotificationRoutingForStream(stream); + + // Automatically enable the remote submix input when output is started on a re routing mix + // of type MIX_TYPE_RECORDERS + if (audio_is_remote_submix_device(newDevice) && outputDesc->mPolicyMix != NULL && + outputDesc->mPolicyMix->mMixType == MIX_TYPE_RECORDERS) { + setDeviceConnectionState(AUDIO_DEVICE_IN_REMOTE_SUBMIX, + AUDIO_POLICY_DEVICE_STATE_AVAILABLE, + outputDesc->mPolicyMix->mRegistrationId); + } + if (waitMs > muteWaitMs) { usleep((waitMs - muteWaitMs) * 2 * 1000); } @@ -1309,6 +1317,16 @@ status_t AudioPolicyManager::stopOutput(audio_io_handle_t output, outputDesc->changeRefCount(stream, -1); // store time at which the stream was stopped - see isStreamActive() if (outputDesc->mRefCount[stream] == 0) { + // Automatically disable the remote submix input when output is stopped on a + // re routing mix of type MIX_TYPE_RECORDERS + if (audio_is_remote_submix_device(outputDesc->mDevice) && + outputDesc->mPolicyMix != NULL && + outputDesc->mPolicyMix->mMixType == MIX_TYPE_RECORDERS) { + setDeviceConnectionState(AUDIO_DEVICE_IN_REMOTE_SUBMIX, + AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE, + outputDesc->mPolicyMix->mRegistrationId); + } + outputDesc->mStopTime[stream] = systemTime(); audio_devices_t newDevice = getNewOutputDevice(output, false /*fromCache*/); // delay the device switch by twice the latency because stopOutput() is executed when @@ -1406,6 +1424,7 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr, String8 address = String8(""); bool isSoundTrigger = false; audio_source_t halInputSource = attr->source; + AudioMix *policyMix = NULL; if (attr->source == AUDIO_SOURCE_REMOTE_SUBMIX && strncmp(attr->tags, "addr=", strlen("addr=")) == 0) { @@ -1416,13 +1435,22 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr, ALOGW("getInputForAttr() no policy for address %s", address.string()); return BAD_VALUE; } + if (mPolicyMixes[index]->mMix.mMixType != MIX_TYPE_PLAYERS) { + ALOGW("getInputForAttr() bad policy mix type for address %s", address.string()); + return BAD_VALUE; + } + policyMix = &mPolicyMixes[index]->mMix; } else { - device = getDeviceForInputSource(attr->source, &address); - + device = getDeviceForInputSource(attr->source, &policyMix); if (device == AUDIO_DEVICE_NONE) { ALOGW("getInputForAttr() could not find device for source %d", attr->source); return BAD_VALUE; } + if (policyMix != NULL) { + address = policyMix->mRegistrationId; + } else if (audio_is_remote_submix_device(device)) { + address = String8("0"); + } // adapt channel selection to input source switch (attr->source) { case AUDIO_SOURCE_VOICE_UPLINK: @@ -1507,8 +1535,9 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr, inputDesc->mFormat = format; inputDesc->mChannelMask = channelMask; inputDesc->mDevice = device; - inputDesc->mSessions.add(session, address); + inputDesc->mSessions.add(session); inputDesc->mIsSoundTrigger = isSoundTrigger; + inputDesc->mPolicyMix = policyMix; addInput(*input, inputDesc); mpClientInterface->onAudioPortListUpdate(); @@ -1526,7 +1555,7 @@ status_t AudioPolicyManager::startInput(audio_io_handle_t input, } sp inputDesc = mInputs.valueAt(index); - index = inputDesc->mSessions.indexOfKey(session); + index = inputDesc->mSessions.indexOf(session); if (index < 0) { ALOGW("startInput() unknown session %d on input %d", session, input); return BAD_VALUE; @@ -1544,8 +1573,8 @@ status_t AudioPolicyManager::startInput(audio_io_handle_t input, sp activeDesc = mInputs.valueFor(activeInput); if (activeDesc->mInputSource == AUDIO_SOURCE_HOTWORD) { ALOGW("startInput(%d) preempting low-priority input %d", input, activeInput); - stopInput(activeInput, activeDesc->mSessions.keyAt(0)); - releaseInput(activeInput, activeDesc->mSessions.keyAt(0)); + stopInput(activeInput, activeDesc->mSessions.itemAt(0)); + releaseInput(activeInput, activeDesc->mSessions.itemAt(0)); } else { ALOGE("startInput(%d) failed: other input %d already started", input, activeInput); return INVALID_OPERATION; @@ -1559,12 +1588,21 @@ status_t AudioPolicyManager::startInput(audio_io_handle_t input, } setInputDevice(input, getNewInputDevice(input), true /* force */); - // Automatically enable the remote submix output when input is started. + // automatically enable the remote submix output when input is started if not + // used by a policy mix of type MIX_TYPE_RECORDERS // For remote submix (a virtual device), we open only one input per capture request. if (audio_is_remote_submix_device(inputDesc->mDevice)) { - setDeviceConnectionState(AUDIO_DEVICE_OUT_REMOTE_SUBMIX, - AUDIO_POLICY_DEVICE_STATE_AVAILABLE, - inputDesc->mSessions.valueAt(index)); + String8 address = String8(""); + if (inputDesc->mPolicyMix == NULL) { + address = String8("0"); + } else if (inputDesc->mPolicyMix->mMixType == MIX_TYPE_PLAYERS) { + address = inputDesc->mPolicyMix->mRegistrationId; + } + if (address != "") { + setDeviceConnectionState(AUDIO_DEVICE_OUT_REMOTE_SUBMIX, + AUDIO_POLICY_DEVICE_STATE_AVAILABLE, + address); + } } } @@ -1585,7 +1623,7 @@ status_t AudioPolicyManager::stopInput(audio_io_handle_t input, } sp inputDesc = mInputs.valueAt(index); - index = inputDesc->mSessions.indexOfKey(session); + index = inputDesc->mSessions.indexOf(session); if (index < 0) { ALOGW("stopInput() unknown session %d on input %d", session, input); return BAD_VALUE; @@ -1599,11 +1637,20 @@ status_t AudioPolicyManager::stopInput(audio_io_handle_t input, inputDesc->mRefCount--; if (inputDesc->mRefCount == 0) { - // automatically disable the remote submix output when input is stopped + // automatically disable the remote submix output when input is stopped if not + // used by a policy mix of type MIX_TYPE_RECORDERS if (audio_is_remote_submix_device(inputDesc->mDevice)) { - setDeviceConnectionState(AUDIO_DEVICE_OUT_REMOTE_SUBMIX, - AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE, - inputDesc->mSessions.valueAt(index)); + String8 address = String8(""); + if (inputDesc->mPolicyMix == NULL) { + address = String8("0"); + } else if (inputDesc->mPolicyMix->mMixType == MIX_TYPE_PLAYERS) { + address = inputDesc->mPolicyMix->mRegistrationId; + } + if (address != "") { + setDeviceConnectionState(AUDIO_DEVICE_OUT_REMOTE_SUBMIX, + AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE, + address); + } } resetInputDevice(input); @@ -1627,12 +1674,12 @@ void AudioPolicyManager::releaseInput(audio_io_handle_t input, sp inputDesc = mInputs.valueAt(index); ALOG_ASSERT(inputDesc != 0); - index = inputDesc->mSessions.indexOfKey(session); + index = inputDesc->mSessions.indexOf(session); if (index < 0) { ALOGW("releaseInput() unknown session %d on input %d", session, input); return; } - inputDesc->mSessions.removeItem(session); + inputDesc->mSessions.remove(session); if (inputDesc->mOpenRefCount == 0) { ALOGW("releaseInput() invalid open ref count %d", inputDesc->mOpenRefCount); return; @@ -1961,10 +2008,9 @@ bool AudioPolicyManager::isStreamActiveRemotely(audio_stream_type_t stream, const sp outputDesc = mOutputs.valueAt(i); if (((outputDesc->device() & APM_AUDIO_OUT_DEVICE_REMOTE_ALL) != 0) && outputDesc->isStreamActive(stream, inPastMs, sysTime)) { - // only consider empty or "0" address to only qualify the screen mirroring case - // as "remote playback" (vs rerouting when the output is going to a dynamic policy) - if (outputDesc->mPolicyMixAddress == String8("") - || outputDesc->mPolicyMixAddress == String8("0")) { + // do not consider re routing (when the output is going to a dynamic policy) + // as "remote playback" + if (outputDesc->mPolicyMix == NULL) { return true; } } @@ -2046,9 +2092,15 @@ status_t AudioPolicyManager::registerPolicyMixes(Vector mixes) sp policyMix = new AudioPolicyMix(); policyMix->mMix = mixes[i]; mPolicyMixes.add(address, policyMix); - setDeviceConnectionState(AUDIO_DEVICE_IN_REMOTE_SUBMIX, - AUDIO_POLICY_DEVICE_STATE_AVAILABLE, - address.string()); + if (mixes[i].mMixType == MIX_TYPE_PLAYERS) { + setDeviceConnectionState(AUDIO_DEVICE_IN_REMOTE_SUBMIX, + AUDIO_POLICY_DEVICE_STATE_AVAILABLE, + address.string()); + } else { + setDeviceConnectionState(AUDIO_DEVICE_OUT_REMOTE_SUBMIX, + AUDIO_POLICY_DEVICE_STATE_AVAILABLE, + address.string()); + } } return NO_ERROR; } @@ -2080,9 +2132,13 @@ status_t AudioPolicyManager::unregisterPolicyMixes(Vector mixes) mPolicyMixes.removeItemsAt(index); - setDeviceConnectionState(AUDIO_DEVICE_IN_REMOTE_SUBMIX, - AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE, - address.string()); + if (getDeviceConnectionState(AUDIO_DEVICE_IN_REMOTE_SUBMIX, address.string()) == + AUDIO_POLICY_DEVICE_STATE_AVAILABLE) + { + setDeviceConnectionState(AUDIO_DEVICE_IN_REMOTE_SUBMIX, + AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE, + address.string()); + } if (getDeviceConnectionState(AUDIO_DEVICE_OUT_REMOTE_SUBMIX, address.string()) == AUDIO_POLICY_DEVICE_STATE_AVAILABLE) @@ -3543,12 +3599,14 @@ status_t AudioPolicyManager::checkOutputsForDevice(const sp de ssize_t index = mPolicyMixes.indexOfKey(address); if (index >= 0) { mPolicyMixes[index]->mOutput = desc; + desc->mPolicyMix = &mPolicyMixes[index]->mMix; } else { ALOGE("checkOutputsForDevice() cannot find policy for address %s", address.string()); } - } - if ((desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) == 0) { + } else if ((desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) == 0) { + // no duplicated output for direct outputs and + // outputs used by dynamic policy mixes audio_io_handle_t duplicatedOutput = AUDIO_IO_HANDLE_NONE; // set initial stream volume for device @@ -5014,7 +5072,7 @@ sp AudioPolicyManager::getInputProfile(audio_devi } audio_devices_t AudioPolicyManager::getDeviceForInputSource(audio_source_t inputSource, - String8 *address) + AudioMix **policyMix) { uint32_t device = AUDIO_DEVICE_NONE; audio_devices_t availableDeviceTypes = mAvailableInputDevices.types() & @@ -5030,8 +5088,8 @@ audio_devices_t AudioPolicyManager::getDeviceForInputSource(audio_source_t input (RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET == mPolicyMixes[i]->mMix.mCriteria[j].mRule && mPolicyMixes[i]->mMix.mCriteria[j].mAttr.mSource != inputSource)) { if (availableDeviceTypes & AUDIO_DEVICE_IN_REMOTE_SUBMIX) { - if (address != NULL) { - *address = mPolicyMixes[i]->mMix.mRegistrationId; + if (policyMix != NULL) { + *policyMix = &mPolicyMixes[i]->mMix; } return AUDIO_DEVICE_IN_REMOTE_SUBMIX; } @@ -5127,9 +5185,6 @@ audio_devices_t AudioPolicyManager::getDeviceForInputSource(audio_source_t input case AUDIO_SOURCE_REMOTE_SUBMIX: if (availableDeviceTypes & AUDIO_DEVICE_IN_REMOTE_SUBMIX) { device = AUDIO_DEVICE_IN_REMOTE_SUBMIX; - if (address != NULL) { - *address = "0"; - } } break; case AUDIO_SOURCE_FM_TUNER: @@ -5571,8 +5626,7 @@ status_t AudioPolicyManager::checkAndSetVolume(audio_stream_type_t stream, ssize_t index = mOutputs.indexOfKey(output); if (index >= 0) { sp outputDesc = mOutputs.valueAt(index); - if (outputDesc->mPolicyMixAddress != String8("") - && outputDesc->mPolicyMixAddress != String8("0")) { + if (outputDesc->mPolicyMix != NULL) { ALOGV("max gain when rerouting for output=%d", output); volume = 1.0f; } @@ -5761,7 +5815,7 @@ uint32_t AudioPolicyManager::getMaxEffectsMemory() AudioPolicyManager::AudioOutputDescriptor::AudioOutputDescriptor( const sp& profile) : mId(0), mIoHandle(0), mLatency(0), - mFlags((audio_output_flags_t)0), mDevice(AUDIO_DEVICE_NONE), mPolicyMixAddress(String8("")), + mFlags((audio_output_flags_t)0), mDevice(AUDIO_DEVICE_NONE), mPolicyMix(NULL), mPatchHandle(0), mOutput1(0), mOutput2(0), mProfile(profile), mDirectOpenCount(0) { @@ -5957,7 +6011,7 @@ status_t AudioPolicyManager::AudioOutputDescriptor::dump(int fd) AudioPolicyManager::AudioInputDescriptor::AudioInputDescriptor(const sp& profile) : mId(0), mIoHandle(0), - mDevice(AUDIO_DEVICE_NONE), mPatchHandle(0), mRefCount(0), + mDevice(AUDIO_DEVICE_NONE), mPolicyMix(NULL), mPatchHandle(0), mRefCount(0), mInputSource(AUDIO_SOURCE_DEFAULT), mProfile(profile), mIsSoundTrigger(false) { if (profile != NULL) { diff --git a/services/audiopolicy/AudioPolicyManager.h b/services/audiopolicy/AudioPolicyManager.h index 3eef8fe..9ec3557 100644 --- a/services/audiopolicy/AudioPolicyManager.h +++ b/services/audiopolicy/AudioPolicyManager.h @@ -497,7 +497,7 @@ protected: uint32_t mLatency; // audio_output_flags_t mFlags; // audio_devices_t mDevice; // current device this output is routed to - String8 mPolicyMixAddress; // non empty or "0" when used by a dynamic policy + AudioMix *mPolicyMix; // non NULL when used by a dynamic policy audio_patch_handle_t mPatchHandle; uint32_t mRefCount[AUDIO_STREAM_CNT]; // number of streams of each type using this output nsecs_t mStopTime[AUDIO_STREAM_CNT]; @@ -523,6 +523,7 @@ protected: audio_port_handle_t mId; audio_io_handle_t mIoHandle; // input handle audio_devices_t mDevice; // current device this input is routed to + AudioMix *mPolicyMix; // non NULL when used by a dynamic policy audio_patch_handle_t mPatchHandle; uint32_t mRefCount; // number of AudioRecord clients using // this input @@ -530,9 +531,7 @@ protected: audio_source_t mInputSource; // input source selected by application //(mediarecorder.h) const sp mProfile; // I/O profile this output derives from - // audio sessions attached to this input and the - // corresponding device address - DefaultKeyedVector mSessions; + SortedVector mSessions; // audio sessions attached to this input bool mIsSoundTrigger; // used by a soundtrigger capture virtual void toAudioPortConfig(struct audio_port_config *dstConfig, @@ -612,7 +611,7 @@ protected: // select input device corresponding to requested audio source virtual audio_devices_t getDeviceForInputSource(audio_source_t inputSource, - String8 *address = NULL); + AudioMix **policyMix = NULL); // return io handle of active input or 0 if no input is active // Only considers inputs from physical devices (e.g. main mic, headset mic) when -- cgit v1.1