Merge changes from topic "fix-b-264712385-primary-module" into main
* changes: audio: Move StreamContext ownership out from StreamCommonImpl audio: Use ChildInterface in StreamCommonImpl audio: Update StreamAlsa and alsa utils for built-in devices audio: Simplify and extend alsa::Mixer
This commit is contained in:
commit
12c4bf6ba1
25 changed files with 393 additions and 257 deletions
|
@ -675,7 +675,7 @@ ndk::ScopedAStatus Module::openInputStream(const OpenInputStreamArguments& in_ar
|
|||
nullptr, nullptr, &context));
|
||||
context.fillDescriptor(&_aidl_return->desc);
|
||||
std::shared_ptr<StreamIn> stream;
|
||||
RETURN_STATUS_IF_ERROR(createInputStream(in_args.sinkMetadata, std::move(context),
|
||||
RETURN_STATUS_IF_ERROR(createInputStream(std::move(context), in_args.sinkMetadata,
|
||||
mConfig->microphones, &stream));
|
||||
StreamWrapper streamWrapper(stream);
|
||||
if (auto patchIt = mPatches.find(in_args.portConfigId); patchIt != mPatches.end()) {
|
||||
|
@ -721,7 +721,7 @@ ndk::ScopedAStatus Module::openOutputStream(const OpenOutputStreamArguments& in_
|
|||
in_args.eventCallback, &context));
|
||||
context.fillDescriptor(&_aidl_return->desc);
|
||||
std::shared_ptr<StreamOut> stream;
|
||||
RETURN_STATUS_IF_ERROR(createOutputStream(in_args.sourceMetadata, std::move(context),
|
||||
RETURN_STATUS_IF_ERROR(createOutputStream(std::move(context), in_args.sourceMetadata,
|
||||
in_args.offloadInfo, &stream));
|
||||
StreamWrapper streamWrapper(stream);
|
||||
if (auto patchIt = mPatches.find(in_args.portConfigId); patchIt != mPatches.end()) {
|
||||
|
|
|
@ -38,22 +38,23 @@ ndk::ScopedAStatus ModulePrimary::getTelephony(std::shared_ptr<ITelephony>* _aid
|
|||
mTelephony = ndk::SharedRefBase::make<Telephony>();
|
||||
}
|
||||
*_aidl_return = mTelephony.getPtr();
|
||||
LOG(DEBUG) << __func__ << ": returning instance of ITelephony: " << _aidl_return->get();
|
||||
LOG(DEBUG) << __func__
|
||||
<< ": returning instance of ITelephony: " << _aidl_return->get()->asBinder().get();
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus ModulePrimary::createInputStream(const SinkMetadata& sinkMetadata,
|
||||
StreamContext&& context,
|
||||
ndk::ScopedAStatus ModulePrimary::createInputStream(StreamContext&& context,
|
||||
const SinkMetadata& sinkMetadata,
|
||||
const std::vector<MicrophoneInfo>& microphones,
|
||||
std::shared_ptr<StreamIn>* result) {
|
||||
return createStreamInstance<StreamInStub>(result, sinkMetadata, std::move(context),
|
||||
return createStreamInstance<StreamInStub>(result, std::move(context), sinkMetadata,
|
||||
microphones);
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus ModulePrimary::createOutputStream(
|
||||
const SourceMetadata& sourceMetadata, StreamContext&& context,
|
||||
StreamContext&& context, const SourceMetadata& sourceMetadata,
|
||||
const std::optional<AudioOffloadInfo>& offloadInfo, std::shared_ptr<StreamOut>* result) {
|
||||
return createStreamInstance<StreamOutStub>(result, sourceMetadata, std::move(context),
|
||||
return createStreamInstance<StreamOutStub>(result, std::move(context), sourceMetadata,
|
||||
offloadInfo);
|
||||
}
|
||||
|
||||
|
|
|
@ -47,13 +47,19 @@ void StreamContext::fillDescriptor(StreamDescriptor* desc) {
|
|||
desc->reply = mReplyMQ->dupeDesc();
|
||||
}
|
||||
if (mDataMQ) {
|
||||
const size_t frameSize = getFrameSize();
|
||||
desc->frameSizeBytes = frameSize;
|
||||
desc->bufferSizeFrames = mDataMQ->getQuantumCount() * mDataMQ->getQuantumSize() / frameSize;
|
||||
desc->frameSizeBytes = getFrameSize();
|
||||
desc->bufferSizeFrames = getBufferSizeInFrames();
|
||||
desc->audio.set<StreamDescriptor::AudioBuffer::Tag::fmq>(mDataMQ->dupeDesc());
|
||||
}
|
||||
}
|
||||
|
||||
size_t StreamContext::getBufferSizeInFrames() const {
|
||||
if (mDataMQ) {
|
||||
return mDataMQ->getQuantumCount() * mDataMQ->getQuantumSize() / getFrameSize();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t StreamContext::getFrameSize() const {
|
||||
return getFrameSizeInBytes(mFormat, mChannelLayout);
|
||||
}
|
||||
|
@ -597,18 +603,16 @@ StreamCommonImpl::~StreamCommonImpl() {
|
|||
ndk::ScopedAStatus StreamCommonImpl::initInstance(
|
||||
const std::shared_ptr<StreamCommonInterface>& delegate) {
|
||||
mCommon = ndk::SharedRefBase::make<StreamCommonDelegator>(delegate);
|
||||
mCommonBinder = mCommon->asBinder();
|
||||
AIBinder_setMinSchedulerPolicy(mCommonBinder.get(), SCHED_NORMAL, ANDROID_PRIORITY_AUDIO);
|
||||
return mWorker->start() ? ndk::ScopedAStatus::ok()
|
||||
: ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus StreamCommonImpl::getStreamCommonCommon(
|
||||
std::shared_ptr<IStreamCommon>* _aidl_return) {
|
||||
if (mCommon == nullptr) {
|
||||
if (!mCommon) {
|
||||
LOG(FATAL) << __func__ << ": the common interface was not created";
|
||||
}
|
||||
*_aidl_return = mCommon;
|
||||
*_aidl_return = mCommon.getPtr();
|
||||
LOG(DEBUG) << __func__ << ": returning " << _aidl_return->get()->asBinder().get();
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
@ -659,7 +663,7 @@ ndk::ScopedAStatus StreamCommonImpl::close() {
|
|||
LOG(DEBUG) << __func__ << ": joining the worker thread...";
|
||||
mWorker->stop();
|
||||
LOG(DEBUG) << __func__ << ": worker thread joined";
|
||||
mContext.reset();
|
||||
onClose();
|
||||
mWorker->setClosed();
|
||||
return ndk::ScopedAStatus::ok();
|
||||
} else {
|
||||
|
@ -723,11 +727,15 @@ static std::map<AudioDevice, std::string> transformMicrophones(
|
|||
}
|
||||
} // namespace
|
||||
|
||||
StreamIn::StreamIn(const std::vector<MicrophoneInfo>& microphones)
|
||||
: mMicrophones(transformMicrophones(microphones)) {
|
||||
StreamIn::StreamIn(StreamContext&& context, const std::vector<MicrophoneInfo>& microphones)
|
||||
: mContext(std::move(context)), mMicrophones(transformMicrophones(microphones)) {
|
||||
LOG(DEBUG) << __func__;
|
||||
}
|
||||
|
||||
void StreamIn::defaultOnClose() {
|
||||
mContext.reset();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus StreamIn::getActiveMicrophones(
|
||||
std::vector<MicrophoneDynamicInfo>* _aidl_return) {
|
||||
std::vector<MicrophoneDynamicInfo> result;
|
||||
|
@ -780,11 +788,15 @@ ndk::ScopedAStatus StreamIn::setHwGain(const std::vector<float>& in_channelGains
|
|||
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
|
||||
}
|
||||
|
||||
StreamOut::StreamOut(const std::optional<AudioOffloadInfo>& offloadInfo)
|
||||
: mOffloadInfo(offloadInfo) {
|
||||
StreamOut::StreamOut(StreamContext&& context, const std::optional<AudioOffloadInfo>& offloadInfo)
|
||||
: mContext(std::move(context)), mOffloadInfo(offloadInfo) {
|
||||
LOG(DEBUG) << __func__;
|
||||
}
|
||||
|
||||
void StreamOut::defaultOnClose() {
|
||||
mContext.reset();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus StreamOut::updateOffloadMetadata(
|
||||
const AudioOffloadMetadata& in_offloadMetadata) {
|
||||
LOG(DEBUG) << __func__;
|
||||
|
|
|
@ -14,44 +14,17 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#define LOG_TAG "AHAL_AlsaMixer"
|
||||
#include <android-base/logging.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
#define LOG_TAG "AHAL_AlsaMixer"
|
||||
#include <android-base/logging.h>
|
||||
#include <android/binder_status.h>
|
||||
|
||||
#include "Mixer.h"
|
||||
|
||||
namespace aidl::android::hardware::audio::core::alsa {
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
MixerControl::MixerControl(struct mixer_ctl* ctl)
|
||||
: mCtl(ctl),
|
||||
mNumValues(mixer_ctl_get_num_values(ctl)),
|
||||
mMinValue(mixer_ctl_get_range_min(ctl)),
|
||||
mMaxValue(mixer_ctl_get_range_max(ctl)) {}
|
||||
|
||||
unsigned int MixerControl::getNumValues() const {
|
||||
return mNumValues;
|
||||
}
|
||||
|
||||
int MixerControl::getMaxValue() const {
|
||||
return mMaxValue;
|
||||
}
|
||||
|
||||
int MixerControl::getMinValue() const {
|
||||
return mMinValue;
|
||||
}
|
||||
|
||||
int MixerControl::setArray(const void* array, size_t count) {
|
||||
const std::lock_guard guard(mLock);
|
||||
return mixer_ctl_set_array(mCtl, array, count);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// static
|
||||
const std::map<Mixer::Control, std::vector<Mixer::ControlNamesAndExpectedCtlType>>
|
||||
Mixer::kPossibleControls = {
|
||||
|
@ -60,18 +33,20 @@ const std::map<Mixer::Control, std::vector<Mixer::ControlNamesAndExpectedCtlType
|
|||
{Mixer::HW_VOLUME,
|
||||
{{"Headphone Playback Volume", MIXER_CTL_TYPE_INT},
|
||||
{"Headset Playback Volume", MIXER_CTL_TYPE_INT},
|
||||
{"PCM Playback Volume", MIXER_CTL_TYPE_INT}}}};
|
||||
{"PCM Playback Volume", MIXER_CTL_TYPE_INT}}},
|
||||
{Mixer::MIC_SWITCH, {{"Capture Switch", MIXER_CTL_TYPE_BOOL}}},
|
||||
{Mixer::MIC_GAIN, {{"Capture Volume", MIXER_CTL_TYPE_INT}}}};
|
||||
|
||||
// static
|
||||
std::map<Mixer::Control, std::shared_ptr<MixerControl>> Mixer::initializeMixerControls(
|
||||
struct mixer* mixer) {
|
||||
std::map<Mixer::Control, std::shared_ptr<MixerControl>> mixerControls;
|
||||
Mixer::Controls Mixer::initializeMixerControls(struct mixer* mixer) {
|
||||
if (mixer == nullptr) return {};
|
||||
Controls mixerControls;
|
||||
std::string mixerCtlNames;
|
||||
for (const auto& [control, possibleCtls] : kPossibleControls) {
|
||||
for (const auto& [ctlName, expectedCtlType] : possibleCtls) {
|
||||
struct mixer_ctl* ctl = mixer_get_ctl_by_name(mixer, ctlName.c_str());
|
||||
if (ctl != nullptr && mixer_ctl_get_type(ctl) == expectedCtlType) {
|
||||
mixerControls.emplace(control, std::make_unique<MixerControl>(ctl));
|
||||
mixerControls.emplace(control, ctl);
|
||||
if (!mixerCtlNames.empty()) {
|
||||
mixerCtlNames += ",";
|
||||
}
|
||||
|
@ -84,71 +59,141 @@ std::map<Mixer::Control, std::shared_ptr<MixerControl>> Mixer::initializeMixerCo
|
|||
return mixerControls;
|
||||
}
|
||||
|
||||
Mixer::Mixer(struct mixer* mixer)
|
||||
: mMixer(mixer), mMixerControls(initializeMixerControls(mMixer)) {}
|
||||
std::ostream& operator<<(std::ostream& s, Mixer::Control c) {
|
||||
switch (c) {
|
||||
case Mixer::Control::MASTER_SWITCH:
|
||||
s << "master mute";
|
||||
break;
|
||||
case Mixer::Control::MASTER_VOLUME:
|
||||
s << "master volume";
|
||||
break;
|
||||
case Mixer::Control::HW_VOLUME:
|
||||
s << "volume";
|
||||
break;
|
||||
case Mixer::Control::MIC_SWITCH:
|
||||
s << "mic mute";
|
||||
break;
|
||||
case Mixer::Control::MIC_GAIN:
|
||||
s << "mic gain";
|
||||
break;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
Mixer::Mixer(int card) : mMixer(mixer_open(card)), mMixerControls(initializeMixerControls(mMixer)) {
|
||||
if (!isValid()) {
|
||||
PLOG(ERROR) << __func__ << ": failed to open mixer for card=" << card;
|
||||
}
|
||||
}
|
||||
|
||||
Mixer::~Mixer() {
|
||||
mixer_close(mMixer);
|
||||
if (isValid()) {
|
||||
std::lock_guard l(mMixerAccess);
|
||||
mixer_close(mMixer);
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
int volumeFloatToInteger(float fValue, int maxValue, int minValue) {
|
||||
return minValue + std::ceil((maxValue - minValue) * fValue);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ndk::ScopedAStatus Mixer::setMasterMute(bool muted) {
|
||||
auto it = mMixerControls.find(Mixer::MASTER_SWITCH);
|
||||
if (it == mMixerControls.end()) {
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
|
||||
}
|
||||
const int numValues = it->second->getNumValues();
|
||||
std::vector<int> values(numValues, muted ? 0 : 1);
|
||||
if (int err = it->second->setArray(values.data(), numValues); err != 0) {
|
||||
LOG(ERROR) << __func__ << ": failed to set master mute, err=" << err;
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
}
|
||||
return ndk::ScopedAStatus::ok();
|
||||
return setMixerControlMute(MASTER_SWITCH, muted);
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Mixer::setMasterVolume(float volume) {
|
||||
auto it = mMixerControls.find(Mixer::MASTER_VOLUME);
|
||||
if (it == mMixerControls.end()) {
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
|
||||
}
|
||||
const int numValues = it->second->getNumValues();
|
||||
std::vector<int> values(numValues, volumeFloatToInteger(volume, it->second->getMaxValue(),
|
||||
it->second->getMinValue()));
|
||||
if (int err = it->second->setArray(values.data(), numValues); err != 0) {
|
||||
LOG(ERROR) << __func__ << ": failed to set master volume, err=" << err;
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
}
|
||||
return ndk::ScopedAStatus::ok();
|
||||
return setMixerControlVolume(MASTER_VOLUME, volume);
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Mixer::setMicGain(float gain) {
|
||||
return setMixerControlVolume(MIC_GAIN, gain);
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Mixer::setMicMute(bool muted) {
|
||||
return setMixerControlMute(MIC_SWITCH, muted);
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Mixer::setVolumes(const std::vector<float>& volumes) {
|
||||
if (!isValid()) {
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
}
|
||||
auto it = mMixerControls.find(Mixer::HW_VOLUME);
|
||||
if (it == mMixerControls.end()) {
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
|
||||
}
|
||||
const int numValues = it->second->getNumValues();
|
||||
if (numValues < 0) {
|
||||
LOG(FATAL) << __func__ << ": negative number of values: " << numValues;
|
||||
}
|
||||
const int maxValue = it->second->getMaxValue();
|
||||
const int minValue = it->second->getMinValue();
|
||||
std::vector<int> values;
|
||||
size_t i = 0;
|
||||
for (; i < static_cast<size_t>(numValues) && i < values.size(); ++i) {
|
||||
values.emplace_back(volumeFloatToInteger(volumes[i], maxValue, minValue));
|
||||
}
|
||||
if (int err = it->second->setArray(values.data(), values.size()); err != 0) {
|
||||
std::vector<int> percents;
|
||||
std::transform(
|
||||
volumes.begin(), volumes.end(), std::back_inserter(percents),
|
||||
[](float volume) -> int { return std::floor(std::clamp(volume, 0.0f, 1.0f) * 100); });
|
||||
std::lock_guard l(mMixerAccess);
|
||||
if (int err = setMixerControlPercent(it->second, percents); err != 0) {
|
||||
LOG(ERROR) << __func__ << ": failed to set volume, err=" << err;
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
}
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Mixer::setMixerControlMute(Mixer::Control ctl, bool muted) {
|
||||
if (!isValid()) {
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
}
|
||||
auto it = mMixerControls.find(ctl);
|
||||
if (it == mMixerControls.end()) {
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
|
||||
}
|
||||
std::lock_guard l(mMixerAccess);
|
||||
if (int err = setMixerControlValue(it->second, muted ? 0 : 1); err != 0) {
|
||||
LOG(ERROR) << __func__ << ": failed to set " << ctl << " to " << muted << ", err=" << err;
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
}
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Mixer::setMixerControlVolume(Control ctl, float volume) {
|
||||
if (!isValid()) {
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
}
|
||||
auto it = mMixerControls.find(ctl);
|
||||
if (it == mMixerControls.end()) {
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
|
||||
}
|
||||
volume = std::clamp(volume, 0.0f, 1.0f);
|
||||
std::lock_guard l(mMixerAccess);
|
||||
if (int err = setMixerControlPercent(it->second, std::floor(volume * 100)); err != 0) {
|
||||
LOG(ERROR) << __func__ << ": failed to set " << ctl << " to " << volume << ", err=" << err;
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
}
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
int Mixer::setMixerControlPercent(struct mixer_ctl* ctl, int percent) {
|
||||
int ret = 0;
|
||||
const unsigned int n = mixer_ctl_get_num_values(ctl);
|
||||
for (unsigned int id = 0; id < n; id++) {
|
||||
if (int error = mixer_ctl_set_percent(ctl, id, percent); error != 0) {
|
||||
ret = error;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Mixer::setMixerControlPercent(struct mixer_ctl* ctl, const std::vector<int>& percents) {
|
||||
int ret = 0;
|
||||
const unsigned int n = mixer_ctl_get_num_values(ctl);
|
||||
for (unsigned int id = 0; id < n; id++) {
|
||||
if (int error = mixer_ctl_set_percent(ctl, id, id < percents.size() ? percents[id] : 0);
|
||||
error != 0) {
|
||||
ret = error;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Mixer::setMixerControlValue(struct mixer_ctl* ctl, int value) {
|
||||
int ret = 0;
|
||||
const unsigned int n = mixer_ctl_get_num_values(ctl);
|
||||
for (unsigned int id = 0; id < n; id++) {
|
||||
if (int error = mixer_ctl_set_value(ctl, id, value); error != 0) {
|
||||
ret = error;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace aidl::android::hardware::audio::core::alsa
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
@ -31,34 +32,17 @@ extern "C" {
|
|||
|
||||
namespace aidl::android::hardware::audio::core::alsa {
|
||||
|
||||
class MixerControl {
|
||||
public:
|
||||
explicit MixerControl(struct mixer_ctl* ctl);
|
||||
|
||||
unsigned int getNumValues() const;
|
||||
int getMaxValue() const;
|
||||
int getMinValue() const;
|
||||
int setArray(const void* array, size_t count);
|
||||
|
||||
private:
|
||||
std::mutex mLock;
|
||||
// The mixer_ctl object is owned by ALSA and will be released when the mixer is closed.
|
||||
struct mixer_ctl* mCtl GUARDED_BY(mLock);
|
||||
const unsigned int mNumValues;
|
||||
const int mMinValue;
|
||||
const int mMaxValue;
|
||||
};
|
||||
|
||||
class Mixer {
|
||||
public:
|
||||
explicit Mixer(struct mixer* mixer);
|
||||
|
||||
explicit Mixer(int card);
|
||||
~Mixer();
|
||||
|
||||
bool isValid() const { return mMixer != nullptr; }
|
||||
|
||||
ndk::ScopedAStatus setMasterMute(bool muted);
|
||||
ndk::ScopedAStatus setMasterVolume(float volume);
|
||||
ndk::ScopedAStatus setMicGain(float gain);
|
||||
ndk::ScopedAStatus setMicMute(bool muted);
|
||||
ndk::ScopedAStatus setVolumes(const std::vector<float>& volumes);
|
||||
|
||||
private:
|
||||
|
@ -66,17 +50,32 @@ class Mixer {
|
|||
MASTER_SWITCH,
|
||||
MASTER_VOLUME,
|
||||
HW_VOLUME,
|
||||
MIC_SWITCH,
|
||||
MIC_GAIN,
|
||||
};
|
||||
using ControlNamesAndExpectedCtlType = std::pair<std::string, enum mixer_ctl_type>;
|
||||
static const std::map<Control, std::vector<ControlNamesAndExpectedCtlType>> kPossibleControls;
|
||||
static std::map<Control, std::shared_ptr<MixerControl>> initializeMixerControls(
|
||||
struct mixer* mixer);
|
||||
using Controls = std::map<Control, struct mixer_ctl*>;
|
||||
|
||||
friend std::ostream& operator<<(std::ostream&, Control);
|
||||
static const std::map<Control, std::vector<ControlNamesAndExpectedCtlType>> kPossibleControls;
|
||||
static Controls initializeMixerControls(struct mixer* mixer);
|
||||
|
||||
ndk::ScopedAStatus setMixerControlMute(Control ctl, bool muted);
|
||||
ndk::ScopedAStatus setMixerControlVolume(Control ctl, float volume);
|
||||
|
||||
int setMixerControlPercent(struct mixer_ctl* ctl, int percent) REQUIRES(mMixerAccess);
|
||||
int setMixerControlPercent(struct mixer_ctl* ctl, const std::vector<int>& percents)
|
||||
REQUIRES(mMixerAccess);
|
||||
int setMixerControlValue(struct mixer_ctl* ctl, int value) REQUIRES(mMixerAccess);
|
||||
|
||||
// Since ALSA functions do not use internal locking, enforce thread safety at our level.
|
||||
std::mutex mMixerAccess;
|
||||
// The mixer object is owned by ALSA and will be released when the mixer is closed.
|
||||
struct mixer* mMixer;
|
||||
struct mixer* const mMixer;
|
||||
// `mMixerControls` will only be initialized in constructor. After that, it wil only be
|
||||
// read but not be modified.
|
||||
const std::map<Control, std::shared_ptr<MixerControl>> mMixerControls;
|
||||
// read but not be modified. Each mixer_ctl object is owned by ALSA, it's life span is
|
||||
// the same as of the mixer itself.
|
||||
const Controls mMixerControls;
|
||||
};
|
||||
|
||||
} // namespace aidl::android::hardware::audio::core::alsa
|
||||
|
|
|
@ -27,16 +27,32 @@
|
|||
|
||||
namespace aidl::android::hardware::audio::core {
|
||||
|
||||
StreamAlsa::StreamAlsa(const Metadata& metadata, StreamContext&& context)
|
||||
: StreamCommonImpl(metadata, std::move(context)),
|
||||
StreamAlsa::StreamAlsa(const StreamContext& context, const Metadata& metadata, int readWriteRetries)
|
||||
: StreamCommonImpl(context, metadata),
|
||||
mFrameSizeBytes(getContext().getFrameSize()),
|
||||
mIsInput(isInput(metadata)),
|
||||
mConfig(alsa::getPcmConfig(getContext(), mIsInput)) {}
|
||||
mConfig(alsa::getPcmConfig(getContext(), mIsInput)),
|
||||
mReadWriteRetries(readWriteRetries) {}
|
||||
|
||||
::android::status_t StreamAlsa::init() {
|
||||
return mConfig.has_value() ? ::android::OK : ::android::NO_INIT;
|
||||
}
|
||||
|
||||
::android::status_t StreamAlsa::drain(StreamDescriptor::DrainMode) {
|
||||
usleep(1000);
|
||||
return ::android::OK;
|
||||
}
|
||||
|
||||
::android::status_t StreamAlsa::flush() {
|
||||
usleep(1000);
|
||||
return ::android::OK;
|
||||
}
|
||||
|
||||
::android::status_t StreamAlsa::pause() {
|
||||
usleep(1000);
|
||||
return ::android::OK;
|
||||
}
|
||||
|
||||
::android::status_t StreamAlsa::standby() {
|
||||
mAlsaDeviceProxies.clear();
|
||||
return ::android::OK;
|
||||
|
@ -45,27 +61,21 @@ StreamAlsa::StreamAlsa(const Metadata& metadata, StreamContext&& context)
|
|||
::android::status_t StreamAlsa::start() {
|
||||
decltype(mAlsaDeviceProxies) alsaDeviceProxies;
|
||||
for (const auto& device : getDeviceProfiles()) {
|
||||
auto profile = alsa::readAlsaDeviceInfo(device);
|
||||
if (!profile.has_value()) {
|
||||
LOG(ERROR) << __func__ << ": unable to read device info, device address=" << device;
|
||||
return ::android::UNKNOWN_ERROR;
|
||||
alsa::DeviceProxy proxy;
|
||||
if (device.isExternal) {
|
||||
// Always ask alsa configure as required since the configuration should be supported
|
||||
// by the connected device. That is guaranteed by `setAudioPortConfig` and
|
||||
// `setAudioPatch`.
|
||||
proxy = alsa::openProxyForExternalDevice(
|
||||
device, const_cast<struct pcm_config*>(&mConfig.value()),
|
||||
true /*require_exact_match*/);
|
||||
} else {
|
||||
proxy = alsa::openProxyForAttachedDevice(
|
||||
device, const_cast<struct pcm_config*>(&mConfig.value()),
|
||||
getContext().getBufferSizeInFrames());
|
||||
}
|
||||
|
||||
auto proxy = alsa::makeDeviceProxy();
|
||||
// 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.value(),
|
||||
const_cast<struct pcm_config*>(&mConfig.value()),
|
||||
true /*require_exact_match*/);
|
||||
err != 0) {
|
||||
LOG(ERROR) << __func__ << ": fail to prepare for device address=" << device
|
||||
<< " error=" << err;
|
||||
return ::android::UNKNOWN_ERROR;
|
||||
}
|
||||
if (int err = proxy_open(proxy.get()); err != 0) {
|
||||
LOG(ERROR) << __func__ << ": failed to open device, address=" << device
|
||||
<< " error=" << err;
|
||||
return ::android::UNKNOWN_ERROR;
|
||||
if (!proxy) {
|
||||
return ::android::NO_INIT;
|
||||
}
|
||||
alsaDeviceProxies.push_back(std::move(proxy));
|
||||
}
|
||||
|
@ -83,11 +93,12 @@ StreamAlsa::StreamAlsa(const Metadata& metadata, StreamContext&& context)
|
|||
return ::android::NO_INIT;
|
||||
}
|
||||
// For input case, only support single device.
|
||||
proxy_read(mAlsaDeviceProxies[0].get(), buffer, bytesToTransfer);
|
||||
proxy_read_with_retries(mAlsaDeviceProxies[0].get(), buffer, bytesToTransfer,
|
||||
mReadWriteRetries);
|
||||
maxLatency = proxy_get_latency(mAlsaDeviceProxies[0].get());
|
||||
} else {
|
||||
for (auto& proxy : mAlsaDeviceProxies) {
|
||||
proxy_write(proxy.get(), buffer, bytesToTransfer);
|
||||
proxy_write_with_retries(proxy.get(), buffer, bytesToTransfer, mReadWriteRetries);
|
||||
maxLatency = std::max(maxLatency, proxy_get_latency(proxy.get()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -217,7 +217,8 @@ std::optional<DeviceProfile> getDeviceProfile(
|
|||
}
|
||||
return DeviceProfile{.card = alsaAddress[0],
|
||||
.device = alsaAddress[1],
|
||||
.direction = isInput ? PCM_IN : PCM_OUT};
|
||||
.direction = isInput ? PCM_IN : PCM_OUT,
|
||||
.isExternal = !audioDevice.type.connection.empty()};
|
||||
}
|
||||
|
||||
std::optional<DeviceProfile> getDeviceProfile(
|
||||
|
@ -269,6 +270,57 @@ DeviceProxy makeDeviceProxy() {
|
|||
});
|
||||
}
|
||||
|
||||
DeviceProxy openProxyForAttachedDevice(const DeviceProfile& deviceProfile,
|
||||
struct pcm_config* pcmConfig, size_t bufferFrameCount) {
|
||||
if (deviceProfile.isExternal) {
|
||||
LOG(FATAL) << __func__ << ": called for an external device, address=" << deviceProfile;
|
||||
}
|
||||
alsa_device_profile profile;
|
||||
profile_init(&profile, deviceProfile.direction);
|
||||
profile.card = deviceProfile.card;
|
||||
profile.device = deviceProfile.device;
|
||||
if (!profile_fill_builtin_device_info(&profile, pcmConfig, bufferFrameCount)) {
|
||||
LOG(FATAL) << __func__ << ": failed to init for built-in device, address=" << deviceProfile;
|
||||
}
|
||||
auto proxy = makeDeviceProxy();
|
||||
if (int err = proxy_prepare_from_default_config(proxy.get(), &profile); err != 0) {
|
||||
LOG(FATAL) << __func__ << ": fail to prepare for device address=" << deviceProfile
|
||||
<< " error=" << err;
|
||||
return nullptr;
|
||||
}
|
||||
if (int err = proxy_open(proxy.get()); err != 0) {
|
||||
LOG(ERROR) << __func__ << ": failed to open device, address=" << deviceProfile
|
||||
<< " error=" << err;
|
||||
return nullptr;
|
||||
}
|
||||
return proxy;
|
||||
}
|
||||
|
||||
DeviceProxy openProxyForExternalDevice(const DeviceProfile& deviceProfile,
|
||||
struct pcm_config* pcmConfig, bool requireExactMatch) {
|
||||
if (!deviceProfile.isExternal) {
|
||||
LOG(FATAL) << __func__ << ": called for an attached device, address=" << deviceProfile;
|
||||
}
|
||||
auto profile = readAlsaDeviceInfo(deviceProfile);
|
||||
if (!profile.has_value()) {
|
||||
LOG(ERROR) << __func__ << ": unable to read device info, device address=" << deviceProfile;
|
||||
return nullptr;
|
||||
}
|
||||
auto proxy = makeDeviceProxy();
|
||||
if (int err = proxy_prepare(proxy.get(), &profile.value(), pcmConfig, requireExactMatch);
|
||||
err != 0) {
|
||||
LOG(ERROR) << __func__ << ": fail to prepare for device address=" << deviceProfile
|
||||
<< " error=" << err;
|
||||
return nullptr;
|
||||
}
|
||||
if (int err = proxy_open(proxy.get()); err != 0) {
|
||||
LOG(ERROR) << __func__ << ": failed to open device, address=" << deviceProfile
|
||||
<< " error=" << err;
|
||||
return nullptr;
|
||||
}
|
||||
return proxy;
|
||||
}
|
||||
|
||||
std::optional<alsa_device_profile> readAlsaDeviceInfo(const DeviceProfile& deviceProfile) {
|
||||
alsa_device_profile profile;
|
||||
profile_init(&profile, deviceProfile.direction);
|
||||
|
|
|
@ -40,6 +40,7 @@ struct DeviceProfile {
|
|||
int card;
|
||||
int device;
|
||||
int direction; /* PCM_OUT or PCM_IN */
|
||||
bool isExternal;
|
||||
};
|
||||
std::ostream& operator<<(std::ostream& os, const DeviceProfile& device);
|
||||
using DeviceProxyDeleter = std::function<void(alsa_device_proxy*)>;
|
||||
|
@ -60,6 +61,10 @@ std::optional<DeviceProfile> getDeviceProfile(
|
|||
std::optional<struct pcm_config> getPcmConfig(const StreamContext& context, bool isInput);
|
||||
std::vector<int> getSampleRatesFromProfile(const alsa_device_profile* profile);
|
||||
DeviceProxy makeDeviceProxy();
|
||||
DeviceProxy openProxyForAttachedDevice(const DeviceProfile& deviceProfile,
|
||||
struct pcm_config* pcmConfig, size_t bufferFrameCount);
|
||||
DeviceProxy openProxyForExternalDevice(const DeviceProfile& deviceProfile,
|
||||
struct pcm_config* pcmConfig, bool requireExactMatch);
|
||||
std::optional<alsa_device_profile> readAlsaDeviceInfo(const DeviceProfile& deviceProfile);
|
||||
|
||||
::aidl::android::media::audio::common::AudioFormatDescription
|
||||
|
|
|
@ -159,13 +159,13 @@ class Module : public BnModule {
|
|||
// The following virtual functions are intended for vendor extension via inheritance.
|
||||
|
||||
virtual ndk::ScopedAStatus createInputStream(
|
||||
const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
|
||||
StreamContext&& context,
|
||||
const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
|
||||
const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones,
|
||||
std::shared_ptr<StreamIn>* result) = 0;
|
||||
virtual ndk::ScopedAStatus createOutputStream(
|
||||
const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
|
||||
StreamContext&& context,
|
||||
const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
|
||||
const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
|
||||
offloadInfo,
|
||||
std::shared_ptr<StreamOut>* result) = 0;
|
||||
|
|
|
@ -28,13 +28,13 @@ class ModulePrimary final : public Module {
|
|||
ndk::ScopedAStatus getTelephony(std::shared_ptr<ITelephony>* _aidl_return) override;
|
||||
|
||||
ndk::ScopedAStatus createInputStream(
|
||||
const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
|
||||
StreamContext&& context,
|
||||
const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
|
||||
const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones,
|
||||
std::shared_ptr<StreamIn>* result) override;
|
||||
ndk::ScopedAStatus createOutputStream(
|
||||
const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
|
||||
StreamContext&& context,
|
||||
const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
|
||||
const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
|
||||
offloadInfo,
|
||||
std::shared_ptr<StreamOut>* result) override;
|
||||
|
|
|
@ -33,13 +33,13 @@ class ModuleRemoteSubmix : public Module {
|
|||
|
||||
// Module interfaces
|
||||
ndk::ScopedAStatus createInputStream(
|
||||
const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
|
||||
StreamContext&& context,
|
||||
const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
|
||||
const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones,
|
||||
std::shared_ptr<StreamIn>* result) override;
|
||||
ndk::ScopedAStatus createOutputStream(
|
||||
const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
|
||||
StreamContext&& context,
|
||||
const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
|
||||
const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
|
||||
offloadInfo,
|
||||
std::shared_ptr<StreamOut>* result) override;
|
||||
|
|
|
@ -30,13 +30,13 @@ class ModuleStub final : public Module {
|
|||
ndk::ScopedAStatus getBluetoothLe(std::shared_ptr<IBluetoothLe>* _aidl_return) override;
|
||||
|
||||
ndk::ScopedAStatus createInputStream(
|
||||
const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
|
||||
StreamContext&& context,
|
||||
const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
|
||||
const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones,
|
||||
std::shared_ptr<StreamIn>* result) override;
|
||||
ndk::ScopedAStatus createOutputStream(
|
||||
const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
|
||||
StreamContext&& context,
|
||||
const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
|
||||
const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
|
||||
offloadInfo,
|
||||
std::shared_ptr<StreamOut>* result) override;
|
||||
|
|
|
@ -33,13 +33,13 @@ class ModuleUsb final : public ModuleAlsa {
|
|||
|
||||
// Module interfaces
|
||||
ndk::ScopedAStatus createInputStream(
|
||||
const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
|
||||
StreamContext&& context,
|
||||
const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
|
||||
const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones,
|
||||
std::shared_ptr<StreamIn>* result) override;
|
||||
ndk::ScopedAStatus createOutputStream(
|
||||
const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
|
||||
StreamContext&& context,
|
||||
const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
|
||||
const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
|
||||
offloadInfo,
|
||||
std::shared_ptr<StreamOut>* result) override;
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#include <system/thread_defs.h>
|
||||
#include <utils/Errors.h>
|
||||
|
||||
#include "core-impl/ChildInterface.h"
|
||||
#include "core-impl/utils.h"
|
||||
|
||||
namespace aidl::android::hardware::audio::core {
|
||||
|
@ -132,6 +133,7 @@ class StreamContext {
|
|||
|
||||
void fillDescriptor(StreamDescriptor* desc);
|
||||
std::shared_ptr<IStreamCallback> getAsyncCallback() const { return mAsyncCallback; }
|
||||
size_t getBufferSizeInFrames() const;
|
||||
::aidl::android::media::audio::common::AudioChannelLayout getChannelLayout() const {
|
||||
return mChannelLayout;
|
||||
}
|
||||
|
@ -409,16 +411,17 @@ class StreamCommonDelegator : public BnStreamCommon {
|
|||
};
|
||||
|
||||
// The implementation of DriverInterface must be provided by each concrete stream implementation.
|
||||
// Note that StreamCommonImpl does not own the context. This is to support swapping on the fly
|
||||
// implementations of the stream while keeping the same IStreamIn/Out instance. It's that instance
|
||||
// who must be owner of the context.
|
||||
class StreamCommonImpl : virtual public StreamCommonInterface, virtual public DriverInterface {
|
||||
public:
|
||||
StreamCommonImpl(const Metadata& metadata, StreamContext&& context,
|
||||
StreamCommonImpl(const StreamContext& context, const Metadata& metadata,
|
||||
const StreamWorkerInterface::CreateInstance& createWorker)
|
||||
: mMetadata(metadata),
|
||||
mContext(std::move(context)),
|
||||
mWorker(createWorker(mContext, this)) {}
|
||||
StreamCommonImpl(const Metadata& metadata, StreamContext&& context)
|
||||
: mContext(context), mMetadata(metadata), mWorker(createWorker(mContext, this)) {}
|
||||
StreamCommonImpl(const StreamContext& context, const Metadata& metadata)
|
||||
: StreamCommonImpl(
|
||||
metadata, std::move(context),
|
||||
context, metadata,
|
||||
isInput(metadata) ? getDefaultInWorkerCreator() : getDefaultOutWorkerCreator()) {}
|
||||
~StreamCommonImpl();
|
||||
|
||||
|
@ -460,13 +463,13 @@ class StreamCommonImpl : virtual public StreamCommonInterface, virtual public Dr
|
|||
};
|
||||
}
|
||||
|
||||
virtual void onClose() = 0;
|
||||
void stopWorker();
|
||||
|
||||
const StreamContext& mContext;
|
||||
Metadata mMetadata;
|
||||
StreamContext mContext;
|
||||
std::unique_ptr<StreamWorkerInterface> mWorker;
|
||||
std::shared_ptr<StreamCommonDelegator> mCommon;
|
||||
ndk::SpAIBinder mCommonBinder;
|
||||
ChildInterface<StreamCommonDelegator> mCommon;
|
||||
ConnectedDevices mConnectedDevices;
|
||||
};
|
||||
|
||||
|
@ -474,6 +477,8 @@ class StreamCommonImpl : virtual public StreamCommonInterface, virtual public Dr
|
|||
// concrete input/output stream implementations.
|
||||
class StreamIn : virtual public StreamCommonInterface, public BnStreamIn {
|
||||
protected:
|
||||
void defaultOnClose();
|
||||
|
||||
ndk::ScopedAStatus getStreamCommon(std::shared_ptr<IStreamCommon>* _aidl_return) override {
|
||||
return getStreamCommonCommon(_aidl_return);
|
||||
}
|
||||
|
@ -493,14 +498,17 @@ class StreamIn : virtual public StreamCommonInterface, public BnStreamIn {
|
|||
|
||||
friend class ndk::SharedRefBase;
|
||||
|
||||
explicit StreamIn(
|
||||
const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones);
|
||||
StreamIn(StreamContext&& context,
|
||||
const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones);
|
||||
|
||||
StreamContext mContext;
|
||||
const std::map<::aidl::android::media::audio::common::AudioDevice, std::string> mMicrophones;
|
||||
};
|
||||
|
||||
class StreamOut : virtual public StreamCommonInterface, public BnStreamOut {
|
||||
protected:
|
||||
void defaultOnClose();
|
||||
|
||||
ndk::ScopedAStatus getStreamCommon(std::shared_ptr<IStreamCommon>* _aidl_return) override {
|
||||
return getStreamCommonCommon(_aidl_return);
|
||||
}
|
||||
|
@ -534,10 +542,12 @@ class StreamOut : virtual public StreamCommonInterface, public BnStreamOut {
|
|||
|
||||
friend class ndk::SharedRefBase;
|
||||
|
||||
explicit StreamOut(const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
|
||||
offloadInfo);
|
||||
StreamOut(StreamContext&& context,
|
||||
const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
|
||||
offloadInfo);
|
||||
|
||||
std::optional<::aidl::android::media::audio::common::AudioOffloadInfo> mOffloadInfo;
|
||||
StreamContext mContext;
|
||||
const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo> mOffloadInfo;
|
||||
std::optional<::aidl::android::hardware::audio::common::AudioOffloadMetadata> mOffloadMetadata;
|
||||
};
|
||||
|
||||
|
|
|
@ -31,9 +31,12 @@ namespace aidl::android::hardware::audio::core {
|
|||
// provide necessary overrides for all interface methods omitted here.
|
||||
class StreamAlsa : public StreamCommonImpl {
|
||||
public:
|
||||
StreamAlsa(const Metadata& metadata, StreamContext&& context);
|
||||
StreamAlsa(const StreamContext& context, const Metadata& metadata, int readWriteRetries);
|
||||
// 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,
|
||||
|
@ -48,6 +51,7 @@ class StreamAlsa : public StreamCommonImpl {
|
|||
const size_t mFrameSizeBytes;
|
||||
const bool mIsInput;
|
||||
const std::optional<struct pcm_config> mConfig;
|
||||
const int mReadWriteRetries;
|
||||
// All fields below are only used on the worker thread.
|
||||
std::vector<alsa::DeviceProxy> mAlsaDeviceProxies;
|
||||
};
|
||||
|
|
|
@ -29,7 +29,7 @@ using aidl::android::hardware::audio::core::r_submix::SubmixRoute;
|
|||
|
||||
class StreamRemoteSubmix : public StreamCommonImpl {
|
||||
public:
|
||||
StreamRemoteSubmix(const Metadata& metadata, StreamContext&& context);
|
||||
StreamRemoteSubmix(const StreamContext& context, const Metadata& metadata);
|
||||
|
||||
::android::status_t init() override;
|
||||
::android::status_t drain(StreamDescriptor::DrainMode) override;
|
||||
|
@ -72,28 +72,32 @@ class StreamRemoteSubmix : public StreamCommonImpl {
|
|||
static constexpr int kReadAttemptSleepUs = 5000;
|
||||
};
|
||||
|
||||
class StreamInRemoteSubmix final : public StreamRemoteSubmix, public StreamIn {
|
||||
class StreamInRemoteSubmix final : public StreamIn, public StreamRemoteSubmix {
|
||||
public:
|
||||
friend class ndk::SharedRefBase;
|
||||
StreamInRemoteSubmix(
|
||||
const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
|
||||
StreamContext&& context,
|
||||
const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
|
||||
const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones);
|
||||
|
||||
private:
|
||||
void onClose() override { defaultOnClose(); }
|
||||
ndk::ScopedAStatus getActiveMicrophones(
|
||||
std::vector<::aidl::android::media::audio::common::MicrophoneDynamicInfo>* _aidl_return)
|
||||
override;
|
||||
};
|
||||
|
||||
class StreamOutRemoteSubmix final : public StreamRemoteSubmix, public StreamOut {
|
||||
class StreamOutRemoteSubmix final : public StreamOut, public StreamRemoteSubmix {
|
||||
public:
|
||||
friend class ndk::SharedRefBase;
|
||||
StreamOutRemoteSubmix(
|
||||
const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
|
||||
StreamContext&& context,
|
||||
const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
|
||||
const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
|
||||
offloadInfo);
|
||||
|
||||
private:
|
||||
void onClose() override { defaultOnClose(); }
|
||||
};
|
||||
|
||||
} // namespace aidl::android::hardware::audio::core
|
||||
|
|
|
@ -22,7 +22,7 @@ namespace aidl::android::hardware::audio::core {
|
|||
|
||||
class StreamStub : public StreamCommonImpl {
|
||||
public:
|
||||
StreamStub(const Metadata& metadata, StreamContext&& context);
|
||||
StreamStub(const StreamContext& context, const Metadata& metadata);
|
||||
// Methods of 'DriverInterface'.
|
||||
::android::status_t init() override;
|
||||
::android::status_t drain(StreamDescriptor::DrainMode) override;
|
||||
|
@ -43,22 +43,28 @@ class StreamStub : public StreamCommonImpl {
|
|||
bool mIsStandby = true; // Used for validating the state machine logic.
|
||||
};
|
||||
|
||||
class StreamInStub final : public StreamStub, public StreamIn {
|
||||
class StreamInStub final : public StreamIn, public StreamStub {
|
||||
public:
|
||||
friend class ndk::SharedRefBase;
|
||||
StreamInStub(
|
||||
const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
|
||||
StreamContext&& context,
|
||||
const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
|
||||
const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones);
|
||||
|
||||
private:
|
||||
void onClose() override { defaultOnClose(); }
|
||||
};
|
||||
|
||||
class StreamOutStub final : public StreamStub, public StreamOut {
|
||||
class StreamOutStub final : public StreamOut, public StreamStub {
|
||||
public:
|
||||
friend class ndk::SharedRefBase;
|
||||
StreamOutStub(const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
|
||||
StreamContext&& context,
|
||||
StreamOutStub(StreamContext&& context,
|
||||
const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
|
||||
const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
|
||||
offloadInfo);
|
||||
|
||||
private:
|
||||
void onClose() override { defaultOnClose(); }
|
||||
};
|
||||
|
||||
} // namespace aidl::android::hardware::audio::core
|
||||
|
|
|
@ -28,11 +28,8 @@ namespace aidl::android::hardware::audio::core {
|
|||
|
||||
class StreamUsb : public StreamAlsa {
|
||||
public:
|
||||
StreamUsb(const Metadata& metadata, StreamContext&& context);
|
||||
StreamUsb(const StreamContext& context, const Metadata& metadata);
|
||||
// Methods of 'DriverInterface'.
|
||||
::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;
|
||||
|
||||
|
@ -47,29 +44,31 @@ class StreamUsb : public StreamAlsa {
|
|||
std::atomic<bool> mConnectedDevicesUpdated = false;
|
||||
};
|
||||
|
||||
class StreamInUsb final : public StreamUsb, public StreamIn {
|
||||
class StreamInUsb final : public StreamIn, public StreamUsb {
|
||||
public:
|
||||
friend class ndk::SharedRefBase;
|
||||
StreamInUsb(
|
||||
const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
|
||||
StreamContext&& context,
|
||||
const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
|
||||
const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones);
|
||||
|
||||
private:
|
||||
void onClose() override { defaultOnClose(); }
|
||||
ndk::ScopedAStatus getActiveMicrophones(
|
||||
std::vector<::aidl::android::media::audio::common::MicrophoneDynamicInfo>* _aidl_return)
|
||||
override;
|
||||
};
|
||||
|
||||
class StreamOutUsb final : public StreamUsb, public StreamOut {
|
||||
class StreamOutUsb final : public StreamOut, public StreamUsb {
|
||||
public:
|
||||
friend class ndk::SharedRefBase;
|
||||
StreamOutUsb(const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
|
||||
StreamContext&& context,
|
||||
StreamOutUsb(StreamContext&& context,
|
||||
const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
|
||||
const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
|
||||
offloadInfo);
|
||||
|
||||
private:
|
||||
void onClose() override { defaultOnClose(); }
|
||||
ndk::ScopedAStatus getHwVolume(std::vector<float>* _aidl_return) override;
|
||||
ndk::ScopedAStatus setHwVolume(const std::vector<float>& in_channelVolumes) override;
|
||||
|
||||
|
|
|
@ -56,16 +56,16 @@ ndk::ScopedAStatus ModuleRemoteSubmix::setMicMute(bool in_mute __unused) {
|
|||
}
|
||||
|
||||
ndk::ScopedAStatus ModuleRemoteSubmix::createInputStream(
|
||||
const SinkMetadata& sinkMetadata, StreamContext&& context,
|
||||
StreamContext&& context, const SinkMetadata& sinkMetadata,
|
||||
const std::vector<MicrophoneInfo>& microphones, std::shared_ptr<StreamIn>* result) {
|
||||
return createStreamInstance<StreamInRemoteSubmix>(result, sinkMetadata, std::move(context),
|
||||
return createStreamInstance<StreamInRemoteSubmix>(result, std::move(context), sinkMetadata,
|
||||
microphones);
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus ModuleRemoteSubmix::createOutputStream(
|
||||
const SourceMetadata& sourceMetadata, StreamContext&& context,
|
||||
StreamContext&& context, const SourceMetadata& sourceMetadata,
|
||||
const std::optional<AudioOffloadInfo>& offloadInfo, std::shared_ptr<StreamOut>* result) {
|
||||
return createStreamInstance<StreamOutRemoteSubmix>(result, sourceMetadata, std::move(context),
|
||||
return createStreamInstance<StreamOutRemoteSubmix>(result, std::move(context), sourceMetadata,
|
||||
offloadInfo);
|
||||
}
|
||||
|
||||
|
|
|
@ -29,8 +29,8 @@ using aidl::android::media::audio::common::MicrophoneInfo;
|
|||
|
||||
namespace aidl::android::hardware::audio::core {
|
||||
|
||||
StreamRemoteSubmix::StreamRemoteSubmix(const Metadata& metadata, StreamContext&& context)
|
||||
: StreamCommonImpl(metadata, std::move(context)),
|
||||
StreamRemoteSubmix::StreamRemoteSubmix(const StreamContext& context, const Metadata& metadata)
|
||||
: StreamCommonImpl(context, metadata),
|
||||
mPortId(context.getPortId()),
|
||||
mIsInput(isInput(metadata)) {
|
||||
mStreamConfig.frameSize = context.getFrameSize();
|
||||
|
@ -353,10 +353,11 @@ size_t StreamRemoteSubmix::getStreamPipeSizeInFrames() {
|
|||
return ::android::OK;
|
||||
}
|
||||
|
||||
StreamInRemoteSubmix::StreamInRemoteSubmix(const SinkMetadata& sinkMetadata,
|
||||
StreamContext&& context,
|
||||
StreamInRemoteSubmix::StreamInRemoteSubmix(StreamContext&& context,
|
||||
const SinkMetadata& sinkMetadata,
|
||||
const std::vector<MicrophoneInfo>& microphones)
|
||||
: StreamRemoteSubmix(sinkMetadata, std::move(context)), StreamIn(microphones) {}
|
||||
: StreamIn(std::move(context), microphones),
|
||||
StreamRemoteSubmix(StreamIn::mContext, sinkMetadata) {}
|
||||
|
||||
ndk::ScopedAStatus StreamInRemoteSubmix::getActiveMicrophones(
|
||||
std::vector<MicrophoneDynamicInfo>* _aidl_return) {
|
||||
|
@ -365,9 +366,10 @@ ndk::ScopedAStatus StreamInRemoteSubmix::getActiveMicrophones(
|
|||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
StreamOutRemoteSubmix::StreamOutRemoteSubmix(const SourceMetadata& sourceMetadata,
|
||||
StreamContext&& context,
|
||||
StreamOutRemoteSubmix::StreamOutRemoteSubmix(StreamContext&& context,
|
||||
const SourceMetadata& sourceMetadata,
|
||||
const std::optional<AudioOffloadInfo>& offloadInfo)
|
||||
: StreamRemoteSubmix(sourceMetadata, std::move(context)), StreamOut(offloadInfo) {}
|
||||
: StreamOut(std::move(context), offloadInfo),
|
||||
StreamRemoteSubmix(StreamOut::mContext, sourceMetadata) {}
|
||||
|
||||
} // namespace aidl::android::hardware::audio::core
|
||||
|
|
|
@ -38,7 +38,8 @@ ndk::ScopedAStatus ModuleStub::getBluetooth(std::shared_ptr<IBluetooth>* _aidl_r
|
|||
mBluetooth = ndk::SharedRefBase::make<Bluetooth>();
|
||||
}
|
||||
*_aidl_return = mBluetooth.getPtr();
|
||||
LOG(DEBUG) << __func__ << ": returning instance of IBluetooth: " << _aidl_return->get();
|
||||
LOG(DEBUG) << __func__
|
||||
<< ": returning instance of IBluetooth: " << _aidl_return->get()->asBinder().get();
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
|
@ -47,7 +48,8 @@ ndk::ScopedAStatus ModuleStub::getBluetoothA2dp(std::shared_ptr<IBluetoothA2dp>*
|
|||
mBluetoothA2dp = ndk::SharedRefBase::make<BluetoothA2dp>();
|
||||
}
|
||||
*_aidl_return = mBluetoothA2dp.getPtr();
|
||||
LOG(DEBUG) << __func__ << ": returning instance of IBluetoothA2dp: " << _aidl_return->get();
|
||||
LOG(DEBUG) << __func__ << ": returning instance of IBluetoothA2dp: "
|
||||
<< _aidl_return->get()->asBinder().get();
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
|
@ -56,22 +58,23 @@ ndk::ScopedAStatus ModuleStub::getBluetoothLe(std::shared_ptr<IBluetoothLe>* _ai
|
|||
mBluetoothLe = ndk::SharedRefBase::make<BluetoothLe>();
|
||||
}
|
||||
*_aidl_return = mBluetoothLe.getPtr();
|
||||
LOG(DEBUG) << __func__ << ": returning instance of IBluetoothLe: " << _aidl_return->get();
|
||||
LOG(DEBUG) << __func__
|
||||
<< ": returning instance of IBluetoothLe: " << _aidl_return->get()->asBinder().get();
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus ModuleStub::createInputStream(const SinkMetadata& sinkMetadata,
|
||||
StreamContext&& context,
|
||||
ndk::ScopedAStatus ModuleStub::createInputStream(StreamContext&& context,
|
||||
const SinkMetadata& sinkMetadata,
|
||||
const std::vector<MicrophoneInfo>& microphones,
|
||||
std::shared_ptr<StreamIn>* result) {
|
||||
return createStreamInstance<StreamInStub>(result, sinkMetadata, std::move(context),
|
||||
return createStreamInstance<StreamInStub>(result, std::move(context), sinkMetadata,
|
||||
microphones);
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus ModuleStub::createOutputStream(
|
||||
const SourceMetadata& sourceMetadata, StreamContext&& context,
|
||||
StreamContext&& context, const SourceMetadata& sourceMetadata,
|
||||
const std::optional<AudioOffloadInfo>& offloadInfo, std::shared_ptr<StreamOut>* result) {
|
||||
return createStreamInstance<StreamOutStub>(result, sourceMetadata, std::move(context),
|
||||
return createStreamInstance<StreamOutStub>(result, std::move(context), sourceMetadata,
|
||||
offloadInfo);
|
||||
}
|
||||
|
||||
|
|
|
@ -31,8 +31,8 @@ using aidl::android::media::audio::common::MicrophoneInfo;
|
|||
|
||||
namespace aidl::android::hardware::audio::core {
|
||||
|
||||
StreamStub::StreamStub(const Metadata& metadata, StreamContext&& context)
|
||||
: StreamCommonImpl(metadata, std::move(context)),
|
||||
StreamStub::StreamStub(const StreamContext& context, const Metadata& metadata)
|
||||
: StreamCommonImpl(context, metadata),
|
||||
mFrameSizeBytes(getContext().getFrameSize()),
|
||||
mSampleRate(getContext().getSampleRate()),
|
||||
mIsAsynchronous(!!getContext().getAsyncCallback()),
|
||||
|
@ -118,12 +118,12 @@ void StreamStub::shutdown() {
|
|||
mIsInitialized = false;
|
||||
}
|
||||
|
||||
StreamInStub::StreamInStub(const SinkMetadata& sinkMetadata, StreamContext&& context,
|
||||
StreamInStub::StreamInStub(StreamContext&& context, const SinkMetadata& sinkMetadata,
|
||||
const std::vector<MicrophoneInfo>& microphones)
|
||||
: StreamStub(sinkMetadata, std::move(context)), StreamIn(microphones) {}
|
||||
: StreamIn(std::move(context), microphones), StreamStub(StreamIn::mContext, sinkMetadata) {}
|
||||
|
||||
StreamOutStub::StreamOutStub(const SourceMetadata& sourceMetadata, StreamContext&& context,
|
||||
StreamOutStub::StreamOutStub(StreamContext&& context, const SourceMetadata& sourceMetadata,
|
||||
const std::optional<AudioOffloadInfo>& offloadInfo)
|
||||
: StreamStub(sourceMetadata, std::move(context)), StreamOut(offloadInfo) {}
|
||||
: StreamOut(std::move(context), offloadInfo), StreamStub(StreamOut::mContext, sourceMetadata) {}
|
||||
|
||||
} // namespace aidl::android::hardware::audio::core
|
||||
|
|
|
@ -68,22 +68,22 @@ ndk::ScopedAStatus ModuleUsb::setMicMute(bool in_mute __unused) {
|
|||
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus ModuleUsb::createInputStream(const SinkMetadata& sinkMetadata,
|
||||
StreamContext&& context,
|
||||
ndk::ScopedAStatus ModuleUsb::createInputStream(StreamContext&& context,
|
||||
const SinkMetadata& sinkMetadata,
|
||||
const std::vector<MicrophoneInfo>& microphones,
|
||||
std::shared_ptr<StreamIn>* result) {
|
||||
return createStreamInstance<StreamInUsb>(result, sinkMetadata, std::move(context), microphones);
|
||||
return createStreamInstance<StreamInUsb>(result, std::move(context), sinkMetadata, microphones);
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus ModuleUsb::createOutputStream(const SourceMetadata& sourceMetadata,
|
||||
StreamContext&& context,
|
||||
ndk::ScopedAStatus ModuleUsb::createOutputStream(StreamContext&& context,
|
||||
const SourceMetadata& sourceMetadata,
|
||||
const std::optional<AudioOffloadInfo>& offloadInfo,
|
||||
std::shared_ptr<StreamOut>* result) {
|
||||
if (offloadInfo.has_value()) {
|
||||
LOG(ERROR) << __func__ << ": offload is not supported";
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
|
||||
}
|
||||
return createStreamInstance<StreamOutUsb>(result, sourceMetadata, std::move(context),
|
||||
return createStreamInstance<StreamOutUsb>(result, std::move(context), sourceMetadata,
|
||||
offloadInfo);
|
||||
}
|
||||
|
||||
|
|
|
@ -35,8 +35,8 @@ using aidl::android::media::audio::common::MicrophoneInfo;
|
|||
|
||||
namespace aidl::android::hardware::audio::core {
|
||||
|
||||
StreamUsb::StreamUsb(const Metadata& metadata, StreamContext&& context)
|
||||
: StreamAlsa(metadata, std::move(context)) {}
|
||||
StreamUsb::StreamUsb(const StreamContext& context, const Metadata& metadata)
|
||||
: StreamAlsa(context, metadata, 1 /*readWriteRetries*/) {}
|
||||
|
||||
ndk::ScopedAStatus StreamUsb::setConnectedDevices(
|
||||
const std::vector<AudioDevice>& connectedDevices) {
|
||||
|
@ -55,28 +55,13 @@ ndk::ScopedAStatus StreamUsb::setConnectedDevices(
|
|||
}
|
||||
connectedDeviceProfiles.push_back(*profile);
|
||||
}
|
||||
RETURN_STATUS_IF_ERROR(StreamCommonImpl::setConnectedDevices(connectedDevices));
|
||||
RETURN_STATUS_IF_ERROR(setConnectedDevices(connectedDevices));
|
||||
std::lock_guard guard(mLock);
|
||||
mConnectedDeviceProfiles = std::move(connectedDeviceProfiles);
|
||||
mConnectedDevicesUpdated.store(true, std::memory_order_release);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
::android::status_t StreamUsb::drain(StreamDescriptor::DrainMode) {
|
||||
usleep(1000);
|
||||
return ::android::OK;
|
||||
}
|
||||
|
||||
::android::status_t StreamUsb::flush() {
|
||||
usleep(1000);
|
||||
return ::android::OK;
|
||||
}
|
||||
|
||||
::android::status_t StreamUsb::pause() {
|
||||
usleep(1000);
|
||||
return ::android::OK;
|
||||
}
|
||||
|
||||
::android::status_t StreamUsb::transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
|
||||
int32_t* latencyMs) {
|
||||
if (mConnectedDevicesUpdated.load(std::memory_order_acquire)) {
|
||||
|
@ -98,9 +83,9 @@ std::vector<alsa::DeviceProfile> StreamUsb::getDeviceProfiles() {
|
|||
return connectedDevices;
|
||||
}
|
||||
|
||||
StreamInUsb::StreamInUsb(const SinkMetadata& sinkMetadata, StreamContext&& context,
|
||||
StreamInUsb::StreamInUsb(StreamContext&& context, const SinkMetadata& sinkMetadata,
|
||||
const std::vector<MicrophoneInfo>& microphones)
|
||||
: StreamUsb(sinkMetadata, std::move(context)), StreamIn(microphones) {}
|
||||
: StreamIn(std::move(context), microphones), StreamUsb(StreamIn::mContext, sinkMetadata) {}
|
||||
|
||||
ndk::ScopedAStatus StreamInUsb::getActiveMicrophones(
|
||||
std::vector<MicrophoneDynamicInfo>* _aidl_return __unused) {
|
||||
|
@ -108,10 +93,10 @@ ndk::ScopedAStatus StreamInUsb::getActiveMicrophones(
|
|||
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
|
||||
}
|
||||
|
||||
StreamOutUsb::StreamOutUsb(const SourceMetadata& sourceMetadata, StreamContext&& context,
|
||||
StreamOutUsb::StreamOutUsb(StreamContext&& context, const SourceMetadata& sourceMetadata,
|
||||
const std::optional<AudioOffloadInfo>& offloadInfo)
|
||||
: StreamUsb(sourceMetadata, std::move(context)),
|
||||
StreamOut(offloadInfo),
|
||||
: StreamOut(std::move(context), offloadInfo),
|
||||
StreamUsb(StreamOut::mContext, sourceMetadata),
|
||||
mChannelCount(getChannelCount(getContext().getChannelLayout())) {}
|
||||
|
||||
ndk::ScopedAStatus StreamOutUsb::getHwVolume(std::vector<float>* _aidl_return) {
|
||||
|
|
|
@ -33,12 +33,10 @@ void UsbAlsaMixerControl::setDeviceConnectionState(int card, bool masterMuted, f
|
|||
bool connected) {
|
||||
LOG(DEBUG) << __func__ << ": card=" << card << ", connected=" << connected;
|
||||
if (connected) {
|
||||
struct mixer* mixer = mixer_open(card);
|
||||
if (mixer == nullptr) {
|
||||
PLOG(ERROR) << __func__ << ": failed to open mixer for card=" << card;
|
||||
auto alsaMixer = std::make_shared<alsa::Mixer>(card);
|
||||
if (!alsaMixer->isValid()) {
|
||||
return;
|
||||
}
|
||||
auto alsaMixer = std::make_shared<alsa::Mixer>(mixer);
|
||||
alsaMixer->setMasterMute(masterMuted);
|
||||
alsaMixer->setMasterVolume(masterVolume);
|
||||
const std::lock_guard guard(mLock);
|
||||
|
|
Loading…
Reference in a new issue