diff options
Diffstat (limited to 'media/libstagefright/AwesomePlayer.cpp')
-rw-r--r-- | media/libstagefright/AwesomePlayer.cpp | 431 |
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 |