xref: /aosp_15_r20/hardware/interfaces/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp (revision 4d7e907c777eeecc4c5bd7cf640a754fac206ff7)
1*4d7e907cSAndroid Build Coastguard Worker /*
2*4d7e907cSAndroid Build Coastguard Worker  * Copyright (C) 2022 The Android Open Source Project
3*4d7e907cSAndroid Build Coastguard Worker  *
4*4d7e907cSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*4d7e907cSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*4d7e907cSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*4d7e907cSAndroid Build Coastguard Worker  *
8*4d7e907cSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*4d7e907cSAndroid Build Coastguard Worker  *
10*4d7e907cSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*4d7e907cSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*4d7e907cSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*4d7e907cSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*4d7e907cSAndroid Build Coastguard Worker  * limitations under the License.
15*4d7e907cSAndroid Build Coastguard Worker  */
16*4d7e907cSAndroid Build Coastguard Worker 
17*4d7e907cSAndroid Build Coastguard Worker #define LOG_TAG "BTAudioProviderLeAudioHW"
18*4d7e907cSAndroid Build Coastguard Worker 
19*4d7e907cSAndroid Build Coastguard Worker #include "LeAudioOffloadAudioProvider.h"
20*4d7e907cSAndroid Build Coastguard Worker 
21*4d7e907cSAndroid Build Coastguard Worker #include <BluetoothAudioCodecs.h>
22*4d7e907cSAndroid Build Coastguard Worker #include <BluetoothAudioSessionReport.h>
23*4d7e907cSAndroid Build Coastguard Worker #include <android-base/logging.h>
24*4d7e907cSAndroid Build Coastguard Worker 
25*4d7e907cSAndroid Build Coastguard Worker namespace aidl {
26*4d7e907cSAndroid Build Coastguard Worker namespace android {
27*4d7e907cSAndroid Build Coastguard Worker namespace hardware {
28*4d7e907cSAndroid Build Coastguard Worker namespace bluetooth {
29*4d7e907cSAndroid Build Coastguard Worker namespace audio {
30*4d7e907cSAndroid Build Coastguard Worker 
31*4d7e907cSAndroid Build Coastguard Worker constexpr uint8_t kLeAudioDirectionSink = 0x01;
32*4d7e907cSAndroid Build Coastguard Worker constexpr uint8_t kLeAudioDirectionSource = 0x02;
33*4d7e907cSAndroid Build Coastguard Worker constexpr uint8_t kIsoDataPathHci = 0x00;
34*4d7e907cSAndroid Build Coastguard Worker constexpr uint8_t kIsoDataPathPlatformDefault = 0x01;
35*4d7e907cSAndroid Build Coastguard Worker 
36*4d7e907cSAndroid Build Coastguard Worker const std::map<CodecSpecificConfigurationLtv::SamplingFrequency, uint32_t>
37*4d7e907cSAndroid Build Coastguard Worker     freq_to_support_bitmask_map = {
38*4d7e907cSAndroid Build Coastguard Worker         {CodecSpecificConfigurationLtv::SamplingFrequency::HZ8000,
39*4d7e907cSAndroid Build Coastguard Worker          CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ8000},
40*4d7e907cSAndroid Build Coastguard Worker         {CodecSpecificConfigurationLtv::SamplingFrequency::HZ11025,
41*4d7e907cSAndroid Build Coastguard Worker          CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ11025},
42*4d7e907cSAndroid Build Coastguard Worker         {CodecSpecificConfigurationLtv::SamplingFrequency::HZ16000,
43*4d7e907cSAndroid Build Coastguard Worker          CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ16000},
44*4d7e907cSAndroid Build Coastguard Worker         {CodecSpecificConfigurationLtv::SamplingFrequency::HZ22050,
45*4d7e907cSAndroid Build Coastguard Worker          CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ22050},
46*4d7e907cSAndroid Build Coastguard Worker         {CodecSpecificConfigurationLtv::SamplingFrequency::HZ24000,
47*4d7e907cSAndroid Build Coastguard Worker          CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ24000},
48*4d7e907cSAndroid Build Coastguard Worker         {CodecSpecificConfigurationLtv::SamplingFrequency::HZ32000,
49*4d7e907cSAndroid Build Coastguard Worker          CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ32000},
50*4d7e907cSAndroid Build Coastguard Worker         {CodecSpecificConfigurationLtv::SamplingFrequency::HZ48000,
51*4d7e907cSAndroid Build Coastguard Worker          CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ48000},
52*4d7e907cSAndroid Build Coastguard Worker         {CodecSpecificConfigurationLtv::SamplingFrequency::HZ88200,
53*4d7e907cSAndroid Build Coastguard Worker          CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ88200},
54*4d7e907cSAndroid Build Coastguard Worker         {CodecSpecificConfigurationLtv::SamplingFrequency::HZ96000,
55*4d7e907cSAndroid Build Coastguard Worker          CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ96000},
56*4d7e907cSAndroid Build Coastguard Worker         {CodecSpecificConfigurationLtv::SamplingFrequency::HZ176400,
57*4d7e907cSAndroid Build Coastguard Worker          CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ176400},
58*4d7e907cSAndroid Build Coastguard Worker         {CodecSpecificConfigurationLtv::SamplingFrequency::HZ192000,
59*4d7e907cSAndroid Build Coastguard Worker          CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ192000},
60*4d7e907cSAndroid Build Coastguard Worker         {CodecSpecificConfigurationLtv::SamplingFrequency::HZ384000,
61*4d7e907cSAndroid Build Coastguard Worker          CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ384000},
62*4d7e907cSAndroid Build Coastguard Worker };
63*4d7e907cSAndroid Build Coastguard Worker 
64*4d7e907cSAndroid Build Coastguard Worker // Helper map from capability's tag to configuration's tag
65*4d7e907cSAndroid Build Coastguard Worker std::map<CodecSpecificCapabilitiesLtv::Tag, CodecSpecificConfigurationLtv::Tag>
66*4d7e907cSAndroid Build Coastguard Worker     cap_to_cfg_tag_map = {
67*4d7e907cSAndroid Build Coastguard Worker         {CodecSpecificCapabilitiesLtv::Tag::supportedSamplingFrequencies,
68*4d7e907cSAndroid Build Coastguard Worker          CodecSpecificConfigurationLtv::Tag::samplingFrequency},
69*4d7e907cSAndroid Build Coastguard Worker         {CodecSpecificCapabilitiesLtv::Tag::supportedMaxCodecFramesPerSDU,
70*4d7e907cSAndroid Build Coastguard Worker          CodecSpecificConfigurationLtv::Tag::codecFrameBlocksPerSDU},
71*4d7e907cSAndroid Build Coastguard Worker         {CodecSpecificCapabilitiesLtv::Tag::supportedFrameDurations,
72*4d7e907cSAndroid Build Coastguard Worker          CodecSpecificConfigurationLtv::Tag::frameDuration},
73*4d7e907cSAndroid Build Coastguard Worker         {CodecSpecificCapabilitiesLtv::Tag::supportedAudioChannelCounts,
74*4d7e907cSAndroid Build Coastguard Worker          CodecSpecificConfigurationLtv::Tag::audioChannelAllocation},
75*4d7e907cSAndroid Build Coastguard Worker         {CodecSpecificCapabilitiesLtv::Tag::supportedOctetsPerCodecFrame,
76*4d7e907cSAndroid Build Coastguard Worker          CodecSpecificConfigurationLtv::Tag::octetsPerCodecFrame},
77*4d7e907cSAndroid Build Coastguard Worker };
78*4d7e907cSAndroid Build Coastguard Worker 
79*4d7e907cSAndroid Build Coastguard Worker const std::map<CodecSpecificConfigurationLtv::FrameDuration, uint32_t>
80*4d7e907cSAndroid Build Coastguard Worker     fduration_to_support_fduration_map = {
81*4d7e907cSAndroid Build Coastguard Worker         {CodecSpecificConfigurationLtv::FrameDuration::US7500,
82*4d7e907cSAndroid Build Coastguard Worker          CodecSpecificCapabilitiesLtv::SupportedFrameDurations::US7500},
83*4d7e907cSAndroid Build Coastguard Worker         {CodecSpecificConfigurationLtv::FrameDuration::US10000,
84*4d7e907cSAndroid Build Coastguard Worker          CodecSpecificCapabilitiesLtv::SupportedFrameDurations::US10000},
85*4d7e907cSAndroid Build Coastguard Worker         {CodecSpecificConfigurationLtv::FrameDuration::US20000,
86*4d7e907cSAndroid Build Coastguard Worker          CodecSpecificCapabilitiesLtv::SupportedFrameDurations::US20000},
87*4d7e907cSAndroid Build Coastguard Worker };
88*4d7e907cSAndroid Build Coastguard Worker 
89*4d7e907cSAndroid Build Coastguard Worker std::map<int32_t, CodecSpecificConfigurationLtv::SamplingFrequency>
90*4d7e907cSAndroid Build Coastguard Worker     sampling_freq_map = {
91*4d7e907cSAndroid Build Coastguard Worker         {16000, CodecSpecificConfigurationLtv::SamplingFrequency::HZ16000},
92*4d7e907cSAndroid Build Coastguard Worker         {24000, CodecSpecificConfigurationLtv::SamplingFrequency::HZ24000},
93*4d7e907cSAndroid Build Coastguard Worker         {48000, CodecSpecificConfigurationLtv::SamplingFrequency::HZ48000},
94*4d7e907cSAndroid Build Coastguard Worker         {96000, CodecSpecificConfigurationLtv::SamplingFrequency::HZ96000},
95*4d7e907cSAndroid Build Coastguard Worker };
96*4d7e907cSAndroid Build Coastguard Worker 
97*4d7e907cSAndroid Build Coastguard Worker std::map<int32_t, CodecSpecificConfigurationLtv::FrameDuration>
98*4d7e907cSAndroid Build Coastguard Worker     frame_duration_map = {
99*4d7e907cSAndroid Build Coastguard Worker         {7500, CodecSpecificConfigurationLtv::FrameDuration::US7500},
100*4d7e907cSAndroid Build Coastguard Worker         {10000, CodecSpecificConfigurationLtv::FrameDuration::US10000},
101*4d7e907cSAndroid Build Coastguard Worker };
102*4d7e907cSAndroid Build Coastguard Worker 
LeAudioOffloadOutputAudioProvider()103*4d7e907cSAndroid Build Coastguard Worker LeAudioOffloadOutputAudioProvider::LeAudioOffloadOutputAudioProvider()
104*4d7e907cSAndroid Build Coastguard Worker     : LeAudioOffloadAudioProvider() {
105*4d7e907cSAndroid Build Coastguard Worker   session_type_ = SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH;
106*4d7e907cSAndroid Build Coastguard Worker }
107*4d7e907cSAndroid Build Coastguard Worker 
LeAudioOffloadInputAudioProvider()108*4d7e907cSAndroid Build Coastguard Worker LeAudioOffloadInputAudioProvider::LeAudioOffloadInputAudioProvider()
109*4d7e907cSAndroid Build Coastguard Worker     : LeAudioOffloadAudioProvider() {
110*4d7e907cSAndroid Build Coastguard Worker   session_type_ = SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH;
111*4d7e907cSAndroid Build Coastguard Worker }
112*4d7e907cSAndroid Build Coastguard Worker 
LeAudioOffloadBroadcastAudioProvider()113*4d7e907cSAndroid Build Coastguard Worker LeAudioOffloadBroadcastAudioProvider::LeAudioOffloadBroadcastAudioProvider()
114*4d7e907cSAndroid Build Coastguard Worker     : LeAudioOffloadAudioProvider() {
115*4d7e907cSAndroid Build Coastguard Worker   session_type_ =
116*4d7e907cSAndroid Build Coastguard Worker       SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH;
117*4d7e907cSAndroid Build Coastguard Worker }
118*4d7e907cSAndroid Build Coastguard Worker 
LeAudioOffloadAudioProvider()119*4d7e907cSAndroid Build Coastguard Worker LeAudioOffloadAudioProvider::LeAudioOffloadAudioProvider()
120*4d7e907cSAndroid Build Coastguard Worker     : BluetoothAudioProvider() {}
121*4d7e907cSAndroid Build Coastguard Worker 
isValid(const SessionType & sessionType)122*4d7e907cSAndroid Build Coastguard Worker bool LeAudioOffloadAudioProvider::isValid(const SessionType& sessionType) {
123*4d7e907cSAndroid Build Coastguard Worker   return (sessionType == session_type_);
124*4d7e907cSAndroid Build Coastguard Worker }
125*4d7e907cSAndroid Build Coastguard Worker 
getSettingOutputString(IBluetoothAudioProvider::LeAudioAseConfigurationSetting & setting)126*4d7e907cSAndroid Build Coastguard Worker std::string getSettingOutputString(
127*4d7e907cSAndroid Build Coastguard Worker     IBluetoothAudioProvider::LeAudioAseConfigurationSetting& setting) {
128*4d7e907cSAndroid Build Coastguard Worker   std::stringstream ss;
129*4d7e907cSAndroid Build Coastguard Worker   std::string name = "";
130*4d7e907cSAndroid Build Coastguard Worker   if (!setting.sinkAseConfiguration.has_value() &&
131*4d7e907cSAndroid Build Coastguard Worker       !setting.sourceAseConfiguration.has_value())
132*4d7e907cSAndroid Build Coastguard Worker     return "";
133*4d7e907cSAndroid Build Coastguard Worker   std::vector<
134*4d7e907cSAndroid Build Coastguard Worker       std::optional<LeAudioAseConfigurationSetting::AseDirectionConfiguration>>*
135*4d7e907cSAndroid Build Coastguard Worker       directionAseConfiguration;
136*4d7e907cSAndroid Build Coastguard Worker   if (setting.sinkAseConfiguration.has_value() &&
137*4d7e907cSAndroid Build Coastguard Worker       !setting.sinkAseConfiguration.value().empty())
138*4d7e907cSAndroid Build Coastguard Worker     directionAseConfiguration = &setting.sinkAseConfiguration.value();
139*4d7e907cSAndroid Build Coastguard Worker   else
140*4d7e907cSAndroid Build Coastguard Worker     directionAseConfiguration = &setting.sourceAseConfiguration.value();
141*4d7e907cSAndroid Build Coastguard Worker   for (auto& aseConfiguration : *directionAseConfiguration) {
142*4d7e907cSAndroid Build Coastguard Worker     if (aseConfiguration.has_value() &&
143*4d7e907cSAndroid Build Coastguard Worker         aseConfiguration.value().aseConfiguration.metadata.has_value()) {
144*4d7e907cSAndroid Build Coastguard Worker       for (auto& meta :
145*4d7e907cSAndroid Build Coastguard Worker            aseConfiguration.value().aseConfiguration.metadata.value()) {
146*4d7e907cSAndroid Build Coastguard Worker         if (meta.has_value() &&
147*4d7e907cSAndroid Build Coastguard Worker             meta.value().getTag() == MetadataLtv::vendorSpecific) {
148*4d7e907cSAndroid Build Coastguard Worker           auto k = meta.value().get<MetadataLtv::vendorSpecific>().opaqueValue;
149*4d7e907cSAndroid Build Coastguard Worker           name = std::string(k.begin(), k.end());
150*4d7e907cSAndroid Build Coastguard Worker           break;
151*4d7e907cSAndroid Build Coastguard Worker         }
152*4d7e907cSAndroid Build Coastguard Worker       }
153*4d7e907cSAndroid Build Coastguard Worker     }
154*4d7e907cSAndroid Build Coastguard Worker   }
155*4d7e907cSAndroid Build Coastguard Worker 
156*4d7e907cSAndroid Build Coastguard Worker   ss << "setting name: " << name << ", setting: " << setting.toString();
157*4d7e907cSAndroid Build Coastguard Worker   return ss.str();
158*4d7e907cSAndroid Build Coastguard Worker }
159*4d7e907cSAndroid Build Coastguard Worker 
startSession(const std::shared_ptr<IBluetoothAudioPort> & host_if,const AudioConfiguration & audio_config,const std::vector<LatencyMode> & latency_modes,DataMQDesc * _aidl_return)160*4d7e907cSAndroid Build Coastguard Worker ndk::ScopedAStatus LeAudioOffloadAudioProvider::startSession(
161*4d7e907cSAndroid Build Coastguard Worker     const std::shared_ptr<IBluetoothAudioPort>& host_if,
162*4d7e907cSAndroid Build Coastguard Worker     const AudioConfiguration& audio_config,
163*4d7e907cSAndroid Build Coastguard Worker     const std::vector<LatencyMode>& latency_modes, DataMQDesc* _aidl_return) {
164*4d7e907cSAndroid Build Coastguard Worker   if (session_type_ ==
165*4d7e907cSAndroid Build Coastguard Worker       SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
166*4d7e907cSAndroid Build Coastguard Worker     if (audio_config.getTag() != AudioConfiguration::leAudioBroadcastConfig) {
167*4d7e907cSAndroid Build Coastguard Worker       LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
168*4d7e907cSAndroid Build Coastguard Worker                    << audio_config.toString();
169*4d7e907cSAndroid Build Coastguard Worker       *_aidl_return = DataMQDesc();
170*4d7e907cSAndroid Build Coastguard Worker       return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
171*4d7e907cSAndroid Build Coastguard Worker     }
172*4d7e907cSAndroid Build Coastguard Worker   } else if (audio_config.getTag() != AudioConfiguration::leAudioConfig) {
173*4d7e907cSAndroid Build Coastguard Worker     LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
174*4d7e907cSAndroid Build Coastguard Worker                  << audio_config.toString();
175*4d7e907cSAndroid Build Coastguard Worker     *_aidl_return = DataMQDesc();
176*4d7e907cSAndroid Build Coastguard Worker     return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
177*4d7e907cSAndroid Build Coastguard Worker   }
178*4d7e907cSAndroid Build Coastguard Worker 
179*4d7e907cSAndroid Build Coastguard Worker   return BluetoothAudioProvider::startSession(host_if, audio_config,
180*4d7e907cSAndroid Build Coastguard Worker                                               latency_modes, _aidl_return);
181*4d7e907cSAndroid Build Coastguard Worker }
182*4d7e907cSAndroid Build Coastguard Worker 
onSessionReady(DataMQDesc * _aidl_return)183*4d7e907cSAndroid Build Coastguard Worker ndk::ScopedAStatus LeAudioOffloadAudioProvider::onSessionReady(
184*4d7e907cSAndroid Build Coastguard Worker     DataMQDesc* _aidl_return) {
185*4d7e907cSAndroid Build Coastguard Worker   BluetoothAudioSessionReport::OnSessionStarted(
186*4d7e907cSAndroid Build Coastguard Worker       session_type_, stack_iface_, nullptr, *audio_config_, latency_modes_);
187*4d7e907cSAndroid Build Coastguard Worker   *_aidl_return = DataMQDesc();
188*4d7e907cSAndroid Build Coastguard Worker   return ndk::ScopedAStatus::ok();
189*4d7e907cSAndroid Build Coastguard Worker }
setCodecPriority(const CodecId & in_codecId,int32_t in_priority)190*4d7e907cSAndroid Build Coastguard Worker ndk::ScopedAStatus LeAudioOffloadAudioProvider::setCodecPriority(
191*4d7e907cSAndroid Build Coastguard Worker     const CodecId& in_codecId, int32_t in_priority) {
192*4d7e907cSAndroid Build Coastguard Worker   codec_priority_map_[in_codecId] = in_priority;
193*4d7e907cSAndroid Build Coastguard Worker   return ndk::ScopedAStatus::ok();
194*4d7e907cSAndroid Build Coastguard Worker };
195*4d7e907cSAndroid Build Coastguard Worker 
isMatchedValidCodec(CodecId cfg_codec,CodecId req_codec)196*4d7e907cSAndroid Build Coastguard Worker bool LeAudioOffloadAudioProvider::isMatchedValidCodec(CodecId cfg_codec,
197*4d7e907cSAndroid Build Coastguard Worker                                                       CodecId req_codec) {
198*4d7e907cSAndroid Build Coastguard Worker   auto priority = codec_priority_map_.find(cfg_codec);
199*4d7e907cSAndroid Build Coastguard Worker   if (priority != codec_priority_map_.end() &&
200*4d7e907cSAndroid Build Coastguard Worker       priority->second ==
201*4d7e907cSAndroid Build Coastguard Worker           LeAudioOffloadAudioProvider::CODEC_PRIORITY_DISABLED) {
202*4d7e907cSAndroid Build Coastguard Worker     return false;
203*4d7e907cSAndroid Build Coastguard Worker   }
204*4d7e907cSAndroid Build Coastguard Worker   return cfg_codec == req_codec;
205*4d7e907cSAndroid Build Coastguard Worker }
206*4d7e907cSAndroid Build Coastguard Worker 
filterCapabilitiesMatchedContext(AudioContext & setting_context,const IBluetoothAudioProvider::LeAudioDeviceCapabilities & capabilities)207*4d7e907cSAndroid Build Coastguard Worker bool LeAudioOffloadAudioProvider::filterCapabilitiesMatchedContext(
208*4d7e907cSAndroid Build Coastguard Worker     AudioContext& setting_context,
209*4d7e907cSAndroid Build Coastguard Worker     const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities) {
210*4d7e907cSAndroid Build Coastguard Worker   // If has no metadata, assume match
211*4d7e907cSAndroid Build Coastguard Worker   if (!capabilities.metadata.has_value()) return true;
212*4d7e907cSAndroid Build Coastguard Worker 
213*4d7e907cSAndroid Build Coastguard Worker   for (auto metadata : capabilities.metadata.value()) {
214*4d7e907cSAndroid Build Coastguard Worker     if (!metadata.has_value()) continue;
215*4d7e907cSAndroid Build Coastguard Worker     if (metadata.value().getTag() == MetadataLtv::Tag::preferredAudioContexts) {
216*4d7e907cSAndroid Build Coastguard Worker       // Check all pref audio context to see if anything matched
217*4d7e907cSAndroid Build Coastguard Worker       auto& prefer_context =
218*4d7e907cSAndroid Build Coastguard Worker           metadata.value()
219*4d7e907cSAndroid Build Coastguard Worker               .get<MetadataLtv::Tag::preferredAudioContexts>()
220*4d7e907cSAndroid Build Coastguard Worker               .values;
221*4d7e907cSAndroid Build Coastguard Worker       if (setting_context.bitmask & prefer_context.bitmask) {
222*4d7e907cSAndroid Build Coastguard Worker         // New mask with matched capability
223*4d7e907cSAndroid Build Coastguard Worker         setting_context.bitmask &= prefer_context.bitmask;
224*4d7e907cSAndroid Build Coastguard Worker         return true;
225*4d7e907cSAndroid Build Coastguard Worker       }
226*4d7e907cSAndroid Build Coastguard Worker     }
227*4d7e907cSAndroid Build Coastguard Worker   }
228*4d7e907cSAndroid Build Coastguard Worker 
229*4d7e907cSAndroid Build Coastguard Worker   return false;
230*4d7e907cSAndroid Build Coastguard Worker }
231*4d7e907cSAndroid Build Coastguard Worker 
isMatchedSamplingFreq(CodecSpecificConfigurationLtv::SamplingFrequency & cfg_freq,CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies & capability_freq)232*4d7e907cSAndroid Build Coastguard Worker bool LeAudioOffloadAudioProvider::isMatchedSamplingFreq(
233*4d7e907cSAndroid Build Coastguard Worker     CodecSpecificConfigurationLtv::SamplingFrequency& cfg_freq,
234*4d7e907cSAndroid Build Coastguard Worker     CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies&
235*4d7e907cSAndroid Build Coastguard Worker         capability_freq) {
236*4d7e907cSAndroid Build Coastguard Worker   auto p = freq_to_support_bitmask_map.find(cfg_freq);
237*4d7e907cSAndroid Build Coastguard Worker   if (p != freq_to_support_bitmask_map.end()) {
238*4d7e907cSAndroid Build Coastguard Worker     if (capability_freq.bitmask & p->second) {
239*4d7e907cSAndroid Build Coastguard Worker       return true;
240*4d7e907cSAndroid Build Coastguard Worker     }
241*4d7e907cSAndroid Build Coastguard Worker   }
242*4d7e907cSAndroid Build Coastguard Worker   return false;
243*4d7e907cSAndroid Build Coastguard Worker }
244*4d7e907cSAndroid Build Coastguard Worker 
isMatchedFrameDuration(CodecSpecificConfigurationLtv::FrameDuration & cfg_fduration,CodecSpecificCapabilitiesLtv::SupportedFrameDurations & capability_fduration)245*4d7e907cSAndroid Build Coastguard Worker bool LeAudioOffloadAudioProvider::isMatchedFrameDuration(
246*4d7e907cSAndroid Build Coastguard Worker     CodecSpecificConfigurationLtv::FrameDuration& cfg_fduration,
247*4d7e907cSAndroid Build Coastguard Worker     CodecSpecificCapabilitiesLtv::SupportedFrameDurations&
248*4d7e907cSAndroid Build Coastguard Worker         capability_fduration) {
249*4d7e907cSAndroid Build Coastguard Worker   auto p = fduration_to_support_fduration_map.find(cfg_fduration);
250*4d7e907cSAndroid Build Coastguard Worker   if (p != fduration_to_support_fduration_map.end())
251*4d7e907cSAndroid Build Coastguard Worker     if (capability_fduration.bitmask & p->second) {
252*4d7e907cSAndroid Build Coastguard Worker       return true;
253*4d7e907cSAndroid Build Coastguard Worker     }
254*4d7e907cSAndroid Build Coastguard Worker   return false;
255*4d7e907cSAndroid Build Coastguard Worker }
256*4d7e907cSAndroid Build Coastguard Worker 
getCountFromBitmask(int bitmask)257*4d7e907cSAndroid Build Coastguard Worker int getCountFromBitmask(int bitmask) {
258*4d7e907cSAndroid Build Coastguard Worker   return std::bitset<32>(bitmask).count();
259*4d7e907cSAndroid Build Coastguard Worker }
260*4d7e907cSAndroid Build Coastguard Worker 
isMatchedAudioChannel(CodecSpecificConfigurationLtv::AudioChannelAllocation & cfg_channel,CodecSpecificCapabilitiesLtv::SupportedAudioChannelCounts & capability_channel)261*4d7e907cSAndroid Build Coastguard Worker bool LeAudioOffloadAudioProvider::isMatchedAudioChannel(
262*4d7e907cSAndroid Build Coastguard Worker     CodecSpecificConfigurationLtv::AudioChannelAllocation& cfg_channel,
263*4d7e907cSAndroid Build Coastguard Worker     CodecSpecificCapabilitiesLtv::SupportedAudioChannelCounts&
264*4d7e907cSAndroid Build Coastguard Worker         capability_channel) {
265*4d7e907cSAndroid Build Coastguard Worker   int count = getCountFromBitmask(cfg_channel.bitmask);
266*4d7e907cSAndroid Build Coastguard Worker   if (count == 1 &&
267*4d7e907cSAndroid Build Coastguard Worker       !(capability_channel.bitmask &
268*4d7e907cSAndroid Build Coastguard Worker         CodecSpecificCapabilitiesLtv::SupportedAudioChannelCounts::ONE))
269*4d7e907cSAndroid Build Coastguard Worker     return false;
270*4d7e907cSAndroid Build Coastguard Worker   if (count == 2 &&
271*4d7e907cSAndroid Build Coastguard Worker       !(capability_channel.bitmask &
272*4d7e907cSAndroid Build Coastguard Worker         CodecSpecificCapabilitiesLtv::SupportedAudioChannelCounts::TWO))
273*4d7e907cSAndroid Build Coastguard Worker     return false;
274*4d7e907cSAndroid Build Coastguard Worker   return true;
275*4d7e907cSAndroid Build Coastguard Worker }
276*4d7e907cSAndroid Build Coastguard Worker 
isMatchedCodecFramesPerSDU(CodecSpecificConfigurationLtv::CodecFrameBlocksPerSDU & cfg_frame_sdu,CodecSpecificCapabilitiesLtv::SupportedMaxCodecFramesPerSDU & capability_frame_sdu)277*4d7e907cSAndroid Build Coastguard Worker bool LeAudioOffloadAudioProvider::isMatchedCodecFramesPerSDU(
278*4d7e907cSAndroid Build Coastguard Worker     CodecSpecificConfigurationLtv::CodecFrameBlocksPerSDU& cfg_frame_sdu,
279*4d7e907cSAndroid Build Coastguard Worker     CodecSpecificCapabilitiesLtv::SupportedMaxCodecFramesPerSDU&
280*4d7e907cSAndroid Build Coastguard Worker         capability_frame_sdu) {
281*4d7e907cSAndroid Build Coastguard Worker   return cfg_frame_sdu.value <= capability_frame_sdu.value;
282*4d7e907cSAndroid Build Coastguard Worker }
283*4d7e907cSAndroid Build Coastguard Worker 
isMatchedOctetsPerCodecFrame(CodecSpecificConfigurationLtv::OctetsPerCodecFrame & cfg_octets,CodecSpecificCapabilitiesLtv::SupportedOctetsPerCodecFrame & capability_octets)284*4d7e907cSAndroid Build Coastguard Worker bool LeAudioOffloadAudioProvider::isMatchedOctetsPerCodecFrame(
285*4d7e907cSAndroid Build Coastguard Worker     CodecSpecificConfigurationLtv::OctetsPerCodecFrame& cfg_octets,
286*4d7e907cSAndroid Build Coastguard Worker     CodecSpecificCapabilitiesLtv::SupportedOctetsPerCodecFrame&
287*4d7e907cSAndroid Build Coastguard Worker         capability_octets) {
288*4d7e907cSAndroid Build Coastguard Worker   return cfg_octets.value >= capability_octets.min &&
289*4d7e907cSAndroid Build Coastguard Worker          cfg_octets.value <= capability_octets.max;
290*4d7e907cSAndroid Build Coastguard Worker }
291*4d7e907cSAndroid Build Coastguard Worker 
isCapabilitiesMatchedCodecConfiguration(std::vector<CodecSpecificConfigurationLtv> & codec_cfg,std::vector<CodecSpecificCapabilitiesLtv> codec_capabilities)292*4d7e907cSAndroid Build Coastguard Worker bool LeAudioOffloadAudioProvider::isCapabilitiesMatchedCodecConfiguration(
293*4d7e907cSAndroid Build Coastguard Worker     std::vector<CodecSpecificConfigurationLtv>& codec_cfg,
294*4d7e907cSAndroid Build Coastguard Worker     std::vector<CodecSpecificCapabilitiesLtv> codec_capabilities) {
295*4d7e907cSAndroid Build Coastguard Worker   // Convert all codec_cfg into a map of tags -> correct data
296*4d7e907cSAndroid Build Coastguard Worker   std::map<CodecSpecificConfigurationLtv::Tag, CodecSpecificConfigurationLtv>
297*4d7e907cSAndroid Build Coastguard Worker       cfg_tag_map;
298*4d7e907cSAndroid Build Coastguard Worker   for (auto codec_cfg_data : codec_cfg)
299*4d7e907cSAndroid Build Coastguard Worker     cfg_tag_map[codec_cfg_data.getTag()] = codec_cfg_data;
300*4d7e907cSAndroid Build Coastguard Worker 
301*4d7e907cSAndroid Build Coastguard Worker   for (auto& codec_capability : codec_capabilities) {
302*4d7e907cSAndroid Build Coastguard Worker     auto cfg = cfg_tag_map.find(cap_to_cfg_tag_map[codec_capability.getTag()]);
303*4d7e907cSAndroid Build Coastguard Worker     // If capability has this tag, but our configuration doesn't
304*4d7e907cSAndroid Build Coastguard Worker     // Then we will assume it is matched
305*4d7e907cSAndroid Build Coastguard Worker     if (cfg == cfg_tag_map.end()) {
306*4d7e907cSAndroid Build Coastguard Worker       continue;
307*4d7e907cSAndroid Build Coastguard Worker     }
308*4d7e907cSAndroid Build Coastguard Worker 
309*4d7e907cSAndroid Build Coastguard Worker     switch (codec_capability.getTag()) {
310*4d7e907cSAndroid Build Coastguard Worker       case CodecSpecificCapabilitiesLtv::Tag::supportedSamplingFrequencies: {
311*4d7e907cSAndroid Build Coastguard Worker         if (!isMatchedSamplingFreq(
312*4d7e907cSAndroid Build Coastguard Worker                 cfg->second.get<
313*4d7e907cSAndroid Build Coastguard Worker                     CodecSpecificConfigurationLtv::Tag::samplingFrequency>(),
314*4d7e907cSAndroid Build Coastguard Worker                 codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
315*4d7e907cSAndroid Build Coastguard Worker                                          supportedSamplingFrequencies>())) {
316*4d7e907cSAndroid Build Coastguard Worker           return false;
317*4d7e907cSAndroid Build Coastguard Worker         }
318*4d7e907cSAndroid Build Coastguard Worker         break;
319*4d7e907cSAndroid Build Coastguard Worker       }
320*4d7e907cSAndroid Build Coastguard Worker 
321*4d7e907cSAndroid Build Coastguard Worker       case CodecSpecificCapabilitiesLtv::Tag::supportedFrameDurations: {
322*4d7e907cSAndroid Build Coastguard Worker         if (!isMatchedFrameDuration(
323*4d7e907cSAndroid Build Coastguard Worker                 cfg->second
324*4d7e907cSAndroid Build Coastguard Worker                     .get<CodecSpecificConfigurationLtv::Tag::frameDuration>(),
325*4d7e907cSAndroid Build Coastguard Worker                 codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
326*4d7e907cSAndroid Build Coastguard Worker                                          supportedFrameDurations>())) {
327*4d7e907cSAndroid Build Coastguard Worker           return false;
328*4d7e907cSAndroid Build Coastguard Worker         }
329*4d7e907cSAndroid Build Coastguard Worker         break;
330*4d7e907cSAndroid Build Coastguard Worker       }
331*4d7e907cSAndroid Build Coastguard Worker 
332*4d7e907cSAndroid Build Coastguard Worker       case CodecSpecificCapabilitiesLtv::Tag::supportedAudioChannelCounts: {
333*4d7e907cSAndroid Build Coastguard Worker         if (!isMatchedAudioChannel(
334*4d7e907cSAndroid Build Coastguard Worker                 cfg->second.get<CodecSpecificConfigurationLtv::Tag::
335*4d7e907cSAndroid Build Coastguard Worker                                     audioChannelAllocation>(),
336*4d7e907cSAndroid Build Coastguard Worker                 codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
337*4d7e907cSAndroid Build Coastguard Worker                                          supportedAudioChannelCounts>())) {
338*4d7e907cSAndroid Build Coastguard Worker           return false;
339*4d7e907cSAndroid Build Coastguard Worker         }
340*4d7e907cSAndroid Build Coastguard Worker         break;
341*4d7e907cSAndroid Build Coastguard Worker       }
342*4d7e907cSAndroid Build Coastguard Worker 
343*4d7e907cSAndroid Build Coastguard Worker       case CodecSpecificCapabilitiesLtv::Tag::supportedMaxCodecFramesPerSDU: {
344*4d7e907cSAndroid Build Coastguard Worker         if (!isMatchedCodecFramesPerSDU(
345*4d7e907cSAndroid Build Coastguard Worker                 cfg->second.get<CodecSpecificConfigurationLtv::Tag::
346*4d7e907cSAndroid Build Coastguard Worker                                     codecFrameBlocksPerSDU>(),
347*4d7e907cSAndroid Build Coastguard Worker                 codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
348*4d7e907cSAndroid Build Coastguard Worker                                          supportedMaxCodecFramesPerSDU>())) {
349*4d7e907cSAndroid Build Coastguard Worker           return false;
350*4d7e907cSAndroid Build Coastguard Worker         }
351*4d7e907cSAndroid Build Coastguard Worker         break;
352*4d7e907cSAndroid Build Coastguard Worker       }
353*4d7e907cSAndroid Build Coastguard Worker 
354*4d7e907cSAndroid Build Coastguard Worker       case CodecSpecificCapabilitiesLtv::Tag::supportedOctetsPerCodecFrame: {
355*4d7e907cSAndroid Build Coastguard Worker         if (!isMatchedOctetsPerCodecFrame(
356*4d7e907cSAndroid Build Coastguard Worker                 cfg->second.get<
357*4d7e907cSAndroid Build Coastguard Worker                     CodecSpecificConfigurationLtv::Tag::octetsPerCodecFrame>(),
358*4d7e907cSAndroid Build Coastguard Worker                 codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
359*4d7e907cSAndroid Build Coastguard Worker                                          supportedOctetsPerCodecFrame>())) {
360*4d7e907cSAndroid Build Coastguard Worker           return false;
361*4d7e907cSAndroid Build Coastguard Worker         }
362*4d7e907cSAndroid Build Coastguard Worker         break;
363*4d7e907cSAndroid Build Coastguard Worker       }
364*4d7e907cSAndroid Build Coastguard Worker     }
365*4d7e907cSAndroid Build Coastguard Worker   }
366*4d7e907cSAndroid Build Coastguard Worker 
367*4d7e907cSAndroid Build Coastguard Worker   return true;
368*4d7e907cSAndroid Build Coastguard Worker }
369*4d7e907cSAndroid Build Coastguard Worker 
filterMatchedAseConfiguration(LeAudioAseConfiguration & setting_cfg,const LeAudioAseConfiguration & requirement_cfg)370*4d7e907cSAndroid Build Coastguard Worker bool LeAudioOffloadAudioProvider::filterMatchedAseConfiguration(
371*4d7e907cSAndroid Build Coastguard Worker     LeAudioAseConfiguration& setting_cfg,
372*4d7e907cSAndroid Build Coastguard Worker     const LeAudioAseConfiguration& requirement_cfg) {
373*4d7e907cSAndroid Build Coastguard Worker   // Check matching for codec configuration <=> requirement ASE codec
374*4d7e907cSAndroid Build Coastguard Worker   // Also match if no CodecId requirement
375*4d7e907cSAndroid Build Coastguard Worker   if (requirement_cfg.codecId.has_value()) {
376*4d7e907cSAndroid Build Coastguard Worker     if (!setting_cfg.codecId.has_value()) return false;
377*4d7e907cSAndroid Build Coastguard Worker     if (!isMatchedValidCodec(setting_cfg.codecId.value(),
378*4d7e907cSAndroid Build Coastguard Worker                              requirement_cfg.codecId.value())) {
379*4d7e907cSAndroid Build Coastguard Worker       return false;
380*4d7e907cSAndroid Build Coastguard Worker     }
381*4d7e907cSAndroid Build Coastguard Worker   }
382*4d7e907cSAndroid Build Coastguard Worker 
383*4d7e907cSAndroid Build Coastguard Worker   if (requirement_cfg.targetLatency !=
384*4d7e907cSAndroid Build Coastguard Worker           LeAudioAseConfiguration::TargetLatency::UNDEFINED &&
385*4d7e907cSAndroid Build Coastguard Worker       setting_cfg.targetLatency != requirement_cfg.targetLatency) {
386*4d7e907cSAndroid Build Coastguard Worker     return false;
387*4d7e907cSAndroid Build Coastguard Worker   }
388*4d7e907cSAndroid Build Coastguard Worker   // Ignore PHY requirement
389*4d7e907cSAndroid Build Coastguard Worker 
390*4d7e907cSAndroid Build Coastguard Worker   // Check all codec configuration
391*4d7e907cSAndroid Build Coastguard Worker   std::map<CodecSpecificConfigurationLtv::Tag, CodecSpecificConfigurationLtv>
392*4d7e907cSAndroid Build Coastguard Worker       cfg_tag_map;
393*4d7e907cSAndroid Build Coastguard Worker   for (auto cfg : setting_cfg.codecConfiguration)
394*4d7e907cSAndroid Build Coastguard Worker     cfg_tag_map[cfg.getTag()] = cfg;
395*4d7e907cSAndroid Build Coastguard Worker 
396*4d7e907cSAndroid Build Coastguard Worker   for (auto requirement_cfg : requirement_cfg.codecConfiguration) {
397*4d7e907cSAndroid Build Coastguard Worker     // Directly compare CodecSpecificConfigurationLtv
398*4d7e907cSAndroid Build Coastguard Worker     auto cfg = cfg_tag_map.find(requirement_cfg.getTag());
399*4d7e907cSAndroid Build Coastguard Worker     // Config not found for this requirement, cannot match
400*4d7e907cSAndroid Build Coastguard Worker     if (cfg == cfg_tag_map.end()) {
401*4d7e907cSAndroid Build Coastguard Worker       return false;
402*4d7e907cSAndroid Build Coastguard Worker     }
403*4d7e907cSAndroid Build Coastguard Worker 
404*4d7e907cSAndroid Build Coastguard Worker     // Ignore matching for audio channel allocation
405*4d7e907cSAndroid Build Coastguard Worker     // since the rule is complicated. Match outside instead
406*4d7e907cSAndroid Build Coastguard Worker     if (requirement_cfg.getTag() ==
407*4d7e907cSAndroid Build Coastguard Worker         CodecSpecificConfigurationLtv::Tag::audioChannelAllocation)
408*4d7e907cSAndroid Build Coastguard Worker       continue;
409*4d7e907cSAndroid Build Coastguard Worker 
410*4d7e907cSAndroid Build Coastguard Worker     if (cfg->second != requirement_cfg) {
411*4d7e907cSAndroid Build Coastguard Worker       return false;
412*4d7e907cSAndroid Build Coastguard Worker     }
413*4d7e907cSAndroid Build Coastguard Worker   }
414*4d7e907cSAndroid Build Coastguard Worker   // Ignore vendor configuration and metadata requirement
415*4d7e907cSAndroid Build Coastguard Worker 
416*4d7e907cSAndroid Build Coastguard Worker   return true;
417*4d7e907cSAndroid Build Coastguard Worker }
418*4d7e907cSAndroid Build Coastguard Worker 
isMatchedBISConfiguration(LeAudioBisConfiguration bis_cfg,const IBluetoothAudioProvider::LeAudioDeviceCapabilities & capabilities)419*4d7e907cSAndroid Build Coastguard Worker bool LeAudioOffloadAudioProvider::isMatchedBISConfiguration(
420*4d7e907cSAndroid Build Coastguard Worker     LeAudioBisConfiguration bis_cfg,
421*4d7e907cSAndroid Build Coastguard Worker     const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities) {
422*4d7e907cSAndroid Build Coastguard Worker   if (!isMatchedValidCodec(bis_cfg.codecId, capabilities.codecId)) {
423*4d7e907cSAndroid Build Coastguard Worker     return false;
424*4d7e907cSAndroid Build Coastguard Worker   }
425*4d7e907cSAndroid Build Coastguard Worker   if (!isCapabilitiesMatchedCodecConfiguration(
426*4d7e907cSAndroid Build Coastguard Worker           bis_cfg.codecConfiguration, capabilities.codecSpecificCapabilities)) {
427*4d7e907cSAndroid Build Coastguard Worker     return false;
428*4d7e907cSAndroid Build Coastguard Worker   }
429*4d7e907cSAndroid Build Coastguard Worker   return true;
430*4d7e907cSAndroid Build Coastguard Worker }
431*4d7e907cSAndroid Build Coastguard Worker 
filterCapabilitiesAseDirectionConfiguration(std::vector<std::optional<AseDirectionConfiguration>> & direction_configurations,const IBluetoothAudioProvider::LeAudioDeviceCapabilities & capabilities,std::vector<std::optional<AseDirectionConfiguration>> & valid_direction_configurations)432*4d7e907cSAndroid Build Coastguard Worker void LeAudioOffloadAudioProvider::filterCapabilitiesAseDirectionConfiguration(
433*4d7e907cSAndroid Build Coastguard Worker     std::vector<std::optional<AseDirectionConfiguration>>&
434*4d7e907cSAndroid Build Coastguard Worker         direction_configurations,
435*4d7e907cSAndroid Build Coastguard Worker     const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities,
436*4d7e907cSAndroid Build Coastguard Worker     std::vector<std::optional<AseDirectionConfiguration>>&
437*4d7e907cSAndroid Build Coastguard Worker         valid_direction_configurations) {
438*4d7e907cSAndroid Build Coastguard Worker   for (auto direction_configuration : direction_configurations) {
439*4d7e907cSAndroid Build Coastguard Worker     if (!direction_configuration.has_value()) continue;
440*4d7e907cSAndroid Build Coastguard Worker     if (!direction_configuration.value().aseConfiguration.codecId.has_value())
441*4d7e907cSAndroid Build Coastguard Worker       continue;
442*4d7e907cSAndroid Build Coastguard Worker     if (!isMatchedValidCodec(
443*4d7e907cSAndroid Build Coastguard Worker             direction_configuration.value().aseConfiguration.codecId.value(),
444*4d7e907cSAndroid Build Coastguard Worker             capabilities.codecId))
445*4d7e907cSAndroid Build Coastguard Worker       continue;
446*4d7e907cSAndroid Build Coastguard Worker     // Check matching for codec configuration <=> codec capabilities
447*4d7e907cSAndroid Build Coastguard Worker     if (!isCapabilitiesMatchedCodecConfiguration(
448*4d7e907cSAndroid Build Coastguard Worker             direction_configuration.value().aseConfiguration.codecConfiguration,
449*4d7e907cSAndroid Build Coastguard Worker             capabilities.codecSpecificCapabilities))
450*4d7e907cSAndroid Build Coastguard Worker       continue;
451*4d7e907cSAndroid Build Coastguard Worker     valid_direction_configurations.push_back(direction_configuration);
452*4d7e907cSAndroid Build Coastguard Worker   }
453*4d7e907cSAndroid Build Coastguard Worker }
454*4d7e907cSAndroid Build Coastguard Worker 
getLeAudioAseConfigurationAllocationBitmask(LeAudioAseConfiguration cfg)455*4d7e907cSAndroid Build Coastguard Worker int getLeAudioAseConfigurationAllocationBitmask(LeAudioAseConfiguration cfg) {
456*4d7e907cSAndroid Build Coastguard Worker   for (auto cfg_ltv : cfg.codecConfiguration) {
457*4d7e907cSAndroid Build Coastguard Worker     if (cfg_ltv.getTag() ==
458*4d7e907cSAndroid Build Coastguard Worker         CodecSpecificConfigurationLtv::Tag::audioChannelAllocation) {
459*4d7e907cSAndroid Build Coastguard Worker       return cfg_ltv
460*4d7e907cSAndroid Build Coastguard Worker           .get<CodecSpecificConfigurationLtv::Tag::audioChannelAllocation>()
461*4d7e907cSAndroid Build Coastguard Worker           .bitmask;
462*4d7e907cSAndroid Build Coastguard Worker     }
463*4d7e907cSAndroid Build Coastguard Worker   }
464*4d7e907cSAndroid Build Coastguard Worker   return 0;
465*4d7e907cSAndroid Build Coastguard Worker }
466*4d7e907cSAndroid Build Coastguard Worker 
findValidMonoConfig(std::vector<AseDirectionConfiguration> & valid_direction_configurations,int bitmask)467*4d7e907cSAndroid Build Coastguard Worker std::optional<AseDirectionConfiguration> findValidMonoConfig(
468*4d7e907cSAndroid Build Coastguard Worker     std::vector<AseDirectionConfiguration>& valid_direction_configurations,
469*4d7e907cSAndroid Build Coastguard Worker     int bitmask) {
470*4d7e907cSAndroid Build Coastguard Worker   for (auto& cfg : valid_direction_configurations) {
471*4d7e907cSAndroid Build Coastguard Worker     int cfg_bitmask =
472*4d7e907cSAndroid Build Coastguard Worker         getLeAudioAseConfigurationAllocationBitmask(cfg.aseConfiguration);
473*4d7e907cSAndroid Build Coastguard Worker     if (getCountFromBitmask(cfg_bitmask) <= 1) {
474*4d7e907cSAndroid Build Coastguard Worker       // Modify the bitmask to be the same as the requirement
475*4d7e907cSAndroid Build Coastguard Worker       for (auto& codec_cfg : cfg.aseConfiguration.codecConfiguration) {
476*4d7e907cSAndroid Build Coastguard Worker         if (codec_cfg.getTag() ==
477*4d7e907cSAndroid Build Coastguard Worker             CodecSpecificConfigurationLtv::Tag::audioChannelAllocation) {
478*4d7e907cSAndroid Build Coastguard Worker           codec_cfg
479*4d7e907cSAndroid Build Coastguard Worker               .get<CodecSpecificConfigurationLtv::Tag::audioChannelAllocation>()
480*4d7e907cSAndroid Build Coastguard Worker               .bitmask = bitmask;
481*4d7e907cSAndroid Build Coastguard Worker           return cfg;
482*4d7e907cSAndroid Build Coastguard Worker         }
483*4d7e907cSAndroid Build Coastguard Worker       }
484*4d7e907cSAndroid Build Coastguard Worker     }
485*4d7e907cSAndroid Build Coastguard Worker   }
486*4d7e907cSAndroid Build Coastguard Worker   return std::nullopt;
487*4d7e907cSAndroid Build Coastguard Worker }
488*4d7e907cSAndroid Build Coastguard Worker 
getValidConfigurationsFromAllocation(int req_allocation_bitmask,std::vector<AseDirectionConfiguration> & valid_direction_configurations,bool is_exact)489*4d7e907cSAndroid Build Coastguard Worker std::vector<AseDirectionConfiguration> getValidConfigurationsFromAllocation(
490*4d7e907cSAndroid Build Coastguard Worker     int req_allocation_bitmask,
491*4d7e907cSAndroid Build Coastguard Worker     std::vector<AseDirectionConfiguration>& valid_direction_configurations,
492*4d7e907cSAndroid Build Coastguard Worker     bool is_exact) {
493*4d7e907cSAndroid Build Coastguard Worker   // Prefer the same allocation_bitmask
494*4d7e907cSAndroid Build Coastguard Worker   int channel_count = getCountFromBitmask(req_allocation_bitmask);
495*4d7e907cSAndroid Build Coastguard Worker 
496*4d7e907cSAndroid Build Coastguard Worker   if (is_exact) {
497*4d7e907cSAndroid Build Coastguard Worker     for (auto& cfg : valid_direction_configurations) {
498*4d7e907cSAndroid Build Coastguard Worker       int cfg_bitmask =
499*4d7e907cSAndroid Build Coastguard Worker           getLeAudioAseConfigurationAllocationBitmask(cfg.aseConfiguration);
500*4d7e907cSAndroid Build Coastguard Worker       if (cfg_bitmask == req_allocation_bitmask) {
501*4d7e907cSAndroid Build Coastguard Worker         LOG(DEBUG)
502*4d7e907cSAndroid Build Coastguard Worker             << __func__
503*4d7e907cSAndroid Build Coastguard Worker             << ": Found an exact match for the requirement allocation of "
504*4d7e907cSAndroid Build Coastguard Worker             << cfg_bitmask;
505*4d7e907cSAndroid Build Coastguard Worker         return {cfg};
506*4d7e907cSAndroid Build Coastguard Worker       }
507*4d7e907cSAndroid Build Coastguard Worker     }
508*4d7e907cSAndroid Build Coastguard Worker     return {};
509*4d7e907cSAndroid Build Coastguard Worker   }
510*4d7e907cSAndroid Build Coastguard Worker   // Not using exact match strategy
511*4d7e907cSAndroid Build Coastguard Worker   if (channel_count <= 1) {
512*4d7e907cSAndroid Build Coastguard Worker     // Mono requirement matched if cfg is a mono config
513*4d7e907cSAndroid Build Coastguard Worker     auto cfg = findValidMonoConfig(valid_direction_configurations,
514*4d7e907cSAndroid Build Coastguard Worker                                    req_allocation_bitmask);
515*4d7e907cSAndroid Build Coastguard Worker     if (cfg.has_value()) return {cfg.value()};
516*4d7e907cSAndroid Build Coastguard Worker   } else {
517*4d7e907cSAndroid Build Coastguard Worker     // Stereo requirement returns 2 mono configs
518*4d7e907cSAndroid Build Coastguard Worker     // that has a combined bitmask equal to the stereo config
519*4d7e907cSAndroid Build Coastguard Worker     std::vector<AseDirectionConfiguration> temp;
520*4d7e907cSAndroid Build Coastguard Worker     for (int bit = 0; bit < 32; ++bit)
521*4d7e907cSAndroid Build Coastguard Worker       if (req_allocation_bitmask & (1 << bit)) {
522*4d7e907cSAndroid Build Coastguard Worker         auto cfg =
523*4d7e907cSAndroid Build Coastguard Worker             findValidMonoConfig(valid_direction_configurations, (1 << bit));
524*4d7e907cSAndroid Build Coastguard Worker         if (cfg.has_value()) temp.push_back(cfg.value());
525*4d7e907cSAndroid Build Coastguard Worker       }
526*4d7e907cSAndroid Build Coastguard Worker     if (temp.size() == channel_count) return temp;
527*4d7e907cSAndroid Build Coastguard Worker   }
528*4d7e907cSAndroid Build Coastguard Worker   return {};
529*4d7e907cSAndroid Build Coastguard Worker }
530*4d7e907cSAndroid Build Coastguard Worker 
531*4d7e907cSAndroid Build Coastguard Worker // Check and filter each index to see if it's a match.
filterRequirementAseDirectionConfiguration(std::optional<std::vector<std::optional<AseDirectionConfiguration>>> & direction_configurations,const std::vector<std::optional<AseDirectionRequirement>> & requirements,std::optional<std::vector<std::optional<AseDirectionConfiguration>>> & valid_direction_configurations,bool isExact)532*4d7e907cSAndroid Build Coastguard Worker void LeAudioOffloadAudioProvider::filterRequirementAseDirectionConfiguration(
533*4d7e907cSAndroid Build Coastguard Worker     std::optional<std::vector<std::optional<AseDirectionConfiguration>>>&
534*4d7e907cSAndroid Build Coastguard Worker         direction_configurations,
535*4d7e907cSAndroid Build Coastguard Worker     const std::vector<std::optional<AseDirectionRequirement>>& requirements,
536*4d7e907cSAndroid Build Coastguard Worker     std::optional<std::vector<std::optional<AseDirectionConfiguration>>>&
537*4d7e907cSAndroid Build Coastguard Worker         valid_direction_configurations,
538*4d7e907cSAndroid Build Coastguard Worker     bool isExact) {
539*4d7e907cSAndroid Build Coastguard Worker   if (!direction_configurations.has_value()) return;
540*4d7e907cSAndroid Build Coastguard Worker 
541*4d7e907cSAndroid Build Coastguard Worker   if (!valid_direction_configurations.has_value()) {
542*4d7e907cSAndroid Build Coastguard Worker     valid_direction_configurations =
543*4d7e907cSAndroid Build Coastguard Worker         std::vector<std::optional<AseDirectionConfiguration>>();
544*4d7e907cSAndroid Build Coastguard Worker   }
545*4d7e907cSAndroid Build Coastguard Worker 
546*4d7e907cSAndroid Build Coastguard Worker   if (isExact) {
547*4d7e907cSAndroid Build Coastguard Worker     // Exact matching process
548*4d7e907cSAndroid Build Coastguard Worker     // Need to respect the number of device
549*4d7e907cSAndroid Build Coastguard Worker     for (int i = 0; i < requirements.size(); ++i) {
550*4d7e907cSAndroid Build Coastguard Worker       auto requirement = requirements[i];
551*4d7e907cSAndroid Build Coastguard Worker       auto direction_configuration = direction_configurations.value()[i];
552*4d7e907cSAndroid Build Coastguard Worker       if (!direction_configuration.has_value()) {
553*4d7e907cSAndroid Build Coastguard Worker         valid_direction_configurations = std::nullopt;
554*4d7e907cSAndroid Build Coastguard Worker         return;
555*4d7e907cSAndroid Build Coastguard Worker       }
556*4d7e907cSAndroid Build Coastguard Worker       auto cfg = direction_configuration.value();
557*4d7e907cSAndroid Build Coastguard Worker       if (!filterMatchedAseConfiguration(
558*4d7e907cSAndroid Build Coastguard Worker               cfg.aseConfiguration, requirement.value().aseConfiguration)) {
559*4d7e907cSAndroid Build Coastguard Worker         valid_direction_configurations = std::nullopt;
560*4d7e907cSAndroid Build Coastguard Worker         return;  // No way to match
561*4d7e907cSAndroid Build Coastguard Worker       }
562*4d7e907cSAndroid Build Coastguard Worker       // For exact match, we require this direction to have the same allocation.
563*4d7e907cSAndroid Build Coastguard Worker       // If stereo, need stereo.
564*4d7e907cSAndroid Build Coastguard Worker       // If mono, need mono (modified to the correct required allocation)
565*4d7e907cSAndroid Build Coastguard Worker       auto req_allocation_bitmask = getLeAudioAseConfigurationAllocationBitmask(
566*4d7e907cSAndroid Build Coastguard Worker           requirement.value().aseConfiguration);
567*4d7e907cSAndroid Build Coastguard Worker       int req_channel_count = getCountFromBitmask(req_allocation_bitmask);
568*4d7e907cSAndroid Build Coastguard Worker       int cfg_bitmask =
569*4d7e907cSAndroid Build Coastguard Worker           getLeAudioAseConfigurationAllocationBitmask(cfg.aseConfiguration);
570*4d7e907cSAndroid Build Coastguard Worker       int cfg_channel_count = getCountFromBitmask(cfg_bitmask);
571*4d7e907cSAndroid Build Coastguard Worker       if (req_channel_count <= 1) {
572*4d7e907cSAndroid Build Coastguard Worker         // MONO case, is a match if also mono, modify to the same allocation
573*4d7e907cSAndroid Build Coastguard Worker         if (cfg_channel_count > 1) {
574*4d7e907cSAndroid Build Coastguard Worker           valid_direction_configurations = std::nullopt;
575*4d7e907cSAndroid Build Coastguard Worker           return;  // Not a match
576*4d7e907cSAndroid Build Coastguard Worker         }
577*4d7e907cSAndroid Build Coastguard Worker         // Modify the bitmask to be the same as the requirement
578*4d7e907cSAndroid Build Coastguard Worker         for (auto& codec_cfg : cfg.aseConfiguration.codecConfiguration) {
579*4d7e907cSAndroid Build Coastguard Worker           if (codec_cfg.getTag() ==
580*4d7e907cSAndroid Build Coastguard Worker               CodecSpecificConfigurationLtv::Tag::audioChannelAllocation) {
581*4d7e907cSAndroid Build Coastguard Worker             codec_cfg
582*4d7e907cSAndroid Build Coastguard Worker                 .get<CodecSpecificConfigurationLtv::Tag::
583*4d7e907cSAndroid Build Coastguard Worker                          audioChannelAllocation>()
584*4d7e907cSAndroid Build Coastguard Worker                 .bitmask = req_allocation_bitmask;
585*4d7e907cSAndroid Build Coastguard Worker             break;
586*4d7e907cSAndroid Build Coastguard Worker           }
587*4d7e907cSAndroid Build Coastguard Worker         }
588*4d7e907cSAndroid Build Coastguard Worker       } else {
589*4d7e907cSAndroid Build Coastguard Worker         // STEREO case, is a match if same allocation
590*4d7e907cSAndroid Build Coastguard Worker         if (req_allocation_bitmask != cfg_bitmask) {
591*4d7e907cSAndroid Build Coastguard Worker           valid_direction_configurations = std::nullopt;
592*4d7e907cSAndroid Build Coastguard Worker           return;  // Not a match
593*4d7e907cSAndroid Build Coastguard Worker         }
594*4d7e907cSAndroid Build Coastguard Worker       }
595*4d7e907cSAndroid Build Coastguard Worker       // Push to list if valid
596*4d7e907cSAndroid Build Coastguard Worker       valid_direction_configurations.value().push_back(cfg);
597*4d7e907cSAndroid Build Coastguard Worker     }
598*4d7e907cSAndroid Build Coastguard Worker   } else {
599*4d7e907cSAndroid Build Coastguard Worker     // Loose matching process
600*4d7e907cSAndroid Build Coastguard Worker     for (auto& requirement : requirements) {
601*4d7e907cSAndroid Build Coastguard Worker       if (!requirement.has_value()) continue;
602*4d7e907cSAndroid Build Coastguard Worker       auto req_allocation_bitmask = getLeAudioAseConfigurationAllocationBitmask(
603*4d7e907cSAndroid Build Coastguard Worker           requirement.value().aseConfiguration);
604*4d7e907cSAndroid Build Coastguard Worker       auto req_channel_count = getCountFromBitmask(req_allocation_bitmask);
605*4d7e907cSAndroid Build Coastguard Worker 
606*4d7e907cSAndroid Build Coastguard Worker       auto temp = std::vector<AseDirectionConfiguration>();
607*4d7e907cSAndroid Build Coastguard Worker 
608*4d7e907cSAndroid Build Coastguard Worker       for (auto direction_configuration : direction_configurations.value()) {
609*4d7e907cSAndroid Build Coastguard Worker         if (!direction_configuration.has_value()) continue;
610*4d7e907cSAndroid Build Coastguard Worker         if (!filterMatchedAseConfiguration(
611*4d7e907cSAndroid Build Coastguard Worker                 direction_configuration.value().aseConfiguration,
612*4d7e907cSAndroid Build Coastguard Worker                 requirement.value().aseConfiguration))
613*4d7e907cSAndroid Build Coastguard Worker           continue;
614*4d7e907cSAndroid Build Coastguard Worker         // Valid if match any requirement.
615*4d7e907cSAndroid Build Coastguard Worker         temp.push_back(direction_configuration.value());
616*4d7e907cSAndroid Build Coastguard Worker       }
617*4d7e907cSAndroid Build Coastguard Worker 
618*4d7e907cSAndroid Build Coastguard Worker       // Get the best matching config based on channel allocation
619*4d7e907cSAndroid Build Coastguard Worker       auto total_cfg_channel_count = 0;
620*4d7e907cSAndroid Build Coastguard Worker       auto req_valid_configs = getValidConfigurationsFromAllocation(
621*4d7e907cSAndroid Build Coastguard Worker           req_allocation_bitmask, temp, isExact);
622*4d7e907cSAndroid Build Coastguard Worker       // Count and check required channel counts
623*4d7e907cSAndroid Build Coastguard Worker       for (auto& cfg : req_valid_configs) {
624*4d7e907cSAndroid Build Coastguard Worker         total_cfg_channel_count += getCountFromBitmask(
625*4d7e907cSAndroid Build Coastguard Worker             getLeAudioAseConfigurationAllocationBitmask(cfg.aseConfiguration));
626*4d7e907cSAndroid Build Coastguard Worker         valid_direction_configurations.value().push_back(cfg);
627*4d7e907cSAndroid Build Coastguard Worker       }
628*4d7e907cSAndroid Build Coastguard Worker       if (total_cfg_channel_count != req_channel_count) {
629*4d7e907cSAndroid Build Coastguard Worker         valid_direction_configurations = std::nullopt;
630*4d7e907cSAndroid Build Coastguard Worker         return;
631*4d7e907cSAndroid Build Coastguard Worker       }
632*4d7e907cSAndroid Build Coastguard Worker     }
633*4d7e907cSAndroid Build Coastguard Worker   }
634*4d7e907cSAndroid Build Coastguard Worker }
635*4d7e907cSAndroid Build Coastguard Worker 
636*4d7e907cSAndroid Build Coastguard Worker /* Get a new LeAudioAseConfigurationSetting by matching a setting with a
637*4d7e907cSAndroid Build Coastguard Worker  * capabilities. The new setting will have a filtered list of
638*4d7e907cSAndroid Build Coastguard Worker  * AseDirectionConfiguration that matched the capabilities */
639*4d7e907cSAndroid Build Coastguard Worker std::optional<LeAudioAseConfigurationSetting>
getCapabilitiesMatchedAseConfigurationSettings(IBluetoothAudioProvider::LeAudioAseConfigurationSetting & setting,const IBluetoothAudioProvider::LeAudioDeviceCapabilities & capabilities,uint8_t direction)640*4d7e907cSAndroid Build Coastguard Worker LeAudioOffloadAudioProvider::getCapabilitiesMatchedAseConfigurationSettings(
641*4d7e907cSAndroid Build Coastguard Worker     IBluetoothAudioProvider::LeAudioAseConfigurationSetting& setting,
642*4d7e907cSAndroid Build Coastguard Worker     const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities,
643*4d7e907cSAndroid Build Coastguard Worker     uint8_t direction) {
644*4d7e907cSAndroid Build Coastguard Worker   // Create a new LeAudioAseConfigurationSetting and return
645*4d7e907cSAndroid Build Coastguard Worker   LeAudioAseConfigurationSetting filtered_setting{
646*4d7e907cSAndroid Build Coastguard Worker       .audioContext = setting.audioContext,
647*4d7e907cSAndroid Build Coastguard Worker       .sinkAseConfiguration = setting.sinkAseConfiguration,
648*4d7e907cSAndroid Build Coastguard Worker       .sourceAseConfiguration = setting.sourceAseConfiguration,
649*4d7e907cSAndroid Build Coastguard Worker       .flags = setting.flags,
650*4d7e907cSAndroid Build Coastguard Worker       .packing = setting.packing,
651*4d7e907cSAndroid Build Coastguard Worker   };
652*4d7e907cSAndroid Build Coastguard Worker 
653*4d7e907cSAndroid Build Coastguard Worker   // Get a list of all matched AseDirectionConfiguration
654*4d7e907cSAndroid Build Coastguard Worker   // for the input direction
655*4d7e907cSAndroid Build Coastguard Worker   std::vector<std::optional<AseDirectionConfiguration>>*
656*4d7e907cSAndroid Build Coastguard Worker       direction_configuration = nullptr;
657*4d7e907cSAndroid Build Coastguard Worker   if (direction == kLeAudioDirectionSink) {
658*4d7e907cSAndroid Build Coastguard Worker     if (!filtered_setting.sinkAseConfiguration.has_value()) return std::nullopt;
659*4d7e907cSAndroid Build Coastguard Worker     direction_configuration = &filtered_setting.sinkAseConfiguration.value();
660*4d7e907cSAndroid Build Coastguard Worker   } else {
661*4d7e907cSAndroid Build Coastguard Worker     if (!filtered_setting.sourceAseConfiguration.has_value())
662*4d7e907cSAndroid Build Coastguard Worker       return std::nullopt;
663*4d7e907cSAndroid Build Coastguard Worker     direction_configuration = &filtered_setting.sourceAseConfiguration.value();
664*4d7e907cSAndroid Build Coastguard Worker   }
665*4d7e907cSAndroid Build Coastguard Worker   std::vector<std::optional<AseDirectionConfiguration>>
666*4d7e907cSAndroid Build Coastguard Worker       valid_direction_configuration;
667*4d7e907cSAndroid Build Coastguard Worker   filterCapabilitiesAseDirectionConfiguration(
668*4d7e907cSAndroid Build Coastguard Worker       *direction_configuration, capabilities, valid_direction_configuration);
669*4d7e907cSAndroid Build Coastguard Worker 
670*4d7e907cSAndroid Build Coastguard Worker   // No valid configuration for this direction
671*4d7e907cSAndroid Build Coastguard Worker   if (valid_direction_configuration.empty()) {
672*4d7e907cSAndroid Build Coastguard Worker     return std::nullopt;
673*4d7e907cSAndroid Build Coastguard Worker   }
674*4d7e907cSAndroid Build Coastguard Worker 
675*4d7e907cSAndroid Build Coastguard Worker   // Create a new LeAudioAseConfigurationSetting and return
676*4d7e907cSAndroid Build Coastguard Worker   // For other direction will contain all settings
677*4d7e907cSAndroid Build Coastguard Worker   if (direction == kLeAudioDirectionSink) {
678*4d7e907cSAndroid Build Coastguard Worker     filtered_setting.sinkAseConfiguration = valid_direction_configuration;
679*4d7e907cSAndroid Build Coastguard Worker   } else {
680*4d7e907cSAndroid Build Coastguard Worker     filtered_setting.sourceAseConfiguration = valid_direction_configuration;
681*4d7e907cSAndroid Build Coastguard Worker   }
682*4d7e907cSAndroid Build Coastguard Worker 
683*4d7e907cSAndroid Build Coastguard Worker   return filtered_setting;
684*4d7e907cSAndroid Build Coastguard Worker }
685*4d7e907cSAndroid Build Coastguard Worker 
686*4d7e907cSAndroid Build Coastguard Worker /* Get a new LeAudioAseConfigurationSetting by matching a setting with a
687*4d7e907cSAndroid Build Coastguard Worker  * requirement. The new setting will have a filtered list of
688*4d7e907cSAndroid Build Coastguard Worker  * AseDirectionConfiguration that matched the requirement */
689*4d7e907cSAndroid Build Coastguard Worker std::optional<LeAudioAseConfigurationSetting>
getRequirementMatchedAseConfigurationSettings(IBluetoothAudioProvider::LeAudioAseConfigurationSetting & setting,const IBluetoothAudioProvider::LeAudioConfigurationRequirement & requirement,bool isExact)690*4d7e907cSAndroid Build Coastguard Worker LeAudioOffloadAudioProvider::getRequirementMatchedAseConfigurationSettings(
691*4d7e907cSAndroid Build Coastguard Worker     IBluetoothAudioProvider::LeAudioAseConfigurationSetting& setting,
692*4d7e907cSAndroid Build Coastguard Worker     const IBluetoothAudioProvider::LeAudioConfigurationRequirement& requirement,
693*4d7e907cSAndroid Build Coastguard Worker     bool isExact) {
694*4d7e907cSAndroid Build Coastguard Worker   // Create a new LeAudioAseConfigurationSetting to return
695*4d7e907cSAndroid Build Coastguard Worker   // Make context the same as the requirement
696*4d7e907cSAndroid Build Coastguard Worker   LeAudioAseConfigurationSetting filtered_setting{
697*4d7e907cSAndroid Build Coastguard Worker       .audioContext = requirement.audioContext,
698*4d7e907cSAndroid Build Coastguard Worker       .packing = setting.packing,
699*4d7e907cSAndroid Build Coastguard Worker       .flags = setting.flags,
700*4d7e907cSAndroid Build Coastguard Worker   };
701*4d7e907cSAndroid Build Coastguard Worker 
702*4d7e907cSAndroid Build Coastguard Worker   // The number of AseDirectionRequirement in the requirement
703*4d7e907cSAndroid Build Coastguard Worker   // is the number of device.
704*4d7e907cSAndroid Build Coastguard Worker 
705*4d7e907cSAndroid Build Coastguard Worker   // The exact matching process is as follow:
706*4d7e907cSAndroid Build Coastguard Worker   // 1. Setting direction has the same number of cfg (ignore when null
707*4d7e907cSAndroid Build Coastguard Worker   // require)
708*4d7e907cSAndroid Build Coastguard Worker   // 2. For each index, it's a 1-1 filter / mapping.
709*4d7e907cSAndroid Build Coastguard Worker   if (isExact) {
710*4d7e907cSAndroid Build Coastguard Worker     if (requirement.sinkAseRequirement.has_value() &&
711*4d7e907cSAndroid Build Coastguard Worker         requirement.sinkAseRequirement.value().size() !=
712*4d7e907cSAndroid Build Coastguard Worker             setting.sinkAseConfiguration.value().size()) {
713*4d7e907cSAndroid Build Coastguard Worker       return std::nullopt;
714*4d7e907cSAndroid Build Coastguard Worker     }
715*4d7e907cSAndroid Build Coastguard Worker 
716*4d7e907cSAndroid Build Coastguard Worker     if (requirement.sourceAseRequirement.has_value() &&
717*4d7e907cSAndroid Build Coastguard Worker         requirement.sourceAseRequirement.value().size() !=
718*4d7e907cSAndroid Build Coastguard Worker             setting.sourceAseConfiguration.value().size()) {
719*4d7e907cSAndroid Build Coastguard Worker       return std::nullopt;
720*4d7e907cSAndroid Build Coastguard Worker     }
721*4d7e907cSAndroid Build Coastguard Worker   }
722*4d7e907cSAndroid Build Coastguard Worker 
723*4d7e907cSAndroid Build Coastguard Worker   if (requirement.sinkAseRequirement.has_value()) {
724*4d7e907cSAndroid Build Coastguard Worker     filterRequirementAseDirectionConfiguration(
725*4d7e907cSAndroid Build Coastguard Worker         setting.sinkAseConfiguration, requirement.sinkAseRequirement.value(),
726*4d7e907cSAndroid Build Coastguard Worker         filtered_setting.sinkAseConfiguration, isExact);
727*4d7e907cSAndroid Build Coastguard Worker     if (!filtered_setting.sinkAseConfiguration.has_value()) {
728*4d7e907cSAndroid Build Coastguard Worker       return std::nullopt;
729*4d7e907cSAndroid Build Coastguard Worker     }
730*4d7e907cSAndroid Build Coastguard Worker   }
731*4d7e907cSAndroid Build Coastguard Worker 
732*4d7e907cSAndroid Build Coastguard Worker   if (requirement.sourceAseRequirement.has_value()) {
733*4d7e907cSAndroid Build Coastguard Worker     filterRequirementAseDirectionConfiguration(
734*4d7e907cSAndroid Build Coastguard Worker         setting.sourceAseConfiguration,
735*4d7e907cSAndroid Build Coastguard Worker         requirement.sourceAseRequirement.value(),
736*4d7e907cSAndroid Build Coastguard Worker         filtered_setting.sourceAseConfiguration, isExact);
737*4d7e907cSAndroid Build Coastguard Worker     if (!filtered_setting.sourceAseConfiguration.has_value()) {
738*4d7e907cSAndroid Build Coastguard Worker       return std::nullopt;
739*4d7e907cSAndroid Build Coastguard Worker     }
740*4d7e907cSAndroid Build Coastguard Worker   }
741*4d7e907cSAndroid Build Coastguard Worker 
742*4d7e907cSAndroid Build Coastguard Worker   return filtered_setting;
743*4d7e907cSAndroid Build Coastguard Worker }
744*4d7e907cSAndroid Build Coastguard Worker 
745*4d7e907cSAndroid Build Coastguard Worker std::optional<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
matchWithRequirement(std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting> & matched_ase_configuration_settings,const IBluetoothAudioProvider::LeAudioConfigurationRequirement & requirement,bool isMatchContext,bool isExact)746*4d7e907cSAndroid Build Coastguard Worker LeAudioOffloadAudioProvider::matchWithRequirement(
747*4d7e907cSAndroid Build Coastguard Worker     std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>&
748*4d7e907cSAndroid Build Coastguard Worker         matched_ase_configuration_settings,
749*4d7e907cSAndroid Build Coastguard Worker     const IBluetoothAudioProvider::LeAudioConfigurationRequirement& requirement,
750*4d7e907cSAndroid Build Coastguard Worker     bool isMatchContext, bool isExact) {
751*4d7e907cSAndroid Build Coastguard Worker   LOG(INFO) << __func__ << ": Trying to match for the requirement "
752*4d7e907cSAndroid Build Coastguard Worker             << requirement.toString() << ", match context = " << isMatchContext
753*4d7e907cSAndroid Build Coastguard Worker             << ", match exact = " << isExact;
754*4d7e907cSAndroid Build Coastguard Worker   for (auto& setting : matched_ase_configuration_settings) {
755*4d7e907cSAndroid Build Coastguard Worker     // Try to match context in metadata.
756*4d7e907cSAndroid Build Coastguard Worker     if (isMatchContext) {
757*4d7e907cSAndroid Build Coastguard Worker       if ((setting.audioContext.bitmask & requirement.audioContext.bitmask) !=
758*4d7e907cSAndroid Build Coastguard Worker           requirement.audioContext.bitmask)
759*4d7e907cSAndroid Build Coastguard Worker         continue;
760*4d7e907cSAndroid Build Coastguard Worker       LOG(DEBUG) << __func__ << ": Setting with matched context: "
761*4d7e907cSAndroid Build Coastguard Worker                  << getSettingOutputString(setting);
762*4d7e907cSAndroid Build Coastguard Worker     }
763*4d7e907cSAndroid Build Coastguard Worker 
764*4d7e907cSAndroid Build Coastguard Worker     auto filtered_ase_configuration_setting =
765*4d7e907cSAndroid Build Coastguard Worker         getRequirementMatchedAseConfigurationSettings(setting, requirement,
766*4d7e907cSAndroid Build Coastguard Worker                                                       isExact);
767*4d7e907cSAndroid Build Coastguard Worker     if (filtered_ase_configuration_setting.has_value()) {
768*4d7e907cSAndroid Build Coastguard Worker       LOG(INFO) << __func__ << ": Result found: "
769*4d7e907cSAndroid Build Coastguard Worker                 << getSettingOutputString(
770*4d7e907cSAndroid Build Coastguard Worker                        filtered_ase_configuration_setting.value());
771*4d7e907cSAndroid Build Coastguard Worker       // Found a matched setting, ignore other settings
772*4d7e907cSAndroid Build Coastguard Worker       return filtered_ase_configuration_setting;
773*4d7e907cSAndroid Build Coastguard Worker     }
774*4d7e907cSAndroid Build Coastguard Worker   }
775*4d7e907cSAndroid Build Coastguard Worker   // If cannot satisfy this requirement, return nullopt
776*4d7e907cSAndroid Build Coastguard Worker   LOG(WARNING) << __func__ << ": Cannot match the requirement "
777*4d7e907cSAndroid Build Coastguard Worker                << requirement.toString()
778*4d7e907cSAndroid Build Coastguard Worker                << ", match context = " << isMatchContext;
779*4d7e907cSAndroid Build Coastguard Worker   return std::nullopt;
780*4d7e907cSAndroid Build Coastguard Worker }
781*4d7e907cSAndroid Build Coastguard Worker 
782*4d7e907cSAndroid Build Coastguard Worker // For each requirement, a valid ASE configuration will satify:
783*4d7e907cSAndroid Build Coastguard Worker // - matched with the sink capability (if presented)
784*4d7e907cSAndroid Build Coastguard Worker // - AND matched with the source capability (if presented)
785*4d7e907cSAndroid Build Coastguard Worker // - and the setting need to pass the requirement
getLeAudioAseConfiguration(const std::optional<std::vector<std::optional<IBluetoothAudioProvider::LeAudioDeviceCapabilities>>> & in_remoteSinkAudioCapabilities,const std::optional<std::vector<std::optional<IBluetoothAudioProvider::LeAudioDeviceCapabilities>>> & in_remoteSourceAudioCapabilities,const std::vector<IBluetoothAudioProvider::LeAudioConfigurationRequirement> & in_requirements,std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting> * _aidl_return)786*4d7e907cSAndroid Build Coastguard Worker ndk::ScopedAStatus LeAudioOffloadAudioProvider::getLeAudioAseConfiguration(
787*4d7e907cSAndroid Build Coastguard Worker     const std::optional<std::vector<
788*4d7e907cSAndroid Build Coastguard Worker         std::optional<IBluetoothAudioProvider::LeAudioDeviceCapabilities>>>&
789*4d7e907cSAndroid Build Coastguard Worker         in_remoteSinkAudioCapabilities,
790*4d7e907cSAndroid Build Coastguard Worker     const std::optional<std::vector<
791*4d7e907cSAndroid Build Coastguard Worker         std::optional<IBluetoothAudioProvider::LeAudioDeviceCapabilities>>>&
792*4d7e907cSAndroid Build Coastguard Worker         in_remoteSourceAudioCapabilities,
793*4d7e907cSAndroid Build Coastguard Worker     const std::vector<IBluetoothAudioProvider::LeAudioConfigurationRequirement>&
794*4d7e907cSAndroid Build Coastguard Worker         in_requirements,
795*4d7e907cSAndroid Build Coastguard Worker     std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>*
796*4d7e907cSAndroid Build Coastguard Worker         _aidl_return) {
797*4d7e907cSAndroid Build Coastguard Worker   // Get all configuration settings
798*4d7e907cSAndroid Build Coastguard Worker   std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
799*4d7e907cSAndroid Build Coastguard Worker       ase_configuration_settings =
800*4d7e907cSAndroid Build Coastguard Worker           BluetoothAudioCodecs::GetLeAudioAseConfigurationSettings();
801*4d7e907cSAndroid Build Coastguard Worker 
802*4d7e907cSAndroid Build Coastguard Worker   if (!in_remoteSinkAudioCapabilities.has_value() &&
803*4d7e907cSAndroid Build Coastguard Worker       !in_remoteSourceAudioCapabilities.has_value()) {
804*4d7e907cSAndroid Build Coastguard Worker     return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
805*4d7e907cSAndroid Build Coastguard Worker   }
806*4d7e907cSAndroid Build Coastguard Worker 
807*4d7e907cSAndroid Build Coastguard Worker   // Matched ASE configuration with ignored audio context
808*4d7e907cSAndroid Build Coastguard Worker   std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
809*4d7e907cSAndroid Build Coastguard Worker       sink_matched_ase_configuration_settings;
810*4d7e907cSAndroid Build Coastguard Worker   std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
811*4d7e907cSAndroid Build Coastguard Worker       matched_ase_configuration_settings;
812*4d7e907cSAndroid Build Coastguard Worker 
813*4d7e907cSAndroid Build Coastguard Worker   // A setting must match both source and sink.
814*4d7e907cSAndroid Build Coastguard Worker   // First filter all setting matched with sink capability
815*4d7e907cSAndroid Build Coastguard Worker   if (in_remoteSinkAudioCapabilities.has_value()) {
816*4d7e907cSAndroid Build Coastguard Worker     for (auto& setting : ase_configuration_settings) {
817*4d7e907cSAndroid Build Coastguard Worker       for (auto& capability : in_remoteSinkAudioCapabilities.value()) {
818*4d7e907cSAndroid Build Coastguard Worker         if (!capability.has_value()) continue;
819*4d7e907cSAndroid Build Coastguard Worker         auto filtered_ase_configuration_setting =
820*4d7e907cSAndroid Build Coastguard Worker             getCapabilitiesMatchedAseConfigurationSettings(
821*4d7e907cSAndroid Build Coastguard Worker                 setting, capability.value(), kLeAudioDirectionSink);
822*4d7e907cSAndroid Build Coastguard Worker         if (filtered_ase_configuration_setting.has_value()) {
823*4d7e907cSAndroid Build Coastguard Worker           sink_matched_ase_configuration_settings.push_back(
824*4d7e907cSAndroid Build Coastguard Worker               filtered_ase_configuration_setting.value());
825*4d7e907cSAndroid Build Coastguard Worker         }
826*4d7e907cSAndroid Build Coastguard Worker       }
827*4d7e907cSAndroid Build Coastguard Worker     }
828*4d7e907cSAndroid Build Coastguard Worker   } else {
829*4d7e907cSAndroid Build Coastguard Worker     sink_matched_ase_configuration_settings = ase_configuration_settings;
830*4d7e907cSAndroid Build Coastguard Worker   }
831*4d7e907cSAndroid Build Coastguard Worker 
832*4d7e907cSAndroid Build Coastguard Worker   // Combine filter every source capability
833*4d7e907cSAndroid Build Coastguard Worker   if (in_remoteSourceAudioCapabilities.has_value()) {
834*4d7e907cSAndroid Build Coastguard Worker     for (auto& setting : sink_matched_ase_configuration_settings)
835*4d7e907cSAndroid Build Coastguard Worker       for (auto& capability : in_remoteSourceAudioCapabilities.value()) {
836*4d7e907cSAndroid Build Coastguard Worker         if (!capability.has_value()) continue;
837*4d7e907cSAndroid Build Coastguard Worker         auto filtered_ase_configuration_setting =
838*4d7e907cSAndroid Build Coastguard Worker             getCapabilitiesMatchedAseConfigurationSettings(
839*4d7e907cSAndroid Build Coastguard Worker                 setting, capability.value(), kLeAudioDirectionSource);
840*4d7e907cSAndroid Build Coastguard Worker         if (filtered_ase_configuration_setting.has_value()) {
841*4d7e907cSAndroid Build Coastguard Worker           matched_ase_configuration_settings.push_back(
842*4d7e907cSAndroid Build Coastguard Worker               filtered_ase_configuration_setting.value());
843*4d7e907cSAndroid Build Coastguard Worker         }
844*4d7e907cSAndroid Build Coastguard Worker       }
845*4d7e907cSAndroid Build Coastguard Worker   } else {
846*4d7e907cSAndroid Build Coastguard Worker     matched_ase_configuration_settings =
847*4d7e907cSAndroid Build Coastguard Worker         sink_matched_ase_configuration_settings;
848*4d7e907cSAndroid Build Coastguard Worker   }
849*4d7e907cSAndroid Build Coastguard Worker 
850*4d7e907cSAndroid Build Coastguard Worker   std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting> result;
851*4d7e907cSAndroid Build Coastguard Worker   for (auto& requirement : in_requirements) {
852*4d7e907cSAndroid Build Coastguard Worker     // For each requirement, try to match with a setting.
853*4d7e907cSAndroid Build Coastguard Worker     // If we cannot match, return an empty result.
854*4d7e907cSAndroid Build Coastguard Worker 
855*4d7e907cSAndroid Build Coastguard Worker     // Matching priority list:
856*4d7e907cSAndroid Build Coastguard Worker     // Preferred context - exact match with allocation
857*4d7e907cSAndroid Build Coastguard Worker     // Preferred context - loose match with allocation
858*4d7e907cSAndroid Build Coastguard Worker     // Any context - exact match with allocation
859*4d7e907cSAndroid Build Coastguard Worker     // Any context - loose match with allocation
860*4d7e907cSAndroid Build Coastguard Worker     bool found = false;
861*4d7e907cSAndroid Build Coastguard Worker     for (bool match_context : {true, false}) {
862*4d7e907cSAndroid Build Coastguard Worker       for (bool match_exact : {true, false}) {
863*4d7e907cSAndroid Build Coastguard Worker         auto matched_setting =
864*4d7e907cSAndroid Build Coastguard Worker             matchWithRequirement(matched_ase_configuration_settings,
865*4d7e907cSAndroid Build Coastguard Worker                                  requirement, match_context, match_exact);
866*4d7e907cSAndroid Build Coastguard Worker         if (matched_setting.has_value()) {
867*4d7e907cSAndroid Build Coastguard Worker           result.push_back(matched_setting.value());
868*4d7e907cSAndroid Build Coastguard Worker           found = true;
869*4d7e907cSAndroid Build Coastguard Worker           break;
870*4d7e907cSAndroid Build Coastguard Worker         }
871*4d7e907cSAndroid Build Coastguard Worker       }
872*4d7e907cSAndroid Build Coastguard Worker       if (found) break;
873*4d7e907cSAndroid Build Coastguard Worker     }
874*4d7e907cSAndroid Build Coastguard Worker 
875*4d7e907cSAndroid Build Coastguard Worker     if (!found) {
876*4d7e907cSAndroid Build Coastguard Worker       LOG(ERROR) << __func__
877*4d7e907cSAndroid Build Coastguard Worker                  << ": Cannot find any match for this requirement, exitting...";
878*4d7e907cSAndroid Build Coastguard Worker       result.clear();
879*4d7e907cSAndroid Build Coastguard Worker       *_aidl_return = result;
880*4d7e907cSAndroid Build Coastguard Worker       return ndk::ScopedAStatus::ok();
881*4d7e907cSAndroid Build Coastguard Worker     }
882*4d7e907cSAndroid Build Coastguard Worker   }
883*4d7e907cSAndroid Build Coastguard Worker 
884*4d7e907cSAndroid Build Coastguard Worker   LOG(INFO) << __func__ << ": Found matches for all requirements!";
885*4d7e907cSAndroid Build Coastguard Worker   *_aidl_return = result;
886*4d7e907cSAndroid Build Coastguard Worker   return ndk::ScopedAStatus::ok();
887*4d7e907cSAndroid Build Coastguard Worker };
888*4d7e907cSAndroid Build Coastguard Worker 
isMatchedQosRequirement(LeAudioAseQosConfiguration setting_qos,AseQosDirectionRequirement requirement_qos)889*4d7e907cSAndroid Build Coastguard Worker bool LeAudioOffloadAudioProvider::isMatchedQosRequirement(
890*4d7e907cSAndroid Build Coastguard Worker     LeAudioAseQosConfiguration setting_qos,
891*4d7e907cSAndroid Build Coastguard Worker     AseQosDirectionRequirement requirement_qos) {
892*4d7e907cSAndroid Build Coastguard Worker   if (setting_qos.retransmissionNum !=
893*4d7e907cSAndroid Build Coastguard Worker       requirement_qos.preferredRetransmissionNum) {
894*4d7e907cSAndroid Build Coastguard Worker     return false;
895*4d7e907cSAndroid Build Coastguard Worker   }
896*4d7e907cSAndroid Build Coastguard Worker   if (setting_qos.maxTransportLatencyMs >
897*4d7e907cSAndroid Build Coastguard Worker       requirement_qos.maxTransportLatencyMs) {
898*4d7e907cSAndroid Build Coastguard Worker     return false;
899*4d7e907cSAndroid Build Coastguard Worker   }
900*4d7e907cSAndroid Build Coastguard Worker   return true;
901*4d7e907cSAndroid Build Coastguard Worker }
902*4d7e907cSAndroid Build Coastguard Worker 
isValidQosRequirement(AseQosDirectionRequirement qosRequirement)903*4d7e907cSAndroid Build Coastguard Worker bool isValidQosRequirement(AseQosDirectionRequirement qosRequirement) {
904*4d7e907cSAndroid Build Coastguard Worker   return ((qosRequirement.maxTransportLatencyMs > 0) &&
905*4d7e907cSAndroid Build Coastguard Worker           (qosRequirement.presentationDelayMaxUs > 0) &&
906*4d7e907cSAndroid Build Coastguard Worker           (qosRequirement.presentationDelayMaxUs >=
907*4d7e907cSAndroid Build Coastguard Worker            qosRequirement.presentationDelayMinUs));
908*4d7e907cSAndroid Build Coastguard Worker }
909*4d7e907cSAndroid Build Coastguard Worker 
910*4d7e907cSAndroid Build Coastguard Worker std::optional<LeAudioAseQosConfiguration>
getDirectionQosConfiguration(uint8_t direction,const IBluetoothAudioProvider::LeAudioAseQosConfigurationRequirement & qosRequirement,std::vector<LeAudioAseConfigurationSetting> & ase_configuration_settings,bool is_exact)911*4d7e907cSAndroid Build Coastguard Worker LeAudioOffloadAudioProvider::getDirectionQosConfiguration(
912*4d7e907cSAndroid Build Coastguard Worker     uint8_t direction,
913*4d7e907cSAndroid Build Coastguard Worker     const IBluetoothAudioProvider::LeAudioAseQosConfigurationRequirement&
914*4d7e907cSAndroid Build Coastguard Worker         qosRequirement,
915*4d7e907cSAndroid Build Coastguard Worker     std::vector<LeAudioAseConfigurationSetting>& ase_configuration_settings,
916*4d7e907cSAndroid Build Coastguard Worker     bool is_exact) {
917*4d7e907cSAndroid Build Coastguard Worker   std::optional<AseQosDirectionRequirement> direction_qos_requirement =
918*4d7e907cSAndroid Build Coastguard Worker       std::nullopt;
919*4d7e907cSAndroid Build Coastguard Worker 
920*4d7e907cSAndroid Build Coastguard Worker   // Get the correct direction
921*4d7e907cSAndroid Build Coastguard Worker   if (direction == kLeAudioDirectionSink) {
922*4d7e907cSAndroid Build Coastguard Worker     direction_qos_requirement = qosRequirement.sinkAseQosRequirement.value();
923*4d7e907cSAndroid Build Coastguard Worker   } else {
924*4d7e907cSAndroid Build Coastguard Worker     direction_qos_requirement = qosRequirement.sourceAseQosRequirement.value();
925*4d7e907cSAndroid Build Coastguard Worker   }
926*4d7e907cSAndroid Build Coastguard Worker 
927*4d7e907cSAndroid Build Coastguard Worker   for (auto& setting : ase_configuration_settings) {
928*4d7e907cSAndroid Build Coastguard Worker     // Context matching
929*4d7e907cSAndroid Build Coastguard Worker     if ((setting.audioContext.bitmask & qosRequirement.audioContext.bitmask) !=
930*4d7e907cSAndroid Build Coastguard Worker         qosRequirement.audioContext.bitmask)
931*4d7e907cSAndroid Build Coastguard Worker       continue;
932*4d7e907cSAndroid Build Coastguard Worker 
933*4d7e907cSAndroid Build Coastguard Worker     // Match configuration flags
934*4d7e907cSAndroid Build Coastguard Worker     // Currently configuration flags are not populated, ignore.
935*4d7e907cSAndroid Build Coastguard Worker 
936*4d7e907cSAndroid Build Coastguard Worker     // Get a list of all matched AseDirectionConfiguration
937*4d7e907cSAndroid Build Coastguard Worker     // for the input direction
938*4d7e907cSAndroid Build Coastguard Worker     std::optional<std::vector<std::optional<AseDirectionConfiguration>>>
939*4d7e907cSAndroid Build Coastguard Worker         direction_configuration = std::nullopt;
940*4d7e907cSAndroid Build Coastguard Worker     if (direction == kLeAudioDirectionSink) {
941*4d7e907cSAndroid Build Coastguard Worker       if (!setting.sinkAseConfiguration.has_value()) continue;
942*4d7e907cSAndroid Build Coastguard Worker       direction_configuration.emplace(setting.sinkAseConfiguration.value());
943*4d7e907cSAndroid Build Coastguard Worker     } else {
944*4d7e907cSAndroid Build Coastguard Worker       if (!setting.sourceAseConfiguration.has_value()) continue;
945*4d7e907cSAndroid Build Coastguard Worker       direction_configuration.emplace(setting.sourceAseConfiguration.value());
946*4d7e907cSAndroid Build Coastguard Worker     }
947*4d7e907cSAndroid Build Coastguard Worker 
948*4d7e907cSAndroid Build Coastguard Worker     if (!direction_configuration.has_value()) {
949*4d7e907cSAndroid Build Coastguard Worker       return std::nullopt;
950*4d7e907cSAndroid Build Coastguard Worker     }
951*4d7e907cSAndroid Build Coastguard Worker 
952*4d7e907cSAndroid Build Coastguard Worker     // Collect all valid cfg into a vector
953*4d7e907cSAndroid Build Coastguard Worker     // Then try to get the best match for audio allocation
954*4d7e907cSAndroid Build Coastguard Worker 
955*4d7e907cSAndroid Build Coastguard Worker     auto temp = std::vector<AseDirectionConfiguration>();
956*4d7e907cSAndroid Build Coastguard Worker 
957*4d7e907cSAndroid Build Coastguard Worker     for (auto& cfg : direction_configuration.value()) {
958*4d7e907cSAndroid Build Coastguard Worker       if (!cfg.has_value()) continue;
959*4d7e907cSAndroid Build Coastguard Worker       // If no requirement, return the first QoS
960*4d7e907cSAndroid Build Coastguard Worker       if (!direction_qos_requirement.has_value()) {
961*4d7e907cSAndroid Build Coastguard Worker         return cfg.value().qosConfiguration;
962*4d7e907cSAndroid Build Coastguard Worker       }
963*4d7e907cSAndroid Build Coastguard Worker 
964*4d7e907cSAndroid Build Coastguard Worker       // If has requirement, return the first matched QoS
965*4d7e907cSAndroid Build Coastguard Worker       // Try to match the ASE configuration
966*4d7e907cSAndroid Build Coastguard Worker       // and QoS with requirement
967*4d7e907cSAndroid Build Coastguard Worker       if (!cfg.value().qosConfiguration.has_value()) continue;
968*4d7e907cSAndroid Build Coastguard Worker       if (filterMatchedAseConfiguration(
969*4d7e907cSAndroid Build Coastguard Worker               cfg.value().aseConfiguration,
970*4d7e907cSAndroid Build Coastguard Worker               direction_qos_requirement.value().aseConfiguration) &&
971*4d7e907cSAndroid Build Coastguard Worker           isMatchedQosRequirement(cfg.value().qosConfiguration.value(),
972*4d7e907cSAndroid Build Coastguard Worker                                   direction_qos_requirement.value())) {
973*4d7e907cSAndroid Build Coastguard Worker         temp.push_back(cfg.value());
974*4d7e907cSAndroid Build Coastguard Worker       }
975*4d7e907cSAndroid Build Coastguard Worker     }
976*4d7e907cSAndroid Build Coastguard Worker     LOG(WARNING) << __func__ << ": Got " << temp.size()
977*4d7e907cSAndroid Build Coastguard Worker                  << " configs, start matching allocation";
978*4d7e907cSAndroid Build Coastguard Worker 
979*4d7e907cSAndroid Build Coastguard Worker     int qos_allocation_bitmask = getLeAudioAseConfigurationAllocationBitmask(
980*4d7e907cSAndroid Build Coastguard Worker         direction_qos_requirement.value().aseConfiguration);
981*4d7e907cSAndroid Build Coastguard Worker     // Get the best matching config based on channel allocation
982*4d7e907cSAndroid Build Coastguard Worker     auto req_valid_configs = getValidConfigurationsFromAllocation(
983*4d7e907cSAndroid Build Coastguard Worker         qos_allocation_bitmask, temp, is_exact);
984*4d7e907cSAndroid Build Coastguard Worker     if (req_valid_configs.empty()) {
985*4d7e907cSAndroid Build Coastguard Worker       LOG(WARNING) << __func__
986*4d7e907cSAndroid Build Coastguard Worker                    << ": Cannot find matching allocation for bitmask "
987*4d7e907cSAndroid Build Coastguard Worker                    << qos_allocation_bitmask;
988*4d7e907cSAndroid Build Coastguard Worker 
989*4d7e907cSAndroid Build Coastguard Worker     } else {
990*4d7e907cSAndroid Build Coastguard Worker       return req_valid_configs[0].qosConfiguration;
991*4d7e907cSAndroid Build Coastguard Worker     }
992*4d7e907cSAndroid Build Coastguard Worker   }
993*4d7e907cSAndroid Build Coastguard Worker 
994*4d7e907cSAndroid Build Coastguard Worker   return std::nullopt;
995*4d7e907cSAndroid Build Coastguard Worker }
996*4d7e907cSAndroid Build Coastguard Worker 
getLeAudioAseQosConfiguration(const IBluetoothAudioProvider::LeAudioAseQosConfigurationRequirement & in_qosRequirement,IBluetoothAudioProvider::LeAudioAseQosConfigurationPair * _aidl_return)997*4d7e907cSAndroid Build Coastguard Worker ndk::ScopedAStatus LeAudioOffloadAudioProvider::getLeAudioAseQosConfiguration(
998*4d7e907cSAndroid Build Coastguard Worker     const IBluetoothAudioProvider::LeAudioAseQosConfigurationRequirement&
999*4d7e907cSAndroid Build Coastguard Worker         in_qosRequirement,
1000*4d7e907cSAndroid Build Coastguard Worker     IBluetoothAudioProvider::LeAudioAseQosConfigurationPair* _aidl_return) {
1001*4d7e907cSAndroid Build Coastguard Worker   IBluetoothAudioProvider::LeAudioAseQosConfigurationPair result;
1002*4d7e907cSAndroid Build Coastguard Worker 
1003*4d7e907cSAndroid Build Coastguard Worker   // Get all configuration settings
1004*4d7e907cSAndroid Build Coastguard Worker   std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
1005*4d7e907cSAndroid Build Coastguard Worker       ase_configuration_settings =
1006*4d7e907cSAndroid Build Coastguard Worker           BluetoothAudioCodecs::GetLeAudioAseConfigurationSettings();
1007*4d7e907cSAndroid Build Coastguard Worker 
1008*4d7e907cSAndroid Build Coastguard Worker   // Direction QoS matching
1009*4d7e907cSAndroid Build Coastguard Worker   // Only handle one direction input case
1010*4d7e907cSAndroid Build Coastguard Worker   if (in_qosRequirement.sinkAseQosRequirement.has_value()) {
1011*4d7e907cSAndroid Build Coastguard Worker     if (!isValidQosRequirement(in_qosRequirement.sinkAseQosRequirement.value()))
1012*4d7e907cSAndroid Build Coastguard Worker       return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
1013*4d7e907cSAndroid Build Coastguard Worker     {
1014*4d7e907cSAndroid Build Coastguard Worker       // Try exact match first
1015*4d7e907cSAndroid Build Coastguard Worker       result.sinkQosConfiguration =
1016*4d7e907cSAndroid Build Coastguard Worker           getDirectionQosConfiguration(kLeAudioDirectionSink, in_qosRequirement,
1017*4d7e907cSAndroid Build Coastguard Worker                                        ase_configuration_settings, true);
1018*4d7e907cSAndroid Build Coastguard Worker       if (!result.sinkQosConfiguration.has_value()) {
1019*4d7e907cSAndroid Build Coastguard Worker         result.sinkQosConfiguration = getDirectionQosConfiguration(
1020*4d7e907cSAndroid Build Coastguard Worker             kLeAudioDirectionSink, in_qosRequirement,
1021*4d7e907cSAndroid Build Coastguard Worker             ase_configuration_settings, false);
1022*4d7e907cSAndroid Build Coastguard Worker       }
1023*4d7e907cSAndroid Build Coastguard Worker     }
1024*4d7e907cSAndroid Build Coastguard Worker   }
1025*4d7e907cSAndroid Build Coastguard Worker   if (in_qosRequirement.sourceAseQosRequirement.has_value()) {
1026*4d7e907cSAndroid Build Coastguard Worker     if (!isValidQosRequirement(
1027*4d7e907cSAndroid Build Coastguard Worker             in_qosRequirement.sourceAseQosRequirement.value()))
1028*4d7e907cSAndroid Build Coastguard Worker       return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
1029*4d7e907cSAndroid Build Coastguard Worker     result.sourceQosConfiguration =
1030*4d7e907cSAndroid Build Coastguard Worker         getDirectionQosConfiguration(kLeAudioDirectionSource, in_qosRequirement,
1031*4d7e907cSAndroid Build Coastguard Worker                                      ase_configuration_settings, true);
1032*4d7e907cSAndroid Build Coastguard Worker     if (!result.sourceQosConfiguration.has_value()) {
1033*4d7e907cSAndroid Build Coastguard Worker       result.sourceQosConfiguration = getDirectionQosConfiguration(
1034*4d7e907cSAndroid Build Coastguard Worker           kLeAudioDirectionSource, in_qosRequirement,
1035*4d7e907cSAndroid Build Coastguard Worker           ase_configuration_settings, false);
1036*4d7e907cSAndroid Build Coastguard Worker     }
1037*4d7e907cSAndroid Build Coastguard Worker   }
1038*4d7e907cSAndroid Build Coastguard Worker 
1039*4d7e907cSAndroid Build Coastguard Worker   *_aidl_return = result;
1040*4d7e907cSAndroid Build Coastguard Worker   return ndk::ScopedAStatus::ok();
1041*4d7e907cSAndroid Build Coastguard Worker };
1042*4d7e907cSAndroid Build Coastguard Worker 
onSinkAseMetadataChanged(IBluetoothAudioProvider::AseState in_state,int32_t,int32_t,const std::optional<std::vector<std::optional<MetadataLtv>>> & in_metadata)1043*4d7e907cSAndroid Build Coastguard Worker ndk::ScopedAStatus LeAudioOffloadAudioProvider::onSinkAseMetadataChanged(
1044*4d7e907cSAndroid Build Coastguard Worker     IBluetoothAudioProvider::AseState in_state, int32_t /*in_cigId*/,
1045*4d7e907cSAndroid Build Coastguard Worker     int32_t /*in_cisId*/,
1046*4d7e907cSAndroid Build Coastguard Worker     const std::optional<std::vector<std::optional<MetadataLtv>>>& in_metadata) {
1047*4d7e907cSAndroid Build Coastguard Worker   (void)in_state;
1048*4d7e907cSAndroid Build Coastguard Worker   (void)in_metadata;
1049*4d7e907cSAndroid Build Coastguard Worker   return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
1050*4d7e907cSAndroid Build Coastguard Worker };
1051*4d7e907cSAndroid Build Coastguard Worker 
onSourceAseMetadataChanged(IBluetoothAudioProvider::AseState in_state,int32_t,int32_t,const std::optional<std::vector<std::optional<MetadataLtv>>> & in_metadata)1052*4d7e907cSAndroid Build Coastguard Worker ndk::ScopedAStatus LeAudioOffloadAudioProvider::onSourceAseMetadataChanged(
1053*4d7e907cSAndroid Build Coastguard Worker     IBluetoothAudioProvider::AseState in_state, int32_t /*in_cigId*/,
1054*4d7e907cSAndroid Build Coastguard Worker     int32_t /*in_cisId*/,
1055*4d7e907cSAndroid Build Coastguard Worker     const std::optional<std::vector<std::optional<MetadataLtv>>>& in_metadata) {
1056*4d7e907cSAndroid Build Coastguard Worker   (void)in_state;
1057*4d7e907cSAndroid Build Coastguard Worker   (void)in_metadata;
1058*4d7e907cSAndroid Build Coastguard Worker   return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
1059*4d7e907cSAndroid Build Coastguard Worker };
1060*4d7e907cSAndroid Build Coastguard Worker 
getDefaultBroadcastSetting(int context_bitmask,IBluetoothAudioProvider::BroadcastQuality quality)1061*4d7e907cSAndroid Build Coastguard Worker LeAudioBroadcastConfigurationSetting getDefaultBroadcastSetting(
1062*4d7e907cSAndroid Build Coastguard Worker     int context_bitmask, IBluetoothAudioProvider::BroadcastQuality quality) {
1063*4d7e907cSAndroid Build Coastguard Worker   LeAudioBroadcastConfigurationSetting setting;
1064*4d7e907cSAndroid Build Coastguard Worker   setting.retransmitionNum = 4;
1065*4d7e907cSAndroid Build Coastguard Worker   setting.maxTransportLatencyMs = 60;
1066*4d7e907cSAndroid Build Coastguard Worker   setting.sduIntervalUs = 10000;
1067*4d7e907cSAndroid Build Coastguard Worker   setting.maxSduOctets = 40;
1068*4d7e907cSAndroid Build Coastguard Worker 
1069*4d7e907cSAndroid Build Coastguard Worker   if (quality == IBluetoothAudioProvider::BroadcastQuality::HIGH) {
1070*4d7e907cSAndroid Build Coastguard Worker     LOG(INFO) << __func__ << ": High quality, returning high quality settings";
1071*4d7e907cSAndroid Build Coastguard Worker     setting.retransmitionNum = 4;
1072*4d7e907cSAndroid Build Coastguard Worker     setting.maxTransportLatencyMs = 65;
1073*4d7e907cSAndroid Build Coastguard Worker     setting.maxSduOctets = 200;
1074*4d7e907cSAndroid Build Coastguard Worker     return setting;
1075*4d7e907cSAndroid Build Coastguard Worker   }
1076*4d7e907cSAndroid Build Coastguard Worker 
1077*4d7e907cSAndroid Build Coastguard Worker   // Populate other settings base on context
1078*4d7e907cSAndroid Build Coastguard Worker   // TODO: Populate with better design
1079*4d7e907cSAndroid Build Coastguard Worker   if (context_bitmask & (AudioContext::LIVE_AUDIO | AudioContext::GAME)) {
1080*4d7e907cSAndroid Build Coastguard Worker     setting.retransmitionNum = 2;
1081*4d7e907cSAndroid Build Coastguard Worker     setting.maxTransportLatencyMs = 10;
1082*4d7e907cSAndroid Build Coastguard Worker     setting.maxSduOctets = 120;
1083*4d7e907cSAndroid Build Coastguard Worker   } else if (context_bitmask & (AudioContext::INSTRUCTIONAL)) {
1084*4d7e907cSAndroid Build Coastguard Worker     setting.retransmitionNum = 2;
1085*4d7e907cSAndroid Build Coastguard Worker     setting.maxTransportLatencyMs = 10;
1086*4d7e907cSAndroid Build Coastguard Worker     setting.maxSduOctets = 40;
1087*4d7e907cSAndroid Build Coastguard Worker   } else if (context_bitmask &
1088*4d7e907cSAndroid Build Coastguard Worker              (AudioContext::SOUND_EFFECTS | AudioContext::UNSPECIFIED)) {
1089*4d7e907cSAndroid Build Coastguard Worker     setting.retransmitionNum = 4;
1090*4d7e907cSAndroid Build Coastguard Worker     setting.maxTransportLatencyMs = 60;
1091*4d7e907cSAndroid Build Coastguard Worker     setting.maxSduOctets = 80;
1092*4d7e907cSAndroid Build Coastguard Worker   } else if (context_bitmask &
1093*4d7e907cSAndroid Build Coastguard Worker              (AudioContext::ALERTS | AudioContext::NOTIFICATIONS |
1094*4d7e907cSAndroid Build Coastguard Worker               AudioContext::EMERGENCY_ALARM)) {
1095*4d7e907cSAndroid Build Coastguard Worker     setting.retransmitionNum = 4;
1096*4d7e907cSAndroid Build Coastguard Worker     setting.maxTransportLatencyMs = 60;
1097*4d7e907cSAndroid Build Coastguard Worker     setting.maxSduOctets = 40;
1098*4d7e907cSAndroid Build Coastguard Worker   } else if (context_bitmask & AudioContext::MEDIA) {
1099*4d7e907cSAndroid Build Coastguard Worker     setting.retransmitionNum = 4;
1100*4d7e907cSAndroid Build Coastguard Worker     setting.maxTransportLatencyMs = 60;
1101*4d7e907cSAndroid Build Coastguard Worker     setting.maxSduOctets = 120;
1102*4d7e907cSAndroid Build Coastguard Worker   }
1103*4d7e907cSAndroid Build Coastguard Worker 
1104*4d7e907cSAndroid Build Coastguard Worker   return setting;
1105*4d7e907cSAndroid Build Coastguard Worker }
modifySubBISConfigAllocation(IBluetoothAudioProvider::LeAudioSubgroupBisConfiguration & sub_bis_cfg,int allocation_bitmask)1106*4d7e907cSAndroid Build Coastguard Worker void modifySubBISConfigAllocation(
1107*4d7e907cSAndroid Build Coastguard Worker     IBluetoothAudioProvider::LeAudioSubgroupBisConfiguration& sub_bis_cfg,
1108*4d7e907cSAndroid Build Coastguard Worker     int allocation_bitmask) {
1109*4d7e907cSAndroid Build Coastguard Worker   for (auto& codec_cfg : sub_bis_cfg.bisConfiguration.codecConfiguration) {
1110*4d7e907cSAndroid Build Coastguard Worker     if (codec_cfg.getTag() ==
1111*4d7e907cSAndroid Build Coastguard Worker         CodecSpecificConfigurationLtv::audioChannelAllocation) {
1112*4d7e907cSAndroid Build Coastguard Worker       codec_cfg.get<CodecSpecificConfigurationLtv::audioChannelAllocation>()
1113*4d7e907cSAndroid Build Coastguard Worker           .bitmask = allocation_bitmask;
1114*4d7e907cSAndroid Build Coastguard Worker       break;
1115*4d7e907cSAndroid Build Coastguard Worker     }
1116*4d7e907cSAndroid Build Coastguard Worker   }
1117*4d7e907cSAndroid Build Coastguard Worker }
modifySubgroupConfiguration(IBluetoothAudioProvider::LeAudioBroadcastSubgroupConfiguration & subgroup_cfg,int context_bitmask)1118*4d7e907cSAndroid Build Coastguard Worker void modifySubgroupConfiguration(
1119*4d7e907cSAndroid Build Coastguard Worker     IBluetoothAudioProvider::LeAudioBroadcastSubgroupConfiguration&
1120*4d7e907cSAndroid Build Coastguard Worker         subgroup_cfg,
1121*4d7e907cSAndroid Build Coastguard Worker     int context_bitmask) {
1122*4d7e907cSAndroid Build Coastguard Worker   // STEREO configs
1123*4d7e907cSAndroid Build Coastguard Worker   // Split into 2 sub BIS config, each has numBis = 1
1124*4d7e907cSAndroid Build Coastguard Worker   if (context_bitmask & (AudioContext::LIVE_AUDIO | AudioContext::GAME |
1125*4d7e907cSAndroid Build Coastguard Worker                          AudioContext::SOUND_EFFECTS |
1126*4d7e907cSAndroid Build Coastguard Worker                          AudioContext::UNSPECIFIED | AudioContext::MEDIA)) {
1127*4d7e907cSAndroid Build Coastguard Worker     if (subgroup_cfg.bisConfigurations.size() == 1)
1128*4d7e907cSAndroid Build Coastguard Worker       subgroup_cfg.bisConfigurations.push_back(
1129*4d7e907cSAndroid Build Coastguard Worker           subgroup_cfg.bisConfigurations[0]);
1130*4d7e907cSAndroid Build Coastguard Worker 
1131*4d7e907cSAndroid Build Coastguard Worker     subgroup_cfg.bisConfigurations[0].numBis = 1;
1132*4d7e907cSAndroid Build Coastguard Worker     modifySubBISConfigAllocation(
1133*4d7e907cSAndroid Build Coastguard Worker         subgroup_cfg.bisConfigurations[0],
1134*4d7e907cSAndroid Build Coastguard Worker         CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_LEFT);
1135*4d7e907cSAndroid Build Coastguard Worker 
1136*4d7e907cSAndroid Build Coastguard Worker     subgroup_cfg.bisConfigurations[1].numBis = 1;
1137*4d7e907cSAndroid Build Coastguard Worker     modifySubBISConfigAllocation(
1138*4d7e907cSAndroid Build Coastguard Worker         subgroup_cfg.bisConfigurations[1],
1139*4d7e907cSAndroid Build Coastguard Worker         CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_RIGHT);
1140*4d7e907cSAndroid Build Coastguard Worker     return;
1141*4d7e907cSAndroid Build Coastguard Worker   }
1142*4d7e907cSAndroid Build Coastguard Worker 
1143*4d7e907cSAndroid Build Coastguard Worker   // MONO configs
1144*4d7e907cSAndroid Build Coastguard Worker   for (auto& sub_bis_cfg : subgroup_cfg.bisConfigurations) {
1145*4d7e907cSAndroid Build Coastguard Worker     sub_bis_cfg.numBis = 1;
1146*4d7e907cSAndroid Build Coastguard Worker     modifySubBISConfigAllocation(
1147*4d7e907cSAndroid Build Coastguard Worker         sub_bis_cfg,
1148*4d7e907cSAndroid Build Coastguard Worker         CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_CENTER);
1149*4d7e907cSAndroid Build Coastguard Worker   }
1150*4d7e907cSAndroid Build Coastguard Worker }
1151*4d7e907cSAndroid Build Coastguard Worker 
getBroadcastSettings()1152*4d7e907cSAndroid Build Coastguard Worker void LeAudioOffloadAudioProvider::getBroadcastSettings() {
1153*4d7e907cSAndroid Build Coastguard Worker   if (!broadcast_settings.empty()) return;
1154*4d7e907cSAndroid Build Coastguard Worker 
1155*4d7e907cSAndroid Build Coastguard Worker   LOG(INFO) << __func__
1156*4d7e907cSAndroid Build Coastguard Worker             << ": Loading basic broadcast settings from provider info";
1157*4d7e907cSAndroid Build Coastguard Worker 
1158*4d7e907cSAndroid Build Coastguard Worker   std::vector<CodecInfo> db_codec_info =
1159*4d7e907cSAndroid Build Coastguard Worker       BluetoothAudioCodecs::GetLeAudioOffloadCodecInfo(
1160*4d7e907cSAndroid Build Coastguard Worker           SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH);
1161*4d7e907cSAndroid Build Coastguard Worker   for (auto x : db_codec_info) {
1162*4d7e907cSAndroid Build Coastguard Worker     LOG(INFO) << __func__ << ": codec info = " << x.toString();
1163*4d7e907cSAndroid Build Coastguard Worker   }
1164*4d7e907cSAndroid Build Coastguard Worker   broadcast_settings.clear();
1165*4d7e907cSAndroid Build Coastguard Worker 
1166*4d7e907cSAndroid Build Coastguard Worker   // Default value population
1167*4d7e907cSAndroid Build Coastguard Worker   CodecSpecificConfigurationLtv::AudioChannelAllocation default_allocation;
1168*4d7e907cSAndroid Build Coastguard Worker   default_allocation.bitmask =
1169*4d7e907cSAndroid Build Coastguard Worker       CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_CENTER;
1170*4d7e907cSAndroid Build Coastguard Worker   CodecSpecificConfigurationLtv::CodecFrameBlocksPerSDU default_frame;
1171*4d7e907cSAndroid Build Coastguard Worker   default_frame.value = 1;
1172*4d7e907cSAndroid Build Coastguard Worker 
1173*4d7e907cSAndroid Build Coastguard Worker   for (auto& codec_info : db_codec_info) {
1174*4d7e907cSAndroid Build Coastguard Worker     if (codec_info.transport.getTag() != CodecInfo::Transport::leAudio)
1175*4d7e907cSAndroid Build Coastguard Worker       continue;
1176*4d7e907cSAndroid Build Coastguard Worker     auto& transport = codec_info.transport.get<CodecInfo::Transport::leAudio>();
1177*4d7e907cSAndroid Build Coastguard Worker     LeAudioBroadcastConfigurationSetting setting;
1178*4d7e907cSAndroid Build Coastguard Worker     setting.retransmitionNum = 4;
1179*4d7e907cSAndroid Build Coastguard Worker     setting.maxTransportLatencyMs = 60;
1180*4d7e907cSAndroid Build Coastguard Worker     setting.sduIntervalUs = 10000;
1181*4d7e907cSAndroid Build Coastguard Worker     setting.maxSduOctets = 40;
1182*4d7e907cSAndroid Build Coastguard Worker     // Default setting
1183*4d7e907cSAndroid Build Coastguard Worker     setting.numBis = 1;
1184*4d7e907cSAndroid Build Coastguard Worker     setting.phy = {Phy::TWO_M};
1185*4d7e907cSAndroid Build Coastguard Worker     // Populate BIS configuration info using codec_info
1186*4d7e907cSAndroid Build Coastguard Worker     LeAudioBisConfiguration bis_cfg;
1187*4d7e907cSAndroid Build Coastguard Worker     bis_cfg.codecId = codec_info.id;
1188*4d7e907cSAndroid Build Coastguard Worker 
1189*4d7e907cSAndroid Build Coastguard Worker     CodecSpecificConfigurationLtv::OctetsPerCodecFrame octets;
1190*4d7e907cSAndroid Build Coastguard Worker     octets.value = transport.bitdepth[0];
1191*4d7e907cSAndroid Build Coastguard Worker 
1192*4d7e907cSAndroid Build Coastguard Worker     bis_cfg.codecConfiguration = {
1193*4d7e907cSAndroid Build Coastguard Worker         sampling_freq_map[transport.samplingFrequencyHz[0]],
1194*4d7e907cSAndroid Build Coastguard Worker         octets,
1195*4d7e907cSAndroid Build Coastguard Worker         frame_duration_map[transport.frameDurationUs[0]],
1196*4d7e907cSAndroid Build Coastguard Worker         default_allocation,
1197*4d7e907cSAndroid Build Coastguard Worker         default_frame,
1198*4d7e907cSAndroid Build Coastguard Worker     };
1199*4d7e907cSAndroid Build Coastguard Worker 
1200*4d7e907cSAndroid Build Coastguard Worker     // Ignore bis_cfg.metadata
1201*4d7e907cSAndroid Build Coastguard Worker 
1202*4d7e907cSAndroid Build Coastguard Worker     // Add information to structure
1203*4d7e907cSAndroid Build Coastguard Worker     IBluetoothAudioProvider::LeAudioSubgroupBisConfiguration sub_bis_cfg;
1204*4d7e907cSAndroid Build Coastguard Worker     sub_bis_cfg.numBis = 1;
1205*4d7e907cSAndroid Build Coastguard Worker     sub_bis_cfg.bisConfiguration = bis_cfg;
1206*4d7e907cSAndroid Build Coastguard Worker     IBluetoothAudioProvider::LeAudioBroadcastSubgroupConfiguration sub_cfg;
1207*4d7e907cSAndroid Build Coastguard Worker     // Populate the same sub config
1208*4d7e907cSAndroid Build Coastguard Worker     sub_cfg.bisConfigurations = {sub_bis_cfg};
1209*4d7e907cSAndroid Build Coastguard Worker     setting.subgroupsConfigurations = {sub_cfg};
1210*4d7e907cSAndroid Build Coastguard Worker 
1211*4d7e907cSAndroid Build Coastguard Worker     broadcast_settings.push_back(setting);
1212*4d7e907cSAndroid Build Coastguard Worker   }
1213*4d7e907cSAndroid Build Coastguard Worker 
1214*4d7e907cSAndroid Build Coastguard Worker   LOG(INFO) << __func__
1215*4d7e907cSAndroid Build Coastguard Worker             << ": Done loading broadcast settings from provider info";
1216*4d7e907cSAndroid Build Coastguard Worker }
1217*4d7e907cSAndroid Build Coastguard Worker 
1218*4d7e907cSAndroid Build Coastguard Worker /* Get a new LeAudioAseConfigurationSetting by matching a setting with a
1219*4d7e907cSAndroid Build Coastguard Worker  * capabilities. The new setting will have a filtered list of
1220*4d7e907cSAndroid Build Coastguard Worker  * AseDirectionConfiguration that matched the capabilities */
1221*4d7e907cSAndroid Build Coastguard Worker std::optional<LeAudioBroadcastConfigurationSetting>
1222*4d7e907cSAndroid Build Coastguard Worker LeAudioOffloadAudioProvider::
getCapabilitiesMatchedBroadcastConfigurationSettings(LeAudioBroadcastConfigurationSetting & setting,const IBluetoothAudioProvider::LeAudioDeviceCapabilities & capabilities)1223*4d7e907cSAndroid Build Coastguard Worker     getCapabilitiesMatchedBroadcastConfigurationSettings(
1224*4d7e907cSAndroid Build Coastguard Worker         LeAudioBroadcastConfigurationSetting& setting,
1225*4d7e907cSAndroid Build Coastguard Worker         const IBluetoothAudioProvider::LeAudioDeviceCapabilities&
1226*4d7e907cSAndroid Build Coastguard Worker             capabilities) {
1227*4d7e907cSAndroid Build Coastguard Worker   std::vector<IBluetoothAudioProvider::LeAudioBroadcastSubgroupConfiguration>
1228*4d7e907cSAndroid Build Coastguard Worker       filter_subgroup;
1229*4d7e907cSAndroid Build Coastguard Worker   for (auto& sub_cfg : setting.subgroupsConfigurations) {
1230*4d7e907cSAndroid Build Coastguard Worker     std::vector<IBluetoothAudioProvider::LeAudioSubgroupBisConfiguration>
1231*4d7e907cSAndroid Build Coastguard Worker         filtered_bis_cfg;
1232*4d7e907cSAndroid Build Coastguard Worker     for (auto& bis_cfg : sub_cfg.bisConfigurations)
1233*4d7e907cSAndroid Build Coastguard Worker       if (isMatchedBISConfiguration(bis_cfg.bisConfiguration, capabilities)) {
1234*4d7e907cSAndroid Build Coastguard Worker         filtered_bis_cfg.push_back(bis_cfg);
1235*4d7e907cSAndroid Build Coastguard Worker       }
1236*4d7e907cSAndroid Build Coastguard Worker     if (!filtered_bis_cfg.empty()) {
1237*4d7e907cSAndroid Build Coastguard Worker       IBluetoothAudioProvider::LeAudioBroadcastSubgroupConfiguration
1238*4d7e907cSAndroid Build Coastguard Worker           subgroup_cfg;
1239*4d7e907cSAndroid Build Coastguard Worker       subgroup_cfg.bisConfigurations = filtered_bis_cfg;
1240*4d7e907cSAndroid Build Coastguard Worker       filter_subgroup.push_back(subgroup_cfg);
1241*4d7e907cSAndroid Build Coastguard Worker     }
1242*4d7e907cSAndroid Build Coastguard Worker   }
1243*4d7e907cSAndroid Build Coastguard Worker   if (filter_subgroup.empty()) return std::nullopt;
1244*4d7e907cSAndroid Build Coastguard Worker 
1245*4d7e907cSAndroid Build Coastguard Worker   // Create a new LeAudioAseConfigurationSetting and return
1246*4d7e907cSAndroid Build Coastguard Worker   LeAudioBroadcastConfigurationSetting filtered_setting(setting);
1247*4d7e907cSAndroid Build Coastguard Worker   filtered_setting.subgroupsConfigurations = filter_subgroup;
1248*4d7e907cSAndroid Build Coastguard Worker 
1249*4d7e907cSAndroid Build Coastguard Worker   return filtered_setting;
1250*4d7e907cSAndroid Build Coastguard Worker }
1251*4d7e907cSAndroid Build Coastguard Worker 
getCodecRequirementBasedOnContext(int context_bitmask,IBluetoothAudioProvider::BroadcastQuality quality)1252*4d7e907cSAndroid Build Coastguard Worker std::vector<CodecSpecificConfigurationLtv> getCodecRequirementBasedOnContext(
1253*4d7e907cSAndroid Build Coastguard Worker     int context_bitmask, IBluetoothAudioProvider::BroadcastQuality quality) {
1254*4d7e907cSAndroid Build Coastguard Worker   // Default requirement: lc3_stereo_16_2
1255*4d7e907cSAndroid Build Coastguard Worker   std::vector<CodecSpecificConfigurationLtv> requirement = {
1256*4d7e907cSAndroid Build Coastguard Worker       CodecSpecificConfigurationLtv::SamplingFrequency::HZ16000,
1257*4d7e907cSAndroid Build Coastguard Worker       CodecSpecificConfigurationLtv::FrameDuration::US10000,
1258*4d7e907cSAndroid Build Coastguard Worker   };
1259*4d7e907cSAndroid Build Coastguard Worker 
1260*4d7e907cSAndroid Build Coastguard Worker   if (quality == IBluetoothAudioProvider::BroadcastQuality::HIGH) {
1261*4d7e907cSAndroid Build Coastguard Worker     LOG(INFO) << __func__
1262*4d7e907cSAndroid Build Coastguard Worker               << ": High quality, returning high quality requirement";
1263*4d7e907cSAndroid Build Coastguard Worker     requirement = {
1264*4d7e907cSAndroid Build Coastguard Worker         CodecSpecificConfigurationLtv::SamplingFrequency::HZ48000,
1265*4d7e907cSAndroid Build Coastguard Worker         CodecSpecificConfigurationLtv::FrameDuration::US10000,
1266*4d7e907cSAndroid Build Coastguard Worker     };
1267*4d7e907cSAndroid Build Coastguard Worker     return requirement;
1268*4d7e907cSAndroid Build Coastguard Worker   }
1269*4d7e907cSAndroid Build Coastguard Worker 
1270*4d7e907cSAndroid Build Coastguard Worker   if (context_bitmask & (AudioContext::LIVE_AUDIO | AudioContext::GAME)) {
1271*4d7e907cSAndroid Build Coastguard Worker     // lc3_stereo_24_2_1
1272*4d7e907cSAndroid Build Coastguard Worker     requirement = {
1273*4d7e907cSAndroid Build Coastguard Worker         CodecSpecificConfigurationLtv::SamplingFrequency::HZ24000,
1274*4d7e907cSAndroid Build Coastguard Worker         CodecSpecificConfigurationLtv::FrameDuration::US10000,
1275*4d7e907cSAndroid Build Coastguard Worker     };
1276*4d7e907cSAndroid Build Coastguard Worker   } else if (context_bitmask & (AudioContext::INSTRUCTIONAL)) {
1277*4d7e907cSAndroid Build Coastguard Worker     // lc3_mono_16_2
1278*4d7e907cSAndroid Build Coastguard Worker     requirement = {
1279*4d7e907cSAndroid Build Coastguard Worker         CodecSpecificConfigurationLtv::SamplingFrequency::HZ16000,
1280*4d7e907cSAndroid Build Coastguard Worker         CodecSpecificConfigurationLtv::FrameDuration::US10000,
1281*4d7e907cSAndroid Build Coastguard Worker     };
1282*4d7e907cSAndroid Build Coastguard Worker   } else if (context_bitmask &
1283*4d7e907cSAndroid Build Coastguard Worker              (AudioContext::SOUND_EFFECTS | AudioContext::UNSPECIFIED)) {
1284*4d7e907cSAndroid Build Coastguard Worker     // lc3_stereo_16_2
1285*4d7e907cSAndroid Build Coastguard Worker     requirement = {
1286*4d7e907cSAndroid Build Coastguard Worker         CodecSpecificConfigurationLtv::SamplingFrequency::HZ16000,
1287*4d7e907cSAndroid Build Coastguard Worker         CodecSpecificConfigurationLtv::FrameDuration::US10000,
1288*4d7e907cSAndroid Build Coastguard Worker     };
1289*4d7e907cSAndroid Build Coastguard Worker   } else if (context_bitmask &
1290*4d7e907cSAndroid Build Coastguard Worker              (AudioContext::ALERTS | AudioContext::NOTIFICATIONS |
1291*4d7e907cSAndroid Build Coastguard Worker               AudioContext::EMERGENCY_ALARM)) {
1292*4d7e907cSAndroid Build Coastguard Worker     // Default requirement: lc3_stereo_16_2
1293*4d7e907cSAndroid Build Coastguard Worker     requirement = {
1294*4d7e907cSAndroid Build Coastguard Worker         CodecSpecificConfigurationLtv::SamplingFrequency::HZ16000,
1295*4d7e907cSAndroid Build Coastguard Worker         CodecSpecificConfigurationLtv::FrameDuration::US10000,
1296*4d7e907cSAndroid Build Coastguard Worker     };
1297*4d7e907cSAndroid Build Coastguard Worker   } else if (context_bitmask & AudioContext::MEDIA) {
1298*4d7e907cSAndroid Build Coastguard Worker     // Default requirement: lc3_stereo_16_2
1299*4d7e907cSAndroid Build Coastguard Worker     // Return the 48k requirement
1300*4d7e907cSAndroid Build Coastguard Worker     requirement = {
1301*4d7e907cSAndroid Build Coastguard Worker         CodecSpecificConfigurationLtv::SamplingFrequency::HZ24000,
1302*4d7e907cSAndroid Build Coastguard Worker         CodecSpecificConfigurationLtv::FrameDuration::US10000,
1303*4d7e907cSAndroid Build Coastguard Worker     };
1304*4d7e907cSAndroid Build Coastguard Worker   }
1305*4d7e907cSAndroid Build Coastguard Worker   return requirement;
1306*4d7e907cSAndroid Build Coastguard Worker }
1307*4d7e907cSAndroid Build Coastguard Worker 
isSubgroupConfigurationMatchedContext(AudioContext requirement_context,IBluetoothAudioProvider::BroadcastQuality quality,LeAudioBroadcastSubgroupConfiguration configuration)1308*4d7e907cSAndroid Build Coastguard Worker bool LeAudioOffloadAudioProvider::isSubgroupConfigurationMatchedContext(
1309*4d7e907cSAndroid Build Coastguard Worker     AudioContext requirement_context,
1310*4d7e907cSAndroid Build Coastguard Worker     IBluetoothAudioProvider::BroadcastQuality quality,
1311*4d7e907cSAndroid Build Coastguard Worker     LeAudioBroadcastSubgroupConfiguration configuration) {
1312*4d7e907cSAndroid Build Coastguard Worker   // Find any valid context metadata in the bisConfigurations
1313*4d7e907cSAndroid Build Coastguard Worker   // assuming the bis configuration in the same bis subgroup
1314*4d7e907cSAndroid Build Coastguard Worker   // will have the same context metadata
1315*4d7e907cSAndroid Build Coastguard Worker   std::optional<AudioContext> config_context = std::nullopt;
1316*4d7e907cSAndroid Build Coastguard Worker 
1317*4d7e907cSAndroid Build Coastguard Worker   auto codec_requirement =
1318*4d7e907cSAndroid Build Coastguard Worker       getCodecRequirementBasedOnContext(requirement_context.bitmask, quality);
1319*4d7e907cSAndroid Build Coastguard Worker   std::map<CodecSpecificConfigurationLtv::Tag, CodecSpecificConfigurationLtv>
1320*4d7e907cSAndroid Build Coastguard Worker       req_tag_map;
1321*4d7e907cSAndroid Build Coastguard Worker   for (auto x : codec_requirement) req_tag_map[x.getTag()] = x;
1322*4d7e907cSAndroid Build Coastguard Worker 
1323*4d7e907cSAndroid Build Coastguard Worker   for (auto& bis_cfg : configuration.bisConfigurations) {
1324*4d7e907cSAndroid Build Coastguard Worker     // Check every sub_bis_cfg to see which match
1325*4d7e907cSAndroid Build Coastguard Worker     for (auto& x : bis_cfg.bisConfiguration.codecConfiguration) {
1326*4d7e907cSAndroid Build Coastguard Worker       auto p = req_tag_map.find(x.getTag());
1327*4d7e907cSAndroid Build Coastguard Worker       if (p == req_tag_map.end()) continue;
1328*4d7e907cSAndroid Build Coastguard Worker       if (p->second != x) {
1329*4d7e907cSAndroid Build Coastguard Worker         LOG(WARNING) << __func__ << ": does not match for context "
1330*4d7e907cSAndroid Build Coastguard Worker                      << requirement_context.toString()
1331*4d7e907cSAndroid Build Coastguard Worker                      << ", cfg = " << x.toString();
1332*4d7e907cSAndroid Build Coastguard Worker         return false;
1333*4d7e907cSAndroid Build Coastguard Worker       }
1334*4d7e907cSAndroid Build Coastguard Worker     }
1335*4d7e907cSAndroid Build Coastguard Worker   }
1336*4d7e907cSAndroid Build Coastguard Worker   return true;
1337*4d7e907cSAndroid Build Coastguard Worker }
1338*4d7e907cSAndroid Build Coastguard Worker 
1339*4d7e907cSAndroid Build Coastguard Worker ndk::ScopedAStatus
getLeAudioBroadcastConfiguration(const std::optional<std::vector<std::optional<IBluetoothAudioProvider::LeAudioDeviceCapabilities>>> & in_remoteSinkAudioCapabilities,const IBluetoothAudioProvider::LeAudioBroadcastConfigurationRequirement & in_requirement,LeAudioBroadcastConfigurationSetting * _aidl_return)1340*4d7e907cSAndroid Build Coastguard Worker LeAudioOffloadAudioProvider::getLeAudioBroadcastConfiguration(
1341*4d7e907cSAndroid Build Coastguard Worker     const std::optional<std::vector<
1342*4d7e907cSAndroid Build Coastguard Worker         std::optional<IBluetoothAudioProvider::LeAudioDeviceCapabilities>>>&
1343*4d7e907cSAndroid Build Coastguard Worker         in_remoteSinkAudioCapabilities,
1344*4d7e907cSAndroid Build Coastguard Worker     const IBluetoothAudioProvider::LeAudioBroadcastConfigurationRequirement&
1345*4d7e907cSAndroid Build Coastguard Worker         in_requirement,
1346*4d7e907cSAndroid Build Coastguard Worker     LeAudioBroadcastConfigurationSetting* _aidl_return) {
1347*4d7e907cSAndroid Build Coastguard Worker   if (in_requirement.subgroupConfigurationRequirements.empty()) {
1348*4d7e907cSAndroid Build Coastguard Worker     LOG(WARNING) << __func__ << ": Empty requirement";
1349*4d7e907cSAndroid Build Coastguard Worker     return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
1350*4d7e907cSAndroid Build Coastguard Worker   }
1351*4d7e907cSAndroid Build Coastguard Worker 
1352*4d7e907cSAndroid Build Coastguard Worker   // Broadcast setting are from provider info
1353*4d7e907cSAndroid Build Coastguard Worker   // We will allow empty capability input, match all settings with requirements.
1354*4d7e907cSAndroid Build Coastguard Worker   getBroadcastSettings();
1355*4d7e907cSAndroid Build Coastguard Worker   std::vector<LeAudioBroadcastConfigurationSetting> filtered_settings;
1356*4d7e907cSAndroid Build Coastguard Worker   if (!in_remoteSinkAudioCapabilities.has_value() ||
1357*4d7e907cSAndroid Build Coastguard Worker       in_remoteSinkAudioCapabilities.value().empty()) {
1358*4d7e907cSAndroid Build Coastguard Worker     LOG(INFO) << __func__ << ": Empty capability, get all broadcast settings";
1359*4d7e907cSAndroid Build Coastguard Worker     filtered_settings = broadcast_settings;
1360*4d7e907cSAndroid Build Coastguard Worker   } else {
1361*4d7e907cSAndroid Build Coastguard Worker     for (auto& setting : broadcast_settings) {
1362*4d7e907cSAndroid Build Coastguard Worker       for (auto& capability : in_remoteSinkAudioCapabilities.value()) {
1363*4d7e907cSAndroid Build Coastguard Worker         if (!capability.has_value()) continue;
1364*4d7e907cSAndroid Build Coastguard Worker         auto filtered_setting =
1365*4d7e907cSAndroid Build Coastguard Worker             getCapabilitiesMatchedBroadcastConfigurationSettings(
1366*4d7e907cSAndroid Build Coastguard Worker                 setting, capability.value());
1367*4d7e907cSAndroid Build Coastguard Worker         if (filtered_setting.has_value())
1368*4d7e907cSAndroid Build Coastguard Worker           filtered_settings.push_back(filtered_setting.value());
1369*4d7e907cSAndroid Build Coastguard Worker       }
1370*4d7e907cSAndroid Build Coastguard Worker     }
1371*4d7e907cSAndroid Build Coastguard Worker   }
1372*4d7e907cSAndroid Build Coastguard Worker 
1373*4d7e907cSAndroid Build Coastguard Worker   if (filtered_settings.empty()) {
1374*4d7e907cSAndroid Build Coastguard Worker     LOG(WARNING) << __func__ << ": Cannot match any remote capability";
1375*4d7e907cSAndroid Build Coastguard Worker     return ndk::ScopedAStatus::ok();
1376*4d7e907cSAndroid Build Coastguard Worker   }
1377*4d7e907cSAndroid Build Coastguard Worker 
1378*4d7e907cSAndroid Build Coastguard Worker   if (in_requirement.subgroupConfigurationRequirements.empty()) {
1379*4d7e907cSAndroid Build Coastguard Worker     LOG(INFO) << __func__ << ": Empty requirement";
1380*4d7e907cSAndroid Build Coastguard Worker     *_aidl_return = filtered_settings[0];
1381*4d7e907cSAndroid Build Coastguard Worker     return ndk::ScopedAStatus::ok();
1382*4d7e907cSAndroid Build Coastguard Worker   }
1383*4d7e907cSAndroid Build Coastguard Worker 
1384*4d7e907cSAndroid Build Coastguard Worker   // For each subgroup config requirement, find a suitable subgroup config.
1385*4d7e907cSAndroid Build Coastguard Worker   // Gather these suitable subgroup config in an array.
1386*4d7e907cSAndroid Build Coastguard Worker   // If the setting can satisfy all requirement, we can return the setting
1387*4d7e907cSAndroid Build Coastguard Worker   // with the filtered array.
1388*4d7e907cSAndroid Build Coastguard Worker 
1389*4d7e907cSAndroid Build Coastguard Worker   auto context_bitmask =
1390*4d7e907cSAndroid Build Coastguard Worker       in_requirement.subgroupConfigurationRequirements[0].audioContext.bitmask;
1391*4d7e907cSAndroid Build Coastguard Worker   auto quality = in_requirement.subgroupConfigurationRequirements[0].quality;
1392*4d7e907cSAndroid Build Coastguard Worker   LeAudioBroadcastConfigurationSetting return_setting =
1393*4d7e907cSAndroid Build Coastguard Worker       getDefaultBroadcastSetting(context_bitmask, quality);
1394*4d7e907cSAndroid Build Coastguard Worker   // Default setting
1395*4d7e907cSAndroid Build Coastguard Worker   return_setting.numBis = 0;
1396*4d7e907cSAndroid Build Coastguard Worker   return_setting.subgroupsConfigurations = {};
1397*4d7e907cSAndroid Build Coastguard Worker 
1398*4d7e907cSAndroid Build Coastguard Worker   LeAudioDataPathConfiguration path;
1399*4d7e907cSAndroid Build Coastguard Worker   path.isoDataPathConfiguration.isTransparent = true;
1400*4d7e907cSAndroid Build Coastguard Worker   path.dataPathId = kIsoDataPathPlatformDefault;
1401*4d7e907cSAndroid Build Coastguard Worker 
1402*4d7e907cSAndroid Build Coastguard Worker   // Each subreq, find a setting that match
1403*4d7e907cSAndroid Build Coastguard Worker   for (auto& sub_req : in_requirement.subgroupConfigurationRequirements) {
1404*4d7e907cSAndroid Build Coastguard Worker     bool is_setting_matched = false;
1405*4d7e907cSAndroid Build Coastguard Worker     for (auto setting : filtered_settings) {
1406*4d7e907cSAndroid Build Coastguard Worker       bool is_matched = true;
1407*4d7e907cSAndroid Build Coastguard Worker       // Check if every sub BIS config satisfy
1408*4d7e907cSAndroid Build Coastguard Worker       for (auto& sub_group_config : setting.subgroupsConfigurations) {
1409*4d7e907cSAndroid Build Coastguard Worker         if (!isSubgroupConfigurationMatchedContext(
1410*4d7e907cSAndroid Build Coastguard Worker                 sub_req.audioContext, sub_req.quality, sub_group_config)) {
1411*4d7e907cSAndroid Build Coastguard Worker           is_matched = false;
1412*4d7e907cSAndroid Build Coastguard Worker           break;
1413*4d7e907cSAndroid Build Coastguard Worker         }
1414*4d7e907cSAndroid Build Coastguard Worker         path.isoDataPathConfiguration.codecId =
1415*4d7e907cSAndroid Build Coastguard Worker             sub_group_config.bisConfigurations[0].bisConfiguration.codecId;
1416*4d7e907cSAndroid Build Coastguard Worker         // Also modify the subgroup config to match the context
1417*4d7e907cSAndroid Build Coastguard Worker         modifySubgroupConfiguration(sub_group_config, context_bitmask);
1418*4d7e907cSAndroid Build Coastguard Worker       }
1419*4d7e907cSAndroid Build Coastguard Worker 
1420*4d7e907cSAndroid Build Coastguard Worker       if (is_matched) {
1421*4d7e907cSAndroid Build Coastguard Worker         is_setting_matched = true;
1422*4d7e907cSAndroid Build Coastguard Worker         for (auto& sub_group_config : setting.subgroupsConfigurations)
1423*4d7e907cSAndroid Build Coastguard Worker           return_setting.subgroupsConfigurations.push_back(sub_group_config);
1424*4d7e907cSAndroid Build Coastguard Worker         break;
1425*4d7e907cSAndroid Build Coastguard Worker       }
1426*4d7e907cSAndroid Build Coastguard Worker     }
1427*4d7e907cSAndroid Build Coastguard Worker 
1428*4d7e907cSAndroid Build Coastguard Worker     if (!is_setting_matched) {
1429*4d7e907cSAndroid Build Coastguard Worker       LOG(WARNING) << __func__
1430*4d7e907cSAndroid Build Coastguard Worker                    << ": Cannot find a setting that match requirement "
1431*4d7e907cSAndroid Build Coastguard Worker                    << sub_req.toString();
1432*4d7e907cSAndroid Build Coastguard Worker       return ndk::ScopedAStatus::ok();
1433*4d7e907cSAndroid Build Coastguard Worker     }
1434*4d7e907cSAndroid Build Coastguard Worker   }
1435*4d7e907cSAndroid Build Coastguard Worker 
1436*4d7e907cSAndroid Build Coastguard Worker   // Populate all numBis
1437*4d7e907cSAndroid Build Coastguard Worker   for (auto& sub_group_config : return_setting.subgroupsConfigurations) {
1438*4d7e907cSAndroid Build Coastguard Worker     for (auto& sub_bis_config : sub_group_config.bisConfigurations) {
1439*4d7e907cSAndroid Build Coastguard Worker       return_setting.numBis += sub_bis_config.numBis;
1440*4d7e907cSAndroid Build Coastguard Worker     }
1441*4d7e907cSAndroid Build Coastguard Worker   }
1442*4d7e907cSAndroid Build Coastguard Worker   return_setting.phy = std::vector<Phy>(return_setting.numBis, Phy::TWO_M);
1443*4d7e907cSAndroid Build Coastguard Worker   // Populate data path config
1444*4d7e907cSAndroid Build Coastguard Worker   return_setting.dataPathConfiguration = path;
1445*4d7e907cSAndroid Build Coastguard Worker   // TODO: Workaround for STEREO configs maxSduOctets being doubled
1446*4d7e907cSAndroid Build Coastguard Worker   if (context_bitmask & (AudioContext::LIVE_AUDIO | AudioContext::GAME |
1447*4d7e907cSAndroid Build Coastguard Worker                          AudioContext::SOUND_EFFECTS |
1448*4d7e907cSAndroid Build Coastguard Worker                          AudioContext::UNSPECIFIED | AudioContext::MEDIA)) {
1449*4d7e907cSAndroid Build Coastguard Worker     return_setting.maxSduOctets /= 2;
1450*4d7e907cSAndroid Build Coastguard Worker   }
1451*4d7e907cSAndroid Build Coastguard Worker   LOG(INFO) << __func__
1452*4d7e907cSAndroid Build Coastguard Worker             << ": Combined setting that match: " << return_setting.toString();
1453*4d7e907cSAndroid Build Coastguard Worker   *_aidl_return = return_setting;
1454*4d7e907cSAndroid Build Coastguard Worker   return ndk::ScopedAStatus::ok();
1455*4d7e907cSAndroid Build Coastguard Worker };
1456*4d7e907cSAndroid Build Coastguard Worker 
1457*4d7e907cSAndroid Build Coastguard Worker }  // namespace audio
1458*4d7e907cSAndroid Build Coastguard Worker }  // namespace bluetooth
1459*4d7e907cSAndroid Build Coastguard Worker }  // namespace hardware
1460*4d7e907cSAndroid Build Coastguard Worker }  // namespace android
1461*4d7e907cSAndroid Build Coastguard Worker }  // namespace aidl
1462