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