Merge "Camera: Low Light Boost AE Mode" into main
diff --git a/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl b/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl
index 8e1fcc0..843e0d4 100644
--- a/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl
+++ b/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl
@@ -99,6 +99,15 @@
*/
boolean isSessionConfigurationSupported(in SessionConfiguration sessionConfiguration);
+ /**
+ * Get the camera characteristics for a particular session configuration
+ *
+ * @param sessionConfiguration Specific session configuration for which the characteristics
+ * are fetched.
+ * @return - characteristics associated with the given session.
+ */
+ CameraMetadataNative getSessionCharacteristics(in SessionConfiguration sessionConfiguration);
+
void deleteStream(int streamId);
/**
diff --git a/media/libaaudio/src/Android.bp b/media/libaaudio/src/Android.bp
index 886603d..fcb376c 100644
--- a/media/libaaudio/src/Android.bp
+++ b/media/libaaudio/src/Android.bp
@@ -41,10 +41,10 @@
"modernize-use-emplace",
"modernize-use-equals-default",
"modernize-use-equals-delete",
- // "modernize-use-nodiscard", // found in aidl generated files
+ "modernize-use-nodiscard",
"modernize-use-noexcept",
"modernize-use-nullptr",
- // "modernize-use-override", // found in aidl generated files
+ "modernize-use-override",
// "modernize-use-trailing-return-type", // not necessarily more readable
"modernize-use-transparent-functors",
"modernize-use-uncaught-exceptions",
@@ -225,10 +225,12 @@
"flowgraph/SinkI16.cpp",
"flowgraph/SinkI24.cpp",
"flowgraph/SinkI32.cpp",
+ "flowgraph/SinkI8_24.cpp",
"flowgraph/SourceFloat.cpp",
"flowgraph/SourceI16.cpp",
"flowgraph/SourceI24.cpp",
"flowgraph/SourceI32.cpp",
+ "flowgraph/SourceI8_24.cpp",
"flowgraph/resampler/IntegerRatio.cpp",
"flowgraph/resampler/LinearResampler.cpp",
"flowgraph/resampler/MultiChannelResampler.cpp",
diff --git a/media/libaaudio/src/client/AAudioFlowGraph.cpp b/media/libaaudio/src/client/AAudioFlowGraph.cpp
index b7e0ae6..14e2007 100644
--- a/media/libaaudio/src/client/AAudioFlowGraph.cpp
+++ b/media/libaaudio/src/client/AAudioFlowGraph.cpp
@@ -30,10 +30,12 @@
#include <flowgraph/SinkI16.h>
#include <flowgraph/SinkI24.h>
#include <flowgraph/SinkI32.h>
+#include <flowgraph/SinkI8_24.h>
#include <flowgraph/SourceFloat.h>
#include <flowgraph/SourceI16.h>
#include <flowgraph/SourceI24.h>
#include <flowgraph/SourceI32.h>
+#include <flowgraph/SourceI8_24.h>
using namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph;
@@ -68,6 +70,9 @@
case AUDIO_FORMAT_PCM_32_BIT:
mSource = std::make_unique<SourceI32>(sourceChannelCount);
break;
+ case AUDIO_FORMAT_PCM_8_24_BIT:
+ mSource = std::make_unique<SourceI8_24>(sourceChannelCount);
+ break;
default:
ALOGE("%s() Unsupported source format = %d", __func__, sourceFormat);
return AAUDIO_ERROR_UNIMPLEMENTED;
@@ -139,6 +144,9 @@
case AUDIO_FORMAT_PCM_32_BIT:
mSink = std::make_unique<SinkI32>(sinkChannelCount);
break;
+ case AUDIO_FORMAT_PCM_8_24_BIT:
+ mSink = std::make_unique<SinkI8_24>(sinkChannelCount);
+ break;
default:
ALOGE("%s() Unsupported sink format = %d", __func__, sinkFormat);
return AAUDIO_ERROR_UNIMPLEMENTED;
diff --git a/media/libaaudio/src/core/AAudioStreamParameters.cpp b/media/libaaudio/src/core/AAudioStreamParameters.cpp
index 1db62f3..3e51575 100644
--- a/media/libaaudio/src/core/AAudioStreamParameters.cpp
+++ b/media/libaaudio/src/core/AAudioStreamParameters.cpp
@@ -61,6 +61,7 @@
case AUDIO_FORMAT_PCM_32_BIT:
case AUDIO_FORMAT_PCM_FLOAT:
case AUDIO_FORMAT_PCM_24_BIT_PACKED:
+ case AUDIO_FORMAT_PCM_8_24_BIT:
case AUDIO_FORMAT_IEC61937:
break; // valid
default:
diff --git a/media/libaaudio/src/flowgraph/FlowgraphUtilities.h b/media/libaaudio/src/flowgraph/FlowgraphUtilities.h
index 5e90588..e277d6e 100644
--- a/media/libaaudio/src/flowgraph/FlowgraphUtilities.h
+++ b/media/libaaudio/src/flowgraph/FlowgraphUtilities.h
@@ -17,6 +17,7 @@
#ifndef FLOWGRAPH_UTILITIES_H
#define FLOWGRAPH_UTILITIES_H
+#include <math.h>
#include <unistd.h>
using namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph;
@@ -50,6 +51,20 @@
return f > 0 ? f + 0.5 : f - 0.5;
}
+/**
+ * Convert a single-precision floating point value to a Q0.23 integer value, stored in a
+ * 32 bit signed integer (technically stored as Q8.23, but clamped to Q0.23).
+ *
+ * Values outside the range [-1.0, 1.0) are properly clamped to -8388608 and 8388607,
+ * including -Inf and +Inf. NaN values are considered undefined, and behavior may change
+ * depending on hardware and future implementation of this function.
+ */
+static int32_t clamp24FromFloat(float f)
+{
+ static const float scale = 1 << 23;
+ return (int32_t) lroundf(fmaxf(fminf(f * scale, scale - 1.f), -scale));
+}
+
};
#endif // FLOWGRAPH_UTILITIES_H
diff --git a/media/libaaudio/src/flowgraph/SinkI8_24.cpp b/media/libaaudio/src/flowgraph/SinkI8_24.cpp
new file mode 100644
index 0000000..d5e4b80
--- /dev/null
+++ b/media/libaaudio/src/flowgraph/SinkI8_24.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2023 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.
+ */
+
+#include "FlowGraphNode.h"
+#include "FlowgraphUtilities.h"
+#include "SinkI8_24.h"
+
+#if FLOWGRAPH_ANDROID_INTERNAL
+#include <audio_utils/primitives.h>
+#endif
+
+using namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph;
+
+SinkI8_24::SinkI8_24(int32_t channelCount)
+ : FlowGraphSink(channelCount) {}
+
+int32_t SinkI8_24::read(void *data, int32_t numFrames) {
+ int32_t *intData = (int32_t *) data;
+ const int32_t channelCount = input.getSamplesPerFrame();
+
+ int32_t framesLeft = numFrames;
+ while (framesLeft > 0) {
+ // Run the graph and pull data through the input port.
+ int32_t framesRead = pullData(framesLeft);
+ if (framesRead <= 0) {
+ break;
+ }
+ const float *signal = input.getBuffer();
+ int32_t numSamples = framesRead * channelCount;
+#if FLOWGRAPH_ANDROID_INTERNAL
+ memcpy_to_q8_23_from_float_with_clamp(intData, signal, numSamples);
+ intData += numSamples;
+ signal += numSamples;
+#else
+ for (int i = 0; i < numSamples; i++) {
+ *intData++ = FlowgraphUtilities::clamp24FromFloat(*signal++);
+ }
+#endif
+ framesLeft -= framesRead;
+ }
+ return numFrames - framesLeft;
+}
diff --git a/media/libaaudio/src/flowgraph/SinkI8_24.h b/media/libaaudio/src/flowgraph/SinkI8_24.h
new file mode 100644
index 0000000..aa96918
--- /dev/null
+++ b/media/libaaudio/src/flowgraph/SinkI8_24.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2023 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.
+ */
+
+#ifndef FLOWGRAPH_SINK_I8_24_H
+#define FLOWGRAPH_SINK_I8_24_H
+
+#include <stdint.h>
+
+#include "FlowGraphNode.h"
+
+namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph {
+
+class SinkI8_24 : public FlowGraphSink {
+public:
+ explicit SinkI8_24(int32_t channelCount);
+ ~SinkI8_24() override = default;
+
+ int32_t read(void *data, int32_t numFrames) override;
+
+ const char *getName() override {
+ return "SinkI8_24";
+ }
+};
+
+} /* namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph */
+
+#endif //FLOWGRAPH_SINK_I8_24_H
diff --git a/media/libaaudio/src/flowgraph/SourceI8_24.cpp b/media/libaaudio/src/flowgraph/SourceI8_24.cpp
new file mode 100644
index 0000000..684446c
--- /dev/null
+++ b/media/libaaudio/src/flowgraph/SourceI8_24.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2023 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.
+ */
+
+#include <algorithm>
+#include <unistd.h>
+
+#include "FlowGraphNode.h"
+#include "SourceI8_24.h"
+
+#if FLOWGRAPH_ANDROID_INTERNAL
+#include <audio_utils/primitives.h>
+#endif
+
+using namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph;
+
+SourceI8_24::SourceI8_24(int32_t channelCount)
+ : FlowGraphSourceBuffered(channelCount) {
+}
+
+int32_t SourceI8_24::onProcess(int32_t numFrames) {
+ float *floatData = output.getBuffer();
+ const int32_t channelCount = output.getSamplesPerFrame();
+
+ const int32_t framesLeft = mSizeInFrames - mFrameIndex;
+ const int32_t framesToProcess = std::min(numFrames, framesLeft);
+ const int32_t numSamples = framesToProcess * channelCount;
+
+ const int32_t *intBase = static_cast<const int32_t *>(mData);
+ const int32_t *intData = &intBase[mFrameIndex * channelCount];
+
+#if FLOWGRAPH_ANDROID_INTERNAL
+ memcpy_to_float_from_q8_23(floatData, intData, numSamples);
+#else
+ for (int i = 0; i < numSamples; i++) {
+ *floatData++ = *intData++ * kScale;
+ }
+#endif
+
+ mFrameIndex += framesToProcess;
+ return framesToProcess;
+}
diff --git a/media/libaaudio/src/flowgraph/SourceI8_24.h b/media/libaaudio/src/flowgraph/SourceI8_24.h
new file mode 100644
index 0000000..91c756c
--- /dev/null
+++ b/media/libaaudio/src/flowgraph/SourceI8_24.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2023 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.
+ */
+
+#ifndef FLOWGRAPH_SOURCE_I8_24_H
+#define FLOWGRAPH_SOURCE_I8_24_H
+
+#include <stdint.h>
+
+#include "FlowGraphNode.h"
+
+namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph {
+
+class SourceI8_24 : public FlowGraphSourceBuffered {
+public:
+ explicit SourceI8_24(int32_t channelCount);
+ ~SourceI8_24() override = default;
+
+ int32_t onProcess(int32_t numFrames) override;
+
+ const char *getName() override {
+ return "SourceI8_24";
+ }
+private:
+ static constexpr float kScale = 1.0 / (1UL << 23);
+};
+
+} /* namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph */
+
+#endif //FLOWGRAPH_SOURCE_I8_24_H
diff --git a/media/libaaudio/tests/test_flowgraph.cpp b/media/libaaudio/tests/test_flowgraph.cpp
index 7eb8b0d..f20a4bb 100644
--- a/media/libaaudio/tests/test_flowgraph.cpp
+++ b/media/libaaudio/tests/test_flowgraph.cpp
@@ -31,14 +31,16 @@
#include "flowgraph/Limiter.h"
#include "flowgraph/MonoBlend.h"
#include "flowgraph/MonoToMultiConverter.h"
-#include "flowgraph/SourceFloat.h"
#include "flowgraph/RampLinear.h"
#include "flowgraph/SinkFloat.h"
#include "flowgraph/SinkI16.h"
#include "flowgraph/SinkI24.h"
#include "flowgraph/SinkI32.h"
+#include "flowgraph/SinkI8_24.h"
+#include "flowgraph/SourceFloat.h"
#include "flowgraph/SourceI16.h"
#include "flowgraph/SourceI24.h"
+#include "flowgraph/SourceI8_24.h"
#include "flowgraph/resampler/IntegerRatio.h"
using namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph;
@@ -52,6 +54,9 @@
PARAM_RESAMPLER_QUALITY
};
+constexpr int kInt24Min = 0xff800000;
+constexpr int kInt24Max = 0x007fffff;
+
constexpr int kBytesPerI24Packed = 3;
constexpr int kNumSamples = 8;
@@ -59,15 +64,19 @@
1.0f, 0.5f, -0.25f, -1.0f,
0.0f, 53.9f, -87.2f, -1.02f};
-// Corresponding PCM values as integers.
-constexpr std::array<int16_t, kNumSamples> kExpectedI16 = {
+// Corresponding PCM values as integers.
+constexpr std::array<int16_t, kNumSamples> kExpectedI16 = {
INT16_MAX, 1 << 14, INT16_MIN / 4, INT16_MIN,
0, INT16_MAX, INT16_MIN, INT16_MIN};
-constexpr std::array<int32_t, kNumSamples> kExpectedI32 = {
+constexpr std::array<int32_t, kNumSamples> kExpectedI32 = {
INT32_MAX, 1 << 30, INT32_MIN / 4, INT32_MIN,
0, INT32_MAX, INT32_MIN, INT32_MIN};
+constexpr std::array<int32_t, kNumSamples> kExpectedI8_24 = {
+ kInt24Max, 1 << 22, kInt24Min / 4, kInt24Min,
+ 0, kInt24Max, kInt24Min, kInt24Min};
+
// =================================== FLOAT to I16 ==============
// Simple test that tries to reproduce a Clang compiler bug.
@@ -215,6 +224,8 @@
EXPECT_EQ(input[0], output[1]);
EXPECT_EQ(input[1], output[2]);
EXPECT_EQ(input[1], output[3]);
+ EXPECT_EQ(input[2], output[4]);
+ EXPECT_EQ(input[2], output[5]);
}
TEST(test_flowgraph, module_ramp_linear) {
@@ -434,6 +445,70 @@
}
}
+// =================================== FLOAT to Q8.23 ==============
+__attribute__((noinline))
+static int32_t clamp24FromFloat(float f)
+{
+ static const float scale = 1 << 23;
+ return (int32_t) lroundf(fmaxf(fminf(f * scale, scale - 1.f), -scale));
+}
+
+void local_convert_float_to_i8_24(const float *input,
+ int32_t *output,
+ int count) {
+ for (int i = 0; i < count; i++) {
+ *output++ = clamp24FromFloat(*input++);
+ }
+}
+
+TEST(test_flowgraph, local_convert_float_to_i8_24) {
+ std::array<int32_t, kNumSamples> output;
+ // Convert audio signal using the function.
+ output.fill(777);
+ local_convert_float_to_i8_24(kInputFloat.data(), output.data(), kNumSamples);
+ for (int i = 0; i < kNumSamples; i++) {
+ EXPECT_EQ(kExpectedI8_24.at(i), output.at(i)) << ", i = " << i;
+ }
+}
+
+TEST(test_flowgraph, module_sinkI8_24) {
+ std::array<int32_t, kNumSamples + 10> output; // larger than input
+
+ SourceFloat sourceFloat{2};
+ SinkI8_24 sinkI8_24{2};
+
+ sourceFloat.setData(kInputFloat.data(), kNumSamples);
+ sourceFloat.output.connect(&sinkI8_24.input);
+
+ output.fill(777);
+ int32_t numRead = sinkI8_24.read(output.data(), output.size());
+ ASSERT_EQ(kNumSamples, numRead);
+ for (int i = 0; i < numRead; i++) {
+ EXPECT_EQ(kExpectedI8_24.at(i), output.at(i)) << ", i = " << i;
+ }
+}
+
+TEST(test_flowgraph, module_sourceI8_24) {
+ static const int32_t input[] = {1 << 23, 1 << 22, -(1 << 21), -(1 << 23), 0, 1 << 25,
+ -(1 << 25)};
+ static const float expected[] = {1.0f, 0.5f, -0.25f, -1.0f, 0.0f, 4.0f, -4.0f};
+ float output[100];
+
+ SourceI8_24 sourceI8_24{1};
+ SinkFloat sinkFloat{1};
+
+ int numSamples = std::size(input);
+
+ sourceI8_24.setData(input, numSamples);
+ sourceI8_24.output.connect(&sinkFloat.input);
+
+ int32_t numRead = sinkFloat.read(output, numSamples);
+ ASSERT_EQ(numSamples, numRead);
+ for (int i = 0; i < numRead; i++) {
+ EXPECT_EQ(expected[i], output[i]) << ", i = " << i;
+ }
+}
+
void checkSampleRateConversionVariedSizes(int32_t sourceSampleRate,
int32_t sinkSampleRate,
MultiChannelResampler::Quality resamplerQuality) {
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 54880f8..0f02944 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -7881,6 +7881,15 @@
}
}
+void SpatializerThread::threadLoop_exit()
+{
+ // The Spatializer EffectHandle must be released on the PlaybackThread
+ // threadLoop() to prevent lock inversion in the SpatializerThread dtor.
+ mFinalDownMixer.clear();
+
+ PlaybackThread::threadLoop_exit();
+}
+
// ----------------------------------------------------------------------------
// Record
// ----------------------------------------------------------------------------
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index a5afdd8..9477795 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -1900,6 +1900,8 @@
REQUIRES(ThreadBase_ThreadLoop) EXCLUDES_ThreadBase_Mutex;
void setHalLatencyMode_l() final REQUIRES(mutex());
+ void threadLoop_exit() final REQUIRES(ThreadBase_ThreadLoop);
+
private:
// Do not request a specific mode by default
audio_latency_mode_t mRequestedLatencyMode = AUDIO_LATENCY_MODE_FREE;
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
index b560bc4..f066c09 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
@@ -61,7 +61,7 @@
status_t updateMix(const AudioMix& mix, const std::vector<AudioMixMatchCriterion>& newCriteria);
- void closeOutput(sp<SwAudioOutputDescriptor> &desc);
+ void closeOutput(sp<SwAudioOutputDescriptor> &desc, const SwAudioOutputCollection& allOutputs);
/**
* Tries to find the best matching audio policy mix
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
index 7ee75c7..dc0f466 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
@@ -272,12 +272,33 @@
return BAD_VALUE;
}
-void AudioPolicyMixCollection::closeOutput(sp<SwAudioOutputDescriptor> &desc)
+void AudioPolicyMixCollection::closeOutput(sp<SwAudioOutputDescriptor> &desc,
+ const SwAudioOutputCollection& allOutputs)
{
for (size_t i = 0; i < size(); i++) {
sp<AudioPolicyMix> policyMix = itemAt(i);
- if (policyMix->getOutput() == desc) {
- policyMix->clearOutput();
+ if (policyMix->getOutput() != desc) {
+ continue;
+ }
+ policyMix->clearOutput();
+ if (policyMix->mRouteFlags != MIX_ROUTE_FLAG_RENDER) {
+ continue;
+ }
+ auto device = desc->supportedDevices().getDevice(
+ policyMix->mDeviceType, policyMix->mDeviceAddress, AUDIO_FORMAT_DEFAULT);
+ if (device == nullptr) {
+ // This must not happen
+ ALOGE("%s, the rerouted device is not found", __func__);
+ continue;
+ }
+ // Restore the policy mix mix output to the first opened output supporting a route to
+ // the mix device. This is because the current mix output can be changed to a direct output.
+ for (size_t j = 0; j < allOutputs.size(); ++j) {
+ if (allOutputs[i] != desc && !allOutputs[i]->isDuplicated() &&
+ allOutputs[i]->supportedDevices().contains(device)) {
+ policyMix->setOutput(allOutputs[i]);
+ break;
+ }
}
}
}
@@ -335,13 +356,6 @@
"audio policy mix.", __func__);
return INVALID_OPERATION;
}
- if (mixDevice != nullptr) {
- // TODO(b/301619865): Only disallow the device that doesn't support MMAP.
- ALOGD("%s: Rejecting MMAP_NOIRQ request matched to dynamic audio policy "
- "mix pointing to device %s which the mmap support is unknown at this moment",
- __func__, mixDevice->toString(false).c_str());
- return INVALID_OPERATION;
- }
}
if (mixDevice != nullptr && mixDevice->equals(requestedDevice)) {
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 69d3b5d..135548f 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1217,13 +1217,14 @@
return BAD_VALUE;
}
if (usePrimaryOutputFromPolicyMixes) {
- sp<DeviceDescriptor> deviceDesc =
+ sp<DeviceDescriptor> policyMixDevice =
mAvailableOutputDevices.getDevice(primaryMix->mDeviceType,
primaryMix->mDeviceAddress,
AUDIO_FORMAT_DEFAULT);
sp<SwAudioOutputDescriptor> policyDesc = primaryMix->getOutput();
bool tryDirectForFlags = policyDesc == nullptr ||
- (policyDesc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT);
+ (policyDesc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) ||
+ (*flags & (AUDIO_OUTPUT_FLAG_HW_AV_SYNC | AUDIO_OUTPUT_FLAG_MMAP_NOIRQ));
// if a direct output can be opened to deliver the track's multi-channel content to the
// output rather than being downmixed by the primary output, then use this direct
// output by by-passing the primary mix if possible, otherwise fall-through to primary
@@ -1231,23 +1232,29 @@
bool tryDirectForChannelMask = policyDesc != nullptr
&& (audio_channel_count_from_out_mask(policyDesc->getConfig().channel_mask) <
audio_channel_count_from_out_mask(config->channel_mask));
- if (deviceDesc != nullptr && (tryDirectForFlags || tryDirectForChannelMask)) {
+ if (policyMixDevice != nullptr && (tryDirectForFlags || tryDirectForChannelMask)) {
audio_io_handle_t newOutput;
status = openDirectOutput(
*stream, session, config,
(audio_output_flags_t)(*flags | AUDIO_OUTPUT_FLAG_DIRECT),
- DeviceVector(deviceDesc), &newOutput);
+ DeviceVector(policyMixDevice), &newOutput);
if (status == NO_ERROR) {
policyDesc = mOutputs.valueFor(newOutput);
primaryMix->setOutput(policyDesc);
} else if (tryDirectForFlags) {
+ ALOGW("%s, failed open direct, status: %d", __func__, status);
policyDesc = nullptr;
} // otherwise use primary if available.
}
if (policyDesc != nullptr) {
policyDesc->mPolicyMix = primaryMix;
*output = policyDesc->mIoHandle;
- *selectedDeviceId = deviceDesc != 0 ? deviceDesc->getId() : AUDIO_PORT_HANDLE_NONE;
+ *selectedDeviceId = policyMixDevice != nullptr ? policyMixDevice->getId()
+ : AUDIO_PORT_HANDLE_NONE;
+ if ((policyDesc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) != AUDIO_OUTPUT_FLAG_DIRECT) {
+ // Remove direct flag as it is not on a direct output.
+ *flags = (audio_output_flags_t) (*flags & ~AUDIO_OUTPUT_FLAG_DIRECT);
+ }
ALOGV("getOutputForAttr() returns output %d", *output);
if (resultAttr->usage == AUDIO_USAGE_VIRTUAL_SOURCE) {
@@ -1256,6 +1263,13 @@
*outputType = API_OUTPUT_LEGACY;
}
return NO_ERROR;
+ } else {
+ if (policyMixDevice != nullptr) {
+ ALOGE("%s, try to use primary mix but no output found", __func__);
+ return INVALID_OPERATION;
+ }
+ // Fallback to default engine selection as the selected primary mix device is not
+ // available.
}
}
// Virtual sources must always be dynamicaly or explicitly routed
@@ -6689,7 +6703,7 @@
return;
}
const bool closingOutputWasActive = closingOutput->isActive();
- mPolicyMixes.closeOutput(closingOutput);
+ mPolicyMixes.closeOutput(closingOutput, mOutputs);
// look for duplicated outputs connected to the output being removed.
for (size_t i = 0; i < mOutputs.size(); i++) {
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index 7241597..5d3788d 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -299,7 +299,11 @@
AudioDeviceTypeAddrVector devices;
bool hasSpatializer = mAudioPolicyManager->canBeSpatialized(&attr, nullptr, devices);
if (hasSpatializer) {
+ // Unlock as Spatializer::create() will use the callback and acquire the
+ // AudioPolicyService_Mutex.
+ mLock.unlock();
mSpatializer = Spatializer::create(this, effectsFactoryHal);
+ mLock.lock();
}
if (mSpatializer == nullptr) {
// No spatializer created, signal the reason: NO_INIT a failure, OK means intended.
diff --git a/services/audiopolicy/tests/audiopolicymanager_tests.cpp b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
index 8dbf471..74d3474 100644
--- a/services/audiopolicy/tests/audiopolicymanager_tests.cpp
+++ b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
@@ -211,7 +211,7 @@
std::unique_ptr<AudioPolicyManagerTestClient> mClient;
std::unique_ptr<AudioPolicyTestManager> mManager;
- const uint32_t k48000SamplingRate = 48000;
+ constexpr static const uint32_t k48000SamplingRate = 48000;
};
void AudioPolicyManagerTest::SetUp() {
@@ -1274,13 +1274,30 @@
std::string mixAddress, const audio_config_t& audioConfig,
const std::vector<AudioMixMatchCriterion>& matchCriteria);
void clearPolicyMix();
+ void addPolicyMixAndStartInputForLoopback(
+ int mixType, int mixFlag, audio_devices_t deviceType, std::string mixAddress,
+ const audio_config_t& audioConfig,
+ const std::vector<AudioMixMatchCriterion>& matchCriteria,
+ audio_session_t session=AUDIO_SESSION_NONE,
+ audio_config_base_t config=DEFAULT_INPUT_CONFIG,
+ audio_input_flags_t inputFlags=AUDIO_INPUT_FLAG_NONE);
Vector<AudioMix> mAudioMixes;
const std::string mMixAddress = "remote_submix_media";
+
+ audio_port_handle_t mLoopbackInputPortId = AUDIO_PORT_HANDLE_NONE;
+ std::unique_ptr<RecordingActivityTracker> mTracker;
+ struct audio_port_v7 mInjectionPort;
+
+ constexpr static const audio_config_base_t DEFAULT_INPUT_CONFIG = {
+ .sample_rate = k48000SamplingRate,
+ .channel_mask = AUDIO_CHANNEL_IN_STEREO,
+ .format = AUDIO_FORMAT_PCM_16_BIT
+ };
};
void AudioPolicyManagerTestDynamicPolicy::TearDown() {
- mManager->unregisterPolicyMixes(mAudioMixes);
+ clearPolicyMix();
AudioPolicyManagerTestWithConfigurationFile::TearDown();
}
@@ -1302,11 +1319,45 @@
void AudioPolicyManagerTestDynamicPolicy::clearPolicyMix() {
if (mManager != nullptr) {
+ mManager->stopInput(mLoopbackInputPortId);
mManager->unregisterPolicyMixes(mAudioMixes);
}
mAudioMixes.clear();
}
+void AudioPolicyManagerTestDynamicPolicy::addPolicyMixAndStartInputForLoopback(
+ int mixType, int mixFlag, audio_devices_t deviceType, std::string mixAddress,
+ const audio_config_t& audioConfig,
+ const std::vector<AudioMixMatchCriterion>& matchCriteria, audio_session_t session,
+ audio_config_base_t config, audio_input_flags_t inputFlags) {
+ ASSERT_EQ(NO_ERROR,
+ addPolicyMix(mixType, mixFlag, deviceType, mixAddress, audioConfig, matchCriteria));
+ if ((mixFlag & MIX_ROUTE_FLAG_LOOP_BACK) != MIX_ROUTE_FLAG_LOOP_BACK) {
+ return;
+ }
+
+ mTracker.reset(new RecordingActivityTracker());
+ struct audio_port_v7 extractionPort;
+ ASSERT_TRUE(findDevicePort(AUDIO_PORT_ROLE_SOURCE, AUDIO_DEVICE_IN_REMOTE_SUBMIX,
+ mixAddress, &extractionPort));
+ audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
+ audio_source_t source = AUDIO_SOURCE_REMOTE_SUBMIX;
+ audio_attributes_t attr = {
+ AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN, source, AUDIO_FLAG_NONE, ""};
+ std::string tags = "addr=" + mMixAddress;
+ audio_io_handle_t input = AUDIO_PORT_HANDLE_NONE;
+ strncpy(attr.tags, tags.c_str(), AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1);
+ ASSERT_NO_FATAL_FAILURE(
+ getInputForAttr(attr, &input, session, mTracker->getRiid(),
+ &selectedDeviceId, config.format, config.channel_mask,
+ config.sample_rate, inputFlags, &mLoopbackInputPortId));
+ ASSERT_EQ(NO_ERROR, mManager->startInput(mLoopbackInputPortId));
+ ASSERT_EQ(extractionPort.id, selectedDeviceId);
+
+ ASSERT_TRUE(findDevicePort(AUDIO_PORT_ROLE_SINK, AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
+ mMixAddress, &mInjectionPort));
+}
+
TEST_F(AudioPolicyManagerTestDynamicPolicy, InitSuccess) {
// SetUp must finish with no assertions
}
@@ -1684,11 +1735,6 @@
public testing::WithParamInterface<DPTestParam> {
protected:
void SetUp() override;
- void TearDown() override;
-
- std::unique_ptr<RecordingActivityTracker> mTracker;
- struct audio_port_v7 mInjectionPort;
- audio_port_handle_t mPortId = AUDIO_PORT_HANDLE_NONE;
};
void AudioPolicyManagerTestDPPlaybackReRouting::SetUp() {
@@ -1702,34 +1748,10 @@
audioConfig.sample_rate = k48000SamplingRate;
DPTestParam param = GetParam();
- status_t ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_LOOP_BACK,
- AUDIO_DEVICE_OUT_REMOTE_SUBMIX, mMixAddress, audioConfig, param.mixCriteria);
- ASSERT_EQ(NO_ERROR, ret);
-
- struct audio_port_v7 extractionPort;
- ASSERT_TRUE(findDevicePort(AUDIO_PORT_ROLE_SOURCE, AUDIO_DEVICE_IN_REMOTE_SUBMIX,
- mMixAddress, &extractionPort));
-
- audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
- audio_source_t source = AUDIO_SOURCE_REMOTE_SUBMIX;
- audio_attributes_t attr = {
- AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN, source, AUDIO_FLAG_NONE, ""};
- std::string tags = "addr=" + mMixAddress;
- audio_io_handle_t input = AUDIO_PORT_HANDLE_NONE;
- strncpy(attr.tags, tags.c_str(), AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1);
- getInputForAttr(attr, &input, param.session, mTracker->getRiid(),
- &selectedDeviceId, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO,
- k48000SamplingRate, AUDIO_INPUT_FLAG_NONE, &mPortId);
- ASSERT_EQ(NO_ERROR, mManager->startInput(mPortId));
- ASSERT_EQ(extractionPort.id, selectedDeviceId);
-
- ASSERT_TRUE(findDevicePort(AUDIO_PORT_ROLE_SINK, AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
- mMixAddress, &mInjectionPort));
-}
-
-void AudioPolicyManagerTestDPPlaybackReRouting::TearDown() {
- mManager->stopInput(mPortId);
- AudioPolicyManagerTestDynamicPolicy::TearDown();
+ ASSERT_NO_FATAL_FAILURE(
+ addPolicyMixAndStartInputForLoopback(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_LOOP_BACK,
+ AUDIO_DEVICE_OUT_REMOTE_SUBMIX, mMixAddress, audioConfig, param.mixCriteria,
+ param.session));
}
TEST_P(AudioPolicyManagerTestDPPlaybackReRouting, PlaybackReRouting) {
@@ -1924,12 +1946,14 @@
// Add mix matching the test uid.
const int testUid = 12345;
const auto param = GetParam();
- status_t ret = addPolicyMix(MIX_TYPE_PLAYERS, param.mixRouteFlags, param.deviceType,
- param.deviceAddress, audioConfig, {createUidCriterion(testUid)});
- ASSERT_EQ(NO_ERROR, ret);
+ ASSERT_NO_FATAL_FAILURE(
+ addPolicyMixAndStartInputForLoopback(MIX_TYPE_PLAYERS, param.mixRouteFlags,
+ param.deviceType, param.deviceAddress, audioConfig,
+ {createUidCriterion(testUid)}));
- // Geting output for matching uid and mmap-ed stream should fail.
- audio_output_flags_t outputFlags = AUDIO_OUTPUT_FLAG_MMAP_NOIRQ;
+ // Getting output for matching uid and mmap-ed stream should fail.
+ audio_output_flags_t outputFlags =
+ (audio_output_flags_t) (AUDIO_OUTPUT_FLAG_MMAP_NOIRQ | AUDIO_OUTPUT_FLAG_DIRECT);
ASSERT_EQ(INVALID_OPERATION,
mManager->getOutputForAttr(&attr, &mOutput, AUDIO_SESSION_NONE, &mStream,
createAttributionSourceState(testUid), &audioConfig,
@@ -1942,11 +1966,12 @@
// Add mix matching the test uid.
const int testUid = 12345;
const auto param = GetParam();
- status_t ret = addPolicyMix(MIX_TYPE_PLAYERS, param.mixRouteFlags, param.deviceType,
- param.deviceAddress, audioConfig, {createUidCriterion(testUid)});
- ASSERT_EQ(NO_ERROR, ret);
+ ASSERT_NO_FATAL_FAILURE(
+ addPolicyMixAndStartInputForLoopback(MIX_TYPE_PLAYERS, param.mixRouteFlags,
+ param.deviceType,param.deviceAddress, audioConfig,
+ {createUidCriterion(testUid)}));
- // Geting output for matching uid should succeed for non-mmaped stream.
+ // Getting output for matching uid should succeed for non-mmaped stream.
audio_output_flags_t outputFlags = AUDIO_OUTPUT_FLAG_NONE;
ASSERT_EQ(NO_ERROR,
mManager->getOutputForAttr(&attr, &mOutput, AUDIO_SESSION_NONE, &mStream,
@@ -1957,23 +1982,57 @@
TEST_F(AudioPolicyManagerTestMMapPlaybackRerouting,
MmapPlaybackStreamMatchingRenderDapMixSupportingMmapSucceeds) {
+ const std::string usbAddress = "card=1;device=0";
+ ASSERT_EQ(NO_ERROR, mManager->setDeviceConnectionState(
+ AUDIO_DEVICE_OUT_USB_DEVICE, AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
+ usbAddress.c_str(), "", AUDIO_FORMAT_DEFAULT));
+ audio_port_v7 usbDevicePort;
+ ASSERT_TRUE(findDevicePort(AUDIO_PORT_ROLE_SINK, AUDIO_DEVICE_OUT_USB_DEVICE,
+ usbAddress, &usbDevicePort));
+
// Add render-only mix matching the test uid.
const int testUid = 12345;
// test_audio_policy_configuration.xml declares mmap-capable mix port
// for AUDIO_DEVICE_OUT_USB_DEVICE.
- status_t ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_RENDER,
- AUDIO_DEVICE_OUT_USB_DEVICE, /*mixAddress=*/"",
- audioConfig, {createUidCriterion(testUid)});
- ASSERT_EQ(NO_ERROR, ret);
+ ASSERT_EQ(NO_ERROR,
+ addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_RENDER,
+ AUDIO_DEVICE_OUT_USB_DEVICE, /*mixAddress=*/"",
+ audioConfig, {createUidCriterion(testUid)}));
- // Geting output for matching uid should succeed for mmaped stream, because matched mix
+ static const audio_output_flags_t mmapDirectFlags =
+ (audio_output_flags_t) (AUDIO_OUTPUT_FLAG_MMAP_NOIRQ | AUDIO_OUTPUT_FLAG_DIRECT);
+ // Getting output for matching uid should succeed for mmaped stream, because matched mix
// redirects to mmap capable device.
- audio_output_flags_t outputFlags = AUDIO_OUTPUT_FLAG_MMAP_NOIRQ;
+ audio_output_flags_t outputFlags = mmapDirectFlags;
ASSERT_EQ(NO_ERROR,
mManager->getOutputForAttr(&attr, &mOutput, AUDIO_SESSION_NONE, &mStream,
createAttributionSourceState(testUid), &audioConfig,
&outputFlags, &mSelectedDeviceId, &mPortId, {},
&mOutputType, &mIsSpatialized, &mIsBitPerfect));
+ ASSERT_EQ(usbDevicePort.id, mSelectedDeviceId);
+ auto outputDesc = mManager->getOutputs().valueFor(mOutput);
+ ASSERT_NE(nullptr, outputDesc);
+ ASSERT_EQ(mmapDirectFlags, outputDesc->getFlags().output);
+
+ // After releasing the client, the output is closed. APM should reselect output for the policy
+ // mix.
+ mManager->releaseOutput(mPortId);
+ ASSERT_EQ(nullptr, mManager->getOutputs().valueFor(mOutput));
+ outputFlags = AUDIO_OUTPUT_FLAG_NONE;
+ mPortId = AUDIO_PORT_HANDLE_NONE;
+ ASSERT_EQ(NO_ERROR,
+ mManager->getOutputForAttr(&attr, &mOutput, AUDIO_SESSION_NONE, &mStream,
+ createAttributionSourceState(testUid), &audioConfig,
+ &outputFlags, &mSelectedDeviceId, &mPortId, {},
+ &mOutputType, &mIsSpatialized, &mIsBitPerfect));
+ ASSERT_EQ(usbDevicePort.id, mSelectedDeviceId);
+ outputDesc = mManager->getOutputs().valueFor(mOutput);
+ ASSERT_NE(nullptr, outputDesc);
+ ASSERT_NE(mmapDirectFlags, outputDesc->getFlags().output);
+
+ ASSERT_EQ(NO_ERROR, mManager->setDeviceConnectionState(
+ AUDIO_DEVICE_OUT_USB_DEVICE, AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
+ usbAddress.c_str(), "", AUDIO_FORMAT_DEFAULT));
}
TEST_F(AudioPolicyManagerTestMMapPlaybackRerouting,
@@ -1981,14 +2040,15 @@
// Add render-only mix matching the test uid.
const int testUid = 12345;
// Per test_audio_policy_configuration.xml AUDIO_DEVICE_OUT_SPEAKER doesn't support mmap.
- status_t ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_RENDER,
- AUDIO_DEVICE_OUT_SPEAKER, /*mixAddress=*/"", audioConfig,
- {createUidCriterion(testUid)});
- ASSERT_EQ(NO_ERROR, ret);
+ ASSERT_EQ(NO_ERROR,
+ addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_RENDER,
+ AUDIO_DEVICE_OUT_SPEAKER, /*mixAddress=*/"", audioConfig,
+ {createUidCriterion(testUid)}));
- // Geting output for matching uid should fail for mmaped stream, because
+ // Getting output for matching uid should fail for mmaped stream, because
// matched mix redirects to device which doesn't support mmap.
- audio_output_flags_t outputFlags = AUDIO_OUTPUT_FLAG_MMAP_NOIRQ;
+ audio_output_flags_t outputFlags =
+ (audio_output_flags_t) (AUDIO_OUTPUT_FLAG_MMAP_NOIRQ | AUDIO_OUTPUT_FLAG_DIRECT);
ASSERT_EQ(INVALID_OPERATION,
mManager->getOutputForAttr(&attr, &mOutput, AUDIO_SESSION_NONE, &mStream,
createAttributionSourceState(testUid), &audioConfig,
@@ -2322,6 +2382,7 @@
static const std::string sCarBusNavigationOutput;
static const std::string sCarRearZoneOneOutput;
static const std::string sCarRearZoneTwoOutput;
+ static const std::string sCarBusMmapOutput;
};
const std::string AudioPolicyManagerCarTest::sCarConfig =
@@ -2335,6 +2396,8 @@
const std::string AudioPolicyManagerCarTest::sCarRearZoneTwoOutput = "bus200_audio_zone_2";
+const std::string AudioPolicyManagerCarTest::sCarBusMmapOutput = "bus8_mmap_out";
+
TEST_F(AudioPolicyManagerCarTest, InitSuccess) {
// SetUp must finish with no assertions.
}
@@ -2784,6 +2847,37 @@
ASSERT_EQ(navDevicePort.id, selectedDeviceId);
}
+TEST_F(AudioPolicyManagerCarTest, GetOutputForAttrForMMapWithPolicyMatched) {
+ status_t ret;
+ audio_config_t audioConfig = AUDIO_CONFIG_INITIALIZER;
+ audioConfig.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
+ audioConfig.format = AUDIO_FORMAT_PCM_16_BIT;
+ audioConfig.sample_rate = k48000SamplingRate;
+ std::vector<AudioMixMatchCriterion> mediaMatchCriteria = {
+ createUsageCriterion(AUDIO_USAGE_MEDIA, /*exclude=*/ false)};
+ ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_RENDER,
+ AUDIO_DEVICE_OUT_BUS, sCarBusMmapOutput, audioConfig, mediaMatchCriteria);
+ ASSERT_EQ(NO_ERROR, ret);
+ ASSERT_EQ(NO_ERROR, ret);
+ audio_port_v7 mmapDevicePort;
+ ASSERT_TRUE(findDevicePort(AUDIO_PORT_ROLE_SINK, AUDIO_DEVICE_OUT_BUS,
+ sCarBusMmapOutput, &mmapDevicePort));
+ audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
+ audio_io_handle_t output;
+ audio_port_handle_t portId;
+ const audio_attributes_t mediaAttribute = {
+ AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_MEDIA,
+ AUDIO_SOURCE_DEFAULT, AUDIO_FLAG_NONE, ""};
+
+ getOutputForAttr(
+ &selectedDeviceId, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
+ k48000SamplingRate,
+ (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_MMAP_NOIRQ | AUDIO_OUTPUT_FLAG_DIRECT),
+ &output, &portId, mediaAttribute);
+
+ ASSERT_EQ(mmapDevicePort.id, selectedDeviceId);
+}
+
class AudioPolicyManagerTVTest : public AudioPolicyManagerTestWithConfigurationFile {
protected:
std::string getConfigFile() override { return sTvConfig; }
diff --git a/services/audiopolicy/tests/resources/test_audio_policy_configuration.xml b/services/audiopolicy/tests/resources/test_audio_policy_configuration.xml
index 9e092c6..4efdf8a 100644
--- a/services/audiopolicy/tests/resources/test_audio_policy_configuration.xml
+++ b/services/audiopolicy/tests/resources/test_audio_policy_configuration.xml
@@ -56,7 +56,7 @@
</mixPort>
<mixPort name="hifi_output" role="source" flags="AUDIO_OUTPUT_FLAG_BIT_PERFECT"/>
<mixPort name="mmap_no_irq_out" role="source"
- flags="AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_MMAP_NOIRQ">
+ flags="AUDIO_OUTPUT_FLAG_DIRECT AUDIO_OUTPUT_FLAG_MMAP_NOIRQ">
<profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
</mixPort>
diff --git a/services/audiopolicy/tests/resources/test_car_ap_atmos_offload_configuration.xml b/services/audiopolicy/tests/resources/test_car_ap_atmos_offload_configuration.xml
index d131ed8..d40ebfc 100644
--- a/services/audiopolicy/tests/resources/test_car_ap_atmos_offload_configuration.xml
+++ b/services/audiopolicy/tests/resources/test_car_ap_atmos_offload_configuration.xml
@@ -30,6 +30,7 @@
<item>bus5_alarm_out</item>
<item>bus6_notification_out</item>
<item>bus7_system_sound_out</item>
+ <item>bus8_mmap_out</item>
<!-- names with _audio_zone_# are used for defined an emulator rear seat audio zone
where each number # is the zone id number -->
<item>bus100_audio_zone_1</item>
@@ -96,6 +97,11 @@
samplingRates="48000"
channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
</mixPort>
+ <mixPort name="mixport_bus8_mmap_out" role="source"
+ flags="AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_MMAP_NOIRQ">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </mixPort>
<mixPort name="mixport_bus100_audio_zone_1" role="source">
<profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
samplingRates="48000"
@@ -213,6 +219,16 @@
stepValueMB="100"/>
</gains>
</devicePort>
+ <devicePort tagName="bus8_mmap_out" role="sink" type="AUDIO_DEVICE_OUT_BUS"
+ address="bus8_mmap_out">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ <gains>
+ <gain name="" mode="AUDIO_GAIN_MODE_JOINT"
+ minValueMB="-3200" maxValueMB="600" defaultValueMB="0"
+ stepValueMB="100"/>
+ </gains>
+ </devicePort>
<devicePort tagName="bus100_audio_zone_1" role="sink" type="AUDIO_DEVICE_OUT_BUS"
address="bus100_audio_zone_1">
<profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
@@ -295,6 +311,8 @@
sources="mixport_bus6_notification_out"/>
<route type="mix" sink="bus7_system_sound_out"
sources="mixport_bus7_system_sound_out"/>
+ <route type="mix" sink="bus8_mmap_out"
+ sources="mixport_bus8_mmap_out"/>
<route type="mix" sink="bus100_audio_zone_1" sources="mixport_bus100_audio_zone_1"/>
<route type="mix" sink="bus200_audio_zone_2" sources="mixport_bus200_audio_zone_2"/>
<route type="mix" sink="primary input"
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index 095d425..7443788 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -777,6 +777,60 @@
return res;
}
+binder::Status CameraDeviceClient::getSessionCharacteristics(
+ const SessionConfiguration& sessionConfiguration,
+ /*out*/
+ hardware::camera2::impl::CameraMetadataNative* sessionCharacteristics) {
+ ATRACE_CALL();
+ binder::Status res;
+ status_t ret = OK;
+ if (!(res = checkPidStatus(__FUNCTION__)).isOk()) return res;
+
+ Mutex::Autolock icl(mBinderSerializationLock);
+
+ if (!mDevice.get()) {
+ return STATUS_ERROR(CameraService::ERROR_DISCONNECTED, "Camera device no longer alive");
+ }
+
+ auto operatingMode = sessionConfiguration.getOperatingMode();
+ res = SessionConfigurationUtils::checkOperatingMode(operatingMode, mDevice->info(),
+ mCameraIdStr);
+ if (!res.isOk()) {
+ return res;
+ }
+
+ camera3::metadataGetter getMetadata = [this](const std::string &id,
+ bool /*overrideForPerfClass*/) {
+ return mDevice->infoPhysical(id);};
+ ret = mProviderManager->getSessionCharacteristics(mCameraIdStr.c_str(),
+ sessionConfiguration, mOverrideForPerfClass, getMetadata,
+ sessionCharacteristics);
+
+ switch (ret) {
+ case OK:
+ // Expected, do nothing.
+ break;
+ case INVALID_OPERATION: {
+ std::string msg = fmt::sprintf(
+ "Camera %s: Session characteristics query not supported!",
+ mCameraIdStr.c_str());
+ ALOGD("%s: %s", __FUNCTION__, msg.c_str());
+ res = STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.c_str());
+ }
+
+ break;
+ default: {
+ std::string msg = fmt::sprintf( "Camera %s: Error: %s (%d)", mCameraIdStr.c_str(),
+ strerror(-ret), ret);
+ ALOGE("%s: %s", __FUNCTION__, msg.c_str());
+ res = STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
+ msg.c_str());
+ }
+ }
+
+ return res;
+}
+
binder::Status CameraDeviceClient::deleteStream(int streamId) {
ATRACE_CALL();
ALOGV("%s (streamId = 0x%x)", __FUNCTION__, streamId);
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h
index b2c9626..c2f7f56 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.h
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h
@@ -109,6 +109,11 @@
/*out*/
bool* streamStatus) override;
+ virtual binder::Status getSessionCharacteristics(
+ const SessionConfiguration& sessionConfiguration,
+ /*out*/
+ hardware::camera2::impl::CameraMetadataNative* sessionCharacteristics) override;
+
// Returns -EBUSY if device is not idle or in error state
virtual binder::Status deleteStream(int streamId) override;
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index fbb5e1b..1ba3de4 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -442,6 +442,23 @@
return OK;
}
+status_t CameraProviderManager::getSessionCharacteristics(const std::string& id,
+ const SessionConfiguration &configuration, bool overrideForPerfClass,
+ metadataGetter getMetadata,
+ CameraMetadata* sessionCharacteristics /*out*/) const {
+ if (!flags::feature_combination_query()) {
+ return INVALID_OPERATION;
+ }
+ std::lock_guard<std::mutex> lock(mInterfaceMutex);
+ auto deviceInfo = findDeviceInfoLocked(id);
+ if (deviceInfo == nullptr) {
+ return NAME_NOT_FOUND;
+ }
+
+ return deviceInfo->getSessionCharacteristics(configuration,
+ overrideForPerfClass, getMetadata, sessionCharacteristics);
+}
+
status_t CameraProviderManager::getCameraIdIPCTransport(const std::string &id,
IPCTransport *providerTransport) const {
std::lock_guard<std::mutex> lock(mInterfaceMutex);
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.h b/services/camera/libcameraservice/common/CameraProviderManager.h
index 6142a71..53a2102 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.h
+++ b/services/camera/libcameraservice/common/CameraProviderManager.h
@@ -317,6 +317,14 @@
bool *status /*out*/) const;
/**
+ * Get session characteristics for a particular session.
+ */
+ status_t getSessionCharacteristics(const std::string& id,
+ const SessionConfiguration &configuration,
+ bool overrideForPerfClass, camera3::metadataGetter getMetadata,
+ CameraMetadata* sessionCharacteristics /*out*/) const;
+
+ /**
* Return the highest supported device interface version for this ID
*/
status_t getHighestSupportedVersion(const std::string &id,
@@ -632,6 +640,15 @@
bool * /*status*/) {
return INVALID_OPERATION;
}
+
+ virtual status_t getSessionCharacteristics(
+ const SessionConfiguration &/*configuration*/,
+ bool /*overrideForPerfClass*/,
+ camera3::metadataGetter /*getMetadata*/,
+ CameraMetadata* /*sessionCharacteristics*/) {
+ return INVALID_OPERATION;
+ }
+
virtual status_t filterSmallJpegSizes() = 0;
virtual void notifyDeviceStateChange(int64_t /*newState*/) {}
virtual status_t createDefaultRequest(
diff --git a/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp b/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp
index a64c9d7..d773af3 100644
--- a/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp
+++ b/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp
@@ -900,6 +900,54 @@
return res;
}
+status_t AidlProviderInfo::AidlDeviceInfo3::getSessionCharacteristics(
+ const SessionConfiguration &configuration, bool overrideForPerfClass,
+ camera3::metadataGetter getMetadata, CameraMetadata *sessionCharacteristics) {
+ camera::device::StreamConfiguration streamConfiguration;
+ bool earlyExit = false;
+ auto res = SessionConfigurationUtils::convertToHALStreamCombination(configuration,
+ mId, mCameraCharacteristics, mCompositeJpegRDisabled, getMetadata,
+ mPhysicalIds, streamConfiguration, overrideForPerfClass, mProviderTagid,
+ /*checkSessionParams*/true, &earlyExit);
+
+ if (!res.isOk()) {
+ return UNKNOWN_ERROR;
+ }
+
+ if (earlyExit) {
+ return BAD_VALUE;
+ }
+
+ const std::shared_ptr<camera::device::ICameraDevice> interface =
+ startDeviceInterface();
+
+ if (interface == nullptr) {
+ return DEAD_OBJECT;
+ }
+
+ aidl::android::hardware::camera::device::CameraMetadata chars;
+ ::ndk::ScopedAStatus ret =
+ interface->getSessionCharacteristics(streamConfiguration, &chars);
+ std::vector<uint8_t> &metadata = chars.metadata;
+
+ camera_metadata_t *buffer = reinterpret_cast<camera_metadata_t*>(metadata.data());
+ size_t expectedSize = metadata.size();
+ int resV = validate_camera_metadata_structure(buffer, &expectedSize);
+ if (resV == OK || resV == CAMERA_METADATA_VALIDATION_SHIFTED) {
+ set_camera_metadata_vendor_id(buffer, mProviderTagid);
+ *sessionCharacteristics = buffer;
+ } else {
+ ALOGE("%s: Malformed camera metadata received from HAL", __FUNCTION__);
+ return BAD_VALUE;
+ }
+
+ if (!ret.isOk()) {
+ ALOGE("%s: Unexpected binder error: %s", __FUNCTION__, ret.getMessage());
+ return mapToStatusT(ret);
+ }
+ return OK;
+}
+
status_t AidlProviderInfo::convertToAidlHALStreamCombinationAndCameraIdsLocked(
const std::vector<CameraIdAndSessionConfiguration> &cameraIdsAndSessionConfigs,
const std::set<std::string>& perfClassPrimaryCameraIds,
diff --git a/services/camera/libcameraservice/common/aidl/AidlProviderInfo.h b/services/camera/libcameraservice/common/aidl/AidlProviderInfo.h
index cc5101a..0bfa7d4 100644
--- a/services/camera/libcameraservice/common/aidl/AidlProviderInfo.h
+++ b/services/camera/libcameraservice/common/aidl/AidlProviderInfo.h
@@ -134,6 +134,11 @@
camera3::camera_request_template_t templateId,
camera_metadata_t** metadata) override;
+ virtual status_t getSessionCharacteristics(
+ const SessionConfiguration &/*configuration*/,
+ bool overrideForPerfClass, camera3::metadataGetter /*getMetadata*/,
+ CameraMetadata *sessionCharacteristics /*sessionCharacteristics*/);
+
std::shared_ptr<aidl::android::hardware::camera::device::ICameraDevice>
startDeviceInterface();
};
diff --git a/services/camera/libcameraservice/common/hidl/HidlProviderInfo.h b/services/camera/libcameraservice/common/hidl/HidlProviderInfo.h
index f53db7f..869bba0 100644
--- a/services/camera/libcameraservice/common/hidl/HidlProviderInfo.h
+++ b/services/camera/libcameraservice/common/hidl/HidlProviderInfo.h
@@ -107,6 +107,7 @@
const SessionConfiguration &/*configuration*/,
bool overrideForPerfClass, bool checkSessionParams,
bool *status/*status*/);
+
sp<hardware::camera::device::V3_2::ICameraDevice> startDeviceInterface();
};
diff --git a/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp b/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp
index 467707e..a53d26d 100644
--- a/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp
+++ b/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp
@@ -309,6 +309,12 @@
bool*) override {
return ndk::ScopedAStatus::ok();
}
+
+ ::ndk::ScopedAStatus getSessionCharacteristics(
+ const ::aidl::android::hardware::camera::device::StreamConfiguration&,
+ ::aidl::android::hardware::camera::device::CameraMetadata*) override {
+ return ndk::ScopedAStatus::ok();
+ }
};
/**
diff --git a/services/oboeservice/AAudioServiceEndpointMMAP.cpp b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
index 2ef6fe5..4438b0a 100644
--- a/services/oboeservice/AAudioServiceEndpointMMAP.cpp
+++ b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
@@ -76,7 +76,8 @@
const static std::map<audio_format_t, audio_format_t> NEXT_FORMAT_TO_TRY = {
{AUDIO_FORMAT_PCM_FLOAT, AUDIO_FORMAT_PCM_32_BIT},
{AUDIO_FORMAT_PCM_32_BIT, AUDIO_FORMAT_PCM_24_BIT_PACKED},
- {AUDIO_FORMAT_PCM_24_BIT_PACKED, AUDIO_FORMAT_PCM_16_BIT}
+ {AUDIO_FORMAT_PCM_24_BIT_PACKED, AUDIO_FORMAT_PCM_8_24_BIT},
+ {AUDIO_FORMAT_PCM_8_24_BIT, AUDIO_FORMAT_PCM_16_BIT}
};
audio_format_t getNextFormatToTry(audio_format_t curFormat) {
diff --git a/services/oboeservice/Android.bp b/services/oboeservice/Android.bp
index 3521979..9fe06b7 100644
--- a/services/oboeservice/Android.bp
+++ b/services/oboeservice/Android.bp
@@ -55,7 +55,7 @@
"modernize-use-emplace",
"modernize-use-equals-default",
"modernize-use-equals-delete",
- // "modernize-use-nodiscard", // Maybe add this in the future
+ "modernize-use-nodiscard",
"modernize-use-noexcept",
"modernize-use-nullptr",
"modernize-use-override",