libaudiohal: Implement basic stream I/O
Implement completely DeviceHalAidl::open{Input|Output}Stream.
Implement reading, writing, and position reporting in StreamHalAidl.
Implement pause, resume, and drain for StreamOutHalAidl.
Bug: 205884982
Test: boot cuttlefish with AIDL enabled
Test: run tests from libaudioclient/TEST_MAPPING
Test: atest CtsMediaAudioTestCases
Change-Id: I928593094e4d8adbdecfd22cb3acdd60027924da
diff --git a/media/libaudiohal/impl/StreamHalAidl.h b/media/libaudiohal/impl/StreamHalAidl.h
index e55c413..ce6c31c 100644
--- a/media/libaudiohal/impl/StreamHalAidl.h
+++ b/media/libaudiohal/impl/StreamHalAidl.h
@@ -16,7 +16,9 @@
#pragma once
+#include <atomic>
#include <memory>
+#include <mutex>
#include <string_view>
#include <aidl/android/hardware/audio/core/BpStreamCommon.h>
@@ -32,7 +34,68 @@
namespace android {
-class DeviceHalAidl;
+class StreamContextAidl {
+ public:
+ typedef AidlMessageQueue<::aidl::android::hardware::audio::core::StreamDescriptor::Command,
+ ::aidl::android::hardware::common::fmq::SynchronizedReadWrite> CommandMQ;
+ typedef AidlMessageQueue<::aidl::android::hardware::audio::core::StreamDescriptor::Reply,
+ ::aidl::android::hardware::common::fmq::SynchronizedReadWrite> ReplyMQ;
+ typedef AidlMessageQueue<int8_t,
+ ::aidl::android::hardware::common::fmq::SynchronizedReadWrite> DataMQ;
+
+ explicit StreamContextAidl(
+ const ::aidl::android::hardware::audio::core::StreamDescriptor& descriptor)
+ : mFrameSizeBytes(descriptor.frameSizeBytes),
+ mCommandMQ(new CommandMQ(descriptor.command)),
+ mReplyMQ(new ReplyMQ(descriptor.reply)),
+ mBufferSizeFrames(descriptor.bufferSizeFrames),
+ mDataMQ(maybeCreateDataMQ(descriptor)) {}
+ StreamContextAidl(StreamContextAidl&& other) :
+ mFrameSizeBytes(other.mFrameSizeBytes),
+ mCommandMQ(std::move(other.mCommandMQ)),
+ mReplyMQ(std::move(other.mReplyMQ)),
+ mBufferSizeFrames(other.mBufferSizeFrames),
+ mDataMQ(std::move(other.mDataMQ)) {}
+ StreamContextAidl& operator=(StreamContextAidl&& other) {
+ mFrameSizeBytes = other.mFrameSizeBytes;
+ mCommandMQ = std::move(other.mCommandMQ);
+ mReplyMQ = std::move(other.mReplyMQ);
+ mBufferSizeFrames = other.mBufferSizeFrames;
+ mDataMQ = std::move(other.mDataMQ);
+ return *this;
+ }
+ bool isValid() const {
+ return mFrameSizeBytes != 0 &&
+ mCommandMQ != nullptr && mCommandMQ->isValid() &&
+ mReplyMQ != nullptr && mReplyMQ->isValid() &&
+ (mDataMQ != nullptr || (
+ mDataMQ->isValid() &&
+ mDataMQ->getQuantumCount() * mDataMQ->getQuantumSize() >=
+ mFrameSizeBytes * mBufferSizeFrames));
+ }
+ size_t getBufferSizeBytes() const { return mFrameSizeBytes * mBufferSizeFrames; }
+ size_t getBufferSizeFrames() const { return mBufferSizeFrames; }
+ CommandMQ* getCommandMQ() const { return mCommandMQ.get(); }
+ DataMQ* getDataMQ() const { return mDataMQ.get(); }
+ size_t getFrameSizeBytes() const { return mFrameSizeBytes; }
+ ReplyMQ* getReplyMQ() const { return mReplyMQ.get(); }
+
+ private:
+ static std::unique_ptr<DataMQ> maybeCreateDataMQ(
+ const ::aidl::android::hardware::audio::core::StreamDescriptor& descriptor) {
+ using Tag = ::aidl::android::hardware::audio::core::StreamDescriptor::AudioBuffer::Tag;
+ if (descriptor.audio.getTag() == Tag::fmq) {
+ return std::make_unique<DataMQ>(descriptor.audio.get<Tag::fmq>());
+ }
+ return nullptr;
+ }
+
+ size_t mFrameSizeBytes;
+ std::unique_ptr<CommandMQ> mCommandMQ;
+ std::unique_ptr<ReplyMQ> mReplyMQ;
+ size_t mBufferSizeFrames;
+ std::unique_ptr<DataMQ> mDataMQ;
+};
class StreamHalAidl : public virtual StreamHalInterface, public ConversionHelperAidl {
public:
@@ -87,13 +150,6 @@
status_t legacyReleaseAudioPatch() override;
protected:
- typedef AidlMessageQueue<::aidl::android::hardware::audio::core::StreamDescriptor::Command,
- ::aidl::android::hardware::common::fmq::SynchronizedReadWrite> CommandMQ;
- typedef AidlMessageQueue<::aidl::android::hardware::audio::core::StreamDescriptor::Reply,
- ::aidl::android::hardware::common::fmq::SynchronizedReadWrite> ReplyMQ;
- typedef AidlMessageQueue<int8_t,
- ::aidl::android::hardware::common::fmq::SynchronizedReadWrite> DataMQ;
-
template<class T>
static std::shared_ptr<::aidl::android::hardware::audio::core::IStreamCommon> getStreamCommon(
const std::shared_ptr<T>& stream);
@@ -102,7 +158,8 @@
StreamHalAidl(std::string_view className,
bool isInput,
const audio_config& config,
- const ::aidl::android::hardware::audio::core::StreamDescriptor& descriptor,
+ int32_t nominalLatency,
+ StreamContextAidl&& context,
const std::shared_ptr<::aidl::android::hardware::audio::core::IStreamCommon>& stream);
~StreamHalAidl() override;
@@ -111,17 +168,31 @@
bool requestHalThreadPriority(pid_t threadPid, pid_t threadId);
+ status_t getLatency(uint32_t *latency);
+
+ status_t getObservablePosition(int64_t *frames, int64_t *timestamp);
+
+ status_t getXruns(int32_t *frames);
+
+ status_t transfer(void *buffer, size_t bytes, size_t *transferred);
+
+ status_t pause(
+ ::aidl::android::hardware::audio::core::StreamDescriptor::Reply* reply = nullptr);
+
+ status_t resume(
+ ::aidl::android::hardware::audio::core::StreamDescriptor::Reply* reply = nullptr);
+
+ status_t drain(bool earlyNotify,
+ ::aidl::android::hardware::audio::core::StreamDescriptor::Reply* reply = nullptr);
+
+ status_t flush(
+ ::aidl::android::hardware::audio::core::StreamDescriptor::Reply* reply = nullptr);
+
+ status_t exit();
+
const bool mIsInput;
const audio_config_base_t mConfig;
- const size_t mFrameSizeBytes;
- const size_t mBufferSizeFrames;
- const std::unique_ptr<CommandMQ> mCommandMQ;
- const std::unique_ptr<ReplyMQ> mReplyMQ;
- const std::unique_ptr<DataMQ> mDataMQ;
- // mStreamPowerLog is used for audio signal power logging.
- StreamPowerLog mStreamPowerLog;
- ::aidl::android::hardware::audio::core::StreamDescriptor::State mState =
- ::aidl::android::hardware::audio::core::StreamDescriptor::State::STANDBY;
+ const StreamContextAidl mContext;
private:
static audio_config_base_t configToBase(const audio_config& config) {
@@ -131,16 +202,23 @@
result.format = config.format;
return result;
}
- static std::unique_ptr<DataMQ> maybeCreateDataMQ(
- const ::aidl::android::hardware::audio::core::StreamDescriptor& descriptor) {
- using Tag = ::aidl::android::hardware::audio::core::StreamDescriptor::AudioBuffer::Tag;
- if (descriptor.audio.getTag() == Tag::fmq) {
- return std::make_unique<DataMQ>(descriptor.audio.get<Tag::fmq>());
- }
- return nullptr;
+ ::aidl::android::hardware::audio::core::StreamDescriptor::State getState() {
+ std::lock_guard l(mLock);
+ return mLastReply.state;
}
+ status_t sendCommand(
+ const ::aidl::android::hardware::audio::core::StreamDescriptor::Command &command,
+ ::aidl::android::hardware::audio::core::StreamDescriptor::Reply* reply = nullptr,
+ bool safeFromNonWorkerThread = false);
+ status_t updateCountersIfNeeded(
+ ::aidl::android::hardware::audio::core::StreamDescriptor::Reply* reply = nullptr);
const std::shared_ptr<::aidl::android::hardware::audio::core::IStreamCommon> mStream;
+ std::mutex mLock;
+ ::aidl::android::hardware::audio::core::StreamDescriptor::Reply mLastReply GUARDED_BY(mLock);
+ // mStreamPowerLog is used for audio signal power logging.
+ StreamPowerLog mStreamPowerLog;
+ std::atomic<pid_t> mWorkerTid = -1;
};
class StreamOutHalAidl : public StreamOutHalInterface, public StreamHalAidl {
@@ -239,8 +317,7 @@
// Can not be constructed directly by clients.
StreamOutHalAidl(
- const audio_config& config,
- const ::aidl::android::hardware::audio::core::StreamDescriptor& descriptor,
+ const audio_config& config, StreamContextAidl&& context, int32_t nominalLatency,
const std::shared_ptr<::aidl::android::hardware::audio::core::IStreamOut>& stream);
~StreamOutHalAidl() override = default;
@@ -281,8 +358,7 @@
// Can not be constructed directly by clients.
StreamInHalAidl(
- const audio_config& config,
- const ::aidl::android::hardware::audio::core::StreamDescriptor& descriptor,
+ const audio_config& config, StreamContextAidl&& context, int32_t nominalLatency,
const std::shared_ptr<::aidl::android::hardware::audio::core::IStreamIn>& stream);
~StreamInHalAidl() override = default;