diff options
Diffstat (limited to 'media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp')
| -rw-r--r-- | media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp | 239 | 
1 files changed, 179 insertions, 60 deletions
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp index 86ce385..25225a8 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp @@ -20,12 +20,11 @@  #include "NuPlayerRenderer.h" -#include <cutils/properties.h> -  #include <media/stagefright/foundation/ABuffer.h>  #include <media/stagefright/foundation/ADebug.h>  #include <media/stagefright/foundation/AMessage.h>  #include <media/stagefright/foundation/AUtils.h> +#include <media/stagefright/foundation/AWakeLock.h>  #include <media/stagefright/MediaErrors.h>  #include <media/stagefright/MetaData.h>  #include <media/stagefright/Utils.h> @@ -38,20 +37,19 @@ namespace android {  // Maximum time in paused state when offloading audio decompression. When elapsed, the AudioSink  // is closed to allow the audio DSP to power down. -static const int64_t kOffloadPauseMaxUs = 60000000ll; +static const int64_t kOffloadPauseMaxUs = 10000000ll;  // static -const int64_t NuPlayer::Renderer::kMinPositionUpdateDelayUs = 100000ll; +const NuPlayer::Renderer::PcmInfo NuPlayer::Renderer::AUDIO_PCMINFO_INITIALIZER = { +        AUDIO_CHANNEL_NONE, +        AUDIO_OUTPUT_FLAG_NONE, +        AUDIO_FORMAT_INVALID, +        0, // mNumChannels +        0 // mSampleRate +}; -static bool sFrameAccurateAVsync = false; - -static void readProperties() { -    char value[PROPERTY_VALUE_MAX]; -    if (property_get("persist.sys.media.avsync", value, NULL)) { -        sFrameAccurateAVsync = -            !strcmp("1", value) || !strcasecmp("true", value); -    } -} +// static +const int64_t NuPlayer::Renderer::kMinPositionUpdateDelayUs = 100000ll;  NuPlayer::Renderer::Renderer(          const sp<MediaPlayerBase::AudioSink> &sink, @@ -76,8 +74,11 @@ NuPlayer::Renderer::Renderer(        mPauseStartedTimeRealUs(-1),        mFlushingAudio(false),        mFlushingVideo(false), +      mNotifyCompleteAudio(false), +      mNotifyCompleteVideo(false),        mSyncQueues(false),        mPaused(false), +      mPausePositionMediaTimeUs(-1),        mVideoSampleReceived(false),        mVideoRenderingStarted(false),        mVideoRenderingStartGeneration(0), @@ -85,9 +86,11 @@ NuPlayer::Renderer::Renderer(        mAudioOffloadPauseTimeoutGeneration(0),        mAudioOffloadTornDown(false),        mCurrentOffloadInfo(AUDIO_INFO_INITIALIZER), +      mCurrentPcmInfo(AUDIO_PCMINFO_INITIALIZER),        mTotalBuffersQueued(0), -      mLastAudioBufferDrained(0) { -    readProperties(); +      mLastAudioBufferDrained(0), +      mWakeLock(new AWakeLock()) { +  }  NuPlayer::Renderer::~Renderer() { @@ -118,15 +121,17 @@ void NuPlayer::Renderer::queueEOS(bool audio, status_t finalResult) {      msg->post();  } -void NuPlayer::Renderer::flush(bool audio) { +void NuPlayer::Renderer::flush(bool audio, bool notifyComplete) {      {          Mutex::Autolock autoLock(mFlushLock);          if (audio) { +            mNotifyCompleteAudio |= notifyComplete;              if (mFlushingAudio) {                  return;              }              mFlushingAudio = true;          } else { +            mNotifyCompleteVideo |= notifyComplete;              if (mFlushingVideo) {                  return;              } @@ -157,6 +162,10 @@ void NuPlayer::Renderer::signalDisableOffloadAudio() {      (new AMessage(kWhatDisableOffloadAudio, id()))->post();  } +void NuPlayer::Renderer::signalEnableOffloadAudio() { +    (new AMessage(kWhatEnableOffloadAudio, id()))->post(); +} +  void NuPlayer::Renderer::pause() {      (new AMessage(kWhatPause, id()))->post();  } @@ -171,11 +180,48 @@ void NuPlayer::Renderer::setVideoFrameRate(float fps) {      msg->post();  } +// Called on any threads, except renderer's thread.  status_t NuPlayer::Renderer::getCurrentPosition(int64_t *mediaUs) { -    return getCurrentPosition(mediaUs, ALooper::GetNowUs()); +    { +        Mutex::Autolock autoLock(mLock); +        int64_t currentPositionUs; +        if (getCurrentPositionIfPaused_l(¤tPositionUs)) { +            *mediaUs = currentPositionUs; +            return OK; +        } +    } +    return getCurrentPositionFromAnchor(mediaUs, ALooper::GetNowUs()); +} + +// Called on only renderer's thread. +status_t NuPlayer::Renderer::getCurrentPositionOnLooper(int64_t *mediaUs) { +    return getCurrentPositionOnLooper(mediaUs, ALooper::GetNowUs());  } -status_t NuPlayer::Renderer::getCurrentPosition( +// Called on only renderer's thread. +// Since mPaused and mPausePositionMediaTimeUs are changed only on renderer's +// thread, no need to acquire mLock. +status_t NuPlayer::Renderer::getCurrentPositionOnLooper( +        int64_t *mediaUs, int64_t nowUs, bool allowPastQueuedVideo) { +    int64_t currentPositionUs; +    if (getCurrentPositionIfPaused_l(¤tPositionUs)) { +        *mediaUs = currentPositionUs; +        return OK; +    } +    return getCurrentPositionFromAnchor(mediaUs, nowUs, allowPastQueuedVideo); +} + +// Called either with mLock acquired or on renderer's thread. +bool NuPlayer::Renderer::getCurrentPositionIfPaused_l(int64_t *mediaUs) { +    if (!mPaused || mPausePositionMediaTimeUs < 0ll) { +        return false; +    } +    *mediaUs = mPausePositionMediaTimeUs; +    return true; +} + +// Called on any threads. +status_t NuPlayer::Renderer::getCurrentPositionFromAnchor(          int64_t *mediaUs, int64_t nowUs, bool allowPastQueuedVideo) {      Mutex::Autolock autoLock(mTimeLock);      if (!mHasAudio && !mHasVideo) { @@ -255,11 +301,12 @@ void NuPlayer::Renderer::setPauseStartedTimeRealUs(int64_t realUs) {      mPauseStartedTimeRealUs = realUs;  } -bool NuPlayer::Renderer::openAudioSink( +status_t NuPlayer::Renderer::openAudioSink(          const sp<AMessage> &format,          bool offloadOnly,          bool hasVideo, -        uint32_t flags) { +        uint32_t flags, +        bool *isOffloaded) {      sp<AMessage> msg = new AMessage(kWhatOpenAudioSink, id());      msg->setMessage("format", format);      msg->setInt32("offload-only", offloadOnly); @@ -269,9 +316,15 @@ bool NuPlayer::Renderer::openAudioSink(      sp<AMessage> response;      msg->postAndAwaitResponse(&response); -    int32_t offload; -    CHECK(response->findInt32("offload", &offload)); -    return (offload != 0); +    int32_t err; +    if (!response->findInt32("err", &err)) { +        err = INVALID_OPERATION; +    } else if (err == OK && isOffloaded != NULL) { +        int32_t offload; +        CHECK(response->findInt32("offload", &offload)); +        *isOffloaded = (offload != 0); +    } +    return err;  }  void NuPlayer::Renderer::closeAudioSink() { @@ -297,10 +350,11 @@ void NuPlayer::Renderer::onMessageReceived(const sp<AMessage> &msg) {              uint32_t flags;              CHECK(msg->findInt32("flags", (int32_t *)&flags)); -            bool offload = onOpenAudioSink(format, offloadOnly, hasVideo, flags); +            status_t err = onOpenAudioSink(format, offloadOnly, hasVideo, flags);              sp<AMessage> response = new AMessage; -            response->setInt32("offload", offload); +            response->setInt32("err", err); +            response->setInt32("offload", offloadingAudio());              uint32_t replyID;              CHECK(msg->senderAwaitsResponse(&replyID)); @@ -373,7 +427,8 @@ void NuPlayer::Renderer::onMessageReceived(const sp<AMessage> &msg) {              onDrainVideoQueue(); -            postDrainVideoQueue(); +            Mutex::Autolock autoLock(mLock); +            postDrainVideoQueue_l();              break;          } @@ -386,7 +441,8 @@ void NuPlayer::Renderer::onMessageReceived(const sp<AMessage> &msg) {              }              mDrainVideoQueuePending = false; -            postDrainVideoQueue(); +            Mutex::Autolock autoLock(mLock); +            postDrainVideoQueue_l();              break;          } @@ -420,6 +476,12 @@ void NuPlayer::Renderer::onMessageReceived(const sp<AMessage> &msg) {              break;          } +        case kWhatEnableOffloadAudio: +        { +            onEnableOffloadAudio(); +            break; +        } +          case kWhatPause:          {              onPause(); @@ -455,6 +517,7 @@ void NuPlayer::Renderer::onMessageReceived(const sp<AMessage> &msg) {              }              ALOGV("Audio Offload tear down due to pause timeout.");              onAudioOffloadTearDown(kDueToTimeout); +            mWakeLock->release();              break;          } @@ -629,6 +692,13 @@ bool NuPlayer::Renderer::onDrainAudioQueue() {              mAudioQueue.erase(mAudioQueue.begin());              entry = NULL; +            if (mAudioSink->needsTrailingPadding()) { +                // If we're not in gapless playback (i.e. through setNextPlayer), we +                // need to stop the track here, because that will play out the last +                // little bit at the end of the file. Otherwise short files won't play. +                mAudioSink->stop(); +                mNumFramesWritten = 0; +            }              return false;          } @@ -646,8 +716,9 @@ bool NuPlayer::Renderer::onDrainAudioQueue() {          ssize_t written = mAudioSink->write(entry->mBuffer->data() + entry->mOffset, copy);          if (written < 0) { -            // An error in AudioSink write is fatal here. -            LOG_ALWAYS_FATAL("AudioSink write error(%zd) when writing %zu bytes", written, copy); +            // An error in AudioSink write. Perhaps the AudioSink was not properly opened. +            ALOGE("AudioSink write error(%zd) when writing %zu bytes", written, copy); +            break;          }          entry->mOffset += written; @@ -701,7 +772,8 @@ int64_t NuPlayer::Renderer::getPendingAudioPlayoutDurationUs(int64_t nowUs) {  int64_t NuPlayer::Renderer::getRealTimeUs(int64_t mediaTimeUs, int64_t nowUs) {      int64_t currentPositionUs; -    if (getCurrentPosition(¤tPositionUs, nowUs, true /* allowPastQueuedVideo */) != OK) { +    if (mPaused || getCurrentPositionOnLooper( +            ¤tPositionUs, nowUs, true /* allowPastQueuedVideo */) != OK) {          // If failed to get current position, e.g. due to audio clock is not ready, then just          // play out video immediately without delay.          return nowUs; @@ -721,7 +793,7 @@ void NuPlayer::Renderer::onNewAudioMediaTime(int64_t mediaTimeUs) {              mediaTimeUs, nowUs + getPendingAudioPlayoutDurationUs(nowUs), mNumFramesWritten);  } -void NuPlayer::Renderer::postDrainVideoQueue() { +void NuPlayer::Renderer::postDrainVideoQueue_l() {      if (mDrainVideoQueuePending              || mSyncQueues              || (mPaused && mVideoSampleReceived)) { @@ -757,6 +829,8 @@ void NuPlayer::Renderer::postDrainVideoQueue() {          if (mAnchorTimeMediaUs < 0) {              setAnchorTime(mediaTimeUs, nowUs); +            mPausePositionMediaTimeUs = mediaTimeUs; +            mAnchorMaxMediaUs = mediaTimeUs;              realTimeUs = nowUs;          } else {              realTimeUs = getRealTimeUs(mediaTimeUs, nowUs); @@ -792,11 +866,6 @@ void NuPlayer::Renderer::postDrainVideoQueue() {      ALOGW_IF(delayUs > 500000, "unusually high delayUs: %" PRId64, delayUs);      // post 2 display refreshes before rendering is due -    // FIXME currently this increases power consumption, so unless frame-accurate -    // AV sync is requested, post closer to required render time (at 0.63 vsyncs) -    if (!sFrameAccurateAVsync) { -        twoVsyncsUs >>= 4; -    }      msg->post(delayUs > twoVsyncsUs ? delayUs - twoVsyncsUs : 0);      mDrainVideoQueuePending = true; @@ -924,16 +993,15 @@ void NuPlayer::Renderer::onQueueBuffer(const sp<AMessage> &msg) {      entry.mFinalResult = OK;      entry.mBufferOrdinal = ++mTotalBuffersQueued; +    Mutex::Autolock autoLock(mLock);      if (audio) { -        Mutex::Autolock autoLock(mLock);          mAudioQueue.push_back(entry);          postDrainAudioQueue_l();      } else {          mVideoQueue.push_back(entry); -        postDrainVideoQueue(); +        postDrainVideoQueue_l();      } -    Mutex::Autolock autoLock(mLock);      if (!mSyncQueues || mAudioQueue.empty() || mVideoQueue.empty()) {          return;      } @@ -982,7 +1050,7 @@ void NuPlayer::Renderer::syncQueuesDone_l() {      }      if (!mVideoQueue.empty()) { -        postDrainVideoQueue(); +        postDrainVideoQueue_l();      }  } @@ -1001,8 +1069,8 @@ void NuPlayer::Renderer::onQueueEOS(const sp<AMessage> &msg) {      entry.mOffset = 0;      entry.mFinalResult = finalResult; +    Mutex::Autolock autoLock(mLock);      if (audio) { -        Mutex::Autolock autoLock(mLock);          if (mAudioQueue.empty() && mSyncQueues) {              syncQueuesDone_l();          } @@ -1010,24 +1078,27 @@ void NuPlayer::Renderer::onQueueEOS(const sp<AMessage> &msg) {          postDrainAudioQueue_l();      } else {          if (mVideoQueue.empty() && mSyncQueues) { -            Mutex::Autolock autoLock(mLock);              syncQueuesDone_l();          }          mVideoQueue.push_back(entry); -        postDrainVideoQueue(); +        postDrainVideoQueue_l();      }  }  void NuPlayer::Renderer::onFlush(const sp<AMessage> &msg) { -    int32_t audio; +    int32_t audio, notifyComplete;      CHECK(msg->findInt32("audio", &audio));      {          Mutex::Autolock autoLock(mFlushLock);          if (audio) {              mFlushingAudio = false; +            notifyComplete = mNotifyCompleteAudio; +            mNotifyCompleteAudio = false;          } else {              mFlushingVideo = false; +            notifyComplete = mNotifyCompleteVideo; +            mNotifyCompleteVideo = false;          }      } @@ -1043,6 +1114,7 @@ void NuPlayer::Renderer::onFlush(const sp<AMessage> &msg) {           Mutex::Autolock autoLock(mLock);           syncQueuesDone_l();           setPauseStartedTimeRealUs(-1); +         setAnchorTime(-1, -1);      }      ALOGV("flushing %s", audio ? "audio" : "video"); @@ -1080,7 +1152,10 @@ void NuPlayer::Renderer::onFlush(const sp<AMessage> &msg) {      }      mVideoSampleReceived = false; -    notifyFlushComplete(audio); + +    if (notifyComplete) { +        notifyFlushComplete(audio); +    }  }  void NuPlayer::Renderer::flushQueue(List<QueueEntry> *queue) { @@ -1147,13 +1222,32 @@ void NuPlayer::Renderer::onDisableOffloadAudio() {      ++mAudioQueueGeneration;  } +void NuPlayer::Renderer::onEnableOffloadAudio() { +    Mutex::Autolock autoLock(mLock); +    mFlags |= FLAG_OFFLOAD_AUDIO; +    ++mAudioQueueGeneration; +} +  void NuPlayer::Renderer::onPause() {      if (mPaused) {          ALOGW("Renderer::onPause() called while already paused!");          return;      } +    int64_t currentPositionUs; +    int64_t pausePositionMediaTimeUs; +    if (getCurrentPositionFromAnchor( +            ¤tPositionUs, ALooper::GetNowUs()) == OK) { +        pausePositionMediaTimeUs = currentPositionUs; +    } else { +        // Set paused position to -1 (unavailabe) if we don't have anchor time +        // This could happen if client does a seekTo() immediately followed by +        // pause(). Renderer will be flushed with anchor time cleared. We don't +        // want to leave stale value in mPausePositionMediaTimeUs. +        pausePositionMediaTimeUs = -1; +    }      {          Mutex::Autolock autoLock(mLock); +        mPausePositionMediaTimeUs = pausePositionMediaTimeUs;          ++mAudioQueueGeneration;          ++mVideoQueueGeneration;          prepareForMediaRenderingStart(); @@ -1174,8 +1268,6 @@ void NuPlayer::Renderer::onPause() {  }  void NuPlayer::Renderer::onResume() { -    readProperties(); -      if (!mPaused) {          return;      } @@ -1199,7 +1291,7 @@ void NuPlayer::Renderer::onResume() {      }      if (!mVideoQueue.empty()) { -        postDrainVideoQueue(); +        postDrainVideoQueue_l();      }  } @@ -1281,7 +1373,7 @@ void NuPlayer::Renderer::onAudioOffloadTearDown(AudioOffloadTearDownReason reaso      mAudioOffloadTornDown = true;      int64_t currentPositionUs; -    if (getCurrentPosition(¤tPositionUs) != OK) { +    if (getCurrentPositionOnLooper(¤tPositionUs) != OK) {          currentPositionUs = 0;      } @@ -1297,6 +1389,7 @@ void NuPlayer::Renderer::onAudioOffloadTearDown(AudioOffloadTearDownReason reaso  void NuPlayer::Renderer::startAudioOffloadPauseTimeout() {      if (offloadingAudio()) { +        mWakeLock->acquire();          sp<AMessage> msg = new AMessage(kWhatAudioOffloadPauseTimeout, id());          msg->setInt32("generation", mAudioOffloadPauseTimeoutGeneration);          msg->post(kOffloadPauseMaxUs); @@ -1305,11 +1398,12 @@ void NuPlayer::Renderer::startAudioOffloadPauseTimeout() {  void NuPlayer::Renderer::cancelAudioOffloadPauseTimeout() {      if (offloadingAudio()) { +        mWakeLock->release(true);          ++mAudioOffloadPauseTimeoutGeneration;      }  } -bool NuPlayer::Renderer::onOpenAudioSink( +status_t NuPlayer::Renderer::onOpenAudioSink(          const sp<AMessage> &format,          bool offloadOnly,          bool hasVideo, @@ -1371,11 +1465,14 @@ bool NuPlayer::Renderer::onOpenAudioSink(              if (memcmp(&mCurrentOffloadInfo, &offloadInfo, sizeof(offloadInfo)) == 0) {                  ALOGV("openAudioSink: no change in offload mode");                  // no change from previous configuration, everything ok. -                return offloadingAudio(); +                return OK;              } +            mCurrentPcmInfo = AUDIO_PCMINFO_INITIALIZER; +              ALOGV("openAudioSink: try to open AudioSink in offload mode"); -            flags |= AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD; -            flags &= ~AUDIO_OUTPUT_FLAG_DEEP_BUFFER; +            uint32_t offloadFlags = flags; +            offloadFlags |= AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD; +            offloadFlags &= ~AUDIO_OUTPUT_FLAG_DEEP_BUFFER;              audioSinkChanged = true;              mAudioSink->close();              err = mAudioSink->open( @@ -1386,7 +1483,7 @@ bool NuPlayer::Renderer::onOpenAudioSink(                      8 /* bufferCount */,                      &NuPlayer::Renderer::AudioSinkCallback,                      this, -                    (audio_output_flags_t)flags, +                    (audio_output_flags_t)offloadFlags,                      &offloadInfo);              if (err == OK) { @@ -1410,13 +1507,27 @@ bool NuPlayer::Renderer::onOpenAudioSink(          }      }      if (!offloadOnly && !offloadingAudio()) { -        flags &= ~AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD;          ALOGV("openAudioSink: open AudioSink in NON-offload mode"); +        uint32_t pcmFlags = flags; +        pcmFlags &= ~AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD; + +        const PcmInfo info = { +                (audio_channel_mask_t)channelMask, +                (audio_output_flags_t)pcmFlags, +                AUDIO_FORMAT_PCM_16_BIT, // TODO: change to audioFormat +                numChannels, +                sampleRate +        }; +        if (memcmp(&mCurrentPcmInfo, &info, sizeof(info)) == 0) { +            ALOGV("openAudioSink: no change in pcm mode"); +            // no change from previous configuration, everything ok. +            return OK; +        }          audioSinkChanged = true;          mAudioSink->close();          mCurrentOffloadInfo = AUDIO_INFO_INITIALIZER; -        CHECK_EQ(mAudioSink->open( +        status_t err = mAudioSink->open(                      sampleRate,                      numChannels,                      (audio_channel_mask_t)channelMask, @@ -1424,20 +1535,28 @@ bool NuPlayer::Renderer::onOpenAudioSink(                      8 /* bufferCount */,                      NULL,                      NULL, -                    (audio_output_flags_t)flags), -                 (status_t)OK); +                    (audio_output_flags_t)pcmFlags); +        if (err != OK) { +            ALOGW("openAudioSink: non offloaded open failed status: %d", err); +            mCurrentPcmInfo = AUDIO_PCMINFO_INITIALIZER; +            return err; +        } +        mCurrentPcmInfo = info;          mAudioSink->start();      }      if (audioSinkChanged) {          onAudioSinkChanged();      } - -    return offloadingAudio(); +    if (offloadingAudio()) { +        mAudioOffloadTornDown = false; +    } +    return OK;  }  void NuPlayer::Renderer::onCloseAudioSink() {      mAudioSink->close();      mCurrentOffloadInfo = AUDIO_INFO_INITIALIZER; +    mCurrentPcmInfo = AUDIO_PCMINFO_INITIALIZER;  }  }  // namespace android  | 
