From 9459fb087c97c3cad66221821eb32755fdb9c9f5 Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Wed, 12 Aug 2015 18:36:32 -0700 Subject: audio policy: refine TTS stream mute management Do not mute the TTS stream if a dedicated output for TTS is available. Bug: 22100304. Change-Id: Ic126100ce1144f765bc0ae42c8ea87fa47cfb822 --- .../audiopolicy/managerdefault/AudioPolicyManager.cpp | 17 +++++++++++++++-- .../audiopolicy/managerdefault/AudioPolicyManager.h | 1 + 2 files changed, 16 insertions(+), 2 deletions(-) (limited to 'services/audiopolicy') diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp index fc27789..3e6df38 100644 --- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp +++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp @@ -1066,7 +1066,7 @@ status_t AudioPolicyManager::startSource(sp outputDesc, *delayMs = 0; if (stream == AUDIO_STREAM_TTS) { ALOGV("\t found BEACON stream"); - if (mOutputs.isAnyOutputActive(AUDIO_STREAM_TTS /*streamToIgnore*/)) { + if (!mTtsOutputAvailable && mOutputs.isAnyOutputActive(AUDIO_STREAM_TTS /*streamToIgnore*/)) { return INVALID_OPERATION; } else { beaconMuteLatency = handleEventForBeacon(STARTING_BEACON); @@ -1998,6 +1998,9 @@ status_t AudioPolicyManager::dump(int fd) snprintf(buffer, SIZE, " Force use for hdmi system audio %d\n", mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_HDMI_SYSTEM_AUDIO)); result.append(buffer); + snprintf(buffer, SIZE, " TTS output %s\n", mTtsOutputAvailable ? "available" : "not available"); + result.append(buffer); + write(fd, result.string(), result.size()); mAvailableOutputDevices.dump(fd, String8("output")); @@ -2678,7 +2681,8 @@ AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterfa mAudioPortGeneration(1), mBeaconMuteRefCount(0), mBeaconPlayingRefCount(0), - mBeaconMuted(false) + mBeaconMuted(false), + mTtsOutputAvailable(false) { audio_policy::EngineInstance *engineInstance = audio_policy::EngineInstance::getInstance(); if (!engineInstance) { @@ -2735,6 +2739,9 @@ AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterfa ALOGW("Output profile contains no device on module %s", mHwModules[i]->mName); continue; } + if ((outProfile->mFlags & AUDIO_OUTPUT_FLAG_TTS) != 0) { + mTtsOutputAvailable = true; + } if ((outProfile->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) != 0) { continue; @@ -4034,6 +4041,12 @@ void AudioPolicyManager::handleNotificationRoutingForStream(audio_stream_type_t } uint32_t AudioPolicyManager::handleEventForBeacon(int event) { + + // skip beacon mute management if a dedicated TTS output is available + if (mTtsOutputAvailable) { + return 0; + } + switch(event) { case STARTING_OUTPUT: mBeaconMuteRefCount++; diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h index bf3ae4a..bbdf396 100644 --- a/services/audiopolicy/managerdefault/AudioPolicyManager.h +++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h @@ -548,6 +548,7 @@ protected: uint32_t mBeaconMuteRefCount; // ref count for stream that would mute beacon uint32_t mBeaconPlayingRefCount;// ref count for the playing beacon streams bool mBeaconMuted; // has STREAM_TTS been muted + bool mTtsOutputAvailable; // true if a dedicated output for TTS stream is available AudioPolicyMixCollection mPolicyMixes; // list of registered mixes -- cgit v1.1 From b9017af21e097ef12867e0d4b72c432579f29674 Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Thu, 10 Sep 2015 18:38:08 -0700 Subject: Force fixed volume for TTS stream Always play Transmitted Through Speaker stream at max volume instead of tracking media stream volume. Bug: 23729461. Change-Id: I61021f59617bb851a4cd7da80924e587029e96a3 --- services/audiopolicy/enginedefault/src/Gains.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'services/audiopolicy') diff --git a/services/audiopolicy/enginedefault/src/Gains.cpp b/services/audiopolicy/enginedefault/src/Gains.cpp index 78f2909..d06365c 100644 --- a/services/audiopolicy/enginedefault/src/Gains.cpp +++ b/services/audiopolicy/enginedefault/src/Gains.cpp @@ -171,10 +171,10 @@ const VolumeCurvePoint *Gains::sVolumeProfiles[AUDIO_STREAM_CNT] }, { // AUDIO_STREAM_TTS // "Transmitted Through Speaker": always silent except on DEVICE_CATEGORY_SPEAKER - Gains::sSilentVolumeCurve, // DEVICE_CATEGORY_HEADSET - Gains::sLinearVolumeCurve, // DEVICE_CATEGORY_SPEAKER - Gains::sSilentVolumeCurve, // DEVICE_CATEGORY_EARPIECE - Gains::sSilentVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA + Gains::sSilentVolumeCurve, // DEVICE_CATEGORY_HEADSET + Gains::sFullScaleVolumeCurve, // DEVICE_CATEGORY_SPEAKER + Gains::sSilentVolumeCurve, // DEVICE_CATEGORY_EARPIECE + Gains::sSilentVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA }, { // AUDIO_STREAM_ACCESSIBILITY Gains::sDefaultMediaVolumeCurve, // DEVICE_CATEGORY_HEADSET -- cgit v1.1 From af20bc26704458eac0ddc23f12b637939b0df7a4 Mon Sep 17 00:00:00 2001 From: Jean-Michel Trivi Date: Mon, 14 Sep 2015 16:37:07 -0700 Subject: AudioPolicy: don't always change ACCESSIBILITY volume Only change the volume for AUDIO_STREAM_ACCESSIBILITY when changing the media volume. Bug 23366575 Change-Id: Ic42c726ec4d47615c20500c20e4d43cef159b3c6 --- services/audiopolicy/managerdefault/AudioPolicyManager.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'services/audiopolicy') diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp index b1d7b13..dfb477d 100644 --- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp +++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp @@ -1718,7 +1718,9 @@ status_t AudioPolicyManager::setStreamVolumeIndex(audio_stream_type_t stream, status = volStatus; } } - if ((device == AUDIO_DEVICE_OUT_DEFAULT) || ((curDevice & accessibilityDevice) != 0)) { + if ((accessibilityDevice != AUDIO_DEVICE_NONE) && + ((device == AUDIO_DEVICE_OUT_DEFAULT) || ((curDevice & accessibilityDevice) != 0))) + { status_t volStatus = checkAndSetVolume(AUDIO_STREAM_ACCESSIBILITY, index, desc, curDevice); } -- cgit v1.1 From beb07febdc0cae2f43a2008d3bd06b7bb933b19a Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Wed, 16 Sep 2015 15:49:30 -0700 Subject: audio policy: bind setMode() and setPhoneState() operations No routing operation should be allowed between setMode() and setPhoneState() when starting a call as the audio HAL relies on a precise sequence of mode change and routing change to select the initial audio device for the call. Bug: 24083591. Change-Id: I2d5ef62c11cf7aedc2ec7ca5e5fadd7ac875afbc --- services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'services/audiopolicy') diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp index 793c26a..ca365a5 100644 --- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp +++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp @@ -76,10 +76,14 @@ status_t AudioPolicyService::setPhoneState(audio_mode_t state) ALOGV("setPhoneState()"); + // acquire lock before calling setMode() so that setMode() + setPhoneState() are an atomic + // operation from policy manager standpoint (no other operation (e.g track start or stop) + // can be interleaved). + Mutex::Autolock _l(mLock); + // TODO: check if it is more appropriate to do it in platform specific policy manager AudioSystem::setMode(state); - Mutex::Autolock _l(mLock); mAudioPolicyManager->setPhoneState(state); mPhoneState = state; return NO_ERROR; -- cgit v1.1 From 64265b2fb8f5be63b6c2ad4fcbec9acf74705bc4 Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Fri, 18 Sep 2015 18:32:07 -0700 Subject: audio policy: fix preemtible capture race Because a preemtible capture session can preempt another one, we end up in an endless loop situation were each session is allowed to restart after being preempted, thus preempting the other one which restarts and so on. To avoid this situation, we store which audio session was preempted when a particular input started and prevent preemption of this active input by this session. We also inherit sessions from the preempted input to avoid a 3 way preemption loop etc... Bug: 24007220. Change-Id: I0eab5299440ef3ab9e987635dc9a300cf42f2c79 --- .../include/AudioInputDescriptor.h | 12 ++++++++++++ .../managerdefinitions/src/AudioInputDescriptor.cpp | 20 ++++++++++++++++++++ .../managerdefault/AudioPolicyManager.cpp | 12 +++++++++--- 3 files changed, 41 insertions(+), 3 deletions(-) (limited to 'services/audiopolicy') diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h index 18bcfdb..48d09ed 100644 --- a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h +++ b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h @@ -56,9 +56,21 @@ public: const struct audio_port_config *srcConfig = NULL) const; virtual sp getAudioPort() const { return mProfile; } void toAudioPort(struct audio_port *port) const; + void setPreemptedSessions(const SortedVector& sessions); + SortedVector getPreemptedSessions() const; + bool hasPreemptedSession(audio_session_t session) const; + void clearPreemptedSessions(); private: audio_port_handle_t mId; + // Because a preemtible capture session can preempt another one, we end up in an endless loop + // situation were each session is allowed to restart after being preempted, + // thus preempting the other one which restarts and so on. + // To avoid this situation, we store which audio session was preempted when + // a particular input started and prevent preemption of this active input by this session. + // We also inherit sessions from the preempted input to avoid a 3 way preemption loop etc... + SortedVector mPreemptedSessions; + }; class AudioInputCollection : diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp index 937160b..626fdae 100644 --- a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp +++ b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp @@ -93,6 +93,26 @@ void AudioInputDescriptor::toAudioPort(struct audio_port *port) const port->ext.mix.latency_class = AUDIO_LATENCY_NORMAL; } +void AudioInputDescriptor::setPreemptedSessions(const SortedVector& sessions) +{ + mPreemptedSessions = sessions; +} + +SortedVector AudioInputDescriptor::getPreemptedSessions() const +{ + return mPreemptedSessions; +} + +bool AudioInputDescriptor::hasPreemptedSession(audio_session_t session) const +{ + return (mPreemptedSessions.indexOf(session) >= 0); +} + +void AudioInputDescriptor::clearPreemptedSessions() +{ + mPreemptedSessions.clear(); +} + status_t AudioInputDescriptor::dump(int fd) { const size_t SIZE = 256; diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp index dfb477d..8419ed5 100644 --- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp +++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp @@ -1485,10 +1485,15 @@ status_t AudioPolicyManager::startInput(audio_io_handle_t input, // If the already active input uses AUDIO_SOURCE_HOTWORD then it is closed, // otherwise the active input continues and the new input cannot be started. sp activeDesc = mInputs.valueFor(activeInput); - if (activeDesc->mInputSource == AUDIO_SOURCE_HOTWORD) { + if ((activeDesc->mInputSource == AUDIO_SOURCE_HOTWORD) && + !activeDesc->hasPreemptedSession(session)) { ALOGW("startInput(%d) preempting low-priority input %d", input, activeInput); - stopInput(activeInput, activeDesc->mSessions.itemAt(0)); - releaseInput(activeInput, activeDesc->mSessions.itemAt(0)); + audio_session_t activeSession = activeDesc->mSessions.itemAt(0); + SortedVector sessions = activeDesc->getPreemptedSessions(); + sessions.add(activeSession); + inputDesc->setPreemptedSessions(sessions); + stopInput(activeInput, activeSession); + releaseInput(activeInput, activeSession); } else { ALOGE("startInput(%d) failed: other input %d already started", input, activeInput); return INVALID_OPERATION; @@ -1592,6 +1597,7 @@ status_t AudioPolicyManager::stopInput(audio_io_handle_t input, if (mInputs.activeInputsCount() == 0) { SoundTrigger::setCaptureState(false); } + inputDesc->clearPreemptedSessions(); } return NO_ERROR; } -- cgit v1.1 From 047d97b2d046374e2a25c81a984d9cde23f5d781 Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Wed, 23 Sep 2015 10:25:31 -0700 Subject: AudioPolicyService: fix race in AudioCommandThread Fixe race condition in AudioCommandThread::threadLoop() where a command can be inserted in first position in the queue after the sleep time has been calculated causing a longer delay than expected. Also fix a failure to hold a wake lock while commands are still in the queue. Bug: 22707905. Change-Id: I813626986677bf00106acb37ee20d3dd75d5cf33 --- .../audiopolicy/service/AudioPolicyService.cpp | 24 ++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) (limited to 'services/audiopolicy') diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp index eefff3d..c77cc45 100644 --- a/services/audiopolicy/service/AudioPolicyService.cpp +++ b/services/audiopolicy/service/AudioPolicyService.cpp @@ -577,22 +577,28 @@ bool AudioPolicyService::AudioCommandThread::threadLoop() } } waitTime = INT64_MAX; + // release mLock before releasing strong reference on the service as + // AudioPolicyService destructor calls AudioCommandThread::exit() which + // acquires mLock. + mLock.unlock(); + svc.clear(); + mLock.lock(); } else { waitTime = mAudioCommands[0]->mTime - curTime; break; } } - // release mLock before releasing strong reference on the service as - // AudioPolicyService destructor calls AudioCommandThread::exit() which acquires mLock. - mLock.unlock(); - svc.clear(); - mLock.lock(); - if (!exitPending() && (mAudioCommands.isEmpty() || waitTime != INT64_MAX)) { - // release delayed commands wake lock + + // release delayed commands wake lock if the queue is empty + if (mAudioCommands.isEmpty()) { release_wake_lock(mName.string()); + } + + // At this stage we have either an empty command queue or the first command in the queue + // has a finite delay. So unless we are exiting it is safe to wait. + if (!exitPending()) { ALOGV("AudioCommandThread() going to sleep"); mWaitWorkCV.waitRelative(mLock, waitTime); - ALOGV("AudioCommandThread() waking up"); } } // release delayed commands wake lock before quitting @@ -1003,6 +1009,8 @@ void AudioPolicyService::AudioCommandThread::exit() requestExit(); mWaitWorkCV.signal(); } + // Note that we can call it from the thread loop if all other references have been released + // but it will safely return WOULD_BLOCK in this case requestExitAndWait(); } -- cgit v1.1