Merge "Fix typo in Engine::getDevicesForProductStrategy."
diff --git a/camera/aidl/android/hardware/ICameraService.aidl b/camera/aidl/android/hardware/ICameraService.aidl
index 3687b15..1e748c7 100644
--- a/camera/aidl/android/hardware/ICameraService.aidl
+++ b/camera/aidl/android/hardware/ICameraService.aidl
@@ -187,6 +187,8 @@
*/
const int EVENT_NONE = 0;
const int EVENT_USER_SWITCHED = 1; // The argument is the set of new foreground user IDs.
+ const int EVENT_USB_DEVICE_ATTACHED = 2; // The argument is the deviceId and vendorId
+ const int EVENT_USB_DEVICE_DETACHED = 3; // The argument is the deviceId and vendorId
oneway void notifySystemEvent(int eventId, in int[] args);
/**
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index bd6db55..a1e1702 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -55,6 +55,7 @@
// for audio_track_cblk_t::mState, to match TrackBase.h
static inline constexpr int CBLK_STATE_IDLE = 0;
+static inline constexpr int CBLK_STATE_ACTIVE = 6;
static inline constexpr int CBLK_STATE_PAUSING = 7;
/**
diff --git a/media/libaaudio/examples/utils/AAudioSimplePlayer.h b/media/libaaudio/examples/utils/AAudioSimplePlayer.h
index 7daac20..956b3cd 100644
--- a/media/libaaudio/examples/utils/AAudioSimplePlayer.h
+++ b/media/libaaudio/examples/utils/AAudioSimplePlayer.h
@@ -40,6 +40,31 @@
int64_t nanoseconds;
} Timestamp;
+static constexpr int32_t kWorkloadScaler = 500;
+
+// Linear congruential random number generator.
+static uint32_t s_random16() {
+ static uint32_t seed = 1234;
+ seed = ((seed * 31421) + 6927) & 0x0FFFF;
+ return seed;
+}
+
+/**
+ * The random number generator is good for burning CPU because the compiler cannot
+ * easily optimize away the computation.
+ * @param workload number of times to execute the loop
+ * @return a white noise value between -1.0 and +1.0
+ */
+static float s_burnCPU(int32_t workload) {
+ uint32_t random = 0;
+ for (int32_t i = 0; i < workload; i++) {
+ for (int32_t j = 0; j < 10; j++) {
+ random = random ^ s_random16();
+ }
+ }
+ return (random - 32768) * (1.0 / 32768);
+}
+
/**
* Simple wrapper for AAudio that opens an output stream either in callback or blocking write mode.
*/
@@ -268,11 +293,13 @@
int32_t timestampCount = 0; // in timestamps
int32_t sampleRate = 48000;
int32_t prefixToneFrames = 0;
+ double workload = 0.0;
bool sweepSetup = false;
int scheduler = 0;
bool schedulerChecked = false;
int32_t hangTimeMSec = 0;
+ int cpuAffinity = -1;
AAudioSimplePlayer simplePlayer;
int32_t callbackCount = 0;
@@ -304,6 +331,14 @@
} SineThreadedData_t;
+int setCpuAffinity(int cpuIndex) {
+cpu_set_t cpu_set;
+ CPU_ZERO(&cpu_set);
+ CPU_SET(cpuIndex, &cpu_set);
+ int err = sched_setaffinity((pid_t) 0, sizeof(cpu_set_t), &cpu_set);
+ return err == 0 ? 0 : -errno;
+}
+
// Callback function that fills the audio output buffer.
aaudio_data_callback_result_t SimplePlayerDataCallbackProc(
AAudioStream *stream,
@@ -319,6 +354,10 @@
}
SineThreadedData_t *sineData = (SineThreadedData_t *) userData;
+ if (sineData->cpuAffinity >= 0) {
+ setCpuAffinity(sineData->cpuAffinity);
+ sineData->cpuAffinity = -1;
+ }
// Play an initial high tone so we can tell whether the beginning was truncated.
if (!sineData->sweepSetup && sineData->framesTotal >= sineData->prefixToneFrames) {
sineData->setupSineSweeps();
@@ -398,6 +437,8 @@
return AAUDIO_CALLBACK_RESULT_STOP;
}
+ s_burnCPU((int32_t)(sineData->workload * kWorkloadScaler * numFrames));
+
sineData->callbackCount++;
sineData->framesTotal += numFrames;
return AAUDIO_CALLBACK_RESULT_CONTINUE;
diff --git a/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp b/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
index cdc987b..400fc7c 100644
--- a/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
+++ b/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
@@ -31,10 +31,10 @@
#include "AAudioSimplePlayer.h"
#include "AAudioArgsParser.h"
-#define APP_VERSION "0.1.8"
+#define APP_VERSION "0.2.1"
-constexpr int32_t kDefaultHangTimeMSec = 10;
-
+static constexpr int32_t kDefaultHangTimeMSec = 10;
+static constexpr int32_t kWorkPeriodSeconds = 6;
/**
* Open stream, play some sine waves, then close the stream.
*
@@ -44,7 +44,11 @@
static aaudio_result_t testOpenPlayClose(AAudioArgsParser &argParser,
int32_t loopCount,
int32_t prefixToneMsec,
- int32_t hangTimeMSec)
+ int32_t hangTimeMSec,
+ int cpuAffinity,
+ double lowWorkLoad,
+ double highWorkLoad,
+ int32_t workPeriodSeconds)
{
SineThreadedData_t myData;
AAudioSimplePlayer &player = myData.simplePlayer;
@@ -57,6 +61,7 @@
myData.schedulerChecked = false;
myData.callbackCount = 0;
myData.hangTimeMSec = hangTimeMSec; // test AAudioStream_getXRunCount()
+ myData.cpuAffinity = cpuAffinity;
result = player.open(argParser,
SimplePlayerDataCallbackProc,
@@ -111,8 +116,8 @@
}
// Play a sine wave in the background.
- printf("Sleep for %d seconds while audio plays in a callback thread. %d of %d\n",
- argParser.getDurationSeconds(), (loopIndex + 1), loopCount);
+ printf("Monitor for %d seconds while audio plays in a callback thread. %d of %d, %d\n",
+ argParser.getDurationSeconds(), (loopIndex + 1), loopCount, workPeriodSeconds);
startedAtNanos = getNanoseconds(CLOCK_MONOTONIC);
for (int second = 0; second < durationSeconds; second++) {
// Sleep a while. Wake up early if there is an error, for example a DISCONNECT.
@@ -123,13 +128,17 @@
const int32_t framesWritten = (int32_t) AAudioStream_getFramesWritten(player.getStream());
const int32_t framesRead = (int32_t) AAudioStream_getFramesRead(player.getStream());
const int32_t xruns = AAudioStream_getXRunCount(player.getStream());
+ myData.workload = ((second % (2 * workPeriodSeconds)) < workPeriodSeconds)
+ ? lowWorkLoad : highWorkLoad;
printf(" waker result = %d, at %6d millis"
- ", second = %3d, frames written %8d - read %8d = %8d, underruns = %d\n",
+ ", second = %3d, frames written %8d - read %8d = %8d"
+ ", work = %5.1f, underruns = %d\n",
result, (int) millis,
second,
framesWritten,
framesRead,
framesWritten - framesRead,
+ myData.workload,
xruns);
if (result != AAUDIO_OK) {
disconnected = (result == AAUDIO_ERROR_DISCONNECTED);
@@ -220,6 +229,11 @@
AAudioArgsParser::usage();
printf(" -l{count} loopCount start/stop, every other one is silent\n");
printf(" -t{msec} play a high pitched tone at the beginning\n");
+ printf(" -w{workload} set base workload, default 0.0\n");
+ printf(" -W{workload} alternate between this higher workload and base workload\n");
+ printf(" -Z{duration} number of seconds to spend at each workload, default = %d\n",
+ kWorkPeriodSeconds);
+ printf(" -a{cpu} set CPU affinity, default none\n");
printf(" -h{msec} force periodic underruns by hanging in callback\n");
printf(" If no value specified then %d used.\n",
kDefaultHangTimeMSec);
@@ -232,6 +246,10 @@
int32_t loopCount = 1;
int32_t prefixToneMsec = 0;
int32_t hangTimeMSec = 0;
+ int cpuAffinity = -1;
+ double lowWorkLoad = 0.0;
+ double highWorkLoad = -1.0;
+ int32_t workPeriodSeconds = kWorkPeriodSeconds;
// Make printf print immediately so that debug info is not stuck
// in a buffer if we hang or crash.
@@ -247,6 +265,9 @@
if (arg[0] == '-') {
char option = arg[1];
switch (option) {
+ case 'a':
+ cpuAffinity = atoi(&arg[2]);
+ break;
case 'l':
loopCount = atoi(&arg[2]);
break;
@@ -258,6 +279,15 @@
? atoi(&arg[2])
: kDefaultHangTimeMSec;
break;
+ case 'w':
+ lowWorkLoad = atof(&arg[2]);
+ break;
+ case 'W':
+ highWorkLoad = atof(&arg[2]);
+ break;
+ case 'Z':
+ workPeriodSeconds = atoi(&arg[2]);
+ break;
default:
usage();
exit(EXIT_FAILURE);
@@ -271,9 +301,21 @@
}
}
+ if (highWorkLoad > 0) {
+ if (highWorkLoad < lowWorkLoad) {
+ printf("ERROR - -W%f workload lower than -w%f workload", highWorkLoad, lowWorkLoad);
+ return EXIT_FAILURE;
+ }
+ } else {
+ highWorkLoad = lowWorkLoad; // high not specified so use low
+ }
+
// Keep looping until we can complete the test without disconnecting.
while((result = testOpenPlayClose(argParser, loopCount,
- prefixToneMsec, hangTimeMSec))
+ prefixToneMsec, hangTimeMSec,
+ cpuAffinity,
+ lowWorkLoad, highWorkLoad,
+ workPeriodSeconds))
== AAUDIO_ERROR_DISCONNECTED);
return (result) ? EXIT_FAILURE : EXIT_SUCCESS;
diff --git a/media/libaudioclient/AidlConversion.cpp b/media/libaudioclient/AidlConversion.cpp
index 323e002..b7be3ff 100644
--- a/media/libaudioclient/AidlConversion.cpp
+++ b/media/libaudioclient/AidlConversion.cpp
@@ -1434,6 +1434,8 @@
return AUDIO_INPUT_FLAG_HW_AV_SYNC;
case AudioInputFlags::DIRECT:
return AUDIO_INPUT_FLAG_DIRECT;
+ case AudioInputFlags::ULTRASOUND:
+ return AUDIO_INPUT_FLAG_ULTRASOUND;
}
return unexpected(BAD_VALUE);
}
@@ -1459,6 +1461,8 @@
return AudioInputFlags::HW_AV_SYNC;
case AUDIO_INPUT_FLAG_DIRECT:
return AudioInputFlags::DIRECT;
+ case AUDIO_INPUT_FLAG_ULTRASOUND:
+ return AudioInputFlags::ULTRASOUND;
}
return unexpected(BAD_VALUE);
}
@@ -1498,6 +1502,8 @@
return AUDIO_OUTPUT_FLAG_INCALL_MUSIC;
case AudioOutputFlags::GAPLESS_OFFLOAD:
return AUDIO_OUTPUT_FLAG_GAPLESS_OFFLOAD;
+ case AudioOutputFlags::ULTRASOUND:
+ return AUDIO_OUTPUT_FLAG_ULTRASOUND;
}
return unexpected(BAD_VALUE);
}
@@ -1539,6 +1545,8 @@
return AudioOutputFlags::INCALL_MUSIC;
case AUDIO_OUTPUT_FLAG_GAPLESS_OFFLOAD:
return AudioOutputFlags::GAPLESS_OFFLOAD;
+ case AUDIO_OUTPUT_FLAG_ULTRASOUND:
+ return AudioOutputFlags::ULTRASOUND;
}
return unexpected(BAD_VALUE);
}
@@ -1744,6 +1752,8 @@
return AUDIO_SOURCE_UNPROCESSED;
case AudioSource::VOICE_PERFORMANCE:
return AUDIO_SOURCE_VOICE_PERFORMANCE;
+ case AudioSource::ULTRASOUND:
+ return AUDIO_SOURCE_ULTRASOUND;
case AudioSource::ECHO_REFERENCE:
return AUDIO_SOURCE_ECHO_REFERENCE;
case AudioSource::FM_TUNER:
@@ -1781,6 +1791,8 @@
return AudioSource::UNPROCESSED;
case AUDIO_SOURCE_VOICE_PERFORMANCE:
return AudioSource::VOICE_PERFORMANCE;
+ case AUDIO_SOURCE_ULTRASOUND:
+ return AudioSource::ULTRASOUND;
case AUDIO_SOURCE_ECHO_REFERENCE:
return AudioSource::ECHO_REFERENCE;
case AUDIO_SOURCE_FM_TUNER:
@@ -2141,6 +2153,8 @@
return AUDIO_CONTENT_TYPE_MOVIE;
case AudioContentType::SONIFICATION:
return AUDIO_CONTENT_TYPE_SONIFICATION;
+ case AudioContentType::ULTRASOUND:
+ return AUDIO_CONTENT_TYPE_ULTRASOUND;
}
return unexpected(BAD_VALUE);
}
@@ -2158,6 +2172,8 @@
return AudioContentType::MOVIE;
case AUDIO_CONTENT_TYPE_SONIFICATION:
return AudioContentType::SONIFICATION;
+ case AUDIO_CONTENT_TYPE_ULTRASOUND:
+ return AudioContentType::ULTRASOUND;
}
return unexpected(BAD_VALUE);
}
diff --git a/media/libaudioclient/Android.bp b/media/libaudioclient/Android.bp
index 9733cb3..be39527 100644
--- a/media/libaudioclient/Android.bp
+++ b/media/libaudioclient/Android.bp
@@ -41,7 +41,7 @@
},
}
-cc_library_shared {
+cc_library {
name: "libaudiopolicy",
srcs: [
"AudioAttributes.cpp",
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index bdf3147..de14e1c 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -1120,8 +1120,16 @@
{
using namespace std::chrono_literals;
+ // We use atomic access here for state variables - these are used as hints
+ // to ensure we have ramped down audio.
+ const int priorState = mProxy->getState();
+ const uint32_t priorPosition = mProxy->getPosition().unsignedValue();
+
pause();
+ // Only if we were previously active, do we wait to ramp down the audio.
+ if (priorState != CBLK_STATE_ACTIVE) return true;
+
AutoMutex lock(mLock);
// offload and direct tracks do not wait because pause volume ramp is handled by hardware.
if (isOffloadedOrDirect_l()) return true;
@@ -1129,16 +1137,25 @@
// Wait for the track state to be anything besides pausing.
// This ensures that the volume has ramped down.
constexpr auto SLEEP_INTERVAL_MS = 10ms;
+ constexpr auto POSITION_TIMEOUT_MS = 40ms; // don't wait longer than this for position change.
auto begin = std::chrono::steady_clock::now();
while (true) {
- // wait for state to change
+ // Wait for state and position to change.
+ // After pause() the server state should be PAUSING, but that may immediately
+ // convert to PAUSED by prepareTracks before data is read into the mixer.
+ // Hence we check that the state is not PAUSING and that the server position
+ // has advanced to be a more reliable estimate that the volume ramp has completed.
const int state = mProxy->getState();
+ const uint32_t position = mProxy->getPosition().unsignedValue();
mLock.unlock(); // only local variables accessed until lock.
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::steady_clock::now() - begin);
- if (state != CBLK_STATE_PAUSING) {
- ALOGV("%s: success state:%d after %lld ms", __func__, state, elapsed.count());
+ if (state != CBLK_STATE_PAUSING &&
+ (elapsed >= POSITION_TIMEOUT_MS || position != priorPosition)) {
+ ALOGV("%s: success state:%d, position:%u after %lld ms"
+ " (prior state:%d prior position:%u)",
+ __func__, state, position, elapsed.count(), priorState, priorPosition);
return true;
}
std::chrono::milliseconds remaining = timeout - elapsed;
diff --git a/media/libheadtracking/HeadTrackingProcessor.cpp b/media/libheadtracking/HeadTrackingProcessor.cpp
index b2d2dbd..f2f15df 100644
--- a/media/libheadtracking/HeadTrackingProcessor.cpp
+++ b/media/libheadtracking/HeadTrackingProcessor.cpp
@@ -66,6 +66,7 @@
Pose3f predictedWorldToHead =
worldToHead * integrate(headTwist, mOptions.predictionDuration);
mHeadPoseDriftCompensator.setInput(timestamp, predictedWorldToHead);
+ mHeadStillnessDetector.setInput(timestamp, predictedWorldToHead);
mWorldToHeadTimestamp = timestamp;
}
@@ -76,8 +77,9 @@
mPhysicalToLogicalAngle = mPendingPhysicalToLogicalAngle;
}
- mScreenPoseDriftCompensator.setInput(
- timestamp, worldToScreen * Pose3f(rotateY(-mPhysicalToLogicalAngle)));
+ Pose3f worldToLogicalScreen = worldToScreen * Pose3f(rotateY(-mPhysicalToLogicalAngle));
+ mScreenPoseDriftCompensator.setInput(timestamp, worldToLogicalScreen);
+ mScreenStillnessDetector.setInput(timestamp, worldToLogicalScreen);
mWorldToScreenTimestamp = timestamp;
}
@@ -93,8 +95,6 @@
// Handle the screen first, since it might trigger a recentering of the head.
if (mWorldToScreenTimestamp.has_value()) {
const Pose3f worldToLogicalScreen = mScreenPoseDriftCompensator.getOutput();
- mScreenStillnessDetector.setInput(mWorldToScreenTimestamp.value(),
- worldToLogicalScreen);
bool screenStable = mScreenStillnessDetector.calculate(timestamp);
mModeSelector.setScreenStable(mWorldToScreenTimestamp.value(), screenStable);
// Whenever the screen is unstable, recenter the head pose.
@@ -108,7 +108,6 @@
// Handle head.
if (mWorldToHeadTimestamp.has_value()) {
Pose3f worldToHead = mHeadPoseDriftCompensator.getOutput();
- mHeadStillnessDetector.setInput(mWorldToHeadTimestamp.value(), worldToHead);
// Auto-recenter.
if (mHeadStillnessDetector.calculate(timestamp)) {
recenter(true, false);
diff --git a/media/libheadtracking/StillnessDetector-test.cpp b/media/libheadtracking/StillnessDetector-test.cpp
index 02f9d8a..b6cd479 100644
--- a/media/libheadtracking/StillnessDetector-test.cpp
+++ b/media/libheadtracking/StillnessDetector-test.cpp
@@ -83,13 +83,10 @@
EXPECT_EQ(mDefaultValue, detector.calculate(300));
detector.setInput(600, baseline);
EXPECT_EQ(mDefaultValue, detector.calculate(600));
- detector.setInput(900, withinThreshold);
- EXPECT_EQ(mDefaultValue, detector.calculate(900));
+ detector.setInput(1299, withinThreshold);
+ EXPECT_FALSE(detector.calculate(1299));
detector.setInput(1300, baseline);
- EXPECT_FALSE(detector.calculate(1300));
- detector.setInput(1500, baseline);
- EXPECT_FALSE(detector.calculate(1899));
- EXPECT_TRUE(detector.calculate(1900));
+ EXPECT_TRUE(detector.calculate(1300));
}
TEST_P(StillnessDetectorTest, NotStillRotation) {
@@ -110,13 +107,10 @@
EXPECT_EQ(mDefaultValue, detector.calculate(300));
detector.setInput(600, baseline);
EXPECT_EQ(mDefaultValue, detector.calculate(600));
- detector.setInput(900, withinThreshold);
- EXPECT_EQ(mDefaultValue, detector.calculate(900));
+ detector.setInput(1299, withinThreshold);
+ EXPECT_FALSE(detector.calculate(1299));
detector.setInput(1300, baseline);
- EXPECT_FALSE(detector.calculate(1300));
- detector.setInput(1500, baseline);
- EXPECT_FALSE(detector.calculate(1899));
- EXPECT_TRUE(detector.calculate(1900));
+ EXPECT_TRUE(detector.calculate(1300));
}
TEST_P(StillnessDetectorTest, Suppression) {
@@ -134,10 +128,10 @@
EXPECT_TRUE(detector.calculate(1000));
detector.setInput(1100, outsideThreshold);
EXPECT_FALSE(detector.calculate(1100));
- detector.setInput(2000, middlePoint);
- EXPECT_FALSE(detector.calculate(2000));
- EXPECT_FALSE(detector.calculate(2099));
- EXPECT_TRUE(detector.calculate(2100));
+ detector.setInput(1500, middlePoint);
+ EXPECT_FALSE(detector.calculate(1500));
+ EXPECT_FALSE(detector.calculate(1999));
+ EXPECT_TRUE(detector.calculate(2000));
}
TEST_P(StillnessDetectorTest, Reset) {
@@ -150,8 +144,8 @@
const Pose3f withinThreshold =
baseline * Pose3f(Vector3f(0.3, -0.3, 0), rotateX(0.01) * rotateY(-0.01));
EXPECT_EQ(mDefaultValue, detector.calculate(0));
- detector.setInput(0, baseline);
- EXPECT_EQ(mDefaultValue, detector.calculate(0));
+ detector.setInput(300, baseline);
+ EXPECT_EQ(mDefaultValue, detector.calculate(300));
detector.reset();
detector.setInput(600, baseline);
EXPECT_EQ(mDefaultValue, detector.calculate(600));
diff --git a/media/libheadtracking/StillnessDetector.cpp b/media/libheadtracking/StillnessDetector.cpp
index 9806352..be7c893 100644
--- a/media/libheadtracking/StillnessDetector.cpp
+++ b/media/libheadtracking/StillnessDetector.cpp
@@ -36,17 +36,22 @@
bool StillnessDetector::calculate(int64_t timestamp) {
discardOld(timestamp);
- // Check whether all the poses in the queue are in the proximity of the new
- // one. We want to do this before checking the overriding conditions below, in order to update
- // the suppression deadline correctly.
+ // Check whether all the poses in the queue are in the proximity of the new one. We want to do
+ // this before checking the overriding conditions below, in order to update the suppression
+ // deadline correctly. We always go from end to start, to find the most recent pose that
+ // violated stillness and update the suppression deadline if it has not been set or if the new
+ // one ends after the current one.
bool moved = false;
if (!mFifo.empty()) {
- for (auto iter = mFifo.begin(); iter != mFifo.end() - 1; ++iter) {
+ for (auto iter = mFifo.rbegin() + 1; iter != mFifo.rend(); ++iter) {
const auto& event = *iter;
if (!areNear(event.pose, mFifo.back().pose)) {
// Enable suppression for the duration of the window.
- mSuppressionDeadline = timestamp + mOptions.windowDuration;
+ int64_t deadline = event.timestamp + mOptions.windowDuration;
+ if (!mSuppressionDeadline.has_value() || mSuppressionDeadline.value() < deadline) {
+ mSuppressionDeadline = deadline;
+ }
moved = true;
break;
}
diff --git a/media/utils/ServiceUtilities.cpp b/media/utils/ServiceUtilities.cpp
index 15d6d3697..1ab5bc1 100644
--- a/media/utils/ServiceUtilities.cpp
+++ b/media/utils/ServiceUtilities.cpp
@@ -220,6 +220,17 @@
return ok;
}
+bool accessUltrasoundAllowed(const AttributionSourceState& attributionSource) {
+ uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(attributionSource.uid));
+ uid_t pid = VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(attributionSource.pid));
+ if (isAudioServerOrRootUid(uid)) return true;
+ static const String16 sAccessUltrasound(
+ "android.permission.ACCESS_ULTRASOUND");
+ bool ok = PermissionCache::checkPermission(sAccessUltrasound, pid, uid);
+ if (!ok) ALOGE("Request requires android.permission.ACCESS_ULTRASOUND");
+ return ok;
+}
+
bool captureHotwordAllowed(const AttributionSourceState& attributionSource) {
// CAPTURE_AUDIO_HOTWORD permission implies RECORD_AUDIO permission
bool ok = recordingAllowed(attributionSource);
diff --git a/media/utils/include/mediautils/ServiceUtilities.h b/media/utils/include/mediautils/ServiceUtilities.h
index cb428ec..de20d55 100644
--- a/media/utils/include/mediautils/ServiceUtilities.h
+++ b/media/utils/include/mediautils/ServiceUtilities.h
@@ -96,6 +96,7 @@
bool captureMediaOutputAllowed(const AttributionSourceState& attributionSource);
bool captureTunerAudioInputAllowed(const AttributionSourceState& attributionSource);
bool captureVoiceCommunicationOutputAllowed(const AttributionSourceState& attributionSource);
+bool accessUltrasoundAllowed(const AttributionSourceState& attributionSource);
bool captureHotwordAllowed(const AttributionSourceState& attributionSource);
bool settingsAllowed();
bool modifyAudioRoutingAllowed();
diff --git a/services/audiopolicy/common/include/policy.h b/services/audiopolicy/common/include/policy.h
index 577f641..3d3e0cf 100644
--- a/services/audiopolicy/common/include/policy.h
+++ b/services/audiopolicy/common/include/policy.h
@@ -133,6 +133,7 @@
* - AUDIO_SOURCE_FM_TUNER
* - AUDIO_SOURCE_VOICE_RECOGNITION
* - AUDIO_SOURCE_HOTWORD
+ * - AUDIO_SOURCE_ULTRASOUND
*
* @return the corresponding input source priority or 0 if priority is irrelevant for this source.
* This happens when the specified source cannot share a given input stream (e.g remote submix)
@@ -142,22 +143,24 @@
{
switch (inputSource) {
case AUDIO_SOURCE_VOICE_COMMUNICATION:
- return 9;
+ return 10;
case AUDIO_SOURCE_CAMCORDER:
- return 8;
+ return 9;
case AUDIO_SOURCE_VOICE_PERFORMANCE:
- return 7;
+ return 8;
case AUDIO_SOURCE_UNPROCESSED:
- return 6;
+ return 7;
case AUDIO_SOURCE_MIC:
- return 5;
+ return 6;
case AUDIO_SOURCE_ECHO_REFERENCE:
- return 4;
+ return 5;
case AUDIO_SOURCE_FM_TUNER:
- return 3;
+ return 4;
case AUDIO_SOURCE_VOICE_RECOGNITION:
- return 2;
+ return 3;
case AUDIO_SOURCE_HOTWORD:
+ return 2;
+ case AUDIO_SOURCE_ULTRASOUND:
return 1;
default:
break;
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index 235e4aa..999c321 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -569,6 +569,11 @@
audio_output_flags_t halFlags = mFlags;
if ((mFlags & AUDIO_OUTPUT_FLAG_SPATIALIZER) != 0) {
halFlags = (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_FAST | AUDIO_OUTPUT_FLAG_DEEP_BUFFER);
+ // If no mixer config is specified for a spatializer output, default to 5.1 for proper
+ // configuration of the final downmixer or spatializer
+ if (mixerConfig == nullptr) {
+ lMixerConfig.channel_mask = AUDIO_CHANNEL_OUT_5POINT1;
+ }
}
ALOGV("opening output for device %s profile %p name %s",
diff --git a/services/audiopolicy/engine/common/src/EngineDefaultConfig.h b/services/audiopolicy/engine/common/src/EngineDefaultConfig.h
index 665c2dd..b036e12 100644
--- a/services/audiopolicy/engine/common/src/EngineDefaultConfig.h
+++ b/services/audiopolicy/engine/common/src/EngineDefaultConfig.h
@@ -122,8 +122,12 @@
{"STRATEGY_TRANSMITTED_THROUGH_SPEAKER",
{
{"", AUDIO_STREAM_TTS, "AUDIO_STREAM_TTS",
- {{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN, AUDIO_SOURCE_DEFAULT,
- AUDIO_FLAG_BEACON, ""}}
+ {
+ {AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN, AUDIO_SOURCE_DEFAULT,
+ AUDIO_FLAG_BEACON, ""},
+ {AUDIO_CONTENT_TYPE_ULTRASOUND, AUDIO_USAGE_UNKNOWN, AUDIO_SOURCE_DEFAULT,
+ AUDIO_FLAG_NONE, ""}
+ }
}
},
}
diff --git a/services/audiopolicy/engineconfigurable/src/InputSource.cpp b/services/audiopolicy/engineconfigurable/src/InputSource.cpp
index 5779c00..6fd2b70 100644
--- a/services/audiopolicy/engineconfigurable/src/InputSource.cpp
+++ b/services/audiopolicy/engineconfigurable/src/InputSource.cpp
@@ -26,7 +26,8 @@
status_t Element<audio_source_t>::setIdentifier(audio_source_t identifier)
{
if (identifier > AUDIO_SOURCE_MAX && identifier != AUDIO_SOURCE_HOTWORD
- && identifier != AUDIO_SOURCE_FM_TUNER && identifier != AUDIO_SOURCE_ECHO_REFERENCE) {
+ && identifier != AUDIO_SOURCE_FM_TUNER && identifier != AUDIO_SOURCE_ECHO_REFERENCE
+ && identifier != AUDIO_SOURCE_ULTRASOUND) {
return BAD_VALUE;
}
mIdentifier = identifier;
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index 622be7a..4c3d92c 100644
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -460,6 +460,7 @@
case AUDIO_SOURCE_HOTWORD:
case AUDIO_SOURCE_CAMCORDER:
case AUDIO_SOURCE_VOICE_PERFORMANCE:
+ case AUDIO_SOURCE_ULTRASOUND:
inputSource = AUDIO_SOURCE_VOICE_COMMUNICATION;
break;
default:
@@ -586,6 +587,10 @@
device = availableDevices.getDevice(
AUDIO_DEVICE_IN_ECHO_REFERENCE, String8(""), AUDIO_FORMAT_DEFAULT);
break;
+ case AUDIO_SOURCE_ULTRASOUND:
+ device = availableDevices.getFirstExistingDevice({
+ AUDIO_DEVICE_IN_BUILTIN_MIC, AUDIO_DEVICE_IN_BACK_MIC});
+ break;
default:
ALOGW("getDeviceForInputSource() invalid input source %d", inputSource);
break;
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index fc6e05e..92074a6 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1386,8 +1386,14 @@
ALOGV("Set VoIP and Direct output flags for PCM format");
}
+ // Attach the Ultrasound flag for the AUDIO_CONTENT_TYPE_ULTRASOUND
+ if (attr->content_type == AUDIO_CONTENT_TYPE_ULTRASOUND) {
+ *flags = (audio_output_flags_t)(*flags | AUDIO_OUTPUT_FLAG_ULTRASOUND);
+ }
+
if (mSpatializerOutput != nullptr
- && canBeSpatialized(attr, config, devices.toTypeAddrVector())) {
+ && canBeSpatializedInt(attr, config,
+ devices.toTypeAddrVector(), false /* allowCurrentOutputReconfig */)) {
return mSpatializerOutput->mIoHandle;
}
@@ -1683,7 +1689,7 @@
// other criteria
static const audio_output_flags_t kFunctionalFlags = (audio_output_flags_t)
(AUDIO_OUTPUT_FLAG_VOIP_RX | AUDIO_OUTPUT_FLAG_INCALL_MUSIC |
- AUDIO_OUTPUT_FLAG_TTS | AUDIO_OUTPUT_FLAG_DIRECT_PCM);
+ AUDIO_OUTPUT_FLAG_TTS | AUDIO_OUTPUT_FLAG_DIRECT_PCM | AUDIO_OUTPUT_FLAG_ULTRASOUND);
// Flags expressing a performance request: have lower priority than serving
// requested sampling rate or channel mask
static const audio_output_flags_t kPerformanceFlags = (audio_output_flags_t)
@@ -2371,6 +2377,10 @@
flags = (audio_input_flags_t)(flags | AUDIO_INPUT_FLAG_VOIP_TX);
}
+ if (attributes.source == AUDIO_SOURCE_ULTRASOUND) {
+ flags = (audio_input_flags_t)(flags | AUDIO_INPUT_FLAG_ULTRASOUND);
+ }
+
// find a compatible input profile (not necessarily identical in parameters)
sp<IOProfile> profile;
// sampling rate and flags may be updated by getInputProfile
@@ -4949,9 +4959,10 @@
}
}
-bool AudioPolicyManager::canBeSpatialized(const audio_attributes_t *attr,
+bool AudioPolicyManager::canBeSpatializedInt(const audio_attributes_t *attr,
const audio_config_t *config,
- const AudioDeviceTypeAddrVector &devices) const
+ const AudioDeviceTypeAddrVector &devices,
+ bool allowCurrentOutputReconfig) const
{
// The caller can have the audio attributes criteria ignored by either passing a null ptr or
// the AUDIO_ATTRIBUTES_INITIALIZER value.
@@ -4987,7 +4998,8 @@
if (!isChannelMaskSpatialized(config->channel_mask)) {
return false;
}
- if (mSpatializerOutput != nullptr && mSpatializerOutput->mProfile == profile) {
+ if (!allowCurrentOutputReconfig && mSpatializerOutput != nullptr
+ && mSpatializerOutput->mProfile == profile) {
if ((config->channel_mask & mSpatializerOutput->mMixerChannelMask)
!= config->channel_mask) {
return false;
@@ -5008,7 +5020,8 @@
audio_config_base_t clientConfig = client->config();
audio_config_t config = audio_config_initializer(&clientConfig);
if (desc != mSpatializerOutput
- && canBeSpatialized(&attr, &config, devicesTypeAddress)) {
+ && canBeSpatializedInt(&attr, &config,
+ devicesTypeAddress, false /* allowCurrentOutputReconfig */)) {
streamsToInvalidate.insert(client->stream());
}
}
@@ -5032,7 +5045,8 @@
config = audio_config_initializer(mixerConfig);
configPtr = &config;
}
- if (!canBeSpatialized(attr, configPtr, devicesTypeAddress)) {
+ if (!canBeSpatializedInt(
+ attr, configPtr, devicesTypeAddress)) {
ALOGW("%s provided attributes or mixer config cannot be spatialized", __func__);
return BAD_VALUE;
}
@@ -5055,6 +5069,7 @@
for (size_t i = 0; i < mOutputs.size(); i++) {
sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
if (!desc->isDuplicated() && desc->mProfile == profile) {
+ ALOGV("%s found output %d for spatializer profile", __func__, desc->mIoHandle);
mSpatializerOutput = desc;
break;
}
@@ -5074,39 +5089,29 @@
};
DeviceVector savedDevices = mSpatializerOutput->devices();
- closeOutput(mSpatializerOutput->mIoHandle);
- mSpatializerOutput.clear();
+ ALOGV("%s reopening spatializer output to match channel mask %#x (current mask %#x)",
+ __func__, configPtr->channel_mask, mSpatializerOutput->mMixerChannelMask);
- const sp<SwAudioOutputDescriptor> desc =
- new SwAudioOutputDescriptor(profile, mpClientInterface);
- status_t status = desc->open(nullptr, mixerConfig, devices,
- mEngine->getStreamTypeForAttributes(*attr),
- AUDIO_OUTPUT_FLAG_SPATIALIZER, output);
- if (status != NO_ERROR) {
- ALOGW("%s failed opening output: status %d, output %d", __func__, status, *output);
- if (*output != AUDIO_IO_HANDLE_NONE) {
- desc->close();
- }
+ closeOutput(mSpatializerOutput->mIoHandle);
+ //from now on mSpatializerOutput is null
+
+ sp<SwAudioOutputDescriptor> desc =
+ openOutputWithProfileAndDevice(profile, devices, mixerConfig);
+ if (desc == nullptr) {
// re open the spatializer output with previous channel mask
- status_t newStatus = desc->open(nullptr, &savedMixerConfig, savedDevices,
- mEngine->getStreamTypeForAttributes(*attr),
- AUDIO_OUTPUT_FLAG_SPATIALIZER, output);
- if (newStatus != NO_ERROR) {
- if (*output != AUDIO_IO_HANDLE_NONE) {
- desc->close();
- }
- ALOGE("%s failed to re-open mSpatializerOutput, status %d", __func__, newStatus);
+ desc = openOutputWithProfileAndDevice(profile, savedDevices, &savedMixerConfig);
+ if (desc == nullptr) {
+ ALOGE("%s failed to restore mSpatializerOutput with previous config", __func__);
} else {
mSpatializerOutput = desc;
- addOutput(*output, desc);
}
mPreviousOutputs = mOutputs;
mpClientInterface->onAudioPortListUpdate();
*output = AUDIO_IO_HANDLE_NONE;
- return status;
+ ALOGW("%s could not open spatializer output with requested config", __func__);
+ return BAD_VALUE;
}
mSpatializerOutput = desc;
- addOutput(*output, desc);
mPreviousOutputs = mOutputs;
mpClientInterface->onAudioPortListUpdate();
}
@@ -5778,6 +5783,9 @@
removeOutput(output);
mPreviousOutputs = mOutputs;
+ if (closingOutput == mSpatializerOutput) {
+ mSpatializerOutput.clear();
+ }
// MSD patches may have been released to support a non-MSD direct output. Reset MSD patch if
// no direct outputs are open.
@@ -7331,7 +7339,8 @@
}
sp<SwAudioOutputDescriptor> AudioPolicyManager::openOutputWithProfileAndDevice(
- const sp<IOProfile>& profile, const DeviceVector& devices)
+ const sp<IOProfile>& profile, const DeviceVector& devices,
+ const audio_config_base_t *mixerConfig)
{
for (const auto& device : devices) {
// TODO: This should be checking if the profile supports the device combo.
@@ -7341,7 +7350,7 @@
}
sp<SwAudioOutputDescriptor> desc = new SwAudioOutputDescriptor(profile, mpClientInterface);
audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
- status_t status = desc->open(nullptr /* halConfig */, nullptr /* mixerConfig */, devices,
+ status_t status = desc->open(nullptr /* halConfig */, mixerConfig, devices,
AUDIO_STREAM_DEFAULT, AUDIO_OUTPUT_FLAG_NONE, &output);
if (status != NO_ERROR) {
return nullptr;
@@ -7371,7 +7380,7 @@
config.offload_info.channel_mask = config.channel_mask;
config.offload_info.format = config.format;
- status = desc->open(&config, nullptr /* mixerConfig */, devices,
+ status = desc->open(&config, mixerConfig, devices,
AUDIO_STREAM_DEFAULT, AUDIO_OUTPUT_FLAG_NONE, &output);
if (status != NO_ERROR) {
return nullptr;
@@ -7379,6 +7388,7 @@
}
addOutput(output, desc);
+
if (audio_is_remote_submix_device(deviceType) && address != "0") {
sp<AudioPolicyMix> policyMix;
if (mPolicyMixes.getAudioPolicyMix(deviceType, address, policyMix) == NO_ERROR) {
@@ -7389,9 +7399,13 @@
address.string());
}
- } else if (((desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) == 0) && hasPrimaryOutput()) {
- // no duplicated output for direct outputs and
- // outputs used by dynamic policy mixes
+ } else if (hasPrimaryOutput() && profile->getModule()
+ != mHwModules.getModuleFromName(AUDIO_HARDWARE_MODULE_ID_PRIMARY)
+ && ((desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) == 0)) {
+ // no duplicated output for:
+ // - direct outputs
+ // - outputs used by dynamic policy mixes
+ // - outputs opened on the primary HW module
audio_io_handle_t duplicatedOutput = AUDIO_IO_HANDLE_NONE;
//TODO: configure audio effect output stage here
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index bdeba3d..30ca9b3 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -358,7 +358,9 @@
virtual bool canBeSpatialized(const audio_attributes_t *attr,
const audio_config_t *config,
- const AudioDeviceTypeAddrVector &devices) const;
+ const AudioDeviceTypeAddrVector &devices) const {
+ return canBeSpatializedInt(attr, config, devices);
+ }
virtual status_t getSpatializerOutput(const audio_config_base_t *config,
const audio_attributes_t *attr,
@@ -964,6 +966,30 @@
const DeviceVector &devices,
audio_io_handle_t *output);
+ /**
+ * @brief Queries if some kind of spatialization will be performed if the audio playback
+ * context described by the provided arguments is present.
+ * The context is made of:
+ * - The audio attributes describing the playback use case.
+ * - The audio configuration describing the audio format, channels, sampling rate ...
+ * - The devices describing the sink audio device selected for playback.
+ * All arguments are optional and only the specified arguments are used to match against
+ * supported criteria. For instance, supplying no argument will tell if spatialization is
+ * supported or not in general.
+ * @param attr audio attributes describing the playback use case
+ * @param config audio configuration describing the audio format, channels, sample rate...
+ * @param devices the sink audio device selected for playback
+ * @param allowCurrentOutputReconfig if true, the result will be considering it is possible
+ * to close and reopen an existing spatializer output stream to match the requested
+ * criteria. If false, the criteria must be compatible with the opened sptializer
+ * output.
+ * @return true if spatialization is possible for this context, false otherwise.
+ */
+ virtual bool canBeSpatializedInt(const audio_attributes_t *attr,
+ const audio_config_t *config,
+ const AudioDeviceTypeAddrVector &devices,
+ bool allowCurrentOutputReconfig = true) const;
+
sp<IOProfile> getSpatializerOutputProfile(const audio_config_t *config,
const AudioDeviceTypeAddrVector &devices) const;
@@ -1059,8 +1085,20 @@
bool areAllActiveTracksRerouted(const sp<SwAudioOutputDescriptor>& output);
- sp<SwAudioOutputDescriptor> openOutputWithProfileAndDevice(const sp<IOProfile>& profile,
- const DeviceVector& devices);
+ /**
+ * @brief Opens an output stream from the supplied IOProfile and route it to the
+ * supplied audio devices. If a mixer config is specified, it is forwarded to audio
+ * flinger. If not, a default config is derived from the output stream config.
+ * Also opens a duplicating output if needed and queries the audio HAL for supported
+ * audio profiles if the IOProfile is dynamic.
+ * @param[in] profile IOProfile to use as template
+ * @param[in] devices initial route to apply to this output stream
+ * @param[in] mixerConfig if not null, use this to configure the mixer
+ * @return an output descriptor for the newly opened stream or null in case of error.
+ */
+ sp<SwAudioOutputDescriptor> openOutputWithProfileAndDevice(
+ const sp<IOProfile>& profile, const DeviceVector& devices,
+ const audio_config_base_t *mixerConfig = nullptr);
bool isOffloadPossible(const audio_offload_info_t& offloadInfo,
bool durationIgnored = false);
diff --git a/services/audiopolicy/service/AudioPolicyEffects.cpp b/services/audiopolicy/service/AudioPolicyEffects.cpp
index 3f01de9..858a3fd 100644
--- a/services/audiopolicy/service/AudioPolicyEffects.cpp
+++ b/services/audiopolicy/service/AudioPolicyEffects.cpp
@@ -345,7 +345,8 @@
(source > AUDIO_SOURCE_MAX &&
source != AUDIO_SOURCE_HOTWORD &&
source != AUDIO_SOURCE_FM_TUNER &&
- source != AUDIO_SOURCE_ECHO_REFERENCE)) {
+ source != AUDIO_SOURCE_ECHO_REFERENCE &&
+ source != AUDIO_SOURCE_ULTRASOUND)) {
ALOGE("addSourceDefaultEffect(): Unsupported source type %d", source);
return BAD_VALUE;
}
@@ -544,6 +545,7 @@
CAMCORDER_SRC_TAG,
VOICE_REC_SRC_TAG,
VOICE_COMM_SRC_TAG,
+ REMOTE_SUBMIX_SRC_TAG,
UNPROCESSED_SRC_TAG,
VOICE_PERFORMANCE_SRC_TAG
};
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index 8ddd2a4..a30768a 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -376,6 +376,15 @@
attr.flags = static_cast<audio_flags_mask_t>(
attr.flags & ~(AUDIO_FLAG_BYPASS_INTERRUPTION_POLICY|AUDIO_FLAG_BYPASS_MUTE));
}
+
+ if (attr.content_type == AUDIO_CONTENT_TYPE_ULTRASOUND) {
+ if (!accessUltrasoundAllowed(adjAttributionSource)) {
+ ALOGE("%s: permission denied: ultrasound not allowed for uid %d pid %d",
+ __func__, adjAttributionSource.uid, adjAttributionSource.pid);
+ return binderStatusFromStatusT(PERMISSION_DENIED);
+ }
+ }
+
AutoCallerClear acc;
AudioPolicyInterface::output_type_t outputType;
status_t result = mAudioPolicyManager->getOutputForAttr(&attr, &output, session,
@@ -596,7 +605,8 @@
|| (inputSource >= AUDIO_SOURCE_CNT
&& inputSource != AUDIO_SOURCE_HOTWORD
&& inputSource != AUDIO_SOURCE_FM_TUNER
- && inputSource != AUDIO_SOURCE_ECHO_REFERENCE)) {
+ && inputSource != AUDIO_SOURCE_ECHO_REFERENCE
+ && inputSource != AUDIO_SOURCE_ULTRASOUND)) {
return binderStatusFromStatusT(BAD_VALUE);
}
@@ -677,6 +687,14 @@
return binderStatusFromStatusT(PERMISSION_DENIED);
}
+ if (attr.source == AUDIO_SOURCE_ULTRASOUND) {
+ if (!accessUltrasoundAllowed(adjAttributionSource)) {
+ ALOGE("%s: permission denied: ultrasound not allowed for uid %d pid %d",
+ __func__, adjAttributionSource.uid, adjAttributionSource.pid);
+ return binderStatusFromStatusT(PERMISSION_DENIED);
+ }
+ }
+
sp<AudioPolicyEffects>audioPolicyEffects;
{
status_t status;
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index ef7a83b..8add137 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -392,7 +392,8 @@
audio_config_base_t config = mSpatializer->getAudioInConfig();
status_t status =
mAudioPolicyManager->getSpatializerOutput(&config, &attr, &newOutput);
-
+ ALOGV("%s currentOutput %d newOutput %d channel_mask %#x",
+ __func__, currentOutput, newOutput, config.channel_mask);
if (status == NO_ERROR && currentOutput == newOutput) {
return;
}
diff --git a/services/audiopolicy/service/Spatializer.cpp b/services/audiopolicy/service/Spatializer.cpp
index 0fdbe20..54d9094 100644
--- a/services/audiopolicy/service/Spatializer.cpp
+++ b/services/audiopolicy/service/Spatializer.cpp
@@ -227,12 +227,8 @@
if (status != NO_ERROR) {
return status;
}
- status = getHalParameter<true>(effect, SPATIALIZER_PARAM_SUPPORTED_CHANNEL_MASKS,
+ return getHalParameter<true>(effect, SPATIALIZER_PARAM_SUPPORTED_CHANNEL_MASKS,
&mChannelMasks);
- if (status != NO_ERROR) {
- return status;
- }
- return NO_ERROR;
}
/** Gets the channel mask, sampling rate and format set for the spatializer input. */
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index a593500..97ec5d1 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -2335,6 +2335,13 @@
doUserSwitch(/*newUserIds*/ args);
break;
}
+ case ICameraService::EVENT_USB_DEVICE_ATTACHED:
+ case ICameraService::EVENT_USB_DEVICE_DETACHED: {
+ // Notify CameraProviderManager for lazy HALs
+ mCameraProviderManager->notifyUsbDeviceEvent(eventId,
+ std::to_string(args[0]));
+ break;
+ }
case ICameraService::EVENT_NONE:
default: {
ALOGW("%s: Received invalid system event from system_server: %d", __FUNCTION__,
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index 5e8d188..9831328 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -53,6 +53,7 @@
namespace {
const bool kEnableLazyHal(property_get_bool("ro.camera.enableLazyHal", false));
+const std::string kExternalProviderName = "external/0";
} // anonymous namespace
const float CameraProviderManager::kDepthARTolerance = .1f;
@@ -395,6 +396,73 @@
return OK;
}
+sp<CameraProviderManager::ProviderInfo> CameraProviderManager::startExternalLazyProvider() const {
+ std::lock_guard<std::mutex> providerLock(mProviderLifecycleLock);
+ std::lock_guard<std::mutex> lock(mInterfaceMutex);
+
+ for (const auto& providerInfo : mProviders) {
+ if (providerInfo->isExternalLazyHAL()) {
+ const sp<provider::V2_4::ICameraProvider>
+ interface = providerInfo->startProviderInterface();
+ if (interface == nullptr) {
+ return nullptr;
+ } else {
+ return providerInfo;
+ }
+ }
+ }
+ return nullptr;
+}
+
+status_t CameraProviderManager::notifyUsbDeviceEvent(int32_t eventId,
+ const std::string& usbDeviceId) {
+ if (!kEnableLazyHal) {
+ return OK;
+ }
+
+ ALOGV("notifySystemEvent: %d usbDeviceId : %s", eventId, usbDeviceId.c_str());
+
+ if (eventId == android::hardware::ICameraService::EVENT_USB_DEVICE_ATTACHED) {
+ sp<ProviderInfo> externalProvider = startExternalLazyProvider();
+ if (externalProvider != nullptr) {
+ auto usbDevices = mExternalUsbDevicesForProvider.first;
+ usbDevices.push_back(usbDeviceId);
+ mExternalUsbDevicesForProvider = {usbDevices, externalProvider};
+ }
+ } else if (eventId
+ == android::hardware::ICameraService::EVENT_USB_DEVICE_DETACHED) {
+ usbDeviceDetached(usbDeviceId);
+ }
+
+ return OK;
+}
+
+status_t CameraProviderManager::usbDeviceDetached(const std::string &usbDeviceId) {
+ std::lock_guard<std::mutex> providerLock(mProviderLifecycleLock);
+ std::lock_guard<std::mutex> interfaceLock(mInterfaceMutex);
+
+ auto usbDevices = mExternalUsbDevicesForProvider.first;
+ auto foundId = std::find(usbDevices.begin(), usbDevices.end(), usbDeviceId);
+ if (foundId != usbDevices.end()) {
+ sp<ProviderInfo> providerInfo = mExternalUsbDevicesForProvider.second;
+ if (providerInfo == nullptr) {
+ ALOGE("%s No valid external provider for USB device: %s",
+ __FUNCTION__,
+ usbDeviceId.c_str());
+ mExternalUsbDevicesForProvider = {std::vector<std::string>(), nullptr};
+ return DEAD_OBJECT;
+ } else {
+ mInterfaceMutex.unlock();
+ providerInfo->removeAllDevices();
+ mInterfaceMutex.lock();
+ mExternalUsbDevicesForProvider = {std::vector<std::string>(), nullptr};
+ }
+ } else {
+ return DEAD_OBJECT;
+ }
+ return OK;
+}
+
status_t CameraProviderManager::notifyDeviceStateChange(
hardware::hidl_bitfield<provider::V2_5::DeviceState> newState) {
std::lock_guard<std::mutex> lock(mInterfaceMutex);
@@ -1314,9 +1382,10 @@
if (providerInfo->mProviderName == newProvider) {
ALOGW("%s: Camera provider HAL with name '%s' already registered",
__FUNCTION__, newProvider.c_str());
- if (preexisting) {
+ // Do not add new instances for lazy HAL external provider
+ if (preexisting || providerInfo->isExternalLazyHAL()) {
return ALREADY_EXISTS;
- } else{
+ } else {
ALOGW("%s: The new provider instance will get initialized immediately after the"
" currently present instance is removed!", __FUNCTION__);
providerPresent = true;
@@ -1606,36 +1675,56 @@
auto interface = mActiveInterface.promote();
if (interface == nullptr) {
- ALOGI("Camera HAL provider needs restart, calling getService(%s)", mProviderName.c_str());
- interface = mManager->mServiceProxy->getService(mProviderName);
- interface->setCallback(this);
- hardware::Return<bool> linked = interface->linkToDeath(this, /*cookie*/ mId);
- if (!linked.isOk()) {
- ALOGE("%s: Transaction error in linking to camera provider '%s' death: %s",
- __FUNCTION__, mProviderName.c_str(), linked.description().c_str());
- mManager->removeProvider(mProviderName);
- return nullptr;
- } else if (!linked) {
- ALOGW("%s: Unable to link to provider '%s' death notifications",
+ // Try to get service without starting
+ interface = mManager->mServiceProxy->tryGetService(mProviderName);
+ if (interface == nullptr) {
+ ALOGV("Camera provider actually needs restart, calling getService(%s)",
+ mProviderName.c_str());
+ interface = mManager->mServiceProxy->getService(mProviderName);
+
+ // Set all devices as ENUMERATING, provider should update status
+ // to PRESENT after initializing.
+ // This avoids failing getCameraDeviceInterface_V3_x before devices
+ // are ready.
+ for (auto& device : mDevices) {
+ device->mIsDeviceAvailable = false;
+ }
+
+ interface->setCallback(this);
+ hardware::Return<bool>
+ linked = interface->linkToDeath(this, /*cookie*/ mId);
+ if (!linked.isOk()) {
+ ALOGE(
+ "%s: Transaction error in linking to camera provider '%s' death: %s",
+ __FUNCTION__,
+ mProviderName.c_str(),
+ linked.description().c_str());
+ mManager->removeProvider(mProviderName);
+ return nullptr;
+ } else if (!linked) {
+ ALOGW("%s: Unable to link to provider '%s' death notifications",
__FUNCTION__, mProviderName.c_str());
- }
- // Send current device state
- if (mMinorVersion >= 5) {
- auto castResult = provider::V2_5::ICameraProvider::castFrom(interface);
- if (castResult.isOk()) {
+ }
+ // Send current device state
+ if (mMinorVersion >= 5) {
+ auto castResult =
+ provider::V2_5::ICameraProvider::castFrom(interface);
+ if (castResult.isOk()) {
sp<provider::V2_5::ICameraProvider> interface_2_5 = castResult;
if (interface_2_5 != nullptr) {
- ALOGV("%s: Initial device state for %s: 0x %" PRIx64,
- __FUNCTION__, mProviderName.c_str(), mDeviceState);
- interface_2_5->notifyDeviceStateChange(mDeviceState);
+ ALOGV("%s: Initial device state for %s: 0x %" PRIx64,
+ __FUNCTION__, mProviderName.c_str(), mDeviceState);
+ interface_2_5->notifyDeviceStateChange(mDeviceState);
}
+ }
}
}
-
mActiveInterface = interface;
} else {
- ALOGV("Camera provider (%s) already in use. Re-using instance.", mProviderName.c_str());
+ ALOGV("Camera provider (%s) already in use. Re-using instance.",
+ mProviderName.c_str());
}
+
return interface;
}
@@ -1710,15 +1799,50 @@
mUniqueCameraIds.erase(id);
if ((*it)->isAPI1Compatible()) {
mUniqueAPI1CompatibleCameraIds.erase(std::remove(
- mUniqueAPI1CompatibleCameraIds.begin(),
- mUniqueAPI1CompatibleCameraIds.end(), id));
+ mUniqueAPI1CompatibleCameraIds.begin(),
+ mUniqueAPI1CompatibleCameraIds.end(), id));
}
+
+ // Remove reference to camera provider to avoid pointer leak when
+ // unplugging external camera while in use with lazy HALs
+ mManager->removeRef(DeviceMode::CAMERA, id);
+ mManager->removeRef(DeviceMode::TORCH, id);
+
mDevices.erase(it);
break;
}
}
}
+void CameraProviderManager::ProviderInfo::removeAllDevices() {
+ std::lock_guard<std::mutex> lock(mLock);
+
+ auto itDevices = mDevices.begin();
+ while (itDevices != mDevices.end()) {
+ std::string id = (*itDevices)->mId;
+ std::string deviceName = (*itDevices)->mName;
+ removeDevice(id);
+ // device was removed, reset iterator
+ itDevices = mDevices.begin();
+
+ //notify CameraService of status change
+ sp<StatusListener> listener = mManager->getStatusListener();
+ if (listener != nullptr) {
+ mLock.unlock();
+ ALOGV("%s: notify device not_present: %s",
+ __FUNCTION__,
+ deviceName.c_str());
+ listener->onDeviceStatusChanged(String8(id.c_str()),
+ CameraDeviceStatus::NOT_PRESENT);
+ mLock.lock();
+ }
+ }
+}
+
+bool CameraProviderManager::ProviderInfo::isExternalLazyHAL() const {
+ return kEnableLazyHal && (mProviderName == kExternalProviderName);
+}
+
status_t CameraProviderManager::ProviderInfo::dump(int fd, const Vector<String16>&) const {
dprintf(fd, "== Camera Provider HAL %s (v2.%d, %s) static info: %zu devices: ==\n",
mProviderInstance.c_str(),
@@ -1898,12 +2022,16 @@
std::string cameraId;
for (auto& deviceInfo : mDevices) {
if (deviceInfo->mName == cameraDeviceName) {
+ Mutex::Autolock l(deviceInfo->mDeviceAvailableLock);
ALOGI("Camera device %s status is now %s, was %s", cameraDeviceName.c_str(),
deviceStatusToString(newStatus), deviceStatusToString(deviceInfo->mStatus));
deviceInfo->mStatus = newStatus;
// TODO: Handle device removal (NOT_PRESENT)
cameraId = deviceInfo->mId;
known = true;
+ deviceInfo->mIsDeviceAvailable =
+ (newStatus == CameraDeviceStatus::PRESENT);
+ deviceInfo->mDeviceAvailableSignal.signal();
break;
}
}
@@ -1917,6 +2045,11 @@
addDevice(cameraDeviceName, newStatus, &cameraId);
} else if (newStatus == CameraDeviceStatus::NOT_PRESENT) {
removeDevice(cameraId);
+ } else if (isExternalLazyHAL()) {
+ // Do not notify CameraService for PRESENT->PRESENT (lazy HAL restart)
+ // because NOT_AVAILABLE is set on CameraService::connect and a PRESENT
+ // notif. would overwrite it
+ return BAD_VALUE;
}
if (reCacheConcurrentStreamingCameraIdsLocked() != OK) {
ALOGE("%s: CameraProvider %s could not re-cache concurrent streaming camera id list ",
@@ -2297,11 +2430,27 @@
template<class InterfaceT>
sp<InterfaceT> CameraProviderManager::ProviderInfo::DeviceInfo::startDeviceInterface() {
+ Mutex::Autolock l(mDeviceAvailableLock);
sp<InterfaceT> device;
ATRACE_CALL();
if (mSavedInterface == nullptr) {
sp<ProviderInfo> parentProvider = mParentProvider.promote();
if (parentProvider != nullptr) {
+ // Wait for lazy HALs to confirm device availability
+ if (parentProvider->isExternalLazyHAL() && !mIsDeviceAvailable) {
+ ALOGV("%s: Wait for external device to become available %s",
+ __FUNCTION__,
+ mId.c_str());
+
+ auto res = mDeviceAvailableSignal.waitRelative(mDeviceAvailableLock,
+ kDeviceAvailableTimeout);
+ if (res != OK) {
+ ALOGE("%s: Failed waiting for device to become available",
+ __FUNCTION__);
+ return nullptr;
+ }
+ }
+
device = parentProvider->startDeviceInterface<InterfaceT>(mName);
}
} else {
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.h b/services/camera/libcameraservice/common/CameraProviderManager.h
index 891c8b1..ac710bf 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.h
+++ b/services/camera/libcameraservice/common/CameraProviderManager.h
@@ -29,7 +29,9 @@
#include <camera/CameraParameters2.h>
#include <camera/CameraMetadata.h>
#include <camera/CameraBase.h>
+#include <utils/Condition.h>
#include <utils/Errors.h>
+#include <android/hardware/ICameraService.h>
#include <android/hardware/camera/common/1.0/types.h>
#include <android/hardware/camera/provider/2.5/ICameraProvider.h>
#include <android/hardware/camera/provider/2.6/ICameraProviderCallback.h>
@@ -358,6 +360,8 @@
status_t filterSmallJpegSizes(const std::string& cameraId);
+ status_t notifyUsbDeviceEvent(int32_t eventId, const std::string &usbDeviceId);
+
static const float kDepthARTolerance;
private:
// All private members, unless otherwise noted, expect mInterfaceMutex to be locked before use
@@ -488,6 +492,17 @@
&halCameraIdsAndStreamCombinations,
bool *isSupported);
+ /**
+ * Remove all devices associated with this provider and notify listeners
+ * with NOT_PRESENT state.
+ */
+ void removeAllDevices();
+
+ /**
+ * Provider is an external lazy HAL
+ */
+ bool isExternalLazyHAL() const;
+
// Basic device information, common to all camera devices
struct DeviceInfo {
const std::string mName; // Full instance name
@@ -511,6 +526,12 @@
int32_t mTorchMaximumStrengthLevel;
int32_t mTorchDefaultStrengthLevel;
+ // Wait for lazy HALs to confirm device availability
+ static const nsecs_t kDeviceAvailableTimeout = 2000e6; // 2000 ms
+ Mutex mDeviceAvailableLock;
+ Condition mDeviceAvailableSignal;
+ bool mIsDeviceAvailable = true;
+
bool hasFlashUnit() const { return mHasFlashUnit; }
bool supportNativeZoomRatio() const { return mSupportNativeZoomRatio; }
virtual status_t setTorchMode(bool enabled) = 0;
@@ -735,6 +756,12 @@
hardware::hidl_version minVersion = hardware::hidl_version{0,0},
hardware::hidl_version maxVersion = hardware::hidl_version{1000,0}) const;
+ // Map external providers to USB devices in order to handle USB hotplug
+ // events for lazy HALs
+ std::pair<std::vector<std::string>, sp<ProviderInfo>>
+ mExternalUsbDevicesForProvider;
+ sp<ProviderInfo> startExternalLazyProvider() const;
+
status_t addProviderLocked(const std::string& newProvider, bool preexisting = false);
status_t tryToInitializeProviderLocked(const std::string& providerName,
@@ -782,6 +809,8 @@
hardware::hidl_vec<hardware::camera::provider::V2_7::CameraIdAndStreamCombination>
*halCameraIdsAndStreamCombinations,
bool *earlyExit);
+
+ status_t usbDeviceDetached(const std::string &usbDeviceId);
};
} // namespace android
diff --git a/services/camera/libcameraservice/utils/SessionConfigurationUtils.h b/services/camera/libcameraservice/utils/SessionConfigurationUtils.h
index c05b59b..9a5dc2c 100644
--- a/services/camera/libcameraservice/utils/SessionConfigurationUtils.h
+++ b/services/camera/libcameraservice/utils/SessionConfigurationUtils.h
@@ -138,8 +138,8 @@
// V3_7::StreamConfiguration. Return false if the original V3_8 configuration cannot
// be used by older version HAL.
bool convertHALStreamCombinationFromV38ToV37(
- hardware::camera::device::V3_7::StreamConfiguration &streamConfigV34,
- const hardware::camera::device::V3_8::StreamConfiguration &streamConfigV37);
+ hardware::camera::device::V3_7::StreamConfiguration &streamConfigV37,
+ const hardware::camera::device::V3_8::StreamConfiguration &streamConfigV38);
// Utility function to convert a V3_7::StreamConfiguration to
// V3_4::StreamConfiguration. Return false if the original V3_7 configuration cannot
diff --git a/services/tuner/TunerFrontend.cpp b/services/tuner/TunerFrontend.cpp
index a5ef2bb..0340573 100644
--- a/services/tuner/TunerFrontend.cpp
+++ b/services/tuner/TunerFrontend.cpp
@@ -174,6 +174,16 @@
return mFrontend->getHardwareInfo(_aidl_return);
}
+::ndk::ScopedAStatus TunerFrontend::removeOutputPid(int32_t in_pid) {
+ if (mFrontend == nullptr) {
+ ALOGD("IFrontend is not initialized");
+ return ::ndk::ScopedAStatus::fromServiceSpecificError(
+ static_cast<int32_t>(Result::UNAVAILABLE));
+ }
+
+ return mFrontend->removeOutputPid(in_pid);
+}
+
/////////////// FrontendCallback ///////////////////////
::ndk::ScopedAStatus TunerFrontend::FrontendCallback::onEvent(FrontendEventType frontendEventType) {
ALOGV("FrontendCallback::onEvent, type=%d", frontendEventType);
diff --git a/services/tuner/TunerFrontend.h b/services/tuner/TunerFrontend.h
index 418a751..a96099e 100644
--- a/services/tuner/TunerFrontend.h
+++ b/services/tuner/TunerFrontend.h
@@ -63,6 +63,7 @@
vector<FrontendStatus>* _aidl_return) override;
::ndk::ScopedAStatus getFrontendId(int32_t* _aidl_return) override;
::ndk::ScopedAStatus getHardwareInfo(std::string* _aidl_return) override;
+ ::ndk::ScopedAStatus removeOutputPid(int32_t in_pid) override;
struct FrontendCallback : public BnFrontendCallback {
FrontendCallback(const shared_ptr<ITunerFrontendCallback> tunerFrontendCallback)
diff --git a/services/tuner/aidl/android/media/tv/tuner/ITunerFrontend.aidl b/services/tuner/aidl/android/media/tv/tuner/ITunerFrontend.aidl
index 96f285f..2887d80 100644
--- a/services/tuner/aidl/android/media/tv/tuner/ITunerFrontend.aidl
+++ b/services/tuner/aidl/android/media/tv/tuner/ITunerFrontend.aidl
@@ -99,4 +99,9 @@
* Request hardware information about the frontend.
*/
String getHardwareInfo();
+
+ /**
+ * Filter out unnecessary PID from frontend output.
+ */
+ void removeOutputPid(int pid);
}
diff --git a/services/tuner/hidl/TunerHidlFrontend.cpp b/services/tuner/hidl/TunerHidlFrontend.cpp
index 057f24a..9733063 100644
--- a/services/tuner/hidl/TunerHidlFrontend.cpp
+++ b/services/tuner/hidl/TunerHidlFrontend.cpp
@@ -428,6 +428,11 @@
static_cast<int32_t>(Result::UNAVAILABLE));
}
+::ndk::ScopedAStatus TunerHidlFrontend::removeOutputPid(int32_t /* in_pid */) {
+ return ::ndk::ScopedAStatus::fromServiceSpecificError(
+ static_cast<int32_t>(Result::UNAVAILABLE));
+}
+
void TunerHidlFrontend::setLna(bool bEnable) {
if (mFrontend == nullptr) {
ALOGD("IFrontend is not initialized");
diff --git a/services/tuner/hidl/TunerHidlFrontend.h b/services/tuner/hidl/TunerHidlFrontend.h
index 7ff278c..95d2c1a 100644
--- a/services/tuner/hidl/TunerHidlFrontend.h
+++ b/services/tuner/hidl/TunerHidlFrontend.h
@@ -83,6 +83,7 @@
vector<FrontendStatus>* _aidl_return) override;
::ndk::ScopedAStatus getFrontendId(int32_t* _aidl_return) override;
::ndk::ScopedAStatus getHardwareInfo(std::string* _aidl_return) override;
+ ::ndk::ScopedAStatus removeOutputPid(int32_t in_pid) override;
void setLna(bool in_bEnable);