From 2744dea37ee3bef216d08fb5db9e656830a2d253 Mon Sep 17 00:00:00 2001 From: Oscar Azucena Date: Fri, 20 Sep 2024 19:35:03 -0700 Subject: [PATCH 1/3] Add audio configurations API to audio control HAL The API will be used to obtain the car audio configuration: - Audio device configurations - Audio mirroring devices - Audio zone information - - Audio zone fade configuration - - Audio zone configurations - - Input audio devices - - Audio zone info Bug: 359686069 Test: m -j, presubmit Flag: EXEMPT HAL interface Change-Id: I32cd7fc351c58e7816a9187d70e5e9c790163dcc --- .../AudioDeviceConfiguration.aidl | 41 ++++++ .../audiocontrol/AudioFadeConfiguration.aidl | 50 ++++++++ .../audiocontrol/AudioFocusChange.aidl | 6 +- .../automotive/audiocontrol/AudioZone.aidl | 45 +++++++ .../audiocontrol/AudioZoneConfig.aidl | 41 ++++++ .../audiocontrol/AudioZoneContext.aidl | 38 ++++++ .../audiocontrol/AudioZoneContextInfo.aidl | 41 ++++++ .../AudioZoneFadeConfiguration.aidl | 39 ++++++ .../audiocontrol/DeviceToContextEntry.aidl | 39 ++++++ .../audiocontrol/FadeConfiguration.aidl | 44 +++++++ .../automotive/audiocontrol/FadeState.aidl | 39 ++++++ .../audiocontrol/IAudioControl.aidl | 31 +++++ .../automotive/audiocontrol/Reasons.aidl | 20 +-- .../RoutingDeviceConfiguration.aidl | 40 ++++++ .../TransientFadeConfigurationEntry.aidl | 39 ++++++ .../VolumeActivationConfiguration.aidl | 39 ++++++ .../VolumeActivationConfigurationEntry.aidl | 42 +++++++ .../audiocontrol/VolumeGroupConfig.aidl | 42 +++++++ .../audiocontrol/VolumeInvocationType.aidl | 40 ++++++ .../AudioDeviceConfiguration.aidl | 48 +++++++ .../audiocontrol/AudioFadeConfiguration.aidl | 118 ++++++++++++++++++ .../automotive/audiocontrol/AudioZone.aidl | 74 +++++++++++ .../audiocontrol/AudioZoneConfig.aidl | 51 ++++++++ .../audiocontrol/AudioZoneContext.aidl | 34 +++++ .../audiocontrol/AudioZoneContextInfo.aidl | 54 ++++++++ .../AudioZoneFadeConfiguration.aidl | 40 ++++++ .../audiocontrol/DeviceToContextEntry.aidl | 47 +++++++ .../audiocontrol/FadeConfiguration.aidl | 45 +++++++ .../automotive/audiocontrol/FadeState.aidl | 34 +++++ .../audiocontrol/IAudioControl.aidl | 40 ++++++ .../RoutingDeviceConfiguration.aidl | 52 ++++++++ .../TransientFadeConfigurationEntry.aidl | 38 ++++++ .../VolumeActivationConfiguration.aidl | 42 +++++++ .../VolumeActivationConfigurationEntry.aidl | 63 ++++++++++ .../audiocontrol/VolumeGroupConfig.aidl | 59 +++++++++ .../audiocontrol/VolumeInvocationType.aidl | 40 ++++++ .../aidl/default/AudioControl.cpp | 31 +++++ .../audiocontrol/aidl/default/AudioControl.h | 5 + .../audiocontrol/aidl/rust_impl/Android.bp | 3 +- .../audiocontrol/aidl/rust_impl/README.md | 2 +- .../src/default_audio_control_hal.rs | 21 +++- 41 files changed, 1641 insertions(+), 16 deletions(-) create mode 100644 automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/AudioDeviceConfiguration.aidl create mode 100644 automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/AudioFadeConfiguration.aidl create mode 100644 automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/AudioZone.aidl create mode 100644 automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/AudioZoneConfig.aidl create mode 100644 automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/AudioZoneContext.aidl create mode 100644 automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/AudioZoneContextInfo.aidl create mode 100644 automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/AudioZoneFadeConfiguration.aidl create mode 100644 automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/DeviceToContextEntry.aidl create mode 100644 automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/FadeConfiguration.aidl create mode 100644 automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/FadeState.aidl create mode 100644 automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/RoutingDeviceConfiguration.aidl create mode 100644 automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/TransientFadeConfigurationEntry.aidl create mode 100644 automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/VolumeActivationConfiguration.aidl create mode 100644 automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/VolumeActivationConfigurationEntry.aidl create mode 100644 automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/VolumeGroupConfig.aidl create mode 100644 automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/VolumeInvocationType.aidl create mode 100644 automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/AudioDeviceConfiguration.aidl create mode 100644 automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/AudioFadeConfiguration.aidl create mode 100644 automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/AudioZone.aidl create mode 100644 automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/AudioZoneConfig.aidl create mode 100644 automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/AudioZoneContext.aidl create mode 100644 automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/AudioZoneContextInfo.aidl create mode 100644 automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/AudioZoneFadeConfiguration.aidl create mode 100644 automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/DeviceToContextEntry.aidl create mode 100644 automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/FadeConfiguration.aidl create mode 100644 automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/FadeState.aidl create mode 100644 automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/RoutingDeviceConfiguration.aidl create mode 100644 automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/TransientFadeConfigurationEntry.aidl create mode 100644 automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/VolumeActivationConfiguration.aidl create mode 100644 automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/VolumeActivationConfigurationEntry.aidl create mode 100644 automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/VolumeGroupConfig.aidl create mode 100644 automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/VolumeInvocationType.aidl diff --git a/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/AudioDeviceConfiguration.aidl b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/AudioDeviceConfiguration.aidl new file mode 100644 index 0000000000..2685f58485 --- /dev/null +++ b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/AudioDeviceConfiguration.aidl @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.automotive.audiocontrol; +@JavaDerive(equals=true, toString=true) @VintfStability +parcelable AudioDeviceConfiguration { + android.hardware.automotive.audiocontrol.RoutingDeviceConfiguration routingConfig; + boolean useCoreAudioVolume; + boolean useHalDuckingSignals; + boolean useCarVolumeGroupMuting; +} diff --git a/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/AudioFadeConfiguration.aidl b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/AudioFadeConfiguration.aidl new file mode 100644 index 0000000000..0a3c677036 --- /dev/null +++ b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/AudioFadeConfiguration.aidl @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.automotive.audiocontrol; +@JavaDerive(equals=true, toString=true) @VintfStability +parcelable AudioFadeConfiguration { + String name; + android.hardware.automotive.audiocontrol.FadeState fadeState; + long fadeInDurationMs = DEFAULT_FADE_IN_DURATION_MS /* 1000 */; + long fadeOutDurationMs = DEFAULT_FADE_OUT_DURATION_MS /* 2000 */; + long fadeInDelayedForOffendersMs = DEFAULT_DELAY_FADE_IN_OFFENDERS_MS /* 2000 */; + android.media.audio.common.AudioUsage[] fadeableUsages; + @nullable android.media.audio.common.AudioContentType[] unfadeableContentTypes; + List unfadableAudioAttributes; + List fadeOutConfigurations; + List fadeInConfigurations; + const long DEFAULT_FADE_IN_DURATION_MS = 1000; + const long DEFAULT_FADE_OUT_DURATION_MS = 2000; + const long DEFAULT_DELAY_FADE_IN_OFFENDERS_MS = 2000; +} diff --git a/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/AudioFocusChange.aidl b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/AudioFocusChange.aidl index 58a36673cd..8eab521ce4 100644 --- a/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/AudioFocusChange.aidl +++ b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/AudioFocusChange.aidl @@ -39,7 +39,7 @@ enum AudioFocusChange { GAIN_TRANSIENT = 2, GAIN_TRANSIENT_MAY_DUCK = 3, GAIN_TRANSIENT_EXCLUSIVE = 4, - LOSS = -1, - LOSS_TRANSIENT = -2, - LOSS_TRANSIENT_CAN_DUCK = -3, + LOSS = ((-1) * GAIN) /* -1 */, + LOSS_TRANSIENT = ((-1) * GAIN_TRANSIENT) /* -2 */, + LOSS_TRANSIENT_CAN_DUCK = ((-1) * GAIN_TRANSIENT_MAY_DUCK) /* -3 */, } diff --git a/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/AudioZone.aidl b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/AudioZone.aidl new file mode 100644 index 0000000000..2cb176078e --- /dev/null +++ b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/AudioZone.aidl @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.automotive.audiocontrol; +@JavaDerive(equals=true, toString=true) @VintfStability +parcelable AudioZone { + String name; + int id; + int occupantZoneId = UNASSIGNED_OCCUPANT /* -1 */; + android.hardware.automotive.audiocontrol.AudioZoneContext audioZoneContext; + List audioZoneConfigs; + List inputAudioDevices; + const int PRIMARY_AUDIO_ZONE = 0; + const int UNASSIGNED_OCCUPANT = (-1) /* -1 */; +} diff --git a/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/AudioZoneConfig.aidl b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/AudioZoneConfig.aidl new file mode 100644 index 0000000000..3fd37bc1cf --- /dev/null +++ b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/AudioZoneConfig.aidl @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.automotive.audiocontrol; +@JavaDerive(equals=true, toString=true) @VintfStability +parcelable AudioZoneConfig { + String name; + boolean isDefault; + List volumeGroups; + @nullable android.hardware.automotive.audiocontrol.AudioZoneFadeConfiguration fadeConfiguration; +} diff --git a/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/AudioZoneContext.aidl b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/AudioZoneContext.aidl new file mode 100644 index 0000000000..0f8b946e30 --- /dev/null +++ b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/AudioZoneContext.aidl @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.automotive.audiocontrol; +@JavaDerive(equals=true, toString=true) @VintfStability +parcelable AudioZoneContext { + List audioContextInfos; +} diff --git a/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/AudioZoneContextInfo.aidl b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/AudioZoneContextInfo.aidl new file mode 100644 index 0000000000..01ab1be643 --- /dev/null +++ b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/AudioZoneContextInfo.aidl @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.automotive.audiocontrol; +@JavaDerive(equals=true, toString=true) @VintfStability +parcelable AudioZoneContextInfo { + String name; + int id = UNASSIGNED_CONTEXT_ID /* -1 */; + List audioAttributes; + const int UNASSIGNED_CONTEXT_ID = (-1) /* -1 */; +} diff --git a/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/AudioZoneFadeConfiguration.aidl b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/AudioZoneFadeConfiguration.aidl new file mode 100644 index 0000000000..f3f32bf6f3 --- /dev/null +++ b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/AudioZoneFadeConfiguration.aidl @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.automotive.audiocontrol; +@JavaDerive(equals=true, toString=true) @VintfStability +parcelable AudioZoneFadeConfiguration { + android.hardware.automotive.audiocontrol.AudioFadeConfiguration defaultConfiguration; + List transientConfiguration; +} diff --git a/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/DeviceToContextEntry.aidl b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/DeviceToContextEntry.aidl new file mode 100644 index 0000000000..923b0bdc48 --- /dev/null +++ b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/DeviceToContextEntry.aidl @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.automotive.audiocontrol; +@JavaDerive(equals=true, toString=true) @VintfStability +parcelable DeviceToContextEntry { + List contextNames; + android.media.audio.common.AudioPort device; +} diff --git a/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/FadeConfiguration.aidl b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/FadeConfiguration.aidl new file mode 100644 index 0000000000..2c978e75ad --- /dev/null +++ b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/FadeConfiguration.aidl @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.automotive.audiocontrol; +@JavaDerive(equals=true, toString=true) @VintfStability +parcelable FadeConfiguration { + long fadeDurationMillis; + android.hardware.automotive.audiocontrol.FadeConfiguration.AudioAttributesOrUsage audioAttributesOrUsage; + @JavaDerive(equals=true, toString=true) @VintfStability + union AudioAttributesOrUsage { + android.media.audio.common.AudioAttributes fadeAttribute; + android.media.audio.common.AudioUsage usage; + } +} diff --git a/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/FadeState.aidl b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/FadeState.aidl new file mode 100644 index 0000000000..9b25dfbdec --- /dev/null +++ b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/FadeState.aidl @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.automotive.audiocontrol; +@Backing(type="int") @JavaDerive(toString=true) @VintfStability +enum FadeState { + FADE_STATE_DISABLED, + FADE_STATE_ENABLED_DEFAULT, +} diff --git a/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/IAudioControl.aidl b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/IAudioControl.aidl index ffd575dfa4..fe39f92cc0 100644 --- a/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/IAudioControl.aidl +++ b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/IAudioControl.aidl @@ -12,6 +12,34 @@ * 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. + *//** + * Important note on Metadata: + * Metadata qualifies a playback track for an output stream. + * This is highly closed to {@link android.media.AudioAttributes}. + * It allows to identify the audio stream rendered / requesting / abandonning the focus. + * + * AudioControl 1.0 was limited to identification through {@code AttributeUsage} listed as + * {@code audioUsage} in audio_policy_configuration.xsd. + * + * Any new OEM needs would not be possible without extension. + * + * Relying on {@link android.hardware.automotive.audiocontrol.PlaybackTrackMetadata} allows + * to use a combination of {@code AttributeUsage}, {@code AttributeContentType} and + * {@code AttributeTags} to identify the use case / routing thanks to + * {@link android.media.audiopolicy.AudioProductStrategy}. + * The belonging to a strategy is deduced by an AOSP logic (in sync at native and java layer). + * + * IMPORTANT NOTE ON TAGS: + * To limit the possibilies and prevent from confusion, we expect the String to follow + * a given formalism that will be enforced. + * + * 1 / By convention, tags shall be a "key=value" pair. + * Vendor must namespace their tag's key (for example com.google.strategy=VR) to avoid conflicts. + * vendor specific applications and must be prefixed by "VX_". Vendor must + * + * 2 / Tags reported here shall be the same as the tags used to define a given + * {@link android.media.audiopolicy.AudioProductStrategy} and so in + * audio_policy_engine_configuration.xml file. */ /////////////////////////////////////////////////////////////////////////////// // THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // @@ -48,4 +76,7 @@ interface IAudioControl { oneway void registerGainCallback(in android.hardware.automotive.audiocontrol.IAudioGainCallback callback); void setModuleChangeCallback(in android.hardware.automotive.audiocontrol.IModuleChangeCallback callback); void clearModuleChangeCallback(); + android.hardware.automotive.audiocontrol.AudioDeviceConfiguration getAudioDeviceConfiguration(); + List getOutputMirroringDevices(); + List getCarAudioZones(); } diff --git a/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/Reasons.aidl b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/Reasons.aidl index c1e22d44a7..8d669850a5 100644 --- a/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/Reasons.aidl +++ b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/Reasons.aidl @@ -34,14 +34,14 @@ package android.hardware.automotive.audiocontrol; @Backing(type="int") @VintfStability enum Reasons { - FORCED_MASTER_MUTE = 1, - REMOTE_MUTE = 2, - TCU_MUTE = 4, - ADAS_DUCKING = 8, - NAV_DUCKING = 16, - PROJECTION_DUCKING = 32, - THERMAL_LIMITATION = 64, - SUSPEND_EXIT_VOL_LIMITATION = 128, - EXTERNAL_AMP_VOL_FEEDBACK = 256, - OTHER = -2147483648, + FORCED_MASTER_MUTE = 0x1, + REMOTE_MUTE = 0x2, + TCU_MUTE = 0x4, + ADAS_DUCKING = 0x8, + NAV_DUCKING = 0x10, + PROJECTION_DUCKING = 0x20, + THERMAL_LIMITATION = 0x40, + SUSPEND_EXIT_VOL_LIMITATION = 0x80, + EXTERNAL_AMP_VOL_FEEDBACK = 0x100, + OTHER = 0x80000000, } diff --git a/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/RoutingDeviceConfiguration.aidl b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/RoutingDeviceConfiguration.aidl new file mode 100644 index 0000000000..901078c696 --- /dev/null +++ b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/RoutingDeviceConfiguration.aidl @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.automotive.audiocontrol; +@JavaDerive(equals=true, toString=true) @VintfStability +enum RoutingDeviceConfiguration { + DEFAULT_AUDIO_ROUTING, + DYNAMIC_AUDIO_ROUTING, + CONFIGURABLE_AUDIO_ENGINE_ROUTING, +} diff --git a/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/TransientFadeConfigurationEntry.aidl b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/TransientFadeConfigurationEntry.aidl new file mode 100644 index 0000000000..72b247bb8e --- /dev/null +++ b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/TransientFadeConfigurationEntry.aidl @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.automotive.audiocontrol; +@JavaDerive(equals=true, toString=true) @VintfStability +parcelable TransientFadeConfigurationEntry { + android.media.audio.common.AudioUsage[] transientUsages; + android.hardware.automotive.audiocontrol.AudioFadeConfiguration transientFadeConfiguration; +} diff --git a/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/VolumeActivationConfiguration.aidl b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/VolumeActivationConfiguration.aidl new file mode 100644 index 0000000000..50b76a163e --- /dev/null +++ b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/VolumeActivationConfiguration.aidl @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.automotive.audiocontrol; +@JavaDerive(equals=true, toString=true) @VintfStability +parcelable VolumeActivationConfiguration { + @nullable String name; + List volumeActivationEntries; +} diff --git a/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/VolumeActivationConfigurationEntry.aidl b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/VolumeActivationConfigurationEntry.aidl new file mode 100644 index 0000000000..d457e57db7 --- /dev/null +++ b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/VolumeActivationConfigurationEntry.aidl @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.automotive.audiocontrol; +@JavaDerive(equals=true, toString=true) @VintfStability +parcelable VolumeActivationConfigurationEntry { + android.hardware.automotive.audiocontrol.VolumeInvocationType type = android.hardware.automotive.audiocontrol.VolumeInvocationType.ON_PLAYBACK_CHANGED; + int maxActivationVolumePercentage = DEFAULT_MAX_ACTIVATION_VALUE /* 100 */; + int minActivationVolumePercentage = DEFAULT_MIN_ACTIVATION_VALUE /* 0 */; + const int DEFAULT_MAX_ACTIVATION_VALUE = 100; + const int DEFAULT_MIN_ACTIVATION_VALUE = 0; +} diff --git a/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/VolumeGroupConfig.aidl b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/VolumeGroupConfig.aidl new file mode 100644 index 0000000000..cc90bbe77f --- /dev/null +++ b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/VolumeGroupConfig.aidl @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.automotive.audiocontrol; +@JavaDerive(equals=true, toString=true) @VintfStability +parcelable VolumeGroupConfig { + String name; + int id = UNASSIGNED_ID /* -1 */; + List carAudioRoutes; + @nullable android.hardware.automotive.audiocontrol.VolumeActivationConfiguration activationConfiguration; + const int UNASSIGNED_ID = (-1) /* -1 */; +} diff --git a/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/VolumeInvocationType.aidl b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/VolumeInvocationType.aidl new file mode 100644 index 0000000000..8ce84913ca --- /dev/null +++ b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/VolumeInvocationType.aidl @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.automotive.audiocontrol; +@Backing(type="int") @JavaDerive(toString=true) @VintfStability +enum VolumeInvocationType { + ON_PLAYBACK_CHANGED, + ON_SOURCE_CHANGED, + ON_BOOT, +} diff --git a/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/AudioDeviceConfiguration.aidl b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/AudioDeviceConfiguration.aidl new file mode 100644 index 0000000000..9b5e72422f --- /dev/null +++ b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/AudioDeviceConfiguration.aidl @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.automotive.audiocontrol; + +import android.hardware.automotive.audiocontrol.RoutingDeviceConfiguration; + +/** + * Use to configure audio configurations at boot up time. + */ +@JavaDerive(equals=true, toString=true) +@VintfStability +parcelable AudioDeviceConfiguration { + /** + * Use to configure audio device routing mechanism + */ + RoutingDeviceConfiguration routingConfig; + + /** + * Use to configure core audio volume usage in car audio service + */ + boolean useCoreAudioVolume; + + /** + * Use to determine if HAL ducking signal should be sent to audio control HAL from car audio + * service + */ + boolean useHalDuckingSignals; + + /** + * Use to determine if HAL volume signal should be sent to audio control HAL from car audio + * service + */ + boolean useCarVolumeGroupMuting; +} diff --git a/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/AudioFadeConfiguration.aidl b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/AudioFadeConfiguration.aidl new file mode 100644 index 0000000000..d3181da732 --- /dev/null +++ b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/AudioFadeConfiguration.aidl @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.automotive.audiocontrol; + +import android.hardware.automotive.audiocontrol.FadeConfiguration; +import android.hardware.automotive.audiocontrol.FadeState; +import android.media.audio.common.AudioAttributes; +import android.media.audio.common.AudioContentType; +import android.media.audio.common.AudioUsage; + +/** + * Encapsulates the audio fade configuration info + */ +@JavaDerive(equals=true, toString=true) +@VintfStability +parcelable AudioFadeConfiguration { + /** + * Default fade in duration + */ + const long DEFAULT_FADE_IN_DURATION_MS = 1000; + + /** + * Default fade out duration + */ + const long DEFAULT_FADE_OUT_DURATION_MS = 2000; + + /** + * Default delay for fade in offenders + */ + const long DEFAULT_DELAY_FADE_IN_OFFENDERS_MS = 2000; + + /** + * Audio configuration name, use for debugging purposes + */ + String name; + + /** + * Audio configuration state + */ + FadeState fadeState; + + /** + * Fade in duration in milliseconds + * + *

Use to construct the default fade in configuration. This can be overwritten for different + * attributes/usages by passing a list of fade-in configuration, + * see {@code #fadeInConfigurations} + */ + long fadeInDurationMs = DEFAULT_FADE_IN_DURATION_MS; + + /** + * Fade out duration in milliseconds + * + *

Use to construct the default fade out configuration. This can be overwritten for different + * attributes/usages by passing a list of fade-out configuration, + * see {@code #fadeOutConfigurations} + */ + long fadeOutDurationMs = DEFAULT_FADE_OUT_DURATION_MS; + + /** + * Fade in delayed duration for audio focus offender in milliseconds + */ + long fadeInDelayedForOffendersMs = DEFAULT_DELAY_FADE_IN_OFFENDERS_MS; + + /** + * List of audio attribute usage that should be faded using the parameters in + * this configuration. + * + *

If the list is empty car audio service will overwrite the list for the confgiruation with + * default usages, e.g. {AudioUsage#MEDIA, AudioUsage#GAME} + */ + AudioUsage[] fadeableUsages; + + /** + * Optional list of audio attribute content types that should not be faded. + * + **

The list can be empty in cases where there are no unfadeable content types. + * + *

If the list is not set car audio service will overwrite the list for the confgiruation + * with default content type, e.g. {AudioContentType#SPEECH}. + */ + @nullable AudioContentType[] unfadeableContentTypes; + + /** + * List of audio attribute that should not be faded. + * + *

The list can be empty in cases where there are no unfadeable attributes + */ + List unfadableAudioAttributes; + + /** + * List of fade out configutions which should apply to this audio fade configurations + * + *

The list can be empty in cases where there are no fade out configurations. + */ + List fadeOutConfigurations; + + /** + * List of fade in configutions which should apply to this audio fade configurations + * + *

The list can be empty in cases where there are no fade out configurations + */ + List fadeInConfigurations; +} diff --git a/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/AudioZone.aidl b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/AudioZone.aidl new file mode 100644 index 0000000000..c90bcfd9dc --- /dev/null +++ b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/AudioZone.aidl @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.automotive.audiocontrol; + +import android.hardware.automotive.audiocontrol.AudioZoneConfig; +import android.hardware.automotive.audiocontrol.AudioZoneContext; +import android.media.audio.common.AudioPort; + +/** + * Encapsulates the audio configurations for each audio zone + */ +@JavaDerive(equals=true, toString=true) +@VintfStability +parcelable AudioZone { + /** + * Value indicating the primary audio zone + */ + const int PRIMARY_AUDIO_ZONE = 0; + + /** + * Value indicating the occupant zone is not assigned. + */ + const int UNASSIGNED_OCCUPANT = -1; + + /** + * Audio zone name, only use for debug purposes. + * + *

If present it must be non-empty otherwise car audio service will construct a name + * based on audio zone id. + */ + String name; + + /** + * Audio zone id use to distiguish between the different audio zones for + * volume management, fade, and min/max activation management. + */ + int id; + + /** + * Occupant zone id that should be mapped to this audio zone. + * + *

For audio zones not mapped to an occupant zone use UNASSIGNED_OCCUPANT + */ + int occupantZoneId = UNASSIGNED_OCCUPANT; + + /** + * Car audio context which can be used in the audio zone + */ + AudioZoneContext audioZoneContext; + + /** + * List of car audio configurations + */ + List audioZoneConfigs; + + /** + * List of input audio devices used for this zone + */ + List inputAudioDevices; +} diff --git a/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/AudioZoneConfig.aidl b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/AudioZoneConfig.aidl new file mode 100644 index 0000000000..6822da580a --- /dev/null +++ b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/AudioZoneConfig.aidl @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.automotive.audiocontrol; + +import android.hardware.automotive.audiocontrol.AudioZoneFadeConfiguration; +import android.hardware.automotive.audiocontrol.VolumeGroupConfig; + +/** + * Encapsulates the audio zone config information + */ +@JavaDerive(equals=true, toString=true) +@VintfStability +parcelable AudioZoneConfig { + /** + * Audio zone config name + * + *

Must be non-empty and unique among the configurations within a zone. + */ + String name; + + /** + * Determines if the audio configuration is the default configuration. + * + *

There can only be a single default configuration per zone. + */ + boolean isDefault; + + /** + * List car volume group that should be managed within this configuration + */ + List volumeGroups; + + /** + * Car audio zone fade configuration + */ + @nullable AudioZoneFadeConfiguration fadeConfiguration; +} diff --git a/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/AudioZoneContext.aidl b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/AudioZoneContext.aidl new file mode 100644 index 0000000000..390cb09160 --- /dev/null +++ b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/AudioZoneContext.aidl @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.automotive.audiocontrol; + +import android.hardware.automotive.audiocontrol.AudioZoneContextInfo; + +/** + * Encapsulates the list of car audio context info definitions + */ +@JavaDerive(equals=true, toString=true) +@VintfStability +parcelable AudioZoneContext { + /** + * List of car audio context info. + * + *

The list must include all audio attributes usages currently supported so that all audio + * attribute usages can be routed for each car audio configuration. + */ + List audioContextInfos; +} diff --git a/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/AudioZoneContextInfo.aidl b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/AudioZoneContextInfo.aidl new file mode 100644 index 0000000000..0ca425c044 --- /dev/null +++ b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/AudioZoneContextInfo.aidl @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.automotive.audiocontrol; + +import android.media.audio.common.AudioAttributes; + +/** + * Encapsulates groups of audio attributes which should be managed together. + */ +@JavaDerive(equals=true, toString=true) +@VintfStability +parcelable AudioZoneContextInfo { + /** + * Value indicating the context info id is not assigned. + */ + const int UNASSIGNED_CONTEXT_ID = -1; + + /** + * Context name which can be used to map the info to an audio route + * management as described in each audio configuration. + * + *

Name must be non-empty and unique among all audio context info within the same + * {@link android.hardware.automotive.audiocontrol.AudioZoneContext} container. + */ + String name; + + /** + * Used in car audio service to manage the info + * + *

Must be non-negative integer if assigned, or UNASSIGNED_CONTEXT_ID otherwise. If using + * configurable audio policy engine audio routing with multi-zone configurations the value must + * be assigned. + */ + int id = UNASSIGNED_CONTEXT_ID; + + /** + * List of audio attributes that belong to the context + */ + List audioAttributes; +} diff --git a/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/AudioZoneFadeConfiguration.aidl b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/AudioZoneFadeConfiguration.aidl new file mode 100644 index 0000000000..a604214713 --- /dev/null +++ b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/AudioZoneFadeConfiguration.aidl @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.automotive.audiocontrol; + +import android.hardware.automotive.audiocontrol.AudioFadeConfiguration; +import android.hardware.automotive.audiocontrol.TransientFadeConfigurationEntry; + +/** + * Encapsulates the audio zone fade configuration + */ +@JavaDerive(equals=true, toString=true) +@VintfStability +parcelable AudioZoneFadeConfiguration { + /** + * Defines the default fade configuration + */ + AudioFadeConfiguration defaultConfiguration; + + /** + * List of transient fade configurations. + * + *

The list can be empty if the fade configuration for the zone does not have transient fade + * configurations. + */ + List transientConfiguration; +} diff --git a/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/DeviceToContextEntry.aidl b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/DeviceToContextEntry.aidl new file mode 100644 index 0000000000..bcb5ee7c7c --- /dev/null +++ b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/DeviceToContextEntry.aidl @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.automotive.audiocontrol; + +import android.media.audio.common.AudioPort; + +/** + * Encapsulates the audio context that should be route to particular device + */ +@JavaDerive(equals=true, toString=true) +@VintfStability +parcelable DeviceToContextEntry { + /** + * List of audio context names that should be routed to the audio device. + * + *

The names must match a {@link AudioZoneContextInfo#name} in the corresponding + * {@link AudioZone#audioZoneContext). + * + *

Within a {@link AudioZoneConfig} a context name must not repeat among the different + * {@link VolumeGroupConfig}. The value can repeat among different {@link AudioZoneConfig} + * within a {@link AudioZone}. + */ + List contextNames; + + /** + * Audio port where contexts should be routed. + * + *

For dynamic devices (OUT_HEADSET, OUT_HEADPHONE, etc.) , the audio device address can be + * omitted since the information will be obtained at run time when the device is + * connected/enabled. + */ + AudioPort device; +} diff --git a/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/FadeConfiguration.aidl b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/FadeConfiguration.aidl new file mode 100644 index 0000000000..e700d6c184 --- /dev/null +++ b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/FadeConfiguration.aidl @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.automotive.audiocontrol; + +import android.media.audio.common.AudioAttributes; +import android.media.audio.common.AudioUsage; + +/** + * Encapsulates the in/out fade configuration + */ +@JavaDerive(equals=true, toString=true) +@VintfStability +parcelable FadeConfiguration { + /** + * Fade duration in milliseconds + */ + long fadeDurationMillis; + + @JavaDerive(equals=true, toString=true) + @VintfStability + union AudioAttributesOrUsage { + AudioAttributes fadeAttribute; + AudioUsage usage; + } + + /** + * Audio attribute or usage that should be impacted by the fade out duration + * {@code #fadeDurationMillis} + */ + AudioAttributesOrUsage audioAttributesOrUsage; +} diff --git a/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/FadeState.aidl b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/FadeState.aidl new file mode 100644 index 0000000000..346caae57c --- /dev/null +++ b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/FadeState.aidl @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.automotive.audiocontrol; + +/** + * Encapsulates the audio fade configuration state + */ +@VintfStability +@Backing(type="int") +@JavaDerive(toString=true) +enum FadeState { + /** + * Fade configuration should be disabled + */ + FADE_STATE_DISABLED, + /** + * Fade configuration should be enabled by default + */ + FADE_STATE_ENABLED_DEFAULT, +} diff --git a/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/IAudioControl.aidl b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/IAudioControl.aidl index 9564efc859..1202b4cd01 100644 --- a/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/IAudioControl.aidl +++ b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/IAudioControl.aidl @@ -46,14 +46,17 @@ package android.hardware.automotive.audiocontrol; * audio_policy_engine_configuration.xml file. */ import android.hardware.audio.common.PlaybackTrackMetadata; +import android.hardware.automotive.audiocontrol.AudioDeviceConfiguration; import android.hardware.automotive.audiocontrol.AudioFocusChange; import android.hardware.automotive.audiocontrol.AudioGainConfigInfo; +import android.hardware.automotive.audiocontrol.AudioZone; import android.hardware.automotive.audiocontrol.DuckingInfo; import android.hardware.automotive.audiocontrol.IAudioGainCallback; import android.hardware.automotive.audiocontrol.IFocusListener; import android.hardware.automotive.audiocontrol.IModuleChangeCallback; import android.hardware.automotive.audiocontrol.MutingInfo; import android.hardware.automotive.audiocontrol.Reasons; +import android.media.audio.common.AudioPort; /** * Interacts with the car's audio subsystem to manage audio sources and volumes @@ -206,4 +209,41 @@ interface IAudioControl { * @throws EX_UNSUPPORTED_OPERATION if dynamic audio configs are not supported. */ void clearModuleChangeCallback(); + + /** + * Returns the audio device configurations that should be used to configure + * the car audio service audio management. + * + *

If this method is not supported, car audio service will attempt to configure the car audio + * service properties based on previously supported mechanisms. + * + *

If the returned value contains the + * {@link RoutingDeviceConfiguration#DEFAULT_AUDIO_ROUTING} value, the car audio service will + * attempt to configure audio routing based on the mechanism previously supported by car audio + * service (e.g. car audio configuration file). Otherwise, the {@link #getCarAudioZones()} + * API must return valid audio zone(s) configuration(s) for the device. + * + */ + AudioDeviceConfiguration getAudioDeviceConfiguration(); + + /** + * Returns the list of audio devices that can be used for mirroring between different audio + * zones. + * + * @throws EX_UNSUPPORTED_OPERATION if mirroring devices are not supported. + */ + List getOutputMirroringDevices(); + + /** + * List of audio zones used to configure car audio service at bootup. + * + *

If the returned value from {@link #getAudioDeviceConfiguration()} contains + * {@link RoutingDeviceConfiguration#DEFAULT_AUDIO_ROUTING} value, the car audio service will + * attempt to configure the audio routing based on the mechanism previously supported by + * car audio service (e.g. car audio configuration file). Otherwise, this method must return + * valid audio zone(s) configuration(s) for the device. + * + * @throws EX_UNSUPPORTED_OPERATION if audio zone configuration are not supported. + */ + List getCarAudioZones(); } diff --git a/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/RoutingDeviceConfiguration.aidl b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/RoutingDeviceConfiguration.aidl new file mode 100644 index 0000000000..2d175401c5 --- /dev/null +++ b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/RoutingDeviceConfiguration.aidl @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.automotive.audiocontrol; + +/** + * Use to configure audio device routing mechanism + */ +@JavaDerive(equals=true, toString=true) +@VintfStability +enum RoutingDeviceConfiguration { + /** + * Use to indicate that audio should be managed based on previously supportec mechamisms in + * car audio service. + * + *

If this used then the API to setup the audio zones can just throw + * {@code EX_UNSUPPORTED_OPERATION} if called. + */ + DEFAULT_AUDIO_ROUTING, + /** + * Use to indicate that audio should be managed using the dynamic audio + * policy as setup by car audio service using the setup configuration from + * the {@Link android.hardware.automotive.audiocontrol.AudioZone}'s info from audio control HAL. + * + *

If this used then the APIs to setup the audio zones must return a valid audio zone + * configuration for the device. + */ + DYNAMIC_AUDIO_ROUTING, + /** + * Use to indicate that audio should be managed using the core audio + * routing as setup by car audio service using the setup configuration from + * the {@Link android.hardware.automotive.audiocontrol.AudioZone}'s info from audio control HAL + * and the information contained within the configurable audio policy engine. + * + *

If this used then the APIs to setup the audio zone(s) must return valid audio zone + * configuration(s) for the device. + */ + CONFIGURABLE_AUDIO_ENGINE_ROUTING, +} diff --git a/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/TransientFadeConfigurationEntry.aidl b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/TransientFadeConfigurationEntry.aidl new file mode 100644 index 0000000000..198423657f --- /dev/null +++ b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/TransientFadeConfigurationEntry.aidl @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.automotive.audiocontrol; + +import android.hardware.automotive.audiocontrol.AudioFadeConfiguration; +import android.media.audio.common.AudioUsage; + +/** + * Encapsulates the transient audio fade configuration entry. + */ +@JavaDerive(equals=true, toString=true) +@VintfStability +parcelable TransientFadeConfigurationEntry { + /** + * List of audio usages gainers that should be used for this configuration entry. + */ + AudioUsage[] transientUsages; + + /** + * Defines the transient fade configuration that should be used for the focus interaction with + * the usages defined in {@link #transientUsages} + */ + AudioFadeConfiguration transientFadeConfiguration; +} diff --git a/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/VolumeActivationConfiguration.aidl b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/VolumeActivationConfiguration.aidl new file mode 100644 index 0000000000..edc5f6010e --- /dev/null +++ b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/VolumeActivationConfiguration.aidl @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.automotive.audiocontrol; + +import android.hardware.automotive.audiocontrol.VolumeActivationConfigurationEntry; + +/** + * Use to configure audio activiations, only used at boot up time. + */ +@JavaDerive(equals=true, toString=true) +@VintfStability +parcelable VolumeActivationConfiguration { + /** + * Configuration name used for debugging purposes to identify config used. + * + *

Is present, it must be non-empty and unique for all volume acvitations, otherwise + * car audio service will construct one based on audio zone, configuration and volume group + * info. + */ + @nullable String name; + + /** + * List of activation configurations. + * + *

Car audio service currently only uses the first activation config on the list. + */ + List volumeActivationEntries; +} diff --git a/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/VolumeActivationConfigurationEntry.aidl b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/VolumeActivationConfigurationEntry.aidl new file mode 100644 index 0000000000..7072a2c84c --- /dev/null +++ b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/VolumeActivationConfigurationEntry.aidl @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.automotive.audiocontrol; + +import android.hardware.automotive.audiocontrol.VolumeInvocationType; + +/** + * Audio activiation volume configuration entry. + * + *

The entry can defined both the minimum and maximum activation values or only one. The latter + * allows activations to occur only on the minimum value or maximum value as configured. + */ +@JavaDerive(equals=true, toString=true) +@VintfStability +parcelable VolumeActivationConfigurationEntry { + /** + * Default maximum activation value. + */ + const int DEFAULT_MAX_ACTIVATION_VALUE = 100; + + /** + * Default minimum activation value. + */ + const int DEFAULT_MIN_ACTIVATION_VALUE = 0; + + /** + * Activation type, should be one of: + * ON_PLAYBACK_CHANGED, ON_SOURCE_CHANGED, ON_BOOT + */ + VolumeInvocationType type = VolumeInvocationType.ON_PLAYBACK_CHANGED; + + /** + * Max activation percentage between {@code DEFAULT_MIN_ACTIVATION_VALUE} to + * {@code DEFAULT_MAX_ACTIVATION_VALUE} percen. + * + *

The value should be {@code DEFAULT_MAX_ACTIVATION_VALUE} if max activation should not + * apply. + */ + int maxActivationVolumePercentage = DEFAULT_MAX_ACTIVATION_VALUE; + + /** + * Min activation percentage between {@code DEFAULT_MIN_ACTIVATION_VALUE} to + * {@code DEFAULT_MAX_ACTIVATION_VALUE} percent. + * + *

The value should be {@code DEFAULT_MIN_ACTIVATION_VALUE} if min activation should not + * apply. + */ + int minActivationVolumePercentage = DEFAULT_MIN_ACTIVATION_VALUE; +} diff --git a/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/VolumeGroupConfig.aidl b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/VolumeGroupConfig.aidl new file mode 100644 index 0000000000..7e3bc60da5 --- /dev/null +++ b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/VolumeGroupConfig.aidl @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.automotive.audiocontrol; + +import android.hardware.automotive.audiocontrol.DeviceToContextEntry; +import android.hardware.automotive.audiocontrol.VolumeActivationConfiguration; + +/** + * Encapsulates the audio volume grouping for audio zone config. + */ +@JavaDerive(equals=true, toString=true) +@VintfStability +parcelable VolumeGroupConfig { + /** + * Value indicating the volume group is not assigned an ID. + */ + const int UNASSIGNED_ID = -1; + + /** + * Audio zone group name. + * + *

Must be non-empty if using configurable audio policy engine volume management, see + * {@code AudioDeviceConfiguration#useCoreAudioVolume} for details. + */ + String name; + + /** + * Audio zone group id. + * + *

Must be set if using configurable audio policy engine volume management, can be + * {@code #UNASSIGNED_ID} otherwise. See {@code AudioDeviceConfiguration#useCoreAudioVolume} + * for details. + */ + int id = UNASSIGNED_ID; + + /** + * Entries of audio device to audio context that are managed similarly for this volume group. + */ + List carAudioRoutes; + + /** + * Optional volume activation configuration that should be used for this volume group. + */ + @nullable VolumeActivationConfiguration activationConfiguration; +} diff --git a/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/VolumeInvocationType.aidl b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/VolumeInvocationType.aidl new file mode 100644 index 0000000000..0323505048 --- /dev/null +++ b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/VolumeInvocationType.aidl @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.automotive.audiocontrol; + +/** + * Audio activiation type which can be used to activate the min/max + * volume changes. + */ +@VintfStability +@Backing(type="int") +@JavaDerive(toString=true) +enum VolumeInvocationType { + /** + * Invocation of volume group activation performed at every playback change. + */ + ON_PLAYBACK_CHANGED, + /** + * Invocation of volume group activation performed only once at playback after first playback + * for a client (app/service UID). + */ + ON_SOURCE_CHANGED, + /** + * Invocation of volume group activation in perform only at playback once after boot up. + */ + ON_BOOT, +} diff --git a/automotive/audiocontrol/aidl/default/AudioControl.cpp b/automotive/audiocontrol/aidl/default/AudioControl.cpp index 7e7e145d37..730aee8dcb 100644 --- a/automotive/audiocontrol/aidl/default/AudioControl.cpp +++ b/automotive/audiocontrol/aidl/default/AudioControl.cpp @@ -19,6 +19,7 @@ #include "AudioControl.h" +#include #include #include #include @@ -256,6 +257,15 @@ static inline std::string toEnumString(const std::vector& in_val }); } +template +static inline std::string toString(const std::vector>& in_values) { + return std::accumulate(std::begin(in_values), std::end(in_values), std::string{}, + [](const std::string& ls, const std::optional& rs) { + return ls + (ls.empty() ? "" : ",") + + (rs.has_value() ? rs.value().toString() : "empty"); + }); +} + ndk::ScopedAStatus AudioControl::onAudioFocusChangeWithMetaData( const audiohalcommon::PlaybackTrackMetadata& in_playbackMetaData, int32_t in_zoneId, AudioFocusChange in_focusChange) { @@ -309,6 +319,27 @@ ndk::ScopedAStatus AudioControl::clearModuleChangeCallback() { return ndk::ScopedAStatus::ok(); } +ndk::ScopedAStatus AudioControl::getAudioDeviceConfiguration( + AudioDeviceConfiguration* audioDeviceConfig) { + LOG(DEBUG) << ":" << __func__ << "audioDeviceConfig" << audioDeviceConfig->toString(); + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus AudioControl::getOutputMirroringDevices( + std::vector* mirroringDevices) { + for (const auto& mirroringDevice : *mirroringDevices) { + LOG(DEBUG) << ":" << __func__ << "Mirror device: " << mirroringDevice.toString().c_str(); + } + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus AudioControl::getCarAudioZones(std::vector* audioZones) { + for (const auto& audioZone : *audioZones) { + LOG(DEBUG) << ":" << __func__ << "Audio zone: " << audioZone.toString().c_str(); + } + return ndk::ScopedAStatus::ok(); +} + binder_status_t AudioControl::dump(int fd, const char** args, uint32_t numArgs) { if (numArgs == 0) { return dumpsys(fd); diff --git a/automotive/audiocontrol/aidl/default/AudioControl.h b/automotive/audiocontrol/aidl/default/AudioControl.h index 7eca446f12..cc06ab281a 100644 --- a/automotive/audiocontrol/aidl/default/AudioControl.h +++ b/automotive/audiocontrol/aidl/default/AudioControl.h @@ -63,6 +63,11 @@ class AudioControl : public BnAudioControl { ndk::ScopedAStatus setModuleChangeCallback( const std::shared_ptr& in_callback) override; ndk::ScopedAStatus clearModuleChangeCallback() override; + ndk::ScopedAStatus getAudioDeviceConfiguration( + AudioDeviceConfiguration* audioDeviceConfig) override; + ndk::ScopedAStatus getOutputMirroringDevices( + std::vector<::aidl::android::media::audio::common::AudioPort>* mirrorDevices) override; + ndk::ScopedAStatus getCarAudioZones(std::vector* audioZones) override; binder_status_t dump(int fd, const char** args, uint32_t numArgs) override; diff --git a/automotive/audiocontrol/aidl/rust_impl/Android.bp b/automotive/audiocontrol/aidl/rust_impl/Android.bp index 062d989bab..f9d07b22ce 100644 --- a/automotive/audiocontrol/aidl/rust_impl/Android.bp +++ b/automotive/audiocontrol/aidl/rust_impl/Android.bp @@ -15,7 +15,7 @@ */ rust_binary { - name: "android.hardware.automotive.audiocontrol-V4-rust-service", + name: "android.hardware.automotive.audiocontrol-rust-service", relative_install_path: "hw", vendor: true, srcs: ["src/*.rs"], @@ -23,6 +23,7 @@ rust_binary { defaults: [ "latest_android_hardware_automotive_audiocontrol_rust", "latest_android_hardware_audio_common_rust", + "latest_android_media_audio_common_types_rust", ], vintf_fragments: ["audiocontrol-rust-service.xml"], init_rc: ["audiocontrol-rust-service.rc"], diff --git a/automotive/audiocontrol/aidl/rust_impl/README.md b/automotive/audiocontrol/aidl/rust_impl/README.md index ed22356920..b68daf3f87 100644 --- a/automotive/audiocontrol/aidl/rust_impl/README.md +++ b/automotive/audiocontrol/aidl/rust_impl/README.md @@ -6,7 +6,7 @@ not contain any actual implementation. This folder contains a skeleton audio control HAL implementation in Rust to demonstrate how vendor may implement a Rust audio control HAL. To run this audio control HAL, include -`android.hardware.automotive.audiocontrol-V4-rust-service` in your image. +`android.hardware.automotive.audiocontrol-rust-service` in your image. This implementation returns `StatusCode::UNKNOWN_ERROR` for all operations and does not pass VTS/CTS. Vendor must replace the logic in diff --git a/automotive/audiocontrol/aidl/rust_impl/src/default_audio_control_hal.rs b/automotive/audiocontrol/aidl/rust_impl/src/default_audio_control_hal.rs index ba0ca238f4..8184c436fc 100644 --- a/automotive/audiocontrol/aidl/rust_impl/src/default_audio_control_hal.rs +++ b/automotive/audiocontrol/aidl/rust_impl/src/default_audio_control_hal.rs @@ -23,8 +23,15 @@ use android_hardware_automotive_audiocontrol::aidl::android::hardware::automotiv IModuleChangeCallback::IModuleChangeCallback, MutingInfo::MutingInfo, Reasons::Reasons, + AudioDeviceConfiguration::AudioDeviceConfiguration, + AudioZone::AudioZone +}; +use android_hardware_audio_common::aidl::android::hardware::audio::common::{ + PlaybackTrackMetadata::PlaybackTrackMetadata, +}; +use android_media_audio_common_types::aidl::android::media::audio::common::{ + AudioPort::AudioPort, }; -use android_hardware_audio_common::aidl::android::hardware::audio::common::PlaybackTrackMetadata::PlaybackTrackMetadata; use binder::{Interface, Result as BinderResult, StatusCode, Strong}; /// This struct is defined to implement IAudioControl AIDL interface. @@ -81,4 +88,16 @@ impl IAudioControl for DefaultAudioControlHal { fn clearModuleChangeCallback(&self) -> BinderResult<()> { Err(StatusCode::UNKNOWN_ERROR.into()) } + + fn getAudioDeviceConfiguration(&self) -> std::result::Result { + Err(binder::StatusCode::UNKNOWN_ERROR.into()) + } + + fn getOutputMirroringDevices(&self) -> std::result::Result, binder::Status> { + Err(binder::StatusCode::UNKNOWN_ERROR.into()) + } + + fn getCarAudioZones(&self) -> std::result::Result, binder::Status> { + Err(binder::StatusCode::UNKNOWN_ERROR.into()) + } } From 2bf55fb661ea28f8faf7372c5a7ebd4a6d28d07d Mon Sep 17 00:00:00 2001 From: Oscar Azucena Date: Fri, 27 Sep 2024 23:18:57 -0700 Subject: [PATCH 2/3] Add default implementation to load current XML Added support to the default configuration to load the current car audio configuration file. This will load the all the required info for the configuration. Bug: 359686069 Test: m -j, presubmit Flag: EXEMPT HAL interface Change-Id: Ibe520b468ab145518f56dd26f0cceda970c6f226 --- .../audiocontrol/aidl/default/Android.bp | 8 +- .../aidl/default/AudioControl.cpp | 128 +- .../audiocontrol/aidl/default/AudioControl.h | 9 +- .../aidl/default/converter/Android.bp | 56 + .../include/CarAudioConfigurationUtils.h | 37 + .../CarAudioConfigurationXmlConverter.h | 87 ++ .../src/CarAudioConfigurationUtils.cpp | 104 ++ .../src/CarAudioConfigurationXmlConverter.cpp | 1134 +++++++++++++++++ .../aidl/default/converter/test/Android.bp | 63 + .../test/AudioControlConverterUnitTest.cpp | 834 ++++++++++++ ...dio_configuration_with_default_context.xml | 56 + ...audio_configuration_with_missing_zones.xml | 92 ++ ...audio_configuration_without_audio_zone.xml | 90 ++ ...io_configuration_without_configuration.xml | 15 + .../test/car_audio_fade_configuration.xml | 191 +++ .../multi_zone_car_audio_configuration.xml | 196 +++ .../test/simple_car_audio_configuration.xml | 233 ++++ ...r_audio_configuration_with_device_type.xml | 233 ++++ .../aidl/default/loaders/config/Android.bp | 45 + .../default/loaders/config/api/current.txt | 331 +++++ .../loaders/config/api/last_current.txt | 0 .../loaders/config/api/last_removed.txt | 0 .../default/loaders/config/api/removed.txt | 1 + .../config/car_audio_configuration.xsd | 248 ++++ .../aidl/default/loaders/fade/Android.bp | 45 + .../aidl/default/loaders/fade/api/current.txt | 160 +++ .../default/loaders/fade/api/last_current.txt | 0 .../default/loaders/fade/api/last_removed.txt | 0 .../aidl/default/loaders/fade/api/removed.txt | 1 + .../fade/car_fade_audio_configuration.xsd | 118 ++ 30 files changed, 4499 insertions(+), 16 deletions(-) create mode 100644 automotive/audiocontrol/aidl/default/converter/Android.bp create mode 100644 automotive/audiocontrol/aidl/default/converter/include/CarAudioConfigurationUtils.h create mode 100644 automotive/audiocontrol/aidl/default/converter/include/CarAudioConfigurationXmlConverter.h create mode 100644 automotive/audiocontrol/aidl/default/converter/src/CarAudioConfigurationUtils.cpp create mode 100644 automotive/audiocontrol/aidl/default/converter/src/CarAudioConfigurationXmlConverter.cpp create mode 100644 automotive/audiocontrol/aidl/default/converter/test/Android.bp create mode 100644 automotive/audiocontrol/aidl/default/converter/test/AudioControlConverterUnitTest.cpp create mode 100644 automotive/audiocontrol/aidl/default/converter/test/car_audio_configuration_with_default_context.xml create mode 100644 automotive/audiocontrol/aidl/default/converter/test/car_audio_configuration_with_missing_zones.xml create mode 100644 automotive/audiocontrol/aidl/default/converter/test/car_audio_configuration_without_audio_zone.xml create mode 100644 automotive/audiocontrol/aidl/default/converter/test/car_audio_configuration_without_configuration.xml create mode 100644 automotive/audiocontrol/aidl/default/converter/test/car_audio_fade_configuration.xml create mode 100644 automotive/audiocontrol/aidl/default/converter/test/multi_zone_car_audio_configuration.xml create mode 100644 automotive/audiocontrol/aidl/default/converter/test/simple_car_audio_configuration.xml create mode 100644 automotive/audiocontrol/aidl/default/converter/test/simple_car_audio_configuration_with_device_type.xml create mode 100644 automotive/audiocontrol/aidl/default/loaders/config/Android.bp create mode 100644 automotive/audiocontrol/aidl/default/loaders/config/api/current.txt create mode 100644 automotive/audiocontrol/aidl/default/loaders/config/api/last_current.txt create mode 100644 automotive/audiocontrol/aidl/default/loaders/config/api/last_removed.txt create mode 100644 automotive/audiocontrol/aidl/default/loaders/config/api/removed.txt create mode 100644 automotive/audiocontrol/aidl/default/loaders/config/car_audio_configuration.xsd create mode 100644 automotive/audiocontrol/aidl/default/loaders/fade/Android.bp create mode 100644 automotive/audiocontrol/aidl/default/loaders/fade/api/current.txt create mode 100644 automotive/audiocontrol/aidl/default/loaders/fade/api/last_current.txt create mode 100644 automotive/audiocontrol/aidl/default/loaders/fade/api/last_removed.txt create mode 100644 automotive/audiocontrol/aidl/default/loaders/fade/api/removed.txt create mode 100644 automotive/audiocontrol/aidl/default/loaders/fade/car_fade_audio_configuration.xsd diff --git a/automotive/audiocontrol/aidl/default/Android.bp b/automotive/audiocontrol/aidl/default/Android.bp index fd7e167545..1c11c989b7 100644 --- a/automotive/audiocontrol/aidl/default/Android.bp +++ b/automotive/audiocontrol/aidl/default/Android.bp @@ -31,13 +31,19 @@ cc_binary { "latest_android_hardware_audio_common_ndk_shared", "latest_android_hardware_automotive_audiocontrol_ndk_shared", "powerpolicyclient_defaults", + "car.audio.configuration.xsd.default", + "car.fade.configuration.xsd.default", ], shared_libs: [ "android.hardware.audio.common@7.0-enums", - "libbase", "libbinder_ndk", "libcutils", "liblog", + "libbase", + "libxml2", + "libutils", + "android.hardware.audiocontrol.internal", + "libaudio_aidl_conversion_common_ndk", ], srcs: [ "AudioControl.cpp", diff --git a/automotive/audiocontrol/aidl/default/AudioControl.cpp b/automotive/audiocontrol/aidl/default/AudioControl.cpp index 730aee8dcb..9ae422b1cf 100644 --- a/automotive/audiocontrol/aidl/default/AudioControl.cpp +++ b/automotive/audiocontrol/aidl/default/AudioControl.cpp @@ -28,8 +28,8 @@ #include #include #include - #include + #include #include @@ -42,16 +42,18 @@ using ::android::base::EqualsIgnoreCase; using ::android::base::ParseBool; using ::android::base::ParseBoolResult; using ::android::base::ParseInt; +using ::android::hardware::audiocontrol::internal::CarAudioConfigurationXmlConverter; using ::std::shared_ptr; using ::std::string; -namespace xsd { -using namespace ::android::audio::policy::configuration::V7_0; +namespace converter { +using namespace ::android::hardware::audiocontrol::internal; } +namespace api = aidl::android::hardware::automotive::audiocontrol; +namespace xsd = ::android::audio::policy::configuration::V7_0; + namespace { -const float kLowerBound = -1.0f; -const float kUpperBound = 1.0f; bool checkCallerHasWritePermissions(int fd) { // Double check that's only called by root - it should be be blocked at debug() level, // but it doesn't hurt to make sure... @@ -63,7 +65,7 @@ bool checkCallerHasWritePermissions(int fd) { } bool isValidValue(float value) { - return (value >= kLowerBound) && (value <= kUpperBound); + return (value >= -1.0f) && (value <= 1.0f); } bool safelyParseInt(string s, int* out) { @@ -72,6 +74,53 @@ bool safelyParseInt(string s, int* out) { } return true; } + +std::string formatDump(const std::string& input) { + const char kSpacer = ' '; + std::string output; + int indentLevel = 0; + bool newLine = false; + + for (char c : input) { + switch (c) { + case '{': + if (!newLine) { + output += '\n'; + } + newLine = true; + indentLevel++; + for (int i = 0; i < indentLevel; ++i) { + output += kSpacer; + } + break; + case '}': + if (!newLine) { + output += '\n'; + } + newLine = true; + indentLevel--; + for (int i = 0; i < indentLevel; ++i) { + output += kSpacer; + } + break; + case ',': + if (!newLine) { + output += '\n'; + } + newLine = true; + for (int i = 0; i < indentLevel; ++i) { + output += kSpacer; + } + break; + default: + newLine = false; + output += c; + } + } + + return output; +} + } // namespace namespace { @@ -91,6 +140,9 @@ using ::aidl::android::media::audio::common::AudioPortMixExt; using ::aidl::android::media::audio::common::AudioProfile; using ::aidl::android::media::audio::common::PcmType; +const static std::string kAudioConfigFile = "/vendor/etc/car_audio_configuration.xml"; +const static std::string kFadeConfigFile = "/vendor/etc/car_audio_fade_configuration.xml"; + // reuse common code artifacts void fillProfile(const std::vector& channelLayouts, const std::vector& sampleRates, AudioProfile* profile) { @@ -163,6 +215,12 @@ AudioGain createGain(int32_t mode, AudioChannelLayout channelMask, int32_t minVa } } // namespace +AudioControl::AudioControl() : AudioControl(kAudioConfigFile, kFadeConfigFile) {} + +AudioControl::AudioControl(const std::string& carAudioConfig, const std::string& audioFadeConfig) + : mCarAudioConfigurationConverter(std::make_shared( + carAudioConfig, audioFadeConfig)) {} + ndk::ScopedAStatus AudioControl::registerFocusListener( const shared_ptr& in_listener) { LOG(DEBUG) << "registering focus listener"; @@ -246,14 +304,14 @@ template static inline std::string toString(const std::vector& in_values) { return std::accumulate(std::begin(in_values), std::end(in_values), std::string{}, [](const std::string& ls, const aidl_type& rs) { - return ls + (ls.empty() ? "" : ",") + rs.toString(); + return ls + (ls.empty() ? "" : ", ") + rs.toString(); }); } template static inline std::string toEnumString(const std::vector& in_values) { return std::accumulate(std::begin(in_values), std::end(in_values), std::string{}, [](const std::string& ls, const aidl_enum_type& rs) { - return ls + (ls.empty() ? "" : ",") + toString(rs); + return ls + (ls.empty() ? "" : ", ") + toString(rs); }); } @@ -261,7 +319,7 @@ template static inline std::string toString(const std::vector>& in_values) { return std::accumulate(std::begin(in_values), std::end(in_values), std::string{}, [](const std::string& ls, const std::optional& rs) { - return ls + (ls.empty() ? "" : ",") + + return ls + (ls.empty() ? "" : ", ") + (rs.has_value() ? rs.value().toString() : "empty"); }); } @@ -321,22 +379,45 @@ ndk::ScopedAStatus AudioControl::clearModuleChangeCallback() { ndk::ScopedAStatus AudioControl::getAudioDeviceConfiguration( AudioDeviceConfiguration* audioDeviceConfig) { - LOG(DEBUG) << ":" << __func__ << "audioDeviceConfig" << audioDeviceConfig->toString(); + if (!audioDeviceConfig) { + LOG(ERROR) << __func__ << "Audio device configuration must not be null"; + return ndk::ScopedAStatus::fromStatus(STATUS_UNEXPECTED_NULL); + } + if (!mCarAudioConfigurationConverter) { + return ndk::ScopedAStatus::ok(); + } + const auto& innerDeviceConfig = mCarAudioConfigurationConverter->getAudioDeviceConfiguration(); + audioDeviceConfig->routingConfig = innerDeviceConfig.routingConfig; + audioDeviceConfig->useCoreAudioVolume = innerDeviceConfig.useCoreAudioVolume; + audioDeviceConfig->useCarVolumeGroupMuting = innerDeviceConfig.useCarVolumeGroupMuting; + audioDeviceConfig->useHalDuckingSignals = innerDeviceConfig.useHalDuckingSignals; return ndk::ScopedAStatus::ok(); } ndk::ScopedAStatus AudioControl::getOutputMirroringDevices( std::vector* mirroringDevices) { - for (const auto& mirroringDevice : *mirroringDevices) { - LOG(DEBUG) << ":" << __func__ << "Mirror device: " << mirroringDevice.toString().c_str(); + if (!mirroringDevices) { + LOG(ERROR) << __func__ << "Mirroring devices must not be null"; + return ndk::ScopedAStatus::fromStatus(STATUS_UNEXPECTED_NULL); } + if (!mCarAudioConfigurationConverter || !mCarAudioConfigurationConverter->getErrors().empty()) { + return ndk::ScopedAStatus::ok(); + } + const auto& innerDevice = mCarAudioConfigurationConverter->getOutputMirroringDevices(); + mirroringDevices->insert(mirroringDevices->end(), innerDevice.begin(), innerDevice.end()); return ndk::ScopedAStatus::ok(); } ndk::ScopedAStatus AudioControl::getCarAudioZones(std::vector* audioZones) { - for (const auto& audioZone : *audioZones) { - LOG(DEBUG) << ":" << __func__ << "Audio zone: " << audioZone.toString().c_str(); + if (!audioZones) { + LOG(ERROR) << __func__ << "Audio zones must not be null"; + return ndk::ScopedAStatus::fromStatus(STATUS_UNEXPECTED_NULL); } + if (!mCarAudioConfigurationConverter || !mCarAudioConfigurationConverter->getErrors().empty()) { + return ndk::ScopedAStatus::ok(); + } + const auto& innerZones = mCarAudioConfigurationConverter->getAudioZones(); + audioZones->insert(audioZones->end(), innerZones.begin(), innerZones.end()); return ndk::ScopedAStatus::ok(); } @@ -373,6 +454,25 @@ binder_status_t AudioControl::dumpsys(int fd) { dprintf(fd, "Focus listener registered\n"); } dprintf(fd, "AudioGainCallback %sregistered\n", (mAudioGainCallback == nullptr ? "NOT " : "")); + + AudioDeviceConfiguration configuration; + if (getAudioDeviceConfiguration(&configuration).isOk()) { + dprintf(fd, "AudioDeviceConfiguration: %s\n", configuration.toString().c_str()); + } + std::vector audioZones; + if (getCarAudioZones(&audioZones).isOk()) { + dprintf(fd, "Audio zones count: %zu\n", audioZones.size()); + for (const auto& zone : audioZones) { + dprintf(fd, "AudioZone: %s\n", formatDump(zone.toString()).c_str()); + } + } + std::vector mirroringDevices; + if (getOutputMirroringDevices(&mirroringDevices).isOk()) { + dprintf(fd, "Mirroring devices count: %zu\n", mirroringDevices.size()); + for (const auto& device : mirroringDevices) { + dprintf(fd, "Mirroring device: %s\n", formatDump(device.toString()).c_str()); + } + } return STATUS_OK; } diff --git a/automotive/audiocontrol/aidl/default/AudioControl.h b/automotive/audiocontrol/aidl/default/AudioControl.h index cc06ab281a..0425570e2b 100644 --- a/automotive/audiocontrol/aidl/default/AudioControl.h +++ b/automotive/audiocontrol/aidl/default/AudioControl.h @@ -35,13 +35,17 @@ #include #include +#include "converter/include/CarAudioConfigurationXmlConverter.h" + namespace aidl::android::hardware::automotive::audiocontrol { -namespace audiohalcommon = ::aidl::android::hardware::audio::common; namespace audiomediacommon = ::aidl::android::media::audio::common; +namespace audiohalcommon = ::aidl::android::hardware::audio::common; class AudioControl : public BnAudioControl { public: + AudioControl(); + AudioControl(const std::string& carAudioConfig, const std::string& audioFadeConfig); ndk::ScopedAStatus onAudioFocusChange(const std::string& in_usage, int32_t in_zoneId, AudioFocusChange in_focusChange) override; ndk::ScopedAStatus onDevicesToDuckChange( @@ -86,6 +90,9 @@ class AudioControl : public BnAudioControl { std::shared_ptr mModuleChangeCallback = nullptr; + std::shared_ptr<::android::hardware::audiocontrol::internal::CarAudioConfigurationXmlConverter> + mCarAudioConfigurationConverter = nullptr; + binder_status_t cmdHelp(int fd) const; binder_status_t cmdRequestFocus(int fd, const char** args, uint32_t numArgs); binder_status_t cmdAbandonFocus(int fd, const char** args, uint32_t numArgs); diff --git a/automotive/audiocontrol/aidl/default/converter/Android.bp b/automotive/audiocontrol/aidl/default/converter/Android.bp new file mode 100644 index 0000000000..c00afa2dbf --- /dev/null +++ b/automotive/audiocontrol/aidl/default/converter/Android.bp @@ -0,0 +1,56 @@ +// Copyright (C) 2024 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "hardware_interfaces_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["hardware_interfaces_license"], +} + +cc_library { + name: "android.hardware.audiocontrol.internal", + vendor: true, + srcs: [ + "src/CarAudioConfigurationXmlConverter.cpp", + "src/CarAudioConfigurationUtils.cpp", + ], + export_include_dirs: [ + "include", + ], + defaults: [ + "latest_android_hardware_audio_common_ndk_static", + "latest_android_hardware_automotive_audiocontrol_ndk_shared", + "car.audio.configuration.xsd.default", + "car.fade.configuration.xsd.default", + "aidlaudioservice_defaults", + "latest_android_media_audio_common_types_ndk_static", + ], + shared_libs: [ + "libbase", + "libutils", + "libmedia_helper", + "car.audio.configuration.xsd.default", + "car.fade.configuration.xsd.default", + "liblog", + ], + static_libs: [ + "libaudio_aidl_conversion_common_ndk_cpp", + ], + header_libs: [ + "libaudio_system_headers", + ], +} diff --git a/automotive/audiocontrol/aidl/default/converter/include/CarAudioConfigurationUtils.h b/automotive/audiocontrol/aidl/default/converter/include/CarAudioConfigurationUtils.h new file mode 100644 index 0000000000..29fec0b1f1 --- /dev/null +++ b/automotive/audiocontrol/aidl/default/converter/include/CarAudioConfigurationUtils.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_HARDWARE_AUDIOCONTROL_INTERNAL_CONFIGURATION_UTILS_H +#define ANDROID_HARDWARE_AUDIOCONTROL_INTERNAL_CONFIGURATION_UTILS_H + +#include + +#include +#include + +namespace android { +namespace hardware { +namespace audiocontrol { +namespace internal { + +::aidl::android::hardware::automotive::audiocontrol::AudioZoneContext getDefaultCarAudioContext(); + +} // namespace internal +} // namespace audiocontrol +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_AUDIOCONTROL_INTERNAL_CONFIGURATION_UTILS_H diff --git a/automotive/audiocontrol/aidl/default/converter/include/CarAudioConfigurationXmlConverter.h b/automotive/audiocontrol/aidl/default/converter/include/CarAudioConfigurationXmlConverter.h new file mode 100644 index 0000000000..ed29172cf5 --- /dev/null +++ b/automotive/audiocontrol/aidl/default/converter/include/CarAudioConfigurationXmlConverter.h @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MAIN8_CARAUDIOCONFIGURATIONXMLCONVERTER_H +#define MAIN8_CARAUDIOCONFIGURATIONXMLCONVERTER_H + +#include + +#include "../include/CarAudioConfigurationUtils.h" + +#include +#include +#include + +namespace android::hardware::automotive::audiocontrol { +class CarAudioConfigurationType; +} + +namespace android { +namespace hardware { +namespace audiocontrol { +namespace internal { + +class CarAudioConfigurationXmlConverter { + public: + explicit CarAudioConfigurationXmlConverter(const std::string& audioConfigFile, + const std::string& fadeConfigFile) + : mAudioConfigFile(audioConfigFile), mFadeConfigFile(fadeConfigFile) { + init(); + } + + ::aidl::android::hardware::automotive::audiocontrol::AudioDeviceConfiguration + getAudioDeviceConfiguration() const; + + std::vector<::aidl::android::hardware::automotive::audiocontrol::AudioZone> getAudioZones() + const; + std::vector<::aidl::android::media::audio::common::AudioPort> getOutputMirroringDevices() const; + + const std::string getErrors() const { return mParseErrors; } + + private: + void init(); + void initNonDynamicRouting(); + void initFadeConfigurations(); + void initAudioDeviceConfiguration( + const ::android::hardware::automotive::audiocontrol::CarAudioConfigurationType& + carAudioConfigurationType); + void initCarAudioConfigurations( + const ::android::hardware::automotive::audiocontrol::CarAudioConfigurationType& + carAudioConfigurationType); + void parseAudioDeviceConfigurations( + const ::android::hardware::automotive::audiocontrol::CarAudioConfigurationType& + carAudioConfigurationType); + + const std::string mAudioConfigFile; + const std::string mFadeConfigFile; + ::aidl::android::hardware::automotive::audiocontrol::AudioDeviceConfiguration + mAudioDeviceConfiguration; + std::optional<::aidl::android::hardware::automotive::audiocontrol::AudioZoneContext> + mAudioZoneContext; + std::vector<::aidl::android::hardware::automotive::audiocontrol::AudioZone> mAudioZones; + std::vector<::aidl::android::media::audio::common::AudioPort> mOutputMirroringDevices; + std::string mParseErrors; + std::unordered_map + mFadeConfigurations; +}; + +} // namespace internal +} // namespace audiocontrol +} // namespace hardware +} // namespace android + +#endif // MAIN8_CARAUDIOCONFIGURATIONXMLCONVERTER_H diff --git a/automotive/audiocontrol/aidl/default/converter/src/CarAudioConfigurationUtils.cpp b/automotive/audiocontrol/aidl/default/converter/src/CarAudioConfigurationUtils.cpp new file mode 100644 index 0000000000..e2f81915c4 --- /dev/null +++ b/automotive/audiocontrol/aidl/default/converter/src/CarAudioConfigurationUtils.cpp @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "../include/CarAudioConfigurationUtils.h" + +#include +#include + +#include +#include + +using ::aidl::android::hardware::automotive::audiocontrol::AudioZoneContext; +using ::aidl::android::hardware::automotive::audiocontrol::AudioZoneContextInfo; + +using aidl::android::media::audio::common::AudioAttributes; +using aidl::android::media::audio::common::AudioUsage; +using aidl::android::media::audio::common::AudioUsage::ALARM; +using aidl::android::media::audio::common::AudioUsage::ANNOUNCEMENT; +using aidl::android::media::audio::common::AudioUsage::ASSISTANCE_ACCESSIBILITY; +using aidl::android::media::audio::common::AudioUsage::ASSISTANCE_NAVIGATION_GUIDANCE; +using aidl::android::media::audio::common::AudioUsage::ASSISTANCE_SONIFICATION; +using aidl::android::media::audio::common::AudioUsage::ASSISTANT; +using aidl::android::media::audio::common::AudioUsage::CALL_ASSISTANT; +using aidl::android::media::audio::common::AudioUsage::EMERGENCY; +using aidl::android::media::audio::common::AudioUsage::GAME; +using aidl::android::media::audio::common::AudioUsage::MEDIA; +using aidl::android::media::audio::common::AudioUsage::NOTIFICATION; +using aidl::android::media::audio::common::AudioUsage::NOTIFICATION_EVENT; +using aidl::android::media::audio::common::AudioUsage::NOTIFICATION_TELEPHONY_RINGTONE; +using aidl::android::media::audio::common::AudioUsage::SAFETY; +using aidl::android::media::audio::common::AudioUsage::UNKNOWN; +using aidl::android::media::audio::common::AudioUsage::VEHICLE_STATUS; +using aidl::android::media::audio::common::AudioUsage::VOICE_COMMUNICATION; +using aidl::android::media::audio::common::AudioUsage::VOICE_COMMUNICATION_SIGNALLING; + +namespace android { +namespace hardware { +namespace audiocontrol { +namespace internal { + +std::vector createAudioAttributes(const std::vector& usages) { + std::vector audioAttributes; + for (const auto& usage : usages) { + AudioAttributes attributes; + attributes.usage = usage; + audioAttributes.push_back(attributes); + } + return audioAttributes; +} + +AudioZoneContextInfo createAudioZoneContextInfo(const std::string& name, int id, + const std::vector& usages) { + AudioZoneContextInfo info; + info.name = name; + info.id = id; + info.audioAttributes = createAudioAttributes(usages); + return info; +} + +AudioZoneContext createAudioZoneContextInfo(const std::vector& info) { + AudioZoneContext context; + context.audioContextInfos.insert(context.audioContextInfos.begin(), info.begin(), info.end()); + return context; +} + +AudioZoneContext getDefaultCarAudioContext() { + // For legacy reasons, context names are lower case here. + static const AudioZoneContext kDefaultContext = createAudioZoneContextInfo( + {createAudioZoneContextInfo("music", 1, {UNKNOWN, MEDIA, GAME}), + createAudioZoneContextInfo("navigation", 2, {ASSISTANCE_NAVIGATION_GUIDANCE}), + createAudioZoneContextInfo("voice_command", 3, {ASSISTANCE_ACCESSIBILITY, ASSISTANT}), + createAudioZoneContextInfo("call_ring", 4, {NOTIFICATION_TELEPHONY_RINGTONE}), + createAudioZoneContextInfo( + "call", 5, + {VOICE_COMMUNICATION, CALL_ASSISTANT, VOICE_COMMUNICATION_SIGNALLING}), + createAudioZoneContextInfo("alarm", 6, {ALARM}), + createAudioZoneContextInfo("notification", 7, {NOTIFICATION, NOTIFICATION_EVENT}), + createAudioZoneContextInfo("system_sound", 8, {ASSISTANCE_SONIFICATION}), + createAudioZoneContextInfo("emergency", 9, {EMERGENCY}), + createAudioZoneContextInfo("safety", 10, {SAFETY}), + createAudioZoneContextInfo("vehicle_status", 11, {VEHICLE_STATUS}), + createAudioZoneContextInfo("announcement", 12, {ANNOUNCEMENT})}); + return kDefaultContext; +} + +} // namespace internal +} // namespace audiocontrol +} // namespace hardware +} // namespace android diff --git a/automotive/audiocontrol/aidl/default/converter/src/CarAudioConfigurationXmlConverter.cpp b/automotive/audiocontrol/aidl/default/converter/src/CarAudioConfigurationXmlConverter.cpp new file mode 100644 index 0000000000..d43b595cb9 --- /dev/null +++ b/automotive/audiocontrol/aidl/default/converter/src/CarAudioConfigurationXmlConverter.cpp @@ -0,0 +1,1134 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "AudioControl::XSD_Converter" + +#define LOG_NDEBUG 0 +#include + +#include "../include/CarAudioConfigurationXmlConverter.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace android { +namespace hardware { +namespace audiocontrol { +namespace internal { +namespace xsd = ::android::hardware::automotive::audiocontrol; +namespace fade = android::hardware::automotive::audiocontrol::fade; +namespace api = ::aidl::android::hardware::automotive::audiocontrol; + +using aidl::android::media::audio::common::AudioAttributes; +using aidl::android::media::audio::common::AudioContentType; +using aidl::android::media::audio::common::AudioDevice; +using aidl::android::media::audio::common::AudioDeviceAddress; +using aidl::android::media::audio::common::AudioDeviceDescription; +using aidl::android::media::audio::common::AudioDeviceType; +using aidl::android::media::audio::common::AudioPort; +using aidl::android::media::audio::common::AudioPortDeviceExt; +using aidl::android::media::audio::common::AudioPortExt; +using aidl::android::media::audio::common::AudioUsage; + +using namespace ::android::base; + +namespace { + +static const std::string kUseCoreRouting{"useCoreAudioRouting"}; +static const std::string kUseCoreVolume{"useCoreAudioVolume"}; +static const std::string kUseHalDuckingSignals{"useHalDuckingSignals"}; +static const std::string kUseCarVolumeGroupMuting{"useCarVolumeGroupMuting"}; + +static constexpr char kOutBusType[] = "AUDIO_DEVICE_OUT_BUS"; +static constexpr char kInBusType[] = "AUDIO_DEVICE_IN_BUS"; + +using ActivationMap = std::unordered_map; +using FadeConfigurationMap = std::unordered_map< + std::string, ::aidl::android::hardware::automotive::audiocontrol::AudioFadeConfiguration>; + +inline bool isReadableConfigurationFile(const std::string& filePath) { + return !filePath.empty() && filePath.ends_with(".xml") && (access(filePath.c_str(), R_OK) == 0); +} + +inline bool parseBoolOrDefaultIfFailed(const std::string& value, bool defaultValue) { + ParseBoolResult results = ParseBool(value); + return results == ParseBoolResult::kError ? defaultValue : results == ParseBoolResult::kTrue; +} + +void parseCoreRoutingInfo(const std::string& value, api::AudioDeviceConfiguration& config) { + if (!parseBoolOrDefaultIfFailed(value, /* defaultValue= */ false)) { + return; + } + config.routingConfig = api::RoutingDeviceConfiguration::CONFIGURABLE_AUDIO_ENGINE_ROUTING; +} + +void parseCoreVolumeInfo(const std::string& value, api::AudioDeviceConfiguration& config) { + config.useCoreAudioVolume = parseBoolOrDefaultIfFailed(value, config.useCoreAudioVolume); +} + +void parseHalDuckingInfo(const std::string& value, api::AudioDeviceConfiguration& config) { + config.useHalDuckingSignals = parseBoolOrDefaultIfFailed(value, config.useHalDuckingSignals); +} + +void parseHalMutingInfo(const std::string& value, api::AudioDeviceConfiguration& config) { + config.useCarVolumeGroupMuting = + parseBoolOrDefaultIfFailed(value, config.useCarVolumeGroupMuting); +} + +bool parseAudioAttributeUsageString(const std::string& usageString, AudioUsage& usage) { + audio_usage_t legacyUsage; + if (!::android::UsageTypeConverter::fromString(usageString, legacyUsage)) { + LOG(ERROR) << __func__ << " could not parse usage from string " << usageString; + return false; + } + ConversionResult result = + ::aidl::android::legacy2aidl_audio_usage_t_AudioUsage(legacyUsage); + if (!result.ok()) { + LOG(ERROR) << __func__ << " could not parse usage legacy type " << legacyUsage; + return false; + } + usage = result.value(); + return true; +} + +bool parseAudioAttributeUsage(const xsd::UsageType& usageType, AudioAttributes& attributes) { + if (!usageType.hasValue()) { + LOG(ERROR) << __func__ << " usage does not have value"; + return false; + } + if (!parseAudioAttributeUsageString(xsd::toString(usageType.getValue()), attributes.usage)) { + return false; + } + return true; +} + +bool parseAudioAttributesUsages(const std::vector& usages, + std::vector& audioAttributes) { + for (const auto& xsdUsage : usages) { + AudioAttributes attributes; + if (!parseAudioAttributeUsage(xsdUsage, attributes)) { + return false; + } + audioAttributes.push_back(attributes); + } + return true; +} + +bool parseContentTypeString(const std::string& typeString, AudioContentType& type) { + audio_content_type_t legacyContentType; + if (!::android::AudioContentTypeConverter::fromString(typeString, legacyContentType)) { + LOG(ERROR) << __func__ << " could not parse content type from string " << typeString; + return false; + } + ConversionResult result = + ::aidl::android::legacy2aidl_audio_content_type_t_AudioContentType(legacyContentType); + if (!result.ok()) { + LOG(ERROR) << __func__ << " could not convert legacy content type " << legacyContentType; + return false; + } + type = result.value(); + return true; +} + +bool parseAudioAttribute(const xsd::AttributesType& attributesType, AudioAttributes& attributes) { + if (attributesType.hasUsage()) { + if (!parseAudioAttributeUsageString(xsd::toString(attributesType.getUsage()), + attributes.usage)) { + LOG(ERROR) << __func__ << " could not parse audio usage: " + << xsd::toString(attributesType.getUsage()); + return false; + } + } + + if (attributesType.hasContentType()) { + if (!parseContentTypeString(xsd::toString(attributesType.getContentType()), + attributes.contentType)) { + return false; + } + } + + if (attributesType.hasTags()) { + attributes.tags.push_back(attributesType.getTags()); + } + return true; +} + +bool parseAudioAttributes(const std::vector& xsdAttributes, + std::vector& audioAttributes) { + for (const auto& xsdAttribute : xsdAttributes) { + AudioAttributes attribute; + if (!parseAudioAttribute(xsdAttribute, attribute)) { + return false; + } + audioAttributes.push_back(attribute); + } + return true; +} + +bool parseAudioAttributes(const xsd::AudioAttributesUsagesType& xsdAttributeOrUsages, + std::vector& audioAttributes) { + if (xsdAttributeOrUsages.hasUsage_optional()) { + if (!parseAudioAttributesUsages(xsdAttributeOrUsages.getUsage_optional(), + audioAttributes)) { + LOG(ERROR) << __func__ << " could not parse audio usages"; + return false; + } + } + + if (xsdAttributeOrUsages.hasAudioAttribute_optional()) { + if (!parseAudioAttributes(xsdAttributeOrUsages.getAudioAttribute_optional(), + audioAttributes)) { + LOG(ERROR) << __func__ << " could not parse audio attributes"; + return false; + } + } + return true; +} + +bool parseAudioContext(const xsd::OemContextType& xsdContextInfo, + api::AudioZoneContextInfo& contextInfo) { + if (!xsdContextInfo.hasName()) { + LOG(ERROR) << __func__ << " Audio context info missing name"; + return false; + } + + contextInfo.name = xsdContextInfo.getName(); + + if (xsdContextInfo.hasId()) { + ParseInt(xsdContextInfo.getId().c_str(), &contextInfo.id); + } + + if (xsdContextInfo.hasAudioAttributes()) { + if (!parseAudioAttributes(*xsdContextInfo.getFirstAudioAttributes(), + contextInfo.audioAttributes)) { + return false; + } + } + + return true; +} + +bool parseAudioContexts(const xsd::OemContextsType* xsdContexts, api::AudioZoneContext& context) { + if (!xsdContexts->hasOemContext()) { + return false; + } + const auto xsdContextInfos = xsdContexts->getOemContext(); + for (const auto& xsdContextInfo : xsdContextInfos) { + api::AudioZoneContextInfo info; + if (!parseAudioContext(xsdContextInfo, info)) { + continue; + } + context.audioContextInfos.push_back(info); + } + return true; +} + +bool createAudioDevice(const std::string& address, const std::string& type, AudioPort& port) { + audio_devices_t legacyDeviceType = AUDIO_DEVICE_NONE; + ::android::DeviceConverter::fromString(type, legacyDeviceType); + std::string tempString; + ::android::DeviceConverter::toString(legacyDeviceType, tempString); + ConversionResult result = + ::aidl::android::legacy2aidl_audio_devices_t_AudioDeviceDescription(legacyDeviceType); + if (legacyDeviceType == AUDIO_DEVICE_NONE || !result.ok()) { + LOG(ERROR) << __func__ << " could not parse legacy device type"; + return false; + } + AudioDevice device; + if (!address.empty()) { + device.address = AudioDeviceAddress::make(address); + } + device.type = result.value(); + + port.ext = AudioPortExt::make(device); + + return true; +} + +std::string outTypeToOutAudioDevice(const std::string& device) { + const static std::unordered_map typeToOutDevice{ + {"TYPE_BUILTIN_SPEAKER", "AUDIO_DEVICE_OUT_SPEAKER"}, + {"TYPE_WIRED_HEADSET", "AUDIO_DEVICE_OUT_WIRED_HEADSET"}, + {"TYPE_WIRED_HEADPHONES", "AUDIO_DEVICE_OUT_WIRED_HEADPHONE,"}, + {"TYPE_BLUETOOTH_A2DP", "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP"}, + {"TYPE_HDMI", "AUDIO_DEVICE_OUT_HDMI"}, + {"TYPE_USB_ACCESSORY", "AUDIO_DEVICE_OUT_USB_ACCESSORY"}, + {"TYPE_USB_DEVICE", "AUDIO_DEVICE_OUT_USB_DEVICE,"}, + {"TYPE_USB_HEADSET", "AUDIO_DEVICE_OUT_USB_HEADSET"}, + {"TYPE_AUX_LINE", "AUDIO_DEVICE_OUT_AUX_LINE"}, + {"TYPE_BUS", "AUDIO_DEVICE_OUT_BUS"}, + {"TYPE_BLE_HEADSET", "AUDIO_DEVICE_OUT_BLE_HEADSET"}, + {"TYPE_BLE_SPEAKER", "AUDIO_DEVICE_OUT_BLE_SPEAKER"}, + {"TYPE_BLE_BROADCAST", "AUDIO_DEVICE_OUT_BLE_BROADCAST"}, + }; + + if (!device.starts_with("TYPE_")) { + return device; + } + + const auto it = typeToOutDevice.find(device); + return it != typeToOutDevice.end() ? it->second : device; +} + +bool parseAudioDeviceToContexts(const xsd::DeviceRoutesType& deviceRoutesType, + api::DeviceToContextEntry& route) { + std::string address = deviceRoutesType.hasAddress() ? deviceRoutesType.getAddress() : ""; + // Default type is bus for schema + std::string type = outTypeToOutAudioDevice(deviceRoutesType.hasType() + ? xsd::toString(deviceRoutesType.getType()) + : std::string(kOutBusType)); + // Address must be present for audio device bus + if (address.empty() && type == std::string(kOutBusType)) { + LOG(ERROR) << __func__ << " empty device address for bus device type"; + return false; + } + if (!createAudioDevice(address, type, route.device)) { + return false; + } + + if (!deviceRoutesType.hasContext()) { + LOG(ERROR) << __func__ << " empty device context mapping"; + return false; + } + + for (const auto& xsdContext : deviceRoutesType.getContext()) { + if (!xsdContext.hasContext()) { + LOG(ERROR) << __func__ << " audio device route missing context info"; + return false; + } + route.contextNames.push_back(xsdContext.getContext()); + } + + return true; +} + +bool parseAudioDeviceRoutes(const std::vector deviceRoutesTypes, + std::vector& routes) { + for (const auto& deviceRouteType : deviceRoutesTypes) { + api::DeviceToContextEntry entry; + if (!parseAudioDeviceToContexts(deviceRouteType, entry)) { + return false; + } + routes.push_back(entry); + } + return true; +} + +void parseVolumeGroupActivation(const std::string& activationConfigName, + const ActivationMap& activations, + api::VolumeGroupConfig& volumeGroup) { + if (activationConfigName.empty()) { + LOG(ERROR) << __func__ << " Volume group " << volumeGroup.name + << " has empty volume group activation name"; + return; + } + const auto& it = activations.find(activationConfigName); + if (it == activations.end()) { + LOG(ERROR) << __func__ << " Volume group " << volumeGroup.name + << " has non-existing volume group activation name " << activationConfigName; + return; + } + volumeGroup.activationConfiguration = it->second; +} + +bool parseVolumeGroup(const xsd::VolumeGroupType& volumeGroupType, const ActivationMap& activations, + api::VolumeGroupConfig& volumeGroup) { + if (!volumeGroupType.hasDevice()) { + LOG(ERROR) << __func__ << " no device found"; + return false; + } + + if (volumeGroupType.hasName()) { + volumeGroup.name = volumeGroupType.getName(); + } + + if (!parseAudioDeviceRoutes(volumeGroupType.getDevice(), volumeGroup.carAudioRoutes)) { + return false; + } + + if (volumeGroupType.hasActivationConfig()) { + parseVolumeGroupActivation(volumeGroupType.getActivationConfig(), activations, volumeGroup); + } + + return true; +} + +bool parseVolumeGroups(const xsd::VolumeGroupsType* volumeGroupsType, + const ActivationMap& activations, + std::vector& volumeGroups) { + if (!volumeGroupsType->hasGroup()) { + LOG(ERROR) << __func__ << " no volume groups found"; + return false; + } + for (const auto& volumeGroupType : volumeGroupsType->getGroup()) { + api::VolumeGroupConfig volumeGroup; + if (!parseVolumeGroup(volumeGroupType, activations, volumeGroup)) { + return false; + } + volumeGroups.push_back(volumeGroup); + } + return true; +} + +void parseFadeConfigurationUsages(const xsd::ApplyFadeConfigType& fadeConfigType, + std::vector& usages) { + if (!fadeConfigType.hasAudioAttributes()) { + return; + } + const xsd::AudioAttributeUsagesType* attributesOrUsagesType = + fadeConfigType.getFirstAudioAttributes(); + if (!attributesOrUsagesType->hasUsage()) { + return; + } + for (const auto& usageType : attributesOrUsagesType->getUsage()) { + AudioUsage usage; + if (!usageType.hasValue() || + !parseAudioAttributeUsageString(xsd::toString(usageType.getValue()), usage)) { + continue; + } + usages.push_back(usage); + } +} + +void parseZoneFadeConfiguration(const xsd::ApplyFadeConfigType& fadeConfigType, + const FadeConfigurationMap& fadeConfigurations, + api::AudioZoneFadeConfiguration& zoneFadeConfiguration) { + if (!fadeConfigType.hasName()) { + LOG(ERROR) << __func__ << " Found a fade config without a name, skipping assignment"; + return; + } + + const auto it = fadeConfigurations.find(fadeConfigType.getName()); + if (it == fadeConfigurations.end()) { + LOG(ERROR) << __func__ << " Config name " << fadeConfigType.getName() + << " not found, skipping assignment"; + return; + } + // Return for default since default configurations do not have any audio attributes mapping + if (fadeConfigType.hasIsDefault()) { + zoneFadeConfiguration.defaultConfiguration = it->second; + return; + } + + api::TransientFadeConfigurationEntry entry; + entry.transientFadeConfiguration = it->second; + parseFadeConfigurationUsages(fadeConfigType, entry.transientUsages); + zoneFadeConfiguration.transientConfiguration.push_back(entry); +} + +void parseZoneFadeConfigurations(const xsd::ZoneConfigType& zoneConfigType, + const FadeConfigurationMap& fadeConfigurations, + std::optional& zoneFadeConfig) { + if (!zoneConfigType.hasApplyFadeConfigs()) { + return; + } + const xsd::ApplyFadeConfigsType* applyFadeConfigs = zoneConfigType.getFirstApplyFadeConfigs(); + if (!applyFadeConfigs->hasFadeConfig()) { + return; + } + api::AudioZoneFadeConfiguration zoneFadeConfiguration; + for (const auto& fadeConfigType : applyFadeConfigs->getFadeConfig()) { + parseZoneFadeConfiguration(fadeConfigType, fadeConfigurations, zoneFadeConfiguration); + } + zoneFadeConfig = zoneFadeConfiguration; +} + +bool parseAudioZoneConfig(const xsd::ZoneConfigType& zoneConfigType, + const ActivationMap& activations, + const FadeConfigurationMap& fadeConfigurations, + api::AudioZoneConfig& config) { + if (!zoneConfigType.hasVolumeGroups()) { + LOG(ERROR) << __func__ << " no volume groups found"; + return false; + } + + if (zoneConfigType.hasName()) { + config.name = zoneConfigType.getName(); + } + if (!parseVolumeGroups(zoneConfigType.getFirstVolumeGroups(), activations, + config.volumeGroups)) { + return false; + } + + parseZoneFadeConfigurations(zoneConfigType, fadeConfigurations, config.fadeConfiguration); + + config.isDefault = zoneConfigType.hasIsDefault() && zoneConfigType.getIsDefault(); + + return true; +} + +bool parseAudioZoneConfigs(const xsd::ZoneConfigsType* zoneConfigsType, + const ActivationMap& activations, + const FadeConfigurationMap& fadeConfigurations, + std::vector& configs) { + if (!zoneConfigsType->hasZoneConfig()) { + LOG(ERROR) << __func__ << " No zone configs found"; + return false; + } + + if (zoneConfigsType->getZoneConfig().empty()) { + LOG(ERROR) << __func__ << " Empty list of audio configurations"; + return false; + } + + for (const auto& zoneConfigType : zoneConfigsType->getZoneConfig()) { + api::AudioZoneConfig config; + if (!parseAudioZoneConfig(zoneConfigType, activations, fadeConfigurations, config)) { + return false; + } + configs.push_back(config); + } + + return true; +} + +bool parseInputDevice(const xsd::InputDeviceType& xsdInputDevice, AudioPort& inputDevice) { + // Input device must have a non-empty address + if (!xsdInputDevice.hasAddress() || xsdInputDevice.getAddress().empty()) { + LOG(ERROR) << __func__ << " missing device address"; + return false; + } + // By default a device is bus type, unless specified + std::string inputDeviceType = + xsdInputDevice.hasType() ? xsd::toString(xsdInputDevice.getType()) : kInBusType; + if (!createAudioDevice(xsdInputDevice.getAddress(), inputDeviceType, inputDevice)) { + return false; + } + return true; +} + +void parseInputDevices(const xsd::InputDevicesType* xsdInputDevices, + std::vector& inputDevices) { + if (!xsdInputDevices->hasInputDevice()) { + return; + } + for (const auto& xsdInputDevice : xsdInputDevices->getInputDevice()) { + AudioPort inputDevice; + if (!parseInputDevice(xsdInputDevice, inputDevice)) { + continue; + } + inputDevices.push_back(inputDevice); + } +} + +bool parseAudioZone(const xsd::ZoneType& zone, const ActivationMap& activations, + const FadeConfigurationMap& fadeConfigurations, api::AudioZone& audioZone) { + if (zone.hasName()) { + audioZone.name = zone.getName(); + } + + if (zone.hasOccupantZoneId()) { + ParseInt(zone.getOccupantZoneId().c_str(), &audioZone.occupantZoneId); + } + + if (zone.hasInputDevices()) { + parseInputDevices(zone.getFirstInputDevices(), audioZone.inputAudioDevices); + } + + // Audio zone id is required + if (!zone.hasAudioZoneId()) { + LOG(ERROR) << __func__ << " Audio zone id required for each zone"; + return false; + } + + bool isPrimary = zone.hasIsPrimary() && zone.getIsPrimary(); + + if (isPrimary) { + audioZone.id = api::AudioZone::PRIMARY_AUDIO_ZONE; + } + + // ID not required in XML for primary zone + if (!ParseInt(zone.getAudioZoneId().c_str(), &audioZone.id) && !isPrimary) { + LOG(ERROR) << __func__ + << " Could not parse audio zone id, must be a non-negative integer or isPrimary " + "must be specify as true for primary zone"; + return false; + } + + if (isPrimary && audioZone.id != api::AudioZone::PRIMARY_AUDIO_ZONE) { + LOG(ERROR) << __func__ << " Audio zone is primary but has zone id " + << std::to_string(audioZone.id) << " instead of primary zone id " + << std::to_string(api::AudioZone::PRIMARY_AUDIO_ZONE); + return false; + } + + if (!zone.hasZoneConfigs()) { + LOG(ERROR) << __func__ << " Missing audio zone configs for audio zone id " << audioZone.id; + return false; + } + if (!parseAudioZoneConfigs(zone.getFirstZoneConfigs(), activations, fadeConfigurations, + audioZone.audioZoneConfigs)) { + LOG(ERROR) << __func__ << " Could not parse zone configs for audio zone id " << audioZone.id + << ", name " << audioZone.name; + return false; + } + + return true; +} + +std::string parseAudioZones(const xsd::ZonesType* zones, const api::AudioZoneContext& context, + const ActivationMap& activations, + const FadeConfigurationMap& fadeConfigurations, + std::vector& audioZones) { + if (!zones->hasZone()) { + return "audio zones are missing"; + } + const auto& xsdZones = zones->getZone(); + for (const auto& xsdZone : xsdZones) { + api::AudioZone audioZone; + audioZone.audioZoneContext = context; + if (!parseAudioZone(xsdZone, activations, fadeConfigurations, audioZone)) { + continue; + } + audioZones.push_back(audioZone); + } + return ""; +} + +std::unordered_map> +getConfigsParsers() { + static const std::unordered_map< + std::string, std::function> + parsers{ + {kUseCoreRouting, parseCoreRoutingInfo}, + {kUseCoreVolume, parseCoreVolumeInfo}, + {kUseHalDuckingSignals, parseHalDuckingInfo}, + {kUseCarVolumeGroupMuting, parseHalMutingInfo}, + }; + + return parsers; +} + +bool parseVolumeActivationType(const xsd::ActivationType& xsdType, + api::VolumeInvocationType& activationType) { + switch (xsdType) { + case xsd::ActivationType::onBoot: + activationType = api::VolumeInvocationType::ON_BOOT; + break; + case xsd::ActivationType::onSourceChanged: + activationType = api::VolumeInvocationType::ON_SOURCE_CHANGED; + break; + case xsd::ActivationType::onPlaybackChanged: + activationType = api::VolumeInvocationType::ON_PLAYBACK_CHANGED; + break; + default: + return false; + } + return true; +} + +bool parseVolumeGroupActivationEntry(const xsd::ActivationVolumeConfigEntryType& xsdEntry, + api::VolumeActivationConfigurationEntry& entry) { + if (!xsdEntry.hasInvocationType()) { + LOG(ERROR) << __func__ << " Activation config entry missing invocation type"; + return false; + } + + if (!parseVolumeActivationType(xsdEntry.getInvocationType(), entry.type)) { + LOG(ERROR) << __func__ << " Could not parse configuration entry type"; + return false; + } + + if (xsdEntry.hasMaxActivationVolumePercentage()) { + // Parse int ranges are not inclusive + ParseInt(xsdEntry.getMaxActivationVolumePercentage().c_str(), + &entry.maxActivationVolumePercentage, + api::VolumeActivationConfigurationEntry::DEFAULT_MIN_ACTIVATION_VALUE - 1, + api::VolumeActivationConfigurationEntry::DEFAULT_MAX_ACTIVATION_VALUE + 1); + } + + if (xsdEntry.hasMinActivationVolumePercentage()) { + // Parse int ranges are not inclusive + ParseInt(xsdEntry.getMinActivationVolumePercentage().c_str(), + &entry.minActivationVolumePercentage, + api::VolumeActivationConfigurationEntry::DEFAULT_MIN_ACTIVATION_VALUE - 1, + api::VolumeActivationConfigurationEntry::DEFAULT_MAX_ACTIVATION_VALUE + 1); + } + + return true; +} + +bool parseVolumeGroupActivationEntries( + const std::vector& xsdEntries, + std::vector& entries) { + for (const auto& xsdEntry : xsdEntries) { + api::VolumeActivationConfigurationEntry entry; + if (!parseVolumeGroupActivationEntry(xsdEntry, entry)) { + LOG(ERROR) << __func__ << " Could not parse volume group activation entries"; + return false; + } + entries.push_back(entry); + } + return true; +} + +bool parseVolumeGroupActivation(const xsd::ActivationVolumeConfigType& xsdActivationConfig, + api::VolumeActivationConfiguration& activation) { + if (!xsdActivationConfig.hasName()) { + LOG(ERROR) << __func__ << " Activation config missing volume activation name"; + return false; + } + if (!xsdActivationConfig.hasActivationVolumeConfigEntry()) { + LOG(ERROR) << __func__ << " Activation config missing volume activation entries"; + return false; + } + if (!parseVolumeGroupActivationEntries(xsdActivationConfig.getActivationVolumeConfigEntry(), + activation.volumeActivationEntries)) { + LOG(ERROR) << __func__ << " Could not parse volume activation name"; + return false; + } + activation.name = xsdActivationConfig.getName(); + return true; +} + +void parseVolumeGroupActivations(const xsd::ActivationVolumeConfigsType* xsdActivationConfigs, + ActivationMap& activations) { + if (!xsdActivationConfigs->hasActivationVolumeConfig()) { + LOG(ERROR) << __func__ << " No volume group activations found"; + return; + } + for (const auto& xsdActivationConfig : xsdActivationConfigs->getActivationVolumeConfig()) { + api::VolumeActivationConfiguration activationConfiguration; + if (!parseVolumeGroupActivation(xsdActivationConfig, activationConfiguration)) { + continue; + } + std::string name = xsdActivationConfig.getName(); + activations.emplace(name, activationConfiguration); + } +} + +void parseOutputMirroringDevices(const xsd::MirroringDevicesType* mirroringDevicesType, + std::vector& mirroringDevices) { + if (!mirroringDevicesType->hasMirroringDevice()) { + LOG(ERROR) << __func__ << " Missing audio mirroring devices"; + return; + } + for (const auto& xsdMirrorDevice : mirroringDevicesType->getMirroringDevice()) { + AudioPort mirrorDevicePort; + if (!xsdMirrorDevice.hasAddress()) { + LOG(ERROR) << __func__ << " Missing audio mirroring device address"; + continue; + } + if (!createAudioDevice(xsdMirrorDevice.getAddress(), kOutBusType, mirrorDevicePort)) { + LOG(ERROR) << __func__ << " Could not create mirror device with address " + << xsdMirrorDevice.getAddress(); + continue; + } + mirroringDevices.push_back(mirrorDevicePort); + } +} + +api::FadeState getFadeState(const fade::FadeStateType& xsdFadeState) { + // Return default value if missing + if (!xsdFadeState.hasValue()) { + return api::FadeState::FADE_STATE_ENABLED_DEFAULT; + } + // For legacy files, "0" and "1 " need to be supported. + switch (xsdFadeState.getValue()) { + case fade::FadeStateEnumType::_0: + // Fallthrough + case fade::FadeStateEnumType::FADE_STATE_DISABLED: + return api::FadeState::FADE_STATE_DISABLED; + case fade::FadeStateEnumType::_1: + // Fallthrough + case fade::FadeStateEnumType::FADE_STATE_ENABLED_DEFAULT: + // Fallthrough + default: + return api::FadeState::FADE_STATE_ENABLED_DEFAULT; + } +} + +void parseFadeableUsages(const fade::FadeableUsagesType& fadeUsages, + std::vector& usages) { + if (!fadeUsages.hasUsage()) { + return; + } + for (const auto& fadeUsage : fadeUsages.getUsage()) { + AudioUsage audioUsage; + if (!fadeUsage.hasValue() || + !parseAudioAttributeUsageString(fade::toString(fadeUsage.getValue()), audioUsage)) { + continue; + } + usages.push_back(audioUsage); + } +} + +void parseFadeAudioAttribute(const fade::AttributesType& fadeAttributes, + AudioAttributes& attributes) { + if (fadeAttributes.hasUsage()) { + parseAudioAttributeUsageString(fade::toString(fadeAttributes.getUsage()), attributes.usage); + } + if (fadeAttributes.hasContentType()) { + parseContentTypeString(fade::toString(fadeAttributes.getContentType()), + attributes.contentType); + } + if (fadeAttributes.hasTags()) { + attributes.tags.push_back(fadeAttributes.getTags()); + } +} + +bool parseFadeAudioAttribute(const fade::AudioAttributesUsagesType& fadeAttributes, + std::vector& audioAttributes) { + if (fadeAttributes.hasUsage_optional()) { + for (const auto& usage : fadeAttributes.getUsage_optional()) { + AudioAttributes attributes; + if (!usage.hasValue() || !parseAudioAttributeUsageString( + fade::toString(usage.getValue()), attributes.usage)) { + continue; + } + audioAttributes.push_back(attributes); + } + } + if (fadeAttributes.hasAudioAttribute_optional()) { + for (const auto& fadeAttribute : fadeAttributes.getAudioAttribute_optional()) { + AudioAttributes attribute; + parseFadeAudioAttribute(fadeAttribute, attribute); + audioAttributes.push_back(attribute); + } + } + return true; +} + +void parseUnfadeableAudioAttributes(const fade::UnfadeableAudioAttributesType& fadeAttributes, + std::vector& audioAttributes) { + if (!fadeAttributes.hasAudioAttributes()) { + return; + } + parseFadeAudioAttribute(*fadeAttributes.getFirstAudioAttributes(), audioAttributes); +} + +void parseUnfadeableContentType(const fade::UnfadeableContentTypesType& fadeTypes, + std::optional>& contentTypes) { + if (!fadeTypes.hasContentType()) { + return; + } + std::vector contents; + for (const auto& fadeContentType : fadeTypes.getContentType()) { + AudioContentType contentType; + if (!fadeContentType.hasValue() || + !parseContentTypeString(fade::toString(fadeContentType.getValue()), contentType)) { + continue; + } + contents.push_back(contentType); + } + contentTypes = contents; +} + +void parseFadeConfigAudioAttributes(const fade::AudioAttributesUsagesType& fadeAudioAttributesType, + const int64_t fadeDurationMillins, + std::vector& fadeInConfigurations) { + if (fadeAudioAttributesType.hasAudioAttribute_optional()) { + for (const auto& fadeAudioAttribute : + fadeAudioAttributesType.getAudioAttribute_optional()) { + api::FadeConfiguration fadeConfiguration; + AudioAttributes attributes; + parseFadeAudioAttribute(fadeAudioAttribute, attributes); + fadeConfiguration.fadeDurationMillis = fadeDurationMillins; + fadeConfiguration.audioAttributesOrUsage + .set(attributes); + fadeInConfigurations.push_back(fadeConfiguration); + } + } + + if (fadeAudioAttributesType.hasUsage_optional()) { + for (const auto& fadeAudioUsage : fadeAudioAttributesType.getUsage_optional()) { + api::FadeConfiguration fadeConfiguration; + AudioUsage usage; + if (!fadeAudioUsage.hasValue() || + !parseAudioAttributeUsageString(fade::toString(fadeAudioUsage.getValue()), usage)) { + continue; + } + fadeConfiguration.fadeDurationMillis = fadeDurationMillins; + fadeConfiguration.audioAttributesOrUsage + .set(usage); + fadeInConfigurations.push_back(fadeConfiguration); + } + } +} +void parseFadeConfiguration(const fade::FadeConfigurationType& fadeConfigurationType, + std::vector& fadeConfigurations) { + if (!fadeConfigurationType.hasFadeDurationMillis() || + !fadeConfigurationType.hasAudioAttributes() || + fadeConfigurationType.getAudioAttributes().empty()) { + return; + } + + int64_t fadeDurationMillis = 0L; + + if (!ParseInt(fadeConfigurationType.getFadeDurationMillis().c_str(), &fadeDurationMillis, + static_cast(0))) { + return; + } + parseFadeConfigAudioAttributes(*fadeConfigurationType.getFirstAudioAttributes(), + fadeDurationMillis, fadeConfigurations); +} + +void parseFadeInConfigurations(const fade::FadeInConfigurationsType& fadeInConfigurationsType, + std::vector& fadeInConfigurations) { + if (!fadeInConfigurationsType.hasFadeConfiguration()) { + return; + } + for (const auto& fadeConfigurationType : fadeInConfigurationsType.getFadeConfiguration()) { + parseFadeConfiguration(fadeConfigurationType, fadeInConfigurations); + } +} + +void parseFadeOutConfigurations(const fade::FadeOutConfigurationsType& fadeOutConfigurationsType, + std::vector& fadeOutConfigurations) { + if (!fadeOutConfigurationsType.hasFadeConfiguration()) { + return; + } + for (const auto& fadeConfigurationType : fadeOutConfigurationsType.getFadeConfiguration()) { + parseFadeConfiguration(fadeConfigurationType, fadeOutConfigurations); + } +} + +bool parseFadeConfig(const fade::FadeConfigurationConfig& fadeConfig, + api::AudioFadeConfiguration& configuration) { + // Fade configuration must have a name for zone association. Fade state is also needed to + // determine accurate usage. + if (!fadeConfig.hasName()) { + LOG(ERROR) << __func__ << " Fade configuration missing name"; + return false; + } + if (!fadeConfig.hasFadeState()) { + LOG(ERROR) << __func__ << " Fade configuration missing fade state"; + return false; + } + configuration.name = fadeConfig.getName(); + configuration.fadeState = getFadeState(*fadeConfig.getFirstFadeState()); + if (fadeConfig.hasDefaultFadeOutDurationInMillis()) { + ParseInt(fadeConfig.getDefaultFadeOutDurationInMillis().c_str(), + &configuration.fadeOutDurationMs, static_cast(0)); + } + if (fadeConfig.hasDefaultFadeInDurationInMillis()) { + ParseInt(fadeConfig.getDefaultFadeInDurationInMillis().c_str(), + &configuration.fadeInDurationMs, static_cast(0)); + } + if (fadeConfig.hasDefaultFadeInDelayForOffenders()) { + ParseInt(fadeConfig.getDefaultFadeInDelayForOffenders().c_str(), + &configuration.fadeInDelayedForOffendersMs, static_cast(0)); + } + + if (fadeConfig.hasFadeableUsages()) { + parseFadeableUsages(*fadeConfig.getFirstFadeableUsages(), configuration.fadeableUsages); + } + + if (fadeConfig.hasUnfadeableContentTypes()) { + parseUnfadeableContentType(*fadeConfig.getFirstUnfadeableContentTypes(), + configuration.unfadeableContentTypes); + } + + if (fadeConfig.hasUnfadeableAudioAttributes()) { + parseUnfadeableAudioAttributes(*fadeConfig.getFirstUnfadeableAudioAttributes(), + configuration.unfadableAudioAttributes); + } + if (fadeConfig.hasFadeInConfigurations()) { + parseFadeInConfigurations(*fadeConfig.getFirstFadeInConfigurations(), + configuration.fadeInConfigurations); + } + if (fadeConfig.hasFadeOutConfigurations()) { + parseFadeOutConfigurations(*fadeConfig.getFirstFadeOutConfigurations(), + configuration.fadeOutConfigurations); + } + + return true; +} + +void parseFadeConfigs(const std::vector& fadeConfigTypes, + std::vector& fadeConfigs) { + for (const auto& fadeConfig : fadeConfigTypes) { + api::AudioFadeConfiguration configuration; + if (!parseFadeConfig(fadeConfig, configuration)) { + continue; + } + fadeConfigs.push_back(configuration); + } +} + +void parseFadeConfigs(const fade::FadeConfigurationConfigs& fadeConfigsType, + std::vector& fadeConfigs) { + if (!fadeConfigsType.hasConfig()) { + LOG(ERROR) << __func__ << " Fade config file does not contains any fade configs"; + return; + } + parseFadeConfigs(fadeConfigsType.getConfig(), fadeConfigs); +} +} // namespace + +void CarAudioConfigurationXmlConverter::init() { + if (!isReadableConfigurationFile(mAudioConfigFile)) { + mParseErrors = "Configuration file " + mAudioConfigFile + " is not readable"; + initNonDynamicRouting(); + return; + } + + // Supports loading legacy fade configurations from a different file + if (isReadableConfigurationFile(mFadeConfigFile)) { + initFadeConfigurations(); + } + + const auto& configOptional = xsd::read(mAudioConfigFile.c_str()); + + if (!configOptional.has_value()) { + mParseErrors = + "Configuration file " + mAudioConfigFile + " , does not have any configurations"; + initNonDynamicRouting(); + return; + } + + const auto& configurations = configOptional.value(); + initAudioDeviceConfiguration(configurations); + initCarAudioConfigurations(configurations); +} + +void CarAudioConfigurationXmlConverter::initFadeConfigurations() { + const auto& fadeConfigOptional = fade::read(mFadeConfigFile.c_str()); + if (!fadeConfigOptional.has_value() || !fadeConfigOptional.value().hasConfigs()) { + LOG(ERROR) << __func__ << " Fade config file " << mFadeConfigFile.c_str() + << " does not contains fade configuration"; + return; + } + + const auto& fadeConfigs = fadeConfigOptional.value().getConfigs(); + + if (fadeConfigs.empty()) { + LOG(ERROR) << __func__ << " Fade config file " << mFadeConfigFile.c_str() + << " does not contains fade configs"; + } + std::vector fadeConfigurations; + parseFadeConfigs(fadeConfigs.front(), fadeConfigurations); + for (const auto& fadeConfiguration : fadeConfigurations) { + mFadeConfigurations.emplace(fadeConfiguration.name, fadeConfiguration); + } +} + +void CarAudioConfigurationXmlConverter::initNonDynamicRouting() { + mAudioDeviceConfiguration.routingConfig = + api::RoutingDeviceConfiguration::DEFAULT_AUDIO_ROUTING; +} + +void CarAudioConfigurationXmlConverter::initAudioDeviceConfiguration( + const xsd::CarAudioConfigurationType& carAudioConfigurationType) { + parseAudioDeviceConfigurations(carAudioConfigurationType); +} + +void CarAudioConfigurationXmlConverter::parseAudioDeviceConfigurations( + const xsd::CarAudioConfigurationType& carAudioConfigurationType) { + if (!carAudioConfigurationType.hasDeviceConfigurations()) { + return; + } + + mAudioDeviceConfiguration.routingConfig = + api::RoutingDeviceConfiguration::DYNAMIC_AUDIO_ROUTING; + + const auto deviceConfigs = carAudioConfigurationType.getFirstDeviceConfigurations(); + if (!deviceConfigs->hasDeviceConfiguration()) { + return; + } + + std::vector<::android::hardware::automotive::audiocontrol::DeviceConfigurationType> configs = + deviceConfigs->getDeviceConfiguration(); + const auto& parsers = getConfigsParsers(); + for (const auto& deviceConfig : configs) { + if (!deviceConfig.hasName() || !deviceConfig.hasValue()) { + continue; + } + const auto& parser = parsers.find(deviceConfig.getName()); + if (parser == parsers.end()) { + continue; + } + const auto& method = parser->second; + method(deviceConfig.getValue(), mAudioDeviceConfiguration); + } +} + +void CarAudioConfigurationXmlConverter::initCarAudioConfigurations( + const automotive::audiocontrol::CarAudioConfigurationType& carAudioConfigurationType) { + if (!carAudioConfigurationType.hasZones()) { + mParseErrors = "Audio zones not found in file " + mAudioConfigFile; + initNonDynamicRouting(); + return; + } + + api::AudioZoneContext context; + if (!carAudioConfigurationType.hasOemContexts() || + !parseAudioContexts(carAudioConfigurationType.getFirstOemContexts(), context)) { + context = getDefaultCarAudioContext(); + } + + ActivationMap activations; + if (carAudioConfigurationType.hasActivationVolumeConfigs()) { + parseVolumeGroupActivations(carAudioConfigurationType.getFirstActivationVolumeConfigs(), + activations); + } + + if (carAudioConfigurationType.hasMirroringDevices()) { + parseOutputMirroringDevices(carAudioConfigurationType.getFirstMirroringDevices(), + mOutputMirroringDevices); + } + + const auto audioZones = carAudioConfigurationType.getFirstZones(); + + std::string message = + parseAudioZones(audioZones, context, activations, mFadeConfigurations, mAudioZones); + + // Assign dynamic configuration if not assigned + if (!mAudioZones.empty() && mAudioDeviceConfiguration.routingConfig == + api::RoutingDeviceConfiguration::DEFAULT_AUDIO_ROUTING) { + mAudioDeviceConfiguration.routingConfig = + api::RoutingDeviceConfiguration::DYNAMIC_AUDIO_ROUTING; + } + + if (message.empty()) { + return; + } + mParseErrors = + "Error parsing audio zone(s) in file " + mAudioConfigFile + ", message: " + message; + LOG(ERROR) << __func__ << " Error parsing zones: " << message; + initNonDynamicRouting(); +} + +api::AudioDeviceConfiguration CarAudioConfigurationXmlConverter::getAudioDeviceConfiguration() + const { + return mAudioDeviceConfiguration; +} + +std::vector CarAudioConfigurationXmlConverter::getAudioZones() const { + return mAudioZones; +} + +std::vector<::aidl::android::media::audio::common::AudioPort> +CarAudioConfigurationXmlConverter::getOutputMirroringDevices() const { + return mOutputMirroringDevices; +} + +} // namespace internal +} // namespace audiocontrol +} // namespace hardware +} // namespace android \ No newline at end of file diff --git a/automotive/audiocontrol/aidl/default/converter/test/Android.bp b/automotive/audiocontrol/aidl/default/converter/test/Android.bp new file mode 100644 index 0000000000..70d4a20456 --- /dev/null +++ b/automotive/audiocontrol/aidl/default/converter/test/Android.bp @@ -0,0 +1,63 @@ +// Copyright (C) 2024 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package { + default_team: "trendy_team_aaos_framework", + default_applicable_licenses: ["Android-Apache-2.0"], +} + +filegroup { + name: "simple_car_audio_configuration_xml", + srcs: [ + "simple_car_audio_configuration.xml", + "simple_car_audio_configuration_with_device_type.xml", + "multi_zone_car_audio_configuration.xml", + "car_audio_configuration_without_configuration.xml", + "car_audio_configuration_with_default_context.xml", + "car_audio_configuration_with_missing_zones.xml", + "car_audio_configuration_without_audio_zone.xml", + "car_audio_fade_configuration.xml", + ], +} + +cc_test { + name: "AudioControlConverterUnitTest", + vendor: true, + require_root: true, + srcs: ["*.cpp"], + stl: "libc++_static", + static_libs: [ + "libbase", + "android.hardware.audiocontrol.internal", + "libgtest", + "libgmock", + "libutils", + "libaudio_aidl_conversion_common_ndk", + ], + shared_libs: ["liblog"], + defaults: [ + "latest_android_hardware_audio_common_ndk_static", + "car.audio.configuration.xsd.default", + "car.fade.configuration.xsd.default", + "latest_android_hardware_automotive_audiocontrol_ndk_static", + "latest_android_media_audio_common_types_ndk_static", + ], + data: [ + ":simple_car_audio_configuration_xml", + ], + test_suites: ["device-tests"], + exclude_shared_libs: [ + "android.hardware.automotive.audiocontrol-V5-ndk", + ], +} diff --git a/automotive/audiocontrol/aidl/default/converter/test/AudioControlConverterUnitTest.cpp b/automotive/audiocontrol/aidl/default/converter/test/AudioControlConverterUnitTest.cpp new file mode 100644 index 0000000000..b6bebe5f39 --- /dev/null +++ b/automotive/audiocontrol/aidl/default/converter/test/AudioControlConverterUnitTest.cpp @@ -0,0 +1,834 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace converter = ::android::hardware::audiocontrol::internal; +namespace api = ::aidl::android::hardware::automotive::audiocontrol; + +using ::testing::ContainsRegex; +using ::testing::UnorderedElementsAreArray; + +namespace { + +using ::aidl::android::media::audio::common::AudioAttributes; +using ::aidl::android::media::audio::common::AudioContentType; +using ::aidl::android::media::audio::common::AudioDevice; +using ::aidl::android::media::audio::common::AudioDeviceAddress; +using ::aidl::android::media::audio::common::AudioDeviceDescription; +using ::aidl::android::media::audio::common::AudioDeviceType; +using ::aidl::android::media::audio::common::AudioPort; +using ::aidl::android::media::audio::common::AudioPortDeviceExt; +using ::aidl::android::media::audio::common::AudioPortExt; +using ::aidl::android::media::audio::common::AudioUsage; + +std::string getTestFilePath(const std::string& filename) { + static std::string baseDir = android::base::GetExecutableDirectory(); + return baseDir + "/" + filename; +} + +AudioAttributes createAudioAttributes(const AudioUsage& usage, + const AudioContentType& type = AudioContentType::UNKNOWN, + const std::string tags = "") { + AudioAttributes attributes; + attributes.usage = usage; + attributes.contentType = type; + if (!tags.empty()) { + attributes.tags.push_back(tags); + } + return attributes; +} + +api::AudioZoneContextInfo createContextInfo(const std::string& name, + const std::vector& attributes, + const int id = -1) { + api::AudioZoneContextInfo info; + info.name = name; + if (id != -1) { + info.id = id; + } + for (const auto& attribute : attributes) { + info.audioAttributes.push_back(attribute); + } + return info; +} + +api::AudioZoneContextInfo createContextInfo(const std::string& name, + const std::vector& usages, + const int id = -1) { + std::vector attributes; + attributes.reserve(usages.size()); + for (const auto& usage : usages) { + attributes.push_back(createAudioAttributes(usage)); + } + return createContextInfo(name, attributes, id); +} + +AudioPort createAudioPort(const std::string& address, const AudioDeviceType& type, + const std::string& connection = "") { + AudioPort port; + AudioDevice device; + device.address = AudioDeviceAddress::make(address); + + AudioDeviceDescription description; + description.type = type; + description.connection = connection; + device.type = description; + + port.ext = AudioPortExt::make(device); + + return port; +} + +api::DeviceToContextEntry createRoutes(const AudioPort& port, + const std::vector& contexts) { + api::DeviceToContextEntry entry; + entry.device = port; + entry.contextNames = contexts; + return entry; +} + +api::VolumeGroupConfig createVolumeGroup(const std::string& name, + const api::VolumeActivationConfiguration& activation, + const std::vector& routes) { + api::VolumeGroupConfig config; + config.name = name; + config.activationConfiguration = activation; + config.carAudioRoutes = routes; + return config; +} + +api::AudioZoneConfig createAudioZoneConfig(const std::string& name, + const api::AudioZoneFadeConfiguration& fadeConfiguration, + const std::vector& groups, + bool isDefault = false) { + api::AudioZoneConfig config; + config.name = name; + config.isDefault = isDefault; + config.volumeGroups = groups; + config.fadeConfiguration = fadeConfiguration; + return config; +} + +api::VolumeActivationConfiguration createVolumeActivation(const std::string& name, + const api::VolumeInvocationType& type, + int minVolume, int maxVolume) { + api::VolumeActivationConfiguration activation; + activation.name = name; + api::VolumeActivationConfigurationEntry entry; + entry.maxActivationVolumePercentage = maxVolume; + entry.minActivationVolumePercentage = minVolume; + entry.type = type; + activation.volumeActivationEntries.push_back(entry); + + return activation; +} + +api::FadeConfiguration createFadeConfiguration(const long& fadeDurationsMillis, + const AudioAttributes& audioAttributes) { + api::FadeConfiguration configuration; + configuration.fadeDurationMillis = fadeDurationsMillis; + configuration.audioAttributesOrUsage + .set( + audioAttributes); + return configuration; +} + +api::FadeConfiguration createFadeConfiguration(const long& fadeDurationsMillis, + const AudioUsage& audioUsage) { + api::FadeConfiguration configuration; + configuration.fadeDurationMillis = fadeDurationsMillis; + configuration.audioAttributesOrUsage + .set(audioUsage); + return configuration; +} + +api::AudioFadeConfiguration createAudioFadeConfiguration( + const std::string& name, const api::FadeState& state, + const std::vector& fadeableUsages = std::vector(), + const std::optional>& unfadeableContentTypes = std::nullopt, + const std::vector unfadeableAudioAttributes = + std::vector(), + const std::vector fadeOutConfigurations = + std::vector(), + const std::vector fadeInConfigurations = + std::vector(), + const long& fadeOutDurationMs = api::AudioFadeConfiguration::DEFAULT_FADE_OUT_DURATION_MS, + const long& fadeInDurationMs = api::AudioFadeConfiguration::DEFAULT_FADE_IN_DURATION_MS, + const long& fadeInDelayedForOffendersMs = + api::AudioFadeConfiguration::DEFAULT_DELAY_FADE_IN_OFFENDERS_MS) { + api::AudioFadeConfiguration audioZoneFadeConfiguration; + audioZoneFadeConfiguration.name = name; + audioZoneFadeConfiguration.fadeInDurationMs = fadeInDurationMs; + audioZoneFadeConfiguration.fadeOutDurationMs = fadeOutDurationMs; + audioZoneFadeConfiguration.fadeInDelayedForOffendersMs = fadeInDelayedForOffendersMs; + audioZoneFadeConfiguration.fadeState = state; + audioZoneFadeConfiguration.fadeableUsages = fadeableUsages; + audioZoneFadeConfiguration.unfadeableContentTypes = unfadeableContentTypes; + audioZoneFadeConfiguration.unfadableAudioAttributes = unfadeableAudioAttributes; + audioZoneFadeConfiguration.fadeOutConfigurations = fadeOutConfigurations; + audioZoneFadeConfiguration.fadeInConfigurations = fadeInConfigurations; + + return audioZoneFadeConfiguration; +} + +api::TransientFadeConfigurationEntry createTransientFadeConfiguration( + const api::AudioFadeConfiguration& fadeConfig, const std::vector& usages) { + api::TransientFadeConfigurationEntry entry; + entry.transientFadeConfiguration = fadeConfig; + entry.transientUsages = usages; + return entry; +} + +api::AudioZoneFadeConfiguration createAudioZoneFadeConfiguration( + const api::AudioFadeConfiguration& defaultConfig, + const std::vector& transientConfigs) { + api::AudioZoneFadeConfiguration zoneFadeConfiguration; + zoneFadeConfiguration.defaultConfiguration = defaultConfig; + zoneFadeConfiguration.transientConfiguration = transientConfigs; + return zoneFadeConfiguration; +} + +api::AudioZone createAudioZone(const std::string& name, const int zoneId, + const std::vector& contexts, + const std::vector& configs) { + api::AudioZone zone; + zone.name = name; + zone.id = zoneId; + zone.occupantZoneId = zoneId; + zone.audioZoneContext.audioContextInfos = contexts; + zone.audioZoneConfigs = configs; + return zone; +} + +const std::vector kFadeableUsages = {AudioUsage::MEDIA, + AudioUsage::GAME, + AudioUsage::ASSISTANCE_SONIFICATION, + AudioUsage::ASSISTANCE_ACCESSIBILITY, + AudioUsage::ASSISTANCE_NAVIGATION_GUIDANCE, + AudioUsage::ASSISTANT, + AudioUsage::NOTIFICATION, + AudioUsage::ANNOUNCEMENT}; + +const std::vector kUnfadeableAudioAttributes = { + createAudioAttributes(AudioUsage::MEDIA, AudioContentType::UNKNOWN, "oem_specific_tag1")}; + +const std::vector kFadeOutConfigurations = { + createFadeConfiguration( + 500, createAudioAttributes(AudioUsage::ASSISTANT, AudioContentType::UNKNOWN, + "oem_specific_tag2")), + createFadeConfiguration(500, AudioUsage::MEDIA), + createFadeConfiguration(500, AudioUsage::GAME), + createFadeConfiguration(800, AudioUsage::ASSISTANCE_SONIFICATION), + createFadeConfiguration(800, AudioUsage::ASSISTANCE_ACCESSIBILITY), + createFadeConfiguration(800, AudioUsage::ASSISTANCE_NAVIGATION_GUIDANCE), + createFadeConfiguration(800, AudioUsage::ASSISTANT), + createFadeConfiguration(800, AudioUsage::ANNOUNCEMENT), +}; + +const std::vector kFadeInConfigurations = { + createFadeConfiguration( + 1000, createAudioAttributes(AudioUsage::ASSISTANT, AudioContentType::UNKNOWN, + "oem_specific_tag2")), + createFadeConfiguration(1000, AudioUsage::MEDIA), + createFadeConfiguration(1000, AudioUsage::GAME), + createFadeConfiguration(800, AudioUsage::ASSISTANCE_SONIFICATION), + createFadeConfiguration(800, AudioUsage::ASSISTANCE_ACCESSIBILITY), + createFadeConfiguration(800, AudioUsage::ASSISTANCE_NAVIGATION_GUIDANCE), + createFadeConfiguration(800, AudioUsage::ASSISTANT), + createFadeConfiguration(800, AudioUsage::ANNOUNCEMENT), +}; + +const api::AudioFadeConfiguration kRelaxedFading = createAudioFadeConfiguration( + "relaxed fading", api::FadeState::FADE_STATE_ENABLED_DEFAULT, kFadeableUsages, + std::optional>( + {AudioContentType::SPEECH, AudioContentType::SONIFICATION}), + kUnfadeableAudioAttributes, kFadeOutConfigurations, kFadeInConfigurations, 800, 500, 10000); + +const std::vector kAggressiveUnfadeableAudioAttributes = { + createAudioAttributes(AudioUsage::MEDIA, AudioContentType::UNKNOWN, "oem_specific_tag1"), + createAudioAttributes(AudioUsage::ASSISTANT, AudioContentType::UNKNOWN, + "oem_projection_service"), +}; + +const std::vector kAggressiveFadeOutConfigurations = { + createFadeConfiguration(150, AudioUsage::MEDIA), + createFadeConfiguration(150, AudioUsage::GAME), + createFadeConfiguration(400, AudioUsage::ASSISTANCE_SONIFICATION), + createFadeConfiguration(400, AudioUsage::ASSISTANCE_ACCESSIBILITY), + createFadeConfiguration(400, AudioUsage::ASSISTANCE_NAVIGATION_GUIDANCE), + createFadeConfiguration(400, AudioUsage::ASSISTANT), + createFadeConfiguration(400, AudioUsage::ANNOUNCEMENT), +}; + +const std::vector kAggressiveFadeInConfigurations = { + createFadeConfiguration(300, AudioUsage::MEDIA), + createFadeConfiguration(300, AudioUsage::GAME), + createFadeConfiguration(550, AudioUsage::ASSISTANCE_SONIFICATION), + createFadeConfiguration(550, AudioUsage::ASSISTANCE_ACCESSIBILITY), + createFadeConfiguration(550, AudioUsage::ASSISTANCE_NAVIGATION_GUIDANCE), + createFadeConfiguration(550, AudioUsage::ASSISTANT), + createFadeConfiguration(550, AudioUsage::ANNOUNCEMENT), +}; + +const api::AudioFadeConfiguration kAggressiveFading = createAudioFadeConfiguration( + "aggressive fading", api::FadeState::FADE_STATE_ENABLED_DEFAULT, kFadeableUsages, + std::optional>( + {AudioContentType::SPEECH, AudioContentType::MUSIC}), + kAggressiveUnfadeableAudioAttributes, kAggressiveFadeOutConfigurations, + kAggressiveFadeInConfigurations); + +const api::AudioFadeConfiguration kDisabledFading = + createAudioFadeConfiguration("disabled fading", api::FadeState::FADE_STATE_DISABLED); + +const std::vector kDynamicFadeOutConfigurations = { + createFadeConfiguration( + 500, createAudioAttributes(AudioUsage::ASSISTANT, AudioContentType::UNKNOWN, + "oem_specific_tag2")), + createFadeConfiguration(800, AudioUsage::ASSISTANCE_SONIFICATION), + createFadeConfiguration(800, AudioUsage::ASSISTANCE_ACCESSIBILITY), + createFadeConfiguration(800, AudioUsage::ASSISTANCE_NAVIGATION_GUIDANCE), + createFadeConfiguration(800, AudioUsage::ASSISTANT), + createFadeConfiguration(800, AudioUsage::ANNOUNCEMENT), +}; + +const std::vector kDynamicFadeInConfigurations = { + createFadeConfiguration( + 1000, createAudioAttributes(AudioUsage::ASSISTANT, AudioContentType::UNKNOWN, + "oem_specific_tag2")), + createFadeConfiguration(800, AudioUsage::ASSISTANCE_SONIFICATION), + createFadeConfiguration(800, AudioUsage::ASSISTANCE_ACCESSIBILITY), + createFadeConfiguration(800, AudioUsage::ASSISTANCE_NAVIGATION_GUIDANCE), + createFadeConfiguration(800, AudioUsage::ASSISTANT), + createFadeConfiguration(800, AudioUsage::ANNOUNCEMENT), +}; + +const api::AudioFadeConfiguration kDynamicFading = createAudioFadeConfiguration( + "dynamic fading", api::FadeState::FADE_STATE_ENABLED_DEFAULT, kFadeableUsages, + std::optional>( + {AudioContentType::SPEECH, AudioContentType::MOVIE}), + kUnfadeableAudioAttributes, kDynamicFadeOutConfigurations, kDynamicFadeInConfigurations, + 800, 500); + +const api::AudioZoneFadeConfiguration kDefaultAudioConfigFading = createAudioZoneFadeConfiguration( + kRelaxedFading, + {createTransientFadeConfiguration( + kAggressiveFading, {AudioUsage::VOICE_COMMUNICATION, AudioUsage::ANNOUNCEMENT, + AudioUsage::VEHICLE_STATUS, AudioUsage::SAFETY}), + createTransientFadeConfiguration(kDisabledFading, {AudioUsage::EMERGENCY})}); + +const api::AudioZoneFadeConfiguration kDynamicDeviceAudioConfigFading = + createAudioZoneFadeConfiguration( + kDynamicFading, + {createTransientFadeConfiguration( + kAggressiveFading, + {AudioUsage::VOICE_COMMUNICATION, AudioUsage::ANNOUNCEMENT, + AudioUsage::VEHICLE_STATUS, AudioUsage::SAFETY}), + createTransientFadeConfiguration(kDisabledFading, {AudioUsage::EMERGENCY})}); + +const api::AudioZoneContextInfo kMusicContextInfo = + createContextInfo("oem_music", {AudioUsage::MEDIA, AudioUsage::GAME, AudioUsage::UNKNOWN}); +const api::AudioZoneContextInfo kNotificationContextInfo = createContextInfo( + "oem_notification", {AudioUsage::NOTIFICATION, AudioUsage::NOTIFICATION_EVENT}); +const api::AudioZoneContextInfo kVoiceContextInfo = createContextInfo( + "oem_voice_command", {AudioUsage::ASSISTANT, AudioUsage::ASSISTANCE_ACCESSIBILITY, + AudioUsage::ASSISTANCE_NAVIGATION_GUIDANCE}); +const api::AudioZoneContextInfo kCallContextInfo = + createContextInfo("oem_call", {AudioUsage::VOICE_COMMUNICATION, AudioUsage::CALL_ASSISTANT, + AudioUsage::VOICE_COMMUNICATION_SIGNALLING}); +const api::AudioZoneContextInfo kRingContextInfo = + createContextInfo("oem_call_ring", {AudioUsage::NOTIFICATION_TELEPHONY_RINGTONE}); +const api::AudioZoneContextInfo kAlarmContextInfo = + createContextInfo("oem_alarm", {AudioUsage::ALARM}); +const api::AudioZoneContextInfo kSystemContextInfo = createContextInfo( + "oem_system_sound", + {AudioUsage::ASSISTANCE_SONIFICATION, AudioUsage::EMERGENCY, AudioUsage::SAFETY, + AudioUsage::VEHICLE_STATUS, AudioUsage::ANNOUNCEMENT}); +const api::AudioZoneContextInfo kOemContextInfo = createContextInfo( + "oem_context", {createAudioAttributes(AudioUsage::ASSISTANCE_NAVIGATION_GUIDANCE, + AudioContentType::SPEECH, "oem=extension_8675309")}); + +const std::vector kSimpleCarAudioConfigurationContext = { + kOemContextInfo, kMusicContextInfo, kNotificationContextInfo, kVoiceContextInfo, + kCallContextInfo, kRingContextInfo, kAlarmContextInfo, kSystemContextInfo}; + +const api::AudioZoneContextInfo kDefaultMusicContextInfo = + createContextInfo("music", {AudioUsage::UNKNOWN, AudioUsage::MEDIA, AudioUsage::GAME}, 1); +const api::AudioZoneContextInfo kDefaultNavContextInfo = + createContextInfo("navigation", {AudioUsage::ASSISTANCE_NAVIGATION_GUIDANCE}, 2); +const api::AudioZoneContextInfo kDefaultVoiceContextInfo = createContextInfo( + "voice_command", {AudioUsage::ASSISTANCE_ACCESSIBILITY, AudioUsage::ASSISTANT}, 3); +const api::AudioZoneContextInfo kDefaultRingContextInfo = + createContextInfo("call_ring", {AudioUsage::NOTIFICATION_TELEPHONY_RINGTONE}, 4); +const api::AudioZoneContextInfo kDefaultCallContextInfo = + createContextInfo("call", + {AudioUsage::VOICE_COMMUNICATION, AudioUsage::CALL_ASSISTANT, + AudioUsage::VOICE_COMMUNICATION_SIGNALLING}, + 5); +const api::AudioZoneContextInfo kDefaultAlarmContextInfo = + createContextInfo("alarm", {AudioUsage::ALARM}, 6); +const api::AudioZoneContextInfo kDefaultNotificationContextInfo = createContextInfo( + "notification", {AudioUsage::NOTIFICATION, AudioUsage::NOTIFICATION_EVENT}, 7); +const api::AudioZoneContextInfo kDefaultSystemContextInfo = + createContextInfo("system_sound", {AudioUsage::ASSISTANCE_SONIFICATION}, 8); +const api::AudioZoneContextInfo kDefaultEmergencyContextInfo = + createContextInfo("emergency", {AudioUsage::EMERGENCY}, 9); +const api::AudioZoneContextInfo kDefaultSafetyContextInfo = + createContextInfo("safety", {AudioUsage::SAFETY}, 10); +const api::AudioZoneContextInfo kDefaultVehicleStatusContextInfo = + createContextInfo("vehicle_status", {AudioUsage::VEHICLE_STATUS}, 11); +const api::AudioZoneContextInfo kDefaultAnnouncementContextInfo = + createContextInfo("announcement", {AudioUsage::ANNOUNCEMENT}, 12); + +const std::vector kDefaultCarAudioConfigurationContext = { + kDefaultMusicContextInfo, kDefaultNavContextInfo, + kDefaultVoiceContextInfo, kDefaultRingContextInfo, + kDefaultCallContextInfo, kDefaultAlarmContextInfo, + kDefaultNotificationContextInfo, kDefaultSystemContextInfo, + kDefaultEmergencyContextInfo, kDefaultSafetyContextInfo, + kDefaultVehicleStatusContextInfo, kDefaultAnnouncementContextInfo}; + +const api::VolumeActivationConfiguration kOnBootVolumeActivation = + createVolumeActivation("on_boot_config", api::VolumeInvocationType::ON_BOOT, 0, 80); +const api::VolumeActivationConfiguration kOnSourceVolumeActivation = createVolumeActivation( + "on_source_changed_config", api::VolumeInvocationType::ON_SOURCE_CHANGED, 20, 80); +const api::VolumeActivationConfiguration kOnPlayVolumeActivation = createVolumeActivation( + "on_playback_changed_config", api::VolumeInvocationType::ON_PLAYBACK_CHANGED, 10, 90); + +const AudioPort kBusMediaDevice = createAudioPort("BUS00_MEDIA", AudioDeviceType::OUT_BUS); +const AudioPort kBTMediaDevice = createAudioPort("temp", AudioDeviceType::OUT_DEVICE, "bt-a2dp"); +const AudioPort kUSBMediaDevice = createAudioPort("", AudioDeviceType::OUT_HEADSET, "usb"); + +const AudioPort kBusNavDevice = createAudioPort("BUS02_NAV_GUIDANCE", AudioDeviceType::OUT_BUS); +const AudioPort kBusPhoneDevice = createAudioPort("BUS03_PHONE", AudioDeviceType::OUT_BUS); +const AudioPort kBusSysDevice = createAudioPort("BUS01_SYS_NOTIFICATION", AudioDeviceType::OUT_BUS); + +const AudioPort kMirrorDevice1 = createAudioPort("mirror_bus_device_1", AudioDeviceType::OUT_BUS); +const AudioPort kMirrorDevice2 = createAudioPort("mirror_bus_device_2", AudioDeviceType::OUT_BUS); +const std::vector kMirroringDevices = {kMirrorDevice1, kMirrorDevice2}; + +const AudioPort kMirrorDeviceThree = + createAudioPort("mirror_bus_device_three", AudioDeviceType::OUT_BUS); +const AudioPort kMirrorDeviceFour = + createAudioPort("mirror_bus_device_four", AudioDeviceType::OUT_BUS); +const std::vector kMultiZoneMirroringDevices = {kMirrorDeviceThree, kMirrorDeviceFour}; + +const AudioPort kInFMTunerDevice = createAudioPort("fm_tuner", AudioDeviceType::IN_FM_TUNER); +const AudioPort kInMicDevice = createAudioPort("built_in_mic", AudioDeviceType::IN_MICROPHONE); +const AudioPort kInBusDevice = createAudioPort("in_bus_device", AudioDeviceType::IN_BUS); +const std::vector kInputDevices{kInFMTunerDevice, kInMicDevice, kInBusDevice}; + +const api::VolumeGroupConfig kBusMediaVolumeGroup = createVolumeGroup( + "entertainment", kOnBootVolumeActivation, {createRoutes(kBusMediaDevice, {"oem_music"})}); +const api::VolumeGroupConfig kUSBMediaVolumeGroup = createVolumeGroup( + "entertainment", kOnBootVolumeActivation, {createRoutes(kUSBMediaDevice, {"oem_music"})}); +const api::VolumeGroupConfig kBTMediaVolumeGroup = createVolumeGroup( + "entertainment", kOnBootVolumeActivation, {createRoutes(kBTMediaDevice, {"oem_music"})}); +const api::VolumeGroupConfig kBusNavVolumeGroup = + createVolumeGroup("navvoicecommand", kOnSourceVolumeActivation, + {createRoutes(kBusNavDevice, {"oem_voice_command"})}); +const api::VolumeGroupConfig kBusCallVolumeGroup = + createVolumeGroup("telringvol", kOnPlayVolumeActivation, + {createRoutes(kBusPhoneDevice, {"oem_call", "oem_call_ring"})}); +const api::VolumeGroupConfig kBusSysVolumeGroup = createVolumeGroup( + "systemalarm", kOnSourceVolumeActivation, + {createRoutes(kBusSysDevice, {"oem_alarm", "oem_system_sound", "oem_notification"})}); + +const api::AudioZoneConfig kAllBusZoneConfig = createAudioZoneConfig( + "primary zone config 0", kDefaultAudioConfigFading, + {kBusMediaVolumeGroup, kBusNavVolumeGroup, kBusCallVolumeGroup, kBusSysVolumeGroup}, true); +const api::AudioZoneConfig kBTMediaZoneConfig = createAudioZoneConfig( + "primary zone BT media", kDynamicDeviceAudioConfigFading, + {kBTMediaVolumeGroup, kBusNavVolumeGroup, kBusCallVolumeGroup, kBusSysVolumeGroup}); +const api::AudioZoneConfig kUsBMediaZoneConfig = createAudioZoneConfig( + "primary zone USB media", kDynamicDeviceAudioConfigFading, + {kUSBMediaVolumeGroup, kBusNavVolumeGroup, kBusCallVolumeGroup, kBusSysVolumeGroup}); + +const std::unordered_map kConfigNameToZoneConfig = { + {kAllBusZoneConfig.name, kAllBusZoneConfig}, + {kBTMediaZoneConfig.name, kBTMediaZoneConfig}, + {kUsBMediaZoneConfig.name, kUsBMediaZoneConfig}, +}; + +const api::AudioZoneConfig kDriverZoneConfig = createAudioZoneConfig( + "driver zone config 0", kDefaultAudioConfigFading, + {kBusMediaVolumeGroup, kBusNavVolumeGroup, kBusCallVolumeGroup, kBusSysVolumeGroup}, true); + +const api::AudioZone kDriverZone = + createAudioZone("driver zone", api::AudioZone::PRIMARY_AUDIO_ZONE, + kSimpleCarAudioConfigurationContext, {kDriverZoneConfig}); + +const api::AudioZoneFadeConfiguration kZoneAudioConfigFading = createAudioZoneFadeConfiguration( + kRelaxedFading, + {createTransientFadeConfiguration(kDisabledFading, {AudioUsage::EMERGENCY})}); + +const AudioPort kBusFrontDevice = createAudioPort("BUS_FRONT", AudioDeviceType::OUT_BUS); +const api::VolumeGroupConfig kFrontVolumeGroup = createVolumeGroup( + "entertainment", kOnBootVolumeActivation, + {createRoutes(kBusFrontDevice, + {"oem_music", "oem_voice_command", "oem_call", "oem_call_ring", "oem_alarm", + "oem_system_sound", "oem_notification"})}); +const api::AudioZoneConfig kFrontZoneConfig = createAudioZoneConfig( + "front passenger config 0", kZoneAudioConfigFading, {kFrontVolumeGroup}, true); +const api::AudioZone kFrontZone = + createAudioZone("front passenger zone", api::AudioZone::PRIMARY_AUDIO_ZONE + 1, + kSimpleCarAudioConfigurationContext, {kFrontZoneConfig}); + +const AudioPort kBusRearDevice = createAudioPort("BUS_REAR", AudioDeviceType::OUT_BUS); +const api::VolumeGroupConfig kRearVolumeGroup = + createVolumeGroup("entertainment", kOnBootVolumeActivation, + {createRoutes(kBusRearDevice, {"oem_music", "oem_voice_command", + "oem_call", "oem_call_ring", "oem_alarm", + "oem_system_sound", "oem_notification"})}); +const api::AudioZoneConfig kRearZoneConfig = createAudioZoneConfig( + "rear seat config 0", kZoneAudioConfigFading, {kRearVolumeGroup}, true); +const api::AudioZone kRearZone = + createAudioZone("rear seat zone", api::AudioZone::PRIMARY_AUDIO_ZONE + 2, + kSimpleCarAudioConfigurationContext, {kRearZoneConfig}); + +std::vector kMultiZones = {kDriverZone, kFrontZone, kRearZone}; + +void expectSameFadeConfiguration(const api::AudioFadeConfiguration& actual, + const api::AudioFadeConfiguration& expected, + const std::string& configName) { + EXPECT_EQ(actual.name, expected.name) << "Audio fade configuration for config " << configName; + const std::string fadeConfigInfo = + "fade config " + actual.name + " in config name " + configName; + EXPECT_EQ(actual.fadeState, expected.fadeState) + << "Audio fade config state for " << fadeConfigInfo; + EXPECT_EQ(actual.fadeInDurationMs, expected.fadeInDurationMs) + << "Audio fade in duration for " << fadeConfigInfo; + EXPECT_EQ(actual.fadeOutDurationMs, expected.fadeOutDurationMs) + << "Audio fade out duration for " << fadeConfigInfo; + EXPECT_EQ(actual.fadeInDelayedForOffendersMs, expected.fadeInDelayedForOffendersMs) + << "Audio fade in delayed for offenders duration for " << fadeConfigInfo; + EXPECT_THAT(actual.fadeableUsages, UnorderedElementsAreArray(expected.fadeableUsages)) + << "Fadeable usages for " << fadeConfigInfo; + EXPECT_TRUE(actual.unfadeableContentTypes.has_value() == + expected.unfadeableContentTypes.has_value()) + << "Optional unfadeable for " << fadeConfigInfo; + if (actual.unfadeableContentTypes.has_value() && expected.unfadeableContentTypes.has_value()) { + EXPECT_THAT(actual.unfadeableContentTypes.value(), + UnorderedElementsAreArray(expected.unfadeableContentTypes.value())) + << "Unfadeable content type for " << fadeConfigInfo; + } + EXPECT_THAT(actual.unfadableAudioAttributes, + UnorderedElementsAreArray(expected.unfadableAudioAttributes)) + << "Unfadeable audio attributes type for " << fadeConfigInfo; + EXPECT_THAT(actual.fadeOutConfigurations, + UnorderedElementsAreArray(expected.fadeOutConfigurations)) + << "Fade-out configurations for " << fadeConfigInfo; + EXPECT_THAT(actual.fadeInConfigurations, + UnorderedElementsAreArray(expected.fadeInConfigurations)) + << "Fade-in configurations for " << fadeConfigInfo; +} + +void expectSameAudioZoneFadeConfiguration( + const std::optional& actual, + const std::optional& expected, + const std::string& configName) { + if (!actual.has_value() || !expected.has_value()) { + EXPECT_EQ(actual.has_value(), expected.has_value()) + << "Audio zone config " << configName << " fade configuration missing"; + return; + } + const api::AudioZoneFadeConfiguration& actualConfig = actual.value(); + const api::AudioZoneFadeConfiguration& expectedConfig = expected.value(); + expectSameFadeConfiguration(actualConfig.defaultConfiguration, + expectedConfig.defaultConfiguration, configName); + EXPECT_THAT(actualConfig.transientConfiguration, + UnorderedElementsAreArray(expectedConfig.transientConfiguration)) + << "Transient fade configuration for config " << configName; +} + +void expectSameAudioZoneConfiguration(const api::AudioZoneConfig& actual, + const api::AudioZoneConfig& expected) { + EXPECT_EQ(actual.isDefault, expected.isDefault) + << "Zone default's status do not match for config " << actual.name; + EXPECT_THAT(actual.volumeGroups, UnorderedElementsAreArray(expected.volumeGroups)) + << "Volume groups for config " << actual.name; + expectSameAudioZoneFadeConfiguration(actual.fadeConfiguration, expected.fadeConfiguration, + actual.name); +} + +class CarAudioConfigurationTest : public testing::Test { + protected: + void SetUp() override; + void TearDown() override; + + std::unique_ptr converter; + + protected: + virtual std::string getCarAudioConfiguration() = 0; + virtual std::string getCarFadeConfiguration() = 0; +}; + +void CarAudioConfigurationTest::SetUp() { + converter = std::make_unique( + getTestFilePath(getCarAudioConfiguration()), + getTestFilePath(getCarFadeConfiguration())); +} + +void CarAudioConfigurationTest::TearDown() { + converter.reset(); +} + +class SimpleCarAudioConfigurationTest : public CarAudioConfigurationTest { + virtual std::string getCarAudioConfiguration() { return "simple_car_audio_configuration.xml"; } + + virtual std::string getCarFadeConfiguration() { return "car_audio_fade_configuration.xml"; } +}; + +TEST_F(SimpleCarAudioConfigurationTest, TestLoadSimpleConfiguration) { + EXPECT_EQ(converter->getErrors(), ""); + + const auto audioDeviceConfigs = converter->getAudioDeviceConfiguration(); + EXPECT_EQ(audioDeviceConfigs.routingConfig, + api::RoutingDeviceConfiguration::DYNAMIC_AUDIO_ROUTING); + EXPECT_FALSE(audioDeviceConfigs.useCoreAudioVolume); + EXPECT_TRUE(audioDeviceConfigs.useHalDuckingSignals); + EXPECT_TRUE(audioDeviceConfigs.useCarVolumeGroupMuting); + + const auto& mirroringDevices = converter->getOutputMirroringDevices(); + + EXPECT_EQ(mirroringDevices.size(), 2) << "Mirroring device size"; + for (const auto& mirroringDevice : mirroringDevices) { + const auto& it = + std::find(kMirroringDevices.begin(), kMirroringDevices.end(), mirroringDevice); + EXPECT_TRUE(it != kMirroringDevices.end()) + << "Mirroring device not found " << mirroringDevice.toString(); + } + + const auto zones = converter->getAudioZones(); + EXPECT_EQ(zones.size(), 1); + + const auto& zone = zones.front(); + EXPECT_EQ(zone.id, api::AudioZone::PRIMARY_AUDIO_ZONE); + EXPECT_EQ(zone.occupantZoneId, 0); + EXPECT_EQ(zone.name, "primary zone"); + + EXPECT_EQ(zone.audioZoneContext.audioContextInfos.size(), + kSimpleCarAudioConfigurationContext.size()); + for (const auto& info : zone.audioZoneContext.audioContextInfos) { + const auto iterator = std::find(kSimpleCarAudioConfigurationContext.begin(), + kSimpleCarAudioConfigurationContext.end(), info); + EXPECT_TRUE(iterator != kSimpleCarAudioConfigurationContext.end()) + << "Context name " << info.toString() << kMusicContextInfo.toString(); + } + + for (const auto& config : zone.audioZoneConfigs) { + const auto& iterator = kConfigNameToZoneConfig.find(config.name); + EXPECT_TRUE(iterator != kConfigNameToZoneConfig.end()) + << "Zone config not found " << config.name; + expectSameAudioZoneConfiguration(config, iterator->second); + } + + const auto& inputDevices = zone.inputAudioDevices; + EXPECT_EQ(inputDevices.size(), 3) << "Input devices"; + for (const auto& inputDevice : inputDevices) { + const auto& it = std::find(kInputDevices.begin(), kInputDevices.end(), inputDevice); + EXPECT_TRUE(it != kInputDevices.end()) + << "Input device " << inputDevice.toString() << " not found"; + } +} + +class TypeDeviceCarAudioConfigurationTest : public CarAudioConfigurationTest { + virtual std::string getCarAudioConfiguration() { + return "simple_car_audio_configuration_with_device_type.xml"; + } + + virtual std::string getCarFadeConfiguration() { return "car_audio_fade_configuration.xml"; } +}; + +TEST_F(TypeDeviceCarAudioConfigurationTest, TestLoadConfigurationWithDeviceType) { + EXPECT_EQ(converter->getErrors(), ""); + + const auto audioDeviceConfigs = converter->getAudioDeviceConfiguration(); + EXPECT_EQ(audioDeviceConfigs.routingConfig, + api::RoutingDeviceConfiguration::DYNAMIC_AUDIO_ROUTING); + EXPECT_FALSE(audioDeviceConfigs.useCoreAudioVolume); + EXPECT_TRUE(audioDeviceConfigs.useHalDuckingSignals); + EXPECT_TRUE(audioDeviceConfigs.useCarVolumeGroupMuting); + + const auto& mirroringDevices = converter->getOutputMirroringDevices(); + + EXPECT_EQ(mirroringDevices.size(), 2) << "Mirroring device size"; + for (const auto& mirroringDevice : mirroringDevices) { + const auto& it = + std::find(kMirroringDevices.begin(), kMirroringDevices.end(), mirroringDevice); + EXPECT_TRUE(it != kMirroringDevices.end()) + << "Mirroring device not found " << mirroringDevice.toString(); + } + + const auto zones = converter->getAudioZones(); + EXPECT_EQ(zones.size(), 1); + + const auto& zone = zones.front(); + EXPECT_EQ(zone.id, api::AudioZone::PRIMARY_AUDIO_ZONE); + EXPECT_EQ(zone.occupantZoneId, 0); + EXPECT_EQ(zone.name, "primary zone"); + + EXPECT_EQ(zone.audioZoneContext.audioContextInfos.size(), + kSimpleCarAudioConfigurationContext.size()); + for (const auto& info : zone.audioZoneContext.audioContextInfos) { + const auto iterator = std::find(kSimpleCarAudioConfigurationContext.begin(), + kSimpleCarAudioConfigurationContext.end(), info); + EXPECT_TRUE(iterator != kSimpleCarAudioConfigurationContext.end()) + << "Context name " << info.toString() << kMusicContextInfo.toString(); + } + + for (const auto& config : zone.audioZoneConfigs) { + const auto& iterator = kConfigNameToZoneConfig.find(config.name); + EXPECT_TRUE(iterator != kConfigNameToZoneConfig.end()) + << "Zone config not found " << config.name; + expectSameAudioZoneConfiguration(config, iterator->second); + } + + const auto& inputDevices = zone.inputAudioDevices; + EXPECT_EQ(inputDevices.size(), 3) << "Input devices"; + for (const auto& inputDevice : inputDevices) { + const auto& it = std::find(kInputDevices.begin(), kInputDevices.end(), inputDevice); + EXPECT_TRUE(it != kInputDevices.end()) + << "Input device " << inputDevice.toString() << " not found"; + } +} + +class CarAudioConfigurationWithDefaultContextTest : public CarAudioConfigurationTest { + virtual std::string getCarAudioConfiguration() { + return "car_audio_configuration_with_default_context.xml"; + } + + virtual std::string getCarFadeConfiguration() { return ""; } +}; + +TEST_F(CarAudioConfigurationWithDefaultContextTest, TestLoadConfiguration) { + EXPECT_EQ(converter->getErrors(), ""); + const auto& zones = converter->getAudioZones(); + EXPECT_EQ(zones.size(), 1) << "Default audio context zones"; + const auto& zone = zones.front(); + const auto& context = zone.audioZoneContext; + EXPECT_THAT(context.audioContextInfos, + UnorderedElementsAreArray(kDefaultCarAudioConfigurationContext)) + << "Default audio contexts"; +} + +class MultiZoneCarAudioConfigurationTest : public CarAudioConfigurationTest { + std::string getCarAudioConfiguration() override { + return "multi_zone_car_audio_configuration.xml"; + } + + std::string getCarFadeConfiguration() override { return "car_audio_fade_configuration.xml"; } +}; + +TEST_F(MultiZoneCarAudioConfigurationTest, TestLoadMultiZoneConfiguration) { + EXPECT_EQ(converter->getErrors(), ""); + + const auto audioDeviceConfigs = converter->getAudioDeviceConfiguration(); + EXPECT_EQ(audioDeviceConfigs.routingConfig, + api::RoutingDeviceConfiguration::CONFIGURABLE_AUDIO_ENGINE_ROUTING); + EXPECT_TRUE(audioDeviceConfigs.useCoreAudioVolume); + EXPECT_FALSE(audioDeviceConfigs.useHalDuckingSignals); + EXPECT_FALSE(audioDeviceConfigs.useCarVolumeGroupMuting); + + const auto& mirroringDevices = converter->getOutputMirroringDevices(); + + EXPECT_THAT(mirroringDevices, UnorderedElementsAreArray(kMultiZoneMirroringDevices)); + + const auto zones = converter->getAudioZones(); + EXPECT_THAT(zones, UnorderedElementsAreArray(kMultiZones)); +} + +class MalformedCarAudioConfigurationTest : public testing::Test { + protected: + void TearDown() override; + + std::unique_ptr converter; +}; + +void MalformedCarAudioConfigurationTest::TearDown() { + converter.reset(); +} + +TEST_F(MalformedCarAudioConfigurationTest, TestLoadEmptyConfiguration) { + converter = + std::make_unique(getTestFilePath(""), ""); + EXPECT_THAT(converter->getErrors(), ContainsRegex("Configuration file .+ is not readable")) + << "Empty configuration file"; + + const auto audioDeviceConfigs = converter->getAudioDeviceConfiguration(); + EXPECT_EQ(audioDeviceConfigs.routingConfig, + api::RoutingDeviceConfiguration::DEFAULT_AUDIO_ROUTING) + << "Default configuration for empty file"; +} + +TEST_F(MalformedCarAudioConfigurationTest, TestLoadNonExistingConfiguration) { + converter = std::make_unique( + getTestFilePath("non_existing_file.xml"), ""); + EXPECT_THAT(converter->getErrors(), ContainsRegex("Configuration file .+ is not readable")) + << "Empty configuration file"; + + const auto audioDeviceConfigs = converter->getAudioDeviceConfiguration(); + EXPECT_EQ(audioDeviceConfigs.routingConfig, + api::RoutingDeviceConfiguration::DEFAULT_AUDIO_ROUTING) + << "Default configuration for empty file"; +} + +TEST_F(MalformedCarAudioConfigurationTest, TestLoadMalforedConfiguration) { + converter = std::make_unique( + getTestFilePath("car_audio_configuration_without_configuration.xml"), ""); + EXPECT_THAT(converter->getErrors(), + ContainsRegex("Configuration file .+ does not have any configurations")) + << "Configuration file without configurations"; + + const auto audioDeviceConfigs = converter->getAudioDeviceConfiguration(); + EXPECT_EQ(audioDeviceConfigs.routingConfig, + api::RoutingDeviceConfiguration::DEFAULT_AUDIO_ROUTING) + << "Default configuration for malformed file"; +} + +TEST_F(MalformedCarAudioConfigurationTest, TestLoadConfigurationWithoutZones) { + converter = std::make_unique( + getTestFilePath("car_audio_configuration_without_audio_zone.xml"), ""); + EXPECT_THAT(converter->getErrors(), ContainsRegex("Audio zones not found in file")) + << "Configuration file without zones"; + + const auto audioDeviceConfigs = converter->getAudioDeviceConfiguration(); + EXPECT_EQ(audioDeviceConfigs.routingConfig, + api::RoutingDeviceConfiguration::DEFAULT_AUDIO_ROUTING) + << "Default configuration for file without zones"; +} + +TEST_F(MalformedCarAudioConfigurationTest, TestLoadConfigurationWithMissingZones) { + converter = std::make_unique( + getTestFilePath("car_audio_configuration_with_missing_zones.xml"), ""); + EXPECT_THAT(converter->getErrors(), ContainsRegex("Error parsing audio zone")) + << "Configuration file with missing zones"; + + const auto audioDeviceConfigs = converter->getAudioDeviceConfiguration(); + EXPECT_EQ(audioDeviceConfigs.routingConfig, + api::RoutingDeviceConfiguration::DEFAULT_AUDIO_ROUTING) + << "Default configuration for file with missing zones"; +} + +} // namespace diff --git a/automotive/audiocontrol/aidl/default/converter/test/car_audio_configuration_with_default_context.xml b/automotive/audiocontrol/aidl/default/converter/test/car_audio_configuration_with_default_context.xml new file mode 100644 index 0000000000..80cb5cdfc1 --- /dev/null +++ b/automotive/audiocontrol/aidl/default/converter/test/car_audio_configuration_with_default_context.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/automotive/audiocontrol/aidl/default/converter/test/car_audio_configuration_with_missing_zones.xml b/automotive/audiocontrol/aidl/default/converter/test/car_audio_configuration_with_missing_zones.xml new file mode 100644 index 0000000000..a5880b33f4 --- /dev/null +++ b/automotive/audiocontrol/aidl/default/converter/test/car_audio_configuration_with_missing_zones.xml @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/automotive/audiocontrol/aidl/default/converter/test/car_audio_configuration_without_audio_zone.xml b/automotive/audiocontrol/aidl/default/converter/test/car_audio_configuration_without_audio_zone.xml new file mode 100644 index 0000000000..1e50e6e2d2 --- /dev/null +++ b/automotive/audiocontrol/aidl/default/converter/test/car_audio_configuration_without_audio_zone.xml @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/automotive/audiocontrol/aidl/default/converter/test/car_audio_configuration_without_configuration.xml b/automotive/audiocontrol/aidl/default/converter/test/car_audio_configuration_without_configuration.xml new file mode 100644 index 0000000000..4f50ca260c --- /dev/null +++ b/automotive/audiocontrol/aidl/default/converter/test/car_audio_configuration_without_configuration.xml @@ -0,0 +1,15 @@ + + + + + diff --git a/automotive/audiocontrol/aidl/default/converter/test/car_audio_fade_configuration.xml b/automotive/audiocontrol/aidl/default/converter/test/car_audio_fade_configuration.xml new file mode 100644 index 0000000000..249f915815 --- /dev/null +++ b/automotive/audiocontrol/aidl/default/converter/test/car_audio_fade_configuration.xml @@ -0,0 +1,191 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/automotive/audiocontrol/aidl/default/converter/test/multi_zone_car_audio_configuration.xml b/automotive/audiocontrol/aidl/default/converter/test/multi_zone_car_audio_configuration.xml new file mode 100644 index 0000000000..f0c9081f59 --- /dev/null +++ b/automotive/audiocontrol/aidl/default/converter/test/multi_zone_car_audio_configuration.xml @@ -0,0 +1,196 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/automotive/audiocontrol/aidl/default/converter/test/simple_car_audio_configuration.xml b/automotive/audiocontrol/aidl/default/converter/test/simple_car_audio_configuration.xml new file mode 100644 index 0000000000..a6f5317a41 --- /dev/null +++ b/automotive/audiocontrol/aidl/default/converter/test/simple_car_audio_configuration.xml @@ -0,0 +1,233 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/automotive/audiocontrol/aidl/default/converter/test/simple_car_audio_configuration_with_device_type.xml b/automotive/audiocontrol/aidl/default/converter/test/simple_car_audio_configuration_with_device_type.xml new file mode 100644 index 0000000000..eec9db9c71 --- /dev/null +++ b/automotive/audiocontrol/aidl/default/converter/test/simple_car_audio_configuration_with_device_type.xml @@ -0,0 +1,233 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/automotive/audiocontrol/aidl/default/loaders/config/Android.bp b/automotive/audiocontrol/aidl/default/loaders/config/Android.bp new file mode 100644 index 0000000000..0d5eb8139c --- /dev/null +++ b/automotive/audiocontrol/aidl/default/loaders/config/Android.bp @@ -0,0 +1,45 @@ +// Copyright (C) 2024 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "hardware_interfaces_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["hardware_interfaces_license"], +} + +xsd_config { + name: "car_audio_configuration_xsd", + srcs: ["car_audio_configuration.xsd"], + package_name: "android.hardware.automotive.audiocontrol", + nullability: true, +} + +cc_defaults { + name: "car.audio.configuration.xsd.default", + static_libs: [ + "libxml2", + ], + generated_sources: [ + "car_audio_configuration_xsd", + ], + generated_headers: [ + "car_audio_configuration_xsd", + ], + header_libs: [ + "libxsdc-utils", + ], +} diff --git a/automotive/audiocontrol/aidl/default/loaders/config/api/current.txt b/automotive/audiocontrol/aidl/default/loaders/config/api/current.txt new file mode 100644 index 0000000000..c87b8c6adb --- /dev/null +++ b/automotive/audiocontrol/aidl/default/loaders/config/api/current.txt @@ -0,0 +1,331 @@ +// Signature format: 2.0 +package android.hardware.automotive.audiocontrol { + + public enum ActivationType { + method @NonNull public String getRawName(); + enum_constant public static final android.hardware.automotive.audiocontrol.ActivationType onBoot; + enum_constant public static final android.hardware.automotive.audiocontrol.ActivationType onPlaybackChanged; + enum_constant public static final android.hardware.automotive.audiocontrol.ActivationType onSourceChanged; + } + + public class ActivationVolumeConfigEntryType { + ctor public ActivationVolumeConfigEntryType(); + method @Nullable public android.hardware.automotive.audiocontrol.ActivationType getInvocationType(); + method @Nullable public String getMaxActivationVolumePercentage(); + method @Nullable public String getMinActivationVolumePercentage(); + method public void setInvocationType(@Nullable android.hardware.automotive.audiocontrol.ActivationType); + method public void setMaxActivationVolumePercentage(@Nullable String); + method public void setMinActivationVolumePercentage(@Nullable String); + } + + public class ActivationVolumeConfigType { + ctor public ActivationVolumeConfigType(); + method @Nullable public java.util.List getActivationVolumeConfigEntry(); + method @Nullable public String getName(); + method public void setName(@Nullable String); + } + + public class ActivationVolumeConfigsType { + ctor public ActivationVolumeConfigsType(); + method @Nullable public java.util.List getActivationVolumeConfig(); + } + + public class ApplyFadeConfigType { + ctor public ApplyFadeConfigType(); + method @Nullable public java.util.List getAudioAttributes(); + method @Nullable public boolean getIsDefault(); + method @Nullable public String getName(); + method public void setIsDefault(@Nullable boolean); + method public void setName(@Nullable String); + } + + public class ApplyFadeConfigsType { + ctor public ApplyFadeConfigsType(); + method @Nullable public java.util.List getFadeConfig(); + } + + public class AttributesType { + ctor public AttributesType(); + method @Nullable public android.hardware.automotive.audiocontrol.ContentTypeEnum getContentType(); + method @Nullable public String getTags(); + method @Nullable public android.hardware.automotive.audiocontrol.UsageEnumType getUsage(); + method public void setContentType(@Nullable android.hardware.automotive.audiocontrol.ContentTypeEnum); + method public void setTags(@Nullable String); + method public void setUsage(@Nullable android.hardware.automotive.audiocontrol.UsageEnumType); + } + + public class AudioAttributeUsagesType { + ctor public AudioAttributeUsagesType(); + method @Nullable public java.util.List getUsage(); + } + + public class AudioAttributesUsagesType { + ctor public AudioAttributesUsagesType(); + method @Nullable public java.util.List getAudioAttribute_optional(); + method @Nullable public java.util.List getUsage_optional(); + } + + public class CarAudioConfigurationType { + ctor public CarAudioConfigurationType(); + method @Nullable public android.hardware.automotive.audiocontrol.ActivationVolumeConfigsType getActivationVolumeConfigs(); + method @Nullable public android.hardware.automotive.audiocontrol.DeviceConfigurationsType getDeviceConfigurations(); + method @Nullable public android.hardware.automotive.audiocontrol.MirroringDevicesType getMirroringDevices(); + method @Nullable public android.hardware.automotive.audiocontrol.OemContextsType getOemContexts(); + method @Nullable public String getVersion(); + method @Nullable public android.hardware.automotive.audiocontrol.ZonesType getZones(); + method public void setActivationVolumeConfigs(@Nullable android.hardware.automotive.audiocontrol.ActivationVolumeConfigsType); + method public void setDeviceConfigurations(@Nullable android.hardware.automotive.audiocontrol.DeviceConfigurationsType); + method public void setMirroringDevices(@Nullable android.hardware.automotive.audiocontrol.MirroringDevicesType); + method public void setOemContexts(@Nullable android.hardware.automotive.audiocontrol.OemContextsType); + method public void setVersion(@Nullable String); + method public void setZones(@Nullable android.hardware.automotive.audiocontrol.ZonesType); + } + + public class ContentType { + ctor public ContentType(); + method @Nullable public android.hardware.automotive.audiocontrol.ContentTypeEnum getValue(); + method public void setValue(@Nullable android.hardware.automotive.audiocontrol.ContentTypeEnum); + } + + public enum ContentTypeEnum { + method @NonNull public String getRawName(); + enum_constant public static final android.hardware.automotive.audiocontrol.ContentTypeEnum AUDIO_CONTENT_TYPE_MOVIE; + enum_constant public static final android.hardware.automotive.audiocontrol.ContentTypeEnum AUDIO_CONTENT_TYPE_MUSIC; + enum_constant public static final android.hardware.automotive.audiocontrol.ContentTypeEnum AUDIO_CONTENT_TYPE_SONIFICATION; + enum_constant public static final android.hardware.automotive.audiocontrol.ContentTypeEnum AUDIO_CONTENT_TYPE_SPEECH; + enum_constant public static final android.hardware.automotive.audiocontrol.ContentTypeEnum AUDIO_CONTENT_TYPE_UNKNOWN; + } + + public class ContextNameType { + ctor public ContextNameType(); + method @Nullable public String getContext(); + method public void setContext(@Nullable String); + } + + public class DeviceConfigurationType { + ctor public DeviceConfigurationType(); + method @Nullable public String getName(); + method @Nullable public String getValue(); + method public void setName(@Nullable String); + method public void setValue(@Nullable String); + } + + public class DeviceConfigurationsType { + ctor public DeviceConfigurationsType(); + method @Nullable public java.util.List getDeviceConfiguration(); + } + + public class DeviceRoutesType { + ctor public DeviceRoutesType(); + method @Nullable public String getAddress(); + method @Nullable public java.util.List getContext(); + method @Nullable public android.hardware.automotive.audiocontrol.OutDeviceType getType(); + method public void setAddress(@Nullable String); + method public void setType(@Nullable android.hardware.automotive.audiocontrol.OutDeviceType); + } + + public enum InDeviceType { + method @NonNull public String getRawName(); + enum_constant public static final android.hardware.automotive.audiocontrol.InDeviceType AUDIO_DEVICE_IN_AMBIENT; + enum_constant public static final android.hardware.automotive.audiocontrol.InDeviceType AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET; + enum_constant public static final android.hardware.automotive.audiocontrol.InDeviceType AUDIO_DEVICE_IN_AUX_DIGITAL; + enum_constant public static final android.hardware.automotive.audiocontrol.InDeviceType AUDIO_DEVICE_IN_BACK_MIC; + enum_constant public static final android.hardware.automotive.audiocontrol.InDeviceType AUDIO_DEVICE_IN_BLUETOOTH_A2DP; + enum_constant public static final android.hardware.automotive.audiocontrol.InDeviceType AUDIO_DEVICE_IN_BLUETOOTH_BLE; + enum_constant public static final android.hardware.automotive.audiocontrol.InDeviceType AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET; + enum_constant public static final android.hardware.automotive.audiocontrol.InDeviceType AUDIO_DEVICE_IN_BUILTIN_MIC; + enum_constant public static final android.hardware.automotive.audiocontrol.InDeviceType AUDIO_DEVICE_IN_BUS; + enum_constant public static final android.hardware.automotive.audiocontrol.InDeviceType AUDIO_DEVICE_IN_COMMUNICATION; + enum_constant public static final android.hardware.automotive.audiocontrol.InDeviceType AUDIO_DEVICE_IN_DEFAULT; + enum_constant public static final android.hardware.automotive.audiocontrol.InDeviceType AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET; + enum_constant public static final android.hardware.automotive.audiocontrol.InDeviceType AUDIO_DEVICE_IN_ECHO_REFERENCE; + enum_constant public static final android.hardware.automotive.audiocontrol.InDeviceType AUDIO_DEVICE_IN_FM_TUNER; + enum_constant public static final android.hardware.automotive.audiocontrol.InDeviceType AUDIO_DEVICE_IN_HDMI; + enum_constant public static final android.hardware.automotive.audiocontrol.InDeviceType AUDIO_DEVICE_IN_HDMI_ARC; + enum_constant public static final android.hardware.automotive.audiocontrol.InDeviceType AUDIO_DEVICE_IN_IP; + enum_constant public static final android.hardware.automotive.audiocontrol.InDeviceType AUDIO_DEVICE_IN_LINE; + enum_constant public static final android.hardware.automotive.audiocontrol.InDeviceType AUDIO_DEVICE_IN_LOOPBACK; + enum_constant public static final android.hardware.automotive.audiocontrol.InDeviceType AUDIO_DEVICE_IN_PROXY; + enum_constant public static final android.hardware.automotive.audiocontrol.InDeviceType AUDIO_DEVICE_IN_REMOTE_SUBMIX; + enum_constant public static final android.hardware.automotive.audiocontrol.InDeviceType AUDIO_DEVICE_IN_SPDIF; + enum_constant public static final android.hardware.automotive.audiocontrol.InDeviceType AUDIO_DEVICE_IN_STUB; + enum_constant public static final android.hardware.automotive.audiocontrol.InDeviceType AUDIO_DEVICE_IN_TELEPHONY_RX; + enum_constant public static final android.hardware.automotive.audiocontrol.InDeviceType AUDIO_DEVICE_IN_TV_TUNER; + enum_constant public static final android.hardware.automotive.audiocontrol.InDeviceType AUDIO_DEVICE_IN_USB_ACCESSORY; + enum_constant public static final android.hardware.automotive.audiocontrol.InDeviceType AUDIO_DEVICE_IN_USB_DEVICE; + enum_constant public static final android.hardware.automotive.audiocontrol.InDeviceType AUDIO_DEVICE_IN_USB_HEADSET; + enum_constant public static final android.hardware.automotive.audiocontrol.InDeviceType AUDIO_DEVICE_IN_VOICE_CALL; + enum_constant public static final android.hardware.automotive.audiocontrol.InDeviceType AUDIO_DEVICE_IN_WIRED_HEADSET; + } + + public class InputDeviceType { + ctor public InputDeviceType(); + method @Nullable public String getAddress(); + method @Nullable public android.hardware.automotive.audiocontrol.InDeviceType getType(); + method public void setAddress(@Nullable String); + method public void setType(@Nullable android.hardware.automotive.audiocontrol.InDeviceType); + } + + public class InputDevicesType { + ctor public InputDevicesType(); + method @Nullable public java.util.List getInputDevice(); + } + + public class MirroringDevice { + ctor public MirroringDevice(); + method @Nullable public String getAddress(); + method public void setAddress(@Nullable String); + } + + public class MirroringDevicesType { + ctor public MirroringDevicesType(); + method @Nullable public java.util.List getMirroringDevice(); + } + + public class OemContextType { + ctor public OemContextType(); + method @Nullable public android.hardware.automotive.audiocontrol.AudioAttributesUsagesType getAudioAttributes(); + method @Nullable public String getId(); + method @Nullable public String getName(); + method public void setAudioAttributes(@Nullable android.hardware.automotive.audiocontrol.AudioAttributesUsagesType); + method public void setId(@Nullable String); + method public void setName(@Nullable String); + } + + public class OemContextsType { + ctor public OemContextsType(); + method @Nullable public java.util.List getOemContext(); + } + + public enum OutDeviceType { + method @NonNull public String getRawName(); + enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType AUDIO_DEVICE_OUT_AUX_DIGITAL; + enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType AUDIO_DEVICE_OUT_AUX_LINE; + enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType AUDIO_DEVICE_OUT_BLE_BROADCAST; + enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType AUDIO_DEVICE_OUT_BLE_HEADSET; + enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType AUDIO_DEVICE_OUT_BLE_SPEAKER; + enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType AUDIO_DEVICE_OUT_BLUETOOTH_A2DP; + enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES; + enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER; + enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType AUDIO_DEVICE_OUT_BUS; + enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType AUDIO_DEVICE_OUT_DEFAULT; + enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType AUDIO_DEVICE_OUT_HDMI; + enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType AUDIO_DEVICE_OUT_HDMI_ARC; + enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType AUDIO_DEVICE_OUT_HDMI_EARC; + enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType AUDIO_DEVICE_OUT_LINE; + enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType AUDIO_DEVICE_OUT_SPEAKER; + enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType AUDIO_DEVICE_OUT_SPEAKER_SAFE; + enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType AUDIO_DEVICE_OUT_USB_ACCESSORY; + enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType AUDIO_DEVICE_OUT_USB_DEVICE; + enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType AUDIO_DEVICE_OUT_USB_HEADSET; + enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType AUDIO_DEVICE_OUT_WIRED_HEADPHONE; + enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType AUDIO_DEVICE_OUT_WIRED_HEADSET; + enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType TYPE_AUX_LINE; + enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType TYPE_BLE_BROADCAST; + enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType TYPE_BLE_HEADSET; + enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType TYPE_BLE_SPEAKER; + enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType TYPE_BLUETOOTH_A2DP; + enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType TYPE_BUILTIN_SPEAKER; + enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType TYPE_BUS; + enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType TYPE_HDMI; + enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType TYPE_USB_ACCESSORY; + enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType TYPE_USB_DEVICE; + enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType TYPE_USB_HEADSET; + enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType TYPE_WIRED_HEADPHONES; + enum_constant public static final android.hardware.automotive.audiocontrol.OutDeviceType TYPE_WIRED_HEADSET; + } + + public enum UsageEnumType { + method @NonNull public String getRawName(); + enum_constant public static final android.hardware.automotive.audiocontrol.UsageEnumType AUDIO_USAGE_ALARM; + enum_constant public static final android.hardware.automotive.audiocontrol.UsageEnumType AUDIO_USAGE_ANNOUNCEMENT; + enum_constant public static final android.hardware.automotive.audiocontrol.UsageEnumType AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY; + enum_constant public static final android.hardware.automotive.audiocontrol.UsageEnumType AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE; + enum_constant public static final android.hardware.automotive.audiocontrol.UsageEnumType AUDIO_USAGE_ASSISTANCE_SONIFICATION; + enum_constant public static final android.hardware.automotive.audiocontrol.UsageEnumType AUDIO_USAGE_ASSISTANT; + enum_constant public static final android.hardware.automotive.audiocontrol.UsageEnumType AUDIO_USAGE_CALL_ASSISTANT; + enum_constant public static final android.hardware.automotive.audiocontrol.UsageEnumType AUDIO_USAGE_EMERGENCY; + enum_constant public static final android.hardware.automotive.audiocontrol.UsageEnumType AUDIO_USAGE_GAME; + enum_constant public static final android.hardware.automotive.audiocontrol.UsageEnumType AUDIO_USAGE_MEDIA; + enum_constant public static final android.hardware.automotive.audiocontrol.UsageEnumType AUDIO_USAGE_NOTIFICATION; + enum_constant public static final android.hardware.automotive.audiocontrol.UsageEnumType AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED; + enum_constant public static final android.hardware.automotive.audiocontrol.UsageEnumType AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT; + enum_constant public static final android.hardware.automotive.audiocontrol.UsageEnumType AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST; + enum_constant public static final android.hardware.automotive.audiocontrol.UsageEnumType AUDIO_USAGE_NOTIFICATION_EVENT; + enum_constant public static final android.hardware.automotive.audiocontrol.UsageEnumType AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE; + enum_constant public static final android.hardware.automotive.audiocontrol.UsageEnumType AUDIO_USAGE_SAFETY; + enum_constant public static final android.hardware.automotive.audiocontrol.UsageEnumType AUDIO_USAGE_UNKNOWN; + enum_constant public static final android.hardware.automotive.audiocontrol.UsageEnumType AUDIO_USAGE_VEHICLE_STATUS; + enum_constant public static final android.hardware.automotive.audiocontrol.UsageEnumType AUDIO_USAGE_VIRTUAL_SOURCE; + enum_constant public static final android.hardware.automotive.audiocontrol.UsageEnumType AUDIO_USAGE_VOICE_COMMUNICATION; + enum_constant public static final android.hardware.automotive.audiocontrol.UsageEnumType AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING; + } + + public class UsageType { + ctor public UsageType(); + method @Nullable public android.hardware.automotive.audiocontrol.UsageEnumType getValue(); + method public void setValue(@Nullable android.hardware.automotive.audiocontrol.UsageEnumType); + } + + public class VolumeGroupType { + ctor public VolumeGroupType(); + method @Nullable public String getActivationConfig(); + method @Nullable public java.util.List getDevice(); + method @Nullable public String getName(); + method public void setActivationConfig(@Nullable String); + method public void setName(@Nullable String); + } + + public class VolumeGroupsType { + ctor public VolumeGroupsType(); + method @Nullable public java.util.List getGroup(); + } + + public class XmlParser { + ctor public XmlParser(); + method @Nullable public static android.hardware.automotive.audiocontrol.CarAudioConfigurationType read(@NonNull java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException; + method @Nullable public static String readText(@NonNull org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; + method public static void skip(@NonNull org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; + } + + public class ZoneConfigType { + ctor public ZoneConfigType(); + method @Nullable public android.hardware.automotive.audiocontrol.ApplyFadeConfigsType getApplyFadeConfigs(); + method @Nullable public boolean getIsDefault(); + method @Nullable public String getName(); + method @Nullable public android.hardware.automotive.audiocontrol.VolumeGroupsType getVolumeGroups(); + method public void setApplyFadeConfigs(@Nullable android.hardware.automotive.audiocontrol.ApplyFadeConfigsType); + method public void setIsDefault(@Nullable boolean); + method public void setName(@Nullable String); + method public void setVolumeGroups(@Nullable android.hardware.automotive.audiocontrol.VolumeGroupsType); + } + + public class ZoneConfigsType { + ctor public ZoneConfigsType(); + method @Nullable public android.hardware.automotive.audiocontrol.ZoneConfigType getZoneConfig(); + method public void setZoneConfig(@Nullable android.hardware.automotive.audiocontrol.ZoneConfigType); + } + + public class ZoneType { + ctor public ZoneType(); + method @Nullable public String getAudioZoneId(); + method @Nullable public android.hardware.automotive.audiocontrol.InputDevicesType getInputDevices(); + method @Nullable public boolean getIsPrimary(); + method @Nullable public String getName(); + method @Nullable public String getOccupantZoneId(); + method @Nullable public android.hardware.automotive.audiocontrol.ZoneConfigsType getZoneConfigs(); + method public void setAudioZoneId(@Nullable String); + method public void setInputDevices(@Nullable android.hardware.automotive.audiocontrol.InputDevicesType); + method public void setIsPrimary(@Nullable boolean); + method public void setName(@Nullable String); + method public void setOccupantZoneId(@Nullable String); + method public void setZoneConfigs(@Nullable android.hardware.automotive.audiocontrol.ZoneConfigsType); + } + + public class ZonesType { + ctor public ZonesType(); + method @Nullable public java.util.List getZone(); + } + +} + diff --git a/automotive/audiocontrol/aidl/default/loaders/config/api/last_current.txt b/automotive/audiocontrol/aidl/default/loaders/config/api/last_current.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/automotive/audiocontrol/aidl/default/loaders/config/api/last_removed.txt b/automotive/audiocontrol/aidl/default/loaders/config/api/last_removed.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/automotive/audiocontrol/aidl/default/loaders/config/api/removed.txt b/automotive/audiocontrol/aidl/default/loaders/config/api/removed.txt new file mode 100644 index 0000000000..d802177e24 --- /dev/null +++ b/automotive/audiocontrol/aidl/default/loaders/config/api/removed.txt @@ -0,0 +1 @@ +// Signature format: 2.0 diff --git a/automotive/audiocontrol/aidl/default/loaders/config/car_audio_configuration.xsd b/automotive/audiocontrol/aidl/default/loaders/config/car_audio_configuration.xsd new file mode 100644 index 0000000000..634aedab66 --- /dev/null +++ b/automotive/audiocontrol/aidl/default/loaders/config/car_audio_configuration.xsd @@ -0,0 +1,248 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/automotive/audiocontrol/aidl/default/loaders/fade/Android.bp b/automotive/audiocontrol/aidl/default/loaders/fade/Android.bp new file mode 100644 index 0000000000..3dbc2f1ce0 --- /dev/null +++ b/automotive/audiocontrol/aidl/default/loaders/fade/Android.bp @@ -0,0 +1,45 @@ +// Copyright (C) 2024 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "hardware_interfaces_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["hardware_interfaces_license"], +} + +xsd_config { + name: "car_fade_audio_configuration_xsd", + srcs: ["car_fade_audio_configuration.xsd"], + package_name: "android.hardware.automotive.audiocontrol.fade", + nullability: true, +} + +cc_defaults { + name: "car.fade.configuration.xsd.default", + static_libs: [ + "libxml2", + ], + generated_sources: [ + "car_fade_audio_configuration_xsd", + ], + generated_headers: [ + "car_fade_audio_configuration_xsd", + ], + header_libs: [ + "libxsdc-utils", + ], +} diff --git a/automotive/audiocontrol/aidl/default/loaders/fade/api/current.txt b/automotive/audiocontrol/aidl/default/loaders/fade/api/current.txt new file mode 100644 index 0000000000..f40f1bef4f --- /dev/null +++ b/automotive/audiocontrol/aidl/default/loaders/fade/api/current.txt @@ -0,0 +1,160 @@ +// Signature format: 2.0 +package android.hardware.automotive.audiocontrol.fade { + + public class AttributesType { + ctor public AttributesType(); + method @Nullable public android.hardware.automotive.audiocontrol.fade.ContentTypeEnum getContentType(); + method @Nullable public String getTags(); + method @Nullable public android.hardware.automotive.audiocontrol.fade.UsageEnumType getUsage(); + method public void setContentType(@Nullable android.hardware.automotive.audiocontrol.fade.ContentTypeEnum); + method public void setTags(@Nullable String); + method public void setUsage(@Nullable android.hardware.automotive.audiocontrol.fade.UsageEnumType); + } + + public class AudioAttributesUsagesType { + ctor public AudioAttributesUsagesType(); + method @Nullable public java.util.List getAudioAttribute_optional(); + method @Nullable public java.util.List getUsage_optional(); + } + + public class CarAudioFadeConfigurationType { + ctor public CarAudioFadeConfigurationType(); + method @Nullable public android.hardware.automotive.audiocontrol.fade.FadeConfigurationConfigs getConfigs(); + method public void setConfigs(@Nullable android.hardware.automotive.audiocontrol.fade.FadeConfigurationConfigs); + } + + public class ContentType { + ctor public ContentType(); + method @Nullable public android.hardware.automotive.audiocontrol.fade.ContentTypeEnum getValue(); + method public void setValue(@Nullable android.hardware.automotive.audiocontrol.fade.ContentTypeEnum); + } + + public enum ContentTypeEnum { + method @NonNull public String getRawName(); + enum_constant public static final android.hardware.automotive.audiocontrol.fade.ContentTypeEnum AUDIO_CONTENT_TYPE_MOVIE; + enum_constant public static final android.hardware.automotive.audiocontrol.fade.ContentTypeEnum AUDIO_CONTENT_TYPE_MUSIC; + enum_constant public static final android.hardware.automotive.audiocontrol.fade.ContentTypeEnum AUDIO_CONTENT_TYPE_SONIFICATION; + enum_constant public static final android.hardware.automotive.audiocontrol.fade.ContentTypeEnum AUDIO_CONTENT_TYPE_SPEECH; + enum_constant public static final android.hardware.automotive.audiocontrol.fade.ContentTypeEnum AUDIO_CONTENT_TYPE_UNKNOWN; + } + + public class FadeConfigurationConfig { + ctor public FadeConfigurationConfig(); + method @Nullable public String getDefaultFadeInDelayForOffenders(); + method @Nullable public String getDefaultFadeInDurationInMillis(); + method @Nullable public String getDefaultFadeOutDurationInMillis(); + method @Nullable public android.hardware.automotive.audiocontrol.fade.FadeInConfigurationsType getFadeInConfigurations(); + method @Nullable public android.hardware.automotive.audiocontrol.fade.FadeOutConfigurationsType getFadeOutConfigurations(); + method @Nullable public android.hardware.automotive.audiocontrol.fade.FadeStateType getFadeState(); + method @Nullable public android.hardware.automotive.audiocontrol.fade.FadeableUsagesType getFadeableUsages(); + method @Nullable public String getName(); + method @Nullable public android.hardware.automotive.audiocontrol.fade.UnfadeableAudioAttributesType getUnfadeableAudioAttributes(); + method @Nullable public android.hardware.automotive.audiocontrol.fade.UnfadeableContentTypesType getUnfadeableContentTypes(); + method public void setDefaultFadeInDelayForOffenders(@Nullable String); + method public void setDefaultFadeInDurationInMillis(@Nullable String); + method public void setDefaultFadeOutDurationInMillis(@Nullable String); + method public void setFadeInConfigurations(@Nullable android.hardware.automotive.audiocontrol.fade.FadeInConfigurationsType); + method public void setFadeOutConfigurations(@Nullable android.hardware.automotive.audiocontrol.fade.FadeOutConfigurationsType); + method public void setFadeState(@Nullable android.hardware.automotive.audiocontrol.fade.FadeStateType); + method public void setFadeableUsages(@Nullable android.hardware.automotive.audiocontrol.fade.FadeableUsagesType); + method public void setName(@Nullable String); + method public void setUnfadeableAudioAttributes(@Nullable android.hardware.automotive.audiocontrol.fade.UnfadeableAudioAttributesType); + method public void setUnfadeableContentTypes(@Nullable android.hardware.automotive.audiocontrol.fade.UnfadeableContentTypesType); + } + + public class FadeConfigurationConfigs { + ctor public FadeConfigurationConfigs(); + method @Nullable public java.util.List getConfig(); + } + + public class FadeConfigurationType { + ctor public FadeConfigurationType(); + method @Nullable public android.hardware.automotive.audiocontrol.fade.AudioAttributesUsagesType getAudioAttributes(); + method @Nullable public String getFadeDurationMillis(); + method public void setAudioAttributes(@Nullable android.hardware.automotive.audiocontrol.fade.AudioAttributesUsagesType); + method public void setFadeDurationMillis(@Nullable String); + } + + public class FadeInConfigurationsType { + ctor public FadeInConfigurationsType(); + method @Nullable public android.hardware.automotive.audiocontrol.fade.FadeConfigurationType getFadeConfiguration(); + method public void setFadeConfiguration(@Nullable android.hardware.automotive.audiocontrol.fade.FadeConfigurationType); + } + + public class FadeOutConfigurationsType { + ctor public FadeOutConfigurationsType(); + method @Nullable public android.hardware.automotive.audiocontrol.fade.FadeConfigurationType getFadeConfiguration(); + method public void setFadeConfiguration(@Nullable android.hardware.automotive.audiocontrol.fade.FadeConfigurationType); + } + + public enum FadeStateEnumType { + method @NonNull public String getRawName(); + enum_constant public static final android.hardware.automotive.audiocontrol.fade.FadeStateEnumType FADE_STATE_DISABLED; + enum_constant public static final android.hardware.automotive.audiocontrol.fade.FadeStateEnumType FADE_STATE_ENABLED_DEFAULT; + enum_constant public static final android.hardware.automotive.audiocontrol.fade.FadeStateEnumType _0; + enum_constant public static final android.hardware.automotive.audiocontrol.fade.FadeStateEnumType _1; + } + + public class FadeStateType { + ctor public FadeStateType(); + method @Nullable public android.hardware.automotive.audiocontrol.fade.FadeStateEnumType getValue(); + method public void setValue(@Nullable android.hardware.automotive.audiocontrol.fade.FadeStateEnumType); + } + + public class FadeableUsagesType { + ctor public FadeableUsagesType(); + method @Nullable public java.util.List getUsage(); + } + + public class UnfadeableAudioAttributesType { + ctor public UnfadeableAudioAttributesType(); + method @Nullable public android.hardware.automotive.audiocontrol.fade.AudioAttributesUsagesType getAudioAttributes(); + method public void setAudioAttributes(@Nullable android.hardware.automotive.audiocontrol.fade.AudioAttributesUsagesType); + } + + public class UnfadeableContentTypesType { + ctor public UnfadeableContentTypesType(); + method @Nullable public java.util.List getContentType(); + } + + public enum UsageEnumType { + method @NonNull public String getRawName(); + enum_constant public static final android.hardware.automotive.audiocontrol.fade.UsageEnumType AUDIO_USAGE_ALARM; + enum_constant public static final android.hardware.automotive.audiocontrol.fade.UsageEnumType AUDIO_USAGE_ANNOUNCEMENT; + enum_constant public static final android.hardware.automotive.audiocontrol.fade.UsageEnumType AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY; + enum_constant public static final android.hardware.automotive.audiocontrol.fade.UsageEnumType AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE; + enum_constant public static final android.hardware.automotive.audiocontrol.fade.UsageEnumType AUDIO_USAGE_ASSISTANCE_SONIFICATION; + enum_constant public static final android.hardware.automotive.audiocontrol.fade.UsageEnumType AUDIO_USAGE_ASSISTANT; + enum_constant public static final android.hardware.automotive.audiocontrol.fade.UsageEnumType AUDIO_USAGE_CALL_ASSISTANT; + enum_constant public static final android.hardware.automotive.audiocontrol.fade.UsageEnumType AUDIO_USAGE_EMERGENCY; + enum_constant public static final android.hardware.automotive.audiocontrol.fade.UsageEnumType AUDIO_USAGE_GAME; + enum_constant public static final android.hardware.automotive.audiocontrol.fade.UsageEnumType AUDIO_USAGE_MEDIA; + enum_constant public static final android.hardware.automotive.audiocontrol.fade.UsageEnumType AUDIO_USAGE_NOTIFICATION; + enum_constant public static final android.hardware.automotive.audiocontrol.fade.UsageEnumType AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED; + enum_constant public static final android.hardware.automotive.audiocontrol.fade.UsageEnumType AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT; + enum_constant public static final android.hardware.automotive.audiocontrol.fade.UsageEnumType AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST; + enum_constant public static final android.hardware.automotive.audiocontrol.fade.UsageEnumType AUDIO_USAGE_NOTIFICATION_EVENT; + enum_constant public static final android.hardware.automotive.audiocontrol.fade.UsageEnumType AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE; + enum_constant public static final android.hardware.automotive.audiocontrol.fade.UsageEnumType AUDIO_USAGE_SAFETY; + enum_constant public static final android.hardware.automotive.audiocontrol.fade.UsageEnumType AUDIO_USAGE_UNKNOWN; + enum_constant public static final android.hardware.automotive.audiocontrol.fade.UsageEnumType AUDIO_USAGE_VEHICLE_STATUS; + enum_constant public static final android.hardware.automotive.audiocontrol.fade.UsageEnumType AUDIO_USAGE_VIRTUAL_SOURCE; + enum_constant public static final android.hardware.automotive.audiocontrol.fade.UsageEnumType AUDIO_USAGE_VOICE_COMMUNICATION; + enum_constant public static final android.hardware.automotive.audiocontrol.fade.UsageEnumType AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING; + } + + public class UsageType { + ctor public UsageType(); + method @Nullable public android.hardware.automotive.audiocontrol.fade.UsageEnumType getValue(); + method public void setValue(@Nullable android.hardware.automotive.audiocontrol.fade.UsageEnumType); + } + + public class XmlParser { + ctor public XmlParser(); + method @Nullable public static android.hardware.automotive.audiocontrol.fade.CarAudioFadeConfigurationType read(@NonNull java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException; + method @Nullable public static String readText(@NonNull org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; + method public static void skip(@NonNull org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; + } + +} + diff --git a/automotive/audiocontrol/aidl/default/loaders/fade/api/last_current.txt b/automotive/audiocontrol/aidl/default/loaders/fade/api/last_current.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/automotive/audiocontrol/aidl/default/loaders/fade/api/last_removed.txt b/automotive/audiocontrol/aidl/default/loaders/fade/api/last_removed.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/automotive/audiocontrol/aidl/default/loaders/fade/api/removed.txt b/automotive/audiocontrol/aidl/default/loaders/fade/api/removed.txt new file mode 100644 index 0000000000..d802177e24 --- /dev/null +++ b/automotive/audiocontrol/aidl/default/loaders/fade/api/removed.txt @@ -0,0 +1 @@ +// Signature format: 2.0 diff --git a/automotive/audiocontrol/aidl/default/loaders/fade/car_fade_audio_configuration.xsd b/automotive/audiocontrol/aidl/default/loaders/fade/car_fade_audio_configuration.xsd new file mode 100644 index 0000000000..051be7e286 --- /dev/null +++ b/automotive/audiocontrol/aidl/default/loaders/fade/car_fade_audio_configuration.xsd @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 7fc9c4c8c5aa7807e1f286e9c3c1cabe42fdda5c Mon Sep 17 00:00:00 2001 From: Oscar Azucena Date: Fri, 18 Oct 2024 20:25:46 -0700 Subject: [PATCH 3/3] Add audio control configuraiton APIs VTS Bug: 359686069 Test: atest VtsAidlHalAudioControlTest Flag: EXEMPT HAL interface Change-Id: I9fcaaae15dc9049567587ce1fefd4ff1caa71ef1 --- .../aidl/default/audiocontrol-default.xml | 2 +- automotive/audiocontrol/aidl/vts/Android.bp | 21 + .../aidl/vts/VtsHalAudioControlTargetTest.cpp | 415 ++++++++++++++++++ .../aidl/vts/include/AudioControlTestUtils.h | 67 +++ .../aidl/vts/src/AudioControlTestUtils.cpp | 203 +++++++++ 5 files changed, 707 insertions(+), 1 deletion(-) create mode 100644 automotive/audiocontrol/aidl/vts/include/AudioControlTestUtils.h create mode 100644 automotive/audiocontrol/aidl/vts/src/AudioControlTestUtils.cpp diff --git a/automotive/audiocontrol/aidl/default/audiocontrol-default.xml b/automotive/audiocontrol/aidl/default/audiocontrol-default.xml index bcb5669f38..ffef7fc6dd 100644 --- a/automotive/audiocontrol/aidl/default/audiocontrol-default.xml +++ b/automotive/audiocontrol/aidl/default/audiocontrol-default.xml @@ -1,7 +1,7 @@ android.hardware.automotive.audiocontrol - 4 + 5 IAudioControl/default diff --git a/automotive/audiocontrol/aidl/vts/Android.bp b/automotive/audiocontrol/aidl/vts/Android.bp index d94ad556dc..57c6ae47ff 100644 --- a/automotive/audiocontrol/aidl/vts/Android.bp +++ b/automotive/audiocontrol/aidl/vts/Android.bp @@ -22,6 +22,25 @@ package { default_applicable_licenses: ["hardware_interfaces_license"], } +cc_library { + name: "AudioControlHalTestUtils", + srcs: [ + "src/AudioControlTestUtils.cpp", + ], + export_include_dirs: [ + "include", + ], + defaults: [ + "latest_android_hardware_audio_common_cpp_static", + "latest_android_hardware_automotive_audiocontrol_cpp_static", + "latest_android_media_audio_common_types_cpp_static", + ], + shared_libs: [ + "libbase", + "libutils", + ], +} + cc_test { name: "VtsAidlHalAudioControlTest", defaults: [ @@ -39,9 +58,11 @@ cc_test { "libbinder", "libbase", "libxml2", + "libutils", ], static_libs: [ "libgmock", + "AudioControlHalTestUtils", ], test_suites: [ "general-tests", diff --git a/automotive/audiocontrol/aidl/vts/VtsHalAudioControlTargetTest.cpp b/automotive/audiocontrol/aidl/vts/VtsHalAudioControlTargetTest.cpp index 4e7e963981..6e646a6ddd 100644 --- a/automotive/audiocontrol/aidl/vts/VtsHalAudioControlTargetTest.cpp +++ b/automotive/audiocontrol/aidl/vts/VtsHalAudioControlTargetTest.cpp @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include #include @@ -26,24 +28,49 @@ #include #include #include +#include using android::ProcessState; using android::sp; using android::String16; using android::binder::Status; +using android::hardware::automotive::audiocontrol::AudioDeviceConfiguration; +using android::hardware::automotive::audiocontrol::AudioFadeConfiguration; using android::hardware::automotive::audiocontrol::AudioFocusChange; using android::hardware::automotive::audiocontrol::AudioGainConfigInfo; +using android::hardware::automotive::audiocontrol::AudioZone; +using android::hardware::automotive::audiocontrol::AudioZoneConfig; +using android::hardware::automotive::audiocontrol::AudioZoneContextInfo; +using android::hardware::automotive::audiocontrol::AudioZoneFadeConfiguration; using android::hardware::automotive::audiocontrol::BnAudioGainCallback; using android::hardware::automotive::audiocontrol::BnFocusListener; using android::hardware::automotive::audiocontrol::BnModuleChangeCallback; +using android::hardware::automotive::audiocontrol::DeviceToContextEntry; using android::hardware::automotive::audiocontrol::DuckingInfo; +using android::hardware::automotive::audiocontrol::FadeConfiguration; using android::hardware::automotive::audiocontrol::IAudioControl; using android::hardware::automotive::audiocontrol::IModuleChangeCallback; using android::hardware::automotive::audiocontrol::MutingInfo; using android::hardware::automotive::audiocontrol::Reasons; +using android::hardware::automotive::audiocontrol::VolumeActivationConfiguration; +using android::hardware::automotive::audiocontrol::VolumeActivationConfigurationEntry; +using android::hardware::automotive::audiocontrol::VolumeGroupConfig; +using android::hardware::automotive::audiocontrol::RoutingDeviceConfiguration:: + CONFIGURABLE_AUDIO_ENGINE_ROUTING; +using android::hardware::automotive::audiocontrol::RoutingDeviceConfiguration:: + DEFAULT_AUDIO_ROUTING; +using android::hardware::automotive::audiocontrol::VolumeActivationConfigurationEntry:: + DEFAULT_MAX_ACTIVATION_VALUE; +using android::hardware::automotive::audiocontrol::VolumeActivationConfigurationEntry:: + DEFAULT_MIN_ACTIVATION_VALUE; using ::testing::AnyOf; using ::testing::Eq; +using ::testing::Not; +using ::testing::UnorderedElementsAreArray; + +using android::internal::ToString; + #include "android_audio_policy_configuration_V7_0.h" namespace xsd { @@ -52,11 +79,218 @@ using namespace android::audio::policy::configuration::V7_0; namespace audiohalcommon = android::hardware::audio::common; namespace audiomediacommon = android::media::audio::common; +namespace testutils = android::hardware::audiocontrol::testutils; namespace { constexpr int32_t kAidlVersionThree = 3; +constexpr int32_t kAidlVersionFive = 5; + +bool hasValidVolumeGroupActivation(const VolumeActivationConfiguration& activation, + std::string& message) { + if (activation.volumeActivationEntries.empty()) { + message = "Volume group activation must have at least one volume activation entry"; + return false; + } + for (const auto& entry : activation.volumeActivationEntries) { + int32_t max = entry.maxActivationVolumePercentage; + int32_t min = entry.minActivationVolumePercentage; + if (min > DEFAULT_MAX_ACTIVATION_VALUE || min < DEFAULT_MIN_ACTIVATION_VALUE) { + message = "Invalid minActivationVolumePercentage, must be between " + + std::to_string(DEFAULT_MIN_ACTIVATION_VALUE) + " and " + + std::to_string(DEFAULT_MAX_ACTIVATION_VALUE); + return false; + } + if (max > DEFAULT_MAX_ACTIVATION_VALUE || max < DEFAULT_MIN_ACTIVATION_VALUE) { + message = "Invalid maxActivationVolumePercentage, must be between " + + std::to_string(DEFAULT_MIN_ACTIVATION_VALUE) + " and " + + std::to_string(DEFAULT_MAX_ACTIVATION_VALUE); + return false; + } + if (min >= max) { + message = + "Invalid maxActivationVolumePercentage and minActivationVolumePercentage " + "combination, minActivationVolumePercentage must be less than " + "maxActivationVolumePercentage"; + return false; + } + } + return true; } +bool hasValidAudioRoute(const DeviceToContextEntry& entry, std::string& message, + std::set& groupDevices) { + if (entry.contextNames.empty()) { + message = " Contexts can not be empty for DeviceToContextEntry"; + return false; + } + std::set contextInRoute; + for (const auto& context : entry.contextNames) { + if (!contextInRoute.contains(ToString(context))) { + continue; + } + message = " Context can not repeat for the same DeviceToContextEntry"; + return false; + } + audiomediacommon::AudioDeviceDescription description; + if (!testutils::getAudioPortDeviceDescriptor(entry.device, description)) { + message = " DeviceToContextEntry must have a valid device port"; + return false; + } + // BUS type also has empty connection + // Note: OUT_BUS is also mapped to OUT_DEVICE + if (description.type != audiomediacommon::AudioDeviceType::OUT_BUS && + !description.connection.empty()) { + return true; + } + std::string address; + if (!testutils::getAddressForAudioPort(entry.device, address) || address.empty()) { + message = " Address can not be empty for BUS devices"; + return false; + } + if (groupDevices.contains(address)) { + message = " Audio device address can not repeat in the same volume group"; + return false; + } + groupDevices.insert(address); + return true; +} + +inline bool hasValidTimeout(int64_t timeout) { + return timeout > 0; +} +bool hasValidFadeConfiguration(const FadeConfiguration& fadeConfiguration, + const std::string& prefix, std::string& message) { + if (!hasValidTimeout(fadeConfiguration.fadeDurationMillis)) { + message = prefix + " duration must be greater than 0"; + return false; + } + return true; +} +bool hadValidAudioFadeConfiguration(const AudioFadeConfiguration& fadeConfiguration, + std::string& message) { + if (!hasValidTimeout(fadeConfiguration.fadeInDurationMs)) { + message = "Fade-in duration must be greater than 0"; + return false; + } + if (!hasValidTimeout(fadeConfiguration.fadeOutDurationMs)) { + message = "Fade-out duration must be greater than 0"; + return false; + } + if (!hasValidTimeout(fadeConfiguration.fadeInDelayedForOffendersMs)) { + message = "Fade-in delayed for offenders duration must be greater than 0"; + return false; + } + for (const auto& fadeOutConfig : fadeConfiguration.fadeOutConfigurations) { + if (!hasValidFadeConfiguration(fadeOutConfig, "Fade-out", message)) { + return false; + } + } + for (const auto& fadeOutConfig : fadeConfiguration.fadeInConfigurations) { + if (!hasValidFadeConfiguration(fadeOutConfig, "Fade-in", message)) { + return false; + } + } + return true; +} + +void validateVolumeGroupInfo(const AudioZoneConfig& audioZoneConfig, + const VolumeGroupConfig& volumeGroupConfig, + const AudioDeviceConfiguration& deviceConfig) { + std::string zoneConfigName = testutils::toAlphaNumeric(ToString(audioZoneConfig.name)); + std::string volumeGroupName = testutils::toAlphaNumeric(ToString(volumeGroupConfig.name)); + std::string volumeGroupInfo = + "Audio zone config " + zoneConfigName + " volume group " + volumeGroupName; + ALOGI("%s test", volumeGroupInfo.c_str()); + + EXPECT_FALSE(volumeGroupConfig.carAudioRoutes.empty()) + << volumeGroupInfo << " must have at least one audio route"; + if (deviceConfig.routingConfig == CONFIGURABLE_AUDIO_ENGINE_ROUTING) { + EXPECT_FALSE(volumeGroupConfig.name.empty()) + << volumeGroupInfo << " must have a non-empty volume name"; + } + std::set groupDevices; + for (const auto& audioRoute : volumeGroupConfig.carAudioRoutes) { + std::string routeMessage; + EXPECT_TRUE(hasValidAudioRoute(audioRoute, routeMessage, groupDevices)) + << volumeGroupInfo << " Volume route message: " << routeMessage; + } + if (volumeGroupConfig.activationConfiguration.has_value()) { + std::string activationMessage; + EXPECT_TRUE(hasValidVolumeGroupActivation(volumeGroupConfig.activationConfiguration.value(), + activationMessage)) + << volumeGroupInfo << " Activation message: " << activationMessage; + } +} + +void validateAudioZoneFadeConfiguration(const AudioZoneFadeConfiguration& fadeConfiguration) { + ALOGI("Fade configuration test"); + std::set usages; + std::string defaultValidationMessage; + EXPECT_TRUE(hadValidAudioFadeConfiguration(fadeConfiguration.defaultConfiguration, + defaultValidationMessage)) + << "Default configuration validation failed: " << defaultValidationMessage; + for (const auto& entry : fadeConfiguration.transientConfiguration) { + ALOGI("Transient fade configuration test"); + std::string transientFadeConfigurationMessage; + EXPECT_TRUE(hadValidAudioFadeConfiguration(entry.transientFadeConfiguration, + transientFadeConfigurationMessage)) + << "Transient fade configuration validation failed: " + << transientFadeConfigurationMessage; + EXPECT_FALSE(entry.transientUsages.empty()) + << "Transient fade configuration must have at least one audio usage"; + for (const auto& usage : entry.transientUsages) { + EXPECT_FALSE(usages.contains(usage)) << "Audio usages " << ToString(usage) + << " repeat in transient fade configuration"; + } + } +} + +void validateAudioZoneConfiguration(const AudioZone& carAudioZone, + const AudioZoneConfig& audioZoneConfig, + const AudioDeviceConfiguration& deviceConfig) { + std::string zoneConfigName = testutils::toAlphaNumeric(ToString(audioZoneConfig.name)); + ALOGI("Zone config name %s test", zoneConfigName.c_str()); + std::set contextInfoNames; + EXPECT_FALSE(audioZoneConfig.volumeGroups.empty()) + << "Volume groups for zone config " << zoneConfigName.c_str(); + for (const auto& volumeGroup : audioZoneConfig.volumeGroups) { + ALOGI("Zone config name %s volume group test %s", zoneConfigName.c_str(), + ToString(volumeGroup.name).c_str()); + std::vector groupContexts = + testutils::getContextInfoNamesForVolumeGroup(volumeGroup); + for (const auto& context : groupContexts) { + EXPECT_FALSE(contextInfoNames.contains(context)) + << "Context " << context << " repeats in zone config " << zoneConfigName; + contextInfoNames.insert(context); + } + validateVolumeGroupInfo(audioZoneConfig, volumeGroup, deviceConfig); + } + const auto& audioZoneContexts = carAudioZone.audioZoneContext.audioContextInfos; + std::map infoNameToInfo; + std::transform(audioZoneContexts.begin(), audioZoneContexts.end(), + std::inserter(infoNameToInfo, infoNameToInfo.end()), + [&](const AudioZoneContextInfo& context) { + return std::make_pair(ToString(context.name), context); + }); + std::vector configContextInfos; + for (const auto& contextName : contextInfoNames) { + const auto& pair = infoNameToInfo.find(contextName); + if (pair == infoNameToInfo.end()) { + continue; + } + configContextInfos.push_back(pair->second); + } + std::string message; + EXPECT_TRUE(testutils::contextInfosContainAllAudioAttributeUsages(configContextInfos, message)) + << "Config " << zoneConfigName << " message: " << message; + + if (audioZoneConfig.fadeConfiguration.has_value()) { + validateAudioZoneFadeConfiguration(audioZoneConfig.fadeConfiguration.value()); + } +} + +} // namespace + class AudioControlAidl : public testing::TestWithParam { public: virtual void SetUp() override { @@ -292,12 +526,193 @@ TEST_P(AudioControlAidl, RegisterModuleChangeNullCallbackThrowsException) { AnyOf(Eq(Status::EX_ILLEGAL_ARGUMENT), Eq(Status::EX_UNSUPPORTED_OPERATION))); } +class AudioControlVersionFiveAndAbove : public AudioControlAidl { + public: + virtual void SetUp() override { + AudioControlAidl::SetUp(); + if (isAidlVersionAtleast(kAidlVersionFive)) { + return; + } + GTEST_SKIP() << " Version is lower than " << std::to_string(kAidlVersionFive); + } +}; + +class AudioControlWithAudioConfiguration : public AudioControlVersionFiveAndAbove { + public: + virtual void SetUp() override { + AudioControlVersionFiveAndAbove::SetUp(); + + if (IsSkipped()) { + return; + } + + const auto& configStatus = + audioControl->getAudioDeviceConfiguration(&audioDeviceConfiguration); + + EXPECT_THAT(configStatus.exceptionCode(), + AnyOf(Eq(Status::EX_NONE), Eq(Status::EX_UNSUPPORTED_OPERATION))); + if (!configStatus.isOk()) { + GTEST_SKIP() << "Device does not support audio configurations APIs"; + } + ALOGD("Audio device info: %s", audioDeviceConfiguration.toString().c_str()); + } + + AudioDeviceConfiguration audioDeviceConfiguration; +}; + +TEST_P(AudioControlWithAudioConfiguration, DefaultAudioRoutingConfiguration) { + if (audioDeviceConfiguration.routingConfig != DEFAULT_AUDIO_ROUTING) { + GTEST_SKIP() << "Default audio routing not supported"; + } + std::vector zones; + + const auto& zoneStatus = audioControl->getCarAudioZones(&zones); + + EXPECT_THAT(zoneStatus.exceptionCode(), + AnyOf(Eq(Status::EX_NONE), Eq(Status::EX_UNSUPPORTED_OPERATION))) + << "Default routing can be implemented or unsupported"; + if (!zoneStatus.isOk()) return; + EXPECT_TRUE(zones.empty()) << "Zones must be empty for default routing"; +} + +class AudioControlWithDynamicConfiguration : public AudioControlWithAudioConfiguration { + public: + virtual void SetUp() override { + AudioControlWithAudioConfiguration::SetUp(); + if (IsSkipped()) { + return; + } + if (audioDeviceConfiguration.routingConfig == DEFAULT_AUDIO_ROUTING) { + GTEST_SKIP() << "Dynamic/core audio routing not supported"; + } + const auto& zoneStatus = audioControl->getCarAudioZones(&audioZones); + EXPECT_EQ(zoneStatus.exceptionCode(), Status::EX_NONE) + << "Zones API must be supported for core/dynamic routing"; + } + + std::vector audioZones; +}; + +TEST_P(AudioControlWithDynamicConfiguration, DynamicAudioRoutingConfiguration) { + EXPECT_FALSE(audioZones.empty()) << "Zones must not be empty for core/dynamic routing"; +} + +class AudioControlWithAudioZoneInfo : public AudioControlWithDynamicConfiguration { + public: + virtual void SetUp() override { + AudioControlWithDynamicConfiguration::SetUp(); + if (IsSkipped()) { + return; + } + EXPECT_TRUE(!audioZones.empty()) << "Zones must exist for core/dynamic routing"; + } +}; + +TEST_P(AudioControlWithAudioZoneInfo, AudioZonesRequirements) { + bool primaryZoneFound = false; + std::set zoneIds; + std::set occupantIds; + std::set zoneNames; + std::set deviceAddresses; + for (const auto& zone : audioZones) { + if (zone.id == AudioZone::PRIMARY_AUDIO_ZONE) { + EXPECT_FALSE(primaryZoneFound) << "There can only be one primary zone"; + primaryZoneFound = true; + } + EXPECT_FALSE(zoneIds.contains(zone.id)) << "Zone " << std::to_string(zone.id) << " repeats"; + zoneIds.insert(zone.id); + if (!zone.name.empty()) { + EXPECT_FALSE(zoneNames.contains(zone.name)) << "Zone " << zone.name << " repeats"; + zoneNames.insert(zone.name); + } + if (zone.occupantZoneId != AudioZone::UNASSIGNED_OCCUPANT) { + EXPECT_FALSE(occupantIds.contains(zone.occupantZoneId)) + << "Occupant zone id " << zone.occupantZoneId << " repeats"; + occupantIds.insert(zone.occupantZoneId); + } + const auto& zoneAddresses = testutils::getDeviceAddressesForZone(zone); + for (const auto& address : zoneAddresses) { + EXPECT_FALSE(deviceAddresses.contains(address)) + << "Device address " << address << " in zone " << zone.name << " repeats"; + } + // Add after zone comparison is done since devices may repeat within a zone for different + // configurations + deviceAddresses.insert(zoneAddresses.begin(), zoneAddresses.end()); + } + EXPECT_TRUE(primaryZoneFound) << "Primary zone must exist"; +} + +TEST_P(AudioControlWithAudioZoneInfo, AudioZoneInfoRequirements) { + for (const auto& carAudioZone : audioZones) { + ALOGI("Zone id %d test", carAudioZone.id); + std::string missingContextMessage; + EXPECT_TRUE(testutils::contextContainsAllAudioAttributeUsages(carAudioZone.audioZoneContext, + missingContextMessage)) + << "Audio zone context for zone id " << std::to_string(carAudioZone.id) + << missingContextMessage; + EXPECT_FALSE(carAudioZone.audioZoneConfigs.empty()) + << "Audio zone zone id " << std::to_string(carAudioZone.id) + << " missing zone configs"; + std::set configNames; + bool defaultConfigFound = false; + for (const auto& config : carAudioZone.audioZoneConfigs) { + ALOGI("Zone id %d config name %s test", carAudioZone.id, ToString(config.name).c_str()); + if (config.isDefault) { + EXPECT_FALSE(defaultConfigFound) + << "Config name " << config.name + << " repeats default config value in zone id " << carAudioZone.id; + defaultConfigFound = true; + } + EXPECT_FALSE(configNames.contains(config.name)) + << "Config name " << config.name << " repeats in " << carAudioZone.id; + } + EXPECT_TRUE(defaultConfigFound) + << "Audio zone " << carAudioZone.id << " must contain default config"; + std::set inputPorts; + ALOGI("Zone id %d input devices test", carAudioZone.id); + for (const auto& audioPort : carAudioZone.inputAudioDevices) { + std::string address; + const auto hasAddress = testutils::getAddressForAudioPort(audioPort, address); + EXPECT_FALSE(inputPorts.contains(audioPort)) + << "Repeating input device for " << carAudioZone.id << ", device address " + << (hasAddress ? address : "empty address"); + inputPorts.insert(audioPort); + } + } +} + +TEST_P(AudioControlWithAudioZoneInfo, AudioZoneConfigInfoRequirements) { + for (const auto& carAudioZone : audioZones) { + for (const auto& audioZoneConfig : carAudioZone.audioZoneConfigs) { + validateAudioZoneConfiguration(carAudioZone, audioZoneConfig, audioDeviceConfiguration); + } + } +} + GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioControlAidl); INSTANTIATE_TEST_SUITE_P( Audiocontrol, AudioControlAidl, testing::ValuesIn(android::getAidlHalInstanceNames(IAudioControl::descriptor)), android::PrintInstanceNameToString); +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioControlWithAudioConfiguration); +INSTANTIATE_TEST_SUITE_P( + Audiocontrol, AudioControlWithAudioConfiguration, + testing::ValuesIn(android::getAidlHalInstanceNames(IAudioControl::descriptor)), + android::PrintInstanceNameToString); + +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioControlWithDynamicConfiguration); +INSTANTIATE_TEST_SUITE_P( + Audiocontrol, AudioControlWithDynamicConfiguration, + testing::ValuesIn(android::getAidlHalInstanceNames(IAudioControl::descriptor)), + android::PrintInstanceNameToString); + +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioControlWithAudioZoneInfo); +INSTANTIATE_TEST_SUITE_P( + Audiocontrol, AudioControlWithAudioZoneInfo, + testing::ValuesIn(android::getAidlHalInstanceNames(IAudioControl::descriptor)), + android::PrintInstanceNameToString); + int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); ProcessState::self()->setThreadPoolMaxThreadCount(1); diff --git a/automotive/audiocontrol/aidl/vts/include/AudioControlTestUtils.h b/automotive/audiocontrol/aidl/vts/include/AudioControlTestUtils.h new file mode 100644 index 0000000000..46fdce2111 --- /dev/null +++ b/automotive/audiocontrol/aidl/vts/include/AudioControlTestUtils.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MAIN8_AUDIOCONTROLTESTUTILS_H +#define MAIN8_AUDIOCONTROLTESTUTILS_H + +#include +#include +#include + +namespace android { +namespace hardware { +namespace audiocontrol { +namespace testutils { + +std::string toAlphaNumeric(const std::string& info); + +bool getAudioPortDeviceDescriptor( + const android::media::audio::common::AudioPort& audioPort, + android::media::audio::common::AudioDeviceDescription& description); + +bool getAddressForAudioPort(const android::media::audio::common::AudioPort& audioPort, + std::string& address); + +bool getAddressForAudioDevice( + const android::hardware::automotive::audiocontrol::DeviceToContextEntry& device, + std::string& address); + +std::vector getDeviceAddressesForVolumeGroup( + const android::hardware::automotive::audiocontrol::VolumeGroupConfig& config); + +std::vector getDeviceAddressesForZoneConfig( + const android::hardware::automotive::audiocontrol::AudioZoneConfig& config); + +std::vector getDeviceAddressesForZone( + const android::hardware::automotive::audiocontrol::AudioZone& config); + +bool contextInfosContainAllAudioAttributeUsages( + const std::vector& infos, + std::string& message); + +bool contextContainsAllAudioAttributeUsages( + const android::hardware::automotive::audiocontrol::AudioZoneContext& context, + std::string& message); + +std::vector getContextInfoNamesForVolumeGroup( + const android::hardware::automotive::audiocontrol::VolumeGroupConfig& group); + +} // namespace testutils +} // namespace audiocontrol +} // namespace hardware +} // namespace android + +#endif // MAIN8_AUDIOCONTROLTESTUTILS_H diff --git a/automotive/audiocontrol/aidl/vts/src/AudioControlTestUtils.cpp b/automotive/audiocontrol/aidl/vts/src/AudioControlTestUtils.cpp new file mode 100644 index 0000000000..7b7c896fc6 --- /dev/null +++ b/automotive/audiocontrol/aidl/vts/src/AudioControlTestUtils.cpp @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "../include/AudioControlTestUtils.h" + +#include + +using android::hardware::automotive::audiocontrol::AudioZone; +using android::hardware::automotive::audiocontrol::AudioZoneConfig; +using android::hardware::automotive::audiocontrol::AudioZoneContext; +using android::hardware::automotive::audiocontrol::AudioZoneContextInfo; +using android::hardware::automotive::audiocontrol::DeviceToContextEntry; +using android::hardware::automotive::audiocontrol::VolumeGroupConfig; + +namespace audiomediacommon = android::media::audio::common; + +namespace android { +namespace hardware { +namespace audiocontrol { +namespace testutils { + +std::string toAlphaNumeric(const std::string& info) { + std::string name = info; + for (size_t i = 0; i < name.size(); i++) { + // gtest test names must only contain alphanumeric characters + if (!std::isalnum(name[i])) name[i] = '_'; + } + + return name; +} + +bool getAudioPortDeviceDescriptor(const audiomediacommon::AudioPort& audioPort, + audiomediacommon::AudioDeviceDescription& description) { + if (audioPort.ext.getTag() != audiomediacommon::AudioPortExt::Tag::device) { + return false; + } + const auto& audioDevice = + audioPort.ext.get().device; + description = audioDevice.type; + return true; +} + +bool getAddressForAudioPort(const android::media::audio::common::AudioPort& audioPort, + std::string& address) { + if (audioPort.ext.getTag() != audiomediacommon::AudioPortExt::Tag::device) { + return false; + } + const auto& audioDevice = + audioPort.ext.get().device; + + switch (audioDevice.address.getTag()) { + case audiomediacommon::AudioDeviceAddress::Tag::id: + address = audioDevice.address.get(); + return true; + case audiomediacommon::AudioDeviceAddress::Tag::alsa: + address = android::internal::ToString( + audioDevice.address.get()); + return true; + case audiomediacommon::AudioDeviceAddress::Tag::mac: + address = android::internal::ToString( + audioDevice.address.get()); + return true; + case audiomediacommon::AudioDeviceAddress::Tag::ipv4: + address = android::internal::ToString( + audioDevice.address.get()); + return true; + case audiomediacommon::AudioDeviceAddress::Tag::ipv6: + address = android::internal::ToString( + audioDevice.address.get()); + return true; + default: + address = audioDevice.address.toString(); + return true; + } +} + +bool getAddressForAudioDevice(const DeviceToContextEntry& device, std::string& address) { + if (device.device.flags.getTag() == audiomediacommon::AudioIoFlags::input || + device.device.ext.getTag() != audiomediacommon::AudioPortExt::Tag::device) { + return false; + } + return getAddressForAudioPort(device.device, address); +} + +std::vector getDeviceAddressesForVolumeGroup(const VolumeGroupConfig& config) { + std::vector addresses; + for (const auto& route : config.carAudioRoutes) { + std::string address; + if (!getAddressForAudioDevice(route, address)) { + continue; + } + addresses.push_back(address); + } + return addresses; +} + +std::vector getDeviceAddressesForZoneConfig(const AudioZoneConfig& config) { + std::vector addresses; + for (const auto& volumeGroup : config.volumeGroups) { + const auto groupAddresses = getDeviceAddressesForVolumeGroup(volumeGroup); + addresses.insert(addresses.begin(), groupAddresses.begin(), groupAddresses.end()); + } + return addresses; +} + +std::vector getDeviceAddressesForZone(const AudioZone& config) { + std::vector addresses; + for (const auto& zoneConfig : config.audioZoneConfigs) { + const auto groupAddresses = getDeviceAddressesForZoneConfig(zoneConfig); + addresses.insert(addresses.begin(), groupAddresses.begin(), groupAddresses.end()); + } + return addresses; +} + +static void addContextUsages(const AudioZoneContextInfo& info, + std::set& contextUsages) { + for (const auto& audioAttribute : info.audioAttributes) { + contextUsages.insert(audioAttribute.usage); + } +} + +bool contextInfosContainAllAudioAttributeUsages(const std::vector& infos, + std::string& message) { + static const std::vector audioUsages{ + audiomediacommon::AudioUsage::UNKNOWN, + audiomediacommon::AudioUsage::MEDIA, + audiomediacommon::AudioUsage::VOICE_COMMUNICATION, + audiomediacommon::AudioUsage::VOICE_COMMUNICATION_SIGNALLING, + audiomediacommon::AudioUsage::ALARM, + audiomediacommon::AudioUsage::NOTIFICATION, + audiomediacommon::AudioUsage::NOTIFICATION_TELEPHONY_RINGTONE, + audiomediacommon::AudioUsage::NOTIFICATION_EVENT, + audiomediacommon::AudioUsage::ASSISTANCE_ACCESSIBILITY, + audiomediacommon::AudioUsage::ASSISTANCE_NAVIGATION_GUIDANCE, + audiomediacommon::AudioUsage::ASSISTANCE_SONIFICATION, + audiomediacommon::AudioUsage::GAME, + audiomediacommon::AudioUsage::ASSISTANT, + audiomediacommon::AudioUsage::CALL_ASSISTANT, + audiomediacommon::AudioUsage::EMERGENCY, + audiomediacommon::AudioUsage::SAFETY, + audiomediacommon::AudioUsage::VEHICLE_STATUS, + audiomediacommon::AudioUsage::ANNOUNCEMENT, + }; + + std::set contextUsages; + for (const auto& contextInfo : infos) { + addContextUsages(contextInfo, contextUsages); + } + + bool allUsagesPresent = true; + for (const auto& usage : audioUsages) { + if (contextUsages.contains(usage)) { + continue; + } + if (message.empty()) { + message = " Missing usage(s): "; + } + message += audiomediacommon::toString(usage) + ", "; + allUsagesPresent = false; + } + return allUsagesPresent; +} + +bool contextContainsAllAudioAttributeUsages(const AudioZoneContext& context, std::string& message) { + return contextInfosContainAllAudioAttributeUsages(context.audioContextInfos, message); +} + +std::vector getContextInfoNamesForAudioRoute(const DeviceToContextEntry& route) { + std::vector contextInfoNames; + contextInfoNames.reserve(route.contextNames.size()); + for (const auto& contextName : route.contextNames) { + contextInfoNames.push_back(android::internal::ToString(contextName)); + } + return contextInfoNames; +} + +std::vector getContextInfoNamesForVolumeGroup(const VolumeGroupConfig& group) { + std::vector contextInfoNames; + for (const auto& route : group.carAudioRoutes) { + std::vector routeContexts = getContextInfoNamesForAudioRoute(route); + contextInfoNames.insert(contextInfoNames.begin(), routeContexts.begin(), + routeContexts.end()); + } + return contextInfoNames; +} + +} // namespace testutils +} // namespace audiocontrol +} // namespace hardware +} // namespace android \ No newline at end of file