Merge "Use fast mode with patch track and patch record if possible."
diff --git a/media/extractors/mp4/SampleIterator.cpp b/media/extractors/mp4/SampleIterator.cpp
index 93ee7c6..1a6d306 100644
--- a/media/extractors/mp4/SampleIterator.cpp
+++ b/media/extractors/mp4/SampleIterator.cpp
@@ -328,7 +328,15 @@
++mTimeToSampleIndex;
}
- *time = mTTSSampleTime + mTTSDuration * (sampleIndex - mTTSSampleIndex);
+ // below is equivalent to:
+ // *time = mTTSSampleTime + mTTSDuration * (sampleIndex - mTTSSampleIndex);
+ uint32_t tmp;
+ if (__builtin_sub_overflow(sampleIndex, mTTSSampleIndex, &tmp) ||
+ __builtin_mul_overflow(mTTSDuration, tmp, &tmp) ||
+ __builtin_add_overflow(mTTSSampleTime, tmp, &tmp)) {
+ return ERROR_OUT_OF_RANGE;
+ }
+ *time = tmp;
int32_t offset = mTable->getCompositionTimeOffset(sampleIndex);
if ((offset < 0 && *time < (offset == INT32_MIN ?
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/libmedia/MediaProfiles.cpp b/media/libmedia/MediaProfiles.cpp
index aade69a..e0f5a40 100644
--- a/media/libmedia/MediaProfiles.cpp
+++ b/media/libmedia/MediaProfiles.cpp
@@ -546,8 +546,8 @@
if (info->mHasRefProfile) {
- CamcorderProfile *profile =
- new CamcorderProfile(
+ std::unique_ptr<CamcorderProfile> profile =
+ std::make_unique<CamcorderProfile>(
*mCamcorderProfiles[info->mRefProfileIndex]);
// Overwrite the quality
@@ -581,7 +581,7 @@
mCamcorderProfiles[info->mRefProfileIndex]->mQuality,
profile->mQuality, cameraId);
- mCamcorderProfiles.add(profile);
+ mCamcorderProfiles.add(profile.release());
}
}
}
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Decoder.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2Decoder.cpp
index 645138a..931b86e 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Decoder.cpp
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2Decoder.cpp
@@ -1088,6 +1088,12 @@
static_cast<MediaBufferHolder*>(holder.get())->mediaBuffer() : nullptr;
}
if (mediaBuf != NULL) {
+ if (mediaBuf->size() > codecBuffer->capacity()) {
+ handleError(ERROR_BUFFER_TOO_SMALL);
+ mDequeuedInputBuffers.push_back(bufferIx);
+ return false;
+ }
+
codecBuffer->setRange(0, mediaBuf->size());
memcpy(codecBuffer->data(), mediaBuf->data(), mediaBuf->size());
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index 69cd82e..050e4fb 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -1069,6 +1069,12 @@
static_cast<MediaBufferHolder*>(holder.get())->mediaBuffer() : nullptr;
}
if (mediaBuf != NULL) {
+ if (mediaBuf->size() > codecBuffer->capacity()) {
+ handleError(ERROR_BUFFER_TOO_SMALL);
+ mDequeuedInputBuffers.push_back(bufferIx);
+ return false;
+ }
+
codecBuffer->setRange(0, mediaBuf->size());
memcpy(codecBuffer->data(), mediaBuf->data(), mediaBuf->size());
diff --git a/media/libnblog/PerformanceAnalysis.cpp b/media/libnblog/PerformanceAnalysis.cpp
index 22a30b9..3418dc0 100644
--- a/media/libnblog/PerformanceAnalysis.cpp
+++ b/media/libnblog/PerformanceAnalysis.cpp
@@ -32,6 +32,7 @@
#include <sys/prctl.h>
#include <time.h>
#include <new>
+#include <audio_utils/LogPlot.h>
#include <audio_utils/roundup.h>
#include <media/nblog/NBLog.h>
#include <media/nblog/PerformanceAnalysis.h>
@@ -208,27 +209,6 @@
return isOutlier;
}
-static int widthOf(int x) {
- int width = 0;
- if (x < 0) {
- width++;
- x = x == INT_MIN ? INT_MAX : -x;
- }
- // assert (x >= 0)
- do {
- ++width;
- x /= 10;
- } while (x > 0);
- return width;
-}
-
-// computes the column width required for a specific histogram value
-inline int numberWidth(double number, int leftPadding) {
- // Added values account for whitespaces needed around numbers, and for the
- // dot and decimal digit not accounted for by widthOf
- return std::max(std::max(widthOf(static_cast<int>(number)) + 3, 2), leftPadding + 1);
-}
-
// rounds value to precision based on log-distance from mean
__attribute__((no_sanitize("signed-integer-overflow")))
inline double logRound(double x, double mean) {
@@ -281,65 +261,8 @@
static_cast<long long>(hash), static_cast<long long>(startingTs));
static const char * const kLabel = "ms";
- auto it = buckets.begin();
- double maxDelta = it->first;
- int maxCount = it->second;
- // Compute maximum values
- while (++it != buckets.end()) {
- if (it->first > maxDelta) {
- maxDelta = it->first;
- }
- if (it->second > maxCount) {
- maxCount = it->second;
- }
- }
- int height = log2(maxCount) + 1; // maxCount > 0, safe to call log2
- const int leftPadding = widthOf(1 << height);
- const int bucketWidth = numberWidth(maxDelta, leftPadding);
- int scalingFactor = 1;
- // scale data if it exceeds maximum height
- if (height > maxHeight) {
- scalingFactor = (height + maxHeight) / maxHeight;
- height /= scalingFactor;
- }
- body->appendFormat("%s", title);
- // write histogram label line with bucket values
- body->appendFormat("\n%s", " ");
- body->appendFormat("%*s", leftPadding, " ");
- for (auto const &x : buckets) {
- const int colWidth = numberWidth(x.first, leftPadding);
- body->appendFormat("%*d", colWidth, x.second);
- }
- // write histogram ascii art
- // underscores and spaces length corresponds to maximum width of histogram
- static const int kLen = 200;
- static const std::string underscores(kLen, '_');
- static const std::string spaces(kLen, ' ');
-
- body->appendFormat("\n%s", " ");
- for (int row = height * scalingFactor; row >= 0; row -= scalingFactor) {
- const int value = 1 << row;
- body->appendFormat("%.*s", leftPadding, spaces.c_str());
- for (auto const &x : buckets) {
- const int colWidth = numberWidth(x.first, leftPadding);
- body->appendFormat("%.*s%s", colWidth - 1,
- spaces.c_str(), x.second < value ? " " : "|");
- }
- body->appendFormat("\n%s", " ");
- }
- // print x-axis
- const int columns = static_cast<int>(buckets.size());
- body->appendFormat("%*c", leftPadding, ' ');
- body->appendFormat("%.*s", (columns + 1) * bucketWidth, underscores.c_str());
- body->appendFormat("\n%s", " ");
-
- // write footer with bucket labels
- body->appendFormat("%*s", leftPadding, " ");
- for (auto const &x : buckets) {
- const int colWidth = numberWidth(x.first, leftPadding);
- body->appendFormat("%*.*f", colWidth, 1, x.first);
- }
- body->appendFormat("%.*s%s\n", bucketWidth, spaces.c_str(), kLabel);
+ body->appendFormat("%s",
+ audio_utils_plot_histogram(buckets, title, kLabel, maxHeight).c_str());
// Now report glitches
body->appendFormat("\ntime elapsed between glitches and glitch timestamps:\n");
diff --git a/media/libnblog/include/media/nblog/PerformanceAnalysis.h b/media/libnblog/include/media/nblog/PerformanceAnalysis.h
index ddfe9d6..56e0ea6 100644
--- a/media/libnblog/include/media/nblog/PerformanceAnalysis.h
+++ b/media/libnblog/include/media/nblog/PerformanceAnalysis.h
@@ -25,6 +25,8 @@
namespace android {
+class String8;
+
namespace ReportPerformance {
class PerformanceAnalysis;
diff --git a/media/libnblog/include/media/nblog/ReportPerformance.h b/media/libnblog/include/media/nblog/ReportPerformance.h
index ec0842f..1b11197 100644
--- a/media/libnblog/include/media/nblog/ReportPerformance.h
+++ b/media/libnblog/include/media/nblog/ReportPerformance.h
@@ -23,9 +23,6 @@
namespace android {
-// The String8 class is used by reportPerformance function
-class String8;
-
namespace ReportPerformance {
constexpr int kMsPerSec = 1000;
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 68c8cac..6cead19 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();
@@ -3354,7 +3354,7 @@
continue;
}
- if ((!mActiveTracks.size() && systemTime() > mStandbyTimeNs) ||
+ if ((mActiveTracks.isEmpty() && systemTime() > mStandbyTimeNs) ||
isSuspended()) {
// put audio hardware into standby after short delay
if (shouldStandby_l()) {
@@ -3368,7 +3368,7 @@
mStandby = true;
}
- if (!mActiveTracks.size() && mConfigEvents.isEmpty()) {
+ if (mActiveTracks.isEmpty() && mConfigEvents.isEmpty()) {
// we're about to wait, flush the binder command buffer
IPCThreadState::self()->flushCommands();
@@ -6649,7 +6649,7 @@
}
// sleep if there are no active tracks to process
- if (activeTracks.size() == 0) {
+ if (activeTracks.isEmpty()) {
if (sleepUs == 0) {
sleepUs = kRecordThreadSleepUs;
}
@@ -7451,7 +7451,7 @@
audio_input_flags_t flags = input != NULL ? input->flags : AUDIO_INPUT_FLAG_NONE;
dprintf(fd, " AudioStreamIn: %p flags %#x (%s)\n",
input, flags, inputFlagsToString(flags).c_str());
- if (mActiveTracks.size() == 0) {
+ if (mActiveTracks.isEmpty()) {
dprintf(fd, " No active record clients\n");
}
@@ -7917,7 +7917,7 @@
status_t AudioFlinger::RecordThread::addEffectChain_l(const sp<EffectChain>& chain)
{
// only one chain per input thread
- if (mEffectChains.size() != 0) {
+ if (!mEffectChains.isEmpty()) {
ALOGW("addEffectChain_l() already one chain %p on thread %p", chain.get(), this);
return INVALID_OPERATION;
}
@@ -8253,7 +8253,7 @@
// abort if start is rejected by audio policy manager
if (ret != NO_ERROR) {
ALOGE("%s: error start rejected by AudioPolicyManager = %d", __FUNCTION__, ret);
- if (mActiveTracks.size() != 0) {
+ if (!mActiveTracks.isEmpty()) {
mLock.unlock();
if (isOutput()) {
AudioSystem::releaseOutput(portId);
@@ -8354,7 +8354,7 @@
if (mHalStream == 0) {
return NO_INIT;
}
- if (mActiveTracks.size() != 0) {
+ if (!mActiveTracks.isEmpty()) {
return INVALID_OPERATION;
}
mHalStream->standby();
@@ -8792,7 +8792,7 @@
dprintf(fd, " Attributes: content type %d usage %d source %d\n",
mAttr.content_type, mAttr.usage, mAttr.source);
dprintf(fd, " Session: %d port Id: %d\n", mSessionId, mPortId);
- if (mActiveTracks.size() == 0) {
+ if (mActiveTracks.isEmpty()) {
dprintf(fd, " No active clients\n");
}
}
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 23ab37b..f0d625c 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -555,6 +555,9 @@
size_t size() const {
return mActiveTracks.size();
}
+ bool isEmpty() const {
+ return mActiveTracks.isEmpty();
+ }
ssize_t indexOf(const sp<T>& item) {
return mActiveTracks.indexOf(item);
}
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index fe49483..d4c49d9 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -124,17 +124,11 @@
audio_port_handle_t *selectedDeviceId,
audio_port_handle_t *portId) = 0;
// indicates to the audio policy manager that the output starts being used by corresponding stream.
- virtual status_t startOutput(audio_io_handle_t output,
- audio_stream_type_t stream,
- audio_session_t session) = 0;
+ virtual status_t startOutput(audio_port_handle_t portId) = 0;
// indicates to the audio policy manager that the output stops being used by corresponding stream.
- virtual status_t stopOutput(audio_io_handle_t output,
- audio_stream_type_t stream,
- audio_session_t session) = 0;
+ virtual status_t stopOutput(audio_port_handle_t portId) = 0;
// releases the output.
- virtual void releaseOutput(audio_io_handle_t output,
- audio_stream_type_t stream,
- audio_session_t session) = 0;
+ virtual void releaseOutput(audio_port_handle_t portId) = 0;
// request an input appropriate for record from the supplied device with supplied parameters.
virtual status_t getInputForAttr(const audio_attributes_t *attr,
@@ -147,16 +141,13 @@
input_type_t *inputType,
audio_port_handle_t *portId) = 0;
// indicates to the audio policy manager that the input starts being used.
- virtual status_t startInput(audio_io_handle_t input,
- audio_session_t session,
+ virtual status_t startInput(audio_port_handle_t portId,
bool silenced,
concurrency_type__mask_t *concurrency) = 0;
// indicates to the audio policy manager that the input stops being used.
- virtual status_t stopInput(audio_io_handle_t input,
- audio_session_t session) = 0;
+ virtual status_t stopInput(audio_port_handle_t portId) = 0;
// releases the input.
- virtual void releaseInput(audio_io_handle_t input,
- audio_session_t session) = 0;
+ virtual void releaseInput(audio_port_handle_t portId) = 0;
//
// volume control functions
@@ -235,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 b3611c4..9b8f095 100644
--- a/services/audiopolicy/common/managerdefinitions/Android.mk
+++ b/services/audiopolicy/common/managerdefinitions/Android.mk
@@ -18,10 +18,10 @@
src/EffectDescriptor.cpp \
src/SoundTriggerSession.cpp \
src/SessionRoute.cpp \
- src/AudioSourceDescriptor.cpp \
src/VolumeCurve.cpp \
src/TypeConverter.cpp \
- src/AudioSession.cpp
+ src/AudioSession.cpp \
+ src/ClientDescriptor.cpp
LOCAL_SHARED_LIBRARIES := \
libcutils \
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioIODescriptorInterface.h b/services/audiopolicy/common/managerdefinitions/include/AudioIODescriptorInterface.h
index 9f3fc0c..555412e 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioIODescriptorInterface.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioIODescriptorInterface.h
@@ -34,12 +34,4 @@
virtual void setPatchHandle(audio_patch_handle_t handle) = 0;
};
-class AudioIODescriptorUpdateListener
-{
-public:
- virtual ~AudioIODescriptorUpdateListener() {};
-
- virtual void onIODescriptorUpdate() const = 0;
-};
-
} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
index 85f3b86..44662e5 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
@@ -19,6 +19,7 @@
#include "AudioIODescriptorInterface.h"
#include "AudioPort.h"
#include "AudioSession.h"
+#include "ClientDescriptor.h"
#include <utils/Errors.h>
#include <system/audio.h>
#include <utils/SortedVector.h>
@@ -66,6 +67,8 @@
AudioSessionCollection getAudioSessions(bool activeOnly) const;
size_t getAudioSessionCount(bool activeOnly) const;
audio_source_t getHighestPrioritySource(bool activeOnly) const;
+ void changeRefCount(audio_session_t session, int delta);
+
// implementation of AudioIODescriptorInterface
audio_config_base_t getConfig() const override;
@@ -79,14 +82,20 @@
audio_input_flags_t flags,
audio_io_handle_t *input);
// Called when a stream is about to be started.
- // Note: called after AudioSession::changeActiveCount(1)
+ // Note: called after changeRefCount(session, 1)
status_t start();
// Called after a stream is stopped
- // Note: called after AudioSession::changeActiveCount(-1)
+ // Note: called after changeRefCount(session, -1)
void stop();
void close();
-private:
+ RecordClientMap& clients() { return mClients; }
+ RecordClientVector getClientsForSession(audio_session_t session);
+
+ private:
+
+ void updateSessionRecordingConfiguration(int event, const sp<AudioSession>& audioSession);
+
audio_patch_handle_t mPatchHandle;
audio_port_handle_t mId;
// audio sessions attached to this input
@@ -99,6 +108,9 @@
// We also inherit sessions from the preempted input to avoid a 3 way preemption loop etc...
SortedVector<audio_session_t> mPreemptedSessions;
AudioPolicyClientInterface *mClientInterface;
+ uint32_t mGlobalRefCount; // non-session-specific ref count
+
+ RecordClientMap mClients;
};
class AudioInputCollection :
@@ -122,6 +134,8 @@
audio_devices_t getSupportedDevices(audio_io_handle_t handle) const;
+ sp<AudioInputDescriptor> getInputForClient(audio_port_handle_t portId);
+
status_t dump(int fd) const;
};
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
index 57d1cfa..ff0201a 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
@@ -17,15 +17,14 @@
#pragma once
#include <sys/types.h>
-
-#include "AudioPort.h"
-#include <RoutingStrategy.h>
#include <utils/Errors.h>
#include <utils/Timers.h>
#include <utils/KeyedVector.h>
#include <system/audio.h>
+#include <RoutingStrategy.h>
#include "AudioIODescriptorInterface.h"
-#include "AudioSourceDescriptor.h"
+#include "AudioPort.h"
+#include "ClientDescriptor.h"
namespace android {
@@ -79,7 +78,9 @@
audio_patch_handle_t getPatchHandle() const override;
void setPatchHandle(audio_patch_handle_t handle) override;
- sp<AudioPort> mPort;
+ TrackClientMap& clients() { return mClients; }
+
+ sp<AudioPort> mPort;
audio_devices_t mDevice; // current device this output is routed to
uint32_t mRefCount[AUDIO_STREAM_CNT]; // number of streams of each type using this output
nsecs_t mStopTime[AUDIO_STREAM_CNT];
@@ -92,6 +93,7 @@
protected:
audio_patch_handle_t mPatchHandle;
audio_port_handle_t mId;
+ TrackClientMap mClients;
};
// Audio output driven by a software mixer in audio flinger.
@@ -156,7 +158,7 @@
class HwAudioOutputDescriptor: public AudioOutputDescriptor
{
public:
- HwAudioOutputDescriptor(const sp<AudioSourceDescriptor>& source,
+ HwAudioOutputDescriptor(const sp<SourceClientDescriptor>& source,
AudioPolicyClientInterface *clientInterface);
virtual ~HwAudioOutputDescriptor() {}
@@ -173,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;
};
@@ -227,6 +229,8 @@
audio_devices_t getSupportedDevices(audio_io_handle_t handle) const;
+ sp<SwAudioOutputDescriptor> getOutputForClient(audio_port_handle_t portId);
+
status_t dump(int fd) const;
};
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioProfile.h b/services/audiopolicy/common/managerdefinitions/include/AudioProfile.h
index 4226ff2..a1ee708 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioProfile.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioProfile.h
@@ -16,93 +16,84 @@
#pragma once
-#include "policy.h"
-#include <utils/String8.h>
-#include <utils/SortedVector.h>
-#include <utils/RefBase.h>
-#include <utils/Errors.h>
+#include <vector>
+
#include <system/audio.h>
-#include <cutils/config_utils.h>
+#include <utils/RefBase.h>
+#include <utils/SortedVector.h>
+#include <utils/String8.h>
+
+#include "policy.h"
namespace android {
typedef SortedVector<uint32_t> SampleRateVector;
-typedef SortedVector<audio_channel_mask_t> ChannelsVector;
typedef Vector<audio_format_t> FormatVector;
template <typename T>
-bool operator == (const SortedVector<T> &left, const SortedVector<T> &right);
+bool operator== (const SortedVector<T> &left, const SortedVector<T> &right)
+{
+ if (left.size() != right.size()) {
+ return false;
+ }
+ for (size_t index = 0; index < right.size(); index++) {
+ if (left[index] != right[index]) {
+ return false;
+ }
+ }
+ return true;
+}
+
+template <typename T>
+bool operator!= (const SortedVector<T> &left, const SortedVector<T> &right)
+{
+ return !(left == right);
+}
+
+class ChannelsVector : public SortedVector<audio_channel_mask_t>
+{
+public:
+ ChannelsVector() = default;
+ ChannelsVector(const ChannelsVector&) = default;
+ ChannelsVector(const SortedVector<audio_channel_mask_t>& sv) :
+ SortedVector<audio_channel_mask_t>(sv) {}
+ ChannelsVector& operator=(const ChannelsVector&) = default;
+
+ // Applies audio_channel_mask_out_to_in to all elements and returns the result.
+ ChannelsVector asInMask() const;
+ // Applies audio_channel_mask_in_to_out to all elements and returns the result.
+ ChannelsVector asOutMask() const;
+};
class AudioProfile : public virtual RefBase
{
public:
static sp<AudioProfile> createFullDynamic();
- AudioProfile(audio_format_t format,
- audio_channel_mask_t channelMasks,
- uint32_t samplingRate) :
- mName(String8("")),
- mFormat(format)
- {
- mChannelMasks.add(channelMasks);
- mSamplingRates.add(samplingRate);
- }
-
+ AudioProfile(audio_format_t format, audio_channel_mask_t channelMasks, uint32_t samplingRate);
AudioProfile(audio_format_t format,
const ChannelsVector &channelMasks,
- const SampleRateVector &samplingRateCollection) :
- mName(String8("")),
- mFormat(format),
- mChannelMasks(channelMasks),
- mSamplingRates(samplingRateCollection)
- {}
+ const SampleRateVector &samplingRateCollection);
audio_format_t getFormat() const { return mFormat; }
-
- void setChannels(const ChannelsVector &channelMasks)
- {
- if (mIsDynamicChannels) {
- mChannelMasks = channelMasks;
- }
- }
const ChannelsVector &getChannels() const { return mChannelMasks; }
-
- void setSampleRates(const SampleRateVector &sampleRates)
- {
- if (mIsDynamicRate) {
- mSamplingRates = sampleRates;
- }
- }
const SampleRateVector &getSampleRates() const { return mSamplingRates; }
+ void setChannels(const ChannelsVector &channelMasks);
+ void setSampleRates(const SampleRateVector &sampleRates);
+ void clear();
bool isValid() const { return hasValidFormat() && hasValidRates() && hasValidChannels(); }
-
- void clear()
- {
- if (mIsDynamicChannels) {
- mChannelMasks.clear();
- }
- if (mIsDynamicRate) {
- mSamplingRates.clear();
- }
- }
-
- inline bool supportsChannels(audio_channel_mask_t channels) const
+ bool supportsChannels(audio_channel_mask_t channels) const
{
return mChannelMasks.indexOf(channels) >= 0;
}
- inline bool supportsRate(uint32_t rate) const
- {
- return mSamplingRates.indexOf(rate) >= 0;
- }
+ bool supportsRate(uint32_t rate) const { return mSamplingRates.indexOf(rate) >= 0; }
status_t checkExact(uint32_t rate, audio_channel_mask_t channels, audio_format_t format) const;
-
status_t checkCompatibleChannelMask(audio_channel_mask_t channelMask,
audio_channel_mask_t &updatedChannelMask,
audio_port_type_t portType,
audio_port_role_t portRole) const;
-
status_t checkCompatibleSamplingRate(uint32_t samplingRate,
uint32_t &updatedSamplingRate) const;
@@ -138,213 +129,48 @@
class AudioProfileVector : public Vector<sp<AudioProfile> >
{
public:
- ssize_t add(const sp<AudioProfile> &profile)
- {
- ssize_t index = Vector::add(profile);
- // we sort from worst to best, so that AUDIO_FORMAT_DEFAULT is always the first entry.
- // TODO: compareFormats could be a lambda to convert between pointer-to-format to format:
- // [](const audio_format_t *format1, const audio_format_t *format2) {
- // return compareFormats(*format1, *format2);
- // }
- sort(compareFormats);
- return index;
- }
-
+ ssize_t add(const sp<AudioProfile> &profile);
// This API is intended to be used by the policy manager once retrieving capabilities
// for a profile with dynamic format, rate and channels attributes
- ssize_t addProfileFromHal(const sp<AudioProfile> &profileToAdd)
- {
- // Check valid profile to add:
- if (!profileToAdd->hasValidFormat()) {
- return -1;
- }
- if (!profileToAdd->hasValidChannels() && !profileToAdd->hasValidRates()) {
- FormatVector formats;
- formats.add(profileToAdd->getFormat());
- setFormats(FormatVector(formats));
- return 0;
- }
- if (!profileToAdd->hasValidChannels() && profileToAdd->hasValidRates()) {
- setSampleRatesFor(profileToAdd->getSampleRates(), profileToAdd->getFormat());
- return 0;
- }
- if (profileToAdd->hasValidChannels() && !profileToAdd->hasValidRates()) {
- setChannelsFor(profileToAdd->getChannels(), profileToAdd->getFormat());
- return 0;
- }
- // Go through the list of profile to avoid duplicates
- for (size_t profileIndex = 0; profileIndex < size(); profileIndex++) {
- const sp<AudioProfile> &profile = itemAt(profileIndex);
- if (profile->isValid() && profile == profileToAdd) {
- // Nothing to do
- return profileIndex;
- }
- }
- profileToAdd->setDynamicFormat(true); // set the format as dynamic to allow removal
- return add(profileToAdd);
- }
-
- sp<AudioProfile> getFirstValidProfile() const
- {
- for (size_t i = 0; i < size(); i++) {
- if (itemAt(i)->isValid()) {
- return itemAt(i);
- }
- }
- return 0;
- }
-
- bool hasValidProfile() const { return getFirstValidProfile() != 0; }
+ ssize_t addProfileFromHal(const sp<AudioProfile> &profileToAdd);
status_t checkExactProfile(uint32_t samplingRate, audio_channel_mask_t channelMask,
audio_format_t format) const;
-
status_t checkCompatibleProfile(uint32_t &samplingRate, audio_channel_mask_t &channelMask,
audio_format_t &format,
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;
- FormatVector getSupportedFormats() const
- {
- FormatVector supportedFormats;
- for (size_t i = 0; i < size(); i++) {
- if (itemAt(i)->hasValidFormat()) {
- supportedFormats.add(itemAt(i)->getFormat());
- }
- }
- return supportedFormats;
- }
+ sp<AudioProfile> getFirstValidProfile() const;
+ sp<AudioProfile> getFirstValidProfileFor(audio_format_t format) const;
+ bool hasValidProfile() const { return getFirstValidProfile() != 0; }
- bool hasDynamicProfile() const
- {
- for (size_t i = 0; i < size(); i++) {
- if (itemAt(i)->isDynamic()) {
- return true;
- }
- }
- return false;
- }
-
- bool hasDynamicFormat() const
- {
- return getProfileFor(gDynamicFormat) != 0;
- }
-
- bool hasDynamicChannelsFor(audio_format_t format) const
- {
- for (size_t i = 0; i < size(); i++) {
- sp<AudioProfile> profile = itemAt(i);
- if (profile->getFormat() == format && profile->isDynamicChannels()) {
- return true;
- }
- }
- return false;
- }
-
- bool hasDynamicRateFor(audio_format_t format) const
- {
- for (size_t i = 0; i < size(); i++) {
- sp<AudioProfile> profile = itemAt(i);
- if (profile->getFormat() == format && profile->isDynamicRate()) {
- return true;
- }
- }
- return false;
- }
+ FormatVector getSupportedFormats() const;
+ bool hasDynamicChannelsFor(audio_format_t format) const;
+ bool hasDynamicFormat() const { return getProfileFor(gDynamicFormat) != 0; }
+ bool hasDynamicProfile() const;
+ bool hasDynamicRateFor(audio_format_t format) const;
// One audio profile will be added for each format supported by Audio HAL
- void setFormats(const FormatVector &formats)
- {
- // Only allow to change the format of dynamic profile
- sp<AudioProfile> dynamicFormatProfile = getProfileFor(gDynamicFormat);
- if (dynamicFormatProfile == 0) {
- return;
- }
- for (size_t i = 0; i < formats.size(); i++) {
- sp<AudioProfile> profile = new AudioProfile(formats[i],
- dynamicFormatProfile->getChannels(),
- dynamicFormatProfile->getSampleRates());
- profile->setDynamicFormat(true);
- profile->setDynamicChannels(dynamicFormatProfile->isDynamicChannels());
- profile->setDynamicRate(dynamicFormatProfile->isDynamicRate());
- add(profile);
- }
- }
+ void setFormats(const FormatVector &formats);
- void clearProfiles()
- {
- for (size_t i = size(); i != 0; ) {
- sp<AudioProfile> profile = itemAt(--i);
- if (profile->isDynamicFormat() && profile->hasValidFormat()) {
- removeAt(i);
- continue;
- }
- profile->clear();
- }
- }
-
- void dump(int fd, int spaces) const
- {
- const size_t SIZE = 256;
- char buffer[SIZE];
-
- snprintf(buffer, SIZE, "%*s- Profiles:\n", spaces, "");
- write(fd, buffer, strlen(buffer));
- for (size_t i = 0; i < size(); i++) {
- snprintf(buffer, SIZE, "%*sProfile %zu:", spaces + 4, "", i);
- write(fd, buffer, strlen(buffer));
- itemAt(i)->dump(fd, spaces + 8);
- }
- }
+ void dump(int fd, int spaces) const;
private:
- void setSampleRatesFor(const SampleRateVector &sampleRates, audio_format_t format)
- {
- for (size_t i = 0; i < size(); i++) {
- sp<AudioProfile> profile = itemAt(i);
- if (profile->getFormat() == format && profile->isDynamicRate()) {
- if (profile->hasValidRates()) {
- // Need to create a new profile with same format
- sp<AudioProfile> profileToAdd = new AudioProfile(format, profile->getChannels(),
- sampleRates);
- profileToAdd->setDynamicFormat(true); // need to set to allow cleaning
- add(profileToAdd);
- } else {
- profile->setSampleRates(sampleRates);
- }
- return;
- }
- }
- }
-
- void setChannelsFor(const ChannelsVector &channelMasks, audio_format_t format)
- {
- for (size_t i = 0; i < size(); i++) {
- sp<AudioProfile> profile = itemAt(i);
- if (profile->getFormat() == format && profile->isDynamicChannels()) {
- if (profile->hasValidChannels()) {
- // Need to create a new profile with same format
- sp<AudioProfile> profileToAdd = new AudioProfile(format, channelMasks,
- profile->getSampleRates());
- profileToAdd->setDynamicFormat(true); // need to set to allow cleaning
- add(profileToAdd);
- } else {
- profile->setChannels(channelMasks);
- }
- return;
- }
- }
- }
-
- sp<AudioProfile> getProfileFor(audio_format_t format) const
- {
- for (size_t i = 0; i < size(); i++) {
- if (itemAt(i)->getFormat() == format) {
- return itemAt(i);
- }
- }
- return 0;
- }
+ sp<AudioProfile> getProfileFor(audio_format_t format) const;
+ void setSampleRatesFor(const SampleRateVector &sampleRates, audio_format_t format);
+ void setChannelsFor(const ChannelsVector &channelMasks, audio_format_t format);
static int compareFormats(const sp<AudioProfile> *profile1, const sp<AudioProfile> *profile2);
};
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioSession.h b/services/audiopolicy/common/managerdefinitions/include/AudioSession.h
index 53e6ec9..1636d3a 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioSession.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioSession.h
@@ -29,7 +29,7 @@
class AudioPolicyClientInterface;
-class AudioSession : public RefBase, public AudioIODescriptorUpdateListener
+class AudioSession : public RefBase
{
public:
AudioSession(audio_session_t session,
@@ -39,9 +39,7 @@
audio_channel_mask_t channelMask,
audio_input_flags_t flags,
uid_t uid,
- bool isSoundTrigger,
- AudioMix* policyMix,
- AudioPolicyClientInterface *clientInterface);
+ bool isSoundTrigger);
status_t dump(int fd, int spaces, int index) const;
@@ -50,6 +48,8 @@
audio_format_t format() const { return mConfig.format; }
uint32_t sampleRate() const { return mConfig.sample_rate; }
audio_channel_mask_t channelMask() const { return mConfig.channel_mask; }
+ audio_config_base config() const { return mConfig; }
+ record_client_info_t recordClientInfo() const { return mRecordClientInfo; }
audio_input_flags_t flags() const { return mFlags; }
uid_t uid() const { return mRecordClientInfo.uid; }
void setUid(uid_t uid) { mRecordClientInfo.uid = uid; }
@@ -63,10 +63,6 @@
uint32_t changeOpenCount(int delta);
uint32_t changeActiveCount(int delta);
- void setInfoProvider(AudioIODescriptorInterface *provider);
- // implementation of AudioIODescriptorUpdateListener
- virtual void onIODescriptorUpdate() const;
-
private:
record_client_info_t mRecordClientInfo;
const struct audio_config_base mConfig;
@@ -75,19 +71,14 @@
bool mSilenced;
uint32_t mOpenCount;
uint32_t mActiveCount;
- AudioMix* mPolicyMix; // non NULL when used by a dynamic policy
- AudioPolicyClientInterface* mClientInterface;
- const AudioIODescriptorInterface* mInfoProvider;
};
class AudioSessionCollection :
- public DefaultKeyedVector<audio_session_t, sp<AudioSession> >,
- public AudioIODescriptorUpdateListener
+ public DefaultKeyedVector<audio_session_t, sp<AudioSession> >
{
public:
status_t addSession(audio_session_t session,
- const sp<AudioSession>& audioSession,
- AudioIODescriptorInterface *provider);
+ const sp<AudioSession>& audioSession);
status_t removeSession(audio_session_t session);
@@ -99,9 +90,6 @@
bool isSourceActive(audio_source_t source) const;
audio_source_t getHighestPrioritySource(bool activeOnly) const;
- // implementation of AudioIODescriptorUpdateListener
- virtual void onIODescriptorUpdate() const;
-
status_t dump(int fd, int spaces) 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
new file mode 100644
index 0000000..9efe57f
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2018 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 <vector>
+#include <map>
+#include <unistd.h>
+#include <sys/types.h>
+
+#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:
+ ClientDescriptor(audio_port_handle_t portId, uid_t uid, audio_session_t sessionId,
+ audio_attributes_t attributes, audio_config_base_t config,
+ audio_port_handle_t preferredDeviceId) :
+ mPortId(portId), mUid(uid), mSessionId(sessionId), mAttributes(attributes),
+ mConfig(config), mPreferredDeviceId(preferredDeviceId), mActive(false) {}
+ ~ClientDescriptor() override = default;
+
+ status_t dump(int fd, int spaces, int index);
+ virtual status_t dump(String8& dst, int spaces, int index);
+
+ audio_port_handle_t portId() const { return mPortId; }
+ uid_t uid() const { return mUid; }
+ audio_session_t session() const { return mSessionId; };
+ audio_attributes_t attributes() const { return mAttributes; }
+ audio_config_base_t config() const { return mConfig; }
+ audio_port_handle_t preferredDeviceId() const { return mPreferredDeviceId; };
+ void setActive(bool active) { mActive = active; }
+ bool active() const { return mActive; }
+
+private:
+ const audio_port_handle_t mPortId; // unique Id for this client
+ const uid_t mUid; // client UID
+ const audio_session_t mSessionId; // audio session ID
+ const audio_attributes_t mAttributes; // usage...
+ 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
+{
+public:
+ TrackClientDescriptor(audio_port_handle_t portId, uid_t uid, audio_session_t sessionId,
+ audio_attributes_t attributes, audio_config_base_t config,
+ audio_port_handle_t preferredDeviceId,
+ audio_stream_type_t stream, audio_output_flags_t flags) :
+ ClientDescriptor(portId, uid, sessionId, attributes, config, preferredDeviceId),
+ mStream(stream), mFlags(flags) {}
+ ~TrackClientDescriptor() override = default;
+
+ using ClientDescriptor::dump;
+ status_t dump(String8& dst, int spaces, int index) override;
+
+ audio_output_flags_t flags() const { return mFlags; }
+ audio_stream_type_t stream() const { return mStream; }
+
+private:
+ const audio_stream_type_t mStream;
+ const audio_output_flags_t mFlags;
+};
+
+class RecordClientDescriptor: public ClientDescriptor
+{
+public:
+ RecordClientDescriptor(audio_port_handle_t portId, uid_t uid, audio_session_t sessionId,
+ audio_attributes_t attributes, audio_config_base_t config,
+ audio_port_handle_t preferredDeviceId,
+ audio_source_t source, audio_input_flags_t flags) :
+ ClientDescriptor(portId, uid, sessionId, attributes, config, preferredDeviceId),
+ mSource(source), mFlags(flags) {}
+ ~RecordClientDescriptor() override = default;
+
+ using ClientDescriptor::dump;
+ status_t dump(String8& dst, int spaces, int index) override;
+
+ audio_source_t source() const { return mSource; }
+ audio_input_flags_t flags() const { return mFlags; }
+
+private:
+ const audio_source_t mSource;
+ 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;
+typedef std::map< audio_port_handle_t, sp<RecordClientDescriptor> > RecordClientMap;
+
+} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
index 2325e4f..c08e752 100644
--- a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
@@ -82,8 +82,8 @@
DeviceVector getDevicesFromTypeMask(audio_devices_t types) const;
sp<DeviceDescriptor> getDeviceFromId(audio_port_handle_t id) const;
sp<DeviceDescriptor> getDeviceFromTagName(const String8 &tagName) const;
-
- audio_devices_t getDevicesFromHwModule(audio_module_handle_t moduleHandle) const;
+ DeviceVector getDevicesFromHwModule(audio_module_handle_t moduleHandle) const;
+ audio_devices_t getDeviceTypesFromHwModule(audio_module_handle_t moduleHandle) const;
status_t dump(int fd, const String8 &tag, int spaces = 0, bool verbose = true) const;
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
index f0144db..2770e74 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
@@ -32,7 +32,7 @@
: mIoHandle(0),
mDevice(AUDIO_DEVICE_NONE), mPolicyMix(NULL),
mProfile(profile), mPatchHandle(AUDIO_PATCH_HANDLE_NONE), mId(0),
- mClientInterface(clientInterface)
+ mClientInterface(clientInterface), mGlobalRefCount(0)
{
if (profile != NULL) {
profile->pickAudioProfile(mSamplingRate, mChannelMask, mFormat);
@@ -164,7 +164,7 @@
status_t AudioInputDescriptor::addAudioSession(audio_session_t session,
const sp<AudioSession>& audioSession) {
- return mSessions.addSession(session, audioSession, /*AudioIODescriptorInterface*/this);
+ return mSessions.addSession(session, audioSession);
}
status_t AudioInputDescriptor::removeAudioSession(audio_session_t session) {
@@ -179,7 +179,11 @@
void AudioInputDescriptor::setPatchHandle(audio_patch_handle_t handle)
{
mPatchHandle = handle;
- mSessions.onIODescriptorUpdate();
+ for (size_t i = 0; i < mSessions.size(); i++) {
+ if (mSessions[i]->activeCount() > 0) {
+ updateSessionRecordingConfiguration(RECORD_CONFIG_EVENT_START, mSessions[i]);
+ }
+ }
}
audio_config_base_t AudioInputDescriptor::getConfig() const
@@ -266,7 +270,7 @@
LOG_ALWAYS_FATAL_IF(mProfile->curOpenCount < 1, "%s profile open count %u",
__FUNCTION__, mProfile->curOpenCount);
// do not call stop() here as stop() is supposed to be called after
- // AudioSession::changeActiveCount(-1) and we don't know how many sessions
+ // changeRefCount(session, -1) and we don't know how many sessions
// are still active at this time
if (isActive()) {
mProfile->curActiveCount--;
@@ -276,6 +280,78 @@
}
}
+void AudioInputDescriptor::changeRefCount(audio_session_t session, int delta)
+{
+ sp<AudioSession> audioSession = mSessions.valueFor(session);
+ if (audioSession == 0) {
+ return;
+ }
+ // handle session-independent ref count
+ uint32_t oldGlobalRefCount = mGlobalRefCount;
+ if ((delta + (int)mGlobalRefCount) < 0) {
+ ALOGW("changeRefCount() invalid delta %d globalRefCount %d", delta, mGlobalRefCount);
+ delta = -((int)mGlobalRefCount);
+ }
+ mGlobalRefCount += delta;
+ if ((oldGlobalRefCount == 0) && (mGlobalRefCount > 0)) {
+ if ((mPolicyMix != NULL) && ((mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0))
+ {
+ mClientInterface->onDynamicPolicyMixStateUpdate(mPolicyMix->mDeviceAddress,
+ MIX_STATE_MIXING);
+ }
+
+ } else if ((oldGlobalRefCount > 0) && (mGlobalRefCount == 0)) {
+ if ((mPolicyMix != NULL) && ((mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0))
+ {
+ mClientInterface->onDynamicPolicyMixStateUpdate(mPolicyMix->mDeviceAddress,
+ MIX_STATE_IDLE);
+ }
+ }
+
+ uint32_t oldActiveCount = audioSession->activeCount();
+ if ((delta + (int)oldActiveCount) < 0) {
+ ALOGW("changeRefCount() invalid delta %d for sesion %d active count %d",
+ delta, session, oldActiveCount);
+ delta = -((int)oldActiveCount);
+ }
+
+ audioSession->changeActiveCount(delta);
+
+ int event = RECORD_CONFIG_EVENT_NONE;
+ if ((oldActiveCount == 0) && (audioSession->activeCount() > 0)) {
+ event = RECORD_CONFIG_EVENT_START;
+ } else if ((oldActiveCount > 0) && (audioSession->activeCount() == 0)) {
+ event = RECORD_CONFIG_EVENT_STOP;
+ }
+ if (event != RECORD_CONFIG_EVENT_NONE) {
+ updateSessionRecordingConfiguration(event, audioSession);
+ }
+
+}
+
+void AudioInputDescriptor::updateSessionRecordingConfiguration(
+ int event, const sp<AudioSession>& audioSession) {
+
+ const audio_config_base_t sessionConfig = audioSession->config();
+ const record_client_info_t recordClientInfo = audioSession->recordClientInfo();
+ const audio_config_base_t config = getConfig();
+ mClientInterface->onRecordingConfigurationUpdate(event,
+ &recordClientInfo, &sessionConfig,
+ &config, mPatchHandle);
+}
+
+RecordClientVector AudioInputDescriptor::getClientsForSession(
+ audio_session_t session)
+{
+ RecordClientVector clients;
+ for (const auto &client : mClients) {
+ if (client.second->session() == session) {
+ clients.push_back(client.second);
+ }
+ }
+ return clients;
+}
+
status_t AudioInputDescriptor::dump(int fd)
{
const size_t SIZE = 256;
@@ -297,6 +373,13 @@
mSessions.dump(fd, 1);
+ size_t index = 0;
+ result = " AudioRecord clients:\n";
+ for (const auto& client: mClients) {
+ client.second->dump(result, 2, index++);
+ }
+ result.append(" \n");
+ write(fd, result.string(), result.size());
return NO_ERROR;
}
@@ -359,6 +442,19 @@
return devices;
}
+sp<AudioInputDescriptor> AudioInputCollection::getInputForClient(audio_port_handle_t portId)
+{
+ for (size_t i = 0; i < size(); i++) {
+ sp<AudioInputDescriptor> inputDesc = valueAt(i);
+ for (const auto& client : inputDesc->clients()) {
+ if (client.second->portId() == portId) {
+ return inputDesc;
+ }
+ }
+ }
+ return 0;
+}
+
status_t AudioInputCollection::dump(int fd) const
{
const size_t SIZE = 256;
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index 3c69de5..39fce4d 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -224,6 +224,13 @@
i, mCurVolume[i], mRefCount[i], mMuteCount[i]);
result.append(buffer);
}
+
+ result.append(" AudioTrack clients:\n");
+ size_t index = 0;
+ for (const auto& client : mClients) {
+ client.second->dump(result, 2, index++);
+ }
+ result.append(" \n");
write(fd, result.string(), result.size());
return NO_ERROR;
@@ -551,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)
{
}
@@ -569,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;
}
@@ -583,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);
}
@@ -731,6 +738,18 @@
return devices;
}
+sp<SwAudioOutputDescriptor> SwAudioOutputCollection::getOutputForClient(audio_port_handle_t portId)
+{
+ for (size_t i = 0; i < size(); i++) {
+ sp<SwAudioOutputDescriptor> outputDesc = valueAt(i);
+ for (const auto& client : outputDesc->clients()) {
+ if (client.second->portId() == portId) {
+ return outputDesc;
+ }
+ }
+ }
+ return 0;
+}
status_t SwAudioOutputCollection::dump(int fd) const
{
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioProfile.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioProfile.cpp
index 26af9b4..d04beec 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioProfile.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioProfile.cpp
@@ -14,20 +14,53 @@
* limitations under the License.
*/
+#include <algorithm>
+#include <set>
+#include <string>
+
#define LOG_TAG "APM::AudioProfile"
//#define LOG_NDEBUG 0
-#include "AudioProfile.h"
-#include "AudioPort.h"
-#include "HwModule.h"
-#include "AudioGain.h"
-#include <utils/SortedVector.h>
-#include "TypeConverter.h"
#include <media/AudioResamplerPublic.h>
-#include <algorithm>
+#include <utils/Errors.h>
+
+#include "AudioGain.h"
+#include "AudioPort.h"
+#include "AudioProfile.h"
+#include "HwModule.h"
+#include "TypeConverter.h"
namespace android {
+ChannelsVector ChannelsVector::asInMask() const
+{
+ ChannelsVector inMaskVector;
+ for (const auto& channel : *this) {
+ if (audio_channel_mask_out_to_in(channel) != AUDIO_CHANNEL_INVALID) {
+ inMaskVector.add(audio_channel_mask_out_to_in(channel));
+ }
+ }
+ return inMaskVector;
+}
+
+ChannelsVector ChannelsVector::asOutMask() const
+{
+ ChannelsVector outMaskVector;
+ for (const auto& channel : *this) {
+ if (audio_channel_mask_in_to_out(channel) != AUDIO_CHANNEL_INVALID) {
+ outMaskVector.add(audio_channel_mask_in_to_out(channel));
+ }
+ }
+ return outMaskVector;
+}
+
+bool operator == (const AudioProfile &left, const AudioProfile &compareTo)
+{
+ return (left.getFormat() == compareTo.getFormat()) &&
+ (left.getChannels() == compareTo.getChannels()) &&
+ (left.getSampleRates() == compareTo.getSampleRates());
+}
+
static AudioProfile* createFullDynamicImpl()
{
AudioProfile* dynamicProfile = new AudioProfile(gDynamicFormat,
@@ -45,6 +78,48 @@
return dynamicProfile;
}
+AudioProfile::AudioProfile(audio_format_t format,
+ audio_channel_mask_t channelMasks,
+ uint32_t samplingRate) :
+ mName(String8("")),
+ mFormat(format)
+{
+ mChannelMasks.add(channelMasks);
+ mSamplingRates.add(samplingRate);
+}
+
+AudioProfile::AudioProfile(audio_format_t format,
+ const ChannelsVector &channelMasks,
+ const SampleRateVector &samplingRateCollection) :
+ mName(String8("")),
+ mFormat(format),
+ mChannelMasks(channelMasks),
+ mSamplingRates(samplingRateCollection) {}
+
+void AudioProfile::setChannels(const ChannelsVector &channelMasks)
+{
+ if (mIsDynamicChannels) {
+ mChannelMasks = channelMasks;
+ }
+}
+
+void AudioProfile::setSampleRates(const SampleRateVector &sampleRates)
+{
+ if (mIsDynamicRate) {
+ mSamplingRates = sampleRates;
+ }
+}
+
+void AudioProfile::clear()
+{
+ if (mIsDynamicChannels) {
+ mChannelMasks.clear();
+ }
+ if (mIsDynamicRate) {
+ mSamplingRates.clear();
+ }
+}
+
status_t AudioProfile::checkExact(uint32_t samplingRate, audio_channel_mask_t channelMask,
audio_format_t format) const
{
@@ -56,27 +131,6 @@
return BAD_VALUE;
}
-template <typename T>
-bool operator == (const SortedVector<T> &left, const SortedVector<T> &right)
-{
- if (left.size() != right.size()) {
- return false;
- }
- for(size_t index = 0; index < right.size(); index++) {
- if (left[index] != right[index]) {
- return false;
- }
- }
- return true;
-}
-
-bool operator == (const AudioProfile &left, const AudioProfile &compareTo)
-{
- return (left.getFormat() == compareTo.getFormat()) &&
- (left.getChannels() == compareTo.getChannels()) &&
- (left.getSampleRates() == compareTo.getSampleRates());
-}
-
status_t AudioProfile::checkCompatibleSamplingRate(uint32_t samplingRate,
uint32_t &updatedSamplingRate) const
{
@@ -242,6 +296,50 @@
write(fd, result.string(), result.size());
}
+ssize_t AudioProfileVector::add(const sp<AudioProfile> &profile)
+{
+ ssize_t index = Vector::add(profile);
+ // we sort from worst to best, so that AUDIO_FORMAT_DEFAULT is always the first entry.
+ // TODO: compareFormats could be a lambda to convert between pointer-to-format to format:
+ // [](const audio_format_t *format1, const audio_format_t *format2) {
+ // return compareFormats(*format1, *format2);
+ // }
+ sort(compareFormats);
+ return index;
+}
+
+ssize_t AudioProfileVector::addProfileFromHal(const sp<AudioProfile> &profileToAdd)
+{
+ // Check valid profile to add:
+ if (!profileToAdd->hasValidFormat()) {
+ return -1;
+ }
+ if (!profileToAdd->hasValidChannels() && !profileToAdd->hasValidRates()) {
+ FormatVector formats;
+ formats.add(profileToAdd->getFormat());
+ setFormats(FormatVector(formats));
+ return 0;
+ }
+ if (!profileToAdd->hasValidChannels() && profileToAdd->hasValidRates()) {
+ setSampleRatesFor(profileToAdd->getSampleRates(), profileToAdd->getFormat());
+ return 0;
+ }
+ if (profileToAdd->hasValidChannels() && !profileToAdd->hasValidRates()) {
+ setChannelsFor(profileToAdd->getChannels(), profileToAdd->getFormat());
+ return 0;
+ }
+ // Go through the list of profile to avoid duplicates
+ for (size_t profileIndex = 0; profileIndex < size(); profileIndex++) {
+ const sp<AudioProfile> &profile = itemAt(profileIndex);
+ if (profile->isValid() && profile == profileToAdd) {
+ // Nothing to do
+ return profileIndex;
+ }
+ }
+ profileToAdd->setDynamicFormat(true); // set the format as dynamic to allow removal
+ return add(profileToAdd);
+}
+
status_t AudioProfileVector::checkExactProfile(uint32_t samplingRate,
audio_channel_mask_t channelMask,
audio_format_t format) const
@@ -298,6 +396,233 @@
return BAD_VALUE;
}
+void AudioProfileVector::clearProfiles()
+{
+ for (size_t i = size(); i != 0; ) {
+ sp<AudioProfile> profile = itemAt(--i);
+ if (profile->isDynamicFormat() && profile->hasValidFormat()) {
+ removeAt(i);
+ continue;
+ }
+ profile->clear();
+ }
+}
+
+// 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++) {
+ if (itemAt(i)->isValid()) {
+ return itemAt(i);
+ }
+ }
+ return 0;
+}
+
+sp<AudioProfile> AudioProfileVector::getFirstValidProfileFor(audio_format_t format) const
+{
+ for (size_t i = 0; i < size(); i++) {
+ if (itemAt(i)->isValid() && itemAt(i)->getFormat() == format) {
+ return itemAt(i);
+ }
+ }
+ return 0;
+}
+
+FormatVector AudioProfileVector::getSupportedFormats() const
+{
+ FormatVector supportedFormats;
+ for (size_t i = 0; i < size(); i++) {
+ if (itemAt(i)->hasValidFormat()) {
+ supportedFormats.add(itemAt(i)->getFormat());
+ }
+ }
+ return supportedFormats;
+}
+
+bool AudioProfileVector::hasDynamicChannelsFor(audio_format_t format) const
+{
+ for (size_t i = 0; i < size(); i++) {
+ sp<AudioProfile> profile = itemAt(i);
+ if (profile->getFormat() == format && profile->isDynamicChannels()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool AudioProfileVector::hasDynamicProfile() const
+{
+ for (size_t i = 0; i < size(); i++) {
+ if (itemAt(i)->isDynamic()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool AudioProfileVector::hasDynamicRateFor(audio_format_t format) const
+{
+ for (size_t i = 0; i < size(); i++) {
+ sp<AudioProfile> profile = itemAt(i);
+ if (profile->getFormat() == format && profile->isDynamicRate()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void AudioProfileVector::setFormats(const FormatVector &formats)
+{
+ // Only allow to change the format of dynamic profile
+ sp<AudioProfile> dynamicFormatProfile = getProfileFor(gDynamicFormat);
+ if (dynamicFormatProfile == 0) {
+ return;
+ }
+ for (size_t i = 0; i < formats.size(); i++) {
+ sp<AudioProfile> profile = new AudioProfile(formats[i],
+ dynamicFormatProfile->getChannels(),
+ dynamicFormatProfile->getSampleRates());
+ profile->setDynamicFormat(true);
+ profile->setDynamicChannels(dynamicFormatProfile->isDynamicChannels());
+ profile->setDynamicRate(dynamicFormatProfile->isDynamicRate());
+ add(profile);
+ }
+}
+
+void AudioProfileVector::dump(int fd, int spaces) const
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+
+ snprintf(buffer, SIZE, "%*s- Profiles:\n", spaces, "");
+ write(fd, buffer, strlen(buffer));
+ for (size_t i = 0; i < size(); i++) {
+ snprintf(buffer, SIZE, "%*sProfile %zu:", spaces + 4, "", i);
+ write(fd, buffer, strlen(buffer));
+ itemAt(i)->dump(fd, spaces + 8);
+ }
+}
+
+sp<AudioProfile> AudioProfileVector::getProfileFor(audio_format_t format) const
+{
+ for (size_t i = 0; i < size(); i++) {
+ if (itemAt(i)->getFormat() == format) {
+ return itemAt(i);
+ }
+ }
+ return 0;
+}
+
+void AudioProfileVector::setSampleRatesFor(
+ const SampleRateVector &sampleRates, audio_format_t format)
+{
+ for (size_t i = 0; i < size(); i++) {
+ sp<AudioProfile> profile = itemAt(i);
+ if (profile->getFormat() == format && profile->isDynamicRate()) {
+ if (profile->hasValidRates()) {
+ // Need to create a new profile with same format
+ sp<AudioProfile> profileToAdd = new AudioProfile(format, profile->getChannels(),
+ sampleRates);
+ profileToAdd->setDynamicFormat(true); // need to set to allow cleaning
+ add(profileToAdd);
+ } else {
+ profile->setSampleRates(sampleRates);
+ }
+ return;
+ }
+ }
+}
+
+void AudioProfileVector::setChannelsFor(const ChannelsVector &channelMasks, audio_format_t format)
+{
+ for (size_t i = 0; i < size(); i++) {
+ sp<AudioProfile> profile = itemAt(i);
+ if (profile->getFormat() == format && profile->isDynamicChannels()) {
+ if (profile->hasValidChannels()) {
+ // Need to create a new profile with same format
+ sp<AudioProfile> profileToAdd = new AudioProfile(format, channelMasks,
+ profile->getSampleRates());
+ profileToAdd->setDynamicFormat(true); // need to set to allow cleaning
+ add(profileToAdd);
+ } else {
+ profile->setChannels(channelMasks);
+ }
+ return;
+ }
+ }
+}
+
+// static
int AudioProfileVector::compareFormats(const sp<AudioProfile> *profile1,
const sp<AudioProfile> *profile2)
{
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioSession.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioSession.cpp
index 91dee35..5ea4c92 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioSession.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioSession.cpp
@@ -35,14 +35,11 @@
audio_channel_mask_t channelMask,
audio_input_flags_t flags,
uid_t uid,
- bool isSoundTrigger,
- AudioMix* policyMix,
- AudioPolicyClientInterface *clientInterface) :
+ bool isSoundTrigger) :
mRecordClientInfo({ .uid = uid, .session = session, .source = inputSource}),
mConfig({ .format = format, .sample_rate = sampleRate, .channel_mask = channelMask}),
mFlags(flags), mIsSoundTrigger(isSoundTrigger),
- mOpenCount(1), mActiveCount(0), mPolicyMix(policyMix), mClientInterface(clientInterface),
- mInfoProvider(NULL)
+ mOpenCount(1), mActiveCount(0)
{
}
@@ -60,7 +57,6 @@
uint32_t AudioSession::changeActiveCount(int delta)
{
- const uint32_t oldActiveCount = mActiveCount;
if ((delta + (int)mActiveCount) < 0) {
ALOGW("%s invalid delta %d, active count %d",
__FUNCTION__, delta, mActiveCount);
@@ -68,34 +64,6 @@
}
mActiveCount += delta;
ALOGV("%s active count %d", __FUNCTION__, mActiveCount);
- int event = RECORD_CONFIG_EVENT_NONE;
-
- if ((oldActiveCount == 0) && (mActiveCount > 0)) {
- event = RECORD_CONFIG_EVENT_START;
- } else if ((oldActiveCount > 0) && (mActiveCount == 0)) {
- event = RECORD_CONFIG_EVENT_STOP;
- }
-
- if (event != RECORD_CONFIG_EVENT_NONE) {
- // Dynamic policy callback:
- // if input maps to a dynamic policy with an activity listener, notify of state change
- if ((mPolicyMix != NULL) && ((mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0))
- {
- mClientInterface->onDynamicPolicyMixStateUpdate(mPolicyMix->mDeviceAddress,
- (event == RECORD_CONFIG_EVENT_START) ? MIX_STATE_MIXING : MIX_STATE_IDLE);
- }
-
- // Recording configuration callback:
- const AudioIODescriptorInterface* provider = mInfoProvider;
- const audio_config_base_t deviceConfig = (provider != NULL) ? provider->getConfig() :
- AUDIO_CONFIG_BASE_INITIALIZER;
- const audio_patch_handle_t patchHandle = (provider != NULL) ? provider->getPatchHandle() :
- AUDIO_PATCH_HANDLE_NONE;
- if (patchHandle != AUDIO_PATCH_HANDLE_NONE) {
- mClientInterface->onRecordingConfigurationUpdate(event, &mRecordClientInfo,
- &mConfig, &deviceConfig, patchHandle);
- }
- }
return mActiveCount;
}
@@ -114,27 +82,6 @@
return false;
}
-void AudioSession::setInfoProvider(AudioIODescriptorInterface *provider)
-{
- mInfoProvider = provider;
-}
-
-void AudioSession::onIODescriptorUpdate() const
-{
- if (mActiveCount > 0) {
- // resend the callback after requerying the informations from the info provider
- const AudioIODescriptorInterface* provider = mInfoProvider;
- const audio_config_base_t deviceConfig = (provider != NULL) ? provider->getConfig() :
- AUDIO_CONFIG_BASE_INITIALIZER;
- const audio_patch_handle_t patchHandle = (provider != NULL) ? provider->getPatchHandle() :
- AUDIO_PATCH_HANDLE_NONE;
- if (patchHandle != AUDIO_PATCH_HANDLE_NONE) {
- mClientInterface->onRecordingConfigurationUpdate(RECORD_CONFIG_EVENT_START,
- &mRecordClientInfo, &mConfig, &deviceConfig, patchHandle);
- }
- }
-}
-
status_t AudioSession::dump(int fd, int spaces, int index) const
{
const size_t SIZE = 256;
@@ -169,8 +116,7 @@
}
status_t AudioSessionCollection::addSession(audio_session_t session,
- const sp<AudioSession>& audioSession,
- AudioIODescriptorInterface *provider)
+ const sp<AudioSession>& audioSession)
{
ssize_t index = indexOfKey(session);
@@ -178,7 +124,6 @@
ALOGW("addSession() session %d already in", session);
return ALREADY_EXISTS;
}
- audioSession->setInfoProvider(provider);
add(session, audioSession);
ALOGV("addSession() session %d client %d source %d",
session, audioSession->uid(), audioSession->inputSource());
@@ -194,7 +139,6 @@
return ALREADY_EXISTS;
}
ALOGV("removeSession() session %d", session);
- valueAt(index)->setInfoProvider(NULL);
removeItemsAt(index);
return NO_ERROR;
}
@@ -271,13 +215,6 @@
return source;
}
-void AudioSessionCollection::onIODescriptorUpdate() const
-{
- for (size_t i = 0; i < size(); i++) {
- valueAt(i)->onIODescriptorUpdate();
- }
-}
-
status_t AudioSessionCollection::dump(int fd, int spaces) const
{
const size_t SIZE = 256;
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
new file mode 100644
index 0000000..5aca3cc
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2018 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_ClientDescriptor"
+//#define LOG_NDEBUG 0
+
+#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 {
+
+status_t ClientDescriptor::dump(int fd, int spaces, int index)
+{
+ 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());
+ }
+
+ return status;
+}
+
+status_t ClientDescriptor::dump(String8& out, int spaces, int index)
+{
+ out.appendFormat("%*sClient %d:\n", spaces, "", index+1);
+ out.appendFormat("%*s- Port ID: %d Session Id: %d UID: %d\n", spaces, "",
+ mPortId, mSessionId, mUid);
+ out.appendFormat("%*s- Format: %08x Sampling rate: %d Channels: %08x\n", spaces, "",
+ mConfig.format, mConfig.sample_rate, mConfig.channel_mask);
+ out.appendFormat("%*s- Preferred Device Id: %08x\n", spaces, "", mPreferredDeviceId);
+ out.appendFormat("%*s- State: %s\n", spaces, "", mActive ? "Active" : "Inactive");
+ return NO_ERROR;
+}
+
+status_t TrackClientDescriptor::dump(String8& out, int spaces, int index)
+{
+ ClientDescriptor::dump(out, spaces, index);
+
+ out.appendFormat("%*s- Stream: %d flags: %08x\n", spaces, "", mStream, mFlags);
+
+ return NO_ERROR;
+}
+
+status_t RecordClientDescriptor::dump(String8& out, int spaces, int index)
+{
+ ClientDescriptor::dump(out, spaces, index);
+
+ out.appendFormat("%*s- Source: %d flags: %08x\n", spaces, "", mSource, mFlags);
+
+ 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/common/managerdefinitions/src/DeviceDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
index d3cc8b9..1638645 100644
--- a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
@@ -121,17 +121,28 @@
return ret;
}
-audio_devices_t DeviceVector::getDevicesFromHwModule(audio_module_handle_t moduleHandle) const
+DeviceVector DeviceVector::getDevicesFromHwModule(audio_module_handle_t moduleHandle) const
{
- audio_devices_t devices = AUDIO_DEVICE_NONE;
- for (size_t i = 0; i < size(); i++) {
- if (itemAt(i)->getModuleHandle() == moduleHandle) {
- devices |= itemAt(i)->type();
+ DeviceVector devices;
+ for (const auto& device : *this) {
+ if (device->getModuleHandle() == moduleHandle) {
+ devices.add(device);
}
}
return devices;
}
+audio_devices_t DeviceVector::getDeviceTypesFromHwModule(audio_module_handle_t moduleHandle) const
+{
+ audio_devices_t deviceTypes = AUDIO_DEVICE_NONE;
+ for (const auto& device : *this) {
+ if (device->getModuleHandle() == moduleHandle) {
+ deviceTypes |= device->type();
+ }
+ }
+ return deviceTypes;
+}
+
sp<DeviceDescriptor> DeviceVector::getDevice(audio_devices_t type, const String8& address) const
{
sp<DeviceDescriptor> device;
diff --git a/services/audiopolicy/common/managerdefinitions/src/SessionRoute.cpp b/services/audiopolicy/common/managerdefinitions/src/SessionRoute.cpp
index 38ab560..440a4e7 100644
--- a/services/audiopolicy/common/managerdefinitions/src/SessionRoute.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/SessionRoute.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "APM::SessionRoute"
+#define LOG_TAG "APM_SessionRoute"
//#define LOG_NDEBUG 0
#include "SessionRoute.h"
@@ -122,19 +122,17 @@
audio_devices_t SessionRouteMap::getActiveDeviceForStream(audio_stream_type_t streamType,
const DeviceVector& availableDevices)
{
- audio_devices_t device = AUDIO_DEVICE_NONE;
-
for (size_t index = 0; index < size(); index++) {
sp<SessionRoute> route = valueAt(index);
if (streamType == route->mStreamType && route->isActiveOrChanged()
&& route->mDeviceDescriptor != 0) {
- device = route->mDeviceDescriptor->type();
+ audio_devices_t device = route->mDeviceDescriptor->type();
if (!availableDevices.getDevicesFromTypeMask(device).isEmpty()) {
- break;
+ return device;
}
}
}
- return device;
+ return AUDIO_DEVICE_NONE;
}
} // namespace android
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index ca64d86..30f275f 100644
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -313,7 +313,7 @@
audio_devices_t txDevice = getDeviceForInputSource(AUDIO_SOURCE_VOICE_COMMUNICATION);
sp<AudioOutputDescriptor> primaryOutput = outputs.getPrimaryOutput();
audio_devices_t availPrimaryInputDevices =
- availableInputDevices.getDevicesFromHwModule(primaryOutput->getModuleHandle());
+ availableInputDevices.getDeviceTypesFromHwModule(primaryOutput->getModuleHandle());
// TODO: getPrimaryOutput return only devices from first module in
// audio_policy_configuration.xml, hearing aid is not there, but it's
@@ -668,9 +668,8 @@
if ((getPhoneState() == AUDIO_MODE_IN_CALL) &&
(availableOutputDevices.types() & AUDIO_DEVICE_OUT_TELEPHONY_TX) == 0) {
sp<AudioOutputDescriptor> primaryOutput = outputs.getPrimaryOutput();
- availableDeviceTypes =
- availableInputDevices.getDevicesFromHwModule(primaryOutput->getModuleHandle())
- & ~AUDIO_DEVICE_BIT_IN;
+ availableDeviceTypes = availableInputDevices.getDeviceTypesFromHwModule(
+ primaryOutput->getModuleHandle()) & ~AUDIO_DEVICE_BIT_IN;
}
switch (mForceUse[AUDIO_POLICY_FORCE_FOR_COMMUNICATION]) {
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index bc9514f..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));
@@ -505,13 +517,7 @@
// symmetric to the one in startInput()
for (const auto& activeDesc : mInputs.getActiveInputs()) {
if (activeDesc->hasSameHwModuleAs(txSourceDeviceDesc)) {
- AudioSessionCollection activeSessions =
- activeDesc->getAudioSessions(true /*activeOnly*/);
- for (size_t j = 0; j < activeSessions.size(); j++) {
- audio_session_t activeSession = activeSessions.keyAt(j);
- stopInput(activeDesc->mIoHandle, activeSession);
- releaseInput(activeDesc->mIoHandle, activeSession);
- }
+ closeSessions(activeDesc, true /*activeOnly*/);
}
}
}
@@ -531,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);
@@ -779,6 +785,12 @@
audio_port_handle_t *portId)
{
audio_attributes_t attributes;
+ DeviceVector outputDevices;
+ routing_strategy strategy;
+ audio_devices_t device;
+ audio_port_handle_t requestedDeviceId = *selectedDeviceId;
+ audio_devices_t msdDevice = getMsdAudioOutDeviceTypes();
+
if (attr != NULL) {
if (!isValidAttributes(attr)) {
ALOGE("getOutputForAttr() invalid attributes: usage=%d content=%d flags=0x%x tags=[%s]",
@@ -820,7 +832,7 @@
*stream = streamTypefromAttributesInt(&attributes);
*output = desc->mIoHandle;
ALOGV("getOutputForAttr() returns output %d", *output);
- return NO_ERROR;
+ goto exit;
}
// Virtual sources must always be dynamicaly or explicitly routed
@@ -844,8 +856,8 @@
// explicit route. Is that the intended and necessary behavior?
mOutputRoutes.addRoute(session, *stream, SessionRoute::SOURCE_TYPE_NA, deviceDesc, uid);
- routing_strategy strategy = (routing_strategy) getStrategyForAttr(&attributes);
- audio_devices_t device = getDeviceForStrategy(strategy, false /*fromCache*/);
+ strategy = (routing_strategy) getStrategyForAttr(&attributes);
+ device = getDeviceForStrategy(strategy, false /*fromCache*/);
if ((attributes.flags & AUDIO_FLAG_HW_AV_SYNC) != 0) {
*flags = (audio_output_flags_t)(*flags | AUDIO_OUTPUT_FLAG_HW_AV_SYNC);
@@ -870,17 +882,41 @@
"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;
}
- DeviceVector outputDevices = mAvailableOutputDevices.getDevicesFromTypeMask(device);
+ outputDevices = mAvailableOutputDevices.getDevicesFromTypeMask(device);
*selectedDeviceId = outputDevices.size() > 0 ? outputDevices.itemAt(0)->getId()
: AUDIO_PORT_HANDLE_NONE;
- ALOGV(" getOutputForAttr() returns output %d selectedDeviceId %d", *output, *selectedDeviceId);
+exit:
+ audio_config_base_t clientConfig = {.sample_rate = config->sample_rate,
+ .format = config->format,
+ .channel_mask = config->channel_mask };
+ sp<TrackClientDescriptor> clientDesc =
+ new TrackClientDescriptor(*portId, uid, session,
+ attributes, clientConfig, requestedDeviceId, *stream, *flags);
+ sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueFor(*output);
+ outputDesc->clients().emplace(*portId, clientDesc);
+
+ ALOGV(" getOutputForAttr() returns output %d selectedDeviceId %d for port ID %d",
+ *output, *selectedDeviceId, *portId);
return NO_ERROR;
}
@@ -1042,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)
@@ -1122,19 +1316,21 @@
return outputs[0];
}
-status_t AudioPolicyManager::startOutput(audio_io_handle_t output,
- audio_stream_type_t stream,
- audio_session_t session)
+status_t AudioPolicyManager::startOutput(audio_port_handle_t portId)
{
- ALOGV("startOutput() output %d, stream %d, session %d",
- output, stream, session);
- ssize_t index = mOutputs.indexOfKey(output);
- if (index < 0) {
- ALOGW("startOutput() unknown output %d", output);
+ ALOGV("%s portId %d", __FUNCTION__, portId);
+
+ sp<SwAudioOutputDescriptor> outputDesc = mOutputs.getOutputForClient(portId);
+ if (outputDesc == 0) {
+ ALOGW("startOutput() no output for client %d", portId);
return BAD_VALUE;
}
+ sp<TrackClientDescriptor> client = outputDesc->clients()[portId];
+ audio_stream_type_t stream = client->stream();
+ audio_session_t session = client->session();
- sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueAt(index);
+ ALOGV("startOutput() output %d, stream %d, session %d",
+ outputDesc->mIoHandle, stream, session);
status_t status = outputDesc->start();
if (status != NO_ERROR) {
@@ -1158,7 +1354,7 @@
} else if (mOutputRoutes.getAndClearRouteChanged(session)) {
newDevice = getNewOutputDevice(outputDesc, false /*fromCache*/);
if (newDevice != outputDesc->device()) {
- checkStrategyRoute(getStrategy(stream), output);
+ checkStrategyRoute(getStrategy(stream), outputDesc->mIoHandle);
}
} else {
newDevice = AUDIO_DEVICE_NONE;
@@ -1326,19 +1522,20 @@
return NO_ERROR;
}
-
-status_t AudioPolicyManager::stopOutput(audio_io_handle_t output,
- audio_stream_type_t stream,
- audio_session_t session)
+status_t AudioPolicyManager::stopOutput(audio_port_handle_t portId)
{
- ALOGV("stopOutput() output %d, stream %d, session %d", output, stream, session);
- ssize_t index = mOutputs.indexOfKey(output);
- if (index < 0) {
- ALOGW("stopOutput() unknown output %d", output);
+ ALOGV("%s portId %d", __FUNCTION__, portId);
+
+ sp<SwAudioOutputDescriptor> outputDesc = mOutputs.getOutputForClient(portId);
+ if (outputDesc == 0) {
+ ALOGW("stopOutput() no output for client %d", portId);
return BAD_VALUE;
}
+ sp<TrackClientDescriptor> client = outputDesc->clients()[portId];
+ audio_stream_type_t stream = client->stream();
+ audio_session_t session = client->session();
- sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueAt(index);
+ ALOGV("stopOutput() output %d, stream %d, session %d", outputDesc->mIoHandle, stream, session);
if (outputDesc->mRefCount[stream] == 1) {
// Automatically disable the remote submix input when output is stopped on a
@@ -1435,32 +1632,35 @@
}
}
-void AudioPolicyManager::releaseOutput(audio_io_handle_t output,
- audio_stream_type_t stream __unused,
- audio_session_t session __unused)
+void AudioPolicyManager::releaseOutput(audio_port_handle_t portId)
{
- ALOGV("releaseOutput() %d", output);
- ssize_t index = mOutputs.indexOfKey(output);
- if (index < 0) {
- ALOGW("releaseOutput() releasing unknown output %d", output);
+ ALOGV("%s portId %d", __FUNCTION__, portId);
+
+ sp<SwAudioOutputDescriptor> outputDesc = mOutputs.getOutputForClient(portId);
+ if (outputDesc == 0) {
+ ALOGW("releaseOutput() no output for client %d", portId);
return;
}
+ sp<TrackClientDescriptor> client = outputDesc->clients()[portId];
+ audio_session_t session = client->session();
+
+ ALOGV("releaseOutput() %d", outputDesc->mIoHandle);
// Routing
mOutputRoutes.removeRoute(session);
- sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(index);
- if (desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) {
- if (desc->mDirectOpenCount <= 0) {
+ if (outputDesc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) {
+ if (outputDesc->mDirectOpenCount <= 0) {
ALOGW("releaseOutput() invalid open count %d for output %d",
- desc->mDirectOpenCount, output);
+ outputDesc->mDirectOpenCount, outputDesc->mIoHandle);
return;
}
- if (--desc->mDirectOpenCount == 0) {
- closeOutput(output);
+ if (--outputDesc->mDirectOpenCount == 0) {
+ closeOutput(outputDesc->mIoHandle);
mpClientInterface->onAudioPortListUpdate();
}
}
+ outputDesc->clients().erase(portId);
}
@@ -1485,6 +1685,9 @@
audio_source_t inputSource = attr->source;
AudioMix *policyMix = NULL;
DeviceVector inputDevices;
+ sp<AudioInputDescriptor> inputDesc;
+ sp<RecordClientDescriptor> clientDesc;
+ audio_port_handle_t requestedDeviceId = *selectedDeviceId;
if (inputSource == AUDIO_SOURCE_DEFAULT) {
inputSource = AUDIO_SOURCE_MIC;
@@ -1540,7 +1743,7 @@
: AUDIO_PORT_HANDLE_NONE;
ALOGI("%s reusing MMAP input %d for session %d", __FUNCTION__, *input, session);
- return NO_ERROR;
+ goto exit;
}
*input = AUDIO_IO_HANDLE_NONE;
@@ -1606,8 +1809,14 @@
*selectedDeviceId = inputDevices.size() > 0 ? inputDevices.itemAt(0)->getId()
: AUDIO_PORT_HANDLE_NONE;
- ALOGV("getInputForAttr() returns input %d type %d selectedDeviceId %d",
- *input, *inputType, *selectedDeviceId);
+exit:
+ clientDesc = new RecordClientDescriptor(*portId, uid, session,
+ *attr, *config, requestedDeviceId, inputSource, flags);
+ inputDesc = mInputs.valueFor(*input);
+ inputDesc->clients().emplace(*portId, clientDesc);
+
+ ALOGV("getInputForAttr() returns input %d type %d selectedDeviceId %d for port ID %d",
+ *input, *inputType, *selectedDeviceId, *portId);
return NO_ERROR;
@@ -1689,74 +1898,7 @@
config->channel_mask,
flags,
uid,
- isSoundTrigger,
- policyMix, mpClientInterface);
-
-// FIXME: disable concurrent capture until UI is ready
-#if 0
- // 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:
- // - it shares the same profile
- // AND
- // - it is not a reroute submix input
- // AND
- // - it is: not used for sound trigger
- // OR
- // used for sound trigger and all clients use the same session ID
- //
- if ((profile == desc->mProfile) &&
- (isSoundTrigger == desc->isSoundTrigger()) &&
- !is_virtual_input_device(device)) {
-
- sp<AudioSession> as = desc->getAudioSession(session);
- if (as != 0) {
- // do not allow unmatching properties on same session
- if (as->matches(audioSession)) {
- as->changeOpenCount(1);
- } else {
- ALOGW("getInputForDevice() record with different attributes"
- " exists for session %d", session);
- continue;
- }
- } else if (isSoundTrigger) {
- continue;
- }
-
- // 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 != config->channel_mask ||
- !audio_formats_match(desc->mFormat, config->format)) &&
- (source_priority(desc->getHighestPrioritySource(false /*activeOnly*/)) <
- source_priority(inputSource)))) {
- reusedInputDesc = desc;
- continue;
- } else {
- desc->addAudioSession(session, audioSession);
- ALOGV("%s: reusing input %d", __FUNCTION__, mInputs.keyAt(i));
- return mInputs.keyAt(i);
- }
- }
- }
-
- 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);
- }
- }
-#endif
+ isSoundTrigger);
if (!profile->canOpenNewIo()) {
return AUDIO_IO_HANDLE_NONE;
@@ -1877,44 +2019,32 @@
}
-status_t AudioPolicyManager::startInput(audio_io_handle_t input,
- audio_session_t session,
+status_t AudioPolicyManager::startInput(audio_port_handle_t portId,
bool silenced,
concurrency_type__mask_t *concurrency)
{
+ *concurrency = API_INPUT_CONCURRENCY_NONE;
+
+ ALOGV("%s portId %d", __FUNCTION__, portId);
+
+ sp<AudioInputDescriptor> inputDesc = mInputs.getInputForClient(portId);
+ if (inputDesc == 0) {
+ ALOGW("startInput() no input for client %d", portId);
+ return BAD_VALUE;
+ }
+ sp<RecordClientDescriptor> client = inputDesc->clients()[portId];
+ audio_session_t session = client->session();
+ audio_io_handle_t input = inputDesc->mIoHandle;
ALOGV("AudioPolicyManager::startInput(input:%d, session:%d, silenced:%d, concurrency:%d)",
input, session, silenced, *concurrency);
- *concurrency = API_INPUT_CONCURRENCY_NONE;
-
- ssize_t index = mInputs.indexOfKey(input);
- if (index < 0) {
- ALOGW("startInput() unknown input %d", input);
- return BAD_VALUE;
- }
- sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(index);
-
sp<AudioSession> audioSession = inputDesc->getAudioSession(session);
if (audioSession == 0) {
ALOGW("startInput() unknown session %d on input %d", session, input);
return BAD_VALUE;
}
-// FIXME: disable concurrent capture until UI is ready
-#if 0
- if (!isConcurentCaptureAllowed(inputDesc, audioSession)) {
- ALOGW("startInput(%d) failed: other input already started", input);
- return INVALID_OPERATION;
- }
-
- if (isInCall()) {
- *concurrency |= API_INPUT_CONCURRENCY_CALL;
- }
- if (mInputs.activeInputsCountOnDevices() != 0) {
- *concurrency |= API_INPUT_CONCURRENCY_CAPTURE;
- }
-#else
if (!is_virtual_input_device(inputDesc->mDevice)) {
if (mCallTxPatch != 0 &&
inputDesc->getModuleHandle() == mCallTxPatch->mPatch.sources[0].ext.device.hw_module) {
@@ -1939,11 +2069,8 @@
true /*activeOnly*/);
sp<AudioSession> activeSession = activeSessions.valueAt(0);
if (activeSession->isSilenced()) {
- audio_io_handle_t activeInput = activeDesc->mIoHandle;
- audio_session_t activeSessionId = activeSession->session();
- stopInput(activeInput, activeSessionId);
- releaseInput(activeInput, activeSessionId);
- ALOGV("startInput(%d) stopping silenced input %d", input, activeInput);
+ closeSession(activeDesc, activeSession);
+ ALOGV("startInput() session %d stopping silenced session %d", session, activeSession->session());
activeInputs = mInputs.getActiveInputs();
}
}
@@ -1997,27 +2124,24 @@
if (activeSource == AUDIO_SOURCE_HOTWORD) {
AudioSessionCollection activeSessions =
activeDesc->getAudioSessions(true /*activeOnly*/);
- audio_session_t activeSession = activeSessions.keyAt(0);
- audio_io_handle_t activeHandle = activeDesc->mIoHandle;
+ sp<AudioSession> activeSession = activeSessions[0];
SortedVector<audio_session_t> sessions = activeDesc->getPreemptedSessions();
*concurrency |= API_INPUT_CONCURRENCY_PREEMPT;
- sessions.add(activeSession);
+ sessions.add(activeSession->session());
inputDesc->setPreemptedSessions(sessions);
- stopInput(activeHandle, activeSession);
- releaseInput(activeHandle, activeSession);
+ closeSession(inputDesc, activeSession);
ALOGV("startInput(%d) for HOTWORD preempting HOTWORD input %d",
input, activeDesc->mIoHandle);
}
}
}
-#endif
// Make sure we start with the correct silence state
audioSession->setSilenced(silenced);
// increment activity count before calling getNewInputDevice() below as only active sessions
// are considered for device selection
- audioSession->changeActiveCount(1);
+ inputDesc->changeRefCount(session, 1);
// Routing?
mInputRoutes.incRouteActivity(session);
@@ -2031,7 +2155,7 @@
status_t status = inputDesc->start();
if (status != NO_ERROR) {
mInputRoutes.decRouteActivity(session);
- audioSession->changeActiveCount(-1);
+ inputDesc->changeRefCount(session, -1);
return status;
}
@@ -2073,29 +2197,29 @@
return NO_ERROR;
}
-status_t AudioPolicyManager::stopInput(audio_io_handle_t input,
- audio_session_t session)
+status_t AudioPolicyManager::stopInput(audio_port_handle_t portId)
{
- ALOGV("stopInput() input %d", input);
- ssize_t index = mInputs.indexOfKey(input);
- if (index < 0) {
- ALOGW("stopInput() unknown input %d", input);
+ ALOGV("%s portId %d", __FUNCTION__, portId);
+
+ sp<AudioInputDescriptor> inputDesc = mInputs.getInputForClient(portId);
+ if (inputDesc == 0) {
+ ALOGW("stopInput() no input for client %d", portId);
return BAD_VALUE;
}
- sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(index);
+ sp<RecordClientDescriptor> client = inputDesc->clients()[portId];
+ audio_session_t session = client->session();
+ audio_io_handle_t input = inputDesc->mIoHandle;
+
+ ALOGV("stopInput() input %d", input);
sp<AudioSession> audioSession = inputDesc->getAudioSession(session);
- if (index < 0) {
- ALOGW("stopInput() unknown session %d on input %d", session, input);
- return BAD_VALUE;
- }
if (audioSession->activeCount() == 0) {
ALOGW("stopInput() input %d already stopped", input);
return INVALID_OPERATION;
}
- audioSession->changeActiveCount(-1);
+ inputDesc->changeRefCount(session, -1);
// Routing?
mInputRoutes.decRouteActivity(session);
@@ -2144,22 +2268,24 @@
return NO_ERROR;
}
-void AudioPolicyManager::releaseInput(audio_io_handle_t input,
- audio_session_t session)
+void AudioPolicyManager::releaseInput(audio_port_handle_t portId)
{
- ALOGV("releaseInput() %d", input);
- ssize_t index = mInputs.indexOfKey(input);
- if (index < 0) {
- ALOGW("releaseInput() releasing unknown input %d", input);
+ ALOGV("%s portId %d", __FUNCTION__, portId);
+
+ sp<AudioInputDescriptor> inputDesc = mInputs.getInputForClient(portId);
+ if (inputDesc == 0) {
+ ALOGW("releaseInput() no input for client %d", portId);
return;
}
+ sp<RecordClientDescriptor> client = inputDesc->clients()[portId];
+ audio_session_t session = client->session();
+ audio_io_handle_t input = inputDesc->mIoHandle;
+
+ ALOGV("releaseInput() %d", input);
// Routing
mInputRoutes.removeRoute(session);
- sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(index);
- ALOG_ASSERT(inputDesc != 0);
-
sp<AudioSession> audioSession = inputDesc->getAudioSession(session);
if (audioSession == 0) {
ALOGW("releaseInput() unknown session %d on input %d", session, input);
@@ -2182,10 +2308,31 @@
}
closeInput(input);
+ inputDesc->clients().erase(portId);
mpClientInterface->onAudioPortListUpdate();
ALOGV("releaseInput() exit");
}
+void AudioPolicyManager::closeSessions(const sp<AudioInputDescriptor>& input, bool activeOnly)
+{
+ AudioSessionCollection sessions = input->getAudioSessions(activeOnly /*activeOnly*/);
+ for (size_t i = 0; i < sessions.size(); i++) {
+ closeSession(input, sessions[i]);
+ }
+}
+
+void AudioPolicyManager::closeSession(const sp<AudioInputDescriptor>& input,
+ const sp<AudioSession>& session)
+{
+ RecordClientVector clients = input->getClientsForSession(session->session());
+
+ for (const auto& client : clients) {
+ stopInput(client->portId());
+ releaseInput(client->portId());
+ }
+}
+
+
void AudioPolicyManager::closeAllInputs() {
bool patchRemoved = false;
@@ -2647,6 +2794,7 @@
mEffects.dump(fd);
mAudioPatches.dump(fd);
mPolicyMixes.dump(fd);
+ mAudioSources.dump(fd);
return NO_ERROR;
}
@@ -3289,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));
}
}
@@ -3308,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;
}
@@ -3329,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 =
@@ -3401,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);
@@ -3411,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 __unused)
+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;
}
@@ -3770,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) {
@@ -3791,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
@@ -3802,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;
@@ -4637,33 +4792,17 @@
return outputs;
}
-bool AudioPolicyManager::vectorsEqual(SortedVector<audio_io_handle_t>& outputs1,
- SortedVector<audio_io_handle_t>& outputs2)
-{
- if (outputs1.size() != outputs2.size()) {
- return false;
- }
- for (size_t i = 0; i < outputs1.size(); i++) {
- if (outputs1[i] != outputs2[i]) {
- return false;
- }
- }
- return true;
-}
-
-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)
@@ -4691,7 +4830,7 @@
}
}
- if (!vectorsEqual(srcOutputs,dstOutputs)) {
+ if (srcOutputs != dstOutputs) {
// get maximum latency of all source outputs to determine the minimum mute time guaranteeing
// audio from invalidated tracks will be rendered when unmuting
uint32_t maxLatency = 0;
@@ -4710,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);
@@ -5791,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 70ca39f..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>
@@ -39,6 +40,7 @@
#include <AudioPolicyConfig.h>
#include <AudioPort.h>
#include <AudioPatch.h>
+#include <AudioProfile.h>
#include <DeviceDescriptor.h>
#include <IOProfile.h>
#include <HwModule.h>
@@ -119,15 +121,9 @@
audio_output_flags_t *flags,
audio_port_handle_t *selectedDeviceId,
audio_port_handle_t *portId);
- virtual status_t startOutput(audio_io_handle_t output,
- audio_stream_type_t stream,
- audio_session_t session);
- virtual status_t stopOutput(audio_io_handle_t output,
- audio_stream_type_t stream,
- audio_session_t session);
- virtual void releaseOutput(audio_io_handle_t output,
- audio_stream_type_t stream,
- audio_session_t session);
+ virtual status_t startOutput(audio_port_handle_t portId);
+ virtual status_t stopOutput(audio_port_handle_t portId);
+ virtual void releaseOutput(audio_port_handle_t portId);
virtual status_t getInputForAttr(const audio_attributes_t *attr,
audio_io_handle_t *input,
audio_session_t session,
@@ -139,16 +135,13 @@
audio_port_handle_t *portId);
// indicates to the audio policy manager that the input starts being used.
- virtual status_t startInput(audio_io_handle_t input,
- audio_session_t session,
+ virtual status_t startInput(audio_port_handle_t portId,
bool silenced,
concurrency_type__mask_t *concurrency);
// indicates to the audio policy manager that the input stops being used.
- virtual status_t stopInput(audio_io_handle_t input,
- audio_session_t session);
- virtual void releaseInput(audio_io_handle_t input,
- audio_session_t session);
+ virtual status_t stopInput(audio_port_handle_t portId);
+ virtual void releaseInput(audio_port_handle_t portId);
virtual void closeAllInputs();
virtual void initStreamVolume(audio_stream_type_t stream,
int indexMin,
@@ -230,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);
@@ -415,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
@@ -459,8 +451,6 @@
SortedVector<audio_io_handle_t> getOutputsForDevice(audio_devices_t device,
const SwAudioOutputCollection& openOutputs);
- bool vectorsEqual(SortedVector<audio_io_handle_t>& outputs1,
- SortedVector<audio_io_handle_t>& outputs2);
// mute/unmute strategies using an incompatible device combination
// if muting, wait for the audio in pcm buffer to be drained before proceeding
@@ -509,13 +499,14 @@
if (!hasPrimaryOutput()) {
return AUDIO_DEVICE_NONE;
}
- return mAvailableInputDevices.getDevicesFromHwModule(mPrimaryOutput->getModuleHandle());
+ return mAvailableInputDevices.getDeviceTypesFromHwModule(
+ mPrimaryOutput->getModuleHandle());
}
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.
@@ -534,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);
@@ -552,6 +543,10 @@
static bool streamsMatchForvolume(audio_stream_type_t stream1,
audio_stream_type_t stream2);
+ void closeSessions(const sp<AudioInputDescriptor>& input, bool activeOnly);
+ void closeSession(const sp<AudioInputDescriptor>& input,
+ const sp<AudioSession>& session);
+
const uid_t mUidCached; // AID_AUDIOSERVER
AudioPolicyClientInterface *mpClientInterface; // audio policy client interface
sp<SwAudioOutputDescriptor> mPrimaryOutput; // primary output descriptor
@@ -592,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
@@ -625,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 859072b..dbfda44 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -200,7 +200,7 @@
!modifyPhoneStateAllowed(pid, uid)) {
// If the app tries to play music through the telephony device and doesn't have permission
// the fallback to the default output device.
- mAudioPolicyManager->releaseOutput(*output, *stream, session);
+ mAudioPolicyManager->releaseOutput(*portId);
flags = originalFlags;
*selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
*portId = AUDIO_PORT_HANDLE_NONE;
@@ -245,8 +245,7 @@
}
Mutex::Autolock _l(mLock);
AutoCallerClear acc;
- status_t status = mAudioPolicyManager->startOutput(
- client->io, client->stream, client->session);
+ status_t status = mAudioPolicyManager->startOutput(portId);
if (status == NO_ERROR) {
client->active = true;
}
@@ -298,8 +297,7 @@
}
Mutex::Autolock _l(mLock);
AutoCallerClear acc;
- status_t status = mAudioPolicyManager->stopOutput(
- client->io, client->stream, client->session);
+ status_t status = mAudioPolicyManager->stopOutput(portId);
if (status == NO_ERROR) {
client->active = false;
}
@@ -328,8 +326,7 @@
mAudioRecordClients.removeItem(portId);
// called from internal thread: no need to clear caller identity
- mAudioPolicyManager->releaseOutput(
- client->io, client->stream, client->session);
+ mAudioPolicyManager->releaseOutput(portId);
}
status_t AudioPolicyService::getInputForAttr(const audio_attributes_t *attr,
@@ -433,7 +430,7 @@
if (status != NO_ERROR) {
if (status == PERMISSION_DENIED) {
AutoCallerClear acc;
- mAudioPolicyManager->releaseInput(*input, session);
+ mAudioPolicyManager->releaseInput(*portId);
}
return status;
}
@@ -527,8 +524,7 @@
status_t status;
{
AutoCallerClear acc;
- status = mAudioPolicyManager->startInput(
- client->io, client->session, *silenced, &concurrency);
+ status = mAudioPolicyManager->startInput(portId, *silenced, &concurrency);
}
@@ -641,7 +637,7 @@
// finish the recording app op
finishRecording(client->opPackageName, client->uid);
AutoCallerClear acc;
- return mAudioPolicyManager->stopInput(client->io, client->session);
+ return mAudioPolicyManager->stopInput(portId);
}
void AudioPolicyService::releaseInput(audio_port_handle_t portId)
@@ -674,7 +670,7 @@
{
Mutex::Autolock _l(mLock);
AutoCallerClear acc;
- mAudioPolicyManager->releaseInput(client->io, client->session);
+ mAudioPolicyManager->releaseInput(portId);
}
}
@@ -994,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/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index d59b313..c8b3c2f 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -780,33 +780,35 @@
int lastJpegStreamId = mJpegProcessor->getStreamId();
// If jpeg stream will slow down preview, make sure we remove it before starting preview
if (params.slowJpegMode) {
- // Pause preview if we are streaming
- int32_t activeRequestId = mStreamingProcessor->getActiveRequestId();
- if (activeRequestId != 0) {
- res = mStreamingProcessor->togglePauseStream(/*pause*/true);
- if (res != OK) {
- ALOGE("%s: Camera %d: Can't pause streaming: %s (%d)",
- __FUNCTION__, mCameraId, strerror(-res), res);
+ if (lastJpegStreamId != NO_STREAM) {
+ // Pause preview if we are streaming
+ int32_t activeRequestId = mStreamingProcessor->getActiveRequestId();
+ if (activeRequestId != 0) {
+ res = mStreamingProcessor->togglePauseStream(/*pause*/true);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Can't pause streaming: %s (%d)",
+ __FUNCTION__, mCameraId, strerror(-res), res);
+ }
+ res = mDevice->waitUntilDrained();
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Waiting to stop streaming failed: %s (%d)",
+ __FUNCTION__, mCameraId, strerror(-res), res);
+ }
}
- res = mDevice->waitUntilDrained();
+
+ res = mJpegProcessor->deleteStream();
+
if (res != OK) {
- ALOGE("%s: Camera %d: Waiting to stop streaming failed: %s (%d)",
- __FUNCTION__, mCameraId, strerror(-res), res);
+ ALOGE("%s: Camera %d: delete Jpeg stream failed: %s (%d)",
+ __FUNCTION__, mCameraId, strerror(-res), res);
}
- }
- res = mJpegProcessor->deleteStream();
-
- if (res != OK) {
- ALOGE("%s: Camera %d: delete Jpeg stream failed: %s (%d)",
- __FUNCTION__, mCameraId, strerror(-res), res);
- }
-
- if (activeRequestId != 0) {
- res = mStreamingProcessor->togglePauseStream(/*pause*/false);
- if (res != OK) {
- ALOGE("%s: Camera %d: Can't unpause streaming: %s (%d)",
- __FUNCTION__, mCameraId, strerror(-res), res);
+ if (activeRequestId != 0) {
+ res = mStreamingProcessor->togglePauseStream(/*pause*/false);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Can't unpause streaming: %s (%d)",
+ __FUNCTION__, mCameraId, strerror(-res), res);
+ }
}
}
} else {
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index baf051a..84428c2 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -1682,9 +1682,12 @@
// WORKAROUND: HAL refuses to disconnect while there's streams in flight
{
- mDevice->clearStreamingRequest();
-
+ int64_t lastFrameNumber;
status_t code;
+ if ((code = mDevice->flush(&lastFrameNumber)) != OK) {
+ ALOGE("%s: flush failed with code 0x%x", __FUNCTION__, code);
+ }
+
if ((code = mDevice->waitUntilDrained()) != OK) {
ALOGE("%s: waitUntilDrained failed with code 0x%x", __FUNCTION__,
code);
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