mirror of
https://github.com/Evolution-X/hardware_interfaces
synced 2026-02-01 21:37:44 +00:00
audio: Add IStreamCommon.prepareToClose method
This method is needed to implement HAL modules that are proxies for other subsystems, for example the "bluetooth" and "r_submix" modules. This method replaces string parameters "exiting=1" and "closing=true" which the framework sends to streams prior to closing them in order to unblock the I/O thread of the stream. Bug: 270731693 Test: atest VtsHalAudioCoreTargetTest Change-Id: I3d13fe34535ab853c9f8237a08c31cdafadbb390
This commit is contained in:
@@ -35,6 +35,7 @@ package android.hardware.audio.core;
|
||||
@VintfStability
|
||||
interface IStreamCommon {
|
||||
void close();
|
||||
void prepareToClose();
|
||||
void updateHwAvSyncId(int hwAvSyncId);
|
||||
android.hardware.audio.core.VendorParameter[] getVendorParameters(in @utf8InCpp String[] ids);
|
||||
void setVendorParameters(in android.hardware.audio.core.VendorParameter[] parameters, boolean async);
|
||||
|
||||
@@ -43,6 +43,33 @@ interface IStreamCommon {
|
||||
*/
|
||||
void close();
|
||||
|
||||
/**
|
||||
* Notify the stream that it is about to be closed.
|
||||
*
|
||||
* This is a notification sent by the client to indicate that it intends to
|
||||
* close the stream "soon" (the actual time period is unspecified). The
|
||||
* purpose of this notification is to allow the stream implementation to
|
||||
* unblock the I/O thread. This is useful for HAL modules that act as
|
||||
* proxies to other subsystems, examples are "bluetooth" and "r_submix"
|
||||
* modules. In such modules the I/O thread might get blocked on a read or
|
||||
* write operation to the external subsystem. Thus, calling 'close' directly
|
||||
* will stall, as it will try to send the 'Command.halReservedExit' on the
|
||||
* I/O thread which is blocked and is not reading commands from the FMQ. The
|
||||
* HAL implementation must initiate unblocking as a result of receiving the
|
||||
* 'prepareToClose' notification.
|
||||
*
|
||||
* This operation must be handled by the HAL module in an "asynchronous"
|
||||
* manner, returning control back as quick as possible.
|
||||
*
|
||||
* Since this operation does not have any effects observable from the client
|
||||
* side, the HAL module must be able to handle multiple calls of this method
|
||||
* without throwing any errors. The only case when this method is allowed
|
||||
* to throw is when the stream has been closed.
|
||||
*
|
||||
* @throws EX_ILLEGAL_STATE If the stream is closed.
|
||||
*/
|
||||
void prepareToClose();
|
||||
|
||||
/**
|
||||
* Update the HW AV Sync identifier for the stream.
|
||||
*
|
||||
|
||||
@@ -659,6 +659,16 @@ ndk::ScopedAStatus StreamCommonImpl<Metadata>::close() {
|
||||
}
|
||||
}
|
||||
|
||||
template <class Metadata>
|
||||
ndk::ScopedAStatus StreamCommonImpl<Metadata>::prepareToClose() {
|
||||
LOG(DEBUG) << __func__;
|
||||
if (!isClosed()) {
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
LOG(ERROR) << __func__ << ": stream was closed";
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
}
|
||||
|
||||
template <class Metadata>
|
||||
void StreamCommonImpl<Metadata>::stopWorker() {
|
||||
if (auto commandMQ = mContext.getCommandMQ(); commandMQ != nullptr) {
|
||||
|
||||
@@ -294,6 +294,7 @@ using StreamOutWorker = StreamWorkerImpl<StreamOutWorkerLogic>;
|
||||
struct StreamCommonInterface {
|
||||
virtual ~StreamCommonInterface() = default;
|
||||
virtual ndk::ScopedAStatus close() = 0;
|
||||
virtual ndk::ScopedAStatus prepareToClose() = 0;
|
||||
virtual ndk::ScopedAStatus updateHwAvSyncId(int32_t in_hwAvSyncId) = 0;
|
||||
virtual ndk::ScopedAStatus getVendorParameters(const std::vector<std::string>& in_ids,
|
||||
std::vector<VendorParameter>* _aidl_return) = 0;
|
||||
@@ -318,6 +319,11 @@ class StreamCommon : public BnStreamCommon {
|
||||
return delegate != nullptr ? delegate->close()
|
||||
: ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
}
|
||||
ndk::ScopedAStatus prepareToClose() override {
|
||||
auto delegate = mDelegate.lock();
|
||||
return delegate != nullptr ? delegate->prepareToClose()
|
||||
: ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
}
|
||||
ndk::ScopedAStatus updateHwAvSyncId(int32_t in_hwAvSyncId) override {
|
||||
auto delegate = mDelegate.lock();
|
||||
return delegate != nullptr ? delegate->updateHwAvSyncId(in_hwAvSyncId)
|
||||
@@ -359,6 +365,7 @@ template <class Metadata>
|
||||
class StreamCommonImpl : public StreamCommonInterface {
|
||||
public:
|
||||
ndk::ScopedAStatus close() override;
|
||||
ndk::ScopedAStatus prepareToClose() override;
|
||||
ndk::ScopedAStatus updateHwAvSyncId(int32_t in_hwAvSyncId) override;
|
||||
ndk::ScopedAStatus getVendorParameters(const std::vector<std::string>& in_ids,
|
||||
std::vector<VendorParameter>* _aidl_return) override;
|
||||
|
||||
@@ -1070,6 +1070,8 @@ class WithStream {
|
||||
std::shared_ptr<IStreamCommon> common;
|
||||
ndk::ScopedAStatus status = stream->getStreamCommon(&common);
|
||||
if (!status.isOk()) return status;
|
||||
status = common->prepareToClose();
|
||||
if (!status.isOk()) return status;
|
||||
return common->close();
|
||||
}
|
||||
|
||||
@@ -2302,6 +2304,26 @@ class AudioStream : public AudioCoreModule {
|
||||
<< "when closing the stream twice";
|
||||
}
|
||||
|
||||
void PrepareToCloseTwice() {
|
||||
const auto portConfig = moduleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
|
||||
if (!portConfig.has_value()) {
|
||||
GTEST_SKIP() << "No mix port for attached devices";
|
||||
}
|
||||
std::shared_ptr<IStreamCommon> heldStreamCommon;
|
||||
{
|
||||
WithStream<Stream> stream(portConfig.value());
|
||||
ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
|
||||
std::shared_ptr<IStreamCommon> streamCommon;
|
||||
ASSERT_IS_OK(stream.get()->getStreamCommon(&streamCommon));
|
||||
heldStreamCommon = streamCommon;
|
||||
EXPECT_IS_OK(streamCommon->prepareToClose());
|
||||
EXPECT_IS_OK(streamCommon->prepareToClose())
|
||||
<< "when calling prepareToClose second time";
|
||||
}
|
||||
EXPECT_STATUS(EX_ILLEGAL_STATE, heldStreamCommon->prepareToClose())
|
||||
<< "when calling prepareToClose on a closed stream";
|
||||
}
|
||||
|
||||
void OpenAllConfigs() {
|
||||
const auto allPortConfigs =
|
||||
moduleConfig->getPortConfigsForMixPorts(IOTraits<Stream>::is_input);
|
||||
@@ -2597,6 +2619,7 @@ using AudioStreamOut = AudioStream<IStreamOut>;
|
||||
}
|
||||
|
||||
TEST_IN_AND_OUT_STREAM(CloseTwice);
|
||||
TEST_IN_AND_OUT_STREAM(PrepareToCloseTwice);
|
||||
TEST_IN_AND_OUT_STREAM(GetStreamCommon);
|
||||
TEST_IN_AND_OUT_STREAM(OpenAllConfigs);
|
||||
TEST_IN_AND_OUT_STREAM(OpenInvalidBufferSize);
|
||||
|
||||
Reference in New Issue
Block a user