Merge "libeffects: Added sample testbench for downmix module"
diff --git a/camera/aidl/android/hardware/ICameraService.aidl b/camera/aidl/android/hardware/ICameraService.aidl
index c038314..0e969c7 100644
--- a/camera/aidl/android/hardware/ICameraService.aidl
+++ b/camera/aidl/android/hardware/ICameraService.aidl
@@ -162,6 +162,28 @@
* Callers require the android.permission.CAMERA_SEND_SYSTEM_EVENTS permission.
*/
const int EVENT_NONE = 0;
- const int EVENT_USER_SWITCHED = 1;
+ const int EVENT_USER_SWITCHED = 1; // The argument is the set of new foreground user IDs.
oneway void notifySystemEvent(int eventId, in int[] args);
+
+ /**
+ * Notify the camera service of a device physical status change. May only be called from
+ * a privileged process.
+ *
+ * newState is a bitfield consisting of DEVICE_STATE_* values combined together. Valid state
+ * combinations are device-specific. At device startup, the camera service will assume the device
+ * state is NORMAL until otherwise notified.
+ *
+ * Callers require the android.permission.CAMERA_SEND_SYSTEM_EVENTS permission.
+ */
+ oneway void notifyDeviceStateChange(long newState);
+
+ // Bitfield constants for notifyDeviceStateChange
+ // All bits >= 32 are for custom vendor states
+ // Written as ints since AIDL does not support long constants.
+ const int DEVICE_STATE_NORMAL = 0;
+ const int DEVICE_STATE_BACK_COVERED = 1;
+ const int DEVICE_STATE_FRONT_COVERED = 2;
+ const int DEVICE_STATE_FOLDED = 4;
+ const int DEVICE_STATE_LAST_FRAMEWORK_BIT = 0x80000000; // 1 << 31;
+
}
diff --git a/camera/cameraserver/Android.bp b/camera/cameraserver/Android.bp
index b88a2c5..92b06c2 100644
--- a/camera/cameraserver/Android.bp
+++ b/camera/cameraserver/Android.bp
@@ -27,6 +27,7 @@
"libhidltransport",
"android.hardware.camera.common@1.0",
"android.hardware.camera.provider@2.4",
+ "android.hardware.camera.provider@2.5",
"android.hardware.camera.device@1.0",
"android.hardware.camera.device@3.2",
"android.hardware.camera.device@3.4",
diff --git a/media/codec2/core/include/C2Config.h b/media/codec2/core/include/C2Config.h
index 0357115..fb6edb6 100644
--- a/media/codec2/core/include/C2Config.h
+++ b/media/codec2/core/include/C2Config.h
@@ -597,6 +597,9 @@
LEVEL_AVC_5, ///< AVC (H.264) Level 5
LEVEL_AVC_5_1, ///< AVC (H.264) Level 5.1
LEVEL_AVC_5_2, ///< AVC (H.264) Level 5.2
+ LEVEL_AVC_6, ///< AVC (H.264) Level 6
+ LEVEL_AVC_6_1, ///< AVC (H.264) Level 6.1
+ LEVEL_AVC_6_2, ///< AVC (H.264) Level 6.2
// HEVC (H.265) tiers and levels
LEVEL_HEVC_MAIN_1 = _C2_PL_HEVC_BASE, ///< HEVC (H.265) Main Tier Level 1
diff --git a/media/codec2/hidl/1.0/utils/Configurable.cpp b/media/codec2/hidl/1.0/utils/Configurable.cpp
index a35b74c..ec9c170 100644
--- a/media/codec2/hidl/1.0/utils/Configurable.cpp
+++ b/media/codec2/hidl/1.0/utils/Configurable.cpp
@@ -171,17 +171,15 @@
c2fields,
mayBlock ? C2_MAY_BLOCK : C2_DONT_BLOCK);
hidl_vec<FieldSupportedValuesQueryResult> outFields(inFields.size());
- {
- size_t ix = 0;
- for (const C2FieldSupportedValuesQuery &result : c2fields) {
- if (!objcpy(&outFields[ix], result)) {
- ++ix;
- } else {
- outFields.resize(ix);
- c2res = C2_CORRUPTED;
- LOG(WARNING) << "querySupportedValues -- invalid output params.";
- break;
- }
+ size_t dstIx = 0;
+ for (const C2FieldSupportedValuesQuery &result : c2fields) {
+ if (objcpy(&outFields[dstIx], result)) {
+ ++dstIx;
+ } else {
+ outFields.resize(dstIx);
+ c2res = C2_CORRUPTED;
+ LOG(WARNING) << "querySupportedValues -- invalid output params.";
+ break;
}
}
_hidl_cb((Status)c2res, outFields);
diff --git a/media/codec2/sfplugin/SkipCutBuffer.cpp b/media/codec2/sfplugin/SkipCutBuffer.cpp
index 5762440..8d1de65 100644
--- a/media/codec2/sfplugin/SkipCutBuffer.cpp
+++ b/media/codec2/sfplugin/SkipCutBuffer.cpp
@@ -20,7 +20,7 @@
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/SkipCutBuffer.h>
+#include "SkipCutBuffer.h"
namespace android {
diff --git a/media/codec2/sfplugin/utils/Codec2Mapper.cpp b/media/codec2/sfplugin/utils/Codec2Mapper.cpp
index c369e16..0a6a717 100644
--- a/media/codec2/sfplugin/utils/Codec2Mapper.cpp
+++ b/media/codec2/sfplugin/utils/Codec2Mapper.cpp
@@ -65,7 +65,9 @@
{ C2Config::LEVEL_AVC_5, AVCLevel5 },
{ C2Config::LEVEL_AVC_5_1, AVCLevel51 },
{ C2Config::LEVEL_AVC_5_2, AVCLevel52 },
-
+ { C2Config::LEVEL_AVC_6, AVCLevel6 },
+ { C2Config::LEVEL_AVC_6_1, AVCLevel61 },
+ { C2Config::LEVEL_AVC_6_2, AVCLevel62 },
};
ALookup<C2Config::profile_t, int32_t> sAvcProfiles = {
diff --git a/media/codec2/vndk/C2Config.cpp b/media/codec2/vndk/C2Config.cpp
index 8a27088..34680a7 100644
--- a/media/codec2/vndk/C2Config.cpp
+++ b/media/codec2/vndk/C2Config.cpp
@@ -186,6 +186,9 @@
{ "avc-5", C2Config::LEVEL_AVC_5 },
{ "avc-5.1", C2Config::LEVEL_AVC_5_1 },
{ "avc-5.2", C2Config::LEVEL_AVC_5_2 },
+ { "avc-6", C2Config::LEVEL_AVC_6 },
+ { "avc-6.1", C2Config::LEVEL_AVC_6_1 },
+ { "avc-6.2", C2Config::LEVEL_AVC_6_2 },
{ "hevc-main-1", C2Config::LEVEL_HEVC_MAIN_1 },
{ "hevc-main-2", C2Config::LEVEL_HEVC_MAIN_2 },
{ "hevc-main-2.1", C2Config::LEVEL_HEVC_MAIN_2_1 },
diff --git a/media/extractors/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
index ac54116..0243c03 100755
--- a/media/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/extractors/mp4/MPEG4Extractor.cpp
@@ -6214,6 +6214,7 @@
static const char *extensions[] = {
"3g2",
+ "3ga",
"3gp",
"3gpp",
"3gpp2",
@@ -6222,6 +6223,7 @@
"m4v",
"mov",
"mp4",
+ "qt",
NULL
};
diff --git a/media/extractors/ogg/OggExtractor.cpp b/media/extractors/ogg/OggExtractor.cpp
index ba40690..cb5f173 100644
--- a/media/extractors/ogg/OggExtractor.cpp
+++ b/media/extractors/ogg/OggExtractor.cpp
@@ -364,7 +364,13 @@
return OK;
}
- ++*pageOffset;
+ // see how far ahead to skip; avoid some fruitless comparisons
+ unsigned int i;
+ for (i = 1; i < 4 ; i++) {
+ if (signature[i] == 'O')
+ break;
+ }
+ *pageOffset += i;
}
}
diff --git a/media/libaaudio/examples/loopback/src/loopback.cpp b/media/libaaudio/examples/loopback/src/loopback.cpp
index 75d425f..6578156 100644
--- a/media/libaaudio/examples/loopback/src/loopback.cpp
+++ b/media/libaaudio/examples/loopback/src/loopback.cpp
@@ -36,8 +36,11 @@
#include "LoopbackAnalyzer.h"
#include "../../utils/AAudioExampleUtils.h"
-// V0.4.00 = rectify and low-pass filter the echos, use auto-correlation on entire echo
-#define APP_VERSION "0.4.00"
+// V0.4.00 = rectify and low-pass filter the echos, auto-correlate entire echo
+// V0.4.01 = add -h hang option
+// fix -n option to set output buffer for -tm
+// plot first glitch
+#define APP_VERSION "0.4.01"
// Tag for machine readable results as property = value pairs
#define RESULT_TAG "RESULT: "
@@ -396,7 +399,7 @@
int32_t requestedInputCapacity = AAUDIO_UNSPECIFIED;
aaudio_performance_mode_t inputPerformanceLevel = AAUDIO_PERFORMANCE_MODE_LOW_LATENCY;
- int32_t outputFramesPerBurst = 0;
+ int32_t outputFramesPerBurst = 0;
aaudio_format_t actualOutputFormat = AAUDIO_FORMAT_INVALID;
int32_t actualSampleRate = 0;
@@ -476,6 +479,8 @@
int32_t timeMillis = 0;
int32_t recordingDuration = std::min(60 * 5, requestedDuration);
+ int32_t requestedOutputBursts = argParser.getNumberOfBursts();
+
switch(testMode) {
case TEST_SINE_MAGNITUDE:
loopbackData.loopbackProcessor = &loopbackData.sineAnalyzer;
@@ -541,20 +546,19 @@
}
inputStream = loopbackData.inputStream = recorder.getStream();
- argParser.compareWithStream(inputStream);
-
{
int32_t actualCapacity = AAudioStream_getBufferCapacityInFrames(inputStream);
(void) AAudioStream_setBufferSizeInFrames(inputStream, actualCapacity);
- if (testMode == TEST_SINE_MAGNITUDE) {
+ if (testMode == TEST_SINE_MAGNITUDE
+ && requestedOutputBursts == AAUDIO_UNSPECIFIED) {
result = AAudioStream_setBufferSizeInFrames(outputStream, actualCapacity);
if (result < 0) {
fprintf(stderr, "ERROR - AAudioStream_setBufferSizeInFrames(output) returned %d\n",
result);
goto finish;
} else {
- printf("Output buffer size set to match input capacity = %d frames.\n", result);
+ printf("Output buffer size set to match input capacity = %d frames!\n", result);
}
}
@@ -565,6 +569,8 @@
}
}
+ argParser.compareWithStream(inputStream);
+
// ------- Setup loopbackData -----------------------------
loopbackData.actualInputFormat = AAudioStream_getFormat(inputStream);
diff --git a/media/libaaudio/examples/utils/AAudioSimplePlayer.h b/media/libaaudio/examples/utils/AAudioSimplePlayer.h
index 1645986..4373fa9 100644
--- a/media/libaaudio/examples/utils/AAudioSimplePlayer.h
+++ b/media/libaaudio/examples/utils/AAudioSimplePlayer.h
@@ -32,8 +32,6 @@
// Arbitrary period for glitches
#define FORCED_UNDERRUN_PERIOD_FRAMES (2 * 48000)
-// How long to sleep in a callback to cause an intentional glitch. For testing.
-#define FORCED_UNDERRUN_SLEEP_MICROS (10 * 1000)
#define MAX_TIMESTAMPS 16
@@ -275,7 +273,7 @@
int scheduler = 0;
bool schedulerChecked = false;
- bool forceUnderruns = false;
+ int32_t hangTimeMSec = 0;
AAudioSimplePlayer simplePlayer;
int32_t callbackCount = 0;
@@ -327,10 +325,12 @@
sineData->setupSineSweeps();
}
- if (sineData->forceUnderruns) {
+ if (sineData->hangTimeMSec > 0) {
if (sineData->framesTotal > sineData->nextFrameToGlitch) {
- usleep(FORCED_UNDERRUN_SLEEP_MICROS);
- printf("Simulate glitch at %lld\n", (long long) sineData->framesTotal);
+ usleep(sineData->hangTimeMSec * 1000);
+ printf("Hang callback at %lld frames for %d msec\n",
+ (long long) sineData->framesTotal,
+ sineData->hangTimeMSec);
sineData->nextFrameToGlitch += FORCED_UNDERRUN_PERIOD_FRAMES;
}
}
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 7a48153..2b05f10 100644
--- a/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
+++ b/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
@@ -26,11 +26,14 @@
#include <string.h>
#include <time.h>
#include <aaudio/AAudio.h>
+
#include "AAudioExampleUtils.h"
#include "AAudioSimplePlayer.h"
#include "AAudioArgsParser.h"
-#define APP_VERSION "0.1.5"
+#define APP_VERSION "0.1.6"
+
+constexpr int32_t kDefaultHangTimeMSec = 10;
/**
* Open stream, play some sine waves, then close the stream.
@@ -41,7 +44,7 @@
static aaudio_result_t testOpenPlayClose(AAudioArgsParser &argParser,
int32_t loopCount,
int32_t prefixToneMsec,
- bool forceUnderruns)
+ int32_t hangTimeMSec)
{
SineThreadedData_t myData;
AAudioSimplePlayer &player = myData.simplePlayer;
@@ -53,10 +56,12 @@
printf("----------------------- run complete test --------------------------\n");
myData.schedulerChecked = false;
myData.callbackCount = 0;
- myData.forceUnderruns = forceUnderruns; // test AAudioStream_getXRunCount()
+ myData.hangTimeMSec = hangTimeMSec; // test AAudioStream_getXRunCount()
result = player.open(argParser,
- SimplePlayerDataCallbackProc, SimplePlayerErrorCallbackProc, &myData);
+ SimplePlayerDataCallbackProc,
+ SimplePlayerErrorCallbackProc,
+ &myData);
if (result != AAUDIO_OK) {
fprintf(stderr, "ERROR - player.open() returned %s\n",
AAudio_convertResultToText(result));
@@ -115,12 +120,17 @@
int64_t millis =
(getNanoseconds(CLOCK_MONOTONIC) - startedAtNanos) / NANOS_PER_MILLISECOND;
result = myData.waker.get();
+ 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());
printf(" waker result = %d, at %6d millis"
- ", second = %3d, framesWritten = %8d, underruns = %d\n",
+ ", second = %3d, frames written %8d - read %8d = %8d, underruns = %d\n",
result, (int) millis,
second,
- (int) AAudioStream_getFramesWritten(player.getStream()),
- (int) AAudioStream_getXRunCount(player.getStream()));
+ framesWritten,
+ framesRead,
+ framesWritten - framesRead,
+ xruns);
if (result != AAUDIO_OK) {
disconnected = (result == AAUDIO_ERROR_DISCONNECTED);
bailOut = true;
@@ -210,7 +220,9 @@
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(" -z force periodic underruns by sleeping in callback\n");
+ printf(" -h{msec} force periodic underruns by hanging in callback\n");
+ printf(" If no value specified then %d used.\n",
+ kDefaultHangTimeMSec);
}
int main(int argc, const char **argv)
@@ -219,13 +231,14 @@
aaudio_result_t result;
int32_t loopCount = 1;
int32_t prefixToneMsec = 0;
- bool forceUnderruns = false;
+ int32_t hangTimeMSec = 0;
// Make printf print immediately so that debug info is not stuck
// in a buffer if we hang or crash.
setvbuf(stdout, nullptr, _IONBF, (size_t) 0);
- printf("%s - Play a sine sweep using an AAudio callback V%s\n", argv[0], APP_VERSION);
+ printf("%s - Play a sine sweep using an AAudio callback V%s\n",
+ argv[0], APP_VERSION);
for (int i = 1; i < argc; i++) {
const char *arg = argv[i];
@@ -240,8 +253,10 @@
case 't':
prefixToneMsec = atoi(&arg[2]);
break;
- case 'z':
- forceUnderruns = true; // Zzzzzzz
+ case 'h':
+ hangTimeMSec = (arg[2]) // value specified?
+ ? atoi(&arg[2])
+ : kDefaultHangTimeMSec;
break;
default:
usage();
@@ -257,7 +272,8 @@
}
// Keep looping until we can complete the test without disconnecting.
- while((result = testOpenPlayClose(argParser, loopCount, prefixToneMsec, forceUnderruns))
+ while((result = testOpenPlayClose(argParser, loopCount,
+ prefixToneMsec, hangTimeMSec))
== AAUDIO_ERROR_DISCONNECTED);
return (result) ? EXIT_FAILURE : EXIT_SUCCESS;
diff --git a/media/libaudioclient/AudioRecord.cpp b/media/libaudioclient/AudioRecord.cpp
index 8afb1cc..baa1469 100644
--- a/media/libaudioclient/AudioRecord.cpp
+++ b/media/libaudioclient/AudioRecord.cpp
@@ -1361,14 +1361,12 @@
ALOGW("%s(%d): removing NULL callback!", __func__, mPortId);
return BAD_VALUE;
}
- {
- AutoMutex lock(mLock);
- if (mDeviceCallback.unsafe_get() != callback.get()) {
- ALOGW("%s(%d): removing different callback!", __func__, mPortId);
- return INVALID_OPERATION;
- }
- mDeviceCallback.clear();
+ AutoMutex lock(mLock);
+ if (mDeviceCallback.unsafe_get() != callback.get()) {
+ ALOGW("%s(%d): removing different callback!", __func__, mPortId);
+ return INVALID_OPERATION;
}
+ mDeviceCallback.clear();
if (mInput != AUDIO_IO_HANDLE_NONE) {
AudioSystem::removeAudioDeviceCallback(this, mInput);
}
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index 52ad5a6..01d9b3d 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -522,11 +522,12 @@
if (ioDesc == 0 || ioDesc->mIoHandle == AUDIO_IO_HANDLE_NONE) return;
audio_port_handle_t deviceId = AUDIO_PORT_HANDLE_NONE;
- AudioDeviceCallbacks callbacks;
- bool deviceValidOrChanged = false;
- Mutex::Autolock _l(mCallbacksLock);
+ Vector<sp<AudioDeviceCallback>> callbacksToCall;
{
Mutex::Autolock _l(mLock);
+ bool deviceValidOrChanged = false;
+ bool sendCallbacks = false;
+ ssize_t ioIndex = -1;
switch (event) {
case AUDIO_OUTPUT_OPENED:
@@ -544,17 +545,16 @@
if (ioDesc->getDeviceId() != AUDIO_PORT_HANDLE_NONE) {
deviceId = ioDesc->getDeviceId();
if (event == AUDIO_OUTPUT_OPENED || event == AUDIO_INPUT_OPENED) {
- ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(ioDesc->mIoHandle);
+ ioIndex = mAudioDeviceCallbackProxies.indexOfKey(ioDesc->mIoHandle);
if (ioIndex >= 0) {
- callbacks = mAudioDeviceCallbacks.valueAt(ioIndex);
+ sendCallbacks = true;
deviceValidOrChanged = true;
}
}
if (event == AUDIO_OUTPUT_REGISTERED || event == AUDIO_INPUT_REGISTERED) {
- ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(ioDesc->mIoHandle);
- if ((ioIndex >= 0) && !mAudioDeviceCallbacks.valueAt(ioIndex).notifiedOnce()) {
- callbacks = mAudioDeviceCallbacks.valueAt(ioIndex);
- }
+ ioIndex = mAudioDeviceCallbackProxies.indexOfKey(ioDesc->mIoHandle);
+ sendCallbacks = (ioIndex >= 0)
+ && !mAudioDeviceCallbackProxies.valueAt(ioIndex).notifiedOnce();
}
}
ALOGV("ioConfigChanged() new %s %s %d samplingRate %u, format %#x channel mask %#x "
@@ -577,7 +577,7 @@
event == AUDIO_OUTPUT_CLOSED ? "output" : "input", ioDesc->mIoHandle);
mIoDescriptors.removeItem(ioDesc->mIoHandle);
- mAudioDeviceCallbacks.removeItem(ioDesc->mIoHandle);
+ mAudioDeviceCallbackProxies.removeItem(ioDesc->mIoHandle);
} break;
case AUDIO_OUTPUT_CONFIG_CHANGED:
@@ -594,10 +594,8 @@
if (deviceId != ioDesc->getDeviceId()) {
deviceValidOrChanged = true;
deviceId = ioDesc->getDeviceId();
- ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(ioDesc->mIoHandle);
- if (ioIndex >= 0) {
- callbacks = mAudioDeviceCallbacks.valueAt(ioIndex);
- }
+ ioIndex = mAudioDeviceCallbackProxies.indexOfKey(ioDesc->mIoHandle);
+ sendCallbacks = ioIndex >= 0;
}
ALOGV("ioConfigChanged() new config for %s %d samplingRate %u, format %#x "
"channel mask %#x frameCount %zu frameCountHAL %zu deviceId %d",
@@ -608,30 +606,34 @@
} break;
}
- }
- // callbacks.size() != 0 => ioDesc->mIoHandle and deviceId are valid
- if (callbacks.size() != 0) {
- for (size_t i = 0; i < callbacks.size(); ) {
- sp<AudioDeviceCallback> callback = callbacks[i].promote();
- if (callback.get() != nullptr) {
- // Call the callback only if the device actually changed, the input or output was
- // opened or closed or the client was newly registered and the callback was never
- // called
- if (!callback->notifiedOnce() || deviceValidOrChanged) {
- // Must be called without mLock held. May lead to dead lock if calling for
- // example getRoutedDevice that updates the device and tries to acquire mLock.
- callback->onAudioDeviceUpdate(ioDesc->mIoHandle, deviceId);
- callback->setNotifiedOnce();
+
+ // sendCallbacks true => ioDesc->mIoHandle and deviceId are valid
+ if (sendCallbacks) {
+ AudioDeviceCallbackProxies &callbackProxies =
+ mAudioDeviceCallbackProxies.editValueAt(ioIndex);
+ for (size_t i = 0; i < callbackProxies.size(); ) {
+ sp<AudioDeviceCallback> callback = callbackProxies[i]->callback();
+ if (callback.get() != nullptr) {
+ // Call the callback only if the device actually changed, the input or output
+ // was opened or closed or the client was newly registered and the callback
+ // was never called
+ if (!callbackProxies[i]->notifiedOnce() || deviceValidOrChanged) {
+ callbacksToCall.add(callback);
+ callbackProxies[i]->setNotifiedOnce();
+ }
+ i++;
+ } else {
+ callbackProxies.removeAt(i);
}
- i++;
- } else {
- callbacks.removeAt(i);
}
+ callbackProxies.setNotifiedOnce();
}
- callbacks.setNotifiedOnce();
- // clean up callback list while we are here if some clients have disappeared without
- // unregistering their callback, or if cb was served for the first time since registered
- mAudioDeviceCallbacks.replaceValueFor(ioDesc->mIoHandle, callbacks);
+ }
+
+ // Callbacks must be called without mLock held. May lead to dead lock if calling for
+ // example getRoutedDevice that updates the device and tries to acquire mLock.
+ for (size_t i = 0; i < callbacksToCall.size(); i++) {
+ callbacksToCall[i]->onAudioDeviceUpdate(ioDesc->mIoHandle, deviceId);
}
}
@@ -686,48 +688,49 @@
status_t AudioSystem::AudioFlingerClient::addAudioDeviceCallback(
const wp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
{
- Mutex::Autolock _l(mCallbacksLock);
- AudioDeviceCallbacks callbacks;
- ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(audioIo);
+ Mutex::Autolock _l(mLock);
+ AudioDeviceCallbackProxies callbackProxies;
+ ssize_t ioIndex = mAudioDeviceCallbackProxies.indexOfKey(audioIo);
if (ioIndex >= 0) {
- callbacks = mAudioDeviceCallbacks.valueAt(ioIndex);
+ callbackProxies = mAudioDeviceCallbackProxies.valueAt(ioIndex);
}
- for (size_t cbIndex = 0; cbIndex < callbacks.size(); cbIndex++) {
- if (callbacks[cbIndex].unsafe_get() == callback.unsafe_get()) {
+ for (size_t cbIndex = 0; cbIndex < callbackProxies.size(); cbIndex++) {
+ sp<AudioDeviceCallback> cbk = callbackProxies[cbIndex]->callback();
+ if (cbk.get() == callback.unsafe_get()) {
return INVALID_OPERATION;
}
}
- callbacks.add(callback);
- callbacks.resetNotifiedOnce();
- mAudioDeviceCallbacks.replaceValueFor(audioIo, callbacks);
+ callbackProxies.add(new AudioDeviceCallbackProxy(callback));
+ callbackProxies.resetNotifiedOnce();
+ mAudioDeviceCallbackProxies.replaceValueFor(audioIo, callbackProxies);
return NO_ERROR;
}
status_t AudioSystem::AudioFlingerClient::removeAudioDeviceCallback(
const wp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
{
- Mutex::Autolock _l(mCallbacksLock);
- ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(audioIo);
+ Mutex::Autolock _l(mLock);
+ ssize_t ioIndex = mAudioDeviceCallbackProxies.indexOfKey(audioIo);
if (ioIndex < 0) {
return INVALID_OPERATION;
}
- AudioDeviceCallbacks callbacks = mAudioDeviceCallbacks.valueAt(ioIndex);
-
+ AudioDeviceCallbackProxies callbackProxies = mAudioDeviceCallbackProxies.valueAt(ioIndex);
size_t cbIndex;
- for (cbIndex = 0; cbIndex < callbacks.size(); cbIndex++) {
- if (callbacks[cbIndex].unsafe_get() == callback.unsafe_get()) {
+ for (cbIndex = 0; cbIndex < callbackProxies.size(); cbIndex++) {
+ sp<AudioDeviceCallback> cbk = callbackProxies[cbIndex]->callback();
+ if (cbk.get() == callback.unsafe_get()) {
break;
}
}
- if (cbIndex == callbacks.size()) {
+ if (cbIndex == callbackProxies.size()) {
return INVALID_OPERATION;
}
- callbacks.removeAt(cbIndex);
- if (callbacks.size() != 0) {
- mAudioDeviceCallbacks.replaceValueFor(audioIo, callbacks);
+ callbackProxies.removeAt(cbIndex);
+ if (callbackProxies.size() != 0) {
+ mAudioDeviceCallbackProxies.replaceValueFor(audioIo, callbackProxies);
} else {
- mAudioDeviceCallbacks.removeItem(audioIo);
+ mAudioDeviceCallbackProxies.removeItem(audioIo);
}
return NO_ERROR;
}
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index b5a7ebe..7881bb8 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -2959,14 +2959,12 @@
ALOGW("%s(%d): removing NULL callback!", __func__, mPortId);
return BAD_VALUE;
}
- {
- AutoMutex lock(mLock);
- if (mDeviceCallback.unsafe_get() != callback.get()) {
- ALOGW("%s removing different callback!", __FUNCTION__);
- return INVALID_OPERATION;
- }
- mDeviceCallback.clear();
+ AutoMutex lock(mLock);
+ if (mDeviceCallback.unsafe_get() != callback.get()) {
+ ALOGW("%s removing different callback!", __FUNCTION__);
+ return INVALID_OPERATION;
}
+ mDeviceCallback.clear();
if (mOutput != AUDIO_IO_HANDLE_NONE) {
AudioSystem::removeAudioDeviceCallback(this, mOutput);
}
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index 3df49e6..b9ee24a 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -399,15 +399,28 @@
virtual void onAudioDeviceUpdate(audio_io_handle_t audioIo,
audio_port_handle_t deviceId) = 0;
- bool notifiedOnce() const { return mNotifiedOnce; }
- void setNotifiedOnce() { mNotifiedOnce = true; }
+ };
+
+ class AudioDeviceCallbackProxy : public RefBase
+ {
+ public:
+
+ AudioDeviceCallbackProxy(wp<AudioDeviceCallback> callback)
+ : mCallback(callback) {}
+ ~AudioDeviceCallbackProxy() override {}
+
+ sp<AudioDeviceCallback> callback() const { return mCallback.promote(); };
+
+ bool notifiedOnce() const { return mNotifiedOnce; }
+ void setNotifiedOnce() { mNotifiedOnce = true; }
private:
- /**
- * @brief mNotifiedOnce it forces the callback to be called at least once when
- * registered with a VALID AudioDevice, and allows not to flood other listeners
- * on this iohandle that already know the valid device.
- */
- bool mNotifiedOnce = false;
+ /**
+ * @brief mNotifiedOnce it forces the callback to be called at least once when
+ * registered with a VALID AudioDevice, and allows not to flood other listeners
+ * on this iohandle that already know the valid device.
+ */
+ bool mNotifiedOnce = false;
+ wp<AudioDeviceCallback> mCallback;
};
static status_t addAudioDeviceCallback(const wp<AudioDeviceCallback>& callback,
@@ -454,7 +467,7 @@
Mutex mLock;
DefaultKeyedVector<audio_io_handle_t, sp<AudioIoDescriptor> > mIoDescriptors;
- class AudioDeviceCallbacks : public Vector<wp<AudioDeviceCallback>>
+ class AudioDeviceCallbackProxies : public Vector<sp<AudioDeviceCallbackProxy>>
{
public:
/**
@@ -472,8 +485,8 @@
*/
bool mNotifiedOnce = false;
};
- Mutex mCallbacksLock; // prevents race on Callbacks
- DefaultKeyedVector<audio_io_handle_t, AudioDeviceCallbacks> mAudioDeviceCallbacks;
+ DefaultKeyedVector<audio_io_handle_t, AudioDeviceCallbackProxies>
+ mAudioDeviceCallbackProxies;
// cached values for recording getInputBufferSize() queries
size_t mInBuffSize; // zero indicates cache is invalid
uint32_t mInSamplingRate;
diff --git a/media/libeffects/lvm/tests/lvmtest.cpp b/media/libeffects/lvm/tests/lvmtest.cpp
index 43271d2..fe47d0b 100644
--- a/media/libeffects/lvm/tests/lvmtest.cpp
+++ b/media/libeffects/lvm/tests/lvmtest.cpp
@@ -571,17 +571,12 @@
0); /* Audio Time */
}
-int lvmMainProcess(lvmConfigParams_t *plvmConfigParams, FILE *finp, FILE *fout) {
- struct EffectContext context;
- LVM_ControlParams_t params;
-
- int errCode = lvmCreate(&context, plvmConfigParams, ¶ms);
- if (errCode) {
- ALOGE("Error: lvmCreate returned with %d\n", errCode);
- return errCode;
- }
-
- errCode = lvmControl(&context, plvmConfigParams, ¶ms);
+int lvmMainProcess(EffectContext *pContext,
+ LVM_ControlParams_t *pParams,
+ lvmConfigParams_t *plvmConfigParams,
+ FILE *finp,
+ FILE *fout) {
+ int errCode = lvmControl(pContext, plvmConfigParams, pParams);
if (errCode) {
ALOGE("Error: lvmControl returned with %d\n", errCode);
return errCode;
@@ -625,7 +620,7 @@
}
}
#if 1
- errCode = lvmExecute(floatIn.data(), floatOut.data(), &context, plvmConfigParams);
+ errCode = lvmExecute(floatIn.data(), floatOut.data(), pContext, plvmConfigParams);
if (errCode) {
printf("\nError: lvmExecute returned with %d\n", errCode);
return errCode;
@@ -654,14 +649,15 @@
}
lvmConfigParams_t lvmConfigParams{}; // default initialize
- FILE *finp = nullptr, *fout = nullptr;
+ const char *infile = nullptr;
+ const char *outfile = nullptr;
for (int i = 1; i < argc; i++) {
printf("%s ", argv[i]);
if (!strncmp(argv[i], "-i:", 3)) {
- finp = fopen(argv[i] + 3, "rb");
+ infile = argv[i] + 3;
} else if (!strncmp(argv[i], "-o:", 3)) {
- fout = fopen(argv[i] + 3, "wb");
+ outfile = argv[i] + 3;
} else if (!strncmp(argv[i], "-fs:", 4)) {
const int samplingFreq = atoi(argv[i] + 4);
if (samplingFreq != 8000 && samplingFreq != 11025 &&
@@ -671,21 +667,21 @@
samplingFreq != 48000 && samplingFreq != 88200 &&
samplingFreq != 96000 && samplingFreq != 176400 &&
samplingFreq != 192000) {
- ALOGE("\nError: Unsupported Sampling Frequency : %d\n", samplingFreq);
+ printf("Error: Unsupported Sampling Frequency : %d\n", samplingFreq);
return -1;
}
lvmConfigParams.samplingFreq = samplingFreq;
} else if (!strncmp(argv[i], "-ch:", 4)) {
const int nrChannels = atoi(argv[i] + 4);
if (nrChannels > 8 || nrChannels < 1) {
- ALOGE("\nError: Unsupported number of channels : %d\n", nrChannels);
+ printf("Error: Unsupported number of channels : %d\n", nrChannels);
return -1;
}
lvmConfigParams.nrChannels = nrChannels;
} else if (!strncmp(argv[i], "-fch:", 5)) {
const int fChannels = atoi(argv[i] + 5);
if (fChannels > 8 || fChannels < 1) {
- ALOGE("\nError: Unsupported number of file channels : %d\n", fChannels);
+ printf("Error: Unsupported number of file channels : %d\n", fChannels);
return -1;
}
lvmConfigParams.fChannels = fChannels;
@@ -694,7 +690,7 @@
} else if (!strncmp(argv[i], "-basslvl:", 9)) {
const int bassEffectLevel = atoi(argv[i] + 9);
if (bassEffectLevel > 15 || bassEffectLevel < 0) {
- ALOGE("\nError: Unsupported Bass Effect Level : %d\n",
+ printf("Error: Unsupported Bass Effect Level : %d\n",
bassEffectLevel);
printUsage();
return -1;
@@ -703,7 +699,7 @@
} else if (!strncmp(argv[i], "-eqPreset:", 10)) {
const int eqPresetLevel = atoi(argv[i] + 10);
if (eqPresetLevel > 9 || eqPresetLevel < 0) {
- ALOGE("\nError: Unsupported Equalizer Preset : %d\n", eqPresetLevel);
+ printf("Error: Unsupported Equalizer Preset : %d\n", eqPresetLevel);
printUsage();
return -1;
}
@@ -722,19 +718,47 @@
}
}
- if (finp == nullptr || fout == nullptr) {
- ALOGE("\nError: missing input/output files\n");
+ if (infile == nullptr || outfile == nullptr) {
+ printf("Error: missing input/output files\n");
printUsage();
- // ok not to close.
return -1;
}
- const int errCode = lvmMainProcess(&lvmConfigParams, finp, fout);
+ FILE *finp = fopen(infile, "rb");
+ if (finp == nullptr) {
+ printf("Cannot open input file %s", infile);
+ return -1;
+ }
+
+ FILE *fout = fopen(outfile, "wb");
+ if (fout == nullptr) {
+ printf("Cannot open output file %s", outfile);
+ fclose(finp);
+ return -1;
+ }
+
+ EffectContext context;
+ LVM_ControlParams_t params;
+ int errCode = lvmCreate(&context, &lvmConfigParams, ¶ms);
+ if (errCode == 0) {
+ errCode = lvmMainProcess(&context, ¶ms, &lvmConfigParams, finp, fout);
+ if (errCode != 0) {
+ printf("Error: lvmMainProcess returned with the error: %d",errCode);
+ }
+ } else {
+ printf("Error: lvmCreate returned with the error: %d", errCode);
+ }
fclose(finp);
fclose(fout);
+ /* Free the allocated buffers */
+ if (context.pBundledContext != nullptr) {
+ if (context.pBundledContext->hInstance != nullptr) {
+ LvmEffect_free(&context);
+ }
+ free(context.pBundledContext);
+ }
if (errCode) {
- ALOGE("Error: lvmMainProcess returns with the error: %d \n", errCode);
return -1;
}
return 0;
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index 9a1ac53..5853e4b 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -21,6 +21,7 @@
vndk: {
enabled: true,
},
+ double_loadable: true,
srcs: ["AudioParameter.cpp", "TypeConverter.cpp"],
cflags: [
"-Werror",
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 6d2329f..52cb5fa 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -4298,24 +4298,27 @@
int maxDimension = max(width, height);
static const int limits[][5] = {
- /* MBps MB dim bitrate level */
- { 1485, 99, 28, 64, OMX_VIDEO_AVCLevel1 },
- { 1485, 99, 28, 128, OMX_VIDEO_AVCLevel1b },
- { 3000, 396, 56, 192, OMX_VIDEO_AVCLevel11 },
- { 6000, 396, 56, 384, OMX_VIDEO_AVCLevel12 },
- { 11880, 396, 56, 768, OMX_VIDEO_AVCLevel13 },
- { 11880, 396, 56, 2000, OMX_VIDEO_AVCLevel2 },
- { 19800, 792, 79, 4000, OMX_VIDEO_AVCLevel21 },
- { 20250, 1620, 113, 4000, OMX_VIDEO_AVCLevel22 },
- { 40500, 1620, 113, 10000, OMX_VIDEO_AVCLevel3 },
- { 108000, 3600, 169, 14000, OMX_VIDEO_AVCLevel31 },
- { 216000, 5120, 202, 20000, OMX_VIDEO_AVCLevel32 },
- { 245760, 8192, 256, 20000, OMX_VIDEO_AVCLevel4 },
- { 245760, 8192, 256, 50000, OMX_VIDEO_AVCLevel41 },
- { 522240, 8704, 263, 50000, OMX_VIDEO_AVCLevel42 },
- { 589824, 22080, 420, 135000, OMX_VIDEO_AVCLevel5 },
- { 983040, 36864, 543, 240000, OMX_VIDEO_AVCLevel51 },
- { 2073600, 36864, 543, 240000, OMX_VIDEO_AVCLevel52 },
+ /* MBps MB dim bitrate level */
+ { 1485, 99, 28, 64, OMX_VIDEO_AVCLevel1 },
+ { 1485, 99, 28, 128, OMX_VIDEO_AVCLevel1b },
+ { 3000, 396, 56, 192, OMX_VIDEO_AVCLevel11 },
+ { 6000, 396, 56, 384, OMX_VIDEO_AVCLevel12 },
+ { 11880, 396, 56, 768, OMX_VIDEO_AVCLevel13 },
+ { 11880, 396, 56, 2000, OMX_VIDEO_AVCLevel2 },
+ { 19800, 792, 79, 4000, OMX_VIDEO_AVCLevel21 },
+ { 20250, 1620, 113, 4000, OMX_VIDEO_AVCLevel22 },
+ { 40500, 1620, 113, 10000, OMX_VIDEO_AVCLevel3 },
+ { 108000, 3600, 169, 14000, OMX_VIDEO_AVCLevel31 },
+ { 216000, 5120, 202, 20000, OMX_VIDEO_AVCLevel32 },
+ { 245760, 8192, 256, 20000, OMX_VIDEO_AVCLevel4 },
+ { 245760, 8192, 256, 50000, OMX_VIDEO_AVCLevel41 },
+ { 522240, 8704, 263, 50000, OMX_VIDEO_AVCLevel42 },
+ { 589824, 22080, 420, 135000, OMX_VIDEO_AVCLevel5 },
+ { 983040, 36864, 543, 240000, OMX_VIDEO_AVCLevel51 },
+ { 2073600, 36864, 543, 240000, OMX_VIDEO_AVCLevel52 },
+ { 4177920, 139264, 1055, 240000, OMX_VIDEO_AVCLevel6 },
+ { 8355840, 139264, 1055, 480000, OMX_VIDEO_AVCLevel61 },
+ { 16711680, 139264, 1055, 800000, OMX_VIDEO_AVCLevel62 },
};
for (size_t i = 0; i < ARRAY_SIZE(limits); i++) {
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index 2e7da01..82f7026 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -192,6 +192,9 @@
{ 50, OMX_VIDEO_AVCLevel5 },
{ 51, OMX_VIDEO_AVCLevel51 },
{ 52, OMX_VIDEO_AVCLevel52 },
+ { 60, OMX_VIDEO_AVCLevel6 },
+ { 61, OMX_VIDEO_AVCLevel61 },
+ { 62, OMX_VIDEO_AVCLevel62 },
};
const static ALookup<uint8_t, OMX_VIDEO_AVCPROFILETYPE> profiles {
{ 66, OMX_VIDEO_AVCProfileBaseline },
diff --git a/media/libstagefright/omx/Android.bp b/media/libstagefright/omx/Android.bp
index 362b7f5..4383004 100644
--- a/media/libstagefright/omx/Android.bp
+++ b/media/libstagefright/omx/Android.bp
@@ -87,6 +87,7 @@
vndk: {
enabled: true,
},
+ double_loadable: true,
srcs: ["OMXUtils.cpp"],
export_include_dirs: [
"include",
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index 5d993db..8454ca1 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -1913,7 +1913,7 @@
mLastMediaTimeUs = mediaTimeUs;
}
- if (mediaTimeUs < 0) {
+ if (mediaTimeUs < 0 && !mSeekable) {
ALOGV("dropping early accessUnit.");
return false;
}
diff --git a/media/libstagefright/xmlparser/Android.bp b/media/libstagefright/xmlparser/Android.bp
index bebfb3b..819058c 100644
--- a/media/libstagefright/xmlparser/Android.bp
+++ b/media/libstagefright/xmlparser/Android.bp
@@ -10,6 +10,7 @@
vndk: {
enabled: true,
},
+ double_loadable: true,
srcs: [
"MediaCodecsXmlParser.cpp",
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 7733071..2d80bd8 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -3277,9 +3277,13 @@
}
// look for the thread where the specified audio session is present
for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
- if (mPlaybackThreads.valueAt(i)->hasAudioSession(sessionId) != 0) {
+ uint32_t sessionType = mPlaybackThreads.valueAt(i)->hasAudioSession(sessionId);
+ if (sessionType != 0) {
io = mPlaybackThreads.keyAt(i);
- break;
+ // thread with same effect session is preferable
+ if ((sessionType & ThreadBase::EFFECT_SESSION) != 0) {
+ break;
+ }
}
}
if (io == AUDIO_IO_HANDLE_NONE) {
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index 3f62bc3..94ea042 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -222,6 +222,8 @@
private:
void interceptBuffer(const AudioBufferProvider::Buffer& buffer);
+ /** Write the source data in the buffer provider. @return written frame count. */
+ size_t writeFrames(AudioBufferProvider* dest, const void* src, size_t frameCount);
template <class F>
void forEachTeePatchTrack(F f) {
for (auto& tp : mTeePatches) { f(tp.patchTrack); }
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index dd1eabf..6dd9cab 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -4784,7 +4784,10 @@
track->mFillingUpStatus = Track::FS_ACTIVE;
if (track->mState == TrackBase::RESUMING) {
track->mState = TrackBase::ACTIVE;
- param = AudioMixer::RAMP_VOLUME;
+ // If a new track is paused immediately after start, do not ramp on resume.
+ if (cblk->mServer != 0) {
+ param = AudioMixer::RAMP_VOLUME;
+ }
}
mAudioMixer->setParameter(trackId, AudioMixer::RESAMPLE, AudioMixer::RESET, NULL);
mLeftVolFloat = -1.0;
@@ -5462,6 +5465,11 @@
mFlushPending = true;
}
}
+ } else if (previousTrack == 0) {
+ // there could be an old track added back during track transition for direct
+ // output, so always issues flush to flush data of the previous track if it
+ // was already destroyed with HAL paused, then flush can resume the playback
+ mFlushPending = true;
}
PlaybackThread::onAddNewTrack_l();
}
@@ -5500,7 +5508,6 @@
doHwPause = true;
mHwPaused = true;
}
- tracksToRemove->add(track);
} else if (track->isFlushPending()) {
track->flushAck();
if (last) {
@@ -5597,7 +5604,8 @@
int64_t framesWritten = mBytesWritten / mFrameSize;
if (mStandby || !last ||
- track->presentationComplete(framesWritten, audioHALFrames)) {
+ track->presentationComplete(framesWritten, audioHALFrames) ||
+ track->isPaused()) {
if (track->isStopping_2()) {
track->mState = TrackBase::STOPPED;
}
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 57dd568..922547d 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -697,28 +697,44 @@
// TODO: compensate for time shift between HW modules.
void AudioFlinger::PlaybackThread::Track::interceptBuffer(
- const AudioBufferProvider::Buffer& buffer) {
+ const AudioBufferProvider::Buffer& sourceBuffer) {
+ const size_t frameCount = sourceBuffer.frameCount;
for (auto& sink : mTeePatches) {
- RecordThread::PatchRecord& patchRecord = *sink.patchRecord;
- AudioBufferProvider::Buffer patchBuffer;
- patchBuffer.frameCount = buffer.frameCount;
- auto status = patchRecord.getNextBuffer(&patchBuffer);
- if (status != NO_ERROR) {
- ALOGW("%s PathRecord getNextBuffer failed with error %d: %s",
- __func__, status, strerror(-status));
- continue;
+ RecordThread::PatchRecord* patchRecord = sink.patchRecord.get();
+
+ size_t framesWritten = writeFrames(patchRecord, sourceBuffer.i8, frameCount);
+ // On buffer wrap, the buffer frame count will be less than requested,
+ // when this happens a second buffer needs to be used to write the leftover audio
+ size_t framesLeft = frameCount - framesWritten;
+ if (framesWritten != 0 && framesLeft != 0) {
+ framesWritten +=
+ writeFrames(patchRecord, sourceBuffer.i8 + framesWritten * mFrameSize, framesLeft);
+ framesLeft = frameCount - framesWritten;
}
- // FIXME: On buffer wrap, the frame count will be less then requested,
- // retry to write the rest. (unlikely due to lcm buffer sizing)
- ALOGW_IF(patchBuffer.frameCount != buffer.frameCount,
- "%s PatchRecord can not provide big enough buffer %zu/%zu, dropping %zu frames",
- __func__, patchBuffer.frameCount, buffer.frameCount,
- buffer.frameCount - patchBuffer.frameCount);
- memcpy(patchBuffer.raw, buffer.raw, patchBuffer.frameCount * mFrameSize);
- patchRecord.releaseBuffer(&patchBuffer);
+ ALOGW_IF(framesLeft != 0, "%s(%d) PatchRecord %d can not provide big enough "
+ "buffer %zu/%zu, dropping %zu frames", __func__, mId, patchRecord->mId,
+ framesWritten, frameCount, framesLeft);
}
}
+size_t AudioFlinger::PlaybackThread::Track::writeFrames(AudioBufferProvider* dest,
+ const void* src,
+ size_t frameCount) {
+ AudioBufferProvider::Buffer patchBuffer;
+ patchBuffer.frameCount = frameCount;
+ auto status = dest->getNextBuffer(&patchBuffer);
+ if (status != NO_ERROR) {
+ ALOGW("%s PathRecord getNextBuffer failed with error %d: %s",
+ __func__, status, strerror(-status));
+ return 0;
+ }
+ ALOG_ASSERT(patchBuffer.frameCount <= frameCount);
+ memcpy(patchBuffer.raw, src, patchBuffer.frameCount * mFrameSize);
+ auto framesWritten = patchBuffer.frameCount;
+ dest->releaseBuffer(&patchBuffer);
+ return framesWritten;
+}
+
// releaseBuffer() is not overridden
// ExtendedAudioBufferProvider interface
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
index d4cfd1e..803cfac 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
@@ -143,6 +143,16 @@
void trackEffectEnabled(const sp<EffectDescriptor> &effect, bool enabled);
+ /**
+ * @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
+ * device.
+ * In other words, the preferred device port id of these clients will be resetted to NONE.
+ * @param disconnectedDevice device to be disconnected
+ */
+ void clearSessionRoutesForDevice(const sp<DeviceDescriptor> &disconnectedDevice);
+
void dump(String8 *dst) const;
};
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
index 6132bb4..c84636e 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
@@ -380,6 +380,16 @@
uint32_t inPastMs = 0, nsecs_t sysTime = 0) 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
+ * device.
+ * In other words, the preferred device port id of these clients will be resetted to NONE.
+ * @param disconnectedDevice device to be disconnected
+ */
+ void clearSessionRoutesForDevice(const sp<DeviceDescriptor> &disconnectedDevice);
+
+ /**
* returns the A2DP output handle if it is open or 0 otherwise
*/
audio_io_handle_t getA2dpOutput() const;
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
index 1abce6f..d6f24b2 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
@@ -43,12 +43,12 @@
android::AudioMix *getMix();
- void setMix(AudioMix &mix);
+ void setMix(const AudioMix &mix);
void dump(String8 *dst, int spaces, int index) const;
private:
- AudioMix mMix; // Audio policy mix descriptor
+ AudioMix mMix; // Audio policy mix descriptor
sp<SwAudioOutputDescriptor> mOutput; // Corresponding output stream
};
@@ -71,7 +71,7 @@
* @param[out] desc to return if an primary output could be found.
* @param[out] secondaryDesc other desc that the audio should be routed to.
*/
- status_t getOutputForAttr(audio_attributes_t attributes, uid_t uid,
+ status_t getOutputForAttr(const audio_attributes_t& attributes, uid_t uid,
sp<SwAudioOutputDescriptor> &primaryDesc,
std::vector<sp<SwAudioOutputDescriptor>> *secondaryDescs);
@@ -102,7 +102,7 @@
private:
enum class MixMatchStatus { MATCH, NO_MATCH, INVALID_MIX };
MixMatchStatus mixMatch(const AudioMix* mix, size_t mixIndex,
- audio_attributes_t attributes, uid_t uid);
+ const audio_attributes_t& attributes, uid_t uid);
};
} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
index c880e67..1fa1123 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
@@ -511,6 +511,19 @@
}
}
+void AudioInputCollection::clearSessionRoutesForDevice(
+ const sp<DeviceDescriptor> &disconnectedDevice)
+{
+ for (size_t i = 0; i < size(); i++) {
+ sp<AudioInputDescriptor> inputDesc = valueAt(i);
+ for (const auto& client : inputDesc->getClientIterable()) {
+ if (client->preferredDeviceId() == disconnectedDevice->getId()) {
+ client->setPreferredDeviceId(AUDIO_PORT_HANDLE_NONE);
+ }
+ }
+ }
+}
+
void AudioInputCollection::dump(String8 *dst) const
{
dst->append("\nInputs dump:\n");
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index 1dfd88a..77e7add 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -802,6 +802,19 @@
return 0;
}
+void SwAudioOutputCollection::clearSessionRoutesForDevice(
+ const sp<DeviceDescriptor> &disconnectedDevice)
+{
+ for (size_t i = 0; i < size(); i++) {
+ sp<AudioOutputDescriptor> outputDesc = valueAt(i);
+ for (const auto& client : outputDesc->getClientIterable()) {
+ if (client->preferredDeviceId() == disconnectedDevice->getId()) {
+ client->setPreferredDeviceId(AUDIO_PORT_HANDLE_NONE);
+ }
+ }
+ }
+}
+
void SwAudioOutputCollection::dump(String8 *dst) const
{
dst->append("\nOutputs dump:\n");
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
index 6b6d9d2..446a1e6 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
@@ -42,7 +42,7 @@
mOutput.clear();
}
-void AudioPolicyMix::setMix(AudioMix &mix)
+void AudioPolicyMix::setMix(const AudioMix &mix)
{
mMix = mix;
}
@@ -157,7 +157,7 @@
}
status_t AudioPolicyMixCollection::getOutputForAttr(
- audio_attributes_t attributes, uid_t uid, sp<SwAudioOutputDescriptor> &primaryDesc,
+ const audio_attributes_t& attributes, uid_t uid, sp<SwAudioOutputDescriptor> &primaryDesc,
std::vector<sp<SwAudioOutputDescriptor>> *secondaryDescs)
{
ALOGV("getOutputForAttr() querying %zu mixes:", size());
@@ -203,7 +203,7 @@
}
AudioPolicyMixCollection::MixMatchStatus AudioPolicyMixCollection::mixMatch(
- const AudioMix* mix, size_t mixIndex, audio_attributes_t attributes, uid_t uid) {
+ const AudioMix* mix, size_t mixIndex, const audio_attributes_t& attributes, uid_t uid) {
if (mix->mMixType == MIX_TYPE_PLAYERS) {
// TODO if adding more player rules (currently only 2), make rule handling "generic"
@@ -378,7 +378,7 @@
ALOGV("getInputMixForAttr looking for address %s\n mixes available:", address.string());
for (size_t i = 0; i < size(); i++) {
sp<AudioPolicyMix> policyMix = valueAt(i);
- AudioMix *mix = policyMix->getMix();
+ const AudioMix *mix = policyMix->getMix();
ALOGV("\tmix %zu address=%s", i, mix->mDeviceAddress.string());
}
#endif
@@ -435,7 +435,7 @@
// for each player mix: remove existing rules that match or exclude this uid
for (size_t i = 0; i < size(); i++) {
bool foundUidRule = false;
- AudioMix *mix = valueAt(i)->getMix();
+ const AudioMix *mix = valueAt(i)->getMix();
if (mix->mMixType != MIX_TYPE_PLAYERS) {
continue;
}
@@ -463,7 +463,7 @@
// for each player mix: find rules that don't exclude this uid, and add the device to the list
for (size_t i = 0; i < size(); i++) {
bool ruleAllowsUid = true;
- AudioMix *mix = valueAt(i)->getMix();
+ const AudioMix *mix = valueAt(i)->getMix();
if (mix->mMixType != MIX_TYPE_PLAYERS) {
continue;
}
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index ccec93f..5c22727 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -193,6 +193,8 @@
// remove device from available output devices
mAvailableOutputDevices.remove(device);
+ mOutputs.clearSessionRoutesForDevice(device);
+
checkOutputsForDevice(device, state, outputs);
// Reset active device codec
@@ -929,8 +931,6 @@
const sp<DeviceDescriptor> requestedDevice =
mAvailableOutputDevices.getDeviceFromId(requestedPortId);
-
-
status_t status = getAudioAttributes(resultAttr, attr, *stream);
if (status != NO_ERROR) {
return status;
@@ -953,8 +953,8 @@
// FIXME: in case of RENDER policy, the output capabilities should be checked
if ((usePrimaryOutputFromPolicyMixes || !secondaryDescs->empty())
- && !audio_has_proportional_frames(config->format)) {
- ALOGW("%s: audio loopback only supports proportional frames", __func__);
+ && !audio_is_linear_pcm(config->format)) {
+ ALOGD("%s: rejecting request as dynamic audio policy only support pcm", __func__);
return BAD_VALUE;
}
if (usePrimaryOutputFromPolicyMixes) {
@@ -1045,6 +1045,14 @@
audio_attributes_t resultAttr;
bool isRequestedDeviceForExclusiveUse = false;
std::vector<sp<SwAudioOutputDescriptor>> secondaryOutputDescs;
+ const sp<DeviceDescriptor> requestedDevice =
+ mAvailableOutputDevices.getDeviceFromId(requestedPortId);
+
+ // Prevent from storing invalid requested device id in clients
+ const audio_port_handle_t sanitizedRequestedPortId =
+ requestedDevice != nullptr ? requestedPortId : AUDIO_PORT_HANDLE_NONE;
+ *selectedDeviceId = sanitizedRequestedPortId;
+
status_t status = getOutputForAttrInt(&resultAttr, output, session, attr, stream, uid,
config, flags, selectedDeviceId, &isRequestedDeviceForExclusiveUse,
&secondaryOutputDescs);
@@ -1064,15 +1072,15 @@
sp<TrackClientDescriptor> clientDesc =
new TrackClientDescriptor(*portId, uid, session, resultAttr, clientConfig,
- requestedPortId, *stream,
+ sanitizedRequestedPortId, *stream,
mEngine->getProductStrategyForAttributes(resultAttr),
*flags, isRequestedDeviceForExclusiveUse,
std::move(weakSecondaryOutputDescs));
sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueFor(*output);
outputDesc->addClient(clientDesc);
- ALOGV("%s() returns output %d selectedDeviceId %d for port ID %d", __func__,
- *output, *selectedDeviceId, *portId);
+ ALOGV("%s() returns output %d requestedPortId %d selectedDeviceId %d for port ID %d", __func__,
+ *output, requestedPortId, *selectedDeviceId, *portId);
return NO_ERROR;
}
@@ -1953,6 +1961,8 @@
if (explicitRoutingDevice != nullptr) {
device = explicitRoutingDevice;
} else {
+ // Prevent from storing invalid requested device id in clients
+ requestedDeviceId = AUDIO_PORT_HANDLE_NONE;
device = mEngine->getInputDeviceForAttributes(attributes, &policyMix);
}
if (device == nullptr) {
@@ -5295,16 +5305,17 @@
// filter devices according to output selected
DeviceVector filteredDevices = outputDesc->filterSupportedDevices(devices);
+ DeviceVector prevDevices = outputDesc->devices();
// no need to proceed if new device is not AUDIO_DEVICE_NONE and not supported by current
- // output profile
- if (!devices.isEmpty() && filteredDevices.isEmpty()) {
+ // output profile or if new device is not supported AND previous device(s) is(are) still
+ // available (otherwise reset device must be done on the output)
+ if (!devices.isEmpty() && filteredDevices.isEmpty() &&
+ !mAvailableOutputDevices.filter(prevDevices).empty()) {
ALOGV("%s: unsupported device %s for output", __func__, devices.toString().c_str());
return 0;
}
- DeviceVector prevDevices = outputDesc->devices();
-
ALOGV("setOutputDevices() prevDevice %s", prevDevices.toString().c_str());
if (!filteredDevices.isEmpty()) {
@@ -5819,6 +5830,8 @@
}
}
+ mInputs.clearSessionRoutesForDevice(deviceDesc);
+
mHwModules.cleanUpForDevice(deviceDesc);
}
diff --git a/services/camera/libcameraservice/Android.bp b/services/camera/libcameraservice/Android.bp
index 2d923bf..2ca8356 100644
--- a/services/camera/libcameraservice/Android.bp
+++ b/services/camera/libcameraservice/Android.bp
@@ -99,6 +99,7 @@
"android.frameworks.cameraservice.device@2.0",
"android.hardware.camera.common@1.0",
"android.hardware.camera.provider@2.4",
+ "android.hardware.camera.provider@2.5",
"android.hardware.camera.device@1.0",
"android.hardware.camera.device@3.2",
"android.hardware.camera.device@3.3",
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index ee8d7e1..e06897f 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -1654,6 +1654,49 @@
return Status::ok();
}
+Status CameraService::notifyDeviceStateChange(int64_t newState) {
+ const int pid = CameraThreadState::getCallingPid();
+ const int selfPid = getpid();
+
+ // Permission checks
+ if (pid != selfPid) {
+ // Ensure we're being called by system_server, or similar process with
+ // permissions to notify the camera service about system events
+ if (!checkCallingPermission(
+ String16("android.permission.CAMERA_SEND_SYSTEM_EVENTS"))) {
+ const int uid = CameraThreadState::getCallingUid();
+ ALOGE("Permission Denial: cannot send updates to camera service about device"
+ " state changes from pid=%d, uid=%d", pid, uid);
+ return STATUS_ERROR_FMT(ERROR_PERMISSION_DENIED,
+ "No permission to send updates to camera service about device state"
+ " changes from pid=%d, uid=%d", pid, uid);
+ }
+ }
+
+ ATRACE_CALL();
+
+ using hardware::camera::provider::V2_5::DeviceState;
+ hardware::hidl_bitfield<DeviceState> newDeviceState{};
+ if (newState & ICameraService::DEVICE_STATE_BACK_COVERED) {
+ newDeviceState |= DeviceState::BACK_COVERED;
+ }
+ if (newState & ICameraService::DEVICE_STATE_FRONT_COVERED) {
+ newDeviceState |= DeviceState::FRONT_COVERED;
+ }
+ if (newState & ICameraService::DEVICE_STATE_FOLDED) {
+ newDeviceState |= DeviceState::FOLDED;
+ }
+ // Only map vendor bits directly
+ uint64_t vendorBits = static_cast<uint64_t>(newState) & 0xFFFFFFFF00000000l;
+ newDeviceState |= vendorBits;
+
+ ALOGV("%s: New device state 0x%" PRIx64, __FUNCTION__, newDeviceState);
+ Mutex::Autolock l(mServiceLock);
+ mCameraProviderManager->notifyDeviceStateChange(newDeviceState);
+
+ return Status::ok();
+}
+
Status CameraService::addListener(const sp<ICameraServiceListener>& listener,
/*out*/
std::vector<hardware::CameraStatus> *cameraStatuses) {
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 3af52fa..cf0cef8 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -154,6 +154,8 @@
virtual binder::Status notifySystemEvent(int32_t eventId,
const std::vector<int32_t>& args);
+ virtual binder::Status notifyDeviceStateChange(int64_t newState);
+
// OK = supports api of that version, -EOPNOTSUPP = does not support
virtual binder::Status supportsCameraApi(
const String16& cameraId, int32_t apiVersion,
diff --git a/services/camera/libcameraservice/api2/DepthCompositeStream.cpp b/services/camera/libcameraservice/api2/DepthCompositeStream.cpp
index f627b25..2eec0f7 100644
--- a/services/camera/libcameraservice/api2/DepthCompositeStream.cpp
+++ b/services/camera/libcameraservice/api2/DepthCompositeStream.cpp
@@ -634,6 +634,11 @@
mDepthStreamId = -1;
}
+ if (mOutputSurface != nullptr) {
+ mOutputSurface->disconnect(NATIVE_WINDOW_API_CAMERA);
+ mOutputSurface.clear();
+ }
+
return ret;
}
diff --git a/services/camera/libcameraservice/api2/HeicCompositeStream.cpp b/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
index 3eba863..8e9c39e 100644
--- a/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
+++ b/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
@@ -214,6 +214,10 @@
mAppSegmentStreamId = -1;
}
+ if (mOutputSurface != nullptr) {
+ mOutputSurface->disconnect(NATIVE_WINDOW_API_CAMERA);
+ mOutputSurface.clear();
+ }
return res;
}
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index f35c66a..d6789a4 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -71,6 +71,8 @@
}
mListener = listener;
mServiceProxy = proxy;
+ mDeviceState = static_cast<hardware::hidl_bitfield<provider::V2_5::DeviceState>>(
+ provider::V2_5::DeviceState::NORMAL);
// Registering will trigger notifications for all already-known providers
bool success = mServiceProxy->registerForNotifications(
@@ -274,6 +276,26 @@
return OK;
}
+status_t CameraProviderManager::notifyDeviceStateChange(
+ hardware::hidl_bitfield<provider::V2_5::DeviceState> newState) {
+ std::lock_guard<std::mutex> lock(mInterfaceMutex);
+ mDeviceState = newState;
+ status_t res = OK;
+ for (auto& provider : mProviders) {
+ ALOGV("%s: Notifying %s for new state 0x%" PRIx64,
+ __FUNCTION__, provider->mProviderName.c_str(), newState);
+ status_t singleRes = provider->notifyDeviceStateChange(mDeviceState);
+ if (singleRes != OK) {
+ ALOGE("%s: Unable to notify provider %s about device state change",
+ __FUNCTION__,
+ provider->mProviderName.c_str());
+ res = singleRes;
+ // continue to do the rest of the providers instead of returning now
+ }
+ }
+ return res;
+}
+
status_t CameraProviderManager::openSession(const std::string &id,
const sp<device::V3_2::ICameraDeviceCallback>& callback,
/*out*/
@@ -359,7 +381,7 @@
if (!kEnableLazyHal) {
return;
}
- ALOGI("Saving camera provider %s for camera device %s", provider->descriptor, cameraId.c_str());
+ ALOGV("Saving camera provider %s for camera device %s", provider->descriptor, cameraId.c_str());
std::lock_guard<std::mutex> lock(mProviderInterfaceMapLock);
std::unordered_map<std::string, sp<provider::V2_4::ICameraProvider>> *primaryMap, *alternateMap;
if (usageType == DeviceMode::TORCH) {
@@ -383,7 +405,7 @@
if (!kEnableLazyHal) {
return;
}
- ALOGI("Removing camera device %s", cameraId.c_str());
+ ALOGV("Removing camera device %s", cameraId.c_str());
std::unordered_map<std::string, sp<provider::V2_4::ICameraProvider>> *providerMap;
if (usageType == DeviceMode::TORCH) {
providerMap = &mTorchProviderByCameraId;
@@ -1088,7 +1110,7 @@
}
sp<ProviderInfo> providerInfo = new ProviderInfo(newProvider, this);
- status_t res = providerInfo->initialize(interface);
+ status_t res = providerInfo->initialize(interface, mDeviceState);
if (res != OK) {
return res;
}
@@ -1149,7 +1171,8 @@
}
status_t CameraProviderManager::ProviderInfo::initialize(
- sp<provider::V2_4::ICameraProvider>& interface) {
+ sp<provider::V2_4::ICameraProvider>& interface,
+ hardware::hidl_bitfield<provider::V2_5::DeviceState> currentDeviceState) {
status_t res = parseProviderName(mProviderName, &mType, &mId);
if (res != OK) {
ALOGE("%s: Invalid provider name, ignoring", __FUNCTION__);
@@ -1157,6 +1180,15 @@
}
ALOGI("Connecting to new camera provider: %s, isRemote? %d",
mProviderName.c_str(), interface->isRemote());
+
+ // Determine minor version
+ auto castResult = provider::V2_5::ICameraProvider::castFrom(interface);
+ if (castResult.isOk()) {
+ mMinorVersion = 5;
+ } else {
+ mMinorVersion = 4;
+ }
+
// cameraDeviceStatusChange callbacks may be called (and causing new devices added)
// before setCallback returns
hardware::Return<Status> status = interface->setCallback(this);
@@ -1181,6 +1213,24 @@
__FUNCTION__, mProviderName.c_str());
}
+ if (!kEnableLazyHal) {
+ // Save HAL reference indefinitely
+ mSavedInterface = interface;
+ } else {
+ mActiveInterface = interface;
+ }
+
+ ALOGV("%s: Setting device state for %s: 0x%" PRIx64,
+ __FUNCTION__, mProviderName.c_str(), mDeviceState);
+ notifyDeviceStateChange(currentDeviceState);
+
+ res = setUpVendorTags();
+ if (res != OK) {
+ ALOGE("%s: Unable to set up vendor tags from provider '%s'",
+ __FUNCTION__, mProviderName.c_str());
+ return res;
+ }
+
// Get initial list of camera devices, if any
std::vector<std::string> devices;
hardware::Return<void> ret = interface->getCameraIdList([&status, this, &devices](
@@ -1237,34 +1287,28 @@
}
}
- res = setUpVendorTags();
- if (res != OK) {
- ALOGE("%s: Unable to set up vendor tags from provider '%s'",
- __FUNCTION__, mProviderName.c_str());
- return res;
- }
-
ALOGI("Camera provider %s ready with %zu camera devices",
mProviderName.c_str(), mDevices.size());
mInitialized = true;
- if (!kEnableLazyHal) {
- // Save HAL reference indefinitely
- mSavedInterface = interface;
- }
return OK;
}
const sp<provider::V2_4::ICameraProvider>
CameraProviderManager::ProviderInfo::startProviderInterface() {
ATRACE_CALL();
- ALOGI("Request to start camera provider: %s", mProviderName.c_str());
+ ALOGV("Request to start camera provider: %s", mProviderName.c_str());
if (mSavedInterface != nullptr) {
return mSavedInterface;
}
+ if (!kEnableLazyHal) {
+ ALOGE("Bad provider state! Should not be here on a non-lazy HAL!");
+ return nullptr;
+ }
+
auto interface = mActiveInterface.promote();
if (interface == nullptr) {
- ALOGI("Could not promote, calling getService(%s)", mProviderName.c_str());
+ 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);
@@ -1277,9 +1321,22 @@
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()) {
+ 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);
+ }
+ }
+ }
+
mActiveInterface = interface;
} else {
- ALOGI("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;
}
@@ -1364,8 +1421,10 @@
}
status_t CameraProviderManager::ProviderInfo::dump(int fd, const Vector<String16>&) const {
- dprintf(fd, "== Camera Provider HAL %s (v2.4, %s) static info: %zu devices: ==\n",
- mProviderName.c_str(), mIsRemote ? "remote" : "passthrough",
+ dprintf(fd, "== Camera Provider HAL %s (v2.%d, %s) static info: %zu devices: ==\n",
+ mProviderName.c_str(),
+ mMinorVersion,
+ mIsRemote ? "remote" : "passthrough",
mDevices.size());
for (auto& device : mDevices) {
@@ -1564,6 +1623,26 @@
return OK;
}
+status_t CameraProviderManager::ProviderInfo::notifyDeviceStateChange(
+ hardware::hidl_bitfield<provider::V2_5::DeviceState> newDeviceState) {
+ mDeviceState = newDeviceState;
+ if (mMinorVersion >= 5) {
+ // Check if the provider is currently active - not going to start it up for this notification
+ auto interface = mSavedInterface != nullptr ? mSavedInterface : mActiveInterface.promote();
+ if (interface != nullptr) {
+ // Send current device state
+ 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) {
+ interface_2_5->notifyDeviceStateChange(mDeviceState);
+ }
+ }
+ }
+ }
+ return OK;
+}
+
template<class DeviceInfoT>
std::unique_ptr<CameraProviderManager::ProviderInfo::DeviceInfo>
CameraProviderManager::ProviderInfo::initializeDeviceInfo(
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.h b/services/camera/libcameraservice/common/CameraProviderManager.h
index 3173eda..a42fb4d 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.h
+++ b/services/camera/libcameraservice/common/CameraProviderManager.h
@@ -28,9 +28,8 @@
#include <camera/CameraBase.h>
#include <utils/Errors.h>
#include <android/hardware/camera/common/1.0/types.h>
-#include <android/hardware/camera/provider/2.4/ICameraProvider.h>
+#include <android/hardware/camera/provider/2.5/ICameraProvider.h>
#include <android/hardware/camera/device/3.4/ICameraDeviceSession.h>
-//#include <android/hardware/camera/provider/2.4/ICameraProviderCallbacks.h>
#include <android/hidl/manager/1.0/IServiceNotification.h>
#include <camera/VendorTagDescriptor.h>
@@ -206,6 +205,12 @@
status_t setUpVendorTags();
/**
+ * Inform registered providers about a device state change, such as folding or unfolding
+ */
+ status_t notifyDeviceStateChange(
+ android::hardware::hidl_bitfield<hardware::camera::provider::V2_5::DeviceState> newState);
+
+ /**
* Open an active session to a camera device.
*
* This fully powers on the camera device hardware, and returns a handle to a
@@ -277,6 +282,9 @@
wp<StatusListener> mListener;
ServiceInteractionProxy* mServiceProxy;
+ // Current overall Android device physical status
+ android::hardware::hidl_bitfield<hardware::camera::provider::V2_5::DeviceState> mDeviceState;
+
// mProviderLifecycleLock is locked during onRegistration and removeProvider
mutable std::mutex mProviderLifecycleLock;
@@ -303,10 +311,14 @@
{
const std::string mProviderName;
const metadata_vendor_id_t mProviderTagid;
+ int mMinorVersion;
sp<VendorTagDescriptor> mVendorTagDescriptor;
bool mSetTorchModeSupported;
bool mIsRemote;
+ // Current overall Android device physical status
+ hardware::hidl_bitfield<hardware::camera::provider::V2_5::DeviceState> mDeviceState;
+
// This pointer is used to keep a reference to the ICameraProvider that was last accessed.
wp<hardware::camera::provider::V2_4::ICameraProvider> mActiveInterface;
@@ -316,7 +328,9 @@
CameraProviderManager *manager);
~ProviderInfo();
- status_t initialize(sp<hardware::camera::provider::V2_4::ICameraProvider>& interface);
+ status_t initialize(sp<hardware::camera::provider::V2_4::ICameraProvider>& interface,
+ hardware::hidl_bitfield<hardware::camera::provider::V2_5::DeviceState>
+ currentDeviceState);
const sp<hardware::camera::provider::V2_4::ICameraProvider> startProviderInterface();
@@ -345,6 +359,13 @@
*/
status_t setUpVendorTags();
+ /**
+ * Notify provider about top-level device physical state changes
+ */
+ status_t notifyDeviceStateChange(
+ hardware::hidl_bitfield<hardware::camera::provider::V2_5::DeviceState>
+ newDeviceState);
+
// Basic device information, common to all camera devices
struct DeviceInfo {
const std::string mName; // Full instance name
diff --git a/services/camera/libcameraservice/tests/Android.mk b/services/camera/libcameraservice/tests/Android.mk
index ad9963a..d777ca1 100644
--- a/services/camera/libcameraservice/tests/Android.mk
+++ b/services/camera/libcameraservice/tests/Android.mk
@@ -29,6 +29,7 @@
libutils \
android.hardware.camera.common@1.0 \
android.hardware.camera.provider@2.4 \
+ android.hardware.camera.provider@2.5 \
android.hardware.camera.device@1.0 \
android.hardware.camera.device@3.2 \
android.hardware.camera.device@3.4
diff --git a/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp b/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp
index 0086c6c..f47e5a5 100644
--- a/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp
+++ b/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp
@@ -33,6 +33,7 @@
using android::hardware::camera::common::V1_0::CameraMetadataType;
using android::hardware::camera::device::V3_2::ICameraDeviceCallback;
using android::hardware::camera::device::V3_2::ICameraDeviceSession;
+using android::hardware::camera::provider::V2_5::DeviceState;
/**
* Basic test implementation of a camera ver. 3.2 device interface
@@ -87,7 +88,7 @@
/**
* Basic test implementation of a camera provider
*/
-struct TestICameraProvider : virtual public provider::V2_4::ICameraProvider {
+struct TestICameraProvider : virtual public provider::V2_5::ICameraProvider {
sp<provider::V2_4::ICameraProviderCallback> mCallbacks;
std::vector<hardware::hidl_string> mDeviceNames;
sp<device::V3_2::ICameraDevice> mDeviceInterface;
@@ -101,6 +102,7 @@
virtual hardware::Return<Status> setCallback(
const sp<provider::V2_4::ICameraProviderCallback>& callbacks) override {
+ mCalledCounter[SET_CALLBACK]++;
mCallbacks = callbacks;
return hardware::Return<Status>(Status::OK);
}
@@ -108,6 +110,7 @@
using getVendorTags_cb = std::function<void(Status status,
const hardware::hidl_vec<common::V1_0::VendorTagSection>& sections)>;
hardware::Return<void> getVendorTags(getVendorTags_cb _hidl_cb) override {
+ mCalledCounter[GET_VENDOR_TAGS]++;
_hidl_cb(Status::OK, mVendorTagSections);
return hardware::Void();
}
@@ -117,6 +120,7 @@
bool support)>;
virtual ::hardware::Return<void> isSetTorchModeSupported(
isSetTorchModeSupported_cb _hidl_cb) override {
+ mCalledCounter[IS_SET_TORCH_MODE_SUPPORTED]++;
_hidl_cb(Status::OK, false);
return hardware::Void();
}
@@ -124,6 +128,7 @@
using getCameraIdList_cb = std::function<void(Status status,
const hardware::hidl_vec<hardware::hidl_string>& cameraDeviceNames)>;
virtual hardware::Return<void> getCameraIdList(getCameraIdList_cb _hidl_cb) override {
+ mCalledCounter[GET_CAMERA_ID_LIST]++;
_hidl_cb(Status::OK, mDeviceNames);
return hardware::Void();
}
@@ -148,6 +153,25 @@
return hardware::Void();
}
+ virtual hardware::Return<void> notifyDeviceStateChange(
+ hardware::hidl_bitfield<DeviceState> newState) override {
+ mCalledCounter[NOTIFY_DEVICE_STATE]++;
+ mCurrentState = newState;
+ return hardware::Void();
+ }
+
+ enum MethodNames {
+ SET_CALLBACK,
+ GET_VENDOR_TAGS,
+ IS_SET_TORCH_MODE_SUPPORTED,
+ NOTIFY_DEVICE_STATE,
+ GET_CAMERA_ID_LIST,
+
+ METHOD_NAME_COUNT
+ };
+ int mCalledCounter[METHOD_NAME_COUNT] {0};
+
+ hardware::hidl_bitfield<DeviceState> mCurrentState = 0xFFFFFFFF; // Unlikely to be a real state
};
/**
@@ -209,11 +233,26 @@
res = providerManager->initialize(statusListener, &serviceProxy);
ASSERT_EQ(res, OK) << "Unable to initialize provider manager";
+ // Check that both "legacy" and "external" providers (really the same object) are called
+ // once for all the init methods
+ EXPECT_EQ(provider->mCalledCounter[TestICameraProvider::SET_CALLBACK], 2) <<
+ "Only one call to setCallback per provider expected during init";
+ EXPECT_EQ(provider->mCalledCounter[TestICameraProvider::GET_VENDOR_TAGS], 2) <<
+ "Only one call to getVendorTags per provider expected during init";
+ EXPECT_EQ(provider->mCalledCounter[TestICameraProvider::IS_SET_TORCH_MODE_SUPPORTED], 2) <<
+ "Only one call to isSetTorchModeSupported per provider expected during init";
+ EXPECT_EQ(provider->mCalledCounter[TestICameraProvider::GET_CAMERA_ID_LIST], 2) <<
+ "Only one call to getCameraIdList per provider expected during init";
+ EXPECT_EQ(provider->mCalledCounter[TestICameraProvider::NOTIFY_DEVICE_STATE], 2) <<
+ "Only one call to notifyDeviceState per provider expected during init";
std::string legacyInstanceName = "legacy/0";
std::string externalInstanceName = "external/0";
bool gotLegacy = false;
bool gotExternal = false;
+ EXPECT_EQ(2u, serviceProxy.mLastRequestedServiceNames.size()) <<
+ "Only two service queries expected to be seen by hardware service manager";
+
for (auto& serviceName : serviceProxy.mLastRequestedServiceNames) {
if (serviceName == legacyInstanceName) gotLegacy = true;
if (serviceName == externalInstanceName) gotExternal = true;
@@ -375,3 +414,35 @@
metadataCopy.dump(1, 2);
secondMetadata.dump(1, 2);
}
+
+TEST(CameraProviderManagerTest, NotifyStateChangeTest) {
+ std::vector<hardware::hidl_string> deviceNames {
+ "device@3.2/test/0",
+ "device@1.0/test/0",
+ "device@3.2/test/1"};
+
+ hardware::hidl_vec<common::V1_0::VendorTagSection> vendorSection;
+ status_t res;
+ sp<CameraProviderManager> providerManager = new CameraProviderManager();
+ sp<TestStatusListener> statusListener = new TestStatusListener();
+ TestInteractionProxy serviceProxy;
+ sp<TestICameraProvider> provider = new TestICameraProvider(deviceNames,
+ vendorSection);
+ serviceProxy.setProvider(provider);
+
+ res = providerManager->initialize(statusListener, &serviceProxy);
+ ASSERT_EQ(res, OK) << "Unable to initialize provider manager";
+
+ ASSERT_EQ(provider->mCurrentState,
+ static_cast<hardware::hidl_bitfield<DeviceState>>(DeviceState::NORMAL))
+ << "Initial device state not set";
+
+ res = providerManager->notifyDeviceStateChange(
+ static_cast<hardware::hidl_bitfield<DeviceState>>(DeviceState::FOLDED));
+
+ ASSERT_EQ(res, OK) << "Unable to call notifyDeviceStateChange";
+ ASSERT_EQ(provider->mCurrentState,
+ static_cast<hardware::hidl_bitfield<DeviceState>>(DeviceState::FOLDED))
+ << "Unable to change device state";
+
+}