audio: import aidl hal
* hardware/interfaces/audio/aidl/default/ at android-16.0.0_r1.
This commit is contained in:
271
audio/deprecated/StreamSwitcher.cpp
Normal file
271
audio/deprecated/StreamSwitcher.cpp
Normal file
@@ -0,0 +1,271 @@
|
||||
/*
|
||||
* Copyright (C) 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.
|
||||
*/
|
||||
|
||||
#include <limits>
|
||||
|
||||
#define LOG_TAG "AHAL_StreamSwitcher"
|
||||
|
||||
#include <Utils.h>
|
||||
#include <android-base/logging.h>
|
||||
#include <error/expected_utils.h>
|
||||
|
||||
#include "core-impl/StreamStub.h"
|
||||
#include "deprecated/StreamSwitcher.h"
|
||||
|
||||
using aidl::android::hardware::audio::effect::IEffect;
|
||||
using aidl::android::media::audio::common::AudioDevice;
|
||||
|
||||
namespace aidl::android::hardware::audio::core::deprecated {
|
||||
|
||||
StreamSwitcher::StreamSwitcher(StreamContext* context, const Metadata& metadata)
|
||||
: mContext(context),
|
||||
mMetadata(metadata),
|
||||
mStream(new InnerStreamWrapper<StreamStub>(context, mMetadata)) {}
|
||||
|
||||
ndk::ScopedAStatus StreamSwitcher::closeCurrentStream(bool validateStreamState) {
|
||||
if (!mStream) return ndk::ScopedAStatus::ok();
|
||||
RETURN_STATUS_IF_ERROR(mStream->prepareToClose());
|
||||
RETURN_STATUS_IF_ERROR(mStream->close());
|
||||
if (validateStreamState && !isValidClosingStreamState(mStream->getStatePriorToClosing())) {
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
}
|
||||
mStream.reset();
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus StreamSwitcher::close() {
|
||||
if (mStream != nullptr) {
|
||||
auto status = closeCurrentStream(false /*validateStreamState*/);
|
||||
// The actual state is irrelevant since only StreamSwitcher cares about it.
|
||||
onClose(StreamDescriptor::State::STANDBY);
|
||||
return status;
|
||||
}
|
||||
LOG(ERROR) << __func__ << ": stream was already closed";
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus StreamSwitcher::prepareToClose() {
|
||||
if (mStream != nullptr) {
|
||||
return mStream->prepareToClose();
|
||||
}
|
||||
LOG(ERROR) << __func__ << ": stream was closed";
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus StreamSwitcher::updateHwAvSyncId(int32_t in_hwAvSyncId) {
|
||||
if (mStream == nullptr) {
|
||||
LOG(ERROR) << __func__ << ": stream was closed";
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
}
|
||||
RETURN_STATUS_IF_ERROR(mStream->updateHwAvSyncId(in_hwAvSyncId));
|
||||
mHwAvSyncId = in_hwAvSyncId;
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus StreamSwitcher::getVendorParameters(const std::vector<std::string>& in_ids,
|
||||
std::vector<VendorParameter>* _aidl_return) {
|
||||
if (mStream == nullptr) {
|
||||
LOG(ERROR) << __func__ << ": stream was closed";
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
}
|
||||
if (mIsStubStream) {
|
||||
LOG(ERROR) << __func__ << ": the stream is not connected";
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
}
|
||||
return mStream->getVendorParameters(in_ids, _aidl_return);
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus StreamSwitcher::setVendorParameters(
|
||||
const std::vector<VendorParameter>& in_parameters, bool in_async) {
|
||||
if (mStream == nullptr) {
|
||||
LOG(ERROR) << __func__ << ": stream was closed";
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
}
|
||||
if (mIsStubStream) {
|
||||
mMissedParameters.emplace_back(in_parameters, in_async);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
return mStream->setVendorParameters(in_parameters, in_async);
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus StreamSwitcher::addEffect(const std::shared_ptr<IEffect>& in_effect) {
|
||||
if (in_effect == nullptr) {
|
||||
LOG(DEBUG) << __func__ << ": null effect";
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
|
||||
}
|
||||
if (mStream == nullptr) {
|
||||
LOG(ERROR) << __func__ << ": stream was closed";
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
}
|
||||
if (!mIsStubStream) {
|
||||
RETURN_STATUS_IF_ERROR(mStream->addEffect(in_effect));
|
||||
}
|
||||
mEffects.push_back(in_effect);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus StreamSwitcher::removeEffect(const std::shared_ptr<IEffect>& in_effect) {
|
||||
if (in_effect == nullptr) {
|
||||
LOG(DEBUG) << __func__ << ": null effect";
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
|
||||
}
|
||||
if (mStream == nullptr) {
|
||||
LOG(ERROR) << __func__ << ": stream was closed";
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
}
|
||||
for (auto it = mEffects.begin(); it != mEffects.end(); ++it) {
|
||||
if ((*it)->asBinder() == in_effect->asBinder()) {
|
||||
mEffects.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return !mIsStubStream ? mStream->removeEffect(in_effect) : ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus StreamSwitcher::getStreamCommonCommon(
|
||||
std::shared_ptr<IStreamCommon>* _aidl_return) {
|
||||
if (!mCommon) {
|
||||
LOG(FATAL) << __func__ << ": the common interface was not created";
|
||||
}
|
||||
*_aidl_return = mCommon.getInstance();
|
||||
LOG(DEBUG) << __func__ << ": returning " << _aidl_return->get()->asBinder().get();
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus StreamSwitcher::updateMetadataCommon(const Metadata& metadata) {
|
||||
if (mStream == nullptr) {
|
||||
LOG(ERROR) << __func__ << ": stream was closed";
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
}
|
||||
mMetadata = metadata;
|
||||
return !mIsStubStream ? mStream->updateMetadataCommon(metadata) : ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus StreamSwitcher::initInstance(
|
||||
const std::shared_ptr<StreamCommonInterface>& delegate) {
|
||||
mCommon = ndk::SharedRefBase::make<StreamCommonDelegator>(delegate);
|
||||
// The delegate is null because StreamSwitcher handles IStreamCommon methods by itself.
|
||||
return mStream->initInstance(nullptr);
|
||||
}
|
||||
|
||||
const StreamContext& StreamSwitcher::getContext() const {
|
||||
return *mContext;
|
||||
}
|
||||
|
||||
bool StreamSwitcher::isClosed() const {
|
||||
return mStream == nullptr || mStream->isClosed();
|
||||
}
|
||||
|
||||
const StreamCommonInterface::ConnectedDevices& StreamSwitcher::getConnectedDevices() const {
|
||||
return mStream->getConnectedDevices();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus StreamSwitcher::setConnectedDevices(const std::vector<AudioDevice>& devices) {
|
||||
LOG(DEBUG) << __func__ << ": " << ::android::internal::ToString(devices);
|
||||
if (mStream->getConnectedDevices() == devices) return ndk::ScopedAStatus::ok();
|
||||
const DeviceSwitchBehavior behavior = switchCurrentStream(devices);
|
||||
if (behavior == DeviceSwitchBehavior::UNSUPPORTED_DEVICES) {
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
|
||||
} else if (behavior == DeviceSwitchBehavior::SWITCH_TO_STUB_STREAM && !devices.empty()) {
|
||||
// This is an error in the extending class.
|
||||
LOG(FATAL) << __func__
|
||||
<< ": switching to stub stream with connected devices is not allowed";
|
||||
}
|
||||
if (behavior == USE_CURRENT_STREAM) {
|
||||
mIsStubStream = false;
|
||||
} else {
|
||||
LOG(DEBUG) << __func__ << ": connected devices changed, switching stream";
|
||||
// Two streams can't be opened for the same context, thus we always need to close
|
||||
// the current one before creating a new one.
|
||||
RETURN_STATUS_IF_ERROR(closeCurrentStream(true /*validateStreamState*/));
|
||||
if (behavior == CREATE_NEW_STREAM) {
|
||||
mStream = createNewStream(devices, mContext, mMetadata);
|
||||
mIsStubStream = false;
|
||||
} else { // SWITCH_TO_STUB_STREAM
|
||||
mStream.reset(new InnerStreamWrapper<StreamStub>(mContext, mMetadata));
|
||||
mIsStubStream = true;
|
||||
}
|
||||
// The delegate is null because StreamSwitcher handles IStreamCommon methods by itself.
|
||||
if (ndk::ScopedAStatus status = mStream->initInstance(nullptr); !status.isOk()) {
|
||||
if (mIsStubStream) {
|
||||
LOG(FATAL) << __func__
|
||||
<< ": failed to initialize stub stream: " << status.getDescription();
|
||||
}
|
||||
// Need to close the current failed stream, and report an error.
|
||||
// Since we can't operate without a stream implementation, put a stub in.
|
||||
RETURN_STATUS_IF_ERROR(closeCurrentStream(false /*validateStreamState*/));
|
||||
mStream.reset(new InnerStreamWrapper<StreamStub>(mContext, mMetadata));
|
||||
(void)mStream->initInstance(nullptr);
|
||||
(void)mStream->setConnectedDevices(devices);
|
||||
return status;
|
||||
}
|
||||
}
|
||||
RETURN_STATUS_IF_ERROR(mStream->setConnectedDevices(devices));
|
||||
if (behavior == CREATE_NEW_STREAM) {
|
||||
// These updates are less critical, only log warning on failure.
|
||||
if (mHwAvSyncId.has_value()) {
|
||||
if (auto status = mStream->updateHwAvSyncId(*mHwAvSyncId); !status.isOk()) {
|
||||
LOG(WARNING) << __func__ << ": could not update HW AV Sync for a new stream: "
|
||||
<< status.getDescription();
|
||||
}
|
||||
}
|
||||
for (const auto& vndParam : mMissedParameters) {
|
||||
if (auto status = mStream->setVendorParameters(vndParam.first, vndParam.second);
|
||||
!status.isOk()) {
|
||||
LOG(WARNING) << __func__ << ": error while setting parameters for a new stream: "
|
||||
<< status.getDescription();
|
||||
}
|
||||
}
|
||||
mMissedParameters.clear();
|
||||
for (const auto& effect : mEffects) {
|
||||
if (auto status = mStream->addEffect(effect); !status.isOk()) {
|
||||
LOG(WARNING) << __func__ << ": error while adding effect for a new stream: "
|
||||
<< status.getDescription();
|
||||
}
|
||||
}
|
||||
if (mBluetoothParametersUpdated) {
|
||||
if (auto status = mStream->bluetoothParametersUpdated(); !status.isOk()) {
|
||||
LOG(WARNING) << __func__
|
||||
<< ": error while updating BT parameters for a new stream: "
|
||||
<< status.getDescription();
|
||||
}
|
||||
}
|
||||
mBluetoothParametersUpdated = false;
|
||||
}
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus StreamSwitcher::bluetoothParametersUpdated() {
|
||||
if (mStream == nullptr) {
|
||||
LOG(ERROR) << __func__ << ": stream was closed";
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
}
|
||||
if (mIsStubStream) {
|
||||
mBluetoothParametersUpdated = true;
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
return mStream->bluetoothParametersUpdated();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus StreamSwitcher::setGain(float gain) {
|
||||
if (mStream == nullptr) {
|
||||
LOG(ERROR) << __func__ << ": stream was closed";
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
}
|
||||
return mStream->setGain(gain);
|
||||
}
|
||||
|
||||
} // namespace aidl::android::hardware::audio::core::deprecated
|
||||
Reference in New Issue
Block a user