Merge "Add a method to reset circular references in audio flinger service" into main
diff --git a/camera/tests/fuzzer/camera_fuzzer.cpp b/camera/tests/fuzzer/camera_fuzzer.cpp
index c2a7549..9912fbe 100644
--- a/camera/tests/fuzzer/camera_fuzzer.cpp
+++ b/camera/tests/fuzzer/camera_fuzzer.cpp
@@ -88,6 +88,7 @@
bool initCamera();
void invokeCamera();
void invokeSetParameters();
+ native_handle_t* createNativeHandle();
sp<Camera> mCamera = nullptr;
FuzzedDataProvider* mFDP = nullptr;
@@ -102,6 +103,18 @@
};
};
+native_handle_t* CameraFuzzer::createNativeHandle() {
+ int32_t numFds = mFDP->ConsumeIntegralInRange<int32_t>(kMinElements, kMaxElements);
+ int32_t numInts = mFDP->ConsumeIntegralInRange<int32_t>(kNumMin, kNumMax);
+ native_handle_t* handle = native_handle_create(numFds, numInts);
+ for (int32_t i = 0; i < numFds; ++i) {
+ std::string filename = mFDP->ConsumeRandomLengthString(kMaxBytes);
+ int32_t fd = open(filename.c_str(), O_RDWR | O_CREAT | O_TRUNC);
+ handle->data[i] = fd;
+ }
+ return handle;
+}
+
bool CameraFuzzer::initCamera() {
ProcessState::self()->startThreadPool();
sp<IServiceManager> sm = defaultServiceManager();
@@ -288,15 +301,11 @@
},
[&]() {
int64_t timestamp = mFDP->ConsumeIntegral<int64_t>();
- int32_t numFds = mFDP->ConsumeIntegralInRange<int32_t>(kNumMin, kNumMax);
- int32_t numInts = mFDP->ConsumeIntegralInRange<int32_t>(kNumMin, kNumMax);
- native_handle_t* handle = native_handle_create(numFds, numInts);
+ native_handle_t* handle = createNativeHandle();
mCamera->recordingFrameHandleCallbackTimestamp(timestamp, handle);
},
[&]() {
- int32_t numFds = mFDP->ConsumeIntegralInRange<int32_t>(kNumMin, kNumMax);
- int32_t numInts = mFDP->ConsumeIntegralInRange<int32_t>(kNumMin, kNumMax);
- native_handle_t* handle = native_handle_create(numFds, numInts);
+ native_handle_t* handle = createNativeHandle();
mCamera->releaseRecordingFrameHandle(handle);
},
[&]() { mCamera->releaseRecordingFrame(iMem); },
@@ -305,9 +314,7 @@
for (int8_t i = 0;
i < mFDP->ConsumeIntegralInRange<int8_t>(kMinElements, kMaxElements);
++i) {
- int32_t numFds = mFDP->ConsumeIntegralInRange<int32_t>(kNumMin, kNumMax);
- int32_t numInts = mFDP->ConsumeIntegralInRange<int32_t>(kNumMin, kNumMax);
- native_handle_t* handle = native_handle_create(numFds, numInts);
+ native_handle_t* handle = createNativeHandle();
handles.push_back(handle);
}
mCamera->releaseRecordingFrameHandleBatch(handles);
@@ -317,9 +324,7 @@
for (int8_t i = 0;
i < mFDP->ConsumeIntegralInRange<int8_t>(kMinElements, kMaxElements);
++i) {
- int32_t numFds = mFDP->ConsumeIntegralInRange<int32_t>(kNumMin, kNumMax);
- int32_t numInts = mFDP->ConsumeIntegralInRange<int32_t>(kNumMin, kNumMax);
- native_handle_t* handle = native_handle_create(numFds, numInts);
+ native_handle_t* handle = createNativeHandle();
handles.push_back(handle);
}
std::vector<nsecs_t> timestamps;
diff --git a/media/audio/aconfig/OWNERS b/media/audio/aconfig/OWNERS
new file mode 100644
index 0000000..fb1e866
--- /dev/null
+++ b/media/audio/aconfig/OWNERS
@@ -0,0 +1,4 @@
+# Bug component: 48436
+atneya@google.com
+elaurent@google.com
+include platform/frameworks/av:/media/janitors/audio_OWNERS #{LAST_RESORT_SUGGESTION}
diff --git a/media/codec2/components/avc/Android.bp b/media/codec2/components/avc/Android.bp
index a7ae85b..8ccb9ac 100644
--- a/media/codec2/components/avc/Android.bp
+++ b/media/codec2/components/avc/Android.bp
@@ -17,6 +17,10 @@
static_libs: ["libavcdec"],
+ cflags: [
+ "-DKEEP_THREADS_ACTIVE=1",
+ ],
+
srcs: ["C2SoftAvcDec.cpp"],
export_include_dirs: ["."],
diff --git a/media/codec2/components/avc/C2SoftAvcDec.cpp b/media/codec2/components/avc/C2SoftAvcDec.cpp
index 3385b95..77fdeb9 100644
--- a/media/codec2/components/avc/C2SoftAvcDec.cpp
+++ b/media/codec2/components/avc/C2SoftAvcDec.cpp
@@ -16,6 +16,9 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "C2SoftAvcDec"
+#ifndef KEEP_THREADS_ACTIVE
+#define KEEP_THREADS_ACTIVE 0
+#endif
#include <log/log.h>
#include <media/stagefright/foundation/MediaDefs.h>
@@ -416,7 +419,7 @@
ivdext_create_op_t s_create_op = {};
s_create_ip.s_ivd_create_ip_t.u4_size = sizeof(ivdext_create_ip_t);
- s_create_ip.u4_keep_threads_active = 1;
+ s_create_ip.u4_keep_threads_active = KEEP_THREADS_ACTIVE;
s_create_ip.s_ivd_create_ip_t.e_cmd = IVD_CMD_CREATE;
s_create_ip.s_ivd_create_ip_t.u4_share_disp_buf = 0;
s_create_ip.s_ivd_create_ip_t.e_output_format = mIvColorFormat;
diff --git a/media/codec2/components/flac/C2SoftFlacEnc.cpp b/media/codec2/components/flac/C2SoftFlacEnc.cpp
index 7b63e75..780660e 100644
--- a/media/codec2/components/flac/C2SoftFlacEnc.cpp
+++ b/media/codec2/components/flac/C2SoftFlacEnc.cpp
@@ -155,7 +155,7 @@
mSignalledError = false;
mSignalledOutputEos = false;
mIsFirstFrame = true;
- mAnchorTimeStamp = 0ull;
+ mAnchorTimeStamp = 0;
mProcessedSamples = 0u;
mEncoderWriteData = false;
mEncoderReturnedNbBytes = 0;
@@ -186,7 +186,7 @@
mSignalledError = false;
mSignalledOutputEos = false;
mIsFirstFrame = true;
- mAnchorTimeStamp = 0ull;
+ mAnchorTimeStamp = 0;
mProcessedSamples = 0u;
mEncoderWriteData = false;
mEncoderReturnedNbBytes = 0;
@@ -236,7 +236,7 @@
inSize, (int)work->input.ordinal.timestamp.peeku(),
(int)work->input.ordinal.frameIndex.peeku(), work->input.flags);
if (mIsFirstFrame && inSize) {
- mAnchorTimeStamp = work->input.ordinal.timestamp.peekull();
+ mAnchorTimeStamp = work->input.ordinal.timestamp.peekll();
mIsFirstFrame = false;
}
@@ -405,7 +405,7 @@
C2WriteView wView = mOutputBlock->map().get();
uint8_t* outData = wView.data();
const uint32_t sampleRate = mIntf->getSampleRate();
- const uint64_t outTimeStamp = mProcessedSamples * 1000000ll / sampleRate;
+ const int64_t outTimeStamp = mProcessedSamples * 1000000ll / sampleRate;
ALOGV("writing %zu bytes of encoded data on output", bytes);
// increment mProcessedSamples to maintain audio synchronization during
// play back
diff --git a/media/codec2/components/flac/C2SoftFlacEnc.h b/media/codec2/components/flac/C2SoftFlacEnc.h
index 1f3be3c..ed9c298 100644
--- a/media/codec2/components/flac/C2SoftFlacEnc.h
+++ b/media/codec2/components/flac/C2SoftFlacEnc.h
@@ -72,7 +72,7 @@
bool mSignalledOutputEos;
uint32_t mBlockSize;
bool mIsFirstFrame;
- uint64_t mAnchorTimeStamp;
+ int64_t mAnchorTimeStamp;
uint64_t mProcessedSamples;
// should the data received by the callback be written to the output port
bool mEncoderWriteData;
diff --git a/media/codec2/components/hevc/Android.bp b/media/codec2/components/hevc/Android.bp
index d1388b9..cb9c2ae 100644
--- a/media/codec2/components/hevc/Android.bp
+++ b/media/codec2/components/hevc/Android.bp
@@ -15,6 +15,10 @@
"libcodec2_soft_sanitize_cfi-defaults",
],
+ cflags: [
+ "-DKEEP_THREADS_ACTIVE=1",
+ ],
+
srcs: ["C2SoftHevcDec.cpp"],
static_libs: ["libhevcdec"],
diff --git a/media/codec2/components/hevc/C2SoftHevcDec.cpp b/media/codec2/components/hevc/C2SoftHevcDec.cpp
index 81db2a1..64aa7a4 100644
--- a/media/codec2/components/hevc/C2SoftHevcDec.cpp
+++ b/media/codec2/components/hevc/C2SoftHevcDec.cpp
@@ -16,6 +16,9 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "C2SoftHevcDec"
+#ifndef KEEP_THREADS_ACTIVE
+#define KEEP_THREADS_ACTIVE 0
+#endif
#include <log/log.h>
#include <media/stagefright/foundation/MediaDefs.h>
@@ -407,7 +410,7 @@
ivdext_create_op_t s_create_op = {};
s_create_ip.s_ivd_create_ip_t.u4_size = sizeof(ivdext_create_ip_t);
- s_create_ip.u4_keep_threads_active = 1;
+ s_create_ip.u4_keep_threads_active = KEEP_THREADS_ACTIVE;
s_create_ip.s_ivd_create_ip_t.e_cmd = IVD_CMD_CREATE;
s_create_ip.s_ivd_create_ip_t.u4_share_disp_buf = 0;
s_create_ip.s_ivd_create_ip_t.e_output_format = mIvColorformat;
diff --git a/media/codec2/components/mpeg2/Android.bp b/media/codec2/components/mpeg2/Android.bp
index a58044c..e644ee3 100644
--- a/media/codec2/components/mpeg2/Android.bp
+++ b/media/codec2/components/mpeg2/Android.bp
@@ -14,6 +14,10 @@
"libcodec2_soft_sanitize_signed-defaults",
],
+ cflags: [
+ "-DKEEP_THREADS_ACTIVE=0",
+ ],
+
srcs: ["C2SoftMpeg2Dec.cpp"],
static_libs: ["libmpeg2dec"],
diff --git a/media/codec2/components/mpeg2/C2SoftMpeg2Dec.cpp b/media/codec2/components/mpeg2/C2SoftMpeg2Dec.cpp
index 491098d..562dcf5 100644
--- a/media/codec2/components/mpeg2/C2SoftMpeg2Dec.cpp
+++ b/media/codec2/components/mpeg2/C2SoftMpeg2Dec.cpp
@@ -16,6 +16,9 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "C2SoftMpeg2Dec"
+#ifndef KEEP_THREADS_ACTIVE
+#define KEEP_THREADS_ACTIVE 0
+#endif
#include <log/log.h>
#include <media/stagefright/foundation/MediaDefs.h>
@@ -433,7 +436,7 @@
s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_size = sizeof(ivdext_fill_mem_rec_ip_t);
s_fill_mem_ip.u4_share_disp_buf = 0;
- s_fill_mem_ip.u4_keep_threads_active = 1;
+ s_fill_mem_ip.u4_keep_threads_active = KEEP_THREADS_ACTIVE;
s_fill_mem_ip.e_output_format = mIvColorformat;
s_fill_mem_ip.u4_deinterlace = 1;
s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.e_cmd = IV_CMD_FILL_NUM_MEM_REC;
@@ -475,7 +478,7 @@
s_init_ip.s_ivd_init_ip_t.u4_frm_max_ht = mHeight;
s_init_ip.u4_share_disp_buf = 0;
s_init_ip.u4_deinterlace = 1;
- s_init_ip.u4_keep_threads_active = 1;
+ s_init_ip.u4_keep_threads_active = KEEP_THREADS_ACTIVE;
s_init_ip.s_ivd_init_ip_t.u4_num_mem_rec = mNumMemRecords;
s_init_ip.s_ivd_init_ip_t.e_output_format = mIvColorformat;
s_init_op.s_ivd_init_op_t.u4_size = sizeof(ivdext_init_op_t);
diff --git a/media/codec2/components/vpx/C2SoftVpxEnc.cpp b/media/codec2/components/vpx/C2SoftVpxEnc.cpp
index 1c5772f..8eb8da5 100644
--- a/media/codec2/components/vpx/C2SoftVpxEnc.cpp
+++ b/media/codec2/components/vpx/C2SoftVpxEnc.cpp
@@ -465,6 +465,7 @@
mTemporalPatternIdx(0),
mLastTimestamp(0x7FFFFFFFFFFFFFFFull),
mSignalledOutputEos(false),
+ mHeaderGenerated(false),
mSignalledError(false) {
for (int i = 0; i < MAXTEMPORALLAYERS; i++) {
mTemporalLayerBitrateRatio[i] = 1.0f;
@@ -494,6 +495,7 @@
// this one is not allocated by us
mCodecInterface = nullptr;
+ mHeaderGenerated = false;
}
c2_status_t C2SoftVpxEnc::onStop() {
@@ -558,6 +560,7 @@
(uint32_t)mBitrateControlMode, mTemporalLayers, mIntf->getSyncFramePeriod(),
mMinQuantizer, mMaxQuantizer);
+ mHeaderGenerated = false;
mCodecConfiguration = new vpx_codec_enc_cfg_t;
if (!mCodecConfiguration) goto CleanUp;
codec_return = vpx_codec_enc_config_default(mCodecInterface,
@@ -873,6 +876,27 @@
return;
}
+ // Header generation is limited to Android V and above, as MediaMuxer did not handle
+ // CSD for VP9 correctly in Android U and before.
+ if (isAtLeastV() && !mHeaderGenerated) {
+ vpx_fixed_buf_t* codec_private_data = vpx_codec_get_global_headers(mCodecContext);
+ if (codec_private_data) {
+ std::unique_ptr<C2StreamInitDataInfo::output> csd =
+ C2StreamInitDataInfo::output::AllocUnique(codec_private_data->sz, 0u);
+ if (!csd) {
+ ALOGE("CSD allocation failed");
+ mSignalledError = true;
+ work->result = C2_NO_MEMORY;
+ work->workletsProcessed = 1u;
+ return;
+ }
+ memcpy(csd->m.value, codec_private_data->buf, codec_private_data->sz);
+ work->worklets.front()->output.configUpdate.push_back(std::move(csd));
+ ALOGV("CSD Produced of size %zu bytes", codec_private_data->sz);
+ }
+ mHeaderGenerated = true;
+ }
+
const C2ConstGraphicBlock inBuffer =
inputBuffer->data().graphicBlocks().front();
if (inBuffer.width() < mSize->width ||
diff --git a/media/codec2/components/vpx/C2SoftVpxEnc.h b/media/codec2/components/vpx/C2SoftVpxEnc.h
index 980de04..87d24f9 100644
--- a/media/codec2/components/vpx/C2SoftVpxEnc.h
+++ b/media/codec2/components/vpx/C2SoftVpxEnc.h
@@ -207,6 +207,9 @@
// Signalled EOS
bool mSignalledOutputEos;
+ // Header generated
+ bool mHeaderGenerated;
+
// Signalled Error
bool mSignalledError;
diff --git a/media/codec2/hal/client/Android.bp b/media/codec2/hal/client/Android.bp
index af6f4ae..864eeb8 100644
--- a/media/codec2/hal/client/Android.bp
+++ b/media/codec2/hal/client/Android.bp
@@ -33,6 +33,13 @@
"libcodec2-aidl-client-defaults",
],
+ // http://b/343951602#comment4 Explicitly set cpp_std to gnu++20. The
+ // default inherited from libcodec2-impl-defaults sets it to gnu++17 which
+ // causes a segfault when mixing global std::string symbols built with
+ // gnu++17 and gnu++20. TODO(b/343951602): clean this after
+ // libcodec2-impl-defaults opt into gnu++17 is removed.
+ cpp_std: "gnu++20",
+
header_libs: [
"libcodec2_internal", // private
],
diff --git a/media/codec2/sfplugin/C2AidlNode.cpp b/media/codec2/sfplugin/C2AidlNode.cpp
index 0f23205..4e46ad6 100644
--- a/media/codec2/sfplugin/C2AidlNode.cpp
+++ b/media/codec2/sfplugin/C2AidlNode.cpp
@@ -68,10 +68,15 @@
}
::ndk::ScopedAStatus C2AidlNode::submitBuffer(
- int32_t buffer, const ::aidl::android::hardware::HardwareBuffer& hBuffer,
+ int32_t buffer,
+ const std::optional<::aidl::android::hardware::HardwareBuffer>& hBuffer,
int32_t flags, int64_t timestamp, const ::ndk::ScopedFileDescriptor& fence) {
sp<GraphicBuffer> gBuf;
- AHardwareBuffer *ahwb = hBuffer.get();
+ AHardwareBuffer *ahwb = nullptr;
+ if (hBuffer.has_value()) {
+ ahwb = hBuffer.value().get();
+ }
+
if (ahwb) {
gBuf = AHardwareBuffer_to_GraphicBuffer(ahwb);
}
diff --git a/media/codec2/sfplugin/C2AidlNode.h b/media/codec2/sfplugin/C2AidlNode.h
index 9dd3504..95290fd 100644
--- a/media/codec2/sfplugin/C2AidlNode.h
+++ b/media/codec2/sfplugin/C2AidlNode.h
@@ -49,7 +49,7 @@
::ndk::ScopedAStatus submitBuffer(
int32_t buffer,
- const ::aidl::android::hardware::HardwareBuffer& hBuffer,
+ const std::optional<::aidl::android::hardware::HardwareBuffer>& hBuffer,
int32_t flags,
int64_t timestampUs,
const ::ndk::ScopedFileDescriptor& fence) override;
diff --git a/media/libaudiohal/impl/DeviceHalAidl.cpp b/media/libaudiohal/impl/DeviceHalAidl.cpp
index 2447b18..9f21404 100644
--- a/media/libaudiohal/impl/DeviceHalAidl.cpp
+++ b/media/libaudiohal/impl/DeviceHalAidl.cpp
@@ -386,7 +386,7 @@
return runCb([](CbRef cb) { cb->onWriteReady(); });
}
ndk::ScopedAStatus onError() override {
- return runCb([](CbRef cb) { cb->onError(); });
+ return runCb([](CbRef cb) { cb->onError(true /*isHardError*/); });
}
ndk::ScopedAStatus onDrainReady() override {
return runCb([](CbRef cb) { cb->onDrainReady(); });
diff --git a/media/libaudiohal/impl/Hal2AidlMapper.cpp b/media/libaudiohal/impl/Hal2AidlMapper.cpp
index 453f9e2..cbade70 100644
--- a/media/libaudiohal/impl/Hal2AidlMapper.cpp
+++ b/media/libaudiohal/impl/Hal2AidlMapper.cpp
@@ -136,8 +136,8 @@
// 'sinks' will not be updated because 'setAudioPatch' only needs IDs. Here we log
// the source arguments, where only the audio configuration and device specifications
// are relevant.
- ALOGD("%s: [disregard IDs] sources: %s, sinks: %s",
- __func__, ::android::internal::ToString(sources).c_str(),
+ ALOGD("%s: patch ID: %d, [disregard IDs] sources: %s, sinks: %s",
+ __func__, *patchId, ::android::internal::ToString(sources).c_str(),
::android::internal::ToString(sinks).c_str());
auto fillPortConfigs = [&](
const std::vector<AudioPortConfig>& configs,
@@ -209,11 +209,24 @@
// that there can only be one patch for an I/O thread.
PatchMatch match = sourceIsDevice && sinkIsDevice ?
MATCH_BOTH : (sourceIsDevice ? MATCH_SINKS : MATCH_SOURCES);
+ auto requestedPatch = patch;
RETURN_STATUS_IF_ERROR(findOrCreatePatch(patch, match,
&patch, &created));
// No cleanup of the patch is needed, it is managed by the framework.
*patchId = patch.id;
if (!created) {
+ requestedPatch.id = patch.id;
+ if (patch != requestedPatch) {
+ ALOGI("%s: Updating transient patch. Current: %s, new: %s",
+ __func__, patch.toString().c_str(), requestedPatch.toString().c_str());
+ // Since matching may be done by mix port only, update the patch if the device port
+ // config has changed.
+ patch = requestedPatch;
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
+ mModule->setAudioPatch(patch, &patch)));
+ existingPatchIt = mPatches.find(patch.id);
+ existingPatchIt->second = patch;
+ }
// The framework might have "created" a patch which already existed due to
// stream creation. Need to release the ownership from the stream.
for (auto& s : mStreams) {
diff --git a/media/libaudiohal/impl/StreamHalAidl.cpp b/media/libaudiohal/impl/StreamHalAidl.cpp
index 10c3105..6c0dc76 100644
--- a/media/libaudiohal/impl/StreamHalAidl.cpp
+++ b/media/libaudiohal/impl/StreamHalAidl.cpp
@@ -253,20 +253,71 @@
ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
TIME_CHECK();
if (!mStream) return NO_INIT;
- const auto state = getState();
- StreamDescriptor::Reply reply;
- if (state == StreamDescriptor::State::STANDBY) {
- RETURN_STATUS_IF_ERROR(sendCommand(makeHalCommand<HalCommand::Tag::start>(), &reply, true));
- return sendCommand(makeHalCommand<HalCommand::Tag::burst>(0), &reply, true);
+ if (!mContext.isMmapped()) {
+ return BAD_VALUE;
}
-
- return INVALID_OPERATION;
+ StreamDescriptor::Reply reply;
+ RETURN_STATUS_IF_ERROR(updateCountersIfNeeded(&reply));
+ switch (reply.state) {
+ case StreamDescriptor::State::STANDBY:
+ RETURN_STATUS_IF_ERROR(
+ sendCommand(makeHalCommand<HalCommand::Tag::start>(), &reply, true));
+ if (reply.state != StreamDescriptor::State::IDLE) {
+ ALOGE("%s: unexpected stream state: %s (expected IDLE)",
+ __func__, toString(reply.state).c_str());
+ return INVALID_OPERATION;
+ }
+ FALLTHROUGH_INTENDED;
+ case StreamDescriptor::State::IDLE:
+ RETURN_STATUS_IF_ERROR(
+ sendCommand(makeHalCommand<HalCommand::Tag::burst>(0), &reply, true));
+ if (reply.state != StreamDescriptor::State::ACTIVE) {
+ ALOGE("%s: unexpected stream state: %s (expected ACTIVE)",
+ __func__, toString(reply.state).c_str());
+ return INVALID_OPERATION;
+ }
+ FALLTHROUGH_INTENDED;
+ case StreamDescriptor::State::ACTIVE:
+ return OK;
+ case StreamDescriptor::State::DRAINING:
+ RETURN_STATUS_IF_ERROR(
+ sendCommand(makeHalCommand<HalCommand::Tag::start>(), &reply, true));
+ if (reply.state != StreamDescriptor::State::ACTIVE) {
+ ALOGE("%s: unexpected stream state: %s (expected ACTIVE)",
+ __func__, toString(reply.state).c_str());
+ return INVALID_OPERATION;
+ }
+ return OK;
+ default:
+ ALOGE("%s: not supported from %s stream state %s",
+ __func__, mIsInput ? "input" : "output", toString(reply.state).c_str());
+ return INVALID_OPERATION;
+ }
}
status_t StreamHalAidl::stop() {
ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
+ TIME_CHECK();
if (!mStream) return NO_INIT;
- return standby();
+ if (!mContext.isMmapped()) {
+ return BAD_VALUE;
+ }
+ StreamDescriptor::Reply reply;
+ RETURN_STATUS_IF_ERROR(updateCountersIfNeeded(&reply));
+ if (const auto state = reply.state; state == StreamDescriptor::State::ACTIVE) {
+ return drain(false /*earlyNotify*/, nullptr);
+ } else if (state == StreamDescriptor::State::DRAINING) {
+ RETURN_STATUS_IF_ERROR(pause());
+ return flush();
+ } else if (state == StreamDescriptor::State::PAUSED) {
+ return flush();
+ } else if (state != StreamDescriptor::State::IDLE &&
+ state != StreamDescriptor::State::STANDBY) {
+ ALOGE("%s: not supported from %s stream state %s",
+ __func__, mIsInput ? "input" : "output", toString(state).c_str());
+ return INVALID_OPERATION;
+ }
+ return OK;
}
status_t StreamHalAidl::getLatency(uint32_t *latency) {
@@ -901,10 +952,10 @@
}
}
-void StreamOutHalAidl::onError() {
+void StreamOutHalAidl::onError(bool isHardError) {
onAsyncError();
if (auto clientCb = mClientCallback.load().promote(); clientCb != nullptr) {
- clientCb->onError();
+ clientCb->onError(isHardError);
}
}
diff --git a/media/libaudiohal/impl/StreamHalAidl.h b/media/libaudiohal/impl/StreamHalAidl.h
index fff7a92..9cb2cff 100644
--- a/media/libaudiohal/impl/StreamHalAidl.h
+++ b/media/libaudiohal/impl/StreamHalAidl.h
@@ -95,7 +95,8 @@
size_t getBufferSizeBytes() const { return mFrameSizeBytes * mBufferSizeFrames; }
size_t getBufferSizeFrames() const { return mBufferSizeFrames; }
size_t getBufferDurationMs(int32_t sampleRate) const {
- return sampleRate != 0 ? mBufferSizeFrames * MILLIS_PER_SECOND / sampleRate : 0;
+ auto bufferSize = mIsMmapped ? getMmapBurstSize() : mBufferSizeFrames;
+ return sampleRate != 0 ? bufferSize * MILLIS_PER_SECOND / sampleRate : 0;
}
CommandMQ* getCommandMQ() const { return mCommandMQ.get(); }
DataMQ* getDataMQ() const { return mDataMQ.get(); }
@@ -104,7 +105,7 @@
bool isAsynchronous() const { return mIsAsynchronous; }
bool isMmapped() const { return mIsMmapped; }
const MmapBufferDescriptor& getMmapBufferDescriptor() const { return mMmapBufferDescriptor; }
-
+ size_t getMmapBurstSize() const { return mMmapBufferDescriptor.burstSizeFrames;}
private:
static std::unique_ptr<DataMQ> maybeCreateDataMQ(
const ::aidl::android::hardware::audio::core::StreamDescriptor& descriptor) {
@@ -385,7 +386,7 @@
// StreamOutHalInterfaceCallback
void onWriteReady() override;
void onDrainReady() override;
- void onError() override;
+ void onError(bool isHardError) override;
private:
friend class sp<StreamOutHalAidl>;
diff --git a/media/libaudiohal/impl/StreamHalHidl.cpp b/media/libaudiohal/impl/StreamHalHidl.cpp
index 9e22700..a931fdd 100644
--- a/media/libaudiohal/impl/StreamHalHidl.cpp
+++ b/media/libaudiohal/impl/StreamHalHidl.cpp
@@ -997,7 +997,7 @@
sp<StreamOutHalInterfaceCallback> callback = mCallback.load().promote();
if (callback == 0) return;
ALOGV("asyncCallback onError");
- callback->onError();
+ callback->onError(false /*isHardError*/);
}
void StreamOutHalHidl::onCodecFormatChanged(const std::vector<uint8_t>& metadataBs) {
diff --git a/media/libaudiohal/include/media/audiohal/StreamHalInterface.h b/media/libaudiohal/include/media/audiohal/StreamHalInterface.h
index 585a895..4bd7e3d 100644
--- a/media/libaudiohal/include/media/audiohal/StreamHalInterface.h
+++ b/media/libaudiohal/include/media/audiohal/StreamHalInterface.h
@@ -107,7 +107,7 @@
public:
virtual void onWriteReady() {}
virtual void onDrainReady() {}
- virtual void onError() {}
+ virtual void onError(bool /*isHardError*/) {}
protected:
StreamOutHalInterfaceCallback() = default;
diff --git a/media/libaudiohal/tests/CoreAudioHalAidl_test.cpp b/media/libaudiohal/tests/CoreAudioHalAidl_test.cpp
index 5106874..0bd6fb0 100644
--- a/media/libaudiohal/tests/CoreAudioHalAidl_test.cpp
+++ b/media/libaudiohal/tests/CoreAudioHalAidl_test.cpp
@@ -39,6 +39,7 @@
using ::aidl::android::hardware::audio::core::VendorParameter;
using ::aidl::android::media::audio::common::AudioChannelLayout;
using ::aidl::android::media::audio::common::AudioConfig;
+using ::aidl::android::media::audio::common::AudioDevice;
using ::aidl::android::media::audio::common::AudioDeviceDescription;
using ::aidl::android::media::audio::common::AudioDeviceType;
using ::aidl::android::media::audio::common::AudioFormatDescription;
@@ -160,6 +161,24 @@
createProfile(PcmType::INT_16_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000})};
Configuration c;
+ AudioPort micInDevice =
+ createPort(c.nextPortId++, "Built-In Mic", 0, true,
+ createPortDeviceExt(AudioDeviceType::IN_MICROPHONE,
+ 1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE));
+ micInDevice.profiles = standardPcmAudioProfiles;
+ c.ports.push_back(micInDevice);
+
+ AudioPort micInBackDevice =
+ createPort(c.nextPortId++, "Built-In Back Mic", 0, true,
+ createPortDeviceExt(AudioDeviceType::IN_MICROPHONE_BACK, 0));
+ micInDevice.profiles = standardPcmAudioProfiles;
+ c.ports.push_back(micInBackDevice);
+
+ AudioPort primaryInMix =
+ createPort(c.nextPortId++, "primary input", 0, true, createPortMixExt(0, 1));
+ primaryInMix.profiles = standardPcmAudioProfiles;
+ c.ports.push_back(primaryInMix);
+
AudioPort btOutDevice =
createPort(c.nextPortId++, "BT A2DP Out", 0, false,
createPortDeviceExt(AudioDeviceType::OUT_DEVICE, 0,
@@ -172,6 +191,7 @@
btOutMix.profiles = standardPcmAudioProfiles;
c.ports.push_back(btOutMix);
+ c.routes.push_back(createRoute({micInDevice, micInBackDevice}, primaryInMix));
c.routes.push_back(createRoute({btOutMix}, btOutDevice));
return c;
@@ -184,6 +204,11 @@
explicit ModuleMock(const Configuration& config) : mConfig(config) {}
bool isScreenTurnedOn() const { return mIsScreenTurnedOn; }
ScreenRotation getScreenRotation() const { return mScreenRotation; }
+ std::vector<AudioPatch> getPatches() {
+ std::vector<AudioPatch> result;
+ getAudioPatches(&result);
+ return result;
+ }
private:
ndk::ScopedAStatus setModuleDebug(
@@ -1141,3 +1166,51 @@
EXPECT_EQ(0, mMapper->findFwkPatch(mPatch.id));
EXPECT_EQ(0, mMapper->findFwkPatch(newPatchId));
}
+
+TEST_F(Hal2AidlMapperTest, ChangeTransientPatchDevice) {
+ std::mutex mutex; // Only needed for cleanups.
+ auto mapperAccessor = std::make_unique<LockedAccessor<Hal2AidlMapper>>(*mMapper, mutex);
+ Hal2AidlMapper::Cleanups cleanups(*mapperAccessor);
+ AudioConfig config;
+ config.base.channelMask = AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
+ AudioChannelLayout::LAYOUT_STEREO);
+ config.base.format =
+ AudioFormatDescription{.type = AudioFormatType::PCM, .pcm = PcmType::INT_16_BIT};
+ config.base.sampleRate = 48000;
+ AudioDevice defaultDevice;
+ defaultDevice.type.type = AudioDeviceType::IN_DEFAULT;
+ AudioPortConfig mixPortConfig;
+ AudioPatch transientPatch;
+ ASSERT_EQ(OK, mMapper->prepareToOpenStream(43 /*ioHandle*/, defaultDevice,
+ AudioIoFlags::make<AudioIoFlags::input>(0),
+ AudioSource::DEFAULT, &cleanups, &config,
+ &mixPortConfig, &transientPatch));
+ cleanups.disarmAll();
+ ASSERT_NE(0, transientPatch.id);
+ ASSERT_NE(0, mixPortConfig.id);
+ sp<StreamHalInterface> stream = sp<StreamHalMock>::make();
+ mMapper->addStream(stream, mixPortConfig.id, transientPatch.id);
+
+ AudioPatch patch{};
+ int32_t patchId;
+ AudioPortConfig backMicPortConfig;
+ backMicPortConfig.channelMask = config.base.channelMask;
+ backMicPortConfig.format = config.base.format;
+ backMicPortConfig.sampleRate = aidl::android::media::audio::common::Int{config.base.sampleRate};
+ backMicPortConfig.flags = AudioIoFlags::make<AudioIoFlags::input>(0);
+ backMicPortConfig.ext = createPortDeviceExt(AudioDeviceType::IN_MICROPHONE_BACK, 0);
+ ASSERT_EQ(OK, mMapper->createOrUpdatePatch({backMicPortConfig}, {mixPortConfig}, &patchId,
+ &cleanups));
+ cleanups.disarmAll();
+ ASSERT_EQ(android::OK,
+ mMapper->findPortConfig(backMicPortConfig.ext.get<AudioPortExt::device>().device,
+ &backMicPortConfig));
+ EXPECT_NE(0, backMicPortConfig.id);
+
+ EXPECT_EQ(transientPatch.id, patchId);
+ auto patches = mModule->getPatches();
+ auto patchIt = findById(patches, patchId);
+ ASSERT_NE(patchIt, patches.end());
+ EXPECT_EQ(std::vector<int32_t>{backMicPortConfig.id}, patchIt->sourcePortConfigIds);
+ EXPECT_EQ(std::vector<int32_t>{mixPortConfig.id}, patchIt->sinkPortConfigIds);
+}
diff --git a/media/libeffects/lvm/wrapper/Reverb/aidl/ReverbContext.cpp b/media/libeffects/lvm/wrapper/Reverb/aidl/ReverbContext.cpp
index 44ea2a4..3ae3edc 100644
--- a/media/libeffects/lvm/wrapper/Reverb/aidl/ReverbContext.cpp
+++ b/media/libeffects/lvm/wrapper/Reverb/aidl/ReverbContext.cpp
@@ -19,6 +19,7 @@
#define LOG_TAG "ReverbContext"
#include <android-base/logging.h>
#include <Utils.h>
+#include <audio_utils/primitives.h>
#include "ReverbContext.h"
#include "VectorArithmetic.h"
@@ -347,6 +348,15 @@
mCommon.output.base.channelMask);
int frameCount = mCommon.input.frameCount;
+ if (mBypass) {
+ if (isAuxiliary()) {
+ memset(out, 0, getOutputFrameSize() * frameCount);
+ } else {
+ memcpy_to_float_from_float_with_clamping(out, in, samples, 1);
+ }
+ return {STATUS_OK, samples, outChannels * frameCount};
+ }
+
// Reverb only effects the stereo channels in multichannel source.
if (channels < 1 || channels > LVM_MAX_CHANNELS) {
LOG(ERROR) << __func__ << " process invalid PCM channels " << channels;
diff --git a/media/libmediaplayerservice/fuzzer/Android.bp b/media/libmediaplayerservice/fuzzer/Android.bp
index 6469ab6..5ff5a33 100644
--- a/media/libmediaplayerservice/fuzzer/Android.bp
+++ b/media/libmediaplayerservice/fuzzer/Android.bp
@@ -130,7 +130,6 @@
"libplayerservice_datasource",
],
shared_libs: [
- "libmediaplayerservice",
"libdatasource",
"libdrmframework",
"libstagefright_httplive",
diff --git a/media/libstagefright/MediaMuxer.cpp b/media/libstagefright/MediaMuxer.cpp
index aaf7465..1008445 100644
--- a/media/libstagefright/MediaMuxer.cpp
+++ b/media/libstagefright/MediaMuxer.cpp
@@ -249,6 +249,11 @@
sampleMetaData.setInt32(kKeyIsMuxerData, 1);
}
+ if (flags & MediaCodec::BUFFER_FLAG_CODECCONFIG) {
+ sampleMetaData.setInt32(kKeyIsCodecConfig, true);
+ ALOGV("BUFFER_FLAG_CODEC_CONFIG");
+ }
+
if (flags & MediaCodec::BUFFER_FLAG_EOS) {
sampleMetaData.setInt32(kKeyIsEndOfStream, 1);
ALOGV("BUFFER_FLAG_EOS");
diff --git a/media/libstagefright/webm/WebmFrameThread.cpp b/media/libstagefright/webm/WebmFrameThread.cpp
index 7d1442b..e20a08d 100644
--- a/media/libstagefright/webm/WebmFrameThread.cpp
+++ b/media/libstagefright/webm/WebmFrameThread.cpp
@@ -354,6 +354,17 @@
}
MetaDataBase &md = buffer->meta_data();
+
+ if (mType == kVideoType) {
+ int32_t isCodecConfig = 0;
+ if (md.findInt32(kKeyIsCodecConfig, &isCodecConfig) && isCodecConfig) {
+ ALOGI("ignoring CSD for video track");
+ buffer->release();
+ buffer = NULL;
+ continue;
+ }
+ }
+
CHECK(md.findInt64(kKeyTime, ×tampUs));
if (mStartTimeUs == kUninitialized) {
mStartTimeUs = timestampUs;
diff --git a/media/module/aidlpersistentsurface/aidl/android/media/IAidlNode.aidl b/media/module/aidlpersistentsurface/aidl/android/media/IAidlNode.aidl
index cf880c2..fe3caf3 100644
--- a/media/module/aidlpersistentsurface/aidl/android/media/IAidlNode.aidl
+++ b/media/module/aidlpersistentsurface/aidl/android/media/IAidlNode.aidl
@@ -44,7 +44,7 @@
void setInputSurface(IAidlBufferSource bufferSource);
void submitBuffer(
int buffer,
- in HardwareBuffer hBuffer,
+ in @nullable HardwareBuffer hBuffer,
int flags,
long timestampUs,
in @nullable ParcelFileDescriptor fence);
diff --git a/media/module/aidlpersistentsurface/wrapper/WAidlGraphicBufferSource.cpp b/media/module/aidlpersistentsurface/wrapper/WAidlGraphicBufferSource.cpp
index 5526b10..a5c72d6 100644
--- a/media/module/aidlpersistentsurface/wrapper/WAidlGraphicBufferSource.cpp
+++ b/media/module/aidlpersistentsurface/wrapper/WAidlGraphicBufferSource.cpp
@@ -51,19 +51,24 @@
int32_t bufferId, uint32_t flags,
const sp<GraphicBuffer> &buffer,
int64_t timestamp, int fenceFd) override {
- AHardwareBuffer *ahwBuffer = nullptr;
- ::aidl::android::hardware::HardwareBuffer hBuffer;
+ ::ndk::ScopedFileDescriptor fence(fenceFd);
if (buffer.get()) {
- ahwBuffer = AHardwareBuffer_from_GraphicBuffer(buffer.get());
+ ::aidl::android::hardware::HardwareBuffer hBuffer;
+ AHardwareBuffer *ahwBuffer = AHardwareBuffer_from_GraphicBuffer(buffer.get());
AHardwareBuffer_acquire(ahwBuffer);
hBuffer.reset(ahwBuffer);
- }
- ::ndk::ScopedFileDescriptor fence(fenceFd);
+ return fromAidlStatus(mNode->submitBuffer(
+ bufferId,
+ std::move(hBuffer),
+ flags,
+ timestamp,
+ fence));
+ }
return fromAidlStatus(mNode->submitBuffer(
bufferId,
- hBuffer,
+ {},
flags,
timestamp,
fence));
diff --git a/media/utils/Android.bp b/media/utils/Android.bp
index 5b7319a..e340b40 100644
--- a/media/utils/Android.bp
+++ b/media/utils/Android.bp
@@ -113,6 +113,7 @@
export_shared_lib_headers: [
"libpermission",
+ "packagemanager_aidl-cpp",
],
required: [
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index fa18a71..c8b0aa1 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -2179,6 +2179,13 @@
}
}
+void AudioFlinger::onHardError(std::set<audio_port_handle_t>& trackPortIds) {
+ ALOGI("releasing tracks due to a hard error occurred on an I/O thread");
+ for (const auto portId : trackPortIds) {
+ AudioSystem::releaseOutput(portId);
+ }
+}
+
// removeClient_l() must be called with AudioFlinger::clientMutex() held
void AudioFlinger::removeClient_l(pid_t pid)
{
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index fbd3e4a..3885465 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -398,6 +398,8 @@
void onSupportedLatencyModesChanged(
audio_io_handle_t output, const std::vector<audio_latency_mode_t>& modes) final
EXCLUDES_AudioFlinger_ClientMutex;
+ void onHardError(std::set<audio_port_handle_t>& trackPortIds) final
+ EXCLUDES_AudioFlinger_ClientMutex;
// ---- end of IAfThreadCallback interface
diff --git a/services/audioflinger/IAfThread.h b/services/audioflinger/IAfThread.h
index 46a67e8..c2a58c6 100644
--- a/services/audioflinger/IAfThread.h
+++ b/services/audioflinger/IAfThread.h
@@ -115,9 +115,11 @@
const sp<AudioIoDescriptor>& ioDesc,
pid_t pid = 0) EXCLUDES_AudioFlinger_ClientMutex = 0;
virtual void onNonOffloadableGlobalEffectEnable() EXCLUDES_AudioFlinger_Mutex = 0;
- virtual void onSupportedLatencyModesChanged(
- audio_io_handle_t output, const std::vector<audio_latency_mode_t>& modes)
+ virtual void onSupportedLatencyModesChanged(audio_io_handle_t output,
+ const std::vector<audio_latency_mode_t>& modes)
EXCLUDES_AudioFlinger_ClientMutex = 0;
+
+ virtual void onHardError(std::set<audio_port_handle_t>& trackPortIds) = 0;
};
class IAfThreadBase : public virtual RefBase {
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 60abb58..0766a0d 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -3000,6 +3000,23 @@
}
}
+std::set<audio_port_handle_t> PlaybackThread::getTrackPortIds_l()
+{
+ std::set<int32_t> result;
+ for (const auto& t : mTracks) {
+ if (t->isExternalTrack()) {
+ result.insert(t->portId());
+ }
+ }
+ return result;
+}
+
+std::set<audio_port_handle_t> PlaybackThread::getTrackPortIds()
+{
+ audio_utils::lock_guard _l(mutex());
+ return getTrackPortIds_l();
+}
+
String8 PlaybackThread::getParameters(const String8& keys)
{
audio_utils::lock_guard _l(mutex());
@@ -3053,9 +3070,9 @@
mCallbackThread->resetDraining();
}
-void PlaybackThread::onError()
+void PlaybackThread::onError(bool isHardError)
{
- mCallbackThread->setAsyncError();
+ mCallbackThread->setAsyncError(isHardError);
}
void PlaybackThread::onCodecFormatChanged(
@@ -5360,11 +5377,15 @@
broadcast_l();
}
-void PlaybackThread::onAsyncError()
+void PlaybackThread::onAsyncError(bool isHardError)
{
+ auto allTrackPortIds = getTrackPortIds();
for (int i = AUDIO_STREAM_SYSTEM; i < (int)AUDIO_STREAM_CNT; i++) {
invalidateTracks((audio_stream_type_t)i);
}
+ if (isHardError) {
+ mAfThreadCallback->onHardError(allTrackPortIds);
+ }
}
void MixerThread::threadLoop_mix()
@@ -7080,11 +7101,14 @@
{
PlaybackThread::flushHw_l();
mOutput->flush();
- mHwPaused = false;
mFlushPending = false;
mTimestampVerifier.discontinuity(discontinuityForStandbyOrFlush());
mTimestamp.clear();
mMonotonicFrameCounter.onFlush();
+ // We do not reset mHwPaused which is hidden from the Track client.
+ // Note: the client track in Tracks.cpp and AudioTrack.cpp
+ // has a FLUSHED state but the DirectOutputThread does not;
+ // those tracks will continue to show isStopped().
}
int64_t DirectOutputThread::computeWaitTimeNs_l() const {
@@ -7102,7 +7126,7 @@
mPlaybackThread(playbackThread),
mWriteAckSequence(0),
mDrainSequence(0),
- mAsyncError(false)
+ mAsyncError(ASYNC_ERROR_NONE)
{
}
@@ -7116,7 +7140,7 @@
while (!exitPending()) {
uint32_t writeAckSequence;
uint32_t drainSequence;
- bool asyncError;
+ AsyncError asyncError;
{
audio_utils::unique_lock _l(mutex());
@@ -7137,7 +7161,7 @@
drainSequence = mDrainSequence;
mDrainSequence &= ~1;
asyncError = mAsyncError;
- mAsyncError = false;
+ mAsyncError = ASYNC_ERROR_NONE;
}
{
const sp<PlaybackThread> playbackThread = mPlaybackThread.promote();
@@ -7148,8 +7172,8 @@
if (drainSequence & 1) {
playbackThread->resetDraining(drainSequence >> 1);
}
- if (asyncError) {
- playbackThread->onAsyncError();
+ if (asyncError != ASYNC_ERROR_NONE) {
+ playbackThread->onAsyncError(asyncError == ASYNC_ERROR_HARD);
}
}
}
@@ -7199,10 +7223,10 @@
}
}
-void AsyncCallbackThread::setAsyncError()
+void AsyncCallbackThread::setAsyncError(bool isHardError)
{
audio_utils::lock_guard _l(mutex());
- mAsyncError = true;
+ mAsyncError = isHardError ? ASYNC_ERROR_HARD : ASYNC_ERROR_SOFT;
mWaitWorkCV.notify_one();
}
@@ -8173,6 +8197,7 @@
for (int64_t loopCount = 0;; ++loopCount) { // loopCount used for statistics tracking
// Note: these sp<> are released at the end of the for loop outside of the mutex() lock.
sp<IAfRecordTrack> activeTrack;
+ std::vector<sp<IAfRecordTrack>> oldActiveTracks;
Vector<sp<IAfEffectChain>> effectChains;
// activeTracks accumulates a copy of a subset of mActiveTracks
@@ -8222,7 +8247,9 @@
bool doBroadcast = false;
bool allStopped = true;
for (size_t i = 0; i < size; ) {
-
+ if (activeTrack) { // ensure track release is outside lock.
+ oldActiveTracks.emplace_back(std::move(activeTrack));
+ }
activeTrack = mActiveTracks[i];
if (activeTrack->isTerminated()) {
if (activeTrack->isFastTrack()) {
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index ddf0669..98e3298 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -946,7 +946,7 @@
// StreamOutHalInterfaceCallback implementation
virtual void onWriteReady();
virtual void onDrainReady();
- virtual void onError();
+ virtual void onError(bool /*isHardError*/);
public: // AsyncCallbackThread
void resetWriteBlocked(uint32_t sequence);
@@ -958,7 +958,7 @@
virtual bool shouldStandby_l() REQUIRES(mutex(), ThreadBase_ThreadLoop);
virtual void onAddNewTrack_l() REQUIRES(mutex());
public: // AsyncCallbackThread
- void onAsyncError(); // error reported by AsyncCallbackThread
+ void onAsyncError(bool isHardError); // error reported by AsyncCallbackThread
protected:
// StreamHalInterfaceCodecFormatCallback implementation
void onCodecFormatChanged(
@@ -1371,6 +1371,8 @@
bool destroyTrack_l(const sp<IAfTrack>& track) final REQUIRES(mutex());
void removeTrack_l(const sp<IAfTrack>& track) REQUIRES(mutex());
+ std::set<audio_port_handle_t> getTrackPortIds_l() REQUIRES(mutex());
+ std::set<audio_port_handle_t> getTrackPortIds();
void readOutputParameters_l() REQUIRES(mutex());
MetadataUpdate updateMetadata_l() final REQUIRES(mutex());
@@ -1834,7 +1836,7 @@
void resetWriteBlocked();
void setDraining(uint32_t sequence);
void resetDraining();
- void setAsyncError();
+ void setAsyncError(bool isHardError);
private:
const wp<PlaybackThread> mPlaybackThread;
@@ -1848,7 +1850,8 @@
uint32_t mDrainSequence;
audio_utils::condition_variable mWaitWorkCV;
mutable audio_utils::mutex mMutex{audio_utils::MutexOrder::kAsyncCallbackThread_Mutex};
- bool mAsyncError;
+ enum AsyncError { ASYNC_ERROR_NONE, ASYNC_ERROR_SOFT, ASYNC_ERROR_HARD };
+ AsyncError mAsyncError;
audio_utils::mutex& mutex() const RETURN_CAPABILITY(audio_utils::AsyncCallbackThread_Mutex) {
return mMutex;
diff --git a/services/audiopolicy/common/managerdefinitions/include/IOProfile.h b/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
index f3a9518..688772c 100644
--- a/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
+++ b/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
@@ -70,10 +70,17 @@
return mMixerBehaviors;
}
+ enum CompatibilityScore{
+ NO_MATCH = 0,
+ PARTIAL_MATCH = 1,
+ EXACT_MATCH = 2
+ };
+
/**
- * @brief isCompatibleProfile: This method is used for input and direct output,
+ * @brief compatibilityScore: This method is used for input and direct output,
* and is not used for other output.
- * Checks if the IO profile is compatible with specified parameters.
+ * Return the compatibility score to measure how much the IO profile is compatible
+ * with specified parameters.
* For input, flags is interpreted as audio_input_flags_t.
* TODO: merge audio_output_flags_t and audio_input_flags_t.
*
@@ -86,18 +93,18 @@
* @param updatedChannelMask if non-NULL, it is assigned the actual channel mask
* @param flags to be checked for compatibility
* @param exactMatchRequiredForInputFlags true if exact match is required on flags
- * @return true if the profile is compatible, false otherwise.
+ * @return how the IO profile is compatible with the given parameters.
*/
- bool isCompatibleProfile(const DeviceVector &devices,
- uint32_t samplingRate,
- uint32_t *updatedSamplingRate,
- audio_format_t format,
- audio_format_t *updatedFormat,
- audio_channel_mask_t channelMask,
- audio_channel_mask_t *updatedChannelMask,
- // FIXME parameter type
- uint32_t flags,
- bool exactMatchRequiredForInputFlags = false) const;
+ CompatibilityScore getCompatibilityScore(const DeviceVector &devices,
+ uint32_t samplingRate,
+ uint32_t *updatedSamplingRate,
+ audio_format_t format,
+ audio_format_t *updatedFormat,
+ audio_channel_mask_t channelMask,
+ audio_channel_mask_t *updatedChannelMask,
+ // FIXME parameter type
+ uint32_t flags,
+ bool exactMatchRequiredForInputFlags = false) const;
/**
* @brief areAllDevicesSupported: Checks if the given devices are supported by the IO profile.
diff --git a/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp b/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
index c7d2e6b..d9fbd89 100644
--- a/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
@@ -33,17 +33,17 @@
}
}
-bool IOProfile::isCompatibleProfile(const DeviceVector &devices,
- uint32_t samplingRate,
- uint32_t *updatedSamplingRate,
- audio_format_t format,
- audio_format_t *updatedFormat,
- audio_channel_mask_t channelMask,
- audio_channel_mask_t *updatedChannelMask,
- // FIXME type punning here
- uint32_t flags,
- bool exactMatchRequiredForInputFlags) const
-{
+IOProfile::CompatibilityScore IOProfile::getCompatibilityScore(
+ const android::DeviceVector &devices,
+ uint32_t samplingRate,
+ uint32_t *updatedSamplingRate,
+ audio_format_t format,
+ audio_format_t *updatedFormat,
+ audio_channel_mask_t channelMask,
+ audio_channel_mask_t *updatedChannelMask,
+ // FIXME type punning here
+ uint32_t flags,
+ bool exactMatchRequiredForInputFlags) const {
const bool isPlaybackThread =
getType() == AUDIO_PORT_TYPE_MIX && getRole() == AUDIO_PORT_ROLE_SOURCE;
const bool isRecordThread =
@@ -51,13 +51,13 @@
ALOG_ASSERT(isPlaybackThread != isRecordThread);
if (!areAllDevicesSupported(devices) ||
!isCompatibleProfileForFlags(flags, exactMatchRequiredForInputFlags)) {
- return false;
+ return NO_MATCH;
}
if (!audio_is_valid_format(format) ||
(isPlaybackThread && (samplingRate == 0 || !audio_is_output_channel(channelMask))) ||
(isRecordThread && (!audio_is_input_channel(channelMask)))) {
- return false;
+ return NO_MATCH;
}
audio_format_t myUpdatedFormat = format;
@@ -69,32 +69,40 @@
.channel_mask = channelMask,
.format = format,
};
+ auto result = NO_MATCH;
if (isRecordThread)
{
if ((flags & AUDIO_INPUT_FLAG_MMAP_NOIRQ) != 0) {
if (checkExactAudioProfile(&config) != NO_ERROR) {
- return false;
+ return result;
}
- } else if (checkExactAudioProfile(&config) != NO_ERROR && checkCompatibleAudioProfile(
- myUpdatedSamplingRate, myUpdatedChannelMask, myUpdatedFormat) != NO_ERROR) {
- return false;
+ result = EXACT_MATCH;
+ } else if (checkExactAudioProfile(&config) == NO_ERROR) {
+ result = EXACT_MATCH;
+ } else if (checkCompatibleAudioProfile(
+ myUpdatedSamplingRate, myUpdatedChannelMask, myUpdatedFormat) == NO_ERROR) {
+ result = PARTIAL_MATCH;
+ } else {
+ return result;
}
} else {
- if (checkExactAudioProfile(&config) != NO_ERROR) {
- return false;
+ if (checkExactAudioProfile(&config) == NO_ERROR) {
+ result = EXACT_MATCH;
+ } else {
+ return result;
}
}
- if (updatedSamplingRate != NULL) {
+ if (updatedSamplingRate != nullptr) {
*updatedSamplingRate = myUpdatedSamplingRate;
}
- if (updatedFormat != NULL) {
+ if (updatedFormat != nullptr) {
*updatedFormat = myUpdatedFormat;
}
- if (updatedChannelMask != NULL) {
+ if (updatedChannelMask != nullptr) {
*updatedChannelMask = myUpdatedChannelMask;
}
- return true;
+ return result;
}
bool IOProfile::areAllDevicesSupported(const DeviceVector &devices) const {
diff --git a/services/audiopolicy/engine/config/src/EngineConfig.cpp b/services/audiopolicy/engine/config/src/EngineConfig.cpp
index ca78ce7..3f9ae19 100644
--- a/services/audiopolicy/engine/config/src/EngineConfig.cpp
+++ b/services/audiopolicy/engine/config/src/EngineConfig.cpp
@@ -22,6 +22,7 @@
#include <string>
#include <string>
#include <vector>
+#include <unordered_map>
#define LOG_TAG "APM::AudioPolicyEngine/Config"
//#define LOG_NDEBUG 0
@@ -51,6 +52,27 @@
namespace {
+ConversionResult<std::string> aidl2legacy_AudioHalProductStrategy_ProductStrategyType(int id) {
+ using AudioProductStrategyType = media::audio::common::AudioProductStrategyType;
+
+#define STRATEGY_ENTRY(name) {static_cast<int>(AudioProductStrategyType::name), "STRATEGY_" #name}
+ static const std::unordered_map<int, std::string> productStrategyMap = {STRATEGY_ENTRY(MEDIA),
+ STRATEGY_ENTRY(PHONE),
+ STRATEGY_ENTRY(SONIFICATION),
+ STRATEGY_ENTRY(SONIFICATION_RESPECTFUL),
+ STRATEGY_ENTRY(DTMF),
+ STRATEGY_ENTRY(ENFORCED_AUDIBLE),
+ STRATEGY_ENTRY(TRANSMITTED_THROUGH_SPEAKER),
+ STRATEGY_ENTRY(ACCESSIBILITY)};
+#undef STRATEGY_ENTRY
+
+ auto it = productStrategyMap.find(id);
+ if (it == productStrategyMap.end()) {
+ return base::unexpected(BAD_VALUE);
+ }
+ return it->second;
+}
+
ConversionResult<AttributesGroup> aidl2legacy_AudioHalAttributeGroup_AttributesGroup(
const media::audio::common::AudioHalAttributesGroup& aidl) {
AttributesGroup legacy;
@@ -65,7 +87,8 @@
ConversionResult<ProductStrategy> aidl2legacy_AudioHalProductStrategy_ProductStrategy(
const media::audio::common::AudioHalProductStrategy& aidl) {
ProductStrategy legacy;
- legacy.name = "strategy_" + std::to_string(aidl.id);
+ legacy.name = VALUE_OR_RETURN(
+ aidl2legacy_AudioHalProductStrategy_ProductStrategyType(aidl.id));
legacy.attributesGroups = VALUE_OR_RETURN(convertContainer<AttributesGroups>(
aidl.attributesGroups,
aidl2legacy_AudioHalAttributeGroup_AttributesGroup));
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 5c4ab7b..15c6a75 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -390,8 +390,12 @@
// Before checking intputs, broadcast connect event to allow HAL to retrieve dynamic
// parameters on newly connected devices (instead of opening the inputs...)
broadcastDeviceConnectionState(device, media::DeviceConnectedState::CONNECTED);
+ // Propagate device availability to Engine
+ setEngineDeviceConnectionState(device, state);
if (checkInputsForDevice(device, state) != NO_ERROR) {
+ setEngineDeviceConnectionState(device, AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE);
+
mAvailableInputDevices.remove(device);
broadcastDeviceConnectionState(device, media::DeviceConnectedState::DISCONNECTED);
@@ -425,6 +429,9 @@
// remove device from mReportedFormatsMap cache
mReportedFormatsMap.erase(device);
+
+ // Propagate device availability to Engine
+ setEngineDeviceConnectionState(device, state);
} break;
default:
@@ -432,9 +439,6 @@
return BAD_VALUE;
}
- // Propagate device availability to Engine
- setEngineDeviceConnectionState(device, state);
-
checkCloseInputs();
// As the input device list can impact the output device selection, update
// getDeviceForStrategy() cache
@@ -1043,11 +1047,11 @@
sp<IOProfile> profile;
for (const auto& hwModule : hwModules) {
for (const auto& curProfile : hwModule->getOutputProfiles()) {
- if (!curProfile->isCompatibleProfile(devices,
+ if (curProfile->getCompatibilityScore(devices,
samplingRate, NULL /*updatedSamplingRate*/,
format, NULL /*updatedFormat*/,
channelMask, NULL /*updatedChannelMask*/,
- flags)) {
+ flags) == IOProfile::NO_MATCH) {
continue;
}
// reject profiles not corresponding to a device currently available
@@ -3175,6 +3179,23 @@
releaseInput(portId);
}
+bool AudioPolicyManager::checkCloseInput(const sp<AudioInputDescriptor>& input) {
+ if (input->clientsList().size() == 0
+ || !mAvailableInputDevices.containsAtLeastOne(input->supportedDevices())) {
+ return true;
+ }
+ for (const auto& client : input->clientsList()) {
+ sp<DeviceDescriptor> device =
+ mEngine->getInputDeviceForAttributes(client->attributes(), client->uid(),
+ client->session());
+ if (!input->supportedDevices().contains(device)) {
+ return true;
+ }
+ }
+ setInputDevice(input->mIoHandle, getNewInputDevice(input));
+ return false;
+}
+
void AudioPolicyManager::checkCloseInputs() {
// After connecting or disconnecting an input device, close input if:
// - it has no client (was just opened to check profile) OR
@@ -3183,29 +3204,10 @@
// devices anymore. Otherwise update device selection
std::vector<audio_io_handle_t> inputsToClose;
for (size_t i = 0; i < mInputs.size(); i++) {
- const sp<AudioInputDescriptor> input = mInputs.valueAt(i);
- if (input->clientsList().size() == 0
- || !mAvailableInputDevices.containsAtLeastOne(input->supportedDevices())) {
+ if (checkCloseInput(mInputs.valueAt(i))) {
inputsToClose.push_back(mInputs.keyAt(i));
- } else {
- bool close = false;
- for (const auto& client : input->clientsList()) {
- sp<DeviceDescriptor> device =
- mEngine->getInputDeviceForAttributes(client->attributes(), client->uid(),
- client->session());
- if (!input->supportedDevices().contains(device)) {
- close = true;
- break;
- }
- }
- if (close) {
- inputsToClose.push_back(mInputs.keyAt(i));
- } else {
- setInputDevice(input->mIoHandle, getNewInputDevice(input));
- }
}
}
-
for (const audio_io_handle_t handle : inputsToClose) {
ALOGV("%s closing input %d", __func__, handle);
closeInput(handle);
@@ -4463,11 +4465,11 @@
outputDevices = getMsdAudioOutDevices();
}
for (const auto& curProfile : hwModule->getOutputProfiles()) {
- if (!curProfile->isCompatibleProfile(outputDevices,
+ if (curProfile->getCompatibilityScore(outputDevices,
config->sample_rate, nullptr /*updatedSamplingRate*/,
config->format, nullptr /*updatedFormat*/,
config->channel_mask, nullptr /*updatedChannelMask*/,
- flags)) {
+ flags) == IOProfile::NO_MATCH) {
continue;
}
// reject profiles not corresponding to a device currently available
@@ -4573,15 +4575,17 @@
for (const auto& hwModule : mHwModules) {
for (const auto& curProfile : hwModule->getOutputProfiles()) {
if (curProfile->hasDynamicAudioProfile()
- && curProfile->isCompatibleProfile(devices,
- mixerAttributes->config.sample_rate,
- nullptr /*updatedSamplingRate*/,
- mixerAttributes->config.format,
- nullptr /*updatedFormat*/,
- mixerAttributes->config.channel_mask,
- nullptr /*updatedChannelMask*/,
- flags,
- false /*exactMatchRequiredForInputFlags*/)) {
+ && curProfile->getCompatibilityScore(
+ devices,
+ mixerAttributes->config.sample_rate,
+ nullptr /*updatedSamplingRate*/,
+ mixerAttributes->config.format,
+ nullptr /*updatedFormat*/,
+ mixerAttributes->config.channel_mask,
+ nullptr /*updatedChannelMask*/,
+ flags,
+ false /*exactMatchRequiredForInputFlags*/)
+ != IOProfile::NO_MATCH) {
profile = curProfile;
break;
}
@@ -4984,14 +4988,15 @@
return BAD_VALUE;
}
- if (!outputDesc->mProfile->isCompatibleProfile(DeviceVector(devDesc),
- patch->sources[0].sample_rate,
- NULL, // updatedSamplingRate
- patch->sources[0].format,
- NULL, // updatedFormat
- patch->sources[0].channel_mask,
- NULL, // updatedChannelMask
- AUDIO_OUTPUT_FLAG_NONE /*FIXME*/)) {
+ if (outputDesc->mProfile->getCompatibilityScore(
+ DeviceVector(devDesc),
+ patch->sources[0].sample_rate,
+ nullptr, // updatedSamplingRate
+ patch->sources[0].format,
+ nullptr, // updatedFormat
+ patch->sources[0].channel_mask,
+ nullptr, // updatedChannelMask
+ AUDIO_OUTPUT_FLAG_NONE /*FIXME*/) == IOProfile::NO_MATCH) {
ALOGV("%s profile not supported for device %08x", __func__, devDesc->type());
return INVALID_OPERATION;
}
@@ -5039,17 +5044,18 @@
return BAD_VALUE;
}
- if (!inputDesc->mProfile->isCompatibleProfile(DeviceVector(device),
- patch->sinks[0].sample_rate,
- NULL, /*updatedSampleRate*/
- patch->sinks[0].format,
- NULL, /*updatedFormat*/
- patch->sinks[0].channel_mask,
- NULL, /*updatedChannelMask*/
- // FIXME for the parameter type,
- // and the NONE
- (audio_output_flags_t)
- AUDIO_INPUT_FLAG_NONE)) {
+ if (inputDesc->mProfile->getCompatibilityScore(
+ DeviceVector(device),
+ patch->sinks[0].sample_rate,
+ nullptr, /*updatedSampleRate*/
+ patch->sinks[0].format,
+ nullptr, /*updatedFormat*/
+ patch->sinks[0].channel_mask,
+ nullptr, /*updatedChannelMask*/
+ // FIXME for the parameter type,
+ // and the NONE
+ (audio_output_flags_t)
+ AUDIO_INPUT_FLAG_NONE) == IOProfile::NO_MATCH) {
return INVALID_OPERATION;
}
// TODO: reconfigure output format and channels here
@@ -6606,14 +6612,14 @@
status_t AudioPolicyManager::checkInputsForDevice(const sp<DeviceDescriptor>& device,
audio_policy_dev_state_t state)
{
- sp<AudioInputDescriptor> desc;
-
if (audio_device_is_digital(device->type())) {
// erase all current sample rates, formats and channel masks
device->clearAudioProfiles();
}
if (state == AUDIO_POLICY_DEVICE_STATE_AVAILABLE) {
+ sp<AudioInputDescriptor> desc;
+
// first call getAudioPort to get the supported attributes from the HAL
struct audio_port_v7 port = {};
device->toAudioPort(&port);
@@ -6704,6 +6710,11 @@
device->importAudioPortAndPickAudioProfile(profile);
}
ALOGV("checkInputsForDevice(): adding input %d", input);
+
+ if (checkCloseInput(desc)) {
+ ALOGV("%s closing input %d", __func__, input);
+ closeInput(input);
+ }
}
} // end scan profiles
@@ -7675,9 +7686,6 @@
// Choose an input profile based on the requested capture parameters: select the first available
// profile supporting all requested parameters.
// The flags can be ignored if it doesn't contain a much match flag.
- //
- // TODO: perhaps isCompatibleProfile should return a "matching" score so we can return
- // the best matching profile, not the first one.
using underlying_input_flag_t = std::underlying_type_t<audio_input_flags_t>;
const underlying_input_flag_t mustMatchFlag = AUDIO_INPUT_FLAG_MMAP_NOIRQ |
@@ -7694,27 +7702,35 @@
for (const auto& profile : hwModule->getInputProfiles()) {
// profile->log();
//updatedFormat = format;
- if (profile->isCompatibleProfile(DeviceVector(device), samplingRate,
- &samplingRate /*updatedSamplingRate*/,
- format,
- &format, /*updatedFormat*/
- channelMask,
- &channelMask /*updatedChannelMask*/,
- // FIXME ugly cast
- (audio_output_flags_t) flags,
- true /*exactMatchRequiredForInputFlags*/)) {
+ if (profile->getCompatibilityScore(
+ DeviceVector(device),
+ samplingRate,
+ &updatedSamplingRate,
+ format,
+ &updatedFormat,
+ channelMask,
+ &updatedChannelMask,
+ // FIXME ugly cast
+ (audio_output_flags_t) flags,
+ true /*exactMatchRequiredForInputFlags*/) == IOProfile::EXACT_MATCH) {
+ samplingRate = updatedSamplingRate;
+ format = updatedFormat;
+ channelMask = updatedChannelMask;
return profile;
}
- if (firstInexact == nullptr && profile->isCompatibleProfile(DeviceVector(device),
- samplingRate,
- &updatedSamplingRate,
- format,
- &updatedFormat,
- channelMask,
- &updatedChannelMask,
- // FIXME ugly cast
- (audio_output_flags_t) flags,
- false /*exactMatchRequiredForInputFlags*/)) {
+ if (firstInexact == nullptr
+ && profile->getCompatibilityScore(
+ DeviceVector(device),
+ samplingRate,
+ &updatedSamplingRate,
+ format,
+ &updatedFormat,
+ channelMask,
+ &updatedChannelMask,
+ // FIXME ugly cast
+ (audio_output_flags_t) flags,
+ false /*exactMatchRequiredForInputFlags*/)
+ != IOProfile::NO_MATCH) {
firstInexact = profile;
}
}
@@ -7919,7 +7935,7 @@
if (deviceTypes.empty()) {
deviceTypes = outputDesc->devices().types();
index = curves.getVolumeIndex(deviceTypes);
- ALOGD("%s if deviceTypes is change from none to device %s, need get index %d",
+ ALOGV("%s if deviceTypes is change from none to device %s, need get index %d",
__func__, dumpDeviceTypes(deviceTypes).c_str(), index);
}
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 61be09f..7513952 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -526,6 +526,7 @@
void addOutput(audio_io_handle_t output, const sp<SwAudioOutputDescriptor>& outputDesc);
void removeOutput(audio_io_handle_t output);
void addInput(audio_io_handle_t input, const sp<AudioInputDescriptor>& inputDesc);
+ bool checkCloseInput(const sp<AudioInputDescriptor>& input);
/**
* @brief setOutputDevices change the route of the specified output.
diff --git a/services/audiopolicy/tests/AudioPolicyManagerTestClient.h b/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
index 7ef0266..072d9c0 100644
--- a/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
+++ b/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
@@ -70,6 +70,22 @@
return BAD_VALUE;
}
*input = mNextIoHandle++;
+ mOpenedInputs.insert(*input);
+ ALOGD("%s: opened input %d", __func__, *input);
+ return NO_ERROR;
+ }
+
+ status_t closeInput(audio_io_handle_t input) override {
+ if (mOpenedInputs.erase(input) != 1) {
+ if (input >= mNextIoHandle) {
+ ALOGE("%s: I/O handle %d has not been allocated yet (next is %d)",
+ __func__, input, mNextIoHandle);
+ } else {
+ ALOGE("%s: Attempt to close input %d twice", __func__, input);
+ }
+ return BAD_VALUE;
+ }
+ ALOGD("%s: closed input %d", __func__, input);
return NO_ERROR;
}
@@ -124,6 +140,8 @@
return &it->second;
};
+ size_t getOpenedInputsCount() const { return mOpenedInputs.size(); }
+
audio_module_handle_t peekNextModuleHandle() const { return mNextModuleHandle; }
void swapAllowedModuleNames(std::set<std::string>&& names = {}) {
@@ -241,6 +259,7 @@
std::vector<struct audio_port_v7> mDisconnectedDevicePorts;
std::set<audio_format_t> mSupportedFormats;
std::set<audio_channel_mask_t> mSupportedChannelMasks;
+ std::set<audio_io_handle_t> mOpenedInputs;
};
} // namespace android
diff --git a/services/audiopolicy/tests/AudioPolicyTestManager.h b/services/audiopolicy/tests/AudioPolicyTestManager.h
index 31ee252..34ceeab 100644
--- a/services/audiopolicy/tests/AudioPolicyTestManager.h
+++ b/services/audiopolicy/tests/AudioPolicyTestManager.h
@@ -31,8 +31,10 @@
using AudioPolicyManager::getConfig;
using AudioPolicyManager::initialize;
using AudioPolicyManager::getOutputs;
+ using AudioPolicyManager::getInputs;
using AudioPolicyManager::getAvailableOutputDevices;
using AudioPolicyManager::getAvailableInputDevices;
+ using AudioPolicyManager::checkInputsForDevice;
using AudioPolicyManager::setSurroundFormatEnabled;
using AudioPolicyManager::releaseMsdOutputPatches;
using AudioPolicyManager::setMsdOutputPatches;
@@ -43,6 +45,7 @@
using AudioPolicyManager::deviceToAudioPort;
using AudioPolicyManager::handleDeviceConfigChange;
uint32_t getAudioPortGeneration() const { return mAudioPortGeneration; }
+ HwModuleCollection getHwModules() const { return mHwModules; }
};
} // namespace android
diff --git a/services/audiopolicy/tests/audiopolicymanager_tests.cpp b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
index 8642fd4..4d9d87c 100644
--- a/services/audiopolicy/tests/audiopolicymanager_tests.cpp
+++ b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
@@ -92,6 +92,12 @@
return attributionSourceState;
}
+bool equals(const audio_config_base_t& config1, const audio_config_base_t& config2) {
+ return config1.format == config2.format
+ && config1.sample_rate == config2.sample_rate
+ && config1.channel_mask == config2.channel_mask;
+}
+
} // namespace
TEST(AudioPolicyConfigTest, DefaultConfigForTestsIsEmpty) {
@@ -1266,6 +1272,82 @@
"", "", AUDIO_FORMAT_LDAC));
}
+TEST_F(AudioPolicyManagerTestWithConfigurationFile, PreferExactConfigForInput) {
+ const audio_channel_mask_t deviceChannelMask = AUDIO_CHANNEL_IN_3POINT1;
+ mClient->addSupportedFormat(AUDIO_FORMAT_PCM_16_BIT);
+ mClient->addSupportedChannelMask(deviceChannelMask);
+ ASSERT_EQ(NO_ERROR, mManager->setDeviceConnectionState(AUDIO_DEVICE_IN_USB_DEVICE,
+ AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
+ "", "", AUDIO_FORMAT_DEFAULT));
+
+ audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
+ audio_attributes_t attr = {AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN,
+ AUDIO_SOURCE_VOICE_COMMUNICATION,AUDIO_FLAG_NONE, ""};
+ AudioPolicyInterface::input_type_t inputType;
+ audio_io_handle_t input = AUDIO_PORT_HANDLE_NONE;
+ AttributionSourceState attributionSource = createAttributionSourceState(/*uid=*/ 0);
+ audio_config_base_t requestedConfig = {
+ .channel_mask = AUDIO_CHANNEL_IN_STEREO,
+ .format = AUDIO_FORMAT_PCM_16_BIT,
+ .sample_rate = 48000
+ };
+ audio_config_base_t config = requestedConfig;
+ audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
+ ASSERT_EQ(OK, mManager->getInputForAttr(
+ &attr, &input, 1 /*riid*/, AUDIO_SESSION_NONE, attributionSource, &config,
+ AUDIO_INPUT_FLAG_NONE,
+ &selectedDeviceId, &inputType, &portId));
+ ASSERT_NE(AUDIO_PORT_HANDLE_NONE, portId);
+ ASSERT_TRUE(equals(requestedConfig, config));
+
+ attr = {AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN,
+ AUDIO_SOURCE_VOICE_COMMUNICATION, AUDIO_FLAG_NONE, ""};
+ requestedConfig.channel_mask = deviceChannelMask;
+ config = requestedConfig;
+ selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
+ input = AUDIO_PORT_HANDLE_NONE;
+ portId = AUDIO_PORT_HANDLE_NONE;
+ ASSERT_EQ(OK, mManager->getInputForAttr(
+ &attr, &input, 1 /*riid*/, AUDIO_SESSION_NONE, attributionSource, &config,
+ AUDIO_INPUT_FLAG_NONE,
+ &selectedDeviceId, &inputType, &portId));
+ ASSERT_NE(AUDIO_PORT_HANDLE_NONE, portId);
+ ASSERT_TRUE(equals(requestedConfig, config));
+
+ ASSERT_EQ(NO_ERROR, mManager->setDeviceConnectionState(AUDIO_DEVICE_IN_USB_DEVICE,
+ AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
+ "", "", AUDIO_FORMAT_DEFAULT));
+}
+
+TEST_F(AudioPolicyManagerTestWithConfigurationFile, CheckInputsForDeviceClosesStreams) {
+ mClient->addSupportedFormat(AUDIO_FORMAT_PCM_16_BIT);
+ mClient->addSupportedFormat(AUDIO_FORMAT_PCM_24_BIT_PACKED);
+ mClient->addSupportedChannelMask(AUDIO_CHANNEL_IN_MONO);
+ mClient->addSupportedChannelMask(AUDIO_CHANNEL_IN_STEREO);
+ // Since 'checkInputsForDevice' is called as part of the 'setDeviceConnectionState',
+ // call it directly here, as we need to ensure that it does not keep all intermediate
+ // streams opened, as it may cause a rejection from the HAL based on the cap.
+ const size_t streamCountBefore = mClient->getOpenedInputsCount();
+ sp<DeviceDescriptor> device = mManager->getHwModules().getDeviceDescriptor(
+ AUDIO_DEVICE_IN_USB_DEVICE, "", "", AUDIO_FORMAT_DEFAULT, true /*allowToCreate*/);
+ ASSERT_NE(nullptr, device.get());
+ EXPECT_EQ(NO_ERROR,
+ mManager->checkInputsForDevice(device, AUDIO_POLICY_DEVICE_STATE_AVAILABLE));
+ EXPECT_EQ(streamCountBefore, mClient->getOpenedInputsCount());
+}
+
+TEST_F(AudioPolicyManagerTestWithConfigurationFile, SetDeviceConnectionStateClosesStreams) {
+ mClient->addSupportedFormat(AUDIO_FORMAT_PCM_16_BIT);
+ mClient->addSupportedFormat(AUDIO_FORMAT_PCM_24_BIT_PACKED);
+ mClient->addSupportedChannelMask(AUDIO_CHANNEL_IN_MONO);
+ mClient->addSupportedChannelMask(AUDIO_CHANNEL_IN_STEREO);
+ const size_t streamCountBefore = mClient->getOpenedInputsCount();
+ EXPECT_EQ(NO_ERROR, mManager->setDeviceConnectionState(AUDIO_DEVICE_IN_USB_DEVICE,
+ AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
+ "", "", AUDIO_FORMAT_DEFAULT));
+ EXPECT_EQ(streamCountBefore, mClient->getOpenedInputsCount());
+}
+
class AudioPolicyManagerTestDynamicPolicy : public AudioPolicyManagerTestWithConfigurationFile {
protected:
void TearDown() override;
diff --git a/services/audiopolicy/tests/resources/test_audio_policy_configuration.xml b/services/audiopolicy/tests/resources/test_audio_policy_configuration.xml
index 4efdf8a..bbc19fa 100644
--- a/services/audiopolicy/tests/resources/test_audio_policy_configuration.xml
+++ b/services/audiopolicy/tests/resources/test_audio_policy_configuration.xml
@@ -65,6 +65,7 @@
samplingRates="48000"
channelMasks="AUDIO_CHANNEL_IN_STEREO"/>
</mixPort>
+ <mixPort name="hifi_input" role="sink" />
</mixPorts>
<devicePorts>
<devicePort tagName="Speaker" type="AUDIO_DEVICE_OUT_SPEAKER" role="sink">
@@ -98,7 +99,7 @@
<route type="mix" sink="primary input"
sources="Built-In Mic,Hdmi-In Mic,USB Device In"/>
<route type="mix" sink="voip_tx"
- sources="Built-In Mic"/>
+ sources="Built-In Mic,USB Device In"/>
<route type="mix" sink="Hdmi"
sources="primary output"/>
<route type="mix" sink="BT SCO"
@@ -111,6 +112,8 @@
sources="primary output,hifi_output,mmap_no_irq_out"/>
<route type="mix" sink="mixport_bus_input"
sources="BUS Device In"/>
+ <route type="mix" sink="hifi_input"
+ sources="USB Device In" />
</routes>
</module>
diff --git a/services/camera/virtualcamera/util/EglProgram.cc b/services/camera/virtualcamera/util/EglProgram.cc
index 510fd33..85ff735 100644
--- a/services/camera/virtualcamera/util/EglProgram.cc
+++ b/services/camera/virtualcamera/util/EglProgram.cc
@@ -88,7 +88,7 @@
})";
constexpr char kExternalRgbaTextureFragmentShader[] = R"(#version 300 es
- #extension GL_OES_EGL_image_external : require
+ #extension GL_OES_EGL_image_external_essl3 : require
#extension GL_EXT_YUV_target : require
precision mediump float;
in vec2 vTextureCoord;