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