Mikhail Naganov | 4f5d3f1 | 2022-07-22 23:23:25 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2022 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 | #pragma once |
| 18 | |
Mikhail Naganov | 04ae822 | 2023-01-11 15:48:10 -0800 | [diff] [blame] | 19 | #include <algorithm> |
| 20 | #include <array> |
Mikhail Naganov | a2c5ddf | 2022-09-12 22:57:14 +0000 | [diff] [blame] | 21 | #include <initializer_list> |
Mikhail Naganov | 817da7d | 2023-03-08 17:40:35 -0800 | [diff] [blame] | 22 | #include <regex> |
Mikhail Naganov | a2c5ddf | 2022-09-12 22:57:14 +0000 | [diff] [blame] | 23 | #include <type_traits> |
| 24 | |
Mikhail Naganov | 4f5d3f1 | 2022-07-22 23:23:25 +0000 | [diff] [blame] | 25 | #include <aidl/android/media/audio/common/AudioChannelLayout.h> |
Mikhail Naganov | c8e4312 | 2022-12-09 00:33:47 +0000 | [diff] [blame] | 26 | #include <aidl/android/media/audio/common/AudioDeviceType.h> |
Mikhail Naganov | 4f5d3f1 | 2022-07-22 23:23:25 +0000 | [diff] [blame] | 27 | #include <aidl/android/media/audio/common/AudioFormatDescription.h> |
Mikhail Naganov | a2c5ddf | 2022-09-12 22:57:14 +0000 | [diff] [blame] | 28 | #include <aidl/android/media/audio/common/AudioInputFlags.h> |
Kuowei Li | 53a8d4d | 2024-06-24 14:35:07 +0800 | [diff] [blame] | 29 | #include <aidl/android/media/audio/common/AudioIoFlags.h> |
Mikhail Naganov | 04ae822 | 2023-01-11 15:48:10 -0800 | [diff] [blame] | 30 | #include <aidl/android/media/audio/common/AudioMode.h> |
Mikhail Naganov | a2c5ddf | 2022-09-12 22:57:14 +0000 | [diff] [blame] | 31 | #include <aidl/android/media/audio/common/AudioOutputFlags.h> |
François Gaffie | 32aa870 | 2024-08-02 17:22:14 +0200 | [diff] [blame^] | 32 | #include <aidl/android/media/audio/common/AudioPolicyForcedConfig.h> |
Mikhail Naganov | 4f5d3f1 | 2022-07-22 23:23:25 +0000 | [diff] [blame] | 33 | #include <aidl/android/media/audio/common/PcmType.h> |
Mikhail Naganov | 26dc9ad | 2023-06-23 13:55:37 -0700 | [diff] [blame] | 34 | #include <android/binder_auto_utils.h> |
| 35 | |
| 36 | namespace ndk { |
| 37 | |
| 38 | // This enables use of 'error/expected_utils' for ScopedAStatus. |
| 39 | |
| 40 | inline bool errorIsOk(const ScopedAStatus& s) { |
| 41 | return s.isOk(); |
| 42 | } |
| 43 | |
| 44 | inline std::string errorToString(const ScopedAStatus& s) { |
| 45 | return s.getDescription(); |
| 46 | } |
| 47 | |
| 48 | } // namespace ndk |
Mikhail Naganov | 4f5d3f1 | 2022-07-22 23:23:25 +0000 | [diff] [blame] | 49 | |
Mikhail Naganov | 872d4a6 | 2023-03-09 18:19:01 -0800 | [diff] [blame] | 50 | namespace aidl::android::hardware::audio::common { |
Mikhail Naganov | 4f5d3f1 | 2022-07-22 23:23:25 +0000 | [diff] [blame] | 51 | |
Mikhail Naganov | 04ae822 | 2023-01-11 15:48:10 -0800 | [diff] [blame] | 52 | // Some values are reserved for use by the system code only. |
| 53 | // HALs must not accept or emit values outside from the provided list. |
| 54 | constexpr std::array<::aidl::android::media::audio::common::AudioMode, 5> kValidAudioModes = { |
| 55 | ::aidl::android::media::audio::common::AudioMode::NORMAL, |
| 56 | ::aidl::android::media::audio::common::AudioMode::RINGTONE, |
| 57 | ::aidl::android::media::audio::common::AudioMode::IN_CALL, |
| 58 | ::aidl::android::media::audio::common::AudioMode::IN_COMMUNICATION, |
| 59 | ::aidl::android::media::audio::common::AudioMode::CALL_SCREEN, |
| 60 | }; |
| 61 | |
François Gaffie | 32aa870 | 2024-08-02 17:22:14 +0200 | [diff] [blame^] | 62 | constexpr std::array<::aidl::android::media::audio::common::AudioPolicyForcedConfig, 17> |
| 63 | kValidAudioPolicyForcedConfig = { |
| 64 | ::aidl::android::media::audio::common::AudioPolicyForcedConfig::NONE, |
| 65 | ::aidl::android::media::audio::common::AudioPolicyForcedConfig::SPEAKER, |
| 66 | ::aidl::android::media::audio::common::AudioPolicyForcedConfig::HEADPHONES, |
| 67 | ::aidl::android::media::audio::common::AudioPolicyForcedConfig::BT_SCO, |
| 68 | ::aidl::android::media::audio::common::AudioPolicyForcedConfig::BT_A2DP, |
| 69 | ::aidl::android::media::audio::common::AudioPolicyForcedConfig::WIRED_ACCESSORY, |
| 70 | ::aidl::android::media::audio::common::AudioPolicyForcedConfig::BT_CAR_DOCK, |
| 71 | ::aidl::android::media::audio::common::AudioPolicyForcedConfig::BT_DESK_DOCK, |
| 72 | ::aidl::android::media::audio::common::AudioPolicyForcedConfig::ANALOG_DOCK, |
| 73 | ::aidl::android::media::audio::common::AudioPolicyForcedConfig::DIGITAL_DOCK, |
| 74 | ::aidl::android::media::audio::common::AudioPolicyForcedConfig::NO_BT_A2DP, |
| 75 | ::aidl::android::media::audio::common::AudioPolicyForcedConfig::SYSTEM_ENFORCED, |
| 76 | ::aidl::android::media::audio::common::AudioPolicyForcedConfig:: |
| 77 | HDMI_SYSTEM_AUDIO_ENFORCED, |
| 78 | ::aidl::android::media::audio::common::AudioPolicyForcedConfig:: |
| 79 | ENCODED_SURROUND_NEVER, |
| 80 | ::aidl::android::media::audio::common::AudioPolicyForcedConfig:: |
| 81 | ENCODED_SURROUND_ALWAYS, |
| 82 | ::aidl::android::media::audio::common::AudioPolicyForcedConfig:: |
| 83 | ENCODED_SURROUND_MANUAL, |
| 84 | ::aidl::android::media::audio::common::AudioPolicyForcedConfig::BT_BLE, |
| 85 | }; |
| 86 | |
Mikhail Naganov | 4f5d3f1 | 2022-07-22 23:23:25 +0000 | [diff] [blame] | 87 | constexpr size_t getPcmSampleSizeInBytes(::aidl::android::media::audio::common::PcmType pcm) { |
| 88 | using ::aidl::android::media::audio::common::PcmType; |
| 89 | switch (pcm) { |
| 90 | case PcmType::UINT_8_BIT: |
| 91 | return 1; |
| 92 | case PcmType::INT_16_BIT: |
| 93 | return 2; |
| 94 | case PcmType::INT_32_BIT: |
| 95 | return 4; |
| 96 | case PcmType::FIXED_Q_8_24: |
| 97 | return 4; |
| 98 | case PcmType::FLOAT_32_BIT: |
| 99 | return 4; |
| 100 | case PcmType::INT_24_BIT: |
| 101 | return 3; |
| 102 | } |
| 103 | return 0; |
| 104 | } |
| 105 | |
| 106 | constexpr size_t getChannelCount( |
Shraddha Basantwani | ae7dde5 | 2022-12-18 15:01:14 +0530 | [diff] [blame] | 107 | const ::aidl::android::media::audio::common::AudioChannelLayout& layout, |
| 108 | int32_t mask = std::numeric_limits<int32_t>::max()) { |
Mikhail Naganov | 4f5d3f1 | 2022-07-22 23:23:25 +0000 | [diff] [blame] | 109 | using Tag = ::aidl::android::media::audio::common::AudioChannelLayout::Tag; |
| 110 | switch (layout.getTag()) { |
| 111 | case Tag::none: |
| 112 | return 0; |
| 113 | case Tag::invalid: |
| 114 | return 0; |
| 115 | case Tag::indexMask: |
Shraddha Basantwani | ae7dde5 | 2022-12-18 15:01:14 +0530 | [diff] [blame] | 116 | return __builtin_popcount(layout.get<Tag::indexMask>() & mask); |
Mikhail Naganov | 4f5d3f1 | 2022-07-22 23:23:25 +0000 | [diff] [blame] | 117 | case Tag::layoutMask: |
Shraddha Basantwani | ae7dde5 | 2022-12-18 15:01:14 +0530 | [diff] [blame] | 118 | return __builtin_popcount(layout.get<Tag::layoutMask>() & mask); |
Mikhail Naganov | 4f5d3f1 | 2022-07-22 23:23:25 +0000 | [diff] [blame] | 119 | case Tag::voiceMask: |
Shraddha Basantwani | ae7dde5 | 2022-12-18 15:01:14 +0530 | [diff] [blame] | 120 | return __builtin_popcount(layout.get<Tag::voiceMask>() & mask); |
Mikhail Naganov | 4f5d3f1 | 2022-07-22 23:23:25 +0000 | [diff] [blame] | 121 | } |
| 122 | return 0; |
| 123 | } |
| 124 | |
| 125 | constexpr size_t getFrameSizeInBytes( |
| 126 | const ::aidl::android::media::audio::common::AudioFormatDescription& format, |
| 127 | const ::aidl::android::media::audio::common::AudioChannelLayout& layout) { |
Mikhail Naganov | a2c7141 | 2022-08-19 21:37:35 +0000 | [diff] [blame] | 128 | if (format == ::aidl::android::media::audio::common::AudioFormatDescription{}) { |
| 129 | // Unspecified format. |
| 130 | return 0; |
| 131 | } |
Mikhail Naganov | 4f5d3f1 | 2022-07-22 23:23:25 +0000 | [diff] [blame] | 132 | using ::aidl::android::media::audio::common::AudioFormatType; |
| 133 | if (format.type == AudioFormatType::PCM) { |
| 134 | return getPcmSampleSizeInBytes(format.pcm) * getChannelCount(layout); |
Mikhail Naganov | a2c7141 | 2022-08-19 21:37:35 +0000 | [diff] [blame] | 135 | } else if (format.type == AudioFormatType::NON_PCM) { |
| 136 | // For non-PCM formats always use the underlying PCM size. The default value for |
| 137 | // PCM is "UINT_8_BIT", thus non-encapsulated streams have the frame size of 1. |
| 138 | return getPcmSampleSizeInBytes(format.pcm); |
Mikhail Naganov | 4f5d3f1 | 2022-07-22 23:23:25 +0000 | [diff] [blame] | 139 | } |
Mikhail Naganov | a2c7141 | 2022-08-19 21:37:35 +0000 | [diff] [blame] | 140 | // Something unexpected. |
| 141 | return 0; |
Mikhail Naganov | 4f5d3f1 | 2022-07-22 23:23:25 +0000 | [diff] [blame] | 142 | } |
| 143 | |
Mikhail Naganov | d5536d9 | 2023-03-24 18:27:58 -0700 | [diff] [blame] | 144 | constexpr bool isDefaultAudioFormat( |
| 145 | const ::aidl::android::media::audio::common::AudioFormatDescription& desc) { |
| 146 | return desc.type == ::aidl::android::media::audio::common::AudioFormatType::DEFAULT && |
Lorena Torres-Huerta | aa8f76a | 2022-12-12 18:17:10 +0000 | [diff] [blame] | 147 | desc.pcm == ::aidl::android::media::audio::common::PcmType::DEFAULT && |
| 148 | desc.encoding.empty(); |
Mikhail Naganov | d5536d9 | 2023-03-24 18:27:58 -0700 | [diff] [blame] | 149 | } |
| 150 | |
Mikhail Naganov | c8e4312 | 2022-12-09 00:33:47 +0000 | [diff] [blame] | 151 | constexpr bool isTelephonyDeviceType( |
| 152 | ::aidl::android::media::audio::common::AudioDeviceType device) { |
| 153 | return device == ::aidl::android::media::audio::common::AudioDeviceType::IN_TELEPHONY_RX || |
| 154 | device == ::aidl::android::media::audio::common::AudioDeviceType::OUT_TELEPHONY_TX; |
| 155 | } |
| 156 | |
Mikhail Naganov | 04ae822 | 2023-01-11 15:48:10 -0800 | [diff] [blame] | 157 | constexpr bool isValidAudioMode(::aidl::android::media::audio::common::AudioMode mode) { |
| 158 | return std::find(kValidAudioModes.begin(), kValidAudioModes.end(), mode) != |
| 159 | kValidAudioModes.end(); |
| 160 | } |
| 161 | |
François Gaffie | 32aa870 | 2024-08-02 17:22:14 +0200 | [diff] [blame^] | 162 | constexpr bool isValidAudioPolicyForcedConfig( |
| 163 | ::aidl::android::media::audio::common::AudioPolicyForcedConfig config) { |
| 164 | return std::find(kValidAudioPolicyForcedConfig.begin(), kValidAudioPolicyForcedConfig.end(), |
| 165 | config) != kValidAudioPolicyForcedConfig.end(); |
| 166 | } |
| 167 | |
Mikhail Naganov | 817da7d | 2023-03-08 17:40:35 -0800 | [diff] [blame] | 168 | static inline bool maybeVendorExtension(const std::string& s) { |
| 169 | // Only checks whether the string starts with the "vendor prefix". |
| 170 | static const std::string vendorPrefix = "VX_"; |
| 171 | return s.size() > vendorPrefix.size() && s.substr(0, vendorPrefix.size()) == vendorPrefix; |
| 172 | } |
| 173 | |
| 174 | static inline bool isVendorExtension(const std::string& s) { |
| 175 | // Must be the same as defined in {Playback|Record}TrackMetadata.aidl |
| 176 | static const std::regex vendorExtension("VX_[A-Z0-9]{3,}_[_A-Z0-9]+"); |
| 177 | return std::regex_match(s.begin(), s.end(), vendorExtension); |
| 178 | } |
| 179 | |
Mikhail Naganov | a2c5ddf | 2022-09-12 22:57:14 +0000 | [diff] [blame] | 180 | // The helper functions defined below are only applicable to the case when an enum type |
| 181 | // specifies zero-based bit positions, not bit masks themselves. This is why instantiation |
| 182 | // is restricted to certain enum types. |
| 183 | template <typename E> |
| 184 | using is_bit_position_enum = std::integral_constant< |
| 185 | bool, std::is_same_v<E, ::aidl::android::media::audio::common::AudioInputFlags> || |
| 186 | std::is_same_v<E, ::aidl::android::media::audio::common::AudioOutputFlags>>; |
| 187 | |
| 188 | template <typename E, typename U = std::underlying_type_t<E>, |
| 189 | typename = std::enable_if_t<is_bit_position_enum<E>::value>> |
| 190 | constexpr U makeBitPositionFlagMask(E flag) { |
| 191 | return 1 << static_cast<U>(flag); |
| 192 | } |
| 193 | |
| 194 | template <typename E, typename U = std::underlying_type_t<E>, |
| 195 | typename = std::enable_if_t<is_bit_position_enum<E>::value>> |
| 196 | constexpr bool isBitPositionFlagSet(U mask, E flag) { |
| 197 | return (mask & makeBitPositionFlagMask(flag)) != 0; |
| 198 | } |
| 199 | |
| 200 | template <typename E, typename U = std::underlying_type_t<E>, |
| 201 | typename = std::enable_if_t<is_bit_position_enum<E>::value>> |
| 202 | constexpr U makeBitPositionFlagMask(std::initializer_list<E> flags) { |
| 203 | U result = 0; |
| 204 | for (const auto flag : flags) { |
| 205 | result |= makeBitPositionFlagMask(flag); |
| 206 | } |
| 207 | return result; |
| 208 | } |
| 209 | |
Mikhail Naganov | 69d60aa | 2024-03-28 15:15:44 -0700 | [diff] [blame] | 210 | template <typename E, typename U = std::underlying_type_t<E>, |
| 211 | typename = std::enable_if_t<is_bit_position_enum<E>::value>> |
| 212 | constexpr bool isAnyBitPositionFlagSet(U mask, std::initializer_list<E> flags) { |
| 213 | return (mask & makeBitPositionFlagMask<E>(flags)) != 0; |
| 214 | } |
| 215 | |
Mikhail Naganov | 55045b5 | 2023-10-24 17:03:50 -0700 | [diff] [blame] | 216 | constexpr int32_t frameCountFromDurationUs(long durationUs, int32_t sampleRateHz) { |
Michael Chan | 76f06f2 | 2023-11-13 14:54:44 +1100 | [diff] [blame] | 217 | return (static_cast<long long>(durationUs) * sampleRateHz) / 1000000LL; |
Mikhail Naganov | 55045b5 | 2023-10-24 17:03:50 -0700 | [diff] [blame] | 218 | } |
| 219 | |
| 220 | constexpr int32_t frameCountFromDurationMs(int32_t durationMs, int32_t sampleRateHz) { |
| 221 | return frameCountFromDurationUs(durationMs * 1000, sampleRateHz); |
| 222 | } |
| 223 | |
Kuowei Li | 53a8d4d | 2024-06-24 14:35:07 +0800 | [diff] [blame] | 224 | constexpr bool hasMmapFlag(const ::aidl::android::media::audio::common::AudioIoFlags& flags) { |
| 225 | return (flags.getTag() == ::aidl::android::media::audio::common::AudioIoFlags::Tag::input && |
| 226 | isBitPositionFlagSet( |
| 227 | flags.get<::aidl::android::media::audio::common::AudioIoFlags::Tag::input>(), |
| 228 | ::aidl::android::media::audio::common::AudioInputFlags::MMAP_NOIRQ)) || |
| 229 | (flags.getTag() == ::aidl::android::media::audio::common::AudioIoFlags::Tag::output && |
| 230 | isBitPositionFlagSet( |
| 231 | flags.get<::aidl::android::media::audio::common::AudioIoFlags::Tag::output>(), |
| 232 | ::aidl::android::media::audio::common::AudioOutputFlags::MMAP_NOIRQ)); |
| 233 | } |
| 234 | |
Mikhail Naganov | 872d4a6 | 2023-03-09 18:19:01 -0800 | [diff] [blame] | 235 | } // namespace aidl::android::hardware::audio::common |