From f5ec73e546cd7e4abfc065a697f84a19741221a7 Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Wed, 2 Oct 2024 11:02:52 -0700 Subject: [PATCH] audio: Do not use StreamSwitcher for StreamPrimary Since use of StreamSwitcher causes the worker thread to be changed during connected device change, its use for the primary HAL streams must be avoided. The reason is that switching of the FMQ reader thread accompanied with simultaneous writes from two writers: one on the framework side, another on the HAL side sending the "exit" command, violates threading assumptions of blocking FMQ and causes spurious races that eventually make FMQ non-functional. Bug: 300130515 Bug: 368723297 Bug: 369272078 Bug: 369289912 Bug: 369964381 Test: atest VtsHalAudioCoreTargetTest Change-Id: I14dc6fc08ae9e8aaaf3cd80e96b20dd1df54f633 --- audio/aidl/default/Android.bp | 1 + .../include/core-impl/DriverStubImpl.h | 49 +++++ audio/aidl/default/include/core-impl/Stream.h | 3 + .../default/include/core-impl/StreamPrimary.h | 65 +++--- .../default/include/core-impl/StreamStub.h | 27 +-- audio/aidl/default/primary/PrimaryMixer.h | 10 +- audio/aidl/default/primary/StreamPrimary.cpp | 192 +++++++++--------- audio/aidl/default/stub/DriverStubImpl.cpp | 126 ++++++++++++ audio/aidl/default/stub/StreamStub.cpp | 100 +-------- 9 files changed, 317 insertions(+), 256 deletions(-) create mode 100644 audio/aidl/default/include/core-impl/DriverStubImpl.h create mode 100644 audio/aidl/default/stub/DriverStubImpl.cpp diff --git a/audio/aidl/default/Android.bp b/audio/aidl/default/Android.bp index f51f65e60e..d47b0b1bb6 100644 --- a/audio/aidl/default/Android.bp +++ b/audio/aidl/default/Android.bp @@ -77,6 +77,7 @@ cc_library { "r_submix/ModuleRemoteSubmix.cpp", "r_submix/SubmixRoute.cpp", "r_submix/StreamRemoteSubmix.cpp", + "stub/DriverStubImpl.cpp", "stub/ModuleStub.cpp", "stub/StreamStub.cpp", "usb/ModuleUsb.cpp", diff --git a/audio/aidl/default/include/core-impl/DriverStubImpl.h b/audio/aidl/default/include/core-impl/DriverStubImpl.h new file mode 100644 index 0000000000..40a9feab88 --- /dev/null +++ b/audio/aidl/default/include/core-impl/DriverStubImpl.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "core-impl/Stream.h" + +namespace aidl::android::hardware::audio::core { + +class DriverStubImpl : virtual public DriverInterface { + public: + explicit DriverStubImpl(const StreamContext& context); + + ::android::status_t init() override; + ::android::status_t drain(StreamDescriptor::DrainMode) override; + ::android::status_t flush() override; + ::android::status_t pause() override; + ::android::status_t standby() override; + ::android::status_t start() override; + ::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount, + int32_t* latencyMs) override; + void shutdown() override; + + private: + const size_t mBufferSizeFrames; + const size_t mFrameSizeBytes; + const int mSampleRate; + const bool mIsAsynchronous; + const bool mIsInput; + bool mIsInitialized = false; // Used for validating the state machine logic. + bool mIsStandby = true; // Used for validating the state machine logic. + int64_t mStartTimeNs = 0; + long mFramesSinceStart = 0; +}; + +} // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/include/core-impl/Stream.h b/audio/aidl/default/include/core-impl/Stream.h index 5dca739039..f7b926961e 100644 --- a/audio/aidl/default/include/core-impl/Stream.h +++ b/audio/aidl/default/include/core-impl/Stream.h @@ -133,6 +133,9 @@ class StreamContext { ReplyMQ* getReplyMQ() const { return mReplyMQ.get(); } int getTransientStateDelayMs() const { return mDebugParameters.transientStateDelayMs; } int getSampleRate() const { return mSampleRate; } + bool isInput() const { + return mFlags.getTag() == ::aidl::android::media::audio::common::AudioIoFlags::input; + } bool isValid() const; // 'reset' is called on a Binder thread when closing the stream. Does not use // locking because it only cleans MQ pointers which were also set on the Binder thread. diff --git a/audio/aidl/default/include/core-impl/StreamPrimary.h b/audio/aidl/default/include/core-impl/StreamPrimary.h index 600c3779cd..4f19a468a3 100644 --- a/audio/aidl/default/include/core-impl/StreamPrimary.h +++ b/audio/aidl/default/include/core-impl/StreamPrimary.h @@ -16,25 +16,39 @@ #pragma once +#include #include +#include + +#include "DriverStubImpl.h" #include "StreamAlsa.h" -#include "StreamSwitcher.h" +#include "primary/PrimaryMixer.h" namespace aidl::android::hardware::audio::core { class StreamPrimary : public StreamAlsa { public: - StreamPrimary(StreamContext* context, const Metadata& metadata, - const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices); + StreamPrimary(StreamContext* context, const Metadata& metadata); + // Methods of 'DriverInterface'. + ::android::status_t init() override; + ::android::status_t drain(StreamDescriptor::DrainMode mode) override; + ::android::status_t flush() override; + ::android::status_t pause() override; + ::android::status_t standby() override; ::android::status_t start() override; ::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount, int32_t* latencyMs) override; ::android::status_t refinePosition(StreamDescriptor::Position* position) override; + void shutdown() override; + + // Overridden methods of 'StreamCommonImpl', called on a Binder thread. + ndk::ScopedAStatus setConnectedDevices(const ConnectedDevices& devices) override; protected: std::vector getDeviceProfiles() override; + bool isStubStream(); const bool mIsAsynchronous; int64_t mStartTimeNs = 0; @@ -42,12 +56,29 @@ class StreamPrimary : public StreamAlsa { bool mSkipNextTransfer = false; private: - static std::pair getCardAndDeviceId( + using AlsaDeviceId = std::pair; + + static constexpr StreamPrimary::AlsaDeviceId kDefaultCardAndDeviceId{ + primary::PrimaryMixer::kAlsaCard, primary::PrimaryMixer::kAlsaDevice}; + static constexpr StreamPrimary::AlsaDeviceId kStubDeviceId{ + primary::PrimaryMixer::kInvalidAlsaCard, primary::PrimaryMixer::kInvalidAlsaDevice}; + + static AlsaDeviceId getCardAndDeviceId( const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices); - const std::pair mCardAndDeviceId; + static bool useStubStream(bool isInput, + const ::aidl::android::media::audio::common::AudioDevice& device); + + bool isStubStreamOnWorker() const { return mCurrAlsaDeviceId == kStubDeviceId; } + + DriverStubImpl mStubDriver; + mutable std::mutex mLock; + AlsaDeviceId mAlsaDeviceId GUARDED_BY(mLock) = kStubDeviceId; + + // Used by the worker thread only. + AlsaDeviceId mCurrAlsaDeviceId = kStubDeviceId; }; -class StreamInPrimary final : public StreamIn, public StreamSwitcher, public StreamInHwGainHelper { +class StreamInPrimary final : public StreamIn, public StreamPrimary, public StreamInHwGainHelper { public: friend class ndk::SharedRefBase; StreamInPrimary( @@ -56,14 +87,6 @@ class StreamInPrimary final : public StreamIn, public StreamSwitcher, public Str const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones); private: - static bool useStubStream(const ::aidl::android::media::audio::common::AudioDevice& device); - - DeviceSwitchBehavior switchCurrentStream( - const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) - override; - std::unique_ptr createNewStream( - const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices, - StreamContext* context, const Metadata& metadata) override; void onClose(StreamDescriptor::State) override { defaultOnClose(); } ndk::ScopedAStatus getHwGain(std::vector* _aidl_return) override; @@ -71,7 +94,7 @@ class StreamInPrimary final : public StreamIn, public StreamSwitcher, public Str }; class StreamOutPrimary final : public StreamOut, - public StreamSwitcher, + public StreamPrimary, public StreamOutHwVolumeHelper { public: friend class ndk::SharedRefBase; @@ -81,22 +104,10 @@ class StreamOutPrimary final : public StreamOut, offloadInfo); private: - static bool useStubStream(const ::aidl::android::media::audio::common::AudioDevice& device); - - DeviceSwitchBehavior switchCurrentStream( - const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) - override; - std::unique_ptr createNewStream( - const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices, - StreamContext* context, const Metadata& metadata) override; void onClose(StreamDescriptor::State) override { defaultOnClose(); } ndk::ScopedAStatus getHwVolume(std::vector* _aidl_return) override; ndk::ScopedAStatus setHwVolume(const std::vector& in_channelVolumes) override; - - ndk::ScopedAStatus setConnectedDevices( - const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) - override; }; } // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/include/core-impl/StreamStub.h b/audio/aidl/default/include/core-impl/StreamStub.h index 22b20202c5..cee44db848 100644 --- a/audio/aidl/default/include/core-impl/StreamStub.h +++ b/audio/aidl/default/include/core-impl/StreamStub.h @@ -16,38 +16,15 @@ #pragma once +#include "core-impl/DriverStubImpl.h" #include "core-impl/Stream.h" namespace aidl::android::hardware::audio::core { -class StreamStub : public StreamCommonImpl { +class StreamStub : public StreamCommonImpl, public DriverStubImpl { public: StreamStub(StreamContext* context, const Metadata& metadata); ~StreamStub(); - - // Methods of 'DriverInterface'. - ::android::status_t init() override; - ::android::status_t drain(StreamDescriptor::DrainMode) override; - ::android::status_t flush() override; - ::android::status_t pause() override; - ::android::status_t standby() override; - ::android::status_t start() override; - ::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount, - int32_t* latencyMs) override; - void shutdown() override; - - private: - const size_t mBufferSizeFrames; - const size_t mFrameSizeBytes; - const int mSampleRate; - const bool mIsAsynchronous; - const bool mIsInput; - bool mIsInitialized = false; // Used for validating the state machine logic. - bool mIsStandby = true; // Used for validating the state machine logic. - - // Used by the worker thread. - int64_t mStartTimeNs = 0; - long mFramesSinceStart = 0; }; class StreamInStub final : public StreamIn, public StreamStub { diff --git a/audio/aidl/default/primary/PrimaryMixer.h b/audio/aidl/default/primary/PrimaryMixer.h index 3806428cfd..760d42f362 100644 --- a/audio/aidl/default/primary/PrimaryMixer.h +++ b/audio/aidl/default/primary/PrimaryMixer.h @@ -16,20 +16,14 @@ #pragma once -#include -#include -#include -#include - -#include -#include - #include "alsa/Mixer.h" namespace aidl::android::hardware::audio::core::primary { class PrimaryMixer : public alsa::Mixer { public: + static constexpr int kInvalidAlsaCard = -1; + static constexpr int kInvalidAlsaDevice = -1; static constexpr int kAlsaCard = 0; static constexpr int kAlsaDevice = 0; diff --git a/audio/aidl/default/primary/StreamPrimary.cpp b/audio/aidl/default/primary/StreamPrimary.cpp index 801bbb8e59..1176d05316 100644 --- a/audio/aidl/default/primary/StreamPrimary.cpp +++ b/audio/aidl/default/primary/StreamPrimary.cpp @@ -25,9 +25,7 @@ #include #include -#include "PrimaryMixer.h" #include "core-impl/StreamPrimary.h" -#include "core-impl/StreamStub.h" using aidl::android::hardware::audio::common::SinkMetadata; using aidl::android::hardware::audio::common::SourceMetadata; @@ -41,19 +39,49 @@ using android::base::GetBoolProperty; namespace aidl::android::hardware::audio::core { -const static constexpr std::pair kDefaultCardAndDeviceId = { - primary::PrimaryMixer::kAlsaCard, primary::PrimaryMixer::kAlsaDevice}; - -StreamPrimary::StreamPrimary( - StreamContext* context, const Metadata& metadata, - const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) +StreamPrimary::StreamPrimary(StreamContext* context, const Metadata& metadata) : StreamAlsa(context, metadata, 3 /*readWriteRetries*/), mIsAsynchronous(!!getContext().getAsyncCallback()), - mCardAndDeviceId(getCardAndDeviceId(devices)) { + mStubDriver(getContext()) { context->startStreamDataProcessor(); } +::android::status_t StreamPrimary::init() { + RETURN_STATUS_IF_ERROR(mStubDriver.init()); + return StreamAlsa::init(); +} + +::android::status_t StreamPrimary::drain(StreamDescriptor::DrainMode mode) { + return isStubStreamOnWorker() ? mStubDriver.drain(mode) : StreamAlsa::drain(mode); +} + +::android::status_t StreamPrimary::flush() { + return isStubStreamOnWorker() ? mStubDriver.flush() : StreamAlsa::flush(); +} + +::android::status_t StreamPrimary::pause() { + return isStubStreamOnWorker() ? mStubDriver.pause() : StreamAlsa::pause(); +} + +::android::status_t StreamPrimary::standby() { + return isStubStreamOnWorker() ? mStubDriver.standby() : StreamAlsa::standby(); +} + ::android::status_t StreamPrimary::start() { + bool isStub = true, shutdownAlsaStream = false; + { + std::lock_guard l(mLock); + isStub = mAlsaDeviceId == kStubDeviceId; + shutdownAlsaStream = + mCurrAlsaDeviceId != mAlsaDeviceId && mCurrAlsaDeviceId != kStubDeviceId; + mCurrAlsaDeviceId = mAlsaDeviceId; + } + if (shutdownAlsaStream) { + StreamAlsa::shutdown(); // Close currently opened ALSA devices. + } + if (isStub) { + return mStubDriver.start(); + } RETURN_STATUS_IF_ERROR(StreamAlsa::start()); mStartTimeNs = ::android::uptimeNanos(); mFramesSinceStart = 0; @@ -63,6 +91,9 @@ StreamPrimary::StreamPrimary( ::android::status_t StreamPrimary::transfer(void* buffer, size_t frameCount, size_t* actualFrameCount, int32_t* latencyMs) { + if (isStubStreamOnWorker()) { + return mStubDriver.transfer(buffer, frameCount, actualFrameCount, latencyMs); + } // This is a workaround for the emulator implementation which has a host-side buffer // and is not being able to achieve real-time behavior similar to ADSPs (b/302587331). if (!mSkipNextTransfer) { @@ -102,19 +133,52 @@ StreamPrimary::StreamPrimary( return ::android::OK; } +void StreamPrimary::shutdown() { + StreamAlsa::shutdown(); + mStubDriver.shutdown(); +} + +ndk::ScopedAStatus StreamPrimary::setConnectedDevices(const ConnectedDevices& devices) { + LOG(DEBUG) << __func__ << ": " << ::android::internal::ToString(devices); + if (devices.size() > 1) { + LOG(ERROR) << __func__ << ": primary stream can only be connected to one device, got: " + << devices.size(); + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); + } + { + const bool useStubDriver = devices.empty() || useStubStream(mIsInput, devices[0]); + std::lock_guard l(mLock); + mAlsaDeviceId = useStubDriver ? kStubDeviceId : getCardAndDeviceId(devices); + } + if (!devices.empty()) { + auto streamDataProcessor = getContext().getStreamDataProcessor().lock(); + if (streamDataProcessor != nullptr) { + streamDataProcessor->setAudioDevice(devices[0]); + } + } + return StreamAlsa::setConnectedDevices(devices); +} + std::vector StreamPrimary::getDeviceProfiles() { - return {alsa::DeviceProfile{.card = mCardAndDeviceId.first, - .device = mCardAndDeviceId.second, + return {alsa::DeviceProfile{.card = mCurrAlsaDeviceId.first, + .device = mCurrAlsaDeviceId.second, .direction = mIsInput ? PCM_IN : PCM_OUT, .isExternal = false}}; } -std::pair StreamPrimary::getCardAndDeviceId(const std::vector& devices) { +bool StreamPrimary::isStubStream() { + std::lock_guard l(mLock); + return mAlsaDeviceId == kStubDeviceId; +} + +// static +StreamPrimary::AlsaDeviceId StreamPrimary::getCardAndDeviceId( + const std::vector& devices) { if (devices.empty() || devices[0].address.getTag() != AudioDeviceAddress::id) { return kDefaultCardAndDeviceId; } std::string deviceAddress = devices[0].address.get(); - std::pair cardAndDeviceId; + AlsaDeviceId cardAndDeviceId; if (const size_t suffixPos = deviceAddress.rfind("CARD_"); suffixPos == std::string::npos || sscanf(deviceAddress.c_str() + suffixPos, "CARD_%d_DEV_%d", &cardAndDeviceId.first, @@ -126,48 +190,28 @@ std::pair StreamPrimary::getCardAndDeviceId(const std::vector& microphones) : StreamIn(std::move(context), microphones), - StreamSwitcher(&mContextInstance, sinkMetadata), + StreamPrimary(&mContextInstance, sinkMetadata), StreamInHwGainHelper(&mContextInstance) {} -bool StreamInPrimary::useStubStream(const AudioDevice& device) { - static const bool kSimulateInput = - GetBoolProperty("ro.boot.audio.tinyalsa.simulate_input", false); - return kSimulateInput || device.type.type == AudioDeviceType::IN_TELEPHONY_RX || - device.type.type == AudioDeviceType::IN_FM_TUNER || - device.type.connection == AudioDeviceDescription::CONNECTION_BUS /*deprecated */; -} - -StreamSwitcher::DeviceSwitchBehavior StreamInPrimary::switchCurrentStream( - const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) { - LOG(DEBUG) << __func__; - if (devices.size() > 1) { - LOG(ERROR) << __func__ << ": primary stream can only be connected to one device, got: " - << devices.size(); - return DeviceSwitchBehavior::UNSUPPORTED_DEVICES; - } - if (devices.empty() || useStubStream(devices[0]) == isStubStream()) { - return DeviceSwitchBehavior::USE_CURRENT_STREAM; - } - return DeviceSwitchBehavior::CREATE_NEW_STREAM; -} - -std::unique_ptr StreamInPrimary::createNewStream( - const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices, - StreamContext* context, const Metadata& metadata) { - if (devices.empty()) { - LOG(FATAL) << __func__ << ": called with empty devices"; // see 'switchCurrentStream' - } - if (useStubStream(devices[0])) { - return std::unique_ptr( - new InnerStreamWrapper(context, metadata)); - } - return std::unique_ptr( - new InnerStreamWrapper(context, metadata, devices)); -} - ndk::ScopedAStatus StreamInPrimary::getHwGain(std::vector* _aidl_return) { if (isStubStream()) { return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); @@ -201,44 +245,9 @@ ndk::ScopedAStatus StreamInPrimary::setHwGain(const std::vector& in_chann StreamOutPrimary::StreamOutPrimary(StreamContext&& context, const SourceMetadata& sourceMetadata, const std::optional& offloadInfo) : StreamOut(std::move(context), offloadInfo), - StreamSwitcher(&mContextInstance, sourceMetadata), + StreamPrimary(&mContextInstance, sourceMetadata), StreamOutHwVolumeHelper(&mContextInstance) {} -bool StreamOutPrimary::useStubStream(const AudioDevice& device) { - static const bool kSimulateOutput = - GetBoolProperty("ro.boot.audio.tinyalsa.ignore_output", false); - return kSimulateOutput || device.type.type == AudioDeviceType::OUT_TELEPHONY_TX || - device.type.connection == AudioDeviceDescription::CONNECTION_BUS /*deprecated*/; -} - -StreamSwitcher::DeviceSwitchBehavior StreamOutPrimary::switchCurrentStream( - const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) { - LOG(DEBUG) << __func__; - if (devices.size() > 1) { - LOG(ERROR) << __func__ << ": primary stream can only be connected to one device, got: " - << devices.size(); - return DeviceSwitchBehavior::UNSUPPORTED_DEVICES; - } - if (devices.empty() || useStubStream(devices[0]) == isStubStream()) { - return DeviceSwitchBehavior::USE_CURRENT_STREAM; - } - return DeviceSwitchBehavior::CREATE_NEW_STREAM; -} - -std::unique_ptr StreamOutPrimary::createNewStream( - const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices, - StreamContext* context, const Metadata& metadata) { - if (devices.empty()) { - LOG(FATAL) << __func__ << ": called with empty devices"; // see 'switchCurrentStream' - } - if (useStubStream(devices[0])) { - return std::unique_ptr( - new InnerStreamWrapper(context, metadata)); - } - return std::unique_ptr( - new InnerStreamWrapper(context, metadata, devices)); -} - ndk::ScopedAStatus StreamOutPrimary::getHwVolume(std::vector* _aidl_return) { if (isStubStream()) { return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); @@ -264,15 +273,4 @@ ndk::ScopedAStatus StreamOutPrimary::setHwVolume(const std::vector& in_ch return ndk::ScopedAStatus::ok(); } -ndk::ScopedAStatus StreamOutPrimary::setConnectedDevices( - const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) { - if (!devices.empty()) { - auto streamDataProcessor = mContextInstance.getStreamDataProcessor().lock(); - if (streamDataProcessor != nullptr) { - streamDataProcessor->setAudioDevice(devices[0]); - } - } - return StreamSwitcher::setConnectedDevices(devices); -} - } // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/stub/DriverStubImpl.cpp b/audio/aidl/default/stub/DriverStubImpl.cpp new file mode 100644 index 0000000000..beb0114bda --- /dev/null +++ b/audio/aidl/default/stub/DriverStubImpl.cpp @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#define LOG_TAG "AHAL_Stream" +#include +#include + +#include "core-impl/DriverStubImpl.h" + +namespace aidl::android::hardware::audio::core { + +DriverStubImpl::DriverStubImpl(const StreamContext& context) + : mBufferSizeFrames(context.getBufferSizeInFrames()), + mFrameSizeBytes(context.getFrameSize()), + mSampleRate(context.getSampleRate()), + mIsAsynchronous(!!context.getAsyncCallback()), + mIsInput(context.isInput()) {} + +::android::status_t DriverStubImpl::init() { + mIsInitialized = true; + return ::android::OK; +} + +::android::status_t DriverStubImpl::drain(StreamDescriptor::DrainMode) { + if (!mIsInitialized) { + LOG(FATAL) << __func__ << ": must not happen for an uninitialized driver"; + } + if (!mIsInput) { + if (!mIsAsynchronous) { + static constexpr float kMicrosPerSecond = MICROS_PER_SECOND; + const size_t delayUs = static_cast( + std::roundf(mBufferSizeFrames * kMicrosPerSecond / mSampleRate)); + usleep(delayUs); + } else { + usleep(500); + } + } + return ::android::OK; +} + +::android::status_t DriverStubImpl::flush() { + if (!mIsInitialized) { + LOG(FATAL) << __func__ << ": must not happen for an uninitialized driver"; + } + return ::android::OK; +} + +::android::status_t DriverStubImpl::pause() { + if (!mIsInitialized) { + LOG(FATAL) << __func__ << ": must not happen for an uninitialized driver"; + } + return ::android::OK; +} + +::android::status_t DriverStubImpl::standby() { + if (!mIsInitialized) { + LOG(FATAL) << __func__ << ": must not happen for an uninitialized driver"; + } + mIsStandby = true; + return ::android::OK; +} + +::android::status_t DriverStubImpl::start() { + if (!mIsInitialized) { + LOG(FATAL) << __func__ << ": must not happen for an uninitialized driver"; + } + mIsStandby = false; + mStartTimeNs = ::android::uptimeNanos(); + mFramesSinceStart = 0; + return ::android::OK; +} + +::android::status_t DriverStubImpl::transfer(void* buffer, size_t frameCount, + size_t* actualFrameCount, int32_t*) { + if (!mIsInitialized) { + LOG(FATAL) << __func__ << ": must not happen for an uninitialized driver"; + } + if (mIsStandby) { + LOG(FATAL) << __func__ << ": must not happen while in standby"; + } + *actualFrameCount = frameCount; + if (mIsAsynchronous) { + usleep(500); + } else { + mFramesSinceStart += *actualFrameCount; + const long bufferDurationUs = (*actualFrameCount) * MICROS_PER_SECOND / mSampleRate; + const auto totalDurationUs = + (::android::uptimeNanos() - mStartTimeNs) / NANOS_PER_MICROSECOND; + const long totalOffsetUs = + mFramesSinceStart * MICROS_PER_SECOND / mSampleRate - totalDurationUs; + LOG(VERBOSE) << __func__ << ": totalOffsetUs " << totalOffsetUs; + if (totalOffsetUs > 0) { + const long sleepTimeUs = std::min(totalOffsetUs, bufferDurationUs); + LOG(VERBOSE) << __func__ << ": sleeping for " << sleepTimeUs << " us"; + usleep(sleepTimeUs); + } + } + if (mIsInput) { + uint8_t* byteBuffer = static_cast(buffer); + for (size_t i = 0; i < frameCount * mFrameSizeBytes; ++i) { + byteBuffer[i] = std::rand() % 255; + } + } + return ::android::OK; +} + +void DriverStubImpl::shutdown() { + mIsInitialized = false; +} + +} // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/stub/StreamStub.cpp b/audio/aidl/default/stub/StreamStub.cpp index a3d99a8873..f6c87e1911 100644 --- a/audio/aidl/default/stub/StreamStub.cpp +++ b/audio/aidl/default/stub/StreamStub.cpp @@ -32,110 +32,12 @@ using aidl::android::media::audio::common::MicrophoneInfo; namespace aidl::android::hardware::audio::core { StreamStub::StreamStub(StreamContext* context, const Metadata& metadata) - : StreamCommonImpl(context, metadata), - mBufferSizeFrames(getContext().getBufferSizeInFrames()), - mFrameSizeBytes(getContext().getFrameSize()), - mSampleRate(getContext().getSampleRate()), - mIsAsynchronous(!!getContext().getAsyncCallback()), - mIsInput(isInput(metadata)) {} + : StreamCommonImpl(context, metadata), DriverStubImpl(getContext()) {} StreamStub::~StreamStub() { cleanupWorker(); } -::android::status_t StreamStub::init() { - mIsInitialized = true; - return ::android::OK; -} - -::android::status_t StreamStub::drain(StreamDescriptor::DrainMode) { - if (!mIsInitialized) { - LOG(FATAL) << __func__ << ": must not happen for an uninitialized driver"; - } - if (!mIsInput) { - if (!mIsAsynchronous) { - static constexpr float kMicrosPerSecond = MICROS_PER_SECOND; - const size_t delayUs = static_cast( - std::roundf(mBufferSizeFrames * kMicrosPerSecond / mSampleRate)); - usleep(delayUs); - } else { - usleep(500); - } - } - return ::android::OK; -} - -::android::status_t StreamStub::flush() { - if (!mIsInitialized) { - LOG(FATAL) << __func__ << ": must not happen for an uninitialized driver"; - } - return ::android::OK; -} - -::android::status_t StreamStub::pause() { - if (!mIsInitialized) { - LOG(FATAL) << __func__ << ": must not happen for an uninitialized driver"; - } - return ::android::OK; -} - -::android::status_t StreamStub::standby() { - if (!mIsInitialized) { - LOG(FATAL) << __func__ << ": must not happen for an uninitialized driver"; - } - mIsStandby = true; - return ::android::OK; -} - -::android::status_t StreamStub::start() { - if (!mIsInitialized) { - LOG(FATAL) << __func__ << ": must not happen for an uninitialized driver"; - } - mIsStandby = false; - mStartTimeNs = ::android::uptimeNanos(); - mFramesSinceStart = 0; - return ::android::OK; -} - -::android::status_t StreamStub::transfer(void* buffer, size_t frameCount, size_t* actualFrameCount, - int32_t*) { - if (!mIsInitialized) { - LOG(FATAL) << __func__ << ": must not happen for an uninitialized driver"; - } - if (mIsStandby) { - LOG(FATAL) << __func__ << ": must not happen while in standby"; - } - *actualFrameCount = frameCount; - if (mIsAsynchronous) { - usleep(500); - } else { - mFramesSinceStart += *actualFrameCount; - const long bufferDurationUs = - (*actualFrameCount) * MICROS_PER_SECOND / mContext.getSampleRate(); - const auto totalDurationUs = - (::android::uptimeNanos() - mStartTimeNs) / NANOS_PER_MICROSECOND; - const long totalOffsetUs = - mFramesSinceStart * MICROS_PER_SECOND / mContext.getSampleRate() - totalDurationUs; - LOG(VERBOSE) << __func__ << ": totalOffsetUs " << totalOffsetUs; - if (totalOffsetUs > 0) { - const long sleepTimeUs = std::min(totalOffsetUs, bufferDurationUs); - LOG(VERBOSE) << __func__ << ": sleeping for " << sleepTimeUs << " us"; - usleep(sleepTimeUs); - } - } - if (mIsInput) { - uint8_t* byteBuffer = static_cast(buffer); - for (size_t i = 0; i < frameCount * mFrameSizeBytes; ++i) { - byteBuffer[i] = std::rand() % 255; - } - } - return ::android::OK; -} - -void StreamStub::shutdown() { - mIsInitialized = false; -} - StreamInStub::StreamInStub(StreamContext&& context, const SinkMetadata& sinkMetadata, const std::vector& microphones) : StreamIn(std::move(context), microphones), StreamStub(&mContextInstance, sinkMetadata) {}