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> |
Mikhail Naganov | 04ae822 | 2023-01-11 15:48:10 -0800 | [diff] [blame] | 29 | #include <aidl/android/media/audio/common/AudioMode.h> |
Mikhail Naganov | a2c5ddf | 2022-09-12 22:57:14 +0000 | [diff] [blame] | 30 | #include <aidl/android/media/audio/common/AudioOutputFlags.h> |
Mikhail Naganov | 4f5d3f1 | 2022-07-22 23:23:25 +0000 | [diff] [blame] | 31 | #include <aidl/android/media/audio/common/PcmType.h> |
| 32 | |
Mikhail Naganov | 872d4a6 | 2023-03-09 18:19:01 -0800 | [diff] [blame] | 33 | namespace aidl::android::hardware::audio::common { |
Mikhail Naganov | 4f5d3f1 | 2022-07-22 23:23:25 +0000 | [diff] [blame] | 34 | |
Mikhail Naganov | 04ae822 | 2023-01-11 15:48:10 -0800 | [diff] [blame] | 35 | // Some values are reserved for use by the system code only. |
| 36 | // HALs must not accept or emit values outside from the provided list. |
| 37 | constexpr std::array<::aidl::android::media::audio::common::AudioMode, 5> kValidAudioModes = { |
| 38 | ::aidl::android::media::audio::common::AudioMode::NORMAL, |
| 39 | ::aidl::android::media::audio::common::AudioMode::RINGTONE, |
| 40 | ::aidl::android::media::audio::common::AudioMode::IN_CALL, |
| 41 | ::aidl::android::media::audio::common::AudioMode::IN_COMMUNICATION, |
| 42 | ::aidl::android::media::audio::common::AudioMode::CALL_SCREEN, |
| 43 | }; |
| 44 | |
Mikhail Naganov | 4f5d3f1 | 2022-07-22 23:23:25 +0000 | [diff] [blame] | 45 | constexpr size_t getPcmSampleSizeInBytes(::aidl::android::media::audio::common::PcmType pcm) { |
| 46 | using ::aidl::android::media::audio::common::PcmType; |
| 47 | switch (pcm) { |
| 48 | case PcmType::UINT_8_BIT: |
| 49 | return 1; |
| 50 | case PcmType::INT_16_BIT: |
| 51 | return 2; |
| 52 | case PcmType::INT_32_BIT: |
| 53 | return 4; |
| 54 | case PcmType::FIXED_Q_8_24: |
| 55 | return 4; |
| 56 | case PcmType::FLOAT_32_BIT: |
| 57 | return 4; |
| 58 | case PcmType::INT_24_BIT: |
| 59 | return 3; |
| 60 | } |
| 61 | return 0; |
| 62 | } |
| 63 | |
| 64 | constexpr size_t getChannelCount( |
Shraddha Basantwani | ae7dde5 | 2022-12-18 15:01:14 +0530 | [diff] [blame] | 65 | const ::aidl::android::media::audio::common::AudioChannelLayout& layout, |
| 66 | int32_t mask = std::numeric_limits<int32_t>::max()) { |
Mikhail Naganov | 4f5d3f1 | 2022-07-22 23:23:25 +0000 | [diff] [blame] | 67 | using Tag = ::aidl::android::media::audio::common::AudioChannelLayout::Tag; |
| 68 | switch (layout.getTag()) { |
| 69 | case Tag::none: |
| 70 | return 0; |
| 71 | case Tag::invalid: |
| 72 | return 0; |
| 73 | case Tag::indexMask: |
Shraddha Basantwani | ae7dde5 | 2022-12-18 15:01:14 +0530 | [diff] [blame] | 74 | return __builtin_popcount(layout.get<Tag::indexMask>() & mask); |
Mikhail Naganov | 4f5d3f1 | 2022-07-22 23:23:25 +0000 | [diff] [blame] | 75 | case Tag::layoutMask: |
Shraddha Basantwani | ae7dde5 | 2022-12-18 15:01:14 +0530 | [diff] [blame] | 76 | return __builtin_popcount(layout.get<Tag::layoutMask>() & mask); |
Mikhail Naganov | 4f5d3f1 | 2022-07-22 23:23:25 +0000 | [diff] [blame] | 77 | case Tag::voiceMask: |
Shraddha Basantwani | ae7dde5 | 2022-12-18 15:01:14 +0530 | [diff] [blame] | 78 | return __builtin_popcount(layout.get<Tag::voiceMask>() & mask); |
Mikhail Naganov | 4f5d3f1 | 2022-07-22 23:23:25 +0000 | [diff] [blame] | 79 | } |
| 80 | return 0; |
| 81 | } |
| 82 | |
| 83 | constexpr size_t getFrameSizeInBytes( |
| 84 | const ::aidl::android::media::audio::common::AudioFormatDescription& format, |
| 85 | const ::aidl::android::media::audio::common::AudioChannelLayout& layout) { |
Mikhail Naganov | a2c7141 | 2022-08-19 21:37:35 +0000 | [diff] [blame] | 86 | if (format == ::aidl::android::media::audio::common::AudioFormatDescription{}) { |
| 87 | // Unspecified format. |
| 88 | return 0; |
| 89 | } |
Mikhail Naganov | 4f5d3f1 | 2022-07-22 23:23:25 +0000 | [diff] [blame] | 90 | using ::aidl::android::media::audio::common::AudioFormatType; |
| 91 | if (format.type == AudioFormatType::PCM) { |
| 92 | return getPcmSampleSizeInBytes(format.pcm) * getChannelCount(layout); |
Mikhail Naganov | a2c7141 | 2022-08-19 21:37:35 +0000 | [diff] [blame] | 93 | } else if (format.type == AudioFormatType::NON_PCM) { |
| 94 | // For non-PCM formats always use the underlying PCM size. The default value for |
| 95 | // PCM is "UINT_8_BIT", thus non-encapsulated streams have the frame size of 1. |
| 96 | return getPcmSampleSizeInBytes(format.pcm); |
Mikhail Naganov | 4f5d3f1 | 2022-07-22 23:23:25 +0000 | [diff] [blame] | 97 | } |
Mikhail Naganov | a2c7141 | 2022-08-19 21:37:35 +0000 | [diff] [blame] | 98 | // Something unexpected. |
| 99 | return 0; |
Mikhail Naganov | 4f5d3f1 | 2022-07-22 23:23:25 +0000 | [diff] [blame] | 100 | } |
| 101 | |
Mikhail Naganov | 04b2cdb | 2023-03-24 18:27:58 -0700 | [diff] [blame] | 102 | constexpr bool isDefaultAudioFormat( |
| 103 | const ::aidl::android::media::audio::common::AudioFormatDescription& desc) { |
| 104 | return desc.type == ::aidl::android::media::audio::common::AudioFormatType::DEFAULT && |
| 105 | desc.pcm == ::aidl::android::media::audio::common::PcmType::DEFAULT; |
| 106 | } |
| 107 | |
Mikhail Naganov | c8e4312 | 2022-12-09 00:33:47 +0000 | [diff] [blame] | 108 | constexpr bool isTelephonyDeviceType( |
| 109 | ::aidl::android::media::audio::common::AudioDeviceType device) { |
| 110 | return device == ::aidl::android::media::audio::common::AudioDeviceType::IN_TELEPHONY_RX || |
| 111 | device == ::aidl::android::media::audio::common::AudioDeviceType::OUT_TELEPHONY_TX; |
| 112 | } |
| 113 | |
jiabin | 253bd32 | 2023-01-25 23:57:31 +0000 | [diff] [blame] | 114 | constexpr bool isUsbInputDeviceType(::aidl::android::media::audio::common::AudioDeviceType type) { |
| 115 | switch (type) { |
| 116 | case ::aidl::android::media::audio::common::AudioDeviceType::IN_DOCK: |
| 117 | case ::aidl::android::media::audio::common::AudioDeviceType::IN_ACCESSORY: |
| 118 | case ::aidl::android::media::audio::common::AudioDeviceType::IN_DEVICE: |
| 119 | case ::aidl::android::media::audio::common::AudioDeviceType::IN_HEADSET: |
| 120 | return true; |
| 121 | default: |
| 122 | return false; |
| 123 | } |
| 124 | } |
| 125 | |
| 126 | constexpr bool isUsbOutputtDeviceType(::aidl::android::media::audio::common::AudioDeviceType type) { |
| 127 | switch (type) { |
| 128 | case ::aidl::android::media::audio::common::AudioDeviceType::OUT_DOCK: |
| 129 | case ::aidl::android::media::audio::common::AudioDeviceType::OUT_ACCESSORY: |
| 130 | case ::aidl::android::media::audio::common::AudioDeviceType::OUT_DEVICE: |
| 131 | case ::aidl::android::media::audio::common::AudioDeviceType::OUT_HEADSET: |
| 132 | return true; |
| 133 | default: |
| 134 | return false; |
| 135 | } |
| 136 | } |
| 137 | |
Mikhail Naganov | 04ae822 | 2023-01-11 15:48:10 -0800 | [diff] [blame] | 138 | constexpr bool isValidAudioMode(::aidl::android::media::audio::common::AudioMode mode) { |
| 139 | return std::find(kValidAudioModes.begin(), kValidAudioModes.end(), mode) != |
| 140 | kValidAudioModes.end(); |
| 141 | } |
| 142 | |
Mikhail Naganov | 817da7d | 2023-03-08 17:40:35 -0800 | [diff] [blame] | 143 | static inline bool maybeVendorExtension(const std::string& s) { |
| 144 | // Only checks whether the string starts with the "vendor prefix". |
| 145 | static const std::string vendorPrefix = "VX_"; |
| 146 | return s.size() > vendorPrefix.size() && s.substr(0, vendorPrefix.size()) == vendorPrefix; |
| 147 | } |
| 148 | |
| 149 | static inline bool isVendorExtension(const std::string& s) { |
| 150 | // Must be the same as defined in {Playback|Record}TrackMetadata.aidl |
| 151 | static const std::regex vendorExtension("VX_[A-Z0-9]{3,}_[_A-Z0-9]+"); |
| 152 | return std::regex_match(s.begin(), s.end(), vendorExtension); |
| 153 | } |
| 154 | |
Mikhail Naganov | a2c5ddf | 2022-09-12 22:57:14 +0000 | [diff] [blame] | 155 | // The helper functions defined below are only applicable to the case when an enum type |
| 156 | // specifies zero-based bit positions, not bit masks themselves. This is why instantiation |
| 157 | // is restricted to certain enum types. |
| 158 | template <typename E> |
| 159 | using is_bit_position_enum = std::integral_constant< |
| 160 | bool, std::is_same_v<E, ::aidl::android::media::audio::common::AudioInputFlags> || |
| 161 | std::is_same_v<E, ::aidl::android::media::audio::common::AudioOutputFlags>>; |
| 162 | |
| 163 | template <typename E, typename U = std::underlying_type_t<E>, |
| 164 | typename = std::enable_if_t<is_bit_position_enum<E>::value>> |
| 165 | constexpr U makeBitPositionFlagMask(E flag) { |
| 166 | return 1 << static_cast<U>(flag); |
| 167 | } |
| 168 | |
| 169 | template <typename E, typename U = std::underlying_type_t<E>, |
| 170 | typename = std::enable_if_t<is_bit_position_enum<E>::value>> |
| 171 | constexpr bool isBitPositionFlagSet(U mask, E flag) { |
| 172 | return (mask & makeBitPositionFlagMask(flag)) != 0; |
| 173 | } |
| 174 | |
| 175 | template <typename E, typename U = std::underlying_type_t<E>, |
| 176 | typename = std::enable_if_t<is_bit_position_enum<E>::value>> |
| 177 | constexpr U makeBitPositionFlagMask(std::initializer_list<E> flags) { |
| 178 | U result = 0; |
| 179 | for (const auto flag : flags) { |
| 180 | result |= makeBitPositionFlagMask(flag); |
| 181 | } |
| 182 | return result; |
| 183 | } |
| 184 | |
Mikhail Naganov | 872d4a6 | 2023-03-09 18:19:01 -0800 | [diff] [blame] | 185 | } // namespace aidl::android::hardware::audio::common |