summaryrefslogtreecommitdiffstats
path: root/media/libstagefright/AwesomePlayer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'media/libstagefright/AwesomePlayer.cpp')
-rw-r--r--media/libstagefright/AwesomePlayer.cpp431
1 files changed, 415 insertions, 16 deletions
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 1e2625a..7d077f5 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -1,6 +1,9 @@
/*
* Copyright (C) 2009 The Android Open Source Project
- *
+ * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution, Apache license notifications and license are retained
+ * for attribution purposes only.
+
* 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
@@ -39,8 +42,15 @@
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/timedtext/TimedTextDriver.h>
#include <media/stagefright/AudioPlayer.h>
+#ifdef QCOM_ENHANCED_AUDIO
+#include <media/stagefright/LPAPlayer.h>
+#ifdef USE_TUNNEL_MODE
+#include <media/stagefright/TunnelPlayer.h>
+#endif
+#endif
#include <media/stagefright/DataSource.h>
#include <media/stagefright/FileSource.h>
+#include <media/stagefright/FMRadioSource.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaExtractor.h>
@@ -57,6 +67,8 @@
#define USE_SURFACE_ALLOC 1
#define FRAME_DROP_FREQ 0
+#define LPA_MIN_DURATION_USEC_ALLOWED 30000000
+#define LPA_MIN_DURATION_USEC_DEFAULT 60000000
namespace android {
@@ -64,6 +76,9 @@ static int64_t kLowWaterMarkUs = 2000000ll; // 2secs
static int64_t kHighWaterMarkUs = 5000000ll; // 5secs
static const size_t kLowWaterMarkBytes = 40000;
static const size_t kHighWaterMarkBytes = 200000;
+#ifdef QCOM_ENHANCED_AUDIO
+int AwesomePlayer::mTunnelAliveAP = 0;
+#endif
struct AwesomeEvent : public TimedEventQueue::Event {
AwesomeEvent(
@@ -214,6 +229,9 @@ AwesomePlayer::AwesomePlayer()
mAudioStatusEventPending = false;
reset();
+#ifdef USE_TUNNEL_MODE
+ mIsTunnelAudio = false;
+#endif
}
AwesomePlayer::~AwesomePlayer() {
@@ -223,6 +241,17 @@ AwesomePlayer::~AwesomePlayer() {
reset();
+#ifdef USE_TUNNEL_MODE
+ // Disable Tunnel Mode Audio
+ if (mIsTunnelAudio) {
+ if(mTunnelAliveAP > 0) {
+ mTunnelAliveAP--;
+ ALOGV("mTunnelAliveAP = %d", mTunnelAliveAP);
+ }
+ }
+ mIsTunnelAudio = false;
+#endif
+
mClient.disconnect();
}
@@ -579,6 +608,18 @@ void AwesomePlayer::reset_l() {
mStats.mVideoHeight = -1;
mStats.mFlags = 0;
mStats.mTracks.clear();
+ mStats.mConsecutiveFramesDropped = 0;
+ mStats.mCatchupTimeStart = 0;
+ mStats.mNumTimesSyncLoss = 0;
+ mStats.mMaxEarlyDelta = 0;
+ mStats.mMaxLateDelta = 0;
+ mStats.mMaxTimeSyncLoss = 0;
+ mStats.mTotalFrames = 0;
+ mStats.mLastFrameUs = 0;
+ mStats.mTotalTimeUs = 0;
+ mStats.mLastPausedTimeMs = 0;
+ mStats.mLastSeekToTimeMs = 0;
+ mStats.mFirstFrameLatencyUs = 0;
}
mWatchForAudioSeekComplete = false;
@@ -857,6 +898,9 @@ status_t AwesomePlayer::play() {
}
status_t AwesomePlayer::play_l() {
+#ifdef QCOM_ENHANCED_AUDIO
+ int tunnelObjectsAlive = 0;
+#endif
modifyFlags(SEEK_PREVIEW, CLEAR);
if (mFlags & PLAYING) {
@@ -884,6 +928,13 @@ status_t AwesomePlayer::play_l() {
if (mAudioSource != NULL) {
if (mAudioPlayer == NULL) {
if (mAudioSink != NULL) {
+#ifdef QCOM_ENHANCED_AUDIO
+ sp<MetaData> format = mAudioTrack->getFormat();
+ const char *mime;
+ bool success = format->findCString(kKeyMIMEType, &mime);
+ CHECK(success);
+#endif
+
bool allowDeepBuffering;
int64_t cachedDurationUs;
bool eos;
@@ -895,8 +946,81 @@ status_t AwesomePlayer::play_l() {
} else {
allowDeepBuffering = false;
}
-
- mAudioPlayer = new AudioPlayer(mAudioSink, allowDeepBuffering, this);
+#ifdef QCOM_ENHANCED_AUDIO
+#ifdef USE_TUNNEL_MODE
+ // Create tunnel player if tunnel mode is enabled
+ ALOGW("Trying to create tunnel player mIsTunnelAudio %d, \
+ LPAPlayer::objectsAlive %d, \
+ TunnelPlayer::mTunnelObjectsAlive = %d,\
+ (mAudioPlayer == NULL) %d",
+ mIsTunnelAudio, TunnelPlayer::mTunnelObjectsAlive,
+ LPAPlayer::objectsAlive,(mAudioPlayer == NULL));
+
+ if(mIsTunnelAudio && (mAudioPlayer == NULL) &&
+ (LPAPlayer::objectsAlive == 0) &&
+ (TunnelPlayer::mTunnelObjectsAlive == 0)) {
+ ALOGD("Tunnel player created for mime %s duration %lld\n",\
+ mime, mDurationUs);
+ bool initCheck = false;
+ if(mVideoSource != NULL) {
+ // The parameter true is to inform tunnel player that
+ // clip is audio video
+ mAudioPlayer = new TunnelPlayer(mAudioSink, initCheck,
+ this, true);
+ }
+ else {
+ mAudioPlayer = new TunnelPlayer(mAudioSink, initCheck,
+ this);
+ }
+ if(!initCheck) {
+ ALOGE("deleting Tunnel Player - initCheck failed");
+ delete mAudioPlayer;
+ mAudioPlayer = NULL;
+ }
+ }
+ tunnelObjectsAlive = (TunnelPlayer::mTunnelObjectsAlive);
+#endif
+ int32_t nchannels = 0;
+ if(mAudioTrack != NULL) {
+ sp<MetaData> format = mAudioTrack->getFormat();
+ if(format != NULL) {
+ format->findInt32( kKeyChannelCount, &nchannels );
+ ALOGV("nchannels %d;LPA will be skipped if nchannels is > 2 or nchannels == 0",nchannels);
+ }
+ }
+ char lpaDecode[PROPERTY_VALUE_MAX];
+ uint32_t minDurationForLPA = LPA_MIN_DURATION_USEC_DEFAULT;
+ char minUserDefDuration[PROPERTY_VALUE_MAX];
+ property_get("lpa.decode",lpaDecode,"0");
+ property_get("lpa.min_duration",minUserDefDuration,"LPA_MIN_DURATION_USEC_DEFAULT");
+ minDurationForLPA = atoi(minUserDefDuration);
+ if(minDurationForLPA < LPA_MIN_DURATION_USEC_ALLOWED) {
+ ALOGE("LPAPlayer::Clip duration setting of less than 30sec not supported, defaulting to 60sec");
+ minDurationForLPA = LPA_MIN_DURATION_USEC_DEFAULT;
+ }
+ if((strcmp("true",lpaDecode) == 0) && (mAudioPlayer == NULL) &&
+ (tunnelObjectsAlive==0) && (nchannels && (nchannels <= 2)))
+ {
+ ALOGV("LPAPlayer::getObjectsAlive() %d",LPAPlayer::objectsAlive);
+ if ( mDurationUs > minDurationForLPA
+ && (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG) || !strcasecmp(mime,MEDIA_MIMETYPE_AUDIO_AAC))
+ && LPAPlayer::objectsAlive == 0 && mVideoSource == NULL) {
+ ALOGD("LPAPlayer created, LPA MODE detected mime %s duration %lld", mime, mDurationUs);
+ bool initCheck = false;
+ mAudioPlayer = new LPAPlayer(mAudioSink, initCheck, this);
+ if(!initCheck) {
+ delete mAudioPlayer;
+ mAudioPlayer = NULL;
+ }
+ }
+ }
+ if(mAudioPlayer == NULL) {
+ ALOGV("AudioPlayer created, Non-LPA mode mime %s duration %lld\n", mime, mDurationUs);
+#endif
+ mAudioPlayer = new AudioPlayer(mAudioSink, allowDeepBuffering, this);
+#ifdef QCOM_ENHANCED_AUDIO
+ }
+#endif
mAudioPlayer->setSource(mAudioSource);
mTimeSource = mAudioPlayer;
@@ -914,9 +1038,14 @@ status_t AwesomePlayer::play_l() {
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 */);
+ bool sendErrorNotification = false;
+#ifdef IS_TUNNEL_MODE
+ if(mIsTunnelAudio) {
+ // For tunnel Audio error has to be posted to the client
+ sendErrorNotification = true;
+ }
+#endif
+ status_t err = startAudioPlayer_l(sendErrorNotification);
if (err != OK) {
delete mAudioPlayer;
@@ -938,6 +1067,12 @@ status_t AwesomePlayer::play_l() {
mTimeSource = &mSystemTimeSource;
}
+ {
+ Mutex::Autolock autoLock(mStatsLock);
+ mStats.mFirstFrameLatencyStartUs = getTimeOfDayUs();
+ mStats.mVeryFirstFrame = true;
+ }
+
if (mVideoSource != NULL) {
// Kick off video playback
postVideoEvent_l();
@@ -1161,6 +1296,11 @@ status_t AwesomePlayer::pause_l(bool at_eos) {
Playback::PAUSE, 0);
}
+ if(!(mFlags & AT_EOS)){
+ Mutex::Autolock autoLock(mStatsLock);
+ mStats.mLastPausedTimeMs = mVideoTimeUs/1000;
+ }
+
uint32_t params = IMediaPlayerService::kBatteryDataTrackDecoder;
if ((mAudioSource != NULL) && (mAudioSource != mAudioTrack)) {
params |= IMediaPlayerService::kBatteryDataTrackAudio;
@@ -1297,7 +1437,8 @@ status_t AwesomePlayer::getPosition(int64_t *positionUs) {
status_t AwesomePlayer::seekTo(int64_t timeUs) {
ATRACE_CALL();
- if (mExtractorFlags & MediaExtractor::CAN_SEEK) {
+ if (((timeUs == 0) && (mExtractorFlags & MediaExtractor::CAN_SEEK_TO_ZERO)) ||
+ (mExtractorFlags & MediaExtractor::CAN_SEEK)) {
Mutex::Autolock autoLock(mLock);
return seekTo_l(timeUs);
}
@@ -1320,6 +1461,12 @@ status_t AwesomePlayer::seekTo_l(int64_t timeUs) {
}
mSeeking = SEEK;
+
+ {
+ Mutex::Autolock autoLock(mStatsLock);
+ mStats.mFirstFrameLatencyStartUs = getTimeOfDayUs();
+ mStats.mVeryFirstFrame = true;
+ }
mSeekNotificationSent = false;
mSeekTimeUs = timeUs;
modifyFlags((AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS), CLEAR);
@@ -1385,14 +1532,119 @@ status_t AwesomePlayer::initAudioDecoder() {
const char *mime;
CHECK(meta->findCString(kKeyMIMEType, &mime));
+#ifdef QCOM_ENHANCED_AUDIO
+ int32_t nchannels = 0;
+ int32_t isADTS = 0;
+ meta->findInt32( kKeyChannelCount, &nchannels );
+ meta->findInt32(kKeyIsADTS, &isADTS);
+ if(isADTS == 1){
+ ALOGV("Widevine content\n");
+ }
+ ALOGV("nchannels %d;LPA will be skipped if nchannels is > 2 or nchannels == 0",
+ nchannels);
+#endif
+#ifdef USE_TUNNEL_MODE
+ char tunnelDecode[PROPERTY_VALUE_MAX];
+ property_get("tunnel.decode",tunnelDecode,"0");
+ // Enable tunnel mode for mp3 and aac and if the clip is not aac adif
+ // and if no other tunnel mode instances aare running.
+ ALOGD("Tunnel Mime Type: %s, object alive = %d, mTunnelAliveAP = %d",\
+ mime, (TunnelPlayer::mTunnelObjectsAlive), mTunnelAliveAP);
+
+ bool sys_prop_enabled = !strcmp("true",tunnelDecode) || atoi(tunnelDecode);
+
+ //widevine will fallback to software decoder
+ if (sys_prop_enabled && (TunnelPlayer::mTunnelObjectsAlive == 0) &&
+ mTunnelAliveAP == 0 && (isADTS == 0) &&
+ mAudioSink->realtime() &&
+ inSupportedTunnelFormats(mime)) {
+
+ if (mVideoSource != NULL) {
+ char tunnelAVDecode[PROPERTY_VALUE_MAX];
+ property_get("tunnel.audiovideo.decode",tunnelAVDecode,"0");
+ sys_prop_enabled = !strncmp("true", tunnelAVDecode, 4) || atoi(tunnelAVDecode);
+ if (sys_prop_enabled) {
+ ALOGD("Enable Tunnel Mode for A-V playback");
+ mIsTunnelAudio = true;
+ }
+ }
+ else {
+ ALOGI("Tunnel Mode Audio Enabled");
+ mIsTunnelAudio = true;
+ }
+ }
+ else
+ ALOGD("Normal Audio Playback");
+
+ if (isStreamingHTTP()) {
+ ALOGV("Streaming, force disable tunnel mode playback");
+ mIsTunnelAudio = false;
+ }
+ if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW) ||
+ (mIsTunnelAudio && (mTunnelAliveAP == 0))) {
+ ALOGD("Set Audio Track as Audio Source");
+ if(mIsTunnelAudio) {
+ mTunnelAliveAP++;
+ }
+#else
if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) {
+#endif
mAudioSource = mAudioTrack;
} else {
+#ifdef QCOM_ENHANCED_AUDIO
+ // For LPA Playback use the decoder without OMX layer
+ char *matchComponentName = NULL;
+ int64_t durationUs;
+ uint32_t flags = 0;
+ char lpaDecode[128];
+ uint32_t minDurationForLPA = LPA_MIN_DURATION_USEC_DEFAULT;
+ char minUserDefDuration[PROPERTY_VALUE_MAX];
+ property_get("lpa.decode",lpaDecode,"0");
+ property_get("lpa.min_duration",minUserDefDuration,"LPA_MIN_DURATION_USEC_DEFAULT");
+ minDurationForLPA = atoi(minUserDefDuration);
+ if(minDurationForLPA < LPA_MIN_DURATION_USEC_ALLOWED) {
+ ALOGE("LPAPlayer::Clip duration setting of less than 30sec not supported, defaulting to 60sec");
+ minDurationForLPA = LPA_MIN_DURATION_USEC_DEFAULT;
+ }
+ if (mAudioTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
+ Mutex::Autolock autoLock(mMiscStateLock);
+ if (mDurationUs < 0 || durationUs > mDurationUs) {
+ mDurationUs = durationUs;
+ }
+ }
+ if ( mDurationUs > minDurationForLPA
+ && (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG) || !strcasecmp(mime,MEDIA_MIMETYPE_AUDIO_AAC))
+ && LPAPlayer::objectsAlive == 0 && mVideoSource == NULL && (strcmp("true",lpaDecode) == 0)
+ && (nchannels && (nchannels <= 2)) ) {
+ char nonOMXDecoder[128];
+ if(!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) {
+ ALOGD("matchComponentName is set to MP3Decoder %lld, mime %s",mDurationUs,mime);
+ property_get("use.non-omx.mp3.decoder",nonOMXDecoder,"0");
+ if((strcmp("true",nonOMXDecoder) == 0)) {
+ matchComponentName = (char *) "MP3Decoder";
+ }
+ } else if((!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC))) {
+ ALOGD("matchComponentName is set to AACDecoder %lld, mime %s",mDurationUs,mime);
+ property_get("use.non-omx.aac.decoder",nonOMXDecoder,"0");
+ if((strcmp("true",nonOMXDecoder) == 0)) {
+ matchComponentName = (char *) "AACDecoder";
+ } else {
+ matchComponentName = (char *) "OMX.google.aac.decoder";
+ }
+ }
+ flags |= OMXCodec::kSoftwareCodecsOnly;
+ }
+ mAudioSource = OMXCodec::Create(
+ mClient.interface(), mAudioTrack->getFormat(),
+ false, // createEncoder
+ mAudioTrack, matchComponentName, flags,NULL);
+#else
mAudioSource = OMXCodec::Create(
mClient.interface(), mAudioTrack->getFormat(),
false, // createEncoder
mAudioTrack);
+#endif
}
if (mAudioSource != NULL) {
@@ -1576,6 +1828,12 @@ void AwesomePlayer::finishSeekIfNecessary(int64_t videoTimeUs) {
mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
Playback::START, videoTimeUs / 1000);
}
+
+ {
+ Mutex::Autolock autoLock(mStatsLock);
+ mStats.mLastSeekToTimeMs = mSeekTimeUs/1000;
+ logFirstFrame();
+ }
}
void AwesomePlayer::onVideoEvent() {
@@ -1588,6 +1846,14 @@ void AwesomePlayer::onVideoEvent() {
}
mVideoEventPending = false;
+ {
+ Mutex::Autolock autoLock(mStatsLock);
+ if(!mStats.mVeryFirstFrame && mSeeking == NO_SEEK){
+ mStats.mTotalTimeUs += getTimeOfDayUs() - mStats.mLastFrameUs;
+ }
+ mStats.mLastFrameUs = getTimeOfDayUs();
+ }
+
if (mSeeking != NO_SEEK) {
if (mVideoBuffer) {
mVideoBuffer->release();
@@ -1721,18 +1987,26 @@ void AwesomePlayer::onVideoEvent() {
modifyFlags(FIRST_FRAME, CLEAR);
mSinceLastDropped = 0;
mTimeSourceDeltaUs = ts->getRealTimeUs() - timeUs;
+
+ {
+ Mutex::Autolock autoLock(mStatsLock);
+ if(mStats.mVeryFirstFrame){
+ logFirstFrame();
+ mStats.mLastFrameUs = getTimeOfDayUs();
+ }
+ }
}
- int64_t realTimeUs, mediaTimeUs;
+ int64_t realTimeUs, mediaTimeUs, nowUs = 0, latenessUs = 0;
if (!(mFlags & AUDIO_AT_EOS) && mAudioPlayer != NULL
&& mAudioPlayer->getMediaTimeMapping(&realTimeUs, &mediaTimeUs)) {
mTimeSourceDeltaUs = realTimeUs - mediaTimeUs;
}
if (wasSeeking == SEEK_VIDEO_ONLY) {
- int64_t nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs;
+ nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs;
- int64_t latenessUs = nowUs - timeUs;
+ latenessUs = nowUs - timeUs;
ATRACE_INT("Video Lateness (ms)", latenessUs / 1E3);
@@ -1744,9 +2018,9 @@ void AwesomePlayer::onVideoEvent() {
if (wasSeeking == NO_SEEK) {
// Let's display the first frame after seeking right away.
- int64_t nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs;
+ nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs;
- int64_t latenessUs = nowUs - timeUs;
+ latenessUs = nowUs - timeUs;
ATRACE_INT("Video Lateness (ms)", latenessUs / 1E3);
@@ -1793,6 +2067,11 @@ void AwesomePlayer::onVideoEvent() {
{
Mutex::Autolock autoLock(mStatsLock);
++mStats.mNumVideoFramesDropped;
+ mStats.mConsecutiveFramesDropped++;
+ if (mStats.mConsecutiveFramesDropped == 1){
+ mStats.mCatchupTimeStart = mTimeSource->getRealTimeUs();
+ }
+ if(!(mFlags & AT_EOS)) logLate(timeUs,nowUs,latenessUs);
}
postVideoEvent_l();
@@ -1802,6 +2081,11 @@ void AwesomePlayer::onVideoEvent() {
if (latenessUs < -10000) {
// We're more than 10ms early.
+ logOnTime(timeUs,nowUs,latenessUs);
+ {
+ Mutex::Autolock autoLock(mStatsLock);
+ mStats.mConsecutiveFramesDropped = 0;
+ }
postVideoEvent_l(10000);
return;
}
@@ -1822,6 +2106,12 @@ void AwesomePlayer::onVideoEvent() {
notifyListener_l(MEDIA_INFO, MEDIA_INFO_RENDERING_START);
}
+ {
+ Mutex::Autolock autoLock(mStatsLock);
+ logOnTime(timeUs,nowUs,latenessUs);
+ mStats.mTotalFrames++;
+ mStats.mConsecutiveFramesDropped = 0;
+ }
}
mVideoBuffer->release();
@@ -2121,6 +2411,15 @@ status_t AwesomePlayer::finishSetDataSource_l() {
return UNKNOWN_ERROR;
}
}
+#ifdef STE_FM
+ } else if (!strncasecmp("fmradio://rx", mUri.string(), 12)) {
+ sniffedMIME = MEDIA_MIMETYPE_AUDIO_RAW;
+ dataSource = new FMRadioSource();
+ status_t err = dataSource->initCheck();
+ if (err != OK) {
+ return err;
+ }
+#endif
} else {
dataSource = DataSource::CreateFromURI(mUri.string(), &mUriHeaders);
}
@@ -2619,13 +2918,37 @@ status_t AwesomePlayer::dump(int fd, const Vector<String16> &args) const {
if ((ssize_t)i == mStats.mVideoTrackIndex) {
fprintf(out,
- " videoDimensions(%d x %d), "
- "numVideoFramesDecoded(%lld), "
- "numVideoFramesDropped(%lld)\n",
+ " videoDimensions(%d x %d)\n"
+ " Total Video Frames Decoded(%lld)\n"
+ " Total Video Frames Rendered(%lld)\n"
+ " Total Playback Duration(%lld ms)\n"
+ " numVideoFramesDropped(%lld)\n"
+ " Average Frames Per Second(%.4f)\n"
+ " Last Seek To Time(%lld ms)\n"
+ " Last Paused Time(%lld ms)\n"
+ " First Frame Latency (%lld ms)\n"
+ " Number of times AV Sync Lost(%u)\n"
+ " Max Video Ahead Time Delta(%u)\n"
+ " Max Video Behind Time Delta(%u)\n"
+ " Max Time Sync Loss(%u)\n"
+ " EOS(%d)\n"
+ " PLAYING(%d)\n",
mStats.mVideoWidth,
mStats.mVideoHeight,
mStats.mNumVideoFramesDecoded,
- mStats.mNumVideoFramesDropped);
+ mStats.mTotalFrames,
+ mStats.mTotalTimeUs/1000,
+ mStats.mNumVideoFramesDropped,
+ ((double)(mStats.mTotalFrames)*1E6)/((double)mStats.mTotalTimeUs),
+ mStats.mLastSeekToTimeMs,
+ mStats.mLastPausedTimeMs,
+ mStats.mFirstFrameLatencyUs/1000,
+ mStats.mNumTimesSyncLoss,
+ -mStats.mMaxEarlyDelta/1000,
+ mStats.mMaxLateDelta/1000,
+ mStats.mMaxTimeSyncLoss/1000,
+ (mFlags & AT_EOS) > 0,
+ (mFlags & PLAYING) > 0);
}
}
@@ -2659,4 +2982,80 @@ void AwesomePlayer::modifyFlags(unsigned value, FlagMode mode) {
}
}
+inline void AwesomePlayer::logFirstFrame() {
+ mStats.mFirstFrameLatencyUs = getTimeOfDayUs()-mStats.mFirstFrameLatencyStartUs;
+ mStats.mVeryFirstFrame = false;
+}
+
+inline void AwesomePlayer::logCatchUp(int64_t ts, int64_t clock, int64_t delta)
+{
+ if (mStats.mConsecutiveFramesDropped > 0) {
+ mStats.mNumTimesSyncLoss++;
+ if (mStats.mMaxTimeSyncLoss < (clock - mStats.mCatchupTimeStart) && clock > 0 && ts > 0) {
+ mStats.mMaxTimeSyncLoss = clock - mStats.mCatchupTimeStart;
+ }
+ }
+}
+
+inline void AwesomePlayer::logLate(int64_t ts, int64_t clock, int64_t delta)
+{
+ if (mStats.mMaxLateDelta < delta && clock > 0 && ts > 0) {
+ mStats.mMaxLateDelta = delta;
+ }
+}
+
+inline void AwesomePlayer::logOnTime(int64_t ts, int64_t clock, int64_t delta)
+{
+ bool needLogLate = false;
+ logCatchUp(ts, clock, delta);
+ if (delta <= 0) {
+ if ((-delta) > (-mStats.mMaxEarlyDelta) && clock > 0 && ts > 0) {
+ mStats.mMaxEarlyDelta = delta;
+ }
+ }
+ else {
+ needLogLate = true;
+ }
+
+ if(needLogLate) logLate(ts, clock, delta);
+}
+
+inline int64_t AwesomePlayer::getTimeOfDayUs() {
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+
+ return (int64_t)tv.tv_sec * 1000000 + tv.tv_usec;
+}
+
+#ifdef USE_TUNNEL_MODE
+bool AwesomePlayer::inSupportedTunnelFormats(const char * mime) {
+ const char * tunnelFormats [ ] = {
+ MEDIA_MIMETYPE_AUDIO_MPEG,
+ MEDIA_MIMETYPE_AUDIO_AAC,
+#ifdef TUNNEL_MODE_SUPPORTS_AMRWB
+ MEDIA_MIMETYPE_AUDIO_AMR_WB,
+ MEDIA_MIMETYPE_AUDIO_AMR_WB_PLUS
+#endif
+ };
+
+ if (!mime) {
+ return false;
+ }
+
+ size_t len = sizeof(tunnelFormats)/sizeof(const char *);
+ for (size_t i = 0; i < len; i++) {
+ const char * tf = tunnelFormats[i];
+ if (!strncasecmp(mime, tf, strlen(tf))) {
+ if (strlen(mime) == strlen(tf)) { //to prevent a substring match
+ ALOGD("Tunnel playback supported for %s", tf);
+ return true;
+ }
+ }
+ }
+
+ ALOGW("Tunnel playback unsupported for %s", mime);
+ return false;
+}
+#endif
+
} // namespace android