Merge "NuPlayerDecoder: check buffer size before memcpy"
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index cb4bcfc..e260fd8 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -1238,18 +1238,18 @@
status_t AudioSystem::startAudioSource(const struct audio_port_config *source,
const audio_attributes_t *attributes,
- audio_patch_handle_t *handle)
+ audio_port_handle_t *portId)
{
const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
if (aps == 0) return PERMISSION_DENIED;
- return aps->startAudioSource(source, attributes, handle);
+ return aps->startAudioSource(source, attributes, portId);
}
-status_t AudioSystem::stopAudioSource(audio_patch_handle_t handle)
+status_t AudioSystem::stopAudioSource(audio_port_handle_t portId)
{
const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
if (aps == 0) return PERMISSION_DENIED;
- return aps->stopAudioSource(handle);
+ return aps->stopAudioSource(portId);
}
status_t AudioSystem::setMasterMono(bool mono)
diff --git a/media/libaudioclient/IAudioPolicyService.cpp b/media/libaudioclient/IAudioPolicyService.cpp
index e229f4c..73a8b74 100644
--- a/media/libaudioclient/IAudioPolicyService.cpp
+++ b/media/libaudioclient/IAudioPolicyService.cpp
@@ -740,11 +740,11 @@
virtual status_t startAudioSource(const struct audio_port_config *source,
const audio_attributes_t *attributes,
- audio_patch_handle_t *handle)
+ audio_port_handle_t *portId)
{
Parcel data, reply;
data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
- if (source == NULL || attributes == NULL || handle == NULL) {
+ if (source == NULL || attributes == NULL || portId == NULL) {
return BAD_VALUE;
}
data.write(source, sizeof(struct audio_port_config));
@@ -757,15 +757,15 @@
if (status != NO_ERROR) {
return status;
}
- *handle = (audio_patch_handle_t)reply.readInt32();
+ *portId = (audio_port_handle_t)reply.readInt32();
return status;
}
- virtual status_t stopAudioSource(audio_patch_handle_t handle)
+ virtual status_t stopAudioSource(audio_port_handle_t portId)
{
Parcel data, reply;
data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
- data.writeInt32(handle);
+ data.writeInt32(portId);
status_t status = remote()->transact(STOP_AUDIO_SOURCE, data, &reply);
if (status != NO_ERROR) {
return status;
@@ -1472,17 +1472,17 @@
audio_attributes_t attributes = {};
data.read(&attributes, sizeof(audio_attributes_t));
sanetizeAudioAttributes(&attributes);
- audio_patch_handle_t handle = AUDIO_PATCH_HANDLE_NONE;
- status_t status = startAudioSource(&source, &attributes, &handle);
+ audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
+ status_t status = startAudioSource(&source, &attributes, &portId);
reply->writeInt32(status);
- reply->writeInt32(handle);
+ reply->writeInt32(portId);
return NO_ERROR;
} break;
case STOP_AUDIO_SOURCE: {
CHECK_INTERFACE(IAudioPolicyService, data, reply);
- audio_patch_handle_t handle = (audio_patch_handle_t) data.readInt32();
- status_t status = stopAudioSource(handle);
+ audio_port_handle_t portId = (audio_port_handle_t) data.readInt32();
+ status_t status = stopAudioSource(portId);
reply->writeInt32(status);
return NO_ERROR;
} break;
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index 10d6e92..adfee8b 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -322,9 +322,9 @@
static status_t registerPolicyMixes(const Vector<AudioMix>& mixes, bool registration);
static status_t startAudioSource(const struct audio_port_config *source,
- const audio_attributes_t *attributes,
- audio_patch_handle_t *handle);
- static status_t stopAudioSource(audio_patch_handle_t handle);
+ const audio_attributes_t *attributes,
+ audio_port_handle_t *portId);
+ static status_t stopAudioSource(audio_port_handle_t portId);
static status_t setMasterMono(bool mono);
static status_t getMasterMono(bool *mono);
diff --git a/media/libaudioclient/include/media/IAudioPolicyService.h b/media/libaudioclient/include/media/IAudioPolicyService.h
index 6c017a3..cdbb876 100644
--- a/media/libaudioclient/include/media/IAudioPolicyService.h
+++ b/media/libaudioclient/include/media/IAudioPolicyService.h
@@ -153,8 +153,8 @@
virtual status_t startAudioSource(const struct audio_port_config *source,
const audio_attributes_t *attributes,
- audio_patch_handle_t *handle) = 0;
- virtual status_t stopAudioSource(audio_patch_handle_t handle) = 0;
+ audio_port_handle_t *portId) = 0;
+ virtual status_t stopAudioSource(audio_port_handle_t portId) = 0;
virtual status_t setMasterMono(bool mono) = 0;
virtual status_t getMasterMono(bool *mono) = 0;
diff --git a/media/libaudioprocessing/AudioMixer.cpp b/media/libaudioprocessing/AudioMixer.cpp
index f6f817a..f3ea826 100644
--- a/media/libaudioprocessing/AudioMixer.cpp
+++ b/media/libaudioprocessing/AudioMixer.cpp
@@ -875,7 +875,7 @@
t->hook = Track::getTrackHook(TRACKTYPE_RESAMPLE, t->mMixerChannelCount,
t->mMixerInFormat, t->mMixerFormat);
ALOGV_IF((n & NEEDS_CHANNEL_COUNT__MASK) > NEEDS_CHANNEL_2,
- "Track %d needs downmix + resample", i);
+ "Track %d needs downmix + resample", name);
} else {
if ((n & NEEDS_CHANNEL_COUNT__MASK) == NEEDS_CHANNEL_1){
t->hook = Track::getTrackHook(
@@ -890,7 +890,7 @@
t->hook = Track::getTrackHook(TRACKTYPE_NORESAMPLE, t->mMixerChannelCount,
t->mMixerInFormat, t->mMixerFormat);
ALOGV_IF((n & NEEDS_CHANNEL_COUNT__MASK) > NEEDS_CHANNEL_2,
- "Track %d needs downmix", i);
+ "Track %d needs downmix", name);
}
}
}
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index db37021..41f5db0 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -217,6 +217,7 @@
mNumFramesReceived(0),
mLastFrameTimestampUs(0),
mStarted(false),
+ mEos(false),
mNumFramesEncoded(0),
mTimeBetweenFrameCaptureUs(0),
mFirstFrameTimeUs(0),
@@ -880,6 +881,7 @@
{
Mutex::Autolock autoLock(mLock);
mStarted = false;
+ mEos = false;
mStopSystemTimeUs = -1;
mFrameAvailableCondition.signal();
@@ -1075,7 +1077,7 @@
{
Mutex::Autolock autoLock(mLock);
- while (mStarted && mFramesReceived.empty()) {
+ while (mStarted && !mEos && mFramesReceived.empty()) {
if (NO_ERROR !=
mFrameAvailableCondition.waitRelative(mLock,
mTimeBetweenFrameCaptureUs * 1000LL + CAMERA_SOURCE_TIMEOUT_NS)) {
@@ -1091,6 +1093,9 @@
if (!mStarted) {
return OK;
}
+ if (mFramesReceived.empty()) {
+ return ERROR_END_OF_STREAM;
+ }
frame = *mFramesReceived.begin();
mFramesReceived.erase(mFramesReceived.begin());
@@ -1129,6 +1134,8 @@
if (mStopSystemTimeUs != -1 && timestampUs >= mStopSystemTimeUs) {
ALOGV("Drop Camera frame at %lld stop time: %lld us",
(long long)timestampUs, (long long)mStopSystemTimeUs);
+ mEos = true;
+ mFrameAvailableCondition.signal();
return true;
}
diff --git a/media/libstagefright/VideoFrameScheduler.cpp b/media/libstagefright/VideoFrameScheduler.cpp
index 6819bba..9020fc1 100644
--- a/media/libstagefright/VideoFrameScheduler.cpp
+++ b/media/libstagefright/VideoFrameScheduler.cpp
@@ -475,7 +475,16 @@
nextVsyncTime += mVsyncPeriod;
if (vsyncsForLastFrame < ULONG_MAX)
++vsyncsForLastFrame;
+ } else if (mTimeCorrection < -correctionLimit * 2
+ || mTimeCorrection > correctionLimit * 2) {
+ ALOGW("correction beyond limit: %lld vs %lld (vsyncs for last frame: %zu, min: %zu)"
+ " restarting. render=%lld",
+ (long long)mTimeCorrection, (long long)correctionLimit,
+ vsyncsForLastFrame, minVsyncsPerFrame, (long long)origRenderTime);
+ restart();
+ return origRenderTime;
}
+
ATRACE_INT("FRAME_VSYNCS", vsyncsForLastFrame);
}
mLastVsyncTime = nextVsyncTime;
diff --git a/media/libstagefright/include/media/stagefright/CameraSource.h b/media/libstagefright/include/media/stagefright/CameraSource.h
index 475976b..3037b72 100644
--- a/media/libstagefright/include/media/stagefright/CameraSource.h
+++ b/media/libstagefright/include/media/stagefright/CameraSource.h
@@ -204,6 +204,7 @@
int32_t mNumFramesReceived;
int64_t mLastFrameTimestampUs;
bool mStarted;
+ bool mEos;
int32_t mNumFramesEncoded;
// Time between capture of two frames.
diff --git a/services/audioflinger/Configuration.h b/services/audioflinger/Configuration.h
index 64bb426..34cd821 100644
--- a/services/audioflinger/Configuration.h
+++ b/services/audioflinger/Configuration.h
@@ -27,7 +27,7 @@
//#define AUDIO_WATCHDOG
// uncomment to display CPU load adjusted for CPU frequency
-#define CPU_FREQUENCY_STATISTICS
+//define CPU_FREQUENCY_STATISTICS
// uncomment to enable fast threads to take performance samples for later statistical analysis
#define FAST_THREAD_STATISTICS
diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp
index ad35264..a42d6b3 100644
--- a/services/audioflinger/FastMixer.cpp
+++ b/services/audioflinger/FastMixer.cpp
@@ -32,7 +32,7 @@
#include <utils/Trace.h>
#include <system/audio.h>
#ifdef FAST_THREAD_STATISTICS
-#include <cpustats/CentralTendencyStatistics.h>
+#include <audio_utils/Statistics.h>
#ifdef CPU_FREQUENCY_STATISTICS
#include <cpustats/ThreadCpuUsage.h>
#endif
diff --git a/services/audioflinger/FastMixerDumpState.cpp b/services/audioflinger/FastMixerDumpState.cpp
index c0f9f0f..ffdc117 100644
--- a/services/audioflinger/FastMixerDumpState.cpp
+++ b/services/audioflinger/FastMixerDumpState.cpp
@@ -19,7 +19,7 @@
#include "Configuration.h"
#ifdef FAST_THREAD_STATISTICS
-#include <cpustats/CentralTendencyStatistics.h>
+#include <audio_utils/Statistics.h>
#ifdef CPU_FREQUENCY_STATISTICS
#include <cpustats/ThreadCpuUsage.h>
#endif
@@ -92,9 +92,9 @@
}
// statistics for monotonic (wall clock) time, thread raw CPU load in time, CPU clock frequency,
// and adjusted CPU load in MHz normalized for CPU clock frequency
- CentralTendencyStatistics wall, loadNs;
+ Statistics<double> wall, loadNs;
#ifdef CPU_FREQUENCY_STATISTICS
- CentralTendencyStatistics kHz, loadMHz;
+ Statistics<double> kHz, loadMHz;
uint32_t previousCpukHz = 0;
#endif
// Assuming a normal distribution for cycle times, three standard deviations on either side of
@@ -109,18 +109,18 @@
if (tail != NULL) {
tail[j] = wallNs;
}
- wall.sample(wallNs);
+ wall.add(wallNs);
uint32_t sampleLoadNs = mLoadNs[i];
- loadNs.sample(sampleLoadNs);
+ loadNs.add(sampleLoadNs);
#ifdef CPU_FREQUENCY_STATISTICS
uint32_t sampleCpukHz = mCpukHz[i];
// skip bad kHz samples
if ((sampleCpukHz & ~0xF) != 0) {
- kHz.sample(sampleCpukHz >> 4);
+ kHz.add(sampleCpukHz >> 4);
if (sampleCpukHz == previousCpukHz) {
double megacycles = (double) sampleLoadNs * (double) (sampleCpukHz >> 4) * 1e-12;
double adjMHz = megacycles / mixPeriodSec; // _not_ wallNs * 1e9
- loadMHz.sample(adjMHz);
+ loadMHz.add(adjMHz);
}
}
previousCpukHz = sampleCpukHz;
@@ -128,42 +128,42 @@
}
if (n) {
dprintf(fd, " Simple moving statistics over last %.1f seconds:\n",
- wall.n() * mixPeriodSec);
+ wall.getN() * mixPeriodSec);
dprintf(fd, " wall clock time in ms per mix cycle:\n"
" mean=%.2f min=%.2f max=%.2f stddev=%.2f\n",
- wall.mean()*1e-6, wall.minimum()*1e-6, wall.maximum()*1e-6,
- wall.stddev()*1e-6);
+ wall.getMean()*1e-6, wall.getMin()*1e-6, wall.getMax()*1e-6,
+ wall.getStdDev()*1e-6);
dprintf(fd, " raw CPU load in us per mix cycle:\n"
" mean=%.0f min=%.0f max=%.0f stddev=%.0f\n",
- loadNs.mean()*1e-3, loadNs.minimum()*1e-3, loadNs.maximum()*1e-3,
- loadNs.stddev()*1e-3);
+ loadNs.getMean()*1e-3, loadNs.getMin()*1e-3, loadNs.getMax()*1e-3,
+ loadNs.getStdDev()*1e-3);
} else {
dprintf(fd, " No FastMixer statistics available currently\n");
}
#ifdef CPU_FREQUENCY_STATISTICS
dprintf(fd, " CPU clock frequency in MHz:\n"
" mean=%.0f min=%.0f max=%.0f stddev=%.0f\n",
- kHz.mean()*1e-3, kHz.minimum()*1e-3, kHz.maximum()*1e-3, kHz.stddev()*1e-3);
+ kHz.getMean()*1e-3, kHz.getMin()*1e-3, kHz.getMax()*1e-3, kHz.getStdDev()*1e-3);
dprintf(fd, " adjusted CPU load in MHz (i.e. normalized for CPU clock frequency):\n"
" mean=%.1f min=%.1f max=%.1f stddev=%.1f\n",
- loadMHz.mean(), loadMHz.minimum(), loadMHz.maximum(), loadMHz.stddev());
+ loadMHz.getMean(), loadMHz.getMin(), loadMHz.getMax(), loadMHz.getStdDev());
#endif
if (tail != NULL) {
qsort(tail, n, sizeof(uint32_t), compare_uint32_t);
// assume same number of tail samples on each side, left and right
uint32_t count = n / kTailDenominator;
- CentralTendencyStatistics left, right;
+ Statistics<double> left, right;
for (uint32_t i = 0; i < count; ++i) {
- left.sample(tail[i]);
- right.sample(tail[n - (i + 1)]);
+ left.add(tail[i]);
+ right.add(tail[n - (i + 1)]);
}
dprintf(fd, " Distribution of mix cycle times in ms for the tails "
"(> ~3 stddev outliers):\n"
" left tail: mean=%.2f min=%.2f max=%.2f stddev=%.2f\n"
" right tail: mean=%.2f min=%.2f max=%.2f stddev=%.2f\n",
- left.mean()*1e-6, left.minimum()*1e-6, left.maximum()*1e-6, left.stddev()*1e-6,
- right.mean()*1e-6, right.minimum()*1e-6, right.maximum()*1e-6,
- right.stddev()*1e-6);
+ left.getMean()*1e-6, left.getMin()*1e-6, left.getMax()*1e-6, left.getStdDev()*1e-6,
+ right.getMean()*1e-6, right.getMin()*1e-6, right.getMax()*1e-6,
+ right.getStdDev()*1e-6);
delete[] tail;
}
#endif
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index d55da1b..6c7179e 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -73,7 +73,7 @@
#endif
#ifdef DEBUG_CPU_USAGE
-#include <cpustats/CentralTendencyStatistics.h>
+#include <audio_utils/Statistics.h>
#include <cpustats/ThreadCpuUsage.h>
#endif
@@ -335,9 +335,9 @@
#ifdef DEBUG_CPU_USAGE
private:
ThreadCpuUsage mCpuUsage; // instantaneous thread CPU usage in wall clock ns
- CentralTendencyStatistics mWcStats; // statistics on thread CPU usage in wall clock ns
+ Statistics<double> mWcStats; // statistics on thread CPU usage in wall clock ns
- CentralTendencyStatistics mHzStats; // statistics on thread CPU usage in cycles
+ Statistics<double> mHzStats; // statistics on thread CPU usage in cycles
int mCpuNum; // thread's current CPU number
int mCpukHz; // frequency of thread's current CPU in kHz
@@ -363,7 +363,7 @@
// record sample for wall clock statistics
if (valid) {
- mWcStats.sample(wcNs);
+ mWcStats.add(wcNs);
}
// get the current CPU number
@@ -382,26 +382,26 @@
// if no change in CPU number or frequency, then record sample for cycle statistics
if (valid && mCpukHz > 0) {
- double cycles = wcNs * cpukHz * 0.000001;
- mHzStats.sample(cycles);
+ const double cycles = wcNs * cpukHz * 0.000001;
+ mHzStats.add(cycles);
}
- unsigned n = mWcStats.n();
+ const unsigned n = mWcStats.getN();
// mCpuUsage.elapsed() is expensive, so don't call it every loop
if ((n & 127) == 1) {
- long long elapsed = mCpuUsage.elapsed();
+ const long long elapsed = mCpuUsage.elapsed();
if (elapsed >= DEBUG_CPU_USAGE * 1000000000LL) {
- double perLoop = elapsed / (double) n;
- double perLoop100 = perLoop * 0.01;
- double perLoop1k = perLoop * 0.001;
- double mean = mWcStats.mean();
- double stddev = mWcStats.stddev();
- double minimum = mWcStats.minimum();
- double maximum = mWcStats.maximum();
- double meanCycles = mHzStats.mean();
- double stddevCycles = mHzStats.stddev();
- double minCycles = mHzStats.minimum();
- double maxCycles = mHzStats.maximum();
+ const double perLoop = elapsed / (double) n;
+ const double perLoop100 = perLoop * 0.01;
+ const double perLoop1k = perLoop * 0.001;
+ const double mean = mWcStats.getMean();
+ const double stddev = mWcStats.getStdDev();
+ const double minimum = mWcStats.getMin();
+ const double maximum = mWcStats.getMax();
+ const double meanCycles = mHzStats.getMean();
+ const double stddevCycles = mHzStats.getStdDev();
+ const double minCycles = mHzStats.getMin();
+ const double maxCycles = mHzStats.getMax();
mCpuUsage.resetElapsed();
mWcStats.reset();
mHzStats.reset();
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index c9e99d5..d4c49d9 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -226,9 +226,9 @@
virtual status_t startAudioSource(const struct audio_port_config *source,
const audio_attributes_t *attributes,
- audio_patch_handle_t *handle,
+ audio_port_handle_t *portId,
uid_t uid) = 0;
- virtual status_t stopAudioSource(audio_patch_handle_t handle) = 0;
+ virtual status_t stopAudioSource(audio_port_handle_t portId) = 0;
virtual status_t setMasterMono(bool mono) = 0;
virtual status_t getMasterMono(bool *mono) = 0;
diff --git a/services/audiopolicy/common/managerdefinitions/Android.mk b/services/audiopolicy/common/managerdefinitions/Android.mk
index 09dbb32..9b8f095 100644
--- a/services/audiopolicy/common/managerdefinitions/Android.mk
+++ b/services/audiopolicy/common/managerdefinitions/Android.mk
@@ -18,7 +18,6 @@
src/EffectDescriptor.cpp \
src/SoundTriggerSession.cpp \
src/SessionRoute.cpp \
- src/AudioSourceDescriptor.cpp \
src/VolumeCurve.cpp \
src/TypeConverter.cpp \
src/AudioSession.cpp \
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
index e6112bf..ff0201a 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
@@ -24,7 +24,6 @@
#include <RoutingStrategy.h>
#include "AudioIODescriptorInterface.h"
#include "AudioPort.h"
-#include "AudioSourceDescriptor.h"
#include "ClientDescriptor.h"
namespace android {
@@ -159,7 +158,7 @@
class HwAudioOutputDescriptor: public AudioOutputDescriptor
{
public:
- HwAudioOutputDescriptor(const sp<AudioSourceDescriptor>& source,
+ HwAudioOutputDescriptor(const sp<SourceClientDescriptor>& source,
AudioPolicyClientInterface *clientInterface);
virtual ~HwAudioOutputDescriptor() {}
@@ -176,7 +175,7 @@
const struct audio_port_config *srcConfig = NULL) const;
virtual void toAudioPort(struct audio_port *port) const;
- const sp<AudioSourceDescriptor> mSource;
+ const sp<SourceClientDescriptor> mSource;
};
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioProfile.h b/services/audiopolicy/common/managerdefinitions/include/AudioProfile.h
index 31c75a4..a1ee708 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioProfile.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioProfile.h
@@ -16,6 +16,8 @@
#pragma once
+#include <vector>
+
#include <system/audio.h>
#include <utils/RefBase.h>
#include <utils/SortedVector.h>
@@ -139,6 +141,16 @@
audio_port_type_t portType,
audio_port_role_t portRole) const;
void clearProfiles();
+ // Assuming that this profile vector contains input profiles,
+ // find the best matching config from 'outputProfiles', according to
+ // the given preferences for audio formats and channel masks.
+ // Note: std::vectors are used because specialized containers for formats
+ // and channels can be sorted and use their own ordering.
+ status_t findBestMatchingOutputConfig(const AudioProfileVector& outputProfiles,
+ const std::vector<audio_format_t>& preferredFormats, // order: most pref -> least pref
+ const std::vector<audio_channel_mask_t>& preferredOutputChannels,
+ bool preferHigherSamplingRates,
+ audio_config_base *bestOutputConfig) const;
sp<AudioProfile> getFirstValidProfile() const;
sp<AudioProfile> getFirstValidProfileFor(audio_format_t format) const;
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioSourceDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioSourceDescriptor.h
deleted file mode 100644
index 0d90f42..0000000
--- a/services/audiopolicy/common/managerdefinitions/include/AudioSourceDescriptor.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <system/audio.h>
-#include <utils/Errors.h>
-#include <utils/KeyedVector.h>
-#include <utils/RefBase.h>
-#include <RoutingStrategy.h>
-#include <AudioPatch.h>
-
-namespace android {
-
-class SwAudioOutputDescriptor;
-class HwAudioOutputDescriptor;
-class DeviceDescriptor;
-
-class AudioSourceDescriptor: public RefBase
-{
-public:
- AudioSourceDescriptor(const sp<DeviceDescriptor> device, const audio_attributes_t *attributes,
- uid_t uid) :
- mDevice(device), mAttributes(*attributes), mUid(uid) {}
- virtual ~AudioSourceDescriptor() {}
-
- audio_patch_handle_t getHandle() const { return mPatchDesc->mHandle; }
-
- status_t dump(int fd);
-
- const sp<DeviceDescriptor> mDevice;
- const audio_attributes_t mAttributes;
- uid_t mUid;
- sp<AudioPatch> mPatchDesc;
- wp<SwAudioOutputDescriptor> mSwOutput;
- wp<HwAudioOutputDescriptor> mHwOutput;
-};
-
-class AudioSourceCollection :
- public DefaultKeyedVector< audio_patch_handle_t, sp<AudioSourceDescriptor> >
-{
-public:
- status_t dump(int fd) const;
-};
-
-} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
index 221c2e9..9efe57f 100644
--- a/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
@@ -23,11 +23,17 @@
#include <system/audio.h>
#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
#include <utils/RefBase.h>
#include <utils/String8.h>
+#include "AudioPatch.h"
namespace android {
+class DeviceDescriptor;
+class HwAudioOutputDescriptor;
+class SwAudioOutputDescriptor;
+
class ClientDescriptor: public RefBase
{
public:
@@ -58,6 +64,10 @@
const audio_config_base_t mConfig;
const audio_port_handle_t mPreferredDeviceId; // selected input device port ID
bool mActive;
+
+protected:
+ // FIXME: use until other descriptor classes have a dump to String8 method
+ int mDumpFd;
};
class TrackClientDescriptor: public ClientDescriptor
@@ -104,6 +114,38 @@
const audio_input_flags_t mFlags;
};
+class SourceClientDescriptor: public TrackClientDescriptor
+{
+public:
+ SourceClientDescriptor(audio_port_handle_t portId, uid_t uid, audio_attributes_t attributes,
+ const sp<AudioPatch>& patchDesc, const sp<DeviceDescriptor>& srcDevice,
+ audio_stream_type_t stream);
+ ~SourceClientDescriptor() override = default;
+
+ sp<AudioPatch> patchDesc() const { return mPatchDesc; }
+ sp<DeviceDescriptor> srcDevice() const { return mSrcDevice; };
+ wp<SwAudioOutputDescriptor> swOutput() const { return mSwOutput; }
+ void setSwOutput(const sp<SwAudioOutputDescriptor>& swOutput);
+ wp<HwAudioOutputDescriptor> hwOutput() const { return mHwOutput; }
+ void setHwOutput(const sp<HwAudioOutputDescriptor>& hwOutput);
+
+ using ClientDescriptor::dump;
+ status_t dump(String8& dst, int spaces, int index) override;
+
+ private:
+ const sp<AudioPatch> mPatchDesc;
+ const sp<DeviceDescriptor> mSrcDevice;
+ wp<SwAudioOutputDescriptor> mSwOutput;
+ wp<HwAudioOutputDescriptor> mHwOutput;
+};
+
+class SourceClientCollection :
+ public DefaultKeyedVector< audio_port_handle_t, sp<SourceClientDescriptor> >
+{
+public:
+ status_t dump(int fd) const;
+};
+
typedef std::vector< sp<TrackClientDescriptor> > TrackClientVector;
typedef std::map< audio_port_handle_t, sp<TrackClientDescriptor> > TrackClientMap;
typedef std::vector< sp<RecordClientDescriptor> > RecordClientVector;
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index 3dfbe1b..39fce4d 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -558,9 +558,9 @@
}
// HwAudioOutputDescriptor implementation
-HwAudioOutputDescriptor::HwAudioOutputDescriptor(const sp<AudioSourceDescriptor>& source,
+HwAudioOutputDescriptor::HwAudioOutputDescriptor(const sp<SourceClientDescriptor>& source,
AudioPolicyClientInterface *clientInterface)
- : AudioOutputDescriptor(source->mDevice, clientInterface),
+ : AudioOutputDescriptor(source->srcDevice(), clientInterface),
mSource(source)
{
}
@@ -576,7 +576,7 @@
snprintf(buffer, SIZE, "Source:\n");
result.append(buffer);
write(fd, result.string(), result.size());
- mSource->dump(fd);
+ mSource->dump(fd, 0, 0);
return NO_ERROR;
}
@@ -590,13 +590,13 @@
struct audio_port_config *dstConfig,
const struct audio_port_config *srcConfig) const
{
- mSource->mDevice->toAudioPortConfig(dstConfig, srcConfig);
+ mSource->srcDevice()->toAudioPortConfig(dstConfig, srcConfig);
}
void HwAudioOutputDescriptor::toAudioPort(
struct audio_port *port) const
{
- mSource->mDevice->toAudioPort(port);
+ mSource->srcDevice()->toAudioPort(port);
}
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioProfile.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioProfile.cpp
index b76b609..d04beec 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioProfile.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioProfile.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include <algorithm>
+#include <set>
#include <string>
#define LOG_TAG "APM::AudioProfile"
@@ -406,6 +408,76 @@
}
}
+// Returns an intersection between two possibly unsorted vectors and the contents of 'order'.
+// The result is ordered according to 'order'.
+template<typename T, typename Order>
+std::vector<typename T::value_type> intersectFilterAndOrder(
+ const T& input1, const T& input2, const Order& order)
+{
+ std::set<typename T::value_type> set1{input1.begin(), input1.end()};
+ std::set<typename T::value_type> set2{input2.begin(), input2.end()};
+ std::set<typename T::value_type> common;
+ std::set_intersection(set1.begin(), set1.end(), set2.begin(), set2.end(),
+ std::inserter(common, common.begin()));
+ std::vector<typename T::value_type> result;
+ for (const auto& e : order) {
+ if (common.find(e) != common.end()) result.push_back(e);
+ }
+ return result;
+}
+
+// Intersect two possibly unsorted vectors, return common elements according to 'comp' ordering.
+// 'comp' is a comparator function.
+template<typename T, typename Compare>
+std::vector<typename T::value_type> intersectAndOrder(
+ const T& input1, const T& input2, Compare comp)
+{
+ std::set<typename T::value_type, Compare> set1{input1.begin(), input1.end(), comp};
+ std::set<typename T::value_type, Compare> set2{input2.begin(), input2.end(), comp};
+ std::vector<typename T::value_type> result;
+ std::set_intersection(set1.begin(), set1.end(), set2.begin(), set2.end(),
+ std::back_inserter(result), comp);
+ return result;
+}
+
+status_t AudioProfileVector::findBestMatchingOutputConfig(const AudioProfileVector& outputProfiles,
+ const std::vector<audio_format_t>& preferredFormats,
+ const std::vector<audio_channel_mask_t>& preferredOutputChannels,
+ bool preferHigherSamplingRates,
+ audio_config_base *bestOutputConfig) const
+{
+ auto formats = intersectFilterAndOrder(getSupportedFormats(),
+ outputProfiles.getSupportedFormats(), preferredFormats);
+ // Pick the best compatible profile.
+ for (const auto& f : formats) {
+ sp<AudioProfile> inputProfile = getFirstValidProfileFor(f);
+ sp<AudioProfile> outputProfile = outputProfiles.getFirstValidProfileFor(f);
+ if (inputProfile == nullptr || outputProfile == nullptr) {
+ continue;
+ }
+ auto channels = intersectFilterAndOrder(inputProfile->getChannels().asOutMask(),
+ outputProfile->getChannels(), preferredOutputChannels);
+ if (channels.empty()) {
+ continue;
+ }
+ auto sampleRates = preferHigherSamplingRates ?
+ intersectAndOrder(inputProfile->getSampleRates(), outputProfile->getSampleRates(),
+ std::greater<typename SampleRateVector::value_type>()) :
+ intersectAndOrder(inputProfile->getSampleRates(), outputProfile->getSampleRates(),
+ std::less<typename SampleRateVector::value_type>());
+ if (sampleRates.empty()) {
+ continue;
+ }
+ ALOGD("%s() found channel mask %#x and sample rate %d for format %#x.",
+ __func__, *channels.begin(), *sampleRates.begin(), f);
+ bestOutputConfig->format = f;
+ bestOutputConfig->sample_rate = *sampleRates.begin();
+ bestOutputConfig->channel_mask = *channels.begin();
+ return NO_ERROR;
+ }
+ return BAD_VALUE;
+}
+
sp<AudioProfile> AudioProfileVector::getFirstValidProfile() const
{
for (size_t i = 0; i < size(); i++) {
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioSourceDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioSourceDescriptor.cpp
deleted file mode 100644
index ba33e57..0000000
--- a/services/audiopolicy/common/managerdefinitions/src/AudioSourceDescriptor.cpp
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "APM::AudioSourceDescriptor"
-//#define LOG_NDEBUG 0
-
-#include <utils/Log.h>
-#include <utils/String8.h>
-#include <media/AudioPolicyHelper.h>
-#include <HwModule.h>
-#include <AudioGain.h>
-#include <AudioSourceDescriptor.h>
-#include <DeviceDescriptor.h>
-#include <IOProfile.h>
-#include <AudioOutputDescriptor.h>
-
-namespace android {
-
-status_t AudioSourceDescriptor::dump(int fd)
-{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
-
- snprintf(buffer, SIZE, "mStream: %d\n", audio_attributes_to_stream_type(&mAttributes));
- result.append(buffer);
- snprintf(buffer, SIZE, "mDevice:\n");
- result.append(buffer);
- write(fd, result.string(), result.size());
- mDevice->dump(fd, 2 , 0);
- return NO_ERROR;
-}
-
-
-status_t AudioSourceCollection::dump(int fd) const
-{
- const size_t SIZE = 256;
- char buffer[SIZE];
-
- snprintf(buffer, SIZE, "\nAudio sources dump:\n");
- write(fd, buffer, strlen(buffer));
- for (size_t i = 0; i < size(); i++) {
- snprintf(buffer, SIZE, "- Source %d dump:\n", keyAt(i));
- write(fd, buffer, strlen(buffer));
- valueAt(i)->dump(fd);
- }
-
- return NO_ERROR;
-}
-
-}; //namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
index bdc748e..5aca3cc 100644
--- a/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
@@ -19,7 +19,13 @@
#include <utils/Log.h>
#include <utils/String8.h>
+#include "AudioGain.h"
+#include "AudioOutputDescriptor.h"
+#include "AudioPatch.h"
#include "ClientDescriptor.h"
+#include "DeviceDescriptor.h"
+#include "HwModule.h"
+#include "IOProfile.h"
namespace android {
@@ -27,6 +33,9 @@
{
String8 out;
+ // FIXME: use until other descriptor classes have a dump to String8 method
+ mDumpFd = fd;
+
status_t status = dump(out, spaces, index);
if (status == NO_ERROR) {
write(fd, out.string(), out.size());
@@ -65,4 +74,50 @@
return NO_ERROR;
}
+SourceClientDescriptor::SourceClientDescriptor(audio_port_handle_t portId, uid_t uid,
+ audio_attributes_t attributes, const sp<AudioPatch>& patchDesc,
+ const sp<DeviceDescriptor>& srcDevice, audio_stream_type_t stream) :
+ TrackClientDescriptor::TrackClientDescriptor(portId, uid, AUDIO_SESSION_NONE, attributes,
+ AUDIO_CONFIG_BASE_INITIALIZER, AUDIO_PORT_HANDLE_NONE, stream, AUDIO_OUTPUT_FLAG_NONE),
+ mPatchDesc(patchDesc), mSrcDevice(srcDevice)
+{
+}
+
+void SourceClientDescriptor::setSwOutput(const sp<SwAudioOutputDescriptor>& swOutput)
+{
+ mSwOutput = swOutput;
+}
+
+void SourceClientDescriptor::setHwOutput(const sp<HwAudioOutputDescriptor>& hwOutput)
+{
+ mHwOutput = hwOutput;
+}
+
+status_t SourceClientDescriptor::dump(String8& out, int spaces, int index)
+{
+ TrackClientDescriptor::dump(out, spaces, index);
+
+ if (mDumpFd >= 0) {
+ out.appendFormat("%*s- Device:\n", spaces, "");
+ write(mDumpFd, out.string(), out.size());
+
+ mSrcDevice->dump(mDumpFd, 2, 0);
+ mDumpFd = -1;
+ }
+
+ return NO_ERROR;
+}
+
+status_t SourceClientCollection::dump(int fd) const
+{
+ String8 out;
+ out.append("\nAudio sources:\n");
+ write(fd, out.string(), out.size());
+ for (size_t i = 0; i < size(); i++) {
+ valueAt(i)->dump(fd, 2, i);
+ }
+
+ return NO_ERROR;
+}
+
}; //namespace android
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index f343bec..92f6c79 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -31,6 +31,7 @@
#include <inttypes.h>
#include <math.h>
+#include <vector>
#include <AudioPolicyManagerInterface.h>
#include <AudioPolicyEngineInstance.h>
@@ -38,7 +39,6 @@
#include <utils/Log.h>
#include <media/AudioParameter.h>
#include <media/AudioPolicyHelper.h>
-#include <media/PatchBuilder.h>
#include <private/android_filesystem_config.h>
#include <soundtrigger/SoundTrigger.h>
#include <system/audio.h>
@@ -82,6 +82,16 @@
AUDIO_FORMAT_AAC_XHE,
};
+// Compressed formats for MSD module, ordered from most preferred to least preferred.
+static const std::vector<audio_format_t> compressedFormatsOrder = {{
+ AUDIO_FORMAT_MAT_2_1, AUDIO_FORMAT_MAT_2_0, AUDIO_FORMAT_E_AC3,
+ AUDIO_FORMAT_AC3, AUDIO_FORMAT_PCM_16_BIT }};
+// Channel masks for MSD module, 3D > 2D > 1D ordering (most preferred to least preferred).
+static const std::vector<audio_channel_mask_t> surroundChannelMasksOrder = {{
+ AUDIO_CHANNEL_OUT_3POINT1POINT2, AUDIO_CHANNEL_OUT_3POINT0POINT2,
+ AUDIO_CHANNEL_OUT_2POINT1POINT2, AUDIO_CHANNEL_OUT_2POINT0POINT2,
+ AUDIO_CHANNEL_OUT_5POINT1, AUDIO_CHANNEL_OUT_STEREO }};
+
// ----------------------------------------------------------------------------
// AudioPolicyInterface implementation
// ----------------------------------------------------------------------------
@@ -225,6 +235,7 @@
audio_devices_t newDevice = getNewOutputDevice(mPrimaryOutput, false /*fromCache*/);
updateCallRouting(newDevice);
}
+ const audio_devices_t msdOutDevice = getMsdAudioOutDeviceTypes();
for (size_t i = 0; i < mOutputs.size(); i++) {
sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
if ((mEngine->getPhoneState() != AUDIO_MODE_IN_CALL) || (desc != mPrimaryOutput)) {
@@ -232,7 +243,8 @@
// do not force device change on duplicated output because if device is 0, it will
// also force a device 0 for the two outputs it is duplicated to which may override
// a valid device selection on those outputs.
- bool force = !desc->isDuplicated()
+ bool force = (msdOutDevice == AUDIO_DEVICE_NONE || msdOutDevice != desc->device())
+ && !desc->isDuplicated()
&& (!device_distinguishes_on_address(device)
// always force when disconnecting (a non-duplicated device)
|| (state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE));
@@ -525,7 +537,7 @@
}
sp<DeviceDescriptor> AudioPolicyManager::findDevice(
- const DeviceVector& devices, audio_devices_t device) {
+ const DeviceVector& devices, audio_devices_t device) const {
DeviceVector deviceList = devices.getDevicesFromTypeMask(device);
ALOG_ASSERT(!deviceList.isEmpty(),
"%s() selected device type %#x is not in devices list", __func__, device);
@@ -777,6 +789,7 @@
routing_strategy strategy;
audio_devices_t device;
audio_port_handle_t requestedDeviceId = *selectedDeviceId;
+ audio_devices_t msdDevice = getMsdAudioOutDeviceTypes();
if (attr != NULL) {
if (!isValidAttributes(attr)) {
@@ -869,7 +882,20 @@
"flags %#x",
device, config->sample_rate, config->format, config->channel_mask, *flags);
- *output = getOutputForDevice(device, session, *stream, config, flags);
+ *output = AUDIO_IO_HANDLE_NONE;
+ if (msdDevice != AUDIO_DEVICE_NONE) {
+ *output = getOutputForDevice(msdDevice, session, *stream, config, flags);
+ if (*output != AUDIO_IO_HANDLE_NONE && setMsdPatch(device) == NO_ERROR) {
+ ALOGV("%s() Using MSD device 0x%x instead of device 0x%x",
+ __func__, msdDevice, device);
+ device = msdDevice;
+ } else {
+ *output = AUDIO_IO_HANDLE_NONE;
+ }
+ }
+ if (*output == AUDIO_IO_HANDLE_NONE) {
+ *output = getOutputForDevice(device, session, *stream, config, flags);
+ }
if (*output == AUDIO_IO_HANDLE_NONE) {
mOutputRoutes.removeRoute(session);
return INVALID_OPERATION;
@@ -1052,6 +1078,164 @@
return output;
}
+sp<DeviceDescriptor> AudioPolicyManager::getMsdAudioInDevice() const {
+ sp<HwModule> msdModule = mHwModules.getModuleFromName(AUDIO_HARDWARE_MODULE_ID_MSD);
+ if (msdModule != 0) {
+ DeviceVector msdInputDevices = mAvailableInputDevices.getDevicesFromHwModule(
+ msdModule->getHandle());
+ if (!msdInputDevices.isEmpty()) return msdInputDevices.itemAt(0);
+ }
+ return 0;
+}
+
+audio_devices_t AudioPolicyManager::getMsdAudioOutDeviceTypes() const {
+ sp<HwModule> msdModule = mHwModules.getModuleFromName(AUDIO_HARDWARE_MODULE_ID_MSD);
+ if (msdModule != 0) {
+ return mAvailableOutputDevices.getDeviceTypesFromHwModule(msdModule->getHandle());
+ }
+ return AUDIO_DEVICE_NONE;
+}
+
+const AudioPatchCollection AudioPolicyManager::getMsdPatches() const {
+ AudioPatchCollection msdPatches;
+ audio_module_handle_t msdModuleHandle = mHwModules.getModuleFromName(
+ AUDIO_HARDWARE_MODULE_ID_MSD)->getHandle();
+ if (msdModuleHandle == AUDIO_MODULE_HANDLE_NONE) return msdPatches;
+ for (size_t i = 0; i < mAudioPatches.size(); ++i) {
+ sp<AudioPatch> patch = mAudioPatches.valueAt(i);
+ for (size_t j = 0; j < patch->mPatch.num_sources; ++j) {
+ const struct audio_port_config *source = &patch->mPatch.sources[j];
+ if (source->type == AUDIO_PORT_TYPE_DEVICE &&
+ source->ext.device.hw_module == msdModuleHandle) {
+ msdPatches.addAudioPatch(patch->mHandle, patch);
+ }
+ }
+ }
+ return msdPatches;
+}
+
+status_t AudioPolicyManager::getBestMsdAudioProfileFor(audio_devices_t outputDevice,
+ bool hwAvSync, audio_port_config *sourceConfig, audio_port_config *sinkConfig) const
+{
+ sp<HwModule> msdModule = mHwModules.getModuleFromName(AUDIO_HARDWARE_MODULE_ID_MSD);
+ if (msdModule == nullptr) {
+ ALOGE("%s() unable to get MSD module", __func__);
+ return NO_INIT;
+ }
+ sp<HwModule> deviceModule = mHwModules.getModuleForDevice(outputDevice);
+ if (deviceModule == nullptr) {
+ ALOGE("%s() unable to get module for %#x", __func__, outputDevice);
+ return NO_INIT;
+ }
+ const InputProfileCollection &inputProfiles = msdModule->getInputProfiles();
+ if (inputProfiles.isEmpty()) {
+ ALOGE("%s() no input profiles for MSD module", __func__);
+ return NO_INIT;
+ }
+ const OutputProfileCollection &outputProfiles = deviceModule->getOutputProfiles();
+ if (outputProfiles.isEmpty()) {
+ ALOGE("%s() no output profiles for device %#x", __func__, outputDevice);
+ return NO_INIT;
+ }
+ AudioProfileVector msdProfiles;
+ // Each IOProfile represents a MixPort from audio_policy_configuration.xml
+ for (const auto &inProfile : inputProfiles) {
+ if (hwAvSync == ((inProfile->getFlags() & AUDIO_INPUT_FLAG_HW_AV_SYNC) != 0)) {
+ msdProfiles.appendVector(inProfile->getAudioProfiles());
+ }
+ }
+ AudioProfileVector deviceProfiles;
+ for (const auto &outProfile : outputProfiles) {
+ if (hwAvSync == ((outProfile->getFlags() & AUDIO_OUTPUT_FLAG_HW_AV_SYNC) != 0)) {
+ deviceProfiles.appendVector(outProfile->getAudioProfiles());
+ }
+ }
+ struct audio_config_base bestSinkConfig;
+ status_t result = msdProfiles.findBestMatchingOutputConfig(deviceProfiles,
+ compressedFormatsOrder, surroundChannelMasksOrder, true /*preferHigherSamplingRates*/,
+ &bestSinkConfig);
+ if (result != NO_ERROR) {
+ ALOGD("%s() no matching profiles found for device: %#x, hwAvSync: %d",
+ __func__, outputDevice, hwAvSync);
+ return result;
+ }
+ sinkConfig->sample_rate = bestSinkConfig.sample_rate;
+ sinkConfig->channel_mask = bestSinkConfig.channel_mask;
+ sinkConfig->format = bestSinkConfig.format;
+ // For encoded streams force direct flag to prevent downstream mixing.
+ sinkConfig->flags.output = static_cast<audio_output_flags_t>(
+ sinkConfig->flags.output | AUDIO_OUTPUT_FLAG_DIRECT);
+ sourceConfig->sample_rate = bestSinkConfig.sample_rate;
+ // Specify exact channel mask to prevent guessing by bit count in PatchPanel.
+ sourceConfig->channel_mask = audio_channel_mask_out_to_in(bestSinkConfig.channel_mask);
+ sourceConfig->format = bestSinkConfig.format;
+ // Copy input stream directly without any processing (e.g. resampling).
+ sourceConfig->flags.input = static_cast<audio_input_flags_t>(
+ sourceConfig->flags.input | AUDIO_INPUT_FLAG_DIRECT);
+ if (hwAvSync) {
+ sinkConfig->flags.output = static_cast<audio_output_flags_t>(
+ sinkConfig->flags.output | AUDIO_OUTPUT_FLAG_HW_AV_SYNC);
+ sourceConfig->flags.input = static_cast<audio_input_flags_t>(
+ sourceConfig->flags.input | AUDIO_INPUT_FLAG_HW_AV_SYNC);
+ }
+ const unsigned int config_mask = AUDIO_PORT_CONFIG_SAMPLE_RATE |
+ AUDIO_PORT_CONFIG_CHANNEL_MASK | AUDIO_PORT_CONFIG_FORMAT | AUDIO_PORT_CONFIG_FLAGS;
+ sinkConfig->config_mask |= config_mask;
+ sourceConfig->config_mask |= config_mask;
+ return NO_ERROR;
+}
+
+PatchBuilder AudioPolicyManager::buildMsdPatch(audio_devices_t outputDevice) const
+{
+ PatchBuilder patchBuilder;
+ patchBuilder.addSource(getMsdAudioInDevice()).
+ addSink(findDevice(mAvailableOutputDevices, outputDevice));
+ audio_port_config sourceConfig = patchBuilder.patch()->sources[0];
+ audio_port_config sinkConfig = patchBuilder.patch()->sinks[0];
+ // TODO: Figure out whether MSD module has HW_AV_SYNC flag set in the AP config file.
+ // For now, we just forcefully try with HwAvSync first.
+ status_t res = getBestMsdAudioProfileFor(outputDevice, true /*hwAvSync*/,
+ &sourceConfig, &sinkConfig) == NO_ERROR ? NO_ERROR :
+ getBestMsdAudioProfileFor(
+ outputDevice, false /*hwAvSync*/, &sourceConfig, &sinkConfig);
+ if (res == NO_ERROR) {
+ // Found a matching profile for encoded audio. Re-create PatchBuilder with this config.
+ return (PatchBuilder()).addSource(sourceConfig).addSink(sinkConfig);
+ }
+ ALOGV("%s() no matching profile found. Fall through to default PCM patch"
+ " supporting PCM format conversion.", __func__);
+ return patchBuilder;
+}
+
+status_t AudioPolicyManager::setMsdPatch(audio_devices_t outputDevice) {
+ ALOGV("%s() for outputDevice %#x", __func__, outputDevice);
+ if (outputDevice == AUDIO_DEVICE_NONE) {
+ // Use media strategy for unspecified output device. This should only
+ // occur on checkForDeviceAndOutputChanges(). Device connection events may
+ // therefore invalidate explicit routing requests.
+ outputDevice = getDeviceForStrategy(STRATEGY_MEDIA, false /*fromCache*/);
+ }
+ PatchBuilder patchBuilder = buildMsdPatch(outputDevice);
+ const struct audio_patch* patch = patchBuilder.patch();
+ const AudioPatchCollection msdPatches = getMsdPatches();
+ if (!msdPatches.isEmpty()) {
+ LOG_ALWAYS_FATAL_IF(msdPatches.size() > 1,
+ "The current MSD prototype only supports one output patch");
+ sp<AudioPatch> currentPatch = msdPatches.valueAt(0);
+ if (audio_patches_are_equal(¤tPatch->mPatch, patch)) {
+ return NO_ERROR;
+ }
+ releaseAudioPatch(currentPatch->mHandle, mUidCached);
+ }
+ status_t status = installPatch(__func__, -1 /*index*/, nullptr /*patchHandle*/,
+ patch, 0 /*delayMs*/, mUidCached, nullptr /*patchDescPtr*/);
+ ALOGE_IF(status != NO_ERROR, "%s() error %d creating MSD audio patch", __func__, status);
+ ALOGI_IF(status == NO_ERROR, "%s() Patch created from MSD_IN to "
+ "device:%#x (format:%#x channels:%#x samplerate:%d)", __func__, outputDevice,
+ patch->sources[0].format, patch->sources[0].channel_mask, patch->sources[0].sample_rate);
+ return status;
+}
+
audio_io_handle_t AudioPolicyManager::selectOutput(const SortedVector<audio_io_handle_t>& outputs,
audio_output_flags_t flags,
audio_format_t format)
@@ -2610,6 +2794,7 @@
mEffects.dump(fd);
mAudioPatches.dump(fd);
mPolicyMixes.dump(fd);
+ mAudioSources.dump(fd);
return NO_ERROR;
}
@@ -3252,8 +3437,8 @@
void AudioPolicyManager::clearAudioSources(uid_t uid)
{
for (ssize_t i = (ssize_t)mAudioSources.size() - 1; i >= 0; i--) {
- sp<AudioSourceDescriptor> sourceDesc = mAudioSources.valueAt(i);
- if (sourceDesc->mUid == uid) {
+ sp<SourceClientDescriptor> sourceDesc = mAudioSources.valueAt(i);
+ if (sourceDesc->uid() == uid) {
stopAudioSource(mAudioSources.keyAt(i));
}
}
@@ -3271,20 +3456,23 @@
}
status_t AudioPolicyManager::startAudioSource(const struct audio_port_config *source,
- const audio_attributes_t *attributes,
- audio_patch_handle_t *handle,
- uid_t uid)
+ const audio_attributes_t *attributes,
+ audio_port_handle_t *portId,
+ uid_t uid)
{
- ALOGV("%s source %p attributes %p handle %p", __FUNCTION__, source, attributes, handle);
- if (source == NULL || attributes == NULL || handle == NULL) {
+ ALOGV("%s", __FUNCTION__);
+ *portId = AUDIO_PORT_HANDLE_NONE;
+
+ if (source == NULL || attributes == NULL || portId == NULL) {
+ ALOGW("%s invalid argument: source %p attributes %p handle %p",
+ __FUNCTION__, source, attributes, portId);
return BAD_VALUE;
}
- *handle = AUDIO_PATCH_HANDLE_NONE;
-
if (source->role != AUDIO_PORT_ROLE_SOURCE ||
source->type != AUDIO_PORT_TYPE_DEVICE) {
- ALOGV("%s INVALID_OPERATION source->role %d source->type %d", __FUNCTION__, source->role, source->type);
+ ALOGW("%s INVALID_OPERATION source->role %d source->type %d",
+ __FUNCTION__, source->role, source->type);
return INVALID_OPERATION;
}
@@ -3292,34 +3480,37 @@
mAvailableInputDevices.getDevice(source->ext.device.type,
String8(source->ext.device.address));
if (srcDeviceDesc == 0) {
- ALOGV("%s source->ext.device.type %08x not found", __FUNCTION__, source->ext.device.type);
+ ALOGW("%s source->ext.device.type %08x not found", __FUNCTION__, source->ext.device.type);
return BAD_VALUE;
}
- sp<AudioSourceDescriptor> sourceDesc =
- new AudioSourceDescriptor(srcDeviceDesc, attributes, uid);
+
+ *portId = AudioPort::getNextUniqueId();
struct audio_patch dummyPatch = {};
sp<AudioPatch> patchDesc = new AudioPatch(&dummyPatch, uid);
- sourceDesc->mPatchDesc = patchDesc;
+
+ sp<SourceClientDescriptor> sourceDesc =
+ new SourceClientDescriptor(*portId, uid, *attributes, patchDesc, srcDeviceDesc,
+ streamTypefromAttributesInt(attributes));
status_t status = connectAudioSource(sourceDesc);
if (status == NO_ERROR) {
- mAudioSources.add(sourceDesc->getHandle(), sourceDesc);
- *handle = sourceDesc->getHandle();
+ mAudioSources.add(*portId, sourceDesc);
}
return status;
}
-status_t AudioPolicyManager::connectAudioSource(const sp<AudioSourceDescriptor>& sourceDesc)
+status_t AudioPolicyManager::connectAudioSource(const sp<SourceClientDescriptor>& sourceDesc)
{
- ALOGV("%s handle %d", __FUNCTION__, sourceDesc->getHandle());
+ ALOGV("%s handle %d", __FUNCTION__, sourceDesc->portId());
// make sure we only have one patch per source.
disconnectAudioSource(sourceDesc);
- routing_strategy strategy = (routing_strategy) getStrategyForAttr(&sourceDesc->mAttributes);
- audio_stream_type_t stream = streamTypefromAttributesInt(&sourceDesc->mAttributes);
- sp<DeviceDescriptor> srcDeviceDesc = sourceDesc->mDevice;
+ audio_attributes_t attributes = sourceDesc->attributes();
+ routing_strategy strategy = (routing_strategy) getStrategyForAttr(&attributes);
+ audio_stream_type_t stream = sourceDesc->stream();
+ sp<DeviceDescriptor> srcDeviceDesc = sourceDesc->srcDevice();
audio_devices_t sinkDevice = getDeviceForStrategy(strategy, true);
sp<DeviceDescriptor> sinkDeviceDesc =
@@ -3364,7 +3555,7 @@
0);
ALOGV("%s patch panel returned %d patchHandle %d", __FUNCTION__,
status, afPatchHandle);
- sourceDesc->mPatchDesc->mPatch = *patchBuilder.patch();
+ sourceDesc->patchDesc()->mPatch = *patchBuilder.patch();
if (status != NO_ERROR) {
ALOGW("%s patch panel could not connect device patch, error %d",
__FUNCTION__, status);
@@ -3374,32 +3565,32 @@
status = startSource(outputDesc, stream, sinkDevice, NULL, &delayMs);
if (status != NO_ERROR) {
- mpClientInterface->releaseAudioPatch(sourceDesc->mPatchDesc->mAfPatchHandle, 0);
+ mpClientInterface->releaseAudioPatch(sourceDesc->patchDesc()->mAfPatchHandle, 0);
return status;
}
- sourceDesc->mSwOutput = outputDesc;
+ sourceDesc->setSwOutput(outputDesc);
if (delayMs != 0) {
usleep(delayMs * 1000);
}
}
- sourceDesc->mPatchDesc->mAfPatchHandle = afPatchHandle;
- addAudioPatch(sourceDesc->mPatchDesc->mHandle, sourceDesc->mPatchDesc);
+ sourceDesc->patchDesc()->mAfPatchHandle = afPatchHandle;
+ addAudioPatch(sourceDesc->patchDesc()->mHandle, sourceDesc->patchDesc());
return NO_ERROR;
}
-status_t AudioPolicyManager::stopAudioSource(audio_patch_handle_t handle)
+status_t AudioPolicyManager::stopAudioSource(audio_port_handle_t portId)
{
- sp<AudioSourceDescriptor> sourceDesc = mAudioSources.valueFor(handle);
- ALOGV("%s handle %d", __FUNCTION__, handle);
+ sp<SourceClientDescriptor> sourceDesc = mAudioSources.valueFor(portId);
+ ALOGV("%s port ID %d", __FUNCTION__, portId);
if (sourceDesc == 0) {
- ALOGW("%s unknown source for handle %d", __FUNCTION__, handle);
+ ALOGW("%s unknown source for port ID %d", __FUNCTION__, portId);
return BAD_VALUE;
}
status_t status = disconnectAudioSource(sourceDesc);
- mAudioSources.removeItem(handle);
+ mAudioSources.removeItem(portId);
return status;
}
@@ -3733,20 +3924,20 @@
}
}
-status_t AudioPolicyManager::disconnectAudioSource(const sp<AudioSourceDescriptor>& sourceDesc)
+status_t AudioPolicyManager::disconnectAudioSource(const sp<SourceClientDescriptor>& sourceDesc)
{
- ALOGV("%s handle %d", __FUNCTION__, sourceDesc->getHandle());
+ ALOGV("%s port Id %d", __FUNCTION__, sourceDesc->portId());
- sp<AudioPatch> patchDesc = mAudioPatches.valueFor(sourceDesc->mPatchDesc->mHandle);
+ sp<AudioPatch> patchDesc = mAudioPatches.valueFor(sourceDesc->patchDesc()->mHandle);
if (patchDesc == 0) {
ALOGW("%s source has no patch with handle %d", __FUNCTION__,
- sourceDesc->mPatchDesc->mHandle);
+ sourceDesc->patchDesc()->mHandle);
return BAD_VALUE;
}
- removeAudioPatch(sourceDesc->mPatchDesc->mHandle);
+ removeAudioPatch(sourceDesc->patchDesc()->mHandle);
- audio_stream_type_t stream = streamTypefromAttributesInt(&sourceDesc->mAttributes);
- sp<SwAudioOutputDescriptor> swOutputDesc = sourceDesc->mSwOutput.promote();
+ audio_stream_type_t stream = sourceDesc->stream();
+ sp<SwAudioOutputDescriptor> swOutputDesc = sourceDesc->swOutput().promote();
if (swOutputDesc != 0) {
status_t status = stopSource(swOutputDesc, stream, false);
if (status == NO_ERROR) {
@@ -3754,7 +3945,7 @@
}
mpClientInterface->releaseAudioPatch(patchDesc->mAfPatchHandle, 0);
} else {
- sp<HwAudioOutputDescriptor> hwOutputDesc = sourceDesc->mHwOutput.promote();
+ sp<HwAudioOutputDescriptor> hwOutputDesc = sourceDesc->hwOutput().promote();
if (hwOutputDesc != 0) {
// release patch between src device and output device
// close Hwoutput and remove from mHwOutputs
@@ -3765,15 +3956,16 @@
return NO_ERROR;
}
-sp<AudioSourceDescriptor> AudioPolicyManager::getSourceForStrategyOnOutput(
+sp<SourceClientDescriptor> AudioPolicyManager::getSourceForStrategyOnOutput(
audio_io_handle_t output, routing_strategy strategy)
{
- sp<AudioSourceDescriptor> source;
+ sp<SourceClientDescriptor> source;
for (size_t i = 0; i < mAudioSources.size(); i++) {
- sp<AudioSourceDescriptor> sourceDesc = mAudioSources.valueAt(i);
+ sp<SourceClientDescriptor> sourceDesc = mAudioSources.valueAt(i);
+ audio_attributes_t attributes = sourceDesc->attributes();
routing_strategy sourceStrategy =
- (routing_strategy) getStrategyForAttr(&sourceDesc->mAttributes);
- sp<SwAudioOutputDescriptor> outputDesc = sourceDesc->mSwOutput.promote();
+ (routing_strategy) getStrategyForAttr(&attributes);
+ sp<SwAudioOutputDescriptor> outputDesc = sourceDesc->swOutput().promote();
if (sourceStrategy == strategy && outputDesc != 0 && outputDesc->mIoHandle == output) {
source = sourceDesc;
break;
@@ -4600,19 +4792,17 @@
return outputs;
}
-void AudioPolicyManager::checkForDeviceAndOutputChanges()
-{
- checkForDeviceAndOutputChanges([](){ return false; });
-}
-
void AudioPolicyManager::checkForDeviceAndOutputChanges(std::function<bool()> onOutputsChecked)
{
// checkA2dpSuspend must run before checkOutputForAllStrategies so that A2DP
// output is suspended before any tracks are moved to it
checkA2dpSuspend();
checkOutputForAllStrategies();
- if (onOutputsChecked()) checkA2dpSuspend();
+ if (onOutputsChecked != nullptr && onOutputsChecked()) checkA2dpSuspend();
updateDevicesAndOutputs();
+ if (mHwModules.getModuleFromName(AUDIO_HARDWARE_MODULE_ID_MSD) != 0) {
+ setMsdPatch();
+ }
}
void AudioPolicyManager::checkOutputForStrategy(routing_strategy strategy)
@@ -4659,7 +4849,7 @@
setStrategyMute(strategy, true, desc);
setStrategyMute(strategy, false, desc, maxLatency * LATENCY_MUTE_FACTOR, newDevice);
}
- sp<AudioSourceDescriptor> source =
+ sp<SourceClientDescriptor> source =
getSourceForStrategyOnOutput(srcOut, strategy);
if (source != 0){
connectAudioSource(source);
@@ -5740,10 +5930,10 @@
void AudioPolicyManager::cleanUpForDevice(const sp<DeviceDescriptor>& deviceDesc)
{
for (ssize_t i = (ssize_t)mAudioSources.size() - 1; i >= 0; i--) {
- sp<AudioSourceDescriptor> sourceDesc = mAudioSources.valueAt(i);
- if (sourceDesc->mDevice->equals(deviceDesc)) {
- ALOGV("%s releasing audio source %d", __FUNCTION__, sourceDesc->getHandle());
- stopAudioSource(sourceDesc->getHandle());
+ sp<SourceClientDescriptor> sourceDesc = mAudioSources.valueAt(i);
+ if (sourceDesc->srcDevice()->equals(deviceDesc)) {
+ ALOGV("%s releasing audio source %d", __FUNCTION__, sourceDesc->portId());
+ stopAudioSource(sourceDesc->portId());
}
}
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index e025803..9436767 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -31,6 +31,7 @@
#include <utils/SortedVector.h>
#include <media/AudioParameter.h>
#include <media/AudioPolicy.h>
+#include <media/PatchBuilder.h>
#include "AudioPolicyInterface.h"
#include <AudioPolicyManagerInterface.h>
@@ -222,9 +223,9 @@
virtual status_t startAudioSource(const struct audio_port_config *source,
const audio_attributes_t *attributes,
- audio_patch_handle_t *handle,
+ audio_port_handle_t *portId,
uid_t uid);
- virtual status_t stopAudioSource(audio_patch_handle_t handle);
+ virtual status_t stopAudioSource(audio_port_handle_t portId);
virtual status_t setMasterMono(bool mono);
virtual status_t getMasterMono(bool *mono);
@@ -407,8 +408,7 @@
// if 'onOutputsChecked' callback is provided, it is executed after the outputs
// check via 'checkOutputForAllStrategies'. If the callback returns 'true',
// A2DP suspend status is rechecked.
- void checkForDeviceAndOutputChanges();
- void checkForDeviceAndOutputChanges(std::function<bool()> onOutputsChecked);
+ void checkForDeviceAndOutputChanges(std::function<bool()> onOutputsChecked = nullptr);
// checks and if necessary changes outputs used for all strategies.
// must be called every time a condition that affects the output choice for a given strategy
@@ -506,7 +506,7 @@
uint32_t updateCallRouting(audio_devices_t rxDevice, uint32_t delayMs = 0);
sp<AudioPatch> createTelephonyPatch(bool isRx, audio_devices_t device, uint32_t delayMs);
sp<DeviceDescriptor> findDevice(
- const DeviceVector& devices, audio_devices_t device);
+ const DeviceVector& devices, audio_devices_t device) const;
// if argument "device" is different from AUDIO_DEVICE_NONE, startSource() will force
// the re-evaluation of the output device.
@@ -525,10 +525,10 @@
status_t hasPrimaryOutput() const { return mPrimaryOutput != 0; }
- status_t connectAudioSource(const sp<AudioSourceDescriptor>& sourceDesc);
- status_t disconnectAudioSource(const sp<AudioSourceDescriptor>& sourceDesc);
+ status_t connectAudioSource(const sp<SourceClientDescriptor>& sourceDesc);
+ status_t disconnectAudioSource(const sp<SourceClientDescriptor>& sourceDesc);
- sp<AudioSourceDescriptor> getSourceForStrategyOnOutput(audio_io_handle_t output,
+ sp<SourceClientDescriptor> getSourceForStrategyOnOutput(audio_io_handle_t output,
routing_strategy strategy);
void cleanUpForDevice(const sp<DeviceDescriptor>& deviceDesc);
@@ -587,7 +587,7 @@
sp<AudioPatch> mCallRxPatch;
HwAudioOutputCollection mHwOutputs;
- AudioSourceCollection mAudioSources;
+ SourceClientCollection mAudioSources;
// for supporting "beacon" streams, i.e. streams that only play on speaker, and never
// when something other than STREAM_TTS (a.k.a. "Transmitted Through Speaker") is playing
@@ -620,6 +620,17 @@
status_t getSupportedFormats(audio_io_handle_t ioHandle, FormatVector& formats);
+ // Support for Multi-Stream Decoder (MSD) module
+ sp<DeviceDescriptor> getMsdAudioInDevice() const;
+ audio_devices_t getMsdAudioOutDeviceTypes() const;
+ const AudioPatchCollection getMsdPatches() const;
+ status_t getBestMsdAudioProfileFor(audio_devices_t outputDevice,
+ bool hwAvSync,
+ audio_port_config *sourceConfig,
+ audio_port_config *sinkConfig) const;
+ PatchBuilder buildMsdPatch(audio_devices_t outputDevice) const;
+ status_t setMsdPatch(audio_devices_t outputDevice = AUDIO_DEVICE_NONE);
+
// If any, resolve any "dynamic" fields of an Audio Profiles collection
void updateAudioProfiles(audio_devices_t device, audio_io_handle_t ioHandle,
AudioProfileVector &profiles);
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index fdfd573..dbfda44 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -990,26 +990,26 @@
}
status_t AudioPolicyService::startAudioSource(const struct audio_port_config *source,
- const audio_attributes_t *attributes,
- audio_patch_handle_t *handle)
+ const audio_attributes_t *attributes,
+ audio_port_handle_t *portId)
{
Mutex::Autolock _l(mLock);
if (mAudioPolicyManager == NULL) {
return NO_INIT;
}
AutoCallerClear acc;
- return mAudioPolicyManager->startAudioSource(source, attributes, handle,
+ return mAudioPolicyManager->startAudioSource(source, attributes, portId,
IPCThreadState::self()->getCallingUid());
}
-status_t AudioPolicyService::stopAudioSource(audio_patch_handle_t handle)
+status_t AudioPolicyService::stopAudioSource(audio_port_handle_t portId)
{
Mutex::Autolock _l(mLock);
if (mAudioPolicyManager == NULL) {
return NO_INIT;
}
AutoCallerClear acc;
- return mAudioPolicyManager->stopAudioSource(handle);
+ return mAudioPolicyManager->stopAudioSource(portId);
}
status_t AudioPolicyService::setMasterMono(bool mono)
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index d41069e..6a25668 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -184,8 +184,8 @@
virtual status_t startAudioSource(const struct audio_port_config *source,
const audio_attributes_t *attributes,
- audio_patch_handle_t *handle);
- virtual status_t stopAudioSource(audio_patch_handle_t handle);
+ audio_port_handle_t *portId);
+ virtual status_t stopAudioSource(audio_port_handle_t portId);
virtual status_t setMasterMono(bool mono);
virtual status_t getMasterMono(bool *mono);
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index d4f78e0..491ed72 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -2173,8 +2173,14 @@
res = stream->finishConfiguration();
if (res != OK) {
- SET_ERR_L("Can't finish configuring output stream %d: %s (%d)",
- stream->getId(), strerror(-res), res);
+ // If finishConfiguration fails due to abandoned surface, do not set
+ // device to error state.
+ bool isSurfaceAbandoned =
+ (res == NO_INIT || res == DEAD_OBJECT) && stream->isAbandoned();
+ if (!isSurfaceAbandoned) {
+ SET_ERR_L("Can't finish configuring output stream %d: %s (%d)",
+ stream->getId(), strerror(-res), res);
+ }
return res;
}
}
@@ -2391,9 +2397,16 @@
//present streams end up with outstanding buffers that will
//not get drained.
internalUpdateStatusLocked(STATUS_ACTIVE);
+ } else if (rc == DEAD_OBJECT) {
+ // DEAD_OBJECT can be returned if either the consumer surface is
+ // abandoned, or the HAL has died.
+ // - If the HAL has died, configureStreamsLocked call will set
+ // device to error state,
+ // - If surface is abandoned, we should not set device to error
+ // state.
+ ALOGE("Failed to re-configure camera due to abandoned surface");
} else {
- setErrorStateLocked("%s: Failed to re-configure camera: %d",
- __FUNCTION__, rc);
+ SET_ERR_L("Failed to re-configure camera: %d", rc);
}
} else {
ALOGE("%s: Failed to pause streaming: %d", __FUNCTION__, rc);
@@ -2527,6 +2540,9 @@
CLOGE("Can't finish configuring input stream %d: %s (%d)",
mInputStream->getId(), strerror(-res), res);
cancelStreamsConfigurationLocked();
+ if ((res == NO_INIT || res == DEAD_OBJECT) && mInputStream->isAbandoned()) {
+ return DEAD_OBJECT;
+ }
return BAD_VALUE;
}
}
@@ -2540,6 +2556,9 @@
CLOGE("Can't finish configuring output stream %d: %s (%d)",
outputStream->getId(), strerror(-res), res);
cancelStreamsConfigurationLocked();
+ if ((res == NO_INIT || res == DEAD_OBJECT) && outputStream->isAbandoned()) {
+ return DEAD_OBJECT;
+ }
return BAD_VALUE;
}
}
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp
index 1105b75..6030d15 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp
@@ -331,7 +331,14 @@
status_t res;
res = configureQueueLocked();
- if (res != OK) {
+ // configureQueueLocked could return error in case of abandoned surface.
+ // Treat as non-fatal error.
+ if (res == NO_INIT || res == DEAD_OBJECT) {
+ ALOGE("%s: Unable to configure stream %d queue (non-fatal): %s (%d)",
+ __FUNCTION__, mId, strerror(-res), res);
+ mState = STATE_ABANDONED;
+ return res;
+ } else if (res != OK) {
ALOGE("%s: Unable to configure stream %d queue: %s (%d)",
__FUNCTION__, mId, strerror(-res), res);
mState = STATE_ERROR;
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.h b/services/camera/libcameraservice/device3/Camera3Stream.h
index a60cb56..4ddcf1a 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.h
+++ b/services/camera/libcameraservice/device3/Camera3Stream.h
@@ -482,6 +482,7 @@
// after the HAL has provided usage and max_buffers values. After this call,
// the stream must be ready to produce all buffers for registration with
// HAL.
+ // Returns NO_INIT or DEAD_OBJECT if the queue has been abandoned.
virtual status_t configureQueueLocked() = 0;
// Get the total number of buffers in the queue