audiopolicy: rework stream activity for volume management on output
-Manage duplicated output ref count in client itself
-Use VolumeSource to track volume activity in output
(today mapped on legacy stream type)
-Use accessor APIs to control activity/mute from apm.
Test: audio smoke tests
Bug: 124767636
Change-Id: I452e3973f6869d41231d984896a5886ebb86afb1
Signed-off-by: François Gaffie <francois.gaffie@renault.com>
diff --git a/services/audiopolicy/common/include/Volume.h b/services/audiopolicy/common/include/Volume.h
index 5ccc8fd..a3b6b36 100644
--- a/services/audiopolicy/common/include/Volume.h
+++ b/services/audiopolicy/common/include/Volume.h
@@ -20,6 +20,22 @@
#include <utils/Log.h>
#include <math.h>
+namespace android {
+/**
+ * VolumeSource is the discriminent for volume management on an output.
+ * It used to be the stream type by legacy, it may be host volume group or a volume curves if
+ * we allow to have more than one curve per volume group.
+ */
+enum VolumeSource : std::underlying_type<audio_stream_type_t>::type;
+static const VolumeSource VOLUME_SOURCE_NONE = static_cast<VolumeSource>(AUDIO_STREAM_DEFAULT);
+
+static inline VolumeSource streamToVolumeSource(audio_stream_type_t stream) {
+ return static_cast<VolumeSource>(stream);
+}
+
+
+} // namespace android
+
// Absolute min volume in dB (can be represented in single precision normal float value)
#define VOLUME_MIN_DB (-758)
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
index c84636e..cf9519b 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
@@ -73,7 +73,7 @@
virtual void dump(String8 *dst, int spaces) const
{
- dst->appendFormat("%*s- ActivityCount: %d, StopTime: %" PRId64 " \n", spaces, "",
+ dst->appendFormat("%*s- ActivityCount: %d, StopTime: %" PRId64 ", ", spaces, "",
getActivityCount(), getStopTime());
}
private:
@@ -82,6 +82,37 @@
};
/**
+ * @brief VolumeActivity: it tracks the activity for volume policy (volume index, mute,
+ * memorize previous stop, and store mute if incompatible device with another strategy.
+ */
+class VolumeActivity : public ActivityTracking
+{
+public:
+ bool isMuted() const { return mMuteCount > 0; }
+ int getMuteCount() const { return mMuteCount; }
+ int incMuteCount() { return ++mMuteCount; }
+ int decMuteCount() { return mMuteCount > 0 ? --mMuteCount : -1; }
+
+ void dump(String8 *dst, int spaces) const override
+ {
+ ActivityTracking::dump(dst, spaces);
+ dst->appendFormat(", Volume: %.03f, MuteCount: %02d\n", mCurVolumeDb, mMuteCount);
+ }
+ void setVolume(float volume) { mCurVolumeDb = volume; }
+ float getVolume() const { return mCurVolumeDb; }
+
+private:
+ int mMuteCount = 0; /**< mute request counter */
+ float mCurVolumeDb = NAN; /**< current volume in dB. */
+};
+/**
+ * Note: volume activities shall be indexed by CurvesId if we want to allow multiple
+ * curves per volume group, inferring a mute management or volume balancing between HW and SW is
+ * done
+ */
+using VolumeActivities = std::map<VolumeSource, VolumeActivity>;
+
+/**
* @brief The Activity class: it tracks the activity for volume policy (volume index, mute,
* memorize previous stop, and store mute if incompatible device with another strategy.
* Having this class prevents from looping on all attributes (legacy streams) of the strategy
@@ -92,6 +123,10 @@
void setMutedByDevice( bool isMuted) { mIsMutedByDevice = isMuted; }
bool isMutedByDevice() const { return mIsMutedByDevice; }
+ void dump(String8 *dst, int spaces) const override {
+ ActivityTracking::dump(dst, spaces);
+ dst->appendFormat("\n");
+ }
private:
/**
* strategies muted because of incompatible device selection.
@@ -128,15 +163,6 @@
bool force);
/**
- * Changes the stream active count and mActiveClients only.
- * This does not change the client->active() state or the output descriptor's
- * global active count.
- */
- virtual void changeStreamActiveCount(const sp<TrackClientDescriptor>& client, int delta);
- uint32_t streamActiveCount(audio_stream_type_t stream) const
- { return mActiveCount[stream]; }
-
- /**
* @brief setStopTime set the stop time due to the client stoppage or a re routing of this
* client
* @param client to be considered
@@ -148,13 +174,61 @@
* Changes the client->active() state and the output descriptor's global active count,
* along with the stream active count and mActiveClients.
* The client must be previously added by the base class addClient().
+ * In case of duplicating thread, client shall be added on the duplicated thread, not on the
+ * involved outputs but setClientActive will be called on all output to track strategy and
+ * active client for a given output.
+ * Active ref count of the client will be incremented/decremented through setActive API
*/
- void setClientActive(const sp<TrackClientDescriptor>& client, bool active);
+ virtual void setClientActive(const sp<TrackClientDescriptor>& client, bool active);
- bool isActive(uint32_t inPastMs = 0) const;
- bool isStreamActive(audio_stream_type_t stream,
- uint32_t inPastMs = 0,
- nsecs_t sysTime = 0) const;
+ bool isActive(uint32_t inPastMs) const;
+ bool isActive(VolumeSource volumeSource = VOLUME_SOURCE_NONE,
+ uint32_t inPastMs = 0,
+ nsecs_t sysTime = 0) const;
+ bool isAnyActive(VolumeSource volumeSourceToIgnore) const;
+
+ std::vector<VolumeSource> getActiveVolumeSources() const {
+ std::vector<VolumeSource> activeList;
+ for (const auto &iter : mVolumeActivities) {
+ if (iter.second.isActive()) {
+ activeList.push_back(iter.first);
+ }
+ }
+ return activeList;
+ }
+ uint32_t getActivityCount(VolumeSource vs) const
+ {
+ return mVolumeActivities.find(vs) != std::end(mVolumeActivities)?
+ mVolumeActivities.at(vs).getActivityCount() : 0;
+ }
+ bool isMuted(VolumeSource vs) const
+ {
+ return mVolumeActivities.find(vs) != std::end(mVolumeActivities)?
+ mVolumeActivities.at(vs).isMuted() : false;
+ }
+ int getMuteCount(VolumeSource vs) const
+ {
+ return mVolumeActivities.find(vs) != std::end(mVolumeActivities)?
+ mVolumeActivities.at(vs).getMuteCount() : 0;
+ }
+ int incMuteCount(VolumeSource vs)
+ {
+ return mVolumeActivities[vs].incMuteCount();
+ }
+ int decMuteCount(VolumeSource vs)
+ {
+ return mVolumeActivities[vs].decMuteCount();
+ }
+ void setCurVolume(VolumeSource vs, float volume)
+ {
+ // Even if not activity for this group registered, need to create anyway
+ mVolumeActivities[vs].setVolume(volume);
+ }
+ float getCurVolume(VolumeSource vs) const
+ {
+ return mVolumeActivities.find(vs) != std::end(mVolumeActivities) ?
+ mVolumeActivities.at(vs).getVolume() : NAN;
+ }
bool isStrategyActive(product_strategy_t ps, uint32_t inPastMs = 0, nsecs_t sysTime = 0) const
{
@@ -195,40 +269,36 @@
// it is possible that when a client is removed, we could remove its
// associated active count by calling changeStreamActiveCount(),
// but that would be hiding a problem, so we log fatal instead.
- auto it2 = mActiveClients.find(client);
- LOG_ALWAYS_FATAL_IF(it2 != mActiveClients.end(),
- "%s(%d) removing client portId %d which is active (count %zu)",
- __func__, mId, portId, it2->second);
+ auto clientIter = std::find(begin(mActiveClients), end(mActiveClients), client);
+ LOG_ALWAYS_FATAL_IF(clientIter != mActiveClients.end(),
+ "%s(%d) removing client portId %d which is active (count %d)",
+ __func__, mId, portId, client->getActivityCount());
ClientMapHandler<TrackClientDescriptor>::removeClient(portId);
}
- using ActiveClientMap = std::map<sp<TrackClientDescriptor>, size_t /* count */>;
- // required for duplicating thread
- const ActiveClientMap& getActiveClients() const {
+ const TrackClientVector& getActiveClients() const {
return mActiveClients;
}
DeviceVector mDevices; /**< current devices this output is routed to */
- nsecs_t mStopTime[AUDIO_STREAM_CNT];
- int mMuteCount[AUDIO_STREAM_CNT]; // mute request counter
AudioMix *mPolicyMix = nullptr; // non NULL when used by a dynamic policy
protected:
const sp<AudioPort> mPort;
AudioPolicyClientInterface * const mClientInterface;
- float mCurVolume[AUDIO_STREAM_CNT]; // current stream volume in dB
- uint32_t mActiveCount[AUDIO_STREAM_CNT]; // number of streams of each type active on this output
uint32_t mGlobalActiveCount = 0; // non-client-specific active count
audio_patch_handle_t mPatchHandle = AUDIO_PATCH_HANDLE_NONE;
audio_port_handle_t mId = AUDIO_PORT_HANDLE_NONE;
- // The ActiveClientMap shows the clients that contribute to the streams counts
+ // The ActiveClients shows the clients that contribute to the @VolumeSource counts
// and may include upstream clients from a duplicating thread.
// Compare with the ClientMap (mClients) which are external AudioTrack clients of the
// output descriptor (and do not count internal PatchTracks).
- ActiveClientMap mActiveClients;
+ TrackClientVector mActiveClients;
RoutingActivities mRoutingActivities; /**< track routing activity on this ouput.*/
+
+ VolumeActivities mVolumeActivities; /**< track volume activity on this ouput.*/
};
// Audio output driven by a software mixer in audio flinger.
@@ -250,8 +320,13 @@
virtual bool isFixedVolume(audio_devices_t device);
sp<SwAudioOutputDescriptor> subOutput1() { return mOutput1; }
sp<SwAudioOutputDescriptor> subOutput2() { return mOutput2; }
- void changeStreamActiveCount(
- const sp<TrackClientDescriptor>& client, int delta) override;
+ void setClientActive(const sp<TrackClientDescriptor>& client, bool active) override;
+ void setAllClientsInactive()
+ {
+ for (const auto &client : clientsList(true)) {
+ setClientActive(client, false);
+ }
+ }
virtual bool setVolume(float volume,
audio_stream_type_t stream,
audio_devices_t device,
@@ -344,25 +419,27 @@
public DefaultKeyedVector< audio_io_handle_t, sp<SwAudioOutputDescriptor> >
{
public:
- bool isStreamActive(audio_stream_type_t stream, uint32_t inPastMs = 0) const;
+ bool isActive(VolumeSource volumeSource, uint32_t inPastMs = 0) const;
/**
- * return whether a stream is playing remotely, override to change the definition of
+ * return whether any source contributing to VolumeSource is playing remotely, override
+ * to change the definition of
* local/remote playback, used for instance by notification manager to not make
* media players lose audio focus when not playing locally
* For the base implementation, "remotely" means playing during screen mirroring which
* uses an output for playback with a non-empty, non "0" address.
*/
- bool isStreamActiveRemotely(audio_stream_type_t stream, uint32_t inPastMs = 0) const;
+ bool isActiveRemotely(VolumeSource volumeSource, uint32_t inPastMs = 0) const;
/**
- * return whether a stream is playing, but not on a "remote" device.
+ * return whether any source contributing to VolumeSource is playing, but not on a "remote"
+ * device.
* Override to change the definition of a local/remote playback.
* Used for instance by policy manager to alter the speaker playback ("speaker safe" behavior)
* when media plays or not locally.
* For the base implementation, "remotely" means playing during screen mirroring.
*/
- bool isStreamActiveLocally(audio_stream_type_t stream, uint32_t inPastMs = 0) const;
+ bool isActiveLocally(VolumeSource volumeSource, uint32_t inPastMs = 0) const;
/**
* @brief isStrategyActiveOnSameModule checks if the given strategy is active (or was active
@@ -409,9 +486,21 @@
sp<SwAudioOutputDescriptor> getPrimaryOutput() const;
/**
- * return true if any output is playing anything besides the stream to ignore
+ * @brief isAnyOutputActive checks if any output is active (aka playing) except the one(s) that
+ * hold the volume source to be ignored
+ * @param volumeSourceToIgnore source not considered in the activity detection
+ * @return true if any output is active for any source except the one to be ignored
*/
- bool isAnyOutputActive(audio_stream_type_t streamToIgnore) const;
+ bool isAnyOutputActive(VolumeSource volumeSourceToIgnore) const
+ {
+ for (size_t i = 0; i < size(); i++) {
+ const sp<AudioOutputDescriptor> &outputDesc = valueAt(i);
+ if (outputDesc->isAnyActive(volumeSourceToIgnore)) {
+ return true;
+ }
+ }
+ return false;
+ }
audio_devices_t getSupportedDevices(audio_io_handle_t handle) const;
@@ -424,12 +513,24 @@
public DefaultKeyedVector< audio_io_handle_t, sp<HwAudioOutputDescriptor> >
{
public:
- bool isStreamActive(audio_stream_type_t stream, uint32_t inPastMs = 0) const;
+ bool isActive(VolumeSource volumeSource, uint32_t inPastMs = 0) const;
/**
- * return true if any output is playing anything besides the stream to ignore
+ * @brief isAnyOutputActive checks if any output is active (aka playing) except the one(s) that
+ * hold the volume source to be ignored
+ * @param volumeSourceToIgnore source not considered in the activity detection
+ * @return true if any output is active for any source except the one to be ignored
*/
- bool isAnyOutputActive(audio_stream_type_t streamToIgnore) const;
+ bool isAnyOutputActive(VolumeSource volumeSourceToIgnore) const
+ {
+ for (size_t i = 0; i < size(); i++) {
+ const sp<AudioOutputDescriptor> &outputDesc = valueAt(i);
+ if (outputDesc->isAnyActive(volumeSourceToIgnore)) {
+ return true;
+ }
+ }
+ return false;
+ }
void dump(String8 *dst) const;
};
diff --git a/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
index 2e44a60..4bb225d 100644
--- a/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
@@ -28,6 +28,7 @@
#include <utils/RefBase.h>
#include <utils/String8.h>
#include <policy.h>
+#include <Volume.h>
#include "AudioPatch.h"
#include "EffectDescriptor.h"
@@ -62,7 +63,7 @@
mPreferredDeviceId = preferredDeviceId;
}
bool isPreferredDeviceForExclusiveUse() const { return mPreferredDeviceForExclusiveUse; }
- void setActive(bool active) { mActive = active; }
+ virtual void setActive(bool active) { mActive = active; }
bool active() const { return mActive; }
bool hasPreferredDevice(bool activeOnly = false) const {
return mPreferredDeviceId != AUDIO_PORT_HANDLE_NONE && (!activeOnly || mActive);
@@ -85,12 +86,13 @@
TrackClientDescriptor(audio_port_handle_t portId, uid_t uid, audio_session_t sessionId,
audio_attributes_t attributes, audio_config_base_t config,
audio_port_handle_t preferredDeviceId, audio_stream_type_t stream,
- product_strategy_t strategy, audio_output_flags_t flags,
+ product_strategy_t strategy, VolumeSource volumeSource,
+ audio_output_flags_t flags,
bool isPreferredDeviceForExclusiveUse,
std::vector<wp<SwAudioOutputDescriptor>> secondaryOutputs) :
ClientDescriptor(portId, uid, sessionId, attributes, config, preferredDeviceId,
isPreferredDeviceForExclusiveUse),
- mStream(stream), mStrategy(strategy), mFlags(flags),
+ mStream(stream), mStrategy(strategy), mVolumeSource(volumeSource), mFlags(flags),
mSecondaryOutputs(std::move(secondaryOutputs)) {}
~TrackClientDescriptor() override = default;
@@ -104,12 +106,41 @@
const std::vector<wp<SwAudioOutputDescriptor>>& getSecondaryOutputs() const {
return mSecondaryOutputs;
};
+ VolumeSource volumeSource() const { return mVolumeSource; }
+
+ void setActive(bool active) override
+ {
+ int delta = active ? 1 : -1;
+ changeActivityCount(delta);
+ }
+ void changeActivityCount(int delta)
+ {
+ if (delta > 0) {
+ mActivityCount += delta;
+ } else {
+ LOG_ALWAYS_FATAL_IF(!mActivityCount, "%s(%s) invalid delta %d, inactive client",
+ __func__, toShortString().c_str(), delta);
+ LOG_ALWAYS_FATAL_IF(static_cast<int>(mActivityCount) < -delta,
+ "%s(%s) invalid delta %d, active client count %d",
+ __func__, toShortString().c_str(), delta, mActivityCount);
+ mActivityCount += delta;
+ }
+ ClientDescriptor::setActive(mActivityCount > 0);
+ }
+ uint32_t getActivityCount() const { return mActivityCount; }
private:
const audio_stream_type_t mStream;
const product_strategy_t mStrategy;
+ const VolumeSource mVolumeSource;
const audio_output_flags_t mFlags;
const std::vector<wp<SwAudioOutputDescriptor>> mSecondaryOutputs;
+
+ /**
+ * required for duplicating thread, prevent from removing active client from an output
+ * involved in a duplication.
+ */
+ uint32_t mActivityCount = 0;
};
class RecordClientDescriptor: public ClientDescriptor
@@ -148,7 +179,8 @@
public:
SourceClientDescriptor(audio_port_handle_t portId, uid_t uid, audio_attributes_t attributes,
const sp<AudioPatch>& patchDesc, const sp<DeviceDescriptor>& srcDevice,
- audio_stream_type_t stream, product_strategy_t strategy);
+ audio_stream_type_t stream, product_strategy_t strategy,
+ VolumeSource volumeSource);
~SourceClientDescriptor() override = default;
sp<AudioPatch> patchDesc() const { return mPatchDesc; }
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index 77e7add..7293bc4 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -34,16 +34,8 @@
AudioOutputDescriptor::AudioOutputDescriptor(const sp<AudioPort>& port,
AudioPolicyClientInterface *clientInterface)
- : mPort(port)
- , mClientInterface(clientInterface)
+ : mPort(port), mClientInterface(clientInterface)
{
- // clear usage count for all stream types
- for (int i = 0; i < AUDIO_STREAM_CNT; i++) {
- mActiveCount[i] = 0;
- mCurVolume[i] = -1.0;
- mMuteCount[i] = 0;
- mStopTime[i] = 0;
- }
if (mPort.get() != nullptr) {
mPort->pickAudioProfile(mSamplingRate, mChannelMask, mFormat);
if (mPort->mGains.size() > 0) {
@@ -85,124 +77,73 @@
return hasSameHwModuleAs(outputDesc);
}
-void AudioOutputDescriptor::changeStreamActiveCount(const sp<TrackClientDescriptor>& client,
- int delta)
-{
- if (delta == 0) return;
- const audio_stream_type_t stream = client->stream();
- if ((delta + (int)mActiveCount[stream]) < 0) {
- // any mismatched active count will abort.
- LOG_ALWAYS_FATAL("%s(%s) invalid delta %d, active stream count %d",
- __func__, client->toShortString().c_str(), delta, mActiveCount[stream]);
- // mActiveCount[stream] = 0;
- // return;
- }
- mActiveCount[stream] += delta;
- mRoutingActivities[client->strategy()].changeActivityCount(delta);
-
- if (delta > 0) {
- mActiveClients[client] += delta;
- } else {
- auto it = mActiveClients.find(client);
- if (it == mActiveClients.end()) { // client not found!
- LOG_ALWAYS_FATAL("%s(%s) invalid delta %d, inactive client",
- __func__, client->toShortString().c_str(), delta);
- } else if (it->second < -delta) { // invalid delta!
- LOG_ALWAYS_FATAL("%s(%s) invalid delta %d, active client count %zu",
- __func__, client->toShortString().c_str(), delta, it->second);
- }
- it->second += delta;
- if (it->second == 0) {
- (void)mActiveClients.erase(it);
- }
- }
-
- ALOGV("%s stream %d, count %d", __FUNCTION__, stream, mActiveCount[stream]);
-}
-
void AudioOutputDescriptor::setStopTime(const sp<TrackClientDescriptor>& client, nsecs_t sysTime)
{
- mStopTime[client->stream()] = sysTime;
+ mVolumeActivities[client->volumeSource()].setStopTime(sysTime);
mRoutingActivities[client->strategy()].setStopTime(sysTime);
}
void AudioOutputDescriptor::setClientActive(const sp<TrackClientDescriptor>& client, bool active)
{
- LOG_ALWAYS_FATAL_IF(getClient(client->portId()) == nullptr,
- "%s(%d) does not exist on output descriptor", __func__, client->portId());
-
- if (active == client->active()) {
- ALOGW("%s(%s): ignored active: %d, current stream count %d",
- __func__, client->toShortString().c_str(),
- active, mActiveCount[client->stream()]);
+ auto clientIter = std::find(begin(mActiveClients), end(mActiveClients), client);
+ if (active == (clientIter != end(mActiveClients))) {
+ ALOGW("%s(%s): ignored active: %d, current stream count %d", __func__,
+ client->toShortString().c_str(), active,
+ mRoutingActivities.at(client->strategy()).getActivityCount());
return;
}
+ if (active) {
+ mActiveClients.push_back(client);
+ } else {
+ mActiveClients.erase(clientIter);
+ }
const int delta = active ? 1 : -1;
- changeStreamActiveCount(client, delta);
+ // If ps is unknown, it is time to track it!
+ mRoutingActivities[client->strategy()].changeActivityCount(delta);
+ mVolumeActivities[client->volumeSource()].changeActivityCount(delta);
// Handle non-client-specific activity ref count
int32_t oldGlobalActiveCount = mGlobalActiveCount;
if (!active && mGlobalActiveCount < 1) {
ALOGW("%s(%s): invalid deactivation with globalRefCount %d",
- __func__, client->toShortString().c_str(), mGlobalActiveCount);
+ __func__, client->toShortString().c_str(), mGlobalActiveCount);
mGlobalActiveCount = 1;
}
mGlobalActiveCount += delta;
- if ((oldGlobalActiveCount == 0) && (mGlobalActiveCount > 0)) {
- if ((mPolicyMix != NULL) && ((mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0))
- {
+ if ((mPolicyMix != NULL) && ((mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0)) {
+ if ((oldGlobalActiveCount == 0) || (mGlobalActiveCount == 0)) {
mClientInterface->onDynamicPolicyMixStateUpdate(mPolicyMix->mDeviceAddress,
- MIX_STATE_MIXING);
- }
- } else if ((oldGlobalActiveCount > 0) && (mGlobalActiveCount == 0)) {
- if ((mPolicyMix != NULL) && ((mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0))
- {
- mClientInterface->onDynamicPolicyMixStateUpdate(mPolicyMix->mDeviceAddress,
- MIX_STATE_IDLE);
+ mGlobalActiveCount > 0 ? MIX_STATE_MIXING : MIX_STATE_IDLE);
}
}
-
client->setActive(active);
}
+bool AudioOutputDescriptor::isActive(VolumeSource vs, uint32_t inPastMs, nsecs_t sysTime) const
+{
+ return (vs == VOLUME_SOURCE_NONE) ?
+ isActive(inPastMs) : (mVolumeActivities.find(vs) != std::end(mVolumeActivities)?
+ mVolumeActivities.at(vs).isActive(inPastMs, sysTime) : false);
+}
+
bool AudioOutputDescriptor::isActive(uint32_t inPastMs) const
{
nsecs_t sysTime = 0;
if (inPastMs != 0) {
sysTime = systemTime();
}
- for (int i = 0; i < (int)AUDIO_STREAM_CNT; i++) {
- if (i == AUDIO_STREAM_PATCH) {
+ for (const auto &iter : mVolumeActivities) {
+ if (iter.first == streamToVolumeSource(AUDIO_STREAM_PATCH)) {
continue;
}
- if (isStreamActive((audio_stream_type_t)i, inPastMs, sysTime)) {
+ if (iter.second.isActive(inPastMs, sysTime)) {
return true;
}
}
return false;
}
-bool AudioOutputDescriptor::isStreamActive(audio_stream_type_t stream,
- uint32_t inPastMs,
- nsecs_t sysTime) const
-{
- if (mActiveCount[stream] != 0) {
- return true;
- }
- if (inPastMs == 0) {
- return false;
- }
- if (sysTime == 0) {
- sysTime = systemTime();
- }
- if (ns2ms(sysTime - mStopTime[stream]) < inPastMs) {
- return true;
- }
- return false;
-}
-
-
bool AudioOutputDescriptor::isFixedVolume(audio_devices_t device __unused)
{
return false;
@@ -217,9 +158,9 @@
// We actually change the volume if:
// - the float value returned by computeVolume() changed
// - the force flag is set
- if (volume != mCurVolume[stream] || force) {
+ if (volume != getCurVolume(static_cast<VolumeSource>(stream)) || force) {
ALOGV("setVolume() for stream %d, volume %f, delay %d", stream, volume, delayMs);
- mCurVolume[stream] = volume;
+ setCurVolume(static_cast<VolumeSource>(stream), volume);
return true;
}
return false;
@@ -266,6 +207,13 @@
return clients;
}
+bool AudioOutputDescriptor::isAnyActive(VolumeSource volumeSourceToIgnore) const
+{
+ return std::find_if(begin(mActiveClients), end(mActiveClients),
+ [&volumeSourceToIgnore](const auto &client) {
+ return client->volumeSource() != volumeSourceToIgnore; }) != end(mActiveClients);
+}
+
void AudioOutputDescriptor::dump(String8 *dst) const
{
dst->appendFormat(" ID: %d\n", mId);
@@ -274,20 +222,22 @@
dst->appendFormat(" Channels: %08x\n", mChannelMask);
dst->appendFormat(" Devices: %s\n", devices().toString().c_str());
dst->appendFormat(" Global active count: %u\n", mGlobalActiveCount);
- dst->append(" Stream volume activeCount muteCount\n");
- for (int i = 0; i < (int)AUDIO_STREAM_CNT; i++) {
- dst->appendFormat(" %02d %.03f %02d %02d\n",
- i, mCurVolume[i], streamActiveCount((audio_stream_type_t)i), mMuteCount[i]);
+ for (const auto &iter : mRoutingActivities) {
+ dst->appendFormat(" Product Strategy id: %d", iter.first);
+ iter.second.dump(dst, 4);
+ }
+ for (const auto &iter : mVolumeActivities) {
+ dst->appendFormat(" Volume Activities id: %d", iter.first);
+ iter.second.dump(dst, 4);
}
dst->append(" AudioTrack Clients:\n");
ClientMapHandler<TrackClientDescriptor>::dump(dst);
dst->append("\n");
- if (mActiveClients.size() > 0) {
+ if (!mActiveClients.empty()) {
dst->append(" AudioTrack active (stream) clients:\n");
size_t index = 0;
- for (const auto& clientPair : mActiveClients) {
- dst->appendFormat(" Refcount: %zu", clientPair.second);
- clientPair.first->dump(dst, 2, index++);
+ for (const auto& client : mActiveClients) {
+ client->dump(dst, 2, index++);
}
dst->append(" \n");
}
@@ -388,15 +338,14 @@
}
}
-void SwAudioOutputDescriptor::changeStreamActiveCount(const sp<TrackClientDescriptor>& client,
- int delta)
+void SwAudioOutputDescriptor::setClientActive(const sp<TrackClientDescriptor>& client, bool active)
{
// forward usage count change to attached outputs
if (isDuplicated()) {
- mOutput1->changeStreamActiveCount(client, delta);
- mOutput2->changeStreamActiveCount(client, delta);
+ mOutput1->setClientActive(client, active);
+ mOutput2->setClientActive(client, active);
}
- AudioOutputDescriptor::changeStreamActiveCount(client, delta);
+ AudioOutputDescriptor::setClientActive(client, active);
}
bool SwAudioOutputDescriptor::isFixedVolume(audio_devices_t device)
@@ -445,19 +394,16 @@
uint32_t delayMs,
bool force)
{
- bool changed = AudioOutputDescriptor::setVolume(volume, stream, device, delayMs, force);
-
- if (changed) {
- // Force VOICE_CALL to track BLUETOOTH_SCO stream volume when bluetooth audio is
- // enabled
- float volume = Volume::DbToAmpl(mCurVolume[stream]);
- if (stream == AUDIO_STREAM_BLUETOOTH_SCO) {
- mClientInterface->setStreamVolume(
- AUDIO_STREAM_VOICE_CALL, volume, mIoHandle, delayMs);
- }
- mClientInterface->setStreamVolume(stream, volume, mIoHandle, delayMs);
+ if (!AudioOutputDescriptor::setVolume(volume, stream, device, delayMs, force)) {
+ return false;
}
- return changed;
+ // Force VOICE_CALL to track BLUETOOTH_SCO stream volume when bluetooth audio is enabled
+ float volumeAmpl = Volume::DbToAmpl(getCurVolume(static_cast<VolumeSource>(stream)));
+ if (stream == AUDIO_STREAM_BLUETOOTH_SCO) {
+ mClientInterface->setStreamVolume(AUDIO_STREAM_VOICE_CALL, volumeAmpl, mIoHandle, delayMs);
+ }
+ mClientInterface->setStreamVolume(stream, volumeAmpl, mIoHandle, delayMs);
+ return true;
}
status_t SwAudioOutputDescriptor::open(const audio_config_t *config,
@@ -660,24 +606,24 @@
}
// SwAudioOutputCollection implementation
-bool SwAudioOutputCollection::isStreamActive(audio_stream_type_t stream, uint32_t inPastMs) const
+bool SwAudioOutputCollection::isActive(VolumeSource volumeSource, uint32_t inPastMs) const
{
nsecs_t sysTime = systemTime();
for (size_t i = 0; i < this->size(); i++) {
const sp<SwAudioOutputDescriptor> outputDesc = this->valueAt(i);
- if (outputDesc->isStreamActive(stream, inPastMs, sysTime)) {
+ if (outputDesc->isActive(volumeSource, inPastMs, sysTime)) {
return true;
}
}
return false;
}
-bool SwAudioOutputCollection::isStreamActiveLocally(audio_stream_type_t stream, uint32_t inPastMs) const
+bool SwAudioOutputCollection::isActiveLocally(VolumeSource volumeSource, uint32_t inPastMs) const
{
nsecs_t sysTime = systemTime();
for (size_t i = 0; i < this->size(); i++) {
const sp<SwAudioOutputDescriptor> outputDesc = this->valueAt(i);
- if (outputDesc->isStreamActive(stream, inPastMs, sysTime)
+ if (outputDesc->isActive(volumeSource, inPastMs, sysTime)
&& ((outputDesc->devices().types() & APM_AUDIO_OUT_DEVICE_REMOTE_ALL) == 0)) {
return true;
}
@@ -685,14 +631,13 @@
return false;
}
-bool SwAudioOutputCollection::isStreamActiveRemotely(audio_stream_type_t stream,
- uint32_t inPastMs) const
+bool SwAudioOutputCollection::isActiveRemotely(VolumeSource volumeSource, uint32_t inPastMs) const
{
nsecs_t sysTime = systemTime();
for (size_t i = 0; i < size(); i++) {
const sp<SwAudioOutputDescriptor> outputDesc = valueAt(i);
if (((outputDesc->devices().types() & APM_AUDIO_OUT_DEVICE_REMOTE_ALL) != 0) &&
- outputDesc->isStreamActive(stream, inPastMs, sysTime)) {
+ outputDesc->isActive(volumeSource, inPastMs, sysTime)) {
// do not consider re routing (when the output is going to a dynamic policy)
// as "remote playback"
if (outputDesc->mPolicyMix == NULL) {
@@ -775,22 +720,6 @@
return NULL;
}
-bool SwAudioOutputCollection::isAnyOutputActive(audio_stream_type_t streamToIgnore) const
-{
- for (size_t s = 0 ; s < AUDIO_STREAM_CNT ; s++) {
- if (s == (size_t) streamToIgnore) {
- continue;
- }
- for (size_t i = 0; i < size(); i++) {
- const sp<SwAudioOutputDescriptor> outputDesc = valueAt(i);
- if (outputDesc->streamActiveCount((audio_stream_type_t)s)!= 0) {
- return true;
- }
- }
- }
- return false;
-}
-
sp<SwAudioOutputDescriptor> SwAudioOutputCollection::getOutputForClient(audio_port_handle_t portId)
{
for (size_t i = 0; i < size(); i++) {
@@ -825,34 +754,18 @@
}
// HwAudioOutputCollection implementation
-bool HwAudioOutputCollection::isStreamActive(audio_stream_type_t stream, uint32_t inPastMs) const
+bool HwAudioOutputCollection::isActive(VolumeSource volumeSource, uint32_t inPastMs) const
{
nsecs_t sysTime = systemTime();
for (size_t i = 0; i < this->size(); i++) {
const sp<HwAudioOutputDescriptor> outputDesc = this->valueAt(i);
- if (outputDesc->isStreamActive(stream, inPastMs, sysTime)) {
+ if (outputDesc->isActive(volumeSource, inPastMs, sysTime)) {
return true;
}
}
return false;
}
-bool HwAudioOutputCollection::isAnyOutputActive(audio_stream_type_t streamToIgnore) const
-{
- for (size_t s = 0 ; s < AUDIO_STREAM_CNT ; s++) {
- if (s == (size_t) streamToIgnore) {
- continue;
- }
- for (size_t i = 0; i < size(); i++) {
- const sp<HwAudioOutputDescriptor> outputDesc = valueAt(i);
- if (outputDesc->streamActiveCount((audio_stream_type_t)s) != 0) {
- return true;
- }
- }
- }
- return false;
-}
-
void HwAudioOutputCollection::dump(String8 *dst) const
{
dst->append("\nOutputs dump:\n");
diff --git a/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
index 633c40e..ad07ab1 100644
--- a/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
@@ -20,6 +20,7 @@
#include <sstream>
#include <utils/Log.h>
#include <utils/String8.h>
+#include <TypeConverter.h>
#include "AudioGain.h"
#include "AudioOutputDescriptor.h"
#include "AudioPatch.h"
@@ -45,6 +46,7 @@
mPortId, mSessionId, mUid);
dst->appendFormat("%*s- Format: %08x Sampling rate: %d Channels: %08x\n", spaces, "",
mConfig.format, mConfig.sample_rate, mConfig.channel_mask);
+ dst->appendFormat("%*s- Attributes: %s\n", spaces, "", toString(mAttributes).c_str());
dst->appendFormat("%*s- Preferred Device Id: %08x\n", spaces, "", mPreferredDeviceId);
dst->appendFormat("%*s- State: %s\n", spaces, "", mActive ? "Active" : "Inactive");
}
@@ -53,6 +55,7 @@
{
ClientDescriptor::dump(dst, spaces, index);
dst->appendFormat("%*s- Stream: %d flags: %08x\n", spaces, "", mStream, mFlags);
+ dst->appendFormat("%*s- Refcount: %d\n", spaces, "", mActivityCount);
}
std::string TrackClientDescriptor::toShortString() const
@@ -82,10 +85,10 @@
SourceClientDescriptor::SourceClientDescriptor(audio_port_handle_t portId, uid_t uid,
audio_attributes_t attributes, const sp<AudioPatch>& patchDesc,
const sp<DeviceDescriptor>& srcDevice, audio_stream_type_t stream,
- product_strategy_t strategy) :
+ product_strategy_t strategy, VolumeSource volumeSource) :
TrackClientDescriptor::TrackClientDescriptor(portId, uid, AUDIO_SESSION_NONE, attributes,
AUDIO_CONFIG_BASE_INITIALIZER, AUDIO_PORT_HANDLE_NONE,
- stream, strategy, AUDIO_OUTPUT_FLAG_NONE, false,
+ stream, strategy, volumeSource, AUDIO_OUTPUT_FLAG_NONE, false,
{} /* Sources do not support secondary outputs*/),
mPatchDesc(patchDesc), mSrcDevice(srcDevice)
{
diff --git a/services/audiopolicy/engineconfigurable/src/Engine.cpp b/services/audiopolicy/engineconfigurable/src/Engine.cpp
index f486dca..719ef01 100644
--- a/services/audiopolicy/engineconfigurable/src/Engine.cpp
+++ b/services/audiopolicy/engineconfigurable/src/Engine.cpp
@@ -224,16 +224,16 @@
audio_devices_t devices = AUDIO_DEVICE_NONE;
if (ps == getProductStrategyForStream(AUDIO_STREAM_NOTIFICATION) &&
!is_state_in_call(getPhoneState()) &&
- !outputs.isStreamActiveRemotely(AUDIO_STREAM_MUSIC,
- SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY) &&
- outputs.isStreamActive(AUDIO_STREAM_MUSIC,
- SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) {
+ !outputs.isActiveRemotely(streamToVolumeSource(AUDIO_STREAM_MUSIC),
+ SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY) &&
+ outputs.isActive(streamToVolumeSource(AUDIO_STREAM_MUSIC),
+ SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) {
product_strategy_t strategyForMedia =
getProductStrategyForStream(AUDIO_STREAM_MUSIC);
devices = productStrategies.getDeviceTypesForProductStrategy(strategyForMedia);
} else if (ps == getProductStrategyForStream(AUDIO_STREAM_ACCESSIBILITY) &&
- (outputs.isStreamActive(AUDIO_STREAM_RING) ||
- outputs.isStreamActive(AUDIO_STREAM_ALARM))) {
+ (outputs.isActive(streamToVolumeSource(AUDIO_STREAM_RING)) ||
+ outputs.isActive(streamToVolumeSource(AUDIO_STREAM_ALARM)))) {
// do not route accessibility prompts to a digital output currently configured with a
// compressed format as they would likely not be mixed and dropped.
// Device For Sonification conf file has HDMI, SPDIF and HDMI ARC unreacheable.
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index 93af8a6..43023a8 100644
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -182,16 +182,17 @@
break;
case STRATEGY_SONIFICATION_RESPECTFUL:
- if (isInCall() || outputs.isStreamActiveLocally(AUDIO_STREAM_VOICE_CALL)) {
+ if (isInCall() || outputs.isActiveLocally(streamToVolumeSource(AUDIO_STREAM_VOICE_CALL))) {
device = getDeviceForStrategyInt(
STRATEGY_SONIFICATION, availableOutputDevices, availableInputDevices, outputs,
outputDeviceTypesToIgnore);
} else {
bool media_active_locally =
- outputs.isStreamActiveLocally(
- AUDIO_STREAM_MUSIC, SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)
- || outputs.isStreamActiveLocally(
- AUDIO_STREAM_ACCESSIBILITY, SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY);
+ outputs.isActiveLocally(streamToVolumeSource(AUDIO_STREAM_MUSIC),
+ SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)
+ || outputs.isActiveLocally(
+ streamToVolumeSource(AUDIO_STREAM_ACCESSIBILITY),
+ SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY);
// routing is same as media without the "remote" device
device = getDeviceForStrategyInt(STRATEGY_MEDIA,
availableOutputDevices,
@@ -324,7 +325,8 @@
case STRATEGY_SONIFICATION:
// If incall, just select the STRATEGY_PHONE device
- if (isInCall() || outputs.isStreamActiveLocally(AUDIO_STREAM_VOICE_CALL)) {
+ if (isInCall() ||
+ outputs.isActiveLocally(streamToVolumeSource(AUDIO_STREAM_VOICE_CALL))) {
device = getDeviceForStrategyInt(
STRATEGY_PHONE, availableOutputDevices, availableInputDevices, outputs,
outputDeviceTypesToIgnore);
@@ -397,8 +399,8 @@
}
availableOutputDevices =
availableOutputDevices.getDevicesFromTypeMask(availableOutputDevicesType);
- if (outputs.isStreamActive(AUDIO_STREAM_RING) ||
- outputs.isStreamActive(AUDIO_STREAM_ALARM)) {
+ if (outputs.isActive(streamToVolumeSource(AUDIO_STREAM_RING)) ||
+ outputs.isActive(streamToVolumeSource(AUDIO_STREAM_ALARM))) {
return getDeviceForStrategyInt(
STRATEGY_SONIFICATION, availableOutputDevices, availableInputDevices, outputs,
outputDeviceTypesToIgnore);
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 32cc380..3366141 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1078,6 +1078,7 @@
new TrackClientDescriptor(*portId, uid, session, resultAttr, clientConfig,
sanitizedRequestedPortId, *stream,
mEngine->getProductStrategyForAttributes(resultAttr),
+ streamToVolumeSource(*stream),
*flags, isRequestedDeviceForExclusiveUse,
std::move(weakSecondaryOutputDescs));
sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueFor(*output);
@@ -1569,11 +1570,13 @@
*delayMs = 0;
audio_stream_type_t stream = client->stream();
+ auto clientVolSrc = client->volumeSource();
auto clientStrategy = client->strategy();
auto clientAttr = client->attributes();
if (stream == AUDIO_STREAM_TTS) {
ALOGV("\t found BEACON stream");
- if (!mTtsOutputAvailable && mOutputs.isAnyOutputActive(AUDIO_STREAM_TTS /*streamToIgnore*/)) {
+ if (!mTtsOutputAvailable && mOutputs.isAnyOutputActive(
+ streamToVolumeSource(AUDIO_STREAM_TTS) /*sourceToIgnore*/)) {
return INVALID_OPERATION;
} else {
beaconMuteLatency = handleEventForBeacon(STARTING_BEACON);
@@ -1628,7 +1631,7 @@
selectOutputForMusicEffects();
}
- if (outputDesc->streamActiveCount(stream) == 1 || !devices.isEmpty()) {
+ if (outputDesc->getActivityCount(clientVolSrc) == 1 || !devices.isEmpty()) {
// starting an output being rerouted?
if (devices.isEmpty()) {
devices = getNewOutputDevices(outputDesc, false /*fromCache*/);
@@ -1754,11 +1757,12 @@
{
// always handle stream stop, check which stream type is stopping
audio_stream_type_t stream = client->stream();
+ auto clientVolSrc = client->volumeSource();
handleEventForBeacon(stream == AUDIO_STREAM_TTS ? STOPPING_BEACON : STOPPING_OUTPUT);
- if (outputDesc->streamActiveCount(stream) > 0) {
- if (outputDesc->streamActiveCount(stream) == 1) {
+ if (outputDesc->getActivityCount(clientVolSrc) > 0) {
+ if (outputDesc->getActivityCount(clientVolSrc) == 1) {
// Automatically disable the remote submix input when output is stopped on a
// re routing mix of type MIX_TYPE_RECORDERS
if (audio_is_remote_submix_device(outputDesc->devices().types()) &&
@@ -1780,7 +1784,7 @@
outputDesc->setClientActive(client, false);
// store time at which the stream was stopped - see isStreamActive()
- if (outputDesc->streamActiveCount(stream) == 0 || forceDeviceUpdate) {
+ if (outputDesc->getActivityCount(clientVolSrc) == 0 || forceDeviceUpdate) {
outputDesc->setStopTime(client, systemTime());
DeviceVector newDevices = getNewOutputDevices(outputDesc, false /*fromCache*/);
// delay the device switch by twice the latency because stopOutput() is executed when
@@ -2411,7 +2415,7 @@
if (!(streamsMatchForvolume(stream, (audio_stream_type_t)curStream))) {
continue;
}
- if (!(desc->isStreamActive((audio_stream_type_t)curStream) || isInCall())) {
+ if (!(desc->isActive(streamToVolumeSource((audio_stream_type_t)curStream)) || isInCall())) {
continue;
}
audio_devices_t curStreamDevice = Volume::getDeviceForVolume(
@@ -2499,7 +2503,7 @@
for (audio_io_handle_t output : outputs) {
sp<SwAudioOutputDescriptor> desc = mOutputs.valueFor(output);
- if (activeOnly && !desc->isStreamActive(AUDIO_STREAM_MUSIC)) {
+ if (activeOnly && !desc->isActive(streamToVolumeSource(AUDIO_STREAM_MUSIC))) {
continue;
}
ALOGV("selectOutputForMusicEffects activeOnly %d output %d flags 0x%08x",
@@ -2593,14 +2597,14 @@
if (!streamsMatchForvolume(stream, (audio_stream_type_t)curStream)) {
continue;
}
- active = mOutputs.isStreamActive((audio_stream_type_t)curStream, inPastMs);
+ active = mOutputs.isActive(streamToVolumeSource((audio_stream_type_t)curStream), inPastMs);
}
return active;
}
bool AudioPolicyManager::isStreamActiveRemotely(audio_stream_type_t stream, uint32_t inPastMs) const
{
- return mOutputs.isStreamActiveRemotely(stream, inPastMs);
+ return mOutputs.isActiveRemotely(streamToVolumeSource((audio_stream_type_t)stream), inPastMs);
}
bool AudioPolicyManager::isSourceActive(audio_source_t source) const
@@ -3630,10 +3634,11 @@
struct audio_patch dummyPatch = {};
sp<AudioPatch> patchDesc = new AudioPatch(&dummyPatch, uid);
- sp<SourceClientDescriptor> sourceDesc =
- new SourceClientDescriptor(*portId, uid, *attributes, patchDesc, srcDevice,
- mEngine->getStreamTypeForAttributes(*attributes),
- mEngine->getProductStrategyForAttributes(*attributes));
+ sp<SourceClientDescriptor> sourceDesc = new SourceClientDescriptor(
+ *portId, uid, *attributes, patchDesc, srcDevice,
+ mEngine->getStreamTypeForAttributes(*attributes),
+ mEngine->getProductStrategyForAttributes(*attributes),
+ streamToVolumeSource(mEngine->getStreamTypeForAttributes(*attributes)));
status_t status = connectAudioSource(sourceDesc);
if (status == NO_ERROR) {
@@ -4704,37 +4709,31 @@
{
ALOGV("closeOutput(%d)", output);
- sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueFor(output);
- if (outputDesc == NULL) {
+ sp<SwAudioOutputDescriptor> closingOutput = mOutputs.valueFor(output);
+ if (closingOutput == NULL) {
ALOGW("closeOutput() unknown output %d", output);
return;
}
- mPolicyMixes.closeOutput(outputDesc);
+ mPolicyMixes.closeOutput(closingOutput);
// look for duplicated outputs connected to the output being removed.
for (size_t i = 0; i < mOutputs.size(); i++) {
- sp<SwAudioOutputDescriptor> dupOutputDesc = mOutputs.valueAt(i);
- if (dupOutputDesc->isDuplicated() &&
- (dupOutputDesc->mOutput1 == outputDesc ||
- dupOutputDesc->mOutput2 == outputDesc)) {
- sp<SwAudioOutputDescriptor> outputDesc2;
- if (dupOutputDesc->mOutput1 == outputDesc) {
- outputDesc2 = dupOutputDesc->mOutput2;
- } else {
- outputDesc2 = dupOutputDesc->mOutput1;
- }
+ sp<SwAudioOutputDescriptor> dupOutput = mOutputs.valueAt(i);
+ if (dupOutput->isDuplicated() &&
+ (dupOutput->mOutput1 == closingOutput || dupOutput->mOutput2 == closingOutput)) {
+ sp<SwAudioOutputDescriptor> remainingOutput =
+ dupOutput->mOutput1 == closingOutput ? dupOutput->mOutput2 : dupOutput->mOutput1;
// As all active tracks on duplicated output will be deleted,
// and as they were also referenced on the other output, the reference
// count for their stream type must be adjusted accordingly on
// the other output.
- const bool wasActive = outputDesc2->isActive();
- for (const auto &clientPair : dupOutputDesc->getActiveClients()) {
- outputDesc2->changeStreamActiveCount(clientPair.first, -clientPair.second);
- }
+ const bool wasActive = remainingOutput->isActive();
+ // Note: no-op on the closing output where all clients has already been set inactive
+ dupOutput->setAllClientsInactive();
// stop() will be a no op if the output is still active but is needed in case all
// active streams refcounts where cleared above
if (wasActive) {
- outputDesc2->stop();
+ remainingOutput->stop();
}
audio_io_handle_t duplicatedOutput = mOutputs.keyAt(i);
ALOGV("closeOutput() closing also duplicated output %d", duplicatedOutput);
@@ -4746,7 +4745,7 @@
nextAudioPortGeneration();
- ssize_t index = mAudioPatches.indexOfKey(outputDesc->getPatchHandle());
+ ssize_t index = mAudioPatches.indexOfKey(closingOutput->getPatchHandle());
if (index >= 0) {
sp<AudioPatch> patchDesc = mAudioPatches.valueAt(index);
(void) /*status_t status*/ mpClientInterface->releaseAudioPatch(patchDesc->mAfPatchHandle, 0);
@@ -4754,7 +4753,7 @@
mpClientInterface->onAudioPatchListUpdate();
}
- outputDesc->close();
+ closingOutput->close();
removeOutput(output);
mPreviousOutputs = mOutputs;
@@ -5105,7 +5104,7 @@
devices.merge(curDevices);
for (audio_io_handle_t output : getOutputsForDevices(curDevices, mOutputs)) {
sp<AudioOutputDescriptor> outputDesc = mOutputs.valueFor(output);
- if (outputDesc->isStreamActive((audio_stream_type_t)curStream)) {
+ if (outputDesc->isActive(streamToVolumeSource((audio_stream_type_t)curStream))) {
activeDevices.merge(outputDesc->devices());
}
}
@@ -5519,7 +5518,7 @@
// in-call: always cap volume by voice volume + some low headroom
if ((stream != AUDIO_STREAM_VOICE_CALL) &&
- (isInCall() || mOutputs.isStreamActiveLocally(AUDIO_STREAM_VOICE_CALL))) {
+ (isInCall() || mOutputs.isActiveLocally(streamToVolumeSource(AUDIO_STREAM_VOICE_CALL)))) {
switch (stream) {
case AUDIO_STREAM_SYSTEM:
case AUDIO_STREAM_RING:
@@ -5637,9 +5636,8 @@
bool force)
{
// do not change actual stream volume if the stream is muted
- if (outputDesc->mMuteCount[stream] != 0) {
- ALOGVV("checkAndSetVolume() stream %d muted count %d",
- stream, outputDesc->mMuteCount[stream]);
+ if (outputDesc->isMuted(streamToVolumeSource(stream))) {
+ ALOGVV("%s() stream %d muted count %d", __func__, stream, outputDesc->getMuteCount(stream));
return NO_ERROR;
}
audio_policy_forced_cfg_t forceUseForComm =
@@ -5726,10 +5724,10 @@
}
ALOGVV("setStreamMute() stream %d, mute %d, mMuteCount %d device %04x",
- stream, on, outputDesc->mMuteCount[stream], device);
+ stream, on, outputDesc->getMuteCount(stream), device);
if (on) {
- if (outputDesc->mMuteCount[stream] == 0) {
+ if (!outputDesc->isMuted(streamToVolumeSource(stream))) {
if (mVolumeCurves->canBeMuted(stream) &&
((stream != AUDIO_STREAM_ENFORCED_AUDIBLE) ||
(mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_NONE))) {
@@ -5737,13 +5735,13 @@
}
}
// increment mMuteCount after calling checkAndSetVolume() so that volume change is not ignored
- outputDesc->mMuteCount[stream]++;
+ outputDesc->incMuteCount(streamToVolumeSource(stream));
} else {
- if (outputDesc->mMuteCount[stream] == 0) {
+ if (!outputDesc->isMuted(streamToVolumeSource(stream))) {
ALOGV("setStreamMute() unmuting non muted stream!");
return;
}
- if (--outputDesc->mMuteCount[stream] == 0) {
+ if (outputDesc->decMuteCount(streamToVolumeSource(stream)) == 0) {
checkAndSetVolume(stream,
mVolumeCurves->getVolumeIndex(stream, device),
outputDesc,