Merge "Remove obsolete include path from makefiles"
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.cpp b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
index 672b832..fa41c06 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.cpp
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
@@ -48,7 +48,6 @@
{
ALOGV("MetadataRetrieverClient constructor pid(%d)", pid);
mPid = pid;
- mThumbnail = NULL;
mAlbumArt = NULL;
mRetriever = NULL;
}
@@ -77,7 +76,6 @@
ALOGV("disconnect from pid %d", mPid);
Mutex::Autolock lock(mLock);
mRetriever.clear();
- mThumbnail.clear();
mAlbumArt.clear();
IPCThreadState::self()->flushCommands();
}
@@ -201,7 +199,6 @@
(long long)timeUs, option, colorFormat, metaOnly);
Mutex::Autolock lock(mLock);
Mutex::Autolock glock(sLock);
- mThumbnail.clear();
if (mRetriever == NULL) {
ALOGE("retriever is not initialized");
return NULL;
@@ -220,7 +217,6 @@
index, colorFormat, metaOnly, thumbnail);
Mutex::Autolock lock(mLock);
Mutex::Autolock glock(sLock);
- mThumbnail.clear();
if (mRetriever == NULL) {
ALOGE("retriever is not initialized");
return NULL;
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.h b/media/libmediaplayerservice/MetadataRetrieverClient.h
index e774c8f..63ba44a 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.h
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.h
@@ -73,9 +73,8 @@
sp<MediaMetadataRetrieverBase> mRetriever;
pid_t mPid;
- // Keep the shared memory copy of album art and capture frame (for thumbnail)
+ // Keep the shared memory copy of album art
sp<IMemory> mAlbumArt;
- sp<IMemory> mThumbnail;
};
}; // namespace android
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index 3a28bbd..57a0198 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -358,8 +358,12 @@
// AudioSink has rendered some frames.
int64_t nowUs = ALooper::GetNowUs();
- int64_t nowMediaUs = mAudioSink->getPlayedOutDurationUs(nowUs)
- + mAudioFirstAnchorTimeMediaUs;
+ int64_t playedOutDurationUs = mAudioSink->getPlayedOutDurationUs(nowUs);
+ if (playedOutDurationUs == 0) {
+ *mediaUs = mAudioFirstAnchorTimeMediaUs;
+ return OK;
+ }
+ int64_t nowMediaUs = playedOutDurationUs + mAudioFirstAnchorTimeMediaUs;
mMediaClock->updateAnchor(nowMediaUs, nowUs, -1);
}
diff --git a/media/libnbaio/PipeReader.cpp b/media/libnbaio/PipeReader.cpp
index 2486b76..35a43d8 100644
--- a/media/libnbaio/PipeReader.cpp
+++ b/media/libnbaio/PipeReader.cpp
@@ -26,7 +26,7 @@
PipeReader::PipeReader(Pipe& pipe) :
NBAIO_Source(pipe.mFormat),
- mPipe(pipe), mFifoReader(mPipe.mFifo, false /*throttlesWriter*/, true /*flush*/),
+ mPipe(pipe), mFifoReader(mPipe.mFifo, false /*throttlesWriter*/, false /*flush*/),
mFramesOverrun(0),
mOverruns(0)
{
diff --git a/media/libstagefright/FrameDecoder.cpp b/media/libstagefright/FrameDecoder.cpp
index 09a8be5..e2605ca 100644
--- a/media/libstagefright/FrameDecoder.cpp
+++ b/media/libstagefright/FrameDecoder.cpp
@@ -42,7 +42,6 @@
static const int64_t kBufferTimeOutUs = 10000ll; // 10 msec
static const size_t kRetryCount = 50; // must be >0
-//static
sp<IMemory> allocVideoFrame(const sp<MetaData>& trackMeta,
int32_t width, int32_t height, int32_t dstBpp, bool metaOnly = false) {
int32_t rotationAngle;
@@ -94,7 +93,6 @@
return frameMem;
}
-//static
bool findThumbnailInfo(
const sp<MetaData> &trackMeta, int32_t *width, int32_t *height,
uint32_t *type = NULL, const void **data = NULL, size_t *size = NULL) {
@@ -107,30 +105,15 @@
type ?: &dummyType, data ?: &dummyData, size ?: &dummySize);
}
-//static
-sp<IMemory> FrameDecoder::getMetadataOnly(
- const sp<MetaData> &trackMeta, int colorFormat, bool thumbnail) {
- OMX_COLOR_FORMATTYPE dstFormat;
- int32_t dstBpp;
- if (!getDstColorFormat(
- (android_pixel_format_t)colorFormat, &dstFormat, &dstBpp)) {
- return NULL;
- }
-
- int32_t width, height;
- if (thumbnail) {
- if (!findThumbnailInfo(trackMeta, &width, &height)) {
- return NULL;
- }
- } else {
- CHECK(trackMeta->findInt32(kKeyWidth, &width));
- CHECK(trackMeta->findInt32(kKeyHeight, &height));
- }
- return allocVideoFrame(trackMeta, width, height, dstBpp, true /*metaOnly*/);
+bool findGridInfo(const sp<MetaData> &trackMeta,
+ int32_t *tileWidth, int32_t *tileHeight, int32_t *gridRows, int32_t *gridCols) {
+ return trackMeta->findInt32(kKeyTileWidth, tileWidth) && (*tileWidth > 0)
+ && trackMeta->findInt32(kKeyTileHeight, tileHeight) && (*tileHeight > 0)
+ && trackMeta->findInt32(kKeyGridRows, gridRows) && (*gridRows > 0)
+ && trackMeta->findInt32(kKeyGridCols, gridCols) && (*gridCols > 0);
}
-//static
-bool FrameDecoder::getDstColorFormat(
+bool getDstColorFormat(
android_pixel_format_t colorFormat,
OMX_COLOR_FORMATTYPE *dstFormat,
int32_t *dstBpp) {
@@ -162,46 +145,57 @@
return false;
}
-sp<IMemory> FrameDecoder::extractFrame(
- int64_t frameTimeUs, int option, int colorFormat) {
+//static
+sp<IMemory> FrameDecoder::getMetadataOnly(
+ const sp<MetaData> &trackMeta, int colorFormat, bool thumbnail) {
+ OMX_COLOR_FORMATTYPE dstFormat;
+ int32_t dstBpp;
if (!getDstColorFormat(
- (android_pixel_format_t)colorFormat, &mDstFormat, &mDstBpp)) {
+ (android_pixel_format_t)colorFormat, &dstFormat, &dstBpp)) {
return NULL;
}
- status_t err = extractInternal(frameTimeUs, 1, option);
- if (err != OK) {
- return NULL;
+ int32_t width, height;
+ if (thumbnail) {
+ if (!findThumbnailInfo(trackMeta, &width, &height)) {
+ return NULL;
+ }
+ } else {
+ CHECK(trackMeta->findInt32(kKeyWidth, &width));
+ CHECK(trackMeta->findInt32(kKeyHeight, &height));
}
-
- return mFrames.size() > 0 ? mFrames[0] : NULL;
+ return allocVideoFrame(trackMeta, width, height, dstBpp, true /*metaOnly*/);
}
-status_t FrameDecoder::extractFrames(
- int64_t frameTimeUs, size_t numFrames, int option, int colorFormat,
- std::vector<sp<IMemory> >* frames) {
+FrameDecoder::FrameDecoder(
+ const AString &componentName,
+ const sp<MetaData> &trackMeta,
+ const sp<IMediaSource> &source)
+ : mComponentName(componentName),
+ mTrackMeta(trackMeta),
+ mSource(source),
+ mDstFormat(OMX_COLOR_Format16bitRGB565),
+ mDstBpp(2),
+ mHaveMoreInputs(true),
+ mFirstSample(true) {
+}
+
+FrameDecoder::~FrameDecoder() {
+ if (mDecoder != NULL) {
+ mDecoder->release();
+ mSource->stop();
+ }
+}
+
+status_t FrameDecoder::init(
+ int64_t frameTimeUs, size_t numFrames, int option, int colorFormat) {
if (!getDstColorFormat(
(android_pixel_format_t)colorFormat, &mDstFormat, &mDstBpp)) {
return ERROR_UNSUPPORTED;
}
- status_t err = extractInternal(frameTimeUs, numFrames, option);
- if (err != OK) {
- return err;
- }
-
- for (size_t i = 0; i < mFrames.size(); i++) {
- frames->push_back(mFrames[i]);
- }
- return OK;
-}
-
-status_t FrameDecoder::extractInternal(
- int64_t frameTimeUs, size_t numFrames, int option) {
-
- MediaSource::ReadOptions options;
sp<AMessage> videoFormat = onGetFormatAndSeekOptions(
- frameTimeUs, numFrames, option, &options);
+ frameTimeUs, numFrames, option, &mReadOptions);
if (videoFormat == NULL) {
ALOGE("video format or seek mode not supported");
return ERROR_UNSUPPORTED;
@@ -217,7 +211,8 @@
return (decoder.get() == NULL) ? NO_MEMORY : err;
}
- err = decoder->configure(videoFormat, NULL /* surface */, NULL /* crypto */, 0 /* flags */);
+ err = decoder->configure(
+ videoFormat, NULL /* surface */, NULL /* crypto */, 0 /* flags */);
if (err != OK) {
ALOGW("configure returned error %d (%s)", err, asString(err));
decoder->release();
@@ -237,43 +232,46 @@
decoder->release();
return err;
}
+ mDecoder = decoder;
- Vector<sp<MediaCodecBuffer> > inputBuffers;
- err = decoder->getInputBuffers(&inputBuffers);
+ return OK;
+}
+
+sp<IMemory> FrameDecoder::extractFrame() {
+ status_t err = extractInternal();
if (err != OK) {
- ALOGW("failed to get input buffers: %d (%s)", err, asString(err));
- decoder->release();
- mSource->stop();
+ return NULL;
+ }
+
+ return mFrames.size() > 0 ? mFrames[0] : NULL;
+}
+
+status_t FrameDecoder::extractFrames(std::vector<sp<IMemory> >* frames) {
+ status_t err = extractInternal();
+ if (err != OK) {
return err;
}
- Vector<sp<MediaCodecBuffer> > outputBuffers;
- err = decoder->getOutputBuffers(&outputBuffers);
- if (err != OK) {
- ALOGW("failed to get output buffers: %d (%s)", err, asString(err));
- decoder->release();
- mSource->stop();
- return err;
+ for (size_t i = 0; i < mFrames.size(); i++) {
+ frames->push_back(mFrames[i]);
}
+ return OK;
+}
- sp<AMessage> outputFormat = NULL;
- bool haveMoreInputs = true;
- size_t index, offset, size;
- int64_t timeUs;
- size_t retriesLeft = kRetryCount;
+status_t FrameDecoder::extractInternal() {
+ status_t err = OK;
bool done = false;
- bool firstSample = true;
+ size_t retriesLeft = kRetryCount;
do {
- size_t inputIndex = -1;
+ size_t index;
int64_t ptsUs = 0ll;
uint32_t flags = 0;
- sp<MediaCodecBuffer> codecBuffer = NULL;
// Queue as many inputs as we possibly can, then block on dequeuing
// outputs. After getting each output, come back and queue the inputs
// again to keep the decoder busy.
- while (haveMoreInputs) {
- err = decoder->dequeueInputBuffer(&inputIndex, 0);
+ while (mHaveMoreInputs) {
+ err = mDecoder->dequeueInputBuffer(&index, 0);
if (err != OK) {
ALOGV("Timed out waiting for input");
if (retriesLeft) {
@@ -281,16 +279,21 @@
}
break;
}
- codecBuffer = inputBuffers[inputIndex];
+ sp<MediaCodecBuffer> codecBuffer;
+ err = mDecoder->getInputBuffer(index, &codecBuffer);
+ if (err != OK) {
+ ALOGE("failed to get input buffer %zu", index);
+ break;
+ }
MediaBufferBase *mediaBuffer = NULL;
- err = mSource->read(&mediaBuffer, &options);
- options.clearSeekTo();
+ err = mSource->read(&mediaBuffer, &mReadOptions);
+ mReadOptions.clearSeekTo();
if (err != OK) {
ALOGW("Input Error or EOS");
- haveMoreInputs = false;
- if (!firstSample && err == ERROR_END_OF_STREAM) {
+ mHaveMoreInputs = false;
+ if (!mFirstSample && err == ERROR_END_OF_STREAM) {
err = OK;
}
break;
@@ -299,7 +302,7 @@
if (mediaBuffer->range_length() > codecBuffer->capacity()) {
ALOGE("buffer size (%zu) too large for codec input size (%zu)",
mediaBuffer->range_length(), codecBuffer->capacity());
- haveMoreInputs = false;
+ mHaveMoreInputs = false;
err = BAD_VALUE;
} else {
codecBuffer->setRange(0, mediaBuffer->range_length());
@@ -309,45 +312,46 @@
(const uint8_t*)mediaBuffer->data() + mediaBuffer->range_offset(),
mediaBuffer->range_length());
- onInputReceived(codecBuffer, mediaBuffer->meta_data(), firstSample, &flags);
- firstSample = false;
+ onInputReceived(codecBuffer, mediaBuffer->meta_data(), mFirstSample, &flags);
+ mFirstSample = false;
}
mediaBuffer->release();
- if (haveMoreInputs && inputIndex < inputBuffers.size()) {
+ if (mHaveMoreInputs) {
ALOGV("QueueInput: size=%zu ts=%" PRId64 " us flags=%x",
codecBuffer->size(), ptsUs, flags);
- err = decoder->queueInputBuffer(
- inputIndex,
+ err = mDecoder->queueInputBuffer(
+ index,
codecBuffer->offset(),
codecBuffer->size(),
ptsUs,
flags);
if (flags & MediaCodec::BUFFER_FLAG_EOS) {
- haveMoreInputs = false;
+ mHaveMoreInputs = false;
}
}
}
while (err == OK) {
+ size_t offset, size;
// wait for a decoded buffer
- err = decoder->dequeueOutputBuffer(
+ err = mDecoder->dequeueOutputBuffer(
&index,
&offset,
&size,
- &timeUs,
+ &ptsUs,
&flags,
kBufferTimeOutUs);
if (err == INFO_FORMAT_CHANGED) {
ALOGV("Received format change");
- err = decoder->getOutputFormat(&outputFormat);
+ err = mDecoder->getOutputFormat(&mOutputFormat);
} else if (err == INFO_OUTPUT_BUFFERS_CHANGED) {
ALOGV("Output buffers changed");
- err = decoder->getOutputBuffers(&outputBuffers);
+ err = OK;
} else {
if (err == -EAGAIN /* INFO_TRY_AGAIN_LATER */ && --retriesLeft > 0) {
ALOGV("Timed-out waiting for output.. retries left = %zu", retriesLeft);
@@ -355,12 +359,15 @@
} else if (err == OK) {
// If we're seeking with CLOSEST option and obtained a valid targetTimeUs
// from the extractor, decode to the specified frame. Otherwise we're done.
- ALOGV("Received an output buffer, timeUs=%lld", (long long)timeUs);
- sp<MediaCodecBuffer> videoFrameBuffer = outputBuffers.itemAt(index);
-
- err = onOutputReceived(videoFrameBuffer, outputFormat, timeUs, &done);
-
- decoder->releaseOutputBuffer(index);
+ ALOGV("Received an output buffer, timeUs=%lld", (long long)ptsUs);
+ sp<MediaCodecBuffer> videoFrameBuffer;
+ err = mDecoder->getOutputBuffer(index, &videoFrameBuffer);
+ if (err != OK) {
+ ALOGE("failed to get output buffer %zu", index);
+ break;
+ }
+ err = onOutputReceived(videoFrameBuffer, mOutputFormat, ptsUs, &done);
+ mDecoder->releaseOutputBuffer(index);
} else {
ALOGW("Received error %d (%s) instead of output", err, asString(err));
done = true;
@@ -370,9 +377,6 @@
}
} while (err == OK && !done);
- mSource->stop();
- decoder->release();
-
if (err != OK) {
ALOGE("failed to get video frame (err %d)", err);
}
@@ -380,6 +384,20 @@
return err;
}
+//////////////////////////////////////////////////////////////////////
+
+VideoFrameDecoder::VideoFrameDecoder(
+ const AString &componentName,
+ const sp<MetaData> &trackMeta,
+ const sp<IMediaSource> &source)
+ : FrameDecoder(componentName, trackMeta, source),
+ mIsAvcOrHevc(false),
+ mSeekMode(MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC),
+ mTargetTimeUs(-1ll),
+ mNumFrames(0),
+ mNumFramesDecoded(0) {
+}
+
sp<AMessage> VideoFrameDecoder::onGetFormatAndSeekOptions(
int64_t frameTimeUs, size_t numFrames, int seekMode, MediaSource::ReadOptions *options) {
mSeekMode = static_cast<MediaSource::ReadOptions::SeekMode>(seekMode);
@@ -511,33 +529,47 @@
return ERROR_UNSUPPORTED;
}
+////////////////////////////////////////////////////////////////////////
+
+ImageDecoder::ImageDecoder(
+ const AString &componentName,
+ const sp<MetaData> &trackMeta,
+ const sp<IMediaSource> &source)
+ : FrameDecoder(componentName, trackMeta, source),
+ mFrame(NULL),
+ mWidth(0),
+ mHeight(0),
+ mGridRows(1),
+ mGridCols(1),
+ mTilesDecoded(0) {
+}
+
sp<AMessage> ImageDecoder::onGetFormatAndSeekOptions(
int64_t frameTimeUs, size_t /*numFrames*/,
int /*seekMode*/, MediaSource::ReadOptions *options) {
sp<MetaData> overrideMeta;
- mThumbnail = false;
if (frameTimeUs < 0) {
uint32_t type;
const void *data;
size_t size;
- int32_t thumbWidth, thumbHeight;
// if we have a stand-alone thumbnail, set up the override meta,
// and set seekTo time to -1.
- if (!findThumbnailInfo(trackMeta(),
- &thumbWidth, &thumbHeight, &type, &data, &size)) {
+ if (!findThumbnailInfo(trackMeta(), &mWidth, &mHeight, &type, &data, &size)) {
ALOGE("Thumbnail not available");
return NULL;
}
overrideMeta = new MetaData(*(trackMeta()));
overrideMeta->remove(kKeyDisplayWidth);
overrideMeta->remove(kKeyDisplayHeight);
- overrideMeta->setInt32(kKeyWidth, thumbWidth);
- overrideMeta->setInt32(kKeyHeight, thumbHeight);
+ overrideMeta->setInt32(kKeyWidth, mWidth);
+ overrideMeta->setInt32(kKeyHeight, mHeight);
overrideMeta->setData(kKeyHVCC, type, data, size);
options->setSeekTo(-1);
- mThumbnail = true;
} else {
+ CHECK(trackMeta()->findInt32(kKeyWidth, &mWidth));
+ CHECK(trackMeta()->findInt32(kKeyHeight, &mHeight));
+
options->setSeekTo(frameTimeUs);
}
@@ -545,17 +577,10 @@
if (overrideMeta == NULL) {
// check if we're dealing with a tiled heif
int32_t tileWidth, tileHeight, gridRows, gridCols;
- if (trackMeta()->findInt32(kKeyTileWidth, &tileWidth) && tileWidth > 0
- && trackMeta()->findInt32(kKeyTileHeight, &tileHeight) && tileHeight > 0
- && trackMeta()->findInt32(kKeyGridRows, &gridRows) && gridRows > 0
- && trackMeta()->findInt32(kKeyGridCols, &gridCols) && gridCols > 0) {
- int32_t width, height;
- CHECK(trackMeta()->findInt32(kKeyWidth, &width));
- CHECK(trackMeta()->findInt32(kKeyHeight, &height));
-
- if (width <= tileWidth * gridCols && height <= tileHeight * gridRows) {
+ if (findGridInfo(trackMeta(), &tileWidth, &tileHeight, &gridRows, &gridCols)) {
+ if (mWidth <= tileWidth * gridCols && mHeight <= tileHeight * gridRows) {
ALOGV("grid: %dx%d, tile size: %dx%d, picture size: %dx%d",
- gridCols, gridRows, tileWidth, tileHeight, width, height);
+ gridCols, gridRows, tileWidth, tileHeight, mWidth, mHeight);
overrideMeta = new MetaData(*(trackMeta()));
overrideMeta->setInt32(kKeyWidth, tileWidth);
@@ -563,8 +588,8 @@
mGridCols = gridCols;
mGridRows = gridRows;
} else {
- ALOGE("bad grid: %dx%d, tile size: %dx%d, picture size: %dx%d",
- gridCols, gridRows, tileWidth, tileHeight, width, height);
+ ALOGE("ignore bad grid: %dx%d, tile size: %dx%d, picture size: %dx%d",
+ gridCols, gridRows, tileWidth, tileHeight, mWidth, mHeight);
}
}
if (overrideMeta == NULL) {
@@ -600,17 +625,8 @@
CHECK(outputFormat->findInt32("width", &width));
CHECK(outputFormat->findInt32("height", &height));
- int32_t imageWidth, imageHeight;
- if (mThumbnail) {
- CHECK(trackMeta()->findInt32(kKeyThumbnailWidth, &imageWidth));
- CHECK(trackMeta()->findInt32(kKeyThumbnailHeight, &imageHeight));
- } else {
- CHECK(trackMeta()->findInt32(kKeyWidth, &imageWidth));
- CHECK(trackMeta()->findInt32(kKeyHeight, &imageHeight));
- }
-
if (mFrame == NULL) {
- sp<IMemory> frameMem = allocVideoFrame(trackMeta(), imageWidth, imageHeight, dstBpp());
+ sp<IMemory> frameMem = allocVideoFrame(trackMeta(), mWidth, mHeight, dstBpp());
mFrame = static_cast<VideoFrame*>(frameMem->pointer());
addFrame(frameMem);
@@ -638,12 +654,12 @@
// apply crop on bottom-right
// TODO: need to move this into the color converter itself.
- if (dstRight >= imageWidth) {
- crop_right = imageWidth - dstLeft - 1;
+ if (dstRight >= mWidth) {
+ crop_right = mWidth - dstLeft - 1;
dstRight = dstLeft + crop_right;
}
- if (dstBottom >= imageHeight) {
- crop_bottom = imageHeight - dstTop - 1;
+ if (dstBottom >= mHeight) {
+ crop_bottom = mHeight - dstTop - 1;
dstBottom = dstTop + crop_bottom;
}
diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp
index cd091a6..9a33168 100644
--- a/media/libstagefright/MediaCodecList.cpp
+++ b/media/libstagefright/MediaCodecList.cpp
@@ -287,7 +287,9 @@
//static
bool MediaCodecList::isSoftwareCodec(const AString &componentName) {
return componentName.startsWithIgnoreCase("OMX.google.")
- || !componentName.startsWithIgnoreCase("OMX.");
+ || componentName.startsWithIgnoreCase("c2.android.")
+ || (!componentName.startsWithIgnoreCase("OMX.")
+ && !componentName.startsWithIgnoreCase("c2."));
}
static int compareSoftwareCodecsFirst(const AString *name1, const AString *name2) {
@@ -298,7 +300,14 @@
return isSoftwareCodec2 - isSoftwareCodec1;
}
- // sort order 2: OMX codecs are first (lower)
+ // sort order 2: Codec 2.0 codecs are first (lower)
+ bool isC2_1 = name1->startsWithIgnoreCase("c2.");
+ bool isC2_2 = name2->startsWithIgnoreCase("c2.");
+ if (isC2_1 != isC2_2) {
+ return isC2_2 - isC2_1;
+ }
+
+ // sort order 3: OMX codecs are first (lower)
bool isOMX1 = name1->startsWithIgnoreCase("OMX.");
bool isOMX2 = name2->startsWithIgnoreCase("OMX.");
return isOMX2 - isOMX1;
diff --git a/media/libstagefright/MediaCodecListOverrides.cpp b/media/libstagefright/MediaCodecListOverrides.cpp
index 6920e51..cac53f4 100644
--- a/media/libstagefright/MediaCodecListOverrides.cpp
+++ b/media/libstagefright/MediaCodecListOverrides.cpp
@@ -222,7 +222,7 @@
AString supportMultipleSecureCodecs = "true";
for (const auto& info : infos) {
AString name = info->getCodecName();
- if (name.startsWith("OMX.google.") ||
+ if (name.startsWith("OMX.google.") || name.startsWith("c2.android.") ||
// TODO: reenable below codecs once fixed
name == "OMX.Intel.VideoDecoder.VP9.hybrid") {
continue;
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index 5417fef..e6c318c 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -193,11 +193,13 @@
for (size_t i = 0; i < matchingCodecs.size(); ++i) {
const AString &componentName = matchingCodecs[i];
ImageDecoder decoder(componentName, trackMeta, source);
- sp<IMemory> frame = decoder.extractFrame(
- thumbnail ? -1 : 0 /*frameTimeUs*/, 0 /*seekMode*/, colorFormat);
+ int64_t frameTimeUs = thumbnail ? -1 : 0;
+ if (decoder.init(frameTimeUs, 1 /*numFrames*/, 0 /*option*/, colorFormat) == OK) {
+ sp<IMemory> frame = decoder.extractFrame();
- if (frame != NULL) {
- return frame;
+ if (frame != NULL) {
+ return frame;
+ }
}
ALOGV("%s failed to extract thumbnail, trying next decoder.", componentName.c_str());
}
@@ -307,16 +309,17 @@
for (size_t i = 0; i < matchingCodecs.size(); ++i) {
const AString &componentName = matchingCodecs[i];
VideoFrameDecoder decoder(componentName, trackMeta, source);
- if (outFrame != NULL) {
- *outFrame = decoder.extractFrame(timeUs, option, colorFormat);
- if (*outFrame != NULL) {
- return OK;
- }
- } else if (outFrames != NULL) {
- status_t err = decoder.extractFrames(
- timeUs, numFrames, option, colorFormat, outFrames);
- if (err == OK) {
- return OK;
+ if (decoder.init(timeUs, numFrames, option, colorFormat) == OK) {
+ if (outFrame != NULL) {
+ *outFrame = decoder.extractFrame();
+ if (*outFrame != NULL) {
+ return OK;
+ }
+ } else if (outFrames != NULL) {
+ status_t err = decoder.extractFrames(outFrames);
+ if (err == OK) {
+ return OK;
+ }
}
}
ALOGV("%s failed to extract frame, trying next decoder.", componentName.c_str());
diff --git a/media/libstagefright/data/media_codecs_google_c2_audio.xml b/media/libstagefright/data/media_codecs_google_c2_audio.xml
index b86f4ad..0b554a2 100644
--- a/media/libstagefright/data/media_codecs_google_c2_audio.xml
+++ b/media/libstagefright/data/media_codecs_google_c2_audio.xml
@@ -16,77 +16,77 @@
<Included>
<Decoders>
- <MediaCodec name="c2.google.mp3.decoder" type="audio/mpeg">
+ <MediaCodec name="c2.android.mp3.decoder" type="audio/mpeg">
<Limit name="channel-count" max="2" />
<Limit name="sample-rate" ranges="8000,11025,12000,16000,22050,24000,32000,44100,48000" />
<Limit name="bitrate" range="8000-320000" />
</MediaCodec>
- <MediaCodec name="c2.google.amrnb.decoder" type="audio/3gpp">
+ <MediaCodec name="c2.android.amrnb.decoder" type="audio/3gpp">
<Limit name="channel-count" max="1" />
<Limit name="sample-rate" ranges="8000" />
<Limit name="bitrate" range="4750-12200" />
</MediaCodec>
- <MediaCodec name="c2.google.amrwb.decoder" type="audio/amr-wb">
+ <MediaCodec name="c2.android.amrwb.decoder" type="audio/amr-wb">
<Limit name="channel-count" max="1" />
<Limit name="sample-rate" ranges="16000" />
<Limit name="bitrate" range="6600-23850" />
</MediaCodec>
- <MediaCodec name="c2.google.aac.decoder" type="audio/mp4a-latm">
+ <MediaCodec name="c2.android.aac.decoder" type="audio/mp4a-latm">
<Limit name="channel-count" max="8" />
<Limit name="sample-rate" ranges="7350,8000,11025,12000,16000,22050,24000,32000,44100,48000" />
<Limit name="bitrate" range="8000-960000" />
</MediaCodec>
- <MediaCodec name="c2.google.g711.alaw.decoder" type="audio/g711-alaw">
+ <MediaCodec name="c2.android.g711.alaw.decoder" type="audio/g711-alaw">
<Limit name="channel-count" max="1" />
<Limit name="sample-rate" ranges="8000-48000" />
<Limit name="bitrate" range="64000" />
</MediaCodec>
- <MediaCodec name="c2.google.g711.mlaw.decoder" type="audio/g711-mlaw">
+ <MediaCodec name="c2.android.g711.mlaw.decoder" type="audio/g711-mlaw">
<Limit name="channel-count" max="1" />
<Limit name="sample-rate" ranges="8000-48000" />
<Limit name="bitrate" range="64000" />
</MediaCodec>
- <MediaCodec name="c2.google.vorbis.decoder" type="audio/vorbis">
+ <MediaCodec name="c2.android.vorbis.decoder" type="audio/vorbis">
<Limit name="channel-count" max="8" />
<Limit name="sample-rate" ranges="8000-96000" />
<Limit name="bitrate" range="32000-500000" />
</MediaCodec>
- <MediaCodec name="c2.google.opus.decoder" type="audio/opus">
+ <MediaCodec name="c2.android.opus.decoder" type="audio/opus">
<Limit name="channel-count" max="8" />
<Limit name="sample-rate" ranges="48000" />
<Limit name="bitrate" range="6000-510000" />
</MediaCodec>
- <MediaCodec name="c2.google.raw.decoder" type="audio/raw">
+ <MediaCodec name="c2.android.raw.decoder" type="audio/raw">
<Limit name="channel-count" max="8" />
<Limit name="sample-rate" ranges="8000-96000" />
<Limit name="bitrate" range="1-10000000" />
</MediaCodec>
- <MediaCodec name="c2.google.flac.decoder" type="audio/flac">
+ <MediaCodec name="c2.android.flac.decoder" type="audio/flac">
<Limit name="channel-count" max="8" />
<Limit name="sample-rate" ranges="1-655350" />
<Limit name="bitrate" range="1-21000000" />
</MediaCodec>
</Decoders>
<Encoders>
- <MediaCodec name="c2.google.aac.encoder" type="audio/mp4a-latm">
+ <MediaCodec name="c2.android.aac.encoder" type="audio/mp4a-latm">
<Limit name="channel-count" max="6" />
<Limit name="sample-rate" ranges="8000,11025,12000,16000,22050,24000,32000,44100,48000" />
<!-- also may support 64000, 88200 and 96000 Hz -->
<Limit name="bitrate" range="8000-960000" />
</MediaCodec>
- <MediaCodec name="c2.google.amrnb.encoder" type="audio/3gpp">
+ <MediaCodec name="c2.android.amrnb.encoder" type="audio/3gpp">
<Limit name="channel-count" max="1" />
<Limit name="sample-rate" ranges="8000" />
<Limit name="bitrate" range="4750-12200" />
<Feature name="bitrate-modes" value="CBR" />
</MediaCodec>
- <MediaCodec name="c2.google.amrwb.encoder" type="audio/amr-wb">
+ <MediaCodec name="c2.android.amrwb.encoder" type="audio/amr-wb">
<Limit name="channel-count" max="1" />
<Limit name="sample-rate" ranges="16000" />
<Limit name="bitrate" range="6600-23850" />
<Feature name="bitrate-modes" value="CBR" />
</MediaCodec>
- <MediaCodec name="c2.google.flac.encoder" type="audio/flac">
+ <MediaCodec name="c2.android.flac.encoder" type="audio/flac">
<Limit name="channel-count" max="2" />
<Limit name="sample-rate" ranges="1-655350" />
<Limit name="bitrate" range="1-21000000" />
diff --git a/media/libstagefright/data/media_codecs_google_c2_video.xml b/media/libstagefright/data/media_codecs_google_c2_video.xml
index 593463b..adb45b3 100644
--- a/media/libstagefright/data/media_codecs_google_c2_video.xml
+++ b/media/libstagefright/data/media_codecs_google_c2_video.xml
@@ -16,7 +16,7 @@
<Included>
<Decoders>
- <MediaCodec name="c2.google.mpeg4.decoder" type="video/mp4v-es">
+ <MediaCodec name="c2.android.mpeg4.decoder" type="video/mp4v-es">
<!-- profiles and levels: ProfileSimple : Level3 -->
<Limit name="size" min="2x2" max="352x288" />
<Limit name="alignment" value="2x2" />
@@ -25,7 +25,7 @@
<Limit name="bitrate" range="1-384000" />
<Feature name="adaptive-playback" />
</MediaCodec>
- <MediaCodec name="c2.google.h263.decoder" type="video/3gpp">
+ <MediaCodec name="c2.android.h263.decoder" type="video/3gpp">
<!-- profiles and levels: ProfileBaseline : Level30, ProfileBaseline : Level45
ProfileISWV2 : Level30, ProfileISWV2 : Level45 -->
<Limit name="size" min="2x2" max="352x288" />
@@ -33,7 +33,7 @@
<Limit name="bitrate" range="1-384000" />
<Feature name="adaptive-playback" />
</MediaCodec>
- <MediaCodec name="c2.google.avc.decoder" type="video/avc">
+ <MediaCodec name="c2.android.avc.decoder" type="video/avc">
<!-- profiles and levels: ProfileHigh : Level52 -->
<Limit name="size" min="2x2" max="4080x4080" />
<Limit name="alignment" value="2x2" />
@@ -43,7 +43,7 @@
<Limit name="bitrate" range="1-48000000" />
<Feature name="adaptive-playback" />
</MediaCodec>
- <MediaCodec name="c2.google.hevc.decoder" type="video/hevc">
+ <MediaCodec name="c2.android.hevc.decoder" type="video/hevc">
<!-- profiles and levels: ProfileMain : MainTierLevel51 -->
<Limit name="size" min="2x2" max="4096x4096" />
<Limit name="alignment" value="2x2" />
@@ -53,7 +53,7 @@
<Limit name="bitrate" range="1-10000000" />
<Feature name="adaptive-playback" />
</MediaCodec>
- <MediaCodec name="c2.google.vp8.decoder" type="video/x-vnd.on2.vp8">
+ <MediaCodec name="c2.android.vp8.decoder" type="video/x-vnd.on2.vp8">
<Limit name="size" min="2x2" max="2048x2048" />
<Limit name="alignment" value="2x2" />
<Limit name="block-size" value="16x16" />
@@ -62,7 +62,7 @@
<Limit name="bitrate" range="1-40000000" />
<Feature name="adaptive-playback" />
</MediaCodec>
- <MediaCodec name="c2.google.vp9.decoder" type="video/x-vnd.on2.vp9">
+ <MediaCodec name="c2.android.vp9.decoder" type="video/x-vnd.on2.vp9">
<Limit name="size" min="2x2" max="2048x2048" />
<Limit name="alignment" value="2x2" />
<Limit name="block-size" value="16x16" />
@@ -74,13 +74,13 @@
</Decoders>
<Encoders>
- <MediaCodec name="c2.google.h263.encoder" type="video/3gpp">
+ <MediaCodec name="c2.android.h263.encoder" type="video/3gpp">
<!-- profiles and levels: ProfileBaseline : Level45 -->
<Limit name="size" min="176x144" max="176x144" />
<Limit name="alignment" value="16x16" />
<Limit name="bitrate" range="1-128000" />
</MediaCodec>
- <MediaCodec name="c2.google.avc.encoder" type="video/avc">
+ <MediaCodec name="c2.android.avc.encoder" type="video/avc">
<!-- profiles and levels: ProfileBaseline : Level41 -->
<Limit name="size" min="16x16" max="2048x2048" />
<Limit name="alignment" value="2x2" />
@@ -90,7 +90,7 @@
<Limit name="bitrate" range="1-12000000" />
<Feature name="intra-refresh" />
</MediaCodec>
- <MediaCodec name="c2.google.mpeg4.encoder" type="video/mp4v-es">
+ <MediaCodec name="c2.android.mpeg4.encoder" type="video/mp4v-es">
<!-- profiles and levels: ProfileCore : Level2 -->
<Limit name="size" min="16x16" max="176x144" />
<Limit name="alignment" value="16x16" />
@@ -98,7 +98,7 @@
<Limit name="blocks-per-second" range="12-1485" />
<Limit name="bitrate" range="1-64000" />
</MediaCodec>
- <MediaCodec name="c2.google.vp8.encoder" type="video/x-vnd.on2.vp8">
+ <MediaCodec name="c2.android.vp8.encoder" type="video/x-vnd.on2.vp8">
<!-- profiles and levels: ProfileMain : Level_Version0-3 -->
<Limit name="size" min="2x2" max="2048x2048" />
<Limit name="alignment" value="2x2" />
@@ -108,7 +108,7 @@
<Limit name="bitrate" range="1-40000000" />
<Feature name="bitrate-modes" value="VBR,CBR" />
</MediaCodec>
- <MediaCodec name="c2.google.vp9.encoder" type="video/x-vnd.on2.vp9">
+ <MediaCodec name="c2.android.vp9.encoder" type="video/x-vnd.on2.vp9">
<!-- profiles and levels: ProfileMain : Level_Version0-3 -->
<Limit name="size" min="2x2" max="2048x2048" />
<Limit name="alignment" value="2x2" />
diff --git a/media/libstagefright/include/FrameDecoder.h b/media/libstagefright/include/FrameDecoder.h
index f6d4727..3d4ea39 100644
--- a/media/libstagefright/include/FrameDecoder.h
+++ b/media/libstagefright/include/FrameDecoder.h
@@ -32,32 +32,26 @@
class MediaCodecBuffer;
class IMediaSource;
class VideoFrame;
+struct MediaCodec;
struct FrameDecoder {
FrameDecoder(
const AString &componentName,
const sp<MetaData> &trackMeta,
- const sp<IMediaSource> &source) :
- mComponentName(componentName),
- mTrackMeta(trackMeta),
- mSource(source),
- mDstFormat(OMX_COLOR_Format16bitRGB565),
- mDstBpp(2) {}
+ const sp<IMediaSource> &source);
- sp<IMemory> extractFrame(int64_t frameTimeUs, int option, int colorFormat);
+ status_t init(
+ int64_t frameTimeUs, size_t numFrames, int option, int colorFormat);
- status_t extractFrames(
- int64_t frameTimeUs,
- size_t numFrames,
- int option,
- int colorFormat,
- std::vector<sp<IMemory> >* frames);
+ sp<IMemory> extractFrame();
+
+ status_t extractFrames(std::vector<sp<IMemory> >* frames);
static sp<IMemory> getMetadataOnly(
const sp<MetaData> &trackMeta, int colorFormat, bool thumbnail = false);
protected:
- virtual ~FrameDecoder() {}
+ virtual ~FrameDecoder();
virtual sp<AMessage> onGetFormatAndSeekOptions(
int64_t frameTimeUs,
@@ -92,13 +86,13 @@
OMX_COLOR_FORMATTYPE mDstFormat;
int32_t mDstBpp;
std::vector<sp<IMemory> > mFrames;
+ MediaSource::ReadOptions mReadOptions;
+ sp<MediaCodec> mDecoder;
+ sp<AMessage> mOutputFormat;
+ bool mHaveMoreInputs;
+ bool mFirstSample;
- static bool getDstColorFormat(
- android_pixel_format_t colorFormat,
- OMX_COLOR_FORMATTYPE *dstFormat,
- int32_t *dstBpp);
-
- status_t extractInternal(int64_t frameTimeUs, size_t numFrames, int option);
+ status_t extractInternal();
DISALLOW_EVIL_CONSTRUCTORS(FrameDecoder);
};
@@ -107,13 +101,7 @@
VideoFrameDecoder(
const AString &componentName,
const sp<MetaData> &trackMeta,
- const sp<IMediaSource> &source) :
- FrameDecoder(componentName, trackMeta, source),
- mIsAvcOrHevc(false),
- mSeekMode(MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC),
- mTargetTimeUs(-1ll),
- mNumFrames(0),
- mNumFramesDecoded(0) {}
+ const sp<IMediaSource> &source);
protected:
virtual sp<AMessage> onGetFormatAndSeekOptions(
@@ -146,10 +134,7 @@
ImageDecoder(
const AString &componentName,
const sp<MetaData> &trackMeta,
- const sp<IMediaSource> &source) :
- FrameDecoder(componentName, trackMeta, source),
- mFrame(NULL), mGridRows(1), mGridCols(1),
- mTilesDecoded(0), mThumbnail(false) {}
+ const sp<IMediaSource> &source);
protected:
virtual sp<AMessage> onGetFormatAndSeekOptions(
@@ -172,10 +157,11 @@
private:
VideoFrame *mFrame;
+ int32_t mWidth;
+ int32_t mHeight;
int32_t mGridRows;
int32_t mGridCols;
int32_t mTilesDecoded;
- bool mThumbnail;
};
} // namespace android
diff --git a/media/libstagefright/omx/Android.bp b/media/libstagefright/omx/Android.bp
index 3eb98f3..3e6942b 100644
--- a/media/libstagefright/omx/Android.bp
+++ b/media/libstagefright/omx/Android.bp
@@ -62,6 +62,7 @@
"libmedia_omx",
"libstagefright_foundation",
"libstagefright_xmlparser",
+ "libutils",
],
cflags: [
diff --git a/media/libstagefright/omx/include/media/stagefright/omx/1.0/Omx.h b/media/libstagefright/omx/include/media/stagefright/omx/1.0/Omx.h
index baa7b81..5a46b26 100644
--- a/media/libstagefright/omx/include/media/stagefright/omx/1.0/Omx.h
+++ b/media/libstagefright/omx/include/media/stagefright/omx/1.0/Omx.h
@@ -22,6 +22,8 @@
#include <media/stagefright/xmlparser/MediaCodecsXmlParser.h>
#include <android/hardware/media/omx/1.0/IOmx.h>
+#include <utils/KeyedVector.h>
+#include <utils/Mutex.h>
namespace android {
diff --git a/media/ndk/NdkMediaDrm.cpp b/media/ndk/NdkMediaDrm.cpp
index fe08ab9..6d10f1c 100644
--- a/media/ndk/NdkMediaDrm.cpp
+++ b/media/ndk/NdkMediaDrm.cpp
@@ -224,7 +224,7 @@
static bool findId(AMediaDrm *mObj, const AMediaDrmByteArray &id, List<idvec_t>::iterator &iter) {
for (iter = mObj->mIds.begin(); iter != mObj->mIds.end(); ++iter) {
- if (iter->array() == id.ptr && iter->size() == id.length) {
+ if (id.length == iter->size() && memcmp(iter->array(), id.ptr, iter->size()) == 0) {
return true;
}
}
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index f28132d..e3e53b7 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -2293,7 +2293,7 @@
delete out;
}
-void AudioFlinger::closeOutputInternal_l(const sp<PlaybackThread>& thread)
+void AudioFlinger::closeThreadInternal_l(const sp<PlaybackThread>& thread)
{
mPlaybackThreads.removeItem(thread->mId);
thread->exit();
@@ -2586,7 +2586,7 @@
delete in;
}
-void AudioFlinger::closeInputInternal_l(const sp<RecordThread>& thread)
+void AudioFlinger::closeThreadInternal_l(const sp<RecordThread>& thread)
{
mRecordThreads.removeItem(thread->mId);
closeInputFinish(thread);
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 692a904..7cfe542 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -791,9 +791,9 @@
// for use from destructor
status_t closeOutput_nonvirtual(audio_io_handle_t output);
- void closeOutputInternal_l(const sp<PlaybackThread>& thread);
+ void closeThreadInternal_l(const sp<PlaybackThread>& thread);
status_t closeInput_nonvirtual(audio_io_handle_t input);
- void closeInputInternal_l(const sp<RecordThread>& thread);
+ void closeThreadInternal_l(const sp<RecordThread>& thread);
void setAudioHwSyncForSession_l(PlaybackThread *thread, audio_session_t sessionId);
status_t checkStreamType(audio_stream_type_t stream) const;
diff --git a/services/audioflinger/PatchPanel.cpp b/services/audioflinger/PatchPanel.cpp
index 3ae198b..eaf1120 100644
--- a/services/audioflinger/PatchPanel.cpp
+++ b/services/audioflinger/PatchPanel.cpp
@@ -125,18 +125,16 @@
if (iter != mPatches.end()) {
ALOGV("%s() removing patch handle %d", __func__, *handle);
Patch &removedPatch = iter->second;
- halHandle = removedPatch.mHalHandle;
// free resources owned by the removed patch if applicable
// 1) if a software patch is present, release the playback and capture threads and
// tracks created. This will also release the corresponding audio HAL patches
- if ((removedPatch.mRecordPatchHandle != AUDIO_PATCH_HANDLE_NONE) ||
- (removedPatch.mPlaybackPatchHandle != AUDIO_PATCH_HANDLE_NONE)) {
+ if (removedPatch.isSoftware()) {
removedPatch.clearConnections(this);
}
// 2) if the new patch and old patch source or sink are devices from different
// hw modules, clear the audio HAL patches now because they will not be updated
// by call to create_audio_patch() below which will happen on a different HW module
- if (halHandle != AUDIO_PATCH_HANDLE_NONE) {
+ if (removedPatch.mHalHandle != AUDIO_PATCH_HANDLE_NONE) {
audio_module_handle_t hwModule = AUDIO_MODULE_HANDLE_NONE;
const struct audio_patch &oldPatch = removedPatch.mAudioPatch;
if (oldPatch.sources[0].type == AUDIO_PORT_TYPE_DEVICE &&
@@ -153,16 +151,12 @@
// these special patches are only created by the policy manager but just
// in case, systematically clear the HAL patch.
// Note that removedPatch.mAudioPatch.num_sinks cannot be 0 here because
- // halHandle would be AUDIO_PATCH_HANDLE_NONE in this case.
+ // removedPatch.mHalHandle would be AUDIO_PATCH_HANDLE_NONE in this case.
hwModule = oldPatch.sinks[0].ext.device.hw_module;
}
- if (hwModule != AUDIO_MODULE_HANDLE_NONE) {
- ssize_t index = mAudioFlinger.mAudioHwDevs.indexOfKey(hwModule);
- if (index >= 0) {
- sp<DeviceHalInterface> hwDevice =
- mAudioFlinger.mAudioHwDevs.valueAt(index)->hwDevice();
- hwDevice->releaseAudioPatch(halHandle);
- }
+ sp<DeviceHalInterface> hwDevice = findHwDeviceByModule(hwModule);
+ if (hwDevice != 0) {
+ hwDevice->releaseAudioPatch(removedPatch.mHalHandle);
}
}
mPatches.erase(iter);
@@ -217,12 +211,14 @@
sp<ThreadBase> thread =
mAudioFlinger.checkPlaybackThread_l(patch->sources[1].ext.mix.handle);
- newPatch.mPlaybackThread = (MixerThread *)thread.get();
if (thread == 0) {
ALOGW("%s() cannot get playback thread", __func__);
status = INVALID_OPERATION;
goto exit;
}
+ // existing playback thread is reused, so it is not closed when patch is cleared
+ newPatch.mPlayback.setThread(
+ reinterpret_cast<PlaybackThread*>(thread.get()), false /*closeThread*/);
} else {
audio_config_t config = AUDIO_CONFIG_INITIALIZER;
audio_devices_t device = patch->sinks[0].ext.device.type;
@@ -235,13 +231,12 @@
device,
address,
AUDIO_OUTPUT_FLAG_NONE);
- newPatch.mPlaybackThread = (PlaybackThread *)thread.get();
- ALOGV("mAudioFlinger.openOutput_l() returned %p",
- newPatch.mPlaybackThread.get());
- if (newPatch.mPlaybackThread == 0) {
+ ALOGV("mAudioFlinger.openOutput_l() returned %p", thread.get());
+ if (thread == 0) {
status = NO_MEMORY;
goto exit;
}
+ newPatch.mPlayback.setThread(reinterpret_cast<PlaybackThread*>(thread.get()));
}
audio_devices_t device = patch->sources[0].ext.device.type;
String8 address = String8(patch->sources[0].ext.device.address);
@@ -251,18 +246,18 @@
if (patch->sources[0].config_mask & AUDIO_PORT_CONFIG_SAMPLE_RATE) {
config.sample_rate = patch->sources[0].sample_rate;
} else {
- config.sample_rate = newPatch.mPlaybackThread->sampleRate();
+ config.sample_rate = newPatch.mPlayback.thread()->sampleRate();
}
if (patch->sources[0].config_mask & AUDIO_PORT_CONFIG_CHANNEL_MASK) {
config.channel_mask = patch->sources[0].channel_mask;
} else {
- config.channel_mask =
- audio_channel_in_mask_from_count(newPatch.mPlaybackThread->channelCount());
+ config.channel_mask = audio_channel_in_mask_from_count(
+ newPatch.mPlayback.thread()->channelCount());
}
if (patch->sources[0].config_mask & AUDIO_PORT_CONFIG_FORMAT) {
config.format = patch->sources[0].format;
} else {
- config.format = newPatch.mPlaybackThread->format();
+ config.format = newPatch.mPlayback.thread()->format();
}
audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
sp<ThreadBase> thread = mAudioFlinger.openInput_l(srcModule,
@@ -272,13 +267,13 @@
address,
AUDIO_SOURCE_MIC,
AUDIO_INPUT_FLAG_NONE);
- newPatch.mRecordThread = (RecordThread *)thread.get();
ALOGV("mAudioFlinger.openInput_l() returned %p inChannelMask %08x",
- newPatch.mRecordThread.get(), config.channel_mask);
- if (newPatch.mRecordThread == 0) {
+ thread.get(), config.channel_mask);
+ if (thread == 0) {
status = NO_MEMORY;
goto exit;
}
+ newPatch.mRecord.setThread(reinterpret_cast<RecordThread*>(thread.get()));
status = newPatch.createConnections(this);
if (status != NO_ERROR) {
goto exit;
@@ -369,6 +364,12 @@
return status;
}
+AudioFlinger::PatchPanel::Patch::~Patch()
+{
+ ALOGE_IF(isSoftware(), "Software patch connections leaked %d %d",
+ mRecord.handle(), mPlayback.handle());
+}
+
status_t AudioFlinger::PatchPanel::Patch::createConnections(PatchPanel *panel)
{
// create patch from source device to record thread input
@@ -377,32 +378,32 @@
subPatch.sources[0] = mAudioPatch.sources[0];
subPatch.num_sinks = 1;
- mRecordThread->getAudioPortConfig(&subPatch.sinks[0]);
+ mRecord.thread()->getAudioPortConfig(&subPatch.sinks[0]);
subPatch.sinks[0].ext.mix.usecase.source = AUDIO_SOURCE_MIC;
- status_t status = panel->createAudioPatch(&subPatch, &mRecordPatchHandle);
+ status_t status = panel->createAudioPatch(&subPatch, mRecord.handlePtr());
if (status != NO_ERROR) {
- mRecordPatchHandle = AUDIO_PATCH_HANDLE_NONE;
+ *mRecord.handlePtr() = AUDIO_PATCH_HANDLE_NONE;
return status;
}
// create patch from playback thread output to sink device
if (mAudioPatch.num_sinks != 0) {
- mPlaybackThread->getAudioPortConfig(&subPatch.sources[0]);
+ mPlayback.thread()->getAudioPortConfig(&subPatch.sources[0]);
subPatch.sinks[0] = mAudioPatch.sinks[0];
- status = panel->createAudioPatch(&subPatch, &mPlaybackPatchHandle);
+ status = panel->createAudioPatch(&subPatch, mPlayback.handlePtr());
if (status != NO_ERROR) {
- mPlaybackPatchHandle = AUDIO_PATCH_HANDLE_NONE;
+ *mPlayback.handlePtr() = AUDIO_PATCH_HANDLE_NONE;
return status;
}
} else {
- mPlaybackPatchHandle = AUDIO_PATCH_HANDLE_NONE;
+ *mPlayback.handlePtr() = AUDIO_PATCH_HANDLE_NONE;
}
// use a pseudo LCM between input and output framecount
- size_t playbackFrameCount = mPlaybackThread->frameCount();
+ size_t playbackFrameCount = mPlayback.thread()->frameCount();
int playbackShift = __builtin_ctz(playbackFrameCount);
- size_t recordFramecount = mRecordThread->frameCount();
+ size_t recordFramecount = mRecord.thread()->frameCount();
int shift = __builtin_ctz(recordFramecount);
if (playbackShift < shift) {
shift = playbackShift;
@@ -412,14 +413,14 @@
__func__, playbackFrameCount, recordFramecount, frameCount);
// create a special record track to capture from record thread
- uint32_t channelCount = mPlaybackThread->channelCount();
+ uint32_t channelCount = mPlayback.thread()->channelCount();
audio_channel_mask_t inChannelMask = audio_channel_in_mask_from_count(channelCount);
- audio_channel_mask_t outChannelMask = mPlaybackThread->channelMask();
- uint32_t sampleRate = mPlaybackThread->sampleRate();
- audio_format_t format = mPlaybackThread->format();
+ audio_channel_mask_t outChannelMask = mPlayback.thread()->channelMask();
+ uint32_t sampleRate = mPlayback.thread()->sampleRate();
+ audio_format_t format = mPlayback.thread()->format();
- mPatchRecord = new RecordThread::PatchRecord(
- mRecordThread.get(),
+ sp<RecordThread::PatchRecord> tempRecordTrack = new (std::nothrow) RecordThread::PatchRecord(
+ mRecord.thread().get(),
sampleRate,
inChannelMask,
format,
@@ -427,91 +428,47 @@
NULL,
(size_t)0 /* bufferSize */,
AUDIO_INPUT_FLAG_NONE);
- if (mPatchRecord == 0) {
- return NO_MEMORY;
- }
- status = mPatchRecord->initCheck();
+ status = mRecord.checkTrack(tempRecordTrack.get());
if (status != NO_ERROR) {
return status;
}
- mRecordThread->addPatchRecord(mPatchRecord);
// create a special playback track to render to playback thread.
// this track is given the same buffer as the PatchRecord buffer
- mPatchTrack = new PlaybackThread::PatchTrack(
- mPlaybackThread.get(),
+ sp<PlaybackThread::PatchTrack> tempPatchTrack = new (std::nothrow) PlaybackThread::PatchTrack(
+ mPlayback.thread().get(),
mAudioPatch.sources[1].ext.mix.usecase.stream,
sampleRate,
outChannelMask,
format,
frameCount,
- mPatchRecord->buffer(),
- mPatchRecord->bufferSize(),
+ tempRecordTrack->buffer(),
+ tempRecordTrack->bufferSize(),
AUDIO_OUTPUT_FLAG_NONE);
- status = mPatchTrack->initCheck();
+ status = mPlayback.checkTrack(tempPatchTrack.get());
if (status != NO_ERROR) {
return status;
}
- mPlaybackThread->addPatchTrack(mPatchTrack);
// tie playback and record tracks together
- mPatchRecord->setPeerProxy(mPatchTrack.get());
- mPatchTrack->setPeerProxy(mPatchRecord.get());
+ mRecord.setTrackAndPeer(tempRecordTrack, tempPatchTrack.get());
+ mPlayback.setTrackAndPeer(tempPatchTrack, tempRecordTrack.get());
// start capture and playback
- mPatchRecord->start(AudioSystem::SYNC_EVENT_NONE, AUDIO_SESSION_NONE);
- mPatchTrack->start();
+ mRecord.track()->start(AudioSystem::SYNC_EVENT_NONE, AUDIO_SESSION_NONE);
+ mPlayback.track()->start();
return status;
}
void AudioFlinger::PatchPanel::Patch::clearConnections(PatchPanel *panel)
{
- ALOGV("%s() mRecordPatchHandle %d mPlaybackPatchHandle %d",
- __func__, mRecordPatchHandle, mPlaybackPatchHandle);
-
- if (mPatchRecord != 0) {
- mPatchRecord->stop();
- }
- if (mPatchTrack != 0) {
- mPatchTrack->stop();
- }
- if (mRecordPatchHandle != AUDIO_PATCH_HANDLE_NONE) {
- panel->releaseAudioPatch(mRecordPatchHandle);
- mRecordPatchHandle = AUDIO_PATCH_HANDLE_NONE;
- }
- if (mPlaybackPatchHandle != AUDIO_PATCH_HANDLE_NONE) {
- panel->releaseAudioPatch(mPlaybackPatchHandle);
- mPlaybackPatchHandle = AUDIO_PATCH_HANDLE_NONE;
- }
- if (mRecordThread != 0) {
- if (mPatchRecord != 0) {
- mRecordThread->deletePatchRecord(mPatchRecord);
- }
- panel->mAudioFlinger.closeInputInternal_l(mRecordThread);
- }
- if (mPlaybackThread != 0) {
- if (mPatchTrack != 0) {
- mPlaybackThread->deletePatchTrack(mPatchTrack);
- }
- // if num sources == 2 we are reusing an existing playback thread so we do not close it
- if (mAudioPatch.num_sources != 2) {
- panel->mAudioFlinger.closeOutputInternal_l(mPlaybackThread);
- }
- }
- if (mRecordThread != 0) {
- if (mPatchRecord != 0) {
- mPatchRecord.clear();
- }
- mRecordThread.clear();
- }
- if (mPlaybackThread != 0) {
- if (mPatchTrack != 0) {
- mPatchTrack.clear();
- }
- mPlaybackThread.clear();
- }
-
+ ALOGV("%s() mRecord.handle %d mPlayback.handle %d",
+ __func__, mRecord.handle(), mPlayback.handle());
+ mRecord.stopTrack();
+ mPlayback.stopTrack();
+ mRecord.closeConnections(panel);
+ mPlayback.closeConnections(panel);
}
/* Disconnect a patch */
@@ -527,18 +484,17 @@
Patch &removedPatch = iter->second;
const struct audio_patch &patch = removedPatch.mAudioPatch;
- switch (patch.sources[0].type) {
+ const struct audio_port_config &src = patch.sources[0];
+ switch (src.type) {
case AUDIO_PORT_TYPE_DEVICE: {
- audio_module_handle_t srcModule = patch.sources[0].ext.device.hw_module;
- ssize_t index = mAudioFlinger.mAudioHwDevs.indexOfKey(srcModule);
- if (index < 0) {
- ALOGW("%s() bad src hw module %d", __func__, srcModule);
+ sp<DeviceHalInterface> hwDevice = findHwDeviceByModule(src.ext.device.hw_module);
+ if (hwDevice == 0) {
+ ALOGW("%s() bad src hw module %d", __func__, src.ext.device.hw_module);
status = BAD_VALUE;
break;
}
- if (removedPatch.mRecordPatchHandle != AUDIO_PATCH_HANDLE_NONE ||
- removedPatch.mPlaybackPatchHandle != AUDIO_PATCH_HANDLE_NONE) {
+ if (removedPatch.isSoftware()) {
removedPatch.clearConnections(this);
break;
}
@@ -556,20 +512,16 @@
}
status = thread->sendReleaseAudioPatchConfigEvent(removedPatch.mHalHandle);
} else {
- AudioHwDevice *audioHwDevice = mAudioFlinger.mAudioHwDevs.valueAt(index);
- sp<DeviceHalInterface> hwDevice = audioHwDevice->hwDevice();
status = hwDevice->releaseAudioPatch(removedPatch.mHalHandle);
}
} break;
case AUDIO_PORT_TYPE_MIX: {
- audio_module_handle_t srcModule = patch.sources[0].ext.mix.hw_module;
- ssize_t index = mAudioFlinger.mAudioHwDevs.indexOfKey(srcModule);
- if (index < 0) {
- ALOGW("%s() bad src hw module %d", __func__, srcModule);
+ if (findHwDeviceByModule(src.ext.mix.hw_module) == 0) {
+ ALOGW("%s() bad src hw module %d", __func__, src.ext.mix.hw_module);
status = BAD_VALUE;
break;
}
- audio_io_handle_t ioHandle = patch.sources[0].ext.mix.handle;
+ audio_io_handle_t ioHandle = src.ext.mix.handle;
sp<ThreadBase> thread = mAudioFlinger.checkPlaybackThread_l(ioHandle);
if (thread == 0) {
thread = mAudioFlinger.checkMmapThread_l(ioHandle);
@@ -597,4 +549,14 @@
return NO_ERROR;
}
+sp<DeviceHalInterface> AudioFlinger::PatchPanel::findHwDeviceByModule(audio_module_handle_t module)
+{
+ if (module == AUDIO_MODULE_HANDLE_NONE) return nullptr;
+ ssize_t index = mAudioFlinger.mAudioHwDevs.indexOfKey(module);
+ if (index < 0) {
+ return nullptr;
+ }
+ return mAudioFlinger.mAudioHwDevs.valueAt(index)->hwDevice();
+}
+
} // namespace android
diff --git a/services/audioflinger/PatchPanel.h b/services/audioflinger/PatchPanel.h
index c2cb7ac..5a68960 100644
--- a/services/audioflinger/PatchPanel.h
+++ b/services/audioflinger/PatchPanel.h
@@ -43,12 +43,61 @@
struct audio_patch *patches);
private:
+ template<typename ThreadType, typename TrackType>
+ class Endpoint {
+ public:
+ status_t checkTrack(TrackType *trackOrNull) const {
+ if (trackOrNull == nullptr) return NO_MEMORY;
+ return trackOrNull->initCheck();
+ }
+ audio_patch_handle_t handle() const { return mHandle; }
+ sp<ThreadType> thread() { return mThread; }
+ sp<TrackType> track() { return mTrack; }
+
+ void closeConnections(PatchPanel *panel) {
+ if (mHandle != AUDIO_PATCH_HANDLE_NONE) {
+ panel->releaseAudioPatch(mHandle);
+ mHandle = AUDIO_PATCH_HANDLE_NONE;
+ }
+ if (mThread != 0) {
+ if (mTrack != 0) {
+ mThread->deletePatchTrack(mTrack);
+ }
+ if (mCloseThread) {
+ panel->mAudioFlinger.closeThreadInternal_l(mThread);
+ }
+ }
+ }
+ audio_patch_handle_t* handlePtr() { return &mHandle; }
+ void setThread(const sp<ThreadType>& thread, bool closeThread = true) {
+ mThread = thread;
+ mCloseThread = closeThread;
+ }
+ void setTrackAndPeer(const sp<TrackType>& track,
+ ThreadBase::PatchProxyBufferProvider *peer) {
+ mTrack = track;
+ mThread->addPatchTrack(mTrack);
+ mTrack->setPeerProxy(peer);
+ }
+ void stopTrack() { if (mTrack) mTrack->stop(); }
+
+ private:
+ sp<ThreadType> mThread;
+ bool mCloseThread = true;
+ audio_patch_handle_t mHandle = AUDIO_PATCH_HANDLE_NONE;
+ sp<TrackType> mTrack;
+ };
+
class Patch {
public:
explicit Patch(const struct audio_patch &patch) : mAudioPatch(patch) {}
+ ~Patch();
status_t createConnections(PatchPanel *panel);
void clearConnections(PatchPanel *panel);
+ bool isSoftware() const {
+ return mRecord.handle() != AUDIO_PATCH_HANDLE_NONE ||
+ mPlayback.handle() != AUDIO_PATCH_HANDLE_NONE; }
// Note that audio_patch::id is only unique within a HAL module
struct audio_patch mAudioPatch;
@@ -58,17 +107,14 @@
// given audio HW module to a sink device on an other audio HW module.
// the objects are created by createConnections() and released by clearConnections()
// playback thread is created if no existing playback thread can be used
- sp<PlaybackThread> mPlaybackThread;
- sp<PlaybackThread::PatchTrack> mPatchTrack;
- sp<RecordThread> mRecordThread;
- sp<RecordThread::PatchRecord> mPatchRecord;
- // handle for audio patch connecting source device to record thread input.
- audio_patch_handle_t mRecordPatchHandle = AUDIO_PATCH_HANDLE_NONE;
- // handle for audio patch connecting playback thread output to sink device
- audio_patch_handle_t mPlaybackPatchHandle = AUDIO_PATCH_HANDLE_NONE;
-
+ // connects playback thread output to sink device
+ Endpoint<PlaybackThread, PlaybackThread::PatchTrack> mPlayback;
+ // connects source device to record thread input
+ Endpoint<RecordThread, RecordThread::PatchRecord> mRecord;
};
+ sp<DeviceHalInterface> findHwDeviceByModule(audio_module_handle_t module);
+
AudioFlinger &mAudioFlinger;
std::map<audio_patch_handle_t, Patch> mPatches;
};
diff --git a/services/audioflinger/RecordTracks.h b/services/audioflinger/RecordTracks.h
index 2b993ee..fc2dbbb 100644
--- a/services/audioflinger/RecordTracks.h
+++ b/services/audioflinger/RecordTracks.h
@@ -64,7 +64,7 @@
virtual bool isFastTrack() const { return (mFlags & AUDIO_INPUT_FLAG_FAST) != 0; }
- void setSilenced(bool silenced) { mSilenced = silenced; }
+ void setSilenced(bool silenced) { if (!isPatchTrack()) mSilenced = silenced; }
bool isSilenced() const { return mSilenced; }
status_t getActiveMicrophones(std::vector<media::MicrophoneInfo>* activeMicrophones);
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index c47aa01..d037207 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -6614,11 +6614,16 @@
if (framesRead != OVERRUN) break;
}
- // since pipe is non-blocking, simulate blocking input by waiting for 1/2 of
- // buffer size or at least for 20ms.
- size_t sleepFrames = max(
- min(mPipeFramesP2, mRsmpInFramesP2) / 2, FMS_20 * mSampleRate / 1000);
- if (framesRead <= (ssize_t) sleepFrames) {
+ const ssize_t availableToRead = mPipeSource->availableToRead();
+ if (availableToRead >= 0) {
+ // PipeSource is the master clock. It is up to the AudioRecord client to keep up.
+ LOG_ALWAYS_FATAL_IF((size_t)availableToRead > mPipeFramesP2,
+ "more frames to read than fifo size, %zd > %zu",
+ availableToRead, mPipeFramesP2);
+ const size_t pipeFramesFree = mPipeFramesP2 - availableToRead;
+ const size_t sleepFrames = min(pipeFramesFree, mRsmpInFramesP2) / 2;
+ ALOGVV("mPipeFramesP2:%zu mRsmpInFramesP2:%zu sleepFrames:%zu availableToRead:%zd",
+ mPipeFramesP2, mRsmpInFramesP2, sleepFrames, availableToRead);
sleepUs = (sleepFrames * 1000000LL) / mSampleRate;
}
if (framesRead < 0) {
@@ -7835,13 +7840,13 @@
return status;
}
-void AudioFlinger::RecordThread::addPatchRecord(const sp<PatchRecord>& record)
+void AudioFlinger::RecordThread::addPatchTrack(const sp<PatchRecord>& record)
{
Mutex::Autolock _l(mLock);
mTracks.add(record);
}
-void AudioFlinger::RecordThread::deletePatchRecord(const sp<PatchRecord>& record)
+void AudioFlinger::RecordThread::deletePatchTrack(const sp<PatchRecord>& record)
{
Mutex::Autolock _l(mLock);
destroyTrack_l(record);
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 28d4482..c490fb5 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -1437,8 +1437,8 @@
audio_patch_handle_t *handle);
virtual status_t releaseAudioPatch_l(const audio_patch_handle_t handle);
- void addPatchRecord(const sp<PatchRecord>& record);
- void deletePatchRecord(const sp<PatchRecord>& record);
+ void addPatchTrack(const sp<PatchRecord>& record);
+ void deletePatchTrack(const sp<PatchRecord>& record);
void readInputParameters_l();
virtual uint32_t getInputFramesLost();
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index aff1239..49552a1 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -1663,7 +1663,8 @@
mFramesToDrop(0),
mResamplerBufferProvider(NULL), // initialize in case of early constructor exit
mRecordBufferConverter(NULL),
- mFlags(flags)
+ mFlags(flags),
+ mSilenced(false)
{
if (mCblk == NULL) {
return;
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 67b5e06..6b958a8 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -4325,9 +4325,9 @@
uint32_t numRequestProcessed = 0;
for (size_t i = 0; i < batchSize; i++) {
requests[i] = &mNextRequests.editItemAt(i).halRequest;
+ ATRACE_ASYNC_BEGIN("frame capture", mNextRequests[i].halRequest.frame_number);
}
- ATRACE_ASYNC_BEGIN("batch frame capture", mNextRequests[0].halRequest.frame_number);
res = mInterface->processBatchCaptureRequests(requests, &numRequestProcessed);
bool triggerRemoveFailed = false;
diff --git a/services/oboeservice/AAudioServiceEndpoint.h b/services/oboeservice/AAudioServiceEndpoint.h
index 6015b28..253f290 100644
--- a/services/oboeservice/AAudioServiceEndpoint.h
+++ b/services/oboeservice/AAudioServiceEndpoint.h
@@ -49,9 +49,9 @@
virtual aaudio_result_t close() = 0;
- virtual aaudio_result_t registerStream(android::sp<AAudioServiceStreamBase> stream);
+ aaudio_result_t registerStream(android::sp<AAudioServiceStreamBase> stream);
- virtual aaudio_result_t unregisterStream(android::sp<AAudioServiceStreamBase> stream);
+ aaudio_result_t unregisterStream(android::sp<AAudioServiceStreamBase> stream);
virtual aaudio_result_t startStream(android::sp<AAudioServiceStreamBase> stream,
audio_port_handle_t *clientHandle) = 0;
diff --git a/services/oboeservice/AAudioServiceStreamBase.cpp b/services/oboeservice/AAudioServiceStreamBase.cpp
index c943008..48d8002 100644
--- a/services/oboeservice/AAudioServiceStreamBase.cpp
+++ b/services/oboeservice/AAudioServiceStreamBase.cpp
@@ -105,6 +105,9 @@
goto error;
}
+ // This is not protected by a lock because the stream cannot be
+ // referenced until the service returns a handle to the client.
+ // So only one thread can open a stream.
mServiceEndpoint = mEndpointManager.openEndpoint(mAudioService,
request,
sharingMode);
@@ -113,6 +116,9 @@
result = AAUDIO_ERROR_UNAVAILABLE;
goto error;
}
+ // Save a weak pointer that we will use to access the endpoint.
+ mServiceEndpointWeak = mServiceEndpoint;
+
mFramesPerBurst = mServiceEndpoint->getFramesPerBurst();
copyFrom(*mServiceEndpoint);
}
@@ -131,13 +137,16 @@
stop();
- if (mServiceEndpoint == nullptr) {
+ sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
+ if (endpoint == nullptr) {
result = AAUDIO_ERROR_INVALID_STATE;
} else {
- mServiceEndpoint->unregisterStream(this);
- AAudioEndpointManager &mEndpointManager = AAudioEndpointManager::getInstance();
- mEndpointManager.closeEndpoint(mServiceEndpoint);
- mServiceEndpoint.clear();
+ endpoint->unregisterStream(this);
+ AAudioEndpointManager &endpointManager = AAudioEndpointManager::getInstance();
+ endpointManager.closeEndpoint(endpoint);
+
+ // AAudioService::closeStream() prevents two threads from closing at the same time.
+ mServiceEndpoint.clear(); // endpoint will hold the pointer until this method returns.
}
{
@@ -153,7 +162,12 @@
aaudio_result_t AAudioServiceStreamBase::startDevice() {
mClientHandle = AUDIO_PORT_HANDLE_NONE;
- return mServiceEndpoint->startStream(this, &mClientHandle);
+ sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
+ if (endpoint == nullptr) {
+ ALOGE("%s() has no endpoint", __func__);
+ return AAUDIO_ERROR_INVALID_STATE;
+ }
+ return endpoint->startStream(this, &mClientHandle);
}
/**
@@ -163,16 +177,11 @@
*/
aaudio_result_t AAudioServiceStreamBase::start() {
aaudio_result_t result = AAUDIO_OK;
+
if (isRunning()) {
return AAUDIO_OK;
}
- if (mServiceEndpoint == nullptr) {
- ALOGE("%s() missing endpoint", __func__);
- result = AAUDIO_ERROR_INVALID_STATE;
- goto error;
- }
-
setFlowing(false);
// Start with fresh presentation timestamps.
@@ -201,10 +210,6 @@
if (!isRunning()) {
return result;
}
- if (mServiceEndpoint == nullptr) {
- ALOGE("%s() missing endpoint", __func__);
- return AAUDIO_ERROR_INVALID_STATE;
- }
// Send it now because the timestamp gets rounded up when stopStream() is called below.
// Also we don't need the timestamps while we are shutting down.
@@ -216,7 +221,12 @@
return result;
}
- result = mServiceEndpoint->stopStream(this, mClientHandle);
+ sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
+ if (endpoint == nullptr) {
+ ALOGE("%s() has no endpoint", __func__);
+ return AAUDIO_ERROR_INVALID_STATE;
+ }
+ result = endpoint->stopStream(this, mClientHandle);
if (result != AAUDIO_OK) {
ALOGE("%s() mServiceEndpoint returned %d, %s", __func__, result, getTypeText());
disconnect(); // TODO should we return or pause Base first?
@@ -233,11 +243,6 @@
return result;
}
- if (mServiceEndpoint == nullptr) {
- ALOGE("%s() missing endpoint", __func__);
- return AAUDIO_ERROR_INVALID_STATE;
- }
-
setState(AAUDIO_STREAM_STATE_STOPPING);
// Send it now because the timestamp gets rounded up when stopStream() is called below.
@@ -249,10 +254,15 @@
return result;
}
+ sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
+ if (endpoint == nullptr) {
+ ALOGE("%s() has no endpoint", __func__);
+ return AAUDIO_ERROR_INVALID_STATE;
+ }
// TODO wait for data to be played out
- result = mServiceEndpoint->stopStream(this, mClientHandle);
+ result = endpoint->stopStream(this, mClientHandle);
if (result != AAUDIO_OK) {
- ALOGE("%s() mServiceEndpoint returned %d, %s", __func__, result, getTypeText());
+ ALOGE("%s() stopStream returned %d, %s", __func__, result, getTypeText());
disconnect();
// TODO what to do with result here?
}
diff --git a/services/oboeservice/AAudioServiceStreamBase.h b/services/oboeservice/AAudioServiceStreamBase.h
index d8102be..0ad015e 100644
--- a/services/oboeservice/AAudioServiceStreamBase.h
+++ b/services/oboeservice/AAudioServiceStreamBase.h
@@ -279,7 +279,12 @@
SimpleDoubleBuffer<Timestamp> mAtomicTimestamp;
android::AAudioService &mAudioService;
+
+ // The mServiceEndpoint variable can be accessed by multiple threads.
+ // So we access it by locally promoting a weak pointer to a smart pointer,
+ // which is thread-safe.
android::sp<AAudioServiceEndpoint> mServiceEndpoint;
+ android::wp<AAudioServiceEndpoint> mServiceEndpointWeak;
private:
aaudio_handle_t mHandle = -1;
diff --git a/services/oboeservice/AAudioServiceStreamMMAP.cpp b/services/oboeservice/AAudioServiceStreamMMAP.cpp
index 34ddb4b..c845309 100644
--- a/services/oboeservice/AAudioServiceStreamMMAP.cpp
+++ b/services/oboeservice/AAudioServiceStreamMMAP.cpp
@@ -70,14 +70,19 @@
return result;
}
- result = mServiceEndpoint->registerStream(keep);
+ sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
+ if (endpoint == nullptr) {
+ ALOGE("%s() has no endpoint", __func__);
+ return AAUDIO_ERROR_INVALID_STATE;
+ }
+
+ result = endpoint->registerStream(keep);
if (result != AAUDIO_OK) {
- goto error;
+ return result;
}
setState(AAUDIO_STREAM_STATE_OPEN);
-error:
return AAUDIO_OK;
}
@@ -118,21 +123,37 @@
aaudio_result_t AAudioServiceStreamMMAP::startClient(const android::AudioClient& client,
audio_port_handle_t *clientHandle) {
+ sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
+ if (endpoint == nullptr) {
+ ALOGE("%s() has no endpoint", __func__);
+ return AAUDIO_ERROR_INVALID_STATE;
+ }
// Start the client on behalf of the application. Generate a new porthandle.
- aaudio_result_t result = mServiceEndpoint->startClient(client, clientHandle);
+ aaudio_result_t result = endpoint->startClient(client, clientHandle);
return result;
}
aaudio_result_t AAudioServiceStreamMMAP::stopClient(audio_port_handle_t clientHandle) {
- aaudio_result_t result = mServiceEndpoint->stopClient(clientHandle);
+ sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
+ if (endpoint == nullptr) {
+ ALOGE("%s() has no endpoint", __func__);
+ return AAUDIO_ERROR_INVALID_STATE;
+ }
+ aaudio_result_t result = endpoint->stopClient(clientHandle);
return result;
}
// Get free-running DSP or DMA hardware position from the HAL.
aaudio_result_t AAudioServiceStreamMMAP::getFreeRunningPosition(int64_t *positionFrames,
int64_t *timeNanos) {
- sp<AAudioServiceEndpointMMAP> serviceEndpointMMAP{
- static_cast<AAudioServiceEndpointMMAP *>(mServiceEndpoint.get())};
+ sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
+ if (endpoint == nullptr) {
+ ALOGE("%s() has no endpoint", __func__);
+ return AAUDIO_ERROR_INVALID_STATE;
+ }
+ sp<AAudioServiceEndpointMMAP> serviceEndpointMMAP =
+ static_cast<AAudioServiceEndpointMMAP *>(endpoint.get());
+
aaudio_result_t result = serviceEndpointMMAP->getFreeRunningPosition(positionFrames, timeNanos);
if (result == AAUDIO_OK) {
Timestamp timestamp(*positionFrames, *timeNanos);
@@ -148,8 +169,15 @@
// Get timestamp that was written by getFreeRunningPosition()
aaudio_result_t AAudioServiceStreamMMAP::getHardwareTimestamp(int64_t *positionFrames,
int64_t *timeNanos) {
- sp<AAudioServiceEndpointMMAP> serviceEndpointMMAP{
- static_cast<AAudioServiceEndpointMMAP *>(mServiceEndpoint.get())};
+
+ sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
+ if (endpoint == nullptr) {
+ ALOGE("%s() has no endpoint", __func__);
+ return AAUDIO_ERROR_INVALID_STATE;
+ }
+ sp<AAudioServiceEndpointMMAP> serviceEndpointMMAP =
+ static_cast<AAudioServiceEndpointMMAP *>(endpoint.get());
+
// TODO Get presentation timestamp from the HAL
if (mAtomicTimestamp.isValid()) {
Timestamp timestamp = mAtomicTimestamp.read();
@@ -165,7 +193,12 @@
aaudio_result_t AAudioServiceStreamMMAP::getAudioDataDescription(
AudioEndpointParcelable &parcelable)
{
- sp<AAudioServiceEndpointMMAP> serviceEndpointMMAP{
- static_cast<AAudioServiceEndpointMMAP *>(mServiceEndpoint.get())};
+ sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
+ if (endpoint == nullptr) {
+ ALOGE("%s() has no endpoint", __func__);
+ return AAUDIO_ERROR_INVALID_STATE;
+ }
+ sp<AAudioServiceEndpointMMAP> serviceEndpointMMAP =
+ static_cast<AAudioServiceEndpointMMAP *>(endpoint.get());
return serviceEndpointMMAP->getDownDataDescription(parcelable);
}
diff --git a/services/oboeservice/AAudioServiceStreamShared.cpp b/services/oboeservice/AAudioServiceStreamShared.cpp
index 864a008..05c5735 100644
--- a/services/oboeservice/AAudioServiceStreamShared.cpp
+++ b/services/oboeservice/AAudioServiceStreamShared.cpp
@@ -128,6 +128,12 @@
const AAudioStreamConfiguration &configurationInput = request.getConstantConfiguration();
+ sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
+ if (endpoint == nullptr) {
+ result = AAUDIO_ERROR_INVALID_STATE;
+ goto error;
+ }
+
// Is the request compatible with the shared endpoint?
setFormat(configurationInput.getFormat());
if (getFormat() == AAUDIO_FORMAT_UNSPECIFIED) {
@@ -140,20 +146,20 @@
setSampleRate(configurationInput.getSampleRate());
if (getSampleRate() == AAUDIO_UNSPECIFIED) {
- setSampleRate(mServiceEndpoint->getSampleRate());
- } else if (getSampleRate() != mServiceEndpoint->getSampleRate()) {
+ setSampleRate(endpoint->getSampleRate());
+ } else if (getSampleRate() != endpoint->getSampleRate()) {
ALOGD("%s() mSampleRate = %d, need %d",
- __func__, getSampleRate(), mServiceEndpoint->getSampleRate());
+ __func__, getSampleRate(), endpoint->getSampleRate());
result = AAUDIO_ERROR_INVALID_RATE;
goto error;
}
setSamplesPerFrame(configurationInput.getSamplesPerFrame());
if (getSamplesPerFrame() == AAUDIO_UNSPECIFIED) {
- setSamplesPerFrame(mServiceEndpoint->getSamplesPerFrame());
- } else if (getSamplesPerFrame() != mServiceEndpoint->getSamplesPerFrame()) {
+ setSamplesPerFrame(endpoint->getSamplesPerFrame());
+ } else if (getSamplesPerFrame() != endpoint->getSamplesPerFrame()) {
ALOGD("%s() mSamplesPerFrame = %d, need %d",
- __func__, getSamplesPerFrame(), mServiceEndpoint->getSamplesPerFrame());
+ __func__, getSamplesPerFrame(), endpoint->getSamplesPerFrame());
result = AAUDIO_ERROR_OUT_OF_RANGE;
goto error;
}
@@ -179,7 +185,10 @@
}
}
- result = mServiceEndpoint->registerStream(keep);
+ ALOGD("AAudioServiceStreamShared::open() actual rate = %d, channels = %d, deviceId = %d",
+ getSampleRate(), getSamplesPerFrame(), endpoint->getDeviceId());
+
+ result = endpoint->registerStream(keep);
if (result != AAUDIO_OK) {
goto error;
}
@@ -246,7 +255,13 @@
int64_t *timeNanos) {
int64_t position = 0;
- aaudio_result_t result = mServiceEndpoint->getTimestamp(&position, timeNanos);
+ sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
+ if (endpoint == nullptr) {
+ ALOGE("%s() has no endpoint", __func__);
+ return AAUDIO_ERROR_INVALID_STATE;
+ }
+
+ aaudio_result_t result = endpoint->getTimestamp(&position, timeNanos);
if (result == AAUDIO_OK) {
int64_t offset = mTimestampPositionOffset.load();
// TODO, do not go below starting value