Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 99d4458c authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge changes Ic8eaee53,Ide961d91,Ie97f3ce9

* changes:
  audio: Allow going to 'IDLE' for synchronous drain
  audio: Improve test coverage
  audio VTS: Refactor support for non-deterministic SM behavior
parents 0a9430ad 194daaac
Loading
Loading
Loading
Loading
+2 −0
Original line number Original line Diff line number Diff line
@@ -30,6 +30,7 @@ digraph stream_out_async_state_machine {
    STANDBY -> PAUSED [label="burst"];                // producer -> active
    STANDBY -> PAUSED [label="burst"];                // producer -> active
    IDLE -> STANDBY [label="standby"];                // consumer -> passive
    IDLE -> STANDBY [label="standby"];                // consumer -> passive
    IDLE -> TRANSFERRING [label="burst"];             // producer -> active
    IDLE -> TRANSFERRING [label="burst"];             // producer -> active
    IDLE -> ACTIVE [label="burst"];                   // full write
    ACTIVE -> PAUSED [label="pause"];                 // consumer -> passive (not consuming)
    ACTIVE -> PAUSED [label="pause"];                 // consumer -> passive (not consuming)
    ACTIVE -> DRAINING [label="drain"];               // producer -> passive
    ACTIVE -> DRAINING [label="drain"];               // producer -> passive
    ACTIVE -> TRANSFERRING [label="burst"];           // early unblocking
    ACTIVE -> TRANSFERRING [label="burst"];           // early unblocking
@@ -45,6 +46,7 @@ digraph stream_out_async_state_machine {
    PAUSED -> IDLE [label="flush"];                   // producer -> passive, buffer is cleared
    PAUSED -> IDLE [label="flush"];                   // producer -> passive, buffer is cleared
    DRAINING -> IDLE [label="←IStreamCallback.onDrainReady"];
    DRAINING -> IDLE [label="←IStreamCallback.onDrainReady"];
    DRAINING -> TRANSFERRING [label="burst"];         // producer -> active
    DRAINING -> TRANSFERRING [label="burst"];         // producer -> active
    DRAINING -> ACTIVE [label="burst"];               // full write
    DRAINING -> DRAIN_PAUSED [label="pause"];         // consumer -> passive (not consuming)
    DRAINING -> DRAIN_PAUSED [label="pause"];         // consumer -> passive (not consuming)
    DRAIN_PAUSED -> DRAINING [label="start"];         // consumer -> active
    DRAIN_PAUSED -> DRAINING [label="start"];         // consumer -> active
    DRAIN_PAUSED -> TRANSFER_PAUSED [label="burst"];  // producer -> active
    DRAIN_PAUSED -> TRANSFER_PAUSED [label="burst"];  // producer -> active
+1 −0
Original line number Original line Diff line number Diff line
@@ -31,6 +31,7 @@ digraph stream_out_state_machine {
    ACTIVE -> ACTIVE [label="burst"];
    ACTIVE -> ACTIVE [label="burst"];
    ACTIVE -> PAUSED [label="pause"];          // consumer -> passive (not consuming)
    ACTIVE -> PAUSED [label="pause"];          // consumer -> passive (not consuming)
    ACTIVE -> DRAINING [label="drain"];        // producer -> passive
    ACTIVE -> DRAINING [label="drain"];        // producer -> passive
    ACTIVE -> IDLE [label="drain"];            // synchronous drain
    PAUSED -> PAUSED [label="burst"];
    PAUSED -> PAUSED [label="burst"];
    PAUSED -> ACTIVE [label="start"];          // consumer -> active
    PAUSED -> ACTIVE [label="start"];          // consumer -> active
    PAUSED -> IDLE [label="flush"];            // producer -> passive, buffer is cleared
    PAUSED -> IDLE [label="flush"];            // producer -> passive, buffer is cleared
+59 −4
Original line number Original line Diff line number Diff line
@@ -46,6 +46,7 @@ using aidl::android::media::audio::common::AudioPort;
using aidl::android::media::audio::common::AudioPortConfig;
using aidl::android::media::audio::common::AudioPortConfig;
using aidl::android::media::audio::common::AudioPortExt;
using aidl::android::media::audio::common::AudioPortExt;
using aidl::android::media::audio::common::AudioProfile;
using aidl::android::media::audio::common::AudioProfile;
using aidl::android::media::audio::common::Boolean;
using aidl::android::media::audio::common::Int;
using aidl::android::media::audio::common::Int;
using aidl::android::media::audio::common::PcmType;
using aidl::android::media::audio::common::PcmType;
using android::hardware::audio::common::getFrameSizeInBytes;
using android::hardware::audio::common::getFrameSizeInBytes;
@@ -138,12 +139,15 @@ ndk::ScopedAStatus Module::createStreamContext(int32_t in_portConfigId, int64_t
        (flags.getTag() == AudioIoFlags::Tag::output &&
        (flags.getTag() == AudioIoFlags::Tag::output &&
         !isBitPositionFlagSet(flags.get<AudioIoFlags::Tag::output>(),
         !isBitPositionFlagSet(flags.get<AudioIoFlags::Tag::output>(),
                               AudioOutputFlags::MMAP_NOIRQ))) {
                               AudioOutputFlags::MMAP_NOIRQ))) {
        StreamContext::DebugParameters params{mDebug.streamTransientStateDelayMs,
                                              mVendorDebug.forceTransientBurst,
                                              mVendorDebug.forceSynchronousDrain};
        StreamContext temp(
        StreamContext temp(
                std::make_unique<StreamContext::CommandMQ>(1, true /*configureEventFlagWord*/),
                std::make_unique<StreamContext::CommandMQ>(1, true /*configureEventFlagWord*/),
                std::make_unique<StreamContext::ReplyMQ>(1, true /*configureEventFlagWord*/),
                std::make_unique<StreamContext::ReplyMQ>(1, true /*configureEventFlagWord*/),
                portConfigIt->format.value(), portConfigIt->channelMask.value(),
                portConfigIt->format.value(), portConfigIt->channelMask.value(),
                std::make_unique<StreamContext::DataMQ>(frameSize * in_bufferSizeFrames),
                std::make_unique<StreamContext::DataMQ>(frameSize * in_bufferSizeFrames),
                asyncCallback, mDebug.streamTransientStateDelayMs);
                asyncCallback, params);
        if (temp.isValid()) {
        if (temp.isValid()) {
            *out_context = std::move(temp);
            *out_context = std::move(temp);
        } else {
        } else {
@@ -976,18 +980,69 @@ ndk::ScopedAStatus Module::generateHwAvSyncId(int32_t* _aidl_return) {
    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
}


const std::string Module::VendorDebug::kForceTransientBurstName = "aosp.forceTransientBurst";
const std::string Module::VendorDebug::kForceSynchronousDrainName = "aosp.forceSynchronousDrain";

ndk::ScopedAStatus Module::getVendorParameters(const std::vector<std::string>& in_ids,
ndk::ScopedAStatus Module::getVendorParameters(const std::vector<std::string>& in_ids,
                                               std::vector<VendorParameter>* _aidl_return) {
                                               std::vector<VendorParameter>* _aidl_return) {
    LOG(DEBUG) << __func__ << ": id count: " << in_ids.size();
    LOG(DEBUG) << __func__ << ": id count: " << in_ids.size();
    (void)_aidl_return;
    bool allParametersKnown = true;
    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
    for (const auto& id : in_ids) {
        if (id == VendorDebug::kForceTransientBurstName) {
            VendorParameter forceTransientBurst{.id = id};
            forceTransientBurst.ext.setParcelable(Boolean{mVendorDebug.forceTransientBurst});
            _aidl_return->push_back(std::move(forceTransientBurst));
        } else if (id == VendorDebug::kForceSynchronousDrainName) {
            VendorParameter forceSynchronousDrain{.id = id};
            forceSynchronousDrain.ext.setParcelable(Boolean{mVendorDebug.forceSynchronousDrain});
            _aidl_return->push_back(std::move(forceSynchronousDrain));
        } else {
            allParametersKnown = false;
            LOG(ERROR) << __func__ << ": unrecognized parameter \"" << id << "\"";
        }
    }
    if (allParametersKnown) return ndk::ScopedAStatus::ok();
    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
}


namespace {

template <typename W>
bool extractParameter(const VendorParameter& p, decltype(W::value)* v) {
    std::optional<W> value;
    binder_status_t result = p.ext.getParcelable(&value);
    if (result == STATUS_OK && value.has_value()) {
        *v = value.value().value;
        return true;
    }
    LOG(ERROR) << __func__ << ": failed to read the value of the parameter \"" << p.id
               << "\": " << result;
    return false;
}

}  // namespace

ndk::ScopedAStatus Module::setVendorParameters(const std::vector<VendorParameter>& in_parameters,
ndk::ScopedAStatus Module::setVendorParameters(const std::vector<VendorParameter>& in_parameters,
                                               bool in_async) {
                                               bool in_async) {
    LOG(DEBUG) << __func__ << ": parameter count " << in_parameters.size()
    LOG(DEBUG) << __func__ << ": parameter count " << in_parameters.size()
               << ", async: " << in_async;
               << ", async: " << in_async;
    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
    bool allParametersKnown = true;
    for (const auto& p : in_parameters) {
        if (p.id == VendorDebug::kForceTransientBurstName) {
            if (!extractParameter<Boolean>(p, &mVendorDebug.forceTransientBurst)) {
                return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
            }
        } else if (p.id == VendorDebug::kForceSynchronousDrainName) {
            if (!extractParameter<Boolean>(p, &mVendorDebug.forceSynchronousDrain)) {
                return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
            }
        } else {
            allParametersKnown = false;
            LOG(ERROR) << __func__ << ": unrecognized parameter \"" << p.id << "\"";
        }
    }
    if (allParametersKnown) return ndk::ScopedAStatus::ok();
    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
}


ndk::ScopedAStatus Module::addDeviceEffect(
ndk::ScopedAStatus Module::addDeviceEffect(
+13 −4
Original line number Original line Diff line number Diff line
@@ -402,7 +402,11 @@ StreamOutWorkerLogic::Status StreamOutWorkerLogic::cycle() {
                    usleep(1000);  // Simulate a blocking call into the driver.
                    usleep(1000);  // Simulate a blocking call into the driver.
                    populateReply(&reply, mIsConnected);
                    populateReply(&reply, mIsConnected);
                    // Can switch the state to ERROR if a driver error occurs.
                    // Can switch the state to ERROR if a driver error occurs.
                    if (mState == StreamDescriptor::State::ACTIVE && mForceSynchronousDrain) {
                        mState = StreamDescriptor::State::IDLE;
                    } else {
                        switchToTransientState(StreamDescriptor::State::DRAINING);
                        switchToTransientState(StreamDescriptor::State::DRAINING);
                    }
                } else if (mState == StreamDescriptor::State::TRANSFER_PAUSED) {
                } else if (mState == StreamDescriptor::State::TRANSFER_PAUSED) {
                    mState = StreamDescriptor::State::DRAIN_PAUSED;
                    mState = StreamDescriptor::State::DRAIN_PAUSED;
                    populateReply(&reply, mIsConnected);
                    populateReply(&reply, mIsConnected);
@@ -467,14 +471,19 @@ StreamOutWorkerLogic::Status StreamOutWorkerLogic::cycle() {


bool StreamOutWorkerLogic::write(size_t clientSize, StreamDescriptor::Reply* reply) {
bool StreamOutWorkerLogic::write(size_t clientSize, StreamDescriptor::Reply* reply) {
    const size_t readByteCount = mDataMQ->availableToRead();
    const size_t readByteCount = mDataMQ->availableToRead();
    // Amount of data that the HAL module is going to actually use.
    const size_t byteCount = std::min({clientSize, readByteCount, mDataBufferSize});
    bool fatal = false;
    bool fatal = false;
    if (bool success = readByteCount > 0 ? mDataMQ->read(&mDataBuffer[0], readByteCount) : true) {
    if (bool success = readByteCount > 0 ? mDataMQ->read(&mDataBuffer[0], readByteCount) : true) {
        const bool isConnected = mIsConnected;
        const bool isConnected = mIsConnected;
        LOG(DEBUG) << __func__ << ": reading of " << readByteCount << " bytes from data MQ"
        LOG(DEBUG) << __func__ << ": reading of " << readByteCount << " bytes from data MQ"
                   << " succeeded; connected? " << isConnected;
                   << " succeeded; connected? " << isConnected;
        // Frames are consumed and counted regardless of connection status.
        // Amount of data that the HAL module is going to actually use.
        size_t byteCount = std::min({clientSize, readByteCount, mDataBufferSize});
        if (byteCount >= mFrameSize && mForceTransientBurst) {
            // In order to prevent the state machine from going to ACTIVE state,
            // simulate partial write.
            byteCount -= mFrameSize;
        }
        // Frames are consumed and counted regardless of the connection status.
        reply->fmqByteCount += byteCount;
        reply->fmqByteCount += byteCount;
        mFrameCount += byteCount / mFrameSize;
        mFrameCount += byteCount / mFrameSize;
        populateReply(reply, isConnected);
        populateReply(reply, isConnected);
+8 −0
Original line number Original line Diff line number Diff line
@@ -36,6 +36,13 @@ class Module : public BnModule {
    explicit Module(Type type) : mType(type) {}
    explicit Module(Type type) : mType(type) {}


  private:
  private:
    struct VendorDebug {
        static const std::string kForceTransientBurstName;
        static const std::string kForceSynchronousDrainName;
        bool forceTransientBurst = false;
        bool forceSynchronousDrain = false;
    };

    ndk::ScopedAStatus setModuleDebug(
    ndk::ScopedAStatus setModuleDebug(
            const ::aidl::android::hardware::audio::core::ModuleDebug& in_debug) override;
            const ::aidl::android::hardware::audio::core::ModuleDebug& in_debug) override;
    ndk::ScopedAStatus getTelephony(std::shared_ptr<ITelephony>* _aidl_return) override;
    ndk::ScopedAStatus getTelephony(std::shared_ptr<ITelephony>* _aidl_return) override;
@@ -128,6 +135,7 @@ class Module : public BnModule {
    const Type mType;
    const Type mType;
    std::unique_ptr<internal::Configuration> mConfig;
    std::unique_ptr<internal::Configuration> mConfig;
    ModuleDebug mDebug;
    ModuleDebug mDebug;
    VendorDebug mVendorDebug;
    // For the interfaces requiring to return the same instance, we need to hold them
    // For the interfaces requiring to return the same instance, we need to hold them
    // via a strong pointer. The binder token is retained for a call to 'setMinSchedulerPolicy'.
    // via a strong pointer. The binder token is retained for a call to 'setMinSchedulerPolicy'.
    std::shared_ptr<ITelephony> mTelephony;
    std::shared_ptr<ITelephony> mTelephony;
Loading