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 <bluetooth/log.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/main_thread.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::GroupStreamStatus;
36 using bluetooth::le_audio::LeAudioClientCallbacks;
37 using bluetooth::le_audio::LeAudioClientInterface;
38 using bluetooth::le_audio::UnicastMonitorModeStatus;
39 using namespace bluetooth;
40 
41 namespace {
42 class LeAudioClientInterfaceImpl;
43 std::unique_ptr<LeAudioClientInterface> leAudioInstance;
44 std::atomic_bool initialized = false;
45 
46 class LeAudioClientInterfaceImpl : public LeAudioClientInterface,
47                                    public LeAudioClientCallbacks {
48   ~LeAudioClientInterfaceImpl() = default;
49 
OnInitialized(void)50   void OnInitialized(void) {
51     do_in_jni_thread(
52         Bind(&LeAudioClientCallbacks::OnInitialized, Unretained(callbacks)));
53   }
54 
OnConnectionState(ConnectionState state,const RawAddress & address)55   void OnConnectionState(ConnectionState state,
56                          const RawAddress& address) override {
57     do_in_jni_thread(Bind(&LeAudioClientCallbacks::OnConnectionState,
58                           Unretained(callbacks), state, address));
59   }
60 
OnGroupStatus(int group_id,GroupStatus group_status)61   void OnGroupStatus(int group_id, GroupStatus group_status) override {
62     do_in_jni_thread(Bind(&LeAudioClientCallbacks::OnGroupStatus,
63                           Unretained(callbacks), group_id, group_status));
64   }
65 
OnGroupNodeStatus(const RawAddress & addr,int group_id,GroupNodeStatus node_status)66   void OnGroupNodeStatus(const RawAddress& addr, int group_id,
67                          GroupNodeStatus node_status) override {
68     do_in_jni_thread(Bind(&LeAudioClientCallbacks::OnGroupNodeStatus,
69                           Unretained(callbacks), addr, group_id, node_status));
70   }
71 
OnAudioConf(uint8_t direction,int group_id,uint32_t snk_audio_location,uint32_t src_audio_location,uint16_t avail_cont)72   void OnAudioConf(uint8_t direction, int group_id, uint32_t snk_audio_location,
73                    uint32_t src_audio_location, uint16_t avail_cont) override {
74     do_in_jni_thread(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(Bind(&LeAudioClientCallbacks::OnSinkAudioLocationAvailable,
82                           Unretained(callbacks), address, snk_audio_location));
83   }
84 
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)85   void OnAudioLocalCodecCapabilities(
86       std::vector<btle_audio_codec_config_t> local_input_capa_codec_conf,
87       std::vector<btle_audio_codec_config_t> local_output_capa_codec_conf)
88       override {
89     do_in_jni_thread(
90         Bind(&LeAudioClientCallbacks::OnAudioLocalCodecCapabilities,
91              Unretained(callbacks), local_input_capa_codec_conf,
92              local_output_capa_codec_conf));
93   }
94 
OnAudioGroupCurrentCodecConf(int group_id,btle_audio_codec_config_t input_codec_conf,btle_audio_codec_config_t output_codec_conf)95   void OnAudioGroupCurrentCodecConf(
96       int group_id, btle_audio_codec_config_t input_codec_conf,
97       btle_audio_codec_config_t output_codec_conf) override {
98     do_in_jni_thread(Bind(&LeAudioClientCallbacks::OnAudioGroupCurrentCodecConf,
99                           Unretained(callbacks), group_id, input_codec_conf,
100                           output_codec_conf));
101   }
102 
OnAudioGroupSelectableCodecConf(int group_id,std::vector<btle_audio_codec_config_t> input_selectable_codec_conf,std::vector<btle_audio_codec_config_t> output_selectable_codec_conf)103   void OnAudioGroupSelectableCodecConf(
104       int group_id,
105       std::vector<btle_audio_codec_config_t> input_selectable_codec_conf,
106       std::vector<btle_audio_codec_config_t> output_selectable_codec_conf)
107       override {
108     do_in_jni_thread(
109         Bind(&LeAudioClientCallbacks::OnAudioGroupSelectableCodecConf,
110              Unretained(callbacks), group_id, input_selectable_codec_conf,
111              output_selectable_codec_conf));
112   }
113 
OnHealthBasedRecommendationAction(const RawAddress & address,bluetooth::le_audio::LeAudioHealthBasedAction action)114   void OnHealthBasedRecommendationAction(
115       const RawAddress& address,
116       bluetooth::le_audio::LeAudioHealthBasedAction action) override {
117     do_in_jni_thread(
118         Bind(&LeAudioClientCallbacks::OnHealthBasedRecommendationAction,
119              Unretained(callbacks), address, action));
120   }
121 
OnHealthBasedGroupRecommendationAction(int group_id,bluetooth::le_audio::LeAudioHealthBasedAction action)122   void OnHealthBasedGroupRecommendationAction(
123       int group_id,
124       bluetooth::le_audio::LeAudioHealthBasedAction action) override {
125     do_in_jni_thread(
126         Bind(&LeAudioClientCallbacks::OnHealthBasedGroupRecommendationAction,
127              Unretained(callbacks), group_id, action));
128   }
129 
OnUnicastMonitorModeStatus(uint8_t direction,UnicastMonitorModeStatus status)130   void OnUnicastMonitorModeStatus(uint8_t direction,
131                                   UnicastMonitorModeStatus status) override {
132     do_in_jni_thread(Bind(&LeAudioClientCallbacks::OnUnicastMonitorModeStatus,
133                           Unretained(callbacks), direction, status));
134   }
135 
OnGroupStreamStatus(int group_id,GroupStreamStatus group_stream_status)136   void OnGroupStreamStatus(int group_id,
137                            GroupStreamStatus group_stream_status) override {
138     do_in_jni_thread(Bind(&LeAudioClientCallbacks::OnGroupStreamStatus,
139                           Unretained(callbacks), group_id,
140                           group_stream_status));
141   }
142 
Initialize(LeAudioClientCallbacks * callbacks,const std::vector<btle_audio_codec_config_t> & offloading_preference)143   void Initialize(LeAudioClientCallbacks* callbacks,
144                   const std::vector<btle_audio_codec_config_t>&
145                       offloading_preference) override {
146     this->callbacks = callbacks;
147 
148     for (auto codec : offloading_preference) {
149       log::info("supported codec: {}", codec.ToString());
150     }
151 
152     do_in_main_thread(
153         FROM_HERE,
154         Bind(&LeAudioClient::Initialize, this,
155              jni_thread_wrapper(Bind(&btif_storage_load_bonded_leaudio)),
156              base::Bind([]() -> bool {
157                return LeAudioHalVerifier::SupportsLeAudio();
158              }),
159              offloading_preference));
160 
161     /* It might be not yet initialized, but setting this flag here is safe,
162      * because other calls will check this and the native instance
163      */
164     initialized = true;
165   }
166 
Cleanup(void)167   void Cleanup(void) override {
168     if (!initialized || !LeAudioClient::IsLeAudioClientRunning()) {
169       log::verbose(
170           "call ignored, due to already started cleanup procedure or service "
171           "being not read");
172       return;
173     }
174 
175     initialized = false;
176 
177     do_in_main_thread(FROM_HERE, Bind(&LeAudioClient::Cleanup));
178   }
179 
RemoveDevice(const RawAddress & address)180   void RemoveDevice(const RawAddress& address) override {
181     if (!initialized || !LeAudioClient::IsLeAudioClientRunning()) {
182       log::verbose(
183           "call ignored, due to already started cleanup procedure or service "
184           "being not read");
185 
186       do_in_jni_thread(Bind(&btif_storage_remove_leaudio, address));
187       return;
188     }
189 
190     do_in_main_thread(FROM_HERE,
191                       Bind(&LeAudioClient::RemoveDevice,
192                            Unretained(LeAudioClient::Get()), address));
193 
194     do_in_jni_thread(Bind(&btif_storage_remove_leaudio, address));
195   }
196 
Connect(const RawAddress & address)197   void Connect(const RawAddress& address) override {
198     if (!initialized || !LeAudioClient::IsLeAudioClientRunning()) {
199       log::verbose(
200           "call ignored, due to already started cleanup procedure or service "
201           "being not read");
202       return;
203     }
204 
205     do_in_main_thread(FROM_HERE,
206                       Bind(&LeAudioClient::Connect,
207                            Unretained(LeAudioClient::Get()), address));
208   }
209 
Disconnect(const RawAddress & address)210   void Disconnect(const RawAddress& address) override {
211     if (!initialized || !LeAudioClient::IsLeAudioClientRunning()) {
212       log::verbose(
213           "call ignored, due to already started cleanup procedure or service "
214           "being not read");
215       return;
216     }
217 
218     do_in_main_thread(FROM_HERE,
219                       Bind(&LeAudioClient::Disconnect,
220                            Unretained(LeAudioClient::Get()), address));
221   }
222 
SetEnableState(const RawAddress & address,bool enabled)223   void SetEnableState(const RawAddress& address, bool enabled) override {
224     if (!initialized || !LeAudioClient::IsLeAudioClientRunning()) {
225       log::verbose(
226           "call ignored, due to already started cleanup procedure or service "
227           "being not read");
228       return;
229     }
230 
231     do_in_main_thread(FROM_HERE,
232                       Bind(&LeAudioClient::SetEnableState,
233                            Unretained(LeAudioClient::Get()), address, enabled));
234   }
235 
GroupAddNode(const int group_id,const RawAddress & address)236   void GroupAddNode(const int group_id, const RawAddress& address) override {
237     if (!initialized || !LeAudioClient::IsLeAudioClientRunning()) {
238       log::verbose(
239           "call ignored, due to already started cleanup procedure or service "
240           "being not read");
241       return;
242     }
243 
244     do_in_main_thread(
245         FROM_HERE, Bind(&LeAudioClient::GroupAddNode,
246                         Unretained(LeAudioClient::Get()), group_id, address));
247   }
248 
GroupRemoveNode(const int group_id,const RawAddress & address)249   void GroupRemoveNode(const int group_id, const RawAddress& address) override {
250     if (!initialized || !LeAudioClient::IsLeAudioClientRunning()) {
251       log::verbose(
252           "call ignored, due to already started cleanup procedure or service "
253           "being not read");
254       return;
255     }
256 
257     do_in_main_thread(
258         FROM_HERE, Bind(&LeAudioClient::GroupRemoveNode,
259                         Unretained(LeAudioClient::Get()), group_id, address));
260   }
261 
GroupSetActive(const int group_id)262   void GroupSetActive(const int group_id) override {
263     if (!initialized || !LeAudioClient::IsLeAudioClientRunning()) {
264       log::verbose(
265           "call ignored, due to already started cleanup procedure or service "
266           "being not read");
267       return;
268     }
269 
270     do_in_main_thread(FROM_HERE,
271                       Bind(&LeAudioClient::GroupSetActive,
272                            Unretained(LeAudioClient::Get()), group_id));
273   }
274 
SetCodecConfigPreference(int group_id,btle_audio_codec_config_t input_codec_config,btle_audio_codec_config_t output_codec_config)275   void SetCodecConfigPreference(int group_id,
276                                 btle_audio_codec_config_t input_codec_config,
277                                 btle_audio_codec_config_t output_codec_config) {
278     if (!initialized || !LeAudioClient::IsLeAudioClientRunning()) {
279       log::verbose(
280           "call ignored, due to already started cleanup procedure or service "
281           "being not read");
282       return;
283     }
284     do_in_main_thread(FROM_HERE,
285                       Bind(&LeAudioClient::SetCodecConfigPreference,
286                            Unretained(LeAudioClient::Get()), group_id,
287                            input_codec_config, output_codec_config));
288   }
289 
SetCcidInformation(int ccid,int context_type)290   void SetCcidInformation(int ccid, int context_type) {
291     if (!initialized || !LeAudioClient::IsLeAudioClientRunning()) {
292       log::verbose(
293           "call ignored, due to already started cleanup procedure or service "
294           "being not read");
295       return;
296     }
297 
298     do_in_main_thread(
299         FROM_HERE, Bind(&LeAudioClient::SetCcidInformation,
300                         Unretained(LeAudioClient::Get()), ccid, context_type));
301   }
302 
SetInCall(bool in_call)303   void SetInCall(bool in_call) {
304     if (!initialized || !LeAudioClient::IsLeAudioClientRunning()) {
305       log::verbose(
306           "call ignored, due to already started cleanup procedure or service "
307           "being not read");
308       return;
309     }
310 
311     do_in_main_thread(FROM_HERE,
312                       Bind(&LeAudioClient::SetInCall,
313                            Unretained(LeAudioClient::Get()), in_call));
314   }
315 
SetUnicastMonitorMode(uint8_t direction,bool enable)316   void SetUnicastMonitorMode(uint8_t direction, bool enable) {
317     log::verbose("enable: {}", enable);
318     if (!initialized || !LeAudioClient::IsLeAudioClientRunning()) {
319       log::verbose(
320           "Unicast monitoring mode set ignored, due to already"
321           " started cleanup procedure or service being not read");
322       return;
323     }
324 
325     do_in_main_thread(
326         FROM_HERE, Bind(&LeAudioClient::SetUnicastMonitorMode,
327                         Unretained(LeAudioClient::Get()), direction, enable));
328   }
329 
SendAudioProfilePreferences(int group_id,bool is_output_preference_le_audio,bool is_duplex_preference_le_audio)330   void SendAudioProfilePreferences(int group_id,
331                                    bool is_output_preference_le_audio,
332                                    bool is_duplex_preference_le_audio) {
333     if (!initialized || !LeAudioClient::IsLeAudioClientRunning()) {
334       log::verbose(
335           "call ignored, due to already started cleanup procedure or service "
336           "being not read");
337       return;
338     }
339 
340     do_in_main_thread(
341         FROM_HERE,
342         Bind(&LeAudioClient::SendAudioProfilePreferences,
343              Unretained(LeAudioClient::Get()), group_id,
344              is_output_preference_le_audio, is_duplex_preference_le_audio));
345   }
346 
SetGroupAllowedContextMask(int group_id,int sink_context_types,int source_context_types)347   void SetGroupAllowedContextMask(int group_id, int sink_context_types,
348                                   int source_context_types) {
349     if (!initialized || !LeAudioClient::IsLeAudioClientRunning()) {
350       log::verbose(
351           "call ignored, due to already started cleanup procedure or service "
352           "being not read");
353       return;
354     }
355 
356     log::info("group_id: {}, sink context types: {}, source context types: {}",
357               group_id, sink_context_types, source_context_types);
358 
359     do_in_main_thread(FROM_HERE,
360                       Bind(&LeAudioClient::SetGroupAllowedContextMask,
361                            Unretained(LeAudioClient::Get()), group_id,
362                            sink_context_types, source_context_types));
363   }
364 
365  private:
366   LeAudioClientCallbacks* callbacks;
367 };
368 
369 } /* namespace */
370 
btif_le_audio_get_interface()371 LeAudioClientInterface* btif_le_audio_get_interface() {
372   if (!leAudioInstance) {
373     leAudioInstance.reset(new LeAudioClientInterfaceImpl());
374   }
375 
376   return leAudioInstance.get();
377 }
378