Merge "audio: Add AudioOffloadMetadata and a method to update it" into udc-dev

This commit is contained in:
TreeHugger Robot 2023-03-01 01:23:23 +00:00 committed by Android (Google) Code Review
commit e6c11eea73
10 changed files with 179 additions and 10 deletions

View file

@ -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: {

View file

@ -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 <name>-update-api`.
//
// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.audio.common;
@JavaDerive(equals=true, toString=true) @VintfStability
parcelable AudioOffloadMetadata {
int sampleRate;
android.media.audio.common.AudioChannelLayout channelMask;
int averageBitRatePerSecond;
int delayFrames;
int paddingFrames;
}

View file

@ -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();

View file

@ -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;
}

View file

@ -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;
/**

View file

@ -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<float>* _aidl_return) {
LOG(DEBUG) << __func__;
(void)_aidl_return;

View file

@ -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<float>* _aidl_return) override;
ndk::ScopedAStatus setHwVolume(const std::vector<float>& 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<ndk::ScopedAStatus(

View file

@ -56,7 +56,7 @@ std::optional<AudioOffloadInfo> 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;

View file

@ -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<IStreamOut> 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<AudioPlaybackRate>(
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<IStreamOut> 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<IStreamOut> 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<StateSequence> commands, size_t frameSizeBytes)

View file

@ -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: [