Merge "cameraserver: Fix HIDL vs AIDL CameraBlobId discrepancy; Move HIDL into seperate source files." into tm-dev
diff --git a/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp b/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
index 85ab0c2..0a57590 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
+++ b/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
@@ -491,6 +491,7 @@
}
if (mRemote != nullptr) {
+ ALOGD("%s: binder disconnect reached", __FUNCTION__);
auto ret = mRemote->disconnect();
if (!ret.isOk()) {
ALOGE("%s: Transaction error while disconnecting device %s", __FUNCTION__,
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index fffd60a..19bb206 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -1074,6 +1074,17 @@
}
} else {
if ((config->mDomain & Config::IS_ENCODER) || !surface) {
+ if (vendorSdkVersion < __ANDROID_API_S__ &&
+ (format == COLOR_FormatYUV420Flexible ||
+ format == COLOR_FormatYUV420Planar ||
+ format == COLOR_FormatYUV420PackedPlanar ||
+ format == COLOR_FormatYUV420SemiPlanar ||
+ format == COLOR_FormatYUV420PackedSemiPlanar)) {
+ // pre-S framework used to map these color formats into YV12.
+ // Codecs from older vendor partition may be relying on
+ // this assumption.
+ format = HAL_PIXEL_FORMAT_YV12;
+ }
switch (format) {
case COLOR_FormatYUV420Flexible:
format = COLOR_FormatYUV420Planar;
@@ -1815,15 +1826,13 @@
return;
}
- err2 = mChannel->requestInitialInputBuffers();
-
- if (err2 != OK) {
- ALOGE("Initial request for Input Buffers failed");
- mCallback->onError(err2,ACTION_CODE_FATAL);
- return;
- }
mCallback->onStartCompleted();
+ err2 = mChannel->requestInitialInputBuffers();
+ if (err2 != OK) {
+ ALOGE("Initial request for Input Buffers failed");
+ mCallback->onError(err2, ACTION_CODE_FATAL);
+ }
}
void CCodec::initiateShutdown(bool keepComponentAllocated) {
@@ -2117,7 +2126,11 @@
state->set(RUNNING);
}
- (void)mChannel->requestInitialInputBuffers();
+ status_t err = mChannel->requestInitialInputBuffers();
+ if (err != OK) {
+ ALOGE("Resume request for Input Buffers failed");
+ mCallback->onError(err, ACTION_CODE_FATAL);
+ }
}
void CCodec::signalSetParameters(const sp<AMessage> &msg) {
diff --git a/media/codec2/sfplugin/CCodecConfig.cpp b/media/codec2/sfplugin/CCodecConfig.cpp
index 836d2a7..f3fb5ff 100644
--- a/media/codec2/sfplugin/CCodecConfig.cpp
+++ b/media/codec2/sfplugin/CCodecConfig.cpp
@@ -1072,6 +1072,13 @@
C2_PARAMKEY_SURFACE_SCALING_MODE);
} else {
addLocalParam(new C2StreamColorAspectsInfo::input(0u), C2_PARAMKEY_COLOR_ASPECTS);
+
+ if (domain.value == C2Component::DOMAIN_VIDEO) {
+ addLocalParam(new C2AndroidStreamAverageBlockQuantizationInfo::output(0u, 0),
+ C2_PARAMKEY_AVERAGE_QP);
+ addLocalParam(new C2StreamPictureTypeMaskInfo::output(0u, 0),
+ C2_PARAMKEY_PICTURE_TYPE);
+ }
}
}
diff --git a/media/libaudioclient/AudioRecord.cpp b/media/libaudioclient/AudioRecord.cpp
index 0871365..15203d6 100644
--- a/media/libaudioclient/AudioRecord.cpp
+++ b/media/libaudioclient/AudioRecord.cpp
@@ -1331,6 +1331,7 @@
const sp<IAudioRecordCallback> callback = mCallback.promote();
if (!callback) {
mCallback = nullptr;
+ mLock.unlock();
return NS_NEVER;
}
if (mAwaitBoost) {
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index 02e7114..de8c298 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -832,6 +832,11 @@
return ap;
}
+void AudioSystem::clearAudioPolicyService() {
+ Mutex::Autolock _l(gLockAPS);
+ gAudioPolicyService.clear();
+}
+
// ---------------------------------------------------------------------------
void AudioSystem::onNewAudioModulesAvailable() {
@@ -1150,8 +1155,15 @@
legacy2aidl_audio_stream_type_t_AudioStreamType(stream));
int32_t indexMinAidl = VALUE_OR_RETURN_STATUS(convertIntegral<int32_t>(indexMin));
int32_t indexMaxAidl = VALUE_OR_RETURN_STATUS(convertIntegral<int32_t>(indexMax));
- return statusTFromBinderStatus(
+ status_t status = statusTFromBinderStatus(
aps->initStreamVolume(streamAidl, indexMinAidl, indexMaxAidl));
+ if (status == DEAD_OBJECT) {
+ // This is a critical operation since w/o proper stream volumes no audio
+ // will be heard. Make sure we recover from a failure in any case.
+ ALOGE("Received DEAD_OBJECT from APS, clearing the client");
+ clearAudioPolicyService();
+ }
+ return status;
}
status_t AudioSystem::setStreamVolumeIndex(audio_stream_type_t stream,
@@ -1412,10 +1424,7 @@
}
gAudioFlinger.clear();
}
- {
- Mutex::Autolock _l(gLockAPS);
- gAudioPolicyService.clear();
- }
+ clearAudioPolicyService();
}
status_t AudioSystem::setSupportedSystemUsages(const std::vector<audio_usage_t>& systemUsages) {
@@ -2603,10 +2612,7 @@
mAudioVolumeGroupCallback[i]->onServiceDied();
}
}
- {
- Mutex::Autolock _l(gLockAPS);
- AudioSystem::gAudioPolicyService.clear();
- }
+ AudioSystem::clearAudioPolicyService();
ALOGW("AudioPolicyService server died!");
}
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index bec6b10..36f8e10 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -2448,6 +2448,7 @@
sp<IAudioTrackCallback> callback = mCallback.promote();
if (!callback) {
mCallback = nullptr;
+ mLock.unlock();
return NS_NEVER;
}
if (mAwaitBoost) {
diff --git a/media/libaudioclient/ToneGenerator.cpp b/media/libaudioclient/ToneGenerator.cpp
index 9b43f3c..4662247 100644
--- a/media/libaudioclient/ToneGenerator.cpp
+++ b/media/libaudioclient/ToneGenerator.cpp
@@ -17,6 +17,7 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "ToneGenerator"
+#include <inttypes.h>
#include <utility>
#include <math.h>
@@ -1229,7 +1230,8 @@
sec = sec * 1000 + nsec / 1000000; // duration in milliseconds
mMaxSmp = (unsigned int)(((int64_t)sec * mSamplingRate) / 1000);
}
- ALOGV("stopTone() forcing mMaxSmp to %d, total for far %d", mMaxSmp, mTotalSmp);
+ ALOGV("stopTone() forcing mMaxSmp to %d, total for far %" PRIu64, mMaxSmp,
+ mTotalSmp);
} else {
mState = TONE_STOPPING;
}
@@ -1399,7 +1401,7 @@
mNextSegSmp = TONEGEN_INF; // forced to skip state machine management below
}
- if (mTotalSmp > mNextSegSmp) {
+ if (mTotalSmp > mNextSegSmp && mNextSegSmp != TONEGEN_INF) {
// Time to go to next sequence segment
ALOGV("End Segment, time: %d", (unsigned int)(systemTime()/1000000));
@@ -1483,8 +1485,11 @@
}
// Update next segment transition position. No harm to do it also for last segment as
- // mNextSegSmp won't be used any more
- mNextSegSmp += (mpToneDesc->segments[mCurSegment].duration * mSamplingRate) / 1000;
+ // mNextSegSmp won't be used any more.
+ // Handle 32 bit wraparound gracefully.
+ const uint64_t res = static_cast<uint64_t>(mNextSegSmp) +
+ (mpToneDesc->segments[mCurSegment].duration * mSamplingRate) / 1000;
+ mNextSegSmp = static_cast<uint32_t>(std::min<uint64_t>(TONEGEN_INF, res));
} else {
// Inside a segment keep tone ON or OFF
diff --git a/media/libaudioclient/aidl/android/media/ISpatializer.aidl b/media/libaudioclient/aidl/android/media/ISpatializer.aidl
index b871238..a61ad58 100644
--- a/media/libaudioclient/aidl/android/media/ISpatializer.aidl
+++ b/media/libaudioclient/aidl/android/media/ISpatializer.aidl
@@ -57,8 +57,10 @@
boolean isHeadTrackingSupported();
/** Reports the list of supported head tracking modes (see SpatializerHeadTrackingMode.aidl).
- * The list can be empty if the spatializer implementation does not support head tracking or if
- * no head tracking sensor is registered (see setHeadSensor() and setScreenSensor()).
+ * The list always contains SpatializerHeadTrackingMode.DISABLED and can include other modes
+ * if the spatializer effect implementation supports head tracking.
+ * The result does not depend on currently connected sensors but reflects the capabilities
+ * when sensors are available.
*/
SpatializerHeadTrackingMode[] getSupportedHeadTrackingModes();
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index b5b9277..360b83d 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -350,6 +350,7 @@
static void clearAudioConfigCache();
static const sp<media::IAudioPolicyService> get_audio_policy_service();
+ static void clearAudioPolicyService();
// helpers for android.media.AudioManager.getProperty(), see description there for meaning
static uint32_t getPrimaryOutputSamplingRate();
diff --git a/media/libaudioclient/include/media/ToneGenerator.h b/media/libaudioclient/include/media/ToneGenerator.h
index 43c0100..d00dfd2 100644
--- a/media/libaudioclient/include/media/ToneGenerator.h
+++ b/media/libaudioclient/include/media/ToneGenerator.h
@@ -287,11 +287,10 @@
static const ToneDescriptor sToneDescriptors[];
bool mThreadCanCallJava;
- unsigned int mTotalSmp; // Total number of audio samples played (gives current time)
+ uint64_t mTotalSmp; // Total number of audio samples played (gives current time)
+ // Since these types are 32 bit, we may have issues with aborting on
+ // overflow now that we have integer overflow sanitization enabled globally.
unsigned int mNextSegSmp; // Position of next segment transition expressed in samples
- // NOTE: because mTotalSmp, mNextSegSmp are stored on 32 bit, current design will operate properly
- // only if tone duration is less than about 27 Hours(@44100Hz sampling rate). If this time is exceeded,
- // no crash will occur but tone sequence will show a glitch.
unsigned int mMaxSmp; // Maximum number of audio samples played (maximun tone duration)
int mDurationMs; // Maximum tone duration in ms
diff --git a/media/libaudiofoundation/AudioContainers.cpp b/media/libaudiofoundation/AudioContainers.cpp
index 553a319..0a8188f 100644
--- a/media/libaudiofoundation/AudioContainers.cpp
+++ b/media/libaudiofoundation/AudioContainers.cpp
@@ -70,6 +70,13 @@
return audioDeviceOutAllBleSet;
}
+const DeviceTypeSet& getAudioDeviceOutLeAudioUnicastSet() {
+ static const DeviceTypeSet audioDeviceOutLeAudioUnicastSet = DeviceTypeSet(
+ std::begin(AUDIO_DEVICE_OUT_BLE_UNICAST_ARRAY),
+ std::end(AUDIO_DEVICE_OUT_BLE_UNICAST_ARRAY));
+ return audioDeviceOutLeAudioUnicastSet;
+}
+
std::string deviceTypesToString(const DeviceTypeSet &deviceTypes) {
if (deviceTypes.empty()) {
return "Empty device types";
diff --git a/media/libaudiofoundation/include/media/AudioContainers.h b/media/libaudiofoundation/include/media/AudioContainers.h
index a9c7824..b6e6c84 100644
--- a/media/libaudiofoundation/include/media/AudioContainers.h
+++ b/media/libaudiofoundation/include/media/AudioContainers.h
@@ -41,6 +41,7 @@
const DeviceTypeSet& getAudioDeviceInAllSet();
const DeviceTypeSet& getAudioDeviceInAllUsbSet();
const DeviceTypeSet& getAudioDeviceOutAllBleSet();
+const DeviceTypeSet& getAudioDeviceOutLeAudioUnicastSet();
template<typename T>
static std::vector<T> Intersection(const std::set<T>& a, const std::set<T>& b) {
diff --git a/media/libheadtracking/SensorPoseProvider.cpp b/media/libheadtracking/SensorPoseProvider.cpp
index f3f9b77..4884ae4 100644
--- a/media/libheadtracking/SensorPoseProvider.cpp
+++ b/media/libheadtracking/SensorPoseProvider.cpp
@@ -158,7 +158,6 @@
enum DataFormat {
kUnknown,
kQuaternion,
- kRotationVectorsAndFlags,
kRotationVectorsAndDiscontinuityCount,
};
@@ -283,10 +282,6 @@
return DataFormat::kRotationVectorsAndDiscontinuityCount;
}
- if (sensor->getStringType() == "com.google.hardware.sensor.hid_dynamic.headtracker") {
- return DataFormat::kRotationVectorsAndFlags;
- }
-
return DataFormat::kUnknown;
}
@@ -332,21 +327,6 @@
return PoseEvent{Pose3f(quat), std::optional<Twist3f>(), false};
}
- case DataFormat::kRotationVectorsAndFlags: {
- // Custom sensor, assumed to contain:
- // 3 floats representing orientation as a rotation vector (in rad).
- // 3 floats representing angular velocity as a rotation vector (in rad/s).
- // 1 uint32_t of flags, where:
- // - LSb is '1' iff the given sample is the first one in a new frame of reference.
- // - The rest of the bits are reserved for future use.
- Eigen::Vector3f rotation = {event.data[0], event.data[1], event.data[2]};
- Eigen::Vector3f twist = {event.data[3], event.data[4], event.data[5]};
- Eigen::Quaternionf quat = rotationVectorToQuaternion(rotation);
- uint32_t flags = *reinterpret_cast<const uint32_t*>(&event.data[6]);
- return PoseEvent{Pose3f(quat), Twist3f(Eigen::Vector3f::Zero(), twist),
- (flags & (1 << 0)) != 0};
- }
-
case DataFormat::kRotationVectorsAndDiscontinuityCount: {
Eigen::Vector3f rotation = {event.head_tracker.rx, event.head_tracker.ry,
event.head_tracker.rz};
diff --git a/media/libstagefright/foundation/MetaDataBase.cpp b/media/libstagefright/foundation/MetaDataBase.cpp
index 980eb22..3370748 100644
--- a/media/libstagefright/foundation/MetaDataBase.cpp
+++ b/media/libstagefright/foundation/MetaDataBase.cpp
@@ -521,9 +521,64 @@
}
setData(key, type, blob.data(), size);
blob.release();
+ } else if (type == TYPE_C_STRING) {
+ // copy data directly from Parcel storage, then advance position
+ // NB: readInplace() bumps position, it is NOT idempotent.
+ const void *src = parcel.readInplace(size);
+ char *str = (char *) src;
+ if (src == nullptr || size == 0 || str[size-1] != '\0') {
+ char ccKey[5];
+ MakeFourCCString(key, ccKey);
+ if (src == nullptr) {
+ ALOGW("ignoring key '%s' string with no data (expected %d)", ccKey, size);
+ } else {
+ ALOGW("ignoring key '%s': unterminated string of %d bytes", ccKey, size);
+ }
+ } else {
+ setData(key, type, src, size);
+ }
} else {
// copy data directly from Parcel storage, then advance position
- setData(key, type, parcel.readInplace(size), size);
+ // verify that the received size is enough
+ uint32_t needed = 0;
+ switch (type) {
+ case TYPE_INT32:
+ needed = sizeof(int32_t);
+ break;
+ case TYPE_INT64:
+ needed = sizeof(int64_t);
+ break;
+ case TYPE_FLOAT:
+ needed = sizeof(float);
+ break;
+ case TYPE_POINTER:
+ // NB: this rejects passing between 32-bit and 64-bit space.
+ needed = sizeof(void*);
+ break;
+ case TYPE_RECT:
+ needed = sizeof(Rect);
+ break;
+ default:
+ // non-standard entities can be any size >= 0
+ needed = 0;
+ break;
+ }
+ const void *src = parcel.readInplace(size);
+ if (src == nullptr || (needed != 0 && size != needed)) {
+ char ccKey[5];
+ MakeFourCCString(key, ccKey);
+ char ccType[5];
+ MakeFourCCString(type, ccType);
+ if (src == nullptr) {
+ ALOGW("ignoring key '%s' type '%s' missing data (expected %d)",
+ ccKey, ccType, size);
+ } else {
+ ALOGW("ignoring key '%s': type '%s' bytes: expected %d != %d received",
+ ccKey, ccType, needed, size);
+ }
+ } else {
+ setData(key, type, src, size);
+ }
}
}
diff --git a/media/utils/include/mediautils/ScopedStatistics.h b/media/utils/include/mediautils/ScopedStatistics.h
new file mode 100644
index 0000000..c5fc1e9
--- /dev/null
+++ b/media/utils/include/mediautils/ScopedStatistics.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "MethodStatistics.h"
+#include <chrono>
+#include <memory>
+#include <string>
+#include <utility>
+
+namespace android::mediautils {
+
+class ScopedStatistics {
+ public:
+ /**
+ * ScopedStatistics is a RAII way of obtaining
+ * execution time statistics for a scoped C++ block.
+ *
+ * It updates the MethodStatistics shared pointer parameter
+ * with the methodName parameter and the duration/lifetime of the
+ * ScopedStatistics object.
+ *
+ * Not thread-safe, but expected to run in a single execution
+ * thread, and there are no user serviceable parts exposed.
+ *
+ * Example:
+ *
+ * std::shared_ptr<mediautils::MethodStatistics<std::string>> stats =
+ * std::make_shared<mediautils::MethodStatistics<std::string>>();
+ *
+ * // ...
+ * {
+ * mediautils::ScopedStatistics scopedStatistics("MyClass:myMethod", stats);
+ *
+ * // some work to be timed here - up to the end of the block.
+ * }
+ *
+ * \param methodName the methodname to use "ClassName::methodName"
+ * \param statistics a shared ptr to the MethodStatistics object to use.
+ */
+ ScopedStatistics(std::string methodName,
+ std::shared_ptr<mediautils::MethodStatistics<std::string>> statistics)
+ : mMethodName{std::move(methodName)}
+ , mStatistics{std::move(statistics)}
+ , mBegin{std::chrono::steady_clock::now()} {}
+
+ // No copy constructor.
+ ScopedStatistics(const ScopedStatistics& scopedStatistics) = delete;
+ ScopedStatistics& operator=(const ScopedStatistics& scopedStatistics) = delete;
+
+ ~ScopedStatistics() {
+ if (mStatistics) {
+ const float elapsedMs = std::chrono::duration_cast<std::chrono::nanoseconds>(
+ std::chrono::steady_clock::now() - mBegin)
+ .count() *
+ 1e-6; // ns to ms.
+ mStatistics->event(mMethodName, elapsedMs);
+ }
+ }
+
+ private:
+ const std::string mMethodName;
+ const std::shared_ptr<mediautils::MethodStatistics<std::string>> mStatistics;
+ const std::chrono::steady_clock::time_point mBegin;
+};
+
+} // namespace android::mediautils
diff --git a/media/utils/tests/Android.bp b/media/utils/tests/Android.bp
index a6f408d..1024018 100644
--- a/media/utils/tests/Android.bp
+++ b/media/utils/tests/Android.bp
@@ -124,6 +124,27 @@
}
cc_test {
+ name: "mediautils_scopedstatistics_tests",
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ ],
+
+ shared_libs: [
+ "libaudioutils",
+ "liblog",
+ "libmediautils",
+ "libutils",
+ ],
+
+ srcs: [
+ "mediautils_scopedstatistics_tests.cpp",
+ ],
+}
+
+cc_test {
name: "methodstatistics_tests",
cflags: [
diff --git a/media/utils/tests/mediautils_scopedstatistics_tests.cpp b/media/utils/tests/mediautils_scopedstatistics_tests.cpp
new file mode 100644
index 0000000..807ce63
--- /dev/null
+++ b/media/utils/tests/mediautils_scopedstatistics_tests.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "mediautils_scopedstatistics_tests"
+
+#include <mediautils/ScopedStatistics.h>
+
+#include <atomic>
+#include <chrono>
+#include <gtest/gtest.h>
+#include <thread>
+#include <utils/Log.h>
+
+using namespace android::mediautils;
+using namespace std::chrono_literals;
+
+TEST(mediautils_scopedstatistics_tests, basic) {
+ auto methodStatistics = std::make_shared<MethodStatistics<std::string>>();
+ std::string METHOD_NAME{"MyMethod"};
+
+ // no stats before
+ auto empty = methodStatistics->getStatistics(METHOD_NAME);
+ ASSERT_EQ(0, empty.getN());
+
+ // create a scoped statistics object.
+ {
+ ScopedStatistics scopedStatistics(METHOD_NAME, methodStatistics);
+
+ std::this_thread::sleep_for(100ms);
+ }
+
+ // check that some stats were logged.
+ auto stats = methodStatistics->getStatistics(METHOD_NAME);
+ ASSERT_EQ(1, stats.getN());
+ auto mean = stats.getMean();
+
+ // mean should be about 100ms, but to avoid false failures,
+ // we check 50ms < mean < 300ms.
+ ASSERT_GT(mean, 50.); // took more than 50ms.
+ ASSERT_LT(mean, 300.); // took less than 300ms.
+}
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
index 64c7923..75fa595 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
@@ -518,6 +518,14 @@
uint32_t inPastMs = 0, nsecs_t sysTime = 0) const;
/**
+ * @brief isStrategyActive checks if the given strategy is active
+ * on the given output
+ * @param ps product strategy to be checked upon activity status
+ * @return true if an output following the strategy is active, false otherwise
+ */
+ bool isStrategyActive(product_strategy_t ps) const;
+
+ /**
* @brief clearSessionRoutesForDevice: when a device is disconnected, and if this device has
* been chosen as the preferred device by any client, the policy manager shall
* prevent from using this device any more by clearing all the session routes involving this
@@ -562,6 +570,11 @@
sp<SwAudioOutputDescriptor> getOutputForClient(audio_port_handle_t portId);
+ /**
+ * return whether any output is active and routed to any of the specified devices
+ */
+ bool isAnyDeviceTypeActive(const DeviceTypeSet& deviceTypes) const;
+
void dump(String8 *dst) const;
};
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index 009fa82..40a1eaa 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -841,6 +841,16 @@
return false;
}
+bool SwAudioOutputCollection::isStrategyActive(product_strategy_t ps) const
+{
+ for (size_t i = 0; i < size(); i++) {
+ if (valueAt(i)->isStrategyActive(ps)) {
+ return true;
+ }
+ }
+ return false;
+}
+
audio_io_handle_t SwAudioOutputCollection::getA2dpOutput() const
{
for (size_t i = 0; i < size(); i++) {
@@ -916,6 +926,16 @@
}
}
}
+bool SwAudioOutputCollection::isAnyDeviceTypeActive(const DeviceTypeSet& deviceTypes) const {
+ for (size_t i = 0; i < size(); i++) {
+ const sp<SwAudioOutputDescriptor> outputDesc = valueAt(i);
+ if (outputDesc->isActive()
+ && outputDesc->devices().containsDeviceAmongTypes(deviceTypes)) {
+ return true;
+ }
+ }
+ return false;
+}
void SwAudioOutputCollection::dump(String8 *dst) const
{
diff --git a/services/audiopolicy/config/bluetooth_with_le_audio_policy_configuration.xml b/services/audiopolicy/config/bluetooth_with_le_audio_policy_configuration.xml
index 22ff954..d34cca0 100644
--- a/services/audiopolicy/config/bluetooth_with_le_audio_policy_configuration.xml
+++ b/services/audiopolicy/config/bluetooth_with_le_audio_policy_configuration.xml
@@ -11,17 +11,7 @@
channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
</mixPort>
<!-- Le Audio Audio Ports -->
- <mixPort name="le audio output" role="source">
- <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
- samplingRates="8000,16000,24000,32000,44100,48000"
- channelMasks="AUDIO_CHANNEL_OUT_MONO,AUDIO_CHANNEL_OUT_STEREO"/>
- <profile name="" format="AUDIO_FORMAT_PCM_24_BIT_PACKED"
- samplingRates="8000,16000,24000,32000,44100,48000"
- channelMasks="AUDIO_CHANNEL_OUT_MONO,AUDIO_CHANNEL_OUT_STEREO"/>
- <profile name="" format="AUDIO_FORMAT_PCM_32_BIT"
- samplingRates="8000,16000,24000,32000,44100,48000"
- channelMasks="AUDIO_CHANNEL_OUT_MONO,AUDIO_CHANNEL_OUT_STEREO"/>
- </mixPort>
+ <mixPort name="le audio output" role="source"/>
<mixPort name="le audio input" role="sink">
<profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
samplingRates="8000,16000,24000,32000,44100,48000"
diff --git a/services/audiopolicy/config/bluetooth_with_le_audio_policy_configuration_7_0.xml b/services/audiopolicy/config/bluetooth_with_le_audio_policy_configuration_7_0.xml
index aad00d6..e7908eb 100644
--- a/services/audiopolicy/config/bluetooth_with_le_audio_policy_configuration_7_0.xml
+++ b/services/audiopolicy/config/bluetooth_with_le_audio_policy_configuration_7_0.xml
@@ -11,17 +11,7 @@
channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
</mixPort>
<!-- Le Audio Audio Ports -->
- <mixPort name="le audio output" role="source">
- <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
- samplingRates="8000 16000 24000 32000 44100 48000"
- channelMasks="AUDIO_CHANNEL_OUT_MONO AUDIO_CHANNEL_OUT_STEREO"/>
- <profile name="" format="AUDIO_FORMAT_PCM_24_BIT_PACKED"
- samplingRates="8000 16000 24000 32000 44100 48000"
- channelMasks="AUDIO_CHANNEL_OUT_MONO AUDIO_CHANNEL_OUT_STEREO"/>
- <profile name="" format="AUDIO_FORMAT_PCM_32_BIT"
- samplingRates="8000 16000 24000 32000 44100 48000"
- channelMasks="AUDIO_CHANNEL_OUT_MONO AUDIO_CHANNEL_OUT_STEREO"/>
- </mixPort>
+ <mixPort name="le audio output" role="source" />
<mixPort name="le audio input" role="sink">
<profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
samplingRates="8000 16000 24000 32000 44100 48000"
diff --git a/services/audiopolicy/engine/common/include/EngineBase.h b/services/audiopolicy/engine/common/include/EngineBase.h
index 0f8b0a5..7d21ae0 100644
--- a/services/audiopolicy/engine/common/include/EngineBase.h
+++ b/services/audiopolicy/engine/common/include/EngineBase.h
@@ -87,10 +87,17 @@
status_t listAudioVolumeGroups(AudioVolumeGroupVector &groups) const override;
+ /**
+ * Get the list of currently connected removable device types ordered from most recently
+ * connected to least recently connected.
+ * @param group the device group to consider: wired, a2dp... If none, consider all groups.
+ * @param excludedDevices list of device types to ignore
+ * @return a potentially empty ordered list of connected removable devices.
+ */
std::vector<audio_devices_t> getLastRemovableMediaDevices(
- device_out_group_t group = GROUP_NONE) const
- {
- return mLastRemovableMediaDevices.getLastRemovableMediaDevices(group);
+ device_out_group_t group = GROUP_NONE,
+ std::vector<audio_devices_t> excludedDevices = {}) const {
+ return mLastRemovableMediaDevices.getLastRemovableMediaDevices(group, excludedDevices);
}
void dump(String8 *dst) const override;
diff --git a/services/audiopolicy/engine/common/include/LastRemovableMediaDevices.h b/services/audiopolicy/engine/common/include/LastRemovableMediaDevices.h
index d7f8b1e..2662cd3 100644
--- a/services/audiopolicy/engine/common/include/LastRemovableMediaDevices.h
+++ b/services/audiopolicy/engine/common/include/LastRemovableMediaDevices.h
@@ -35,7 +35,8 @@
public:
void setRemovableMediaDevices(sp<DeviceDescriptor> desc, audio_policy_dev_state_t state);
std::vector<audio_devices_t> getLastRemovableMediaDevices(
- device_out_group_t group = GROUP_NONE) const;
+ device_out_group_t group = GROUP_NONE,
+ std::vector<audio_devices_t> excludedDevices = {}) const;
sp<DeviceDescriptor> getLastRemovableMediaDevice(
const DeviceVector& excludedDevices, device_out_group_t group = GROUP_NONE) const;
diff --git a/services/audiopolicy/engine/common/src/EngineBase.cpp b/services/audiopolicy/engine/common/src/EngineBase.cpp
index 7a06206..99507ee 100644
--- a/services/audiopolicy/engine/common/src/EngineBase.cpp
+++ b/services/audiopolicy/engine/common/src/EngineBase.cpp
@@ -72,9 +72,12 @@
{
audio_devices_t deviceType = devDesc->type();
if ((deviceType != AUDIO_DEVICE_NONE) && audio_is_output_device(deviceType)
- && deviceType != AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET) {
+ && deviceType != AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET
+ && deviceType != AUDIO_DEVICE_OUT_BLE_BROADCAST) {
// USB dock does not follow the rule of last removable device connected wins.
// It is only used if no removable device is connected or if set as preferred device
+ // LE audio broadcast device has a specific policy depending on active strategies and
+ // devices and does not follow the rule of last connected removable device.
mLastRemovableMediaDevices.setRemovableMediaDevices(devDesc, state);
}
diff --git a/services/audiopolicy/engine/common/src/LastRemovableMediaDevices.cpp b/services/audiopolicy/engine/common/src/LastRemovableMediaDevices.cpp
index 06cc799..93122e0 100644
--- a/services/audiopolicy/engine/common/src/LastRemovableMediaDevices.cpp
+++ b/services/audiopolicy/engine/common/src/LastRemovableMediaDevices.cpp
@@ -44,12 +44,15 @@
}
std::vector<audio_devices_t> LastRemovableMediaDevices::getLastRemovableMediaDevices(
- device_out_group_t group) const
+ device_out_group_t group, std::vector<audio_devices_t> excludedDevices) const
{
std::vector<audio_devices_t> ret;
for (auto iter = mMediaDevices.begin(); iter != mMediaDevices.end(); ++iter) {
- if ((group == GROUP_NONE) || (group == getDeviceOutGroup((iter->desc)->type()))) {
- ret.push_back((iter->desc)->type());
+ audio_devices_t type = (iter->desc)->type();
+ if ((group == GROUP_NONE || group == getDeviceOutGroup(type))
+ && std::find(excludedDevices.begin(), excludedDevices.end(), type) ==
+ excludedDevices.end()) {
+ ret.push_back(type);
}
}
return ret;
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index dc34a38..95aacb2 100644
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -270,7 +270,7 @@
devices = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_HEARING_AID);
if (!devices.isEmpty()) break;
devices = availableOutputDevices.getFirstDevicesFromTypes(
- getLastRemovableMediaDevices());
+ getLastRemovableMediaDevices(GROUP_NONE, {AUDIO_DEVICE_OUT_BLE_HEADSET}));
if (!devices.isEmpty()) break;
devices = availableOutputDevices.getFirstDevicesFromTypes({
AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET, AUDIO_DEVICE_OUT_EARPIECE});
@@ -344,6 +344,30 @@
(getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) == AUDIO_POLICY_FORCE_SPEAKER)) {
devices2 = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER);
}
+
+ // LE audio broadcast device is only used if:
+ // - No call is active
+ // - either MEDIA or SONIFICATION_RESPECTFUL is the highest priority active strategy
+ // OR the LE audio unicast device is not active
+ if (devices2.isEmpty() && !isInCall()
+ && (strategy == STRATEGY_MEDIA || strategy == STRATEGY_SONIFICATION_RESPECTFUL)) {
+ legacy_strategy topActiveStrategy = STRATEGY_NONE;
+ for (const auto &ps : getOrderedProductStrategies()) {
+ if (outputs.isStrategyActive(ps)) {
+ topActiveStrategy = mLegacyStrategyMap.find(ps) != end(mLegacyStrategyMap) ?
+ mLegacyStrategyMap.at(ps) : STRATEGY_NONE;
+ break;
+ }
+ }
+
+ if (topActiveStrategy == STRATEGY_NONE || topActiveStrategy == STRATEGY_MEDIA
+ || topActiveStrategy == STRATEGY_SONIFICATION_RESPECTFUL
+ || !outputs.isAnyDeviceTypeActive(getAudioDeviceOutLeAudioUnicastSet())) {
+ devices2 =
+ availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_BLE_BROADCAST);
+ }
+ }
+
if (devices2.isEmpty() && (getLastRemovableMediaDevices().size() > 0)) {
if ((getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) != AUDIO_POLICY_FORCE_NO_BT_A2DP)) {
// Get the last connected device of wired and bluetooth a2dp
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index ddc72f6..d6384f0 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -190,6 +190,9 @@
// save a copy of the opened output descriptors before any output is opened or closed
// by checkOutputsForDevice(). This will be needed by checkOutputForAllStrategies()
mPreviousOutputs = mOutputs;
+
+ bool wasLeUnicastActive = isLeUnicastActive();
+
switch (state)
{
// handle output device connection
@@ -356,6 +359,8 @@
cleanUpForDevice(device);
}
+ checkLeBroadcastRoutes(wasLeUnicastActive, nullptr, 0);
+
mpClientInterface->onAudioPortListUpdate();
return NO_ERROR;
} // end if is output device
@@ -804,6 +809,7 @@
ALOGV("setPhoneState() state %d", state);
// store previous phone state for management of sonification strategy below
int oldState = mEngine->getPhoneState();
+ bool wasLeUnicastActive = isLeUnicastActive();
if (mEngine->setPhoneState(state) != NO_ERROR) {
ALOGW("setPhoneState() invalid or same state %d", state);
@@ -882,6 +888,8 @@
}
}
+ checkLeBroadcastRoutes(wasLeUnicastActive, nullptr, delayMs);
+
if (isStateInCall(state)) {
ALOGV("setPhoneState() in call state management: new state is %d", state);
// force reevaluating accessibility routing when call starts
@@ -1989,6 +1997,22 @@
return status;
}
+bool AudioPolicyManager::isLeUnicastActive() const {
+ if (isInCall()) {
+ return true;
+ }
+ return isAnyDeviceTypeActive(getAudioDeviceOutLeAudioUnicastSet());
+}
+
+bool AudioPolicyManager::isAnyDeviceTypeActive(const DeviceTypeSet& deviceTypes) const {
+ if (mAvailableOutputDevices.getDevicesFromTypes(deviceTypes).isEmpty()) {
+ return false;
+ }
+ bool active = mOutputs.isAnyDeviceTypeActive(deviceTypes);
+ ALOGV("%s active %d", __func__, active);
+ return active;
+}
+
status_t AudioPolicyManager::startSource(const sp<SwAudioOutputDescriptor>& outputDesc,
const sp<TrackClientDescriptor>& client,
uint32_t *delayMs)
@@ -2040,6 +2064,7 @@
// and muting would result in unnecessary delay and dropped audio.
const uint32_t outputLatencyMs = outputDesc->latency();
bool requiresMuteCheck = outputDesc->isActive(outputLatencyMs * 2); // account for drain
+ bool wasLeUnicastActive = isLeUnicastActive();
// increment usage count for this stream on the requested output:
// NOTE that the usage count is the same for duplicated output and hardware output which is
@@ -2167,9 +2192,38 @@
AUDIO_FORMAT_DEFAULT);
}
+ checkLeBroadcastRoutes(wasLeUnicastActive, outputDesc, *delayMs);
+
return NO_ERROR;
}
+void AudioPolicyManager::checkLeBroadcastRoutes(bool wasUnicastActive,
+ sp<SwAudioOutputDescriptor> ignoredOutput, uint32_t delayMs) {
+ bool isUnicastActive = isLeUnicastActive();
+
+ if (wasUnicastActive != isUnicastActive) {
+ //reroute all outputs routed to LE broadcast if LE unicast activy changed on any output
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
+ if (desc != ignoredOutput && desc->isActive()
+ && ((isUnicastActive &&
+ !desc->devices().
+ getDevicesFromType(AUDIO_DEVICE_OUT_BLE_BROADCAST).isEmpty())
+ || (wasUnicastActive &&
+ !desc->devices().getDevicesFromTypes(
+ getAudioDeviceOutLeAudioUnicastSet()).isEmpty()))) {
+ DeviceVector newDevices = getNewOutputDevices(desc, false /*fromCache*/);
+ bool force = desc->devices() != newDevices;
+ setOutputDevices(desc, newDevices, force, delayMs);
+ // re-apply device specific volume if not done by setOutputDevice()
+ if (!force) {
+ applyStreamVolumes(desc, newDevices.types(), delayMs);
+ }
+ }
+ }
+ }
+}
+
status_t AudioPolicyManager::stopOutput(audio_port_handle_t portId)
{
ALOGV("%s portId %d", __FUNCTION__, portId);
@@ -2198,6 +2252,7 @@
// always handle stream stop, check which stream type is stopping
audio_stream_type_t stream = client->stream();
auto clientVolSrc = client->volumeSource();
+ bool wasLeUnicastActive = isLeUnicastActive();
handleEventForBeacon(stream == AUDIO_STREAM_TTS ? STOPPING_BEACON : STOPPING_OUTPUT);
@@ -2276,6 +2331,9 @@
if (followsSameRouting(client->attributes(), attributes_initializer(AUDIO_USAGE_MEDIA))) {
selectOutputForMusicEffects();
}
+
+ checkLeBroadcastRoutes(wasLeUnicastActive, outputDesc, outputDesc->latency()*2);
+
return NO_ERROR;
} else {
ALOGW("stopOutput() refcount is already 0");
@@ -2351,7 +2409,6 @@
session, flags, toString(*attr).c_str(), *selectedDeviceId);
status_t status = NO_ERROR;
- audio_source_t halInputSource;
audio_attributes_t attributes = *attr;
sp<AudioPolicyMix> policyMix;
sp<DeviceDescriptor> device;
@@ -2422,8 +2479,6 @@
*input = AUDIO_IO_HANDLE_NONE;
*inputType = API_INPUT_INVALID;
- halInputSource = attributes.source;
-
if (attributes.source == AUDIO_SOURCE_REMOTE_SUBMIX &&
strncmp(attributes.tags, "addr=", strlen("addr=")) == 0) {
status = mPolicyMixes.getInputMixForAttr(attributes, &policyMix);
@@ -3585,6 +3640,7 @@
void AudioPolicyManager::updateCallAndOutputRouting(bool forceVolumeReeval, uint32_t delayMs)
{
uint32_t waitMs = 0;
+ bool wasLeUnicastActive = isLeUnicastActive();
if (updateCallRouting(true /*fromCache*/, delayMs, &waitMs) == NO_ERROR) {
// Only apply special touch sound delay once
delayMs = 0;
@@ -3608,6 +3664,7 @@
applyStreamVolumes(outputDesc, newDevices.types(), waitMs, true);
}
}
+ checkLeBroadcastRoutes(wasLeUnicastActive, nullptr, delayMs);
}
void AudioPolicyManager::updateInputRouting() {
@@ -7443,13 +7500,11 @@
return mEngine->getForceUse(usage);
}
-bool AudioPolicyManager::isInCall()
-{
+bool AudioPolicyManager::isInCall() const {
return isStateInCall(mEngine->getPhoneState());
}
-bool AudioPolicyManager::isStateInCall(int state)
-{
+bool AudioPolicyManager::isStateInCall(int state) const {
return is_state_in_call(state);
}
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 0d9b5bf..441a0b7 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -598,9 +598,9 @@
audio_mode_t getPhoneState();
// true if device is in a telephony or VoIP call
- virtual bool isInCall();
+ virtual bool isInCall() const;
// true if given state represents a device in a telephony or VoIP call
- virtual bool isStateInCall(int state);
+ virtual bool isStateInCall(int state) const;
// true if playback to call TX or capture from call RX is possible
bool isCallAudioAccessible();
@@ -887,6 +887,21 @@
void closeActiveClients(const sp<AudioInputDescriptor>& input);
void closeClient(audio_port_handle_t portId);
+ /**
+ * @brief isAnyDeviceTypeActive: returns true if at least one active client is routed to
+ * one of the specified devices
+ * @param deviceTypes list of devices to consider
+ */
+ bool isAnyDeviceTypeActive(const DeviceTypeSet& deviceTypes) const;
+ /**
+ * @brief isLeUnicastActive: returns true if a call is active or at least one active client
+ * is routed to a LE unicast device
+ */
+ bool isLeUnicastActive() const;
+
+ void checkLeBroadcastRoutes(bool wasUnicastActive,
+ sp<SwAudioOutputDescriptor> ignoredOutput, uint32_t delayMs);
+
const uid_t mUidCached; // AID_AUDIOSERVER
AudioPolicyClientInterface *mpClientInterface; // audio policy client interface
sp<SwAudioOutputDescriptor> mPrimaryOutput; // primary output descriptor
diff --git a/services/audiopolicy/service/Spatializer.cpp b/services/audiopolicy/service/Spatializer.cpp
index 389233e..ef11072 100644
--- a/services/audiopolicy/service/Spatializer.cpp
+++ b/services/audiopolicy/service/Spatializer.cpp
@@ -342,12 +342,7 @@
modes->push_back(SpatializerHeadTrackingMode::DISABLED);
if (mSupportsHeadTracking) {
- if (mHeadSensor != SpatializerPoseController::INVALID_SENSOR) {
- modes->push_back(SpatializerHeadTrackingMode::RELATIVE_WORLD);
- if (mScreenSensor != SpatializerPoseController::INVALID_SENSOR) {
- modes->push_back(SpatializerHeadTrackingMode::RELATIVE_SCREEN);
- }
- }
+ modes->push_back(SpatializerHeadTrackingMode::RELATIVE_WORLD);
}
return Status::ok();
}
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.cpp b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
index 0ac047a..a7097fb 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.cpp
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
@@ -243,20 +243,23 @@
template <typename TClientBase>
binder::Status Camera2ClientBase<TClientBase>::disconnect() {
ATRACE_CALL();
+ ALOGD("Camera %s: start to disconnect", TClientBase::mCameraIdStr.string());
Mutex::Autolock icl(mBinderSerializationLock);
+ ALOGD("Camera %s: serializationLock acquired", TClientBase::mCameraIdStr.string());
binder::Status res = binder::Status::ok();
// Allow both client and the media server to disconnect at all times
int callingPid = CameraThreadState::getCallingPid();
if (callingPid != TClientBase::mClientPid &&
callingPid != TClientBase::mServicePid) return res;
- ALOGV("Camera %s: Shutting down", TClientBase::mCameraIdStr.string());
+ ALOGD("Camera %s: Shutting down", TClientBase::mCameraIdStr.string());
// Before detaching the device, cache the info from current open session.
// The disconnected check avoids duplication of info and also prevents
// deadlock while acquiring service lock in cacheDump.
if (!TClientBase::mDisconnected) {
+ ALOGD("Camera %s: start to cacheDump", TClientBase::mCameraIdStr.string());
Camera2ClientBase::getCameraService()->cacheDump();
}
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index d545484..6edf1ac 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -1243,6 +1243,34 @@
return OK;
}
+status_t CameraProviderManager::ProviderInfo::DeviceInfo3::fixupTorchStrengthTags() {
+ status_t res = OK;
+ auto& c = mCameraCharacteristics;
+ auto flashInfoStrengthDefaultLevelEntry = c.find(ANDROID_FLASH_INFO_STRENGTH_DEFAULT_LEVEL);
+ if (flashInfoStrengthDefaultLevelEntry.count == 0) {
+ int32_t flashInfoStrengthDefaultLevel = 1;
+ res = c.update(ANDROID_FLASH_INFO_STRENGTH_DEFAULT_LEVEL,
+ &flashInfoStrengthDefaultLevel, 1);
+ if (res != OK) {
+ ALOGE("%s: Failed to update ANDROID_FLASH_INFO_STRENGTH_DEFAULT_LEVEL: %s (%d)",
+ __FUNCTION__,strerror(-res), res);
+ return res;
+ }
+ }
+ auto flashInfoStrengthMaximumLevelEntry = c.find(ANDROID_FLASH_INFO_STRENGTH_MAXIMUM_LEVEL);
+ if (flashInfoStrengthMaximumLevelEntry.count == 0) {
+ int32_t flashInfoStrengthMaximumLevel = 1;
+ res = c.update(ANDROID_FLASH_INFO_STRENGTH_MAXIMUM_LEVEL,
+ &flashInfoStrengthMaximumLevel, 1);
+ if (res != OK) {
+ ALOGE("%s: Failed to update ANDROID_FLASH_INFO_STRENGTH_MAXIMUM_LEVEL: %s (%d)",
+ __FUNCTION__,strerror(-res), res);
+ return res;
+ }
+ }
+ return res;
+}
+
status_t CameraProviderManager::ProviderInfo::DeviceInfo3::fixupMonochromeTags() {
status_t res = OK;
auto& c = mCameraCharacteristics;
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.h b/services/camera/libcameraservice/common/CameraProviderManager.h
index d934ae8..3a366e5 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.h
+++ b/services/camera/libcameraservice/common/CameraProviderManager.h
@@ -667,6 +667,7 @@
void queryPhysicalCameraIds();
SystemCameraKind getSystemCameraKind();
status_t fixupMonochromeTags();
+ status_t fixupTorchStrengthTags();
status_t addDynamicDepthTags(bool maxResolution = false);
status_t deriveHeicTags(bool maxResolution = false);
status_t addRotateCropTags();
diff --git a/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp b/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp
index f58ed00..81b4779 100644
--- a/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp
+++ b/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp
@@ -538,6 +538,13 @@
if (flashAvailable.count == 1 &&
flashAvailable.data.u8[0] == ANDROID_FLASH_INFO_AVAILABLE_TRUE) {
mHasFlashUnit = true;
+ // Fix up flash strength tags for devices without these keys.
+ res = fixupTorchStrengthTags();
+ if (OK != res) {
+ ALOGE("%s: Unable to add default ANDROID_FLASH_INFO_STRENGTH_DEFAULT_LEVEL and"
+ "ANDROID_FLASH_INFO_STRENGTH_MAXIMUM_LEVEL tags: %s (%d)", __FUNCTION__,
+ strerror(-res), res);
+ }
} else {
mHasFlashUnit = false;
}
diff --git a/services/camera/libcameraservice/common/hidl/HidlProviderInfo.cpp b/services/camera/libcameraservice/common/hidl/HidlProviderInfo.cpp
index 195cf45..b3cce1c 100644
--- a/services/camera/libcameraservice/common/hidl/HidlProviderInfo.cpp
+++ b/services/camera/libcameraservice/common/hidl/HidlProviderInfo.cpp
@@ -662,6 +662,13 @@
if (flashAvailable.count == 1 &&
flashAvailable.data.u8[0] == ANDROID_FLASH_INFO_AVAILABLE_TRUE) {
mHasFlashUnit = true;
+ // Fix up flash strength tags for devices without these keys.
+ res = fixupTorchStrengthTags();
+ if (OK != res) {
+ ALOGE("%s: Unable to add default ANDROID_FLASH_INFO_STRENGTH_DEFAULT_LEVEL and"
+ "ANDROID_FLASH_INFO_STRENGTH_MAXIMUM_LEVEL tags: %s (%d)", __FUNCTION__,
+ strerror(-res), res);
+ }
} else {
mHasFlashUnit = false;
}
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index f7b6b58..b133263 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -1557,13 +1557,22 @@
}
bool stateSeen = false;
+ nsecs_t startTime = systemTime();
do {
if (active == (mStatus == STATUS_ACTIVE)) {
// Desired state is current
break;
}
- res = mStatusChanged.waitRelative(mLock, timeout);
+ nsecs_t timeElapsed = systemTime() - startTime;
+ nsecs_t timeToWait = timeout - timeElapsed;
+ if (timeToWait <= 0) {
+ // Thread woke up spuriously but has timed out since.
+ // Force out of loop with TIMED_OUT result.
+ res = TIMED_OUT;
+ break;
+ }
+ res = mStatusChanged.waitRelative(mLock, timeToWait);
if (res != OK) break;
// This is impossible, but if not, could result in subtle deadlocks and invalid state