Merge "Use static libaudiofoundation in VTS."
diff --git a/Android.bp b/Android.bp
index dd84737..70e0574 100644
--- a/Android.bp
+++ b/Android.bp
@@ -45,4 +45,5 @@
"-g",
],
+ require_root: true,
}
diff --git a/CleanSpec.mk b/CleanSpec.mk
index edde1cb..da2635e 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -80,3 +80,4 @@
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib64/android.hardware.configstore@1.2.so)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/vndk-Q/android.hardware.configstore@1.2.so)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/android.hardware.configstore@1.2.so)
+$(call add-clean-step, rm -f $(PRODUCT_OUT)/etc/init/android.hardware.audio@2.0-service.rc $(PRODUCT_OUT)/vendor/bin/hw/android.hardware.audio@2.0-service)
diff --git a/audio/4.0/config/api/current.txt b/audio/4.0/config/api/current.txt
index d59cade..3462568 100644
--- a/audio/4.0/config/api/current.txt
+++ b/audio/4.0/config/api/current.txt
@@ -114,11 +114,15 @@
enum_constant public static final audio.policy.configuration.V4_0.AudioFormat AUDIO_FORMAT_EVRCNW;
enum_constant public static final audio.policy.configuration.V4_0.AudioFormat AUDIO_FORMAT_EVRCWB;
enum_constant public static final audio.policy.configuration.V4_0.AudioFormat AUDIO_FORMAT_E_AC3;
+ enum_constant public static final audio.policy.configuration.V4_0.AudioFormat AUDIO_FORMAT_E_AC3_JOC;
enum_constant public static final audio.policy.configuration.V4_0.AudioFormat AUDIO_FORMAT_FLAC;
enum_constant public static final audio.policy.configuration.V4_0.AudioFormat AUDIO_FORMAT_HE_AAC_V1;
enum_constant public static final audio.policy.configuration.V4_0.AudioFormat AUDIO_FORMAT_HE_AAC_V2;
enum_constant public static final audio.policy.configuration.V4_0.AudioFormat AUDIO_FORMAT_IEC61937;
enum_constant public static final audio.policy.configuration.V4_0.AudioFormat AUDIO_FORMAT_LDAC;
+ enum_constant public static final audio.policy.configuration.V4_0.AudioFormat AUDIO_FORMAT_MAT_1_0;
+ enum_constant public static final audio.policy.configuration.V4_0.AudioFormat AUDIO_FORMAT_MAT_2_0;
+ enum_constant public static final audio.policy.configuration.V4_0.AudioFormat AUDIO_FORMAT_MAT_2_1;
enum_constant public static final audio.policy.configuration.V4_0.AudioFormat AUDIO_FORMAT_MP2;
enum_constant public static final audio.policy.configuration.V4_0.AudioFormat AUDIO_FORMAT_MP3;
enum_constant public static final audio.policy.configuration.V4_0.AudioFormat AUDIO_FORMAT_OPUS;
diff --git a/audio/4.0/config/audio_policy_configuration.xsd b/audio/4.0/config/audio_policy_configuration.xsd
index 58bab22..f26e41b 100644
--- a/audio/4.0/config/audio_policy_configuration.xsd
+++ b/audio/4.0/config/audio_policy_configuration.xsd
@@ -357,6 +357,10 @@
<xs:enumeration value="AUDIO_FORMAT_APTX_HD"/>
<xs:enumeration value="AUDIO_FORMAT_AC4"/>
<xs:enumeration value="AUDIO_FORMAT_LDAC"/>
+ <xs:enumeration value="AUDIO_FORMAT_E_AC3_JOC"/>
+ <xs:enumeration value="AUDIO_FORMAT_MAT_1_0"/>
+ <xs:enumeration value="AUDIO_FORMAT_MAT_2_0"/>
+ <xs:enumeration value="AUDIO_FORMAT_MAT_2_1"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="extendableAudioFormat">
diff --git a/audio/6.0/Android.bp b/audio/6.0/Android.bp
new file mode 100644
index 0000000..dc6bb98
--- /dev/null
+++ b/audio/6.0/Android.bp
@@ -0,0 +1,27 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.audio@6.0",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "types.hal",
+ "IDevice.hal",
+ "IDevicesFactory.hal",
+ "IPrimaryDevice.hal",
+ "IStream.hal",
+ "IStreamIn.hal",
+ "IStreamOut.hal",
+ "IStreamOutCallback.hal",
+ ],
+ interfaces: [
+ "android.hardware.audio.common@6.0",
+ "android.hardware.audio.effect@6.0",
+ "android.hidl.base@1.0",
+ "android.hidl.safe_union@1.0",
+ ],
+ gen_java: false,
+ gen_java_constants: true,
+}
diff --git a/audio/6.0/IDevice.hal b/audio/6.0/IDevice.hal
new file mode 100644
index 0000000..42a545b
--- /dev/null
+++ b/audio/6.0/IDevice.hal
@@ -0,0 +1,282 @@
+/*
+ * Copyright (C) 2019 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@6.0;
+
+import android.hardware.audio.common@6.0;
+import IStreamIn;
+import IStreamOut;
+
+interface IDevice {
+ /**
+ * Returns whether the audio hardware interface has been initialized.
+ *
+ * @return retval OK on success, NOT_INITIALIZED on failure.
+ */
+ initCheck() generates (Result retval);
+
+ /**
+ * Sets the audio volume for all audio activities other than voice call. If
+ * NOT_SUPPORTED is returned, the software mixer will emulate this
+ * capability.
+ *
+ * @param volume 1.0f means unity, 0.0f is zero.
+ * @return retval operation completion status.
+ */
+ setMasterVolume(float volume) generates (Result retval);
+
+ /**
+ * Get the current master volume value for the HAL, if the HAL supports
+ * master volume control. For example, AudioFlinger will query this value
+ * from the primary audio HAL when the service starts and use the value for
+ * setting the initial master volume across all HALs. HALs which do not
+ * support this method must return NOT_SUPPORTED in 'retval'.
+ *
+ * @return retval operation completion status.
+ * @return volume 1.0f means unity, 0.0f is zero.
+ */
+ getMasterVolume() generates (Result retval, float volume);
+
+ /**
+ * Sets microphone muting state.
+ *
+ * @param mute whether microphone is muted.
+ * @return retval operation completion status.
+ */
+ setMicMute(bool mute) generates (Result retval);
+
+ /**
+ * Gets whether microphone is muted.
+ *
+ * @return retval operation completion status.
+ * @return mute whether microphone is muted.
+ */
+ getMicMute() generates (Result retval, bool mute);
+
+ /**
+ * Set the audio mute status for all audio activities. If the return value
+ * is NOT_SUPPORTED, the software mixer will emulate this capability.
+ *
+ * @param mute whether audio is muted.
+ * @return retval operation completion status.
+ */
+ setMasterMute(bool mute) generates (Result retval);
+
+ /**
+ * Get the current master mute status for the HAL, if the HAL supports
+ * master mute control. AudioFlinger will query this value from the primary
+ * audio HAL when the service starts and use the value for setting the
+ * initial master mute across all HALs. HAL must indicate that the feature
+ * is not supported by returning NOT_SUPPORTED status.
+ *
+ * @return retval operation completion status.
+ * @return mute whether audio is muted.
+ */
+ getMasterMute() generates (Result retval, bool mute);
+
+ /**
+ * Returns audio input buffer size according to parameters passed or
+ * INVALID_ARGUMENTS if one of the parameters is not supported.
+ *
+ * @param config audio configuration.
+ * @return retval operation completion status.
+ * @return bufferSize input buffer size in bytes.
+ */
+ getInputBufferSize(AudioConfig config)
+ generates (Result retval, uint64_t bufferSize);
+
+ /**
+ * This method creates and opens the audio hardware output stream.
+ * If the stream can not be opened with the proposed audio config,
+ * HAL must provide suggested values for the audio config.
+ *
+ * @param ioHandle handle assigned by AudioFlinger.
+ * @param device device type and (if needed) address.
+ * @param config stream configuration.
+ * @param flags additional flags.
+ * @param sourceMetadata Description of the audio that will be played.
+ May be used by implementations to configure hardware effects.
+ * @return retval operation completion status.
+ * @return outStream created output stream.
+ * @return suggestedConfig in case of invalid parameters, suggested config.
+ */
+ openOutputStream(
+ AudioIoHandle ioHandle,
+ DeviceAddress device,
+ AudioConfig config,
+ bitfield<AudioOutputFlag> flags,
+ SourceMetadata sourceMetadata) generates (
+ Result retval,
+ IStreamOut outStream,
+ AudioConfig suggestedConfig);
+
+ /**
+ * This method creates and opens the audio hardware input stream.
+ * If the stream can not be opened with the proposed audio config,
+ * HAL must provide suggested values for the audio config.
+ *
+ * @param ioHandle handle assigned by AudioFlinger.
+ * @param device device type and (if needed) address.
+ * @param config stream configuration.
+ * @param flags additional flags.
+ * @param sinkMetadata Description of the audio that is suggested by the client.
+ * May be used by implementations to configure processing effects.
+ * @return retval operation completion status.
+ * @return inStream in case of success, created input stream.
+ * @return suggestedConfig in case of invalid parameters, suggested config.
+ */
+ openInputStream(
+ AudioIoHandle ioHandle,
+ DeviceAddress device,
+ AudioConfig config,
+ bitfield<AudioInputFlag> flags,
+ SinkMetadata sinkMetadata) generates (
+ Result retval,
+ IStreamIn inStream,
+ AudioConfig suggestedConfig);
+
+ /**
+ * Returns whether HAL supports audio patches.
+ *
+ * @return supports true if audio patches are supported.
+ */
+ supportsAudioPatches() generates (bool supports);
+
+ /**
+ * Creates an audio patch between several source and sink ports. The handle
+ * is allocated by the HAL and must be unique for this audio HAL module.
+ *
+ * @param sources patch sources.
+ * @param sinks patch sinks.
+ * @return retval operation completion status.
+ * @return patch created patch handle.
+ */
+ createAudioPatch(vec<AudioPortConfig> sources, vec<AudioPortConfig> sinks)
+ generates (Result retval, AudioPatchHandle patch);
+
+ /**
+ * Release an audio patch.
+ *
+ * @param patch patch handle.
+ * @return retval operation completion status.
+ */
+ releaseAudioPatch(AudioPatchHandle patch) generates (Result retval);
+
+ /**
+ * Returns the list of supported attributes for a given audio port.
+ *
+ * As input, 'port' contains the information (type, role, address etc...)
+ * needed by the HAL to identify the port.
+ *
+ * As output, 'resultPort' contains possible attributes (sampling rates,
+ * formats, channel masks, gain controllers...) for this port.
+ *
+ * @param port port identifier.
+ * @return retval operation completion status.
+ * @return resultPort port descriptor with all parameters filled up.
+ */
+ getAudioPort(AudioPort port)
+ generates (Result retval, AudioPort resultPort);
+
+ /**
+ * Set audio port configuration.
+ *
+ * @param config audio port configuration.
+ * @return retval operation completion status.
+ */
+ setAudioPortConfig(AudioPortConfig config) generates (Result retval);
+
+ /**
+ * Gets the HW synchronization source of the device. Calling this method is
+ * equivalent to getting AUDIO_PARAMETER_HW_AV_SYNC on the legacy HAL.
+ * Optional method
+ *
+ * @return retval operation completion status: OK or NOT_SUPPORTED.
+ * @return hwAvSync HW synchronization source
+ */
+ getHwAvSync() generates (Result retval, AudioHwSync hwAvSync);
+
+ /**
+ * Sets whether the screen is on. Calling this method is equivalent to
+ * setting AUDIO_PARAMETER_KEY_SCREEN_STATE on the legacy HAL.
+ * Optional method
+ *
+ * @param turnedOn whether the screen is turned on.
+ * @return retval operation completion status.
+ */
+ setScreenState(bool turnedOn) generates (Result retval);
+
+ /**
+ * Generic method for retrieving vendor-specific parameter values.
+ * The framework does not interpret the parameters, they are passed
+ * in an opaque manner between a vendor application and HAL.
+ *
+ * Multiple parameters can be retrieved at the same time.
+ * The implementation should return as many requested parameters
+ * as possible, even if one or more is not supported
+ *
+ * @param context provides more information about the request
+ * @param keys keys of the requested parameters
+ * @return retval operation completion status.
+ * OK must be returned if keys is empty.
+ * NOT_SUPPORTED must be returned if at least one key is unknown.
+ * @return parameters parameter key value pairs.
+ * Must contain the value of all requested keys if retval == OK
+ */
+ getParameters(vec<ParameterValue> context, vec<string> keys)
+ generates (Result retval, vec<ParameterValue> parameters);
+
+ /**
+ * Generic method for setting vendor-specific parameter values.
+ * The framework does not interpret the parameters, they are passed
+ * in an opaque manner between a vendor application and HAL.
+ *
+ * Multiple parameters can be set at the same time though this is
+ * discouraged as it make failure analysis harder.
+ *
+ * If possible, a failed setParameters should not impact the platform state.
+ *
+ * @param context provides more information about the request
+ * @param parameters parameter key value pairs.
+ * @return retval operation completion status.
+ * All parameters must be successfully set for OK to be returned
+ */
+ setParameters(vec<ParameterValue> context, vec<ParameterValue> parameters)
+ generates (Result retval);
+
+ /**
+ * Returns an array with available microphones in device.
+ *
+ * @return retval INVALID_STATE if the call is not successful,
+ * OK otherwise.
+ *
+ * @return microphones array with microphones info
+ */
+ getMicrophones()
+ generates(Result retval, vec<MicrophoneInfo> microphones);
+
+ /**
+ * Notifies the device module about the connection state of an input/output
+ * device attached to it. Calling this method is equivalent to setting
+ * AUDIO_PARAMETER_DEVICE_[DIS]CONNECT on the legacy HAL.
+ *
+ * @param address audio device specification.
+ * @param connected whether the device is connected.
+ * @return retval operation completion status.
+ */
+ setConnectedState(DeviceAddress address, bool connected)
+ generates (Result retval);
+};
diff --git a/audio/6.0/IDevicesFactory.hal b/audio/6.0/IDevicesFactory.hal
new file mode 100644
index 0000000..0483473
--- /dev/null
+++ b/audio/6.0/IDevicesFactory.hal
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2019 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@6.0;
+
+import android.hardware.audio.common@6.0;
+import IDevice;
+import IPrimaryDevice;
+
+/** This factory allows a HAL implementation to be split in multiple independent
+ * devices (called module in the pre-treble API).
+ * Note that this division is arbitrary and implementation are free
+ * to only have a Primary.
+ * The framework will query the devices according to audio_policy_configuration.xml
+ *
+ * Each device name is arbitrary, provided by the vendor's audio_policy_configuration.xml
+ * and only used to identify a device in this factory.
+ * The framework must not interpret the name, treating it as a vendor opaque data
+ * with the following exception:
+ * - the "r_submix" device that must be present to support policyMixes (Eg: Android projected).
+ * Note that this Device is included by default in a build derived from AOSP.
+ *
+ * Note that on AOSP Oreo (including MR1) the "a2dp" module is not using this API
+ * but is loaded directly from the system partition using the legacy API
+ * due to limitations with the Bluetooth framework.
+ */
+interface IDevicesFactory {
+
+ /**
+ * Opens an audio device. To close the device, it is necessary to release
+ * references to the returned device object.
+ *
+ * @param device device name.
+ * @return retval operation completion status. Returns INVALID_ARGUMENTS
+ * if there is no corresponding hardware module found,
+ * NOT_INITIALIZED if an error occurred while opening the hardware
+ * module.
+ * @return result the interface for the created device.
+ */
+ openDevice(string device) generates (Result retval, IDevice result);
+
+ /**
+ * Opens the Primary audio device that must be present.
+ * This function is not optional and must return successfully the primary device.
+ *
+ * This device must have the name "primary".
+ *
+ * The telephony stack uses this device to control the audio during a voice call.
+ *
+ * @return retval operation completion status. Must be SUCCESS.
+ * For debugging, return INVALID_ARGUMENTS if there is no corresponding
+ * hardware module found, NOT_INITIALIZED if an error occurred
+ * while opening the hardware module.
+ * @return result the interface for the created device.
+ */
+ openPrimaryDevice() generates (Result retval, IPrimaryDevice result);
+};
diff --git a/audio/6.0/IPrimaryDevice.hal b/audio/6.0/IPrimaryDevice.hal
new file mode 100644
index 0000000..78cfc65
--- /dev/null
+++ b/audio/6.0/IPrimaryDevice.hal
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2019 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@6.0;
+
+import android.hardware.audio.common@6.0;
+import IDevice;
+
+interface IPrimaryDevice extends IDevice {
+ /**
+ * Sets the audio volume of a voice call.
+ *
+ * @param volume 1.0f means unity, 0.0f is zero.
+ * @return retval operation completion status.
+ */
+ setVoiceVolume(float volume) generates (Result retval);
+
+ /**
+ * This method is used to notify the HAL about audio mode changes.
+ *
+ * @param mode new mode.
+ * @return retval operation completion status.
+ */
+ setMode(AudioMode mode) generates (Result retval);
+
+ /**
+ * Sets the name of the current BT SCO headset. Calling this method
+ * is equivalent to setting legacy "bt_headset_name" parameter.
+ * The BT SCO headset name must only be used for debugging purposes.
+ * Optional method
+ *
+ * @param name the name of the current BT SCO headset (can be empty).
+ * @return retval operation completion status.
+ */
+ setBtScoHeadsetDebugName(string name) generates (Result retval);
+
+ /**
+ * Gets whether BT SCO Noise Reduction and Echo Cancellation are enabled.
+ * Calling this method is equivalent to getting AUDIO_PARAMETER_KEY_BT_NREC
+ * on the legacy HAL.
+ *
+ * @return retval operation completion status.
+ * @return enabled whether BT SCO NR + EC are enabled.
+ */
+ getBtScoNrecEnabled() generates (Result retval, bool enabled);
+
+ /**
+ * Sets whether BT SCO Noise Reduction and Echo Cancellation are enabled.
+ * Calling this method is equivalent to setting AUDIO_PARAMETER_KEY_BT_NREC
+ * on the legacy HAL.
+ * Optional method
+ *
+ * @param enabled whether BT SCO NR + EC are enabled.
+ * @return retval operation completion status.
+ */
+ setBtScoNrecEnabled(bool enabled) generates (Result retval);
+
+ /**
+ * Gets whether BT SCO Wideband mode is enabled. Calling this method is
+ * equivalent to getting AUDIO_PARAMETER_KEY_BT_SCO_WB on the legacy HAL.
+ *
+ * @return retval operation completion status.
+ * @return enabled whether BT Wideband is enabled.
+ */
+ getBtScoWidebandEnabled() generates (Result retval, bool enabled);
+
+ /**
+ * Sets whether BT SCO Wideband mode is enabled. Calling this method is
+ * equivalent to setting AUDIO_PARAMETER_KEY_BT_SCO_WB on the legacy HAL.
+ * Optional method
+ *
+ * @param enabled whether BT Wideband is enabled.
+ * @return retval operation completion status.
+ */
+ setBtScoWidebandEnabled(bool enabled) generates (Result retval);
+
+ /**
+ * Gets whether BT HFP (Hands-Free Profile) is enabled. Calling this method
+ * is equivalent to getting "hfp_enable" parameter value on the legacy HAL.
+ *
+ * @return retval operation completion status.
+ * @return enabled whether BT HFP is enabled.
+ */
+ getBtHfpEnabled() generates (Result retval, bool enabled);
+
+ /**
+ * Sets whether BT HFP (Hands-Free Profile) is enabled. Calling this method
+ * is equivalent to setting "hfp_enable" parameter on the legacy HAL.
+ * Optional method
+ *
+ * @param enabled whether BT HFP is enabled.
+ * @return retval operation completion status.
+ */
+ setBtHfpEnabled(bool enabled) generates (Result retval);
+
+ /**
+ * Sets the sampling rate of BT HFP (Hands-Free Profile). Calling this
+ * method is equivalent to setting "hfp_set_sampling_rate" parameter
+ * on the legacy HAL.
+ * Optional method
+ *
+ * @param sampleRateHz sample rate in Hz.
+ * @return retval operation completion status.
+ */
+ setBtHfpSampleRate(uint32_t sampleRateHz) generates (Result retval);
+
+ /**
+ * Sets the current output volume Hz for BT HFP (Hands-Free Profile).
+ * Calling this method is equivalent to setting "hfp_volume" parameter value
+ * on the legacy HAL (except that legacy HAL implementations expect
+ * an integer value in the range from 0 to 15.)
+ * Optional method
+ *
+ * @param volume 1.0f means unity, 0.0f is zero.
+ * @return retval operation completion status.
+ */
+ setBtHfpVolume(float volume) generates (Result retval);
+
+ enum TtyMode : int32_t {
+ OFF,
+ VCO,
+ HCO,
+ FULL
+ };
+
+ /**
+ * Gets current TTY mode selection. Calling this method is equivalent to
+ * getting AUDIO_PARAMETER_KEY_TTY_MODE on the legacy HAL.
+ *
+ * @return retval operation completion status.
+ * @return mode TTY mode.
+ */
+ getTtyMode() generates (Result retval, TtyMode mode);
+
+ /**
+ * Sets current TTY mode. Calling this method is equivalent to setting
+ * AUDIO_PARAMETER_KEY_TTY_MODE on the legacy HAL.
+ *
+ * @param mode TTY mode.
+ * @return retval operation completion status.
+ */
+ setTtyMode(TtyMode mode) generates (Result retval);
+
+ /**
+ * Gets whether Hearing Aid Compatibility - Telecoil (HAC-T) mode is
+ * enabled. Calling this method is equivalent to getting
+ * AUDIO_PARAMETER_KEY_HAC on the legacy HAL.
+ *
+ * @return retval operation completion status.
+ * @return enabled whether HAC mode is enabled.
+ */
+ getHacEnabled() generates (Result retval, bool enabled);
+
+ /**
+ * Sets whether Hearing Aid Compatibility - Telecoil (HAC-T) mode is
+ * enabled. Calling this method is equivalent to setting
+ * AUDIO_PARAMETER_KEY_HAC on the legacy HAL.
+ * Optional method
+ *
+ * @param enabled whether HAC mode is enabled.
+ * @return retval operation completion status.
+ */
+ setHacEnabled(bool enabled) generates (Result retval);
+
+ enum Rotation : int32_t {
+ DEG_0,
+ DEG_90,
+ DEG_180,
+ DEG_270
+ };
+
+ /**
+ * Updates HAL on the current rotation of the device relative to natural
+ * orientation. Calling this method is equivalent to setting legacy
+ * parameter "rotation".
+ *
+ * @param rotation rotation in degrees relative to natural device
+ * orientation.
+ * @return retval operation completion status.
+ */
+ updateRotation(Rotation rotation) generates (Result retval);
+};
diff --git a/audio/6.0/IStream.hal b/audio/6.0/IStream.hal
new file mode 100644
index 0000000..f4c91f8
--- /dev/null
+++ b/audio/6.0/IStream.hal
@@ -0,0 +1,310 @@
+/*
+ * Copyright (C) 2019 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@6.0;
+
+import android.hardware.audio.common@6.0;
+import android.hardware.audio.effect@6.0::IEffect;
+
+interface IStream {
+ /**
+ * Return the frame size (number of bytes per sample).
+ *
+ * @return frameSize frame size in bytes.
+ */
+ getFrameSize() generates (uint64_t frameSize);
+
+ /**
+ * Return the frame count of the buffer. Calling this method is equivalent
+ * to getting AUDIO_PARAMETER_STREAM_FRAME_COUNT on the legacy HAL.
+ *
+ * @return count frame count.
+ */
+ getFrameCount() generates (uint64_t count);
+
+ /**
+ * Return the size of input/output buffer in bytes for this stream.
+ * It must be a multiple of the frame size.
+ *
+ * @return buffer buffer size in bytes.
+ */
+ getBufferSize() generates (uint64_t bufferSize);
+
+ /**
+ * Return the sampling rate in Hz.
+ *
+ * @return sampleRateHz sample rate in Hz.
+ */
+ getSampleRate() generates (uint32_t sampleRateHz);
+
+ /**
+ * Return supported native sampling rates of the stream for a given format.
+ * A supported native sample rate is a sample rate that can be efficiently
+ * played by the hardware (typically without sample-rate conversions).
+ *
+ * This function is only called for dynamic profile. If called for
+ * non-dynamic profile is should return NOT_SUPPORTED or the same list
+ * as in audio_policy_configuration.xml.
+ *
+ * Calling this method is equivalent to getting
+ * AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES on the legacy HAL.
+ *
+ *
+ * @param format audio format for which the sample rates are supported.
+ * @return retval operation completion status.
+ * Must be OK if the format is supported.
+ * @return sampleRateHz supported sample rates.
+ */
+ getSupportedSampleRates(AudioFormat format)
+ generates (Result retval, vec<uint32_t> sampleRates);
+
+ /**
+ * Sets the sampling rate of the stream. Calling this method is equivalent
+ * to setting AUDIO_PARAMETER_STREAM_SAMPLING_RATE on the legacy HAL.
+ * Optional method. If implemented, only called on a stopped stream.
+ *
+ * @param sampleRateHz sample rate in Hz.
+ * @return retval operation completion status.
+ */
+ setSampleRate(uint32_t sampleRateHz) generates (Result retval);
+
+ /**
+ * Return the channel mask of the stream.
+ *
+ * @return mask channel mask.
+ */
+ getChannelMask() generates (bitfield<AudioChannelMask> mask);
+
+ /**
+ * Return supported channel masks of the stream. Calling this method is
+ * equivalent to getting AUDIO_PARAMETER_STREAM_SUP_CHANNELS on the legacy
+ * HAL.
+ *
+ * @param format audio format for which the channel masks are supported.
+ * @return retval operation completion status.
+ * Must be OK if the format is supported.
+ * @return masks supported audio masks.
+ */
+ getSupportedChannelMasks(AudioFormat format)
+ generates (Result retval, vec<bitfield<AudioChannelMask>> masks);
+
+ /**
+ * Sets the channel mask of the stream. Calling this method is equivalent to
+ * setting AUDIO_PARAMETER_STREAM_CHANNELS on the legacy HAL.
+ * Optional method
+ *
+ * @param format audio format.
+ * @return retval operation completion status.
+ */
+ setChannelMask(bitfield<AudioChannelMask> mask) generates (Result retval);
+
+ /**
+ * Return the audio format of the stream.
+ *
+ * @return format audio format.
+ */
+ getFormat() generates (AudioFormat format);
+
+ /**
+ * Return supported audio formats of the stream. Calling this method is
+ * equivalent to getting AUDIO_PARAMETER_STREAM_SUP_FORMATS on the legacy
+ * HAL.
+ *
+ * @return formats supported audio formats.
+ */
+ getSupportedFormats() generates (vec<AudioFormat> formats);
+
+ /**
+ * Sets the audio format of the stream. Calling this method is equivalent to
+ * setting AUDIO_PARAMETER_STREAM_FORMAT on the legacy HAL.
+ * Optional method
+ *
+ * @param format audio format.
+ * @return retval operation completion status.
+ */
+ setFormat(AudioFormat format) generates (Result retval);
+
+ /**
+ * Convenience method for retrieving several stream parameters in
+ * one transaction.
+ *
+ * @return sampleRateHz sample rate in Hz.
+ * @return mask channel mask.
+ * @return format audio format.
+ */
+ getAudioProperties() generates (
+ uint32_t sampleRateHz, bitfield<AudioChannelMask> mask, AudioFormat format);
+
+ /**
+ * Applies audio effect to the stream.
+ *
+ * @param effectId effect ID (obtained from IEffectsFactory.createEffect) of
+ * the effect to apply.
+ * @return retval operation completion status.
+ */
+ addEffect(uint64_t effectId) generates (Result retval);
+
+ /**
+ * Stops application of the effect to the stream.
+ *
+ * @param effectId effect ID (obtained from IEffectsFactory.createEffect) of
+ * the effect to remove.
+ * @return retval operation completion status.
+ */
+ removeEffect(uint64_t effectId) generates (Result retval);
+
+ /**
+ * Put the audio hardware input/output into standby mode.
+ * Driver must exit from standby mode at the next I/O operation.
+ *
+ * @return retval operation completion status.
+ */
+ standby() generates (Result retval);
+
+ /**
+ * Return the set of devices which this stream is connected to.
+ * Optional method
+ *
+ * @return retval operation completion status: OK or NOT_SUPPORTED.
+ * @return device set of devices which this stream is connected to.
+ */
+ getDevices() generates (Result retval, vec<DeviceAddress> devices);
+
+ /**
+ * Connects the stream to one or multiple devices.
+ *
+ * This method must only be used for HALs that do not support
+ * 'IDevice.createAudioPatch' method. Calling this method is
+ * equivalent to setting AUDIO_PARAMETER_STREAM_ROUTING preceded
+ * with a device address in the legacy HAL interface.
+ *
+ * @param address device to connect the stream to.
+ * @return retval operation completion status.
+ */
+ setDevices(vec<DeviceAddress> devices) generates (Result retval);
+
+ /**
+ * Sets the HW synchronization source. Calling this method is equivalent to
+ * setting AUDIO_PARAMETER_STREAM_HW_AV_SYNC on the legacy HAL.
+ * Optional method
+ *
+ * @param hwAvSync HW synchronization source
+ * @return retval operation completion status.
+ */
+ setHwAvSync(AudioHwSync hwAvSync) generates (Result retval);
+
+ /**
+ * Generic method for retrieving vendor-specific parameter values.
+ * The framework does not interpret the parameters, they are passed
+ * in an opaque manner between a vendor application and HAL.
+ *
+ * Multiple parameters can be retrieved at the same time.
+ * The implementation should return as many requested parameters
+ * as possible, even if one or more is not supported
+ *
+ * @param context provides more information about the request
+ * @param keys keys of the requested parameters
+ * @return retval operation completion status.
+ * OK must be returned if keys is empty.
+ * NOT_SUPPORTED must be returned if at least one key is unknown.
+ * @return parameters parameter key value pairs.
+ * Must contain the value of all requested keys if retval == OK
+ */
+ getParameters(vec<ParameterValue> context, vec<string> keys)
+ generates (Result retval, vec<ParameterValue> parameters);
+
+ /**
+ * Generic method for setting vendor-specific parameter values.
+ * The framework does not interpret the parameters, they are passed
+ * in an opaque manner between a vendor application and HAL.
+ *
+ * Multiple parameters can be set at the same time though this is
+ * discouraged as it make failure analysis harder.
+ *
+ * If possible, a failed setParameters should not impact the platform state.
+ *
+ * @param context provides more information about the request
+ * @param parameters parameter key value pairs.
+ * @return retval operation completion status.
+ * All parameters must be successfully set for OK to be returned
+ */
+ setParameters(vec<ParameterValue> context, vec<ParameterValue> parameters)
+ generates (Result retval);
+
+ /**
+ * Called by the framework to start a stream operating in mmap mode.
+ * createMmapBuffer() must be called before calling start().
+ * Function only implemented by streams operating in mmap mode.
+ *
+ * @return retval OK in case the success.
+ * NOT_SUPPORTED on non mmap mode streams
+ * INVALID_STATE if called out of sequence
+ */
+ start() generates (Result retval);
+
+ /**
+ * Called by the framework to stop a stream operating in mmap mode.
+ * Function only implemented by streams operating in mmap mode.
+ *
+ * @return retval OK in case the success.
+ * NOT_SUPPORTED on non mmap mode streams
+ * INVALID_STATE if called out of sequence
+ */
+ stop() generates (Result retval) ;
+
+ /**
+ * Called by the framework to retrieve information on the mmap buffer used for audio
+ * samples transfer.
+ * Function only implemented by streams operating in mmap mode.
+ *
+ * @param minSizeFrames minimum buffer size requested. The actual buffer
+ * size returned in struct MmapBufferInfo can be larger.
+ * @return retval OK in case the success.
+ * NOT_SUPPORTED on non mmap mode streams
+ * NOT_INITIALIZED in case of memory allocation error
+ * INVALID_ARGUMENTS if the requested buffer size is too large
+ * INVALID_STATE if called out of sequence
+ * @return info a MmapBufferInfo struct containing information on the MMMAP buffer created.
+ */
+ createMmapBuffer(int32_t minSizeFrames)
+ generates (Result retval, MmapBufferInfo info);
+
+ /**
+ * Called by the framework to read current read/write position in the mmap buffer
+ * with associated time stamp.
+ * Function only implemented by streams operating in mmap mode.
+ *
+ * @return retval OK in case the success.
+ * NOT_SUPPORTED on non mmap mode streams
+ * INVALID_STATE if called out of sequence
+ * @return position a MmapPosition struct containing current HW read/write position in frames
+ * with associated time stamp.
+ */
+ getMmapPosition()
+ generates (Result retval, MmapPosition position);
+
+ /**
+ * Called by the framework to deinitialize the stream and free up
+ * all the currently allocated resources. It is recommended to close
+ * the stream on the client side as soon as it is becomes unused.
+ *
+ * @return retval OK in case the success.
+ * NOT_SUPPORTED if called on IStream instead of input or
+ * output stream interface.
+ * INVALID_STATE if the stream was already closed.
+ */
+ close() generates (Result retval);
+};
diff --git a/audio/6.0/IStreamIn.hal b/audio/6.0/IStreamIn.hal
new file mode 100644
index 0000000..aadc370
--- /dev/null
+++ b/audio/6.0/IStreamIn.hal
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2019 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@6.0;
+
+import android.hardware.audio.common@6.0;
+import IStream;
+
+interface IStreamIn extends IStream {
+ /**
+ * Returns the source descriptor of the input stream. Calling this method is
+ * equivalent to getting AUDIO_PARAMETER_STREAM_INPUT_SOURCE on the legacy
+ * HAL.
+ * Optional method
+ *
+ * @return retval operation completion status.
+ * @return source audio source.
+ */
+ getAudioSource() generates (Result retval, AudioSource source);
+
+ /**
+ * Set the input gain for the audio driver.
+ * Optional method
+ *
+ * @param gain 1.0f is unity, 0.0f is zero.
+ * @result retval operation completion status.
+ */
+ setGain(float gain) generates (Result retval);
+
+ /**
+ * Commands that can be executed on the driver reader thread.
+ */
+ enum ReadCommand : int32_t {
+ READ,
+ GET_CAPTURE_POSITION
+ };
+
+ /**
+ * Data structure passed to the driver for executing commands
+ * on the driver reader thread.
+ */
+ struct ReadParameters {
+ ReadCommand command; // discriminator
+ union Params {
+ uint64_t read; // READ command, amount of bytes to read, >= 0.
+ // No parameters for GET_CAPTURE_POSITION.
+ } params;
+ };
+
+ /**
+ * Data structure passed back to the client via status message queue
+ * of 'read' operation.
+ *
+ * Possible values of 'retval' field:
+ * - OK, read operation was successful;
+ * - INVALID_ARGUMENTS, stream was not configured properly;
+ * - INVALID_STATE, stream is in a state that doesn't allow reads.
+ */
+ struct ReadStatus {
+ Result retval;
+ ReadCommand replyTo; // discriminator
+ union Reply {
+ uint64_t read; // READ command, amount of bytes read, >= 0.
+ struct CapturePosition { // same as generated by getCapturePosition.
+ uint64_t frames;
+ uint64_t time;
+ } capturePosition;
+ } reply;
+ };
+
+ /**
+ * Called when the metadata of the stream's sink has been changed.
+ * @param sinkMetadata Description of the audio that is suggested by the clients.
+ */
+ updateSinkMetadata(SinkMetadata sinkMetadata);
+
+ /**
+ * Set up required transports for receiving audio buffers from the driver.
+ *
+ * The transport consists of three message queues:
+ * -- command queue is used to instruct the reader thread what operation
+ * to perform;
+ * -- data queue is used for passing audio data from the driver
+ * to the client;
+ * -- status queue is used for reporting operation status
+ * (e.g. amount of bytes actually read or error code).
+ *
+ * The driver operates on a dedicated thread. The client must ensure that
+ * the thread is given an appropriate priority and assigned to correct
+ * scheduler and cgroup. For this purpose, the method returns identifiers
+ * of the driver thread.
+ *
+ * @param frameSize the size of a single frame, in bytes.
+ * @param framesCount the number of frames in a buffer.
+ * @param threadPriority priority of the driver thread.
+ * @return retval OK if both message queues were created successfully.
+ * INVALID_STATE if the method was already called.
+ * INVALID_ARGUMENTS if there was a problem setting up
+ * the queues.
+ * @return commandMQ a message queue used for passing commands.
+ * @return dataMQ a message queue used for passing audio data in the format
+ * specified at the stream opening.
+ * @return statusMQ a message queue used for passing status from the driver
+ * using ReadStatus structures.
+ * @return threadInfo identifiers of the driver's dedicated thread.
+ */
+ prepareForReading(uint32_t frameSize, uint32_t framesCount)
+ generates (
+ Result retval,
+ fmq_sync<ReadParameters> commandMQ,
+ fmq_sync<uint8_t> dataMQ,
+ fmq_sync<ReadStatus> statusMQ,
+ ThreadInfo threadInfo);
+
+ /**
+ * Return the amount of input frames lost in the audio driver since the last
+ * call of this function.
+ *
+ * Audio driver is expected to reset the value to 0 and restart counting
+ * upon returning the current value by this function call. Such loss
+ * typically occurs when the user space process is blocked longer than the
+ * capacity of audio driver buffers.
+ *
+ * @return framesLost the number of input audio frames lost.
+ */
+ getInputFramesLost() generates (uint32_t framesLost);
+
+ /**
+ * Return a recent count of the number of audio frames received and the
+ * clock time associated with that frame count.
+ *
+ * @return retval INVALID_STATE if the device is not ready/available,
+ * NOT_SUPPORTED if the command is not supported,
+ * OK otherwise.
+ * @return frames the total frame count received. This must be as early in
+ * the capture pipeline as possible. In general, frames
+ * must be non-negative and must not go "backwards".
+ * @return time is the clock monotonic time when frames was measured. In
+ * general, time must be a positive quantity and must not
+ * go "backwards".
+ */
+ getCapturePosition()
+ generates (Result retval, uint64_t frames, uint64_t time);
+
+ /**
+ * Returns an array with active microphones in the stream.
+ *
+ * @return retval INVALID_STATE if the call is not successful,
+ * OK otherwise.
+ *
+ * @return microphones array with microphones info
+ */
+ getActiveMicrophones()
+ generates(Result retval, vec<MicrophoneInfo> microphones);
+
+ /**
+ * Specifies the logical microphone (for processing).
+ *
+ * If the feature is not supported an error should be returned
+ * If multiple microphones are present, this should be treated as a preference
+ * for their combined direction.
+ *
+ * Optional method
+ *
+ * @param Direction constant
+ * @return retval OK if the call is successful, an error code otherwise.
+ */
+ setMicrophoneDirection(MicrophoneDirection direction)
+ generates(Result retval);
+
+ /**
+ * Specifies the zoom factor for the selected microphone (for processing).
+ *
+ * If the feature is not supported an error should be returned
+ * If multiple microphones are present, this should be treated as a preference
+ * for their combined field dimension.
+ *
+ * Optional method
+ *
+ * @param the desired field dimension of microphone capture. Range is from -1 (wide angle),
+ * though 0 (no zoom) to 1 (maximum zoom).
+ *
+ * @return retval OK if the call is not successful, an error code otherwise.
+ */
+ setMicrophoneFieldDimension(float zoom) generates(Result retval);
+};
diff --git a/audio/6.0/IStreamOut.hal b/audio/6.0/IStreamOut.hal
new file mode 100644
index 0000000..941ba61
--- /dev/null
+++ b/audio/6.0/IStreamOut.hal
@@ -0,0 +1,279 @@
+/*
+ * Copyright (C) 2019 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@6.0;
+
+import android.hardware.audio.common@6.0;
+import IStream;
+import IStreamOutCallback;
+
+interface IStreamOut extends IStream {
+ /**
+ * Return the audio hardware driver estimated latency in milliseconds.
+ *
+ * @return latencyMs latency in milliseconds.
+ */
+ getLatency() generates (uint32_t latencyMs);
+
+ /**
+ * This method is used in situations where audio mixing is done in the
+ * hardware. This method serves as a direct interface with hardware,
+ * allowing to directly set the volume as apposed to via the framework.
+ * This method might produce multiple PCM outputs or hardware accelerated
+ * codecs, such as MP3 or AAC.
+ * Optional method
+ *
+ * @param left left channel attenuation, 1.0f is unity, 0.0f is zero.
+ * @param right right channel attenuation, 1.0f is unity, 0.0f is zero.
+ * @return retval operation completion status.
+ * If a volume is outside [0,1], return INVALID_ARGUMENTS
+ */
+ setVolume(float left, float right) generates (Result retval);
+
+ /**
+ * Commands that can be executed on the driver writer thread.
+ */
+ enum WriteCommand : int32_t {
+ WRITE,
+ GET_PRESENTATION_POSITION,
+ GET_LATENCY
+ };
+
+ /**
+ * Data structure passed back to the client via status message queue
+ * of 'write' operation.
+ *
+ * Possible values of 'retval' field:
+ * - OK, write operation was successful;
+ * - INVALID_ARGUMENTS, stream was not configured properly;
+ * - INVALID_STATE, stream is in a state that doesn't allow writes;
+ * - INVALID_OPERATION, retrieving presentation position isn't supported.
+ */
+ struct WriteStatus {
+ Result retval;
+ WriteCommand replyTo; // discriminator
+ union Reply {
+ uint64_t written; // WRITE command, amount of bytes written, >= 0.
+ struct PresentationPosition { // same as generated by
+ uint64_t frames; // getPresentationPosition.
+ TimeSpec timeStamp;
+ } presentationPosition;
+ uint32_t latencyMs; // Same as generated by getLatency.
+ } reply;
+ };
+
+ /**
+ * Called when the metadata of the stream's source has been changed.
+ * @param sourceMetadata Description of the audio that is played by the clients.
+ */
+ updateSourceMetadata(SourceMetadata sourceMetadata);
+
+ /**
+ * Set up required transports for passing audio buffers to the driver.
+ *
+ * The transport consists of three message queues:
+ * -- command queue is used to instruct the writer thread what operation
+ * to perform;
+ * -- data queue is used for passing audio data from the client
+ * to the driver;
+ * -- status queue is used for reporting operation status
+ * (e.g. amount of bytes actually written or error code).
+ *
+ * The driver operates on a dedicated thread. The client must ensure that
+ * the thread is given an appropriate priority and assigned to correct
+ * scheduler and cgroup. For this purpose, the method returns identifiers
+ * of the driver thread.
+ *
+ * @param frameSize the size of a single frame, in bytes.
+ * @param framesCount the number of frames in a buffer.
+ * @return retval OK if both message queues were created successfully.
+ * INVALID_STATE if the method was already called.
+ * INVALID_ARGUMENTS if there was a problem setting up
+ * the queues.
+ * @return commandMQ a message queue used for passing commands.
+ * @return dataMQ a message queue used for passing audio data in the format
+ * specified at the stream opening.
+ * @return statusMQ a message queue used for passing status from the driver
+ * using WriteStatus structures.
+ * @return threadInfo identifiers of the driver's dedicated thread.
+ */
+ prepareForWriting(uint32_t frameSize, uint32_t framesCount)
+ generates (
+ Result retval,
+ fmq_sync<WriteCommand> commandMQ,
+ fmq_sync<uint8_t> dataMQ,
+ fmq_sync<WriteStatus> statusMQ,
+ ThreadInfo threadInfo);
+
+ /**
+ * Return the number of audio frames written by the audio DSP to DAC since
+ * the output has exited standby.
+ * Optional method
+ *
+ * @return retval operation completion status.
+ * @return dspFrames number of audio frames written.
+ */
+ getRenderPosition() generates (Result retval, uint32_t dspFrames);
+
+ /**
+ * Get the local time at which the next write to the audio driver will be
+ * presented. The units are microseconds, where the epoch is decided by the
+ * local audio HAL.
+ * Optional method
+ *
+ * @return retval operation completion status.
+ * @return timestampUs time of the next write.
+ */
+ getNextWriteTimestamp() generates (Result retval, int64_t timestampUs);
+
+ /**
+ * Set the callback interface for notifying completion of non-blocking
+ * write and drain.
+ *
+ * Calling this function implies that all future 'write' and 'drain'
+ * must be non-blocking and use the callback to signal completion.
+ *
+ * 'clearCallback' method needs to be called in order to release the local
+ * callback proxy on the server side and thus dereference the callback
+ * implementation on the client side.
+ *
+ * @return retval operation completion status.
+ */
+ setCallback(IStreamOutCallback callback) generates (Result retval);
+
+ /**
+ * Clears the callback previously set via 'setCallback' method.
+ *
+ * Warning: failure to call this method results in callback implementation
+ * on the client side being held until the HAL server termination.
+ *
+ * If no callback was previously set, the method should be a no-op
+ * and return OK.
+ *
+ * @return retval operation completion status: OK or NOT_SUPPORTED.
+ */
+ clearCallback() generates (Result retval);
+
+ /**
+ * Returns whether HAL supports pausing and resuming of streams.
+ *
+ * @return supportsPause true if pausing is supported.
+ * @return supportsResume true if resume is supported.
+ */
+ supportsPauseAndResume()
+ generates (bool supportsPause, bool supportsResume);
+
+ /**
+ * Notifies to the audio driver to stop playback however the queued buffers
+ * are retained by the hardware. Useful for implementing pause/resume. Empty
+ * implementation if not supported however must be implemented for hardware
+ * with non-trivial latency. In the pause state, some audio hardware may
+ * still be using power. Client code may consider calling 'suspend' after a
+ * timeout to prevent that excess power usage.
+ *
+ * Implementation of this function is mandatory for offloaded playback.
+ *
+ * @return retval operation completion status.
+ */
+ pause() generates (Result retval);
+
+ /**
+ * Notifies to the audio driver to resume playback following a pause.
+ * Returns error INVALID_STATE if called without matching pause.
+ *
+ * Implementation of this function is mandatory for offloaded playback.
+ *
+ * @return retval operation completion status.
+ */
+ resume() generates (Result retval);
+
+ /**
+ * Returns whether HAL supports draining of streams.
+ *
+ * @return supports true if draining is supported.
+ */
+ supportsDrain() generates (bool supports);
+
+ /**
+ * Requests notification when data buffered by the driver/hardware has been
+ * played. If 'setCallback' has previously been called to enable
+ * non-blocking mode, then 'drain' must not block, instead it must return
+ * quickly and completion of the drain is notified through the callback. If
+ * 'setCallback' has not been called, then 'drain' must block until
+ * completion.
+ *
+ * If 'type' is 'ALL', the drain completes when all previously written data
+ * has been played.
+ *
+ * If 'type' is 'EARLY_NOTIFY', the drain completes shortly before all data
+ * for the current track has played to allow time for the framework to
+ * perform a gapless track switch.
+ *
+ * Drain must return immediately on 'stop' and 'flush' calls.
+ *
+ * Implementation of this function is mandatory for offloaded playback.
+ *
+ * @param type type of drain.
+ * @return retval operation completion status.
+ */
+ drain(AudioDrain type) generates (Result retval);
+
+ /**
+ * Notifies to the audio driver to flush the queued data. Stream must
+ * already be paused before calling 'flush'.
+ * Optional method
+ *
+ * Implementation of this function is mandatory for offloaded playback.
+ *
+ * @return retval operation completion status.
+ */
+ flush() generates (Result retval);
+
+ /**
+ * Return a recent count of the number of audio frames presented to an
+ * external observer. This excludes frames which have been written but are
+ * still in the pipeline. The count is not reset to zero when output enters
+ * standby. Also returns the value of CLOCK_MONOTONIC as of this
+ * presentation count. The returned count is expected to be 'recent', but
+ * does not need to be the most recent possible value. However, the
+ * associated time must correspond to whatever count is returned.
+ *
+ * Example: assume that N+M frames have been presented, where M is a 'small'
+ * number. Then it is permissible to return N instead of N+M, and the
+ * timestamp must correspond to N rather than N+M. The terms 'recent' and
+ * 'small' are not defined. They reflect the quality of the implementation.
+ *
+ * Optional method
+ *
+ * @return retval operation completion status.
+ * @return frames count of presented audio frames.
+ * @return timeStamp associated clock time.
+ */
+ getPresentationPosition()
+ generates (Result retval, uint64_t frames, TimeSpec timeStamp);
+
+ /**
+ * Selects a presentation for decoding from a next generation media stream
+ * (as defined per ETSI TS 103 190-2) and a program within the presentation.
+ * Optional method
+ *
+ * @param presentationId selected audio presentation.
+ * @param programId refinement for the presentation.
+ * @return retval operation completion status.
+ */
+ selectPresentation(int32_t presentationId, int32_t programId)
+ generates (Result retval);
+};
diff --git a/audio/6.0/IStreamOutCallback.hal b/audio/6.0/IStreamOutCallback.hal
new file mode 100644
index 0000000..e393d9a
--- /dev/null
+++ b/audio/6.0/IStreamOutCallback.hal
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2019 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@6.0;
+
+/**
+ * Asynchronous write callback interface.
+ */
+interface IStreamOutCallback {
+ /**
+ * Non blocking write completed.
+ */
+ oneway onWriteReady();
+
+ /**
+ * Drain completed.
+ */
+ oneway onDrainReady();
+
+ /**
+ * Stream hit an error.
+ */
+ oneway onError();
+};
diff --git a/audio/6.0/config/Android.bp b/audio/6.0/config/Android.bp
new file mode 100644
index 0000000..182dfcc
--- /dev/null
+++ b/audio/6.0/config/Android.bp
@@ -0,0 +1,7 @@
+
+xsd_config {
+ name: "audio_policy_configuration_V6_0",
+ srcs: ["audio_policy_configuration.xsd"],
+ package_name: "audio.policy.configuration.V6_0",
+}
+
diff --git a/audio/6.0/config/api/current.txt b/audio/6.0/config/api/current.txt
new file mode 100644
index 0000000..7aa147c
--- /dev/null
+++ b/audio/6.0/config/api/current.txt
@@ -0,0 +1,422 @@
+// Signature format: 2.0
+package audio.policy.configuration.V6_0 {
+
+ public class AttachedDevices {
+ ctor public AttachedDevices();
+ method public java.util.List<java.lang.String> getItem();
+ }
+
+ public enum AudioDevice {
+ method public String getRawName();
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_AMBIENT;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_AUX_DIGITAL;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_BACK_MIC;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_BLUETOOTH_A2DP;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_BLUETOOTH_BLE;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_BUILTIN_MIC;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_BUS;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_COMMUNICATION;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_DEFAULT;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_ECHO_REFERENCE;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_FM_TUNER;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_HDMI;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_HDMI_ARC;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_IP;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_LINE;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_LOOPBACK;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_PROXY;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_REMOTE_SUBMIX;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_SPDIF;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_STUB;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_TELEPHONY_RX;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_TV_TUNER;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_USB_ACCESSORY;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_USB_DEVICE;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_USB_HEADSET;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_VOICE_CALL;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_WIRED_HEADSET;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_NONE;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_AUX_DIGITAL;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_AUX_LINE;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_SCO;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_BUS;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_DEFAULT;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_EARPIECE;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_ECHO_CANCELLER;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_FM;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_HDMI;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_HDMI_ARC;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_HEARING_AID;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_IP;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_LINE;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_PROXY;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_SPDIF;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_SPEAKER;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_SPEAKER_SAFE;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_STUB;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_TELEPHONY_TX;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_USB_ACCESSORY;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_USB_DEVICE;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_USB_HEADSET;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_WIRED_HEADSET;
+ }
+
+ public enum AudioFormat {
+ method public String getRawName();
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADIF;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADTS;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_ELD;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_ERLC;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_HE_V1;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_HE_V2;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_LC;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_LD;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_LTP;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_MAIN;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_SCALABLE;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_SSR;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_XHE;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ELD;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ERLC;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_HE_V1;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_HE_V2;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_LATM;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_LATM_HE_V1;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_LATM_HE_V2;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_LATM_LC;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_LC;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_LD;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_LTP;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_MAIN;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_SCALABLE;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_SSR;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_XHE;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AC3;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AC4;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_ALAC;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AMR_NB;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AMR_WB;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AMR_WB_PLUS;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_APE;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_APTX;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_APTX_ADAPTIVE;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_APTX_HD;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_APTX_TWSP;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_CELT;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_DOLBY_TRUEHD;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_DSD;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_DTS;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_DTS_HD;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_EVRC;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_EVRCB;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_EVRCNW;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_EVRCWB;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_E_AC3;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_E_AC3_JOC;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_FLAC;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_HE_AAC_V1;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_HE_AAC_V2;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_IEC61937;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_LDAC;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_LHDC;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_LHDC_LL;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_MAT_1_0;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_MAT_2_0;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_MAT_2_1;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_MP2;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_MP3;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_OPUS;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_PCM_16_BIT;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_PCM_24_BIT_PACKED;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_PCM_32_BIT;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_PCM_8_24_BIT;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_PCM_8_BIT;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_PCM_FLOAT;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_QCELP;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_SBC;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_VORBIS;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_WMA;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_WMA_PRO;
+ }
+
+ public class AudioPolicyConfiguration {
+ ctor public AudioPolicyConfiguration();
+ method public audio.policy.configuration.V6_0.GlobalConfiguration getGlobalConfiguration();
+ method public java.util.List<audio.policy.configuration.V6_0.Modules> getModules();
+ method public audio.policy.configuration.V6_0.SurroundSound getSurroundSound();
+ method public audio.policy.configuration.V6_0.Version getVersion();
+ method public java.util.List<audio.policy.configuration.V6_0.Volumes> getVolumes();
+ method public void setGlobalConfiguration(audio.policy.configuration.V6_0.GlobalConfiguration);
+ method public void setSurroundSound(audio.policy.configuration.V6_0.SurroundSound);
+ method public void setVersion(audio.policy.configuration.V6_0.Version);
+ }
+
+ public enum AudioUsage {
+ method public String getRawName();
+ enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_ALARM;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_ASSISTANCE_SONIFICATION;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_ASSISTANT;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_GAME;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_MEDIA;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_NOTIFICATION;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_UNKNOWN;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_VIRTUAL_SOURCE;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_VOICE_COMMUNICATION;
+ enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING;
+ }
+
+ public enum DeviceCategory {
+ method public String getRawName();
+ enum_constant public static final audio.policy.configuration.V6_0.DeviceCategory DEVICE_CATEGORY_EARPIECE;
+ enum_constant public static final audio.policy.configuration.V6_0.DeviceCategory DEVICE_CATEGORY_EXT_MEDIA;
+ enum_constant public static final audio.policy.configuration.V6_0.DeviceCategory DEVICE_CATEGORY_HEADSET;
+ enum_constant public static final audio.policy.configuration.V6_0.DeviceCategory DEVICE_CATEGORY_HEARING_AID;
+ enum_constant public static final audio.policy.configuration.V6_0.DeviceCategory DEVICE_CATEGORY_SPEAKER;
+ }
+
+ public class DevicePorts {
+ ctor public DevicePorts();
+ method public java.util.List<audio.policy.configuration.V6_0.DevicePorts.DevicePort> getDevicePort();
+ }
+
+ public static class DevicePorts.DevicePort {
+ ctor public DevicePorts.DevicePort();
+ method public String getAddress();
+ method public java.util.List<audio.policy.configuration.V6_0.AudioFormat> getEncodedFormats();
+ method public audio.policy.configuration.V6_0.Gains getGains();
+ method public java.util.List<audio.policy.configuration.V6_0.Profile> getProfile();
+ method public audio.policy.configuration.V6_0.Role getRole();
+ method public String getTagName();
+ method public String getType();
+ method public boolean get_default();
+ method public void setAddress(String);
+ method public void setEncodedFormats(java.util.List<audio.policy.configuration.V6_0.AudioFormat>);
+ method public void setGains(audio.policy.configuration.V6_0.Gains);
+ method public void setRole(audio.policy.configuration.V6_0.Role);
+ method public void setTagName(String);
+ method public void setType(String);
+ method public void set_default(boolean);
+ }
+
+ public enum GainMode {
+ method public String getRawName();
+ enum_constant public static final audio.policy.configuration.V6_0.GainMode AUDIO_GAIN_MODE_CHANNELS;
+ enum_constant public static final audio.policy.configuration.V6_0.GainMode AUDIO_GAIN_MODE_JOINT;
+ enum_constant public static final audio.policy.configuration.V6_0.GainMode AUDIO_GAIN_MODE_RAMP;
+ }
+
+ public class Gains {
+ ctor public Gains();
+ method public java.util.List<audio.policy.configuration.V6_0.Gains.Gain> getGain();
+ }
+
+ public static class Gains.Gain {
+ ctor public Gains.Gain();
+ method public String getChannel_mask();
+ method public int getDefaultValueMB();
+ method public int getMaxRampMs();
+ method public int getMaxValueMB();
+ method public int getMinRampMs();
+ method public int getMinValueMB();
+ method public audio.policy.configuration.V6_0.GainMode getMode();
+ method public String getName();
+ method public int getStepValueMB();
+ method public void setChannel_mask(String);
+ method public void setDefaultValueMB(int);
+ method public void setMaxRampMs(int);
+ method public void setMaxValueMB(int);
+ method public void setMinRampMs(int);
+ method public void setMinValueMB(int);
+ method public void setMode(audio.policy.configuration.V6_0.GainMode);
+ method public void setName(String);
+ method public void setStepValueMB(int);
+ }
+
+ public class GlobalConfiguration {
+ ctor public GlobalConfiguration();
+ method public boolean getSpeaker_drc_enabled();
+ method public void setSpeaker_drc_enabled(boolean);
+ }
+
+ public enum HalVersion {
+ method public String getRawName();
+ enum_constant public static final audio.policy.configuration.V6_0.HalVersion _2_0;
+ enum_constant public static final audio.policy.configuration.V6_0.HalVersion _3_0;
+ }
+
+ public class MixPorts {
+ ctor public MixPorts();
+ method public java.util.List<audio.policy.configuration.V6_0.MixPorts.MixPort> getMixPort();
+ }
+
+ public static class MixPorts.MixPort {
+ ctor public MixPorts.MixPort();
+ method public String getFlags();
+ method public audio.policy.configuration.V6_0.Gains getGains();
+ method public long getMaxActiveCount();
+ method public long getMaxOpenCount();
+ method public String getName();
+ method public java.util.List<audio.policy.configuration.V6_0.AudioUsage> getPreferredUsage();
+ method public java.util.List<audio.policy.configuration.V6_0.Profile> getProfile();
+ method public audio.policy.configuration.V6_0.Role getRole();
+ method public void setFlags(String);
+ method public void setGains(audio.policy.configuration.V6_0.Gains);
+ method public void setMaxActiveCount(long);
+ method public void setMaxOpenCount(long);
+ method public void setName(String);
+ method public void setPreferredUsage(java.util.List<audio.policy.configuration.V6_0.AudioUsage>);
+ method public void setRole(audio.policy.configuration.V6_0.Role);
+ }
+
+ public enum MixType {
+ method public String getRawName();
+ enum_constant public static final audio.policy.configuration.V6_0.MixType mix;
+ enum_constant public static final audio.policy.configuration.V6_0.MixType mux;
+ }
+
+ public class Modules {
+ ctor public Modules();
+ method public java.util.List<audio.policy.configuration.V6_0.Modules.Module> getModule();
+ }
+
+ public static class Modules.Module {
+ ctor public Modules.Module();
+ method public audio.policy.configuration.V6_0.AttachedDevices getAttachedDevices();
+ method public String getDefaultOutputDevice();
+ method public audio.policy.configuration.V6_0.DevicePorts getDevicePorts();
+ method public audio.policy.configuration.V6_0.HalVersion getHalVersion();
+ method public audio.policy.configuration.V6_0.MixPorts getMixPorts();
+ method public String getName();
+ method public audio.policy.configuration.V6_0.Routes getRoutes();
+ method public void setAttachedDevices(audio.policy.configuration.V6_0.AttachedDevices);
+ method public void setDefaultOutputDevice(String);
+ method public void setDevicePorts(audio.policy.configuration.V6_0.DevicePorts);
+ method public void setHalVersion(audio.policy.configuration.V6_0.HalVersion);
+ method public void setMixPorts(audio.policy.configuration.V6_0.MixPorts);
+ method public void setName(String);
+ method public void setRoutes(audio.policy.configuration.V6_0.Routes);
+ }
+
+ public class Profile {
+ ctor public Profile();
+ method public String getChannelMasks();
+ method public String getFormat();
+ method public String getName();
+ method public String getSamplingRates();
+ method public void setChannelMasks(String);
+ method public void setFormat(String);
+ method public void setName(String);
+ method public void setSamplingRates(String);
+ }
+
+ public class Reference {
+ ctor public Reference();
+ method public String getName();
+ method public java.util.List<java.lang.String> getPoint();
+ method public void setName(String);
+ }
+
+ public enum Role {
+ method public String getRawName();
+ enum_constant public static final audio.policy.configuration.V6_0.Role sink;
+ enum_constant public static final audio.policy.configuration.V6_0.Role source;
+ }
+
+ public class Routes {
+ ctor public Routes();
+ method public java.util.List<audio.policy.configuration.V6_0.Routes.Route> getRoute();
+ }
+
+ public static class Routes.Route {
+ ctor public Routes.Route();
+ method public String getSink();
+ method public String getSources();
+ method public audio.policy.configuration.V6_0.MixType getType();
+ method public void setSink(String);
+ method public void setSources(String);
+ method public void setType(audio.policy.configuration.V6_0.MixType);
+ }
+
+ public enum Stream {
+ method public String getRawName();
+ enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_ACCESSIBILITY;
+ enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_ALARM;
+ enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_BLUETOOTH_SCO;
+ enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_DTMF;
+ enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_ENFORCED_AUDIBLE;
+ enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_MUSIC;
+ enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_NOTIFICATION;
+ enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_PATCH;
+ enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_REROUTING;
+ enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_RING;
+ enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_SYSTEM;
+ enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_TTS;
+ enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_VOICE_CALL;
+ }
+
+ public class SurroundFormats {
+ ctor public SurroundFormats();
+ method public java.util.List<audio.policy.configuration.V6_0.SurroundFormats.Format> getFormat();
+ }
+
+ public static class SurroundFormats.Format {
+ ctor public SurroundFormats.Format();
+ method public audio.policy.configuration.V6_0.AudioFormat getName();
+ method public java.util.List<audio.policy.configuration.V6_0.AudioFormat> getSubformats();
+ method public void setName(audio.policy.configuration.V6_0.AudioFormat);
+ method public void setSubformats(java.util.List<audio.policy.configuration.V6_0.AudioFormat>);
+ }
+
+ public class SurroundSound {
+ ctor public SurroundSound();
+ method public audio.policy.configuration.V6_0.SurroundFormats getFormats();
+ method public void setFormats(audio.policy.configuration.V6_0.SurroundFormats);
+ }
+
+ public enum Version {
+ method public String getRawName();
+ enum_constant public static final audio.policy.configuration.V6_0.Version _1_0;
+ }
+
+ public class Volume {
+ ctor public Volume();
+ method public audio.policy.configuration.V6_0.DeviceCategory getDeviceCategory();
+ method public java.util.List<java.lang.String> getPoint();
+ method public String getRef();
+ method public audio.policy.configuration.V6_0.Stream getStream();
+ method public void setDeviceCategory(audio.policy.configuration.V6_0.DeviceCategory);
+ method public void setRef(String);
+ method public void setStream(audio.policy.configuration.V6_0.Stream);
+ }
+
+ public class Volumes {
+ ctor public Volumes();
+ method public java.util.List<audio.policy.configuration.V6_0.Reference> getReference();
+ method public java.util.List<audio.policy.configuration.V6_0.Volume> getVolume();
+ }
+
+ public class XmlParser {
+ ctor public XmlParser();
+ method public static audio.policy.configuration.V6_0.AudioPolicyConfiguration read(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public static String readText(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public static void skip(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ }
+
+}
+
diff --git a/audio/6.0/config/api/last_current.txt b/audio/6.0/config/api/last_current.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/audio/6.0/config/api/last_current.txt
diff --git a/audio/6.0/config/api/last_removed.txt b/audio/6.0/config/api/last_removed.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/audio/6.0/config/api/last_removed.txt
diff --git a/audio/6.0/config/api/removed.txt b/audio/6.0/config/api/removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/audio/6.0/config/api/removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/audio/6.0/config/audio_policy_configuration.xsd b/audio/6.0/config/audio_policy_configuration.xsd
new file mode 100644
index 0000000..0dc89bb
--- /dev/null
+++ b/audio/6.0/config/audio_policy_configuration.xsd
@@ -0,0 +1,624 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2019 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.
+-->
+<!-- TODO: define a targetNamespace. Note that it will break retrocompatibility -->
+<xs:schema version="2.0"
+ elementFormDefault="qualified"
+ attributeFormDefault="unqualified"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <!-- List the config versions supported by audio policy. -->
+ <xs:simpleType name="version">
+ <xs:restriction base="xs:decimal">
+ <xs:enumeration value="1.0"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="halVersion">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ Version of the interface the hal implements.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:restriction base="xs:decimal">
+ <!-- List of HAL versions supported by the framework. -->
+ <xs:enumeration value="2.0"/>
+ <xs:enumeration value="3.0"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:element name="audioPolicyConfiguration">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="globalConfiguration" type="globalConfiguration"/>
+ <xs:element name="modules" type="modules" maxOccurs="unbounded"/>
+ <xs:element name="volumes" type="volumes" maxOccurs="unbounded"/>
+ <xs:element name="surroundSound" type="surroundSound" minOccurs="0" />
+ </xs:sequence>
+ <xs:attribute name="version" type="version"/>
+ </xs:complexType>
+ <xs:key name="moduleNameKey">
+ <xs:selector xpath="modules/module"/>
+ <xs:field xpath="@name"/>
+ </xs:key>
+ <xs:unique name="volumeTargetUniqueness">
+ <xs:selector xpath="volumes/volume"/>
+ <xs:field xpath="@stream"/>
+ <xs:field xpath="@deviceCategory"/>
+ </xs:unique>
+ <xs:key name="volumeCurveNameKey">
+ <xs:selector xpath="volumes/reference"/>
+ <xs:field xpath="@name"/>
+ </xs:key>
+ <xs:keyref name="volumeCurveRef" refer="volumeCurveNameKey">
+ <xs:selector xpath="volumes/volume"/>
+ <xs:field xpath="@ref"/>
+ </xs:keyref>
+ </xs:element>
+ <xs:complexType name="globalConfiguration">
+ <xs:attribute name="speaker_drc_enabled" type="xs:boolean" use="required"/>
+ </xs:complexType>
+ <xs:complexType name="modules">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ There should be one section per audio HW module present on the platform.
+ Each <module/> contains two mandatory tags: “halVersion” and “name”.
+ The module "name" is the same as in previous .conf file.
+ Each module must contain the following sections:
+ - <devicePorts/>: a list of device descriptors for all
+ input and output devices accessible via this module.
+ This contains both permanently attached devices and removable devices.
+ - <mixPorts/>: listing all output and input streams exposed by the audio HAL
+ - <routes/>: list of possible connections between input
+ and output devices or between stream and devices.
+ A <route/> is defined by a set of 3 attributes:
+ -"type": mux|mix means all sources are mutual exclusive (mux) or can be mixed (mix)
+ -"sink": the sink involved in this route
+ -"sources": all the sources than can be connected to the sink via this route
+ - <attachedDevices/>: permanently attached devices.
+ The attachedDevices section is a list of devices names.
+ Their names correspond to device names defined in "devicePorts" section.
+ - <defaultOutputDevice/> is the device to be used when no policy rule applies
+ </xs:documentation>
+ </xs:annotation>
+ <xs:sequence>
+ <xs:element name="module" maxOccurs="unbounded">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="attachedDevices" type="attachedDevices" minOccurs="0">
+ <xs:unique name="attachedDevicesUniqueness">
+ <xs:selector xpath="item"/>
+ <xs:field xpath="."/>
+ </xs:unique>
+ </xs:element>
+ <xs:element name="defaultOutputDevice" type="xs:token" minOccurs="0"/>
+ <xs:element name="mixPorts" type="mixPorts" minOccurs="0"/>
+ <xs:element name="devicePorts" type="devicePorts" minOccurs="0"/>
+ <xs:element name="routes" type="routes" minOccurs="0"/>
+ </xs:sequence>
+ <xs:attribute name="name" type="xs:string" use="required"/>
+ <xs:attribute name="halVersion" type="halVersion" use="required"/>
+ </xs:complexType>
+ <xs:unique name="mixPortNameUniqueness">
+ <xs:selector xpath="mixPorts/mixPort"/>
+ <xs:field xpath="@name"/>
+ </xs:unique>
+ <xs:key name="devicePortNameKey">
+ <xs:selector xpath="devicePorts/devicePort"/>
+ <xs:field xpath="@tagName"/>
+ </xs:key>
+ <xs:unique name="devicePortUniqueness">
+ <xs:selector xpath="devicePorts/devicePort"/>
+ <xs:field xpath="@type"/>
+ <xs:field xpath="@address"/>
+ </xs:unique>
+ <xs:keyref name="defaultOutputDeviceRef" refer="devicePortNameKey">
+ <xs:selector xpath="defaultOutputDevice"/>
+ <xs:field xpath="."/>
+ </xs:keyref>
+ <xs:keyref name="attachedDeviceRef" refer="devicePortNameKey">
+ <xs:selector xpath="attachedDevices/item"/>
+ <xs:field xpath="."/>
+ </xs:keyref>
+ <!-- The following 3 constraints try to make sure each sink port
+ is reference in one an only one route. -->
+ <xs:key name="routeSinkKey">
+ <!-- predicate [@type='sink'] does not work in xsd 1.0 -->
+ <xs:selector xpath="devicePorts/devicePort|mixPorts/mixPort"/>
+ <xs:field xpath="@tagName|@name"/>
+ </xs:key>
+ <xs:keyref name="routeSinkRef" refer="routeSinkKey">
+ <xs:selector xpath="routes/route"/>
+ <xs:field xpath="@sink"/>
+ </xs:keyref>
+ <xs:unique name="routeUniqueness">
+ <xs:selector xpath="routes/route"/>
+ <xs:field xpath="@sink"/>
+ </xs:unique>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="attachedDevices">
+ <xs:sequence>
+ <xs:element name="item" type="xs:token" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ <!-- TODO: separate values by space for better xsd validations. -->
+ <xs:simpleType name="audioInOutFlags">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ "|" separated list of audio_output_flags_t or audio_input_flags_t.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:restriction base="xs:string">
+ <xs:pattern value="|[_A-Z]+(\|[_A-Z]+)*"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="role">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="sink"/>
+ <xs:enumeration value="source"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:complexType name="mixPorts">
+ <xs:sequence>
+ <xs:element name="mixPort" minOccurs="0" maxOccurs="unbounded">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="profile" type="profile" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element name="gains" type="gains" minOccurs="0"/>
+ </xs:sequence>
+ <xs:attribute name="name" type="xs:token" use="required"/>
+ <xs:attribute name="role" type="role" use="required"/>
+ <xs:attribute name="flags" type="audioInOutFlags"/>
+ <xs:attribute name="maxOpenCount" type="xs:unsignedInt"/>
+ <xs:attribute name="maxActiveCount" type="xs:unsignedInt"/>
+ <xs:attribute name="preferredUsage" type="audioUsageList">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ When choosing the mixPort of an audio track, the audioPolicy
+ first considers the mixPorts with a preferredUsage including
+ the track AudioUsage preferred .
+ If non support the track format, the other mixPorts are considered.
+ Eg: a <mixPort preferredUsage="AUDIO_USAGE_MEDIA" /> will receive
+ the audio of all apps playing with a MEDIA usage.
+ It may receive audio from ALARM if there are no audio compatible
+ <mixPort preferredUsage="AUDIO_USAGE_ALARM" />.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+ <xs:unique name="mixPortProfileUniqueness">
+ <xs:selector xpath="profile"/>
+ <xs:field xpath="format"/>
+ <xs:field xpath="samplingRate"/>
+ <xs:field xpath="channelMasks"/>
+ </xs:unique>
+ <xs:unique name="mixPortGainUniqueness">
+ <xs:selector xpath="gains/gain"/>
+ <xs:field xpath="@name"/>
+ </xs:unique>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ <!-- Enum values of audio_device_t in audio.h
+ TODO: generate from hidl to avoid manual sync.
+ TODO: separate source and sink in the xml for better xsd validations. -->
+ <xs:simpleType name="audioDevice">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="AUDIO_DEVICE_NONE"/>
+
+ <xs:enumeration value="AUDIO_DEVICE_OUT_EARPIECE"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_SPEAKER"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_WIRED_HEADSET"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_WIRED_HEADPHONE"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_SCO"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_AUX_DIGITAL"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_HDMI"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_USB_ACCESSORY"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_USB_DEVICE"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_REMOTE_SUBMIX"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_TELEPHONY_TX"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_LINE"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_HDMI_ARC"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_SPDIF"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_FM"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_AUX_LINE"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_SPEAKER_SAFE"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_IP"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_BUS"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_PROXY"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_USB_HEADSET"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_HEARING_AID"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_ECHO_CANCELLER"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_DEFAULT"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_STUB"/>
+
+ <!-- Due to the xml format, IN types can not be a separated from OUT types -->
+ <xs:enumeration value="AUDIO_DEVICE_IN_COMMUNICATION"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_AMBIENT"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_BUILTIN_MIC"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_WIRED_HEADSET"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_AUX_DIGITAL"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_HDMI"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_VOICE_CALL"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_TELEPHONY_RX"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_BACK_MIC"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_REMOTE_SUBMIX"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_USB_ACCESSORY"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_USB_DEVICE"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_FM_TUNER"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_TV_TUNER"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_LINE"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_SPDIF"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_BLUETOOTH_A2DP"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_LOOPBACK"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_IP"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_BUS"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_PROXY"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_USB_HEADSET"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_BLUETOOTH_BLE"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_HDMI_ARC"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_ECHO_REFERENCE"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_DEFAULT"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_STUB"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="vendorExtension">
+ <!-- Vendor extension names must be prefixed by "VX_" to distinguish them from AOSP values.
+ Vendor are encouraged to namespace their module names to avoid conflicts.
+ Example for an hypothetical Google virtual reality device:
+ <devicePort tagName="VR" type="VX_GOOGLE_VR" role="sink">
+ -->
+ <xs:restriction base="xs:string">
+ <xs:pattern value="VX_[_a-zA-Z0-9]+"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="extendableAudioDevice">
+ <xs:union memberTypes="audioDevice vendorExtension"/>
+ </xs:simpleType>
+ <!-- Enum values of audio_format_t in audio.h
+ TODO: generate from hidl to avoid manual sync. -->
+ <xs:simpleType name="audioFormat">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="AUDIO_FORMAT_PCM_16_BIT" />
+ <xs:enumeration value="AUDIO_FORMAT_PCM_8_BIT"/>
+ <xs:enumeration value="AUDIO_FORMAT_PCM_32_BIT"/>
+ <xs:enumeration value="AUDIO_FORMAT_PCM_8_24_BIT"/>
+ <xs:enumeration value="AUDIO_FORMAT_PCM_FLOAT"/>
+ <xs:enumeration value="AUDIO_FORMAT_PCM_24_BIT_PACKED"/>
+ <xs:enumeration value="AUDIO_FORMAT_MP3"/>
+ <xs:enumeration value="AUDIO_FORMAT_AMR_NB"/>
+ <xs:enumeration value="AUDIO_FORMAT_AMR_WB"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_MAIN"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_LC"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_SSR"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_LTP"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_HE_V1"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_SCALABLE"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_ERLC"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_LD"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_HE_V2"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_ELD"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_MAIN"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_LC"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_SSR"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_LTP"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_HE_V1"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_SCALABLE"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_ERLC"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_LD"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_HE_V2"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_ELD"/>
+ <xs:enumeration value="AUDIO_FORMAT_VORBIS"/>
+ <xs:enumeration value="AUDIO_FORMAT_HE_AAC_V1"/>
+ <xs:enumeration value="AUDIO_FORMAT_HE_AAC_V2"/>
+ <xs:enumeration value="AUDIO_FORMAT_OPUS"/>
+ <xs:enumeration value="AUDIO_FORMAT_AC3"/>
+ <xs:enumeration value="AUDIO_FORMAT_E_AC3"/>
+ <xs:enumeration value="AUDIO_FORMAT_DTS"/>
+ <xs:enumeration value="AUDIO_FORMAT_DTS_HD"/>
+ <xs:enumeration value="AUDIO_FORMAT_IEC61937"/>
+ <xs:enumeration value="AUDIO_FORMAT_DOLBY_TRUEHD"/>
+ <xs:enumeration value="AUDIO_FORMAT_EVRC"/>
+ <xs:enumeration value="AUDIO_FORMAT_EVRCB"/>
+ <xs:enumeration value="AUDIO_FORMAT_EVRCWB"/>
+ <xs:enumeration value="AUDIO_FORMAT_EVRCNW"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_ADIF"/>
+ <xs:enumeration value="AUDIO_FORMAT_WMA"/>
+ <xs:enumeration value="AUDIO_FORMAT_WMA_PRO"/>
+ <xs:enumeration value="AUDIO_FORMAT_AMR_WB_PLUS"/>
+ <xs:enumeration value="AUDIO_FORMAT_MP2"/>
+ <xs:enumeration value="AUDIO_FORMAT_QCELP"/>
+ <xs:enumeration value="AUDIO_FORMAT_DSD"/>
+ <xs:enumeration value="AUDIO_FORMAT_FLAC"/>
+ <xs:enumeration value="AUDIO_FORMAT_ALAC"/>
+ <xs:enumeration value="AUDIO_FORMAT_APE"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS"/>
+ <xs:enumeration value="AUDIO_FORMAT_SBC"/>
+ <xs:enumeration value="AUDIO_FORMAT_APTX"/>
+ <xs:enumeration value="AUDIO_FORMAT_APTX_HD"/>
+ <xs:enumeration value="AUDIO_FORMAT_AC4"/>
+ <xs:enumeration value="AUDIO_FORMAT_LDAC"/>
+ <xs:enumeration value="AUDIO_FORMAT_E_AC3_JOC"/>
+ <xs:enumeration value="AUDIO_FORMAT_MAT_1_0"/>
+ <xs:enumeration value="AUDIO_FORMAT_MAT_2_0"/>
+ <xs:enumeration value="AUDIO_FORMAT_MAT_2_1"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_XHE"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_XHE"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_LATM"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_LATM_LC"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_LATM_HE_V1"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_LATM_HE_V2"/>
+ <xs:enumeration value="AUDIO_FORMAT_CELT"/>
+ <xs:enumeration value="AUDIO_FORMAT_APTX_ADAPTIVE"/>
+ <xs:enumeration value="AUDIO_FORMAT_LHDC"/>
+ <xs:enumeration value="AUDIO_FORMAT_LHDC_LL"/>
+ <xs:enumeration value="AUDIO_FORMAT_APTX_TWSP"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="extendableAudioFormat">
+ <xs:union memberTypes="audioFormat vendorExtension"/>
+ </xs:simpleType>
+ <!-- Enum values of audio::common::4_0::AudioUsage
+ TODO: generate from HIDL to avoid manual sync. -->
+ <xs:simpleType name="audioUsage">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="AUDIO_USAGE_UNKNOWN" />
+ <xs:enumeration value="AUDIO_USAGE_MEDIA" />
+ <xs:enumeration value="AUDIO_USAGE_VOICE_COMMUNICATION" />
+ <xs:enumeration value="AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING" />
+ <xs:enumeration value="AUDIO_USAGE_ALARM" />
+ <xs:enumeration value="AUDIO_USAGE_NOTIFICATION" />
+ <xs:enumeration value="AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE" />
+ <xs:enumeration value="AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY" />
+ <xs:enumeration value="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE" />
+ <xs:enumeration value="AUDIO_USAGE_ASSISTANCE_SONIFICATION" />
+ <xs:enumeration value="AUDIO_USAGE_GAME" />
+ <xs:enumeration value="AUDIO_USAGE_VIRTUAL_SOURCE" />
+ <xs:enumeration value="AUDIO_USAGE_ASSISTANT" />
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="audioUsageList">
+ <xs:list itemType="audioUsage"/>
+ </xs:simpleType>
+ <!-- TODO: Change to a space separated list to xsd enforce correctness. -->
+ <xs:simpleType name="samplingRates">
+ <xs:restriction base="xs:string">
+ <xs:pattern value="[0-9]+(,[0-9]+)*"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <!-- TODO: Change to a space separated list to xsd enforce correctness. -->
+ <xs:simpleType name="channelMask">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ Comma (",") separated list of channel flags
+ from audio_channel_mask_t.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:restriction base="xs:string">
+ <xs:pattern value="[_A-Z][_A-Z0-9]*(,[_A-Z][_A-Z0-9]*)*"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:complexType name="profile">
+ <xs:attribute name="name" type="xs:token" use="optional"/>
+ <xs:attribute name="format" type="extendableAudioFormat" use="optional"/>
+ <xs:attribute name="samplingRates" type="samplingRates" use="optional"/>
+ <xs:attribute name="channelMasks" type="channelMask" use="optional"/>
+ </xs:complexType>
+ <xs:simpleType name="gainMode">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="AUDIO_GAIN_MODE_JOINT"/>
+ <xs:enumeration value="AUDIO_GAIN_MODE_CHANNELS"/>
+ <xs:enumeration value="AUDIO_GAIN_MODE_RAMP"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:complexType name="gains">
+ <xs:sequence>
+ <xs:element name="gain" minOccurs="0" maxOccurs="unbounded">
+ <xs:complexType>
+ <xs:attribute name="name" type="xs:token" use="required"/>
+ <xs:attribute name="mode" type="gainMode" use="required"/>
+ <xs:attribute name="channel_mask" type="channelMask" use="optional"/>
+ <xs:attribute name="minValueMB" type="xs:int" use="optional"/>
+ <xs:attribute name="maxValueMB" type="xs:int" use="optional"/>
+ <xs:attribute name="defaultValueMB" type="xs:int" use="optional"/>
+ <xs:attribute name="stepValueMB" type="xs:int" use="optional"/>
+ <xs:attribute name="minRampMs" type="xs:int" use="optional"/>
+ <xs:attribute name="maxRampMs" type="xs:int" use="optional"/>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="devicePorts">
+ <xs:sequence>
+ <xs:element name="devicePort" minOccurs="0" maxOccurs="unbounded">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="profile" type="profile" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element name="gains" type="gains" minOccurs="0"/>
+ </xs:sequence>
+ <xs:attribute name="tagName" type="xs:token" use="required"/>
+ <xs:attribute name="type" type="extendableAudioDevice" use="required"/>
+ <xs:attribute name="role" type="role" use="required"/>
+ <xs:attribute name="address" type="xs:string" use="optional" default=""/>
+ <!-- Note that XSD 1.0 can not check that a type only has one default. -->
+ <xs:attribute name="default" type="xs:boolean" use="optional">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ The default device will be used if multiple have the same type
+ and no explicit route request exists for a specific device of
+ that type.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="encodedFormats" type="audioFormatsList" use="optional"
+ default="" />
+ </xs:complexType>
+ <xs:unique name="devicePortProfileUniqueness">
+ <xs:selector xpath="profile"/>
+ <xs:field xpath="format"/>
+ <xs:field xpath="samplingRate"/>
+ <xs:field xpath="channelMasks"/>
+ </xs:unique>
+ <xs:unique name="devicePortGainUniqueness">
+ <xs:selector xpath="gains/gain"/>
+ <xs:field xpath="@name"/>
+ </xs:unique>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:simpleType name="mixType">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="mix"/>
+ <xs:enumeration value="mux"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:complexType name="routes">
+ <xs:sequence>
+ <xs:element name="route" minOccurs="0" maxOccurs="unbounded">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ List all available sources for a given sink.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:attribute name="type" type="mixType" use="required"/>
+ <xs:attribute name="sink" type="xs:string" use="required"/>
+ <xs:attribute name="sources" type="xs:string" use="required"/>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="volumes">
+ <xs:sequence>
+ <xs:element name="volume" type="volume" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element name="reference" type="reference" minOccurs="0" maxOccurs="unbounded">
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ <!-- TODO: Always require a ref for better xsd validations.
+ Currently a volume could have no points nor ref
+ as it can not be forbidden by xsd 1.0.-->
+ <xs:simpleType name="volumePoint">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ Comma separated pair of number.
+ The fist one is the framework level (between 0 and 100).
+ The second one is the volume to send to the HAL.
+ The framework will interpolate volumes not specified.
+ Their MUST be at least 2 points specified.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:restriction base="xs:string">
+ <xs:pattern value="([0-9]{1,2}|100),-?[0-9]+"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <!-- Enum values of audio_stream_type_t in audio-base.h
+ TODO: generate from hidl to avoid manual sync. -->
+ <xs:simpleType name="stream">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="AUDIO_STREAM_VOICE_CALL"/>
+ <xs:enumeration value="AUDIO_STREAM_SYSTEM"/>
+ <xs:enumeration value="AUDIO_STREAM_RING"/>
+ <xs:enumeration value="AUDIO_STREAM_MUSIC"/>
+ <xs:enumeration value="AUDIO_STREAM_ALARM"/>
+ <xs:enumeration value="AUDIO_STREAM_NOTIFICATION"/>
+ <xs:enumeration value="AUDIO_STREAM_BLUETOOTH_SCO"/>
+ <xs:enumeration value="AUDIO_STREAM_ENFORCED_AUDIBLE"/>
+ <xs:enumeration value="AUDIO_STREAM_DTMF"/>
+ <xs:enumeration value="AUDIO_STREAM_TTS"/>
+ <xs:enumeration value="AUDIO_STREAM_ACCESSIBILITY"/>
+ <xs:enumeration value="AUDIO_STREAM_REROUTING"/>
+ <xs:enumeration value="AUDIO_STREAM_PATCH"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <!-- Enum values of device_category from Volume.h.
+ TODO: generate from hidl to avoid manual sync. -->
+ <xs:simpleType name="deviceCategory">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="DEVICE_CATEGORY_HEADSET"/>
+ <xs:enumeration value="DEVICE_CATEGORY_SPEAKER"/>
+ <xs:enumeration value="DEVICE_CATEGORY_EARPIECE"/>
+ <xs:enumeration value="DEVICE_CATEGORY_EXT_MEDIA"/>
+ <xs:enumeration value="DEVICE_CATEGORY_HEARING_AID"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:complexType name="volume">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ Volume section defines a volume curve for a given use case and device category.
+ It contains a list of points of this curve expressing the attenuation in Millibels
+ for a given volume index from 0 to 100.
+ <volume stream="AUDIO_STREAM_MUSIC" deviceCategory="DEVICE_CATEGORY_SPEAKER">
+ <point>0,-9600</point>
+ <point>100,0</point>
+ </volume>
+
+ It may also reference a reference/@name to avoid duplicating curves.
+ <volume stream="AUDIO_STREAM_MUSIC" deviceCategory="DEVICE_CATEGORY_SPEAKER"
+ ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+ <reference name="DEFAULT_MEDIA_VOLUME_CURVE">
+ <point>0,-9600</point>
+ <point>100,0</point>
+ </reference>
+ </xs:documentation>
+ </xs:annotation>
+ <xs:sequence>
+ <xs:element name="point" type="volumePoint" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:attribute name="stream" type="stream"/>
+ <xs:attribute name="deviceCategory" type="deviceCategory"/>
+ <xs:attribute name="ref" type="xs:token" use="optional"/>
+ </xs:complexType>
+ <xs:complexType name="reference">
+ <xs:sequence>
+ <xs:element name="point" type="volumePoint" minOccurs="2" maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:attribute name="name" type="xs:token" use="required"/>
+ </xs:complexType>
+ <xs:complexType name="surroundSound">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ Surround Sound section provides configuration related to handling of
+ multi-channel formats.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:sequence>
+ <xs:element name="formats" type="surroundFormats"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:simpleType name="audioFormatsList">
+ <xs:list itemType="audioFormat" />
+ </xs:simpleType>
+ <xs:complexType name="surroundFormats">
+ <xs:sequence>
+ <xs:element name="format" minOccurs="0" maxOccurs="unbounded">
+ <xs:complexType>
+ <xs:attribute name="name" type="audioFormat" use="required"/>
+ <xs:attribute name="subformats" type="audioFormatsList" />
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+</xs:schema>
diff --git a/audio/6.0/types.hal b/audio/6.0/types.hal
new file mode 100644
index 0000000..1a704f8
--- /dev/null
+++ b/audio/6.0/types.hal
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2019 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@6.0;
+
+import android.hardware.audio.common@6.0;
+
+enum Result : int32_t {
+ OK,
+ NOT_INITIALIZED,
+ INVALID_ARGUMENTS,
+ INVALID_STATE,
+ /**
+ * Methods marked as "Optional method" must return this result value
+ * if the operation is not supported by HAL.
+ */
+ NOT_SUPPORTED
+};
+
+@export(name="audio_drain_type_t", value_prefix="AUDIO_DRAIN_")
+enum AudioDrain : int32_t {
+ /** drain() returns when all data has been played. */
+ ALL,
+ /**
+ * drain() returns a short time before all data from the current track has
+ * been played to give time for gapless track switch.
+ */
+ EARLY_NOTIFY
+};
+
+/**
+ * A substitute for POSIX timespec.
+ */
+struct TimeSpec {
+ uint64_t tvSec; // seconds
+ uint64_t tvNSec; // nanoseconds
+};
+
+struct ParameterValue {
+ string key;
+ string value;
+};
+
+enum MmapBufferFlag : uint32_t {
+ NONE = 0x0,
+ /**
+ * If the buffer can be securely shared to untrusted applications
+ * through the AAudio exclusive mode.
+ * Only set this flag if applications are restricted from accessing the
+ * memory surrounding the audio data buffer by a kernel mechanism.
+ * See Linux kernel's dma_buf.
+ */
+ APPLICATION_SHAREABLE = 0x1,
+};
+
+/**
+ * Mmap buffer descriptor returned by IStream.createMmapBuffer().
+ * Used by streams opened in mmap mode.
+ */
+struct MmapBufferInfo {
+ /** Mmap memory buffer */
+ memory sharedMemory;
+ /** Total buffer size in frames */
+ uint32_t bufferSizeFrames;
+ /** Transfer size granularity in frames */
+ uint32_t burstSizeFrames;
+ /** Attributes describing the buffer. */
+ bitfield<MmapBufferFlag> flags;
+};
+
+/**
+ * Mmap buffer read/write position returned by IStream.getMmapPosition().
+ * Used by streams opened in mmap mode.
+ */
+struct MmapPosition {
+ int64_t timeNanoseconds; // time stamp in ns, CLOCK_MONOTONIC
+ int32_t positionFrames; // increasing 32 bit frame count reset when IStream.stop() is called
+};
+
+/**
+ * The message queue flags used to synchronize reads and writes from
+ * message queues used by StreamIn and StreamOut.
+ */
+enum MessageQueueFlagBits : uint32_t {
+ NOT_EMPTY = 1 << 0,
+ NOT_FULL = 1 << 1
+};
+
+/*
+ * Microphone information
+ *
+ */
+
+/**
+ * A 3D point used to represent position or orientation of a microphone.
+ *
+ * Position: Coordinates of the microphone's capsule, in meters, from the
+ * bottom-left-back corner of the bounding box of android device in natural
+ * orientation (PORTRAIT for phones, LANDSCAPE for tablets, tvs, etc).
+ * The orientation musth match the reported by the api Display.getRotation().
+ *
+ * Orientation: Normalized vector to signal the main orientation of the
+ * microphone's capsule. Magnitude = sqrt(x^2 + y^2 + z^2) = 1
+ */
+struct AudioMicrophoneCoordinate {
+ float x;
+ float y;
+ float z;
+};
+
+/**
+ * Enum to identify the type of channel mapping for active microphones.
+ * Used channels further identify if the microphone has any significative
+ * process (e.g. High Pass Filtering, dynamic compression)
+ * Simple processing as constant gain adjustment must be DIRECT.
+ */
+enum AudioMicrophoneChannelMapping : uint32_t {
+ UNUSED = 0, /* Channel not used */
+ DIRECT = 1, /* Channel used and signal not processed */
+ PROCESSED = 2, /* Channel used and signal has some process */
+};
+
+/**
+ * Enum to identify locations of microphones in regards to the body of the
+ * android device.
+ */
+enum AudioMicrophoneLocation : uint32_t {
+ UNKNOWN = 0,
+ MAINBODY = 1,
+ MAINBODY_MOVABLE = 2,
+ PERIPHERAL = 3,
+};
+
+/**
+ * Identifier to help group related microphones together
+ * e.g. microphone arrays should belong to the same group
+ */
+typedef int32_t AudioMicrophoneGroup;
+
+/**
+ * Enum with standard polar patterns of microphones
+ */
+enum AudioMicrophoneDirectionality : uint32_t {
+ UNKNOWN = 0,
+ OMNI = 1,
+ BI_DIRECTIONAL = 2,
+ CARDIOID = 3,
+ HYPER_CARDIOID = 4,
+ SUPER_CARDIOID = 5,
+};
+
+/**
+ * A (frequency, level) pair. Used to represent frequency response.
+ */
+struct AudioFrequencyResponsePoint {
+ /** In Hz */
+ float frequency;
+ /** In dB */
+ float level;
+};
+
+/**
+ * Structure used by the HAL to describe microphone's characteristics
+ * Used by StreamIn and Device
+ */
+struct MicrophoneInfo {
+ /** Unique alphanumeric id for microphone. Guaranteed to be the same
+ * even after rebooting.
+ */
+ string deviceId;
+ /**
+ * Device specific information
+ */
+ DeviceAddress deviceAddress;
+ /** Each element of the vector must describe the channel with the same
+ * index.
+ */
+ vec<AudioMicrophoneChannelMapping> channelMapping;
+ /** Location of the microphone in regard to the body of the device */
+ AudioMicrophoneLocation location;
+ /** Identifier to help group related microphones together
+ * e.g. microphone arrays should belong to the same group
+ */
+ AudioMicrophoneGroup group;
+ /** Index of this microphone within the group.
+ * (group, index) must be unique within the same device.
+ */
+ uint32_t indexInTheGroup;
+ /** Level in dBFS produced by a 1000 Hz tone at 94 dB SPL */
+ float sensitivity;
+ /** Level in dB of the max SPL supported at 1000 Hz */
+ float maxSpl;
+ /** Level in dB of the min SPL supported at 1000 Hz */
+ float minSpl;
+ /** Standard polar pattern of the microphone */
+ AudioMicrophoneDirectionality directionality;
+ /** Vector with ordered frequency responses (from low to high frequencies)
+ * with the frequency response of the microphone.
+ * Levels are in dB, relative to level at 1000 Hz
+ */
+ vec<AudioFrequencyResponsePoint> frequencyResponse;
+ /** Position of the microphone's capsule in meters, from the
+ * bottom-left-back corner of the bounding box of device.
+ */
+ AudioMicrophoneCoordinate position;
+ /** Normalized point to signal the main orientation of the microphone's
+ * capsule. sqrt(x^2 + y^2 + z^2) = 1
+ */
+ AudioMicrophoneCoordinate orientation;
+};
+
+/**
+ * Constants used by the HAL to determine how to select microphones and process those inputs in
+ * order to optimize for capture in the specified direction.
+ *
+ * MicrophoneDirection Constants are defined in MicrophoneDirection.java.
+ */
+@export(name="audio_microphone_direction_t", value_prefix="MIC_DIRECTION_")
+enum MicrophoneDirection : int32_t {
+ /**
+ * Don't do any directionality processing of the activated microphone(s).
+ */
+ UNSPECIFIED = 0,
+ /**
+ * Optimize capture for audio coming from the screen-side of the device.
+ */
+ FRONT = 1,
+ /**
+ * Optimize capture for audio coming from the side of the device opposite the screen.
+ */
+ BACK = 2,
+ /**
+ * Optimize capture for audio coming from an off-device microphone.
+ */
+ EXTERNAL = 3,
+};
diff --git a/audio/common/6.0/Android.bp b/audio/common/6.0/Android.bp
new file mode 100644
index 0000000..1a4e054
--- /dev/null
+++ b/audio/common/6.0/Android.bp
@@ -0,0 +1,17 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.audio.common@6.0",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "types.hal",
+ ],
+ interfaces: [
+ "android.hidl.safe_union@1.0",
+ ],
+ gen_java: false,
+ gen_java_constants: true,
+}
diff --git a/audio/common/6.0/types.hal b/audio/common/6.0/types.hal
new file mode 100644
index 0000000..132f86d
--- /dev/null
+++ b/audio/common/6.0/types.hal
@@ -0,0 +1,1032 @@
+/*
+ * Copyright (C) 2019 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.common@6.0;
+
+import android.hidl.safe_union@1.0;
+
+/*
+ *
+ * IDs and Handles
+ *
+ */
+
+/**
+ * Handle type for identifying audio sources and sinks.
+ */
+typedef int32_t AudioIoHandle;
+
+/**
+ * Audio hw module handle functions or structures referencing a module.
+ */
+typedef int32_t AudioModuleHandle;
+
+/**
+ * Each port has a unique ID or handle allocated by policy manager.
+ */
+typedef int32_t AudioPortHandle;
+
+/**
+ * Each patch is identified by a handle at the interface used to create that
+ * patch. For instance, when a patch is created by the audio HAL, the HAL
+ * allocates and returns a handle. This handle is unique to a given audio HAL
+ * hardware module. But the same patch receives another system wide unique
+ * handle allocated by the framework. This unique handle is used for all
+ * transactions inside the framework.
+ */
+typedef int32_t AudioPatchHandle;
+
+/**
+ * A HW synchronization source returned by the audio HAL.
+ */
+typedef uint32_t AudioHwSync;
+
+/**
+ * Each port has a unique ID or handle allocated by policy manager.
+ */
+@export(name="")
+enum AudioHandleConsts : int32_t {
+ AUDIO_IO_HANDLE_NONE = 0,
+ AUDIO_MODULE_HANDLE_NONE = 0,
+ AUDIO_PORT_HANDLE_NONE = 0,
+ AUDIO_PATCH_HANDLE_NONE = 0,
+};
+
+/**
+ * Commonly used structure for passing unique identifieds (UUID).
+ * For the definition of UUID, refer to ITU-T X.667 spec.
+ */
+struct Uuid {
+ uint32_t timeLow;
+ uint16_t timeMid;
+ uint16_t versionAndTimeHigh;
+ uint16_t variantAndClockSeqHigh;
+ uint8_t[6] node;
+};
+
+
+/*
+ *
+ * Audio streams
+ *
+ */
+
+/**
+ * Audio stream type describing the intended use case of a stream.
+ */
+@export(name="audio_stream_type_t", value_prefix="AUDIO_STREAM_")
+enum AudioStreamType : int32_t {
+ // These values must kept in sync with
+ // frameworks/base/media/java/android/media/AudioSystem.java
+ DEFAULT = -1,
+ MIN = 0,
+ VOICE_CALL = 0,
+ SYSTEM = 1,
+ RING = 2,
+ MUSIC = 3,
+ ALARM = 4,
+ NOTIFICATION = 5,
+ BLUETOOTH_SCO = 6,
+ ENFORCED_AUDIBLE = 7, // Sounds that cannot be muted by user and must be
+ // routed to speaker
+ DTMF = 8,
+ TTS = 9, // Transmitted Through Speaker. Plays over speaker
+ // only, silent on other devices
+ ACCESSIBILITY = 10, // For accessibility talk back prompts
+};
+
+@export(name="audio_source_t", value_prefix="AUDIO_SOURCE_")
+enum AudioSource : int32_t {
+ // These values must kept in sync with
+ // frameworks/base/media/java/android/media/MediaRecorder.java,
+ // frameworks/av/services/audiopolicy/AudioPolicyService.cpp,
+ // system/media/audio_effects/include/audio_effects/audio_effects_conf.h
+ DEFAULT = 0,
+ MIC = 1,
+ VOICE_UPLINK = 2,
+ VOICE_DOWNLINK = 3,
+ VOICE_CALL = 4,
+ CAMCORDER = 5,
+ VOICE_RECOGNITION = 6,
+ VOICE_COMMUNICATION = 7,
+ /**
+ * Source for the mix to be presented remotely. An example of remote
+ * presentation is Wifi Display where a dongle attached to a TV can be used
+ * to play the mix captured by this audio source.
+ */
+ REMOTE_SUBMIX = 8,
+ /**
+ * Source for unprocessed sound. Usage examples include level measurement
+ * and raw signal analysis.
+ */
+ UNPROCESSED = 9,
+ /**
+ * Source for capturing audio meant to be processed in real time and played back for live
+ * performance (e.g karaoke). The capture path will minimize latency and coupling with
+ * playback path.
+ */
+ VOICE_PERFORMANCE = 10,
+ /**
+ * Source for an echo canceller to capture the reference signal to be cancelled.
+ * The echo reference signal will be captured as close as possible to the DAC in order
+ * to include all post processing applied to the playback path.
+ */
+ ECHO_REFERENCE = 1997,
+ FM_TUNER = 1998,
+ HOTWORD = 1999,
+};
+
+typedef int32_t AudioSession;
+/**
+ * Special audio session values.
+ */
+@export(name="audio_session_t", value_prefix="AUDIO_SESSION_")
+enum AudioSessionConsts : int32_t {
+ /**
+ * Session for effects attached to a particular output stream
+ * (value must be less than 0)
+ */
+ OUTPUT_STAGE = -1,
+ /**
+ * Session for effects applied to output mix. These effects can
+ * be moved by audio policy manager to another output stream
+ * (value must be 0)
+ */
+ OUTPUT_MIX = 0,
+ /**
+ * Application does not specify an explicit session ID to be used, and
+ * requests a new session ID to be allocated. Corresponds to
+ * AudioManager.AUDIO_SESSION_ID_GENERATE and
+ * AudioSystem.AUDIO_SESSION_ALLOCATE.
+ */
+ ALLOCATE = 0,
+ /**
+ * For use with AudioRecord::start(), this indicates no trigger session.
+ * It is also used with output tracks and patch tracks, which never have a
+ * session.
+ */
+ NONE = 0
+};
+
+/**
+ * Audio format is a 32-bit word that consists of:
+ * main format field (upper 8 bits)
+ * sub format field (lower 24 bits).
+ *
+ * The main format indicates the main codec type. The sub format field indicates
+ * options and parameters for each format. The sub format is mainly used for
+ * record to indicate for instance the requested bitrate or profile. It can
+ * also be used for certain formats to give informations not present in the
+ * encoded audio stream (e.g. octet alignement for AMR).
+ */
+@export(name="audio_format_t", value_prefix="AUDIO_FORMAT_")
+enum AudioFormat : uint32_t {
+ INVALID = 0xFFFFFFFFUL,
+ DEFAULT = 0,
+ PCM = 0x00000000UL,
+ MP3 = 0x01000000UL,
+ AMR_NB = 0x02000000UL,
+ AMR_WB = 0x03000000UL,
+ AAC = 0x04000000UL,
+ /** Deprecated, Use AAC_HE_V1 */
+ HE_AAC_V1 = 0x05000000UL,
+ /** Deprecated, Use AAC_HE_V2 */
+ HE_AAC_V2 = 0x06000000UL,
+ VORBIS = 0x07000000UL,
+ OPUS = 0x08000000UL,
+ AC3 = 0x09000000UL,
+ E_AC3 = 0x0A000000UL,
+ DTS = 0x0B000000UL,
+ DTS_HD = 0x0C000000UL,
+ /** IEC61937 is encoded audio wrapped in 16-bit PCM. */
+ IEC61937 = 0x0D000000UL,
+ DOLBY_TRUEHD = 0x0E000000UL,
+ EVRC = 0x10000000UL,
+ EVRCB = 0x11000000UL,
+ EVRCWB = 0x12000000UL,
+ EVRCNW = 0x13000000UL,
+ AAC_ADIF = 0x14000000UL,
+ WMA = 0x15000000UL,
+ WMA_PRO = 0x16000000UL,
+ AMR_WB_PLUS = 0x17000000UL,
+ MP2 = 0x18000000UL,
+ QCELP = 0x19000000UL,
+ DSD = 0x1A000000UL,
+ FLAC = 0x1B000000UL,
+ ALAC = 0x1C000000UL,
+ APE = 0x1D000000UL,
+ AAC_ADTS = 0x1E000000UL,
+ SBC = 0x1F000000UL,
+ APTX = 0x20000000UL,
+ APTX_HD = 0x21000000UL,
+ AC4 = 0x22000000UL,
+ LDAC = 0x23000000UL,
+ /** Dolby Metadata-enhanced Audio Transmission */
+ MAT = 0x24000000UL,
+ AAC_LATM = 0x25000000UL,
+ CELT = 0x26000000UL,
+ APTX_ADAPTIVE = 0x27000000UL,
+ LHDC = 0x28000000UL,
+ LHDC_LL = 0x29000000UL,
+ APTX_TWSP = 0x2A000000UL,
+
+ /** Deprecated */
+ MAIN_MASK = 0xFF000000UL,
+ SUB_MASK = 0x00FFFFFFUL,
+
+ /* Subformats */
+ PCM_SUB_16_BIT = 0x1, // PCM signed 16 bits
+ PCM_SUB_8_BIT = 0x2, // PCM unsigned 8 bits
+ PCM_SUB_32_BIT = 0x3, // PCM signed .31 fixed point
+ PCM_SUB_8_24_BIT = 0x4, // PCM signed 8.23 fixed point
+ PCM_SUB_FLOAT = 0x5, // PCM single-precision float pt
+ PCM_SUB_24_BIT_PACKED = 0x6, // PCM signed .23 fix pt (3 bytes)
+
+ MP3_SUB_NONE = 0x0,
+
+ AMR_SUB_NONE = 0x0,
+
+ AAC_SUB_MAIN = 0x1,
+ AAC_SUB_LC = 0x2,
+ AAC_SUB_SSR = 0x4,
+ AAC_SUB_LTP = 0x8,
+ AAC_SUB_HE_V1 = 0x10,
+ AAC_SUB_SCALABLE = 0x20,
+ AAC_SUB_ERLC = 0x40,
+ AAC_SUB_LD = 0x80,
+ AAC_SUB_HE_V2 = 0x100,
+ AAC_SUB_ELD = 0x200,
+ AAC_SUB_XHE = 0x300,
+
+ VORBIS_SUB_NONE = 0x0,
+
+ E_AC3_SUB_JOC = 0x1,
+
+ MAT_SUB_1_0 = 0x1,
+ MAT_SUB_2_0 = 0x2,
+ MAT_SUB_2_1 = 0x3,
+
+ /* Aliases */
+ /** note != AudioFormat.ENCODING_PCM_16BIT */
+ PCM_16_BIT = (PCM | PCM_SUB_16_BIT),
+ /** note != AudioFormat.ENCODING_PCM_8BIT */
+ PCM_8_BIT = (PCM | PCM_SUB_8_BIT),
+ PCM_32_BIT = (PCM | PCM_SUB_32_BIT),
+ PCM_8_24_BIT = (PCM | PCM_SUB_8_24_BIT),
+ PCM_FLOAT = (PCM | PCM_SUB_FLOAT),
+ PCM_24_BIT_PACKED = (PCM | PCM_SUB_24_BIT_PACKED),
+ AAC_MAIN = (AAC | AAC_SUB_MAIN),
+ AAC_LC = (AAC | AAC_SUB_LC),
+ AAC_SSR = (AAC | AAC_SUB_SSR),
+ AAC_LTP = (AAC | AAC_SUB_LTP),
+ AAC_HE_V1 = (AAC | AAC_SUB_HE_V1),
+ AAC_SCALABLE = (AAC | AAC_SUB_SCALABLE),
+ AAC_ERLC = (AAC | AAC_SUB_ERLC),
+ AAC_LD = (AAC | AAC_SUB_LD),
+ AAC_HE_V2 = (AAC | AAC_SUB_HE_V2),
+ AAC_ELD = (AAC | AAC_SUB_ELD),
+ AAC_XHE = (AAC | AAC_SUB_XHE),
+ AAC_ADTS_MAIN = (AAC_ADTS | AAC_SUB_MAIN),
+ AAC_ADTS_LC = (AAC_ADTS | AAC_SUB_LC),
+ AAC_ADTS_SSR = (AAC_ADTS | AAC_SUB_SSR),
+ AAC_ADTS_LTP = (AAC_ADTS | AAC_SUB_LTP),
+ AAC_ADTS_HE_V1 = (AAC_ADTS | AAC_SUB_HE_V1),
+ AAC_ADTS_SCALABLE = (AAC_ADTS | AAC_SUB_SCALABLE),
+ AAC_ADTS_ERLC = (AAC_ADTS | AAC_SUB_ERLC),
+ AAC_ADTS_LD = (AAC_ADTS | AAC_SUB_LD),
+ AAC_ADTS_HE_V2 = (AAC_ADTS | AAC_SUB_HE_V2),
+ AAC_ADTS_ELD = (AAC_ADTS | AAC_SUB_ELD),
+ AAC_ADTS_XHE = (AAC_ADTS | AAC_SUB_XHE),
+ E_AC3_JOC = (E_AC3 | E_AC3_SUB_JOC),
+ MAT_1_0 = (MAT | MAT_SUB_1_0),
+ MAT_2_0 = (MAT | MAT_SUB_2_0),
+ MAT_2_1 = (MAT | MAT_SUB_2_1),
+ AAC_LATM_LC = (AAC_LATM | AAC_SUB_LC),
+ AAC_LATM_HE_V1 = (AAC_LATM | AAC_SUB_HE_V1),
+ AAC_LATM_HE_V2 = (AAC_LATM | AAC_SUB_HE_V2),
+};
+
+/**
+ * Usage of these values highlights places in the code that use 2- or 8- channel
+ * assumptions.
+ */
+@export(name="")
+enum FixedChannelCount : int32_t {
+ FCC_2 = 2, // This is typically due to legacy implementation of stereo I/O
+ FCC_8 = 8 // This is typically due to audio mixer and resampler limitations
+};
+
+/**
+ * A channel mask per se only defines the presence or absence of a channel, not
+ * the order.
+ *
+ * The channel order convention is that channels are interleaved in order from
+ * least significant channel mask bit to most significant channel mask bit,
+ * with unused bits skipped. For example for stereo, LEFT would be first,
+ * followed by RIGHT.
+ * Any exceptions to this convention are noted at the appropriate API.
+ *
+ * AudioChannelMask is an opaque type and its internal layout should not be
+ * assumed as it may change in the future. Instead, always use functions
+ * to examine it.
+ *
+ * These are the current representations:
+ *
+ * REPRESENTATION_POSITION
+ * is a channel mask representation for position assignment. Each low-order
+ * bit corresponds to the spatial position of a transducer (output), or
+ * interpretation of channel (input). The user of a channel mask needs to
+ * know the context of whether it is for output or input. The constants
+ * OUT_* or IN_* apply to the bits portion. It is not permitted for no bits
+ * to be set.
+ *
+ * REPRESENTATION_INDEX
+ * is a channel mask representation for index assignment. Each low-order
+ * bit corresponds to a selected channel. There is no platform
+ * interpretation of the various bits. There is no concept of output or
+ * input. It is not permitted for no bits to be set.
+ *
+ * All other representations are reserved for future use.
+ *
+ * Warning: current representation distinguishes between input and output, but
+ * this will not the be case in future revisions of the platform. Wherever there
+ * is an ambiguity between input and output that is currently resolved by
+ * checking the channel mask, the implementer should look for ways to fix it
+ * with additional information outside of the mask.
+ */
+@export(name="", value_prefix="AUDIO_CHANNEL_")
+enum AudioChannelMask : uint32_t {
+ /** must be 0 for compatibility */
+ REPRESENTATION_POSITION = 0,
+ /** 1 is reserved for future use */
+ REPRESENTATION_INDEX = 2,
+ /* 3 is reserved for future use */
+
+ /** These can be a complete value of AudioChannelMask */
+ NONE = 0x0,
+ INVALID = 0xC0000000,
+
+ /*
+ * These can be the bits portion of an AudioChannelMask
+ * with representation REPRESENTATION_POSITION.
+ */
+
+ /** output channels */
+ OUT_FRONT_LEFT = 0x1,
+ OUT_FRONT_RIGHT = 0x2,
+ OUT_FRONT_CENTER = 0x4,
+ OUT_LOW_FREQUENCY = 0x8,
+ OUT_BACK_LEFT = 0x10,
+ OUT_BACK_RIGHT = 0x20,
+ OUT_FRONT_LEFT_OF_CENTER = 0x40,
+ OUT_FRONT_RIGHT_OF_CENTER = 0x80,
+ OUT_BACK_CENTER = 0x100,
+ OUT_SIDE_LEFT = 0x200,
+ OUT_SIDE_RIGHT = 0x400,
+ OUT_TOP_CENTER = 0x800,
+ OUT_TOP_FRONT_LEFT = 0x1000,
+ OUT_TOP_FRONT_CENTER = 0x2000,
+ OUT_TOP_FRONT_RIGHT = 0x4000,
+ OUT_TOP_BACK_LEFT = 0x8000,
+ OUT_TOP_BACK_CENTER = 0x10000,
+ OUT_TOP_BACK_RIGHT = 0x20000,
+ OUT_TOP_SIDE_LEFT = 0x40000,
+ OUT_TOP_SIDE_RIGHT = 0x80000,
+
+ /**
+ * Haptic channel characteristics are specific to a device and
+ * only used to play device specific resources (eg: ringtones).
+ * The HAL can freely map A and B to haptic controllers, the
+ * framework shall not interpret those values and forward them
+ * from the device audio assets.
+ */
+ OUT_HAPTIC_A = 0x20000000,
+ OUT_HAPTIC_B = 0x10000000,
+
+ OUT_MONO = OUT_FRONT_LEFT,
+ OUT_STEREO = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT),
+ OUT_2POINT1 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_LOW_FREQUENCY),
+ OUT_2POINT0POINT2 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
+ OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT),
+ OUT_2POINT1POINT2 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
+ OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT |
+ OUT_LOW_FREQUENCY),
+ OUT_3POINT0POINT2 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_FRONT_CENTER |
+ OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT),
+ OUT_3POINT1POINT2 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_FRONT_CENTER |
+ OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT |
+ OUT_LOW_FREQUENCY),
+ OUT_QUAD = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
+ OUT_BACK_LEFT | OUT_BACK_RIGHT),
+ OUT_QUAD_BACK = OUT_QUAD,
+ /** like OUT_QUAD_BACK with *_SIDE_* instead of *_BACK_* */
+ OUT_QUAD_SIDE = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
+ OUT_SIDE_LEFT | OUT_SIDE_RIGHT),
+ OUT_SURROUND = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
+ OUT_FRONT_CENTER | OUT_BACK_CENTER),
+ OUT_PENTA = (OUT_QUAD | OUT_FRONT_CENTER),
+ OUT_5POINT1 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
+ OUT_FRONT_CENTER | OUT_LOW_FREQUENCY |
+ OUT_BACK_LEFT | OUT_BACK_RIGHT),
+ OUT_5POINT1_BACK = OUT_5POINT1,
+ /** like OUT_5POINT1_BACK with *_SIDE_* instead of *_BACK_* */
+ OUT_5POINT1_SIDE = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
+ OUT_FRONT_CENTER | OUT_LOW_FREQUENCY |
+ OUT_SIDE_LEFT | OUT_SIDE_RIGHT),
+ OUT_5POINT1POINT2 = (OUT_5POINT1 | OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT),
+ OUT_5POINT1POINT4 = (OUT_5POINT1 |
+ OUT_TOP_FRONT_LEFT | OUT_TOP_FRONT_RIGHT |
+ OUT_TOP_BACK_LEFT | OUT_TOP_BACK_RIGHT),
+ OUT_6POINT1 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
+ OUT_FRONT_CENTER | OUT_LOW_FREQUENCY |
+ OUT_BACK_LEFT | OUT_BACK_RIGHT |
+ OUT_BACK_CENTER),
+ /** matches the correct AudioFormat.CHANNEL_OUT_7POINT1_SURROUND */
+ OUT_7POINT1 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
+ OUT_FRONT_CENTER | OUT_LOW_FREQUENCY |
+ OUT_BACK_LEFT | OUT_BACK_RIGHT |
+ OUT_SIDE_LEFT | OUT_SIDE_RIGHT),
+ OUT_7POINT1POINT2 = (OUT_7POINT1 | OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT),
+ OUT_7POINT1POINT4 = (OUT_7POINT1 |
+ OUT_TOP_FRONT_LEFT | OUT_TOP_FRONT_RIGHT |
+ OUT_TOP_BACK_LEFT | OUT_TOP_BACK_RIGHT),
+ OUT_MONO_HAPTIC_A = (OUT_FRONT_LEFT | OUT_HAPTIC_A),
+ OUT_STEREO_HAPTIC_A = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_HAPTIC_A),
+ OUT_HAPTIC_AB = (OUT_HAPTIC_A | OUT_HAPTIC_B),
+ OUT_MONO_HAPTIC_AB = (OUT_FRONT_LEFT | OUT_HAPTIC_A | OUT_HAPTIC_B),
+ OUT_STEREO_HAPTIC_AB = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
+ OUT_HAPTIC_A | OUT_HAPTIC_B),
+ // Note that the 2.0 OUT_ALL* have been moved to helper functions
+
+ /* These are bits only, not complete values */
+
+ /** input channels */
+ IN_LEFT = 0x4,
+ IN_RIGHT = 0x8,
+ IN_FRONT = 0x10,
+ IN_BACK = 0x20,
+ IN_LEFT_PROCESSED = 0x40,
+ IN_RIGHT_PROCESSED = 0x80,
+ IN_FRONT_PROCESSED = 0x100,
+ IN_BACK_PROCESSED = 0x200,
+ IN_PRESSURE = 0x400,
+ IN_X_AXIS = 0x800,
+ IN_Y_AXIS = 0x1000,
+ IN_Z_AXIS = 0x2000,
+ IN_BACK_LEFT = 0x10000,
+ IN_BACK_RIGHT = 0x20000,
+ IN_CENTER = 0x40000,
+ IN_LOW_FREQUENCY = 0x100000,
+ IN_TOP_LEFT = 0x200000,
+ IN_TOP_RIGHT = 0x400000,
+
+ IN_VOICE_UPLINK = 0x4000,
+ IN_VOICE_DNLINK = 0x8000,
+
+ IN_MONO = IN_FRONT,
+ IN_STEREO = (IN_LEFT | IN_RIGHT),
+ IN_FRONT_BACK = (IN_FRONT | IN_BACK),
+ IN_6 = (IN_LEFT | IN_RIGHT |
+ IN_FRONT | IN_BACK |
+ IN_LEFT_PROCESSED | IN_RIGHT_PROCESSED),
+ IN_2POINT0POINT2 = (IN_LEFT | IN_RIGHT | IN_TOP_LEFT | IN_TOP_RIGHT),
+ IN_2POINT1POINT2 = (IN_LEFT | IN_RIGHT | IN_TOP_LEFT | IN_TOP_RIGHT |
+ IN_LOW_FREQUENCY),
+ IN_3POINT0POINT2 = (IN_LEFT | IN_CENTER | IN_RIGHT | IN_TOP_LEFT | IN_TOP_RIGHT),
+ IN_3POINT1POINT2 = (IN_LEFT | IN_CENTER | IN_RIGHT |
+ IN_TOP_LEFT | IN_TOP_RIGHT | IN_LOW_FREQUENCY),
+ IN_5POINT1 = (IN_LEFT | IN_CENTER | IN_RIGHT |
+ IN_BACK_LEFT | IN_BACK_RIGHT | IN_LOW_FREQUENCY),
+ IN_VOICE_UPLINK_MONO = (IN_VOICE_UPLINK | IN_MONO),
+ IN_VOICE_DNLINK_MONO = (IN_VOICE_DNLINK | IN_MONO),
+ IN_VOICE_CALL_MONO = (IN_VOICE_UPLINK_MONO |
+ IN_VOICE_DNLINK_MONO),
+ // Note that the 2.0 IN_ALL* have been moved to helper functions
+
+ COUNT_MAX = 30,
+ INDEX_HDR = REPRESENTATION_INDEX << COUNT_MAX,
+ INDEX_MASK_1 = INDEX_HDR | ((1 << 1) - 1),
+ INDEX_MASK_2 = INDEX_HDR | ((1 << 2) - 1),
+ INDEX_MASK_3 = INDEX_HDR | ((1 << 3) - 1),
+ INDEX_MASK_4 = INDEX_HDR | ((1 << 4) - 1),
+ INDEX_MASK_5 = INDEX_HDR | ((1 << 5) - 1),
+ INDEX_MASK_6 = INDEX_HDR | ((1 << 6) - 1),
+ INDEX_MASK_7 = INDEX_HDR | ((1 << 7) - 1),
+ INDEX_MASK_8 = INDEX_HDR | ((1 << 8) - 1),
+ INDEX_MASK_9 = INDEX_HDR | ((1 << 9) - 1),
+ INDEX_MASK_10 = INDEX_HDR | ((1 << 10) - 1),
+ INDEX_MASK_11 = INDEX_HDR | ((1 << 11) - 1),
+ INDEX_MASK_12 = INDEX_HDR | ((1 << 12) - 1),
+ INDEX_MASK_13 = INDEX_HDR | ((1 << 13) - 1),
+ INDEX_MASK_14 = INDEX_HDR | ((1 << 14) - 1),
+ INDEX_MASK_15 = INDEX_HDR | ((1 << 15) - 1),
+ INDEX_MASK_16 = INDEX_HDR | ((1 << 16) - 1),
+ INDEX_MASK_17 = INDEX_HDR | ((1 << 17) - 1),
+ INDEX_MASK_18 = INDEX_HDR | ((1 << 18) - 1),
+ INDEX_MASK_19 = INDEX_HDR | ((1 << 19) - 1),
+ INDEX_MASK_20 = INDEX_HDR | ((1 << 20) - 1),
+ INDEX_MASK_21 = INDEX_HDR | ((1 << 21) - 1),
+ INDEX_MASK_22 = INDEX_HDR | ((1 << 22) - 1),
+ INDEX_MASK_23 = INDEX_HDR | ((1 << 23) - 1),
+ INDEX_MASK_24 = INDEX_HDR | ((1 << 24) - 1),
+};
+
+/**
+ * Major modes for a mobile device. The current mode setting affects audio
+ * routing.
+ */
+@export(name="audio_mode_t", value_prefix="AUDIO_MODE_")
+enum AudioMode : int32_t {
+ NORMAL = 0,
+ RINGTONE = 1,
+ /** Calls handled by the telephony stack (Eg: PSTN). */
+ IN_CALL = 2,
+ /** Calls handled by apps (Eg: Hangout). */
+ IN_COMMUNICATION = 3,
+};
+
+@export(name="", value_prefix="AUDIO_DEVICE_")
+enum AudioDevice : uint32_t {
+ NONE = 0x0,
+ /** reserved bits */
+ BIT_IN = 0x80000000,
+ BIT_DEFAULT = 0x40000000,
+ /** output devices */
+ OUT_EARPIECE = 0x1,
+ OUT_SPEAKER = 0x2,
+ OUT_WIRED_HEADSET = 0x4,
+ OUT_WIRED_HEADPHONE = 0x8,
+ OUT_BLUETOOTH_SCO = 0x10,
+ OUT_BLUETOOTH_SCO_HEADSET = 0x20,
+ OUT_BLUETOOTH_SCO_CARKIT = 0x40,
+ OUT_BLUETOOTH_A2DP = 0x80,
+ OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100,
+ OUT_BLUETOOTH_A2DP_SPEAKER = 0x200,
+ OUT_AUX_DIGITAL = 0x400,
+ OUT_HDMI = OUT_AUX_DIGITAL,
+ /** uses an analog connection (multiplexed over the USB pins for instance) */
+ OUT_ANLG_DOCK_HEADSET = 0x800,
+ OUT_DGTL_DOCK_HEADSET = 0x1000,
+ /** USB accessory mode: Android device is USB device and dock is USB host */
+ OUT_USB_ACCESSORY = 0x2000,
+ /** USB host mode: Android device is USB host and dock is USB device */
+ OUT_USB_DEVICE = 0x4000,
+ OUT_REMOTE_SUBMIX = 0x8000,
+ /** Telephony voice TX path */
+ OUT_TELEPHONY_TX = 0x10000,
+ /** Analog jack with line impedance detected */
+ OUT_LINE = 0x20000,
+ /** HDMI Audio Return Channel */
+ OUT_HDMI_ARC = 0x40000,
+ /** S/PDIF out */
+ OUT_SPDIF = 0x80000,
+ /** FM transmitter out */
+ OUT_FM = 0x100000,
+ /** Line out for av devices */
+ OUT_AUX_LINE = 0x200000,
+ /** limited-output speaker device for acoustic safety */
+ OUT_SPEAKER_SAFE = 0x400000,
+ OUT_IP = 0x800000,
+ /** audio bus implemented by the audio system (e.g an MOST stereo channel) */
+ OUT_BUS = 0x1000000,
+ OUT_PROXY = 0x2000000,
+ OUT_USB_HEADSET = 0x4000000,
+ OUT_HEARING_AID = 0x8000000,
+ OUT_ECHO_CANCELLER = 0x10000000,
+ OUT_DEFAULT = BIT_DEFAULT,
+ // Note that the 2.0 OUT_ALL* have been moved to helper functions
+
+ /** input devices */
+ IN_COMMUNICATION = BIT_IN | 0x1,
+ IN_AMBIENT = BIT_IN | 0x2,
+ IN_BUILTIN_MIC = BIT_IN | 0x4,
+ IN_BLUETOOTH_SCO_HEADSET = BIT_IN | 0x8,
+ IN_WIRED_HEADSET = BIT_IN | 0x10,
+ IN_AUX_DIGITAL = BIT_IN | 0x20,
+ IN_HDMI = IN_AUX_DIGITAL,
+ /** Telephony voice RX path */
+ IN_VOICE_CALL = BIT_IN | 0x40,
+ IN_TELEPHONY_RX = IN_VOICE_CALL,
+ IN_BACK_MIC = BIT_IN | 0x80,
+ IN_REMOTE_SUBMIX = BIT_IN | 0x100,
+ IN_ANLG_DOCK_HEADSET = BIT_IN | 0x200,
+ IN_DGTL_DOCK_HEADSET = BIT_IN | 0x400,
+ IN_USB_ACCESSORY = BIT_IN | 0x800,
+ IN_USB_DEVICE = BIT_IN | 0x1000,
+ /** FM tuner input */
+ IN_FM_TUNER = BIT_IN | 0x2000,
+ /** TV tuner input */
+ IN_TV_TUNER = BIT_IN | 0x4000,
+ /** Analog jack with line impedance detected */
+ IN_LINE = BIT_IN | 0x8000,
+ /** S/PDIF in */
+ IN_SPDIF = BIT_IN | 0x10000,
+ IN_BLUETOOTH_A2DP = BIT_IN | 0x20000,
+ IN_LOOPBACK = BIT_IN | 0x40000,
+ IN_IP = BIT_IN | 0x80000,
+ /** audio bus implemented by the audio system (e.g an MOST stereo channel) */
+ IN_BUS = BIT_IN | 0x100000,
+ IN_PROXY = BIT_IN | 0x1000000,
+ IN_USB_HEADSET = BIT_IN | 0x2000000,
+ IN_BLUETOOTH_BLE = BIT_IN | 0x4000000,
+ IN_ECHO_REFERENCE = BIT_IN | 0x10000000,
+ IN_DEFAULT = BIT_IN | BIT_DEFAULT,
+
+ // Note that the 2.0 IN_ALL* have been moved to helper functions
+};
+
+/**
+ * IEEE 802 MAC address.
+ */
+typedef uint8_t[6] MacAddress;
+
+/**
+ * Specifies a device address in case when several devices of the same type
+ * can be connected (e.g. BT A2DP, USB).
+ */
+struct DeviceAddress {
+ AudioDevice device; // discriminator
+ union Address {
+ MacAddress mac; // used for BLUETOOTH_A2DP_*
+ uint8_t[4] ipv4; // used for IP
+ struct Alsa {
+ int32_t card;
+ int32_t device;
+ } alsa; // used for USB_*
+ } address;
+ /** Arbitrary BUS device unique address. Should not be interpreted by the framework. */
+ string busAddress;
+ /** Arbitrary REMOTE_SUBMIX device unique address. Should not be interpreted by the HAL. */
+ string rSubmixAddress;
+};
+
+/**
+ * The audio output flags serve two purposes:
+ *
+ * - when an AudioTrack is created they indicate a "wish" to be connected to an
+ * output stream with attributes corresponding to the specified flags;
+ *
+ * - when present in an output profile descriptor listed for a particular audio
+ * hardware module, they indicate that an output stream can be opened that
+ * supports the attributes indicated by the flags.
+ *
+ * The audio policy manager will try to match the flags in the request
+ * (when getOuput() is called) to an available output stream.
+ */
+@export(name="audio_output_flags_t", value_prefix="AUDIO_OUTPUT_FLAG_")
+enum AudioOutputFlag : int32_t {
+ NONE = 0x0, // no attributes
+ DIRECT = 0x1, // this output directly connects a track
+ // to one output stream: no software mixer
+ PRIMARY = 0x2, // this output is the primary output of the device. It is
+ // unique and must be present. It is opened by default and
+ // receives routing, audio mode and volume controls related
+ // to voice calls.
+ FAST = 0x4, // output supports "fast tracks", defined elsewhere
+ DEEP_BUFFER = 0x8, // use deep audio buffers
+ COMPRESS_OFFLOAD = 0x10, // offload playback of compressed streams to
+ // hardware codec
+ NON_BLOCKING = 0x20, // use non-blocking write
+ HW_AV_SYNC = 0x40, // output uses a hardware A/V sync
+ TTS = 0x80, // output for streams transmitted through speaker at a
+ // sample rate high enough to accommodate lower-range
+ // ultrasonic p/b
+ RAW = 0x100, // minimize signal processing
+ SYNC = 0x200, // synchronize I/O streams
+ IEC958_NONAUDIO = 0x400, // Audio stream contains compressed audio in SPDIF
+ // data bursts, not PCM.
+ DIRECT_PCM = 0x2000, // Audio stream containing PCM data that needs
+ // to pass through compress path for DSP post proc.
+ MMAP_NOIRQ = 0x4000, // output operates in MMAP no IRQ mode.
+ VOIP_RX = 0x8000, // preferred output for VoIP calls.
+ /** preferred output for call music */
+ INCALL_MUSIC = 0x10000,
+};
+
+/**
+ * The audio input flags are analogous to audio output flags.
+ * Currently they are used only when an AudioRecord is created,
+ * to indicate a preference to be connected to an input stream with
+ * attributes corresponding to the specified flags.
+ */
+@export(name="audio_input_flags_t", value_prefix="AUDIO_INPUT_FLAG_")
+enum AudioInputFlag : int32_t {
+ NONE = 0x0, // no attributes
+ FAST = 0x1, // prefer an input that supports "fast tracks"
+ HW_HOTWORD = 0x2, // prefer an input that captures from hw hotword source
+ RAW = 0x4, // minimize signal processing
+ SYNC = 0x8, // synchronize I/O streams
+ MMAP_NOIRQ = 0x10, // input operates in MMAP no IRQ mode.
+ VOIP_TX = 0x20, // preferred input for VoIP calls.
+ HW_AV_SYNC = 0x40, // input connected to an output that uses a hardware A/V sync
+};
+
+@export(name="audio_usage_t", value_prefix="AUDIO_USAGE_")
+enum AudioUsage : int32_t {
+ // These values must kept in sync with
+ // frameworks/base/media/java/android/media/AudioAttributes.java
+ // Note that not all framework values are exposed
+ UNKNOWN = 0,
+ MEDIA = 1,
+ VOICE_COMMUNICATION = 2,
+ VOICE_COMMUNICATION_SIGNALLING = 3,
+ ALARM = 4,
+ NOTIFICATION = 5,
+ NOTIFICATION_TELEPHONY_RINGTONE = 6,
+ ASSISTANCE_ACCESSIBILITY = 11,
+ ASSISTANCE_NAVIGATION_GUIDANCE = 12,
+ ASSISTANCE_SONIFICATION = 13,
+ GAME = 14,
+ VIRTUAL_SOURCE = 15,
+ ASSISTANT = 16,
+};
+
+/** Type of audio generated by an application. */
+@export(name="audio_content_type_t", value_prefix="AUDIO_CONTENT_TYPE_")
+enum AudioContentType : uint32_t {
+ // Do not change these values without updating their counterparts
+ // in frameworks/base/media/java/android/media/AudioAttributes.java
+ UNKNOWN = 0,
+ SPEECH = 1,
+ MUSIC = 2,
+ MOVIE = 3,
+ SONIFICATION = 4,
+};
+
+/**
+ * Additional information about the stream passed to hardware decoders.
+ */
+struct AudioOffloadInfo {
+ uint32_t sampleRateHz;
+ bitfield<AudioChannelMask> channelMask;
+ AudioFormat format;
+ AudioStreamType streamType;
+ uint32_t bitRatePerSecond;
+ int64_t durationMicroseconds; // -1 if unknown
+ bool hasVideo;
+ bool isStreaming;
+ uint32_t bitWidth;
+ uint32_t bufferSize;
+ AudioUsage usage;
+};
+
+/**
+ * Commonly used audio stream configuration parameters.
+ */
+struct AudioConfig {
+ uint32_t sampleRateHz;
+ bitfield<AudioChannelMask> channelMask;
+ AudioFormat format;
+ AudioOffloadInfo offloadInfo;
+ uint64_t frameCount;
+};
+
+/** Metadata of a playback track for a StreamOut. */
+struct PlaybackTrackMetadata {
+ AudioUsage usage;
+ AudioContentType contentType;
+ /**
+ * Positive linear gain applied to the track samples. 0 being muted and 1 is no attenuation,
+ * 2 means double amplification...
+ * Must not be negative.
+ */
+ float gain;
+};
+
+/** Metadatas of the source of a StreamOut. */
+struct SourceMetadata {
+ vec<PlaybackTrackMetadata> tracks;
+};
+
+/** Metadata of a record track for a StreamIn. */
+struct RecordTrackMetadata {
+ AudioSource source;
+ /**
+ * Positive linear gain applied to the track samples. 0 being muted and 1 is no attenuation,
+ * 2 means double amplification...
+ * Must not be negative.
+ */
+ float gain;
+ /**
+ * Indicates the destination of an input stream, can be left unspecified.
+ */
+ safe_union Destination {
+ Monostate unspecified;
+ DeviceAddress device;
+ };
+ Destination destination;
+};
+
+/** Metadatas of the sink of a StreamIn. */
+struct SinkMetadata {
+ vec<RecordTrackMetadata> tracks;
+};
+
+
+/*
+ *
+ * Volume control
+ *
+ */
+
+/**
+ * Type of gain control exposed by an audio port.
+ */
+@export(name="", value_prefix="AUDIO_GAIN_MODE_")
+enum AudioGainMode : uint32_t {
+ JOINT = 0x1, // supports joint channel gain control
+ CHANNELS = 0x2, // supports separate channel gain control
+ RAMP = 0x4 // supports gain ramps
+};
+
+/**
+ * An audio_gain struct is a representation of a gain stage.
+ * A gain stage is always attached to an audio port.
+ */
+struct AudioGain {
+ bitfield<AudioGainMode> mode;
+ bitfield<AudioChannelMask> channelMask; // channels which gain an be controlled
+ int32_t minValue; // minimum gain value in millibels
+ int32_t maxValue; // maximum gain value in millibels
+ int32_t defaultValue; // default gain value in millibels
+ uint32_t stepValue; // gain step in millibels
+ uint32_t minRampMs; // minimum ramp duration in ms
+ uint32_t maxRampMs; // maximum ramp duration in ms
+};
+
+/**
+ * The gain configuration structure is used to get or set the gain values of a
+ * given port.
+ */
+struct AudioGainConfig {
+ int32_t index; // index of the corresponding AudioGain in AudioPort.gains
+ AudioGainMode mode;
+ AudioChannelMask channelMask; // channels which gain value follows
+ /**
+ * 4 = sizeof(AudioChannelMask),
+ * 8 is not "FCC_8", so it won't need to be changed for > 8 channels.
+ * Gain values in millibels for each channel ordered from LSb to MSb in
+ * channel mask. The number of values is 1 in joint mode or
+ * popcount(channel_mask).
+ */
+ int32_t[4 * 8] values;
+ uint32_t rampDurationMs; // ramp duration in ms
+};
+
+
+/*
+ *
+ * Routing control
+ *
+ */
+
+/*
+ * Types defined here are used to describe an audio source or sink at internal
+ * framework interfaces (audio policy, patch panel) or at the audio HAL.
+ * Sink and sources are grouped in a concept of “audio port” representing an
+ * audio end point at the edge of the system managed by the module exposing
+ * the interface.
+ */
+
+/** Audio port role: either source or sink */
+@export(name="audio_port_role_t", value_prefix="AUDIO_PORT_ROLE_")
+enum AudioPortRole : int32_t {
+ NONE,
+ SOURCE,
+ SINK,
+};
+
+/**
+ * Audio port type indicates if it is a session (e.g AudioTrack), a mix (e.g
+ * PlaybackThread output) or a physical device (e.g OUT_SPEAKER)
+ */
+@export(name="audio_port_type_t", value_prefix="AUDIO_PORT_TYPE_")
+enum AudioPortType : int32_t {
+ NONE,
+ DEVICE,
+ MIX,
+ SESSION,
+};
+
+/**
+ * Extension for audio port configuration structure when the audio port is a
+ * hardware device.
+ */
+struct AudioPortConfigDeviceExt {
+ AudioModuleHandle hwModule; // module the device is attached to
+ AudioDevice type; // device type (e.g OUT_SPEAKER)
+ uint8_t[32] address; // device address. "" if N/A
+};
+
+/**
+ * Extension for audio port configuration structure when the audio port is an
+ * audio session.
+ */
+struct AudioPortConfigSessionExt {
+ AudioSession session;
+};
+
+/**
+ * Flags indicating which fields are to be considered in AudioPortConfig.
+ */
+@export(name="", value_prefix="AUDIO_PORT_CONFIG_")
+enum AudioPortConfigMask : uint32_t {
+ SAMPLE_RATE = 0x1,
+ CHANNEL_MASK = 0x2,
+ FORMAT = 0x4,
+ GAIN = 0x8,
+};
+
+/**
+ * Audio port configuration structure used to specify a particular configuration
+ * of an audio port.
+ */
+struct AudioPortConfig {
+ AudioPortHandle id;
+ bitfield<AudioPortConfigMask> configMask;
+ uint32_t sampleRateHz;
+ bitfield<AudioChannelMask> channelMask;
+ AudioFormat format;
+ AudioGainConfig gain;
+ AudioPortType type; // type is used as a discriminator for Ext union
+ AudioPortRole role; // role is used as a discriminator for UseCase union
+ union Ext {
+ AudioPortConfigDeviceExt device;
+ struct AudioPortConfigMixExt {
+ AudioModuleHandle hwModule; // module the stream is attached to
+ AudioIoHandle ioHandle; // I/O handle of the input/output stream
+ union UseCase {
+ AudioStreamType stream;
+ AudioSource source;
+ } useCase;
+ } mix;
+ AudioPortConfigSessionExt session;
+ } ext;
+};
+
+/**
+ * Extension for audio port structure when the audio port is a hardware device.
+ */
+struct AudioPortDeviceExt {
+ AudioModuleHandle hwModule; // module the device is attached to
+ AudioDevice type;
+ /** 32 byte string identifying the port. */
+ uint8_t[32] address;
+};
+
+/**
+ * Latency class of the audio mix.
+ */
+@export(name="audio_mix_latency_class_t", value_prefix="AUDIO_LATENCY_")
+enum AudioMixLatencyClass : int32_t {
+ LOW,
+ NORMAL
+};
+
+struct AudioPortMixExt {
+ AudioModuleHandle hwModule; // module the stream is attached to
+ AudioIoHandle ioHandle; // I/O handle of the stream
+ AudioMixLatencyClass latencyClass;
+};
+
+/**
+ * Extension for audio port structure when the audio port is an audio session.
+ */
+struct AudioPortSessionExt {
+ AudioSession session;
+};
+
+struct AudioPort {
+ AudioPortHandle id;
+ AudioPortRole role;
+ string name;
+ vec<uint32_t> sampleRates;
+ vec<bitfield<AudioChannelMask>> channelMasks;
+ vec<AudioFormat> formats;
+ vec<AudioGain> gains;
+ AudioPortConfig activeConfig; // current audio port configuration
+ AudioPortType type; // type is used as a discriminator
+ union Ext {
+ AudioPortDeviceExt device;
+ AudioPortMixExt mix;
+ AudioPortSessionExt session;
+ } ext;
+};
+
+struct ThreadInfo {
+ int64_t pid;
+ int64_t tid;
+};
diff --git a/audio/common/all-versions/copyHAL.sh b/audio/common/all-versions/copyHAL.sh
new file mode 100755
index 0000000..d07012f
--- /dev/null
+++ b/audio/common/all-versions/copyHAL.sh
@@ -0,0 +1,204 @@
+#/usr/bin/env bash
+
+set -euo pipefail
+
+if (echo "$@" |grep -qe -h); then
+ echo "This script will generate a new HAL version identical to an other one."
+ echo "This helps creating the boilerplate for a new version."
+ echo
+ echo "USAGE: $0 [BASE_VERSION] [NEW_VERSION]"
+ echo " BASE_VERSION default value is the highest version currently existing"
+ echo " NEW_VERSION default value is BASE_VERSION + 1"
+ echo
+ echo "Example: to generate a V6.0 by copying V5, do: $0 5.0 6.0"
+ exit
+fi
+readonly HAL_DIRECTORY=hardware/interfaces/audio
+readonly HAL_VTS_DIRECTORY=core/all-versions/vts/functional
+readonly HAL_VTS_FILE=AudioPrimaryHidlHalTest.cpp
+readonly HAL_SERVICE_DIRECTORY=common/all-versions/default/service/
+readonly HAL_SERVICE_CPP=service.cpp
+
+readonly FWK_DIRECTORY=frameworks/av/media/libaudiohal
+readonly IMPL_DIRECTORY=impl
+readonly IMPL_FACTORYHAL=$IMPL_DIRECTORY/include/libaudiohal/FactoryHalHidl.h
+
+readonly VTS_DIRECTORY=test/vts-testcase/hal/audio
+readonly VTS_LIST=test/vts/tools/build/tasks/list/vts_test_lib_hidl_package_list.mk
+readonly WATCHDOG=frameworks/base/services/core/java/com/android/server/Watchdog.cpp
+readonly GSI_CURRENT=build/make/target/product/gsi/current.txt
+
+readonly BASE_VERSION=${1:-$(ls $ANDROID_BUILD_TOP/$HAL_DIRECTORY | grep -E '[0-9]+\.[0-9]+' |
+ sort -n |tail -n1)}
+readonly BASE_MAJOR_VERSION=${BASE_VERSION%.*}
+readonly BASE_MINOR_VERSION=${BASE_VERSION##*.}
+
+readonly NEW_VERSION="${2:-$((${BASE_MAJOR_VERSION} + 1)).0}"
+readonly NEW_MAJOR_VERSION=${NEW_VERSION%.*}
+readonly NEW_MINOR_VERSION=${NEW_VERSION##*.}
+
+
+readonly BASE_VERSION_REGEX="${BASE_MAJOR_VERSION}[._]${BASE_MINOR_VERSION}"
+readonly NEW_VERSION_REGEX="${NEW_MAJOR_VERSION}[._]${NEW_MINOR_VERSION}"
+
+readonly BASE_VERSION_ESCAPE="${BASE_MAJOR_VERSION}\.${BASE_MINOR_VERSION}"
+readonly BASE_VERSION_UNDERSCORE="${BASE_MAJOR_VERSION}_${BASE_MINOR_VERSION}"
+readonly NEW_VERSION_UNDERSCORE="${NEW_MAJOR_VERSION}_${NEW_MINOR_VERSION}"
+updateVersion() {
+ if [ $1 == "-e" ]; then
+ local -r REGEX="$2"; shift 2
+ else
+ local -r REGEX="$BASE_VERSION_REGEX"
+ fi
+ awk -i inplace -e "{if (!/$REGEX/) print; else {
+ if (original_before) print
+ if (original_after) original_line=\$0;
+
+ gsub(/$BASE_VERSION_ESCAPE/,\"$NEW_VERSION\");
+ gsub(/$BASE_VERSION_UNDERSCORE/,\"$NEW_VERSION_UNDERSCORE\");
+ gsub(/MAJOR_VERSION=$BASE_MAJOR_VERSION/,
+ \"MAJOR_VERSION=$NEW_MAJOR_VERSION\");
+ gsub(/MINOR_VERSION=$BASE_MINOR_VERSION/,
+ \"MINOR_VERSION=$NEW_MINOR_VERSION\");
+
+ print
+ if (original_after) print original_line
+ }}" "$@"
+}
+
+updateAudioVersion() {
+ updateVersion -e "audio.*$BASE_VERSION_REGEX" "$@"
+}
+
+updateLicenceDates() {
+ # Update date on the 2 first lines
+ sed -i "1,2 s/20[0-9][0-9]/$(date +"%Y")/g" "$@"
+}
+
+echo "Creating new audio HAL V$NEW_VERSION based on V$BASE_VERSION"
+echo "Press Ctrl-C to cancel, Enter to continue"
+read
+
+MODIFIED=
+runIfNeeded() {
+ local -r TARGET=$1; shift
+ cd $ANDROID_BUILD_TOP/$TARGET
+ if grep -q -r "audio.*$NEW_VERSION_REGEX"; then
+ echo " Skipping $TARGET as already up to date"
+ else
+ echo " Updating $PWD"
+ MODIFIED+=$'\n - '$TARGET
+ "$@"
+ fi
+}
+
+createHALVersion() {
+ local -r DIRS=". common effect"
+ local COPY=
+ echo "Copy $BASE_VERSION to $NEW_VERSION in $DIRS"
+ for DIR in $DIRS; do
+ cp -Tar $DIR/$BASE_VERSION $DIR/$NEW_VERSION
+ COPY+=" $DIR/$NEW_VERSION"
+ done
+
+ echo "Replacing $BASE_VERSION by $NEW_VERSION in the copied files"
+ updateVersion $(find $COPY -type f)
+ updateLicenceDates $(find $COPY -type f)
+
+ echo "Update implementation and VTS generic code"
+ local -r FILES="*/all-versions/default/Android.bp */all-versions/vts/functional/Android.bp"
+ updateVersion -v original_before=1 -v RS= -v ORS='\n\n' $FILES
+ sed -i '${/^$/d}' $FILES # Remove \n at the end of the files
+
+ updateVersion -v original_before=1 $HAL_SERVICE_DIRECTORY/Android.bp
+
+ updateVersion -e "audio::.*$BASE_VERSION_REGEX" -v original_after=1 \
+ $HAL_SERVICE_DIRECTORY/$HAL_SERVICE_CPP
+ updateVersion -e "audio\/.*$BASE_VERSION_REGEX" -v original_before=1 \
+ $HAL_SERVICE_DIRECTORY/$HAL_SERVICE_CPP
+
+ local -r HAL_VTS_PATH=$HAL_VTS_DIRECTORY/$NEW_VERSION/$HAL_VTS_FILE
+ mkdir -p $(dirname $HAL_VTS_PATH)
+ cat > $HAL_VTS_PATH <<EOF
+/*
+ * Copyright (C) $(date +"%Y") 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.
+ */
+
+// pull in all the <= $BASE_VERSION tests
+#include "$BASE_VERSION/$(basename AudioPrimaryHidlHalTest.cpp)"
+EOF
+
+ echo "New HAL version $NEW_VERSION successfully created"
+}
+
+echo "Creating new audio HAL definition, default impl and VTS"
+runIfNeeded $HAL_DIRECTORY createHALVersion
+
+
+createFrameworkAdapter() {
+ updateVersion -v original_before=1 Android.bp
+ updateVersion -v original_before=1 -v RS= -v ORS='\n\n' $IMPL_FACTORYHAL/Android.bp
+ updateVersion -v original_after=1 $IMPL_FACTORYHAL
+}
+echo "Now creating the framework adapter version"
+runIfNeeded $FWK_DIRECTORY createFrameworkAdapter
+
+createVTSXML() {
+ cp -Tar V$BASE_VERSION_UNDERSCORE V$NEW_VERSION_UNDERSCORE
+ cp -Tar effect/{V$BASE_VERSION_UNDERSCORE,V$NEW_VERSION_UNDERSCORE}
+ local -r FILES=$(find {.,effect}/V$NEW_VERSION_UNDERSCORE -type f)
+ updateVersion $FILES
+ updateLicenceDates $FILES
+}
+echo "Now update VTS XML"
+runIfNeeded $VTS_DIRECTORY createVTSXML
+
+echo "Now register new VTS"
+runIfNeeded $(dirname $VTS_LIST) updateAudioVersion -v original_before=1 $(basename $VTS_LIST)
+
+echo "Now update watchdog"
+runIfNeeded $(dirname $WATCHDOG) updateAudioVersion -v original_before=1 $(basename $WATCHDOG)
+
+echo "Now update GSI current.txt"
+runIfNeeded $(dirname $GSI_CURRENT) update-vndk-list.sh
+
+if ! [ "$MODIFIED" ]; then
+ echo
+ echo "$NEW_VERSION already exist, nothing to do"
+ exit
+fi
+
+cat << EOF
+
+All File generated successfully. Please submit a patch in all those directories: $MODIFIED
+
+-----------------------------------------------------------
+WHAT WAS *NOT* DONE, and you need to do now:
+ 1) You need to choose if the new HAL is optional or not for new devices.
+ Either add or replace $BASE_VERSION by $NEW_VERSION in
+ compatibility_matrices/compatibility_matrix.current.xml
+ Do not forget to update both the "audio" and "audio.effects" HAL'
+
+ 2) Then you need to choose a device to update its audio HAL implementation:
+ a) Update the HAL manifest of your device: open your device manifest.xml
+ and replace $BASE_VERSION by $NEW_VERSION for both
+ - android.hardware.audio
+ - android.hardware.audio.effect
+ b) Go to your device device.mk (usually next to the manifest) and replace:
+ - android.hardware.audio@$BASE_VERSION-impl by
+ android.hardware.audio@$NEW_VERSION-impl
+ - android.hardware.audio.effect@$BASE_VERSION-impl by
+ android.hardware.audio.effect@$NEW_VERSION-impl
+EOF
diff --git a/audio/common/all-versions/default/Android.bp b/audio/common/all-versions/default/Android.bp
index c0bd34c..0eb4a71 100644
--- a/audio/common/all-versions/default/Android.bp
+++ b/audio/common/all-versions/default/Android.bp
@@ -69,7 +69,6 @@
cc_library_shared {
name: "android.hardware.audio.common@2.0-util",
defaults: ["android.hardware.audio.common-util_default"],
-
shared_libs: [
"android.hardware.audio.common@2.0",
],
@@ -83,7 +82,6 @@
cc_library_shared {
name: "android.hardware.audio.common@4.0-util",
defaults: ["android.hardware.audio.common-util_default"],
-
shared_libs: [
"android.hardware.audio.common@4.0",
],
@@ -97,7 +95,6 @@
cc_library_shared {
name: "android.hardware.audio.common@5.0-util",
defaults: ["android.hardware.audio.common-util_default"],
-
shared_libs: [
"android.hardware.audio.common@5.0",
],
@@ -107,3 +104,16 @@
"-include common/all-versions/VersionMacro.h",
]
}
+
+cc_library_shared {
+ name: "android.hardware.audio.common@6.0-util",
+ defaults: ["android.hardware.audio.common-util_default"],
+ shared_libs: [
+ "android.hardware.audio.common@6.0",
+ ],
+ cflags: [
+ "-DMAJOR_VERSION=6",
+ "-DMINOR_VERSION=0",
+ "-include common/all-versions/VersionMacro.h",
+ ]
+}
diff --git a/audio/common/all-versions/default/service/Android.bp b/audio/common/all-versions/default/service/Android.bp
new file mode 100644
index 0000000..4565730
--- /dev/null
+++ b/audio/common/all-versions/default/service/Android.bp
@@ -0,0 +1,51 @@
+cc_binary {
+ name: "android.hardware.audio.service",
+
+ init_rc: ["android.hardware.audio.service.rc"],
+ relative_install_path: "hw",
+ vendor: true,
+ // Only support 32 bit as the binary must always be installed at the same
+ // location for init to start it and the build system does not support
+ // having two binaries installable to the same location even if they are
+ // not installed in the same build.
+ compile_multilib: "32",
+ srcs: ["service.cpp"],
+
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ ],
+
+ shared_libs: [
+ "libcutils",
+ "libbinder",
+ "libhidlbase",
+ "liblog",
+ "libutils",
+ "libhardware",
+ "android.hardware.audio@2.0",
+ "android.hardware.audio@4.0",
+ "android.hardware.audio@5.0",
+ "android.hardware.audio@6.0",
+ "android.hardware.audio.common@2.0",
+ "android.hardware.audio.common@4.0",
+ "android.hardware.audio.common@5.0",
+ "android.hardware.audio.common@6.0",
+ "android.hardware.audio.effect@2.0",
+ "android.hardware.audio.effect@4.0",
+ "android.hardware.audio.effect@5.0",
+ "android.hardware.audio.effect@6.0",
+ "android.hardware.bluetooth.a2dp@1.0",
+ "android.hardware.bluetooth.audio@2.0",
+ "android.hardware.soundtrigger@2.0",
+ "android.hardware.soundtrigger@2.1",
+ "android.hardware.soundtrigger@2.2",
+ ],
+}
+
+// Legacy service name, use android.hardware.audio.service instead
+phony {
+ name: "android.hardware.audio@2.0-service",
+ required: ["android.hardware.audio.service"],
+}
diff --git a/audio/common/all-versions/default/service/Android.mk b/audio/common/all-versions/default/service/Android.mk
deleted file mode 100644
index 236f1fd..0000000
--- a/audio/common/all-versions/default/service/Android.mk
+++ /dev/null
@@ -1,63 +0,0 @@
-#
-# Copyright (C) 2016 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.
-
-
-LOCAL_PATH := $(call my-dir)
-
-#
-# Service
-#
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := android.hardware.audio@2.0-service
-LOCAL_INIT_RC := android.hardware.audio@2.0-service.rc
-LOCAL_MODULE_RELATIVE_PATH := hw
-LOCAL_PROPRIETARY_MODULE := true
-LOCAL_SRC_FILES := \
- service.cpp
-
-LOCAL_CFLAGS := -Wall -Werror
-
-LOCAL_SHARED_LIBRARIES := \
- libcutils \
- libbinder \
- libhidlbase \
- liblog \
- libutils \
- libhardware \
- android.hardware.audio@2.0 \
- android.hardware.audio@4.0 \
- android.hardware.audio@5.0 \
- android.hardware.audio.common@2.0 \
- android.hardware.audio.common@4.0 \
- android.hardware.audio.common@5.0 \
- android.hardware.audio.effect@2.0 \
- android.hardware.audio.effect@4.0 \
- android.hardware.audio.effect@5.0 \
- android.hardware.bluetooth.a2dp@1.0 \
- android.hardware.bluetooth.audio@2.0 \
- android.hardware.soundtrigger@2.0 \
- android.hardware.soundtrigger@2.1 \
- android.hardware.soundtrigger@2.2
-
-# Can not switch to Android.bp until AUDIOSERVER_MULTILIB
-# is deprecated as build config variable are not supported
-ifeq ($(strip $(AUDIOSERVER_MULTILIB)),)
-LOCAL_MULTILIB := 32
-else
-LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
-endif
-
-include $(BUILD_EXECUTABLE)
diff --git a/audio/common/all-versions/default/service/android.hardware.audio@2.0-service.rc b/audio/common/all-versions/default/service/android.hardware.audio.service.rc
similarity index 81%
rename from audio/common/all-versions/default/service/android.hardware.audio@2.0-service.rc
rename to audio/common/all-versions/default/service/android.hardware.audio.service.rc
index 72b4d19..63d2542 100644
--- a/audio/common/all-versions/default/service/android.hardware.audio@2.0-service.rc
+++ b/audio/common/all-versions/default/service/android.hardware.audio.service.rc
@@ -1,4 +1,4 @@
-service vendor.audio-hal-2-0 /vendor/bin/hw/android.hardware.audio@2.0-service
+service vendor.audio-hal /vendor/bin/hw/android.hardware.audio.service
class hal
user audioserver
# media gid needed for /dev/fm (radio) and for /data/misc/media (tee)
diff --git a/audio/common/all-versions/default/service/service.cpp b/audio/common/all-versions/default/service/service.cpp
index 2a6571b..2730f3b 100644
--- a/audio/common/all-versions/default/service/service.cpp
+++ b/audio/common/all-versions/default/service/service.cpp
@@ -19,9 +19,11 @@
#include <android/hardware/audio/2.0/IDevicesFactory.h>
#include <android/hardware/audio/4.0/IDevicesFactory.h>
#include <android/hardware/audio/5.0/IDevicesFactory.h>
+#include <android/hardware/audio/6.0/IDevicesFactory.h>
#include <android/hardware/audio/effect/2.0/IEffectsFactory.h>
#include <android/hardware/audio/effect/4.0/IEffectsFactory.h>
#include <android/hardware/audio/effect/5.0/IEffectsFactory.h>
+#include <android/hardware/audio/effect/6.0/IEffectsFactory.h>
#include <android/hardware/bluetooth/a2dp/1.0/IBluetoothAudioOffload.h>
#include <android/hardware/bluetooth/audio/2.0/IBluetoothAudioProvidersFactory.h>
#include <android/hardware/soundtrigger/2.0/ISoundTriggerHw.h>
@@ -59,16 +61,22 @@
}
configureRpcThreadpool(16, true /*callerWillJoin*/);
- LOG_ALWAYS_FATAL_IF((registerPassthroughServiceImplementations<audio::V5_0::IDevicesFactory,
- audio::V4_0::IDevicesFactory,
- audio::V2_0::IDevicesFactory>()),
+ // Keep versions on a separate line for easier parsing
+ // clang-format off
+ LOG_ALWAYS_FATAL_IF((registerPassthroughServiceImplementations<
+ audio::V6_0::IDevicesFactory,
+ audio::V5_0::IDevicesFactory,
+ audio::V4_0::IDevicesFactory,
+ audio::V2_0::IDevicesFactory>()),
"Could not register audio core API");
- LOG_ALWAYS_FATAL_IF(
- (registerPassthroughServiceImplementations<audio::effect::V5_0::IEffectsFactory,
- audio::effect::V4_0::IEffectsFactory,
- audio::effect::V2_0::IEffectsFactory>()),
- "Could not register audio effect API");
+ LOG_ALWAYS_FATAL_IF((registerPassthroughServiceImplementations<
+ audio::effect::V6_0::IEffectsFactory,
+ audio::effect::V5_0::IEffectsFactory,
+ audio::effect::V4_0::IEffectsFactory,
+ audio::effect::V2_0::IEffectsFactory>()),
+ "Could not register audio effect API");
+ // clang-format on
ALOGW_IF((registerPassthroughServiceImplementations<soundtrigger::V2_2::ISoundTriggerHw,
soundtrigger::V2_1::ISoundTriggerHw,
diff --git a/audio/core/all-versions/default/Android.bp b/audio/core/all-versions/default/Android.bp
index c4548c3..b8b7fee 100644
--- a/audio/core/all-versions/default/Android.bp
+++ b/audio/core/all-versions/default/Android.bp
@@ -43,13 +43,11 @@
cc_library_shared {
name: "android.hardware.audio@2.0-impl",
defaults: ["android.hardware.audio-impl_default"],
-
shared_libs: [
"android.hardware.audio@2.0",
"android.hardware.audio.common@2.0",
"android.hardware.audio.common@2.0-util",
],
-
cflags: [
"-DMAJOR_VERSION=2",
"-DMINOR_VERSION=0",
@@ -66,7 +64,6 @@
"android.hardware.audio.common@4.0",
"android.hardware.audio.common@4.0-util",
],
-
cflags: [
"-DMAJOR_VERSION=4",
"-DMINOR_VERSION=0",
@@ -77,16 +74,29 @@
cc_library_shared {
name: "android.hardware.audio@5.0-impl",
defaults: ["android.hardware.audio-impl_default"],
-
shared_libs: [
"android.hardware.audio@5.0",
"android.hardware.audio.common@5.0",
"android.hardware.audio.common@5.0-util",
],
-
cflags: [
"-DMAJOR_VERSION=5",
"-DMINOR_VERSION=0",
"-include common/all-versions/VersionMacro.h",
]
}
+
+cc_library_shared {
+ name: "android.hardware.audio@6.0-impl",
+ defaults: ["android.hardware.audio-impl_default"],
+ shared_libs: [
+ "android.hardware.audio@6.0",
+ "android.hardware.audio.common@6.0",
+ "android.hardware.audio.common@6.0-util",
+ ],
+ cflags: [
+ "-DMAJOR_VERSION=6",
+ "-DMINOR_VERSION=0",
+ "-include common/all-versions/VersionMacro.h",
+ ]
+}
diff --git a/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp
index 022f75e..2703b2b 100644
--- a/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp
+++ b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp
@@ -29,18 +29,21 @@
TEST_F(AudioHidlTest, OpenPrimaryDeviceUsingGetDevice) {
doc::test("Calling openDevice(\"primary\") should return the primary device.");
- {
- Result result;
- sp<IDevice> baseDevice;
- ASSERT_OK(devicesFactory->openDevice("primary", returnIn(result, baseDevice)));
- ASSERT_OK(result);
- ASSERT_TRUE(baseDevice != nullptr);
+ struct WaitExecutor {
+ ~WaitExecutor() { waitForDeviceDestruction(); }
+ } waitExecutor; // Make sure we wait for the device destruction on exiting from the test.
+ Result result;
+ sp<IDevice> baseDevice;
+ ASSERT_OK(devicesFactory->openDevice("primary", returnIn(result, baseDevice)));
+ if (result != Result::OK && isPrimaryDeviceOptional()) {
+ GTEST_SKIP() << "No primary device on this factory"; // returns
+ }
+ ASSERT_OK(result);
+ ASSERT_TRUE(baseDevice != nullptr);
- Return<sp<IPrimaryDevice>> primaryDevice = IPrimaryDevice::castFrom(baseDevice);
- ASSERT_TRUE(primaryDevice.isOk());
- ASSERT_TRUE(sp<IPrimaryDevice>(primaryDevice) != nullptr);
- } // Destroy local IDevice proxy
- waitForDeviceDestruction();
+ Return<sp<IPrimaryDevice>> primaryDevice = IPrimaryDevice::castFrom(baseDevice);
+ ASSERT_TRUE(primaryDevice.isOk());
+ ASSERT_TRUE(sp<IPrimaryDevice>(primaryDevice) != nullptr);
}
//////////////////////////////////////////////////////////////////////////////
@@ -117,6 +120,10 @@
ASSERT_NE(0U, activeMicrophones.size());
}
stream->close();
+ // Workaround for b/139329877. Ensures the stream gets closed on the audio hal side.
+ stream.clear();
+ IPCThreadState::self()->flushCommands();
+ usleep(1000);
if (efGroup) {
EventFlag::deleteEventFlag(&efGroup);
}
@@ -148,6 +155,7 @@
// initial state. To workaround this, destroy the HAL at the end of this test.
device.clear();
waitForDeviceDestruction();
+ ASSERT_NO_FATAL_FAILURE(initPrimaryDevice());
}
static void testGetDevices(IStream* stream, AudioDevice expectedDevice) {
diff --git a/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp
new file mode 100644
index 0000000..6314ea7
--- /dev/null
+++ b/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+// pull in all the <= 5.0 tests
+#include "5.0/AudioPrimaryHidlHalTest.cpp"
diff --git a/audio/core/all-versions/vts/functional/Android.bp b/audio/core/all-versions/vts/functional/Android.bp
index c73970f..1818e36 100644
--- a/audio/core/all-versions/vts/functional/Android.bp
+++ b/audio/core/all-versions/vts/functional/Android.bp
@@ -84,3 +84,20 @@
"-include common/all-versions/VersionMacro.h",
]
}
+
+cc_test {
+ name: "VtsHalAudioV6_0TargetTest",
+ defaults: ["VtsHalAudioTargetTest_defaults"],
+ srcs: [
+ "6.0/AudioPrimaryHidlHalTest.cpp",
+ ],
+ static_libs: [
+ "android.hardware.audio@6.0",
+ "android.hardware.audio.common@6.0",
+ ],
+ cflags: [
+ "-DMAJOR_VERSION=6",
+ "-DMINOR_VERSION=0",
+ "-include common/all-versions/VersionMacro.h",
+ ]
+}
diff --git a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
index 7f8b6a0..fb96323 100644
--- a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
+++ b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
@@ -215,25 +215,32 @@
// Test all audio devices
class AudioHidlTest : public AudioPolicyConfigTest {
public:
- void SetUp() override {
- ASSERT_NO_FATAL_FAILURE(HidlTest::SetUp()); // setup base
+ static void SetUpTestSuite() {
+ devicesFactory = ::testing::VtsHalHidlTargetTestBase::getService<IDevicesFactory>(
+ environment->getServiceName<IDevicesFactory>());
+ }
- if (devicesFactory == nullptr) {
- environment->registerTearDown([] { devicesFactory.clear(); });
- devicesFactory = ::testing::VtsHalHidlTargetTestBase::getService<IDevicesFactory>(
- environment->getServiceName<IDevicesFactory>("default"));
- }
- ASSERT_TRUE(devicesFactory != nullptr);
- }
+ static void TearDownTestSuite() { devicesFactory.clear(); }
+
+ void SetUp() override {
+ ASSERT_NO_FATAL_FAILURE(AudioPolicyConfigTest::SetUp()); // setup base
+ // Failures during SetUpTestSuite do not cause test termination.
+ ASSERT_TRUE(devicesFactory != nullptr);
+ }
protected:
// Cache the devicesFactory retrieval to speed up each test by ~0.5s
static sp<IDevicesFactory> devicesFactory;
+
+ static bool isPrimaryDeviceOptional() {
+ // It's OK not to have "primary" device on non-default audio HAL service.
+ return environment->getServiceName<IDevicesFactory>() != kDefaultServiceName;
+ }
};
sp<IDevicesFactory> AudioHidlTest::devicesFactory;
TEST_F(AudioHidlTest, GetAudioDevicesFactoryService) {
- doc::test("Test the getService (called in SetUp)");
+ doc::test("Test the getService");
}
TEST_F(AudioHidlTest, OpenDeviceInvalidParameter) {
@@ -257,23 +264,31 @@
// Test the primary device
class AudioPrimaryHidlTest : public AudioHidlTest {
public:
- /** Primary HAL test are NOT thread safe. */
+ static void SetUpTestSuite() {
+ ASSERT_NO_FATAL_FAILURE(AudioHidlTest::SetUpTestSuite());
+ ASSERT_NO_FATAL_FAILURE(initPrimaryDevice());
+ }
+
+ static void TearDownTestSuite() {
+ device.clear();
+ AudioHidlTest::TearDownTestSuite();
+ }
+
void SetUp() override {
ASSERT_NO_FATAL_FAILURE(AudioHidlTest::SetUp()); // setup base
-
- if (device == nullptr) {
- initPrimaryDevice();
- ASSERT_TRUE(device != nullptr);
- environment->registerTearDown([] { device.clear(); });
+ if (device == nullptr && isPrimaryDeviceOptional()) {
+ GTEST_SKIP() << "No primary device on this factory";
}
+ ASSERT_TRUE(device != nullptr);
}
protected:
// Cache the device opening to speed up each test by ~0.5s
static sp<IPrimaryDevice> device;
- private:
- void initPrimaryDevice() {
+ static void initPrimaryDevice() {
+ // Failures during test suite set up do not cause test termination.
+ ASSERT_TRUE(devicesFactory != nullptr);
Result result;
#if MAJOR_VERSION == 2
sp<IDevice> baseDevice;
@@ -292,7 +307,7 @@
sp<IPrimaryDevice> AudioPrimaryHidlTest::device;
TEST_F(AudioPrimaryHidlTest, OpenPrimaryDevice) {
- doc::test("Test the openDevice (called in SetUp)");
+ doc::test("Test the openDevice (called during setup)");
}
TEST_F(AudioPrimaryHidlTest, Init) {
@@ -692,6 +707,7 @@
if (open) {
ASSERT_OK(stream->close());
}
+ AudioConfigPrimaryTest::TearDown();
}
protected:
@@ -704,8 +720,9 @@
////////////////////////////// openOutputStream //////////////////////////////
class OutputStreamTest : public OpenStreamTest<IStreamOut> {
- virtual void SetUp() override {
+ void SetUp() override {
ASSERT_NO_FATAL_FAILURE(OpenStreamTest::SetUp()); // setup base
+ if (IsSkipped()) return; // do not attempt to use 'device'
address.device = AudioDevice::OUT_DEFAULT;
const AudioConfig& config = GetParam();
// TODO: test all flag combination
@@ -752,8 +769,9 @@
////////////////////////////// openInputStream //////////////////////////////
class InputStreamTest : public OpenStreamTest<IStreamIn> {
- virtual void SetUp() override {
+ void SetUp() override {
ASSERT_NO_FATAL_FAILURE(OpenStreamTest::SetUp()); // setup base
+ if (IsSkipped()) return; // do not attempt to use 'device'
address.device = AudioDevice::IN_DEFAULT;
const AudioConfig& config = GetParam();
// TODO: test all supported flags and source
diff --git a/audio/effect/6.0/Android.bp b/audio/effect/6.0/Android.bp
new file mode 100644
index 0000000..b6184f3
--- /dev/null
+++ b/audio/effect/6.0/Android.bp
@@ -0,0 +1,33 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.audio.effect@6.0",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "types.hal",
+ "IAcousticEchoCancelerEffect.hal",
+ "IAutomaticGainControlEffect.hal",
+ "IBassBoostEffect.hal",
+ "IDownmixEffect.hal",
+ "IEffect.hal",
+ "IEffectBufferProviderCallback.hal",
+ "IEffectsFactory.hal",
+ "IEnvironmentalReverbEffect.hal",
+ "IEqualizerEffect.hal",
+ "ILoudnessEnhancerEffect.hal",
+ "INoiseSuppressionEffect.hal",
+ "IPresetReverbEffect.hal",
+ "IVirtualizerEffect.hal",
+ "IVisualizerEffect.hal",
+ ],
+ interfaces: [
+ "android.hardware.audio.common@6.0",
+ "android.hidl.base@1.0",
+ "android.hidl.safe_union@1.0",
+ ],
+ gen_java: false,
+ gen_java_constants: true,
+}
diff --git a/audio/effect/6.0/IAcousticEchoCancelerEffect.hal b/audio/effect/6.0/IAcousticEchoCancelerEffect.hal
new file mode 100644
index 0000000..f7d769f
--- /dev/null
+++ b/audio/effect/6.0/IAcousticEchoCancelerEffect.hal
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2019 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.effect@6.0;
+
+import android.hardware.audio.common@6.0;
+import IEffect;
+
+interface IAcousticEchoCancelerEffect extends IEffect {
+ /**
+ * Sets echo delay value in milliseconds.
+ */
+ setEchoDelay(uint32_t echoDelayMs) generates (Result retval);
+
+ /**
+ * Gets echo delay value in milliseconds.
+ */
+ getEchoDelay() generates (Result retval, uint32_t echoDelayMs);
+};
diff --git a/audio/effect/6.0/IAutomaticGainControlEffect.hal b/audio/effect/6.0/IAutomaticGainControlEffect.hal
new file mode 100644
index 0000000..d264cd4
--- /dev/null
+++ b/audio/effect/6.0/IAutomaticGainControlEffect.hal
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2019 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.effect@6.0;
+
+import android.hardware.audio.common@6.0;
+import IEffect;
+
+interface IAutomaticGainControlEffect extends IEffect {
+ /**
+ * Sets target level in millibels.
+ */
+ setTargetLevel(int16_t targetLevelMb) generates (Result retval);
+
+ /**
+ * Gets target level.
+ */
+ getTargetLevel() generates (Result retval, int16_t targetLevelMb);
+
+ /**
+ * Sets gain in the compression range in millibels.
+ */
+ setCompGain(int16_t compGainMb) generates (Result retval);
+
+ /**
+ * Gets gain in the compression range.
+ */
+ getCompGain() generates (Result retval, int16_t compGainMb);
+
+ /**
+ * Enables or disables limiter.
+ */
+ setLimiterEnabled(bool enabled) generates (Result retval);
+
+ /**
+ * Returns whether limiter is enabled.
+ */
+ isLimiterEnabled() generates (Result retval, bool enabled);
+
+ struct AllProperties {
+ int16_t targetLevelMb;
+ int16_t compGainMb;
+ bool limiterEnabled;
+ };
+
+ /**
+ * Sets all properties at once.
+ */
+ setAllProperties(AllProperties properties) generates (Result retval);
+
+ /**
+ * Gets all properties at once.
+ */
+ getAllProperties() generates (Result retval, AllProperties properties);
+};
diff --git a/audio/effect/6.0/IBassBoostEffect.hal b/audio/effect/6.0/IBassBoostEffect.hal
new file mode 100644
index 0000000..91c4092
--- /dev/null
+++ b/audio/effect/6.0/IBassBoostEffect.hal
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2019 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.effect@6.0;
+
+import android.hardware.audio.common@6.0;
+import IEffect;
+
+interface IBassBoostEffect extends IEffect {
+ /**
+ * Returns whether setting bass boost strength is supported.
+ */
+ isStrengthSupported() generates (Result retval, bool strengthSupported);
+
+ enum StrengthRange : uint16_t {
+ MIN = 0,
+ MAX = 1000
+ };
+
+ /**
+ * Sets bass boost strength.
+ *
+ * @param strength strength of the effect. The valid range for strength
+ * strength is [0, 1000], where 0 per mille designates the
+ * mildest effect and 1000 per mille designates the
+ * strongest.
+ * @return retval operation completion status.
+ */
+ setStrength(uint16_t strength) generates (Result retval);
+
+ /**
+ * Gets virtualization strength.
+ */
+ getStrength() generates (Result retval, uint16_t strength);
+};
diff --git a/audio/effect/6.0/IDownmixEffect.hal b/audio/effect/6.0/IDownmixEffect.hal
new file mode 100644
index 0000000..e3a38e2
--- /dev/null
+++ b/audio/effect/6.0/IDownmixEffect.hal
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2019 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.effect@6.0;
+
+import android.hardware.audio.common@6.0;
+import IEffect;
+
+interface IDownmixEffect extends IEffect {
+ enum Type : int32_t {
+ STRIP, // throw away the extra channels
+ FOLD // mix the extra channels with FL/FR
+ };
+
+ /**
+ * Sets the current downmix preset.
+ */
+ setType(Type preset) generates (Result retval);
+
+ /**
+ * Gets the current downmix preset.
+ */
+ getType() generates (Result retval, Type preset);
+};
diff --git a/audio/effect/6.0/IEffect.hal b/audio/effect/6.0/IEffect.hal
new file mode 100644
index 0000000..b35afee
--- /dev/null
+++ b/audio/effect/6.0/IEffect.hal
@@ -0,0 +1,418 @@
+/*
+ * Copyright (C) 2019 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.effect@6.0;
+
+import android.hardware.audio.common@6.0;
+import IEffectBufferProviderCallback;
+
+interface IEffect {
+ /**
+ * Initialize effect engine--all configurations return to default.
+ *
+ * @return retval operation completion status.
+ */
+ @entry
+ init() generates (Result retval);
+
+ /**
+ * Apply new audio parameters configurations for input and output buffers.
+ * The provider callbacks may be empty, but in this case the buffer
+ * must be provided in the EffectConfig structure.
+ *
+ * @param config configuration descriptor.
+ * @param inputBufferProvider optional buffer provider reference.
+ * @param outputBufferProvider optional buffer provider reference.
+ * @return retval operation completion status.
+ */
+ setConfig(EffectConfig config,
+ IEffectBufferProviderCallback inputBufferProvider,
+ IEffectBufferProviderCallback outputBufferProvider)
+ generates (Result retval);
+
+ /**
+ * Reset the effect engine. Keep configuration but resets state and buffer
+ * content.
+ *
+ * @return retval operation completion status.
+ */
+ reset() generates (Result retval);
+
+ /**
+ * Enable processing.
+ *
+ * @return retval operation completion status.
+ */
+ @callflow(next={"prepareForProcessing"})
+ enable() generates (Result retval);
+
+ /**
+ * Disable processing.
+ *
+ * @return retval operation completion status.
+ */
+ @callflow(next={"close"})
+ disable() generates (Result retval);
+
+ /**
+ * Set the rendering device the audio output path is connected to. The
+ * effect implementation must set EFFECT_FLAG_DEVICE_IND flag in its
+ * descriptor to receive this command when the device changes.
+ *
+ * Note: this method is only supported for effects inserted into
+ * the output chain.
+ *
+ * @param device output device specification.
+ * @return retval operation completion status.
+ */
+ setDevice(bitfield<AudioDevice> device) generates (Result retval);
+
+ /**
+ * Set and get volume. Used by audio framework to delegate volume control to
+ * effect engine. The effect implementation must set EFFECT_FLAG_VOLUME_CTRL
+ * flag in its descriptor to receive this command. The effect engine must
+ * return the volume that should be applied before the effect is
+ * processed. The overall volume (the volume actually applied by the effect
+ * engine multiplied by the returned value) should match the value indicated
+ * in the command.
+ *
+ * @param volumes vector containing volume for each channel defined in
+ * EffectConfig for output buffer expressed in 8.24 fixed
+ * point format.
+ * @return result updated volume values.
+ * @return retval operation completion status.
+ */
+ setAndGetVolume(vec<uint32_t> volumes)
+ generates (Result retval, vec<uint32_t> result);
+
+ /**
+ * Notify the effect of the volume change. The effect implementation must
+ * set EFFECT_FLAG_VOLUME_IND flag in its descriptor to receive this
+ * command.
+ *
+ * @param volumes vector containing volume for each channel defined in
+ * EffectConfig for output buffer expressed in 8.24 fixed
+ * point format.
+ * @return retval operation completion status.
+ */
+ volumeChangeNotification(vec<uint32_t> volumes)
+ generates (Result retval);
+
+ /**
+ * Set the audio mode. The effect implementation must set
+ * EFFECT_FLAG_AUDIO_MODE_IND flag in its descriptor to receive this command
+ * when the audio mode changes.
+ *
+ * @param mode desired audio mode.
+ * @return retval operation completion status.
+ */
+ setAudioMode(AudioMode mode) generates (Result retval);
+
+ /**
+ * Apply new audio parameters configurations for input and output buffers of
+ * reverse stream. An example of reverse stream is the echo reference
+ * supplied to an Acoustic Echo Canceler.
+ *
+ * @param config configuration descriptor.
+ * @param inputBufferProvider optional buffer provider reference.
+ * @param outputBufferProvider optional buffer provider reference.
+ * @return retval operation completion status.
+ */
+ setConfigReverse(EffectConfig config,
+ IEffectBufferProviderCallback inputBufferProvider,
+ IEffectBufferProviderCallback outputBufferProvider)
+ generates (Result retval);
+
+ /**
+ * Set the capture device the audio input path is connected to. The effect
+ * implementation must set EFFECT_FLAG_DEVICE_IND flag in its descriptor to
+ * receive this command when the device changes.
+ *
+ * Note: this method is only supported for effects inserted into
+ * the input chain.
+ *
+ * @param device input device specification.
+ * @return retval operation completion status.
+ */
+ setInputDevice(bitfield<AudioDevice> device) generates (Result retval);
+
+ /**
+ * Read audio parameters configurations for input and output buffers.
+ *
+ * @return retval operation completion status.
+ * @return config configuration descriptor.
+ */
+ getConfig() generates (Result retval, EffectConfig config);
+
+ /**
+ * Read audio parameters configurations for input and output buffers of
+ * reverse stream.
+ *
+ * @return retval operation completion status.
+ * @return config configuration descriptor.
+ */
+ getConfigReverse() generates (Result retval, EffectConfig config);
+
+ /**
+ * Queries for supported combinations of main and auxiliary channels
+ * (e.g. for a multi-microphone noise suppressor).
+ *
+ * @param maxConfigs maximum number of the combinations to return.
+ * @return retval absence of the feature support is indicated using
+ * NOT_SUPPORTED code. RESULT_TOO_BIG is returned if
+ * the number of supported combinations exceeds 'maxConfigs'.
+ * @return result list of configuration descriptors.
+ */
+ getSupportedAuxChannelsConfigs(uint32_t maxConfigs)
+ generates (Result retval, vec<EffectAuxChannelsConfig> result);
+
+ /**
+ * Retrieves the current configuration of main and auxiliary channels.
+ *
+ * @return retval absence of the feature support is indicated using
+ * NOT_SUPPORTED code.
+ * @return result configuration descriptor.
+ */
+ getAuxChannelsConfig()
+ generates (Result retval, EffectAuxChannelsConfig result);
+
+ /**
+ * Sets the current configuration of main and auxiliary channels.
+ *
+ * @return retval operation completion status; absence of the feature
+ * support is indicated using NOT_SUPPORTED code.
+ */
+ setAuxChannelsConfig(EffectAuxChannelsConfig config)
+ generates (Result retval);
+
+ /**
+ * Set the audio source the capture path is configured for (Camcorder, voice
+ * recognition...).
+ *
+ * Note: this method is only supported for effects inserted into
+ * the input chain.
+ *
+ * @param source source descriptor.
+ * @return retval operation completion status.
+ */
+ setAudioSource(AudioSource source) generates (Result retval);
+
+ /**
+ * This command indicates if the playback thread the effect is attached to
+ * is offloaded or not, and updates the I/O handle of the playback thread
+ * the effect is attached to.
+ *
+ * @param param effect offload descriptor.
+ * @return retval operation completion status.
+ */
+ offload(EffectOffloadParameter param) generates (Result retval);
+
+ /**
+ * Returns the effect descriptor.
+ *
+ * @return retval operation completion status.
+ * @return descriptor effect descriptor.
+ */
+ getDescriptor() generates (Result retval, EffectDescriptor descriptor);
+
+ /**
+ * Set up required transports for passing audio buffers to the effect.
+ *
+ * The transport consists of shared memory and a message queue for reporting
+ * effect processing operation status. The shared memory is set up
+ * separately using 'setProcessBuffers' method.
+ *
+ * Processing is requested by setting 'REQUEST_PROCESS' or
+ * 'REQUEST_PROCESS_REVERSE' EventFlags associated with the status message
+ * queue. The result of processing may be one of the following:
+ * OK if there were no errors during processing;
+ * INVALID_ARGUMENTS if audio buffers are invalid;
+ * INVALID_STATE if the engine has finished the disable phase;
+ * NOT_INITIALIZED if the audio buffers were not set;
+ * NOT_SUPPORTED if the requested processing type is not supported by
+ * the effect.
+ *
+ * @return retval OK if both message queues were created successfully.
+ * INVALID_STATE if the method was already called.
+ * INVALID_ARGUMENTS if there was a problem setting up
+ * the queue.
+ * @return statusMQ a message queue used for passing status from the effect.
+ */
+ @callflow(next={"setProcessBuffers"})
+ prepareForProcessing() generates (Result retval, fmq_sync<Result> statusMQ);
+
+ /**
+ * Set up input and output buffers for processing audio data. The effect
+ * may modify both the input and the output buffer during the operation.
+ * Buffers may be set multiple times during effect lifetime.
+ *
+ * The input and the output buffer may be reused between different effects,
+ * and the input buffer may be used as an output buffer. Buffers are
+ * distinguished using 'AudioBuffer.id' field.
+ *
+ * @param inBuffer input audio buffer.
+ * @param outBuffer output audio buffer.
+ * @return retval OK if both buffers were mapped successfully.
+ * INVALID_ARGUMENTS if there was a problem with mapping
+ * any of the buffers.
+ */
+ setProcessBuffers(AudioBuffer inBuffer, AudioBuffer outBuffer)
+ generates (Result retval);
+
+ /**
+ * Execute a vendor specific command on the effect. The command code
+ * and data, as well as result data are not interpreted by Android
+ * Framework and are passed as-is between the application and the effect.
+ *
+ * The effect must use standard POSIX.1-2001 error codes for the operation
+ * completion status.
+ *
+ * Use this method only if the effect is provided by a third party, and
+ * there is no interface defined for it. This method only works for effects
+ * implemented in software.
+ *
+ * @param commandId the ID of the command.
+ * @param data command data.
+ * @param resultMaxSize maximum size in bytes of the result; can be 0.
+ * @return status command completion status.
+ * @return result result data.
+ */
+ command(uint32_t commandId, vec<uint8_t> data, uint32_t resultMaxSize)
+ generates (int32_t status, vec<uint8_t> result);
+
+ /**
+ * Set a vendor-specific parameter and apply it immediately. The parameter
+ * code and data are not interpreted by Android Framework and are passed
+ * as-is between the application and the effect.
+ *
+ * The effect must use INVALID_ARGUMENTS return code if the parameter ID is
+ * unknown or if provided parameter data is invalid. If the effect does not
+ * support setting vendor-specific parameters, it must return NOT_SUPPORTED.
+ *
+ * Use this method only if the effect is provided by a third party, and
+ * there is no interface defined for it. This method only works for effects
+ * implemented in software.
+ *
+ * @param parameter identifying data of the parameter.
+ * @param value the value of the parameter.
+ * @return retval operation completion status.
+ */
+ setParameter(vec<uint8_t> parameter, vec<uint8_t> value)
+ generates (Result retval);
+
+ /**
+ * Get a vendor-specific parameter value. The parameter code and returned
+ * data are not interpreted by Android Framework and are passed as-is
+ * between the application and the effect.
+ *
+ * The effect must use INVALID_ARGUMENTS return code if the parameter ID is
+ * unknown. If the effect does not support setting vendor-specific
+ * parameters, it must return NOT_SUPPORTED.
+ *
+ * Use this method only if the effect is provided by a third party, and
+ * there is no interface defined for it. This method only works for effects
+ * implemented in software.
+ *
+ * @param parameter identifying data of the parameter.
+ * @param valueMaxSize maximum size in bytes of the value.
+ * @return retval operation completion status.
+ * @return result the value of the parameter.
+ */
+ getParameter(vec<uint8_t> parameter, uint32_t valueMaxSize)
+ generates (Result retval, vec<uint8_t> value);
+
+ /**
+ * Get supported configs for a vendor-specific feature. The configs returned
+ * are not interpreted by Android Framework and are passed as-is between the
+ * application and the effect.
+ *
+ * The effect must use INVALID_ARGUMENTS return code if the feature ID is
+ * unknown. If the effect does not support getting vendor-specific feature
+ * configs, it must return NOT_SUPPORTED. If the feature is supported but
+ * the total number of supported configurations exceeds the maximum number
+ * indicated by the caller, the method must return RESULT_TOO_BIG.
+ *
+ * Use this method only if the effect is provided by a third party, and
+ * there is no interface defined for it. This method only works for effects
+ * implemented in software.
+ *
+ * @param featureId feature identifier.
+ * @param maxConfigs maximum number of configs to return.
+ * @param configSize size of each config in bytes.
+ * @return retval operation completion status.
+ * @return configsCount number of configs returned.
+ * @return configsData data for all the configs returned.
+ */
+ getSupportedConfigsForFeature(
+ uint32_t featureId,
+ uint32_t maxConfigs,
+ uint32_t configSize) generates (
+ Result retval,
+ uint32_t configsCount,
+ vec<uint8_t> configsData);
+
+ /**
+ * Get the current config for a vendor-specific feature. The config returned
+ * is not interpreted by Android Framework and is passed as-is between the
+ * application and the effect.
+ *
+ * The effect must use INVALID_ARGUMENTS return code if the feature ID is
+ * unknown. If the effect does not support getting vendor-specific
+ * feature configs, it must return NOT_SUPPORTED.
+ *
+ * Use this method only if the effect is provided by a third party, and
+ * there is no interface defined for it. This method only works for effects
+ * implemented in software.
+ *
+ * @param featureId feature identifier.
+ * @param configSize size of the config in bytes.
+ * @return retval operation completion status.
+ * @return configData config data.
+ */
+ getCurrentConfigForFeature(uint32_t featureId, uint32_t configSize)
+ generates (Result retval, vec<uint8_t> configData);
+
+ /**
+ * Set the current config for a vendor-specific feature. The config data
+ * is not interpreted by Android Framework and is passed as-is between the
+ * application and the effect.
+ *
+ * The effect must use INVALID_ARGUMENTS return code if the feature ID is
+ * unknown. If the effect does not support getting vendor-specific
+ * feature configs, it must return NOT_SUPPORTED.
+ *
+ * Use this method only if the effect is provided by a third party, and
+ * there is no interface defined for it. This method only works for effects
+ * implemented in software.
+ *
+ * @param featureId feature identifier.
+ * @param configData config data.
+ * @return retval operation completion status.
+ */
+ setCurrentConfigForFeature(uint32_t featureId, vec<uint8_t> configData)
+ generates (Result retval);
+
+ /**
+ * Called by the framework to deinitialize the effect and free up
+ * all the currently allocated resources. It is recommended to close
+ * the effect on the client side as soon as it is becomes unused.
+ *
+ * @return retval OK in case the success.
+ * INVALID_STATE if the effect was already closed.
+ */
+ @exit
+ close() generates (Result retval);
+};
diff --git a/audio/effect/6.0/IEffectBufferProviderCallback.hal b/audio/effect/6.0/IEffectBufferProviderCallback.hal
new file mode 100644
index 0000000..097528d
--- /dev/null
+++ b/audio/effect/6.0/IEffectBufferProviderCallback.hal
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2019 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.effect@6.0;
+
+/**
+ * This callback interface contains functions that can be used by the effect
+ * engine 'process' function to exchange input and output audio buffers.
+ */
+interface IEffectBufferProviderCallback {
+ /**
+ * Called to retrieve a buffer where data should read from by 'process'
+ * function.
+ *
+ * @return buffer audio buffer for processing
+ */
+ getBuffer() generates (AudioBuffer buffer);
+
+ /**
+ * Called to provide a buffer with the data written by 'process' function.
+ *
+ * @param buffer audio buffer for processing
+ */
+ putBuffer(AudioBuffer buffer);
+};
diff --git a/audio/effect/6.0/IEffectsFactory.hal b/audio/effect/6.0/IEffectsFactory.hal
new file mode 100644
index 0000000..e08b2de
--- /dev/null
+++ b/audio/effect/6.0/IEffectsFactory.hal
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2019 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.effect@6.0;
+
+import android.hardware.audio.common@6.0;
+import IEffect;
+
+interface IEffectsFactory {
+ /**
+ * Returns descriptors of different effects in all loaded libraries.
+ *
+ * @return retval operation completion status.
+ * @return result list of effect descriptors.
+ */
+ getAllDescriptors() generates(Result retval, vec<EffectDescriptor> result);
+
+ /**
+ * Returns a descriptor of a particular effect.
+ *
+ * @return retval operation completion status.
+ * @return result effect descriptor.
+ */
+ getDescriptor(Uuid uid) generates(Result retval, EffectDescriptor result);
+
+ /**
+ * Creates an effect engine of the specified type. To release the effect
+ * engine, it is necessary to release references to the returned effect
+ * object.
+ *
+ * @param uid effect uuid.
+ * @param session audio session to which this effect instance will be
+ * attached. All effects created with the same session ID
+ * are connected in series and process the same signal
+ * stream.
+ * @param ioHandle identifies the output or input stream this effect is
+ * directed to in audio HAL.
+ * @return retval operation completion status.
+ * @return result the interface for the created effect.
+ * @return effectId the unique ID of the effect to be used with
+ * IStream::addEffect and IStream::removeEffect methods.
+ */
+ createEffect(Uuid uid, AudioSession session, AudioIoHandle ioHandle)
+ generates (Result retval, IEffect result, uint64_t effectId);
+};
diff --git a/audio/effect/6.0/IEnvironmentalReverbEffect.hal b/audio/effect/6.0/IEnvironmentalReverbEffect.hal
new file mode 100644
index 0000000..8887533
--- /dev/null
+++ b/audio/effect/6.0/IEnvironmentalReverbEffect.hal
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2019 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.effect@6.0;
+
+import android.hardware.audio.common@6.0;
+import IEffect;
+
+interface IEnvironmentalReverbEffect extends IEffect {
+ /**
+ * Sets whether the effect should be bypassed.
+ */
+ setBypass(bool bypass) generates (Result retval);
+
+ /**
+ * Gets whether the effect should be bypassed.
+ */
+ getBypass() generates (Result retval, bool bypass);
+
+ enum ParamRange : int16_t {
+ ROOM_LEVEL_MIN = -6000,
+ ROOM_LEVEL_MAX = 0,
+ ROOM_HF_LEVEL_MIN = -4000,
+ ROOM_HF_LEVEL_MAX = 0,
+ DECAY_TIME_MIN = 100,
+ DECAY_TIME_MAX = 20000,
+ DECAY_HF_RATIO_MIN = 100,
+ DECAY_HF_RATIO_MAX = 1000,
+ REFLECTIONS_LEVEL_MIN = -6000,
+ REFLECTIONS_LEVEL_MAX = 0,
+ REFLECTIONS_DELAY_MIN = 0,
+ REFLECTIONS_DELAY_MAX = 65,
+ REVERB_LEVEL_MIN = -6000,
+ REVERB_LEVEL_MAX = 0,
+ REVERB_DELAY_MIN = 0,
+ REVERB_DELAY_MAX = 65,
+ DIFFUSION_MIN = 0,
+ DIFFUSION_MAX = 1000,
+ DENSITY_MIN = 0,
+ DENSITY_MAX = 1000
+ };
+
+ /**
+ * Sets the room level.
+ */
+ setRoomLevel(int16_t roomLevel) generates (Result retval);
+
+ /**
+ * Gets the room level.
+ */
+ getRoomLevel() generates (Result retval, int16_t roomLevel);
+
+ /**
+ * Sets the room high frequencies level.
+ */
+ setRoomHfLevel(int16_t roomHfLevel) generates (Result retval);
+
+ /**
+ * Gets the room high frequencies level.
+ */
+ getRoomHfLevel() generates (Result retval, int16_t roomHfLevel);
+
+ /**
+ * Sets the room decay time.
+ */
+ setDecayTime(uint32_t decayTime) generates (Result retval);
+
+ /**
+ * Gets the room decay time.
+ */
+ getDecayTime() generates (Result retval, uint32_t decayTime);
+
+ /**
+ * Sets the ratio of high frequencies decay.
+ */
+ setDecayHfRatio(int16_t decayHfRatio) generates (Result retval);
+
+ /**
+ * Gets the ratio of high frequencies decay.
+ */
+ getDecayHfRatio() generates (Result retval, int16_t decayHfRatio);
+
+ /**
+ * Sets the level of reflections in the room.
+ */
+ setReflectionsLevel(int16_t reflectionsLevel) generates (Result retval);
+
+ /**
+ * Gets the level of reflections in the room.
+ */
+ getReflectionsLevel() generates (Result retval, int16_t reflectionsLevel);
+
+ /**
+ * Sets the reflections delay in the room.
+ */
+ setReflectionsDelay(uint32_t reflectionsDelay) generates (Result retval);
+
+ /**
+ * Gets the reflections delay in the room.
+ */
+ getReflectionsDelay() generates (Result retval, uint32_t reflectionsDelay);
+
+ /**
+ * Sets the reverb level of the room.
+ */
+ setReverbLevel(int16_t reverbLevel) generates (Result retval);
+
+ /**
+ * Gets the reverb level of the room.
+ */
+ getReverbLevel() generates (Result retval, int16_t reverbLevel);
+
+ /**
+ * Sets the reverb delay of the room.
+ */
+ setReverbDelay(uint32_t reverDelay) generates (Result retval);
+
+ /**
+ * Gets the reverb delay of the room.
+ */
+ getReverbDelay() generates (Result retval, uint32_t reverbDelay);
+
+ /**
+ * Sets room diffusion.
+ */
+ setDiffusion(int16_t diffusion) generates (Result retval);
+
+ /**
+ * Gets room diffusion.
+ */
+ getDiffusion() generates (Result retval, int16_t diffusion);
+
+ /**
+ * Sets room wall density.
+ */
+ setDensity(int16_t density) generates (Result retval);
+
+ /**
+ * Gets room wall density.
+ */
+ getDensity() generates (Result retval, int16_t density);
+
+ struct AllProperties {
+ int16_t roomLevel; // in millibels, range -6000 to 0
+ int16_t roomHfLevel; // in millibels, range -4000 to 0
+ uint32_t decayTime; // in milliseconds, range 100 to 20000
+ int16_t decayHfRatio; // in permilles, range 100 to 1000
+ int16_t reflectionsLevel; // in millibels, range -6000 to 0
+ uint32_t reflectionsDelay; // in milliseconds, range 0 to 65
+ int16_t reverbLevel; // in millibels, range -6000 to 0
+ uint32_t reverbDelay; // in milliseconds, range 0 to 65
+ int16_t diffusion; // in permilles, range 0 to 1000
+ int16_t density; // in permilles, range 0 to 1000
+ };
+
+ /**
+ * Sets all properties at once.
+ */
+ setAllProperties(AllProperties properties) generates (Result retval);
+
+ /**
+ * Gets all properties at once.
+ */
+ getAllProperties() generates (Result retval, AllProperties properties);
+};
diff --git a/audio/effect/6.0/IEqualizerEffect.hal b/audio/effect/6.0/IEqualizerEffect.hal
new file mode 100644
index 0000000..962d518
--- /dev/null
+++ b/audio/effect/6.0/IEqualizerEffect.hal
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2019 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.effect@6.0;
+
+import android.hardware.audio.common@6.0;
+import IEffect;
+
+interface IEqualizerEffect extends IEffect {
+ /**
+ * Gets the number of frequency bands that the equalizer supports.
+ */
+ getNumBands() generates (Result retval, uint16_t numBands);
+
+ /**
+ * Returns the minimum and maximum band levels supported.
+ */
+ getLevelRange()
+ generates (Result retval, int16_t minLevel, int16_t maxLevel);
+
+ /**
+ * Sets the gain for the given equalizer band.
+ */
+ setBandLevel(uint16_t band, int16_t level) generates (Result retval);
+
+ /**
+ * Gets the gain for the given equalizer band.
+ */
+ getBandLevel(uint16_t band) generates (Result retval, int16_t level);
+
+ /**
+ * Gets the center frequency of the given band, in milliHertz.
+ */
+ getBandCenterFrequency(uint16_t band)
+ generates (Result retval, uint32_t centerFreqmHz);
+
+ /**
+ * Gets the frequency range of the given frequency band, in milliHertz.
+ */
+ getBandFrequencyRange(uint16_t band)
+ generates (Result retval, uint32_t minFreqmHz, uint32_t maxFreqmHz);
+
+ /**
+ * Gets the band that has the most effect on the given frequency
+ * in milliHertz.
+ */
+ getBandForFrequency(uint32_t freqmHz)
+ generates (Result retval, uint16_t band);
+
+ /**
+ * Gets the names of all presets the equalizer supports.
+ */
+ getPresetNames() generates (Result retval, vec<string> names);
+
+ /**
+ * Sets the current preset using the index of the preset in the names
+ * vector returned via 'getPresetNames'.
+ */
+ setCurrentPreset(uint16_t preset) generates (Result retval);
+
+ /**
+ * Gets the current preset.
+ */
+ getCurrentPreset() generates (Result retval, uint16_t preset);
+
+ struct AllProperties {
+ uint16_t curPreset;
+ vec<int16_t> bandLevels;
+ };
+
+ /**
+ * Sets all properties at once.
+ */
+ setAllProperties(AllProperties properties) generates (Result retval);
+
+ /**
+ * Gets all properties at once.
+ */
+ getAllProperties() generates (Result retval, AllProperties properties);
+};
diff --git a/audio/effect/6.0/ILoudnessEnhancerEffect.hal b/audio/effect/6.0/ILoudnessEnhancerEffect.hal
new file mode 100644
index 0000000..73dc818
--- /dev/null
+++ b/audio/effect/6.0/ILoudnessEnhancerEffect.hal
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2019 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.effect@6.0;
+
+import android.hardware.audio.common@6.0;
+import IEffect;
+
+interface ILoudnessEnhancerEffect extends IEffect {
+ /**
+ * Sets target gain expressed in millibels.
+ */
+ setTargetGain(int32_t targetGainMb) generates (Result retval);
+
+ /**
+ * Gets target gain expressed in millibels.
+ */
+ getTargetGain() generates (Result retval, int32_t targetGainMb);
+};
diff --git a/audio/effect/6.0/INoiseSuppressionEffect.hal b/audio/effect/6.0/INoiseSuppressionEffect.hal
new file mode 100644
index 0000000..16dee57
--- /dev/null
+++ b/audio/effect/6.0/INoiseSuppressionEffect.hal
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2019 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.effect@6.0;
+
+import android.hardware.audio.common@6.0;
+import IEffect;
+
+interface INoiseSuppressionEffect extends IEffect {
+ enum Level : int32_t {
+ LOW,
+ MEDIUM,
+ HIGH
+ };
+
+ /**
+ * Sets suppression level.
+ */
+ setSuppressionLevel(Level level) generates (Result retval);
+
+ /**
+ * Gets suppression level.
+ */
+ getSuppressionLevel() generates (Result retval, Level level);
+
+ enum Type : int32_t {
+ SINGLE_CHANNEL,
+ MULTI_CHANNEL
+ };
+
+ /**
+ * Set suppression type.
+ */
+ setSuppressionType(Type type) generates (Result retval);
+
+ /**
+ * Get suppression type.
+ */
+ getSuppressionType() generates (Result retval, Type type);
+
+ struct AllProperties {
+ Level level;
+ Type type;
+ };
+
+ /**
+ * Sets all properties at once.
+ */
+ setAllProperties(AllProperties properties) generates (Result retval);
+
+ /**
+ * Gets all properties at once.
+ */
+ getAllProperties() generates (Result retval, AllProperties properties);
+};
diff --git a/audio/effect/6.0/IPresetReverbEffect.hal b/audio/effect/6.0/IPresetReverbEffect.hal
new file mode 100644
index 0000000..d00c8af
--- /dev/null
+++ b/audio/effect/6.0/IPresetReverbEffect.hal
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2019 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.effect@6.0;
+
+import android.hardware.audio.common@6.0;
+import IEffect;
+
+interface IPresetReverbEffect extends IEffect {
+ enum Preset : int32_t {
+ NONE, // no reverb or reflections
+ SMALLROOM, // a small room less than five meters in length
+ MEDIUMROOM, // a medium room with a length of ten meters or less
+ LARGEROOM, // a large-sized room suitable for live performances
+ MEDIUMHALL, // a medium-sized hall
+ LARGEHALL, // a large-sized hall suitable for a full orchestra
+ PLATE, // synthesis of the traditional plate reverb
+ LAST = PLATE
+ };
+
+ /**
+ * Sets the current preset.
+ */
+ setPreset(Preset preset) generates (Result retval);
+
+ /**
+ * Gets the current preset.
+ */
+ getPreset() generates (Result retval, Preset preset);
+};
diff --git a/audio/effect/6.0/IVirtualizerEffect.hal b/audio/effect/6.0/IVirtualizerEffect.hal
new file mode 100644
index 0000000..5967b33
--- /dev/null
+++ b/audio/effect/6.0/IVirtualizerEffect.hal
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2019 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.effect@6.0;
+
+import android.hardware.audio.common@6.0;
+import IEffect;
+
+interface IVirtualizerEffect extends IEffect {
+ /**
+ * Returns whether setting virtualization strength is supported.
+ */
+ isStrengthSupported() generates (bool strengthSupported);
+
+ enum StrengthRange : uint16_t {
+ MIN = 0,
+ MAX = 1000
+ };
+
+ /**
+ * Sets virtualization strength.
+ *
+ * @param strength strength of the effect. The valid range for strength
+ * strength is [0, 1000], where 0 per mille designates the
+ * mildest effect and 1000 per mille designates the
+ * strongest.
+ * @return retval operation completion status.
+ */
+ setStrength(uint16_t strength) generates (Result retval);
+
+ /**
+ * Gets virtualization strength.
+ */
+ getStrength() generates (Result retval, uint16_t strength);
+
+ struct SpeakerAngle {
+ /** Speaker channel mask */
+ bitfield<AudioChannelMask> mask;
+ // all angles are expressed in degrees and
+ // are relative to the listener.
+ int16_t azimuth; // 0 is the direction the listener faces
+ // 180 is behind the listener
+ // -90 is to their left
+ int16_t elevation; // 0 is the horizontal plane
+ // +90 is above the listener, -90 is below
+ };
+ /**
+ * Retrieves virtual speaker angles for the given channel mask on the
+ * specified device.
+ */
+ getVirtualSpeakerAngles(bitfield<AudioChannelMask> mask, AudioDevice device)
+ generates (Result retval, vec<SpeakerAngle> speakerAngles);
+
+ /**
+ * Forces the virtualizer effect for the given output device.
+ */
+ forceVirtualizationMode(AudioDevice device) generates (Result retval);
+
+ /**
+ * Returns audio device reflecting the current virtualization mode,
+ * AUDIO_DEVICE_NONE when not virtualizing.
+ */
+ getVirtualizationMode() generates (Result retval, AudioDevice device);
+};
diff --git a/audio/effect/6.0/IVisualizerEffect.hal b/audio/effect/6.0/IVisualizerEffect.hal
new file mode 100644
index 0000000..3df3e6f
--- /dev/null
+++ b/audio/effect/6.0/IVisualizerEffect.hal
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2019 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.effect@6.0;
+
+import android.hardware.audio.common@6.0;
+import IEffect;
+
+interface IVisualizerEffect extends IEffect {
+ enum CaptureSizeRange : int32_t {
+ MAX = 1024, // maximum capture size in samples
+ MIN = 128 // minimum capture size in samples
+ };
+
+ /**
+ * Sets the number PCM samples in the capture.
+ */
+ setCaptureSize(uint16_t captureSize) generates (Result retval);
+
+ /**
+ * Gets the number PCM samples in the capture.
+ */
+ getCaptureSize() generates (Result retval, uint16_t captureSize);
+
+ enum ScalingMode : int32_t {
+ // Keep in sync with SCALING_MODE_... in
+ // frameworks/base/media/java/android/media/audiofx/Visualizer.java
+ NORMALIZED = 0,
+ AS_PLAYED = 1
+ };
+
+ /**
+ * Specifies the way the captured data is scaled.
+ */
+ setScalingMode(ScalingMode scalingMode) generates (Result retval);
+
+ /**
+ * Retrieves the way the captured data is scaled.
+ */
+ getScalingMode() generates (Result retval, ScalingMode scalingMode);
+
+ /**
+ * Informs the visualizer about the downstream latency.
+ */
+ setLatency(uint32_t latencyMs) generates (Result retval);
+
+ /**
+ * Gets the downstream latency.
+ */
+ getLatency() generates (Result retval, uint32_t latencyMs);
+
+ enum MeasurementMode : int32_t {
+ // Keep in sync with MEASUREMENT_MODE_... in
+ // frameworks/base/media/java/android/media/audiofx/Visualizer.java
+ NONE = 0x0,
+ PEAK_RMS = 0x1
+ };
+
+ /**
+ * Specifies which measurements are to be made.
+ */
+ setMeasurementMode(MeasurementMode measurementMode)
+ generates (Result retval);
+
+ /**
+ * Retrieves which measurements are to be made.
+ */
+ getMeasurementMode() generates (
+ Result retval, MeasurementMode measurementMode);
+
+ /**
+ * Retrieves the latest PCM snapshot captured by the visualizer engine. The
+ * number of samples to capture is specified by 'setCaptureSize' parameter.
+ *
+ * @return retval operation completion status.
+ * @return samples samples in 8 bit unsigned format (0 = 0x80)
+ */
+ capture() generates (Result retval, vec<uint8_t> samples);
+
+ struct Measurement {
+ MeasurementMode mode; // discriminator
+ union Values {
+ struct PeakAndRms {
+ int32_t peakMb; // millibels
+ int32_t rmsMb; // millibels
+ } peakAndRms;
+ } value;
+ };
+ /**
+ * Retrieves the latest measurements. The measurements to be made
+ * are specified by 'setMeasurementMode' parameter.
+ *
+ * @return retval operation completion status.
+ * @return result measurement.
+ */
+ measure() generates (Result retval, Measurement result);
+};
diff --git a/audio/effect/6.0/types.hal b/audio/effect/6.0/types.hal
new file mode 100644
index 0000000..dd5a4ad
--- /dev/null
+++ b/audio/effect/6.0/types.hal
@@ -0,0 +1,301 @@
+/*
+ * Copyright (C) 2019 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.effect@6.0;
+
+import android.hardware.audio.common@6.0;
+
+enum Result : int32_t {
+ OK,
+ NOT_INITIALIZED,
+ INVALID_ARGUMENTS,
+ INVALID_STATE,
+ NOT_SUPPORTED,
+ RESULT_TOO_BIG
+};
+
+/**
+ * Effect engine capabilities/requirements flags.
+ *
+ * Definitions for flags field of effect descriptor.
+ *
+ * +----------------+--------+--------------------------------------------------
+ * | description | bits | values
+ * +----------------+--------+--------------------------------------------------
+ * | connection | 0..2 | 0 insert: after track process
+ * | mode | | 1 auxiliary: connect to track auxiliary
+ * | | | output and use send level
+ * | | | 2 replace: replaces track process function;
+ * | | | must implement SRC, volume and mono to stereo.
+ * | | | 3 pre processing: applied below audio HAL on in
+ * | | | 4 post processing: applied below audio HAL on out
+ * | | | 5 - 7 reserved
+ * +----------------+--------+--------------------------------------------------
+ * | insertion | 3..5 | 0 none
+ * | preference | | 1 first of the chain
+ * | | | 2 last of the chain
+ * | | | 3 exclusive (only effect in the insert chain)
+ * | | | 4..7 reserved
+ * +----------------+--------+--------------------------------------------------
+ * | Volume | 6..8 | 0 none
+ * | management | | 1 implements volume control
+ * | | | 2 requires volume indication
+ * | | | 3 monitors requested volume
+ * | | | 4 reserved
+ * +----------------+--------+--------------------------------------------------
+ * | Device | 9..11 | 0 none
+ * | indication | | 1 requires device updates
+ * | | | 2, 4 reserved
+ * +----------------+--------+--------------------------------------------------
+ * | Sample input | 12..13 | 1 direct: process() function or
+ * | mode | | EFFECT_CMD_SET_CONFIG command must specify
+ * | | | a buffer descriptor
+ * | | | 2 provider: process() function uses the
+ * | | | bufferProvider indicated by the
+ * | | | EFFECT_CMD_SET_CONFIG command to request input.
+ * | | | buffers.
+ * | | | 3 both: both input modes are supported
+ * +----------------+--------+--------------------------------------------------
+ * | Sample output | 14..15 | 1 direct: process() function or
+ * | mode | | EFFECT_CMD_SET_CONFIG command must specify
+ * | | | a buffer descriptor
+ * | | | 2 provider: process() function uses the
+ * | | | bufferProvider indicated by the
+ * | | | EFFECT_CMD_SET_CONFIG command to request output
+ * | | | buffers.
+ * | | | 3 both: both output modes are supported
+ * +----------------+--------+--------------------------------------------------
+ * | Hardware | 16..17 | 0 No hardware acceleration
+ * | acceleration | | 1 non tunneled hw acceleration: the process()
+ * | | | function reads the samples, send them to HW
+ * | | | accelerated effect processor, reads back
+ * | | | the processed samples and returns them
+ * | | | to the output buffer.
+ * | | | 2 tunneled hw acceleration: the process()
+ * | | | function is transparent. The effect interface
+ * | | | is only used to control the effect engine.
+ * | | | This mode is relevant for global effects
+ * | | | actually applied by the audio hardware on
+ * | | | the output stream.
+ * +----------------+--------+--------------------------------------------------
+ * | Audio Mode | 18..19 | 0 none
+ * | indication | | 1 requires audio mode updates
+ * | | | 2..3 reserved
+ * +----------------+--------+--------------------------------------------------
+ * | Audio source | 20..21 | 0 none
+ * | indication | | 1 requires audio source updates
+ * | | | 2..3 reserved
+ * +----------------+--------+--------------------------------------------------
+ * | Effect offload | 22 | 0 The effect cannot be offloaded to an audio DSP
+ * | supported | | 1 The effect can be offloaded to an audio DSP
+ * +----------------+--------+--------------------------------------------------
+ * | Process | 23 | 0 The effect implements a process function.
+ * | function | | 1 The effect does not implement a process
+ * | not | | function: enabling the effect has no impact
+ * | implemented | | on latency or CPU load.
+ * | | | Effect implementations setting this flag do not
+ * | | | have to implement a process function.
+ * +----------------+--------+--------------------------------------------------
+ */
+@export(name="", value_prefix="EFFECT_FLAG_")
+enum EffectFlags : int32_t {
+ // Insert mode
+ TYPE_SHIFT = 0,
+ TYPE_SIZE = 3,
+ TYPE_MASK = ((1 << TYPE_SIZE) -1) << TYPE_SHIFT,
+ TYPE_INSERT = 0 << TYPE_SHIFT,
+ TYPE_AUXILIARY = 1 << TYPE_SHIFT,
+ TYPE_REPLACE = 2 << TYPE_SHIFT,
+ TYPE_PRE_PROC = 3 << TYPE_SHIFT,
+ TYPE_POST_PROC = 4 << TYPE_SHIFT,
+
+ // Insert preference
+ INSERT_SHIFT = TYPE_SHIFT + TYPE_SIZE,
+ INSERT_SIZE = 3,
+ INSERT_MASK = ((1 << INSERT_SIZE) -1) << INSERT_SHIFT,
+ INSERT_ANY = 0 << INSERT_SHIFT,
+ INSERT_FIRST = 1 << INSERT_SHIFT,
+ INSERT_LAST = 2 << INSERT_SHIFT,
+ INSERT_EXCLUSIVE = 3 << INSERT_SHIFT,
+
+ // Volume control
+ VOLUME_SHIFT = INSERT_SHIFT + INSERT_SIZE,
+ VOLUME_SIZE = 3,
+ VOLUME_MASK = ((1 << VOLUME_SIZE) -1) << VOLUME_SHIFT,
+ VOLUME_CTRL = 1 << VOLUME_SHIFT,
+ VOLUME_IND = 2 << VOLUME_SHIFT,
+ VOLUME_MONITOR = 3 << VOLUME_SHIFT,
+ VOLUME_NONE = 0 << VOLUME_SHIFT,
+
+ // Device indication
+ DEVICE_SHIFT = VOLUME_SHIFT + VOLUME_SIZE,
+ DEVICE_SIZE = 3,
+ DEVICE_MASK = ((1 << DEVICE_SIZE) -1) << DEVICE_SHIFT,
+ DEVICE_IND = 1 << DEVICE_SHIFT,
+ DEVICE_NONE = 0 << DEVICE_SHIFT,
+
+ // Sample input modes
+ INPUT_SHIFT = DEVICE_SHIFT + DEVICE_SIZE,
+ INPUT_SIZE = 2,
+ INPUT_MASK = ((1 << INPUT_SIZE) -1) << INPUT_SHIFT,
+ INPUT_DIRECT = 1 << INPUT_SHIFT,
+ INPUT_PROVIDER = 2 << INPUT_SHIFT,
+ INPUT_BOTH = 3 << INPUT_SHIFT,
+
+ // Sample output modes
+ OUTPUT_SHIFT = INPUT_SHIFT + INPUT_SIZE,
+ OUTPUT_SIZE = 2,
+ OUTPUT_MASK = ((1 << OUTPUT_SIZE) -1) << OUTPUT_SHIFT,
+ OUTPUT_DIRECT = 1 << OUTPUT_SHIFT,
+ OUTPUT_PROVIDER = 2 << OUTPUT_SHIFT,
+ OUTPUT_BOTH = 3 << OUTPUT_SHIFT,
+
+ // Hardware acceleration mode
+ HW_ACC_SHIFT = OUTPUT_SHIFT + OUTPUT_SIZE,
+ HW_ACC_SIZE = 2,
+ HW_ACC_MASK = ((1 << HW_ACC_SIZE) -1) << HW_ACC_SHIFT,
+ HW_ACC_SIMPLE = 1 << HW_ACC_SHIFT,
+ HW_ACC_TUNNEL = 2 << HW_ACC_SHIFT,
+
+ // Audio mode indication
+ AUDIO_MODE_SHIFT = HW_ACC_SHIFT + HW_ACC_SIZE,
+ AUDIO_MODE_SIZE = 2,
+ AUDIO_MODE_MASK = ((1 << AUDIO_MODE_SIZE) -1) << AUDIO_MODE_SHIFT,
+ AUDIO_MODE_IND = 1 << AUDIO_MODE_SHIFT,
+ AUDIO_MODE_NONE = 0 << AUDIO_MODE_SHIFT,
+
+ // Audio source indication
+ AUDIO_SOURCE_SHIFT = AUDIO_MODE_SHIFT + AUDIO_MODE_SIZE,
+ AUDIO_SOURCE_SIZE = 2,
+ AUDIO_SOURCE_MASK = ((1 << AUDIO_SOURCE_SIZE) -1) << AUDIO_SOURCE_SHIFT,
+ AUDIO_SOURCE_IND = 1 << AUDIO_SOURCE_SHIFT,
+ AUDIO_SOURCE_NONE = 0 << AUDIO_SOURCE_SHIFT,
+
+ // Effect offload indication
+ OFFLOAD_SHIFT = AUDIO_SOURCE_SHIFT + AUDIO_SOURCE_SIZE,
+ OFFLOAD_SIZE = 1,
+ OFFLOAD_MASK = ((1 << OFFLOAD_SIZE) -1) << OFFLOAD_SHIFT,
+ OFFLOAD_SUPPORTED = 1 << OFFLOAD_SHIFT,
+
+ // Effect has no process indication
+ NO_PROCESS_SHIFT = OFFLOAD_SHIFT + OFFLOAD_SIZE,
+ NO_PROCESS_SIZE = 1,
+ NO_PROCESS_MASK = ((1 << NO_PROCESS_SIZE) -1) << NO_PROCESS_SHIFT,
+ NO_PROCESS = 1 << NO_PROCESS_SHIFT
+};
+
+/**
+ * The effect descriptor contains necessary information to facilitate the
+ * enumeration of the effect engines present in a library.
+ */
+struct EffectDescriptor {
+ Uuid type; // UUID of to the OpenSL ES interface implemented
+ // by this effect
+ Uuid uuid; // UUID for this particular implementation
+ bitfield<EffectFlags> flags; // effect engine capabilities/requirements flags
+ uint16_t cpuLoad; // CPU load indication expressed in 0.1 MIPS units
+ // as estimated on an ARM9E core (ARMv5TE) with 0 WS
+ uint16_t memoryUsage; // data memory usage expressed in KB and includes
+ // only dynamically allocated memory
+ uint8_t[64] name; // human readable effect name
+ uint8_t[64] implementor; // human readable effect implementor name
+};
+
+/**
+ * A buffer is a chunk of audio data for processing. Multi-channel audio is
+ * always interleaved. The channel order is from LSB to MSB with regard to the
+ * channel mask definition in audio.h, audio_channel_mask_t, e.g.:
+ * Stereo: L, R; 5.1: FL, FR, FC, LFE, BL, BR.
+ *
+ * The buffer size is expressed in frame count, a frame being composed of
+ * samples for all channels at a given time. Frame size for unspecified format
+ * (AUDIO_FORMAT_OTHER) is 8 bit by definition.
+ */
+struct AudioBuffer {
+ uint64_t id;
+ uint32_t frameCount;
+ memory data;
+};
+
+@export(name="effect_buffer_access_e", value_prefix="EFFECT_BUFFER_")
+enum EffectBufferAccess : int32_t {
+ ACCESS_WRITE,
+ ACCESS_READ,
+ ACCESS_ACCUMULATE
+};
+
+/**
+ * Determines what fields of EffectBufferConfig need to be considered.
+ */
+@export(name="", value_prefix="EFFECT_CONFIG_")
+enum EffectConfigParameters : int32_t {
+ BUFFER = 0x0001, // buffer field
+ SMP_RATE = 0x0002, // samplingRate
+ CHANNELS = 0x0004, // channels
+ FORMAT = 0x0008, // format
+ ACC_MODE = 0x0010, // accessMode
+ // Note that the 2.0 ALL have been moved to an helper function
+};
+
+/**
+ * The buffer config structure specifies the input or output audio format
+ * to be used by the effect engine.
+ */
+struct EffectBufferConfig {
+ AudioBuffer buffer;
+ uint32_t samplingRateHz;
+ bitfield<AudioChannelMask> channels;
+ AudioFormat format;
+ EffectBufferAccess accessMode;
+ bitfield<EffectConfigParameters> mask;
+};
+
+struct EffectConfig {
+ EffectBufferConfig inputCfg;
+ EffectBufferConfig outputCfg;
+};
+
+@export(name="effect_feature_e", value_prefix="EFFECT_FEATURE_")
+enum EffectFeature : int32_t {
+ AUX_CHANNELS, // supports auxiliary channels
+ // (e.g. dual mic noise suppressor)
+ CNT
+};
+
+struct EffectAuxChannelsConfig {
+ bitfield<AudioChannelMask> mainChannels; // channel mask for main channels
+ bitfield<AudioChannelMask> auxChannels; // channel mask for auxiliary channels
+};
+
+struct EffectOffloadParameter {
+ bool isOffload; // true if the playback thread the effect
+ // is attached to is offloaded
+ AudioIoHandle ioHandle; // io handle of the playback thread
+ // the effect is attached to
+};
+
+/**
+ * The message queue flags used to synchronize reads and writes from
+ * the status message queue used by effects.
+ */
+enum MessageQueueFlagBits : uint32_t {
+ DONE_PROCESSING = 1 << 0,
+ REQUEST_PROCESS = 1 << 1,
+ REQUEST_PROCESS_REVERSE = 1 << 2,
+ REQUEST_QUIT = 1 << 3,
+ REQUEST_PROCESS_ALL =
+ REQUEST_PROCESS | REQUEST_PROCESS_REVERSE | REQUEST_QUIT
+};
diff --git a/audio/effect/6.0/xml/Android.bp b/audio/effect/6.0/xml/Android.bp
new file mode 100644
index 0000000..353686b
--- /dev/null
+++ b/audio/effect/6.0/xml/Android.bp
@@ -0,0 +1,6 @@
+
+xsd_config {
+ name: "audio_effects_conf_V6_0",
+ srcs: ["audio_effects_conf.xsd"],
+ package_name: "audio.effects.V6_0",
+}
diff --git a/audio/effect/6.0/xml/api/current.txt b/audio/effect/6.0/xml/api/current.txt
new file mode 100644
index 0000000..2021639
--- /dev/null
+++ b/audio/effect/6.0/xml/api/current.txt
@@ -0,0 +1,132 @@
+// Signature format: 2.0
+package audio.effects.V6_0 {
+
+ public class AudioEffectsConf {
+ ctor public AudioEffectsConf();
+ method public audio.effects.V6_0.EffectsType getEffects();
+ method public audio.effects.V6_0.LibrariesType getLibraries();
+ method public audio.effects.V6_0.AudioEffectsConf.Postprocess getPostprocess();
+ method public audio.effects.V6_0.AudioEffectsConf.Preprocess getPreprocess();
+ method public audio.effects.V6_0.VersionType getVersion();
+ method public void setEffects(audio.effects.V6_0.EffectsType);
+ method public void setLibraries(audio.effects.V6_0.LibrariesType);
+ method public void setPostprocess(audio.effects.V6_0.AudioEffectsConf.Postprocess);
+ method public void setPreprocess(audio.effects.V6_0.AudioEffectsConf.Preprocess);
+ method public void setVersion(audio.effects.V6_0.VersionType);
+ }
+
+ public static class AudioEffectsConf.Postprocess {
+ ctor public AudioEffectsConf.Postprocess();
+ method public java.util.List<audio.effects.V6_0.StreamPostprocessType> getStream();
+ }
+
+ public static class AudioEffectsConf.Preprocess {
+ ctor public AudioEffectsConf.Preprocess();
+ method public java.util.List<audio.effects.V6_0.StreamPreprocessType> getStream();
+ }
+
+ public class EffectImplType {
+ ctor public EffectImplType();
+ method public String getLibrary();
+ method public String getUuid();
+ method public void setLibrary(String);
+ method public void setUuid(String);
+ }
+
+ public class EffectProxyType extends audio.effects.V6_0.EffectType {
+ ctor public EffectProxyType();
+ method public audio.effects.V6_0.EffectImplType getLibhw();
+ method public audio.effects.V6_0.EffectImplType getLibsw();
+ method public void setLibhw(audio.effects.V6_0.EffectImplType);
+ method public void setLibsw(audio.effects.V6_0.EffectImplType);
+ }
+
+ public class EffectType extends audio.effects.V6_0.EffectImplType {
+ ctor public EffectType();
+ method public String getName();
+ method public void setName(String);
+ }
+
+ public class EffectsType {
+ ctor public EffectsType();
+ method public java.util.List<audio.effects.V6_0.EffectProxyType> getEffectProxy_optional();
+ method public java.util.List<audio.effects.V6_0.EffectType> getEffect_optional();
+ }
+
+ public class LibrariesType {
+ ctor public LibrariesType();
+ method public java.util.List<audio.effects.V6_0.LibrariesType.Library> getLibrary();
+ }
+
+ public static class LibrariesType.Library {
+ ctor public LibrariesType.Library();
+ method public String getName();
+ method public String getPath();
+ method public void setName(String);
+ method public void setPath(String);
+ }
+
+ public enum StreamInputType {
+ method public String getRawName();
+ enum_constant public static final audio.effects.V6_0.StreamInputType camcorder;
+ enum_constant public static final audio.effects.V6_0.StreamInputType mic;
+ enum_constant public static final audio.effects.V6_0.StreamInputType unprocessed;
+ enum_constant public static final audio.effects.V6_0.StreamInputType voice_call;
+ enum_constant public static final audio.effects.V6_0.StreamInputType voice_communication;
+ enum_constant public static final audio.effects.V6_0.StreamInputType voice_downlink;
+ enum_constant public static final audio.effects.V6_0.StreamInputType voice_performance;
+ enum_constant public static final audio.effects.V6_0.StreamInputType voice_recognition;
+ enum_constant public static final audio.effects.V6_0.StreamInputType voice_uplink;
+ }
+
+ public enum StreamOutputType {
+ method public String getRawName();
+ enum_constant public static final audio.effects.V6_0.StreamOutputType alarm;
+ enum_constant public static final audio.effects.V6_0.StreamOutputType bluetooth_sco;
+ enum_constant public static final audio.effects.V6_0.StreamOutputType dtmf;
+ enum_constant public static final audio.effects.V6_0.StreamOutputType enforced_audible;
+ enum_constant public static final audio.effects.V6_0.StreamOutputType music;
+ enum_constant public static final audio.effects.V6_0.StreamOutputType notification;
+ enum_constant public static final audio.effects.V6_0.StreamOutputType ring;
+ enum_constant public static final audio.effects.V6_0.StreamOutputType system;
+ enum_constant public static final audio.effects.V6_0.StreamOutputType tts;
+ enum_constant public static final audio.effects.V6_0.StreamOutputType voice_call;
+ }
+
+ public class StreamPostprocessType extends audio.effects.V6_0.StreamProcessingType {
+ ctor public StreamPostprocessType();
+ method public audio.effects.V6_0.StreamOutputType getType();
+ method public void setType(audio.effects.V6_0.StreamOutputType);
+ }
+
+ public class StreamPreprocessType extends audio.effects.V6_0.StreamProcessingType {
+ ctor public StreamPreprocessType();
+ method public audio.effects.V6_0.StreamInputType getType();
+ method public void setType(audio.effects.V6_0.StreamInputType);
+ }
+
+ public class StreamProcessingType {
+ ctor public StreamProcessingType();
+ method public java.util.List<audio.effects.V6_0.StreamProcessingType.Apply> getApply();
+ }
+
+ public static class StreamProcessingType.Apply {
+ ctor public StreamProcessingType.Apply();
+ method public String getEffect();
+ method public void setEffect(String);
+ }
+
+ public enum VersionType {
+ method public String getRawName();
+ enum_constant public static final audio.effects.V6_0.VersionType _2_0;
+ }
+
+ public class XmlParser {
+ ctor public XmlParser();
+ method public static audio.effects.V6_0.AudioEffectsConf read(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public static String readText(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public static void skip(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ }
+
+}
+
diff --git a/audio/effect/6.0/xml/api/last_current.txt b/audio/effect/6.0/xml/api/last_current.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/audio/effect/6.0/xml/api/last_current.txt
diff --git a/audio/effect/6.0/xml/api/last_removed.txt b/audio/effect/6.0/xml/api/last_removed.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/audio/effect/6.0/xml/api/last_removed.txt
diff --git a/audio/effect/6.0/xml/api/removed.txt b/audio/effect/6.0/xml/api/removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/audio/effect/6.0/xml/api/removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/audio/effect/6.0/xml/audio_effects_conf.xsd b/audio/effect/6.0/xml/audio_effects_conf.xsd
new file mode 120000
index 0000000..9d85fa7
--- /dev/null
+++ b/audio/effect/6.0/xml/audio_effects_conf.xsd
@@ -0,0 +1 @@
+../../2.0/xml/audio_effects_conf.xsd
\ No newline at end of file
diff --git a/audio/effect/all-versions/default/Android.bp b/audio/effect/all-versions/default/Android.bp
index 653b30c..d9bb78b 100644
--- a/audio/effect/all-versions/default/Android.bp
+++ b/audio/effect/all-versions/default/Android.bp
@@ -52,7 +52,6 @@
"android.hardware.audio.common@2.0-util",
"android.hardware.audio.effect@2.0",
],
-
cflags: [
"-DMAJOR_VERSION=2",
"-DMINOR_VERSION=0",
@@ -68,7 +67,6 @@
"android.hardware.audio.common@4.0-util",
"android.hardware.audio.effect@4.0",
],
-
cflags: [
"-DMAJOR_VERSION=4",
"-DMINOR_VERSION=0",
@@ -84,10 +82,24 @@
"android.hardware.audio.common@5.0-util",
"android.hardware.audio.effect@5.0",
],
-
cflags: [
"-DMAJOR_VERSION=5",
"-DMINOR_VERSION=0",
"-include common/all-versions/VersionMacro.h",
]
}
+
+cc_library_shared {
+ name: "android.hardware.audio.effect@6.0-impl",
+ defaults: ["android.hardware.audio.effect-impl_default"],
+ shared_libs: [
+ "android.hardware.audio.common@6.0",
+ "android.hardware.audio.common@6.0-util",
+ "android.hardware.audio.effect@6.0",
+ ],
+ cflags: [
+ "-DMAJOR_VERSION=6",
+ "-DMINOR_VERSION=0",
+ "-include common/all-versions/VersionMacro.h",
+ ]
+}
diff --git a/audio/effect/all-versions/vts/functional/Android.bp b/audio/effect/all-versions/vts/functional/Android.bp
index cccb5c8..edc9076 100644
--- a/audio/effect/all-versions/vts/functional/Android.bp
+++ b/audio/effect/all-versions/vts/functional/Android.bp
@@ -76,3 +76,16 @@
]
}
+cc_test {
+ name: "VtsHalAudioEffectV6_0TargetTest",
+ defaults: ["VtsHalAudioEffectTargetTest_default"],
+ static_libs: [
+ "android.hardware.audio.common@6.0",
+ "android.hardware.audio.effect@6.0",
+ ],
+ cflags: [
+ "-DMAJOR_VERSION=6",
+ "-DMINOR_VERSION=0",
+ "-include common/all-versions/VersionMacro.h",
+ ]
+}
diff --git a/authsecret/1.0/vts/functional/Android.bp b/authsecret/1.0/vts/functional/Android.bp
index f2b3a8a..9ce9cda 100644
--- a/authsecret/1.0/vts/functional/Android.bp
+++ b/authsecret/1.0/vts/functional/Android.bp
@@ -19,5 +19,9 @@
defaults: ["VtsHalTargetTestDefaults"],
srcs: ["VtsHalAuthSecretV1_0TargetTest.cpp"],
static_libs: ["android.hardware.authsecret@1.0"],
- test_suites: ["general-tests"],
+ test_suites: [
+ "general-tests",
+ "vts-core",
+ ],
+ require_root: true,
}
diff --git a/authsecret/1.0/vts/functional/VtsHalAuthSecretV1_0TargetTest.cpp b/authsecret/1.0/vts/functional/VtsHalAuthSecretV1_0TargetTest.cpp
index 255d4de..0bff9df 100644
--- a/authsecret/1.0/vts/functional/VtsHalAuthSecretV1_0TargetTest.cpp
+++ b/authsecret/1.0/vts/functional/VtsHalAuthSecretV1_0TargetTest.cpp
@@ -16,36 +16,22 @@
#include <android/hardware/authsecret/1.0/IAuthSecret.h>
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
using ::android::hardware::hidl_vec;
using ::android::hardware::authsecret::V1_0::IAuthSecret;
using ::android::sp;
-// Test environment for Boot HIDL HAL.
-class AuthSecretHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static AuthSecretHidlEnvironment* Instance() {
- static AuthSecretHidlEnvironment* instance = new AuthSecretHidlEnvironment;
- return instance;
- }
-
- virtual void registerTestServices() override { registerTestService<IAuthSecret>(); }
-
- private:
- AuthSecretHidlEnvironment() {}
-};
-
/**
* There is no expected behaviour that can be tested so these tests check the
* HAL doesn't crash with different execution orders.
*/
-struct AuthSecretHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class AuthSecretHidlTest : public testing::TestWithParam<std::string> {
+ public:
virtual void SetUp() override {
- authsecret = ::testing::VtsHalHidlTargetTestBase::getService<IAuthSecret>(
- AuthSecretHidlEnvironment::Instance()->getServiceName<IAuthSecret>());
+ authsecret = IAuthSecret::getService(GetParam());
ASSERT_NE(authsecret, nullptr);
// All tests must enroll the correct secret first as this cannot be changed
@@ -59,18 +45,18 @@
};
/* Provision the primary user with a secret. */
-TEST_F(AuthSecretHidlTest, provisionPrimaryUserCredential) {
+TEST_P(AuthSecretHidlTest, provisionPrimaryUserCredential) {
// Secret provisioned by SetUp()
}
/* Provision the primary user with a secret and pass the secret again. */
-TEST_F(AuthSecretHidlTest, provisionPrimaryUserCredentialAndPassAgain) {
+TEST_P(AuthSecretHidlTest, provisionPrimaryUserCredentialAndPassAgain) {
// Secret provisioned by SetUp()
authsecret->primaryUserCredential(CORRECT_SECRET);
}
/* Provision the primary user with a secret and pass the secret again repeatedly. */
-TEST_F(AuthSecretHidlTest, provisionPrimaryUserCredentialAndPassAgainMultipleTimes) {
+TEST_P(AuthSecretHidlTest, provisionPrimaryUserCredentialAndPassAgainMultipleTimes) {
// Secret provisioned by SetUp()
constexpr int N = 5;
for (int i = 0; i < N; ++i) {
@@ -82,16 +68,12 @@
* should never happen and is an framework bug if it does. As the secret is
* wrong, the HAL implementation may not be able to function correctly but it
* should fail gracefully. */
-TEST_F(AuthSecretHidlTest, provisionPrimaryUserCredentialAndWrongSecret) {
+TEST_P(AuthSecretHidlTest, provisionPrimaryUserCredentialAndWrongSecret) {
// Secret provisioned by SetUp()
authsecret->primaryUserCredential(WRONG_SECRET);
}
-int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(AuthSecretHidlEnvironment::Instance());
- ::testing::InitGoogleTest(&argc, argv);
- AuthSecretHidlEnvironment::Instance()->init(&argc, argv);
- int status = RUN_ALL_TESTS();
- ALOGI("Test result = %d", status);
- return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, AuthSecretHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IAuthSecret::descriptor)),
+ android::hardware::PrintInstanceNameToString);
diff --git a/automotive/evs/1.1/Android.bp b/automotive/evs/1.1/Android.bp
index d2e85f1..c850c91 100644
--- a/automotive/evs/1.1/Android.bp
+++ b/automotive/evs/1.1/Android.bp
@@ -10,13 +10,15 @@
"types.hal",
"IEvsCamera.hal",
"IEvsCameraStream.hal",
+ "IEvsEnumerator.hal",
],
interfaces: [
"android.hardware.automotive.evs@1.0",
+ "android.hardware.camera.device@3.2",
"android.hardware.graphics.common@1.0",
"android.hardware.graphics.common@1.1",
"android.hardware.graphics.common@1.2",
"android.hidl.base@1.0",
],
- gen_java: true,
+ gen_java: false,
}
diff --git a/automotive/evs/1.1/IEvsCamera.hal b/automotive/evs/1.1/IEvsCamera.hal
index 21ca79e..975b6c6 100644
--- a/automotive/evs/1.1/IEvsCamera.hal
+++ b/automotive/evs/1.1/IEvsCamera.hal
@@ -26,6 +26,14 @@
*/
interface IEvsCamera extends @1.0::IEvsCamera {
/**
+ * Returns the description of this camera.
+ *
+ * @return info The description of this camera. This must be the same value as
+ * reported by EvsEnumerator::getCameraList_1_1().
+ */
+ getCameraInfo_1_1() generates (CameraDesc info);
+
+ /**
* Requests to pause EVS camera stream events.
*
* Like stopVideoStream(), events may continue to arrive for some time
@@ -100,7 +108,27 @@
unsetMaster() generates (EvsResult result);
/**
- * Requests to set a camera parameter.
+ * Retrieves a list of parameters this camera supports.
+ *
+ * @return params A list of CameraParam that this camera supports.
+ */
+ getParameterList() generates (vec<CameraParam> params);
+
+ /**
+ * Requests a valid value range of a camera parameter
+ *
+ * @param id The identifier of camera parameter, CameraParam enum.
+ *
+ * @return min The lower bound of valid parameter value range.
+ * @return max The upper bound of valid parameter value range.
+ * @return step The resolution of values in valid range.
+ */
+ getIntParameterRange(CameraParam id)
+ generates (int32_t min, int32_t max, int32_t step);
+
+ /**
+ * Requests to set a camera parameter. Only a request from the master
+ * client will be processed successfully.
*
* @param id The identifier of camera parameter, CameraParam enum.
* value A desired parameter value.
@@ -114,7 +142,7 @@
* from what the client gives if, for example, the
* driver does not support a target parameter.
*/
- setParameter(CameraParam id, int32_t value)
+ setIntParameter(CameraParam id, int32_t value)
generates (EvsResult result, int32_t effectiveValue);
/**
@@ -126,5 +154,5 @@
* not supported.
* value A value of requested camera parameter.
*/
- getParameter(CameraParam id) generates(EvsResult result, int32_t value);
+ getIntParameter(CameraParam id) generates(EvsResult result, int32_t value);
};
diff --git a/automotive/evs/1.1/IEvsCameraStream.hal b/automotive/evs/1.1/IEvsCameraStream.hal
index 7c7f832..9e4ea19 100644
--- a/automotive/evs/1.1/IEvsCameraStream.hal
+++ b/automotive/evs/1.1/IEvsCameraStream.hal
@@ -17,15 +17,32 @@
package android.hardware.automotive.evs@1.1;
import @1.0::IEvsCameraStream;
+import @1.1::BufferDesc;
+import @1.1::EvsEvent;
/**
* Implemented on client side to receive asynchronous streaming event deliveries.
*/
interface IEvsCameraStream extends @1.0::IEvsCameraStream {
+
+ /**
+ * Receives calls from the HAL each time a video frame is ready for inspection.
+ * Buffer handles received by this method must be returned via calls to
+ * IEvsCamera::doneWithFrame_1_1(). When the video stream is stopped via a call
+ * to IEvsCamera::stopVideoStream(), this callback may continue to happen for
+ * some time as the pipeline drains. Each frame must still be returned.
+ * When the last frame in the stream has been delivered, STREAM_STOPPED
+ * event must be delivered. No further frame deliveries may happen
+ * thereafter.
+ *
+ * @param buffer a buffer descriptor of a delivered image frame.
+ */
+ oneway deliverFrame_1_1(BufferDesc buffer);
+
/**
* Receives calls from the HAL each time an event happens.
*
* @param event EVS event with possible event information.
*/
- oneway notifyEvent(EvsEvent event);
+ oneway notify(EvsEvent event);
};
diff --git a/automotive/evs/1.1/IEvsEnumerator.hal b/automotive/evs/1.1/IEvsEnumerator.hal
new file mode 100644
index 0000000..1695821
--- /dev/null
+++ b/automotive/evs/1.1/IEvsEnumerator.hal
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2019 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.automotive.evs@1.1;
+
+import IEvsCamera;
+import @1.0::IEvsEnumerator;
+import @1.0::EvsResult;
+import android.hardware.camera.device@3.2::Stream;
+
+/**
+ * Provides the mechanism for EVS camera discovery
+ */
+interface IEvsEnumerator extends @1.0::IEvsEnumerator {
+ /**
+ * Returns a list of all EVS cameras available to the system
+ *
+ * @return cameras A list of cameras availale for EVS service.
+ */
+ getCameraList_1_1() generates (vec<CameraDesc> cameras);
+
+ /**
+ * Gets the IEvsCamera associated with a cameraId from a CameraDesc
+ *
+ * Given a camera's unique cameraId from CameraDesc, returns the
+ * IEvsCamera interface associated with the specified camera. When
+ * done using the camera, the caller may release it by calling closeCamera().
+ *
+ * @param cameraId A unique identifier of the camera.
+ * @param streamCfg A stream configuration the client wants to use.
+ * @return evsCamera EvsCamera object associated with a given cameraId.
+ * Returned object would be null if a camera device does
+ * not support a given stream configuration or is already
+ * configured differently by another client.
+ */
+ openCamera_1_1(string cameraId, Stream streamCfg) generates (IEvsCamera evsCamera);
+};
diff --git a/automotive/evs/1.1/default/Android.bp b/automotive/evs/1.1/default/Android.bp
index a463471..41cb426 100644
--- a/automotive/evs/1.1/default/Android.bp
+++ b/automotive/evs/1.1/default/Android.bp
@@ -7,25 +7,41 @@
"service.cpp",
"EvsCamera.cpp",
"EvsEnumerator.cpp",
- "EvsDisplay.cpp"
+ "EvsDisplay.cpp",
+ "ConfigManager.cpp",
+ "ConfigManagerUtil.cpp",
],
init_rc: ["android.hardware.automotive.evs@1.1-service.rc"],
shared_libs: [
"android.hardware.automotive.evs@1.0",
"android.hardware.automotive.evs@1.1",
+ "android.hardware.camera.device@3.2",
"libbase",
"libbinder",
- "libcutils",
+ "liblog",
"libhardware",
"libhidlbase",
"liblog",
"libui",
"libutils",
+ "libcamera_metadata",
+ "libtinyxml2",
],
cflags: [
"-O0",
"-g",
],
+
+ required: [
+ "evs_default_configuration.xml",
+ ],
+}
+
+prebuilt_etc {
+ name: "evs_default_configuration.xml",
+
+ src: "resources/evs_default_configuration.xml",
+ sub_dir: "automotive/evs",
}
diff --git a/automotive/evs/1.1/default/ConfigManager.cpp b/automotive/evs/1.1/default/ConfigManager.cpp
new file mode 100644
index 0000000..96a2f98
--- /dev/null
+++ b/automotive/evs/1.1/default/ConfigManager.cpp
@@ -0,0 +1,487 @@
+/*
+ * Copyright (C) 2019 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 <sstream>
+#include <fstream>
+#include <thread>
+
+#include <hardware/gralloc.h>
+#include <utils/SystemClock.h>
+#include <android/hardware/camera/device/3.2/ICameraDevice.h>
+
+#include "ConfigManager.h"
+
+using ::android::hardware::camera::device::V3_2::StreamRotation;
+
+
+ConfigManager::~ConfigManager() {
+ /* Nothing to do */
+}
+
+
+void ConfigManager::readCameraInfo(const XMLElement * const aCameraElem) {
+ if (aCameraElem == nullptr) {
+ ALOGW("XML file does not have required camera element");
+ return;
+ }
+
+ const XMLElement *curElem = aCameraElem->FirstChildElement();
+ while (curElem != nullptr) {
+ if (!strcmp(curElem->Name(), "group")) {
+ /* camera group identifier */
+ const char *group_id = curElem->FindAttribute("group_id")->Value();
+
+ /* create CameraGroup */
+ unique_ptr<ConfigManager::CameraGroup> aCameraGroup(new ConfigManager::CameraGroup());
+
+ /* add a camera device to its group */
+ addCameraDevices(curElem->FindAttribute("device_id")->Value(), aCameraGroup);
+
+ /* a list of camera stream configurations */
+ const XMLElement *childElem =
+ curElem->FirstChildElement("caps")->FirstChildElement("stream");
+ while (childElem != nullptr) {
+ /* read 5 attributes */
+ const XMLAttribute *idAttr = childElem->FindAttribute("id");
+ const XMLAttribute *widthAttr = childElem->FindAttribute("width");
+ const XMLAttribute *heightAttr = childElem->FindAttribute("height");
+ const XMLAttribute *fmtAttr = childElem->FindAttribute("format");
+ const XMLAttribute *fpsAttr = childElem->FindAttribute("framerate");
+
+ const int32_t id = stoi(idAttr->Value());
+ int32_t framerate = 0;
+ if (fpsAttr != nullptr) {
+ framerate = stoi(fpsAttr->Value());
+ }
+
+ int32_t pixFormat;
+ if (ConfigManagerUtil::convertToPixelFormat(fmtAttr->Value(),
+ pixFormat)) {
+ RawStreamConfiguration cfg = {
+ id,
+ stoi(widthAttr->Value()),
+ stoi(heightAttr->Value()),
+ pixFormat,
+ ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT,
+ framerate
+ };
+ aCameraGroup->streamConfigurations[id] = cfg;
+ }
+
+ childElem = childElem->NextSiblingElement("stream");
+ }
+
+ /* camera group synchronization */
+ const char *sync = curElem->FindAttribute("synchronized")->Value();
+ aCameraGroup->synchronized =
+ static_cast<bool>(strcmp(sync, "false"));
+
+ /* add a group to hash map */
+ mCameraGroups[group_id] = std::move(aCameraGroup);
+ } else if (!strcmp(curElem->Name(), "device")) {
+ /* camera unique identifier */
+ const char *id = curElem->FindAttribute("id")->Value();
+
+ /* camera mount location */
+ const char *pos = curElem->FindAttribute("position")->Value();
+
+ /* store read camera module information */
+ mCameraInfo[id] = readCameraDeviceInfo(curElem);
+
+ /* assign a camera device to a position group */
+ mCameraPosition[pos].emplace(id);
+ } else {
+ /* ignore other device types */
+ ALOGD("Unknown element %s is ignored", curElem->Name());
+ }
+
+ curElem = curElem->NextSiblingElement();
+ }
+}
+
+
+unique_ptr<ConfigManager::CameraInfo>
+ConfigManager::readCameraDeviceInfo(const XMLElement *aDeviceElem) {
+ if (aDeviceElem == nullptr) {
+ return nullptr;
+ }
+
+ /* create a CameraInfo to be filled */
+ unique_ptr<ConfigManager::CameraInfo> aCamera(new ConfigManager::CameraInfo());
+
+ /* size information to allocate camera_metadata_t */
+ size_t totalEntries = 0;
+ size_t totalDataSize = 0;
+
+ /* read device capabilities */
+ totalEntries +=
+ readCameraCapabilities(aDeviceElem->FirstChildElement("caps"),
+ aCamera,
+ totalDataSize);
+
+
+ /* read camera metadata */
+ totalEntries +=
+ readCameraMetadata(aDeviceElem->FirstChildElement("characteristics"),
+ aCamera,
+ totalDataSize);
+
+ /* construct camera_metadata_t */
+ if (!constructCameraMetadata(aCamera, totalEntries, totalDataSize)) {
+ ALOGW("Either failed to allocate memory or "
+ "allocated memory was not large enough");
+ }
+
+ return aCamera;
+}
+
+
+size_t ConfigManager::readCameraCapabilities(const XMLElement * const aCapElem,
+ unique_ptr<ConfigManager::CameraInfo> &aCamera,
+ size_t &dataSize) {
+ if (aCapElem == nullptr) {
+ return 0;
+ }
+
+ string token;
+ const XMLElement *curElem = nullptr;
+
+ /* a list of supported camera parameters/controls */
+ curElem = aCapElem->FirstChildElement("supported_controls");
+ if (curElem != nullptr) {
+ const XMLElement *ctrlElem = curElem->FirstChildElement("control");
+ while (ctrlElem != nullptr) {
+ const char *nameAttr = ctrlElem->FindAttribute("name")->Value();;
+ const int32_t minVal = stoi(ctrlElem->FindAttribute("min")->Value());
+ const int32_t maxVal = stoi(ctrlElem->FindAttribute("max")->Value());
+
+ int32_t stepVal = 1;
+ const XMLAttribute *stepAttr = ctrlElem->FindAttribute("step");
+ if (stepAttr != nullptr) {
+ stepVal = stoi(stepAttr->Value());
+ }
+
+ CameraParam aParam;
+ if (ConfigManagerUtil::convertToEvsCameraParam(nameAttr,
+ aParam)) {
+ aCamera->controls.emplace(
+ aParam,
+ make_tuple(minVal, maxVal, stepVal)
+ );
+ }
+
+ ctrlElem = ctrlElem->NextSiblingElement("control");
+ }
+ }
+
+ /* a list of camera stream configurations */
+ curElem = aCapElem->FirstChildElement("stream");
+ while (curElem != nullptr) {
+ /* read 5 attributes */
+ const XMLAttribute *idAttr = curElem->FindAttribute("id");
+ const XMLAttribute *widthAttr = curElem->FindAttribute("width");
+ const XMLAttribute *heightAttr = curElem->FindAttribute("height");
+ const XMLAttribute *fmtAttr = curElem->FindAttribute("format");
+ const XMLAttribute *fpsAttr = curElem->FindAttribute("framerate");
+
+ const int32_t id = stoi(idAttr->Value());
+ int32_t framerate = 0;
+ if (fpsAttr != nullptr) {
+ framerate = stoi(fpsAttr->Value());
+ }
+
+ int32_t pixFormat;
+ if (ConfigManagerUtil::convertToPixelFormat(fmtAttr->Value(),
+ pixFormat)) {
+ RawStreamConfiguration cfg = {
+ id,
+ stoi(widthAttr->Value()),
+ stoi(heightAttr->Value()),
+ pixFormat,
+ ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT,
+ framerate
+ };
+ aCamera->streamConfigurations[id] = cfg;
+ }
+
+ curElem = curElem->NextSiblingElement("stream");
+ }
+
+ dataSize = calculate_camera_metadata_entry_data_size(
+ get_camera_metadata_tag_type(
+ ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS
+ ),
+ aCamera->streamConfigurations.size() * kStreamCfgSz
+ );
+
+ /* a single camera metadata entry contains multiple stream configurations */
+ return dataSize > 0 ? 1 : 0;
+}
+
+
+size_t ConfigManager::readCameraMetadata(const XMLElement * const aParamElem,
+ unique_ptr<ConfigManager::CameraInfo> &aCamera,
+ size_t &dataSize) {
+ if (aParamElem == nullptr) {
+ return 0;
+ }
+
+ const XMLElement *curElem = aParamElem->FirstChildElement("parameter");
+ size_t numEntries = 0;
+ camera_metadata_tag_t tag;
+ while (curElem != nullptr) {
+ if (!ConfigManagerUtil::convertToMetadataTag(curElem->FindAttribute("name")->Value(),
+ tag)) {
+ switch(tag) {
+ case ANDROID_LENS_DISTORTION:
+ case ANDROID_LENS_POSE_ROTATION:
+ case ANDROID_LENS_POSE_TRANSLATION:
+ case ANDROID_LENS_INTRINSIC_CALIBRATION: {
+ /* float[] */
+ size_t count = 0;
+ void *data = ConfigManagerUtil::convertFloatArray(
+ curElem->FindAttribute("size")->Value(),
+ curElem->FindAttribute("value")->Value(),
+ count
+ );
+
+ aCamera->cameraMetadata[tag] =
+ make_pair(make_unique<void *>(data), count);
+
+ ++numEntries;
+ dataSize += calculate_camera_metadata_entry_data_size(
+ get_camera_metadata_tag_type(tag), count
+ );
+
+ break;
+ }
+
+ default:
+ ALOGW("Parameter %s is not supported",
+ curElem->FindAttribute("name")->Value());
+ break;
+ }
+ }
+
+ curElem = curElem->NextSiblingElement("parameter");
+ }
+
+ return numEntries;
+}
+
+
+bool ConfigManager::constructCameraMetadata(unique_ptr<CameraInfo> &aCamera,
+ const size_t totalEntries,
+ const size_t totalDataSize) {
+ if (!aCamera->allocate(totalEntries, totalDataSize)) {
+ ALOGE("Failed to allocate memory for camera metadata");
+ return false;
+ }
+
+ const size_t numStreamConfigs = aCamera->streamConfigurations.size();
+ unique_ptr<int32_t[]> data(new int32_t[kStreamCfgSz * numStreamConfigs]);
+ int32_t *ptr = data.get();
+ for (auto &cfg : aCamera->streamConfigurations) {
+ for (auto i = 0; i < kStreamCfgSz; ++i) {
+ *ptr++ = cfg.second[i];
+ }
+ }
+ int32_t err = add_camera_metadata_entry(aCamera->characteristics,
+ ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
+ data.get(),
+ numStreamConfigs * kStreamCfgSz);
+
+ if (err) {
+ ALOGE("Failed to add stream configurations to metadata, ignored");
+ return false;
+ }
+
+ bool success = true;
+ for (auto &[tag, entry] : aCamera->cameraMetadata) {
+ /* try to add new camera metadata entry */
+ int32_t err = add_camera_metadata_entry(aCamera->characteristics,
+ tag,
+ entry.first.get(),
+ entry.second);
+ if (err) {
+ ALOGE("Failed to add an entry with a tag 0x%X", tag);
+
+ /* may exceed preallocated capacity */
+ ALOGE("Camera metadata has %ld / %ld entries and %ld / %ld bytes are filled",
+ (long)get_camera_metadata_entry_count(aCamera->characteristics),
+ (long)get_camera_metadata_entry_capacity(aCamera->characteristics),
+ (long)get_camera_metadata_data_count(aCamera->characteristics),
+ (long)get_camera_metadata_data_capacity(aCamera->characteristics));
+ ALOGE("\tCurrent metadata entry requires %ld bytes",
+ (long)calculate_camera_metadata_entry_data_size(tag, entry.second));
+
+ success = false;
+ }
+ }
+
+ ALOGV("Camera metadata has %ld / %ld entries and %ld / %ld bytes are filled",
+ (long)get_camera_metadata_entry_count(aCamera->characteristics),
+ (long)get_camera_metadata_entry_capacity(aCamera->characteristics),
+ (long)get_camera_metadata_data_count(aCamera->characteristics),
+ (long)get_camera_metadata_data_capacity(aCamera->characteristics));
+
+ return success;
+}
+
+
+void ConfigManager::readSystemInfo(const XMLElement * const aSysElem) {
+ if (aSysElem == nullptr) {
+ return;
+ }
+
+ /*
+ * Please note that this function assumes that a given system XML element
+ * and its child elements follow DTD. If it does not, it will cause a
+ * segmentation fault due to the failure of finding expected attributes.
+ */
+
+ /* read number of cameras available in the system */
+ const XMLElement *xmlElem = aSysElem->FirstChildElement("num_cameras");
+ if (xmlElem != nullptr) {
+ mSystemInfo.numCameras =
+ stoi(xmlElem->FindAttribute("value")->Value());
+ }
+}
+
+
+void ConfigManager::readDisplayInfo(const XMLElement * const aDisplayElem) {
+ if (aDisplayElem == nullptr) {
+ ALOGW("XML file does not have required camera element");
+ return;
+ }
+
+ const XMLElement *curDev = aDisplayElem->FirstChildElement("device");
+ while (curDev != nullptr) {
+ const char *id = curDev->FindAttribute("id")->Value();
+ //const char *pos = curDev->FirstAttribute("position")->Value();
+
+ unique_ptr<DisplayInfo> dpy(new DisplayInfo());
+ if (dpy == nullptr) {
+ ALOGE("Failed to allocate memory for DisplayInfo");
+ return;
+ }
+
+ const XMLElement *cap = curDev->FirstChildElement("caps");
+ if (cap != nullptr) {
+ const XMLElement *curStream = cap->FirstChildElement("stream");
+ while (curStream != nullptr) {
+ /* read 4 attributes */
+ const XMLAttribute *idAttr = curStream->FindAttribute("id");
+ const XMLAttribute *widthAttr = curStream->FindAttribute("width");
+ const XMLAttribute *heightAttr = curStream->FindAttribute("height");
+ const XMLAttribute *fmtAttr = curStream->FindAttribute("format");
+
+ const int32_t id = stoi(idAttr->Value());
+ int32_t pixFormat;
+ if (ConfigManagerUtil::convertToPixelFormat(fmtAttr->Value(),
+ pixFormat)) {
+ RawStreamConfiguration cfg = {
+ id,
+ stoi(widthAttr->Value()),
+ stoi(heightAttr->Value()),
+ pixFormat,
+ ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT,
+ 0 // unused
+ };
+ dpy->streamConfigurations[id] = cfg;
+ }
+
+ curStream = curStream->NextSiblingElement("stream");
+ }
+ }
+
+ mDisplayInfo[id] = std::move(dpy);
+ curDev = curDev->NextSiblingElement("device");
+ }
+
+ return;
+}
+
+
+bool ConfigManager::readConfigDataFromXML() noexcept {
+ XMLDocument xmlDoc;
+
+ const int64_t parsingStart = android::elapsedRealtimeNano();
+
+ /* load and parse a configuration file */
+ xmlDoc.LoadFile(mConfigFilePath);
+ if (xmlDoc.ErrorID() != XML_SUCCESS) {
+ ALOGE("Failed to load and/or parse a configuration file, %s", xmlDoc.ErrorStr());
+ return false;
+ }
+
+ /* retrieve the root element */
+ const XMLElement *rootElem = xmlDoc.RootElement();
+ if (strcmp(rootElem->Name(), "configuration")) {
+ ALOGE("A configuration file is not in the required format. "
+ "See /etc/automotive/evs/evs_configuration.dtd");
+ return false;
+ }
+
+ /*
+ * parse camera information; this needs to be done before reading system
+ * information
+ */
+ readCameraInfo(rootElem->FirstChildElement("camera"));
+
+ /* parse system information */
+ readSystemInfo(rootElem->FirstChildElement("system"));
+
+ /* parse display information */
+ readDisplayInfo(rootElem->FirstChildElement("display"));
+
+ const int64_t parsingEnd = android::elapsedRealtimeNano();
+ ALOGI("Parsing configuration file takes %lf (ms)",
+ (double)(parsingEnd - parsingStart) / 1000000.0);
+
+
+ return true;
+}
+
+
+void ConfigManager::addCameraDevices(const char *devices,
+ unique_ptr<CameraGroup> &aGroup) {
+ stringstream device_list(devices);
+ string token;
+ while (getline(device_list, token, ',')) {
+ aGroup->devices.emplace(token);
+ }
+}
+
+
+std::unique_ptr<ConfigManager> ConfigManager::Create(const char *path) {
+ unique_ptr<ConfigManager> cfgMgr(new ConfigManager(path));
+
+ /*
+ * Read a configuration from XML file
+ *
+ * If this is too slow, ConfigManager::readConfigDataFromBinary() and
+ * ConfigManager::writeConfigDataToBinary()can serialize CameraInfo object
+ * to the filesystem and construct CameraInfo instead; this was
+ * evaluated as 10x faster.
+ */
+ if (!cfgMgr->readConfigDataFromXML()) {
+ return nullptr;
+ } else {
+ return cfgMgr;
+ }
+}
+
diff --git a/automotive/evs/1.1/default/ConfigManager.h b/automotive/evs/1.1/default/ConfigManager.h
new file mode 100644
index 0000000..0275f90
--- /dev/null
+++ b/automotive/evs/1.1/default/ConfigManager.h
@@ -0,0 +1,336 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+#ifndef CONFIG_MANAGER_H
+#define CONFIG_MANAGER_H
+
+#include <vector>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+
+#include <tinyxml2.h>
+
+#include <system/camera_metadata.h>
+#include <log/log.h>
+#include <android/hardware/automotive/evs/1.1/types.h>
+
+#include "ConfigManagerUtil.h"
+
+using namespace std;
+using namespace tinyxml2;
+
+using ::android::hardware::hidl_vec;
+using ::android::hardware::camera::device::V3_2::Stream;
+using ::android::hardware::automotive::evs::V1_1::CameraParam;
+
+/*
+ * Plese note that this is different from what is defined in
+ * libhardware/modules/camera/3_4/metadata/types.h; this has one additional
+ * field to store a framerate.
+ */
+const size_t kStreamCfgSz = 6;
+typedef std::array<int32_t, kStreamCfgSz> RawStreamConfiguration;
+
+class ConfigManager {
+public:
+ static std::unique_ptr<ConfigManager> Create(const char *path = "");
+ ConfigManager(const ConfigManager&) = delete;
+ ConfigManager& operator=(const ConfigManager&) = delete;
+
+ virtual ~ConfigManager();
+
+ /* Camera device's capabilities and metadata */
+ class CameraInfo {
+ public:
+ CameraInfo() :
+ characteristics(nullptr) {
+ /* Nothing to do */
+ }
+
+ virtual ~CameraInfo() {
+ free_camera_metadata(characteristics);
+ }
+
+ /* Allocate memory for camera_metadata_t */
+ bool allocate(size_t entry_cap, size_t data_cap) {
+ if (characteristics != nullptr) {
+ ALOGE("Camera metadata is already allocated");
+ return false;
+ }
+
+ characteristics = allocate_camera_metadata(entry_cap, data_cap);
+ return characteristics != nullptr;
+ }
+
+ /*
+ * List of supported controls that the master client can program.
+ * Paraemters are stored with its valid range
+ */
+ unordered_map<CameraParam,
+ tuple<int32_t, int32_t, int32_t>> controls;
+
+ /* List of supported frame rates */
+ unordered_set<int32_t> frameRates;
+
+ /*
+ * List of supported output stream configurations; each array stores
+ * format, width, height, and direction values in the order.
+ */
+ unordered_map<int32_t, RawStreamConfiguration> streamConfigurations;
+
+ /*
+ * Internal storage for camera metadata. Each entry holds a pointer to
+ * data and number of elements
+ */
+ unordered_map<camera_metadata_tag_t,
+ pair<unique_ptr<void *>, size_t>> cameraMetadata;
+
+ /* Camera module characteristics */
+ camera_metadata_t *characteristics;
+ };
+
+ class CameraGroup {
+ public:
+ CameraGroup() {}
+
+ /* ID of member camera devices */
+ unordered_set<string> devices;
+
+ /* The capture operation of member camera devices are synchronized */
+ bool synchronized = false;
+
+ /*
+ * List of stream configurations that are supposed by all camera devices
+ * in this group.
+ */
+ unordered_map<int32_t, RawStreamConfiguration> streamConfigurations;
+ };
+
+ class SystemInfo {
+ public:
+ /* number of available cameras */
+ int32_t numCameras = 0;
+ };
+
+ class DisplayInfo {
+ public:
+ /*
+ * List of supported input stream configurations; each array stores
+ * format, width, height, and direction values in the order.
+ */
+ unordered_map<int32_t, RawStreamConfiguration> streamConfigurations;
+ };
+
+ /*
+ * Return system information
+ *
+ * @return SystemInfo
+ * Constant reference of SystemInfo.
+ */
+ const SystemInfo &getSystemInfo() {
+ return mSystemInfo;
+ }
+
+ /*
+ * Return a list of cameras
+ *
+ * This function assumes that it is not being called frequently.
+ *
+ * @return vector<string>
+ * A vector that contains unique camera device identifiers.
+ */
+ vector<string> getCameraList() {
+ vector<string> aList;
+ for (auto &v : mCameraInfo) {
+ aList.emplace_back(v.first);
+ }
+
+ return aList;
+ }
+
+
+ /*
+ * Return a list of cameras
+ *
+ * @return CameraGroup
+ * A pointer to a camera group identified by a given id.
+ */
+ unique_ptr<CameraGroup>& getCameraGroup(const string& gid) {
+ return mCameraGroups[gid];
+ }
+
+
+ /*
+ * Return a camera metadata
+ *
+ * @param cameraId
+ * Unique camera node identifier in string
+ *
+ * @return unique_ptr<CameraInfo>
+ * A pointer to CameraInfo that is associated with a given camera
+ * ID. This returns a null pointer if this does not recognize a
+ * given camera identifier.
+ */
+ unique_ptr<CameraInfo>& getCameraInfo(const string cameraId) noexcept {
+ return mCameraInfo[cameraId];
+ }
+
+private:
+ /* Constructors */
+ ConfigManager(const char *xmlPath) :
+ mConfigFilePath(xmlPath) {
+ }
+
+ /* System configuration */
+ SystemInfo mSystemInfo;
+
+ /* Internal data structure for camera device information */
+ unordered_map<string, unique_ptr<CameraInfo>> mCameraInfo;
+
+ /* Internal data structure for camera device information */
+ unordered_map<string, unique_ptr<DisplayInfo>> mDisplayInfo;
+
+ /* Camera groups are stored in <groud id, CameraGroup> hash map */
+ unordered_map<string, unique_ptr<CameraGroup>> mCameraGroups;
+
+ /*
+ * Camera positions are stored in <position, camera id set> hash map.
+ * The position must be one of front, rear, left, and right.
+ */
+ unordered_map<string, unordered_set<string>> mCameraPosition;
+
+ /* A path to XML configuration file */
+ const char *mConfigFilePath;
+
+ /*
+ * Parse a given EVS configuration file and store the information
+ * internally.
+ *
+ * @return bool
+ * True if it completes parsing a file successfully.
+ */
+ bool readConfigDataFromXML() noexcept;
+
+ /*
+ * read the information of the vehicle
+ *
+ * @param aSysElem
+ * A pointer to "system" XML element.
+ */
+ void readSystemInfo(const XMLElement * const aSysElem);
+
+ /*
+ * read the information of camera devices
+ *
+ * @param aCameraElem
+ * A pointer to "camera" XML element that may contain multiple
+ * "device" elements.
+ */
+ void readCameraInfo(const XMLElement * const aCameraElem);
+
+ /*
+ * read display device information
+ *
+ * @param aDisplayElem
+ * A pointer to "display" XML element that may contain multiple
+ * "device" elements.
+ */
+ void readDisplayInfo(const XMLElement * const aDisplayElem);
+
+ /*
+ * read camera device information
+ *
+ * @param aDeviceElem
+ * A pointer to "device" XML element that contains camera module
+ * capability info and its characteristics.
+ *
+ * @return unique_ptr<CameraInfo>
+ * A pointer to CameraInfo class that contains camera module
+ * capability and characteristics. Please note that this transfers
+ * the ownership of created CameraInfo to the caller.
+ */
+ unique_ptr<CameraInfo> readCameraDeviceInfo(const XMLElement *aDeviceElem);
+
+ /*
+ * read camera metadata
+ *
+ * @param aCapElem
+ * A pointer to "cap" XML element.
+ * @param aCamera
+ * A pointer to CameraInfo that is being filled by this method.
+ * @param dataSize
+ * Required size of memory to store camera metadata found in this
+ * method. This is calculated in this method and returned to the
+ * caller for camera_metadata allocation.
+ *
+ * @return size_t
+ * Number of camera metadata entries
+ */
+ size_t readCameraCapabilities(const XMLElement * const aCapElem,
+ unique_ptr<CameraInfo> &aCamera,
+ size_t &dataSize);
+
+ /*
+ * read camera metadata
+ *
+ * @param aParamElem
+ * A pointer to "characteristics" XML element.
+ * @param aCamera
+ * A pointer to CameraInfo that is being filled by this method.
+ * @param dataSize
+ * Required size of memory to store camera metadata found in this
+ * method.
+ *
+ * @return size_t
+ * Number of camera metadata entries
+ */
+ size_t readCameraMetadata(const XMLElement * const aParamElem,
+ unique_ptr<CameraInfo> &aCamera,
+ size_t &dataSize);
+
+ /*
+ * construct camera_metadata_t from camera capabilities and metadata
+ *
+ * @param aCamera
+ * A pointer to CameraInfo that is being filled by this method.
+ * @param totalEntries
+ * Number of camera metadata entries to be added.
+ * @param totalDataSize
+ * Sum of sizes of camera metadata entries to be added.
+ *
+ * @return bool
+ * False if either it fails to allocate memory for camera metadata
+ * or its size is not large enough to add all found camera metadata
+ * entries.
+ */
+ bool constructCameraMetadata(unique_ptr<CameraInfo> &aCamera,
+ const size_t totalEntries,
+ const size_t totalDataSize);
+
+ /*
+ * parse a comma-separated list of camera devices and add them to
+ * CameraGroup.
+ *
+ * @param devices
+ * A comma-separated list of camera device identifiers.
+ * @param aGroup
+ * Camera group which cameras will be added to.
+ */
+ void addCameraDevices(const char *devices,
+ unique_ptr<CameraGroup> &aGroup);
+};
+#endif // CONFIG_MANAGER_H
+
diff --git a/automotive/evs/1.1/default/ConfigManagerUtil.cpp b/automotive/evs/1.1/default/ConfigManagerUtil.cpp
new file mode 100644
index 0000000..8206daa
--- /dev/null
+++ b/automotive/evs/1.1/default/ConfigManagerUtil.cpp
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2019 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 "ConfigManagerUtil.h"
+
+#include <string>
+#include <sstream>
+#include <linux/videodev2.h>
+
+#include <log/log.h>
+#include <system/graphics-base-v1.0.h>
+
+
+bool ConfigManagerUtil::convertToEvsCameraParam(const string &id,
+ CameraParam &camParam) {
+ string trimmed = ConfigManagerUtil::trimString(id);
+ bool success = true;
+
+ if (!trimmed.compare("BRIGHTNESS")) {
+ camParam = CameraParam::BRIGHTNESS;
+ } else if (!trimmed.compare("CONTRAST")) {
+ camParam = CameraParam::CONTRAST;
+ } else if (!trimmed.compare("AUTOGAIN")) {
+ camParam = CameraParam::AUTOGAIN;
+ } else if (!trimmed.compare("GAIN")) {
+ camParam = CameraParam::GAIN;
+ } else if (!trimmed.compare("AUTO_WHITE_BALANCE")) {
+ camParam = CameraParam::AUTO_WHITE_BALANCE;
+ } else if (!trimmed.compare("WHITE_BALANCE_TEMPERATURE")) {
+ camParam = CameraParam::WHITE_BALANCE_TEMPERATURE;
+ } else if (!trimmed.compare("SHARPNESS")) {
+ camParam = CameraParam::SHARPNESS;
+ } else if (!trimmed.compare("AUTO_EXPOSURE")) {
+ camParam = CameraParam::AUTO_EXPOSURE;
+ } else if (!trimmed.compare("ABSOLUTE_EXPOSURE")) {
+ camParam = CameraParam::ABSOLUTE_EXPOSURE;
+ } else if (!trimmed.compare("ABSOLUTE_FOCUS")) {
+ camParam = CameraParam::ABSOLUTE_FOCUS;
+ } else if (!trimmed.compare("AUTO_FOCUS")) {
+ camParam = CameraParam::AUTO_FOCUS;
+ } else if (!trimmed.compare("ABSOLUTE_ZOOM")) {
+ camParam = CameraParam::ABSOLUTE_ZOOM;
+ } else {
+ success = false;
+ }
+
+ return success;
+}
+
+
+bool ConfigManagerUtil::convertToPixelFormat(const string &format,
+ int32_t &pixFormat) {
+ string trimmed = ConfigManagerUtil::trimString(format);
+ bool success = true;
+
+ if (!trimmed.compare("RGBA_8888")) {
+ pixFormat = HAL_PIXEL_FORMAT_RGBA_8888;
+ } else if (!trimmed.compare("YCRCB_420_SP")) {
+ pixFormat = HAL_PIXEL_FORMAT_YCRCB_420_SP;
+ } else if (!trimmed.compare("YCBCR_422_I")) {
+ pixFormat = HAL_PIXEL_FORMAT_YCBCR_422_I;
+ } else {
+ success = false;
+ }
+
+ return success;
+}
+
+
+bool ConfigManagerUtil::convertToMetadataTag(const char *name,
+ camera_metadata_tag &aTag) {
+ if (!strcmp(name, "LENS_DISTORTION")) {
+ aTag = ANDROID_LENS_DISTORTION;
+ } else if (!strcmp(name, "LENS_INTRINSIC_CALIBRATION")) {
+ aTag = ANDROID_LENS_INTRINSIC_CALIBRATION;
+ } else if (!strcmp(name, "LENS_POSE_ROTATION")) {
+ aTag = ANDROID_LENS_POSE_ROTATION;
+ } else if (!strcmp(name, "LENS_POSE_TRANSLATION")) {
+ aTag = ANDROID_LENS_POSE_TRANSLATION;
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+
+float *ConfigManagerUtil::convertFloatArray(const char *sz, const char *vals,
+ size_t &count, const char delimiter) {
+ string size_string(sz);
+ string value_string(vals);
+
+ count = stoi(size_string);
+ float *result = new float[count];
+ stringstream values(value_string);
+
+ int32_t idx = 0;
+ string token;
+ while (getline(values, token, delimiter)) {
+ result[idx++] = stof(token);
+ }
+
+ return result;
+}
+
+
+string ConfigManagerUtil::trimString(const string &src, const string &ws) {
+ const auto s = src.find_first_not_of(ws);
+ if (s == string::npos) {
+ return "";
+ }
+
+ const auto e = src.find_last_not_of(ws);
+ const auto r = e - s + 1;
+
+ return src.substr(s, r);
+}
+
diff --git a/automotive/evs/1.1/default/ConfigManagerUtil.h b/automotive/evs/1.1/default/ConfigManagerUtil.h
new file mode 100644
index 0000000..8c89ae7
--- /dev/null
+++ b/automotive/evs/1.1/default/ConfigManagerUtil.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+#ifndef CONFIG_MANAGER_UTIL_H
+#define CONFIG_MANAGER_UTIL_H
+
+#include <utility>
+#include <string>
+#include <system/camera_metadata.h>
+#include <android/hardware/automotive/evs/1.1/types.h>
+
+using namespace std;
+using ::android::hardware::automotive::evs::V1_1::CameraParam;
+
+
+class ConfigManagerUtil {
+public:
+ /**
+ * Convert a given string into V4L2_CID_*
+ */
+ static bool convertToEvsCameraParam(const string &id,
+ CameraParam &camParam);
+ /**
+ * Convert a given string into android.hardware.graphics.common.PixelFormat
+ */
+ static bool convertToPixelFormat(const string &format,
+ int32_t &pixelFormat);
+ /**
+ * Convert a given string into corresponding camera metadata data tag defined in
+ * system/media/camera/include/system/camera_metadta_tags.h
+ */
+ static bool convertToMetadataTag(const char *name,
+ camera_metadata_tag &aTag);
+ /**
+ * Convert a given string into a floating value array
+ */
+ static float *convertFloatArray(const char *sz,
+ const char *vals,
+ size_t &count,
+ const char delimiter = ',');
+ /**
+ * Trim a string
+ */
+ static string trimString(const string &src,
+ const string &ws = " \n\r\t\f\v");
+};
+
+#endif // CONFIG_MANAGER_UTIL_H
+
diff --git a/automotive/evs/1.1/default/EvsCamera.cpp b/automotive/evs/1.1/default/EvsCamera.cpp
index 2d55566..5ba753d 100644
--- a/automotive/evs/1.1/default/EvsCamera.cpp
+++ b/automotive/evs/1.1/default/EvsCamera.cpp
@@ -40,28 +40,21 @@
const unsigned MAX_BUFFERS_IN_FLIGHT = 100;
-EvsCamera::EvsCamera(const char *id) :
+EvsCamera::EvsCamera(const char *id,
+ unique_ptr<ConfigManager::CameraInfo> &camInfo) :
mFramesAllowed(0),
mFramesInUse(0),
- mStreamState(STOPPED) {
+ mStreamState(STOPPED),
+ mCameraInfo(camInfo) {
ALOGD("EvsCamera instantiated");
- mDescription.cameraId = id;
+ /* set a camera id */
+ mDescription.v1.cameraId = id;
- // Set up dummy data for testing
- if (mDescription.cameraId == kCameraName_Backup) {
- mWidth = 640; // full NTSC/VGA
- mHeight = 480; // full NTSC/VGA
- mDescription.vendorFlags = 0xFFFFFFFF; // Arbitrary value
- } else {
- mWidth = 320; // 1/2 NTSC/VGA
- mHeight = 240; // 1/2 NTSC/VGA
- }
-
- mFormat = HAL_PIXEL_FORMAT_RGBA_8888;
- mUsage = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_CAMERA_WRITE |
- GRALLOC_USAGE_SW_READ_RARELY | GRALLOC_USAGE_SW_WRITE_RARELY;
+ /* set camera metadata */
+ mDescription.metadata.setToExternal((uint8_t *)camInfo->characteristics,
+ get_camera_metadata_size(camInfo->characteristics));
}
@@ -109,7 +102,7 @@
ALOGD("getCameraInfo");
// Send back our self description
- _hidl_cb(mDescription);
+ _hidl_cb(mDescription.v1);
return Void();
}
@@ -194,7 +187,7 @@
// Block outside the mutex until the "stop" flag has been acknowledged
// We won't send any more frames, but the client might still get some already in flight
- ALOGD("Waiting for stream thread to end..");
+ ALOGD("Waiting for stream thread to end...");
lock.unlock();
mCaptureThread.join();
lock.lock();
@@ -238,6 +231,15 @@
// Methods from ::android::hardware::automotive::evs::V1_1::IEvsCamera follow.
+Return<void> EvsCamera::getCameraInfo_1_1(getCameraInfo_1_1_cb _hidl_cb) {
+ ALOGD("getCameraInfo_1_1");
+
+ // Send back our self description
+ _hidl_cb(mDescription);
+ return Void();
+}
+
+
Return<EvsResult> EvsCamera::doneWithFrame_1_1(const BufferDesc_1_1& bufDesc) {
std::lock_guard <std::mutex> lock(mAccessLock);
returnBuffer(bufDesc.bufferId, bufDesc.buffer.nativeHandle);
@@ -278,8 +280,29 @@
}
-Return<void> EvsCamera::setParameter(CameraParam id, int32_t value,
- setParameter_cb _hidl_cb) {
+Return<void> EvsCamera::getParameterList(getParameterList_cb _hidl_cb) {
+ hidl_vec<CameraParam> hidlCtrls;
+ hidlCtrls.resize(mCameraInfo->controls.size());
+ unsigned idx = 0;
+ for (auto& [cid, cfg] : mCameraInfo->controls) {
+ hidlCtrls[idx++] = cid;
+ }
+
+ _hidl_cb(hidlCtrls);
+ return Void();
+}
+
+
+Return<void> EvsCamera::getIntParameterRange(CameraParam id,
+ getIntParameterRange_cb _hidl_cb) {
+ auto range = mCameraInfo->controls[id];
+ _hidl_cb(get<0>(range), get<1>(range), get<2>(range));
+ return Void();
+}
+
+
+Return<void> EvsCamera::setIntParameter(CameraParam id, int32_t value,
+ setIntParameter_cb _hidl_cb) {
// Default implementation does not support this.
(void)id;
(void)value;
@@ -288,7 +311,8 @@
}
-Return<void> EvsCamera::getParameter(CameraParam id, getParameter_cb _hidl_cb) {
+Return<void> EvsCamera::getIntParameter(CameraParam id,
+ getIntParameter_cb _hidl_cb) {
// Default implementation does not support this.
(void)id;
_hidl_cb(EvsResult::INVALID_ARG, 0);
@@ -471,9 +495,7 @@
fillTestFrame(newBuffer);
// Issue the (asynchronous) callback to the client -- can't be holding the lock
- EvsEvent event;
- event.buffer(newBuffer);
- auto result = mStream->notifyEvent(event);
+ auto result = mStream->deliverFrame_1_1(newBuffer);
if (result.isOk()) {
ALOGD("Delivered %p as id %d",
newBuffer.buffer.nativeHandle.getNativeHandle(), newBuffer.bufferId);
@@ -506,10 +528,8 @@
// If we've been asked to stop, send an event to signal the actual end of stream
EvsEvent event;
- InfoEventDesc desc = {};
- desc.aType = InfoEventType::STREAM_STOPPED;
- event.info(desc);
- auto result = mStream->notifyEvent(event);
+ event.aType = EvsEventType::STREAM_STOPPED;
+ auto result = mStream->notify(event);
if (!result.isOk()) {
ALOGE("Error delivering end of stream marker");
}
@@ -616,6 +636,38 @@
}
+sp<EvsCamera> EvsCamera::Create(const char *deviceName) {
+ unique_ptr<ConfigManager::CameraInfo> nullCamInfo = nullptr;
+
+ return Create(deviceName, nullCamInfo);
+}
+
+
+sp<EvsCamera> EvsCamera::Create(const char *deviceName,
+ unique_ptr<ConfigManager::CameraInfo> &camInfo,
+ const Stream *streamCfg) {
+ sp<EvsCamera> evsCamera = new EvsCamera(deviceName, camInfo);
+ if (evsCamera == nullptr) {
+ return nullptr;
+ }
+
+ /* default implementation does not use a given configuration */
+ (void)streamCfg;
+
+ /* Use the first resolution from the list for the testing */
+ auto it = camInfo->streamConfigurations.begin();
+ evsCamera->mWidth = it->second[1];
+ evsCamera->mHeight = it->second[2];
+ evsCamera->mDescription.v1.vendorFlags = 0xFFFFFFFF; // Arbitrary test value
+
+ evsCamera->mFormat = HAL_PIXEL_FORMAT_RGBA_8888;
+ evsCamera->mUsage = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_CAMERA_WRITE |
+ GRALLOC_USAGE_SW_READ_RARELY | GRALLOC_USAGE_SW_WRITE_RARELY;
+
+ return evsCamera;
+}
+
+
} // namespace implementation
} // namespace V1_0
} // namespace evs
diff --git a/automotive/evs/1.1/default/EvsCamera.h b/automotive/evs/1.1/default/EvsCamera.h
index 47a3164..c15b4b1 100644
--- a/automotive/evs/1.1/default/EvsCamera.h
+++ b/automotive/evs/1.1/default/EvsCamera.h
@@ -25,6 +25,8 @@
#include <thread>
+#include "ConfigManager.h"
+
using BufferDesc_1_0 = ::android::hardware::automotive::evs::V1_0::BufferDesc;
using BufferDesc_1_1 = ::android::hardware::automotive::evs::V1_1::BufferDesc;
using IEvsCameraStream_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCameraStream;
@@ -59,18 +61,28 @@
Return<EvsResult> setExtendedInfo(uint32_t opaqueIdentifier, int32_t opaqueValue) override;
// Methods from ::android::hardware::automotive::evs::V1_1::IEvsCamera follow.
+ Return<void> getCameraInfo_1_1(getCameraInfo_1_1_cb _hidl_cb) override;
Return<EvsResult> pauseVideoStream() override;
Return<EvsResult> resumeVideoStream() override;
Return<EvsResult> doneWithFrame_1_1(const BufferDesc_1_1& buffer) override;
Return<EvsResult> setMaster() override;
Return<EvsResult> forceMaster(const sp<IEvsDisplay>& display) override;
Return<EvsResult> unsetMaster() override;
- Return<void> setParameter(CameraParam id, int32_t value,
- setParameter_cb _hidl_cb) override;
- Return<void> getParameter(CameraParam id, getParameter_cb _hidl_cb) override;
+ Return<void> getParameterList(getParameterList_cb _hidl_cb) override;
+ Return<void> getIntParameterRange(CameraParam id,
+ getIntParameterRange_cb _hidl_cb) override;
+ Return<void> setIntParameter(CameraParam id, int32_t value,
+ setIntParameter_cb _hidl_cb) override;
+ Return<void> getIntParameter(CameraParam id,
+ getIntParameter_cb _hidl_cb) override;
- // Implementation details
- EvsCamera(const char *id);
+ static sp<EvsCamera> Create(const char *deviceName);
+ static sp<EvsCamera> Create(const char *deviceName,
+ unique_ptr<ConfigManager::CameraInfo> &camInfo,
+ const Stream *streamCfg = nullptr);
+ EvsCamera(const EvsCamera&) = delete;
+ EvsCamera& operator=(const EvsCamera&) = delete;
+
virtual ~EvsCamera() override;
void forceShutdown(); // This gets called if another caller "steals" ownership of the camera
@@ -79,7 +91,10 @@
static const char kCameraName_Backup[];
private:
+ EvsCamera(const char *id,
+ unique_ptr<ConfigManager::CameraInfo> &camInfo);
// These three functions are expected to be called while mAccessLock is held
+ //
bool setAvailableFrames_Locked(unsigned bufferCount);
unsigned increaseAvailableFrames_Locked(unsigned numToAdd);
unsigned decreaseAvailableFrames_Locked(unsigned numToRemove);
@@ -124,6 +139,9 @@
// Synchronization necessary to deconflict mCaptureThread from the main service thread
std::mutex mAccessLock;
+
+ // Static camera module information
+ unique_ptr<ConfigManager::CameraInfo> &mCameraInfo;
};
} // namespace implementation
diff --git a/automotive/evs/1.1/default/EvsEnumerator.cpp b/automotive/evs/1.1/default/EvsEnumerator.cpp
index b324907..a010729 100644
--- a/automotive/evs/1.1/default/EvsEnumerator.cpp
+++ b/automotive/evs/1.1/default/EvsEnumerator.cpp
@@ -33,6 +33,7 @@
// constructs a new instance for each client.
std::list<EvsEnumerator::CameraRecord> EvsEnumerator::sCameraList;
wp<EvsDisplay> EvsEnumerator::sActiveDisplay;
+unique_ptr<ConfigManager> EvsEnumerator::sConfigManager;
EvsEnumerator::EvsEnumerator() {
@@ -40,9 +41,11 @@
// Add sample camera data to our list of cameras
// In a real driver, this would be expected to can the available hardware
- sCameraList.emplace_back(EvsCamera::kCameraName_Backup);
- sCameraList.emplace_back("LaneView");
- sCameraList.emplace_back("right turn");
+ sConfigManager =
+ ConfigManager::Create("/etc/automotive/evs/evs_sample_configuration.xml");
+ for (auto v : sConfigManager->getCameraList()) {
+ sCameraList.emplace_back(v.c_str());
+ }
}
@@ -57,7 +60,7 @@
std::vector<CameraDesc_1_0> descriptions;
descriptions.reserve(numCameras);
for (const auto& cam : sCameraList) {
- descriptions.push_back( cam.desc );
+ descriptions.push_back( cam.desc.v1 );
}
// Encapsulate our camera descriptions in the HIDL vec type
@@ -78,7 +81,7 @@
// Find the named camera
CameraRecord *pRecord = nullptr;
for (auto &&cam : sCameraList) {
- if (cam.desc.cameraId == cameraId) {
+ if (cam.desc.v1.cameraId == cameraId) {
// Found a match!
pRecord = &cam;
break;
@@ -99,7 +102,12 @@
}
// Construct a camera instance for the caller
- pActiveCamera = new EvsCamera(cameraId.c_str());
+ if (sConfigManager == nullptr) {
+ pActiveCamera = EvsCamera::Create(cameraId.c_str());
+ } else {
+ pActiveCamera = EvsCamera::Create(cameraId.c_str(),
+ sConfigManager->getCameraInfo(cameraId));
+ }
pRecord->activeInstance = pActiveCamera;
if (pActiveCamera == nullptr) {
ALOGE("Failed to allocate new EvsCamera object for %s\n", cameraId.c_str());
@@ -120,15 +128,15 @@
// Get the camera id so we can find it in our list
std::string cameraId;
- pCamera_1_1->getCameraInfo([&cameraId](CameraDesc desc) {
- cameraId = desc.cameraId;
+ pCamera_1_1->getCameraInfo_1_1([&cameraId](CameraDesc desc) {
+ cameraId = desc.v1.cameraId;
}
);
// Find the named camera
CameraRecord *pRecord = nullptr;
for (auto &&cam : sCameraList) {
- if (cam.desc.cameraId == cameraId) {
+ if (cam.desc.v1.cameraId == cameraId) {
// Found a match!
pRecord = &cam;
break;
@@ -209,6 +217,89 @@
}
+// Methods from ::android::hardware::automotive::evs::V1_1::IEvsEnumerator follow.
+Return<void> EvsEnumerator::getCameraList_1_1(getCameraList_1_1_cb _hidl_cb) {
+ ALOGD("getCameraList");
+
+ const unsigned numCameras = sCameraList.size();
+
+ // Build up a packed array of CameraDesc for return
+ // NOTE: Only has to live until the callback returns
+ std::vector<CameraDesc_1_1> descriptions;
+ descriptions.reserve(numCameras);
+ for (const auto& cam : sCameraList) {
+ descriptions.push_back( cam.desc );
+ }
+
+ // Encapsulate our camera descriptions in the HIDL vec type
+ hidl_vec<CameraDesc_1_1> hidlCameras(descriptions);
+
+ // Send back the results
+ ALOGD("reporting %zu cameras available", hidlCameras.size());
+ _hidl_cb(hidlCameras);
+
+ // HIDL convention says we return Void if we sent our result back via callback
+ return Void();
+}
+
+Return<sp<IEvsCamera_1_1>>
+EvsEnumerator::openCamera_1_1(const hidl_string& cameraId,
+ const Stream& streamCfg) {
+ // Find the named camera
+ CameraRecord *pRecord = nullptr;
+ for (auto &&cam : sCameraList) {
+ if (cam.desc.v1.cameraId == cameraId) {
+ // Found a match!
+ pRecord = &cam;
+ break;
+ }
+ }
+
+ // Is this a recognized camera id?
+ if (!pRecord) {
+ ALOGE("Requested camera %s not found", cameraId.c_str());
+ return nullptr;
+ }
+
+ // Has this camera already been instantiated by another caller?
+ sp<EvsCamera> pActiveCamera = pRecord->activeInstance.promote();
+ if (pActiveCamera != nullptr) {
+ ALOGW("Killing previous camera because of new caller");
+ closeCamera(pActiveCamera);
+ }
+
+ // Construct a camera instance for the caller
+ if (sConfigManager == nullptr) {
+ pActiveCamera = EvsCamera::Create(cameraId.c_str());
+ } else {
+ pActiveCamera = EvsCamera::Create(cameraId.c_str(),
+ sConfigManager->getCameraInfo(cameraId),
+ &streamCfg);
+ }
+
+ pRecord->activeInstance = pActiveCamera;
+ if (pActiveCamera == nullptr) {
+ ALOGE("Failed to allocate new EvsCamera object for %s\n", cameraId.c_str());
+ }
+
+ return pActiveCamera;
+}
+
+
+EvsEnumerator::CameraRecord* EvsEnumerator::findCameraById(const std::string& cameraId) {
+ // Find the named camera
+ CameraRecord *pRecord = nullptr;
+ for (auto &&cam : sCameraList) {
+ if (cam.desc.v1.cameraId == cameraId) {
+ // Found a match!
+ pRecord = &cam;
+ break;
+ }
+ }
+
+ return pRecord;
+}
+
} // namespace implementation
} // namespace V1_1
} // namespace evs
diff --git a/automotive/evs/1.1/default/EvsEnumerator.h b/automotive/evs/1.1/default/EvsEnumerator.h
index 11c2170..475ec76 100644
--- a/automotive/evs/1.1/default/EvsEnumerator.h
+++ b/automotive/evs/1.1/default/EvsEnumerator.h
@@ -17,18 +17,20 @@
#ifndef ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSCAMERAENUMERATOR_H
#define ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSCAMERAENUMERATOR_H
-#include <android/hardware/automotive/evs/1.0/IEvsEnumerator.h>
+#include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
#include <android/hardware/automotive/evs/1.1/IEvsCamera.h>
#include <list>
+#include "ConfigManager.h"
+
using ::android::hardware::automotive::evs::V1_0::EvsResult;
using ::android::hardware::automotive::evs::V1_0::IEvsDisplay;
using ::android::hardware::automotive::evs::V1_0::DisplayState;
-using ::android::hardware::automotive::evs::V1_0::IEvsEnumerator;
using IEvsCamera_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCamera;
using IEvsCamera_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCamera;
using CameraDesc_1_0 = ::android::hardware::automotive::evs::V1_0::CameraDesc;
+using CameraDesc_1_1 = ::android::hardware::automotive::evs::V1_1::CameraDesc;
namespace android {
@@ -53,6 +55,11 @@
Return<void> closeDisplay(const ::android::sp<IEvsDisplay>& display) override;
Return<DisplayState> getDisplayState() override;
+ // Methods from ::android::hardware::automotive::evs::V1_1::IEvsEnumerator follow.
+ Return<void> getCameraList_1_1(getCameraList_1_1_cb _hidl_cb) override;
+ Return<sp<IEvsCamera_1_1>> openCamera_1_1(const hidl_string& cameraId,
+ const Stream& streamCfg) override;
+
// Implementation details
EvsEnumerator();
@@ -61,14 +68,20 @@
// That is to say, this is effectively a singleton despite the fact that HIDL
// constructs a new instance for each client.
struct CameraRecord {
- CameraDesc_1_0 desc;
+ CameraDesc_1_1 desc;
wp<EvsCamera> activeInstance;
- CameraRecord(const char *cameraId) : desc() { desc.cameraId = cameraId; }
+ CameraRecord(const char *cameraId) : desc() { desc.v1.cameraId = cameraId; }
};
- static std::list<CameraRecord> sCameraList;
- static wp<EvsDisplay> sActiveDisplay; // Weak pointer. Object destructs if client dies.
+ static CameraRecord* findCameraById(const std::string& cameraId);
+
+ static std::list<CameraRecord> sCameraList;
+
+ // Weak pointer. Object destructs if client dies.
+ static wp<EvsDisplay> sActiveDisplay;
+
+ static unique_ptr<ConfigManager> sConfigManager;
};
} // namespace implementation
diff --git a/automotive/evs/1.1/default/resources/evs_default_configuration.xml b/automotive/evs/1.1/default/resources/evs_default_configuration.xml
new file mode 100644
index 0000000..692102e
--- /dev/null
+++ b/automotive/evs/1.1/default/resources/evs_default_configuration.xml
@@ -0,0 +1,68 @@
+<?xml version='1.0' encoding='utf-8'?>
+<!-- Copyright (C) 2019 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.
+-->
+
+<!-- Exterior View System Example Configuration
+
+ Android Automotive axes are used to define coordinates.
+ See https://source.android.com/devices/sensors/sensor-types#auto_axes
+
+ Use evs_configuration.dtd with xmllint tool, to validate XML configuration file
+-->
+
+<configuration>
+ <!-- system configuration -->
+ <system>
+ <!-- number of cameras available to EVS -->
+ <num_cameras value='1'/>
+ </system>
+
+ <!-- camera device information -->
+ <camera>
+ <!-- camera device starts -->
+ <device id='/dev/video1' position='rear'>
+ <caps>
+ <!-- list of supported controls -->
+ <supported_controls>
+ <control name='BRIGHTNESS' min='0' max='255'/>
+ <control name='CONTRAST' min='0' max='255'/>
+ </supported_controls>
+
+ <stream id='0' width='640' height='360' format='RGBA_8888' framerate='30'/>
+ </caps>
+
+ <!-- list of parameters -->
+ <characteristics>
+ <!-- Camera intrinsic calibration matrix. See
+ https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#LENS_INTRINSIC_CALIBRATION
+ -->
+ <parameter
+ name='LENS_INTRINSIC_CALIBRATION'
+ type='float'
+ size='5'
+ value='0.0,0.0,0.0,0.0,0.0'
+ />
+ </characteristics>
+ </device>
+ </camera>
+ <display>
+ <device id='display0' position='driver'>
+ <caps>
+ <!-- list of supported inpu stream configurations -->
+ <stream id='0' width='1280' height='720' format='RGBA_8888' framerate='30'/>
+ </caps>
+ </device>
+ </display>
+</configuration>
+
diff --git a/automotive/evs/1.1/default/service.cpp b/automotive/evs/1.1/default/service.cpp
index 128a14a..5135864 100644
--- a/automotive/evs/1.1/default/service.cpp
+++ b/automotive/evs/1.1/default/service.cpp
@@ -33,7 +33,7 @@
using android::hardware::joinRpcThreadpool;
// Generated HIDL files
-using android::hardware::automotive::evs::V1_0::IEvsEnumerator;
+using android::hardware::automotive::evs::V1_1::IEvsEnumerator;
using android::hardware::automotive::evs::V1_0::IEvsDisplay;
// The namespace in which all our implementation code lives
diff --git a/automotive/evs/1.1/types.hal b/automotive/evs/1.1/types.hal
index 2c6b2ed..dcb2abb 100644
--- a/automotive/evs/1.1/types.hal
+++ b/automotive/evs/1.1/types.hal
@@ -21,6 +21,22 @@
import @1.0::DisplayState;
import @1.0::EvsResult;
import android.hardware.graphics.common@1.2::HardwareBuffer;
+import android.hardware.camera.device@3.2::CameraMetadata;
+
+/**
+ * Structure describing the basic properties of an EVS camera, extended from its
+ * v1.0 declaration.
+ *
+ * The HAL is responsible for filling out this structure for each
+ * EVS camera in the system.
+ */
+struct CameraDesc {
+ @1.0::CameraDesc v1;
+ /**
+ * Store camera metadata such as lens characteristics.
+ */
+ CameraMetadata metadata;
+};
/**
* Structure representing an image buffer through our APIs
@@ -50,7 +66,7 @@
/**
* Types of informative streaming events
*/
-enum InfoEventType : uint32_t {
+enum EvsEventType : uint32_t {
/**
* Video stream is started
*/
@@ -81,11 +97,11 @@
/**
* Structure that describes informative events occurred during EVS is streaming
*/
-struct InfoEventDesc {
+struct EvsEvent {
/**
* Type of an informative event
*/
- InfoEventType aType;
+ EvsEventType aType;
/**
* Possible additional information
*/
@@ -93,20 +109,6 @@
};
/**
- * EVS event definition
- */
-safe_union EvsEvent {
- /**
- * A buffer descriptor of an image frame
- */
- BufferDesc buffer;
- /**
- * General streaming events
- */
- InfoEventDesc info;
-};
-
-/**
* EVS Camera Parameter
*/
enum CameraParam : uint32_t {
@@ -127,14 +129,6 @@
*/
GAIN,
/**
- * Mirror the image horizontally
- */
- HFLIP,
- /**
- * Mirror the image vertically
- */
- VFLIP,
- /**
* Automatic Whitebalance
*/
AUTO_WHITE_BALANCE,
@@ -156,11 +150,6 @@
*/
ABSOLUTE_EXPOSURE,
/**
- * When AEC is running in either auto or aperture priority, this parameter
- * sets whether a frame rate varies.
- */
- AUTO_EXPOSURE_PRIORITY,
- /**
* Set the focal point of the camera to the specified position. This
* parameter may not be effective when auto focus is enabled.
*/
diff --git a/automotive/evs/1.1/vts/functional/Android.bp b/automotive/evs/1.1/vts/functional/Android.bp
index 55c50a4..4753933 100644
--- a/automotive/evs/1.1/vts/functional/Android.bp
+++ b/automotive/evs/1.1/vts/functional/Android.bp
@@ -23,6 +23,7 @@
defaults: ["VtsHalTargetTestDefaults"],
shared_libs: [
"libui",
+ "libcamera_metadata",
],
static_libs: [
"android.hardware.automotive.evs@1.0",
@@ -31,6 +32,7 @@
"android.hardware.graphics.common@1.0",
"android.hardware.graphics.common@1.1",
"android.hardware.graphics.common@1.2",
+ "android.hardware.camera.device@3.2",
],
test_suites: ["general-tests"],
cflags: [
diff --git a/automotive/evs/1.1/vts/functional/FrameHandler.cpp b/automotive/evs/1.1/vts/functional/FrameHandler.cpp
index 1627689..6d53652 100644
--- a/automotive/evs/1.1/vts/functional/FrameHandler.cpp
+++ b/automotive/evs/1.1/vts/functional/FrameHandler.cpp
@@ -138,93 +138,93 @@
}
-Return<void> FrameHandler::notifyEvent(const EvsEvent& event) {
- // Local flag we use to keep track of when the stream is stopping
- auto type = event.getDiscriminator();
- if (type == EvsEvent::hidl_discriminator::info) {
- mLock.lock();
- mLatestEventDesc = event.info();
- if (mLatestEventDesc.aType == InfoEventType::STREAM_STOPPED) {
- // Signal that the last frame has been received and the stream is stopped
- mRunning = false;
- } else if (mLatestEventDesc.aType == InfoEventType::PARAMETER_CHANGED) {
- ALOGD("Camera parameter 0x%X is changed to 0x%X",
- mLatestEventDesc.payload[0], mLatestEventDesc.payload[1]);
+Return<void> FrameHandler::deliverFrame_1_1(const BufferDesc_1_1& bufDesc) {
+ const AHardwareBuffer_Desc* pDesc =
+ reinterpret_cast<const AHardwareBuffer_Desc *>(&bufDesc.buffer.description);
+ ALOGD("Received a frame from the camera (%p)",
+ bufDesc.buffer.nativeHandle.getNativeHandle());
+
+ // Store a dimension of a received frame.
+ mFrameWidth = pDesc->width;
+ mFrameHeight = pDesc->height;
+
+ // If we were given an opened display at construction time, then send the received
+ // image back down the camera.
+ if (mDisplay.get()) {
+ // Get the output buffer we'll use to display the imagery
+ BufferDesc_1_0 tgtBuffer = {};
+ mDisplay->getTargetBuffer([&tgtBuffer](const BufferDesc_1_0& buff) {
+ tgtBuffer = buff;
+ }
+ );
+
+ if (tgtBuffer.memHandle == nullptr) {
+ printf("Didn't get target buffer - frame lost\n");
+ ALOGE("Didn't get requested output buffer -- skipping this frame.");
} else {
- ALOGD("Received an event %s", eventToString(mLatestEventDesc.aType));
- }
- mLock.unlock();
- mEventSignal.notify_all();
- } else {
- auto bufDesc = event.buffer();
- const AHardwareBuffer_Desc* pDesc =
- reinterpret_cast<const AHardwareBuffer_Desc *>(&bufDesc.buffer.description);
- ALOGD("Received a frame from the camera (%p)",
- bufDesc.buffer.nativeHandle.getNativeHandle());
+ // Copy the contents of the of buffer.memHandle into tgtBuffer
+ copyBufferContents(tgtBuffer, bufDesc);
- // Store a dimension of a received frame.
- mFrameWidth = pDesc->width;
- mFrameHeight = pDesc->height;
-
- // If we were given an opened display at construction time, then send the received
- // image back down the camera.
- if (mDisplay.get()) {
- // Get the output buffer we'll use to display the imagery
- BufferDesc_1_0 tgtBuffer = {};
- mDisplay->getTargetBuffer([&tgtBuffer](const BufferDesc_1_0& buff) {
- tgtBuffer = buff;
- }
- );
-
- if (tgtBuffer.memHandle == nullptr) {
- printf("Didn't get target buffer - frame lost\n");
- ALOGE("Didn't get requested output buffer -- skipping this frame.");
+ // Send the target buffer back for display
+ Return<EvsResult> result = mDisplay->returnTargetBufferForDisplay(tgtBuffer);
+ if (!result.isOk()) {
+ printf("HIDL error on display buffer (%s)- frame lost\n",
+ result.description().c_str());
+ ALOGE("Error making the remote function call. HIDL said %s",
+ result.description().c_str());
+ } else if (result != EvsResult::OK) {
+ printf("Display reported error - frame lost\n");
+ ALOGE("We encountered error %d when returning a buffer to the display!",
+ (EvsResult) result);
} else {
- // Copy the contents of the of buffer.memHandle into tgtBuffer
- copyBufferContents(tgtBuffer, bufDesc);
-
- // Send the target buffer back for display
- Return<EvsResult> result = mDisplay->returnTargetBufferForDisplay(tgtBuffer);
- if (!result.isOk()) {
- printf("HIDL error on display buffer (%s)- frame lost\n",
- result.description().c_str());
- ALOGE("Error making the remote function call. HIDL said %s",
- result.description().c_str());
- } else if (result != EvsResult::OK) {
- printf("Display reported error - frame lost\n");
- ALOGE("We encountered error %d when returning a buffer to the display!",
- (EvsResult) result);
- } else {
- // Everything looks good!
- // Keep track so tests or watch dogs can monitor progress
- mLock.lock();
- mFramesDisplayed++;
- mLock.unlock();
- }
+ // Everything looks good!
+ // Keep track so tests or watch dogs can monitor progress
+ mLock.lock();
+ mFramesDisplayed++;
+ mLock.unlock();
}
}
-
-
- switch (mReturnMode) {
- case eAutoReturn:
- // Send the camera buffer back now that the client has seen it
- ALOGD("Calling doneWithFrame");
- // TODO: Why is it that we get a HIDL crash if we pass back the cloned buffer?
- mCamera->doneWithFrame_1_1(bufDesc);
- break;
- case eNoAutoReturn:
- // Hang onto the buffer handle for now -- the client will return it explicitly later
- mHeldBuffers.push(bufDesc);
- }
-
- mLock.lock();
- ++mFramesReceived;
- mLock.unlock();
- mFrameSignal.notify_all();
-
- ALOGD("Frame handling complete");
}
+
+ switch (mReturnMode) {
+ case eAutoReturn:
+ // Send the camera buffer back now that the client has seen it
+ ALOGD("Calling doneWithFrame");
+ mCamera->doneWithFrame_1_1(bufDesc);
+ break;
+ case eNoAutoReturn:
+ // Hang onto the buffer handle for now -- the client will return it explicitly later
+ mHeldBuffers.push(bufDesc);
+ }
+
+ mLock.lock();
+ ++mFramesReceived;
+ mLock.unlock();
+ mFrameSignal.notify_all();
+
+ ALOGD("Frame handling complete");
+
+ return Void();
+}
+
+
+Return<void> FrameHandler::notify(const EvsEvent& event) {
+ // Local flag we use to keep track of when the stream is stopping
+ mLock.lock();
+ mLatestEventDesc = event;
+ if (mLatestEventDesc.aType == EvsEventType::STREAM_STOPPED) {
+ // Signal that the last frame has been received and the stream is stopped
+ mRunning = false;
+ } else if (mLatestEventDesc.aType == EvsEventType::PARAMETER_CHANGED) {
+ ALOGD("Camera parameter 0x%X is changed to 0x%X",
+ mLatestEventDesc.payload[0], mLatestEventDesc.payload[1]);
+ } else {
+ ALOGD("Received an event %s", eventToString(mLatestEventDesc.aType));
+ }
+ mLock.unlock();
+ mEventSignal.notify_all();
+
return Void();
}
@@ -342,18 +342,18 @@
}
}
-bool FrameHandler::waitForEvent(const InfoEventType aTargetEvent,
- InfoEventDesc &eventDesc) {
+bool FrameHandler::waitForEvent(const EvsEventType aTargetEvent,
+ EvsEvent &event) {
// Wait until we get an expected parameter change event.
std::unique_lock<std::mutex> lock(mLock);
auto now = std::chrono::system_clock::now();
bool result = mEventSignal.wait_until(lock, now + 5s,
- [this, aTargetEvent, &eventDesc](){
+ [this, aTargetEvent, &event](){
bool flag = mLatestEventDesc.aType == aTargetEvent;
if (flag) {
- eventDesc.aType = mLatestEventDesc.aType;
- eventDesc.payload[0] = mLatestEventDesc.payload[0];
- eventDesc.payload[1] = mLatestEventDesc.payload[1];
+ event.aType = mLatestEventDesc.aType;
+ event.payload[0] = mLatestEventDesc.payload[0];
+ event.payload[1] = mLatestEventDesc.payload[1];
}
return flag;
@@ -363,21 +363,22 @@
return !result;
}
-const char *FrameHandler::eventToString(const InfoEventType aType) {
+const char *FrameHandler::eventToString(const EvsEventType aType) {
switch (aType) {
- case InfoEventType::STREAM_STARTED:
+ case EvsEventType::STREAM_STARTED:
return "STREAM_STARTED";
- case InfoEventType::STREAM_STOPPED:
+ case EvsEventType::STREAM_STOPPED:
return "STREAM_STOPPED";
- case InfoEventType::FRAME_DROPPED:
+ case EvsEventType::FRAME_DROPPED:
return "FRAME_DROPPED";
- case InfoEventType::TIMEOUT:
+ case EvsEventType::TIMEOUT:
return "TIMEOUT";
- case InfoEventType::PARAMETER_CHANGED:
+ case EvsEventType::PARAMETER_CHANGED:
return "PARAMETER_CHANGED";
- case InfoEventType::MASTER_RELEASED:
+ case EvsEventType::MASTER_RELEASED:
return "MASTER_RELEASED";
default:
return "Unknown";
}
}
+
diff --git a/automotive/evs/1.1/vts/functional/FrameHandler.h b/automotive/evs/1.1/vts/functional/FrameHandler.h
index 7f87cb4..e5f1b8f 100644
--- a/automotive/evs/1.1/vts/functional/FrameHandler.h
+++ b/automotive/evs/1.1/vts/functional/FrameHandler.h
@@ -33,7 +33,6 @@
using ::android::sp;
using ::android::hardware::automotive::evs::V1_0::IEvsDisplay;
using ::android::hardware::automotive::evs::V1_0::EvsResult;
-using ::android::hardware::automotive::evs::V1_0::CameraDesc;
using BufferDesc_1_0 = ::android::hardware::automotive::evs::V1_0::BufferDesc;
using BufferDesc_1_1 = ::android::hardware::automotive::evs::V1_1::BufferDesc;
@@ -56,6 +55,13 @@
FrameHandler(android::sp <IEvsCamera> pCamera, CameraDesc cameraInfo,
android::sp <IEvsDisplay> pDisplay = nullptr,
BufferControlFlag mode = eAutoReturn);
+ virtual ~FrameHandler() {
+ if (mCamera != nullptr) {
+ /* shutdown a camera explicitly */
+ shutdown();
+ }
+ }
+
void shutdown();
bool startStream();
@@ -67,19 +73,22 @@
bool isRunning();
void waitForFrameCount(unsigned frameCount);
- bool waitForEvent(const InfoEventType aTargetEvent,
- InfoEventDesc &eventDesc);
+ bool waitForEvent(const EvsEventType aTargetEvent,
+ EvsEvent &eventDesc);
void getFramesCounters(unsigned* received, unsigned* displayed);
void getFrameDimension(unsigned* width, unsigned* height);
private:
- // Implementation for ::android::hardware::automotive::evs::V1_1::IEvsCameraStream
+ // Implementation for ::android::hardware::automotive::evs::V1_0::IEvsCameraStream
Return<void> deliverFrame(const BufferDesc_1_0& buffer) override;
- Return<void> notifyEvent(const EvsEvent& event) override;
+
+ // Implementation for ::android::hardware::automotive::evs::V1_1::IEvsCameraStream
+ Return<void> deliverFrame_1_1(const BufferDesc_1_1& buffer) override;
+ Return<void> notify(const EvsEvent& event) override;
// Local implementation details
bool copyBufferContents(const BufferDesc_1_0& tgtBuffer, const BufferDesc_1_1& srcBuffer);
- const char *eventToString(const InfoEventType aType);
+ const char *eventToString(const EvsEventType aType);
// Values initialized as startup
android::sp <IEvsCamera> mCamera;
@@ -100,7 +109,7 @@
unsigned mFramesDisplayed = 0; // Simple counter -- rolls over eventually!
unsigned mFrameWidth = 0;
unsigned mFrameHeight = 0;
- InfoEventDesc mLatestEventDesc;
+ EvsEvent mLatestEventDesc;
};
diff --git a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
index a6e4881..1d3fd87 100644
--- a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
+++ b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
@@ -38,8 +38,9 @@
#include "FrameHandler.h"
-#include <stdio.h>
-#include <string.h>
+#include <cstdio>
+#include <cstring>
+#include <cstdlib>
#include <hidl/HidlTransportSupport.h>
#include <hwbinder/ProcessState.h>
@@ -50,8 +51,10 @@
#include <android/log.h>
#include <android/hardware/automotive/evs/1.1/IEvsCamera.h>
#include <android/hardware/automotive/evs/1.1/IEvsCameraStream.h>
-#include <android/hardware/automotive/evs/1.0/IEvsEnumerator.h>
+#include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
#include <android/hardware/automotive/evs/1.0/IEvsDisplay.h>
+#include <android/hardware/camera/device/3.2/ICameraDevice.h>
+#include <system/camera_metadata.h>
#include <VtsHalHidlTargetTestBase.h>
#include <VtsHalHidlTargetTestEnvBase.h>
@@ -64,13 +67,28 @@
using ::android::hardware::hidl_handle;
using ::android::hardware::hidl_string;
using ::android::sp;
-using ::android::hardware::automotive::evs::V1_0::CameraDesc;
+using ::android::hardware::camera::device::V3_2::Stream;
using ::android::hardware::automotive::evs::V1_0::DisplayDesc;
using ::android::hardware::automotive::evs::V1_0::DisplayState;
-using ::android::hardware::automotive::evs::V1_0::IEvsEnumerator;
+using ::android::hardware::graphics::common::V1_0::PixelFormat;
using IEvsCamera_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCamera;
using IEvsCamera_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCamera;
+/*
+ * Plese note that this is different from what is defined in
+ * libhardware/modules/camera/3_4/metadata/types.h; this has one additional
+ * field to store a framerate.
+ */
+const size_t kStreamCfgSz = 5;
+typedef struct {
+ int32_t width;
+ int32_t height;
+ int32_t format;
+ int32_t direction;
+ int32_t framerate;
+} RawStreamConfig;
+
+
// Test environment for Evs HIDL HAL.
class EvsHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
public:
@@ -107,15 +125,16 @@
assert(pEnumerator != nullptr);
// Get the camera list
- pEnumerator->getCameraList([this](hidl_vec <CameraDesc> cameraList) {
- ALOGI("Camera list callback received %zu cameras",
- cameraList.size());
- cameraInfo.reserve(cameraList.size());
- for (auto&& cam: cameraList) {
- ALOGI("Found camera %s", cam.cameraId.c_str());
- cameraInfo.push_back(cam);
- }
- }
+ pEnumerator->getCameraList_1_1(
+ [this](hidl_vec <CameraDesc> cameraList) {
+ ALOGI("Camera list callback received %zu cameras",
+ cameraList.size());
+ cameraInfo.reserve(cameraList.size());
+ for (auto&& cam: cameraList) {
+ ALOGI("Found camera %s", cam.v1.cameraId.c_str());
+ cameraInfo.push_back(cam);
+ }
+ }
);
// We insist on at least one camera for EVS to pass any camera tests
@@ -143,19 +162,23 @@
// Get the camera list
loadCameraList();
+ // Using null stream configuration makes EVS uses the default resolution and
+ // output format.
+ Stream nullCfg = {};
+
// Open and close each camera twice
for (auto&& cam: cameraInfo) {
for (int pass = 0; pass < 2; pass++) {
sp<IEvsCamera_1_1> pCam =
- IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+ IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
ASSERT_NE(pCam, nullptr);
// Verify that this camera self-identifies correctly
- pCam->getCameraInfo([&cam](CameraDesc desc) {
- ALOGD("Found camera %s", desc.cameraId.c_str());
- EXPECT_EQ(cam.cameraId, desc.cameraId);
- }
+ pCam->getCameraInfo_1_1([&cam](CameraDesc desc) {
+ ALOGD("Found camera %s", desc.v1.cameraId.c_str());
+ EXPECT_EQ(cam.v1.cameraId, desc.v1.cameraId);
+ }
);
// Explicitly close the camera so resources are released right away
@@ -177,22 +200,26 @@
// Get the camera list
loadCameraList();
+ // Using null stream configuration makes EVS uses the default resolution and
+ // output format.
+ Stream nullCfg = {};
+
// Open and close each camera twice
for (auto&& cam: cameraInfo) {
sp<IEvsCamera_1_1> pCam =
- IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+ IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
ASSERT_NE(pCam, nullptr);
// Verify that this camera self-identifies correctly
- pCam->getCameraInfo([&cam](CameraDesc desc) {
- ALOGD("Found camera %s", desc.cameraId.c_str());
- EXPECT_EQ(cam.cameraId, desc.cameraId);
- }
+ pCam->getCameraInfo_1_1([&cam](CameraDesc desc) {
+ ALOGD("Found camera %s", desc.v1.cameraId.c_str());
+ EXPECT_EQ(cam.v1.cameraId, desc.v1.cameraId);
+ }
);
sp<IEvsCamera_1_1> pCam2 =
- IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+ IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
ASSERT_NE(pCam, pCam2);
ASSERT_NE(pCam2, nullptr);
@@ -210,10 +237,10 @@
pEnumerator->closeCamera(pCam);
// Verify that the second camera instance self-identifies correctly
- pCam2->getCameraInfo([&cam](CameraDesc desc) {
- ALOGD("Found camera %s", desc.cameraId.c_str());
- EXPECT_EQ(cam.cameraId, desc.cameraId);
- }
+ pCam2->getCameraInfo_1_1([&cam](CameraDesc desc) {
+ ALOGD("Found camera %s", desc.v1.cameraId.c_str());
+ EXPECT_EQ(cam.v1.cameraId, desc.v1.cameraId);
+ }
);
// Close the second camera instance
@@ -235,10 +262,14 @@
// Get the camera list
loadCameraList();
+ // Using null stream configuration makes EVS uses the default resolution and
+ // output format.
+ Stream nullCfg = {};
+
// Test each reported camera
for (auto&& cam: cameraInfo) {
sp<IEvsCamera_1_1> pCam =
- IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+ IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
ASSERT_NE(pCam, nullptr);
@@ -303,11 +334,15 @@
// Get the camera list
loadCameraList();
+ // Using null stream configuration makes EVS uses the default resolution and
+ // output format.
+ Stream nullCfg = {};
+
// Test each reported camera
for (auto&& cam: cameraInfo) {
sp<IEvsCamera_1_1> pCam =
- IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+ IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
ASSERT_NE(pCam, nullptr);
@@ -371,6 +406,10 @@
// Get the camera list
loadCameraList();
+ // Using null stream configuration makes EVS uses the default resolution and
+ // output format.
+ Stream nullCfg = {};
+
// Request exclusive access to the EVS display
sp<IEvsDisplay> pDisplay = pEnumerator->openDisplay();
ASSERT_NE(pDisplay, nullptr);
@@ -378,7 +417,7 @@
// Test each reported camera
for (auto&& cam: cameraInfo) {
sp<IEvsCamera_1_1> pCam =
- IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+ IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
ASSERT_NE(pCam, nullptr);
@@ -439,16 +478,20 @@
// Get the camera list
loadCameraList();
+ // Using null stream configuration makes EVS uses the default resolution and
+ // output format.
+ Stream nullCfg = {};
+
// Test each reported camera
for (auto&& cam: cameraInfo) {
// Create two camera clients.
sp<IEvsCamera_1_1> pCam0 =
- IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+ IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
ASSERT_NE(pCam0, nullptr);
sp<IEvsCamera_1_1> pCam1 =
- IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+ IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
ASSERT_NE(pCam1, nullptr);
@@ -486,7 +529,6 @@
nsecs_t runTime = end - firstFrame;
float framesPerSecond0 = framesReceived0 / (runTime * kNanoToSeconds);
float framesPerSecond1 = framesReceived1 / (runTime * kNanoToSeconds);
- printf("Measured camera rate %3.2f fps and %3.2f fps\n", framesPerSecond0, framesPerSecond1);
ALOGI("Measured camera rate %3.2f fps and %3.2f fps", framesPerSecond0, framesPerSecond1);
EXPECT_GE(framesPerSecond0, kMinimumFramesPerSecond);
EXPECT_GE(framesPerSecond1, kMinimumFramesPerSecond);
@@ -526,14 +568,33 @@
// Get the camera list
loadCameraList();
+ // Using null stream configuration makes EVS uses the default resolution and
+ // output format.
+ Stream nullCfg = {};
+
// Test each reported camera
+ Return<EvsResult> result = EvsResult::OK;
for (auto&& cam: cameraInfo) {
// Create a camera client
sp<IEvsCamera_1_1> pCam =
- IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+ IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
ASSERT_NE(pCam, nullptr);
+ // Get the parameter list
+ std::vector<CameraParam> cmds;
+ pCam->getParameterList([&cmds](hidl_vec<CameraParam> cmdList) {
+ cmds.reserve(cmdList.size());
+ for (auto &&cmd : cmdList) {
+ cmds.push_back(cmd);
+ }
+ }
+ );
+
+ if (cmds.size() < 1) {
+ continue;
+ }
+
// Set up per-client frame receiver objects which will fire up its own thread
sp<FrameHandler> frameHandler = new FrameHandler(pCam, cam,
nullptr,
@@ -547,83 +608,70 @@
// Ensure the stream starts
frameHandler->waitForFrameCount(1);
- // Try to program few parameters
- EvsResult result = EvsResult::OK;
- int32_t val0 = 100;
- int32_t val1 = 0;
-
result = pCam->setMaster();
- ASSERT_TRUE(result == EvsResult::OK);
+ ASSERT_EQ(EvsResult::OK, result);
- pCam->setParameter(CameraParam::BRIGHTNESS, val0,
- [&result, &val1](auto status, auto effectiveValue) {
- result = status;
- val1 = effectiveValue;
- });
- ASSERT_TRUE(result == EvsResult::OK ||
- result == EvsResult::INVALID_ARG);
+ for (auto &cmd : cmds) {
+ // Get a valid parameter value range
+ int32_t minVal, maxVal, step;
+ pCam->getIntParameterRange(
+ cmd,
+ [&minVal, &maxVal, &step](int32_t val0, int32_t val1, int32_t val2) {
+ minVal = val0;
+ maxVal = val1;
+ step = val2;
+ }
+ );
- if (result == EvsResult::OK) {
- pCam->getParameter(CameraParam::BRIGHTNESS,
+ EvsResult result = EvsResult::OK;
+ if (cmd == CameraParam::ABSOLUTE_FOCUS) {
+ // Try to turn off auto-focus
+ int32_t val1 = 0;
+ pCam->getIntParameter(CameraParam::AUTO_FOCUS,
+ [&result, &val1](auto status, auto value) {
+ result = status;
+ if (status == EvsResult::OK) {
+ val1 = value;
+ }
+ });
+ if (val1 != 0) {
+ pCam->setIntParameter(CameraParam::AUTO_FOCUS, 0,
+ [&result, &val1](auto status, auto effectiveValue) {
+ result = status;
+ val1 = effectiveValue;
+ });
+ ASSERT_EQ(EvsResult::OK, result);
+ ASSERT_EQ(val1, 0);
+ }
+ }
+
+ // Try to program a parameter with a random value [minVal, maxVal]
+ int32_t val0 = minVal + (std::rand() % (maxVal - minVal));
+ int32_t val1 = 0;
+
+ // Rounding down
+ val0 = val0 - (val0 % step);
+ pCam->setIntParameter(cmd, val0,
+ [&result, &val1](auto status, auto effectiveValue) {
+ result = status;
+ val1 = effectiveValue;
+ });
+
+ ASSERT_EQ(EvsResult::OK, result);
+
+ pCam->getIntParameter(cmd,
[&result, &val1](auto status, auto value) {
result = status;
if (status == EvsResult::OK) {
val1 = value;
}
});
- ASSERT_TRUE(result == EvsResult::OK ||
- result == EvsResult::INVALID_ARG);
- ASSERT_EQ(val0, val1) << "Values are not matched.";
- }
-
- val0 = 80;
- val1 = 0;
- pCam->setParameter(CameraParam::CONTRAST, val0,
- [&result, &val1](auto status, auto effectiveValue) {
- result = status;
- val1 = effectiveValue;
- });
- ASSERT_TRUE(result == EvsResult::OK ||
- result == EvsResult::INVALID_ARG);
-
- if (result == EvsResult::OK) {
- pCam->getParameter(CameraParam::CONTRAST,
- [&result, &val1](auto status, auto value) {
- result = status;
- if (status == EvsResult::OK) {
- val1 = value;
- }
- });
- ASSERT_TRUE(result == EvsResult::OK ||
- result == EvsResult::INVALID_ARG);
- ASSERT_EQ(val0, val1) << "Values are not matched.";
- }
-
- val0 = 300;
- val1 = 0;
- pCam->setParameter(CameraParam::ABSOLUTE_ZOOM, val0,
- [&result, &val1](auto status, auto effectiveValue) {
- result = status;
- val1 = effectiveValue;
- });
- ASSERT_TRUE(result == EvsResult::OK ||
- result == EvsResult::INVALID_ARG);
-
- if (result == EvsResult::OK) {
- pCam->getParameter(CameraParam::ABSOLUTE_ZOOM,
- [&result, &val1](auto status, auto value) {
- result = status;
- if (status == EvsResult::OK) {
- val1 = value;
- }
- });
- ASSERT_TRUE(result == EvsResult::OK ||
- result == EvsResult::INVALID_ARG);
+ ASSERT_EQ(EvsResult::OK, result);
ASSERT_EQ(val0, val1) << "Values are not matched.";
}
result = pCam->unsetMaster();
- ASSERT_TRUE(result == EvsResult::OK);
+ ASSERT_EQ(EvsResult::OK, result);
// Shutdown
frameHandler->shutdown();
@@ -650,15 +698,19 @@
// Get the camera list
loadCameraList();
+ // Using null stream configuration makes EVS uses the default resolution and
+ // output format.
+ Stream nullCfg = {};
+
// Test each reported camera
for (auto&& cam: cameraInfo) {
// Create two camera clients.
sp<IEvsCamera_1_1> pCamMaster =
- IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+ IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
ASSERT_NE(pCamMaster, nullptr);
sp<IEvsCamera_1_1> pCamNonMaster =
- IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+ IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
ASSERT_NE(pCamNonMaster, nullptr);
@@ -698,15 +750,15 @@
// Non-master client expects to receive a master role relesed
// notification.
- InfoEventDesc aNotification = {};
+ EvsEvent aNotification = {};
// Release a master role.
pCamMaster->unsetMaster();
// Verify a change notification.
- frameHandlerNonMaster->waitForEvent(InfoEventType::MASTER_RELEASED, aNotification);
- ASSERT_EQ(InfoEventType::MASTER_RELEASED,
- static_cast<InfoEventType>(aNotification.aType));
+ frameHandlerNonMaster->waitForEvent(EvsEventType::MASTER_RELEASED, aNotification);
+ ASSERT_EQ(EvsEventType::MASTER_RELEASED,
+ static_cast<EvsEventType>(aNotification.aType));
// Non-master becomes a master.
result = pCamNonMaster->setMaster();
@@ -720,9 +772,9 @@
frameHandlerNonMaster->shutdown();
// Verify a change notification.
- frameHandlerMaster->waitForEvent(InfoEventType::MASTER_RELEASED, aNotification);
- ASSERT_EQ(InfoEventType::MASTER_RELEASED,
- static_cast<InfoEventType>(aNotification.aType));
+ frameHandlerMaster->waitForEvent(EvsEventType::MASTER_RELEASED, aNotification);
+ ASSERT_EQ(EvsEventType::MASTER_RELEASED,
+ static_cast<EvsEventType>(aNotification.aType));
// Closing another stream.
frameHandlerMaster->shutdown();
@@ -752,18 +804,46 @@
// Get the camera list
loadCameraList();
+ // Using null stream configuration makes EVS uses the default resolution and
+ // output format.
+ Stream nullCfg = {};
+
// Test each reported camera
for (auto&& cam: cameraInfo) {
// Create two camera clients.
sp<IEvsCamera_1_1> pCamMaster =
- IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+ IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
ASSERT_NE(pCamMaster, nullptr);
sp<IEvsCamera_1_1> pCamNonMaster =
- IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+ IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
ASSERT_NE(pCamNonMaster, nullptr);
+ // Get the parameter list
+ std::vector<CameraParam> camMasterCmds, camNonMasterCmds;
+ pCamMaster->getParameterList([&camMasterCmds](hidl_vec<CameraParam> cmdList) {
+ camMasterCmds.reserve(cmdList.size());
+ for (auto &&cmd : cmdList) {
+ camMasterCmds.push_back(cmd);
+ }
+ }
+ );
+
+ pCamNonMaster->getParameterList([&camNonMasterCmds](hidl_vec<CameraParam> cmdList) {
+ camNonMasterCmds.reserve(cmdList.size());
+ for (auto &&cmd : cmdList) {
+ camNonMasterCmds.push_back(cmd);
+ }
+ }
+ );
+
+ if (camMasterCmds.size() < 1 ||
+ camNonMasterCmds.size() < 1) {
+ // Skip a camera device if it does not support any parameter.
+ continue;
+ }
+
// Set up per-client frame receiver objects which will fire up its own thread
sp<FrameHandler> frameHandlerMaster =
new FrameHandler(pCamMaster, cam,
@@ -778,11 +858,11 @@
// Set one client as the master
EvsResult result = pCamMaster->setMaster();
- ASSERT_TRUE(result == EvsResult::OK);
+ ASSERT_EQ(EvsResult::OK, result);
// Try to set another client as the master.
result = pCamNonMaster->setMaster();
- ASSERT_TRUE(result == EvsResult::OWNERSHIP_LOST);
+ ASSERT_EQ(EvsResult::OWNERSHIP_LOST, result);
// Start the camera's video stream via a master client.
bool startResult = frameHandlerMaster->startStream();
@@ -798,131 +878,168 @@
// Ensure the stream starts
frameHandlerNonMaster->waitForFrameCount(1);
- // Try to program CameraParam::BRIGHTNESS
- int32_t val0 = 100;
+ int32_t val0 = 0;
int32_t val1 = 0;
+ for (auto &cmd : camMasterCmds) {
+ // Get a valid parameter value range
+ int32_t minVal, maxVal, step;
+ pCamMaster->getIntParameterRange(
+ cmd,
+ [&minVal, &maxVal, &step](int32_t val0, int32_t val1, int32_t val2) {
+ minVal = val0;
+ maxVal = val1;
+ step = val2;
+ }
+ );
- pCamMaster->setParameter(CameraParam::BRIGHTNESS, val0,
- [&result, &val1](auto status, auto effectiveValue) {
- result = status;
- val1 = effectiveValue;
- });
- ASSERT_TRUE(result == EvsResult::OK || // Succeeded to program
- result == EvsResult::INVALID_ARG); // Camera parameter is not supported
+ EvsResult result = EvsResult::OK;
+ if (cmd == CameraParam::ABSOLUTE_FOCUS) {
+ // Try to turn off auto-focus
+ int32_t val1 = 1;
+ pCamMaster->setIntParameter(CameraParam::AUTO_FOCUS, 0,
+ [&result, &val1](auto status, auto effectiveValue) {
+ result = status;
+ val1 = effectiveValue;
+ });
+ ASSERT_EQ(EvsResult::OK, result);
+ ASSERT_EQ(val1, 0);
+ }
- // Non-master client expects to receive a parameter change notification
- // whenever a master client adjusts it.
- InfoEventDesc aNotification = {};
+ // Try to program a parameter
+ val0 = minVal + (std::rand() % (maxVal - minVal));
- pCamMaster->getParameter(CameraParam::BRIGHTNESS,
- [&result, &val1](auto status, auto value) {
- result = status;
- if (status == EvsResult::OK) {
- val1 = value;
- }
- });
- ASSERT_TRUE(result == EvsResult::OK || // Succeeded to program
- result == EvsResult::INVALID_ARG); // Camera parameter is not supported
- if (result == EvsResult::OK) {
- ASSERT_EQ(val0, val1) << "Values are not matched.";
+ // Rounding down
+ val0 = val0 - (val0 % step);
+ pCamMaster->setIntParameter(cmd, val0,
+ [&result, &val1](auto status, auto effectiveValue) {
+ result = status;
+ val1 = effectiveValue;
+ });
+ ASSERT_EQ(EvsResult::OK, result);
- // Verify a change notification
- frameHandlerNonMaster->waitForEvent(InfoEventType::PARAMETER_CHANGED, aNotification);
- ASSERT_EQ(InfoEventType::PARAMETER_CHANGED,
- static_cast<InfoEventType>(aNotification.aType));
- ASSERT_EQ(CameraParam::BRIGHTNESS,
- static_cast<CameraParam>(aNotification.payload[0]));
- ASSERT_EQ(val1,
- static_cast<int32_t>(aNotification.payload[1]));
- }
+ // Wait a moment
+ sleep(1);
- // Try to program CameraParam::CONTRAST
- val0 = 80;
- val1 = 0;
- pCamMaster->setParameter(CameraParam::CONTRAST, val0,
- [&result, &val1](auto status, auto effectiveValue) {
- result = status;
- val1 = effectiveValue;
- });
- ASSERT_TRUE(result == EvsResult::OK || // Succeeded to program
- result == EvsResult::INVALID_ARG); // Camera parameter is not supported
+ // Non-master client expects to receive a parameter change notification
+ // whenever a master client adjusts it.
+ EvsEvent aNotification = {};
- if (result == EvsResult::OK) {
- pCamMaster->getParameter(CameraParam::CONTRAST,
+ pCamMaster->getIntParameter(cmd,
[&result, &val1](auto status, auto value) {
result = status;
if (status == EvsResult::OK) {
val1 = value;
}
});
- ASSERT_TRUE(result == EvsResult::OK);
+ ASSERT_EQ(EvsResult::OK, result);
ASSERT_EQ(val0, val1) << "Values are not matched.";
-
// Verify a change notification
- frameHandlerNonMaster->waitForEvent(InfoEventType::PARAMETER_CHANGED, aNotification);
- ASSERT_EQ(InfoEventType::PARAMETER_CHANGED,
- static_cast<InfoEventType>(aNotification.aType));
- ASSERT_EQ(CameraParam::CONTRAST,
+ frameHandlerNonMaster->waitForEvent(EvsEventType::PARAMETER_CHANGED, aNotification);
+ ASSERT_EQ(EvsEventType::PARAMETER_CHANGED,
+ static_cast<EvsEventType>(aNotification.aType));
+ ASSERT_EQ(cmd,
static_cast<CameraParam>(aNotification.payload[0]));
ASSERT_EQ(val1,
static_cast<int32_t>(aNotification.payload[1]));
}
// Try to adjust a parameter via non-master client
- pCamNonMaster->setParameter(CameraParam::CONTRAST, val0,
+ pCamNonMaster->setIntParameter(camNonMasterCmds[0], val0,
[&result, &val1](auto status, auto effectiveValue) {
result = status;
val1 = effectiveValue;
});
- ASSERT_TRUE(result == EvsResult::INVALID_ARG);
+ ASSERT_EQ(EvsResult::INVALID_ARG, result);
// Non-master client attemps to be a master
result = pCamNonMaster->setMaster();
- ASSERT_TRUE(result == EvsResult::OWNERSHIP_LOST);
+ ASSERT_EQ(EvsResult::OWNERSHIP_LOST, result);
// Master client retires from a master role
result = pCamMaster->unsetMaster();
- ASSERT_TRUE(result == EvsResult::OK);
+ ASSERT_EQ(EvsResult::OK, result);
// Try to adjust a parameter after being retired
- pCamMaster->setParameter(CameraParam::BRIGHTNESS, val0,
+ pCamMaster->setIntParameter(camMasterCmds[0], val0,
[&result, &val1](auto status, auto effectiveValue) {
result = status;
val1 = effectiveValue;
});
- ASSERT_TRUE(result == EvsResult::INVALID_ARG);
+ ASSERT_EQ(EvsResult::INVALID_ARG, result);
// Non-master client becomes a master
result = pCamNonMaster->setMaster();
- ASSERT_TRUE(result == EvsResult::OK);
+ ASSERT_EQ(EvsResult::OK, result);
// Try to adjust a parameter via new master client
- pCamNonMaster->setParameter(CameraParam::BRIGHTNESS, val0,
- [&result, &val1](auto status, auto effectiveValue) {
- result = status;
- val1 = effectiveValue;
- });
- ASSERT_TRUE(result == EvsResult::OK || // Succeeded to program
- result == EvsResult::INVALID_ARG); // Camera parameter is not supported
+ for (auto &cmd : camNonMasterCmds) {
+ // Get a valid parameter value range
+ int32_t minVal, maxVal, step;
+ pCamNonMaster->getIntParameterRange(
+ cmd,
+ [&minVal, &maxVal, &step](int32_t val0, int32_t val1, int32_t val2) {
+ minVal = val0;
+ maxVal = val1;
+ step = val2;
+ }
+ );
- // Wait a moment
- sleep(1);
+ EvsResult result = EvsResult::OK;
+ if (cmd == CameraParam::ABSOLUTE_FOCUS) {
+ // Try to turn off auto-focus
+ int32_t val1 = 1;
+ pCamNonMaster->setIntParameter(CameraParam::AUTO_FOCUS, 0,
+ [&result, &val1](auto status, auto effectiveValue) {
+ result = status;
+ val1 = effectiveValue;
+ });
+ ASSERT_EQ(EvsResult::OK, result);
+ ASSERT_EQ(val1, 0);
+ }
- // Verify a change notification
- if (result == EvsResult::OK) {
- frameHandlerMaster->waitForEvent(InfoEventType::PARAMETER_CHANGED, aNotification);
- ASSERT_EQ(static_cast<InfoEventType>(aNotification.aType),
- InfoEventType::PARAMETER_CHANGED);
- ASSERT_EQ(static_cast<CameraParam>(aNotification.payload[0]),
- CameraParam::BRIGHTNESS);
+ // Try to program a parameter
+ val0 = minVal + (std::rand() % (maxVal - minVal));
+
+ // Rounding down
+ val0 = val0 - (val0 % step);
+ pCamNonMaster->setIntParameter(cmd, val0,
+ [&result, &val1](auto status, auto effectiveValue) {
+ result = status;
+ val1 = effectiveValue;
+ });
+ ASSERT_EQ(EvsResult::OK, result);
+
+ // Wait a moment
+ sleep(1);
+
+ // Non-master client expects to receive a parameter change notification
+ // whenever a master client adjusts it.
+ EvsEvent aNotification = {};
+
+ pCamNonMaster->getIntParameter(cmd,
+ [&result, &val1](auto status, auto value) {
+ result = status;
+ if (status == EvsResult::OK) {
+ val1 = value;
+ }
+ });
+ ASSERT_EQ(EvsResult::OK, result);
+ ASSERT_EQ(val0, val1) << "Values are not matched.";
+
+ // Verify a change notification
+ frameHandlerMaster->waitForEvent(EvsEventType::PARAMETER_CHANGED, aNotification);
+ ASSERT_EQ(EvsEventType::PARAMETER_CHANGED,
+ static_cast<EvsEventType>(aNotification.aType));
+ ASSERT_EQ(cmd,
+ static_cast<CameraParam>(aNotification.payload[0]));
ASSERT_EQ(val1,
static_cast<int32_t>(aNotification.payload[1]));
}
// New master retires from a master role
result = pCamNonMaster->unsetMaster();
- ASSERT_TRUE(result == EvsResult::OK);
+ ASSERT_EQ(EvsResult::OK, result);
// Shutdown
frameHandlerMaster->shutdown();
@@ -943,9 +1060,18 @@
TEST_F(EvsHidlTest, HighPriorityCameraClient) {
ALOGI("Starting HighPriorityCameraClient test");
+ if (mIsHwModule) {
+ // This test is not for HW module implementation.
+ return;
+ }
+
// Get the camera list
loadCameraList();
+ // Using null stream configuration makes EVS uses the default resolution and
+ // output format.
+ Stream nullCfg = {};
+
// Request exclusive access to the EVS display
sp<IEvsDisplay> pDisplay = pEnumerator->openDisplay();
ASSERT_NE(pDisplay, nullptr);
@@ -954,15 +1080,38 @@
for (auto&& cam: cameraInfo) {
// Create two clients
sp<IEvsCamera_1_1> pCam0 =
- IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+ IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
ASSERT_NE(pCam0, nullptr);
sp<IEvsCamera_1_1> pCam1 =
- IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+ IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
ASSERT_NE(pCam1, nullptr);
+ // Get the parameter list; this test will use the first command in both
+ // lists.
+ std::vector<CameraParam> cam0Cmds, cam1Cmds;
+ pCam0->getParameterList([&cam0Cmds](hidl_vec<CameraParam> cmdList) {
+ cam0Cmds.reserve(cmdList.size());
+ for (auto &&cmd : cmdList) {
+ cam0Cmds.push_back(cmd);
+ }
+ }
+ );
+
+ pCam1->getParameterList([&cam1Cmds](hidl_vec<CameraParam> cmdList) {
+ cam1Cmds.reserve(cmdList.size());
+ for (auto &&cmd : cmdList) {
+ cam1Cmds.push_back(cmd);
+ }
+ }
+ );
+ if (cam0Cmds.size() < 1 || cam1Cmds.size() < 1) {
+ // Cannot execute this test.
+ return;
+ }
+
// Set up a frame receiver object which will fire up its own thread.
sp<FrameHandler> frameHandler0 = new FrameHandler(pCam0, cam,
pDisplay,
@@ -982,67 +1131,121 @@
frameHandler0->waitForFrameCount(1);
frameHandler1->waitForFrameCount(1);
- // Client 1 becomes a master and programs a brightness.
+ // Client 1 becomes a master and programs a parameter.
EvsResult result = EvsResult::OK;
- int32_t val0 = 100;
+ // Get a valid parameter value range
+ int32_t minVal, maxVal, step;
+ pCam1->getIntParameterRange(
+ cam1Cmds[0],
+ [&minVal, &maxVal, &step](int32_t val0, int32_t val1, int32_t val2) {
+ minVal = val0;
+ maxVal = val1;
+ step = val2;
+ }
+ );
+
+ if (cam1Cmds[0] == CameraParam::ABSOLUTE_FOCUS) {
+ // Try to turn off auto-focus
+ int32_t val1 = 0;
+ pCam1->getIntParameter(CameraParam::AUTO_FOCUS,
+ [&result, &val1](auto status, auto value) {
+ result = status;
+ if (status == EvsResult::OK) {
+ val1 = value;
+ }
+ });
+ if (val1 != 0) {
+ pCam1->setIntParameter(CameraParam::AUTO_FOCUS, 0,
+ [&result, &val1](auto status, auto effectiveValue) {
+ result = status;
+ val1 = effectiveValue;
+ });
+ ASSERT_EQ(EvsResult::OK, result);
+ ASSERT_EQ(val1, 0);
+ }
+ }
+
+ // Try to program a parameter with a random value [minVal, maxVal]
+ int32_t val0 = minVal + (std::rand() % (maxVal - minVal));
int32_t val1 = 0;
- result = pCam1->setMaster();
- ASSERT_TRUE(result == EvsResult::OK);
+ // Rounding down
+ val0 = val0 - (val0 % step);
- pCam1->setParameter(CameraParam::BRIGHTNESS, val0,
+ result = pCam1->setMaster();
+ ASSERT_EQ(EvsResult::OK, result);
+
+ pCam1->setIntParameter(cam1Cmds[0], val0,
[&result, &val1](auto status, auto effectiveValue) {
result = status;
val1 = effectiveValue;
});
- ASSERT_TRUE(result == EvsResult::OK ||
- result == EvsResult::INVALID_ARG);
-
+ ASSERT_EQ(EvsResult::OK, result);
// Verify a change notification
- InfoEventDesc aNotification = {};
- if (result == EvsResult::OK) {
- bool timeout =
- frameHandler0->waitForEvent(InfoEventType::PARAMETER_CHANGED, aNotification);
- ASSERT_FALSE(timeout) << "Expected event does not arrive";
- ASSERT_EQ(static_cast<InfoEventType>(aNotification.aType),
- InfoEventType::PARAMETER_CHANGED);
- ASSERT_EQ(static_cast<CameraParam>(aNotification.payload[0]),
- CameraParam::BRIGHTNESS);
- ASSERT_EQ(val1,
- static_cast<int32_t>(aNotification.payload[1]));
- }
+ EvsEvent aNotification = {};
+ bool timeout =
+ frameHandler0->waitForEvent(EvsEventType::PARAMETER_CHANGED, aNotification);
+ ASSERT_FALSE(timeout) << "Expected event does not arrive";
+ ASSERT_EQ(static_cast<EvsEventType>(aNotification.aType),
+ EvsEventType::PARAMETER_CHANGED);
+ ASSERT_EQ(static_cast<CameraParam>(aNotification.payload[0]),
+ cam1Cmds[0]);
+ ASSERT_EQ(val1,
+ static_cast<int32_t>(aNotification.payload[1]));
// Client 0 steals a master role
ASSERT_EQ(EvsResult::OK, pCam0->forceMaster(pDisplay));
- frameHandler1->waitForEvent(InfoEventType::MASTER_RELEASED, aNotification);
- ASSERT_EQ(static_cast<InfoEventType>(aNotification.aType),
- InfoEventType::MASTER_RELEASED);
+ frameHandler1->waitForEvent(EvsEventType::MASTER_RELEASED, aNotification);
+ ASSERT_EQ(static_cast<EvsEventType>(aNotification.aType),
+ EvsEventType::MASTER_RELEASED);
- // Client 0 programs a brightness
- val0 = 50;
+ // Client 0 programs a parameter
+ val0 = minVal + (std::rand() % (maxVal - minVal));
val1 = 0;
- pCam0->setParameter(CameraParam::BRIGHTNESS, val0,
+
+ // Rounding down
+ val0 = val0 - (val0 % step);
+
+ if (cam0Cmds[0] == CameraParam::ABSOLUTE_FOCUS) {
+ // Try to turn off auto-focus
+ int32_t val1 = 0;
+ pCam0->getIntParameter(CameraParam::AUTO_FOCUS,
+ [&result, &val1](auto status, auto value) {
+ result = status;
+ if (status == EvsResult::OK) {
+ val1 = value;
+ }
+ });
+ if (val1 != 0) {
+ pCam0->setIntParameter(CameraParam::AUTO_FOCUS, 0,
+ [&result, &val1](auto status, auto effectiveValue) {
+ result = status;
+ val1 = effectiveValue;
+ });
+ ASSERT_EQ(EvsResult::OK, result);
+ ASSERT_EQ(val1, 0);
+ }
+ }
+
+ pCam0->setIntParameter(cam0Cmds[0], val0,
[&result, &val1](auto status, auto effectiveValue) {
result = status;
val1 = effectiveValue;
});
- ASSERT_TRUE(result == EvsResult::OK ||
- result == EvsResult::INVALID_ARG);
+ ASSERT_EQ(EvsResult::OK, result);
// Verify a change notification
- if (result == EvsResult::OK) {
- bool timeout =
- frameHandler1->waitForEvent(InfoEventType::PARAMETER_CHANGED, aNotification);
- ASSERT_FALSE(timeout) << "Expected event does not arrive";
- ASSERT_EQ(static_cast<InfoEventType>(aNotification.aType),
- InfoEventType::PARAMETER_CHANGED);
- ASSERT_EQ(static_cast<CameraParam>(aNotification.payload[0]),
- CameraParam::BRIGHTNESS);
- ASSERT_EQ(val1,
- static_cast<int32_t>(aNotification.payload[1]));
- }
+ timeout =
+ frameHandler1->waitForEvent(EvsEventType::PARAMETER_CHANGED, aNotification);
+ ASSERT_FALSE(timeout) << "Expected event does not arrive";
+ ASSERT_EQ(static_cast<EvsEventType>(aNotification.aType),
+ EvsEventType::PARAMETER_CHANGED);
+ ASSERT_EQ(static_cast<CameraParam>(aNotification.payload[0]),
+ cam0Cmds[0]);
+ ASSERT_EQ(val1,
+ static_cast<int32_t>(aNotification.payload[1]));
// Turn off the display (yes, before the stream stops -- it should be handled)
pDisplay->setDisplayState(DisplayState::NOT_VISIBLE);
@@ -1061,6 +1264,248 @@
}
+/*
+ * CameraUseStreamConfigToDisplay:
+ * End to end test of data flowing from the camera to the display. Similar to
+ * CameraToDisplayRoundTrip test case but this case retrieves available stream
+ * configurations from EVS and uses one of them to start a video stream.
+ */
+TEST_F(EvsHidlTest, CameraUseStreamConfigToDisplay) {
+ ALOGI("Starting CameraUseStreamConfigToDisplay test");
+
+ // Get the camera list
+ loadCameraList();
+
+ // Request exclusive access to the EVS display
+ sp<IEvsDisplay> pDisplay = pEnumerator->openDisplay();
+ ASSERT_NE(pDisplay, nullptr);
+
+ // Test each reported camera
+ for (auto&& cam: cameraInfo) {
+ // choose a configuration that has a frame rate faster than minReqFps.
+ Stream targetCfg = {};
+ const int32_t minReqFps = 15;
+ int32_t maxArea = 0;
+ camera_metadata_entry_t streamCfgs;
+ bool foundCfg = false;
+ if (!find_camera_metadata_entry(
+ reinterpret_cast<camera_metadata_t *>(cam.metadata.data()),
+ ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
+ &streamCfgs)) {
+ // Stream configurations are found in metadata
+ RawStreamConfig *ptr = reinterpret_cast<RawStreamConfig *>(streamCfgs.data.i32);
+ for (unsigned idx = 0; idx < streamCfgs.count; idx += kStreamCfgSz) {
+ if (ptr->direction == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
+ ptr->format == HAL_PIXEL_FORMAT_RGBA_8888) {
+
+ if (ptr->width * ptr->height > maxArea &&
+ ptr->framerate >= minReqFps) {
+ targetCfg.width = ptr->width;
+ targetCfg.height = ptr->height;
+
+ maxArea = ptr->width * ptr->height;
+ foundCfg = true;
+ }
+ }
+ ++ptr;
+ }
+ }
+ targetCfg.format =
+ static_cast<PixelFormat>(HAL_PIXEL_FORMAT_RGBA_8888);
+
+ if (!foundCfg) {
+ // Current EVS camera does not provide stream configurations in the
+ // metadata.
+ continue;
+ }
+
+ sp<IEvsCamera_1_1> pCam =
+ IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg))
+ .withDefault(nullptr);
+ ASSERT_NE(pCam, nullptr);
+
+ // Set up a frame receiver object which will fire up its own thread.
+ sp<FrameHandler> frameHandler = new FrameHandler(pCam, cam,
+ pDisplay,
+ FrameHandler::eAutoReturn);
+
+
+ // Activate the display
+ pDisplay->setDisplayState(DisplayState::VISIBLE_ON_NEXT_FRAME);
+
+ // Start the camera's video stream
+ bool startResult = frameHandler->startStream();
+ ASSERT_TRUE(startResult);
+
+ // Wait a while to let the data flow
+ static const int kSecondsToWait = 5;
+ const int streamTimeMs = kSecondsToWait * kSecondsToMilliseconds -
+ kMaxStreamStartMilliseconds;
+ const unsigned minimumFramesExpected = streamTimeMs * kMinimumFramesPerSecond /
+ kSecondsToMilliseconds;
+ sleep(kSecondsToWait);
+ unsigned framesReceived = 0;
+ unsigned framesDisplayed = 0;
+ frameHandler->getFramesCounters(&framesReceived, &framesDisplayed);
+ EXPECT_EQ(framesReceived, framesDisplayed);
+ EXPECT_GE(framesDisplayed, minimumFramesExpected);
+
+ // Turn off the display (yes, before the stream stops -- it should be handled)
+ pDisplay->setDisplayState(DisplayState::NOT_VISIBLE);
+
+ // Shut down the streamer
+ frameHandler->shutdown();
+
+ // Explicitly release the camera
+ pEnumerator->closeCamera(pCam);
+ }
+
+ // Explicitly release the display
+ pEnumerator->closeDisplay(pDisplay);
+}
+
+
+/*
+ * MultiCameraStreamUseConfig:
+ * Verify that each client can start and stop video streams on the same
+ * underlying camera with same configuration.
+ */
+TEST_F(EvsHidlTest, MultiCameraStreamUseConfig) {
+ ALOGI("Starting MultiCameraStream test");
+
+ if (mIsHwModule) {
+ // This test is not for HW module implementation.
+ return;
+ }
+
+ // Get the camera list
+ loadCameraList();
+
+ // Test each reported camera
+ for (auto&& cam: cameraInfo) {
+ // choose a configuration that has a frame rate faster than minReqFps.
+ Stream targetCfg = {};
+ const int32_t minReqFps = 15;
+ int32_t maxArea = 0;
+ camera_metadata_entry_t streamCfgs;
+ bool foundCfg = false;
+ if (!find_camera_metadata_entry(
+ reinterpret_cast<camera_metadata_t *>(cam.metadata.data()),
+ ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
+ &streamCfgs)) {
+ // Stream configurations are found in metadata
+ RawStreamConfig *ptr = reinterpret_cast<RawStreamConfig *>(streamCfgs.data.i32);
+ for (unsigned idx = 0; idx < streamCfgs.count; idx += kStreamCfgSz) {
+ if (ptr->direction == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
+ ptr->format == HAL_PIXEL_FORMAT_RGBA_8888) {
+
+ if (ptr->width * ptr->height > maxArea &&
+ ptr->framerate >= minReqFps) {
+ targetCfg.width = ptr->width;
+ targetCfg.height = ptr->height;
+
+ maxArea = ptr->width * ptr->height;
+ foundCfg = true;
+ }
+ }
+ ++ptr;
+ }
+ }
+ targetCfg.format =
+ static_cast<PixelFormat>(HAL_PIXEL_FORMAT_RGBA_8888);
+
+ if (!foundCfg) {
+ ALOGI("Device %s does not provide a list of supported stream configurations, skipped",
+ cam.v1.cameraId.c_str());
+
+ continue;
+ }
+
+ // Create the first camera client with a selected stream configuration.
+ sp<IEvsCamera_1_1> pCam0 =
+ IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg))
+ .withDefault(nullptr);
+ ASSERT_NE(pCam0, nullptr);
+
+ // Try to create the second camera client with different stream
+ // configuration.
+ int32_t id = targetCfg.id;
+ targetCfg.id += 1; // EVS manager sees only the stream id.
+ sp<IEvsCamera_1_1> pCam1 =
+ IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg))
+ .withDefault(nullptr);
+ ASSERT_EQ(pCam1, nullptr);
+
+ // Try again with same stream configuration.
+ targetCfg.id = id;
+ pCam1 =
+ IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg))
+ .withDefault(nullptr);
+ ASSERT_NE(pCam1, nullptr);
+
+ // Set up per-client frame receiver objects which will fire up its own thread
+ sp<FrameHandler> frameHandler0 = new FrameHandler(pCam0, cam,
+ nullptr,
+ FrameHandler::eAutoReturn);
+ ASSERT_NE(frameHandler0, nullptr);
+
+ sp<FrameHandler> frameHandler1 = new FrameHandler(pCam1, cam,
+ nullptr,
+ FrameHandler::eAutoReturn);
+ ASSERT_NE(frameHandler1, nullptr);
+
+ // Start the camera's video stream via client 0
+ bool startResult = false;
+ startResult = frameHandler0->startStream() &&
+ frameHandler1->startStream();
+ ASSERT_TRUE(startResult);
+
+ // Ensure the stream starts
+ frameHandler0->waitForFrameCount(1);
+ frameHandler1->waitForFrameCount(1);
+
+ nsecs_t firstFrame = systemTime(SYSTEM_TIME_MONOTONIC);
+
+ // Wait a bit, then ensure both clients get at least the required minimum number of frames
+ sleep(5);
+ nsecs_t end = systemTime(SYSTEM_TIME_MONOTONIC);
+ unsigned framesReceived0 = 0, framesReceived1 = 0;
+ frameHandler0->getFramesCounters(&framesReceived0, nullptr);
+ frameHandler1->getFramesCounters(&framesReceived1, nullptr);
+ framesReceived0 = framesReceived0 - 1; // Back out the first frame we already waited for
+ framesReceived1 = framesReceived1 - 1; // Back out the first frame we already waited for
+ nsecs_t runTime = end - firstFrame;
+ float framesPerSecond0 = framesReceived0 / (runTime * kNanoToSeconds);
+ float framesPerSecond1 = framesReceived1 / (runTime * kNanoToSeconds);
+ ALOGI("Measured camera rate %3.2f fps and %3.2f fps", framesPerSecond0, framesPerSecond1);
+ EXPECT_GE(framesPerSecond0, kMinimumFramesPerSecond);
+ EXPECT_GE(framesPerSecond1, kMinimumFramesPerSecond);
+
+ // Shutdown one client
+ frameHandler0->shutdown();
+
+ // Read frame counters again
+ frameHandler0->getFramesCounters(&framesReceived0, nullptr);
+ frameHandler1->getFramesCounters(&framesReceived1, nullptr);
+
+ // Wait a bit again
+ sleep(5);
+ unsigned framesReceivedAfterStop0 = 0, framesReceivedAfterStop1 = 0;
+ frameHandler0->getFramesCounters(&framesReceivedAfterStop0, nullptr);
+ frameHandler1->getFramesCounters(&framesReceivedAfterStop1, nullptr);
+ EXPECT_EQ(framesReceived0, framesReceivedAfterStop0);
+ EXPECT_LT(framesReceived1, framesReceivedAfterStop1);
+
+ // Shutdown another
+ frameHandler1->shutdown();
+
+ // Explicitly release the camera
+ pEnumerator->closeCamera(pCam0);
+ pEnumerator->closeCamera(pCam1);
+ }
+}
+
+
int main(int argc, char** argv) {
::testing::AddGlobalTestEnvironment(EvsHidlEnvironment::Instance());
::testing::InitGoogleTest(&argc, argv);
diff --git a/automotive/vehicle/2.0/default/tests/VehicleObjectPool_test.cpp b/automotive/vehicle/2.0/default/tests/VehicleObjectPool_test.cpp
index a291351..4e3ade1 100644
--- a/automotive/vehicle/2.0/default/tests/VehicleObjectPool_test.cpp
+++ b/automotive/vehicle/2.0/default/tests/VehicleObjectPool_test.cpp
@@ -57,11 +57,11 @@
};
TEST_F(VehicleObjectPoolTest, valuePoolBasicCorrectness) {
- void* raw = valuePool->obtain(VehiclePropertyType::INT32).get();
+ auto value = valuePool->obtain(VehiclePropertyType::INT32);
// At this point, v1 should be recycled and the only object in the pool.
- ASSERT_EQ(raw, valuePool->obtain(VehiclePropertyType::INT32).get());
+ ASSERT_EQ(value.get(), valuePool->obtain(VehiclePropertyType::INT32).get());
// Obtaining value of another type - should return a new object
- ASSERT_NE(raw, valuePool->obtain(VehiclePropertyType::FLOAT).get());
+ ASSERT_NE(value.get(), valuePool->obtain(VehiclePropertyType::FLOAT).get());
ASSERT_EQ(3u, stats->Obtained);
ASSERT_EQ(2u, stats->Created);
diff --git a/bluetooth/audio/2.0/default/session/BluetoothAudioSession.h b/bluetooth/audio/2.0/default/session/BluetoothAudioSession.h
index 85e8742..838d1cc 100644
--- a/bluetooth/audio/2.0/default/session/BluetoothAudioSession.h
+++ b/bluetooth/audio/2.0/default/session/BluetoothAudioSession.h
@@ -156,8 +156,9 @@
static constexpr PcmParameters kInvalidPcmParameters = {
.sampleRate = SampleRate::RATE_UNKNOWN,
+ .channelMode = ChannelMode::UNKNOWN,
.bitsPerSample = BitsPerSample::BITS_UNKNOWN,
- .channelMode = ChannelMode::UNKNOWN};
+ };
// can't be constexpr because of non-literal type
static const CodecConfiguration kInvalidCodecConfiguration;
diff --git a/bluetooth/audio/2.0/default/session/BluetoothAudioSupportedCodecsDB.cpp b/bluetooth/audio/2.0/default/session/BluetoothAudioSupportedCodecsDB.cpp
index 292e28b..6ea61e1 100644
--- a/bluetooth/audio/2.0/default/session/BluetoothAudioSupportedCodecsDB.cpp
+++ b/bluetooth/audio/2.0/default/session/BluetoothAudioSupportedCodecsDB.cpp
@@ -94,16 +94,18 @@
static const AptxParameters kDefaultOffloadAptxCapability = {
.sampleRate = static_cast<SampleRate>(SampleRate::RATE_44100 |
SampleRate::RATE_48000),
+ .channelMode = ChannelMode::STEREO,
.bitsPerSample = BitsPerSample::BITS_16,
- .channelMode = ChannelMode::STEREO};
+};
// aptX HD: mSampleRate:(44100|48000), mBitsPerSample:(24),
// mChannelMode:(STEREO)
static const AptxParameters kDefaultOffloadAptxHdCapability = {
.sampleRate = static_cast<SampleRate>(SampleRate::RATE_44100 |
SampleRate::RATE_48000),
+ .channelMode = ChannelMode::STEREO,
.bitsPerSample = BitsPerSample::BITS_24,
- .channelMode = ChannelMode::STEREO};
+};
const std::vector<CodecCapabilities> kDefaultOffloadA2dpCodecCapabilities = {
{.codecType = CodecType::SBC, .capabilities = {}},
diff --git a/camera/device/3.4/default/ExternalCameraDevice.cpp b/camera/device/3.4/default/ExternalCameraDevice.cpp
index 9a2fddf..f518a15 100644
--- a/camera/device/3.4/default/ExternalCameraDevice.cpp
+++ b/camera/device/3.4/default/ExternalCameraDevice.cpp
@@ -754,11 +754,11 @@
int fd, double fpsUpperBound, SupportedV4L2Format* format) {
format->frameRates.clear();
- v4l2_frmivalenum frameInterval {
- .pixel_format = format->fourcc,
- .width = format->width,
- .height = format->height,
- .index = 0
+ v4l2_frmivalenum frameInterval{
+ .index = 0,
+ .pixel_format = format->fourcc,
+ .width = format->width,
+ .height = format->height,
};
for (frameInterval.index = 0;
diff --git a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
index dc5579a..9ff0d74 100644
--- a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
+++ b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
@@ -2412,9 +2412,7 @@
mV4L2BufferCount = req_buffers.count;
for (uint32_t i = 0; i < req_buffers.count; i++) {
v4l2_buffer buffer = {
- .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
- .index = i,
- .memory = V4L2_MEMORY_MMAP};
+ .index = i, .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, .memory = V4L2_MEMORY_MMAP};
if (TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_QUERYBUF, &buffer)) < 0) {
ALOGE("%s: QUERYBUF %d failed: %s", __FUNCTION__, i, strerror(errno));
diff --git a/cas/1.0/vts/functional/Android.bp b/cas/1.0/vts/functional/Android.bp
index 622baa5..ab39c0e 100644
--- a/cas/1.0/vts/functional/Android.bp
+++ b/cas/1.0/vts/functional/Android.bp
@@ -29,6 +29,6 @@
shared_libs: [
"libbinder",
],
- test_suites: ["general-tests"],
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/cas/1.0/vts/functional/VtsHalCasV1_0TargetTest.cpp b/cas/1.0/vts/functional/VtsHalCasV1_0TargetTest.cpp
index f0bba57..0f16de5 100644
--- a/cas/1.0/vts/functional/VtsHalCasV1_0TargetTest.cpp
+++ b/cas/1.0/vts/functional/VtsHalCasV1_0TargetTest.cpp
@@ -16,8 +16,6 @@
#define LOG_TAG "mediacas_hidl_hal_test"
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
#include <android-base/logging.h>
#include <android/hardware/cas/1.0/ICas.h>
#include <android/hardware/cas/1.0/ICasListener.h>
@@ -27,8 +25,11 @@
#include <android/hardware/cas/native/1.0/IDescrambler.h>
#include <android/hardware/cas/native/1.0/types.h>
#include <binder/MemoryDealer.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
#include <hidl/HidlSupport.h>
#include <hidl/HidlTransportSupport.h>
+#include <hidl/ServiceManagement.h>
#include <hidl/Status.h>
#include <hidlmemory/FrameworkUtils.h>
#include <utils/Condition.h>
@@ -208,29 +209,16 @@
EXPECT_TRUE(mEventData == eventData);
}
-// Test environment for Cas HIDL HAL.
-class CasHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static CasHidlEnvironment* Instance() {
- static CasHidlEnvironment* instance = new CasHidlEnvironment;
- return instance;
- }
-
- virtual void registerTestServices() override { registerTestService<IMediaCasService>(); }
-};
-
-class MediaCasHidlTest : public ::testing::VtsHalHidlTargetTestBase {
- public:
+class MediaCasHidlTest : public testing::TestWithParam<std::string> {
+ public:
virtual void SetUp() override {
- mService = ::testing::VtsHalHidlTargetTestBase::getService<IMediaCasService>(
- CasHidlEnvironment::Instance()->getServiceName<IMediaCasService>());
+ mService = IMediaCasService::getService(GetParam());
ASSERT_NE(mService, nullptr);
}
- sp<IMediaCasService> mService;
+ sp<IMediaCasService> mService = nullptr;
- protected:
+ protected:
static void description(const std::string& description) {
RecordProperty("description", description);
}
@@ -419,7 +407,7 @@
return ::testing::AssertionResult(returnVoid.isOk());
}
-TEST_F(MediaCasHidlTest, EnumeratePlugins) {
+TEST_P(MediaCasHidlTest, EnumeratePlugins) {
description("Test enumerate plugins");
hidl_vec<HidlCasPluginDescriptor> descriptors;
EXPECT_TRUE(mService
@@ -440,7 +428,7 @@
}
}
-TEST_F(MediaCasHidlTest, TestInvalidSystemIdFails) {
+TEST_P(MediaCasHidlTest, TestInvalidSystemIdFails) {
description("Test failure for invalid system ID");
sp<MediaCasListener> casListener = new MediaCasListener();
@@ -458,7 +446,7 @@
EXPECT_EQ(descramblerBase, nullptr);
}
-TEST_F(MediaCasHidlTest, TestClearKeyPluginInstalled) {
+TEST_P(MediaCasHidlTest, TestClearKeyPluginInstalled) {
description("Test if ClearKey plugin is installed");
hidl_vec<HidlCasPluginDescriptor> descriptors;
EXPECT_TRUE(mService
@@ -480,7 +468,7 @@
ASSERT_TRUE(false) << "ClearKey plugin not installed";
}
-TEST_F(MediaCasHidlTest, TestClearKeyApis) {
+TEST_P(MediaCasHidlTest, TestClearKeyApis) {
description("Test that valid call sequences succeed");
ASSERT_TRUE(createCasPlugin(CLEAR_KEY_SYSTEM_ID));
@@ -584,7 +572,7 @@
EXPECT_EQ(Status::OK, returnStatus);
}
-TEST_F(MediaCasHidlTest, TestClearKeySessionClosedAfterRelease) {
+TEST_P(MediaCasHidlTest, TestClearKeySessionClosedAfterRelease) {
description("Test that all sessions are closed after a MediaCas object is released");
ASSERT_TRUE(createCasPlugin(CLEAR_KEY_SYSTEM_ID));
@@ -611,7 +599,7 @@
EXPECT_EQ(Status::ERROR_CAS_SESSION_NOT_OPENED, returnStatus);
}
-TEST_F(MediaCasHidlTest, TestClearKeyErrors) {
+TEST_P(MediaCasHidlTest, TestClearKeyErrors) {
description("Test that invalid call sequences fail with expected error codes");
ASSERT_TRUE(createCasPlugin(CLEAR_KEY_SYSTEM_ID));
@@ -700,7 +688,7 @@
EXPECT_FALSE(mDescramblerBase->requiresSecureDecoderComponent("bad"));
}
-TEST_F(MediaCasHidlTest, TestClearKeyOobFails) {
+TEST_P(MediaCasHidlTest, TestClearKeyOobFails) {
description("Test that oob descramble request fails with expected error");
ASSERT_TRUE(createCasPlugin(CLEAR_KEY_SYSTEM_ID));
@@ -849,11 +837,7 @@
} // anonymous namespace
-int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(CasHidlEnvironment::Instance());
- ::testing::InitGoogleTest(&argc, argv);
- CasHidlEnvironment::Instance()->init(&argc, argv);
- int status = RUN_ALL_TESTS();
- LOG(INFO) << "Test result = " << status;
- return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, MediaCasHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IMediaCasService::descriptor)),
+ android::hardware::PrintInstanceNameToString);
\ No newline at end of file
diff --git a/cas/1.1/vts/functional/Android.bp b/cas/1.1/vts/functional/Android.bp
index 8afd19a..9e8eb52 100644
--- a/cas/1.1/vts/functional/Android.bp
+++ b/cas/1.1/vts/functional/Android.bp
@@ -30,6 +30,6 @@
shared_libs: [
"libbinder",
],
- test_suites: ["general-tests"],
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/cas/1.1/vts/functional/VtsHalCasV1_1TargetTest.cpp b/cas/1.1/vts/functional/VtsHalCasV1_1TargetTest.cpp
index 0264bdd..7e5a61a 100644
--- a/cas/1.1/vts/functional/VtsHalCasV1_1TargetTest.cpp
+++ b/cas/1.1/vts/functional/VtsHalCasV1_1TargetTest.cpp
@@ -27,8 +27,11 @@
#include <android/hardware/cas/native/1.0/IDescrambler.h>
#include <android/hardware/cas/native/1.0/types.h>
#include <binder/MemoryDealer.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
#include <hidl/HidlSupport.h>
#include <hidl/HidlTransportSupport.h>
+#include <hidl/ServiceManagement.h>
#include <hidl/Status.h>
#include <hidlmemory/FrameworkUtils.h>
#include <utils/Condition.h>
@@ -251,27 +254,14 @@
EXPECT_TRUE(mEventData == eventData);
}
-// Test environment for Cas HIDL HAL.
-class CasHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static CasHidlEnvironment* Instance() {
- static CasHidlEnvironment* instance = new CasHidlEnvironment;
- return instance;
- }
-
- virtual void registerTestServices() override { registerTestService<IMediaCasService>(); }
-};
-
-class MediaCasHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class MediaCasHidlTest : public testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
- mService = ::testing::VtsHalHidlTargetTestBase::getService<IMediaCasService>(
- CasHidlEnvironment::Instance()->getServiceName<IMediaCasService>());
+ mService = IMediaCasService::getService(GetParam());
ASSERT_NE(mService, nullptr);
}
- sp<IMediaCasService> mService;
+ sp<IMediaCasService> mService = nullptr;
protected:
static void description(const std::string& description) {
@@ -453,7 +443,7 @@
return ::testing::AssertionResult(returnVoid.isOk());
}
-TEST_F(MediaCasHidlTest, TestClearKeyApisWithSession) {
+TEST_P(MediaCasHidlTest, TestClearKeyApisWithSession) {
description("Test that valid call sequences with SessionEvent send and receive");
ASSERT_TRUE(createCasPlugin(CLEAR_KEY_SYSTEM_ID));
@@ -561,11 +551,7 @@
} // anonymous namespace
-int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(CasHidlEnvironment::Instance());
- ::testing::InitGoogleTest(&argc, argv);
- CasHidlEnvironment::Instance()->init(&argc, argv);
- int status = RUN_ALL_TESTS();
- LOG(INFO) << "Test result = " << status;
- return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, MediaCasHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IMediaCasService::descriptor)),
+ android::hardware::PrintInstanceNameToString);
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index a409650..34cbe26 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -10,6 +10,7 @@
<hal format="hidl" optional="false">
<name>android.hardware.audio</name>
<version>5.0</version>
+ <version>6.0</version>
<interface>
<name>IDevicesFactory</name>
<instance>default</instance>
@@ -18,6 +19,7 @@
<hal format="hidl" optional="false">
<name>android.hardware.audio.effect</name>
<version>5.0</version>
+ <version>6.0</version>
<interface>
<name>IEffectsFactory</name>
<instance>default</instance>
diff --git a/current.txt b/current.txt
index 4e0d0e0..87649d2 100644
--- a/current.txt
+++ b/current.txt
@@ -595,6 +595,6 @@
619fc9839ec6e369cfa9b28e3e9412e6885720ff8f9b5750c1b6ffb905120391 android.hardware.wifi.supplicant@1.3::ISupplicantStaIfaceCallback
6fe09b18e913608579638594788198ec45bb2369e567d7df661db46c4f0e5f08 android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork
91931b05bd70ea6bdffbe075086183f803379571788564e28854207620eb75cf android.hardware.wifi.supplicant@1.3::types
-033eae03c09ebc75e82db37bc39995dfaa9086745577b44d9e14e9ccb48bd8cc android.hardware.vibrator@1.4::types
544049dcda3f943ad67d83d5277f06681a3782982a9af5a78b5d4e8d295d061a android.hardware.vibrator@1.4::IVibrator
5e1c12efbbba89c9143d10b1b90eceff8bc79aa079f5106215b528e104fef101 android.hardware.vibrator@1.4::IVibratorCallback
+033eae03c09ebc75e82db37bc39995dfaa9086745577b44d9e14e9ccb48bd8cc android.hardware.vibrator@1.4::types
diff --git a/gnss/1.0/default/Gnss.cpp b/gnss/1.0/default/Gnss.cpp
index 32c131c..7d1cacf 100644
--- a/gnss/1.0/default/Gnss.cpp
+++ b/gnss/1.0/default/Gnss.cpp
@@ -128,20 +128,20 @@
for (size_t i = 0; i < svStatus.numSvs; i++) {
auto svInfo = status->gnss_sv_list[i];
IGnssCallback::GnssSvInfo gnssSvInfo = {
- .svid = svInfo.svid,
- .constellation = static_cast<
- android::hardware::gnss::V1_0::GnssConstellationType>(
- svInfo.constellation),
- .cN0Dbhz = svInfo.c_n0_dbhz,
- .elevationDegrees = svInfo.elevation,
- .azimuthDegrees = svInfo.azimuth,
- // Older chipsets do not provide carrier frequency, hence
- // HAS_CARRIER_FREQUENCY flag and the carrierFrequencyHz fields
- // are not set. So we are resetting both fields here.
- .svFlag = static_cast<uint8_t>(
- svInfo.flags &= ~(static_cast<uint8_t>(
- IGnssCallback::GnssSvFlags::HAS_CARRIER_FREQUENCY))),
- .carrierFrequencyHz = 0};
+ .svid = svInfo.svid,
+ .constellation = static_cast<android::hardware::gnss::V1_0::GnssConstellationType>(
+ svInfo.constellation),
+ .cN0Dbhz = svInfo.c_n0_dbhz,
+ .elevationDegrees = svInfo.elevation,
+ .azimuthDegrees = svInfo.azimuth,
+ .carrierFrequencyHz = 0,
+ // Older chipsets do not provide carrier frequency, hence
+ // HAS_CARRIER_FREQUENCY flag and the carrierFrequencyHz fields
+ // are not set. So we are resetting both fields here.
+ .svFlag = static_cast<uint8_t>(
+ svInfo.flags &=
+ ~(static_cast<uint8_t>(IGnssCallback::GnssSvFlags::HAS_CARRIER_FREQUENCY))),
+ };
svStatus.gnssSvList[i] = gnssSvInfo;
}
diff --git a/gnss/1.0/vts/functional/Android.bp b/gnss/1.0/vts/functional/Android.bp
index 505cb41..d73b32e 100644
--- a/gnss/1.0/vts/functional/Android.bp
+++ b/gnss/1.0/vts/functional/Android.bp
@@ -19,5 +19,5 @@
defaults: ["VtsHalTargetTestDefaults"],
srcs: ["VtsHalGnssV1_0TargetTest.cpp"],
static_libs: ["android.hardware.gnss@1.0"],
- test_suites: ["general-tests"],
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/gnss/1.0/vts/functional/VtsHalGnssV1_0TargetTest.cpp b/gnss/1.0/vts/functional/VtsHalGnssV1_0TargetTest.cpp
index c26f60a..1a80ecf 100644
--- a/gnss/1.0/vts/functional/VtsHalGnssV1_0TargetTest.cpp
+++ b/gnss/1.0/vts/functional/VtsHalGnssV1_0TargetTest.cpp
@@ -16,11 +16,11 @@
#define LOG_TAG "VtsHalGnssV1_0TargetTest"
#include <android/hardware/gnss/1.0/IGnss.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
#include <log/log.h>
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
-
#include <chrono>
#include <condition_variable>
#include <mutex>
@@ -42,23 +42,8 @@
bool sAgpsIsPresent = false; // if SUPL or XTRA assistance available
bool sSignalIsWeak = false; // if GNSS signals are weak (e.g. light indoor)
-// Test environment for GNSS HIDL HAL.
-class GnssHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static GnssHidlEnvironment* Instance() {
- static GnssHidlEnvironment* instance = new GnssHidlEnvironment;
- return instance;
- }
-
- virtual void registerTestServices() override { registerTestService<IGnss>(); }
-
- private:
- GnssHidlEnvironment() {}
-};
-
// The main test class for GNSS HAL.
-class GnssHalTest : public ::testing::VtsHalHidlTargetTestBase {
+class GnssHalTest : public testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
// Clean between tests
@@ -67,8 +52,7 @@
info_called_count_ = 0;
notify_count_ = 0;
- gnss_hal_ = ::testing::VtsHalHidlTargetTestBase::getService<IGnss>(
- GnssHidlEnvironment::Instance()->getServiceName<IGnss>());
+ gnss_hal_ = IGnss::getService(GetParam());
ASSERT_NE(gnss_hal_, nullptr);
gnss_cb_ = new GnssCallback(*this);
@@ -344,14 +328,14 @@
* Since this is just the basic operation of SetUp() and TearDown(),
* the function definition is intentionally empty
*/
-TEST_F(GnssHalTest, SetCallbackCapabilitiesCleanup) {}
+TEST_P(GnssHalTest, SetCallbackCapabilitiesCleanup) {}
/*
* GetLocation:
* Turns on location, waits 45 second for at least 5 locations,
* and checks them for reasonable validity.
*/
-TEST_F(GnssHalTest, GetLocation) {
+TEST_P(GnssHalTest, GetLocation) {
#define MIN_INTERVAL_MSEC 500
#define PREFERRED_ACCURACY 0 // Ideally perfect (matches GnssLocationProvider)
#define PREFERRED_TIME_MSEC 0 // Ideally immediate
@@ -391,7 +375,7 @@
* InjectDelete:
* Ensures that calls to inject and/or delete information state are handled.
*/
-TEST_F(GnssHalTest, InjectDelete) {
+TEST_P(GnssHalTest, InjectDelete) {
// confidently, well north of Alaska
auto result = gnss_hal_->injectLocation(80.0, -170.0, 1000.0);
@@ -424,7 +408,7 @@
* null or actual extension, no crash.
* Confirms year-based required extensions (Measurement & Debug) are present
*/
-TEST_F(GnssHalTest, GetAllExtensions) {
+TEST_P(GnssHalTest, GetAllExtensions) {
// Basic call-is-handled checks
auto gnssXtra = gnss_hal_->getExtensionXtra();
ASSERT_TRUE(gnssXtra.isOk());
@@ -470,7 +454,7 @@
* MeasurementCapabilities:
* Verifies that modern hardware supports measurement capabilities.
*/
-TEST_F(GnssHalTest, MeasurementCapabilites) {
+TEST_P(GnssHalTest, MeasurementCapabilites) {
if (info_called_count_ > 0 && last_info_.yearOfHw >= 2016) {
EXPECT_TRUE(last_capabilities_ & IGnssCallback::Capabilities::MEASUREMENTS);
}
@@ -480,16 +464,19 @@
* SchedulingCapabilities:
* Verifies that 2018+ hardware supports Scheduling capabilities.
*/
-TEST_F(GnssHalTest, SchedulingCapabilities) {
+TEST_P(GnssHalTest, SchedulingCapabilities) {
if (info_called_count_ > 0 && last_info_.yearOfHw >= 2018) {
EXPECT_TRUE(last_capabilities_ & IGnssCallback::Capabilities::SCHEDULING);
}
}
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, GnssHalTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IGnss::descriptor)),
+ android::hardware::PrintInstanceNameToString);
+
int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(GnssHidlEnvironment::Instance());
::testing::InitGoogleTest(&argc, argv);
- GnssHidlEnvironment::Instance()->init(&argc, argv);
/*
* These arguments not used by automated VTS testing.
* Only for use in manual testing, when wanting to run
@@ -502,7 +489,6 @@
sSignalIsWeak = true;
}
}
- int status = RUN_ALL_TESTS();
- ALOGI("Test result = %d", status);
- return status;
-}
+
+ return RUN_ALL_TESTS();
+}
\ No newline at end of file
diff --git a/gnss/1.1/vts/functional/Android.bp b/gnss/1.1/vts/functional/Android.bp
index cc34290..bdd02d2 100644
--- a/gnss/1.1/vts/functional/Android.bp
+++ b/gnss/1.1/vts/functional/Android.bp
@@ -30,5 +30,5 @@
shared_libs: [
"android.hardware.gnss.measurement_corrections@1.0",
],
- test_suites: ["general-tests"],
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/gnss/1.1/vts/functional/VtsHalGnssV1_1TargetTest.cpp b/gnss/1.1/vts/functional/VtsHalGnssV1_1TargetTest.cpp
index ca9eef4..4a0a7f9 100644
--- a/gnss/1.1/vts/functional/VtsHalGnssV1_1TargetTest.cpp
+++ b/gnss/1.1/vts/functional/VtsHalGnssV1_1TargetTest.cpp
@@ -15,15 +15,15 @@
*/
#define LOG_TAG "VtsHalGnssV1_1TargetTest"
-#include <VtsHalHidlTargetTestBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
#include "gnss_hal_test.h"
-int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(GnssHidlEnvironment::Instance());
- ::testing::InitGoogleTest(&argc, argv);
- GnssHidlEnvironment::Instance()->init(&argc, argv);
- int status = RUN_ALL_TESTS();
- ALOGI("Test result = %d", status);
- return status;
-}
+using android::hardware::gnss::V1_1::IGnss;
+
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, GnssHalTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IGnss::descriptor)),
+ android::hardware::PrintInstanceNameToString);
\ No newline at end of file
diff --git a/gnss/1.1/vts/functional/gnss_hal_test.cpp b/gnss/1.1/vts/functional/gnss_hal_test.cpp
index 61a2ce4..2c8a7b1 100644
--- a/gnss/1.1/vts/functional/gnss_hal_test.cpp
+++ b/gnss/1.1/vts/functional/gnss_hal_test.cpp
@@ -17,6 +17,8 @@
#define LOG_TAG "GnssHalTest"
#include <android/hidl/manager/1.2/IServiceManager.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
#include <hidl/ServiceManagement.h>
#include <gnss_hal_test.h>
@@ -29,8 +31,7 @@
using ::android::hardware::gnss::common::Utils;
void GnssHalTest::SetUp() {
- gnss_hal_ = ::testing::VtsHalHidlTargetTestBase::getService<IGnss>(
- GnssHidlEnvironment::Instance()->getServiceName<IGnss>());
+ gnss_hal_ = IGnss::getService(GetParam());
ASSERT_NE(gnss_hal_, nullptr);
SetUpGnssCallback();
diff --git a/gnss/1.1/vts/functional/gnss_hal_test.h b/gnss/1.1/vts/functional/gnss_hal_test.h
index e4325bf..169cd62 100644
--- a/gnss/1.1/vts/functional/gnss_hal_test.h
+++ b/gnss/1.1/vts/functional/gnss_hal_test.h
@@ -19,8 +19,7 @@
#include <android/hardware/gnss/1.1/IGnss.h>
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
+#include <gtest/gtest.h>
#include "GnssCallbackEventQueue.h"
using android::hardware::Return;
@@ -37,24 +36,9 @@
#define TIMEOUT_SEC 2 // for basic commands/responses
-// Test environment for GNSS HIDL HAL.
-class GnssHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static GnssHidlEnvironment* Instance() {
- static GnssHidlEnvironment* instance = new GnssHidlEnvironment;
- return instance;
- }
-
- virtual void registerTestServices() override { registerTestService<IGnss>(); }
-
- private:
- GnssHidlEnvironment() {}
-};
-
// The main test class for GNSS HAL.
-class GnssHalTest : public ::testing::VtsHalHidlTargetTestBase {
- public:
+class GnssHalTest : public testing::TestWithParam<std::string> {
+ public:
virtual void SetUp() override;
virtual void TearDown() override;
diff --git a/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp b/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
index 3294bcd..79da84a 100644
--- a/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
+++ b/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
@@ -18,9 +18,8 @@
#include <gnss_hal_test.h>
-#include <VtsHalHidlTargetTestBase.h>
-
#include <android/hardware/gnss/1.1/IGnssConfiguration.h>
+#include <gtest/gtest.h>
using android::hardware::hidl_vec;
@@ -39,13 +38,13 @@
*
* Empty test fixture to verify basic Setup & Teardown
*/
-TEST_F(GnssHalTest, SetupTeardownCreateCleanup) {}
+TEST_P(GnssHalTest, SetupTeardownCreateCleanup) {}
/*
* TestGnssMeasurementCallback:
* Gets the GnssMeasurementExtension and verify that it returns an actual extension.
*/
-TEST_F(GnssHalTest, TestGnssMeasurementCallback) {
+TEST_P(GnssHalTest, TestGnssMeasurementCallback) {
auto gnssMeasurement_1_1 = gnss_hal_->getExtensionGnssMeasurement_1_1();
ASSERT_TRUE(gnssMeasurement_1_1.isOk());
auto gnssMeasurement_1_0 = gnss_hal_->getExtensionGnssMeasurement();
@@ -65,7 +64,7 @@
* NO_LOCATION_PERIOD_SEC and verfiy that no location is received. Also perform validity checks on
* each received location.
*/
-TEST_F(GnssHalTest, GetLocationLowPower) {
+TEST_P(GnssHalTest, GetLocationLowPower) {
if (!IsGnssHalVersion_1_1()) {
ALOGI("Test GetLocationLowPower skipped. GNSS HAL version is greater than 1.1.");
return;
@@ -97,7 +96,6 @@
gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_, kNoLocationPeriodSec);
const int location_called_count = gnss_cb_->location_cbq_.calledCount();
-
// Tolerate (ignore) one extra location right after the first one
// to handle startup edge case scheduling limitations in some implementations
if ((i == 1) && (location_called_count == 2)) {
@@ -132,7 +130,8 @@
*/
IGnssConfiguration::BlacklistedSource FindStrongFrequentNonGpsSource(
- const list<IGnssCallback::GnssSvStatus> list_gnss_sv_status, const int min_observations) {
+ const std::list<IGnssCallback::GnssSvStatus> list_gnss_sv_status,
+ const int min_observations) {
struct ComparableBlacklistedSource {
IGnssConfiguration::BlacklistedSource id;
@@ -218,7 +217,7 @@
* 5b) Retry a few times, in case GNSS search strategy takes a while to reacquire even the
* formerly strongest satellite
*/
-TEST_F(GnssHalTest, BlacklistIndividualSatellites) {
+TEST_P(GnssHalTest, BlacklistIndividualSatellites) {
if (!IsGnssHalVersion_1_1()) {
ALOGI("Test BlacklistIndividualSatellites skipped. GNSS HAL version is greater than 1.1.");
return;
@@ -244,7 +243,7 @@
*/
const int kGnssSvStatusTimeout = 2;
- list<IGnssCallback::GnssSvStatus> sv_status_list;
+ std::list<IGnssCallback::GnssSvStatus> sv_status_list;
int count = gnss_cb_->sv_status_cbq_.retrieve(sv_status_list, sv_status_cbq_size,
kGnssSvStatusTimeout);
ASSERT_EQ(count, sv_status_cbq_size);
@@ -362,7 +361,7 @@
* GnssStatus does not use any constellation but GPS.
* 4a & b) Clean up by turning off location, and send in empty blacklist.
*/
-TEST_F(GnssHalTest, BlacklistConstellation) {
+TEST_P(GnssHalTest, BlacklistConstellation) {
if (!IsGnssHalVersion_1_1()) {
ALOGI("Test BlacklistConstellation skipped. GNSS HAL version is greater than 1.1.");
return;
@@ -457,7 +456,7 @@
*
* Ensure successfully injecting a location.
*/
-TEST_F(GnssHalTest, InjectBestLocation) {
+TEST_P(GnssHalTest, InjectBestLocation) {
StartAndCheckLocations(1);
GnssLocation gnssLocation = gnss_cb_->last_location_;
CheckLocation(gnssLocation, true);
@@ -476,7 +475,7 @@
* GnssDebugValuesSanityTest:
* Ensures that GnssDebug values make sense.
*/
-TEST_F(GnssHalTest, GnssDebugValuesSanityTest) {
+TEST_P(GnssHalTest, GnssDebugValuesSanityTest) {
auto gnssDebug = gnss_hal_->getExtensionGnssDebug();
ASSERT_TRUE(gnssDebug.isOk());
if (gnss_cb_->info_cbq_.calledCount() > 0 && gnss_cb_->last_info_.yearOfHw >= 2017) {
diff --git a/gnss/2.0/default/GnssMeasurement.cpp b/gnss/2.0/default/GnssMeasurement.cpp
index 93de89c..1f95ff9 100644
--- a/gnss/2.0/default/GnssMeasurement.cpp
+++ b/gnss/2.0/default/GnssMeasurement.cpp
@@ -119,12 +119,13 @@
V2_0::IGnssMeasurementCallback::GnssMeasurement measurement_2_0 = {
.v1_1 = measurement_1_1,
.codeType = "C",
- .constellation = GnssConstellationType::GLONASS,
.state = GnssMeasurementState::STATE_CODE_LOCK | GnssMeasurementState::STATE_BIT_SYNC |
GnssMeasurementState::STATE_SUBFRAME_SYNC |
GnssMeasurementState::STATE_TOW_DECODED |
GnssMeasurementState::STATE_GLO_STRING_SYNC |
- GnssMeasurementState::STATE_GLO_TOD_DECODED};
+ GnssMeasurementState::STATE_GLO_TOD_DECODED,
+ .constellation = GnssConstellationType::GLONASS,
+ };
hidl_vec<IGnssMeasurementCallback::GnssMeasurement> measurements(1);
measurements[0] = measurement_2_0;
diff --git a/gnss/2.0/vts/functional/Android.bp b/gnss/2.0/vts/functional/Android.bp
index 278d87b..9aa1334 100644
--- a/gnss/2.0/vts/functional/Android.bp
+++ b/gnss/2.0/vts/functional/Android.bp
@@ -30,4 +30,5 @@
"android.hardware.gnss@2.0",
"android.hardware.gnss@common-vts-lib",
],
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/gnss/2.0/vts/functional/VtsHalGnssV2_0TargetTest.cpp b/gnss/2.0/vts/functional/VtsHalGnssV2_0TargetTest.cpp
index ae36c50..2c74fa3 100644
--- a/gnss/2.0/vts/functional/VtsHalGnssV2_0TargetTest.cpp
+++ b/gnss/2.0/vts/functional/VtsHalGnssV2_0TargetTest.cpp
@@ -15,15 +15,15 @@
*/
#define LOG_TAG "VtsHalGnssV2_0TargetTest"
-#include <VtsHalHidlTargetTestBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
#include "gnss_hal_test.h"
-int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(GnssHidlEnvironment::Instance());
- ::testing::InitGoogleTest(&argc, argv);
- GnssHidlEnvironment::Instance()->init(&argc, argv);
- int status = RUN_ALL_TESTS();
- ALOGI("Test result = %d", status);
- return status;
-}
+using android::hardware::gnss::V2_0::IGnss;
+
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, GnssHalTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IGnss::descriptor)),
+ android::hardware::PrintInstanceNameToString);
\ No newline at end of file
diff --git a/gnss/2.0/vts/functional/gnss_hal_test.cpp b/gnss/2.0/vts/functional/gnss_hal_test.cpp
index 14ae43c..8ca3f68 100644
--- a/gnss/2.0/vts/functional/gnss_hal_test.cpp
+++ b/gnss/2.0/vts/functional/gnss_hal_test.cpp
@@ -20,12 +20,13 @@
#include <chrono>
#include "Utils.h"
+#include <gtest/gtest.h>
+
using ::android::hardware::gnss::common::Utils;
// Implementations for the main test class for GNSS HAL
void GnssHalTest::SetUp() {
- gnss_hal_ = ::testing::VtsHalHidlTargetTestBase::getService<IGnss>(
- GnssHidlEnvironment::Instance()->getServiceName<IGnss>());
+ gnss_hal_ = IGnss::getService(GetParam());
ASSERT_NE(gnss_hal_, nullptr);
SetUpGnssCallback();
diff --git a/gnss/2.0/vts/functional/gnss_hal_test.h b/gnss/2.0/vts/functional/gnss_hal_test.h
index 7d07c0f..4f7b87a 100644
--- a/gnss/2.0/vts/functional/gnss_hal_test.h
+++ b/gnss/2.0/vts/functional/gnss_hal_test.h
@@ -17,11 +17,11 @@
#ifndef GNSS_HAL_TEST_H_
#define GNSS_HAL_TEST_H_
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
#include <android/hardware/gnss/2.0/IGnss.h>
#include "GnssCallbackEventQueue.h"
+#include <gtest/gtest.h>
+
using android::hardware::hidl_vec;
using android::hardware::Return;
using android::hardware::Void;
@@ -45,24 +45,9 @@
#define TIMEOUT_SEC 2 // for basic commands/responses
-// Test environment for GNSS HIDL HAL.
-class GnssHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static GnssHidlEnvironment* Instance() {
- static GnssHidlEnvironment* instance = new GnssHidlEnvironment;
- return instance;
- }
-
- virtual void registerTestServices() override { registerTestService<IGnss>(); }
-
- private:
- GnssHidlEnvironment() {}
-};
-
// The main test class for GNSS HAL.
-class GnssHalTest : public ::testing::VtsHalHidlTargetTestBase {
- public:
+class GnssHalTest : public testing::TestWithParam<std::string> {
+ public:
virtual void SetUp() override;
virtual void TearDown() override;
diff --git a/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp b/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp
index ca3edc5..c442cc6 100644
--- a/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp
+++ b/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp
@@ -16,10 +16,11 @@
#define LOG_TAG "GnssHalTestCases"
-#include <VtsHalHidlTargetTestBase.h>
#include <gnss_hal_test.h>
#include "Utils.h"
+#include <gtest/gtest.h>
+
using android::hardware::hidl_string;
using android::hardware::hidl_vec;
@@ -51,13 +52,13 @@
*
* Empty test fixture to verify basic Setup & Teardown
*/
-TEST_F(GnssHalTest, SetupTeardownCreateCleanup) {}
+TEST_P(GnssHalTest, SetupTeardownCreateCleanup) {}
/*
* TestGnssMeasurementExtension:
* Gets the GnssMeasurementExtension and verifies that it returns an actual extension.
*/
-TEST_F(GnssHalTest, TestGnssMeasurementExtension) {
+TEST_P(GnssHalTest, TestGnssMeasurementExtension) {
auto gnssMeasurement_2_0 = gnss_hal_->getExtensionGnssMeasurement_2_0();
auto gnssMeasurement_1_1 = gnss_hal_->getExtensionGnssMeasurement_1_1();
auto gnssMeasurement_1_0 = gnss_hal_->getExtensionGnssMeasurement();
@@ -80,7 +81,7 @@
* The GNSS HAL 2.0 implementation must support @2.0::IGnssConfiguration interface due to
* the deprecation of some methods in @1.0::IGnssConfiguration interface.
*/
-TEST_F(GnssHalTest, TestGnssConfigurationExtension) {
+TEST_P(GnssHalTest, TestGnssConfigurationExtension) {
auto gnssConfiguration = gnss_hal_->getExtensionGnssConfiguration_2_0();
ASSERT_TRUE(gnssConfiguration.isOk());
sp<IGnssConfiguration_2_0> iGnssConfiguration = gnssConfiguration;
@@ -96,7 +97,7 @@
* TestGnssConfiguration_setSuplEs_Deprecation:
* Calls setSuplEs and verifies that it returns false.
*/
-TEST_F(GnssHalTest, TestGnssConfiguration_setSuplEs_Deprecation) {
+TEST_P(GnssHalTest, TestGnssConfiguration_setSuplEs_Deprecation) {
auto gnssConfiguration = gnss_hal_->getExtensionGnssConfiguration_2_0();
ASSERT_TRUE(gnssConfiguration.isOk());
sp<IGnssConfiguration_2_0> iGnssConfiguration = gnssConfiguration;
@@ -111,7 +112,7 @@
* TestGnssConfiguration_setGpsLock_Deprecation:
* Calls setGpsLock and verifies that it returns false.
*/
-TEST_F(GnssHalTest, TestGnssConfiguration_setGpsLock_Deprecation) {
+TEST_P(GnssHalTest, TestGnssConfiguration_setGpsLock_Deprecation) {
auto gnssConfiguration = gnss_hal_->getExtensionGnssConfiguration_2_0();
ASSERT_TRUE(gnssConfiguration.isOk());
sp<IGnssConfiguration_2_0> iGnssConfiguration = gnssConfiguration;
@@ -130,7 +131,7 @@
* @2.0::IAGnssRil interface due to the deprecation of framework network API methods needed
* to support the @1.0::IAGnssRil interface.
*/
-TEST_F(GnssHalTest, TestAGnssRilExtension) {
+TEST_P(GnssHalTest, TestAGnssRilExtension) {
auto agnssRil_2_0 = gnss_hal_->getExtensionAGnssRil_2_0();
ASSERT_TRUE(agnssRil_2_0.isOk());
sp<IAGnssRil_2_0> iAGnssRil_2_0 = agnssRil_2_0;
@@ -148,7 +149,7 @@
* 1. Updates GNSS HAL that a network has connected.
* 2. Updates GNSS HAL that network has disconnected.
*/
-TEST_F(GnssHalTest, TestAGnssRil_UpdateNetworkState_2_0) {
+TEST_P(GnssHalTest, TestAGnssRil_UpdateNetworkState_2_0) {
auto agnssRil = gnss_hal_->getExtensionAGnssRil_2_0();
ASSERT_TRUE(agnssRil.isOk());
sp<IAGnssRil_2_0> iAGnssRil = agnssRil;
@@ -180,7 +181,7 @@
* 2. constellation is valid.
* 3. state is valid.
*/
-TEST_F(GnssHalTest, TestGnssMeasurementFields) {
+TEST_P(GnssHalTest, TestGnssMeasurementFields) {
const int kFirstGnssMeasurementTimeoutSeconds = 10;
auto gnssMeasurement = gnss_hal_->getExtensionGnssMeasurement_2_0();
@@ -234,7 +235,7 @@
* @2.0::IAGnss interface due to the deprecation of framework network API methods needed
* to support the @1.0::IAGnss interface.
*/
-TEST_F(GnssHalTest, TestAGnssExtension) {
+TEST_P(GnssHalTest, TestAGnssExtension) {
auto agnss_2_0 = gnss_hal_->getExtensionAGnss_2_0();
ASSERT_TRUE(agnss_2_0.isOk());
sp<IAGnss_2_0> iAGnss_2_0 = agnss_2_0;
@@ -258,7 +259,7 @@
* TestGnssNiExtension_Deprecation:
* Gets the @1.0::IGnssNi extension and verifies that it is a nullptr.
*/
-TEST_F(GnssHalTest, TestGnssNiExtension_Deprecation) {
+TEST_P(GnssHalTest, TestGnssNiExtension_Deprecation) {
// Verify IGnssNi 1.0 is not supported.
auto gnssNi = gnss_hal_->getExtensionGnssNi();
ASSERT_TRUE(!gnssNi.isOk() || ((sp<IGnssNi>)gnssNi) == nullptr);
@@ -269,7 +270,7 @@
* Gets the GnssVisibilityControlExtension and if it is not null, verifies that it supports
* the gnss.visibility_control@1.0::IGnssVisibilityControl interface by invoking a method.
*/
-TEST_F(GnssHalTest, TestGnssVisibilityControlExtension) {
+TEST_P(GnssHalTest, TestGnssVisibilityControlExtension) {
auto gnssVisibilityControl = gnss_hal_->getExtensionVisibilityControl();
ASSERT_TRUE(gnssVisibilityControl.isOk());
sp<IGnssVisibilityControl> iGnssVisibilityControl = gnssVisibilityControl;
@@ -290,7 +291,7 @@
* capabilities are reported and the mandatory LOS_SATS or the EXCESS_PATH_LENGTH
* capability flag is set.
*/
-TEST_F(GnssHalTest, TestGnssMeasurementCorrectionsCapabilities) {
+TEST_P(GnssHalTest, TestGnssMeasurementCorrectionsCapabilities) {
if (!(gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::MEASUREMENT_CORRECTIONS)) {
return;
}
@@ -318,7 +319,7 @@
* If measurement corrections capability is supported, verifies that it supports the
* gnss.measurement_corrections@1.0::IMeasurementCorrections interface by invoking a method.
*/
-TEST_F(GnssHalTest, TestGnssMeasurementCorrections) {
+TEST_P(GnssHalTest, TestGnssMeasurementCorrections) {
if (!(gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::MEASUREMENT_CORRECTIONS)) {
return;
}
@@ -348,7 +349,7 @@
* Sets a GnssMeasurementCallback, waits for a GnssData object, and verifies the flags in member
* elapsedRealitme are valid.
*/
-TEST_F(GnssHalTest, TestGnssDataElapsedRealtimeFlags) {
+TEST_P(GnssHalTest, TestGnssDataElapsedRealtimeFlags) {
const int kFirstGnssMeasurementTimeoutSeconds = 10;
auto gnssMeasurement = gnss_hal_->getExtensionGnssMeasurement_2_0();
@@ -383,7 +384,7 @@
iGnssMeasurement->close();
}
-TEST_F(GnssHalTest, TestGnssLocationElapsedRealtime) {
+TEST_P(GnssHalTest, TestGnssLocationElapsedRealtime) {
StartAndCheckFirstLocation();
ASSERT_TRUE((int)gnss_cb_->last_location_.elapsedRealtime.flags <=
@@ -399,7 +400,7 @@
}
// This test only verify that injectBestLocation_2_0 does not crash.
-TEST_F(GnssHalTest, TestInjectBestLocation_2_0) {
+TEST_P(GnssHalTest, TestInjectBestLocation_2_0) {
StartAndCheckFirstLocation();
gnss_hal_->injectBestLocation_2_0(gnss_cb_->last_location_);
StopAndClearLocations();
@@ -410,7 +411,7 @@
* Gets the @2.0::IGnssBatching extension and verifies that it doesn't return an error. Support
* for this interface is optional.
*/
-TEST_F(GnssHalTest, TestGnssBatchingExtension) {
+TEST_P(GnssHalTest, TestGnssBatchingExtension) {
auto gnssBatching_2_0 = gnss_hal_->getExtensionGnssBatching_2_0();
ASSERT_TRUE(gnssBatching_2_0.isOk());
}
@@ -422,7 +423,7 @@
* NO_LOCATION_PERIOD_SEC and verfiy that no location is received. Also perform validity checks on
* each received location.
*/
-TEST_F(GnssHalTest, GetLocationLowPower) {
+TEST_P(GnssHalTest, GetLocationLowPower) {
if (!(gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::LOW_POWER_MODE)) {
ALOGI("Test GetLocationLowPower skipped. LOW_POWER_MODE capability not supported.");
return;
@@ -513,7 +514,7 @@
* or a source with constellation == UNKNOWN if none are found sufficient times
*/
IGnssConfiguration_1_1::BlacklistedSource FindStrongFrequentNonGpsSource(
- const list<hidl_vec<IGnssCallback_2_0::GnssSvInfo>>& sv_info_lists,
+ const std::list<hidl_vec<IGnssCallback_2_0::GnssSvInfo>>& sv_info_lists,
const int min_observations) {
struct ComparableBlacklistedSource {
IGnssConfiguration_1_1::BlacklistedSource id;
@@ -599,7 +600,7 @@
* 5b) Retry a few times, in case GNSS search strategy takes a while to reacquire even the
* formerly strongest satellite
*/
-TEST_F(GnssHalTest, BlacklistIndividualSatellites) {
+TEST_P(GnssHalTest, BlacklistIndividualSatellites) {
if (!(gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::SATELLITE_BLACKLIST)) {
ALOGI("Test BlacklistIndividualSatellites skipped. SATELLITE_BLACKLIST capability"
" not supported.");
@@ -626,7 +627,7 @@
*/
const int kGnssSvStatusTimeout = 2;
- list<hidl_vec<IGnssCallback_2_0::GnssSvInfo>> sv_info_lists;
+ std::list<hidl_vec<IGnssCallback_2_0::GnssSvInfo>> sv_info_lists;
int count = gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_lists, sv_info_list_cbq_size,
kGnssSvStatusTimeout);
ASSERT_EQ(count, sv_info_list_cbq_size);
@@ -744,7 +745,7 @@
* GnssStatus does not use any constellation but GPS.
* 4a & b) Clean up by turning off location, and send in empty blacklist.
*/
-TEST_F(GnssHalTest, BlacklistConstellation) {
+TEST_P(GnssHalTest, BlacklistConstellation) {
if (!(gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::SATELLITE_BLACKLIST)) {
ALOGI("Test BlacklistConstellation skipped. SATELLITE_BLACKLIST capability not supported.");
return;
diff --git a/gnss/common/utils/vts/include/GnssCallbackEventQueue.h b/gnss/common/utils/vts/include/GnssCallbackEventQueue.h
index b1d8ed4..3dc429b 100644
--- a/gnss/common/utils/vts/include/GnssCallbackEventQueue.h
+++ b/gnss/common/utils/vts/include/GnssCallbackEventQueue.h
@@ -53,7 +53,7 @@
* timeout_seconds to retrieve each event. If timeout occurs, it returns the number of
* items retrieved which will be less than count.
*/
- int retrieve(list<T>& event_list, int count, int timeout_seconds);
+ int retrieve(std::list<T>& event_list, int count, int timeout_seconds);
/* Returns the number of events pending to be retrieved from the callback event queue. */
int size() const;
@@ -97,7 +97,7 @@
}
template <class T>
-int GnssCallbackEventQueue<T>::retrieve(list<T>& event_list, int count, int timeout_seconds) {
+int GnssCallbackEventQueue<T>::retrieve(std::list<T>& event_list, int count, int timeout_seconds) {
for (int i = 0; i < count; ++i) {
T event;
if (!retrieve(event, timeout_seconds)) {
diff --git a/graphics/mapper/4.0/IMapper.hal b/graphics/mapper/4.0/IMapper.hal
index f5df04b..85c7c81 100644
--- a/graphics/mapper/4.0/IMapper.hal
+++ b/graphics/mapper/4.0/IMapper.hal
@@ -202,6 +202,9 @@
* the buffer. If the bytesPerStride is unknown or variable, a value of -1
* should be returned.
*
+ * The locked buffer must adhere to the format requested at allocation time
+ * in the BufferDescriptorInfo.
+ *
* @param buffer Buffer to lock.
* @param cpuUsage CPU usage flags to request. See +ndk
* libnativewindow#AHardwareBuffer_UsageFlags for possible values.
diff --git a/health/2.0/vts/functional/VtsHalHealthV2_0TargetTest.cpp b/health/2.0/vts/functional/VtsHalHealthV2_0TargetTest.cpp
index 74fe4fb..6e13a98 100644
--- a/health/2.0/vts/functional/VtsHalHealthV2_0TargetTest.cpp
+++ b/health/2.0/vts/functional/VtsHalHealthV2_0TargetTest.cpp
@@ -257,15 +257,21 @@
using V1_0::BatteryStatus;
using V1_0::BatteryHealth;
- if (!((health_info.legacy.batteryChargeCounter > 0) &&
- (health_info.legacy.batteryCurrent != INT32_MIN) &&
+ if (!((health_info.legacy.batteryCurrent != INT32_MIN) &&
(0 <= health_info.legacy.batteryLevel && health_info.legacy.batteryLevel <= 100) &&
verifyEnum<BatteryHealth>(health_info.legacy.batteryHealth) &&
- (health_info.legacy.batteryStatus != BatteryStatus::UNKNOWN) &&
verifyEnum<BatteryStatus>(health_info.legacy.batteryStatus))) {
return false;
}
+ if (health_info.legacy.batteryPresent) {
+ // If a battery is present, the battery status must be known.
+ if (!((health_info.legacy.batteryChargeCounter > 0) &&
+ (health_info.legacy.batteryStatus != BatteryStatus::UNKNOWN))) {
+ return false;
+ }
+ }
+
return true;
}
diff --git a/light/2.0/vts/functional/Android.bp b/light/2.0/vts/functional/Android.bp
index 9f03d27..2c0a08f 100644
--- a/light/2.0/vts/functional/Android.bp
+++ b/light/2.0/vts/functional/Android.bp
@@ -19,6 +19,6 @@
defaults: ["VtsHalTargetTestDefaults"],
srcs: ["VtsHalLightV2_0TargetTest.cpp"],
static_libs: ["android.hardware.light@2.0"],
- test_suites: ["general-tests"],
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/neuralnetworks/1.0/vts/functional/Android.bp b/neuralnetworks/1.0/vts/functional/Android.bp
index 3e9d5f7..ba9fb45 100644
--- a/neuralnetworks/1.0/vts/functional/Android.bp
+++ b/neuralnetworks/1.0/vts/functional/Android.bp
@@ -71,5 +71,5 @@
header_libs: [
"libneuralnetworks_headers",
],
- test_suites: ["general-tests"],
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/neuralnetworks/1.1/vts/functional/Android.bp b/neuralnetworks/1.1/vts/functional/Android.bp
index 4e85355..69e1761 100644
--- a/neuralnetworks/1.1/vts/functional/Android.bp
+++ b/neuralnetworks/1.1/vts/functional/Android.bp
@@ -47,5 +47,5 @@
header_libs: [
"libneuralnetworks_headers",
],
- test_suites: ["general-tests"],
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/neuralnetworks/1.2/vts/functional/Android.bp b/neuralnetworks/1.2/vts/functional/Android.bp
index fc727b7..bdca0e9 100644
--- a/neuralnetworks/1.2/vts/functional/Android.bp
+++ b/neuralnetworks/1.2/vts/functional/Android.bp
@@ -71,5 +71,5 @@
header_libs: [
"libneuralnetworks_headers",
],
- test_suites: ["general-tests"],
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/renderscript/1.0/default/Device.cpp b/renderscript/1.0/default/Device.cpp
index d603a12..9a6d7ba 100644
--- a/renderscript/1.0/default/Device.cpp
+++ b/renderscript/1.0/default/Device.cpp
@@ -86,150 +86,116 @@
}
dispatchTable dispatchHal = {
- .SetNativeLibDir = (SetNativeLibDirFnPtr) nullptr,
+ .SetNativeLibDir = (SetNativeLibDirFnPtr) nullptr,
- .Allocation1DData =
- (Allocation1DDataFnPtr)dlsym(handle, "rsAllocation1DData"),
- .Allocation1DElementData = (Allocation1DElementDataFnPtr) nullptr,
- .Allocation1DRead =
- (Allocation1DReadFnPtr)dlsym(handle, "rsAllocation1DRead"),
- .Allocation2DData =
- (Allocation2DDataFnPtr)dlsym(handle, "rsAllocation2DData"),
- .Allocation2DRead =
- (Allocation2DReadFnPtr)dlsym(handle, "rsAllocation2DRead"),
- .Allocation3DData =
- (Allocation3DDataFnPtr)dlsym(handle, "rsAllocation3DData"),
- .Allocation3DRead =
- (Allocation3DReadFnPtr)dlsym(handle, "rsAllocation3DRead"),
- .AllocationAdapterCreate = (AllocationAdapterCreateFnPtr)dlsym(
- handle, "rsAllocationAdapterCreate"),
- .AllocationAdapterOffset = (AllocationAdapterOffsetFnPtr)dlsym(
- handle, "rsAllocationAdapterOffset"),
- .AllocationCopy2DRange = (AllocationCopy2DRangeFnPtr)dlsym(
- handle, "rsAllocationCopy2DRange"),
- .AllocationCopy3DRange = (AllocationCopy3DRangeFnPtr)dlsym(
- handle, "rsAllocationCopy3DRange"),
- .AllocationCopyToBitmap = (AllocationCopyToBitmapFnPtr)dlsym(
- handle, "rsAllocationCopyToBitmap"),
- .AllocationCreateFromBitmap = (AllocationCreateFromBitmapFnPtr)dlsym(
- handle, "rsAllocationCreateFromBitmap"),
- .AllocationCreateStrided = (AllocationCreateStridedFnPtr)dlsym(
- handle, "rsAllocationCreateStrided"),
- .AllocationCreateTyped = (AllocationCreateTypedFnPtr)dlsym(
- handle, "rsAllocationCreateTyped"),
- .AllocationCubeCreateFromBitmap =
- (AllocationCubeCreateFromBitmapFnPtr)dlsym(
- handle, "rsAllocationCubeCreateFromBitmap"),
- .AllocationElementData = (AllocationElementDataFnPtr)dlsym(
- handle, "rsAllocationElementData"),
- .AllocationElementRead = (AllocationElementReadFnPtr)dlsym(
- handle, "rsAllocationElementRead"),
- .AllocationGenerateMipmaps = (AllocationGenerateMipmapsFnPtr)dlsym(
- handle, "rsAllocationGenerateMipmaps"),
- .AllocationGetPointer =
- (AllocationGetPointerFnPtr)dlsym(handle, "rsAllocationGetPointer"),
- .AllocationGetSurface =
- (AllocationGetSurfaceFnPtr)dlsym(handle, "rsAllocationGetSurface"),
- .AllocationGetType =
- (AllocationGetTypeFnPtr)dlsym(handle, "rsaAllocationGetType"),
- .AllocationIoReceive =
- (AllocationIoReceiveFnPtr)dlsym(handle, "rsAllocationIoReceive"),
- .AllocationIoSend =
- (AllocationIoSendFnPtr)dlsym(handle, "rsAllocationIoSend"),
- .AllocationRead =
- (AllocationReadFnPtr)dlsym(handle, "rsAllocationRead"),
- .AllocationResize1D =
- (AllocationResize1DFnPtr)dlsym(handle, "rsAllocationResize1D"),
- .AllocationSetSurface =
- (AllocationSetSurfaceFnPtr)dlsym(handle, "rsAllocationSetSurface"),
- .AllocationSetupBufferQueue = (AllocationSetupBufferQueueFnPtr)dlsym(
- handle, "rsAllocationSetupBufferQueue"),
- .AllocationShareBufferQueue = (AllocationShareBufferQueueFnPtr)dlsym(
- handle, "rsAllocationShareBufferQueue"),
- .AllocationSyncAll =
- (AllocationSyncAllFnPtr)dlsym(handle, "rsAllocationSyncAll"),
- .AssignName = (AssignNameFnPtr)dlsym(handle, "rsAssignName"),
- .ClosureCreate = (ClosureCreateFnPtr)dlsym(handle, "rsClosureCreate"),
- .ClosureSetArg = (ClosureSetArgFnPtr)dlsym(handle, "rsClosureSetArg"),
- .ClosureSetGlobal =
- (ClosureSetGlobalFnPtr)dlsym(handle, "rsClosureSetGlobal"),
- .ContextCreateVendor =
- (ContextCreateVendorFnPtr)dlsym(handle, "rsContextCreateVendor"),
- .ContextDeinitToClient = (ContextDeinitToClientFnPtr)dlsym(
- handle, "rsContextDeinitToClient"),
- .ContextDestroy =
- (ContextDestroyFnPtr)dlsym(handle, "rsContextDestroy"),
- .ContextDump = (ContextDumpFnPtr)dlsym(handle, "rsContextDump"),
- .ContextFinish = (ContextFinishFnPtr)dlsym(handle, "rsContextFinish"),
- .ContextGetMessage =
- (ContextGetMessageFnPtr)dlsym(handle, "rsContextGetMessage"),
- .ContextInitToClient =
- (ContextInitToClientFnPtr)dlsym(handle, "rsContextInitToClient"),
- .ContextPeekMessage =
- (ContextPeekMessageFnPtr)dlsym(handle, "rsContextPeekMessage"),
- .ContextSendMessage =
- (ContextSendMessageFnPtr)dlsym(handle, "rsContextSendMessage"),
- .ContextSetCacheDir =
- (ContextSetCacheDirFnPtr)dlsym(handle, "rsContextSetCacheDir"),
- .ContextSetPriority =
- (ContextSetPriorityFnPtr)dlsym(handle, "rsContextSetPriority"),
- .DeviceCreate = (DeviceCreateFnPtr) nullptr,
- .DeviceDestroy = (DeviceDestroyFnPtr) nullptr,
- .DeviceSetConfig = (DeviceSetConfigFnPtr) nullptr,
- .ElementCreate2 =
- (ElementCreate2FnPtr)dlsym(handle, "rsElementCreate2"),
- .ElementCreate = (ElementCreateFnPtr)dlsym(handle, "rsElementCreate"),
- .ElementGetNativeData =
- (ElementGetNativeDataFnPtr)dlsym(handle, "rsaElementGetNativeData"),
- .ElementGetSubElements = (ElementGetSubElementsFnPtr)dlsym(
- handle, "rsaElementGetSubElements"),
- .GetName = (GetNameFnPtr)dlsym(handle, "rsaGetName"),
- .InvokeClosureCreate =
- (InvokeClosureCreateFnPtr)dlsym(handle, "rsInvokeClosureCreate"),
- .ObjDestroy = (ObjDestroyFnPtr)dlsym(handle, "rsObjDestroy"),
- .SamplerCreate = (SamplerCreateFnPtr)dlsym(handle, "rsSamplerCreate"),
- .ScriptBindAllocation =
- (ScriptBindAllocationFnPtr)dlsym(handle, "rsScriptBindAllocation"),
- .ScriptCCreate = (ScriptCCreateFnPtr)dlsym(handle, "rsScriptCCreate"),
- .ScriptFieldIDCreate =
- (ScriptFieldIDCreateFnPtr)dlsym(handle, "rsScriptFieldIDCreate"),
- .ScriptForEach = (ScriptForEachFnPtr) nullptr,
- .ScriptForEachMulti =
- (ScriptForEachMultiFnPtr)dlsym(handle, "rsScriptForEachMulti"),
- .ScriptGetVarV = (ScriptGetVarVFnPtr)dlsym(handle, "rsScriptGetVarV"),
- .ScriptGroup2Create =
- (ScriptGroup2CreateFnPtr)dlsym(handle, "rsScriptGroup2Create"),
- .ScriptGroupCreate =
- (ScriptGroupCreateFnPtr)dlsym(handle, "rsScriptGroupCreate"),
- .ScriptGroupExecute =
- (ScriptGroupExecuteFnPtr)dlsym(handle, "rsScriptGroupExecute"),
- .ScriptGroupSetInput =
- (ScriptGroupSetInputFnPtr)dlsym(handle, "rsScriptGroupSetInput"),
- .ScriptGroupSetOutput =
- (ScriptGroupSetOutputFnPtr)dlsym(handle, "rsScriptGroupSetOutput"),
- .ScriptIntrinsicCreate = (ScriptIntrinsicCreateFnPtr)dlsym(
- handle, "rsScriptIntrinsicCreate"),
- .ScriptInvoke = (ScriptInvokeFnPtr)dlsym(handle, "rsScriptInvoke"),
- .ScriptInvokeIDCreate =
- (ScriptInvokeIDCreateFnPtr)dlsym(handle, "rsScriptInvokeIDCreate"),
- .ScriptInvokeV = (ScriptInvokeVFnPtr)dlsym(handle, "rsScriptInvokeV"),
- .ScriptKernelIDCreate =
- (ScriptKernelIDCreateFnPtr)dlsym(handle, "rsScriptKernelIDCreate"),
- .ScriptReduce = (ScriptReduceFnPtr)dlsym(handle, "rsScriptReduce"),
- .ScriptSetTimeZone =
- (ScriptSetTimeZoneFnPtr)dlsym(handle, "rsScriptSetTimeZone"),
- .ScriptSetVarD = (ScriptSetVarDFnPtr)dlsym(handle, "rsScriptSetVarD"),
- .ScriptSetVarF = (ScriptSetVarFFnPtr)dlsym(handle, "rsScriptSetVarF"),
- .ScriptSetVarI = (ScriptSetVarIFnPtr)dlsym(handle, "rsScriptSetVarI"),
- .ScriptSetVarJ = (ScriptSetVarJFnPtr)dlsym(handle, "rsScriptSetVarJ"),
- .ScriptSetVarObj =
- (ScriptSetVarObjFnPtr)dlsym(handle, "rsScriptSetVarObj"),
- .ScriptSetVarVE =
- (ScriptSetVarVEFnPtr)dlsym(handle, "rsScriptSetVarVE"),
- .ScriptSetVarV = (ScriptSetVarVFnPtr)dlsym(handle, "rsScriptSetVarV"),
- .TypeCreate = (TypeCreateFnPtr)dlsym(handle, "rsTypeCreate"),
- .TypeGetNativeData =
- (TypeGetNativeDataFnPtr)dlsym(handle, "rsaTypeGetNativeData"),
+ .Allocation1DData = (Allocation1DDataFnPtr)dlsym(handle, "rsAllocation1DData"),
+ .Allocation1DElementData = (Allocation1DElementDataFnPtr) nullptr,
+ .Allocation1DRead = (Allocation1DReadFnPtr)dlsym(handle, "rsAllocation1DRead"),
+ .Allocation2DData = (Allocation2DDataFnPtr)dlsym(handle, "rsAllocation2DData"),
+ .Allocation2DRead = (Allocation2DReadFnPtr)dlsym(handle, "rsAllocation2DRead"),
+ .Allocation3DData = (Allocation3DDataFnPtr)dlsym(handle, "rsAllocation3DData"),
+ .Allocation3DRead = (Allocation3DReadFnPtr)dlsym(handle, "rsAllocation3DRead"),
+ .AllocationAdapterCreate =
+ (AllocationAdapterCreateFnPtr)dlsym(handle, "rsAllocationAdapterCreate"),
+ .AllocationAdapterOffset =
+ (AllocationAdapterOffsetFnPtr)dlsym(handle, "rsAllocationAdapterOffset"),
+ .AllocationCopy2DRange =
+ (AllocationCopy2DRangeFnPtr)dlsym(handle, "rsAllocationCopy2DRange"),
+ .AllocationCopy3DRange =
+ (AllocationCopy3DRangeFnPtr)dlsym(handle, "rsAllocationCopy3DRange"),
+ .AllocationCopyToBitmap =
+ (AllocationCopyToBitmapFnPtr)dlsym(handle, "rsAllocationCopyToBitmap"),
+ .AllocationCreateFromBitmap =
+ (AllocationCreateFromBitmapFnPtr)dlsym(handle, "rsAllocationCreateFromBitmap"),
+ .AllocationCreateStrided =
+ (AllocationCreateStridedFnPtr)dlsym(handle, "rsAllocationCreateStrided"),
+ .AllocationCreateTyped =
+ (AllocationCreateTypedFnPtr)dlsym(handle, "rsAllocationCreateTyped"),
+ .AllocationCubeCreateFromBitmap = (AllocationCubeCreateFromBitmapFnPtr)dlsym(
+ handle, "rsAllocationCubeCreateFromBitmap"),
+ .AllocationElementData =
+ (AllocationElementDataFnPtr)dlsym(handle, "rsAllocationElementData"),
+ .AllocationElementRead =
+ (AllocationElementReadFnPtr)dlsym(handle, "rsAllocationElementRead"),
+ .AllocationGenerateMipmaps =
+ (AllocationGenerateMipmapsFnPtr)dlsym(handle, "rsAllocationGenerateMipmaps"),
+ .AllocationGetPointer =
+ (AllocationGetPointerFnPtr)dlsym(handle, "rsAllocationGetPointer"),
+ .AllocationGetSurface =
+ (AllocationGetSurfaceFnPtr)dlsym(handle, "rsAllocationGetSurface"),
+ .AllocationGetType = (AllocationGetTypeFnPtr)dlsym(handle, "rsaAllocationGetType"),
+ .AllocationIoReceive = (AllocationIoReceiveFnPtr)dlsym(handle, "rsAllocationIoReceive"),
+ .AllocationIoSend = (AllocationIoSendFnPtr)dlsym(handle, "rsAllocationIoSend"),
+ .AllocationRead = (AllocationReadFnPtr)dlsym(handle, "rsAllocationRead"),
+ .AllocationResize1D = (AllocationResize1DFnPtr)dlsym(handle, "rsAllocationResize1D"),
+ .AllocationSetSurface =
+ (AllocationSetSurfaceFnPtr)dlsym(handle, "rsAllocationSetSurface"),
+ .AllocationSyncAll = (AllocationSyncAllFnPtr)dlsym(handle, "rsAllocationSyncAll"),
+ .AllocationSetupBufferQueue =
+ (AllocationSetupBufferQueueFnPtr)dlsym(handle, "rsAllocationSetupBufferQueue"),
+ .AllocationShareBufferQueue =
+ (AllocationShareBufferQueueFnPtr)dlsym(handle, "rsAllocationShareBufferQueue"),
+ .AssignName = (AssignNameFnPtr)dlsym(handle, "rsAssignName"),
+ .ClosureCreate = (ClosureCreateFnPtr)dlsym(handle, "rsClosureCreate"),
+ .ClosureSetArg = (ClosureSetArgFnPtr)dlsym(handle, "rsClosureSetArg"),
+ .ClosureSetGlobal = (ClosureSetGlobalFnPtr)dlsym(handle, "rsClosureSetGlobal"),
+ .ContextCreateVendor = (ContextCreateVendorFnPtr)dlsym(handle, "rsContextCreateVendor"),
+ .ContextDeinitToClient =
+ (ContextDeinitToClientFnPtr)dlsym(handle, "rsContextDeinitToClient"),
+ .ContextDestroy = (ContextDestroyFnPtr)dlsym(handle, "rsContextDestroy"),
+ .ContextDump = (ContextDumpFnPtr)dlsym(handle, "rsContextDump"),
+ .ContextFinish = (ContextFinishFnPtr)dlsym(handle, "rsContextFinish"),
+ .ContextGetMessage = (ContextGetMessageFnPtr)dlsym(handle, "rsContextGetMessage"),
+ .ContextInitToClient = (ContextInitToClientFnPtr)dlsym(handle, "rsContextInitToClient"),
+ .ContextPeekMessage = (ContextPeekMessageFnPtr)dlsym(handle, "rsContextPeekMessage"),
+ .ContextSendMessage = (ContextSendMessageFnPtr)dlsym(handle, "rsContextSendMessage"),
+ .ContextSetPriority = (ContextSetPriorityFnPtr)dlsym(handle, "rsContextSetPriority"),
+ .ContextSetCacheDir = (ContextSetCacheDirFnPtr)dlsym(handle, "rsContextSetCacheDir"),
+ .DeviceCreate = (DeviceCreateFnPtr) nullptr,
+ .DeviceDestroy = (DeviceDestroyFnPtr) nullptr,
+ .DeviceSetConfig = (DeviceSetConfigFnPtr) nullptr,
+ .ElementCreate2 = (ElementCreate2FnPtr)dlsym(handle, "rsElementCreate2"),
+ .ElementCreate = (ElementCreateFnPtr)dlsym(handle, "rsElementCreate"),
+ .ElementGetNativeData =
+ (ElementGetNativeDataFnPtr)dlsym(handle, "rsaElementGetNativeData"),
+ .ElementGetSubElements =
+ (ElementGetSubElementsFnPtr)dlsym(handle, "rsaElementGetSubElements"),
+ .GetName = (GetNameFnPtr)dlsym(handle, "rsaGetName"),
+ .InvokeClosureCreate = (InvokeClosureCreateFnPtr)dlsym(handle, "rsInvokeClosureCreate"),
+ .ObjDestroy = (ObjDestroyFnPtr)dlsym(handle, "rsObjDestroy"),
+ .SamplerCreate = (SamplerCreateFnPtr)dlsym(handle, "rsSamplerCreate"),
+ .ScriptBindAllocation =
+ (ScriptBindAllocationFnPtr)dlsym(handle, "rsScriptBindAllocation"),
+ .ScriptCCreate = (ScriptCCreateFnPtr)dlsym(handle, "rsScriptCCreate"),
+ .ScriptFieldIDCreate = (ScriptFieldIDCreateFnPtr)dlsym(handle, "rsScriptFieldIDCreate"),
+ .ScriptForEach = (ScriptForEachFnPtr) nullptr,
+ .ScriptForEachMulti = (ScriptForEachMultiFnPtr)dlsym(handle, "rsScriptForEachMulti"),
+ .ScriptGetVarV = (ScriptGetVarVFnPtr)dlsym(handle, "rsScriptGetVarV"),
+ .ScriptGroup2Create = (ScriptGroup2CreateFnPtr)dlsym(handle, "rsScriptGroup2Create"),
+ .ScriptGroupCreate = (ScriptGroupCreateFnPtr)dlsym(handle, "rsScriptGroupCreate"),
+ .ScriptGroupExecute = (ScriptGroupExecuteFnPtr)dlsym(handle, "rsScriptGroupExecute"),
+ .ScriptGroupSetInput = (ScriptGroupSetInputFnPtr)dlsym(handle, "rsScriptGroupSetInput"),
+ .ScriptGroupSetOutput =
+ (ScriptGroupSetOutputFnPtr)dlsym(handle, "rsScriptGroupSetOutput"),
+ .ScriptIntrinsicCreate =
+ (ScriptIntrinsicCreateFnPtr)dlsym(handle, "rsScriptIntrinsicCreate"),
+ .ScriptInvoke = (ScriptInvokeFnPtr)dlsym(handle, "rsScriptInvoke"),
+ .ScriptInvokeIDCreate =
+ (ScriptInvokeIDCreateFnPtr)dlsym(handle, "rsScriptInvokeIDCreate"),
+ .ScriptInvokeV = (ScriptInvokeVFnPtr)dlsym(handle, "rsScriptInvokeV"),
+ .ScriptKernelIDCreate =
+ (ScriptKernelIDCreateFnPtr)dlsym(handle, "rsScriptKernelIDCreate"),
+ .ScriptReduce = (ScriptReduceFnPtr)dlsym(handle, "rsScriptReduce"),
+ .ScriptSetTimeZone = (ScriptSetTimeZoneFnPtr)dlsym(handle, "rsScriptSetTimeZone"),
+ .ScriptSetVarD = (ScriptSetVarDFnPtr)dlsym(handle, "rsScriptSetVarD"),
+ .ScriptSetVarF = (ScriptSetVarFFnPtr)dlsym(handle, "rsScriptSetVarF"),
+ .ScriptSetVarI = (ScriptSetVarIFnPtr)dlsym(handle, "rsScriptSetVarI"),
+ .ScriptSetVarJ = (ScriptSetVarJFnPtr)dlsym(handle, "rsScriptSetVarJ"),
+ .ScriptSetVarObj = (ScriptSetVarObjFnPtr)dlsym(handle, "rsScriptSetVarObj"),
+ .ScriptSetVarVE = (ScriptSetVarVEFnPtr)dlsym(handle, "rsScriptSetVarVE"),
+ .ScriptSetVarV = (ScriptSetVarVFnPtr)dlsym(handle, "rsScriptSetVarV"),
+ .TypeCreate = (TypeCreateFnPtr)dlsym(handle, "rsTypeCreate"),
+ .TypeGetNativeData = (TypeGetNativeDataFnPtr)dlsym(handle, "rsaTypeGetNativeData"),
};
return dispatchHal;
diff --git a/sensors/2.0/multihal/Android.bp b/sensors/2.0/multihal/Android.bp
index 710835f..5c67676 100644
--- a/sensors/2.0/multihal/Android.bp
+++ b/sensors/2.0/multihal/Android.bp
@@ -28,6 +28,7 @@
"libpower",
"libutils",
],
+ cflags: ["-DLOG_TAG=\"SensorsMultiHal\""],
}
cc_binary {
@@ -45,7 +46,6 @@
],
init_rc: ["android.hardware.sensors@2.0-service-multihal.rc"],
vintf_fragments: ["android.hardware.sensors@2.0-multihal.xml"],
- cflags: ["-DLOG_TAG=\"SensorsMultiHal\""],
}
cc_library_headers {
@@ -66,4 +66,7 @@
export_header_lib_headers: [
"android.hardware.sensors@2.0-multihal.header",
],
+ shared_libs: [
+ "libutils",
+ ],
}
diff --git a/sensors/2.0/multihal/HalProxy.cpp b/sensors/2.0/multihal/HalProxy.cpp
index 1fbc787..d667218 100644
--- a/sensors/2.0/multihal/HalProxy.cpp
+++ b/sensors/2.0/multihal/HalProxy.cpp
@@ -24,6 +24,7 @@
#include <dlfcn.h>
+#include <cinttypes>
#include <fstream>
#include <functional>
#include <thread>
@@ -35,29 +36,44 @@
namespace implementation {
using ::android::hardware::sensors::V2_0::EventQueueFlagBits;
+using ::android::hardware::sensors::V2_0::WakeLockQueueFlagBits;
+using ::android::hardware::sensors::V2_0::implementation::getTimeNow;
+using ::android::hardware::sensors::V2_0::implementation::kWakelockTimeoutNs;
typedef ISensorsSubHal*(SensorsHalGetSubHalFunc)(uint32_t*);
+/**
+ * Set the subhal index as first byte of sensor handle and return this modified version.
+ *
+ * @param sensorHandle The sensor handle to modify.
+ * @param subHalIndex The index in the hal proxy of the sub hal this sensor belongs to.
+ *
+ * @return The modified sensor handle.
+ */
+uint32_t setSubHalIndex(uint32_t sensorHandle, size_t subHalIndex) {
+ return sensorHandle | (subHalIndex << 24);
+}
+
HalProxy::HalProxy() {
const char* kMultiHalConfigFile = "/vendor/etc/sensors/hals.conf";
initializeSubHalListFromConfigFile(kMultiHalConfigFile);
- initializeSubHalCallbacksAndSensorList();
+ init();
}
HalProxy::HalProxy(std::vector<ISensorsSubHal*>& subHalList) : mSubHalList(subHalList) {
- initializeSubHalCallbacksAndSensorList();
+ init();
}
HalProxy::~HalProxy() {
- {
- std::lock_guard<std::mutex> lockGuard(mEventQueueWriteMutex);
- mPendingWritesRun = false;
- mEventQueueWriteCV.notify_one();
- }
+ mThreadsRun.store(false);
+ mWakelockCV.notify_one();
+ mEventQueueWriteCV.notify_one();
if (mPendingWritesThread.joinable()) {
mPendingWritesThread.join();
}
- // TODO: Cleanup wakeup thread once it is implemented
+ if (mWakelockThread.joinable()) {
+ mWakelockThread.join();
+ }
}
Return<void> HalProxy::getSensorsList(getSensorsList_cb _hidl_cb) {
@@ -128,7 +144,7 @@
}
mPendingWritesThread = std::thread(startPendingWritesThread, this);
- // TODO: start threads to read wake locks.
+ mWakelockThread = std::thread(startWakelockThread, this);
for (size_t i = 0; i < mSubHalList.size(); i++) {
auto subHal = mSubHalList[i];
@@ -206,15 +222,45 @@
return Return<void>();
}
-Return<void> HalProxy::onDynamicSensorsConnected(
- const hidl_vec<SensorInfo>& /* dynamicSensorsAdded */, int32_t /* subHalIndex */) {
- // TODO: Map the SensorInfo to the global list and then invoke the framework's callback.
+Return<void> HalProxy::onDynamicSensorsConnected(const hidl_vec<SensorInfo>& dynamicSensorsAdded,
+ int32_t subHalIndex) {
+ std::vector<SensorInfo> sensors;
+ {
+ std::lock_guard<std::mutex> lock(mDynamicSensorsMutex);
+ for (SensorInfo sensor : dynamicSensorsAdded) {
+ if (!subHalIndexIsClear(sensor.sensorHandle)) {
+ ALOGE("Dynamic sensor added %s had sensorHandle with first byte not 0.",
+ sensor.name.c_str());
+ } else {
+ sensor.sensorHandle = setSubHalIndex(sensor.sensorHandle, subHalIndex);
+ mDynamicSensors[sensor.sensorHandle] = sensor;
+ sensors.push_back(sensor);
+ }
+ }
+ }
+ mDynamicSensorsCallback->onDynamicSensorsConnected(sensors);
return Return<void>();
}
Return<void> HalProxy::onDynamicSensorsDisconnected(
- const hidl_vec<int32_t>& /* dynamicSensorHandlesRemoved */, int32_t /* subHalIndex */) {
- // TODO: Unmap the SensorInfo from the global list and then invoke the framework's callback.
+ const hidl_vec<int32_t>& dynamicSensorHandlesRemoved, int32_t subHalIndex) {
+ // TODO: Block this call until all pending events are flushed from queue
+ std::vector<int32_t> sensorHandles;
+ {
+ std::lock_guard<std::mutex> lock(mDynamicSensorsMutex);
+ for (int32_t sensorHandle : dynamicSensorHandlesRemoved) {
+ if (!subHalIndexIsClear(sensorHandle)) {
+ ALOGE("Dynamic sensorHandle removed had first byte not 0.");
+ } else {
+ sensorHandle = setSubHalIndex(sensorHandle, subHalIndex);
+ if (mDynamicSensors.find(sensorHandle) != mDynamicSensors.end()) {
+ mDynamicSensors.erase(sensorHandle);
+ sensorHandles.push_back(sensorHandle);
+ }
+ }
+ }
+ }
+ mDynamicSensorsCallback->onDynamicSensorsDisconnected(sensorHandles);
return Return<void>();
}
@@ -264,7 +310,7 @@
ISensorsSubHal* subHal = mSubHalList[subHalIndex];
auto result = subHal->getSensorsList([&](const auto& list) {
for (SensorInfo sensor : list) {
- if ((sensor.sensorHandle & kSensorHandleSubHalIndexMask) != 0) {
+ if (!subHalIndexIsClear(sensor.sensorHandle)) {
ALOGE("SubHal sensorHandle's first byte was not 0");
} else {
ALOGV("Loaded sensor: %s", sensor.name.c_str());
@@ -280,7 +326,7 @@
}
}
-void HalProxy::initializeSubHalCallbacksAndSensorList() {
+void HalProxy::init() {
initializeSubHalCallbacks();
initializeSensorList();
}
@@ -292,11 +338,12 @@
void HalProxy::handlePendingWrites() {
// TODO: Find a way to optimize locking strategy maybe using two mutexes instead of one.
std::unique_lock<std::mutex> lock(mEventQueueWriteMutex);
- while (mPendingWritesRun) {
+ while (mThreadsRun.load()) {
mEventQueueWriteCV.wait(
- lock, [&] { return !mPendingWriteEventsQueue.empty() || !mPendingWritesRun; });
- if (!mPendingWriteEventsQueue.empty() && mPendingWritesRun) {
- std::vector<Event>& pendingWriteEvents = mPendingWriteEventsQueue.front();
+ lock, [&] { return !mPendingWriteEventsQueue.empty() || !mThreadsRun.load(); });
+ if (mThreadsRun.load()) {
+ std::vector<Event>& pendingWriteEvents = mPendingWriteEventsQueue.front().first;
+ size_t numWakeupEvents = mPendingWriteEventsQueue.front().second;
size_t eventQueueSize = mEventQueue->getQuantumCount();
size_t numToWrite = std::min(pendingWriteEvents.size(), eventQueueSize);
lock.unlock();
@@ -306,10 +353,16 @@
pendingWriteEvents.data(), numToWrite,
static_cast<uint32_t>(EventQueueFlagBits::EVENTS_READ),
static_cast<uint32_t>(EventQueueFlagBits::READ_AND_PROCESS),
- kWakelockTimeoutNs, mEventQueueFlag)) {
+ kPendingWriteTimeoutNs, mEventQueueFlag)) {
ALOGE("Dropping %zu events after blockingWrite failed.", numToWrite);
- } else {
- mEventQueueFlag->wake(static_cast<uint32_t>(EventQueueFlagBits::READ_AND_PROCESS));
+ if (numWakeupEvents > 0) {
+ if (pendingWriteEvents.size() > eventQueueSize) {
+ decrementRefCountAndMaybeReleaseWakelock(
+ countNumWakeupEvents(pendingWriteEvents, eventQueueSize));
+ } else {
+ decrementRefCountAndMaybeReleaseWakelock(numWakeupEvents);
+ }
+ }
}
lock.lock();
if (pendingWriteEvents.size() > eventQueueSize) {
@@ -324,9 +377,60 @@
}
}
-void HalProxy::postEventsToMessageQueue(const std::vector<Event>& events) {
+void HalProxy::startWakelockThread(HalProxy* halProxy) {
+ halProxy->handleWakelocks();
+}
+
+void HalProxy::handleWakelocks() {
+ std::unique_lock<std::recursive_mutex> lock(mWakelockMutex);
+ while (mThreadsRun.load()) {
+ mWakelockCV.wait(lock, [&] { return mWakelockRefCount > 0 || !mThreadsRun.load(); });
+ if (mThreadsRun.load()) {
+ int64_t timeLeft;
+ if (sharedWakelockDidTimeout(&timeLeft)) {
+ resetSharedWakelock();
+ } else {
+ uint32_t numWakeLocksProcessed;
+ lock.unlock();
+ bool success = mWakeLockQueue->readBlocking(
+ &numWakeLocksProcessed, 1, 0,
+ static_cast<uint32_t>(WakeLockQueueFlagBits::DATA_WRITTEN), timeLeft);
+ lock.lock();
+ if (success) {
+ decrementRefCountAndMaybeReleaseWakelock(
+ static_cast<size_t>(numWakeLocksProcessed));
+ }
+ }
+ }
+ }
+ resetSharedWakelock();
+}
+
+bool HalProxy::sharedWakelockDidTimeout(int64_t* timeLeft) {
+ bool didTimeout;
+ int64_t duration = getTimeNow() - mWakelockTimeoutStartTime;
+ if (duration > kWakelockTimeoutNs) {
+ didTimeout = true;
+ } else {
+ didTimeout = false;
+ *timeLeft = kWakelockTimeoutNs - duration;
+ }
+ return didTimeout;
+}
+
+void HalProxy::resetSharedWakelock() {
+ std::lock_guard<std::recursive_mutex> lockGuard(mWakelockMutex);
+ decrementRefCountAndMaybeReleaseWakelock(mWakelockRefCount);
+ mWakelockTimeoutResetTime = getTimeNow();
+}
+
+void HalProxy::postEventsToMessageQueue(const std::vector<Event>& events, size_t numWakeupEvents,
+ ScopedWakelock wakelock) {
size_t numToWrite = 0;
std::lock_guard<std::mutex> lock(mEventQueueWriteMutex);
+ if (wakelock.isLocked()) {
+ incrementRefCountAndMaybeAcquireWakelock(numWakeupEvents);
+ }
if (mPendingWriteEventsQueue.empty()) {
numToWrite = std::min(events.size(), mEventQueue->availableToWrite());
if (numToWrite > 0) {
@@ -342,28 +446,37 @@
if (numToWrite < events.size()) {
// TODO: Bound the mPendingWriteEventsQueue so that we do not trigger OOMs if framework
// stalls
- mPendingWriteEventsQueue.push(
- std::vector<Event>(events.begin() + numToWrite, events.end()));
+ std::vector<Event> eventsLeft(events.begin() + numToWrite, events.end());
+ mPendingWriteEventsQueue.push({eventsLeft, numWakeupEvents});
mEventQueueWriteCV.notify_one();
}
}
-// TODO: Implement the wakelock timeout in these next two methods. Also pass in the subhal
-// index for better tracking.
-
-void HalProxy::incrementRefCountAndMaybeAcquireWakelock() {
- std::lock_guard<std::mutex> lockGuard(mWakelockRefCountMutex);
+bool HalProxy::incrementRefCountAndMaybeAcquireWakelock(size_t delta,
+ int64_t* timeoutStart /* = nullptr */) {
+ if (!mThreadsRun.load()) return false;
+ std::lock_guard<std::recursive_mutex> lockGuard(mWakelockMutex);
if (mWakelockRefCount == 0) {
- acquire_wake_lock(PARTIAL_WAKE_LOCK, kWakeLockName);
+ acquire_wake_lock(PARTIAL_WAKE_LOCK, kWakelockName);
+ mWakelockCV.notify_one();
}
- mWakelockRefCount++;
+ mWakelockTimeoutStartTime = getTimeNow();
+ mWakelockRefCount += delta;
+ if (timeoutStart != nullptr) {
+ *timeoutStart = mWakelockTimeoutStartTime;
+ }
+ return true;
}
-void HalProxy::decrementRefCountAndMaybeReleaseWakelock() {
- std::lock_guard<std::mutex> lockGuard(mWakelockRefCountMutex);
- mWakelockRefCount--;
+void HalProxy::decrementRefCountAndMaybeReleaseWakelock(size_t delta,
+ int64_t timeoutStart /* = -1 */) {
+ if (!mThreadsRun.load()) return;
+ std::lock_guard<std::recursive_mutex> lockGuard(mWakelockMutex);
+ if (timeoutStart == -1) timeoutStart = mWakelockTimeoutResetTime;
+ if (mWakelockRefCount == 0 || timeoutStart < mWakelockTimeoutResetTime) return;
+ mWakelockRefCount -= std::min(mWakelockRefCount, delta);
if (mWakelockRefCount == 0) {
- release_wake_lock(kWakeLockName);
+ release_wake_lock(kWakelockName);
}
}
@@ -385,12 +498,27 @@
return mSubHalList[static_cast<size_t>(sensorHandle >> 24)];
}
+size_t HalProxy::countNumWakeupEvents(const std::vector<Event>& events, size_t n) {
+ size_t numWakeupEvents = 0;
+ for (size_t i = 0; i < n; i++) {
+ int32_t sensorHandle = events[i].sensorHandle;
+ if (mSensors[sensorHandle].flags & static_cast<uint32_t>(V1_0::SensorFlagBits::WAKE_UP)) {
+ numWakeupEvents++;
+ }
+ }
+ return numWakeupEvents;
+}
+
uint32_t HalProxy::clearSubHalIndex(uint32_t sensorHandle) {
return sensorHandle & (~kSensorHandleSubHalIndexMask);
}
+bool HalProxy::subHalIndexIsClear(uint32_t sensorHandle) {
+ return (sensorHandle & kSensorHandleSubHalIndexMask) == 0;
+}
+
void HalProxyCallback::postEvents(const std::vector<Event>& events, ScopedWakelock wakelock) {
- (void)wakelock;
+ if (events.empty() || !mHalProxy->areThreadsRunning()) return;
size_t numWakeupEvents;
std::vector<Event> processedEvents = processEvents(events, &numWakeupEvents);
if (numWakeupEvents > 0) {
@@ -404,8 +532,7 @@
" w/ index %zu.",
mSubHalIndex);
}
-
- mHalProxy->postEventsToMessageQueue(processedEvents);
+ mHalProxy->postEventsToMessageQueue(events, numWakeupEvents, std::move(wakelock));
}
ScopedWakelock HalProxyCallback::createScopedWakelock(bool lock) {
@@ -415,23 +542,19 @@
std::vector<Event> HalProxyCallback::processEvents(const std::vector<Event>& events,
size_t* numWakeupEvents) const {
- std::vector<Event> eventsOut;
*numWakeupEvents = 0;
+ std::vector<Event> eventsOut;
for (Event event : events) {
- event.sensorHandle = setSubHalIndex(event.sensorHandle);
+ event.sensorHandle = setSubHalIndex(event.sensorHandle, mSubHalIndex);
eventsOut.push_back(event);
- if ((mHalProxy->getSensorInfo(event.sensorHandle).flags & V1_0::SensorFlagBits::WAKE_UP) !=
- 0) {
+ const SensorInfo& sensor = mHalProxy->getSensorInfo(event.sensorHandle);
+ if ((sensor.flags & V1_0::SensorFlagBits::WAKE_UP) != 0) {
(*numWakeupEvents)++;
}
}
return eventsOut;
}
-uint32_t HalProxyCallback::setSubHalIndex(uint32_t sensorHandle) const {
- return sensorHandle | mSubHalIndex << 24;
-}
-
} // namespace implementation
} // namespace V2_0
} // namespace sensors
diff --git a/sensors/2.0/multihal/ScopedWakelock.cpp b/sensors/2.0/multihal/ScopedWakelock.cpp
index 0430fa3..d85d4a7 100644
--- a/sensors/2.0/multihal/ScopedWakelock.cpp
+++ b/sensors/2.0/multihal/ScopedWakelock.cpp
@@ -22,18 +22,22 @@
namespace V2_0 {
namespace implementation {
+int64_t getTimeNow() {
+ return std::chrono::duration_cast<std::chrono::nanoseconds>(
+ std::chrono::system_clock::now().time_since_epoch())
+ .count();
+}
+
ScopedWakelock::ScopedWakelock(IScopedWakelockRefCounter* refCounter, bool locked)
: mRefCounter(refCounter), mLocked(locked) {
- // TODO: Move this implementation into HalProxy object instead
if (mLocked) {
- mRefCounter->incrementRefCountAndMaybeAcquireWakelock();
+ mLocked = mRefCounter->incrementRefCountAndMaybeAcquireWakelock(1, &mCreatedAtTimeNs);
}
}
ScopedWakelock::~ScopedWakelock() {
- // TODO: Move this implementation into HalProxy object instead
if (mLocked) {
- mRefCounter->decrementRefCountAndMaybeReleaseWakelock();
+ mRefCounter->decrementRefCountAndMaybeReleaseWakelock(1, mCreatedAtTimeNs);
}
}
diff --git a/sensors/2.0/multihal/android.hardware.sensors@2.0-service-multihal.rc b/sensors/2.0/multihal/android.hardware.sensors@2.0-service-multihal.rc
index 1671689..a4da3b0 100644
--- a/sensors/2.0/multihal/android.hardware.sensors@2.0-service-multihal.rc
+++ b/sensors/2.0/multihal/android.hardware.sensors@2.0-service-multihal.rc
@@ -1,6 +1,7 @@
service vendor.sensors-hal-2-0-multihal /vendor/bin/hw/android.hardware.sensors@2.0-service.multihal
class hal
user system
- group system
+ group system wakelock
+ writepid /dev/cpuset/system-background/tasks
capabilities BLOCK_SUSPEND
rlimit rtprio 10 10
diff --git a/sensors/2.0/multihal/include/HalProxy.h b/sensors/2.0/multihal/include/HalProxy.h
index ae4b2c5..6592afe 100644
--- a/sensors/2.0/multihal/include/HalProxy.h
+++ b/sensors/2.0/multihal/include/HalProxy.h
@@ -16,9 +16,11 @@
#pragma once
+#include "ScopedWakelock.h"
#include "SubHal.h"
#include <android/hardware/sensors/2.0/ISensors.h>
+#include <android/hardware/sensors/2.0/types.h>
#include <fmq/MessageQueue.h>
#include <hardware_legacy/power.h>
#include <hidl/MQDescriptor.h>
@@ -30,6 +32,7 @@
#include <mutex>
#include <queue>
#include <thread>
+#include <utility>
namespace android {
namespace hardware {
@@ -100,45 +103,41 @@
Return<void> onDynamicSensorsDisconnected(const hidl_vec<int32_t>& dynamicSensorHandlesRemoved,
int32_t subHalIndex);
- // Below methods follow IScopedWakelockRefCounter
-
- /**
- * Increment ref count and maybe acquire wakelock.
- */
- void incrementRefCountAndMaybeAcquireWakelock() override;
-
- /**
- * Decrement ref count and maybe release wakelock.
- */
- void decrementRefCountAndMaybeReleaseWakelock() override;
-
// Below methods are for HalProxyCallback
/**
* Post events to the event message queue if there is room to write them. Otherwise post the
- * remaining events to a background thread for a blocking write with a 5 second timeout.
+ * remaining events to a background thread for a blocking write with a kPendingWriteTimeoutNs
+ * timeout.
*
* @param events The list of events to post to the message queue.
+ * @param numWakeupEvents The number of wakeup events in events.
+ * @param wakelock The wakelock associated with this post of events.
*/
- void postEventsToMessageQueue(const std::vector<Event>& events);
+ void postEventsToMessageQueue(const std::vector<Event>& events, size_t numWakeupEvents,
+ ScopedWakelock wakelock);
/**
- * Get the SensorInfo object associated with the sensorHandle.
+ * Get the sensor info associated with that sensorHandle.
*
- * @param sensorHandle The sensorHandle for the sensor.
+ * @param sensorHandle The sensor handle.
*
- * @return The sensor info for the sensor.
+ * @return The sensor info object in the mapping.
*/
- const SensorInfo& getSensorInfo(uint32_t sensorHandle) const {
- return mSensors.at(sensorHandle);
- }
+ const SensorInfo& getSensorInfo(uint32_t sensorHandle) { return mSensors[sensorHandle]; }
+
+ bool areThreadsRunning() { return mThreadsRun.load(); }
+
+ // Below methods are from IScopedWakelockRefCounter interface
+ bool incrementRefCountAndMaybeAcquireWakelock(size_t delta,
+ int64_t* timeoutStart = nullptr) override;
+
+ void decrementRefCountAndMaybeReleaseWakelock(size_t delta, int64_t timeoutStart = -1) override;
private:
using EventMessageQueue = MessageQueue<Event, kSynchronizedReadWrite>;
using WakeLockMessageQueue = MessageQueue<uint32_t, kSynchronizedReadWrite>;
- const char* kWakeLockName = "SensorsHAL_WAKEUP";
-
/**
* The Event FMQ where sensor events are written
*/
@@ -176,29 +175,26 @@
*/
std::map<uint32_t, SensorInfo> mSensors;
+ //! Map of the dynamic sensors that have been added to halproxy.
+ std::map<uint32_t, SensorInfo> mDynamicSensors;
+
//! The current operation mode for all subhals.
OperationMode mCurrentOperationMode = OperationMode::NORMAL;
//! The single subHal that supports directChannel reporting.
ISensorsSubHal* mDirectChannelSubHal = nullptr;
- //! The mutex for the event queue.
- std::mutex mEventQueueMutex;
-
//! The timeout for each pending write on background thread for events.
- static const int64_t kWakelockTimeoutNs = 5 * INT64_C(1000000000) /* 5 seconds */;
-
- //! The scoped wakelock ref count.
- size_t mWakelockRefCount = 0;
-
- //! The mutex guarding the mWakelockRefCount variable
- std::mutex mWakelockRefCountMutex;
+ static const int64_t kPendingWriteTimeoutNs = 5 * INT64_C(1000000000) /* 5 seconds */;
//! The bit mask used to get the subhal index from a sensor handle.
static constexpr uint32_t kSensorHandleSubHalIndexMask = 0xFF000000;
- //! The events that were not able to be written to fmq right away
- std::queue<std::vector<Event>> mPendingWriteEventsQueue;
+ /**
+ * A FIFO queue of pairs of vector of events and the number of wakeup events in that vector
+ * which are waiting to be written to the events fmq in the background thread.
+ */
+ std::queue<std::pair<std::vector<Event>, size_t>> mPendingWriteEventsQueue;
//! The mutex protecting writing to the fmq and the pending events queue
std::mutex mEventQueueWriteMutex;
@@ -209,8 +205,31 @@
//! The thread object ptr that handles pending writes
std::thread mPendingWritesThread;
- //! The bool indicating whether to end the pending writes background thread or not
- bool mPendingWritesRun = true;
+ //! The thread object that handles wakelocks
+ std::thread mWakelockThread;
+
+ //! The bool indicating whether to end the threads started in initialize
+ std::atomic_bool mThreadsRun = true;
+
+ //! The mutex protecting access to the dynamic sensors added and removed methods.
+ std::mutex mDynamicSensorsMutex;
+
+ // WakelockRefCount membar vars below
+
+ //! The mutex protecting the wakelock refcount and subsequent wakelock releases and
+ //! acquisitions
+ std::recursive_mutex mWakelockMutex;
+
+ std::condition_variable_any mWakelockCV;
+
+ //! The refcount of how many ScopedWakelocks and pending wakeup events are active
+ size_t mWakelockRefCount = 0;
+
+ int64_t mWakelockTimeoutStartTime = getTimeNow();
+
+ int64_t mWakelockTimeoutResetTime = getTimeNow();
+
+ const char* kWakelockName = "SensorsMultiHal";
/**
* Initialize the list of SubHal objects in mSubHalList by reading from dynamic libraries
@@ -230,9 +249,9 @@
void initializeSensorList();
/**
- * Calls the above two helper methods which are shared in both ctors.
+ * Calls the helper methods that all ctors use.
*/
- void initializeSubHalCallbacksAndSensorList();
+ void init();
/**
* Starts the thread that handles pending writes to event fmq.
@@ -245,6 +264,31 @@
void handlePendingWrites();
/**
+ * Starts the thread that handles decrementing the ref count on wakeup events processed by the
+ * framework and timing out wakelocks.
+ *
+ * @param halProxy The HalProxy object pointer.
+ */
+ static void startWakelockThread(HalProxy* halProxy);
+
+ //! Handles the wakelocks.
+ void handleWakelocks();
+
+ /**
+ * @param timeLeft The variable that should be set to the timeleft before timeout will occur or
+ * unmodified if timeout occurred.
+ *
+ * @return true if the shared wakelock has been held passed the timeout and should be released
+ */
+ bool sharedWakelockDidTimeout(int64_t* timeLeft);
+
+ /**
+ * Reset all the member variables associated with the wakelock ref count and maybe release
+ * the shared wakelock.
+ */
+ void resetSharedWakelock();
+
+ /**
* Clear direct channel flags if the HalProxy has already chosen a subhal as its direct channel
* subhal. Set the directChannelSubHal pointer to the subHal passed in if this is the first
* direct channel enabled sensor seen.
@@ -263,6 +307,16 @@
*/
ISensorsSubHal* getSubHalForSensorHandle(uint32_t sensorHandle);
+ /**
+ * Count the number of wakeup events in the first n events of the vector.
+ *
+ * @param events The vector of Event objects.
+ * @param n The end index not inclusive of events to consider.
+ *
+ * @return The number of wakeup events of the considered events.
+ */
+ size_t countNumWakeupEvents(const std::vector<Event>& events, size_t n);
+
/*
* Clear out the subhal index bytes from a sensorHandle.
*
@@ -271,6 +325,13 @@
* @return The modified version of the sensor handle.
*/
static uint32_t clearSubHalIndex(uint32_t sensorHandle);
+
+ /**
+ * @param sensorHandle The sensor handle to modify.
+ *
+ * @return true if subHalIndex byte of sensorHandle is zeroed.
+ */
+ static bool subHalIndexIsClear(uint32_t sensorHandle);
};
/**
@@ -303,8 +364,6 @@
std::vector<Event> processEvents(const std::vector<Event>& events,
size_t* numWakeupEvents) const;
-
- uint32_t setSubHalIndex(uint32_t sensorHandle) const;
};
} // namespace implementation
diff --git a/sensors/2.0/multihal/include/ScopedWakelock.h b/sensors/2.0/multihal/include/ScopedWakelock.h
index a151f15..aa6d9db 100644
--- a/sensors/2.0/multihal/include/ScopedWakelock.h
+++ b/sensors/2.0/multihal/include/ScopedWakelock.h
@@ -16,7 +16,7 @@
#pragma once
-#include <mutex>
+#include <android/hardware/sensors/2.0/types.h>
namespace android {
namespace hardware {
@@ -24,10 +24,36 @@
namespace V2_0 {
namespace implementation {
-class IScopedWakelockRefCounter {
+using ::android::hardware::sensors::V2_0::SensorTimeout;
+
+const int64_t kWakelockTimeoutNs =
+ static_cast<int64_t>(SensorTimeout::WAKE_LOCK_SECONDS) * INT64_C(1000000000);
+
+int64_t getTimeNow();
+
+class IScopedWakelockRefCounter : public RefBase {
public:
- virtual void incrementRefCountAndMaybeAcquireWakelock() = 0;
- virtual void decrementRefCountAndMaybeReleaseWakelock() = 0;
+ /**
+ * Increment the wakelock ref count and maybe acquire the shared wakelock if incrementing
+ * from 0 then return the time of incrementing back to caller.
+ *
+ * @param delta The amount to change ref count by.
+ * @param timeoutStart The ptr to the timestamp in ns that the increment occurred which will be
+ * set in the function or nullptr if not specified.
+ *
+ * @return true if successfully incremented the wakelock ref count.
+ */
+ virtual bool incrementRefCountAndMaybeAcquireWakelock(size_t delta,
+ int64_t* timeoutStart = nullptr) = 0;
+ /**
+ * Decrement the wakelock ref count and maybe release wakelock if ref count ends up 0.
+ *
+ * @param delta The amount to change ref count by.
+ * @param timeoutStart The timestamp in ns that the calling context kept track of when
+ * incrementing the ref count or -1 by default
+ */
+ virtual void decrementRefCountAndMaybeReleaseWakelock(size_t delta,
+ int64_t timeoutStart = -1) = 0;
// Virtual dtor needed for compilation success
virtual ~IScopedWakelockRefCounter(){};
};
@@ -64,6 +90,7 @@
private:
friend class HalProxyCallback;
IScopedWakelockRefCounter* mRefCounter;
+ int64_t mCreatedAtTimeNs;
bool mLocked;
ScopedWakelock(IScopedWakelockRefCounter* refCounter, bool locked);
ScopedWakelock(const ScopedWakelock&) = delete;
diff --git a/sensors/2.0/multihal/tests/Android.bp b/sensors/2.0/multihal/tests/Android.bp
index aa44687..e3a4af1 100644
--- a/sensors/2.0/multihal/tests/Android.bp
+++ b/sensors/2.0/multihal/tests/Android.bp
@@ -35,6 +35,9 @@
static_libs: [
"android.hardware.sensors@2.0-HalProxy",
],
+ cflags: [
+ "-DLOG_TAG=\"FakeSubHal\""
+ ],
}
cc_library {
@@ -87,4 +90,7 @@
"libutils",
],
test_suites: ["device-tests"],
+ cflags: [
+ "-DLOG_TAG=\"HalProxyUnitTests\"",
+ ],
}
diff --git a/sensors/2.0/multihal/tests/HalProxy_test.cpp b/sensors/2.0/multihal/tests/HalProxy_test.cpp
index 61fb14c..fa527c9 100644
--- a/sensors/2.0/multihal/tests/HalProxy_test.cpp
+++ b/sensors/2.0/multihal/tests/HalProxy_test.cpp
@@ -23,11 +23,13 @@
#include "SensorsSubHal.h"
#include <chrono>
+#include <set>
#include <thread>
#include <vector>
namespace {
+using ::android::hardware::EventFlag;
using ::android::hardware::hidl_vec;
using ::android::hardware::MessageQueue;
using ::android::hardware::Return;
@@ -35,9 +37,12 @@
using ::android::hardware::sensors::V1_0::SensorFlagBits;
using ::android::hardware::sensors::V1_0::SensorInfo;
using ::android::hardware::sensors::V1_0::SensorType;
+using ::android::hardware::sensors::V2_0::EventQueueFlagBits;
using ::android::hardware::sensors::V2_0::ISensorsCallback;
+using ::android::hardware::sensors::V2_0::WakeLockQueueFlagBits;
using ::android::hardware::sensors::V2_0::implementation::HalProxy;
using ::android::hardware::sensors::V2_0::implementation::HalProxyCallback;
+using ::android::hardware::sensors::V2_0::subhal::implementation::AddAndRemoveDynamicSensorsSubHal;
using ::android::hardware::sensors::V2_0::subhal::implementation::AllSensorsSubHal;
using ::android::hardware::sensors::V2_0::subhal::implementation::
AllSupportDirectChannelSensorsSubHal;
@@ -68,6 +73,34 @@
}
};
+// The sensors callback that expects a variable list of sensors to be added
+class TestSensorsCallback : public ISensorsCallback {
+ public:
+ Return<void> onDynamicSensorsConnected(
+ const hidl_vec<SensorInfo>& dynamicSensorsAdded) override {
+ mSensorsConnected.insert(mSensorsConnected.end(), dynamicSensorsAdded.begin(),
+ dynamicSensorsAdded.end());
+ return Return<void>();
+ }
+
+ Return<void> onDynamicSensorsDisconnected(
+ const hidl_vec<int32_t>& dynamicSensorHandlesRemoved) override {
+ mSensorHandlesDisconnected.insert(mSensorHandlesDisconnected.end(),
+ dynamicSensorHandlesRemoved.begin(),
+ dynamicSensorHandlesRemoved.end());
+ return Return<void>();
+ }
+
+ const std::vector<SensorInfo>& getSensorsConnected() const { return mSensorsConnected; }
+ const std::vector<int32_t>& getSensorHandlesDisconnected() const {
+ return mSensorHandlesDisconnected;
+ }
+
+ private:
+ std::vector<SensorInfo> mSensorsConnected;
+ std::vector<int32_t> mSensorHandlesDisconnected;
+};
+
// Helper declarations follow
/**
@@ -93,6 +126,16 @@
void testSensorsListForOneDirectChannelEnabledSubHal(const std::vector<SensorInfo>& sensorsList,
size_t enabledSubHalIndex);
+void ackWakeupEventsToHalProxy(size_t numEvents, std::unique_ptr<WakeupMessageQueue>& wakelockQueue,
+ EventFlag* wakelockQueueFlag);
+
+bool readEventsOutOfQueue(size_t numEvents, std::unique_ptr<EventMessageQueue>& eventQueue,
+ EventFlag* eventQueueFlag);
+
+std::unique_ptr<EventMessageQueue> makeEventFMQ(size_t size);
+
+std::unique_ptr<WakeupMessageQueue> makeWakelockFMQ(size_t size);
+
/**
* Construct and return a HIDL Event type thats sensorHandle refers to a proximity sensor
* which is a wakeup type sensor.
@@ -129,6 +172,20 @@
*/
std::vector<Event> makeMultipleAccelerometerEvents(size_t numEvents);
+/**
+ * Given a SensorInfo vector and a sensor handles vector populate 'sensors' with SensorInfo
+ * objects that have the sensorHandle property set to int32_ts from start to start + size
+ * (exclusive) and push those sensorHandles also onto 'sensorHandles'.
+ *
+ * @param start The starting sensorHandle value.
+ * @param size The ending (not included) sensorHandle value.
+ * @param sensors The SensorInfo object vector reference to push_back to.
+ * @param sensorHandles The sensor handles int32_t vector reference to push_back to.
+ */
+void makeSensorsAndSensorHandlesStartingAndOfSize(int32_t start, size_t size,
+ std::vector<SensorInfo>& sensors,
+ std::vector<int32_t>& sensorHandles);
+
// Tests follow
TEST(HalProxyTest, GetSensorsListOneSubHalTest) {
AllSensorsSubHal subHal;
@@ -225,10 +282,8 @@
AllSensorsSubHal subHal;
std::vector<ISensorsSubHal*> subHals{&subHal};
HalProxy proxy(subHals);
- std::unique_ptr<EventMessageQueue> eventQueue =
- std::make_unique<EventMessageQueue>(kQueueSize, true);
- std::unique_ptr<WakeupMessageQueue> wakeLockQueue =
- std::make_unique<WakeupMessageQueue>(kQueueSize, true);
+ std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+ std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
::android::sp<ISensorsCallback> callback = new SensorsCallback();
proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
@@ -244,10 +299,8 @@
AllSensorsSubHal subHal;
std::vector<ISensorsSubHal*> subHals{&subHal};
HalProxy proxy(subHals);
- std::unique_ptr<EventMessageQueue> eventQueue =
- std::make_unique<EventMessageQueue>(kQueueSize, true);
- std::unique_ptr<WakeupMessageQueue> wakeLockQueue =
- std::make_unique<WakeupMessageQueue>(kQueueSize, true);
+ std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+ std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
::android::sp<ISensorsCallback> callback = new SensorsCallback();
proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
@@ -262,17 +315,24 @@
AllSensorsSubHal subHal;
std::vector<ISensorsSubHal*> subHals{&subHal};
HalProxy proxy(subHals);
- std::unique_ptr<EventMessageQueue> eventQueue =
- std::make_unique<EventMessageQueue>(kQueueSize, true);
- std::unique_ptr<WakeupMessageQueue> wakeLockQueue =
- std::make_unique<WakeupMessageQueue>(kQueueSize, true);
+ std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+ std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
::android::sp<ISensorsCallback> callback = new SensorsCallback();
proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+ EventFlag* eventQueueFlag;
+ EventFlag::createEventFlag(eventQueue->getEventFlagWord(), &eventQueueFlag);
+
+ EventFlag* wakelockQueueFlag;
+ EventFlag::createEventFlag(wakeLockQueue->getEventFlagWord(), &wakelockQueueFlag);
+
std::vector<Event> events{makeProximityEvent()};
subHal.postEvents(events, true /* wakeup */);
EXPECT_EQ(eventQueue->availableToRead(), 1);
+
+ readEventsOutOfQueue(1, eventQueue, eventQueueFlag);
+ ackWakeupEventsToHalProxy(1, wakeLockQueue, wakelockQueueFlag);
}
TEST(HalProxyTest, PostMultipleWakeupEvents) {
@@ -281,17 +341,24 @@
AllSensorsSubHal subHal;
std::vector<ISensorsSubHal*> subHals{&subHal};
HalProxy proxy(subHals);
- std::unique_ptr<EventMessageQueue> eventQueue =
- std::make_unique<EventMessageQueue>(kQueueSize, true);
- std::unique_ptr<WakeupMessageQueue> wakeLockQueue =
- std::make_unique<WakeupMessageQueue>(kQueueSize, true);
+ std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+ std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
::android::sp<ISensorsCallback> callback = new SensorsCallback();
proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+ EventFlag* eventQueueFlag;
+ EventFlag::createEventFlag(eventQueue->getEventFlagWord(), &eventQueueFlag);
+
+ EventFlag* wakelockQueueFlag;
+ EventFlag::createEventFlag(wakeLockQueue->getEventFlagWord(), &wakelockQueueFlag);
+
std::vector<Event> events = makeMultipleProximityEvents(kNumEvents);
subHal.postEvents(events, true /* wakeup */);
EXPECT_EQ(eventQueue->availableToRead(), kNumEvents);
+
+ readEventsOutOfQueue(kNumEvents, eventQueue, eventQueueFlag);
+ ackWakeupEventsToHalProxy(kNumEvents, wakeLockQueue, wakelockQueueFlag);
}
TEST(HalProxyTest, PostEventsMultipleSubhals) {
@@ -300,10 +367,8 @@
AllSensorsSubHal subHal1, subHal2;
std::vector<ISensorsSubHal*> subHals{&subHal1, &subHal2};
HalProxy proxy(subHals);
- std::unique_ptr<EventMessageQueue> eventQueue =
- std::make_unique<EventMessageQueue>(kQueueSize, true);
- std::unique_ptr<WakeupMessageQueue> wakeLockQueue =
- std::make_unique<WakeupMessageQueue>(kQueueSize, true);
+ std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+ std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
::android::sp<ISensorsCallback> callback = new SensorsCallback();
proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
@@ -323,27 +388,26 @@
AllSensorsSubHal subHal1, subHal2;
std::vector<ISensorsSubHal*> subHals{&subHal1, &subHal2};
HalProxy proxy(subHals);
- std::unique_ptr<EventMessageQueue> eventQueue =
- std::make_unique<EventMessageQueue>(kQueueSize, true);
- std::unique_ptr<WakeupMessageQueue> wakeLockQueue =
- std::make_unique<WakeupMessageQueue>(kQueueSize, true);
+ std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+ std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
::android::sp<ISensorsCallback> callback = new SensorsCallback();
proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+ EventFlag* eventQueueFlag;
+ EventFlag::createEventFlag(eventQueue->getEventFlagWord(), &eventQueueFlag);
+
std::vector<Event> events = makeMultipleAccelerometerEvents(kNumEvents);
subHal1.postEvents(events, false /* wakeup */);
EXPECT_EQ(eventQueue->availableToRead(), kQueueSize);
- Event eventOut;
- // writeblock 1 event out of queue, timeout for half a second
- EXPECT_TRUE(eventQueue->readBlocking(&eventOut, 1, 500000000));
+ // readblock a full queue size worth of events out of queue, timeout for half a second
+ EXPECT_TRUE(readEventsOutOfQueue(kQueueSize, eventQueue, eventQueueFlag));
- // Sleep for a half second so that blocking write has time complete in background thread
- std::this_thread::sleep_for(std::chrono::milliseconds(500));
+ // proxy background thread should have wrote remaining events when it saw space
+ EXPECT_TRUE(readEventsOutOfQueue(kNumEvents - kQueueSize, eventQueue, eventQueueFlag));
- // proxy background thread should have wrote last event when it saw space
- EXPECT_EQ(eventQueue->availableToRead(), kQueueSize);
+ EXPECT_EQ(eventQueue->availableToRead(), 0);
}
TEST(HalProxyTest, PostEventsMultipleSubhalsThreaded) {
@@ -352,10 +416,8 @@
AllSensorsSubHal subHal1, subHal2;
std::vector<ISensorsSubHal*> subHals{&subHal1, &subHal2};
HalProxy proxy(subHals);
- std::unique_ptr<EventMessageQueue> eventQueue =
- std::make_unique<EventMessageQueue>(kQueueSize, true);
- std::unique_ptr<WakeupMessageQueue> wakeLockQueue =
- std::make_unique<WakeupMessageQueue>(kQueueSize, true);
+ std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+ std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
::android::sp<ISensorsCallback> callback = new SensorsCallback();
proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
@@ -376,10 +438,8 @@
AllSensorsSubHal subHal;
std::vector<ISensorsSubHal*> subHals{&subHal};
- std::unique_ptr<EventMessageQueue> eventQueue =
- std::make_unique<EventMessageQueue>(kQueueSize, true);
- std::unique_ptr<WakeupMessageQueue> wakeLockQueue =
- std::make_unique<WakeupMessageQueue>(kQueueSize, true);
+ std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+ std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
::android::sp<ISensorsCallback> callback = new SensorsCallback();
HalProxy proxy(subHals);
proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
@@ -396,6 +456,81 @@
// If this TEST completes then it was a success, if it hangs we will see a crash
}
+TEST(HalProxyTest, DynamicSensorsConnectedTest) {
+ constexpr size_t kNumSensors = 3;
+ AddAndRemoveDynamicSensorsSubHal subHal;
+ std::vector<ISensorsSubHal*> subHals{&subHal};
+ HalProxy proxy(subHals);
+ std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(0);
+ std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(0);
+
+ std::vector<SensorInfo> sensorsToConnect;
+ std::vector<int32_t> sensorHandlesToExpect;
+ makeSensorsAndSensorHandlesStartingAndOfSize(1, kNumSensors, sensorsToConnect,
+ sensorHandlesToExpect);
+
+ TestSensorsCallback* callback = new TestSensorsCallback();
+ ::android::sp<ISensorsCallback> callbackPtr = callback;
+ proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callbackPtr);
+ subHal.addDynamicSensors(sensorsToConnect);
+
+ std::vector<SensorInfo> sensorsSeen = callback->getSensorsConnected();
+ EXPECT_EQ(kNumSensors, sensorsSeen.size());
+ for (size_t i = 0; i < kNumSensors; i++) {
+ auto sensorHandleSeen = sensorsSeen[i].sensorHandle;
+ // Note since only one subhal we do not need to change first byte for expected
+ auto sensorHandleExpected = sensorHandlesToExpect[i];
+ EXPECT_EQ(sensorHandleSeen, sensorHandleExpected);
+ }
+}
+
+TEST(HalProxyTest, DynamicSensorsDisconnectedTest) {
+ constexpr size_t kNumSensors = 3;
+ AddAndRemoveDynamicSensorsSubHal subHal;
+ std::vector<ISensorsSubHal*> subHals{&subHal};
+ HalProxy proxy(subHals);
+ std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(0);
+ std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(0);
+
+ std::vector<SensorInfo> sensorsToConnect;
+ std::vector<int32_t> sensorHandlesToExpect;
+ makeSensorsAndSensorHandlesStartingAndOfSize(20, kNumSensors, sensorsToConnect,
+ sensorHandlesToExpect);
+
+ std::vector<int32_t> nonDynamicSensorHandles;
+ for (int32_t sensorHandle = 1; sensorHandle < 10; sensorHandle++) {
+ nonDynamicSensorHandles.push_back(sensorHandle);
+ }
+
+ std::set<int32_t> nonDynamicSensorHandlesSet(nonDynamicSensorHandles.begin(),
+ nonDynamicSensorHandles.end());
+
+ std::vector<int32_t> sensorHandlesToAttemptToRemove;
+ sensorHandlesToAttemptToRemove.insert(sensorHandlesToAttemptToRemove.end(),
+ sensorHandlesToExpect.begin(),
+ sensorHandlesToExpect.end());
+ sensorHandlesToAttemptToRemove.insert(sensorHandlesToAttemptToRemove.end(),
+ nonDynamicSensorHandles.begin(),
+ nonDynamicSensorHandles.end());
+
+ TestSensorsCallback* callback = new TestSensorsCallback();
+ ::android::sp<ISensorsCallback> callbackPtr = callback;
+ proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callbackPtr);
+ subHal.addDynamicSensors(sensorsToConnect);
+ subHal.removeDynamicSensors(sensorHandlesToAttemptToRemove);
+
+ std::vector<int32_t> sensorHandlesSeen = callback->getSensorHandlesDisconnected();
+ EXPECT_EQ(kNumSensors, sensorHandlesSeen.size());
+ for (size_t i = 0; i < kNumSensors; i++) {
+ auto sensorHandleSeen = sensorHandlesSeen[i];
+ // Note since only one subhal we do not need to change first byte for expected
+ auto sensorHandleExpected = sensorHandlesToExpect[i];
+ EXPECT_EQ(sensorHandleSeen, sensorHandleExpected);
+ EXPECT_TRUE(nonDynamicSensorHandlesSet.find(sensorHandleSeen) ==
+ nonDynamicSensorHandlesSet.end());
+ }
+}
+
// Helper implementations follow
void testSensorsListFromProxyAndSubHal(const std::vector<SensorInfo>& proxySensorsList,
const std::vector<SensorInfo>& subHalSensorsList) {
@@ -427,6 +562,31 @@
}
}
+void ackWakeupEventsToHalProxy(size_t numEvents, std::unique_ptr<WakeupMessageQueue>& wakelockQueue,
+ EventFlag* wakelockQueueFlag) {
+ uint32_t numEventsUInt32 = static_cast<uint32_t>(numEvents);
+ wakelockQueue->write(&numEventsUInt32);
+ wakelockQueueFlag->wake(static_cast<uint32_t>(WakeLockQueueFlagBits::DATA_WRITTEN));
+}
+
+bool readEventsOutOfQueue(size_t numEvents, std::unique_ptr<EventMessageQueue>& eventQueue,
+ EventFlag* eventQueueFlag) {
+ constexpr int64_t kReadBlockingTimeout = INT64_C(500000000);
+ std::vector<Event> events(numEvents);
+ return eventQueue->readBlocking(events.data(), numEvents,
+ static_cast<uint32_t>(EventQueueFlagBits::EVENTS_READ),
+ static_cast<uint32_t>(EventQueueFlagBits::READ_AND_PROCESS),
+ kReadBlockingTimeout, eventQueueFlag);
+}
+
+std::unique_ptr<EventMessageQueue> makeEventFMQ(size_t size) {
+ return std::make_unique<EventMessageQueue>(size, true);
+}
+
+std::unique_ptr<WakeupMessageQueue> makeWakelockFMQ(size_t size) {
+ return std::make_unique<WakeupMessageQueue>(size, true);
+}
+
Event makeProximityEvent() {
Event event;
event.timestamp = 0xFF00FF00;
@@ -463,4 +623,18 @@
return events;
}
+void makeSensorsAndSensorHandlesStartingAndOfSize(int32_t start, size_t size,
+ std::vector<SensorInfo>& sensors,
+ std::vector<int32_t>& sensorHandles) {
+ for (int32_t sensorHandle = start; sensorHandle < start + static_cast<int32_t>(size);
+ sensorHandle++) {
+ SensorInfo sensor;
+ // Just set the sensorHandle field to the correct value so as to not have
+ // to compare every field
+ sensor.sensorHandle = sensorHandle;
+ sensors.push_back(sensor);
+ sensorHandles.push_back(sensorHandle);
+ }
+}
+
} // namespace
diff --git a/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp b/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp
index d581c49..cf3ae75 100644
--- a/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp
+++ b/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp
@@ -221,6 +221,16 @@
return Void();
}
+void AddAndRemoveDynamicSensorsSubHal::addDynamicSensors(
+ const std::vector<SensorInfo>& sensorsAdded) {
+ mCallback->onDynamicSensorsConnected(sensorsAdded);
+}
+
+void AddAndRemoveDynamicSensorsSubHal::removeDynamicSensors(
+ const std::vector<int32_t>& sensorHandlesRemoved) {
+ mCallback->onDynamicSensorsDisconnected(sensorHandlesRemoved);
+}
+
} // namespace implementation
} // namespace subhal
} // namespace V2_0
diff --git a/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.h b/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.h
index 61caa2c..c1e3647 100644
--- a/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.h
+++ b/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.h
@@ -98,13 +98,6 @@
*/
std::map<int32_t, std::shared_ptr<Sensor>> mSensors;
- private:
- /**
- * The current operation mode of the multihal framework. Ensures that all subhals are set to
- * the same operation mode.
- */
- OperationMode mCurrentOperationMode = OperationMode::NORMAL;
-
/**
* Callback used to communicate to the HalProxy when dynamic sensors are connected /
* disconnected, sensor events need to be sent to the framework, and when a wakelock should be
@@ -112,6 +105,13 @@
*/
sp<IHalProxyCallback> mCallback;
+ private:
+ /**
+ * The current operation mode of the multihal framework. Ensures that all subhals are set to
+ * the same operation mode.
+ */
+ OperationMode mCurrentOperationMode = OperationMode::NORMAL;
+
/**
* The next available sensor handle
*/
@@ -151,6 +151,12 @@
Return<void> getSensorsList(getSensorsList_cb _hidl_cb) override;
};
+class AddAndRemoveDynamicSensorsSubHal : public AllSensorsSubHal {
+ public:
+ void addDynamicSensors(const std::vector<SensorInfo>& sensorsAdded);
+ void removeDynamicSensors(const std::vector<int32_t>& sensorHandlesAdded);
+};
+
} // namespace implementation
} // namespace subhal
} // namespace V2_0
diff --git a/tv/tuner/1.0/default/Demux.cpp b/tv/tuner/1.0/default/Demux.cpp
index d65df59..8bb79f9 100644
--- a/tv/tuner/1.0/default/Demux.cpp
+++ b/tv/tuner/1.0/default/Demux.cpp
@@ -106,7 +106,7 @@
} else {
filterId = ++mLastUsedFilterId;
- mDemuxCallbacks.resize(filterId + 1);
+ mFilterCallbacks.resize(filterId + 1);
mFilterMQs.resize(filterId + 1);
mFilterEvents.resize(filterId + 1);
mFilterEventFlags.resize(filterId + 1);
@@ -114,6 +114,7 @@
mFilterThreads.resize(filterId + 1);
mFilterPids.resize(filterId + 1);
mFilterOutputs.resize(filterId + 1);
+ mFilterStatus.resize(filterId + 1);
}
mUsedFilterIds.insert(filterId);
@@ -125,7 +126,7 @@
}
// Add callback
- mDemuxCallbacks[filterId] = cb;
+ mFilterCallbacks[filterId] = cb;
// Mapping from the filter ID to the filter event
DemuxFilterEvent event{
@@ -211,9 +212,16 @@
return Result::SUCCESS;
}
-Return<Result> Demux::flushFilter(uint32_t /* filterId */) {
+Return<Result> Demux::flushFilter(uint32_t filterId) {
ALOGV("%s", __FUNCTION__);
+ // temp implementation to flush the FMQ
+ int size = mFilterMQs[filterId]->availableToRead();
+ char* buffer = new char[size];
+ mOutputMQ->read((unsigned char*)&buffer[0], size);
+ delete[] buffer;
+ mFilterStatus[filterId] = DemuxFilterStatus::DATA_READY;
+
return Result::SUCCESS;
}
@@ -254,7 +262,7 @@
mFilterThreads.clear();
mUnusedFilterIds.clear();
mUsedFilterIds.clear();
- mDemuxCallbacks.clear();
+ mFilterCallbacks.clear();
mFilterMQs.clear();
mFilterEvents.clear();
mFilterEventFlags.clear();
@@ -458,32 +466,55 @@
Result Demux::startPesFilterHandler(uint32_t filterId) {
std::lock_guard<std::mutex> lock(mFilterEventLock);
- DemuxFilterPesEvent pesEvent;
if (mFilterOutputs[filterId].empty()) {
return Result::SUCCESS;
}
for (int i = 0; i < mFilterOutputs[filterId].size(); i += 188) {
- uint8_t pusi = mFilterOutputs[filterId][i + 1] & 0x40;
- uint8_t adaptFieldControl = (mFilterOutputs[filterId][i + 3] & 0x30) >> 4;
- ALOGD("[Demux] pusi %d, adaptFieldControl %d", pusi, adaptFieldControl);
- if (pusi && (adaptFieldControl == 0x01)) {
- vector<uint8_t>::const_iterator first = mFilterOutputs[filterId].begin() + i + 4;
- vector<uint8_t>::const_iterator last = mFilterOutputs[filterId].begin() + i + 187;
- vector<uint8_t> filterOutData(first, last);
- if (!writeDataToFilterMQ(filterOutData, filterId)) {
- mFilterOutputs[filterId].clear();
- return Result::INVALID_STATE;
+ if (mPesSizeLeft == 0) {
+ uint32_t prefix = (mFilterOutputs[filterId][i + 4] << 16) |
+ (mFilterOutputs[filterId][i + 5] << 8) |
+ mFilterOutputs[filterId][i + 6];
+ ALOGD("[Demux] prefix %d", prefix);
+ if (prefix == 0x000001) {
+ // TODO handle mulptiple Pes filters
+ mPesSizeLeft =
+ (mFilterOutputs[filterId][i + 8] << 8) | mFilterOutputs[filterId][i + 9];
+ mPesSizeLeft += 6;
+ ALOGD("[Demux] pes data length %d", mPesSizeLeft);
+ } else {
+ continue;
}
- pesEvent = {
- // temp dump meta data
- .streamId = filterOutData[3],
- .dataLength = static_cast<uint16_t>(filterOutData.size()),
- };
- int size = mFilterEvents[filterId].events.size();
- mFilterEvents[filterId].events.resize(size + 1);
- mFilterEvents[filterId].events[size].pes(pesEvent);
}
+
+ int endPoint = min(184, mPesSizeLeft);
+ // append data and check size
+ vector<uint8_t>::const_iterator first = mFilterOutputs[filterId].begin() + i + 4;
+ vector<uint8_t>::const_iterator last = mFilterOutputs[filterId].begin() + i + 4 + endPoint;
+ mPesOutput.insert(mPesOutput.end(), first, last);
+ // size does not match then continue
+ mPesSizeLeft -= endPoint;
+ if (mPesSizeLeft > 0) {
+ continue;
+ }
+ // size match then create event
+ if (!writeDataToFilterMQ(mPesOutput, filterId)) {
+ mFilterOutputs[filterId].clear();
+ return Result::INVALID_STATE;
+ }
+ maySendFilterStatusCallback(filterId);
+ DemuxFilterPesEvent pesEvent;
+ pesEvent = {
+ // temp dump meta data
+ .streamId = mPesOutput[3],
+ .dataLength = static_cast<uint16_t>(mPesOutput.size()),
+ };
+ ALOGD("[Demux] assembled pes data length %d", pesEvent.dataLength);
+
+ int size = mFilterEvents[filterId].events.size();
+ mFilterEvents[filterId].events.resize(size + 1);
+ mFilterEvents[filterId].events[size].pes(pesEvent);
+ mPesOutput.clear();
}
mFilterOutputs[filterId].clear();
@@ -672,8 +703,10 @@
continue;
}
// After successfully write, send a callback and wait for the read to be done
- mDemuxCallbacks[filterId]->onFilterEvent(mFilterEvents[filterId]);
+ mFilterCallbacks[filterId]->onFilterEvent(mFilterEvents[filterId]);
mFilterEvents[filterId].events.resize(0);
+ mFilterStatus[filterId] = DemuxFilterStatus::DATA_READY;
+ mFilterCallbacks[filterId]->onFilterStatus(filterId, mFilterStatus[filterId]);
break;
}
@@ -693,18 +726,20 @@
break;
}
- if (mDemuxCallbacks[filterId] == nullptr) {
+ if (mFilterCallbacks[filterId] == nullptr) {
ALOGD("[Demux] filter %d does not hava callback. Ending thread", filterId);
break;
}
+ maySendFilterStatusCallback(filterId);
+
while (mFilterThreadRunning[filterId]) {
std::lock_guard<std::mutex> lock(mFilterEventLock);
if (mFilterEvents[filterId].events.size() == 0) {
continue;
}
// After successfully write, send a callback and wait for the read to be done
- mDemuxCallbacks[filterId]->onFilterEvent(mFilterEvents[filterId]);
+ mFilterCallbacks[filterId]->onFilterEvent(mFilterEvents[filterId]);
mFilterEvents[filterId].events.resize(0);
break;
}
@@ -755,16 +790,31 @@
int availableToWrite = mInputMQ->availableToWrite();
DemuxInputStatus newStatus =
- checkStatusChange(availableToWrite, availableToRead, mInputSettings.highThreshold,
- mInputSettings.lowThreshold);
+ checkInputStatusChange(availableToWrite, availableToRead, mInputSettings.highThreshold,
+ mInputSettings.lowThreshold);
if (mIntputStatus != newStatus) {
mInputCallback->onInputStatus(newStatus);
mIntputStatus = newStatus;
}
}
-DemuxInputStatus Demux::checkStatusChange(uint32_t availableToWrite, uint32_t availableToRead,
- uint32_t highThreshold, uint32_t lowThreshold) {
+void Demux::maySendFilterStatusCallback(uint32_t filterId) {
+ std::lock_guard<std::mutex> lock(mFilterStatusLock);
+ int availableToRead = mFilterMQs[filterId]->availableToRead();
+ int availableToWrite = mFilterMQs[filterId]->availableToWrite();
+ int fmqSize = mFilterMQs[filterId]->getQuantumCount();
+
+ DemuxFilterStatus newStatus =
+ checkFilterStatusChange(filterId, availableToWrite, availableToRead,
+ ceil(fmqSize * 0.75), ceil(fmqSize * 0.25));
+ if (mFilterStatus[filterId] != newStatus) {
+ mFilterCallbacks[filterId]->onFilterStatus(filterId, newStatus);
+ mFilterStatus[filterId] = newStatus;
+ }
+}
+
+DemuxInputStatus Demux::checkInputStatusChange(uint32_t availableToWrite, uint32_t availableToRead,
+ uint32_t highThreshold, uint32_t lowThreshold) {
if (availableToWrite == 0) {
return DemuxInputStatus::SPACE_FULL;
} else if (availableToRead > highThreshold) {
@@ -777,6 +827,19 @@
return mIntputStatus;
}
+DemuxFilterStatus Demux::checkFilterStatusChange(uint32_t filterId, uint32_t availableToWrite,
+ uint32_t availableToRead, uint32_t highThreshold,
+ uint32_t lowThreshold) {
+ if (availableToWrite == 0) {
+ return DemuxFilterStatus::OVERFLOW;
+ } else if (availableToRead > highThreshold) {
+ return DemuxFilterStatus::HIGH_WATER;
+ } else if (availableToRead < lowThreshold) {
+ return DemuxFilterStatus::LOW_WATER;
+ }
+ return mFilterStatus[filterId];
+}
+
Result Demux::startBroadcastInputLoop() {
pthread_create(&mBroadcastInputThread, NULL, __threadLoopBroadcast, this);
pthread_setname_np(mBroadcastInputThread, "broadcast_input_thread");
@@ -818,12 +881,11 @@
}
// filter and dispatch filter output
vector<uint8_t> byteBuffer;
- byteBuffer.resize(sizeof(buffer));
+ byteBuffer.resize(packetSize);
for (int index = 0; index < byteBuffer.size(); index++) {
byteBuffer[index] = static_cast<uint8_t>(buffer[index]);
}
startTsFilter(byteBuffer);
- inputData.seekg(packetSize, inputData.cur);
}
startFilterDispatcher();
sleep(1);
diff --git a/tv/tuner/1.0/default/Demux.h b/tv/tuner/1.0/default/Demux.h
index e4a4e2b..ba0b9b0 100644
--- a/tv/tuner/1.0/default/Demux.h
+++ b/tv/tuner/1.0/default/Demux.h
@@ -19,6 +19,7 @@
#include <android/hardware/tv/tuner/1.0/IDemux.h>
#include <fmq/MessageQueue.h>
+#include <math.h>
#include <set>
#include "Frontend.h"
#include "Tuner.h"
@@ -153,8 +154,12 @@
bool readDataFromMQ();
bool writeSectionsAndCreateEvent(uint32_t filterId, vector<uint8_t> data);
void maySendInputStatusCallback();
- DemuxInputStatus checkStatusChange(uint32_t availableToWrite, uint32_t availableToRead,
- uint32_t highThreshold, uint32_t lowThreshold);
+ void maySendFilterStatusCallback(uint32_t filterId);
+ DemuxInputStatus checkInputStatusChange(uint32_t availableToWrite, uint32_t availableToRead,
+ uint32_t highThreshold, uint32_t lowThreshold);
+ DemuxFilterStatus checkFilterStatusChange(uint32_t filterId, uint32_t availableToWrite,
+ uint32_t availableToRead, uint32_t highThreshold,
+ uint32_t lowThreshold);
/**
* A dispatcher to read and dispatch input data to all the started filters.
* Each filter handler handles the data filtering/output writing/filterEvent updating.
@@ -203,7 +208,7 @@
/**
* Demux callbacks used on filter events or IO buffer status
*/
- vector<sp<IDemuxCallback>> mDemuxCallbacks;
+ vector<sp<IDemuxCallback>> mFilterCallbacks;
sp<IDemuxCallback> mInputCallback;
sp<IDemuxCallback> mOutputCallback;
bool mInputConfigured = false;
@@ -219,6 +224,7 @@
// FMQ status local records
DemuxInputStatus mIntputStatus;
+ vector<DemuxFilterStatus> mFilterStatus;
/**
* If a specific filter's writing loop is still running
*/
@@ -239,6 +245,7 @@
* Lock to protect writes to the input status
*/
std::mutex mInputStatusLock;
+ std::mutex mFilterStatusLock;
std::mutex mBroadcastInputThreadLock;
std::mutex mFilterThreadLock;
std::mutex mInputThreadLock;
@@ -247,6 +254,11 @@
* TODO make this dynamic/random/can take as a parameter
*/
const uint16_t SECTION_WRITE_COUNT = 10;
+
+ // temp handle single PES filter
+ // TODO handle mulptiple Pes filters
+ int mPesSizeLeft = 0;
+ vector<uint8_t> mPesOutput;
};
} // namespace implementation
diff --git a/tv/tuner/README.md b/tv/tuner/README.md
index a833c87..aa1f62d 100644
--- a/tv/tuner/README.md
+++ b/tv/tuner/README.md
@@ -4,7 +4,7 @@
TV specific tuners.
-Sett 1.0/ITuner.hal for an overview.
+See 1.0/ITuner.hal for an overview.
*** note
**Warning:** The HALs are not (yet) frozen, as the HAL definition is
diff --git a/vibrator/1.3/example/android.hardware.vibrator@1.3-service.example.rc b/vibrator/1.3/example/android.hardware.vibrator@1.3-service.example.rc
deleted file mode 100644
index ed7a562..0000000
--- a/vibrator/1.3/example/android.hardware.vibrator@1.3-service.example.rc
+++ /dev/null
@@ -1,4 +0,0 @@
-service vendor.vibrator-1-3 /vendor/bin/hw/android.hardware.vibrator@1.3-service.example
- class hal
- user system
- group system
diff --git a/vibrator/1.3/example/Android.bp b/vibrator/1.x/example/Android.bp
similarity index 81%
rename from vibrator/1.3/example/Android.bp
rename to vibrator/1.x/example/Android.bp
index 07f1c26..afbbb75 100644
--- a/vibrator/1.3/example/Android.bp
+++ b/vibrator/1.x/example/Android.bp
@@ -14,11 +14,11 @@
// limitations under the License.
cc_binary {
- name: "android.hardware.vibrator@1.3-service.example",
+ name: "android.hardware.vibrator@1.x-service.example",
vendor: true,
relative_install_path: "hw",
- init_rc: ["android.hardware.vibrator@1.3-service.example.rc"],
- vintf_fragments: ["android.hardware.vibrator@1.3-service.example.xml"],
+ init_rc: ["android.hardware.vibrator@1.x-service.example.rc"],
+ vintf_fragments: ["android.hardware.vibrator@1.x-service.example.xml"],
srcs: ["service.cpp", "Vibrator.cpp"],
cflags: ["-Wall", "-Werror"],
shared_libs: [
@@ -29,5 +29,6 @@
"android.hardware.vibrator@1.1",
"android.hardware.vibrator@1.2",
"android.hardware.vibrator@1.3",
+ "android.hardware.vibrator@1.4",
],
}
diff --git a/vibrator/1.3/example/OWNERS b/vibrator/1.x/example/OWNERS
similarity index 100%
rename from vibrator/1.3/example/OWNERS
rename to vibrator/1.x/example/OWNERS
diff --git a/vibrator/1.3/example/Vibrator.cpp b/vibrator/1.x/example/Vibrator.cpp
similarity index 86%
rename from vibrator/1.3/example/Vibrator.cpp
rename to vibrator/1.x/example/Vibrator.cpp
index b529437..4dd1cb9 100644
--- a/vibrator/1.3/example/Vibrator.cpp
+++ b/vibrator/1.x/example/Vibrator.cpp
@@ -23,7 +23,7 @@
namespace android {
namespace hardware {
namespace vibrator {
-namespace V1_3 {
+namespace V1_4 {
namespace implementation {
static constexpr uint32_t MS_PER_S = 1000;
@@ -100,7 +100,25 @@
}
}
-Return<void> Vibrator::perform_1_3(Effect effect, EffectStrength strength, perform_cb _hidl_cb) {
+Return<void> Vibrator::perform_1_3(V1_3::Effect effect, EffectStrength strength,
+ perform_cb _hidl_cb) {
+ return perform<decltype(effect)>(effect, strength, _hidl_cb);
+}
+
+// Methods from ::android::hardware::vibrator::V1_4::IVibrator follow.
+
+Return<hidl_bitfield<Capabilities>> Vibrator::getCapabilities() {
+ return Capabilities::ON_COMPLETION_CALLBACK | Capabilities::PERFORM_COMPLETION_CALLBACK;
+}
+
+Return<Status> Vibrator::on_1_4(uint32_t timeoutMs, const sp<IVibratorCallback>& callback) {
+ mCallback = callback;
+ return on(timeoutMs);
+}
+
+Return<void> Vibrator::perform_1_4(V1_3::Effect effect, EffectStrength strength,
+ const sp<IVibratorCallback>& callback, perform_cb _hidl_cb) {
+ mCallback = callback;
return perform<decltype(effect)>(effect, strength, _hidl_cb);
}
@@ -148,6 +166,14 @@
return Status::UNSUPPORTED_OPERATION;
} else {
ALOGI("Enabled: %s -> %s\n", mEnabled ? "true" : "false", enabled ? "true" : "false");
+ if (mEnabled && !enabled) {
+ if (auto callback = mCallback) {
+ mCallback = nullptr;
+ if (auto ret = callback->onComplete(); !ret.isOk()) {
+ ALOGE("Failed completion callback: %s", ret.description().c_str());
+ }
+ }
+ }
mEnabled = enabled;
return Status::OK;
}
@@ -271,7 +297,7 @@
}
} // namespace implementation
-} // namespace V1_3
+} // namespace V1_4
} // namespace vibrator
} // namespace hardware
} // namespace android
diff --git a/vibrator/1.3/example/Vibrator.h b/vibrator/1.x/example/Vibrator.h
similarity index 75%
rename from vibrator/1.3/example/Vibrator.h
rename to vibrator/1.x/example/Vibrator.h
index 5180774..ff63431 100644
--- a/vibrator/1.3/example/Vibrator.h
+++ b/vibrator/1.x/example/Vibrator.h
@@ -13,20 +13,21 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#ifndef ANDROID_HARDWARE_VIBRATOR_V1_3_VIBRATOR_H
-#define ANDROID_HARDWARE_VIBRATOR_V1_3_VIBRATOR_H
+#ifndef ANDROID_HARDWARE_VIBRATOR_V1_x_VIBRATOR_H
+#define ANDROID_HARDWARE_VIBRATOR_V1_x_VIBRATOR_H
-#include <android/hardware/vibrator/1.3/IVibrator.h>
+#include <android/hardware/vibrator/1.4/IVibrator.h>
#include <hidl/Status.h>
namespace android {
namespace hardware {
namespace vibrator {
-namespace V1_3 {
+namespace V1_4 {
namespace implementation {
using android::hardware::vibrator::V1_0::EffectStrength;
using android::hardware::vibrator::V1_0::Status;
+using android::hardware::vibrator::V1_3::Effect;
class Vibrator : public IVibrator {
public:
@@ -51,7 +52,14 @@
// Methods from ::android::hardware::vibrator::V1_3::IVibrator follow.
Return<bool> supportsExternalControl() override;
Return<Status> setExternalControl(bool enabled) override;
- Return<void> perform_1_3(Effect effect, EffectStrength strength, perform_cb _hidl_cb) override;
+ Return<void> perform_1_3(V1_3::Effect effect, EffectStrength strength,
+ perform_cb _hidl_cb) override;
+
+ // Methods from ::android::hardware::vibrator::V1_4::IVibrator follow.
+ Return<hidl_bitfield<Capabilities>> getCapabilities() override;
+ Return<Status> on_1_4(uint32_t timeoutMs, const sp<IVibratorCallback>& callback) override;
+ Return<void> perform_1_4(V1_3::Effect effect, EffectStrength strength,
+ const sp<IVibratorCallback>& callback, perform_cb _hidl_cb) override;
private:
Return<void> perform(Effect effect, EffectStrength strength, perform_cb _hidl_cb);
@@ -72,11 +80,12 @@
bool mExternalControl{false};
std::mutex mMutex;
timer_t mTimer{nullptr};
+ sp<IVibratorCallback> mCallback{nullptr};
};
} // namespace implementation
-} // namespace V1_3
+} // namespace V1_4
} // namespace vibrator
} // namespace hardware
} // namespace android
-#endif // ANDROID_HARDWARE_VIBRATOR_V1_3_VIBRATOR_H
+#endif // ANDROID_HARDWARE_VIBRATOR_V1_x_VIBRATOR_H
diff --git a/vibrator/1.x/example/android.hardware.vibrator@1.x-service.example.rc b/vibrator/1.x/example/android.hardware.vibrator@1.x-service.example.rc
new file mode 100644
index 0000000..4893db6
--- /dev/null
+++ b/vibrator/1.x/example/android.hardware.vibrator@1.x-service.example.rc
@@ -0,0 +1,4 @@
+service vendor.vibrator-1-x /vendor/bin/hw/android.hardware.vibrator@1.x-service.example
+ class hal
+ user system
+ group system
diff --git a/vibrator/1.3/example/android.hardware.vibrator@1.3-service.example.xml b/vibrator/1.x/example/android.hardware.vibrator@1.x-service.example.xml
similarity index 89%
rename from vibrator/1.3/example/android.hardware.vibrator@1.3-service.example.xml
rename to vibrator/1.x/example/android.hardware.vibrator@1.x-service.example.xml
index 172aa21..ebc8c4b 100644
--- a/vibrator/1.3/example/android.hardware.vibrator@1.3-service.example.xml
+++ b/vibrator/1.x/example/android.hardware.vibrator@1.x-service.example.xml
@@ -2,7 +2,7 @@
<hal format="hidl">
<name>android.hardware.vibrator</name>
<transport>hwbinder</transport>
- <version>1.3</version>
+ <version>1.4</version>
<interface>
<name>IVibrator</name>
<instance>default</instance>
diff --git a/vibrator/1.3/example/service.cpp b/vibrator/1.x/example/service.cpp
similarity index 82%
rename from vibrator/1.3/example/service.cpp
rename to vibrator/1.x/example/service.cpp
index 449996e..13c6691 100644
--- a/vibrator/1.3/example/service.cpp
+++ b/vibrator/1.x/example/service.cpp
@@ -13,17 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#define LOG_TAG "android.hardware.vibrator@1.3-service.example"
+#define LOG_TAG "android.hardware.vibrator@1.x-service.example"
-#include <android/hardware/vibrator/1.3/IVibrator.h>
+#include <android/hardware/vibrator/1.4/IVibrator.h>
#include <hidl/HidlTransportSupport.h>
#include "Vibrator.h"
using android::hardware::configureRpcThreadpool;
using android::hardware::joinRpcThreadpool;
-using android::hardware::vibrator::V1_3::IVibrator;
-using android::hardware::vibrator::V1_3::implementation::Vibrator;
+using android::hardware::vibrator::V1_4::IVibrator;
+using android::hardware::vibrator::V1_4::implementation::Vibrator;
using namespace android;
status_t registerVibratorService() {
diff --git a/wifi/1.4/default/Android.mk b/wifi/1.4/default/Android.mk
index 943becc..ab76ff6 100644
--- a/wifi/1.4/default/Android.mk
+++ b/wifi/1.4/default/Android.mk
@@ -150,7 +150,6 @@
tests/mock_wifi_legacy_hal.cpp \
tests/mock_wifi_mode_controller.cpp \
tests/ringbuffer_unit_tests.cpp \
- tests/wifi_ap_iface_unit_tests.cpp \
tests/wifi_nan_iface_unit_tests.cpp \
tests/wifi_chip_unit_tests.cpp \
tests/wifi_iface_util_unit_tests.cpp
diff --git a/wifi/1.4/default/tests/hidl_struct_util_unit_tests.cpp b/wifi/1.4/default/tests/hidl_struct_util_unit_tests.cpp
index fde1df0..14a1504 100644
--- a/wifi/1.4/default/tests/hidl_struct_util_unit_tests.cpp
+++ b/wifi/1.4/default/tests/hidl_struct_util_unit_tests.cpp
@@ -170,12 +170,14 @@
legacy_hal::wifi_channel_stat channel_stat1 = {
.channel = {legacy_hal::WIFI_CHAN_WIDTH_20, 2437, 2437, 0},
+ .on_time = 0x1111,
.cca_busy_time = 0x55,
- .on_time = 0x1111};
+ };
legacy_hal::wifi_channel_stat channel_stat2 = {
.channel = {legacy_hal::WIFI_CHAN_WIDTH_20, 5180, 5180, 0},
+ .on_time = 0x2222,
.cca_busy_time = 0x66,
- .on_time = 0x2222};
+ };
radio.channel_stats.push_back(channel_stat1);
radio.channel_stats.push_back(channel_stat2);
}
diff --git a/wifi/1.4/default/tests/wifi_ap_iface_unit_tests.cpp b/wifi/1.4/default/tests/wifi_ap_iface_unit_tests.cpp
deleted file mode 100644
index 230edd2..0000000
--- a/wifi/1.4/default/tests/wifi_ap_iface_unit_tests.cpp
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2019, 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-base/logging.h>
-#include <android-base/macros.h>
-#include <cutils/properties.h>
-#include <gmock/gmock.h>
-
-#undef NAN // This is weird, NAN is defined in bionic/libc/include/math.h:38
-#include "wifi_ap_iface.h"
-
-#include "mock_interface_tool.h"
-#include "mock_wifi_feature_flags.h"
-#include "mock_wifi_iface_util.h"
-#include "mock_wifi_legacy_hal.h"
-
-using testing::NiceMock;
-using testing::Return;
-using testing::Test;
-
-namespace {
-constexpr char kIfaceName[] = "mockWlan0";
-} // namespace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_4 {
-namespace implementation {
-
-class WifiApIfaceTest : public Test {
- protected:
- std::shared_ptr<NiceMock<wifi_system::MockInterfaceTool>> iface_tool_{
- new NiceMock<wifi_system::MockInterfaceTool>};
- std::shared_ptr<NiceMock<legacy_hal::MockWifiLegacyHal>> legacy_hal_{
- new NiceMock<legacy_hal::MockWifiLegacyHal>(iface_tool_)};
- std::shared_ptr<NiceMock<iface_util::MockWifiIfaceUtil>> iface_util_{
- new NiceMock<iface_util::MockWifiIfaceUtil>(iface_tool_)};
- std::shared_ptr<NiceMock<feature_flags::MockWifiFeatureFlags>>
- feature_flags_{new NiceMock<feature_flags::MockWifiFeatureFlags>};
-};
-
-TEST_F(WifiApIfaceTest, SetRandomMacAddressIfFeatureEnabled) {
- EXPECT_CALL(*feature_flags_, isApMacRandomizationDisabled())
- .WillOnce(testing::Return(false));
- EXPECT_CALL(*iface_util_, getOrCreateRandomMacAddress())
- .WillOnce(testing::Return(std::array<uint8_t, 6>{0, 0, 0, 0, 0, 0}));
- EXPECT_CALL(*iface_util_, setMacAddress(testing::_, testing::_))
- .WillOnce(testing::Return(true));
- sp<WifiApIface> ap_iface =
- new WifiApIface(kIfaceName, legacy_hal_, iface_util_, feature_flags_);
-}
-
-TEST_F(WifiApIfaceTest, DontSetRandomMacAddressIfFeatureDisabled) {
- EXPECT_CALL(*feature_flags_, isApMacRandomizationDisabled())
- .WillOnce(testing::Return(true));
- EXPECT_CALL(*iface_util_, getOrCreateRandomMacAddress()).Times(0);
- EXPECT_CALL(*iface_util_, setMacAddress(testing::_, testing::_)).Times(0);
- sp<WifiApIface> ap_iface =
- new WifiApIface(kIfaceName, legacy_hal_, iface_util_, feature_flags_);
-}
-} // namespace implementation
-} // namespace V1_4
-} // namespace wifi
-} // namespace hardware
-} // namespace android
diff --git a/wifi/1.4/default/wifi_ap_iface.cpp b/wifi/1.4/default/wifi_ap_iface.cpp
index b860910..e677f19 100644
--- a/wifi/1.4/default/wifi_ap_iface.cpp
+++ b/wifi/1.4/default/wifi_ap_iface.cpp
@@ -31,26 +31,11 @@
WifiApIface::WifiApIface(
const std::string& ifname,
const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
- const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util,
- const std::weak_ptr<feature_flags::WifiFeatureFlags> feature_flags)
+ const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util)
: ifname_(ifname),
legacy_hal_(legacy_hal),
iface_util_(iface_util),
- feature_flags_(feature_flags),
- is_valid_(true) {
- if (feature_flags_.lock()->isApMacRandomizationDisabled()) {
- LOG(INFO) << "AP MAC randomization disabled";
- return;
- }
- LOG(INFO) << "AP MAC randomization enabled";
- // Set random MAC address
- std::array<uint8_t, 6> randomized_mac =
- iface_util_.lock()->getOrCreateRandomMacAddress();
- bool status = iface_util_.lock()->setMacAddress(ifname_, randomized_mac);
- if (!status) {
- LOG(ERROR) << "Failed to set random mac address";
- }
-}
+ is_valid_(true) {}
void WifiApIface::invalidate() {
legacy_hal_.reset();
diff --git a/wifi/1.4/default/wifi_ap_iface.h b/wifi/1.4/default/wifi_ap_iface.h
index cb3ed3d..4f3438c 100644
--- a/wifi/1.4/default/wifi_ap_iface.h
+++ b/wifi/1.4/default/wifi_ap_iface.h
@@ -20,7 +20,6 @@
#include <android-base/macros.h>
#include <android/hardware/wifi/1.4/IWifiApIface.h>
-#include "wifi_feature_flags.h"
#include "wifi_iface_util.h"
#include "wifi_legacy_hal.h"
@@ -36,11 +35,9 @@
*/
class WifiApIface : public V1_4::IWifiApIface {
public:
- WifiApIface(
- const std::string& ifname,
- const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
- const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util,
- const std::weak_ptr<feature_flags::WifiFeatureFlags> feature_flags);
+ WifiApIface(const std::string& ifname,
+ const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+ const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util);
// Refer to |WifiChip::invalidate()|.
void invalidate();
bool isValid();
@@ -72,7 +69,6 @@
std::string ifname_;
std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
std::weak_ptr<iface_util::WifiIfaceUtil> iface_util_;
- std::weak_ptr<feature_flags::WifiFeatureFlags> feature_flags_;
bool is_valid_;
DISALLOW_COPY_AND_ASSIGN(WifiApIface);
diff --git a/wifi/1.4/default/wifi_chip.cpp b/wifi/1.4/default/wifi_chip.cpp
index 5a14b01..408096f 100644
--- a/wifi/1.4/default/wifi_chip.cpp
+++ b/wifi/1.4/default/wifi_chip.cpp
@@ -321,7 +321,6 @@
legacy_hal_(legacy_hal),
mode_controller_(mode_controller),
iface_util_(iface_util),
- feature_flags_(feature_flags),
is_valid_(true),
current_mode_id_(feature_flags::chip_mode_ids::kInvalid),
modes_(feature_flags.lock()->getChipModes()),
@@ -806,8 +805,7 @@
return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
}
std::string ifname = allocateApIfaceName();
- sp<WifiApIface> iface =
- new WifiApIface(ifname, legacy_hal_, iface_util_, feature_flags_);
+ sp<WifiApIface> iface = new WifiApIface(ifname, legacy_hal_, iface_util_);
ap_ifaces_.push_back(iface);
for (const auto& callback : event_cb_handler_.getCallbacks()) {
if (!callback->onIfaceAdded(IfaceType::AP, ifname).isOk()) {
diff --git a/wifi/1.4/default/wifi_chip.h b/wifi/1.4/default/wifi_chip.h
index ae9af90..0d7061c 100644
--- a/wifi/1.4/default/wifi_chip.h
+++ b/wifi/1.4/default/wifi_chip.h
@@ -251,7 +251,6 @@
std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
std::weak_ptr<mode_controller::WifiModeController> mode_controller_;
std::weak_ptr<iface_util::WifiIfaceUtil> iface_util_;
- std::weak_ptr<feature_flags::WifiFeatureFlags> feature_flags_;
std::vector<sp<WifiApIface>> ap_ifaces_;
std::vector<sp<WifiNanIface>> nan_ifaces_;
std::vector<sp<WifiP2pIface>> p2p_ifaces_;
diff --git a/wifi/1.4/default/wifi_feature_flags.cpp b/wifi/1.4/default/wifi_feature_flags.cpp
index f9746eb..195b460 100644
--- a/wifi/1.4/default/wifi_feature_flags.cpp
+++ b/wifi/1.4/default/wifi_feature_flags.cpp
@@ -145,10 +145,12 @@
#undef NAN
#ifdef WIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION
-static const bool wifiHidlFeatureDisableApMacRandomization = true;
-#else
-static const bool wifiHidlFeatureDisableApMacRandomization = false;
-#endif // WIFI_HIDL_FEATURE_DISABLE_AP
+#pragma message \
+ "WIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION is deprecated; override " \
+ "'config_wifi_ap_randomization_supported' in " \
+ "frameworks/base/core/res/res/values/config.xml in the device overlay " \
+ "instead"
+#endif // WIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION
WifiFeatureFlags::WifiFeatureFlags() {}
@@ -156,10 +158,6 @@
return kChipModes;
}
-bool WifiFeatureFlags::isApMacRandomizationDisabled() {
- return wifiHidlFeatureDisableApMacRandomization;
-}
-
} // namespace feature_flags
} // namespace implementation
} // namespace V1_4
diff --git a/wifi/1.4/default/wifi_feature_flags.h b/wifi/1.4/default/wifi_feature_flags.h
index 4e146cd..292dedf 100644
--- a/wifi/1.4/default/wifi_feature_flags.h
+++ b/wifi/1.4/default/wifi_feature_flags.h
@@ -43,7 +43,6 @@
virtual ~WifiFeatureFlags() = default;
virtual std::vector<V1_0::IWifiChip::ChipMode> getChipModes();
- virtual bool isApMacRandomizationDisabled();
};
} // namespace feature_flags