blob: 8cb93e3ceab27a607c367cea3ea2734c500068f2 [file] [log] [blame]
Mikhail Naganovb03b5c42023-07-26 13:13:35 -07001/*
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#define LOG_TAG "AHAL_StreamBluetooth"
18
19#include <Utils.h>
20#include <android-base/logging.h>
21#include <audio_utils/clock.h>
22
23#include "BluetoothAudioSessionControl.h"
24#include "core-impl/StreamBluetooth.h"
25
26namespace aidl::android::hardware::audio::core {
27
28using ::aidl::android::hardware::audio::common::SinkMetadata;
29using ::aidl::android::hardware::audio::common::SourceMetadata;
30using ::aidl::android::hardware::audio::core::VendorParameter;
31using ::aidl::android::hardware::bluetooth::audio::ChannelMode;
32using ::aidl::android::hardware::bluetooth::audio::PcmConfiguration;
33using ::aidl::android::hardware::bluetooth::audio::PresentationPosition;
34using ::aidl::android::media::audio::common::AudioChannelLayout;
35using ::aidl::android::media::audio::common::AudioDevice;
36using ::aidl::android::media::audio::common::AudioDeviceAddress;
37using ::aidl::android::media::audio::common::AudioFormatDescription;
38using ::aidl::android::media::audio::common::AudioFormatType;
39using ::aidl::android::media::audio::common::AudioOffloadInfo;
40using ::aidl::android::media::audio::common::MicrophoneDynamicInfo;
41using ::aidl::android::media::audio::common::MicrophoneInfo;
42using ::android::bluetooth::audio::aidl::BluetoothAudioPortAidl;
43using ::android::bluetooth::audio::aidl::BluetoothAudioPortAidlIn;
44using ::android::bluetooth::audio::aidl::BluetoothAudioPortAidlOut;
45using ::android::bluetooth::audio::aidl::BluetoothStreamState;
46
47constexpr int kBluetoothDefaultInputBufferMs = 20;
48constexpr int kBluetoothDefaultOutputBufferMs = 10;
49// constexpr int kBluetoothSpatializerOutputBufferMs = 10;
50
51size_t getFrameCount(uint64_t durationUs, uint32_t sampleRate) {
52 return (durationUs * sampleRate) / 1000000;
53}
54
55// pcm configuration params are not really used by the module
Ram Mohan18f0d512023-07-01 00:47:09 +053056StreamBluetooth::StreamBluetooth(StreamContext* context, const Metadata& metadata,
57 Module::BtProfileHandles&& btHandles)
Mikhail Naganovb03b5c42023-07-26 13:13:35 -070058 : StreamCommonImpl(context, metadata),
59 mSampleRate(getContext().getSampleRate()),
60 mChannelLayout(getContext().getChannelLayout()),
61 mFormat(getContext().getFormat()),
62 mFrameSizeBytes(getContext().getFrameSize()),
Ram Mohan18f0d512023-07-01 00:47:09 +053063 mIsInput(isInput(metadata)),
64 mBluetoothA2dp(std::move(std::get<Module::BtInterface::BTA2DP>(btHandles))),
65 mBluetoothLe(std::move(std::get<Module::BtInterface::BTLE>(btHandles))) {
Mikhail Naganovb03b5c42023-07-26 13:13:35 -070066 mPreferredDataIntervalUs =
67 mIsInput ? kBluetoothDefaultInputBufferMs : kBluetoothDefaultOutputBufferMs;
68 mPreferredFrameCount = getFrameCount(mPreferredDataIntervalUs, mSampleRate);
69 mIsInitialized = false;
70 mIsReadyToClose = false;
71}
72
73::android::status_t StreamBluetooth::init() {
74 return ::android::OK; // defering this till we get AudioDeviceDescription
75}
76
77const StreamCommonInterface::ConnectedDevices& StreamBluetooth::getConnectedDevices() const {
78 std::lock_guard guard(mLock);
79 return StreamCommonImpl::getConnectedDevices();
80}
81
82ndk::ScopedAStatus StreamBluetooth::setConnectedDevices(
83 const std::vector<AudioDevice>& connectedDevices) {
84 if (mIsInput && connectedDevices.size() > 1) {
85 LOG(ERROR) << __func__ << ": wrong device size(" << connectedDevices.size()
86 << ") for input stream";
87 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
88 }
89 for (const auto& connectedDevice : connectedDevices) {
90 if (connectedDevice.address.getTag() != AudioDeviceAddress::mac) {
91 LOG(ERROR) << __func__ << ": bad device address" << connectedDevice.address.toString();
92 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
93 }
94 }
95 std::lock_guard guard(mLock);
96 RETURN_STATUS_IF_ERROR(StreamCommonImpl::setConnectedDevices(connectedDevices));
97 mIsInitialized = false; // updated connected device list, need initialization
98 return ndk::ScopedAStatus::ok();
99}
100
101::android::status_t StreamBluetooth::drain(StreamDescriptor::DrainMode) {
102 usleep(1000);
103 return ::android::OK;
104}
105
106::android::status_t StreamBluetooth::flush() {
107 usleep(1000);
108 return ::android::OK;
109}
110
111::android::status_t StreamBluetooth::pause() {
112 return standby();
113}
114
115::android::status_t StreamBluetooth::transfer(void* buffer, size_t frameCount,
116 size_t* actualFrameCount, int32_t* latencyMs) {
117 std::lock_guard guard(mLock);
118 if (!mIsInitialized || mIsReadyToClose) {
119 // 'setConnectedDevices' has been called or stream is ready to close, so no transfers
120 *actualFrameCount = 0;
121 *latencyMs = StreamDescriptor::LATENCY_UNKNOWN;
122 return ::android::OK;
123 }
124 *actualFrameCount = 0;
125 *latencyMs = 0;
126 for (auto proxy : mBtDeviceProxies) {
127 if (!proxy->start()) {
128 LOG(ERROR) << __func__ << ": state = " << proxy->getState() << " failed to start ";
129 return -EIO;
130 }
131 const size_t fc = std::min(frameCount, mPreferredFrameCount);
132 const size_t bytesToTransfer = fc * mFrameSizeBytes;
133 if (mIsInput) {
134 const size_t totalRead = proxy->readData(buffer, bytesToTransfer);
135 *actualFrameCount = std::max(*actualFrameCount, totalRead / mFrameSizeBytes);
136 } else {
137 const size_t totalWrite = proxy->writeData(buffer, bytesToTransfer);
138 *actualFrameCount = std::max(*actualFrameCount, totalWrite / mFrameSizeBytes);
139 }
140 PresentationPosition presentation_position;
141 if (!proxy->getPresentationPosition(presentation_position)) {
142 LOG(ERROR) << __func__ << ": getPresentationPosition returned error ";
143 return ::android::UNKNOWN_ERROR;
144 }
145 *latencyMs =
146 std::max(*latencyMs, (int32_t)(presentation_position.remoteDeviceAudioDelayNanos /
147 NANOS_PER_MILLISECOND));
148 }
149 return ::android::OK;
150}
151
152::android::status_t StreamBluetooth::initialize() {
153 if (!::aidl::android::hardware::bluetooth::audio::BluetoothAudioSession::IsAidlAvailable()) {
154 LOG(ERROR) << __func__ << ": IBluetoothAudioProviderFactory service not available";
155 return ::android::UNKNOWN_ERROR;
156 }
157 if (StreamCommonImpl::getConnectedDevices().empty()) {
158 LOG(ERROR) << __func__ << ", has no connected devices";
159 return ::android::NO_INIT;
160 }
161 // unregister older proxies (if any)
162 for (auto proxy : mBtDeviceProxies) {
163 proxy->stop();
164 proxy->unregisterPort();
165 }
166 mBtDeviceProxies.clear();
167 for (auto it = StreamCommonImpl::getConnectedDevices().begin();
168 it != StreamCommonImpl::getConnectedDevices().end(); ++it) {
169 std::shared_ptr<BluetoothAudioPortAidl> proxy =
170 mIsInput ? std::shared_ptr<BluetoothAudioPortAidl>(
171 std::make_shared<BluetoothAudioPortAidlIn>())
172 : std::shared_ptr<BluetoothAudioPortAidl>(
173 std::make_shared<BluetoothAudioPortAidlOut>());
174 if (proxy->registerPort(it->type)) {
175 LOG(ERROR) << __func__ << ": cannot init HAL";
176 return ::android::UNKNOWN_ERROR;
177 }
178 PcmConfiguration config;
179 if (!proxy->loadAudioConfig(&config)) {
180 LOG(ERROR) << __func__ << ": state=" << proxy->getState()
181 << " failed to get audio config";
182 return ::android::UNKNOWN_ERROR;
183 }
184 // TODO: Ensure minimum duration for spatialized output?
185 // WAR to support Mono / 16 bits per sample as the Bluetooth stack required
186 if (!mIsInput && config.channelMode == ChannelMode::MONO && config.bitsPerSample == 16) {
187 proxy->forcePcmStereoToMono(true);
188 config.channelMode = ChannelMode::STEREO;
189 LOG(INFO) << __func__ << ": force channels = to be AUDIO_CHANNEL_OUT_STEREO";
190 }
191 if (!checkConfigParams(config)) {
192 LOG(ERROR) << __func__ << " checkConfigParams failed";
193 return ::android::UNKNOWN_ERROR;
194 }
195 mBtDeviceProxies.push_back(std::move(proxy));
196 }
197 mIsInitialized = true;
198 return ::android::OK;
199}
200
201bool StreamBluetooth::checkConfigParams(
202 ::aidl::android::hardware::bluetooth::audio::PcmConfiguration& config) {
203 if ((int)mSampleRate != config.sampleRateHz) {
204 LOG(ERROR) << __func__ << ": Sample Rate mismatch, stream val = " << mSampleRate
205 << " hal val = " << config.sampleRateHz;
206 return false;
207 }
208 auto channelCount = aidl::android::hardware::audio::common::getChannelCount(mChannelLayout);
209 if ((config.channelMode == ChannelMode::MONO && channelCount != 1) ||
210 (config.channelMode == ChannelMode::STEREO && channelCount != 2)) {
211 LOG(ERROR) << __func__ << ": Channel count mismatch, stream val = " << channelCount
212 << " hal val = " << toString(config.channelMode);
213 return false;
214 }
215 if (mFormat.type != AudioFormatType::PCM) {
216 LOG(ERROR) << __func__ << ": unexpected format type "
217 << aidl::android::media::audio::common::toString(mFormat.type);
218 return false;
219 }
220 int8_t bps = aidl::android::hardware::audio::common::getPcmSampleSizeInBytes(mFormat.pcm) * 8;
221 if (bps != config.bitsPerSample) {
222 LOG(ERROR) << __func__ << ": bits per sample mismatch, stream val = " << bps
223 << " hal val = " << config.bitsPerSample;
224 return false;
225 }
226 if (config.dataIntervalUs > 0) {
227 mPreferredDataIntervalUs =
228 std::min((int32_t)mPreferredDataIntervalUs, config.dataIntervalUs);
229 mPreferredFrameCount = getFrameCount(mPreferredDataIntervalUs, mSampleRate);
230 }
231 return true;
232}
233
234ndk::ScopedAStatus StreamBluetooth::prepareToClose() {
235 std::lock_guard guard(mLock);
236 mIsReadyToClose = true;
237 return ndk::ScopedAStatus::ok();
238}
239
240::android::status_t StreamBluetooth::standby() {
241 std::lock_guard guard(mLock);
242 if (!mIsInitialized) {
243 if (auto status = initialize(); status != ::android::OK) return status;
244 }
245 for (auto proxy : mBtDeviceProxies) {
246 if (!proxy->suspend()) {
247 LOG(ERROR) << __func__ << ": state = " << proxy->getState() << " failed to stand by ";
248 return -EIO;
249 }
250 }
251 return ::android::OK;
252}
253
254::android::status_t StreamBluetooth::start() {
255 std::lock_guard guard(mLock);
256 if (!mIsInitialized) return initialize();
257 return ::android::OK;
258}
259
260void StreamBluetooth::shutdown() {
261 std::lock_guard guard(mLock);
262 for (auto proxy : mBtDeviceProxies) {
263 proxy->stop();
264 proxy->unregisterPort();
265 }
266 mBtDeviceProxies.clear();
267}
268
269ndk::ScopedAStatus StreamBluetooth::updateMetadataCommon(const Metadata& metadata) {
270 std::lock_guard guard(mLock);
271 if (!mIsInitialized) return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
272 bool isOk = true;
273 if (isInput(metadata)) {
274 isOk = mBtDeviceProxies[0]->updateSinkMetadata(std::get<SinkMetadata>(metadata));
275 } else {
276 for (auto proxy : mBtDeviceProxies) {
277 if (!proxy->updateSourceMetadata(std::get<SourceMetadata>(metadata))) isOk = false;
278 }
279 }
280 return isOk ? ndk::ScopedAStatus::ok()
281 : ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
282}
283
Ram Mohan18f0d512023-07-01 00:47:09 +0530284ndk::ScopedAStatus StreamBluetooth::bluetoothParametersUpdated() {
285 if (mIsInput) {
286 LOG(WARNING) << __func__ << ": not handled";
287 return ndk::ScopedAStatus::ok();
288 }
289 auto applyParam = [](const std::shared_ptr<BluetoothAudioPortAidl>& proxy,
290 bool isEnabled) -> bool {
291 if (!isEnabled) {
292 if (proxy->suspend()) return proxy->setState(BluetoothStreamState::DISABLED);
293 return false;
294 }
295 return proxy->standby();
296 };
297 bool hasA2dpParam, enableA2dp;
298 auto btA2dp = mBluetoothA2dp.lock();
299 hasA2dpParam = btA2dp != nullptr && btA2dp->isEnabled(&enableA2dp).isOk();
300 bool hasLeParam, enableLe;
301 auto btLe = mBluetoothLe.lock();
302 hasLeParam = btLe != nullptr && btLe->isEnabled(&enableLe).isOk();
303 std::unique_lock lock(mLock);
304 ::android::base::ScopedLockAssertion lock_assertion(mLock);
305 if (!mIsInitialized) {
306 LOG(WARNING) << __func__ << ": init not done";
307 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
308 }
309 for (auto proxy : mBtDeviceProxies) {
310 if ((hasA2dpParam && proxy->isA2dp() && !applyParam(proxy, enableA2dp)) ||
311 (hasLeParam && proxy->isLeAudio() && !applyParam(proxy, enableLe))) {
312 LOG(DEBUG) << __func__ << ": applyParam failed";
313 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
314 }
315 }
316 return ndk::ScopedAStatus::ok();
317}
318
Mikhail Naganovb03b5c42023-07-26 13:13:35 -0700319StreamInBluetooth::StreamInBluetooth(StreamContext&& context, const SinkMetadata& sinkMetadata,
Ram Mohan18f0d512023-07-01 00:47:09 +0530320 const std::vector<MicrophoneInfo>& microphones,
321 Module::BtProfileHandles&& btProfileHandles)
Mikhail Naganovb03b5c42023-07-26 13:13:35 -0700322 : StreamIn(std::move(context), microphones),
Ram Mohan18f0d512023-07-01 00:47:09 +0530323 StreamBluetooth(&(StreamIn::mContext), sinkMetadata, std::move(btProfileHandles)) {}
Mikhail Naganovb03b5c42023-07-26 13:13:35 -0700324
325ndk::ScopedAStatus StreamInBluetooth::getActiveMicrophones(
326 std::vector<MicrophoneDynamicInfo>* _aidl_return __unused) {
327 LOG(DEBUG) << __func__ << ": not supported";
328 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
329}
330
331StreamOutBluetooth::StreamOutBluetooth(StreamContext&& context,
332 const SourceMetadata& sourceMetadata,
Ram Mohan18f0d512023-07-01 00:47:09 +0530333 const std::optional<AudioOffloadInfo>& offloadInfo,
334 Module::BtProfileHandles&& btProfileHandles)
Mikhail Naganovb03b5c42023-07-26 13:13:35 -0700335 : StreamOut(std::move(context), offloadInfo),
Ram Mohan18f0d512023-07-01 00:47:09 +0530336 StreamBluetooth(&(StreamOut::mContext), sourceMetadata, std::move(btProfileHandles)) {}
Mikhail Naganovb03b5c42023-07-26 13:13:35 -0700337
338} // namespace aidl::android::hardware::audio::core