Merge "Return correct error codes from extractors"
diff --git a/camera/ndk/impl/ACameraDevice.cpp b/camera/ndk/impl/ACameraDevice.cpp
index 5ba76d9..ac3be25 100644
--- a/camera/ndk/impl/ACameraDevice.cpp
+++ b/camera/ndk/impl/ACameraDevice.cpp
@@ -1294,12 +1294,17 @@
case ERROR_CAMERA_DEVICE:
case ERROR_CAMERA_SERVICE:
{
+ int32_t errorVal = ::ERROR_CAMERA_DEVICE;
+ // We keep this switch since this block might be encountered with
+ // more than just 2 states. The default fallthrough could have us
+ // handling more unmatched error cases.
switch (errorCode) {
case ERROR_CAMERA_DEVICE:
dev->setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_DEVICE);
break;
case ERROR_CAMERA_SERVICE:
dev->setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_SERVICE);
+ errorVal = ::ERROR_CAMERA_SERVICE;
break;
default:
dev->setCameraDeviceErrorLocked(ACAMERA_ERROR_UNKNOWN);
@@ -1309,7 +1314,7 @@
msg->setPointer(kContextKey, dev->mAppCallbacks.context);
msg->setPointer(kDeviceKey, (void*) dev->getWrapper());
msg->setPointer(kCallbackFpKey, (void*) dev->mAppCallbacks.onError);
- msg->setInt32(kErrorCodeKey, errorCode);
+ msg->setInt32(kErrorCodeKey, errorVal);
msg->post();
break;
}
diff --git a/media/libaaudio/tests/Android.bp b/media/libaaudio/tests/Android.bp
index ef272b0..319467e 100644
--- a/media/libaaudio/tests/Android.bp
+++ b/media/libaaudio/tests/Android.bp
@@ -19,6 +19,18 @@
}
cc_test {
+ name: "test_clock_model",
+ defaults: ["libaaudio_tests_defaults"],
+ srcs: ["test_clock_model.cpp"],
+ shared_libs: [
+ "libaaudio",
+ "libaudioutils",
+ "libcutils",
+ "libutils",
+ ],
+}
+
+cc_test {
name: "test_block_adapter",
defaults: ["libaaudio_tests_defaults"],
srcs: ["test_block_adapter.cpp"],
diff --git a/media/libaaudio/tests/test_clock_model.cpp b/media/libaaudio/tests/test_clock_model.cpp
new file mode 100644
index 0000000..3c09025
--- /dev/null
+++ b/media/libaaudio/tests/test_clock_model.cpp
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Unit tests for Isochronous Clock Model
+
+#include <math.h>
+#include <stdlib.h>
+
+
+#include <aaudio/AAudio.h>
+#include <audio_utils/clock.h>
+#include <client/IsochronousClockModel.h>
+#include <gtest/gtest.h>
+
+using namespace aaudio;
+
+// We can use arbitrary values here because we are not opening a real audio stream.
+#define SAMPLE_RATE 48000
+#define HW_FRAMES_PER_BURST 48
+#define NANOS_PER_BURST (NANOS_PER_SECOND * HW_FRAMES_PER_BURST / SAMPLE_RATE)
+
+class ClockModelTestFixture: public ::testing::Test {
+public:
+ ClockModelTestFixture() {
+ }
+
+ void SetUp() {
+ model.setSampleRate(SAMPLE_RATE);
+ model.setFramesPerBurst(HW_FRAMES_PER_BURST);
+ }
+
+ void TearDown() {
+
+ }
+
+ ~ClockModelTestFixture() {
+ // cleanup any pending stuff, but no exceptions allowed
+ }
+
+ IsochronousClockModel model;
+};
+
+// Check default setup.
+TEST_F(ClockModelTestFixture, clock_setup) {
+ ASSERT_EQ(SAMPLE_RATE, model.getSampleRate());
+ ASSERT_EQ(HW_FRAMES_PER_BURST, model.getFramesPerBurst());
+}
+
+// Test delta calculations.
+TEST_F(ClockModelTestFixture, clock_deltas) {
+ int64_t position = model.convertDeltaTimeToPosition(NANOS_PER_SECOND);
+ ASSERT_EQ(SAMPLE_RATE, position);
+
+ // Deltas are not quantized.
+ // Compare time to the equivalent position in frames.
+ constexpr int64_t kNanosPerBurst = HW_FRAMES_PER_BURST * NANOS_PER_SECOND / SAMPLE_RATE;
+ position = model.convertDeltaTimeToPosition(NANOS_PER_SECOND + (kNanosPerBurst / 2));
+ ASSERT_EQ(SAMPLE_RATE + (HW_FRAMES_PER_BURST / 2), position);
+
+ int64_t time = model.convertDeltaPositionToTime(SAMPLE_RATE);
+ ASSERT_EQ(NANOS_PER_SECOND, time);
+
+ // Compare position in frames to the equivalent time.
+ time = model.convertDeltaPositionToTime(SAMPLE_RATE + (HW_FRAMES_PER_BURST / 2));
+ ASSERT_EQ(NANOS_PER_SECOND + (kNanosPerBurst / 2), time);
+}
+
+// start() should force the internal markers
+TEST_F(ClockModelTestFixture, clock_start) {
+ const int64_t startTime = 100000;
+ model.start(startTime);
+
+ int64_t position = model.convertTimeToPosition(startTime);
+ EXPECT_EQ(0, position);
+
+ int64_t time = model.convertPositionToTime(position);
+ EXPECT_EQ(startTime, time);
+
+ time = startTime + (500 * NANOS_PER_MICROSECOND);
+ position = model.convertTimeToPosition(time);
+ EXPECT_EQ(0, position);
+}
+
+// timestamps moves the window if outside the bounds
+// TODO test nudging the window
+TEST_F(ClockModelTestFixture, clock_timestamp) {
+ const int64_t startTime = 100000000;
+ model.start(startTime);
+
+ const int64_t position = HW_FRAMES_PER_BURST; // hardware
+ int64_t markerTime = startTime + NANOS_PER_MILLISECOND + (200 * NANOS_PER_MICROSECOND);
+
+ // Should set marker.
+ model.processTimestamp(position, markerTime);
+ EXPECT_EQ(position, model.convertTimeToPosition(markerTime));
+
+ // convertTimeToPosition rounds down
+ EXPECT_EQ(position, model.convertTimeToPosition(markerTime + (73 * NANOS_PER_MICROSECOND)));
+
+ // convertPositionToTime rounds up
+ EXPECT_EQ(markerTime + NANOS_PER_BURST, model.convertPositionToTime(position + 17));
+}
diff --git a/media/libaudioclient/AudioRecord.cpp b/media/libaudioclient/AudioRecord.cpp
index 34c5428..038c854 100644
--- a/media/libaudioclient/AudioRecord.cpp
+++ b/media/libaudioclient/AudioRecord.cpp
@@ -1300,10 +1300,7 @@
mNewPosition = position + mUpdatePeriod;
status_t result = createRecord_l(position, mOpPackageName);
- if (result != NO_ERROR) {
- ALOGW("%s(%d): createRecord_l failed, do not retry", __func__, mId);
- retries = 0;
- } else {
+ if (result == NO_ERROR) {
if (mActive) {
// callback thread or sync event hasn't changed
// FIXME this fails if we have a new AudioFlinger instance
@@ -1316,13 +1313,15 @@
if (result != NO_ERROR) {
ALOGW("%s(%d): failed status %d, retries %d", __func__, mId, result, retries);
if (--retries > 0) {
+ // leave time for an eventual race condition to clear before retrying
+ usleep(500000);
goto retry;
}
- }
-
- if (result != NO_ERROR) {
- ALOGW("%s(%d): failed status %d", __func__, mId, result);
- mActive = false;
+ // if no retries left, set invalid bit to force restoring at next occasion
+ // and avoid inconsistent active state on client and server sides
+ if (mCblk != nullptr) {
+ android_atomic_or(CBLK_INVALID, &mCblk->mFlags);
+ }
}
return result;
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index e77abc6..c86d4ce 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -2308,10 +2308,7 @@
// If a new IAudioTrack cannot be created, the previous (dead) instance will be left intact.
status_t result = createTrack_l();
- if (result != NO_ERROR) {
- ALOGW("%s(%d): createTrack_l failed, do not retry", __func__, mId);
- retries = 0;
- } else {
+ if (result == NO_ERROR) {
// take the frames that will be lost by track recreation into account in saved position
// For streaming tracks, this is the amount we obtained from the user/client
// (not the number actually consumed at the server - those are already lost).
@@ -2358,12 +2355,16 @@
if (result != NO_ERROR) {
ALOGW("%s(%d): failed status %d, retries %d", __func__, mId, result, retries);
if (--retries > 0) {
+ // leave time for an eventual race condition to clear before retrying
+ usleep(500000);
goto retry;
}
- mState = STATE_STOPPED;
- mReleased = 0;
+ // if no retries left, set invalid bit to force restoring at next occasion
+ // and avoid inconsistent active state on client and server sides
+ if (mCblk != nullptr) {
+ android_atomic_or(CBLK_INVALID, &mCblk->mFlags);
+ }
}
-
return result;
}
diff --git a/media/libmedia/NdkWrapper.cpp b/media/libmedia/NdkWrapper.cpp
index 7d67262..9e09c7e 100644
--- a/media/libmedia/NdkWrapper.cpp
+++ b/media/libmedia/NdkWrapper.cpp
@@ -1244,37 +1244,15 @@
return new AMediaCodecCryptoInfoWrapper(AMediaExtractor_getSampleCryptoInfo(mAMediaExtractor));
}
-ssize_t AMediaDataSourceWrapper::AMediaDataSourceWrapper_getSize(void *userdata) {
- DataSource *source = static_cast<DataSource *>(userdata);
- off64_t size = -1;
- source->getSize(&size);
- return size;
-}
-
-ssize_t AMediaDataSourceWrapper::AMediaDataSourceWrapper_readAt(void *userdata, off64_t offset, void * buf, size_t size) {
- DataSource *source = static_cast<DataSource *>(userdata);
- return source->readAt(offset, buf, size);
-}
-
-void AMediaDataSourceWrapper::AMediaDataSourceWrapper_close(void *userdata) {
- DataSource *source = static_cast<DataSource *>(userdata);
- source->close();
-}
-
-AMediaDataSourceWrapper::AMediaDataSourceWrapper(const sp<DataSource> &dataSource)
- : mDataSource(dataSource),
- mAMediaDataSource(AMediaDataSource_new()) {
- ALOGV("setDataSource (source: %p)", dataSource.get());
- AMediaDataSource_setUserdata(mAMediaDataSource, dataSource.get());
- AMediaDataSource_setReadAt(mAMediaDataSource, AMediaDataSourceWrapper_readAt);
- AMediaDataSource_setGetSize(mAMediaDataSource, AMediaDataSourceWrapper_getSize);
- AMediaDataSource_setClose(mAMediaDataSource, AMediaDataSourceWrapper_close);
+AMediaDataSourceWrapper::AMediaDataSourceWrapper(AMediaDataSource *aDataSource)
+ : mAMediaDataSource(aDataSource) {
}
AMediaDataSourceWrapper::~AMediaDataSourceWrapper() {
if (mAMediaDataSource == NULL) {
return;
}
+ AMediaDataSource_close(mAMediaDataSource);
AMediaDataSource_delete(mAMediaDataSource);
mAMediaDataSource = NULL;
}
@@ -1283,4 +1261,8 @@
return mAMediaDataSource;
}
+void AMediaDataSourceWrapper::close() {
+ AMediaDataSource_close(mAMediaDataSource);
+}
+
} // namespace android
diff --git a/media/libmedia/include/media/NdkWrapper.h b/media/libmedia/include/media/NdkWrapper.h
index 191665a..b3b0688 100644
--- a/media/libmedia/include/media/NdkWrapper.h
+++ b/media/libmedia/include/media/NdkWrapper.h
@@ -278,6 +278,30 @@
DISALLOW_EVIL_CONSTRUCTORS(AMediaCodecWrapper);
};
+struct AMediaDataSourceWrapper : public RefBase {
+
+ AMediaDataSourceWrapper(AMediaDataSource*);
+ AMediaDataSourceWrapper(int fd, int64_t offset, int64_t length);
+
+ AMediaDataSource *getAMediaDataSource();
+ int getFd() { return mFd; }
+ int64_t getOffset() { return mOffset; }
+ int64_t getLength() { return mLength; }
+
+ void close();
+
+protected:
+ virtual ~AMediaDataSourceWrapper();
+
+private:
+ AMediaDataSource *mAMediaDataSource;
+ int mFd;
+ int64_t mOffset;
+ int64_t mLength;
+
+ DISALLOW_EVIL_CONSTRUCTORS(AMediaDataSourceWrapper);
+};
+
struct AMediaExtractorWrapper : public RefBase {
AMediaExtractorWrapper(AMediaExtractor *aMediaExtractor);
@@ -337,31 +361,6 @@
DISALLOW_EVIL_CONSTRUCTORS(AMediaExtractorWrapper);
};
-struct AMediaDataSourceWrapper : public RefBase {
-
- static status_t translate_error(media_status_t err);
-
- static ssize_t AMediaDataSourceWrapper_getSize(void *userdata);
-
- static ssize_t AMediaDataSourceWrapper_readAt(void *userdata, off64_t offset, void * buf, size_t size);
-
- static void AMediaDataSourceWrapper_close(void *userdata);
-
- AMediaDataSourceWrapper(const sp<DataSource> &dataSource);
-
- AMediaDataSource *getAMediaDataSource();
-
-protected:
- virtual ~AMediaDataSourceWrapper();
-
-private:
- sp<DataSource> mDataSource;
-
- AMediaDataSource *mAMediaDataSource;
-
- DISALLOW_EVIL_CONSTRUCTORS(AMediaDataSourceWrapper);
-};
-
} // namespace android
#endif // NDK_WRAPPER_H_
diff --git a/media/libmediaplayer2/Android.bp b/media/libmediaplayer2/Android.bp
index a26cc81..75d1df0 100644
--- a/media/libmediaplayer2/Android.bp
+++ b/media/libmediaplayer2/Android.bp
@@ -28,6 +28,7 @@
"libcrypto",
"libmediametrics",
"libmediandk",
+ "libmediandk_utils",
"libmediautils",
"libmemunreachable",
"libnativewindow",
diff --git a/media/libmediaplayer2/mediaplayer2.cpp b/media/libmediaplayer2/mediaplayer2.cpp
index 74ccf56..3b155c5 100644
--- a/media/libmediaplayer2/mediaplayer2.cpp
+++ b/media/libmediaplayer2/mediaplayer2.cpp
@@ -403,6 +403,15 @@
if (dsd == NULL) {
return BAD_VALUE;
}
+ // Microsecond is used in NuPlayer2.
+ if (dsd->mStartPositionMs > INT64_MAX / 1000) {
+ dsd->mStartPositionMs = INT64_MAX / 1000;
+ ALOGW("setDataSource, start poistion clamped to %lld ms", (long long)dsd->mStartPositionMs);
+ }
+ if (dsd->mEndPositionMs > INT64_MAX / 1000) {
+ dsd->mEndPositionMs = INT64_MAX / 1000;
+ ALOGW("setDataSource, end poistion clamped to %lld ms", (long long)dsd->mStartPositionMs);
+ }
ALOGV("setDataSource type(%d), srcId(%lld)", dsd->mType, (long long)dsd->mId);
sp<MediaPlayer2Interface> oldPlayer;
diff --git a/media/libmediaplayer2/nuplayer2/Android.bp b/media/libmediaplayer2/nuplayer2/Android.bp
index 26da491..c3c94b6 100644
--- a/media/libmediaplayer2/nuplayer2/Android.bp
+++ b/media/libmediaplayer2/nuplayer2/Android.bp
@@ -28,6 +28,7 @@
"frameworks/av/media/libstagefright/mpeg2ts",
"frameworks/av/media/libstagefright/rtsp",
"frameworks/av/media/libstagefright/timedtext",
+ "frameworks/av/media/ndk",
],
cflags: [
@@ -49,6 +50,7 @@
"libgui",
"libmedia",
"libmediandk",
+ "libmediandk_utils",
"libpowermanager",
],
diff --git a/media/libmediaplayer2/nuplayer2/GenericSource2.cpp b/media/libmediaplayer2/nuplayer2/GenericSource2.cpp
index 4ce1a88..6056ad9 100644
--- a/media/libmediaplayer2/nuplayer2/GenericSource2.cpp
+++ b/media/libmediaplayer2/nuplayer2/GenericSource2.cpp
@@ -21,29 +21,20 @@
#include "NuPlayer2Drm.h"
#include "AnotherPacketSource.h"
-#include <binder/IServiceManager.h>
#include <cutils/properties.h>
#include <media/DataSource.h>
#include <media/MediaBufferHolder.h>
-#include <media/IMediaExtractorService.h>
-#include <media/IMediaSource.h>
-#include <media/MediaHTTPService.h>
-#include <media/MediaSource.h>
#include <media/NdkWrapper.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/ClearDataSourceFactory.h>
-#include <media/stagefright/InterfaceUtils.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaClock.h>
#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaExtractorFactory.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/NdkUtils.h>
#include <media/stagefright/Utils.h>
-#include "../../libstagefright/include/NuCachedSource2.h"
-#include "../../libstagefright/include/HTTPBase.h"
+#include "NdkMediaDataSourceCallbacksPriv.h"
namespace android {
@@ -88,9 +79,6 @@
void NuPlayer2::GenericSource2::resetDataSource() {
ALOGV("resetDataSource");
- mHTTPService.clear();
- mHttpSource.clear();
- mDisconnected = false;
mUri.clear();
mUriHeaders.clear();
if (mFd >= 0) {
@@ -109,7 +97,6 @@
}
status_t NuPlayer2::GenericSource2::setDataSource(
- const sp<MediaHTTPService> &httpService,
const char *url,
const KeyedVector<String8, String8> *headers) {
Mutex::Autolock _l(mLock);
@@ -117,7 +104,6 @@
resetDataSource();
- mHTTPService = httpService;
mUri = url;
if (headers) {
@@ -150,7 +136,8 @@
ALOGV("setDataSource (source: %p)", source.get());
resetDataSource();
- mDataSource = source;
+ AMediaDataSource *aSource = convertDataSourceToAMediaDataSource(source);
+ mDataSourceWrapper = new AMediaDataSourceWrapper(aSource);
return OK;
}
@@ -161,24 +148,21 @@
status_t NuPlayer2::GenericSource2::initFromDataSource() {
mExtractor = new AMediaExtractorWrapper(AMediaExtractor_new());
- CHECK(mDataSource != NULL || mFd != -1);
- sp<DataSource> dataSource = mDataSource;
+ CHECK(mFd >=0 || mDataSourceWrapper != NULL);
+ sp<AMediaDataSourceWrapper> aSourceWrapper = mDataSourceWrapper;
const int fd = mFd;
- const int64_t offset = mOffset;
- const int64_t length = mLength;
mLock.unlock();
// This might take long time if data source is not reliable.
status_t err;
- if (dataSource != nullptr) {
- mDataSourceWrapper = new AMediaDataSourceWrapper(dataSource);
- err = mExtractor->setDataSource(mDataSourceWrapper->getAMediaDataSource());
+ if (aSourceWrapper != NULL) {
+ err = mExtractor->setDataSource(aSourceWrapper->getAMediaDataSource());
} else {
- err = mExtractor->setDataSource(fd, offset, length);
+ err = mExtractor->setDataSource(fd, mOffset, mLength);
}
if (err != OK) {
- ALOGE("initFromDataSource, failed to create data source!");
+ ALOGE("initFromDataSource, failed to set extractor data source!");
mLock.lock();
return UNKNOWN_ERROR;
}
@@ -190,10 +174,8 @@
return UNKNOWN_ERROR;
}
- mLock.lock();
- mFd = -1;
- mDataSource = dataSource;
mFileMeta = convertMediaFormatWrapperToMetaData(mExtractor->getFormat());
+ mLock.lock();
if (mFileMeta != NULL) {
int64_t duration;
if (mFileMeta->findInt64(kKeyDuration, &duration)) {
@@ -214,11 +196,7 @@
}
sp<AMediaExtractorWrapper> trackExtractor = new AMediaExtractorWrapper(AMediaExtractor_new());
- if (mDataSourceWrapper != nullptr) {
- err = trackExtractor->setDataSource(mDataSourceWrapper->getAMediaDataSource());
- } else {
- err = trackExtractor->setDataSource(fd, offset, length);
- }
+ trackExtractor->setDataSource(mDataSourceWrapper->getAMediaDataSource());
const char *mime;
sp<MetaData> meta = convertMediaFormatWrapperToMetaData(trackFormat);
@@ -329,13 +307,13 @@
mLooper->unregisterHandler(id());
mLooper->stop();
}
- if (mDataSource != NULL) {
- mDataSource->close();
+ if (mDataSourceWrapper != NULL) {
+ mDataSourceWrapper->close();
}
resetDataSource();
}
-void NuPlayer2::GenericSource2::prepareAsync() {
+void NuPlayer2::GenericSource2::prepareAsync(int64_t startTimeUs) {
Mutex::Autolock _l(mLock);
ALOGV("prepareAsync: (looper: %d)", (mLooper != NULL));
@@ -350,59 +328,45 @@
}
sp<AMessage> msg = new AMessage(kWhatPrepareAsync, this);
+ msg->setInt64("startTimeUs", startTimeUs);
+
msg->post();
}
-void NuPlayer2::GenericSource2::onPrepareAsync() {
- ALOGV("onPrepareAsync: mDataSource: %d", (mDataSource != NULL));
+void NuPlayer2::GenericSource2::onPrepareAsync(int64_t startTimeUs) {
+ ALOGV("onPrepareAsync: mFd %d mUri %s mDataSourceWrapper: %p",
+ mFd, mUri.c_str(), mDataSourceWrapper.get());
- // delayed data source creation
- if (mDataSource == NULL) {
- // set to false first, if the extractor
- // comes back as secure, set it to true then.
- mIsSecure = false;
-
- if (!mUri.empty()) {
- const char* uri = mUri.c_str();
- String8 contentType;
-
- if (!strncasecmp("http://", uri, 7) || !strncasecmp("https://", uri, 8)) {
- mHttpSource = ClearDataSourceFactory::CreateMediaHTTP(mHTTPService);
- if (mHttpSource == NULL) {
- ALOGE("Failed to create http source!");
- notifyPreparedAndCleanup(UNKNOWN_ERROR);
- return;
- }
- }
-
- mLock.unlock();
- // This might take long time if connection has some issue.
- sp<DataSource> dataSource = ClearDataSourceFactory::CreateFromURI(
- mHTTPService, uri, &mUriHeaders, &contentType,
- static_cast<HTTPBase *>(mHttpSource.get()));
- mLock.lock();
- if (!mDisconnected) {
- mDataSource = dataSource;
- }
+ if (!mUri.empty()) {
+ const char* uri = mUri.c_str();
+ size_t numheaders = mUriHeaders.size();
+ const char **key_values = numheaders ? new const char *[numheaders * 2] : NULL;
+ for (size_t i = 0; i < numheaders; ++i) {
+ key_values[i * 2] = mUriHeaders.keyAt(i).c_str();
+ key_values[i * 2 + 1] = mUriHeaders.valueAt(i).c_str();
}
-
- if (mFd == -1 && mDataSource == NULL) {
- ALOGE("Failed to create data source!");
- notifyPreparedAndCleanup(UNKNOWN_ERROR);
- return;
- }
+ mLock.unlock();
+ AMediaDataSource *aSource = AMediaDataSource_newUri(uri, numheaders, key_values);
+ mLock.lock();
+ mDataSourceWrapper = aSource ? new AMediaDataSourceWrapper(aSource) : NULL;
+ delete[] key_values;
+ // For cached streaming cases, we need to wait for enough
+ // buffering before reporting prepared.
+ mIsStreaming = !strncasecmp("http://", uri, 7) || !strncasecmp("https://", uri, 8);
}
- if (mDataSource != nullptr && mDataSource->flags() & DataSource::kIsCachingDataSource) {
- mCachedSource = static_cast<NuCachedSource2 *>(mDataSource.get());
+ if (mDisconnected || (mFd < 0 && mDataSourceWrapper == NULL)) {
+ ALOGE("mDisconnected(%d) or Failed to create data source!", mDisconnected);
+ notifyPreparedAndCleanup(UNKNOWN_ERROR);
+ return;
}
- // For cached streaming cases, we need to wait for enough
- // buffering before reporting prepared.
- mIsStreaming = (mCachedSource != NULL);
-
// init extractor from data source
status_t err = initFromDataSource();
+ if (mFd >= 0) {
+ close(mFd);
+ mFd = -1;
+ }
if (err != OK) {
ALOGE("Failed to init from data source!");
@@ -429,6 +393,7 @@
FLAG_CAN_SEEK_FORWARD |
FLAG_CAN_SEEK);
+ doSeek(startTimeUs, MediaPlayer2SeekMode::SEEK_CLOSEST);
finishPrepareAsync();
ALOGV("onPrepareAsync: Done");
@@ -438,8 +403,8 @@
ALOGV("finishPrepareAsync");
if (mIsStreaming) {
- mCachedSource->resumeFetchingIfNecessary();
mPreparing = true;
+ ++mPollBufferingGeneration;
schedulePollBuffering();
} else {
notifyPrepared();
@@ -456,9 +421,7 @@
void NuPlayer2::GenericSource2::notifyPreparedAndCleanup(status_t err) {
if (err != OK) {
- mDataSource.clear();
- mCachedSource.clear();
- mHttpSource.clear();
+ mDataSourceWrapper.clear();
mBitrate = -1;
mPrevBufferPercentage = -1;
@@ -498,53 +461,27 @@
}
void NuPlayer2::GenericSource2::disconnect() {
- sp<DataSource> dataSource, httpSource;
{
Mutex::Autolock _l(mLock);
- dataSource = mDataSource;
- httpSource = mHttpSource;
mDisconnected = true;
}
-
- if (dataSource != NULL) {
- // disconnect data source
- if (dataSource->flags() & DataSource::kIsCachingDataSource) {
- static_cast<NuCachedSource2 *>(dataSource.get())->disconnect();
- }
- } else if (httpSource != NULL) {
- static_cast<HTTPBase *>(httpSource.get())->disconnect();
+ if (mDataSourceWrapper != NULL) {
+ mDataSourceWrapper->close();
}
-
- mDataSourceWrapper = NULL;
-
}
status_t NuPlayer2::GenericSource2::feedMoreTSData() {
return OK;
}
-void NuPlayer2::GenericSource2::sendCacheStats() {
- int32_t kbps = 0;
- status_t err = UNKNOWN_ERROR;
-
- if (mCachedSource != NULL) {
- err = mCachedSource->getEstimatedBandwidthKbps(&kbps);
- }
-
- if (err == OK) {
- sp<AMessage> notify = dupNotify();
- notify->setInt32("what", kWhatCacheStats);
- notify->setInt32("bandwidth", kbps);
- notify->post();
- }
-}
-
void NuPlayer2::GenericSource2::onMessageReceived(const sp<AMessage> &msg) {
Mutex::Autolock _l(mLock);
switch (msg->what()) {
case kWhatPrepareAsync:
{
- onPrepareAsync();
+ int64_t startTimeUs;
+ CHECK(msg->findInt64("startTimeUs", &startTimeUs));
+ onPrepareAsync(startTimeUs);
break;
}
case kWhatFetchSubtitleData:
@@ -834,8 +771,6 @@
}
if (track->mPackets->getAvailableBufferCount(&finalResult) < 2
&& !mSentPauseOnBuffering && !mPreparing) {
- mCachedSource->resumeFetchingIfNecessary();
- sendCacheStats();
mSentPauseOnBuffering = true;
sp<AMessage> notify = dupNotify();
notify->setInt32("what", kWhatPauseOnBufferingStart);
@@ -1391,7 +1326,6 @@
notifyPrepared();
mPreparing = false;
} else {
- sendCacheStats();
mSentPauseOnBuffering = false;
sp<AMessage> notify = dupNotify();
notify->setInt32("what", kWhatResumeOnBufferingEnd);
@@ -1443,47 +1377,31 @@
}
void NuPlayer2::GenericSource2::schedulePollBuffering() {
- sp<AMessage> msg = new AMessage(kWhatPollBuffering, this);
- msg->setInt32("generation", mPollBufferingGeneration);
- // Enquires buffering status every second.
- msg->post(1000000ll);
+ if (mIsStreaming) {
+ sp<AMessage> msg = new AMessage(kWhatPollBuffering, this);
+ msg->setInt32("generation", mPollBufferingGeneration);
+ // Enquires buffering status every second.
+ msg->post(1000000ll);
+ }
}
void NuPlayer2::GenericSource2::onPollBuffering() {
- status_t finalStatus = UNKNOWN_ERROR;
int64_t cachedDurationUs = -1ll;
- ssize_t cachedDataRemaining = -1;
- if (mCachedSource != NULL) {
- cachedDataRemaining = mCachedSource->approxDataRemaining(&finalStatus);
-
- if (finalStatus == OK) {
- off64_t size;
- int64_t bitrate = 0ll;
- if (mDurationUs > 0 && mCachedSource->getSize(&size) == OK) {
- // |bitrate| uses bits/second unit, while size is number of bytes.
- bitrate = size * 8000000ll / mDurationUs;
- } else if (mBitrate > 0) {
- bitrate = mBitrate;
- }
- if (bitrate > 0) {
- cachedDurationUs = cachedDataRemaining * 8000000ll / bitrate;
- }
- }
+ sp<AMediaExtractorWrapper> extractor;
+ if (mVideoTrack.mExtractor != NULL) {
+ extractor = mVideoTrack.mExtractor;
+ } else if (mAudioTrack.mExtractor != NULL) {
+ extractor = mAudioTrack.mExtractor;
}
- if (finalStatus != OK) {
- ALOGV("onPollBuffering: EOS (finalStatus = %d)", finalStatus);
-
- if (finalStatus == ERROR_END_OF_STREAM) {
- notifyBufferingUpdate(100);
- }
-
- return;
+ if (extractor != NULL) {
+ cachedDurationUs = extractor->getCachedDuration();
}
if (cachedDurationUs >= 0ll) {
- if (mDurationUs > 0ll) {
+ ssize_t sampleSize = extractor->getSampleSize();
+ if (sampleSize >= 0ll) {
int64_t cachedPosUs = getLastReadPosition() + cachedDurationUs;
int percentage = 100.0 * cachedPosUs / mDurationUs;
if (percentage > 100) {
@@ -1491,9 +1409,11 @@
}
notifyBufferingUpdate(percentage);
+ ALOGV("onPollBuffering: cachedDurationUs %.1f sec", cachedDurationUs / 1000000.0f);
+ } else {
+ notifyBufferingUpdate(100);
+ ALOGV("onPollBuffering: EOS");
}
-
- ALOGV("onPollBuffering: cachedDurationUs %.1f sec", cachedDurationUs / 1000000.0f);
}
schedulePollBuffering();
diff --git a/media/libmediaplayer2/nuplayer2/GenericSource2.h b/media/libmediaplayer2/nuplayer2/GenericSource2.h
index 9bc5182..ade1aa3 100644
--- a/media/libmediaplayer2/nuplayer2/GenericSource2.h
+++ b/media/libmediaplayer2/nuplayer2/GenericSource2.h
@@ -37,11 +37,9 @@
class DataSource;
class IDataSource;
class IMediaSource;
-struct MediaHTTPService;
struct MediaSource;
class MediaBuffer;
struct MediaClock;
-struct NuCachedSource2;
struct NuPlayer2::GenericSource2 : public NuPlayer2::Source,
public MediaBufferObserver // Modular DRM
@@ -50,7 +48,6 @@
const sp<MediaClock> &mediaClock);
status_t setDataSource(
- const sp<MediaHTTPService> &httpService,
const char *url,
const KeyedVector<String8, String8> *headers);
@@ -62,7 +59,7 @@
BufferingSettings* buffering /* nonnull */) override;
virtual status_t setBufferingSettings(const BufferingSettings& buffering) override;
- virtual void prepareAsync();
+ virtual void prepareAsync(int64_t startTimeUs);
virtual void start();
virtual void stop();
@@ -151,7 +148,6 @@
bool mIsStreaming;
uid_t mUID;
const sp<MediaClock> mMediaClock;
- sp<MediaHTTPService> mHTTPService;
AString mUri;
KeyedVector<String8, String8> mUriHeaders;
int mFd;
@@ -159,9 +155,6 @@
int64_t mLength;
bool mDisconnected;
- sp<DataSource> mDataSource;
- sp<NuCachedSource2> mCachedSource;
- sp<DataSource> mHttpSource;
sp<MetaData> mFileMeta;
sp<AMediaDataSourceWrapper> mDataSourceWrapper;
sp<AMediaExtractorWrapper> mExtractor;
@@ -194,7 +187,7 @@
void onSeek(const sp<AMessage>& msg);
status_t doSeek(int64_t seekTimeUs, MediaPlayer2SeekMode mode);
- void onPrepareAsync();
+ void onPrepareAsync(int64_t startTimeUs);
void fetchTextData(
uint32_t what, media_track_type type,
@@ -232,8 +225,6 @@
void onPollBuffering();
void notifyBufferingUpdate(int32_t percentage);
- void sendCacheStats();
-
sp<AMessage> getFormat_l(bool audio);
sp<MetaData> getFormatMeta_l(bool audio);
int32_t getDataGeneration(media_track_type type) const;
diff --git a/media/libmediaplayer2/nuplayer2/HTTPLiveSource2.cpp b/media/libmediaplayer2/nuplayer2/HTTPLiveSource2.cpp
index a61cacd..175be53 100644
--- a/media/libmediaplayer2/nuplayer2/HTTPLiveSource2.cpp
+++ b/media/libmediaplayer2/nuplayer2/HTTPLiveSource2.cpp
@@ -99,7 +99,8 @@
return OK;
}
-void NuPlayer2::HTTPLiveSource2::prepareAsync() {
+// TODO: fetch data starting from |startTimeUs|
+void NuPlayer2::HTTPLiveSource2::prepareAsync(int64_t /* startTimeUs */) {
if (mLiveLooper == NULL) {
mLiveLooper = new ALooper;
mLiveLooper->setName("http live");
diff --git a/media/libmediaplayer2/nuplayer2/HTTPLiveSource2.h b/media/libmediaplayer2/nuplayer2/HTTPLiveSource2.h
index 97d3653..8fc71e2 100644
--- a/media/libmediaplayer2/nuplayer2/HTTPLiveSource2.h
+++ b/media/libmediaplayer2/nuplayer2/HTTPLiveSource2.h
@@ -38,7 +38,7 @@
BufferingSettings* buffering /* nonnull */) override;
virtual status_t setBufferingSettings(const BufferingSettings& buffering) override;
- virtual void prepareAsync();
+ virtual void prepareAsync(int64_t startTimeUs);
virtual void start();
virtual status_t dequeueAccessUnit(bool audio, sp<ABuffer> *accessUnit);
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
index 5bd1674..018324e 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
@@ -212,7 +212,6 @@
: mPID(pid),
mUID(uid),
mMediaClock(mediaClock),
- mSourceFlags(0),
mOffloadAudio(false),
mAudioDecoderGeneration(0),
mVideoDecoderGeneration(0),
@@ -240,8 +239,7 @@
mPaused(false),
mPausedByClient(true),
mPausedForBuffering(false),
- mIsDrmProtected(false),
- mDataSourceType(DATA_SOURCE_TYPE_NONE) {
+ mIsDrmProtected(false) {
CHECK(mediaClock != NULL);
clearFlushComplete();
}
@@ -309,7 +307,7 @@
sp<GenericSource2> genericSource =
new GenericSource2(notify, mUID, mMediaClock);
- err = genericSource->setDataSource(httpService, url, headers);
+ err = genericSource->setDataSource(url, headers);
if (err == OK) {
*source = genericSource;
@@ -393,11 +391,13 @@
// Now, source != NULL.
*/
- mDataSourceType = dataSourceType;
+ mCurrentSourceInfo.mDataSourceType = dataSourceType;
sp<AMessage> msg = new AMessage(kWhatSetDataSource, this);
msg->setObject("source", source);
msg->setInt64("srcId", dsd->mId);
+ msg->setInt64("startTimeUs", dsd->mStartPositionMs * 1000);
+ msg->setInt64("endTimeUs", dsd->mEndPositionMs * 1000);
msg->post();
}
@@ -415,11 +415,13 @@
// Now, source != NULL.
*/
- mNextDataSourceType = dataSourceType;
+ mNextSourceInfo.mDataSourceType = dataSourceType;
sp<AMessage> msg = new AMessage(kWhatPrepareNextDataSource, this);
msg->setObject("source", source);
msg->setInt64("srcId", dsd->mId);
+ msg->setInt64("startTimeUs", dsd->mStartPositionMs * 1000);
+ msg->setInt64("endTimeUs", dsd->mEndPositionMs * 1000);
msg->post();
}
@@ -554,7 +556,7 @@
sp<Source> source;
{
Mutex::Autolock autoLock(mSourceLock);
- source = mSource;
+ source = mCurrentSourceInfo.mSource;
}
if (source != NULL) {
@@ -640,15 +642,17 @@
{
ALOGV("kWhatSetDataSource");
- CHECK(mSource == NULL);
+ CHECK(mCurrentSourceInfo.mSource == NULL);
status_t err = OK;
sp<RefBase> obj;
CHECK(msg->findObject("source", &obj));
if (obj != NULL) {
Mutex::Autolock autoLock(mSourceLock);
- CHECK(msg->findInt64("srcId", &mSrcId));
- mSource = static_cast<Source *>(obj.get());
+ CHECK(msg->findInt64("srcId", &mCurrentSourceInfo.mSrcId));
+ CHECK(msg->findInt64("startTimeUs", &mCurrentSourceInfo.mStartTimeUs));
+ CHECK(msg->findInt64("endTimeUs", &mCurrentSourceInfo.mEndTimeUs));
+ mCurrentSourceInfo.mSource = static_cast<Source *>(obj.get());
} else {
err = UNKNOWN_ERROR;
ALOGE("kWhatSetDataSource, source should not be NULL");
@@ -657,7 +661,7 @@
CHECK(mDriver != NULL);
sp<NuPlayer2Driver> driver = mDriver.promote();
if (driver != NULL) {
- driver->notifySetDataSourceCompleted(mSrcId, err);
+ driver->notifySetDataSourceCompleted(mCurrentSourceInfo.mSrcId, err);
}
break;
}
@@ -671,9 +675,11 @@
CHECK(msg->findObject("source", &obj));
if (obj != NULL) {
Mutex::Autolock autoLock(mSourceLock);
- CHECK(msg->findInt64("srcId", &mNextSrcId));
- mNextSource = static_cast<Source *>(obj.get());
- mNextSource->prepareAsync();
+ CHECK(msg->findInt64("srcId", &mNextSourceInfo.mSrcId));
+ CHECK(msg->findInt64("startTimeUs", &mNextSourceInfo.mStartTimeUs));
+ CHECK(msg->findInt64("endTimeUs", &mNextSourceInfo.mEndTimeUs));
+ mNextSourceInfo.mSource = static_cast<Source *>(obj.get());
+ mNextSourceInfo.mSource->prepareAsync(mNextSourceInfo.mStartTimeUs);
} else {
err = UNKNOWN_ERROR;
}
@@ -686,7 +692,7 @@
ALOGV("kWhatPlayNextDataSource");
int64_t srcId;
CHECK(msg->findInt64("srcId", &srcId));
- if (srcId != mNextSrcId) {
+ if (srcId != mNextSourceInfo.mSrcId) {
notifyListener(srcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, 0);
return;
}
@@ -715,8 +721,8 @@
ALOGV("kWhatGetBufferingSettings");
BufferingSettings buffering;
status_t err = OK;
- if (mSource != NULL) {
- err = mSource->getBufferingSettings(&buffering);
+ if (mCurrentSourceInfo.mSource != NULL) {
+ err = mCurrentSourceInfo.mSource->getBufferingSettings(&buffering);
} else {
err = INVALID_OPERATION;
}
@@ -738,8 +744,8 @@
BufferingSettings buffering;
readFromAMessage(msg, &buffering);
status_t err = OK;
- if (mSource != NULL) {
- err = mSource->setBufferingSettings(buffering);
+ if (mCurrentSourceInfo.mSource != NULL) {
+ err = mCurrentSourceInfo.mSource->setBufferingSettings(buffering);
} else {
err = INVALID_OPERATION;
}
@@ -753,7 +759,7 @@
{
ALOGV("onMessageReceived kWhatPrepare");
- mSource->prepareAsync();
+ mCurrentSourceInfo.mSource->prepareAsync(mCurrentSourceInfo.mStartTimeUs);
break;
}
@@ -766,8 +772,8 @@
CHECK(msg->findPointer("reply", (void**)&reply));
size_t inbandTracks = 0;
- if (mSource != NULL) {
- inbandTracks = mSource->getTrackCount();
+ if (mCurrentSourceInfo.mSource != NULL) {
+ inbandTracks = mCurrentSourceInfo.mSource->getTrackCount();
}
size_t ccTracks = 0;
@@ -780,7 +786,7 @@
// write inband tracks
for (size_t i = 0; i < inbandTracks; ++i) {
- writeTrackInfo(reply, mSource->getTrackInfo(i));
+ writeTrackInfo(reply, mCurrentSourceInfo.mSource->getTrackInfo(i));
}
// write CC track
@@ -796,13 +802,13 @@
case kWhatGetSelectedTrack:
{
status_t err = INVALID_OPERATION;
- if (mSource != NULL) {
+ if (mCurrentSourceInfo.mSource != NULL) {
err = OK;
int32_t type32;
CHECK(msg->findInt32("type", (int32_t*)&type32));
media_track_type type = (media_track_type)type32;
- ssize_t selectedTrack = mSource->getSelectedTrack(type);
+ ssize_t selectedTrack = mCurrentSourceInfo.mSource->getSelectedTrack(type);
PlayerMessage* reply;
CHECK(msg->findPointer("reply", (void**)&reply));
@@ -833,8 +839,8 @@
status_t err = INVALID_OPERATION;
size_t inbandTracks = 0;
- if (mSource != NULL) {
- inbandTracks = mSource->getTrackCount();
+ if (mCurrentSourceInfo.mSource != NULL) {
+ inbandTracks = mCurrentSourceInfo.mSource->getTrackCount();
}
size_t ccTracks = 0;
if (mCCDecoder != NULL) {
@@ -842,11 +848,11 @@
}
if (trackIndex < inbandTracks) {
- err = mSource->selectTrack(trackIndex, select, timeUs);
+ err = mCurrentSourceInfo.mSource->selectTrack(trackIndex, select, timeUs);
if (!select && err == OK) {
int32_t type;
- sp<AMessage> info = mSource->getTrackInfo(trackIndex);
+ sp<AMessage> info = mCurrentSourceInfo.mSource->getTrackInfo(trackIndex);
if (info != NULL
&& info->findInt32("type", &type)
&& type == MEDIA_TRACK_TYPE_TIMEDTEXT) {
@@ -879,10 +885,10 @@
}
int64_t durationUs;
- if (mDriver != NULL && mSource->getDuration(&durationUs) == OK) {
+ if (mDriver != NULL && mCurrentSourceInfo.mSource->getDuration(&durationUs) == OK) {
sp<NuPlayer2Driver> driver = mDriver.promote();
if (driver != NULL) {
- driver->notifyDuration(mSrcId, durationUs);
+ driver->notifyDuration(mCurrentSourceInfo.mSrcId, durationUs);
}
}
@@ -899,13 +905,15 @@
ALOGD("onSetVideoSurface(%p, %s video decoder)",
(nww == NULL ? NULL : nww->getANativeWindow()),
- (mSource != NULL && mStarted && mSource->getFormat(false /* audio */) != NULL
+ (mCurrentSourceInfo.mSource != NULL && mStarted
+ && mCurrentSourceInfo.mSource->getFormat(false /* audio */) != NULL
&& mVideoDecoder != NULL) ? "have" : "no");
- // Need to check mStarted before calling mSource->getFormat because NuPlayer2 might
- // be in preparing state and it could take long time.
- // When mStarted is true, mSource must have been set.
- if (mSource == NULL || !mStarted || mSource->getFormat(false /* audio */) == NULL
+ // Need to check mStarted before calling mCurrentSourceInfo.mSource->getFormat
+ // because NuPlayer2 might be in preparing state and it could take long time.
+ // When mStarted is true, mCurrentSourceInfo.mSource must have been set.
+ if (mCurrentSourceInfo.mSource == NULL || !mStarted
+ || mCurrentSourceInfo.mSource->getFormat(false /* audio */) == NULL
// NOTE: mVideoDecoder's mNativeWindow is always non-null
|| (mVideoDecoder != NULL && mVideoDecoder->setVideoSurface(nww) == OK)) {
performSetSurface(nww);
@@ -972,7 +980,7 @@
onStart(true /* play */);
}
mPausedByClient = false;
- notifyListener(mSrcId, MEDIA2_STARTED, 0, 0);
+ notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_STARTED, 0, 0);
break;
}
@@ -1130,21 +1138,22 @@
&& (mAudioDecoder != NULL || mVideoDecoder != NULL)) {
// This is the first time we've found anything playable.
- if (mSourceFlags & Source::FLAG_DYNAMIC_DURATION) {
+ if (mCurrentSourceInfo.mSourceFlags & Source::FLAG_DYNAMIC_DURATION) {
schedulePollDuration();
}
}
status_t err;
- if ((err = mSource->feedMoreTSData()) != OK) {
+ if ((err = mCurrentSourceInfo.mSource->feedMoreTSData()) != OK) {
if (mAudioDecoder == NULL && mVideoDecoder == NULL) {
// We're not currently decoding anything (no audio or
// video tracks found) and we just ran out of input data.
if (err == ERROR_END_OF_STREAM) {
- notifyListener(mSrcId, MEDIA2_PLAYBACK_COMPLETE, 0, 0);
+ notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_PLAYBACK_COMPLETE, 0, 0);
} else {
- notifyListener(mSrcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
+ notifyListener(
+ mCurrentSourceInfo.mSrcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
}
}
break;
@@ -1226,10 +1235,10 @@
CHECK(msg->findMessage("format", &format));
sp<AMessage> inputFormat =
- mSource->getFormat(false /* audio */);
+ mCurrentSourceInfo.mSource->getFormat(false /* audio */);
setVideoScalingMode(mVideoScalingMode);
- updateVideoSize(mSrcId, inputFormat, format);
+ updateVideoSize(mCurrentSourceInfo.mSrcId, inputFormat, format);
} else if (what == DecoderBase::kWhatShutdownCompleted) {
ALOGV("%s shutdown completed", audio ? "audio" : "video");
if (audio) {
@@ -1296,28 +1305,39 @@
finishFlushIfPossible(); // Should not occur.
break; // Finish anyways.
}
- if (mSource != nullptr) {
+ if (mCurrentSourceInfo.mSource != nullptr) {
if (audio) {
- if (mVideoDecoderError || mSource->getFormat(false /* audio */) == NULL
- || mNativeWindow == NULL || mNativeWindow->getANativeWindow() == NULL
+ if (mVideoDecoderError
+ || mCurrentSourceInfo.mSource->getFormat(false /* audio */) == NULL
+ || mNativeWindow == NULL
+ || mNativeWindow->getANativeWindow() == NULL
|| mVideoDecoder == NULL) {
// When both audio and video have error, or this stream has only audio
// which has error, notify client of error.
- notifyListener(mSrcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
+ notifyListener(
+ mCurrentSourceInfo.mSrcId, MEDIA2_ERROR,
+ MEDIA2_ERROR_UNKNOWN, err);
} else {
// Only audio track has error. Video track could be still good to play.
- notifyListener(mSrcId, MEDIA2_INFO, MEDIA2_INFO_PLAY_AUDIO_ERROR, err);
+ notifyListener(
+ mCurrentSourceInfo.mSrcId, MEDIA2_INFO,
+ MEDIA2_INFO_PLAY_AUDIO_ERROR, err);
}
mAudioDecoderError = true;
} else {
- if (mAudioDecoderError || mSource->getFormat(true /* audio */) == NULL
+ if (mAudioDecoderError
+ || mCurrentSourceInfo.mSource->getFormat(true /* audio */) == NULL
|| mAudioSink == NULL || mAudioDecoder == NULL) {
// When both audio and video have error, or this stream has only video
// which has error, notify client of error.
- notifyListener(mSrcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
+ notifyListener(
+ mCurrentSourceInfo.mSrcId, MEDIA2_ERROR,
+ MEDIA2_ERROR_UNKNOWN, err);
} else {
// Only video track has error. Audio track could be still good to play.
- notifyListener(mSrcId, MEDIA2_INFO, MEDIA2_INFO_PLAY_VIDEO_ERROR, err);
+ notifyListener(
+ mCurrentSourceInfo.mSrcId, MEDIA2_INFO,
+ MEDIA2_INFO_PLAY_VIDEO_ERROR, err);
}
mVideoDecoderError = true;
}
@@ -1367,12 +1387,13 @@
audio ? "audio" : "video", finalResult);
notifyListener(
- mSrcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, finalResult);
+ mCurrentSourceInfo.mSrcId, MEDIA2_ERROR,
+ MEDIA2_ERROR_UNKNOWN, finalResult);
}
if ((mAudioEOS || mAudioDecoder == NULL)
&& (mVideoEOS || mVideoDecoder == NULL)) {
- notifyListener(mSrcId, MEDIA2_PLAYBACK_COMPLETE, 0, 0);
+ notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_PLAYBACK_COMPLETE, 0, 0);
}
} else if (what == Renderer::kWhatFlushComplete) {
int32_t audio;
@@ -1393,10 +1414,11 @@
handleFlushComplete(audio, false /* isDecoder */);
finishFlushIfPossible();
} else if (what == Renderer::kWhatVideoRenderingStart) {
- notifyListener(mSrcId, MEDIA2_INFO, MEDIA2_INFO_VIDEO_RENDERING_START, 0);
+ notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_INFO,
+ MEDIA2_INFO_VIDEO_RENDERING_START, 0);
} else if (what == Renderer::kWhatMediaRenderingStart) {
ALOGV("media rendering started");
- notifyListener(mSrcId, MEDIA2_STARTED, 0, 0);
+ notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_STARTED, 0, 0);
} else if (what == Renderer::kWhatAudioTearDown) {
int32_t reason;
CHECK(msg->findInt32("reason", &reason));
@@ -1449,7 +1471,7 @@
int64_t timerUs;
CHECK(msg->findInt64("timerUs", &timerUs));
- notifyListener(mSrcId, MEDIA2_NOTIFY_TIME, timerUs, 0);
+ notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_NOTIFY_TIME, timerUs, 0);
break;
}
@@ -1468,20 +1490,20 @@
if (!mStarted) {
if (!mSourceStarted) {
mSourceStarted = true;
- mSource->start();
+ mCurrentSourceInfo.mSource->start();
}
if (seekTimeUs > 0) {
performSeek(seekTimeUs, (MediaPlayer2SeekMode)mode);
}
if (needNotify) {
- notifyDriverSeekComplete(mSrcId);
+ notifyDriverSeekComplete(mCurrentSourceInfo.mSrcId);
}
break;
}
// seeks can take a while, so we essentially paused
- notifyListener(mSrcId, MEDIA2_PAUSED, 0, 0);
+ notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_PAUSED, 0, 0);
mDeferredActions.push_back(
new FlushDecoderAction(FLUSH_CMD_FLUSH /* audio */,
@@ -1506,7 +1528,7 @@
onStart(false /* play */);
}
onPause();
- notifyListener(mSrcId, MEDIA2_PAUSED, 0, 0);
+ notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_PAUSED, 0, 0);
mPausedByClient = true;
break;
}
@@ -1559,8 +1581,8 @@
return;
}
mPaused = false;
- if (mSource != NULL) {
- mSource->resume();
+ if (mCurrentSourceInfo.mSource != NULL) {
+ mCurrentSourceInfo.mSource->resume();
} else {
ALOGW("resume called when source is gone or not set");
}
@@ -1583,7 +1605,7 @@
if (!mSourceStarted) {
mSourceStarted = true;
- mSource->start();
+ mCurrentSourceInfo.mSource->start();
}
mOffloadAudio = false;
@@ -1594,22 +1616,23 @@
uint32_t flags = 0;
- if (mSource->isRealTime()) {
+ if (mCurrentSourceInfo.mSource->isRealTime()) {
flags |= Renderer::FLAG_REAL_TIME;
}
- bool hasAudio = (mSource->getFormat(true /* audio */) != NULL);
- bool hasVideo = (mSource->getFormat(false /* audio */) != NULL);
+ bool hasAudio = (mCurrentSourceInfo.mSource->getFormat(true /* audio */) != NULL);
+ bool hasVideo = (mCurrentSourceInfo.mSource->getFormat(false /* audio */) != NULL);
if (!hasAudio && !hasVideo) {
ALOGE("no metadata for either audio or video source");
- mSource->stop();
+ mCurrentSourceInfo.mSource->stop();
mSourceStarted = false;
- notifyListener(mSrcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, ERROR_MALFORMED);
+ notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_ERROR,
+ MEDIA2_ERROR_UNKNOWN, ERROR_MALFORMED);
return;
}
ALOGV_IF(!hasAudio, "no metadata for audio source"); // video only stream
- sp<MetaData> audioMeta = mSource->getFormatMeta(true /* audio */);
+ sp<MetaData> audioMeta = mCurrentSourceInfo.mSource->getFormatMeta(true /* audio */);
audio_stream_type_t streamType = AUDIO_STREAM_MUSIC;
if (mAudioSink != NULL) {
@@ -1617,7 +1640,7 @@
}
mOffloadAudio =
- canOffloadStream(audioMeta, hasVideo, mSource->isStreaming(), streamType)
+ canOffloadStream(audioMeta, hasVideo, mCurrentSourceInfo.mSource->isStreaming(), streamType)
&& (mPlaybackSettings.mSpeed == 1.f && mPlaybackSettings.mPitch == 1.f);
// Modular DRM: Disabling audio offload if the source is protected
@@ -1641,9 +1664,9 @@
status_t err = mRenderer->setPlaybackSettings(mPlaybackSettings);
if (err != OK) {
- mSource->stop();
+ mCurrentSourceInfo.mSource->stop();
mSourceStarted = false;
- notifyListener(mSrcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
+ notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
return;
}
@@ -1665,7 +1688,7 @@
}
startPlaybackTimer("onstart");
- notifyListener(mSrcId, MEDIA2_INFO, MEDIA2_INFO_DATA_SOURCE_START, 0);
+ notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_INFO, MEDIA2_INFO_DATA_SOURCE_START, 0);
postScanSources();
}
@@ -1691,7 +1714,7 @@
ALOGV("stopPlaybackTimer() log %20" PRId64 "", played);
if (played > 0) {
- driver->notifyMorePlayingTimeUs(mSrcId, (played+500)/1000);
+ driver->notifyMorePlayingTimeUs(mCurrentSourceInfo.mSrcId, (played+500)/1000);
}
}
mLastStartedPlayingTimeNs = 0;
@@ -1709,7 +1732,8 @@
void NuPlayer2::stopRebufferingTimer(bool exitingPlayback) {
Mutex::Autolock autoLock(mPlayingTimeLock);
- ALOGV("stopRebufferTimer() time %20" PRId64 " (exiting %d)", mLastStartedRebufferingTimeNs, exitingPlayback);
+ ALOGV("stopRebufferTimer() time %20" PRId64 " (exiting %d)",
+ mLastStartedRebufferingTimeNs, exitingPlayback);
if (mLastStartedRebufferingTimeNs != 0) {
sp<NuPlayer2Driver> driver = mDriver.promote();
@@ -1719,9 +1743,10 @@
ALOGV("stopRebufferingTimer() log %20" PRId64 "", rebuffered);
if (rebuffered > 0) {
- driver->notifyMoreRebufferingTimeUs(mSrcId, (rebuffered+500)/1000);
+ driver->notifyMoreRebufferingTimeUs(
+ mCurrentSourceInfo.mSrcId, (rebuffered+500)/1000);
if (exitingPlayback) {
- driver->notifyRebufferingWhenExit(mSrcId, true);
+ driver->notifyRebufferingWhenExit(mCurrentSourceInfo.mSrcId, true);
}
}
}
@@ -1737,8 +1762,8 @@
return;
}
mPaused = true;
- if (mSource != NULL) {
- mSource->pause();
+ if (mCurrentSourceInfo.mSource != NULL) {
+ mCurrentSourceInfo.mSource->pause();
} else {
ALOGW("pause called when source is gone or not set");
}
@@ -1828,7 +1853,7 @@
status_t err = mRenderer->openAudioSink(
format, true /* offloadOnly */, hasVideo,
- AUDIO_OUTPUT_FLAG_NONE, &mOffloadAudio, mSource->isStreaming());
+ AUDIO_OUTPUT_FLAG_NONE, &mOffloadAudio, mCurrentSourceInfo.mSource->isStreaming());
if (err != OK) {
// Any failure we turn off mOffloadAudio.
mOffloadAudio = false;
@@ -1881,7 +1906,7 @@
}
void NuPlayer2::determineAudioModeChange(const sp<AMessage> &audioFormat) {
- if (mSource == NULL || mAudioSink == NULL) {
+ if (mCurrentSourceInfo.mSource == NULL || mAudioSink == NULL) {
return;
}
@@ -1891,12 +1916,12 @@
return;
}
- sp<MetaData> audioMeta = mSource->getFormatMeta(true /* audio */);
- sp<AMessage> videoFormat = mSource->getFormat(false /* audio */);
+ sp<MetaData> audioMeta = mCurrentSourceInfo.mSource->getFormatMeta(true /* audio */);
+ sp<AMessage> videoFormat = mCurrentSourceInfo.mSource->getFormat(false /* audio */);
audio_stream_type_t streamType = mAudioSink->getAudioStreamType();
const bool hasVideo = (videoFormat != NULL);
bool canOffload = canOffloadStream(
- audioMeta, hasVideo, mSource->isStreaming(), streamType)
+ audioMeta, hasVideo, mCurrentSourceInfo.mSource->isStreaming(), streamType)
&& (mPlaybackSettings.mSpeed == 1.f && mPlaybackSettings.mPitch == 1.f);
// Modular DRM: Disabling audio offload if the source is protected
@@ -1927,7 +1952,7 @@
return OK;
}
- sp<AMessage> format = mSource->getFormat(audio);
+ sp<AMessage> format = mCurrentSourceInfo.mSource->getFormat(audio);
if (format == NULL) {
return UNKNOWN_ERROR;
@@ -1949,11 +1974,11 @@
mCCDecoder = new CCDecoder(ccNotify);
}
- if (mSourceFlags & Source::FLAG_SECURE) {
+ if (mCurrentSourceInfo.mSourceFlags & Source::FLAG_SECURE) {
format->setInt32("secure", true);
}
- if (mSourceFlags & Source::FLAG_PROTECTED) {
+ if (mCurrentSourceInfo.mSourceFlags & Source::FLAG_PROTECTED) {
format->setInt32("protected", true);
}
@@ -1972,16 +1997,16 @@
determineAudioModeChange(format);
}
if (mOffloadAudio) {
- mSource->setOffloadAudio(true /* offload */);
+ mCurrentSourceInfo.mSource->setOffloadAudio(true /* offload */);
- const bool hasVideo = (mSource->getFormat(false /*audio */) != NULL);
+ const bool hasVideo = (mCurrentSourceInfo.mSource->getFormat(false /*audio */) != NULL);
format->setInt32("has-video", hasVideo);
- *decoder = new DecoderPassThrough(notify, mSource, mRenderer);
+ *decoder = new DecoderPassThrough(notify, mCurrentSourceInfo.mSource, mRenderer);
ALOGV("instantiateDecoder audio DecoderPassThrough hasVideo: %d", hasVideo);
} else {
- mSource->setOffloadAudio(false /* offload */);
+ mCurrentSourceInfo.mSource->setOffloadAudio(false /* offload */);
- *decoder = new Decoder(notify, mSource, mPID, mUID, mRenderer);
+ *decoder = new Decoder(notify, mCurrentSourceInfo.mSource, mPID, mUID, mRenderer);
ALOGV("instantiateDecoder audio Decoder");
}
mAudioDecoderError = false;
@@ -1991,7 +2016,8 @@
notify->setInt32("generation", mVideoDecoderGeneration);
*decoder = new Decoder(
- notify, mSource, mPID, mUID, mRenderer, mNativeWindow, mCCDecoder);
+ notify, mCurrentSourceInfo.mSource, mPID, mUID, mRenderer, mNativeWindow,
+ mCCDecoder);
mVideoDecoderError = false;
// enable FRC if high-quality AV sync is requested, even if not
@@ -2008,8 +2034,8 @@
// Modular DRM
if (mIsDrmProtected) {
format->setObject("crypto", mCrypto);
- ALOGV("instantiateDecoder: mCrypto: %p isSecure: %d", mCrypto.get(),
- (mSourceFlags & Source::FLAG_SECURE) != 0);
+ ALOGV("instantiateDecoder: mCrypto: %p isSecure: %d",
+ mCrypto.get(), (mCurrentSourceInfo.mSourceFlags & Source::FLAG_SECURE) != 0);
}
(*decoder)->configure(format);
@@ -2277,11 +2303,11 @@
}
sp<MetaData> NuPlayer2::getFileMeta() {
- return mSource->getFileFormatMeta();
+ return mCurrentSourceInfo.mSource->getFileFormatMeta();
}
float NuPlayer2::getFrameRate() {
- sp<MetaData> meta = mSource->getFormatMeta(false /* audio */);
+ sp<MetaData> meta = mCurrentSourceInfo.mSource->getFormatMeta(false /* audio */);
if (meta == NULL) {
return 0;
}
@@ -2339,16 +2365,16 @@
ALOGV("performSeek seekTimeUs=%lld us (%.2f secs), mode=%d",
(long long)seekTimeUs, seekTimeUs / 1E6, mode);
- if (mSource == NULL) {
+ if (mCurrentSourceInfo.mSource == NULL) {
// This happens when reset occurs right before the loop mode
// asynchronously seeks to the start of the stream.
LOG_ALWAYS_FATAL_IF(mAudioDecoder != NULL || mVideoDecoder != NULL,
- "mSource is NULL and decoders not NULL audio(%p) video(%p)",
+ "mCurrentSourceInfo.mSource is NULL and decoders not NULL audio(%p) video(%p)",
mAudioDecoder.get(), mVideoDecoder.get());
return;
}
mPreviousSeekTimeUs = seekTimeUs;
- mSource->seekTo(seekTimeUs, mode);
+ mCurrentSourceInfo.mSource->seekTo(seekTimeUs, mode);
++mTimedTextGeneration;
// everything's flushed, continue playback.
@@ -2395,17 +2421,17 @@
mRenderer.clear();
++mRendererGeneration;
- if (mSource != NULL) {
- mSource->stop();
+ if (mCurrentSourceInfo.mSource != NULL) {
+ mCurrentSourceInfo.mSource->stop();
Mutex::Autolock autoLock(mSourceLock);
- mSource.clear();
+ mCurrentSourceInfo.mSource.clear();
}
if (mDriver != NULL) {
sp<NuPlayer2Driver> driver = mDriver.promote();
if (driver != NULL) {
- driver->notifyResetComplete(mSrcId);
+ driver->notifyResetComplete(mCurrentSourceInfo.mSrcId);
}
}
@@ -2440,25 +2466,26 @@
++mRendererGeneration;
- if (mSource != NULL) {
- mSource->stop();
+ if (mCurrentSourceInfo.mSource != NULL) {
+ mCurrentSourceInfo.mSource->stop();
}
long previousSrcId;
{
Mutex::Autolock autoLock(mSourceLock);
- mSource = mNextSource;
- mNextSource = NULL;
- previousSrcId = mSrcId;
- mSrcId = mNextSrcId;
- ++mNextSrcId; // to distinguish the two sources.
+ mCurrentSourceInfo.mSource = mNextSourceInfo.mSource;
+ mNextSourceInfo.mSource = NULL;
+ previousSrcId = mCurrentSourceInfo.mSrcId;
+ mCurrentSourceInfo.mSrcId = mNextSourceInfo.mSrcId;
+ ++mNextSourceInfo.mSrcId; // to distinguish the two sources.
}
if (mDriver != NULL) {
sp<NuPlayer2Driver> driver = mDriver.promote();
if (driver != NULL) {
notifyListener(previousSrcId, MEDIA2_INFO, MEDIA2_INFO_DATA_SOURCE_END, 0);
- notifyListener(mSrcId, MEDIA2_INFO, MEDIA2_INFO_DATA_SOURCE_START, 0);
+ notifyListener(
+ mCurrentSourceInfo.mSrcId, MEDIA2_INFO, MEDIA2_INFO_DATA_SOURCE_START, 0);
}
}
@@ -2482,7 +2509,7 @@
onStart(true /* play */);
mPausedByClient = false;
- notifyListener(mSrcId, MEDIA2_STARTED, 0, 0);
+ notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_STARTED, 0, 0);
}
void NuPlayer2::performScanSources() {
@@ -2508,7 +2535,7 @@
if (mDriver != NULL) {
sp<NuPlayer2Driver> driver = mDriver.promote();
if (driver != NULL) {
- driver->notifySetSurfaceComplete(mSrcId);
+ driver->notifySetSurfaceComplete(mCurrentSourceInfo.mSrcId);
}
}
}
@@ -2540,7 +2567,7 @@
void NuPlayer2::finishResume() {
if (mResumePending) {
mResumePending = false;
- notifyDriverSeekComplete(mSrcId);
+ notifyDriverSeekComplete(mCurrentSourceInfo.mSrcId);
}
}
@@ -2562,8 +2589,9 @@
switch (what) {
case Source::kWhatPrepared:
{
- ALOGV("NuPlayer2::onSourceNotify Source::kWhatPrepared source: %p", mSource.get());
- if (mSource == NULL) {
+ ALOGV("NuPlayer2::onSourceNotify Source::kWhatPrepared source: %p",
+ mCurrentSourceInfo.mSource.get());
+ if (mCurrentSourceInfo.mSource == NULL) {
// This is a stale notification from a source that was
// asynchronously preparing when the client called reset().
// We handled the reset, the source is gone.
@@ -2588,7 +2616,7 @@
// notify duration first, so that it's definitely set when
// the app received the "prepare complete" callback.
int64_t durationUs;
- if (mSource->getDuration(&durationUs) == OK) {
+ if (mCurrentSourceInfo.mSource->getDuration(&durationUs) == OK) {
driver->notifyDuration(srcId, durationUs);
}
driver->notifyPrepareCompleted(srcId, err);
@@ -2640,16 +2668,21 @@
driver->notifyFlagsChanged(srcId, flags);
}
- if ((mSourceFlags & Source::FLAG_DYNAMIC_DURATION)
- && (!(flags & Source::FLAG_DYNAMIC_DURATION))) {
- cancelPollDuration();
- } else if (!(mSourceFlags & Source::FLAG_DYNAMIC_DURATION)
- && (flags & Source::FLAG_DYNAMIC_DURATION)
- && (mAudioDecoder != NULL || mVideoDecoder != NULL)) {
- schedulePollDuration();
- }
+ if (srcId == mCurrentSourceInfo.mSrcId) {
+ if ((mCurrentSourceInfo.mSourceFlags & Source::FLAG_DYNAMIC_DURATION)
+ && (!(flags & Source::FLAG_DYNAMIC_DURATION))) {
+ cancelPollDuration();
+ } else if (!(mCurrentSourceInfo.mSourceFlags & Source::FLAG_DYNAMIC_DURATION)
+ && (flags & Source::FLAG_DYNAMIC_DURATION)
+ && (mAudioDecoder != NULL || mVideoDecoder != NULL)) {
+ schedulePollDuration();
+ }
- mSourceFlags = flags;
+ mCurrentSourceInfo.mSourceFlags = flags;
+ } else if (srcId == mNextSourceInfo.mSrcId) {
+ // TODO: handle duration polling for next source.
+ mNextSourceInfo.mSourceFlags = flags;
+ }
break;
}
@@ -2800,8 +2833,8 @@
CHECK(msg->findBuffer("buffer", &buffer));
size_t inbandTracks = 0;
- if (mSource != NULL) {
- inbandTracks = mSource->getTrackCount();
+ if (mCurrentSourceInfo.mSource != NULL) {
+ inbandTracks = mCurrentSourceInfo.mSource->getTrackCount();
}
sendSubtitleData(buffer, inbandTracks);
@@ -2810,7 +2843,7 @@
case NuPlayer2::CCDecoder::kWhatTrackAdded:
{
- notifyListener(mSrcId, MEDIA2_INFO, MEDIA2_INFO_METADATA_UPDATE, 0);
+ notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_INFO, MEDIA2_INFO_METADATA_UPDATE, 0);
break;
}
@@ -2835,7 +2868,7 @@
playerMsg.add_values()->set_int64_value(durationUs);
playerMsg.add_values()->set_bytes_value(buffer->data(), buffer->size());
- notifyListener(mSrcId, MEDIA2_SUBTITLE_DATA, 0, 0, &playerMsg);
+ notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_SUBTITLE_DATA, 0, 0, &playerMsg);
}
void NuPlayer2::sendTimedMetaData(const sp<ABuffer> &buffer) {
@@ -2846,7 +2879,7 @@
playerMsg.add_values()->set_int64_value(timeUs);
playerMsg.add_values()->set_bytes_value(buffer->data(), buffer->size());
- notifyListener(mSrcId, MEDIA2_META_DATA, 0, 0, &playerMsg);
+ notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_META_DATA, 0, 0, &playerMsg);
}
void NuPlayer2::sendTimedTextData(const sp<ABuffer> &buffer) {
@@ -2876,14 +2909,14 @@
}
if (playerMsg.values_size() > 0) {
- notifyListener(mSrcId, MEDIA2_TIMED_TEXT, 0, 0, &playerMsg);
+ notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_TIMED_TEXT, 0, 0, &playerMsg);
} else { // send an empty timed text
- notifyListener(mSrcId, MEDIA2_TIMED_TEXT, 0, 0);
+ notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_TIMED_TEXT, 0, 0);
}
}
const char *NuPlayer2::getDataSourceType() {
- switch (mDataSourceType) {
+ switch (mCurrentSourceInfo.mDataSourceType) {
case DATA_SOURCE_TYPE_HTTP_LIVE:
return "HTTPLive";
@@ -2957,7 +2990,7 @@
ALOGD("onPrepareDrm ");
status_t status = INVALID_OPERATION;
- if (mSource == NULL) {
+ if (mCurrentSourceInfo.mSource == NULL) {
ALOGE("onPrepareDrm: No source. onPrepareDrm failed with %d.", status);
return status;
}
@@ -2970,12 +3003,12 @@
status = OK;
sp<AMediaCryptoWrapper> crypto = NULL;
- status = mSource->prepareDrm(uuid, *drmSessionId, &crypto);
+ status = mCurrentSourceInfo.mSource->prepareDrm(uuid, *drmSessionId, &crypto);
if (crypto == NULL) {
- ALOGE("onPrepareDrm: mSource->prepareDrm failed. status: %d", status);
+ ALOGE("onPrepareDrm: mCurrentSourceInfo.mSource->prepareDrm failed. status: %d", status);
return status;
}
- ALOGV("onPrepareDrm: mSource->prepareDrm succeeded");
+ ALOGV("onPrepareDrm: mCurrentSourceInfo.mSource->prepareDrm succeeded");
if (mCrypto != NULL) {
ALOGE("onPrepareDrm: Unexpected. Already having mCrypto: %p", mCrypto.get());
@@ -3004,8 +3037,8 @@
status_t status;
if (mCrypto != NULL) {
// notifying the source first before removing crypto from codec
- if (mSource != NULL) {
- mSource->releaseDrm();
+ if (mCurrentSourceInfo.mSource != NULL) {
+ mCurrentSourceInfo.mSource->releaseDrm();
}
status=OK;
@@ -3090,4 +3123,12 @@
TRESPASS();
}
+NuPlayer2::SourceInfo::SourceInfo()
+ : mDataSourceType(DATA_SOURCE_TYPE_NONE),
+ mSrcId(0),
+ mSourceFlags(0),
+ mStartTimeUs(0),
+ mEndTimeUs(INT64_MAX) {
+}
+
} // namespace android
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2.h b/media/libmediaplayer2/nuplayer2/NuPlayer2.h
index e55cdbe..4db0cbf 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2.h
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2.h
@@ -156,17 +156,33 @@
kWhatReleaseDrm = 'rDrm',
};
+ typedef enum {
+ DATA_SOURCE_TYPE_NONE,
+ DATA_SOURCE_TYPE_HTTP_LIVE,
+ DATA_SOURCE_TYPE_RTSP,
+ DATA_SOURCE_TYPE_GENERIC_URL,
+ DATA_SOURCE_TYPE_GENERIC_FD,
+ DATA_SOURCE_TYPE_MEDIA,
+ } DATA_SOURCE_TYPE;
+
+ struct SourceInfo {
+ SourceInfo();
+
+ sp<Source> mSource;
+ std::atomic<DATA_SOURCE_TYPE> mDataSourceType;
+ int64_t mSrcId;
+ uint32_t mSourceFlags;
+ int64_t mStartTimeUs;
+ int64_t mEndTimeUs;
+ };
+
wp<NuPlayer2Driver> mDriver;
pid_t mPID;
uid_t mUID;
const sp<MediaClock> mMediaClock;
Mutex mSourceLock; // guard |mSource|.
- sp<Source> mSource;
- int64_t mSrcId;
- uint32_t mSourceFlags;
- sp<Source> mNextSource;
- int64_t mNextSrcId;
- uint32_t mNextSourceFlags;
+ SourceInfo mCurrentSourceInfo;
+ SourceInfo mNextSourceInfo;
sp<ANativeWindowWrapper> mNativeWindow;
sp<MediaPlayer2Interface::AudioSink> mAudioSink;
sp<DecoderBase> mVideoDecoder;
@@ -252,18 +268,6 @@
sp<AMediaCryptoWrapper> mCrypto;
bool mIsDrmProtected;
- typedef enum {
- DATA_SOURCE_TYPE_NONE,
- DATA_SOURCE_TYPE_HTTP_LIVE,
- DATA_SOURCE_TYPE_RTSP,
- DATA_SOURCE_TYPE_GENERIC_URL,
- DATA_SOURCE_TYPE_GENERIC_FD,
- DATA_SOURCE_TYPE_MEDIA,
- } DATA_SOURCE_TYPE;
-
- std::atomic<DATA_SOURCE_TYPE> mDataSourceType;
- std::atomic<DATA_SOURCE_TYPE> mNextDataSourceType;
-
inline const sp<DecoderBase> &getDecoder(bool audio) {
return audio ? mAudioDecoder : mVideoDecoder;
}
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Source.h b/media/libmediaplayer2/nuplayer2/NuPlayer2Source.h
index 662235f..9298a99 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Source.h
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2Source.h
@@ -69,7 +69,7 @@
BufferingSettings* buffering /* nonnull */) = 0;
virtual status_t setBufferingSettings(const BufferingSettings& buffering) = 0;
- virtual void prepareAsync() = 0;
+ virtual void prepareAsync(int64_t startTimeUs) = 0;
virtual void start() = 0;
virtual void stop() {}
diff --git a/media/libmediaplayer2/nuplayer2/RTSPSource2.cpp b/media/libmediaplayer2/nuplayer2/RTSPSource2.cpp
index 1dfe383..53c66c0 100644
--- a/media/libmediaplayer2/nuplayer2/RTSPSource2.cpp
+++ b/media/libmediaplayer2/nuplayer2/RTSPSource2.cpp
@@ -96,7 +96,8 @@
return OK;
}
-void NuPlayer2::RTSPSource2::prepareAsync() {
+// TODO: fetch data starting from |startTimeUs|
+void NuPlayer2::RTSPSource2::prepareAsync(int64_t /* startTimeUs */) {
if (mIsSDP && mHTTPService == NULL) {
notifyPrepared(BAD_VALUE);
return;
diff --git a/media/libmediaplayer2/nuplayer2/RTSPSource2.h b/media/libmediaplayer2/nuplayer2/RTSPSource2.h
index 712c3e5..e5f1716 100644
--- a/media/libmediaplayer2/nuplayer2/RTSPSource2.h
+++ b/media/libmediaplayer2/nuplayer2/RTSPSource2.h
@@ -43,7 +43,7 @@
BufferingSettings* buffering /* nonnull */) override;
virtual status_t setBufferingSettings(const BufferingSettings& buffering) override;
- virtual void prepareAsync();
+ virtual void prepareAsync(int64_t startTimeUs);
virtual void start();
virtual void stop();
diff --git a/media/ndk/NdkMediaDataSource.cpp b/media/ndk/NdkMediaDataSource.cpp
index 43c89bb..3c10024 100644
--- a/media/ndk/NdkMediaDataSource.cpp
+++ b/media/ndk/NdkMediaDataSource.cpp
@@ -224,6 +224,11 @@
}
sp<DataSource> source = DataSourceFactory::CreateFromURI(service, uri, &headers);
+ if (source == NULL) {
+ ALOGE("AMediaDataSource_newUri source is null");
+ return NULL;
+ }
+ ALOGI("AMediaDataSource_newUri source %s flags %u", source->toString().c_str(), source->flags());
AMediaDataSource* aSource = convertDataSourceToAMediaDataSource(source);
aSource->mImpl = source;
aSource->mFlags = source->flags();
diff --git a/media/ndk/libmediandk.map.txt b/media/ndk/libmediandk.map.txt
index bf4802d..d3bdbae 100644
--- a/media/ndk/libmediandk.map.txt
+++ b/media/ndk/libmediandk.map.txt
@@ -166,6 +166,8 @@
AMediaDrm_setOnEventListener;
AMediaDrm_setPropertyByteArray;
AMediaDrm_setPropertyString;
+ AMediaDrm_setOnExpirationUpdateListener; # introduced=29
+ AMediaDrm_setOnKeysChangeListener; # introduced=29
AMediaDrm_sign;
AMediaDrm_verify;
AMediaExtractor_advance;
diff --git a/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp b/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
index f42cdd3..97f7fdc 100644
--- a/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
+++ b/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
@@ -551,9 +551,11 @@
return DONE;
}
- if (l.mParameters.isDeviceZslSupported) {
+ if ((l.mParameters.isDeviceZslSupported) && (l.mParameters.state != Parameters::RECORD) &&
+ (l.mParameters.state != Parameters::VIDEO_SNAPSHOT)) {
// If device ZSL is supported, drop all pending preview buffers to reduce the chance of
// rendering preview frames newer than the still frame.
+ // Additionally, preview must not get interrupted during video recording.
client->getCameraDevice()->dropStreamBuffers(true, client->getPreviewStreamId());
}