audio: Add DriverInterface::start method am: 49712b56d8 am: d8e545d9d8 am: 4eb39af463 am: 5e9873805d am: 9a652231e0 am: ef83280c00

Original change: https://android-review.googlesource.com/c/platform/hardware/interfaces/+/2647304

Change-Id: I43852509f7326b8ab5010ca9f92514668be06b72
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Mikhail Naganov 2023-07-01 02:41:45 +00:00 committed by Automerger Merge Worker
commit a225cb7a28
8 changed files with 150 additions and 96 deletions

View file

@ -166,10 +166,15 @@ StreamInWorkerLogic::Status StreamInWorkerLogic::cycle() {
case Tag::start:
if (mState == StreamDescriptor::State::STANDBY ||
mState == StreamDescriptor::State::DRAINING) {
populateReply(&reply, mIsConnected);
mState = mState == StreamDescriptor::State::STANDBY
? StreamDescriptor::State::IDLE
: StreamDescriptor::State::ACTIVE;
if (::android::status_t status = mDriver->start(); status == ::android::OK) {
populateReply(&reply, mIsConnected);
mState = mState == StreamDescriptor::State::STANDBY
? StreamDescriptor::State::IDLE
: StreamDescriptor::State::ACTIVE;
} else {
LOG(ERROR) << __func__ << ": start failed: " << status;
mState = StreamDescriptor::State::ERROR;
}
} else {
populateReplyWrongState(&reply, command);
}
@ -377,26 +382,36 @@ StreamOutWorkerLogic::Status StreamOutWorkerLogic::cycle() {
populateReply(&reply, mIsConnected);
break;
case Tag::start: {
bool commandAccepted = true;
std::optional<StreamDescriptor::State> nextState;
switch (mState) {
case StreamDescriptor::State::STANDBY:
mState = StreamDescriptor::State::IDLE;
nextState = StreamDescriptor::State::IDLE;
break;
case StreamDescriptor::State::PAUSED:
mState = StreamDescriptor::State::ACTIVE;
nextState = StreamDescriptor::State::ACTIVE;
break;
case StreamDescriptor::State::DRAIN_PAUSED:
switchToTransientState(StreamDescriptor::State::DRAINING);
nextState = StreamDescriptor::State::DRAINING;
break;
case StreamDescriptor::State::TRANSFER_PAUSED:
switchToTransientState(StreamDescriptor::State::TRANSFERRING);
nextState = StreamDescriptor::State::TRANSFERRING;
break;
default:
populateReplyWrongState(&reply, command);
commandAccepted = false;
}
if (commandAccepted) {
populateReply(&reply, mIsConnected);
if (nextState.has_value()) {
if (::android::status_t status = mDriver->start(); status == ::android::OK) {
populateReply(&reply, mIsConnected);
if (*nextState == StreamDescriptor::State::IDLE ||
*nextState == StreamDescriptor::State::ACTIVE) {
mState = *nextState;
} else {
switchToTransientState(*nextState);
}
} else {
LOG(ERROR) << __func__ << ": start failed: " << status;
mState = StreamDescriptor::State::ERROR;
}
}
} break;
case Tag::burst:

View file

@ -33,33 +33,67 @@ namespace aidl::android::hardware::audio::core {
StreamStub::StreamStub(const Metadata& metadata, StreamContext&& context)
: StreamCommonImpl(metadata, std::move(context)),
mFrameSizeBytes(context.getFrameSize()),
mSampleRate(context.getSampleRate()),
mIsAsynchronous(!!context.getAsyncCallback()),
mFrameSizeBytes(getContext().getFrameSize()),
mSampleRate(getContext().getSampleRate()),
mIsAsynchronous(!!getContext().getAsyncCallback()),
mIsInput(isInput(metadata)) {}
::android::status_t StreamStub::init() {
mIsInitialized = true;
usleep(500);
return ::android::OK;
}
::android::status_t StreamStub::drain(StreamDescriptor::DrainMode) {
if (!mIsInitialized) {
LOG(FATAL) << __func__ << ": must not happen for an uninitialized driver";
}
usleep(500);
return ::android::OK;
}
::android::status_t StreamStub::flush() {
if (!mIsInitialized) {
LOG(FATAL) << __func__ << ": must not happen for an uninitialized driver";
}
usleep(500);
return ::android::OK;
}
::android::status_t StreamStub::pause() {
if (!mIsInitialized) {
LOG(FATAL) << __func__ << ": must not happen for an uninitialized driver";
}
usleep(500);
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* latencyMs) {
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) {
@ -80,13 +114,10 @@ StreamStub::StreamStub(const Metadata& metadata, StreamContext&& context)
return ::android::OK;
}
::android::status_t StreamStub::standby() {
usleep(500);
return ::android::OK;
void StreamStub::shutdown() {
mIsInitialized = false;
}
void StreamStub::shutdown() {}
StreamInStub::StreamInStub(const SinkMetadata& sinkMetadata, StreamContext&& context,
const std::vector<MicrophoneInfo>& microphones)
: StreamStub(sinkMetadata, std::move(context)), StreamIn(microphones) {}

View file

@ -180,9 +180,10 @@ struct DriverInterface {
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 standby() = 0;
virtual ::android::status_t start() = 0;
virtual ::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
int32_t* latencyMs) = 0;
virtual ::android::status_t standby() = 0;
virtual void shutdown() = 0; // This function is only called once.
};

View file

@ -35,9 +35,10 @@ class StreamRemoteSubmix : public StreamCommonImpl {
::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;
::android::status_t standby() override;
void shutdown() override;
// Overridden methods of 'StreamCommonImpl', called on a Binder thread.
@ -53,7 +54,6 @@ class StreamRemoteSubmix : public StreamCommonImpl {
const bool mIsInput;
AudioConfig mStreamConfig;
std::shared_ptr<SubmixRoute> mCurrentRoute = nullptr;
::android::status_t mStatus = ::android::NO_INIT;
// Mutex lock to protect vector of submix routes, each of these submix routes have their mutex
// locks and none of the mutex locks should be taken together.

View file

@ -28,9 +28,10 @@ class StreamStub : public StreamCommonImpl {
::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;
::android::status_t standby() override;
void shutdown() override;
private:
@ -38,6 +39,8 @@ class StreamStub : public StreamCommonImpl {
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.
};
class StreamInStub final : public StreamStub, public StreamIn {

View file

@ -16,7 +16,10 @@
#pragma once
#include <atomic>
#include <functional>
#include <mutex>
#include <optional>
#include <vector>
#include <aidl/android/media/audio/common/AudioChannelLayout.h>
@ -38,9 +41,10 @@ class StreamUsb : public StreamCommonImpl {
::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;
::android::status_t standby() override;
void shutdown() override;
// Overridden methods of 'StreamCommonImpl', called on a Binder thread.
@ -48,15 +52,20 @@ class StreamUsb : public StreamCommonImpl {
ndk::ScopedAStatus setConnectedDevices(const ConnectedDevices& devices) override;
private:
::android::status_t exitStandby();
using AlsaDeviceProxyDeleter = std::function<void(alsa_device_proxy*)>;
using AlsaDeviceProxy = std::unique_ptr<alsa_device_proxy, AlsaDeviceProxyDeleter>;
static std::optional<struct pcm_config> maybePopulateConfig(const StreamContext& context,
bool isInput);
mutable std::mutex mLock;
const size_t mFrameSizeBytes;
std::optional<struct pcm_config> mConfig;
const bool mIsInput;
std::vector<std::shared_ptr<alsa_device_proxy>> mAlsaDeviceProxies GUARDED_BY(mLock);
bool mIsStandby = true;
const std::optional<struct pcm_config> mConfig;
std::atomic<bool> mConnectedDevicesUpdated = false;
// All fields below are only used on the worker thread.
std::vector<AlsaDeviceProxy> mAlsaDeviceProxies;
};
class StreamInUsb final : public StreamUsb, public StreamIn {

View file

@ -55,7 +55,7 @@ std::map<int32_t, std::shared_ptr<SubmixRoute>> StreamRemoteSubmix::sSubmixRoute
mCurrentRoute = std::make_shared<SubmixRoute>();
if (::android::OK != mCurrentRoute->createPipe(mStreamConfig)) {
LOG(ERROR) << __func__ << ": create pipe failed";
return mStatus;
return ::android::NO_INIT;
}
{
std::lock_guard guard(sSubmixRoutesLock);
@ -64,12 +64,12 @@ std::map<int32_t, std::shared_ptr<SubmixRoute>> StreamRemoteSubmix::sSubmixRoute
} else {
if (!mCurrentRoute->isStreamConfigValid(mIsInput, mStreamConfig)) {
LOG(ERROR) << __func__ << ": invalid stream config";
return mStatus;
return ::android::NO_INIT;
}
sp<MonoPipe> sink = mCurrentRoute->getSink();
if (sink == nullptr) {
LOG(ERROR) << __func__ << ": nullptr sink when opening stream";
return mStatus;
return ::android::NO_INIT;
}
// If the sink has been shutdown or pipe recreation is forced, delete the pipe and
// recreate it.
@ -77,14 +77,13 @@ std::map<int32_t, std::shared_ptr<SubmixRoute>> StreamRemoteSubmix::sSubmixRoute
LOG(DEBUG) << __func__ << ": Non-nullptr shut down sink when opening stream";
if (::android::OK != mCurrentRoute->resetPipe()) {
LOG(ERROR) << __func__ << ": reset pipe failed";
return mStatus;
return ::android::NO_INIT;
}
}
}
mCurrentRoute->openStream(mIsInput);
mStatus = ::android::OK;
return mStatus;
return ::android::OK;
}
::android::status_t StreamRemoteSubmix::drain(StreamDescriptor::DrainMode) {
@ -102,6 +101,16 @@ std::map<int32_t, std::shared_ptr<SubmixRoute>> StreamRemoteSubmix::sSubmixRoute
return ::android::OK;
}
::android::status_t StreamRemoteSubmix::standby() {
mCurrentRoute->standby(mIsInput);
return ::android::OK;
}
::android::status_t StreamRemoteSubmix::start() {
mCurrentRoute->exitStandby(mIsInput);
return ::android::OK;
}
ndk::ScopedAStatus StreamRemoteSubmix::prepareToClose() {
if (!mIsInput) {
std::shared_ptr<SubmixRoute> route = nullptr;
@ -138,17 +147,12 @@ void StreamRemoteSubmix::shutdown() {
std::lock_guard guard(sSubmixRoutesLock);
sSubmixRoutes.erase(mPortId);
mStatus = ::android::NO_INIT;
}
mCurrentRoute.reset();
}
::android::status_t StreamRemoteSubmix::transfer(void* buffer, size_t frameCount,
size_t* actualFrameCount, int32_t* latencyMs) {
if (mStatus != ::android::OK) {
LOG(ERROR) << __func__ << ": failed, not configured";
return ::android::NO_INIT;
}
*latencyMs = (getStreamPipeSizeInFrames() * MILLIS_PER_SECOND) / mStreamConfig.sampleRate;
LOG(VERBOSE) << __func__ << ": Latency " << *latencyMs << "ms";
@ -171,7 +175,6 @@ void StreamRemoteSubmix::shutdown() {
return ::android::UNEXPECTED_NULL;
}
mCurrentRoute->exitStandby(mIsInput);
return (mIsInput ? inRead(buffer, frameCount, actualFrameCount)
: outWrite(buffer, frameCount, actualFrameCount));
}
@ -329,11 +332,6 @@ size_t StreamRemoteSubmix::getStreamPipeSizeInFrames() {
return ::android::OK;
}
::android::status_t StreamRemoteSubmix::standby() {
mCurrentRoute->standby(mIsInput);
return ::android::OK;
}
StreamInRemoteSubmix::StreamInRemoteSubmix(const SinkMetadata& sinkMetadata,
StreamContext&& context,
const std::vector<MicrophoneInfo>& microphones)

View file

@ -14,6 +14,8 @@
* limitations under the License.
*/
#include <limits>
#define LOG_TAG "AHAL_StreamUsb"
#include <android-base/logging.h>
@ -45,25 +47,30 @@ namespace aidl::android::hardware::audio::core {
StreamUsb::StreamUsb(const Metadata& metadata, StreamContext&& context)
: StreamCommonImpl(metadata, std::move(context)),
mFrameSizeBytes(context.getFrameSize()),
mIsInput(isInput(metadata)) {
mFrameSizeBytes(getContext().getFrameSize()),
mIsInput(isInput(metadata)),
mConfig(maybePopulateConfig(getContext(), mIsInput)) {}
// static
std::optional<struct pcm_config> StreamUsb::maybePopulateConfig(const StreamContext& context,
bool isInput) {
struct pcm_config config;
config.channels = usb::getChannelCountFromChannelMask(context.getChannelLayout(), mIsInput);
config.channels = usb::getChannelCountFromChannelMask(context.getChannelLayout(), isInput);
if (config.channels == 0) {
LOG(ERROR) << __func__ << ": invalid channel=" << context.getChannelLayout().toString();
return;
return std::nullopt;
}
config.format = usb::aidl2legacy_AudioFormatDescription_pcm_format(context.getFormat());
if (config.format == PCM_FORMAT_INVALID) {
LOG(ERROR) << __func__ << ": invalid format=" << context.getFormat().toString();
return;
return std::nullopt;
}
config.rate = context.getSampleRate();
if (config.rate == 0) {
LOG(ERROR) << __func__ << ": invalid sample rate=" << config.rate;
return;
return std::nullopt;
}
mConfig = config;
return config;
}
::android::status_t StreamUsb::init() {
@ -89,8 +96,8 @@ ndk::ScopedAStatus StreamUsb::setConnectedDevices(
}
}
std::lock_guard guard(mLock);
mAlsaDeviceProxies.clear();
RETURN_STATUS_IF_ERROR(StreamCommonImpl::setConnectedDevices(connectedDevices));
mConnectedDevicesUpdated.store(true, std::memory_order_release);
return ndk::ScopedAStatus::ok();
}
@ -111,59 +118,53 @@ ndk::ScopedAStatus StreamUsb::setConnectedDevices(
::android::status_t StreamUsb::transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
int32_t* latencyMs) {
{
std::lock_guard guard(mLock);
if (!mConfig.has_value() || mConnectedDevices.empty()) {
LOG(ERROR) << __func__ << ": failed, has config: " << mConfig.has_value()
<< ", has connected devices: " << mConnectedDevices.empty();
return ::android::NO_INIT;
}
}
if (mIsStandby) {
if (::android::status_t status = exitStandby(); status != ::android::OK) {
LOG(ERROR) << __func__ << ": failed to exit standby, status=" << status;
return status;
}
}
std::vector<std::shared_ptr<alsa_device_proxy>> alsaDeviceProxies;
{
std::lock_guard guard(mLock);
alsaDeviceProxies = mAlsaDeviceProxies;
if (mConnectedDevicesUpdated.load(std::memory_order_acquire)) {
// 'setConnectedDevices' has been called. I/O will be restarted.
*actualFrameCount = 0;
*latencyMs = StreamDescriptor::LATENCY_UNKNOWN;
return ::android::OK;
}
const size_t bytesToTransfer = frameCount * mFrameSizeBytes;
unsigned maxLatency = 0;
if (mIsInput) {
if (mAlsaDeviceProxies.empty()) {
LOG(FATAL) << __func__ << ": no input devices";
return ::android::NO_INIT;
}
// For input case, only support single device.
proxy_read(alsaDeviceProxies[0].get(), buffer, bytesToTransfer);
proxy_read(mAlsaDeviceProxies[0].get(), buffer, bytesToTransfer);
maxLatency = proxy_get_latency(mAlsaDeviceProxies[0].get());
} else {
for (auto& proxy : alsaDeviceProxies) {
for (auto& proxy : mAlsaDeviceProxies) {
proxy_write(proxy.get(), buffer, bytesToTransfer);
maxLatency = std::max(maxLatency, proxy_get_latency(proxy.get()));
}
}
*actualFrameCount = frameCount;
*latencyMs = Module::kLatencyMs;
maxLatency = std::min(maxLatency, static_cast<unsigned>(std::numeric_limits<int32_t>::max()));
*latencyMs = maxLatency;
return ::android::OK;
}
::android::status_t StreamUsb::standby() {
if (!mIsStandby) {
std::lock_guard guard(mLock);
mAlsaDeviceProxies.clear();
mIsStandby = true;
}
mAlsaDeviceProxies.clear();
return ::android::OK;
}
void StreamUsb::shutdown() {}
void StreamUsb::shutdown() {
mAlsaDeviceProxies.clear();
}
::android::status_t StreamUsb::exitStandby() {
::android::status_t StreamUsb::start() {
std::vector<AudioDeviceAddress> connectedDevices;
{
std::lock_guard guard(mLock);
std::transform(mConnectedDevices.begin(), mConnectedDevices.end(),
std::back_inserter(connectedDevices),
[](const auto& device) { return device.address; });
mConnectedDevicesUpdated.store(false, std::memory_order_release);
}
std::vector<std::shared_ptr<alsa_device_proxy>> alsaDeviceProxies;
decltype(mAlsaDeviceProxies) alsaDeviceProxies;
for (const auto& device : connectedDevices) {
alsa_device_profile profile;
profile_init(&profile, mIsInput ? PCM_IN : PCM_OUT);
@ -175,16 +176,16 @@ void StreamUsb::shutdown() {}
return ::android::UNKNOWN_ERROR;
}
auto proxy = std::shared_ptr<alsa_device_proxy>(new alsa_device_proxy(),
[](alsa_device_proxy* proxy) {
proxy_close(proxy);
free(proxy);
});
AlsaDeviceProxy proxy(new alsa_device_proxy, [](alsa_device_proxy* proxy) {
proxy_close(proxy);
free(proxy);
});
// Always ask for alsa configure as required since the configuration should be supported
// by the connected device. That is guaranteed by `setAudioPortConfig` and
// `setAudioPatch`.
if (int err =
proxy_prepare(proxy.get(), &profile, &mConfig.value(), true /*is_bit_perfect*/);
if (int err = proxy_prepare(proxy.get(), &profile,
const_cast<struct pcm_config*>(&mConfig.value()),
true /*is_bit_perfect*/);
err != 0) {
LOG(ERROR) << __func__ << ": fail to prepare for device address=" << device.toString()
<< " error=" << err;
@ -197,11 +198,7 @@ void StreamUsb::shutdown() {}
}
alsaDeviceProxies.push_back(std::move(proxy));
}
{
std::lock_guard guard(mLock);
mAlsaDeviceProxies = alsaDeviceProxies;
}
mIsStandby = false;
mAlsaDeviceProxies = std::move(alsaDeviceProxies);
return ::android::OK;
}