diff options
author | Eric Laurent <elaurent@google.com> | 2014-11-30 15:14:47 -0800 |
---|---|---|
committer | Eric Laurent <elaurent@google.com> | 2014-12-09 15:47:19 -0800 |
commit | 275e8e9de2e11b4b344f5a201f1f0e51fda02d9c (patch) | |
tree | c22e1c0b8541aa04fd6c8d803e4fa6704a84e6e2 | |
parent | 82a69ea8b090d57bff5e02774688b546a711bbb8 (diff) | |
download | frameworks_av-275e8e9de2e11b4b344f5a201f1f0e51fda02d9c.zip frameworks_av-275e8e9de2e11b4b344f5a201f1f0e51fda02d9c.tar.gz frameworks_av-275e8e9de2e11b4b344f5a201f1f0e51fda02d9c.tar.bz2 |
audio policy: add support for custom mixes
Add support for custom mixes in AudioPolicyManager.
Two methods are added to register or unregister a list of custom mixes
with their attributes and format.
getOutputForAttr() and getInputForAttr() first look for a match in
registered mixes before defaulting to normal output/input selection
Remote submix device connection disconnection now takes address into
account to identify the correspnoding custom mix.
Bug: 16009464.
Change-Id: I3f1c2a485a0fb71b1f984ed0adc9b68aa971e408
-rw-r--r-- | include/media/AudioPolicy.h | 82 | ||||
-rw-r--r-- | include/media/AudioPolicyHelper.h | 2 | ||||
-rw-r--r-- | media/libmedia/Android.mk | 3 | ||||
-rw-r--r-- | media/libmedia/AudioPolicy.cpp | 115 | ||||
-rw-r--r-- | media/libmedia/AudioTrack.cpp | 8 | ||||
-rw-r--r-- | services/audioflinger/Threads.cpp | 8 | ||||
-rw-r--r-- | services/audiopolicy/AudioPolicyManager.cpp | 496 | ||||
-rw-r--r-- | services/audiopolicy/AudioPolicyManager.h | 40 |
8 files changed, 648 insertions, 106 deletions
diff --git a/include/media/AudioPolicy.h b/include/media/AudioPolicy.h new file mode 100644 index 0000000..a755e1e --- /dev/null +++ b/include/media/AudioPolicy.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef ANDROID_AUDIO_POLICY_H +#define ANDROID_AUDIO_POLICY_H + +#include <system/audio.h> +#include <system/audio_policy.h> +#include <binder/Parcel.h> +#include <utils/String8.h> +#include <utils/Vector.h> + +namespace android { + +// Keep in sync with AudioMix.java, AudioMixingRule.java, AudioPolicyConfig.java +#define RULE_EXCLUSION_MASK 0x8000 +#define RULE_MATCH_ATTRIBUTE_USAGE 0x1 +#define RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET (0x1 << 1) +#define RULE_EXCLUDE_ATTRIBUTE_USAGE (RULE_EXCLUSION_MASK|RULE_MATCH_ATTRIBUTE_USAGE) +#define RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET \ + (RULE_EXCLUSION_MASK|RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET) + +#define MIX_TYPE_INVALID -1 +#define MIX_TYPE_PLAYERS 0 +#define MIX_TYPE_RECORDERS 1 + +#define ROUTE_FLAG_RENDER 0x1 +#define ROUTE_FLAG_LOOP_BACK (0x1 << 1) + +#define MAX_MIXES_PER_POLICY 10 +#define MAX_CRITERIA_PER_MIX 20 + +class AttributeMatchCriterion { +public: + AttributeMatchCriterion() {} + AttributeMatchCriterion(audio_usage_t usage, audio_source_t source, uint32_t rule); + + status_t readFromParcel(Parcel *parcel); + status_t writeToParcel(Parcel *parcel) const; + + union { + audio_usage_t mUsage; + audio_source_t mSource; + } mAttr; + uint32_t mRule; +}; + +class AudioMix { +public: + AudioMix() {} + AudioMix(Vector<AttributeMatchCriterion> criteria, uint32_t mixType, audio_config_t format, + uint32_t routeFlags, String8 registrationId) : + mCriteria(criteria), mMixType(mixType), mFormat(format), + mRouteFlags(routeFlags), mRegistrationId(registrationId) {} + + status_t readFromParcel(Parcel *parcel); + status_t writeToParcel(Parcel *parcel) const; + + Vector<AttributeMatchCriterion> mCriteria; + uint32_t mMixType; + audio_config_t mFormat; + uint32_t mRouteFlags; + String8 mRegistrationId; +}; + +}; // namespace android + +#endif // ANDROID_AUDIO_POLICY_H diff --git a/include/media/AudioPolicyHelper.h b/include/media/AudioPolicyHelper.h index 3ed0b74..79231be 100644 --- a/include/media/AudioPolicyHelper.h +++ b/include/media/AudioPolicyHelper.h @@ -63,7 +63,7 @@ static audio_stream_type_t audio_attributes_to_stream_type(const audio_attribute static void stream_type_to_audio_attributes(audio_stream_type_t streamType, audio_attributes_t *attr) { - attr->flags = 0x0; + memset(attr, 0, sizeof(audio_attributes_t)); switch (streamType) { case AUDIO_STREAM_DEFAULT: diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk index e012116..a2e0909 100644 --- a/media/libmedia/Android.mk +++ b/media/libmedia/Android.mk @@ -59,7 +59,8 @@ LOCAL_SRC_FILES:= \ MemoryLeakTrackUtil.cpp \ SoundPool.cpp \ SoundPoolThread.cpp \ - StringArray.cpp + StringArray.cpp \ + AudioPolicy.cpp LOCAL_SRC_FILES += ../libnbaio/roundup.c diff --git a/media/libmedia/AudioPolicy.cpp b/media/libmedia/AudioPolicy.cpp new file mode 100644 index 0000000..d2d0971 --- /dev/null +++ b/media/libmedia/AudioPolicy.cpp @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "AudioPolicy" +//#define LOG_NDEBUG 0 +#include <utils/Log.h> +#include <media/AudioPolicy.h> + +namespace android { + +// +// AttributeMatchCriterion implementation +// +AttributeMatchCriterion::AttributeMatchCriterion(audio_usage_t usage, + audio_source_t source, + uint32_t rule) +: mRule(rule) +{ + if (mRule == RULE_MATCH_ATTRIBUTE_USAGE || + mRule == RULE_EXCLUDE_ATTRIBUTE_USAGE) { + mAttr.mUsage = usage; + } else { + mAttr.mSource = source; + } +} + +status_t AttributeMatchCriterion::readFromParcel(Parcel *parcel) +{ + mRule = parcel->readInt32(); + if (mRule == RULE_MATCH_ATTRIBUTE_USAGE || + mRule == RULE_EXCLUDE_ATTRIBUTE_USAGE) { + mAttr.mUsage = (audio_usage_t)parcel->readInt32(); + } else { + mAttr.mSource = (audio_source_t)parcel->readInt32(); + } + return NO_ERROR; +} + +status_t AttributeMatchCriterion::writeToParcel(Parcel *parcel) const +{ + parcel->writeInt32(mRule); + parcel->writeInt32(mAttr.mUsage); + return NO_ERROR; +} + +// +// AudioMix implementation +// + +status_t AudioMix::readFromParcel(Parcel *parcel) +{ + mMixType = parcel->readInt32(); + mFormat.sample_rate = (uint32_t)parcel->readInt32(); + mFormat.channel_mask = (audio_channel_mask_t)parcel->readInt32(); + mFormat.format = (audio_format_t)parcel->readInt32(); + mRouteFlags = parcel->readInt32(); + mRegistrationId = parcel->readString8(); + size_t size = (size_t)parcel->readInt32(); + if (size > MAX_CRITERIA_PER_MIX) { + size = MAX_CRITERIA_PER_MIX; + } + for (size_t i = 0; i < size; i++) { + AttributeMatchCriterion criterion; + if (criterion.readFromParcel(parcel) == NO_ERROR) { + mCriteria.add(criterion); + } + } + return NO_ERROR; +} + +status_t AudioMix::writeToParcel(Parcel *parcel) const +{ + parcel->writeInt32(mMixType); + parcel->writeInt32(mFormat.sample_rate); + parcel->writeInt32(mFormat.channel_mask); + parcel->writeInt32(mFormat.format); + parcel->writeInt32(mRouteFlags); + parcel->writeString8(mRegistrationId); + size_t size = mCriteria.size(); + if (size > MAX_CRITERIA_PER_MIX) { + size = MAX_CRITERIA_PER_MIX; + } + size_t sizePosition = parcel->dataPosition(); + parcel->writeInt32(size); + size_t finalSize = size; + for (size_t i = 0; i < size; i++) { + size_t position = parcel->dataPosition(); + if (mCriteria[i].writeToParcel(parcel) != NO_ERROR) { + parcel->setDataPosition(position); + finalSize--; + } + } + if (size != finalSize) { + size_t position = parcel->dataPosition(); + parcel->setDataPosition(sizePosition); + parcel->writeInt32(finalSize); + parcel->setDataPosition(position); + } + return NO_ERROR; +} + +}; // namespace android diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index e4c3c08..d9c3177 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -851,6 +851,10 @@ status_t AudioTrack::getPosition(uint32_t *position) // due to hardware latency. We leave this behavior for now. *position = dspFrames; } else { + if (mCblk->mFlags & CBLK_INVALID) { + restoreTrack_l("getPosition"); + } + // IAudioTrack::stop() isn't synchronous; we don't know when presentation completes *position = (mState == STATE_STOPPED || mState == STATE_FLUSHED) ? 0 : updateAndGetPosition_l(); @@ -1946,6 +1950,10 @@ status_t AudioTrack::getTimestamp(AudioTimestamp& timestamp) break; } + if (mCblk->mFlags & CBLK_INVALID) { + restoreTrack_l("getTimestamp"); + } + // The presented frame count must always lag behind the consumed frame count. // To avoid a race, read the presented frames first. This ensures that presented <= consumed. status_t status = mAudioTrack->getTimestamp(timestamp); diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index dab6d91..1c3cf5d 100644 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -2180,7 +2180,13 @@ void AudioFlinger::PlaybackThread::threadLoop_drain() void AudioFlinger::PlaybackThread::threadLoop_exit() { - // Default implementation has nothing to do + { + Mutex::Autolock _l(mLock); + for (size_t i = 0; i < mTracks.size(); i++) { + sp<Track> track = mTracks[i]; + track->invalidate(); + } + } } /* diff --git a/services/audiopolicy/AudioPolicyManager.cpp b/services/audiopolicy/AudioPolicyManager.cpp index 8bb35f9..68f3802 100644 --- a/services/audiopolicy/AudioPolicyManager.cpp +++ b/services/audiopolicy/AudioPolicyManager.cpp @@ -211,7 +211,6 @@ bool AudioPolicyManager::stringToBool(const char *value) // AudioPolicyInterface implementation // ---------------------------------------------------------------------------- - status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device, audio_policy_dev_state_t state, const char *device_address) @@ -818,7 +817,7 @@ sp<AudioPolicyManager::IOProfile> AudioPolicyManager::getProfileForDirectOutput( } for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++) { sp<IOProfile> profile = mHwModules[i]->mOutputProfiles[j]; - bool found = profile->isCompatibleProfile(device, samplingRate, + bool found = profile->isCompatibleProfile(device, String8(""), samplingRate, NULL /*updatedSamplingRate*/, format, channelMask, flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD ? AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD : AUDIO_OUTPUT_FLAG_DIRECT); @@ -874,6 +873,51 @@ status_t AudioPolicyManager::getOutputForAttr(const audio_attributes_t *attr, stream_type_to_audio_attributes(*stream, &attributes); } + for (size_t i = 0; i < mPolicyMixes.size(); i++) { + sp<AudioOutputDescriptor> desc; + if (mPolicyMixes[i]->mMix.mMixType == MIX_TYPE_PLAYERS) { + for (size_t j = 0; j < mPolicyMixes[i]->mMix.mCriteria.size(); j++) { + if ((RULE_MATCH_ATTRIBUTE_USAGE == mPolicyMixes[i]->mMix.mCriteria[j].mRule && + mPolicyMixes[i]->mMix.mCriteria[j].mAttr.mUsage == attributes.usage) || + (RULE_EXCLUDE_ATTRIBUTE_USAGE == mPolicyMixes[i]->mMix.mCriteria[j].mRule && + mPolicyMixes[i]->mMix.mCriteria[j].mAttr.mUsage != attributes.usage)) { + desc = mPolicyMixes[i]->mOutput; + break; + } + if (strncmp(attributes.tags, "addr=", strlen("addr=")) == 0 && + strncmp(attributes.tags + strlen("addr="), + mPolicyMixes[i]->mMix.mRegistrationId.string(), + AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - strlen("addr=") - 1) == 0) { + desc = mPolicyMixes[i]->mOutput; + break; + } + } + } else if (mPolicyMixes[i]->mMix.mMixType == MIX_TYPE_RECORDERS) { + if (attributes.usage == AUDIO_USAGE_VIRTUAL_SOURCE && + strncmp(attributes.tags, "addr=", strlen("addr=")) == 0 && + strncmp(attributes.tags + strlen("addr="), + 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; + *stream = streamTypefromAttributesInt(&attributes); + *output = desc->mIoHandle; + ALOGV("getOutputForAttr() returns output %d", *output); + return NO_ERROR; + } + } + if (attributes.usage == AUDIO_USAGE_VIRTUAL_SOURCE) { + ALOGW("getOutputForAttr() no policy mix found for usage AUDIO_USAGE_VIRTUAL_SOURCE"); + return BAD_VALUE; + } + ALOGV("getOutputForAttr() usage=%d, content=%d, tag=%s flags=%08x", attributes.usage, attributes.content_type, attributes.tags, attributes.flags); @@ -1182,7 +1226,14 @@ status_t AudioPolicyManager::startOutput(audio_io_handle_t output, outputDesc->changeRefCount(stream, 1); if (outputDesc->mRefCount[stream] == 1) { - audio_devices_t newDevice = getNewOutputDevice(output, false /*fromCache*/); + // starting an output being rerouted? + audio_devices_t newDevice; + if (outputDesc->mPolicyMixAddress != String8("") + && outputDesc->mPolicyMixAddress != String8("0")) { + newDevice = AUDIO_DEVICE_OUT_REMOTE_SUBMIX; + } else { + newDevice = getNewOutputDevice(output, false /*fromCache*/); + } routing_strategy strategy = getStrategy(stream); bool shouldWait = (strategy == STRATEGY_SONIFICATION) || (strategy == STRATEGY_SONIFICATION_RESPECTFUL) || @@ -1350,57 +1401,66 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr, "session %d, flags %#x", attr->source, samplingRate, format, channelMask, session, flags); - audio_devices_t device = getDeviceForInputSource(attr->source); - - if (device == AUDIO_DEVICE_NONE) { - ALOGW("getInputForAttr() could not find device for source %d", attr->source); - return BAD_VALUE; - } - - // adapt channel selection to input source - switch (attr->source) { - case AUDIO_SOURCE_VOICE_UPLINK: - channelMask = AUDIO_CHANNEL_IN_VOICE_UPLINK; - break; - case AUDIO_SOURCE_VOICE_DOWNLINK: - channelMask = AUDIO_CHANNEL_IN_VOICE_DNLINK; - break; - case AUDIO_SOURCE_VOICE_CALL: - channelMask = AUDIO_CHANNEL_IN_VOICE_UPLINK | AUDIO_CHANNEL_IN_VOICE_DNLINK; - break; - default: - break; - } - *input = AUDIO_IO_HANDLE_NONE; + audio_devices_t device; + // handle legacy remote submix case where the address was not always specified + String8 address = String8(""); bool isSoundTrigger = false; audio_source_t halInputSource = attr->source; - if (attr->source == AUDIO_SOURCE_HOTWORD) { - ssize_t index = mSoundTriggerSessions.indexOfKey(session); - if (index >= 0) { - *input = mSoundTriggerSessions.valueFor(session); - isSoundTrigger = true; - flags = (audio_input_flags_t)(flags | AUDIO_INPUT_FLAG_HW_HOTWORD); - ALOGV("SoundTrigger capture on session %d input %d", session, *input); - } else { - halInputSource = AUDIO_SOURCE_VOICE_RECOGNITION; + + if (attr->source == AUDIO_SOURCE_REMOTE_SUBMIX && + strncmp(attr->tags, "addr=", strlen("addr=")) == 0) { + device = AUDIO_DEVICE_IN_REMOTE_SUBMIX; + address = String8(attr->tags + strlen("addr=")); + ssize_t index = mPolicyMixes.indexOfKey(address); + if (index < 0) { + ALOGW("getInputForAttr() no policy for address %s", address.string()); + return BAD_VALUE; + } + } else { + device = getDeviceForInputSource(attr->source, &address); + + if (device == AUDIO_DEVICE_NONE) { + ALOGW("getInputForAttr() could not find device for source %d", attr->source); + return BAD_VALUE; + } + // adapt channel selection to input source + switch (attr->source) { + case AUDIO_SOURCE_VOICE_UPLINK: + channelMask = AUDIO_CHANNEL_IN_VOICE_UPLINK; + break; + case AUDIO_SOURCE_VOICE_DOWNLINK: + channelMask = AUDIO_CHANNEL_IN_VOICE_DNLINK; + break; + case AUDIO_SOURCE_VOICE_CALL: + channelMask = AUDIO_CHANNEL_IN_VOICE_UPLINK | AUDIO_CHANNEL_IN_VOICE_DNLINK; + break; + default: + break; + } + if (attr->source == AUDIO_SOURCE_HOTWORD) { + ssize_t index = mSoundTriggerSessions.indexOfKey(session); + if (index >= 0) { + *input = mSoundTriggerSessions.valueFor(session); + isSoundTrigger = true; + flags = (audio_input_flags_t)(flags | AUDIO_INPUT_FLAG_HW_HOTWORD); + ALOGV("SoundTrigger capture on session %d input %d", session, *input); + } else { + halInputSource = AUDIO_SOURCE_VOICE_RECOGNITION; + } } } - sp<IOProfile> profile = getInputProfile(device, - samplingRate, - format, - channelMask, - flags); + sp<IOProfile> profile = getInputProfile(device, address, + samplingRate, format, channelMask, + flags); if (profile == 0) { //retry without flags audio_input_flags_t log_flags = flags; flags = AUDIO_INPUT_FLAG_NONE; - profile = getInputProfile(device, - samplingRate, - format, - channelMask, - flags); + profile = getInputProfile(device, address, + samplingRate, format, channelMask, + flags); if (profile == 0) { ALOGW("getInputForAttr() could not find profile for device 0x%X, samplingRate %u," "format %#x, channelMask 0x%X, flags %#x", @@ -1419,9 +1479,6 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr, config.channel_mask = channelMask; config.format = format; - // handle legacy remote submix case where the address was not always specified - String8 address = deviceDistinguishesOnAddress(device) ? String8("0") : String8(""); - status_t status = mpClientInterface->openInput(profile->mModule->mHandle, input, &config, @@ -1451,7 +1508,7 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr, inputDesc->mFormat = format; inputDesc->mChannelMask = channelMask; inputDesc->mDevice = device; - inputDesc->mSessions.add(session); + inputDesc->mSessions.add(session, address); inputDesc->mIsSoundTrigger = isSoundTrigger; addInput(*input, inputDesc); @@ -1470,7 +1527,7 @@ status_t AudioPolicyManager::startInput(audio_io_handle_t input, } sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(index); - index = inputDesc->mSessions.indexOf(session); + index = inputDesc->mSessions.indexOfKey(session); if (index < 0) { ALOGW("startInput() unknown session %d on input %d", session, input); return BAD_VALUE; @@ -1488,8 +1545,8 @@ status_t AudioPolicyManager::startInput(audio_io_handle_t input, sp<AudioInputDescriptor> activeDesc = mInputs.valueFor(activeInput); if (activeDesc->mInputSource == AUDIO_SOURCE_HOTWORD) { ALOGW("startInput(%d) preempting low-priority input %d", input, activeInput); - stopInput(activeInput, activeDesc->mSessions.itemAt(0)); - releaseInput(activeInput, activeDesc->mSessions.itemAt(0)); + stopInput(activeInput, activeDesc->mSessions.keyAt(0)); + releaseInput(activeInput, activeDesc->mSessions.keyAt(0)); } else { ALOGE("startInput(%d) failed: other input %d already started", input, activeInput); return INVALID_OPERATION; @@ -1507,7 +1564,8 @@ status_t AudioPolicyManager::startInput(audio_io_handle_t input, // 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, AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS); + AUDIO_POLICY_DEVICE_STATE_AVAILABLE, + inputDesc->mSessions.valueAt(index)); } } @@ -1528,7 +1586,7 @@ status_t AudioPolicyManager::stopInput(audio_io_handle_t input, } sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(index); - index = inputDesc->mSessions.indexOf(session); + index = inputDesc->mSessions.indexOfKey(session); if (index < 0) { ALOGW("stopInput() unknown session %d on input %d", session, input); return BAD_VALUE; @@ -1545,7 +1603,8 @@ status_t AudioPolicyManager::stopInput(audio_io_handle_t input, // automatically disable the remote submix output when input is stopped if (audio_is_remote_submix_device(inputDesc->mDevice)) { setDeviceConnectionState(AUDIO_DEVICE_OUT_REMOTE_SUBMIX, - AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE, AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS); + AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE, + inputDesc->mSessions.valueAt(index)); } resetInputDevice(input); @@ -1569,12 +1628,12 @@ void AudioPolicyManager::releaseInput(audio_io_handle_t input, sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(index); ALOG_ASSERT(inputDesc != 0); - index = inputDesc->mSessions.indexOf(session); + index = inputDesc->mSessions.indexOfKey(session); if (index < 0) { ALOGW("releaseInput() unknown session %d on input %d", session, input); return; } - inputDesc->mSessions.remove(session); + inputDesc->mSessions.removeItem(session); if (inputDesc->mOpenRefCount == 0) { ALOGW("releaseInput() invalid open ref count %d", inputDesc->mOpenRefCount); return; @@ -1923,6 +1982,117 @@ bool AudioPolicyManager::isSourceActive(audio_source_t source) const return false; } +// Register a list of custom mixes with their attributes and format. +// When a mix is registered, corresponding input and output profiles are +// added to the remote submix hw module. The profile contains only the +// parameters (sampling rate, format...) specified by the mix. +// The corresponding input remote submix device is also connected. +// +// When a remote submix device is connected, the address is checked to select the +// appropriate profile and the corresponding input or output stream is opened. +// +// When capture starts, getInputForAttr() will: +// - 1 look for a mix matching the address passed in attribtutes tags if any +// - 2 if none found, getDeviceForInputSource() will: +// - 2.1 look for a mix matching the attributes source +// - 2.2 if none found, default to device selection by policy rules +// At this time, the corresponding output remote submix device is also connected +// and active playback use cases can be transferred to this mix if needed when reconnecting +// after AudioTracks are invalidated +// +// When playback starts, getOutputForAttr() will: +// - 1 look for a mix matching the address passed in attribtutes tags if any +// - 2 if none found, look for a mix matching the attributes usage +// - 3 if none found, default to device and output selection by policy rules. + +status_t AudioPolicyManager::registerPolicyMixes(Vector<AudioMix> mixes) +{ + sp<HwModule> module; + for (size_t i = 0; i < mHwModules.size(); i++) { + if (strcmp(AUDIO_HARDWARE_MODULE_ID_REMOTE_SUBMIX, mHwModules[i]->mName) == 0 && + mHwModules[i]->mHandle != 0) { + module = mHwModules[i]; + break; + } + } + + if (module == 0) { + return INVALID_OPERATION; + } + + ALOGV("registerPolicyMixes() num mixes %d", mixes.size()); + + for (size_t i = 0; i < mixes.size(); i++) { + String8 address = mixes[i].mRegistrationId; + ssize_t index = mPolicyMixes.indexOfKey(address); + if (index >= 0) { + ALOGE("registerPolicyMixes(): mix for address %s already registered", address.string()); + continue; + } + audio_config_t outputConfig = mixes[i].mFormat; + audio_config_t inputConfig = mixes[i].mFormat; + // NOTE: audio flinger mixer does not support mono output: configure remote submix HAL in + // stereo and let audio flinger do the channel conversion if needed. + outputConfig.channel_mask = AUDIO_CHANNEL_OUT_STEREO; + inputConfig.channel_mask = AUDIO_CHANNEL_IN_STEREO; + module->addOutputProfile(address, &outputConfig, + AUDIO_DEVICE_OUT_REMOTE_SUBMIX, address); + module->addInputProfile(address, &inputConfig, + AUDIO_DEVICE_IN_REMOTE_SUBMIX, address); + sp<AudioPolicyMix> policyMix = new AudioPolicyMix(); + policyMix->mMix = mixes[i]; + mPolicyMixes.add(address, policyMix); + setDeviceConnectionState(AUDIO_DEVICE_IN_REMOTE_SUBMIX, + AUDIO_POLICY_DEVICE_STATE_AVAILABLE, + address.string()); + } + return NO_ERROR; +} + +status_t AudioPolicyManager::unregisterPolicyMixes(Vector<AudioMix> mixes) +{ + sp<HwModule> module; + for (size_t i = 0; i < mHwModules.size(); i++) { + if (strcmp(AUDIO_HARDWARE_MODULE_ID_REMOTE_SUBMIX, mHwModules[i]->mName) == 0 && + mHwModules[i]->mHandle != 0) { + module = mHwModules[i]; + break; + } + } + + if (module == 0) { + return INVALID_OPERATION; + } + + ALOGV("unregisterPolicyMixes() num mixes %d", mixes.size()); + + for (size_t i = 0; i < mixes.size(); i++) { + String8 address = mixes[i].mRegistrationId; + ssize_t index = mPolicyMixes.indexOfKey(address); + if (index < 0) { + ALOGE("unregisterPolicyMixes(): mix for address %s not registered", address.string()); + continue; + } + + mPolicyMixes.removeItemsAt(index); + + 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) + { + setDeviceConnectionState(AUDIO_DEVICE_OUT_REMOTE_SUBMIX, + AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE, + address.string()); + } + module->removeOutputProfile(address); + module->removeInputProfile(address); + } + return NO_ERROR; +} + status_t AudioPolicyManager::dump(int fd) { @@ -2323,6 +2493,7 @@ status_t AudioPolicyManager::createAudioPatch(const struct audio_patch *patch, } if (!outputDesc->mProfile->isCompatibleProfile(devDesc->mDeviceType, + devDesc->mAddress, patch->sources[0].sample_rate, NULL, // updatedSamplingRate patch->sources[0].format, @@ -2377,13 +2548,14 @@ status_t AudioPolicyManager::createAudioPatch(const struct audio_patch *patch, } if (!inputDesc->mProfile->isCompatibleProfile(devDesc->mDeviceType, - patch->sinks[0].sample_rate, - NULL, /*updatedSampleRate*/ - patch->sinks[0].format, - patch->sinks[0].channel_mask, - // FIXME for the parameter type, - // and the NONE - (audio_output_flags_t) + devDesc->mAddress, + patch->sinks[0].sample_rate, + NULL, /*updatedSampleRate*/ + patch->sinks[0].format, + patch->sinks[0].channel_mask, + // FIXME for the parameter type, + // and the NONE + (audio_output_flags_t) AUDIO_INPUT_FLAG_NONE)) { return INVALID_OPERATION; } @@ -3225,9 +3397,13 @@ status_t AudioPolicyManager::checkOutputsForDevice(const sp<DeviceDescriptor> de } for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++) { - if (mHwModules[i]->mOutputProfiles[j]->mSupportedDevices.types() & device) { - ALOGV("checkOutputsForDevice(): adding profile %zu from module %zu", j, i); - profiles.add(mHwModules[i]->mOutputProfiles[j]); + sp<IOProfile> profile = mHwModules[i]->mOutputProfiles[j]; + if (profile->mSupportedDevices.types() & device) { + if (!deviceDistinguishesOnAddress(device) || + address == profile->mSupportedDevices[0]->mAddress) { + profiles.add(profile); + ALOGV("checkOutputsForDevice(): adding profile %zu from module %zu", j, i); + } } } } @@ -3359,6 +3535,15 @@ status_t AudioPolicyManager::checkOutputsForDevice(const sp<DeviceDescriptor> de if (output != AUDIO_IO_HANDLE_NONE) { addOutput(output, desc); + if (deviceDistinguishesOnAddress(device) && address != "0") { + ssize_t index = mPolicyMixes.indexOfKey(address); + if (index >= 0) { + mPolicyMixes[index]->mOutput = desc; + } else { + ALOGE("checkOutputsForDevice() cannot find policy for address %s", + address.string()); + } + } if ((desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) == 0) { audio_io_handle_t duplicatedOutput = AUDIO_IO_HANDLE_NONE; @@ -3422,15 +3607,15 @@ status_t AudioPolicyManager::checkOutputsForDevice(const sp<DeviceDescriptor> de for (size_t i = 0; i < mOutputs.size(); i++) { desc = mOutputs.valueAt(i); if (!desc->isDuplicated()) { - if (!(desc->mProfile->mSupportedDevices.types() + // exact match on device + if (deviceDistinguishesOnAddress(device) && + (desc->mProfile->mSupportedDevices.types() == device)) { + findIoHandlesByAddress(desc, address, outputs); + } else if (!(desc->mProfile->mSupportedDevices.types() & mAvailableOutputDevices.types())) { ALOGV("checkOutputsForDevice(): disconnecting adding output %d", mOutputs.keyAt(i)); outputs.add(mOutputs.keyAt(i)); - } else if (deviceDistinguishesOnAddress(device) && - // exact match on device - (desc->mProfile->mSupportedDevices.types() == device)) { - findIoHandlesByAddress(desc, address, outputs); } } } @@ -3492,11 +3677,15 @@ status_t AudioPolicyManager::checkInputsForDevice(audio_devices_t device, profile_index < mHwModules[module_idx]->mInputProfiles.size(); profile_index++) { - if (mHwModules[module_idx]->mInputProfiles[profile_index]->mSupportedDevices.types() - & (device & ~AUDIO_DEVICE_BIT_IN)) { - ALOGV("checkInputsForDevice(): adding profile %zu from module %zu", - profile_index, module_idx); - profiles.add(mHwModules[module_idx]->mInputProfiles[profile_index]); + sp<IOProfile> profile = mHwModules[module_idx]->mInputProfiles[profile_index]; + + if (profile->mSupportedDevices.types() & (device & ~AUDIO_DEVICE_BIT_IN)) { + if (!deviceDistinguishesOnAddress(device) || + address == profile->mSupportedDevices[0]->mAddress) { + profiles.add(profile); + ALOGV("checkInputsForDevice(): adding profile %zu from module %zu", + profile_index, module_idx); + } } } } @@ -3664,6 +3853,12 @@ void AudioPolicyManager::closeOutput(audio_io_handle_t output) return; } + for (size_t i = 0; i < mPolicyMixes.size(); i++) { + if (mPolicyMixes[i]->mOutput == outputDesc) { + mPolicyMixes[i]->mOutput.clear(); + } + } + // look for duplicated outputs connected to the output being removed. for (size_t i = 0; i < mOutputs.size(); i++) { sp<AudioOutputDescriptor> dupOutputDesc = mOutputs.valueAt(i); @@ -4373,7 +4568,9 @@ audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strate uint32_t device2 = AUDIO_DEVICE_NONE; if (strategy != STRATEGY_SONIFICATION) { // no sonification on remote submix (e.g. WFD) - device2 = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_REMOTE_SUBMIX; + if (mAvailableOutputDevices.getDevice(AUDIO_DEVICE_OUT_REMOTE_SUBMIX, String8("0")) != 0) { + device2 = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_REMOTE_SUBMIX; + } } if ((device2 == AUDIO_DEVICE_NONE) && (mForceUse[AUDIO_POLICY_FORCE_FOR_MEDIA] != AUDIO_POLICY_FORCE_NO_BT_A2DP) && @@ -4783,6 +4980,7 @@ status_t AudioPolicyManager::resetInputDevice(audio_io_handle_t input, } sp<AudioPolicyManager::IOProfile> AudioPolicyManager::getInputProfile(audio_devices_t device, + String8 address, uint32_t& samplingRate, audio_format_t format, audio_channel_mask_t channelMask, @@ -4800,9 +4998,10 @@ sp<AudioPolicyManager::IOProfile> AudioPolicyManager::getInputProfile(audio_devi { sp<IOProfile> profile = mHwModules[i]->mInputProfiles[j]; // profile->log(); - if (profile->isCompatibleProfile(device, samplingRate, + if (profile->isCompatibleProfile(device, address, samplingRate, &samplingRate /*updatedSamplingRate*/, format, channelMask, (audio_output_flags_t) flags)) { + return profile; } } @@ -4810,11 +5009,33 @@ sp<AudioPolicyManager::IOProfile> AudioPolicyManager::getInputProfile(audio_devi return NULL; } -audio_devices_t AudioPolicyManager::getDeviceForInputSource(audio_source_t inputSource) +audio_devices_t AudioPolicyManager::getDeviceForInputSource(audio_source_t inputSource, + String8 *address) { uint32_t device = AUDIO_DEVICE_NONE; audio_devices_t availableDeviceTypes = mAvailableInputDevices.types() & ~AUDIO_DEVICE_BIT_IN; + + for (size_t i = 0; i < mPolicyMixes.size(); i++) { + if (mPolicyMixes[i]->mMix.mMixType != MIX_TYPE_RECORDERS) { + continue; + } + for (size_t j = 0; j < mPolicyMixes[i]->mMix.mCriteria.size(); j++) { + if ((RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET == mPolicyMixes[i]->mMix.mCriteria[j].mRule && + mPolicyMixes[i]->mMix.mCriteria[j].mAttr.mSource == inputSource) || + (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; + } + return AUDIO_DEVICE_IN_REMOTE_SUBMIX; + } + break; + } + } + } + switch (inputSource) { case AUDIO_SOURCE_VOICE_UPLINK: if (availableDeviceTypes & AUDIO_DEVICE_IN_VOICE_CALL) { @@ -4902,6 +5123,9 @@ 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: @@ -4928,7 +5152,7 @@ bool AudioPolicyManager::isVirtualInputDevice(audio_devices_t device) } bool AudioPolicyManager::deviceDistinguishesOnAddress(audio_devices_t device) { - return ((device & APM_AUDIO_DEVICE_MATCH_ADDRESS_ALL) != 0); + return ((device & APM_AUDIO_DEVICE_MATCH_ADDRESS_ALL & ~AUDIO_DEVICE_BIT_IN) != 0); } audio_io_handle_t AudioPolicyManager::getActiveInput(bool ignoreVirtualInputs) @@ -5338,6 +5562,19 @@ status_t AudioPolicyManager::checkAndSetVolume(audio_stream_type_t stream, } float volume = computeVolume(stream, index, output, device); + // unit gain if rerouting to external policy + if (device == AUDIO_DEVICE_OUT_REMOTE_SUBMIX) { + ssize_t index = mOutputs.indexOfKey(output); + if (index >= 0) { + sp<AudioOutputDescriptor> outputDesc = mOutputs.valueAt(index); + if (outputDesc->mPolicyMixAddress != String8("") + && outputDesc->mPolicyMixAddress != String8("0")) { + ALOGV("max gain when rerouting for output=%d", output); + volume = 1.0f; + } + } + + } // We actually change the volume if: // - the float value returned by computeVolume() changed // - the force flag is set @@ -5520,7 +5757,8 @@ uint32_t AudioPolicyManager::getMaxEffectsMemory() AudioPolicyManager::AudioOutputDescriptor::AudioOutputDescriptor( const sp<IOProfile>& profile) : mId(0), mIoHandle(0), mLatency(0), - mFlags((audio_output_flags_t)0), mDevice(AUDIO_DEVICE_NONE), mPatchHandle(0), + mFlags((audio_output_flags_t)0), mDevice(AUDIO_DEVICE_NONE), mPolicyMixAddress(String8("")), + mPatchHandle(0), mOutput1(0), mOutput2(0), mProfile(profile), mDirectOpenCount(0) { // clear usage count for all stream types @@ -6005,6 +6243,69 @@ status_t AudioPolicyManager::HwModule::loadDevice(cnode *root) return NO_ERROR; } +status_t AudioPolicyManager::HwModule::addOutputProfile(String8 name, const audio_config_t *config, + audio_devices_t device, String8 address) +{ + sp<IOProfile> profile = new IOProfile(name, AUDIO_PORT_ROLE_SOURCE, this); + + profile->mSamplingRates.add(config->sample_rate); + profile->mChannelMasks.add(config->channel_mask); + profile->mFormats.add(config->format); + + sp<DeviceDescriptor> devDesc = new DeviceDescriptor(String8(""), device); + devDesc->mAddress = address; + profile->mSupportedDevices.add(devDesc); + + mOutputProfiles.add(profile); + + return NO_ERROR; +} + +status_t AudioPolicyManager::HwModule::removeOutputProfile(String8 name) +{ + for (size_t i = 0; i < mOutputProfiles.size(); i++) { + if (mOutputProfiles[i]->mName == name) { + mOutputProfiles.removeAt(i); + break; + } + } + + return NO_ERROR; +} + +status_t AudioPolicyManager::HwModule::addInputProfile(String8 name, const audio_config_t *config, + audio_devices_t device, String8 address) +{ + sp<IOProfile> profile = new IOProfile(name, AUDIO_PORT_ROLE_SINK, this); + + profile->mSamplingRates.add(config->sample_rate); + profile->mChannelMasks.add(config->channel_mask); + profile->mFormats.add(config->format); + + sp<DeviceDescriptor> devDesc = new DeviceDescriptor(String8(""), device); + devDesc->mAddress = address; + profile->mSupportedDevices.add(devDesc); + + ALOGV("addInputProfile() name %s rate %d mask 0x08", name.string(), config->sample_rate, config->channel_mask); + + mInputProfiles.add(profile); + + return NO_ERROR; +} + +status_t AudioPolicyManager::HwModule::removeInputProfile(String8 name) +{ + for (size_t i = 0; i < mInputProfiles.size(); i++) { + if (mInputProfiles[i]->mName == name) { + mInputProfiles.removeAt(i); + break; + } + } + + return NO_ERROR; +} + + void AudioPolicyManager::HwModule::dump(int fd) { const size_t SIZE = 256; @@ -6911,17 +7212,18 @@ AudioPolicyManager::IOProfile::~IOProfile() // Sampling rate, format and channel mask must be specified in order to // get a valid a match bool AudioPolicyManager::IOProfile::isCompatibleProfile(audio_devices_t device, - uint32_t samplingRate, - uint32_t *updatedSamplingRate, - audio_format_t format, - audio_channel_mask_t channelMask, - uint32_t flags) const + String8 address, + uint32_t samplingRate, + uint32_t *updatedSamplingRate, + audio_format_t format, + audio_channel_mask_t channelMask, + uint32_t flags) const { const bool isPlaybackThread = mType == AUDIO_PORT_TYPE_MIX && mRole == AUDIO_PORT_ROLE_SOURCE; const bool isRecordThread = mType == AUDIO_PORT_TYPE_MIX && mRole == AUDIO_PORT_ROLE_SINK; ALOG_ASSERT(isPlaybackThread != isRecordThread); - if ((mSupportedDevices.types() & device) != device) { + if (device != AUDIO_DEVICE_NONE && mSupportedDevices.getDevice(device, address) == 0) { return false; } @@ -7116,7 +7418,8 @@ void AudioPolicyManager::DeviceVector::loadDevicesFromName(char *name, devName); if (type != AUDIO_DEVICE_NONE) { sp<DeviceDescriptor> dev = new DeviceDescriptor(String8(""), type); - if (type == AUDIO_DEVICE_IN_REMOTE_SUBMIX) { + if (type == AUDIO_DEVICE_IN_REMOTE_SUBMIX || + type == AUDIO_DEVICE_OUT_REMOTE_SUBMIX ) { dev->mAddress = String8("0"); } add(dev); @@ -7128,7 +7431,7 @@ void AudioPolicyManager::DeviceVector::loadDevicesFromName(char *name, } } } - devName = strtok(NULL, "|"); + devName = strtok(NULL, "|"); } } @@ -7138,13 +7441,15 @@ sp<AudioPolicyManager::DeviceDescriptor> AudioPolicyManager::DeviceVector::getDe sp<DeviceDescriptor> device; for (size_t i = 0; i < size(); i++) { if (itemAt(i)->mDeviceType == type) { - device = itemAt(i); - if (itemAt(i)->mAddress = address) { - break; + if (address == "" || itemAt(i)->mAddress == address) { + device = itemAt(i); + if (itemAt(i)->mAddress == address) { + break; + } } } } - ALOGV("DeviceVector::getDevice() for type %d address %s found %p", + ALOGV("DeviceVector::getDevice() for type %08x address %s found %p", type, address.string(), device.get()); return device; } @@ -7182,13 +7487,9 @@ AudioPolicyManager::DeviceVector AudioPolicyManager::DeviceVector::getDevicesFro audio_devices_t type, String8 address) const { DeviceVector devices; - //ALOGV(" looking for device=%x, addr=%s", type, address.string()); for (size_t i = 0; i < size(); i++) { - //ALOGV(" at i=%d: device=%x, addr=%s", - // i, itemAt(i)->mDeviceType, itemAt(i)->mAddress.string()); if (itemAt(i)->mDeviceType == type) { if (itemAt(i)->mAddress == address) { - //ALOGV(" found matching address %s", address.string()); devices.add(itemAt(i)); } } @@ -7616,6 +7917,7 @@ bool AudioPolicyManager::isValidAttributes(const audio_attributes_t *paa) { case AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE: case AUDIO_USAGE_ASSISTANCE_SONIFICATION: case AUDIO_USAGE_GAME: + case AUDIO_USAGE_VIRTUAL_SOURCE: break; default: return false; diff --git a/services/audiopolicy/AudioPolicyManager.h b/services/audiopolicy/AudioPolicyManager.h index 17348e9..4214131 100644 --- a/services/audiopolicy/AudioPolicyManager.h +++ b/services/audiopolicy/AudioPolicyManager.h @@ -23,6 +23,7 @@ #include <utils/Errors.h> #include <utils/KeyedVector.h> #include <utils/SortedVector.h> +#include <media/AudioPolicy.h> #include "AudioPolicyInterface.h" @@ -184,6 +185,9 @@ public: virtual status_t releaseSoundTriggerSession(audio_session_t session); + virtual status_t registerPolicyMixes(Vector<AudioMix> mixes); + virtual status_t unregisterPolicyMixes(Vector<AudioMix> mixes); + protected: enum routing_strategy { @@ -392,6 +396,7 @@ protected: // For input, flags is interpreted as audio_input_flags_t. // TODO: merge audio_output_flags_t and audio_input_flags_t. bool isCompatibleProfile(audio_devices_t device, + String8 address, uint32_t samplingRate, uint32_t *updatedSamplingRate, audio_format_t format, @@ -415,6 +420,13 @@ protected: status_t loadInput(cnode *root); status_t loadDevice(cnode *root); + status_t addOutputProfile(String8 name, const audio_config_t *config, + audio_devices_t device, String8 address); + status_t removeOutputProfile(String8 name); + status_t addInputProfile(String8 name, const audio_config_t *config, + audio_devices_t device, String8 address); + status_t removeInputProfile(String8 name); + void dump(int fd); const char *const mName; // base name of the audio HW module (primary, a2dp ...) @@ -483,6 +495,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 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]; @@ -515,7 +528,9 @@ protected: audio_source_t mInputSource; // input source selected by application //(mediarecorder.h) const sp<IOProfile> mProfile; // I/O profile this output derives from - SortedVector<audio_session_t> mSessions; // audio sessions attached to this input + // audio sessions attached to this input and the + // corresponding device address + DefaultKeyedVector<audio_session_t, String8> mSessions; bool mIsSoundTrigger; // used by a soundtrigger capture virtual void toAudioPortConfig(struct audio_port_config *dstConfig, @@ -594,7 +609,8 @@ protected: audio_patch_handle_t *patchHandle = NULL); // select input device corresponding to requested audio source - virtual audio_devices_t getDeviceForInputSource(audio_source_t inputSource); + virtual audio_devices_t getDeviceForInputSource(audio_source_t inputSource, + String8 *address = 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 @@ -731,10 +747,11 @@ protected: audio_format_t format); // samplingRate parameter is an in/out and so may be modified sp<IOProfile> getInputProfile(audio_devices_t device, - uint32_t& samplingRate, - audio_format_t format, - audio_channel_mask_t channelMask, - audio_input_flags_t flags); + String8 address, + uint32_t& samplingRate, + audio_format_t format, + audio_channel_mask_t channelMask, + audio_input_flags_t flags); sp<IOProfile> getProfileForDirectOutput(audio_devices_t device, uint32_t samplingRate, audio_format_t format, @@ -832,6 +849,17 @@ protected: uint32_t mBeaconPlayingRefCount;// ref count for the playing beacon streams bool mBeaconMuted; // has STREAM_TTS been muted + // custom mix entry in mPolicyMixes + class AudioPolicyMix : public RefBase { + public: + AudioPolicyMix() {} + + AudioMix mMix; // Audio policy mix descriptor + sp<AudioOutputDescriptor> mOutput; // Corresponding output stream + }; + DefaultKeyedVector<String8, sp<AudioPolicyMix> > mPolicyMixes; // list of registered mixes + + #ifdef AUDIO_POLICY_TEST Mutex mLock; Condition mWaitWorkCV; |