Merge "Correctly parse Command Complete and Status events with empty op_code" into android15-tests-dev
diff --git a/audio/aidl/default/Android.bp b/audio/aidl/default/Android.bp
index 844f1e9..a3db45f 100644
--- a/audio/aidl/default/Android.bp
+++ b/audio/aidl/default/Android.bp
@@ -76,6 +76,7 @@
"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/Stream.cpp b/audio/aidl/default/Stream.cpp
index 8f5e839..eecc972 100644
--- a/audio/aidl/default/Stream.cpp
+++ b/audio/aidl/default/Stream.cpp
@@ -663,10 +663,14 @@
}
StreamCommonImpl::~StreamCommonImpl() {
- if (!isClosed()) {
- LOG(ERROR) << __func__ << ": stream was not closed prior to destruction, resource leak";
- stopWorker();
- // The worker and the context should clean up by themselves via destructors.
+ // It is responsibility of the class that implements 'DriverInterface' to call 'cleanupWorker'
+ // in the destructor. Note that 'cleanupWorker' can not be properly called from this destructor
+ // because any subclasses have already been destroyed and thus the 'DriverInterface'
+ // implementation is not valid. Thus, here it can only be asserted whether the subclass has done
+ // its job.
+ if (!mWorkerStopIssued && !isClosed()) {
+ LOG(FATAL) << __func__ << ": the stream implementation must call 'cleanupWorker' "
+ << "in order to clean up the worker thread.";
}
}
@@ -770,10 +774,7 @@
ndk::ScopedAStatus StreamCommonImpl::close() {
LOG(DEBUG) << __func__;
if (!isClosed()) {
- stopWorker();
- LOG(DEBUG) << __func__ << ": joining the worker thread...";
- mWorker->stop();
- LOG(DEBUG) << __func__ << ": worker thread joined";
+ stopAndJoinWorker();
onClose(mWorker->setClosed());
return ndk::ScopedAStatus::ok();
} else {
@@ -791,6 +792,20 @@
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
}
+void StreamCommonImpl::cleanupWorker() {
+ if (!isClosed()) {
+ LOG(ERROR) << __func__ << ": stream was not closed prior to destruction, resource leak";
+ stopAndJoinWorker();
+ }
+}
+
+void StreamCommonImpl::stopAndJoinWorker() {
+ stopWorker();
+ LOG(DEBUG) << __func__ << ": joining the worker thread...";
+ mWorker->join();
+ LOG(DEBUG) << __func__ << ": worker thread joined";
+}
+
void StreamCommonImpl::stopWorker() {
if (auto commandMQ = mContext.getCommandMQ(); commandMQ != nullptr) {
LOG(DEBUG) << __func__ << ": asking the worker to exit...";
@@ -805,6 +820,7 @@
}
LOG(DEBUG) << __func__ << ": done";
}
+ mWorkerStopIssued = true;
}
ndk::ScopedAStatus StreamCommonImpl::updateMetadataCommon(const Metadata& metadata) {
diff --git a/audio/aidl/default/alsa/StreamAlsa.cpp b/audio/aidl/default/alsa/StreamAlsa.cpp
index e57d538..f548903 100644
--- a/audio/aidl/default/alsa/StreamAlsa.cpp
+++ b/audio/aidl/default/alsa/StreamAlsa.cpp
@@ -37,6 +37,10 @@
mConfig(alsa::getPcmConfig(getContext(), mIsInput)),
mReadWriteRetries(readWriteRetries) {}
+StreamAlsa::~StreamAlsa() {
+ cleanupWorker();
+}
+
::android::status_t StreamAlsa::init() {
return mConfig.has_value() ? ::android::OK : ::android::NO_INIT;
}
diff --git a/audio/aidl/default/bluetooth/StreamBluetooth.cpp b/audio/aidl/default/bluetooth/StreamBluetooth.cpp
index efab470..6e1a811 100644
--- a/audio/aidl/default/bluetooth/StreamBluetooth.cpp
+++ b/audio/aidl/default/bluetooth/StreamBluetooth.cpp
@@ -66,6 +66,10 @@
1000),
mBtDeviceProxy(btDeviceProxy) {}
+StreamBluetooth::~StreamBluetooth() {
+ cleanupWorker();
+}
+
::android::status_t StreamBluetooth::init() {
std::lock_guard guard(mLock);
if (mBtDeviceProxy == nullptr) {
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 0000000..40a9fea
--- /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 6b45866..00f3af1 100644
--- a/audio/aidl/default/include/core-impl/Stream.h
+++ b/audio/aidl/default/include/core-impl/Stream.h
@@ -132,6 +132,9 @@
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.
@@ -245,7 +248,7 @@
virtual StreamDescriptor::State setClosed() = 0;
virtual bool start() = 0;
virtual pid_t getTid() = 0;
- virtual void stop() = 0;
+ virtual void join() = 0;
virtual std::string getError() = 0;
};
@@ -265,7 +268,7 @@
return WorkerImpl::start(WorkerImpl::kThreadName, ANDROID_PRIORITY_URGENT_AUDIO);
}
pid_t getTid() override { return WorkerImpl::getTid(); }
- void stop() override { return WorkerImpl::stop(); }
+ void join() override { return WorkerImpl::join(); }
std::string getError() override { return WorkerImpl::getError(); }
};
@@ -457,6 +460,11 @@
}
virtual void onClose(StreamDescriptor::State statePriorToClosing) = 0;
+ // Any stream class implementing 'DriverInterface::shutdown' must call 'cleanupWorker' in
+ // the destructor in order to stop and join the worker thread in the case when the client
+ // has not called 'IStreamCommon::close' method.
+ void cleanupWorker();
+ void stopAndJoinWorker();
void stopWorker();
const StreamContext& mContext;
@@ -464,6 +472,9 @@
std::unique_ptr<StreamWorkerInterface> mWorker;
ChildInterface<StreamCommonDelegator> mCommon;
ConnectedDevices mConnectedDevices;
+
+ private:
+ std::atomic<bool> mWorkerStopIssued = false;
};
// Note: 'StreamIn/Out' can not be used on their own. Instead, they must be used for defining
diff --git a/audio/aidl/default/include/core-impl/StreamAlsa.h b/audio/aidl/default/include/core-impl/StreamAlsa.h
index 2c3b284..0356946 100644
--- a/audio/aidl/default/include/core-impl/StreamAlsa.h
+++ b/audio/aidl/default/include/core-impl/StreamAlsa.h
@@ -32,6 +32,8 @@
class StreamAlsa : public StreamCommonImpl {
public:
StreamAlsa(StreamContext* context, const Metadata& metadata, int readWriteRetries);
+ ~StreamAlsa();
+
// Methods of 'DriverInterface'.
::android::status_t init() override;
::android::status_t drain(StreamDescriptor::DrainMode) override;
diff --git a/audio/aidl/default/include/core-impl/StreamBluetooth.h b/audio/aidl/default/include/core-impl/StreamBluetooth.h
index 7f4239c..357a546 100644
--- a/audio/aidl/default/include/core-impl/StreamBluetooth.h
+++ b/audio/aidl/default/include/core-impl/StreamBluetooth.h
@@ -41,6 +41,8 @@
const std::shared_ptr<::android::bluetooth::audio::aidl::BluetoothAudioPortAidl>&
btDeviceProxy,
const ::aidl::android::hardware::bluetooth::audio::PcmConfiguration& pcmConfig);
+ ~StreamBluetooth();
+
// Methods of 'DriverInterface'.
::android::status_t init() override;
::android::status_t drain(StreamDescriptor::DrainMode) override;
diff --git a/audio/aidl/default/include/core-impl/StreamPrimary.h b/audio/aidl/default/include/core-impl/StreamPrimary.h
index 8d5c57d..4f19a46 100644
--- a/audio/aidl/default/include/core-impl/StreamPrimary.h
+++ b/audio/aidl/default/include/core-impl/StreamPrimary.h
@@ -16,10 +16,14 @@
#pragma once
+#include <mutex>
#include <vector>
+#include <android-base/thread_annotations.h>
+
+#include "DriverStubImpl.h"
#include "StreamAlsa.h"
-#include "StreamSwitcher.h"
+#include "primary/PrimaryMixer.h"
namespace aidl::android::hardware::audio::core {
@@ -27,21 +31,54 @@
public:
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<alsa::DeviceProfile> getDeviceProfiles() override;
+ bool isStubStream();
const bool mIsAsynchronous;
int64_t mStartTimeNs = 0;
long mFramesSinceStart = 0;
bool mSkipNextTransfer = false;
+
+ private:
+ using AlsaDeviceId = std::pair<int, int>;
+
+ 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);
+ 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(
@@ -50,14 +87,6 @@
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<StreamCommonInterfaceEx> 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<float>* _aidl_return) override;
@@ -65,7 +94,7 @@
};
class StreamOutPrimary final : public StreamOut,
- public StreamSwitcher,
+ public StreamPrimary,
public StreamOutHwVolumeHelper {
public:
friend class ndk::SharedRefBase;
@@ -75,22 +104,10 @@
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<StreamCommonInterfaceEx> 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<float>* _aidl_return) override;
ndk::ScopedAStatus setHwVolume(const std::vector<float>& 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/StreamRemoteSubmix.h b/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h
index 0d50c96..6ea7968 100644
--- a/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h
+++ b/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h
@@ -29,7 +29,9 @@
StreamRemoteSubmix(
StreamContext* context, const Metadata& metadata,
const ::aidl::android::media::audio::common::AudioDeviceAddress& deviceAddress);
+ ~StreamRemoteSubmix();
+ // Methods of 'DriverInterface'.
::android::status_t init() override;
::android::status_t drain(StreamDescriptor::DrainMode) override;
::android::status_t flush() override;
diff --git a/audio/aidl/default/include/core-impl/StreamStub.h b/audio/aidl/default/include/core-impl/StreamStub.h
index 3857e0e..cee44db 100644
--- a/audio/aidl/default/include/core-impl/StreamStub.h
+++ b/audio/aidl/default/include/core-impl/StreamStub.h
@@ -16,32 +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);
- // 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.
+ ~StreamStub();
};
class StreamInStub final : public StreamIn, public StreamStub {
diff --git a/audio/aidl/default/include/core-impl/StreamUsb.h b/audio/aidl/default/include/core-impl/StreamUsb.h
index 608f27d..694fccf 100644
--- a/audio/aidl/default/include/core-impl/StreamUsb.h
+++ b/audio/aidl/default/include/core-impl/StreamUsb.h
@@ -29,6 +29,7 @@
class StreamUsb : public StreamAlsa {
public:
StreamUsb(StreamContext* context, const Metadata& metadata);
+
// Methods of 'DriverInterface'.
::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
int32_t* latencyMs) override;
diff --git a/audio/aidl/default/primary/PrimaryMixer.h b/audio/aidl/default/primary/PrimaryMixer.h
index 3806428..760d42f 100644
--- a/audio/aidl/default/primary/PrimaryMixer.h
+++ b/audio/aidl/default/primary/PrimaryMixer.h
@@ -16,20 +16,14 @@
#pragma once
-#include <map>
-#include <memory>
-#include <mutex>
-#include <vector>
-
-#include <android-base/thread_annotations.h>
-#include <android/binder_auto_utils.h>
-
#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 7325a91..9fb07e5 100644
--- a/audio/aidl/default/primary/StreamPrimary.cpp
+++ b/audio/aidl/default/primary/StreamPrimary.cpp
@@ -21,9 +21,7 @@
#include <error/Result.h>
#include <error/expected_utils.h>
-#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;
@@ -38,11 +36,47 @@
StreamPrimary::StreamPrimary(StreamContext* context, const Metadata& metadata)
: StreamAlsa(context, metadata, 3 /*readWriteRetries*/),
- mIsAsynchronous(!!getContext().getAsyncCallback()) {
+ mIsAsynchronous(!!getContext().getAsyncCallback()),
+ 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;
@@ -52,6 +86,9 @@
::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) {
@@ -91,63 +128,73 @@
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<alsa::DeviceProfile> StreamPrimary::getDeviceProfiles() {
- static const std::vector<alsa::DeviceProfile> kBuiltInSource{
- alsa::DeviceProfile{.card = primary::PrimaryMixer::kAlsaCard,
- .device = primary::PrimaryMixer::kAlsaDevice,
- .direction = PCM_IN,
+ return {alsa::DeviceProfile{.card = mCurrAlsaDeviceId.first,
+ .device = mCurrAlsaDeviceId.second,
+ .direction = mIsInput ? PCM_IN : PCM_OUT,
.isExternal = false}};
- static const std::vector<alsa::DeviceProfile> kBuiltInSink{
- alsa::DeviceProfile{.card = primary::PrimaryMixer::kAlsaCard,
- .device = primary::PrimaryMixer::kAlsaDevice,
- .direction = PCM_OUT,
- .isExternal = false}};
- return mIsInput ? kBuiltInSource : kBuiltInSink;
+}
+
+bool StreamPrimary::isStubStream() {
+ std::lock_guard l(mLock);
+ return mAlsaDeviceId == kStubDeviceId;
+}
+
+// static
+StreamPrimary::AlsaDeviceId StreamPrimary::getCardAndDeviceId(const std::vector<AudioDevice>&) {
+ return kDefaultCardAndDeviceId;
+}
+
+// static
+bool StreamPrimary::useStubStream(
+ bool isInput, const ::aidl::android::media::audio::common::AudioDevice& device) {
+ static const bool kSimulateInput =
+ GetBoolProperty("ro.boot.audio.tinyalsa.simulate_input", false);
+ static const bool kSimulateOutput =
+ GetBoolProperty("ro.boot.audio.tinyalsa.ignore_output", false);
+ if (isInput) {
+ return kSimulateInput || device.type.type == AudioDeviceType::IN_TELEPHONY_RX ||
+ device.type.type == AudioDeviceType::IN_FM_TUNER ||
+ device.type.connection == AudioDeviceDescription::CONNECTION_BUS /*deprecated */ ||
+ (device.type.type == AudioDeviceType::IN_BUS && device.type.connection.empty());
+ }
+ return kSimulateOutput || device.type.type == AudioDeviceType::OUT_TELEPHONY_TX ||
+ device.type.connection == AudioDeviceDescription::CONNECTION_BUS /*deprecated*/ ||
+ (device.type.type == AudioDeviceType::OUT_BUS && device.type.connection.empty());
}
StreamInPrimary::StreamInPrimary(StreamContext&& context, const SinkMetadata& sinkMetadata,
const std::vector<MicrophoneInfo>& 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 */ ||
- (device.type.type == AudioDeviceType::IN_BUS && device.type.connection.empty());
-}
-
-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<StreamCommonInterfaceEx> 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<StreamCommonInterfaceEx>(
- new InnerStreamWrapper<StreamStub>(context, metadata));
- }
- return std::unique_ptr<StreamCommonInterfaceEx>(
- new InnerStreamWrapper<StreamPrimary>(context, metadata));
-}
-
ndk::ScopedAStatus StreamInPrimary::getHwGain(std::vector<float>* _aidl_return) {
if (isStubStream()) {
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
@@ -181,45 +228,9 @@
StreamOutPrimary::StreamOutPrimary(StreamContext&& context, const SourceMetadata& sourceMetadata,
const std::optional<AudioOffloadInfo>& 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*/ ||
- (device.type.type == AudioDeviceType::OUT_BUS && device.type.connection.empty());
-}
-
-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<StreamCommonInterfaceEx> 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<StreamCommonInterfaceEx>(
- new InnerStreamWrapper<StreamStub>(context, metadata));
- }
- return std::unique_ptr<StreamCommonInterfaceEx>(
- new InnerStreamWrapper<StreamPrimary>(context, metadata));
-}
-
ndk::ScopedAStatus StreamOutPrimary::getHwVolume(std::vector<float>* _aidl_return) {
if (isStubStream()) {
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
@@ -245,15 +256,4 @@
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/r_submix/StreamRemoteSubmix.cpp b/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp
index ca3f91a..28b633c 100644
--- a/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp
+++ b/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp
@@ -43,6 +43,10 @@
mStreamConfig.sampleRate = context->getSampleRate();
}
+StreamRemoteSubmix::~StreamRemoteSubmix() {
+ cleanupWorker();
+}
+
::android::status_t StreamRemoteSubmix::init() {
mCurrentRoute = SubmixRoute::findOrCreateRoute(mDeviceAddress, mStreamConfig);
if (mCurrentRoute == nullptr) {
diff --git a/audio/aidl/default/stub/DriverStubImpl.cpp b/audio/aidl/default/stub/DriverStubImpl.cpp
new file mode 100644
index 0000000..beb0114
--- /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 <cmath>
+
+#define LOG_TAG "AHAL_Stream"
+#include <android-base/logging.h>
+#include <audio_utils/clock.h>
+
+#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<size_t>(
+ 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<uint8_t*>(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 2422fe4..f6c87e1 100644
--- a/audio/aidl/default/stub/StreamStub.cpp
+++ b/audio/aidl/default/stub/StreamStub.cpp
@@ -32,96 +32,10 @@
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()) {}
-::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<size_t>(
- 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";
- }
- usleep(500);
- mIsStandby = true;
- return ::android::OK;
-}
-
-::android::status_t StreamStub::start() {
- if (!mIsInitialized) {
- LOG(FATAL) << __func__ << ": must not happen for an uninitialized driver";
- }
- usleep(500);
- mIsStandby = false;
- 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";
- }
- static constexpr float kMicrosPerSecond = MICROS_PER_SECOND;
- static constexpr float kScaleFactor = .8f;
- if (mIsAsynchronous) {
- usleep(500);
- } else {
- const size_t delayUs = static_cast<size_t>(
- std::roundf(kScaleFactor * frameCount * kMicrosPerSecond / mSampleRate));
- usleep(delayUs);
- }
- if (mIsInput) {
- uint8_t* byteBuffer = static_cast<uint8_t*>(buffer);
- for (size_t i = 0; i < frameCount * mFrameSizeBytes; ++i) {
- byteBuffer[i] = std::rand() % 255;
- }
- }
- *actualFrameCount = frameCount;
- return ::android::OK;
-}
-
-void StreamStub::shutdown() {
- mIsInitialized = false;
+StreamStub::~StreamStub() {
+ cleanupWorker();
}
StreamInStub::StreamInStub(StreamContext&& context, const SinkMetadata& sinkMetadata,
diff --git a/radio/1.6/vts/functional/radio_hidl_hal_api.cpp b/radio/1.6/vts/functional/radio_hidl_hal_api.cpp
index 9f530b3..f909676 100644
--- a/radio/1.6/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.6/vts/functional/radio_hidl_hal_api.cpp
@@ -239,18 +239,13 @@
EXPECT_EQ(std::cv_status::no_timeout, wait());
EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_6->rspInfo.type);
EXPECT_EQ(serial, radioRsp_v1_6->rspInfo.serial);
- if (getRadioHalCapabilities()) {
- ASSERT_TRUE(CheckAnyOfErrors(
- radioRsp_v1_6->rspInfo.error,
- {::android::hardware::radio::V1_6::RadioError::REQUEST_NOT_SUPPORTED}));
- } else {
- ASSERT_TRUE(
- CheckAnyOfErrors(radioRsp_v1_6->rspInfo.error,
- {::android::hardware::radio::V1_6::RadioError::NONE,
- ::android::hardware::radio::V1_6::RadioError::RADIO_NOT_AVAILABLE,
- ::android::hardware::radio::V1_6::RadioError::INTERNAL_ERR,
- ::android::hardware::radio::V1_6::RadioError::MODEM_ERR}));
- }
+ ASSERT_TRUE(CheckAnyOfErrors(
+ radioRsp_v1_6->rspInfo.error,
+ {::android::hardware::radio::V1_6::RadioError::NONE,
+ ::android::hardware::radio::V1_6::RadioError::REQUEST_NOT_SUPPORTED,
+ ::android::hardware::radio::V1_6::RadioError::RADIO_NOT_AVAILABLE,
+ ::android::hardware::radio::V1_6::RadioError::INTERNAL_ERR,
+ ::android::hardware::radio::V1_6::RadioError::MODEM_ERR}));
}
/*
diff --git a/security/keymint/support/remote_prov_utils.cpp b/security/keymint/support/remote_prov_utils.cpp
index 6638775..d426919 100644
--- a/security/keymint/support/remote_prov_utils.cpp
+++ b/security/keymint/support/remote_prov_utils.cpp
@@ -974,15 +974,14 @@
ErrMsgOr<hwtrust::DiceChain::Kind> getDiceChainKind() {
int vendor_api_level = ::android::base::GetIntProperty("ro.vendor.api_level", -1);
- switch (vendor_api_level) {
- case __ANDROID_API_T__:
- return hwtrust::DiceChain::Kind::kVsr13;
- case __ANDROID_API_U__:
- return hwtrust::DiceChain::Kind::kVsr14;
- case 202404: /* TODO(b/315056516) Use a version macro for vendor API 24Q2 */
- return hwtrust::DiceChain::Kind::kVsr15;
- default:
- return "Unsupported vendor API level: " + std::to_string(vendor_api_level);
+ if (vendor_api_level <= __ANDROID_API_T__) {
+ return hwtrust::DiceChain::Kind::kVsr13;
+ } else if (vendor_api_level == __ANDROID_API_U__) {
+ return hwtrust::DiceChain::Kind::kVsr14;
+ } else if (vendor_api_level == 202404) {
+ return hwtrust::DiceChain::Kind::kVsr15;
+ } else {
+ return "Unsupported vendor API level: " + std::to_string(vendor_api_level);
}
}
diff --git a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.cpp b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.cpp
index 2b39bc6..158e4f1 100644
--- a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.cpp
+++ b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.cpp
@@ -100,7 +100,9 @@
ASSERT_TRUE(mFilterTests.configFilter(filterReconf.settings, filterId));
ASSERT_TRUE(mFilterTests.startFilter(filterId));
ASSERT_TRUE(mFrontendTests.tuneFrontend(frontendConf, true /*testWithDemux*/));
- ASSERT_TRUE(mFilterTests.startIdTest(filterId));
+ if (!isPassthroughFilter(filterReconf)) {
+ ASSERT_TRUE(mFilterTests.startIdTest(filterId));
+ }
ASSERT_TRUE(mFrontendTests.stopTuneFrontend(true /*testWithDemux*/));
ASSERT_TRUE(mFilterTests.stopFilter(filterId));
ASSERT_TRUE(mFilterTests.closeFilter(filterId));
@@ -152,7 +154,9 @@
ASSERT_TRUE(mFilterTests.startFilter(filterId));
// tune test
ASSERT_TRUE(mFrontendTests.tuneFrontend(frontendConf, true /*testWithDemux*/));
- ASSERT_TRUE(filterDataOutputTest());
+ if (!isPassthroughFilter(filterConf)) {
+ ASSERT_TRUE(filterDataOutputTest());
+ }
ASSERT_TRUE(mFrontendTests.stopTuneFrontend(true /*testWithDemux*/));
ASSERT_TRUE(mFilterTests.stopFilter(filterId));
ASSERT_TRUE(mFilterTests.closeFilter(filterId));
@@ -210,7 +214,9 @@
ASSERT_TRUE(mFilterTests.startFilter(filterId));
// tune test
ASSERT_TRUE(mFrontendTests.tuneFrontend(frontendConf, true /*testWithDemux*/));
- ASSERT_TRUE(filterDataOutputTest());
+ if (!isPassthroughFilter(filterConf)) {
+ ASSERT_TRUE(filterDataOutputTest());
+ }
ASSERT_TRUE(mFrontendTests.stopTuneFrontend(true /*testWithDemux*/));
ASSERT_TRUE(mFilterTests.stopFilter(filterId));
ASSERT_TRUE(mFilterTests.releaseShareAvHandle(filterId));
diff --git a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.h b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.h
index be9b996..5fdc3dc 100644
--- a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.h
+++ b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.h
@@ -89,6 +89,28 @@
sectionFilterIds.clear();
}
+bool isPassthroughFilter(FilterConfig filterConfig) {
+ auto type = filterConfig.type;
+ if (type.mainType == DemuxFilterMainType::TS) {
+ auto subType = type.subType.get<DemuxFilterSubType::Tag::tsFilterType>();
+ if (subType == DemuxTsFilterType::AUDIO || subType == DemuxTsFilterType::VIDEO) {
+ auto tsFilterSettings = filterConfig.settings.get<DemuxFilterSettings::Tag::ts>();
+ auto avSettings = tsFilterSettings.filterSettings
+ .get<DemuxTsFilterSettingsFilterSettings::Tag::av>();
+ return avSettings.isPassthrough;
+ }
+ } else if (filterConfig.type.mainType != DemuxFilterMainType::MMTP) {
+ auto subType = type.subType.get<DemuxFilterSubType::Tag::mmtpFilterType>();
+ if (subType == DemuxMmtpFilterType::AUDIO || subType == DemuxMmtpFilterType::VIDEO) {
+ auto mmtpFilterSettings = filterConfig.settings.get<DemuxFilterSettings::Tag::mmtp>();
+ auto avSettings = mmtpFilterSettings.filterSettings
+ .get<DemuxMmtpFilterSettingsFilterSettings::Tag::av>();
+ return avSettings.isPassthrough;
+ }
+ }
+ return false;
+}
+
enum class Dataflow_Context { LNBRECORD, RECORD, DESCRAMBLING, LNBDESCRAMBLING };
class TunerLnbAidlTest : public testing::TestWithParam<std::string> {