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
This commit is contained in:
parent
e8d695d9b2
commit
cf824f65c8
20 changed files with 637 additions and 172 deletions
|
@ -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",
|
||||
|
|
|
@ -136,7 +136,7 @@ static AudioRoute createRoute(const std::vector<AudioPort>& 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<AudioPort>& 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<Configuration> getPrimaryConfiguration() {
|
||||
static const Configuration configuration = []() {
|
||||
const std::vector<AudioProfile> 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<Configuration> 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<Configuration> 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<Configuration> 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<Configuration> 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<Configuration> 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<Configuration> 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<Configuration> 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<Configuration> 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<Configuration> 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<Configuration> 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<Configuration> 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<Configuration> 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<Configuration> 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;
|
||||
}();
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#include <android-base/logging.h>
|
||||
|
||||
#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<MicrophoneInfo>& microphones,
|
||||
std::shared_ptr<StreamIn>* result) {
|
||||
return createStreamInstance<StreamInStub>(result, std::move(context), sinkMetadata,
|
||||
microphones);
|
||||
return createStreamInstance<StreamInPrimary>(result, std::move(context), sinkMetadata,
|
||||
microphones);
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus ModulePrimary::createOutputStream(
|
||||
StreamContext&& context, const SourceMetadata& sourceMetadata,
|
||||
const std::optional<AudioOffloadInfo>& offloadInfo, std::shared_ptr<StreamOut>* result) {
|
||||
return createStreamInstance<StreamOutStub>(result, std::move(context), sourceMetadata,
|
||||
offloadInfo);
|
||||
return createStreamInstance<StreamOutPrimary>(result, std::move(context), sourceMetadata,
|
||||
offloadInfo);
|
||||
}
|
||||
|
||||
} // namespace aidl::android::hardware::audio::core
|
||||
|
|
|
@ -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<float>& in_channelGains
|
|||
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
|
||||
}
|
||||
|
||||
StreamInHwGainHelper::StreamInHwGainHelper(const StreamContext* context)
|
||||
: mChannelCount(getChannelCount(context->getChannelLayout())) {}
|
||||
|
||||
ndk::ScopedAStatus StreamInHwGainHelper::getHwGainImpl(std::vector<float>* _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<float>& 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<AudioOffloadInfo>& 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<float>* _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<float>& 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
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
|
||||
#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<size_t>(
|
||||
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<struct pcm_config*>(&mConfig.value()),
|
||||
getContext().getBufferSizeInFrames());
|
||||
device, const_cast<struct pcm_config*>(&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);
|
||||
|
|
|
@ -262,12 +262,14 @@ std::vector<int> 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<alsa_device_profile> 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());
|
||||
}
|
||||
|
|
|
@ -66,6 +66,7 @@ DeviceProxy openProxyForAttachedDevice(const DeviceProfile& deviceProfile,
|
|||
DeviceProxy openProxyForExternalDevice(const DeviceProfile& deviceProfile,
|
||||
struct pcm_config* pcmConfig, bool requireExactMatch);
|
||||
std::optional<alsa_device_profile> 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);
|
||||
|
|
|
@ -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<float>* _aidl_return);
|
||||
ndk::ScopedAStatus setHwGainImpl(const std::vector<float>& in_channelGains);
|
||||
|
||||
const size_t mChannelCount;
|
||||
std::vector<float> 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<float>* _aidl_return);
|
||||
ndk::ScopedAStatus setHwVolumeImpl(const std::vector<float>& in_channelVolumes);
|
||||
|
||||
const size_t mChannelCount;
|
||||
std::vector<float> 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'.
|
||||
|
|
|
@ -48,7 +48,9 @@ class StreamAlsa : public StreamCommonImpl {
|
|||
// Called from 'start' to initialize 'mAlsaDeviceProxies', the vector must be non-empty.
|
||||
virtual std::vector<alsa::DeviceProfile> getDeviceProfiles() = 0;
|
||||
|
||||
const size_t mBufferSizeFrames;
|
||||
const size_t mFrameSizeBytes;
|
||||
const int mSampleRate;
|
||||
const bool mIsInput;
|
||||
const std::optional<struct pcm_config> mConfig;
|
||||
const int mReadWriteRetries;
|
||||
|
|
84
audio/aidl/default/include/core-impl/StreamPrimary.h
Normal file
84
audio/aidl/default/include/core-impl/StreamPrimary.h
Normal file
|
@ -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 <vector>
|
||||
|
||||
#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<alsa::DeviceProfile> 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<StreamCommonInterfaceEx> 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<float>* _aidl_return) override;
|
||||
ndk::ScopedAStatus setHwGain(const std::vector<float>& 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<StreamCommonInterfaceEx> 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<float>* _aidl_return) override;
|
||||
ndk::ScopedAStatus setHwVolume(const std::vector<float>& in_channelVolumes) override;
|
||||
};
|
||||
|
||||
} // namespace aidl::android::hardware::audio::core
|
|
@ -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;
|
||||
|
|
|
@ -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<float>* _aidl_return) override;
|
||||
ndk::ScopedAStatus setHwVolume(const std::vector<float>& in_channelVolumes) override;
|
||||
|
||||
const int mChannelCount;
|
||||
std::vector<float> mHwVolumes;
|
||||
};
|
||||
|
||||
} // namespace aidl::android::hardware::audio::core
|
||||
|
|
29
audio/aidl/default/primary/PrimaryMixer.cpp
Normal file
29
audio/aidl/default/primary/PrimaryMixer.cpp
Normal file
|
@ -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
|
42
audio/aidl/default/primary/PrimaryMixer.h
Normal file
42
audio/aidl/default/primary/PrimaryMixer.h
Normal 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
#include <android-base/thread_annotations.h>
|
||||
#include <android/binder_auto_utils.h>
|
||||
|
||||
#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
|
186
audio/aidl/default/primary/StreamPrimary.cpp
Normal file
186
audio/aidl/default/primary/StreamPrimary.cpp
Normal file
|
@ -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 <limits>
|
||||
|
||||
#define LOG_TAG "AHAL_StreamPrimary"
|
||||
#include <android-base/logging.h>
|
||||
#include <android-base/properties.h>
|
||||
#include <error/expected_utils.h>
|
||||
|
||||
#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<alsa::DeviceProfile> StreamPrimary::getDeviceProfiles() {
|
||||
static const std::vector<alsa::DeviceProfile> kBuiltInSource{
|
||||
alsa::DeviceProfile{.card = primary::PrimaryMixer::kAlsaCard,
|
||||
.device = primary::PrimaryMixer::kAlsaDevice,
|
||||
.direction = PCM_IN,
|
||||
.isExternal = false}};
|
||||
static const std::vector<alsa::DeviceProfile> 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<MicrophoneInfo>& 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<StreamCommonInterfaceEx> 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<StreamCommonInterfaceEx>(
|
||||
new InnerStreamWrapper<StreamStub>(context, metadata));
|
||||
}
|
||||
return std::unique_ptr<StreamCommonInterfaceEx>(
|
||||
new InnerStreamWrapper<StreamPrimary>(context, metadata));
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus StreamInPrimary::getHwGain(std::vector<float>* _aidl_return) {
|
||||
if (isStubStream()) {
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
|
||||
}
|
||||
return getHwGainImpl(_aidl_return);
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus StreamInPrimary::setHwGain(const std::vector<float>& 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<AudioOffloadInfo>& 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<StreamCommonInterfaceEx> 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<StreamCommonInterfaceEx>(
|
||||
new InnerStreamWrapper<StreamStub>(context, metadata));
|
||||
}
|
||||
return std::unique_ptr<StreamCommonInterfaceEx>(
|
||||
new InnerStreamWrapper<StreamPrimary>(context, metadata));
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus StreamOutPrimary::getHwVolume(std::vector<float>* _aidl_return) {
|
||||
if (isStubStream()) {
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
|
||||
}
|
||||
return getHwVolumeImpl(_aidl_return);
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus StreamOutPrimary::setHwVolume(const std::vector<float>& 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
|
|
@ -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<size_t>(
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -18,14 +18,11 @@
|
|||
|
||||
#define LOG_TAG "AHAL_StreamUsb"
|
||||
#include <android-base/logging.h>
|
||||
|
||||
#include <Utils.h>
|
||||
#include <error/expected_utils.h>
|
||||
|
||||
#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<AudioOffloadInfo>& offloadInfo)
|
||||
: StreamOut(std::move(context), offloadInfo),
|
||||
StreamUsb(&mContextInstance, sourceMetadata),
|
||||
mChannelCount(getChannelCount(getContext().getChannelLayout())) {}
|
||||
StreamOutHwVolumeHelper(&mContextInstance) {}
|
||||
|
||||
ndk::ScopedAStatus StreamOutUsb::getHwVolume(std::vector<float>* _aidl_return) {
|
||||
*_aidl_return = mHwVolumes;
|
||||
return ndk::ScopedAStatus::ok();
|
||||
return getHwVolumeImpl(_aidl_return);
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus StreamOutUsb::setHwVolume(const std::vector<float>& 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<float>& 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();
|
||||
}
|
||||
|
||||
|
|
|
@ -55,6 +55,7 @@ cc_test {
|
|||
"VtsHalAudioCoreConfigTargetTest.cpp",
|
||||
"VtsHalAudioCoreModuleTargetTest.cpp",
|
||||
],
|
||||
test_config: "VtsHalAudioCoreTargetTest.xml",
|
||||
}
|
||||
|
||||
cc_test {
|
||||
|
|
|
@ -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::string, int, StreamTypeFilter, std::shared_ptr<StateSequence>>;
|
||||
std::tuple<std::string, int /*cmdDelayMs*/, StreamTypeFilter,
|
||||
std::shared_ptr<StateSequence>, bool /*validatePositionIncrease*/>;
|
||||
enum { PARAM_MODULE_NAME, PARAM_CMD_SEQ, PARAM_SETUP_SEQ };
|
||||
using StreamIoTestParameters =
|
||||
std::tuple<std::string /*moduleName*/, NamedCommandSequence, bool /*useSetupSequence2*/>;
|
||||
|
@ -3236,10 +3243,14 @@ class AudioStreamIo : public AudioCoreModuleBase,
|
|||
ASSERT_NO_FATAL_FAILURE(delayTransientStates.SetUp(module.get()));
|
||||
const auto& commandsAndStates =
|
||||
std::get<NAMED_CMD_CMDS>(std::get<PARAM_CMD_SEQ>(GetParam()));
|
||||
const bool validatePositionIncrease =
|
||||
std::get<NAMED_CMD_VALIDATE_POS_INCREASE>(std::get<PARAM_CMD_SEQ>(GetParam()));
|
||||
if (!std::get<PARAM_SETUP_SEQ>(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<PARAM_SETUP_SEQ>(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<Stream>::is_input) {
|
||||
|
@ -3267,11 +3278,11 @@ class AudioStreamIo : public AudioCoreModuleBase,
|
|||
if (forceSynchronousDrain.SetUpNoChecks(module.get(), true /*failureExpected*/)
|
||||
.isOk()) {
|
||||
if (!std::get<PARAM_SETUP_SEQ>(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<StateSequence> commandsAndStates) {
|
||||
std::shared_ptr<StateSequence> commandsAndStates,
|
||||
bool validatePositionIncrease) {
|
||||
auto devicePorts = moduleConfig->getAttachedDevicesPortsForMixPort(
|
||||
IOTraits<Stream>::is_input, portConfig);
|
||||
ASSERT_FALSE(devicePorts.empty());
|
||||
auto devicePortConfig = moduleConfig->getSingleConfigForDevicePort(devicePorts[0]);
|
||||
SCOPED_TRACE(devicePortConfig.toString());
|
||||
WithAudioPatch patch(IOTraits<Stream>::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<StateSequence> commandsAndStates) {
|
||||
std::shared_ptr<StateSequence> commandsAndStates,
|
||||
bool validatePositionIncrease) {
|
||||
WithStream<Stream> stream(portConfig);
|
||||
ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
|
||||
StreamLogicDefaultDriver driver(commandsAndStates,
|
||||
|
@ -3326,6 +3342,7 @@ class AudioStreamIo : public AudioCoreModuleBase,
|
|||
IOTraits<Stream>::is_input, portConfig);
|
||||
ASSERT_FALSE(devicePorts.empty());
|
||||
auto devicePortConfig = moduleConfig->getSingleConfigForDevicePort(devicePorts[0]);
|
||||
SCOPED_TRACE(devicePortConfig.toString());
|
||||
WithAudioPatch patch(IOTraits<Stream>::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<StateSequence> makeBurstCommands(bool isSync) {
|
|||
using State = StreamDescriptor::State;
|
||||
auto d = std::make_unique<StateDag>();
|
||||
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<StateSequenceFollower>(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<StateSequence> makeAsyncDrainCommands(bool isInput) {
|
||||
using State = StreamDescriptor::State;
|
||||
|
@ -3711,11 +3736,12 @@ std::shared_ptr<StateSequence> makeAsyncDrainCommands(bool isInput) {
|
|||
}
|
||||
return std::make_shared<StateSequenceFollower>(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<StateSequence> makeDrainOutCommands(bool isSync) {
|
||||
using State = StreamDescriptor::State;
|
||||
|
@ -3735,10 +3761,12 @@ std::shared_ptr<StateSequence> makeDrainOutCommands(bool isSync) {
|
|||
d->makeNode(State::STANDBY, kStartCommand, idle);
|
||||
return std::make_shared<StateSequenceFollower>(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<StateSequence> makeDrainPauseOutCommands(bool isSync) {
|
||||
using State = StreamDescriptor::State;
|
||||
|
@ -3759,12 +3787,12 @@ std::shared_ptr<StateSequence> makeDrainPauseOutCommands(bool isSync) {
|
|||
d->makeNode(State::STANDBY, kStartCommand, idle);
|
||||
return std::make_shared<StateSequenceFollower>(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<StateSequence> makeStandbyCommands(bool isInput, bool isSync) {
|
||||
|
@ -3805,13 +3833,15 @@ std::shared_ptr<StateSequence> makeStandbyCommands(bool isInput, bool isSync) {
|
|||
}
|
||||
return std::make_shared<StateSequenceFollower>(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<StateSequence> makePauseCommands(bool isInput, bool isSync) {
|
||||
using State = StreamDescriptor::State;
|
||||
|
@ -3846,13 +3876,15 @@ std::shared_ptr<StateSequence> makePauseCommands(bool isInput, bool isSync) {
|
|||
}
|
||||
return std::make_shared<StateSequenceFollower>(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<StateSequence> makeFlushCommands(bool isInput, bool isSync) {
|
||||
using State = StreamDescriptor::State;
|
||||
|
@ -3879,13 +3911,15 @@ std::shared_ptr<StateSequence> makeFlushCommands(bool isInput, bool isSync) {
|
|||
}
|
||||
return std::make_shared<StateSequenceFollower>(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<StateSequence> makeDrainPauseFlushOutCommands(bool isSync) {
|
||||
using State = StreamDescriptor::State;
|
||||
|
@ -3906,10 +3940,12 @@ std::shared_ptr<StateSequence> 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) {
|
||||
|
|
|
@ -25,6 +25,11 @@
|
|||
<option name="teardown-command" value="setprop vts.native_server.on 0"/>
|
||||
</target_preparer>
|
||||
|
||||
<target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
|
||||
<option name="cleanup" value="true" />
|
||||
<option name="push" value="VtsHalAudioCoreTargetTest->/data/local/tmp/VtsHalAudioCoreTargetTest" />
|
||||
</target_preparer>
|
||||
|
||||
<test class="com.android.tradefed.testtype.GTest" >
|
||||
<option name="native-test-device-path" value="/data/local/tmp" />
|
||||
<option name="module-name" value="VtsHalAudioCoreTargetTest" />
|
||||
|
|
Loading…
Reference in a new issue