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 #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 
26 namespace aidl::android::hardware::audio::core {
27 
28 using ::aidl::android::hardware::audio::common::SinkMetadata;
29 using ::aidl::android::hardware::audio::common::SourceMetadata;
30 using ::aidl::android::hardware::audio::core::VendorParameter;
31 using ::aidl::android::hardware::bluetooth::audio::ChannelMode;
32 using ::aidl::android::hardware::bluetooth::audio::PcmConfiguration;
33 using ::aidl::android::hardware::bluetooth::audio::PresentationPosition;
34 using ::aidl::android::media::audio::common::AudioChannelLayout;
35 using ::aidl::android::media::audio::common::AudioDevice;
36 using ::aidl::android::media::audio::common::AudioDeviceAddress;
37 using ::aidl::android::media::audio::common::AudioFormatDescription;
38 using ::aidl::android::media::audio::common::AudioFormatType;
39 using ::aidl::android::media::audio::common::AudioOffloadInfo;
40 using ::aidl::android::media::audio::common::MicrophoneDynamicInfo;
41 using ::aidl::android::media::audio::common::MicrophoneInfo;
42 using ::android::bluetooth::audio::aidl::BluetoothAudioPortAidl;
43 using ::android::bluetooth::audio::aidl::BluetoothAudioPortAidlIn;
44 using ::android::bluetooth::audio::aidl::BluetoothAudioPortAidlOut;
45 using ::android::bluetooth::audio::aidl::BluetoothStreamState;
46 
47 constexpr int kBluetoothDefaultInputBufferMs = 20;
48 constexpr int kBluetoothDefaultOutputBufferMs = 10;
49 // constexpr int kBluetoothSpatializerOutputBufferMs = 10;
50 
getFrameCount(uint64_t durationUs,uint32_t sampleRate)51 size_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
StreamBluetooth(StreamContext * context,const Metadata & metadata,Module::BtProfileHandles && btHandles)56 StreamBluetooth::StreamBluetooth(StreamContext* context, const Metadata& metadata,
57                                  Module::BtProfileHandles&& btHandles)
58     : StreamCommonImpl(context, metadata),
59       mSampleRate(getContext().getSampleRate()),
60       mChannelLayout(getContext().getChannelLayout()),
61       mFormat(getContext().getFormat()),
62       mFrameSizeBytes(getContext().getFrameSize()),
63       mIsInput(isInput(metadata)),
64       mBluetoothA2dp(std::move(std::get<Module::BtInterface::BTA2DP>(btHandles))),
65       mBluetoothLe(std::move(std::get<Module::BtInterface::BTLE>(btHandles))) {
66     mPreferredDataIntervalUs =
67             mIsInput ? kBluetoothDefaultInputBufferMs : kBluetoothDefaultOutputBufferMs;
68     mPreferredFrameCount = getFrameCount(mPreferredDataIntervalUs, mSampleRate);
69     mIsInitialized = false;
70     mIsReadyToClose = false;
71 }
72 
init()73 ::android::status_t StreamBluetooth::init() {
74     return ::android::OK;  // defering this till we get AudioDeviceDescription
75 }
76 
getConnectedDevices() const77 const StreamCommonInterface::ConnectedDevices& StreamBluetooth::getConnectedDevices() const {
78     std::lock_guard guard(mLock);
79     return StreamCommonImpl::getConnectedDevices();
80 }
81 
setConnectedDevices(const std::vector<AudioDevice> & connectedDevices)82 ndk::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 
drain(StreamDescriptor::DrainMode)101 ::android::status_t StreamBluetooth::drain(StreamDescriptor::DrainMode) {
102     usleep(1000);
103     return ::android::OK;
104 }
105 
flush()106 ::android::status_t StreamBluetooth::flush() {
107     usleep(1000);
108     return ::android::OK;
109 }
110 
pause()111 ::android::status_t StreamBluetooth::pause() {
112     return standby();
113 }
114 
transfer(void * buffer,size_t frameCount,size_t * actualFrameCount,int32_t * latencyMs)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 
initialize()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 
checkConfigParams(::aidl::android::hardware::bluetooth::audio::PcmConfiguration & config)201 bool 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 
prepareToClose()234 ndk::ScopedAStatus StreamBluetooth::prepareToClose() {
235     std::lock_guard guard(mLock);
236     mIsReadyToClose = true;
237     return ndk::ScopedAStatus::ok();
238 }
239 
standby()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 
start()254 ::android::status_t StreamBluetooth::start() {
255     std::lock_guard guard(mLock);
256     if (!mIsInitialized) return initialize();
257     return ::android::OK;
258 }
259 
shutdown()260 void 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 
updateMetadataCommon(const Metadata & metadata)269 ndk::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 
bluetoothParametersUpdated()284 ndk::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 
StreamInBluetooth(StreamContext && context,const SinkMetadata & sinkMetadata,const std::vector<MicrophoneInfo> & microphones,Module::BtProfileHandles && btProfileHandles)319 StreamInBluetooth::StreamInBluetooth(StreamContext&& context, const SinkMetadata& sinkMetadata,
320                                      const std::vector<MicrophoneInfo>& microphones,
321                                      Module::BtProfileHandles&& btProfileHandles)
322     : StreamIn(std::move(context), microphones),
323       StreamBluetooth(&mContextInstance, sinkMetadata, std::move(btProfileHandles)) {}
324 
getActiveMicrophones(std::vector<MicrophoneDynamicInfo> * _aidl_return __unused)325 ndk::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 
StreamOutBluetooth(StreamContext && context,const SourceMetadata & sourceMetadata,const std::optional<AudioOffloadInfo> & offloadInfo,Module::BtProfileHandles && btProfileHandles)331 StreamOutBluetooth::StreamOutBluetooth(StreamContext&& context,
332                                        const SourceMetadata& sourceMetadata,
333                                        const std::optional<AudioOffloadInfo>& offloadInfo,
334                                        Module::BtProfileHandles&& btProfileHandles)
335     : StreamOut(std::move(context), offloadInfo),
336       StreamBluetooth(&mContextInstance, sourceMetadata, std::move(btProfileHandles)) {}
337 
338 }  // namespace aidl::android::hardware::audio::core
339