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