audio: several concurrent capture fixes
Make sure AudioRecord clients are invalidated synchronously
when closing an input stream instead of when the capture thread
exits.
Fix AudioPolicyManager::getInputForDevice() logic to make sure that
not only the first opened input encountered is considered when looking
for a compatible input to reuse for concurrent capture.
Bug: 22702906
Test: run CTS test
Change-Id: I7f69609d4ee70a37ab06753ff970b12df17d885b
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index a1d81f9..b42bd05 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -5976,6 +5976,18 @@
run(mThreadName, PRIORITY_URGENT_AUDIO);
}
+void AudioFlinger::RecordThread::preExit()
+{
+ ALOGV(" preExit()");
+ Mutex::Autolock _l(mLock);
+ for (size_t i = 0; i < mTracks.size(); i++) {
+ sp<RecordTrack> track = mTracks[i];
+ track->invalidate();
+ }
+ mActiveTracks.clear();
+ mStartStopCond.broadcast();
+}
+
bool AudioFlinger::RecordThread::threadLoop()
{
nsecs_t lastWarning = 0;
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 3fb0b07..9d0c32c 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -1346,6 +1346,7 @@
// Thread virtuals
virtual bool threadLoop();
+ virtual void preExit();
// RefBase
virtual void onFirstRef();
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 564ed56..edbff1b 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1631,8 +1631,8 @@
isSoundTrigger,
policyMix, mpClientInterface);
-
// reuse an open input if possible
+ sp<AudioInputDescriptor> reusedInputDesc;
for (size_t i = 0; i < mInputs.size(); i++) {
sp<AudioInputDescriptor> desc = mInputs.valueAt(i);
// reuse input if:
@@ -1656,28 +1656,27 @@
} else {
ALOGW("getInputForDevice() record with different attributes"
" exists for session %d", session);
- break;
+ continue;
}
} else if (isSoundTrigger) {
- break;
+ continue;
}
- // force close input if current source is now the highest priority request on this input
- // and current input properties are not exactly as requested.
- if (!isConcurrentSource(inputSource) && !isConcurrentSource(desc->inputSource()) &&
+ // Reuse the already opened input stream on this profile if:
+ // - the new capture source is background OR
+ // - the path requested configurations match OR
+ // - the new source priority is less than the highest source priority on this input
+ // If the input stream cannot be reused, close it before opening a new stream
+ // on the same profile for the new client so that the requested path configuration
+ // can be selected.
+ if (!isConcurrentSource(inputSource) &&
((desc->mSamplingRate != samplingRate ||
desc->mChannelMask != channelMask ||
!audio_formats_match(desc->mFormat, format)) &&
(source_priority(desc->getHighestPrioritySource(false /*activeOnly*/)) <
source_priority(inputSource)))) {
- ALOGV("%s: ", __FUNCTION__);
- AudioSessionCollection sessions = desc->getAudioSessions(false /*activeOnly*/);
- for (size_t j = 0; j < sessions.size(); j++) {
- audio_session_t currentSession = sessions.keyAt(j);
- stopInput(desc->mIoHandle, currentSession);
- releaseInput(desc->mIoHandle, currentSession);
- }
- break;
+ reusedInputDesc = desc;
+ continue;
} else {
desc->addAudioSession(session, audioSession);
ALOGV("%s: reusing input %d", __FUNCTION__, mInputs.keyAt(i));
@@ -1686,6 +1685,15 @@
}
}
+ if (reusedInputDesc != 0) {
+ AudioSessionCollection sessions = reusedInputDesc->getAudioSessions(false /*activeOnly*/);
+ for (size_t j = 0; j < sessions.size(); j++) {
+ audio_session_t currentSession = sessions.keyAt(j);
+ stopInput(reusedInputDesc->mIoHandle, currentSession);
+ releaseInput(reusedInputDesc->mIoHandle, currentSession);
+ }
+ }
+
audio_config_t config = AUDIO_CONFIG_INITIALIZER;
config.sample_rate = profileSamplingRate;
config.channel_mask = profileChannelMask;