From 9940a55995c7e64b6575b73ab01c8923a3e16cdb Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Fri, 24 Feb 2023 19:50:51 -0800 Subject: [PATCH] audio: Add AudioOffloadMetadata and a method to update it AudioOffloadMetadata contains the same information as 'AUDIO_OFFLOAD_CODEC_*' framework parameters. It is updated via a new method IStreamOut.updateOffloadMetadata which only works for compressed offload streams. Bug: 270731693 Test: atest VtsHalAudioCoreTargetTest Change-Id: I6c8a8853f216438284082f79e3f57e511a2a1f06 Merged-In: I6c8a8853f216438284082f79e3f57e511a2a1f06 --- audio/aidl/Android.bp | 9 ++-- .../audio/common/AudioOffloadMetadata.aidl | 42 ++++++++++++++++++ .../hardware/audio/core/IStreamOut.aidl | 1 + .../audio/common/AudioOffloadMetadata.aidl | 44 +++++++++++++++++++ .../hardware/audio/core/IStreamOut.aidl | 13 ++++++ audio/aidl/default/Stream.cpp | 35 +++++++++++++++ audio/aidl/default/include/core-impl/Stream.h | 4 ++ audio/aidl/vts/ModuleConfig.cpp | 2 +- .../vts/VtsHalAudioCoreModuleTargetTest.cpp | 37 ++++++++++++++-- automotive/audiocontrol/aidl/vts/Android.bp | 2 +- 10 files changed, 179 insertions(+), 10 deletions(-) create mode 100644 audio/aidl/aidl_api/android.hardware.audio.common/current/android/hardware/audio/common/AudioOffloadMetadata.aidl create mode 100644 audio/aidl/android/hardware/audio/common/AudioOffloadMetadata.aidl diff --git a/audio/aidl/Android.bp b/audio/aidl/Android.bp index e6b0cee401..2c91918d76 100644 --- a/audio/aidl/Android.bp +++ b/audio/aidl/Android.bp @@ -36,12 +36,13 @@ aidl_interface { "android.hardware.audio_defaults", ], srcs: [ + "android/hardware/audio/common/AudioOffloadMetadata.aidl", "android/hardware/audio/common/PlaybackTrackMetadata.aidl", "android/hardware/audio/common/RecordTrackMetadata.aidl", "android/hardware/audio/common/SinkMetadata.aidl", "android/hardware/audio/common/SourceMetadata.aidl", ], - frozen: true, + frozen: false, imports: [ "android.media.audio.common.types-V2", ], @@ -77,7 +78,7 @@ aidl_interface { } // Note: This should always be one version ahead of the last frozen version -latest_android_hardware_audio_common = "android.hardware.audio.common-V1" +latest_android_hardware_audio_common = "android.hardware.audio.common-V2" // Modules that depend on android.hardware.audio.common directly can include // the following cc_defaults to avoid explicitly managing dependency versions @@ -129,7 +130,7 @@ aidl_interface { imports: [ "android.hardware.common-V2", "android.hardware.common.fmq-V1", - "android.hardware.audio.common-V1", + "android.hardware.audio.common-V2", "android.hardware.audio.core.sounddose-V1", "android.hardware.audio.effect-V1", "android.media.audio.common.types-V2", @@ -253,7 +254,7 @@ aidl_interface { imports: [ "android.hardware.common-V2", "android.hardware.common.fmq-V1", - "android.hardware.audio.common-V1", + "android.hardware.audio.common-V2", "android.media.audio.common.types-V2", ], backend: { diff --git a/audio/aidl/aidl_api/android.hardware.audio.common/current/android/hardware/audio/common/AudioOffloadMetadata.aidl b/audio/aidl/aidl_api/android.hardware.audio.common/current/android/hardware/audio/common/AudioOffloadMetadata.aidl new file mode 100644 index 0000000000..000504bd40 --- /dev/null +++ b/audio/aidl/aidl_api/android.hardware.audio.common/current/android/hardware/audio/common/AudioOffloadMetadata.aidl @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/////////////////////////////////////////////////////////////////////////////// +// 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.audio.common; +@JavaDerive(equals=true, toString=true) @VintfStability +parcelable AudioOffloadMetadata { + int sampleRate; + android.media.audio.common.AudioChannelLayout channelMask; + int averageBitRatePerSecond; + int delayFrames; + int paddingFrames; +} diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamOut.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamOut.aidl index 46acc1156e..ec3078efd7 100644 --- a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamOut.aidl +++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamOut.aidl @@ -36,6 +36,7 @@ package android.hardware.audio.core; interface IStreamOut { android.hardware.audio.core.IStreamCommon getStreamCommon(); void updateMetadata(in android.hardware.audio.common.SourceMetadata sourceMetadata); + void updateOffloadMetadata(in android.hardware.audio.common.AudioOffloadMetadata offloadMetadata); float[] getHwVolume(); void setHwVolume(in float[] channelVolumes); float getAudioDescriptionMixLevel(); diff --git a/audio/aidl/android/hardware/audio/common/AudioOffloadMetadata.aidl b/audio/aidl/android/hardware/audio/common/AudioOffloadMetadata.aidl new file mode 100644 index 0000000000..588165824b --- /dev/null +++ b/audio/aidl/android/hardware/audio/common/AudioOffloadMetadata.aidl @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.audio.common; + +import android.media.audio.common.AudioChannelLayout; + +/** + * Dynamic metadata for offloaded compressed audio. + * For static metadata, see android.media.audio.common.AudioOffloadInfo. + */ +@JavaDerive(equals=true, toString=true) +@VintfStability +parcelable AudioOffloadMetadata { + int sampleRate; + AudioChannelLayout channelMask; + /** Average bit rate in bits per second. */ + int averageBitRatePerSecond; + /** + * Number of frames to be ignored at the beginning of the stream. + * The value must be non-negative. A value of 0 indicates no delay + * has to be applied. + */ + int delayFrames; + /** + * Number of frames to be ignored at the end of the stream. + * The value must be non-negative. A value of 0 indicates no padding + * has to be applied. + */ + int paddingFrames; +} diff --git a/audio/aidl/android/hardware/audio/core/IStreamOut.aidl b/audio/aidl/android/hardware/audio/core/IStreamOut.aidl index 0e58addd7d..54c81621e1 100644 --- a/audio/aidl/android/hardware/audio/core/IStreamOut.aidl +++ b/audio/aidl/android/hardware/audio/core/IStreamOut.aidl @@ -16,6 +16,7 @@ package android.hardware.audio.core; +import android.hardware.audio.common.AudioOffloadMetadata; import android.hardware.audio.common.SourceMetadata; import android.hardware.audio.core.IStreamCommon; import android.media.audio.common.AudioDualMonoMode; @@ -48,6 +49,18 @@ interface IStreamOut { */ void updateMetadata(in SourceMetadata sourceMetadata); + /** + * Update offload metadata for a compressed stream. + * + * Updates the offload metadata initially provided at the stream creation. + * + * @param offloadMetadata Updated offload metadata. + * @throws EX_ILLEGAL_STATE If the stream is closed. + * @throws EX_ILLEGAL_ARGUMENT If the metadata contains invalid values. + * @throws EX_UNSUPPORTED_OPERATION If the stream is not for compressed offload. + */ + void updateOffloadMetadata(in AudioOffloadMetadata offloadMetadata); + const int HW_VOLUME_MIN = 0; const int HW_VOLUME_MAX = 1; /** diff --git a/audio/aidl/default/Stream.cpp b/audio/aidl/default/Stream.cpp index 49ad2f2d74..193c793ba0 100644 --- a/audio/aidl/default/Stream.cpp +++ b/audio/aidl/default/Stream.cpp @@ -24,6 +24,7 @@ #include "core-impl/Module.h" #include "core-impl/Stream.h" +using aidl::android::hardware::audio::common::AudioOffloadMetadata; using aidl::android::hardware::audio::common::SinkMetadata; using aidl::android::hardware::audio::common::SourceMetadata; using aidl::android::media::audio::common::AudioDevice; @@ -785,6 +786,40 @@ StreamOut::StreamOut(const SourceMetadata& sourceMetadata, StreamContext&& conte LOG(DEBUG) << __func__; } +ndk::ScopedAStatus StreamOut::updateOffloadMetadata( + const AudioOffloadMetadata& in_offloadMetadata) { + LOG(DEBUG) << __func__; + if (isClosed()) { + LOG(ERROR) << __func__ << ": stream was closed"; + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } + if (!mOffloadInfo.has_value()) { + LOG(ERROR) << __func__ << ": not a compressed offload stream"; + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); + } + if (in_offloadMetadata.sampleRate < 0) { + LOG(ERROR) << __func__ << ": invalid sample rate value: " << in_offloadMetadata.sampleRate; + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } + if (in_offloadMetadata.averageBitRatePerSecond < 0) { + LOG(ERROR) << __func__ + << ": invalid average BPS value: " << in_offloadMetadata.averageBitRatePerSecond; + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } + if (in_offloadMetadata.delayFrames < 0) { + LOG(ERROR) << __func__ + << ": invalid delay frames value: " << in_offloadMetadata.delayFrames; + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } + if (in_offloadMetadata.paddingFrames < 0) { + LOG(ERROR) << __func__ + << ": invalid padding frames value: " << in_offloadMetadata.paddingFrames; + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } + mOffloadMetadata = in_offloadMetadata; + return ndk::ScopedAStatus::ok(); +} + ndk::ScopedAStatus StreamOut::getHwVolume(std::vector* _aidl_return) { LOG(DEBUG) << __func__; (void)_aidl_return; diff --git a/audio/aidl/default/include/core-impl/Stream.h b/audio/aidl/default/include/core-impl/Stream.h index 0d4365a3ae..e9b1fbb847 100644 --- a/audio/aidl/default/include/core-impl/Stream.h +++ b/audio/aidl/default/include/core-impl/Stream.h @@ -463,6 +463,9 @@ class StreamOut : public StreamCommonImpl<::aidl::android::hardware::audio::comm return StreamCommonImpl<::aidl::android::hardware::audio::common::SourceMetadata>:: updateMetadata(in_sourceMetadata); } + ndk::ScopedAStatus updateOffloadMetadata( + const ::aidl::android::hardware::audio::common::AudioOffloadMetadata& + in_offloadMetadata) override; ndk::ScopedAStatus getHwVolume(std::vector* _aidl_return) override; ndk::ScopedAStatus setHwVolume(const std::vector& in_channelVolumes) override; ndk::ScopedAStatus getAudioDescriptionMixLevel(float* _aidl_return) override; @@ -500,6 +503,7 @@ class StreamOut : public StreamCommonImpl<::aidl::android::hardware::audio::comm offloadInfo); std::optional<::aidl::android::media::audio::common::AudioOffloadInfo> mOffloadInfo; + std::optional<::aidl::android::hardware::audio::common::AudioOffloadMetadata> mOffloadMetadata; public: using CreateInstance = std::function ModuleConfig::generateOffloadInfoIfNeeded( offloadInfo.base.sampleRate = portConfig.sampleRate.value().value; offloadInfo.base.channelMask = portConfig.channelMask.value(); offloadInfo.base.format = portConfig.format.value(); - offloadInfo.bitRatePerSecond = 256; // Arbitrary value. + offloadInfo.bitRatePerSecond = 256000; // Arbitrary value. offloadInfo.durationUs = std::chrono::microseconds(1min).count(); // Arbitrary value. offloadInfo.usage = AudioUsage::MEDIA; offloadInfo.encapsulationMode = AudioEncapsulationMode::NONE; diff --git a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp index b6015ffca5..cd7ab0e91e 100644 --- a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp +++ b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp @@ -53,6 +53,7 @@ #include "TestUtils.h" using namespace android; +using aidl::android::hardware::audio::common::AudioOffloadMetadata; using aidl::android::hardware::audio::common::PlaybackTrackMetadata; using aidl::android::hardware::audio::common::RecordTrackMetadata; using aidl::android::hardware::audio::common::SinkMetadata; @@ -401,8 +402,9 @@ void TestSetVendorParameters(Instance* inst, bool* isSupported) { // Can be used as a base for any test here, does not depend on the fixture GTest parameters. class AudioCoreModuleBase { public: - // The default buffer size is used mostly for negative tests. + // Default buffer sizes are used mostly for negative tests. static constexpr int kDefaultBufferSizeFrames = 256; + static constexpr int kDefaultLargeBufferSizeFrames = 48000; void SetUpImpl(const std::string& moduleName) { ASSERT_NO_FATAL_FAILURE(ConnectToService(moduleName)); @@ -2696,7 +2698,7 @@ TEST_P(AudioStreamOut, RequireOffloadInfo) { aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args; args.portConfigId = portConfig.getId(); args.sourceMetadata = GenerateSourceMetadata(portConfig.get()); - args.bufferSizeFrames = kDefaultBufferSizeFrames; + args.bufferSizeFrames = kDefaultLargeBufferSizeFrames; aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret; EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->openOutputStream(args, &ret)) << "when no offload info is provided for a compressed offload mix port"; @@ -2876,7 +2878,7 @@ TEST_P(AudioStreamOut, PlaybackRate) { const auto portConfig = moduleConfig->getSingleConfigForMixPort(false, port); ASSERT_TRUE(portConfig.has_value()) << "No profiles specified for output mix port"; WithStream stream(portConfig.value()); - ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames)); + ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultLargeBufferSizeFrames)); bool isSupported = false; EXPECT_NO_FATAL_FAILURE(TestAccessors( stream.get(), &IStreamOut::getPlaybackRateParameters, @@ -2901,7 +2903,7 @@ TEST_P(AudioStreamOut, SelectPresentation) { const auto portConfig = moduleConfig->getSingleConfigForMixPort(false, port); ASSERT_TRUE(portConfig.has_value()) << "No profiles specified for output mix port"; WithStream stream(portConfig.value()); - ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames)); + ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultLargeBufferSizeFrames)); ndk::ScopedAStatus status; EXPECT_STATUS(kStatuses, status = stream.get()->selectPresentation(0, 0)); if (status.getExceptionCode() != EX_UNSUPPORTED_OPERATION) atLeastOneSupports = true; @@ -2911,6 +2913,33 @@ TEST_P(AudioStreamOut, SelectPresentation) { } } +TEST_P(AudioStreamOut, UpdateOffloadMetadata) { + const auto offloadMixPorts = + moduleConfig->getOffloadMixPorts(true /*attachedOnly*/, false /*singlePort*/); + if (offloadMixPorts.empty()) { + GTEST_SKIP() + << "No mix port for compressed offload that could be routed to attached devices"; + } + for (const auto& port : offloadMixPorts) { + const auto portConfig = moduleConfig->getSingleConfigForMixPort(false, port); + ASSERT_TRUE(portConfig.has_value()) << "No profiles specified for output mix port"; + WithStream stream(portConfig.value()); + ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultLargeBufferSizeFrames)); + AudioOffloadMetadata validMetadata{ + .sampleRate = portConfig.value().sampleRate.value().value, + .channelMask = portConfig.value().channelMask.value(), + .averageBitRatePerSecond = 256000, + .delayFrames = 0, + .paddingFrames = 0}; + EXPECT_IS_OK(stream.get()->updateOffloadMetadata(validMetadata)); + AudioOffloadMetadata invalidMetadata{.sampleRate = -1, + .averageBitRatePerSecond = -1, + .delayFrames = -1, + .paddingFrames = -1}; + EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, stream.get()->updateOffloadMetadata(invalidMetadata)); + } +} + class StreamLogicDefaultDriver : public StreamLogicDriver { public: StreamLogicDefaultDriver(std::shared_ptr commands, size_t frameSizeBytes) diff --git a/automotive/audiocontrol/aidl/vts/Android.bp b/automotive/audiocontrol/aidl/vts/Android.bp index a9122ce2d6..cfc2a3e4ec 100644 --- a/automotive/audiocontrol/aidl/vts/Android.bp +++ b/automotive/audiocontrol/aidl/vts/Android.bp @@ -25,7 +25,6 @@ cc_test { name: "VtsAidlHalAudioControlTest", defaults: [ "latest_android_media_audio_common_types_cpp_static", - "latest_android_hardware_audio_common_cpp_static", "VtsHalTargetTestDefaults", "use_libaidlvintf_gtest_helper_static", ], @@ -40,6 +39,7 @@ cc_test { ], static_libs: [ "android.hardware.automotive.audiocontrol-V3-cpp", + "android.hardware.audio.common-V1-cpp", "libgmock", ], test_suites: [