335 lines
11 KiB
C++
335 lines
11 KiB
C++
|
|
/*
|
||
|
|
* 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 <hardware/bluetooth.h>
|
||
|
|
#include <vector>
|
||
|
|
|
||
|
|
#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 <hardware/bt_le_audio.h>
|
||
|
|
|
||
|
|
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<LeAudioClientInterface> 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,
|
||
|
|
};
|