summaryrefslogtreecommitdiffstats
path: root/services/audiopolicy
diff options
context:
space:
mode:
authorRicardo Cerqueira <ricardo@cyngn.com>2015-11-05 01:41:03 +0000
committerRicardo Cerqueira <ricardo@cyngn.com>2015-11-05 15:12:16 +0000
commitd5d618443b0166393389b422892ec033825e57ce (patch)
treead66ae383f72046ed6805b570450ae78709df3aa /services/audiopolicy
parent2848080cc0182847cb2130cba1a59282db88bce0 (diff)
parentf733ab6e153fb89f045bfb1cb2746bd58399a0c2 (diff)
downloadframeworks_av-d5d618443b0166393389b422892ec033825e57ce.zip
frameworks_av-d5d618443b0166393389b422892ec033825e57ce.tar.gz
frameworks_av-d5d618443b0166393389b422892ec033825e57ce.tar.bz2
Merge tag 'android-6.0.0_r26' into cm-13.0
Android 6.0.0 release 26 Change-Id: I8a57007bf6efcd8b95c3cebf5e0444345bdd4cda
Diffstat (limited to 'services/audiopolicy')
-rw-r--r--services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h12
-rw-r--r--services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp20
-rw-r--r--services/audiopolicy/enginedefault/src/Gains.cpp8
-rw-r--r--services/audiopolicy/managerdefault/AudioPolicyManager.cpp33
-rw-r--r--services/audiopolicy/managerdefault/AudioPolicyManager.h1
-rw-r--r--services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp6
-rw-r--r--services/audiopolicy/service/AudioPolicyService.cpp24
7 files changed, 85 insertions, 19 deletions
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<AudioPort> getAudioPort() const { return mProfile; }
void toAudioPort(struct audio_port *port) const;
+ void setPreemptedSessions(const SortedVector<audio_session_t>& sessions);
+ SortedVector<audio_session_t> 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<audio_session_t> 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<audio_session_t>& sessions)
+{
+ mPreemptedSessions = sessions;
+}
+
+SortedVector<audio_session_t> 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/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
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 483855f..acdd23d 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1074,7 +1074,7 @@ status_t AudioPolicyManager::startSource(sp<AudioOutputDescriptor> 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);
@@ -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<AudioInputDescriptor> 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<audio_session_t> 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;
}
@@ -1718,7 +1724,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);
}
@@ -2007,6 +2015,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"));
@@ -2687,7 +2698,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) {
@@ -2744,6 +2756,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;
@@ -4043,6 +4058,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 80c41c8..c40a435 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
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;
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index d689065..41dd40c 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
@@ -1005,6 +1011,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();
}