Revert "audio policy: concurrent capture"
This reverts commit 4c1ef4b64d113be6ee1106375bd10cdc643e80d8.
Reason for revert: b/120588242
Bug: 120588242
Change-Id: Iac41f371cb739c54d5ce519232688bebe2285c72
Test: Launch QSB and capture from mic icon
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index e70e567..45d3a06 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -7367,7 +7367,8 @@
status_t status = NO_ERROR;
if (recordTrack->isExternalTrack()) {
mLock.unlock();
- status = AudioSystem::startInput(recordTrack->portId());
+ bool silenced;
+ status = AudioSystem::startInput(recordTrack->portId(), &silenced);
mLock.lock();
if (recordTrack->isInvalid()) {
recordTrack->clearSyncStartEvent();
@@ -7395,6 +7396,7 @@
recordTrack->clearSyncStartEvent();
return status;
}
+ recordTrack->setSilenced(silenced);
}
// Catch up with current buffer indices if thread is already running.
// This is what makes a new client discard all buffered data. If the track's mRsmpInFront
@@ -8344,10 +8346,11 @@
return BAD_VALUE;
}
+ bool silenced = false;
if (isOutput()) {
ret = AudioSystem::startOutput(portId);
} else {
- ret = AudioSystem::startInput(portId);
+ ret = AudioSystem::startInput(portId, &silenced);
}
Mutex::Autolock _l(mLock);
@@ -8368,21 +8371,21 @@
return PERMISSION_DENIED;
}
+ if (isOutput()) {
+ // force volume update when a new track is added
+ mHalVolFloat = -1.0f;
+ } else if (!silenced) {
+ for (const sp<MmapTrack> &track : mActiveTracks) {
+ if (track->isSilenced_l() && track->uid() != client.clientUid)
+ track->invalidate();
+ }
+ }
+
// Given that MmapThread::mAttr is mutable, should a MmapTrack have attributes ?
sp<MmapTrack> track = new MmapTrack(this, mAttr, mSampleRate, mFormat, mChannelMask, mSessionId,
isOutput(), client.clientUid, client.clientPid, portId);
- if (isOutput()) {
- // force volume update when a new track is added
- mHalVolFloat = -1.0f;
- } else if (!track->isSilenced_l()) {
- for (const sp<MmapTrack> &t : mActiveTracks) {
- if (t->isSilenced_l() && t->uid() != client.clientUid)
- t->invalidate();
- }
- }
-
-
+ track->setSilenced_l(silenced);
mActiveTracks.add(track);
sp<EffectChain> chain = getEffectChain_l(mSessionId);
if (chain != 0) {
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index 3fb505d..3c3a82b 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -65,6 +65,20 @@
API_INPUT_TELEPHONY_RX, // used for capture from telephony RX path
} input_type_t;
+ enum {
+ API_INPUT_CONCURRENCY_NONE = 0,
+ API_INPUT_CONCURRENCY_CALL = (1 << 0), // Concurrency with a call
+ API_INPUT_CONCURRENCY_CAPTURE = (1 << 1), // Concurrency with another capture
+ API_INPUT_CONCURRENCY_HOTWORD = (1 << 2), // Concurrency with a hotword
+ API_INPUT_CONCURRENCY_PREEMPT = (1 << 3), // pre-empted someone
+ // NB: preempt is marked on a successful return, others are on failing calls
+ API_INPUT_CONCURRENCY_LAST = (1 << 4),
+
+ API_INPUT_CONCURRENCY_ALL = (API_INPUT_CONCURRENCY_LAST - 1),
+ };
+
+ typedef uint32_t concurrency_type__mask_t;
+
public:
virtual ~AudioPolicyInterface() {}
//
@@ -127,7 +141,9 @@
input_type_t *inputType,
audio_port_handle_t *portId) = 0;
// indicates to the audio policy manager that the input starts being used.
- virtual status_t startInput(audio_port_handle_t portId) = 0;
+ virtual status_t startInput(audio_port_handle_t portId,
+ bool silenced,
+ concurrency_type__mask_t *concurrency) = 0;
// indicates to the audio policy manager that the input stops being used.
virtual status_t stopInput(audio_port_handle_t portId) = 0;
// releases the input.
diff --git a/services/audiopolicy/common/include/policy.h b/services/audiopolicy/common/include/policy.h
index 30b0044..9bd68e1 100644
--- a/services/audiopolicy/common/include/policy.h
+++ b/services/audiopolicy/common/include/policy.h
@@ -32,6 +32,14 @@
#define MAX_MIXER_CHANNEL_COUNT FCC_8
/**
+ * A device mask for all audio input devices that are considered "virtual" when evaluating
+ * active inputs in getActiveInputs()
+ */
+#define APM_AUDIO_IN_DEVICE_VIRTUAL_ALL (AUDIO_DEVICE_IN_REMOTE_SUBMIX|\
+ AUDIO_DEVICE_IN_BUS|AUDIO_DEVICE_IN_FM_TUNER)
+
+
+/**
* A device mask for all audio input and output devices where matching inputs/outputs on device
* type alone is not enough: the address must match too
*/
@@ -60,6 +68,23 @@
}
/**
+ * Check if the input device given is considered as a virtual device.
+ *
+ * @param[in] device to consider
+ *
+ * @return true if the device is a virtual one, false otherwise.
+ */
+static inline bool is_virtual_input_device(audio_devices_t device)
+{
+ if ((device & AUDIO_DEVICE_BIT_IN) != 0) {
+ device &= ~AUDIO_DEVICE_BIT_IN;
+ if ((popcount(device) == 1) && ((device & ~APM_AUDIO_IN_DEVICE_VIRTUAL_ALL) == 0))
+ return true;
+ }
+ return false;
+}
+
+/**
* Check whether the device type is one
* where addresses are used to distinguish between one connected device and another
*
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
index 9f8b8c0..6e4c044 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
@@ -58,8 +58,9 @@
void clearPreemptedSessions();
bool isActive() const { return mGlobalActiveCount > 0; }
bool isSourceActive(audio_source_t source) const;
- audio_source_t source() const;
+ audio_source_t inputSource(bool activeOnly = false) const;
bool isSoundTrigger() const;
+ audio_source_t getHighestPrioritySource(bool activeOnly) const;
void setClientActive(const sp<RecordClientDescriptor>& client, bool active);
int32_t activeCount() { return mGlobalActiveCount; }
@@ -120,7 +121,7 @@
* Only considers inputs from physical devices (e.g. main mic, headset mic) when
* ignoreVirtualInputs is true.
*/
- Vector<sp <AudioInputDescriptor> > getActiveInputs();
+ Vector<sp <AudioInputDescriptor> > getActiveInputs(bool ignoreVirtualInputs = true);
audio_devices_t getSupportedDevices(audio_io_handle_t handle) const;
diff --git a/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
index 986d109..030bf4b 100644
--- a/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
@@ -22,7 +22,6 @@
#include <sys/types.h>
#include <system/audio.h>
-#include <system/audio_policy.h>
#include <utils/Errors.h>
#include <utils/KeyedVector.h>
#include <utils/RefBase.h>
@@ -107,7 +106,7 @@
audio_port_handle_t preferredDeviceId,
audio_source_t source, audio_input_flags_t flags, bool isSoundTrigger) :
ClientDescriptor(portId, uid, sessionId, attributes, config, preferredDeviceId),
- mSource(source), mFlags(flags), mIsSoundTrigger(isSoundTrigger), mAppState(APP_STATE_IDLE) {}
+ mSource(source), mFlags(flags), mIsSoundTrigger(isSoundTrigger), mSilenced(false) {}
~RecordClientDescriptor() override = default;
using ClientDescriptor::dump;
@@ -116,16 +115,14 @@
audio_source_t source() const { return mSource; }
audio_input_flags_t flags() const { return mFlags; }
bool isSoundTrigger() const { return mIsSoundTrigger; }
- void setAppState(app_state_t appState) { mAppState = appState; }
- app_state_t appState() { return mAppState; }
- bool isSilenced() const { return mAppState == APP_STATE_IDLE; }
+ void setSilenced(bool silenced) { mSilenced = silenced; }
+ bool isSilenced() const { return mSilenced; }
private:
const audio_source_t mSource;
const audio_input_flags_t mFlags;
const bool mIsSoundTrigger;
- app_state_t mAppState;
-
+ bool mSilenced;
};
class SourceClientDescriptor: public TrackClientDescriptor
diff --git a/services/audiopolicy/common/managerdefinitions/include/IOProfile.h b/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
index 8ff8238..eb32959 100644
--- a/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
+++ b/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
@@ -35,7 +35,7 @@
public:
IOProfile(const String8 &name, audio_port_role_t role)
: AudioPort(name, AUDIO_PORT_TYPE_MIX, role),
- maxOpenCount(1),
+ maxOpenCount((role == AUDIO_PORT_ROLE_SOURCE) ? 1 : 0),
curOpenCount(0),
maxActiveCount(1),
curActiveCount(0) {}
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
index 559274f..1f29874 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
@@ -53,32 +53,9 @@
return mId;
}
-audio_source_t AudioInputDescriptor::source() const
+audio_source_t AudioInputDescriptor::inputSource(bool activeOnly) const
{
- audio_source_t source = AUDIO_SOURCE_DEFAULT;
-
- for (bool activeOnly : { true, false }) {
- int32_t topPriority = -1;
- app_state_t topState = APP_STATE_IDLE;
- for (const auto &client : getClientIterable()) {
- if (activeOnly && !client->active()) {
- continue;
- }
- app_state_t curState = client->appState();
- if (curState >= topState) {
- int32_t curPriority = source_priority(client->source());
- if (curPriority > topPriority) {
- source = client->source();
- topPriority = curPriority;
- }
- topState = curState;
- }
- }
- if (source != AUDIO_SOURCE_DEFAULT) {
- break;
- }
- }
- return source;
+ return getHighestPrioritySource(activeOnly);
}
void AudioInputDescriptor::toAudioPortConfig(struct audio_port_config *dstConfig,
@@ -99,7 +76,7 @@
dstConfig->type = AUDIO_PORT_TYPE_MIX;
dstConfig->ext.mix.hw_module = getModuleHandle();
dstConfig->ext.mix.handle = mIoHandle;
- dstConfig->ext.mix.usecase.source = source();
+ dstConfig->ext.mix.usecase.source = inputSource();
}
void AudioInputDescriptor::toAudioPort(struct audio_port *port) const
@@ -148,6 +125,24 @@
return false;
}
+audio_source_t AudioInputDescriptor::getHighestPrioritySource(bool activeOnly) const
+{
+ audio_source_t source = AUDIO_SOURCE_DEFAULT;
+ int32_t priority = -1;
+
+ for (const auto &client : getClientIterable()) {
+ if (activeOnly && !client->active() ) {
+ continue;
+ }
+ int32_t curPriority = source_priority(client->source());
+ if (curPriority > priority) {
+ priority = curPriority;
+ source = client->source();
+ }
+ }
+ return source;
+}
+
bool AudioInputDescriptor::isSoundTrigger() const {
// sound trigger and non sound trigger clients are not mixed on a given input
// so check only first client
@@ -229,7 +224,7 @@
status_t AudioInputDescriptor::start()
{
- if (!isActive()) {
+ if (mGlobalActiveCount == 1) {
if (!mProfile->canStartNewIo()) {
ALOGI("%s mProfile->curActiveCount %d", __func__, mProfile->curActiveCount);
return INVALID_OPERATION;
@@ -393,13 +388,15 @@
return count;
}
-Vector<sp <AudioInputDescriptor> > AudioInputCollection::getActiveInputs()
+Vector<sp <AudioInputDescriptor> > AudioInputCollection::getActiveInputs(bool ignoreVirtualInputs)
{
Vector<sp <AudioInputDescriptor> > activeInputs;
for (size_t i = 0; i < size(); i++) {
const sp<AudioInputDescriptor> inputDescriptor = valueAt(i);
- if (inputDescriptor->isActive()) {
+ if ((inputDescriptor->isActive())
+ && (!ignoreVirtualInputs ||
+ !is_virtual_input_device(inputDescriptor->mDevice))) {
activeInputs.add(inputDescriptor);
}
}
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 1b088bb..6ec6a76 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1876,38 +1876,7 @@
}
if (!profile->canOpenNewIo()) {
- for (size_t i = 0; i < mInputs.size(); ) {
- sp <AudioInputDescriptor> desc = mInputs.valueAt(i);
- if (desc->mProfile != profile) {
- continue;
- }
- // if sound trigger, reuse input if used by other sound trigger on same session
- // else
- // reuse input if active client app is not in IDLE state
- //
- RecordClientVector clients = desc->clientsList();
- bool doClose = false;
- for (const auto& client : clients) {
- if (isSoundTrigger != client->isSoundTrigger()) {
- continue;
- }
- if (client->isSoundTrigger()) {
- if (session == client->session()) {
- return desc->mIoHandle;
- }
- continue;
- }
- if (client->active() && client->appState() != APP_STATE_IDLE) {
- return desc->mIoHandle;
- }
- doClose = true;
- }
- if (doClose) {
- closeInput(desc->mIoHandle);
- } else {
- i++;
- }
- }
+ return AUDIO_IO_HANDLE_NONE;
}
sp<AudioInputDescriptor> inputDesc = new AudioInputDescriptor(profile, mpClientInterface);
@@ -1948,8 +1917,55 @@
return input;
}
-status_t AudioPolicyManager::startInput(audio_port_handle_t portId)
+//static
+bool AudioPolicyManager::isConcurrentSource(audio_source_t source)
{
+ return (source == AUDIO_SOURCE_HOTWORD) ||
+ (source == AUDIO_SOURCE_VOICE_RECOGNITION) ||
+ (source == AUDIO_SOURCE_FM_TUNER);
+}
+
+// FIXME: remove when concurrent capture is ready. This is a hack to work around bug b/63083537.
+bool AudioPolicyManager::soundTriggerSupportsConcurrentCapture() {
+ if (!mHasComputedSoundTriggerSupportsConcurrentCapture) {
+ bool soundTriggerSupportsConcurrentCapture = false;
+ unsigned int numModules = 0;
+ struct sound_trigger_module_descriptor* nModules = NULL;
+
+ status_t status = SoundTrigger::listModules(nModules, &numModules);
+ if (status == NO_ERROR && numModules != 0) {
+ nModules = (struct sound_trigger_module_descriptor*) calloc(
+ numModules, sizeof(struct sound_trigger_module_descriptor));
+ if (nModules == NULL) {
+ // We failed to malloc the buffer, so just say no for now, and hope that we have more
+ // ram the next time this function is called.
+ ALOGE("Failed to allocate buffer for module descriptors");
+ return false;
+ }
+
+ status = SoundTrigger::listModules(nModules, &numModules);
+ if (status == NO_ERROR) {
+ soundTriggerSupportsConcurrentCapture = true;
+ for (size_t i = 0; i < numModules; ++i) {
+ soundTriggerSupportsConcurrentCapture &=
+ nModules[i].properties.concurrent_capture;
+ }
+ }
+ free(nModules);
+ }
+ mSoundTriggerSupportsConcurrentCapture = soundTriggerSupportsConcurrentCapture;
+ mHasComputedSoundTriggerSupportsConcurrentCapture = true;
+ }
+ return mSoundTriggerSupportsConcurrentCapture;
+}
+
+
+status_t AudioPolicyManager::startInput(audio_port_handle_t portId,
+ bool silenced,
+ concurrency_type__mask_t *concurrency)
+{
+ *concurrency = API_INPUT_CONCURRENCY_NONE;
+
ALOGV("%s portId %d", __FUNCTION__, portId);
sp<AudioInputDescriptor> inputDesc = mInputs.getInputForClient(portId);
@@ -1966,16 +1982,106 @@
audio_session_t session = client->session();
- ALOGV("%s input:%d, session:%d)", __FUNCTION__, input, session);
+ ALOGV("%s input:%d, session:%d, silenced:%d, concurrency:%d)",
+ __FUNCTION__, input, session, silenced, *concurrency);
- Vector<sp<AudioInputDescriptor>> activeInputs = mInputs.getActiveInputs();
+ if (!is_virtual_input_device(inputDesc->mDevice)) {
+ if (mCallTxPatch != 0 &&
+ inputDesc->getModuleHandle() == mCallTxPatch->mPatch.sources[0].ext.device.hw_module) {
+ ALOGW("startInput(%d) failed: call in progress", input);
+ *concurrency |= API_INPUT_CONCURRENCY_CALL;
+ return INVALID_OPERATION;
+ }
- status_t status = inputDesc->start();
- if (status != NO_ERROR) {
- return status;
+ Vector<sp<AudioInputDescriptor>> activeInputs = mInputs.getActiveInputs();
+
+ // If a UID is idle and records silence and another not silenced recording starts
+ // from another UID (idle or active) we stop the current idle UID recording in
+ // favor of the new one - "There can be only one" TM
+ if (!silenced) {
+ for (const auto& activeDesc : activeInputs) {
+ if ((activeDesc->getAudioPort()->getFlags() & AUDIO_INPUT_FLAG_MMAP_NOIRQ) != 0 &&
+ activeDesc->getId() == inputDesc->getId()) {
+ continue;
+ }
+
+ RecordClientVector activeClients = activeDesc->clientsList(true /*activeOnly*/);
+ for (const auto& activeClient : activeClients) {
+ if (activeClient->isSilenced()) {
+ closeClient(activeClient->portId());
+ ALOGV("%s client %d stopping silenced client %d", __FUNCTION__,
+ portId, activeClient->portId());
+ activeInputs = mInputs.getActiveInputs();
+ }
+ }
+ }
+ }
+
+ for (const auto& activeDesc : activeInputs) {
+ if ((client->flags() & AUDIO_INPUT_FLAG_MMAP_NOIRQ) != 0 &&
+ activeDesc->getId() == inputDesc->getId()) {
+ continue;
+ }
+
+ audio_source_t activeSource = activeDesc->inputSource(true);
+ if (client->source() == AUDIO_SOURCE_HOTWORD) {
+ if (activeSource == AUDIO_SOURCE_HOTWORD) {
+ if (activeDesc->hasPreemptedSession(session)) {
+ ALOGW("%s input %d failed for HOTWORD: "
+ "other input %d already started for HOTWORD", __FUNCTION__,
+ input, activeDesc->mIoHandle);
+ *concurrency |= API_INPUT_CONCURRENCY_HOTWORD;
+ return INVALID_OPERATION;
+ }
+ } else {
+ ALOGV("%s input %d failed for HOTWORD: other input %d already started",
+ __FUNCTION__, input, activeDesc->mIoHandle);
+ *concurrency |= API_INPUT_CONCURRENCY_CAPTURE;
+ return INVALID_OPERATION;
+ }
+ } else {
+ if (activeSource != AUDIO_SOURCE_HOTWORD) {
+ ALOGW("%s input %d failed: other input %d already started", __FUNCTION__,
+ input, activeDesc->mIoHandle);
+ *concurrency |= API_INPUT_CONCURRENCY_CAPTURE;
+ return INVALID_OPERATION;
+ }
+ }
+ }
+
+ // We only need to check if the sound trigger session supports concurrent capture if the
+ // input is also a sound trigger input. Otherwise, we should preempt any hotword stream
+ // that's running.
+ const bool allowConcurrentWithSoundTrigger =
+ inputDesc->isSoundTrigger() ? soundTriggerSupportsConcurrentCapture() : false;
+
+ // if capture is allowed, preempt currently active HOTWORD captures
+ for (const auto& activeDesc : activeInputs) {
+ if (allowConcurrentWithSoundTrigger && activeDesc->isSoundTrigger()) {
+ continue;
+ }
+ RecordClientVector activeHotwordClients =
+ activeDesc->clientsList(true, AUDIO_SOURCE_HOTWORD);
+ if (activeHotwordClients.size() > 0) {
+ SortedVector<audio_session_t> sessions = activeDesc->getPreemptedSessions();
+
+ for (const auto& activeClient : activeHotwordClients) {
+ *concurrency |= API_INPUT_CONCURRENCY_PREEMPT;
+ sessions.add(activeClient->session());
+ closeClient(activeClient->portId());
+ ALOGV("%s input %d for HOTWORD preempting HOTWORD input %d", __FUNCTION__,
+ input, activeDesc->mIoHandle);
+ }
+
+ inputDesc->setPreemptedSessions(sessions);
+ }
+ }
}
- // increment activity count before calling getNewInputDevice() below as only active sessions
+ // Make sure we start with the correct silence state
+ client->setSilenced(silenced);
+
+ // increment activity count before calling getNewInputDevice() below as only active sessions
// are considered for device selection
inputDesc->setClientActive(client, true);
@@ -1984,6 +2090,12 @@
audio_devices_t device = getNewInputDevice(inputDesc);
setInputDevice(input, device, true /* force */);
+ status_t status = inputDesc->start();
+ if (status != NO_ERROR) {
+ inputDesc->setClientActive(client, false);
+ return status;
+ }
+
if (inputDesc->activeCount() == 1) {
// if input maps to a dynamic policy with an activity listener, notify of state change
if ((inputDesc->mPolicyMix != NULL)
@@ -3232,7 +3344,7 @@
SortedVector<audio_io_handle_t> inputsToClose;
for (size_t i = 0; i < mInputs.size(); i++) {
sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(i);
- if (affectedSources.indexOf(inputDesc->source()) >= 0) {
+ if (affectedSources.indexOf(inputDesc->inputSource()) >= 0) {
inputsToClose.add(inputDesc->mIoHandle);
}
}
@@ -3609,15 +3721,16 @@
void AudioPolicyManager::setAppState(uid_t uid, app_state_t state)
{
Vector<sp<AudioInputDescriptor> > activeInputs = mInputs.getActiveInputs();
+ bool silenced = state == APP_STATE_IDLE;
- ALOGV("%s(uid:%d, state:%d)", __func__, uid, state);
+ ALOGV("AudioPolicyManager:setRecordSilenced(uid:%d, silenced:%d)", uid, silenced);
for (size_t i = 0; i < activeInputs.size(); i++) {
sp<AudioInputDescriptor> activeDesc = activeInputs[i];
RecordClientVector clients = activeDesc->clientsList(true /*activeOnly*/);
for (const auto& client : clients) {
if (uid == client->uid()) {
- client->setAppState(state);
+ client->setSilenced(silenced);
}
}
}
@@ -3727,7 +3840,8 @@
mBeaconMuted(false),
mTtsOutputAvailable(false),
mMasterMono(false),
- mMusicEffectOutput(AUDIO_IO_HANDLE_NONE)
+ mMusicEffectOutput(AUDIO_IO_HANDLE_NONE),
+ mHasComputedSoundTriggerSupportsConcurrentCapture(false)
{
}
@@ -4780,7 +4894,7 @@
// 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->source();
+ audio_source_t source = inputDesc->getHighestPrioritySource(true /*activeOnly*/);
if (source == AUDIO_SOURCE_DEFAULT && isInCall()) {
source = AUDIO_SOURCE_VOICE_COMMUNICATION;
}
@@ -5119,6 +5233,20 @@
}
installPatch(__func__, patchHandle, outputDesc.get(), patchBuilder.patch(), delayMs);
}
+
+ // inform all input as well
+ for (size_t i = 0; i < mInputs.size(); i++) {
+ const sp<AudioInputDescriptor> inputDescriptor = mInputs.valueAt(i);
+ if (!is_virtual_input_device(inputDescriptor->mDevice)) {
+ AudioParameter inputCmd = AudioParameter();
+ ALOGV("%s: inform input %d of device:%d", __func__,
+ inputDescriptor->mIoHandle, device);
+ inputCmd.addInt(String8(AudioParameter::keyRouting),device);
+ mpClientInterface->setParameters(inputDescriptor->mIoHandle,
+ inputCmd.toString(),
+ delayMs);
+ }
+ }
}
// update stream volumes according to new device
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 22bfab0..0436b1d 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -134,7 +134,9 @@
audio_port_handle_t *portId);
// indicates to the audio policy manager that the input starts being used.
- virtual status_t startInput(audio_port_handle_t portId);
+ virtual status_t startInput(audio_port_handle_t portId,
+ bool silenced,
+ concurrency_type__mask_t *concurrency);
// indicates to the audio policy manager that the input stops being used.
virtual status_t stopInput(audio_port_handle_t portId);
@@ -537,6 +539,8 @@
void clearAudioSources(uid_t uid);
+ static bool isConcurrentSource(audio_source_t source);
+
static bool streamsMatchForvolume(audio_stream_type_t stream1,
audio_stream_type_t stream2);
@@ -700,6 +704,10 @@
int delayMs,
uid_t uid,
sp<AudioPatch> *patchDescPtr);
+
+ bool soundTriggerSupportsConcurrentCapture();
+ bool mSoundTriggerSupportsConcurrentCapture;
+ bool mHasComputedSoundTriggerSupportsConcurrentCapture;
};
};
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index c2ce754..59c8f10 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -454,6 +454,23 @@
return rawbuffer;
}
+static std::string audioConcurrencyString(
+ AudioPolicyInterface::concurrency_type__mask_t concurrency)
+{
+ char buffer[64]; // oversized
+ if (concurrency & AudioPolicyInterface::API_INPUT_CONCURRENCY_ALL) {
+ snprintf(buffer, sizeof(buffer), "%s%s%s%s",
+ (concurrency & AudioPolicyInterface::API_INPUT_CONCURRENCY_CALL)? ",call":"",
+ (concurrency & AudioPolicyInterface::API_INPUT_CONCURRENCY_CAPTURE)? ",capture":"",
+ (concurrency & AudioPolicyInterface::API_INPUT_CONCURRENCY_HOTWORD)? ",hotword":"",
+ (concurrency & AudioPolicyInterface::API_INPUT_CONCURRENCY_PREEMPT)? ",preempt":"");
+ } else {
+ snprintf(buffer, sizeof(buffer), ",none");
+ }
+
+ return &buffer[1];
+}
+
std::string AudioPolicyService::getDeviceTypeStrForPortId(audio_port_handle_t portId) {
std::string typeStr;
struct audio_port port = {};
@@ -465,7 +482,7 @@
return typeStr;
}
-status_t AudioPolicyService::startInput(audio_port_handle_t portId)
+status_t AudioPolicyService::startInput(audio_port_handle_t portId, bool *silenced)
{
if (mAudioPolicyManager == NULL) {
return NO_INIT;
@@ -488,16 +505,17 @@
return PERMISSION_DENIED;
}
- Mutex::Autolock _l(mLock);
+ // If UID inactive it records silence until becoming active
+ *silenced = !mUidPolicy->isUidActive(client->uid) && !client->isVirtualDevice;
- client->active = true;
- client->startTimeNs = systemTime();
- updateUidStates_l();
+ Mutex::Autolock _l(mLock);
+ AudioPolicyInterface::concurrency_type__mask_t concurrency =
+ AudioPolicyInterface::API_INPUT_CONCURRENCY_NONE;
status_t status;
{
AutoCallerClear acc;
- status = mAudioPolicyManager->startInput(portId);
+ status = mAudioPolicyManager->startInput(portId, *silenced, &concurrency);
}
@@ -506,6 +524,7 @@
static constexpr char kAudioPolicy[] = "audiopolicy";
+ static constexpr char kAudioPolicyReason[] = "android.media.audiopolicy.reason";
static constexpr char kAudioPolicyStatus[] = "android.media.audiopolicy.status";
static constexpr char kAudioPolicyRqstSrc[] = "android.media.audiopolicy.rqst.src";
static constexpr char kAudioPolicyRqstPkg[] = "android.media.audiopolicy.rqst.pkg";
@@ -522,6 +541,7 @@
MediaAnalyticsItem *item = new MediaAnalyticsItem(kAudioPolicy);
if (item != NULL) {
+ item->setCString(kAudioPolicyReason, audioConcurrencyString(concurrency).c_str());
item->setInt32(kAudioPolicyStatus, status);
item->setCString(kAudioPolicyRqstSrc,
@@ -536,35 +556,54 @@
item->setCString(
kAudioPolicyRqstDevice, getDeviceTypeStrForPortId(client->deviceId).c_str());
- int count = mAudioRecordClients.size();
- for (int i = 0; i < count ; i++) {
- if (portId == mAudioRecordClients.keyAt(i)) {
- continue;
- }
- sp<AudioRecordClient> other = mAudioRecordClients.valueAt(i);
- if (other->active) {
- // keeps the last of the clients marked active
- item->setCString(kAudioPolicyActiveSrc,
- audioSourceString(other->attributes.source).c_str());
- item->setInt32(kAudioPolicyActiveSession, other->session);
- if (other->opPackageName.size() != 0) {
- item->setCString(kAudioPolicyActivePkg,
- std::string(String8(other->opPackageName).string()).c_str());
- } else {
- item->setCString(kAudioPolicyRqstPkg,
- std::to_string(other->uid).c_str());
+ // figure out who is active
+ // NB: might the other party have given up the microphone since then? how sure.
+ // perhaps could have given up on it.
+ // we hold mLock, so perhaps we're safe for this looping
+ if (concurrency != AudioPolicyInterface::API_INPUT_CONCURRENCY_NONE) {
+ int count = mAudioRecordClients.size();
+ for (int i = 0; i<count ; i++) {
+ if (portId == mAudioRecordClients.keyAt(i)) {
+ continue;
}
- item->setCString(kAudioPolicyActiveDevice,
- getDeviceTypeStrForPortId(other->deviceId).c_str());
+ sp<AudioRecordClient> other = mAudioRecordClients.valueAt(i);
+ if (other->active) {
+ // keeps the last of the clients marked active
+ item->setCString(kAudioPolicyActiveSrc,
+ audioSourceString(other->attributes.source).c_str());
+ item->setInt32(kAudioPolicyActiveSession, other->session);
+ if (other->opPackageName.size() != 0) {
+ item->setCString(kAudioPolicyActivePkg,
+ std::string(String8(other->opPackageName).string()).c_str());
+ } else {
+ item->setCString(kAudioPolicyRqstPkg,
+ std::to_string(other->uid).c_str());
+ }
+ item->setCString(kAudioPolicyActiveDevice,
+ getDeviceTypeStrForPortId(other->deviceId).c_str());
+ }
}
}
item->selfrecord();
delete item;
item = NULL;
}
- client->active = false;
- client->startTimeNs = 0;
- updateUidStates_l();
+ }
+
+ if (status == NO_ERROR) {
+ LOG_ALWAYS_FATAL_IF(concurrency & ~AudioPolicyInterface::API_INPUT_CONCURRENCY_ALL,
+ "startInput(): invalid concurrency type %d", (int)concurrency);
+
+ // enforce permission (if any) required for each type of concurrency
+ if (concurrency & AudioPolicyInterface::API_INPUT_CONCURRENCY_CALL) {
+ //TODO: check incall capture permission
+ }
+ if (concurrency & AudioPolicyInterface::API_INPUT_CONCURRENCY_CAPTURE) {
+ //TODO: check concurrent capture permission
+ }
+
+ client->active = true;
+ } else {
finishRecording(client->opPackageName, client->uid);
}
@@ -576,7 +615,6 @@
if (mAudioPolicyManager == NULL) {
return NO_INIT;
}
-
Mutex::Autolock _l(mLock);
ssize_t index = mAudioRecordClients.indexOfKey(portId);
@@ -586,9 +624,6 @@
sp<AudioRecordClient> client = mAudioRecordClients.valueAt(index);
client->active = false;
- client->startTimeNs = 0;
-
- updateUidStates_l();
// finish the recording app op
finishRecording(client->opPackageName, client->uid);
@@ -611,14 +646,6 @@
return;
}
client = mAudioRecordClients.valueAt(index);
-
- if (client->active) {
- ALOGW("%s releasing active client portId %d", __FUNCTION__, portId);
- client->active = false;
- client->startTimeNs = 0;
- updateUidStates_l();
- }
-
mAudioRecordClients.removeItem(portId);
}
if (client == 0) {
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index 2893872..78dbf5f 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -348,91 +348,11 @@
void AudioPolicyService::updateUidStates_l()
{
-// Go over all active clients and allow capture (does not force silence) in the
-// following cases:
-// - The client is the assistant AND
-// an accessibility service is on TOP AND the source is VOICE_RECOGNITION or HOTWORD
-// OR
-// is on TOP AND uses VOICE_RECOGNITION
-// OR uses HOTWORD AND there is no privacy sensitive active capture
-// - The client is an accessibility service AND
-// is on TOP AND the source is VOICE_RECOGNITION or HOTWORD
-// - Any other client AND
-// The assistant is not on TOP AND
-// is on TOP OR latest started AND
-// there is no privacy sensitive active capture
-//TODO: mamanage pre processing effects according to use case priority
-
- sp<AudioRecordClient> topActive;
- sp<AudioRecordClient> latestActive;
- nsecs_t latestStartNs = 0;
- sp<AudioRecordClient> latestSensitiveActive;
- nsecs_t latestSensitiveStartNs = 0;
- bool isA11yOnTop = mUidPolicy->isA11yOnTop();
- bool isAssistantOnTop = false;
- bool isSensitiveActive = false;
-
+ //TODO: implement real concurrent capture policy: for now just apply each app state directly
for (size_t i =0; i < mAudioRecordClients.size(); i++) {
sp<AudioRecordClient> current = mAudioRecordClients[i];
if (!current->active) continue;
- if (isPrivacySensitive(current->attributes.source)) {
- if (current->startTimeNs > latestSensitiveStartNs) {
- latestSensitiveActive = current;
- latestSensitiveStartNs = current->startTimeNs;
- }
- isSensitiveActive = true;
- }
- if (mUidPolicy->getUidState(current->uid) == ActivityManager::PROCESS_STATE_TOP) {
- topActive = current;
- latestActive = nullptr;
- if (mUidPolicy->isAssistantUid(current->uid)) {
- isAssistantOnTop = true;
- }
- }
- if (current->startTimeNs > latestStartNs) {
- latestActive = current;
- latestStartNs = current->startTimeNs;
- }
- }
-
- if (topActive == nullptr && latestActive == nullptr) {
- return;
- }
-
- for (size_t i =0; i < mAudioRecordClients.size(); i++) {
- sp<AudioRecordClient> current = mAudioRecordClients[i];
- if (!current->active) continue;
-
- audio_source_t source = current->attributes.source;
- bool isOnTop = mUidPolicy->getUidState(current->uid) == ActivityManager::PROCESS_STATE_TOP;
- bool isLatest = current == latestActive;
- bool isLatestSensitive = current == latestSensitiveActive;
- bool forceIdle = true;
- if (mUidPolicy->isAssistantUid(current->uid)) {
- if (isA11yOnTop) {
- if (source == AUDIO_SOURCE_HOTWORD || source == AUDIO_SOURCE_VOICE_RECOGNITION) {
- forceIdle = false;
- }
- } else {
- if (((isOnTop && source == AUDIO_SOURCE_VOICE_RECOGNITION) ||
- source == AUDIO_SOURCE_HOTWORD) && !isSensitiveActive) {
- forceIdle = false;
- }
- }
- } else if (mUidPolicy->isA11yUid(current->uid)) {
- if (isOnTop &&
- (source == AUDIO_SOURCE_VOICE_RECOGNITION || source == AUDIO_SOURCE_HOTWORD)) {
- forceIdle = false;
- }
- } else {
- if (!isAssistantOnTop && (isOnTop || (topActive == nullptr && isLatest)) &&
- (!isSensitiveActive || isLatestSensitive)) {
- forceIdle = false;
- }
- }
- setAppState_l(current->uid,
- forceIdle ? APP_STATE_IDLE :
- apmStatFromAmState(mUidPolicy->getUidState(current->uid)));
+ setAppState_l(current->uid, apmStatFromAmState(mUidPolicy->getUidState(current->uid)));
}
}
@@ -449,22 +369,6 @@
return APP_STATE_FOREGROUND;
}
-/* static */
-bool AudioPolicyService::isPrivacySensitive(audio_source_t source)
-{
- switch (source) {
- case AUDIO_SOURCE_VOICE_UPLINK:
- case AUDIO_SOURCE_VOICE_DOWNLINK:
- case AUDIO_SOURCE_VOICE_CALL:
- case AUDIO_SOURCE_CAMCORDER:
- case AUDIO_SOURCE_VOICE_COMMUNICATION:
- return true;
- default:
- break;
- }
- return false;
-}
-
void AudioPolicyService::setAppState_l(uid_t uid, app_state_t state)
{
AutoCallerClear acc;
@@ -644,7 +548,6 @@
mObserverRegistered = true;
} else {
ALOGE("UidPolicy::registerSelf linkToDeath failed: %d", res);
-
am.unregisterUidObserver(this);
}
}
@@ -747,7 +650,6 @@
mCachedUids.insert(std::pair<uid_t,
std::pair<bool, int>>(uid, std::pair<bool, int>(active, state)));
}
-
return state;
}
@@ -828,21 +730,6 @@
}
}
-bool AudioPolicyService::UidPolicy::isA11yOnTop() {
- for (const auto &uid : mCachedUids) {
- std::vector<uid_t>::iterator it = find(mA11yUids.begin(), mA11yUids.end(), uid.first);
- if (it == mA11yUids.end()) {
- continue;
- }
- if (uid.second.second == ActivityManager::PROCESS_STATE_TOP ||
- uid.second.second == ActivityManager::PROCESS_STATE_FOREGROUND_SERVICE ||
- uid.second.second == ActivityManager::PROCESS_STATE_BOUND_FOREGROUND_SERVICE) {
- return true;
- }
- }
- return false;
-}
-
bool AudioPolicyService::UidPolicy::isA11yUid(uid_t uid)
{
std::vector<uid_t>::iterator it = find(mA11yUids.begin(), mA11yUids.end(), uid);
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index dc5a36d..4d7235f 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -94,7 +94,8 @@
audio_input_flags_t flags,
audio_port_handle_t *selectedDeviceId = NULL,
audio_port_handle_t *portId = NULL);
- virtual status_t startInput(audio_port_handle_t portId);
+ virtual status_t startInput(audio_port_handle_t portId,
+ bool *silenced);
virtual status_t stopInput(audio_port_handle_t portId);
virtual void releaseInput(audio_port_handle_t portId);
virtual status_t initStreamVolume(audio_stream_type_t stream,
@@ -275,8 +276,6 @@
void updateUidStates();
void updateUidStates_l();
- static bool isPrivacySensitive(audio_source_t source);
-
// If recording we need to make sure the UID is allowed to do that. If the UID is idle
// then it cannot record and gets buffers with zeros - silence. As soon as the UID
// transitions to an active state we will start reporting buffers with data. This approach
@@ -300,7 +299,6 @@
bool isAssistantUid(uid_t uid) { return uid == mAssistantUid; }
void setA11yUids(const std::vector<uid_t>& uids) { mA11yUids.clear(); mA11yUids = uids; }
bool isA11yUid(uid_t uid);
- bool isA11yOnTop();
// BnUidObserver implementation
void onUidActive(uid_t uid) override;
@@ -652,11 +650,12 @@
const audio_session_t session, const audio_port_handle_t deviceId,
const String16& opPackageName) :
AudioClient(attributes, io, uid, pid, session, deviceId),
- opPackageName(opPackageName), startTimeNs(0) {}
+ opPackageName(opPackageName), isConcurrent(false), isVirtualDevice(false) {}
~AudioRecordClient() override = default;
const String16 opPackageName; // client package name
- nsecs_t startTimeNs;
+ bool isConcurrent; // is allowed to concurrent capture
+ bool isVirtualDevice; // uses virtual device: updated by APM::getInputForAttr()
};
// --- AudioPlaybackClient ---