From cf824f65c807c4dd2ae0a278e97b2e9fe0ee29fd Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Mon, 24 Jul 2023 14:51:36 -0700 Subject: [PATCH] audio: Implement the major functionality of the primary CF HAL Core HAL changes: 1. Add StreamPrimary implemented via StreamAlsa. 2. Align the configuration with the HIDL HAL. 3. Fix position retrieval vs. standby call. 4. Fix sleeps in StreamAlsa. VTS changes: 1. Use several bursts for stream I/O test scenarios that check observable position increase. This is because the position may not be available until a couple of transfers have been made. 2. Do not require position increase for the scenarios that do not make several bursts. As specified above, the position may not have been increased for the ALSA case. Whereas, using multiple bursts in all scenarios will increase test time, and make the state machine transitions graph more complicated. 3. Hook up the test config file to shut down audioserver during VTS tests, fix the test config file. Bug: 286914845 Test: atest VtsHalAudioCoreTargetTest Test: compare APM dumps for AIDL vs. HIDL Change-Id: I85271564c664fa40008d60e82b32eaa66a99c68f --- audio/aidl/default/Android.bp | 2 + audio/aidl/default/Configuration.cpp | 139 ++++++------- audio/aidl/default/ModulePrimary.cpp | 10 +- audio/aidl/default/Stream.cpp | 57 +++++- audio/aidl/default/alsa/StreamAlsa.cpp | 32 ++- audio/aidl/default/alsa/Utils.cpp | 10 +- audio/aidl/default/alsa/Utils.h | 1 + audio/aidl/default/include/core-impl/Stream.h | 22 +++ .../default/include/core-impl/StreamAlsa.h | 2 + .../default/include/core-impl/StreamPrimary.h | 84 ++++++++ .../default/include/core-impl/StreamStub.h | 1 + .../default/include/core-impl/StreamUsb.h | 5 +- audio/aidl/default/primary/PrimaryMixer.cpp | 29 +++ audio/aidl/default/primary/PrimaryMixer.h | 42 ++++ audio/aidl/default/primary/StreamPrimary.cpp | 186 ++++++++++++++++++ audio/aidl/default/stub/StreamStub.cpp | 15 +- audio/aidl/default/usb/StreamUsb.cpp | 12 +- audio/aidl/vts/Android.bp | 1 + .../vts/VtsHalAudioCoreModuleTargetTest.cpp | 154 +++++++++------ audio/aidl/vts/VtsHalAudioCoreTargetTest.xml | 5 + 20 files changed, 637 insertions(+), 172 deletions(-) create mode 100644 audio/aidl/default/include/core-impl/StreamPrimary.h create mode 100644 audio/aidl/default/primary/PrimaryMixer.cpp create mode 100644 audio/aidl/default/primary/PrimaryMixer.h create mode 100644 audio/aidl/default/primary/StreamPrimary.cpp diff --git a/audio/aidl/default/Android.bp b/audio/aidl/default/Android.bp index b6cfc1329c..8596466738 100644 --- a/audio/aidl/default/Android.bp +++ b/audio/aidl/default/Android.bp @@ -85,6 +85,8 @@ cc_library { "bluetooth/DevicePortProxy.cpp", "bluetooth/ModuleBluetooth.cpp", "bluetooth/StreamBluetooth.cpp", + "primary/PrimaryMixer.cpp", + "primary/StreamPrimary.cpp", "r_submix/ModuleRemoteSubmix.cpp", "r_submix/RemoteSubmixUtils.cpp", "r_submix/SubmixRoute.cpp", diff --git a/audio/aidl/default/Configuration.cpp b/audio/aidl/default/Configuration.cpp index 385ffbf9fc..d05d214557 100644 --- a/audio/aidl/default/Configuration.cpp +++ b/audio/aidl/default/Configuration.cpp @@ -136,7 +136,7 @@ static AudioRoute createRoute(const std::vector& sources, const Audio // Device ports: // * "Speaker", OUT_SPEAKER, default // - no profiles specified -// * "Built-in Mic", IN_MICROPHONE, default +// * "Built-In Mic", IN_MICROPHONE, default // - no profiles specified // * "Telephony Tx", OUT_TELEPHONY_TX // - no profiles specified @@ -148,45 +148,34 @@ static AudioRoute createRoute(const std::vector& sources, const Audio // Mix ports: // * "primary output", PRIMARY, 1 max open, 1 max active stream // - profile PCM 16-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000 -// - profile PCM 24-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000 -// * "compressed offload", DIRECT|COMPRESS_OFFLOAD|NON_BLOCKING, 1 max open, 1 max active stream -// - profile MP3; MONO, STEREO; 44100, 48000 -// * "primary input", 2 max open, 2 max active streams -// - profile PCM 16-bit; MONO, STEREO, FRONT_BACK; -// 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000 -// - profile PCM 24-bit; MONO, STEREO, FRONT_BACK; -// 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000 +// * "primary input", 1 max open, 1 max active stream +// - profile PCM 16-bit; MONO, STEREO; +// 8000, 11025, 16000, 32000, 44100, 48000 // * "telephony_tx", 1 max open, 1 max active stream // - profile PCM 16-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000 -// - profile PCM 24-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000 // * "telephony_rx", 1 max open, 1 max active stream // - profile PCM 16-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000 -// - profile PCM 24-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000 // * "fm_tuner", 1 max open, 1 max active stream // - profile PCM 16-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000 -// - profile PCM 24-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000 // // Routes: -// "primary out", "compressed offload" -> "Speaker" -// "Built-in Mic" -> "primary input" -// "telephony_tx" -> "Telephony Tx" +// "primary out" -> "Speaker" +// "Built-In Mic" -> "primary input" // "Telephony Rx" -> "telephony_rx" +// "telephony_tx" -> "Telephony Tx" // "FM Tuner" -> "fm_tuner" // // Initial port configs: -// * "Speaker" device port: PCM 24-bit; STEREO; 48000 -// * "Built-in Mic" device port: PCM 24-bit; MONO; 48000 -// * "Telephony Tx" device port: PCM 24-bit; MONO; 48000 -// * "Telephony Rx" device port: PCM 24-bit; MONO; 48000 -// * "FM Tuner" device port: PCM 24-bit; STEREO; 48000 +// * "Speaker" device port: PCM 16-bit; STEREO; 48000 +// * "Built-In Mic" device port: PCM 16-bit; MONO; 48000 +// * "Telephony Tx" device port: PCM 16-bit; MONO; 48000 +// * "Telephony Rx" device port: PCM 16-bit; MONO; 48000 +// * "FM Tuner" device port: PCM 16-bit; STEREO; 48000 // std::unique_ptr getPrimaryConfiguration() { static const Configuration configuration = []() { const std::vector standardPcmAudioProfiles = { createProfile(PcmType::INT_16_BIT, - {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO}, - {8000, 11025, 16000, 32000, 44100, 48000}), - createProfile(PcmType::INT_24_BIT, {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO}, {8000, 11025, 16000, 32000, 44100, 48000})}; Configuration c; @@ -199,17 +188,17 @@ std::unique_ptr getPrimaryConfiguration() { 1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE)); c.ports.push_back(speakerOutDevice); c.initialConfigs.push_back( - createPortConfig(speakerOutDevice.id, speakerOutDevice.id, PcmType::INT_24_BIT, + createPortConfig(speakerOutDevice.id, speakerOutDevice.id, PcmType::INT_16_BIT, AudioChannelLayout::LAYOUT_STEREO, 48000, 0, false, createDeviceExt(AudioDeviceType::OUT_SPEAKER, 0))); AudioPort micInDevice = - createPort(c.nextPortId++, "Built-in Mic", 0, true, + createPort(c.nextPortId++, "Built-In Mic", 0, true, createDeviceExt(AudioDeviceType::IN_MICROPHONE, 1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE)); c.ports.push_back(micInDevice); c.initialConfigs.push_back( - createPortConfig(micInDevice.id, micInDevice.id, PcmType::INT_24_BIT, + createPortConfig(micInDevice.id, micInDevice.id, PcmType::INT_16_BIT, AudioChannelLayout::LAYOUT_MONO, 48000, 0, true, createDeviceExt(AudioDeviceType::IN_MICROPHONE, 0))); @@ -219,7 +208,7 @@ std::unique_ptr getPrimaryConfiguration() { c.ports.push_back(telephonyTxOutDevice); c.initialConfigs.push_back( createPortConfig(telephonyTxOutDevice.id, telephonyTxOutDevice.id, - PcmType::INT_24_BIT, AudioChannelLayout::LAYOUT_MONO, 48000, 0, + PcmType::INT_16_BIT, AudioChannelLayout::LAYOUT_MONO, 48000, 0, false, createDeviceExt(AudioDeviceType::OUT_TELEPHONY_TX, 0))); AudioPort telephonyRxInDevice = @@ -228,14 +217,14 @@ std::unique_ptr getPrimaryConfiguration() { c.ports.push_back(telephonyRxInDevice); c.initialConfigs.push_back( createPortConfig(telephonyRxInDevice.id, telephonyRxInDevice.id, - PcmType::INT_24_BIT, AudioChannelLayout::LAYOUT_MONO, 48000, 0, + PcmType::INT_16_BIT, AudioChannelLayout::LAYOUT_MONO, 48000, 0, true, createDeviceExt(AudioDeviceType::IN_TELEPHONY_RX, 0))); AudioPort fmTunerInDevice = createPort(c.nextPortId++, "FM Tuner", 0, true, createDeviceExt(AudioDeviceType::IN_FM_TUNER, 0)); c.ports.push_back(fmTunerInDevice); c.initialConfigs.push_back( - createPortConfig(fmTunerInDevice.id, fmTunerInDevice.id, PcmType::INT_24_BIT, + createPortConfig(fmTunerInDevice.id, fmTunerInDevice.id, PcmType::INT_16_BIT, AudioChannelLayout::LAYOUT_STEREO, 48000, 0, true, createDeviceExt(AudioDeviceType::IN_FM_TUNER, 0))); @@ -249,30 +238,12 @@ std::unique_ptr getPrimaryConfiguration() { standardPcmAudioProfiles.end()); c.ports.push_back(primaryOutMix); - AudioPort compressedOffloadOutMix = - createPort(c.nextPortId++, "compressed offload", - makeBitPositionFlagMask({AudioOutputFlags::DIRECT, - AudioOutputFlags::COMPRESS_OFFLOAD, - AudioOutputFlags::NON_BLOCKING}), - false, createPortMixExt(1, 1)); - compressedOffloadOutMix.profiles.push_back( - createProfile(::android::MEDIA_MIMETYPE_AUDIO_MPEG, - {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO}, - {44100, 48000})); - c.ports.push_back(compressedOffloadOutMix); - AudioPort primaryInMix = - createPort(c.nextPortId++, "primary input", 0, true, createPortMixExt(2, 2)); + createPort(c.nextPortId++, "primary input", 0, true, createPortMixExt(1, 1)); primaryInMix.profiles.push_back( createProfile(PcmType::INT_16_BIT, - {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO, - AudioChannelLayout::LAYOUT_FRONT_BACK}, - {8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000})); - primaryInMix.profiles.push_back( - createProfile(PcmType::INT_24_BIT, - {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO, - AudioChannelLayout::LAYOUT_FRONT_BACK}, - {8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000})); + {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO}, + {8000, 11025, 16000, 32000, 44100, 48000})); c.ports.push_back(primaryInMix); AudioPort telephonyTxOutMix = @@ -296,10 +267,10 @@ std::unique_ptr getPrimaryConfiguration() { standardPcmAudioProfiles.end()); c.ports.push_back(fmTunerInMix); - c.routes.push_back(createRoute({primaryOutMix, compressedOffloadOutMix}, speakerOutDevice)); + c.routes.push_back(createRoute({primaryOutMix}, speakerOutDevice)); c.routes.push_back(createRoute({micInDevice}, primaryInMix)); - c.routes.push_back(createRoute({telephonyTxOutMix}, telephonyTxOutDevice)); c.routes.push_back(createRoute({telephonyRxInDevice}, telephonyRxInMix)); + c.routes.push_back(createRoute({telephonyTxOutMix}, telephonyTxOutDevice)); c.routes.push_back(createRoute({fmTunerInDevice}, fmTunerInMix)); c.portConfigs.insert(c.portConfigs.end(), c.initialConfigs.begin(), c.initialConfigs.end()); @@ -320,15 +291,15 @@ std::unique_ptr getPrimaryConfiguration() { // // Device ports: // * "Remote Submix Out", OUT_SUBMIX -// - profile PCM 24-bit; STEREO; 48000 +// - profile PCM 16-bit; STEREO; 48000 // * "Remote Submix In", IN_SUBMIX -// - profile PCM 24-bit; STEREO; 48000 +// - profile PCM 16-bit; STEREO; 48000 // // Mix ports: -// * "r_submix output", stream count unlimited -// - profile PCM 24-bit; STEREO; 48000 -// * "r_submix input", stream count unlimited -// - profile PCM 24-bit; STEREO; 48000 +// * "r_submix output", 1 max open, 1 max active stream +// - profile PCM 16-bit; STEREO; 48000 +// * "r_submix input", 1 max open, 1 max active stream +// - profile PCM 16-bit; STEREO; 48000 // // Routes: // "r_submix output" -> "Remote Submix Out" @@ -345,27 +316,27 @@ std::unique_ptr getRSubmixConfiguration() { createDeviceExt(AudioDeviceType::OUT_SUBMIX, 0, AudioDeviceDescription::CONNECTION_VIRTUAL)); rsubmixOutDevice.profiles.push_back( - createProfile(PcmType::INT_24_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000})); + createProfile(PcmType::INT_16_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000})); c.ports.push_back(rsubmixOutDevice); AudioPort rsubmixInDevice = createPort(c.nextPortId++, "Remote Submix In", 0, true, createDeviceExt(AudioDeviceType::IN_SUBMIX, 0)); rsubmixInDevice.profiles.push_back( - createProfile(PcmType::INT_24_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000})); + createProfile(PcmType::INT_16_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000})); c.ports.push_back(rsubmixInDevice); // Mix ports AudioPort rsubmixOutMix = - createPort(c.nextPortId++, "r_submix output", 0, false, createPortMixExt(0, 0)); + createPort(c.nextPortId++, "r_submix output", 0, false, createPortMixExt(1, 1)); rsubmixOutMix.profiles.push_back( - createProfile(PcmType::INT_24_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000})); + createProfile(PcmType::INT_16_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000})); c.ports.push_back(rsubmixOutMix); AudioPort rsubmixInMix = - createPort(c.nextPortId++, "r_submix input", 0, true, createPortMixExt(0, 0)); + createPort(c.nextPortId++, "r_submix input", 0, true, createPortMixExt(1, 1)); rsubmixInMix.profiles.push_back( - createProfile(PcmType::INT_24_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000})); + createProfile(PcmType::INT_16_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000})); c.ports.push_back(rsubmixInMix); c.routes.push_back(createRoute({rsubmixOutMix}, rsubmixOutDevice)); @@ -483,7 +454,7 @@ std::unique_ptr getUsbConfiguration() { // - profile MP3; MONO, STEREO; 44100, 48000 // * "test input", 2 max open, 2 max active streams // - profile PCM 24-bit; MONO, STEREO, FRONT_BACK; -// 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000 +// 8000, 11025, 16000, 22050, 32000, 44100, 48000 // // Routes: // "test output", "compressed offload" -> "Test Out" @@ -543,12 +514,12 @@ std::unique_ptr getStubConfiguration() { createProfile(PcmType::INT_16_BIT, {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO, AudioChannelLayout::LAYOUT_FRONT_BACK}, - {8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000})); + {8000, 11025, 16000, 22050, 32000, 44100, 48000})); testInMIx.profiles.push_back( createProfile(PcmType::INT_24_BIT, {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO, AudioChannelLayout::LAYOUT_FRONT_BACK}, - {8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000})); + {8000, 11025, 16000, 22050, 32000, 44100, 48000})); c.ports.push_back(testInMIx); c.routes.push_back(createRoute({testOutMix, compressedOffloadOutMix}, testOutDevice)); @@ -566,7 +537,7 @@ std::unique_ptr getStubConfiguration() { // Device ports: // * "BT A2DP Out", OUT_DEVICE, CONNECTION_BT_A2DP // - profile PCM 16-bit; STEREO; 44100, 48000, 88200, 96000 -// * "BT A2DP Headphones", OUT_HEADSET, CONNECTION_BT_A2DP +// * "BT A2DP Headphones", OUT_HEADPHONE, CONNECTION_BT_A2DP // - profile PCM 16-bit; STEREO; 44100, 48000, 88200, 96000 // * "BT A2DP Speaker", OUT_SPEAKER, CONNECTION_BT_A2DP // - profile PCM 16-bit; STEREO; 44100, 48000, 88200, 96000 @@ -597,13 +568,18 @@ std::unique_ptr getBluetoothConfiguration() { createPort(c.nextPortId++, "BT A2DP Out", 0, false, createDeviceExt(AudioDeviceType::OUT_DEVICE, 0, AudioDeviceDescription::CONNECTION_BT_A2DP)); + btOutDevice.profiles.insert(btOutDevice.profiles.begin(), standardPcmAudioProfiles.begin(), + standardPcmAudioProfiles.end()); c.ports.push_back(btOutDevice); c.connectedProfiles[btOutDevice.id] = standardPcmAudioProfiles; AudioPort btOutHeadphone = createPort(c.nextPortId++, "BT A2DP Headphones", 0, false, - createDeviceExt(AudioDeviceType::OUT_HEADSET, 0, + createDeviceExt(AudioDeviceType::OUT_HEADPHONE, 0, AudioDeviceDescription::CONNECTION_BT_A2DP)); + btOutHeadphone.profiles.insert(btOutHeadphone.profiles.begin(), + standardPcmAudioProfiles.begin(), + standardPcmAudioProfiles.end()); c.ports.push_back(btOutHeadphone); c.connectedProfiles[btOutHeadphone.id] = standardPcmAudioProfiles; @@ -611,6 +587,9 @@ std::unique_ptr getBluetoothConfiguration() { createPort(c.nextPortId++, "BT A2DP Speaker", 0, false, createDeviceExt(AudioDeviceType::OUT_SPEAKER, 0, AudioDeviceDescription::CONNECTION_BT_A2DP)); + btOutSpeaker.profiles.insert(btOutSpeaker.profiles.begin(), + standardPcmAudioProfiles.begin(), + standardPcmAudioProfiles.end()); c.ports.push_back(btOutSpeaker); c.connectedProfiles[btOutSpeaker.id] = standardPcmAudioProfiles; @@ -623,20 +602,20 @@ std::unique_ptr getBluetoothConfiguration() { {createProfile(PcmType::INT_16_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {16000})}); // Mix ports - AudioPort btInMix = - createPort(c.nextPortId++, "a2dp output", 0, true, createPortMixExt(1, 1)); - c.ports.push_back(btInMix); + AudioPort btOutMix = + createPort(c.nextPortId++, "a2dp output", 0, false, createPortMixExt(1, 1)); + c.ports.push_back(btOutMix); - AudioPort btHeadsetInMix = - createPort(c.nextPortId++, "hearing aid output", 0, true, createPortMixExt(1, 1)); - btHeadsetInMix.profiles.push_back(createProfile( + AudioPort btHearingOutMix = + createPort(c.nextPortId++, "hearing aid output", 0, false, createPortMixExt(1, 1)); + btHearingOutMix.profiles.push_back(createProfile( PcmType::INT_16_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {16000, 24000})); - c.ports.push_back(btHeadsetInMix); + c.ports.push_back(btHearingOutMix); - c.routes.push_back(createRoute({btInMix}, btOutDevice)); - c.routes.push_back(createRoute({btInMix}, btOutHeadphone)); - c.routes.push_back(createRoute({btInMix}, btOutSpeaker)); - c.routes.push_back(createRoute({btHeadsetInMix}, btOutHearingAid)); + c.routes.push_back(createRoute({btOutMix}, btOutDevice)); + c.routes.push_back(createRoute({btOutMix}, btOutHeadphone)); + c.routes.push_back(createRoute({btOutMix}, btOutSpeaker)); + c.routes.push_back(createRoute({btHearingOutMix}, btOutHearingAid)); return c; }(); diff --git a/audio/aidl/default/ModulePrimary.cpp b/audio/aidl/default/ModulePrimary.cpp index 29e81264ac..9919c7f6cc 100644 --- a/audio/aidl/default/ModulePrimary.cpp +++ b/audio/aidl/default/ModulePrimary.cpp @@ -21,7 +21,7 @@ #include #include "core-impl/ModulePrimary.h" -#include "core-impl/StreamStub.h" +#include "core-impl/StreamPrimary.h" #include "core-impl/Telephony.h" using aidl::android::hardware::audio::common::SinkMetadata; @@ -47,15 +47,15 @@ ndk::ScopedAStatus ModulePrimary::createInputStream(StreamContext&& context, const SinkMetadata& sinkMetadata, const std::vector& microphones, std::shared_ptr* result) { - return createStreamInstance(result, std::move(context), sinkMetadata, - microphones); + return createStreamInstance(result, std::move(context), sinkMetadata, + microphones); } ndk::ScopedAStatus ModulePrimary::createOutputStream( StreamContext&& context, const SourceMetadata& sourceMetadata, const std::optional& offloadInfo, std::shared_ptr* result) { - return createStreamInstance(result, std::move(context), sourceMetadata, - offloadInfo); + return createStreamInstance(result, std::move(context), sourceMetadata, + offloadInfo); } } // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/Stream.cpp b/audio/aidl/default/Stream.cpp index 7a617c9f9a..196ab2ff7a 100644 --- a/audio/aidl/default/Stream.cpp +++ b/audio/aidl/default/Stream.cpp @@ -238,8 +238,8 @@ StreamInWorkerLogic::Status StreamInWorkerLogic::cycle() { break; case Tag::standby: if (mState == StreamDescriptor::State::IDLE) { + populateReply(&reply, mIsConnected); if (::android::status_t status = mDriver->standby(); status == ::android::OK) { - populateReply(&reply, mIsConnected); mState = StreamDescriptor::State::STANDBY; } else { LOG(ERROR) << __func__ << ": standby failed: " << status; @@ -492,8 +492,8 @@ StreamOutWorkerLogic::Status StreamOutWorkerLogic::cycle() { break; case Tag::standby: if (mState == StreamDescriptor::State::IDLE) { + populateReply(&reply, mIsConnected); if (::android::status_t status = mDriver->standby(); status == ::android::OK) { - populateReply(&reply, mIsConnected); mState = StreamDescriptor::State::STANDBY; } else { LOG(ERROR) << __func__ << ": standby failed: " << status; @@ -799,6 +799,32 @@ ndk::ScopedAStatus StreamIn::setHwGain(const std::vector& in_channelGains return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); } +StreamInHwGainHelper::StreamInHwGainHelper(const StreamContext* context) + : mChannelCount(getChannelCount(context->getChannelLayout())) {} + +ndk::ScopedAStatus StreamInHwGainHelper::getHwGainImpl(std::vector* _aidl_return) { + *_aidl_return = mHwGains; + LOG(DEBUG) << __func__ << ": returning " << ::android::internal::ToString(*_aidl_return); + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus StreamInHwGainHelper::setHwGainImpl(const std::vector& in_channelGains) { + LOG(DEBUG) << __func__ << ": gains " << ::android::internal::ToString(in_channelGains); + if (in_channelGains.size() != mChannelCount) { + LOG(ERROR) << __func__ + << ": channel count does not match stream channel count: " << mChannelCount; + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } + for (float gain : in_channelGains) { + if (gain < StreamIn::HW_GAIN_MIN || gain > StreamIn::HW_GAIN_MAX) { + LOG(ERROR) << __func__ << ": gain value out of range: " << gain; + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } + } + mHwGains = in_channelGains; + return ndk::ScopedAStatus::ok(); +} + StreamOut::StreamOut(StreamContext&& context, const std::optional& offloadInfo) : mContextInstance(std::move(context)), mOffloadInfo(offloadInfo) { LOG(DEBUG) << __func__; @@ -904,4 +930,31 @@ ndk::ScopedAStatus StreamOut::selectPresentation(int32_t in_presentationId, int3 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); } +StreamOutHwVolumeHelper::StreamOutHwVolumeHelper(const StreamContext* context) + : mChannelCount(getChannelCount(context->getChannelLayout())) {} + +ndk::ScopedAStatus StreamOutHwVolumeHelper::getHwVolumeImpl(std::vector* _aidl_return) { + *_aidl_return = mHwVolumes; + LOG(DEBUG) << __func__ << ": returning " << ::android::internal::ToString(*_aidl_return); + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus StreamOutHwVolumeHelper::setHwVolumeImpl( + const std::vector& in_channelVolumes) { + LOG(DEBUG) << __func__ << ": volumes " << ::android::internal::ToString(in_channelVolumes); + if (in_channelVolumes.size() != mChannelCount) { + LOG(ERROR) << __func__ + << ": channel count does not match stream channel count: " << mChannelCount; + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } + for (float volume : in_channelVolumes) { + if (volume < StreamOut::HW_VOLUME_MIN || volume > StreamOut::HW_VOLUME_MAX) { + LOG(ERROR) << __func__ << ": volume value out of range: " << volume; + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } + } + mHwVolumes = in_channelVolumes; + return ndk::ScopedAStatus::ok(); +} + } // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/alsa/StreamAlsa.cpp b/audio/aidl/default/alsa/StreamAlsa.cpp index 1d22a607e5..0605d6f464 100644 --- a/audio/aidl/default/alsa/StreamAlsa.cpp +++ b/audio/aidl/default/alsa/StreamAlsa.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#include #include #define LOG_TAG "AHAL_StreamAlsa" @@ -29,7 +30,9 @@ namespace aidl::android::hardware::audio::core { StreamAlsa::StreamAlsa(StreamContext* context, const Metadata& metadata, int readWriteRetries) : StreamCommonImpl(context, metadata), + mBufferSizeFrames(getContext().getBufferSizeInFrames()), mFrameSizeBytes(getContext().getFrameSize()), + mSampleRate(getContext().getSampleRate()), mIsInput(isInput(metadata)), mConfig(alsa::getPcmConfig(getContext(), mIsInput)), mReadWriteRetries(readWriteRetries) {} @@ -39,17 +42,20 @@ StreamAlsa::StreamAlsa(StreamContext* context, const Metadata& metadata, int rea } ::android::status_t StreamAlsa::drain(StreamDescriptor::DrainMode) { - usleep(1000); + if (!mIsInput) { + static constexpr float kMicrosPerSecond = MICROS_PER_SECOND; + const size_t delayUs = static_cast( + std::roundf(mBufferSizeFrames * kMicrosPerSecond / mSampleRate)); + usleep(delayUs); + } return ::android::OK; } ::android::status_t StreamAlsa::flush() { - usleep(1000); return ::android::OK; } ::android::status_t StreamAlsa::pause() { - usleep(1000); return ::android::OK; } @@ -59,6 +65,10 @@ StreamAlsa::StreamAlsa(StreamContext* context, const Metadata& metadata, int rea } ::android::status_t StreamAlsa::start() { + if (!mAlsaDeviceProxies.empty()) { + // This is a resume after a pause. + return ::android::OK; + } decltype(mAlsaDeviceProxies) alsaDeviceProxies; for (const auto& device : getDeviceProfiles()) { alsa::DeviceProxy proxy; @@ -71,8 +81,7 @@ StreamAlsa::StreamAlsa(StreamContext* context, const Metadata& metadata, int rea true /*require_exact_match*/); } else { proxy = alsa::openProxyForAttachedDevice( - device, const_cast(&mConfig.value()), - getContext().getBufferSizeInFrames()); + device, const_cast(&mConfig.value()), mBufferSizeFrames); } if (!proxy) { return ::android::NO_INIT; @@ -85,13 +94,13 @@ StreamAlsa::StreamAlsa(StreamContext* context, const Metadata& metadata, int rea ::android::status_t StreamAlsa::transfer(void* buffer, size_t frameCount, size_t* actualFrameCount, int32_t* latencyMs) { + if (mAlsaDeviceProxies.empty()) { + LOG(FATAL) << __func__ << ": no opened devices"; + return ::android::NO_INIT; + } const size_t bytesToTransfer = frameCount * mFrameSizeBytes; unsigned maxLatency = 0; if (mIsInput) { - if (mAlsaDeviceProxies.empty()) { - LOG(FATAL) << __func__ << ": no input devices"; - return ::android::NO_INIT; - } // For input case, only support single device. proxy_read_with_retries(mAlsaDeviceProxies[0].get(), buffer, bytesToTransfer, mReadWriteRetries); @@ -110,9 +119,12 @@ StreamAlsa::StreamAlsa(StreamContext* context, const Metadata& metadata, int rea ::android::status_t StreamAlsa::refinePosition(StreamDescriptor::Position* position) { if (mAlsaDeviceProxies.empty()) { - LOG(FATAL) << __func__ << ": no input devices"; + LOG(FATAL) << __func__ << ": no opened devices"; return ::android::NO_INIT; } + // Since the proxy can only count transferred frames since its creation, + // we override its counter value with ours and let it to correct for buffered frames. + alsa::resetTransferredFrames(mAlsaDeviceProxies[0], position->frames); if (mIsInput) { if (int ret = proxy_get_capture_position(mAlsaDeviceProxies[0].get(), &position->frames, &position->timeNs); diff --git a/audio/aidl/default/alsa/Utils.cpp b/audio/aidl/default/alsa/Utils.cpp index 20f77978fd..9dcd024d1c 100644 --- a/audio/aidl/default/alsa/Utils.cpp +++ b/audio/aidl/default/alsa/Utils.cpp @@ -262,12 +262,14 @@ std::vector getSampleRatesFromProfile(const alsa_device_profile* profile) { } DeviceProxy makeDeviceProxy() { - return DeviceProxy(new alsa_device_proxy, [](alsa_device_proxy* proxy) { + DeviceProxy proxy(new alsa_device_proxy, [](alsa_device_proxy* proxy) { if (proxy != nullptr) { proxy_close(proxy); delete proxy; } }); + memset(proxy.get(), 0, sizeof(alsa_device_proxy)); + return proxy; } DeviceProxy openProxyForAttachedDevice(const DeviceProfile& deviceProfile, @@ -334,6 +336,12 @@ std::optional readAlsaDeviceInfo(const DeviceProfile& devic return profile; } +void resetTransferredFrames(DeviceProxy& proxy, uint64_t frames) { + if (proxy != nullptr) { + proxy->transferred = frames; + } +} + AudioFormatDescription c2aidl_pcm_format_AudioFormatDescription(enum pcm_format legacy) { return findValueOrDefault(getPcmFormatToAudioFormatDescMap(), legacy, AudioFormatDescription()); } diff --git a/audio/aidl/default/alsa/Utils.h b/audio/aidl/default/alsa/Utils.h index 615e657064..37414b3d75 100644 --- a/audio/aidl/default/alsa/Utils.h +++ b/audio/aidl/default/alsa/Utils.h @@ -66,6 +66,7 @@ DeviceProxy openProxyForAttachedDevice(const DeviceProfile& deviceProfile, DeviceProxy openProxyForExternalDevice(const DeviceProfile& deviceProfile, struct pcm_config* pcmConfig, bool requireExactMatch); std::optional readAlsaDeviceInfo(const DeviceProfile& deviceProfile); +void resetTransferredFrames(DeviceProxy& proxy, uint64_t frames); ::aidl::android::media::audio::common::AudioFormatDescription c2aidl_pcm_format_AudioFormatDescription(enum pcm_format legacy); diff --git a/audio/aidl/default/include/core-impl/Stream.h b/audio/aidl/default/include/core-impl/Stream.h index a2edb6f937..e9fd6dfcc4 100644 --- a/audio/aidl/default/include/core-impl/Stream.h +++ b/audio/aidl/default/include/core-impl/Stream.h @@ -511,6 +511,17 @@ class StreamIn : virtual public StreamCommonInterface, public BnStreamIn { const std::map<::aidl::android::media::audio::common::AudioDevice, std::string> mMicrophones; }; +class StreamInHwGainHelper { + protected: + explicit StreamInHwGainHelper(const StreamContext* context); + + ndk::ScopedAStatus getHwGainImpl(std::vector* _aidl_return); + ndk::ScopedAStatus setHwGainImpl(const std::vector& in_channelGains); + + const size_t mChannelCount; + std::vector mHwGains; +}; + class StreamOut : virtual public StreamCommonInterface, public BnStreamOut { protected: void defaultOnClose(); @@ -557,6 +568,17 @@ class StreamOut : virtual public StreamCommonInterface, public BnStreamOut { std::optional<::aidl::android::hardware::audio::common::AudioOffloadMetadata> mOffloadMetadata; }; +class StreamOutHwVolumeHelper { + protected: + explicit StreamOutHwVolumeHelper(const StreamContext* context); + + ndk::ScopedAStatus getHwVolumeImpl(std::vector* _aidl_return); + ndk::ScopedAStatus setHwVolumeImpl(const std::vector& in_channelVolumes); + + const size_t mChannelCount; + std::vector mHwVolumes; +}; + // The recommended way to create a stream instance. // 'StreamImpl' is the concrete stream implementation, 'StreamInOrOut' is either 'StreamIn' or // 'StreamOut', the rest are the arguments forwarded to the constructor of 'StreamImpl'. diff --git a/audio/aidl/default/include/core-impl/StreamAlsa.h b/audio/aidl/default/include/core-impl/StreamAlsa.h index 555b27a772..2c3b284448 100644 --- a/audio/aidl/default/include/core-impl/StreamAlsa.h +++ b/audio/aidl/default/include/core-impl/StreamAlsa.h @@ -48,7 +48,9 @@ class StreamAlsa : public StreamCommonImpl { // Called from 'start' to initialize 'mAlsaDeviceProxies', the vector must be non-empty. virtual std::vector getDeviceProfiles() = 0; + const size_t mBufferSizeFrames; const size_t mFrameSizeBytes; + const int mSampleRate; const bool mIsInput; const std::optional mConfig; const int mReadWriteRetries; diff --git a/audio/aidl/default/include/core-impl/StreamPrimary.h b/audio/aidl/default/include/core-impl/StreamPrimary.h new file mode 100644 index 0000000000..b3ddd0bd53 --- /dev/null +++ b/audio/aidl/default/include/core-impl/StreamPrimary.h @@ -0,0 +1,84 @@ +/* + * 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. + */ + +#pragma once + +#include + +#include "StreamAlsa.h" +#include "StreamSwitcher.h" + +namespace aidl::android::hardware::audio::core { + +class StreamPrimary : public StreamAlsa { + public: + StreamPrimary(StreamContext* context, const Metadata& metadata); + + protected: + std::vector getDeviceProfiles() override; + + const bool mIsInput; +}; + +class StreamInPrimary final : public StreamIn, public StreamSwitcher, public StreamInHwGainHelper { + public: + friend class ndk::SharedRefBase; + StreamInPrimary( + StreamContext&& context, + const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata, + const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones); + + private: + static bool useStubStream(const ::aidl::android::media::audio::common::AudioDevice& device); + + DeviceSwitchBehavior switchCurrentStream( + const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) + override; + std::unique_ptr createNewStream( + const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices, + StreamContext* context, const Metadata& metadata) override; + void onClose(StreamDescriptor::State) override { defaultOnClose(); } + + ndk::ScopedAStatus getHwGain(std::vector* _aidl_return) override; + ndk::ScopedAStatus setHwGain(const std::vector& in_channelGains) override; +}; + +class StreamOutPrimary final : public StreamOut, + public StreamSwitcher, + public StreamOutHwVolumeHelper { + public: + friend class ndk::SharedRefBase; + StreamOutPrimary(StreamContext&& context, + const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata, + const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>& + offloadInfo); + + private: + static bool useStubStream(const ::aidl::android::media::audio::common::AudioDevice& device); + + DeviceSwitchBehavior switchCurrentStream( + const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) + override; + std::unique_ptr createNewStream( + const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices, + StreamContext* context, const Metadata& metadata) override; + void onClose(StreamDescriptor::State) override { defaultOnClose(); } + + ndk::ScopedAStatus getHwVolume(std::vector* _aidl_return) override; + ndk::ScopedAStatus setHwVolume(const std::vector& in_channelVolumes) override; +}; + +} // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/include/core-impl/StreamStub.h b/audio/aidl/default/include/core-impl/StreamStub.h index a8a3fc4961..3857e0e75e 100644 --- a/audio/aidl/default/include/core-impl/StreamStub.h +++ b/audio/aidl/default/include/core-impl/StreamStub.h @@ -35,6 +35,7 @@ class StreamStub : public StreamCommonImpl { void shutdown() override; private: + const size_t mBufferSizeFrames; const size_t mFrameSizeBytes; const int mSampleRate; const bool mIsAsynchronous; diff --git a/audio/aidl/default/include/core-impl/StreamUsb.h b/audio/aidl/default/include/core-impl/StreamUsb.h index 74e30ff97b..608f27d410 100644 --- a/audio/aidl/default/include/core-impl/StreamUsb.h +++ b/audio/aidl/default/include/core-impl/StreamUsb.h @@ -59,7 +59,7 @@ class StreamInUsb final : public StreamIn, public StreamUsb { override; }; -class StreamOutUsb final : public StreamOut, public StreamUsb { +class StreamOutUsb final : public StreamOut, public StreamUsb, public StreamOutHwVolumeHelper { public: friend class ndk::SharedRefBase; StreamOutUsb(StreamContext&& context, @@ -71,9 +71,6 @@ class StreamOutUsb final : public StreamOut, public StreamUsb { void onClose(StreamDescriptor::State) override { defaultOnClose(); } ndk::ScopedAStatus getHwVolume(std::vector* _aidl_return) override; ndk::ScopedAStatus setHwVolume(const std::vector& in_channelVolumes) override; - - const int mChannelCount; - std::vector mHwVolumes; }; } // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/primary/PrimaryMixer.cpp b/audio/aidl/default/primary/PrimaryMixer.cpp new file mode 100644 index 0000000000..577d010f20 --- /dev/null +++ b/audio/aidl/default/primary/PrimaryMixer.cpp @@ -0,0 +1,29 @@ +/* + * 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. + */ + +#define LOG_TAG "AHAL_PrimaryMixer" + +#include "PrimaryMixer.h" + +namespace aidl::android::hardware::audio::core::primary { + +// static +PrimaryMixer& PrimaryMixer::getInstance() { + static PrimaryMixer gInstance; + return gInstance; +} + +} // namespace aidl::android::hardware::audio::core::primary diff --git a/audio/aidl/default/primary/PrimaryMixer.h b/audio/aidl/default/primary/PrimaryMixer.h new file mode 100644 index 0000000000..3806428cfd --- /dev/null +++ b/audio/aidl/default/primary/PrimaryMixer.h @@ -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. + */ + +#pragma once + +#include +#include +#include +#include + +#include +#include + +#include "alsa/Mixer.h" + +namespace aidl::android::hardware::audio::core::primary { + +class PrimaryMixer : public alsa::Mixer { + public: + static constexpr int kAlsaCard = 0; + static constexpr int kAlsaDevice = 0; + + static PrimaryMixer& getInstance(); + + private: + PrimaryMixer() : alsa::Mixer(kAlsaCard) {} +}; + +} // namespace aidl::android::hardware::audio::core::primary diff --git a/audio/aidl/default/primary/StreamPrimary.cpp b/audio/aidl/default/primary/StreamPrimary.cpp new file mode 100644 index 0000000000..e01be8a3c6 --- /dev/null +++ b/audio/aidl/default/primary/StreamPrimary.cpp @@ -0,0 +1,186 @@ +/* + * 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. + */ + +#include + +#define LOG_TAG "AHAL_StreamPrimary" +#include +#include +#include + +#include "PrimaryMixer.h" +#include "core-impl/StreamPrimary.h" +#include "core-impl/StreamStub.h" + +using aidl::android::hardware::audio::common::SinkMetadata; +using aidl::android::hardware::audio::common::SourceMetadata; +using aidl::android::media::audio::common::AudioDevice; +using aidl::android::media::audio::common::AudioDeviceDescription; +using aidl::android::media::audio::common::AudioDeviceType; +using aidl::android::media::audio::common::AudioOffloadInfo; +using aidl::android::media::audio::common::MicrophoneInfo; +using android::base::GetBoolProperty; + +namespace aidl::android::hardware::audio::core { + +StreamPrimary::StreamPrimary(StreamContext* context, const Metadata& metadata) + : StreamAlsa(context, metadata, 3 /*readWriteRetries*/), mIsInput(isInput(metadata)) {} + +std::vector StreamPrimary::getDeviceProfiles() { + static const std::vector kBuiltInSource{ + alsa::DeviceProfile{.card = primary::PrimaryMixer::kAlsaCard, + .device = primary::PrimaryMixer::kAlsaDevice, + .direction = PCM_IN, + .isExternal = false}}; + static const std::vector kBuiltInSink{ + alsa::DeviceProfile{.card = primary::PrimaryMixer::kAlsaCard, + .device = primary::PrimaryMixer::kAlsaDevice, + .direction = PCM_OUT, + .isExternal = false}}; + return mIsInput ? kBuiltInSource : kBuiltInSink; +} + +StreamInPrimary::StreamInPrimary(StreamContext&& context, const SinkMetadata& sinkMetadata, + const std::vector& microphones) + : StreamIn(std::move(context), microphones), + StreamSwitcher(&mContextInstance, sinkMetadata), + StreamInHwGainHelper(&mContextInstance) {} + +bool StreamInPrimary::useStubStream(const AudioDevice& device) { + static const bool kSimulateInput = + GetBoolProperty("ro.boot.audio.tinyalsa.simulate_input", false); + return kSimulateInput || device.type.type == AudioDeviceType::IN_TELEPHONY_RX || + device.type.type == AudioDeviceType::IN_FM_TUNER || + device.type.connection == AudioDeviceDescription::CONNECTION_BUS; +} + +StreamSwitcher::DeviceSwitchBehavior StreamInPrimary::switchCurrentStream( + const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) { + LOG(DEBUG) << __func__; + if (devices.size() > 1) { + LOG(ERROR) << __func__ << ": primary stream can only be connected to one device, got: " + << devices.size(); + return DeviceSwitchBehavior::UNSUPPORTED_DEVICES; + } + if (devices.empty() || useStubStream(devices[0]) == isStubStream()) { + return DeviceSwitchBehavior::USE_CURRENT_STREAM; + } + return DeviceSwitchBehavior::CREATE_NEW_STREAM; +} + +std::unique_ptr StreamInPrimary::createNewStream( + const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices, + StreamContext* context, const Metadata& metadata) { + if (devices.empty()) { + LOG(FATAL) << __func__ << ": called with empty devices"; // see 'switchCurrentStream' + } + if (useStubStream(devices[0])) { + return std::unique_ptr( + new InnerStreamWrapper(context, metadata)); + } + return std::unique_ptr( + new InnerStreamWrapper(context, metadata)); +} + +ndk::ScopedAStatus StreamInPrimary::getHwGain(std::vector* _aidl_return) { + if (isStubStream()) { + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); + } + return getHwGainImpl(_aidl_return); +} + +ndk::ScopedAStatus StreamInPrimary::setHwGain(const std::vector& in_channelGains) { + if (isStubStream()) { + LOG(DEBUG) << __func__ << ": gains " << ::android::internal::ToString(in_channelGains); + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); + } + auto currentGains = mHwGains; + RETURN_STATUS_IF_ERROR(setHwGainImpl(in_channelGains)); + if (in_channelGains.size() < 1) { + LOG(FATAL) << __func__ << ": unexpected gain vector size: " << in_channelGains.size(); + } + if (auto status = primary::PrimaryMixer::getInstance().setMicGain(in_channelGains[0]); + !status.isOk()) { + mHwGains = currentGains; + return status; + } + return ndk::ScopedAStatus::ok(); +} + +StreamOutPrimary::StreamOutPrimary(StreamContext&& context, const SourceMetadata& sourceMetadata, + const std::optional& offloadInfo) + : StreamOut(std::move(context), offloadInfo), + StreamSwitcher(&mContextInstance, sourceMetadata), + StreamOutHwVolumeHelper(&mContextInstance) {} + +bool StreamOutPrimary::useStubStream(const AudioDevice& device) { + static const bool kSimulateOutput = + GetBoolProperty("ro.boot.audio.tinyalsa.ignore_output", false); + return kSimulateOutput || device.type.type == AudioDeviceType::OUT_TELEPHONY_TX || + device.type.connection == AudioDeviceDescription::CONNECTION_BUS; +} + +StreamSwitcher::DeviceSwitchBehavior StreamOutPrimary::switchCurrentStream( + const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) { + LOG(DEBUG) << __func__; + if (devices.size() > 1) { + LOG(ERROR) << __func__ << ": primary stream can only be connected to one device, got: " + << devices.size(); + return DeviceSwitchBehavior::UNSUPPORTED_DEVICES; + } + if (devices.empty() || useStubStream(devices[0]) == isStubStream()) { + return DeviceSwitchBehavior::USE_CURRENT_STREAM; + } + return DeviceSwitchBehavior::CREATE_NEW_STREAM; +} + +std::unique_ptr StreamOutPrimary::createNewStream( + const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices, + StreamContext* context, const Metadata& metadata) { + if (devices.empty()) { + LOG(FATAL) << __func__ << ": called with empty devices"; // see 'switchCurrentStream' + } + if (useStubStream(devices[0])) { + return std::unique_ptr( + new InnerStreamWrapper(context, metadata)); + } + return std::unique_ptr( + new InnerStreamWrapper(context, metadata)); +} + +ndk::ScopedAStatus StreamOutPrimary::getHwVolume(std::vector* _aidl_return) { + if (isStubStream()) { + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); + } + return getHwVolumeImpl(_aidl_return); +} + +ndk::ScopedAStatus StreamOutPrimary::setHwVolume(const std::vector& in_channelVolumes) { + if (isStubStream()) { + LOG(DEBUG) << __func__ << ": volumes " << ::android::internal::ToString(in_channelVolumes); + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); + } + auto currentVolumes = mHwVolumes; + RETURN_STATUS_IF_ERROR(setHwVolumeImpl(in_channelVolumes)); + if (auto status = primary::PrimaryMixer::getInstance().setVolumes(in_channelVolumes); + !status.isOk()) { + mHwVolumes = currentVolumes; + return status; + } + return ndk::ScopedAStatus::ok(); +} + +} // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/stub/StreamStub.cpp b/audio/aidl/default/stub/StreamStub.cpp index 9b6a759c65..660a51e2e0 100644 --- a/audio/aidl/default/stub/StreamStub.cpp +++ b/audio/aidl/default/stub/StreamStub.cpp @@ -33,6 +33,7 @@ namespace aidl::android::hardware::audio::core { StreamStub::StreamStub(StreamContext* context, const Metadata& metadata) : StreamCommonImpl(context, metadata), + mBufferSizeFrames(getContext().getBufferSizeInFrames()), mFrameSizeBytes(getContext().getFrameSize()), mSampleRate(getContext().getSampleRate()), mIsAsynchronous(!!getContext().getAsyncCallback()), @@ -40,7 +41,6 @@ StreamStub::StreamStub(StreamContext* context, const Metadata& metadata) ::android::status_t StreamStub::init() { mIsInitialized = true; - usleep(500); return ::android::OK; } @@ -48,7 +48,16 @@ StreamStub::StreamStub(StreamContext* context, const Metadata& metadata) if (!mIsInitialized) { LOG(FATAL) << __func__ << ": must not happen for an uninitialized driver"; } - usleep(500); + if (!mIsInput) { + if (!mIsAsynchronous) { + static constexpr float kMicrosPerSecond = MICROS_PER_SECOND; + const size_t delayUs = static_cast( + std::roundf(mBufferSizeFrames * kMicrosPerSecond / mSampleRate)); + usleep(delayUs); + } else { + usleep(500); + } + } return ::android::OK; } @@ -56,7 +65,6 @@ StreamStub::StreamStub(StreamContext* context, const Metadata& metadata) if (!mIsInitialized) { LOG(FATAL) << __func__ << ": must not happen for an uninitialized driver"; } - usleep(500); return ::android::OK; } @@ -64,7 +72,6 @@ StreamStub::StreamStub(StreamContext* context, const Metadata& metadata) if (!mIsInitialized) { LOG(FATAL) << __func__ << ": must not happen for an uninitialized driver"; } - usleep(500); return ::android::OK; } diff --git a/audio/aidl/default/usb/StreamUsb.cpp b/audio/aidl/default/usb/StreamUsb.cpp index 4efe0d8b42..b60b4fd020 100644 --- a/audio/aidl/default/usb/StreamUsb.cpp +++ b/audio/aidl/default/usb/StreamUsb.cpp @@ -18,14 +18,11 @@ #define LOG_TAG "AHAL_StreamUsb" #include - -#include #include #include "UsbAlsaMixerControl.h" #include "core-impl/StreamUsb.h" -using aidl::android::hardware::audio::common::getChannelCount; using aidl::android::hardware::audio::common::SinkMetadata; using aidl::android::hardware::audio::common::SourceMetadata; using aidl::android::media::audio::common::AudioDevice; @@ -97,14 +94,15 @@ StreamOutUsb::StreamOutUsb(StreamContext&& context, const SourceMetadata& source const std::optional& offloadInfo) : StreamOut(std::move(context), offloadInfo), StreamUsb(&mContextInstance, sourceMetadata), - mChannelCount(getChannelCount(getContext().getChannelLayout())) {} + StreamOutHwVolumeHelper(&mContextInstance) {} ndk::ScopedAStatus StreamOutUsb::getHwVolume(std::vector* _aidl_return) { - *_aidl_return = mHwVolumes; - return ndk::ScopedAStatus::ok(); + return getHwVolumeImpl(_aidl_return); } ndk::ScopedAStatus StreamOutUsb::setHwVolume(const std::vector& in_channelVolumes) { + auto currentVolumes = mHwVolumes; + RETURN_STATUS_IF_ERROR(setHwVolumeImpl(in_channelVolumes)); // Avoid using mConnectedDeviceProfiles because it requires a lock. for (const auto& device : getConnectedDevices()) { if (auto deviceProfile = alsa::getDeviceProfile(device, mIsInput); @@ -114,11 +112,11 @@ ndk::ScopedAStatus StreamOutUsb::setHwVolume(const std::vector& in_channe !result.isOk()) { LOG(ERROR) << __func__ << ": failed to set volume for device address=" << *deviceProfile; + mHwVolumes = currentVolumes; return result; } } } - mHwVolumes = in_channelVolumes; return ndk::ScopedAStatus::ok(); } diff --git a/audio/aidl/vts/Android.bp b/audio/aidl/vts/Android.bp index 852255d433..f7cf4cece3 100644 --- a/audio/aidl/vts/Android.bp +++ b/audio/aidl/vts/Android.bp @@ -55,6 +55,7 @@ cc_test { "VtsHalAudioCoreConfigTargetTest.cpp", "VtsHalAudioCoreModuleTargetTest.cpp", ], + test_config: "VtsHalAudioCoreTargetTest.xml", } cc_test { diff --git a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp index a2e2ef7606..6ad130e728 100644 --- a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp +++ b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp @@ -3189,10 +3189,17 @@ class StreamLogicDefaultDriver : public StreamLogicDriver { std::string mUnexpectedTransition; }; -enum { NAMED_CMD_NAME, NAMED_CMD_DELAY_MS, NAMED_CMD_STREAM_TYPE, NAMED_CMD_CMDS }; +enum { + NAMED_CMD_NAME, + NAMED_CMD_DELAY_MS, + NAMED_CMD_STREAM_TYPE, + NAMED_CMD_CMDS, + NAMED_CMD_VALIDATE_POS_INCREASE +}; enum class StreamTypeFilter { ANY, SYNC, ASYNC }; using NamedCommandSequence = - std::tuple>; + std::tuple, bool /*validatePositionIncrease*/>; enum { PARAM_MODULE_NAME, PARAM_CMD_SEQ, PARAM_SETUP_SEQ }; using StreamIoTestParameters = std::tuple; @@ -3236,10 +3243,14 @@ class AudioStreamIo : public AudioCoreModuleBase, ASSERT_NO_FATAL_FAILURE(delayTransientStates.SetUp(module.get())); const auto& commandsAndStates = std::get(std::get(GetParam())); + const bool validatePositionIncrease = + std::get(std::get(GetParam())); if (!std::get(GetParam())) { - ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq1(portConfig, commandsAndStates)); + ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq1(portConfig, commandsAndStates, + validatePositionIncrease)); } else { - ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq2(portConfig, commandsAndStates)); + ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq2(portConfig, commandsAndStates, + validatePositionIncrease)); } if (isNonBlocking) { // Also try running the same sequence with "aosp.forceTransientBurst" set. @@ -3250,11 +3261,11 @@ class AudioStreamIo : public AudioCoreModuleBase, if (forceTransientBurst.SetUpNoChecks(module.get(), true /*failureExpected*/) .isOk()) { if (!std::get(GetParam())) { - ASSERT_NO_FATAL_FAILURE( - RunStreamIoCommandsImplSeq1(portConfig, commandsAndStates)); + ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq1( + portConfig, commandsAndStates, validatePositionIncrease)); } else { - ASSERT_NO_FATAL_FAILURE( - RunStreamIoCommandsImplSeq2(portConfig, commandsAndStates)); + ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq2( + portConfig, commandsAndStates, validatePositionIncrease)); } } } else if (!IOTraits::is_input) { @@ -3267,11 +3278,11 @@ class AudioStreamIo : public AudioCoreModuleBase, if (forceSynchronousDrain.SetUpNoChecks(module.get(), true /*failureExpected*/) .isOk()) { if (!std::get(GetParam())) { - ASSERT_NO_FATAL_FAILURE( - RunStreamIoCommandsImplSeq1(portConfig, commandsAndStates)); + ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq1( + portConfig, commandsAndStates, validatePositionIncrease)); } else { - ASSERT_NO_FATAL_FAILURE( - RunStreamIoCommandsImplSeq2(portConfig, commandsAndStates)); + ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq2( + portConfig, commandsAndStates, validatePositionIncrease)); } } } @@ -3285,11 +3296,13 @@ class AudioStreamIo : public AudioCoreModuleBase, // Set up a patch first, then open a stream. void RunStreamIoCommandsImplSeq1(const AudioPortConfig& portConfig, - std::shared_ptr commandsAndStates) { + std::shared_ptr commandsAndStates, + bool validatePositionIncrease) { auto devicePorts = moduleConfig->getAttachedDevicesPortsForMixPort( IOTraits::is_input, portConfig); ASSERT_FALSE(devicePorts.empty()); auto devicePortConfig = moduleConfig->getSingleConfigForDevicePort(devicePorts[0]); + SCOPED_TRACE(devicePortConfig.toString()); WithAudioPatch patch(IOTraits::is_input, portConfig, devicePortConfig); ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get())); @@ -3307,14 +3320,17 @@ class AudioStreamIo : public AudioCoreModuleBase, EXPECT_FALSE(worker.hasError()) << worker.getError(); EXPECT_EQ("", driver.getUnexpectedStateTransition()); if (ValidateObservablePosition(devicePortConfig)) { - EXPECT_TRUE(driver.hasObservablePositionIncrease()); + if (validatePositionIncrease) { + EXPECT_TRUE(driver.hasObservablePositionIncrease()); + } EXPECT_FALSE(driver.hasRetrogradeObservablePosition()); } } // Open a stream, then set up a patch for it. void RunStreamIoCommandsImplSeq2(const AudioPortConfig& portConfig, - std::shared_ptr commandsAndStates) { + std::shared_ptr commandsAndStates, + bool validatePositionIncrease) { WithStream stream(portConfig); ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames)); StreamLogicDefaultDriver driver(commandsAndStates, @@ -3326,6 +3342,7 @@ class AudioStreamIo : public AudioCoreModuleBase, IOTraits::is_input, portConfig); ASSERT_FALSE(devicePorts.empty()); auto devicePortConfig = moduleConfig->getSingleConfigForDevicePort(devicePorts[0]); + SCOPED_TRACE(devicePortConfig.toString()); WithAudioPatch patch(IOTraits::is_input, stream.getPortConfig(), devicePortConfig); ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get())); @@ -3336,7 +3353,9 @@ class AudioStreamIo : public AudioCoreModuleBase, EXPECT_FALSE(worker.hasError()) << worker.getError(); EXPECT_EQ("", driver.getUnexpectedStateTransition()); if (ValidateObservablePosition(devicePortConfig)) { - EXPECT_TRUE(driver.hasObservablePositionIncrease()); + if (validatePositionIncrease) { + EXPECT_TRUE(driver.hasObservablePositionIncrease()); + } EXPECT_FALSE(driver.hasRetrogradeObservablePosition()); } } @@ -3668,22 +3687,28 @@ std::shared_ptr makeBurstCommands(bool isSync) { using State = StreamDescriptor::State; auto d = std::make_unique(); StateDag::Node last = d->makeFinalNode(State::ACTIVE); - StateDag::Node active = d->makeNode(State::ACTIVE, kBurstCommand, last); + // Use a couple of bursts to ensure that the driver starts reporting the position. + StateDag::Node active2 = d->makeNode(State::ACTIVE, kBurstCommand, last); + StateDag::Node active = d->makeNode(State::ACTIVE, kBurstCommand, active2); StateDag::Node idle = d->makeNode(State::IDLE, kBurstCommand, active); if (!isSync) { // Allow optional routing via the TRANSFERRING state on bursts. - active.children().push_back(d->makeNode(State::TRANSFERRING, kTransferReadyEvent, last)); + active2.children().push_back(d->makeNode(State::TRANSFERRING, kTransferReadyEvent, last)); + active.children().push_back(d->makeNode(State::TRANSFERRING, kTransferReadyEvent, active2)); idle.children().push_back(d->makeNode(State::TRANSFERRING, kTransferReadyEvent, active)); } d->makeNode(State::STANDBY, kStartCommand, idle); return std::make_shared(std::move(d)); } static const NamedCommandSequence kReadSeq = - std::make_tuple(std::string("Read"), 0, StreamTypeFilter::ANY, makeBurstCommands(true)); + std::make_tuple(std::string("Read"), 0, StreamTypeFilter::ANY, makeBurstCommands(true), + true /*validatePositionIncrease*/); static const NamedCommandSequence kWriteSyncSeq = - std::make_tuple(std::string("Write"), 0, StreamTypeFilter::SYNC, makeBurstCommands(true)); + std::make_tuple(std::string("Write"), 0, StreamTypeFilter::SYNC, makeBurstCommands(true), + true /*validatePositionIncrease*/); static const NamedCommandSequence kWriteAsyncSeq = - std::make_tuple(std::string("Write"), 0, StreamTypeFilter::ASYNC, makeBurstCommands(false)); + std::make_tuple(std::string("Write"), 0, StreamTypeFilter::ASYNC, makeBurstCommands(false), + true /*validatePositionIncrease*/); std::shared_ptr makeAsyncDrainCommands(bool isInput) { using State = StreamDescriptor::State; @@ -3711,11 +3736,12 @@ std::shared_ptr makeAsyncDrainCommands(bool isInput) { } return std::make_shared(std::move(d)); } -static const NamedCommandSequence kWriteDrainAsyncSeq = - std::make_tuple(std::string("WriteDrain"), kStreamTransientStateTransitionDelayMs, - StreamTypeFilter::ASYNC, makeAsyncDrainCommands(false)); -static const NamedCommandSequence kDrainInSeq = std::make_tuple( - std::string("Drain"), 0, StreamTypeFilter::ANY, makeAsyncDrainCommands(true)); +static const NamedCommandSequence kWriteDrainAsyncSeq = std::make_tuple( + std::string("WriteDrain"), kStreamTransientStateTransitionDelayMs, StreamTypeFilter::ASYNC, + makeAsyncDrainCommands(false), false /*validatePositionIncrease*/); +static const NamedCommandSequence kDrainInSeq = + std::make_tuple(std::string("Drain"), 0, StreamTypeFilter::ANY, + makeAsyncDrainCommands(true), false /*validatePositionIncrease*/); std::shared_ptr makeDrainOutCommands(bool isSync) { using State = StreamDescriptor::State; @@ -3735,10 +3761,12 @@ std::shared_ptr makeDrainOutCommands(bool isSync) { d->makeNode(State::STANDBY, kStartCommand, idle); return std::make_shared(std::move(d)); } -static const NamedCommandSequence kDrainOutSyncSeq = std::make_tuple( - std::string("Drain"), 0, StreamTypeFilter::SYNC, makeDrainOutCommands(true)); -static const NamedCommandSequence kDrainOutAsyncSeq = std::make_tuple( - std::string("Drain"), 0, StreamTypeFilter::ASYNC, makeDrainOutCommands(false)); +static const NamedCommandSequence kDrainOutSyncSeq = + std::make_tuple(std::string("Drain"), 0, StreamTypeFilter::SYNC, makeDrainOutCommands(true), + false /*validatePositionIncrease*/); +static const NamedCommandSequence kDrainOutAsyncSeq = + std::make_tuple(std::string("Drain"), 0, StreamTypeFilter::ASYNC, + makeDrainOutCommands(false), false /*validatePositionIncrease*/); std::shared_ptr makeDrainPauseOutCommands(bool isSync) { using State = StreamDescriptor::State; @@ -3759,12 +3787,12 @@ std::shared_ptr makeDrainPauseOutCommands(bool isSync) { d->makeNode(State::STANDBY, kStartCommand, idle); return std::make_shared(std::move(d)); } -static const NamedCommandSequence kDrainPauseOutSyncSeq = - std::make_tuple(std::string("DrainPause"), kStreamTransientStateTransitionDelayMs, - StreamTypeFilter::SYNC, makeDrainPauseOutCommands(true)); -static const NamedCommandSequence kDrainPauseOutAsyncSeq = - std::make_tuple(std::string("DrainPause"), kStreamTransientStateTransitionDelayMs, - StreamTypeFilter::ASYNC, makeDrainPauseOutCommands(false)); +static const NamedCommandSequence kDrainPauseOutSyncSeq = std::make_tuple( + std::string("DrainPause"), kStreamTransientStateTransitionDelayMs, StreamTypeFilter::SYNC, + makeDrainPauseOutCommands(true), false /*validatePositionIncrease*/); +static const NamedCommandSequence kDrainPauseOutAsyncSeq = std::make_tuple( + std::string("DrainPause"), kStreamTransientStateTransitionDelayMs, StreamTypeFilter::ASYNC, + makeDrainPauseOutCommands(false), false /*validatePositionIncrease*/); // This sequence also verifies that the capture / presentation position is not reset on standby. std::shared_ptr makeStandbyCommands(bool isInput, bool isSync) { @@ -3805,13 +3833,15 @@ std::shared_ptr makeStandbyCommands(bool isInput, bool isSync) { } return std::make_shared(std::move(d)); } -static const NamedCommandSequence kStandbyInSeq = std::make_tuple( - std::string("Standby"), 0, StreamTypeFilter::ANY, makeStandbyCommands(true, false)); -static const NamedCommandSequence kStandbyOutSyncSeq = std::make_tuple( - std::string("Standby"), 0, StreamTypeFilter::SYNC, makeStandbyCommands(false, true)); -static const NamedCommandSequence kStandbyOutAsyncSeq = - std::make_tuple(std::string("Standby"), kStreamTransientStateTransitionDelayMs, - StreamTypeFilter::ASYNC, makeStandbyCommands(false, false)); +static const NamedCommandSequence kStandbyInSeq = + std::make_tuple(std::string("Standby"), 0, StreamTypeFilter::ANY, + makeStandbyCommands(true, false), false /*validatePositionIncrease*/); +static const NamedCommandSequence kStandbyOutSyncSeq = + std::make_tuple(std::string("Standby"), 0, StreamTypeFilter::SYNC, + makeStandbyCommands(false, true), false /*validatePositionIncrease*/); +static const NamedCommandSequence kStandbyOutAsyncSeq = std::make_tuple( + std::string("Standby"), kStreamTransientStateTransitionDelayMs, StreamTypeFilter::ASYNC, + makeStandbyCommands(false, false), false /*validatePositionIncrease*/); std::shared_ptr makePauseCommands(bool isInput, bool isSync) { using State = StreamDescriptor::State; @@ -3846,13 +3876,15 @@ std::shared_ptr makePauseCommands(bool isInput, bool isSync) { } return std::make_shared(std::move(d)); } -static const NamedCommandSequence kPauseInSeq = std::make_tuple( - std::string("Pause"), 0, StreamTypeFilter::ANY, makePauseCommands(true, false)); -static const NamedCommandSequence kPauseOutSyncSeq = std::make_tuple( - std::string("Pause"), 0, StreamTypeFilter::SYNC, makePauseCommands(false, true)); -static const NamedCommandSequence kPauseOutAsyncSeq = - std::make_tuple(std::string("Pause"), kStreamTransientStateTransitionDelayMs, - StreamTypeFilter::ASYNC, makePauseCommands(false, false)); +static const NamedCommandSequence kPauseInSeq = + std::make_tuple(std::string("Pause"), 0, StreamTypeFilter::ANY, + makePauseCommands(true, false), false /*validatePositionIncrease*/); +static const NamedCommandSequence kPauseOutSyncSeq = + std::make_tuple(std::string("Pause"), 0, StreamTypeFilter::SYNC, + makePauseCommands(false, true), false /*validatePositionIncrease*/); +static const NamedCommandSequence kPauseOutAsyncSeq = std::make_tuple( + std::string("Pause"), kStreamTransientStateTransitionDelayMs, StreamTypeFilter::ASYNC, + makePauseCommands(false, false), false /*validatePositionIncrease*/); std::shared_ptr makeFlushCommands(bool isInput, bool isSync) { using State = StreamDescriptor::State; @@ -3879,13 +3911,15 @@ std::shared_ptr makeFlushCommands(bool isInput, bool isSync) { } return std::make_shared(std::move(d)); } -static const NamedCommandSequence kFlushInSeq = std::make_tuple( - std::string("Flush"), 0, StreamTypeFilter::ANY, makeFlushCommands(true, false)); -static const NamedCommandSequence kFlushOutSyncSeq = std::make_tuple( - std::string("Flush"), 0, StreamTypeFilter::SYNC, makeFlushCommands(false, true)); -static const NamedCommandSequence kFlushOutAsyncSeq = - std::make_tuple(std::string("Flush"), kStreamTransientStateTransitionDelayMs, - StreamTypeFilter::ASYNC, makeFlushCommands(false, false)); +static const NamedCommandSequence kFlushInSeq = + std::make_tuple(std::string("Flush"), 0, StreamTypeFilter::ANY, + makeFlushCommands(true, false), false /*validatePositionIncrease*/); +static const NamedCommandSequence kFlushOutSyncSeq = + std::make_tuple(std::string("Flush"), 0, StreamTypeFilter::SYNC, + makeFlushCommands(false, true), false /*validatePositionIncrease*/); +static const NamedCommandSequence kFlushOutAsyncSeq = std::make_tuple( + std::string("Flush"), kStreamTransientStateTransitionDelayMs, StreamTypeFilter::ASYNC, + makeFlushCommands(false, false), false /*validatePositionIncrease*/); std::shared_ptr makeDrainPauseFlushOutCommands(bool isSync) { using State = StreamDescriptor::State; @@ -3906,10 +3940,12 @@ std::shared_ptr makeDrainPauseFlushOutCommands(bool isSync) { } static const NamedCommandSequence kDrainPauseFlushOutSyncSeq = std::make_tuple(std::string("DrainPauseFlush"), kStreamTransientStateTransitionDelayMs, - StreamTypeFilter::SYNC, makeDrainPauseFlushOutCommands(true)); + StreamTypeFilter::SYNC, makeDrainPauseFlushOutCommands(true), + false /*validatePositionIncrease*/); static const NamedCommandSequence kDrainPauseFlushOutAsyncSeq = std::make_tuple(std::string("DrainPauseFlush"), kStreamTransientStateTransitionDelayMs, - StreamTypeFilter::ASYNC, makeDrainPauseFlushOutCommands(false)); + StreamTypeFilter::ASYNC, makeDrainPauseFlushOutCommands(false), + false /*validatePositionIncrease*/); // Note, this isn't the "official" enum printer, it is only used to make the test name suffix. std::string PrintStreamFilterToString(StreamTypeFilter filter) { diff --git a/audio/aidl/vts/VtsHalAudioCoreTargetTest.xml b/audio/aidl/vts/VtsHalAudioCoreTargetTest.xml index dfc10397f7..9d3adc1d0f 100644 --- a/audio/aidl/vts/VtsHalAudioCoreTargetTest.xml +++ b/audio/aidl/vts/VtsHalAudioCoreTargetTest.xml @@ -25,6 +25,11 @@