mirror of
https://github.com/Evolution-X/hardware_interfaces
synced 2026-02-01 15:58:43 +00:00
Merge "audio: Do not use StreamSwitcher for StreamPrimary" into main
This commit is contained in:
@@ -77,6 +77,7 @@ cc_library {
|
||||
"r_submix/ModuleRemoteSubmix.cpp",
|
||||
"r_submix/SubmixRoute.cpp",
|
||||
"r_submix/StreamRemoteSubmix.cpp",
|
||||
"stub/DriverStubImpl.cpp",
|
||||
"stub/ModuleStub.cpp",
|
||||
"stub/StreamStub.cpp",
|
||||
"usb/ModuleUsb.cpp",
|
||||
|
||||
49
audio/aidl/default/include/core-impl/DriverStubImpl.h
Normal file
49
audio/aidl/default/include/core-impl/DriverStubImpl.h
Normal file
@@ -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
|
||||
@@ -133,6 +133,9 @@ class StreamContext {
|
||||
ReplyMQ* getReplyMQ() const { return mReplyMQ.get(); }
|
||||
int getTransientStateDelayMs() const { return mDebugParameters.transientStateDelayMs; }
|
||||
int getSampleRate() const { return mSampleRate; }
|
||||
bool isInput() const {
|
||||
return mFlags.getTag() == ::aidl::android::media::audio::common::AudioIoFlags::input;
|
||||
}
|
||||
bool isValid() const;
|
||||
// 'reset' is called on a Binder thread when closing the stream. Does not use
|
||||
// locking because it only cleans MQ pointers which were also set on the Binder thread.
|
||||
|
||||
@@ -16,25 +16,39 @@
|
||||
|
||||
#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 {
|
||||
|
||||
class StreamPrimary : public StreamAlsa {
|
||||
public:
|
||||
StreamPrimary(StreamContext* context, const Metadata& metadata,
|
||||
const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices);
|
||||
StreamPrimary(StreamContext* context, const Metadata& metadata);
|
||||
|
||||
// Methods of 'DriverInterface'.
|
||||
::android::status_t init() override;
|
||||
::android::status_t drain(StreamDescriptor::DrainMode mode) override;
|
||||
::android::status_t flush() override;
|
||||
::android::status_t pause() override;
|
||||
::android::status_t standby() override;
|
||||
::android::status_t start() override;
|
||||
::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
|
||||
int32_t* latencyMs) override;
|
||||
::android::status_t refinePosition(StreamDescriptor::Position* position) override;
|
||||
void shutdown() override;
|
||||
|
||||
// Overridden methods of 'StreamCommonImpl', called on a Binder thread.
|
||||
ndk::ScopedAStatus setConnectedDevices(const ConnectedDevices& devices) override;
|
||||
|
||||
protected:
|
||||
std::vector<alsa::DeviceProfile> getDeviceProfiles() override;
|
||||
bool isStubStream();
|
||||
|
||||
const bool mIsAsynchronous;
|
||||
int64_t mStartTimeNs = 0;
|
||||
@@ -42,12 +56,29 @@ class StreamPrimary : public StreamAlsa {
|
||||
bool mSkipNextTransfer = false;
|
||||
|
||||
private:
|
||||
static std::pair<int, int> getCardAndDeviceId(
|
||||
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);
|
||||
const std::pair<int, int> mCardAndDeviceId;
|
||||
static bool useStubStream(bool isInput,
|
||||
const ::aidl::android::media::audio::common::AudioDevice& device);
|
||||
|
||||
bool isStubStreamOnWorker() const { return mCurrAlsaDeviceId == kStubDeviceId; }
|
||||
|
||||
DriverStubImpl mStubDriver;
|
||||
mutable std::mutex mLock;
|
||||
AlsaDeviceId mAlsaDeviceId GUARDED_BY(mLock) = kStubDeviceId;
|
||||
|
||||
// Used by the worker thread only.
|
||||
AlsaDeviceId mCurrAlsaDeviceId = kStubDeviceId;
|
||||
};
|
||||
|
||||
class StreamInPrimary final : public StreamIn, public StreamSwitcher, public StreamInHwGainHelper {
|
||||
class StreamInPrimary final : public StreamIn, public StreamPrimary, public StreamInHwGainHelper {
|
||||
public:
|
||||
friend class ndk::SharedRefBase;
|
||||
StreamInPrimary(
|
||||
@@ -56,14 +87,6 @@ class StreamInPrimary final : public StreamIn, public StreamSwitcher, public Str
|
||||
const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones);
|
||||
|
||||
private:
|
||||
static bool useStubStream(const ::aidl::android::media::audio::common::AudioDevice& device);
|
||||
|
||||
DeviceSwitchBehavior switchCurrentStream(
|
||||
const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices)
|
||||
override;
|
||||
std::unique_ptr<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;
|
||||
@@ -71,7 +94,7 @@ class StreamInPrimary final : public StreamIn, public StreamSwitcher, public Str
|
||||
};
|
||||
|
||||
class StreamOutPrimary final : public StreamOut,
|
||||
public StreamSwitcher,
|
||||
public StreamPrimary,
|
||||
public StreamOutHwVolumeHelper {
|
||||
public:
|
||||
friend class ndk::SharedRefBase;
|
||||
@@ -81,22 +104,10 @@ class StreamOutPrimary final : public StreamOut,
|
||||
offloadInfo);
|
||||
|
||||
private:
|
||||
static bool useStubStream(const ::aidl::android::media::audio::common::AudioDevice& device);
|
||||
|
||||
DeviceSwitchBehavior switchCurrentStream(
|
||||
const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices)
|
||||
override;
|
||||
std::unique_ptr<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
|
||||
|
||||
@@ -16,38 +16,15 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core-impl/DriverStubImpl.h"
|
||||
#include "core-impl/Stream.h"
|
||||
|
||||
namespace aidl::android::hardware::audio::core {
|
||||
|
||||
class StreamStub : public StreamCommonImpl {
|
||||
class StreamStub : public StreamCommonImpl, public DriverStubImpl {
|
||||
public:
|
||||
StreamStub(StreamContext* context, const Metadata& metadata);
|
||||
~StreamStub();
|
||||
|
||||
// Methods of 'DriverInterface'.
|
||||
::android::status_t init() override;
|
||||
::android::status_t drain(StreamDescriptor::DrainMode) override;
|
||||
::android::status_t flush() override;
|
||||
::android::status_t pause() override;
|
||||
::android::status_t standby() override;
|
||||
::android::status_t start() override;
|
||||
::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
|
||||
int32_t* latencyMs) override;
|
||||
void shutdown() override;
|
||||
|
||||
private:
|
||||
const size_t mBufferSizeFrames;
|
||||
const size_t mFrameSizeBytes;
|
||||
const int mSampleRate;
|
||||
const bool mIsAsynchronous;
|
||||
const bool mIsInput;
|
||||
bool mIsInitialized = false; // Used for validating the state machine logic.
|
||||
bool mIsStandby = true; // Used for validating the state machine logic.
|
||||
|
||||
// Used by the worker thread.
|
||||
int64_t mStartTimeNs = 0;
|
||||
long mFramesSinceStart = 0;
|
||||
};
|
||||
|
||||
class StreamInStub final : public StreamIn, public StreamStub {
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -25,9 +25,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;
|
||||
@@ -41,19 +39,49 @@ using android::base::GetBoolProperty;
|
||||
|
||||
namespace aidl::android::hardware::audio::core {
|
||||
|
||||
const static constexpr std::pair<int, int> kDefaultCardAndDeviceId = {
|
||||
primary::PrimaryMixer::kAlsaCard, primary::PrimaryMixer::kAlsaDevice};
|
||||
|
||||
StreamPrimary::StreamPrimary(
|
||||
StreamContext* context, const Metadata& metadata,
|
||||
const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices)
|
||||
StreamPrimary::StreamPrimary(StreamContext* context, const Metadata& metadata)
|
||||
: StreamAlsa(context, metadata, 3 /*readWriteRetries*/),
|
||||
mIsAsynchronous(!!getContext().getAsyncCallback()),
|
||||
mCardAndDeviceId(getCardAndDeviceId(devices)) {
|
||||
mStubDriver(getContext()) {
|
||||
context->startStreamDataProcessor();
|
||||
}
|
||||
|
||||
::android::status_t StreamPrimary::init() {
|
||||
RETURN_STATUS_IF_ERROR(mStubDriver.init());
|
||||
return StreamAlsa::init();
|
||||
}
|
||||
|
||||
::android::status_t StreamPrimary::drain(StreamDescriptor::DrainMode mode) {
|
||||
return isStubStreamOnWorker() ? mStubDriver.drain(mode) : StreamAlsa::drain(mode);
|
||||
}
|
||||
|
||||
::android::status_t StreamPrimary::flush() {
|
||||
return isStubStreamOnWorker() ? mStubDriver.flush() : StreamAlsa::flush();
|
||||
}
|
||||
|
||||
::android::status_t StreamPrimary::pause() {
|
||||
return isStubStreamOnWorker() ? mStubDriver.pause() : StreamAlsa::pause();
|
||||
}
|
||||
|
||||
::android::status_t StreamPrimary::standby() {
|
||||
return isStubStreamOnWorker() ? mStubDriver.standby() : StreamAlsa::standby();
|
||||
}
|
||||
|
||||
::android::status_t StreamPrimary::start() {
|
||||
bool isStub = true, shutdownAlsaStream = false;
|
||||
{
|
||||
std::lock_guard l(mLock);
|
||||
isStub = mAlsaDeviceId == kStubDeviceId;
|
||||
shutdownAlsaStream =
|
||||
mCurrAlsaDeviceId != mAlsaDeviceId && mCurrAlsaDeviceId != kStubDeviceId;
|
||||
mCurrAlsaDeviceId = mAlsaDeviceId;
|
||||
}
|
||||
if (shutdownAlsaStream) {
|
||||
StreamAlsa::shutdown(); // Close currently opened ALSA devices.
|
||||
}
|
||||
if (isStub) {
|
||||
return mStubDriver.start();
|
||||
}
|
||||
RETURN_STATUS_IF_ERROR(StreamAlsa::start());
|
||||
mStartTimeNs = ::android::uptimeNanos();
|
||||
mFramesSinceStart = 0;
|
||||
@@ -63,6 +91,9 @@ StreamPrimary::StreamPrimary(
|
||||
|
||||
::android::status_t StreamPrimary::transfer(void* buffer, size_t frameCount,
|
||||
size_t* actualFrameCount, int32_t* latencyMs) {
|
||||
if (isStubStreamOnWorker()) {
|
||||
return mStubDriver.transfer(buffer, frameCount, actualFrameCount, latencyMs);
|
||||
}
|
||||
// This is a workaround for the emulator implementation which has a host-side buffer
|
||||
// and is not being able to achieve real-time behavior similar to ADSPs (b/302587331).
|
||||
if (!mSkipNextTransfer) {
|
||||
@@ -102,19 +133,52 @@ StreamPrimary::StreamPrimary(
|
||||
return ::android::OK;
|
||||
}
|
||||
|
||||
void StreamPrimary::shutdown() {
|
||||
StreamAlsa::shutdown();
|
||||
mStubDriver.shutdown();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus StreamPrimary::setConnectedDevices(const ConnectedDevices& devices) {
|
||||
LOG(DEBUG) << __func__ << ": " << ::android::internal::ToString(devices);
|
||||
if (devices.size() > 1) {
|
||||
LOG(ERROR) << __func__ << ": primary stream can only be connected to one device, got: "
|
||||
<< devices.size();
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
|
||||
}
|
||||
{
|
||||
const bool useStubDriver = devices.empty() || useStubStream(mIsInput, devices[0]);
|
||||
std::lock_guard l(mLock);
|
||||
mAlsaDeviceId = useStubDriver ? kStubDeviceId : getCardAndDeviceId(devices);
|
||||
}
|
||||
if (!devices.empty()) {
|
||||
auto streamDataProcessor = getContext().getStreamDataProcessor().lock();
|
||||
if (streamDataProcessor != nullptr) {
|
||||
streamDataProcessor->setAudioDevice(devices[0]);
|
||||
}
|
||||
}
|
||||
return StreamAlsa::setConnectedDevices(devices);
|
||||
}
|
||||
|
||||
std::vector<alsa::DeviceProfile> StreamPrimary::getDeviceProfiles() {
|
||||
return {alsa::DeviceProfile{.card = mCardAndDeviceId.first,
|
||||
.device = mCardAndDeviceId.second,
|
||||
return {alsa::DeviceProfile{.card = mCurrAlsaDeviceId.first,
|
||||
.device = mCurrAlsaDeviceId.second,
|
||||
.direction = mIsInput ? PCM_IN : PCM_OUT,
|
||||
.isExternal = false}};
|
||||
}
|
||||
|
||||
std::pair<int, int> StreamPrimary::getCardAndDeviceId(const std::vector<AudioDevice>& devices) {
|
||||
bool StreamPrimary::isStubStream() {
|
||||
std::lock_guard l(mLock);
|
||||
return mAlsaDeviceId == kStubDeviceId;
|
||||
}
|
||||
|
||||
// static
|
||||
StreamPrimary::AlsaDeviceId StreamPrimary::getCardAndDeviceId(
|
||||
const std::vector<AudioDevice>& devices) {
|
||||
if (devices.empty() || devices[0].address.getTag() != AudioDeviceAddress::id) {
|
||||
return kDefaultCardAndDeviceId;
|
||||
}
|
||||
std::string deviceAddress = devices[0].address.get<AudioDeviceAddress::id>();
|
||||
std::pair<int, int> cardAndDeviceId;
|
||||
AlsaDeviceId cardAndDeviceId;
|
||||
if (const size_t suffixPos = deviceAddress.rfind("CARD_");
|
||||
suffixPos == std::string::npos ||
|
||||
sscanf(deviceAddress.c_str() + suffixPos, "CARD_%d_DEV_%d", &cardAndDeviceId.first,
|
||||
@@ -126,48 +190,28 @@ std::pair<int, int> StreamPrimary::getCardAndDeviceId(const std::vector<AudioDev
|
||||
return cardAndDeviceId;
|
||||
}
|
||||
|
||||
// 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 */;
|
||||
}
|
||||
return kSimulateOutput || device.type.type == AudioDeviceType::OUT_TELEPHONY_TX ||
|
||||
device.type.connection == AudioDeviceDescription::CONNECTION_BUS /*deprecated*/;
|
||||
}
|
||||
|
||||
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 */;
|
||||
}
|
||||
|
||||
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, devices));
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus StreamInPrimary::getHwGain(std::vector<float>* _aidl_return) {
|
||||
if (isStubStream()) {
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
|
||||
@@ -201,44 +245,9 @@ ndk::ScopedAStatus StreamInPrimary::setHwGain(const std::vector<float>& in_chann
|
||||
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*/;
|
||||
}
|
||||
|
||||
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, devices));
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus StreamOutPrimary::getHwVolume(std::vector<float>* _aidl_return) {
|
||||
if (isStubStream()) {
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
|
||||
@@ -264,15 +273,4 @@ ndk::ScopedAStatus StreamOutPrimary::setHwVolume(const std::vector<float>& in_ch
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus StreamOutPrimary::setConnectedDevices(
|
||||
const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) {
|
||||
if (!devices.empty()) {
|
||||
auto streamDataProcessor = mContextInstance.getStreamDataProcessor().lock();
|
||||
if (streamDataProcessor != nullptr) {
|
||||
streamDataProcessor->setAudioDevice(devices[0]);
|
||||
}
|
||||
}
|
||||
return StreamSwitcher::setConnectedDevices(devices);
|
||||
}
|
||||
|
||||
} // namespace aidl::android::hardware::audio::core
|
||||
|
||||
126
audio/aidl/default/stub/DriverStubImpl.cpp
Normal file
126
audio/aidl/default/stub/DriverStubImpl.cpp
Normal file
@@ -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
|
||||
@@ -32,110 +32,12 @@ using aidl::android::media::audio::common::MicrophoneInfo;
|
||||
namespace aidl::android::hardware::audio::core {
|
||||
|
||||
StreamStub::StreamStub(StreamContext* context, const Metadata& metadata)
|
||||
: StreamCommonImpl(context, metadata),
|
||||
mBufferSizeFrames(getContext().getBufferSizeInFrames()),
|
||||
mFrameSizeBytes(getContext().getFrameSize()),
|
||||
mSampleRate(getContext().getSampleRate()),
|
||||
mIsAsynchronous(!!getContext().getAsyncCallback()),
|
||||
mIsInput(isInput(metadata)) {}
|
||||
: StreamCommonImpl(context, metadata), DriverStubImpl(getContext()) {}
|
||||
|
||||
StreamStub::~StreamStub() {
|
||||
cleanupWorker();
|
||||
}
|
||||
|
||||
::android::status_t StreamStub::init() {
|
||||
mIsInitialized = true;
|
||||
return ::android::OK;
|
||||
}
|
||||
|
||||
::android::status_t StreamStub::drain(StreamDescriptor::DrainMode) {
|
||||
if (!mIsInitialized) {
|
||||
LOG(FATAL) << __func__ << ": must not happen for an uninitialized driver";
|
||||
}
|
||||
if (!mIsInput) {
|
||||
if (!mIsAsynchronous) {
|
||||
static constexpr float kMicrosPerSecond = MICROS_PER_SECOND;
|
||||
const size_t delayUs = static_cast<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";
|
||||
}
|
||||
mIsStandby = true;
|
||||
return ::android::OK;
|
||||
}
|
||||
|
||||
::android::status_t StreamStub::start() {
|
||||
if (!mIsInitialized) {
|
||||
LOG(FATAL) << __func__ << ": must not happen for an uninitialized driver";
|
||||
}
|
||||
mIsStandby = false;
|
||||
mStartTimeNs = ::android::uptimeNanos();
|
||||
mFramesSinceStart = 0;
|
||||
return ::android::OK;
|
||||
}
|
||||
|
||||
::android::status_t StreamStub::transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
|
||||
int32_t*) {
|
||||
if (!mIsInitialized) {
|
||||
LOG(FATAL) << __func__ << ": must not happen for an uninitialized driver";
|
||||
}
|
||||
if (mIsStandby) {
|
||||
LOG(FATAL) << __func__ << ": must not happen while in standby";
|
||||
}
|
||||
*actualFrameCount = frameCount;
|
||||
if (mIsAsynchronous) {
|
||||
usleep(500);
|
||||
} else {
|
||||
mFramesSinceStart += *actualFrameCount;
|
||||
const long bufferDurationUs =
|
||||
(*actualFrameCount) * MICROS_PER_SECOND / mContext.getSampleRate();
|
||||
const auto totalDurationUs =
|
||||
(::android::uptimeNanos() - mStartTimeNs) / NANOS_PER_MICROSECOND;
|
||||
const long totalOffsetUs =
|
||||
mFramesSinceStart * MICROS_PER_SECOND / mContext.getSampleRate() - totalDurationUs;
|
||||
LOG(VERBOSE) << __func__ << ": totalOffsetUs " << totalOffsetUs;
|
||||
if (totalOffsetUs > 0) {
|
||||
const long sleepTimeUs = std::min(totalOffsetUs, bufferDurationUs);
|
||||
LOG(VERBOSE) << __func__ << ": sleeping for " << sleepTimeUs << " us";
|
||||
usleep(sleepTimeUs);
|
||||
}
|
||||
}
|
||||
if (mIsInput) {
|
||||
uint8_t* byteBuffer = static_cast<uint8_t*>(buffer);
|
||||
for (size_t i = 0; i < frameCount * mFrameSizeBytes; ++i) {
|
||||
byteBuffer[i] = std::rand() % 255;
|
||||
}
|
||||
}
|
||||
return ::android::OK;
|
||||
}
|
||||
|
||||
void StreamStub::shutdown() {
|
||||
mIsInitialized = false;
|
||||
}
|
||||
|
||||
StreamInStub::StreamInStub(StreamContext&& context, const SinkMetadata& sinkMetadata,
|
||||
const std::vector<MicrophoneInfo>& microphones)
|
||||
: StreamIn(std::move(context), microphones), StreamStub(&mContextInstance, sinkMetadata) {}
|
||||
|
||||
Reference in New Issue
Block a user