audio policy: refactor preferred route implementation
Remove SessionRoute class and replace by use of
preferredDevice and active state in ClientDescriptor
Also fix the behavior for other clients using same strategy as
client with preferred route: the preferred route is only used if
no other clients using the same strategy are active without a preferred
route.
If all clients have a preferred route, the route of the last active
client is used.
Also fixed getOutputForAttr() to return correct selected device ID when
dynamic policies are used.
Test: CTS RoutingTest, AudioPlayRoutingNative, AudioRecordRoutingNative
Test: Manual: AudioExplicitRouting, UplinkMusicSampleApp
Change-Id: Id342c2241ace3e1a359ea74f4a539a395f793b86
diff --git a/services/audiopolicy/common/include/RoutingStrategy.h b/services/audiopolicy/common/include/RoutingStrategy.h
index d38967e..f8a1cd6 100644
--- a/services/audiopolicy/common/include/RoutingStrategy.h
+++ b/services/audiopolicy/common/include/RoutingStrategy.h
@@ -23,6 +23,7 @@
#define SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY 5000
enum routing_strategy {
+ STRATEGY_NONE = -1,
STRATEGY_MEDIA,
STRATEGY_PHONE,
STRATEGY_SONIFICATION,
diff --git a/services/audiopolicy/common/managerdefinitions/Android.mk b/services/audiopolicy/common/managerdefinitions/Android.mk
index 9b8f095..5ba2d4a 100644
--- a/services/audiopolicy/common/managerdefinitions/Android.mk
+++ b/services/audiopolicy/common/managerdefinitions/Android.mk
@@ -17,7 +17,6 @@
src/AudioCollections.cpp \
src/EffectDescriptor.cpp \
src/SoundTriggerSession.cpp \
- src/SessionRoute.cpp \
src/VolumeCurve.cpp \
src/TypeConverter.cpp \
src/AudioSession.cpp \
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
index 44662e5..0d1d8c3 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
@@ -89,8 +89,10 @@
void stop();
void close();
- RecordClientMap& clients() { return mClients; }
+ RecordClientMap& clientsMap() { return mClients; }
RecordClientVector getClientsForSession(audio_session_t session);
+ RecordClientVector clientsList(bool activeOnly = false,
+ audio_source_t source = AUDIO_SOURCE_DEFAULT, bool preferredDeviceOnly = false) const;
private:
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
index ff0201a..4cf16a0 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
@@ -78,7 +78,9 @@
audio_patch_handle_t getPatchHandle() const override;
void setPatchHandle(audio_patch_handle_t handle) override;
- TrackClientMap& clients() { return mClients; }
+ TrackClientMap& clientsMap() { return mClients; }
+ TrackClientVector clientsList(bool activeOnly = false,
+ routing_strategy strategy = STRATEGY_NONE, bool preferredDeviceOnly = false) const;
sp<AudioPort> mPort;
audio_devices_t mDevice; // current device this output is routed to
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
index f861b95..78e7ec9 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
@@ -28,7 +28,6 @@
#include <AudioPolicyMix.h>
#include <EffectDescriptor.h>
#include <SoundTriggerSession.h>
-#include <SessionRoute.h>
namespace android {
diff --git a/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
index 9efe57f..cc751b1 100644
--- a/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
@@ -27,6 +27,7 @@
#include <utils/RefBase.h>
#include <utils/String8.h>
#include "AudioPatch.h"
+#include "RoutingStrategy.h"
namespace android {
@@ -53,8 +54,14 @@
audio_attributes_t attributes() const { return mAttributes; }
audio_config_base_t config() const { return mConfig; }
audio_port_handle_t preferredDeviceId() const { return mPreferredDeviceId; };
+ void setPreferredDeviceId(audio_port_handle_t preferredDeviceId) {
+ mPreferredDeviceId = preferredDeviceId;
+ };
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);
+ }
private:
const audio_port_handle_t mPortId; // unique Id for this client
@@ -62,7 +69,7 @@
const audio_session_t mSessionId; // audio session ID
const audio_attributes_t mAttributes; // usage...
const audio_config_base_t mConfig;
- const audio_port_handle_t mPreferredDeviceId; // selected input device port ID
+ audio_port_handle_t mPreferredDeviceId; // selected input device port ID
bool mActive;
protected:
@@ -75,10 +82,10 @@
public:
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, audio_output_flags_t flags) :
+ audio_port_handle_t preferredDeviceId, audio_stream_type_t stream,
+ routing_strategy strategy, audio_output_flags_t flags) :
ClientDescriptor(portId, uid, sessionId, attributes, config, preferredDeviceId),
- mStream(stream), mFlags(flags) {}
+ mStream(stream), mStrategy(strategy), mFlags(flags) {}
~TrackClientDescriptor() override = default;
using ClientDescriptor::dump;
@@ -86,9 +93,11 @@
audio_output_flags_t flags() const { return mFlags; }
audio_stream_type_t stream() const { return mStream; }
+ routing_strategy strategy() const { return mStrategy; }
private:
const audio_stream_type_t mStream;
+ const routing_strategy mStrategy;
const audio_output_flags_t mFlags;
};
@@ -119,7 +128,7 @@
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);
+ audio_stream_type_t stream, routing_strategy strategy);
~SourceClientDescriptor() override = default;
sp<AudioPatch> patchDesc() const { return mPatchDesc; }
diff --git a/services/audiopolicy/common/managerdefinitions/include/SessionRoute.h b/services/audiopolicy/common/managerdefinitions/include/SessionRoute.h
deleted file mode 100644
index 32b4440..0000000
--- a/services/audiopolicy/common/managerdefinitions/include/SessionRoute.h
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (C) 2015 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 <system/audio.h>
-#include <utils/KeyedVector.h>
-#include <utils/RefBase.h>
-#include <utils/Errors.h>
-
-namespace android {
-
-class DeviceDescriptor;
-class DeviceVector;
-
-class SessionRoute : public RefBase
-{
-public:
- // For Input (Source) routes, use STREAM_TYPE_NA ("NA" = "not applicable)for the
- // streamType argument
- static const audio_stream_type_t STREAM_TYPE_NA = AUDIO_STREAM_DEFAULT;
-
- // For Output (Sink) routes, use SOURCE_TYPE_NA ("NA" = "not applicable") for the
- // source argument
-
- static const audio_source_t SOURCE_TYPE_NA = AUDIO_SOURCE_DEFAULT;
-
- SessionRoute(audio_session_t session,
- audio_stream_type_t streamType,
- audio_source_t source,
- sp<DeviceDescriptor> deviceDescriptor,
- uid_t uid)
- : mUid(uid),
- mSession(session),
- mDeviceDescriptor(deviceDescriptor),
- mRefCount(0),
- mActivityCount(0),
- mChanged(false),
- mStreamType(streamType),
- mSource(source)
- {}
-
- void log(const char* prefix);
-
- bool isActiveOrChanged() {
- return (mDeviceDescriptor != 0) && (mChanged || (mActivityCount > 0));
- }
-
- uid_t mUid;
- audio_session_t mSession;
- sp<DeviceDescriptor> mDeviceDescriptor;
-
- // "reference" counting
- int mRefCount; // +/- on references
- int mActivityCount; // +/- on start/stop
- bool mChanged;
- // for outputs
- const audio_stream_type_t mStreamType;
- // for inputs
- const audio_source_t mSource;
-};
-
-class SessionRouteMap: public KeyedVector<audio_session_t, sp<SessionRoute> >
-{
-public:
- // These constants identify the SessionRoutMap as holding EITHER input routes,
- // or output routes. An error will occur if an attempt is made to add a SessionRoute
- // object with mStreamType == STREAM_TYPE_NA (i.e. an input SessionRoute) to a
- // SessionRoutMap that is marked for output (i.e. mMapType == SESSION_ROUTE_MAP_OUTPUT)
- // and similarly for output SessionRoutes and Input SessionRouteMaps.
- typedef enum
- {
- MAPTYPE_INPUT = 0,
- MAPTYPE_OUTPUT = 1
- } session_route_map_type_t;
-
- explicit SessionRouteMap(session_route_map_type_t mapType) :
- mMapType(mapType)
- {}
-
- bool hasRoute(audio_session_t session);
-
- void removeRoute(audio_session_t session);
-
- int incRouteActivity(audio_session_t session);
- int decRouteActivity(audio_session_t session);
- bool getAndClearRouteChanged(audio_session_t session); // also clears the changed flag
- void log(const char* caption);
- audio_devices_t getActiveDeviceForStream(audio_stream_type_t streamType,
- const DeviceVector& availableDevices);
- // Specify an Output(Sink) route by passing SessionRoute::SOURCE_TYPE_NA in the
- // source argument.
- // Specify an Input(Source) rout by passing SessionRoute::AUDIO_STREAM_DEFAULT
- // in the streamType argument.
- void addRoute(audio_session_t session,
- audio_stream_type_t streamType,
- audio_source_t source,
- const sp<DeviceDescriptor>& deviceDescriptor,
- uid_t uid);
-
-private:
- // Used to mark a SessionRoute as for either inputs (mMapType == kSessionRouteMap_Input)
- // or outputs (mMapType == kSessionRouteMap_Output)
- const session_route_map_type_t mMapType;
-};
-
-} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
index 2770e74..3c7562e 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
@@ -352,6 +352,20 @@
return clients;
}
+RecordClientVector AudioInputDescriptor::clientsList(bool activeOnly, audio_source_t source,
+ bool preferredDeviceOnly) const
+{
+ RecordClientVector clients;
+ for (const auto &client : mClients) {
+ if ((!activeOnly || client.second->active())
+ && (source == AUDIO_SOURCE_DEFAULT || source == client.second->source())
+ && (!preferredDeviceOnly || client.second->hasPreferredDevice())) {
+ clients.push_back(client.second);
+ }
+ }
+ return clients;
+}
+
status_t AudioInputDescriptor::dump(int fd)
{
const size_t SIZE = 256;
@@ -446,7 +460,7 @@
{
for (size_t i = 0; i < size(); i++) {
sp<AudioInputDescriptor> inputDesc = valueAt(i);
- for (const auto& client : inputDesc->clients()) {
+ for (const auto& client : inputDesc->clientsMap()) {
if (client.second->portId() == portId) {
return inputDesc;
}
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index 39fce4d..a39ac6d 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -201,6 +201,20 @@
port->ext.mix.hw_module = getModuleHandle();
}
+TrackClientVector AudioOutputDescriptor::clientsList(bool activeOnly, routing_strategy strategy,
+ bool preferredDeviceOnly) const
+{
+ TrackClientVector clients;
+ for (const auto &client : mClients) {
+ if ((!activeOnly || client.second->active())
+ && (strategy == STRATEGY_NONE || strategy == client.second->strategy())
+ && (!preferredDeviceOnly || client.second->hasPreferredDevice())) {
+ clients.push_back(client.second);
+ }
+ }
+ return clients;
+}
+
status_t AudioOutputDescriptor::dump(int fd)
{
const size_t SIZE = 256;
@@ -742,7 +756,7 @@
{
for (size_t i = 0; i < size(); i++) {
sp<SwAudioOutputDescriptor> outputDesc = valueAt(i);
- for (const auto& client : outputDesc->clients()) {
+ for (const auto& client : outputDesc->clientsMap()) {
if (client.second->portId() == portId) {
return outputDesc;
}
diff --git a/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
index 5aca3cc..0cf206d 100644
--- a/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
@@ -29,6 +29,7 @@
namespace android {
+
status_t ClientDescriptor::dump(int fd, int spaces, int index)
{
String8 out;
@@ -76,9 +77,11 @@
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) :
+ const sp<DeviceDescriptor>& srcDevice, audio_stream_type_t stream,
+ routing_strategy strategy) :
TrackClientDescriptor::TrackClientDescriptor(portId, uid, AUDIO_SESSION_NONE, attributes,
- AUDIO_CONFIG_BASE_INITIALIZER, AUDIO_PORT_HANDLE_NONE, stream, AUDIO_OUTPUT_FLAG_NONE),
+ AUDIO_CONFIG_BASE_INITIALIZER, AUDIO_PORT_HANDLE_NONE,
+ stream, strategy, AUDIO_OUTPUT_FLAG_NONE),
mPatchDesc(patchDesc), mSrcDevice(srcDevice)
{
}
diff --git a/services/audiopolicy/common/managerdefinitions/src/SessionRoute.cpp b/services/audiopolicy/common/managerdefinitions/src/SessionRoute.cpp
deleted file mode 100644
index 440a4e7..0000000
--- a/services/audiopolicy/common/managerdefinitions/src/SessionRoute.cpp
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (C) 2015 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 "APM_SessionRoute"
-//#define LOG_NDEBUG 0
-
-#include "SessionRoute.h"
-#include "HwModule.h"
-#include "AudioGain.h"
-#include "DeviceDescriptor.h"
-#include <utils/Log.h>
-
-namespace android {
-
-// --- SessionRoute class implementation
-void SessionRoute::log(const char* prefix)
-{
- ALOGI("%s[SessionRoute strm:0x%X, src:%d, sess:0x%X, dev:0x%X refs:%d act:%d",
- prefix, mStreamType, mSource, mSession,
- mDeviceDescriptor != 0 ? mDeviceDescriptor->type() : AUDIO_DEVICE_NONE,
- mRefCount, mActivityCount);
-}
-
-// --- SessionRouteMap class implementation
-bool SessionRouteMap::hasRoute(audio_session_t session)
-{
- return indexOfKey(session) >= 0 && valueFor(session)->mDeviceDescriptor != 0;
-}
-
-bool SessionRouteMap::getAndClearRouteChanged(audio_session_t session)
-{
- if (indexOfKey(session) >= 0) {
- if (valueFor(session)->mChanged) {
- valueFor(session)->mChanged = false;
- return true;
- }
- }
- return false;
-}
-
-void SessionRouteMap::removeRoute(audio_session_t session)
-{
- sp<SessionRoute> route = indexOfKey(session) >= 0 ? valueFor(session) : 0;
- if (route != 0) {
- ALOG_ASSERT(route->mRefCount > 0);
- --route->mRefCount;
- if (route->mRefCount <= 0) {
- removeItem(session);
- }
- }
-}
-
-int SessionRouteMap::incRouteActivity(audio_session_t session)
-{
- sp<SessionRoute> route = indexOfKey(session) >= 0 ? valueFor(session) : 0;
- return route != 0 ? ++(route->mActivityCount) : -1;
-}
-
-int SessionRouteMap::decRouteActivity(audio_session_t session)
-{
- sp<SessionRoute> route = indexOfKey(session) >= 0 ? valueFor(session) : 0;
- if (route != 0 && route->mActivityCount > 0) {
- return --(route->mActivityCount);
- } else {
- return -1;
- }
-}
-
-void SessionRouteMap::log(const char* caption)
-{
- ALOGI("%s ----", caption);
- for (size_t index = 0; index < size(); index++) {
- valueAt(index)->log(" ");
- }
-}
-
-void SessionRouteMap::addRoute(audio_session_t session,
- audio_stream_type_t streamType,
- audio_source_t source,
- const sp<DeviceDescriptor>& descriptor,
- uid_t uid)
-{
- if (mMapType == MAPTYPE_INPUT && streamType != SessionRoute::STREAM_TYPE_NA) {
- ALOGE("Adding Output Route to InputRouteMap");
- return;
- } else if (mMapType == MAPTYPE_OUTPUT && source != SessionRoute::SOURCE_TYPE_NA) {
- ALOGE("Adding Input Route to OutputRouteMap");
- return;
- }
-
- sp<SessionRoute> route = indexOfKey(session) >= 0 ? valueFor(session) : 0;
-
- if (route != 0) {
- if (descriptor != 0 || route->mDeviceDescriptor != 0) {
- route->mChanged = true;
- }
- route->mRefCount++;
- route->mDeviceDescriptor = descriptor;
- } else {
- route = new SessionRoute(session, streamType, source, descriptor, uid);
- route->mRefCount++;
- if (descriptor != 0) {
- route->mChanged = true;
- }
- add(session, route);
- }
-}
-
-audio_devices_t SessionRouteMap::getActiveDeviceForStream(audio_stream_type_t streamType,
- const DeviceVector& availableDevices)
-{
- for (size_t index = 0; index < size(); index++) {
- sp<SessionRoute> route = valueAt(index);
- if (streamType == route->mStreamType && route->isActiveOrChanged()
- && route->mDeviceDescriptor != 0) {
- audio_devices_t device = route->mDeviceDescriptor->type();
- if (!availableDevices.getDevicesFromTypeMask(device).isEmpty()) {
- return device;
- }
- }
- }
- return AUDIO_DEVICE_NONE;
-}
-
-} // namespace android
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index e4f3cf1..cd40bc5 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -788,7 +788,7 @@
DeviceVector outputDevices;
routing_strategy strategy;
audio_devices_t device;
- audio_port_handle_t requestedDeviceId = *selectedDeviceId;
+ const audio_port_handle_t requestedDeviceId = *selectedDeviceId;
audio_devices_t msdDevice = getMsdAudioOutDeviceTypes();
if (attr != NULL) {
@@ -808,19 +808,24 @@
}
ALOGV("getOutputForAttr() usage=%d, content=%d, tag=%s flags=%08x"
- " session %d selectedDeviceId %d",
- attributes.usage, attributes.content_type, attributes.tags, attributes.flags,
- session, *selectedDeviceId);
+ " session %d selectedDeviceId %d",
+ attributes.usage, attributes.content_type, attributes.tags, attributes.flags,
+ session, requestedDeviceId);
// TODO: check for existing client for this port ID
if (*portId == AUDIO_PORT_HANDLE_NONE) {
*portId = AudioPort::getNextUniqueId();
}
+ *stream = streamTypefromAttributesInt(&attributes);
+
+ strategy = getStrategyForAttr(&attributes);
+
// First check for explicit routing (eg. setPreferredDevice)
- sp<DeviceDescriptor> deviceDesc;
- if (*selectedDeviceId != AUDIO_PORT_HANDLE_NONE) {
- deviceDesc = mAvailableOutputDevices.getDeviceFromId(*selectedDeviceId);
+ if (requestedDeviceId != AUDIO_PORT_HANDLE_NONE) {
+ sp<DeviceDescriptor> deviceDesc =
+ mAvailableOutputDevices.getDeviceFromId(requestedDeviceId);
+ device = deviceDesc->type();
} else {
// If no explict route, is there a matching dynamic policy that applies?
sp<SwAudioOutputDescriptor> desc;
@@ -831,6 +836,10 @@
}
*stream = streamTypefromAttributesInt(&attributes);
*output = desc->mIoHandle;
+ AudioMix *mix = desc->mPolicyMix;
+ sp<DeviceDescriptor> deviceDesc =
+ mAvailableOutputDevices.getDevice(mix->mDeviceType, mix->mDeviceAddress);
+ *selectedDeviceId = deviceDesc != 0 ? deviceDesc->getId() : AUDIO_PORT_HANDLE_NONE;
ALOGV("getOutputForAttr() returns output %d", *output);
goto exit;
}
@@ -840,25 +849,9 @@
ALOGW("getOutputForAttr() no policy mix found for usage AUDIO_USAGE_VIRTUAL_SOURCE");
return BAD_VALUE;
}
+ device = getDeviceForStrategy(strategy, false /*fromCache*/);
}
- // Virtual sources must always be dynamicaly or explicitly routed
- if (attributes.usage == AUDIO_USAGE_VIRTUAL_SOURCE) {
- ALOGW("getOutputForAttr() no policy mix found for usage AUDIO_USAGE_VIRTUAL_SOURCE");
- return BAD_VALUE;
- }
-
- *stream = streamTypefromAttributesInt(&attributes);
-
- // TODO: Should this happen only if an explicit route is active?
- // the previous code structure meant that this would always happen which
- // would appear to result in adding a null deviceDesc when not using an
- // explicit route. Is that the intended and necessary behavior?
- mOutputRoutes.addRoute(session, *stream, SessionRoute::SOURCE_TYPE_NA, deviceDesc, uid);
-
- strategy = (routing_strategy) getStrategyForAttr(&attributes);
- device = getDeviceForStrategy(strategy, false /*fromCache*/);
-
if ((attributes.flags & AUDIO_FLAG_HW_AV_SYNC) != 0) {
*flags = (audio_output_flags_t)(*flags | AUDIO_OUTPUT_FLAG_HW_AV_SYNC);
}
@@ -871,9 +864,10 @@
*stream == AUDIO_STREAM_MUSIC &&
audio_is_linear_pcm(config->format) &&
isInCall()) {
- if (*selectedDeviceId != AUDIO_PORT_HANDLE_NONE) {
+ if (requestedDeviceId != AUDIO_PORT_HANDLE_NONE) {
*flags = (audio_output_flags_t)AUDIO_OUTPUT_FLAG_INCALL_MUSIC;
} else {
+ // Get the devce type directly from the engine to bypass preferred route logic
device = mEngine->getDeviceForStrategy(strategy);
}
}
@@ -897,7 +891,6 @@
*output = getOutputForDevice(device, session, *stream, config, flags);
}
if (*output == AUDIO_IO_HANDLE_NONE) {
- mOutputRoutes.removeRoute(session);
return INVALID_OPERATION;
}
@@ -910,10 +903,12 @@
.format = config->format,
.channel_mask = config->channel_mask };
sp<TrackClientDescriptor> clientDesc =
- new TrackClientDescriptor(*portId, uid, session,
- attributes, clientConfig, requestedDeviceId, *stream, *flags);
+ new TrackClientDescriptor(*portId, uid, session, attributes, clientConfig,
+ requestedDeviceId, *stream,
+ getStrategyForAttr(&attributes),
+ *flags);
sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueFor(*output);
- outputDesc->clients().emplace(*portId, clientDesc);
+ outputDesc->clientsMap().emplace(*portId, clientDesc);
ALOGV(" getOutputForAttr() returns output %d selectedDeviceId %d for port ID %d",
*output, *selectedDeviceId, *portId);
@@ -1325,60 +1320,23 @@
ALOGW("startOutput() no output for client %d", portId);
return BAD_VALUE;
}
- sp<TrackClientDescriptor> client = outputDesc->clients()[portId];
- audio_stream_type_t stream = client->stream();
- audio_session_t session = client->session();
+ sp<TrackClientDescriptor> client = outputDesc->clientsMap()[portId];
ALOGV("startOutput() output %d, stream %d, session %d",
- outputDesc->mIoHandle, stream, session);
+ outputDesc->mIoHandle, client->stream(), client->session());
status_t status = outputDesc->start();
if (status != NO_ERROR) {
return status;
}
- // Routing?
- mOutputRoutes.incRouteActivity(session);
-
- audio_devices_t newDevice;
- AudioMix *policyMix = NULL;
- const char *address = NULL;
- if (outputDesc->mPolicyMix != NULL) {
- policyMix = outputDesc->mPolicyMix;
- address = policyMix->mDeviceAddress.string();
- if ((policyMix->mRouteFlags & MIX_ROUTE_FLAG_RENDER) == MIX_ROUTE_FLAG_RENDER) {
- newDevice = policyMix->mDeviceType;
- } else {
- newDevice = AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
- }
- } else if (mOutputRoutes.getAndClearRouteChanged(session)) {
- newDevice = getNewOutputDevice(outputDesc, false /*fromCache*/);
- if (newDevice != outputDesc->device()) {
- checkStrategyRoute(getStrategy(stream), outputDesc->mIoHandle);
- }
- } else {
- newDevice = AUDIO_DEVICE_NONE;
- }
-
- uint32_t delayMs = 0;
-
- status = startSource(outputDesc, stream, newDevice, address, &delayMs);
+ uint32_t delayMs;
+ status = startSource(outputDesc, client, &delayMs);
if (status != NO_ERROR) {
- mOutputRoutes.decRouteActivity(session);
outputDesc->stop();
return status;
}
- // Automatically enable the remote submix input when output is started on a re routing mix
- // of type MIX_TYPE_RECORDERS
- if (audio_is_remote_submix_device(newDevice) && policyMix != NULL &&
- policyMix->mMixType == MIX_TYPE_RECORDERS) {
- setDeviceConnectionStateInt(AUDIO_DEVICE_IN_REMOTE_SUBMIX,
- AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
- address,
- "remote-submix");
- }
-
if (delayMs != 0) {
usleep(delayMs * 1000);
}
@@ -1386,16 +1344,15 @@
return status;
}
-status_t AudioPolicyManager::startSource(const sp<AudioOutputDescriptor>& outputDesc,
- audio_stream_type_t stream,
- audio_devices_t device,
- const char *address,
- uint32_t *delayMs)
+status_t AudioPolicyManager::startSource(const sp<SwAudioOutputDescriptor>& outputDesc,
+ const sp<TrackClientDescriptor>& client,
+ uint32_t *delayMs)
{
// cannot start playback of STREAM_TTS if any other output is being used
uint32_t beaconMuteLatency = 0;
*delayMs = 0;
+ audio_stream_type_t stream = client->stream();
if (stream == AUDIO_STREAM_TTS) {
ALOGV("\t found BEACON stream");
if (!mTtsOutputAvailable && mOutputs.isAnyOutputActive(AUDIO_STREAM_TTS /*streamToIgnore*/)) {
@@ -1413,6 +1370,19 @@
bool force = !outputDesc->isActive() &&
(outputDesc->getPatchHandle() == AUDIO_PATCH_HANDLE_NONE);
+ audio_devices_t device = AUDIO_DEVICE_NONE;
+ AudioMix *policyMix = NULL;
+ const char *address = NULL;
+ if (outputDesc->mPolicyMix != NULL) {
+ policyMix = outputDesc->mPolicyMix;
+ address = policyMix->mDeviceAddress.string();
+ if ((policyMix->mRouteFlags & MIX_ROUTE_FLAG_RENDER) == MIX_ROUTE_FLAG_RENDER) {
+ device = policyMix->mDeviceType;
+ } else {
+ device = AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
+ }
+ }
+
// requiresMuteCheck is false when we can bypass mute strategy.
// It covers a common case when there is no materially active audio
// and muting would result in unnecessary delay and dropped audio.
@@ -1423,6 +1393,14 @@
// NOTE that the usage count is the same for duplicated output and hardware output which is
// necessary for a correct control of hardware output routing by startOutput() and stopOutput()
outputDesc->changeRefCount(stream, 1);
+ client->setActive(true);
+
+ if (client->hasPreferredDevice(true)) {
+ device = getNewOutputDevice(outputDesc, false /*fromCache*/);
+ if (device != outputDesc->device()) {
+ checkStrategyRoute(getStrategy(stream), outputDesc->mIoHandle);
+ }
+ }
if (stream == AUDIO_STREAM_MUSIC) {
selectOutputForMusicEffects();
@@ -1514,6 +1492,16 @@
setStrategyMute(STRATEGY_SONIFICATION, true, outputDesc);
}
+ // Automatically enable the remote submix input when output is started on a re routing mix
+ // of type MIX_TYPE_RECORDERS
+ if (audio_is_remote_submix_device(device) && policyMix != NULL &&
+ policyMix->mMixType == MIX_TYPE_RECORDERS) {
+ setDeviceConnectionStateInt(AUDIO_DEVICE_IN_REMOTE_SUBMIX,
+ AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
+ address,
+ "remote-submix");
+ }
+
return NO_ERROR;
}
@@ -1526,37 +1514,12 @@
ALOGW("stopOutput() no output for client %d", portId);
return BAD_VALUE;
}
- sp<TrackClientDescriptor> client = outputDesc->clients()[portId];
- audio_stream_type_t stream = client->stream();
- audio_session_t session = client->session();
+ sp<TrackClientDescriptor> client = outputDesc->clientsMap()[portId];
- ALOGV("stopOutput() output %d, stream %d, session %d", outputDesc->mIoHandle, stream, session);
+ ALOGV("stopOutput() output %d, stream %d, session %d",
+ outputDesc->mIoHandle, client->stream(), client->session());
- if (outputDesc->mRefCount[stream] == 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->mDevice) &&
- outputDesc->mPolicyMix != NULL &&
- outputDesc->mPolicyMix->mMixType == MIX_TYPE_RECORDERS) {
- setDeviceConnectionStateInt(AUDIO_DEVICE_IN_REMOTE_SUBMIX,
- AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
- outputDesc->mPolicyMix->mDeviceAddress,
- "remote-submix");
- }
- }
-
- // Routing?
- bool forceDeviceUpdate = false;
- if (outputDesc->mRefCount[stream] > 0) {
- int activityCount = mOutputRoutes.decRouteActivity(session);
- forceDeviceUpdate = (mOutputRoutes.hasRoute(session) && (activityCount == 0));
-
- if (forceDeviceUpdate) {
- checkStrategyRoute(getStrategy(stream), AUDIO_IO_HANDLE_NONE);
- }
- }
-
- status_t status = stopSource(outputDesc, stream, forceDeviceUpdate);
+ status_t status = stopSource(outputDesc, client);
if (status == NO_ERROR ) {
outputDesc->stop();
@@ -1564,16 +1527,36 @@
return status;
}
-status_t AudioPolicyManager::stopSource(const sp<AudioOutputDescriptor>& outputDesc,
- audio_stream_type_t stream,
- bool forceDeviceUpdate)
+status_t AudioPolicyManager::stopSource(const sp<SwAudioOutputDescriptor>& outputDesc,
+ const sp<TrackClientDescriptor>& client)
{
// always handle stream stop, check which stream type is stopping
+ audio_stream_type_t stream = client->stream();
+
handleEventForBeacon(stream == AUDIO_STREAM_TTS ? STOPPING_BEACON : STOPPING_OUTPUT);
if (outputDesc->mRefCount[stream] > 0) {
+ if (outputDesc->mRefCount[stream] == 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->mDevice) &&
+ outputDesc->mPolicyMix != NULL &&
+ outputDesc->mPolicyMix->mMixType == MIX_TYPE_RECORDERS) {
+ setDeviceConnectionStateInt(AUDIO_DEVICE_IN_REMOTE_SUBMIX,
+ AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
+ outputDesc->mPolicyMix->mDeviceAddress,
+ "remote-submix");
+ }
+ }
+ bool forceDeviceUpdate = false;
+ if (client->hasPreferredDevice(true)) {
+ checkStrategyRoute(getStrategy(stream), AUDIO_IO_HANDLE_NONE);
+ forceDeviceUpdate = true;
+ }
+
// decrement usage count of this stream on the output
outputDesc->changeRefCount(stream, -1);
+ client->setActive(false);
// store time at which the stream was stopped - see isStreamActive()
if (outputDesc->mRefCount[stream] == 0 || forceDeviceUpdate) {
@@ -1636,14 +1619,10 @@
ALOGW("releaseOutput() no output for client %d", portId);
return;
}
- sp<TrackClientDescriptor> client = outputDesc->clients()[portId];
- audio_session_t session = client->session();
+ sp<TrackClientDescriptor> client = outputDesc->clientsMap()[portId];
ALOGV("releaseOutput() %d", outputDesc->mIoHandle);
- // Routing
- mOutputRoutes.removeRoute(session);
-
if (outputDesc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) {
if (outputDesc->mDirectOpenCount <= 0) {
ALOGW("releaseOutput() invalid open count %d for output %d",
@@ -1655,7 +1634,7 @@
mpClientInterface->onAudioPortListUpdate();
}
}
- outputDesc->clients().erase(portId);
+ outputDesc->clientsMap().erase(portId);
}
@@ -1693,7 +1672,6 @@
if (*selectedDeviceId != AUDIO_PORT_HANDLE_NONE) {
deviceDesc = mAvailableInputDevices.getDeviceFromId(*selectedDeviceId);
}
- mInputRoutes.addRoute(session, SessionRoute::STREAM_TYPE_NA, inputSource, deviceDesc, uid);
// special case for mmap capture: if an input IO handle is specified, we reuse this input if
// possible
@@ -1763,7 +1741,11 @@
device = AUDIO_DEVICE_IN_REMOTE_SUBMIX;
address = String8(attr->tags + strlen("addr="));
} else {
- device = getDeviceAndMixForInputSource(inputSource, &policyMix);
+ if (deviceDesc != 0) {
+ device = deviceDesc->type();
+ } else {
+ device = getDeviceAndMixForInputSource(inputSource, &policyMix);
+ }
if (device == AUDIO_DEVICE_NONE) {
ALOGW("getInputForAttr() could not find device for source %d", inputSource);
status = BAD_VALUE;
@@ -1808,7 +1790,7 @@
clientDesc = new RecordClientDescriptor(*portId, uid, session,
*attr, *config, requestedDeviceId, inputSource, flags);
inputDesc = mInputs.valueFor(*input);
- inputDesc->clients().emplace(*portId, clientDesc);
+ inputDesc->clientsMap().emplace(*portId, clientDesc);
ALOGV("getInputForAttr() returns input %d type %d selectedDeviceId %d for port ID %d",
*input, *inputType, *selectedDeviceId, *portId);
@@ -1816,7 +1798,6 @@
return NO_ERROR;
error:
- mInputRoutes.removeRoute(session);
return status;
}
@@ -2027,7 +2008,7 @@
ALOGW("startInput() no input for client %d", portId);
return BAD_VALUE;
}
- sp<RecordClientDescriptor> client = inputDesc->clients()[portId];
+ sp<RecordClientDescriptor> client = inputDesc->clientsMap()[portId];
audio_session_t session = client->session();
audio_io_handle_t input = inputDesc->mIoHandle;
@@ -2137,11 +2118,9 @@
// increment activity count before calling getNewInputDevice() below as only active sessions
// are considered for device selection
inputDesc->changeRefCount(session, 1);
+ client->setActive(true);
- // Routing?
- mInputRoutes.incRouteActivity(session);
-
- if (audioSession->activeCount() == 1 || mInputRoutes.getAndClearRouteChanged(session)) {
+ if (audioSession->activeCount() == 1 || client->hasPreferredDevice(true)) {
// indicate active capture to sound trigger service if starting capture from a mic on
// primary HW module
audio_devices_t device = getNewInputDevice(inputDesc);
@@ -2149,8 +2128,8 @@
status_t status = inputDesc->start();
if (status != NO_ERROR) {
- mInputRoutes.decRouteActivity(session);
inputDesc->changeRefCount(session, -1);
+ client->setActive(false);
return status;
}
@@ -2201,7 +2180,7 @@
ALOGW("stopInput() no input for client %d", portId);
return BAD_VALUE;
}
- sp<RecordClientDescriptor> client = inputDesc->clients()[portId];
+ sp<RecordClientDescriptor> client = inputDesc->clientsMap()[portId];
audio_session_t session = client->session();
audio_io_handle_t input = inputDesc->mIoHandle;
@@ -2215,9 +2194,7 @@
}
inputDesc->changeRefCount(session, -1);
-
- // Routing?
- mInputRoutes.decRouteActivity(session);
+ client->setActive(false);
if (audioSession->activeCount() == 0) {
inputDesc->stop();
@@ -2272,15 +2249,12 @@
ALOGW("releaseInput() no input for client %d", portId);
return;
}
- sp<RecordClientDescriptor> client = inputDesc->clients()[portId];
+ sp<RecordClientDescriptor> client = inputDesc->clientsMap()[portId];
audio_session_t session = client->session();
audio_io_handle_t input = inputDesc->mIoHandle;
ALOGV("releaseInput() %d", input);
- // Routing
- mInputRoutes.removeRoute(session);
-
sp<AudioSession> audioSession = inputDesc->getAudioSession(session);
if (audioSession == 0) {
ALOGW("releaseInput() unknown session %d on input %d", session, input);
@@ -2303,7 +2277,7 @@
}
closeInput(input);
- inputDesc->clients().erase(portId);
+ inputDesc->clientsMap().erase(portId);
mpClientInterface->onAudioPortListUpdate();
ALOGV("releaseInput() exit");
}
@@ -2342,7 +2316,6 @@
}
inputDesc->close();
}
- mInputRoutes.clear();
mInputs.clear();
SoundTrigger::setCaptureState(false);
nextAudioPortGeneration();
@@ -2619,12 +2592,13 @@
sp<HwModule> rSubmixModule;
// examine each mix's route type
for (size_t i = 0; i < mixes.size(); i++) {
+ AudioMix mix = mixes[i];
// we only support MIX_ROUTE_FLAG_LOOP_BACK or MIX_ROUTE_FLAG_RENDER, not the combination
- if ((mixes[i].mRouteFlags & MIX_ROUTE_FLAG_ALL) == MIX_ROUTE_FLAG_ALL) {
+ if ((mix.mRouteFlags & MIX_ROUTE_FLAG_ALL) == MIX_ROUTE_FLAG_ALL) {
res = INVALID_OPERATION;
break;
}
- if ((mixes[i].mRouteFlags & MIX_ROUTE_FLAG_LOOP_BACK) == MIX_ROUTE_FLAG_LOOP_BACK) {
+ if ((mix.mRouteFlags & MIX_ROUTE_FLAG_LOOP_BACK) == MIX_ROUTE_FLAG_LOOP_BACK) {
ALOGV("registerPolicyMixes() mix %zu of %zu is LOOP_BACK", i, mixes.size());
if (rSubmixModule == 0) {
rSubmixModule = mHwModules.getModuleFromName(
@@ -2637,15 +2611,20 @@
}
}
- String8 address = mixes[i].mDeviceAddress;
+ String8 address = mix.mDeviceAddress;
+ if (mix.mMixType == MIX_TYPE_PLAYERS) {
+ mix.mDeviceType = AUDIO_DEVICE_IN_REMOTE_SUBMIX;
+ } else {
+ mix.mDeviceType = AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
+ }
- if (mPolicyMixes.registerMix(address, mixes[i], 0 /*output desc*/) != NO_ERROR) {
+ if (mPolicyMixes.registerMix(address, mix, 0 /*output desc*/) != NO_ERROR) {
ALOGE(" Error registering mix %zu for address %s", i, address.string());
res = INVALID_OPERATION;
break;
}
- audio_config_t outputConfig = mixes[i].mFormat;
- audio_config_t inputConfig = mixes[i].mFormat;
+ audio_config_t outputConfig = mix.mFormat;
+ audio_config_t inputConfig = mix.mFormat;
// NOTE: audio flinger mixer does not support mono output: configure remote submix HAL in
// stereo and let audio flinger do the channel conversion if needed.
outputConfig.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
@@ -2655,7 +2634,7 @@
rSubmixModule->addInputProfile(address, &inputConfig,
AUDIO_DEVICE_IN_REMOTE_SUBMIX, address);
- if (mixes[i].mMixType == MIX_TYPE_PLAYERS) {
+ if (mix.mMixType == MIX_TYPE_PLAYERS) {
setDeviceConnectionStateInt(AUDIO_DEVICE_IN_REMOTE_SUBMIX,
AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
address.string(), "remote-submix");
@@ -2664,9 +2643,9 @@
AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
address.string(), "remote-submix");
}
- } else if ((mixes[i].mRouteFlags & MIX_ROUTE_FLAG_RENDER) == MIX_ROUTE_FLAG_RENDER) {
- String8 address = mixes[i].mDeviceAddress;
- audio_devices_t device = mixes[i].mDeviceType;
+ } else if ((mix.mRouteFlags & MIX_ROUTE_FLAG_RENDER) == MIX_ROUTE_FLAG_RENDER) {
+ String8 address = mix.mDeviceAddress;
+ audio_devices_t device = mix.mDeviceType;
ALOGV(" registerPolicyMixes() mix %zu of %zu is RENDER, dev=0x%X addr=%s",
i, mixes.size(), device, address.string());
@@ -2679,7 +2658,7 @@
&& (patch->mPatch.sinks[0].ext.device.type == device)
&& (strncmp(patch->mPatch.sinks[0].ext.device.address, address.string(),
AUDIO_DEVICE_MAX_ADDRESS_LEN) == 0)) {
- if (mPolicyMixes.registerMix(address, mixes[i], desc) != NO_ERROR) {
+ if (mPolicyMixes.registerMix(address, mix, desc) != NO_ERROR) {
res = INVALID_OPERATION;
} else {
foundOutput = true;
@@ -3391,12 +3370,13 @@
{
// remove output routes associated with this uid
SortedVector<routing_strategy> affectedStrategies;
- for (ssize_t i = (ssize_t)mOutputRoutes.size() - 1; i >= 0; i--) {
- sp<SessionRoute> route = mOutputRoutes.valueAt(i);
- if (route->mUid == uid) {
- mOutputRoutes.removeItemsAt(i);
- if (route->mDeviceDescriptor != 0) {
- affectedStrategies.add(getStrategy(route->mStreamType));
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ sp<AudioOutputDescriptor> outputDesc = mOutputs.valueAt(i);
+ TrackClientMap clients = outputDesc->clientsMap();
+ for (const auto& client : clients) {
+ if (client.second->hasPreferredDevice() && client.second->uid() == uid) {
+ client.second->setPreferredDeviceId(AUDIO_PORT_HANDLE_NONE);
+ affectedStrategies.add(getStrategy(client.second->stream()));
}
}
}
@@ -3407,12 +3387,13 @@
// remove input routes associated with this uid
SortedVector<audio_source_t> affectedSources;
- for (ssize_t i = (ssize_t)mInputRoutes.size() - 1; i >= 0; i--) {
- sp<SessionRoute> route = mInputRoutes.valueAt(i);
- if (route->mUid == uid) {
- mInputRoutes.removeItemsAt(i);
- if (route->mDeviceDescriptor != 0) {
- affectedSources.add(route->mSource);
+ for (size_t i = 0; i < mInputs.size(); i++) {
+ sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(i);
+ RecordClientMap clients = inputDesc->clientsMap();
+ for (const auto& client : clients) {
+ if (client.second->hasPreferredDevice() && client.second->uid() == uid) {
+ client.second->setPreferredDeviceId(AUDIO_PORT_HANDLE_NONE);
+ affectedSources.add(client.second->source());
}
}
}
@@ -3486,7 +3467,8 @@
sp<SourceClientDescriptor> sourceDesc =
new SourceClientDescriptor(*portId, uid, *attributes, patchDesc, srcDeviceDesc,
- streamTypefromAttributesInt(attributes));
+ streamTypefromAttributesInt(attributes),
+ getStrategyForAttr(attributes));
status_t status = connectAudioSource(sourceDesc);
if (status == NO_ERROR) {
@@ -3503,7 +3485,7 @@
disconnectAudioSource(sourceDesc);
audio_attributes_t attributes = sourceDesc->attributes();
- routing_strategy strategy = (routing_strategy) getStrategyForAttr(&attributes);
+ routing_strategy strategy = getStrategyForAttr(&attributes);
audio_stream_type_t stream = sourceDesc->stream();
sp<DeviceDescriptor> srcDeviceDesc = sourceDesc->srcDevice();
@@ -3557,7 +3539,7 @@
return INVALID_OPERATION;
}
uint32_t delayMs = 0;
- status = startSource(outputDesc, stream, sinkDevice, NULL, &delayMs);
+ status = startSource(outputDesc, sourceDesc, &delayMs);
if (status != NO_ERROR) {
mpClientInterface->releaseAudioPatch(sourceDesc->patchDesc()->mAfPatchHandle, 0);
@@ -3931,10 +3913,9 @@
}
removeAudioPatch(sourceDesc->patchDesc()->mHandle);
- audio_stream_type_t stream = sourceDesc->stream();
sp<SwAudioOutputDescriptor> swOutputDesc = sourceDesc->swOutput().promote();
if (swOutputDesc != 0) {
- status_t status = stopSource(swOutputDesc, stream, false);
+ status_t status = stopSource(swOutputDesc, sourceDesc);
if (status == NO_ERROR) {
swOutputDesc->stop();
}
@@ -3958,8 +3939,7 @@
for (size_t i = 0; i < mAudioSources.size(); i++) {
sp<SourceClientDescriptor> sourceDesc = mAudioSources.valueAt(i);
audio_attributes_t attributes = sourceDesc->attributes();
- routing_strategy sourceStrategy =
- (routing_strategy) getStrategyForAttr(&attributes);
+ routing_strategy sourceStrategy = getStrategyForAttr(&attributes);
sp<SwAudioOutputDescriptor> outputDesc = sourceDesc->swOutput().promote();
if (sourceStrategy == strategy && outputDesc != 0 && outputDesc->mIoHandle == output) {
source = sourceDesc;
@@ -4936,11 +4916,41 @@
}
}
+template <class IoDescriptor, class Filter>
+sp<DeviceDescriptor> AudioPolicyManager::findPreferredDevice(
+ IoDescriptor& desc, Filter filter, bool& active, const DeviceVector& devices)
+{
+ auto activeClients = desc->clientsList(true /*activeOnly*/);
+ auto activeClientsWithRoute =
+ desc->clientsList(true /*activeOnly*/, filter, true /*preferredDevice*/);
+ active = activeClients.size() > 0;
+ if (active && activeClients.size() == activeClientsWithRoute.size()) {
+ return devices.getDeviceFromId(activeClientsWithRoute[0]->preferredDeviceId());
+ }
+ return nullptr;
+}
+
+template <class IoCollection, class Filter>
+sp<DeviceDescriptor> AudioPolicyManager::findPreferredDevice(
+ IoCollection& ioCollection, Filter filter, const DeviceVector& devices)
+{
+ sp<DeviceDescriptor> device;
+ for (size_t i = 0; i < ioCollection.size(); i++) {
+ auto desc = ioCollection.valueAt(i);
+ bool active;
+ sp<DeviceDescriptor> curDevice = findPreferredDevice(desc, filter, active, devices);
+ if (active && curDevice == nullptr) {
+ return nullptr;
+ } else if (curDevice != nullptr) {
+ device = curDevice;
+ }
+ }
+ return device;
+}
+
audio_devices_t AudioPolicyManager::getNewOutputDevice(const sp<AudioOutputDescriptor>& outputDesc,
bool fromCache)
{
- audio_devices_t device = AUDIO_DEVICE_NONE;
-
ssize_t index = mAudioPatches.indexOfKey(outputDesc->getPatchHandle());
if (index >= 0) {
sp<AudioPatch> patchDesc = mAudioPatches.valueAt(index);
@@ -4951,18 +4961,13 @@
}
}
- // Check if an explicit routing request exists for an active stream on this output and
- // use it in priority before any other rule
- for (int stream = 0; stream < AUDIO_STREAM_FOR_POLICY_CNT; stream++) {
- if (outputDesc->isStreamActive((audio_stream_type_t)stream)) {
- audio_devices_t forcedDevice =
- mOutputRoutes.getActiveDeviceForStream(
- (audio_stream_type_t)stream, mAvailableOutputDevices);
-
- if (forcedDevice != AUDIO_DEVICE_NONE) {
- return forcedDevice;
- }
- }
+ // Honor explicit routing requests only if no client using default routing is active on this
+ // input: a specific app can not force routing for other apps by setting a preferred device.
+ bool active; // unused
+ sp<DeviceDescriptor> deviceDesc =
+ findPreferredDevice(outputDesc, STRATEGY_NONE, active, mAvailableOutputDevices);
+ if (deviceDesc != nullptr) {
+ return deviceDesc->type();
}
// check the following by order of priority to request a routing change if necessary:
@@ -4988,6 +4993,7 @@
// FIXME: extend use of isStrategyActiveOnSameModule() to all strategies
// with a refined rule considering mutually exclusive devices (using same backend)
// as opposed to all streams on the same audio HAL module.
+ audio_devices_t device = AUDIO_DEVICE_NONE;
if (isStrategyActive(outputDesc, STRATEGY_ENFORCED_AUDIBLE) &&
mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED) {
device = getDeviceForStrategy(STRATEGY_ENFORCED_AUDIBLE, fromCache);
@@ -5030,6 +5036,15 @@
}
}
+ // Honor explicit routing requests only if no client using default routing is active on this
+ // input: a specific app can not force routing for other apps by setting a preferred device.
+ bool active;
+ sp<DeviceDescriptor> deviceDesc =
+ findPreferredDevice(inputDesc, AUDIO_SOURCE_DEFAULT, active, mAvailableInputDevices);
+ if (deviceDesc != nullptr) {
+ return deviceDesc->type();
+ }
+
// If we are not in call and no client is active on this input, this methods returns
// AUDIO_DEVICE_NONE, causing the patch on the input stream to be released.
audio_source_t source = inputDesc->getHighestPrioritySource(true /*activeOnly*/);
@@ -5091,16 +5106,16 @@
return mEngine->getStrategyForStream(stream);
}
-uint32_t AudioPolicyManager::getStrategyForAttr(const audio_attributes_t *attr) {
+routing_strategy AudioPolicyManager::getStrategyForAttr(const audio_attributes_t *attr) {
// flags to strategy mapping
if ((attr->flags & AUDIO_FLAG_BEACON) == AUDIO_FLAG_BEACON) {
- return (uint32_t) STRATEGY_TRANSMITTED_THROUGH_SPEAKER;
+ return STRATEGY_TRANSMITTED_THROUGH_SPEAKER;
}
if ((attr->flags & AUDIO_FLAG_AUDIBILITY_ENFORCED) == AUDIO_FLAG_AUDIBILITY_ENFORCED) {
- return (uint32_t) STRATEGY_ENFORCED_AUDIBLE;
+ return STRATEGY_ENFORCED_AUDIBLE;
}
// usage to strategy mapping
- return static_cast<uint32_t>(mEngine->getStrategyForUsage(attr->usage));
+ return mEngine->getStrategyForUsage(attr->usage);
}
void AudioPolicyManager::handleNotificationRoutingForStream(audio_stream_type_t stream) {
@@ -5176,17 +5191,11 @@
audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strategy,
bool fromCache)
{
- // Check if an explicit routing request exists for a stream type corresponding to the
- // specified strategy and use it in priority over default routing rules.
- for (int stream = 0; stream < AUDIO_STREAM_FOR_POLICY_CNT; stream++) {
- if (getStrategy((audio_stream_type_t)stream) == strategy) {
- audio_devices_t forcedDevice =
- mOutputRoutes.getActiveDeviceForStream(
- (audio_stream_type_t)stream, mAvailableOutputDevices);
- if (forcedDevice != AUDIO_DEVICE_NONE) {
- return forcedDevice;
- }
- }
+ // Honor explicit routing requests only if all active clients have a preferred route in which
+ // case the last active client route is used
+ sp<DeviceDescriptor> deviceDesc = findPreferredDevice(mOutputs, strategy, mAvailableOutputDevices);
+ if (deviceDesc != nullptr) {
+ return deviceDesc->type();
}
if (fromCache) {
@@ -5530,6 +5539,15 @@
audio_devices_t AudioPolicyManager::getDeviceAndMixForInputSource(audio_source_t inputSource,
AudioMix **policyMix)
{
+ // Honor explicit routing requests only if all active clients have a preferred route in which
+ // case the last active client route is used
+ sp<DeviceDescriptor> deviceDesc =
+ findPreferredDevice(mInputs, inputSource, mAvailableInputDevices);
+ if (deviceDesc != nullptr) {
+ return deviceDesc->type();
+ }
+
+
audio_devices_t availableDeviceTypes = mAvailableInputDevices.types() & ~AUDIO_DEVICE_BIT_IN;
audio_devices_t selectedDeviceFromMix =
mPolicyMixes.getDeviceAndMixForInputSource(inputSource, availableDeviceTypes, policyMix);
@@ -5542,20 +5560,7 @@
audio_devices_t AudioPolicyManager::getDeviceForInputSource(audio_source_t inputSource)
{
- // Routing
- // Scan the whole RouteMap to see if we have an explicit route:
- // if the input source in the RouteMap is the same as the argument above,
- // and activity count is non-zero and the device in the route descriptor is available
- // then select this device.
- for (size_t routeIndex = 0; routeIndex < mInputRoutes.size(); routeIndex++) {
- sp<SessionRoute> route = mInputRoutes.valueAt(routeIndex);
- if ((inputSource == route->mSource) && route->isActiveOrChanged() &&
- (mAvailableInputDevices.indexOf(route->mDeviceDescriptor) >= 0)) {
- return route->mDeviceDescriptor->type();
- }
- }
-
- return mEngine->getDeviceForInputSource(inputSource);
+ return mEngine->getDeviceForInputSource(inputSource);
}
float AudioPolicyManager::computeVolume(audio_stream_type_t stream,
@@ -5860,7 +5865,7 @@
}
for (int i = 0; i < (int)AUDIO_STREAM_FOR_POLICY_CNT; i++) {
if (((getStrategy((audio_stream_type_t)i) == strategy) ||
- (NUM_STRATEGIES == strategy)) &&
+ (STRATEGY_NONE == strategy)) &&
outputDesc->isStreamActive((audio_stream_type_t)i, inPastMs, sysTime)) {
return true;
}
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 9436767..cc5739b 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -49,7 +49,6 @@
#include <AudioPolicyMix.h>
#include <EffectDescriptor.h>
#include <SoundTriggerSession.h>
-#include <SessionRoute.h>
#include <VolumeCurve.h>
namespace android {
@@ -156,7 +155,7 @@
// return the strategy corresponding to a given stream type
virtual uint32_t getStrategyForStream(audio_stream_type_t stream);
// return the strategy corresponding to the given audio attributes
- virtual uint32_t getStrategyForAttr(const audio_attributes_t *attr);
+ virtual routing_strategy getStrategyForAttr(const audio_attributes_t *attr);
// return the enabled output devices for the given stream type
virtual audio_devices_t getDevicesForStream(audio_stream_type_t stream);
@@ -366,7 +365,7 @@
bool on,
const sp<AudioOutputDescriptor>& outputDesc,
int delayMs = 0,
- audio_devices_t device = (audio_devices_t)0);
+ audio_devices_t device = AUDIO_DEVICE_NONE);
// Mute or unmute the stream on the specified output
void setStreamMute(audio_stream_type_t stream,
@@ -422,6 +421,14 @@
// manages A2DP output suspend/restore according to phone state and BT SCO usage
void checkA2dpSuspend();
+ template <class IoDescriptor, class Filter>
+ sp<DeviceDescriptor> findPreferredDevice(IoDescriptor& desc, Filter filter,
+ bool& active, const DeviceVector& devices);
+
+ template <class IoCollection, class Filter>
+ sp<DeviceDescriptor> findPreferredDevice(IoCollection& ioCollection, Filter filter,
+ const DeviceVector& devices);
+
// selects the most appropriate device on output for current state
// must be called every time a condition that affects the device choice for a given output is
// changed: connected device, phone state, force use, output start, output stop..
@@ -508,16 +515,11 @@
sp<DeviceDescriptor> findDevice(
const DeviceVector& devices, audio_devices_t device) const;
- // if argument "device" is different from AUDIO_DEVICE_NONE, startSource() will force
- // the re-evaluation of the output device.
- status_t startSource(const sp<AudioOutputDescriptor>& outputDesc,
- audio_stream_type_t stream,
- audio_devices_t device,
- const char *address,
+ status_t startSource(const sp<SwAudioOutputDescriptor>& outputDesc,
+ const sp<TrackClientDescriptor>& client,
uint32_t *delayMs);
- status_t stopSource(const sp<AudioOutputDescriptor>& outputDesc,
- audio_stream_type_t stream,
- bool forceDeviceUpdate);
+ status_t stopSource(const sp<SwAudioOutputDescriptor>& outputDesc,
+ const sp<TrackClientDescriptor>& client);
void clearAudioPatches(uid_t uid);
void clearSessionRoutes(uid_t uid);
@@ -561,9 +563,6 @@
DeviceVector mAvailableOutputDevices; // all available output devices
DeviceVector mAvailableInputDevices; // all available input devices
- SessionRouteMap mOutputRoutes = SessionRouteMap(SessionRouteMap::MAPTYPE_OUTPUT);
- SessionRouteMap mInputRoutes = SessionRouteMap(SessionRouteMap::MAPTYPE_INPUT);
-
bool mLimitRingtoneVolume; // limit ringtone volume to music volume if headset connected
audio_devices_t mDeviceForStrategy[NUM_STRATEGIES];
float mLastVoiceVolume; // last voice volume value sent to audio HAL