| /* |
| * Copyright 2023 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #define LOG_TAG "AHAL_BluetoothAudioPort" |
| |
| #include <android-base/logging.h> |
| #include <android-base/stringprintf.h> |
| #include <audio_utils/primitives.h> |
| #include <log/log.h> |
| |
| #include "BluetoothAudioSessionControl.h" |
| #include "core-impl/DevicePortProxy.h" |
| |
| using aidl::android::hardware::audio::common::SinkMetadata; |
| using aidl::android::hardware::audio::common::SourceMetadata; |
| using aidl::android::hardware::bluetooth::audio::AudioConfiguration; |
| using aidl::android::hardware::bluetooth::audio::BluetoothAudioSessionControl; |
| using aidl::android::hardware::bluetooth::audio::BluetoothAudioStatus; |
| using aidl::android::hardware::bluetooth::audio::ChannelMode; |
| using aidl::android::hardware::bluetooth::audio::PcmConfiguration; |
| using aidl::android::hardware::bluetooth::audio::PortStatusCallbacks; |
| using aidl::android::hardware::bluetooth::audio::PresentationPosition; |
| using aidl::android::hardware::bluetooth::audio::SessionType; |
| using aidl::android::media::audio::common::AudioDeviceDescription; |
| using aidl::android::media::audio::common::AudioDeviceType; |
| using android::base::StringPrintf; |
| |
| namespace android::bluetooth::audio::aidl { |
| |
| namespace { |
| |
| // The maximum time to wait in std::condition_variable::wait_for() |
| constexpr unsigned int kMaxWaitingTimeMs = 4500; |
| |
| } // namespace |
| |
| std::ostream& operator<<(std::ostream& os, const BluetoothStreamState& state) { |
| switch (state) { |
| case BluetoothStreamState::DISABLED: |
| return os << "DISABLED"; |
| case BluetoothStreamState::STANDBY: |
| return os << "STANDBY"; |
| case BluetoothStreamState::STARTING: |
| return os << "STARTING"; |
| case BluetoothStreamState::STARTED: |
| return os << "STARTED"; |
| case BluetoothStreamState::SUSPENDING: |
| return os << "SUSPENDING"; |
| case BluetoothStreamState::UNKNOWN: |
| return os << "UNKNOWN"; |
| default: |
| return os << android::base::StringPrintf("%#hhx", state); |
| } |
| } |
| |
| BluetoothAudioPortAidl::BluetoothAudioPortAidl() |
| : mCookie(::aidl::android::hardware::bluetooth::audio::kObserversCookieUndefined), |
| mState(BluetoothStreamState::DISABLED), |
| mSessionType(SessionType::UNKNOWN) {} |
| |
| BluetoothAudioPortAidl::~BluetoothAudioPortAidl() { |
| unregisterPort(); |
| } |
| |
| bool BluetoothAudioPortAidl::registerPort(const AudioDeviceDescription& description) { |
| if (inUse()) { |
| LOG(ERROR) << __func__ << debugMessage() << " already in use"; |
| return false; |
| } |
| |
| if (!initSessionType(description)) return false; |
| |
| auto control_result_cb = [port = this](uint16_t cookie, bool start_resp, |
| const BluetoothAudioStatus& status) { |
| (void)start_resp; |
| port->controlResultHandler(cookie, status); |
| }; |
| auto session_changed_cb = [port = this](uint16_t cookie) { |
| port->sessionChangedHandler(cookie); |
| }; |
| // TODO: Add audio_config_changed_cb |
| PortStatusCallbacks cbacks = { |
| .control_result_cb_ = control_result_cb, |
| .session_changed_cb_ = session_changed_cb, |
| }; |
| mCookie = BluetoothAudioSessionControl::RegisterControlResultCback(mSessionType, cbacks); |
| auto isOk = (mCookie != ::aidl::android::hardware::bluetooth::audio::kObserversCookieUndefined); |
| if (isOk) { |
| std::lock_guard guard(mCvMutex); |
| mState = BluetoothStreamState::STANDBY; |
| } |
| LOG(DEBUG) << __func__ << debugMessage(); |
| return isOk; |
| } |
| |
| bool BluetoothAudioPortAidl::initSessionType(const AudioDeviceDescription& description) { |
| if (description.connection == AudioDeviceDescription::CONNECTION_BT_A2DP && |
| (description.type == AudioDeviceType::OUT_DEVICE || |
| description.type == AudioDeviceType::OUT_HEADPHONE || |
| description.type == AudioDeviceType::OUT_SPEAKER)) { |
| LOG(VERBOSE) << __func__ |
| << ": device=AUDIO_DEVICE_OUT_BLUETOOTH_A2DP (HEADPHONES/SPEAKER) (" |
| << description.toString() << ")"; |
| mSessionType = SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH; |
| } else if (description.connection == AudioDeviceDescription::CONNECTION_WIRELESS && |
| description.type == AudioDeviceType::OUT_HEARING_AID) { |
| LOG(VERBOSE) << __func__ << ": device=AUDIO_DEVICE_OUT_HEARING_AID (MEDIA/VOICE) (" |
| << description.toString() << ")"; |
| mSessionType = SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH; |
| } else if (description.connection == AudioDeviceDescription::CONNECTION_BT_LE && |
| description.type == AudioDeviceType::OUT_HEADSET) { |
| LOG(VERBOSE) << __func__ << ": device=AUDIO_DEVICE_OUT_BLE_HEADSET (MEDIA/VOICE) (" |
| << description.toString() << ")"; |
| mSessionType = SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH; |
| } else if (description.connection == AudioDeviceDescription::CONNECTION_BT_LE && |
| description.type == AudioDeviceType::OUT_SPEAKER) { |
| LOG(VERBOSE) << __func__ << ": device=AUDIO_DEVICE_OUT_BLE_SPEAKER (MEDIA) (" |
| << description.toString() << ")"; |
| mSessionType = SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH; |
| } else if (description.connection == AudioDeviceDescription::CONNECTION_BT_LE && |
| description.type == AudioDeviceType::IN_HEADSET) { |
| LOG(VERBOSE) << __func__ << ": device=AUDIO_DEVICE_IN_BLE_HEADSET (VOICE) (" |
| << description.toString() << ")"; |
| mSessionType = SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH; |
| } else if (description.connection == AudioDeviceDescription::CONNECTION_BT_LE && |
| description.type == AudioDeviceType::OUT_BROADCAST) { |
| LOG(VERBOSE) << __func__ << ": device=AUDIO_DEVICE_OUT_BLE_BROADCAST (MEDIA) (" |
| << description.toString() << ")"; |
| mSessionType = SessionType::LE_AUDIO_BROADCAST_SOFTWARE_ENCODING_DATAPATH; |
| } else { |
| LOG(ERROR) << __func__ << ": unknown device=" << description.toString(); |
| return false; |
| } |
| |
| if (!BluetoothAudioSessionControl::IsSessionReady(mSessionType)) { |
| LOG(ERROR) << __func__ << ": device=" << description.toString() |
| << ", session_type=" << toString(mSessionType) << " is not ready"; |
| return false; |
| } |
| return true; |
| } |
| |
| void BluetoothAudioPortAidl::unregisterPort() { |
| if (!inUse()) { |
| LOG(WARNING) << __func__ << ": BluetoothAudioPortAidl is not in use"; |
| return; |
| } |
| BluetoothAudioSessionControl::UnregisterControlResultCback(mSessionType, mCookie); |
| mCookie = ::aidl::android::hardware::bluetooth::audio::kObserversCookieUndefined; |
| LOG(VERBOSE) << __func__ << debugMessage() << " port unregistered"; |
| } |
| |
| void BluetoothAudioPortAidl::controlResultHandler(uint16_t cookie, |
| const BluetoothAudioStatus& status) { |
| std::lock_guard guard(mCvMutex); |
| if (!inUse()) { |
| LOG(ERROR) << "control_result_cb: BluetoothAudioPortAidl is not in use"; |
| return; |
| } |
| if (mCookie != cookie) { |
| LOG(ERROR) << "control_result_cb: proxy of device port (cookie=" |
| << StringPrintf("%#hx", cookie) << ") is corrupted"; |
| return; |
| } |
| BluetoothStreamState previous_state = mState; |
| LOG(INFO) << "control_result_cb:" << debugMessage() << ", previous_state=" << previous_state |
| << ", status=" << toString(status); |
| |
| switch (previous_state) { |
| case BluetoothStreamState::STARTED: |
| /* Only Suspend signal can be send in STARTED state*/ |
| if (status == BluetoothAudioStatus::RECONFIGURATION || |
| status == BluetoothAudioStatus::SUCCESS) { |
| mState = BluetoothStreamState::STANDBY; |
| } else { |
| LOG(WARNING) << StringPrintf( |
| "control_result_cb: status=%s failure for session_type= %s, cookie=%#hx, " |
| "previous_state=%#hhx", |
| toString(status).c_str(), toString(mSessionType).c_str(), mCookie, |
| previous_state); |
| } |
| break; |
| case BluetoothStreamState::STARTING: |
| if (status == BluetoothAudioStatus::SUCCESS) { |
| mState = BluetoothStreamState::STARTED; |
| } else { |
| // Set to standby since the stack may be busy switching between outputs |
| LOG(WARNING) << StringPrintf( |
| "control_result_cb: status=%s failure for session_type= %s, cookie=%#hx, " |
| "previous_state=%#hhx", |
| toString(status).c_str(), toString(mSessionType).c_str(), mCookie, |
| previous_state); |
| mState = BluetoothStreamState::STANDBY; |
| } |
| break; |
| case BluetoothStreamState::SUSPENDING: |
| if (status == BluetoothAudioStatus::SUCCESS) { |
| mState = BluetoothStreamState::STANDBY; |
| } else { |
| // It will be failed if the headset is disconnecting, and set to disable |
| // to wait for re-init again |
| LOG(WARNING) << StringPrintf( |
| "control_result_cb: status=%s failure for session_type= %s, cookie=%#hx, " |
| "previous_state=%#hhx", |
| toString(status).c_str(), toString(mSessionType).c_str(), mCookie, |
| previous_state); |
| mState = BluetoothStreamState::DISABLED; |
| } |
| break; |
| default: |
| LOG(ERROR) << "control_result_cb: unexpected previous_state=" |
| << StringPrintf( |
| "control_result_cb: status=%s failure for session_type= %s, " |
| "cookie=%#hx, previous_state=%#hhx", |
| toString(status).c_str(), toString(mSessionType).c_str(), mCookie, |
| previous_state); |
| return; |
| } |
| mInternalCv.notify_all(); |
| } |
| |
| void BluetoothAudioPortAidl::sessionChangedHandler(uint16_t cookie) { |
| std::lock_guard guard(mCvMutex); |
| if (!inUse()) { |
| LOG(ERROR) << "session_changed_cb: BluetoothAudioPortAidl is not in use"; |
| return; |
| } |
| if (mCookie != cookie) { |
| LOG(ERROR) << "session_changed_cb: proxy of device port (cookie=" |
| << StringPrintf("%#hx", cookie) << ") is corrupted"; |
| return; |
| } |
| BluetoothStreamState previous_state = mState; |
| LOG(VERBOSE) << "session_changed_cb:" << debugMessage() |
| << ", previous_state=" << previous_state; |
| mState = BluetoothStreamState::DISABLED; |
| mInternalCv.notify_all(); |
| } |
| |
| bool BluetoothAudioPortAidl::inUse() const { |
| return (mCookie != ::aidl::android::hardware::bluetooth::audio::kObserversCookieUndefined); |
| } |
| |
| bool BluetoothAudioPortAidl::getPreferredDataIntervalUs(size_t& interval_us) const { |
| if (!inUse()) { |
| LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use"; |
| return false; |
| } |
| |
| const AudioConfiguration& hal_audio_cfg = |
| BluetoothAudioSessionControl::GetAudioConfig(mSessionType); |
| if (hal_audio_cfg.getTag() != AudioConfiguration::pcmConfig) { |
| LOG(ERROR) << __func__ << ": unsupported audio cfg tag"; |
| return false; |
| } |
| |
| interval_us = hal_audio_cfg.get<AudioConfiguration::pcmConfig>().dataIntervalUs; |
| return true; |
| } |
| |
| bool BluetoothAudioPortAidl::loadAudioConfig(PcmConfiguration& audio_cfg) { |
| if (!inUse()) { |
| LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use"; |
| return false; |
| } |
| |
| const AudioConfiguration& hal_audio_cfg = |
| BluetoothAudioSessionControl::GetAudioConfig(mSessionType); |
| if (hal_audio_cfg.getTag() != AudioConfiguration::pcmConfig) { |
| LOG(ERROR) << __func__ << ": unsupported audio cfg tag"; |
| return false; |
| } |
| audio_cfg = hal_audio_cfg.get<AudioConfiguration::pcmConfig>(); |
| LOG(VERBOSE) << __func__ << debugMessage() << ", state*=" << getState() << ", PcmConfig=[" |
| << audio_cfg.toString() << "]"; |
| if (audio_cfg.channelMode == ChannelMode::UNKNOWN) { |
| return false; |
| } |
| return true; |
| } |
| |
| bool BluetoothAudioPortAidlOut::loadAudioConfig(PcmConfiguration& audio_cfg) { |
| if (!BluetoothAudioPortAidl::loadAudioConfig(audio_cfg)) return false; |
| // WAR to support Mono / 16 bits per sample as the Bluetooth stack requires |
| if (audio_cfg.channelMode == ChannelMode::MONO && audio_cfg.bitsPerSample == 16) { |
| mIsStereoToMono = true; |
| audio_cfg.channelMode = ChannelMode::STEREO; |
| LOG(INFO) << __func__ << ": force channels = to be AUDIO_CHANNEL_OUT_STEREO"; |
| } |
| return true; |
| } |
| |
| bool BluetoothAudioPortAidl::standby() { |
| if (!inUse()) { |
| LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use"; |
| return false; |
| } |
| std::lock_guard guard(mCvMutex); |
| LOG(VERBOSE) << __func__ << debugMessage() << ", state=" << getState() << " request"; |
| if (mState == BluetoothStreamState::DISABLED) { |
| mState = BluetoothStreamState::STANDBY; |
| LOG(VERBOSE) << __func__ << debugMessage() << ", state=" << getState() << " done"; |
| return true; |
| } |
| return false; |
| } |
| |
| bool BluetoothAudioPortAidl::condWaitState(BluetoothStreamState state) { |
| const auto waitTime = std::chrono::milliseconds(kMaxWaitingTimeMs); |
| std::unique_lock lock(mCvMutex); |
| base::ScopedLockAssertion lock_assertion(mCvMutex); |
| switch (state) { |
| case BluetoothStreamState::STARTING: { |
| LOG(VERBOSE) << __func__ << debugMessage() << " waiting for STARTED"; |
| mInternalCv.wait_for(lock, waitTime, [this] { |
| base::ScopedLockAssertion lock_assertion(mCvMutex); |
| return mState != BluetoothStreamState::STARTING; |
| }); |
| return mState == BluetoothStreamState::STARTED; |
| } |
| case BluetoothStreamState::SUSPENDING: { |
| LOG(VERBOSE) << __func__ << debugMessage() << " waiting for SUSPENDED"; |
| mInternalCv.wait_for(lock, waitTime, [this] { |
| base::ScopedLockAssertion lock_assertion(mCvMutex); |
| return mState != BluetoothStreamState::SUSPENDING; |
| }); |
| return mState == BluetoothStreamState::STANDBY; |
| } |
| default: |
| LOG(WARNING) << __func__ << debugMessage() << " waiting for KNOWN"; |
| return false; |
| } |
| return false; |
| } |
| |
| bool BluetoothAudioPortAidl::start() { |
| if (!inUse()) { |
| LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use"; |
| return false; |
| } |
| LOG(VERBOSE) << __func__ << debugMessage() << ", state=" << getState() |
| << ", mono=" << (mIsStereoToMono ? "true" : "false") << " request"; |
| |
| { |
| std::unique_lock lock(mCvMutex); |
| base::ScopedLockAssertion lock_assertion(mCvMutex); |
| if (mState == BluetoothStreamState::STARTED) { |
| return true; // nop, return |
| } else if (mState == BluetoothStreamState::SUSPENDING || |
| mState == BluetoothStreamState::STARTING) { |
| /* If port is in transient state, give some time to respond */ |
| auto state_ = mState; |
| lock.unlock(); |
| if (!condWaitState(state_)) { |
| LOG(ERROR) << __func__ << debugMessage() << ", state=" << getState() << " failure"; |
| return false; |
| } |
| } |
| } |
| |
| bool retval = false; |
| { |
| std::unique_lock lock(mCvMutex); |
| base::ScopedLockAssertion lock_assertion(mCvMutex); |
| if (mState == BluetoothStreamState::STARTED) { |
| retval = true; |
| } else if (mState == BluetoothStreamState::STANDBY) { |
| mState = BluetoothStreamState::STARTING; |
| lock.unlock(); |
| if (BluetoothAudioSessionControl::StartStream(mSessionType)) { |
| retval = condWaitState(BluetoothStreamState::STARTING); |
| } else { |
| LOG(ERROR) << __func__ << debugMessage() << ", state=" << getState() |
| << " Hal fails"; |
| } |
| } |
| } |
| |
| if (retval) { |
| LOG(INFO) << __func__ << debugMessage() << ", state=" << getState() |
| << ", mono=" << (mIsStereoToMono ? "true" : "false") << " done"; |
| } else { |
| LOG(ERROR) << __func__ << debugMessage() << ", state=" << getState() << " failure"; |
| } |
| |
| return retval; // false if any failure like timeout |
| } |
| |
| bool BluetoothAudioPortAidl::suspend() { |
| if (!inUse()) { |
| LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use"; |
| return false; |
| } |
| LOG(VERBOSE) << __func__ << debugMessage() << ", state=" << getState() << " request"; |
| |
| { |
| std::unique_lock lock(mCvMutex); |
| base::ScopedLockAssertion lock_assertion(mCvMutex); |
| if (mState == BluetoothStreamState::STANDBY) { |
| return true; // nop, return |
| } else if (mState == BluetoothStreamState::SUSPENDING || |
| mState == BluetoothStreamState::STARTING) { |
| /* If port is in transient state, give some time to respond */ |
| auto state_ = mState; |
| lock.unlock(); |
| if (!condWaitState(state_)) { |
| LOG(ERROR) << __func__ << debugMessage() << ", state=" << getState() << " failure"; |
| return false; |
| } |
| } |
| } |
| |
| bool retval = false; |
| { |
| std::unique_lock lock(mCvMutex); |
| base::ScopedLockAssertion lock_assertion(mCvMutex); |
| if (mState == BluetoothStreamState::STANDBY) { |
| retval = true; |
| } else if (mState == BluetoothStreamState::STARTED) { |
| mState = BluetoothStreamState::SUSPENDING; |
| lock.unlock(); |
| if (BluetoothAudioSessionControl::SuspendStream(mSessionType)) { |
| retval = condWaitState(BluetoothStreamState::SUSPENDING); |
| } else { |
| LOG(ERROR) << __func__ << debugMessage() << ", state=" << getState() |
| << " failure to suspend stream"; |
| } |
| } |
| } |
| |
| if (retval) { |
| LOG(INFO) << __func__ << debugMessage() << ", state=" << getState() << " done"; |
| } else { |
| LOG(ERROR) << __func__ << debugMessage() << ", state=" << getState() << " failure"; |
| } |
| |
| return retval; // false if any failure like timeout |
| } |
| |
| void BluetoothAudioPortAidl::stop() { |
| if (!inUse()) { |
| LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use"; |
| return; |
| } |
| std::lock_guard guard(mCvMutex); |
| LOG(VERBOSE) << __func__ << debugMessage() << ", state=" << getState() << " request"; |
| if (mState != BluetoothStreamState::DISABLED) { |
| BluetoothAudioSessionControl::StopStream(mSessionType); |
| mState = BluetoothStreamState::DISABLED; |
| } |
| LOG(VERBOSE) << __func__ << debugMessage() << ", state=" << getState() << " done"; |
| } |
| |
| size_t BluetoothAudioPortAidlOut::writeData(const void* buffer, size_t bytes) const { |
| if (!buffer) { |
| LOG(ERROR) << __func__ << ": bad input arg"; |
| return 0; |
| } |
| |
| if (!inUse()) { |
| LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use"; |
| return 0; |
| } |
| |
| if (!mIsStereoToMono) { |
| return BluetoothAudioSessionControl::OutWritePcmData(mSessionType, buffer, bytes); |
| } |
| |
| // WAR to mix the stereo into Mono (16 bits per sample) |
| const size_t write_frames = bytes >> 2; |
| if (write_frames == 0) return 0; |
| auto src = static_cast<const int16_t*>(buffer); |
| std::unique_ptr<int16_t[]> dst{new int16_t[write_frames]}; |
| downmix_to_mono_i16_from_stereo_i16(dst.get(), src, write_frames); |
| // a frame is 16 bits, and the size of a mono frame is equal to half a stereo. |
| auto totalWrite = BluetoothAudioSessionControl::OutWritePcmData(mSessionType, dst.get(), |
| write_frames * 2); |
| return totalWrite * 2; |
| } |
| |
| size_t BluetoothAudioPortAidlIn::readData(void* buffer, size_t bytes) const { |
| if (!buffer) { |
| LOG(ERROR) << __func__ << ": bad input arg"; |
| return 0; |
| } |
| |
| if (!inUse()) { |
| LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use"; |
| return 0; |
| } |
| |
| return BluetoothAudioSessionControl::InReadPcmData(mSessionType, buffer, bytes); |
| } |
| |
| bool BluetoothAudioPortAidl::getPresentationPosition( |
| PresentationPosition& presentation_position) const { |
| if (!inUse()) { |
| LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use"; |
| return false; |
| } |
| bool retval = BluetoothAudioSessionControl::GetPresentationPosition(mSessionType, |
| presentation_position); |
| LOG(VERBOSE) << __func__ << debugMessage() << ", state=" << getState() |
| << presentation_position.toString(); |
| |
| return retval; |
| } |
| |
| bool BluetoothAudioPortAidl::updateSourceMetadata(const SourceMetadata& source_metadata) const { |
| if (!inUse()) { |
| LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use"; |
| return false; |
| } |
| LOG(DEBUG) << __func__ << debugMessage() << ", state=" << getState() << ", " |
| << source_metadata.tracks.size() << " track(s)"; |
| if (source_metadata.tracks.size() == 0) return true; |
| return BluetoothAudioSessionControl::UpdateSourceMetadata(mSessionType, source_metadata); |
| } |
| |
| bool BluetoothAudioPortAidl::updateSinkMetadata(const SinkMetadata& sink_metadata) const { |
| if (!inUse()) { |
| LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use"; |
| return false; |
| } |
| LOG(DEBUG) << __func__ << debugMessage() << ", state=" << getState() << ", " |
| << sink_metadata.tracks.size() << " track(s)"; |
| if (sink_metadata.tracks.size() == 0) return true; |
| return BluetoothAudioSessionControl::UpdateSinkMetadata(mSessionType, sink_metadata); |
| } |
| |
| BluetoothStreamState BluetoothAudioPortAidl::getState() const { |
| return mState; |
| } |
| |
| bool BluetoothAudioPortAidl::setState(BluetoothStreamState state) { |
| if (!inUse()) { |
| LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use"; |
| return false; |
| } |
| std::lock_guard guard(mCvMutex); |
| LOG(DEBUG) << __func__ << ": BluetoothAudioPortAidl old state = " << mState |
| << " new state = " << state; |
| mState = state; |
| return true; |
| } |
| |
| bool BluetoothAudioPortAidl::isA2dp() const { |
| return mSessionType == SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH || |
| mSessionType == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH; |
| } |
| |
| bool BluetoothAudioPortAidl::isLeAudio() const { |
| return mSessionType == SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH || |
| mSessionType == SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH || |
| mSessionType == SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH || |
| mSessionType == SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH || |
| mSessionType == SessionType::LE_AUDIO_BROADCAST_SOFTWARE_ENCODING_DATAPATH || |
| mSessionType == SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH; |
| } |
| |
| std::string BluetoothAudioPortAidl::debugMessage() const { |
| return StringPrintf(": session_type=%s, cookie=%#hx", toString(mSessionType).c_str(), mCookie); |
| } |
| |
| } // namespace android::bluetooth::audio::aidl |