Merge "MPEG4Extractor: reduce buffer size for audio tracks" into pi-dev
diff --git a/drm/libmediadrm/CryptoHal.cpp b/drm/libmediadrm/CryptoHal.cpp
index ad1ccbc..3035c5a 100644
--- a/drm/libmediadrm/CryptoHal.cpp
+++ b/drm/libmediadrm/CryptoHal.cpp
@@ -269,11 +269,15 @@
* TODO: Add a releaseSharedBuffer method in a future DRM HAL
* API version to make this explicit.
*/
- uint32_t bufferId = mHeapBases.valueFor(seqNum).getBufferId();
- Return<void> hResult = mPlugin->setSharedBufferBase(hidl_memory(), bufferId);
- ALOGE_IF(!hResult.isOk(), "setSharedBufferBase(): remote call failed");
-
- mHeapBases.removeItem(seqNum);
+ ssize_t index = mHeapBases.indexOfKey(seqNum);
+ if (index >= 0) {
+ if (mPlugin != NULL) {
+ uint32_t bufferId = mHeapBases[index].getBufferId();
+ Return<void> hResult = mPlugin->setSharedBufferBase(hidl_memory(), bufferId);
+ ALOGE_IF(!hResult.isOk(), "setSharedBufferBase(): remote call failed");
+ }
+ mHeapBases.removeItem(seqNum);
+ }
}
status_t CryptoHal::toSharedBuffer(const sp<IMemory>& memory, int32_t seqNum, ::SharedBuffer* buffer) {
diff --git a/media/extractors/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
index 47f21e1..1a56edc 100644
--- a/media/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/extractors/mp4/MPEG4Extractor.cpp
@@ -111,6 +111,8 @@
int32_t mCryptoMode; // passed in from extractor
int32_t mDefaultIVSize; // passed in from extractor
uint8_t mCryptoKey[16]; // passed in from extractor
+ int32_t mDefaultEncryptedByteBlock;
+ int32_t mDefaultSkipByteBlock;
uint32_t mCurrentAuxInfoType;
uint32_t mCurrentAuxInfoTypeParameter;
int32_t mCurrentDefaultSampleInfoSize;
@@ -144,6 +146,8 @@
status_t parseTrackFragmentRun(off64_t offset, off64_t size);
status_t parseSampleAuxiliaryInformationSizes(off64_t offset, off64_t size);
status_t parseSampleAuxiliaryInformationOffsets(off64_t offset, off64_t size);
+ status_t parseClearEncryptedSizes(off64_t offset, bool isSubsampleEncryption, uint32_t flags);
+ status_t parseSampleEncryption(off64_t offset);
struct TrackFragmentHeaderInfo {
enum Flags {
@@ -921,6 +925,7 @@
track->timescale = 0;
track->meta.setCString(kKeyMIMEType, "application/octet-stream");
track->has_elst = false;
+ track->subsample_encryption = false;
}
off64_t stop_offset = *offset + chunk_size;
@@ -980,6 +985,49 @@
break;
}
+ case FOURCC('s', 'c', 'h', 'm'):
+ {
+
+ *offset += chunk_size;
+ if (!mLastTrack) {
+ return ERROR_MALFORMED;
+ }
+
+ uint32_t scheme_type;
+ if (mDataSource->readAt(data_offset + 4, &scheme_type, 4) < 4) {
+ return ERROR_IO;
+ }
+ scheme_type = ntohl(scheme_type);
+ int32_t mode = kCryptoModeUnencrypted;
+ switch(scheme_type) {
+ case FOURCC('c', 'b', 'c', '1'):
+ {
+ mode = kCryptoModeAesCbc;
+ break;
+ }
+ case FOURCC('c', 'b', 'c', 's'):
+ {
+ mode = kCryptoModeAesCbc;
+ mLastTrack->subsample_encryption = true;
+ break;
+ }
+ case FOURCC('c', 'e', 'n', 'c'):
+ {
+ mode = kCryptoModeAesCtr;
+ break;
+ }
+ case FOURCC('c', 'e', 'n', 's'):
+ {
+ mode = kCryptoModeAesCtr;
+ mLastTrack->subsample_encryption = true;
+ break;
+ }
+ }
+ mLastTrack->meta.setInt32(kKeyCryptoMode, mode);
+ break;
+ }
+
+
case FOURCC('e', 'l', 's', 't'):
{
*offset += chunk_size;
@@ -1071,31 +1119,54 @@
// tenc box contains 1 byte version, 3 byte flags, 3 byte default algorithm id, one byte
// default IV size, 16 bytes default KeyID
// (ISO 23001-7)
- char buf[4];
+
+ uint8_t version;
+ if (mDataSource->readAt(data_offset, &version, sizeof(version))
+ < (ssize_t)sizeof(version)) {
+ return ERROR_IO;
+ }
+
+ uint8_t buf[4];
memset(buf, 0, 4);
if (mDataSource->readAt(data_offset + 4, buf + 1, 3) < 3) {
return ERROR_IO;
}
- uint32_t defaultAlgorithmId = ntohl(*((int32_t*)buf));
- if (defaultAlgorithmId > 1) {
- // only 0 (clear) and 1 (AES-128) are valid
+
+ if (mLastTrack == NULL) {
return ERROR_MALFORMED;
}
+ uint8_t defaultEncryptedByteBlock = 0;
+ uint8_t defaultSkipByteBlock = 0;
+ uint32_t defaultAlgorithmId = ntohl(*((int32_t*)buf));
+ if (version == 1) {
+ uint32_t pattern = buf[2];
+ defaultEncryptedByteBlock = pattern >> 4;
+ defaultSkipByteBlock = pattern & 0xf;
+ if (defaultEncryptedByteBlock == 0 && defaultSkipByteBlock == 0) {
+ // use (1,0) to mean "encrypt everything"
+ defaultEncryptedByteBlock = 1;
+ }
+ } else if (mLastTrack->subsample_encryption) {
+ ALOGW("subsample_encryption should be version 1");
+ } else if (defaultAlgorithmId > 1) {
+ // only 0 (clear) and 1 (AES-128) are valid
+ ALOGW("defaultAlgorithmId: %u is a reserved value", defaultAlgorithmId);
+ defaultAlgorithmId = 1;
+ }
+
memset(buf, 0, 4);
if (mDataSource->readAt(data_offset + 7, buf + 3, 1) < 1) {
return ERROR_IO;
}
uint32_t defaultIVSize = ntohl(*((int32_t*)buf));
- if ((defaultAlgorithmId == 0 && defaultIVSize != 0) ||
- (defaultAlgorithmId != 0 && defaultIVSize == 0)) {
+ if (defaultAlgorithmId == 0 && defaultIVSize != 0) {
// only unencrypted data must have 0 IV size
return ERROR_MALFORMED;
} else if (defaultIVSize != 0 &&
defaultIVSize != 8 &&
defaultIVSize != 16) {
- // only supported sizes are 0, 8 and 16
return ERROR_MALFORMED;
}
@@ -1105,12 +1176,41 @@
return ERROR_IO;
}
- if (mLastTrack == NULL)
- return ERROR_MALFORMED;
+ sp<ABuffer> defaultConstantIv;
+ if (defaultAlgorithmId != 0 && defaultIVSize == 0) {
- mLastTrack->meta.setInt32(kKeyCryptoMode, defaultAlgorithmId);
+ uint8_t ivlength;
+ if (mDataSource->readAt(data_offset + 24, &ivlength, sizeof(ivlength))
+ < (ssize_t)sizeof(ivlength)) {
+ return ERROR_IO;
+ }
+
+ if (ivlength != 8 && ivlength != 16) {
+ ALOGW("unsupported IV length: %u", ivlength);
+ return ERROR_MALFORMED;
+ }
+
+ defaultConstantIv = new ABuffer(ivlength);
+ if (mDataSource->readAt(data_offset + 25, defaultConstantIv->data(), ivlength)
+ < (ssize_t)ivlength) {
+ return ERROR_IO;
+ }
+
+ defaultConstantIv->setRange(0, ivlength);
+ }
+
+ int32_t tmpAlgorithmId;
+ if (!mLastTrack->meta.findInt32(kKeyCryptoMode, &tmpAlgorithmId)) {
+ mLastTrack->meta.setInt32(kKeyCryptoMode, defaultAlgorithmId);
+ }
+
mLastTrack->meta.setInt32(kKeyCryptoDefaultIVSize, defaultIVSize);
mLastTrack->meta.setData(kKeyCryptoKey, 'tenc', defaultKeyId, 16);
+ mLastTrack->meta.setInt32(kKeyEncryptedByteBlock, defaultEncryptedByteBlock);
+ mLastTrack->meta.setInt32(kKeySkipByteBlock, defaultSkipByteBlock);
+ if (defaultConstantIv != NULL) {
+ mLastTrack->meta.setData(kKeyCryptoIV, 'dciv', defaultConstantIv->data(), defaultConstantIv->size());
+ }
break;
}
@@ -3747,6 +3847,8 @@
mCurrentMoofOffset(firstMoofOffset),
mNextMoofOffset(-1),
mCurrentTime(0),
+ mDefaultEncryptedByteBlock(0),
+ mDefaultSkipByteBlock(0),
mCurrentSampleInfoAllocSize(0),
mCurrentSampleInfoSizes(NULL),
mCurrentSampleInfoOffsetsAllocSize(0),
@@ -3776,6 +3878,9 @@
memcpy(mCryptoKey, key, keysize);
}
+ mFormat.findInt32(kKeyEncryptedByteBlock, &mDefaultEncryptedByteBlock);
+ mFormat.findInt32(kKeySkipByteBlock, &mDefaultSkipByteBlock);
+
const char *mime;
bool success = mFormat.findCString(kKeyMIMEType, &mime);
CHECK(success);
@@ -4022,6 +4127,15 @@
break;
}
+ case FOURCC('s', 'e', 'n', 'c'): {
+ status_t err;
+ if ((err = parseSampleEncryption(data_offset)) != OK) {
+ return err;
+ }
+ *offset += chunk_size;
+ break;
+ }
+
case FOURCC('m', 'd', 'a', 't'): {
// parse DRM info if present
ALOGV("MPEG4Source::parseChunk mdat");
@@ -4172,6 +4286,12 @@
off64_t drmoffset = mCurrentSampleInfoOffsets[0]; // from moof
drmoffset += mCurrentMoofOffset;
+
+ return parseClearEncryptedSizes(drmoffset, false, 0);
+}
+
+status_t MPEG4Source::parseClearEncryptedSizes(off64_t offset, bool isSubsampleEncryption, uint32_t flags) {
+
int ivlength;
CHECK(mFormat.findInt32(kKeyCryptoDefaultIVSize, &ivlength));
@@ -4180,42 +4300,61 @@
ALOGW("unsupported IV length: %d", ivlength);
return ERROR_MALFORMED;
}
+
+ uint32_t sampleCount = mCurrentSampleInfoCount;
+ if (isSubsampleEncryption) {
+ if (!mDataSource->getUInt32(offset, &sampleCount)) {
+ return ERROR_IO;
+ }
+ offset += 4;
+ }
+
// read CencSampleAuxiliaryDataFormats
- for (size_t i = 0; i < mCurrentSampleInfoCount; i++) {
+ for (size_t i = 0; i < sampleCount; i++) {
if (i >= mCurrentSamples.size()) {
ALOGW("too few samples");
break;
}
Sample *smpl = &mCurrentSamples.editItemAt(i);
+ if (!smpl->clearsizes.isEmpty()) {
+ continue;
+ }
memset(smpl->iv, 0, 16);
- if (mDataSource->readAt(drmoffset, smpl->iv, ivlength) != ivlength) {
+ if (mDataSource->readAt(offset, smpl->iv, ivlength) != ivlength) {
return ERROR_IO;
}
- drmoffset += ivlength;
+ offset += ivlength;
- int32_t smplinfosize = mCurrentDefaultSampleInfoSize;
- if (smplinfosize == 0) {
- smplinfosize = mCurrentSampleInfoSizes[i];
+ bool readSubsamples;
+ if (isSubsampleEncryption) {
+ readSubsamples = flags & 2;
+ } else {
+ int32_t smplinfosize = mCurrentDefaultSampleInfoSize;
+ if (smplinfosize == 0) {
+ smplinfosize = mCurrentSampleInfoSizes[i];
+ }
+ readSubsamples = smplinfosize > ivlength;
}
- if (smplinfosize > ivlength) {
+
+ if (readSubsamples) {
uint16_t numsubsamples;
- if (!mDataSource->getUInt16(drmoffset, &numsubsamples)) {
+ if (!mDataSource->getUInt16(offset, &numsubsamples)) {
return ERROR_IO;
}
- drmoffset += 2;
+ offset += 2;
for (size_t j = 0; j < numsubsamples; j++) {
uint16_t numclear;
uint32_t numencrypted;
- if (!mDataSource->getUInt16(drmoffset, &numclear)) {
+ if (!mDataSource->getUInt16(offset, &numclear)) {
return ERROR_IO;
}
- drmoffset += 2;
- if (!mDataSource->getUInt32(drmoffset, &numencrypted)) {
+ offset += 2;
+ if (!mDataSource->getUInt32(offset, &numencrypted)) {
return ERROR_IO;
}
- drmoffset += 4;
+ offset += 4;
smpl->clearsizes.add(numclear);
smpl->encryptedsizes.add(numencrypted);
}
@@ -4225,10 +4364,17 @@
}
}
-
return OK;
}
+status_t MPEG4Source::parseSampleEncryption(off64_t offset) {
+ uint32_t flags;
+ if (!mDataSource->getUInt32(offset, &flags)) { // actually version + flags
+ return ERROR_MALFORMED;
+ }
+ return parseClearEncryptedSizes(offset + 4, true, flags);
+}
+
status_t MPEG4Source::parseTrackFragmentHeader(off64_t offset, off64_t size) {
if (size < 8) {
@@ -4480,6 +4626,7 @@
tmp.size = sampleSize;
tmp.duration = sampleDuration;
tmp.compositionOffset = sampleCtsOffset;
+ memset(tmp.iv, 0, sizeof(tmp.iv));
mCurrentSamples.add(tmp);
dataOffset += sampleSize;
@@ -4984,10 +5131,22 @@
smpl->clearsizes.array(), smpl->clearsizes.size() * 4);
bufmeta.setData(kKeyEncryptedSizes, 0,
smpl->encryptedsizes.array(), smpl->encryptedsizes.size() * 4);
- bufmeta.setData(kKeyCryptoIV, 0, smpl->iv, 16); // use 16 or the actual size?
bufmeta.setInt32(kKeyCryptoDefaultIVSize, mDefaultIVSize);
bufmeta.setInt32(kKeyCryptoMode, mCryptoMode);
bufmeta.setData(kKeyCryptoKey, 0, mCryptoKey, 16);
+ bufmeta.setInt32(kKeyEncryptedByteBlock, mDefaultEncryptedByteBlock);
+ bufmeta.setInt32(kKeySkipByteBlock, mDefaultSkipByteBlock);
+
+ uint32_t type = 0;
+ const void *iv = NULL;
+ size_t ivlength = 0;
+ if (!mFormat.findData(
+ kKeyCryptoIV, &type, &iv, &ivlength)) {
+ iv = smpl->iv;
+ ivlength = 16; // use 16 or the actual size?
+ }
+ bufmeta.setData(kKeyCryptoIV, 0, iv, ivlength);
+
}
if ((!mIsAVC && !mIsHEVC)|| mWantsNALFragments) {
diff --git a/media/extractors/mp4/MPEG4Extractor.h b/media/extractors/mp4/MPEG4Extractor.h
index 831f120..3ea0963 100644
--- a/media/extractors/mp4/MPEG4Extractor.h
+++ b/media/extractors/mp4/MPEG4Extractor.h
@@ -85,6 +85,7 @@
bool has_elst;
int64_t elst_media_time;
uint64_t elst_segment_duration;
+ bool subsample_encryption;
};
Vector<SidxEntry> mSidxEntries;
diff --git a/media/libaaudio/examples/loopback/src/LoopbackAnalyzer.h b/media/libaaudio/examples/loopback/src/LoopbackAnalyzer.h
index f618d3d..ef9a753 100644
--- a/media/libaaudio/examples/loopback/src/LoopbackAnalyzer.h
+++ b/media/libaaudio/examples/loopback/src/LoopbackAnalyzer.h
@@ -41,12 +41,16 @@
#define MAX_ZEROTH_PARTIAL_BINS 40
constexpr double MAX_ECHO_GAIN = 10.0; // based on experiments, otherwise autocorrelation too noisy
+// A narrow impulse seems to have better immunity against over estimating the
+// latency due to detecting subharmonics by the auto-correlator.
static const float s_Impulse[] = {
- 0.0f, 0.0f, 0.0f, 0.0f, 0.2f, // silence on each side of the impulse
- 0.5f, 0.9999f, 0.0f, -0.9999, -0.5f, // bipolar
- -0.2f, 0.0f, 0.0f, 0.0f, 0.0f
+ 0.0f, 0.0f, 0.0f, 0.0f, 0.3f, // silence on each side of the impulse
+ 0.99f, 0.0f, -0.99f, // bipolar with one zero crossing in middle
+ -0.3f, 0.0f, 0.0f, 0.0f, 0.0f
};
+constexpr int32_t kImpulseSizeInFrames = (int32_t)(sizeof(s_Impulse) / sizeof(s_Impulse[0]));
+
class PseudoRandom {
public:
PseudoRandom() {}
@@ -498,13 +502,23 @@
printf("st = %d, echo gain = %f ", mState, mEchoGain);
}
- static void sendImpulse(float *outputData, int outputChannelCount) {
- for (float sample : s_Impulse) {
+ void sendImpulses(float *outputData, int outputChannelCount, int numFrames) {
+ while (numFrames-- > 0) {
+ float sample = s_Impulse[mSampleIndex++];
+ if (mSampleIndex >= kImpulseSizeInFrames) {
+ mSampleIndex = 0;
+ }
+
*outputData = sample;
outputData += outputChannelCount;
}
}
+ void sendOneImpulse(float *outputData, int outputChannelCount) {
+ mSampleIndex = 0;
+ sendImpulses(outputData, outputChannelCount, kImpulseSizeInFrames);
+ }
+
void process(float *inputData, int inputChannelCount,
float *outputData, int outputChannelCount,
int numFrames) override {
@@ -530,7 +544,7 @@
break;
case STATE_MEASURING_GAIN:
- sendImpulse(outputData, outputChannelCount);
+ sendImpulses(outputData, outputChannelCount, numFrames);
peak = measurePeakAmplitude(inputData, inputChannelCount, numFrames);
// If we get several in a row then go to next state.
if (peak > mPulseThreshold) {
@@ -548,7 +562,7 @@
nextState = STATE_WAITING_FOR_SILENCE;
}
}
- } else {
+ } else if (numFrames > kImpulseSizeInFrames){ // ignore short callbacks
mDownCounter = 8;
}
break;
@@ -574,7 +588,7 @@
case STATE_SENDING_PULSE:
mAudioRecording.write(inputData, inputChannelCount, numFrames);
- sendImpulse(outputData, outputChannelCount);
+ sendOneImpulse(outputData, outputChannelCount);
nextState = STATE_GATHERING_ECHOS;
//printf("%5d: switch to STATE_GATHERING_ECHOS\n", mLoopCounter);
break;
@@ -634,8 +648,9 @@
STATE_FAILED
};
- int mDownCounter = 500;
- int mLoopCounter = 0;
+ int32_t mDownCounter = 500;
+ int32_t mLoopCounter = 0;
+ int32_t mSampleIndex = 0;
float mPulseThreshold = 0.02f;
float mSilenceThreshold = 0.002f;
float mMeasuredLoopGain = 0.0f;
diff --git a/media/libaaudio/examples/loopback/src/loopback.cpp b/media/libaaudio/examples/loopback/src/loopback.cpp
index 26d1e4b..91ebf73 100644
--- a/media/libaaudio/examples/loopback/src/loopback.cpp
+++ b/media/libaaudio/examples/loopback/src/loopback.cpp
@@ -42,7 +42,7 @@
#define NUM_INPUT_CHANNELS 1
#define FILENAME_ALL "/data/loopback_all.wav"
#define FILENAME_ECHOS "/data/loopback_echos.wav"
-#define APP_VERSION "0.2.03"
+#define APP_VERSION "0.2.04"
constexpr int kNumCallbacksToDrain = 20;
constexpr int kNumCallbacksToDiscard = 20;
@@ -98,6 +98,9 @@
framesRead = AAudioStream_read(myData->inputStream, myData->inputFloatData,
numFrames,
0 /* timeoutNanoseconds */);
+ } else {
+ printf("ERROR actualInputFormat = %d\n", myData->actualInputFormat);
+ assert(false);
}
if (framesRead < 0) {
myData->inputError = framesRead;
@@ -121,7 +124,7 @@
float *outputData = (float *) audioData;
// Read audio data from the input stream.
- int32_t framesRead;
+ int32_t actualFramesRead;
if (numFrames > myData->inputFramesMaximum) {
myData->inputError = AAUDIO_ERROR_OUT_OF_RANGE;
@@ -141,16 +144,23 @@
if (myData->numCallbacksToDrain > 0) {
// Drain the input.
+ int32_t totalFramesRead = 0;
do {
- framesRead = readFormattedData(myData, numFrames);
+ actualFramesRead = readFormattedData(myData, numFrames);
+ if (actualFramesRead) {
+ totalFramesRead += actualFramesRead;
+ }
// Ignore errors because input stream may not be started yet.
- } while (framesRead > 0);
- myData->numCallbacksToDrain--;
+ } while (actualFramesRead > 0);
+ // Only counts if we actually got some data.
+ if (totalFramesRead > 0) {
+ myData->numCallbacksToDrain--;
+ }
} else if (myData->numCallbacksToDiscard > 0) {
// Ignore. Allow the input to fill back up to equilibrium with the output.
- framesRead = readFormattedData(myData, numFrames);
- if (framesRead < 0) {
+ actualFramesRead = readFormattedData(myData, numFrames);
+ if (actualFramesRead < 0) {
result = AAUDIO_CALLBACK_RESULT_STOP;
}
myData->numCallbacksToDiscard--;
@@ -164,21 +174,29 @@
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) {
+ actualFramesRead = readFormattedData(myData, numFrames);
+ if (actualFramesRead < 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);
+ if (actualFramesRead < numFrames) {
+ if(actualFramesRead < (int32_t) framesAvailable) {
+ printf("insufficient but numFrames = %d"
+ ", actualFramesRead = %d"
+ ", inputFramesWritten = %d"
+ ", inputFramesRead = %d"
+ ", available = %d\n",
+ numFrames,
+ actualFramesRead,
+ (int) inputFramesWritten,
+ (int) inputFramesRead,
+ (int) framesAvailable);
}
myData->insufficientReadCount++;
- myData->insufficientReadFrames += numFrames - framesRead; // deficit
+ myData->insufficientReadFrames += numFrames - actualFramesRead; // deficit
}
- int32_t numSamples = framesRead * myData->actualInputChannelCount;
+ int32_t numSamples = actualFramesRead * myData->actualInputChannelCount;
if (myData->actualInputFormat == AAUDIO_FORMAT_PCM_I16) {
convertPcm16ToFloat(myData->inputShortData, myData->inputFloatData, numSamples);
@@ -216,6 +234,7 @@
static void usage() {
printf("Usage: aaudio_loopback [OPTION]...\n\n");
AAudioArgsParser::usage();
+ printf(" -B{frames} input capacity in frames\n");
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");
@@ -312,16 +331,18 @@
AAudioSimplePlayer player;
AAudioSimpleRecorder recorder;
LoopbackData loopbackData;
- AAudioStream *inputStream = nullptr;
+ AAudioStream *inputStream = nullptr;
AAudioStream *outputStream = nullptr;
aaudio_result_t result = AAUDIO_OK;
aaudio_sharing_mode_t requestedInputSharingMode = AAUDIO_SHARING_MODE_SHARED;
int requestedInputChannelCount = NUM_INPUT_CHANNELS;
aaudio_format_t requestedInputFormat = AAUDIO_FORMAT_UNSPECIFIED;
- const aaudio_format_t requestedOutputFormat = AAUDIO_FORMAT_PCM_FLOAT;
+ int32_t requestedInputCapacity = -1;
aaudio_performance_mode_t inputPerformanceLevel = AAUDIO_PERFORMANCE_MODE_LOW_LATENCY;
+ int32_t outputFramesPerBurst = 0;
+
aaudio_format_t actualOutputFormat = AAUDIO_FORMAT_INVALID;
int32_t actualSampleRate = 0;
int written = 0;
@@ -342,6 +363,9 @@
if (arg[0] == '-') {
char option = arg[1];
switch (option) {
+ case 'B':
+ requestedInputCapacity = atoi(&arg[2]);
+ break;
case 'C':
requestedInputChannelCount = atoi(&arg[2]);
break;
@@ -408,7 +432,6 @@
}
printf("OUTPUT stream ----------------------------------------\n");
- argParser.setFormat(requestedOutputFormat);
result = player.open(argParser, MyDataCallbackProc, MyErrorCallbackProc, &loopbackData);
if (result != AAUDIO_OK) {
fprintf(stderr, "ERROR - player.open() returned %d\n", result);
@@ -417,11 +440,15 @@
outputStream = player.getStream();
actualOutputFormat = AAudioStream_getFormat(outputStream);
- assert(actualOutputFormat == AAUDIO_FORMAT_PCM_FLOAT);
+ if (actualOutputFormat != AAUDIO_FORMAT_PCM_FLOAT) {
+ fprintf(stderr, "ERROR - only AAUDIO_FORMAT_PCM_FLOAT supported\n");
+ exit(1);
+ }
actualSampleRate = AAudioStream_getSampleRate(outputStream);
loopbackData.audioRecording.allocate(recordingDuration * actualSampleRate);
loopbackData.audioRecording.setSampleRate(actualSampleRate);
+ outputFramesPerBurst = AAudioStream_getFramesPerBurst(outputStream);
argParser.compareWithStream(outputStream);
@@ -435,8 +462,11 @@
// 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;
+ int32_t inputBufferCapacity = requestedInputCapacity;
+ if (inputBufferCapacity < 0) {
+ int32_t outputBufferCapacity = AAudioStream_getBufferCapacityInFrames(outputStream);
+ inputBufferCapacity = 2 * outputBufferCapacity;
+ }
argParser.setBufferCapacity(inputBufferCapacity);
result = recorder.open(argParser);
@@ -457,6 +487,15 @@
argParser.compareWithStream(inputStream);
+ // If the input stream is too small then we cannot satisfy the output callback.
+ {
+ int32_t actualCapacity = AAudioStream_getBufferCapacityInFrames(inputStream);
+ if (actualCapacity < 2 * outputFramesPerBurst) {
+ fprintf(stderr, "ERROR - input capacity < 2 * outputFramesPerBurst\n");
+ goto finish;
+ }
+ }
+
// ------- Setup loopbackData -----------------------------
loopbackData.actualInputFormat = AAudioStream_getFormat(inputStream);
@@ -499,7 +538,7 @@
printf(" ERROR on output stream\n");
break;
} else if (loopbackData.isDone) {
- printf(" test says it is done!\n");
+ printf(" Test says it is DONE!\n");
break;
} else {
// Log a line of stream data.
diff --git a/media/libaaudio/examples/loopback/src/loopback.sh b/media/libaaudio/examples/loopback/src/loopback.sh
index bc63125..a5712b8 100644
--- a/media/libaaudio/examples/loopback/src/loopback.sh
+++ b/media/libaaudio/examples/loopback/src/loopback.sh
@@ -1,10 +1,30 @@
#!/system/bin/sh
# Run a loopback test in the background after a delay.
-# To run the script enter:
+# To run the script, enter these commands once:
+# adb disable-verity
+# adb reboot
+# adb remount
+# adb sync
+# adb push loopback.sh /data/
+# For each test run:
# adb shell "nohup sh /data/loopback.sh &"
+# Quickly connect USB audio if needed, either manually or via Tigertail switch.
+# Wait until the test completes, restore USB to host if needed, and then:
+# adb pull /data/loopreport.txt
+# adb pull /data/loopback_all.wav
+# adb pull /data/loopback_echos.wav
SLEEP_TIME=10
-TEST_COMMAND="aaudio_loopback -pl -Pl -C1 -n2 -m2 -tm -d5"
+TEST_COMMAND="/data/nativetest/aaudio_loopback/aaudio_loopback -pl -Pl -C1 -n2 -m2 -te -d5"
+# Partial list of options:
+# -pl (output) performance mode: low latency
+# -Pl input performance mode: low latency
+# -C1 input channel count: 1
+# -n2 number of bursts: 2
+# -m2 mmap policy: 2
+# -t? test mode: -tm for sine magnitude, -te for echo latency, -tf for file latency
+# -d5 device ID
+# For full list of available options, see AAudioArgsParser.h and loopback.cpp
echo "Plug in USB Mir and Fun Plug."
echo "Test will start in ${SLEEP_TIME} seconds: ${TEST_COMMAND}"
diff --git a/media/libmediaextractor/include/media/stagefright/MetaDataBase.h b/media/libmediaextractor/include/media/stagefright/MetaDataBase.h
index 6ad2441..dfe34e8 100644
--- a/media/libmediaextractor/include/media/stagefright/MetaDataBase.h
+++ b/media/libmediaextractor/include/media/stagefright/MetaDataBase.h
@@ -182,6 +182,9 @@
kKeyCASystemID = 'caid', // int32_t
kKeyCASessionID = 'seid', // raw data
+ kKeyEncryptedByteBlock = 'cblk', // uint8_t
+ kKeySkipByteBlock = 'sblk', // uint8_t
+
// Please see MediaFormat.KEY_IS_AUTOSELECT.
kKeyTrackIsAutoselect = 'auto', // bool (int32_t)
// Please see MediaFormat.KEY_IS_DEFAULT.
@@ -231,6 +234,12 @@
kTypeD263 = 'd263',
};
+enum {
+ kCryptoModeUnencrypted = 0,
+ kCryptoModeAesCtr = 1,
+ kCryptoModeAesCbc = 2,
+};
+
class Parcel;
class MetaDataBase {
diff --git a/media/libstagefright/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp
index f292c47..9f39b5e 100644
--- a/media/libstagefright/httplive/PlaylistFetcher.cpp
+++ b/media/libstagefright/httplive/PlaylistFetcher.cpp
@@ -1029,7 +1029,8 @@
sp<AMessage> itemMeta;
int64_t itemDurationUs;
int32_t targetDuration;
- if (mPlaylist->meta()->findInt32("target-duration", &targetDuration)) {
+ if (mPlaylist->meta() != NULL
+ && mPlaylist->meta()->findInt32("target-duration", &targetDuration)) {
do {
--index;
if (!mPlaylist->itemAt(index, NULL /* uri */, &itemMeta)
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index c87b5eb..282871b 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -2337,10 +2337,13 @@
void CameraService::Client::notifyError(int32_t errorCode,
const CaptureResultExtras& resultExtras) {
- (void) errorCode;
(void) resultExtras;
if (mRemoteCallback != NULL) {
- mRemoteCallback->notifyCallback(CAMERA_MSG_ERROR, CAMERA_ERROR_RELEASED, 0);
+ int32_t api1ErrorCode = CAMERA_ERROR_RELEASED;
+ if (errorCode == hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_DISABLED) {
+ api1ErrorCode = CAMERA_ERROR_DISABLED;
+ }
+ mRemoteCallback->notifyCallback(CAMERA_MSG_ERROR, api1ErrorCode, 0);
} else {
ALOGE("mRemoteCallback is NULL!!");
}
diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp b/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
index 37e1495..8dc9863 100644
--- a/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
@@ -802,29 +802,25 @@
__FUNCTION__);
continue;
}
- uint8_t afMode = entry.data.u8[0];
- if (afMode == ANDROID_CONTROL_AF_MODE_OFF) {
- // Skip all the ZSL buffer for manual AF mode, as we don't really
- // know the af state.
- continue;
- }
-
// Check AF state if device has focuser and focus mode isn't fixed
- if (mHasFocuser && !isFixedFocusMode(afMode)) {
- // Make sure the candidate frame has good focus.
- entry = frame.find(ANDROID_CONTROL_AF_STATE);
- if (entry.count == 0) {
- ALOGW("%s: ZSL queue frame has no AF state field!",
- __FUNCTION__);
- continue;
- }
- uint8_t afState = entry.data.u8[0];
- if (afState != ANDROID_CONTROL_AF_STATE_PASSIVE_FOCUSED &&
- afState != ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED &&
- afState != ANDROID_CONTROL_AF_STATE_NOT_FOCUSED_LOCKED) {
- ALOGVV("%s: ZSL queue frame AF state is %d is not good for capture, skip it",
- __FUNCTION__, afState);
- continue;
+ if (mHasFocuser) {
+ uint8_t afMode = entry.data.u8[0];
+ if (!isFixedFocusMode(afMode)) {
+ // Make sure the candidate frame has good focus.
+ entry = frame.find(ANDROID_CONTROL_AF_STATE);
+ if (entry.count == 0) {
+ ALOGW("%s: ZSL queue frame has no AF state field!",
+ __FUNCTION__);
+ continue;
+ }
+ uint8_t afState = entry.data.u8[0];
+ if (afState != ANDROID_CONTROL_AF_STATE_PASSIVE_FOCUSED &&
+ afState != ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED &&
+ afState != ANDROID_CONTROL_AF_STATE_NOT_FOCUSED_LOCKED) {
+ ALOGVV("%s: ZSL queue frame AF state is %d is not good for capture,"
+ " skip it", __FUNCTION__, afState);
+ continue;
+ }
}
}