Home | History | Annotate | Download | only in src
      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 "TypeConverter.h"
     22 #include "HwModule.h"
     23 #include "AudioPort.h"
     24 #include "IOProfile.h"
     25 #include "AudioGain.h"
     26 #include <AudioOutputDescriptor.h>
     27 
     28 namespace android {
     29 
     30 void AudioPolicyMix::setOutput(sp<SwAudioOutputDescriptor> &output)
     31 {
     32     mOutput = output;
     33 }
     34 
     35 const sp<SwAudioOutputDescriptor> &AudioPolicyMix::getOutput() const
     36 {
     37     return mOutput;
     38 }
     39 
     40 void AudioPolicyMix::clearOutput()
     41 {
     42     mOutput.clear();
     43 }
     44 
     45 void AudioPolicyMix::setMix(AudioMix &mix)
     46 {
     47     mMix = mix;
     48 }
     49 
     50 android::AudioMix *AudioPolicyMix::getMix()
     51 {
     52     return &mMix;
     53 }
     54 
     55 status_t AudioPolicyMix::dump(int fd, int spaces, int index) const
     56 {
     57     const size_t SIZE = 256;
     58     char buffer[SIZE];
     59     String8 result;
     60 
     61     snprintf(buffer, SIZE, "%*sAudio Policy Mix %d:\n", spaces, "", index+1);
     62     result.append(buffer);
     63     std::string mixTypeLiteral;
     64     if (!MixTypeConverter::toString(mMix.mMixType, mixTypeLiteral)) {
     65         ALOGE("%s: failed to convert mix type %d", __FUNCTION__, mMix.mMixType);
     66         return BAD_VALUE;
     67     }
     68     snprintf(buffer, SIZE, "%*s- mix type: %s\n", spaces, "", mixTypeLiteral.c_str());
     69     result.append(buffer);
     70     std::string routeFlagLiteral;
     71     RouteFlagTypeConverter::maskToString(mMix.mRouteFlags, routeFlagLiteral);
     72     snprintf(buffer, SIZE, "%*s- Route Flags: %s\n", spaces, "", routeFlagLiteral.c_str());
     73     result.append(buffer);
     74     std::string deviceLiteral;
     75     deviceToString(mMix.mDeviceType, deviceLiteral);
     76     snprintf(buffer, SIZE, "%*s- device type: %s\n", spaces, "", deviceLiteral.c_str());
     77     result.append(buffer);
     78     snprintf(buffer, SIZE, "%*s- device address: %s\n", spaces, "", mMix.mDeviceAddress.string());
     79     result.append(buffer);
     80 
     81     int indexCriterion = 0;
     82     for (const auto &criterion : mMix.mCriteria) {
     83         snprintf(buffer, SIZE, "%*s- Criterion %d:\n", spaces + 2, "", indexCriterion++);
     84         result.append(buffer);
     85         std::string usageLiteral;
     86         if (!UsageTypeConverter::toString(criterion.mValue.mUsage, usageLiteral)) {
     87             ALOGE("%s: failed to convert usage %d", __FUNCTION__, criterion.mValue.mUsage);
     88             return BAD_VALUE;
     89         }
     90         snprintf(buffer, SIZE, "%*s- Usage:%s\n", spaces + 4, "", usageLiteral.c_str());
     91         result.append(buffer);
     92         if (mMix.mMixType == MIX_TYPE_RECORDERS) {
     93             std::string sourceLiteral;
     94             if (!SourceTypeConverter::toString(criterion.mValue.mSource, sourceLiteral)) {
     95                 ALOGE("%s: failed to convert source %d", __FUNCTION__, criterion.mValue.mSource);
     96                 return BAD_VALUE;
     97             }
     98             snprintf(buffer, SIZE, "%*s- Source:%s\n", spaces + 4, "", sourceLiteral.c_str());
     99             result.append(buffer);
    100         }
    101         snprintf(buffer, SIZE, "%*s- Uid:%d\n", spaces + 4, "", criterion.mValue.mUid);
    102         result.append(buffer);
    103         std::string ruleLiteral;
    104         if (!RuleTypeConverter::toString(criterion.mRule, ruleLiteral)) {
    105             ALOGE("%s: failed to convert source %d", __FUNCTION__,criterion.mRule);
    106             return BAD_VALUE;
    107         }
    108         snprintf(buffer, SIZE, "%*s- Rule:%s\n", spaces + 4, "", ruleLiteral.c_str());
    109         result.append(buffer);
    110     }
    111     write(fd, result.string(), result.size());
    112     return NO_ERROR;
    113 }
    114 
    115 status_t AudioPolicyMixCollection::registerMix(const String8& address, AudioMix mix,
    116                                                sp<SwAudioOutputDescriptor> desc)
    117 {
    118     ssize_t index = indexOfKey(address);
    119     if (index >= 0) {
    120         ALOGE("registerPolicyMixes(): mix for address %s already registered", address.string());
    121         return BAD_VALUE;
    122     }
    123     sp<AudioPolicyMix> policyMix = new AudioPolicyMix();
    124     policyMix->setMix(mix);
    125     add(address, policyMix);
    126 
    127     if (desc != 0) {
    128         desc->mPolicyMix = policyMix->getMix();
    129         policyMix->setOutput(desc);
    130     }
    131     return NO_ERROR;
    132 }
    133 
    134 status_t AudioPolicyMixCollection::unregisterMix(const String8& address)
    135 {
    136     ssize_t index = indexOfKey(address);
    137     if (index < 0) {
    138         ALOGE("unregisterPolicyMixes(): mix for address %s not registered", address.string());
    139         return BAD_VALUE;
    140     }
    141 
    142     removeItemsAt(index);
    143     return NO_ERROR;
    144 }
    145 
    146 status_t AudioPolicyMixCollection::getAudioPolicyMix(const String8& address,
    147                                                      sp<AudioPolicyMix> &policyMix) const
    148 {
    149     ssize_t index = indexOfKey(address);
    150     if (index < 0) {
    151         ALOGE("unregisterPolicyMixes(): mix for address %s not registered", address.string());
    152         return BAD_VALUE;
    153     }
    154     policyMix = valueAt(index);
    155     return NO_ERROR;
    156 }
    157 
    158 void AudioPolicyMixCollection::closeOutput(sp<SwAudioOutputDescriptor> &desc)
    159 {
    160     for (size_t i = 0; i < size(); i++) {
    161         sp<AudioPolicyMix> policyMix = valueAt(i);
    162         if (policyMix->getOutput() == desc) {
    163             policyMix->clearOutput();
    164         }
    165     }
    166 }
    167 
    168 status_t AudioPolicyMixCollection::getOutputForAttr(audio_attributes_t attributes, uid_t uid,
    169                                                     sp<SwAudioOutputDescriptor> &desc)
    170 {
    171     ALOGV("getOutputForAttr() querying %zu mixes:", size());
    172     desc = 0;
    173     for (size_t i = 0; i < size(); i++) {
    174         sp<AudioPolicyMix> policyMix = valueAt(i);
    175         AudioMix *mix = policyMix->getMix();
    176 
    177         if (mix->mMixType == MIX_TYPE_PLAYERS) {
    178             // TODO if adding more player rules (currently only 2), make rule handling "generic"
    179             //      as there is no difference in the treatment of usage- or uid-based rules
    180             bool hasUsageMatchRules = false;
    181             bool hasUsageExcludeRules = false;
    182             bool usageMatchFound = false;
    183             bool usageExclusionFound = false;
    184 
    185             bool hasUidMatchRules = false;
    186             bool hasUidExcludeRules = false;
    187             bool uidMatchFound = false;
    188             bool uidExclusionFound = false;
    189 
    190             bool hasAddrMatch = false;
    191 
    192             // iterate over all mix criteria to list what rules this mix contains
    193             for (size_t j = 0; j < mix->mCriteria.size(); j++) {
    194                 ALOGV(" getOutputForAttr: mix %zu: inspecting mix criteria %zu of %zu",
    195                         i, j, mix->mCriteria.size());
    196 
    197                 // if there is an address match, prioritize that match
    198                 if (strncmp(attributes.tags, "addr=", strlen("addr=")) == 0 &&
    199                         strncmp(attributes.tags + strlen("addr="),
    200                                 mix->mDeviceAddress.string(),
    201                                 AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - strlen("addr=") - 1) == 0) {
    202                     hasAddrMatch = true;
    203                     break;
    204                 }
    205 
    206                 switch (mix->mCriteria[j].mRule) {
    207                 case RULE_MATCH_ATTRIBUTE_USAGE:
    208                     ALOGV("\tmix has RULE_MATCH_ATTRIBUTE_USAGE for usage %d",
    209                                                 mix->mCriteria[j].mValue.mUsage);
    210                     hasUsageMatchRules = true;
    211                     if (mix->mCriteria[j].mValue.mUsage == attributes.usage) {
    212                         // found one match against all allowed usages
    213                         usageMatchFound = true;
    214                     }
    215                     break;
    216                 case RULE_EXCLUDE_ATTRIBUTE_USAGE:
    217                     ALOGV("\tmix has RULE_EXCLUDE_ATTRIBUTE_USAGE for usage %d",
    218                             mix->mCriteria[j].mValue.mUsage);
    219                     hasUsageExcludeRules = true;
    220                     if (mix->mCriteria[j].mValue.mUsage == attributes.usage) {
    221                         // found this usage is to be excluded
    222                         usageExclusionFound = true;
    223                     }
    224                     break;
    225                 case RULE_MATCH_UID:
    226                     ALOGV("\tmix has RULE_MATCH_UID for uid %d", mix->mCriteria[j].mValue.mUid);
    227                     hasUidMatchRules = true;
    228                     if (mix->mCriteria[j].mValue.mUid == uid) {
    229                         // found one UID match against all allowed UIDs
    230                         uidMatchFound = true;
    231                     }
    232                     break;
    233                 case RULE_EXCLUDE_UID:
    234                     ALOGV("\tmix has RULE_EXCLUDE_UID for uid %d", mix->mCriteria[j].mValue.mUid);
    235                     hasUidExcludeRules = true;
    236                     if (mix->mCriteria[j].mValue.mUid == uid) {
    237                         // found this UID is to be excluded
    238                         uidExclusionFound = true;
    239                     }
    240                     break;
    241                 default:
    242                     break;
    243                 }
    244 
    245                 // consistency checks: for each "dimension" of rules (usage, uid...), we can
    246                 // only have MATCH rules, or EXCLUDE rules in each dimension, not a combination
    247                 if (hasUsageMatchRules && hasUsageExcludeRules) {
    248                     ALOGE("getOutputForAttr: invalid combination of RULE_MATCH_ATTRIBUTE_USAGE"
    249                             " and RULE_EXCLUDE_ATTRIBUTE_USAGE in mix %zu", i);
    250                     return BAD_VALUE;
    251                 }
    252                 if (hasUidMatchRules && hasUidExcludeRules) {
    253                     ALOGE("getOutputForAttr: invalid combination of RULE_MATCH_UID"
    254                             " and RULE_EXCLUDE_UID in mix %zu", i);
    255                     return BAD_VALUE;
    256                 }
    257 
    258                 if ((hasUsageExcludeRules && usageExclusionFound)
    259                         || (hasUidExcludeRules && uidExclusionFound)) {
    260                     break; // stop iterating on criteria because an exclusion was found (will fail)
    261                 }
    262 
    263             }//iterate on mix criteria
    264 
    265             // determine if exiting on success (or implicit failure as desc is 0)
    266             if (hasAddrMatch ||
    267                     !((hasUsageExcludeRules && usageExclusionFound) ||
    268                       (hasUsageMatchRules && !usageMatchFound)  ||
    269                       (hasUidExcludeRules && uidExclusionFound) ||
    270                       (hasUidMatchRules && !uidMatchFound))) {
    271                 ALOGV("\tgetOutputForAttr will use mix %zu", i);
    272                 desc = policyMix->getOutput();
    273             }
    274 
    275         } else if (mix->mMixType == MIX_TYPE_RECORDERS) {
    276             if (attributes.usage == AUDIO_USAGE_VIRTUAL_SOURCE &&
    277                     strncmp(attributes.tags, "addr=", strlen("addr=")) == 0 &&
    278                     strncmp(attributes.tags + strlen("addr="),
    279                             mix->mDeviceAddress.string(),
    280                             AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - strlen("addr=") - 1) == 0) {
    281                 desc = policyMix->getOutput();
    282             }
    283         }
    284         if (desc != 0) {
    285             desc->mPolicyMix = mix;
    286             return NO_ERROR;
    287         }
    288     }
    289     return BAD_VALUE;
    290 }
    291 
    292 audio_devices_t AudioPolicyMixCollection::getDeviceAndMixForInputSource(audio_source_t inputSource,
    293                                                                         audio_devices_t availDevices,
    294                                                                         AudioMix **policyMix)
    295 {
    296     for (size_t i = 0; i < size(); i++) {
    297         AudioMix *mix = valueAt(i)->getMix();
    298 
    299         if (mix->mMixType != MIX_TYPE_RECORDERS) {
    300             continue;
    301         }
    302         for (size_t j = 0; j < mix->mCriteria.size(); j++) {
    303             if ((RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET == mix->mCriteria[j].mRule &&
    304                     mix->mCriteria[j].mValue.mSource == inputSource) ||
    305                (RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET == mix->mCriteria[j].mRule &&
    306                     mix->mCriteria[j].mValue.mSource != inputSource)) {
    307                 if (availDevices & AUDIO_DEVICE_IN_REMOTE_SUBMIX) {
    308                     if (policyMix != NULL) {
    309                         *policyMix = mix;
    310                     }
    311                     return AUDIO_DEVICE_IN_REMOTE_SUBMIX;
    312                 }
    313                 break;
    314             }
    315         }
    316     }
    317     return AUDIO_DEVICE_NONE;
    318 }
    319 
    320 status_t AudioPolicyMixCollection::getInputMixForAttr(audio_attributes_t attr, AudioMix **policyMix)
    321 {
    322     if (strncmp(attr.tags, "addr=", strlen("addr=")) != 0) {
    323         return BAD_VALUE;
    324     }
    325     String8 address(attr.tags + strlen("addr="));
    326 
    327 #ifdef LOG_NDEBUG
    328     ALOGV("getInputMixForAttr looking for address %s\n  mixes available:", address.string());
    329     for (size_t i = 0; i < size(); i++) {
    330             sp<AudioPolicyMix> policyMix = valueAt(i);
    331             AudioMix *mix = policyMix->getMix();
    332             ALOGV("\tmix %zu address=%s", i, mix->mDeviceAddress.string());
    333     }
    334 #endif
    335 
    336     ssize_t index = indexOfKey(address);
    337     if (index < 0) {
    338         ALOGW("getInputMixForAttr() no policy for address %s", address.string());
    339         return BAD_VALUE;
    340     }
    341     sp<AudioPolicyMix> audioPolicyMix = valueAt(index);
    342     AudioMix *mix = audioPolicyMix->getMix();
    343 
    344     if (mix->mMixType != MIX_TYPE_PLAYERS) {
    345         ALOGW("getInputMixForAttr() bad policy mix type for address %s", address.string());
    346         return BAD_VALUE;
    347     }
    348     *policyMix = mix;
    349     return NO_ERROR;
    350 }
    351 
    352 status_t AudioPolicyMixCollection::dump(int fd) const
    353 {
    354     std::string log("\nAudio Policy Mix:\n");
    355     write(fd, log.c_str(), log.size());
    356     for (size_t i = 0; i < size(); i++) {
    357         valueAt(i)->dump(fd, 2, i);
    358     }
    359     return NO_ERROR;
    360 }
    361 
    362 }; //namespace android
    363