mirror of
https://github.com/Evolution-X/hardware_interfaces
synced 2026-02-02 02:42:35 +00:00
Merge changes I97fd41f8,Iab3c970b am: 98319e92a6 am: 1db5a61aed
Original change: https://android-review.googlesource.com/c/platform/hardware/interfaces/+/2381017 Change-Id: I838fc9641e554fb905d1331a9cc83d829840feca Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -69,6 +69,7 @@ cc_library_static {
|
||||
"Module.cpp",
|
||||
"SoundDose.cpp",
|
||||
"Stream.cpp",
|
||||
"StreamStub.cpp",
|
||||
"Telephony.cpp",
|
||||
],
|
||||
generated_sources: [
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "core-impl/Bluetooth.h"
|
||||
#include "core-impl/Module.h"
|
||||
#include "core-impl/SoundDose.h"
|
||||
#include "core-impl/StreamStub.h"
|
||||
#include "core-impl/Telephony.h"
|
||||
#include "core-impl/utils.h"
|
||||
|
||||
@@ -102,9 +103,10 @@ void Module::cleanUpPatch(int32_t patchId) {
|
||||
erase_all_values(mPatches, std::set<int32_t>{patchId});
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Module::createStreamContext(int32_t in_portConfigId, int64_t in_bufferSizeFrames,
|
||||
std::shared_ptr<IStreamCallback> asyncCallback,
|
||||
StreamContext* out_context) {
|
||||
ndk::ScopedAStatus Module::createStreamContext(
|
||||
int32_t in_portConfigId, int64_t in_bufferSizeFrames,
|
||||
std::shared_ptr<IStreamCallback> asyncCallback,
|
||||
std::shared_ptr<IStreamOutEventCallback> outEventCallback, StreamContext* out_context) {
|
||||
if (in_bufferSizeFrames <= 0) {
|
||||
LOG(ERROR) << __func__ << ": non-positive buffer size " << in_bufferSizeFrames;
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
|
||||
@@ -147,7 +149,7 @@ ndk::ScopedAStatus Module::createStreamContext(int32_t in_portConfigId, int64_t
|
||||
std::make_unique<StreamContext::ReplyMQ>(1, true /*configureEventFlagWord*/),
|
||||
portConfigIt->format.value(), portConfigIt->channelMask.value(),
|
||||
std::make_unique<StreamContext::DataMQ>(frameSize * in_bufferSizeFrames),
|
||||
asyncCallback, params);
|
||||
asyncCallback, outEventCallback, params);
|
||||
if (temp.isValid()) {
|
||||
*out_context = std::move(temp);
|
||||
} else {
|
||||
@@ -545,14 +547,15 @@ ndk::ScopedAStatus Module::openInputStream(const OpenInputStreamArguments& in_ar
|
||||
}
|
||||
StreamContext context;
|
||||
if (auto status = createStreamContext(in_args.portConfigId, in_args.bufferSizeFrames, nullptr,
|
||||
&context);
|
||||
nullptr, &context);
|
||||
!status.isOk()) {
|
||||
return status;
|
||||
}
|
||||
context.fillDescriptor(&_aidl_return->desc);
|
||||
std::shared_ptr<StreamIn> stream;
|
||||
if (auto status = StreamIn::createInstance(in_args.sinkMetadata, std::move(context),
|
||||
mConfig->microphones, &stream);
|
||||
// TODO: Add a mapping from module instance names to a corresponding 'createInstance'.
|
||||
if (auto status = StreamInStub::createInstance(in_args.sinkMetadata, std::move(context),
|
||||
mConfig->microphones, &stream);
|
||||
!status.isOk()) {
|
||||
return status;
|
||||
}
|
||||
@@ -598,14 +601,16 @@ ndk::ScopedAStatus Module::openOutputStream(const OpenOutputStreamArguments& in_
|
||||
}
|
||||
StreamContext context;
|
||||
if (auto status = createStreamContext(in_args.portConfigId, in_args.bufferSizeFrames,
|
||||
isNonBlocking ? in_args.callback : nullptr, &context);
|
||||
isNonBlocking ? in_args.callback : nullptr,
|
||||
in_args.eventCallback, &context);
|
||||
!status.isOk()) {
|
||||
return status;
|
||||
}
|
||||
context.fillDescriptor(&_aidl_return->desc);
|
||||
std::shared_ptr<StreamOut> stream;
|
||||
if (auto status = StreamOut::createInstance(in_args.sourceMetadata, std::move(context),
|
||||
in_args.offloadInfo, &stream);
|
||||
// TODO: Add a mapping from module instance names to a corresponding 'createInstance'.
|
||||
if (auto status = StreamOutStub::createInstance(in_args.sourceMetadata, std::move(context),
|
||||
in_args.offloadInfo, &stream);
|
||||
!status.isOk()) {
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -85,16 +85,19 @@ std::string StreamWorkerCommonLogic::init() {
|
||||
if (mCommandMQ == nullptr) return "Command MQ is null";
|
||||
if (mReplyMQ == nullptr) return "Reply MQ is null";
|
||||
if (mDataMQ == nullptr) return "Data MQ is null";
|
||||
if (sizeof(decltype(mDataBuffer)::element_type) != mDataMQ->getQuantumSize()) {
|
||||
if (sizeof(DataBufferElement) != mDataMQ->getQuantumSize()) {
|
||||
return "Unexpected Data MQ quantum size: " + std::to_string(mDataMQ->getQuantumSize());
|
||||
}
|
||||
mDataBufferSize = mDataMQ->getQuantumCount() * mDataMQ->getQuantumSize();
|
||||
mDataBuffer.reset(new (std::nothrow) int8_t[mDataBufferSize]);
|
||||
mDataBuffer.reset(new (std::nothrow) DataBufferElement[mDataBufferSize]);
|
||||
if (mDataBuffer == nullptr) {
|
||||
return "Failed to allocate data buffer for element count " +
|
||||
std::to_string(mDataMQ->getQuantumCount()) +
|
||||
", size in bytes: " + std::to_string(mDataBufferSize);
|
||||
}
|
||||
if (::android::status_t status = mDriver->init(); status != STATUS_OK) {
|
||||
return "Failed to initialize the driver: " + std::to_string(status);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
@@ -191,46 +194,59 @@ StreamInWorkerLogic::Status StreamInWorkerLogic::cycle() {
|
||||
}
|
||||
break;
|
||||
case Tag::drain:
|
||||
if (command.get<Tag::drain>() == StreamDescriptor::DrainMode::DRAIN_UNSPECIFIED) {
|
||||
if (const auto mode = command.get<Tag::drain>();
|
||||
mode == StreamDescriptor::DrainMode::DRAIN_UNSPECIFIED) {
|
||||
if (mState == StreamDescriptor::State::ACTIVE) {
|
||||
usleep(1000); // Simulate a blocking call into the driver.
|
||||
populateReply(&reply, mIsConnected);
|
||||
// Can switch the state to ERROR if a driver error occurs.
|
||||
mState = StreamDescriptor::State::DRAINING;
|
||||
if (::android::status_t status = mDriver->drain(mode);
|
||||
status == ::android::OK) {
|
||||
populateReply(&reply, mIsConnected);
|
||||
mState = StreamDescriptor::State::DRAINING;
|
||||
} else {
|
||||
LOG(ERROR) << __func__ << ": drain failed: " << status;
|
||||
mState = StreamDescriptor::State::ERROR;
|
||||
}
|
||||
} else {
|
||||
populateReplyWrongState(&reply, command);
|
||||
}
|
||||
} else {
|
||||
LOG(WARNING) << __func__
|
||||
<< ": invalid drain mode: " << toString(command.get<Tag::drain>());
|
||||
LOG(WARNING) << __func__ << ": invalid drain mode: " << toString(mode);
|
||||
}
|
||||
break;
|
||||
case Tag::standby:
|
||||
if (mState == StreamDescriptor::State::IDLE) {
|
||||
usleep(1000); // Simulate a blocking call into the driver.
|
||||
populateReply(&reply, mIsConnected);
|
||||
// Can switch the state to ERROR if a driver error occurs.
|
||||
mState = StreamDescriptor::State::STANDBY;
|
||||
if (::android::status_t status = mDriver->standby(); status == ::android::OK) {
|
||||
populateReply(&reply, mIsConnected);
|
||||
mState = StreamDescriptor::State::STANDBY;
|
||||
} else {
|
||||
LOG(ERROR) << __func__ << ": standby failed: " << status;
|
||||
mState = StreamDescriptor::State::ERROR;
|
||||
}
|
||||
} else {
|
||||
populateReplyWrongState(&reply, command);
|
||||
}
|
||||
break;
|
||||
case Tag::pause:
|
||||
if (mState == StreamDescriptor::State::ACTIVE) {
|
||||
usleep(1000); // Simulate a blocking call into the driver.
|
||||
populateReply(&reply, mIsConnected);
|
||||
// Can switch the state to ERROR if a driver error occurs.
|
||||
mState = StreamDescriptor::State::PAUSED;
|
||||
if (::android::status_t status = mDriver->pause(); status == ::android::OK) {
|
||||
populateReply(&reply, mIsConnected);
|
||||
mState = StreamDescriptor::State::PAUSED;
|
||||
} else {
|
||||
LOG(ERROR) << __func__ << ": pause failed: " << status;
|
||||
mState = StreamDescriptor::State::ERROR;
|
||||
}
|
||||
} else {
|
||||
populateReplyWrongState(&reply, command);
|
||||
}
|
||||
break;
|
||||
case Tag::flush:
|
||||
if (mState == StreamDescriptor::State::PAUSED) {
|
||||
usleep(1000); // Simulate a blocking call into the driver.
|
||||
populateReply(&reply, mIsConnected);
|
||||
// Can switch the state to ERROR if a driver error occurs.
|
||||
mState = StreamDescriptor::State::STANDBY;
|
||||
if (::android::status_t status = mDriver->flush(); status == ::android::OK) {
|
||||
populateReply(&reply, mIsConnected);
|
||||
mState = StreamDescriptor::State::STANDBY;
|
||||
} else {
|
||||
LOG(ERROR) << __func__ << ": flush failed: " << status;
|
||||
mState = StreamDescriptor::State::ERROR;
|
||||
}
|
||||
} else {
|
||||
populateReplyWrongState(&reply, command);
|
||||
}
|
||||
@@ -247,33 +263,39 @@ StreamInWorkerLogic::Status StreamInWorkerLogic::cycle() {
|
||||
}
|
||||
|
||||
bool StreamInWorkerLogic::read(size_t clientSize, StreamDescriptor::Reply* reply) {
|
||||
// Can switch the state to ERROR if a driver error occurs.
|
||||
const size_t byteCount = std::min({clientSize, mDataMQ->availableToWrite(), mDataBufferSize});
|
||||
const bool isConnected = mIsConnected;
|
||||
size_t actualFrameCount = 0;
|
||||
bool fatal = false;
|
||||
// Simulate reading of data, or provide zeroes if the stream is not connected.
|
||||
for (size_t i = 0; i < byteCount; ++i) {
|
||||
using buffer_type = decltype(mDataBuffer)::element_type;
|
||||
constexpr int kBufferValueRange = std::numeric_limits<buffer_type>::max() -
|
||||
std::numeric_limits<buffer_type>::min() + 1;
|
||||
mDataBuffer[i] = isConnected ? (std::rand() % kBufferValueRange) +
|
||||
std::numeric_limits<buffer_type>::min()
|
||||
: 0;
|
||||
int32_t latency = Module::kLatencyMs;
|
||||
if (isConnected) {
|
||||
if (::android::status_t status = mDriver->transfer(
|
||||
mDataBuffer.get(), byteCount / mFrameSize, &actualFrameCount, &latency);
|
||||
status != ::android::OK) {
|
||||
fatal = true;
|
||||
LOG(ERROR) << __func__ << ": read failed: " << status;
|
||||
}
|
||||
} else {
|
||||
usleep(3000); // Simulate blocking transfer delay.
|
||||
for (size_t i = 0; i < byteCount; ++i) mDataBuffer[i] = 0;
|
||||
actualFrameCount = byteCount / mFrameSize;
|
||||
}
|
||||
usleep(3000); // Simulate a blocking call into the driver.
|
||||
// Set 'fatal = true' if a driver error occurs.
|
||||
if (bool success = byteCount > 0 ? mDataMQ->write(&mDataBuffer[0], byteCount) : true; success) {
|
||||
LOG(DEBUG) << __func__ << ": writing of " << byteCount << " bytes into data MQ"
|
||||
const size_t actualByteCount = actualFrameCount * mFrameSize;
|
||||
if (bool success =
|
||||
actualByteCount > 0 ? mDataMQ->write(&mDataBuffer[0], actualByteCount) : true;
|
||||
success) {
|
||||
LOG(DEBUG) << __func__ << ": writing of " << actualByteCount << " bytes into data MQ"
|
||||
<< " succeeded; connected? " << isConnected;
|
||||
// Frames are provided and counted regardless of connection status.
|
||||
reply->fmqByteCount += byteCount;
|
||||
mFrameCount += byteCount / mFrameSize;
|
||||
reply->fmqByteCount += actualByteCount;
|
||||
mFrameCount += actualFrameCount;
|
||||
populateReply(reply, isConnected);
|
||||
} else {
|
||||
LOG(WARNING) << __func__ << ": writing of " << byteCount << " bytes of data to MQ failed";
|
||||
LOG(WARNING) << __func__ << ": writing of " << actualByteCount
|
||||
<< " bytes of data to MQ failed";
|
||||
reply->status = STATUS_NOT_ENOUGH_DATA;
|
||||
}
|
||||
reply->latencyMs = Module::kLatencyMs;
|
||||
reply->latencyMs = latency;
|
||||
return !fatal;
|
||||
}
|
||||
|
||||
@@ -395,17 +417,22 @@ StreamOutWorkerLogic::Status StreamOutWorkerLogic::cycle() {
|
||||
}
|
||||
break;
|
||||
case Tag::drain:
|
||||
if (command.get<Tag::drain>() == StreamDescriptor::DrainMode::DRAIN_ALL ||
|
||||
command.get<Tag::drain>() == StreamDescriptor::DrainMode::DRAIN_EARLY_NOTIFY) {
|
||||
if (const auto mode = command.get<Tag::drain>();
|
||||
mode == StreamDescriptor::DrainMode::DRAIN_ALL ||
|
||||
mode == StreamDescriptor::DrainMode::DRAIN_EARLY_NOTIFY) {
|
||||
if (mState == StreamDescriptor::State::ACTIVE ||
|
||||
mState == StreamDescriptor::State::TRANSFERRING) {
|
||||
usleep(1000); // Simulate a blocking call into the driver.
|
||||
populateReply(&reply, mIsConnected);
|
||||
// Can switch the state to ERROR if a driver error occurs.
|
||||
if (mState == StreamDescriptor::State::ACTIVE && mForceSynchronousDrain) {
|
||||
mState = StreamDescriptor::State::IDLE;
|
||||
if (::android::status_t status = mDriver->drain(mode);
|
||||
status == ::android::OK) {
|
||||
populateReply(&reply, mIsConnected);
|
||||
if (mState == StreamDescriptor::State::ACTIVE && mForceSynchronousDrain) {
|
||||
mState = StreamDescriptor::State::IDLE;
|
||||
} else {
|
||||
switchToTransientState(StreamDescriptor::State::DRAINING);
|
||||
}
|
||||
} else {
|
||||
switchToTransientState(StreamDescriptor::State::DRAINING);
|
||||
LOG(ERROR) << __func__ << ": drain failed: " << status;
|
||||
mState = StreamDescriptor::State::ERROR;
|
||||
}
|
||||
} else if (mState == StreamDescriptor::State::TRANSFER_PAUSED) {
|
||||
mState = StreamDescriptor::State::DRAIN_PAUSED;
|
||||
@@ -414,46 +441,58 @@ StreamOutWorkerLogic::Status StreamOutWorkerLogic::cycle() {
|
||||
populateReplyWrongState(&reply, command);
|
||||
}
|
||||
} else {
|
||||
LOG(WARNING) << __func__
|
||||
<< ": invalid drain mode: " << toString(command.get<Tag::drain>());
|
||||
LOG(WARNING) << __func__ << ": invalid drain mode: " << toString(mode);
|
||||
}
|
||||
break;
|
||||
case Tag::standby:
|
||||
if (mState == StreamDescriptor::State::IDLE) {
|
||||
usleep(1000); // Simulate a blocking call into the driver.
|
||||
populateReply(&reply, mIsConnected);
|
||||
// Can switch the state to ERROR if a driver error occurs.
|
||||
mState = StreamDescriptor::State::STANDBY;
|
||||
if (::android::status_t status = mDriver->standby(); status == ::android::OK) {
|
||||
populateReply(&reply, mIsConnected);
|
||||
mState = StreamDescriptor::State::STANDBY;
|
||||
} else {
|
||||
LOG(ERROR) << __func__ << ": standby failed: " << status;
|
||||
mState = StreamDescriptor::State::ERROR;
|
||||
}
|
||||
} else {
|
||||
populateReplyWrongState(&reply, command);
|
||||
}
|
||||
break;
|
||||
case Tag::pause: {
|
||||
bool commandAccepted = true;
|
||||
std::optional<StreamDescriptor::State> nextState;
|
||||
switch (mState) {
|
||||
case StreamDescriptor::State::ACTIVE:
|
||||
mState = StreamDescriptor::State::PAUSED;
|
||||
nextState = StreamDescriptor::State::PAUSED;
|
||||
break;
|
||||
case StreamDescriptor::State::DRAINING:
|
||||
mState = StreamDescriptor::State::DRAIN_PAUSED;
|
||||
nextState = StreamDescriptor::State::DRAIN_PAUSED;
|
||||
break;
|
||||
case StreamDescriptor::State::TRANSFERRING:
|
||||
mState = StreamDescriptor::State::TRANSFER_PAUSED;
|
||||
nextState = StreamDescriptor::State::TRANSFER_PAUSED;
|
||||
break;
|
||||
default:
|
||||
populateReplyWrongState(&reply, command);
|
||||
commandAccepted = false;
|
||||
}
|
||||
if (commandAccepted) {
|
||||
populateReply(&reply, mIsConnected);
|
||||
if (nextState.has_value()) {
|
||||
if (::android::status_t status = mDriver->pause(); status == ::android::OK) {
|
||||
populateReply(&reply, mIsConnected);
|
||||
mState = nextState.value();
|
||||
} else {
|
||||
LOG(ERROR) << __func__ << ": pause failed: " << status;
|
||||
mState = StreamDescriptor::State::ERROR;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case Tag::flush:
|
||||
if (mState == StreamDescriptor::State::PAUSED ||
|
||||
mState == StreamDescriptor::State::DRAIN_PAUSED ||
|
||||
mState == StreamDescriptor::State::TRANSFER_PAUSED) {
|
||||
populateReply(&reply, mIsConnected);
|
||||
mState = StreamDescriptor::State::IDLE;
|
||||
if (::android::status_t status = mDriver->flush(); status == ::android::OK) {
|
||||
populateReply(&reply, mIsConnected);
|
||||
mState = StreamDescriptor::State::IDLE;
|
||||
} else {
|
||||
LOG(ERROR) << __func__ << ": flush failed: " << status;
|
||||
mState = StreamDescriptor::State::ERROR;
|
||||
}
|
||||
} else {
|
||||
populateReplyWrongState(&reply, command);
|
||||
}
|
||||
@@ -472,6 +511,7 @@ StreamOutWorkerLogic::Status StreamOutWorkerLogic::cycle() {
|
||||
bool StreamOutWorkerLogic::write(size_t clientSize, StreamDescriptor::Reply* reply) {
|
||||
const size_t readByteCount = mDataMQ->availableToRead();
|
||||
bool fatal = false;
|
||||
int32_t latency = Module::kLatencyMs;
|
||||
if (bool success = readByteCount > 0 ? mDataMQ->read(&mDataBuffer[0], readByteCount) : true) {
|
||||
const bool isConnected = mIsConnected;
|
||||
LOG(DEBUG) << __func__ << ": reading of " << readByteCount << " bytes from data MQ"
|
||||
@@ -483,23 +523,36 @@ bool StreamOutWorkerLogic::write(size_t clientSize, StreamDescriptor::Reply* rep
|
||||
// simulate partial write.
|
||||
byteCount -= mFrameSize;
|
||||
}
|
||||
size_t actualFrameCount = 0;
|
||||
if (isConnected) {
|
||||
if (::android::status_t status = mDriver->transfer(
|
||||
mDataBuffer.get(), byteCount / mFrameSize, &actualFrameCount, &latency);
|
||||
status != ::android::OK) {
|
||||
fatal = true;
|
||||
LOG(ERROR) << __func__ << ": write failed: " << status;
|
||||
}
|
||||
} else {
|
||||
if (mAsyncCallback == nullptr) {
|
||||
usleep(3000); // Simulate blocking transfer delay.
|
||||
}
|
||||
actualFrameCount = byteCount / mFrameSize;
|
||||
}
|
||||
const size_t actualByteCount = actualFrameCount * mFrameSize;
|
||||
// Frames are consumed and counted regardless of the connection status.
|
||||
reply->fmqByteCount += byteCount;
|
||||
mFrameCount += byteCount / mFrameSize;
|
||||
reply->fmqByteCount += actualByteCount;
|
||||
mFrameCount += actualFrameCount;
|
||||
populateReply(reply, isConnected);
|
||||
usleep(3000); // Simulate a blocking call into the driver.
|
||||
// Set 'fatal = true' if a driver error occurs.
|
||||
} else {
|
||||
LOG(WARNING) << __func__ << ": reading of " << readByteCount
|
||||
<< " bytes of data from MQ failed";
|
||||
reply->status = STATUS_NOT_ENOUGH_DATA;
|
||||
}
|
||||
reply->latencyMs = Module::kLatencyMs;
|
||||
reply->latencyMs = latency;
|
||||
return !fatal;
|
||||
}
|
||||
|
||||
template <class Metadata, class StreamWorker>
|
||||
StreamCommonImpl<Metadata, StreamWorker>::~StreamCommonImpl() {
|
||||
template <class Metadata>
|
||||
StreamCommonImpl<Metadata>::~StreamCommonImpl() {
|
||||
if (!isClosed()) {
|
||||
LOG(ERROR) << __func__ << ": stream was not closed prior to destruction, resource leak";
|
||||
stopWorker();
|
||||
@@ -507,8 +560,8 @@ StreamCommonImpl<Metadata, StreamWorker>::~StreamCommonImpl() {
|
||||
}
|
||||
}
|
||||
|
||||
template <class Metadata, class StreamWorker>
|
||||
void StreamCommonImpl<Metadata, StreamWorker>::createStreamCommon(
|
||||
template <class Metadata>
|
||||
void StreamCommonImpl<Metadata>::createStreamCommon(
|
||||
const std::shared_ptr<StreamCommonInterface>& delegate) {
|
||||
if (mCommon != nullptr) {
|
||||
LOG(FATAL) << __func__ << ": attempting to create the common interface twice";
|
||||
@@ -518,8 +571,8 @@ void StreamCommonImpl<Metadata, StreamWorker>::createStreamCommon(
|
||||
AIBinder_setMinSchedulerPolicy(mCommonBinder.get(), SCHED_NORMAL, ANDROID_PRIORITY_AUDIO);
|
||||
}
|
||||
|
||||
template <class Metadata, class StreamWorker>
|
||||
ndk::ScopedAStatus StreamCommonImpl<Metadata, StreamWorker>::getStreamCommon(
|
||||
template <class Metadata>
|
||||
ndk::ScopedAStatus StreamCommonImpl<Metadata>::getStreamCommon(
|
||||
std::shared_ptr<IStreamCommon>* _aidl_return) {
|
||||
if (mCommon == nullptr) {
|
||||
LOG(FATAL) << __func__ << ": the common interface was not created";
|
||||
@@ -529,31 +582,30 @@ ndk::ScopedAStatus StreamCommonImpl<Metadata, StreamWorker>::getStreamCommon(
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
template <class Metadata, class StreamWorker>
|
||||
ndk::ScopedAStatus StreamCommonImpl<Metadata, StreamWorker>::updateHwAvSyncId(
|
||||
int32_t in_hwAvSyncId) {
|
||||
template <class Metadata>
|
||||
ndk::ScopedAStatus StreamCommonImpl<Metadata>::updateHwAvSyncId(int32_t in_hwAvSyncId) {
|
||||
LOG(DEBUG) << __func__ << ": id " << in_hwAvSyncId;
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
|
||||
}
|
||||
|
||||
template <class Metadata, class StreamWorker>
|
||||
ndk::ScopedAStatus StreamCommonImpl<Metadata, StreamWorker>::getVendorParameters(
|
||||
template <class Metadata>
|
||||
ndk::ScopedAStatus StreamCommonImpl<Metadata>::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, class StreamWorker>
|
||||
ndk::ScopedAStatus StreamCommonImpl<Metadata, StreamWorker>::setVendorParameters(
|
||||
template <class Metadata>
|
||||
ndk::ScopedAStatus StreamCommonImpl<Metadata>::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, class StreamWorker>
|
||||
ndk::ScopedAStatus StreamCommonImpl<Metadata, StreamWorker>::addEffect(
|
||||
template <class Metadata>
|
||||
ndk::ScopedAStatus StreamCommonImpl<Metadata>::addEffect(
|
||||
const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect) {
|
||||
if (in_effect == nullptr) {
|
||||
LOG(DEBUG) << __func__ << ": null effect";
|
||||
@@ -563,8 +615,8 @@ ndk::ScopedAStatus StreamCommonImpl<Metadata, StreamWorker>::addEffect(
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
|
||||
}
|
||||
|
||||
template <class Metadata, class StreamWorker>
|
||||
ndk::ScopedAStatus StreamCommonImpl<Metadata, StreamWorker>::removeEffect(
|
||||
template <class Metadata>
|
||||
ndk::ScopedAStatus StreamCommonImpl<Metadata>::removeEffect(
|
||||
const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect) {
|
||||
if (in_effect == nullptr) {
|
||||
LOG(DEBUG) << __func__ << ": null effect";
|
||||
@@ -574,16 +626,16 @@ ndk::ScopedAStatus StreamCommonImpl<Metadata, StreamWorker>::removeEffect(
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
|
||||
}
|
||||
|
||||
template <class Metadata, class StreamWorker>
|
||||
ndk::ScopedAStatus StreamCommonImpl<Metadata, StreamWorker>::close() {
|
||||
template <class Metadata>
|
||||
ndk::ScopedAStatus StreamCommonImpl<Metadata>::close() {
|
||||
LOG(DEBUG) << __func__;
|
||||
if (!isClosed()) {
|
||||
stopWorker();
|
||||
LOG(DEBUG) << __func__ << ": joining the worker thread...";
|
||||
mWorker.stop();
|
||||
mWorker->stop();
|
||||
LOG(DEBUG) << __func__ << ": worker thread joined";
|
||||
mContext.reset();
|
||||
mWorker.setClosed();
|
||||
mWorker->setClosed();
|
||||
return ndk::ScopedAStatus::ok();
|
||||
} else {
|
||||
LOG(ERROR) << __func__ << ": stream was already closed";
|
||||
@@ -591,8 +643,8 @@ ndk::ScopedAStatus StreamCommonImpl<Metadata, StreamWorker>::close() {
|
||||
}
|
||||
}
|
||||
|
||||
template <class Metadata, class StreamWorker>
|
||||
void StreamCommonImpl<Metadata, StreamWorker>::stopWorker() {
|
||||
template <class Metadata>
|
||||
void StreamCommonImpl<Metadata>::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>(
|
||||
@@ -608,9 +660,8 @@ void StreamCommonImpl<Metadata, StreamWorker>::stopWorker() {
|
||||
}
|
||||
}
|
||||
|
||||
template <class Metadata, class StreamWorker>
|
||||
ndk::ScopedAStatus StreamCommonImpl<Metadata, StreamWorker>::updateMetadata(
|
||||
const Metadata& metadata) {
|
||||
template <class Metadata>
|
||||
ndk::ScopedAStatus StreamCommonImpl<Metadata>::updateMetadata(const Metadata& metadata) {
|
||||
LOG(DEBUG) << __func__;
|
||||
if (!isClosed()) {
|
||||
mMetadata = metadata;
|
||||
@@ -621,16 +672,11 @@ ndk::ScopedAStatus StreamCommonImpl<Metadata, StreamWorker>::updateMetadata(
|
||||
}
|
||||
|
||||
// static
|
||||
ndk::ScopedAStatus StreamIn::createInstance(const common::SinkMetadata& sinkMetadata,
|
||||
StreamContext context,
|
||||
const std::vector<MicrophoneInfo>& microphones,
|
||||
std::shared_ptr<StreamIn>* result) {
|
||||
auto stream = ndk::SharedRefBase::make<StreamIn>(sinkMetadata, std::move(context), microphones);
|
||||
ndk::ScopedAStatus StreamIn::initInstance(const std::shared_ptr<StreamIn>& stream) {
|
||||
if (auto status = stream->init(); !status.isOk()) {
|
||||
return status;
|
||||
}
|
||||
stream->createStreamCommon(stream);
|
||||
*result = std::move(stream);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
@@ -645,8 +691,10 @@ 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, StreamInWorker>(sinkMetadata, std::move(context)),
|
||||
: StreamCommonImpl<SinkMetadata>(sinkMetadata, std::move(context), createDriver, createWorker),
|
||||
mMicrophones(transformMicrophones(microphones)) {
|
||||
LOG(DEBUG) << __func__;
|
||||
}
|
||||
@@ -704,23 +752,20 @@ ndk::ScopedAStatus StreamIn::setHwGain(const std::vector<float>& in_channelGains
|
||||
}
|
||||
|
||||
// static
|
||||
ndk::ScopedAStatus StreamOut::createInstance(const SourceMetadata& sourceMetadata,
|
||||
StreamContext context,
|
||||
const std::optional<AudioOffloadInfo>& offloadInfo,
|
||||
std::shared_ptr<StreamOut>* result) {
|
||||
auto stream =
|
||||
ndk::SharedRefBase::make<StreamOut>(sourceMetadata, std::move(context), offloadInfo);
|
||||
ndk::ScopedAStatus StreamOut::initInstance(const std::shared_ptr<StreamOut>& stream) {
|
||||
if (auto status = stream->init(); !status.isOk()) {
|
||||
return status;
|
||||
}
|
||||
stream->createStreamCommon(stream);
|
||||
*result = std::move(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, StreamOutWorker>(sourceMetadata, std::move(context)),
|
||||
: StreamCommonImpl<SourceMetadata>(sourceMetadata, std::move(context), createDriver,
|
||||
createWorker),
|
||||
mOffloadInfo(offloadInfo) {
|
||||
LOG(DEBUG) << __func__;
|
||||
}
|
||||
|
||||
125
audio/aidl/default/StreamStub.cpp
Normal file
125
audio/aidl/default/StreamStub.cpp
Normal file
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.
|
||||
*/
|
||||
|
||||
#define LOG_TAG "AHAL_Stream"
|
||||
#include <android-base/logging.h>
|
||||
|
||||
#include "core-impl/Module.h"
|
||||
#include "core-impl/StreamStub.h"
|
||||
|
||||
using aidl::android::hardware::audio::common::SinkMetadata;
|
||||
using aidl::android::hardware::audio::common::SourceMetadata;
|
||||
using aidl::android::media::audio::common::AudioOffloadInfo;
|
||||
|
||||
namespace aidl::android::hardware::audio::core {
|
||||
|
||||
DriverStub::DriverStub(const StreamContext& context, bool isInput)
|
||||
: mFrameSizeBytes(context.getFrameSize()), mIsInput(isInput) {}
|
||||
|
||||
::android::status_t DriverStub::init() {
|
||||
usleep(1000);
|
||||
return ::android::OK;
|
||||
}
|
||||
|
||||
::android::status_t DriverStub::drain(StreamDescriptor::DrainMode) {
|
||||
usleep(1000);
|
||||
return ::android::OK;
|
||||
}
|
||||
|
||||
::android::status_t DriverStub::flush() {
|
||||
usleep(1000);
|
||||
return ::android::OK;
|
||||
}
|
||||
|
||||
::android::status_t DriverStub::pause() {
|
||||
usleep(1000);
|
||||
return ::android::OK;
|
||||
}
|
||||
|
||||
::android::status_t DriverStub::transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
|
||||
int32_t* latencyMs) {
|
||||
usleep(3000);
|
||||
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;
|
||||
*latencyMs = Module::kLatencyMs;
|
||||
return ::android::OK;
|
||||
}
|
||||
|
||||
::android::status_t DriverStub::standby() {
|
||||
usleep(1000);
|
||||
return ::android::OK;
|
||||
}
|
||||
|
||||
// static
|
||||
ndk::ScopedAStatus StreamInStub::createInstance(const SinkMetadata& sinkMetadata,
|
||||
StreamContext&& context,
|
||||
const std::vector<MicrophoneInfo>& microphones,
|
||||
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()) {
|
||||
return status;
|
||||
}
|
||||
*result = std::move(stream);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
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) {}
|
||||
|
||||
// static
|
||||
ndk::ScopedAStatus StreamOutStub::createInstance(const SourceMetadata& sourceMetadata,
|
||||
StreamContext&& context,
|
||||
const std::optional<AudioOffloadInfo>& offloadInfo,
|
||||
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()) {
|
||||
return status;
|
||||
}
|
||||
*result = std::move(stream);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
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) {}
|
||||
|
||||
} // namespace aidl::android::hardware::audio::core
|
||||
@@ -115,6 +115,7 @@ class Module : public BnModule {
|
||||
ndk::ScopedAStatus createStreamContext(
|
||||
int32_t in_portConfigId, int64_t in_bufferSizeFrames,
|
||||
std::shared_ptr<IStreamCallback> asyncCallback,
|
||||
std::shared_ptr<IStreamOutEventCallback> outEventCallback,
|
||||
::aidl::android::hardware::audio::core::StreamContext* out_context);
|
||||
std::vector<::aidl::android::media::audio::common::AudioDevice> findConnectedDevices(
|
||||
int32_t portConfigId);
|
||||
|
||||
@@ -31,12 +31,14 @@
|
||||
#include <aidl/android/hardware/audio/core/BnStreamIn.h>
|
||||
#include <aidl/android/hardware/audio/core/BnStreamOut.h>
|
||||
#include <aidl/android/hardware/audio/core/IStreamCallback.h>
|
||||
#include <aidl/android/hardware/audio/core/IStreamOutEventCallback.h>
|
||||
#include <aidl/android/hardware/audio/core/MicrophoneInfo.h>
|
||||
#include <aidl/android/hardware/audio/core/StreamDescriptor.h>
|
||||
#include <aidl/android/media/audio/common/AudioDevice.h>
|
||||
#include <aidl/android/media/audio/common/AudioOffloadInfo.h>
|
||||
#include <fmq/AidlMessageQueue.h>
|
||||
#include <system/thread_defs.h>
|
||||
#include <utils/Errors.h>
|
||||
|
||||
#include "core-impl/utils.h"
|
||||
|
||||
@@ -76,6 +78,7 @@ class StreamContext {
|
||||
const ::aidl::android::media::audio::common::AudioFormatDescription& format,
|
||||
const ::aidl::android::media::audio::common::AudioChannelLayout& channelLayout,
|
||||
std::unique_ptr<DataMQ> dataMQ, std::shared_ptr<IStreamCallback> asyncCallback,
|
||||
std::shared_ptr<IStreamOutEventCallback> outEventCallback,
|
||||
DebugParameters debugParameters)
|
||||
: mCommandMQ(std::move(commandMQ)),
|
||||
mInternalCommandCookie(std::rand()),
|
||||
@@ -84,6 +87,7 @@ class StreamContext {
|
||||
mChannelLayout(channelLayout),
|
||||
mDataMQ(std::move(dataMQ)),
|
||||
mAsyncCallback(asyncCallback),
|
||||
mOutEventCallback(outEventCallback),
|
||||
mDebugParameters(debugParameters) {}
|
||||
StreamContext(StreamContext&& other)
|
||||
: mCommandMQ(std::move(other.mCommandMQ)),
|
||||
@@ -93,6 +97,7 @@ class StreamContext {
|
||||
mChannelLayout(other.mChannelLayout),
|
||||
mDataMQ(std::move(other.mDataMQ)),
|
||||
mAsyncCallback(std::move(other.mAsyncCallback)),
|
||||
mOutEventCallback(std::move(other.mOutEventCallback)),
|
||||
mDebugParameters(std::move(other.mDebugParameters)) {}
|
||||
StreamContext& operator=(StreamContext&& other) {
|
||||
mCommandMQ = std::move(other.mCommandMQ);
|
||||
@@ -102,6 +107,7 @@ class StreamContext {
|
||||
mChannelLayout = std::move(other.mChannelLayout);
|
||||
mDataMQ = std::move(other.mDataMQ);
|
||||
mAsyncCallback = std::move(other.mAsyncCallback);
|
||||
mOutEventCallback = std::move(other.mOutEventCallback);
|
||||
mDebugParameters = std::move(other.mDebugParameters);
|
||||
return *this;
|
||||
}
|
||||
@@ -120,6 +126,9 @@ class StreamContext {
|
||||
bool getForceSynchronousDrain() const { return mDebugParameters.forceSynchronousDrain; }
|
||||
size_t getFrameSize() const;
|
||||
int getInternalCommandCookie() const { return mInternalCommandCookie; }
|
||||
std::shared_ptr<IStreamOutEventCallback> getOutEventCallback() const {
|
||||
return mOutEventCallback;
|
||||
}
|
||||
ReplyMQ* getReplyMQ() const { return mReplyMQ.get(); }
|
||||
int getTransientStateDelayMs() const { return mDebugParameters.transientStateDelayMs; }
|
||||
bool isValid() const;
|
||||
@@ -133,9 +142,24 @@ class StreamContext {
|
||||
::aidl::android::media::audio::common::AudioChannelLayout mChannelLayout;
|
||||
std::unique_ptr<DataMQ> mDataMQ;
|
||||
std::shared_ptr<IStreamCallback> mAsyncCallback;
|
||||
std::shared_ptr<IStreamOutEventCallback> mOutEventCallback; // Only used by output streams
|
||||
DebugParameters mDebugParameters;
|
||||
};
|
||||
|
||||
struct DriverInterface {
|
||||
using CreateInstance = std::function<DriverInterface*(const StreamContext&)>;
|
||||
virtual ~DriverInterface() = default;
|
||||
// This function is called once, on the main thread, before starting the worker thread.
|
||||
virtual ::android::status_t init() = 0;
|
||||
// All the functions below are called on the worker thread.
|
||||
virtual ::android::status_t drain(StreamDescriptor::DrainMode mode) = 0;
|
||||
virtual ::android::status_t flush() = 0;
|
||||
virtual ::android::status_t pause() = 0;
|
||||
virtual ::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
|
||||
int32_t* latencyMs) = 0;
|
||||
virtual ::android::status_t standby() = 0;
|
||||
};
|
||||
|
||||
class StreamWorkerCommonLogic : public ::android::hardware::audio::common::StreamLogic {
|
||||
public:
|
||||
bool isClosed() const {
|
||||
@@ -145,8 +169,11 @@ class StreamWorkerCommonLogic : public ::android::hardware::audio::common::Strea
|
||||
void setIsConnected(bool connected) { mIsConnected = connected; }
|
||||
|
||||
protected:
|
||||
explicit StreamWorkerCommonLogic(const StreamContext& context)
|
||||
: mInternalCommandCookie(context.getInternalCommandCookie()),
|
||||
using DataBufferElement = int8_t;
|
||||
|
||||
StreamWorkerCommonLogic(const StreamContext& context, DriverInterface* driver)
|
||||
: mDriver(driver),
|
||||
mInternalCommandCookie(context.getInternalCommandCookie()),
|
||||
mFrameSize(context.getFrameSize()),
|
||||
mCommandMQ(context.getCommandMQ()),
|
||||
mReplyMQ(context.getReplyMQ()),
|
||||
@@ -164,6 +191,7 @@ class StreamWorkerCommonLogic : public ::android::hardware::audio::common::Strea
|
||||
mTransientStateStart = std::chrono::steady_clock::now();
|
||||
}
|
||||
|
||||
DriverInterface* const mDriver;
|
||||
// Atomic fields are used both by the main and worker threads.
|
||||
std::atomic<bool> mIsConnected = false;
|
||||
static_assert(std::atomic<StreamDescriptor::State>::is_always_lock_free);
|
||||
@@ -171,9 +199,9 @@ class StreamWorkerCommonLogic : public ::android::hardware::audio::common::Strea
|
||||
// All fields are used on the worker thread only.
|
||||
const int mInternalCommandCookie;
|
||||
const size_t mFrameSize;
|
||||
StreamContext::CommandMQ* mCommandMQ;
|
||||
StreamContext::ReplyMQ* mReplyMQ;
|
||||
StreamContext::DataMQ* mDataMQ;
|
||||
StreamContext::CommandMQ* const mCommandMQ;
|
||||
StreamContext::ReplyMQ* const mReplyMQ;
|
||||
StreamContext::DataMQ* const mDataMQ;
|
||||
std::shared_ptr<IStreamCallback> mAsyncCallback;
|
||||
const std::chrono::duration<int, std::milli> mTransientStateDelayMs;
|
||||
std::chrono::time_point<std::chrono::steady_clock> mTransientStateStart;
|
||||
@@ -181,15 +209,46 @@ class StreamWorkerCommonLogic : public ::android::hardware::audio::common::Strea
|
||||
const bool mForceSynchronousDrain;
|
||||
// We use an array and the "size" field instead of a vector to be able to detect
|
||||
// memory allocation issues.
|
||||
std::unique_ptr<int8_t[]> mDataBuffer;
|
||||
std::unique_ptr<DataBufferElement[]> mDataBuffer;
|
||||
size_t mDataBufferSize;
|
||||
long mFrameCount = 0;
|
||||
};
|
||||
|
||||
// This interface is used to decouple stream implementations from a concrete StreamWorker
|
||||
// implementation.
|
||||
struct StreamWorkerInterface {
|
||||
using CreateInstance = std::function<StreamWorkerInterface*(const StreamContext& context,
|
||||
DriverInterface* driver)>;
|
||||
virtual ~StreamWorkerInterface() = default;
|
||||
virtual bool isClosed() const = 0;
|
||||
virtual void setIsConnected(bool isConnected) = 0;
|
||||
virtual void setClosed() = 0;
|
||||
virtual bool start() = 0;
|
||||
virtual void stop() = 0;
|
||||
};
|
||||
|
||||
template <class WorkerLogic>
|
||||
class StreamWorkerImpl : public StreamWorkerInterface,
|
||||
public ::android::hardware::audio::common::StreamWorker<WorkerLogic> {
|
||||
using WorkerImpl = ::android::hardware::audio::common::StreamWorker<WorkerLogic>;
|
||||
|
||||
public:
|
||||
StreamWorkerImpl(const StreamContext& context, DriverInterface* driver)
|
||||
: WorkerImpl(context, driver) {}
|
||||
bool isClosed() const override { return WorkerImpl::isClosed(); }
|
||||
void setIsConnected(bool isConnected) override { WorkerImpl::setIsConnected(isConnected); }
|
||||
void setClosed() override { WorkerImpl::setClosed(); }
|
||||
bool start() override {
|
||||
return WorkerImpl::start(WorkerImpl::kThreadName, ANDROID_PRIORITY_AUDIO);
|
||||
}
|
||||
void stop() override { return WorkerImpl::stop(); }
|
||||
};
|
||||
|
||||
class StreamInWorkerLogic : public StreamWorkerCommonLogic {
|
||||
public:
|
||||
static const std::string kThreadName;
|
||||
explicit StreamInWorkerLogic(const StreamContext& context) : StreamWorkerCommonLogic(context) {}
|
||||
StreamInWorkerLogic(const StreamContext& context, DriverInterface* driver)
|
||||
: StreamWorkerCommonLogic(context, driver) {}
|
||||
|
||||
protected:
|
||||
Status cycle() override;
|
||||
@@ -197,21 +256,23 @@ class StreamInWorkerLogic : public StreamWorkerCommonLogic {
|
||||
private:
|
||||
bool read(size_t clientSize, StreamDescriptor::Reply* reply);
|
||||
};
|
||||
using StreamInWorker = ::android::hardware::audio::common::StreamWorker<StreamInWorkerLogic>;
|
||||
using StreamInWorker = StreamWorkerImpl<StreamInWorkerLogic>;
|
||||
|
||||
class StreamOutWorkerLogic : public StreamWorkerCommonLogic {
|
||||
public:
|
||||
static const std::string kThreadName;
|
||||
explicit StreamOutWorkerLogic(const StreamContext& context)
|
||||
: StreamWorkerCommonLogic(context) {}
|
||||
StreamOutWorkerLogic(const StreamContext& context, DriverInterface* driver)
|
||||
: StreamWorkerCommonLogic(context, driver), mEventCallback(context.getOutEventCallback()) {}
|
||||
|
||||
protected:
|
||||
Status cycle() override;
|
||||
|
||||
private:
|
||||
bool write(size_t clientSize, StreamDescriptor::Reply* reply);
|
||||
|
||||
std::shared_ptr<IStreamOutEventCallback> mEventCallback;
|
||||
};
|
||||
using StreamOutWorker = ::android::hardware::audio::common::StreamWorker<StreamOutWorkerLogic>;
|
||||
using StreamOutWorker = StreamWorkerImpl<StreamOutWorkerLogic>;
|
||||
|
||||
// This provides a C++ interface with methods of the IStreamCommon Binder interface,
|
||||
// but intentionally does not inherit from it. This is needed to avoid inheriting
|
||||
@@ -283,7 +344,7 @@ class StreamCommon : public BnStreamCommon {
|
||||
std::weak_ptr<StreamCommonInterface> mDelegate;
|
||||
};
|
||||
|
||||
template <class Metadata, class StreamWorker>
|
||||
template <class Metadata>
|
||||
class StreamCommonImpl : public StreamCommonInterface {
|
||||
public:
|
||||
ndk::ScopedAStatus close() override;
|
||||
@@ -301,21 +362,25 @@ class StreamCommonImpl : public StreamCommonInterface {
|
||||
|
||||
ndk::ScopedAStatus getStreamCommon(std::shared_ptr<IStreamCommon>* _aidl_return);
|
||||
ndk::ScopedAStatus init() {
|
||||
return mWorker.start(StreamWorker::kThreadName, ANDROID_PRIORITY_AUDIO)
|
||||
? ndk::ScopedAStatus::ok()
|
||||
: ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
return mWorker->start() ? ndk::ScopedAStatus::ok()
|
||||
: ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
}
|
||||
bool isClosed() const { return mWorker.isClosed(); }
|
||||
bool isClosed() const { return mWorker->isClosed(); }
|
||||
void setIsConnected(
|
||||
const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) {
|
||||
mWorker.setIsConnected(!devices.empty());
|
||||
mWorker->setIsConnected(!devices.empty());
|
||||
mConnectedDevices = devices;
|
||||
}
|
||||
ndk::ScopedAStatus updateMetadata(const Metadata& metadata);
|
||||
|
||||
protected:
|
||||
StreamCommonImpl(const Metadata& metadata, StreamContext&& context)
|
||||
: mMetadata(metadata), mContext(std::move(context)), mWorker(mContext) {}
|
||||
StreamCommonImpl(const Metadata& metadata, StreamContext&& context,
|
||||
const DriverInterface::CreateInstance& createDriver,
|
||||
const StreamWorkerInterface::CreateInstance& createWorker)
|
||||
: mMetadata(metadata),
|
||||
mContext(std::move(context)),
|
||||
mDriver(createDriver(mContext)),
|
||||
mWorker(createWorker(mContext, mDriver.get())) {}
|
||||
~StreamCommonImpl();
|
||||
void stopWorker();
|
||||
void createStreamCommon(const std::shared_ptr<StreamCommonInterface>& delegate);
|
||||
@@ -324,16 +389,16 @@ class StreamCommonImpl : public StreamCommonInterface {
|
||||
ndk::SpAIBinder mCommonBinder;
|
||||
Metadata mMetadata;
|
||||
StreamContext mContext;
|
||||
StreamWorker mWorker;
|
||||
std::unique_ptr<DriverInterface> mDriver;
|
||||
std::unique_ptr<StreamWorkerInterface> mWorker;
|
||||
std::vector<::aidl::android::media::audio::common::AudioDevice> mConnectedDevices;
|
||||
};
|
||||
|
||||
class StreamIn : public StreamCommonImpl<::aidl::android::hardware::audio::common::SinkMetadata,
|
||||
StreamInWorker>,
|
||||
class StreamIn : public StreamCommonImpl<::aidl::android::hardware::audio::common::SinkMetadata>,
|
||||
public BnStreamIn {
|
||||
ndk::ScopedAStatus getStreamCommon(std::shared_ptr<IStreamCommon>* _aidl_return) override {
|
||||
return StreamCommonImpl<::aidl::android::hardware::audio::common::SinkMetadata,
|
||||
StreamInWorker>::getStreamCommon(_aidl_return);
|
||||
return StreamCommonImpl<::aidl::android::hardware::audio::common::SinkMetadata>::
|
||||
getStreamCommon(_aidl_return);
|
||||
}
|
||||
ndk::ScopedAStatus getActiveMicrophones(
|
||||
std::vector<MicrophoneDynamicInfo>* _aidl_return) override;
|
||||
@@ -343,42 +408,46 @@ class StreamIn : public StreamCommonImpl<::aidl::android::hardware::audio::commo
|
||||
ndk::ScopedAStatus setMicrophoneFieldDimension(float in_zoom) override;
|
||||
ndk::ScopedAStatus updateMetadata(const ::aidl::android::hardware::audio::common::SinkMetadata&
|
||||
in_sinkMetadata) override {
|
||||
return StreamCommonImpl<::aidl::android::hardware::audio::common::SinkMetadata,
|
||||
StreamInWorker>::updateMetadata(in_sinkMetadata);
|
||||
return StreamCommonImpl<::aidl::android::hardware::audio::common::SinkMetadata>::
|
||||
updateMetadata(in_sinkMetadata);
|
||||
}
|
||||
ndk::ScopedAStatus getHwGain(std::vector<float>* _aidl_return) override;
|
||||
ndk::ScopedAStatus setHwGain(const std::vector<float>& in_channelGains) override;
|
||||
|
||||
public:
|
||||
static ndk::ScopedAStatus createInstance(
|
||||
const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
|
||||
StreamContext context, const std::vector<MicrophoneInfo>& microphones,
|
||||
std::shared_ptr<StreamIn>* result);
|
||||
|
||||
private:
|
||||
protected:
|
||||
friend class ndk::SharedRefBase;
|
||||
|
||||
static ndk::ScopedAStatus initInstance(const std::shared_ptr<StreamIn>& stream);
|
||||
|
||||
StreamIn(const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
|
||||
StreamContext&& context, const std::vector<MicrophoneInfo>& microphones);
|
||||
StreamContext&& context, const DriverInterface::CreateInstance& createDriver,
|
||||
const StreamWorkerInterface::CreateInstance& createWorker,
|
||||
const std::vector<MicrophoneInfo>& microphones);
|
||||
void createStreamCommon(const std::shared_ptr<StreamIn>& myPtr) {
|
||||
StreamCommonImpl<::aidl::android::hardware::audio::common::SinkMetadata,
|
||||
StreamInWorker>::createStreamCommon(myPtr);
|
||||
StreamCommonImpl<
|
||||
::aidl::android::hardware::audio::common::SinkMetadata>::createStreamCommon(myPtr);
|
||||
}
|
||||
|
||||
const std::map<::aidl::android::media::audio::common::AudioDevice, std::string> mMicrophones;
|
||||
|
||||
public:
|
||||
using CreateInstance = std::function<ndk::ScopedAStatus(
|
||||
const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
|
||||
StreamContext&& context, const std::vector<MicrophoneInfo>& microphones,
|
||||
std::shared_ptr<StreamIn>* result)>;
|
||||
};
|
||||
|
||||
class StreamOut : public StreamCommonImpl<::aidl::android::hardware::audio::common::SourceMetadata,
|
||||
StreamOutWorker>,
|
||||
class StreamOut : public StreamCommonImpl<::aidl::android::hardware::audio::common::SourceMetadata>,
|
||||
public BnStreamOut {
|
||||
ndk::ScopedAStatus getStreamCommon(std::shared_ptr<IStreamCommon>* _aidl_return) override {
|
||||
return StreamCommonImpl<::aidl::android::hardware::audio::common::SourceMetadata,
|
||||
StreamOutWorker>::getStreamCommon(_aidl_return);
|
||||
return StreamCommonImpl<::aidl::android::hardware::audio::common::SourceMetadata>::
|
||||
getStreamCommon(_aidl_return);
|
||||
}
|
||||
ndk::ScopedAStatus updateMetadata(
|
||||
const ::aidl::android::hardware::audio::common::SourceMetadata& in_sourceMetadata)
|
||||
override {
|
||||
return StreamCommonImpl<::aidl::android::hardware::audio::common::SourceMetadata,
|
||||
StreamOutWorker>::updateMetadata(in_sourceMetadata);
|
||||
return StreamCommonImpl<::aidl::android::hardware::audio::common::SourceMetadata>::
|
||||
updateMetadata(in_sourceMetadata);
|
||||
}
|
||||
ndk::ScopedAStatus getHwVolume(std::vector<float>* _aidl_return) override;
|
||||
ndk::ScopedAStatus setHwVolume(const std::vector<float>& in_channelVolumes) override;
|
||||
@@ -400,26 +469,31 @@ class StreamOut : public StreamCommonImpl<::aidl::android::hardware::audio::comm
|
||||
override;
|
||||
ndk::ScopedAStatus selectPresentation(int32_t in_presentationId, int32_t in_programId) override;
|
||||
|
||||
public:
|
||||
static ndk::ScopedAStatus createInstance(
|
||||
const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
|
||||
StreamContext context,
|
||||
const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
|
||||
offloadInfo,
|
||||
std::shared_ptr<StreamOut>* result);
|
||||
|
||||
private:
|
||||
friend class ndk::SharedRefBase;
|
||||
StreamOut(const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
|
||||
StreamContext&& context,
|
||||
const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
|
||||
offloadInfo);
|
||||
void createStreamCommon(const std::shared_ptr<StreamOut>& myPtr) {
|
||||
StreamCommonImpl<::aidl::android::hardware::audio::common::SourceMetadata,
|
||||
StreamOutWorker>::createStreamCommon(myPtr);
|
||||
StreamCommonImpl<::aidl::android::hardware::audio::common::SourceMetadata>::
|
||||
createStreamCommon(myPtr);
|
||||
}
|
||||
|
||||
protected:
|
||||
friend class ndk::SharedRefBase;
|
||||
|
||||
static ndk::ScopedAStatus initInstance(const std::shared_ptr<StreamOut>& stream);
|
||||
|
||||
StreamOut(const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
|
||||
StreamContext&& context, const DriverInterface::CreateInstance& createDriver,
|
||||
const StreamWorkerInterface::CreateInstance& createWorker,
|
||||
const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
|
||||
offloadInfo);
|
||||
|
||||
std::optional<::aidl::android::media::audio::common::AudioOffloadInfo> mOffloadInfo;
|
||||
|
||||
public:
|
||||
using CreateInstance = std::function<ndk::ScopedAStatus(
|
||||
const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
|
||||
StreamContext&& context,
|
||||
const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
|
||||
offloadInfo,
|
||||
std::shared_ptr<StreamOut>* result)>;
|
||||
};
|
||||
|
||||
class StreamWrapper {
|
||||
|
||||
69
audio/aidl/default/include/core-impl/StreamStub.h
Normal file
69
audio/aidl/default/include/core-impl/StreamStub.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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 DriverStub : public DriverInterface {
|
||||
public:
|
||||
DriverStub(const StreamContext& context, bool isInput);
|
||||
::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 transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
|
||||
int32_t* latencyMs) override;
|
||||
::android::status_t standby() override;
|
||||
|
||||
private:
|
||||
const size_t mFrameSizeBytes;
|
||||
const bool mIsInput;
|
||||
};
|
||||
|
||||
class StreamInStub final : public StreamIn {
|
||||
public:
|
||||
static ndk::ScopedAStatus createInstance(
|
||||
const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
|
||||
StreamContext&& context, const std::vector<MicrophoneInfo>& microphones,
|
||||
std::shared_ptr<StreamIn>* result);
|
||||
|
||||
private:
|
||||
friend class ndk::SharedRefBase;
|
||||
StreamInStub(const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
|
||||
StreamContext&& context, const std::vector<MicrophoneInfo>& microphones);
|
||||
};
|
||||
|
||||
class StreamOutStub final : public StreamOut {
|
||||
public:
|
||||
static ndk::ScopedAStatus createInstance(
|
||||
const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
|
||||
StreamContext&& context,
|
||||
const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
|
||||
offloadInfo,
|
||||
std::shared_ptr<StreamOut>* result);
|
||||
|
||||
private:
|
||||
friend class ndk::SharedRefBase;
|
||||
StreamOutStub(const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
|
||||
StreamContext&& context,
|
||||
const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
|
||||
offloadInfo);
|
||||
};
|
||||
|
||||
} // namespace aidl::android::hardware::audio::core
|
||||
Reference in New Issue
Block a user