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 
init()69 ::android::status_t StreamBluetooth::init() {
70     std::lock_guard guard(mLock);
71     if (mBtDeviceProxy == nullptr) {
72         // This is a normal situation in VTS tests.
73         LOG(INFO) << __func__ << ": no BT HAL proxy, stream is non-functional";
74     }
75     LOG(INFO) << __func__ << ": preferred data interval (us): " << mPreferredDataIntervalUs;
76     return ::android::OK;
77 }
78 
drain(StreamDescriptor::DrainMode)79 ::android::status_t StreamBluetooth::drain(StreamDescriptor::DrainMode) {
80     usleep(1000);
81     return ::android::OK;
82 }
83 
flush()84 ::android::status_t StreamBluetooth::flush() {
85     usleep(1000);
86     return ::android::OK;
87 }
88 
pause()89 ::android::status_t StreamBluetooth::pause() {
90     return standby();
91 }
92 
transfer(void * buffer,size_t frameCount,size_t * actualFrameCount,int32_t * latencyMs)93 ::android::status_t StreamBluetooth::transfer(void* buffer, size_t frameCount,
94                                               size_t* actualFrameCount, int32_t* latencyMs) {
95     std::lock_guard guard(mLock);
96     *actualFrameCount = 0;
97     *latencyMs = StreamDescriptor::LATENCY_UNKNOWN;
98     if (mBtDeviceProxy == nullptr || mBtDeviceProxy->getState() == BluetoothStreamState::DISABLED) {
99         // The BT session is turned down, silently ignore write.
100         return ::android::OK;
101     }
102     if (!mBtDeviceProxy->start()) {
103         LOG(WARNING) << __func__ << ": state= " << mBtDeviceProxy->getState()
104                      << " failed to start, will retry";
105         return ::android::OK;
106     }
107     *latencyMs = 0;
108     const size_t bytesToTransfer = frameCount * mFrameSizeBytes;
109     const size_t bytesTransferred = mIsInput ? mBtDeviceProxy->readData(buffer, bytesToTransfer)
110                                              : mBtDeviceProxy->writeData(buffer, bytesToTransfer);
111     *actualFrameCount = bytesTransferred / mFrameSizeBytes;
112     PresentationPosition presentation_position;
113     if (!mBtDeviceProxy->getPresentationPosition(presentation_position)) {
114         presentation_position.remoteDeviceAudioDelayNanos =
115                 kBluetoothDefaultRemoteDelayMs * NANOS_PER_MILLISECOND;
116         LOG(WARNING) << __func__ << ": getPresentationPosition failed, latency info is unavailable";
117     }
118     // TODO(b/317117580): incorporate logic from
119     //                    packages/modules/Bluetooth/system/audio_bluetooth_hw/stream_apis.cc
120     //                    out_calculate_feeding_delay_ms / in_calculate_starving_delay_ms
121     *latencyMs = std::max(*latencyMs, (int32_t)(presentation_position.remoteDeviceAudioDelayNanos /
122                                                 NANOS_PER_MILLISECOND));
123     return ::android::OK;
124 }
125 
126 // static
checkConfigParams(const PcmConfiguration & pcmConfig,const AudioConfigBase & config)127 bool StreamBluetooth::checkConfigParams(const PcmConfiguration& pcmConfig,
128                                         const AudioConfigBase& config) {
129     if ((int)config.sampleRate != pcmConfig.sampleRateHz) {
130         LOG(ERROR) << __func__ << ": sample rate mismatch, stream value=" << config.sampleRate
131                    << ", BT HAL value=" << pcmConfig.sampleRateHz;
132         return false;
133     }
134     const auto channelCount =
135             aidl::android::hardware::audio::common::getChannelCount(config.channelMask);
136     if ((pcmConfig.channelMode == ChannelMode::MONO && channelCount != 1) ||
137         (pcmConfig.channelMode == ChannelMode::STEREO && channelCount != 2)) {
138         LOG(ERROR) << __func__ << ": Channel count mismatch, stream value=" << channelCount
139                    << ", BT HAL value=" << toString(pcmConfig.channelMode);
140         return false;
141     }
142     if (config.format.type != AudioFormatType::PCM) {
143         LOG(ERROR) << __func__
144                    << ": unexpected stream format type: " << toString(config.format.type);
145         return false;
146     }
147     const int8_t bitsPerSample =
148             aidl::android::hardware::audio::common::getPcmSampleSizeInBytes(config.format.pcm) * 8;
149     if (bitsPerSample != pcmConfig.bitsPerSample) {
150         LOG(ERROR) << __func__ << ": bits per sample mismatch, stream value=" << bitsPerSample
151                    << ", BT HAL value=" << pcmConfig.bitsPerSample;
152         return false;
153     }
154     return true;
155 }
156 
prepareToClose()157 ndk::ScopedAStatus StreamBluetooth::prepareToClose() {
158     std::lock_guard guard(mLock);
159     if (mBtDeviceProxy != nullptr) {
160         if (mBtDeviceProxy->getState() != BluetoothStreamState::DISABLED) {
161             mBtDeviceProxy->stop();
162         }
163     }
164     return ndk::ScopedAStatus::ok();
165 }
166 
standby()167 ::android::status_t StreamBluetooth::standby() {
168     std::lock_guard guard(mLock);
169     if (mBtDeviceProxy != nullptr) mBtDeviceProxy->suspend();
170     return ::android::OK;
171 }
172 
start()173 ::android::status_t StreamBluetooth::start() {
174     std::lock_guard guard(mLock);
175     if (mBtDeviceProxy != nullptr) mBtDeviceProxy->start();
176     return ::android::OK;
177 }
178 
shutdown()179 void StreamBluetooth::shutdown() {
180     std::lock_guard guard(mLock);
181     if (mBtDeviceProxy != nullptr) {
182         mBtDeviceProxy->stop();
183         mBtDeviceProxy = nullptr;
184     }
185 }
186 
updateMetadataCommon(const Metadata & metadata)187 ndk::ScopedAStatus StreamBluetooth::updateMetadataCommon(const Metadata& metadata) {
188     std::lock_guard guard(mLock);
189     if (mBtDeviceProxy == nullptr) {
190         return ndk::ScopedAStatus::ok();
191     }
192     bool isOk = true;
193     if (isInput(metadata)) {
194         isOk = mBtDeviceProxy->updateSinkMetadata(std::get<SinkMetadata>(metadata));
195     } else {
196         isOk = mBtDeviceProxy->updateSourceMetadata(std::get<SourceMetadata>(metadata));
197     }
198     return isOk ? ndk::ScopedAStatus::ok()
199                 : ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
200 }
201 
bluetoothParametersUpdated()202 ndk::ScopedAStatus StreamBluetooth::bluetoothParametersUpdated() {
203     if (mIsInput) {
204         return ndk::ScopedAStatus::ok();
205     }
206     auto applyParam = [](const std::shared_ptr<BluetoothAudioPortAidl>& proxy,
207                          bool isEnabled) -> bool {
208         if (!isEnabled) {
209             if (proxy->suspend()) return proxy->setState(BluetoothStreamState::DISABLED);
210             return false;
211         }
212         return proxy->standby();
213     };
214     bool hasA2dpParam, enableA2dp;
215     auto btA2dp = mBluetoothA2dp.lock();
216     hasA2dpParam = btA2dp != nullptr && btA2dp->isEnabled(&enableA2dp).isOk();
217     bool hasLeParam, enableLe;
218     auto btLe = mBluetoothLe.lock();
219     hasLeParam = btLe != nullptr && btLe->isEnabled(&enableLe).isOk();
220     std::lock_guard guard(mLock);
221     if (mBtDeviceProxy != nullptr) {
222         if ((hasA2dpParam && mBtDeviceProxy->isA2dp() && !applyParam(mBtDeviceProxy, enableA2dp)) ||
223             (hasLeParam && mBtDeviceProxy->isLeAudio() && !applyParam(mBtDeviceProxy, enableLe))) {
224             LOG(DEBUG) << __func__ << ": applyParam failed";
225             return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
226         }
227     }
228     return ndk::ScopedAStatus::ok();
229 }
230 
231 // static
getNominalLatencyMs(size_t dataIntervalUs)232 int32_t StreamInBluetooth::getNominalLatencyMs(size_t dataIntervalUs) {
233     if (dataIntervalUs == 0) dataIntervalUs = kBluetoothDefaultInputBufferMs * 1000LL;
234     return dataIntervalUs / 1000LL;
235 }
236 
StreamInBluetooth(StreamContext && context,const SinkMetadata & sinkMetadata,const std::vector<MicrophoneInfo> & microphones,ModuleBluetooth::BtProfileHandles && btProfileHandles,const std::shared_ptr<BluetoothAudioPortAidl> & btDeviceProxy,const PcmConfiguration & pcmConfig)237 StreamInBluetooth::StreamInBluetooth(StreamContext&& context, const SinkMetadata& sinkMetadata,
238                                      const std::vector<MicrophoneInfo>& microphones,
239                                      ModuleBluetooth::BtProfileHandles&& btProfileHandles,
240                                      const std::shared_ptr<BluetoothAudioPortAidl>& btDeviceProxy,
241                                      const PcmConfiguration& pcmConfig)
242     : StreamIn(std::move(context), microphones),
243       StreamBluetooth(&mContextInstance, sinkMetadata, std::move(btProfileHandles), btDeviceProxy,
244                       pcmConfig) {}
245 
getActiveMicrophones(std::vector<MicrophoneDynamicInfo> * _aidl_return __unused)246 ndk::ScopedAStatus StreamInBluetooth::getActiveMicrophones(
247         std::vector<MicrophoneDynamicInfo>* _aidl_return __unused) {
248     LOG(DEBUG) << __func__ << ": not supported";
249     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
250 }
251 
252 // static
getNominalLatencyMs(size_t dataIntervalUs)253 int32_t StreamOutBluetooth::getNominalLatencyMs(size_t dataIntervalUs) {
254     if (dataIntervalUs == 0) dataIntervalUs = kBluetoothDefaultOutputBufferMs * 1000LL;
255     return dataIntervalUs / 1000LL;
256 }
257 
StreamOutBluetooth(StreamContext && context,const SourceMetadata & sourceMetadata,const std::optional<AudioOffloadInfo> & offloadInfo,ModuleBluetooth::BtProfileHandles && btProfileHandles,const std::shared_ptr<BluetoothAudioPortAidl> & btDeviceProxy,const PcmConfiguration & pcmConfig)258 StreamOutBluetooth::StreamOutBluetooth(StreamContext&& context,
259                                        const SourceMetadata& sourceMetadata,
260                                        const std::optional<AudioOffloadInfo>& offloadInfo,
261                                        ModuleBluetooth::BtProfileHandles&& btProfileHandles,
262                                        const std::shared_ptr<BluetoothAudioPortAidl>& btDeviceProxy,
263                                        const PcmConfiguration& pcmConfig)
264     : StreamOut(std::move(context), offloadInfo),
265       StreamBluetooth(&mContextInstance, sourceMetadata, std::move(btProfileHandles), btDeviceProxy,
266                       pcmConfig) {}
267 
268 }  // namespace aidl::android::hardware::audio::core
269