audio: import aidl hal
* hardware/interfaces/audio/aidl/default/ at android-16.0.0_r1.
This commit is contained in:
32
audio/include/core-impl/AidlConversionXsdc.h
Normal file
32
audio/include/core-impl/AidlConversionXsdc.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <aidl/android/hardware/audio/core/SurroundSoundConfig.h>
|
||||
#include <aidl/android/media/audio/common/AudioFormatDescription.h>
|
||||
#include <android_audio_policy_configuration.h>
|
||||
#include <media/AidlConversionUtil.h>
|
||||
|
||||
namespace aidl::android::hardware::audio::core::internal {
|
||||
|
||||
ConversionResult<::aidl::android::media::audio::common::AudioFormatDescription>
|
||||
xsdc2aidl_AudioFormatDescription(const std::string& xsdc);
|
||||
|
||||
ConversionResult<SurroundSoundConfig> xsdc2aidl_SurroundSoundConfig(
|
||||
const ::android::audio::policy::configuration::SurroundSound& xsdc);
|
||||
|
||||
} // namespace aidl::android::hardware::audio::core::internal
|
||||
84
audio/include/core-impl/AudioPolicyConfigXmlConverter.h
Normal file
84
audio/include/core-impl/AudioPolicyConfigXmlConverter.h
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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 <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <aidl/android/hardware/audio/core/SurroundSoundConfig.h>
|
||||
#include <aidl/android/media/audio/common/AudioHalEngineConfig.h>
|
||||
#include <android_audio_policy_configuration.h>
|
||||
#include <android_audio_policy_configuration_enums.h>
|
||||
#include <media/AidlConversionUtil.h>
|
||||
|
||||
#include "core-impl/Module.h"
|
||||
#include "core-impl/XmlConverter.h"
|
||||
|
||||
namespace aidl::android::hardware::audio::core::internal {
|
||||
|
||||
class AudioPolicyConfigXmlConverter {
|
||||
public:
|
||||
using ModuleConfiguration = std::pair<std::string, std::unique_ptr<Module::Configuration>>;
|
||||
using ModuleConfigs = std::vector<ModuleConfiguration>;
|
||||
|
||||
explicit AudioPolicyConfigXmlConverter(const std::string& configFilePath)
|
||||
: mConverter(configFilePath, &::android::audio::policy::configuration::read) {
|
||||
if (mConverter.getXsdcConfig()) {
|
||||
init();
|
||||
}
|
||||
}
|
||||
|
||||
std::string getError() const { return mConverter.getError(); }
|
||||
::android::status_t getStatus() const { return mConverter.getStatus(); }
|
||||
|
||||
const ::aidl::android::media::audio::common::AudioHalEngineConfig& getAidlEngineConfig();
|
||||
const SurroundSoundConfig& getSurroundSoundConfig();
|
||||
std::unique_ptr<ModuleConfigs> releaseModuleConfigs();
|
||||
|
||||
// Public for testing purposes.
|
||||
static const SurroundSoundConfig& getDefaultSurroundSoundConfig();
|
||||
|
||||
private:
|
||||
const std::optional<::android::audio::policy::configuration::AudioPolicyConfiguration>&
|
||||
getXsdcConfig() const {
|
||||
return mConverter.getXsdcConfig();
|
||||
}
|
||||
void addVolumeGroupstoEngineConfig();
|
||||
void init();
|
||||
void mapStreamToVolumeCurve(
|
||||
const ::android::audio::policy::configuration::Volume& xsdcVolumeCurve);
|
||||
void mapStreamsToVolumeCurves();
|
||||
void parseVolumes();
|
||||
ConversionResult<::aidl::android::media::audio::common::AudioHalVolumeCurve>
|
||||
convertVolumeCurveToAidl(
|
||||
const ::android::audio::policy::configuration::Volume& xsdcVolumeCurve);
|
||||
|
||||
::aidl::android::media::audio::common::AudioHalEngineConfig mAidlEngineConfig;
|
||||
XmlConverter<::android::audio::policy::configuration::AudioPolicyConfiguration> mConverter;
|
||||
std::unordered_map<std::string, ::android::audio::policy::configuration::Reference>
|
||||
mVolumesReferenceMap;
|
||||
std::unordered_map<::android::audio::policy::configuration::AudioStreamType,
|
||||
std::vector<::aidl::android::media::audio::common::AudioHalVolumeCurve>>
|
||||
mStreamToVolumeCurvesMap;
|
||||
std::unique_ptr<ModuleConfigs> mModuleConfigurations = std::make_unique<ModuleConfigs>();
|
||||
};
|
||||
|
||||
} // namespace aidl::android::hardware::audio::core::internal
|
||||
76
audio/include/core-impl/Bluetooth.h
Normal file
76
audio/include/core-impl/Bluetooth.h
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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 <aidl/android/hardware/audio/core/BnBluetooth.h>
|
||||
#include <aidl/android/hardware/audio/core/BnBluetoothA2dp.h>
|
||||
#include <aidl/android/hardware/audio/core/BnBluetoothLe.h>
|
||||
|
||||
namespace aidl::android::hardware::audio::core {
|
||||
|
||||
class ParamChangeHandler {
|
||||
public:
|
||||
ParamChangeHandler() = default;
|
||||
void registerHandler(std::function<ndk::ScopedAStatus()> handler) { mHandler = handler; }
|
||||
|
||||
protected:
|
||||
std::function<ndk::ScopedAStatus()> mHandler = nullptr;
|
||||
};
|
||||
|
||||
class Bluetooth : public BnBluetooth {
|
||||
public:
|
||||
Bluetooth();
|
||||
|
||||
private:
|
||||
ndk::ScopedAStatus setScoConfig(const ScoConfig& in_config, ScoConfig* _aidl_return) override;
|
||||
ndk::ScopedAStatus setHfpConfig(const HfpConfig& in_config, HfpConfig* _aidl_return) override;
|
||||
|
||||
ScoConfig mScoConfig;
|
||||
HfpConfig mHfpConfig;
|
||||
};
|
||||
|
||||
class BluetoothA2dp : public BnBluetoothA2dp, public ParamChangeHandler {
|
||||
public:
|
||||
BluetoothA2dp() = default;
|
||||
ndk::ScopedAStatus isEnabled(bool* _aidl_return) override;
|
||||
|
||||
private:
|
||||
ndk::ScopedAStatus setEnabled(bool in_enabled) override;
|
||||
ndk::ScopedAStatus supportsOffloadReconfiguration(bool* _aidl_return) override;
|
||||
ndk::ScopedAStatus reconfigureOffload(
|
||||
const std::vector<::aidl::android::hardware::audio::core::VendorParameter>&
|
||||
in_parameters) override;
|
||||
|
||||
bool mEnabled = false;
|
||||
};
|
||||
|
||||
class BluetoothLe : public BnBluetoothLe, public ParamChangeHandler {
|
||||
public:
|
||||
BluetoothLe() = default;
|
||||
ndk::ScopedAStatus isEnabled(bool* _aidl_return) override;
|
||||
|
||||
private:
|
||||
ndk::ScopedAStatus setEnabled(bool in_enabled) override;
|
||||
ndk::ScopedAStatus supportsOffloadReconfiguration(bool* _aidl_return) override;
|
||||
ndk::ScopedAStatus reconfigureOffload(
|
||||
const std::vector<::aidl::android::hardware::audio::core::VendorParameter>&
|
||||
in_parameters) override;
|
||||
|
||||
bool mEnabled = false;
|
||||
};
|
||||
|
||||
} // namespace aidl::android::hardware::audio::core
|
||||
76
audio/include/core-impl/CapEngineConfigXmlConverter.h
Normal file
76
audio/include/core-impl/CapEngineConfigXmlConverter.h
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* 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 <aidl/android/hardware/audio/core/BnConfig.h>
|
||||
#include <aidl/android/media/audio/common/AudioHalEngineConfig.h>
|
||||
#include <system/audio_config.h>
|
||||
|
||||
#include <android_audio_policy_capengine_configuration.h>
|
||||
#include <android_audio_policy_capengine_configuration_enums.h>
|
||||
|
||||
#include "EngineConfigXmlConverter.h"
|
||||
|
||||
namespace aidl::android::hardware::audio::core::internal {
|
||||
|
||||
namespace capconfiguration = ::android::audio::policy::capengine::configuration;
|
||||
namespace aidlcommon = ::aidl::android::media::audio::common;
|
||||
|
||||
class CapEngineConfigXmlConverter {
|
||||
public:
|
||||
explicit CapEngineConfigXmlConverter(const std::string& configFilePath)
|
||||
: mConverter(configFilePath, &capconfiguration::readConfigurableDomains) {
|
||||
if (mConverter.getXsdcConfig()) {
|
||||
init();
|
||||
}
|
||||
}
|
||||
std::string getError() const { return mConverter.getError(); }
|
||||
::android::status_t getStatus() const { return mConverter.getStatus(); }
|
||||
|
||||
std::optional<
|
||||
std::vector<std::optional<::aidl::android::media::audio::common::AudioHalCapDomain>>>&
|
||||
getAidlCapEngineConfig();
|
||||
|
||||
private:
|
||||
ConversionResult<std::vector<aidlcommon::AudioHalCapParameter>> convertSettingToAidl(
|
||||
const capconfiguration::SettingsType::Configuration& xsdcSetting);
|
||||
|
||||
ConversionResult<std::vector<aidlcommon::AudioHalCapConfiguration>> convertConfigurationsToAidl(
|
||||
const std::vector<capconfiguration::ConfigurationsType>& xsdcConfigurationsVec,
|
||||
const std::vector<capconfiguration::SettingsType>& xsdcSettingsVec);
|
||||
|
||||
ConversionResult<aidlcommon::AudioHalCapConfiguration> convertConfigurationToAidl(
|
||||
const capconfiguration::ConfigurationsType::Configuration& xsdcConfiguration,
|
||||
const capconfiguration::SettingsType::Configuration& xsdcSettingConfiguration);
|
||||
|
||||
ConversionResult<aidlcommon::AudioHalCapParameter> convertParamToAidl(
|
||||
const capconfiguration::ConfigurableElementSettingsType& element);
|
||||
|
||||
ConversionResult<aidlcommon::AudioHalCapConfiguration> convertConfigurationToAidl(
|
||||
const capconfiguration::ConfigurationsType::Configuration& xsdcConfiguration);
|
||||
ConversionResult<aidlcommon::AudioHalCapDomain> convertConfigurableDomainToAidl(
|
||||
const capconfiguration::ConfigurableDomainType& xsdcConfigurableDomain);
|
||||
|
||||
const std::optional<capconfiguration::ConfigurableDomains>& getXsdcConfig() {
|
||||
return mConverter.getXsdcConfig();
|
||||
}
|
||||
void init();
|
||||
|
||||
std::optional<std::vector<std::optional<aidlcommon::AudioHalCapDomain>>> mAidlCapDomains;
|
||||
XmlConverter<capconfiguration::ConfigurableDomains> mConverter;
|
||||
};
|
||||
} // namespace aidl::android::hardware::audio::core::internal
|
||||
59
audio/include/core-impl/ChildInterface.h
Normal file
59
audio/include/core-impl/ChildInterface.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include <android/binder_auto_utils.h>
|
||||
#include <android/binder_ibinder_platform.h>
|
||||
#include <system/thread_defs.h>
|
||||
|
||||
namespace aidl::android::hardware::audio::core {
|
||||
|
||||
// Helper used for interfaces that require a persistent instance. We hold them via a strong
|
||||
// pointer. The binder token is retained for a call to 'setMinSchedulerPolicy'.
|
||||
template <class C>
|
||||
struct ChildInterface : private std::pair<std::shared_ptr<C>, ndk::SpAIBinder> {
|
||||
ChildInterface() = default;
|
||||
ChildInterface& operator=(const std::shared_ptr<C>& c) {
|
||||
return operator=(std::shared_ptr<C>(c));
|
||||
}
|
||||
ChildInterface& operator=(std::shared_ptr<C>&& c) {
|
||||
this->first = std::move(c);
|
||||
return *this;
|
||||
}
|
||||
explicit operator bool() const { return !!this->first; }
|
||||
C& operator*() const { return *(this->first); }
|
||||
C* operator->() const { return this->first; }
|
||||
std::shared_ptr<C> getPtr() { return this->first; }
|
||||
// Use 'getInstance' when returning the interface instance.
|
||||
std::shared_ptr<C> getInstance() {
|
||||
(void)getBinder();
|
||||
return this->first;
|
||||
}
|
||||
AIBinder* getBinder() {
|
||||
if (this->second.get() == nullptr) {
|
||||
const auto binder = this->second = this->first->asBinder();
|
||||
AIBinder_setMinSchedulerPolicy(binder.get(), SCHED_NORMAL, ANDROID_PRIORITY_AUDIO);
|
||||
AIBinder_setInheritRt(binder.get(), true);
|
||||
}
|
||||
return this->second.get();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace aidl::android::hardware::audio::core
|
||||
43
audio/include/core-impl/Config.h
Normal file
43
audio/include/core-impl/Config.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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 <aidl/android/hardware/audio/core/BnConfig.h>
|
||||
#include <system/audio_config.h>
|
||||
|
||||
#include "AudioPolicyConfigXmlConverter.h"
|
||||
#include "EngineConfigXmlConverter.h"
|
||||
|
||||
namespace aidl::android::hardware::audio::core {
|
||||
static const std::string kEngineConfigFileName = "audio_policy_engine_configuration.xml";
|
||||
|
||||
class Config : public BnConfig {
|
||||
public:
|
||||
explicit Config(internal::AudioPolicyConfigXmlConverter& apConverter)
|
||||
: mAudioPolicyConverter(apConverter) {}
|
||||
|
||||
private:
|
||||
ndk::ScopedAStatus getSurroundSoundConfig(SurroundSoundConfig* _aidl_return) override;
|
||||
ndk::ScopedAStatus getEngineConfig(
|
||||
aidl::android::media::audio::common::AudioHalEngineConfig* _aidl_return) override;
|
||||
|
||||
internal::AudioPolicyConfigXmlConverter& mAudioPolicyConverter;
|
||||
internal::EngineConfigXmlConverter mEngConfigConverter{
|
||||
::android::audio_find_readable_configuration_file(kEngineConfigFileName.c_str())};
|
||||
};
|
||||
|
||||
} // namespace aidl::android::hardware::audio::core
|
||||
29
audio/include/core-impl/Configuration.h
Normal file
29
audio/include/core-impl/Configuration.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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 <memory>
|
||||
|
||||
#include "Module.h"
|
||||
|
||||
namespace aidl::android::hardware::audio::core::internal {
|
||||
|
||||
std::unique_ptr<Module::Configuration> getConfiguration(Module::Type moduleType);
|
||||
std::vector<aidl::android::media::audio::common::AudioProfile>
|
||||
getStandard16And24BitPcmAudioProfiles();
|
||||
|
||||
} // namespace aidl::android::hardware::audio::core::internal
|
||||
237
audio/include/core-impl/DevicePortProxy.h
Normal file
237
audio/include/core-impl/DevicePortProxy.h
Normal file
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
* Copyright 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
|
||||
#include <android-base/thread_annotations.h>
|
||||
|
||||
#include <aidl/android/hardware/audio/common/SinkMetadata.h>
|
||||
#include <aidl/android/hardware/audio/common/SourceMetadata.h>
|
||||
#include <aidl/android/hardware/bluetooth/audio/BluetoothAudioStatus.h>
|
||||
#include <aidl/android/hardware/bluetooth/audio/PcmConfiguration.h>
|
||||
#include <aidl/android/hardware/bluetooth/audio/PresentationPosition.h>
|
||||
#include <aidl/android/hardware/bluetooth/audio/SessionType.h>
|
||||
#include <aidl/android/media/audio/common/AudioDeviceDescription.h>
|
||||
|
||||
namespace android::bluetooth::audio::aidl {
|
||||
|
||||
enum class BluetoothStreamState : uint8_t {
|
||||
DISABLED = 0, // This stream is closing or Bluetooth profiles (A2DP/LE) is disabled
|
||||
STANDBY,
|
||||
STARTING,
|
||||
STARTED,
|
||||
SUSPENDING,
|
||||
UNKNOWN,
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const BluetoothStreamState& state);
|
||||
|
||||
/**
|
||||
* Proxy for Bluetooth Audio HW Module to communicate with Bluetooth Audio
|
||||
* Session Control. All methods are not thread safe, so users must acquire a
|
||||
* lock. Note: currently, getState() of DevicePortProxy is only used for
|
||||
* verbose logging, it is not locked, so the state may not be synchronized.
|
||||
*/
|
||||
class BluetoothAudioPort {
|
||||
public:
|
||||
BluetoothAudioPort() = default;
|
||||
virtual ~BluetoothAudioPort() = default;
|
||||
|
||||
/**
|
||||
* Fetch output control / data path of BluetoothAudioPort and setup
|
||||
* callbacks into BluetoothAudioProvider. If registerPort() returns false, the audio
|
||||
* HAL must delete this BluetoothAudioPort and return EINVAL to caller
|
||||
*/
|
||||
virtual bool registerPort(
|
||||
const ::aidl::android::media::audio::common::AudioDeviceDescription&) = 0;
|
||||
|
||||
/**
|
||||
* Unregister this BluetoothAudioPort from BluetoothAudioSessionControl.
|
||||
* Audio HAL must delete this BluetoothAudioPort after calling this.
|
||||
*/
|
||||
virtual void unregisterPort() = 0;
|
||||
|
||||
/**
|
||||
* When the Audio framework / HAL tries to query audio config about format,
|
||||
* channel mask and sample rate, it uses this function to fetch from the
|
||||
* Bluetooth stack
|
||||
*/
|
||||
virtual bool loadAudioConfig(
|
||||
::aidl::android::hardware::bluetooth::audio::PcmConfiguration&) = 0;
|
||||
|
||||
/**
|
||||
* When the Audio framework / HAL wants to change the stream state, it invokes
|
||||
* these 4 functions to control the Bluetooth stack (Audio Control Path).
|
||||
* Note: standby(), start() and suspend() will return true when there are no errors.
|
||||
|
||||
* Called by Audio framework / HAL to change the state to stand by. When A2DP/LE profile is
|
||||
* disabled, the port is first set to STANDBY by calling suspend and then mState is set to
|
||||
* DISABLED. To reset the state back to STANDBY this method is called.
|
||||
*/
|
||||
virtual bool standby() = 0;
|
||||
|
||||
/**
|
||||
* Called by Audio framework / HAL to start the stream
|
||||
*/
|
||||
virtual bool start() = 0;
|
||||
|
||||
/**
|
||||
* Called by Audio framework / HAL to suspend the stream
|
||||
*/
|
||||
virtual bool suspend() = 0;
|
||||
|
||||
/**
|
||||
* Called by Audio framework / HAL to stop the stream
|
||||
*/
|
||||
virtual void stop() = 0;
|
||||
|
||||
/**
|
||||
* Called by the Audio framework / HAL to fetch information about audio frames
|
||||
* presented to an external sink, or frames presented fror an internal sink
|
||||
*/
|
||||
virtual bool getPresentationPosition(
|
||||
::aidl::android::hardware::bluetooth::audio::PresentationPosition&) const = 0;
|
||||
|
||||
/**
|
||||
* Called by the Audio framework / HAL when the metadata of the stream's
|
||||
* source has been changed.
|
||||
*/
|
||||
virtual bool updateSourceMetadata(
|
||||
const ::aidl::android::hardware::audio::common::SourceMetadata&) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the Audio framework / HAL when the metadata of the stream's
|
||||
* sink has been changed.
|
||||
*/
|
||||
virtual bool updateSinkMetadata(
|
||||
const ::aidl::android::hardware::audio::common::SinkMetadata&) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current BluetoothStreamState
|
||||
*/
|
||||
virtual BluetoothStreamState getState() const = 0;
|
||||
|
||||
/**
|
||||
* Set the current BluetoothStreamState
|
||||
*/
|
||||
virtual bool setState(BluetoothStreamState) = 0;
|
||||
|
||||
virtual bool isA2dp() const = 0;
|
||||
|
||||
virtual bool isLeAudio() const = 0;
|
||||
|
||||
virtual bool getPreferredDataIntervalUs(size_t&) const = 0;
|
||||
|
||||
virtual size_t writeData(const void*, size_t) const { return 0; }
|
||||
|
||||
virtual size_t readData(void*, size_t) const { return 0; }
|
||||
};
|
||||
|
||||
class BluetoothAudioPortAidl : public BluetoothAudioPort {
|
||||
public:
|
||||
BluetoothAudioPortAidl();
|
||||
virtual ~BluetoothAudioPortAidl();
|
||||
|
||||
bool registerPort(const ::aidl::android::media::audio::common::AudioDeviceDescription&
|
||||
description) override;
|
||||
|
||||
void unregisterPort() override;
|
||||
|
||||
bool loadAudioConfig(
|
||||
::aidl::android::hardware::bluetooth::audio::PcmConfiguration& audio_cfg) override;
|
||||
|
||||
bool standby() override;
|
||||
bool start() override;
|
||||
bool suspend() override;
|
||||
void stop() override;
|
||||
|
||||
bool getPresentationPosition(::aidl::android::hardware::bluetooth::audio::PresentationPosition&
|
||||
presentation_position) const override;
|
||||
|
||||
bool updateSourceMetadata(const ::aidl::android::hardware::audio::common::SourceMetadata&
|
||||
sourceMetadata) const override;
|
||||
|
||||
bool updateSinkMetadata(const ::aidl::android::hardware::audio::common::SinkMetadata&
|
||||
sinkMetadata) const override;
|
||||
|
||||
/**
|
||||
* Return the current BluetoothStreamState
|
||||
* Note: This method is used for logging, does not lock, so value returned may not be latest
|
||||
*/
|
||||
BluetoothStreamState getState() const override NO_THREAD_SAFETY_ANALYSIS;
|
||||
|
||||
bool setState(BluetoothStreamState state) override;
|
||||
|
||||
bool isA2dp() const override;
|
||||
|
||||
bool isLeAudio() const override;
|
||||
|
||||
bool getPreferredDataIntervalUs(size_t& interval_us) const override;
|
||||
|
||||
protected:
|
||||
uint16_t mCookie;
|
||||
BluetoothStreamState mState GUARDED_BY(mCvMutex);
|
||||
::aidl::android::hardware::bluetooth::audio::SessionType mSessionType;
|
||||
// WR to support Mono: True if fetching Stereo and mixing into Mono
|
||||
bool mIsStereoToMono = false;
|
||||
|
||||
bool inUse() const;
|
||||
|
||||
std::string debugMessage() const;
|
||||
|
||||
private:
|
||||
// start()/suspend() report state change status via callback. Wait until kMaxWaitingTimeMs or a
|
||||
// state change after a call to start()/suspend() and analyse the returned status. Below mutex,
|
||||
// conditional variable serves this purpose.
|
||||
mutable std::mutex mCvMutex;
|
||||
std::condition_variable mInternalCv GUARDED_BY(mCvMutex);
|
||||
|
||||
// Check and initialize session type for |devices| If failed, this
|
||||
// BluetoothAudioPortAidl is not initialized and must be deleted.
|
||||
bool initSessionType(
|
||||
const ::aidl::android::media::audio::common::AudioDeviceDescription& description);
|
||||
|
||||
bool condWaitState(BluetoothStreamState state);
|
||||
|
||||
void controlResultHandler(
|
||||
uint16_t cookie,
|
||||
const ::aidl::android::hardware::bluetooth::audio::BluetoothAudioStatus& status);
|
||||
void sessionChangedHandler(uint16_t cookie);
|
||||
};
|
||||
|
||||
class BluetoothAudioPortAidlOut : public BluetoothAudioPortAidl {
|
||||
public:
|
||||
bool loadAudioConfig(
|
||||
::aidl::android::hardware::bluetooth::audio::PcmConfiguration& audio_cfg) override;
|
||||
|
||||
// The audio data path to the Bluetooth stack (Software encoding)
|
||||
size_t writeData(const void* buffer, size_t bytes) const override;
|
||||
};
|
||||
|
||||
class BluetoothAudioPortAidlIn : public BluetoothAudioPortAidl {
|
||||
public:
|
||||
// The audio data path from the Bluetooth stack (Software decoded)
|
||||
size_t readData(void* buffer, size_t bytes) const override;
|
||||
};
|
||||
|
||||
} // namespace android::bluetooth::audio::aidl
|
||||
53
audio/include/core-impl/DriverStubImpl.h
Normal file
53
audio/include/core-impl/DriverStubImpl.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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)
|
||||
: DriverStubImpl(context, 500 /*asyncSleepTimeUs*/) {}
|
||||
DriverStubImpl(const StreamContext& context, int asyncSleepTimeUs);
|
||||
|
||||
::android::status_t init(DriverCallbackInterface* callback) 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;
|
||||
|
||||
protected:
|
||||
const size_t mBufferSizeFrames;
|
||||
const size_t mFrameSizeBytes;
|
||||
const int mSampleRate;
|
||||
const bool mIsAsynchronous;
|
||||
const bool mIsInput;
|
||||
const int32_t mMixPortHandle;
|
||||
const int mAsyncSleepTimeUs;
|
||||
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
|
||||
86
audio/include/core-impl/EngineConfigXmlConverter.h
Normal file
86
audio/include/core-impl/EngineConfigXmlConverter.h
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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 <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <android_audio_policy_engine_configuration.h>
|
||||
#include <android_audio_policy_engine_configuration_enums.h>
|
||||
#include <media/AidlConversionUtil.h>
|
||||
|
||||
#include "core-impl/XmlConverter.h"
|
||||
|
||||
namespace aidl::android::hardware::audio::core::internal {
|
||||
|
||||
class EngineConfigXmlConverter {
|
||||
public:
|
||||
explicit EngineConfigXmlConverter(const std::string& configFilePath)
|
||||
: mConverter(configFilePath, &::android::audio::policy::engine::configuration::read) {
|
||||
if (mConverter.getXsdcConfig()) {
|
||||
init();
|
||||
}
|
||||
}
|
||||
|
||||
std::string getError() const { return mConverter.getError(); }
|
||||
::android::status_t getStatus() const { return mConverter.getStatus(); }
|
||||
|
||||
::aidl::android::media::audio::common::AudioHalEngineConfig& getAidlEngineConfig();
|
||||
|
||||
private:
|
||||
const std::optional<::android::audio::policy::engine::configuration::Configuration>&
|
||||
getXsdcConfig() {
|
||||
return mConverter.getXsdcConfig();
|
||||
}
|
||||
void init();
|
||||
void initProductStrategyMap();
|
||||
ConversionResult<::aidl::android::media::audio::common::AudioAttributes>
|
||||
convertAudioAttributesToAidl(
|
||||
const ::android::audio::policy::engine::configuration::AttributesType&
|
||||
xsdcAudioAttributes);
|
||||
ConversionResult<::aidl::android::media::audio::common::AudioHalAttributesGroup>
|
||||
convertAttributesGroupToAidl(
|
||||
const ::android::audio::policy::engine::configuration::AttributesGroup&
|
||||
xsdcAttributesGroup);
|
||||
ConversionResult<::aidl::android::media::audio::common::AudioHalProductStrategy>
|
||||
convertProductStrategyToAidl(const ::android::audio::policy::engine::configuration::
|
||||
ProductStrategies::ProductStrategy& xsdcProductStrategy);
|
||||
ConversionResult<int> convertProductStrategyIdToAidl(int xsdcId);
|
||||
ConversionResult<int> convertProductStrategyNameToAidl(
|
||||
const std::string& xsdcProductStrategyName);
|
||||
ConversionResult<::aidl::android::media::audio::common::AudioHalVolumeCurve>
|
||||
convertVolumeCurveToAidl(
|
||||
const ::android::audio::policy::engine::configuration::Volume& xsdcVolumeCurve);
|
||||
ConversionResult<::aidl::android::media::audio::common::AudioHalVolumeGroup>
|
||||
convertVolumeGroupToAidl(
|
||||
const ::android::audio::policy::engine::configuration::VolumeGroupsType::VolumeGroup&
|
||||
xsdcVolumeGroup);
|
||||
|
||||
::aidl::android::media::audio::common::AudioHalEngineConfig mAidlEngineConfig;
|
||||
XmlConverter<::android::audio::policy::engine::configuration::Configuration> mConverter;
|
||||
std::unordered_map<std::string,
|
||||
::android::audio::policy::engine::configuration::AttributesRefType>
|
||||
mAttributesReferenceMap;
|
||||
std::unordered_map<std::string, ::android::audio::policy::engine::configuration::VolumeRef>
|
||||
mVolumesReferenceMap;
|
||||
std::unordered_map<std::string, int> mProductStrategyMap;
|
||||
int mNextVendorStrategy = ::aidl::android::media::audio::common::AudioHalProductStrategy::
|
||||
VENDOR_STRATEGY_ID_START;
|
||||
std::optional<int> mDefaultProductStrategyId;
|
||||
};
|
||||
|
||||
} // namespace aidl::android::hardware::audio::core::internal
|
||||
281
audio/include/core-impl/Module.h
Normal file
281
audio/include/core-impl/Module.h
Normal file
@@ -0,0 +1,281 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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 <functional>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
|
||||
#include <Utils.h>
|
||||
#include <aidl/android/hardware/audio/core/BnModule.h>
|
||||
|
||||
#include "core-impl/ChildInterface.h"
|
||||
#include "core-impl/Stream.h"
|
||||
|
||||
namespace aidl::android::hardware::audio::core {
|
||||
|
||||
class Module : public BnModule {
|
||||
public:
|
||||
struct Configuration {
|
||||
std::vector<::aidl::android::media::audio::common::AudioPort> ports;
|
||||
std::vector<::aidl::android::media::audio::common::AudioPortConfig> portConfigs;
|
||||
std::vector<::aidl::android::media::audio::common::AudioPortConfig> initialConfigs;
|
||||
// Port id -> List of profiles to use when the device port state is set to 'connected'
|
||||
// in connection simulation mode.
|
||||
std::map<int32_t, std::vector<::aidl::android::media::audio::common::AudioProfile>>
|
||||
connectedProfiles;
|
||||
std::vector<AudioRoute> routes;
|
||||
std::vector<AudioPatch> patches;
|
||||
int32_t nextPortId = 1;
|
||||
int32_t nextPatchId = 1;
|
||||
};
|
||||
enum Type : int { DEFAULT, R_SUBMIX, STUB, USB, BLUETOOTH };
|
||||
|
||||
static std::shared_ptr<Module> createInstance(Type type) {
|
||||
return createInstance(type, std::make_unique<Configuration>());
|
||||
}
|
||||
static std::shared_ptr<Module> createInstance(Type type,
|
||||
std::unique_ptr<Configuration>&& config);
|
||||
static std::optional<Type> typeFromString(const std::string& type);
|
||||
|
||||
Module(Type type, std::unique_ptr<Configuration>&& config);
|
||||
|
||||
protected:
|
||||
// The vendor extension done via inheritance can override interface methods and augment
|
||||
// a call to the base implementation.
|
||||
|
||||
binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
|
||||
|
||||
ndk::ScopedAStatus setModuleDebug(
|
||||
const ::aidl::android::hardware::audio::core::ModuleDebug& in_debug) override;
|
||||
ndk::ScopedAStatus getTelephony(std::shared_ptr<ITelephony>* _aidl_return) override;
|
||||
ndk::ScopedAStatus getBluetooth(std::shared_ptr<IBluetooth>* _aidl_return) override;
|
||||
ndk::ScopedAStatus getBluetoothA2dp(std::shared_ptr<IBluetoothA2dp>* _aidl_return) override;
|
||||
ndk::ScopedAStatus getBluetoothLe(std::shared_ptr<IBluetoothLe>* _aidl_return) override;
|
||||
ndk::ScopedAStatus connectExternalDevice(
|
||||
const ::aidl::android::media::audio::common::AudioPort& in_templateIdAndAdditionalData,
|
||||
::aidl::android::media::audio::common::AudioPort* _aidl_return) override;
|
||||
ndk::ScopedAStatus disconnectExternalDevice(int32_t in_portId) override;
|
||||
ndk::ScopedAStatus prepareToDisconnectExternalDevice(int32_t in_portId) override;
|
||||
ndk::ScopedAStatus getAudioPatches(std::vector<AudioPatch>* _aidl_return) override;
|
||||
ndk::ScopedAStatus getAudioPort(
|
||||
int32_t in_portId,
|
||||
::aidl::android::media::audio::common::AudioPort* _aidl_return) override;
|
||||
ndk::ScopedAStatus getAudioPortConfigs(
|
||||
std::vector<::aidl::android::media::audio::common::AudioPortConfig>* _aidl_return)
|
||||
override;
|
||||
ndk::ScopedAStatus getAudioPorts(
|
||||
std::vector<::aidl::android::media::audio::common::AudioPort>* _aidl_return) override;
|
||||
ndk::ScopedAStatus getAudioRoutes(std::vector<AudioRoute>* _aidl_return) override;
|
||||
ndk::ScopedAStatus getAudioRoutesForAudioPort(
|
||||
int32_t in_portId,
|
||||
std::vector<::aidl::android::hardware::audio::core::AudioRoute>* _aidl_return) override;
|
||||
ndk::ScopedAStatus openInputStream(
|
||||
const ::aidl::android::hardware::audio::core::IModule::OpenInputStreamArguments&
|
||||
in_args,
|
||||
::aidl::android::hardware::audio::core::IModule::OpenInputStreamReturn* _aidl_return)
|
||||
override;
|
||||
ndk::ScopedAStatus openOutputStream(
|
||||
const ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments&
|
||||
in_args,
|
||||
::aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn* _aidl_return)
|
||||
override;
|
||||
ndk::ScopedAStatus getSupportedPlaybackRateFactors(
|
||||
SupportedPlaybackRateFactors* _aidl_return) override;
|
||||
ndk::ScopedAStatus setAudioPatch(const AudioPatch& in_requested,
|
||||
AudioPatch* _aidl_return) override;
|
||||
ndk::ScopedAStatus setAudioPortConfig(
|
||||
const ::aidl::android::media::audio::common::AudioPortConfig& in_requested,
|
||||
::aidl::android::media::audio::common::AudioPortConfig* out_suggested,
|
||||
bool* _aidl_return) override;
|
||||
ndk::ScopedAStatus resetAudioPatch(int32_t in_patchId) override;
|
||||
ndk::ScopedAStatus resetAudioPortConfig(int32_t in_portConfigId) override;
|
||||
ndk::ScopedAStatus getMasterMute(bool* _aidl_return) override;
|
||||
ndk::ScopedAStatus setMasterMute(bool in_mute) override;
|
||||
ndk::ScopedAStatus getMasterVolume(float* _aidl_return) override;
|
||||
ndk::ScopedAStatus setMasterVolume(float in_volume) override;
|
||||
ndk::ScopedAStatus getMicMute(bool* _aidl_return) override;
|
||||
ndk::ScopedAStatus setMicMute(bool in_mute) override;
|
||||
ndk::ScopedAStatus getMicrophones(
|
||||
std::vector<::aidl::android::media::audio::common::MicrophoneInfo>* _aidl_return)
|
||||
override;
|
||||
ndk::ScopedAStatus updateAudioMode(
|
||||
::aidl::android::media::audio::common::AudioMode in_mode) override;
|
||||
ndk::ScopedAStatus updateScreenRotation(
|
||||
::aidl::android::hardware::audio::core::IModule::ScreenRotation in_rotation) override;
|
||||
ndk::ScopedAStatus updateScreenState(bool in_isTurnedOn) override;
|
||||
ndk::ScopedAStatus getSoundDose(std::shared_ptr<sounddose::ISoundDose>* _aidl_return) override;
|
||||
ndk::ScopedAStatus generateHwAvSyncId(int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus getVendorParameters(const std::vector<std::string>& in_ids,
|
||||
std::vector<VendorParameter>* _aidl_return) override;
|
||||
ndk::ScopedAStatus setVendorParameters(const std::vector<VendorParameter>& in_parameters,
|
||||
bool in_async) override;
|
||||
ndk::ScopedAStatus addDeviceEffect(
|
||||
int32_t in_portConfigId,
|
||||
const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect)
|
||||
override;
|
||||
ndk::ScopedAStatus removeDeviceEffect(
|
||||
int32_t in_portConfigId,
|
||||
const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect)
|
||||
override;
|
||||
ndk::ScopedAStatus getMmapPolicyInfos(
|
||||
::aidl::android::media::audio::common::AudioMMapPolicyType mmapPolicyType,
|
||||
std::vector<::aidl::android::media::audio::common::AudioMMapPolicyInfo>* _aidl_return)
|
||||
override;
|
||||
ndk::ScopedAStatus supportsVariableLatency(bool* _aidl_return) override;
|
||||
ndk::ScopedAStatus getAAudioMixerBurstCount(int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus getAAudioHardwareBurstMinUsec(int32_t* _aidl_return) override;
|
||||
|
||||
// The maximum stream buffer size is 1 GiB = 2 ** 30 bytes;
|
||||
static constexpr int32_t kMaximumStreamBufferSizeBytes = 1 << 30;
|
||||
|
||||
private:
|
||||
struct VendorDebug {
|
||||
static const std::string kForceTransientBurstName;
|
||||
static const std::string kForceSynchronousDrainName;
|
||||
bool forceTransientBurst = false;
|
||||
bool forceSynchronousDrain = false;
|
||||
};
|
||||
// ids of device ports created at runtime via 'connectExternalDevice'.
|
||||
// Also stores a list of ids of mix ports with dynamic profiles that were populated from
|
||||
// the connected port. This list can be empty, thus an int->int multimap can't be used.
|
||||
using ConnectedDevicePorts = std::map<int32_t, std::set<int32_t>>;
|
||||
// Maps port ids and port config ids to patch ids.
|
||||
// Multimap because both ports and configs can be used by multiple patches.
|
||||
using Patches = std::multimap<int32_t, int32_t>;
|
||||
|
||||
static const std::string kClipTransitionSupportName;
|
||||
const Type mType;
|
||||
std::unique_ptr<Configuration> mConfig;
|
||||
ModuleDebug mDebug;
|
||||
VendorDebug mVendorDebug;
|
||||
ConnectedDevicePorts mConnectedDevicePorts;
|
||||
Streams mStreams;
|
||||
Patches mPatches;
|
||||
bool mMicMute = false;
|
||||
bool mMasterMute = false;
|
||||
float mMasterVolume = 1.0f;
|
||||
ChildInterface<sounddose::SoundDose> mSoundDose;
|
||||
std::optional<bool> mIsMmapSupported;
|
||||
|
||||
protected:
|
||||
// The following virtual functions are intended for vendor extension via inheritance.
|
||||
|
||||
virtual ndk::ScopedAStatus createInputStream(
|
||||
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(
|
||||
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;
|
||||
// If the module is unable to populate the connected device port correctly, the returned error
|
||||
// code must correspond to the errors of `IModule.connectedExternalDevice` method.
|
||||
virtual ndk::ScopedAStatus populateConnectedDevicePort(
|
||||
::aidl::android::media::audio::common::AudioPort* audioPort, int32_t nextPortId);
|
||||
// If the module finds that the patch endpoints configurations are not matched, the returned
|
||||
// error code must correspond to the errors of `IModule.setAudioPatch` method.
|
||||
virtual ndk::ScopedAStatus checkAudioPatchEndpointsMatch(
|
||||
const std::vector<::aidl::android::media::audio::common::AudioPortConfig*>& sources,
|
||||
const std::vector<::aidl::android::media::audio::common::AudioPortConfig*>& sinks);
|
||||
virtual void onExternalDeviceConnectionChanged(
|
||||
const ::aidl::android::media::audio::common::AudioPort& audioPort, bool connected);
|
||||
virtual void onPrepareToDisconnectExternalDevice(
|
||||
const ::aidl::android::media::audio::common::AudioPort& audioPort);
|
||||
virtual ndk::ScopedAStatus onMasterMuteChanged(bool mute);
|
||||
virtual ndk::ScopedAStatus onMasterVolumeChanged(float volume);
|
||||
virtual std::vector<::aidl::android::media::audio::common::MicrophoneInfo> getMicrophoneInfos();
|
||||
virtual std::unique_ptr<Configuration> initializeConfig();
|
||||
virtual int32_t getNominalLatencyMs(
|
||||
const ::aidl::android::media::audio::common::AudioPortConfig& portConfig);
|
||||
virtual ndk::ScopedAStatus calculateBufferSizeFrames(
|
||||
const ::aidl::android::media::audio::common::AudioFormatDescription &format,
|
||||
int32_t latencyMs, int32_t sampleRateHz, int32_t *bufferSizeFrames);
|
||||
virtual ndk::ScopedAStatus createMmapBuffer(
|
||||
const ::aidl::android::media::audio::common::AudioPortConfig& portConfig,
|
||||
int32_t bufferSizeFrames, int32_t frameSizeBytes, MmapBufferDescriptor* desc);
|
||||
|
||||
// Utility and helper functions accessible to subclasses.
|
||||
static int32_t calculateBufferSizeFramesForPcm(int32_t latencyMs, int32_t sampleRateHz) {
|
||||
const int32_t rawSizeFrames =
|
||||
aidl::android::hardware::audio::common::frameCountFromDurationMs(latencyMs,
|
||||
sampleRateHz);
|
||||
// Round up to nearest 16 frames since in the framework this is the size of a mixer burst.
|
||||
const int32_t multipleOf16 = (rawSizeFrames + 15) & ~15;
|
||||
if (sampleRateHz < 44100 || multipleOf16 <= 512) return multipleOf16;
|
||||
// Larger buffers should use powers of 2.
|
||||
int32_t powerOf2 = 1;
|
||||
while (powerOf2 < multipleOf16) powerOf2 <<= 1;
|
||||
return powerOf2;
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus bluetoothParametersUpdated();
|
||||
void cleanUpPatch(int32_t patchId);
|
||||
ndk::ScopedAStatus createStreamContext(
|
||||
int32_t in_portConfigId, int64_t in_bufferSizeFrames,
|
||||
std::shared_ptr<IStreamCallback> asyncCallback,
|
||||
std::shared_ptr<IStreamOutEventCallback> outEventCallback,
|
||||
::aidl::android::hardware::audio::core::StreamContext* out_context);
|
||||
std::vector<::aidl::android::media::audio::common::AudioDevice> findConnectedDevices(
|
||||
int32_t portConfigId);
|
||||
std::set<int32_t> findConnectedPortConfigIds(int32_t portConfigId);
|
||||
ndk::ScopedAStatus findPortIdForNewStream(
|
||||
int32_t in_portConfigId, ::aidl::android::media::audio::common::AudioPort** port);
|
||||
// Note: does not assign an ID to the config.
|
||||
bool generateDefaultPortConfig(const ::aidl::android::media::audio::common::AudioPort& port,
|
||||
::aidl::android::media::audio::common::AudioPortConfig* config);
|
||||
std::vector<AudioRoute*> getAudioRoutesForAudioPortImpl(int32_t portId);
|
||||
Configuration& getConfig();
|
||||
const ConnectedDevicePorts& getConnectedDevicePorts() const { return mConnectedDevicePorts; }
|
||||
std::vector<::aidl::android::media::audio::common::AudioDevice>
|
||||
getDevicesFromDevicePortConfigIds(const std::set<int32_t>& devicePortConfigIds);
|
||||
bool getMasterMute() const { return mMasterMute; }
|
||||
bool getMasterVolume() const { return mMasterVolume; }
|
||||
bool getMicMute() const { return mMicMute; }
|
||||
const ModuleDebug& getModuleDebug() const { return mDebug; }
|
||||
const Patches& getPatches() const { return mPatches; }
|
||||
std::set<int32_t> getRoutableAudioPortIds(int32_t portId,
|
||||
std::vector<AudioRoute*>* routes = nullptr);
|
||||
const Streams& getStreams() const { return mStreams; }
|
||||
Type getType() const { return mType; }
|
||||
bool isMmapSupported();
|
||||
void populateConnectedProfiles();
|
||||
template <typename C>
|
||||
std::set<int32_t> portIdsFromPortConfigIds(C portConfigIds);
|
||||
void registerPatch(const AudioPatch& patch);
|
||||
ndk::ScopedAStatus setAudioPortConfigImpl(
|
||||
const ::aidl::android::media::audio::common::AudioPortConfig& in_requested,
|
||||
const std::function<bool(const ::aidl::android::media::audio::common::AudioPort& port,
|
||||
::aidl::android::media::audio::common::AudioPortConfig*
|
||||
config)>& fillPortConfig,
|
||||
::aidl::android::media::audio::common::AudioPortConfig* out_suggested, bool* applied);
|
||||
ndk::ScopedAStatus updateStreamsConnectedState(const AudioPatch& oldPatch,
|
||||
const AudioPatch& newPatch);
|
||||
bool setAudioPortConfigGain(
|
||||
const ::aidl::android::media::audio::common::AudioPort& port,
|
||||
const ::aidl::android::media::audio::common::AudioGainConfig& gainRequested);
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, Module::Type t);
|
||||
|
||||
} // namespace aidl::android::hardware::audio::core
|
||||
40
audio/include/core-impl/ModuleAlsa.h
Normal file
40
audio/include/core-impl/ModuleAlsa.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core-impl/Module.h"
|
||||
|
||||
namespace aidl::android::hardware::audio::core {
|
||||
|
||||
// This class is intended to be used as a base class for implementations
|
||||
// that use TinyAlsa. This can be either a primary module or a USB Audio
|
||||
// module. This class does not define a complete module implementation,
|
||||
// and should never be used on its own. Derived classes are expected to
|
||||
// provide necessary overrides for all interface methods omitted here.
|
||||
class ModuleAlsa : public Module {
|
||||
public:
|
||||
ModuleAlsa(Type type, std::unique_ptr<Configuration>&& config)
|
||||
: Module(type, std::move(config)) {}
|
||||
|
||||
protected:
|
||||
// Extension methods of 'Module'.
|
||||
ndk::ScopedAStatus populateConnectedDevicePort(
|
||||
::aidl::android::media::audio::common::AudioPort* audioPort,
|
||||
int32_t nextPortId) override;
|
||||
};
|
||||
|
||||
} // namespace aidl::android::hardware::audio::core
|
||||
96
audio/include/core-impl/ModuleBluetooth.h
Normal file
96
audio/include/core-impl/ModuleBluetooth.h
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "core-impl/Bluetooth.h"
|
||||
#include "core-impl/DevicePortProxy.h"
|
||||
#include "core-impl/Module.h"
|
||||
|
||||
namespace aidl::android::hardware::audio::core {
|
||||
|
||||
class ModuleBluetooth final : public Module {
|
||||
public:
|
||||
enum BtInterface : int { BTSCO, BTA2DP, BTLE };
|
||||
typedef std::tuple<std::weak_ptr<IBluetooth>, std::weak_ptr<IBluetoothA2dp>,
|
||||
std::weak_ptr<IBluetoothLe>>
|
||||
BtProfileHandles;
|
||||
|
||||
ModuleBluetooth(std::unique_ptr<Configuration>&& config);
|
||||
|
||||
private:
|
||||
struct CachedProxy {
|
||||
std::shared_ptr<::android::bluetooth::audio::aidl::BluetoothAudioPortAidl> ptr;
|
||||
::aidl::android::hardware::bluetooth::audio::PcmConfiguration pcmConfig;
|
||||
};
|
||||
|
||||
ChildInterface<BluetoothA2dp>& getBtA2dp();
|
||||
ChildInterface<BluetoothLe>& getBtLe();
|
||||
BtProfileHandles getBtProfileManagerHandles();
|
||||
|
||||
ndk::ScopedAStatus getBluetoothA2dp(std::shared_ptr<IBluetoothA2dp>* _aidl_return) override;
|
||||
ndk::ScopedAStatus getBluetoothLe(std::shared_ptr<IBluetoothLe>* _aidl_return) override;
|
||||
ndk::ScopedAStatus getMicMute(bool* _aidl_return) override;
|
||||
ndk::ScopedAStatus setMicMute(bool in_mute) override;
|
||||
|
||||
ndk::ScopedAStatus setAudioPortConfig(
|
||||
const ::aidl::android::media::audio::common::AudioPortConfig& in_requested,
|
||||
::aidl::android::media::audio::common::AudioPortConfig* out_suggested,
|
||||
bool* _aidl_return) override;
|
||||
|
||||
ndk::ScopedAStatus checkAudioPatchEndpointsMatch(
|
||||
const std::vector<::aidl::android::media::audio::common::AudioPortConfig*>& sources,
|
||||
const std::vector<::aidl::android::media::audio::common::AudioPortConfig*>& sinks)
|
||||
override;
|
||||
void onExternalDeviceConnectionChanged(
|
||||
const ::aidl::android::media::audio::common::AudioPort& audioPort, bool connected);
|
||||
ndk::ScopedAStatus createInputStream(
|
||||
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(
|
||||
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;
|
||||
ndk::ScopedAStatus populateConnectedDevicePort(
|
||||
::aidl::android::media::audio::common::AudioPort* audioPort,
|
||||
int32_t nextPortId) override;
|
||||
ndk::ScopedAStatus onMasterMuteChanged(bool mute) override;
|
||||
ndk::ScopedAStatus onMasterVolumeChanged(float volume) override;
|
||||
int32_t getNominalLatencyMs(
|
||||
const ::aidl::android::media::audio::common::AudioPortConfig& portConfig) override;
|
||||
|
||||
ndk::ScopedAStatus createProxy(
|
||||
const ::aidl::android::media::audio::common::AudioPort& audioPort,
|
||||
int32_t instancePortId, CachedProxy& proxy);
|
||||
ndk::ScopedAStatus fetchAndCheckProxy(const StreamContext& context, CachedProxy& proxy);
|
||||
ndk::ScopedAStatus findOrCreateProxy(
|
||||
const ::aidl::android::media::audio::common::AudioPort& audioPort, CachedProxy& proxy);
|
||||
|
||||
static constexpr int kCreateProxyRetries = 5;
|
||||
static constexpr int kCreateProxyRetrySleepMs = 75;
|
||||
ChildInterface<BluetoothA2dp> mBluetoothA2dp;
|
||||
ChildInterface<BluetoothLe> mBluetoothLe;
|
||||
std::map<int32_t /*instantiated device port ID*/, CachedProxy> mProxies;
|
||||
std::map<int32_t /*mix port handle*/, int32_t /*instantiated device port ID*/> mConnections;
|
||||
};
|
||||
|
||||
} // namespace aidl::android::hardware::audio::core
|
||||
55
audio/include/core-impl/ModulePrimary.h
Normal file
55
audio/include/core-impl/ModulePrimary.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core-impl/Module.h"
|
||||
|
||||
namespace aidl::android::hardware::audio::core {
|
||||
|
||||
class ModulePrimary final : public Module {
|
||||
public:
|
||||
ModulePrimary(std::unique_ptr<Configuration>&& config)
|
||||
: Module(Type::DEFAULT, std::move(config)) {}
|
||||
|
||||
protected:
|
||||
ndk::ScopedAStatus getTelephony(std::shared_ptr<ITelephony>* _aidl_return) override;
|
||||
|
||||
ndk::ScopedAStatus calculateBufferSizeFrames(
|
||||
const ::aidl::android::media::audio::common::AudioFormatDescription& format,
|
||||
int32_t latencyMs, int32_t sampleRateHz, int32_t* bufferSizeFrames) override;
|
||||
ndk::ScopedAStatus createInputStream(
|
||||
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(
|
||||
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;
|
||||
ndk::ScopedAStatus createMmapBuffer(
|
||||
const ::aidl::android::media::audio::common::AudioPortConfig& portConfig,
|
||||
int32_t bufferSizeFrames, int32_t frameSizeBytes, MmapBufferDescriptor* desc) override;
|
||||
int32_t getNominalLatencyMs(
|
||||
const ::aidl::android::media::audio::common::AudioPortConfig& portConfig) override;
|
||||
|
||||
private:
|
||||
ChildInterface<ITelephony> mTelephony;
|
||||
};
|
||||
|
||||
} // namespace aidl::android::hardware::audio::core
|
||||
63
audio/include/core-impl/ModuleRemoteSubmix.h
Normal file
63
audio/include/core-impl/ModuleRemoteSubmix.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core-impl/Module.h"
|
||||
|
||||
namespace aidl::android::hardware::audio::core {
|
||||
|
||||
class ModuleRemoteSubmix : public Module {
|
||||
public:
|
||||
ModuleRemoteSubmix(std::unique_ptr<Configuration>&& config)
|
||||
: Module(Type::R_SUBMIX, std::move(config)) {}
|
||||
|
||||
private:
|
||||
// IModule interfaces
|
||||
ndk::ScopedAStatus getMicMute(bool* _aidl_return) override;
|
||||
ndk::ScopedAStatus setMicMute(bool in_mute) override;
|
||||
ndk::ScopedAStatus setAudioPortConfig(
|
||||
const ::aidl::android::media::audio::common::AudioPortConfig& in_requested,
|
||||
::aidl::android::media::audio::common::AudioPortConfig* out_suggested,
|
||||
bool* _aidl_return) override;
|
||||
|
||||
// Module interfaces
|
||||
ndk::ScopedAStatus createInputStream(
|
||||
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(
|
||||
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;
|
||||
ndk::ScopedAStatus populateConnectedDevicePort(
|
||||
::aidl::android::media::audio::common::AudioPort* audioPort,
|
||||
int32_t nextPortId) override;
|
||||
ndk::ScopedAStatus checkAudioPatchEndpointsMatch(
|
||||
const std::vector<::aidl::android::media::audio::common::AudioPortConfig*>& sources,
|
||||
const std::vector<::aidl::android::media::audio::common::AudioPortConfig*>& sinks)
|
||||
override;
|
||||
ndk::ScopedAStatus onMasterMuteChanged(bool mute) override;
|
||||
ndk::ScopedAStatus onMasterVolumeChanged(float volume) override;
|
||||
int32_t getNominalLatencyMs(
|
||||
const ::aidl::android::media::audio::common::AudioPortConfig& portConfig) override;
|
||||
binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
|
||||
};
|
||||
|
||||
} // namespace aidl::android::hardware::audio::core
|
||||
50
audio/include/core-impl/ModuleStub.h
Normal file
50
audio/include/core-impl/ModuleStub.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core-impl/Module.h"
|
||||
|
||||
namespace aidl::android::hardware::audio::core {
|
||||
|
||||
class ModuleStub final : public Module {
|
||||
public:
|
||||
ModuleStub(std::unique_ptr<Configuration>&& config) : Module(Type::STUB, std::move(config)) {}
|
||||
|
||||
protected:
|
||||
ndk::ScopedAStatus getBluetooth(std::shared_ptr<IBluetooth>* _aidl_return) override;
|
||||
ndk::ScopedAStatus getBluetoothA2dp(std::shared_ptr<IBluetoothA2dp>* _aidl_return) override;
|
||||
ndk::ScopedAStatus getBluetoothLe(std::shared_ptr<IBluetoothLe>* _aidl_return) override;
|
||||
|
||||
ndk::ScopedAStatus createInputStream(
|
||||
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(
|
||||
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;
|
||||
|
||||
private:
|
||||
ChildInterface<IBluetooth> mBluetooth;
|
||||
ChildInterface<IBluetoothA2dp> mBluetoothA2dp;
|
||||
ChildInterface<IBluetoothLe> mBluetoothLe;
|
||||
};
|
||||
|
||||
} // namespace aidl::android::hardware::audio::core
|
||||
60
audio/include/core-impl/ModuleUsb.h
Normal file
60
audio/include/core-impl/ModuleUsb.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core-impl/ModuleAlsa.h"
|
||||
|
||||
namespace aidl::android::hardware::audio::core {
|
||||
|
||||
class ModuleUsb final : public ModuleAlsa {
|
||||
public:
|
||||
ModuleUsb(std::unique_ptr<Configuration>&& config) : ModuleAlsa(Type::USB, std::move(config)) {}
|
||||
|
||||
private:
|
||||
// IModule interfaces
|
||||
ndk::ScopedAStatus getTelephony(std::shared_ptr<ITelephony>* _aidl_return) override;
|
||||
ndk::ScopedAStatus getBluetooth(std::shared_ptr<IBluetooth>* _aidl_return) override;
|
||||
ndk::ScopedAStatus getMicMute(bool* _aidl_return) override;
|
||||
ndk::ScopedAStatus setMicMute(bool in_mute) override;
|
||||
|
||||
// Module interfaces
|
||||
ndk::ScopedAStatus createInputStream(
|
||||
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(
|
||||
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;
|
||||
ndk::ScopedAStatus populateConnectedDevicePort(
|
||||
::aidl::android::media::audio::common::AudioPort* audioPort,
|
||||
int32_t nextPortId) override;
|
||||
ndk::ScopedAStatus checkAudioPatchEndpointsMatch(
|
||||
const std::vector<::aidl::android::media::audio::common::AudioPortConfig*>& sources,
|
||||
const std::vector<::aidl::android::media::audio::common::AudioPortConfig*>& sinks)
|
||||
override;
|
||||
void onExternalDeviceConnectionChanged(
|
||||
const ::aidl::android::media::audio::common::AudioPort& audioPort,
|
||||
bool connected) override;
|
||||
ndk::ScopedAStatus onMasterMuteChanged(bool mute) override;
|
||||
ndk::ScopedAStatus onMasterVolumeChanged(float volume) override;
|
||||
};
|
||||
|
||||
} // namespace aidl::android::hardware::audio::core
|
||||
87
audio/include/core-impl/SoundDose.h
Normal file
87
audio/include/core-impl/SoundDose.h
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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 <mutex>
|
||||
|
||||
#include <aidl/android/hardware/audio/core/sounddose/BnSoundDose.h>
|
||||
#include <aidl/android/media/audio/common/AudioDevice.h>
|
||||
#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 {
|
||||
|
||||
// Interface used for processing the data received by a stream.
|
||||
class StreamDataProcessorInterface {
|
||||
public:
|
||||
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:
|
||||
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, bool attenuated) 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
|
||||
740
audio/include/core-impl/Stream.h
Normal file
740
audio/include/core-impl/Stream.h
Normal file
@@ -0,0 +1,740 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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 <atomic>
|
||||
#include <chrono>
|
||||
#include <cstdlib>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <variant>
|
||||
|
||||
#include <StreamWorker.h>
|
||||
#include <Utils.h>
|
||||
#include <aidl/android/hardware/audio/common/SinkMetadata.h>
|
||||
#include <aidl/android/hardware/audio/common/SourceMetadata.h>
|
||||
#include <aidl/android/hardware/audio/core/BnStreamCommon.h>
|
||||
#include <aidl/android/hardware/audio/core/BnStreamIn.h>
|
||||
#include <aidl/android/hardware/audio/core/BnStreamOut.h>
|
||||
#include <aidl/android/hardware/audio/core/IStreamCallback.h>
|
||||
#include <aidl/android/hardware/audio/core/IStreamOutEventCallback.h>
|
||||
#include <aidl/android/hardware/audio/core/StreamDescriptor.h>
|
||||
#include <aidl/android/media/audio/common/AudioDevice.h>
|
||||
#include <aidl/android/media/audio/common/AudioIoFlags.h>
|
||||
#include <aidl/android/media/audio/common/AudioOffloadInfo.h>
|
||||
#include <aidl/android/media/audio/common/MicrophoneInfo.h>
|
||||
#include <android-base/thread_annotations.h>
|
||||
#include <error/expected_utils.h>
|
||||
#include <fmq/AidlMessageQueue.h>
|
||||
#include <system/thread_defs.h>
|
||||
#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 {
|
||||
|
||||
// This class is similar to StreamDescriptor, but unlike
|
||||
// the descriptor, it actually owns the objects implementing
|
||||
// data exchange: FMQs etc, whereas StreamDescriptor only
|
||||
// contains their descriptors.
|
||||
class StreamContext {
|
||||
public:
|
||||
typedef ::android::AidlMessageQueue<
|
||||
StreamDescriptor::Command,
|
||||
::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
|
||||
CommandMQ;
|
||||
typedef ::android::AidlMessageQueue<
|
||||
StreamDescriptor::Reply, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
|
||||
ReplyMQ;
|
||||
typedef ::android::AidlMessageQueue<
|
||||
int8_t, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
|
||||
DataMQ;
|
||||
|
||||
// Ensure that this value is not used by any of StreamDescriptor.State enums
|
||||
static constexpr StreamDescriptor::State STATE_CLOSED =
|
||||
static_cast<StreamDescriptor::State>(-1);
|
||||
|
||||
struct DebugParameters {
|
||||
// An extra delay for transient states, in ms.
|
||||
int transientStateDelayMs = 0;
|
||||
// Force the "burst" command to move the SM to the TRANSFERRING state.
|
||||
bool forceTransientBurst = false;
|
||||
// Force the "drain" command to be synchronous, going directly to the IDLE state.
|
||||
bool forceSynchronousDrain = false;
|
||||
};
|
||||
|
||||
StreamContext() = default;
|
||||
StreamContext(std::unique_ptr<CommandMQ> commandMQ, std::unique_ptr<ReplyMQ> replyMQ,
|
||||
const ::aidl::android::media::audio::common::AudioFormatDescription& format,
|
||||
const ::aidl::android::media::audio::common::AudioChannelLayout& channelLayout,
|
||||
int sampleRate, const ::aidl::android::media::audio::common::AudioIoFlags& flags,
|
||||
int32_t nominalLatencyMs, 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() | 1 /* make sure it's not 0 */),
|
||||
mReplyMQ(std::move(replyMQ)),
|
||||
mFormat(format),
|
||||
mChannelLayout(channelLayout),
|
||||
mSampleRate(sampleRate),
|
||||
mFlags(flags),
|
||||
mNominalLatencyMs(nominalLatencyMs),
|
||||
mMixPortHandle(mixPortHandle),
|
||||
mDataMQ(std::move(dataMQ)),
|
||||
mAsyncCallback(asyncCallback),
|
||||
mOutEventCallback(outEventCallback),
|
||||
mStreamDataProcessor(streamDataProcessor),
|
||||
mDebugParameters(debugParameters) {}
|
||||
StreamContext(std::unique_ptr<CommandMQ> commandMQ, std::unique_ptr<ReplyMQ> replyMQ,
|
||||
const ::aidl::android::media::audio::common::AudioFormatDescription& format,
|
||||
const ::aidl::android::media::audio::common::AudioChannelLayout& channelLayout,
|
||||
int sampleRate, const ::aidl::android::media::audio::common::AudioIoFlags& flags,
|
||||
int32_t nominalLatencyMs, int32_t mixPortHandle, MmapBufferDescriptor&& mmapDesc,
|
||||
std::shared_ptr<IStreamOutEventCallback> outEventCallback,
|
||||
std::weak_ptr<sounddose::StreamDataProcessorInterface> streamDataProcessor,
|
||||
DebugParameters debugParameters)
|
||||
: mCommandMQ(std::move(commandMQ)),
|
||||
mInternalCommandCookie(std::rand() | 1 /* make sure it's not 0 */),
|
||||
mReplyMQ(std::move(replyMQ)),
|
||||
mFormat(format),
|
||||
mChannelLayout(channelLayout),
|
||||
mSampleRate(sampleRate),
|
||||
mFlags(flags),
|
||||
mNominalLatencyMs(nominalLatencyMs),
|
||||
mMixPortHandle(mixPortHandle),
|
||||
mMmapBufferDesc(std::move(mmapDesc)),
|
||||
mOutEventCallback(outEventCallback),
|
||||
mStreamDataProcessor(streamDataProcessor),
|
||||
mDebugParameters(debugParameters) {}
|
||||
|
||||
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;
|
||||
}
|
||||
CommandMQ* getCommandMQ() const { return mCommandMQ.get(); }
|
||||
DataMQ* getDataMQ() const { return mDataMQ.get(); }
|
||||
::aidl::android::media::audio::common::AudioFormatDescription getFormat() const {
|
||||
return mFormat;
|
||||
}
|
||||
::aidl::android::media::audio::common::AudioIoFlags getFlags() const { return mFlags; }
|
||||
bool getForceTransientBurst() const { return mDebugParameters.forceTransientBurst; }
|
||||
bool getForceSynchronousDrain() const { return mDebugParameters.forceSynchronousDrain; }
|
||||
size_t getFrameSize() const;
|
||||
int getInternalCommandCookie() const { return mInternalCommandCookie; }
|
||||
int32_t getMixPortHandle() const { return mMixPortHandle; }
|
||||
int32_t getNominalLatencyMs() const { return mNominalLatencyMs; }
|
||||
std::shared_ptr<IStreamOutEventCallback> getOutEventCallback() const {
|
||||
return mOutEventCallback;
|
||||
}
|
||||
std::weak_ptr<sounddose::StreamDataProcessorInterface> getStreamDataProcessor() const {
|
||||
return mStreamDataProcessor;
|
||||
}
|
||||
void startStreamDataProcessor();
|
||||
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 isMmap() const { return ::aidl::android::hardware::audio::common::hasMmapFlag(mFlags); }
|
||||
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.
|
||||
void reset();
|
||||
// 'advanceFrameCount' and 'getFrameCount' are only called on the worker thread.
|
||||
int64_t advanceFrameCount(size_t increase) { return mFrameCount += increase; }
|
||||
int64_t getFrameCount() const { return mFrameCount; }
|
||||
|
||||
private:
|
||||
// Fields are non const to allow move assignment.
|
||||
std::unique_ptr<CommandMQ> mCommandMQ;
|
||||
int mInternalCommandCookie; // The value used to confirm that the command was posted internally
|
||||
std::unique_ptr<ReplyMQ> mReplyMQ;
|
||||
::aidl::android::media::audio::common::AudioFormatDescription mFormat;
|
||||
::aidl::android::media::audio::common::AudioChannelLayout mChannelLayout;
|
||||
int mSampleRate;
|
||||
::aidl::android::media::audio::common::AudioIoFlags mFlags;
|
||||
int32_t mNominalLatencyMs;
|
||||
int32_t mMixPortHandle;
|
||||
// Only one of `mDataMQ` or `mMapBufferDesc` can be active, depending on `isMmap`
|
||||
std::unique_ptr<DataMQ> mDataMQ;
|
||||
MmapBufferDescriptor mMmapBufferDesc;
|
||||
std::shared_ptr<IStreamCallback> mAsyncCallback;
|
||||
std::shared_ptr<IStreamOutEventCallback> mOutEventCallback; // Only used by output streams
|
||||
std::weak_ptr<sounddose::StreamDataProcessorInterface> mStreamDataProcessor;
|
||||
DebugParameters mDebugParameters;
|
||||
int64_t mFrameCount = 0;
|
||||
};
|
||||
|
||||
// Driver callbacks are executed on a dedicated thread, not on the worker thread.
|
||||
struct DriverCallbackInterface {
|
||||
virtual ~DriverCallbackInterface() = default;
|
||||
// Both callbacks are used to notify the worker about the progress of the playback
|
||||
// offloaded to the DSP.
|
||||
|
||||
// 'bufferFramesLeft' is how many *encoded* frames are left in the buffer until
|
||||
// it depletes.
|
||||
virtual void onBufferStateChange(size_t bufferFramesLeft) = 0;
|
||||
// 'clipFramesLeft' is how many *decoded* frames are left until the end of the currently
|
||||
// playing clip. '0' frames left means that the clip has ended (by itself or due
|
||||
// to draining).
|
||||
// 'hasNextClip' indicates whether the DSP has audio data for the next clip.
|
||||
virtual void onClipStateChange(size_t clipFramesLeft, bool hasNextClip) = 0;
|
||||
};
|
||||
|
||||
// This interface provides operations of the stream which are executed on the worker thread.
|
||||
struct DriverInterface {
|
||||
virtual ~DriverInterface() = default;
|
||||
// All the methods below are called on the worker thread.
|
||||
virtual ::android::status_t init(DriverCallbackInterface* callback) = 0; // Called once.
|
||||
virtual ::android::status_t drain(StreamDescriptor::DrainMode mode) = 0;
|
||||
virtual ::android::status_t flush() = 0;
|
||||
virtual ::android::status_t pause() = 0;
|
||||
virtual ::android::status_t standby() = 0;
|
||||
virtual ::android::status_t start() = 0;
|
||||
virtual ::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
|
||||
int32_t* latencyMs) = 0;
|
||||
// No need to implement 'refinePosition' unless the driver can provide more precise
|
||||
// data than just total frame count. For example, the driver may correctly account
|
||||
// for any intermediate buffers.
|
||||
virtual ::android::status_t refinePosition(StreamDescriptor::Position* /*position*/) {
|
||||
return ::android::OK;
|
||||
}
|
||||
// Implement 'getMmapPositionAndLatency' is necessary if driver can support mmap stream.
|
||||
virtual ::android::status_t getMmapPositionAndLatency(StreamDescriptor::Position* /*position*/,
|
||||
int32_t* /*latency*/) {
|
||||
return ::android::OK;
|
||||
}
|
||||
virtual void shutdown() = 0; // This function is only called once.
|
||||
};
|
||||
|
||||
class StreamWorkerCommonLogic : public ::android::hardware::audio::common::StreamLogic,
|
||||
public DriverCallbackInterface {
|
||||
public:
|
||||
bool isClosed() const { return mState == StreamContext::STATE_CLOSED; }
|
||||
StreamDescriptor::State setClosed() {
|
||||
auto prevState = mState.exchange(StreamContext::STATE_CLOSED);
|
||||
if (prevState != StreamContext::STATE_CLOSED) {
|
||||
mStatePriorToClosing = prevState;
|
||||
}
|
||||
return mStatePriorToClosing;
|
||||
}
|
||||
void setIsConnected(bool connected) { mIsConnected = connected; }
|
||||
|
||||
protected:
|
||||
using DataBufferElement = int8_t;
|
||||
|
||||
StreamWorkerCommonLogic(StreamContext* context, DriverInterface* driver)
|
||||
: mContext(context),
|
||||
mDriver(driver),
|
||||
mTransientStateDelayMs(context->getTransientStateDelayMs()) {}
|
||||
pid_t getTid() const;
|
||||
|
||||
// ::android::hardware::audio::common::StreamLogic
|
||||
std::string init() override;
|
||||
// DriverCallbackInterface
|
||||
void onBufferStateChange(size_t bufferFramesLeft) override;
|
||||
void onClipStateChange(size_t clipFramesLeft, bool hasNextClip) override;
|
||||
|
||||
void populateReply(StreamDescriptor::Reply* reply, bool isConnected) const;
|
||||
void populateReplyWrongState(StreamDescriptor::Reply* reply,
|
||||
const StreamDescriptor::Command& command) const;
|
||||
void switchToTransientState(StreamDescriptor::State state) {
|
||||
mState = state;
|
||||
mTransientStateStart = std::chrono::steady_clock::now();
|
||||
}
|
||||
|
||||
// The context is only used for reading, except for updating the frame count,
|
||||
// which happens on the worker thread only.
|
||||
StreamContext* const mContext;
|
||||
DriverInterface* const mDriver;
|
||||
// This is the state the stream was in before being closed. It is retrieved by the main
|
||||
// thread after joining the worker thread.
|
||||
StreamDescriptor::State mStatePriorToClosing = StreamDescriptor::State::STANDBY;
|
||||
// Atomic fields are used both by the main and worker threads.
|
||||
std::atomic<bool> mIsConnected = false;
|
||||
static_assert(std::atomic<StreamDescriptor::State>::is_always_lock_free);
|
||||
std::atomic<StreamDescriptor::State> mState = StreamDescriptor::State::STANDBY;
|
||||
// All fields below are used on the worker thread only.
|
||||
const std::chrono::duration<int, std::milli> mTransientStateDelayMs;
|
||||
std::chrono::time_point<std::chrono::steady_clock> mTransientStateStart;
|
||||
// We use an array and the "size" field instead of a vector to be able to detect
|
||||
// memory allocation issues.
|
||||
std::unique_ptr<DataBufferElement[]> mDataBuffer;
|
||||
size_t mDataBufferSize;
|
||||
};
|
||||
|
||||
// This interface is used to decouple stream implementations from a concrete StreamWorker
|
||||
// implementation.
|
||||
struct StreamWorkerInterface {
|
||||
using CreateInstance =
|
||||
std::function<StreamWorkerInterface*(StreamContext* context, DriverInterface* driver)>;
|
||||
virtual ~StreamWorkerInterface() = default;
|
||||
virtual bool isClosed() const = 0;
|
||||
virtual void setIsConnected(bool isConnected) = 0;
|
||||
virtual StreamDescriptor::State setClosed() = 0;
|
||||
virtual bool start() = 0;
|
||||
virtual pid_t getTid() = 0;
|
||||
virtual void join() = 0;
|
||||
virtual std::string getError() = 0;
|
||||
};
|
||||
|
||||
template <class WorkerLogic>
|
||||
class StreamWorkerImpl : public StreamWorkerInterface,
|
||||
public ::android::hardware::audio::common::StreamWorker<WorkerLogic> {
|
||||
using WorkerImpl = ::android::hardware::audio::common::StreamWorker<WorkerLogic>;
|
||||
|
||||
public:
|
||||
StreamWorkerImpl(StreamContext* context, DriverInterface* driver)
|
||||
: WorkerImpl(context, driver) {}
|
||||
bool isClosed() const override { return WorkerImpl::isClosed(); }
|
||||
void setIsConnected(bool isConnected) override { WorkerImpl::setIsConnected(isConnected); }
|
||||
StreamDescriptor::State setClosed() override { return WorkerImpl::setClosed(); }
|
||||
bool start() override {
|
||||
// This is an "audio service thread," must have elevated priority.
|
||||
return WorkerImpl::start(WorkerImpl::kThreadName, ANDROID_PRIORITY_URGENT_AUDIO);
|
||||
}
|
||||
pid_t getTid() override { return WorkerImpl::getTid(); }
|
||||
void join() override { return WorkerImpl::join(); }
|
||||
std::string getError() override { return WorkerImpl::getError(); }
|
||||
};
|
||||
|
||||
class StreamInWorkerLogic : public StreamWorkerCommonLogic {
|
||||
public:
|
||||
static const std::string kThreadName;
|
||||
StreamInWorkerLogic(StreamContext* context, DriverInterface* driver)
|
||||
: StreamWorkerCommonLogic(context, driver) {}
|
||||
|
||||
protected:
|
||||
Status cycle() override;
|
||||
|
||||
private:
|
||||
bool read(size_t clientSize, StreamDescriptor::Reply* reply);
|
||||
bool readMmap(StreamDescriptor::Reply* reply);
|
||||
};
|
||||
using StreamInWorker = StreamWorkerImpl<StreamInWorkerLogic>;
|
||||
|
||||
class StreamOutWorkerLogic : public StreamWorkerCommonLogic {
|
||||
public:
|
||||
static const std::string kThreadName;
|
||||
StreamOutWorkerLogic(StreamContext* context, DriverInterface* driver)
|
||||
: StreamWorkerCommonLogic(context, driver),
|
||||
mEventCallback(context->getOutEventCallback()) {}
|
||||
|
||||
protected:
|
||||
Status cycle() override;
|
||||
// DriverCallbackInterface
|
||||
void onBufferStateChange(size_t bufferFramesLeft) override;
|
||||
void onClipStateChange(size_t clipFramesLeft, bool hasNextClip) override;
|
||||
|
||||
private:
|
||||
bool write(size_t clientSize, StreamDescriptor::Reply* reply);
|
||||
bool writeMmap(StreamDescriptor::Reply* reply);
|
||||
|
||||
std::shared_ptr<IStreamOutEventCallback> mEventCallback;
|
||||
|
||||
enum DrainState : int32_t { NONE, ALL, EN /*early notify*/, EN_SENT };
|
||||
std::atomic<DrainState> mDrainState = DrainState::NONE;
|
||||
};
|
||||
using StreamOutWorker = StreamWorkerImpl<StreamOutWorkerLogic>;
|
||||
|
||||
// This interface provides operations of the stream which are executed on a Binder pool thread.
|
||||
// These methods originate both from the AIDL interface and its implementation.
|
||||
struct StreamCommonInterface {
|
||||
using ConnectedDevices = std::vector<::aidl::android::media::audio::common::AudioDevice>;
|
||||
using Metadata =
|
||||
std::variant<::aidl::android::hardware::audio::common::SinkMetadata /*IStreamIn*/,
|
||||
::aidl::android::hardware::audio::common::SourceMetadata /*IStreamOut*/>;
|
||||
|
||||
static constexpr bool isInput(const Metadata& metadata) { return metadata.index() == 0; }
|
||||
|
||||
virtual ~StreamCommonInterface() = default;
|
||||
// Methods below originate from the 'IStreamCommon' interface.
|
||||
// This is semantically equivalent to inheriting from 'IStreamCommon' with a benefit
|
||||
// that concrete stream implementations can inherit both from this interface and IStreamIn/Out.
|
||||
virtual ndk::ScopedAStatus close() = 0;
|
||||
virtual ndk::ScopedAStatus prepareToClose() = 0;
|
||||
virtual ndk::ScopedAStatus updateHwAvSyncId(int32_t in_hwAvSyncId) = 0;
|
||||
virtual ndk::ScopedAStatus getVendorParameters(const std::vector<std::string>& in_ids,
|
||||
std::vector<VendorParameter>* _aidl_return) = 0;
|
||||
virtual ndk::ScopedAStatus setVendorParameters(
|
||||
const std::vector<VendorParameter>& in_parameters, bool in_async) = 0;
|
||||
virtual ndk::ScopedAStatus addEffect(
|
||||
const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>&
|
||||
in_effect) = 0;
|
||||
virtual ndk::ScopedAStatus removeEffect(
|
||||
const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>&
|
||||
in_effect) = 0;
|
||||
// Methods below are common for both 'IStreamIn' and 'IStreamOut'. Note that
|
||||
// 'updateMetadata' in them uses an individual structure which is wrapped here.
|
||||
// The 'Common' suffix is added to distinguish them from the methods from 'IStreamIn/Out'.
|
||||
virtual ndk::ScopedAStatus getStreamCommonCommon(
|
||||
std::shared_ptr<IStreamCommon>* _aidl_return) = 0;
|
||||
virtual ndk::ScopedAStatus updateMetadataCommon(const Metadata& metadata) = 0;
|
||||
// Methods below are called by implementation of 'IModule', 'IStreamIn' and 'IStreamOut'.
|
||||
virtual ndk::ScopedAStatus initInstance(
|
||||
const std::shared_ptr<StreamCommonInterface>& delegate) = 0;
|
||||
virtual const StreamContext& getContext() const = 0;
|
||||
virtual bool isClosed() const = 0;
|
||||
virtual const ConnectedDevices& getConnectedDevices() const = 0;
|
||||
virtual ndk::ScopedAStatus setConnectedDevices(
|
||||
const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) = 0;
|
||||
virtual ndk::ScopedAStatus bluetoothParametersUpdated() = 0;
|
||||
virtual ndk::ScopedAStatus setGain(float gain) = 0;
|
||||
};
|
||||
|
||||
// This is equivalent to automatically generated 'IStreamCommonDelegator' but uses
|
||||
// a weak pointer to avoid creating a reference loop. The loop will occur because
|
||||
// 'IStreamIn/Out.getStreamCommon' must return the same instance every time, thus
|
||||
// the stream implementation must hold a strong pointer to an instance of 'IStreamCommon'.
|
||||
// Also, we use 'StreamCommonInterface' here instead of 'IStreamCommon'.
|
||||
class StreamCommonDelegator : public BnStreamCommon {
|
||||
public:
|
||||
explicit StreamCommonDelegator(const std::shared_ptr<StreamCommonInterface>& delegate)
|
||||
: mDelegate(delegate) {}
|
||||
|
||||
private:
|
||||
ndk::ScopedAStatus close() override {
|
||||
auto delegate = mDelegate.lock();
|
||||
return delegate != nullptr ? delegate->close()
|
||||
: ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
}
|
||||
ndk::ScopedAStatus prepareToClose() override {
|
||||
auto delegate = mDelegate.lock();
|
||||
return delegate != nullptr ? delegate->prepareToClose()
|
||||
: ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
}
|
||||
ndk::ScopedAStatus updateHwAvSyncId(int32_t in_hwAvSyncId) override {
|
||||
auto delegate = mDelegate.lock();
|
||||
return delegate != nullptr ? delegate->updateHwAvSyncId(in_hwAvSyncId)
|
||||
: ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
}
|
||||
ndk::ScopedAStatus getVendorParameters(const std::vector<std::string>& in_ids,
|
||||
std::vector<VendorParameter>* _aidl_return) override {
|
||||
auto delegate = mDelegate.lock();
|
||||
return delegate != nullptr ? delegate->getVendorParameters(in_ids, _aidl_return)
|
||||
: ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
}
|
||||
ndk::ScopedAStatus setVendorParameters(const std::vector<VendorParameter>& in_parameters,
|
||||
bool in_async) override {
|
||||
auto delegate = mDelegate.lock();
|
||||
return delegate != nullptr ? delegate->setVendorParameters(in_parameters, in_async)
|
||||
: ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
}
|
||||
ndk::ScopedAStatus addEffect(
|
||||
const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect)
|
||||
override {
|
||||
auto delegate = mDelegate.lock();
|
||||
return delegate != nullptr ? delegate->addEffect(in_effect)
|
||||
: ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
}
|
||||
ndk::ScopedAStatus removeEffect(
|
||||
const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect)
|
||||
override {
|
||||
auto delegate = mDelegate.lock();
|
||||
return delegate != nullptr ? delegate->removeEffect(in_effect)
|
||||
: ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
}
|
||||
// It is possible that on the client side the proxy for IStreamCommon will outlive
|
||||
// the IStream* instance, and the server side IStream* instance will get destroyed
|
||||
// while this IStreamCommon instance is still alive.
|
||||
std::weak_ptr<StreamCommonInterface> mDelegate;
|
||||
};
|
||||
|
||||
// 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(StreamContext* context, const Metadata& metadata,
|
||||
const StreamWorkerInterface::CreateInstance& createWorker)
|
||||
: mContext(*context), mMetadata(metadata), mWorker(createWorker(context, this)) {}
|
||||
StreamCommonImpl(StreamContext* context, const Metadata& metadata)
|
||||
: StreamCommonImpl(
|
||||
context, metadata,
|
||||
isInput(metadata) ? getDefaultInWorkerCreator() : getDefaultOutWorkerCreator()) {}
|
||||
~StreamCommonImpl();
|
||||
|
||||
ndk::ScopedAStatus close() override;
|
||||
ndk::ScopedAStatus prepareToClose() override;
|
||||
ndk::ScopedAStatus updateHwAvSyncId(int32_t in_hwAvSyncId) override;
|
||||
ndk::ScopedAStatus getVendorParameters(const std::vector<std::string>& in_ids,
|
||||
std::vector<VendorParameter>* _aidl_return) override;
|
||||
ndk::ScopedAStatus setVendorParameters(const std::vector<VendorParameter>& in_parameters,
|
||||
bool in_async) override;
|
||||
ndk::ScopedAStatus addEffect(
|
||||
const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect)
|
||||
override;
|
||||
ndk::ScopedAStatus removeEffect(
|
||||
const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect)
|
||||
override;
|
||||
|
||||
ndk::ScopedAStatus getStreamCommonCommon(std::shared_ptr<IStreamCommon>* _aidl_return) override;
|
||||
ndk::ScopedAStatus updateMetadataCommon(const Metadata& metadata) override;
|
||||
|
||||
ndk::ScopedAStatus initInstance(
|
||||
const std::shared_ptr<StreamCommonInterface>& delegate) override;
|
||||
const StreamContext& getContext() const override { return mContext; }
|
||||
bool isClosed() const override { return mWorker->isClosed(); }
|
||||
const ConnectedDevices& getConnectedDevices() const override { return mConnectedDevices; }
|
||||
ndk::ScopedAStatus setConnectedDevices(
|
||||
const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices)
|
||||
override;
|
||||
ndk::ScopedAStatus bluetoothParametersUpdated() override;
|
||||
ndk::ScopedAStatus setGain(float gain) override;
|
||||
|
||||
protected:
|
||||
static StreamWorkerInterface::CreateInstance getDefaultInWorkerCreator() {
|
||||
return [](StreamContext* ctx, DriverInterface* driver) -> StreamWorkerInterface* {
|
||||
return new StreamInWorker(ctx, driver);
|
||||
};
|
||||
}
|
||||
static StreamWorkerInterface::CreateInstance getDefaultOutWorkerCreator() {
|
||||
return [](StreamContext* ctx, DriverInterface* driver) -> StreamWorkerInterface* {
|
||||
return new StreamOutWorker(ctx, driver);
|
||||
};
|
||||
}
|
||||
|
||||
virtual void onClose(StreamDescriptor::State statePriorToClosing) = 0;
|
||||
// Any stream class implementing 'DriverInterface::shutdown' must call 'cleanupWorker' in
|
||||
// the destructor in order to stop and join the worker thread in the case when the client
|
||||
// has not called 'IStreamCommon::close' method.
|
||||
void cleanupWorker();
|
||||
void setWorkerThreadPriority(pid_t workerTid);
|
||||
void stopAndJoinWorker();
|
||||
void stopWorker();
|
||||
|
||||
const StreamContext& mContext;
|
||||
Metadata mMetadata;
|
||||
std::unique_ptr<StreamWorkerInterface> mWorker;
|
||||
ChildInterface<StreamCommonDelegator> mCommon;
|
||||
ConnectedDevices mConnectedDevices;
|
||||
|
||||
private:
|
||||
std::atomic<bool> mWorkerStopIssued = false;
|
||||
};
|
||||
|
||||
// Note: 'StreamIn/Out' can not be used on their own. Instead, they must be used for defining
|
||||
// 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);
|
||||
}
|
||||
ndk::ScopedAStatus updateMetadata(const ::aidl::android::hardware::audio::common::SinkMetadata&
|
||||
in_sinkMetadata) override {
|
||||
return updateMetadataCommon(in_sinkMetadata);
|
||||
}
|
||||
ndk::ScopedAStatus getActiveMicrophones(
|
||||
std::vector<::aidl::android::media::audio::common::MicrophoneDynamicInfo>* _aidl_return)
|
||||
override;
|
||||
ndk::ScopedAStatus getMicrophoneDirection(MicrophoneDirection* _aidl_return) override;
|
||||
ndk::ScopedAStatus setMicrophoneDirection(MicrophoneDirection in_direction) override;
|
||||
ndk::ScopedAStatus getMicrophoneFieldDimension(float* _aidl_return) override;
|
||||
ndk::ScopedAStatus setMicrophoneFieldDimension(float in_zoom) override;
|
||||
ndk::ScopedAStatus getHwGain(std::vector<float>* _aidl_return) override;
|
||||
ndk::ScopedAStatus setHwGain(const std::vector<float>& in_channelGains) override;
|
||||
|
||||
friend class ndk::SharedRefBase;
|
||||
|
||||
StreamIn(StreamContext&& context,
|
||||
const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones);
|
||||
|
||||
StreamContext mContextInstance;
|
||||
const std::map<::aidl::android::media::audio::common::AudioDevice, std::string> mMicrophones;
|
||||
};
|
||||
|
||||
class StreamInHwGainHelper {
|
||||
protected:
|
||||
explicit StreamInHwGainHelper(const StreamContext* context);
|
||||
|
||||
ndk::ScopedAStatus getHwGainImpl(std::vector<float>* _aidl_return);
|
||||
ndk::ScopedAStatus setHwGainImpl(const std::vector<float>& in_channelGains);
|
||||
|
||||
const size_t mChannelCount;
|
||||
std::vector<float> mHwGains;
|
||||
};
|
||||
|
||||
class StreamOut : virtual public StreamCommonInterface, public BnStreamOut {
|
||||
protected:
|
||||
void defaultOnClose();
|
||||
|
||||
ndk::ScopedAStatus getStreamCommon(std::shared_ptr<IStreamCommon>* _aidl_return) override {
|
||||
return getStreamCommonCommon(_aidl_return);
|
||||
}
|
||||
ndk::ScopedAStatus updateMetadata(
|
||||
const ::aidl::android::hardware::audio::common::SourceMetadata& in_sourceMetadata)
|
||||
override {
|
||||
return updateMetadataCommon(in_sourceMetadata);
|
||||
}
|
||||
ndk::ScopedAStatus updateOffloadMetadata(
|
||||
const ::aidl::android::hardware::audio::common::AudioOffloadMetadata&
|
||||
in_offloadMetadata) override;
|
||||
ndk::ScopedAStatus getHwVolume(std::vector<float>* _aidl_return) override;
|
||||
ndk::ScopedAStatus setHwVolume(const std::vector<float>& in_channelVolumes) override;
|
||||
ndk::ScopedAStatus getAudioDescriptionMixLevel(float* _aidl_return) override;
|
||||
ndk::ScopedAStatus setAudioDescriptionMixLevel(float in_leveldB) override;
|
||||
ndk::ScopedAStatus getDualMonoMode(
|
||||
::aidl::android::media::audio::common::AudioDualMonoMode* _aidl_return) override;
|
||||
ndk::ScopedAStatus setDualMonoMode(
|
||||
::aidl::android::media::audio::common::AudioDualMonoMode in_mode) override;
|
||||
ndk::ScopedAStatus getRecommendedLatencyModes(
|
||||
std::vector<::aidl::android::media::audio::common::AudioLatencyMode>* _aidl_return)
|
||||
override;
|
||||
ndk::ScopedAStatus setLatencyMode(
|
||||
::aidl::android::media::audio::common::AudioLatencyMode in_mode) override;
|
||||
ndk::ScopedAStatus getPlaybackRateParameters(
|
||||
::aidl::android::media::audio::common::AudioPlaybackRate* _aidl_return) override;
|
||||
ndk::ScopedAStatus setPlaybackRateParameters(
|
||||
const ::aidl::android::media::audio::common::AudioPlaybackRate& in_playbackRate)
|
||||
override;
|
||||
ndk::ScopedAStatus selectPresentation(int32_t in_presentationId, int32_t in_programId) override;
|
||||
|
||||
friend class ndk::SharedRefBase;
|
||||
|
||||
StreamOut(StreamContext&& context,
|
||||
const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
|
||||
offloadInfo);
|
||||
|
||||
StreamContext mContextInstance;
|
||||
const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo> mOffloadInfo;
|
||||
std::optional<::aidl::android::hardware::audio::common::AudioOffloadMetadata> mOffloadMetadata;
|
||||
};
|
||||
|
||||
class StreamOutHwVolumeHelper {
|
||||
protected:
|
||||
explicit StreamOutHwVolumeHelper(const StreamContext* context);
|
||||
|
||||
ndk::ScopedAStatus getHwVolumeImpl(std::vector<float>* _aidl_return);
|
||||
ndk::ScopedAStatus setHwVolumeImpl(const std::vector<float>& in_channelVolumes);
|
||||
|
||||
const size_t mChannelCount;
|
||||
std::vector<float> mHwVolumes;
|
||||
};
|
||||
|
||||
// The recommended way to create a stream instance.
|
||||
// 'StreamImpl' is the concrete stream implementation, 'StreamInOrOut' is either 'StreamIn' or
|
||||
// 'StreamOut', the rest are the arguments forwarded to the constructor of 'StreamImpl'.
|
||||
template <class StreamImpl, class StreamInOrOut, class... Args>
|
||||
ndk::ScopedAStatus createStreamInstance(std::shared_ptr<StreamInOrOut>* result, Args&&... args) {
|
||||
std::shared_ptr<StreamInOrOut> stream =
|
||||
::ndk::SharedRefBase::make<StreamImpl>(std::forward<Args>(args)...);
|
||||
RETURN_STATUS_IF_ERROR(stream->initInstance(stream));
|
||||
*result = std::move(stream);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
class StreamWrapper {
|
||||
public:
|
||||
explicit StreamWrapper(const std::shared_ptr<StreamIn>& streamIn)
|
||||
: mStream(streamIn), mStreamBinder(streamIn->asBinder()) {}
|
||||
explicit StreamWrapper(const std::shared_ptr<StreamOut>& streamOut)
|
||||
: mStream(streamOut), mStreamBinder(streamOut->asBinder()) {}
|
||||
ndk::SpAIBinder getBinder() const { return mStreamBinder; }
|
||||
bool isStreamOpen() const {
|
||||
auto s = mStream.lock();
|
||||
return s && !s->isClosed();
|
||||
}
|
||||
ndk::ScopedAStatus setConnectedDevices(
|
||||
const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) {
|
||||
auto s = mStream.lock();
|
||||
if (s) return s->setConnectedDevices(devices);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
ndk::ScopedAStatus bluetoothParametersUpdated() {
|
||||
auto s = mStream.lock();
|
||||
if (s) return s->bluetoothParametersUpdated();
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus setGain(float gain) {
|
||||
auto s = mStream.lock();
|
||||
if (s) return s->setGain(gain);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
void dump(int fd, const char** args, uint32_t numArgs) const {
|
||||
auto s = ::ndk::ICInterface::asInterface(mStreamBinder.get());
|
||||
if (s) s->dump(fd, args, numArgs);
|
||||
return;
|
||||
}
|
||||
|
||||
private:
|
||||
std::weak_ptr<StreamCommonInterface> mStream;
|
||||
ndk::SpAIBinder mStreamBinder;
|
||||
};
|
||||
|
||||
class Streams {
|
||||
public:
|
||||
Streams() = default;
|
||||
Streams(const Streams&) = delete;
|
||||
Streams& operator=(const Streams&) = delete;
|
||||
size_t count(int32_t id) {
|
||||
// Streams do not remove themselves from the collection on close.
|
||||
erase_if(mStreams, [](const auto& pair) { return !pair.second.isStreamOpen(); });
|
||||
return mStreams.count(id);
|
||||
}
|
||||
void insert(int32_t portId, int32_t portConfigId, StreamWrapper sw) {
|
||||
mStreams.insert(std::pair{portConfigId, sw});
|
||||
mStreams.insert(std::pair{portId, std::move(sw)});
|
||||
}
|
||||
ndk::ScopedAStatus setStreamConnectedDevices(
|
||||
int32_t portConfigId,
|
||||
const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) {
|
||||
if (auto it = mStreams.find(portConfigId); it != mStreams.end()) {
|
||||
return it->second.setConnectedDevices(devices);
|
||||
}
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
ndk::ScopedAStatus bluetoothParametersUpdated() {
|
||||
bool isOk = true;
|
||||
for (auto& it : mStreams) {
|
||||
if (!it.second.bluetoothParametersUpdated().isOk()) isOk = false;
|
||||
}
|
||||
return isOk ? ndk::ScopedAStatus::ok()
|
||||
: ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
|
||||
}
|
||||
ndk::ScopedAStatus setGain(int32_t portId, float gain) {
|
||||
if (auto it = mStreams.find(portId); it != mStreams.end()) {
|
||||
return it->second.setGain(gain);
|
||||
}
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
void dump(int32_t portConfigId, int fd, const char** args, uint32_t numArgs) const {
|
||||
if (auto it = mStreams.find(portConfigId); it != mStreams.end()) {
|
||||
it->second.dump(fd, args, numArgs);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
private:
|
||||
// Maps port ids and port config ids to streams. Multimap because a port
|
||||
// (not port config) can have multiple streams opened on it.
|
||||
std::multimap<int32_t, StreamWrapper> mStreams;
|
||||
};
|
||||
|
||||
} // namespace aidl::android::hardware::audio::core
|
||||
85
audio/include/core-impl/StreamAlsa.h
Normal file
85
audio/include/core-impl/StreamAlsa.h
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <optional>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include <media/nbaio/MonoPipe.h>
|
||||
#include <media/nbaio/MonoPipeReader.h>
|
||||
|
||||
#include "Stream.h"
|
||||
#include "alsa/Utils.h"
|
||||
|
||||
namespace aidl::android::hardware::audio::core {
|
||||
|
||||
// This class is intended to be used as a base class for implementations
|
||||
// that use TinyAlsa.
|
||||
// This class does not define a complete stream implementation,
|
||||
// and should never be used on its own. Derived classes are expected to
|
||||
// provide necessary overrides for all interface methods omitted here.
|
||||
class StreamAlsa : public StreamCommonImpl {
|
||||
public:
|
||||
StreamAlsa(StreamContext* context, const Metadata& metadata, int readWriteRetries);
|
||||
~StreamAlsa();
|
||||
|
||||
// Methods of 'DriverInterface'.
|
||||
::android::status_t init(DriverCallbackInterface* callback) 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;
|
||||
::android::status_t refinePosition(StreamDescriptor::Position* position) override;
|
||||
void shutdown() override;
|
||||
ndk::ScopedAStatus setGain(float gain) override;
|
||||
|
||||
protected:
|
||||
// Called from 'start' to initialize 'mAlsaDeviceProxies', the vector must be non-empty.
|
||||
virtual std::vector<alsa::DeviceProfile> getDeviceProfiles() = 0;
|
||||
|
||||
const size_t mBufferSizeFrames;
|
||||
const size_t mFrameSizeBytes;
|
||||
const int mSampleRate;
|
||||
const bool mIsInput;
|
||||
const std::optional<struct pcm_config> mConfig;
|
||||
const int mReadWriteRetries;
|
||||
|
||||
private:
|
||||
::android::NBAIO_Format getPipeFormat() const;
|
||||
::android::sp<::android::MonoPipe> makeSink(bool writeCanBlock);
|
||||
::android::sp<::android::MonoPipeReader> makeSource(::android::MonoPipe* pipe);
|
||||
void inputIoThread(size_t idx);
|
||||
void outputIoThread(size_t idx);
|
||||
void teardownIo();
|
||||
|
||||
std::atomic<float> mGain = 1.0;
|
||||
|
||||
// All fields below are only used on the worker thread.
|
||||
std::vector<alsa::DeviceProxy> mAlsaDeviceProxies;
|
||||
// Only 'libnbaio_mono' is vendor-accessible, thus no access to the multi-reader Pipe.
|
||||
std::vector<::android::sp<::android::MonoPipe>> mSinks;
|
||||
std::vector<::android::sp<::android::MonoPipeReader>> mSources;
|
||||
std::vector<std::thread> mIoThreads;
|
||||
std::atomic<bool> mIoThreadIsRunning = false; // used by all threads
|
||||
};
|
||||
|
||||
} // namespace aidl::android::hardware::audio::core
|
||||
116
audio/include/core-impl/StreamBluetooth.h
Normal file
116
audio/include/core-impl/StreamBluetooth.h
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
#include <aidl/android/hardware/audio/core/IBluetooth.h>
|
||||
#include <aidl/android/hardware/audio/core/IBluetoothA2dp.h>
|
||||
#include <aidl/android/hardware/audio/core/IBluetoothLe.h>
|
||||
|
||||
#include "core-impl/DevicePortProxy.h"
|
||||
#include "core-impl/ModuleBluetooth.h"
|
||||
#include "core-impl/Stream.h"
|
||||
|
||||
namespace aidl::android::hardware::audio::core {
|
||||
|
||||
class StreamBluetooth : public StreamCommonImpl {
|
||||
public:
|
||||
static bool checkConfigParams(
|
||||
const ::aidl::android::hardware::bluetooth::audio::PcmConfiguration& pcmConfig,
|
||||
const ::aidl::android::media::audio::common::AudioConfigBase& config);
|
||||
|
||||
StreamBluetooth(
|
||||
StreamContext* context, const Metadata& metadata,
|
||||
ModuleBluetooth::BtProfileHandles&& btHandles,
|
||||
const std::shared_ptr<::android::bluetooth::audio::aidl::BluetoothAudioPortAidl>&
|
||||
btDeviceProxy,
|
||||
const ::aidl::android::hardware::bluetooth::audio::PcmConfiguration& pcmConfig);
|
||||
~StreamBluetooth();
|
||||
|
||||
// Methods of 'DriverInterface'.
|
||||
::android::status_t init(DriverCallbackInterface*) 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;
|
||||
|
||||
// Overridden methods of 'StreamCommonImpl', called on a Binder thread.
|
||||
ndk::ScopedAStatus updateMetadataCommon(const Metadata& metadata) override;
|
||||
ndk::ScopedAStatus prepareToClose() override;
|
||||
ndk::ScopedAStatus bluetoothParametersUpdated() override;
|
||||
|
||||
private:
|
||||
const size_t mFrameSizeBytes;
|
||||
const bool mIsInput;
|
||||
const std::weak_ptr<IBluetoothA2dp> mBluetoothA2dp;
|
||||
const std::weak_ptr<IBluetoothLe> mBluetoothLe;
|
||||
const size_t mPreferredDataIntervalUs;
|
||||
mutable std::mutex mLock;
|
||||
// The lock is also used to serialize calls to the proxy.
|
||||
std::shared_ptr<::android::bluetooth::audio::aidl::BluetoothAudioPortAidl> mBtDeviceProxy
|
||||
GUARDED_BY(mLock); // proxy may be null if the stream is not connected to a device
|
||||
};
|
||||
|
||||
class StreamInBluetooth final : public StreamIn, public StreamBluetooth {
|
||||
public:
|
||||
friend class ndk::SharedRefBase;
|
||||
|
||||
static int32_t getNominalLatencyMs(size_t dataIntervalUs);
|
||||
|
||||
StreamInBluetooth(
|
||||
StreamContext&& context,
|
||||
const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
|
||||
const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones,
|
||||
ModuleBluetooth::BtProfileHandles&& btHandles,
|
||||
const std::shared_ptr<::android::bluetooth::audio::aidl::BluetoothAudioPortAidl>&
|
||||
btDeviceProxy,
|
||||
const ::aidl::android::hardware::bluetooth::audio::PcmConfiguration& pcmConfig);
|
||||
|
||||
private:
|
||||
void onClose(StreamDescriptor::State) override { defaultOnClose(); }
|
||||
ndk::ScopedAStatus getActiveMicrophones(
|
||||
std::vector<::aidl::android::media::audio::common::MicrophoneDynamicInfo>* _aidl_return)
|
||||
override;
|
||||
};
|
||||
|
||||
class StreamOutBluetooth final : public StreamOut, public StreamBluetooth {
|
||||
public:
|
||||
friend class ndk::SharedRefBase;
|
||||
|
||||
static int32_t getNominalLatencyMs(size_t dataIntervalUs);
|
||||
|
||||
StreamOutBluetooth(
|
||||
StreamContext&& context,
|
||||
const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
|
||||
const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
|
||||
offloadInfo,
|
||||
ModuleBluetooth::BtProfileHandles&& btHandles,
|
||||
const std::shared_ptr<::android::bluetooth::audio::aidl::BluetoothAudioPortAidl>&
|
||||
btDeviceProxy,
|
||||
const ::aidl::android::hardware::bluetooth::audio::PcmConfiguration& pcmConfig);
|
||||
|
||||
private:
|
||||
void onClose(StreamDescriptor::State) override { defaultOnClose(); }
|
||||
};
|
||||
|
||||
} // namespace aidl::android::hardware::audio::core
|
||||
132
audio/include/core-impl/StreamMmapStub.h
Normal file
132
audio/include/core-impl/StreamMmapStub.h
Normal file
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright (C) 2025 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 <mutex>
|
||||
#include <string>
|
||||
|
||||
#include "core-impl/DriverStubImpl.h"
|
||||
#include "core-impl/Stream.h"
|
||||
|
||||
namespace aidl::android::hardware::audio::core {
|
||||
|
||||
namespace mmap {
|
||||
|
||||
struct DspSimulatorState {
|
||||
const bool isInput;
|
||||
const int sampleRate;
|
||||
const int frameSizeBytes;
|
||||
const size_t bufferSizeBytes;
|
||||
std::mutex lock;
|
||||
// The lock is also used to prevent un-mapping while the memory is in use.
|
||||
uint8_t* sharedMemory GUARDED_BY(lock) = nullptr;
|
||||
StreamDescriptor::Position mmapPos GUARDED_BY(lock);
|
||||
};
|
||||
|
||||
class DspSimulatorLogic : public ::android::hardware::audio::common::StreamLogic {
|
||||
protected:
|
||||
explicit DspSimulatorLogic(DspSimulatorState& sharedState) : mSharedState(sharedState) {}
|
||||
std::string init() override;
|
||||
Status cycle() override;
|
||||
|
||||
private:
|
||||
DspSimulatorState& mSharedState;
|
||||
uint32_t mCycleDurationUs = 0;
|
||||
uint8_t* mMemBegin = nullptr;
|
||||
uint8_t* mMemPos = nullptr;
|
||||
int64_t mLastFrames = 0;
|
||||
};
|
||||
|
||||
class DspSimulatorWorker
|
||||
: public ::android::hardware::audio::common::StreamWorker<DspSimulatorLogic> {
|
||||
public:
|
||||
explicit DspSimulatorWorker(DspSimulatorState& sharedState)
|
||||
: ::android::hardware::audio::common::StreamWorker<DspSimulatorLogic>(sharedState) {}
|
||||
};
|
||||
|
||||
} // namespace mmap
|
||||
|
||||
class DriverMmapStubImpl : public DriverStubImpl {
|
||||
public:
|
||||
explicit DriverMmapStubImpl(const StreamContext& context);
|
||||
::android::status_t init(DriverCallbackInterface* callback) override;
|
||||
::android::status_t drain(StreamDescriptor::DrainMode drainMode) override;
|
||||
::android::status_t pause() 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;
|
||||
::android::status_t refinePosition(StreamDescriptor::Position* position) override;
|
||||
::android::status_t getMmapPositionAndLatency(StreamDescriptor::Position* position,
|
||||
int32_t* latency) override;
|
||||
|
||||
protected:
|
||||
::android::status_t initSharedMemory(int ashmemFd);
|
||||
|
||||
private:
|
||||
::android::status_t releaseSharedMemory() REQUIRES(mState.lock);
|
||||
::android::status_t startWorkerIfNeeded();
|
||||
|
||||
mmap::DspSimulatorState mState;
|
||||
mmap::DspSimulatorWorker mDspWorker;
|
||||
bool mDspWorkerStarted = false;
|
||||
};
|
||||
|
||||
class StreamMmapStub : public StreamCommonImpl, public DriverMmapStubImpl {
|
||||
public:
|
||||
static const std::string kCreateMmapBufferName;
|
||||
|
||||
StreamMmapStub(StreamContext* context, const Metadata& metadata);
|
||||
~StreamMmapStub();
|
||||
|
||||
ndk::ScopedAStatus getVendorParameters(const std::vector<std::string>& in_ids,
|
||||
std::vector<VendorParameter>* _aidl_return) override;
|
||||
ndk::ScopedAStatus setVendorParameters(const std::vector<VendorParameter>& in_parameters,
|
||||
bool in_async) override;
|
||||
|
||||
private:
|
||||
ndk::ScopedAStatus createMmapBuffer(MmapBufferDescriptor* desc);
|
||||
|
||||
ndk::ScopedFileDescriptor mSharedMemoryFd;
|
||||
};
|
||||
|
||||
class StreamInMmapStub final : public StreamIn, public StreamMmapStub {
|
||||
public:
|
||||
friend class ndk::SharedRefBase;
|
||||
StreamInMmapStub(
|
||||
StreamContext&& context,
|
||||
const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
|
||||
const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones);
|
||||
|
||||
private:
|
||||
void onClose(StreamDescriptor::State) override { defaultOnClose(); }
|
||||
};
|
||||
|
||||
class StreamOutMmapStub final : public StreamOut, public StreamMmapStub {
|
||||
public:
|
||||
friend class ndk::SharedRefBase;
|
||||
StreamOutMmapStub(
|
||||
StreamContext&& context,
|
||||
const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
|
||||
const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
|
||||
offloadInfo);
|
||||
|
||||
private:
|
||||
void onClose(StreamDescriptor::State) override { defaultOnClose(); }
|
||||
};
|
||||
|
||||
} // namespace aidl::android::hardware::audio::core
|
||||
105
audio/include/core-impl/StreamOffloadStub.h
Normal file
105
audio/include/core-impl/StreamOffloadStub.h
Normal file
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright (C) 2025 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 <mutex>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "core-impl/DriverStubImpl.h"
|
||||
#include "core-impl/Stream.h"
|
||||
|
||||
namespace aidl::android::hardware::audio::core {
|
||||
|
||||
namespace offload {
|
||||
|
||||
struct DspSimulatorState {
|
||||
static constexpr int64_t kSkipBufferNotifyFrames = -1;
|
||||
|
||||
const std::string formatEncoding;
|
||||
const int sampleRate;
|
||||
const int64_t earlyNotifyFrames;
|
||||
DriverCallbackInterface* callback = nullptr; // set before starting DSP worker
|
||||
std::mutex lock;
|
||||
std::vector<int64_t> clipFramesLeft GUARDED_BY(lock);
|
||||
int64_t bufferFramesLeft GUARDED_BY(lock) = 0;
|
||||
int64_t bufferNotifyFrames GUARDED_BY(lock) = kSkipBufferNotifyFrames;
|
||||
};
|
||||
|
||||
class DspSimulatorLogic : public ::android::hardware::audio::common::StreamLogic {
|
||||
protected:
|
||||
explicit DspSimulatorLogic(DspSimulatorState& sharedState) : mSharedState(sharedState) {}
|
||||
std::string init() override;
|
||||
Status cycle() override;
|
||||
|
||||
private:
|
||||
DspSimulatorState& mSharedState;
|
||||
};
|
||||
|
||||
class DspSimulatorWorker
|
||||
: public ::android::hardware::audio::common::StreamWorker<DspSimulatorLogic> {
|
||||
public:
|
||||
explicit DspSimulatorWorker(DspSimulatorState& sharedState)
|
||||
: ::android::hardware::audio::common::StreamWorker<DspSimulatorLogic>(sharedState) {}
|
||||
};
|
||||
|
||||
} // namespace offload
|
||||
|
||||
class DriverOffloadStubImpl : public DriverStubImpl {
|
||||
public:
|
||||
explicit DriverOffloadStubImpl(const StreamContext& context);
|
||||
::android::status_t init(DriverCallbackInterface* callback) override;
|
||||
::android::status_t drain(StreamDescriptor::DrainMode drainMode) override;
|
||||
::android::status_t flush() override;
|
||||
::android::status_t pause() 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:
|
||||
::android::status_t startWorkerIfNeeded();
|
||||
|
||||
const int64_t mBufferNotifyFrames;
|
||||
offload::DspSimulatorState mState;
|
||||
offload::DspSimulatorWorker mDspWorker;
|
||||
bool mDspWorkerStarted = false;
|
||||
};
|
||||
|
||||
class StreamOffloadStub : public StreamCommonImpl, public DriverOffloadStubImpl {
|
||||
public:
|
||||
static const std::set<std::string>& getSupportedEncodings();
|
||||
|
||||
StreamOffloadStub(StreamContext* context, const Metadata& metadata);
|
||||
~StreamOffloadStub();
|
||||
};
|
||||
|
||||
class StreamOutOffloadStub final : public StreamOut, public StreamOffloadStub {
|
||||
public:
|
||||
friend class ndk::SharedRefBase;
|
||||
StreamOutOffloadStub(
|
||||
StreamContext&& context,
|
||||
const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
|
||||
const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
|
||||
offloadInfo);
|
||||
|
||||
private:
|
||||
void onClose(StreamDescriptor::State) override { defaultOnClose(); }
|
||||
};
|
||||
|
||||
} // namespace aidl::android::hardware::audio::core
|
||||
113
audio/include/core-impl/StreamPrimary.h
Normal file
113
audio/include/core-impl/StreamPrimary.h
Normal file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
#include <android-base/thread_annotations.h>
|
||||
|
||||
#include "DriverStubImpl.h"
|
||||
#include "StreamAlsa.h"
|
||||
#include "primary/PrimaryMixer.h"
|
||||
|
||||
namespace aidl::android::hardware::audio::core {
|
||||
|
||||
class StreamPrimary : public StreamAlsa {
|
||||
public:
|
||||
StreamPrimary(StreamContext* context, const Metadata& metadata);
|
||||
|
||||
// Methods of 'DriverInterface'.
|
||||
::android::status_t init(DriverCallbackInterface* callback) 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;
|
||||
long mFramesSinceStart = 0;
|
||||
bool mSkipNextTransfer = false;
|
||||
|
||||
private:
|
||||
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);
|
||||
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 StreamPrimary, public StreamInHwGainHelper {
|
||||
public:
|
||||
friend class ndk::SharedRefBase;
|
||||
StreamInPrimary(
|
||||
StreamContext&& context,
|
||||
const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
|
||||
const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones);
|
||||
|
||||
private:
|
||||
void onClose(StreamDescriptor::State) override { defaultOnClose(); }
|
||||
|
||||
ndk::ScopedAStatus getHwGain(std::vector<float>* _aidl_return) override;
|
||||
ndk::ScopedAStatus setHwGain(const std::vector<float>& in_channelGains) override;
|
||||
};
|
||||
|
||||
class StreamOutPrimary final : public StreamOut,
|
||||
public StreamPrimary,
|
||||
public StreamOutHwVolumeHelper {
|
||||
public:
|
||||
friend class ndk::SharedRefBase;
|
||||
StreamOutPrimary(StreamContext&& context,
|
||||
const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
|
||||
const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
|
||||
offloadInfo);
|
||||
|
||||
private:
|
||||
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;
|
||||
};
|
||||
|
||||
} // namespace aidl::android::hardware::audio::core
|
||||
116
audio/include/core-impl/StreamRemoteSubmix.h
Normal file
116
audio/include/core-impl/StreamRemoteSubmix.h
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "core-impl/Stream.h"
|
||||
#include "deprecated/StreamSwitcher.h"
|
||||
#include "r_submix/SubmixRoute.h"
|
||||
|
||||
namespace aidl::android::hardware::audio::core {
|
||||
|
||||
class StreamRemoteSubmix : public StreamCommonImpl {
|
||||
public:
|
||||
StreamRemoteSubmix(
|
||||
StreamContext* context, const Metadata& metadata,
|
||||
const ::aidl::android::media::audio::common::AudioDeviceAddress& deviceAddress);
|
||||
~StreamRemoteSubmix();
|
||||
|
||||
// Methods of 'DriverInterface'.
|
||||
::android::status_t init(DriverCallbackInterface*) 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;
|
||||
::android::status_t refinePosition(StreamDescriptor::Position* position) override;
|
||||
void shutdown() override;
|
||||
|
||||
// Overridden methods of 'StreamCommonImpl', called on a Binder thread.
|
||||
ndk::ScopedAStatus prepareToClose() override;
|
||||
|
||||
private:
|
||||
long getDelayInUsForFrameCount(size_t frameCount);
|
||||
size_t getStreamPipeSizeInFrames();
|
||||
::android::status_t outWrite(void* buffer, size_t frameCount, size_t* actualFrameCount);
|
||||
::android::status_t inRead(void* buffer, size_t frameCount, size_t* actualFrameCount);
|
||||
|
||||
const ::aidl::android::media::audio::common::AudioDeviceAddress mDeviceAddress;
|
||||
const bool mIsInput;
|
||||
r_submix::AudioConfig mStreamConfig;
|
||||
std::shared_ptr<r_submix::SubmixRoute> mCurrentRoute = nullptr;
|
||||
|
||||
// Limit for the number of error log entries to avoid spamming the logs.
|
||||
static constexpr int kMaxErrorLogs = 5;
|
||||
// The duration of kMaxReadFailureAttempts * READ_ATTEMPT_SLEEP_MS must be strictly inferior
|
||||
// to the duration of a record buffer at the current record sample rate (of the device, not of
|
||||
// the recording itself). Here we have: 3 * 5ms = 15ms < 1024 frames * 1000 / 48000 = 21.333ms
|
||||
static constexpr int kMaxReadFailureAttempts = 3;
|
||||
// 5ms between two read attempts when pipe is empty
|
||||
static constexpr int kReadAttemptSleepUs = 5000;
|
||||
|
||||
int64_t mStartTimeNs = 0;
|
||||
long mFramesSinceStart = 0;
|
||||
int mReadErrorCount = 0;
|
||||
int mReadFailureCount = 0;
|
||||
int mWriteShutdownCount = 0;
|
||||
};
|
||||
|
||||
class StreamInRemoteSubmix final : public StreamIn, public deprecated::StreamSwitcher {
|
||||
public:
|
||||
friend class ndk::SharedRefBase;
|
||||
StreamInRemoteSubmix(
|
||||
StreamContext&& context,
|
||||
const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
|
||||
const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones);
|
||||
|
||||
private:
|
||||
DeviceSwitchBehavior switchCurrentStream(
|
||||
const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices)
|
||||
override;
|
||||
std::unique_ptr<deprecated::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 getActiveMicrophones(
|
||||
std::vector<::aidl::android::media::audio::common::MicrophoneDynamicInfo>* _aidl_return)
|
||||
override;
|
||||
};
|
||||
|
||||
class StreamOutRemoteSubmix final : public StreamOut, public deprecated::StreamSwitcher {
|
||||
public:
|
||||
friend class ndk::SharedRefBase;
|
||||
StreamOutRemoteSubmix(
|
||||
StreamContext&& context,
|
||||
const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
|
||||
const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
|
||||
offloadInfo);
|
||||
|
||||
private:
|
||||
DeviceSwitchBehavior switchCurrentStream(
|
||||
const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices)
|
||||
override;
|
||||
std::unique_ptr<deprecated::StreamCommonInterfaceEx> createNewStream(
|
||||
const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices,
|
||||
StreamContext* context, const Metadata& metadata) override;
|
||||
void onClose(StreamDescriptor::State) override { defaultOnClose(); }
|
||||
};
|
||||
|
||||
} // namespace aidl::android::hardware::audio::core
|
||||
54
audio/include/core-impl/StreamStub.h
Normal file
54
audio/include/core-impl/StreamStub.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core-impl/DriverStubImpl.h"
|
||||
#include "core-impl/Stream.h"
|
||||
|
||||
namespace aidl::android::hardware::audio::core {
|
||||
|
||||
class StreamStub : public StreamCommonImpl, public DriverStubImpl {
|
||||
public:
|
||||
StreamStub(StreamContext* context, const Metadata& metadata);
|
||||
~StreamStub();
|
||||
};
|
||||
|
||||
class StreamInStub final : public StreamIn, public StreamStub {
|
||||
public:
|
||||
friend class ndk::SharedRefBase;
|
||||
StreamInStub(
|
||||
StreamContext&& context,
|
||||
const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
|
||||
const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones);
|
||||
|
||||
private:
|
||||
void onClose(StreamDescriptor::State) override { defaultOnClose(); }
|
||||
};
|
||||
|
||||
class StreamOutStub final : public StreamOut, public StreamStub {
|
||||
public:
|
||||
friend class ndk::SharedRefBase;
|
||||
StreamOutStub(StreamContext&& context,
|
||||
const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
|
||||
const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
|
||||
offloadInfo);
|
||||
|
||||
private:
|
||||
void onClose(StreamDescriptor::State) override { defaultOnClose(); }
|
||||
};
|
||||
|
||||
} // namespace aidl::android::hardware::audio::core
|
||||
77
audio/include/core-impl/StreamUsb.h
Normal file
77
audio/include/core-impl/StreamUsb.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
#include <aidl/android/media/audio/common/AudioChannelLayout.h>
|
||||
|
||||
#include "StreamAlsa.h"
|
||||
|
||||
namespace aidl::android::hardware::audio::core {
|
||||
|
||||
class StreamUsb : public StreamAlsa {
|
||||
public:
|
||||
StreamUsb(StreamContext* context, const Metadata& metadata);
|
||||
|
||||
// Methods of 'DriverInterface'.
|
||||
::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
|
||||
int32_t* latencyMs) override;
|
||||
|
||||
// Overridden methods of 'StreamCommonImpl', called on a Binder thread.
|
||||
ndk::ScopedAStatus setConnectedDevices(const ConnectedDevices& devices) override;
|
||||
|
||||
protected:
|
||||
std::vector<alsa::DeviceProfile> getDeviceProfiles() override;
|
||||
|
||||
mutable std::mutex mLock;
|
||||
std::vector<alsa::DeviceProfile> mConnectedDeviceProfiles GUARDED_BY(mLock);
|
||||
std::atomic<bool> mConnectedDevicesUpdated = false;
|
||||
};
|
||||
|
||||
class StreamInUsb final : public StreamIn, public StreamUsb {
|
||||
public:
|
||||
friend class ndk::SharedRefBase;
|
||||
StreamInUsb(
|
||||
StreamContext&& context,
|
||||
const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
|
||||
const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones);
|
||||
|
||||
private:
|
||||
void onClose(StreamDescriptor::State) override { defaultOnClose(); }
|
||||
ndk::ScopedAStatus getActiveMicrophones(
|
||||
std::vector<::aidl::android::media::audio::common::MicrophoneDynamicInfo>* _aidl_return)
|
||||
override;
|
||||
};
|
||||
|
||||
class StreamOutUsb final : public StreamOut, public StreamUsb, public StreamOutHwVolumeHelper {
|
||||
public:
|
||||
friend class ndk::SharedRefBase;
|
||||
StreamOutUsb(StreamContext&& context,
|
||||
const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
|
||||
const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
|
||||
offloadInfo);
|
||||
|
||||
private:
|
||||
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;
|
||||
};
|
||||
|
||||
} // namespace aidl::android::hardware::audio::core
|
||||
47
audio/include/core-impl/Telephony.h
Normal file
47
audio/include/core-impl/Telephony.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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 <android/binder_enums.h>
|
||||
|
||||
#include <aidl/android/hardware/audio/core/BnTelephony.h>
|
||||
|
||||
namespace aidl::android::hardware::audio::core {
|
||||
|
||||
class Telephony : public BnTelephony {
|
||||
public:
|
||||
Telephony();
|
||||
|
||||
private:
|
||||
ndk::ScopedAStatus getSupportedAudioModes(
|
||||
std::vector<::aidl::android::media::audio::common::AudioMode>* _aidl_return) override;
|
||||
ndk::ScopedAStatus switchAudioMode(
|
||||
::aidl::android::media::audio::common::AudioMode in_mode) override;
|
||||
ndk::ScopedAStatus setTelecomConfig(const TelecomConfig& in_config,
|
||||
TelecomConfig* _aidl_return) override;
|
||||
|
||||
const std::vector<::aidl::android::media::audio::common::AudioMode> mSupportedAudioModes = {
|
||||
::aidl::android::media::audio::common::AudioMode::NORMAL,
|
||||
::aidl::android::media::audio::common::AudioMode::RINGTONE,
|
||||
::aidl::android::media::audio::common::AudioMode::IN_CALL,
|
||||
::aidl::android::media::audio::common::AudioMode::IN_COMMUNICATION,
|
||||
// Omit CALL_SCREEN for a better VTS coverage.
|
||||
};
|
||||
TelecomConfig mTelecomConfig;
|
||||
};
|
||||
|
||||
} // namespace aidl::android::hardware::audio::core
|
||||
162
audio/include/core-impl/XmlConverter.h
Normal file
162
audio/include/core-impl/XmlConverter.h
Normal file
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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 <optional>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <media/AidlConversionUtil.h>
|
||||
#include <system/audio_config.h>
|
||||
|
||||
namespace aidl::android::hardware::audio::core::internal {
|
||||
|
||||
template <typename T>
|
||||
class XmlConverter {
|
||||
public:
|
||||
XmlConverter(const std::string& configFilePath,
|
||||
std::function<std::optional<T>(const char*)> readXmlConfig)
|
||||
: XmlConverter(configFilePath,
|
||||
::android::audio_is_readable_configuration_file(configFilePath.c_str()),
|
||||
readXmlConfig) {}
|
||||
|
||||
const ::android::status_t& getStatus() const { return mStatus; }
|
||||
|
||||
const std::string& getError() const { return mErrorMessage; }
|
||||
|
||||
const std::optional<T>& getXsdcConfig() const { return mXsdcConfig; }
|
||||
|
||||
private:
|
||||
XmlConverter(const std::string& configFilePath, const bool& isReadableConfigFile,
|
||||
const std::function<std::optional<T>(const char*)>& readXmlConfig)
|
||||
: mXsdcConfig{isReadableConfigFile ? readXmlConfig(configFilePath.c_str()) : std::nullopt},
|
||||
mStatus(mXsdcConfig ? ::android::OK : ::android::NO_INIT),
|
||||
mErrorMessage(generateError(configFilePath, isReadableConfigFile, mStatus)) {}
|
||||
|
||||
static std::string generateError(const std::string& configFilePath,
|
||||
const bool& isReadableConfigFile,
|
||||
const ::android::status_t& status) {
|
||||
std::string errorMessage;
|
||||
if (status != ::android::OK) {
|
||||
if (configFilePath.empty()) {
|
||||
errorMessage = "No audio configuration files found";
|
||||
} else if (!isReadableConfigFile) {
|
||||
errorMessage = std::string("Could not read requested XML config file: \"")
|
||||
.append(configFilePath)
|
||||
.append("\"");
|
||||
} else {
|
||||
errorMessage = std::string("Invalid XML config file: \"")
|
||||
.append(configFilePath)
|
||||
.append("\"");
|
||||
}
|
||||
}
|
||||
return errorMessage;
|
||||
}
|
||||
|
||||
const std::optional<T> mXsdcConfig;
|
||||
const ::android::status_t mStatus;
|
||||
const std::string mErrorMessage;
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts a vector of an xsd wrapper type to a flat vector of the
|
||||
* corresponding AIDL type.
|
||||
*
|
||||
* Wrapper types are used in order to have well-formed xIncludes. In the
|
||||
* example below, Modules is the wrapper type for Module.
|
||||
* <Modules>
|
||||
* <Module> ... </Module>
|
||||
* <Module> ... </Module>
|
||||
* </Modules>
|
||||
*/
|
||||
template <typename W, typename X, typename A>
|
||||
static ConversionResult<std::vector<A>> convertWrappedCollectionToAidl(
|
||||
const std::vector<W>& xsdcWrapperTypeVec,
|
||||
std::function<const std::vector<X>&(const W&)> getInnerTypeVec,
|
||||
std::function<ConversionResult<A>(const X&)> convertToAidl) {
|
||||
std::vector<A> resultAidlTypeVec;
|
||||
if (!xsdcWrapperTypeVec.empty()) {
|
||||
/*
|
||||
* xsdcWrapperTypeVec likely only contains one element; that is, it's
|
||||
* likely that all the inner types that we need to convert are inside of
|
||||
* xsdcWrapperTypeVec[0].
|
||||
*/
|
||||
resultAidlTypeVec.reserve(getInnerTypeVec(xsdcWrapperTypeVec[0]).size());
|
||||
for (const W& xsdcWrapperType : xsdcWrapperTypeVec) {
|
||||
for (const X& xsdcType : getInnerTypeVec(xsdcWrapperType)) {
|
||||
resultAidlTypeVec.push_back(VALUE_OR_FATAL(convertToAidl(xsdcType)));
|
||||
}
|
||||
}
|
||||
}
|
||||
return resultAidlTypeVec;
|
||||
}
|
||||
|
||||
template <typename X, typename A>
|
||||
static ConversionResult<std::vector<std::optional<A>>> convertCollectionToAidlOptionalValues(
|
||||
const std::vector<X>& xsdcTypeVec,
|
||||
std::function<ConversionResult<A>(const X&)> convertToAidl) {
|
||||
std::vector<std::optional<A>> resultAidlTypeVec;
|
||||
resultAidlTypeVec.reserve(xsdcTypeVec.size());
|
||||
for (const X& xsdcType : xsdcTypeVec) {
|
||||
resultAidlTypeVec.push_back(
|
||||
std::optional<A>(std::move(VALUE_OR_FATAL(convertToAidl(xsdcType)))));
|
||||
}
|
||||
return resultAidlTypeVec;
|
||||
}
|
||||
|
||||
template <typename X, typename A>
|
||||
static ConversionResult<std::vector<A>> convertCollectionToAidl(
|
||||
const std::vector<X>& xsdcTypeVec,
|
||||
std::function<ConversionResult<A>(const X&)> convertToAidl) {
|
||||
std::vector<A> resultAidlTypeVec;
|
||||
resultAidlTypeVec.reserve(xsdcTypeVec.size());
|
||||
for (const X& xsdcType : xsdcTypeVec) {
|
||||
resultAidlTypeVec.push_back(VALUE_OR_FATAL(convertToAidl(xsdcType)));
|
||||
}
|
||||
return resultAidlTypeVec;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a map of xsd references, keyed by reference name, given a
|
||||
* vector of wrapper types for the reference.
|
||||
*
|
||||
* Wrapper types are used in order to have well-formed xIncludes. In the
|
||||
* example below, Wrapper is the wrapper type for Reference.
|
||||
* <Wrapper>
|
||||
* <Reference> ... </Reference>
|
||||
* <Reference> ... </Reference>
|
||||
* </Wrapper>
|
||||
*/
|
||||
template <typename W, typename R>
|
||||
std::unordered_map<std::string, R> generateReferenceMap(const std::vector<W>& xsdcWrapperTypeVec) {
|
||||
std::unordered_map<std::string, R> resultMap;
|
||||
if (!xsdcWrapperTypeVec.empty()) {
|
||||
/*
|
||||
* xsdcWrapperTypeVec likely only contains one element; that is, it's
|
||||
* likely that all the inner types that we need to convert are inside of
|
||||
* xsdcWrapperTypeVec[0].
|
||||
*/
|
||||
resultMap.reserve(xsdcWrapperTypeVec[0].getReference().size());
|
||||
for (const W& xsdcWrapperType : xsdcWrapperTypeVec) {
|
||||
for (const R& xsdcReference : xsdcWrapperType.getReference()) {
|
||||
resultMap.insert({xsdcReference.getName(), xsdcReference});
|
||||
}
|
||||
}
|
||||
}
|
||||
return resultMap;
|
||||
}
|
||||
} // namespace aidl::android::hardware::audio::core::internal
|
||||
68
audio/include/core-impl/XsdcConversion.h
Normal file
68
audio/include/core-impl/XsdcConversion.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* 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 <string>
|
||||
|
||||
#include <aidl/android/media/audio/common/AudioHalCapCriterion.h>
|
||||
#include <aidl/android/media/audio/common/AudioHalCapCriterionType.h>
|
||||
#include <aidl/android/media/audio/common/AudioHalCapCriterionV2.h>
|
||||
#include <aidl/android/media/audio/common/AudioHalVolumeCurve.h>
|
||||
#include <aidl/android/media/audio/common/AudioPort.h>
|
||||
#include <android_audio_policy_configuration.h>
|
||||
#include <android_audio_policy_configuration_enums.h>
|
||||
#include <android_audio_policy_engine_configuration.h>
|
||||
#include <media/AidlConversionUtil.h>
|
||||
|
||||
#include "core-impl/Module.h"
|
||||
|
||||
namespace aidl::android::hardware::audio::core::internal {
|
||||
|
||||
namespace engineconfiguration = ::android::audio::policy::engine::configuration;
|
||||
namespace aidlaudiocommon = ::aidl::android::media::audio::common;
|
||||
|
||||
static constexpr const char kXsdcForceConfigForUse[] = "ForceUseFor";
|
||||
|
||||
ConversionResult<aidlaudiocommon::AudioPolicyForceUse> convertForceUseToAidl(
|
||||
const std::string& xsdcCriterionName, const std::string& xsdcCriterionValue);
|
||||
ConversionResult<aidlaudiocommon::AudioDeviceAddress> convertDeviceAddressToAidl(
|
||||
const std::string& xsdcAddress);
|
||||
ConversionResult<aidlaudiocommon::AudioMode> convertTelephonyModeToAidl(
|
||||
const std::string& xsdcModeCriterionType);
|
||||
ConversionResult<aidlaudiocommon::AudioDeviceDescription> convertDeviceTypeToAidl(
|
||||
const std::string& xType);
|
||||
ConversionResult<std::vector<std::optional<aidlaudiocommon::AudioHalCapCriterionV2>>>
|
||||
convertCapCriteriaCollectionToAidl(
|
||||
const std::vector<engineconfiguration::CriteriaType>& xsdcCriteriaVec,
|
||||
const std::vector<engineconfiguration::CriterionTypesType>& xsdcCriterionTypesVec);
|
||||
ConversionResult<aidlaudiocommon::AudioHalCapCriterionV2> convertCapCriterionV2ToAidl(
|
||||
const engineconfiguration::CriterionType& xsdcCriterion,
|
||||
const std::vector<engineconfiguration::CriterionTypesType>& xsdcCriterionTypesVec);
|
||||
ConversionResult<aidlaudiocommon::AudioHalVolumeCurve::CurvePoint> convertCurvePointToAidl(
|
||||
const std::string& xsdcCurvePoint);
|
||||
ConversionResult<std::unique_ptr<Module::Configuration>> convertModuleConfigToAidl(
|
||||
const ::android::audio::policy::configuration::Modules::Module& moduleConfig);
|
||||
ConversionResult<aidlaudiocommon::AudioUsage> convertAudioUsageToAidl(
|
||||
const engineconfiguration::UsageEnumType& xsdcUsage);
|
||||
ConversionResult<aidlaudiocommon::AudioContentType> convertAudioContentTypeToAidl(
|
||||
const engineconfiguration::ContentType& xsdcContentType);
|
||||
ConversionResult<aidlaudiocommon::AudioSource> convertAudioSourceToAidl(
|
||||
const engineconfiguration::SourceEnumType& xsdcSourceType);
|
||||
ConversionResult<aidlaudiocommon::AudioStreamType> convertAudioStreamTypeToAidl(
|
||||
const engineconfiguration::Stream& xsdStreamType);
|
||||
ConversionResult<int32_t> convertAudioFlagsToAidl(
|
||||
const std::vector<engineconfiguration::FlagType>& xsdcFlagTypeVec);
|
||||
std::unordered_map<std::string, int> getLegacyProductStrategyMap();
|
||||
} // namespace aidl::android::hardware::audio::core::internal
|
||||
122
audio/include/core-impl/utils.h
Normal file
122
audio/include/core-impl/utils.h
Normal file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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 <algorithm>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
namespace aidl::android::hardware::audio::core {
|
||||
|
||||
// Return whether all the elements in the vector are unique.
|
||||
template <typename T>
|
||||
bool all_unique(const std::vector<T>& v) {
|
||||
return std::set<T>(v.begin(), v.end()).size() == v.size();
|
||||
}
|
||||
|
||||
// Erase all the specified elements from a map.
|
||||
template <typename C, typename V>
|
||||
auto erase_all(C& c, const V& keys) {
|
||||
auto oldSize = c.size();
|
||||
for (auto& k : keys) {
|
||||
c.erase(k);
|
||||
}
|
||||
return oldSize - c.size();
|
||||
}
|
||||
|
||||
// Erase all the elements in the container that satisfy the provided predicate.
|
||||
template <typename C, typename P>
|
||||
auto erase_if(C& c, P pred) {
|
||||
auto oldSize = c.size();
|
||||
for (auto it = c.begin(); it != c.end();) {
|
||||
if (pred(*it)) {
|
||||
it = c.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
return oldSize - c.size();
|
||||
}
|
||||
|
||||
// Erase all the elements in the map that have specified values.
|
||||
template <typename C, typename V>
|
||||
auto erase_all_values(C& c, const V& values) {
|
||||
return erase_if(c, [values](const auto& pair) { return values.count(pair.second) != 0; });
|
||||
}
|
||||
|
||||
// Return non-zero count of elements for any of the provided keys.
|
||||
template <typename M, typename V>
|
||||
size_t count_any(const M& m, const V& keys) {
|
||||
for (auto& k : keys) {
|
||||
if (size_t c = m.count(k); c != 0) return c;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Assuming that M is a map whose values have an 'id' field,
|
||||
// find an element with the specified id.
|
||||
template <typename M>
|
||||
auto findById(M& m, int32_t id) {
|
||||
return std::find_if(m.begin(), m.end(), [&](const auto& p) { return p.second.id == id; });
|
||||
}
|
||||
|
||||
// Assuming that the vector contains elements with an 'id' field,
|
||||
// find an element with the specified id.
|
||||
template <typename T>
|
||||
auto findById(std::vector<T>& v, int32_t id) {
|
||||
return std::find_if(v.begin(), v.end(), [&](const auto& e) { return e.id == id; });
|
||||
}
|
||||
|
||||
// Return elements from the vector that have specified ids, also
|
||||
// optionally return which ids were not found.
|
||||
template <typename T>
|
||||
std::vector<T*> selectByIds(std::vector<T>& v, const std::vector<int32_t>& ids,
|
||||
std::vector<int32_t>* missingIds = nullptr) {
|
||||
std::vector<T*> result;
|
||||
std::set<int32_t> idsSet(ids.begin(), ids.end());
|
||||
for (size_t i = 0; i < v.size(); ++i) {
|
||||
T& e = v[i];
|
||||
if (idsSet.count(e.id) != 0) {
|
||||
result.push_back(&v[i]);
|
||||
idsSet.erase(e.id);
|
||||
}
|
||||
}
|
||||
if (missingIds) {
|
||||
*missingIds = std::vector(idsSet.begin(), idsSet.end());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Assuming that M is a map whose keys' type is K and values' type is V,
|
||||
// return the corresponding value of the given key from the map or default
|
||||
// value if the key is not found.
|
||||
template <typename M, typename K, typename V>
|
||||
auto findValueOrDefault(const M& m, const K& key, V defaultValue) {
|
||||
auto it = m.find(key);
|
||||
return it == m.end() ? defaultValue : it->second;
|
||||
}
|
||||
|
||||
// Assuming that M is a map whose keys' type is K, return the given key if it
|
||||
// is found from the map or default value.
|
||||
template <typename M, typename K>
|
||||
auto findKeyOrDefault(const M& m, const K& key, K defaultValue) {
|
||||
auto it = m.find(key);
|
||||
return it == m.end() ? defaultValue : key;
|
||||
}
|
||||
|
||||
} // namespace aidl::android::hardware::audio::core
|
||||
121
audio/include/effect-impl/EffectContext.h
Normal file
121
audio/include/effect-impl/EffectContext.h
Normal file
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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 <memory>
|
||||
#include <vector>
|
||||
|
||||
#include <Utils.h>
|
||||
#include <android-base/logging.h>
|
||||
#include <fmq/AidlMessageQueue.h>
|
||||
#include <fmq/EventFlag.h>
|
||||
|
||||
#include <aidl/android/hardware/audio/effect/BnEffect.h>
|
||||
#include "EffectTypes.h"
|
||||
|
||||
namespace aidl::android::hardware::audio::effect {
|
||||
|
||||
class EffectContext {
|
||||
public:
|
||||
typedef ::android::AidlMessageQueue<
|
||||
IEffect::Status, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
|
||||
StatusMQ;
|
||||
typedef ::android::AidlMessageQueue<
|
||||
float, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
|
||||
DataMQ;
|
||||
|
||||
EffectContext(size_t statusDepth, const Parameter::Common& common);
|
||||
virtual ~EffectContext() {
|
||||
if (mEfGroup) {
|
||||
::android::hardware::EventFlag::deleteEventFlag(&mEfGroup);
|
||||
}
|
||||
}
|
||||
|
||||
void setVersion(int version) { mVersion = version; }
|
||||
std::shared_ptr<StatusMQ> getStatusFmq() const;
|
||||
std::shared_ptr<DataMQ> getInputDataFmq() const;
|
||||
std::shared_ptr<DataMQ> getOutputDataFmq() const;
|
||||
|
||||
float* getWorkBuffer();
|
||||
size_t getWorkBufferSize() const;
|
||||
|
||||
// reset buffer status by abandon input data in FMQ
|
||||
void resetBuffer();
|
||||
void dupeFmq(IEffect::OpenEffectReturn* effectRet);
|
||||
size_t getInputFrameSize() const;
|
||||
size_t getOutputFrameSize() const;
|
||||
int getSessionId() const;
|
||||
int getIoHandle() const;
|
||||
|
||||
virtual void dupeFmqWithReopen(IEffect::OpenEffectReturn* effectRet);
|
||||
|
||||
virtual RetCode setOutputDevice(
|
||||
const std::vector<aidl::android::media::audio::common::AudioDeviceDescription>& device);
|
||||
|
||||
virtual std::vector<aidl::android::media::audio::common::AudioDeviceDescription>
|
||||
getOutputDevice();
|
||||
|
||||
virtual RetCode setAudioMode(const aidl::android::media::audio::common::AudioMode& mode);
|
||||
virtual aidl::android::media::audio::common::AudioMode getAudioMode();
|
||||
|
||||
virtual RetCode setAudioSource(const aidl::android::media::audio::common::AudioSource& source);
|
||||
virtual aidl::android::media::audio::common::AudioSource getAudioSource();
|
||||
|
||||
virtual RetCode setVolumeStereo(const Parameter::VolumeStereo& volumeStereo);
|
||||
virtual Parameter::VolumeStereo getVolumeStereo();
|
||||
|
||||
virtual RetCode setCommon(const Parameter::Common& common);
|
||||
virtual Parameter::Common getCommon();
|
||||
|
||||
virtual ::android::hardware::EventFlag* getStatusEventFlag();
|
||||
|
||||
virtual RetCode enable();
|
||||
virtual RetCode disable();
|
||||
virtual RetCode reset();
|
||||
|
||||
virtual RetCode startDraining();
|
||||
virtual RetCode finishDraining();
|
||||
virtual bool isDraining();
|
||||
|
||||
protected:
|
||||
bool mIsDraining = false;
|
||||
int mVersion = 0;
|
||||
size_t mInputFrameSize = 0;
|
||||
size_t mOutputFrameSize = 0;
|
||||
size_t mInputChannelCount = 0;
|
||||
size_t mOutputChannelCount = 0;
|
||||
Parameter::Common mCommon = {};
|
||||
std::vector<aidl::android::media::audio::common::AudioDeviceDescription> mOutputDevice = {};
|
||||
aidl::android::media::audio::common::AudioMode mMode =
|
||||
aidl::android::media::audio::common::AudioMode::SYS_RESERVED_INVALID;
|
||||
aidl::android::media::audio::common::AudioSource mSource =
|
||||
aidl::android::media::audio::common::AudioSource::SYS_RESERVED_INVALID;
|
||||
Parameter::VolumeStereo mVolumeStereo = {};
|
||||
RetCode updateIOFrameSize(const Parameter::Common& common);
|
||||
RetCode notifyDataMqUpdate();
|
||||
|
||||
private:
|
||||
// fmq and buffers
|
||||
std::shared_ptr<StatusMQ> mStatusMQ = nullptr;
|
||||
std::shared_ptr<DataMQ> mInputMQ = nullptr;
|
||||
std::shared_ptr<DataMQ> mOutputMQ = nullptr;
|
||||
// std::shared_ptr<IEffect::OpenEffectReturn> mRet;
|
||||
// work buffer set by effect instances, the access and update are in same thread
|
||||
std::vector<float> mWorkBuffer = {};
|
||||
|
||||
::android::hardware::EventFlag* mEfGroup = nullptr;
|
||||
};
|
||||
} // namespace aidl::android::hardware::audio::effect
|
||||
122
audio/include/effect-impl/EffectImpl.h
Normal file
122
audio/include/effect-impl/EffectImpl.h
Normal file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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 <cstdlib>
|
||||
#include <memory>
|
||||
|
||||
#include <aidl/android/hardware/audio/effect/BnEffect.h>
|
||||
#include <fmq/AidlMessageQueue.h>
|
||||
|
||||
#include "EffectContext.h"
|
||||
#include "EffectThread.h"
|
||||
#include "EffectTypes.h"
|
||||
#include "effect-impl/EffectContext.h"
|
||||
#include "effect-impl/EffectThread.h"
|
||||
#include "effect-impl/EffectTypes.h"
|
||||
|
||||
extern "C" binder_exception_t destroyEffect(
|
||||
const std::shared_ptr<aidl::android::hardware::audio::effect::IEffect>& instanceSp);
|
||||
|
||||
namespace aidl::android::hardware::audio::effect {
|
||||
|
||||
class EffectImpl : public BnEffect, public EffectThread {
|
||||
public:
|
||||
EffectImpl() = default;
|
||||
virtual ~EffectImpl() = default;
|
||||
|
||||
virtual ndk::ScopedAStatus open(const Parameter::Common& common,
|
||||
const std::optional<Parameter::Specific>& specific,
|
||||
OpenEffectReturn* ret) override;
|
||||
virtual ndk::ScopedAStatus close() override;
|
||||
virtual ndk::ScopedAStatus command(CommandId id) override;
|
||||
virtual ndk::ScopedAStatus reopen(OpenEffectReturn* ret) override;
|
||||
|
||||
virtual ndk::ScopedAStatus getState(State* state) override;
|
||||
virtual ndk::ScopedAStatus setParameter(const Parameter& param) override;
|
||||
virtual ndk::ScopedAStatus getParameter(const Parameter::Id& id, Parameter* param) override;
|
||||
|
||||
virtual ndk::ScopedAStatus setParameterCommon(const Parameter& param) REQUIRES(mImplMutex);
|
||||
virtual ndk::ScopedAStatus getParameterCommon(const Parameter::Tag& tag, Parameter* param)
|
||||
REQUIRES(mImplMutex);
|
||||
|
||||
/* Methods MUST be implemented by each effect instances */
|
||||
virtual ndk::ScopedAStatus getDescriptor(Descriptor* desc) = 0;
|
||||
virtual ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
|
||||
REQUIRES(mImplMutex) = 0;
|
||||
virtual ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
|
||||
Parameter::Specific* specific)
|
||||
REQUIRES(mImplMutex) = 0;
|
||||
|
||||
virtual std::string getEffectName() = 0;
|
||||
virtual std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
|
||||
REQUIRES(mImplMutex);
|
||||
virtual RetCode releaseContext() REQUIRES(mImplMutex) = 0;
|
||||
|
||||
/**
|
||||
* @brief effectProcessImpl is running in worker thread which created in EffectThread.
|
||||
*
|
||||
* EffectThread will make sure effectProcessImpl only be called after startThread() successful
|
||||
* and before stopThread() successful.
|
||||
*
|
||||
* effectProcessImpl implementation must not call any EffectThread interface, otherwise it will
|
||||
* cause deadlock.
|
||||
*
|
||||
* @param in address of input float buffer.
|
||||
* @param out address of output float buffer.
|
||||
* @param samples number of samples to process.
|
||||
* @return IEffect::Status
|
||||
*/
|
||||
virtual IEffect::Status effectProcessImpl(float* in, float* out, int samples) = 0;
|
||||
|
||||
/**
|
||||
* process() get data from data MQs, and call effectProcessImpl() for effect data processing.
|
||||
* Its important for the implementation to use mImplMutex for context synchronization.
|
||||
*/
|
||||
void process() override;
|
||||
|
||||
protected:
|
||||
// current Hal version
|
||||
int mVersion = 0;
|
||||
// Use kEventFlagNotEmpty for V1 HAL, kEventFlagDataMqNotEmpty for V2 and above
|
||||
int mDataMqNotEmptyEf = aidl::android::hardware::audio::effect::kEventFlagDataMqNotEmpty;
|
||||
|
||||
State mState GUARDED_BY(mImplMutex) = State::INIT;
|
||||
|
||||
IEffect::Status status(binder_status_t status, size_t consumed, size_t produced);
|
||||
void cleanUp();
|
||||
|
||||
std::mutex mImplMutex;
|
||||
std::shared_ptr<EffectContext> mImplContext GUARDED_BY(mImplMutex);
|
||||
|
||||
/**
|
||||
* Optional CommandId handling methods for effects to override.
|
||||
* For CommandId::START, EffectImpl call commandImpl before starting the EffectThread
|
||||
* processing.
|
||||
* For CommandId::STOP and CommandId::RESET, EffectImpl call commandImpl after stop the
|
||||
* EffectThread processing.
|
||||
*/
|
||||
virtual ndk::ScopedAStatus commandImpl(CommandId id) REQUIRES(mImplMutex);
|
||||
|
||||
RetCode notifyEventFlag(uint32_t flag);
|
||||
|
||||
std::string getEffectNameWithVersion() {
|
||||
return getEffectName() + "V" + std::to_string(mVersion);
|
||||
}
|
||||
|
||||
::android::hardware::EventFlag* mEventFlag;
|
||||
};
|
||||
} // namespace aidl::android::hardware::audio::effect
|
||||
48
audio/include/effect-impl/EffectRange.h
Normal file
48
audio/include/effect-impl/EffectRange.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace aidl::android::hardware::audio::effect {
|
||||
|
||||
template <typename T>
|
||||
bool isInRange(const T& value, const T& low, const T& high) {
|
||||
return (value >= low) && (value <= high);
|
||||
}
|
||||
|
||||
template <typename T, std::size_t... Is>
|
||||
bool isTupleInRange(const T& test, const T& min, const T& max, std::index_sequence<Is...>) {
|
||||
return (isInRange(std::get<Is>(test), std::get<Is>(min), std::get<Is>(max)) && ...);
|
||||
}
|
||||
|
||||
template <typename T, std::size_t TupSize = std::tuple_size_v<T>>
|
||||
bool isTupleInRange(const T& test, const T& min, const T& max) {
|
||||
return isTupleInRange(test, min, max, std::make_index_sequence<TupSize>{});
|
||||
}
|
||||
|
||||
template <typename T, typename F>
|
||||
bool isTupleInRange(const std::vector<T>& cfgs, const T& min, const T& max, const F& func) {
|
||||
auto minT = func(min), maxT = func(max);
|
||||
return std::all_of(cfgs.cbegin(), cfgs.cend(),
|
||||
[&](const T& cfg) { return isTupleInRange(func(cfg), minT, maxT); });
|
||||
}
|
||||
|
||||
} // namespace aidl::android::hardware::audio::effect
|
||||
69
audio/include/effect-impl/EffectThread.h
Normal file
69
audio/include/effect-impl/EffectThread.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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 <atomic>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
#include <android-base/thread_annotations.h>
|
||||
#include <fmq/EventFlag.h>
|
||||
#include <system/thread_defs.h>
|
||||
|
||||
#include "effect-impl/EffectContext.h"
|
||||
#include "effect-impl/EffectTypes.h"
|
||||
|
||||
namespace aidl::android::hardware::audio::effect {
|
||||
|
||||
class EffectThread {
|
||||
public:
|
||||
virtual ~EffectThread();
|
||||
|
||||
// called by effect implementation
|
||||
RetCode createThread(const std::string& name, int priority = ANDROID_PRIORITY_URGENT_AUDIO);
|
||||
RetCode destroyThread();
|
||||
RetCode startThread();
|
||||
RetCode stopThread();
|
||||
RetCode startDraining();
|
||||
RetCode finishDraining();
|
||||
|
||||
// Will call process() in a loop if the thread is running.
|
||||
void threadLoop();
|
||||
|
||||
/**
|
||||
* process() call effectProcessImpl() for effect data processing, it is necessary for the
|
||||
* processing to be called under Effect thread mutex mThreadMutex, to avoid the effect state
|
||||
* change before/during data processing, and keep the thread and effect state consistent.
|
||||
*/
|
||||
virtual void process() = 0;
|
||||
|
||||
protected:
|
||||
bool mDraining GUARDED_BY(mThreadMutex) = false;
|
||||
|
||||
private:
|
||||
static constexpr int kMaxTaskNameLen = 15;
|
||||
|
||||
std::mutex mThreadMutex;
|
||||
std::condition_variable mCv;
|
||||
bool mStop GUARDED_BY(mThreadMutex) = true;
|
||||
bool mExit GUARDED_BY(mThreadMutex) = false;
|
||||
|
||||
std::thread mThread;
|
||||
int mPriority;
|
||||
std::string mName;
|
||||
};
|
||||
} // namespace aidl::android::hardware::audio::effect
|
||||
133
audio/include/effect-impl/EffectTypes.h
Normal file
133
audio/include/effect-impl/EffectTypes.h
Normal file
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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 <string>
|
||||
|
||||
#include <aidl/android/hardware/audio/effect/BnEffect.h>
|
||||
#include <aidl/android/hardware/audio/effect/Range.h>
|
||||
#include <android-base/logging.h>
|
||||
#include <system/audio_effects/aidl_effects_utils.h>
|
||||
|
||||
typedef binder_exception_t (*EffectCreateFunctor)(
|
||||
const ::aidl::android::media::audio::common::AudioUuid*,
|
||||
std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>*);
|
||||
typedef binder_exception_t (*EffectDestroyFunctor)(
|
||||
const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>&);
|
||||
typedef binder_exception_t (*EffectQueryFunctor)(
|
||||
const ::aidl::android::media::audio::common::AudioUuid*,
|
||||
::aidl::android::hardware::audio::effect::Descriptor*);
|
||||
|
||||
struct effect_dl_interface_s {
|
||||
EffectCreateFunctor createEffectFunc;
|
||||
EffectDestroyFunctor destroyEffectFunc;
|
||||
EffectQueryFunctor queryEffectFunc;
|
||||
};
|
||||
|
||||
namespace aidl::android::hardware::audio::effect {
|
||||
|
||||
enum class RetCode {
|
||||
SUCCESS,
|
||||
ERROR_ILLEGAL_PARAMETER, /* Illegal parameter */
|
||||
ERROR_THREAD, /* Effect thread error */
|
||||
ERROR_NULL_POINTER, /* NULL pointer */
|
||||
ERROR_ALIGNMENT_ERROR, /* Memory alignment error */
|
||||
ERROR_BLOCK_SIZE_EXCEED, /* Maximum block size exceeded */
|
||||
ERROR_EFFECT_LIB_ERROR, /* Effect implementation library error */
|
||||
ERROR_EVENT_FLAG_ERROR /* Error with effect event flags */
|
||||
};
|
||||
|
||||
static const int INVALID_AUDIO_SESSION_ID = -1;
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& out, const RetCode& code) {
|
||||
switch (code) {
|
||||
case RetCode::SUCCESS:
|
||||
return out << "SUCCESS";
|
||||
case RetCode::ERROR_ILLEGAL_PARAMETER:
|
||||
return out << "ERROR_ILLEGAL_PARAMETER";
|
||||
case RetCode::ERROR_THREAD:
|
||||
return out << "ERROR_THREAD";
|
||||
case RetCode::ERROR_NULL_POINTER:
|
||||
return out << "ERROR_NULL_POINTER";
|
||||
case RetCode::ERROR_ALIGNMENT_ERROR:
|
||||
return out << "ERROR_ALIGNMENT_ERROR";
|
||||
case RetCode::ERROR_BLOCK_SIZE_EXCEED:
|
||||
return out << "ERROR_BLOCK_SIZE_EXCEED";
|
||||
case RetCode::ERROR_EFFECT_LIB_ERROR:
|
||||
return out << "ERROR_EFFECT_LIB_ERROR";
|
||||
case RetCode::ERROR_EVENT_FLAG_ERROR:
|
||||
return out << "ERROR_EVENT_FLAG_ERROR";
|
||||
}
|
||||
|
||||
return out << "EnumError: " << code;
|
||||
}
|
||||
|
||||
#define RETURN_IF_ASTATUS_NOT_OK(status, message) \
|
||||
do { \
|
||||
const ::ndk::ScopedAStatus curr_status = (status); \
|
||||
if (!curr_status.isOk()) { \
|
||||
LOG(ERROR) << __func__ << ": line" << __LINE__ \
|
||||
<< " return with status: " << curr_status.getDescription() << (message); \
|
||||
return ndk::ScopedAStatus::fromExceptionCodeWithMessage( \
|
||||
curr_status.getExceptionCode(), (message)); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define RETURN_IF(expr, exception, message) \
|
||||
do { \
|
||||
if (expr) { \
|
||||
LOG(ERROR) << __func__ << ": line" << __LINE__ << " return with expr " << #expr; \
|
||||
return ndk::ScopedAStatus::fromExceptionCodeWithMessage((exception), (message)); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define RETURN_OK_IF(expr) \
|
||||
do { \
|
||||
if (expr) { \
|
||||
LOG(INFO) << __func__ << ": line" << __LINE__ << " return with expr " << #expr; \
|
||||
return ndk::ScopedAStatus::ok(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define RETURN_VALUE_IF(expr, ret, log) \
|
||||
do { \
|
||||
if (expr) { \
|
||||
LOG(ERROR) << __func__ << ": line" << __LINE__ << " return with expr \"" << #expr \
|
||||
<< "\":" << (log); \
|
||||
return ret; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define RETURN_IF_BINDER_EXCEPTION(functor) \
|
||||
{ \
|
||||
binder_exception_t exception = functor; \
|
||||
if (EX_NONE != exception) { \
|
||||
LOG(ERROR) << #functor << ": failed with error " << exception; \
|
||||
return ndk::ScopedAStatus::fromExceptionCode(exception); \
|
||||
} \
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a Range::$EffectType$Range.
|
||||
* T: The $EffectType$, Visualizer for example.
|
||||
* Tag: The union tag name in $EffectType$ definition, latencyMs for example.
|
||||
* l: The value of Range::$EffectType$Range.min.
|
||||
* r: The value of Range::$EffectType$Range.max.
|
||||
*/
|
||||
#define MAKE_RANGE(T, Tag, l, r) \
|
||||
{ .min = T::make<T::Tag>(l), .max = T::make<T::Tag>(r) }
|
||||
|
||||
} // namespace aidl::android::hardware::audio::effect
|
||||
117
audio/include/effectFactory-impl/EffectConfig.h
Normal file
117
audio/include/effectFactory-impl/EffectConfig.h
Normal file
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright (C) 2017 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 <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include <cutils/properties.h>
|
||||
#include <tinyxml2.h>
|
||||
|
||||
#include <aidl/android/hardware/audio/effect/Processing.h>
|
||||
#include "effect-impl/EffectTypes.h"
|
||||
|
||||
namespace aidl::android::hardware::audio::effect {
|
||||
|
||||
/**
|
||||
* Library contains a mapping from library name to path.
|
||||
* Effect contains a mapping from effect name to Libraries and implementation UUID.
|
||||
* Pre/post processor contains a mapping from processing name to effect names.
|
||||
*/
|
||||
class EffectConfig {
|
||||
public:
|
||||
explicit EffectConfig(const std::string& file);
|
||||
|
||||
struct Library {
|
||||
std::string name; // library name
|
||||
::aidl::android::media::audio::common::AudioUuid uuid; // implementation UUID
|
||||
std::optional<::aidl::android::media::audio::common::AudioUuid> type; // optional type UUID
|
||||
};
|
||||
// <effects>
|
||||
struct EffectLibraries {
|
||||
std::optional<struct Library> proxyLibrary;
|
||||
std::vector<struct Library> libraries;
|
||||
};
|
||||
|
||||
int getSkippedElements() const { return mSkippedElements; }
|
||||
const std::unordered_map<std::string, std::string> getLibraryMap() const { return mLibraryMap; }
|
||||
const std::unordered_map<std::string, struct EffectLibraries> getEffectsMap() const {
|
||||
return mEffectsMap;
|
||||
}
|
||||
|
||||
static bool findUuid(const std::pair<std::string, struct EffectLibraries>& effectElem,
|
||||
::aidl::android::media::audio::common::AudioUuid* uuid);
|
||||
|
||||
using ProcessingLibrariesMap = std::map<Processing::Type, std::vector<struct EffectLibraries>>;
|
||||
const ProcessingLibrariesMap& getProcessingMap() const;
|
||||
|
||||
private:
|
||||
#ifdef __LP64__
|
||||
#define SOUND_FX_PATH "/lib64/soundfx/"
|
||||
#else
|
||||
#define SOUND_FX_PATH "/lib/soundfx/"
|
||||
#endif
|
||||
static constexpr const char* kEffectLibPath[] =
|
||||
{ "/odm" SOUND_FX_PATH, "/vendor" SOUND_FX_PATH, "/system" SOUND_FX_PATH };
|
||||
|
||||
static constexpr const char* kEffectLibApexPath = SOUND_FX_PATH;
|
||||
#undef SOUND_FX_PATH
|
||||
|
||||
int mSkippedElements;
|
||||
/* Parsed Libraries result */
|
||||
std::unordered_map<std::string, std::string> mLibraryMap;
|
||||
/* Parsed Effects result */
|
||||
std::unordered_map<std::string, struct EffectLibraries> mEffectsMap;
|
||||
/**
|
||||
* For parsed pre/post processing result: {key: AudioStreamType/AudioSource/AudioDevice, value:
|
||||
* EffectLibraries}
|
||||
*/
|
||||
ProcessingLibrariesMap mProcessingMap;
|
||||
|
||||
/** @return all `node`s children that are elements and match the tag if provided. */
|
||||
std::vector<std::reference_wrapper<const tinyxml2::XMLElement>> getChildren(
|
||||
const tinyxml2::XMLNode& node, const char* childTag = nullptr);
|
||||
|
||||
/** Parse a library xml note and push the result in mLibraryMap or return false on failure. */
|
||||
bool parseLibrary(const tinyxml2::XMLElement& xml);
|
||||
|
||||
/** Parse an effect from an xml element describing it.
|
||||
* @return true and pushes the effect in mEffectsMap on success, false on failure.
|
||||
*/
|
||||
bool parseEffect(const tinyxml2::XMLElement& xml);
|
||||
|
||||
bool parseProcessing(Processing::Type::Tag typeTag, const tinyxml2::XMLElement& xml);
|
||||
|
||||
// Function to parse effect.library name and effect.uuid from xml
|
||||
bool parseLibrary(const tinyxml2::XMLElement& xml, struct Library& library,
|
||||
bool isProxy = false);
|
||||
|
||||
const char* dump(const tinyxml2::XMLElement& element,
|
||||
tinyxml2::XMLPrinter&& printer = {}) const;
|
||||
|
||||
bool resolveLibrary(const std::string& path, std::string* resolvedPath);
|
||||
|
||||
std::optional<Processing::Type> stringToProcessingType(Processing::Type::Tag typeTag,
|
||||
const std::string& type,
|
||||
const std::string& address);
|
||||
};
|
||||
|
||||
} // namespace aidl::android::hardware::audio::effect
|
||||
125
audio/include/effectFactory-impl/EffectFactory.h
Normal file
125
audio/include/effectFactory-impl/EffectFactory.h
Normal file
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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 <any>
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
#include <aidl/android/hardware/audio/effect/BnFactory.h>
|
||||
#include <android-base/thread_annotations.h>
|
||||
#include "EffectConfig.h"
|
||||
|
||||
namespace aidl::android::hardware::audio::effect {
|
||||
|
||||
class Factory : public BnFactory {
|
||||
public:
|
||||
explicit Factory(const std::string& file);
|
||||
/**
|
||||
* @brief Get identity of all effects supported by the device, with the optional filter by type
|
||||
* and/or by instance UUID.
|
||||
*
|
||||
* @param in_type Type UUID.
|
||||
* @param in_instance Instance UUID.
|
||||
* @param in_proxy Proxy UUID.
|
||||
* @param out_descriptor List of Descriptors.
|
||||
* @return ndk::ScopedAStatus
|
||||
*/
|
||||
ndk::ScopedAStatus queryEffects(
|
||||
const std::optional<::aidl::android::media::audio::common::AudioUuid>& in_type,
|
||||
const std::optional<::aidl::android::media::audio::common::AudioUuid>& in_instance,
|
||||
const std::optional<::aidl::android::media::audio::common::AudioUuid>& in_proxy,
|
||||
std::vector<Descriptor>* out_descriptor) override;
|
||||
|
||||
/**
|
||||
* @brief Query list of defined processing, with the optional filter by AudioStreamType
|
||||
*
|
||||
* @param in_type Type of processing, could be AudioStreamType or AudioSource. Optional.
|
||||
* @param _aidl_return List of processing filtered by in_type.
|
||||
* @return ndk::ScopedAStatus
|
||||
*/
|
||||
ndk::ScopedAStatus queryProcessing(const std::optional<Processing::Type>& in_type,
|
||||
std::vector<Processing>* _aidl_return) override;
|
||||
|
||||
/**
|
||||
* @brief Create an effect instance for a certain implementation (identified by UUID).
|
||||
*
|
||||
* @param in_impl_uuid Effect implementation UUID.
|
||||
* @param _aidl_return A pointer to created effect instance.
|
||||
* @return ndk::ScopedAStatus
|
||||
*/
|
||||
ndk::ScopedAStatus createEffect(
|
||||
const ::aidl::android::media::audio::common::AudioUuid& in_impl_uuid,
|
||||
std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>* _aidl_return)
|
||||
override;
|
||||
|
||||
/**
|
||||
* @brief Destroy an effect instance.
|
||||
*
|
||||
* @param in_handle Effect instance handle.
|
||||
* @return ndk::ScopedAStatus
|
||||
*/
|
||||
ndk::ScopedAStatus destroyEffect(
|
||||
const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_handle)
|
||||
override;
|
||||
|
||||
private:
|
||||
const EffectConfig mConfig;
|
||||
~Factory();
|
||||
|
||||
std::mutex mMutex;
|
||||
// Set of effect descriptors supported by the devices.
|
||||
std::set<Descriptor> mDescSet GUARDED_BY(mMutex);
|
||||
std::set<Descriptor::Identity> mIdentitySet GUARDED_BY(mMutex);
|
||||
|
||||
static constexpr int kMapEntryHandleIndex = 0;
|
||||
static constexpr int kMapEntryInterfaceIndex = 1;
|
||||
static constexpr int kMapEntryLibNameIndex = 2;
|
||||
typedef std::tuple<std::unique_ptr<void, std::function<void(void*)>> /* dlHandle */,
|
||||
std::unique_ptr<struct effect_dl_interface_s> /* interfaces */,
|
||||
std::string /* library name */>
|
||||
DlEntry;
|
||||
|
||||
std::map<aidl::android::media::audio::common::AudioUuid /* implUUID */, DlEntry> mEffectLibMap
|
||||
GUARDED_BY(mMutex);
|
||||
|
||||
typedef std::pair<aidl::android::media::audio::common::AudioUuid, ndk::SpAIBinder> EffectEntry;
|
||||
std::map<std::weak_ptr<IEffect>, EffectEntry, std::owner_less<>> mEffectMap GUARDED_BY(mMutex);
|
||||
|
||||
ndk::ScopedAStatus destroyEffectImpl_l(const std::shared_ptr<IEffect>& in_handle)
|
||||
REQUIRES(mMutex);
|
||||
void cleanupEffectMap_l() REQUIRES(mMutex);
|
||||
bool openEffectLibrary(const ::aidl::android::media::audio::common::AudioUuid& impl,
|
||||
const std::string& path);
|
||||
void createIdentityWithConfig(
|
||||
const EffectConfig::Library& configLib,
|
||||
const ::aidl::android::media::audio::common::AudioUuid& typeUuidStr,
|
||||
const std::optional<::aidl::android::media::audio::common::AudioUuid> proxyUuid);
|
||||
|
||||
ndk::ScopedAStatus getDescriptorWithUuid_l(
|
||||
const aidl::android::media::audio::common::AudioUuid& uuid, Descriptor* desc)
|
||||
REQUIRES(mMutex);
|
||||
|
||||
void loadEffectLibs();
|
||||
/* Get effect_dl_interface_s from library handle */
|
||||
void getDlSyms_l(DlEntry& entry) REQUIRES(mMutex);
|
||||
};
|
||||
|
||||
} // namespace aidl::android::hardware::audio::effect
|
||||
Reference in New Issue
Block a user