Merge "audio: Add IStreamCommon.prepareToClose method" am: 940ca8996a

Original change: https://android-review.googlesource.com/c/platform/hardware/interfaces/+/2475087

Change-Id: Ie919fad86d8da35b0fa297bcf66e4322d0ae0611
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Treehugger Robot 2023-03-07 21:15:55 +00:00 committed by Automerger Merge Worker
commit 1dbc39ea23
5 changed files with 68 additions and 0 deletions

View file

@ -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);

View file

@ -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.
*

View file

@ -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) {

View file

@ -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;

View file

@ -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);