Send playback mute events from audio server
The events are sent by the AudioFlinger which communicates directly
through oneway ipc methods with the AudioService. The mute reasons are
described with a PersistableBundle to keep the interface generic for future
extensions.
Test: dumpsys audio
Bug: 235521198
Change-Id: I82cf7100a80e3fc71b629739ce5a5701ab3afc84
diff --git a/services/audioflinger/Android.bp b/services/audioflinger/Android.bp
index a08879e..420ae52 100644
--- a/services/audioflinger/Android.bp
+++ b/services/audioflinger/Android.bp
@@ -71,6 +71,7 @@
"liblog",
"libbinder",
"libaudioclient",
+ "libaudiomanager",
"libmedialogservice",
"libmediametrics",
"libmediautils",
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 7a9027c..a68f63e 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -54,7 +54,7 @@
#include <cutils/properties.h>
#include <system/audio.h>
-#include <audiomanager/AudioManager.h>
+#include <audiomanager/IAudioManager.h>
#include "AudioFlinger.h"
#include "NBAIO_Tee.h"
@@ -114,11 +114,12 @@
using media::audio::common::AudioMMapPolicyType;
using android::content::AttributionSourceState;
-static const char kDeadlockedString[] = "AudioFlinger may be deadlocked\n";
-static const char kHardwareLockedString[] = "Hardware lock is taken\n";
-static const char kClientLockedString[] = "Client lock is taken\n";
-static const char kNoEffectsFactory[] = "Effects Factory is absent\n";
+static constexpr char kDeadlockedString[] = "AudioFlinger may be deadlocked\n";
+static constexpr char kHardwareLockedString[] = "Hardware lock is taken\n";
+static constexpr char kClientLockedString[] = "Client lock is taken\n";
+static constexpr char kNoEffectsFactory[] = "Effects Factory is absent\n";
+static constexpr char kAudioServiceName[] = "audio";
nsecs_t AudioFlinger::mStandbyTimeInNsecs = kDefaultStandbyTimeInNsecs;
@@ -2722,9 +2723,28 @@
ThreadBase *thread = (ThreadBase *)mMmapThreads.valueAt(i).get();
thread->systemReady();
}
+
+ // Java services are ready, so we can create a reference to AudioService
+ getOrCreateAudioManager();
+
return NO_ERROR;
}
+sp<IAudioManager> AudioFlinger::getOrCreateAudioManager()
+{
+ if (mAudioManager.load() == nullptr) {
+ // use checkService() to avoid blocking
+ sp<IBinder> binder =
+ defaultServiceManager()->checkService(String16(kAudioServiceName));
+ if (binder != nullptr) {
+ mAudioManager = interface_cast<IAudioManager>(binder);
+ } else {
+ ALOGE("%s(): binding to audio service failed.", __func__);
+ }
+ }
+ return mAudioManager.load();
+}
+
status_t AudioFlinger::getMicrophones(std::vector<media::MicrophoneInfo> *microphones)
{
AutoMutex lock(mHardwareLock);
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index fc4c807..08594e2 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -117,6 +117,7 @@
class DevicesFactoryHalInterface;
class EffectsFactoryHalInterface;
class FastMixer;
+class IAudioManager;
class PassthruBufferProvider;
class RecordBufferConverter;
class ServerProxy;
@@ -988,6 +989,8 @@
size_t rejectedKVPSize, const String8& rejectedKVPs,
uid_t callingUid);
+ sp<IAudioManager> getOrCreateAudioManager();
+
public:
// These methods read variables atomically without mLock,
// though the variables are updated with mLock.
@@ -1029,6 +1032,9 @@
std::vector<media::audio::common::AudioMMapPolicyInfo>> mPolicyInfos;
int32_t mAAudioBurstsPerBuffer = 0;
int32_t mAAudioHwBurstMinMicros = 0;
+
+ /** Interface for interacting with the AudioService. */
+ mediautils::atomic_sp<IAudioManager> mAudioManager;
};
#undef INCLUDING_FROM_AUDIOFLINGER_H
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index 6a138bb..e52d1ee 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -204,6 +204,12 @@
float getSpeed() const { return mSpeed; }
bool isSpatialized() const override { return mIsSpatialized; }
+ /**
+ * Updates the mute state and notifies the audio service. Call this only when holding player
+ * thread lock.
+ */
+ void processMuteEvent_l(const sp<IAudioManager>& audioManager, mute_state_t muteState);
+
protected:
// for numerous
friend class PlaybackThread;
@@ -354,6 +360,11 @@
TeePatches mTeePatches;
const float mSpeed;
const bool mIsSpatialized;
+
+ // TODO: replace PersistableBundle with own struct
+ // access these two variables only when holding player thread lock.
+ std::unique_ptr<os::PersistableBundle> mMuteEventExtras;
+ mute_state_t mMuteState;
}; // end of Track
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 348343e..77e2421 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -31,6 +31,7 @@
#include <sys/syscall.h>
#include <cutils/bitops.h>
#include <cutils/properties.h>
+#include <binder/PersistableBundle.h>
#include <media/AudioContainers.h>
#include <media/AudioDeviceTypeAddr.h>
#include <media/AudioParameter.h>
@@ -5375,6 +5376,12 @@
volume = masterVolume * mStreamTypes[track->streamType()].volume;
}
+ track->processMuteEvent_l(mAudioFlinger->getOrCreateAudioManager(),
+ /*muteState=*/{masterVolume == 0.f,
+ mStreamTypes[track->streamType()].volume == 0.f,
+ mStreamTypes[track->streamType()].mute,
+ track->isPlaybackRestricted()});
+
handleVoipVolume_l(&volume);
// cache the combined master volume and stream type volume for fast mixer; this
@@ -5539,6 +5546,12 @@
v = 0;
}
+ track->processMuteEvent_l(mAudioFlinger->getOrCreateAudioManager(),
+ /*muteState=*/{masterVolume == 0.f,
+ mStreamTypes[track->streamType()].volume == 0.f,
+ mStreamTypes[track->streamType()].mute,
+ track->isPlaybackRestricted()});
+
handleVoipVolume_l(&v);
if (track->isPausing()) {
@@ -6169,6 +6182,12 @@
right *= v * mMasterBalanceRight;
}
+ track->processMuteEvent_l(mAudioFlinger->getOrCreateAudioManager(),
+ /*muteState=*/{mMasterMute,
+ mStreamTypes[track->streamType()].volume == 0.f,
+ mStreamTypes[track->streamType()].mute,
+ track->isPlaybackRestricted()});
+
if (lastTrack) {
track->setFinalVolume((left + right) / 2.f);
if (left != mLeftVolFloat || right != mRightVolFloat) {
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 6c0d81c..b477d65 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -624,7 +624,7 @@
virtual void dumpTracks_l(int fd __unused, const Vector<String16>& args __unused) { }
- friend class AudioFlinger; // for mEffectChains
+ friend class AudioFlinger; // for mEffectChains and mAudioManager
const type_t mType;
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 47590ce..3f9c306 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -1494,6 +1494,39 @@
}
}
+// must be called with player thread lock held
+void AudioFlinger::PlaybackThread::Track::processMuteEvent_l(const sp<
+ IAudioManager>& audioManager, mute_state_t muteState)
+{
+ if (mMuteState == muteState) {
+ // mute state did not change, do nothing
+ return;
+ }
+
+ status_t result = UNKNOWN_ERROR;
+ if (audioManager && mPortId != AUDIO_PORT_HANDLE_NONE) {
+ if (mMuteEventExtras == nullptr) {
+ mMuteEventExtras = std::make_unique<os::PersistableBundle>();
+ }
+ mMuteEventExtras->putInt(String16(kExtraPlayerEventMuteKey),
+ static_cast<int>(muteState));
+
+ result = audioManager->portEvent(mPortId,
+ PLAYER_UPDATE_MUTED,
+ mMuteEventExtras);
+ }
+
+ if (result == OK) {
+ mMuteState = muteState;
+ } else {
+ ALOGW("%s(%d): cannot process mute state for port ID %d, status error %d",
+ __func__,
+ id(),
+ mPortId,
+ result);
+ }
+}
+
status_t AudioFlinger::PlaybackThread::Track::getTimestamp(AudioTimestamp& timestamp)
{
if (!isOffloaded() && !isDirect()) {