From 688b88189e87e7cfeca9e51040f0842d48a1414b Mon Sep 17 00:00:00 2001 From: Konsta Date: Sat, 25 Oct 2025 21:41:15 +0300 Subject: [PATCH] audio: probe pcm card from property * Valid values for the audio device property are 'jack', 'hdmi0', 'hdmi1', and 'dac'. * If 'jack' is selected, first PCM card with name 'Headphones' is used. If 'dac' is selected, first PCM card that doesn't match the name for 3.5mm or HDMI devices is used. HDMI audio uses virtual ALSA devices instead of using tinyalsa to open a PCM card directly. * Allow forcing specific PCM card for debugging/development purposes. * PCM card numbers are different between Pi 4 and Pi 5 and order can change depending on the DAC driver that's enabled. Pi 4: console:/ # cat /proc/asound/cards 0 [Headphones ]: bcm2835_headpho - bcm2835 Headphones bcm2835 Headphones 1 [vc4hdmi0 ]: vc4-hdmi - vc4-hdmi-0 vc4-hdmi-0 2 [vc4hdmi1 ]: vc4-hdmi - vc4-hdmi-1 vc4-hdmi-1 Pi 5 with DAC: console:/ # cat /proc/asound/cards 0 [vc4hdmi0 ]: vc4-hdmi - vc4-hdmi-0 vc4-hdmi-0 1 [vc4hdmi1 ]: vc4-hdmi - vc4-hdmi-1 vc4-hdmi-1 2 [sndrpihifiberry]: HifiberryDacp - snd_rpi_hifiberry_dacplus snd_rpi_hifiberry_dacplus --- audio/include/core-impl/StreamPrimary.h | 2 ++ audio/primary/StreamPrimary.cpp | 43 ++++++++++++++++++++++++- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/audio/include/core-impl/StreamPrimary.h b/audio/include/core-impl/StreamPrimary.h index 06f8bc3..a566d8c 100644 --- a/audio/include/core-impl/StreamPrimary.h +++ b/audio/include/core-impl/StreamPrimary.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2023 The Android Open Source Project + * Copyright (C) 2025 KonstaKANG * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -63,6 +64,7 @@ class StreamPrimary : public StreamAlsa { static constexpr StreamPrimary::AlsaDeviceId kStubDeviceId{ primary::PrimaryMixer::kInvalidAlsaCard, primary::PrimaryMixer::kInvalidAlsaDevice}; + static AlsaDeviceId getCardId(); static AlsaDeviceId getCardAndDeviceId( const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices); static bool useStubStream(bool isInput, diff --git a/audio/primary/StreamPrimary.cpp b/audio/primary/StreamPrimary.cpp index 8455680..7a2b0c8 100644 --- a/audio/primary/StreamPrimary.cpp +++ b/audio/primary/StreamPrimary.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2023 The Android Open Source Project + * Copyright (C) 2025 KonstaKANG * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,6 +19,7 @@ #include +#include #include #include #include @@ -36,6 +38,8 @@ 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; +using android::base::GetProperty; +using android::base::ReadFileToString; namespace aidl::android::hardware::audio::core { @@ -150,7 +154,7 @@ ndk::ScopedAStatus StreamPrimary::setConnectedDevices(const ConnectedDevices& de { const bool useStubDriver = devices.empty() || useStubStream(mIsInput, devices[0]); std::lock_guard l(mLock); - mAlsaDeviceId = useStubDriver ? kStubDeviceId : getCardAndDeviceId(devices); + mAlsaDeviceId = useStubDriver ? kStubDeviceId : getCardId(); } if (!devices.empty()) { auto streamDataProcessor = getContext().getStreamDataProcessor().lock(); @@ -173,6 +177,43 @@ bool StreamPrimary::isStubStream() { return mAlsaDeviceId == kStubDeviceId; } +// static +StreamPrimary::AlsaDeviceId StreamPrimary::getCardId() { + AlsaDeviceId cardAndDeviceId; + cardAndDeviceId.second = 0; + + const std::string forceCard = GetProperty("persist.vendor.audio.pcm.card", "-1"); + if (forceCard != "-1") { + int cardId = std::stoi(forceCard.c_str()); + LOG(INFO) << "Forcing PCM card " << cardId; + cardAndDeviceId.first = cardId; + return cardAndDeviceId; + } + + const std::string deviceName = GetProperty("persist.vendor.audio.device", "hdmi0"); + std::string cardPath; + for (int i = 0; i < 8; i++) { + cardPath = "/proc/asound/card" + std::to_string(i) + "/id"; + std::string cardName; + if (ReadFileToString(cardPath, &cardName)) { + if (deviceName == "jack" && cardName.starts_with("Headphones")) { + LOG(INFO) << "Using PCM card " << i << " for 3.5mm audio jack"; + cardAndDeviceId.first = i; + return cardAndDeviceId; + } else if (deviceName == "dac" && !cardName.starts_with("Headphones") + && !cardName.starts_with("vc4hdmi")) { + LOG(INFO) << "Using PCM card " << i << " for audio DAC " << cardName; + cardAndDeviceId.first = i; + return cardAndDeviceId; + } + } + } + + LOG(INFO) << "Could not probe PCM card for " << deviceName << ", falling back to PCM card 0"; + cardAndDeviceId.first = 0; + return cardAndDeviceId; +} + // static StreamPrimary::AlsaDeviceId StreamPrimary::getCardAndDeviceId( const std::vector& devices) {