• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2019 HIMSA II K/S - www.himsa.com. Represented by EHIMA -
3  * www.ehima.com
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 #include <base/logging.h>
19 #include <hardware/bluetooth.h>
20 #include <hardware/bt_le_audio.h>
21 
22 #include <vector>
23 
24 #include "bta_le_audio_api.h"
25 #include "btif_common.h"
26 #include "btif_profile_storage.h"
27 #include "stack/include/btu.h"
28 
29 using base::Bind;
30 using base::Unretained;
31 using bluetooth::le_audio::btle_audio_codec_config_t;
32 using bluetooth::le_audio::ConnectionState;
33 using bluetooth::le_audio::GroupNodeStatus;
34 using bluetooth::le_audio::GroupStatus;
35 using bluetooth::le_audio::LeAudioClientCallbacks;
36 using bluetooth::le_audio::LeAudioClientInterface;
37 
38 namespace {
39 class LeAudioClientInterfaceImpl;
40 std::unique_ptr<LeAudioClientInterface> leAudioInstance;
41 std::atomic_bool initialized = false;
42 
43 class LeAudioClientInterfaceImpl : public LeAudioClientInterface,
44                                    public LeAudioClientCallbacks {
45   ~LeAudioClientInterfaceImpl() = default;
46 
OnInitialized(void)47   void OnInitialized(void) {
48     do_in_jni_thread(FROM_HERE, Bind(&LeAudioClientCallbacks::OnInitialized,
49                                      Unretained(callbacks)));
50   }
51 
OnConnectionState(ConnectionState state,const RawAddress & address)52   void OnConnectionState(ConnectionState state,
53                          const RawAddress& address) override {
54     do_in_jni_thread(FROM_HERE, Bind(&LeAudioClientCallbacks::OnConnectionState,
55                                      Unretained(callbacks), state, address));
56   }
57 
OnGroupStatus(int group_id,GroupStatus group_status)58   void OnGroupStatus(int group_id, GroupStatus group_status) override {
59     do_in_jni_thread(FROM_HERE,
60                      Bind(&LeAudioClientCallbacks::OnGroupStatus,
61                           Unretained(callbacks), group_id, group_status));
62   }
63 
OnGroupNodeStatus(const RawAddress & addr,int group_id,GroupNodeStatus node_status)64   void OnGroupNodeStatus(const RawAddress& addr, int group_id,
65                          GroupNodeStatus node_status) override {
66     do_in_jni_thread(FROM_HERE,
67                      Bind(&LeAudioClientCallbacks::OnGroupNodeStatus,
68                           Unretained(callbacks), addr, group_id, node_status));
69   }
70 
OnAudioConf(uint8_t direction,int group_id,uint32_t snk_audio_location,uint32_t src_audio_location,uint16_t avail_cont)71   void OnAudioConf(uint8_t direction, int group_id, uint32_t snk_audio_location,
72                    uint32_t src_audio_location, uint16_t avail_cont) override {
73     do_in_jni_thread(FROM_HERE,
74                      Bind(&LeAudioClientCallbacks::OnAudioConf,
75                           Unretained(callbacks), direction, group_id,
76                           snk_audio_location, src_audio_location, avail_cont));
77   }
78 
OnSinkAudioLocationAvailable(const RawAddress & address,uint32_t snk_audio_location)79   void OnSinkAudioLocationAvailable(const RawAddress& address,
80                                     uint32_t snk_audio_location) override {
81     do_in_jni_thread(FROM_HERE,
82                      Bind(&LeAudioClientCallbacks::OnSinkAudioLocationAvailable,
83                           Unretained(callbacks), address, snk_audio_location));
84   }
85 
OnAudioLocalCodecCapabilities(std::vector<btle_audio_codec_config_t> local_input_capa_codec_conf,std::vector<btle_audio_codec_config_t> local_output_capa_codec_conf)86   void OnAudioLocalCodecCapabilities(
87       std::vector<btle_audio_codec_config_t> local_input_capa_codec_conf,
88       std::vector<btle_audio_codec_config_t> local_output_capa_codec_conf)
89       override {
90     do_in_jni_thread(
91         FROM_HERE, Bind(&LeAudioClientCallbacks::OnAudioLocalCodecCapabilities,
92                         Unretained(callbacks), local_input_capa_codec_conf,
93                         local_output_capa_codec_conf));
94   }
95 
OnAudioGroupCodecConf(int group_id,btle_audio_codec_config_t input_codec_conf,btle_audio_codec_config_t output_codec_conf,std::vector<btle_audio_codec_config_t> input_selectable_codec_conf,std::vector<btle_audio_codec_config_t> output_selectable_codec_conf)96   void OnAudioGroupCodecConf(
97       int group_id, btle_audio_codec_config_t input_codec_conf,
98       btle_audio_codec_config_t output_codec_conf,
99       std::vector<btle_audio_codec_config_t> input_selectable_codec_conf,
100       std::vector<btle_audio_codec_config_t> output_selectable_codec_conf)
101       override {
102     do_in_jni_thread(FROM_HERE,
103                      Bind(&LeAudioClientCallbacks::OnAudioGroupCodecConf,
104                           Unretained(callbacks), group_id, input_codec_conf,
105                           output_codec_conf, input_selectable_codec_conf,
106                           output_selectable_codec_conf));
107   }
108 
Initialize(LeAudioClientCallbacks * callbacks,const std::vector<btle_audio_codec_config_t> & offloading_preference)109   void Initialize(LeAudioClientCallbacks* callbacks,
110                   const std::vector<btle_audio_codec_config_t>&
111                       offloading_preference) override {
112     this->callbacks = callbacks;
113 
114     for (auto codec : offloading_preference) {
115       LOG_INFO("supported codec: %s", codec.ToString().c_str());
116     }
117 
118     LeAudioClient::InitializeAudioSetConfigurationProvider();
119     do_in_main_thread(
120         FROM_HERE, Bind(&LeAudioClient::Initialize, this,
121                         jni_thread_wrapper(
122                             FROM_HERE, Bind(&btif_storage_load_bonded_leaudio)),
123                         base::Bind([]() -> bool {
124                           return LeAudioHalVerifier::SupportsLeAudio();
125                         }),
126                         offloading_preference));
127 
128     /* It might be not yet initialized, but setting this flag here is safe,
129      * because other calls will check this and the native instance
130      */
131     initialized = true;
132   }
133 
Cleanup(void)134   void Cleanup(void) override {
135     DVLOG(2) << __func__;
136     if (!initialized || !LeAudioClient::IsLeAudioClientRunning()) {
137       DVLOG(2) << __func__
138                << " call ignored, due to already started cleanup procedure or "
139                   "service being not read";
140       return;
141     }
142 
143     initialized = false;
144 
145     do_in_main_thread(
146         FROM_HERE,
147         Bind(&LeAudioClient::Cleanup,
148              jni_thread_wrapper(
149                  FROM_HERE,
150                  Bind(&LeAudioClient::CleanupAudioSetConfigurationProvider))));
151   }
152 
RemoveDevice(const RawAddress & address)153   void RemoveDevice(const RawAddress& address) override {
154     DVLOG(2) << __func__ << " address: " << ADDRESS_TO_LOGGABLE_STR(address);
155 
156     if (!initialized || !LeAudioClient::IsLeAudioClientRunning()) {
157       DVLOG(2) << __func__
158                << " call ignored, due to already started cleanup procedure or "
159                   "service being not read";
160 
161       do_in_jni_thread(FROM_HERE, Bind(&btif_storage_remove_leaudio, address));
162       return;
163     }
164 
165     do_in_main_thread(FROM_HERE,
166                       Bind(&LeAudioClient::RemoveDevice,
167                            Unretained(LeAudioClient::Get()), address));
168 
169     do_in_jni_thread(FROM_HERE, Bind(&btif_storage_remove_leaudio, address));
170   }
171 
Connect(const RawAddress & address)172   void Connect(const RawAddress& address) override {
173     DVLOG(2) << __func__ << " address: " << ADDRESS_TO_LOGGABLE_STR(address);
174 
175     if (!initialized || !LeAudioClient::IsLeAudioClientRunning()) {
176       DVLOG(2) << __func__
177                << " call ignored, due to already started cleanup procedure or "
178                   "service being not read";
179       return;
180     }
181 
182     do_in_main_thread(FROM_HERE,
183                       Bind(&LeAudioClient::Connect,
184                            Unretained(LeAudioClient::Get()), address));
185   }
186 
Disconnect(const RawAddress & address)187   void Disconnect(const RawAddress& address) override {
188     DVLOG(2) << __func__ << " address: " << ADDRESS_TO_LOGGABLE_STR(address);
189 
190     if (!initialized || !LeAudioClient::IsLeAudioClientRunning()) {
191       DVLOG(2) << __func__
192                << " call ignored, due to already started cleanup procedure or "
193                   "service being not read";
194       return;
195     }
196 
197     do_in_main_thread(FROM_HERE,
198                       Bind(&LeAudioClient::Disconnect,
199                            Unretained(LeAudioClient::Get()), address));
200   }
201 
SetEnableState(const RawAddress & address,bool enabled)202   void SetEnableState(const RawAddress& address, bool enabled) override {
203     DVLOG(2) << __func__ << " address: " << address << ", enabled: " << enabled;
204 
205     if (!initialized || !LeAudioClient::IsLeAudioClientRunning()) {
206       DVLOG(2) << __func__
207                << " call ignored, due to already started cleanup procedure or "
208                   "service being not read";
209       return;
210     }
211 
212     do_in_main_thread(FROM_HERE,
213                       Bind(&LeAudioClient::SetEnableState,
214                            Unretained(LeAudioClient::Get()), address, enabled));
215   }
216 
GroupAddNode(const int group_id,const RawAddress & address)217   void GroupAddNode(const int group_id, const RawAddress& address) override {
218     DVLOG(2) << __func__ << " group_id: " << group_id
219              << " address: " << ADDRESS_TO_LOGGABLE_STR(address);
220 
221     if (!initialized || !LeAudioClient::IsLeAudioClientRunning()) {
222       DVLOG(2) << __func__
223                << " call ignored, due to already started cleanup procedure or "
224                   "service being not read";
225       return;
226     }
227 
228     do_in_main_thread(
229         FROM_HERE, Bind(&LeAudioClient::GroupAddNode,
230                         Unretained(LeAudioClient::Get()), group_id, address));
231   }
232 
GroupRemoveNode(const int group_id,const RawAddress & address)233   void GroupRemoveNode(const int group_id, const RawAddress& address) override {
234     DVLOG(2) << __func__ << " group_id: " << group_id
235              << " address: " << ADDRESS_TO_LOGGABLE_STR(address);
236     if (!initialized || !LeAudioClient::IsLeAudioClientRunning()) {
237       DVLOG(2) << __func__
238                << " call ignored, due to already started cleanup procedure or "
239                   "service being not read";
240       return;
241     }
242 
243     do_in_main_thread(
244         FROM_HERE, Bind(&LeAudioClient::GroupRemoveNode,
245                         Unretained(LeAudioClient::Get()), group_id, address));
246   }
247 
GroupSetActive(const int group_id)248   void GroupSetActive(const int group_id) override {
249     DVLOG(2) << __func__ << " group_id: " << group_id;
250     if (!initialized || !LeAudioClient::IsLeAudioClientRunning()) {
251       DVLOG(2) << __func__
252                << " call ignored, due to already started cleanup procedure or "
253                   "service being not read";
254       return;
255     }
256 
257     do_in_main_thread(FROM_HERE,
258                       Bind(&LeAudioClient::GroupSetActive,
259                            Unretained(LeAudioClient::Get()), group_id));
260   }
261 
SetCodecConfigPreference(int group_id,btle_audio_codec_config_t input_codec_config,btle_audio_codec_config_t output_codec_config)262   void SetCodecConfigPreference(int group_id,
263                                 btle_audio_codec_config_t input_codec_config,
264                                 btle_audio_codec_config_t output_codec_config) {
265     DVLOG(2) << __func__ << " group_id: " << group_id;
266     if (!initialized || !LeAudioClient::IsLeAudioClientRunning()) {
267       DVLOG(2) << __func__
268                << " call ignored, due to already started cleanup procedure or "
269                   "service being not read";
270       return;
271     }
272     do_in_main_thread(FROM_HERE,
273                       Bind(&LeAudioClient::SetCodecConfigPreference,
274                            Unretained(LeAudioClient::Get()), group_id,
275                            input_codec_config, output_codec_config));
276   }
277 
SetCcidInformation(int ccid,int context_type)278   void SetCcidInformation(int ccid, int context_type) {
279     DVLOG(2) << __func__ << " ccid: " << ccid << " context_type"
280              << context_type;
281     if (!initialized || !LeAudioClient::IsLeAudioClientRunning()) {
282       DVLOG(2) << __func__
283                << " call ignored, due to already started cleanup procedure or "
284                   "service being not read";
285       return;
286     }
287 
288     do_in_main_thread(
289         FROM_HERE, Bind(&LeAudioClient::SetCcidInformation,
290                         Unretained(LeAudioClient::Get()), ccid, context_type));
291   }
292 
SetInCall(bool in_call)293   void SetInCall(bool in_call) {
294     DVLOG(2) << __func__ << " in_call: " << in_call;
295     if (!initialized || !LeAudioClient::IsLeAudioClientRunning()) {
296       DVLOG(2) << __func__
297                << " call ignored, due to already started cleanup procedure or "
298                   "service being not read";
299       return;
300     }
301 
302     do_in_main_thread(FROM_HERE,
303                       Bind(&LeAudioClient::SetInCall,
304                            Unretained(LeAudioClient::Get()), in_call));
305   }
306 
SendAudioProfilePreferences(int group_id,bool is_output_preference_le_audio,bool is_duplex_preference_le_audio)307   void SendAudioProfilePreferences(int group_id,
308                                    bool is_output_preference_le_audio,
309                                    bool is_duplex_preference_le_audio) {
310     DVLOG(2) << __func__ << " group_id: " << group_id
311              << ", is_output_preference_le_audio: "
312              << is_output_preference_le_audio
313              << ", is_duplex_preference_le_audio: "
314              << is_duplex_preference_le_audio;
315     if (!initialized || !LeAudioClient::IsLeAudioClientRunning()) {
316       DVLOG(2) << __func__
317                << " call ignored, due to already started cleanup procedure or "
318                   "service being not read";
319       return;
320     }
321 
322     do_in_main_thread(
323         FROM_HERE,
324         Bind(&LeAudioClient::SendAudioProfilePreferences,
325              Unretained(LeAudioClient::Get()), group_id,
326              is_output_preference_le_audio, is_duplex_preference_le_audio));
327   }
328 
329  private:
330   LeAudioClientCallbacks* callbacks;
331 };
332 
333 } /* namespace */
334 
btif_le_audio_get_interface()335 LeAudioClientInterface* btif_le_audio_get_interface() {
336   if (!leAudioInstance) {
337     leAudioInstance.reset(new LeAudioClientInterfaceImpl());
338   }
339 
340   return leAudioInstance.get();
341 }
342