Merge "audiopolicy: fix preferred device selection" into pi-dev
diff --git a/media/libaaudio/examples/loopback/src/LoopbackAnalyzer.h b/media/libaaudio/examples/loopback/src/LoopbackAnalyzer.h
index 1e282d1..2623697 100644
--- a/media/libaaudio/examples/loopback/src/LoopbackAnalyzer.h
+++ b/media/libaaudio/examples/loopback/src/LoopbackAnalyzer.h
@@ -684,7 +684,7 @@
}
void printStatus() override {
- printf(" state = %d, glitches = %d,", mState, mGlitchCount);
+ printf(" state = %d, glitches = %3d,", mState, mGlitchCount);
}
double calculateMagnitude(double *phasePtr = NULL) {
diff --git a/media/libaaudio/examples/loopback/src/loopback.cpp b/media/libaaudio/examples/loopback/src/loopback.cpp
index 026ff0f..0ebcdbd 100644
--- a/media/libaaudio/examples/loopback/src/loopback.cpp
+++ b/media/libaaudio/examples/loopback/src/loopback.cpp
@@ -41,19 +41,24 @@
#define NUM_INPUT_CHANNELS 1
#define FILENAME_ALL "/data/loopback_all.wav"
#define FILENAME_ECHOS "/data/loopback_echos.wav"
-#define APP_VERSION "0.1.22"
+#define APP_VERSION "0.2.01"
struct LoopbackData {
AAudioStream *inputStream = nullptr;
int32_t inputFramesMaximum = 0;
- int16_t *inputData = nullptr;
+ int16_t *inputShortData = nullptr;
+ float *inputFloatData = nullptr;
int16_t peakShort = 0;
- float *conversionBuffer = nullptr;
+ aaudio_format_t actualInputFormat = AAUDIO_FORMAT_INVALID;
int32_t actualInputChannelCount = 0;
int32_t actualOutputChannelCount = 0;
int32_t inputBuffersToDiscard = 10;
int32_t minNumFrames = INT32_MAX;
int32_t maxNumFrames = 0;
+ int32_t insufficientReadCount = 0;
+ int32_t insufficientReadFrames = 0;
+ int32_t framesReadTotal = 0;
+ int32_t framesWrittenTotal = 0;
bool isDone = false;
aaudio_result_t inputError = AAUDIO_OK;
@@ -68,7 +73,7 @@
static void convertPcm16ToFloat(const int16_t *source,
float *destination,
int32_t numSamples) {
- const float scaler = 1.0f / 32768.0f;
+ constexpr float scaler = 1.0f / 32768.0f;
for (int i = 0; i < numSamples; i++) {
destination[i] = source[i] * scaler;
}
@@ -78,6 +83,28 @@
// ========================= CALLBACK =================================================
// ====================================================================================
// Callback function that fills the audio output buffer.
+
+static int32_t readFormattedData(LoopbackData *myData, int32_t numFrames) {
+ int32_t framesRead = AAUDIO_ERROR_INVALID_FORMAT;
+ if (myData->actualInputFormat == AAUDIO_FORMAT_PCM_I16) {
+ framesRead = AAudioStream_read(myData->inputStream, myData->inputShortData,
+ numFrames,
+ 0 /* timeoutNanoseconds */);
+ } else if (myData->actualInputFormat == AAUDIO_FORMAT_PCM_FLOAT) {
+ framesRead = AAudioStream_read(myData->inputStream, myData->inputFloatData,
+ numFrames,
+ 0 /* timeoutNanoseconds */);
+ }
+ if (framesRead < 0) {
+ myData->inputError = framesRead;
+ printf("ERROR in read = %d = %s\n", framesRead,
+ AAudio_convertResultToText(framesRead));
+ } else {
+ myData->framesReadTotal += framesRead;
+ }
+ return framesRead;
+}
+
static aaudio_data_callback_result_t MyDataCallbackProc(
AAudioStream *outputStream,
void *userData,
@@ -107,43 +134,58 @@
if (myData->inputBuffersToDiscard > 0) {
// Drain the input.
do {
- framesRead = AAudioStream_read(myData->inputStream, myData->inputData,
- numFrames, 0);
+ framesRead = readFormattedData(myData, numFrames);
if (framesRead < 0) {
- myData->inputError = framesRead;
- printf("ERROR in read = %d", framesRead);
result = AAUDIO_CALLBACK_RESULT_STOP;
} else if (framesRead > 0) {
myData->inputBuffersToDiscard--;
}
- } while(framesRead > 0);
- } else {
- framesRead = AAudioStream_read(myData->inputStream, myData->inputData,
- numFrames, 0);
- if (framesRead < 0) {
- myData->inputError = framesRead;
- printf("ERROR in read = %d", framesRead);
- result = AAUDIO_CALLBACK_RESULT_STOP;
- } else if (framesRead > 0) {
+ } while (framesRead > 0);
- myData->audioRecording.write(myData->inputData,
- myData->actualInputChannelCount,
- framesRead);
+ // Silence the output.
+ int32_t numBytes = numFrames * myData->actualOutputChannelCount * sizeof(float);
+ memset(audioData, 0 /* value */, numBytes);
+
+ } else {
+
+ int64_t inputFramesWritten = AAudioStream_getFramesWritten(myData->inputStream);
+ int64_t inputFramesRead = AAudioStream_getFramesRead(myData->inputStream);
+ int64_t framesAvailable = inputFramesWritten - inputFramesRead;
+ framesRead = readFormattedData(myData, numFrames);
+ if (framesRead < 0) {
+ result = AAUDIO_CALLBACK_RESULT_STOP;
+ } else {
+ if (framesRead < numFrames) {
+ if(framesRead < (int32_t) framesAvailable) {
+ printf("insufficient but numFrames = %d, framesRead = %d, available = %d\n",
+ numFrames, framesRead, (int) framesAvailable);
+ }
+ myData->insufficientReadCount++;
+ myData->insufficientReadFrames += numFrames - framesRead; // deficit
+ }
int32_t numSamples = framesRead * myData->actualInputChannelCount;
- convertPcm16ToFloat(myData->inputData, myData->conversionBuffer, numSamples);
- myData->loopbackProcessor->process(myData->conversionBuffer,
- myData->actualInputChannelCount,
- outputData,
- myData->actualOutputChannelCount,
- framesRead);
+ if (myData->actualInputFormat == AAUDIO_FORMAT_PCM_I16) {
+ convertPcm16ToFloat(myData->inputShortData, myData->inputFloatData, numSamples);
+ }
+ // Save for later.
+ myData->audioRecording.write(myData->inputFloatData,
+ myData->actualInputChannelCount,
+ framesRead);
+ // Analyze the data.
+ myData->loopbackProcessor->process(myData->inputFloatData,
+ myData->actualInputChannelCount,
+ outputData,
+ myData->actualOutputChannelCount,
+ framesRead);
myData->isDone = myData->loopbackProcessor->isDone();
if (myData->isDone) {
result = AAUDIO_CALLBACK_RESULT_STOP;
}
}
}
+ myData->framesWrittenTotal += numFrames;
return result;
}
@@ -161,6 +203,7 @@
printf("Usage: aaudio_loopback [OPTION]...\n\n");
AAudioArgsParser::usage();
printf(" -C{channels} number of input channels\n");
+ printf(" -F{0,1,2} input format, 1=I16, 2=FLOAT\n");
printf(" -g{gain} recirculating loopback gain\n");
printf(" -P{inPerf} set input AAUDIO_PERFORMANCE_MODE*\n");
printf(" n for _NONE\n");
@@ -236,9 +279,10 @@
}
}
float gain = 0.98f / maxSample;
+
for (int32_t i = start; i < end; i++) {
float sample = data[i];
- printf("%5.3f ", sample); // actual value
+ printf("%6d: %7.4f ", i, sample); // actual value
sample *= gain;
printAudioScope(sample);
}
@@ -254,23 +298,22 @@
AAudioSimplePlayer player;
AAudioSimpleRecorder recorder;
LoopbackData loopbackData;
- AAudioStream *outputStream = nullptr;
+ AAudioStream *inputStream = nullptr;
+ AAudioStream *outputStream = nullptr;
aaudio_result_t result = AAUDIO_OK;
- aaudio_sharing_mode_t requestedInputSharingMode = AAUDIO_SHARING_MODE_SHARED;
+ aaudio_sharing_mode_t requestedInputSharingMode = AAUDIO_SHARING_MODE_SHARED;
int requestedInputChannelCount = NUM_INPUT_CHANNELS;
- const aaudio_format_t requestedInputFormat = AAUDIO_FORMAT_PCM_I16;
- const aaudio_format_t requestedOutputFormat = AAUDIO_FORMAT_PCM_FLOAT;
- aaudio_format_t actualInputFormat;
- aaudio_format_t actualOutputFormat;
- aaudio_performance_mode_t inputPerformanceLevel = AAUDIO_PERFORMANCE_MODE_LOW_LATENCY;
- int32_t actualSampleRate = 0;
+ aaudio_format_t requestedInputFormat = AAUDIO_FORMAT_UNSPECIFIED;
+ const aaudio_format_t requestedOutputFormat = AAUDIO_FORMAT_PCM_FLOAT;
+ aaudio_performance_mode_t inputPerformanceLevel = AAUDIO_PERFORMANCE_MODE_LOW_LATENCY;
- int testMode = TEST_ECHO_LATENCY;
- double gain = 1.0;
+ aaudio_format_t actualOutputFormat = AAUDIO_FORMAT_INVALID;
+ int32_t actualSampleRate = 0;
+ int written = 0;
- int32_t framesPerBurst = 0;
- float *outputData = NULL;
+ int testMode = TEST_ECHO_LATENCY;
+ double gain = 1.0;
// Make printf print immediately so that debug info is not stuck
// in a buffer if we hang or crash.
@@ -288,6 +331,9 @@
case 'C':
requestedInputChannelCount = atoi(&arg[2]);
break;
+ case 'F':
+ requestedInputFormat = atoi(&arg[2]);
+ break;
case 'g':
gain = atof(&arg[2]);
break;
@@ -353,7 +399,6 @@
exit(1);
}
outputStream = player.getStream();
- argParser.compareWithStream(outputStream);
actualOutputFormat = AAudioStream_getFormat(outputStream);
assert(actualOutputFormat == AAUDIO_FORMAT_PCM_FLOAT);
@@ -362,40 +407,56 @@
loopbackData.audioRecording.allocate(recordingDuration * actualSampleRate);
loopbackData.audioRecording.setSampleRate(actualSampleRate);
- printf("INPUT stream ----------------------------------------\n");
+ argParser.compareWithStream(outputStream);
+
+ printf("INPUT stream ----------------------------------------\n");
// Use different parameters for the input.
argParser.setNumberOfBursts(AAUDIO_UNSPECIFIED);
argParser.setFormat(requestedInputFormat);
argParser.setPerformanceMode(inputPerformanceLevel);
argParser.setChannelCount(requestedInputChannelCount);
argParser.setSharingMode(requestedInputSharingMode);
+
+ // Make sure the input buffer has plenty of capacity.
+ // Extra capacity on input should not increase latency if we keep it drained.
+ int32_t outputBufferCapacity = AAudioStream_getBufferCapacityInFrames(outputStream);
+ int32_t inputBufferCapacity = 2 * outputBufferCapacity;
+ argParser.setBufferCapacity(inputBufferCapacity);
+
result = recorder.open(argParser);
if (result != AAUDIO_OK) {
fprintf(stderr, "ERROR - recorder.open() returned %d\n", result);
goto finish;
}
- loopbackData.inputStream = recorder.getStream();
- argParser.compareWithStream(loopbackData.inputStream);
+ inputStream = loopbackData.inputStream = recorder.getStream();
- // This is the number of frames that are read in one chunk by a DMA controller
- // or a DSP or a mixer.
- framesPerBurst = AAudioStream_getFramesPerBurst(outputStream);
+ {
+ int32_t actualCapacity = AAudioStream_getBufferCapacityInFrames(inputStream);
+ result = AAudioStream_setBufferSizeInFrames(inputStream, actualCapacity);
+ if (result < 0) {
+ fprintf(stderr, "ERROR - AAudioStream_setBufferSizeInFrames() returned %d\n", result);
+ goto finish;
+ } else {}
+ }
- actualInputFormat = AAudioStream_getFormat(outputStream);
- assert(actualInputFormat == AAUDIO_FORMAT_PCM_I16);
+ argParser.compareWithStream(inputStream);
+ // ------- Setup loopbackData -----------------------------
+ loopbackData.actualInputFormat = AAudioStream_getFormat(inputStream);
loopbackData.actualInputChannelCount = recorder.getChannelCount();
loopbackData.actualOutputChannelCount = player.getChannelCount();
// Allocate a buffer for the audio data.
- loopbackData.inputFramesMaximum = 32 * framesPerBurst;
+ loopbackData.inputFramesMaximum = 32 * AAudioStream_getFramesPerBurst(inputStream);
loopbackData.inputBuffersToDiscard = 200;
- loopbackData.inputData = new int16_t[loopbackData.inputFramesMaximum
- * loopbackData.actualInputChannelCount];
- loopbackData.conversionBuffer = new float[loopbackData.inputFramesMaximum *
- loopbackData.actualInputChannelCount];
+ if (loopbackData.actualInputFormat == AAUDIO_FORMAT_PCM_I16) {
+ loopbackData.inputShortData = new int16_t[loopbackData.inputFramesMaximum
+ * loopbackData.actualInputChannelCount]{};
+ }
+ loopbackData.inputFloatData = new float[loopbackData.inputFramesMaximum *
+ loopbackData.actualInputChannelCount]{};
loopbackData.loopbackProcessor->reset();
@@ -430,63 +491,119 @@
printf("%4d: ", i);
loopbackData.loopbackProcessor->printStatus();
- int64_t inputFramesWritten = AAudioStream_getFramesWritten(loopbackData.inputStream);
- int64_t inputFramesRead = AAudioStream_getFramesRead(loopbackData.inputStream);
+ printf(" insf %3d,", (int) loopbackData.insufficientReadCount);
+
+ int64_t inputFramesWritten = AAudioStream_getFramesWritten(inputStream);
+ int64_t inputFramesRead = AAudioStream_getFramesRead(inputStream);
int64_t outputFramesWritten = AAudioStream_getFramesWritten(outputStream);
int64_t outputFramesRead = AAudioStream_getFramesRead(outputStream);
- printf(" INPUT: wr %lld rd %lld state %s, OUTPUT: wr %lld rd %lld state %s, xruns %d\n",
+ static const int textOffset = strlen("AAUDIO_STREAM_STATE_"); // strip this off
+ printf(" INPUT: wr %7lld - rd %7lld = %5lld, state %s, oruns %3d | ",
(long long) inputFramesWritten,
(long long) inputFramesRead,
- AAudio_convertStreamStateToText(AAudioStream_getState(loopbackData.inputStream)),
+ (long long) (inputFramesWritten - inputFramesRead),
+ &AAudio_convertStreamStateToText(
+ AAudioStream_getState(inputStream))[textOffset],
+ AAudioStream_getXRunCount(inputStream));
+
+ printf(" OUTPUT: wr %7lld - rd %7lld = %5lld, state %s, uruns %3d\n",
(long long) outputFramesWritten,
(long long) outputFramesRead,
- AAudio_convertStreamStateToText(AAudioStream_getState(outputStream)),
+ (long long) (outputFramesWritten - outputFramesRead),
+ &AAudio_convertStreamStateToText(
+ AAudioStream_getState(outputStream))[textOffset],
AAudioStream_getXRunCount(outputStream)
);
}
}
+ result = player.stop();
+ if (result != AAUDIO_OK) {
+ printf("ERROR - player.stop() returned %d = %s\n",
+ result, AAudio_convertResultToText(result));
+ goto finish;
+ }
+
+ result = recorder.stop();
+ if (result != AAUDIO_OK) {
+ printf("ERROR - recorder.stop() returned %d = %s\n",
+ result, AAudio_convertResultToText(result));
+ goto finish;
+ }
+
+ printf("input error = %d = %s\n",
+ loopbackData.inputError, AAudio_convertResultToText(loopbackData.inputError));
+
+ if (loopbackData.inputError == AAUDIO_OK) {
+ if (testMode == TEST_SINE_MAGNITUDE) {
+ printAudioGraph(loopbackData.audioRecording, 200);
+ }
+ // Print again so we don't have to scroll past waveform.
+ printf("OUTPUT Stream ----------------------------------------\n");
+ argParser.compareWithStream(outputStream);
+ printf("INPUT Stream ----------------------------------------\n");
+ argParser.compareWithStream(inputStream);
+
+ loopbackData.loopbackProcessor->report();
+ }
+
+ {
+ int32_t framesRead = AAudioStream_getFramesRead(inputStream);
+ int32_t framesWritten = AAudioStream_getFramesWritten(inputStream);
+ printf("Callback Results ---------------------------------------- INPUT\n");
+ printf(" input overruns = %d\n", AAudioStream_getXRunCount(inputStream));
+ printf(" framesWritten = %8d\n", framesWritten);
+ printf(" framesRead = %8d\n", framesRead);
+ printf(" myFramesRead = %8d\n", (int) loopbackData.framesReadTotal);
+ printf(" written - read = %8d\n", (int) (framesWritten - framesRead));
+ printf(" insufficient # = %8d\n", (int) loopbackData.insufficientReadCount);
+ if (loopbackData.insufficientReadCount > 0) {
+ printf(" insufficient frames = %8d\n", (int) loopbackData.insufficientReadFrames);
+ }
+ }
+ {
+ int32_t framesRead = AAudioStream_getFramesRead(outputStream);
+ int32_t framesWritten = AAudioStream_getFramesWritten(outputStream);
+ printf("Callback Results ---------------------------------------- OUTPUT\n");
+ printf(" output underruns = %d\n", AAudioStream_getXRunCount(outputStream));
+ printf(" myFramesWritten = %8d\n", (int) loopbackData.framesWrittenTotal);
+ printf(" framesWritten = %8d\n", framesWritten);
+ printf(" framesRead = %8d\n", framesRead);
+ printf(" min numFrames = %8d\n", (int) loopbackData.minNumFrames);
+ printf(" max numFrames = %8d\n", (int) loopbackData.maxNumFrames);
+ }
+
+ written = loopbackData.loopbackProcessor->save(FILENAME_ECHOS);
+ if (written > 0) {
+ printf("main() wrote %8d mono samples to \"%s\" on Android device\n",
+ written, FILENAME_ECHOS);
+ }
+
+ written = loopbackData.audioRecording.save(FILENAME_ALL);
+ if (written > 0) {
+ printf("main() wrote %8d mono samples to \"%s\" on Android device\n",
+ written, FILENAME_ALL);
+ }
+
if (loopbackData.loopbackProcessor->getResult() < 0) {
- printf("ERROR: Could not get a good loopback signal. Probably because the volume was too low.\n");
- } else {
- printf("input error = %d = %s\n",
- loopbackData.inputError, AAudio_convertResultToText(loopbackData.inputError));
-
- printf("AAudioStream_getXRunCount %d\n", AAudioStream_getXRunCount(outputStream));
- printf("framesRead = %8d\n", (int) AAudioStream_getFramesRead(outputStream));
- printf("framesWritten = %8d\n", (int) AAudioStream_getFramesWritten(outputStream));
- printf("min numFrames = %8d\n", (int) loopbackData.minNumFrames);
- printf("max numFrames = %8d\n", (int) loopbackData.maxNumFrames);
-
- if (loopbackData.inputError == AAUDIO_OK) {
- if (testMode == TEST_SINE_MAGNITUDE) {
- printAudioGraph(loopbackData.audioRecording, 200);
- }
- loopbackData.loopbackProcessor->report();
- }
-
- int written = loopbackData.loopbackProcessor->save(FILENAME_ECHOS);
- if (written > 0) {
- printf("main() wrote %8d mono samples to \"%s\" on Android device\n",
- written, FILENAME_ECHOS);
- }
-
- written = loopbackData.audioRecording.save(FILENAME_ALL);
- if (written > 0) {
- printf("main() wrote %8d mono samples to \"%s\" on Android device\n",
- written, FILENAME_ALL);
- }
+ printf("ERROR: LOOPBACK PROCESSING FAILED. Maybe because the volume was too low.\n");
+ result = loopbackData.loopbackProcessor->getResult();
+ }
+ if (loopbackData.insufficientReadCount > 3) {
+ printf("ERROR: LOOPBACK PROCESSING FAILED. insufficientReadCount too high\n");
+ result = AAUDIO_ERROR_UNAVAILABLE;
}
finish:
player.close();
recorder.close();
- delete[] loopbackData.conversionBuffer;
- delete[] loopbackData.inputData;
- delete[] outputData;
+ delete[] loopbackData.inputFloatData;
+ delete[] loopbackData.inputShortData;
- printf(RESULT_TAG "result = %s\n", AAudio_convertResultToText(result));
- if ((result != AAUDIO_OK)) {
+ printf(RESULT_TAG "result = %d \n", result); // machine readable
+ printf("result is %s\n", AAudio_convertResultToText(result)); // human readable
+ if (result != AAUDIO_OK) {
+ printf("FAILURE\n");
return EXIT_FAILURE;
} else {
printf("SUCCESS\n");
diff --git a/media/libaaudio/tests/Android.bp b/media/libaaudio/tests/Android.bp
index beec9e2..68194db 100644
--- a/media/libaaudio/tests/Android.bp
+++ b/media/libaaudio/tests/Android.bp
@@ -160,3 +160,10 @@
"libutils",
],
}
+
+cc_test {
+ name: "test_atomic_fifo",
+ defaults: ["libaaudio_tests_defaults"],
+ srcs: ["test_atomic_fifo.cpp"],
+ shared_libs: ["libaaudio"],
+}
diff --git a/media/libaaudio/tests/test_atomic_fifo.cpp b/media/libaaudio/tests/test_atomic_fifo.cpp
new file mode 100644
index 0000000..0085217
--- /dev/null
+++ b/media/libaaudio/tests/test_atomic_fifo.cpp
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <iostream>
+
+#include <gtest/gtest.h>
+#include <stdlib.h>
+
+#include "fifo/FifoBuffer.h"
+#include "fifo/FifoController.h"
+
+using android::fifo_frames_t;
+using android::FifoController;
+using android::FifoBuffer;
+using android::WrappingBuffer;
+
+//void foo() {
+TEST(test_fifi_controller, fifo_indices) {
+ // Values are arbitrary primes designed to trigger edge cases.
+ constexpr int capacity = 83;
+ constexpr int threshold = 47;
+ FifoController fifoController(capacity, threshold);
+ ASSERT_EQ(capacity, fifoController.getCapacity());
+ ASSERT_EQ(threshold, fifoController.getThreshold());
+
+ ASSERT_EQ(0, fifoController.getReadCounter());
+ ASSERT_EQ(0, fifoController.getWriteCounter());
+ ASSERT_EQ(0, fifoController.getFullFramesAvailable());
+ ASSERT_EQ(threshold, fifoController.getEmptyFramesAvailable());
+
+ // Pretend to write some data.
+ constexpr int advance1 = 23;
+ fifoController.advanceWriteIndex(advance1);
+ int advanced = advance1;
+ ASSERT_EQ(0, fifoController.getReadCounter());
+ ASSERT_EQ(0, fifoController.getReadIndex());
+ ASSERT_EQ(advanced, fifoController.getWriteCounter());
+ ASSERT_EQ(advanced, fifoController.getWriteIndex());
+ ASSERT_EQ(advanced, fifoController.getFullFramesAvailable());
+ ASSERT_EQ(threshold - advanced, fifoController.getEmptyFramesAvailable());
+
+ // Pretend to read the data.
+ fifoController.advanceReadIndex(advance1);
+ ASSERT_EQ(advanced, fifoController.getReadCounter());
+ ASSERT_EQ(advanced, fifoController.getReadIndex());
+ ASSERT_EQ(advanced, fifoController.getWriteCounter());
+ ASSERT_EQ(advanced, fifoController.getWriteIndex());
+ ASSERT_EQ(0, fifoController.getFullFramesAvailable());
+ ASSERT_EQ(threshold, fifoController.getEmptyFramesAvailable());
+
+ // Write past end of buffer.
+ constexpr int advance2 = 13 + capacity - advance1;
+ fifoController.advanceWriteIndex(advance2);
+ advanced += advance2;
+ ASSERT_EQ(advance1, fifoController.getReadCounter());
+ ASSERT_EQ(advance1, fifoController.getReadIndex());
+ ASSERT_EQ(advanced, fifoController.getWriteCounter());
+ ASSERT_EQ(advanced - capacity, fifoController.getWriteIndex());
+ ASSERT_EQ(advance2, fifoController.getFullFramesAvailable());
+ ASSERT_EQ(threshold - advance2, fifoController.getEmptyFramesAvailable());
+}
+
+// TODO consider using a template for other data types.
+class TestFifoBuffer {
+public:
+ explicit TestFifoBuffer(fifo_frames_t capacity, fifo_frames_t threshold = 0)
+ : mFifoBuffer(sizeof(int16_t), capacity) {
+ // For reading and writing.
+ mData = new int16_t[capacity];
+ if (threshold <= 0) {
+ threshold = capacity;
+ }
+ mFifoBuffer.setThreshold(threshold);
+ mThreshold = threshold;
+ }
+
+ void checkMisc() {
+ ASSERT_EQ((int32_t)(2 * sizeof(int16_t)), mFifoBuffer.convertFramesToBytes(2));
+ ASSERT_EQ(mThreshold, mFifoBuffer.getThreshold());
+ }
+
+ // Verify that the available frames in each part add up correctly.
+ void checkWrappingBuffer() {
+ WrappingBuffer wrappingBuffer;
+ fifo_frames_t framesAvailable =
+ mFifoBuffer.getFifoControllerBase()->getEmptyFramesAvailable();
+ fifo_frames_t wrapAvailable = mFifoBuffer.getEmptyRoomAvailable(&wrappingBuffer);
+ EXPECT_EQ(framesAvailable, wrapAvailable);
+ fifo_frames_t bothAvailable = wrappingBuffer.numFrames[0] + wrappingBuffer.numFrames[1];
+ EXPECT_EQ(framesAvailable, bothAvailable);
+
+ framesAvailable =
+ mFifoBuffer.getFifoControllerBase()->getFullFramesAvailable();
+ wrapAvailable = mFifoBuffer.getFullDataAvailable(&wrappingBuffer);
+ EXPECT_EQ(framesAvailable, wrapAvailable);
+ bothAvailable = wrappingBuffer.numFrames[0] + wrappingBuffer.numFrames[1];
+ EXPECT_EQ(framesAvailable, bothAvailable);
+ }
+
+ // Write data but do not overflow.
+ void writeData(fifo_frames_t numFrames) {
+ fifo_frames_t framesAvailable =
+ mFifoBuffer.getFifoControllerBase()->getEmptyFramesAvailable();
+ fifo_frames_t framesToWrite = std::min(framesAvailable, numFrames);
+ for (int i = 0; i < framesToWrite; i++) {
+ mData[i] = mNextWriteIndex++;
+ }
+ fifo_frames_t actual = mFifoBuffer.write(mData, framesToWrite);
+ ASSERT_EQ(framesToWrite, actual);
+ }
+
+ // Read data but do not underflow.
+ void verifyData(fifo_frames_t numFrames) {
+ fifo_frames_t framesAvailable =
+ mFifoBuffer.getFifoControllerBase()->getFullFramesAvailable();
+ fifo_frames_t framesToRead = std::min(framesAvailable, numFrames);
+ fifo_frames_t actual = mFifoBuffer.read(mData, framesToRead);
+ ASSERT_EQ(framesToRead, actual);
+ for (int i = 0; i < framesToRead; i++) {
+ ASSERT_EQ(mNextVerifyIndex++, mData[i]);
+ }
+ }
+
+ // Wrap around the end of the buffer.
+ void checkWrappingWriteRead() {
+ constexpr int frames1 = 43;
+ constexpr int frames2 = 15;
+
+ writeData(frames1);
+ checkWrappingBuffer();
+ verifyData(frames1);
+ checkWrappingBuffer();
+
+ writeData(frames2);
+ checkWrappingBuffer();
+ verifyData(frames2);
+ checkWrappingBuffer();
+ }
+
+ // Write and Read a specific amount of data.
+ void checkWriteRead() {
+ const fifo_frames_t capacity = mFifoBuffer.getBufferCapacityInFrames();
+ // Wrap around with the smaller region in the second half.
+ const int frames1 = capacity - 4;
+ const int frames2 = 7; // arbitrary, small
+ writeData(frames1);
+ verifyData(frames1);
+ writeData(frames2);
+ verifyData(frames2);
+ }
+
+ // Write and Read a specific amount of data.
+ void checkWriteReadSmallLarge() {
+ const fifo_frames_t capacity = mFifoBuffer.getBufferCapacityInFrames();
+ // Wrap around with the larger region in the second half.
+ const int frames1 = capacity - 4;
+ const int frames2 = capacity - 9; // arbitrary, large
+ writeData(frames1);
+ verifyData(frames1);
+ writeData(frames2);
+ verifyData(frames2);
+ }
+
+ // Randomly read or write up to the maximum amount of data.
+ void checkRandomWriteRead() {
+ for (int i = 0; i < 20; i++) {
+ fifo_frames_t framesEmpty =
+ mFifoBuffer.getFifoControllerBase()->getEmptyFramesAvailable();
+ fifo_frames_t numFrames = (fifo_frames_t)(drand48() * framesEmpty);
+ writeData(numFrames);
+
+ fifo_frames_t framesFull =
+ mFifoBuffer.getFifoControllerBase()->getFullFramesAvailable();
+ numFrames = (fifo_frames_t)(drand48() * framesFull);
+ verifyData(numFrames);
+ }
+ }
+
+ FifoBuffer mFifoBuffer;
+ int16_t *mData;
+ fifo_frames_t mNextWriteIndex = 0;
+ fifo_frames_t mNextVerifyIndex = 0;
+ fifo_frames_t mThreshold;
+};
+
+TEST(test_fifo_buffer, fifo_read_write) {
+ constexpr int capacity = 51; // arbitrary
+ TestFifoBuffer tester(capacity);
+ tester.checkMisc();
+ tester.checkWriteRead();
+}
+
+TEST(test_fifo_buffer, fifo_wrapping_read_write) {
+ constexpr int capacity = 59; // arbitrary, a little bigger this time
+ TestFifoBuffer tester(capacity);
+ tester.checkWrappingWriteRead();
+}
+
+TEST(test_fifo_buffer, fifo_read_write_small_large) {
+ constexpr int capacity = 51; // arbitrary
+ TestFifoBuffer tester(capacity);
+ tester.checkWriteReadSmallLarge();
+}
+
+TEST(test_fifo_buffer, fifo_random_read_write) {
+ constexpr int capacity = 51; // arbitrary
+ TestFifoBuffer tester(capacity);
+ tester.checkRandomWriteRead();
+}
+
+TEST(test_fifo_buffer, fifo_random_threshold) {
+ constexpr int capacity = 67; // arbitrary
+ constexpr int threshold = 37; // arbitrary
+ TestFifoBuffer tester(capacity, threshold);
+ tester.checkRandomWriteRead();
+}
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index 1c4a80e..39ee437 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -20,6 +20,7 @@
#include <utils/Log.h>
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
+#include <binder/IPCThreadState.h>
#include <media/AudioResamplerPublic.h>
#include <media/AudioSystem.h>
#include <media/IAudioFlinger.h>
@@ -75,7 +76,9 @@
af = gAudioFlinger;
}
if (afc != 0) {
+ int64_t token = IPCThreadState::self()->clearCallingIdentity();
af->registerClient(afc);
+ IPCThreadState::self()->restoreCallingIdentity(token);
}
return af;
}
@@ -767,7 +770,10 @@
ap = gAudioPolicyService;
}
if (apc != 0) {
+ int64_t token = IPCThreadState::self()->clearCallingIdentity();
ap->registerClient(apc);
+ ap->setAudioPortCallbacksEnabled(apc->isAudioPortCbEnabled());
+ IPCThreadState::self()->restoreCallingIdentity(token);
}
return ap;
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index 22b700d..0c4d6ee 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -431,6 +431,7 @@
int addAudioPortCallback(const sp<AudioPortCallback>& callback);
int removeAudioPortCallback(const sp<AudioPortCallback>& callback);
+ bool isAudioPortCbEnabled() const { return (mAudioPortCallbacks.size() != 0); }
// DeathRecipient
virtual void binderDied(const wp<IBinder>& who);
diff --git a/media/libmedia/include/media/CodecServiceRegistrant.h b/media/libmedia/include/media/CodecServiceRegistrant.h
new file mode 100644
index 0000000..e0af781
--- /dev/null
+++ b/media/libmedia/include/media/CodecServiceRegistrant.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CODEC_SERVICE_REGISTRANT_H_
+
+#define CODEC_SERVICE_REGISTRANT_H_
+
+typedef void (*RegisterCodecServicesFunc)();
+
+#endif // CODEC_SERVICE_REGISTRANT_H_
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index a762e76..3a28bbd 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -1703,6 +1703,8 @@
++mAudioDrainGeneration;
if (mAudioRenderingStartGeneration != -1) {
prepareForMediaRenderingStart_l();
+ // PauseTimeout is applied to offload mode only. Cancel pending timer.
+ cancelAudioOffloadPauseTimeout();
}
}
@@ -1805,6 +1807,12 @@
if (mAudioTornDown) {
return;
}
+
+ // TimeoutWhenPaused is only for offload mode.
+ if (reason == kDueToTimeout && !offloadingAudio()) {
+ return;
+ }
+
mAudioTornDown = true;
int64_t currentPositionUs;
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 0296dd8..ad81f04 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -7615,8 +7615,10 @@
config->param[paramIndex].bSet =
(OMX_BOOL)params->findString(existingKey->second.c_str(), &value);
if (config->param[paramIndex].bSet) {
- strncpy((char *)config->param[paramIndex].cString, value.c_str(),
- sizeof(OMX_CONFIG_ANDROID_VENDOR_PARAMTYPE::cString));
+ size_t dstSize = sizeof(config->param[paramIndex].cString);
+ strncpy((char *)config->param[paramIndex].cString, value.c_str(), dstSize - 1);
+ // null terminate value
+ config->param[paramIndex].cString[dstSize - 1] = '\0';
}
break;
}
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index a3261d7..550a99c 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -496,7 +496,6 @@
mStreamableFile = false;
mTimeScale = -1;
mHasFileLevelMeta = false;
- mHasMoovBox = false;
mPrimaryItemId = 0;
mAssociationEntryCount = 0;
mNumGrids = 0;
@@ -505,6 +504,7 @@
// And they will stay the same for all the recording sessions.
if (isFirstSession) {
mMoovExtraSize = 0;
+ mHasMoovBox = false;
mMetaKeys = new AMessage();
addDeviceMeta();
mLatitudex10000 = 0;
diff --git a/media/libstagefright/httplive/M3UParser.cpp b/media/libstagefright/httplive/M3UParser.cpp
index 8f349fc..9bdf895 100644
--- a/media/libstagefright/httplive/M3UParser.cpp
+++ b/media/libstagefright/httplive/M3UParser.cpp
@@ -484,6 +484,9 @@
// Base URL must be absolute
return false;
}
+ if (!strncasecmp("data:", url, 5)) {
+ return false;
+ }
const size_t schemeEnd = (strstr(baseURL, "//") - baseURL) + 2;
CHECK(schemeEnd == 7 || schemeEnd == 8);
diff --git a/media/libstagefright/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp
index 5624f4a..f292c47 100644
--- a/media/libstagefright/httplive/PlaylistFetcher.cpp
+++ b/media/libstagefright/httplive/PlaylistFetcher.cpp
@@ -33,6 +33,7 @@
#include <media/stagefright/foundation/ByteUtils.h>
#include <media/stagefright/foundation/MediaKeys.h>
#include <media/stagefright/foundation/avc_utils.h>
+#include <media/stagefright/DataURISource.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/MetaDataUtils.h>
@@ -347,6 +348,16 @@
sp<ABuffer> key;
if (index >= 0) {
key = mAESKeyForURI.valueAt(index);
+ } else if (keyURI.startsWith("data:")) {
+ sp<DataSource> keySrc = DataURISource::Create(keyURI.c_str());
+ off64_t keyLen;
+ if (keySrc == NULL || keySrc->getSize(&keyLen) != OK || keyLen < 0) {
+ ALOGE("Malformed cipher key data uri.");
+ return ERROR_MALFORMED;
+ }
+ key = new ABuffer(keyLen);
+ keySrc->readAt(0, key->data(), keyLen);
+ key->setRange(0, keyLen);
} else {
ssize_t err = mHTTPDownloader->fetchFile(keyURI.c_str(), &key);
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 83e56b6..c87b5eb 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -1055,16 +1055,8 @@
return BAD_VALUE;
}
- std::string cameraName;
- err = mCameraProviderManager->getCameraDeviceName(
- std::string(cameraId.c_str()), cameraName);
- if (err != OK) {
- ALOGE("%s: Failed to find camera device name for id %s: %d",
- __FUNCTION__, cameraId.c_str(), err);
- return err;
- }
// Make descriptor for incoming client
- clientDescriptor = CameraClientManager::makeClientDescriptor(String8(cameraName.c_str()),
+ clientDescriptor = CameraClientManager::makeClientDescriptor(cameraId,
sp<BasicClient>{nullptr}, static_cast<int32_t>(state->getCost()),
state->getConflicting(),
priorityScores[priorityScores.size() - 1],
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index 9b1b131..077e05e 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -391,16 +391,6 @@
return ret;
}
-status_t CameraProviderManager::getCameraDeviceName(const std::string& id, std::string& name) {
- std::lock_guard<std::mutex> lock(mInterfaceMutex);
-
- auto deviceInfo = findDeviceInfoLocked(id);
- if (deviceInfo == nullptr) return NAME_NOT_FOUND;
-
- name = deviceInfo->mName;
- return OK;
-}
-
status_t CameraProviderManager::addProviderLocked(const std::string& newProvider, bool expected) {
for (const auto& providerInfo : mProviders) {
if (providerInfo->mProviderName == newProvider) {
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.h b/services/camera/libcameraservice/common/CameraProviderManager.h
index 43b69d5..bbe6789 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.h
+++ b/services/camera/libcameraservice/common/CameraProviderManager.h
@@ -230,11 +230,6 @@
hardware::hidl_version minVersion = hardware::hidl_version{0,0},
hardware::hidl_version maxVersion = hardware::hidl_version{1000,0}) const;
- /*
- * Get device name for a particular camera Id
- */
- status_t getCameraDeviceName(const std::string& id, std::string& name);
-
private:
// All private members, unless otherwise noted, expect mInterfaceMutex to be locked before use
mutable std::mutex mInterfaceMutex;
diff --git a/services/mediacodec/main_codecservice.cpp b/services/mediacodec/main_codecservice.cpp
index 701ca6e..51619f6 100644
--- a/services/mediacodec/main_codecservice.cpp
+++ b/services/mediacodec/main_codecservice.cpp
@@ -25,6 +25,9 @@
#include <media/stagefright/omx/1.0/Omx.h>
#include <media/stagefright/omx/1.0/OmxStore.h>
+#include <media/CodecServiceRegistrant.h>
+#include <dlfcn.h>
+
using namespace android;
// Must match location in Android.mk.
@@ -45,20 +48,37 @@
::android::hardware::configureRpcThreadpool(64, false);
- using namespace ::android::hardware::media::omx::V1_0;
- sp<IOmxStore> omxStore = new implementation::OmxStore();
- if (omxStore == nullptr) {
- LOG(ERROR) << "Cannot create IOmxStore HAL service.";
- } else if (omxStore->registerAsService() != OK) {
- LOG(ERROR) << "Cannot register IOmxStore HAL service.";
- }
- sp<IOmx> omx = new implementation::Omx();
- if (omx == nullptr) {
- LOG(ERROR) << "Cannot create IOmx HAL service.";
- } else if (omx->registerAsService() != OK) {
- LOG(ERROR) << "Cannot register IOmx HAL service.";
+ // Registration of customized codec services
+ void *registrantLib = dlopen(
+ "libmedia_codecserviceregistrant.so",
+ RTLD_NOW | RTLD_LOCAL);
+ if (registrantLib) {
+ RegisterCodecServicesFunc registerCodecServices =
+ reinterpret_cast<RegisterCodecServicesFunc>(
+ dlsym(registrantLib, "RegisterCodecServices"));
+ if (registerCodecServices) {
+ registerCodecServices();
+ } else {
+ LOG(WARNING) << "Cannot register additional services "
+ "-- corrupted library.";
+ }
} else {
- LOG(INFO) << "IOmx HAL service created.";
+ // Default codec services
+ using namespace ::android::hardware::media::omx::V1_0;
+ sp<IOmxStore> omxStore = new implementation::OmxStore();
+ if (omxStore == nullptr) {
+ LOG(ERROR) << "Cannot create IOmxStore HAL service.";
+ } else if (omxStore->registerAsService() != OK) {
+ LOG(ERROR) << "Cannot register IOmxStore HAL service.";
+ }
+ sp<IOmx> omx = new implementation::Omx();
+ if (omx == nullptr) {
+ LOG(ERROR) << "Cannot create IOmx HAL service.";
+ } else if (omx->registerAsService() != OK) {
+ LOG(ERROR) << "Cannot register IOmx HAL service.";
+ } else {
+ LOG(INFO) << "IOmx HAL service created.";
+ }
}
::android::hardware::joinRpcThreadpool();