Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9a3361e4 authored by jiabin's avatar jiabin
Browse files

Clear up bit mask usage in audio policy.

This change includes:
1. Use DeviceTypeSet to represent a combination of audio device types.
2. Add helper functions for DeviceTypeSet
3. Stop using audio device type as a bit mask in DeviceVector

Test: atest AudioTrackTest AudioRecordTest AudioPlaybackCaptureTest
Test: atest AudioHostTest AudioServiceHostTest audiopolicy_tests
Test: audio smoke test
Change-Id: If80513b689848bcab6094f70a572f053856afa82
parent 1865ec9e
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@ cc_library_shared {
    vendor_available: true,

    srcs: [
        "AudioContainers.cpp",
        "AudioGain.cpp",
        "AudioPort.cpp",
        "AudioProfile.cpp",
+86 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 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.
 */

#include <sstream>
#include <string>

#include <media/AudioContainers.h>

namespace android {

const DeviceTypeSet& getAudioDeviceOutAllSet() {
    static const DeviceTypeSet audioDeviceOutAllSet = DeviceTypeSet(
            std::begin(AUDIO_DEVICE_OUT_ALL_ARRAY),
            std::end(AUDIO_DEVICE_OUT_ALL_ARRAY));
    return audioDeviceOutAllSet;
}

const DeviceTypeSet& getAudioDeviceOutAllA2dpSet() {
    static const DeviceTypeSet audioDeviceOutAllA2dpSet = DeviceTypeSet(
            std::begin(AUDIO_DEVICE_OUT_ALL_A2DP_ARRAY),
            std::end(AUDIO_DEVICE_OUT_ALL_A2DP_ARRAY));
    return audioDeviceOutAllA2dpSet;
}

const DeviceTypeSet& getAudioDeviceOutAllScoSet() {
    static const DeviceTypeSet audioDeviceOutAllScoSet = DeviceTypeSet(
            std::begin(AUDIO_DEVICE_OUT_ALL_SCO_ARRAY),
            std::end(AUDIO_DEVICE_OUT_ALL_SCO_ARRAY));
    return audioDeviceOutAllScoSet;
}

const DeviceTypeSet& getAudioDeviceInAllSet() {
    static const DeviceTypeSet audioDeviceInAllSet = DeviceTypeSet(
            std::begin(AUDIO_DEVICE_IN_ALL_ARRAY),
            std::end(AUDIO_DEVICE_IN_ALL_ARRAY));
    return audioDeviceInAllSet;
}

bool deviceTypesToString(const DeviceTypeSet &deviceTypes, std::string &str) {
    bool ret = true;
    for (auto it = deviceTypes.begin(); it != deviceTypes.end();) {
        std::string deviceTypeStr;
        ret = audio_is_output_device(*it) ?
              OutputDeviceConverter::toString(*it, deviceTypeStr) :
              InputDeviceConverter::toString(*it, deviceTypeStr);
        if (!ret) {
            break;
        }
        str.append(deviceTypeStr);
        if (++it != deviceTypes.end()) {
            str.append(" , ");
        }
    }
    if (!ret) {
        str = "Unknown values";
    }
    return ret;
}

std::string dumpDeviceTypes(const DeviceTypeSet &deviceTypes) {
    std::string ret;
    for (auto it = deviceTypes.begin(); it != deviceTypes.end();) {
        std::stringstream ss;
        ss << "0x" << std::hex << (*it);
        ret.append(ss.str());
        if (++it != deviceTypes.end()) {
            ret.append(" , ");
        }
    }
    return ret;
}

} // namespace android
+69 −0
Original line number Diff line number Diff line
@@ -16,19 +16,37 @@

#pragma once

#include <algorithm>
#include <iterator>
#include <set>
#include <vector>

#include <media/TypeConverter.h>
#include <system/audio.h>

namespace android {

using ChannelMaskSet = std::set<audio_channel_mask_t>;
using DeviceTypeSet = std::set<audio_devices_t>;
using FormatSet = std::set<audio_format_t>;
using SampleRateSet = std::set<uint32_t>;

using FormatVector = std::vector<audio_format_t>;

const DeviceTypeSet& getAudioDeviceOutAllSet();
const DeviceTypeSet& getAudioDeviceOutAllA2dpSet();
const DeviceTypeSet& getAudioDeviceOutAllScoSet();
const DeviceTypeSet& getAudioDeviceInAllSet();

template<typename T>
static std::vector<T> Intersection(const std::set<T>& a, const std::set<T>& b) {
    std::vector<T> intersection;
    std::set_intersection(a.begin(), a.end(),
                          b.begin(), b.end(),
                          std::back_inserter(intersection));
    return intersection;
}

static inline ChannelMaskSet asInMask(const ChannelMaskSet& channelMasks) {
    ChannelMaskSet inMaskSet;
    for (const auto &channel : channelMasks) {
@@ -49,4 +67,55 @@ static inline ChannelMaskSet asOutMask(const ChannelMaskSet& channelMasks) {
    return outMaskSet;
}

static inline bool isSingleDeviceType(const DeviceTypeSet& deviceTypes,
                                      audio_devices_t deviceType) {
    return deviceTypes.size() == 1 && *(deviceTypes.begin()) == deviceType;
}

typedef bool (*DeviceTypeUnaryPredicate)(audio_devices_t);
static inline bool isSingleDeviceType(const DeviceTypeSet& deviceTypes,
                                      DeviceTypeUnaryPredicate p) {
    return deviceTypes.size() == 1 && p(*(deviceTypes.begin()));
}

static inline void resetDeviceTypes(DeviceTypeSet& deviceTypes, audio_devices_t typeToAdd) {
    deviceTypes.clear();
    deviceTypes.insert(typeToAdd);
}

// FIXME: This is temporary helper function. Remove this when getting rid of all
//  bit mask usages of audio device types.
static inline audio_devices_t deviceTypesToBitMask(const DeviceTypeSet& deviceTypes) {
    audio_devices_t types = AUDIO_DEVICE_NONE;
    for (auto deviceType : deviceTypes) {
        types |= deviceType;
    }
    return types;
}

// FIXME: This is temporary helper function. Remove this when getting rid of all
//  bit mask usages of audio device types.
static inline DeviceTypeSet deviceTypesFromBitMask(audio_devices_t types) {
    DeviceTypeSet deviceTypes;
    if ((types & AUDIO_DEVICE_BIT_IN) == 0) {
        for (auto deviceType : AUDIO_DEVICE_OUT_ALL_ARRAY) {
            if ((types & deviceType) == deviceType) {
                deviceTypes.insert(deviceType);
            }
        }
    } else {
        for (auto deviceType : AUDIO_DEVICE_IN_ALL_ARRAY) {
            if ((types & deviceType) == deviceType) {
                deviceTypes.insert(deviceType);
            }
        }
    }
    return deviceTypes;
}

bool deviceTypesToString(const DeviceTypeSet& deviceTypes, std::string &str);

std::string dumpDeviceTypes(const DeviceTypeSet& deviceTypes);


} // namespace android
 No newline at end of file
+3 −0
Original line number Diff line number Diff line
cc_library_headers {
    name: "libaudiopolicycommon",
    header_libs: [
        "libaudiofoundation_headers",
    ],
    export_include_dirs: ["include"],
}
+36 −23
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#pragma once

#include <media/AudioCommonTypes.h>
#include <media/AudioContainers.h>
#include <system/audio.h>
#include <utils/Log.h>
#include <math.h>
@@ -82,43 +83,55 @@ public:
     *
     * @return subset of device required to limit the number of volume category per device
     */
    static audio_devices_t getDeviceForVolume(audio_devices_t device)
    static audio_devices_t getDeviceForVolume(const android::DeviceTypeSet& deviceTypes)
    {
        if (device == AUDIO_DEVICE_NONE) {
        audio_devices_t deviceType = AUDIO_DEVICE_NONE;
        if (deviceTypes.empty()) {
            // this happens when forcing a route update and no track is active on an output.
            // In this case the returned category is not important.
            device =  AUDIO_DEVICE_OUT_SPEAKER;
        } else if (popcount(device) > 1) {
            deviceType = AUDIO_DEVICE_OUT_SPEAKER;
        } else if (deviceTypes.size() > 1) {
            // Multiple device selection is either:
            //  - speaker + one other device: give priority to speaker in this case.
            //  - one A2DP device + another device: happens with duplicated output. In this case
            // retain the device on the A2DP output as the other must not correspond to an active
            // selection if not the speaker.
            //  - HDMI-CEC system audio mode only output: give priority to available item in order.
            if (device & AUDIO_DEVICE_OUT_SPEAKER) {
                device = AUDIO_DEVICE_OUT_SPEAKER;
            } else if (device & AUDIO_DEVICE_OUT_SPEAKER_SAFE) {
                device = AUDIO_DEVICE_OUT_SPEAKER_SAFE;
            } else if (device & AUDIO_DEVICE_OUT_HDMI_ARC) {
                device = AUDIO_DEVICE_OUT_HDMI_ARC;
            } else if (device & AUDIO_DEVICE_OUT_AUX_LINE) {
                device = AUDIO_DEVICE_OUT_AUX_LINE;
            } else if (device & AUDIO_DEVICE_OUT_SPDIF) {
                device = AUDIO_DEVICE_OUT_SPDIF;
            if (deviceTypes.count(AUDIO_DEVICE_OUT_SPEAKER) != 0) {
                deviceType = AUDIO_DEVICE_OUT_SPEAKER;
            } else if (deviceTypes.count(AUDIO_DEVICE_OUT_SPEAKER_SAFE) != 0) {
                deviceType = AUDIO_DEVICE_OUT_SPEAKER_SAFE;
            } else if (deviceTypes.count(AUDIO_DEVICE_OUT_HDMI_ARC) != 0) {
                deviceType = AUDIO_DEVICE_OUT_HDMI_ARC;
            } else if (deviceTypes.count(AUDIO_DEVICE_OUT_AUX_LINE) != 0) {
                deviceType = AUDIO_DEVICE_OUT_AUX_LINE;
            } else if (deviceTypes.count(AUDIO_DEVICE_OUT_SPDIF) != 0) {
                deviceType = AUDIO_DEVICE_OUT_SPDIF;
            } else {
                device = (audio_devices_t)(device & AUDIO_DEVICE_OUT_ALL_A2DP);
                std::vector<audio_devices_t> a2dpDevices = android::Intersection(
                        deviceTypes, android::getAudioDeviceOutAllA2dpSet());
                if (a2dpDevices.size() > 1) {
                    ALOGW("getDeviceForVolume() invalid device combination: %s",
                          android::dumpDeviceTypes(deviceTypes).c_str());
                }
                if (!a2dpDevices.empty()) {
                    deviceType = a2dpDevices[0];
                }
            }
        } else {
            deviceType = *(deviceTypes.begin());
        }

        /*SPEAKER_SAFE is an alias of SPEAKER for purposes of volume control*/
        if (device == AUDIO_DEVICE_OUT_SPEAKER_SAFE)
            device = AUDIO_DEVICE_OUT_SPEAKER;
        if (deviceType == AUDIO_DEVICE_OUT_SPEAKER_SAFE) {
            deviceType = AUDIO_DEVICE_OUT_SPEAKER;
        }

        ALOGW_IF(popcount(device) != 1,
                 "getDeviceForVolume() invalid device combination: %08x",
                 device);
        ALOGW_IF(deviceType == AUDIO_DEVICE_NONE,
                 "getDeviceForVolume() invalid device combination: %s, returning AUDIO_DEVICE_NONE",
                 android::dumpDeviceTypes(deviceTypes).c_str());

        return device;
        return deviceType;
    }

    /**
@@ -128,9 +141,9 @@ public:
     *
     * @return device category.
     */
    static device_category getDeviceCategory(audio_devices_t device)
    static device_category getDeviceCategory(const android::DeviceTypeSet& deviceTypes)
    {
        switch(getDeviceForVolume(device)) {
        switch(getDeviceForVolume(deviceTypes)) {
        case AUDIO_DEVICE_OUT_EARPIECE:
            return DEVICE_CATEGORY_EARPIECE;
        case AUDIO_DEVICE_OUT_WIRED_HEADSET:
Loading