jiabin | 9a3361e | 2019-10-01 09:38:30 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2019 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 | #include <sstream> |
| 18 | #include <string> |
| 19 | |
| 20 | #include <media/AudioContainers.h> |
| 21 | |
| 22 | namespace android { |
| 23 | |
| 24 | const DeviceTypeSet& getAudioDeviceOutAllSet() { |
| 25 | static const DeviceTypeSet audioDeviceOutAllSet = DeviceTypeSet( |
| 26 | std::begin(AUDIO_DEVICE_OUT_ALL_ARRAY), |
| 27 | std::end(AUDIO_DEVICE_OUT_ALL_ARRAY)); |
| 28 | return audioDeviceOutAllSet; |
| 29 | } |
| 30 | |
| 31 | const DeviceTypeSet& getAudioDeviceOutAllA2dpSet() { |
| 32 | static const DeviceTypeSet audioDeviceOutAllA2dpSet = DeviceTypeSet( |
| 33 | std::begin(AUDIO_DEVICE_OUT_ALL_A2DP_ARRAY), |
| 34 | std::end(AUDIO_DEVICE_OUT_ALL_A2DP_ARRAY)); |
| 35 | return audioDeviceOutAllA2dpSet; |
| 36 | } |
| 37 | |
| 38 | const DeviceTypeSet& getAudioDeviceOutAllScoSet() { |
| 39 | static const DeviceTypeSet audioDeviceOutAllScoSet = DeviceTypeSet( |
| 40 | std::begin(AUDIO_DEVICE_OUT_ALL_SCO_ARRAY), |
| 41 | std::end(AUDIO_DEVICE_OUT_ALL_SCO_ARRAY)); |
| 42 | return audioDeviceOutAllScoSet; |
| 43 | } |
| 44 | |
jiabin | daf4995 | 2019-11-22 14:10:57 -0800 | [diff] [blame] | 45 | const DeviceTypeSet& getAudioDeviceOutAllUsbSet() { |
| 46 | static const DeviceTypeSet audioDeviceOutAllUsbSet = DeviceTypeSet( |
| 47 | std::begin(AUDIO_DEVICE_OUT_ALL_USB_ARRAY), |
| 48 | std::end(AUDIO_DEVICE_OUT_ALL_USB_ARRAY)); |
| 49 | return audioDeviceOutAllUsbSet; |
| 50 | } |
| 51 | |
jiabin | 9a3361e | 2019-10-01 09:38:30 -0700 | [diff] [blame] | 52 | const DeviceTypeSet& getAudioDeviceInAllSet() { |
| 53 | static const DeviceTypeSet audioDeviceInAllSet = DeviceTypeSet( |
| 54 | std::begin(AUDIO_DEVICE_IN_ALL_ARRAY), |
| 55 | std::end(AUDIO_DEVICE_IN_ALL_ARRAY)); |
| 56 | return audioDeviceInAllSet; |
| 57 | } |
| 58 | |
jiabin | daf4995 | 2019-11-22 14:10:57 -0800 | [diff] [blame] | 59 | const DeviceTypeSet& getAudioDeviceInAllUsbSet() { |
| 60 | static const DeviceTypeSet audioDeviceInAllUsbSet = DeviceTypeSet( |
| 61 | std::begin(AUDIO_DEVICE_IN_ALL_USB_ARRAY), |
| 62 | std::end(AUDIO_DEVICE_IN_ALL_USB_ARRAY)); |
| 63 | return audioDeviceInAllUsbSet; |
| 64 | } |
| 65 | |
Patty | dd80758 | 2021-11-04 21:01:03 +0800 | [diff] [blame] | 66 | const DeviceTypeSet& getAudioDeviceOutAllBleSet() { |
| 67 | static const DeviceTypeSet audioDeviceOutAllBleSet = DeviceTypeSet( |
| 68 | std::begin(AUDIO_DEVICE_OUT_ALL_BLE_ARRAY), |
| 69 | std::end(AUDIO_DEVICE_OUT_ALL_BLE_ARRAY)); |
| 70 | return audioDeviceOutAllBleSet; |
| 71 | } |
| 72 | |
Eric Laurent | 96d1dda | 2022-03-14 17:14:19 +0100 | [diff] [blame] | 73 | const DeviceTypeSet& getAudioDeviceOutLeAudioUnicastSet() { |
| 74 | static const DeviceTypeSet audioDeviceOutLeAudioUnicastSet = DeviceTypeSet( |
| 75 | std::begin(AUDIO_DEVICE_OUT_BLE_UNICAST_ARRAY), |
| 76 | std::end(AUDIO_DEVICE_OUT_BLE_UNICAST_ARRAY)); |
| 77 | return audioDeviceOutLeAudioUnicastSet; |
| 78 | } |
| 79 | |
Patty Huang | f5082dd | 2022-07-06 00:14:12 +0800 | [diff] [blame] | 80 | const DeviceTypeSet& getAudioDeviceOutLeAudioBroadcastSet() { |
| 81 | static const DeviceTypeSet audioDeviceOutLeAudioUnicastSet = DeviceTypeSet( |
| 82 | std::begin(AUDIO_DEVICE_OUT_BLE_BROADCAST_ARRAY), |
| 83 | std::end(AUDIO_DEVICE_OUT_BLE_BROADCAST_ARRAY)); |
| 84 | return audioDeviceOutLeAudioUnicastSet; |
| 85 | } |
| 86 | |
Mikhail Naganov | fcfb516 | 2021-12-02 01:35:15 +0000 | [diff] [blame] | 87 | std::string deviceTypesToString(const DeviceTypeSet &deviceTypes) { |
jiabin | c52b1ff | 2019-10-31 17:20:42 -0700 | [diff] [blame] | 88 | if (deviceTypes.empty()) { |
Mikhail Naganov | fcfb516 | 2021-12-02 01:35:15 +0000 | [diff] [blame] | 89 | return "Empty device types"; |
jiabin | c52b1ff | 2019-10-31 17:20:42 -0700 | [diff] [blame] | 90 | } |
Mikhail Naganov | fcfb516 | 2021-12-02 01:35:15 +0000 | [diff] [blame] | 91 | std::stringstream ss; |
| 92 | for (auto it = deviceTypes.begin(); it != deviceTypes.end(); ++it) { |
| 93 | if (it != deviceTypes.begin()) { |
| 94 | ss << ", "; |
jiabin | 9a3361e | 2019-10-01 09:38:30 -0700 | [diff] [blame] | 95 | } |
Mikhail Naganov | fcfb516 | 2021-12-02 01:35:15 +0000 | [diff] [blame] | 96 | const char* strType = audio_device_to_string(*it); |
| 97 | if (strlen(strType) != 0) { |
| 98 | ss << strType; |
| 99 | } else { |
| 100 | ss << "unknown type:0x" << std::hex << *it; |
jiabin | 9a3361e | 2019-10-01 09:38:30 -0700 | [diff] [blame] | 101 | } |
| 102 | } |
Mikhail Naganov | fcfb516 | 2021-12-02 01:35:15 +0000 | [diff] [blame] | 103 | return ss.str(); |
jiabin | 9a3361e | 2019-10-01 09:38:30 -0700 | [diff] [blame] | 104 | } |
| 105 | |
Hongguang | 48dc871 | 2021-12-15 15:35:08 -0800 | [diff] [blame] | 106 | bool deviceTypesToString(const DeviceTypeSet &deviceTypes, std::string &str) { |
| 107 | str = deviceTypesToString(deviceTypes); |
| 108 | return true; |
| 109 | } |
| 110 | |
jiabin | 9a3361e | 2019-10-01 09:38:30 -0700 | [diff] [blame] | 111 | std::string dumpDeviceTypes(const DeviceTypeSet &deviceTypes) { |
Mikhail Naganov | fcfb516 | 2021-12-02 01:35:15 +0000 | [diff] [blame] | 112 | std::stringstream ss; |
| 113 | for (auto it = deviceTypes.begin(); it != deviceTypes.end(); ++it) { |
| 114 | if (it != deviceTypes.begin()) { |
| 115 | ss << ", "; |
jiabin | 9a3361e | 2019-10-01 09:38:30 -0700 | [diff] [blame] | 116 | } |
Mikhail Naganov | fcfb516 | 2021-12-02 01:35:15 +0000 | [diff] [blame] | 117 | ss << "0x" << std::hex << (*it); |
jiabin | 9a3361e | 2019-10-01 09:38:30 -0700 | [diff] [blame] | 118 | } |
Mikhail Naganov | fcfb516 | 2021-12-02 01:35:15 +0000 | [diff] [blame] | 119 | return ss.str(); |
jiabin | c52b1ff | 2019-10-31 17:20:42 -0700 | [diff] [blame] | 120 | } |
| 121 | |
jiabin | f591cd5 | 2023-09-13 22:42:54 +0000 | [diff] [blame] | 122 | std::string dumpMixerBehaviors(const MixerBehaviorSet& mixerBehaviors) { |
| 123 | std::stringstream ss; |
| 124 | for (auto it = mixerBehaviors.begin(); it != mixerBehaviors.end(); ++it) { |
| 125 | if (it != mixerBehaviors.begin()) { |
| 126 | ss << ", "; |
| 127 | } |
| 128 | ss << (*it); |
| 129 | } |
| 130 | return ss.str(); |
| 131 | } |
| 132 | |
Robert Wu | fb97119 | 2024-10-30 21:54:35 +0000 | [diff] [blame] | 133 | std::string toString(const DeviceIdVector& deviceIds) { |
Robert Wu | 9c70c66 | 2024-10-30 18:27:47 +0000 | [diff] [blame] | 134 | if (deviceIds.empty()) { |
Robert Wu | 4511340 | 2024-11-04 23:47:47 +0000 | [diff] [blame] | 135 | return "AUDIO_PORT_HANDLE_NONE"; |
Robert Wu | 9c70c66 | 2024-10-30 18:27:47 +0000 | [diff] [blame] | 136 | } |
| 137 | std::stringstream ss; |
| 138 | for (auto it = deviceIds.begin(); it != deviceIds.end(); ++it) { |
| 139 | if (it != deviceIds.begin()) { |
| 140 | ss << ", "; |
| 141 | } |
| 142 | ss << *it; |
| 143 | } |
| 144 | return ss.str(); |
| 145 | } |
| 146 | |
Robert Wu | fb97119 | 2024-10-30 21:54:35 +0000 | [diff] [blame] | 147 | audio_port_handle_t getFirstDeviceId(const DeviceIdVector& deviceIds) { |
Robert Wu | 9c70c66 | 2024-10-30 18:27:47 +0000 | [diff] [blame] | 148 | if (deviceIds.empty()) { |
| 149 | return AUDIO_PORT_HANDLE_NONE; |
| 150 | } |
Robert Wu | fb97119 | 2024-10-30 21:54:35 +0000 | [diff] [blame] | 151 | return deviceIds[0]; |
Robert Wu | 9c70c66 | 2024-10-30 18:27:47 +0000 | [diff] [blame] | 152 | } |
| 153 | |
Robert Wu | b7f8edc | 2024-11-04 19:54:38 +0000 | [diff] [blame^] | 154 | bool areDeviceIdsEqual(const DeviceIdVector& first, const DeviceIdVector& second) { |
| 155 | const std::set<audio_port_handle_t> firstSet(first.begin(), first.end()); |
| 156 | const std::set<audio_port_handle_t> secondSet(second.begin(), second.end()); |
| 157 | return firstSet == secondSet; |
| 158 | } |
| 159 | |
jiabin | 12537fc | 2023-10-12 17:56:08 +0000 | [diff] [blame] | 160 | AudioProfileAttributesMultimap createAudioProfilesAttrMap(audio_profile profiles[], |
| 161 | uint32_t first, |
| 162 | uint32_t last) { |
| 163 | AudioProfileAttributesMultimap result; |
| 164 | for (uint32_t i = first; i < last; ++i) { |
| 165 | SampleRateSet sampleRates(profiles[i].sample_rates, |
| 166 | profiles[i].sample_rates + profiles[i].num_sample_rates); |
| 167 | ChannelMaskSet channelMasks(profiles[i].channel_masks, |
| 168 | profiles[i].channel_masks + profiles[i].num_channel_masks); |
| 169 | result.emplace(profiles[i].format, std::make_pair(sampleRates, channelMasks)); |
| 170 | } |
| 171 | return result; |
| 172 | } |
| 173 | |
| 174 | namespace { |
| 175 | |
| 176 | void populateAudioProfile(audio_format_t format, |
| 177 | const ChannelMaskSet& channelMasks, |
| 178 | const SampleRateSet& samplingRates, |
| 179 | audio_profile* profile) { |
| 180 | profile->format = format; |
| 181 | profile->num_channel_masks = 0; |
| 182 | for (auto it = channelMasks.begin(); |
| 183 | it != channelMasks.end() && profile->num_channel_masks < AUDIO_PORT_MAX_CHANNEL_MASKS; |
| 184 | ++it) { |
| 185 | profile->channel_masks[profile->num_channel_masks++] = *it; |
| 186 | } |
| 187 | profile->num_sample_rates = 0; |
| 188 | for (auto it = samplingRates.begin(); |
| 189 | it != samplingRates.end() && profile->num_sample_rates < AUDIO_PORT_MAX_SAMPLING_RATES; |
| 190 | ++it) { |
| 191 | profile->sample_rates[profile->num_sample_rates++] = *it; |
| 192 | } |
| 193 | } |
| 194 | |
| 195 | } // namespace |
| 196 | |
| 197 | void populateAudioProfiles(const AudioProfileAttributesMultimap& profileAttrs, |
| 198 | audio_format_t format, |
| 199 | ChannelMaskSet allChannelMasks, |
| 200 | SampleRateSet allSampleRates, |
| 201 | audio_profile audioProfiles[], |
| 202 | uint32_t* numAudioProfiles, |
| 203 | uint32_t maxAudioProfiles) { |
| 204 | if (*numAudioProfiles >= maxAudioProfiles) { |
| 205 | return; |
| 206 | } |
| 207 | |
| 208 | const auto lower= profileAttrs.lower_bound(format); |
| 209 | const auto upper = profileAttrs.upper_bound(format); |
| 210 | SampleRateSet sampleRatesPresent; |
| 211 | ChannelMaskSet channelMasksPresent; |
| 212 | for (auto it = lower; it != upper && *numAudioProfiles < maxAudioProfiles; ++it) { |
| 213 | SampleRateSet srs; |
| 214 | std::set_intersection(it->second.first.begin(), it->second.first.end(), |
| 215 | allSampleRates.begin(), allSampleRates.end(), |
| 216 | std::inserter(srs, srs.begin())); |
| 217 | if (srs.empty()) { |
| 218 | continue; |
| 219 | } |
| 220 | ChannelMaskSet cms; |
| 221 | std::set_intersection(it->second.second.begin(), it->second.second.end(), |
| 222 | allChannelMasks.begin(), allChannelMasks.end(), |
| 223 | std::inserter(cms, cms.begin())); |
| 224 | if (cms.empty()) { |
| 225 | continue; |
| 226 | } |
| 227 | sampleRatesPresent.insert(srs.begin(), srs.end()); |
| 228 | channelMasksPresent.insert(cms.begin(), cms.end()); |
| 229 | populateAudioProfile(it->first, cms, srs, |
| 230 | &audioProfiles[(*numAudioProfiles)++]); |
| 231 | } |
| 232 | if (*numAudioProfiles >= maxAudioProfiles) { |
| 233 | ALOGW("%s, too many audio profiles", __func__); |
| 234 | return; |
| 235 | } |
| 236 | |
| 237 | SampleRateSet srs; |
| 238 | std::set_difference(allSampleRates.begin(), allSampleRates.end(), |
| 239 | sampleRatesPresent.begin(), sampleRatesPresent.end(), |
| 240 | std::inserter(srs, srs.begin())); |
| 241 | if (!srs.empty()) { |
| 242 | populateAudioProfile(format, allChannelMasks, srs, |
| 243 | &audioProfiles[(*numAudioProfiles)++]); |
| 244 | } |
| 245 | if (*numAudioProfiles >= maxAudioProfiles) { |
| 246 | ALOGW("%s, too many audio profiles", __func__); |
| 247 | return; |
| 248 | } |
| 249 | ChannelMaskSet cms; |
| 250 | std::set_difference(allChannelMasks.begin(), allChannelMasks.end(), |
| 251 | channelMasksPresent.begin(), channelMasksPresent.end(), |
| 252 | std::inserter(cms, cms.begin())); |
| 253 | if (!cms.empty()) { |
| 254 | populateAudioProfile(format, cms, allSampleRates, |
| 255 | &audioProfiles[(*numAudioProfiles)++]); |
| 256 | } |
| 257 | |
| 258 | } |
| 259 | |
jiabin | 9a3361e | 2019-10-01 09:38:30 -0700 | [diff] [blame] | 260 | } // namespace android |