stagefright: Remove deprecated AwesomePlayer
Bug: 17108024
Change-Id: Ia721bdfa87b07612ad8e76cbdcda6de2b8ce2a74
diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk
index 4d1b587..81f2af3 100644
--- a/media/libmediaplayerservice/Android.mk
+++ b/media/libmediaplayerservice/Android.mk
@@ -18,7 +18,6 @@
MetadataRetrieverClient.cpp \
RemoteDisplay.cpp \
SharedLibrary.cpp \
- StagefrightPlayer.cpp \
StagefrightRecorder.cpp \
TestPlayerStub.cpp \
@@ -45,6 +44,7 @@
LOCAL_STATIC_LIBRARIES := \
libstagefright_nuplayer \
libstagefright_rtsp \
+ libstagefright_timedtext \
LOCAL_C_INCLUDES := \
$(TOP)/frameworks/av/media/libstagefright/include \
diff --git a/media/libmediaplayerservice/MediaPlayerFactory.cpp b/media/libmediaplayerservice/MediaPlayerFactory.cpp
index d5d12f7..605c710 100644
--- a/media/libmediaplayerservice/MediaPlayerFactory.cpp
+++ b/media/libmediaplayerservice/MediaPlayerFactory.cpp
@@ -31,7 +31,6 @@
#include "MediaPlayerFactory.h"
#include "TestPlayerStub.h"
-#include "StagefrightPlayer.h"
#include "nuplayer/NuPlayerDriver.h"
namespace android {
@@ -64,12 +63,6 @@
}
static player_type getDefaultPlayerType() {
- char value[PROPERTY_VALUE_MAX];
- if (property_get("media.stagefright.use-awesome", value, NULL)
- && (!strcmp("1", value) || !strcasecmp("true", value))) {
- return STAGEFRIGHT_PLAYER;
- }
-
return NU_PLAYER;
}
@@ -176,63 +169,6 @@
* *
*****************************************************************************/
-class StagefrightPlayerFactory :
- public MediaPlayerFactory::IFactory {
- public:
- virtual float scoreFactory(const sp<IMediaPlayer>& /*client*/,
- int fd,
- int64_t offset,
- int64_t length,
- float /*curScore*/) {
- if (legacyDrm()) {
- sp<DataSource> source = new FileSource(dup(fd), offset, length);
- String8 mimeType;
- float confidence;
- if (SniffWVM(source, &mimeType, &confidence, NULL /* format */)) {
- return 1.0;
- }
- }
-
- if (getDefaultPlayerType() == STAGEFRIGHT_PLAYER) {
- char buf[20];
- lseek(fd, offset, SEEK_SET);
- read(fd, buf, sizeof(buf));
- lseek(fd, offset, SEEK_SET);
-
- uint32_t ident = *((uint32_t*)buf);
-
- // Ogg vorbis?
- if (ident == 0x5367674f) // 'OggS'
- return 1.0;
- }
-
- return 0.0;
- }
-
- virtual float scoreFactory(const sp<IMediaPlayer>& /*client*/,
- const char* url,
- float /*curScore*/) {
- if (legacyDrm() && !strncasecmp("widevine://", url, 11)) {
- return 1.0;
- }
- return 0.0;
- }
-
- virtual sp<MediaPlayerBase> createPlayer(pid_t /* pid */) {
- ALOGV(" create StagefrightPlayer");
- return new StagefrightPlayer();
- }
- private:
- bool legacyDrm() {
- char value[PROPERTY_VALUE_MAX];
- if (property_get("persist.sys.media.legacy-drm", value, NULL)
- && (!strcmp("1", value) || !strcasecmp("true", value))) {
- return true;
- }
- return false;
- }
-};
-
class NuPlayerFactory : public MediaPlayerFactory::IFactory {
public:
virtual float scoreFactory(const sp<IMediaPlayer>& /*client*/,
@@ -310,7 +246,6 @@
if (sInitComplete)
return;
- registerFactory_l(new StagefrightPlayerFactory(), STAGEFRIGHT_PLAYER);
registerFactory_l(new NuPlayerFactory(), NU_PLAYER);
registerFactory_l(new TestPlayerFactory(), TEST_PLAYER);
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index dda0a57..c5f53cb 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -57,7 +57,6 @@
#include <media/MemoryLeakTrackUtil.h>
#include <media/stagefright/MediaCodecList.h>
#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/AudioPlayer.h>
#include <media/stagefright/Utils.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooperRoster.h>
@@ -74,7 +73,6 @@
#include "MediaPlayerFactory.h"
#include "TestPlayerStub.h"
-#include "StagefrightPlayer.h"
#include "nuplayer/NuPlayerDriver.h"
#include <OMX.h>
diff --git a/media/libmediaplayerservice/StagefrightPlayer.cpp b/media/libmediaplayerservice/StagefrightPlayer.cpp
deleted file mode 100644
index 8fc4b29..0000000
--- a/media/libmediaplayerservice/StagefrightPlayer.cpp
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- * Copyright (C) 2009 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.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "StagefrightPlayer"
-#include <utils/Log.h>
-
-#include "StagefrightPlayer.h"
-
-#include "AwesomePlayer.h"
-
-#include <media/Metadata.h>
-#include <media/stagefright/MediaExtractor.h>
-
-namespace android {
-
-StagefrightPlayer::StagefrightPlayer()
- : mPlayer(new AwesomePlayer) {
- ALOGV("StagefrightPlayer");
-
- mPlayer->setListener(this);
-}
-
-StagefrightPlayer::~StagefrightPlayer() {
- ALOGV("~StagefrightPlayer");
- reset();
-
- delete mPlayer;
- mPlayer = NULL;
-}
-
-status_t StagefrightPlayer::initCheck() {
- ALOGV("initCheck");
- return OK;
-}
-
-status_t StagefrightPlayer::setUID(uid_t uid) {
- mPlayer->setUID(uid);
-
- return OK;
-}
-
-status_t StagefrightPlayer::setDataSource(
- const sp<IMediaHTTPService> &httpService,
- const char *url,
- const KeyedVector<String8, String8> *headers) {
- return mPlayer->setDataSource(httpService, url, headers);
-}
-
-// Warning: The filedescriptor passed into this method will only be valid until
-// the method returns, if you want to keep it, dup it!
-status_t StagefrightPlayer::setDataSource(int fd, int64_t offset, int64_t length) {
- ALOGV("setDataSource(%d, %lld, %lld)", fd, offset, length);
- return mPlayer->setDataSource(fd, offset, length);
-}
-
-status_t StagefrightPlayer::setDataSource(const sp<IStreamSource> &source) {
- return mPlayer->setDataSource(source);
-}
-
-status_t StagefrightPlayer::setVideoSurfaceTexture(
- const sp<IGraphicBufferProducer> &bufferProducer) {
- ALOGV("setVideoSurfaceTexture");
-
- return mPlayer->setSurfaceTexture(bufferProducer);
-}
-
-status_t StagefrightPlayer::prepare() {
- return mPlayer->prepare();
-}
-
-status_t StagefrightPlayer::prepareAsync() {
- return mPlayer->prepareAsync();
-}
-
-status_t StagefrightPlayer::start() {
- ALOGV("start");
-
- return mPlayer->play();
-}
-
-status_t StagefrightPlayer::stop() {
- ALOGV("stop");
-
- return pause(); // what's the difference?
-}
-
-status_t StagefrightPlayer::pause() {
- ALOGV("pause");
-
- return mPlayer->pause();
-}
-
-bool StagefrightPlayer::isPlaying() {
- ALOGV("isPlaying");
- return mPlayer->isPlaying();
-}
-
-status_t StagefrightPlayer::seekTo(int msec) {
- ALOGV("seekTo %.2f secs", msec / 1E3);
-
- status_t err = mPlayer->seekTo((int64_t)msec * 1000);
-
- return err;
-}
-
-status_t StagefrightPlayer::getCurrentPosition(int *msec) {
- ALOGV("getCurrentPosition");
-
- int64_t positionUs;
- status_t err = mPlayer->getPosition(&positionUs);
-
- if (err != OK) {
- return err;
- }
-
- *msec = (positionUs + 500) / 1000;
-
- return OK;
-}
-
-status_t StagefrightPlayer::getDuration(int *msec) {
- ALOGV("getDuration");
-
- int64_t durationUs;
- status_t err = mPlayer->getDuration(&durationUs);
-
- if (err != OK) {
- *msec = 0;
- return OK;
- }
-
- *msec = (durationUs + 500) / 1000;
-
- return OK;
-}
-
-status_t StagefrightPlayer::reset() {
- ALOGV("reset");
-
- mPlayer->reset();
-
- return OK;
-}
-
-status_t StagefrightPlayer::setLooping(int loop) {
- ALOGV("setLooping");
-
- return mPlayer->setLooping(loop);
-}
-
-player_type StagefrightPlayer::playerType() {
- ALOGV("playerType");
- return STAGEFRIGHT_PLAYER;
-}
-
-status_t StagefrightPlayer::invoke(const Parcel &request, Parcel *reply) {
- ALOGV("invoke()");
- return mPlayer->invoke(request, reply);
-}
-
-void StagefrightPlayer::setAudioSink(const sp<AudioSink> &audioSink) {
- MediaPlayerInterface::setAudioSink(audioSink);
-
- mPlayer->setAudioSink(audioSink);
-}
-
-status_t StagefrightPlayer::setParameter(int key, const Parcel &request) {
- ALOGV("setParameter(key=%d)", key);
- return mPlayer->setParameter(key, request);
-}
-
-status_t StagefrightPlayer::getParameter(int key, Parcel *reply) {
- ALOGV("getParameter");
- return mPlayer->getParameter(key, reply);
-}
-
-status_t StagefrightPlayer::setPlaybackSettings(const AudioPlaybackRate &rate) {
- return mPlayer->setPlaybackSettings(rate);
-}
-
-status_t StagefrightPlayer::getPlaybackSettings(AudioPlaybackRate *rate /* nonnull */) {
- return mPlayer->getPlaybackSettings(rate);
-}
-
-status_t StagefrightPlayer::getMetadata(
- const media::Metadata::Filter& /* ids */, Parcel *records) {
- using media::Metadata;
-
- uint32_t flags = mPlayer->flags();
-
- Metadata metadata(records);
-
- metadata.appendBool(
- Metadata::kPauseAvailable,
- flags & MediaExtractor::CAN_PAUSE);
-
- metadata.appendBool(
- Metadata::kSeekBackwardAvailable,
- flags & MediaExtractor::CAN_SEEK_BACKWARD);
-
- metadata.appendBool(
- Metadata::kSeekForwardAvailable,
- flags & MediaExtractor::CAN_SEEK_FORWARD);
-
- metadata.appendBool(
- Metadata::kSeekAvailable,
- flags & MediaExtractor::CAN_SEEK);
-
- return OK;
-}
-
-status_t StagefrightPlayer::dump(int fd, const Vector<String16> &args) const {
- return mPlayer->dump(fd, args);
-}
-
-} // namespace android
diff --git a/media/libmediaplayerservice/StagefrightPlayer.h b/media/libmediaplayerservice/StagefrightPlayer.h
deleted file mode 100644
index 96013df..0000000
--- a/media/libmediaplayerservice/StagefrightPlayer.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
-**
-** Copyright 2009, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#ifndef ANDROID_STAGEFRIGHTPLAYER_H
-#define ANDROID_STAGEFRIGHTPLAYER_H
-
-#include <media/MediaPlayerInterface.h>
-
-namespace android {
-
-struct AwesomePlayer;
-
-class StagefrightPlayer : public MediaPlayerInterface {
-public:
- StagefrightPlayer();
- virtual ~StagefrightPlayer();
-
- virtual status_t initCheck();
-
- virtual status_t setUID(uid_t uid);
-
- virtual status_t setDataSource(
- const sp<IMediaHTTPService> &httpService,
- const char *url,
- const KeyedVector<String8, String8> *headers);
-
- virtual status_t setDataSource(int fd, int64_t offset, int64_t length);
-
- virtual status_t setDataSource(const sp<IStreamSource> &source);
-
- virtual status_t setVideoSurfaceTexture(
- const sp<IGraphicBufferProducer> &bufferProducer);
- virtual status_t prepare();
- virtual status_t prepareAsync();
- virtual status_t start();
- virtual status_t stop();
- virtual status_t pause();
- virtual bool isPlaying();
- virtual status_t seekTo(int msec);
- virtual status_t getCurrentPosition(int *msec);
- virtual status_t getDuration(int *msec);
- virtual status_t reset();
- virtual status_t setLooping(int loop);
- virtual player_type playerType();
- virtual status_t invoke(const Parcel &request, Parcel *reply);
- virtual void setAudioSink(const sp<AudioSink> &audioSink);
- virtual status_t setParameter(int key, const Parcel &request);
- virtual status_t getParameter(int key, Parcel *reply);
- virtual status_t setPlaybackSettings(const AudioPlaybackRate &rate);
- virtual status_t getPlaybackSettings(AudioPlaybackRate *rate /* nonnull */);
-
- virtual status_t getMetadata(
- const media::Metadata::Filter& ids, Parcel *records);
-
- virtual status_t dump(int fd, const Vector<String16> &args) const;
-
-private:
- AwesomePlayer *mPlayer;
-
- StagefrightPlayer(const StagefrightPlayer &);
- StagefrightPlayer &operator=(const StagefrightPlayer &);
-};
-
-} // namespace android
-
-#endif // ANDROID_STAGEFRIGHTPLAYER_H
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index cac34d0..f297256 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -10,7 +10,6 @@
AMRWriter.cpp \
AudioPlayer.cpp \
AudioSource.cpp \
- AwesomePlayer.cpp \
CallbackDataSource.cpp \
CameraSource.cpp \
CameraSourceTimeLapse.cpp \
@@ -60,7 +59,6 @@
SurfaceUtils.cpp \
ThrottledSource.cpp \
TimeSource.cpp \
- TimedEventQueue.cpp \
Utils.cpp \
VBRISeeker.cpp \
VideoFrameScheduler.cpp \
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
index c977958..9960702 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -33,14 +33,11 @@
#include <media/stagefright/MetaData.h>
#include <media/stagefright/Utils.h>
-#include "include/AwesomePlayer.h"
-
namespace android {
AudioPlayer::AudioPlayer(
const sp<MediaPlayerBase::AudioSink> &audioSink,
- uint32_t flags,
- AwesomePlayer *observer)
+ uint32_t flags)
: mInputBuffer(NULL),
mSampleRate(0),
mLatencyUs(0),
@@ -58,7 +55,6 @@
mFirstBufferResult(OK),
mFirstBuffer(NULL),
mAudioSink(audioSink),
- mObserver(observer),
mPinnedTimeUs(-1ll),
mPlaying(false),
mStartPosUs(0),
@@ -401,11 +397,6 @@
void AudioPlayer::notifyAudioEOS() {
ALOGV("AudioPlayer@0x%p notifyAudioEOS", this);
-
- if (mObserver != NULL) {
- mObserver->postAudioEOS(0);
- ALOGV("Notified observer of EOS!");
- }
}
status_t AudioPlayer::setPlaybackRate(const AudioPlaybackRate &rate) {
@@ -448,7 +439,6 @@
case MediaPlayerBase::AudioSink::CB_EVENT_TEAR_DOWN:
ALOGV("AudioSinkCallback: Tear down event");
- me->mObserver->postAudioTearDown();
break;
}
@@ -501,10 +491,6 @@
return 0;
}
- bool postSeekComplete = false;
- bool postEOS = false;
- int64_t postEOSDelayUs = 0;
-
size_t size_done = 0;
size_t size_remaining = size;
while (size_remaining > 0) {
@@ -532,9 +518,6 @@
}
mSeeking = false;
- if (mObserver) {
- postSeekComplete = true;
- }
}
}
@@ -567,42 +550,6 @@
mAudioTrack->stop();
}
} else {
- if (mObserver) {
- // We don't want to post EOS right away but only
- // after all frames have actually been played out.
-
- // These are the number of frames submitted to the
- // AudioTrack that you haven't heard yet.
- uint32_t numFramesPendingPlayout =
- getNumFramesPendingPlayout();
-
- // These are the number of frames we're going to
- // submit to the AudioTrack by returning from this
- // callback.
- uint32_t numAdditionalFrames = size_done / mFrameSize;
-
- numFramesPendingPlayout += numAdditionalFrames;
-
- int64_t timeToCompletionUs =
- (1000000ll * numFramesPendingPlayout) / mSampleRate;
-
- ALOGV("total number of frames played: %" PRId64 " (%lld us)",
- (mNumFramesPlayed + numAdditionalFrames),
- 1000000ll * (mNumFramesPlayed + numAdditionalFrames)
- / mSampleRate);
-
- ALOGV("%d frames left to play, %" PRId64 " us (%.2f secs)",
- numFramesPendingPlayout,
- timeToCompletionUs, timeToCompletionUs / 1E6);
-
- postEOS = true;
- if (mAudioSink->needsTrailingPadding()) {
- postEOSDelayUs = timeToCompletionUs + mLatencyUs;
- } else {
- postEOSDelayUs = 0;
- }
- }
-
mReachedEOS = true;
}
}
@@ -626,12 +573,6 @@
// might not be able to get the exact seek time requested.
if (refreshSeekTime) {
if (useOffload()) {
- if (postSeekComplete) {
- ALOGV("fillBuffer is going to post SEEK_COMPLETE");
- mObserver->postAudioSeekComplete();
- postSeekComplete = false;
- }
-
mStartPosUs = mPositionTimeMediaUs;
ALOGV("adjust seek time to: %.2f", mStartPosUs/ 1E6);
}
@@ -698,14 +639,6 @@
}
}
- if (postEOS) {
- mObserver->postAudioEOS(postEOSDelayUs);
- }
-
- if (postSeekComplete) {
- mObserver->postAudioSeekComplete();
- }
-
return size_done;
}
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
deleted file mode 100644
index f535e5c..0000000
--- a/media/libstagefright/AwesomePlayer.cpp
+++ /dev/null
@@ -1,3077 +0,0 @@
-/*
- * Copyright (C) 2009 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.
- */
-
-#undef DEBUG_HDCP
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "AwesomePlayer"
-#define ATRACE_TAG ATRACE_TAG_VIDEO
-
-#include <inttypes.h>
-
-#include <utils/Log.h>
-#include <utils/Trace.h>
-
-#include <dlfcn.h>
-
-#include "include/AwesomePlayer.h"
-#include "include/DRMExtractor.h"
-#include "include/SoftwareRenderer.h"
-#include "include/NuCachedSource2.h"
-#include "include/ThrottledSource.h"
-#include "include/MPEG2TSExtractor.h"
-#include "include/WVMExtractor.h"
-
-#include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
-#include <media/IMediaHTTPConnection.h>
-#include <media/IMediaHTTPService.h>
-#include <media/IMediaPlayerService.h>
-#include <media/stagefright/foundation/hexdump.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/timedtext/TimedTextDriver.h>
-#include <media/stagefright/AudioPlayer.h>
-#include <media/stagefright/ClockEstimator.h>
-#include <media/stagefright/DataSource.h>
-#include <media/stagefright/FileSource.h>
-#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaExtractor.h>
-#include <media/stagefright/MediaHTTP.h>
-#include <media/stagefright/MediaSource.h>
-#include <media/stagefright/MetaData.h>
-#include <media/stagefright/OMXCodec.h>
-#include <media/stagefright/Utils.h>
-
-#include <gui/IGraphicBufferProducer.h>
-#include <gui/Surface.h>
-
-#include <media/stagefright/foundation/AMessage.h>
-
-#include <cutils/properties.h>
-
-#define USE_SURFACE_ALLOC 1
-#define FRAME_DROP_FREQ 0
-#define PROPERTY_OFFLOAD_HIWATERMARK "audio.offload.hiwatermark"
-#define PROPERTY_OFFLOAD_LOWATERMARK "audio.offload.lowatermark"
-
-namespace android {
-
-static int64_t kLowWaterMarkUs = 2000000ll; // 2secs
-static int64_t kHighWaterMarkUs = 5000000ll; // 5secs
-static const size_t kLowWaterMarkBytes = 40000;
-static const size_t kHighWaterMarkBytes = 200000;
-static size_t kOffloadLowWaterMarkBytes = kLowWaterMarkBytes;
-static size_t kOffloadHighWaterMarkBytes = kHighWaterMarkBytes;
-// maximum time in paused state when offloading audio decompression. When elapsed, the AudioPlayer
-// is destroyed to allow the audio DSP to power down.
-static int64_t kOffloadPauseMaxUs = 10000000ll;
-
-
-struct AwesomeEvent : public TimedEventQueue::Event {
- AwesomeEvent(
- AwesomePlayer *player,
- void (AwesomePlayer::*method)())
- : mPlayer(player),
- mMethod(method) {
- }
-
-protected:
- virtual ~AwesomeEvent() {}
-
- virtual void fire(TimedEventQueue * /* queue */, int64_t /* now_us */) {
- (mPlayer->*mMethod)();
- }
-
-private:
- AwesomePlayer *mPlayer;
- void (AwesomePlayer::*mMethod)();
-
- AwesomeEvent(const AwesomeEvent &);
- AwesomeEvent &operator=(const AwesomeEvent &);
-};
-
-struct AwesomeLocalRenderer : public AwesomeRenderer {
- AwesomeLocalRenderer(
- const sp<ANativeWindow> &nativeWindow, const sp<AMessage> &format)
- : mFormat(format),
- mTarget(new SoftwareRenderer(nativeWindow)) {
- }
-
- virtual void render(MediaBuffer *buffer) {
- int64_t timeUs;
- CHECK(buffer->meta_data()->findInt64(kKeyTime, &timeUs));
-
- render((const uint8_t *)buffer->data() + buffer->range_offset(),
- buffer->range_length(), timeUs, timeUs * 1000);
- }
-
- void render(const void *data, size_t size, int64_t mediaTimeUs, nsecs_t renderTimeNs) {
- (void)mTarget->render(data, size, mediaTimeUs, renderTimeNs, NULL, mFormat);
- }
-
-protected:
- virtual ~AwesomeLocalRenderer() {
- delete mTarget;
- mTarget = NULL;
- }
-
-private:
- sp<AMessage> mFormat;
- SoftwareRenderer *mTarget;
-
- AwesomeLocalRenderer(const AwesomeLocalRenderer &);
- AwesomeLocalRenderer &operator=(const AwesomeLocalRenderer &);;
-};
-
-struct AwesomeNativeWindowRenderer : public AwesomeRenderer {
- AwesomeNativeWindowRenderer(
- const sp<ANativeWindow> &nativeWindow,
- int32_t rotationDegrees)
- : mNativeWindow(nativeWindow) {
- applyRotation(rotationDegrees);
- }
-
- virtual void render(MediaBuffer *buffer) {
- ATRACE_CALL();
- int64_t timeUs;
- CHECK(buffer->meta_data()->findInt64(kKeyTime, &timeUs));
- native_window_set_buffers_timestamp(mNativeWindow.get(), timeUs * 1000);
- status_t err = mNativeWindow->queueBuffer(
- mNativeWindow.get(), buffer->graphicBuffer().get(), -1);
- if (err != 0) {
- ALOGE("queueBuffer failed with error %s (%d)", strerror(-err),
- -err);
- return;
- }
-
- sp<MetaData> metaData = buffer->meta_data();
- metaData->setInt32(kKeyRendered, 1);
- }
-
-protected:
- virtual ~AwesomeNativeWindowRenderer() {}
-
-private:
- sp<ANativeWindow> mNativeWindow;
-
- void applyRotation(int32_t rotationDegrees) {
- uint32_t transform;
- switch (rotationDegrees) {
- case 0: transform = 0; break;
- case 90: transform = HAL_TRANSFORM_ROT_90; break;
- case 180: transform = HAL_TRANSFORM_ROT_180; break;
- case 270: transform = HAL_TRANSFORM_ROT_270; break;
- default: transform = 0; break;
- }
-
- if (transform) {
- CHECK_EQ(0, native_window_set_buffers_transform(
- mNativeWindow.get(), transform));
- }
- }
-
- AwesomeNativeWindowRenderer(const AwesomeNativeWindowRenderer &);
- AwesomeNativeWindowRenderer &operator=(
- const AwesomeNativeWindowRenderer &);
-};
-
-// To collect the decoder usage
-void addBatteryData(uint32_t params) {
- sp<IBinder> binder =
- defaultServiceManager()->getService(String16("media.player"));
- sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
- CHECK(service.get() != NULL);
-
- service->addBatteryData(params);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-AwesomePlayer::AwesomePlayer()
- : mQueueStarted(false),
- mUIDValid(false),
- mTimeSource(NULL),
- mVideoRenderingStarted(false),
- mVideoRendererIsPreview(false),
- mMediaRenderingStartGeneration(0),
- mStartGeneration(0),
- mAudioPlayer(NULL),
- mDisplayWidth(0),
- mDisplayHeight(0),
- mVideoScalingMode(NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW),
- mFlags(0),
- mExtractorFlags(0),
- mVideoBuffer(NULL),
- mDecryptHandle(NULL),
- mLastVideoTimeUs(-1),
- mTextDriver(NULL),
- mSelectedTimedTextTrack(-1),
- mOffloadAudio(false),
- mAudioTearDown(false) {
- CHECK_EQ(mClient.connect(), (status_t)OK);
-
- DataSource::RegisterDefaultSniffers();
-
- mVideoEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoEvent);
- mVideoEventPending = false;
- mStreamDoneEvent = new AwesomeEvent(this, &AwesomePlayer::onStreamDone);
- mStreamDoneEventPending = false;
- mBufferingEvent = new AwesomeEvent(this, &AwesomePlayer::onBufferingUpdate);
- mBufferingEventPending = false;
- mVideoLagEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoLagUpdate);
- mVideoLagEventPending = false;
-
- mCheckAudioStatusEvent = new AwesomeEvent(
- this, &AwesomePlayer::onCheckAudioStatus);
-
- mAudioStatusEventPending = false;
-
- mAudioTearDownEvent = new AwesomeEvent(this,
- &AwesomePlayer::onAudioTearDownEvent);
- mAudioTearDownEventPending = false;
-
- mClockEstimator = new WindowedLinearFitEstimator();
-
- mPlaybackSettings = AUDIO_PLAYBACK_RATE_DEFAULT;
-
- reset();
-}
-
-AwesomePlayer::~AwesomePlayer() {
- if (mQueueStarted) {
- mQueue.stop();
- }
-
- reset();
-
- mClient.disconnect();
-}
-
-void AwesomePlayer::cancelPlayerEvents(bool keepNotifications) {
- mQueue.cancelEvent(mVideoEvent->eventID());
- mVideoEventPending = false;
- mQueue.cancelEvent(mVideoLagEvent->eventID());
- mVideoLagEventPending = false;
-
- if (mOffloadAudio) {
- mQueue.cancelEvent(mAudioTearDownEvent->eventID());
- mAudioTearDownEventPending = false;
- }
-
- if (!keepNotifications) {
- mQueue.cancelEvent(mStreamDoneEvent->eventID());
- mStreamDoneEventPending = false;
- mQueue.cancelEvent(mCheckAudioStatusEvent->eventID());
- mAudioStatusEventPending = false;
-
- mQueue.cancelEvent(mBufferingEvent->eventID());
- mBufferingEventPending = false;
- mAudioTearDown = false;
- }
-}
-
-void AwesomePlayer::setListener(const wp<MediaPlayerBase> &listener) {
- Mutex::Autolock autoLock(mLock);
- mListener = listener;
-}
-
-void AwesomePlayer::setUID(uid_t uid) {
- ALOGV("AwesomePlayer running on behalf of uid %d", uid);
-
- mUID = uid;
- mUIDValid = true;
-}
-
-status_t AwesomePlayer::setDataSource(
- const sp<IMediaHTTPService> &httpService,
- const char *uri,
- const KeyedVector<String8, String8> *headers) {
- Mutex::Autolock autoLock(mLock);
- return setDataSource_l(httpService, uri, headers);
-}
-
-status_t AwesomePlayer::setDataSource_l(
- const sp<IMediaHTTPService> &httpService,
- const char *uri,
- const KeyedVector<String8, String8> *headers) {
- reset_l();
-
- mHTTPService = httpService;
- mUri = uri;
-
- if (headers) {
- mUriHeaders = *headers;
-
- ssize_t index = mUriHeaders.indexOfKey(String8("x-hide-urls-from-log"));
- if (index >= 0) {
- // Browser is in "incognito" mode, suppress logging URLs.
-
- // This isn't something that should be passed to the server.
- mUriHeaders.removeItemsAt(index);
-
- modifyFlags(INCOGNITO, SET);
- }
- }
-
- ALOGI("setDataSource_l(%s)", uriDebugString(mUri, mFlags & INCOGNITO).c_str());
-
- // The actual work will be done during preparation in the call to
- // ::finishSetDataSource_l to avoid blocking the calling thread in
- // setDataSource for any significant time.
-
- {
- Mutex::Autolock autoLock(mStatsLock);
- mStats.mFd = -1;
- mStats.mURI = mUri;
- }
-
- return OK;
-}
-
-status_t AwesomePlayer::setDataSource(
- int fd, int64_t offset, int64_t length) {
- Mutex::Autolock autoLock(mLock);
-
- reset_l();
-
- fd = dup(fd);
- sp<DataSource> dataSource = new FileSource(fd, offset, length);
-
- status_t err = dataSource->initCheck();
-
- if (err != OK) {
- return err;
- }
-
- mFileSource = dataSource;
-
- {
- Mutex::Autolock autoLock(mStatsLock);
- mStats.mFd = fd;
- mStats.mURI = String8();
- }
-
- return setDataSource_l(dataSource);
-}
-
-status_t AwesomePlayer::setDataSource(const sp<IStreamSource> &source __unused) {
- return INVALID_OPERATION;
-}
-
-status_t AwesomePlayer::setDataSource_l(
- const sp<DataSource> &dataSource) {
- sp<IMediaExtractor> extractor = MediaExtractor::Create(dataSource);
-
- if (extractor == NULL) {
- return UNKNOWN_ERROR;
- }
-
- if (extractor->getDrmFlag()) {
- checkDrmStatus(dataSource);
- }
-
- return setDataSource_l(extractor);
-}
-
-void AwesomePlayer::checkDrmStatus(const sp<DataSource>& dataSource) {
- dataSource->getDrmInfo(mDecryptHandle, &mDrmManagerClient);
- if (mDecryptHandle != NULL) {
- CHECK(mDrmManagerClient);
- if (RightsStatus::RIGHTS_VALID != mDecryptHandle->status) {
- notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_DRM_NO_LICENSE);
- }
- }
-}
-
-status_t AwesomePlayer::setDataSource_l(const sp<IMediaExtractor> &extractor) {
- // Attempt to approximate overall stream bitrate by summing all
- // tracks' individual bitrates, if not all of them advertise bitrate,
- // we have to fail.
-
- int64_t totalBitRate = 0;
-
- mExtractor = extractor;
- for (size_t i = 0; i < extractor->countTracks(); ++i) {
- sp<MetaData> meta = extractor->getTrackMetaData(i);
-
- int32_t bitrate;
- if (!meta->findInt32(kKeyBitRate, &bitrate)) {
- const char *mime;
- CHECK(meta->findCString(kKeyMIMEType, &mime));
- ALOGV("track of type '%s' does not publish bitrate", mime);
-
- totalBitRate = -1;
- break;
- }
-
- totalBitRate += bitrate;
- }
- sp<MetaData> fileMeta = mExtractor->getMetaData();
- if (fileMeta != NULL) {
- int64_t duration;
- if (fileMeta->findInt64(kKeyDuration, &duration)) {
- mDurationUs = duration;
- }
- }
-
- mBitrate = totalBitRate;
-
- ALOGV("mBitrate = %lld bits/sec", (long long)mBitrate);
-
- {
- Mutex::Autolock autoLock(mStatsLock);
- mStats.mBitrate = mBitrate;
- mStats.mTracks.clear();
- mStats.mAudioTrackIndex = -1;
- mStats.mVideoTrackIndex = -1;
- }
-
- bool haveAudio = false;
- bool haveVideo = false;
- for (size_t i = 0; i < extractor->countTracks(); ++i) {
- sp<MetaData> meta = extractor->getTrackMetaData(i);
-
- const char *_mime;
- CHECK(meta->findCString(kKeyMIMEType, &_mime));
-
- String8 mime = String8(_mime);
-
- if (!haveVideo && !strncasecmp(mime.string(), "video/", 6)) {
- setVideoSource(extractor->getTrack(i));
- haveVideo = true;
-
- // Set the presentation/display size
- int32_t displayWidth, displayHeight;
- bool success = meta->findInt32(kKeyDisplayWidth, &displayWidth);
- if (success) {
- success = meta->findInt32(kKeyDisplayHeight, &displayHeight);
- }
- if (success) {
- mDisplayWidth = displayWidth;
- mDisplayHeight = displayHeight;
- }
-
- {
- Mutex::Autolock autoLock(mStatsLock);
- mStats.mVideoTrackIndex = mStats.mTracks.size();
- mStats.mTracks.push();
- TrackStat *stat =
- &mStats.mTracks.editItemAt(mStats.mVideoTrackIndex);
- stat->mMIME = mime.string();
- }
- } else if (!haveAudio && !strncasecmp(mime.string(), "audio/", 6)) {
- setAudioSource(extractor->getTrack(i));
- haveAudio = true;
- mActiveAudioTrackIndex = i;
-
- {
- Mutex::Autolock autoLock(mStatsLock);
- mStats.mAudioTrackIndex = mStats.mTracks.size();
- mStats.mTracks.push();
- TrackStat *stat =
- &mStats.mTracks.editItemAt(mStats.mAudioTrackIndex);
- stat->mMIME = mime.string();
- }
-
- if (!strcasecmp(mime.string(), MEDIA_MIMETYPE_AUDIO_VORBIS)) {
- // Only do this for vorbis audio, none of the other audio
- // formats even support this ringtone specific hack and
- // retrieving the metadata on some extractors may turn out
- // to be very expensive.
- sp<MetaData> fileMeta = extractor->getMetaData();
- int32_t loop;
- if (fileMeta != NULL
- && fileMeta->findInt32(kKeyAutoLoop, &loop) && loop != 0) {
- modifyFlags(AUTO_LOOPING, SET);
- }
- }
- } else if (!strcasecmp(mime.string(), MEDIA_MIMETYPE_TEXT_3GPP)) {
- addTextSource_l(i, extractor->getTrack(i));
- }
- }
-
- if (!haveAudio && !haveVideo) {
- if (mWVMExtractor != NULL) {
- return mWVMExtractor->getError();
- } else {
- return UNKNOWN_ERROR;
- }
- }
-
- mExtractorFlags = extractor->flags();
-
- return OK;
-}
-
-void AwesomePlayer::reset() {
- Mutex::Autolock autoLock(mLock);
- reset_l();
-}
-
-void AwesomePlayer::reset_l() {
- mVideoRenderingStarted = false;
- mActiveAudioTrackIndex = -1;
- mDisplayWidth = 0;
- mDisplayHeight = 0;
-
- notifyListener_l(MEDIA_STOPPED);
-
- if (mDecryptHandle != NULL) {
- mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
- Playback::STOP, 0);
- mDecryptHandle = NULL;
- mDrmManagerClient = NULL;
- }
-
- if (mFlags & PLAYING) {
- uint32_t params = IMediaPlayerService::kBatteryDataTrackDecoder;
- if ((mAudioSource != NULL) && (mAudioSource != mAudioTrack)) {
- params |= IMediaPlayerService::kBatteryDataTrackAudio;
- }
- if (mVideoSource != NULL) {
- params |= IMediaPlayerService::kBatteryDataTrackVideo;
- }
- addBatteryData(params);
- }
-
- if (mFlags & PREPARING) {
- modifyFlags(PREPARE_CANCELLED, SET);
- if (mConnectingDataSource != NULL) {
- ALOGI("interrupting the connection process");
- mConnectingDataSource->disconnect();
- }
-
- if (mFlags & PREPARING_CONNECTED) {
- // We are basically done preparing, we're just buffering
- // enough data to start playback, we can safely interrupt that.
- finishAsyncPrepare_l();
- }
- }
-
- while (mFlags & PREPARING) {
- mPreparedCondition.wait(mLock);
- }
-
- cancelPlayerEvents();
-
- mWVMExtractor.clear();
- mCachedSource.clear();
- mAudioTrack.clear();
- mVideoTrack.clear();
- mExtractor.clear();
-
- // Shutdown audio first, so that the response to the reset request
- // appears to happen instantaneously as far as the user is concerned
- // If we did this later, audio would continue playing while we
- // shutdown the video-related resources and the player appear to
- // not be as responsive to a reset request.
- if ((mAudioPlayer == NULL || !(mFlags & AUDIOPLAYER_STARTED))
- && mAudioSource != NULL) {
- // If we had an audio player, it would have effectively
- // taken possession of the audio source and stopped it when
- // _it_ is stopped. Otherwise this is still our responsibility.
- mAudioSource->stop();
- }
- mAudioSource.clear();
- mOmxSource.clear();
-
- mTimeSource = NULL;
-
- delete mAudioPlayer;
- mAudioPlayer = NULL;
-
- if (mTextDriver != NULL) {
- delete mTextDriver;
- mTextDriver = NULL;
- }
-
- mVideoRenderer.clear();
-
- if (mVideoSource != NULL) {
- shutdownVideoDecoder_l();
- }
-
- mDurationUs = -1;
- modifyFlags(0, ASSIGN);
- mExtractorFlags = 0;
- mTimeSourceDeltaUs = 0;
- mVideoTimeUs = 0;
-
- mSeeking = NO_SEEK;
- mSeekNotificationSent = true;
- mSeekTimeUs = 0;
-
- mHTTPService.clear();
- mUri.setTo("");
- mUriHeaders.clear();
-
- mFileSource.clear();
-
- mBitrate = -1;
- mLastVideoTimeUs = -1;
-
- {
- Mutex::Autolock autoLock(mStatsLock);
- mStats.mFd = -1;
- mStats.mURI = String8();
- mStats.mBitrate = -1;
- mStats.mAudioTrackIndex = -1;
- mStats.mVideoTrackIndex = -1;
- mStats.mNumVideoFramesDecoded = 0;
- mStats.mNumVideoFramesDropped = 0;
- mStats.mVideoWidth = -1;
- mStats.mVideoHeight = -1;
- mStats.mFlags = 0;
- mStats.mTracks.clear();
- }
-
- mWatchForAudioSeekComplete = false;
- mWatchForAudioEOS = false;
-
- mMediaRenderingStartGeneration = 0;
- mStartGeneration = 0;
-
- kOffloadLowWaterMarkBytes =
- property_get_int32(PROPERTY_OFFLOAD_LOWATERMARK, kLowWaterMarkBytes);
- kOffloadHighWaterMarkBytes =
- property_get_int32(PROPERTY_OFFLOAD_HIWATERMARK, kHighWaterMarkBytes);
-}
-
-void AwesomePlayer::notifyListener_l(int msg, int ext1, int ext2) {
- if ((mListener != NULL) && !mAudioTearDown) {
- sp<MediaPlayerBase> listener = mListener.promote();
-
- if (listener != NULL) {
- listener->sendEvent(msg, ext1, ext2);
- }
- }
-}
-
-bool AwesomePlayer::getBitrate(int64_t *bitrate) {
- off64_t size;
- if (mDurationUs > 0 && mCachedSource != NULL
- && mCachedSource->getSize(&size) == OK) {
- *bitrate = size * 8000000ll / mDurationUs; // in bits/sec
- return true;
- }
-
- if (mBitrate >= 0) {
- *bitrate = mBitrate;
- return true;
- }
-
- *bitrate = 0;
-
- return false;
-}
-
-// Returns true iff cached duration is available/applicable.
-bool AwesomePlayer::getCachedDuration_l(int64_t *durationUs, bool *eos) {
- int64_t bitrate;
-
- if (mCachedSource != NULL && getBitrate(&bitrate) && (bitrate > 0)) {
- status_t finalStatus;
- size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&finalStatus);
- *durationUs = cachedDataRemaining * 8000000ll / bitrate;
- *eos = (finalStatus != OK);
- return true;
- } else if (mWVMExtractor != NULL) {
- status_t finalStatus;
- *durationUs = mWVMExtractor->getCachedDurationUs(&finalStatus);
- *eos = (finalStatus != OK);
- return true;
- }
-
- return false;
-}
-
-void AwesomePlayer::ensureCacheIsFetching_l() {
- if (mCachedSource != NULL) {
- mCachedSource->resumeFetchingIfNecessary();
- }
-}
-
-void AwesomePlayer::onVideoLagUpdate() {
- Mutex::Autolock autoLock(mLock);
- if (!mVideoLagEventPending) {
- return;
- }
- mVideoLagEventPending = false;
-
- int64_t audioTimeUs = mAudioPlayer->getMediaTimeUs();
- int64_t videoLateByUs = audioTimeUs - mVideoTimeUs;
-
- if (!(mFlags & VIDEO_AT_EOS) && videoLateByUs > 300000ll) {
- ALOGV("video late by %lld ms.", videoLateByUs / 1000ll);
-
- notifyListener_l(
- MEDIA_INFO,
- MEDIA_INFO_VIDEO_TRACK_LAGGING,
- videoLateByUs / 1000ll);
- }
-
- postVideoLagEvent_l();
-}
-
-void AwesomePlayer::onBufferingUpdate() {
- Mutex::Autolock autoLock(mLock);
- if (!mBufferingEventPending) {
- return;
- }
- mBufferingEventPending = false;
-
- if (mCachedSource != NULL) {
- status_t finalStatus;
- size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&finalStatus);
- bool eos = (finalStatus != OK);
-
- ALOGV("cachedDataRemaining = %zu b, eos=%d", cachedDataRemaining, eos);
- if (eos) {
- if (finalStatus == ERROR_END_OF_STREAM) {
- notifyListener_l(MEDIA_BUFFERING_UPDATE, 100);
- }
- if (mFlags & PREPARING) {
- ALOGV("cache has reached EOS, prepare is done.");
- finishAsyncPrepare_l();
- }
- } else {
- bool eos2;
- bool knownDuration = false;
- int64_t cachedDurationUs;
- if (getCachedDuration_l(&cachedDurationUs, &eos2) && mDurationUs > 0) {
- knownDuration = true;
- int percentage = 100.0 * (double)cachedDurationUs / mDurationUs;
- if (percentage > 100) {
- percentage = 100;
- }
-
- notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage);
- }
- if (!knownDuration || mOffloadAudio) {
- // If we don't know the bitrate/duration of the stream, or are offloading
- // decode, use absolute size limits to maintain the cache.
-
- size_t lowWatermark =
- mOffloadAudio ? kOffloadLowWaterMarkBytes : kLowWaterMarkBytes;
- size_t highWatermark =
- mOffloadAudio ? kOffloadHighWaterMarkBytes : kHighWaterMarkBytes;
-
- if ((mFlags & PLAYING) && !eos && (cachedDataRemaining < lowWatermark)) {
- ALOGI("cache is running low (< %zu) , pausing.", lowWatermark);
- modifyFlags(CACHE_UNDERRUN, SET);
- pause_l();
- ensureCacheIsFetching_l();
- sendCacheStats();
- notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
- } else if (eos || cachedDataRemaining > highWatermark) {
- if (mFlags & CACHE_UNDERRUN) {
- ALOGI("cache has filled up (> %zu), resuming.",
- highWatermark);
- modifyFlags(CACHE_UNDERRUN, CLEAR);
- play_l();
- } else if (mFlags & PREPARING) {
- ALOGV("cache has filled up (> %zu), prepare is done",
- highWatermark);
- finishAsyncPrepare_l();
- }
- }
- }
- }
- } else if (mWVMExtractor != NULL) {
- status_t finalStatus;
-
- int64_t cachedDurationUs
- = mWVMExtractor->getCachedDurationUs(&finalStatus);
-
- bool eos = (finalStatus != OK);
-
- if (eos) {
- if (finalStatus == ERROR_END_OF_STREAM) {
- notifyListener_l(MEDIA_BUFFERING_UPDATE, 100);
- }
- if (mFlags & PREPARING) {
- ALOGV("cache has reached EOS, prepare is done.");
- finishAsyncPrepare_l();
- }
- } else {
- int percentage = 100.0 * (double)cachedDurationUs / mDurationUs;
- if (percentage > 100) {
- percentage = 100;
- }
-
- notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage);
- }
- }
-
- int64_t cachedDurationUs;
- bool eos;
- if (!mOffloadAudio && getCachedDuration_l(&cachedDurationUs, &eos)) {
- ALOGV("cachedDurationUs = %.2f secs, eos=%d",
- cachedDurationUs / 1E6, eos);
-
- if ((mFlags & PLAYING) && !eos
- && (cachedDurationUs < kLowWaterMarkUs)) {
- modifyFlags(CACHE_UNDERRUN, SET);
- ALOGI("cache is running low (%.2f secs) , pausing.",
- cachedDurationUs / 1E6);
- pause_l();
- ensureCacheIsFetching_l();
- sendCacheStats();
- notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
- } else if (eos || cachedDurationUs > kHighWaterMarkUs) {
- if (mFlags & CACHE_UNDERRUN) {
- modifyFlags(CACHE_UNDERRUN, CLEAR);
- ALOGI("cache has filled up (%.2f secs), resuming.",
- cachedDurationUs / 1E6);
- play_l();
- } else if (mFlags & PREPARING) {
- ALOGV("cache has filled up (%.2f secs), prepare is done",
- cachedDurationUs / 1E6);
- finishAsyncPrepare_l();
- }
- }
- }
-
- if ( ((mFlags & PLAYING) && !eos) ||
- (mFlags & (PREPARING | CACHE_UNDERRUN)) ) {
- postBufferingEvent_l();
- }
-}
-
-void AwesomePlayer::sendCacheStats() {
- sp<MediaPlayerBase> listener = mListener.promote();
- if (listener != NULL) {
- int32_t kbps = 0;
- status_t err = UNKNOWN_ERROR;
- if (mCachedSource != NULL) {
- err = mCachedSource->getEstimatedBandwidthKbps(&kbps);
- } else if (mWVMExtractor != NULL) {
- err = mWVMExtractor->getEstimatedBandwidthKbps(&kbps);
- }
- if (err == OK) {
- listener->sendEvent(
- MEDIA_INFO, MEDIA_INFO_NETWORK_BANDWIDTH, kbps);
- }
- }
-}
-
-void AwesomePlayer::onStreamDone() {
- // Posted whenever any stream finishes playing.
- ATRACE_CALL();
-
- Mutex::Autolock autoLock(mLock);
- if (!mStreamDoneEventPending) {
- return;
- }
- mStreamDoneEventPending = false;
-
- if (mStreamDoneStatus != ERROR_END_OF_STREAM) {
- ALOGV("MEDIA_ERROR %d", mStreamDoneStatus);
-
- notifyListener_l(
- MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, mStreamDoneStatus);
-
- pause_l(true /* at eos */);
-
- modifyFlags(AT_EOS, SET);
- return;
- }
-
- const bool allDone =
- (mVideoSource == NULL || (mFlags & VIDEO_AT_EOS))
- && (mAudioSource == NULL || (mFlags & AUDIO_AT_EOS));
-
- if (!allDone) {
- return;
- }
-
- if (mFlags & AUTO_LOOPING) {
- audio_stream_type_t streamType = AUDIO_STREAM_MUSIC;
- if (mAudioSink != NULL) {
- streamType = mAudioSink->getAudioStreamType();
- }
- if (streamType == AUDIO_STREAM_NOTIFICATION) {
- ALOGW("disabling auto-loop for notification");
- modifyFlags(AUTO_LOOPING, CLEAR);
- }
- }
- if ((mFlags & LOOPING)
- || (mFlags & AUTO_LOOPING)) {
-
- seekTo_l(0);
-
- if (mVideoSource != NULL) {
- postVideoEvent_l();
- }
- } else {
- ALOGV("MEDIA_PLAYBACK_COMPLETE");
- notifyListener_l(MEDIA_PLAYBACK_COMPLETE);
-
- pause_l(true /* at eos */);
-
- // If audio hasn't completed MEDIA_SEEK_COMPLETE yet,
- // notify MEDIA_SEEK_COMPLETE to observer immediately for state persistence.
- if (mWatchForAudioSeekComplete) {
- notifyListener_l(MEDIA_SEEK_COMPLETE);
- mWatchForAudioSeekComplete = false;
- }
-
- modifyFlags(AT_EOS, SET);
- }
-}
-
-status_t AwesomePlayer::play() {
- ATRACE_CALL();
-
- Mutex::Autolock autoLock(mLock);
-
- modifyFlags(CACHE_UNDERRUN, CLEAR);
-
- return play_l();
-}
-
-status_t AwesomePlayer::play_l() {
- modifyFlags(SEEK_PREVIEW, CLEAR);
-
- if (mFlags & PLAYING) {
- return OK;
- }
-
- mMediaRenderingStartGeneration = ++mStartGeneration;
-
- if (!(mFlags & PREPARED)) {
- status_t err = prepare_l();
-
- if (err != OK) {
- return err;
- }
- }
-
- modifyFlags(PLAYING, SET);
- modifyFlags(FIRST_FRAME, SET);
-
- if (mDecryptHandle != NULL) {
- int64_t position;
- getPosition(&position);
- mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
- Playback::START, position / 1000);
- }
-
- if (mAudioSource != NULL) {
- if (mAudioPlayer == NULL) {
- createAudioPlayer_l();
- }
-
- CHECK(!(mFlags & AUDIO_RUNNING));
-
- if (mVideoSource == NULL) {
-
- // We don't want to post an error notification at this point,
- // the error returned from MediaPlayer::start() will suffice.
-
- status_t err = startAudioPlayer_l(
- false /* sendErrorNotification */);
-
- if ((err != OK) && mOffloadAudio) {
- ALOGI("play_l() cannot create offload output, fallback to sw decode");
- int64_t curTimeUs;
- getPosition(&curTimeUs);
-
- delete mAudioPlayer;
- mAudioPlayer = NULL;
- // if the player was started it will take care of stopping the source when destroyed
- if (!(mFlags & AUDIOPLAYER_STARTED)) {
- mAudioSource->stop();
- }
- modifyFlags((AUDIO_RUNNING | AUDIOPLAYER_STARTED), CLEAR);
- mOffloadAudio = false;
- mAudioSource = mOmxSource;
- if (mAudioSource != NULL) {
- err = mAudioSource->start();
-
- if (err != OK) {
- mAudioSource.clear();
- } else {
- mSeekNotificationSent = true;
- if (mExtractorFlags & MediaExtractor::CAN_SEEK) {
- seekTo_l(curTimeUs);
- }
- createAudioPlayer_l();
- err = startAudioPlayer_l(false);
- }
- }
- }
-
- if (err != OK) {
- delete mAudioPlayer;
- mAudioPlayer = NULL;
-
- modifyFlags((PLAYING | FIRST_FRAME), CLEAR);
-
- if (mDecryptHandle != NULL) {
- mDrmManagerClient->setPlaybackStatus(
- mDecryptHandle, Playback::STOP, 0);
- }
-
- return err;
- }
- }
-
- if (mAudioPlayer != NULL) {
- mAudioPlayer->setPlaybackRate(mPlaybackSettings);
- }
- }
-
- if (mTimeSource == NULL && mAudioPlayer == NULL) {
- mTimeSource = &mSystemTimeSource;
- }
-
- if (mVideoSource != NULL) {
- // Kick off video playback
- postVideoEvent_l();
-
- if (mAudioSource != NULL && mVideoSource != NULL) {
- postVideoLagEvent_l();
- }
- }
-
- if (mFlags & AT_EOS) {
- // Legacy behaviour, if a stream finishes playing and then
- // is started again, we play from the start...
- seekTo_l(0);
- }
-
- uint32_t params = IMediaPlayerService::kBatteryDataCodecStarted
- | IMediaPlayerService::kBatteryDataTrackDecoder;
- if ((mAudioSource != NULL) && (mAudioSource != mAudioTrack)) {
- params |= IMediaPlayerService::kBatteryDataTrackAudio;
- }
- if (mVideoSource != NULL) {
- params |= IMediaPlayerService::kBatteryDataTrackVideo;
- }
- addBatteryData(params);
-
- if (isStreamingHTTP()) {
- postBufferingEvent_l();
- }
-
- return OK;
-}
-
-void AwesomePlayer::createAudioPlayer_l()
-{
- uint32_t flags = 0;
- int64_t cachedDurationUs;
- bool eos;
-
- if (mOffloadAudio) {
- flags |= AudioPlayer::USE_OFFLOAD;
- } else if (mVideoSource == NULL
- && (mDurationUs > AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US ||
- (getCachedDuration_l(&cachedDurationUs, &eos) &&
- cachedDurationUs > AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US))) {
- flags |= AudioPlayer::ALLOW_DEEP_BUFFERING;
- }
- if (isStreamingHTTP()) {
- flags |= AudioPlayer::IS_STREAMING;
- }
- if (mVideoSource != NULL) {
- flags |= AudioPlayer::HAS_VIDEO;
- }
-
- mAudioPlayer = new AudioPlayer(mAudioSink, flags, this);
- mAudioPlayer->setSource(mAudioSource);
-
- mTimeSource = mAudioPlayer;
-
- // If there was a seek request before we ever started,
- // honor the request now.
- // Make sure to do this before starting the audio player
- // to avoid a race condition.
- seekAudioIfNecessary_l();
-}
-
-void AwesomePlayer::notifyIfMediaStarted_l() {
- if (mMediaRenderingStartGeneration == mStartGeneration) {
- mMediaRenderingStartGeneration = -1;
- notifyListener_l(MEDIA_STARTED);
- }
-}
-
-status_t AwesomePlayer::startAudioPlayer_l(bool sendErrorNotification) {
- CHECK(!(mFlags & AUDIO_RUNNING));
- status_t err = OK;
-
- if (mAudioSource == NULL || mAudioPlayer == NULL) {
- return OK;
- }
-
- if (mOffloadAudio) {
- mQueue.cancelEvent(mAudioTearDownEvent->eventID());
- mAudioTearDownEventPending = false;
- }
-
- if (!(mFlags & AUDIOPLAYER_STARTED)) {
- bool wasSeeking = mAudioPlayer->isSeeking();
-
- // We've already started the MediaSource in order to enable
- // the prefetcher to read its data.
- err = mAudioPlayer->start(
- true /* sourceAlreadyStarted */);
-
- if (err != OK) {
- if (sendErrorNotification) {
- notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
- }
-
- return err;
- }
-
- modifyFlags(AUDIOPLAYER_STARTED, SET);
-
- if (wasSeeking) {
- CHECK(!mAudioPlayer->isSeeking());
-
- // We will have finished the seek while starting the audio player.
- postAudioSeekComplete();
- } else {
- notifyIfMediaStarted_l();
- }
- } else {
- err = mAudioPlayer->resume();
- }
-
- if (err == OK) {
- err = mAudioPlayer->setPlaybackRate(mPlaybackSettings);
- }
-
- if (err == OK) {
- modifyFlags(AUDIO_RUNNING, SET);
-
- mWatchForAudioEOS = true;
- }
-
- return err;
-}
-
-void AwesomePlayer::notifyVideoSize_l() {
- ATRACE_CALL();
- sp<MetaData> meta = mVideoSource->getFormat();
-
- int32_t cropLeft, cropTop, cropRight, cropBottom;
- if (!meta->findRect(
- kKeyCropRect, &cropLeft, &cropTop, &cropRight, &cropBottom)) {
- int32_t width, height;
- CHECK(meta->findInt32(kKeyWidth, &width));
- CHECK(meta->findInt32(kKeyHeight, &height));
-
- cropLeft = cropTop = 0;
- cropRight = width - 1;
- cropBottom = height - 1;
-
- ALOGV("got dimensions only %d x %d", width, height);
- } else {
- ALOGV("got crop rect %d, %d, %d, %d",
- cropLeft, cropTop, cropRight, cropBottom);
- }
-
- int32_t displayWidth;
- if (meta->findInt32(kKeyDisplayWidth, &displayWidth)) {
- ALOGV("Display width changed (%d=>%d)", mDisplayWidth, displayWidth);
- mDisplayWidth = displayWidth;
- }
- int32_t displayHeight;
- if (meta->findInt32(kKeyDisplayHeight, &displayHeight)) {
- ALOGV("Display height changed (%d=>%d)", mDisplayHeight, displayHeight);
- mDisplayHeight = displayHeight;
- }
-
- int32_t usableWidth = cropRight - cropLeft + 1;
- int32_t usableHeight = cropBottom - cropTop + 1;
- if (mDisplayWidth != 0) {
- usableWidth = mDisplayWidth;
- }
- if (mDisplayHeight != 0) {
- usableHeight = mDisplayHeight;
- }
-
- {
- Mutex::Autolock autoLock(mStatsLock);
- mStats.mVideoWidth = usableWidth;
- mStats.mVideoHeight = usableHeight;
- }
-
- int32_t rotationDegrees;
- if (!mVideoTrack->getFormat()->findInt32(
- kKeyRotation, &rotationDegrees)) {
- rotationDegrees = 0;
- }
-
- if (rotationDegrees == 90 || rotationDegrees == 270) {
- notifyListener_l(
- MEDIA_SET_VIDEO_SIZE, usableHeight, usableWidth);
- } else {
- notifyListener_l(
- MEDIA_SET_VIDEO_SIZE, usableWidth, usableHeight);
- }
-}
-
-void AwesomePlayer::initRenderer_l() {
- ATRACE_CALL();
-
- if (mNativeWindow == NULL) {
- return;
- }
-
- sp<MetaData> meta = mVideoSource->getFormat();
-
- int32_t format;
- const char *component;
- int32_t decodedWidth, decodedHeight;
- CHECK(meta->findInt32(kKeyColorFormat, &format));
- CHECK(meta->findCString(kKeyDecoderComponent, &component));
- CHECK(meta->findInt32(kKeyWidth, &decodedWidth));
- CHECK(meta->findInt32(kKeyHeight, &decodedHeight));
-
- int32_t rotationDegrees;
- if (!mVideoTrack->getFormat()->findInt32(
- kKeyRotation, &rotationDegrees)) {
- rotationDegrees = 0;
- }
-
- mVideoRenderer.clear();
-
- // Must ensure that mVideoRenderer's destructor is actually executed
- // before creating a new one.
- IPCThreadState::self()->flushCommands();
-
- // Even if set scaling mode fails, we will continue anyway
- setVideoScalingMode_l(mVideoScalingMode);
- if (USE_SURFACE_ALLOC
- && !strncmp(component, "OMX.", 4)
- && strncmp(component, "OMX.google.", 11)) {
- // Hardware decoders avoid the CPU color conversion by decoding
- // directly to ANativeBuffers, so we must use a renderer that
- // just pushes those buffers to the ANativeWindow.
- mVideoRenderer =
- new AwesomeNativeWindowRenderer(mNativeWindow, rotationDegrees);
- } else {
- // Other decoders are instantiated locally and as a consequence
- // allocate their buffers in local address space. This renderer
- // then performs a color conversion and copy to get the data
- // into the ANativeBuffer.
- sp<AMessage> format;
- CHECK(OK == convertMetaDataToMessage(meta, &format));
- mVideoRenderer = new AwesomeLocalRenderer(mNativeWindow, format);
- }
-}
-
-status_t AwesomePlayer::pause() {
- ATRACE_CALL();
-
- Mutex::Autolock autoLock(mLock);
-
- modifyFlags(CACHE_UNDERRUN, CLEAR);
-
- return pause_l();
-}
-
-status_t AwesomePlayer::pause_l(bool at_eos) {
- if (!(mFlags & PLAYING)) {
- if (mAudioTearDown && mAudioTearDownWasPlaying) {
- ALOGV("pause_l() during teardown and finishSetDataSource_l() mFlags %x" , mFlags);
- mAudioTearDownWasPlaying = false;
- notifyListener_l(MEDIA_PAUSED);
- mMediaRenderingStartGeneration = ++mStartGeneration;
- }
- return OK;
- }
-
- notifyListener_l(MEDIA_PAUSED);
- mMediaRenderingStartGeneration = ++mStartGeneration;
-
- cancelPlayerEvents(true /* keepNotifications */);
-
- if (mAudioPlayer != NULL && (mFlags & AUDIO_RUNNING)) {
- // If we played the audio stream to completion we
- // want to make sure that all samples remaining in the audio
- // track's queue are played out.
- mAudioPlayer->pause(at_eos /* playPendingSamples */);
- // send us a reminder to tear down the AudioPlayer if paused for too long.
- if (mOffloadAudio) {
- postAudioTearDownEvent(kOffloadPauseMaxUs);
- }
- modifyFlags(AUDIO_RUNNING, CLEAR);
- }
-
- if (mFlags & TEXTPLAYER_INITIALIZED) {
- mTextDriver->pause();
- modifyFlags(TEXT_RUNNING, CLEAR);
- }
-
- modifyFlags(PLAYING, CLEAR);
-
- if (mDecryptHandle != NULL) {
- mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
- Playback::PAUSE, 0);
- }
-
- uint32_t params = IMediaPlayerService::kBatteryDataTrackDecoder;
- if ((mAudioSource != NULL) && (mAudioSource != mAudioTrack)) {
- params |= IMediaPlayerService::kBatteryDataTrackAudio;
- }
- if (mVideoSource != NULL) {
- params |= IMediaPlayerService::kBatteryDataTrackVideo;
- }
-
- addBatteryData(params);
-
- return OK;
-}
-
-bool AwesomePlayer::isPlaying() const {
- return (mFlags & PLAYING) || (mFlags & CACHE_UNDERRUN);
-}
-
-status_t AwesomePlayer::setSurfaceTexture(const sp<IGraphicBufferProducer> &bufferProducer) {
- Mutex::Autolock autoLock(mLock);
-
- status_t err;
- if (bufferProducer != NULL) {
- err = setNativeWindow_l(new Surface(bufferProducer));
- } else {
- err = setNativeWindow_l(NULL);
- }
-
- return err;
-}
-
-void AwesomePlayer::shutdownVideoDecoder_l() {
- if (mVideoBuffer) {
- mVideoBuffer->release();
- mVideoBuffer = NULL;
- }
-
- mVideoSource->stop();
-
- // The following hack is necessary to ensure that the OMX
- // component is completely released by the time we may try
- // to instantiate it again.
- wp<IMediaSource> tmp = mVideoSource;
- mVideoSource.clear();
- while (tmp.promote() != NULL) {
- usleep(1000);
- }
- IPCThreadState::self()->flushCommands();
- ALOGV("video decoder shutdown completed");
-}
-
-status_t AwesomePlayer::setNativeWindow_l(const sp<ANativeWindow> &native) {
- mNativeWindow = native;
-
- if (mVideoSource == NULL) {
- return OK;
- }
-
- ALOGV("attempting to reconfigure to use new surface");
-
- bool wasPlaying = (mFlags & PLAYING) != 0;
-
- pause_l();
- mVideoRenderer.clear();
-
- shutdownVideoDecoder_l();
-
- status_t err = initVideoDecoder();
-
- if (err != OK) {
- ALOGE("failed to reinstantiate video decoder after surface change.");
- return err;
- }
-
- if (mLastVideoTimeUs >= 0) {
- mSeeking = SEEK;
- mSeekTimeUs = mLastVideoTimeUs;
- modifyFlags((AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS), CLEAR);
- }
-
- if (wasPlaying) {
- play_l();
- }
-
- return OK;
-}
-
-void AwesomePlayer::setAudioSink(
- const sp<MediaPlayerBase::AudioSink> &audioSink) {
- Mutex::Autolock autoLock(mLock);
-
- mAudioSink = audioSink;
-}
-
-status_t AwesomePlayer::setLooping(bool shouldLoop) {
- Mutex::Autolock autoLock(mLock);
-
- modifyFlags(LOOPING, CLEAR);
-
- if (shouldLoop) {
- modifyFlags(LOOPING, SET);
- }
-
- return OK;
-}
-
-status_t AwesomePlayer::getDuration(int64_t *durationUs) {
- Mutex::Autolock autoLock(mMiscStateLock);
-
- if (mDurationUs < 0) {
- return UNKNOWN_ERROR;
- }
-
- *durationUs = mDurationUs;
-
- return OK;
-}
-
-status_t AwesomePlayer::getPosition(int64_t *positionUs) {
- if (mSeeking != NO_SEEK) {
- *positionUs = mSeekTimeUs;
- } else if (mVideoSource != NULL
- && (mAudioPlayer == NULL || !(mFlags & VIDEO_AT_EOS))) {
- Mutex::Autolock autoLock(mMiscStateLock);
- *positionUs = mVideoTimeUs;
- } else if (mAudioPlayer != NULL) {
- *positionUs = mAudioPlayer->getMediaTimeUs();
- } else {
- *positionUs = 0;
- }
- return OK;
-}
-
-status_t AwesomePlayer::seekTo(int64_t timeUs) {
- ATRACE_CALL();
-
- if (mExtractorFlags & MediaExtractor::CAN_SEEK) {
- Mutex::Autolock autoLock(mLock);
- return seekTo_l(timeUs);
- }
-
- return OK;
-}
-
-status_t AwesomePlayer::seekTo_l(int64_t timeUs) {
- if (mFlags & CACHE_UNDERRUN) {
- modifyFlags(CACHE_UNDERRUN, CLEAR);
- play_l();
- }
-
- if ((mFlags & PLAYING) && mVideoSource != NULL && (mFlags & VIDEO_AT_EOS)) {
- // Video playback completed before, there's no pending
- // video event right now. In order for this new seek
- // to be honored, we need to post one.
-
- postVideoEvent_l();
- }
-
- mSeeking = SEEK;
- mSeekNotificationSent = false;
- mSeekTimeUs = timeUs;
- modifyFlags((AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS), CLEAR);
-
- if (mFlags & PLAYING) {
- notifyListener_l(MEDIA_PAUSED);
- mMediaRenderingStartGeneration = ++mStartGeneration;
- }
-
- seekAudioIfNecessary_l();
-
- if (mFlags & TEXTPLAYER_INITIALIZED) {
- mTextDriver->seekToAsync(mSeekTimeUs);
- }
-
- if (!(mFlags & PLAYING)) {
- ALOGV("seeking while paused, sending SEEK_COMPLETE notification"
- " immediately.");
-
- notifyListener_l(MEDIA_SEEK_COMPLETE);
- mSeekNotificationSent = true;
-
- if ((mFlags & PREPARED) && mVideoSource != NULL) {
- modifyFlags(SEEK_PREVIEW, SET);
- postVideoEvent_l();
- }
- }
-
- return OK;
-}
-
-void AwesomePlayer::seekAudioIfNecessary_l() {
- if (mSeeking != NO_SEEK && mVideoSource == NULL && mAudioPlayer != NULL) {
- mAudioPlayer->seekTo(mSeekTimeUs);
-
- mWatchForAudioSeekComplete = true;
- mWatchForAudioEOS = true;
-
- if (mDecryptHandle != NULL) {
- mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
- Playback::PAUSE, 0);
- mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
- Playback::START, mSeekTimeUs / 1000);
- }
- }
-}
-
-void AwesomePlayer::setAudioSource(sp<IMediaSource> source) {
- CHECK(source != NULL);
-
- mAudioTrack = source;
-}
-
-void AwesomePlayer::addTextSource_l(size_t trackIndex, const sp<IMediaSource>& source) {
- CHECK(source != NULL);
-
- if (mTextDriver == NULL) {
- mTextDriver = new TimedTextDriver(mListener, mHTTPService);
- }
-
- mTextDriver->addInBandTextSource(trackIndex, source);
-}
-
-status_t AwesomePlayer::initAudioDecoder() {
- ATRACE_CALL();
-
- sp<MetaData> meta = mAudioTrack->getFormat();
-
- const char *mime;
- CHECK(meta->findCString(kKeyMIMEType, &mime));
- // Check whether there is a hardware codec for this stream
- // This doesn't guarantee that the hardware has a free stream
- // but it avoids us attempting to open (and re-open) an offload
- // stream to hardware that doesn't have the necessary codec
- audio_stream_type_t streamType = AUDIO_STREAM_MUSIC;
- if (mAudioSink != NULL) {
- streamType = mAudioSink->getAudioStreamType();
- }
-
- mOffloadAudio = canOffloadStream(meta, (mVideoSource != NULL),
- isStreamingHTTP(), streamType);
-
- if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) {
- ALOGV("createAudioPlayer: bypass OMX (raw)");
- mAudioSource = mAudioTrack;
- } else {
- // If offloading we still create a OMX decoder as a fall-back
- // but we don't start it
- mOmxSource = OMXCodec::Create(
- mClient.interface(), mAudioTrack->getFormat(),
- false, // createEncoder
- mAudioTrack);
-
- if (mOffloadAudio) {
- ALOGV("createAudioPlayer: bypass OMX (offload)");
- mAudioSource = mAudioTrack;
- } else {
- mAudioSource = mOmxSource;
- }
- }
-
- if (mAudioSource != NULL) {
- int64_t durationUs;
- if (mAudioTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
- Mutex::Autolock autoLock(mMiscStateLock);
- if (mDurationUs < 0 || durationUs > mDurationUs) {
- mDurationUs = durationUs;
- }
- }
-
- status_t err = mAudioSource->start();
-
- if (err != OK) {
- mAudioSource.clear();
- mOmxSource.clear();
- return err;
- }
- } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_QCELP)) {
- // For legacy reasons we're simply going to ignore the absence
- // of an audio decoder for QCELP instead of aborting playback
- // altogether.
- return OK;
- }
-
- if (mAudioSource != NULL) {
- Mutex::Autolock autoLock(mStatsLock);
- TrackStat *stat = &mStats.mTracks.editItemAt(mStats.mAudioTrackIndex);
- const char *component;
- if (!mAudioSource->getFormat()
- ->findCString(kKeyDecoderComponent, &component)) {
- component = "none";
- }
-
- stat->mDecoderName = component;
- }
-
- return mAudioSource != NULL ? OK : UNKNOWN_ERROR;
-}
-
-void AwesomePlayer::setVideoSource(sp<IMediaSource> source) {
- CHECK(source != NULL);
-
- mVideoTrack = source;
-}
-
-status_t AwesomePlayer::initVideoDecoder(uint32_t flags) {
- ATRACE_CALL();
-
- // Either the application or the DRM system can independently say
- // that there must be a hardware-protected path to an external video sink.
- // For now we always require a hardware-protected path to external video sink
- // if content is DRMed, but eventually this could be optional per DRM agent.
- // When the application wants protection, then
- // (USE_SURFACE_ALLOC && (mSurface != 0) &&
- // (mSurface->getFlags() & ISurfaceComposer::eProtectedByApp))
- // will be true, but that part is already handled by SurfaceFlinger.
-
-#ifdef DEBUG_HDCP
- // For debugging, we allow a system property to control the protected usage.
- // In case of uninitialized or unexpected property, we default to "DRM only".
- bool setProtectionBit = false;
- char value[PROPERTY_VALUE_MAX];
- if (property_get("persist.sys.hdcp_checking", value, NULL)) {
- if (!strcmp(value, "never")) {
- // nop
- } else if (!strcmp(value, "always")) {
- setProtectionBit = true;
- } else if (!strcmp(value, "drm-only")) {
- if (mDecryptHandle != NULL) {
- setProtectionBit = true;
- }
- // property value is empty, or unexpected value
- } else {
- if (mDecryptHandle != NULL) {
- setProtectionBit = true;
- }
- }
- // can' read property value
- } else {
- if (mDecryptHandle != NULL) {
- setProtectionBit = true;
- }
- }
- // note that usage bit is already cleared, so no need to clear it in the "else" case
- if (setProtectionBit) {
- flags |= OMXCodec::kEnableGrallocUsageProtected;
- }
-#else
- if (mDecryptHandle != NULL) {
- flags |= OMXCodec::kEnableGrallocUsageProtected;
- }
-#endif
- ALOGV("initVideoDecoder flags=0x%x", flags);
- mVideoSource = OMXCodec::Create(
- mClient.interface(), mVideoTrack->getFormat(),
- false, // createEncoder
- mVideoTrack,
- NULL, flags, USE_SURFACE_ALLOC ? mNativeWindow : NULL);
-
- if (mVideoSource != NULL) {
- int64_t durationUs;
- if (mVideoTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
- Mutex::Autolock autoLock(mMiscStateLock);
- if (mDurationUs < 0 || durationUs > mDurationUs) {
- mDurationUs = durationUs;
- }
- }
-
- status_t err = mVideoSource->start();
-
- if (err != OK) {
- ALOGE("failed to start video source");
- mVideoSource.clear();
- return err;
- }
- }
-
- if (mVideoSource != NULL) {
- const char *componentName;
- CHECK(mVideoSource->getFormat()
- ->findCString(kKeyDecoderComponent, &componentName));
-
- {
- Mutex::Autolock autoLock(mStatsLock);
- TrackStat *stat = &mStats.mTracks.editItemAt(mStats.mVideoTrackIndex);
-
- stat->mDecoderName = componentName;
- }
-
- static const char *kPrefix = "OMX.Nvidia.";
- static const char *kSuffix = ".decode";
- static const size_t kSuffixLength = strlen(kSuffix);
-
- size_t componentNameLength = strlen(componentName);
-
- if (!strncmp(componentName, kPrefix, strlen(kPrefix))
- && componentNameLength >= kSuffixLength
- && !strcmp(&componentName[
- componentNameLength - kSuffixLength], kSuffix)) {
- modifyFlags(SLOW_DECODER_HACK, SET);
- }
- }
-
- return mVideoSource != NULL ? OK : UNKNOWN_ERROR;
-}
-
-void AwesomePlayer::finishSeekIfNecessary(int64_t videoTimeUs) {
- ATRACE_CALL();
-
- if (mSeeking == SEEK_VIDEO_ONLY) {
- mSeeking = NO_SEEK;
- return;
- }
-
- if (mSeeking == NO_SEEK || (mFlags & SEEK_PREVIEW)) {
- return;
- }
-
- // If we paused, then seeked, then resumed, it is possible that we have
- // signaled SEEK_COMPLETE at a copmletely different media time than where
- // we are now resuming. Signal new position to media time provider.
- // Cannot signal another SEEK_COMPLETE, as existing clients may not expect
- // multiple SEEK_COMPLETE responses to a single seek() request.
- if (mSeekNotificationSent && llabs((long long)(mSeekTimeUs - videoTimeUs)) > 10000) {
- // notify if we are resuming more than 10ms away from desired seek time
- notifyListener_l(MEDIA_SKIPPED);
- }
-
- if (mAudioPlayer != NULL) {
- ALOGV("seeking audio to %" PRId64 " us (%.2f secs).", videoTimeUs, videoTimeUs / 1E6);
-
- // If we don't have a video time, seek audio to the originally
- // requested seek time instead.
-
- mAudioPlayer->seekTo(videoTimeUs < 0 ? mSeekTimeUs : videoTimeUs);
- mWatchForAudioSeekComplete = true;
- mWatchForAudioEOS = true;
- } else if (!mSeekNotificationSent) {
- // If we're playing video only, report seek complete now,
- // otherwise audio player will notify us later.
- notifyListener_l(MEDIA_SEEK_COMPLETE);
- mSeekNotificationSent = true;
- }
-
- modifyFlags(FIRST_FRAME, SET);
- mSeeking = NO_SEEK;
-
- if (mDecryptHandle != NULL) {
- mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
- Playback::PAUSE, 0);
- mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
- Playback::START, videoTimeUs / 1000);
- }
-}
-
-void AwesomePlayer::onVideoEvent() {
- ATRACE_CALL();
- Mutex::Autolock autoLock(mLock);
- if (!mVideoEventPending) {
- // The event has been cancelled in reset_l() but had already
- // been scheduled for execution at that time.
- return;
- }
- mVideoEventPending = false;
-
- if (mSeeking != NO_SEEK) {
- if (mVideoBuffer) {
- mVideoBuffer->release();
- mVideoBuffer = NULL;
- }
-
- if (mSeeking == SEEK && isStreamingHTTP() && mAudioSource != NULL
- && !(mFlags & SEEK_PREVIEW)) {
- // We're going to seek the video source first, followed by
- // the audio source.
- // In order to avoid jumps in the DataSource offset caused by
- // the audio codec prefetching data from the old locations
- // while the video codec is already reading data from the new
- // locations, we'll "pause" the audio source, causing it to
- // stop reading input data until a subsequent seek.
-
- if (mAudioPlayer != NULL && (mFlags & AUDIO_RUNNING)) {
- mAudioPlayer->pause();
-
- modifyFlags(AUDIO_RUNNING, CLEAR);
- }
- mAudioSource->pause();
- }
- }
-
- if (!mVideoBuffer) {
- MediaSource::ReadOptions options;
- if (mSeeking != NO_SEEK) {
- ALOGV("seeking to %" PRId64 " us (%.2f secs)", mSeekTimeUs, mSeekTimeUs / 1E6);
-
- options.setSeekTo(
- mSeekTimeUs,
- mSeeking == SEEK_VIDEO_ONLY
- ? MediaSource::ReadOptions::SEEK_NEXT_SYNC
- : MediaSource::ReadOptions::SEEK_CLOSEST_SYNC);
- }
- for (;;) {
- status_t err = mVideoSource->read(&mVideoBuffer, &options);
- options.clearSeekTo();
-
- if (err != OK) {
- CHECK(mVideoBuffer == NULL);
-
- if (err == INFO_FORMAT_CHANGED) {
- ALOGV("VideoSource signalled format change.");
-
- notifyVideoSize_l();
-
- if (mVideoRenderer != NULL) {
- mVideoRendererIsPreview = false;
- initRenderer_l();
- }
- continue;
- }
-
- // So video playback is complete, but we may still have
- // a seek request pending that needs to be applied
- // to the audio track.
- if (mSeeking != NO_SEEK) {
- ALOGV("video stream ended while seeking!");
- }
- finishSeekIfNecessary(-1);
-
- if (mAudioPlayer != NULL
- && !(mFlags & (AUDIO_RUNNING | SEEK_PREVIEW))) {
- startAudioPlayer_l();
- }
-
- modifyFlags(VIDEO_AT_EOS, SET);
- postStreamDoneEvent_l(err);
- return;
- }
-
- if (mVideoBuffer->range_length() == 0) {
- // Some decoders, notably the PV AVC software decoder
- // return spurious empty buffers that we just want to ignore.
-
- mVideoBuffer->release();
- mVideoBuffer = NULL;
- continue;
- }
-
- break;
- }
-
- {
- Mutex::Autolock autoLock(mStatsLock);
- ++mStats.mNumVideoFramesDecoded;
- }
- }
-
- int64_t timeUs;
- CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
-
- mLastVideoTimeUs = timeUs;
-
- if (mSeeking == SEEK_VIDEO_ONLY) {
- if (mSeekTimeUs > timeUs) {
- ALOGI("XXX mSeekTimeUs = %" PRId64 " us, timeUs = %" PRId64 " us",
- mSeekTimeUs, timeUs);
- }
- }
-
- {
- Mutex::Autolock autoLock(mMiscStateLock);
- mVideoTimeUs = timeUs;
- }
-
- SeekType wasSeeking = mSeeking;
- finishSeekIfNecessary(timeUs);
-
- if (mAudioPlayer != NULL && !(mFlags & (AUDIO_RUNNING | SEEK_PREVIEW))) {
- status_t err = startAudioPlayer_l();
- if (err != OK) {
- ALOGE("Starting the audio player failed w/ err %d", err);
- return;
- }
- }
-
- if ((mFlags & TEXTPLAYER_INITIALIZED)
- && !(mFlags & (TEXT_RUNNING | SEEK_PREVIEW))) {
- mTextDriver->start();
- modifyFlags(TEXT_RUNNING, SET);
- }
-
- TimeSource *ts =
- ((mFlags & AUDIO_AT_EOS) || !(mFlags & AUDIOPLAYER_STARTED))
- ? &mSystemTimeSource : mTimeSource;
- int64_t systemTimeUs = mSystemTimeSource.getRealTimeUs();
- int64_t looperTimeUs = ALooper::GetNowUs();
-
- if (mFlags & FIRST_FRAME) {
- modifyFlags(FIRST_FRAME, CLEAR);
- mSinceLastDropped = 0;
- mClockEstimator->reset();
- mTimeSourceDeltaUs = estimateRealTimeUs(ts, systemTimeUs) - timeUs;
- }
-
- int64_t realTimeUs, mediaTimeUs;
- if (!(mFlags & AUDIO_AT_EOS) && mAudioPlayer != NULL
- && mAudioPlayer->getMediaTimeMapping(&realTimeUs, &mediaTimeUs)) {
- ALOGV("updating TSdelta (%" PRId64 " => %" PRId64 " change %" PRId64 ")",
- mTimeSourceDeltaUs, realTimeUs - mediaTimeUs,
- mTimeSourceDeltaUs - (realTimeUs - mediaTimeUs));
- ATRACE_INT("TS delta change (ms)", (mTimeSourceDeltaUs - (realTimeUs - mediaTimeUs)) / 1E3);
- mTimeSourceDeltaUs = realTimeUs - mediaTimeUs;
- }
-
- if (wasSeeking == SEEK_VIDEO_ONLY) {
- int64_t nowUs = estimateRealTimeUs(ts, systemTimeUs) - mTimeSourceDeltaUs;
-
- int64_t latenessUs = nowUs - timeUs;
-
- ATRACE_INT("Video Lateness (ms)", latenessUs / 1E3);
-
- if (latenessUs > 0) {
- ALOGI("after SEEK_VIDEO_ONLY we're late by %.2f secs", latenessUs / 1E6);
- }
- }
-
- int64_t latenessUs = 0;
- if (wasSeeking == NO_SEEK) {
- // Let's display the first frame after seeking right away.
-
- int64_t nowUs = estimateRealTimeUs(ts, systemTimeUs) - mTimeSourceDeltaUs;
-
- latenessUs = nowUs - timeUs;
-
- ATRACE_INT("Video Lateness (ms)", latenessUs / 1E3);
-
- if (latenessUs > 500000ll
- && mAudioPlayer != NULL
- && mAudioPlayer->getMediaTimeMapping(
- &realTimeUs, &mediaTimeUs)) {
- if (mWVMExtractor == NULL) {
- ALOGI("we're much too late (%.2f secs), video skipping ahead",
- latenessUs / 1E6);
-
- mVideoBuffer->release();
- mVideoBuffer = NULL;
-
- mSeeking = SEEK_VIDEO_ONLY;
- mSeekTimeUs = mediaTimeUs;
-
- postVideoEvent_l();
- return;
- } else {
- // The widevine extractor doesn't deal well with seeking
- // audio and video independently. We'll just have to wait
- // until the decoder catches up, which won't be long at all.
- ALOGI("we're very late (%.2f secs)", latenessUs / 1E6);
- }
- }
-
- if (latenessUs > 40000) {
- // We're more than 40ms late.
- ALOGV("we're late by %" PRId64 " us (%.2f secs)",
- latenessUs, latenessUs / 1E6);
-
- if (!(mFlags & SLOW_DECODER_HACK)
- || mSinceLastDropped > FRAME_DROP_FREQ)
- {
- ALOGV("we're late by %" PRId64 " us (%.2f secs) dropping "
- "one after %d frames",
- latenessUs, latenessUs / 1E6, mSinceLastDropped);
-
- mSinceLastDropped = 0;
- mVideoBuffer->release();
- mVideoBuffer = NULL;
-
- {
- Mutex::Autolock autoLock(mStatsLock);
- ++mStats.mNumVideoFramesDropped;
- }
-
- postVideoEvent_l(0);
- return;
- }
- }
-
- if (latenessUs < -30000) {
- // We're more than 30ms early, schedule at most 20 ms before time due
- postVideoEvent_l(latenessUs < -60000 ? 30000 : -latenessUs - 20000);
- return;
- }
- }
-
- if ((mNativeWindow != NULL)
- && (mVideoRendererIsPreview || mVideoRenderer == NULL)) {
- mVideoRendererIsPreview = false;
-
- initRenderer_l();
- }
-
- if (mVideoRenderer != NULL) {
- mSinceLastDropped++;
- mVideoBuffer->meta_data()->setInt64(kKeyTime, looperTimeUs - latenessUs);
-
- mVideoRenderer->render(mVideoBuffer);
- if (!mVideoRenderingStarted) {
- mVideoRenderingStarted = true;
- notifyListener_l(MEDIA_INFO, MEDIA_INFO_RENDERING_START);
- }
-
- if (mFlags & PLAYING) {
- notifyIfMediaStarted_l();
- }
- }
-
- mVideoBuffer->release();
- mVideoBuffer = NULL;
-
- if (wasSeeking != NO_SEEK && (mFlags & SEEK_PREVIEW)) {
- modifyFlags(SEEK_PREVIEW, CLEAR);
- return;
- }
-
- /* get next frame time */
- if (wasSeeking == NO_SEEK) {
- MediaSource::ReadOptions options;
- for (;;) {
- status_t err = mVideoSource->read(&mVideoBuffer, &options);
- if (err != OK) {
- // deal with any errors next time
- CHECK(mVideoBuffer == NULL);
- postVideoEvent_l(0);
- return;
- }
-
- if (mVideoBuffer->range_length() != 0) {
- break;
- }
-
- // Some decoders, notably the PV AVC software decoder
- // return spurious empty buffers that we just want to ignore.
-
- mVideoBuffer->release();
- mVideoBuffer = NULL;
- }
-
- {
- Mutex::Autolock autoLock(mStatsLock);
- ++mStats.mNumVideoFramesDecoded;
- }
-
- int64_t nextTimeUs;
- CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &nextTimeUs));
- systemTimeUs = mSystemTimeSource.getRealTimeUs();
- int64_t delayUs = nextTimeUs - estimateRealTimeUs(ts, systemTimeUs) + mTimeSourceDeltaUs;
- ATRACE_INT("Frame delta (ms)", (nextTimeUs - timeUs) / 1E3);
- ALOGV("next frame in %" PRId64, delayUs);
- // try to schedule 30ms before time due
- postVideoEvent_l(delayUs > 60000 ? 30000 : (delayUs < 30000 ? 0 : delayUs - 30000));
- return;
- }
-
- postVideoEvent_l();
-}
-
-int64_t AwesomePlayer::estimateRealTimeUs(TimeSource *ts, int64_t systemTimeUs) {
- if (ts == &mSystemTimeSource) {
- return systemTimeUs;
- } else {
- return (int64_t)mClockEstimator->estimate(systemTimeUs, ts->getRealTimeUs());
- }
-}
-
-void AwesomePlayer::postVideoEvent_l(int64_t delayUs) {
- ATRACE_CALL();
-
- if (mVideoEventPending) {
- return;
- }
-
- mVideoEventPending = true;
- mQueue.postEventWithDelay(mVideoEvent, delayUs < 0 ? 10000 : delayUs);
-}
-
-void AwesomePlayer::postStreamDoneEvent_l(status_t status) {
- if (mStreamDoneEventPending) {
- return;
- }
- mStreamDoneEventPending = true;
-
- mStreamDoneStatus = status;
- mQueue.postEvent(mStreamDoneEvent);
-}
-
-void AwesomePlayer::postBufferingEvent_l() {
- if (mBufferingEventPending) {
- return;
- }
- mBufferingEventPending = true;
- mQueue.postEventWithDelay(mBufferingEvent, 1000000ll);
-}
-
-void AwesomePlayer::postVideoLagEvent_l() {
- if (mVideoLagEventPending) {
- return;
- }
- mVideoLagEventPending = true;
- mQueue.postEventWithDelay(mVideoLagEvent, 1000000ll);
-}
-
-void AwesomePlayer::postCheckAudioStatusEvent(int64_t delayUs) {
- Mutex::Autolock autoLock(mAudioLock);
- if (mAudioStatusEventPending) {
- return;
- }
- mAudioStatusEventPending = true;
- // Do not honor delay when looping in order to limit audio gap
- if (mFlags & (LOOPING | AUTO_LOOPING)) {
- delayUs = 0;
- }
- mQueue.postEventWithDelay(mCheckAudioStatusEvent, delayUs);
-}
-
-void AwesomePlayer::postAudioTearDownEvent(int64_t delayUs) {
- Mutex::Autolock autoLock(mAudioLock);
- if (mAudioTearDownEventPending) {
- return;
- }
- mAudioTearDownEventPending = true;
- mQueue.postEventWithDelay(mAudioTearDownEvent, delayUs);
-}
-
-void AwesomePlayer::onCheckAudioStatus() {
- {
- Mutex::Autolock autoLock(mAudioLock);
- if (!mAudioStatusEventPending) {
- // Event was dispatched and while we were blocking on the mutex,
- // has already been cancelled.
- return;
- }
-
- mAudioStatusEventPending = false;
- }
-
- Mutex::Autolock autoLock(mLock);
-
- if (mWatchForAudioSeekComplete && !mAudioPlayer->isSeeking()) {
- mWatchForAudioSeekComplete = false;
-
- if (!mSeekNotificationSent) {
- notifyListener_l(MEDIA_SEEK_COMPLETE);
- mSeekNotificationSent = true;
- }
-
- if (mVideoSource == NULL) {
- // For video the mSeeking flag is always reset in finishSeekIfNecessary
- mSeeking = NO_SEEK;
- }
-
- notifyIfMediaStarted_l();
- }
-
- status_t finalStatus;
- if (mWatchForAudioEOS && mAudioPlayer->reachedEOS(&finalStatus)) {
- mWatchForAudioEOS = false;
- modifyFlags(AUDIO_AT_EOS, SET);
- modifyFlags(FIRST_FRAME, SET);
- postStreamDoneEvent_l(finalStatus);
- }
-}
-
-status_t AwesomePlayer::prepare() {
- ATRACE_CALL();
- Mutex::Autolock autoLock(mLock);
- return prepare_l();
-}
-
-status_t AwesomePlayer::prepare_l() {
- if (mFlags & PREPARED) {
- return OK;
- }
-
- if (mFlags & PREPARING) {
- return UNKNOWN_ERROR;
- }
-
- mIsAsyncPrepare = false;
- status_t err = prepareAsync_l();
-
- if (err != OK) {
- return err;
- }
-
- while (mFlags & PREPARING) {
- mPreparedCondition.wait(mLock);
- }
-
- return mPrepareResult;
-}
-
-status_t AwesomePlayer::prepareAsync() {
- ATRACE_CALL();
- Mutex::Autolock autoLock(mLock);
-
- if (mFlags & PREPARING) {
- return UNKNOWN_ERROR; // async prepare already pending
- }
-
- mIsAsyncPrepare = true;
- return prepareAsync_l();
-}
-
-status_t AwesomePlayer::prepareAsync_l() {
- if (mFlags & PREPARING) {
- return UNKNOWN_ERROR; // async prepare already pending
- }
-
- if (!mQueueStarted) {
- mQueue.start();
- mQueueStarted = true;
- }
-
- modifyFlags(PREPARING, SET);
- mAsyncPrepareEvent = new AwesomeEvent(
- this, &AwesomePlayer::onPrepareAsyncEvent);
-
- mQueue.postEvent(mAsyncPrepareEvent);
-
- return OK;
-}
-
-status_t AwesomePlayer::finishSetDataSource_l() {
- ATRACE_CALL();
- sp<DataSource> dataSource;
-
- bool isWidevineStreaming = false;
- if (!strncasecmp("widevine://", mUri.string(), 11)) {
- isWidevineStreaming = true;
-
- String8 newURI = String8("http://");
- newURI.append(mUri.string() + 11);
-
- mUri = newURI;
- }
-
- AString sniffedMIME;
-
- if (!strncasecmp("http://", mUri.string(), 7)
- || !strncasecmp("https://", mUri.string(), 8)
- || isWidevineStreaming) {
- if (mHTTPService == NULL) {
- ALOGE("Attempt to play media from http URI without HTTP service.");
- return UNKNOWN_ERROR;
- }
-
- sp<IMediaHTTPConnection> conn = mHTTPService->makeHTTPConnection();
- mConnectingDataSource = new MediaHTTP(conn);
-
- String8 cacheConfig;
- bool disconnectAtHighwatermark;
- NuCachedSource2::RemoveCacheSpecificHeaders(
- &mUriHeaders, &cacheConfig, &disconnectAtHighwatermark);
-
- mLock.unlock();
- status_t err = mConnectingDataSource->connect(mUri, &mUriHeaders);
- // force connection at this point, to avoid a race condition between getMIMEType and the
- // caching datasource constructed below, which could result in multiple requests to the
- // server, and/or failed connections.
- String8 contentType = mConnectingDataSource->getMIMEType();
- mLock.lock();
-
- if (err != OK) {
- mConnectingDataSource.clear();
-
- ALOGI("mConnectingDataSource->connect() returned %d", err);
- return err;
- }
-
- if (!isWidevineStreaming) {
- // The widevine extractor does its own caching.
-
-#if 0
- mCachedSource = NuCachedSource2::Create(
- new ThrottledSource(
- mConnectingDataSource, 50 * 1024 /* bytes/sec */));
-#else
- mCachedSource = NuCachedSource2::Create(
- mConnectingDataSource,
- cacheConfig.isEmpty() ? NULL : cacheConfig.string(),
- disconnectAtHighwatermark);
-#endif
-
- dataSource = mCachedSource;
- } else {
- dataSource = mConnectingDataSource;
- }
-
- mConnectingDataSource.clear();
-
- if (strncasecmp(contentType.string(), "audio/", 6)) {
- // We're not doing this for streams that appear to be audio-only
- // streams to ensure that even low bandwidth streams start
- // playing back fairly instantly.
-
- // We're going to prefill the cache before trying to instantiate
- // the extractor below, as the latter is an operation that otherwise
- // could block on the datasource for a significant amount of time.
- // During that time we'd be unable to abort the preparation phase
- // without this prefill.
- if (mCachedSource != NULL) {
- // We're going to prefill the cache before trying to instantiate
- // the extractor below, as the latter is an operation that otherwise
- // could block on the datasource for a significant amount of time.
- // During that time we'd be unable to abort the preparation phase
- // without this prefill.
-
- mLock.unlock();
-
- // Initially make sure we have at least 192 KB for the sniff
- // to complete without blocking.
- static const size_t kMinBytesForSniffing = 192 * 1024;
-
- off64_t metaDataSize = -1ll;
- for (;;) {
- status_t finalStatus;
- size_t cachedDataRemaining =
- mCachedSource->approxDataRemaining(&finalStatus);
-
- if (finalStatus != OK
- || (metaDataSize >= 0
- && (off64_t)cachedDataRemaining >= metaDataSize)
- || (mFlags & PREPARE_CANCELLED)) {
- break;
- }
-
- ALOGV("now cached %zu bytes of data", cachedDataRemaining);
-
- if (metaDataSize < 0
- && cachedDataRemaining >= kMinBytesForSniffing) {
- String8 tmp;
- float confidence;
- sp<AMessage> meta;
- if (!dataSource->sniff(&tmp, &confidence, &meta)) {
- mLock.lock();
- return UNKNOWN_ERROR;
- }
-
- // We successfully identified the file's extractor to
- // be, remember this mime type so we don't have to
- // sniff it again when we call MediaExtractor::Create()
- // below.
- sniffedMIME = tmp.string();
-
- if (meta == NULL
- || !meta->findInt64("meta-data-size",
- reinterpret_cast<int64_t*>(&metaDataSize))) {
- metaDataSize = kHighWaterMarkBytes;
- }
-
- CHECK_GE(metaDataSize, 0ll);
- ALOGV("metaDataSize = %lld bytes", (long long)metaDataSize);
- }
-
- usleep(200000);
- }
-
- mLock.lock();
- }
-
- if (mFlags & PREPARE_CANCELLED) {
- ALOGI("Prepare cancelled while waiting for initial cache fill.");
- return UNKNOWN_ERROR;
- }
- }
- } else {
- dataSource = DataSource::CreateFromURI(
- mHTTPService, mUri.string(), &mUriHeaders);
- }
-
- if (dataSource == NULL) {
- return UNKNOWN_ERROR;
- }
-
- sp<IMediaExtractor> extractor;
-
- if (isWidevineStreaming) {
- String8 mimeType;
- float confidence;
- sp<AMessage> dummy;
- bool success;
-
- // SniffWVM is potentially blocking since it may require network access.
- // Do not call it with mLock held.
- mLock.unlock();
- success = SniffWVM(dataSource, &mimeType, &confidence, &dummy);
- mLock.lock();
-
- if (!success
- || strcasecmp(
- mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM)) {
- return ERROR_UNSUPPORTED;
- }
-
- mWVMExtractor = new WVMExtractor(dataSource);
- mWVMExtractor->setAdaptiveStreamingMode(true);
- if (mUIDValid)
- mWVMExtractor->setUID(mUID);
- extractor = mWVMExtractor;
- } else {
- extractor = MediaExtractor::Create(
- dataSource, sniffedMIME.empty() ? NULL : sniffedMIME.c_str());
-
- if (extractor == NULL) {
- return UNKNOWN_ERROR;
- }
- }
-
- if (extractor->getDrmFlag()) {
- checkDrmStatus(dataSource);
- }
-
- status_t err = setDataSource_l(extractor);
-
- if (err != OK) {
- mWVMExtractor.clear();
-
- return err;
- }
-
- return OK;
-}
-
-void AwesomePlayer::abortPrepare(status_t err) {
- CHECK(err != OK);
-
- if (mIsAsyncPrepare) {
- notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
- }
-
- mPrepareResult = err;
- modifyFlags((PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED), CLEAR);
- mAsyncPrepareEvent = NULL;
- mPreparedCondition.broadcast();
- mAudioTearDown = false;
-}
-
-// static
-bool AwesomePlayer::ContinuePreparation(void *cookie) {
- AwesomePlayer *me = static_cast<AwesomePlayer *>(cookie);
-
- return (me->mFlags & PREPARE_CANCELLED) == 0;
-}
-
-void AwesomePlayer::onPrepareAsyncEvent() {
- Mutex::Autolock autoLock(mLock);
- beginPrepareAsync_l();
-}
-
-void AwesomePlayer::beginPrepareAsync_l() {
- if (mFlags & PREPARE_CANCELLED) {
- ALOGI("prepare was cancelled before doing anything");
- abortPrepare(UNKNOWN_ERROR);
- return;
- }
-
- if (mUri.size() > 0) {
- status_t err = finishSetDataSource_l();
-
- if (err != OK) {
- abortPrepare(err);
- return;
- }
- }
-
- if (mVideoTrack != NULL && mVideoSource == NULL) {
- status_t err = initVideoDecoder();
-
- if (err != OK) {
- abortPrepare(err);
- return;
- }
- }
-
- if (mAudioTrack != NULL && mAudioSource == NULL) {
- status_t err = initAudioDecoder();
-
- if (err != OK) {
- abortPrepare(err);
- return;
- }
- }
-
- modifyFlags(PREPARING_CONNECTED, SET);
-
- if (isStreamingHTTP()) {
- postBufferingEvent_l();
- } else {
- finishAsyncPrepare_l();
- }
-}
-
-void AwesomePlayer::finishAsyncPrepare_l() {
- if (mIsAsyncPrepare) {
- if (mVideoSource == NULL) {
- notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0);
- } else {
- notifyVideoSize_l();
- }
-
- notifyListener_l(MEDIA_PREPARED);
- }
-
- mPrepareResult = OK;
- modifyFlags((PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED), CLEAR);
- modifyFlags(PREPARED, SET);
- mAsyncPrepareEvent = NULL;
- mPreparedCondition.broadcast();
-
- if (mAudioTearDown) {
- if (mPrepareResult == OK) {
- if (mExtractorFlags & MediaExtractor::CAN_SEEK) {
- seekTo_l(mAudioTearDownPosition);
- }
-
- if (mAudioTearDownWasPlaying) {
- modifyFlags(CACHE_UNDERRUN, CLEAR);
- play_l();
- }
- }
- mAudioTearDown = false;
- }
-}
-
-uint32_t AwesomePlayer::flags() const {
- return mExtractorFlags;
-}
-
-void AwesomePlayer::postAudioEOS(int64_t delayUs) {
- postCheckAudioStatusEvent(delayUs);
-}
-
-void AwesomePlayer::postAudioSeekComplete() {
- postCheckAudioStatusEvent(0);
-}
-
-void AwesomePlayer::postAudioTearDown() {
- postAudioTearDownEvent(0);
-}
-
-status_t AwesomePlayer::setParameter(int key, const Parcel &request) {
- switch (key) {
- case KEY_PARAMETER_CACHE_STAT_COLLECT_FREQ_MS:
- {
- return setCacheStatCollectFreq(request);
- }
- default:
- {
- return ERROR_UNSUPPORTED;
- }
- }
-}
-
-status_t AwesomePlayer::setCacheStatCollectFreq(const Parcel &request) {
- if (mCachedSource != NULL) {
- int32_t freqMs = request.readInt32();
- ALOGD("Request to keep cache stats in the past %d ms",
- freqMs);
- return mCachedSource->setCacheStatCollectFreq(freqMs);
- }
- return ERROR_UNSUPPORTED;
-}
-
-status_t AwesomePlayer::getParameter(int key, Parcel *reply) {
- switch (key) {
- case KEY_PARAMETER_AUDIO_CHANNEL_COUNT:
- {
- int32_t channelCount;
- if (mAudioTrack == 0 ||
- !mAudioTrack->getFormat()->findInt32(kKeyChannelCount, &channelCount)) {
- channelCount = 0;
- }
- reply->writeInt32(channelCount);
- }
- return OK;
- default:
- {
- return ERROR_UNSUPPORTED;
- }
- }
-}
-
-status_t AwesomePlayer::setPlaybackSettings(const AudioPlaybackRate &rate) {
- Mutex::Autolock autoLock(mLock);
- // cursory sanity check for non-audio and paused cases
- if ((rate.mSpeed != 0.f && rate.mSpeed < AUDIO_TIMESTRETCH_SPEED_MIN)
- || rate.mSpeed > AUDIO_TIMESTRETCH_SPEED_MAX
- || rate.mPitch < AUDIO_TIMESTRETCH_SPEED_MIN
- || rate.mPitch > AUDIO_TIMESTRETCH_SPEED_MAX) {
- return BAD_VALUE;
- }
-
- status_t err = OK;
- if (rate.mSpeed == 0.f) {
- if (mFlags & PLAYING) {
- modifyFlags(CACHE_UNDERRUN, CLEAR); // same as pause
- err = pause_l();
- }
- if (err == OK) {
- // save settings (using old speed) in case player is resumed
- AudioPlaybackRate newRate = rate;
- newRate.mSpeed = mPlaybackSettings.mSpeed;
- mPlaybackSettings = newRate;
- }
- return err;
- }
- if (mAudioPlayer != NULL) {
- err = mAudioPlayer->setPlaybackRate(rate);
- }
- if (err == OK) {
- mPlaybackSettings = rate;
- if (!(mFlags & PLAYING)) {
- play_l();
- }
- }
- return err;
-}
-
-status_t AwesomePlayer::getPlaybackSettings(AudioPlaybackRate *rate /* nonnull */) {
- if (mAudioPlayer != NULL) {
- status_t err = mAudioPlayer->getPlaybackRate(rate);
- if (err == OK) {
- mPlaybackSettings = *rate;
- Mutex::Autolock autoLock(mLock);
- if (!(mFlags & PLAYING)) {
- rate->mSpeed = 0.f;
- }
- }
- return err;
- }
- *rate = mPlaybackSettings;
- return OK;
-}
-
-status_t AwesomePlayer::getTrackInfo(Parcel *reply) const {
- Mutex::Autolock autoLock(mLock);
- size_t trackCount = mExtractor->countTracks();
- if (mTextDriver != NULL) {
- trackCount += mTextDriver->countExternalTracks();
- }
-
- reply->writeInt32(trackCount);
- for (size_t i = 0; i < mExtractor->countTracks(); ++i) {
- sp<MetaData> meta = mExtractor->getTrackMetaData(i);
-
- const char *_mime;
- CHECK(meta->findCString(kKeyMIMEType, &_mime));
-
- String8 mime = String8(_mime);
-
- reply->writeInt32(2); // 2 fields
-
- if (!strncasecmp(mime.string(), "video/", 6)) {
- reply->writeInt32(MEDIA_TRACK_TYPE_VIDEO);
- } else if (!strncasecmp(mime.string(), "audio/", 6)) {
- reply->writeInt32(MEDIA_TRACK_TYPE_AUDIO);
- } else if (!strcasecmp(mime.string(), MEDIA_MIMETYPE_TEXT_3GPP)) {
- reply->writeInt32(MEDIA_TRACK_TYPE_TIMEDTEXT);
- } else {
- reply->writeInt32(MEDIA_TRACK_TYPE_UNKNOWN);
- }
- reply->writeString16(String16(mime));
-
- const char *lang;
- if (!meta->findCString(kKeyMediaLanguage, &lang)) {
- lang = "und";
- }
- reply->writeString16(String16(lang));
- }
-
- if (mTextDriver != NULL) {
- mTextDriver->getExternalTrackInfo(reply);
- }
- return OK;
-}
-
-status_t AwesomePlayer::selectAudioTrack_l(
- const sp<IMediaSource>& source, size_t trackIndex) {
-
- ALOGI("selectAudioTrack_l: trackIndex=%zu, mFlags=0x%x", trackIndex, mFlags);
-
- {
- Mutex::Autolock autoLock(mStatsLock);
- if ((ssize_t)trackIndex == mActiveAudioTrackIndex) {
- ALOGI("Track %zu is active. Does nothing.", trackIndex);
- return OK;
- }
- //mStats.mFlags = mFlags;
- }
-
- if (mSeeking != NO_SEEK) {
- ALOGE("Selecting a track while seeking is not supported");
- return ERROR_UNSUPPORTED;
- }
-
- if ((mFlags & PREPARED) == 0) {
- ALOGE("Data source has not finished preparation");
- return ERROR_UNSUPPORTED;
- }
-
- CHECK(source != NULL);
- bool wasPlaying = (mFlags & PLAYING) != 0;
-
- pause_l();
-
- int64_t curTimeUs;
- CHECK_EQ(getPosition(&curTimeUs), (status_t)OK);
-
- if ((mAudioPlayer == NULL || !(mFlags & AUDIOPLAYER_STARTED))
- && mAudioSource != NULL) {
- // If we had an audio player, it would have effectively
- // taken possession of the audio source and stopped it when
- // _it_ is stopped. Otherwise this is still our responsibility.
- mAudioSource->stop();
- }
- mAudioSource.clear();
- mOmxSource.clear();
-
- mTimeSource = NULL;
-
- delete mAudioPlayer;
- mAudioPlayer = NULL;
-
- modifyFlags(AUDIOPLAYER_STARTED, CLEAR);
-
- setAudioSource(source);
-
- modifyFlags(AUDIO_AT_EOS, CLEAR);
- modifyFlags(AT_EOS, CLEAR);
-
- status_t err;
- if ((err = initAudioDecoder()) != OK) {
- ALOGE("Failed to init audio decoder: 0x%x", err);
- return err;
- }
-
- mSeekNotificationSent = true;
- seekTo_l(curTimeUs);
-
- if (wasPlaying) {
- play_l();
- }
-
- mActiveAudioTrackIndex = trackIndex;
-
- return OK;
-}
-
-status_t AwesomePlayer::selectTrack(size_t trackIndex, bool select) {
- ATRACE_CALL();
- ALOGV("selectTrack: trackIndex = %zu and select=%d", trackIndex, select);
- Mutex::Autolock autoLock(mLock);
- size_t trackCount = mExtractor->countTracks();
- if (mTextDriver != NULL) {
- trackCount += mTextDriver->countExternalTracks();
- }
- if (trackIndex >= trackCount) {
- ALOGE("Track index (%zu) is out of range [0, %zu)", trackIndex, trackCount);
- return ERROR_OUT_OF_RANGE;
- }
-
- bool isAudioTrack = false;
- if (trackIndex < mExtractor->countTracks()) {
- sp<MetaData> meta = mExtractor->getTrackMetaData(trackIndex);
- const char *mime;
- CHECK(meta->findCString(kKeyMIMEType, &mime));
- isAudioTrack = !strncasecmp(mime, "audio/", 6);
-
- if (!isAudioTrack && strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP) != 0) {
- ALOGE("Track %zu is not either audio or timed text", trackIndex);
- return ERROR_UNSUPPORTED;
- }
- }
-
- if (isAudioTrack) {
- if (!select) {
- ALOGE("Deselect an audio track (%zu) is not supported", trackIndex);
- return ERROR_UNSUPPORTED;
- }
- return selectAudioTrack_l(mExtractor->getTrack(trackIndex), trackIndex);
- }
-
- // Timed text track handling
- if (mTextDriver == NULL) {
- return INVALID_OPERATION;
- }
-
- status_t err = OK;
- if (select) {
- err = mTextDriver->selectTrack(trackIndex);
- if (err == OK) {
- modifyFlags(TEXTPLAYER_INITIALIZED, SET);
- if (mFlags & PLAYING && !(mFlags & TEXT_RUNNING)) {
- mTextDriver->start();
- modifyFlags(TEXT_RUNNING, SET);
- }
- mSelectedTimedTextTrack = trackIndex;
- }
- } else {
- err = mTextDriver->unselectTrack(trackIndex);
- if (err == OK) {
- modifyFlags(TEXTPLAYER_INITIALIZED, CLEAR);
- modifyFlags(TEXT_RUNNING, CLEAR);
- mSelectedTimedTextTrack = -1;
- }
- }
- return err;
-}
-
-size_t AwesomePlayer::countTracks() const {
- return mExtractor->countTracks() + mTextDriver->countExternalTracks();
-}
-
-status_t AwesomePlayer::setVideoScalingMode(int32_t mode) {
- Mutex::Autolock lock(mLock);
- return setVideoScalingMode_l(mode);
-}
-
-status_t AwesomePlayer::setVideoScalingMode_l(int32_t mode) {
- mVideoScalingMode = mode;
- if (mNativeWindow != NULL) {
- status_t err = native_window_set_scaling_mode(
- mNativeWindow.get(), mVideoScalingMode);
- if (err != OK) {
- ALOGW("Failed to set scaling mode: %d", err);
- }
- return err;
- }
- return OK;
-}
-
-status_t AwesomePlayer::invoke(const Parcel &request, Parcel *reply) {
- ATRACE_CALL();
- if (NULL == reply) {
- return android::BAD_VALUE;
- }
- int32_t methodId;
- status_t ret = request.readInt32(&methodId);
- if (ret != android::OK) {
- return ret;
- }
- switch(methodId) {
- case INVOKE_ID_SET_VIDEO_SCALING_MODE:
- {
- int mode = request.readInt32();
- return setVideoScalingMode(mode);
- }
-
- case INVOKE_ID_GET_TRACK_INFO:
- {
- return getTrackInfo(reply);
- }
- case INVOKE_ID_ADD_EXTERNAL_SOURCE:
- {
- Mutex::Autolock autoLock(mLock);
- if (mTextDriver == NULL) {
- mTextDriver = new TimedTextDriver(mListener, mHTTPService);
- }
- // String values written in Parcel are UTF-16 values.
- String8 uri(request.readString16());
- String8 mimeType(request.readString16());
- size_t nTracks = countTracks();
- return mTextDriver->addOutOfBandTextSource(nTracks, uri, mimeType);
- }
- case INVOKE_ID_ADD_EXTERNAL_SOURCE_FD:
- {
- Mutex::Autolock autoLock(mLock);
- if (mTextDriver == NULL) {
- mTextDriver = new TimedTextDriver(mListener, mHTTPService);
- }
- int fd = request.readFileDescriptor();
- off64_t offset = request.readInt64();
- off64_t length = request.readInt64();
- String8 mimeType(request.readString16());
- size_t nTracks = countTracks();
- return mTextDriver->addOutOfBandTextSource(
- nTracks, fd, offset, length, mimeType);
- }
- case INVOKE_ID_SELECT_TRACK:
- {
- int trackIndex = request.readInt32();
- return selectTrack(trackIndex, true /* select */);
- }
- case INVOKE_ID_UNSELECT_TRACK:
- {
- int trackIndex = request.readInt32();
- return selectTrack(trackIndex, false /* select */);
- }
- case INVOKE_ID_GET_SELECTED_TRACK:
- {
- int trackType = request.readInt32();
- if (trackType == MEDIA_TRACK_TYPE_TIMEDTEXT) {
- reply->writeInt32(mSelectedTimedTextTrack);
- return mSelectedTimedTextTrack;
- }
-
- }
- default:
- {
- return ERROR_UNSUPPORTED;
- }
- }
- // It will not reach here.
- return OK;
-}
-
-bool AwesomePlayer::isStreamingHTTP() const {
- return mCachedSource != NULL || mWVMExtractor != NULL;
-}
-
-status_t AwesomePlayer::dump(
- int fd, const Vector<String16> & /* args */) const {
- Mutex::Autolock autoLock(mStatsLock);
-
- FILE *out = fdopen(dup(fd), "w");
-
- fprintf(out, " AwesomePlayer\n");
- if (mStats.mFd < 0) {
- fprintf(out, " URI(%s)", uriDebugString(mUri, mFlags & INCOGNITO).c_str());
- } else {
- fprintf(out, " fd(%d)", mStats.mFd);
- }
-
- fprintf(out, ", flags(0x%08x)", mStats.mFlags);
-
- if (mStats.mBitrate >= 0) {
- fprintf(out, ", bitrate(%" PRId64 " bps)", mStats.mBitrate);
- }
-
- fprintf(out, "\n");
-
- for (size_t i = 0; i < mStats.mTracks.size(); ++i) {
- const TrackStat &stat = mStats.mTracks.itemAt(i);
-
- fprintf(out, " Track %zu\n", i + 1);
- fprintf(out, " MIME(%s)", stat.mMIME.string());
-
- if (!stat.mDecoderName.isEmpty()) {
- fprintf(out, ", decoder(%s)", stat.mDecoderName.string());
- }
-
- fprintf(out, "\n");
-
- if ((ssize_t)i == mStats.mVideoTrackIndex) {
- fprintf(out,
- " videoDimensions(%d x %d), "
- "numVideoFramesDecoded(%" PRId64 "), "
- "numVideoFramesDropped(%" PRId64 ")\n",
- mStats.mVideoWidth,
- mStats.mVideoHeight,
- mStats.mNumVideoFramesDecoded,
- mStats.mNumVideoFramesDropped);
- }
- }
-
- fclose(out);
- out = NULL;
-
- return OK;
-}
-
-void AwesomePlayer::modifyFlags(unsigned value, FlagMode mode) {
- switch (mode) {
- case SET:
- mFlags |= value;
- break;
- case CLEAR:
- if ((value & CACHE_UNDERRUN) && (mFlags & CACHE_UNDERRUN)) {
- notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
- }
- mFlags &= ~value;
- break;
- case ASSIGN:
- mFlags = value;
- break;
- default:
- TRESPASS();
- }
-
- {
- Mutex::Autolock autoLock(mStatsLock);
- mStats.mFlags = mFlags;
- }
-}
-
-void AwesomePlayer::onAudioTearDownEvent() {
-
- Mutex::Autolock autoLock(mLock);
- if (!mAudioTearDownEventPending) {
- return;
- }
- mAudioTearDownEventPending = false;
-
- ALOGV("onAudioTearDownEvent");
-
- // stream info is cleared by reset_l() so copy what we need
- mAudioTearDownWasPlaying = (mFlags & PLAYING);
- KeyedVector<String8, String8> uriHeaders(mUriHeaders);
- sp<DataSource> fileSource(mFileSource);
-
- mStatsLock.lock();
- String8 uri(mStats.mURI);
- mStatsLock.unlock();
-
- // get current position so we can start recreated stream from here
- getPosition(&mAudioTearDownPosition);
-
- sp<IMediaHTTPService> savedHTTPService = mHTTPService;
-
- bool wasLooping = mFlags & LOOPING;
- // Reset and recreate
- reset_l();
-
- status_t err;
-
- if (fileSource != NULL) {
- mFileSource = fileSource;
- err = setDataSource_l(fileSource);
- } else {
- err = setDataSource_l(savedHTTPService, uri, &uriHeaders);
- }
-
- mFlags |= PREPARING;
- if ( err != OK ) {
- // This will force beingPrepareAsync_l() to notify
- // a MEDIA_ERROR to the client and abort the prepare
- mFlags |= PREPARE_CANCELLED;
- }
- if (wasLooping) {
- mFlags |= LOOPING;
- }
-
- mAudioTearDown = true;
- mIsAsyncPrepare = true;
-
- // Call prepare for the host decoding
- beginPrepareAsync_l();
-}
-
-} // namespace android
diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
index 8809640..dd7f6b9 100644
--- a/media/libstagefright/NuMediaExtractor.cpp
+++ b/media/libstagefright/NuMediaExtractor.cpp
@@ -110,7 +110,8 @@
// at the container mime type.
// The cryptoPluginMode ensures that the extractor will actually
// give us data in a call to MediaSource::read(), unlike its
- // default mode that we use from AwesomePlayer.
+ // default mode that we used in AwesomePlayer.
+ // TODO: change default mode
static_cast<WVMExtractor *>(mImpl.get())->setCryptoPluginMode(true);
} else if (mImpl->getDrmFlag()) {
// For all other drm content, we don't want to expose decrypted
diff --git a/media/libstagefright/TimedEventQueue.cpp b/media/libstagefright/TimedEventQueue.cpp
deleted file mode 100644
index 7d15220..0000000
--- a/media/libstagefright/TimedEventQueue.cpp
+++ /dev/null
@@ -1,386 +0,0 @@
-/*
- * Copyright (C) 2009 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.
- */
-
-#undef __STRICT_ANSI__
-#define __STDINT_LIMITS
-#define __STDC_LIMIT_MACROS
-
-#include <inttypes.h>
-#include <stdint.h>
-#include <sys/prctl.h>
-#include <sys/time.h>
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "TimedEventQueue"
-#include <utils/Log.h>
-#include <utils/threads.h>
-
-#include "include/TimedEventQueue.h"
-
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/ALooper.h>
-#include <binder/IServiceManager.h>
-#include <powermanager/PowerManager.h>
-#include <binder/IPCThreadState.h>
-#include <utils/CallStack.h>
-
-namespace android {
-
-static int64_t kWakelockMinDelay = 100000ll; // 100ms
-
-TimedEventQueue::TimedEventQueue()
- : mNextEventID(1),
- mRunning(false),
- mStopped(false),
- mDeathRecipient(new PMDeathRecipient(this)),
- mWakeLockCount(0) {
-}
-
-TimedEventQueue::~TimedEventQueue() {
- stop();
- if (mPowerManager != 0) {
- sp<IBinder> binder = IInterface::asBinder(mPowerManager);
- binder->unlinkToDeath(mDeathRecipient);
- }
-}
-
-void TimedEventQueue::start() {
- if (mRunning) {
- return;
- }
-
- mStopped = false;
-
- pthread_attr_t attr;
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
-
- pthread_create(&mThread, &attr, ThreadWrapper, this);
-
- pthread_attr_destroy(&attr);
-
- mRunning = true;
-}
-
-void TimedEventQueue::stop(bool flush) {
- if (!mRunning) {
- return;
- }
-
- if (flush) {
- postEventToBack(new StopEvent);
- } else {
- postTimedEvent(new StopEvent, INT64_MIN);
- }
-
- void *dummy;
- pthread_join(mThread, &dummy);
-
- // some events may be left in the queue if we did not flush and the wake lock
- // must be released.
- releaseWakeLock_l(true /*force*/);
- mQueue.clear();
-
- mRunning = false;
-}
-
-TimedEventQueue::event_id TimedEventQueue::postEvent(const sp<Event> &event) {
- // Reserve an earlier timeslot an INT64_MIN to be able to post
- // the StopEvent to the absolute head of the queue.
- return postTimedEvent(event, INT64_MIN + 1);
-}
-
-TimedEventQueue::event_id TimedEventQueue::postEventToBack(
- const sp<Event> &event) {
- return postTimedEvent(event, INT64_MAX);
-}
-
-TimedEventQueue::event_id TimedEventQueue::postEventWithDelay(
- const sp<Event> &event, int64_t delay_us) {
- CHECK(delay_us >= 0);
- return postTimedEvent(event, ALooper::GetNowUs() + delay_us);
-}
-
-TimedEventQueue::event_id TimedEventQueue::postTimedEvent(
- const sp<Event> &event, int64_t realtime_us) {
- Mutex::Autolock autoLock(mLock);
-
- event->setEventID(mNextEventID++);
-
- List<QueueItem>::iterator it = mQueue.begin();
- while (it != mQueue.end() && realtime_us >= (*it).realtime_us) {
- ++it;
- }
-
- QueueItem item;
- item.event = event;
- item.realtime_us = realtime_us;
- item.has_wakelock = false;
-
- if (it == mQueue.begin()) {
- mQueueHeadChangedCondition.signal();
- }
-
- if (realtime_us > ALooper::GetNowUs() + kWakelockMinDelay) {
- acquireWakeLock_l();
- item.has_wakelock = true;
- }
- mQueue.insert(it, item);
-
- mQueueNotEmptyCondition.signal();
-
- return event->eventID();
-}
-
-static bool MatchesEventID(
- void *cookie, const sp<TimedEventQueue::Event> &event) {
- TimedEventQueue::event_id *id =
- static_cast<TimedEventQueue::event_id *>(cookie);
-
- if (event->eventID() != *id) {
- return false;
- }
-
- *id = 0;
-
- return true;
-}
-
-bool TimedEventQueue::cancelEvent(event_id id) {
- if (id == 0) {
- return false;
- }
-
- cancelEvents(&MatchesEventID, &id, true /* stopAfterFirstMatch */);
-
- // if MatchesEventID found a match, it will have set id to 0
- // (which is not a valid event_id).
-
- return id == 0;
-}
-
-void TimedEventQueue::cancelEvents(
- bool (*predicate)(void *cookie, const sp<Event> &event),
- void *cookie,
- bool stopAfterFirstMatch) {
- Mutex::Autolock autoLock(mLock);
-
- List<QueueItem>::iterator it = mQueue.begin();
- while (it != mQueue.end()) {
- if (!(*predicate)(cookie, (*it).event)) {
- ++it;
- continue;
- }
-
- if (it == mQueue.begin()) {
- mQueueHeadChangedCondition.signal();
- }
-
- ALOGV("cancelling event %d", (*it).event->eventID());
-
- (*it).event->setEventID(0);
- if ((*it).has_wakelock) {
- releaseWakeLock_l();
- }
- it = mQueue.erase(it);
- if (stopAfterFirstMatch) {
- return;
- }
- }
-}
-
-// static
-void *TimedEventQueue::ThreadWrapper(void *me) {
-
- androidSetThreadPriority(0, ANDROID_PRIORITY_FOREGROUND);
-
- static_cast<TimedEventQueue *>(me)->threadEntry();
-
- return NULL;
-}
-
-void TimedEventQueue::threadEntry() {
- prctl(PR_SET_NAME, (unsigned long)"TimedEventQueue", 0, 0, 0);
-
- for (;;) {
- int64_t now_us = 0;
- sp<Event> event;
- bool wakeLocked = false;
-
- {
- Mutex::Autolock autoLock(mLock);
-
- if (mStopped) {
- break;
- }
-
- while (mQueue.empty()) {
- mQueueNotEmptyCondition.wait(mLock);
- }
-
- event_id eventID = 0;
- for (;;) {
- if (mQueue.empty()) {
- // The only event in the queue could have been cancelled
- // while we were waiting for its scheduled time.
- break;
- }
-
- List<QueueItem>::iterator it = mQueue.begin();
- eventID = (*it).event->eventID();
-
- now_us = ALooper::GetNowUs();
- int64_t when_us = (*it).realtime_us;
-
- int64_t delay_us;
- if (when_us < 0 || when_us == INT64_MAX) {
- delay_us = 0;
- } else {
- delay_us = when_us - now_us;
- }
-
- if (delay_us <= 0) {
- break;
- }
-
- static int64_t kMaxTimeoutUs = 10000000ll; // 10 secs
- bool timeoutCapped = false;
- if (delay_us > kMaxTimeoutUs) {
- ALOGW("delay_us exceeds max timeout: %" PRId64 " us", delay_us);
-
- // We'll never block for more than 10 secs, instead
- // we will split up the full timeout into chunks of
- // 10 secs at a time. This will also avoid overflow
- // when converting from us to ns.
- delay_us = kMaxTimeoutUs;
- timeoutCapped = true;
- }
-
- status_t err = mQueueHeadChangedCondition.waitRelative(
- mLock, delay_us * 1000ll);
-
- if (!timeoutCapped && err == -ETIMEDOUT) {
- // We finally hit the time this event is supposed to
- // trigger.
- now_us = ALooper::GetNowUs();
- break;
- }
- }
-
- // The event w/ this id may have been cancelled while we're
- // waiting for its trigger-time, in that case
- // removeEventFromQueue_l will return NULL.
- // Otherwise, the QueueItem will be removed
- // from the queue and the referenced event returned.
- event = removeEventFromQueue_l(eventID, &wakeLocked);
- }
-
- if (event != NULL) {
- // Fire event with the lock NOT held.
- event->fire(this, now_us);
- if (wakeLocked) {
- Mutex::Autolock autoLock(mLock);
- releaseWakeLock_l();
- }
- }
- }
-}
-
-sp<TimedEventQueue::Event> TimedEventQueue::removeEventFromQueue_l(
- event_id id, bool *wakeLocked) {
- for (List<QueueItem>::iterator it = mQueue.begin();
- it != mQueue.end(); ++it) {
- if ((*it).event->eventID() == id) {
- sp<Event> event = (*it).event;
- event->setEventID(0);
- *wakeLocked = (*it).has_wakelock;
- mQueue.erase(it);
- return event;
- }
- }
-
- ALOGW("Event %d was not found in the queue, already cancelled?", id);
-
- return NULL;
-}
-
-void TimedEventQueue::acquireWakeLock_l()
-{
- if (mWakeLockCount == 0) {
- CHECK(mWakeLockToken == 0);
- if (mPowerManager == 0) {
- // use checkService() to avoid blocking if power service is not up yet
- sp<IBinder> binder =
- defaultServiceManager()->checkService(String16("power"));
- if (binder == 0) {
- ALOGW("cannot connect to the power manager service");
- } else {
- mPowerManager = interface_cast<IPowerManager>(binder);
- binder->linkToDeath(mDeathRecipient);
- }
- }
- if (mPowerManager != 0) {
- sp<IBinder> binder = new BBinder();
- int64_t token = IPCThreadState::self()->clearCallingIdentity();
- status_t status = mPowerManager->acquireWakeLock(POWERMANAGER_PARTIAL_WAKE_LOCK,
- binder,
- String16("TimedEventQueue"),
- String16("media")); // not oneway
- IPCThreadState::self()->restoreCallingIdentity(token);
- if (status == NO_ERROR) {
- mWakeLockToken = binder;
- mWakeLockCount++;
- }
- }
- } else {
- mWakeLockCount++;
- }
-}
-
-void TimedEventQueue::releaseWakeLock_l(bool force)
-{
- if (mWakeLockCount == 0) {
- return;
- }
- if (force) {
- // Force wakelock release below by setting reference count to 1.
- mWakeLockCount = 1;
- }
- if (--mWakeLockCount == 0) {
- CHECK(mWakeLockToken != 0);
- if (mPowerManager != 0) {
- int64_t token = IPCThreadState::self()->clearCallingIdentity();
- mPowerManager->releaseWakeLock(mWakeLockToken, 0); // not oneway
- IPCThreadState::self()->restoreCallingIdentity(token);
- }
- mWakeLockToken.clear();
- }
-}
-
-void TimedEventQueue::clearPowerManager()
-{
- Mutex::Autolock _l(mLock);
- releaseWakeLock_l(true /*force*/);
- mPowerManager.clear();
-}
-
-void TimedEventQueue::PMDeathRecipient::binderDied(
- const wp<IBinder>& /* who */) {
- mQueue->clearPowerManager();
-}
-
-} // namespace android
-
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
deleted file mode 100644
index 1204ee8..0000000
--- a/media/libstagefright/include/AwesomePlayer.h
+++ /dev/null
@@ -1,376 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef AWESOME_PLAYER_H_
-
-#define AWESOME_PLAYER_H_
-
-#include "HTTPBase.h"
-#include "TimedEventQueue.h"
-
-#include <media/AudioResamplerPublic.h>
-#include <media/MediaPlayerInterface.h>
-#include <media/IMediaExtractor.h>
-#include <media/stagefright/DataSource.h>
-#include <media/stagefright/OMXClient.h>
-#include <media/stagefright/TimeSource.h>
-#include <media/stagefright/MetaData.h>
-#include <utils/threads.h>
-#include <drm/DrmManagerClient.h>
-
-namespace android {
-
-class AudioPlayer;
-struct ClockEstimator;
-class IDataSource;
-class MediaBuffer;
-struct NuCachedSource2;
-class IGraphicBufferProducer;
-
-class DrmManagerClinet;
-class DecryptHandle;
-
-class TimedTextDriver;
-class WVMExtractor;
-
-struct AwesomeRenderer : public RefBase {
- AwesomeRenderer() {}
-
- virtual void render(MediaBuffer *buffer) = 0;
-
-private:
- AwesomeRenderer(const AwesomeRenderer &);
- AwesomeRenderer &operator=(const AwesomeRenderer &);
-};
-
-struct AwesomePlayer {
- AwesomePlayer();
- ~AwesomePlayer();
-
- void setListener(const wp<MediaPlayerBase> &listener);
- void setUID(uid_t uid);
-
- status_t setDataSource(
- const sp<IMediaHTTPService> &httpService,
- const char *uri,
- const KeyedVector<String8, String8> *headers = NULL);
-
- status_t setDataSource(int fd, int64_t offset, int64_t length);
-
- status_t setDataSource(const sp<IStreamSource> &source);
-
- void reset();
-
- status_t prepare();
- status_t prepare_l();
- status_t prepareAsync();
- status_t prepareAsync_l();
-
- status_t play();
- status_t pause();
-
- bool isPlaying() const;
-
- status_t setSurfaceTexture(const sp<IGraphicBufferProducer> &bufferProducer);
- void setAudioSink(const sp<MediaPlayerBase::AudioSink> &audioSink);
- status_t setLooping(bool shouldLoop);
-
- status_t getDuration(int64_t *durationUs);
- status_t getPosition(int64_t *positionUs);
-
- status_t setParameter(int key, const Parcel &request);
- status_t getParameter(int key, Parcel *reply);
- status_t setPlaybackSettings(const AudioPlaybackRate &rate);
- status_t getPlaybackSettings(AudioPlaybackRate *rate /* nonnull */);
- status_t invoke(const Parcel &request, Parcel *reply);
- status_t setCacheStatCollectFreq(const Parcel &request);
-
- status_t seekTo(int64_t timeUs);
-
- // This is a mask of MediaExtractor::Flags.
- uint32_t flags() const;
-
- void postAudioEOS(int64_t delayUs = 0ll);
- void postAudioSeekComplete();
- void postAudioTearDown();
- status_t dump(int fd, const Vector<String16> &args) const;
-
-private:
- friend struct AwesomeEvent;
- friend struct PreviewPlayer;
-
- enum {
- PLAYING = 0x01,
- LOOPING = 0x02,
- FIRST_FRAME = 0x04,
- PREPARING = 0x08,
- PREPARED = 0x10,
- AT_EOS = 0x20,
- PREPARE_CANCELLED = 0x40,
- CACHE_UNDERRUN = 0x80,
- AUDIO_AT_EOS = 0x0100,
- VIDEO_AT_EOS = 0x0200,
- AUTO_LOOPING = 0x0400,
-
- // We are basically done preparing but are currently buffering
- // sufficient data to begin playback and finish the preparation phase
- // for good.
- PREPARING_CONNECTED = 0x0800,
-
- // We're triggering a single video event to display the first frame
- // after the seekpoint.
- SEEK_PREVIEW = 0x1000,
-
- AUDIO_RUNNING = 0x2000,
- AUDIOPLAYER_STARTED = 0x4000,
-
- INCOGNITO = 0x8000,
-
- TEXT_RUNNING = 0x10000,
- TEXTPLAYER_INITIALIZED = 0x20000,
-
- SLOW_DECODER_HACK = 0x40000,
- };
-
- mutable Mutex mLock;
- Mutex mMiscStateLock;
- mutable Mutex mStatsLock;
- Mutex mAudioLock;
-
- OMXClient mClient;
- TimedEventQueue mQueue;
- bool mQueueStarted;
- wp<MediaPlayerBase> mListener;
- bool mUIDValid;
- uid_t mUID;
-
- sp<ANativeWindow> mNativeWindow;
- sp<MediaPlayerBase::AudioSink> mAudioSink;
-
- SystemTimeSource mSystemTimeSource;
- TimeSource *mTimeSource;
-
- sp<IMediaHTTPService> mHTTPService;
- String8 mUri;
- KeyedVector<String8, String8> mUriHeaders;
-
- sp<DataSource> mFileSource;
-
- sp<IMediaSource> mVideoTrack;
- sp<IMediaSource> mVideoSource;
- sp<AwesomeRenderer> mVideoRenderer;
- bool mVideoRenderingStarted;
- bool mVideoRendererIsPreview;
- int32_t mMediaRenderingStartGeneration;
- int32_t mStartGeneration;
-
- ssize_t mActiveAudioTrackIndex;
- sp<IMediaSource> mAudioTrack;
- sp<IMediaSource> mOmxSource;
- sp<IMediaSource> mAudioSource;
- AudioPlayer *mAudioPlayer;
- AudioPlaybackRate mPlaybackSettings;
- int64_t mDurationUs;
-
- int32_t mDisplayWidth;
- int32_t mDisplayHeight;
- int32_t mVideoScalingMode;
-
- uint32_t mFlags;
- uint32_t mExtractorFlags;
- uint32_t mSinceLastDropped;
-
- int64_t mTimeSourceDeltaUs;
- int64_t mVideoTimeUs;
-
- enum SeekType {
- NO_SEEK,
- SEEK,
- SEEK_VIDEO_ONLY
- };
- SeekType mSeeking;
-
- bool mSeekNotificationSent;
- int64_t mSeekTimeUs;
-
- int64_t mBitrate; // total bitrate of the file (in bps) or -1 if unknown.
-
- bool mWatchForAudioSeekComplete;
- bool mWatchForAudioEOS;
-
- sp<TimedEventQueue::Event> mVideoEvent;
- bool mVideoEventPending;
- sp<TimedEventQueue::Event> mStreamDoneEvent;
- bool mStreamDoneEventPending;
- sp<TimedEventQueue::Event> mBufferingEvent;
- bool mBufferingEventPending;
- sp<TimedEventQueue::Event> mCheckAudioStatusEvent;
- bool mAudioStatusEventPending;
- sp<TimedEventQueue::Event> mVideoLagEvent;
- bool mVideoLagEventPending;
- sp<TimedEventQueue::Event> mAudioTearDownEvent;
- bool mAudioTearDownEventPending;
- sp<TimedEventQueue::Event> mAsyncPrepareEvent;
- Condition mPreparedCondition;
- bool mIsAsyncPrepare;
- status_t mPrepareResult;
- status_t mStreamDoneStatus;
-
- void postVideoEvent_l(int64_t delayUs = -1);
- void postBufferingEvent_l();
- void postStreamDoneEvent_l(status_t status);
- void postCheckAudioStatusEvent(int64_t delayUs);
- void postVideoLagEvent_l();
- void postAudioTearDownEvent(int64_t delayUs);
-
- status_t play_l();
-
- MediaBuffer *mVideoBuffer;
-
- sp<ClockEstimator> mClockEstimator;
- sp<HTTPBase> mConnectingDataSource;
- sp<NuCachedSource2> mCachedSource;
-
- DrmManagerClient *mDrmManagerClient;
- sp<DecryptHandle> mDecryptHandle;
-
- int64_t mLastVideoTimeUs;
- TimedTextDriver *mTextDriver;
- int32_t mSelectedTimedTextTrack;
-
- sp<WVMExtractor> mWVMExtractor;
- sp<IMediaExtractor> mExtractor;
-
- status_t setDataSource_l(
- const sp<IMediaHTTPService> &httpService,
- const char *uri,
- const KeyedVector<String8, String8> *headers = NULL);
-
- status_t setDataSource_l(const sp<DataSource> &dataSource);
- status_t setDataSource_l(const sp<IMediaExtractor> &extractor);
- void reset_l();
- status_t seekTo_l(int64_t timeUs);
- status_t pause_l(bool at_eos = false);
- void initRenderer_l();
- void notifyVideoSize_l();
- void seekAudioIfNecessary_l();
-
- void cancelPlayerEvents(bool keepNotifications = false);
-
- void setAudioSource(sp<IMediaSource> source);
- status_t initAudioDecoder();
-
-
- void setVideoSource(sp<IMediaSource> source);
- status_t initVideoDecoder(uint32_t flags = 0);
-
- void addTextSource_l(size_t trackIndex, const sp<IMediaSource>& source);
-
- void onStreamDone();
-
- void notifyListener_l(int msg, int ext1 = 0, int ext2 = 0);
-
- void onVideoEvent();
- void onBufferingUpdate();
- void onCheckAudioStatus();
- void onPrepareAsyncEvent();
- void abortPrepare(status_t err);
- void finishAsyncPrepare_l();
- void onVideoLagUpdate();
- void onAudioTearDownEvent();
-
- void beginPrepareAsync_l();
-
- bool getCachedDuration_l(int64_t *durationUs, bool *eos);
-
- status_t finishSetDataSource_l();
-
- static bool ContinuePreparation(void *cookie);
-
- bool getBitrate(int64_t *bitrate);
-
- int64_t estimateRealTimeUs(TimeSource *ts, int64_t systemTimeUs);
- void finishSeekIfNecessary(int64_t videoTimeUs);
- void ensureCacheIsFetching_l();
-
- void notifyIfMediaStarted_l();
- void createAudioPlayer_l();
- status_t startAudioPlayer_l(bool sendErrorNotification = true);
-
- void shutdownVideoDecoder_l();
- status_t setNativeWindow_l(const sp<ANativeWindow> &native);
-
- bool isStreamingHTTP() const;
- void sendCacheStats();
- void checkDrmStatus(const sp<DataSource>& dataSource);
-
- enum FlagMode {
- SET,
- CLEAR,
- ASSIGN
- };
- void modifyFlags(unsigned value, FlagMode mode);
-
- struct TrackStat {
- String8 mMIME;
- String8 mDecoderName;
- };
-
- // protected by mStatsLock
- struct Stats {
- int mFd;
- String8 mURI;
- int64_t mBitrate;
-
- // FIXME:
- // These two indices are just 0 or 1 for now
- // They are not representing the actual track
- // indices in the stream.
- ssize_t mAudioTrackIndex;
- ssize_t mVideoTrackIndex;
-
- int64_t mNumVideoFramesDecoded;
- int64_t mNumVideoFramesDropped;
- int32_t mVideoWidth;
- int32_t mVideoHeight;
- uint32_t mFlags;
- Vector<TrackStat> mTracks;
- } mStats;
-
- bool mOffloadAudio;
- bool mAudioTearDown;
- bool mAudioTearDownWasPlaying;
- int64_t mAudioTearDownPosition;
-
- status_t setVideoScalingMode(int32_t mode);
- status_t setVideoScalingMode_l(int32_t mode);
- status_t getTrackInfo(Parcel* reply) const;
-
- status_t selectAudioTrack_l(const sp<IMediaSource>& source, size_t trackIndex);
-
- // when select is true, the given track is selected.
- // otherwise, the given track is unselected.
- status_t selectTrack(size_t trackIndex, bool select);
-
- size_t countTracks() const;
-
- AwesomePlayer(const AwesomePlayer &);
- AwesomePlayer &operator=(const AwesomePlayer &);
-};
-
-} // namespace android
-
-#endif // AWESOME_PLAYER_H_
diff --git a/media/libstagefright/include/TimedEventQueue.h b/media/libstagefright/include/TimedEventQueue.h
deleted file mode 100644
index 890f7e8..0000000
--- a/media/libstagefright/include/TimedEventQueue.h
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef TIMED_EVENT_QUEUE_H_
-
-#define TIMED_EVENT_QUEUE_H_
-
-#include <pthread.h>
-
-#include <utils/List.h>
-#include <utils/RefBase.h>
-#include <utils/threads.h>
-#include <powermanager/IPowerManager.h>
-
-namespace android {
-
-struct TimedEventQueue {
-
- typedef int32_t event_id;
-
- struct Event : public RefBase {
- Event()
- : mEventID(0) {
- }
-
- virtual ~Event() {}
-
- event_id eventID() {
- return mEventID;
- }
-
- protected:
- virtual void fire(TimedEventQueue *queue, int64_t now_us) = 0;
-
- private:
- friend struct TimedEventQueue;
-
- event_id mEventID;
-
- void setEventID(event_id id) {
- mEventID = id;
- }
-
- Event(const Event &);
- Event &operator=(const Event &);
- };
-
- class PMDeathRecipient : public IBinder::DeathRecipient {
- public:
- PMDeathRecipient(TimedEventQueue *queue) : mQueue(queue) {}
- virtual ~PMDeathRecipient() {}
-
- // IBinder::DeathRecipient
- virtual void binderDied(const wp<IBinder>& who);
-
- private:
- PMDeathRecipient(const PMDeathRecipient&);
- PMDeathRecipient& operator = (const PMDeathRecipient&);
-
- TimedEventQueue *mQueue;
- };
-
- TimedEventQueue();
- ~TimedEventQueue();
-
- // Start executing the event loop.
- void start();
-
- // Stop executing the event loop, if flush is false, any pending
- // events are discarded, otherwise the queue will stop (and this call
- // return) once all pending events have been handled.
- void stop(bool flush = false);
-
- // Posts an event to the front of the queue (after all events that
- // have previously been posted to the front but before timed events).
- event_id postEvent(const sp<Event> &event);
-
- event_id postEventToBack(const sp<Event> &event);
-
- // It is an error to post an event with a negative delay.
- event_id postEventWithDelay(const sp<Event> &event, int64_t delay_us);
-
- // If the event is to be posted at a time that has already passed,
- // it will fire as soon as possible.
- event_id postTimedEvent(const sp<Event> &event, int64_t realtime_us);
-
- // Returns true iff event is currently in the queue and has been
- // successfully cancelled. In this case the event will have been
- // removed from the queue and won't fire.
- bool cancelEvent(event_id id);
-
- // Cancel any pending event that satisfies the predicate.
- // If stopAfterFirstMatch is true, only cancels the first event
- // satisfying the predicate (if any).
- void cancelEvents(
- bool (*predicate)(void *cookie, const sp<Event> &event),
- void *cookie,
- bool stopAfterFirstMatch = false);
-
- static int64_t getRealTimeUs();
-
- void clearPowerManager();
-
-private:
- struct QueueItem {
- sp<Event> event;
- int64_t realtime_us;
- bool has_wakelock;
- };
-
- struct StopEvent : public TimedEventQueue::Event {
- virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) {
- queue->mStopped = true;
- }
- };
-
- pthread_t mThread;
- List<QueueItem> mQueue;
- Mutex mLock;
- Condition mQueueNotEmptyCondition;
- Condition mQueueHeadChangedCondition;
- event_id mNextEventID;
-
- bool mRunning;
- bool mStopped;
-
- sp<IPowerManager> mPowerManager;
- sp<IBinder> mWakeLockToken;
- const sp<PMDeathRecipient> mDeathRecipient;
- uint32_t mWakeLockCount;
-
- static void *ThreadWrapper(void *me);
- void threadEntry();
-
- sp<Event> removeEventFromQueue_l(event_id id, bool *wakeLocked);
-
- void acquireWakeLock_l();
- void releaseWakeLock_l(bool force = false);
-
- TimedEventQueue(const TimedEventQueue &);
- TimedEventQueue &operator=(const TimedEventQueue &);
-};
-
-} // namespace android
-
-#endif // TIMED_EVENT_QUEUE_H_