Merge "audio: Add volume/mute, audio mode, and screen state to IModule"

This commit is contained in:
Treehugger Robot
2022-11-10 22:12:41 +00:00
committed by Gerrit Code Review
14 changed files with 643 additions and 2 deletions

View File

@@ -91,12 +91,14 @@ aidl_interface {
name: "android.hardware.audio.core",
vendor_available: true,
srcs: [
"android/hardware/audio/core/AudioMode.aidl",
"android/hardware/audio/core/AudioPatch.aidl",
"android/hardware/audio/core/AudioRoute.aidl",
"android/hardware/audio/core/IConfig.aidl",
"android/hardware/audio/core/IModule.aidl",
"android/hardware/audio/core/IStreamIn.aidl",
"android/hardware/audio/core/IStreamOut.aidl",
"android/hardware/audio/core/ITelephony.aidl",
"android/hardware/audio/core/MmapBufferDescriptor.aidl",
"android/hardware/audio/core/ModuleDebug.aidl",
"android/hardware/audio/core/StreamDescriptor.aidl",

View File

@@ -0,0 +1,42 @@
/*
* 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.
*/
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL file. Do not edit it manually. There are
// two cases:
// 1). this is a frozen version file - do not edit this in any case.
// 2). this is a 'current' file. If you make a backwards compatible change to
// the interface (from the latest frozen version), the build system will
// prompt you to update this file with `m <name>-update-api`.
//
// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.audio.core;
@Backing(type="int") @VintfStability
enum AudioMode {
NORMAL = 0,
RINGTONE = 1,
IN_CALL = 2,
IN_COMMUNICATION = 3,
CALL_SCREEN = 4,
}

View File

@@ -35,6 +35,7 @@ package android.hardware.audio.core;
@VintfStability
interface IModule {
void setModuleDebug(in android.hardware.audio.core.ModuleDebug debug);
@nullable android.hardware.audio.core.ITelephony getTelephony();
android.media.audio.common.AudioPort connectExternalDevice(in android.media.audio.common.AudioPort templateIdAndAdditionalData);
void disconnectExternalDevice(int portId);
android.hardware.audio.core.AudioPatch[] getAudioPatches();
@@ -49,6 +50,15 @@ interface IModule {
boolean setAudioPortConfig(in android.media.audio.common.AudioPortConfig requested, out android.media.audio.common.AudioPortConfig suggested);
void resetAudioPatch(int patchId);
void resetAudioPortConfig(int portConfigId);
boolean getMasterMute();
void setMasterMute(boolean mute);
float getMasterVolume();
void setMasterVolume(float volume);
boolean getMicMute();
void setMicMute(boolean mute);
void updateAudioMode(android.hardware.audio.core.AudioMode mode);
void updateScreenRotation(android.hardware.audio.core.IModule.ScreenRotation rotation);
void updateScreenState(boolean isTurnedOn);
@VintfStability
parcelable OpenInputStreamArguments {
int portConfigId;
@@ -72,4 +82,11 @@ interface IModule {
android.hardware.audio.core.IStreamOut stream;
android.hardware.audio.core.StreamDescriptor desc;
}
@Backing(type="int") @VintfStability
enum ScreenRotation {
DEG_0 = 0,
DEG_90 = 1,
DEG_180 = 2,
DEG_270 = 3,
}
}

View File

@@ -0,0 +1,39 @@
/*
* 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.
*/
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL file. Do not edit it manually. There are
// two cases:
// 1). this is a frozen version file - do not edit this in any case.
// 2). this is a 'current' file. If you make a backwards compatible change to
// the interface (from the latest frozen version), the build system will
// prompt you to update this file with `m <name>-update-api`.
//
// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.audio.core;
@VintfStability
interface ITelephony {
android.hardware.audio.core.AudioMode[] getSupportedAudioModes();
void switchAudioMode(android.hardware.audio.core.AudioMode mode);
}

View File

@@ -0,0 +1,38 @@
/*
* 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.
*/
package android.hardware.audio.core;
/**
* The audio mode describes states of the audio system of the device that
* can significantly affect the rules of audio routing, volume control, etc.
* The audio mode is controlled by the framework, however the HAL has some
* flexibility in the choice of modes to support, see 'IModule.updateAudioMode'.
*/
@VintfStability
@Backing(type="int")
enum AudioMode {
/** No active calls. */
NORMAL = 0,
/** The device is playing the ringtone. */
RINGTONE = 1,
/** The call is handled by the telephony stack ("voice call"). */
IN_CALL = 2,
/** The call is handled by an application ("VoIP call"). */
IN_COMMUNICATION = 3,
/** Call screening is in progress. */
CALL_SCREEN = 4,
}

View File

@@ -18,10 +18,12 @@ package android.hardware.audio.core;
import android.hardware.audio.common.SinkMetadata;
import android.hardware.audio.common.SourceMetadata;
import android.hardware.audio.core.AudioMode;
import android.hardware.audio.core.AudioPatch;
import android.hardware.audio.core.AudioRoute;
import android.hardware.audio.core.IStreamIn;
import android.hardware.audio.core.IStreamOut;
import android.hardware.audio.core.ITelephony;
import android.hardware.audio.core.ModuleDebug;
import android.hardware.audio.core.StreamDescriptor;
import android.media.audio.common.AudioOffloadInfo;
@@ -59,6 +61,19 @@ interface IModule {
*/
void setModuleDebug(in ModuleDebug debug);
/**
* Retrieve the interface to control telephony audio.
*
* If the HAL module supports telephony functions, it must return an
* instance of the ITelephony interface. The same instance must be returned
* during the lifetime of the HAL module. If the HAL module does not support
* telephony, a null must be returned, without throwing any errors.
*
* @return An instance of the ITelephony interface implementation.
* @throws EX_ILLEGAL_STATE If there was an error creating an instance.
*/
@nullable ITelephony getTelephony();
/**
* Set a device port of an external device into connected state.
*
@@ -487,4 +502,140 @@ interface IModule {
* - If the port config is used by a patch.
*/
void resetAudioPortConfig(int portConfigId);
/**
* Get the current state of audio output muting.
*
* If the HAL module supports muting its combined output completely,
* this method returns whether muting is currently enabled.
*
* Note that muting operates independently from the master volume.
*
* @return Whether the output from the module is muted.
* @throws EX_UNSUPPORTED_OPERATION If muting of combined output
* is not supported by the module.
*/
boolean getMasterMute();
/**
* Set the current value of the audio output muting.
*
* If the HAL module supports muting its combined output completely, this
* method controls the mute. Note that for modules supporting telephony,
* muting does not affect the voice call.
*
* For HAL modules not supporting this operation, it's functionality is
* typically emulated by the client, in the digital domain.
*
* @param mute Whether the output from the module is muted.
* @throws EX_UNSUPPORTED_OPERATION If muting of combined output
* is not supported by the module.
*/
void setMasterMute(boolean mute);
/**
* Get the current value of the audio output attenuation.
*
* If the HAL module supports attenuating the level its combined output,
* this method returns the current attenuation value.
*
* @return Volume 1.0f means no attenuation (unity), 0.0f is mute.
* @throws EX_UNSUPPORTED_OPERATION If attenuation of combined output
* is not supported by the module.
*/
float getMasterVolume();
/**
* Set the current value of the audio output attenuation.
*
* If the HAL module supports attenuating the level its combined output,
* this method sets the attenuation value. Note that for modules supporting
* telephony, the attenuation of the voice call volume is set separately
* via ITelephony interface.
*
* For HAL modules not supporting this operation, it's functionality is
* typically emulated by the client, in the digital domain.
*
* @param volume The new value, 1.0f means no attenuation (unity), 0.0f is mute.
* @throws EX_ILLEGAL_ARGUMENT If the value of the volume is outside of
* accepted range.
* @throws EX_UNSUPPORTED_OPERATION If attenuation of combined output
* is not supported by the module.
*/
void setMasterVolume(float volume);
/**
* Get the current state of audio input muting.
*
* If the HAL module supports muting its external input, this method returns
* whether muting is currently enabled.
*
* @return Whether the input is muted.
* @throws EX_UNSUPPORTED_OPERATION If muting of input is not supported by
* the module.
*/
boolean getMicMute();
/**
* Set the current value of the audio input muting.
*
* If the HAL module supports muting its external input, this method
* controls the mute.
*
* For HAL modules not supporting this operation, it's functionality is
* emulated by the client.
*
* @param mute Whether input is muted.
* @throws EX_UNSUPPORTED_OPERATION If muting of input is not supported by
* the module.
*/
void setMicMute(boolean mute);
/**
* Notify the HAL module on the change of the current audio mode.
*
* The current audio mode is always controlled by the client. This is an
* informative notification sent to all modules, no reply is needed. The HAL
* module should silently ignore this notification if it does not need to
* be aware of the current audio mode.
*
* The client sends this notification to all HAL modules after successfully
* switching the telephony module by calling the 'ITelephony.switchAudioMode'
* method.
*
* @param mode The current mode.
*/
void updateAudioMode(AudioMode mode);
@VintfStability
@Backing(type="int")
enum ScreenRotation {
/** Natural orientation. */
DEG_0 = 0,
DEG_90 = 1,
/** Upside down. */
DEG_180 = 2,
DEG_270 = 3,
}
/**
* Notify the HAL module on the change of the screen rotation.
*
* Informs the HAL of the current orientation of the device screen. This
* information can be used to optimize the output of built-in speakers.
* This is an informative notification sent to all modules, no reply is
* needed.
*
* @param rotation The current rotation.
*/
void updateScreenRotation(ScreenRotation rotation);
/**
* Notify the HAL module on the change of the screen state.
*
* Informs the HAL whether the screen of the device is turned on. This is an
* informative notification sent to all modules, no reply is needed.
*
* @param isTurnedOn True if the screen is turned on.
*/
void updateScreenState(boolean isTurnedOn);
}

View File

@@ -0,0 +1,56 @@
/*
* 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.
*/
package android.hardware.audio.core;
import android.hardware.audio.core.AudioMode;
/**
* An instance of ITelephony manages settings which are specific to voice calls
* and SMS messaging functionality. This interface is optional to implement and
* provide by the vendor. It needs to be provided only if the device actually
* supports telephony.
*/
@VintfStability
interface ITelephony {
/**
* Return the list of supported audio modes.
*
* The first 4 AudioModes: NORMAL, RINGTONE, IN_CALL, IN_COMMUNICATION must
* be supported by all implementations.
*
* This method is only called once, during the audio system initialization,
* and must return the same result all the time.
*
* @return The list of supported audio modes.
*/
AudioMode[] getSupportedAudioModes();
/**
* Switch the HAL into a new audio mode.
*
* The current audio mode is always controlled by the client. The HAL must
* accept all modes returned by 'getSupportedAudioModes' and reject the
* rest. The HAL must return from this method only after switching itself
* to the specified mode, or throw an error if there was a problem during
* switching.
*
* @param mode The mode to switch to.
* @throws EX_UNSUPPORTED_OPERATION If the HAL does not support the specified mode.
* @throws EX_ILLEGAL_STATE If there was an error during switching.
*/
void switchAudioMode(AudioMode mode);
}

View File

@@ -39,6 +39,7 @@ cc_library_static {
"Configuration.cpp",
"Module.cpp",
"Stream.cpp",
"Telephony.cpp",
],
visibility: [
":__subpackages__",

View File

@@ -25,6 +25,7 @@
#include <aidl/android/media/audio/common/AudioOutputFlags.h>
#include "core-impl/Module.h"
#include "core-impl/Telephony.h"
#include "core-impl/utils.h"
using aidl::android::hardware::audio::common::SinkMetadata;
@@ -245,6 +246,15 @@ ndk::ScopedAStatus Module::setModuleDebug(
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Module::getTelephony(std::shared_ptr<ITelephony>* _aidl_return) {
if (mTelephony == nullptr) {
mTelephony = ndk::SharedRefBase::make<Telephony>();
}
*_aidl_return = mTelephony;
LOG(DEBUG) << __func__ << ": returning instance of ITelephony: " << _aidl_return->get();
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Module::connectExternalDevice(const AudioPort& in_templateIdAndAdditionalData,
AudioPort* _aidl_return) {
const int32_t templateId = in_templateIdAndAdditionalData.id;
@@ -779,4 +789,60 @@ ndk::ScopedAStatus Module::resetAudioPortConfig(int32_t in_portConfigId) {
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
ndk::ScopedAStatus Module::getMasterMute(bool* _aidl_return) {
*_aidl_return = mMasterMute;
LOG(DEBUG) << __func__ << ": returning " << *_aidl_return;
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Module::setMasterMute(bool in_mute) {
LOG(DEBUG) << __func__ << ": " << in_mute;
mMasterMute = in_mute;
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Module::getMasterVolume(float* _aidl_return) {
*_aidl_return = mMasterVolume;
LOG(DEBUG) << __func__ << ": returning " << *_aidl_return;
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Module::setMasterVolume(float in_volume) {
LOG(DEBUG) << __func__ << ": " << in_volume;
if (in_volume >= 0.0f && in_volume <= 1.0f) {
mMasterVolume = in_volume;
return ndk::ScopedAStatus::ok();
}
LOG(ERROR) << __func__ << ": invalid master volume value: " << in_volume;
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
ndk::ScopedAStatus Module::getMicMute(bool* _aidl_return) {
*_aidl_return = mMicMute;
LOG(DEBUG) << __func__ << ": returning " << *_aidl_return;
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Module::setMicMute(bool in_mute) {
LOG(DEBUG) << __func__ << ": " << in_mute;
mMicMute = in_mute;
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Module::updateAudioMode(AudioMode in_mode) {
// No checks for supported audio modes here, it's an informative notification.
LOG(DEBUG) << __func__ << ": " << toString(in_mode);
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Module::updateScreenRotation(ScreenRotation in_rotation) {
LOG(DEBUG) << __func__ << ": " << toString(in_rotation);
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Module::updateScreenState(bool in_isTurnedOn) {
LOG(DEBUG) << __func__ << ": " << in_isTurnedOn;
return ndk::ScopedAStatus::ok();
}
} // namespace aidl::android::hardware::audio::core

View File

@@ -0,0 +1,41 @@
/*
* 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.
*/
#include <android/binder_to_string.h>
#define LOG_TAG "AHAL_Telephony"
#include <android-base/logging.h>
#include "core-impl/Telephony.h"
namespace aidl::android::hardware::audio::core {
ndk::ScopedAStatus Telephony::getSupportedAudioModes(std::vector<AudioMode>* _aidl_return) {
*_aidl_return = mSupportedAudioModes;
LOG(DEBUG) << __func__ << ": returning " << ::android::internal::ToString(*_aidl_return);
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Telephony::switchAudioMode(AudioMode in_mode) {
if (std::find(mSupportedAudioModes.begin(), mSupportedAudioModes.end(), in_mode) !=
mSupportedAudioModes.end()) {
LOG(DEBUG) << __func__ << ": " << toString(in_mode);
return ndk::ScopedAStatus::ok();
}
LOG(ERROR) << __func__ << ": unsupported mode " << toString(in_mode);
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
} // namespace aidl::android::hardware::audio::core

View File

@@ -35,6 +35,7 @@ class Module : public BnModule {
private:
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 connectExternalDevice(
const ::aidl::android::media::audio::common::AudioPort& in_templateIdAndAdditionalData,
::aidl::android::media::audio::common::AudioPort* _aidl_return) override;
@@ -70,6 +71,17 @@ class Module : public BnModule {
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 updateAudioMode(
::aidl::android::hardware::audio::core::AudioMode in_mode) override;
ndk::ScopedAStatus updateScreenRotation(
::aidl::android::hardware::audio::core::IModule::ScreenRotation in_rotation) override;
ndk::ScopedAStatus updateScreenState(bool in_isTurnedOn) override;
void cleanUpPatch(int32_t patchId);
ndk::ScopedAStatus createStreamContext(
@@ -88,12 +100,18 @@ class Module : public BnModule {
std::unique_ptr<internal::Configuration> mConfig;
ModuleDebug mDebug;
// Since it is required to return the same instance of the ITelephony, even
// if the client has released it on its side, we need to hold it via a strong pointer.
std::shared_ptr<ITelephony> mTelephony;
// ids of ports created at runtime via 'connectExternalDevice'.
std::set<int32_t> mConnectedDevicePorts;
Streams mStreams;
// Maps port ids and port config ids to patch ids.
// Multimap because both ports and configs can be used by multiple patches.
std::multimap<int32_t, int32_t> mPatches;
bool mMasterMute = false;
float mMasterVolume = 1.0f;
bool mMicMute = false;
};
} // namespace aidl::android::hardware::audio::core

View File

@@ -0,0 +1,34 @@
/*
* 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 {
private:
ndk::ScopedAStatus getSupportedAudioModes(std::vector<AudioMode>* _aidl_return) override;
ndk::ScopedAStatus switchAudioMode(AudioMode in_mode) override;
const std::vector<AudioMode> mSupportedAudioModes = {::ndk::enum_range<AudioMode>().begin(),
::ndk::enum_range<AudioMode>().end()};
};
} // namespace aidl::android::hardware::audio::core

View File

@@ -21,6 +21,7 @@
#include <mutex>
#include <android-base/properties.h>
#include <android/binder_auto_utils.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
@@ -34,7 +35,7 @@ class AudioHalBinderServiceUtil {
if (mBinder == nullptr) {
LOG(ERROR) << "Failed to get service " << serviceName;
} else {
LOG(DEBUG) << "succeed to get service " << serviceName;
LOG(DEBUG) << "Succeeded to get service " << serviceName;
}
return mBinder;
}

View File

@@ -15,6 +15,7 @@
*/
#include <algorithm>
#include <cmath>
#include <limits>
#include <memory>
#include <optional>
@@ -29,8 +30,8 @@
#include <Utils.h>
#include <aidl/Gtest.h>
#include <aidl/Vintf.h>
#include <aidl/android/hardware/audio/core/IConfig.h>
#include <aidl/android/hardware/audio/core/IModule.h>
#include <aidl/android/hardware/audio/core/ITelephony.h>
#include <aidl/android/media/audio/common/AudioIoFlags.h>
#include <aidl/android/media/audio/common/AudioOutputFlags.h>
#include <android-base/chrono_utils.h>
@@ -46,11 +47,13 @@ using aidl::android::hardware::audio::common::PlaybackTrackMetadata;
using aidl::android::hardware::audio::common::RecordTrackMetadata;
using aidl::android::hardware::audio::common::SinkMetadata;
using aidl::android::hardware::audio::common::SourceMetadata;
using aidl::android::hardware::audio::core::AudioMode;
using aidl::android::hardware::audio::core::AudioPatch;
using aidl::android::hardware::audio::core::AudioRoute;
using aidl::android::hardware::audio::core::IModule;
using aidl::android::hardware::audio::core::IStreamIn;
using aidl::android::hardware::audio::core::IStreamOut;
using aidl::android::hardware::audio::core::ITelephony;
using aidl::android::hardware::audio::core::ModuleDebug;
using aidl::android::hardware::audio::core::StreamDescriptor;
using aidl::android::hardware::common::fmq::SynchronizedReadWrite;
@@ -173,6 +176,29 @@ class WithAudioPortConfig {
AudioPortConfig mConfig;
};
template <typename PropType, class Instance, typename Getter, typename Setter>
void TestAccessors(Instance* inst, Getter getter, Setter setter,
const std::vector<PropType>& validValues,
const std::vector<PropType>& invalidValues, bool* isSupported) {
PropType initialValue{};
ScopedAStatus status = (inst->*getter)(&initialValue);
if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
*isSupported = false;
return;
}
*isSupported = true;
for (const auto v : validValues) {
EXPECT_IS_OK((inst->*setter)(v)) << "for valid value: " << v;
PropType currentValue{};
EXPECT_IS_OK((inst->*getter)(&currentValue));
EXPECT_EQ(v, currentValue);
}
for (const auto v : invalidValues) {
EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, (inst->*setter)(v)) << "for invalid value: " << v;
}
EXPECT_IS_OK((inst->*setter)(initialValue)) << "Failed to restore the initial value";
}
// Can be used as a base for any test here, does not depend on the fixture GTest parameters.
class AudioCoreModuleBase {
public:
@@ -1242,6 +1268,112 @@ TEST_P(AudioCoreModule, ExternalDevicePortRoutes) {
}
}
TEST_P(AudioCoreModule, MasterMute) {
bool isSupported = false;
EXPECT_NO_FATAL_FAILURE(TestAccessors<bool>(module.get(), &IModule::getMasterMute,
&IModule::setMasterMute, {false, true}, {},
&isSupported));
if (!isSupported) {
GTEST_SKIP() << "Master mute is not supported";
}
// TODO: Test that master mute actually mutes output.
}
TEST_P(AudioCoreModule, MasterVolume) {
bool isSupported = false;
EXPECT_NO_FATAL_FAILURE(TestAccessors<float>(
module.get(), &IModule::getMasterVolume, &IModule::setMasterVolume, {0.0f, 0.5f, 1.0f},
{-0.1, 1.1, NAN, INFINITY, -INFINITY, 1 + std::numeric_limits<float>::epsilon()},
&isSupported));
if (!isSupported) {
GTEST_SKIP() << "Master volume is not supported";
}
// TODO: Test that master volume actually attenuates output.
}
TEST_P(AudioCoreModule, MicMute) {
bool isSupported = false;
EXPECT_NO_FATAL_FAILURE(TestAccessors<bool>(module.get(), &IModule::getMicMute,
&IModule::setMicMute, {false, true}, {},
&isSupported));
if (!isSupported) {
GTEST_SKIP() << "Mic mute is not supported";
}
// TODO: Test that mic mute actually mutes input.
}
TEST_P(AudioCoreModule, UpdateAudioMode) {
for (const auto mode : ::ndk::enum_range<AudioMode>()) {
EXPECT_IS_OK(module->updateAudioMode(mode)) << toString(mode);
}
EXPECT_IS_OK(module->updateAudioMode(AudioMode::NORMAL));
}
TEST_P(AudioCoreModule, UpdateScreenRotation) {
for (const auto rotation : ::ndk::enum_range<IModule::ScreenRotation>()) {
EXPECT_IS_OK(module->updateScreenRotation(rotation)) << toString(rotation);
}
EXPECT_IS_OK(module->updateScreenRotation(IModule::ScreenRotation::DEG_0));
}
TEST_P(AudioCoreModule, UpdateScreenState) {
EXPECT_IS_OK(module->updateScreenState(false));
EXPECT_IS_OK(module->updateScreenState(true));
}
class AudioCoreTelephony : public AudioCoreModuleBase, public testing::TestWithParam<std::string> {
public:
void SetUp() override {
ASSERT_NO_FATAL_FAILURE(SetUpImpl(GetParam()));
ASSERT_IS_OK(module->getTelephony(&telephony));
}
void TearDown() override { ASSERT_NO_FATAL_FAILURE(TearDownImpl()); }
std::shared_ptr<ITelephony> telephony;
};
TEST_P(AudioCoreTelephony, GetSupportedAudioModes) {
if (telephony == nullptr) {
GTEST_SKIP() << "Telephony is not supported";
}
std::vector<AudioMode> modes1;
ASSERT_IS_OK(telephony->getSupportedAudioModes(&modes1));
const std::vector<AudioMode> kMandatoryModes = {AudioMode::NORMAL, AudioMode::RINGTONE,
AudioMode::IN_CALL,
AudioMode::IN_COMMUNICATION};
for (const auto mode : kMandatoryModes) {
EXPECT_NE(modes1.end(), std::find(modes1.begin(), modes1.end(), mode))
<< "Mandatory mode not supported: " << toString(mode);
}
std::vector<AudioMode> modes2;
ASSERT_IS_OK(telephony->getSupportedAudioModes(&modes2));
ASSERT_EQ(modes1.size(), modes2.size())
<< "Sizes of audio mode arrays do not match across consequent calls to "
<< "getSupportedAudioModes";
std::sort(modes1.begin(), modes1.end());
std::sort(modes2.begin(), modes2.end());
EXPECT_EQ(modes1, modes2);
};
TEST_P(AudioCoreTelephony, SwitchAudioMode) {
if (telephony == nullptr) {
GTEST_SKIP() << "Telephony is not supported";
}
std::vector<AudioMode> supportedModes;
ASSERT_IS_OK(telephony->getSupportedAudioModes(&supportedModes));
std::set<AudioMode> unsupportedModes = {
// Start with all, remove supported ones
::ndk::enum_range<AudioMode>().begin(), ::ndk::enum_range<AudioMode>().end()};
for (const auto mode : supportedModes) {
EXPECT_IS_OK(telephony->switchAudioMode(mode)) << toString(mode);
unsupportedModes.erase(mode);
}
for (const auto mode : unsupportedModes) {
EXPECT_STATUS(EX_UNSUPPORTED_OPERATION, telephony->switchAudioMode(mode)) << toString(mode);
}
}
class StreamLogicDriverInvalidCommand : public StreamLogicDriver {
public:
StreamLogicDriverInvalidCommand(const std::vector<StreamDescriptor::Command>& commands)
@@ -1825,6 +1957,9 @@ TEST_P(AudioModulePatch, ResetInvalidPatchId) {
INSTANTIATE_TEST_SUITE_P(AudioCoreModuleTest, AudioCoreModule,
testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
android::PrintInstanceNameToString);
INSTANTIATE_TEST_SUITE_P(AudioCoreTelephonyTest, AudioCoreTelephony,
testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
android::PrintInstanceNameToString);
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioCoreModule);
INSTANTIATE_TEST_SUITE_P(AudioStreamInTest, AudioStreamIn,
testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),