Mikhail Naganov | b03b5c4 | 2023-07-26 13:13:35 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 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_BluetoothPortProxy" |
| 18 | |
| 19 | #include <android-base/logging.h> |
| 20 | #include <android-base/stringprintf.h> |
| 21 | #include <audio_utils/primitives.h> |
Mikhail Naganov | b03b5c4 | 2023-07-26 13:13:35 -0700 | [diff] [blame] | 22 | #include <log/log.h> |
| 23 | |
Mikhail Naganov | 55045b5 | 2023-10-24 17:03:50 -0700 | [diff] [blame] | 24 | #include "BluetoothAudioSessionControl.h" |
Mikhail Naganov | b03b5c4 | 2023-07-26 13:13:35 -0700 | [diff] [blame] | 25 | #include "core-impl/DevicePortProxy.h" |
| 26 | |
Mikhail Naganov | 55045b5 | 2023-10-24 17:03:50 -0700 | [diff] [blame] | 27 | using aidl::android::hardware::audio::common::SinkMetadata; |
| 28 | using aidl::android::hardware::audio::common::SourceMetadata; |
| 29 | using aidl::android::hardware::bluetooth::audio::AudioConfiguration; |
| 30 | using aidl::android::hardware::bluetooth::audio::BluetoothAudioSessionControl; |
| 31 | using aidl::android::hardware::bluetooth::audio::BluetoothAudioStatus; |
| 32 | using aidl::android::hardware::bluetooth::audio::ChannelMode; |
| 33 | using aidl::android::hardware::bluetooth::audio::PcmConfiguration; |
| 34 | using aidl::android::hardware::bluetooth::audio::PortStatusCallbacks; |
| 35 | using aidl::android::hardware::bluetooth::audio::PresentationPosition; |
| 36 | using aidl::android::hardware::bluetooth::audio::SessionType; |
| 37 | using aidl::android::media::audio::common::AudioDeviceDescription; |
| 38 | using aidl::android::media::audio::common::AudioDeviceType; |
| 39 | using android::base::StringPrintf; |
| 40 | |
Mikhail Naganov | b03b5c4 | 2023-07-26 13:13:35 -0700 | [diff] [blame] | 41 | namespace android::bluetooth::audio::aidl { |
| 42 | |
| 43 | namespace { |
| 44 | |
| 45 | // The maximum time to wait in std::condition_variable::wait_for() |
| 46 | constexpr unsigned int kMaxWaitingTimeMs = 4500; |
| 47 | |
| 48 | } // namespace |
| 49 | |
Mikhail Naganov | b03b5c4 | 2023-07-26 13:13:35 -0700 | [diff] [blame] | 50 | std::ostream& operator<<(std::ostream& os, const BluetoothStreamState& state) { |
| 51 | switch (state) { |
| 52 | case BluetoothStreamState::DISABLED: |
| 53 | return os << "DISABLED"; |
| 54 | case BluetoothStreamState::STANDBY: |
| 55 | return os << "STANDBY"; |
| 56 | case BluetoothStreamState::STARTING: |
| 57 | return os << "STARTING"; |
| 58 | case BluetoothStreamState::STARTED: |
| 59 | return os << "STARTED"; |
| 60 | case BluetoothStreamState::SUSPENDING: |
| 61 | return os << "SUSPENDING"; |
| 62 | case BluetoothStreamState::UNKNOWN: |
| 63 | return os << "UNKNOWN"; |
| 64 | default: |
| 65 | return os << android::base::StringPrintf("%#hhx", state); |
| 66 | } |
| 67 | } |
| 68 | |
| 69 | BluetoothAudioPortAidl::BluetoothAudioPortAidl() |
| 70 | : mCookie(::aidl::android::hardware::bluetooth::audio::kObserversCookieUndefined), |
| 71 | mState(BluetoothStreamState::DISABLED), |
| 72 | mSessionType(SessionType::UNKNOWN) {} |
| 73 | |
| 74 | BluetoothAudioPortAidl::~BluetoothAudioPortAidl() { |
| 75 | unregisterPort(); |
| 76 | } |
| 77 | |
| 78 | bool BluetoothAudioPortAidl::registerPort(const AudioDeviceDescription& description) { |
| 79 | if (inUse()) { |
| 80 | LOG(ERROR) << __func__ << debugMessage() << " already in use"; |
| 81 | return false; |
| 82 | } |
| 83 | |
| 84 | if (!initSessionType(description)) return false; |
| 85 | |
| 86 | auto control_result_cb = [port = this](uint16_t cookie, bool start_resp, |
| 87 | const BluetoothAudioStatus& status) { |
| 88 | (void)start_resp; |
| 89 | port->controlResultHandler(cookie, status); |
| 90 | }; |
| 91 | auto session_changed_cb = [port = this](uint16_t cookie) { |
| 92 | port->sessionChangedHandler(cookie); |
| 93 | }; |
| 94 | // TODO: Add audio_config_changed_cb |
| 95 | PortStatusCallbacks cbacks = { |
| 96 | .control_result_cb_ = control_result_cb, |
| 97 | .session_changed_cb_ = session_changed_cb, |
| 98 | }; |
| 99 | mCookie = BluetoothAudioSessionControl::RegisterControlResultCback(mSessionType, cbacks); |
| 100 | auto isOk = (mCookie != ::aidl::android::hardware::bluetooth::audio::kObserversCookieUndefined); |
| 101 | if (isOk) { |
| 102 | std::lock_guard guard(mCvMutex); |
| 103 | mState = BluetoothStreamState::STANDBY; |
| 104 | } |
| 105 | LOG(DEBUG) << __func__ << debugMessage(); |
| 106 | return isOk; |
| 107 | } |
| 108 | |
| 109 | bool BluetoothAudioPortAidl::initSessionType(const AudioDeviceDescription& description) { |
| 110 | if (description.connection == AudioDeviceDescription::CONNECTION_BT_A2DP && |
| 111 | (description.type == AudioDeviceType::OUT_DEVICE || |
| 112 | description.type == AudioDeviceType::OUT_HEADPHONE || |
| 113 | description.type == AudioDeviceType::OUT_SPEAKER)) { |
| 114 | LOG(VERBOSE) << __func__ |
| 115 | << ": device=AUDIO_DEVICE_OUT_BLUETOOTH_A2DP (HEADPHONES/SPEAKER) (" |
| 116 | << description.toString() << ")"; |
| 117 | mSessionType = SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH; |
| 118 | } else if (description.connection == AudioDeviceDescription::CONNECTION_WIRELESS && |
| 119 | description.type == AudioDeviceType::OUT_HEARING_AID) { |
| 120 | LOG(VERBOSE) << __func__ << ": device=AUDIO_DEVICE_OUT_HEARING_AID (MEDIA/VOICE) (" |
| 121 | << description.toString() << ")"; |
| 122 | mSessionType = SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH; |
| 123 | } else if (description.connection == AudioDeviceDescription::CONNECTION_BT_LE && |
| 124 | description.type == AudioDeviceType::OUT_HEADSET) { |
| 125 | LOG(VERBOSE) << __func__ << ": device=AUDIO_DEVICE_OUT_BLE_HEADSET (MEDIA/VOICE) (" |
| 126 | << description.toString() << ")"; |
| 127 | mSessionType = SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH; |
| 128 | } else if (description.connection == AudioDeviceDescription::CONNECTION_BT_LE && |
| 129 | description.type == AudioDeviceType::OUT_SPEAKER) { |
| 130 | LOG(VERBOSE) << __func__ << ": device=AUDIO_DEVICE_OUT_BLE_SPEAKER (MEDIA) (" |
| 131 | << description.toString() << ")"; |
| 132 | mSessionType = SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH; |
| 133 | } else if (description.connection == AudioDeviceDescription::CONNECTION_BT_LE && |
| 134 | description.type == AudioDeviceType::IN_HEADSET) { |
| 135 | LOG(VERBOSE) << __func__ << ": device=AUDIO_DEVICE_IN_BLE_HEADSET (VOICE) (" |
| 136 | << description.toString() << ")"; |
| 137 | mSessionType = SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH; |
| 138 | } else if (description.connection == AudioDeviceDescription::CONNECTION_BT_LE && |
| 139 | description.type == AudioDeviceType::OUT_BROADCAST) { |
| 140 | LOG(VERBOSE) << __func__ << ": device=AUDIO_DEVICE_OUT_BLE_BROADCAST (MEDIA) (" |
| 141 | << description.toString() << ")"; |
| 142 | mSessionType = SessionType::LE_AUDIO_BROADCAST_SOFTWARE_ENCODING_DATAPATH; |
| 143 | } else { |
| 144 | LOG(ERROR) << __func__ << ": unknown device=" << description.toString(); |
| 145 | return false; |
| 146 | } |
| 147 | |
| 148 | if (!BluetoothAudioSessionControl::IsSessionReady(mSessionType)) { |
| 149 | LOG(ERROR) << __func__ << ": device=" << description.toString() |
| 150 | << ", session_type=" << toString(mSessionType) << " is not ready"; |
| 151 | return false; |
| 152 | } |
| 153 | return true; |
| 154 | } |
| 155 | |
| 156 | void BluetoothAudioPortAidl::unregisterPort() { |
| 157 | if (!inUse()) { |
| 158 | LOG(WARNING) << __func__ << ": BluetoothAudioPortAidl is not in use"; |
| 159 | return; |
| 160 | } |
| 161 | BluetoothAudioSessionControl::UnregisterControlResultCback(mSessionType, mCookie); |
| 162 | mCookie = ::aidl::android::hardware::bluetooth::audio::kObserversCookieUndefined; |
| 163 | LOG(VERBOSE) << __func__ << debugMessage() << " port unregistered"; |
| 164 | } |
| 165 | |
| 166 | void BluetoothAudioPortAidl::controlResultHandler(uint16_t cookie, |
| 167 | const BluetoothAudioStatus& status) { |
| 168 | std::lock_guard guard(mCvMutex); |
| 169 | if (!inUse()) { |
| 170 | LOG(ERROR) << "control_result_cb: BluetoothAudioPortAidl is not in use"; |
| 171 | return; |
| 172 | } |
| 173 | if (mCookie != cookie) { |
| 174 | LOG(ERROR) << "control_result_cb: proxy of device port (cookie=" |
| 175 | << StringPrintf("%#hx", cookie) << ") is corrupted"; |
| 176 | return; |
| 177 | } |
| 178 | BluetoothStreamState previous_state = mState; |
| 179 | LOG(INFO) << "control_result_cb:" << debugMessage() << ", previous_state=" << previous_state |
| 180 | << ", status=" << toString(status); |
| 181 | |
| 182 | switch (previous_state) { |
| 183 | case BluetoothStreamState::STARTED: |
| 184 | /* Only Suspend signal can be send in STARTED state*/ |
| 185 | if (status == BluetoothAudioStatus::RECONFIGURATION || |
| 186 | status == BluetoothAudioStatus::SUCCESS) { |
| 187 | mState = BluetoothStreamState::STANDBY; |
| 188 | } else { |
| 189 | LOG(WARNING) << StringPrintf( |
| 190 | "control_result_cb: status=%s failure for session_type= %s, cookie=%#hx, " |
| 191 | "previous_state=%#hhx", |
| 192 | toString(status).c_str(), toString(mSessionType).c_str(), mCookie, |
| 193 | previous_state); |
| 194 | } |
| 195 | break; |
| 196 | case BluetoothStreamState::STARTING: |
| 197 | if (status == BluetoothAudioStatus::SUCCESS) { |
| 198 | mState = BluetoothStreamState::STARTED; |
| 199 | } else { |
| 200 | // Set to standby since the stack may be busy switching between outputs |
| 201 | LOG(WARNING) << StringPrintf( |
| 202 | "control_result_cb: status=%s failure for session_type= %s, cookie=%#hx, " |
| 203 | "previous_state=%#hhx", |
| 204 | toString(status).c_str(), toString(mSessionType).c_str(), mCookie, |
| 205 | previous_state); |
| 206 | mState = BluetoothStreamState::STANDBY; |
| 207 | } |
| 208 | break; |
| 209 | case BluetoothStreamState::SUSPENDING: |
| 210 | if (status == BluetoothAudioStatus::SUCCESS) { |
| 211 | mState = BluetoothStreamState::STANDBY; |
| 212 | } else { |
| 213 | // It will be failed if the headset is disconnecting, and set to disable |
| 214 | // to wait for re-init again |
| 215 | LOG(WARNING) << StringPrintf( |
| 216 | "control_result_cb: status=%s failure for session_type= %s, cookie=%#hx, " |
| 217 | "previous_state=%#hhx", |
| 218 | toString(status).c_str(), toString(mSessionType).c_str(), mCookie, |
| 219 | previous_state); |
| 220 | mState = BluetoothStreamState::DISABLED; |
| 221 | } |
| 222 | break; |
| 223 | default: |
| 224 | LOG(ERROR) << "control_result_cb: unexpected previous_state=" |
| 225 | << StringPrintf( |
| 226 | "control_result_cb: status=%s failure for session_type= %s, " |
| 227 | "cookie=%#hx, previous_state=%#hhx", |
| 228 | toString(status).c_str(), toString(mSessionType).c_str(), mCookie, |
| 229 | previous_state); |
| 230 | return; |
| 231 | } |
| 232 | mInternalCv.notify_all(); |
| 233 | } |
| 234 | |
| 235 | void BluetoothAudioPortAidl::sessionChangedHandler(uint16_t cookie) { |
| 236 | std::lock_guard guard(mCvMutex); |
| 237 | if (!inUse()) { |
| 238 | LOG(ERROR) << "session_changed_cb: BluetoothAudioPortAidl is not in use"; |
| 239 | return; |
| 240 | } |
| 241 | if (mCookie != cookie) { |
| 242 | LOG(ERROR) << "session_changed_cb: proxy of device port (cookie=" |
| 243 | << StringPrintf("%#hx", cookie) << ") is corrupted"; |
| 244 | return; |
| 245 | } |
| 246 | BluetoothStreamState previous_state = mState; |
| 247 | LOG(VERBOSE) << "session_changed_cb:" << debugMessage() |
| 248 | << ", previous_state=" << previous_state; |
| 249 | mState = BluetoothStreamState::DISABLED; |
| 250 | mInternalCv.notify_all(); |
| 251 | } |
| 252 | |
| 253 | bool BluetoothAudioPortAidl::inUse() const { |
| 254 | return (mCookie != ::aidl::android::hardware::bluetooth::audio::kObserversCookieUndefined); |
| 255 | } |
| 256 | |
| 257 | bool BluetoothAudioPortAidl::getPreferredDataIntervalUs(size_t* interval_us) const { |
| 258 | if (!interval_us) { |
| 259 | LOG(ERROR) << __func__ << ": bad input arg"; |
| 260 | return false; |
| 261 | } |
| 262 | |
| 263 | if (!inUse()) { |
| 264 | LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use"; |
| 265 | return false; |
| 266 | } |
| 267 | |
| 268 | const AudioConfiguration& hal_audio_cfg = |
| 269 | BluetoothAudioSessionControl::GetAudioConfig(mSessionType); |
| 270 | if (hal_audio_cfg.getTag() != AudioConfiguration::pcmConfig) { |
| 271 | LOG(ERROR) << __func__ << ": unsupported audio cfg tag"; |
| 272 | return false; |
| 273 | } |
| 274 | |
| 275 | *interval_us = hal_audio_cfg.get<AudioConfiguration::pcmConfig>().dataIntervalUs; |
| 276 | return true; |
| 277 | } |
| 278 | |
| 279 | bool BluetoothAudioPortAidl::loadAudioConfig(PcmConfiguration* audio_cfg) const { |
| 280 | if (!audio_cfg) { |
| 281 | LOG(ERROR) << __func__ << ": bad input arg"; |
| 282 | return false; |
| 283 | } |
| 284 | |
| 285 | if (!inUse()) { |
| 286 | LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use"; |
| 287 | return false; |
| 288 | } |
| 289 | |
| 290 | const AudioConfiguration& hal_audio_cfg = |
| 291 | BluetoothAudioSessionControl::GetAudioConfig(mSessionType); |
| 292 | if (hal_audio_cfg.getTag() != AudioConfiguration::pcmConfig) { |
| 293 | LOG(ERROR) << __func__ << ": unsupported audio cfg tag"; |
| 294 | return false; |
| 295 | } |
| 296 | *audio_cfg = hal_audio_cfg.get<AudioConfiguration::pcmConfig>(); |
| 297 | LOG(VERBOSE) << __func__ << debugMessage() << ", state*=" << getState() << ", PcmConfig=[" |
| 298 | << audio_cfg->toString() << "]"; |
| 299 | if (audio_cfg->channelMode == ChannelMode::UNKNOWN) { |
| 300 | return false; |
| 301 | } |
| 302 | return true; |
| 303 | } |
| 304 | |
Ram Mohan | 18f0d51 | 2023-07-01 00:47:09 +0530 | [diff] [blame] | 305 | bool BluetoothAudioPortAidl::standby() { |
| 306 | if (!inUse()) { |
| 307 | LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use"; |
| 308 | return false; |
| 309 | } |
| 310 | std::lock_guard guard(mCvMutex); |
| 311 | LOG(VERBOSE) << __func__ << debugMessage() << ", state=" << getState() << " request"; |
| 312 | if (mState == BluetoothStreamState::DISABLED) { |
| 313 | mState = BluetoothStreamState::STANDBY; |
| 314 | LOG(VERBOSE) << __func__ << debugMessage() << ", state=" << getState() << " done"; |
| 315 | return true; |
| 316 | } |
| 317 | return false; |
| 318 | } |
| 319 | |
Mikhail Naganov | b03b5c4 | 2023-07-26 13:13:35 -0700 | [diff] [blame] | 320 | bool BluetoothAudioPortAidl::condWaitState(BluetoothStreamState state) { |
| 321 | const auto waitTime = std::chrono::milliseconds(kMaxWaitingTimeMs); |
| 322 | std::unique_lock lock(mCvMutex); |
| 323 | base::ScopedLockAssertion lock_assertion(mCvMutex); |
| 324 | switch (state) { |
| 325 | case BluetoothStreamState::STARTING: { |
| 326 | LOG(VERBOSE) << __func__ << debugMessage() << " waiting for STARTED"; |
| 327 | mInternalCv.wait_for(lock, waitTime, [this] { |
| 328 | base::ScopedLockAssertion lock_assertion(mCvMutex); |
| 329 | return mState != BluetoothStreamState::STARTING; |
| 330 | }); |
| 331 | return mState == BluetoothStreamState::STARTED; |
| 332 | } |
| 333 | case BluetoothStreamState::SUSPENDING: { |
| 334 | LOG(VERBOSE) << __func__ << debugMessage() << " waiting for SUSPENDED"; |
| 335 | mInternalCv.wait_for(lock, waitTime, [this] { |
| 336 | base::ScopedLockAssertion lock_assertion(mCvMutex); |
| 337 | return mState != BluetoothStreamState::SUSPENDING; |
| 338 | }); |
| 339 | return mState == BluetoothStreamState::STANDBY; |
| 340 | } |
| 341 | default: |
| 342 | LOG(WARNING) << __func__ << debugMessage() << " waiting for KNOWN"; |
| 343 | return false; |
| 344 | } |
| 345 | return false; |
| 346 | } |
| 347 | |
| 348 | bool BluetoothAudioPortAidl::start() { |
| 349 | if (!inUse()) { |
| 350 | LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use"; |
| 351 | return false; |
| 352 | } |
| 353 | LOG(VERBOSE) << __func__ << debugMessage() << ", state=" << getState() |
| 354 | << ", mono=" << (mIsStereoToMono ? "true" : "false") << " request"; |
| 355 | |
| 356 | { |
| 357 | std::unique_lock lock(mCvMutex); |
| 358 | base::ScopedLockAssertion lock_assertion(mCvMutex); |
| 359 | if (mState == BluetoothStreamState::STARTED) { |
| 360 | return true; // nop, return |
| 361 | } else if (mState == BluetoothStreamState::SUSPENDING || |
| 362 | mState == BluetoothStreamState::STARTING) { |
| 363 | /* If port is in transient state, give some time to respond */ |
| 364 | auto state_ = mState; |
| 365 | lock.unlock(); |
| 366 | if (!condWaitState(state_)) { |
| 367 | LOG(ERROR) << __func__ << debugMessage() << ", state=" << getState() << " failure"; |
| 368 | return false; |
| 369 | } |
| 370 | } |
| 371 | } |
| 372 | |
| 373 | bool retval = false; |
| 374 | { |
| 375 | std::unique_lock lock(mCvMutex); |
| 376 | base::ScopedLockAssertion lock_assertion(mCvMutex); |
| 377 | if (mState == BluetoothStreamState::STARTED) { |
| 378 | retval = true; |
| 379 | } else if (mState == BluetoothStreamState::STANDBY) { |
| 380 | mState = BluetoothStreamState::STARTING; |
| 381 | lock.unlock(); |
| 382 | if (BluetoothAudioSessionControl::StartStream(mSessionType)) { |
| 383 | retval = condWaitState(BluetoothStreamState::STARTING); |
| 384 | } else { |
| 385 | LOG(ERROR) << __func__ << debugMessage() << ", state=" << getState() |
| 386 | << " Hal fails"; |
| 387 | } |
| 388 | } |
| 389 | } |
| 390 | |
| 391 | if (retval) { |
| 392 | LOG(INFO) << __func__ << debugMessage() << ", state=" << getState() |
| 393 | << ", mono=" << (mIsStereoToMono ? "true" : "false") << " done"; |
| 394 | } else { |
| 395 | LOG(ERROR) << __func__ << debugMessage() << ", state=" << getState() << " failure"; |
| 396 | } |
| 397 | |
| 398 | return retval; // false if any failure like timeout |
| 399 | } |
| 400 | |
| 401 | bool BluetoothAudioPortAidl::suspend() { |
| 402 | if (!inUse()) { |
| 403 | LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use"; |
| 404 | return false; |
| 405 | } |
| 406 | LOG(VERBOSE) << __func__ << debugMessage() << ", state=" << getState() << " request"; |
| 407 | |
| 408 | { |
| 409 | std::unique_lock lock(mCvMutex); |
| 410 | base::ScopedLockAssertion lock_assertion(mCvMutex); |
| 411 | if (mState == BluetoothStreamState::STANDBY) { |
| 412 | return true; // nop, return |
| 413 | } else if (mState == BluetoothStreamState::SUSPENDING || |
| 414 | mState == BluetoothStreamState::STARTING) { |
| 415 | /* If port is in transient state, give some time to respond */ |
| 416 | auto state_ = mState; |
| 417 | lock.unlock(); |
| 418 | if (!condWaitState(state_)) { |
| 419 | LOG(ERROR) << __func__ << debugMessage() << ", state=" << getState() << " failure"; |
| 420 | return false; |
| 421 | } |
| 422 | } |
| 423 | } |
| 424 | |
| 425 | bool retval = false; |
| 426 | { |
| 427 | std::unique_lock lock(mCvMutex); |
| 428 | base::ScopedLockAssertion lock_assertion(mCvMutex); |
| 429 | if (mState == BluetoothStreamState::STANDBY) { |
| 430 | retval = true; |
| 431 | } else if (mState == BluetoothStreamState::STARTED) { |
| 432 | mState = BluetoothStreamState::SUSPENDING; |
| 433 | lock.unlock(); |
| 434 | if (BluetoothAudioSessionControl::SuspendStream(mSessionType)) { |
| 435 | retval = condWaitState(BluetoothStreamState::SUSPENDING); |
| 436 | } else { |
| 437 | LOG(ERROR) << __func__ << debugMessage() << ", state=" << getState() |
| 438 | << " Hal fails"; |
| 439 | } |
| 440 | } |
| 441 | } |
| 442 | |
| 443 | if (retval) { |
| 444 | LOG(INFO) << __func__ << debugMessage() << ", state=" << getState() << " done"; |
| 445 | } else { |
| 446 | LOG(ERROR) << __func__ << debugMessage() << ", state=" << getState() << " failure"; |
| 447 | } |
| 448 | |
| 449 | return retval; // false if any failure like timeout |
| 450 | } |
| 451 | |
| 452 | void BluetoothAudioPortAidl::stop() { |
| 453 | if (!inUse()) { |
| 454 | LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use"; |
| 455 | return; |
| 456 | } |
| 457 | std::lock_guard guard(mCvMutex); |
| 458 | LOG(VERBOSE) << __func__ << debugMessage() << ", state=" << getState() << " request"; |
| 459 | if (mState != BluetoothStreamState::DISABLED) { |
| 460 | BluetoothAudioSessionControl::StopStream(mSessionType); |
| 461 | mState = BluetoothStreamState::DISABLED; |
| 462 | } |
| 463 | LOG(VERBOSE) << __func__ << debugMessage() << ", state=" << getState() << " done"; |
| 464 | } |
| 465 | |
| 466 | size_t BluetoothAudioPortAidlOut::writeData(const void* buffer, size_t bytes) const { |
| 467 | if (!buffer) { |
| 468 | LOG(ERROR) << __func__ << ": bad input arg"; |
| 469 | return 0; |
| 470 | } |
| 471 | |
| 472 | if (!inUse()) { |
| 473 | LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use"; |
| 474 | return 0; |
| 475 | } |
| 476 | |
| 477 | if (!mIsStereoToMono) { |
| 478 | return BluetoothAudioSessionControl::OutWritePcmData(mSessionType, buffer, bytes); |
| 479 | } |
| 480 | |
| 481 | // WAR to mix the stereo into Mono (16 bits per sample) |
| 482 | const size_t write_frames = bytes >> 2; |
| 483 | if (write_frames == 0) return 0; |
| 484 | auto src = static_cast<const int16_t*>(buffer); |
| 485 | std::unique_ptr<int16_t[]> dst{new int16_t[write_frames]}; |
| 486 | downmix_to_mono_i16_from_stereo_i16(dst.get(), src, write_frames); |
| 487 | // a frame is 16 bits, and the size of a mono frame is equal to half a stereo. |
| 488 | auto totalWrite = BluetoothAudioSessionControl::OutWritePcmData(mSessionType, dst.get(), |
| 489 | write_frames * 2); |
| 490 | return totalWrite * 2; |
| 491 | } |
| 492 | |
| 493 | size_t BluetoothAudioPortAidlIn::readData(void* buffer, size_t bytes) const { |
| 494 | if (!buffer) { |
| 495 | LOG(ERROR) << __func__ << ": bad input arg"; |
| 496 | return 0; |
| 497 | } |
| 498 | |
| 499 | if (!inUse()) { |
| 500 | LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use"; |
| 501 | return 0; |
| 502 | } |
| 503 | |
| 504 | return BluetoothAudioSessionControl::InReadPcmData(mSessionType, buffer, bytes); |
| 505 | } |
| 506 | |
| 507 | bool BluetoothAudioPortAidl::getPresentationPosition( |
| 508 | PresentationPosition& presentation_position) const { |
| 509 | if (!inUse()) { |
| 510 | LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use"; |
| 511 | return false; |
| 512 | } |
| 513 | bool retval = BluetoothAudioSessionControl::GetPresentationPosition(mSessionType, |
| 514 | presentation_position); |
| 515 | LOG(VERBOSE) << __func__ << debugMessage() << ", state=" << getState() |
| 516 | << presentation_position.toString(); |
| 517 | |
| 518 | return retval; |
| 519 | } |
| 520 | |
| 521 | bool BluetoothAudioPortAidl::updateSourceMetadata(const SourceMetadata& source_metadata) const { |
| 522 | if (!inUse()) { |
| 523 | LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use"; |
| 524 | return false; |
| 525 | } |
| 526 | LOG(DEBUG) << __func__ << debugMessage() << ", state=" << getState() << ", " |
| 527 | << source_metadata.tracks.size() << " track(s)"; |
| 528 | if (source_metadata.tracks.size() == 0) return true; |
| 529 | return BluetoothAudioSessionControl::UpdateSourceMetadata(mSessionType, source_metadata); |
| 530 | } |
| 531 | |
| 532 | bool BluetoothAudioPortAidl::updateSinkMetadata(const SinkMetadata& sink_metadata) const { |
| 533 | if (!inUse()) { |
| 534 | LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use"; |
| 535 | return false; |
| 536 | } |
| 537 | LOG(DEBUG) << __func__ << debugMessage() << ", state=" << getState() << ", " |
| 538 | << sink_metadata.tracks.size() << " track(s)"; |
| 539 | if (sink_metadata.tracks.size() == 0) return true; |
| 540 | return BluetoothAudioSessionControl::UpdateSinkMetadata(mSessionType, sink_metadata); |
| 541 | } |
| 542 | |
| 543 | BluetoothStreamState BluetoothAudioPortAidl::getState() const { |
| 544 | return mState; |
| 545 | } |
| 546 | |
| 547 | bool BluetoothAudioPortAidl::setState(BluetoothStreamState state) { |
| 548 | if (!inUse()) { |
| 549 | LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use"; |
| 550 | return false; |
| 551 | } |
| 552 | std::lock_guard guard(mCvMutex); |
| 553 | LOG(DEBUG) << __func__ << ": BluetoothAudioPortAidl old state = " << mState |
| 554 | << " new state = " << state; |
| 555 | mState = state; |
| 556 | return true; |
| 557 | } |
| 558 | |
| 559 | bool BluetoothAudioPortAidl::isA2dp() const { |
| 560 | return mSessionType == SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH || |
| 561 | mSessionType == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH; |
| 562 | } |
| 563 | |
| 564 | bool BluetoothAudioPortAidl::isLeAudio() const { |
| 565 | return mSessionType == SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH || |
| 566 | mSessionType == SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH || |
| 567 | mSessionType == SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH || |
| 568 | mSessionType == SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH || |
| 569 | mSessionType == SessionType::LE_AUDIO_BROADCAST_SOFTWARE_ENCODING_DATAPATH || |
| 570 | mSessionType == SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH; |
| 571 | } |
| 572 | |
| 573 | std::string BluetoothAudioPortAidl::debugMessage() const { |
| 574 | return StringPrintf(": session_type=%s, cookie=%#hx", toString(mSessionType).c_str(), mCookie); |
| 575 | } |
| 576 | |
| 577 | } // namespace android::bluetooth::audio::aidl |