Merge "Move to android_mallopt for malloc debug calls."
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index ef5f26c..4563b41 100644
--- a/camera/ndk/include/camera/NdkCameraMetadataTags.h
+++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -7670,6 +7670,24 @@
* <li>ACAMERA_LENS_POSE_REFERENCE</li>
* <li>ACAMERA_LENS_DISTORTION</li>
* </ul>
+ * <p>The field of view of all non-RAW physical streams must be the same or as close as
+ * possible to that of non-RAW logical streams. If the requested FOV is outside of the
+ * range supported by the physical camera, the physical stream for that physical camera
+ * will use either the maximum or minimum scaler crop region, depending on which one is
+ * closer to the requested FOV. For example, for a logical camera with wide-tele lens
+ * configuration where the wide lens is the default, if the logical camera's crop region
+ * is set to maximum, the physical stream for the tele lens will be configured to its
+ * maximum crop region. On the other hand, if the logical camera has a normal-wide lens
+ * configuration where the normal lens is the default, when the logical camera's crop
+ * region is set to maximum, the FOV of the logical streams will be that of the normal
+ * lens. The FOV of the physical streams for the wide lens will be the same as the
+ * logical stream, by making the crop region smaller than its active array size to
+ * compensate for the smaller focal length.</p>
+ * <p>Even if the underlying physical cameras have different RAW characteristics (such as
+ * size or CFA pattern), a logical camera can still advertise RAW capability. In this
+ * case, when the application configures a RAW stream, the camera device will make sure
+ * the active physical camera will remain active to ensure consistent RAW output
+ * behavior, and not switch to other physical cameras.</p>
* <p>To maintain backward compatibility, the capture request and result metadata tags
* required for basic camera functionalities will be solely based on the
* logical camera capabiltity. Other request and result metadata tags, on the other
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index f324669..de82d2b 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -1067,6 +1067,13 @@
return aps->setEffectEnabled(id, enabled);
}
+status_t AudioSystem::moveEffectsToIo(const std::vector<int>& ids, audio_io_handle_t io)
+{
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) return PERMISSION_DENIED;
+ return aps->moveEffectsToIo(ids, io);
+}
+
status_t AudioSystem::isStreamActive(audio_stream_type_t stream, bool* state, uint32_t inPastMs)
{
const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
diff --git a/media/libaudioclient/IAudioFlinger.cpp b/media/libaudioclient/IAudioFlinger.cpp
index 825cd4e..dd95e34 100644
--- a/media/libaudioclient/IAudioFlinger.cpp
+++ b/media/libaudioclient/IAudioFlinger.cpp
@@ -89,6 +89,7 @@
GET_MICROPHONES,
SET_MASTER_BALANCE,
GET_MASTER_BALANCE,
+ SET_EFFECT_SUSPENDED,
};
#define MAX_ITEMS_PER_LIST 1024
@@ -718,6 +719,18 @@
return reply.readInt32();
}
+ virtual void setEffectSuspended(int effectId,
+ audio_session_t sessionId,
+ bool suspended)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ data.writeInt32(effectId);
+ data.writeInt32(sessionId);
+ data.writeInt32(suspended ? 1 : 0);
+ remote()->transact(SET_EFFECT_SUSPENDED, data, &reply);
+ }
+
virtual audio_module_handle_t loadHwModule(const char *name)
{
Parcel data, reply;
@@ -913,6 +926,7 @@
case INVALIDATE_STREAM:
case SET_VOICE_VOLUME:
case MOVE_EFFECTS:
+ case SET_EFFECT_SUSPENDED:
case LOAD_HW_MODULE:
case LIST_AUDIO_PORTS:
case GET_AUDIO_PORT:
@@ -926,6 +940,7 @@
// return status only for non void methods
switch (code) {
case SET_RECORD_SILENCED:
+ case SET_EFFECT_SUSPENDED:
break;
default:
reply->writeInt32(static_cast<int32_t> (INVALID_OPERATION));
@@ -1371,6 +1386,14 @@
reply->writeInt32(moveEffects(session, srcOutput, dstOutput));
return NO_ERROR;
} break;
+ case SET_EFFECT_SUSPENDED: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ int effectId = data.readInt32();
+ audio_session_t sessionId = (audio_session_t) data.readInt32();
+ bool suspended = data.readInt32() == 1;
+ setEffectSuspended(effectId, sessionId, suspended);
+ return NO_ERROR;
+ } break;
case LOAD_HW_MODULE: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
reply->writeInt32(loadHwModule(data.readCString()));
diff --git a/media/libaudioclient/IAudioPolicyService.cpp b/media/libaudioclient/IAudioPolicyService.cpp
index bf98c60..4a8bb52 100644
--- a/media/libaudioclient/IAudioPolicyService.cpp
+++ b/media/libaudioclient/IAudioPolicyService.cpp
@@ -103,6 +103,7 @@
LIST_AUDIO_VOLUME_GROUPS,
GET_VOLUME_GROUP_FOR_ATTRIBUTES,
SET_ALLOWED_CAPTURE_POLICY,
+ MOVE_EFFECTS_TO_IO,
};
#define MAX_ITEMS_PER_LIST 1024
@@ -550,6 +551,22 @@
return static_cast <status_t> (reply.readInt32());
}
+ status_t moveEffectsToIo(const std::vector<int>& ids, audio_io_handle_t io) override
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+ data.writeInt32(ids.size());
+ for (auto id : ids) {
+ data.writeInt32(id);
+ }
+ data.writeInt32(io);
+ status_t status = remote()->transact(MOVE_EFFECTS_TO_IO, data, &reply);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ return static_cast <status_t> (reply.readInt32());
+ }
+
virtual bool isStreamActive(audio_stream_type_t stream, uint32_t inPastMs) const
{
Parcel data, reply;
@@ -1284,6 +1301,7 @@
case GET_OUTPUT_FOR_ATTR:
case ACQUIRE_SOUNDTRIGGER_SESSION:
case RELEASE_SOUNDTRIGGER_SESSION:
+ case MOVE_EFFECTS_TO_IO:
ALOGW("%s: transaction %d received from PID %d",
__func__, code, IPCThreadState::self()->getCallingPid());
// return status only for non void methods
@@ -1700,6 +1718,31 @@
return NO_ERROR;
} break;
+ case MOVE_EFFECTS_TO_IO: {
+ CHECK_INTERFACE(IAudioPolicyService, data, reply);
+ std::vector<int> ids;
+ int32_t size;
+ status_t status = data.readInt32(&size);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ if (size > MAX_ITEMS_PER_LIST) {
+ return BAD_VALUE;
+ }
+ for (int32_t i = 0; i < size; i++) {
+ int id;
+ status = data.readInt32(&id);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ ids.push_back(id);
+ }
+
+ audio_io_handle_t io = data.readInt32();
+ reply->writeInt32(static_cast <int32_t>(moveEffectsToIo(ids, io)));
+ return NO_ERROR;
+ } break;
+
case IS_STREAM_ACTIVE: {
CHECK_INTERFACE(IAudioPolicyService, data, reply);
audio_stream_type_t stream = (audio_stream_type_t) data.readInt32();
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index 05a1d56..d180bbc 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -286,6 +286,7 @@
int id);
static status_t unregisterEffect(int id);
static status_t setEffectEnabled(int id, bool enabled);
+ static status_t moveEffectsToIo(const std::vector<int>& ids, audio_io_handle_t io);
// clear stream to output mapping cache (gStreamOutputMap)
// and output configuration cache (gOutputs)
diff --git a/media/libaudioclient/include/media/IAudioFlinger.h b/media/libaudioclient/include/media/IAudioFlinger.h
index ef0ed0c..dcc18b6 100644
--- a/media/libaudioclient/include/media/IAudioFlinger.h
+++ b/media/libaudioclient/include/media/IAudioFlinger.h
@@ -457,6 +457,10 @@
virtual status_t moveEffects(audio_session_t session, audio_io_handle_t srcOutput,
audio_io_handle_t dstOutput) = 0;
+ virtual void setEffectSuspended(int effectId,
+ audio_session_t sessionId,
+ bool suspended) = 0;
+
virtual audio_module_handle_t loadHwModule(const char *name) = 0;
// helpers for android.media.AudioManager.getProperty(), see description there for meaning
diff --git a/media/libaudioclient/include/media/IAudioPolicyService.h b/media/libaudioclient/include/media/IAudioPolicyService.h
index 95530ac..11983d5 100644
--- a/media/libaudioclient/include/media/IAudioPolicyService.h
+++ b/media/libaudioclient/include/media/IAudioPolicyService.h
@@ -114,6 +114,7 @@
int id) = 0;
virtual status_t unregisterEffect(int id) = 0;
virtual status_t setEffectEnabled(int id, bool enabled) = 0;
+ virtual status_t moveEffectsToIo(const std::vector<int>& ids, audio_io_handle_t io) = 0;
virtual bool isStreamActive(audio_stream_type_t stream, uint32_t inPastMs = 0) const = 0;
virtual bool isStreamActiveRemotely(audio_stream_type_t stream, uint32_t inPastMs = 0)
const = 0;
diff --git a/media/libaudioprocessing/RecordBufferConverter.cpp b/media/libaudioprocessing/RecordBufferConverter.cpp
index 54151f5..7d6fe72 100644
--- a/media/libaudioprocessing/RecordBufferConverter.cpp
+++ b/media/libaudioprocessing/RecordBufferConverter.cpp
@@ -117,6 +117,11 @@
// format convert to destination buffer
convertResampler(dst, mBuf, frames);
}
+ // Release unused frames in the InputConverterProvider buffer so that
+ // the RecordThread is able to properly account for consumed frames.
+ if (mInputConverterProvider != nullptr) {
+ mInputConverterProvider->reset();
+ }
return frames;
}
diff --git a/media/libeffects/preprocessing/PreProcessing.cpp b/media/libeffects/preprocessing/PreProcessing.cpp
index 50c33c6..5fab5be 100644
--- a/media/libeffects/preprocessing/PreProcessing.cpp
+++ b/media/libeffects/preprocessing/PreProcessing.cpp
@@ -926,7 +926,7 @@
delete session->revBuf;
session->revBuf = NULL;
- session->io = 0;
+ session->id = 0;
}
return 0;
@@ -1155,7 +1155,7 @@
{
size_t i;
for (i = 0; i < PREPROC_NUM_SESSIONS; i++) {
- if (sSessions[i].io == ioId) {
+ if (sSessions[i].id == sessionId) {
if (sSessions[i].createdMsk & (1 << procId)) {
return NULL;
}
@@ -1163,7 +1163,7 @@
}
}
for (i = 0; i < PREPROC_NUM_SESSIONS; i++) {
- if (sSessions[i].io == 0) {
+ if (sSessions[i].id == 0) {
sSessions[i].id = sessionId;
sSessions[i].io = ioId;
return &sSessions[i];
@@ -1915,7 +1915,7 @@
status = Session_CreateEffect(session, procId, pInterface);
if (status < 0 && session->createdMsk == 0) {
- session->io = 0;
+ session->id = 0;
}
return status;
}
@@ -1929,7 +1929,7 @@
preproc_effect_t *fx = (preproc_effect_t *)interface;
- if (fx->session->io == 0) {
+ if (fx->session->id == 0) {
return -EINVAL;
}
return Session_ReleaseEffect(fx->session, fx);
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index b1fdb2c..2ca5eee 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -1659,10 +1659,12 @@
return;
}
int32_t colorFormat;
- if (mSoftRenderer != NULL
- && mOutputFormat->contains("hdr-static-info")
+ if (mOutputFormat->contains("hdr-static-info")
&& mOutputFormat->findInt32("color-format", &colorFormat)
- && (colorFormat == OMX_COLOR_FormatYUV420Planar16)) {
+ // check format for OMX only, for C2 the format is always opaque since the
+ // software rendering doesn't go through client
+ && ((mSoftRenderer != NULL && colorFormat == OMX_COLOR_FormatYUV420Planar16)
+ || mOwnerName.equalsIgnoreCase("codec2::software"))) {
int32_t left, top, right, bottom, width, height;
int64_t totalPixel = 0;
if (mOutputFormat->findRect("crop", &left, &top, &right, &bottom)) {
@@ -1958,6 +1960,7 @@
} else {
mFlags &= ~kFlagUsesSoftwareRenderer;
}
+ mOwnerName = owner;
MediaResource::Type resourceType;
if (mComponentName.endsWith(".secure")) {
diff --git a/media/libstagefright/include/media/stagefright/MediaCodec.h b/media/libstagefright/include/media/stagefright/MediaCodec.h
index 7f6aae6..6cd4265 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodec.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodec.h
@@ -313,6 +313,7 @@
sp<ALooper> mCodecLooper;
sp<CodecBase> mCodec;
AString mComponentName;
+ AString mOwnerName;
sp<MediaCodecInfo> mCodecInfo;
sp<AReplyToken> mReplyID;
uint32_t mFlags;
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 0825cb4..55db699 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -687,6 +687,10 @@
bool updatePid = (input.clientInfo.clientPid == -1);
const uid_t callingUid = IPCThreadState::self()->getCallingUid();
uid_t clientUid = input.clientInfo.clientUid;
+ audio_io_handle_t effectThreadId = AUDIO_IO_HANDLE_NONE;
+ std::vector<int> effectIds;
+
+
if (!isAudioServerOrMediaServerUid(callingUid)) {
ALOGW_IF(clientUid != callingUid,
"%s uid %d tried to pass itself off as %d",
@@ -851,7 +855,10 @@
// no risk of deadlock because AudioFlinger::mLock is held
Mutex::Autolock _dl(thread->mLock);
Mutex::Autolock _sl(effectThread->mLock);
- moveEffectChain_l(sessionId, effectThread, thread, true);
+ if (moveEffectChain_l(sessionId, effectThread, thread) == NO_ERROR) {
+ effectThreadId = thread->id();
+ effectIds = thread->getEffectIds_l(sessionId);
+ }
}
// Look for sync events awaiting for a session to be used.
@@ -885,6 +892,12 @@
goto Exit;
}
+ // effectThreadId is not NONE if an effect chain corresponding to the track session
+ // was found on another thread and must be moved on this thread
+ if (effectThreadId != AUDIO_IO_HANDLE_NONE) {
+ AudioSystem::moveEffectsToIo(effectIds, effectThreadId);
+ }
+
// return handle to client
trackHandle = new TrackHandle(track);
@@ -1225,7 +1238,8 @@
if (output == AUDIO_IO_HANDLE_NONE) {
return BAD_VALUE;
}
- ALOG_ASSERT(stream != AUDIO_STREAM_PATCH, "attempt to change AUDIO_STREAM_PATCH volume");
+ LOG_ALWAYS_FATAL_IF(stream == AUDIO_STREAM_PATCH && value != 1.0f,
+ "AUDIO_STREAM_PATCH must have full scale volume");
AutoMutex lock(mLock);
VolumeInterface *volumeInterface = getVolumeInterface_l(output);
@@ -1630,30 +1644,36 @@
void AudioFlinger::removeNotificationClient(pid_t pid)
{
- Mutex::Autolock _l(mLock);
+ std::vector< sp<AudioFlinger::EffectModule> > removedEffects;
{
- Mutex::Autolock _cl(mClientLock);
- mNotificationClients.removeItem(pid);
- }
+ Mutex::Autolock _l(mLock);
+ {
+ Mutex::Autolock _cl(mClientLock);
+ mNotificationClients.removeItem(pid);
+ }
- ALOGV("%d died, releasing its sessions", pid);
- size_t num = mAudioSessionRefs.size();
- bool removed = false;
- for (size_t i = 0; i < num; ) {
- AudioSessionRef *ref = mAudioSessionRefs.itemAt(i);
- ALOGV(" pid %d @ %zu", ref->mPid, i);
- if (ref->mPid == pid) {
- ALOGV(" removing entry for pid %d session %d", pid, ref->mSessionid);
- mAudioSessionRefs.removeAt(i);
- delete ref;
- removed = true;
- num--;
- } else {
- i++;
+ ALOGV("%d died, releasing its sessions", pid);
+ size_t num = mAudioSessionRefs.size();
+ bool removed = false;
+ for (size_t i = 0; i < num; ) {
+ AudioSessionRef *ref = mAudioSessionRefs.itemAt(i);
+ ALOGV(" pid %d @ %zu", ref->mPid, i);
+ if (ref->mPid == pid) {
+ ALOGV(" removing entry for pid %d session %d", pid, ref->mSessionid);
+ mAudioSessionRefs.removeAt(i);
+ delete ref;
+ removed = true;
+ num--;
+ } else {
+ i++;
+ }
+ }
+ if (removed) {
+ removedEffects = purgeStaleEffects_l();
}
}
- if (removed) {
- purgeStaleEffects_l();
+ for (auto& effect : removedEffects) {
+ effect->updatePolicyState();
}
}
@@ -1679,18 +1699,35 @@
}
// getEffectThread_l() must be called with AudioFlinger::mLock held
-sp<AudioFlinger::PlaybackThread> AudioFlinger::getEffectThread_l(audio_session_t sessionId,
- int EffectId)
+sp<AudioFlinger::ThreadBase> AudioFlinger::getEffectThread_l(audio_session_t sessionId,
+ int effectId)
{
- sp<PlaybackThread> thread;
+ sp<ThreadBase> thread;
for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
- if (mPlaybackThreads.valueAt(i)->getEffect(sessionId, EffectId) != 0) {
+ if (mPlaybackThreads.valueAt(i)->getEffect(sessionId, effectId) != 0) {
ALOG_ASSERT(thread == 0);
thread = mPlaybackThreads.valueAt(i);
}
}
-
+ if (thread != nullptr) {
+ return thread;
+ }
+ for (size_t i = 0; i < mRecordThreads.size(); i++) {
+ if (mRecordThreads.valueAt(i)->getEffect(sessionId, effectId) != 0) {
+ ALOG_ASSERT(thread == 0);
+ thread = mRecordThreads.valueAt(i);
+ }
+ }
+ if (thread != nullptr) {
+ return thread;
+ }
+ for (size_t i = 0; i < mMmapThreads.size(); i++) {
+ if (mMmapThreads.valueAt(i)->getEffect(sessionId, effectId) != 0) {
+ ALOG_ASSERT(thread == 0);
+ thread = mMmapThreads.valueAt(i);
+ }
+ }
return thread;
}
@@ -2425,7 +2462,7 @@
Vector< sp<EffectChain> > effectChains = playbackThread->getEffectChains_l();
for (size_t i = 0; i < effectChains.size(); i ++) {
moveEffectChain_l(effectChains[i]->sessionId(), playbackThread.get(),
- dstThread, true);
+ dstThread);
}
}
}
@@ -2792,31 +2829,40 @@
void AudioFlinger::releaseAudioSessionId(audio_session_t audioSession, pid_t pid)
{
- Mutex::Autolock _l(mLock);
- pid_t caller = IPCThreadState::self()->getCallingPid();
- ALOGV("releasing %d from %d for %d", audioSession, caller, pid);
- const uid_t callerUid = IPCThreadState::self()->getCallingUid();
- if (pid != -1 && isAudioServerUid(callerUid)) { // check must match acquireAudioSessionId()
- caller = pid;
- }
- size_t num = mAudioSessionRefs.size();
- for (size_t i = 0; i < num; i++) {
- AudioSessionRef *ref = mAudioSessionRefs.itemAt(i);
- if (ref->mSessionid == audioSession && ref->mPid == caller) {
- ref->mCnt--;
- ALOGV(" decremented refcount to %d", ref->mCnt);
- if (ref->mCnt == 0) {
- mAudioSessionRefs.removeAt(i);
- delete ref;
- purgeStaleEffects_l();
- }
- return;
+ std::vector< sp<EffectModule> > removedEffects;
+ {
+ Mutex::Autolock _l(mLock);
+ pid_t caller = IPCThreadState::self()->getCallingPid();
+ ALOGV("releasing %d from %d for %d", audioSession, caller, pid);
+ const uid_t callerUid = IPCThreadState::self()->getCallingUid();
+ if (pid != -1 && isAudioServerUid(callerUid)) { // check must match acquireAudioSessionId()
+ caller = pid;
}
+ size_t num = mAudioSessionRefs.size();
+ for (size_t i = 0; i < num; i++) {
+ AudioSessionRef *ref = mAudioSessionRefs.itemAt(i);
+ if (ref->mSessionid == audioSession && ref->mPid == caller) {
+ ref->mCnt--;
+ ALOGV(" decremented refcount to %d", ref->mCnt);
+ if (ref->mCnt == 0) {
+ mAudioSessionRefs.removeAt(i);
+ delete ref;
+ std::vector< sp<EffectModule> > effects = purgeStaleEffects_l();
+ removedEffects.insert(removedEffects.end(), effects.begin(), effects.end());
+ }
+ goto Exit;
+ }
+ }
+ // If the caller is audioserver it is likely that the session being released was acquired
+ // on behalf of a process not in notification clients and we ignore the warning.
+ ALOGW_IF(!isAudioServerUid(callerUid),
+ "session id %d not found for pid %d", audioSession, caller);
}
- // If the caller is audioserver it is likely that the session being released was acquired
- // on behalf of a process not in notification clients and we ignore the warning.
- ALOGW_IF(!isAudioServerUid(callerUid),
- "session id %d not found for pid %d", audioSession, caller);
+
+Exit:
+ for (auto& effect : removedEffects) {
+ effect->updatePolicyState();
+ }
}
bool AudioFlinger::isSessionAcquired_l(audio_session_t audioSession)
@@ -2831,11 +2877,12 @@
return false;
}
-void AudioFlinger::purgeStaleEffects_l() {
+std::vector<sp<AudioFlinger::EffectModule>> AudioFlinger::purgeStaleEffects_l() {
ALOGV("purging stale effects");
Vector< sp<EffectChain> > chains;
+ std::vector< sp<EffectModule> > removedEffects;
for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
sp<PlaybackThread> t = mPlaybackThreads.valueAt(i);
@@ -2847,6 +2894,7 @@
}
}
}
+
for (size_t i = 0; i < mRecordThreads.size(); i++) {
sp<RecordThread> t = mRecordThreads.valueAt(i);
Mutex::Autolock _l(t->mLock);
@@ -2856,6 +2904,15 @@
}
}
+ for (size_t i = 0; i < mMmapThreads.size(); i++) {
+ sp<MmapThread> t = mMmapThreads.valueAt(i);
+ Mutex::Autolock _l(t->mLock);
+ for (size_t j = 0; j < t->mEffectChains.size(); j++) {
+ sp<EffectChain> ec = t->mEffectChains[j];
+ chains.push(ec);
+ }
+ }
+
for (size_t i = 0; i < chains.size(); i++) {
sp<EffectChain> ec = chains[i];
int sessionid = ec->sessionId();
@@ -2884,11 +2941,11 @@
if (effect->purgeHandles()) {
t->checkSuspendOnEffectEnabled_l(effect, false, effect->sessionId());
}
- AudioSystem::unregisterEffect(effect->id());
+ removedEffects.push_back(effect);
}
}
}
- return;
+ return removedEffects;
}
// dumpToThreadLog_l() must be called with AudioFlinger::mLock held
@@ -3380,8 +3437,16 @@
}
}
- if (lStatus != NO_ERROR && lStatus != ALREADY_EXISTS) {
- // handle must be cleared outside lock.
+ if (lStatus == NO_ERROR || lStatus == ALREADY_EXISTS) {
+ // Check CPU and memory usage
+ sp<EffectModule> effect = handle->effect().promote();
+ if (effect != nullptr) {
+ status_t rStatus = effect->updatePolicyState();
+ if (rStatus != NO_ERROR) {
+ lStatus = rStatus;
+ }
+ }
+ } else {
handle.clear();
}
@@ -3413,14 +3478,30 @@
Mutex::Autolock _dl(dstThread->mLock);
Mutex::Autolock _sl(srcThread->mLock);
- return moveEffectChain_l(sessionId, srcThread, dstThread, false);
+ return moveEffectChain_l(sessionId, srcThread, dstThread);
}
+
+void AudioFlinger::setEffectSuspended(int effectId,
+ audio_session_t sessionId,
+ bool suspended)
+{
+ Mutex::Autolock _l(mLock);
+
+ sp<ThreadBase> thread = getEffectThread_l(sessionId, effectId);
+ if (thread == nullptr) {
+ return;
+ }
+ Mutex::Autolock _sl(thread->mLock);
+ sp<EffectModule> effect = thread->getEffect_l(sessionId, effectId);
+ thread->setEffectSuspended_l(&effect->desc().type, suspended, sessionId);
+}
+
+
// moveEffectChain_l must be called with both srcThread and dstThread mLocks held
status_t AudioFlinger::moveEffectChain_l(audio_session_t sessionId,
AudioFlinger::PlaybackThread *srcThread,
- AudioFlinger::PlaybackThread *dstThread,
- bool reRegister)
+ AudioFlinger::PlaybackThread *dstThread)
{
ALOGV("moveEffectChain_l() session %d from thread %p to thread %p",
sessionId, srcThread, dstThread);
@@ -3476,36 +3557,68 @@
}
strategy = dstChain->strategy();
}
- if (reRegister) {
- AudioSystem::unregisterEffect(effect->id());
- AudioSystem::registerEffect(&effect->desc(),
- dstThread->id(),
- strategy,
- sessionId,
- effect->id());
- AudioSystem::setEffectEnabled(effect->id(), effect->isEnabled());
- }
effect = chain->getEffectFromId_l(0);
}
if (status != NO_ERROR) {
for (size_t i = 0; i < removed.size(); i++) {
srcThread->addEffect_l(removed[i]);
- if (dstChain != 0 && reRegister) {
- AudioSystem::unregisterEffect(removed[i]->id());
- AudioSystem::registerEffect(&removed[i]->desc(),
- srcThread->id(),
- strategy,
- sessionId,
- removed[i]->id());
- AudioSystem::setEffectEnabled(effect->id(), effect->isEnabled());
- }
}
}
return status;
}
+status_t AudioFlinger::moveAuxEffectToIo(int EffectId,
+ const sp<PlaybackThread>& dstThread,
+ sp<PlaybackThread> *srcThread)
+{
+ status_t status = NO_ERROR;
+ Mutex::Autolock _l(mLock);
+ sp<PlaybackThread> thread =
+ static_cast<PlaybackThread *>(getEffectThread_l(AUDIO_SESSION_OUTPUT_MIX, EffectId).get());
+
+ if (EffectId != 0 && thread != 0 && dstThread != thread.get()) {
+ Mutex::Autolock _dl(dstThread->mLock);
+ Mutex::Autolock _sl(thread->mLock);
+ sp<EffectChain> srcChain = thread->getEffectChain_l(AUDIO_SESSION_OUTPUT_MIX);
+ sp<EffectChain> dstChain;
+ if (srcChain == 0) {
+ return INVALID_OPERATION;
+ }
+
+ sp<EffectModule> effect = srcChain->getEffectFromId_l(EffectId);
+ if (effect == 0) {
+ return INVALID_OPERATION;
+ }
+ thread->removeEffect_l(effect);
+ status = dstThread->addEffect_l(effect);
+ if (status != NO_ERROR) {
+ thread->addEffect_l(effect);
+ status = INVALID_OPERATION;
+ goto Exit;
+ }
+
+ dstChain = effect->chain().promote();
+ if (dstChain == 0) {
+ thread->addEffect_l(effect);
+ status = INVALID_OPERATION;
+ }
+
+Exit:
+ // removeEffect_l() has stopped the effect if it was active so it must be restarted
+ if (effect->state() == EffectModule::ACTIVE ||
+ effect->state() == EffectModule::STOPPING) {
+ effect->start();
+ }
+ }
+
+ if (status == NO_ERROR && srcThread != nullptr) {
+ *srcThread = thread;
+ }
+ return status;
+}
+
bool AudioFlinger::isNonOffloadableGlobalEffectEnabled_l()
{
if (mGlobalEffectEnableTime != 0 &&
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 9960f0e..72e669a 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -239,6 +239,10 @@
virtual status_t moveEffects(audio_session_t sessionId, audio_io_handle_t srcOutput,
audio_io_handle_t dstOutput);
+ void setEffectSuspended(int effectId,
+ audio_session_t sessionId,
+ bool suspended) override;
+
virtual audio_module_handle_t loadHwModule(const char *name);
virtual uint32_t getPrimaryOutputSamplingRate();
@@ -369,7 +373,6 @@
AudioHwDevice* findSuitableHwDev_l(audio_module_handle_t module,
audio_devices_t devices);
- void purgeStaleEffects_l();
// Set kEnableExtendedChannels to true to enable greater than stereo output
// for the MixerThread and device sink. Number of channels allowed is
@@ -696,8 +699,11 @@
status_t moveEffectChain_l(audio_session_t sessionId,
PlaybackThread *srcThread,
- PlaybackThread *dstThread,
- bool reRegister);
+ PlaybackThread *dstThread);
+
+ status_t moveAuxEffectToIo(int EffectId,
+ const sp<PlaybackThread>& dstThread,
+ sp<PlaybackThread> *srcThread);
// return thread associated with primary hardware device, or NULL
PlaybackThread *primaryPlaybackThread_l() const;
@@ -706,7 +712,7 @@
// return the playback thread with smallest HAL buffer size, and prefer fast
PlaybackThread *fastPlaybackThread_l() const;
- sp<PlaybackThread> getEffectThread_l(audio_session_t sessionId, int EffectId);
+ sp<ThreadBase> getEffectThread_l(audio_session_t sessionId, int effectId);
void removeClient_l(pid_t pid);
@@ -732,6 +738,8 @@
// Return true if the effect was found in mOrphanEffectChains, false otherwise.
bool updateOrphanEffectChains(const sp<EffectModule>& effect);
+ std::vector< sp<EffectModule> > purgeStaleEffects_l();
+
void broacastParametersToRecordThreads_l(const String8& keyValuePairs);
void forwardParametersToDownstreamPatches_l(
audio_io_handle_t upStream, const String8& keyValuePairs,
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 2b34267..3c4fbba 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -168,6 +168,68 @@
return status;
}
+status_t AudioFlinger::EffectModule::updatePolicyState()
+{
+ status_t status = NO_ERROR;
+ bool doRegister = false;
+ bool registered = false;
+ bool doEnable = false;
+ bool enabled = false;
+ audio_io_handle_t io;
+ uint32_t strategy;
+
+ {
+ Mutex::Autolock _l(mLock);
+ // register effect when first handle is attached and unregister when last handle is removed
+ if (mPolicyRegistered != mHandles.size() > 0) {
+ doRegister = true;
+ mPolicyRegistered = mHandles.size() > 0;
+ if (mPolicyRegistered) {
+ sp <EffectChain> chain = mChain.promote();
+ sp <ThreadBase> thread = mThread.promote();
+
+ if (thread == nullptr || chain == nullptr) {
+ return INVALID_OPERATION;
+ }
+ io = thread->id();
+ strategy = chain->strategy();
+ }
+ }
+ // enable effect when registered according to enable state requested by controlling handle
+ if (mHandles.size() > 0) {
+ EffectHandle *handle = controlHandle_l();
+ if (handle != nullptr && mPolicyEnabled != handle->enabled()) {
+ doEnable = true;
+ mPolicyEnabled = handle->enabled();
+ }
+ }
+ registered = mPolicyRegistered;
+ enabled = mPolicyEnabled;
+ mPolicyLock.lock();
+ }
+ ALOGV("%s name %s id %d session %d doRegister %d registered %d doEnable %d enabled %d",
+ __func__, mDescriptor.name, mId, mSessionId, doRegister, registered, doEnable, enabled);
+ if (doRegister) {
+ if (registered) {
+ status = AudioSystem::registerEffect(
+ &mDescriptor,
+ io,
+ strategy,
+ mSessionId,
+ mId);
+ } else {
+ status = AudioSystem::unregisterEffect(mId);
+ }
+ }
+ if (registered && doEnable) {
+ status = AudioSystem::setEffectEnabled(mId, enabled);
+ }
+ mPolicyLock.unlock();
+
+ return status;
+}
+
+
ssize_t AudioFlinger::EffectModule::removeHandle(EffectHandle *handle)
{
Mutex::Autolock _l(mLock);
@@ -230,7 +292,6 @@
Mutex::Autolock _l(mLock);
ssize_t numHandles = removeHandle_l(handle);
if ((numHandles == 0) && (!mPinned || unpinIfLast)) {
- AudioSystem::unregisterEffect(mId);
sp<AudioFlinger> af = mAudioFlinger.promote();
if (af != 0) {
mLock.unlock();
@@ -943,11 +1004,6 @@
ALOGV("setEnabled %p enabled %d", this, enabled);
if (enabled != isEnabled()) {
- status_t status = AudioSystem::setEffectEnabled(mId, enabled);
- if (enabled && status != NO_ERROR) {
- return status;
- }
-
switch (mState) {
// going from disabled to enabled
case IDLE:
@@ -1253,14 +1309,11 @@
{
bool enabled = false;
Mutex::Autolock _l(mLock);
- for (size_t i = 0; i < mHandles.size(); i++) {
- EffectHandle *handle = mHandles[i];
- if (handle != NULL && !handle->disconnected()) {
- if (handle->hasControl()) {
- enabled = handle->enabled();
- }
- }
+ EffectHandle *handle = controlHandle_l();
+ if (handle != NULL) {
+ enabled = handle->enabled();
}
+ mHandles.clear();
return enabled;
}
@@ -1435,9 +1488,10 @@
result.append("\t\tCould not lock Fx mutex:\n");
}
- result.append("\t\tSession Status State Engine:\n");
- result.appendFormat("\t\t%05d %03d %03d %p\n",
- mSessionId, mStatus, mState, mEffectInterface.get());
+ result.append("\t\tSession Status State Registered Enabled Suspended Engine:\n");
+ result.appendFormat("\t\t%05d %03d %03d %s %s %s %p\n",
+ mSessionId, mStatus, mState, mPolicyRegistered ? "y" : "n", mPolicyEnabled ? "y" : "n",
+ mSuspended ? "y" : "n", mEffectInterface.get());
result.append("\t\tDescriptor:\n");
char uuidStr[64];
@@ -1572,6 +1626,12 @@
mEnabled = true;
+ status_t status = effect->updatePolicyState();
+ if (status != NO_ERROR) {
+ mEnabled = false;
+ return status;
+ }
+
sp<ThreadBase> thread = effect->thread().promote();
if (thread != 0) {
thread->checkSuspendOnEffectEnabled(effect, true, effect->sessionId());
@@ -1582,7 +1642,7 @@
return NO_ERROR;
}
- status_t status = effect->setEnabled(true);
+ status = effect->setEnabled(true);
if (status != NO_ERROR) {
if (thread != 0) {
thread->checkSuspendOnEffectEnabled(effect, false, effect->sessionId());
@@ -1625,6 +1685,8 @@
}
mEnabled = false;
+ effect->updatePolicyState();
+
if (effect->suspended()) {
return NO_ERROR;
}
@@ -1660,20 +1722,17 @@
return;
}
mDisconnected = true;
- sp<ThreadBase> thread;
{
sp<EffectModule> effect = mEffect.promote();
if (effect != 0) {
- thread = effect->thread().promote();
- }
- }
- if (thread != 0) {
- thread->disconnectEffectHandle(this, unpinIfLast);
- } else {
- // try to cleanup as much as we can
- sp<EffectModule> effect = mEffect.promote();
- if (effect != 0 && effect->disconnectHandle(this, unpinIfLast) > 0) {
- ALOGW("%s Effect handle %p disconnected after thread destruction", __FUNCTION__, this);
+ sp<ThreadBase> thread = effect->thread().promote();
+ if (thread != 0) {
+ thread->disconnectEffectHandle(this, unpinIfLast);
+ } else if (effect->disconnectHandle(this, unpinIfLast) > 0) {
+ ALOGW("%s Effect handle %p disconnected after thread destruction",
+ __func__, this);
+ }
+ effect->updatePolicyState();
}
}
@@ -1947,6 +2006,16 @@
return 0;
}
+std::vector<int> AudioFlinger::EffectChain::getEffectIds()
+{
+ std::vector<int> ids;
+ Mutex::Autolock _l(mLock);
+ for (size_t i = 0; i < mEffects.size(); i++) {
+ ids.push_back(mEffects[i]->id());
+ }
+ return ids;
+}
+
void AudioFlinger::EffectChain::clearInputBuffer()
{
Mutex::Autolock _l(mLock);
diff --git a/services/audioflinger/Effects.h b/services/audioflinger/Effects.h
index 58ce351..220874d 100644
--- a/services/audioflinger/Effects.h
+++ b/services/audioflinger/Effects.h
@@ -142,6 +142,8 @@
void addEffectToHal_l();
void release_l();
+ status_t updatePolicyState();
+
void dump(int fd, const Vector<String16>& args);
private:
@@ -204,6 +206,16 @@
static constexpr pid_t INVALID_PID = (pid_t)-1;
// this tid is allowed to call setVolume() without acquiring the mutex.
pid_t mSetVolumeReentrantTid = INVALID_PID;
+
+ // Audio policy effect state management
+ // Mutex protecting transactions with audio policy manager as mLock cannot
+ // be held to avoid cross deadlocks with audio policy mutex
+ Mutex mPolicyLock;
+ // Effect is registered in APM or not
+ bool mPolicyRegistered = false;
+ // Effect enabled state communicated to APM. Enabled state corresponds to
+ // state requested by the EffectHandle with control
+ bool mPolicyEnabled = false;
};
// The EffectHandle class implements the IEffect interface. It provides resources
@@ -334,6 +346,7 @@
sp<EffectModule> getEffectFromDesc_l(effect_descriptor_t *descriptor);
sp<EffectModule> getEffectFromId_l(int id);
sp<EffectModule> getEffectFromType_l(const effect_uuid_t *type);
+ std::vector<int> getEffectIds();
// FIXME use float to improve the dynamic range
bool setVolume_l(uint32_t *left, uint32_t *right, bool force = false);
void resetVolume_l();
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 6fea8be..59ced26 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -1306,7 +1306,6 @@
sp<EffectChain> chain;
bool chainCreated = false;
bool effectCreated = false;
- bool effectRegistered = false;
audio_unique_id_t effectId = AUDIO_UNIQUE_ID_USE_UNSPECIFIED;
lStatus = initCheck();
@@ -1342,13 +1341,6 @@
if (effect == 0) {
effectId = mAudioFlinger->nextUniqueId(AUDIO_UNIQUE_ID_USE_EFFECT);
- // Check CPU and memory usage
- lStatus = AudioSystem::registerEffect(
- desc, mId, chain->strategy(), sessionId, effectId);
- if (lStatus != NO_ERROR) {
- goto Exit;
- }
- effectRegistered = true;
// create a new effect module if none present in the chain
lStatus = chain->createEffect_l(effect, this, desc, effectId, sessionId, pinned);
if (lStatus != NO_ERROR) {
@@ -1378,9 +1370,6 @@
if (effectCreated) {
chain->removeEffect_l(effect);
}
- if (effectRegistered) {
- AudioSystem::unregisterEffect(effectId);
- }
if (chainCreated) {
removeEffectChain_l(chain);
}
@@ -1411,7 +1400,6 @@
}
if (remove) {
mAudioFlinger->updateOrphanEffectChains(effect);
- AudioSystem::unregisterEffect(effect->id());
if (handle->enabled()) {
checkSuspendOnEffectEnabled(effect, false, effect->sessionId());
}
@@ -1432,6 +1420,12 @@
return chain != 0 ? chain->getEffectFromId_l(effectId) : 0;
}
+std::vector<int> AudioFlinger::ThreadBase::getEffectIds_l(audio_session_t sessionId)
+{
+ sp<EffectChain> chain = getEffectChain_l(sessionId);
+ return chain != nullptr ? chain->getEffectIds() : std::vector<int>{};
+}
+
// PlaybackThread::addEffect_l() must be called with AudioFlinger::mLock and
// PlaybackThread::mLock held
status_t AudioFlinger::ThreadBase::addEffect_l(const sp<EffectModule>& effect)
@@ -2732,7 +2726,8 @@
// create a copy of mEffectChains as calling moveEffectChain_l() can reorder some effect chains
Vector< sp<EffectChain> > effectChains = mEffectChains;
for (size_t i = 0; i < effectChains.size(); i ++) {
- mAudioFlinger->moveEffectChain_l(effectChains[i]->sessionId(), this, this, false);
+ mAudioFlinger->moveEffectChain_l(effectChains[i]->sessionId(),
+ this/* srcThread */, this/* dstThread */);
}
}
@@ -8253,11 +8248,6 @@
status_t AudioFlinger::RecordThread::addEffectChain_l(const sp<EffectChain>& chain)
{
- // only one chain per input thread
- if (!mEffectChains.isEmpty()) {
- ALOGW("addEffectChain_l() already one chain %p on thread %p", chain.get(), this);
- return INVALID_OPERATION;
- }
ALOGV("addEffectChain_l() %p on thread %p", chain.get(), this);
chain->setThread(this);
chain->setInBuffer(NULL);
@@ -8277,13 +8267,14 @@
size_t AudioFlinger::RecordThread::removeEffectChain_l(const sp<EffectChain>& chain)
{
ALOGV("removeEffectChain_l() %p from thread %p", chain.get(), this);
- ALOGW_IF(mEffectChains.size() != 1,
- "removeEffectChain_l() %p invalid chain size %zu on thread %p",
- chain.get(), mEffectChains.size(), this);
- if (mEffectChains.size() == 1) {
- mEffectChains.removeAt(0);
+
+ for (size_t i = 0; i < mEffectChains.size(); i++) {
+ if (chain == mEffectChains[i]) {
+ mEffectChains.removeAt(i);
+ break;
+ }
}
- return 0;
+ return mEffectChains.size();
}
status_t AudioFlinger::RecordThread::createAudioPatch_l(const struct audio_patch *patch,
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 18cb361..37b2d08 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -315,6 +315,7 @@
sp<EffectChain> getEffectChain(audio_session_t sessionId);
// same as getEffectChain() but must be called with ThreadBase mutex locked
sp<EffectChain> getEffectChain_l(audio_session_t sessionId) const;
+ std::vector<int> getEffectIds_l(audio_session_t sessionId);
// add an effect chain to the chain list (mEffectChains)
virtual status_t addEffectChain_l(const sp<EffectChain>& chain) = 0;
// remove an effect chain from the chain list (mEffectChains)
@@ -334,7 +335,8 @@
sp<AudioFlinger::EffectModule> getEffect(audio_session_t sessionId, int effectId);
sp<AudioFlinger::EffectModule> getEffect_l(audio_session_t sessionId, int effectId);
// add and effect module. Also creates the effect chain is none exists for
- // the effects audio session
+ // the effects audio session. Only called in a context of moving an effect
+ // from one thread to another
status_t addEffect_l(const sp< EffectModule>& effect);
// remove and effect module. Also removes the effect chain is this was the last
// effect
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index bbda17f..2ff80c6 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -1244,54 +1244,25 @@
status_t AudioFlinger::PlaybackThread::Track::attachAuxEffect(int EffectId)
{
- status_t status = DEAD_OBJECT;
sp<ThreadBase> thread = mThread.promote();
- if (thread != 0) {
- PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
- sp<AudioFlinger> af = mClient->audioFlinger();
+ if (thread == nullptr) {
+ return DEAD_OBJECT;
+ }
- Mutex::Autolock _l(af->mLock);
+ sp<PlaybackThread> dstThread = (PlaybackThread *)thread.get();
+ sp<PlaybackThread> srcThread; // srcThread is initialized by call to moveAuxEffectToIo()
+ sp<AudioFlinger> af = mClient->audioFlinger();
+ status_t status = af->moveAuxEffectToIo(EffectId, dstThread, &srcThread);
- sp<PlaybackThread> srcThread = af->getEffectThread_l(AUDIO_SESSION_OUTPUT_MIX, EffectId);
-
- if (EffectId != 0 && srcThread != 0 && playbackThread != srcThread.get()) {
- Mutex::Autolock _dl(playbackThread->mLock);
- Mutex::Autolock _sl(srcThread->mLock);
- sp<EffectChain> chain = srcThread->getEffectChain_l(AUDIO_SESSION_OUTPUT_MIX);
- if (chain == 0) {
- return INVALID_OPERATION;
- }
-
- sp<EffectModule> effect = chain->getEffectFromId_l(EffectId);
- if (effect == 0) {
- return INVALID_OPERATION;
- }
- srcThread->removeEffect_l(effect);
- status = playbackThread->addEffect_l(effect);
- if (status != NO_ERROR) {
- srcThread->addEffect_l(effect);
- return INVALID_OPERATION;
- }
- // removeEffect_l() has stopped the effect if it was active so it must be restarted
- if (effect->state() == EffectModule::ACTIVE ||
- effect->state() == EffectModule::STOPPING) {
- effect->start();
- }
-
- sp<EffectChain> dstChain = effect->chain().promote();
- if (dstChain == 0) {
- srcThread->addEffect_l(effect);
- return INVALID_OPERATION;
- }
- AudioSystem::unregisterEffect(effect->id());
- AudioSystem::registerEffect(&effect->desc(),
- srcThread->id(),
- dstChain->strategy(),
- AUDIO_SESSION_OUTPUT_MIX,
- effect->id());
- AudioSystem::setEffectEnabled(effect->id(), effect->isEnabled());
+ if (EffectId != 0 && status == NO_ERROR) {
+ status = dstThread->attachAuxEffect(this, EffectId);
+ if (status == NO_ERROR) {
+ AudioSystem::moveEffectsToIo(std::vector<int>(EffectId), dstThread->id());
}
- status = playbackThread->attachAuxEffect(this, EffectId);
+ }
+
+ if (status != NO_ERROR && srcThread != nullptr) {
+ af->moveAuxEffectToIo(EffectId, srcThread, &dstThread);
}
return status;
}
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index a2cf7aa..4b56a46 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -189,6 +189,7 @@
int id) = 0;
virtual status_t unregisterEffect(int id) = 0;
virtual status_t setEffectEnabled(int id, bool enabled) = 0;
+ virtual status_t moveEffectsToIo(const std::vector<int>& ids, audio_io_handle_t io) = 0;
virtual bool isStreamActive(audio_stream_type_t stream, uint32_t inPastMs = 0) const = 0;
virtual bool isStreamActiveRemotely(audio_stream_type_t stream,
@@ -347,6 +348,10 @@
audio_io_handle_t srcOutput,
audio_io_handle_t dstOutput) = 0;
+ virtual void setEffectSuspended(int effectId,
+ audio_session_t sessionId,
+ bool suspended) = 0;
+
/* Create a patch between several source and sink ports */
virtual status_t createAudioPatch(const struct audio_patch *patch,
audio_patch_handle_t *handle,
diff --git a/services/audiopolicy/common/include/Volume.h b/services/audiopolicy/common/include/Volume.h
index 54c5c76..1dbd1eb 100644
--- a/services/audiopolicy/common/include/Volume.h
+++ b/services/audiopolicy/common/include/Volume.h
@@ -23,7 +23,6 @@
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
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
index e071fe0..37f9d14 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
@@ -68,11 +68,13 @@
bool isSourceActive(audio_source_t source) const;
audio_source_t source() const;
bool isSoundTrigger() const;
+ sp<RecordClientDescriptor> getHighestPriorityClient() const;
audio_attributes_t getHighestPriorityAttributes() const;
void setClientActive(const sp<RecordClientDescriptor>& client, bool active);
int32_t activeCount() { return mGlobalActiveCount; }
void trackEffectEnabled(const sp<EffectDescriptor> &effect, bool enabled);
EffectDescriptorCollection getEnabledEffects() const;
+ EffectDescriptorCollection getActiveEffects() const; // enabled and not suspended
// implementation of AudioIODescriptorInterface
audio_config_base_t getConfig() const override;
audio_patch_handle_t getPatchHandle() const override;
@@ -100,6 +102,10 @@
// implementation of ClientMapHandler<RecordClientDescriptor>
void addClient(const sp<RecordClientDescriptor> &client) override;
+ // Go over all active clients and suspend or restore effects according highest priority
+ // active use case
+ void checkSuspendEffects();
+
private:
void updateClientRecordingConfiguration(int event, const sp<RecordClientDescriptor>& client);
diff --git a/services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h
index 7f01dc5..c4eab30 100644
--- a/services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h
@@ -29,8 +29,8 @@
{
public:
EffectDescriptor(const effect_descriptor_t *desc, bool isMusicEffect,
- int id, int io, int session) :
- mId(id), mIo(io), mSession(session), mEnabled(false),
+ int id, audio_io_handle_t io, audio_session_t session) :
+ mId(id), mIo(io), mSession(session), mEnabled(false), mSuspended(false),
mIsMusicEffect(isMusicEffect)
{
memcpy (&mDesc, desc, sizeof(effect_descriptor_t));
@@ -38,11 +38,12 @@
void dump(String8 *dst, int spaces = 0) const;
- int mId; // effect unique ID
- int mIo; // io the effect is attached to
- int mSession; // audio session the effect is on
- effect_descriptor_t mDesc; // effect descriptor
- bool mEnabled; // enabled state: CPU load being used or not
+ int mId; // effect unique ID
+ audio_io_handle_t mIo; // io the effect is attached to
+ audio_session_t mSession; // audio session the effect is on
+ effect_descriptor_t mDesc; // effect descriptor
+ bool mEnabled; // enabled state: CPU load being used or not
+ bool mSuspended; // enabled but suspended by concurent capture policy
bool isMusicEffect() const { return mIsMusicEffect; }
@@ -59,12 +60,18 @@
int session, int id, bool isMusicEffect);
status_t unregisterEffect(int id);
sp<EffectDescriptor> getEffect(int id) const;
+ EffectDescriptorCollection getEffectsForIo(audio_io_handle_t io) const;
status_t setEffectEnabled(int id, bool enabled);
bool isEffectEnabled(int id) const;
uint32_t getMaxEffectsCpuLoad() const;
uint32_t getMaxEffectsMemory() const;
bool isNonOffloadableEffectEnabled() const;
+ void moveEffects(audio_session_t session,
+ audio_io_handle_t srcOutput,
+ audio_io_handle_t dstOutput);
+ void moveEffects(const std::vector<int>& ids, audio_io_handle_t dstOutput);
+
void dump(String8 *dst, int spaces = 0, bool verbose = true) const;
private:
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
index 5b4e2eb..58683be 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
@@ -128,6 +128,13 @@
audio_attributes_t AudioInputDescriptor::getHighestPriorityAttributes() const
{
audio_attributes_t attributes = { .source = AUDIO_SOURCE_DEFAULT };
+ sp<RecordClientDescriptor> topClient = getHighestPriorityClient();
+ return topClient ? topClient->attributes() : attributes;
+}
+
+sp<RecordClientDescriptor> AudioInputDescriptor::getHighestPriorityClient() const
+{
+ sp<RecordClientDescriptor> topClient;
for (bool activeOnly : { true, false }) {
int32_t topPriority = -1;
@@ -139,18 +146,18 @@
app_state_t curState = client->appState();
if (curState >= topState) {
int32_t curPriority = source_priority(client->source());
- if (curPriority > topPriority) {
- attributes = client->attributes();
+ if (curPriority >= topPriority) {
+ topClient = client;
topPriority = curPriority;
}
topState = curState;
}
}
- if (attributes.source != AUDIO_SOURCE_DEFAULT) {
+ if (topClient != nullptr) {
break;
}
}
- return attributes;
+ return topClient;
}
bool AudioInputDescriptor::isSoundTrigger() const {
@@ -326,9 +333,10 @@
client->setActive(active);
+ checkSuspendEffects();
+
int event = active ? RECORD_CONFIG_EVENT_START : RECORD_CONFIG_EVENT_STOP;
updateClientRecordingConfiguration(event, client);
-
}
void AudioInputDescriptor::updateClientRecordingConfiguration(
@@ -397,44 +405,90 @@
mEnabledEffects.replaceValueFor(effect->mId, effect);
} else {
mEnabledEffects.removeItem(effect->mId);
+ // always exit from suspend when disabling an effect as only enabled effects
+ // are managed by checkSuspendEffects()
+ if (effect->mSuspended) {
+ effect->mSuspended = false;
+ mClientInterface->setEffectSuspended(effect->mId, effect->mSession, effect->mSuspended);
+ }
}
RecordClientVector clients = getClientsForSession((audio_session_t)effect->mSession);
+ RecordClientVector updatedClients;
+
for (const auto& client : clients) {
sp<EffectDescriptor> clientEffect = client->getEnabledEffects().getEffect(effect->mId);
bool changed = (enabled && clientEffect == nullptr)
|| (!enabled && clientEffect != nullptr);
client->trackEffectEnabled(effect, enabled);
if (changed && client->active()) {
- updateClientRecordingConfiguration(RECORD_CONFIG_EVENT_START, client);
+ updatedClients.push_back(client);
}
}
+
+ checkSuspendEffects();
+
+ for (const auto& client : updatedClients) {
+ updateClientRecordingConfiguration(RECORD_CONFIG_EVENT_START, client);
+ }
}
EffectDescriptorCollection AudioInputDescriptor::getEnabledEffects() const
{
- EffectDescriptorCollection enabledEffects;
// report effects for highest priority active source as applied to all clients
- RecordClientVector clients =
- clientsList(true /*activeOnly*/, source(), false /*preferredDeviceOnly*/);
- if (clients.size() > 0) {
- enabledEffects = clients[0]->getEnabledEffects();
+ EffectDescriptorCollection enabledEffects;
+ sp<RecordClientDescriptor> topClient = getHighestPriorityClient();
+ if (topClient != nullptr) {
+ enabledEffects = topClient->getEnabledEffects();
}
return enabledEffects;
}
-void AudioInputDescriptor::setAppState(uid_t uid, app_state_t state) {
+void AudioInputDescriptor::setAppState(uid_t uid, app_state_t state)
+{
RecordClientVector clients = clientsList(false /*activeOnly*/);
+ RecordClientVector updatedClients;
for (const auto& client : clients) {
if (uid == client->uid()) {
bool wasSilenced = client->isSilenced();
client->setAppState(state);
if (client->active() && wasSilenced != client->isSilenced()) {
- updateClientRecordingConfiguration(RECORD_CONFIG_EVENT_START, client);
+ updatedClients.push_back(client);
}
}
}
+
+ checkSuspendEffects();
+
+ for (const auto& client : updatedClients) {
+ updateClientRecordingConfiguration(RECORD_CONFIG_EVENT_START, client);
+ }
+}
+
+void AudioInputDescriptor::checkSuspendEffects()
+{
+ sp<RecordClientDescriptor> topClient = getHighestPriorityClient();
+ if (topClient == nullptr) {
+ return;
+ }
+
+ for (size_t i = 0; i < mEnabledEffects.size(); i++) {
+ sp<EffectDescriptor> effect = mEnabledEffects.valueAt(i);
+ if (effect->mSession == topClient->session()) {
+ if (effect->mSuspended) {
+ effect->mSuspended = false;
+ mClientInterface->setEffectSuspended(effect->mId,
+ effect->mSession,
+ effect->mSuspended);
+ }
+ } else if (!effect->mSuspended) {
+ effect->mSuspended = true;
+ mClientInterface->setEffectSuspended(effect->mId,
+ effect->mSession,
+ effect->mSuspended);
+ }
+ }
}
void AudioInputDescriptor::dump(String8 *dst) const
@@ -444,7 +498,7 @@
dst->appendFormat(" Format: %d\n", mFormat);
dst->appendFormat(" Channels: %08x\n", mChannelMask);
dst->appendFormat(" Devices %s\n", mDevice->toString().c_str());
- getEnabledEffects().dump(dst, 1 /*spaces*/, false /*verbose*/);
+ mEnabledEffects.dump(dst, 1 /*spaces*/, false /*verbose*/);
dst->append(" AudioRecord Clients:\n");
ClientMapHandler<RecordClientDescriptor>::dump(dst);
dst->append("\n");
diff --git a/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp
index 89f9899..415962a 100644
--- a/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp
@@ -30,6 +30,7 @@
dst->appendFormat("%*sSession: %d\n", spaces, "", mSession);
dst->appendFormat("%*sName: %s\n", spaces, "", mDesc.name);
dst->appendFormat("%*s%s\n", spaces, "", mEnabled ? "Enabled" : "Disabled");
+ dst->appendFormat("%*s%s\n", spaces, "", mSuspended ? "Suspended" : "Active");
}
EffectDescriptorCollection::EffectDescriptorCollection() :
@@ -63,7 +64,8 @@
desc->name, io, session, id);
ALOGV("registerEffect() memory %d, total memory %d", desc->memoryUsage, mTotalEffectsMemory);
- sp<EffectDescriptor> effectDesc = new EffectDescriptor(desc, isMusicEffect, id, io, session);
+ sp<EffectDescriptor> effectDesc =
+ new EffectDescriptor(desc, isMusicEffect, id, io, (audio_session_t)session);
add(id, effectDesc);
return NO_ERROR;
@@ -174,6 +176,43 @@
return MAX_EFFECTS_MEMORY;
}
+void EffectDescriptorCollection::moveEffects(audio_session_t session,
+ audio_io_handle_t srcOutput,
+ audio_io_handle_t dstOutput)
+{
+ ALOGV("%s session %d srcOutput %d dstOutput %d", __func__, session, srcOutput, dstOutput);
+ for (size_t i = 0; i < size(); i++) {
+ sp<EffectDescriptor> effect = valueAt(i);
+ if (effect->mSession == session && effect->mIo == srcOutput) {
+ effect->mIo = dstOutput;
+ }
+ }
+}
+
+void EffectDescriptorCollection::moveEffects(const std::vector<int>& ids,
+ audio_io_handle_t dstOutput)
+{
+ ALOGV("%s num effects %zu, first ID %d, dstOutput %d",
+ __func__, ids.size(), ids.size() ? ids[0] : 0, dstOutput);
+ for (size_t i = 0; i < size(); i++) {
+ sp<EffectDescriptor> effect = valueAt(i);
+ if (std::find(begin(ids), end(ids), effect->mId) != end(ids)) {
+ effect->mIo = dstOutput;
+ }
+ }
+}
+
+EffectDescriptorCollection EffectDescriptorCollection::getEffectsForIo(audio_io_handle_t io) const
+{
+ EffectDescriptorCollection effects;
+ for (size_t i = 0; i < size(); i++) {
+ if (valueAt(i)->mIo == io) {
+ effects.add(keyAt(i), valueAt(i));
+ }
+ }
+ return effects;
+}
+
void EffectDescriptorCollection::dump(String8 *dst, int spaces, bool verbose) const
{
if (verbose) {
diff --git a/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_product_strategies.xml b/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_product_strategies.xml
index c487da9..0ee83a2 100644
--- a/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_product_strategies.xml
+++ b/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_product_strategies.xml
@@ -166,5 +166,20 @@
<Attributes> <Flags value="AUDIO_FLAG_BEACON"/> </Attributes>
</AttributesGroup>
</ProductStrategy>
+
+ <!-- Routing Strategy rerouting may be removed as following media??? -->
+ <ProductStrategy name="rerouting">
+ <AttributesGroup streamType="AUDIO_STREAM_REROUTING" volumeGroup="rerouting">
+ <Attributes></Attributes>
+ </AttributesGroup>
+ </ProductStrategy>
+
+ <!-- Patch stream needs full scale volume, define it otherwise switch to default... -->
+ <ProductStrategy name="patch">
+ <AttributesGroup streamType="AUDIO_STREAM_PATCH" volumeGroup="patch">
+ <Attributes></Attributes>
+ </AttributesGroup>
+ </ProductStrategy>
+
</ProductStrategies>
diff --git a/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_volumes.xml b/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_volumes.xml
index 9ec3d77..6e72dc5 100644
--- a/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_volumes.xml
+++ b/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_volumes.xml
@@ -188,5 +188,26 @@
<point>100,0</point>
</volume>
</volumeGroup>
+
+ <volumeGroup>
+ <name>rerouting</name>
+ <indexMin>0</indexMin>
+ <indexMax>1</indexMax>
+ <volume deviceCategory="DEVICE_CATEGORY_HEADSET">
+ <point>0,0</point>
+ <point>100,0</point>
+ </volume>
+ </volumeGroup>
+
+ <volumeGroup>
+ <name>patch</name>
+ <indexMin>0</indexMin>
+ <indexMax>1</indexMax>
+ <volume deviceCategory="DEVICE_CATEGORY_HEADSET">
+ <point>0,0</point>
+ <point>100,0</point>
+ </volume>
+ </volumeGroup>
+
</volumeGroups>
diff --git a/services/audiopolicy/engineconfigurable/config/example/caremu/audio_policy_engine_product_strategies.xml b/services/audiopolicy/engineconfigurable/config/example/caremu/audio_policy_engine_product_strategies.xml
index c487da9..adcbd83 100644
--- a/services/audiopolicy/engineconfigurable/config/example/caremu/audio_policy_engine_product_strategies.xml
+++ b/services/audiopolicy/engineconfigurable/config/example/caremu/audio_policy_engine_product_strategies.xml
@@ -166,5 +166,19 @@
<Attributes> <Flags value="AUDIO_FLAG_BEACON"/> </Attributes>
</AttributesGroup>
</ProductStrategy>
+
+ <!-- Routing Strategy rerouting may be removed as following media??? -->
+ <ProductStrategy name="rerouting">
+ <AttributesGroup streamType="AUDIO_STREAM_REROUTING" volumeGroup="rerouting">
+ <Attributes></Attributes>
+ </AttributesGroup>
+ </ProductStrategy>
+
+ <!-- Patch stream needs full scale volume, define it otherwise switch to default... -->
+ <ProductStrategy name="patch">
+ <AttributesGroup streamType="AUDIO_STREAM_PATCH" volumeGroup="patch">
+ <Attributes></Attributes>
+ </AttributesGroup>
+ </ProductStrategy>
</ProductStrategies>
diff --git a/services/audiopolicy/engineconfigurable/config/example/caremu/audio_policy_engine_volumes.xml b/services/audiopolicy/engineconfigurable/config/example/caremu/audio_policy_engine_volumes.xml
index 9ec3d77..6e72dc5 100644
--- a/services/audiopolicy/engineconfigurable/config/example/caremu/audio_policy_engine_volumes.xml
+++ b/services/audiopolicy/engineconfigurable/config/example/caremu/audio_policy_engine_volumes.xml
@@ -188,5 +188,26 @@
<point>100,0</point>
</volume>
</volumeGroup>
+
+ <volumeGroup>
+ <name>rerouting</name>
+ <indexMin>0</indexMin>
+ <indexMax>1</indexMax>
+ <volume deviceCategory="DEVICE_CATEGORY_HEADSET">
+ <point>0,0</point>
+ <point>100,0</point>
+ </volume>
+ </volumeGroup>
+
+ <volumeGroup>
+ <name>patch</name>
+ <indexMin>0</indexMin>
+ <indexMax>1</indexMax>
+ <volume deviceCategory="DEVICE_CATEGORY_HEADSET">
+ <point>0,0</point>
+ <point>100,0</point>
+ </volume>
+ </volumeGroup>
+
</volumeGroups>
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index af29f87..6bd64d6 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -142,18 +142,7 @@
__func__, device->toString().c_str(), encodedFormat);
// register new device as available
- index = mAvailableOutputDevices.add(device);
- if (index >= 0) {
- sp<HwModule> module = mHwModules.getModuleForDevice(device, encodedFormat);
- if (module == 0) {
- ALOGD("setDeviceConnectionState() could not find HW module for device %s",
- device->toString().c_str());
- mAvailableOutputDevices.remove(device);
- return INVALID_OPERATION;
- }
- ALOGV("setDeviceConnectionState() module name=%s", module->getName());
- mAvailableOutputDevices[index]->attach(module);
- } else {
+ if (mAvailableOutputDevices.add(device) < 0) {
return NO_MEMORY;
}
@@ -295,13 +284,6 @@
ALOGW("%s() device already connected: %s", __func__, device->toString().c_str());
return INVALID_OPERATION;
}
- sp<HwModule> module = mHwModules.getModuleForDevice(device, AUDIO_FORMAT_DEFAULT);
- if (module == NULL) {
- ALOGW("setDeviceConnectionState(): could not find HW module for device %s",
- device->toString().c_str());
- return INVALID_OPERATION;
- }
-
// Before checking intputs, broadcast connect event to allow HAL to retrieve dynamic
// parameters on newly connected devices (instead of opening the inputs...)
broadcastDeviceConnectionState(device, state);
@@ -2361,25 +2343,8 @@
}
void AudioPolicyManager::closeAllInputs() {
- bool patchRemoved = false;
-
- for (size_t input_index = 0; input_index < mInputs.size(); input_index++) {
- sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(input_index);
- ssize_t patch_index = mAudioPatches.indexOfKey(inputDesc->getPatchHandle());
- if (patch_index >= 0) {
- sp<AudioPatch> patchDesc = mAudioPatches.valueAt(patch_index);
- (void) /*status_t status*/ mpClientInterface->releaseAudioPatch(patchDesc->mAfPatchHandle, 0);
- mAudioPatches.removeItemsAt(patch_index);
- patchRemoved = true;
- }
- inputDesc->close();
- }
- mInputs.clear();
- SoundTrigger::setCaptureState(false);
- nextAudioPortGeneration();
-
- if (patchRemoved) {
- mpClientInterface->onAudioPatchListUpdate();
+ while (mInputs.size() != 0) {
+ closeInput(mInputs.keyAt(0));
}
}
@@ -2481,7 +2446,7 @@
// HW Gain management, do not change the volume
bool applyVolume = false;
if (desc->useHwGain()) {
- if (!(desc->isActive(group) || isInCall())) {
+ if (!(desc->isActive(toVolumeSource(group)) || isInCall())) {
continue;
}
for (const auto &productStrategy : mEngine->getOrderedProductStrategies()) {
@@ -2675,6 +2640,7 @@
}
if (output != mMusicEffectOutput) {
+ mEffects.moveEffects(AUDIO_SESSION_OUTPUT_MIX, mMusicEffectOutput, output);
mpClientInterface->moveEffects(AUDIO_SESSION_OUTPUT_MIX, mMusicEffectOutput, output);
mMusicEffectOutput = output;
}
@@ -2712,7 +2678,6 @@
if (mEffects.getEffect(id) == nullptr) {
return INVALID_OPERATION;
}
-
if (mEffects.isEffectEnabled(id)) {
ALOGW("%s effect %d enabled", __FUNCTION__, id);
setEffectEnabled(id, false);
@@ -2720,6 +2685,16 @@
return mEffects.unregisterEffect(id);
}
+void AudioPolicyManager::cleanUpEffectsForIo(audio_io_handle_t io)
+{
+ EffectDescriptorCollection effects = mEffects.getEffectsForIo(io);
+ for (size_t i = 0; i < effects.size(); i++) {
+ ALOGW("%s removing stale effect %s, id %d on closed IO %d",
+ __func__, effects.valueAt(i)->mDesc.name, effects.keyAt(i), io);
+ unregisterEffect(effects.keyAt(i));
+ }
+}
+
status_t AudioPolicyManager::setEffectEnabled(int id, bool enabled)
{
sp<EffectDescriptor> effect = mEffects.getEffect(id);
@@ -2734,6 +2709,13 @@
return status;
}
+
+status_t AudioPolicyManager::moveEffectsToIo(const std::vector<int>& ids, audio_io_handle_t io)
+{
+ mEffects.moveEffects(ids, io);
+ return NO_ERROR;
+}
+
bool AudioPolicyManager::isStreamActive(audio_stream_type_t stream, uint32_t inPastMs) const
{
return mOutputs.isActive(toVolumeSource(stream), inPastMs);
@@ -4105,15 +4087,8 @@
void AudioPolicyManager::setAppState(uid_t uid, app_state_t state)
{
ALOGV("%s(uid:%d, state:%d)", __func__, uid, state);
-
for (size_t i = 0; i < mInputs.size(); i++) {
- sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(i);
- RecordClientVector clients = inputDesc->clientsList(false /*activeOnly*/);
- for (const auto& client : clients) {
- if (uid == client->uid()) {
- client->setAppState(state);
- }
- }
+ mInputs.valueAt(i)->setAppState(uid, state);
}
}
@@ -4924,6 +4899,8 @@
setMsdPatch();
}
}
+
+ cleanUpEffectsForIo(output);
}
void AudioPolicyManager::closeInput(audio_io_handle_t input)
@@ -4955,6 +4932,8 @@
mInputs.activeInputsCountOnDevices(primaryInputDevices) == 0) {
SoundTrigger::setCaptureState(false);
}
+
+ cleanUpEffectsForIo(input);
}
SortedVector<audio_io_handle_t> AudioPolicyManager::getOutputsForDevices(
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index de447fb..3376965 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -200,6 +200,7 @@
int id);
virtual status_t unregisterEffect(int id);
virtual status_t setEffectEnabled(int id, bool enabled);
+ status_t moveEffectsToIo(const std::vector<int>& ids, audio_io_handle_t io) override;
virtual bool isStreamActive(audio_stream_type_t stream, uint32_t inPastMs = 0) const;
// return whether a stream is playing remotely, override to change the definition of
@@ -344,7 +345,7 @@
}
virtual const DeviceVector getAvailableOutputDevices() const
{
- return mAvailableOutputDevices.filterForEngine();
+ return mAvailableOutputDevices;
}
virtual const DeviceVector getAvailableInputDevices() const
{
@@ -869,6 +870,8 @@
int delayMs,
uid_t uid,
sp<AudioPatch> *patchDescPtr);
+
+ void cleanUpEffectsForIo(audio_io_handle_t io);
};
};
diff --git a/services/audiopolicy/service/AudioPolicyClientImpl.cpp b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
index 5748334..d51cc6e 100644
--- a/services/audiopolicy/service/AudioPolicyClientImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
@@ -172,6 +172,13 @@
return af->moveEffects(session, src_output, dst_output);
}
+void AudioPolicyService::AudioPolicyClient::setEffectSuspended(int effectId,
+ audio_session_t sessionId,
+ bool suspended)
+{
+ mAudioPolicyService->setEffectSuspended(effectId, sessionId, suspended);
+}
+
status_t AudioPolicyService::AudioPolicyClient::createAudioPatch(const struct audio_patch *patch,
audio_patch_handle_t *handle,
int delayMs)
diff --git a/services/audiopolicy/service/AudioPolicyEffects.h b/services/audiopolicy/service/AudioPolicyEffects.h
index 6ad01f7..dcf093b 100644
--- a/services/audiopolicy/service/AudioPolicyEffects.h
+++ b/services/audiopolicy/service/AudioPolicyEffects.h
@@ -225,6 +225,8 @@
size_t *totSize);
// protects access to mInputSources, mInputSessions, mOutputStreams, mOutputSessions
+ // never hold AudioPolicyService::mLock when calling AudioPolicyEffects methods as
+ // those can call back into AudioPolicyService methods and try to acquire the mutex
Mutex mLock;
// Automatic input effects are configured per audio_source_t
KeyedVector< audio_source_t, EffectDescVector* > mInputSources;
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index 2eb272e..2e47eb6 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -797,7 +797,7 @@
if (mAudioPolicyManager == NULL) {
return NO_INIT;
}
- Mutex::Autolock _l(mEffectsLock);
+ Mutex::Autolock _l(mLock);
AutoCallerClear acc;
return mAudioPolicyManager->registerEffect(desc, io, strategy, session, id);
}
@@ -807,7 +807,7 @@
if (mAudioPolicyManager == NULL) {
return NO_INIT;
}
- Mutex::Autolock _l(mEffectsLock);
+ Mutex::Autolock _l(mLock);
AutoCallerClear acc;
return mAudioPolicyManager->unregisterEffect(id);
}
@@ -817,11 +817,21 @@
if (mAudioPolicyManager == NULL) {
return NO_INIT;
}
- Mutex::Autolock _l(mEffectsLock);
+ Mutex::Autolock _l(mLock);
AutoCallerClear acc;
return mAudioPolicyManager->setEffectEnabled(id, enabled);
}
+status_t AudioPolicyService::moveEffectsToIo(const std::vector<int>& ids, audio_io_handle_t io)
+{
+ if (mAudioPolicyManager == NULL) {
+ return NO_INIT;
+ }
+ Mutex::Autolock _l(mLock);
+ AutoCallerClear acc;
+ return mAudioPolicyManager->moveEffectsToIo(ids, io);
+}
+
bool AudioPolicyService::isStreamActive(audio_stream_type_t stream, uint32_t inPastMs) const
{
if (uint32_t(stream) >= AUDIO_STREAM_PUBLIC_CNT) {
@@ -973,8 +983,6 @@
return false;
}
Mutex::Autolock _l(mLock);
- Mutex::Autolock _le(mEffectsLock); // isOffloadSupported queries for
- // non-offloadable effects
AutoCallerClear acc;
return mAudioPolicyManager->isOffloadSupported(info);
}
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index f63fa81..5389c08 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -1196,6 +1196,17 @@
data->mPatchHandle, data->mSource);
mLock.lock();
} break;
+ case SET_EFFECT_SUSPENDED: {
+ SetEffectSuspendedData *data = (SetEffectSuspendedData *)command->mParam.get();
+ ALOGV("AudioCommandThread() processing set effect suspended");
+ sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+ if (af != 0) {
+ mLock.unlock();
+ af->setEffectSuspended(data->mEffectId, data->mSessionId, data->mSuspended);
+ mLock.lock();
+ }
+ } break;
+
default:
ALOGW("AudioCommandThread() unknown command %d", command->mCommand);
}
@@ -1327,6 +1338,23 @@
return sendCommand(command, delayMs);
}
+void AudioPolicyService::AudioCommandThread::setEffectSuspendedCommand(int effectId,
+ audio_session_t sessionId,
+ bool suspended)
+{
+ sp<AudioCommand> command = new AudioCommand();
+ command->mCommand = SET_EFFECT_SUSPENDED;
+ sp<SetEffectSuspendedData> data = new SetEffectSuspendedData();
+ data->mEffectId = effectId;
+ data->mSessionId = sessionId;
+ data->mSuspended = suspended;
+ command->mParam = data;
+ ALOGV("AudioCommandThread() adding set suspended effectId %d sessionId %d suspended %d",
+ effectId, sessionId, suspended);
+ sendCommand(command);
+}
+
+
void AudioPolicyService::AudioCommandThread::stopOutputCommand(audio_port_handle_t portId)
{
sp<AudioCommand> command = new AudioCommand();
@@ -1707,6 +1735,14 @@
return (int)mAudioCommandThread->voiceVolumeCommand(volume, delayMs);
}
+void AudioPolicyService::setEffectSuspended(int effectId,
+ audio_session_t sessionId,
+ bool suspended)
+{
+ mAudioCommandThread->setEffectSuspendedCommand(effectId, sessionId, suspended);
+}
+
+
extern "C" {
audio_module_handle_t aps_load_hw_module(void *service __unused,
const char *name);
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index 189322f..6c19912 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -134,6 +134,7 @@
int id);
virtual status_t unregisterEffect(int id);
virtual status_t setEffectEnabled(int id, bool enabled);
+ status_t moveEffectsToIo(const std::vector<int>& ids, audio_io_handle_t io) override;
virtual bool isStreamActive(audio_stream_type_t stream, uint32_t inPastMs = 0) const;
virtual bool isStreamActiveRemotely(audio_stream_type_t stream, uint32_t inPastMs = 0) const;
virtual bool isSourceActive(audio_source_t source) const;
@@ -292,6 +293,9 @@
void onAudioVolumeGroupChanged(volume_group_t group, int flags);
void doOnAudioVolumeGroupChanged(volume_group_t group, int flags);
+ void setEffectSuspended(int effectId,
+ audio_session_t sessionId,
+ bool suspended);
private:
AudioPolicyService() ANDROID_API;
@@ -426,7 +430,8 @@
CHANGED_AUDIOVOLUMEGROUP,
SET_AUDIOPORT_CONFIG,
DYN_POLICY_MIX_STATE_UPDATE,
- RECORDING_CONFIGURATION_UPDATE
+ RECORDING_CONFIGURATION_UPDATE,
+ SET_EFFECT_SUSPENDED,
};
AudioCommandThread (String8 name, const wp<AudioPolicyService>& service);
@@ -469,6 +474,9 @@
std::vector<effect_descriptor_t> effects,
audio_patch_handle_t patchHandle,
audio_source_t source);
+ void setEffectSuspendedCommand(int effectId,
+ audio_session_t sessionId,
+ bool suspended);
void insertCommand_l(AudioCommand *command, int delayMs = 0);
private:
class AudioCommandData;
@@ -566,6 +574,13 @@
audio_source_t mSource;
};
+ class SetEffectSuspendedData : public AudioCommandData {
+ public:
+ int mEffectId;
+ audio_session_t mSessionId;
+ bool mSuspended;
+ };
+
Mutex mLock;
Condition mWaitWorkCV;
Vector < sp<AudioCommand> > mAudioCommands; // list of pending commands
@@ -651,6 +666,10 @@
audio_io_handle_t srcOutput,
audio_io_handle_t dstOutput);
+ void setEffectSuspended(int effectId,
+ audio_session_t sessionId,
+ bool suspended) override;
+
/* Create a patch between several source and sink ports */
virtual status_t createAudioPatch(const struct audio_patch *patch,
audio_patch_handle_t *handle,
@@ -810,7 +829,6 @@
mutable Mutex mLock; // prevents concurrent access to AudioPolicy manager functions changing
// device connection state or routing
- mutable Mutex mEffectsLock; // serialize access to Effect state within APM.
// Note: lock acquisition order is always mLock > mEffectsLock:
// mLock protects AudioPolicyManager methods that can call into audio flinger
// and possibly back in to audio policy service and acquire mEffectsLock.
@@ -824,6 +842,8 @@
DefaultKeyedVector< int64_t, sp<NotificationClient> > mNotificationClients;
Mutex mNotificationClientsLock; // protects mNotificationClients
// Manage all effects configured in audio_effects.conf
+ // never hold AudioPolicyService::mLock when calling AudioPolicyEffects methods as
+ // those can call back into AudioPolicyService methods and try to acquire the mutex
sp<AudioPolicyEffects> mAudioPolicyEffects;
audio_mode_t mPhoneState;
diff --git a/services/audiopolicy/tests/AudioPolicyTestClient.h b/services/audiopolicy/tests/AudioPolicyTestClient.h
index 8854eb2..e4c64e5 100644
--- a/services/audiopolicy/tests/AudioPolicyTestClient.h
+++ b/services/audiopolicy/tests/AudioPolicyTestClient.h
@@ -84,6 +84,9 @@
std::vector<effect_descriptor_t> effects __unused,
audio_patch_handle_t patchHandle __unused,
audio_source_t source __unused) override { }
+ void setEffectSuspended(int effectId __unused,
+ audio_session_t sessionId __unused,
+ bool suspended __unused) {}
};
} // namespace android
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index cca4049..a1cb8ee 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -973,11 +973,14 @@
// Make sure the UID is in an active state to use the camera
if (!mUidPolicy->isUidActive(callingUid, String16(clientName8))) {
+ int32_t procState = mUidPolicy->getProcState(callingUid);
ALOGE("Access Denial: can't use the camera from an idle UID pid=%d, uid=%d",
clientPid, clientUid);
return STATUS_ERROR_FMT(ERROR_DISABLED,
- "Caller \"%s\" (PID %d, UID %d) cannot open camera \"%s\" from background",
- clientName8.string(), clientUid, clientPid, cameraId.string());
+ "Caller \"%s\" (PID %d, UID %d) cannot open camera \"%s\" from background ("
+ "calling UID %d proc state %" PRId32 ")",
+ clientName8.string(), clientUid, clientPid, cameraId.string(),
+ callingUid, procState);
}
// If sensor privacy is enabled then prevent access to the camera
@@ -2736,6 +2739,19 @@
return active;
}
+int32_t CameraService::UidPolicy::getProcState(uid_t uid) {
+ Mutex::Autolock _l(mUidLock);
+ return getProcStateLocked(uid);
+}
+
+int32_t CameraService::UidPolicy::getProcStateLocked(uid_t uid) {
+ int32_t procState = ActivityManager::PROCESS_STATE_UNKNOWN;
+ if (mMonitoredUids.find(uid) != mMonitoredUids.end()) {
+ procState = mMonitoredUids[uid].first;
+ }
+ return procState;
+}
+
void CameraService::UidPolicy::UidPolicy::addOverrideUid(uid_t uid,
String16 callingPackage, bool active) {
updateOverrideUid(uid, callingPackage, active, true);
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 4bcdeb2..a8c2606 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -542,6 +542,7 @@
void unregisterSelf();
bool isUidActive(uid_t uid, String16 callingPackage);
+ int32_t getProcState(uid_t uid);
void onUidGone(uid_t uid, bool disabled);
void onUidActive(uid_t uid);
@@ -558,6 +559,7 @@
virtual void binderDied(const wp<IBinder> &who);
private:
bool isUidActiveLocked(uid_t uid, String16 callingPackage);
+ int32_t getProcStateLocked(uid_t uid);
void updateOverrideUid(uid_t uid, String16 callingPackage, bool active, bool insert);
Mutex mUidLock;
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index a0d0198..415b2d8 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -132,13 +132,24 @@
bool isLogical = manager->isLogicalCamera(mId.string(), &physicalCameraIds);
if (isLogical) {
for (auto& physicalId : physicalCameraIds) {
- res = manager->getCameraCharacteristics(physicalId, &mPhysicalDeviceInfoMap[physicalId]);
+ res = manager->getCameraCharacteristics(
+ physicalId, &mPhysicalDeviceInfoMap[physicalId]);
if (res != OK) {
SET_ERR_L("Could not retrieve camera %s characteristics: %s (%d)",
physicalId.c_str(), strerror(-res), res);
session->close();
return res;
}
+
+ if (DistortionMapper::isDistortionSupported(mPhysicalDeviceInfoMap[physicalId])) {
+ mDistortionMappers[physicalId].setupStaticInfo(mPhysicalDeviceInfoMap[physicalId]);
+ if (res != OK) {
+ SET_ERR_L("Unable to read camera %s's calibration fields for distortion "
+ "correction", physicalId.c_str());
+ session->close();
+ return res;
+ }
+ }
}
}
@@ -308,7 +319,7 @@
}
if (DistortionMapper::isDistortionSupported(mDeviceInfo)) {
- res = mDistortionMapper.setupStaticInfo(mDeviceInfo);
+ res = mDistortionMappers[mId.c_str()].setupStaticInfo(mDeviceInfo);
if (res != OK) {
SET_ERR_L("Unable to read necessary calibration fields for distortion correction");
return res;
@@ -3503,12 +3514,27 @@
}
// Fix up some result metadata to account for HAL-level distortion correction
- status_t res = mDistortionMapper.correctCaptureResult(&captureResult.mMetadata);
+ status_t res =
+ mDistortionMappers[mId.c_str()].correctCaptureResult(&captureResult.mMetadata);
if (res != OK) {
SET_ERR("Unable to correct capture result metadata for frame %d: %s (%d)",
frameNumber, strerror(res), res);
return;
}
+ for (auto& physicalMetadata : captureResult.mPhysicalMetadatas) {
+ String8 cameraId8(physicalMetadata.mPhysicalCameraId);
+ if (mDistortionMappers.find(cameraId8.c_str()) == mDistortionMappers.end()) {
+ continue;
+ }
+ res = mDistortionMappers[cameraId8.c_str()].correctCaptureResult(
+ &physicalMetadata.mPhysicalCameraMetadata);
+ if (res != OK) {
+ SET_ERR("Unable to correct physical capture result metadata for frame %d: %s (%d)",
+ frameNumber, strerror(res), res);
+ return;
+ }
+ }
+
// Fix up result metadata for monochrome camera.
res = fixupMonochromeTags(mDeviceInfo, captureResult.mMetadata);
if (res != OK) {
@@ -5482,13 +5508,21 @@
// Correct metadata regions for distortion correction if enabled
sp<Camera3Device> parent = mParent.promote();
if (parent != nullptr) {
- res = parent->mDistortionMapper.correctCaptureRequest(
- &(captureRequest->mSettingsList.begin()->metadata));
- if (res != OK) {
- SET_ERR("RequestThread: Unable to correct capture requests "
- "for lens distortion for request %d: %s (%d)",
- halRequest->frame_number, strerror(-res), res);
- return INVALID_OPERATION;
+ List<PhysicalCameraSettings>::iterator it;
+ for (it = captureRequest->mSettingsList.begin();
+ it != captureRequest->mSettingsList.end(); it++) {
+ if (parent->mDistortionMappers.find(it->cameraId) ==
+ parent->mDistortionMappers.end()) {
+ continue;
+ }
+ res = parent->mDistortionMappers[it->cameraId].correctCaptureRequest(
+ &(it->metadata));
+ if (res != OK) {
+ SET_ERR("RequestThread: Unable to correct capture requests "
+ "for lens distortion for request %d: %s (%d)",
+ halRequest->frame_number, strerror(-res), res);
+ return INVALID_OPERATION;
+ }
}
}
}
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index d3bb212..f8245df 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -1250,8 +1250,10 @@
/**
* Distortion correction support
*/
-
- camera3::DistortionMapper mDistortionMapper;
+ // Map from camera IDs to its corresponding distortion mapper. Only contains
+ // 1 ID if the device isn't a logical multi-camera. Otherwise contains both
+ // logical camera and its physical subcameras.
+ std::unordered_map<std::string, camera3::DistortionMapper> mDistortionMappers;
// Debug tracker for metadata tag value changes
// - Enabled with the -m <taglist> option to dumpsys, such as
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
index 1c77581..acb8b3c 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -491,8 +491,11 @@
* sets the mBufferManager if device version is > HAL3.2, which guarantees that the buffer
* manager setup is skipped in below code. Note that HAL3.2 is also excluded here, as some
* HAL3.2 devices may not support the dynamic buffer registeration.
+ * Also Camera3BufferManager does not support display/texture streams as they have its own
+ * buffer management logic.
*/
- if (mBufferManager != 0 && mSetId > CAMERA3_STREAM_SET_ID_INVALID) {
+ if (mBufferManager != 0 && mSetId > CAMERA3_STREAM_SET_ID_INVALID &&
+ !(isConsumedByHWComposer() || isConsumedByHWTexture())) {
uint64_t consumerUsage = 0;
getEndpointUsage(&consumerUsage);
StreamInfo streamInfo(
diff --git a/services/mediacodec/main_swcodecservice.cpp b/services/mediacodec/main_swcodecservice.cpp
index a5db031..d91b788 100644
--- a/services/mediacodec/main_swcodecservice.cpp
+++ b/services/mediacodec/main_swcodecservice.cpp
@@ -33,11 +33,12 @@
extern "C" void RegisterCodecServices();
-int main(int argc __unused, char** /*argv*/)
+int main(int argc __unused, char** argv)
{
LOG(INFO) << "media swcodec service starting";
signal(SIGPIPE, SIG_IGN);
SetUpMinijail(kSystemSeccompPolicyPath, kVendorSeccompPolicyPath);
+ strcpy(argv[0], "media.swcodec");
::android::hardware::configureRpcThreadpool(64, false);
diff --git a/services/oboeservice/AAudioService.cpp b/services/oboeservice/AAudioService.cpp
index e6a8375..af8c67b 100644
--- a/services/oboeservice/AAudioService.cpp
+++ b/services/oboeservice/AAudioService.cpp
@@ -78,6 +78,11 @@
AAudioClientTracker::getInstance().registerClient(pid, client);
}
+bool AAudioService::isCallerInService() {
+ return mAudioClient.clientPid == IPCThreadState::self()->getCallingPid() &&
+ mAudioClient.clientUid == IPCThreadState::self()->getCallingUid();
+}
+
aaudio_handle_t AAudioService::openStream(const aaudio::AAudioStreamRequest &request,
aaudio::AAudioStreamConfiguration &configurationOutput) {
aaudio_result_t result = AAUDIO_OK;
@@ -105,8 +110,7 @@
if (sharingMode == AAUDIO_SHARING_MODE_EXCLUSIVE) {
// only trust audioserver for in service indication
bool inService = false;
- if (mAudioClient.clientPid == IPCThreadState::self()->getCallingPid() &&
- mAudioClient.clientUid == IPCThreadState::self()->getCallingUid()) {
+ if (isCallerInService()) {
inService = request.isInService();
}
serviceStream = new AAudioServiceStreamMMAP(*this, inService);
@@ -274,12 +278,14 @@
result = AAUDIO_ERROR_INVALID_STATE;
} else {
const pid_t ownerPid = IPCThreadState::self()->getCallingPid(); // TODO review
+ int32_t priority = isCallerInService()
+ ? kRealTimeAudioPriorityService : kRealTimeAudioPriorityClient;
serviceStream->setRegisteredThread(clientThreadId);
int err = android::requestPriority(ownerPid, clientThreadId,
- DEFAULT_AUDIO_PRIORITY, true /* isForApp */);
+ priority, true /* isForApp */);
if (err != 0) {
ALOGE("AAudioService::registerAudioThread(%d) failed, errno = %d, priority = %d",
- clientThreadId, errno, DEFAULT_AUDIO_PRIORITY);
+ clientThreadId, errno, priority);
result = AAUDIO_ERROR_INTERNAL;
}
}
diff --git a/services/oboeservice/AAudioService.h b/services/oboeservice/AAudioService.h
index d21b1cd..43a59c3 100644
--- a/services/oboeservice/AAudioService.h
+++ b/services/oboeservice/AAudioService.h
@@ -87,6 +87,10 @@
private:
+ /** @return true if the client is the audioserver
+ */
+ bool isCallerInService();
+
/**
* Lookup stream and then validate access to the stream.
* @param streamHandle
@@ -106,9 +110,10 @@
aaudio::AAudioStreamTracker mStreamTracker;
- enum constants {
- DEFAULT_AUDIO_PRIORITY = 2
- };
+ // TODO Extract the priority constants from services/audioflinger/Threads.cpp
+ // and share them with this code. Look for "kPriorityFastMixer".
+ static constexpr int32_t kRealTimeAudioPriorityClient = 2;
+ static constexpr int32_t kRealTimeAudioPriorityService = 3;
};
} /* namespace android */