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

Commit fbed7e29 authored by Mikhail Naganov's avatar Mikhail Naganov Committed by Gerrit Code Review
Browse files

Merge "libaudiohal@aidl: Provide HIDL-like 'createMmapBuffer'" into main

parents 88e5f815 9555ad75
Loading
Loading
Loading
Loading
+68 −22
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@ using ::aidl::android::hardware::audio::core::IStreamIn;
using ::aidl::android::hardware::audio::core::IStreamOut;
using ::aidl::android::hardware::audio::core::MmapBufferDescriptor;
using ::aidl::android::hardware::audio::core::StreamDescriptor;
using ::aidl::android::hardware::audio::core::VendorParameter;
using ::aidl::android::media::audio::common::MicrophoneDynamicInfo;
using ::aidl::android::media::audio::IHalAdapterVendorExtension;

@@ -73,7 +74,15 @@ using ::aidl::android::media::audio::IHalAdapterVendorExtension;
namespace android {

using HalCommand = StreamDescriptor::Command;

namespace {

static constexpr int32_t kAidlVersion1 = 1;
static constexpr int32_t kAidlVersion2 = 2;
static constexpr int32_t kAidlVersion3 = 3;

static constexpr const char* kCreateMmapBuffer = "aosp.createMmapBuffer";

template<HalCommand::Tag cmd> HalCommand makeHalCommand() {
    return HalCommand::make<cmd>(::aidl::android::media::audio::common::Void{});
}
@@ -135,7 +144,8 @@ StreamHalAidl::StreamHalAidl(std::string_view className, bool isInput, const aud
        mStreamPowerLog.init(config.sample_rate, config.channel_mask, config.format);
    }

    if (mStream != nullptr) {
    if (mStream == nullptr) return;

    mContext.getCommandMQ()->setErrorHandler(
            fmqErrorHandler<StreamContextAidl::CommandMQ::Error>("CommandMQ"));
    mContext.getReplyMQ()->setErrorHandler(
@@ -144,6 +154,17 @@ StreamHalAidl::StreamHalAidl(std::string_view className, bool isInput, const aud
        mContext.getDataMQ()->setErrorHandler(
                fmqErrorHandler<StreamContextAidl::DataMQ::Error>("DataMQ"));
    }

    if (auto status = mStream->getInterfaceVersion(&mAidlInterfaceVersion); status.isOk()) {
        if (mAidlInterfaceVersion > kAidlVersion3) {
            mSupportsCreateMmapBuffer = true;
        } else {
            VendorParameter createMmapBuffer{.id = kCreateMmapBuffer};
            mSupportsCreateMmapBuffer =
                    mStream->setVendorParameters({createMmapBuffer}, false).isOk();
        }
    } else {
        AUGMENT_LOG(E, "failed to retrieve stream interface version: %s", status.getMessage());
    }
}

@@ -400,12 +421,17 @@ status_t StreamHalAidl::getHardwarePosition(int64_t *frames, int64_t *timestamp)
    AUGMENT_LOG(V);
    if (!mStream) return NO_INIT;
    StreamDescriptor::Reply reply;
    RETURN_STATUS_IF_ERROR(updateCountersIfNeeded(&reply));
    StatePositions statePositions{};
    RETURN_STATUS_IF_ERROR(updateCountersIfNeeded(&reply, &statePositions));
    if (reply.hardware.frames == StreamDescriptor::Position::UNKNOWN ||
        reply.hardware.timeNs == StreamDescriptor::Position::UNKNOWN) {
        AUGMENT_LOG(W, "No position was reported by the HAL");
        return INVALID_OPERATION;
    }
    *frames = reply.hardware.frames;
    int64_t mostRecentResetPoint = std::max(statePositions.hardware.framesAtStandby,
                                            statePositions.hardware.framesAtFlushOrDrain);
    int64_t aidlFrames = reply.hardware.frames;
    *frames = aidlFrames <= mostRecentResetPoint ? 0 : aidlFrames - mostRecentResetPoint;
    *timestamp = reply.hardware.timeNs;
    return OK;
}
@@ -627,7 +653,7 @@ void StreamHalAidl::onAsyncDrainReady() {
                                || mStatePositions.drainState == StatePositions::DrainState::ALL))) {
            AUGMENT_LOG(D, "setting position %lld as clip end",
                    (long long)mLastReply.observable.frames);
            mStatePositions.framesAtFlushOrDrain = mLastReply.observable.frames;
            mStatePositions.observable.framesAtFlushOrDrain = mLastReply.observable.frames;
        }
        mStatePositions.drainState = mStatePositions.drainState == StatePositions::DrainState::EN ?
                StatePositions::DrainState::EN_RECEIVED : StatePositions::DrainState::NONE;
@@ -650,12 +676,25 @@ status_t StreamHalAidl::createMmapBuffer(int32_t minSizeFrames __unused,
    if (!mContext.isMmapped()) {
        return BAD_VALUE;
    }
    if (mSupportsCreateMmapBuffer && (mAidlInterfaceVersion <= kAidlVersion3)) {
        std::vector<VendorParameter> parameters;
        RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
                        mStream->getVendorParameters({kCreateMmapBuffer}, &parameters)));
        if (parameters.size() == 1) {
            std::optional<MmapBufferDescriptor> result;
            RETURN_STATUS_IF_ERROR(parameters[0].ext.getParcelable(&result));
            mContext.updateMmapBufferDescriptor(std::move(*result));
        } else {
            AUGMENT_LOG(E, "invalid output from 'createMmapBuffer' via 'getVendorParameters': %s",
                        internal::ToString(parameters).c_str());
            return INVALID_OPERATION;
        }
    }
    const MmapBufferDescriptor& bufferDescriptor = mContext.getMmapBufferDescriptor();
    info->shared_memory_fd = bufferDescriptor.sharedMemory.fd.get();
    info->buffer_size_frames = mContext.getBufferSizeFrames();
    info->burst_size_frames = bufferDescriptor.burstSizeFrames;
    info->flags = static_cast<audio_mmap_buffer_flag>(bufferDescriptor.flags);

    return OK;
}

@@ -727,15 +766,18 @@ status_t StreamHalAidl::sendCommand(
                if (reply->observable.frames != StreamDescriptor::Position::UNKNOWN) {
                    if (command.getTag() == StreamDescriptor::Command::standby &&
                            reply->state == StreamDescriptor::State::STANDBY) {
                        mStatePositions.framesAtStandby = reply->observable.frames;
                        mStatePositions.observable.framesAtStandby = reply->observable.frames;
                        mStatePositions.hardware.framesAtStandby = reply->hardware.frames;
                    } else if (command.getTag() == StreamDescriptor::Command::flush &&
                            reply->state == StreamDescriptor::State::IDLE) {
                        mStatePositions.framesAtFlushOrDrain = reply->observable.frames;
                        mStatePositions.observable.framesAtFlushOrDrain = reply->observable.frames;
                        mStatePositions.hardware.framesAtFlushOrDrain = reply->observable.frames;
                    } else if (!mContext.isAsynchronous() &&
                            command.getTag() == StreamDescriptor::Command::drain &&
                            (reply->state == StreamDescriptor::State::IDLE ||
                                    reply->state == StreamDescriptor::State::DRAINING)) {
                        mStatePositions.framesAtFlushOrDrain = reply->observable.frames;
                        mStatePositions.observable.framesAtFlushOrDrain = reply->observable.frames;
                        mStatePositions.hardware.framesAtFlushOrDrain = reply->observable.frames;
                    } // for asynchronous drain, the frame count is saved in 'onAsyncDrainReady'
                }
                if (mContext.isAsynchronous() &&
@@ -767,15 +809,19 @@ status_t StreamHalAidl::updateCountersIfNeeded(
        ::aidl::android::hardware::audio::core::StreamDescriptor::Reply* reply,
        StatePositions* statePositions) {
    bool doUpdate = false;
    HalCommand cmd;
    {
        std::lock_guard l(mLock);
        doUpdate = uptimeNanos() > mLastReplyExpirationNs;
        cmd = mContext.isMmapped() && mSupportsCreateMmapBuffer
                && mLastReply.state == StreamDescriptor::State::ACTIVE
                ? makeHalCommand<HalCommand::Tag::burst>(0)
                : makeHalCommand<HalCommand::Tag::getStatus>();
    }
    if (doUpdate) {
        // Since updates are paced, it is OK to perform them from any thread, they should
        // not interfere with I/O operations of the worker.
        return sendCommand(makeHalCommand<HalCommand::Tag::getStatus>(),
                reply, true /*safeFromNonWorkerThread */, statePositions);
        return sendCommand(cmd, reply, true /*safeFromNonWorkerThread */, statePositions);
    } else if (reply != nullptr) {  // provide cached reply
        std::lock_guard l(mLock);
        *reply = mLastReply;
@@ -882,10 +928,10 @@ status_t StreamOutHalAidl::getRenderPosition(uint64_t *dspFrames) {
    // See the table at the start of 'StreamHalInterface' on when it needs to reset.
    int64_t mostRecentResetPoint;
    if (!mContext.isAsynchronous() && audio_has_proportional_frames(mConfig.format)) {
        mostRecentResetPoint = statePositions.framesAtStandby;
        mostRecentResetPoint = statePositions.observable.framesAtStandby;
    } else {
        mostRecentResetPoint =
                std::max(statePositions.framesAtStandby, statePositions.framesAtFlushOrDrain);
        mostRecentResetPoint = std::max(statePositions.observable.framesAtStandby,
                statePositions.observable.framesAtFlushOrDrain);
    }
    *dspFrames = aidlFrames <= mostRecentResetPoint ? 0 : aidlFrames - mostRecentResetPoint;
    return OK;
@@ -961,8 +1007,8 @@ status_t StreamOutHalAidl::getPresentationPosition(uint64_t *frames, struct time
    if (!mContext.isAsynchronous() && audio_has_proportional_frames(mConfig.format)) {
        *frames = aidlFrames;
    } else {
        const int64_t mostRecentResetPoint =
                std::max(statePositions.framesAtStandby, statePositions.framesAtFlushOrDrain);
        const int64_t mostRecentResetPoint = std::max(statePositions.observable.framesAtStandby,
                statePositions.observable.framesAtFlushOrDrain);
        *frames = aidlFrames <= mostRecentResetPoint ? 0 : aidlFrames - mostRecentResetPoint;
    }
    timestamp->tv_sec = aidlTimestamp / NANOS_PER_SECOND;
+16 −9
Original line number Diff line number Diff line
@@ -37,9 +37,6 @@
#include "ConversionHelperAidl.h"
#include "StreamPowerLog.h"

using ::aidl::android::hardware::audio::common::AudioOffloadMetadata;
using ::aidl::android::hardware::audio::core::MmapBufferDescriptor;

namespace android {

class StreamContextAidl {
@@ -87,10 +84,14 @@ class StreamContextAidl {
    ReplyMQ* getReplyMQ() const { return mReplyMQ.get(); }
    bool isAsynchronous() const { return mIsAsynchronous; }
    bool isMmapped() const { return mIsMmapped; }
    const MmapBufferDescriptor& getMmapBufferDescriptor() const { return mMmapBufferDescriptor; }
    const ::aidl::android::hardware::audio::core::MmapBufferDescriptor&
            getMmapBufferDescriptor() const { return mMmapBufferDescriptor; }
    size_t getMmapBurstSize() const { return mMmapBufferDescriptor.burstSizeFrames; }
    int getIoHandle() const { return mIoHandle; }
    bool hasClipTransitionSupport() const { return mHasClipTransitionSupport; }
    void updateMmapBufferDescriptor(
            ::aidl::android::hardware::audio::core::MmapBufferDescriptor&& desc) {
        mMmapBufferDescriptor = std::move(desc); }

  private:
    static std::unique_ptr<DataMQ> maybeCreateDataMQ(
@@ -106,7 +107,7 @@ class StreamContextAidl {
        using Tag = ::aidl::android::hardware::audio::core::StreamDescriptor::AudioBuffer::Tag;
        return descriptor.audio.getTag() == Tag::mmap;
    }
    static MmapBufferDescriptor maybeGetMmapBuffer(
    static ::aidl::android::hardware::audio::core::MmapBufferDescriptor maybeGetMmapBuffer(
            ::aidl::android::hardware::audio::core::StreamDescriptor& descriptor) {
        using Tag = ::aidl::android::hardware::audio::core::StreamDescriptor::AudioBuffer::Tag;
        if (descriptor.audio.getTag() == Tag::mmap) {
@@ -122,7 +123,7 @@ class StreamContextAidl {
    std::unique_ptr<DataMQ> mDataMQ;
    bool mIsAsynchronous;
    bool mIsMmapped;
    MmapBufferDescriptor mMmapBufferDescriptor;
    ::aidl::android::hardware::audio::core::MmapBufferDescriptor mMmapBufferDescriptor;
    int mIoHandle;
    bool mHasClipTransitionSupport;
};
@@ -183,9 +184,13 @@ class StreamHalAidl : public virtual StreamHalInterface, public ConversionHelper
    // For tests.
    friend class sp<StreamHalAidl>;

    struct StatePositions {
    struct FrameCounters {
        int64_t framesAtFlushOrDrain;
        int64_t framesAtStandby;
    };
    struct StatePositions {
        FrameCounters observable;
        FrameCounters hardware;
        enum DrainState : int32_t { NONE, ALL, EN /*early notify*/, EN_RECEIVED };
        DrainState drainState;
    };
@@ -288,7 +293,7 @@ class StreamHalAidl : public virtual StreamHalInterface, public ConversionHelper

    const bool mIsInput;
    const audio_config_base_t mConfig;
    const StreamContextAidl mContext;
    StreamContextAidl mContext;
    // This lock is used to make sending of a command and receiving a reply an atomic
    // operation. Otherwise, when two threads are trying to send a command, they may both advance to
    // reading of the reply once the HAL has consumed the command from the MQ, and that creates a
@@ -340,6 +345,8 @@ class StreamHalAidl : public virtual StreamHalInterface, public ConversionHelper
    // mStreamPowerLog is used for audio signal power logging.
    StreamPowerLog mStreamPowerLog;
    std::atomic<pid_t> mWorkerTid = -1;
    int32_t mAidlInterfaceVersion = -1;
    bool mSupportsCreateMmapBuffer = false;
};

class CallbackBroker;
@@ -446,7 +453,7 @@ class StreamOutHalAidl : public virtual StreamOutHalInterface,
    const wp<CallbackBroker> mCallbackBroker;
    mediautils::atomic_wp<StreamOutHalInterfaceCallback> mClientCallback;

    AudioOffloadMetadata mOffloadMetadata;
    ::aidl::android::hardware::audio::common::AudioOffloadMetadata mOffloadMetadata;

    // Can not be constructed directly by clients.
    StreamOutHalAidl(
+6 −0
Original line number Diff line number Diff line
@@ -61,6 +61,10 @@ using ::aidl::android::media::audio::common::PcmType;

class VendorParameterMock {
  public:
    void clearParameters() {
        mAsyncParameters.clear();
        mSyncParameters.clear();
    }
    const std::vector<std::string>& getRetrievedParameterIds() const { return mGetParameterIds; }
    const std::vector<VendorParameter>& getAsyncParameters() const { return mAsyncParameters; }
    const std::vector<VendorParameter>& getSyncParameters() const { return mSyncParameters; }
@@ -995,6 +999,8 @@ class StreamHalAidlVendorParametersTest : public testing::Test {
                                  false /*hasClipTransitionSupport*/);
        mStream = sp<StreamHalAidl>::make("test", false /*isInput*/, config, 0 /*nominalLatency*/,
                                          std::move(context), mStreamCommon, mVendorExt);
        // The stream may check for some properties after creating.
        mStreamCommon->clearParameters();
    }
    void TearDown() override {
        mStream.clear();
+1 −0
Original line number Diff line number Diff line
@@ -93,6 +93,7 @@ const char * const AudioParameter::keyOffloadCodecPaddingSamples =
        AUDIO_OFFLOAD_CODEC_PADDING_SAMPLES;
const char * const AudioParameter::keyClipTransitionSupport =
        AUDIO_PARAMETER_CLIP_TRANSITION_SUPPORT;
const char * const keyCreateMmapBuffer = AUDIO_PARAMETER_CREATE_MMAP_BUFFER;

AudioParameter::AudioParameter(const String8& keyValuePairs)
{
+1 −0
Original line number Diff line number Diff line
@@ -152,6 +152,7 @@ public:
    static const char * const keyOffloadCodecPaddingSamples;

    static const char * const keyClipTransitionSupport;
    static const char * const keyCreateMmapBuffer;

    String8 toString() const { return toStringImpl(true); }
    String8 keysToString() const { return toStringImpl(false); }