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

Commit d5554cfa authored by Mikhail Naganov's avatar Mikhail Naganov
Browse files

audio: Refactor streams implementation

Simplify the experience of implementing stream variants.
Stream class now exposes two interfaces: DriverInterface
and StreamCommonInterface, which represent the two
aspects of its usage: via the FMQ on the worker thread,
and via IStreamCommon Binder interface.

Input/output streams now inherit the concrete stream
variant, and implement interface methods specific for
IStreamIn and IStreamOut.

Added DriverInterface::shutdown method which is called
on the worker thread prior to the exit.

Bug: 282568751
Test: atest VtsHalAudioCoreTargetTest
Change-Id: I5bf8da2f22b27f0e284a41fc30b920d87ac2936c
parent 75b59dfb
Loading
Loading
Loading
Loading
+30 −58
Original line number Diff line number Diff line
@@ -152,6 +152,7 @@ StreamInWorkerLogic::Status StreamInWorkerLogic::cycle() {
        case Tag::halReservedExit:
            if (const int32_t cookie = command.get<Tag::halReservedExit>();
                cookie == mInternalCommandCookie) {
                mDriver->shutdown();
                setClosed();
                // This is an internal command, no need to reply.
                return Status::EXIT;
@@ -364,6 +365,7 @@ StreamOutWorkerLogic::Status StreamOutWorkerLogic::cycle() {
        case Tag::halReservedExit:
            if (const int32_t cookie = command.get<Tag::halReservedExit>();
                cookie == mInternalCommandCookie) {
                mDriver->shutdown();
                setClosed();
                // This is an internal command, no need to reply.
                return Status::EXIT;
@@ -567,8 +569,7 @@ bool StreamOutWorkerLogic::write(size_t clientSize, StreamDescriptor::Reply* rep
    return !fatal;
}

template <class Metadata>
StreamCommonImpl<Metadata>::~StreamCommonImpl() {
StreamCommonImpl::~StreamCommonImpl() {
    if (!isClosed()) {
        LOG(ERROR) << __func__ << ": stream was not closed prior to destruction, resource leak";
        stopWorker();
@@ -576,19 +577,16 @@ StreamCommonImpl<Metadata>::~StreamCommonImpl() {
    }
}

template <class Metadata>
void StreamCommonImpl<Metadata>::createStreamCommon(
ndk::ScopedAStatus StreamCommonImpl::initInstance(
        const std::shared_ptr<StreamCommonInterface>& delegate) {
    if (mCommon != nullptr) {
        LOG(FATAL) << __func__ << ": attempting to create the common interface twice";
    }
    mCommon = ndk::SharedRefBase::make<StreamCommon>(delegate);
    mCommon = ndk::SharedRefBase::make<StreamCommonDelegator>(delegate);
    mCommonBinder = mCommon->asBinder();
    AIBinder_setMinSchedulerPolicy(mCommonBinder.get(), SCHED_NORMAL, ANDROID_PRIORITY_AUDIO);
    return mWorker->start() ? ndk::ScopedAStatus::ok()
                            : ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
}

template <class Metadata>
ndk::ScopedAStatus StreamCommonImpl<Metadata>::getStreamCommon(
ndk::ScopedAStatus StreamCommonImpl::getStreamCommonCommon(
        std::shared_ptr<IStreamCommon>* _aidl_return) {
    if (mCommon == nullptr) {
        LOG(FATAL) << __func__ << ": the common interface was not created";
@@ -598,30 +596,26 @@ ndk::ScopedAStatus StreamCommonImpl<Metadata>::getStreamCommon(
    return ndk::ScopedAStatus::ok();
}

template <class Metadata>
ndk::ScopedAStatus StreamCommonImpl<Metadata>::updateHwAvSyncId(int32_t in_hwAvSyncId) {
ndk::ScopedAStatus StreamCommonImpl::updateHwAvSyncId(int32_t in_hwAvSyncId) {
    LOG(DEBUG) << __func__ << ": id " << in_hwAvSyncId;
    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}

template <class Metadata>
ndk::ScopedAStatus StreamCommonImpl<Metadata>::getVendorParameters(
ndk::ScopedAStatus StreamCommonImpl::getVendorParameters(
        const std::vector<std::string>& in_ids, std::vector<VendorParameter>* _aidl_return) {
    LOG(DEBUG) << __func__ << ": id count: " << in_ids.size();
    (void)_aidl_return;
    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}

template <class Metadata>
ndk::ScopedAStatus StreamCommonImpl<Metadata>::setVendorParameters(
ndk::ScopedAStatus StreamCommonImpl::setVendorParameters(
        const std::vector<VendorParameter>& in_parameters, bool in_async) {
    LOG(DEBUG) << __func__ << ": parameters count " << in_parameters.size()
               << ", async: " << in_async;
    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}

template <class Metadata>
ndk::ScopedAStatus StreamCommonImpl<Metadata>::addEffect(
ndk::ScopedAStatus StreamCommonImpl::addEffect(
        const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect) {
    if (in_effect == nullptr) {
        LOG(DEBUG) << __func__ << ": null effect";
@@ -631,8 +625,7 @@ ndk::ScopedAStatus StreamCommonImpl<Metadata>::addEffect(
    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}

template <class Metadata>
ndk::ScopedAStatus StreamCommonImpl<Metadata>::removeEffect(
ndk::ScopedAStatus StreamCommonImpl::removeEffect(
        const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect) {
    if (in_effect == nullptr) {
        LOG(DEBUG) << __func__ << ": null effect";
@@ -642,8 +635,7 @@ ndk::ScopedAStatus StreamCommonImpl<Metadata>::removeEffect(
    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}

template <class Metadata>
ndk::ScopedAStatus StreamCommonImpl<Metadata>::close() {
ndk::ScopedAStatus StreamCommonImpl::close() {
    LOG(DEBUG) << __func__;
    if (!isClosed()) {
        stopWorker();
@@ -659,8 +651,7 @@ ndk::ScopedAStatus StreamCommonImpl<Metadata>::close() {
    }
}

template <class Metadata>
ndk::ScopedAStatus StreamCommonImpl<Metadata>::prepareToClose() {
ndk::ScopedAStatus StreamCommonImpl::prepareToClose() {
    LOG(DEBUG) << __func__;
    if (!isClosed()) {
        return ndk::ScopedAStatus::ok();
@@ -669,8 +660,7 @@ ndk::ScopedAStatus StreamCommonImpl<Metadata>::prepareToClose() {
    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
}

template <class Metadata>
void StreamCommonImpl<Metadata>::stopWorker() {
void StreamCommonImpl::stopWorker() {
    if (auto commandMQ = mContext.getCommandMQ(); commandMQ != nullptr) {
        LOG(DEBUG) << __func__ << ": asking the worker to exit...";
        auto cmd = StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::halReservedExit>(
@@ -686,10 +676,12 @@ void StreamCommonImpl<Metadata>::stopWorker() {
    }
}

template <class Metadata>
ndk::ScopedAStatus StreamCommonImpl<Metadata>::updateMetadata(const Metadata& metadata) {
ndk::ScopedAStatus StreamCommonImpl::updateMetadataCommon(const Metadata& metadata) {
    LOG(DEBUG) << __func__;
    if (!isClosed()) {
        if (metadata.index() != mMetadata.index()) {
            LOG(FATAL) << __func__ << ": changing metadata variant is not allowed";
        }
        mMetadata = metadata;
        return ndk::ScopedAStatus::ok();
    }
@@ -697,12 +689,10 @@ ndk::ScopedAStatus StreamCommonImpl<Metadata>::updateMetadata(const Metadata& me
    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
}

// static
ndk::ScopedAStatus StreamIn::initInstance(const std::shared_ptr<StreamIn>& stream) {
    if (auto status = stream->init(); !status.isOk()) {
        return status;
    }
    stream->createStreamCommon(stream);
ndk::ScopedAStatus StreamCommonImpl::setConnectedDevices(
        const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) {
    mWorker->setIsConnected(!devices.empty());
    mConnectedDevices = devices;
    return ndk::ScopedAStatus::ok();
}

@@ -716,12 +706,8 @@ static std::map<AudioDevice, std::string> transformMicrophones(
}
}  // namespace

StreamIn::StreamIn(const SinkMetadata& sinkMetadata, StreamContext&& context,
                   const DriverInterface::CreateInstance& createDriver,
                   const StreamWorkerInterface::CreateInstance& createWorker,
                   const std::vector<MicrophoneInfo>& microphones)
    : StreamCommonImpl<SinkMetadata>(sinkMetadata, std::move(context), createDriver, createWorker),
      mMicrophones(transformMicrophones(microphones)) {
StreamIn::StreamIn(const std::vector<MicrophoneInfo>& microphones)
    : mMicrophones(transformMicrophones(microphones)) {
    LOG(DEBUG) << __func__;
}

@@ -729,9 +715,9 @@ ndk::ScopedAStatus StreamIn::getActiveMicrophones(
        std::vector<MicrophoneDynamicInfo>* _aidl_return) {
    std::vector<MicrophoneDynamicInfo> result;
    std::vector<MicrophoneDynamicInfo::ChannelMapping> channelMapping{
            getChannelCount(mContext.getChannelLayout()),
            getChannelCount(getContext().getChannelLayout()),
            MicrophoneDynamicInfo::ChannelMapping::DIRECT};
    for (auto it = mConnectedDevices.begin(); it != mConnectedDevices.end(); ++it) {
    for (auto it = getConnectedDevices().begin(); it != getConnectedDevices().end(); ++it) {
        if (auto micIt = mMicrophones.find(*it); micIt != mMicrophones.end()) {
            MicrophoneDynamicInfo dynMic;
            dynMic.id = micIt->second;
@@ -777,22 +763,8 @@ ndk::ScopedAStatus StreamIn::setHwGain(const std::vector<float>& in_channelGains
    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}

// static
ndk::ScopedAStatus StreamOut::initInstance(const std::shared_ptr<StreamOut>& stream) {
    if (auto status = stream->init(); !status.isOk()) {
        return status;
    }
    stream->createStreamCommon(stream);
    return ndk::ScopedAStatus::ok();
}

StreamOut::StreamOut(const SourceMetadata& sourceMetadata, StreamContext&& context,
                     const DriverInterface::CreateInstance& createDriver,
                     const StreamWorkerInterface::CreateInstance& createWorker,
                     const std::optional<AudioOffloadInfo>& offloadInfo)
    : StreamCommonImpl<SourceMetadata>(sourceMetadata, std::move(context), createDriver,
                                       createWorker),
      mOffloadInfo(offloadInfo) {
StreamOut::StreamOut(const std::optional<AudioOffloadInfo>& offloadInfo)
    : mOffloadInfo(offloadInfo) {
    LOG(DEBUG) << __func__;
}

+15 −36
Original line number Diff line number Diff line
@@ -31,33 +31,34 @@ using aidl::android::media::audio::common::MicrophoneInfo;

namespace aidl::android::hardware::audio::core {

DriverStub::DriverStub(const StreamContext& context, bool isInput)
    : mFrameSizeBytes(context.getFrameSize()),
StreamStub::StreamStub(const Metadata& metadata, StreamContext&& context)
    : StreamCommonImpl(metadata, std::move(context)),
      mFrameSizeBytes(context.getFrameSize()),
      mSampleRate(context.getSampleRate()),
      mIsAsynchronous(!!context.getAsyncCallback()),
      mIsInput(isInput) {}
      mIsInput(isInput(metadata)) {}

::android::status_t DriverStub::init() {
::android::status_t StreamStub::init() {
    usleep(500);
    return ::android::OK;
}

::android::status_t DriverStub::drain(StreamDescriptor::DrainMode) {
::android::status_t StreamStub::drain(StreamDescriptor::DrainMode) {
    usleep(500);
    return ::android::OK;
}

::android::status_t DriverStub::flush() {
::android::status_t StreamStub::flush() {
    usleep(500);
    return ::android::OK;
}

::android::status_t DriverStub::pause() {
::android::status_t StreamStub::pause() {
    usleep(500);
    return ::android::OK;
}

::android::status_t DriverStub::transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
::android::status_t StreamStub::transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
                                         int32_t* latencyMs) {
    static constexpr float kMicrosPerSecond = MICROS_PER_SECOND;
    static constexpr float kScaleFactor = .8f;
@@ -79,16 +80,12 @@ DriverStub::DriverStub(const StreamContext& context, bool isInput)
    return ::android::OK;
}

::android::status_t DriverStub::standby() {
::android::status_t StreamStub::standby() {
    usleep(500);
    return ::android::OK;
}

::android::status_t DriverStub::setConnectedDevices(
        const std::vector<AudioDevice>& connectedDevices __unused) {
    usleep(500);
    return ::android::OK;
}
void StreamStub::shutdown() {}

// static
ndk::ScopedAStatus StreamInStub::createInstance(const SinkMetadata& sinkMetadata,
@@ -97,7 +94,7 @@ ndk::ScopedAStatus StreamInStub::createInstance(const SinkMetadata& sinkMetadata
                                                std::shared_ptr<StreamIn>* result) {
    std::shared_ptr<StreamIn> stream =
            ndk::SharedRefBase::make<StreamInStub>(sinkMetadata, std::move(context), microphones);
    if (auto status = initInstance(stream); !status.isOk()) {
    if (auto status = stream->initInstance(stream); !status.isOk()) {
        return status;
    }
    *result = std::move(stream);
@@ -106,16 +103,7 @@ ndk::ScopedAStatus StreamInStub::createInstance(const SinkMetadata& sinkMetadata

StreamInStub::StreamInStub(const SinkMetadata& sinkMetadata, StreamContext&& context,
                           const std::vector<MicrophoneInfo>& microphones)
    : StreamIn(
              sinkMetadata, std::move(context),
              [](const StreamContext& ctx) -> DriverInterface* {
                  return new DriverStub(ctx, true /*isInput*/);
              },
              [](const StreamContext& ctx, DriverInterface* driver) -> StreamWorkerInterface* {
                  // The default worker implementation is used.
                  return new StreamInWorker(ctx, driver);
              },
              microphones) {}
    : StreamStub(sinkMetadata, std::move(context)), StreamIn(microphones) {}

// static
ndk::ScopedAStatus StreamOutStub::createInstance(const SourceMetadata& sourceMetadata,
@@ -124,7 +112,7 @@ ndk::ScopedAStatus StreamOutStub::createInstance(const SourceMetadata& sourceMet
                                                 std::shared_ptr<StreamOut>* result) {
    std::shared_ptr<StreamOut> stream = ndk::SharedRefBase::make<StreamOutStub>(
            sourceMetadata, std::move(context), offloadInfo);
    if (auto status = initInstance(stream); !status.isOk()) {
    if (auto status = stream->initInstance(stream); !status.isOk()) {
        return status;
    }
    *result = std::move(stream);
@@ -133,15 +121,6 @@ ndk::ScopedAStatus StreamOutStub::createInstance(const SourceMetadata& sourceMet

StreamOutStub::StreamOutStub(const SourceMetadata& sourceMetadata, StreamContext&& context,
                             const std::optional<AudioOffloadInfo>& offloadInfo)
    : StreamOut(
              sourceMetadata, std::move(context),
              [](const StreamContext& ctx) -> DriverInterface* {
                  return new DriverStub(ctx, false /*isInput*/);
              },
              [](const StreamContext& ctx, DriverInterface* driver) -> StreamWorkerInterface* {
                  // The default worker implementation is used.
                  return new StreamOutWorker(ctx, driver);
              },
              offloadInfo) {}
    : StreamStub(sourceMetadata, std::move(context)), StreamOut(offloadInfo) {}

}  // namespace aidl::android::hardware::audio::core
+95 −94

File changed.

Preview size limit exceeded, changes collapsed.

+6 −8
Original line number Diff line number Diff line
@@ -20,9 +20,10 @@

namespace aidl::android::hardware::audio::core {

class DriverStub : public DriverInterface {
class StreamStub : public StreamCommonImpl {
  public:
    DriverStub(const StreamContext& context, bool isInput);
    StreamStub(const Metadata& metadata, StreamContext&& context);
    // Methods of 'DriverInterface'.
    ::android::status_t init() override;
    ::android::status_t drain(StreamDescriptor::DrainMode) override;
    ::android::status_t flush() override;
@@ -30,10 +31,7 @@ class DriverStub : public DriverInterface {
    ::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
                                 int32_t* latencyMs) override;
    ::android::status_t standby() override;
    // Note: called on a different thread.
    ::android::status_t setConnectedDevices(
            const std::vector<::aidl::android::media::audio::common::AudioDevice>& connectedDevices)
            override;
    void shutdown() override;

  private:
    const size_t mFrameSizeBytes;
@@ -42,7 +40,7 @@ class DriverStub : public DriverInterface {
    const bool mIsInput;
};

class StreamInStub final : public StreamIn {
class StreamInStub final : public StreamStub, public StreamIn {
  public:
    static ndk::ScopedAStatus createInstance(
            const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
@@ -58,7 +56,7 @@ class StreamInStub final : public StreamIn {
            const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones);
};

class StreamOutStub final : public StreamOut {
class StreamOutStub final : public StreamStub, public StreamOut {
  public:
    static ndk::ScopedAStatus createInstance(
            const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
+11 −12
Original line number Diff line number Diff line
@@ -30,9 +30,10 @@ extern "C" {

namespace aidl::android::hardware::audio::core {

class DriverUsb : public DriverInterface {
class StreamUsb : public StreamCommonImpl {
  public:
    DriverUsb(const StreamContext& context, bool isInput);
    StreamUsb(const Metadata& metadata, StreamContext&& context);
    // Methods of 'DriverInterface'.
    ::android::status_t init() override;
    ::android::status_t drain(StreamDescriptor::DrainMode) override;
    ::android::status_t flush() override;
@@ -40,27 +41,25 @@ class DriverUsb : public DriverInterface {
    ::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
                                 int32_t* latencyMs) override;
    ::android::status_t standby() override;
    // Note: called on a different thread.
    ::android::status_t setConnectedDevices(
            const std::vector<::aidl::android::media::audio::common::AudioDevice>& connectedDevices)
            override;
    void shutdown() override;

    // Overridden methods of 'StreamCommonImpl', called on a Binder thread.
    const ConnectedDevices& getConnectedDevices() const override;
    ndk::ScopedAStatus setConnectedDevices(const ConnectedDevices& devices) override;

  private:
    ::android::status_t exitStandby();

    std::mutex mLock;
    mutable std::mutex mLock;

    const size_t mFrameSizeBytes;
    std::optional<struct pcm_config> mConfig;
    const bool mIsInput;
    // Cached device addresses for connected devices.
    std::vector<::aidl::android::media::audio::common::AudioDeviceAddress> mConnectedDevices
            GUARDED_BY(mLock);
    std::vector<std::shared_ptr<alsa_device_proxy>> mAlsaDeviceProxies GUARDED_BY(mLock);
    bool mIsStandby = true;
};

class StreamInUsb final : public StreamIn {
class StreamInUsb final : public StreamUsb, public StreamIn {
    ndk::ScopedAStatus getActiveMicrophones(
            std::vector<::aidl::android::media::audio::common::MicrophoneDynamicInfo>* _aidl_return)
            override;
@@ -80,7 +79,7 @@ class StreamInUsb final : public StreamIn {
            const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones);
};

class StreamOutUsb final : public StreamOut {
class StreamOutUsb final : public StreamUsb, public StreamOut {
  public:
    static ndk::ScopedAStatus createInstance(
            const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
Loading