AudioPolicyMix.cpp revision 7638ca29e8400a19524adb982e9d22c02786de82
1/* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#define LOG_TAG "APM::AudioPolicyMix" 18//#define LOG_NDEBUG 0 19 20#include "AudioPolicyMix.h" 21#include "HwModule.h" 22#include "AudioPort.h" 23#include "IOProfile.h" 24#include "AudioGain.h" 25#include <AudioOutputDescriptor.h> 26 27namespace android { 28 29void AudioPolicyMix::setOutput(sp<SwAudioOutputDescriptor> &output) 30{ 31 mOutput = output; 32} 33 34const sp<SwAudioOutputDescriptor> &AudioPolicyMix::getOutput() const 35{ 36 return mOutput; 37} 38 39void AudioPolicyMix::clearOutput() 40{ 41 mOutput.clear(); 42} 43 44void AudioPolicyMix::setMix(AudioMix &mix) 45{ 46 mMix = mix; 47} 48 49android::AudioMix *AudioPolicyMix::getMix() 50{ 51 return &mMix; 52} 53 54status_t AudioPolicyMixCollection::registerMix(String8 address, AudioMix mix, 55 sp<SwAudioOutputDescriptor> desc) 56{ 57 ssize_t index = indexOfKey(address); 58 if (index >= 0) { 59 ALOGE("registerPolicyMixes(): mix for address %s already registered", address.string()); 60 return BAD_VALUE; 61 } 62 sp<AudioPolicyMix> policyMix = new AudioPolicyMix(); 63 policyMix->setMix(mix); 64 add(address, policyMix); 65 66 if (desc != 0) { 67 desc->mPolicyMix = policyMix->getMix(); 68 policyMix->setOutput(desc); 69 } 70 return NO_ERROR; 71} 72 73status_t AudioPolicyMixCollection::unregisterMix(String8 address) 74{ 75 ssize_t index = indexOfKey(address); 76 if (index < 0) { 77 ALOGE("unregisterPolicyMixes(): mix for address %s not registered", address.string()); 78 return BAD_VALUE; 79 } 80 81 removeItemsAt(index); 82 return NO_ERROR; 83} 84 85status_t AudioPolicyMixCollection::getAudioPolicyMix(String8 address, 86 sp<AudioPolicyMix> &policyMix) const 87{ 88 ssize_t index = indexOfKey(address); 89 if (index < 0) { 90 ALOGE("unregisterPolicyMixes(): mix for address %s not registered", address.string()); 91 return BAD_VALUE; 92 } 93 policyMix = valueAt(index); 94 return NO_ERROR; 95} 96 97void AudioPolicyMixCollection::closeOutput(sp<SwAudioOutputDescriptor> &desc) 98{ 99 for (size_t i = 0; i < size(); i++) { 100 sp<AudioPolicyMix> policyMix = valueAt(i); 101 if (policyMix->getOutput() == desc) { 102 policyMix->clearOutput(); 103 } 104 } 105} 106 107status_t AudioPolicyMixCollection::getOutputForAttr(audio_attributes_t attributes, uid_t uid, 108 sp<SwAudioOutputDescriptor> &desc) 109{ 110 desc = 0; 111 for (size_t i = 0; i < size(); i++) { 112 sp<AudioPolicyMix> policyMix = valueAt(i); 113 AudioMix *mix = policyMix->getMix(); 114 115 if (mix->mMixType == MIX_TYPE_PLAYERS) { 116 // TODO if adding more player rules (currently only 2), make rule handling "generic" 117 // as there is no difference in the treatment of usage- or uid-based rules 118 bool hasUsageMatchRules = false; 119 bool hasUsageExcludeRules = false; 120 bool usageMatchFound = false; 121 bool usageExclusionFound = false; 122 123 bool hasUidMatchRules = false; 124 bool hasUidExcludeRules = false; 125 bool uidMatchFound = false; 126 bool uidExclusionFound = false; 127 128 bool hasAddrMatch = false; 129 130 // iterate over all mix criteria to list what rules this mix contains 131 for (size_t j = 0; j < mix->mCriteria.size(); j++) { 132 ALOGV("getOutputForAttr: inspecting mix %zu of %zu", i, mix->mCriteria.size()); 133 134 // if there is an address match, prioritize that match 135 if (strncmp(attributes.tags, "addr=", strlen("addr=")) == 0 && 136 strncmp(attributes.tags + strlen("addr="), 137 mix->mDeviceAddress.string(), 138 AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - strlen("addr=") - 1) == 0) { 139 hasAddrMatch = true; 140 break; 141 } 142 143 switch (mix->mCriteria[j].mRule) { 144 case RULE_MATCH_ATTRIBUTE_USAGE: 145 ALOGV("\tmix has RULE_MATCH_ATTRIBUTE_USAGE for usage %d", 146 mix->mCriteria[j].mValue.mUsage); 147 hasUsageMatchRules = true; 148 if (mix->mCriteria[j].mValue.mUsage == attributes.usage) { 149 // found one match against all allowed usages 150 usageMatchFound = true; 151 } 152 break; 153 case RULE_EXCLUDE_ATTRIBUTE_USAGE: 154 ALOGV("\tmix has RULE_EXCLUDE_ATTRIBUTE_USAGE for usage %d", 155 mix->mCriteria[j].mValue.mUsage); 156 hasUsageExcludeRules = true; 157 if (mix->mCriteria[j].mValue.mUsage == attributes.usage) { 158 // found this usage is to be excluded 159 usageExclusionFound = true; 160 } 161 break; 162 case RULE_MATCH_UID: 163 ALOGV("\tmix has RULE_MATCH_UID for uid %d", mix->mCriteria[j].mValue.mUid); 164 hasUidMatchRules = true; 165 if (mix->mCriteria[j].mValue.mUid == uid) { 166 // found one UID match against all allowed UIDs 167 uidMatchFound = true; 168 } 169 break; 170 case RULE_EXCLUDE_UID: 171 ALOGV("\tmix has RULE_EXCLUDE_UID for uid %d", mix->mCriteria[j].mValue.mUid); 172 hasUidExcludeRules = true; 173 if (mix->mCriteria[j].mValue.mUid == uid) { 174 // found this UID is to be excluded 175 uidExclusionFound = true; 176 } 177 break; 178 default: 179 break; 180 } 181 182 // consistency checks: for each "dimension" of rules (usage, uid...), we can 183 // only have MATCH rules, or EXCLUDE rules in each dimension, not a combination 184 if (hasUsageMatchRules && hasUsageExcludeRules) { 185 ALOGE("getOutputForAttr: invalid combination of RULE_MATCH_ATTRIBUTE_USAGE" 186 " and RULE_EXCLUDE_ATTRIBUTE_USAGE in mix %zu", i); 187 return BAD_VALUE; 188 } 189 if (hasUidMatchRules && hasUidExcludeRules) { 190 ALOGE("getOutputForAttr: invalid combination of RULE_MATCH_UID" 191 " and RULE_EXCLUDE_UID in mix %zu", i); 192 return BAD_VALUE; 193 } 194 195 if ((hasUsageExcludeRules && usageExclusionFound) 196 || (hasUidExcludeRules && uidExclusionFound)) { 197 break; // stop iterating on criteria because an exclusion was found (will fail) 198 } 199 200 }//iterate on mix criteria 201 202 // determine if exiting on success (or implicit failure as desc is 0) 203 if (hasAddrMatch || 204 !((hasUsageExcludeRules && usageExclusionFound) || 205 (hasUsageMatchRules && !usageMatchFound) || 206 (hasUidExcludeRules && uidExclusionFound) || 207 (hasUidMatchRules && !uidMatchFound))) { 208 ALOGV("\tgetOutputForAttr will use mix %zu", i); 209 desc = policyMix->getOutput(); 210 } 211 212 } else if (mix->mMixType == MIX_TYPE_RECORDERS) { 213 if (attributes.usage == AUDIO_USAGE_VIRTUAL_SOURCE && 214 strncmp(attributes.tags, "addr=", strlen("addr=")) == 0 && 215 strncmp(attributes.tags + strlen("addr="), 216 mix->mDeviceAddress.string(), 217 AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - strlen("addr=") - 1) == 0) { 218 desc = policyMix->getOutput(); 219 } 220 } 221 if (desc != 0) { 222 desc->mPolicyMix = mix; 223 return NO_ERROR; 224 } 225 } 226 return BAD_VALUE; 227} 228 229audio_devices_t AudioPolicyMixCollection::getDeviceAndMixForInputSource(audio_source_t inputSource, 230 audio_devices_t availDevices, 231 AudioMix **policyMix) 232{ 233 for (size_t i = 0; i < size(); i++) { 234 AudioMix *mix = valueAt(i)->getMix(); 235 236 if (mix->mMixType != MIX_TYPE_RECORDERS) { 237 continue; 238 } 239 for (size_t j = 0; j < mix->mCriteria.size(); j++) { 240 if ((RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET == mix->mCriteria[j].mRule && 241 mix->mCriteria[j].mValue.mSource == inputSource) || 242 (RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET == mix->mCriteria[j].mRule && 243 mix->mCriteria[j].mValue.mSource != inputSource)) { 244 if (availDevices & AUDIO_DEVICE_IN_REMOTE_SUBMIX) { 245 if (policyMix != NULL) { 246 *policyMix = mix; 247 } 248 return AUDIO_DEVICE_IN_REMOTE_SUBMIX; 249 } 250 break; 251 } 252 } 253 } 254 return AUDIO_DEVICE_NONE; 255} 256 257status_t AudioPolicyMixCollection::getInputMixForAttr(audio_attributes_t attr, AudioMix **policyMix) 258{ 259 if (strncmp(attr.tags, "addr=", strlen("addr=")) != 0) { 260 return BAD_VALUE; 261 } 262 String8 address(attr.tags + strlen("addr=")); 263 264#ifdef LOG_NDEBUG 265 ALOGV("getInputMixForAttr looking for address %s\n mixes available:", address.string()); 266 for (size_t i = 0; i < size(); i++) { 267 sp<AudioPolicyMix> policyMix = valueAt(i); 268 AudioMix *mix = policyMix->getMix(); 269 ALOGV("\tmix %zu address=%s", i, mix->mDeviceAddress.string()); 270 } 271#endif 272 273 ssize_t index = indexOfKey(address); 274 if (index < 0) { 275 ALOGW("getInputMixForAttr() no policy for address %s", address.string()); 276 return BAD_VALUE; 277 } 278 sp<AudioPolicyMix> audioPolicyMix = valueAt(index); 279 AudioMix *mix = audioPolicyMix->getMix(); 280 281 if (mix->mMixType != MIX_TYPE_PLAYERS) { 282 ALOGW("getInputMixForAttr() bad policy mix type for address %s", address.string()); 283 return BAD_VALUE; 284 } 285 *policyMix = mix; 286 return NO_ERROR; 287} 288 289}; //namespace android 290