1 /*
2 * Copyright (C) 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <algorithm>
18
19 #define LOG_TAG "AHAL_StreamBluetooth"
20 #include <Utils.h>
21 #include <android-base/logging.h>
22 #include <audio_utils/clock.h>
23
24 #include "core-impl/StreamBluetooth.h"
25
26 using aidl::android::hardware::audio::common::SinkMetadata;
27 using aidl::android::hardware::audio::common::SourceMetadata;
28 using aidl::android::hardware::audio::core::VendorParameter;
29 using aidl::android::hardware::bluetooth::audio::ChannelMode;
30 using aidl::android::hardware::bluetooth::audio::PcmConfiguration;
31 using aidl::android::hardware::bluetooth::audio::PresentationPosition;
32 using aidl::android::media::audio::common::AudioChannelLayout;
33 using aidl::android::media::audio::common::AudioConfigBase;
34 using aidl::android::media::audio::common::AudioDevice;
35 using aidl::android::media::audio::common::AudioDeviceAddress;
36 using aidl::android::media::audio::common::AudioFormatDescription;
37 using aidl::android::media::audio::common::AudioFormatType;
38 using aidl::android::media::audio::common::AudioOffloadInfo;
39 using aidl::android::media::audio::common::MicrophoneDynamicInfo;
40 using aidl::android::media::audio::common::MicrophoneInfo;
41 using android::bluetooth::audio::aidl::BluetoothAudioPortAidl;
42 using android::bluetooth::audio::aidl::BluetoothAudioPortAidlIn;
43 using android::bluetooth::audio::aidl::BluetoothAudioPortAidlOut;
44 using android::bluetooth::audio::aidl::BluetoothStreamState;
45
46 namespace aidl::android::hardware::audio::core {
47
48 constexpr int kBluetoothDefaultInputBufferMs = 20;
49 constexpr int kBluetoothDefaultOutputBufferMs = 10;
50 // constexpr int kBluetoothSpatializerOutputBufferMs = 10;
51 constexpr int kBluetoothDefaultRemoteDelayMs = 200;
52
StreamBluetooth(StreamContext * context,const Metadata & metadata,ModuleBluetooth::BtProfileHandles && btHandles,const std::shared_ptr<BluetoothAudioPortAidl> & btDeviceProxy,const PcmConfiguration & pcmConfig)53 StreamBluetooth::StreamBluetooth(StreamContext* context, const Metadata& metadata,
54 ModuleBluetooth::BtProfileHandles&& btHandles,
55 const std::shared_ptr<BluetoothAudioPortAidl>& btDeviceProxy,
56 const PcmConfiguration& pcmConfig)
57 : StreamCommonImpl(context, metadata),
58 mFrameSizeBytes(getContext().getFrameSize()),
59 mIsInput(isInput(metadata)),
60 mBluetoothA2dp(std::move(std::get<ModuleBluetooth::BtInterface::BTA2DP>(btHandles))),
61 mBluetoothLe(std::move(std::get<ModuleBluetooth::BtInterface::BTLE>(btHandles))),
62 mPreferredDataIntervalUs(pcmConfig.dataIntervalUs != 0
63 ? pcmConfig.dataIntervalUs
64 : (mIsInput ? kBluetoothDefaultInputBufferMs
65 : kBluetoothDefaultOutputBufferMs) *
66 1000),
67 mBtDeviceProxy(btDeviceProxy) {}
68
~StreamBluetooth()69 StreamBluetooth::~StreamBluetooth() {
70 cleanupWorker();
71 }
72
init()73 ::android::status_t StreamBluetooth::init() {
74 std::lock_guard guard(mLock);
75 if (mBtDeviceProxy == nullptr) {
76 // This is a normal situation in VTS tests.
77 LOG(INFO) << __func__ << ": no BT HAL proxy, stream is non-functional";
78 }
79 LOG(INFO) << __func__ << ": preferred data interval (us): " << mPreferredDataIntervalUs;
80 return ::android::OK;
81 }
82
drain(StreamDescriptor::DrainMode)83 ::android::status_t StreamBluetooth::drain(StreamDescriptor::DrainMode) {
84 usleep(1000);
85 return ::android::OK;
86 }
87
flush()88 ::android::status_t StreamBluetooth::flush() {
89 usleep(1000);
90 return ::android::OK;
91 }
92
pause()93 ::android::status_t StreamBluetooth::pause() {
94 return standby();
95 }
96
transfer(void * buffer,size_t frameCount,size_t * actualFrameCount,int32_t * latencyMs)97 ::android::status_t StreamBluetooth::transfer(void* buffer, size_t frameCount,
98 size_t* actualFrameCount, int32_t* latencyMs) {
99 std::lock_guard guard(mLock);
100 *actualFrameCount = 0;
101 *latencyMs = StreamDescriptor::LATENCY_UNKNOWN;
102 if (mBtDeviceProxy == nullptr || mBtDeviceProxy->getState() == BluetoothStreamState::DISABLED) {
103 // The BT session is turned down, silently ignore write.
104 return ::android::OK;
105 }
106 if (!mBtDeviceProxy->start()) {
107 LOG(WARNING) << __func__ << ": state= " << mBtDeviceProxy->getState()
108 << " failed to start, will retry";
109 return ::android::OK;
110 }
111 *latencyMs = 0;
112 const size_t bytesToTransfer = frameCount * mFrameSizeBytes;
113 const size_t bytesTransferred = mIsInput ? mBtDeviceProxy->readData(buffer, bytesToTransfer)
114 : mBtDeviceProxy->writeData(buffer, bytesToTransfer);
115 *actualFrameCount = bytesTransferred / mFrameSizeBytes;
116 PresentationPosition presentation_position;
117 if (!mBtDeviceProxy->getPresentationPosition(presentation_position)) {
118 presentation_position.remoteDeviceAudioDelayNanos =
119 kBluetoothDefaultRemoteDelayMs * NANOS_PER_MILLISECOND;
120 LOG(WARNING) << __func__ << ": getPresentationPosition failed, latency info is unavailable";
121 }
122 // TODO(b/317117580): incorporate logic from
123 // packages/modules/Bluetooth/system/audio_bluetooth_hw/stream_apis.cc
124 // out_calculate_feeding_delay_ms / in_calculate_starving_delay_ms
125 *latencyMs = std::max(*latencyMs, (int32_t)(presentation_position.remoteDeviceAudioDelayNanos /
126 NANOS_PER_MILLISECOND));
127 return ::android::OK;
128 }
129
130 // static
checkConfigParams(const PcmConfiguration & pcmConfig,const AudioConfigBase & config)131 bool StreamBluetooth::checkConfigParams(const PcmConfiguration& pcmConfig,
132 const AudioConfigBase& config) {
133 if ((int)config.sampleRate != pcmConfig.sampleRateHz) {
134 LOG(ERROR) << __func__ << ": sample rate mismatch, stream value=" << config.sampleRate
135 << ", BT HAL value=" << pcmConfig.sampleRateHz;
136 return false;
137 }
138 const auto channelCount =
139 aidl::android::hardware::audio::common::getChannelCount(config.channelMask);
140 if ((pcmConfig.channelMode == ChannelMode::MONO && channelCount != 1) ||
141 (pcmConfig.channelMode == ChannelMode::STEREO && channelCount != 2)) {
142 LOG(ERROR) << __func__ << ": Channel count mismatch, stream value=" << channelCount
143 << ", BT HAL value=" << toString(pcmConfig.channelMode);
144 return false;
145 }
146 if (config.format.type != AudioFormatType::PCM) {
147 LOG(ERROR) << __func__
148 << ": unexpected stream format type: " << toString(config.format.type);
149 return false;
150 }
151 const int8_t bitsPerSample =
152 aidl::android::hardware::audio::common::getPcmSampleSizeInBytes(config.format.pcm) * 8;
153 if (bitsPerSample != pcmConfig.bitsPerSample) {
154 LOG(ERROR) << __func__ << ": bits per sample mismatch, stream value=" << bitsPerSample
155 << ", BT HAL value=" << pcmConfig.bitsPerSample;
156 return false;
157 }
158 return true;
159 }
160
prepareToClose()161 ndk::ScopedAStatus StreamBluetooth::prepareToClose() {
162 std::lock_guard guard(mLock);
163 if (mBtDeviceProxy != nullptr) {
164 if (mBtDeviceProxy->getState() != BluetoothStreamState::DISABLED) {
165 mBtDeviceProxy->stop();
166 }
167 }
168 return ndk::ScopedAStatus::ok();
169 }
170
standby()171 ::android::status_t StreamBluetooth::standby() {
172 std::lock_guard guard(mLock);
173 if (mBtDeviceProxy != nullptr) mBtDeviceProxy->suspend();
174 return ::android::OK;
175 }
176
start()177 ::android::status_t StreamBluetooth::start() {
178 std::lock_guard guard(mLock);
179 if (mBtDeviceProxy != nullptr) mBtDeviceProxy->start();
180 return ::android::OK;
181 }
182
shutdown()183 void StreamBluetooth::shutdown() {
184 std::lock_guard guard(mLock);
185 if (mBtDeviceProxy != nullptr) {
186 mBtDeviceProxy->stop();
187 mBtDeviceProxy = nullptr;
188 }
189 }
190
updateMetadataCommon(const Metadata & metadata)191 ndk::ScopedAStatus StreamBluetooth::updateMetadataCommon(const Metadata& metadata) {
192 std::lock_guard guard(mLock);
193 if (mBtDeviceProxy == nullptr) {
194 return ndk::ScopedAStatus::ok();
195 }
196 bool isOk = true;
197 if (isInput(metadata)) {
198 isOk = mBtDeviceProxy->updateSinkMetadata(std::get<SinkMetadata>(metadata));
199 } else {
200 isOk = mBtDeviceProxy->updateSourceMetadata(std::get<SourceMetadata>(metadata));
201 }
202 return isOk ? ndk::ScopedAStatus::ok()
203 : ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
204 }
205
bluetoothParametersUpdated()206 ndk::ScopedAStatus StreamBluetooth::bluetoothParametersUpdated() {
207 if (mIsInput) {
208 return ndk::ScopedAStatus::ok();
209 }
210 auto applyParam = [](const std::shared_ptr<BluetoothAudioPortAidl>& proxy,
211 bool isEnabled) -> bool {
212 if (!isEnabled) {
213 if (proxy->suspend()) return proxy->setState(BluetoothStreamState::DISABLED);
214 return false;
215 }
216 return proxy->standby();
217 };
218 bool hasA2dpParam, enableA2dp;
219 auto btA2dp = mBluetoothA2dp.lock();
220 hasA2dpParam = btA2dp != nullptr && btA2dp->isEnabled(&enableA2dp).isOk();
221 bool hasLeParam, enableLe;
222 auto btLe = mBluetoothLe.lock();
223 hasLeParam = btLe != nullptr && btLe->isEnabled(&enableLe).isOk();
224 std::lock_guard guard(mLock);
225 if (mBtDeviceProxy != nullptr) {
226 if ((hasA2dpParam && mBtDeviceProxy->isA2dp() && !applyParam(mBtDeviceProxy, enableA2dp)) ||
227 (hasLeParam && mBtDeviceProxy->isLeAudio() && !applyParam(mBtDeviceProxy, enableLe))) {
228 LOG(DEBUG) << __func__ << ": applyParam failed";
229 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
230 }
231 }
232 return ndk::ScopedAStatus::ok();
233 }
234
235 // static
getNominalLatencyMs(size_t dataIntervalUs)236 int32_t StreamInBluetooth::getNominalLatencyMs(size_t dataIntervalUs) {
237 if (dataIntervalUs == 0) dataIntervalUs = kBluetoothDefaultInputBufferMs * 1000LL;
238 return dataIntervalUs / 1000LL;
239 }
240
StreamInBluetooth(StreamContext && context,const SinkMetadata & sinkMetadata,const std::vector<MicrophoneInfo> & microphones,ModuleBluetooth::BtProfileHandles && btProfileHandles,const std::shared_ptr<BluetoothAudioPortAidl> & btDeviceProxy,const PcmConfiguration & pcmConfig)241 StreamInBluetooth::StreamInBluetooth(StreamContext&& context, const SinkMetadata& sinkMetadata,
242 const std::vector<MicrophoneInfo>& microphones,
243 ModuleBluetooth::BtProfileHandles&& btProfileHandles,
244 const std::shared_ptr<BluetoothAudioPortAidl>& btDeviceProxy,
245 const PcmConfiguration& pcmConfig)
246 : StreamIn(std::move(context), microphones),
247 StreamBluetooth(&mContextInstance, sinkMetadata, std::move(btProfileHandles), btDeviceProxy,
248 pcmConfig) {}
249
getActiveMicrophones(std::vector<MicrophoneDynamicInfo> * _aidl_return __unused)250 ndk::ScopedAStatus StreamInBluetooth::getActiveMicrophones(
251 std::vector<MicrophoneDynamicInfo>* _aidl_return __unused) {
252 LOG(DEBUG) << __func__ << ": not supported";
253 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
254 }
255
256 // static
getNominalLatencyMs(size_t dataIntervalUs)257 int32_t StreamOutBluetooth::getNominalLatencyMs(size_t dataIntervalUs) {
258 if (dataIntervalUs == 0) dataIntervalUs = kBluetoothDefaultOutputBufferMs * 1000LL;
259 return dataIntervalUs / 1000LL;
260 }
261
StreamOutBluetooth(StreamContext && context,const SourceMetadata & sourceMetadata,const std::optional<AudioOffloadInfo> & offloadInfo,ModuleBluetooth::BtProfileHandles && btProfileHandles,const std::shared_ptr<BluetoothAudioPortAidl> & btDeviceProxy,const PcmConfiguration & pcmConfig)262 StreamOutBluetooth::StreamOutBluetooth(StreamContext&& context,
263 const SourceMetadata& sourceMetadata,
264 const std::optional<AudioOffloadInfo>& offloadInfo,
265 ModuleBluetooth::BtProfileHandles&& btProfileHandles,
266 const std::shared_ptr<BluetoothAudioPortAidl>& btDeviceProxy,
267 const PcmConfiguration& pcmConfig)
268 : StreamOut(std::move(context), offloadInfo),
269 StreamBluetooth(&mContextInstance, sourceMetadata, std::move(btProfileHandles), btDeviceProxy,
270 pcmConfig) {}
271
272 } // namespace aidl::android::hardware::audio::core
273