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