From a7f4e0535761ce918693f02812b3aa021d3a7116 Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Tue, 27 Dec 2022 20:28:17 +0000 Subject: [PATCH] audio: Implement ITelephony core interface for telecom Implement telecom functions in ITelephony corresponding to the IPrimaryDevice in the HIDL HAL. Bug: 205884982 Test: atest VtsHalAudioCoreTargetTest Change-Id: Ia83fa4341dd50919d885ac1e10fb31c9a30c5a86 --- .../hardware/audio/core/IStreamIn.aidl | 2 +- .../hardware/audio/core/ITelephony.aidl | 17 +++++ .../hardware/audio/core/MicrophoneInfo.aidl | 8 +- .../hardware/audio/core/StreamDescriptor.aidl | 8 +- .../hardware/audio/core/ITelephony.aidl | 73 +++++++++++++++++++ audio/aidl/default/Telephony.cpp | 33 +++++++++ .../default/include/core-impl/Telephony.h | 6 ++ .../vts/VtsHalAudioCoreModuleTargetTest.cpp | 41 +++++++++++ 8 files changed, 179 insertions(+), 9 deletions(-) diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamIn.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamIn.aidl index 68f1ff34fe..1041943446 100644 --- a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamIn.aidl +++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamIn.aidl @@ -43,7 +43,7 @@ interface IStreamIn { void updateMetadata(in android.hardware.audio.common.SinkMetadata sinkMetadata); float[] getHwGain(); void setHwGain(in float[] channelGains); - const int MIC_FIELD_DIMENSION_WIDE_ANGLE = -1; + const int MIC_FIELD_DIMENSION_WIDE_ANGLE = (-1); const int MIC_FIELD_DIMENSION_NO_ZOOM = 0; const int MIC_FIELD_DIMENSION_MAX_ZOOM = 1; const int HW_GAIN_MIN = 0; diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/ITelephony.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/ITelephony.aidl index a8c58c1cc7..77063df19b 100644 --- a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/ITelephony.aidl +++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/ITelephony.aidl @@ -36,4 +36,21 @@ package android.hardware.audio.core; interface ITelephony { android.hardware.audio.core.AudioMode[] getSupportedAudioModes(); void switchAudioMode(android.hardware.audio.core.AudioMode mode); + android.hardware.audio.core.ITelephony.TelecomConfig setTelecomConfig(in android.hardware.audio.core.ITelephony.TelecomConfig config); + @JavaDerive(equals=true, toString=true) @VintfStability + parcelable TelecomConfig { + @nullable android.media.audio.common.Float voiceVolume; + android.hardware.audio.core.ITelephony.TelecomConfig.TtyMode ttyMode = android.hardware.audio.core.ITelephony.TelecomConfig.TtyMode.UNSPECIFIED; + @nullable android.media.audio.common.Boolean isHacEnabled; + const int VOICE_VOLUME_MIN = 0; + const int VOICE_VOLUME_MAX = 1; + @Backing(type="int") @VintfStability + enum TtyMode { + UNSPECIFIED = (-1), + OFF = 0, + FULL = 1, + HCO = 2, + VCO = 3, + } + } } diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/MicrophoneInfo.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/MicrophoneInfo.aidl index 68c7f880f8..b77afe32cb 100644 --- a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/MicrophoneInfo.aidl +++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/MicrophoneInfo.aidl @@ -37,15 +37,15 @@ parcelable MicrophoneInfo { @utf8InCpp String id; android.media.audio.common.AudioDevice device; android.hardware.audio.core.MicrophoneInfo.Location location = android.hardware.audio.core.MicrophoneInfo.Location.UNKNOWN; - int group = -1; - int indexInTheGroup = -1; + int group = GROUP_UNKNOWN; + int indexInTheGroup = INDEX_IN_THE_GROUP_UNKNOWN; @nullable android.hardware.audio.core.MicrophoneInfo.Sensitivity sensitivity; android.hardware.audio.core.MicrophoneInfo.Directionality directionality = android.hardware.audio.core.MicrophoneInfo.Directionality.UNKNOWN; android.hardware.audio.core.MicrophoneInfo.FrequencyResponsePoint[] frequencyResponse; @nullable android.hardware.audio.core.MicrophoneInfo.Coordinate position; @nullable android.hardware.audio.core.MicrophoneInfo.Coordinate orientation; - const int GROUP_UNKNOWN = -1; - const int INDEX_IN_THE_GROUP_UNKNOWN = -1; + const int GROUP_UNKNOWN = (-1); + const int INDEX_IN_THE_GROUP_UNKNOWN = (-1); @Backing(type="int") @VintfStability enum Location { UNKNOWN = 0, diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/StreamDescriptor.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/StreamDescriptor.aidl index 3a4271b89a..a65d7b7cea 100644 --- a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/StreamDescriptor.aidl +++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/StreamDescriptor.aidl @@ -39,12 +39,12 @@ parcelable StreamDescriptor { int frameSizeBytes; long bufferSizeFrames; android.hardware.audio.core.StreamDescriptor.AudioBuffer audio; - const int LATENCY_UNKNOWN = -1; + const int LATENCY_UNKNOWN = (-1); @FixedSize @VintfStability parcelable Position { - long frames = -1; - long timeNs = -1; - const long UNKNOWN = -1; + long frames = UNKNOWN; + long timeNs = UNKNOWN; + const long UNKNOWN = (-1); } @Backing(type="int") @VintfStability enum State { diff --git a/audio/aidl/android/hardware/audio/core/ITelephony.aidl b/audio/aidl/android/hardware/audio/core/ITelephony.aidl index a872c7c6d3..a817032ed1 100644 --- a/audio/aidl/android/hardware/audio/core/ITelephony.aidl +++ b/audio/aidl/android/hardware/audio/core/ITelephony.aidl @@ -17,6 +17,8 @@ package android.hardware.audio.core; import android.hardware.audio.core.AudioMode; +import android.media.audio.common.Boolean; +import android.media.audio.common.Float; /** * An instance of ITelephony manages settings which are specific to voice calls @@ -53,4 +55,75 @@ interface ITelephony { * @throws EX_ILLEGAL_STATE If there was an error during switching. */ void switchAudioMode(AudioMode mode); + + @JavaDerive(equals=true, toString=true) + @VintfStability + parcelable TelecomConfig { + const int VOICE_VOLUME_MIN = 0; + const int VOICE_VOLUME_MAX = 1; + /** + * Volume of a voice call. 1.0f means unity gain, 0.0f is muted, + * see VOLUME_* constants. + */ + @nullable Float voiceVolume; + /** + * The current mode of teletypewritter (TTY). + */ + @VintfStability + @Backing(type="int") + enum TtyMode { + /** + * The default uninitialized value. + */ + UNSPECIFIED = -1, + /** + * TTY mode is off. + */ + OFF = 0, + /** + * TTY mode is on. The speaker is off and the microphone is muted. The + * user will communicate with the remote party by sending and receiving + * text messages. + */ + FULL = 1, + /** + * TTY mode is in hearing carryover mode (HCO). The microphone is muted + * but the speaker is on. The user will communicate with the remote + * party by sending text messages and hearing an audible reply. + */ + HCO = 2, + /** + * TTY mode is in voice carryover mode (VCO). The speaker is off but the + * microphone is still on. User will communicate with the remote party + * by speaking and receiving text message replies. + */ + VCO = 3, + } + TtyMode ttyMode = TtyMode.UNSPECIFIED; + /** + * Whether Hearing Aid Compatibility - Telecoil (HAC-T) mode is enabled. + */ + @nullable Boolean isHacEnabled; + } + + /** + * Set the configuration of the telephony audio. + * + * In the provided parcelable, the client sets zero, one or more parameters + * which have to be updated on the HAL side. The parameters that are left + * unset must retain their current values. + * + * In the returned parcelable, all parameter fields known to the HAL module + * must be populated to their current values.The client can pass an + * uninitialized parcelable in order to retrieve the current configuration. + * + * @return The current configuration (after update). All fields known to + * the HAL must be populated. + * @param config The configuration to set. Any number of fields may be left + * uninitialized. + * @throws EX_UNSUPPORTED_OPERATION If telephony is not supported. + * @throws EX_ILLEGAL_ARGUMENT If the requested combination of parameter + * values is invalid. + */ + TelecomConfig setTelecomConfig(in TelecomConfig config); } diff --git a/audio/aidl/default/Telephony.cpp b/audio/aidl/default/Telephony.cpp index 1854b357ab..d873178a00 100644 --- a/audio/aidl/default/Telephony.cpp +++ b/audio/aidl/default/Telephony.cpp @@ -20,8 +20,17 @@ #include "core-impl/Telephony.h" +using aidl::android::media::audio::common::Boolean; +using aidl::android::media::audio::common::Float; + namespace aidl::android::hardware::audio::core { +Telephony::Telephony() { + mTelecomConfig.voiceVolume = Float{TelecomConfig::VOICE_VOLUME_MAX}; + mTelecomConfig.ttyMode = TelecomConfig::TtyMode::OFF; + mTelecomConfig.isHacEnabled = Boolean{false}; +} + ndk::ScopedAStatus Telephony::getSupportedAudioModes(std::vector* _aidl_return) { *_aidl_return = mSupportedAudioModes; LOG(DEBUG) << __func__ << ": returning " << ::android::internal::ToString(*_aidl_return); @@ -38,4 +47,28 @@ ndk::ScopedAStatus Telephony::switchAudioMode(AudioMode in_mode) { return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); } +ndk::ScopedAStatus Telephony::setTelecomConfig(const TelecomConfig& in_config, + TelecomConfig* _aidl_return) { + if (in_config.voiceVolume.has_value() && + (in_config.voiceVolume.value().value < TelecomConfig::VOICE_VOLUME_MIN || + in_config.voiceVolume.value().value > TelecomConfig::VOICE_VOLUME_MAX)) { + LOG(ERROR) << __func__ + << ": voice volume value is invalid: " << in_config.voiceVolume.value().value; + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } + if (in_config.voiceVolume.has_value()) { + mTelecomConfig.voiceVolume = in_config.voiceVolume; + } + if (in_config.ttyMode != TelecomConfig::TtyMode::UNSPECIFIED) { + mTelecomConfig.ttyMode = in_config.ttyMode; + } + if (in_config.isHacEnabled.has_value()) { + mTelecomConfig.isHacEnabled = in_config.isHacEnabled; + } + *_aidl_return = mTelecomConfig; + LOG(DEBUG) << __func__ << ": received " << in_config.toString() << ", returning " + << _aidl_return->toString(); + return ndk::ScopedAStatus::ok(); +} + } // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/include/core-impl/Telephony.h b/audio/aidl/default/include/core-impl/Telephony.h index 597f3d60ca..09361722ff 100644 --- a/audio/aidl/default/include/core-impl/Telephony.h +++ b/audio/aidl/default/include/core-impl/Telephony.h @@ -23,12 +23,18 @@ namespace aidl::android::hardware::audio::core { class Telephony : public BnTelephony { + public: + Telephony(); + private: ndk::ScopedAStatus getSupportedAudioModes(std::vector* _aidl_return) override; ndk::ScopedAStatus switchAudioMode(AudioMode in_mode) override; + ndk::ScopedAStatus setTelecomConfig(const TelecomConfig& in_config, + TelecomConfig* _aidl_return) override; const std::vector mSupportedAudioModes = {::ndk::enum_range().begin(), ::ndk::enum_range().end()}; + TelecomConfig mTelecomConfig; }; } // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp index 2508afd778..7e1e2b5f47 100644 --- a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp +++ b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp @@ -81,6 +81,7 @@ using aidl::android::media::audio::common::AudioPortDeviceExt; using aidl::android::media::audio::common::AudioPortExt; using aidl::android::media::audio::common::AudioSource; using aidl::android::media::audio::common::AudioUsage; +using aidl::android::media::audio::common::Float; using aidl::android::media::audio::common::Void; using android::hardware::audio::common::getChannelCount; using android::hardware::audio::common::isBitPositionFlagSet; @@ -1826,6 +1827,46 @@ TEST_P(AudioCoreTelephony, SwitchAudioMode) { } } +TEST_P(AudioCoreTelephony, TelecomConfig) { + static const auto kStatuses = {EX_NONE, EX_UNSUPPORTED_OPERATION}; + if (telephony == nullptr) { + GTEST_SKIP() << "Telephony is not supported"; + } + ndk::ScopedAStatus status; + ITelephony::TelecomConfig telecomConfig; + ASSERT_STATUS(kStatuses, status = telephony->setTelecomConfig({}, &telecomConfig)); + if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) { + GTEST_SKIP() << "Telecom is not supported"; + } + EXPECT_TRUE(telecomConfig.voiceVolume.has_value()); + EXPECT_NE(ITelephony::TelecomConfig::TtyMode::UNSPECIFIED, telecomConfig.ttyMode); + EXPECT_TRUE(telecomConfig.isHacEnabled.has_value()); + ITelephony::TelecomConfig telecomConfig2; + ASSERT_IS_OK(telephony->setTelecomConfig(telecomConfig, &telecomConfig2)); + EXPECT_EQ(telecomConfig, telecomConfig2); +} + +TEST_P(AudioCoreTelephony, TelecomConfigInvalid) { + static const auto kStatuses = {EX_NONE, EX_UNSUPPORTED_OPERATION}; + if (telephony == nullptr) { + GTEST_SKIP() << "Telephony is not supported"; + } + ndk::ScopedAStatus status; + ITelephony::TelecomConfig telecomConfig; + ASSERT_STATUS(kStatuses, status = telephony->setTelecomConfig({}, &telecomConfig)); + if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) { + GTEST_SKIP() << "Telecom is not supported"; + } + EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, + telephony->setTelecomConfig( + {.voiceVolume = Float{ITelephony::TelecomConfig::VOICE_VOLUME_MIN - 1}}, + &telecomConfig)); + EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, + telephony->setTelecomConfig( + {.voiceVolume = Float{ITelephony::TelecomConfig::VOICE_VOLUME_MAX + 1}}, + &telecomConfig)); +} + using CommandSequence = std::vector; class StreamLogicDriverInvalidCommand : public StreamLogicDriver { public: