Ejemplo n.º 1
0
void AudioOffloadPlayer::TimeUpdate()
{
  MOZ_ASSERT(NS_IsMainThread());
  TimeStamp now = TimeStamp::Now();

  // If TIMEUPDATE_MS has passed since the last fire update event fired, fire
  // another timeupdate event.
  if ((mLastFireUpdateTime.IsNull() ||
      now - mLastFireUpdateTime >=
          TimeDuration::FromMilliseconds(TIMEUPDATE_MS))) {
    mLastFireUpdateTime = now;
    NotifyPositionChanged();
  }

  if (mPlayState != MediaDecoder::PLAY_STATE_PLAYING || !mIsElementVisible) {
    StopTimeUpdate();
  }
}
Ejemplo n.º 2
0
size_t AudioOffloadPlayer::FillBuffer(void* aData, size_t aSize)
{
  CHECK(mAudioSink.get());

  if (mReachedEOS) {
    return 0;
  }

  size_t sizeDone = 0;
  size_t sizeRemaining = aSize;
  while (sizeRemaining > 0) {
    MediaSource::ReadOptions options;
    bool refreshSeekTime = false;

    {
      android::Mutex::Autolock autoLock(mLock);

      if (mSeeking) {
        options.setSeekTo(mSeekTimeUs);
        refreshSeekTime = true;

        if (mInputBuffer) {
          mInputBuffer->release();
          mInputBuffer = nullptr;
        }
        mSeeking = false;
      }
    }

    if (!mInputBuffer) {

      status_t err;
      err = mSource->read(&mInputBuffer, &options);

      CHECK((!err && mInputBuffer) || (err && !mInputBuffer));

      android::Mutex::Autolock autoLock(mLock);

      if (err != OK) {
        AUDIO_OFFLOAD_LOG(PR_LOG_ERROR, ("Error while reading media source %d "
            "Ok to receive EOS error at end", err));
        if (!mReachedEOS) {
          // After seek there is a possible race condition if
          // OffloadThread is observing state_stopping_1 before
          // framesReady() > 0. Ensure sink stop is called
          // after last buffer is released. This ensures the
          // partial buffer is written to the driver before
          // stopping one is observed.The drawback is that
          // there will be an unnecessary call to the parser
          // after parser signalled EOS.
          if (sizeDone > 0) {
            AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("send Partial buffer down"));
            AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("skip calling stop till next"
                " fillBuffer"));
            break;
          }
          // no more buffers to push - stop() and wait for STREAM_END
          // don't set mReachedEOS until stream end received
          mAudioSink->Stop();
        }
        break;
      }

      if(mInputBuffer->range_length() != 0) {
        CHECK(mInputBuffer->meta_data()->findInt64(
            kKeyTime, &mPositionTimeMediaUs));
      }

      if (refreshSeekTime) {
        if (mDispatchSeekEvents && !mSeekDuringPause) {
          mDispatchSeekEvents = false;
          AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("FillBuffer posting SEEK_COMPLETE"));
          nsCOMPtr<nsIRunnable> nsEvent = NS_NewRunnableMethod(mObserver,
              &MediaDecoder::SeekingStopped);
          NS_DispatchToMainThread(nsEvent, NS_DISPATCH_NORMAL);

        } else if (mSeekDuringPause) {
          // Callback is already called for seek during pause. Just reset the
          // flag
          AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("Not posting seek complete as its"
              " already faked"));
          mSeekDuringPause = false;
        }

        NotifyPositionChanged();

        // need to adjust the mStartPosUs for offload decoding since parser
        // might not be able to get the exact seek time requested.
        mStartPosUs = mPositionTimeMediaUs;
        AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("Adjust seek time to: %.2f",
            mStartPosUs / 1E6));

        // clear seek time with mLock locked and once we have valid
        // mPositionTimeMediaUs
        // before clearing mSeekTimeUs check if a new seek request has been
        // received while we were reading from the source with mLock released.
        if (!mSeeking) {
          mSeekTimeUs = 0;
        }
      }
    }

    if (mInputBuffer->range_length() == 0) {
      mInputBuffer->release();
      mInputBuffer = nullptr;
      continue;
    }

    size_t copy = sizeRemaining;
    if (copy > mInputBuffer->range_length()) {
      copy = mInputBuffer->range_length();
    }

    memcpy((char *)aData + sizeDone,
        (const char *)mInputBuffer->data() + mInputBuffer->range_offset(),
        copy);

    mInputBuffer->set_range(mInputBuffer->range_offset() + copy,
        mInputBuffer->range_length() - copy);

    sizeDone += copy;
    sizeRemaining -= copy;
  }
  return sizeDone;
}
Ejemplo n.º 3
0
size_t AudioOffloadPlayer::FillBuffer(void* aData, size_t aSize)
{
  CHECK(mAudioSink.get());

  if (mReachedEOS) {
    return 0;
  }

  size_t sizeDone = 0;
  size_t sizeRemaining = aSize;
  int64_t seekTimeUs = -1;
  while (sizeRemaining > 0) {
    MediaSource::ReadOptions options;
    bool refreshSeekTime = false;
    {
      android::Mutex::Autolock autoLock(mLock);

      if (mSeekTarget.IsValid()) {
        seekTimeUs = mSeekTarget.mTime;
        options.setSeekTo(seekTimeUs);
        refreshSeekTime = true;

        if (mInputBuffer) {
          mInputBuffer->release();
          mInputBuffer = nullptr;
        }
      }
    }

    if (!mInputBuffer) {
      status_t err;
      err = mSource->read(&mInputBuffer, &options);

      CHECK((!err && mInputBuffer) || (err && !mInputBuffer));

      android::Mutex::Autolock autoLock(mLock);

      if (err != OK) {
        if (mSeekTarget.IsValid()) {
          mSeekTarget.Reset();
        }
        AUDIO_OFFLOAD_LOG(PR_LOG_ERROR, ("Error while reading media source %d "
            "Ok to receive EOS error at end", err));
        if (!mReachedEOS) {
          // After seek there is a possible race condition if
          // OffloadThread is observing state_stopping_1 before
          // framesReady() > 0. Ensure sink stop is called
          // after last buffer is released. This ensures the
          // partial buffer is written to the driver before
          // stopping one is observed.The drawback is that
          // there will be an unnecessary call to the parser
          // after parser signalled EOS.
          if (sizeDone > 0) {
            AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("send Partial buffer down"));
            AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("skip calling stop till next"
                " fillBuffer"));
            break;
          }
          // no more buffers to push - stop() and wait for STREAM_END
          // don't set mReachedEOS until stream end received
          mAudioSink->Stop();
        }
        break;
      }

      if(mInputBuffer->range_length() != 0) {
        CHECK(mInputBuffer->meta_data()->findInt64(
            kKeyTime, &mPositionTimeMediaUs));
      }

      if (mSeekTarget.IsValid() && seekTimeUs == mSeekTarget.mTime) {
        MOZ_ASSERT(mSeekTarget.IsValid());
        mSeekTarget.Reset();
        if (!mSeekPromise.IsEmpty()) {
          AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("FillBuffer posting SEEK_COMPLETE"));
          MediaDecoder::SeekResolveValue val(mReachedEOS, mSeekTarget.mEventVisibility);
          mSeekPromise.Resolve(val, __func__);
        }
      } else if (mSeekTarget.IsValid()) {
        AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("seek is updated during unlocking mLock"));
      }

      if (refreshSeekTime) {
        NotifyPositionChanged();

        // need to adjust the mStartPosUs for offload decoding since parser
        // might not be able to get the exact seek time requested.
        mStartPosUs = mPositionTimeMediaUs;
        AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("Adjust seek time to: %.2f",
            mStartPosUs / 1E6));
      }
    }

    if (mInputBuffer->range_length() == 0) {
      mInputBuffer->release();
      mInputBuffer = nullptr;
      continue;
    }

    size_t copy = sizeRemaining;
    if (copy > mInputBuffer->range_length()) {
      copy = mInputBuffer->range_length();
    }

    memcpy((char *)aData + sizeDone,
        (const char *)mInputBuffer->data() + mInputBuffer->range_offset(),
        copy);

    mInputBuffer->set_range(mInputBuffer->range_offset() + copy,
        mInputBuffer->range_length() - copy);

    sizeDone += copy;
    sizeRemaining -= copy;
  }
  return sizeDone;
}