mirror of
https://github.com/Evolution-X/hardware_interfaces
synced 2026-02-01 11:36:00 +00:00
Merge "CSD: Add default AIDL HAL implementation" into main
This commit is contained in:
@@ -46,11 +46,20 @@ cc_library {
|
||||
"SoundDose.cpp",
|
||||
],
|
||||
shared_libs: [
|
||||
"libaudio_aidl_conversion_common_ndk",
|
||||
"libaudioutils",
|
||||
"libbase",
|
||||
"libbinder_ndk",
|
||||
"libcutils",
|
||||
"libutils",
|
||||
],
|
||||
cflags: [
|
||||
"-Wall",
|
||||
"-Wextra",
|
||||
"-Werror",
|
||||
"-Wthread-safety",
|
||||
"-DBACKEND_NDK",
|
||||
],
|
||||
visibility: [
|
||||
"//hardware/interfaces/audio/aidl/sounddose/default",
|
||||
],
|
||||
@@ -111,8 +120,12 @@ cc_library {
|
||||
shared_libs: [
|
||||
"android.hardware.bluetooth.audio-V3-ndk",
|
||||
"libaudio_aidl_conversion_common_ndk",
|
||||
"libaudioutils",
|
||||
"libaudioutils_nonvndk",
|
||||
"libbluetooth_audio_session_aidl",
|
||||
"liblog",
|
||||
"libmedia_helper",
|
||||
"libmediautils_vendor",
|
||||
"libstagefright_foundation",
|
||||
],
|
||||
export_shared_lib_headers: [
|
||||
@@ -143,8 +156,10 @@ cc_binary {
|
||||
],
|
||||
shared_libs: [
|
||||
"android.hardware.bluetooth.audio-V3-ndk",
|
||||
"libaudioutils_nonvndk",
|
||||
"libaudio_aidl_conversion_common_ndk",
|
||||
"libbluetooth_audio_session_aidl",
|
||||
"liblog",
|
||||
"libmedia_helper",
|
||||
"libstagefright_foundation",
|
||||
],
|
||||
|
||||
@@ -213,6 +213,11 @@ ndk::ScopedAStatus Module::createStreamContext(
|
||||
StreamContext::DebugParameters params{mDebug.streamTransientStateDelayMs,
|
||||
mVendorDebug.forceTransientBurst,
|
||||
mVendorDebug.forceSynchronousDrain};
|
||||
std::shared_ptr<ISoundDose> soundDose;
|
||||
if (!getSoundDose(&soundDose).isOk()) {
|
||||
LOG(ERROR) << __func__ << ": could not create sound dose instance";
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
}
|
||||
StreamContext temp(
|
||||
std::make_unique<StreamContext::CommandMQ>(1, true /*configureEventFlagWord*/),
|
||||
std::make_unique<StreamContext::ReplyMQ>(1, true /*configureEventFlagWord*/),
|
||||
@@ -220,7 +225,7 @@ ndk::ScopedAStatus Module::createStreamContext(
|
||||
portConfigIt->channelMask.value(), portConfigIt->sampleRate.value().value, flags,
|
||||
portConfigIt->ext.get<AudioPortExt::mix>().handle,
|
||||
std::make_unique<StreamContext::DataMQ>(frameSize * in_bufferSizeFrames),
|
||||
asyncCallback, outEventCallback, params);
|
||||
asyncCallback, outEventCallback, mSoundDose.getInstance(), params);
|
||||
if (temp.isValid()) {
|
||||
*out_context = std::move(temp);
|
||||
} else {
|
||||
|
||||
@@ -18,7 +18,15 @@
|
||||
|
||||
#include "core-impl/SoundDose.h"
|
||||
|
||||
#include <aidl/android/hardware/audio/core/sounddose/ISoundDose.h>
|
||||
#include <android-base/logging.h>
|
||||
#include <media/AidlConversionCppNdk.h>
|
||||
#include <utils/Timers.h>
|
||||
|
||||
using aidl::android::hardware::audio::core::sounddose::ISoundDose;
|
||||
using aidl::android::media::audio::common::AudioDevice;
|
||||
using aidl::android::media::audio::common::AudioDeviceDescription;
|
||||
using aidl::android::media::audio::common::AudioFormatDescription;
|
||||
|
||||
namespace aidl::android::hardware::audio::core::sounddose {
|
||||
|
||||
@@ -28,11 +36,16 @@ ndk::ScopedAStatus SoundDose::setOutputRs2UpperBound(float in_rs2ValueDbA) {
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
|
||||
}
|
||||
|
||||
::android::audio_utils::lock_guard l(mMutex);
|
||||
mRs2Value = in_rs2ValueDbA;
|
||||
if (mMelProcessor != nullptr) {
|
||||
mMelProcessor->setOutputRs2UpperBound(in_rs2ValueDbA);
|
||||
}
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus SoundDose::getOutputRs2UpperBound(float* _aidl_return) {
|
||||
::android::audio_utils::lock_guard l(mMutex);
|
||||
*_aidl_return = mRs2Value;
|
||||
LOG(DEBUG) << __func__ << ": returning " << *_aidl_return;
|
||||
return ndk::ScopedAStatus::ok();
|
||||
@@ -44,6 +57,8 @@ ndk::ScopedAStatus SoundDose::registerSoundDoseCallback(
|
||||
LOG(ERROR) << __func__ << ": Callback is nullptr";
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
|
||||
}
|
||||
|
||||
::android::audio_utils::lock_guard l(mCbMutex);
|
||||
if (mCallback != nullptr) {
|
||||
LOG(ERROR) << __func__ << ": Sound dose callback was already registered";
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
@@ -51,7 +66,81 @@ ndk::ScopedAStatus SoundDose::registerSoundDoseCallback(
|
||||
|
||||
mCallback = in_callback;
|
||||
LOG(DEBUG) << __func__ << ": Registered sound dose callback ";
|
||||
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
void SoundDose::setAudioDevice(const AudioDevice& audioDevice) {
|
||||
::android::audio_utils::lock_guard l(mCbMutex);
|
||||
mAudioDevice = audioDevice;
|
||||
}
|
||||
|
||||
void SoundDose::startDataProcessor(uint32_t sampleRate, uint32_t channelCount,
|
||||
const AudioFormatDescription& aidlFormat) {
|
||||
::android::audio_utils::lock_guard l(mMutex);
|
||||
const auto result = aidl2legacy_AudioFormatDescription_audio_format_t(aidlFormat);
|
||||
const audio_format_t format = result.value_or(AUDIO_FORMAT_INVALID);
|
||||
|
||||
if (mMelProcessor == nullptr) {
|
||||
// we don't have the deviceId concept on the vendor side so just pass 0
|
||||
mMelProcessor = ::android::sp<::android::audio_utils::MelProcessor>::make(
|
||||
sampleRate, channelCount, format, mMelCallback, /*deviceId=*/0, mRs2Value);
|
||||
} else {
|
||||
mMelProcessor->updateAudioFormat(sampleRate, channelCount, format);
|
||||
}
|
||||
}
|
||||
|
||||
void SoundDose::process(const void* buffer, size_t bytes) {
|
||||
::android::audio_utils::lock_guard l(mMutex);
|
||||
if (mMelProcessor != nullptr) {
|
||||
mMelProcessor->process(buffer, bytes);
|
||||
}
|
||||
}
|
||||
|
||||
void SoundDose::onNewMelValues(const std::vector<float>& mels, size_t offset, size_t length,
|
||||
audio_port_handle_t deviceId __attribute__((__unused__))) const {
|
||||
::android::audio_utils::lock_guard l(mCbMutex);
|
||||
if (!mAudioDevice.has_value()) {
|
||||
LOG(WARNING) << __func__ << ": New mel values without a registered device";
|
||||
return;
|
||||
}
|
||||
if (mCallback == nullptr) {
|
||||
LOG(ERROR) << __func__ << ": New mel values without a registered callback";
|
||||
return;
|
||||
}
|
||||
|
||||
ISoundDose::IHalSoundDoseCallback::MelRecord melRecord;
|
||||
melRecord.timestamp = nanoseconds_to_seconds(systemTime());
|
||||
melRecord.melValues = std::vector<float>(mels.begin() + offset, mels.begin() + offset + length);
|
||||
|
||||
mCallback->onNewMelValues(melRecord, mAudioDevice.value());
|
||||
}
|
||||
|
||||
void SoundDose::MelCallback::onNewMelValues(const std::vector<float>& mels, size_t offset,
|
||||
size_t length,
|
||||
audio_port_handle_t deviceId
|
||||
__attribute__((__unused__))) const {
|
||||
mSoundDose.onNewMelValues(mels, offset, length, deviceId);
|
||||
}
|
||||
|
||||
void SoundDose::onMomentaryExposure(float currentMel, audio_port_handle_t deviceId
|
||||
__attribute__((__unused__))) const {
|
||||
::android::audio_utils::lock_guard l(mCbMutex);
|
||||
if (!mAudioDevice.has_value()) {
|
||||
LOG(WARNING) << __func__ << ": Momentary exposure without a registered device";
|
||||
return;
|
||||
}
|
||||
if (mCallback == nullptr) {
|
||||
LOG(ERROR) << __func__ << ": Momentary exposure without a registered callback";
|
||||
return;
|
||||
}
|
||||
|
||||
mCallback->onMomentaryExposureWarning(currentMel, mAudioDevice.value());
|
||||
}
|
||||
|
||||
void SoundDose::MelCallback::onMomentaryExposure(float currentMel, audio_port_handle_t deviceId
|
||||
__attribute__((__unused__))) const {
|
||||
mSoundDose.onMomentaryExposure(currentMel, deviceId);
|
||||
}
|
||||
|
||||
} // namespace aidl::android::hardware::audio::core::sounddose
|
||||
|
||||
@@ -90,6 +90,14 @@ bool StreamContext::isValid() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
void StreamContext::startStreamDataProcessor() {
|
||||
auto streamDataProcessor = mStreamDataProcessor.lock();
|
||||
if (streamDataProcessor != nullptr) {
|
||||
streamDataProcessor->startDataProcessor(mSampleRate, getChannelCount(mChannelLayout),
|
||||
mFormat);
|
||||
}
|
||||
}
|
||||
|
||||
void StreamContext::reset() {
|
||||
mCommandMQ.reset();
|
||||
mReplyMQ.reset();
|
||||
@@ -593,6 +601,10 @@ bool StreamOutWorkerLogic::write(size_t clientSize, StreamDescriptor::Reply* rep
|
||||
fatal = true;
|
||||
LOG(ERROR) << __func__ << ": write failed: " << status;
|
||||
}
|
||||
auto streamDataProcessor = mContext->getStreamDataProcessor().lock();
|
||||
if (streamDataProcessor != nullptr) {
|
||||
streamDataProcessor->process(mDataBuffer.get(), actualFrameCount * frameSize);
|
||||
}
|
||||
} else {
|
||||
if (mContext->getAsyncCallback() == nullptr) {
|
||||
usleep(3000); // Simulate blocking transfer delay.
|
||||
|
||||
@@ -157,7 +157,7 @@ class Module : public BnModule {
|
||||
bool mMicMute = false;
|
||||
bool mMasterMute = false;
|
||||
float mMasterVolume = 1.0f;
|
||||
ChildInterface<sounddose::ISoundDose> mSoundDose;
|
||||
ChildInterface<sounddose::SoundDose> mSoundDose;
|
||||
std::optional<bool> mIsMmapSupported;
|
||||
|
||||
protected:
|
||||
|
||||
@@ -20,23 +20,68 @@
|
||||
|
||||
#include <aidl/android/hardware/audio/core/sounddose/BnSoundDose.h>
|
||||
#include <aidl/android/media/audio/common/AudioDevice.h>
|
||||
|
||||
using aidl::android::media::audio::common::AudioDevice;
|
||||
#include <aidl/android/media/audio/common/AudioFormatDescription.h>
|
||||
#include <audio_utils/MelProcessor.h>
|
||||
#include <audio_utils/mutex.h>
|
||||
|
||||
namespace aidl::android::hardware::audio::core::sounddose {
|
||||
|
||||
class SoundDose : public BnSoundDose {
|
||||
// Interface used for processing the data received by a stream.
|
||||
class StreamDataProcessorInterface {
|
||||
public:
|
||||
SoundDose() : mRs2Value(DEFAULT_MAX_RS2){};
|
||||
virtual ~StreamDataProcessorInterface() = default;
|
||||
|
||||
virtual void startDataProcessor(
|
||||
uint32_t samplerate, uint32_t channelCount,
|
||||
const ::aidl::android::media::audio::common::AudioFormatDescription& format) = 0;
|
||||
virtual void setAudioDevice(
|
||||
const ::aidl::android::media::audio::common::AudioDevice& audioDevice) = 0;
|
||||
virtual void process(const void* buffer, size_t size) = 0;
|
||||
};
|
||||
|
||||
class SoundDose final : public BnSoundDose, public StreamDataProcessorInterface {
|
||||
public:
|
||||
SoundDose() : mMelCallback(::android::sp<MelCallback>::make(this)){};
|
||||
|
||||
// -------------------------------------- BnSoundDose ------------------------------------------
|
||||
ndk::ScopedAStatus setOutputRs2UpperBound(float in_rs2ValueDbA) override;
|
||||
ndk::ScopedAStatus getOutputRs2UpperBound(float* _aidl_return) override;
|
||||
ndk::ScopedAStatus registerSoundDoseCallback(
|
||||
const std::shared_ptr<ISoundDose::IHalSoundDoseCallback>& in_callback) override;
|
||||
|
||||
// ----------------------------- StreamDataProcessorInterface ----------------------------------
|
||||
void setAudioDevice(
|
||||
const ::aidl::android::media::audio::common::AudioDevice& audioDevice) override;
|
||||
void startDataProcessor(
|
||||
uint32_t samplerate, uint32_t channelCount,
|
||||
const ::aidl::android::media::audio::common::AudioFormatDescription& format) override;
|
||||
void process(const void* buffer, size_t size) override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<ISoundDose::IHalSoundDoseCallback> mCallback;
|
||||
float mRs2Value;
|
||||
class MelCallback : public ::android::audio_utils::MelProcessor::MelCallback {
|
||||
public:
|
||||
explicit MelCallback(SoundDose* soundDose) : mSoundDose(*soundDose) {}
|
||||
|
||||
// ------------------------------------ MelCallback ----------------------------------------
|
||||
void onNewMelValues(const std::vector<float>& mels, size_t offset, size_t length,
|
||||
audio_port_handle_t deviceId) const override;
|
||||
void onMomentaryExposure(float currentMel, audio_port_handle_t deviceId) const override;
|
||||
|
||||
SoundDose& mSoundDose; // must outlive MelCallback, not owning
|
||||
};
|
||||
|
||||
void onNewMelValues(const std::vector<float>& mels, size_t offset, size_t length,
|
||||
audio_port_handle_t deviceId) const;
|
||||
void onMomentaryExposure(float currentMel, audio_port_handle_t deviceId) const;
|
||||
|
||||
mutable ::android::audio_utils::mutex mCbMutex;
|
||||
std::shared_ptr<ISoundDose::IHalSoundDoseCallback> mCallback GUARDED_BY(mCbMutex);
|
||||
std::optional<::aidl::android::media::audio::common::AudioDevice> mAudioDevice
|
||||
GUARDED_BY(mCbMutex);
|
||||
mutable ::android::audio_utils::mutex mMutex;
|
||||
float mRs2Value GUARDED_BY(mMutex) = DEFAULT_MAX_RS2;
|
||||
::android::sp<::android::audio_utils::MelProcessor> mMelProcessor GUARDED_BY(mMutex);
|
||||
::android::sp<MelCallback> mMelCallback GUARDED_BY(mMutex);
|
||||
};
|
||||
|
||||
} // namespace aidl::android::hardware::audio::core::sounddose
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
#include <utils/Errors.h>
|
||||
|
||||
#include "core-impl/ChildInterface.h"
|
||||
#include "core-impl/SoundDose.h"
|
||||
#include "core-impl/utils.h"
|
||||
|
||||
namespace aidl::android::hardware::audio::core {
|
||||
@@ -87,6 +88,7 @@ class StreamContext {
|
||||
int32_t mixPortHandle, std::unique_ptr<DataMQ> dataMQ,
|
||||
std::shared_ptr<IStreamCallback> asyncCallback,
|
||||
std::shared_ptr<IStreamOutEventCallback> outEventCallback,
|
||||
std::weak_ptr<sounddose::StreamDataProcessorInterface> streamDataProcessor,
|
||||
DebugParameters debugParameters)
|
||||
: mCommandMQ(std::move(commandMQ)),
|
||||
mInternalCommandCookie(std::rand()),
|
||||
@@ -100,6 +102,7 @@ class StreamContext {
|
||||
mDataMQ(std::move(dataMQ)),
|
||||
mAsyncCallback(asyncCallback),
|
||||
mOutEventCallback(outEventCallback),
|
||||
mStreamDataProcessor(streamDataProcessor),
|
||||
mDebugParameters(debugParameters) {}
|
||||
StreamContext(StreamContext&& other)
|
||||
: mCommandMQ(std::move(other.mCommandMQ)),
|
||||
@@ -114,6 +117,7 @@ class StreamContext {
|
||||
mDataMQ(std::move(other.mDataMQ)),
|
||||
mAsyncCallback(std::move(other.mAsyncCallback)),
|
||||
mOutEventCallback(std::move(other.mOutEventCallback)),
|
||||
mStreamDataProcessor(std::move(other.mStreamDataProcessor)),
|
||||
mDebugParameters(std::move(other.mDebugParameters)),
|
||||
mFrameCount(other.mFrameCount) {}
|
||||
StreamContext& operator=(StreamContext&& other) {
|
||||
@@ -129,6 +133,7 @@ class StreamContext {
|
||||
mDataMQ = std::move(other.mDataMQ);
|
||||
mAsyncCallback = std::move(other.mAsyncCallback);
|
||||
mOutEventCallback = std::move(other.mOutEventCallback);
|
||||
mStreamDataProcessor = std::move(other.mStreamDataProcessor);
|
||||
mDebugParameters = std::move(other.mDebugParameters);
|
||||
mFrameCount = other.mFrameCount;
|
||||
return *this;
|
||||
@@ -154,6 +159,10 @@ class StreamContext {
|
||||
std::shared_ptr<IStreamOutEventCallback> getOutEventCallback() const {
|
||||
return mOutEventCallback;
|
||||
}
|
||||
std::weak_ptr<sounddose::StreamDataProcessorInterface> getStreamDataProcessor() const {
|
||||
return mStreamDataProcessor;
|
||||
}
|
||||
void startStreamDataProcessor();
|
||||
int getPortId() const { return mPortId; }
|
||||
ReplyMQ* getReplyMQ() const { return mReplyMQ.get(); }
|
||||
int getTransientStateDelayMs() const { return mDebugParameters.transientStateDelayMs; }
|
||||
@@ -179,6 +188,7 @@ class StreamContext {
|
||||
std::unique_ptr<DataMQ> mDataMQ;
|
||||
std::shared_ptr<IStreamCallback> mAsyncCallback;
|
||||
std::shared_ptr<IStreamOutEventCallback> mOutEventCallback; // Only used by output streams
|
||||
std::weak_ptr<sounddose::StreamDataProcessorInterface> mStreamDataProcessor;
|
||||
DebugParameters mDebugParameters;
|
||||
long mFrameCount = 0;
|
||||
};
|
||||
|
||||
@@ -79,6 +79,10 @@ class StreamOutPrimary final : public StreamOut,
|
||||
|
||||
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
|
||||
|
||||
@@ -37,7 +37,9 @@ using android::base::GetBoolProperty;
|
||||
namespace aidl::android::hardware::audio::core {
|
||||
|
||||
StreamPrimary::StreamPrimary(StreamContext* context, const Metadata& metadata)
|
||||
: StreamAlsa(context, metadata, 3 /*readWriteRetries*/), mIsInput(isInput(metadata)) {}
|
||||
: StreamAlsa(context, metadata, 3 /*readWriteRetries*/), mIsInput(isInput(metadata)) {
|
||||
context->startStreamDataProcessor();
|
||||
}
|
||||
|
||||
std::vector<alsa::DeviceProfile> StreamPrimary::getDeviceProfiles() {
|
||||
static const std::vector<alsa::DeviceProfile> kBuiltInSource{
|
||||
@@ -183,4 +185,15 @@ 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
|
||||
|
||||
Reference in New Issue
Block a user