| /* |
| * 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 { |
| |
| // |
| // AudioMixMatchCriterion implementation |
| // |
| 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) { |
| mValue.mUsage = usage; |
| } else { |
| mValue.mSource = source; |
| } |
| } |
| |
| status_t AudioMixMatchCriterion::readFromParcel(Parcel *parcel) |
| { |
| mRule = parcel->readInt32(); |
| switch (mRule) { |
| case RULE_MATCH_ATTRIBUTE_USAGE: |
| case RULE_EXCLUDE_ATTRIBUTE_USAGE: |
| mValue.mUsage = (audio_usage_t) parcel->readInt32(); |
| break; |
| case RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET: |
| case RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET: |
| mValue.mSource = (audio_source_t) parcel->readInt32(); |
| break; |
| case RULE_MATCH_UID: |
| case RULE_EXCLUDE_UID: |
| mValue.mUid = (uid_t) parcel->readInt32(); |
| break; |
| case RULE_MATCH_USERID: |
| case RULE_EXCLUDE_USERID: |
| mValue.mUserId = (int) parcel->readInt32(); |
| break; |
| case RULE_MATCH_AUDIO_SESSION_ID: |
| case RULE_EXCLUDE_AUDIO_SESSION_ID: |
| mValue.mAudioSessionId = (audio_session_t) parcel->readInt32(); |
| break; |
| default: |
| ALOGE("Trying to build AudioMixMatchCriterion from unknown rule %d", mRule); |
| return BAD_VALUE; |
| } |
| return NO_ERROR; |
| } |
| |
| status_t AudioMixMatchCriterion::writeToParcel(Parcel *parcel) const |
| { |
| parcel->writeInt32(mRule); |
| parcel->writeInt32(mValue.mUsage); |
| return NO_ERROR; |
| } |
| |
| bool AudioMixMatchCriterion::isExcludeCriterion() const { |
| return mRule & RULE_EXCLUSION_MASK; |
| } |
| |
| // |
| // 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(); |
| mDeviceType = (audio_devices_t) parcel->readInt32(); |
| mDeviceAddress = parcel->readString8(); |
| mCbFlags = (uint32_t)parcel->readInt32(); |
| mAllowPrivilegedMediaPlaybackCapture = parcel->readBool(); |
| mVoiceCommunicationCaptureAllowed = parcel->readBool(); |
| size_t size = (size_t)parcel->readInt32(); |
| if (size > MAX_CRITERIA_PER_MIX) { |
| size = MAX_CRITERIA_PER_MIX; |
| } |
| mCriteria.reserve(size); |
| for (size_t i = 0; i < size; i++) { |
| AudioMixMatchCriterion criterion; |
| if (criterion.readFromParcel(parcel) == NO_ERROR) { |
| mCriteria.push_back(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->writeInt32(mDeviceType); |
| parcel->writeString8(mDeviceAddress); |
| parcel->writeInt32(mCbFlags); |
| parcel->writeBool(mAllowPrivilegedMediaPlaybackCapture); |
| parcel->writeBool(mVoiceCommunicationCaptureAllowed); |
| 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; |
| } |
| |
| void AudioMix::setExcludeUid(uid_t uid) { |
| AudioMixMatchCriterion crit; |
| crit.mRule = RULE_EXCLUDE_UID; |
| crit.mValue.mUid = uid; |
| mCriteria.push_back(crit); |
| } |
| |
| void AudioMix::setMatchUid(uid_t uid) { |
| AudioMixMatchCriterion crit; |
| crit.mRule = RULE_MATCH_UID; |
| crit.mValue.mUid = uid; |
| mCriteria.push_back(crit); |
| } |
| |
| bool AudioMix::hasUidRule(bool match, uid_t uid) const { |
| const uint32_t rule = match ? RULE_MATCH_UID : RULE_EXCLUDE_UID; |
| for (size_t i = 0; i < mCriteria.size(); i++) { |
| if (mCriteria[i].mRule == rule |
| && mCriteria[i].mValue.mUid == uid) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| bool AudioMix::hasMatchUidRule() const { |
| for (size_t i = 0; i < mCriteria.size(); i++) { |
| if (mCriteria[i].mRule == RULE_MATCH_UID) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| void AudioMix::setExcludeUserId(int userId) { |
| AudioMixMatchCriterion crit; |
| crit.mRule = RULE_EXCLUDE_USERID; |
| crit.mValue.mUserId = userId; |
| mCriteria.push_back(crit); |
| } |
| |
| void AudioMix::setMatchUserId(int userId) { |
| AudioMixMatchCriterion crit; |
| crit.mRule = RULE_MATCH_USERID; |
| crit.mValue.mUserId = userId; |
| mCriteria.push_back(crit); |
| } |
| |
| bool AudioMix::hasUserIdRule(bool match, int userId) const { |
| const uint32_t rule = match ? RULE_MATCH_USERID : RULE_EXCLUDE_USERID; |
| for (size_t i = 0; i < mCriteria.size(); i++) { |
| if (mCriteria[i].mRule == rule |
| && mCriteria[i].mValue.mUserId == userId) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| bool AudioMix::hasUserIdRule(bool match) const { |
| const uint32_t rule = match ? RULE_MATCH_USERID : RULE_EXCLUDE_USERID; |
| for (size_t i = 0; i < mCriteria.size(); i++) { |
| if (mCriteria[i].mRule == rule) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| bool AudioMix::isDeviceAffinityCompatible() const { |
| return ((mMixType == MIX_TYPE_PLAYERS) |
| && ((mRouteFlags & MIX_ROUTE_FLAG_RENDER) == MIX_ROUTE_FLAG_RENDER)); |
| } |
| |
| } // namespace android |