Loading include/media/AudioPolicy.h +12 −9 Original line number Diff line number Diff line Loading @@ -30,9 +30,11 @@ namespace android { #define RULE_EXCLUSION_MASK 0x8000 #define RULE_MATCH_ATTRIBUTE_USAGE 0x1 #define RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET (0x1 << 1) #define RULE_MATCH_UID (0x1 << 2) #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 RULE_EXCLUDE_UID (RULE_EXCLUSION_MASK|RULE_MATCH_UID) #define MIX_TYPE_INVALID -1 #define MIX_TYPE_PLAYERS 0 Loading @@ -53,10 +55,10 @@ namespace android { #define MAX_MIXES_PER_POLICY 10 #define MAX_CRITERIA_PER_MIX 20 class AttributeMatchCriterion { class AudioMixMatchCriterion { public: AttributeMatchCriterion() {} AttributeMatchCriterion(audio_usage_t usage, audio_source_t source, uint32_t rule); AudioMixMatchCriterion() {} AudioMixMatchCriterion(audio_usage_t usage, audio_source_t source, uint32_t rule); status_t readFromParcel(Parcel *parcel); status_t writeToParcel(Parcel *parcel) const; Loading @@ -64,7 +66,8 @@ public: union { audio_usage_t mUsage; audio_source_t mSource; } mAttr; uid_t mUid; } mValue; uint32_t mRule; }; Loading @@ -75,7 +78,7 @@ public: static const uint32_t kCbFlagNotifyActivity = 0x1; AudioMix() {} AudioMix(Vector<AttributeMatchCriterion> criteria, uint32_t mixType, audio_config_t format, AudioMix(Vector<AudioMixMatchCriterion> criteria, uint32_t mixType, audio_config_t format, uint32_t routeFlags, String8 registrationId, uint32_t flags) : mCriteria(criteria), mMixType(mixType), mFormat(format), mRouteFlags(routeFlags), mRegistrationId(registrationId), mCbFlags(flags){} Loading @@ -83,7 +86,7 @@ public: status_t readFromParcel(Parcel *parcel); status_t writeToParcel(Parcel *parcel) const; Vector<AttributeMatchCriterion> mCriteria; Vector<AudioMixMatchCriterion> mCriteria; uint32_t mMixType; audio_config_t mFormat; uint32_t mRouteFlags; Loading media/libmedia/AudioPolicy.cpp +10 −10 Original line number Diff line number Diff line Loading @@ -22,37 +22,37 @@ namespace android { // // AttributeMatchCriterion implementation // AudioMixMatchCriterion implementation // AttributeMatchCriterion::AttributeMatchCriterion(audio_usage_t usage, AudioMixMatchCriterion::AudioMixMatchCriterion(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; mValue.mUsage = usage; } else { mAttr.mSource = source; mValue.mSource = source; } } status_t AttributeMatchCriterion::readFromParcel(Parcel *parcel) status_t AudioMixMatchCriterion::readFromParcel(Parcel *parcel) { mRule = parcel->readInt32(); if (mRule == RULE_MATCH_ATTRIBUTE_USAGE || mRule == RULE_EXCLUDE_ATTRIBUTE_USAGE) { mAttr.mUsage = (audio_usage_t)parcel->readInt32(); mValue.mUsage = (audio_usage_t)parcel->readInt32(); } else { mAttr.mSource = (audio_source_t)parcel->readInt32(); mValue.mSource = (audio_source_t)parcel->readInt32(); } return NO_ERROR; } status_t AttributeMatchCriterion::writeToParcel(Parcel *parcel) const status_t AudioMixMatchCriterion::writeToParcel(Parcel *parcel) const { parcel->writeInt32(mRule); parcel->writeInt32(mAttr.mUsage); parcel->writeInt32(mValue.mUsage); return NO_ERROR; } Loading @@ -74,7 +74,7 @@ status_t AudioMix::readFromParcel(Parcel *parcel) size = MAX_CRITERIA_PER_MIX; } for (size_t i = 0; i < size; i++) { AttributeMatchCriterion criterion; AudioMixMatchCriterion criterion; if (criterion.readFromParcel(parcel) == NO_ERROR) { mCriteria.add(criterion); } Loading services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h +2 −1 Original line number Diff line number Diff line Loading @@ -69,7 +69,8 @@ public: * @return NO_ERROR if an output was found for the given attribute (in this case, the * descriptor output param is initialized), error code otherwise. */ status_t getOutputForAttr(audio_attributes_t attributes, sp<SwAudioOutputDescriptor> &desc); status_t getOutputForAttr(audio_attributes_t attributes, uid_t uid, sp<SwAudioOutputDescriptor> &desc); audio_devices_t getDeviceAndMixForInputSource(audio_source_t inputSource, audio_devices_t availableDeviceTypes, Loading services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp +101 −11 Original line number Diff line number Diff line Loading @@ -98,30 +98,111 @@ void AudioPolicyMixCollection::closeOutput(sp<SwAudioOutputDescriptor> &desc) } } status_t AudioPolicyMixCollection::getOutputForAttr(audio_attributes_t attributes, status_t AudioPolicyMixCollection::getOutputForAttr(audio_attributes_t attributes, uid_t uid, sp<SwAudioOutputDescriptor> &desc) { desc = 0; for (size_t i = 0; i < size(); i++) { sp<AudioPolicyMix> policyMix = valueAt(i); AudioMix *mix = policyMix->getMix(); if (mix->mMixType == MIX_TYPE_PLAYERS) { // TODO if adding more player rules (currently only 2), make rule handling "generic" // as there is no difference in the treatment of usage- or uid-based rules bool hasUsageMatchRules = false; bool hasUsageExcludeRules = false; bool usageMatchFound = false; bool usageExclusionFound = false; bool hasUidMatchRules = false; bool hasUidExcludeRules = false; bool uidMatchFound = false; bool uidExclusionFound = false; bool hasAddrMatch = false; // iterate over all mix criteria to list what rules this mix contains for (size_t j = 0; j < mix->mCriteria.size(); j++) { if ((RULE_MATCH_ATTRIBUTE_USAGE == mix->mCriteria[j].mRule && mix->mCriteria[j].mAttr.mUsage == attributes.usage) || (RULE_EXCLUDE_ATTRIBUTE_USAGE == mix->mCriteria[j].mRule && mix->mCriteria[j].mAttr.mUsage != attributes.usage)) { desc = policyMix->getOutput(); break; } ALOGV("getOutputForAttr: inspecting mix %zu of %zu", i, mix->mCriteria.size()); // if there is an address match, prioritize that match if (strncmp(attributes.tags, "addr=", strlen("addr=")) == 0 && strncmp(attributes.tags + strlen("addr="), mix->mRegistrationId.string(), AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - strlen("addr=") - 1) == 0) { desc = policyMix->getOutput(); hasAddrMatch = true; break; } switch (mix->mCriteria[j].mRule) { case RULE_MATCH_ATTRIBUTE_USAGE: ALOGV("\tmix has RULE_MATCH_ATTRIBUTE_USAGE for usage %d", mix->mCriteria[j].mValue.mUsage); hasUsageMatchRules = true; if (mix->mCriteria[j].mValue.mUsage == attributes.usage) { // found one match against all allowed usages usageMatchFound = true; } break; case RULE_EXCLUDE_ATTRIBUTE_USAGE: ALOGV("\tmix has RULE_EXCLUDE_ATTRIBUTE_USAGE for usage %d", mix->mCriteria[j].mValue.mUsage); hasUsageExcludeRules = true; if (mix->mCriteria[j].mValue.mUsage == attributes.usage) { // found this usage is to be excluded usageExclusionFound = true; } break; case RULE_MATCH_UID: ALOGV("\tmix has RULE_MATCH_UID for uid %d", mix->mCriteria[j].mValue.mUid); hasUidMatchRules = true; if (mix->mCriteria[j].mValue.mUid == uid) { // found one UID match against all allowed UIDs uidMatchFound = true; } break; case RULE_EXCLUDE_UID: ALOGV("\tmix has RULE_EXCLUDE_UID for uid %d", mix->mCriteria[j].mValue.mUid); hasUidExcludeRules = true; if (mix->mCriteria[j].mValue.mUid == uid) { // found this UID is to be excluded uidExclusionFound = true; } break; default: break; } // consistency checks: for each "dimension" of rules (usage, uid...), we can // only have MATCH rules, or EXCLUDE rules in each dimension, not a combination if (hasUsageMatchRules && hasUsageExcludeRules) { ALOGE("getOutputForAttr: invalid combination of RULE_MATCH_ATTRIBUTE_USAGE" " and RULE_EXCLUDE_ATTRIBUTE_USAGE in mix %zu", i); return BAD_VALUE; } if (hasUidMatchRules && hasUidExcludeRules) { ALOGE("getOutputForAttr: invalid combination of RULE_MATCH_UID" " and RULE_EXCLUDE_UID in mix %zu", i); return BAD_VALUE; } if ((hasUsageExcludeRules && usageExclusionFound) || (hasUidExcludeRules && uidExclusionFound)) { break; // stop iterating on criteria because an exclusion was found (will fail) } }//iterate on mix criteria // determine if exiting on success (or implicit failure as desc is 0) if (hasAddrMatch || !((hasUsageExcludeRules && usageExclusionFound) || (hasUsageMatchRules && !usageMatchFound) || (hasUidExcludeRules && uidExclusionFound) || (hasUidMatchRules && !uidMatchFound))) { ALOGV("\tgetOutputForAttr will use mix %zu", i); desc = policyMix->getOutput(); } } else if (mix->mMixType == MIX_TYPE_RECORDERS) { if (attributes.usage == AUDIO_USAGE_VIRTUAL_SOURCE && strncmp(attributes.tags, "addr=", strlen("addr=")) == 0 && Loading Loading @@ -151,9 +232,9 @@ audio_devices_t AudioPolicyMixCollection::getDeviceAndMixForInputSource(audio_so } for (size_t j = 0; j < mix->mCriteria.size(); j++) { if ((RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET == mix->mCriteria[j].mRule && mix->mCriteria[j].mAttr.mSource == inputSource) || mix->mCriteria[j].mValue.mSource == inputSource) || (RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET == mix->mCriteria[j].mRule && mix->mCriteria[j].mAttr.mSource != inputSource)) { mix->mCriteria[j].mValue.mSource != inputSource)) { if (availDevices & AUDIO_DEVICE_IN_REMOTE_SUBMIX) { if (policyMix != NULL) { *policyMix = mix; Loading @@ -174,6 +255,15 @@ status_t AudioPolicyMixCollection::getInputMixForAttr(audio_attributes_t attr, A } String8 address(attr.tags + strlen("addr=")); #ifdef LOG_NDEBUG ALOGV("getInputMixForAttr looking for address %s\n mixes available:", address.string()); for (size_t i = 0; i < size(); i++) { sp<AudioPolicyMix> policyMix = valueAt(i); AudioMix *mix = policyMix->getMix(); ALOGV("\tmix %zu address=%s", i, mix->mRegistrationId.string()); } #endif ssize_t index = indexOfKey(address); if (index < 0) { ALOGW("getInputMixForAttr() no policy for address %s", address.string()); Loading services/audiopolicy/managerdefault/AudioPolicyManager.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -709,7 +709,7 @@ status_t AudioPolicyManager::getOutputForAttr(const audio_attributes_t *attr, stream_type_to_audio_attributes(*stream, &attributes); } sp<SwAudioOutputDescriptor> desc; if (mPolicyMixes.getOutputForAttr(attributes, desc) == NO_ERROR) { if (mPolicyMixes.getOutputForAttr(attributes, uid, desc) == NO_ERROR) { ALOG_ASSERT(desc != 0, "Invalid desc returned by getOutputForAttr"); if (!audio_is_linear_pcm(format)) { return BAD_VALUE; Loading Loading
include/media/AudioPolicy.h +12 −9 Original line number Diff line number Diff line Loading @@ -30,9 +30,11 @@ namespace android { #define RULE_EXCLUSION_MASK 0x8000 #define RULE_MATCH_ATTRIBUTE_USAGE 0x1 #define RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET (0x1 << 1) #define RULE_MATCH_UID (0x1 << 2) #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 RULE_EXCLUDE_UID (RULE_EXCLUSION_MASK|RULE_MATCH_UID) #define MIX_TYPE_INVALID -1 #define MIX_TYPE_PLAYERS 0 Loading @@ -53,10 +55,10 @@ namespace android { #define MAX_MIXES_PER_POLICY 10 #define MAX_CRITERIA_PER_MIX 20 class AttributeMatchCriterion { class AudioMixMatchCriterion { public: AttributeMatchCriterion() {} AttributeMatchCriterion(audio_usage_t usage, audio_source_t source, uint32_t rule); AudioMixMatchCriterion() {} AudioMixMatchCriterion(audio_usage_t usage, audio_source_t source, uint32_t rule); status_t readFromParcel(Parcel *parcel); status_t writeToParcel(Parcel *parcel) const; Loading @@ -64,7 +66,8 @@ public: union { audio_usage_t mUsage; audio_source_t mSource; } mAttr; uid_t mUid; } mValue; uint32_t mRule; }; Loading @@ -75,7 +78,7 @@ public: static const uint32_t kCbFlagNotifyActivity = 0x1; AudioMix() {} AudioMix(Vector<AttributeMatchCriterion> criteria, uint32_t mixType, audio_config_t format, AudioMix(Vector<AudioMixMatchCriterion> criteria, uint32_t mixType, audio_config_t format, uint32_t routeFlags, String8 registrationId, uint32_t flags) : mCriteria(criteria), mMixType(mixType), mFormat(format), mRouteFlags(routeFlags), mRegistrationId(registrationId), mCbFlags(flags){} Loading @@ -83,7 +86,7 @@ public: status_t readFromParcel(Parcel *parcel); status_t writeToParcel(Parcel *parcel) const; Vector<AttributeMatchCriterion> mCriteria; Vector<AudioMixMatchCriterion> mCriteria; uint32_t mMixType; audio_config_t mFormat; uint32_t mRouteFlags; Loading
media/libmedia/AudioPolicy.cpp +10 −10 Original line number Diff line number Diff line Loading @@ -22,37 +22,37 @@ namespace android { // // AttributeMatchCriterion implementation // AudioMixMatchCriterion implementation // AttributeMatchCriterion::AttributeMatchCriterion(audio_usage_t usage, AudioMixMatchCriterion::AudioMixMatchCriterion(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; mValue.mUsage = usage; } else { mAttr.mSource = source; mValue.mSource = source; } } status_t AttributeMatchCriterion::readFromParcel(Parcel *parcel) status_t AudioMixMatchCriterion::readFromParcel(Parcel *parcel) { mRule = parcel->readInt32(); if (mRule == RULE_MATCH_ATTRIBUTE_USAGE || mRule == RULE_EXCLUDE_ATTRIBUTE_USAGE) { mAttr.mUsage = (audio_usage_t)parcel->readInt32(); mValue.mUsage = (audio_usage_t)parcel->readInt32(); } else { mAttr.mSource = (audio_source_t)parcel->readInt32(); mValue.mSource = (audio_source_t)parcel->readInt32(); } return NO_ERROR; } status_t AttributeMatchCriterion::writeToParcel(Parcel *parcel) const status_t AudioMixMatchCriterion::writeToParcel(Parcel *parcel) const { parcel->writeInt32(mRule); parcel->writeInt32(mAttr.mUsage); parcel->writeInt32(mValue.mUsage); return NO_ERROR; } Loading @@ -74,7 +74,7 @@ status_t AudioMix::readFromParcel(Parcel *parcel) size = MAX_CRITERIA_PER_MIX; } for (size_t i = 0; i < size; i++) { AttributeMatchCriterion criterion; AudioMixMatchCriterion criterion; if (criterion.readFromParcel(parcel) == NO_ERROR) { mCriteria.add(criterion); } Loading
services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h +2 −1 Original line number Diff line number Diff line Loading @@ -69,7 +69,8 @@ public: * @return NO_ERROR if an output was found for the given attribute (in this case, the * descriptor output param is initialized), error code otherwise. */ status_t getOutputForAttr(audio_attributes_t attributes, sp<SwAudioOutputDescriptor> &desc); status_t getOutputForAttr(audio_attributes_t attributes, uid_t uid, sp<SwAudioOutputDescriptor> &desc); audio_devices_t getDeviceAndMixForInputSource(audio_source_t inputSource, audio_devices_t availableDeviceTypes, Loading
services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp +101 −11 Original line number Diff line number Diff line Loading @@ -98,30 +98,111 @@ void AudioPolicyMixCollection::closeOutput(sp<SwAudioOutputDescriptor> &desc) } } status_t AudioPolicyMixCollection::getOutputForAttr(audio_attributes_t attributes, status_t AudioPolicyMixCollection::getOutputForAttr(audio_attributes_t attributes, uid_t uid, sp<SwAudioOutputDescriptor> &desc) { desc = 0; for (size_t i = 0; i < size(); i++) { sp<AudioPolicyMix> policyMix = valueAt(i); AudioMix *mix = policyMix->getMix(); if (mix->mMixType == MIX_TYPE_PLAYERS) { // TODO if adding more player rules (currently only 2), make rule handling "generic" // as there is no difference in the treatment of usage- or uid-based rules bool hasUsageMatchRules = false; bool hasUsageExcludeRules = false; bool usageMatchFound = false; bool usageExclusionFound = false; bool hasUidMatchRules = false; bool hasUidExcludeRules = false; bool uidMatchFound = false; bool uidExclusionFound = false; bool hasAddrMatch = false; // iterate over all mix criteria to list what rules this mix contains for (size_t j = 0; j < mix->mCriteria.size(); j++) { if ((RULE_MATCH_ATTRIBUTE_USAGE == mix->mCriteria[j].mRule && mix->mCriteria[j].mAttr.mUsage == attributes.usage) || (RULE_EXCLUDE_ATTRIBUTE_USAGE == mix->mCriteria[j].mRule && mix->mCriteria[j].mAttr.mUsage != attributes.usage)) { desc = policyMix->getOutput(); break; } ALOGV("getOutputForAttr: inspecting mix %zu of %zu", i, mix->mCriteria.size()); // if there is an address match, prioritize that match if (strncmp(attributes.tags, "addr=", strlen("addr=")) == 0 && strncmp(attributes.tags + strlen("addr="), mix->mRegistrationId.string(), AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - strlen("addr=") - 1) == 0) { desc = policyMix->getOutput(); hasAddrMatch = true; break; } switch (mix->mCriteria[j].mRule) { case RULE_MATCH_ATTRIBUTE_USAGE: ALOGV("\tmix has RULE_MATCH_ATTRIBUTE_USAGE for usage %d", mix->mCriteria[j].mValue.mUsage); hasUsageMatchRules = true; if (mix->mCriteria[j].mValue.mUsage == attributes.usage) { // found one match against all allowed usages usageMatchFound = true; } break; case RULE_EXCLUDE_ATTRIBUTE_USAGE: ALOGV("\tmix has RULE_EXCLUDE_ATTRIBUTE_USAGE for usage %d", mix->mCriteria[j].mValue.mUsage); hasUsageExcludeRules = true; if (mix->mCriteria[j].mValue.mUsage == attributes.usage) { // found this usage is to be excluded usageExclusionFound = true; } break; case RULE_MATCH_UID: ALOGV("\tmix has RULE_MATCH_UID for uid %d", mix->mCriteria[j].mValue.mUid); hasUidMatchRules = true; if (mix->mCriteria[j].mValue.mUid == uid) { // found one UID match against all allowed UIDs uidMatchFound = true; } break; case RULE_EXCLUDE_UID: ALOGV("\tmix has RULE_EXCLUDE_UID for uid %d", mix->mCriteria[j].mValue.mUid); hasUidExcludeRules = true; if (mix->mCriteria[j].mValue.mUid == uid) { // found this UID is to be excluded uidExclusionFound = true; } break; default: break; } // consistency checks: for each "dimension" of rules (usage, uid...), we can // only have MATCH rules, or EXCLUDE rules in each dimension, not a combination if (hasUsageMatchRules && hasUsageExcludeRules) { ALOGE("getOutputForAttr: invalid combination of RULE_MATCH_ATTRIBUTE_USAGE" " and RULE_EXCLUDE_ATTRIBUTE_USAGE in mix %zu", i); return BAD_VALUE; } if (hasUidMatchRules && hasUidExcludeRules) { ALOGE("getOutputForAttr: invalid combination of RULE_MATCH_UID" " and RULE_EXCLUDE_UID in mix %zu", i); return BAD_VALUE; } if ((hasUsageExcludeRules && usageExclusionFound) || (hasUidExcludeRules && uidExclusionFound)) { break; // stop iterating on criteria because an exclusion was found (will fail) } }//iterate on mix criteria // determine if exiting on success (or implicit failure as desc is 0) if (hasAddrMatch || !((hasUsageExcludeRules && usageExclusionFound) || (hasUsageMatchRules && !usageMatchFound) || (hasUidExcludeRules && uidExclusionFound) || (hasUidMatchRules && !uidMatchFound))) { ALOGV("\tgetOutputForAttr will use mix %zu", i); desc = policyMix->getOutput(); } } else if (mix->mMixType == MIX_TYPE_RECORDERS) { if (attributes.usage == AUDIO_USAGE_VIRTUAL_SOURCE && strncmp(attributes.tags, "addr=", strlen("addr=")) == 0 && Loading Loading @@ -151,9 +232,9 @@ audio_devices_t AudioPolicyMixCollection::getDeviceAndMixForInputSource(audio_so } for (size_t j = 0; j < mix->mCriteria.size(); j++) { if ((RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET == mix->mCriteria[j].mRule && mix->mCriteria[j].mAttr.mSource == inputSource) || mix->mCriteria[j].mValue.mSource == inputSource) || (RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET == mix->mCriteria[j].mRule && mix->mCriteria[j].mAttr.mSource != inputSource)) { mix->mCriteria[j].mValue.mSource != inputSource)) { if (availDevices & AUDIO_DEVICE_IN_REMOTE_SUBMIX) { if (policyMix != NULL) { *policyMix = mix; Loading @@ -174,6 +255,15 @@ status_t AudioPolicyMixCollection::getInputMixForAttr(audio_attributes_t attr, A } String8 address(attr.tags + strlen("addr=")); #ifdef LOG_NDEBUG ALOGV("getInputMixForAttr looking for address %s\n mixes available:", address.string()); for (size_t i = 0; i < size(); i++) { sp<AudioPolicyMix> policyMix = valueAt(i); AudioMix *mix = policyMix->getMix(); ALOGV("\tmix %zu address=%s", i, mix->mRegistrationId.string()); } #endif ssize_t index = indexOfKey(address); if (index < 0) { ALOGW("getInputMixForAttr() no policy for address %s", address.string()); Loading
services/audiopolicy/managerdefault/AudioPolicyManager.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -709,7 +709,7 @@ status_t AudioPolicyManager::getOutputForAttr(const audio_attributes_t *attr, stream_type_to_audio_attributes(*stream, &attributes); } sp<SwAudioOutputDescriptor> desc; if (mPolicyMixes.getOutputForAttr(attributes, desc) == NO_ERROR) { if (mPolicyMixes.getOutputForAttr(attributes, uid, desc) == NO_ERROR) { ALOG_ASSERT(desc != 0, "Invalid desc returned by getOutputForAttr"); if (!audio_is_linear_pcm(format)) { return BAD_VALUE; Loading