Merge "Aaudio: Implement app shareable flag instead of -size hack"
diff --git a/media/extractors/flac/FLACExtractor.cpp b/media/extractors/flac/FLACExtractor.cpp
index e3da259..a721b65 100644
--- a/media/extractors/flac/FLACExtractor.cpp
+++ b/media/extractors/flac/FLACExtractor.cpp
@@ -18,6 +18,8 @@
#define LOG_TAG "FLACExtractor"
#include <utils/Log.h>
+#include <stdint.h>
+
#include "FLACExtractor.h"
// libFLAC parser
#include "FLAC/stream_decoder.h"
@@ -124,7 +126,7 @@
// media buffers
size_t mMaxBufferSize;
MediaBufferGroup *mGroup;
- void (*mCopy)(short *dst, const int * src[kMaxChannels], unsigned nSamples, unsigned nChannels);
+ void (*mCopy)(int16_t *dst, const int * src[kMaxChannels], unsigned nSamples, unsigned nChannels);
// handle to underlying libFLAC parser
FLAC__StreamDecoder *mDecoder;
@@ -383,7 +385,7 @@
// These are candidates for optimization if needed.
static void copyMono8(
- short *dst,
+ int16_t *dst,
const int * src[FLACParser::kMaxChannels],
unsigned nSamples,
unsigned /* nChannels */) {
@@ -393,7 +395,7 @@
}
static void copyStereo8(
- short *dst,
+ int16_t *dst,
const int * src[FLACParser::kMaxChannels],
unsigned nSamples,
unsigned /* nChannels */) {
@@ -403,7 +405,7 @@
}
}
-static void copyMultiCh8(short *dst, const int * src[FLACParser::kMaxChannels], unsigned nSamples, unsigned nChannels)
+static void copyMultiCh8(int16_t *dst, const int * src[FLACParser::kMaxChannels], unsigned nSamples, unsigned nChannels)
{
for (unsigned i = 0; i < nSamples; ++i) {
for (unsigned c = 0; c < nChannels; ++c) {
@@ -413,7 +415,7 @@
}
static void copyMono16(
- short *dst,
+ int16_t *dst,
const int * src[FLACParser::kMaxChannels],
unsigned nSamples,
unsigned /* nChannels */) {
@@ -423,7 +425,7 @@
}
static void copyStereo16(
- short *dst,
+ int16_t *dst,
const int * src[FLACParser::kMaxChannels],
unsigned nSamples,
unsigned /* nChannels */) {
@@ -433,7 +435,7 @@
}
}
-static void copyMultiCh16(short *dst, const int * src[FLACParser::kMaxChannels], unsigned nSamples, unsigned nChannels)
+static void copyMultiCh16(int16_t *dst, const int * src[FLACParser::kMaxChannels], unsigned nSamples, unsigned nChannels)
{
for (unsigned i = 0; i < nSamples; ++i) {
for (unsigned c = 0; c < nChannels; ++c) {
@@ -445,7 +447,7 @@
// 24-bit versions should do dithering or noise-shaping, here or in AudioFlinger
static void copyMono24(
- short *dst,
+ int16_t *dst,
const int * src[FLACParser::kMaxChannels],
unsigned nSamples,
unsigned /* nChannels */) {
@@ -455,7 +457,7 @@
}
static void copyStereo24(
- short *dst,
+ int16_t *dst,
const int * src[FLACParser::kMaxChannels],
unsigned nSamples,
unsigned /* nChannels */) {
@@ -465,7 +467,7 @@
}
}
-static void copyMultiCh24(short *dst, const int * src[FLACParser::kMaxChannels], unsigned nSamples, unsigned nChannels)
+static void copyMultiCh24(int16_t *dst, const int * src[FLACParser::kMaxChannels], unsigned nSamples, unsigned nChannels)
{
for (unsigned i = 0; i < nSamples; ++i) {
for (unsigned c = 0; c < nChannels; ++c) {
@@ -475,7 +477,7 @@
}
static void copyTrespass(
- short * /* dst */,
+ int16_t * /* dst */,
const int *[FLACParser::kMaxChannels] /* src */,
unsigned /* nSamples */,
unsigned /* nChannels */) {
@@ -592,7 +594,7 @@
static const struct {
unsigned mChannels;
unsigned mBitsPerSample;
- void (*mCopy)(short *dst, const int * src[kMaxChannels], unsigned nSamples, unsigned nChannels);
+ void (*mCopy)(int16_t *dst, const int * src[kMaxChannels], unsigned nSamples, unsigned nChannels);
} table[] = {
{ 1, 8, copyMono8 },
{ 2, 8, copyStereo8 },
@@ -635,7 +637,7 @@
{
CHECK(mGroup == NULL);
mGroup = new MediaBufferGroup;
- mMaxBufferSize = getMaxBlockSize() * getChannels() * sizeof(short);
+ mMaxBufferSize = getMaxBlockSize() * getChannels() * sizeof(int16_t);
mGroup->add_buffer(MediaBufferBase::Create(mMaxBufferSize));
}
@@ -688,9 +690,9 @@
if (err != OK) {
return NULL;
}
- size_t bufferSize = blocksize * getChannels() * sizeof(short);
+ size_t bufferSize = blocksize * getChannels() * sizeof(int16_t);
CHECK(bufferSize <= mMaxBufferSize);
- short *data = (short *) buffer->data();
+ int16_t *data = (int16_t *) buffer->data();
buffer->set_range(0, bufferSize);
// copy PCM from FLAC write buffer to our media buffer, with interleaving
(*mCopy)(data, mWriteBuffer, blocksize, getChannels());
diff --git a/media/extractors/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
index 7b3b81d..5331ba8 100644
--- a/media/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/extractors/mp4/MPEG4Extractor.cpp
@@ -66,6 +66,8 @@
kMaxAtomSize = 64 * 1024 * 1024,
};
+static const size_t kMaxPcmFrameSize = 8192;
+
class MPEG4Source : public MediaTrack {
public:
// Caller retains ownership of both "dataSource" and "sampleTable".
@@ -125,6 +127,7 @@
bool mIsAVC;
bool mIsHEVC;
+ bool mIsPcm;
size_t mNALLengthSize;
bool mStarted;
@@ -324,6 +327,11 @@
case FOURCC('h', 'v', 'c', '1'):
case FOURCC('h', 'e', 'v', '1'):
return MEDIA_MIMETYPE_VIDEO_HEVC;
+
+ case FOURCC('t', 'w', 'o', 's'):
+ case FOURCC('s', 'o', 'w', 't'):
+ return MEDIA_MIMETYPE_AUDIO_RAW;
+
default:
ALOGW("Unknown fourcc: %c%c%c%c",
(fourcc >> 24) & 0xff,
@@ -467,8 +475,15 @@
if (__builtin_mul_overflow(media_time, samplerate, &delay) ||
__builtin_add_overflow(delay, halfscale, &delay) ||
(delay /= mHeaderTimescale, false) ||
- delay > INT32_MAX ||
- delay < INT32_MIN) {
+ /* the calculated delay should be small, but some apps
+ * appear to write a bogus edit list that causes a really
+ * large delay, resulting in playback problems.
+ * Ignore such edit lists.
+ * (4096 is enough to drop 4 full samples)
+ */
+ delay > 4096 ||
+ delay < 0) {
+ ALOGW("ignoring edit list with bogus values");
return;
}
ALOGV("delay = %" PRId64, delay);
@@ -1473,6 +1488,8 @@
case FOURCC('e', 'n', 'c', 'a'):
case FOURCC('s', 'a', 'm', 'r'):
case FOURCC('s', 'a', 'w', 'b'):
+ case FOURCC('t', 'w', 'o', 's'):
+ case FOURCC('s', 'o', 'w', 't'):
{
if (mIsQT && chunk_type == FOURCC('m', 'p', '4', 'a')
&& depth >= 1 && mPath[depth - 1] == FOURCC('w', 'a', 'v', 'e')) {
@@ -1542,6 +1559,13 @@
// if the chunk type is enca, we'll get the type from the frma box later
mLastTrack->meta.setCString(kKeyMIMEType, FourCC2MIME(chunk_type));
AdjustChannelsAndRate(chunk_type, &num_channels, &sample_rate);
+
+ if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_RAW, FourCC2MIME(chunk_type))) {
+ mLastTrack->meta.setInt32(kKeyBitsPerSample, sample_size);
+ if (chunk_type == FOURCC('t', 'w', 'o', 's')) {
+ mLastTrack->meta.setInt32(kKeyPcmBigEndian, 1);
+ }
+ }
}
ALOGV("*** coding='%s' %d channels, size %d, rate %d\n",
chunk, num_channels, sample_size, sample_rate);
@@ -3857,6 +3881,7 @@
mCurrentSampleInfoOffsets(NULL),
mIsAVC(false),
mIsHEVC(false),
+ mIsPcm(false),
mNALLengthSize(0),
mStarted(false),
mGroup(NULL),
@@ -3918,6 +3943,27 @@
mNALLengthSize = 1 + (ptr[14 + 7] & 3);
}
+ mIsPcm = !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW);
+
+ if (mIsPcm) {
+ int32_t numChannels = 0;
+ int32_t bitsPerSample = 0;
+ CHECK(mFormat.findInt32(kKeyBitsPerSample, &bitsPerSample));
+ CHECK(mFormat.findInt32(kKeyChannelCount, &numChannels));
+
+ int32_t bytesPerSample = bitsPerSample >> 3;
+ int32_t pcmSampleSize = bytesPerSample * numChannels;
+
+ size_t maxSampleSize;
+ status_t err = mSampleTable->getMaxSampleSize(&maxSampleSize);
+ if (err != OK || maxSampleSize != static_cast<size_t>(pcmSampleSize) || bitsPerSample != 16) {
+ // Not supported
+ mIsPcm = false;
+ } else {
+ mFormat.setInt32(kKeyMaxInputSize, pcmSampleSize * kMaxPcmFrameSize);
+ }
+ }
+
CHECK(format.findInt32(kKeyTrackID, &mTrackId));
}
@@ -4832,34 +4878,78 @@
if ((!mIsAVC && !mIsHEVC) || mWantsNALFragments) {
if (newBuffer) {
- ssize_t num_bytes_read =
- mDataSource->readAt(offset, (uint8_t *)mBuffer->data(), size);
+ if (mIsPcm) {
+ // The twos' PCM block reader assumes that all samples has the same size.
- if (num_bytes_read < (ssize_t)size) {
- mBuffer->release();
- mBuffer = NULL;
+ uint32_t samplesToRead = mSampleTable->getLastSampleIndexInChunk()
+ - mCurrentSampleIndex + 1;
+ if (samplesToRead > kMaxPcmFrameSize) {
+ samplesToRead = kMaxPcmFrameSize;
+ }
- return ERROR_IO;
- }
+ ALOGV("Reading %d PCM frames of size %zu at index %d to stop of chunk at %d",
+ samplesToRead, size, mCurrentSampleIndex,
+ mSampleTable->getLastSampleIndexInChunk());
- CHECK(mBuffer != NULL);
- mBuffer->set_range(0, size);
- mBuffer->meta_data().clear();
- mBuffer->meta_data().setInt64(
- kKeyTime, ((int64_t)cts * 1000000) / mTimescale);
- mBuffer->meta_data().setInt64(
- kKeyDuration, ((int64_t)stts * 1000000) / mTimescale);
+ size_t totalSize = samplesToRead * size;
+ uint8_t* buf = (uint8_t *)mBuffer->data();
+ ssize_t bytesRead = mDataSource->readAt(offset, buf, totalSize);
+ if (bytesRead < (ssize_t)totalSize) {
+ mBuffer->release();
+ mBuffer = NULL;
- if (targetSampleTimeUs >= 0) {
- mBuffer->meta_data().setInt64(
- kKeyTargetTime, targetSampleTimeUs);
- }
+ return ERROR_IO;
+ }
- if (isSyncSample) {
+ mBuffer->meta_data().clear();
+ mBuffer->meta_data().setInt64(kKeyTime, ((int64_t)cts * 1000000) / mTimescale);
mBuffer->meta_data().setInt32(kKeyIsSyncFrame, 1);
- }
- ++mCurrentSampleIndex;
+ int32_t byteOrder;
+ mFormat.findInt32(kKeyPcmBigEndian, &byteOrder);
+
+ if (byteOrder == 1) {
+ // Big-endian -> little-endian
+ uint16_t *dstData = (uint16_t *)buf;
+ uint16_t *srcData = (uint16_t *)buf;
+
+ for (size_t j = 0; j < bytesRead / sizeof(uint16_t); j++) {
+ dstData[j] = ntohs(srcData[j]);
+ }
+ }
+
+ mCurrentSampleIndex += samplesToRead;
+ mBuffer->set_range(0, totalSize);
+ } else {
+ ssize_t num_bytes_read =
+ mDataSource->readAt(offset, (uint8_t *)mBuffer->data(), size);
+
+ if (num_bytes_read < (ssize_t)size) {
+ mBuffer->release();
+ mBuffer = NULL;
+
+ return ERROR_IO;
+ }
+
+ CHECK(mBuffer != NULL);
+ mBuffer->set_range(0, size);
+ mBuffer->meta_data().clear();
+ mBuffer->meta_data().setInt64(
+ kKeyTime, ((int64_t)cts * 1000000) / mTimescale);
+ mBuffer->meta_data().setInt64(
+ kKeyDuration, ((int64_t)stts * 1000000) / mTimescale);
+
+ if (targetSampleTimeUs >= 0) {
+ mBuffer->meta_data().setInt64(
+ kKeyTargetTime, targetSampleTimeUs);
+ }
+
+ if (isSyncSample) {
+ mBuffer->meta_data().setInt32(kKeyIsSyncFrame, 1);
+ }
+
+ ++mCurrentSampleIndex;
+ }
}
if (!mIsAVC && !mIsHEVC) {
diff --git a/media/extractors/mp4/SampleIterator.h b/media/extractors/mp4/SampleIterator.h
index 6a3fd3b..6e4f60e 100644
--- a/media/extractors/mp4/SampleIterator.h
+++ b/media/extractors/mp4/SampleIterator.h
@@ -36,6 +36,11 @@
uint32_t getSampleTime() const { return mCurrentSampleTime; }
uint32_t getSampleDuration() const { return mCurrentSampleDuration; }
+ uint32_t getLastSampleIndexInChunk() const {
+ return mCurrentSampleIndex + mSamplesPerChunk -
+ ((mCurrentSampleIndex - mFirstChunkSampleIndex) % mSamplesPerChunk) - 1;
+ }
+
status_t getSampleSizeDirect(
uint32_t sampleIndex, size_t *size);
diff --git a/media/extractors/mp4/SampleTable.cpp b/media/extractors/mp4/SampleTable.cpp
index 81c353e..28fe717 100644
--- a/media/extractors/mp4/SampleTable.cpp
+++ b/media/extractors/mp4/SampleTable.cpp
@@ -946,6 +946,11 @@
sampleIndex, sampleSize);
}
+uint32_t SampleTable::getLastSampleIndexInChunk() {
+ Mutex::Autolock autoLock(mLock);
+ return mSampleIterator->getLastSampleIndexInChunk();
+}
+
status_t SampleTable::getMetaDataForSample(
uint32_t sampleIndex,
off64_t *offset,
diff --git a/media/extractors/mp4/SampleTable.h b/media/extractors/mp4/SampleTable.h
index e4e974b..dd68860 100644
--- a/media/extractors/mp4/SampleTable.h
+++ b/media/extractors/mp4/SampleTable.h
@@ -69,6 +69,9 @@
bool *isSyncSample = NULL,
uint32_t *sampleDuration = NULL);
+ // call only after getMetaDataForSample has been called successfully.
+ uint32_t getLastSampleIndexInChunk();
+
enum {
kFlagBefore,
kFlagAfter,
diff --git a/media/libaudioclient/AudioEffect.cpp b/media/libaudioclient/AudioEffect.cpp
index b1cb0e7..b40f0db 100644
--- a/media/libaudioclient/AudioEffect.cpp
+++ b/media/libaudioclient/AudioEffect.cpp
@@ -52,6 +52,7 @@
)
: mStatus(NO_INIT), mOpPackageName(opPackageName)
{
+ AutoMutex lock(mConstructLock);
mStatus = set(type, uuid, priority, cbf, user, sessionId, io);
}
@@ -85,6 +86,7 @@
}
}
+ AutoMutex lock(mConstructLock);
mStatus = set(pType, pUuid, priority, cbf, user, sessionId, io);
}
diff --git a/media/libaudioclient/include/media/AudioEffect.h b/media/libaudioclient/include/media/AudioEffect.h
index bfc068b..324bcb9 100644
--- a/media/libaudioclient/include/media/AudioEffect.h
+++ b/media/libaudioclient/include/media/AudioEffect.h
@@ -414,6 +414,7 @@
effect_descriptor_t mDescriptor; // effect descriptor
int32_t mId; // system wide unique effect engine instance ID
Mutex mLock; // Mutex for mEnabled access
+ Mutex mConstructLock; // Mutex for integrality construction
String16 mOpPackageName; // The package name used for app op checks.
@@ -440,12 +441,22 @@
virtual void controlStatusChanged(bool controlGranted) {
sp<AudioEffect> effect = mEffect.promote();
if (effect != 0) {
+ {
+ // Got the mConstructLock means the construction of AudioEffect
+ // has finished, we should release the mConstructLock immediately.
+ AutoMutex lock(effect->mConstructLock);
+ }
effect->controlStatusChanged(controlGranted);
}
}
virtual void enableStatusChanged(bool enabled) {
sp<AudioEffect> effect = mEffect.promote();
if (effect != 0) {
+ {
+ // Got the mConstructLock means the construction of AudioEffect
+ // has finished, we should release the mConstructLock immediately.
+ AutoMutex lock(effect->mConstructLock);
+ }
effect->enableStatusChanged(enabled);
}
}
@@ -456,6 +467,11 @@
void *pReplyData) {
sp<AudioEffect> effect = mEffect.promote();
if (effect != 0) {
+ {
+ // Got the mConstructLock means the construction of AudioEffect
+ // has finished, we should release the mConstructLock immediately.
+ AutoMutex lock(effect->mConstructLock);
+ }
effect->commandExecuted(
cmdCode, cmdSize, pCmdData, replySize, pReplyData);
}
@@ -465,6 +481,11 @@
virtual void binderDied(const wp<IBinder>& /*who*/) {
sp<AudioEffect> effect = mEffect.promote();
if (effect != 0) {
+ {
+ // Got the mConstructLock means the construction of AudioEffect
+ // has finished, we should release the mConstructLock immediately.
+ AutoMutex lock(effect->mConstructLock);
+ }
effect->binderDied();
}
}
diff --git a/media/libeffects/config/include/media/EffectsConfig.h b/media/libeffects/config/include/media/EffectsConfig.h
index 55b946f..fa0415b 100644
--- a/media/libeffects/config/include/media/EffectsConfig.h
+++ b/media/libeffects/config/include/media/EffectsConfig.h
@@ -96,7 +96,7 @@
/** Parsed config, nullptr if the xml lib could not load the file */
std::unique_ptr<Config> parsedConfig;
size_t nbSkippedElement; //< Number of skipped invalid library, effect or processing chain
- const char* configPath; //< Path to the loaded configuration
+ const std::string configPath; //< Path to the loaded configuration
};
/** Parses the provided effect configuration.
diff --git a/media/libeffects/config/src/EffectsConfig.cpp b/media/libeffects/config/src/EffectsConfig.cpp
index d79501f..351b1ee 100644
--- a/media/libeffects/config/src/EffectsConfig.cpp
+++ b/media/libeffects/config/src/EffectsConfig.cpp
@@ -250,14 +250,14 @@
return true;
}
-/** Internal version of the public parse(const char* path) with precondition `path != nullptr`. */
-ParsingResult parseWithPath(const char* path) {
+/** Internal version of the public parse(const char* path) where path always exist. */
+ParsingResult parseWithPath(std::string&& path) {
XMLDocument doc;
- doc.LoadFile(path);
+ doc.LoadFile(path.c_str());
if (doc.Error()) {
- ALOGE("Failed to parse %s: Tinyxml2 error (%d): %s", path,
+ ALOGE("Failed to parse %s: Tinyxml2 error (%d): %s", path.c_str(),
doc.ErrorID(), doc.ErrorStr());
- return {nullptr, 0, path};
+ return {nullptr, 0, std::move(path)};
}
auto config = std::make_unique<Config>();
@@ -295,7 +295,7 @@
}
}
}
- return {std::move(config), nbSkippedElements, path};
+ return {std::move(config), nbSkippedElements, std::move(path)};
}
}; // namespace
@@ -310,14 +310,14 @@
if (access(defaultPath.c_str(), R_OK) != 0) {
continue;
}
- auto result = parseWithPath(defaultPath.c_str());
+ auto result = parseWithPath(std::move(defaultPath));
if (result.parsedConfig != nullptr) {
return result;
}
}
ALOGE("Could not parse effect configuration in any of the default locations.");
- return {nullptr, 0, nullptr};
+ return {nullptr, 0, ""};
}
} // namespace effectsConfig
diff --git a/media/libeffects/factory/EffectsXmlConfigLoader.cpp b/media/libeffects/factory/EffectsXmlConfigLoader.cpp
index 7a7d431..052a88b 100644
--- a/media/libeffects/factory/EffectsXmlConfigLoader.cpp
+++ b/media/libeffects/factory/EffectsXmlConfigLoader.cpp
@@ -327,7 +327,8 @@
&gSkippedEffects, &gSubEffectList);
ALOGE_IF(result.nbSkippedElement != 0, "%zu errors during loading of configuration: %s",
- result.nbSkippedElement, result.configPath ?: "No config file found");
+ result.nbSkippedElement,
+ result.configPath.empty() ? "No config file found" : result.configPath.c_str());
return result.nbSkippedElement;
}
diff --git a/media/libmediaextractor/MediaBuffer.cpp b/media/libmediaextractor/MediaBuffer.cpp
index 39f8d6e..d197b3f 100644
--- a/media/libmediaextractor/MediaBuffer.cpp
+++ b/media/libmediaextractor/MediaBuffer.cpp
@@ -39,7 +39,7 @@
mRangeOffset(0),
mRangeLength(size),
mOwnsData(false),
- mMetaData(new MetaData),
+ mMetaData(new MetaDataBase),
mOriginal(NULL) {
}
@@ -51,7 +51,7 @@
mRangeOffset(0),
mRangeLength(size),
mOwnsData(true),
- mMetaData(new MetaData),
+ mMetaData(new MetaDataBase),
mOriginal(NULL) {
if (size < kSharedMemThreshold
|| std::atomic_load_explicit(&mUseSharedMemory, std::memory_order_seq_cst) == 0) {
@@ -84,7 +84,7 @@
mRangeLength(mSize),
mBuffer(buffer),
mOwnsData(false),
- mMetaData(new MetaData),
+ mMetaData(new MetaDataBase),
mOriginal(NULL) {
}
@@ -96,7 +96,7 @@
return;
}
- int prevCount = __sync_fetch_and_sub(&mRefCount, 1);
+ int prevCount = mRefCount.fetch_sub(1);
if (prevCount == 1) {
if (mObserver == NULL) {
delete this;
@@ -110,13 +110,13 @@
void MediaBuffer::claim() {
CHECK(mObserver != NULL);
- CHECK_EQ(mRefCount, 1);
+ CHECK_EQ(mRefCount.load(std::memory_order_relaxed), 1);
- mRefCount = 0;
+ mRefCount.store(0, std::memory_order_relaxed);
}
void MediaBuffer::add_ref() {
- (void) __sync_fetch_and_add(&mRefCount, 1);
+ (void) mRefCount.fetch_add(1);
}
void *MediaBuffer::data() const {
diff --git a/media/libmediaextractor/include/media/stagefright/MediaBuffer.h b/media/libmediaextractor/include/media/stagefright/MediaBuffer.h
index f944d51..5a25965 100644
--- a/media/libmediaextractor/include/media/stagefright/MediaBuffer.h
+++ b/media/libmediaextractor/include/media/stagefright/MediaBuffer.h
@@ -86,12 +86,14 @@
virtual MediaBufferBase *clone();
// sum of localRefcount() and remoteRefcount()
+ // Result should be treated as approximate unless the result precludes concurrent accesses.
virtual int refcount() const {
return localRefcount() + remoteRefcount();
}
+ // Result should be treated as approximate unless the result precludes concurrent accesses.
virtual int localRefcount() const {
- return mRefCount;
+ return mRefCount.load(std::memory_order_relaxed);
}
virtual int remoteRefcount() const {
@@ -146,7 +148,7 @@
void claim();
MediaBufferObserver *mObserver;
- int mRefCount;
+ std::atomic<int> mRefCount;
void *mData;
size_t mSize, mRangeOffset, mRangeLength;
diff --git a/media/libmediaextractor/include/media/stagefright/MetaDataBase.h b/media/libmediaextractor/include/media/stagefright/MetaDataBase.h
index dfe34e8..9d35568 100644
--- a/media/libmediaextractor/include/media/stagefright/MetaDataBase.h
+++ b/media/libmediaextractor/include/media/stagefright/MetaDataBase.h
@@ -53,6 +53,7 @@
kKeyFrameRate = 'frmR', // int32_t (video frame rate fps)
kKeyBitRate = 'brte', // int32_t (bps)
kKeyMaxBitRate = 'mxBr', // int32_t (bps)
+ kKeyBitsPerSample = 'bits', // int32_t (bits per sample)
kKeyStreamHeader = 'stHd', // raw data
kKeyESDS = 'esds', // raw data
kKeyAACProfile = 'aacp', // int32_t
@@ -225,6 +226,8 @@
kKeyExifOffset = 'exof', // int64_t, Exif data offset
kKeyExifSize = 'exsz', // int64_t, Exif data size
kKeyIsExif = 'exif', // bool (int32_t) buffer contains exif data block
+
+ kKeyPcmBigEndian = 'pcmb', // bool (int32_t)
};
enum {
diff --git a/media/libstagefright/http/HTTPHelper.cpp b/media/libstagefright/http/HTTPHelper.cpp
index 77845e2..b895f03 100644
--- a/media/libstagefright/http/HTTPHelper.cpp
+++ b/media/libstagefright/http/HTTPHelper.cpp
@@ -42,11 +42,11 @@
env, env->FindClass("android/media/MediaHTTPService"));
CHECK(clazz.get() != NULL);
- jmethodID constructID = env->GetMethodID(clazz.get(), "<init>", "()V");
+ jmethodID constructID = env->GetMethodID(clazz.get(), "<init>", "(Ljava/util/List;)V");
CHECK(constructID != NULL);
ScopedLocalRef<jobject> httpServiceObj(
- env, env->NewObject(clazz.get(), constructID));
+ env, env->NewObject(clazz.get(), constructID, NULL));
sp<IMediaHTTPService> httpService;
if (httpServiceObj.get() != NULL) {
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 2047dfd..20c9d37 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -50,6 +50,8 @@
#define ALOGVV(a...) do { } while(0)
#endif
+#define DEFAULT_OUTPUT_SAMPLE_RATE 48000
+
namespace android {
// ----------------------------------------------------------------------------
@@ -263,7 +265,9 @@
}
break;
case STOPPING:
- if (stop_l() == NO_ERROR) {
+ // volume control for offload and direct threads must take effect immediately.
+ if (stop_l() == NO_ERROR
+ && !(isVolumeControl() && isOffloadedOrDirect())) {
mDisableWaitCnt = mMaxDisableWaitCnt;
} else {
mDisableWaitCnt = 1; // will cause immediate transition to IDLE
@@ -547,7 +551,14 @@
mConfig.inputCfg.format = EFFECT_BUFFER_FORMAT;
mConfig.outputCfg.format = EFFECT_BUFFER_FORMAT;
- mConfig.inputCfg.samplingRate = thread->sampleRate();
+
+ // Don't use sample rate for thread if effect isn't offloadable.
+ if ((thread->type() == ThreadBase::OFFLOAD) && !isOffloaded()) {
+ mConfig.inputCfg.samplingRate = DEFAULT_OUTPUT_SAMPLE_RATE;
+ ALOGV("Overriding effect input as 48kHz");
+ } else {
+ mConfig.inputCfg.samplingRate = thread->sampleRate();
+ }
mConfig.outputCfg.samplingRate = mConfig.inputCfg.samplingRate;
mConfig.inputCfg.bufferProvider.cookie = NULL;
mConfig.inputCfg.bufferProvider.getBuffer = NULL;
@@ -778,6 +789,16 @@
}
status_t cmdStatus = NO_ERROR;
uint32_t size = sizeof(status_t);
+
+ if (isVolumeControl() && isOffloadedOrDirect()) {
+ sp<EffectChain>chain = mChain.promote();
+ // We have the EffectChain and EffectModule lock, permit a reentrant call to setVolume:
+ // resetVolume_l --> setVolume_l --> EffectModule::setVolume
+ mSetVolumeReentrantTid = gettid();
+ chain->resetVolume_l();
+ mSetVolumeReentrantTid = INVALID_PID;
+ }
+
status_t status = mEffectInterface->command(EFFECT_CMD_DISABLE,
0,
NULL,
@@ -993,6 +1014,16 @@
}
}
+bool AudioFlinger::EffectModule::isOffloadedOrDirect() const
+{
+ return (mThreadType == ThreadBase::OFFLOAD || mThreadType == ThreadBase::DIRECT);
+}
+
+bool AudioFlinger::EffectModule::isVolumeControlEnabled() const
+{
+ return (isVolumeControl() && (isOffloadedOrDirect() ? isEnabled() : isProcessEnabled()));
+}
+
void AudioFlinger::EffectModule::setInBuffer(const sp<EffectBufferHalInterface>& buffer) {
ALOGVV("setInBuffer %p",(&buffer));
@@ -1091,7 +1122,7 @@
status_t AudioFlinger::EffectModule::setVolume(uint32_t *left, uint32_t *right, bool controller)
{
- Mutex::Autolock _l(mLock);
+ AutoLockReentrant _l(mLock, mSetVolumeReentrantTid);
if (mStatus != NO_ERROR) {
return mStatus;
}
@@ -1122,6 +1153,18 @@
return status;
}
+void AudioFlinger::EffectChain::setVolumeForOutput_l(uint32_t left, uint32_t right)
+{
+ sp<ThreadBase> thread = mThread.promote();
+ if (thread != 0 &&
+ (thread->type() == ThreadBase::OFFLOAD || thread->type() == ThreadBase::DIRECT)) {
+ PlaybackThread *t = (PlaybackThread *)thread.get();
+ float vol_l = (float)left / (1 << 24);
+ float vol_r = (float)right / (1 << 24);
+ t->setVolumeForOutput_l(vol_l, vol_r);
+ }
+}
+
status_t AudioFlinger::EffectModule::setDevice(audio_devices_t device)
{
if (device == AUDIO_DEVICE_NONE) {
@@ -2200,8 +2243,7 @@
// first update volume controller
for (size_t i = size; i > 0; i--) {
- if (mEffects[i - 1]->isProcessEnabled() &&
- (mEffects[i - 1]->desc().flags & EFFECT_FLAG_VOLUME_MASK) == EFFECT_FLAG_VOLUME_CTRL) {
+ if (mEffects[i - 1]->isVolumeControlEnabled()) {
ctrlIdx = i - 1;
hasControl = true;
break;
@@ -2247,6 +2289,8 @@
*left = newLeft;
*right = newRight;
+ setVolumeForOutput_l(*left, *right);
+
return hasControl;
}
diff --git a/services/audioflinger/Effects.h b/services/audioflinger/Effects.h
index 2327bb9..e04ee8e 100644
--- a/services/audioflinger/Effects.h
+++ b/services/audioflinger/Effects.h
@@ -85,6 +85,8 @@
status_t setEnabled_l(bool enabled);
bool isEnabled() const;
bool isProcessEnabled() const;
+ bool isOffloadedOrDirect() const;
+ bool isVolumeControlEnabled() const;
void setInBuffer(const sp<EffectBufferHalInterface>& buffer);
int16_t *inBuffer() const {
@@ -95,7 +97,8 @@
return mOutBuffer != 0 ? reinterpret_cast<int16_t*>(mOutBuffer->ptr()) : NULL;
}
void setChain(const wp<EffectChain>& chain) { mChain = chain; }
- void setThread(const wp<ThreadBase>& thread) { mThread = thread; }
+ void setThread(const wp<ThreadBase>& thread)
+ { mThread = thread; mThreadType = thread.promote()->type(); }
const wp<ThreadBase>& thread() { return mThread; }
status_t addHandle(EffectHandle *handle);
@@ -128,6 +131,9 @@
{ return (mDescriptor.flags & EFFECT_FLAG_HW_ACC_MASK) == 0; }
bool isProcessImplemented() const
{ return (mDescriptor.flags & EFFECT_FLAG_NO_PROCESS) == 0; }
+ bool isVolumeControl() const
+ { return (mDescriptor.flags & EFFECT_FLAG_VOLUME_MASK)
+ == EFFECT_FLAG_VOLUME_CTRL; }
status_t setOffloaded(bool offloaded, audio_io_handle_t io);
bool isOffloaded() const;
void addEffectToHal_l();
@@ -150,6 +156,7 @@
mutable Mutex mLock; // mutex for process, commands and handles list protection
wp<ThreadBase> mThread; // parent thread
+ ThreadBase::type_t mThreadType; // parent thread type
wp<EffectChain> mChain; // parent effect chain
const int mId; // this instance unique ID
const audio_session_t mSessionId; // audio session ID
@@ -176,6 +183,24 @@
uint32_t mInChannelCountRequested;
uint32_t mOutChannelCountRequested;
#endif
+
+ class AutoLockReentrant {
+ public:
+ AutoLockReentrant(Mutex& mutex, pid_t allowedTid)
+ : mMutex(gettid() == allowedTid ? nullptr : &mutex)
+ {
+ if (mMutex != nullptr) mMutex->lock();
+ }
+ ~AutoLockReentrant() {
+ if (mMutex != nullptr) mMutex->unlock();
+ }
+ private:
+ Mutex * const mMutex;
+ };
+
+ static constexpr pid_t INVALID_PID = (pid_t)-1;
+ // this tid is allowed to call setVolume() without acquiring the mutex.
+ pid_t mSetVolumeReentrantTid = INVALID_PID;
};
// The EffectHandle class implements the IEffect interface. It provides resources
@@ -403,6 +428,8 @@
void setThread(const sp<ThreadBase>& thread);
+ void setVolumeForOutput_l(uint32_t left, uint32_t right);
+
wp<ThreadBase> mThread; // parent mixer thread
mutable Mutex mLock; // mutex protecting effect list
Vector< sp<EffectModule> > mEffects; // list of effect modules
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index dcad866..4ca50d7 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -2286,6 +2286,11 @@
return mStreamTypes[stream].volume;
}
+void AudioFlinger::PlaybackThread::setVolumeForOutput_l(float left, float right) const
+{
+ mOutput->stream->setVolume(left, right);
+}
+
// addTrack_l() must be called with ThreadBase::mLock held
status_t AudioFlinger::PlaybackThread::addTrack_l(const sp<Track>& track)
{
@@ -5142,20 +5147,20 @@
mLeftVolFloat = left;
mRightVolFloat = right;
- // Convert volumes from float to 8.24
- uint32_t vl = (uint32_t)(left * (1 << 24));
- uint32_t vr = (uint32_t)(right * (1 << 24));
-
// Delegate volume control to effect in track effect chain if needed
// only one effect chain can be present on DirectOutputThread, so if
// there is one, the track is connected to it
if (!mEffectChains.isEmpty()) {
- mEffectChains[0]->setVolume_l(&vl, &vr);
- left = (float)vl / (1 << 24);
- right = (float)vr / (1 << 24);
+ // if effect chain exists, volume is handled by it.
+ // Convert volumes from float to 8.24
+ uint32_t vl = (uint32_t)(left * (1 << 24));
+ uint32_t vr = (uint32_t)(right * (1 << 24));
+ // Direct/Offload effect chains set output volume in setVolume_l().
+ (void)mEffectChains[0]->setVolume_l(&vl, &vr);
+ } else {
+ // otherwise we directly set the volume.
+ setVolumeForOutput_l(left, right);
}
- status_t result = mOutput->stream->setVolume(left, right);
- ALOGE_IF(result != OK, "Error when setting output stream volume: %d", result);
}
}
}
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 28d4482..ea29455 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -712,6 +712,8 @@
virtual void setStreamMute(audio_stream_type_t stream, bool muted);
virtual float streamVolume(audio_stream_type_t stream) const;
+ void setVolumeForOutput_l(float left, float right) const;
+
sp<Track> createTrack_l(
const sp<AudioFlinger::Client>& client,
audio_stream_type_t streamType,