mirror of
https://github.com/Evolution-X/hardware_interfaces
synced 2026-02-01 21:37:44 +00:00
Merge changes from topic "bt-audio-aidl-default-impl"
* changes: Add Bluetooth Audio default AIDL implementation Add Bluetooth Audio AIDL utils
This commit is contained in:
@@ -43,6 +43,10 @@ aidl_interface {
|
||||
vndk: {
|
||||
enabled: true,
|
||||
},
|
||||
apex_available: [
|
||||
"//apex_available:platform",
|
||||
"com.android.bluetooth",
|
||||
],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
71
bluetooth/audio/aidl/default/A2dpOffloadAudioProvider.cpp
Normal file
71
bluetooth/audio/aidl/default/A2dpOffloadAudioProvider.cpp
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define LOG_TAG "BTAudioProviderA2dpHW"
|
||||
|
||||
#include "A2dpOffloadAudioProvider.h"
|
||||
|
||||
#include <BluetoothAudioCodecs.h>
|
||||
#include <BluetoothAudioSessionReport.h>
|
||||
#include <android-base/logging.h>
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace bluetooth {
|
||||
namespace audio {
|
||||
|
||||
A2dpOffloadAudioProvider::A2dpOffloadAudioProvider() {
|
||||
session_type_ = SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH;
|
||||
}
|
||||
|
||||
bool A2dpOffloadAudioProvider::isValid(const SessionType& session_type) {
|
||||
return (session_type == session_type_);
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus A2dpOffloadAudioProvider::startSession(
|
||||
const std::shared_ptr<IBluetoothAudioPort>& host_if,
|
||||
const AudioConfiguration& audio_config, DataMQDesc* _aidl_return) {
|
||||
if (audio_config.getTag() != AudioConfiguration::a2dpConfig) {
|
||||
LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
|
||||
<< audio_config.toString();
|
||||
*_aidl_return = DataMQDesc();
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
|
||||
}
|
||||
if (!BluetoothAudioCodecs::IsOffloadCodecConfigurationValid(
|
||||
session_type_, audio_config.get<AudioConfiguration::a2dpConfig>())) {
|
||||
LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
|
||||
<< audio_config.toString();
|
||||
*_aidl_return = DataMQDesc();
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
|
||||
}
|
||||
return BluetoothAudioProvider::startSession(host_if, audio_config,
|
||||
_aidl_return);
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus A2dpOffloadAudioProvider::onSessionReady(
|
||||
DataMQDesc* _aidl_return) {
|
||||
*_aidl_return = DataMQDesc();
|
||||
BluetoothAudioSessionReport::OnSessionStarted(session_type_, stack_iface_,
|
||||
nullptr, *audio_config_);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
} // namespace audio
|
||||
} // namespace bluetooth
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
||||
45
bluetooth/audio/aidl/default/A2dpOffloadAudioProvider.h
Normal file
45
bluetooth/audio/aidl/default/A2dpOffloadAudioProvider.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BluetoothAudioProvider.h"
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace bluetooth {
|
||||
namespace audio {
|
||||
|
||||
class A2dpOffloadAudioProvider : public BluetoothAudioProvider {
|
||||
public:
|
||||
A2dpOffloadAudioProvider();
|
||||
|
||||
bool isValid(const SessionType& session_type) override;
|
||||
|
||||
ndk::ScopedAStatus startSession(
|
||||
const std::shared_ptr<IBluetoothAudioPort>& host_if,
|
||||
const AudioConfiguration& audio_config, DataMQDesc* _aidl_return);
|
||||
|
||||
private:
|
||||
ndk::ScopedAStatus onSessionReady(DataMQDesc* _aidl_return) override;
|
||||
};
|
||||
|
||||
} // namespace audio
|
||||
} // namespace bluetooth
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
||||
100
bluetooth/audio/aidl/default/A2dpSoftwareAudioProvider.cpp
Normal file
100
bluetooth/audio/aidl/default/A2dpSoftwareAudioProvider.cpp
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define LOG_TAG "BTAudioProviderA2dpSW"
|
||||
|
||||
#include "A2dpSoftwareAudioProvider.h"
|
||||
|
||||
#include <BluetoothAudioCodecs.h>
|
||||
#include <BluetoothAudioSessionReport.h>
|
||||
#include <android-base/logging.h>
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace bluetooth {
|
||||
namespace audio {
|
||||
|
||||
// Here the buffer size is based on SBC
|
||||
static constexpr uint32_t kPcmFrameSize = 4; // 16 bits per sample / stereo
|
||||
// SBC is 128, and here we choose the LCM of 16, 24, and 32
|
||||
static constexpr uint32_t kPcmFrameCount = 96;
|
||||
static constexpr uint32_t kRtpFrameSize = kPcmFrameSize * kPcmFrameCount;
|
||||
// The max counts by 1 tick (20ms) for SBC is about 7. Since using 96 for the
|
||||
// PCM counts, here we just choose a greater number
|
||||
static constexpr uint32_t kRtpFrameCount = 10;
|
||||
static constexpr uint32_t kBufferSize = kRtpFrameSize * kRtpFrameCount;
|
||||
static constexpr uint32_t kBufferCount = 2; // double buffer
|
||||
static constexpr uint32_t kDataMqSize = kBufferSize * kBufferCount;
|
||||
|
||||
A2dpSoftwareAudioProvider::A2dpSoftwareAudioProvider()
|
||||
: BluetoothAudioProvider(), data_mq_(nullptr) {
|
||||
LOG(INFO) << __func__ << " - size of audio buffer " << kDataMqSize
|
||||
<< " byte(s)";
|
||||
std::unique_ptr<DataMQ> data_mq(
|
||||
new DataMQ(kDataMqSize, /* EventFlag */ true));
|
||||
if (data_mq && data_mq->isValid()) {
|
||||
data_mq_ = std::move(data_mq);
|
||||
session_type_ = SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH;
|
||||
} else {
|
||||
ALOGE_IF(!data_mq, "failed to allocate data MQ");
|
||||
ALOGE_IF(data_mq && !data_mq->isValid(), "data MQ is invalid");
|
||||
}
|
||||
}
|
||||
|
||||
bool A2dpSoftwareAudioProvider::isValid(const SessionType& sessionType) {
|
||||
return (sessionType == session_type_ && data_mq_ && data_mq_->isValid());
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus A2dpSoftwareAudioProvider::startSession(
|
||||
const std::shared_ptr<IBluetoothAudioPort>& host_if,
|
||||
const AudioConfiguration& audio_config, DataMQDesc* _aidl_return) {
|
||||
if (audio_config.getTag() != AudioConfiguration::pcmConfig) {
|
||||
LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
|
||||
<< audio_config.toString();
|
||||
*_aidl_return = DataMQDesc();
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
|
||||
}
|
||||
const PcmConfiguration& pcm_config =
|
||||
audio_config.get<AudioConfiguration::pcmConfig>();
|
||||
if (!BluetoothAudioCodecs::IsSoftwarePcmConfigurationValid(pcm_config)) {
|
||||
LOG(WARNING) << __func__ << " - Unsupported PCM Configuration="
|
||||
<< pcm_config.toString();
|
||||
*_aidl_return = DataMQDesc();
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
|
||||
}
|
||||
|
||||
return BluetoothAudioProvider::startSession(host_if, audio_config,
|
||||
_aidl_return);
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus A2dpSoftwareAudioProvider::onSessionReady(
|
||||
DataMQDesc* _aidl_return) {
|
||||
if (data_mq_ == nullptr || !data_mq_->isValid()) {
|
||||
*_aidl_return = DataMQDesc();
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
|
||||
}
|
||||
*_aidl_return = data_mq_->dupeDesc();
|
||||
BluetoothAudioSessionReport::OnSessionStarted(session_type_, stack_iface_,
|
||||
_aidl_return, *audio_config_);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
} // namespace audio
|
||||
} // namespace bluetooth
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
||||
48
bluetooth/audio/aidl/default/A2dpSoftwareAudioProvider.h
Normal file
48
bluetooth/audio/aidl/default/A2dpSoftwareAudioProvider.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BluetoothAudioProvider.h"
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace bluetooth {
|
||||
namespace audio {
|
||||
|
||||
class A2dpSoftwareAudioProvider : public BluetoothAudioProvider {
|
||||
public:
|
||||
A2dpSoftwareAudioProvider();
|
||||
|
||||
bool isValid(const SessionType& sessionType) override;
|
||||
|
||||
ndk::ScopedAStatus startSession(
|
||||
const std::shared_ptr<IBluetoothAudioPort>& host_if,
|
||||
const AudioConfiguration& audio_config, DataMQDesc* _aidl_return);
|
||||
|
||||
private:
|
||||
// audio data queue for software encoding
|
||||
std::unique_ptr<DataMQ> data_mq_;
|
||||
|
||||
ndk::ScopedAStatus onSessionReady(DataMQDesc* _aidl_return) override;
|
||||
};
|
||||
|
||||
} // namespace audio
|
||||
} // namespace bluetooth
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
||||
34
bluetooth/audio/aidl/default/Android.bp
Normal file
34
bluetooth/audio/aidl/default/Android.bp
Normal file
@@ -0,0 +1,34 @@
|
||||
package {
|
||||
// See: http://go/android-license-faq
|
||||
// A large-scale-change added 'default_applicable_licenses' to import
|
||||
// all of the 'license_kinds' from "hardware_interfaces_license"
|
||||
// to get the below license kinds:
|
||||
// SPDX-license-identifier-Apache-2.0
|
||||
default_applicable_licenses: ["hardware_interfaces_license"],
|
||||
}
|
||||
|
||||
cc_library_shared {
|
||||
name: "android.hardware.bluetooth.audio-V1-impl",
|
||||
vendor: true,
|
||||
vintf_fragments: ["bluetooth_audio.xml"],
|
||||
srcs: [
|
||||
"BluetoothAudioProvider.cpp",
|
||||
"BluetoothAudioProviderFactory.cpp",
|
||||
"A2dpOffloadAudioProvider.cpp",
|
||||
"A2dpSoftwareAudioProvider.cpp",
|
||||
"HearingAidAudioProvider.cpp",
|
||||
"LeAudioOffloadAudioProvider.cpp",
|
||||
"LeAudioSoftwareAudioProvider.cpp",
|
||||
],
|
||||
export_include_dirs: ["."],
|
||||
header_libs: ["libhardware_headers"],
|
||||
shared_libs: [
|
||||
"libbase",
|
||||
"libbinder_ndk",
|
||||
"libcutils",
|
||||
"libfmq",
|
||||
"liblog",
|
||||
"android.hardware.bluetooth.audio-V1-ndk",
|
||||
"libbluetooth_audio_session_aidl",
|
||||
],
|
||||
}
|
||||
138
bluetooth/audio/aidl/default/BluetoothAudioProvider.cpp
Normal file
138
bluetooth/audio/aidl/default/BluetoothAudioProvider.cpp
Normal file
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define LOG_TAG "BTAudioProviderStub"
|
||||
|
||||
#include "BluetoothAudioProvider.h"
|
||||
|
||||
#include <BluetoothAudioSessionReport.h>
|
||||
#include <android-base/logging.h>
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace bluetooth {
|
||||
namespace audio {
|
||||
|
||||
BluetoothAudioProvider::BluetoothAudioProvider() {
|
||||
death_recipient_ = ::ndk::ScopedAIBinder_DeathRecipient(
|
||||
AIBinder_DeathRecipient_new(binderDiedCallbackAidl));
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus BluetoothAudioProvider::startSession(
|
||||
const std::shared_ptr<IBluetoothAudioPort>& host_if,
|
||||
const AudioConfiguration& audio_config, DataMQDesc* _aidl_return) {
|
||||
if (host_if == nullptr) {
|
||||
*_aidl_return = DataMQDesc();
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
|
||||
}
|
||||
audio_config_ = std::make_unique<AudioConfiguration>(audio_config);
|
||||
stack_iface_ = host_if;
|
||||
|
||||
AIBinder_linkToDeath(stack_iface_->asBinder().get(), death_recipient_.get(),
|
||||
this);
|
||||
|
||||
onSessionReady(_aidl_return);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus BluetoothAudioProvider::endSession() {
|
||||
LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_);
|
||||
|
||||
if (stack_iface_ != nullptr) {
|
||||
BluetoothAudioSessionReport::OnSessionEnded(session_type_);
|
||||
|
||||
AIBinder_unlinkToDeath(stack_iface_->asBinder().get(),
|
||||
death_recipient_.get(), this);
|
||||
} else {
|
||||
LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
|
||||
<< " has NO session";
|
||||
}
|
||||
|
||||
stack_iface_ = nullptr;
|
||||
audio_config_ = nullptr;
|
||||
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus BluetoothAudioProvider::streamStarted(
|
||||
BluetoothAudioStatus status) {
|
||||
LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
|
||||
<< ", status=" << toString(status);
|
||||
|
||||
if (stack_iface_ != nullptr) {
|
||||
BluetoothAudioSessionReport::ReportControlStatus(session_type_, true,
|
||||
status);
|
||||
} else {
|
||||
LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_)
|
||||
<< ", status=" << toString(status) << " has NO session";
|
||||
}
|
||||
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus BluetoothAudioProvider::streamSuspended(
|
||||
BluetoothAudioStatus status) {
|
||||
LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
|
||||
<< ", status=" << toString(status);
|
||||
|
||||
if (stack_iface_ != nullptr) {
|
||||
BluetoothAudioSessionReport::ReportControlStatus(session_type_, false,
|
||||
status);
|
||||
} else {
|
||||
LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_)
|
||||
<< ", status=" << toString(status) << " has NO session";
|
||||
}
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus BluetoothAudioProvider::updateAudioConfiguration(
|
||||
const AudioConfiguration& audio_config) {
|
||||
LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_);
|
||||
|
||||
if (stack_iface_ == nullptr || audio_config_ == nullptr) {
|
||||
LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
|
||||
<< " has NO session";
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
|
||||
}
|
||||
|
||||
if (audio_config.getTag() != audio_config_->getTag()) {
|
||||
LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
|
||||
<< " audio config type is not match";
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
|
||||
}
|
||||
|
||||
audio_config_ = std::make_unique<AudioConfiguration>(audio_config);
|
||||
BluetoothAudioSessionReport::ReportAudioConfigChanged(session_type_,
|
||||
*audio_config_);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
void BluetoothAudioProvider::binderDiedCallbackAidl(void* ptr) {
|
||||
LOG(ERROR) << __func__ << " - BluetoothAudio Service died";
|
||||
auto provider = static_cast<BluetoothAudioProvider*>(ptr);
|
||||
if (provider == nullptr) {
|
||||
LOG(ERROR) << __func__ << ": Null AudioProvider HAL died";
|
||||
return;
|
||||
}
|
||||
provider->endSession();
|
||||
}
|
||||
|
||||
} // namespace audio
|
||||
} // namespace bluetooth
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
||||
67
bluetooth/audio/aidl/default/BluetoothAudioProvider.h
Normal file
67
bluetooth/audio/aidl/default/BluetoothAudioProvider.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <aidl/android/hardware/bluetooth/audio/BnBluetoothAudioProvider.h>
|
||||
#include <aidl/android/hardware/bluetooth/audio/SessionType.h>
|
||||
#include <fmq/AidlMessageQueue.h>
|
||||
|
||||
using ::aidl::android::hardware::common::fmq::MQDescriptor;
|
||||
using ::aidl::android::hardware::common::fmq::SynchronizedReadWrite;
|
||||
using ::android::AidlMessageQueue;
|
||||
|
||||
using MqDataType = int8_t;
|
||||
using MqDataMode = SynchronizedReadWrite;
|
||||
using DataMQ = AidlMessageQueue<MqDataType, MqDataMode>;
|
||||
using DataMQDesc = MQDescriptor<MqDataType, MqDataMode>;
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace bluetooth {
|
||||
namespace audio {
|
||||
|
||||
class BluetoothAudioProvider : public BnBluetoothAudioProvider {
|
||||
public:
|
||||
BluetoothAudioProvider();
|
||||
|
||||
ndk::ScopedAStatus startSession(
|
||||
const std::shared_ptr<IBluetoothAudioPort>& host_if,
|
||||
const AudioConfiguration& audio_config, DataMQDesc* _aidl_return);
|
||||
ndk::ScopedAStatus endSession();
|
||||
ndk::ScopedAStatus streamStarted(BluetoothAudioStatus status);
|
||||
ndk::ScopedAStatus streamSuspended(BluetoothAudioStatus status);
|
||||
ndk::ScopedAStatus updateAudioConfiguration(
|
||||
const AudioConfiguration& audio_config);
|
||||
|
||||
virtual bool isValid(const SessionType& sessionType) = 0;
|
||||
|
||||
protected:
|
||||
virtual ndk::ScopedAStatus onSessionReady(DataMQDesc* _aidl_return) = 0;
|
||||
static void binderDiedCallbackAidl(void* cookie_ptr);
|
||||
|
||||
::ndk::ScopedAIBinder_DeathRecipient death_recipient_;
|
||||
|
||||
std::shared_ptr<IBluetoothAudioPort> stack_iface_;
|
||||
std::unique_ptr<AudioConfiguration> audio_config_ = nullptr;
|
||||
SessionType session_type_;
|
||||
};
|
||||
|
||||
} // namespace audio
|
||||
} // namespace bluetooth
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
||||
124
bluetooth/audio/aidl/default/BluetoothAudioProviderFactory.cpp
Normal file
124
bluetooth/audio/aidl/default/BluetoothAudioProviderFactory.cpp
Normal file
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define LOG_TAG "BTAudioProvidersFactory"
|
||||
|
||||
#include "BluetoothAudioProviderFactory.h"
|
||||
|
||||
#include <BluetoothAudioCodecs.h>
|
||||
#include <android-base/logging.h>
|
||||
|
||||
#include "A2dpOffloadAudioProvider.h"
|
||||
#include "A2dpSoftwareAudioProvider.h"
|
||||
#include "BluetoothAudioProvider.h"
|
||||
#include "HearingAidAudioProvider.h"
|
||||
#include "LeAudioOffloadAudioProvider.h"
|
||||
#include "LeAudioSoftwareAudioProvider.h"
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace bluetooth {
|
||||
namespace audio {
|
||||
|
||||
BluetoothAudioProviderFactory::BluetoothAudioProviderFactory() {}
|
||||
|
||||
ndk::ScopedAStatus BluetoothAudioProviderFactory::openProvider(
|
||||
const SessionType session_type,
|
||||
std::shared_ptr<IBluetoothAudioProvider>* _aidl_return) {
|
||||
LOG(INFO) << __func__ << " - SessionType=" << toString(session_type);
|
||||
std::shared_ptr<BluetoothAudioProvider> provider = nullptr;
|
||||
|
||||
switch (session_type) {
|
||||
case SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH:
|
||||
provider = ndk::SharedRefBase::make<A2dpSoftwareAudioProvider>();
|
||||
break;
|
||||
case SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH:
|
||||
provider = ndk::SharedRefBase::make<A2dpOffloadAudioProvider>();
|
||||
break;
|
||||
case SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH:
|
||||
provider = ndk::SharedRefBase::make<HearingAidAudioProvider>();
|
||||
break;
|
||||
case SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH:
|
||||
provider = ndk::SharedRefBase::make<LeAudioSoftwareOutputAudioProvider>();
|
||||
break;
|
||||
case SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH:
|
||||
provider = ndk::SharedRefBase::make<LeAudioOffloadOutputAudioProvider>();
|
||||
break;
|
||||
case SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH:
|
||||
provider = ndk::SharedRefBase::make<LeAudioSoftwareInputAudioProvider>();
|
||||
break;
|
||||
case SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH:
|
||||
provider = ndk::SharedRefBase::make<LeAudioOffloadInputAudioProvider>();
|
||||
break;
|
||||
default:
|
||||
provider = nullptr;
|
||||
break;
|
||||
}
|
||||
|
||||
if (provider == nullptr || !provider->isValid(session_type)) {
|
||||
provider = nullptr;
|
||||
LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type);
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
|
||||
}
|
||||
*_aidl_return = provider;
|
||||
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus BluetoothAudioProviderFactory::getProviderCapabilities(
|
||||
const SessionType session_type,
|
||||
std::vector<AudioCapabilities>* _aidl_return) {
|
||||
if (session_type == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
|
||||
auto codec_capabilities =
|
||||
BluetoothAudioCodecs::GetA2dpOffloadCodecCapabilities(session_type);
|
||||
_aidl_return->resize(codec_capabilities.size());
|
||||
for (int i = 0; i < codec_capabilities.size(); i++) {
|
||||
_aidl_return->at(i).set<AudioCapabilities::a2dpCapabilities>(
|
||||
codec_capabilities[i]);
|
||||
}
|
||||
} else if (session_type ==
|
||||
SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
|
||||
session_type ==
|
||||
SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
|
||||
std::vector<LeAudioCodecCapabilitiesSetting> db_codec_capabilities =
|
||||
BluetoothAudioCodecs::GetLeAudioOffloadCodecCapabilities(session_type);
|
||||
if (db_codec_capabilities.size()) {
|
||||
_aidl_return->resize(db_codec_capabilities.size());
|
||||
for (int i = 0; i < db_codec_capabilities.size(); ++i) {
|
||||
_aidl_return->at(i).set<AudioCapabilities::leAudioCapabilities>(
|
||||
db_codec_capabilities[i]);
|
||||
}
|
||||
}
|
||||
} else if (session_type != SessionType::UNKNOWN) {
|
||||
auto pcm_capabilities = BluetoothAudioCodecs::GetSoftwarePcmCapabilities();
|
||||
_aidl_return->resize(pcm_capabilities.size());
|
||||
for (int i = 0; i < pcm_capabilities.size(); i++) {
|
||||
_aidl_return->at(i).set<AudioCapabilities::pcmCapabilities>(
|
||||
pcm_capabilities[i]);
|
||||
}
|
||||
}
|
||||
|
||||
LOG(INFO) << __func__ << " - SessionType=" << toString(session_type)
|
||||
<< " supports " << _aidl_return->size() << " codecs";
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
} // namespace audio
|
||||
} // namespace bluetooth
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
||||
51
bluetooth/audio/aidl/default/BluetoothAudioProviderFactory.h
Normal file
51
bluetooth/audio/aidl/default/BluetoothAudioProviderFactory.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <aidl/android/hardware/bluetooth/audio/BnBluetoothAudioProviderFactory.h>
|
||||
|
||||
#include "A2dpOffloadAudioProvider.h"
|
||||
#include "A2dpSoftwareAudioProvider.h"
|
||||
#include "BluetoothAudioProvider.h"
|
||||
#include "HearingAidAudioProvider.h"
|
||||
#include "LeAudioOffloadAudioProvider.h"
|
||||
#include "LeAudioSoftwareAudioProvider.h"
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace bluetooth {
|
||||
namespace audio {
|
||||
|
||||
class BluetoothAudioProviderFactory : public BnBluetoothAudioProviderFactory {
|
||||
public:
|
||||
BluetoothAudioProviderFactory();
|
||||
|
||||
ndk::ScopedAStatus openProvider(
|
||||
const SessionType session_type,
|
||||
std::shared_ptr<IBluetoothAudioProvider>* _aidl_return) override;
|
||||
|
||||
ndk::ScopedAStatus getProviderCapabilities(
|
||||
const SessionType session_type,
|
||||
std::vector<AudioCapabilities>* _aidl_return) override;
|
||||
};
|
||||
|
||||
} // namespace audio
|
||||
} // namespace bluetooth
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
||||
95
bluetooth/audio/aidl/default/HearingAidAudioProvider.cpp
Normal file
95
bluetooth/audio/aidl/default/HearingAidAudioProvider.cpp
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define LOG_TAG "BTAudioProviderHearingAid"
|
||||
|
||||
#include "HearingAidAudioProvider.h"
|
||||
|
||||
#include <BluetoothAudioCodecs.h>
|
||||
#include <BluetoothAudioSessionReport.h>
|
||||
#include <android-base/logging.h>
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace bluetooth {
|
||||
namespace audio {
|
||||
|
||||
static constexpr uint32_t kPcmFrameSize = 4; // 16 bits per sample / stereo
|
||||
static constexpr uint32_t kPcmFrameCount = 128;
|
||||
static constexpr uint32_t kRtpFrameSize = kPcmFrameSize * kPcmFrameCount;
|
||||
static constexpr uint32_t kRtpFrameCount = 7; // max counts by 1 tick (20ms)
|
||||
static constexpr uint32_t kBufferSize = kRtpFrameSize * kRtpFrameCount;
|
||||
static constexpr uint32_t kBufferCount = 1; // single buffer
|
||||
static constexpr uint32_t kDataMqSize = kBufferSize * kBufferCount;
|
||||
|
||||
HearingAidAudioProvider::HearingAidAudioProvider()
|
||||
: BluetoothAudioProvider(), data_mq_(nullptr) {
|
||||
LOG(INFO) << __func__ << " - size of audio buffer " << kDataMqSize
|
||||
<< " byte(s)";
|
||||
std::unique_ptr<DataMQ> data_mq(
|
||||
new DataMQ(kDataMqSize, /* EventFlag */ true));
|
||||
if (data_mq && data_mq->isValid()) {
|
||||
data_mq_ = std::move(data_mq);
|
||||
session_type_ = SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH;
|
||||
} else {
|
||||
ALOGE_IF(!data_mq, "failed to allocate data MQ");
|
||||
ALOGE_IF(data_mq && !data_mq->isValid(), "data MQ is invalid");
|
||||
}
|
||||
}
|
||||
bool HearingAidAudioProvider::isValid(const SessionType& sessionType) {
|
||||
return (sessionType == session_type_ && data_mq_ && data_mq_->isValid());
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus HearingAidAudioProvider::startSession(
|
||||
const std::shared_ptr<IBluetoothAudioPort>& host_if,
|
||||
const AudioConfiguration& audio_config, DataMQDesc* _aidl_return) {
|
||||
if (audio_config.getTag() != AudioConfiguration::pcmConfig) {
|
||||
LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
|
||||
<< audio_config.toString();
|
||||
*_aidl_return = DataMQDesc();
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
|
||||
}
|
||||
const auto& pcm_config = audio_config.get<AudioConfiguration::pcmConfig>();
|
||||
if (!BluetoothAudioCodecs::IsSoftwarePcmConfigurationValid(pcm_config)) {
|
||||
LOG(WARNING) << __func__ << " - Unsupported PCM Configuration="
|
||||
<< pcm_config.toString();
|
||||
*_aidl_return = DataMQDesc();
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
|
||||
}
|
||||
|
||||
return BluetoothAudioProvider::startSession(host_if, audio_config,
|
||||
_aidl_return);
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus HearingAidAudioProvider::onSessionReady(
|
||||
DataMQDesc* _aidl_return) {
|
||||
if (data_mq_ == nullptr || !data_mq_->isValid()) {
|
||||
*_aidl_return = DataMQDesc();
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
|
||||
}
|
||||
auto desc = data_mq_->dupeDesc();
|
||||
BluetoothAudioSessionReport::OnSessionStarted(session_type_, stack_iface_,
|
||||
&desc, *audio_config_);
|
||||
*_aidl_return = data_mq_->dupeDesc();
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
} // namespace audio
|
||||
} // namespace bluetooth
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
||||
48
bluetooth/audio/aidl/default/HearingAidAudioProvider.h
Normal file
48
bluetooth/audio/aidl/default/HearingAidAudioProvider.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BluetoothAudioProvider.h"
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace bluetooth {
|
||||
namespace audio {
|
||||
|
||||
class HearingAidAudioProvider : public BluetoothAudioProvider {
|
||||
public:
|
||||
HearingAidAudioProvider();
|
||||
|
||||
bool isValid(const SessionType& sessionType) override;
|
||||
|
||||
ndk::ScopedAStatus startSession(
|
||||
const std::shared_ptr<IBluetoothAudioPort>& host_if,
|
||||
const AudioConfiguration& audio_config, DataMQDesc* _aidl_return);
|
||||
|
||||
private:
|
||||
// audio data queue for software encoding
|
||||
std::unique_ptr<DataMQ> data_mq_;
|
||||
|
||||
ndk::ScopedAStatus onSessionReady(DataMQDesc* _aidl_return) override;
|
||||
};
|
||||
|
||||
} // namespace audio
|
||||
} // namespace bluetooth
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
||||
83
bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp
Normal file
83
bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define LOG_TAG "BTAudioProviderLeAudioSW"
|
||||
|
||||
#include "LeAudioOffloadAudioProvider.h"
|
||||
|
||||
#include <BluetoothAudioCodecs.h>
|
||||
#include <BluetoothAudioSessionReport.h>
|
||||
#include <android-base/logging.h>
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace bluetooth {
|
||||
namespace audio {
|
||||
|
||||
LeAudioOffloadOutputAudioProvider::LeAudioOffloadOutputAudioProvider()
|
||||
: LeAudioOffloadAudioProvider() {
|
||||
session_type_ = SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH;
|
||||
}
|
||||
|
||||
LeAudioOffloadInputAudioProvider::LeAudioOffloadInputAudioProvider()
|
||||
: LeAudioOffloadAudioProvider() {
|
||||
session_type_ = SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH;
|
||||
}
|
||||
|
||||
LeAudioOffloadAudioProvider::LeAudioOffloadAudioProvider()
|
||||
: BluetoothAudioProvider() {}
|
||||
|
||||
bool LeAudioOffloadAudioProvider::isValid(const SessionType& sessionType) {
|
||||
return (sessionType == session_type_);
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus LeAudioOffloadAudioProvider::startSession(
|
||||
const std::shared_ptr<IBluetoothAudioPort>& host_if,
|
||||
const AudioConfiguration& audio_config, DataMQDesc* _aidl_return) {
|
||||
if (audio_config.getTag() != AudioConfiguration::leAudioConfig) {
|
||||
LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
|
||||
<< audio_config.toString();
|
||||
*_aidl_return = DataMQDesc();
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
|
||||
}
|
||||
const auto& le_audio_config =
|
||||
audio_config.get<AudioConfiguration::leAudioConfig>();
|
||||
if (!BluetoothAudioCodecs::IsOffloadLeAudioConfigurationValid(
|
||||
session_type_, le_audio_config)) {
|
||||
LOG(WARNING) << __func__ << " - Unsupported LC3 Offloaded Configuration="
|
||||
<< le_audio_config.toString();
|
||||
*_aidl_return = DataMQDesc();
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
|
||||
}
|
||||
|
||||
return BluetoothAudioProvider::startSession(host_if, audio_config,
|
||||
_aidl_return);
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus LeAudioOffloadAudioProvider::onSessionReady(
|
||||
DataMQDesc* _aidl_return) {
|
||||
BluetoothAudioSessionReport::OnSessionStarted(session_type_, stack_iface_,
|
||||
nullptr, *audio_config_);
|
||||
*_aidl_return = DataMQDesc();
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
} // namespace audio
|
||||
} // namespace bluetooth
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
||||
55
bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h
Normal file
55
bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BluetoothAudioProvider.h"
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace bluetooth {
|
||||
namespace audio {
|
||||
|
||||
class LeAudioOffloadAudioProvider : public BluetoothAudioProvider {
|
||||
public:
|
||||
LeAudioOffloadAudioProvider();
|
||||
|
||||
bool isValid(const SessionType& sessionType) override;
|
||||
|
||||
ndk::ScopedAStatus startSession(
|
||||
const std::shared_ptr<IBluetoothAudioPort>& host_if,
|
||||
const AudioConfiguration& audio_config, DataMQDesc* _aidl_return);
|
||||
|
||||
private:
|
||||
ndk::ScopedAStatus onSessionReady(DataMQDesc* _aidl_return) override;
|
||||
};
|
||||
|
||||
class LeAudioOffloadOutputAudioProvider : public LeAudioOffloadAudioProvider {
|
||||
public:
|
||||
LeAudioOffloadOutputAudioProvider();
|
||||
};
|
||||
|
||||
class LeAudioOffloadInputAudioProvider : public LeAudioOffloadAudioProvider {
|
||||
public:
|
||||
LeAudioOffloadInputAudioProvider();
|
||||
};
|
||||
|
||||
} // namespace audio
|
||||
} // namespace bluetooth
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
||||
125
bluetooth/audio/aidl/default/LeAudioSoftwareAudioProvider.cpp
Normal file
125
bluetooth/audio/aidl/default/LeAudioSoftwareAudioProvider.cpp
Normal file
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define LOG_TAG "BTAudioProviderLeAudioHW"
|
||||
|
||||
#include "LeAudioSoftwareAudioProvider.h"
|
||||
|
||||
#include <BluetoothAudioCodecs.h>
|
||||
#include <BluetoothAudioSessionReport.h>
|
||||
#include <android-base/logging.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace bluetooth {
|
||||
namespace audio {
|
||||
|
||||
static constexpr uint32_t kBufferOutCount = 2; // two frame buffer
|
||||
static constexpr uint32_t kBufferInCount = 2; // two frame buffer
|
||||
|
||||
inline uint32_t channel_mode_to_channel_count(ChannelMode channel_mode) {
|
||||
switch (channel_mode) {
|
||||
case ChannelMode::MONO:
|
||||
return 1;
|
||||
case ChannelMode::STEREO:
|
||||
return 2;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
LeAudioSoftwareOutputAudioProvider::LeAudioSoftwareOutputAudioProvider()
|
||||
: LeAudioSoftwareAudioProvider() {
|
||||
session_type_ = SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH;
|
||||
}
|
||||
|
||||
LeAudioSoftwareInputAudioProvider::LeAudioSoftwareInputAudioProvider()
|
||||
: LeAudioSoftwareAudioProvider() {
|
||||
session_type_ = SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH;
|
||||
}
|
||||
|
||||
LeAudioSoftwareAudioProvider::LeAudioSoftwareAudioProvider()
|
||||
: BluetoothAudioProvider(), data_mq_(nullptr) {}
|
||||
|
||||
bool LeAudioSoftwareAudioProvider::isValid(const SessionType& sessionType) {
|
||||
return (sessionType == session_type_);
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus LeAudioSoftwareAudioProvider::startSession(
|
||||
const std::shared_ptr<IBluetoothAudioPort>& host_if,
|
||||
const AudioConfiguration& audio_config, DataMQDesc* _aidl_return) {
|
||||
if (audio_config.getTag() != AudioConfiguration::pcmConfig) {
|
||||
LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
|
||||
<< audio_config.toString();
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
|
||||
}
|
||||
const auto& pcm_config = audio_config.get<AudioConfiguration::pcmConfig>();
|
||||
if (!BluetoothAudioCodecs::IsSoftwarePcmConfigurationValid(pcm_config)) {
|
||||
LOG(WARNING) << __func__ << " - Unsupported PCM Configuration="
|
||||
<< pcm_config.toString();
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
|
||||
}
|
||||
|
||||
uint32_t buffer_modifier = 0;
|
||||
if (session_type_ == SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH)
|
||||
buffer_modifier = kBufferOutCount;
|
||||
else if (session_type_ == SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH)
|
||||
buffer_modifier = kBufferInCount;
|
||||
|
||||
uint32_t data_mq_size =
|
||||
(ceil(pcm_config.sampleRateHz) / 1000) *
|
||||
channel_mode_to_channel_count(pcm_config.channelMode) *
|
||||
(pcm_config.bitsPerSample / 8) * (pcm_config.dataIntervalUs / 1000) *
|
||||
buffer_modifier;
|
||||
|
||||
LOG(INFO) << __func__ << " - size of audio buffer " << data_mq_size
|
||||
<< " byte(s)";
|
||||
|
||||
std::unique_ptr<DataMQ> temp_data_mq(
|
||||
new DataMQ(data_mq_size, /* EventFlag */ true));
|
||||
if (temp_data_mq == nullptr || !temp_data_mq->isValid()) {
|
||||
ALOGE_IF(!temp_data_mq, "failed to allocate data MQ");
|
||||
ALOGE_IF(temp_data_mq && !temp_data_mq->isValid(), "data MQ is invalid");
|
||||
*_aidl_return = DataMQDesc();
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
|
||||
}
|
||||
data_mq_ = std::move(temp_data_mq);
|
||||
|
||||
return BluetoothAudioProvider::startSession(host_if, audio_config,
|
||||
_aidl_return);
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus LeAudioSoftwareAudioProvider::onSessionReady(
|
||||
DataMQDesc* _aidl_return) {
|
||||
if (data_mq_ == nullptr || !data_mq_->isValid()) {
|
||||
*_aidl_return = DataMQDesc();
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
|
||||
}
|
||||
*_aidl_return = data_mq_->dupeDesc();
|
||||
BluetoothAudioSessionReport::OnSessionStarted(session_type_, stack_iface_,
|
||||
_aidl_return, *audio_config_);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
} // namespace audio
|
||||
} // namespace bluetooth
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
||||
58
bluetooth/audio/aidl/default/LeAudioSoftwareAudioProvider.h
Normal file
58
bluetooth/audio/aidl/default/LeAudioSoftwareAudioProvider.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BluetoothAudioProvider.h"
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace bluetooth {
|
||||
namespace audio {
|
||||
|
||||
class LeAudioSoftwareAudioProvider : public BluetoothAudioProvider {
|
||||
public:
|
||||
LeAudioSoftwareAudioProvider();
|
||||
|
||||
bool isValid(const SessionType& sessionType) override;
|
||||
|
||||
ndk::ScopedAStatus startSession(
|
||||
const std::shared_ptr<IBluetoothAudioPort>& host_if,
|
||||
const AudioConfiguration& audio_config, DataMQDesc* _aidl_return);
|
||||
|
||||
private:
|
||||
// audio data queue for software encoding
|
||||
std::unique_ptr<DataMQ> data_mq_;
|
||||
|
||||
ndk::ScopedAStatus onSessionReady(DataMQDesc* _aidl_return) override;
|
||||
};
|
||||
|
||||
class LeAudioSoftwareOutputAudioProvider : public LeAudioSoftwareAudioProvider {
|
||||
public:
|
||||
LeAudioSoftwareOutputAudioProvider();
|
||||
};
|
||||
|
||||
class LeAudioSoftwareInputAudioProvider : public LeAudioSoftwareAudioProvider {
|
||||
public:
|
||||
LeAudioSoftwareInputAudioProvider();
|
||||
};
|
||||
|
||||
} // namespace audio
|
||||
} // namespace bluetooth
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
||||
6
bluetooth/audio/aidl/default/bluetooth_audio.xml
Normal file
6
bluetooth/audio/aidl/default/bluetooth_audio.xml
Normal file
@@ -0,0 +1,6 @@
|
||||
<manifest version="1.0" type="device">
|
||||
<hal format="aidl">
|
||||
<name>android.hardware.bluetooth.audio</name>
|
||||
<fqname>IBluetoothAudioProviderFactory/default</fqname>
|
||||
</hal>
|
||||
</manifest>
|
||||
@@ -32,5 +32,30 @@ cc_library_shared {
|
||||
"libhidlbase",
|
||||
"liblog",
|
||||
"libutils",
|
||||
"libbluetooth_audio_session_aidl",
|
||||
],
|
||||
}
|
||||
|
||||
cc_library_shared {
|
||||
name: "libbluetooth_audio_session_aidl",
|
||||
vendor: true,
|
||||
srcs: [
|
||||
"aidl_session/BluetoothAudioCodecs.cpp",
|
||||
"aidl_session/BluetoothAudioSession.cpp",
|
||||
"aidl_session/HidlToAidlMiddleware.cpp",
|
||||
],
|
||||
export_include_dirs: ["aidl_session/"],
|
||||
header_libs: ["libhardware_headers"],
|
||||
shared_libs: [
|
||||
"android.hardware.bluetooth.audio@2.0",
|
||||
"android.hardware.bluetooth.audio@2.1",
|
||||
"android.hardware.bluetooth.audio@2.2",
|
||||
"libbase",
|
||||
"libcutils",
|
||||
"libbinder_ndk",
|
||||
"libfmq",
|
||||
"liblog",
|
||||
"android.hardware.bluetooth.audio-V1-ndk",
|
||||
"libhidlbase",
|
||||
],
|
||||
}
|
||||
|
||||
489
bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp
Normal file
489
bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp
Normal file
@@ -0,0 +1,489 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define LOG_TAG "BTAudioCodecsAidl"
|
||||
|
||||
#include "BluetoothAudioCodecs.h"
|
||||
|
||||
#include <aidl/android/hardware/bluetooth/audio/AacCapabilities.h>
|
||||
#include <aidl/android/hardware/bluetooth/audio/AacObjectType.h>
|
||||
#include <aidl/android/hardware/bluetooth/audio/AptxCapabilities.h>
|
||||
#include <aidl/android/hardware/bluetooth/audio/ChannelMode.h>
|
||||
#include <aidl/android/hardware/bluetooth/audio/LdacCapabilities.h>
|
||||
#include <aidl/android/hardware/bluetooth/audio/LdacChannelMode.h>
|
||||
#include <aidl/android/hardware/bluetooth/audio/LdacQualityIndex.h>
|
||||
#include <aidl/android/hardware/bluetooth/audio/LeAudioConfiguration.h>
|
||||
#include <aidl/android/hardware/bluetooth/audio/SbcCapabilities.h>
|
||||
#include <aidl/android/hardware/bluetooth/audio/SbcChannelMode.h>
|
||||
#include <android-base/logging.h>
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace bluetooth {
|
||||
namespace audio {
|
||||
|
||||
static const PcmCapabilities kDefaultSoftwarePcmCapabilities = {
|
||||
.sampleRateHz = {16000, 24000, 44100, 48000, 88200, 96000},
|
||||
.channelMode = {ChannelMode::MONO, ChannelMode::STEREO},
|
||||
.bitsPerSample = {16, 24, 32},
|
||||
.dataIntervalUs = {},
|
||||
};
|
||||
|
||||
static const SbcCapabilities kDefaultOffloadSbcCapability = {
|
||||
.sampleRateHz = {44100},
|
||||
.channelMode = {SbcChannelMode::MONO, SbcChannelMode::JOINT_STEREO},
|
||||
.blockLength = {4, 8, 12, 16},
|
||||
.numSubbands = {8},
|
||||
.allocMethod = {SbcAllocMethod::ALLOC_MD_L},
|
||||
.bitsPerSample = {16},
|
||||
.minBitpool = 2,
|
||||
.maxBitpool = 53};
|
||||
|
||||
static const AacCapabilities kDefaultOffloadAacCapability = {
|
||||
.objectType = {AacObjectType::MPEG2_LC},
|
||||
.sampleRateHz = {44100},
|
||||
.channelMode = {ChannelMode::STEREO},
|
||||
.variableBitRateSupported = true,
|
||||
.bitsPerSample = {16}};
|
||||
|
||||
static const LdacCapabilities kDefaultOffloadLdacCapability = {
|
||||
.sampleRateHz = {44100, 48000, 88200, 96000},
|
||||
.channelMode = {LdacChannelMode::DUAL, LdacChannelMode::STEREO},
|
||||
.qualityIndex = {LdacQualityIndex::HIGH},
|
||||
.bitsPerSample = {16, 24, 32}};
|
||||
|
||||
static const AptxCapabilities kDefaultOffloadAptxCapability = {
|
||||
.sampleRateHz = {44100, 48000},
|
||||
.channelMode = {ChannelMode::STEREO},
|
||||
.bitsPerSample = {16},
|
||||
};
|
||||
|
||||
static const AptxCapabilities kDefaultOffloadAptxHdCapability = {
|
||||
.sampleRateHz = {44100, 48000},
|
||||
.channelMode = {ChannelMode::STEREO},
|
||||
.bitsPerSample = {24},
|
||||
};
|
||||
|
||||
static const Lc3Capabilities kDefaultOffloadLc3Capability = {
|
||||
.samplingFrequencyHz = {44100, 48000},
|
||||
.frameDurationUs = {7500, 10000},
|
||||
.channelMode = {ChannelMode::MONO, ChannelMode::STEREO},
|
||||
};
|
||||
|
||||
const std::vector<CodecCapabilities> kDefaultOffloadA2dpCodecCapabilities = {
|
||||
{.codecType = CodecType::SBC, .capabilities = {}},
|
||||
{.codecType = CodecType::AAC, .capabilities = {}},
|
||||
{.codecType = CodecType::LDAC, .capabilities = {}},
|
||||
{.codecType = CodecType::APTX, .capabilities = {}},
|
||||
{.codecType = CodecType::APTX_HD, .capabilities = {}},
|
||||
{.codecType = CodecType::LC3, .capabilities = {}}};
|
||||
|
||||
std::vector<LeAudioCodecCapabilitiesSetting> kDefaultOffloadLeAudioCapabilities;
|
||||
|
||||
static const UnicastCapability kInvalidUnicastCapability = {
|
||||
.codecType = CodecType::UNKNOWN};
|
||||
|
||||
static const BroadcastCapability kInvalidBroadcastCapability = {
|
||||
.codecType = CodecType::UNKNOWN};
|
||||
|
||||
// Default Supported Codecs
|
||||
// LC3 16_1: sample rate: 16 kHz, frame duration: 7.5 ms, octets per frame: 30
|
||||
static const Lc3Capabilities kLc3Capability_16_1 = {
|
||||
.samplingFrequencyHz = {16000},
|
||||
.frameDurationUs = {7500},
|
||||
.octetsPerFrame = {30}};
|
||||
|
||||
// Default Supported Codecs
|
||||
// LC3 16_2: sample rate: 16 kHz, frame duration: 10 ms, octets per frame: 40
|
||||
static const Lc3Capabilities kLc3Capability_16_2 = {
|
||||
.samplingFrequencyHz = {16000},
|
||||
.frameDurationUs = {10000},
|
||||
.octetsPerFrame = {40}};
|
||||
|
||||
// Default Supported Codecs
|
||||
// LC3 48_4: sample rate: 48 kHz, frame duration: 10 ms, octets per frame: 120
|
||||
static const Lc3Capabilities kLc3Capability_48_4 = {
|
||||
.samplingFrequencyHz = {48000},
|
||||
.frameDurationUs = {10000},
|
||||
.octetsPerFrame = {120}};
|
||||
|
||||
static const std::vector<Lc3Capabilities> supportedLc3CapabilityList = {
|
||||
kLc3Capability_48_4, kLc3Capability_16_2, kLc3Capability_16_1};
|
||||
|
||||
static AudioLocation stereoAudio = static_cast<AudioLocation>(
|
||||
static_cast<uint8_t>(AudioLocation::FRONT_LEFT) |
|
||||
static_cast<uint8_t>(AudioLocation::FRONT_RIGHT));
|
||||
static AudioLocation monoAudio = AudioLocation::UNKNOWN;
|
||||
|
||||
// Stores the supported setting of audio location, connected device, and the
|
||||
// channel count for each device
|
||||
std::vector<std::tuple<AudioLocation, uint8_t, uint8_t>>
|
||||
supportedDeviceSetting = {std::make_tuple(stereoAudio, 2, 1),
|
||||
std::make_tuple(monoAudio, 1, 2),
|
||||
std::make_tuple(monoAudio, 1, 1)};
|
||||
|
||||
template <class T>
|
||||
bool BluetoothAudioCodecs::ContainedInVector(
|
||||
const std::vector<T>& vector, const typename identity<T>::type& target) {
|
||||
return std::find(vector.begin(), vector.end(), target) != vector.end();
|
||||
}
|
||||
|
||||
bool BluetoothAudioCodecs::IsOffloadSbcConfigurationValid(
|
||||
const CodecConfiguration::CodecSpecific& codec_specific) {
|
||||
if (codec_specific.getTag() != CodecConfiguration::CodecSpecific::sbcConfig) {
|
||||
LOG(WARNING) << __func__
|
||||
<< ": Invalid CodecSpecific=" << codec_specific.toString();
|
||||
return false;
|
||||
}
|
||||
const SbcConfiguration sbc_data =
|
||||
codec_specific.get<CodecConfiguration::CodecSpecific::sbcConfig>();
|
||||
|
||||
if (ContainedInVector(kDefaultOffloadSbcCapability.sampleRateHz,
|
||||
sbc_data.sampleRateHz) &&
|
||||
ContainedInVector(kDefaultOffloadSbcCapability.blockLength,
|
||||
sbc_data.blockLength) &&
|
||||
ContainedInVector(kDefaultOffloadSbcCapability.numSubbands,
|
||||
sbc_data.numSubbands) &&
|
||||
ContainedInVector(kDefaultOffloadSbcCapability.bitsPerSample,
|
||||
sbc_data.bitsPerSample) &&
|
||||
ContainedInVector(kDefaultOffloadSbcCapability.channelMode,
|
||||
sbc_data.channelMode) &&
|
||||
ContainedInVector(kDefaultOffloadSbcCapability.allocMethod,
|
||||
sbc_data.allocMethod) &&
|
||||
sbc_data.minBitpool <= sbc_data.maxBitpool &&
|
||||
kDefaultOffloadSbcCapability.minBitpool <= sbc_data.minBitpool &&
|
||||
kDefaultOffloadSbcCapability.maxBitpool >= sbc_data.maxBitpool) {
|
||||
return true;
|
||||
}
|
||||
LOG(WARNING) << __func__
|
||||
<< ": Unsupported CodecSpecific=" << codec_specific.toString();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BluetoothAudioCodecs::IsOffloadAacConfigurationValid(
|
||||
const CodecConfiguration::CodecSpecific& codec_specific) {
|
||||
if (codec_specific.getTag() != CodecConfiguration::CodecSpecific::aacConfig) {
|
||||
LOG(WARNING) << __func__
|
||||
<< ": Invalid CodecSpecific=" << codec_specific.toString();
|
||||
return false;
|
||||
}
|
||||
const AacConfiguration aac_data =
|
||||
codec_specific.get<CodecConfiguration::CodecSpecific::aacConfig>();
|
||||
|
||||
if (ContainedInVector(kDefaultOffloadAacCapability.sampleRateHz,
|
||||
aac_data.sampleRateHz) &&
|
||||
ContainedInVector(kDefaultOffloadAacCapability.bitsPerSample,
|
||||
aac_data.bitsPerSample) &&
|
||||
ContainedInVector(kDefaultOffloadAacCapability.channelMode,
|
||||
aac_data.channelMode) &&
|
||||
ContainedInVector(kDefaultOffloadAacCapability.objectType,
|
||||
aac_data.objectType) &&
|
||||
(!aac_data.variableBitRateEnabled ||
|
||||
kDefaultOffloadAacCapability.variableBitRateSupported)) {
|
||||
return true;
|
||||
}
|
||||
LOG(WARNING) << __func__
|
||||
<< ": Unsupported CodecSpecific=" << codec_specific.toString();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BluetoothAudioCodecs::IsOffloadLdacConfigurationValid(
|
||||
const CodecConfiguration::CodecSpecific& codec_specific) {
|
||||
if (codec_specific.getTag() !=
|
||||
CodecConfiguration::CodecSpecific::ldacConfig) {
|
||||
LOG(WARNING) << __func__
|
||||
<< ": Invalid CodecSpecific=" << codec_specific.toString();
|
||||
return false;
|
||||
}
|
||||
const LdacConfiguration ldac_data =
|
||||
codec_specific.get<CodecConfiguration::CodecSpecific::ldacConfig>();
|
||||
|
||||
if (ContainedInVector(kDefaultOffloadLdacCapability.sampleRateHz,
|
||||
ldac_data.sampleRateHz) &&
|
||||
ContainedInVector(kDefaultOffloadLdacCapability.bitsPerSample,
|
||||
ldac_data.bitsPerSample) &&
|
||||
ContainedInVector(kDefaultOffloadLdacCapability.channelMode,
|
||||
ldac_data.channelMode) &&
|
||||
ContainedInVector(kDefaultOffloadLdacCapability.qualityIndex,
|
||||
ldac_data.qualityIndex)) {
|
||||
return true;
|
||||
}
|
||||
LOG(WARNING) << __func__
|
||||
<< ": Unsupported CodecSpecific=" << codec_specific.toString();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BluetoothAudioCodecs::IsOffloadAptxConfigurationValid(
|
||||
const CodecConfiguration::CodecSpecific& codec_specific) {
|
||||
if (codec_specific.getTag() !=
|
||||
CodecConfiguration::CodecSpecific::aptxConfig) {
|
||||
LOG(WARNING) << __func__
|
||||
<< ": Invalid CodecSpecific=" << codec_specific.toString();
|
||||
return false;
|
||||
}
|
||||
const AptxConfiguration aptx_data =
|
||||
codec_specific.get<CodecConfiguration::CodecSpecific::aptxConfig>();
|
||||
|
||||
if (ContainedInVector(kDefaultOffloadAptxCapability.sampleRateHz,
|
||||
aptx_data.sampleRateHz) &&
|
||||
ContainedInVector(kDefaultOffloadAptxCapability.bitsPerSample,
|
||||
aptx_data.bitsPerSample) &&
|
||||
ContainedInVector(kDefaultOffloadAptxCapability.channelMode,
|
||||
aptx_data.channelMode)) {
|
||||
return true;
|
||||
}
|
||||
LOG(WARNING) << __func__
|
||||
<< ": Unsupported CodecSpecific=" << codec_specific.toString();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BluetoothAudioCodecs::IsOffloadAptxHdConfigurationValid(
|
||||
const CodecConfiguration::CodecSpecific& codec_specific) {
|
||||
if (codec_specific.getTag() !=
|
||||
CodecConfiguration::CodecSpecific::aptxConfig) {
|
||||
LOG(WARNING) << __func__
|
||||
<< ": Invalid CodecSpecific=" << codec_specific.toString();
|
||||
return false;
|
||||
}
|
||||
const AptxConfiguration aptx_data =
|
||||
codec_specific.get<CodecConfiguration::CodecSpecific::aptxConfig>();
|
||||
|
||||
if (ContainedInVector(kDefaultOffloadAptxHdCapability.sampleRateHz,
|
||||
aptx_data.sampleRateHz) &&
|
||||
ContainedInVector(kDefaultOffloadAptxHdCapability.bitsPerSample,
|
||||
aptx_data.bitsPerSample) &&
|
||||
ContainedInVector(kDefaultOffloadAptxHdCapability.channelMode,
|
||||
aptx_data.channelMode)) {
|
||||
return true;
|
||||
}
|
||||
LOG(WARNING) << __func__
|
||||
<< ": Unsupported CodecSpecific=" << codec_specific.toString();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BluetoothAudioCodecs::IsOffloadLc3ConfigurationValid(
|
||||
const CodecConfiguration::CodecSpecific& codec_specific) {
|
||||
if (codec_specific.getTag() != CodecConfiguration::CodecSpecific::lc3Config) {
|
||||
LOG(WARNING) << __func__
|
||||
<< ": Invalid CodecSpecific=" << codec_specific.toString();
|
||||
return false;
|
||||
}
|
||||
const Lc3Configuration lc3_data =
|
||||
codec_specific.get<CodecConfiguration::CodecSpecific::lc3Config>();
|
||||
|
||||
if (ContainedInVector(kDefaultOffloadLc3Capability.samplingFrequencyHz,
|
||||
lc3_data.samplingFrequencyHz) &&
|
||||
ContainedInVector(kDefaultOffloadLc3Capability.frameDurationUs,
|
||||
lc3_data.frameDurationUs) &&
|
||||
ContainedInVector(kDefaultOffloadLc3Capability.channelMode,
|
||||
lc3_data.channelMode)) {
|
||||
return true;
|
||||
}
|
||||
LOG(WARNING) << __func__
|
||||
<< ": Unsupported CodecSpecific=" << codec_specific.toString();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BluetoothAudioCodecs::IsOffloadLeAudioConfigurationValid(
|
||||
const SessionType& session_type, const LeAudioConfiguration&) {
|
||||
if (session_type !=
|
||||
SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH &&
|
||||
session_type !=
|
||||
SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<PcmCapabilities>
|
||||
BluetoothAudioCodecs::GetSoftwarePcmCapabilities() {
|
||||
return {kDefaultSoftwarePcmCapabilities};
|
||||
}
|
||||
|
||||
std::vector<CodecCapabilities>
|
||||
BluetoothAudioCodecs::GetA2dpOffloadCodecCapabilities(
|
||||
const SessionType& session_type) {
|
||||
if (session_type != SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
|
||||
return {};
|
||||
}
|
||||
std::vector<CodecCapabilities> offload_a2dp_codec_capabilities =
|
||||
kDefaultOffloadA2dpCodecCapabilities;
|
||||
for (auto& codec_capability : offload_a2dp_codec_capabilities) {
|
||||
switch (codec_capability.codecType) {
|
||||
case CodecType::SBC:
|
||||
codec_capability.capabilities
|
||||
.set<CodecCapabilities::Capabilities::sbcCapabilities>(
|
||||
kDefaultOffloadSbcCapability);
|
||||
break;
|
||||
case CodecType::AAC:
|
||||
codec_capability.capabilities
|
||||
.set<CodecCapabilities::Capabilities::aacCapabilities>(
|
||||
kDefaultOffloadAacCapability);
|
||||
break;
|
||||
case CodecType::LDAC:
|
||||
codec_capability.capabilities
|
||||
.set<CodecCapabilities::Capabilities::ldacCapabilities>(
|
||||
kDefaultOffloadLdacCapability);
|
||||
break;
|
||||
case CodecType::APTX:
|
||||
codec_capability.capabilities
|
||||
.set<CodecCapabilities::Capabilities::aptxCapabilities>(
|
||||
kDefaultOffloadAptxCapability);
|
||||
break;
|
||||
case CodecType::APTX_HD:
|
||||
codec_capability.capabilities
|
||||
.set<CodecCapabilities::Capabilities::aptxCapabilities>(
|
||||
kDefaultOffloadAptxHdCapability);
|
||||
break;
|
||||
case CodecType::LC3:
|
||||
codec_capability.capabilities
|
||||
.set<CodecCapabilities::Capabilities::lc3Capabilities>(
|
||||
kDefaultOffloadLc3Capability);
|
||||
break;
|
||||
case CodecType::UNKNOWN:
|
||||
codec_capability = {};
|
||||
break;
|
||||
}
|
||||
}
|
||||
return offload_a2dp_codec_capabilities;
|
||||
}
|
||||
|
||||
bool BluetoothAudioCodecs::IsSoftwarePcmConfigurationValid(
|
||||
const PcmConfiguration& pcm_config) {
|
||||
if (ContainedInVector(kDefaultSoftwarePcmCapabilities.sampleRateHz,
|
||||
pcm_config.sampleRateHz) &&
|
||||
ContainedInVector(kDefaultSoftwarePcmCapabilities.bitsPerSample,
|
||||
pcm_config.bitsPerSample) &&
|
||||
ContainedInVector(kDefaultSoftwarePcmCapabilities.channelMode,
|
||||
pcm_config.channelMode)
|
||||
// data interval is not checked for now
|
||||
// && pcm_config.dataIntervalUs != 0
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
LOG(WARNING) << __func__
|
||||
<< ": Unsupported CodecSpecific=" << pcm_config.toString();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BluetoothAudioCodecs::IsOffloadCodecConfigurationValid(
|
||||
const SessionType& session_type, const CodecConfiguration& codec_config) {
|
||||
if (session_type != SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
|
||||
LOG(ERROR) << __func__
|
||||
<< ": Invalid SessionType=" << toString(session_type);
|
||||
return false;
|
||||
}
|
||||
const CodecConfiguration::CodecSpecific& codec_specific = codec_config.config;
|
||||
switch (codec_config.codecType) {
|
||||
case CodecType::SBC:
|
||||
if (IsOffloadSbcConfigurationValid(codec_specific)) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case CodecType::AAC:
|
||||
if (IsOffloadAacConfigurationValid(codec_specific)) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case CodecType::LDAC:
|
||||
if (IsOffloadLdacConfigurationValid(codec_specific)) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case CodecType::APTX:
|
||||
if (IsOffloadAptxConfigurationValid(codec_specific)) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case CodecType::APTX_HD:
|
||||
if (IsOffloadAptxHdConfigurationValid(codec_specific)) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case CodecType::LC3:
|
||||
if (IsOffloadLc3ConfigurationValid(codec_specific)) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case CodecType::UNKNOWN:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
UnicastCapability composeUnicastLc3Capability(
|
||||
AudioLocation audioLocation, uint8_t deviceCnt, uint8_t channelCount,
|
||||
const Lc3Capabilities& capability) {
|
||||
return {
|
||||
.codecType = CodecType::LC3,
|
||||
.supportedChannel = audioLocation,
|
||||
.deviceCount = deviceCnt,
|
||||
.channelCountPerDevice = channelCount,
|
||||
.leAudioCodecCapabilities =
|
||||
UnicastCapability::LeAudioCodecCapabilities(capability),
|
||||
};
|
||||
}
|
||||
|
||||
std::vector<LeAudioCodecCapabilitiesSetting>
|
||||
BluetoothAudioCodecs::GetLeAudioOffloadCodecCapabilities(
|
||||
const SessionType& session_type) {
|
||||
if (session_type !=
|
||||
SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH &&
|
||||
session_type !=
|
||||
SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
|
||||
return std::vector<LeAudioCodecCapabilitiesSetting>(0);
|
||||
}
|
||||
|
||||
if (kDefaultOffloadLeAudioCapabilities.empty()) {
|
||||
for (auto [audioLocation, deviceCnt, channelCount] :
|
||||
supportedDeviceSetting) {
|
||||
for (auto capability : supportedLc3CapabilityList) {
|
||||
UnicastCapability lc3Capability = composeUnicastLc3Capability(
|
||||
audioLocation, deviceCnt, channelCount, capability);
|
||||
UnicastCapability lc3MonoDecodeCapability =
|
||||
composeUnicastLc3Capability(monoAudio, 1, 1, capability);
|
||||
|
||||
// Adds the capability for encode only
|
||||
kDefaultOffloadLeAudioCapabilities.push_back(
|
||||
{.unicastEncodeCapability = lc3Capability,
|
||||
.unicastDecodeCapability = kInvalidUnicastCapability,
|
||||
.broadcastCapability = kInvalidBroadcastCapability});
|
||||
|
||||
// Adds the capability for decode only
|
||||
kDefaultOffloadLeAudioCapabilities.push_back(
|
||||
{.unicastEncodeCapability = kInvalidUnicastCapability,
|
||||
.unicastDecodeCapability = lc3Capability,
|
||||
.broadcastCapability = kInvalidBroadcastCapability});
|
||||
|
||||
// Adds the capability for the case that encode and decode exist at the
|
||||
// same time
|
||||
kDefaultOffloadLeAudioCapabilities.push_back(
|
||||
{.unicastEncodeCapability = lc3Capability,
|
||||
.unicastDecodeCapability = lc3MonoDecodeCapability,
|
||||
.broadcastCapability = kInvalidBroadcastCapability});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return kDefaultOffloadLeAudioCapabilities;
|
||||
}
|
||||
|
||||
} // namespace audio
|
||||
} // namespace bluetooth
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
||||
88
bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.h
Normal file
88
bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.h
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <aidl/android/hardware/bluetooth/audio/CodecCapabilities.h>
|
||||
#include <aidl/android/hardware/bluetooth/audio/CodecConfiguration.h>
|
||||
#include <aidl/android/hardware/bluetooth/audio/Lc3Configuration.h>
|
||||
#include <aidl/android/hardware/bluetooth/audio/LeAudioCodecCapabilitiesSetting.h>
|
||||
#include <aidl/android/hardware/bluetooth/audio/LeAudioConfiguration.h>
|
||||
#include <aidl/android/hardware/bluetooth/audio/PcmCapabilities.h>
|
||||
#include <aidl/android/hardware/bluetooth/audio/PcmConfiguration.h>
|
||||
#include <aidl/android/hardware/bluetooth/audio/SessionType.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace bluetooth {
|
||||
namespace audio {
|
||||
|
||||
class BluetoothAudioCodecs {
|
||||
public:
|
||||
static std::vector<PcmCapabilities> GetSoftwarePcmCapabilities();
|
||||
static std::vector<CodecCapabilities> GetA2dpOffloadCodecCapabilities(
|
||||
const SessionType& session_type);
|
||||
|
||||
static bool IsSoftwarePcmConfigurationValid(
|
||||
const PcmConfiguration& pcm_config);
|
||||
static bool IsOffloadCodecConfigurationValid(
|
||||
const SessionType& session_type, const CodecConfiguration& codec_config);
|
||||
|
||||
static bool IsOffloadLeAudioConfigurationValid(
|
||||
const SessionType& session_type, const Lc3Configuration& codec_config);
|
||||
|
||||
static bool IsOffloadLeAudioConfigurationValid(
|
||||
const SessionType& session_type,
|
||||
const LeAudioConfiguration& codec_config);
|
||||
|
||||
static std::vector<LeAudioCodecCapabilitiesSetting>
|
||||
GetLeAudioOffloadCodecCapabilities(const SessionType& session_type);
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
struct identity {
|
||||
typedef T type;
|
||||
};
|
||||
template <class T>
|
||||
static bool ContainedInVector(const std::vector<T>& vector,
|
||||
const typename identity<T>::type& target);
|
||||
template <class T>
|
||||
static bool ContainedInBitmask(const T& bitmask, const T& target);
|
||||
static bool IsSingleBit(uint32_t bitmasks, uint32_t bitfield);
|
||||
static bool IsOffloadSbcConfigurationValid(
|
||||
const CodecConfiguration::CodecSpecific& codec_specific);
|
||||
static bool IsOffloadAacConfigurationValid(
|
||||
const CodecConfiguration::CodecSpecific& codec_specific);
|
||||
static bool IsOffloadLdacConfigurationValid(
|
||||
const CodecConfiguration::CodecSpecific& codec_specific);
|
||||
static bool IsOffloadAptxConfigurationValid(
|
||||
const CodecConfiguration::CodecSpecific& codec_specific);
|
||||
static bool IsOffloadAptxHdConfigurationValid(
|
||||
const CodecConfiguration::CodecSpecific& codec_specific);
|
||||
static bool IsOffloadLc3ConfigurationValid(
|
||||
const CodecConfiguration::CodecSpecific& codec_specific);
|
||||
static bool IsOffloadLeAudioConfigurationValid(
|
||||
const SessionType& session_type, const LeAudioCodecConfiguration&);
|
||||
};
|
||||
|
||||
} // namespace audio
|
||||
} // namespace bluetooth
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
||||
581
bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
Normal file
581
bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
Normal file
@@ -0,0 +1,581 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* 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 <sys/types.h>
|
||||
#define LOG_TAG "BTAudioSessionAidl"
|
||||
|
||||
#include <android-base/logging.h>
|
||||
#include <android-base/stringprintf.h>
|
||||
#include <android/binder_manager.h>
|
||||
|
||||
#include "BluetoothAudioSession.h"
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace bluetooth {
|
||||
namespace audio {
|
||||
|
||||
static constexpr int kFmqSendTimeoutMs = 1000; // 1000 ms timeout for sending
|
||||
static constexpr int kFmqReceiveTimeoutMs =
|
||||
1000; // 1000 ms timeout for receiving
|
||||
static constexpr int kWritePollMs = 1; // polled non-blocking interval
|
||||
static constexpr int kReadPollMs = 1; // polled non-blocking interval
|
||||
|
||||
const CodecConfiguration BluetoothAudioSession::kInvalidCodecConfiguration = {};
|
||||
const LeAudioConfiguration kInvalidLeAudioConfiguration = {};
|
||||
AudioConfiguration BluetoothAudioSession::invalidSoftwareAudioConfiguration =
|
||||
{};
|
||||
AudioConfiguration BluetoothAudioSession::invalidOffloadAudioConfiguration = {};
|
||||
AudioConfiguration BluetoothAudioSession::invalidLeOffloadAudioConfig = {};
|
||||
|
||||
BluetoothAudioSession::BluetoothAudioSession(const SessionType& session_type)
|
||||
: session_type_(session_type), stack_iface_(nullptr), data_mq_(nullptr) {
|
||||
invalidSoftwareAudioConfiguration.set<AudioConfiguration::pcmConfig>(
|
||||
kInvalidPcmConfiguration);
|
||||
invalidOffloadAudioConfiguration.set<AudioConfiguration::a2dpConfig>(
|
||||
kInvalidCodecConfiguration);
|
||||
invalidLeOffloadAudioConfig.set<AudioConfiguration::leAudioConfig>(
|
||||
kInvalidLeAudioConfiguration);
|
||||
}
|
||||
|
||||
/***
|
||||
*
|
||||
* Callback methods
|
||||
*
|
||||
***/
|
||||
|
||||
void BluetoothAudioSession::OnSessionStarted(
|
||||
const std::shared_ptr<IBluetoothAudioPort> stack_iface,
|
||||
const DataMQDesc* mq_desc, const AudioConfiguration& audio_config) {
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex_);
|
||||
if (stack_iface == nullptr) {
|
||||
LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type_)
|
||||
<< ", IBluetoothAudioPort Invalid";
|
||||
} else if (!UpdateAudioConfig(audio_config)) {
|
||||
LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type_)
|
||||
<< ", AudioConfiguration=" << audio_config.toString()
|
||||
<< " Invalid";
|
||||
} else if (!UpdateDataPath(mq_desc)) {
|
||||
LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type_)
|
||||
<< " MqDescriptor Invalid";
|
||||
if (session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
|
||||
audio_config_ = std::make_unique<AudioConfiguration>(
|
||||
invalidOffloadAudioConfiguration);
|
||||
} else {
|
||||
audio_config_ = std::make_unique<AudioConfiguration>(
|
||||
invalidSoftwareAudioConfiguration);
|
||||
}
|
||||
} else {
|
||||
stack_iface_ = stack_iface;
|
||||
LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
|
||||
<< ", AudioConfiguration=" << audio_config.toString();
|
||||
ReportSessionStatus();
|
||||
}
|
||||
}
|
||||
|
||||
void BluetoothAudioSession::OnSessionEnded() {
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex_);
|
||||
bool toggled = IsSessionReady();
|
||||
LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_);
|
||||
if (session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
|
||||
audio_config_ =
|
||||
std::make_unique<AudioConfiguration>(invalidOffloadAudioConfiguration);
|
||||
} else {
|
||||
audio_config_ =
|
||||
std::make_unique<AudioConfiguration>(invalidSoftwareAudioConfiguration);
|
||||
}
|
||||
stack_iface_ = nullptr;
|
||||
UpdateDataPath(nullptr);
|
||||
if (toggled) {
|
||||
ReportSessionStatus();
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
*
|
||||
* Util methods
|
||||
*
|
||||
***/
|
||||
|
||||
const AudioConfiguration& BluetoothAudioSession::GetAudioConfig() {
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex_);
|
||||
if (!IsSessionReady()) {
|
||||
if (session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
|
||||
return invalidOffloadAudioConfiguration;
|
||||
} else {
|
||||
return invalidSoftwareAudioConfiguration;
|
||||
}
|
||||
switch (session_type_) {
|
||||
case SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH:
|
||||
return invalidOffloadAudioConfiguration;
|
||||
case SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH:
|
||||
case SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH:
|
||||
return invalidLeOffloadAudioConfig;
|
||||
default:
|
||||
return invalidSoftwareAudioConfiguration;
|
||||
}
|
||||
}
|
||||
return *audio_config_;
|
||||
}
|
||||
|
||||
void BluetoothAudioSession::ReportAudioConfigChanged(
|
||||
const AudioConfiguration& audio_config) {
|
||||
if (session_type_ !=
|
||||
SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH &&
|
||||
session_type_ !=
|
||||
SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
|
||||
return;
|
||||
}
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex_);
|
||||
audio_config_ = std::make_unique<AudioConfiguration>(audio_config);
|
||||
if (observers_.empty()) {
|
||||
LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_)
|
||||
<< " has NO port state observer";
|
||||
return;
|
||||
}
|
||||
for (auto& observer : observers_) {
|
||||
uint16_t cookie = observer.first;
|
||||
std::shared_ptr<struct PortStatusCallbacks> cb = observer.second;
|
||||
LOG(INFO) << __func__ << " for SessionType=" << toString(session_type_)
|
||||
<< ", bluetooth_audio=0x"
|
||||
<< ::android::base::StringPrintf("%04x", cookie);
|
||||
if (cb->audio_configuration_changed_cb_ != nullptr) {
|
||||
cb->audio_configuration_changed_cb_(cookie);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool BluetoothAudioSession::IsSessionReady() {
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex_);
|
||||
|
||||
bool is_mq_valid =
|
||||
(session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
|
||||
session_type_ ==
|
||||
SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
|
||||
session_type_ ==
|
||||
SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH ||
|
||||
(data_mq_ != nullptr && data_mq_->isValid()));
|
||||
return stack_iface_ != nullptr && is_mq_valid;
|
||||
}
|
||||
|
||||
/***
|
||||
*
|
||||
* Status callback methods
|
||||
*
|
||||
***/
|
||||
|
||||
uint16_t BluetoothAudioSession::RegisterStatusCback(
|
||||
const PortStatusCallbacks& callbacks) {
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex_);
|
||||
uint16_t cookie = ObserversCookieGetInitValue(session_type_);
|
||||
uint16_t cookie_upper_bound = ObserversCookieGetUpperBound(session_type_);
|
||||
|
||||
while (cookie < cookie_upper_bound) {
|
||||
if (observers_.find(cookie) == observers_.end()) {
|
||||
break;
|
||||
}
|
||||
++cookie;
|
||||
}
|
||||
if (cookie >= cookie_upper_bound) {
|
||||
LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type_)
|
||||
<< " has " << observers_.size()
|
||||
<< " observers already (No Resource)";
|
||||
return kObserversCookieUndefined;
|
||||
}
|
||||
std::shared_ptr<PortStatusCallbacks> cb =
|
||||
std::make_shared<PortStatusCallbacks>();
|
||||
*cb = callbacks;
|
||||
observers_[cookie] = cb;
|
||||
return cookie;
|
||||
}
|
||||
|
||||
void BluetoothAudioSession::UnregisterStatusCback(uint16_t cookie) {
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex_);
|
||||
if (observers_.erase(cookie) != 1) {
|
||||
LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_)
|
||||
<< " no such provider=0x"
|
||||
<< ::android::base::StringPrintf("%04x", cookie);
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
*
|
||||
* Stream methods
|
||||
*
|
||||
***/
|
||||
|
||||
bool BluetoothAudioSession::StartStream() {
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex_);
|
||||
if (!IsSessionReady()) {
|
||||
LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
|
||||
<< " has NO session";
|
||||
return false;
|
||||
}
|
||||
auto hal_retval = stack_iface_->startStream();
|
||||
if (!hal_retval.isOk()) {
|
||||
LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
|
||||
<< toString(session_type_) << " failed";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BluetoothAudioSession::SuspendStream() {
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex_);
|
||||
if (!IsSessionReady()) {
|
||||
LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
|
||||
<< " has NO session";
|
||||
return false;
|
||||
}
|
||||
auto hal_retval = stack_iface_->suspendStream();
|
||||
if (!hal_retval.isOk()) {
|
||||
LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
|
||||
<< toString(session_type_) << " failed";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void BluetoothAudioSession::StopStream() {
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex_);
|
||||
if (!IsSessionReady()) {
|
||||
return;
|
||||
}
|
||||
auto hal_retval = stack_iface_->stopStream();
|
||||
if (!hal_retval.isOk()) {
|
||||
LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
|
||||
<< toString(session_type_) << " failed";
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
*
|
||||
* Private methods
|
||||
*
|
||||
***/
|
||||
|
||||
bool BluetoothAudioSession::UpdateDataPath(const DataMQDesc* mq_desc) {
|
||||
if (mq_desc == nullptr) {
|
||||
// usecase of reset by nullptr
|
||||
data_mq_ = nullptr;
|
||||
return true;
|
||||
}
|
||||
std::unique_ptr<DataMQ> temp_mq;
|
||||
temp_mq.reset(new DataMQ(*mq_desc));
|
||||
if (!temp_mq || !temp_mq->isValid()) {
|
||||
data_mq_ = nullptr;
|
||||
return false;
|
||||
}
|
||||
data_mq_ = std::move(temp_mq);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BluetoothAudioSession::UpdateAudioConfig(
|
||||
const AudioConfiguration& audio_config) {
|
||||
bool is_software_session =
|
||||
(session_type_ == SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH ||
|
||||
session_type_ == SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH ||
|
||||
session_type_ == SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH ||
|
||||
session_type_ == SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH);
|
||||
bool is_offload_a2dp_session =
|
||||
(session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH);
|
||||
bool is_offload_le_audio_session =
|
||||
(session_type_ ==
|
||||
SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
|
||||
session_type_ ==
|
||||
SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH);
|
||||
auto audio_config_tag = audio_config.getTag();
|
||||
bool is_software_audio_config =
|
||||
(is_software_session &&
|
||||
audio_config_tag == AudioConfiguration::pcmConfig);
|
||||
bool is_a2dp_offload_audio_config =
|
||||
(is_offload_a2dp_session &&
|
||||
audio_config_tag == AudioConfiguration::a2dpConfig);
|
||||
bool is_le_audio_offload_audio_config =
|
||||
(is_offload_le_audio_session &&
|
||||
audio_config_tag == AudioConfiguration::leAudioConfig);
|
||||
if (!is_software_audio_config && !is_a2dp_offload_audio_config &&
|
||||
!is_le_audio_offload_audio_config) {
|
||||
return false;
|
||||
}
|
||||
audio_config_ = std::make_unique<AudioConfiguration>(audio_config);
|
||||
return true;
|
||||
}
|
||||
|
||||
void BluetoothAudioSession::ReportSessionStatus() {
|
||||
// This is locked already by OnSessionStarted / OnSessionEnded
|
||||
if (observers_.empty()) {
|
||||
LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
|
||||
<< " has NO port state observer";
|
||||
return;
|
||||
}
|
||||
for (auto& observer : observers_) {
|
||||
uint16_t cookie = observer.first;
|
||||
std::shared_ptr<PortStatusCallbacks> callback = observer.second;
|
||||
LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
|
||||
<< " notify to bluetooth_audio=0x"
|
||||
<< ::android::base::StringPrintf("%04x", cookie);
|
||||
callback->session_changed_cb_(cookie);
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
*
|
||||
* PCM methods
|
||||
*
|
||||
***/
|
||||
|
||||
size_t BluetoothAudioSession::OutWritePcmData(const void* buffer,
|
||||
size_t bytes) {
|
||||
if (buffer == nullptr || bytes <= 0) {
|
||||
return 0;
|
||||
}
|
||||
size_t total_written = 0;
|
||||
int timeout_ms = kFmqSendTimeoutMs;
|
||||
do {
|
||||
std::unique_lock<std::recursive_mutex> lock(mutex_);
|
||||
if (!IsSessionReady()) {
|
||||
break;
|
||||
}
|
||||
size_t num_bytes_to_write = data_mq_->availableToWrite();
|
||||
if (num_bytes_to_write) {
|
||||
if (num_bytes_to_write > (bytes - total_written)) {
|
||||
num_bytes_to_write = bytes - total_written;
|
||||
}
|
||||
|
||||
if (!data_mq_->write(
|
||||
static_cast<const MQDataType*>(buffer) + total_written,
|
||||
num_bytes_to_write)) {
|
||||
LOG(ERROR) << "FMQ datapath writing " << total_written << "/" << bytes
|
||||
<< " failed";
|
||||
return total_written;
|
||||
}
|
||||
total_written += num_bytes_to_write;
|
||||
} else if (timeout_ms >= kWritePollMs) {
|
||||
lock.unlock();
|
||||
usleep(kWritePollMs * 1000);
|
||||
timeout_ms -= kWritePollMs;
|
||||
} else {
|
||||
LOG(DEBUG) << "Data " << total_written << "/" << bytes << " overflow "
|
||||
<< (kFmqSendTimeoutMs - timeout_ms) << " ms";
|
||||
return total_written;
|
||||
}
|
||||
} while (total_written < bytes);
|
||||
return total_written;
|
||||
}
|
||||
|
||||
size_t BluetoothAudioSession::InReadPcmData(void* buffer, size_t bytes) {
|
||||
if (buffer == nullptr || bytes <= 0) {
|
||||
return 0;
|
||||
}
|
||||
size_t total_read = 0;
|
||||
int timeout_ms = kFmqReceiveTimeoutMs;
|
||||
do {
|
||||
std::unique_lock<std::recursive_mutex> lock(mutex_);
|
||||
if (!IsSessionReady()) {
|
||||
break;
|
||||
}
|
||||
size_t num_bytes_to_read = data_mq_->availableToRead();
|
||||
if (num_bytes_to_read) {
|
||||
if (num_bytes_to_read > (bytes - total_read)) {
|
||||
num_bytes_to_read = bytes - total_read;
|
||||
}
|
||||
if (!data_mq_->read(static_cast<MQDataType*>(buffer) + total_read,
|
||||
num_bytes_to_read)) {
|
||||
LOG(ERROR) << "FMQ datapath reading " << total_read << "/" << bytes
|
||||
<< " failed";
|
||||
return total_read;
|
||||
}
|
||||
total_read += num_bytes_to_read;
|
||||
} else if (timeout_ms >= kReadPollMs) {
|
||||
lock.unlock();
|
||||
usleep(kReadPollMs * 1000);
|
||||
timeout_ms -= kReadPollMs;
|
||||
continue;
|
||||
} else {
|
||||
LOG(DEBUG) << "Data " << total_read << "/" << bytes << " overflow "
|
||||
<< (kFmqReceiveTimeoutMs - timeout_ms) << " ms";
|
||||
return total_read;
|
||||
}
|
||||
} while (total_read < bytes);
|
||||
return total_read;
|
||||
}
|
||||
|
||||
/***
|
||||
*
|
||||
* Other methods
|
||||
*
|
||||
***/
|
||||
|
||||
void BluetoothAudioSession::ReportControlStatus(bool start_resp,
|
||||
BluetoothAudioStatus status) {
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex_);
|
||||
if (observers_.empty()) {
|
||||
LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_)
|
||||
<< " has NO port state observer";
|
||||
return;
|
||||
}
|
||||
for (auto& observer : observers_) {
|
||||
uint16_t cookie = observer.first;
|
||||
std::shared_ptr<PortStatusCallbacks> callback = observer.second;
|
||||
LOG(INFO) << __func__ << " - status=" << toString(status)
|
||||
<< " for SessionType=" << toString(session_type_)
|
||||
<< ", bluetooth_audio=0x"
|
||||
<< ::android::base::StringPrintf("%04x", cookie)
|
||||
<< (start_resp ? " started" : " suspended");
|
||||
callback->control_result_cb_(cookie, start_resp, status);
|
||||
}
|
||||
}
|
||||
|
||||
bool BluetoothAudioSession::GetPresentationPosition(
|
||||
PresentationPosition& presentation_position) {
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex_);
|
||||
if (!IsSessionReady()) {
|
||||
LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
|
||||
<< " has NO session";
|
||||
return false;
|
||||
}
|
||||
bool retval = false;
|
||||
|
||||
if (!stack_iface_->getPresentationPosition(&presentation_position).isOk()) {
|
||||
LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
|
||||
<< toString(session_type_) << " failed";
|
||||
return false;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
void BluetoothAudioSession::UpdateSourceMetadata(
|
||||
const struct source_metadata& source_metadata) {
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex_);
|
||||
if (!IsSessionReady()) {
|
||||
LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
|
||||
<< " has NO session";
|
||||
return;
|
||||
}
|
||||
|
||||
ssize_t track_count = source_metadata.track_count;
|
||||
LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_) << ","
|
||||
<< track_count << " track(s)";
|
||||
if (session_type_ == SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH ||
|
||||
session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
|
||||
return;
|
||||
}
|
||||
|
||||
SourceMetadata hal_source_metadata;
|
||||
hal_source_metadata.tracks.resize(track_count);
|
||||
for (int i = 0; i < track_count; i++) {
|
||||
hal_source_metadata.tracks[i].usage =
|
||||
static_cast<media::audio::common::AudioUsage>(
|
||||
source_metadata.tracks[i].usage);
|
||||
hal_source_metadata.tracks[i].contentType =
|
||||
static_cast<media::audio::common::AudioContentType>(
|
||||
source_metadata.tracks[i].content_type);
|
||||
hal_source_metadata.tracks[i].gain = source_metadata.tracks[i].gain;
|
||||
LOG(VERBOSE) << __func__ << " - SessionType=" << toString(session_type_)
|
||||
<< ", usage=" << toString(hal_source_metadata.tracks[i].usage)
|
||||
<< ", content="
|
||||
<< toString(hal_source_metadata.tracks[i].contentType)
|
||||
<< ", gain=" << hal_source_metadata.tracks[i].gain;
|
||||
}
|
||||
|
||||
auto hal_retval = stack_iface_->updateSourceMetadata(hal_source_metadata);
|
||||
if (!hal_retval.isOk()) {
|
||||
LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
|
||||
<< toString(session_type_) << " failed";
|
||||
}
|
||||
}
|
||||
|
||||
void BluetoothAudioSession::UpdateSinkMetadata(
|
||||
const struct sink_metadata& sink_metadata) {
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex_);
|
||||
if (!IsSessionReady()) {
|
||||
LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
|
||||
<< " has NO session";
|
||||
return;
|
||||
}
|
||||
|
||||
ssize_t track_count = sink_metadata.track_count;
|
||||
LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_) << ","
|
||||
<< track_count << " track(s)";
|
||||
if (session_type_ == SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH ||
|
||||
session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
|
||||
return;
|
||||
}
|
||||
|
||||
SinkMetadata hal_sink_metadata;
|
||||
hal_sink_metadata.tracks.resize(track_count);
|
||||
for (int i = 0; i < track_count; i++) {
|
||||
hal_sink_metadata.tracks[i].source =
|
||||
static_cast<media::audio::common::AudioSource>(
|
||||
sink_metadata.tracks[i].source);
|
||||
hal_sink_metadata.tracks[i].gain = sink_metadata.tracks[i].gain;
|
||||
LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
|
||||
<< ", source=" << sink_metadata.tracks[i].source
|
||||
<< ", dest_device=" << sink_metadata.tracks[i].dest_device
|
||||
<< ", gain=" << sink_metadata.tracks[i].gain
|
||||
<< ", dest_device_address="
|
||||
<< sink_metadata.tracks[i].dest_device_address;
|
||||
}
|
||||
|
||||
auto hal_retval = stack_iface_->updateSinkMetadata(hal_sink_metadata);
|
||||
if (!hal_retval.isOk()) {
|
||||
LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
|
||||
<< toString(session_type_) << " failed";
|
||||
}
|
||||
}
|
||||
|
||||
bool BluetoothAudioSession::IsAidlAvailable() {
|
||||
if (is_aidl_checked) return is_aidl_available;
|
||||
is_aidl_available =
|
||||
(AServiceManager_checkService(
|
||||
kDefaultAudioProviderFactoryInterface.c_str()) != nullptr);
|
||||
is_aidl_checked = true;
|
||||
return is_aidl_available;
|
||||
}
|
||||
|
||||
/***
|
||||
*
|
||||
* BluetoothAudioSessionInstance
|
||||
*
|
||||
***/
|
||||
std::mutex BluetoothAudioSessionInstance::mutex_;
|
||||
std::unordered_map<SessionType, std::shared_ptr<BluetoothAudioSession>>
|
||||
BluetoothAudioSessionInstance::sessions_map_;
|
||||
|
||||
std::shared_ptr<BluetoothAudioSession>
|
||||
BluetoothAudioSessionInstance::GetSessionInstance(
|
||||
const SessionType& session_type) {
|
||||
std::lock_guard<std::mutex> guard(mutex_);
|
||||
|
||||
if (!sessions_map_.empty()) {
|
||||
auto entry = sessions_map_.find(session_type);
|
||||
if (entry != sessions_map_.end()) {
|
||||
return entry->second;
|
||||
}
|
||||
}
|
||||
std::shared_ptr<BluetoothAudioSession> session_ptr =
|
||||
std::make_shared<BluetoothAudioSession>(session_type);
|
||||
sessions_map_[session_type] = session_ptr;
|
||||
return session_ptr;
|
||||
}
|
||||
|
||||
} // namespace audio
|
||||
} // namespace bluetooth
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
||||
227
bluetooth/audio/utils/aidl_session/BluetoothAudioSession.h
Normal file
227
bluetooth/audio/utils/aidl_session/BluetoothAudioSession.h
Normal file
@@ -0,0 +1,227 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <aidl/android/hardware/audio/common/SinkMetadata.h>
|
||||
#include <aidl/android/hardware/audio/common/SourceMetadata.h>
|
||||
#include <aidl/android/hardware/bluetooth/audio/IBluetoothAudioProvider.h>
|
||||
#include <aidl/android/hardware/bluetooth/audio/IBluetoothAudioProviderFactory.h>
|
||||
#include <aidl/android/hardware/bluetooth/audio/SessionType.h>
|
||||
#include <fmq/AidlMessageQueue.h>
|
||||
#include <hardware/audio.h>
|
||||
|
||||
#include <mutex>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace bluetooth {
|
||||
namespace audio {
|
||||
|
||||
using ::aidl::android::hardware::common::fmq::MQDescriptor;
|
||||
using ::aidl::android::hardware::common::fmq::SynchronizedReadWrite;
|
||||
using ::android::AidlMessageQueue;
|
||||
|
||||
using ::aidl::android::hardware::audio::common::SinkMetadata;
|
||||
using ::aidl::android::hardware::audio::common::SourceMetadata;
|
||||
|
||||
using MQDataType = int8_t;
|
||||
using MQDataMode = SynchronizedReadWrite;
|
||||
using DataMQ = AidlMessageQueue<MQDataType, MQDataMode>;
|
||||
using DataMQDesc =
|
||||
::aidl::android::hardware::common::fmq::MQDescriptor<MQDataType,
|
||||
MQDataMode>;
|
||||
|
||||
static constexpr uint16_t kObserversCookieSize = 0x0010; // 0x0000 ~ 0x000f
|
||||
static constexpr uint16_t kObserversCookieUndefined =
|
||||
(static_cast<uint16_t>(SessionType::UNKNOWN) << 8 & 0xff00);
|
||||
inline SessionType ObserversCookieGetSessionType(uint16_t cookie) {
|
||||
return static_cast<SessionType>(cookie >> 8 & 0x00ff);
|
||||
}
|
||||
inline uint16_t ObserversCookieGetInitValue(SessionType session_type) {
|
||||
return (static_cast<uint16_t>(session_type) << 8 & 0xff00);
|
||||
}
|
||||
inline uint16_t ObserversCookieGetUpperBound(SessionType session_type) {
|
||||
return (static_cast<uint16_t>(session_type) << 8 & 0xff00) +
|
||||
kObserversCookieSize;
|
||||
}
|
||||
|
||||
/***
|
||||
* This presents the callbacks of started / suspended and session changed,
|
||||
* and the bluetooth_audio module uses to receive the status notification
|
||||
***/
|
||||
struct PortStatusCallbacks {
|
||||
/***
|
||||
* control_result_cb_ - when the Bluetooth stack reports results of
|
||||
* streamStarted or streamSuspended, the BluetoothAudioProvider will invoke
|
||||
* this callback to report to the bluetooth_audio module.
|
||||
* @param: cookie - indicates which bluetooth_audio output should handle
|
||||
* @param: start_resp - this report is for startStream or not
|
||||
* @param: status - the result of startStream
|
||||
***/
|
||||
std::function<void(uint16_t cookie, bool start_resp,
|
||||
BluetoothAudioStatus status)>
|
||||
control_result_cb_;
|
||||
/***
|
||||
* session_changed_cb_ - when the Bluetooth stack start / end session, the
|
||||
* BluetoothAudioProvider will invoke this callback to notify to the
|
||||
* bluetooth_audio module.
|
||||
* @param: cookie - indicates which bluetooth_audio output should handle
|
||||
***/
|
||||
std::function<void(uint16_t cookie)> session_changed_cb_;
|
||||
/***
|
||||
* audio_configuration_changed_cb_ - when the Bluetooth stack change the audio
|
||||
* configuration, the BluetoothAudioProvider will invoke this callback to
|
||||
* notify to the bluetooth_audio module.
|
||||
* @param: cookie - indicates which bluetooth_audio output should handle
|
||||
***/
|
||||
std::function<void(uint16_t cookie)> audio_configuration_changed_cb_;
|
||||
};
|
||||
|
||||
class BluetoothAudioSession {
|
||||
public:
|
||||
BluetoothAudioSession(const SessionType& session_type);
|
||||
|
||||
/***
|
||||
* The function helps to check if this session is ready or not
|
||||
* @return: true if the Bluetooth stack has started the specified session
|
||||
***/
|
||||
bool IsSessionReady();
|
||||
|
||||
/***
|
||||
* The report function is used to report that the Bluetooth stack has started
|
||||
* this session without any failure, and will invoke session_changed_cb_ to
|
||||
* notify those registered bluetooth_audio outputs
|
||||
***/
|
||||
void OnSessionStarted(const std::shared_ptr<IBluetoothAudioPort> stack_iface,
|
||||
const DataMQDesc* mq_desc,
|
||||
const AudioConfiguration& audio_config);
|
||||
|
||||
/***
|
||||
* The report function is used to report that the Bluetooth stack has ended
|
||||
* the session, and will invoke session_changed_cb_ to notify registered
|
||||
* bluetooth_audio outputs
|
||||
***/
|
||||
void OnSessionEnded();
|
||||
|
||||
/***
|
||||
* The report function is used to report that the Bluetooth stack has notified
|
||||
* the result of startStream or suspendStream, and will invoke
|
||||
* control_result_cb_ to notify registered bluetooth_audio outputs
|
||||
***/
|
||||
void ReportControlStatus(bool start_resp, BluetoothAudioStatus status);
|
||||
|
||||
/***
|
||||
* The control function helps the bluetooth_audio module to register
|
||||
* PortStatusCallbacks
|
||||
* @return: cookie - the assigned number to this bluetooth_audio output
|
||||
***/
|
||||
uint16_t RegisterStatusCback(const PortStatusCallbacks& cbacks);
|
||||
|
||||
/***
|
||||
* The control function helps the bluetooth_audio module to unregister
|
||||
* PortStatusCallbacks
|
||||
* @param: cookie - indicates which bluetooth_audio output is
|
||||
***/
|
||||
void UnregisterStatusCback(uint16_t cookie);
|
||||
|
||||
/***
|
||||
* The control function is for the bluetooth_audio module to get the current
|
||||
* AudioConfiguration
|
||||
***/
|
||||
const AudioConfiguration& GetAudioConfig();
|
||||
|
||||
/***
|
||||
* The report function is used to report that the Bluetooth stack has notified
|
||||
* the audio configuration changed, and will invoke
|
||||
* audio_configuration_changed_cb_ to notify registered bluetooth_audio
|
||||
* outputs
|
||||
***/
|
||||
void ReportAudioConfigChanged(const AudioConfiguration& audio_config);
|
||||
|
||||
/***
|
||||
* Those control functions are for the bluetooth_audio module to start,
|
||||
* suspend, stop stream, to check position, and to update metadata.
|
||||
***/
|
||||
bool StartStream();
|
||||
bool SuspendStream();
|
||||
void StopStream();
|
||||
bool GetPresentationPosition(PresentationPosition& presentation_position);
|
||||
void UpdateSourceMetadata(const struct source_metadata& source_metadata);
|
||||
void UpdateSinkMetadata(const struct sink_metadata& sink_metadata);
|
||||
|
||||
// The control function writes stream to FMQ
|
||||
size_t OutWritePcmData(const void* buffer, size_t bytes);
|
||||
// The control function read stream from FMQ
|
||||
size_t InReadPcmData(void* buffer, size_t bytes);
|
||||
|
||||
// Return if IBluetoothAudioProviderFactory implementation existed
|
||||
static bool IsAidlAvailable();
|
||||
|
||||
static constexpr PcmConfiguration kInvalidPcmConfiguration = {};
|
||||
// can't be constexpr because of non-literal type
|
||||
static const CodecConfiguration kInvalidCodecConfiguration;
|
||||
|
||||
static AudioConfiguration invalidSoftwareAudioConfiguration;
|
||||
static AudioConfiguration invalidOffloadAudioConfiguration;
|
||||
static AudioConfiguration invalidLeOffloadAudioConfig;
|
||||
|
||||
private:
|
||||
// using recursive_mutex to allow hwbinder to re-enter again.
|
||||
std::recursive_mutex mutex_;
|
||||
SessionType session_type_;
|
||||
|
||||
// audio control path to use for both software and offloading
|
||||
std::shared_ptr<IBluetoothAudioPort> stack_iface_;
|
||||
// audio data path (FMQ) for software encoding
|
||||
std::unique_ptr<DataMQ> data_mq_;
|
||||
// audio data configuration for both software and offloading
|
||||
std::unique_ptr<AudioConfiguration> audio_config_;
|
||||
|
||||
// saving those registered bluetooth_audio's callbacks
|
||||
std::unordered_map<uint16_t, std::shared_ptr<struct PortStatusCallbacks>>
|
||||
observers_;
|
||||
|
||||
bool UpdateDataPath(const DataMQDesc* mq_desc);
|
||||
bool UpdateAudioConfig(const AudioConfiguration& audio_config);
|
||||
// invoking the registered session_changed_cb_
|
||||
void ReportSessionStatus();
|
||||
|
||||
static inline std::atomic<bool> is_aidl_checked = false;
|
||||
static inline std::atomic<bool> is_aidl_available = false;
|
||||
static inline const std::string kDefaultAudioProviderFactoryInterface =
|
||||
std::string() + IBluetoothAudioProviderFactory::descriptor + "/default";
|
||||
};
|
||||
|
||||
class BluetoothAudioSessionInstance {
|
||||
public:
|
||||
// The API is to fetch the specified session of A2DP / Hearing Aid
|
||||
static std::shared_ptr<BluetoothAudioSession> GetSessionInstance(
|
||||
const SessionType& session_type);
|
||||
|
||||
private:
|
||||
static std::mutex mutex_;
|
||||
static std::unordered_map<SessionType, std::shared_ptr<BluetoothAudioSession>>
|
||||
sessions_map_;
|
||||
};
|
||||
|
||||
} // namespace audio
|
||||
} // namespace bluetooth
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
||||
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* Copyright 2018 The Android Open Source Project
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BluetoothAudioSession.h"
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace bluetooth {
|
||||
namespace audio {
|
||||
|
||||
class BluetoothAudioSessionControl {
|
||||
public:
|
||||
/***
|
||||
* The control API helps to check if session is ready or not
|
||||
* @return: true if the Bluetooth stack has started th specified session
|
||||
***/
|
||||
static bool IsSessionReady(const SessionType& session_type) {
|
||||
std::shared_ptr<BluetoothAudioSession> session_ptr =
|
||||
BluetoothAudioSessionInstance::GetSessionInstance(session_type);
|
||||
if (session_ptr != nullptr) {
|
||||
return session_ptr->IsSessionReady();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/***
|
||||
* The control API helps the bluetooth_audio module to register
|
||||
* PortStatusCallbacks
|
||||
* @return: cookie - the assigned number to this bluetooth_audio output
|
||||
***/
|
||||
static uint16_t RegisterControlResultCback(
|
||||
const SessionType& session_type, const PortStatusCallbacks& cbacks) {
|
||||
std::shared_ptr<BluetoothAudioSession> session_ptr =
|
||||
BluetoothAudioSessionInstance::GetSessionInstance(session_type);
|
||||
if (session_ptr != nullptr) {
|
||||
return session_ptr->RegisterStatusCback(cbacks);
|
||||
}
|
||||
return kObserversCookieUndefined;
|
||||
}
|
||||
|
||||
/***
|
||||
* The control API helps the bluetooth_audio module to unregister
|
||||
* PortStatusCallbacks
|
||||
* @param: cookie - indicates which bluetooth_audio output is
|
||||
***/
|
||||
static void UnregisterControlResultCback(const SessionType& session_type,
|
||||
uint16_t cookie) {
|
||||
std::shared_ptr<BluetoothAudioSession> session_ptr =
|
||||
BluetoothAudioSessionInstance::GetSessionInstance(session_type);
|
||||
if (session_ptr != nullptr) {
|
||||
session_ptr->UnregisterStatusCback(cookie);
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* The control API for the bluetooth_audio module to get current
|
||||
* AudioConfiguration
|
||||
***/
|
||||
static const AudioConfiguration GetAudioConfig(
|
||||
const SessionType& session_type) {
|
||||
std::shared_ptr<BluetoothAudioSession> session_ptr =
|
||||
BluetoothAudioSessionInstance::GetSessionInstance(session_type);
|
||||
if (session_ptr != nullptr) {
|
||||
return session_ptr->GetAudioConfig();
|
||||
} else if (session_type ==
|
||||
SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
|
||||
return BluetoothAudioSession::invalidOffloadAudioConfiguration;
|
||||
} else {
|
||||
return BluetoothAudioSession::invalidSoftwareAudioConfiguration;
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* Those control APIs for the bluetooth_audio module to start / suspend /
|
||||
stop
|
||||
* stream, to check position, and to update metadata.
|
||||
***/
|
||||
static bool StartStream(const SessionType& session_type) {
|
||||
std::shared_ptr<BluetoothAudioSession> session_ptr =
|
||||
BluetoothAudioSessionInstance::GetSessionInstance(session_type);
|
||||
if (session_ptr != nullptr) {
|
||||
return session_ptr->StartStream();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool SuspendStream(const SessionType& session_type) {
|
||||
std::shared_ptr<BluetoothAudioSession> session_ptr =
|
||||
BluetoothAudioSessionInstance::GetSessionInstance(session_type);
|
||||
if (session_ptr != nullptr) {
|
||||
return session_ptr->SuspendStream();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void StopStream(const SessionType& session_type) {
|
||||
std::shared_ptr<BluetoothAudioSession> session_ptr =
|
||||
BluetoothAudioSessionInstance::GetSessionInstance(session_type);
|
||||
if (session_ptr != nullptr) {
|
||||
session_ptr->StopStream();
|
||||
}
|
||||
}
|
||||
|
||||
static bool GetPresentationPosition(
|
||||
const SessionType& session_type,
|
||||
PresentationPosition& presentation_position) {
|
||||
std::shared_ptr<BluetoothAudioSession> session_ptr =
|
||||
BluetoothAudioSessionInstance::GetSessionInstance(session_type);
|
||||
if (session_ptr != nullptr) {
|
||||
return session_ptr->GetPresentationPosition(presentation_position);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void UpdateSourceMetadata(
|
||||
const SessionType& session_type,
|
||||
const struct source_metadata& source_metadata) {
|
||||
std::shared_ptr<BluetoothAudioSession> session_ptr =
|
||||
BluetoothAudioSessionInstance::GetSessionInstance(session_type);
|
||||
if (session_ptr != nullptr) {
|
||||
session_ptr->UpdateSourceMetadata(source_metadata);
|
||||
}
|
||||
}
|
||||
|
||||
static void UpdateSinkMetadata(const SessionType& session_type,
|
||||
const struct sink_metadata& sink_metadata) {
|
||||
std::shared_ptr<BluetoothAudioSession> session_ptr =
|
||||
BluetoothAudioSessionInstance::GetSessionInstance(session_type);
|
||||
if (session_ptr != nullptr) {
|
||||
session_ptr->UpdateSinkMetadata(sink_metadata);
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* The control API writes stream to FMQ
|
||||
***/
|
||||
static size_t OutWritePcmData(const SessionType& session_type,
|
||||
const void* buffer, size_t bytes) {
|
||||
std::shared_ptr<BluetoothAudioSession> session_ptr =
|
||||
BluetoothAudioSessionInstance::GetSessionInstance(session_type);
|
||||
if (session_ptr != nullptr) {
|
||||
return session_ptr->OutWritePcmData(buffer, bytes);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***
|
||||
* The control API reads stream from FMQ
|
||||
***/
|
||||
static size_t InReadPcmData(const SessionType& session_type, void* buffer,
|
||||
size_t bytes) {
|
||||
std::shared_ptr<BluetoothAudioSession> session_ptr =
|
||||
BluetoothAudioSessionInstance::GetSessionInstance(session_type);
|
||||
if (session_ptr != nullptr) {
|
||||
return session_ptr->InReadPcmData(buffer, bytes);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace audio
|
||||
} // namespace bluetooth
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BluetoothAudioSession.h"
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace bluetooth {
|
||||
namespace audio {
|
||||
|
||||
class BluetoothAudioSessionReport {
|
||||
public:
|
||||
/***
|
||||
* The API reports the Bluetooth stack has started the session, and will
|
||||
* inform registered bluetooth_audio outputs
|
||||
***/
|
||||
static void OnSessionStarted(
|
||||
const SessionType& session_type,
|
||||
const std::shared_ptr<IBluetoothAudioPort> host_iface,
|
||||
const DataMQDesc* data_mq, const AudioConfiguration& audio_config) {
|
||||
std::shared_ptr<BluetoothAudioSession> session_ptr =
|
||||
BluetoothAudioSessionInstance::GetSessionInstance(session_type);
|
||||
if (session_ptr != nullptr) {
|
||||
session_ptr->OnSessionStarted(host_iface, data_mq, audio_config);
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* The API reports the Bluetooth stack has ended the session, and will
|
||||
* inform registered bluetooth_audio outputs
|
||||
***/
|
||||
static void OnSessionEnded(const SessionType& session_type) {
|
||||
std::shared_ptr<BluetoothAudioSession> session_ptr =
|
||||
BluetoothAudioSessionInstance::GetSessionInstance(session_type);
|
||||
if (session_ptr != nullptr) {
|
||||
session_ptr->OnSessionEnded();
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* The API reports the Bluetooth stack has replied the result of startStream
|
||||
* or suspendStream, and will inform registered bluetooth_audio outputs
|
||||
***/
|
||||
static void ReportControlStatus(const SessionType& session_type,
|
||||
const bool& start_resp,
|
||||
BluetoothAudioStatus status) {
|
||||
std::shared_ptr<BluetoothAudioSession> session_ptr =
|
||||
BluetoothAudioSessionInstance::GetSessionInstance(session_type);
|
||||
if (session_ptr != nullptr) {
|
||||
session_ptr->ReportControlStatus(start_resp, status);
|
||||
}
|
||||
}
|
||||
/***
|
||||
* The API reports the Bluetooth stack has replied the changed of the audio
|
||||
* configuration, and will inform registered bluetooth_audio outputs
|
||||
***/
|
||||
static void ReportAudioConfigChanged(const SessionType& session_type,
|
||||
const AudioConfiguration& audio_config) {
|
||||
std::shared_ptr<BluetoothAudioSession> session_ptr =
|
||||
BluetoothAudioSessionInstance::GetSessionInstance(session_type);
|
||||
if (session_ptr != nullptr) {
|
||||
session_ptr->ReportAudioConfigChanged(audio_config);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace audio
|
||||
} // namespace bluetooth
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
||||
775
bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware.cpp
Normal file
775
bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware.cpp
Normal file
@@ -0,0 +1,775 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define LOG_TAG "BtAudioNakahara"
|
||||
|
||||
#include <aidl/android/hardware/bluetooth/audio/AudioConfiguration.h>
|
||||
#include <aidl/android/hardware/bluetooth/audio/BluetoothAudioStatus.h>
|
||||
#include <aidl/android/hardware/bluetooth/audio/SessionType.h>
|
||||
#include <android-base/logging.h>
|
||||
|
||||
#include <functional>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "../aidl_session/BluetoothAudioSession.h"
|
||||
#include "../aidl_session/BluetoothAudioSessionControl.h"
|
||||
#include "HidlToAidlMiddleware_2_0.h"
|
||||
#include "HidlToAidlMiddleware_2_1.h"
|
||||
#include "HidlToAidlMiddleware_2_2.h"
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace bluetooth {
|
||||
namespace audio {
|
||||
|
||||
using HidlStatus = ::android::hardware::bluetooth::audio::V2_0::Status;
|
||||
using PcmConfig_2_0 =
|
||||
::android::hardware::bluetooth::audio::V2_0::PcmParameters;
|
||||
using SampleRate_2_0 = ::android::hardware::bluetooth::audio::V2_0::SampleRate;
|
||||
using ChannelMode_2_0 =
|
||||
::android::hardware::bluetooth::audio::V2_0::ChannelMode;
|
||||
using BitsPerSample_2_0 =
|
||||
::android::hardware::bluetooth::audio::V2_0::BitsPerSample;
|
||||
using CodecConfig_2_0 =
|
||||
::android::hardware::bluetooth::audio::V2_0::CodecConfiguration;
|
||||
using CodecType_2_0 = ::android::hardware::bluetooth::audio::V2_0::CodecType;
|
||||
using SbcConfig_2_0 =
|
||||
::android::hardware::bluetooth::audio::V2_0::SbcParameters;
|
||||
using AacConfig_2_0 =
|
||||
::android::hardware::bluetooth::audio::V2_0::AacParameters;
|
||||
using LdacConfig_2_0 =
|
||||
::android::hardware::bluetooth::audio::V2_0::LdacParameters;
|
||||
using AptxConfig_2_0 =
|
||||
::android::hardware::bluetooth::audio::V2_0::AptxParameters;
|
||||
using SbcAllocMethod_2_0 =
|
||||
::android::hardware::bluetooth::audio::V2_0::SbcAllocMethod;
|
||||
using SbcBlockLength_2_0 =
|
||||
::android::hardware::bluetooth::audio::V2_0::SbcBlockLength;
|
||||
using SbcChannelMode_2_0 =
|
||||
::android::hardware::bluetooth::audio::V2_0::SbcChannelMode;
|
||||
using SbcNumSubbands_2_0 =
|
||||
::android::hardware::bluetooth::audio::V2_0::SbcNumSubbands;
|
||||
using AacObjectType_2_0 =
|
||||
::android::hardware::bluetooth::audio::V2_0::AacObjectType;
|
||||
using AacVarBitRate_2_0 =
|
||||
::android::hardware::bluetooth::audio::V2_0::AacVariableBitRate;
|
||||
using LdacChannelMode_2_0 =
|
||||
::android::hardware::bluetooth::audio::V2_0::LdacChannelMode;
|
||||
using LdacQualityIndex_2_0 =
|
||||
::android::hardware::bluetooth::audio::V2_0::LdacQualityIndex;
|
||||
|
||||
using PcmConfig_2_1 =
|
||||
::android::hardware::bluetooth::audio::V2_1::PcmParameters;
|
||||
using SampleRate_2_1 = ::android::hardware::bluetooth::audio::V2_1::SampleRate;
|
||||
using Lc3CodecConfig_2_1 =
|
||||
::android::hardware::bluetooth::audio::V2_1::Lc3CodecConfiguration;
|
||||
using Lc3Config_2_1 =
|
||||
::android::hardware::bluetooth::audio::V2_1::Lc3Parameters;
|
||||
using Lc3FrameDuration_2_1 =
|
||||
::android::hardware::bluetooth::audio::V2_1::Lc3FrameDuration;
|
||||
|
||||
using LeAudioConfig_2_2 =
|
||||
::android::hardware::bluetooth::audio::V2_2::LeAudioConfiguration;
|
||||
using LeAudioMode_2_2 =
|
||||
::android::hardware::bluetooth::audio::V2_2::LeAudioMode;
|
||||
|
||||
std::mutex legacy_callback_lock;
|
||||
std::unordered_map<
|
||||
SessionType,
|
||||
std::unordered_map<uint16_t, std::shared_ptr<PortStatusCallbacks_2_2>>>
|
||||
legacy_callback_table;
|
||||
|
||||
const static std::unordered_map<SessionType_2_0, SessionType>
|
||||
session_type_2_0_to_aidl_map{
|
||||
{SessionType_2_0::A2DP_SOFTWARE_ENCODING_DATAPATH,
|
||||
SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH},
|
||||
{SessionType_2_0::A2DP_HARDWARE_OFFLOAD_DATAPATH,
|
||||
SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH},
|
||||
{SessionType_2_0::HEARING_AID_SOFTWARE_ENCODING_DATAPATH,
|
||||
SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH},
|
||||
};
|
||||
|
||||
const static std::unordered_map<SessionType_2_1, SessionType>
|
||||
session_type_2_1_to_aidl_map{
|
||||
{SessionType_2_1::A2DP_SOFTWARE_ENCODING_DATAPATH,
|
||||
SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH},
|
||||
{SessionType_2_1::A2DP_HARDWARE_OFFLOAD_DATAPATH,
|
||||
SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH},
|
||||
{SessionType_2_1::HEARING_AID_SOFTWARE_ENCODING_DATAPATH,
|
||||
SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH},
|
||||
{SessionType_2_1::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH,
|
||||
SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH},
|
||||
{SessionType_2_1::LE_AUDIO_SOFTWARE_DECODED_DATAPATH,
|
||||
SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH},
|
||||
{SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH,
|
||||
SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH},
|
||||
{SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH,
|
||||
SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH},
|
||||
};
|
||||
|
||||
const static std::unordered_map<int32_t, SampleRate_2_0>
|
||||
sample_rate_to_hidl_2_0_map{
|
||||
{44100, SampleRate_2_0::RATE_44100},
|
||||
{48000, SampleRate_2_0::RATE_48000},
|
||||
{88200, SampleRate_2_0::RATE_88200},
|
||||
{96000, SampleRate_2_0::RATE_96000},
|
||||
{176400, SampleRate_2_0::RATE_176400},
|
||||
{192000, SampleRate_2_0::RATE_192000},
|
||||
{16000, SampleRate_2_0::RATE_16000},
|
||||
{24000, SampleRate_2_0::RATE_24000},
|
||||
};
|
||||
|
||||
const static std::unordered_map<int32_t, SampleRate_2_1>
|
||||
sample_rate_to_hidl_2_1_map{
|
||||
{44100, SampleRate_2_1::RATE_44100},
|
||||
{48000, SampleRate_2_1::RATE_48000},
|
||||
{88200, SampleRate_2_1::RATE_88200},
|
||||
{96000, SampleRate_2_1::RATE_96000},
|
||||
{176400, SampleRate_2_1::RATE_176400},
|
||||
{192000, SampleRate_2_1::RATE_192000},
|
||||
{16000, SampleRate_2_1::RATE_16000},
|
||||
{24000, SampleRate_2_1::RATE_24000},
|
||||
{8000, SampleRate_2_1::RATE_8000},
|
||||
{32000, SampleRate_2_1::RATE_32000},
|
||||
};
|
||||
|
||||
const static std::unordered_map<CodecType, CodecType_2_0>
|
||||
codec_type_to_hidl_2_0_map{
|
||||
{CodecType::UNKNOWN, CodecType_2_0::UNKNOWN},
|
||||
{CodecType::SBC, CodecType_2_0::SBC},
|
||||
{CodecType::AAC, CodecType_2_0::AAC},
|
||||
{CodecType::APTX, CodecType_2_0::APTX},
|
||||
{CodecType::APTX_HD, CodecType_2_0::APTX_HD},
|
||||
{CodecType::LDAC, CodecType_2_0::LDAC},
|
||||
{CodecType::LC3, CodecType_2_0::UNKNOWN},
|
||||
};
|
||||
|
||||
const static std::unordered_map<SbcChannelMode, SbcChannelMode_2_0>
|
||||
sbc_channel_mode_to_hidl_2_0_map{
|
||||
{SbcChannelMode::UNKNOWN, SbcChannelMode_2_0::UNKNOWN},
|
||||
{SbcChannelMode::JOINT_STEREO, SbcChannelMode_2_0::JOINT_STEREO},
|
||||
{SbcChannelMode::STEREO, SbcChannelMode_2_0::STEREO},
|
||||
{SbcChannelMode::DUAL, SbcChannelMode_2_0::DUAL},
|
||||
{SbcChannelMode::MONO, SbcChannelMode_2_0::MONO},
|
||||
};
|
||||
|
||||
const static std::unordered_map<int8_t, SbcBlockLength_2_0>
|
||||
sbc_block_length_to_hidl_map{
|
||||
{4, SbcBlockLength_2_0::BLOCKS_4},
|
||||
{8, SbcBlockLength_2_0::BLOCKS_8},
|
||||
{12, SbcBlockLength_2_0::BLOCKS_12},
|
||||
{16, SbcBlockLength_2_0::BLOCKS_16},
|
||||
};
|
||||
|
||||
const static std::unordered_map<int8_t, SbcNumSubbands_2_0>
|
||||
sbc_subbands_to_hidl_map{
|
||||
{4, SbcNumSubbands_2_0::SUBBAND_4},
|
||||
{8, SbcNumSubbands_2_0::SUBBAND_8},
|
||||
};
|
||||
|
||||
const static std::unordered_map<SbcAllocMethod, SbcAllocMethod_2_0>
|
||||
sbc_alloc_method_to_hidl_map{
|
||||
{SbcAllocMethod::ALLOC_MD_S, SbcAllocMethod_2_0::ALLOC_MD_S},
|
||||
{SbcAllocMethod::ALLOC_MD_L, SbcAllocMethod_2_0::ALLOC_MD_L},
|
||||
};
|
||||
|
||||
const static std::unordered_map<AacObjectType, AacObjectType_2_0>
|
||||
aac_object_type_to_hidl_map{
|
||||
{AacObjectType::MPEG2_LC, AacObjectType_2_0::MPEG2_LC},
|
||||
{AacObjectType::MPEG4_LC, AacObjectType_2_0::MPEG4_LC},
|
||||
{AacObjectType::MPEG4_LTP, AacObjectType_2_0::MPEG4_LTP},
|
||||
{AacObjectType::MPEG4_SCALABLE, AacObjectType_2_0::MPEG4_SCALABLE},
|
||||
};
|
||||
|
||||
const static std::unordered_map<LdacChannelMode, LdacChannelMode_2_0>
|
||||
ldac_channel_mode_to_hidl_map{
|
||||
{LdacChannelMode::UNKNOWN, LdacChannelMode_2_0::UNKNOWN},
|
||||
{LdacChannelMode::STEREO, LdacChannelMode_2_0::STEREO},
|
||||
{LdacChannelMode::DUAL, LdacChannelMode_2_0::DUAL},
|
||||
{LdacChannelMode::MONO, LdacChannelMode_2_0::MONO},
|
||||
};
|
||||
|
||||
const static std::unordered_map<LdacQualityIndex, LdacQualityIndex_2_0>
|
||||
ldac_qindex_to_hidl_map{
|
||||
{LdacQualityIndex::HIGH, LdacQualityIndex_2_0::QUALITY_HIGH},
|
||||
{LdacQualityIndex::MID, LdacQualityIndex_2_0::QUALITY_MID},
|
||||
{LdacQualityIndex::LOW, LdacQualityIndex_2_0::QUALITY_LOW},
|
||||
{LdacQualityIndex::ABR, LdacQualityIndex_2_0::QUALITY_ABR},
|
||||
};
|
||||
|
||||
const static std::unordered_map<LeAudioMode, LeAudioMode_2_2>
|
||||
leaudio_mode_to_hidl_map{
|
||||
{LeAudioMode::UNKNOWN, LeAudioMode_2_2::UNKNOWN},
|
||||
{LeAudioMode::UNICAST, LeAudioMode_2_2::UNICAST},
|
||||
{LeAudioMode::BROADCAST, LeAudioMode_2_2::BROADCAST},
|
||||
};
|
||||
|
||||
inline SessionType from_session_type_2_0(
|
||||
const SessionType_2_0& session_type_hidl) {
|
||||
auto it = session_type_2_0_to_aidl_map.find(session_type_hidl);
|
||||
if (it != session_type_2_0_to_aidl_map.end()) return it->second;
|
||||
return SessionType::UNKNOWN;
|
||||
}
|
||||
|
||||
inline SessionType from_session_type_2_1(
|
||||
const SessionType_2_1& session_type_hidl) {
|
||||
auto it = session_type_2_1_to_aidl_map.find(session_type_hidl);
|
||||
if (it != session_type_2_1_to_aidl_map.end()) return it->second;
|
||||
return SessionType::UNKNOWN;
|
||||
}
|
||||
|
||||
inline HidlStatus to_hidl_status(const BluetoothAudioStatus& status) {
|
||||
switch (status) {
|
||||
case BluetoothAudioStatus::SUCCESS:
|
||||
return HidlStatus::SUCCESS;
|
||||
case BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION:
|
||||
return HidlStatus::UNSUPPORTED_CODEC_CONFIGURATION;
|
||||
default:
|
||||
return HidlStatus::FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
inline SampleRate_2_0 to_hidl_sample_rate_2_0(const int32_t sample_rate_hz) {
|
||||
auto it = sample_rate_to_hidl_2_0_map.find(sample_rate_hz);
|
||||
if (it != sample_rate_to_hidl_2_0_map.end()) return it->second;
|
||||
return SampleRate_2_0::RATE_UNKNOWN;
|
||||
}
|
||||
|
||||
inline SampleRate_2_1 to_hidl_sample_rate_2_1(const int32_t sample_rate_hz) {
|
||||
auto it = sample_rate_to_hidl_2_1_map.find(sample_rate_hz);
|
||||
if (it != sample_rate_to_hidl_2_1_map.end()) return it->second;
|
||||
return SampleRate_2_1::RATE_UNKNOWN;
|
||||
}
|
||||
|
||||
inline BitsPerSample_2_0 to_hidl_bits_per_sample(const int8_t bit_per_sample) {
|
||||
switch (bit_per_sample) {
|
||||
case 16:
|
||||
return BitsPerSample_2_0::BITS_16;
|
||||
case 24:
|
||||
return BitsPerSample_2_0::BITS_24;
|
||||
case 32:
|
||||
return BitsPerSample_2_0::BITS_32;
|
||||
default:
|
||||
return BitsPerSample_2_0::BITS_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
inline ChannelMode_2_0 to_hidl_channel_mode(const ChannelMode channel_mode) {
|
||||
switch (channel_mode) {
|
||||
case ChannelMode::MONO:
|
||||
return ChannelMode_2_0::MONO;
|
||||
case ChannelMode::STEREO:
|
||||
return ChannelMode_2_0::STEREO;
|
||||
default:
|
||||
return ChannelMode_2_0::UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
inline PcmConfig_2_0 to_hidl_pcm_config_2_0(
|
||||
const PcmConfiguration& pcm_config) {
|
||||
PcmConfig_2_0 hidl_pcm_config;
|
||||
hidl_pcm_config.sampleRate = to_hidl_sample_rate_2_0(pcm_config.sampleRateHz);
|
||||
hidl_pcm_config.channelMode = to_hidl_channel_mode(pcm_config.channelMode);
|
||||
hidl_pcm_config.bitsPerSample =
|
||||
to_hidl_bits_per_sample(pcm_config.bitsPerSample);
|
||||
return hidl_pcm_config;
|
||||
}
|
||||
|
||||
inline CodecType_2_0 to_hidl_codec_type_2_0(const CodecType codec_type) {
|
||||
auto it = codec_type_to_hidl_2_0_map.find(codec_type);
|
||||
if (it != codec_type_to_hidl_2_0_map.end()) return it->second;
|
||||
return CodecType_2_0::UNKNOWN;
|
||||
}
|
||||
|
||||
inline SbcConfig_2_0 to_hidl_sbc_config(const SbcConfiguration sbc_config) {
|
||||
SbcConfig_2_0 hidl_sbc_config;
|
||||
hidl_sbc_config.minBitpool = sbc_config.minBitpool;
|
||||
hidl_sbc_config.maxBitpool = sbc_config.maxBitpool;
|
||||
hidl_sbc_config.sampleRate = to_hidl_sample_rate_2_0(sbc_config.sampleRateHz);
|
||||
hidl_sbc_config.bitsPerSample =
|
||||
to_hidl_bits_per_sample(sbc_config.bitsPerSample);
|
||||
if (sbc_channel_mode_to_hidl_2_0_map.find(sbc_config.channelMode) !=
|
||||
sbc_channel_mode_to_hidl_2_0_map.end()) {
|
||||
hidl_sbc_config.channelMode =
|
||||
sbc_channel_mode_to_hidl_2_0_map.at(sbc_config.channelMode);
|
||||
}
|
||||
if (sbc_block_length_to_hidl_map.find(sbc_config.blockLength) !=
|
||||
sbc_block_length_to_hidl_map.end()) {
|
||||
hidl_sbc_config.blockLength =
|
||||
sbc_block_length_to_hidl_map.at(sbc_config.blockLength);
|
||||
}
|
||||
if (sbc_subbands_to_hidl_map.find(sbc_config.numSubbands) !=
|
||||
sbc_subbands_to_hidl_map.end()) {
|
||||
hidl_sbc_config.numSubbands =
|
||||
sbc_subbands_to_hidl_map.at(sbc_config.numSubbands);
|
||||
}
|
||||
if (sbc_alloc_method_to_hidl_map.find(sbc_config.allocMethod) !=
|
||||
sbc_alloc_method_to_hidl_map.end()) {
|
||||
hidl_sbc_config.allocMethod =
|
||||
sbc_alloc_method_to_hidl_map.at(sbc_config.allocMethod);
|
||||
}
|
||||
return hidl_sbc_config;
|
||||
}
|
||||
|
||||
inline AacConfig_2_0 to_hidl_aac_config(const AacConfiguration aac_config) {
|
||||
AacConfig_2_0 hidl_aac_config;
|
||||
hidl_aac_config.sampleRate = to_hidl_sample_rate_2_0(aac_config.sampleRateHz);
|
||||
hidl_aac_config.bitsPerSample =
|
||||
to_hidl_bits_per_sample(aac_config.bitsPerSample);
|
||||
hidl_aac_config.channelMode = to_hidl_channel_mode(aac_config.channelMode);
|
||||
if (aac_object_type_to_hidl_map.find(aac_config.objectType) !=
|
||||
aac_object_type_to_hidl_map.end()) {
|
||||
hidl_aac_config.objectType =
|
||||
aac_object_type_to_hidl_map.at(aac_config.objectType);
|
||||
}
|
||||
hidl_aac_config.variableBitRateEnabled = aac_config.variableBitRateEnabled
|
||||
? AacVarBitRate_2_0::ENABLED
|
||||
: AacVarBitRate_2_0::DISABLED;
|
||||
return hidl_aac_config;
|
||||
}
|
||||
|
||||
inline LdacConfig_2_0 to_hidl_ldac_config(const LdacConfiguration ldac_config) {
|
||||
LdacConfig_2_0 hidl_ldac_config;
|
||||
hidl_ldac_config.sampleRate =
|
||||
to_hidl_sample_rate_2_0(ldac_config.sampleRateHz);
|
||||
hidl_ldac_config.bitsPerSample =
|
||||
to_hidl_bits_per_sample(ldac_config.bitsPerSample);
|
||||
if (ldac_channel_mode_to_hidl_map.find(ldac_config.channelMode) !=
|
||||
ldac_channel_mode_to_hidl_map.end()) {
|
||||
hidl_ldac_config.channelMode =
|
||||
ldac_channel_mode_to_hidl_map.at(ldac_config.channelMode);
|
||||
}
|
||||
if (ldac_qindex_to_hidl_map.find(ldac_config.qualityIndex) !=
|
||||
ldac_qindex_to_hidl_map.end()) {
|
||||
hidl_ldac_config.qualityIndex =
|
||||
ldac_qindex_to_hidl_map.at(ldac_config.qualityIndex);
|
||||
}
|
||||
return hidl_ldac_config;
|
||||
}
|
||||
|
||||
inline AptxConfig_2_0 to_hidl_aptx_config(const AptxConfiguration aptx_config) {
|
||||
AptxConfig_2_0 hidl_aptx_config;
|
||||
hidl_aptx_config.sampleRate =
|
||||
to_hidl_sample_rate_2_0(aptx_config.sampleRateHz);
|
||||
hidl_aptx_config.bitsPerSample =
|
||||
to_hidl_bits_per_sample(aptx_config.bitsPerSample);
|
||||
hidl_aptx_config.channelMode = to_hidl_channel_mode(aptx_config.channelMode);
|
||||
return hidl_aptx_config;
|
||||
}
|
||||
|
||||
inline CodecConfig_2_0 to_hidl_codec_config_2_0(
|
||||
const CodecConfiguration& codec_config) {
|
||||
CodecConfig_2_0 hidl_codec_config;
|
||||
hidl_codec_config.codecType = to_hidl_codec_type_2_0(codec_config.codecType);
|
||||
hidl_codec_config.encodedAudioBitrate =
|
||||
static_cast<uint32_t>(codec_config.encodedAudioBitrate);
|
||||
hidl_codec_config.peerMtu = static_cast<uint32_t>(codec_config.peerMtu);
|
||||
hidl_codec_config.isScmstEnabled = codec_config.isScmstEnabled;
|
||||
switch (codec_config.config.getTag()) {
|
||||
case CodecConfiguration::CodecSpecific::sbcConfig:
|
||||
hidl_codec_config.config.sbcConfig(to_hidl_sbc_config(
|
||||
codec_config.config
|
||||
.get<CodecConfiguration::CodecSpecific::sbcConfig>()));
|
||||
break;
|
||||
case CodecConfiguration::CodecSpecific::aacConfig:
|
||||
hidl_codec_config.config.aacConfig(to_hidl_aac_config(
|
||||
codec_config.config
|
||||
.get<CodecConfiguration::CodecSpecific::aacConfig>()));
|
||||
break;
|
||||
case CodecConfiguration::CodecSpecific::ldacConfig:
|
||||
hidl_codec_config.config.ldacConfig(to_hidl_ldac_config(
|
||||
codec_config.config
|
||||
.get<CodecConfiguration::CodecSpecific::ldacConfig>()));
|
||||
break;
|
||||
case CodecConfiguration::CodecSpecific::aptxConfig:
|
||||
hidl_codec_config.config.aptxConfig(to_hidl_aptx_config(
|
||||
codec_config.config
|
||||
.get<CodecConfiguration::CodecSpecific::aptxConfig>()));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return hidl_codec_config;
|
||||
}
|
||||
|
||||
inline AudioConfig_2_0 to_hidl_audio_config_2_0(
|
||||
const AudioConfiguration& audio_config) {
|
||||
AudioConfig_2_0 hidl_audio_config;
|
||||
if (audio_config.getTag() == AudioConfiguration::pcmConfig) {
|
||||
hidl_audio_config.pcmConfig(to_hidl_pcm_config_2_0(
|
||||
audio_config.get<AudioConfiguration::pcmConfig>()));
|
||||
} else if (audio_config.getTag() == AudioConfiguration::a2dpConfig) {
|
||||
hidl_audio_config.codecConfig(to_hidl_codec_config_2_0(
|
||||
audio_config.get<AudioConfiguration::a2dpConfig>()));
|
||||
}
|
||||
return hidl_audio_config;
|
||||
}
|
||||
|
||||
inline PcmConfig_2_1 to_hidl_pcm_config_2_1(
|
||||
const PcmConfiguration& pcm_config) {
|
||||
PcmConfig_2_1 hidl_pcm_config;
|
||||
hidl_pcm_config.sampleRate = to_hidl_sample_rate_2_1(pcm_config.sampleRateHz);
|
||||
hidl_pcm_config.channelMode = to_hidl_channel_mode(pcm_config.channelMode);
|
||||
hidl_pcm_config.bitsPerSample =
|
||||
to_hidl_bits_per_sample(pcm_config.bitsPerSample);
|
||||
hidl_pcm_config.dataIntervalUs =
|
||||
static_cast<uint32_t>(pcm_config.dataIntervalUs);
|
||||
return hidl_pcm_config;
|
||||
}
|
||||
|
||||
inline Lc3Config_2_1 to_hidl_lc3_config_2_1(
|
||||
const Lc3Configuration& lc3_config) {
|
||||
Lc3Config_2_1 hidl_lc3_config;
|
||||
hidl_lc3_config.pcmBitDepth = to_hidl_bits_per_sample(lc3_config.pcmBitDepth);
|
||||
hidl_lc3_config.samplingFrequency =
|
||||
to_hidl_sample_rate_2_1(lc3_config.samplingFrequencyHz);
|
||||
if (lc3_config.samplingFrequencyHz == 10000)
|
||||
hidl_lc3_config.frameDuration = Lc3FrameDuration_2_1::DURATION_10000US;
|
||||
else if (lc3_config.samplingFrequencyHz == 7500)
|
||||
hidl_lc3_config.frameDuration = Lc3FrameDuration_2_1::DURATION_7500US;
|
||||
hidl_lc3_config.octetsPerFrame =
|
||||
static_cast<uint32_t>(lc3_config.octetsPerFrame);
|
||||
hidl_lc3_config.blocksPerSdu = static_cast<uint32_t>(lc3_config.blocksPerSdu);
|
||||
return hidl_lc3_config;
|
||||
}
|
||||
|
||||
inline Lc3CodecConfig_2_1 to_hidl_leaudio_config_2_1(
|
||||
const LeAudioConfiguration& leaudio_config) {
|
||||
auto& unicast_config =
|
||||
leaudio_config.modeConfig
|
||||
.get<LeAudioConfiguration::LeAudioModeConfig::unicastConfig>();
|
||||
|
||||
auto& le_codec_config = unicast_config.leAudioCodecConfig
|
||||
.get<LeAudioCodecConfiguration::lc3Config>();
|
||||
|
||||
Lc3CodecConfig_2_1 hidl_lc3_codec_config;
|
||||
hidl_lc3_codec_config.lc3Config = to_hidl_lc3_config_2_1(le_codec_config);
|
||||
|
||||
hidl_lc3_codec_config.audioChannelAllocation =
|
||||
unicast_config.streamMap.size();
|
||||
|
||||
return hidl_lc3_codec_config;
|
||||
}
|
||||
|
||||
inline LeAudioConfig_2_2 to_hidl_leaudio_config_2_2(
|
||||
const LeAudioConfiguration& leaudio_config) {
|
||||
LeAudioConfig_2_2 hidl_leaudio_config;
|
||||
if (leaudio_mode_to_hidl_map.find(leaudio_config.mode) !=
|
||||
leaudio_mode_to_hidl_map.end()) {
|
||||
hidl_leaudio_config.mode = leaudio_mode_to_hidl_map.at(leaudio_config.mode);
|
||||
}
|
||||
|
||||
if (leaudio_config.modeConfig.getTag() ==
|
||||
LeAudioConfiguration::LeAudioModeConfig::unicastConfig) {
|
||||
auto& unicast_config =
|
||||
leaudio_config.modeConfig
|
||||
.get<LeAudioConfiguration::LeAudioModeConfig::unicastConfig>();
|
||||
::android::hardware::bluetooth::audio::V2_2::UnicastConfig
|
||||
hidl_unicast_config;
|
||||
hidl_unicast_config.peerDelay =
|
||||
static_cast<uint32_t>(unicast_config.peerDelay);
|
||||
|
||||
auto& lc3_config = unicast_config.leAudioCodecConfig
|
||||
.get<LeAudioCodecConfiguration::lc3Config>();
|
||||
hidl_unicast_config.lc3Config = to_hidl_lc3_config_2_1(lc3_config);
|
||||
|
||||
hidl_unicast_config.streamMap.resize(unicast_config.streamMap.size());
|
||||
for (int i = 0; i < unicast_config.streamMap.size(); i++) {
|
||||
hidl_unicast_config.streamMap[i].audioChannelAllocation =
|
||||
static_cast<uint32_t>(
|
||||
unicast_config.streamMap[i].audioChannelAllocation);
|
||||
hidl_unicast_config.streamMap[i].streamHandle =
|
||||
static_cast<uint16_t>(unicast_config.streamMap[i].streamHandle);
|
||||
}
|
||||
} else if (leaudio_config.modeConfig.getTag() ==
|
||||
LeAudioConfiguration::LeAudioModeConfig::broadcastConfig) {
|
||||
auto bcast_config =
|
||||
leaudio_config.modeConfig
|
||||
.get<LeAudioConfiguration::LeAudioModeConfig::broadcastConfig>();
|
||||
::android::hardware::bluetooth::audio::V2_2::BroadcastConfig
|
||||
hidl_bcast_config;
|
||||
hidl_bcast_config.streamMap.resize(bcast_config.streamMap.size());
|
||||
for (int i = 0; i < bcast_config.streamMap.size(); i++) {
|
||||
hidl_bcast_config.streamMap[i].audioChannelAllocation =
|
||||
static_cast<uint32_t>(
|
||||
bcast_config.streamMap[i].audioChannelAllocation);
|
||||
hidl_bcast_config.streamMap[i].streamHandle =
|
||||
static_cast<uint16_t>(bcast_config.streamMap[i].streamHandle);
|
||||
hidl_bcast_config.streamMap[i].lc3Config = to_hidl_lc3_config_2_1(
|
||||
bcast_config.streamMap[i]
|
||||
.leAudioCodecConfig.get<LeAudioCodecConfiguration::lc3Config>());
|
||||
}
|
||||
}
|
||||
return hidl_leaudio_config;
|
||||
}
|
||||
|
||||
inline AudioConfig_2_1 to_hidl_audio_config_2_1(
|
||||
const AudioConfiguration& audio_config) {
|
||||
AudioConfig_2_1 hidl_audio_config;
|
||||
switch (audio_config.getTag()) {
|
||||
case AudioConfiguration::pcmConfig:
|
||||
hidl_audio_config.pcmConfig(to_hidl_pcm_config_2_1(
|
||||
audio_config.get<AudioConfiguration::pcmConfig>()));
|
||||
break;
|
||||
case AudioConfiguration::a2dpConfig:
|
||||
hidl_audio_config.codecConfig(to_hidl_codec_config_2_0(
|
||||
audio_config.get<AudioConfiguration::a2dpConfig>()));
|
||||
break;
|
||||
case AudioConfiguration::leAudioConfig:
|
||||
hidl_audio_config.leAudioCodecConfig(to_hidl_leaudio_config_2_1(
|
||||
audio_config.get<AudioConfiguration::leAudioConfig>()));
|
||||
break;
|
||||
}
|
||||
return hidl_audio_config;
|
||||
}
|
||||
|
||||
inline AudioConfig_2_2 to_hidl_audio_config_2_2(
|
||||
const AudioConfiguration& audio_config) {
|
||||
AudioConfig_2_2 hidl_audio_config;
|
||||
switch (audio_config.getTag()) {
|
||||
case AudioConfiguration::pcmConfig:
|
||||
hidl_audio_config.pcmConfig(to_hidl_pcm_config_2_1(
|
||||
audio_config.get<AudioConfiguration::pcmConfig>()));
|
||||
break;
|
||||
case AudioConfiguration::a2dpConfig:
|
||||
hidl_audio_config.codecConfig(to_hidl_codec_config_2_0(
|
||||
audio_config.get<AudioConfiguration::a2dpConfig>()));
|
||||
break;
|
||||
case AudioConfiguration::leAudioConfig:
|
||||
hidl_audio_config.leAudioConfig(to_hidl_leaudio_config_2_2(
|
||||
audio_config.get<AudioConfiguration::leAudioConfig>()));
|
||||
break;
|
||||
}
|
||||
return hidl_audio_config;
|
||||
}
|
||||
|
||||
/***
|
||||
*
|
||||
* 2.0
|
||||
*
|
||||
***/
|
||||
|
||||
bool HidlToAidlMiddleware_2_0::IsSessionReady(
|
||||
const SessionType_2_0& session_type) {
|
||||
return BluetoothAudioSessionControl::IsSessionReady(
|
||||
from_session_type_2_0(session_type));
|
||||
}
|
||||
|
||||
uint16_t HidlToAidlMiddleware_2_0::RegisterControlResultCback(
|
||||
const SessionType_2_0& session_type,
|
||||
const PortStatusCallbacks_2_0& cbacks) {
|
||||
PortStatusCallbacks_2_2 callback_2_2{
|
||||
.control_result_cb_ = cbacks.control_result_cb_,
|
||||
.session_changed_cb_ = cbacks.session_changed_cb_,
|
||||
};
|
||||
return HidlToAidlMiddleware_2_2::RegisterControlResultCback(
|
||||
static_cast<SessionType_2_1>(session_type), callback_2_2);
|
||||
}
|
||||
|
||||
void HidlToAidlMiddleware_2_0::UnregisterControlResultCback(
|
||||
const SessionType_2_0& session_type, uint16_t cookie) {
|
||||
HidlToAidlMiddleware_2_2::UnregisterControlResultCback(
|
||||
static_cast<SessionType_2_1>(session_type), cookie);
|
||||
}
|
||||
|
||||
const AudioConfig_2_0 HidlToAidlMiddleware_2_0::GetAudioConfig(
|
||||
const SessionType_2_0& session_type) {
|
||||
return to_hidl_audio_config_2_0(BluetoothAudioSessionControl::GetAudioConfig(
|
||||
from_session_type_2_0(session_type)));
|
||||
}
|
||||
|
||||
bool HidlToAidlMiddleware_2_0::StartStream(
|
||||
const SessionType_2_0& session_type) {
|
||||
return BluetoothAudioSessionControl::StartStream(
|
||||
from_session_type_2_0(session_type));
|
||||
}
|
||||
|
||||
void HidlToAidlMiddleware_2_0::StopStream(const SessionType_2_0& session_type) {
|
||||
return BluetoothAudioSessionControl::StopStream(
|
||||
from_session_type_2_0(session_type));
|
||||
}
|
||||
|
||||
bool HidlToAidlMiddleware_2_0::SuspendStream(
|
||||
const SessionType_2_0& session_type) {
|
||||
return BluetoothAudioSessionControl::SuspendStream(
|
||||
from_session_type_2_0(session_type));
|
||||
}
|
||||
|
||||
bool HidlToAidlMiddleware_2_0::GetPresentationPosition(
|
||||
const SessionType_2_0& session_type, uint64_t* remote_delay_report_ns,
|
||||
uint64_t* total_bytes_readed, timespec* data_position) {
|
||||
PresentationPosition presentation_position;
|
||||
auto ret_val = BluetoothAudioSessionControl::GetPresentationPosition(
|
||||
from_session_type_2_0(session_type), presentation_position);
|
||||
if (remote_delay_report_ns)
|
||||
*remote_delay_report_ns = presentation_position.remoteDeviceAudioDelayNanos;
|
||||
if (total_bytes_readed)
|
||||
*total_bytes_readed = presentation_position.transmittedOctets;
|
||||
if (data_position)
|
||||
*data_position = {
|
||||
.tv_sec = static_cast<__kernel_old_time_t>(
|
||||
presentation_position.transmittedOctetsTimestamp.tvSec),
|
||||
.tv_nsec = static_cast<long>(
|
||||
presentation_position.transmittedOctetsTimestamp.tvNSec)};
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
void HidlToAidlMiddleware_2_0::UpdateTracksMetadata(
|
||||
const SessionType_2_0& session_type,
|
||||
const struct source_metadata* source_metadata) {
|
||||
return BluetoothAudioSessionControl::UpdateSourceMetadata(
|
||||
from_session_type_2_0(session_type), *source_metadata);
|
||||
}
|
||||
|
||||
size_t HidlToAidlMiddleware_2_0::OutWritePcmData(
|
||||
const SessionType_2_0& session_type, const void* buffer, size_t bytes) {
|
||||
return BluetoothAudioSessionControl::OutWritePcmData(
|
||||
from_session_type_2_0(session_type), buffer, bytes);
|
||||
}
|
||||
|
||||
bool HidlToAidlMiddleware_2_0::IsAidlAvailable() {
|
||||
return BluetoothAudioSession::IsAidlAvailable();
|
||||
}
|
||||
|
||||
/***
|
||||
*
|
||||
* 2.1
|
||||
*
|
||||
***/
|
||||
|
||||
const AudioConfig_2_1 HidlToAidlMiddleware_2_1::GetAudioConfig(
|
||||
const SessionType_2_1& session_type) {
|
||||
return to_hidl_audio_config_2_1(BluetoothAudioSessionControl::GetAudioConfig(
|
||||
from_session_type_2_1(session_type)));
|
||||
}
|
||||
|
||||
/***
|
||||
*
|
||||
* 2.2
|
||||
*
|
||||
***/
|
||||
|
||||
bool HidlToAidlMiddleware_2_2::IsSessionReady(
|
||||
const SessionType_2_1& session_type) {
|
||||
return BluetoothAudioSessionControl::IsSessionReady(
|
||||
from_session_type_2_1(session_type));
|
||||
}
|
||||
|
||||
uint16_t HidlToAidlMiddleware_2_2::RegisterControlResultCback(
|
||||
const SessionType_2_1& session_type,
|
||||
const PortStatusCallbacks_2_2& cbacks) {
|
||||
LOG(INFO) << __func__ << ": " << toString(session_type);
|
||||
auto aidl_session_type = from_session_type_2_1(session_type);
|
||||
// Pass the exact reference to the lambda
|
||||
auto& session_legacy_callback_table =
|
||||
legacy_callback_table[aidl_session_type];
|
||||
PortStatusCallbacks aidl_callbacks{};
|
||||
if (cbacks.control_result_cb_) {
|
||||
aidl_callbacks.control_result_cb_ =
|
||||
[&session_legacy_callback_table](uint16_t cookie, bool start_resp,
|
||||
const BluetoothAudioStatus& status) {
|
||||
if (session_legacy_callback_table.find(cookie) ==
|
||||
session_legacy_callback_table.end()) {
|
||||
LOG(ERROR) << __func__ << ": Unknown callback invoked!";
|
||||
return;
|
||||
}
|
||||
auto& cback = session_legacy_callback_table[cookie];
|
||||
cback->control_result_cb_(cookie, start_resp, to_hidl_status(status));
|
||||
};
|
||||
}
|
||||
if (cbacks.session_changed_cb_) {
|
||||
aidl_callbacks.session_changed_cb_ =
|
||||
[&session_legacy_callback_table](uint16_t cookie) {
|
||||
if (session_legacy_callback_table.find(cookie) ==
|
||||
session_legacy_callback_table.end()) {
|
||||
LOG(ERROR) << __func__ << ": Unknown callback invoked!";
|
||||
return;
|
||||
}
|
||||
auto& cback = session_legacy_callback_table[cookie];
|
||||
cback->session_changed_cb_(cookie);
|
||||
};
|
||||
};
|
||||
if (cbacks.audio_configuration_changed_cb_) {
|
||||
aidl_callbacks.audio_configuration_changed_cb_ =
|
||||
[&session_legacy_callback_table](uint16_t cookie) {
|
||||
if (session_legacy_callback_table.find(cookie) ==
|
||||
session_legacy_callback_table.end()) {
|
||||
LOG(ERROR) << __func__ << ": Unknown callback invoked!";
|
||||
return;
|
||||
}
|
||||
auto& cback = session_legacy_callback_table[cookie];
|
||||
cback->audio_configuration_changed_cb_(cookie);
|
||||
};
|
||||
};
|
||||
auto cookie = BluetoothAudioSessionControl::RegisterControlResultCback(
|
||||
aidl_session_type, aidl_callbacks);
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(legacy_callback_lock);
|
||||
session_legacy_callback_table[cookie] =
|
||||
std::make_shared<PortStatusCallbacks_2_2>(cbacks);
|
||||
}
|
||||
return cookie;
|
||||
}
|
||||
|
||||
void HidlToAidlMiddleware_2_2::UnregisterControlResultCback(
|
||||
const SessionType_2_1& session_type, uint16_t cookie) {
|
||||
LOG(INFO) << __func__ << ": " << toString(session_type);
|
||||
auto aidl_session_type = from_session_type_2_1(session_type);
|
||||
BluetoothAudioSessionControl::UnregisterControlResultCback(aidl_session_type,
|
||||
cookie);
|
||||
auto& session_callback_table = legacy_callback_table[aidl_session_type];
|
||||
if (session_callback_table.find(cookie) != session_callback_table.end()) {
|
||||
std::lock_guard<std::mutex> guard(legacy_callback_lock);
|
||||
session_callback_table.erase(cookie);
|
||||
}
|
||||
}
|
||||
|
||||
const AudioConfig_2_2 HidlToAidlMiddleware_2_2::GetAudioConfig(
|
||||
const SessionType_2_1& session_type) {
|
||||
return to_hidl_audio_config_2_2(BluetoothAudioSessionControl::GetAudioConfig(
|
||||
from_session_type_2_1(session_type)));
|
||||
}
|
||||
|
||||
bool HidlToAidlMiddleware_2_2::StartStream(
|
||||
const SessionType_2_1& session_type) {
|
||||
return BluetoothAudioSessionControl::StartStream(
|
||||
from_session_type_2_1(session_type));
|
||||
}
|
||||
|
||||
bool HidlToAidlMiddleware_2_2::SuspendStream(
|
||||
const SessionType_2_1& session_type) {
|
||||
return BluetoothAudioSessionControl::SuspendStream(
|
||||
from_session_type_2_1(session_type));
|
||||
}
|
||||
|
||||
void HidlToAidlMiddleware_2_2::StopStream(const SessionType_2_1& session_type) {
|
||||
return BluetoothAudioSessionControl::StopStream(
|
||||
from_session_type_2_1(session_type));
|
||||
}
|
||||
|
||||
void HidlToAidlMiddleware_2_2::UpdateSinkMetadata(
|
||||
const SessionType_2_1& session_type,
|
||||
const struct sink_metadata* sink_metadata) {
|
||||
return BluetoothAudioSessionControl::UpdateSinkMetadata(
|
||||
from_session_type_2_1(session_type), *sink_metadata);
|
||||
}
|
||||
|
||||
} // namespace audio
|
||||
} // namespace bluetooth
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* 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 <android/hardware/bluetooth/audio/2.0/types.h>
|
||||
|
||||
#include "../session/BluetoothAudioSession.h"
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace bluetooth {
|
||||
namespace audio {
|
||||
|
||||
using SessionType_2_0 =
|
||||
::android::hardware::bluetooth::audio::V2_0::SessionType;
|
||||
using PortStatusCallbacks_2_0 =
|
||||
::android::bluetooth::audio::PortStatusCallbacks;
|
||||
using AudioConfig_2_0 =
|
||||
::android::hardware::bluetooth::audio::V2_0::AudioConfiguration;
|
||||
|
||||
class HidlToAidlMiddleware_2_0 {
|
||||
public:
|
||||
static bool IsAidlAvailable();
|
||||
|
||||
static bool IsSessionReady(const SessionType_2_0& session_type);
|
||||
|
||||
static uint16_t RegisterControlResultCback(
|
||||
const SessionType_2_0& session_type,
|
||||
const PortStatusCallbacks_2_0& cbacks);
|
||||
|
||||
static void UnregisterControlResultCback(const SessionType_2_0& session_type,
|
||||
uint16_t cookie);
|
||||
|
||||
static const AudioConfig_2_0 GetAudioConfig(
|
||||
const SessionType_2_0& session_type);
|
||||
|
||||
static bool StartStream(const SessionType_2_0& session_type);
|
||||
|
||||
static void StopStream(const SessionType_2_0& session_type);
|
||||
|
||||
static bool SuspendStream(const SessionType_2_0& session_type);
|
||||
|
||||
static bool GetPresentationPosition(const SessionType_2_0& session_type,
|
||||
uint64_t* remote_delay_report_ns,
|
||||
uint64_t* total_bytes_readed,
|
||||
timespec* data_position);
|
||||
|
||||
static void UpdateTracksMetadata(
|
||||
const SessionType_2_0& session_type,
|
||||
const struct source_metadata* source_metadata);
|
||||
|
||||
static size_t OutWritePcmData(const SessionType_2_0& session_type,
|
||||
const void* buffer, size_t bytes);
|
||||
};
|
||||
|
||||
} // namespace audio
|
||||
} // namespace bluetooth
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* 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 <android/hardware/bluetooth/audio/2.1/types.h>
|
||||
|
||||
#include "../session/BluetoothAudioSession.h"
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace bluetooth {
|
||||
namespace audio {
|
||||
|
||||
using SessionType_2_1 =
|
||||
::android::hardware::bluetooth::audio::V2_1::SessionType;
|
||||
using AudioConfig_2_1 =
|
||||
::android::hardware::bluetooth::audio::V2_1::AudioConfiguration;
|
||||
|
||||
class HidlToAidlMiddleware_2_1 {
|
||||
public:
|
||||
static const AudioConfig_2_1 GetAudioConfig(
|
||||
const SessionType_2_1& session_type);
|
||||
};
|
||||
|
||||
} // namespace audio
|
||||
} // namespace bluetooth
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* 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 <android/hardware/bluetooth/audio/2.2/types.h>
|
||||
|
||||
#include "../session/BluetoothAudioSession.h"
|
||||
#include "../session/BluetoothAudioSession_2_2.h"
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace bluetooth {
|
||||
namespace audio {
|
||||
|
||||
using SessionType_2_1 =
|
||||
::android::hardware::bluetooth::audio::V2_1::SessionType;
|
||||
using PortStatusCallbacks_2_0 =
|
||||
::android::bluetooth::audio::PortStatusCallbacks;
|
||||
using PortStatusCallbacks_2_2 =
|
||||
::android::bluetooth::audio::PortStatusCallbacks_2_2;
|
||||
using AudioConfig_2_2 =
|
||||
::android::hardware::bluetooth::audio::V2_2::AudioConfiguration;
|
||||
|
||||
class HidlToAidlMiddleware_2_2 {
|
||||
public:
|
||||
static bool IsSessionReady(const SessionType_2_1& session_type);
|
||||
|
||||
static uint16_t RegisterControlResultCback(
|
||||
const SessionType_2_1& session_type,
|
||||
const PortStatusCallbacks_2_2& cbacks);
|
||||
|
||||
static void UnregisterControlResultCback(const SessionType_2_1& session_type,
|
||||
uint16_t cookie);
|
||||
|
||||
static const AudioConfig_2_2 GetAudioConfig(
|
||||
const SessionType_2_1& session_type);
|
||||
|
||||
static bool StartStream(const SessionType_2_1& session_type);
|
||||
|
||||
static bool SuspendStream(const SessionType_2_1& session_type);
|
||||
|
||||
static void StopStream(const SessionType_2_1& session_type);
|
||||
|
||||
static void UpdateSinkMetadata(const SessionType_2_1& session_type,
|
||||
const struct sink_metadata* sink_metadata);
|
||||
};
|
||||
|
||||
} // namespace audio
|
||||
} // namespace bluetooth
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
||||
@@ -21,10 +21,13 @@
|
||||
#include <android-base/logging.h>
|
||||
#include <android-base/stringprintf.h>
|
||||
|
||||
#include "../aidl_session/HidlToAidlMiddleware_2_0.h"
|
||||
|
||||
namespace android {
|
||||
namespace bluetooth {
|
||||
namespace audio {
|
||||
|
||||
using ::aidl::android::hardware::bluetooth::audio::HidlToAidlMiddleware_2_0;
|
||||
using ::android::hardware::audio::common::V5_0::AudioContentType;
|
||||
using ::android::hardware::audio::common::V5_0::AudioUsage;
|
||||
using ::android::hardware::audio::common::V5_0::PlaybackTrackMetadata;
|
||||
@@ -149,6 +152,8 @@ void BluetoothAudioSession::ReportControlStatus(
|
||||
// The function helps to check if this session is ready or not
|
||||
// @return: true if the Bluetooth stack has started the specified session
|
||||
bool BluetoothAudioSession::IsSessionReady() {
|
||||
if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
|
||||
return HidlToAidlMiddleware_2_0::IsSessionReady(session_type_);
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex_);
|
||||
bool dataMQ_valid =
|
||||
(session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH ||
|
||||
@@ -200,6 +205,9 @@ bool BluetoothAudioSession::UpdateAudioConfig(
|
||||
// @return: cookie - the assigned number to this bluetooth_audio output
|
||||
uint16_t BluetoothAudioSession::RegisterStatusCback(
|
||||
const PortStatusCallbacks& cbacks) {
|
||||
if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
|
||||
return HidlToAidlMiddleware_2_0::RegisterControlResultCback(session_type_,
|
||||
cbacks);
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex_);
|
||||
uint16_t cookie = ObserversCookieGetInitValue(session_type_);
|
||||
uint16_t cookie_upper_bound = ObserversCookieGetUpperBound(session_type_);
|
||||
@@ -227,6 +235,9 @@ uint16_t BluetoothAudioSession::RegisterStatusCback(
|
||||
// PortStatusCallbacks
|
||||
// @param: cookie - indicates which bluetooth_audio output is
|
||||
void BluetoothAudioSession::UnregisterStatusCback(uint16_t cookie) {
|
||||
if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
|
||||
return HidlToAidlMiddleware_2_0::UnregisterControlResultCback(session_type_,
|
||||
cookie);
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex_);
|
||||
if (observers_.erase(cookie) != 1) {
|
||||
LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_)
|
||||
@@ -238,6 +249,9 @@ void BluetoothAudioSession::UnregisterStatusCback(uint16_t cookie) {
|
||||
// The control function is for the bluetooth_audio module to get the current
|
||||
// AudioConfiguration
|
||||
const AudioConfiguration& BluetoothAudioSession::GetAudioConfig() {
|
||||
if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
|
||||
return (audio_config_ =
|
||||
HidlToAidlMiddleware_2_0::GetAudioConfig(session_type_));
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex_);
|
||||
if (IsSessionReady()) {
|
||||
return audio_config_;
|
||||
@@ -251,6 +265,8 @@ const AudioConfiguration& BluetoothAudioSession::GetAudioConfig() {
|
||||
// Those control functions are for the bluetooth_audio module to start, suspend,
|
||||
// stop stream, to check position, and to update metadata.
|
||||
bool BluetoothAudioSession::StartStream() {
|
||||
if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
|
||||
return HidlToAidlMiddleware_2_0::StartStream(session_type_);
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex_);
|
||||
if (!IsSessionReady()) {
|
||||
LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
|
||||
@@ -267,6 +283,8 @@ bool BluetoothAudioSession::StartStream() {
|
||||
}
|
||||
|
||||
bool BluetoothAudioSession::SuspendStream() {
|
||||
if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
|
||||
return HidlToAidlMiddleware_2_0::SuspendStream(session_type_);
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex_);
|
||||
if (!IsSessionReady()) {
|
||||
LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
|
||||
@@ -283,6 +301,8 @@ bool BluetoothAudioSession::SuspendStream() {
|
||||
}
|
||||
|
||||
void BluetoothAudioSession::StopStream() {
|
||||
if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
|
||||
return HidlToAidlMiddleware_2_0::StopStream(session_type_);
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex_);
|
||||
if (!IsSessionReady()) {
|
||||
return;
|
||||
@@ -297,6 +317,10 @@ void BluetoothAudioSession::StopStream() {
|
||||
bool BluetoothAudioSession::GetPresentationPosition(
|
||||
uint64_t* remote_delay_report_ns, uint64_t* total_bytes_readed,
|
||||
timespec* data_position) {
|
||||
if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
|
||||
return HidlToAidlMiddleware_2_0::GetPresentationPosition(
|
||||
session_type_, remote_delay_report_ns, total_bytes_readed,
|
||||
data_position);
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex_);
|
||||
if (!IsSessionReady()) {
|
||||
LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
|
||||
@@ -330,6 +354,9 @@ bool BluetoothAudioSession::GetPresentationPosition(
|
||||
|
||||
void BluetoothAudioSession::UpdateTracksMetadata(
|
||||
const struct source_metadata* source_metadata) {
|
||||
if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
|
||||
return HidlToAidlMiddleware_2_0::UpdateTracksMetadata(session_type_,
|
||||
source_metadata);
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex_);
|
||||
if (!IsSessionReady()) {
|
||||
LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
|
||||
@@ -374,6 +401,9 @@ void BluetoothAudioSession::UpdateTracksMetadata(
|
||||
// The control function writes stream to FMQ
|
||||
size_t BluetoothAudioSession::OutWritePcmData(const void* buffer,
|
||||
size_t bytes) {
|
||||
if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
|
||||
return HidlToAidlMiddleware_2_0::OutWritePcmData(session_type_, buffer,
|
||||
bytes);
|
||||
if (buffer == nullptr || !bytes) return 0;
|
||||
size_t totalWritten = 0;
|
||||
int ms_timeout = kFmqSendTimeoutMs;
|
||||
|
||||
@@ -21,9 +21,14 @@
|
||||
#include <android-base/logging.h>
|
||||
#include <android-base/stringprintf.h>
|
||||
|
||||
#include "../aidl_session/HidlToAidlMiddleware_2_0.h"
|
||||
#include "../aidl_session/HidlToAidlMiddleware_2_1.h"
|
||||
|
||||
namespace android {
|
||||
namespace bluetooth {
|
||||
namespace audio {
|
||||
using ::aidl::android::hardware::bluetooth::audio::HidlToAidlMiddleware_2_0;
|
||||
using ::aidl::android::hardware::bluetooth::audio::HidlToAidlMiddleware_2_1;
|
||||
using SessionType_2_1 =
|
||||
::android::hardware::bluetooth::audio::V2_1::SessionType;
|
||||
using SessionType_2_0 =
|
||||
@@ -72,6 +77,7 @@ BluetoothAudioSession_2_1::BluetoothAudioSession_2_1(
|
||||
} else {
|
||||
session_type_2_1_ = (session_type);
|
||||
}
|
||||
raw_session_type_ = session_type;
|
||||
}
|
||||
|
||||
std::shared_ptr<BluetoothAudioSession>
|
||||
@@ -83,6 +89,8 @@ BluetoothAudioSession_2_1::GetAudioSession() {
|
||||
// AudioConfiguration
|
||||
const ::android::hardware::bluetooth::audio::V2_1::AudioConfiguration
|
||||
BluetoothAudioSession_2_1::GetAudioConfig() {
|
||||
if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
|
||||
return HidlToAidlMiddleware_2_1::GetAudioConfig(raw_session_type_);
|
||||
std::lock_guard<std::recursive_mutex> guard(audio_session->mutex_);
|
||||
if (audio_session->IsSessionReady()) {
|
||||
// If session is unknown it means it should be 2.0 type
|
||||
|
||||
@@ -31,6 +31,7 @@ class BluetoothAudioSession_2_1 {
|
||||
std::shared_ptr<BluetoothAudioSession> audio_session;
|
||||
|
||||
::android::hardware::bluetooth::audio::V2_1::SessionType session_type_2_1_;
|
||||
::android::hardware::bluetooth::audio::V2_1::SessionType raw_session_type_;
|
||||
|
||||
// audio data configuration for both software and offloading
|
||||
::android::hardware::bluetooth::audio::V2_1::AudioConfiguration
|
||||
|
||||
@@ -22,10 +22,15 @@
|
||||
#include <android-base/stringprintf.h>
|
||||
#include <android/hardware/bluetooth/audio/2.2/IBluetoothAudioPort.h>
|
||||
|
||||
#include "../aidl_session/HidlToAidlMiddleware_2_0.h"
|
||||
#include "../aidl_session/HidlToAidlMiddleware_2_2.h"
|
||||
|
||||
namespace android {
|
||||
namespace bluetooth {
|
||||
namespace audio {
|
||||
|
||||
using ::aidl::android::hardware::bluetooth::audio::HidlToAidlMiddleware_2_0;
|
||||
using ::aidl::android::hardware::bluetooth::audio::HidlToAidlMiddleware_2_2;
|
||||
using ::android::hardware::audio::common::V5_0::AudioSource;
|
||||
using ::android::hardware::audio::common::V5_0::RecordTrackMetadata;
|
||||
using ::android::hardware::audio::common::V5_0::SinkMetadata;
|
||||
@@ -93,6 +98,7 @@ BluetoothAudioSession_2_2::BluetoothAudioSession_2_2(
|
||||
} else {
|
||||
session_type_2_1_ = (session_type);
|
||||
}
|
||||
raw_session_type_ = session_type;
|
||||
invalidSoftwareAudioConfiguration.pcmConfig(kInvalidPcmParameters);
|
||||
invalidOffloadAudioConfiguration.codecConfig(
|
||||
audio_session->kInvalidCodecConfiguration);
|
||||
@@ -100,6 +106,8 @@ BluetoothAudioSession_2_2::BluetoothAudioSession_2_2(
|
||||
}
|
||||
|
||||
bool BluetoothAudioSession_2_2::IsSessionReady() {
|
||||
if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
|
||||
return HidlToAidlMiddleware_2_2::IsSessionReady(raw_session_type_);
|
||||
if (session_type_2_1_ !=
|
||||
SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH &&
|
||||
session_type_2_1_ !=
|
||||
@@ -122,6 +130,9 @@ BluetoothAudioSession_2_2::GetAudioSession_2_1() {
|
||||
|
||||
void BluetoothAudioSession_2_2::UpdateSinkMetadata(
|
||||
const struct sink_metadata* sink_metadata) {
|
||||
if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
|
||||
return HidlToAidlMiddleware_2_2::UpdateSinkMetadata(raw_session_type_,
|
||||
sink_metadata);
|
||||
std::lock_guard<std::recursive_mutex> guard(audio_session->mutex_);
|
||||
if (!IsSessionReady()) {
|
||||
LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_2_1_)
|
||||
@@ -172,6 +183,8 @@ void BluetoothAudioSession_2_2::UpdateSinkMetadata(
|
||||
// AudioConfiguration
|
||||
const ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration
|
||||
BluetoothAudioSession_2_2::GetAudioConfig() {
|
||||
if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
|
||||
return HidlToAidlMiddleware_2_2::GetAudioConfig(raw_session_type_);
|
||||
std::lock_guard<std::recursive_mutex> guard(audio_session->mutex_);
|
||||
if (IsSessionReady()) {
|
||||
auto audio_config_discriminator = audio_config_2_2_.getDiscriminator();
|
||||
@@ -226,6 +239,8 @@ BluetoothAudioSession_2_2::GetAudioConfig() {
|
||||
// Those control functions are for the bluetooth_audio module to start, suspend,
|
||||
// stop stream, to check position, and to update metadata.
|
||||
bool BluetoothAudioSession_2_2::StartStream() {
|
||||
if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
|
||||
return HidlToAidlMiddleware_2_2::StartStream(raw_session_type_);
|
||||
std::lock_guard<std::recursive_mutex> guard(audio_session->mutex_);
|
||||
if (!IsSessionReady()) {
|
||||
LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_2_1_)
|
||||
@@ -242,6 +257,8 @@ bool BluetoothAudioSession_2_2::StartStream() {
|
||||
}
|
||||
|
||||
bool BluetoothAudioSession_2_2::SuspendStream() {
|
||||
if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
|
||||
return HidlToAidlMiddleware_2_2::SuspendStream(raw_session_type_);
|
||||
std::lock_guard<std::recursive_mutex> guard(audio_session->mutex_);
|
||||
if (!IsSessionReady()) {
|
||||
LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_2_1_)
|
||||
@@ -258,6 +275,8 @@ bool BluetoothAudioSession_2_2::SuspendStream() {
|
||||
}
|
||||
|
||||
void BluetoothAudioSession_2_2::StopStream() {
|
||||
if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
|
||||
return HidlToAidlMiddleware_2_2::StopStream(raw_session_type_);
|
||||
std::lock_guard<std::recursive_mutex> guard(audio_session->mutex_);
|
||||
if (!IsSessionReady()) {
|
||||
return;
|
||||
@@ -395,6 +414,9 @@ void BluetoothAudioSession_2_2::OnSessionEnded() {
|
||||
// @return: cookie - the assigned number to this bluetooth_audio output
|
||||
uint16_t BluetoothAudioSession_2_2::RegisterStatusCback(
|
||||
const PortStatusCallbacks_2_2& cbacks) {
|
||||
if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
|
||||
return HidlToAidlMiddleware_2_2::RegisterControlResultCback(
|
||||
raw_session_type_, cbacks);
|
||||
if (session_type_2_1_ !=
|
||||
SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH &&
|
||||
session_type_2_1_ !=
|
||||
@@ -432,6 +454,9 @@ uint16_t BluetoothAudioSession_2_2::RegisterStatusCback(
|
||||
// PortStatusCallbacks_2_2
|
||||
// @param: cookie - indicates which bluetooth_audio output is
|
||||
void BluetoothAudioSession_2_2::UnregisterStatusCback(uint16_t cookie) {
|
||||
if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
|
||||
return HidlToAidlMiddleware_2_2::UnregisterControlResultCback(
|
||||
raw_session_type_, cookie);
|
||||
std::lock_guard<std::recursive_mutex> guard(audio_session->mutex_);
|
||||
if (session_type_2_1_ !=
|
||||
SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH &&
|
||||
|
||||
@@ -68,6 +68,7 @@ class BluetoothAudioSession_2_2 {
|
||||
std::shared_ptr<BluetoothAudioSession_2_1> audio_session_2_1;
|
||||
|
||||
::android::hardware::bluetooth::audio::V2_1::SessionType session_type_2_1_;
|
||||
::android::hardware::bluetooth::audio::V2_1::SessionType raw_session_type_;
|
||||
|
||||
// audio data configuration for both software and offloading
|
||||
::android::hardware::bluetooth::audio::V2_2::AudioConfiguration
|
||||
|
||||
Reference in New Issue
Block a user