Merge "MEPG4Writer:return track errors to clients" into rvc-dev
diff --git a/apex/testing/Android.bp b/apex/testing/Android.bp
index 376d3e4..a04ab3f 100644
--- a/apex/testing/Android.bp
+++ b/apex/testing/Android.bp
@@ -17,6 +17,7 @@
manifest: "test_manifest.json",
file_contexts: ":com.android.media-file_contexts",
defaults: ["com.android.media-defaults"],
+ prebuilts: ["sdkinfo_45"],
installable: false,
}
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index 79fa5ed..4520823 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -288,7 +288,7 @@
requestStop();
}
- logBufferState();
+ logReleaseBufferState();
setState(AAUDIO_STREAM_STATE_CLOSING);
aaudio_handle_t serviceStreamHandle = mServiceStreamHandle;
@@ -783,6 +783,14 @@
adjustedFrames = std::min(actualFrames, adjustedFrames);
}
+ if (adjustedFrames != mBufferSizeInFrames) {
+ android::mediametrics::LogItem(mMetricsId)
+ .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_SETBUFFERSIZE)
+ .set(AMEDIAMETRICS_PROP_BUFFERSIZEFRAMES, adjustedFrames)
+ .set(AMEDIAMETRICS_PROP_UNDERRUN, (int32_t) getXRunCount())
+ .record();
+ }
+
mBufferSizeInFrames = adjustedFrames;
ALOGV("%s(%d) returns %d", __func__, requestedFrames, adjustedFrames);
return (aaudio_result_t) adjustedFrames;
diff --git a/media/libaaudio/src/core/AudioStream.cpp b/media/libaaudio/src/core/AudioStream.cpp
index 0644368..bc973bd 100644
--- a/media/libaaudio/src/core/AudioStream.cpp
+++ b/media/libaaudio/src/core/AudioStream.cpp
@@ -116,9 +116,10 @@
}
}
-void AudioStream::logBufferState() {
+void AudioStream::logReleaseBufferState() {
if (mMetricsId.size() > 0) {
android::mediametrics::LogItem(mMetricsId)
+ .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_RELEASE)
.set(AMEDIAMETRICS_PROP_BUFFERSIZEFRAMES, (int32_t) getBufferSize())
.set(AMEDIAMETRICS_PROP_UNDERRUN, (int32_t) getXRunCount())
.record();
diff --git a/media/libaaudio/src/core/AudioStream.h b/media/libaaudio/src/core/AudioStream.h
index 613a092..fb71c36 100644
--- a/media/libaaudio/src/core/AudioStream.h
+++ b/media/libaaudio/src/core/AudioStream.h
@@ -115,7 +115,7 @@
// log to MediaMetrics
virtual void logOpen();
- void logBufferState();
+ void logReleaseBufferState();
/**
* Free any hardware or system resources from the open() call.
diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.cpp b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
index 853c0db..6e5110f 100644
--- a/media/libaaudio/src/legacy/AudioStreamRecord.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
@@ -292,7 +292,7 @@
// Then call it from here
if (getState() != AAUDIO_STREAM_STATE_CLOSING) {
mAudioRecord->removeAudioDeviceCallback(mDeviceCallback);
- logBufferState();
+ logReleaseBufferState();
mAudioRecord.clear();
mFixedBlockWriter.close();
return AudioStream::release_l();
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.cpp b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
index 1120f05..ea08361 100644
--- a/media/libaaudio/src/legacy/AudioStreamTrack.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
@@ -254,7 +254,7 @@
aaudio_result_t AudioStreamTrack::release_l() {
if (getState() != AAUDIO_STREAM_STATE_CLOSING) {
mAudioTrack->removeAudioDeviceCallback(mDeviceCallback);
- logBufferState();
+ logReleaseBufferState();
// TODO Investigate why clear() causes a hang in test_various.cpp
// if I call close() from a data callback.
// But the same thing in AudioRecord is OK!
diff --git a/media/libaaudio/tests/Android.bp b/media/libaaudio/tests/Android.bp
index a6e5f70..8935d57 100644
--- a/media/libaaudio/tests/Android.bp
+++ b/media/libaaudio/tests/Android.bp
@@ -233,6 +233,7 @@
srcs: ["test_steal_exclusive.cpp"],
shared_libs: [
"libaaudio",
+ "liblog",
"libbinder",
"libcutils",
"libutils",
diff --git a/media/libaaudio/tests/test_steal_exclusive.cpp b/media/libaaudio/tests/test_steal_exclusive.cpp
index 2a05910..05c560d 100644
--- a/media/libaaudio/tests/test_steal_exclusive.cpp
+++ b/media/libaaudio/tests/test_steal_exclusive.cpp
@@ -47,137 +47,271 @@
*/
#include <atomic>
+#include <mutex>
#include <stdio.h>
#include <thread>
#include <unistd.h>
+#include <android/log.h>
+
#include <aaudio/AAudio.h>
+#include <aaudio/AAudioTesting.h>
#define DEFAULT_TIMEOUT_NANOS ((int64_t)1000000000)
#define SOLO_DURATION_MSEC 2000
#define DUET_DURATION_MSEC 8000
#define SLEEP_DURATION_MSEC 500
+#define MODULE_NAME "stealAudio"
+#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, MODULE_NAME, __VA_ARGS__)
+
static const char * s_sharingModeToText(aaudio_sharing_mode_t mode) {
return (mode == AAUDIO_SHARING_MODE_EXCLUSIVE) ? "EXCLUSIVE"
: ((mode == AAUDIO_SHARING_MODE_SHARED) ? "SHARED"
: AAudio_convertResultToText(mode));
}
+static const char * s_performanceModeToText(aaudio_performance_mode_t mode) {
+ return (mode == AAUDIO_PERFORMANCE_MODE_LOW_LATENCY) ? "LOWLAT"
+ : ((mode == AAUDIO_PERFORMANCE_MODE_NONE) ? "NONE"
+ : AAudio_convertResultToText(mode));
+}
+
+static aaudio_data_callback_result_t s_myDataCallbackProc(
+ AAudioStream * /* stream */,
+ void *userData,
+ void *audioData,
+ int32_t numFrames);
+
static void s_myErrorCallbackProc(
AAudioStream *stream,
void *userData,
aaudio_result_t error);
-struct AudioEngine {
- AAudioStream *stream = nullptr;
- std::thread *thread = nullptr;
- aaudio_direction_t direction = AAUDIO_DIRECTION_OUTPUT;
+class AudioEngine {
+public:
+
+ AudioEngine(const char *name) {
+ mName = name;
+ }
// These counters are read and written by the callback and the main thread.
- std::atomic<int32_t> framesRead{};
std::atomic<int32_t> framesCalled{};
std::atomic<int32_t> callbackCount{};
+ std::atomic<aaudio_sharing_mode_t> sharingMode{};
+ std::atomic<aaudio_performance_mode_t> performanceMode{};
+ std::atomic<bool> isMMap{false};
+ void setMaxRetries(int maxRetries) {
+ mMaxRetries = maxRetries;
+ }
+
+ void setOpenDelayMillis(int openDelayMillis) {
+ mOpenDelayMillis = openDelayMillis;
+ }
+
+ void restartStream() {
+ int retriesLeft = mMaxRetries;
+ aaudio_result_t result;
+ do {
+ closeAudioStream();
+ if (mOpenDelayMillis) usleep(mOpenDelayMillis * 1000);
+ openAudioStream(mDirection, mRequestedSharingMode);
+ // It is possible for the stream to be disconnected, or stolen between the time
+ // it is opened and when it is started. If that happens then try again.
+ // If it was stolen then it should succeed the second time because there will already be
+ // a SHARED stream, which will not get stolen.
+ result = AAudioStream_requestStart(mStream);
+ printf("%s: AAudioStream_requestStart() returns %s\n",
+ mName.c_str(),
+ AAudio_convertResultToText(result));
+ } while (retriesLeft-- > 0 && result != AAUDIO_OK);
+ }
+
+ aaudio_data_callback_result_t onAudioReady(
+ void * /*audioData */,
+ int32_t numFrames) {
+ callbackCount++;
+ framesCalled += numFrames;
+ return AAUDIO_CALLBACK_RESULT_CONTINUE;
+ }
+
+ aaudio_result_t openAudioStream(aaudio_direction_t direction,
+ aaudio_sharing_mode_t requestedSharingMode) {
+ std::lock_guard<std::mutex> lock(mLock);
+
+ AAudioStreamBuilder *builder = nullptr;
+ mDirection = direction;
+ mRequestedSharingMode = requestedSharingMode;
+
+ // Use an AAudioStreamBuilder to contain requested parameters.
+ aaudio_result_t result = AAudio_createStreamBuilder(&builder);
+ if (result != AAUDIO_OK) {
+ printf("AAudio_createStreamBuilder returned %s",
+ AAudio_convertResultToText(result));
+ return result;
+ }
+
+ // Request stream properties.
+ AAudioStreamBuilder_setFormat(builder, AAUDIO_FORMAT_PCM_FLOAT);
+ AAudioStreamBuilder_setPerformanceMode(builder, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);
+ AAudioStreamBuilder_setSharingMode(builder, mRequestedSharingMode);
+ AAudioStreamBuilder_setDirection(builder, direction);
+ AAudioStreamBuilder_setDataCallback(builder, s_myDataCallbackProc, this);
+ AAudioStreamBuilder_setErrorCallback(builder, s_myErrorCallbackProc, this);
+
+ // Create an AAudioStream using the Builder.
+ result = AAudioStreamBuilder_openStream(builder, &mStream);
+ AAudioStreamBuilder_delete(builder);
+ builder = nullptr;
+ if (result != AAUDIO_OK) {
+ printf("AAudioStreamBuilder_openStream returned %s",
+ AAudio_convertResultToText(result));
+ }
+
+ // See what kind of stream we actually opened.
+ int32_t deviceId = AAudioStream_getDeviceId(mStream);
+ sharingMode = AAudioStream_getSharingMode(mStream);
+ performanceMode = AAudioStream_getPerformanceMode(mStream);
+ isMMap = AAudioStream_isMMapUsed(mStream);
+ printf("%s: opened: deviceId = %3d, sharingMode = %s, perf = %s, %s --------\n",
+ mName.c_str(),
+ deviceId,
+ s_sharingModeToText(sharingMode),
+ s_performanceModeToText(performanceMode),
+ (isMMap ? "MMAP" : "Legacy")
+ );
+
+ return result;
+ }
+
+ aaudio_result_t closeAudioStream() {
+ std::lock_guard<std::mutex> lock(mLock);
+ aaudio_result_t result = AAUDIO_OK;
+ if (mStream != nullptr) {
+ result = AAudioStream_close(mStream);
+ if (result != AAUDIO_OK) {
+ printf("AAudioStream_close returned %s\n",
+ AAudio_convertResultToText(result));
+ }
+ mStream = nullptr;
+ }
+ return result;
+ }
+
+ /**
+ * @return 0 is OK, -1 for error
+ */
+ int checkEnginePositions() {
+ std::lock_guard<std::mutex> lock(mLock);
+ if (mStream == nullptr) return 0;
+
+ const int64_t framesRead = AAudioStream_getFramesRead(mStream);
+ const int64_t framesWritten = AAudioStream_getFramesWritten(mStream);
+ const int32_t delta = (int32_t)(framesWritten - framesRead);
+ printf("%s: playing framesRead = %7d, framesWritten = %7d"
+ ", delta = %4d, framesCalled = %6d, callbackCount = %4d\n",
+ mName.c_str(),
+ (int32_t) framesRead,
+ (int32_t) framesWritten,
+ delta,
+ framesCalled.load(),
+ callbackCount.load()
+ );
+ if (delta > AAudioStream_getBufferCapacityInFrames(mStream)) {
+ printf("ERROR - delta > capacity\n");
+ return -1;
+ }
+ return 0;
+ }
+
+ aaudio_result_t start() {
+ std::lock_guard<std::mutex> lock(mLock);
+ reset();
+ if (mStream == nullptr) return 0;
+ return AAudioStream_requestStart(mStream);
+ }
+
+ aaudio_result_t stop() {
+ std::lock_guard<std::mutex> lock(mLock);
+ if (mStream == nullptr) return 0;
+ return AAudioStream_requestStop(mStream);
+ }
+
+ bool hasAdvanced() {
+ std::lock_guard<std::mutex> lock(mLock);
+ if (mStream == nullptr) return 0;
+ if (mDirection == AAUDIO_DIRECTION_OUTPUT) {
+ return AAudioStream_getFramesRead(mStream) > 0;
+ } else {
+ return AAudioStream_getFramesWritten(mStream) > 0;
+ }
+ }
+
+ aaudio_result_t verify() {
+ int errorCount = 0;
+ if (hasAdvanced()) {
+ printf("%s: stream is running => PASS\n", mName.c_str());
+ } else {
+ errorCount++;
+ printf("%s: stream should be running => FAIL!!\n", mName.c_str());
+ }
+
+ if (isMMap) {
+ printf("%s: data path is MMAP => PASS\n", mName.c_str());
+ } else {
+ errorCount++;
+ printf("%s: data path is Legacy! => FAIL\n", mName.c_str());
+ }
+
+ // Check for PASS/FAIL
+ if (sharingMode == AAUDIO_SHARING_MODE_SHARED) {
+ printf("%s: mode is SHARED => PASS\n", mName.c_str());
+ } else {
+ errorCount++;
+ printf("%s: modes is EXCLUSIVE => FAIL!!\n", mName.c_str());
+ }
+ return errorCount ? AAUDIO_ERROR_INVALID_FORMAT : AAUDIO_OK;
+ }
+
+private:
void reset() {
- framesRead.store(0);
framesCalled.store(0);
callbackCount.store(0);
}
+
+ AAudioStream *mStream = nullptr;
+ aaudio_direction_t mDirection = AAUDIO_DIRECTION_OUTPUT;
+ aaudio_sharing_mode_t mRequestedSharingMode = AAUDIO_UNSPECIFIED;
+ std::mutex mLock;
+ std::string mName;
+ int mMaxRetries = 1;
+ int mOpenDelayMillis = 0;
};
// Callback function that fills the audio output buffer.
static aaudio_data_callback_result_t s_myDataCallbackProc(
- AAudioStream *stream,
+ AAudioStream * /* stream */,
void *userData,
void *audioData,
int32_t numFrames
) {
- (void) audioData;
- (void) numFrames;
- AudioEngine *engine = (struct AudioEngine *)userData;
- engine->callbackCount++;
-
- engine->framesRead = (int32_t)AAudioStream_getFramesRead(stream);
- engine->framesCalled += numFrames;
- return AAUDIO_CALLBACK_RESULT_CONTINUE;
-}
-
-static aaudio_result_t s_OpenAudioStream(struct AudioEngine *engine,
- aaudio_direction_t direction) {
- AAudioStreamBuilder *builder = nullptr;
- engine->direction = direction;
-
- // Use an AAudioStreamBuilder to contain requested parameters.
- aaudio_result_t result = AAudio_createStreamBuilder(&builder);
- if (result != AAUDIO_OK) {
- printf("AAudio_createStreamBuilder returned %s",
- AAudio_convertResultToText(result));
- return result;
- }
-
- // Request stream properties.
- AAudioStreamBuilder_setFormat(builder, AAUDIO_FORMAT_PCM_FLOAT);
- AAudioStreamBuilder_setPerformanceMode(builder, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);
- AAudioStreamBuilder_setSharingMode(builder, AAUDIO_SHARING_MODE_EXCLUSIVE);
- AAudioStreamBuilder_setDirection(builder, direction);
- AAudioStreamBuilder_setDataCallback(builder, s_myDataCallbackProc, engine);
- AAudioStreamBuilder_setErrorCallback(builder, s_myErrorCallbackProc, engine);
-
- // Create an AAudioStream using the Builder.
- result = AAudioStreamBuilder_openStream(builder, &engine->stream);
- AAudioStreamBuilder_delete(builder);
- builder = nullptr;
- if (result != AAUDIO_OK) {
- printf("AAudioStreamBuilder_openStream returned %s",
- AAudio_convertResultToText(result));
- }
-
- // See see what kind of stream we actually opened.
- int32_t deviceId = AAudioStream_getDeviceId(engine->stream);
- aaudio_sharing_mode_t actualSharingMode = AAudioStream_getSharingMode(engine->stream);
- printf("-------- opened: deviceId = %3d, actualSharingMode = %s\n",
- deviceId,
- s_sharingModeToText(actualSharingMode));
-
- return result;
-}
-
-static aaudio_result_t s_CloseAudioStream(struct AudioEngine *engine) {
- aaudio_result_t result = AAUDIO_OK;
- if (engine->stream != nullptr) {
- result = AAudioStream_close(engine->stream);
- if (result != AAUDIO_OK) {
- printf("AAudioStream_close returned %s\n",
- AAudio_convertResultToText(result));
- }
- engine->stream = nullptr;
- }
- return result;
+ AudioEngine *engine = (AudioEngine *)userData;
+ return engine->onAudioReady(audioData, numFrames);
}
static void s_myRestartStreamProc(void *userData) {
+ LOGI("%s() called", __func__);
printf("%s() - restart in separate thread\n", __func__);
AudioEngine *engine = (AudioEngine *) userData;
- int retriesLeft = 1;
- aaudio_result_t result;
- do {
- s_CloseAudioStream(engine);
- s_OpenAudioStream(engine, engine->direction);
- // It is possible for the stream to be disconnected, or stolen between the time
- // it is opened and when it is started. If that happens then try again.
- // If it was stolen then it should succeed the second time because there will already be
- // a SHARED stream, which will not get stolen.
- result = AAudioStream_requestStart(engine->stream);
- printf("%s() - AAudioStream_requestStart() returns %s\n", __func__,
- AAudio_convertResultToText(result));
- } while (retriesLeft-- > 0 && result != AAUDIO_OK);
+ engine->restartStream();
}
static void s_myErrorCallbackProc(
AAudioStream * /* stream */,
void *userData,
aaudio_result_t error) {
+ LOGI("%s() called", __func__);
printf("%s() - error = %s\n", __func__, AAudio_convertResultToText(error));
// Handle error on a separate thread.
std::thread t(s_myRestartStreamProc, userData);
@@ -185,48 +319,28 @@
}
static void s_usage() {
- printf("test_steal_exclusive [-i]\n");
+ printf("test_steal_exclusive [-i] [-r{maxRetries}] [-d{delay}] -s\n");
printf(" -i direction INPUT, otherwise OUTPUT\n");
+ printf(" -d delay open by milliseconds, default = 0\n");
+ printf(" -r max retries in the error callback, default = 1\n");
+ printf(" -s try to open in SHARED mode\n");
}
-/**
- * @return 0 is OK, -1 for error
- */
-static int s_checkEnginePositions(AudioEngine *engine) {
- if (engine->stream == nullptr) return 0; // race condition with onError procs!
-
- const int64_t framesRead = AAudioStream_getFramesRead(engine->stream);
- const int64_t framesWritten = AAudioStream_getFramesWritten(engine->stream);
- const int32_t delta = (int32_t)(framesWritten - framesRead);
- printf("playing framesRead = %7d, framesWritten = %7d"
- ", delta = %4d, framesCalled = %6d, callbackCount = %4d\n",
- (int32_t) framesRead,
- (int32_t) framesWritten,
- delta,
- engine->framesCalled.load(),
- engine->callbackCount.load()
- );
- if (delta > AAudioStream_getBufferCapacityInFrames(engine->stream)) {
- printf("ERROR - delta > capacity\n");
- return -1;
- }
- return 0;
-}
-
-int main(int argc, char **argv) {
- (void) argc;
- (void) argv;
- struct AudioEngine victim;
- struct AudioEngine thief;
+int main(int argc, char ** argv) {
+ AudioEngine victim("victim");
+ AudioEngine thief("thief");
aaudio_direction_t direction = AAUDIO_DIRECTION_OUTPUT;
aaudio_result_t result = AAUDIO_OK;
int errorCount = 0;
+ int maxRetries = 1;
+ int openDelayMillis = 0;
+ aaudio_sharing_mode_t requestedSharingMode = AAUDIO_SHARING_MODE_EXCLUSIVE;
// 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("Test Stealing an EXCLUSIVE stream V1.0\n");
+ printf("Test interaction between streams V1.1\n");
printf("\n");
for (int i = 1; i < argc; i++) {
@@ -234,9 +348,18 @@
if (arg[0] == '-') {
char option = arg[1];
switch (option) {
+ case 'd':
+ openDelayMillis = atoi(&arg[2]);
+ break;
case 'i':
direction = AAUDIO_DIRECTION_INPUT;
break;
+ case 'r':
+ maxRetries = atoi(&arg[2]);
+ break;
+ case 's':
+ requestedSharingMode = AAUDIO_SHARING_MODE_SHARED;
+ break;
default:
s_usage();
exit(EXIT_FAILURE);
@@ -249,16 +372,35 @@
}
}
- result = s_OpenAudioStream(&victim, direction);
+ victim.setOpenDelayMillis(openDelayMillis);
+ thief.setOpenDelayMillis(openDelayMillis);
+ victim.setMaxRetries(maxRetries);
+ thief.setMaxRetries(maxRetries);
+
+ result = victim.openAudioStream(direction, requestedSharingMode);
if (result != AAUDIO_OK) {
printf("s_OpenAudioStream victim returned %s\n",
AAudio_convertResultToText(result));
errorCount++;
}
- victim.reset();
+
+ if (victim.sharingMode == requestedSharingMode) {
+ printf("Victim modes is %s => OK\n", s_sharingModeToText(requestedSharingMode));
+ } else {
+ printf("Victim modes should be %s => test not valid!\n",
+ s_sharingModeToText(requestedSharingMode));
+ goto onerror;
+ }
+
+ if (victim.isMMap) {
+ printf("Victim data path is MMAP => OK\n");
+ } else {
+ printf("Victim data path is Legacy! => test not valid\n");
+ goto onerror;
+ }
// Start stream.
- result = AAudioStream_requestStart(victim.stream);
+ result = victim.start();
printf("AAudioStream_requestStart(VICTIM) returned %d >>>>>>>>>>>>>>>>>>>>>>\n", result);
if (result != AAUDIO_OK) {
errorCount++;
@@ -267,77 +409,69 @@
if (result == AAUDIO_OK) {
const int watchLoops = SOLO_DURATION_MSEC / SLEEP_DURATION_MSEC;
for (int i = watchLoops; i > 0; i--) {
- errorCount += s_checkEnginePositions(&victim) ? 1 : 0;
+ errorCount += victim.checkEnginePositions() ? 1 : 0;
usleep(SLEEP_DURATION_MSEC * 1000);
}
}
- printf("Try to start the THIEF stream that may steal the VICTIM MMAP resource -----\n");
- result = s_OpenAudioStream(&thief, direction);
+ printf("Trying to start the THIEF stream, which may steal the VICTIM MMAP resource -----\n");
+ result = thief.openAudioStream(direction, requestedSharingMode);
if (result != AAUDIO_OK) {
printf("s_OpenAudioStream victim returned %s\n",
AAudio_convertResultToText(result));
errorCount++;
}
- thief.reset();
// Start stream.
- result = AAudioStream_requestStart(thief.stream);
+ result = thief.start();
printf("AAudioStream_requestStart(THIEF) returned %d >>>>>>>>>>>>>>>>>>>>>>\n", result);
if (result != AAUDIO_OK) {
errorCount++;
}
- printf("You might enjoy plugging in a headset now to see what happens...\n");
+
+ // Give stream time to advance.
+ usleep(SLEEP_DURATION_MSEC * 1000);
+
+ if (victim.verify()) {
+ errorCount++;
+ goto onerror;
+ }
+ if (thief.verify()) {
+ errorCount++;
+ goto onerror;
+ }
+
+ LOGI("Both streams running. Ask user to plug in headset. ====");
+ printf("\n====\nPlease PLUG IN A HEADSET now!\n====\n\n");
if (result == AAUDIO_OK) {
const int watchLoops = DUET_DURATION_MSEC / SLEEP_DURATION_MSEC;
for (int i = watchLoops; i > 0; i--) {
- printf("victim: ");
- errorCount += s_checkEnginePositions(&victim) ? 1 : 0;
- printf(" thief: ");
- errorCount += s_checkEnginePositions(&thief) ? 1 : 0;
+ errorCount += victim.checkEnginePositions() ? 1 : 0;
+ errorCount += thief.checkEnginePositions() ? 1 : 0;
usleep(SLEEP_DURATION_MSEC * 1000);
}
}
- // Check for PASS/FAIL
- aaudio_sharing_mode_t victimSharingMode = AAudioStream_getSharingMode(victim.stream);
- aaudio_sharing_mode_t thiefSharingMode = AAudioStream_getSharingMode(thief.stream);
- printf("victimSharingMode = %s, thiefSharingMode = %s, - ",
- s_sharingModeToText(victimSharingMode),
- s_sharingModeToText(thiefSharingMode));
- if ((victimSharingMode == AAUDIO_SHARING_MODE_SHARED)
- && (thiefSharingMode == AAUDIO_SHARING_MODE_SHARED)) {
- printf("Both modes are SHARED => PASS\n");
- } else {
- errorCount++;
- printf("Both modes should be SHARED => FAIL!!\n");
- }
+ errorCount += victim.verify() ? 1 : 0;
+ errorCount += thief.verify() ? 1 : 0;
- const int64_t victimFramesRead = AAudioStream_getFramesRead(victim.stream);
- const int64_t thiefFramesRead = AAudioStream_getFramesRead(thief.stream);
- printf("victimFramesRead = %d, thiefFramesRead = %d, - ",
- (int)victimFramesRead, (int)thiefFramesRead);
- if (victimFramesRead > 0 && thiefFramesRead > 0) {
- printf("Both streams are running => PASS\n");
- } else {
- errorCount++;
- printf("Both streams should be running => FAIL!!\n");
- }
-
- result = AAudioStream_requestStop(victim.stream);
+ result = victim.stop();
printf("AAudioStream_requestStop() returned %d <<<<<<<<<<<<<<<<<<<<<\n", result);
if (result != AAUDIO_OK) {
+ printf("stop result = %d = %s\n", result, AAudio_convertResultToText(result));
errorCount++;
}
- result = AAudioStream_requestStop(thief.stream);
+ result = thief.stop();
printf("AAudioStream_requestStop() returned %d <<<<<<<<<<<<<<<<<<<<<\n", result);
if (result != AAUDIO_OK) {
+ printf("stop result = %d = %s\n", result, AAudio_convertResultToText(result));
errorCount++;
}
- s_CloseAudioStream(&victim);
- s_CloseAudioStream(&thief);
+onerror:
+ victim.closeAudioStream();
+ thief.closeAudioStream();
printf("aaudio result = %d = %s\n", result, AAudio_convertResultToText(result));
printf("test %s\n", errorCount ? "FAILED" : "PASSED");
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index 604d182..005d358 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -787,8 +787,9 @@
.set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_STOP)
.set(AMEDIAMETRICS_PROP_EXECUTIONTIMENS, (int64_t)(systemTime() - beginNs))
.set(AMEDIAMETRICS_PROP_STATE, stateToString(mState))
+ .set(AMEDIAMETRICS_PROP_BUFFERSIZEFRAMES, (int32_t)mProxy->getBufferSizeInFrames())
+ .set(AMEDIAMETRICS_PROP_UNDERRUN, (int32_t) getUnderrunCount_l())
.record();
- logBufferSizeUnderruns();
});
ALOGV("%s(%d): prior state:%s", __func__, mPortId, stateToString(mState));
@@ -1141,16 +1142,6 @@
return NO_ERROR;
}
-void AudioTrack::logBufferSizeUnderruns() {
- LOG_ALWAYS_FATAL_IF(mMetricsId.size() == 0, "mMetricsId is empty!");
- ALOGD("%s(), mMetricsId = %s", __func__, mMetricsId.c_str());
- // FIXME THis hangs! Why?
-// android::mediametrics::LogItem(mMetricsId)
-// .set(AMEDIAMETRICS_PROP_BUFFERSIZEFRAMES, (int32_t) getBufferSizeInFrames())
-// .set(AMEDIAMETRICS_PROP_UNDERRUN, (int32_t) getUnderrunCount())
-// .record();
-}
-
ssize_t AudioTrack::setBufferSizeInFrames(size_t bufferSizeInFrames)
{
AutoMutex lock(mLock);
@@ -1165,7 +1156,11 @@
ssize_t originalBufferSize = mProxy->getBufferSizeInFrames();
ssize_t finalBufferSize = mProxy->setBufferSizeInFrames((uint32_t) bufferSizeInFrames);
if (originalBufferSize != finalBufferSize) {
- logBufferSizeUnderruns();
+ android::mediametrics::LogItem(mMetricsId)
+ .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_SETBUFFERSIZE)
+ .set(AMEDIAMETRICS_PROP_BUFFERSIZEFRAMES, (int32_t)mProxy->getBufferSizeInFrames())
+ .set(AMEDIAMETRICS_PROP_UNDERRUN, (int32_t)getUnderrunCount_l())
+ .record();
}
return finalBufferSize;
}
diff --git a/media/libaudioclient/include/media/AudioTrack.h b/media/libaudioclient/include/media/AudioTrack.h
index 17af7d4..0dbd842 100644
--- a/media/libaudioclient/include/media/AudioTrack.h
+++ b/media/libaudioclient/include/media/AudioTrack.h
@@ -1274,8 +1274,6 @@
std::string mMetricsId; // GUARDED_BY(mLock), could change in createTrack_l().
std::string mCallerName; // for example "aaudio"
- void logBufferSizeUnderruns();
-
private:
class AudioTrackCallback : public media::BnAudioTrackCallback {
public:
diff --git a/media/libmediametrics/include/MediaMetricsConstants.h b/media/libmediametrics/include/MediaMetricsConstants.h
index b916a78..0906411 100644
--- a/media/libmediametrics/include/MediaMetricsConstants.h
+++ b/media/libmediametrics/include/MediaMetricsConstants.h
@@ -175,10 +175,12 @@
#define AMEDIAMETRICS_PROP_EVENT_VALUE_OPEN "open"
#define AMEDIAMETRICS_PROP_EVENT_VALUE_PAUSE "pause" // AudioTrack
#define AMEDIAMETRICS_PROP_EVENT_VALUE_READPARAMETERS "readParameters" // Thread
+#define AMEDIAMETRICS_PROP_EVENT_VALUE_RELEASE "release"
#define AMEDIAMETRICS_PROP_EVENT_VALUE_RESTORE "restore"
#define AMEDIAMETRICS_PROP_EVENT_VALUE_SETMODE "setMode" // AudioFlinger
+#define AMEDIAMETRICS_PROP_EVENT_VALUE_SETBUFFERSIZE "setBufferSize" // AudioTrack
#define AMEDIAMETRICS_PROP_EVENT_VALUE_SETPLAYBACKPARAM "setPlaybackParam" // AudioTrack
-#define AMEDIAMETRICS_PROP_EVENT_VALUE_SETVOICEVOLUME "setVoiceVolume" // AudioFlinger
+#define AMEDIAMETRICS_PROP_EVENT_VALUE_SETVOICEVOLUME "setVoiceVolume" // AudioFlinger
#define AMEDIAMETRICS_PROP_EVENT_VALUE_SETVOLUME "setVolume" // AudioTrack
#define AMEDIAMETRICS_PROP_EVENT_VALUE_START "start" // AudioTrack, AudioRecord
#define AMEDIAMETRICS_PROP_EVENT_VALUE_STOP "stop" // AudioTrack, AudioRecord
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index 0eaa503..e6bb2e1 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -1159,7 +1159,7 @@
readBuffer(MEDIA_TRACK_TYPE_VIDEO, seekTimeUs, mode, &actualTimeUs);
if (mode != MediaPlayerSeekMode::SEEK_CLOSEST) {
- seekTimeUs = actualTimeUs;
+ seekTimeUs = std::max<int64_t>(0, actualTimeUs);
}
mVideoLastDequeueTimeUs = actualTimeUs;
}
diff --git a/media/libstagefright/ACodecBufferChannel.cpp b/media/libstagefright/ACodecBufferChannel.cpp
index fa13f32..88b15ae 100644
--- a/media/libstagefright/ACodecBufferChannel.cpp
+++ b/media/libstagefright/ACodecBufferChannel.cpp
@@ -22,11 +22,14 @@
#include <C2Buffer.h>
+#include <Codec2BufferUtils.h>
+
#include <android/hardware/cas/native/1.0/IDescrambler.h>
#include <android/hardware/drm/1.0/types.h>
#include <binder/MemoryDealer.h>
#include <hidlmemory/FrameworkUtils.h>
#include <media/openmax/OMX_Core.h>
+#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/foundation/AUtils.h>
#include <media/stagefright/MediaCodec.h>
@@ -91,15 +94,27 @@
}
status_t ACodecBufferChannel::queueInputBuffer(const sp<MediaCodecBuffer> &buffer) {
- if (mDealer != nullptr) {
- return -ENOSYS;
- }
std::shared_ptr<const std::vector<const BufferInfo>> array(
std::atomic_load(&mInputBuffers));
BufferInfoIterator it = findClientBuffer(array, buffer);
if (it == array->end()) {
return -ENOENT;
}
+ if (it->mClientBuffer != it->mCodecBuffer) {
+ // Copy metadata from client to codec buffer.
+ it->mCodecBuffer->meta()->clear();
+ int64_t timeUs;
+ CHECK(it->mClientBuffer->meta()->findInt64("timeUs", &timeUs));
+ it->mCodecBuffer->meta()->setInt64("timeUs", timeUs);
+ int32_t eos;
+ if (it->mClientBuffer->meta()->findInt32("eos", &eos)) {
+ it->mCodecBuffer->meta()->setInt32("eos", eos);
+ }
+ int32_t csd;
+ if (it->mClientBuffer->meta()->findInt32("csd", &csd)) {
+ it->mCodecBuffer->meta()->setInt32("csd", csd);
+ }
+ }
ALOGV("queueInputBuffer #%d", it->mBufferId);
sp<AMessage> msg = mInputBufferFilled->dup();
msg->setObject("buffer", it->mCodecBuffer);
@@ -267,16 +282,30 @@
}
C2ConstLinearBlock block{c2Buffer->data().linearBlocks().front()};
C2ReadView view{block.map().get()};
- if (view.capacity() > buffer->capacity()) {
- return -ENOSYS;
- }
- memcpy(buffer->base(), view.data(), view.capacity());
- buffer->setRange(0, view.capacity());
+ size_t copyLength = std::min(size_t(view.capacity()), buffer->capacity());
+ ALOGV_IF(view.capacity() > buffer->capacity(),
+ "view.capacity() = %zu, buffer->capacity() = %zu",
+ view.capacity(), buffer->capacity());
+ memcpy(buffer->base(), view.data(), copyLength);
+ buffer->setRange(0, copyLength);
break;
}
case C2BufferData::GRAPHIC: {
- // TODO
- return -ENOSYS;
+ sp<ABuffer> imageData;
+ if (!buffer->format()->findBuffer("image-data", &imageData)) {
+ return -ENOSYS;
+ }
+ if (c2Buffer->data().graphicBlocks().size() != 1u) {
+ return -ENOSYS;
+ }
+ C2ConstGraphicBlock block{c2Buffer->data().graphicBlocks().front()};
+ const C2GraphicView view{block.map().get()};
+ status_t err = ImageCopy(
+ buffer->base(), (const MediaImage2 *)(imageData->base()), view);
+ if (err != OK) {
+ return err;
+ }
+ break;
}
case C2BufferData::LINEAR_CHUNKS: [[fallthrough]];
case C2BufferData::GRAPHIC_CHUNKS: [[fallthrough]];
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index 3e49bae..3bccb7b 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -273,6 +273,7 @@
"libutils",
"libmedia_helper",
"libsfplugin_ccodec",
+ "libsfplugin_ccodec_utils",
"libstagefright_codecbase",
"libstagefright_foundation",
"libstagefright_omx_utils",
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 7f5e762..983fa56 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -2496,6 +2496,18 @@
}
break;
}
+ if (!mLeftover.empty()) {
+ ssize_t index = dequeuePortBuffer(kPortIndexInput);
+ CHECK_GE(index, 0);
+
+ status_t err = handleLeftover(index);
+ if (err != OK) {
+ setStickyError(err);
+ postActivityNotificationIfPossible();
+ cancelPendingDequeueOperations();
+ }
+ break;
+ }
if (mFlags & kFlagIsAsync) {
if (!mHaveInputSurface) {
@@ -3185,7 +3197,15 @@
break;
}
- status_t err = onQueueInputBuffer(msg);
+ status_t err = UNKNOWN_ERROR;
+ if (!mLeftover.empty()) {
+ mLeftover.push_back(msg);
+ size_t index;
+ msg->findSize("index", &index);
+ err = handleLeftover(index);
+ } else {
+ err = onQueueInputBuffer(msg);
+ }
PostReplyWithError(replyID, err);
break;
@@ -3472,8 +3492,8 @@
sp<hardware::HidlMemory> memory;
size_t offset = 0;
- if ((mFlags & kFlagUseBlockModel) && mOwnerName.startsWith("codec2::")) {
- if (mCrypto) {
+ if (mFlags & kFlagUseBlockModel) {
+ if (hasCryptoOrDescrambler()) {
constexpr size_t kInitialDealerCapacity = 1048576; // 1MB
thread_local sp<MemoryDealer> sDealer = new MemoryDealer(
kInitialDealerCapacity, "CSD(1MB)");
@@ -3598,6 +3618,9 @@
CHECK(portIndex == kPortIndexInput || portIndex == kPortIndexOutput);
Mutex::Autolock al(mBufferLock);
+ if (portIndex == kPortIndexInput) {
+ mLeftover.clear();
+ }
for (size_t i = 0; i < mPortBuffers[portIndex].size(); ++i) {
BufferInfo *info = &mPortBuffers[portIndex][i];
@@ -3728,7 +3751,26 @@
err = mBufferChannel->attachEncryptedBuffer(
memory, (mFlags & kFlagIsSecure), key, iv, mode, pattern,
offset, subSamples, numSubSamples, buffer);
+ } else {
+ err = UNKNOWN_ERROR;
}
+
+ if (err == OK && !buffer->asC2Buffer()
+ && c2Buffer && c2Buffer->data().type() == C2BufferData::LINEAR) {
+ C2ConstLinearBlock block{c2Buffer->data().linearBlocks().front()};
+ if (block.size() > buffer->size()) {
+ C2ConstLinearBlock leftover = block.subBlock(
+ block.offset() + buffer->size(), block.size() - buffer->size());
+ sp<WrapperObject<std::shared_ptr<C2Buffer>>> obj{
+ new WrapperObject<std::shared_ptr<C2Buffer>>{
+ C2Buffer::CreateLinearBuffer(leftover)}};
+ msg->setObject("c2buffer", obj);
+ mLeftover.push_front(msg);
+ // Not sending EOS if we have leftovers
+ flags &= ~BUFFER_FLAG_EOS;
+ }
+ }
+
offset = buffer->offset();
size = buffer->size();
if (err != OK) {
@@ -3793,6 +3835,16 @@
return err;
}
+status_t MediaCodec::handleLeftover(size_t index) {
+ if (mLeftover.empty()) {
+ return OK;
+ }
+ sp<AMessage> msg = mLeftover.front();
+ mLeftover.pop_front();
+ msg->setSize("index", index);
+ return onQueueInputBuffer(msg);
+}
+
//static
size_t MediaCodec::CreateFramesRenderedMessage(
const std::list<FrameRenderTracker::Info> &done, sp<AMessage> &msg) {
diff --git a/media/libstagefright/include/media/stagefright/MediaCodec.h b/media/libstagefright/include/media/stagefright/MediaCodec.h
index 7f308c0..02ab4c0 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodec.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodec.h
@@ -515,6 +515,9 @@
class ReleaseSurface;
std::unique_ptr<ReleaseSurface> mReleaseSurface;
+ std::list<sp<AMessage>> mLeftover;
+ status_t handleLeftover(size_t index);
+
sp<BatteryChecker> mBatteryChecker;
void statsBufferSent(int64_t presentationUs);
diff --git a/services/audioflinger/FastCapture.cpp b/services/audioflinger/FastCapture.cpp
index dd84bf2..d6d6e25 100644
--- a/services/audioflinger/FastCapture.cpp
+++ b/services/audioflinger/FastCapture.cpp
@@ -154,7 +154,7 @@
mReadBufferState = -1;
dumpState->mFrameCount = frameCount;
}
-
+ dumpState->mSilenced = current->mSilenceCapture;
}
void FastCapture::onWork()
@@ -208,6 +208,9 @@
mReadBufferState = frameCount;
}
if (mReadBufferState > 0) {
+ if (current->mSilenceCapture) {
+ memset(mReadBuffer, 0, mReadBufferState * Format_frameSize(mFormat));
+ }
ssize_t framesWritten = mPipeSink->write(mReadBuffer, mReadBufferState);
audio_track_cblk_t* cblk = current->mCblk;
if (fastPatchRecordBufferProvider != 0) {
diff --git a/services/audioflinger/FastCaptureDumpState.cpp b/services/audioflinger/FastCaptureDumpState.cpp
index 53eeba5..b8b3866 100644
--- a/services/audioflinger/FastCaptureDumpState.cpp
+++ b/services/audioflinger/FastCaptureDumpState.cpp
@@ -44,10 +44,11 @@
double periodSec = (double) mFrameCount / mSampleRate;
dprintf(fd, " FastCapture command=%s readSequence=%u framesRead=%u\n"
" readErrors=%u sampleRate=%u frameCount=%zu\n"
- " measuredWarmup=%.3g ms, warmupCycles=%u period=%.2f ms\n",
+ " measuredWarmup=%.3g ms, warmupCycles=%u period=%.2f ms\n"
+ " silenced: %s\n",
FastCaptureState::commandToString(mCommand), mReadSequence, mFramesRead,
mReadErrors, mSampleRate, mFrameCount, measuredWarmupMs, mWarmupCycles,
- periodSec * 1e3);
+ periodSec * 1e3, mSilenced ? "true" : "false");
}
} // android
diff --git a/services/audioflinger/FastCaptureDumpState.h b/services/audioflinger/FastCaptureDumpState.h
index 6f9c4c3..a1b8706 100644
--- a/services/audioflinger/FastCaptureDumpState.h
+++ b/services/audioflinger/FastCaptureDumpState.h
@@ -35,6 +35,7 @@
uint32_t mReadErrors; // total number of read() errors
uint32_t mSampleRate;
size_t mFrameCount;
+ bool mSilenced = false; // capture is silenced
};
} // android
diff --git a/services/audioflinger/FastCaptureState.h b/services/audioflinger/FastCaptureState.h
index d287232..f949275 100644
--- a/services/audioflinger/FastCaptureState.h
+++ b/services/audioflinger/FastCaptureState.h
@@ -41,6 +41,8 @@
audio_format_t mFastPatchRecordFormat = AUDIO_FORMAT_INVALID;
AudioBufferProvider* mFastPatchRecordBufferProvider = nullptr; // a reference to a patch
// record in fast mode
+ bool mSilenceCapture = false; // request to silence capture for fast track.
+ // note: this also silences the normal mixer pipe
// Extends FastThreadState::Command
static const Command
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 4a4899f..024168b 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -7089,6 +7089,8 @@
// reference to a fast track which is about to be removed
sp<RecordTrack> fastTrackToRemove;
+ bool silenceFastCapture = false;
+
{ // scope for mLock
Mutex::Autolock _l(mLock);
@@ -7176,14 +7178,33 @@
__func__, activeTrackState, activeTrack->id(), size);
}
- activeTracks.add(activeTrack);
- i++;
-
if (activeTrack->isFastTrack()) {
ALOG_ASSERT(!mFastTrackAvail);
ALOG_ASSERT(fastTrack == 0);
+ // if the active fast track is silenced either:
+ // 1) silence the whole capture from fast capture buffer if this is
+ // the only active track
+ // 2) invalidate this track: this will cause the client to reconnect and possibly
+ // be invalidated again until unsilenced
+ if (activeTrack->isSilenced()) {
+ if (size > 1) {
+ activeTrack->invalidate();
+ ALOG_ASSERT(fastTrackToRemove == 0);
+ fastTrackToRemove = activeTrack;
+ removeTrack_l(activeTrack);
+ mActiveTracks.remove(activeTrack);
+ size--;
+ continue;
+ } else {
+ silenceFastCapture = true;
+ }
+ }
fastTrack = activeTrack;
}
+
+ activeTracks.add(activeTrack);
+ i++;
+
}
mActiveTracks.updatePowerState(this);
@@ -7257,6 +7278,10 @@
AUDIO_FORMAT_INVALID : fastTrack->format();
didModify = true;
}
+ if (state->mSilenceCapture != silenceFastCapture) {
+ state->mSilenceCapture = silenceFastCapture;
+ didModify = true;
+ }
sq->end(didModify);
if (didModify) {
sq->push(block);
@@ -7341,8 +7366,10 @@
// Update server timestamp with server stats
// systemTime() is optional if the hardware supports timestamps.
- mTimestamp.mPosition[ExtendedTimestamp::LOCATION_SERVER] += framesRead;
- mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_SERVER] = lastIoEndNs;
+ if (framesRead >= 0) {
+ mTimestamp.mPosition[ExtendedTimestamp::LOCATION_SERVER] += framesRead;
+ mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_SERVER] = lastIoEndNs;
+ }
// Update server timestamp with kernel stats
if (mPipeSource.get() == nullptr /* don't obtain for FastCapture, could block */) {
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 2a9a4c4..f05be06 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -3820,7 +3820,11 @@
ALOGE("%s output not found for id %d", __func__, patch->sources[0].id);
return BAD_VALUE;
}
- // Reset handle so that setOutputDevice will force new AF patch to reach the sink
+ if (patchDesc->getHandle() != outputDesc->getPatchHandle()) {
+ // force SwOutput patch removal as AF counter part patch has already gone.
+ ALOGV("%s reset patch handle on Output as different from SWBridge", __func__);
+ removeAudioPatch(outputDesc->getPatchHandle());
+ }
outputDesc->setPatchHandle(AUDIO_PATCH_HANDLE_NONE);
setOutputDevices(outputDesc,
getNewOutputDevices(outputDesc, true /*fromCache*/),
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index b00a2d9..deeec7e 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -1777,13 +1777,6 @@
mStatusChanged.broadcast();
}
-void Camera3Device::pauseStateNotify(bool enable) {
- Mutex::Autolock il(mInterfaceLock);
- Mutex::Autolock l(mLock);
-
- mPauseStateNotify = enable;
-}
-
// Pause to reconfigure
status_t Camera3Device::internalPauseAndWaitLocked(nsecs_t maxExpectedDuration) {
if (mRequestThread.get() != nullptr) {
@@ -2359,7 +2352,7 @@
return false;
}
-bool Camera3Device::reconfigureCamera(const CameraMetadata& sessionParams) {
+bool Camera3Device::reconfigureCamera(const CameraMetadata& sessionParams, int clientStatusId) {
ATRACE_CALL();
bool ret = false;
@@ -2373,7 +2366,16 @@
return true;
}
- auto rc = internalPauseAndWaitLocked(maxExpectedDuration);
+ status_t rc = NO_ERROR;
+ bool markClientActive = false;
+ if (mStatus == STATUS_ACTIVE) {
+ markClientActive = true;
+ mPauseStateNotify = true;
+ mStatusTracker->markComponentIdle(clientStatusId, Fence::NO_FENCE);
+
+ rc = internalPauseAndWaitLocked(maxExpectedDuration);
+ }
+
if (rc == NO_ERROR) {
mNeedConfig = true;
rc = configureStreamsLocked(mOperatingMode, sessionParams, /*notifyRequestThread*/ false);
@@ -2401,6 +2403,10 @@
ALOGE("%s: Failed to pause streaming: %d", __FUNCTION__, rc);
}
+ if (markClientActive) {
+ mStatusTracker->markComponentActive(clientStatusId);
+ }
+
return ret;
}
@@ -4277,22 +4283,11 @@
}
if (res == OK) {
- sp<StatusTracker> statusTracker = mStatusTracker.promote();
- if (statusTracker != 0) {
- sp<Camera3Device> parent = mParent.promote();
- if (parent != nullptr) {
- parent->pauseStateNotify(true);
- }
-
- statusTracker->markComponentIdle(mStatusId, Fence::NO_FENCE);
-
- if (parent != nullptr) {
- mReconfigured |= parent->reconfigureCamera(mLatestSessionParams);
- }
-
- statusTracker->markComponentActive(mStatusId);
- setPaused(false);
+ sp<Camera3Device> parent = mParent.promote();
+ if (parent != nullptr) {
+ mReconfigured |= parent->reconfigureCamera(mLatestSessionParams, mStatusId);
}
+ setPaused(false);
if (mNextRequests[0].captureRequest->mInputStream != nullptr) {
mNextRequests[0].captureRequest->mInputStream->restoreConfiguredState();
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index c059f55..2069841 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -638,17 +638,10 @@
const SurfaceMap &surfaceMap);
/**
- * Pause state updates to the client application. Needed to mask out idle/active
- * transitions during internal reconfigure
- */
- void pauseStateNotify(bool enable);
-
- /**
* Internally re-configure camera device using new session parameters.
- * This will get triggered by the request thread. Be sure to call
- * pauseStateNotify(true) before going idle in the requesting location.
+ * This will get triggered by the request thread.
*/
- bool reconfigureCamera(const CameraMetadata& sessionParams);
+ bool reconfigureCamera(const CameraMetadata& sessionParams, int clientStatusId);
/**
* Return true in case of any output or input abandoned streams,
diff --git a/services/oboeservice/AAudioClientTracker.cpp b/services/oboeservice/AAudioClientTracker.cpp
index 6e14434..9d9ca63 100644
--- a/services/oboeservice/AAudioClientTracker.cpp
+++ b/services/oboeservice/AAudioClientTracker.cpp
@@ -106,18 +106,9 @@
aaudio_result_t
AAudioClientTracker::registerClientStream(pid_t pid, sp<AAudioServiceStreamBase> serviceStream) {
- aaudio_result_t result = AAUDIO_OK;
ALOGV("registerClientStream(%d,)\n", pid);
std::lock_guard<std::mutex> lock(mLock);
- sp<NotificationClient> notificationClient = mNotificationClients[pid];
- if (notificationClient == 0) {
- // This will get called the first time the audio server registers an internal stream.
- ALOGV("registerClientStream(%d,) unrecognized pid\n", pid);
- notificationClient = new NotificationClient(pid, nullptr);
- mNotificationClients[pid] = notificationClient;
- }
- notificationClient->registerClientStream(serviceStream);
- return result;
+ return getNotificationClient_l(pid)->registerClientStream(serviceStream);
}
// Find the tracker for this process and remove it.
@@ -136,6 +127,33 @@
return AAUDIO_OK;
}
+void AAudioClientTracker::setExclusiveEnabled(pid_t pid, bool enabled) {
+ ALOGD("%s(%d, %d)\n", __func__, pid, enabled);
+ std::lock_guard<std::mutex> lock(mLock);
+ getNotificationClient_l(pid)->setExclusiveEnabled(enabled);
+}
+
+bool AAudioClientTracker::isExclusiveEnabled(pid_t pid) {
+ std::lock_guard<std::mutex> lock(mLock);
+ return getNotificationClient_l(pid)->isExclusiveEnabled();
+}
+
+sp<AAudioClientTracker::NotificationClient>
+ AAudioClientTracker::getNotificationClient_l(pid_t pid) {
+ sp<NotificationClient> notificationClient = mNotificationClients[pid];
+ if (notificationClient == nullptr) {
+ // This will get called the first time the audio server uses this PID.
+ ALOGV("%s(%d,) unrecognized PID\n", __func__, pid);
+ notificationClient = new AAudioClientTracker::NotificationClient(pid, nullptr);
+ mNotificationClients[pid] = notificationClient;
+ }
+ return notificationClient;
+}
+
+// =======================================
+// AAudioClientTracker::NotificationClient
+// =======================================
+
AAudioClientTracker::NotificationClient::NotificationClient(pid_t pid, const sp<IBinder>& binder)
: mProcessId(pid), mBinder(binder) {
}
diff --git a/services/oboeservice/AAudioClientTracker.h b/services/oboeservice/AAudioClientTracker.h
index 00ff467..943b809 100644
--- a/services/oboeservice/AAudioClientTracker.h
+++ b/services/oboeservice/AAudioClientTracker.h
@@ -58,6 +58,15 @@
aaudio_result_t unregisterClientStream(pid_t pid,
android::sp<AAudioServiceStreamBase> serviceStream);
+ /**
+ * Specify whether a process is allowed to create an EXCLUSIVE MMAP stream.
+ * @param pid
+ * @param enabled
+ */
+ void setExclusiveEnabled(pid_t pid, bool enabled);
+
+ bool isExclusiveEnabled(pid_t pid);
+
android::AAudioService *getAAudioService() const {
return mAAudioService;
}
@@ -84,17 +93,29 @@
aaudio_result_t unregisterClientStream(android::sp<AAudioServiceStreamBase> serviceStream);
+ void setExclusiveEnabled(bool enabled) {
+ mExclusiveEnabled = enabled;
+ }
+
+ bool isExclusiveEnabled() {
+ return mExclusiveEnabled;
+ }
+
// IBinder::DeathRecipient
virtual void binderDied(const android::wp<IBinder>& who);
- protected:
+ private:
mutable std::mutex mLock;
const pid_t mProcessId;
std::set<android::sp<AAudioServiceStreamBase>> mStreams;
// hold onto binder to receive death notifications
android::sp<IBinder> mBinder;
+ bool mExclusiveEnabled = true;
};
+ // This must be called under mLock
+ android::sp<NotificationClient> getNotificationClient_l(pid_t pid);
+
mutable std::mutex mLock;
std::map<pid_t, android::sp<NotificationClient>> mNotificationClients;
android::AAudioService *mAAudioService = nullptr;
diff --git a/services/oboeservice/AAudioEndpointManager.cpp b/services/oboeservice/AAudioEndpointManager.cpp
index c9bf72f..9f34153 100644
--- a/services/oboeservice/AAudioEndpointManager.cpp
+++ b/services/oboeservice/AAudioEndpointManager.cpp
@@ -25,6 +25,7 @@
#include <sstream>
#include <utility/AAudioUtilities.h>
+#include "AAudioClientTracker.h"
#include "AAudioEndpointManager.h"
#include "AAudioServiceEndpointShared.h"
#include "AAudioServiceEndpointMMAP.h"
@@ -174,7 +175,15 @@
&& !request.isSharingModeMatchRequired()) { // app did not request a shared stream
ALOGD("%s() endpoint in EXCLUSIVE use. Steal it!", __func__);
mExclusiveStolenCount++;
- endpointToSteal = endpoint;
+ // Prevent this process from getting another EXCLUSIVE stream.
+ // This will prevent two clients from colliding after a DISCONNECTION
+ // when they both try to open an exclusive stream at the same time.
+ // That can result in a stream getting disconnected between the OPEN
+ // and START calls. This will help preserve app compatibility.
+ // An app can avoid having this happen by closing their streams when
+ // the app is paused.
+ AAudioClientTracker::getInstance().setExclusiveEnabled(request.getProcessId(), false);
+ endpointToSteal = endpoint; // return it to caller
}
return nullptr;
} else {
diff --git a/services/oboeservice/AAudioService.cpp b/services/oboeservice/AAudioService.cpp
index 82b12d6..22cdb35 100644
--- a/services/oboeservice/AAudioService.cpp
+++ b/services/oboeservice/AAudioService.cpp
@@ -117,7 +117,8 @@
return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
}
- if (sharingMode == AAUDIO_SHARING_MODE_EXCLUSIVE) {
+ if (sharingMode == AAUDIO_SHARING_MODE_EXCLUSIVE
+ && AAudioClientTracker::getInstance().isExclusiveEnabled(request.getProcessId())) {
// only trust audioserver for in service indication
bool inService = false;
if (isCallerInService()) {
diff --git a/services/oboeservice/AAudioServiceEndpoint.cpp b/services/oboeservice/AAudioServiceEndpoint.cpp
index 15cbd82..ceefe93 100644
--- a/services/oboeservice/AAudioServiceEndpoint.cpp
+++ b/services/oboeservice/AAudioServiceEndpoint.cpp
@@ -95,9 +95,16 @@
mRegisteredStreams.swap(streamsDisconnected);
}
mConnected.store(false);
+ // We need to stop all the streams before we disconnect them.
+ // Otherwise there is a race condition where the first disconnected app
+ // tries to reopen a stream as MMAP but is blocked by the second stream,
+ // which hasn't stopped yet. Then the first app ends up with a Legacy stream.
for (const auto &stream : streamsDisconnected) {
- ALOGD("%s() - stop and disconnect port %d", __func__, stream->getPortHandle());
+ ALOGD("%s() - stop(), port = %d", __func__, stream->getPortHandle());
stream->stop();
+ }
+ for (const auto &stream : streamsDisconnected) {
+ ALOGD("%s() - disconnect(), port = %d", __func__, stream->getPortHandle());
stream->disconnect();
}
return streamsDisconnected;