/* * Copyright 2019 HIMSA II K/S - www.himsa.com. Represented by EHIMA - * www.ehima.com * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include "mediatek/bta/include/mtk_bta_le_audio_api.h" #include "btif_common.h" #include "btif_storage.h" #include "hardware/bt_le_audio.h" #include "stack/include/btu.h" #include "osi/include/properties.h" #include using base::Bind; using base::Unretained; using bluetooth::le_audio::ConnectionState; using bluetooth::le_audio::GroupLockStatus; using bluetooth::le_audio::GroupNodeStatus; using bluetooth::le_audio::GroupStatus; using bluetooth::le_audio::LeAudioClientCallbacks; using bluetooth::le_audio::LeAudioClientInterface; static char prop_leaudio[PROPERTY_VALUE_MAX]; namespace { class LeAudioClientInterfaceImpl; std::unique_ptr lEAudioInstance; class LeAudioClientInterfaceImpl : public LeAudioClientInterface, public LeAudioClientCallbacks { ~LeAudioClientInterfaceImpl() = default; void OnConnectionState(ConnectionState state, const RawAddress& address) override { DVLOG(2) << __func__ << " address: " << address; do_in_jni_thread(FROM_HERE, Bind(&LeAudioClientCallbacks::OnConnectionState, Unretained(callbacks), state, address)); } void OnGroupStatus(uint8_t group_id, GroupStatus group_status, uint8_t group_flags) override { do_in_jni_thread(FROM_HERE, Bind(&LeAudioClientCallbacks::OnGroupStatus, Unretained(callbacks), group_id, group_status, group_flags)); } void OnGroupNodeStatus(const RawAddress& addr, uint8_t group_id, GroupNodeStatus node_status) override { do_in_jni_thread(FROM_HERE, Bind(&LeAudioClientCallbacks::OnGroupNodeStatus, Unretained(callbacks), addr, group_id, node_status)); } void OnSetMemberAvailable(const RawAddress& address, uint8_t group_id) override { DVLOG(2) << __func__ << " address: " << address << ", group_id: " << group_id; do_in_jni_thread(FROM_HERE, Bind(&LeAudioClientCallbacks::OnSetMemberAvailable, Unretained(callbacks), address, group_id)); } void OnGroupLockChanged(uint8_t group_id, bool locked, GroupLockStatus status) override { DVLOG(2) << __func__ << " group id: " << group_id << ", locked: " << int(locked) << ", status: " << int(status); do_in_jni_thread(FROM_HERE, Bind(&LeAudioClientCallbacks::OnGroupLockChanged, Unretained(callbacks), group_id, locked, status)); } void OnAudioConf(const RawAddress& addr, uint8_t direction, uint8_t group_id, uint32_t snk_audio_location, uint32_t src_audio_location) override { do_in_jni_thread( FROM_HERE, Bind(&LeAudioClientCallbacks::OnAudioConf, Unretained(callbacks), addr, direction, group_id, snk_audio_location, src_audio_location)); } void Initialize(LeAudioClientCallbacks* callbacks) override { this->callbacks = callbacks; do_in_main_thread( FROM_HERE, Bind(&LeAudioClient::Initialize, this, jni_thread_wrapper(FROM_HERE, Bind(&btif_storage_load_bonded_leaudio)))); } void Cleanup(void) override { do_in_main_thread(FROM_HERE, Bind(&LeAudioClient::Cleanup)); } void Connect(const RawAddress& address) override { DVLOG(2) << __func__ << " address: " << address; do_in_main_thread(FROM_HERE, Bind(&LeAudioClient::Connect, Unretained(LeAudioClient::Get()), address)); } void Disconnect(const RawAddress& address) override { DVLOG(2) << __func__ << " address: " << address; do_in_main_thread(FROM_HERE, Bind(&LeAudioClient::Disconnect, Unretained(LeAudioClient::Get()), address)); do_in_jni_thread(FROM_HERE, Bind(&btif_storage_remove_leaudio_white_list, address)); } void Forget(const RawAddress& address) override {} void GroupAddNode(const uint8_t group_id, const RawAddress& addr) override { do_in_main_thread(FROM_HERE, Bind(&LeAudioClient::GroupAddNode, Unretained(LeAudioClient::Get()), group_id, addr)); } void GroupRemoveNode(const uint8_t group_id, const RawAddress& addr) override { do_in_main_thread(FROM_HERE, Bind(&LeAudioClient::GroupRemoveNode, Unretained(LeAudioClient::Get()), group_id, addr)); } void GroupStream(const uint8_t group_id) override { do_in_main_thread(FROM_HERE, Bind(&LeAudioClient::GroupStream, Unretained(LeAudioClient::Get()), group_id)); } void GroupSuspend(const uint8_t group_id) override { do_in_main_thread(FROM_HERE, Bind(&LeAudioClient::GroupSuspend, Unretained(LeAudioClient::Get()), group_id)); } void GroupStart(const uint8_t group_id) override { do_in_main_thread(FROM_HERE, Bind(&LeAudioClient::GroupStart, Unretained(LeAudioClient::Get()), group_id)); } void GroupStop(const uint8_t group_id) override { do_in_main_thread(FROM_HERE, Bind(&LeAudioClient::GroupStop, Unretained(LeAudioClient::Get()), group_id)); } void GroupLockSet(const uint8_t group_id, bool lock) override { do_in_main_thread(FROM_HERE, Bind(&LeAudioClient::GroupLockSet, Unretained(LeAudioClient::Get()), group_id, lock)); } void GroupDestroy(const uint8_t group_id) override { do_in_main_thread(FROM_HERE, Bind(&LeAudioClient::GroupDestroy, Unretained(LeAudioClient::Get()), group_id)); } private: LeAudioClientCallbacks* callbacks; }; } /* namespace */ LeAudioClientInterface* LeAudioInstance() { if (!lEAudioInstance) { lEAudioInstance.reset(new LeAudioClientInterfaceImpl()); } return lEAudioInstance.get(); } static bt_status_t init(LeAudioClientCallbacks* callbacks) { osi_property_get(PROPERTY_LEAUDIO, prop_leaudio, ""); LOG_INFO("%s: prop_leaudio = %s", __func__, prop_leaudio); if (strcmp(prop_leaudio, "ums") == 0 || strcmp(prop_leaudio, "ums-cg") == 0) { LeAudioInstance()->Initialize(callbacks); return BT_STATUS_SUCCESS; } else { LOG_INFO("%s: prop_leaudio doesn't support", __func__); return BT_STATUS_FAIL; } } static void cleanup(void) { if (strcmp(prop_leaudio, "ums") == 0 || strcmp(prop_leaudio, "ums-cg") == 0) LeAudioInstance()->Cleanup(); else LOG_INFO("%s: prop_leaudio doesn't support", __func__); } static bt_status_t connect(const RawAddress* bd_addr) { if (strcmp(prop_leaudio, "ums") == 0 || strcmp(prop_leaudio, "ums-cg") == 0) { LeAudioInstance()->Connect(*bd_addr); return BT_STATUS_SUCCESS; } else { LOG_INFO("%s: prop_leaudio doesn't support", __func__); return BT_STATUS_FAIL; } } static bt_status_t disconnect(const RawAddress* bd_addr) { if (strcmp(prop_leaudio, "ums") == 0 || strcmp(prop_leaudio, "ums-cg") == 0) { LeAudioInstance()->Disconnect(*bd_addr); return BT_STATUS_SUCCESS; } else { LOG_INFO("%s: prop_leaudio doesn't support", __func__); return BT_STATUS_FAIL; } } static bt_status_t forget(const RawAddress* bd_addr) { if (strcmp(prop_leaudio, "ums") == 0 || strcmp(prop_leaudio, "ums-cg") == 0) { LeAudioInstance()->Forget(*bd_addr); return BT_STATUS_SUCCESS; } else { LOG_INFO("%s: prop_leaudio doesn't support", __func__); return BT_STATUS_FAIL; } } static bt_status_t group_add_node(const uint8_t group_id, const RawAddress* bd_addr) { if (strcmp(prop_leaudio, "ums") == 0 || strcmp(prop_leaudio, "ums-cg") == 0) { LeAudioInstance()->GroupAddNode(group_id, *bd_addr); return BT_STATUS_SUCCESS; } else { LOG_INFO("%s: prop_leaudio doesn't support", __func__); return BT_STATUS_FAIL; } } static bt_status_t group_remove_node(const uint8_t group_id, const RawAddress* bd_addr) { if (strcmp(prop_leaudio, "ums") == 0 || strcmp(prop_leaudio, "ums-cg") == 0) { LeAudioInstance()->GroupRemoveNode(group_id, *bd_addr); return BT_STATUS_SUCCESS; } else { LOG_INFO("%s: prop_leaudio doesn't support", __func__); return BT_STATUS_FAIL; } } static bt_status_t group_stream(const uint8_t group_id) { if (strcmp(prop_leaudio, "ums") == 0 || strcmp(prop_leaudio, "ums-cg") == 0) { LeAudioInstance()->GroupStream(group_id); return BT_STATUS_SUCCESS; } else { LOG_INFO("%s: prop_leaudio doesn't support", __func__); return BT_STATUS_FAIL; } } static bt_status_t group_suspend(const uint8_t group_id) { if (strcmp(prop_leaudio, "ums") == 0 || strcmp(prop_leaudio, "ums-cg") == 0) { LeAudioInstance()->GroupSuspend(group_id); return BT_STATUS_SUCCESS; } else { LOG_INFO("%s: prop_leaudio doesn't support", __func__); return BT_STATUS_FAIL; } } static bt_status_t group_start(const uint8_t group_id) { if (strcmp(prop_leaudio, "ums") == 0 || strcmp(prop_leaudio, "ums-cg") == 0) { LeAudioInstance()->GroupStart(group_id); return BT_STATUS_SUCCESS; } else { LOG_INFO("%s: prop_leaudio doesn't support", __func__); return BT_STATUS_FAIL; } } static bt_status_t group_stop(const uint8_t group_id) { if (strcmp(prop_leaudio, "ums") == 0 || strcmp(prop_leaudio, "ums-cg") == 0) { LeAudioInstance()->GroupStop(group_id); return BT_STATUS_SUCCESS; } else { LOG_INFO("%s: prop_leaudio doesn't support", __func__); return BT_STATUS_FAIL; } } static bt_status_t group_lock_set(const uint8_t group_id, bool lock) { if (strcmp(prop_leaudio, "ums") == 0 || strcmp(prop_leaudio, "ums-cg") == 0) { LeAudioInstance()->GroupLockSet(group_id, lock); return BT_STATUS_SUCCESS; } else { LOG_INFO("%s: prop_leaudio doesn't support", __func__); return BT_STATUS_FAIL; } } static bt_status_t group_destroy(const uint8_t group_id) { if (strcmp(prop_leaudio, "ums") == 0 || strcmp(prop_leaudio, "ums-cg") == 0) { LeAudioInstance()->GroupDestroy(group_id); return BT_STATUS_SUCCESS; } else { LOG_INFO("%s: prop_leaudio doesn't support", __func__); return BT_STATUS_FAIL; } } EXPORT_SYMBOL bleaudio_interface_t bleaudioInterface = { sizeof(bleaudioInterface), init, cleanup, connect, disconnect, forget, group_add_node, group_remove_node, group_stream, group_suspend, group_start, group_stop, group_lock_set, group_destroy, };