Merge "audio: Implement the major functionality of the primary CF HAL" into main
This commit is contained in:
commit
ff1f1f3494
20 changed files with 637 additions and 172 deletions
|
@ -85,6 +85,8 @@ cc_library {
|
||||||
"bluetooth/DevicePortProxy.cpp",
|
"bluetooth/DevicePortProxy.cpp",
|
||||||
"bluetooth/ModuleBluetooth.cpp",
|
"bluetooth/ModuleBluetooth.cpp",
|
||||||
"bluetooth/StreamBluetooth.cpp",
|
"bluetooth/StreamBluetooth.cpp",
|
||||||
|
"primary/PrimaryMixer.cpp",
|
||||||
|
"primary/StreamPrimary.cpp",
|
||||||
"r_submix/ModuleRemoteSubmix.cpp",
|
"r_submix/ModuleRemoteSubmix.cpp",
|
||||||
"r_submix/RemoteSubmixUtils.cpp",
|
"r_submix/RemoteSubmixUtils.cpp",
|
||||||
"r_submix/SubmixRoute.cpp",
|
"r_submix/SubmixRoute.cpp",
|
||||||
|
|
|
@ -136,7 +136,7 @@ static AudioRoute createRoute(const std::vector<AudioPort>& sources, const Audio
|
||||||
// Device ports:
|
// Device ports:
|
||||||
// * "Speaker", OUT_SPEAKER, default
|
// * "Speaker", OUT_SPEAKER, default
|
||||||
// - no profiles specified
|
// - no profiles specified
|
||||||
// * "Built-in Mic", IN_MICROPHONE, default
|
// * "Built-In Mic", IN_MICROPHONE, default
|
||||||
// - no profiles specified
|
// - no profiles specified
|
||||||
// * "Telephony Tx", OUT_TELEPHONY_TX
|
// * "Telephony Tx", OUT_TELEPHONY_TX
|
||||||
// - no profiles specified
|
// - no profiles specified
|
||||||
|
@ -148,45 +148,34 @@ static AudioRoute createRoute(const std::vector<AudioPort>& sources, const Audio
|
||||||
// Mix ports:
|
// Mix ports:
|
||||||
// * "primary output", PRIMARY, 1 max open, 1 max active stream
|
// * "primary output", PRIMARY, 1 max open, 1 max active stream
|
||||||
// - profile PCM 16-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
|
// - profile PCM 16-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
|
||||||
// - profile PCM 24-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
|
// * "primary input", 1 max open, 1 max active stream
|
||||||
// * "compressed offload", DIRECT|COMPRESS_OFFLOAD|NON_BLOCKING, 1 max open, 1 max active stream
|
// - profile PCM 16-bit; MONO, STEREO;
|
||||||
// - profile MP3; MONO, STEREO; 44100, 48000
|
// 8000, 11025, 16000, 32000, 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
|
|
||||||
// * "telephony_tx", 1 max open, 1 max active stream
|
// * "telephony_tx", 1 max open, 1 max active stream
|
||||||
// - profile PCM 16-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
|
// - 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
|
// * "telephony_rx", 1 max open, 1 max active stream
|
||||||
// - profile PCM 16-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
|
// - 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
|
// * "fm_tuner", 1 max open, 1 max active stream
|
||||||
// - profile PCM 16-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
|
// - 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:
|
// Routes:
|
||||||
// "primary out", "compressed offload" -> "Speaker"
|
// "primary out" -> "Speaker"
|
||||||
// "Built-in Mic" -> "primary input"
|
// "Built-In Mic" -> "primary input"
|
||||||
// "telephony_tx" -> "Telephony Tx"
|
|
||||||
// "Telephony Rx" -> "telephony_rx"
|
// "Telephony Rx" -> "telephony_rx"
|
||||||
|
// "telephony_tx" -> "Telephony Tx"
|
||||||
// "FM Tuner" -> "fm_tuner"
|
// "FM Tuner" -> "fm_tuner"
|
||||||
//
|
//
|
||||||
// Initial port configs:
|
// Initial port configs:
|
||||||
// * "Speaker" device port: PCM 24-bit; STEREO; 48000
|
// * "Speaker" device port: PCM 16-bit; STEREO; 48000
|
||||||
// * "Built-in Mic" device port: PCM 24-bit; MONO; 48000
|
// * "Built-In Mic" device port: PCM 16-bit; MONO; 48000
|
||||||
// * "Telephony Tx" device port: PCM 24-bit; MONO; 48000
|
// * "Telephony Tx" device port: PCM 16-bit; MONO; 48000
|
||||||
// * "Telephony Rx" device port: PCM 24-bit; MONO; 48000
|
// * "Telephony Rx" device port: PCM 16-bit; MONO; 48000
|
||||||
// * "FM Tuner" device port: PCM 24-bit; STEREO; 48000
|
// * "FM Tuner" device port: PCM 16-bit; STEREO; 48000
|
||||||
//
|
//
|
||||||
std::unique_ptr<Configuration> getPrimaryConfiguration() {
|
std::unique_ptr<Configuration> getPrimaryConfiguration() {
|
||||||
static const Configuration configuration = []() {
|
static const Configuration configuration = []() {
|
||||||
const std::vector<AudioProfile> standardPcmAudioProfiles = {
|
const std::vector<AudioProfile> standardPcmAudioProfiles = {
|
||||||
createProfile(PcmType::INT_16_BIT,
|
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},
|
{AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO},
|
||||||
{8000, 11025, 16000, 32000, 44100, 48000})};
|
{8000, 11025, 16000, 32000, 44100, 48000})};
|
||||||
Configuration c;
|
Configuration c;
|
||||||
|
@ -199,17 +188,17 @@ std::unique_ptr<Configuration> getPrimaryConfiguration() {
|
||||||
1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE));
|
1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE));
|
||||||
c.ports.push_back(speakerOutDevice);
|
c.ports.push_back(speakerOutDevice);
|
||||||
c.initialConfigs.push_back(
|
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,
|
AudioChannelLayout::LAYOUT_STEREO, 48000, 0, false,
|
||||||
createDeviceExt(AudioDeviceType::OUT_SPEAKER, 0)));
|
createDeviceExt(AudioDeviceType::OUT_SPEAKER, 0)));
|
||||||
|
|
||||||
AudioPort micInDevice =
|
AudioPort micInDevice =
|
||||||
createPort(c.nextPortId++, "Built-in Mic", 0, true,
|
createPort(c.nextPortId++, "Built-In Mic", 0, true,
|
||||||
createDeviceExt(AudioDeviceType::IN_MICROPHONE,
|
createDeviceExt(AudioDeviceType::IN_MICROPHONE,
|
||||||
1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE));
|
1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE));
|
||||||
c.ports.push_back(micInDevice);
|
c.ports.push_back(micInDevice);
|
||||||
c.initialConfigs.push_back(
|
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,
|
AudioChannelLayout::LAYOUT_MONO, 48000, 0, true,
|
||||||
createDeviceExt(AudioDeviceType::IN_MICROPHONE, 0)));
|
createDeviceExt(AudioDeviceType::IN_MICROPHONE, 0)));
|
||||||
|
|
||||||
|
@ -219,7 +208,7 @@ std::unique_ptr<Configuration> getPrimaryConfiguration() {
|
||||||
c.ports.push_back(telephonyTxOutDevice);
|
c.ports.push_back(telephonyTxOutDevice);
|
||||||
c.initialConfigs.push_back(
|
c.initialConfigs.push_back(
|
||||||
createPortConfig(telephonyTxOutDevice.id, telephonyTxOutDevice.id,
|
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)));
|
false, createDeviceExt(AudioDeviceType::OUT_TELEPHONY_TX, 0)));
|
||||||
|
|
||||||
AudioPort telephonyRxInDevice =
|
AudioPort telephonyRxInDevice =
|
||||||
|
@ -228,14 +217,14 @@ std::unique_ptr<Configuration> getPrimaryConfiguration() {
|
||||||
c.ports.push_back(telephonyRxInDevice);
|
c.ports.push_back(telephonyRxInDevice);
|
||||||
c.initialConfigs.push_back(
|
c.initialConfigs.push_back(
|
||||||
createPortConfig(telephonyRxInDevice.id, telephonyRxInDevice.id,
|
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)));
|
true, createDeviceExt(AudioDeviceType::IN_TELEPHONY_RX, 0)));
|
||||||
|
|
||||||
AudioPort fmTunerInDevice = createPort(c.nextPortId++, "FM Tuner", 0, true,
|
AudioPort fmTunerInDevice = createPort(c.nextPortId++, "FM Tuner", 0, true,
|
||||||
createDeviceExt(AudioDeviceType::IN_FM_TUNER, 0));
|
createDeviceExt(AudioDeviceType::IN_FM_TUNER, 0));
|
||||||
c.ports.push_back(fmTunerInDevice);
|
c.ports.push_back(fmTunerInDevice);
|
||||||
c.initialConfigs.push_back(
|
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,
|
AudioChannelLayout::LAYOUT_STEREO, 48000, 0, true,
|
||||||
createDeviceExt(AudioDeviceType::IN_FM_TUNER, 0)));
|
createDeviceExt(AudioDeviceType::IN_FM_TUNER, 0)));
|
||||||
|
|
||||||
|
@ -249,30 +238,12 @@ std::unique_ptr<Configuration> getPrimaryConfiguration() {
|
||||||
standardPcmAudioProfiles.end());
|
standardPcmAudioProfiles.end());
|
||||||
c.ports.push_back(primaryOutMix);
|
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 =
|
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(
|
primaryInMix.profiles.push_back(
|
||||||
createProfile(PcmType::INT_16_BIT,
|
createProfile(PcmType::INT_16_BIT,
|
||||||
{AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO,
|
{AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO},
|
||||||
AudioChannelLayout::LAYOUT_FRONT_BACK},
|
{8000, 11025, 16000, 32000, 44100, 48000}));
|
||||||
{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}));
|
|
||||||
c.ports.push_back(primaryInMix);
|
c.ports.push_back(primaryInMix);
|
||||||
|
|
||||||
AudioPort telephonyTxOutMix =
|
AudioPort telephonyTxOutMix =
|
||||||
|
@ -296,10 +267,10 @@ std::unique_ptr<Configuration> getPrimaryConfiguration() {
|
||||||
standardPcmAudioProfiles.end());
|
standardPcmAudioProfiles.end());
|
||||||
c.ports.push_back(fmTunerInMix);
|
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({micInDevice}, primaryInMix));
|
||||||
c.routes.push_back(createRoute({telephonyTxOutMix}, telephonyTxOutDevice));
|
|
||||||
c.routes.push_back(createRoute({telephonyRxInDevice}, telephonyRxInMix));
|
c.routes.push_back(createRoute({telephonyRxInDevice}, telephonyRxInMix));
|
||||||
|
c.routes.push_back(createRoute({telephonyTxOutMix}, telephonyTxOutDevice));
|
||||||
c.routes.push_back(createRoute({fmTunerInDevice}, fmTunerInMix));
|
c.routes.push_back(createRoute({fmTunerInDevice}, fmTunerInMix));
|
||||||
|
|
||||||
c.portConfigs.insert(c.portConfigs.end(), c.initialConfigs.begin(), c.initialConfigs.end());
|
c.portConfigs.insert(c.portConfigs.end(), c.initialConfigs.begin(), c.initialConfigs.end());
|
||||||
|
@ -320,15 +291,15 @@ std::unique_ptr<Configuration> getPrimaryConfiguration() {
|
||||||
//
|
//
|
||||||
// Device ports:
|
// Device ports:
|
||||||
// * "Remote Submix Out", OUT_SUBMIX
|
// * "Remote Submix Out", OUT_SUBMIX
|
||||||
// - profile PCM 24-bit; STEREO; 48000
|
// - profile PCM 16-bit; STEREO; 48000
|
||||||
// * "Remote Submix In", IN_SUBMIX
|
// * "Remote Submix In", IN_SUBMIX
|
||||||
// - profile PCM 24-bit; STEREO; 48000
|
// - profile PCM 16-bit; STEREO; 48000
|
||||||
//
|
//
|
||||||
// Mix ports:
|
// Mix ports:
|
||||||
// * "r_submix output", stream count unlimited
|
// * "r_submix output", 1 max open, 1 max active stream
|
||||||
// - profile PCM 24-bit; STEREO; 48000
|
// - profile PCM 16-bit; STEREO; 48000
|
||||||
// * "r_submix input", stream count unlimited
|
// * "r_submix input", 1 max open, 1 max active stream
|
||||||
// - profile PCM 24-bit; STEREO; 48000
|
// - profile PCM 16-bit; STEREO; 48000
|
||||||
//
|
//
|
||||||
// Routes:
|
// Routes:
|
||||||
// "r_submix output" -> "Remote Submix Out"
|
// "r_submix output" -> "Remote Submix Out"
|
||||||
|
@ -345,27 +316,27 @@ std::unique_ptr<Configuration> getRSubmixConfiguration() {
|
||||||
createDeviceExt(AudioDeviceType::OUT_SUBMIX, 0,
|
createDeviceExt(AudioDeviceType::OUT_SUBMIX, 0,
|
||||||
AudioDeviceDescription::CONNECTION_VIRTUAL));
|
AudioDeviceDescription::CONNECTION_VIRTUAL));
|
||||||
rsubmixOutDevice.profiles.push_back(
|
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);
|
c.ports.push_back(rsubmixOutDevice);
|
||||||
|
|
||||||
AudioPort rsubmixInDevice = createPort(c.nextPortId++, "Remote Submix In", 0, true,
|
AudioPort rsubmixInDevice = createPort(c.nextPortId++, "Remote Submix In", 0, true,
|
||||||
createDeviceExt(AudioDeviceType::IN_SUBMIX, 0));
|
createDeviceExt(AudioDeviceType::IN_SUBMIX, 0));
|
||||||
rsubmixInDevice.profiles.push_back(
|
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);
|
c.ports.push_back(rsubmixInDevice);
|
||||||
|
|
||||||
// Mix ports
|
// Mix ports
|
||||||
|
|
||||||
AudioPort rsubmixOutMix =
|
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(
|
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);
|
c.ports.push_back(rsubmixOutMix);
|
||||||
|
|
||||||
AudioPort rsubmixInMix =
|
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(
|
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.ports.push_back(rsubmixInMix);
|
||||||
|
|
||||||
c.routes.push_back(createRoute({rsubmixOutMix}, rsubmixOutDevice));
|
c.routes.push_back(createRoute({rsubmixOutMix}, rsubmixOutDevice));
|
||||||
|
@ -486,7 +457,7 @@ std::unique_ptr<Configuration> getUsbConfiguration() {
|
||||||
// - profile MP3; MONO, STEREO; 44100, 48000
|
// - profile MP3; MONO, STEREO; 44100, 48000
|
||||||
// * "test input", 2 max open, 2 max active streams
|
// * "test input", 2 max open, 2 max active streams
|
||||||
// - profile PCM 24-bit; MONO, STEREO, FRONT_BACK;
|
// - 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:
|
// Routes:
|
||||||
// "test output", "test fast output", "test compressed offload" -> "Test Out"
|
// "test output", "test fast output", "test compressed offload" -> "Test Out"
|
||||||
|
@ -553,12 +524,12 @@ std::unique_ptr<Configuration> getStubConfiguration() {
|
||||||
createProfile(PcmType::INT_16_BIT,
|
createProfile(PcmType::INT_16_BIT,
|
||||||
{AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO,
|
{AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO,
|
||||||
AudioChannelLayout::LAYOUT_FRONT_BACK},
|
AudioChannelLayout::LAYOUT_FRONT_BACK},
|
||||||
{8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000}));
|
{8000, 11025, 16000, 22050, 32000, 44100, 48000}));
|
||||||
testInMIx.profiles.push_back(
|
testInMIx.profiles.push_back(
|
||||||
createProfile(PcmType::INT_24_BIT,
|
createProfile(PcmType::INT_24_BIT,
|
||||||
{AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO,
|
{AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO,
|
||||||
AudioChannelLayout::LAYOUT_FRONT_BACK},
|
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.ports.push_back(testInMIx);
|
||||||
|
|
||||||
c.routes.push_back(
|
c.routes.push_back(
|
||||||
|
@ -577,7 +548,7 @@ std::unique_ptr<Configuration> getStubConfiguration() {
|
||||||
// Device ports:
|
// Device ports:
|
||||||
// * "BT A2DP Out", OUT_DEVICE, CONNECTION_BT_A2DP
|
// * "BT A2DP Out", OUT_DEVICE, CONNECTION_BT_A2DP
|
||||||
// - profile PCM 16-bit; STEREO; 44100, 48000, 88200, 96000
|
// - 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
|
// - profile PCM 16-bit; STEREO; 44100, 48000, 88200, 96000
|
||||||
// * "BT A2DP Speaker", OUT_SPEAKER, CONNECTION_BT_A2DP
|
// * "BT A2DP Speaker", OUT_SPEAKER, CONNECTION_BT_A2DP
|
||||||
// - profile PCM 16-bit; STEREO; 44100, 48000, 88200, 96000
|
// - profile PCM 16-bit; STEREO; 44100, 48000, 88200, 96000
|
||||||
|
@ -608,13 +579,18 @@ std::unique_ptr<Configuration> getBluetoothConfiguration() {
|
||||||
createPort(c.nextPortId++, "BT A2DP Out", 0, false,
|
createPort(c.nextPortId++, "BT A2DP Out", 0, false,
|
||||||
createDeviceExt(AudioDeviceType::OUT_DEVICE, 0,
|
createDeviceExt(AudioDeviceType::OUT_DEVICE, 0,
|
||||||
AudioDeviceDescription::CONNECTION_BT_A2DP));
|
AudioDeviceDescription::CONNECTION_BT_A2DP));
|
||||||
|
btOutDevice.profiles.insert(btOutDevice.profiles.begin(), standardPcmAudioProfiles.begin(),
|
||||||
|
standardPcmAudioProfiles.end());
|
||||||
c.ports.push_back(btOutDevice);
|
c.ports.push_back(btOutDevice);
|
||||||
c.connectedProfiles[btOutDevice.id] = standardPcmAudioProfiles;
|
c.connectedProfiles[btOutDevice.id] = standardPcmAudioProfiles;
|
||||||
|
|
||||||
AudioPort btOutHeadphone =
|
AudioPort btOutHeadphone =
|
||||||
createPort(c.nextPortId++, "BT A2DP Headphones", 0, false,
|
createPort(c.nextPortId++, "BT A2DP Headphones", 0, false,
|
||||||
createDeviceExt(AudioDeviceType::OUT_HEADSET, 0,
|
createDeviceExt(AudioDeviceType::OUT_HEADPHONE, 0,
|
||||||
AudioDeviceDescription::CONNECTION_BT_A2DP));
|
AudioDeviceDescription::CONNECTION_BT_A2DP));
|
||||||
|
btOutHeadphone.profiles.insert(btOutHeadphone.profiles.begin(),
|
||||||
|
standardPcmAudioProfiles.begin(),
|
||||||
|
standardPcmAudioProfiles.end());
|
||||||
c.ports.push_back(btOutHeadphone);
|
c.ports.push_back(btOutHeadphone);
|
||||||
c.connectedProfiles[btOutHeadphone.id] = standardPcmAudioProfiles;
|
c.connectedProfiles[btOutHeadphone.id] = standardPcmAudioProfiles;
|
||||||
|
|
||||||
|
@ -622,6 +598,9 @@ std::unique_ptr<Configuration> getBluetoothConfiguration() {
|
||||||
createPort(c.nextPortId++, "BT A2DP Speaker", 0, false,
|
createPort(c.nextPortId++, "BT A2DP Speaker", 0, false,
|
||||||
createDeviceExt(AudioDeviceType::OUT_SPEAKER, 0,
|
createDeviceExt(AudioDeviceType::OUT_SPEAKER, 0,
|
||||||
AudioDeviceDescription::CONNECTION_BT_A2DP));
|
AudioDeviceDescription::CONNECTION_BT_A2DP));
|
||||||
|
btOutSpeaker.profiles.insert(btOutSpeaker.profiles.begin(),
|
||||||
|
standardPcmAudioProfiles.begin(),
|
||||||
|
standardPcmAudioProfiles.end());
|
||||||
c.ports.push_back(btOutSpeaker);
|
c.ports.push_back(btOutSpeaker);
|
||||||
c.connectedProfiles[btOutSpeaker.id] = standardPcmAudioProfiles;
|
c.connectedProfiles[btOutSpeaker.id] = standardPcmAudioProfiles;
|
||||||
|
|
||||||
|
@ -634,20 +613,20 @@ std::unique_ptr<Configuration> getBluetoothConfiguration() {
|
||||||
{createProfile(PcmType::INT_16_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {16000})});
|
{createProfile(PcmType::INT_16_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {16000})});
|
||||||
|
|
||||||
// Mix ports
|
// Mix ports
|
||||||
AudioPort btInMix =
|
AudioPort btOutMix =
|
||||||
createPort(c.nextPortId++, "a2dp output", 0, true, createPortMixExt(1, 1));
|
createPort(c.nextPortId++, "a2dp output", 0, false, createPortMixExt(1, 1));
|
||||||
c.ports.push_back(btInMix);
|
c.ports.push_back(btOutMix);
|
||||||
|
|
||||||
AudioPort btHeadsetInMix =
|
AudioPort btHearingOutMix =
|
||||||
createPort(c.nextPortId++, "hearing aid output", 0, true, createPortMixExt(1, 1));
|
createPort(c.nextPortId++, "hearing aid output", 0, false, createPortMixExt(1, 1));
|
||||||
btHeadsetInMix.profiles.push_back(createProfile(
|
btHearingOutMix.profiles.push_back(createProfile(
|
||||||
PcmType::INT_16_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {16000, 24000}));
|
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({btOutMix}, btOutDevice));
|
||||||
c.routes.push_back(createRoute({btInMix}, btOutHeadphone));
|
c.routes.push_back(createRoute({btOutMix}, btOutHeadphone));
|
||||||
c.routes.push_back(createRoute({btInMix}, btOutSpeaker));
|
c.routes.push_back(createRoute({btOutMix}, btOutSpeaker));
|
||||||
c.routes.push_back(createRoute({btHeadsetInMix}, btOutHearingAid));
|
c.routes.push_back(createRoute({btHearingOutMix}, btOutHearingAid));
|
||||||
|
|
||||||
return c;
|
return c;
|
||||||
}();
|
}();
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
#include <android-base/logging.h>
|
#include <android-base/logging.h>
|
||||||
|
|
||||||
#include "core-impl/ModulePrimary.h"
|
#include "core-impl/ModulePrimary.h"
|
||||||
#include "core-impl/StreamStub.h"
|
#include "core-impl/StreamPrimary.h"
|
||||||
#include "core-impl/Telephony.h"
|
#include "core-impl/Telephony.h"
|
||||||
|
|
||||||
using aidl::android::hardware::audio::common::SinkMetadata;
|
using aidl::android::hardware::audio::common::SinkMetadata;
|
||||||
|
@ -47,15 +47,15 @@ ndk::ScopedAStatus ModulePrimary::createInputStream(StreamContext&& context,
|
||||||
const SinkMetadata& sinkMetadata,
|
const SinkMetadata& sinkMetadata,
|
||||||
const std::vector<MicrophoneInfo>& microphones,
|
const std::vector<MicrophoneInfo>& microphones,
|
||||||
std::shared_ptr<StreamIn>* result) {
|
std::shared_ptr<StreamIn>* result) {
|
||||||
return createStreamInstance<StreamInStub>(result, std::move(context), sinkMetadata,
|
return createStreamInstance<StreamInPrimary>(result, std::move(context), sinkMetadata,
|
||||||
microphones);
|
microphones);
|
||||||
}
|
}
|
||||||
|
|
||||||
ndk::ScopedAStatus ModulePrimary::createOutputStream(
|
ndk::ScopedAStatus ModulePrimary::createOutputStream(
|
||||||
StreamContext&& context, const SourceMetadata& sourceMetadata,
|
StreamContext&& context, const SourceMetadata& sourceMetadata,
|
||||||
const std::optional<AudioOffloadInfo>& offloadInfo, std::shared_ptr<StreamOut>* result) {
|
const std::optional<AudioOffloadInfo>& offloadInfo, std::shared_ptr<StreamOut>* result) {
|
||||||
return createStreamInstance<StreamOutStub>(result, std::move(context), sourceMetadata,
|
return createStreamInstance<StreamOutPrimary>(result, std::move(context), sourceMetadata,
|
||||||
offloadInfo);
|
offloadInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace aidl::android::hardware::audio::core
|
} // namespace aidl::android::hardware::audio::core
|
||||||
|
|
|
@ -242,8 +242,8 @@ StreamInWorkerLogic::Status StreamInWorkerLogic::cycle() {
|
||||||
break;
|
break;
|
||||||
case Tag::standby:
|
case Tag::standby:
|
||||||
if (mState == StreamDescriptor::State::IDLE) {
|
if (mState == StreamDescriptor::State::IDLE) {
|
||||||
|
populateReply(&reply, mIsConnected);
|
||||||
if (::android::status_t status = mDriver->standby(); status == ::android::OK) {
|
if (::android::status_t status = mDriver->standby(); status == ::android::OK) {
|
||||||
populateReply(&reply, mIsConnected);
|
|
||||||
mState = StreamDescriptor::State::STANDBY;
|
mState = StreamDescriptor::State::STANDBY;
|
||||||
} else {
|
} else {
|
||||||
LOG(ERROR) << __func__ << ": standby failed: " << status;
|
LOG(ERROR) << __func__ << ": standby failed: " << status;
|
||||||
|
@ -496,8 +496,8 @@ StreamOutWorkerLogic::Status StreamOutWorkerLogic::cycle() {
|
||||||
break;
|
break;
|
||||||
case Tag::standby:
|
case Tag::standby:
|
||||||
if (mState == StreamDescriptor::State::IDLE) {
|
if (mState == StreamDescriptor::State::IDLE) {
|
||||||
|
populateReply(&reply, mIsConnected);
|
||||||
if (::android::status_t status = mDriver->standby(); status == ::android::OK) {
|
if (::android::status_t status = mDriver->standby(); status == ::android::OK) {
|
||||||
populateReply(&reply, mIsConnected);
|
|
||||||
mState = StreamDescriptor::State::STANDBY;
|
mState = StreamDescriptor::State::STANDBY;
|
||||||
} else {
|
} else {
|
||||||
LOG(ERROR) << __func__ << ": standby failed: " << status;
|
LOG(ERROR) << __func__ << ": standby failed: " << status;
|
||||||
|
@ -825,6 +825,32 @@ ndk::ScopedAStatus StreamIn::setHwGain(const std::vector<float>& in_channelGains
|
||||||
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
|
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)
|
StreamOut::StreamOut(StreamContext&& context, const std::optional<AudioOffloadInfo>& offloadInfo)
|
||||||
: mContextInstance(std::move(context)), mOffloadInfo(offloadInfo) {
|
: mContextInstance(std::move(context)), mOffloadInfo(offloadInfo) {
|
||||||
LOG(DEBUG) << __func__;
|
LOG(DEBUG) << __func__;
|
||||||
|
@ -930,4 +956,31 @@ ndk::ScopedAStatus StreamOut::selectPresentation(int32_t in_presentationId, int3
|
||||||
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
|
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
|
} // namespace aidl::android::hardware::audio::core
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
|
||||||
#define LOG_TAG "AHAL_StreamAlsa"
|
#define LOG_TAG "AHAL_StreamAlsa"
|
||||||
|
@ -29,7 +30,9 @@ namespace aidl::android::hardware::audio::core {
|
||||||
|
|
||||||
StreamAlsa::StreamAlsa(StreamContext* context, const Metadata& metadata, int readWriteRetries)
|
StreamAlsa::StreamAlsa(StreamContext* context, const Metadata& metadata, int readWriteRetries)
|
||||||
: StreamCommonImpl(context, metadata),
|
: StreamCommonImpl(context, metadata),
|
||||||
|
mBufferSizeFrames(getContext().getBufferSizeInFrames()),
|
||||||
mFrameSizeBytes(getContext().getFrameSize()),
|
mFrameSizeBytes(getContext().getFrameSize()),
|
||||||
|
mSampleRate(getContext().getSampleRate()),
|
||||||
mIsInput(isInput(metadata)),
|
mIsInput(isInput(metadata)),
|
||||||
mConfig(alsa::getPcmConfig(getContext(), mIsInput)),
|
mConfig(alsa::getPcmConfig(getContext(), mIsInput)),
|
||||||
mReadWriteRetries(readWriteRetries) {}
|
mReadWriteRetries(readWriteRetries) {}
|
||||||
|
@ -39,17 +42,20 @@ StreamAlsa::StreamAlsa(StreamContext* context, const Metadata& metadata, int rea
|
||||||
}
|
}
|
||||||
|
|
||||||
::android::status_t StreamAlsa::drain(StreamDescriptor::DrainMode) {
|
::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;
|
return ::android::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
::android::status_t StreamAlsa::flush() {
|
::android::status_t StreamAlsa::flush() {
|
||||||
usleep(1000);
|
|
||||||
return ::android::OK;
|
return ::android::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
::android::status_t StreamAlsa::pause() {
|
::android::status_t StreamAlsa::pause() {
|
||||||
usleep(1000);
|
|
||||||
return ::android::OK;
|
return ::android::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,6 +65,10 @@ StreamAlsa::StreamAlsa(StreamContext* context, const Metadata& metadata, int rea
|
||||||
}
|
}
|
||||||
|
|
||||||
::android::status_t StreamAlsa::start() {
|
::android::status_t StreamAlsa::start() {
|
||||||
|
if (!mAlsaDeviceProxies.empty()) {
|
||||||
|
// This is a resume after a pause.
|
||||||
|
return ::android::OK;
|
||||||
|
}
|
||||||
decltype(mAlsaDeviceProxies) alsaDeviceProxies;
|
decltype(mAlsaDeviceProxies) alsaDeviceProxies;
|
||||||
for (const auto& device : getDeviceProfiles()) {
|
for (const auto& device : getDeviceProfiles()) {
|
||||||
alsa::DeviceProxy proxy;
|
alsa::DeviceProxy proxy;
|
||||||
|
@ -71,8 +81,7 @@ StreamAlsa::StreamAlsa(StreamContext* context, const Metadata& metadata, int rea
|
||||||
true /*require_exact_match*/);
|
true /*require_exact_match*/);
|
||||||
} else {
|
} else {
|
||||||
proxy = alsa::openProxyForAttachedDevice(
|
proxy = alsa::openProxyForAttachedDevice(
|
||||||
device, const_cast<struct pcm_config*>(&mConfig.value()),
|
device, const_cast<struct pcm_config*>(&mConfig.value()), mBufferSizeFrames);
|
||||||
getContext().getBufferSizeInFrames());
|
|
||||||
}
|
}
|
||||||
if (!proxy) {
|
if (!proxy) {
|
||||||
return ::android::NO_INIT;
|
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,
|
::android::status_t StreamAlsa::transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
|
||||||
int32_t* latencyMs) {
|
int32_t* latencyMs) {
|
||||||
|
if (mAlsaDeviceProxies.empty()) {
|
||||||
|
LOG(FATAL) << __func__ << ": no opened devices";
|
||||||
|
return ::android::NO_INIT;
|
||||||
|
}
|
||||||
const size_t bytesToTransfer = frameCount * mFrameSizeBytes;
|
const size_t bytesToTransfer = frameCount * mFrameSizeBytes;
|
||||||
unsigned maxLatency = 0;
|
unsigned maxLatency = 0;
|
||||||
if (mIsInput) {
|
if (mIsInput) {
|
||||||
if (mAlsaDeviceProxies.empty()) {
|
|
||||||
LOG(FATAL) << __func__ << ": no input devices";
|
|
||||||
return ::android::NO_INIT;
|
|
||||||
}
|
|
||||||
// For input case, only support single device.
|
// For input case, only support single device.
|
||||||
proxy_read_with_retries(mAlsaDeviceProxies[0].get(), buffer, bytesToTransfer,
|
proxy_read_with_retries(mAlsaDeviceProxies[0].get(), buffer, bytesToTransfer,
|
||||||
mReadWriteRetries);
|
mReadWriteRetries);
|
||||||
|
@ -110,9 +119,12 @@ StreamAlsa::StreamAlsa(StreamContext* context, const Metadata& metadata, int rea
|
||||||
|
|
||||||
::android::status_t StreamAlsa::refinePosition(StreamDescriptor::Position* position) {
|
::android::status_t StreamAlsa::refinePosition(StreamDescriptor::Position* position) {
|
||||||
if (mAlsaDeviceProxies.empty()) {
|
if (mAlsaDeviceProxies.empty()) {
|
||||||
LOG(FATAL) << __func__ << ": no input devices";
|
LOG(FATAL) << __func__ << ": no opened devices";
|
||||||
return ::android::NO_INIT;
|
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 (mIsInput) {
|
||||||
if (int ret = proxy_get_capture_position(mAlsaDeviceProxies[0].get(), &position->frames,
|
if (int ret = proxy_get_capture_position(mAlsaDeviceProxies[0].get(), &position->frames,
|
||||||
&position->timeNs);
|
&position->timeNs);
|
||||||
|
|
|
@ -262,12 +262,14 @@ std::vector<int> getSampleRatesFromProfile(const alsa_device_profile* profile) {
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceProxy makeDeviceProxy() {
|
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) {
|
if (proxy != nullptr) {
|
||||||
proxy_close(proxy);
|
proxy_close(proxy);
|
||||||
delete proxy;
|
delete proxy;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
memset(proxy.get(), 0, sizeof(alsa_device_proxy));
|
||||||
|
return proxy;
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceProxy openProxyForAttachedDevice(const DeviceProfile& deviceProfile,
|
DeviceProxy openProxyForAttachedDevice(const DeviceProfile& deviceProfile,
|
||||||
|
@ -334,6 +336,12 @@ std::optional<alsa_device_profile> readAlsaDeviceInfo(const DeviceProfile& devic
|
||||||
return profile;
|
return profile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void resetTransferredFrames(DeviceProxy& proxy, uint64_t frames) {
|
||||||
|
if (proxy != nullptr) {
|
||||||
|
proxy->transferred = frames;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
AudioFormatDescription c2aidl_pcm_format_AudioFormatDescription(enum pcm_format legacy) {
|
AudioFormatDescription c2aidl_pcm_format_AudioFormatDescription(enum pcm_format legacy) {
|
||||||
return findValueOrDefault(getPcmFormatToAudioFormatDescMap(), legacy, AudioFormatDescription());
|
return findValueOrDefault(getPcmFormatToAudioFormatDescMap(), legacy, AudioFormatDescription());
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,6 +66,7 @@ DeviceProxy openProxyForAttachedDevice(const DeviceProfile& deviceProfile,
|
||||||
DeviceProxy openProxyForExternalDevice(const DeviceProfile& deviceProfile,
|
DeviceProxy openProxyForExternalDevice(const DeviceProfile& deviceProfile,
|
||||||
struct pcm_config* pcmConfig, bool requireExactMatch);
|
struct pcm_config* pcmConfig, bool requireExactMatch);
|
||||||
std::optional<alsa_device_profile> readAlsaDeviceInfo(const DeviceProfile& deviceProfile);
|
std::optional<alsa_device_profile> readAlsaDeviceInfo(const DeviceProfile& deviceProfile);
|
||||||
|
void resetTransferredFrames(DeviceProxy& proxy, uint64_t frames);
|
||||||
|
|
||||||
::aidl::android::media::audio::common::AudioFormatDescription
|
::aidl::android::media::audio::common::AudioFormatDescription
|
||||||
c2aidl_pcm_format_AudioFormatDescription(enum pcm_format legacy);
|
c2aidl_pcm_format_AudioFormatDescription(enum pcm_format legacy);
|
||||||
|
|
|
@ -514,6 +514,17 @@ class StreamIn : virtual public StreamCommonInterface, public BnStreamIn {
|
||||||
const std::map<::aidl::android::media::audio::common::AudioDevice, std::string> mMicrophones;
|
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 {
|
class StreamOut : virtual public StreamCommonInterface, public BnStreamOut {
|
||||||
protected:
|
protected:
|
||||||
void defaultOnClose();
|
void defaultOnClose();
|
||||||
|
@ -560,6 +571,17 @@ class StreamOut : virtual public StreamCommonInterface, public BnStreamOut {
|
||||||
std::optional<::aidl::android::hardware::audio::common::AudioOffloadMetadata> mOffloadMetadata;
|
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.
|
// The recommended way to create a stream instance.
|
||||||
// 'StreamImpl' is the concrete stream implementation, 'StreamInOrOut' is either 'StreamIn' or
|
// 'StreamImpl' is the concrete stream implementation, 'StreamInOrOut' is either 'StreamIn' or
|
||||||
// 'StreamOut', the rest are the arguments forwarded to the constructor of 'StreamImpl'.
|
// '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.
|
// Called from 'start' to initialize 'mAlsaDeviceProxies', the vector must be non-empty.
|
||||||
virtual std::vector<alsa::DeviceProfile> getDeviceProfiles() = 0;
|
virtual std::vector<alsa::DeviceProfile> getDeviceProfiles() = 0;
|
||||||
|
|
||||||
|
const size_t mBufferSizeFrames;
|
||||||
const size_t mFrameSizeBytes;
|
const size_t mFrameSizeBytes;
|
||||||
|
const int mSampleRate;
|
||||||
const bool mIsInput;
|
const bool mIsInput;
|
||||||
const std::optional<struct pcm_config> mConfig;
|
const std::optional<struct pcm_config> mConfig;
|
||||||
const int mReadWriteRetries;
|
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;
|
void shutdown() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
const size_t mBufferSizeFrames;
|
||||||
const size_t mFrameSizeBytes;
|
const size_t mFrameSizeBytes;
|
||||||
const int mSampleRate;
|
const int mSampleRate;
|
||||||
const bool mIsAsynchronous;
|
const bool mIsAsynchronous;
|
||||||
|
|
|
@ -59,7 +59,7 @@ class StreamInUsb final : public StreamIn, public StreamUsb {
|
||||||
override;
|
override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class StreamOutUsb final : public StreamOut, public StreamUsb {
|
class StreamOutUsb final : public StreamOut, public StreamUsb, public StreamOutHwVolumeHelper {
|
||||||
public:
|
public:
|
||||||
friend class ndk::SharedRefBase;
|
friend class ndk::SharedRefBase;
|
||||||
StreamOutUsb(StreamContext&& context,
|
StreamOutUsb(StreamContext&& context,
|
||||||
|
@ -71,9 +71,6 @@ class StreamOutUsb final : public StreamOut, public StreamUsb {
|
||||||
void onClose(StreamDescriptor::State) override { defaultOnClose(); }
|
void onClose(StreamDescriptor::State) override { defaultOnClose(); }
|
||||||
ndk::ScopedAStatus getHwVolume(std::vector<float>* _aidl_return) override;
|
ndk::ScopedAStatus getHwVolume(std::vector<float>* _aidl_return) override;
|
||||||
ndk::ScopedAStatus setHwVolume(const std::vector<float>& in_channelVolumes) override;
|
ndk::ScopedAStatus setHwVolume(const std::vector<float>& in_channelVolumes) override;
|
||||||
|
|
||||||
const int mChannelCount;
|
|
||||||
std::vector<float> mHwVolumes;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace aidl::android::hardware::audio::core
|
} // 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)
|
StreamStub::StreamStub(StreamContext* context, const Metadata& metadata)
|
||||||
: StreamCommonImpl(context, metadata),
|
: StreamCommonImpl(context, metadata),
|
||||||
|
mBufferSizeFrames(getContext().getBufferSizeInFrames()),
|
||||||
mFrameSizeBytes(getContext().getFrameSize()),
|
mFrameSizeBytes(getContext().getFrameSize()),
|
||||||
mSampleRate(getContext().getSampleRate()),
|
mSampleRate(getContext().getSampleRate()),
|
||||||
mIsAsynchronous(!!getContext().getAsyncCallback()),
|
mIsAsynchronous(!!getContext().getAsyncCallback()),
|
||||||
|
@ -40,7 +41,6 @@ StreamStub::StreamStub(StreamContext* context, const Metadata& metadata)
|
||||||
|
|
||||||
::android::status_t StreamStub::init() {
|
::android::status_t StreamStub::init() {
|
||||||
mIsInitialized = true;
|
mIsInitialized = true;
|
||||||
usleep(500);
|
|
||||||
return ::android::OK;
|
return ::android::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,7 +48,16 @@ StreamStub::StreamStub(StreamContext* context, const Metadata& metadata)
|
||||||
if (!mIsInitialized) {
|
if (!mIsInitialized) {
|
||||||
LOG(FATAL) << __func__ << ": must not happen for an uninitialized driver";
|
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;
|
return ::android::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,7 +65,6 @@ StreamStub::StreamStub(StreamContext* context, const Metadata& metadata)
|
||||||
if (!mIsInitialized) {
|
if (!mIsInitialized) {
|
||||||
LOG(FATAL) << __func__ << ": must not happen for an uninitialized driver";
|
LOG(FATAL) << __func__ << ": must not happen for an uninitialized driver";
|
||||||
}
|
}
|
||||||
usleep(500);
|
|
||||||
return ::android::OK;
|
return ::android::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,7 +72,6 @@ StreamStub::StreamStub(StreamContext* context, const Metadata& metadata)
|
||||||
if (!mIsInitialized) {
|
if (!mIsInitialized) {
|
||||||
LOG(FATAL) << __func__ << ": must not happen for an uninitialized driver";
|
LOG(FATAL) << __func__ << ": must not happen for an uninitialized driver";
|
||||||
}
|
}
|
||||||
usleep(500);
|
|
||||||
return ::android::OK;
|
return ::android::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,14 +18,11 @@
|
||||||
|
|
||||||
#define LOG_TAG "AHAL_StreamUsb"
|
#define LOG_TAG "AHAL_StreamUsb"
|
||||||
#include <android-base/logging.h>
|
#include <android-base/logging.h>
|
||||||
|
|
||||||
#include <Utils.h>
|
|
||||||
#include <error/expected_utils.h>
|
#include <error/expected_utils.h>
|
||||||
|
|
||||||
#include "UsbAlsaMixerControl.h"
|
#include "UsbAlsaMixerControl.h"
|
||||||
#include "core-impl/StreamUsb.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::SinkMetadata;
|
||||||
using aidl::android::hardware::audio::common::SourceMetadata;
|
using aidl::android::hardware::audio::common::SourceMetadata;
|
||||||
using aidl::android::media::audio::common::AudioDevice;
|
using aidl::android::media::audio::common::AudioDevice;
|
||||||
|
@ -97,14 +94,15 @@ StreamOutUsb::StreamOutUsb(StreamContext&& context, const SourceMetadata& source
|
||||||
const std::optional<AudioOffloadInfo>& offloadInfo)
|
const std::optional<AudioOffloadInfo>& offloadInfo)
|
||||||
: StreamOut(std::move(context), offloadInfo),
|
: StreamOut(std::move(context), offloadInfo),
|
||||||
StreamUsb(&mContextInstance, sourceMetadata),
|
StreamUsb(&mContextInstance, sourceMetadata),
|
||||||
mChannelCount(getChannelCount(getContext().getChannelLayout())) {}
|
StreamOutHwVolumeHelper(&mContextInstance) {}
|
||||||
|
|
||||||
ndk::ScopedAStatus StreamOutUsb::getHwVolume(std::vector<float>* _aidl_return) {
|
ndk::ScopedAStatus StreamOutUsb::getHwVolume(std::vector<float>* _aidl_return) {
|
||||||
*_aidl_return = mHwVolumes;
|
return getHwVolumeImpl(_aidl_return);
|
||||||
return ndk::ScopedAStatus::ok();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ndk::ScopedAStatus StreamOutUsb::setHwVolume(const std::vector<float>& in_channelVolumes) {
|
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.
|
// Avoid using mConnectedDeviceProfiles because it requires a lock.
|
||||||
for (const auto& device : getConnectedDevices()) {
|
for (const auto& device : getConnectedDevices()) {
|
||||||
if (auto deviceProfile = alsa::getDeviceProfile(device, mIsInput);
|
if (auto deviceProfile = alsa::getDeviceProfile(device, mIsInput);
|
||||||
|
@ -114,11 +112,11 @@ ndk::ScopedAStatus StreamOutUsb::setHwVolume(const std::vector<float>& in_channe
|
||||||
!result.isOk()) {
|
!result.isOk()) {
|
||||||
LOG(ERROR) << __func__
|
LOG(ERROR) << __func__
|
||||||
<< ": failed to set volume for device address=" << *deviceProfile;
|
<< ": failed to set volume for device address=" << *deviceProfile;
|
||||||
|
mHwVolumes = currentVolumes;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mHwVolumes = in_channelVolumes;
|
|
||||||
return ndk::ScopedAStatus::ok();
|
return ndk::ScopedAStatus::ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,6 +55,7 @@ cc_test {
|
||||||
"VtsHalAudioCoreConfigTargetTest.cpp",
|
"VtsHalAudioCoreConfigTargetTest.cpp",
|
||||||
"VtsHalAudioCoreModuleTargetTest.cpp",
|
"VtsHalAudioCoreModuleTargetTest.cpp",
|
||||||
],
|
],
|
||||||
|
test_config: "VtsHalAudioCoreTargetTest.xml",
|
||||||
}
|
}
|
||||||
|
|
||||||
cc_test {
|
cc_test {
|
||||||
|
|
|
@ -3189,10 +3189,17 @@ class StreamLogicDefaultDriver : public StreamLogicDriver {
|
||||||
std::string mUnexpectedTransition;
|
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 };
|
enum class StreamTypeFilter { ANY, SYNC, ASYNC };
|
||||||
using NamedCommandSequence =
|
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 };
|
enum { PARAM_MODULE_NAME, PARAM_CMD_SEQ, PARAM_SETUP_SEQ };
|
||||||
using StreamIoTestParameters =
|
using StreamIoTestParameters =
|
||||||
std::tuple<std::string /*moduleName*/, NamedCommandSequence, bool /*useSetupSequence2*/>;
|
std::tuple<std::string /*moduleName*/, NamedCommandSequence, bool /*useSetupSequence2*/>;
|
||||||
|
@ -3236,10 +3243,14 @@ class AudioStreamIo : public AudioCoreModuleBase,
|
||||||
ASSERT_NO_FATAL_FAILURE(delayTransientStates.SetUp(module.get()));
|
ASSERT_NO_FATAL_FAILURE(delayTransientStates.SetUp(module.get()));
|
||||||
const auto& commandsAndStates =
|
const auto& commandsAndStates =
|
||||||
std::get<NAMED_CMD_CMDS>(std::get<PARAM_CMD_SEQ>(GetParam()));
|
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())) {
|
if (!std::get<PARAM_SETUP_SEQ>(GetParam())) {
|
||||||
ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq1(portConfig, commandsAndStates));
|
ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq1(portConfig, commandsAndStates,
|
||||||
|
validatePositionIncrease));
|
||||||
} else {
|
} else {
|
||||||
ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq2(portConfig, commandsAndStates));
|
ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq2(portConfig, commandsAndStates,
|
||||||
|
validatePositionIncrease));
|
||||||
}
|
}
|
||||||
if (isNonBlocking) {
|
if (isNonBlocking) {
|
||||||
// Also try running the same sequence with "aosp.forceTransientBurst" set.
|
// 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*/)
|
if (forceTransientBurst.SetUpNoChecks(module.get(), true /*failureExpected*/)
|
||||||
.isOk()) {
|
.isOk()) {
|
||||||
if (!std::get<PARAM_SETUP_SEQ>(GetParam())) {
|
if (!std::get<PARAM_SETUP_SEQ>(GetParam())) {
|
||||||
ASSERT_NO_FATAL_FAILURE(
|
ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq1(
|
||||||
RunStreamIoCommandsImplSeq1(portConfig, commandsAndStates));
|
portConfig, commandsAndStates, validatePositionIncrease));
|
||||||
} else {
|
} else {
|
||||||
ASSERT_NO_FATAL_FAILURE(
|
ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq2(
|
||||||
RunStreamIoCommandsImplSeq2(portConfig, commandsAndStates));
|
portConfig, commandsAndStates, validatePositionIncrease));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (!IOTraits<Stream>::is_input) {
|
} else if (!IOTraits<Stream>::is_input) {
|
||||||
|
@ -3267,11 +3278,11 @@ class AudioStreamIo : public AudioCoreModuleBase,
|
||||||
if (forceSynchronousDrain.SetUpNoChecks(module.get(), true /*failureExpected*/)
|
if (forceSynchronousDrain.SetUpNoChecks(module.get(), true /*failureExpected*/)
|
||||||
.isOk()) {
|
.isOk()) {
|
||||||
if (!std::get<PARAM_SETUP_SEQ>(GetParam())) {
|
if (!std::get<PARAM_SETUP_SEQ>(GetParam())) {
|
||||||
ASSERT_NO_FATAL_FAILURE(
|
ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq1(
|
||||||
RunStreamIoCommandsImplSeq1(portConfig, commandsAndStates));
|
portConfig, commandsAndStates, validatePositionIncrease));
|
||||||
} else {
|
} else {
|
||||||
ASSERT_NO_FATAL_FAILURE(
|
ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq2(
|
||||||
RunStreamIoCommandsImplSeq2(portConfig, commandsAndStates));
|
portConfig, commandsAndStates, validatePositionIncrease));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3285,11 +3296,13 @@ class AudioStreamIo : public AudioCoreModuleBase,
|
||||||
|
|
||||||
// Set up a patch first, then open a stream.
|
// Set up a patch first, then open a stream.
|
||||||
void RunStreamIoCommandsImplSeq1(const AudioPortConfig& portConfig,
|
void RunStreamIoCommandsImplSeq1(const AudioPortConfig& portConfig,
|
||||||
std::shared_ptr<StateSequence> commandsAndStates) {
|
std::shared_ptr<StateSequence> commandsAndStates,
|
||||||
|
bool validatePositionIncrease) {
|
||||||
auto devicePorts = moduleConfig->getAttachedDevicesPortsForMixPort(
|
auto devicePorts = moduleConfig->getAttachedDevicesPortsForMixPort(
|
||||||
IOTraits<Stream>::is_input, portConfig);
|
IOTraits<Stream>::is_input, portConfig);
|
||||||
ASSERT_FALSE(devicePorts.empty());
|
ASSERT_FALSE(devicePorts.empty());
|
||||||
auto devicePortConfig = moduleConfig->getSingleConfigForDevicePort(devicePorts[0]);
|
auto devicePortConfig = moduleConfig->getSingleConfigForDevicePort(devicePorts[0]);
|
||||||
|
SCOPED_TRACE(devicePortConfig.toString());
|
||||||
WithAudioPatch patch(IOTraits<Stream>::is_input, portConfig, devicePortConfig);
|
WithAudioPatch patch(IOTraits<Stream>::is_input, portConfig, devicePortConfig);
|
||||||
ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
|
ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
|
||||||
|
|
||||||
|
@ -3307,14 +3320,17 @@ class AudioStreamIo : public AudioCoreModuleBase,
|
||||||
EXPECT_FALSE(worker.hasError()) << worker.getError();
|
EXPECT_FALSE(worker.hasError()) << worker.getError();
|
||||||
EXPECT_EQ("", driver.getUnexpectedStateTransition());
|
EXPECT_EQ("", driver.getUnexpectedStateTransition());
|
||||||
if (ValidateObservablePosition(devicePortConfig)) {
|
if (ValidateObservablePosition(devicePortConfig)) {
|
||||||
EXPECT_TRUE(driver.hasObservablePositionIncrease());
|
if (validatePositionIncrease) {
|
||||||
|
EXPECT_TRUE(driver.hasObservablePositionIncrease());
|
||||||
|
}
|
||||||
EXPECT_FALSE(driver.hasRetrogradeObservablePosition());
|
EXPECT_FALSE(driver.hasRetrogradeObservablePosition());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open a stream, then set up a patch for it.
|
// Open a stream, then set up a patch for it.
|
||||||
void RunStreamIoCommandsImplSeq2(const AudioPortConfig& portConfig,
|
void RunStreamIoCommandsImplSeq2(const AudioPortConfig& portConfig,
|
||||||
std::shared_ptr<StateSequence> commandsAndStates) {
|
std::shared_ptr<StateSequence> commandsAndStates,
|
||||||
|
bool validatePositionIncrease) {
|
||||||
WithStream<Stream> stream(portConfig);
|
WithStream<Stream> stream(portConfig);
|
||||||
ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
|
ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
|
||||||
StreamLogicDefaultDriver driver(commandsAndStates,
|
StreamLogicDefaultDriver driver(commandsAndStates,
|
||||||
|
@ -3326,6 +3342,7 @@ class AudioStreamIo : public AudioCoreModuleBase,
|
||||||
IOTraits<Stream>::is_input, portConfig);
|
IOTraits<Stream>::is_input, portConfig);
|
||||||
ASSERT_FALSE(devicePorts.empty());
|
ASSERT_FALSE(devicePorts.empty());
|
||||||
auto devicePortConfig = moduleConfig->getSingleConfigForDevicePort(devicePorts[0]);
|
auto devicePortConfig = moduleConfig->getSingleConfigForDevicePort(devicePorts[0]);
|
||||||
|
SCOPED_TRACE(devicePortConfig.toString());
|
||||||
WithAudioPatch patch(IOTraits<Stream>::is_input, stream.getPortConfig(), devicePortConfig);
|
WithAudioPatch patch(IOTraits<Stream>::is_input, stream.getPortConfig(), devicePortConfig);
|
||||||
ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
|
ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
|
||||||
|
|
||||||
|
@ -3336,7 +3353,9 @@ class AudioStreamIo : public AudioCoreModuleBase,
|
||||||
EXPECT_FALSE(worker.hasError()) << worker.getError();
|
EXPECT_FALSE(worker.hasError()) << worker.getError();
|
||||||
EXPECT_EQ("", driver.getUnexpectedStateTransition());
|
EXPECT_EQ("", driver.getUnexpectedStateTransition());
|
||||||
if (ValidateObservablePosition(devicePortConfig)) {
|
if (ValidateObservablePosition(devicePortConfig)) {
|
||||||
EXPECT_TRUE(driver.hasObservablePositionIncrease());
|
if (validatePositionIncrease) {
|
||||||
|
EXPECT_TRUE(driver.hasObservablePositionIncrease());
|
||||||
|
}
|
||||||
EXPECT_FALSE(driver.hasRetrogradeObservablePosition());
|
EXPECT_FALSE(driver.hasRetrogradeObservablePosition());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3668,22 +3687,28 @@ std::shared_ptr<StateSequence> makeBurstCommands(bool isSync) {
|
||||||
using State = StreamDescriptor::State;
|
using State = StreamDescriptor::State;
|
||||||
auto d = std::make_unique<StateDag>();
|
auto d = std::make_unique<StateDag>();
|
||||||
StateDag::Node last = d->makeFinalNode(State::ACTIVE);
|
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);
|
StateDag::Node idle = d->makeNode(State::IDLE, kBurstCommand, active);
|
||||||
if (!isSync) {
|
if (!isSync) {
|
||||||
// Allow optional routing via the TRANSFERRING state on bursts.
|
// 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));
|
idle.children().push_back(d->makeNode(State::TRANSFERRING, kTransferReadyEvent, active));
|
||||||
}
|
}
|
||||||
d->makeNode(State::STANDBY, kStartCommand, idle);
|
d->makeNode(State::STANDBY, kStartCommand, idle);
|
||||||
return std::make_shared<StateSequenceFollower>(std::move(d));
|
return std::make_shared<StateSequenceFollower>(std::move(d));
|
||||||
}
|
}
|
||||||
static const NamedCommandSequence kReadSeq =
|
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 =
|
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 =
|
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) {
|
std::shared_ptr<StateSequence> makeAsyncDrainCommands(bool isInput) {
|
||||||
using State = StreamDescriptor::State;
|
using State = StreamDescriptor::State;
|
||||||
|
@ -3711,11 +3736,12 @@ std::shared_ptr<StateSequence> makeAsyncDrainCommands(bool isInput) {
|
||||||
}
|
}
|
||||||
return std::make_shared<StateSequenceFollower>(std::move(d));
|
return std::make_shared<StateSequenceFollower>(std::move(d));
|
||||||
}
|
}
|
||||||
static const NamedCommandSequence kWriteDrainAsyncSeq =
|
static const NamedCommandSequence kWriteDrainAsyncSeq = std::make_tuple(
|
||||||
std::make_tuple(std::string("WriteDrain"), kStreamTransientStateTransitionDelayMs,
|
std::string("WriteDrain"), kStreamTransientStateTransitionDelayMs, StreamTypeFilter::ASYNC,
|
||||||
StreamTypeFilter::ASYNC, makeAsyncDrainCommands(false));
|
makeAsyncDrainCommands(false), false /*validatePositionIncrease*/);
|
||||||
static const NamedCommandSequence kDrainInSeq = std::make_tuple(
|
static const NamedCommandSequence kDrainInSeq =
|
||||||
std::string("Drain"), 0, StreamTypeFilter::ANY, makeAsyncDrainCommands(true));
|
std::make_tuple(std::string("Drain"), 0, StreamTypeFilter::ANY,
|
||||||
|
makeAsyncDrainCommands(true), false /*validatePositionIncrease*/);
|
||||||
|
|
||||||
std::shared_ptr<StateSequence> makeDrainOutCommands(bool isSync) {
|
std::shared_ptr<StateSequence> makeDrainOutCommands(bool isSync) {
|
||||||
using State = StreamDescriptor::State;
|
using State = StreamDescriptor::State;
|
||||||
|
@ -3735,10 +3761,12 @@ std::shared_ptr<StateSequence> makeDrainOutCommands(bool isSync) {
|
||||||
d->makeNode(State::STANDBY, kStartCommand, idle);
|
d->makeNode(State::STANDBY, kStartCommand, idle);
|
||||||
return std::make_shared<StateSequenceFollower>(std::move(d));
|
return std::make_shared<StateSequenceFollower>(std::move(d));
|
||||||
}
|
}
|
||||||
static const NamedCommandSequence kDrainOutSyncSeq = std::make_tuple(
|
static const NamedCommandSequence kDrainOutSyncSeq =
|
||||||
std::string("Drain"), 0, StreamTypeFilter::SYNC, makeDrainOutCommands(true));
|
std::make_tuple(std::string("Drain"), 0, StreamTypeFilter::SYNC, makeDrainOutCommands(true),
|
||||||
static const NamedCommandSequence kDrainOutAsyncSeq = std::make_tuple(
|
false /*validatePositionIncrease*/);
|
||||||
std::string("Drain"), 0, StreamTypeFilter::ASYNC, makeDrainOutCommands(false));
|
static const NamedCommandSequence kDrainOutAsyncSeq =
|
||||||
|
std::make_tuple(std::string("Drain"), 0, StreamTypeFilter::ASYNC,
|
||||||
|
makeDrainOutCommands(false), false /*validatePositionIncrease*/);
|
||||||
|
|
||||||
std::shared_ptr<StateSequence> makeDrainPauseOutCommands(bool isSync) {
|
std::shared_ptr<StateSequence> makeDrainPauseOutCommands(bool isSync) {
|
||||||
using State = StreamDescriptor::State;
|
using State = StreamDescriptor::State;
|
||||||
|
@ -3759,12 +3787,12 @@ std::shared_ptr<StateSequence> makeDrainPauseOutCommands(bool isSync) {
|
||||||
d->makeNode(State::STANDBY, kStartCommand, idle);
|
d->makeNode(State::STANDBY, kStartCommand, idle);
|
||||||
return std::make_shared<StateSequenceFollower>(std::move(d));
|
return std::make_shared<StateSequenceFollower>(std::move(d));
|
||||||
}
|
}
|
||||||
static const NamedCommandSequence kDrainPauseOutSyncSeq =
|
static const NamedCommandSequence kDrainPauseOutSyncSeq = std::make_tuple(
|
||||||
std::make_tuple(std::string("DrainPause"), kStreamTransientStateTransitionDelayMs,
|
std::string("DrainPause"), kStreamTransientStateTransitionDelayMs, StreamTypeFilter::SYNC,
|
||||||
StreamTypeFilter::SYNC, makeDrainPauseOutCommands(true));
|
makeDrainPauseOutCommands(true), false /*validatePositionIncrease*/);
|
||||||
static const NamedCommandSequence kDrainPauseOutAsyncSeq =
|
static const NamedCommandSequence kDrainPauseOutAsyncSeq = std::make_tuple(
|
||||||
std::make_tuple(std::string("DrainPause"), kStreamTransientStateTransitionDelayMs,
|
std::string("DrainPause"), kStreamTransientStateTransitionDelayMs, StreamTypeFilter::ASYNC,
|
||||||
StreamTypeFilter::ASYNC, makeDrainPauseOutCommands(false));
|
makeDrainPauseOutCommands(false), false /*validatePositionIncrease*/);
|
||||||
|
|
||||||
// This sequence also verifies that the capture / presentation position is not reset on standby.
|
// This sequence also verifies that the capture / presentation position is not reset on standby.
|
||||||
std::shared_ptr<StateSequence> makeStandbyCommands(bool isInput, bool isSync) {
|
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));
|
return std::make_shared<StateSequenceFollower>(std::move(d));
|
||||||
}
|
}
|
||||||
static const NamedCommandSequence kStandbyInSeq = std::make_tuple(
|
static const NamedCommandSequence kStandbyInSeq =
|
||||||
std::string("Standby"), 0, StreamTypeFilter::ANY, makeStandbyCommands(true, false));
|
std::make_tuple(std::string("Standby"), 0, StreamTypeFilter::ANY,
|
||||||
static const NamedCommandSequence kStandbyOutSyncSeq = std::make_tuple(
|
makeStandbyCommands(true, false), false /*validatePositionIncrease*/);
|
||||||
std::string("Standby"), 0, StreamTypeFilter::SYNC, makeStandbyCommands(false, true));
|
static const NamedCommandSequence kStandbyOutSyncSeq =
|
||||||
static const NamedCommandSequence kStandbyOutAsyncSeq =
|
std::make_tuple(std::string("Standby"), 0, StreamTypeFilter::SYNC,
|
||||||
std::make_tuple(std::string("Standby"), kStreamTransientStateTransitionDelayMs,
|
makeStandbyCommands(false, true), false /*validatePositionIncrease*/);
|
||||||
StreamTypeFilter::ASYNC, makeStandbyCommands(false, false));
|
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) {
|
std::shared_ptr<StateSequence> makePauseCommands(bool isInput, bool isSync) {
|
||||||
using State = StreamDescriptor::State;
|
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));
|
return std::make_shared<StateSequenceFollower>(std::move(d));
|
||||||
}
|
}
|
||||||
static const NamedCommandSequence kPauseInSeq = std::make_tuple(
|
static const NamedCommandSequence kPauseInSeq =
|
||||||
std::string("Pause"), 0, StreamTypeFilter::ANY, makePauseCommands(true, false));
|
std::make_tuple(std::string("Pause"), 0, StreamTypeFilter::ANY,
|
||||||
static const NamedCommandSequence kPauseOutSyncSeq = std::make_tuple(
|
makePauseCommands(true, false), false /*validatePositionIncrease*/);
|
||||||
std::string("Pause"), 0, StreamTypeFilter::SYNC, makePauseCommands(false, true));
|
static const NamedCommandSequence kPauseOutSyncSeq =
|
||||||
static const NamedCommandSequence kPauseOutAsyncSeq =
|
std::make_tuple(std::string("Pause"), 0, StreamTypeFilter::SYNC,
|
||||||
std::make_tuple(std::string("Pause"), kStreamTransientStateTransitionDelayMs,
|
makePauseCommands(false, true), false /*validatePositionIncrease*/);
|
||||||
StreamTypeFilter::ASYNC, makePauseCommands(false, false));
|
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) {
|
std::shared_ptr<StateSequence> makeFlushCommands(bool isInput, bool isSync) {
|
||||||
using State = StreamDescriptor::State;
|
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));
|
return std::make_shared<StateSequenceFollower>(std::move(d));
|
||||||
}
|
}
|
||||||
static const NamedCommandSequence kFlushInSeq = std::make_tuple(
|
static const NamedCommandSequence kFlushInSeq =
|
||||||
std::string("Flush"), 0, StreamTypeFilter::ANY, makeFlushCommands(true, false));
|
std::make_tuple(std::string("Flush"), 0, StreamTypeFilter::ANY,
|
||||||
static const NamedCommandSequence kFlushOutSyncSeq = std::make_tuple(
|
makeFlushCommands(true, false), false /*validatePositionIncrease*/);
|
||||||
std::string("Flush"), 0, StreamTypeFilter::SYNC, makeFlushCommands(false, true));
|
static const NamedCommandSequence kFlushOutSyncSeq =
|
||||||
static const NamedCommandSequence kFlushOutAsyncSeq =
|
std::make_tuple(std::string("Flush"), 0, StreamTypeFilter::SYNC,
|
||||||
std::make_tuple(std::string("Flush"), kStreamTransientStateTransitionDelayMs,
|
makeFlushCommands(false, true), false /*validatePositionIncrease*/);
|
||||||
StreamTypeFilter::ASYNC, makeFlushCommands(false, false));
|
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) {
|
std::shared_ptr<StateSequence> makeDrainPauseFlushOutCommands(bool isSync) {
|
||||||
using State = StreamDescriptor::State;
|
using State = StreamDescriptor::State;
|
||||||
|
@ -3906,10 +3940,12 @@ std::shared_ptr<StateSequence> makeDrainPauseFlushOutCommands(bool isSync) {
|
||||||
}
|
}
|
||||||
static const NamedCommandSequence kDrainPauseFlushOutSyncSeq =
|
static const NamedCommandSequence kDrainPauseFlushOutSyncSeq =
|
||||||
std::make_tuple(std::string("DrainPauseFlush"), kStreamTransientStateTransitionDelayMs,
|
std::make_tuple(std::string("DrainPauseFlush"), kStreamTransientStateTransitionDelayMs,
|
||||||
StreamTypeFilter::SYNC, makeDrainPauseFlushOutCommands(true));
|
StreamTypeFilter::SYNC, makeDrainPauseFlushOutCommands(true),
|
||||||
|
false /*validatePositionIncrease*/);
|
||||||
static const NamedCommandSequence kDrainPauseFlushOutAsyncSeq =
|
static const NamedCommandSequence kDrainPauseFlushOutAsyncSeq =
|
||||||
std::make_tuple(std::string("DrainPauseFlush"), kStreamTransientStateTransitionDelayMs,
|
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.
|
// Note, this isn't the "official" enum printer, it is only used to make the test name suffix.
|
||||||
std::string PrintStreamFilterToString(StreamTypeFilter filter) {
|
std::string PrintStreamFilterToString(StreamTypeFilter filter) {
|
||||||
|
|
|
@ -25,6 +25,11 @@
|
||||||
<option name="teardown-command" value="setprop vts.native_server.on 0"/>
|
<option name="teardown-command" value="setprop vts.native_server.on 0"/>
|
||||||
</target_preparer>
|
</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" >
|
<test class="com.android.tradefed.testtype.GTest" >
|
||||||
<option name="native-test-device-path" value="/data/local/tmp" />
|
<option name="native-test-device-path" value="/data/local/tmp" />
|
||||||
<option name="module-name" value="VtsHalAudioCoreTargetTest" />
|
<option name="module-name" value="VtsHalAudioCoreTargetTest" />
|
||||||
|
|
Loading…
Reference in a new issue