Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 976e659d authored by John Grossman's avatar John Grossman Committed by Android Git Automerger
Browse files

am 092bae63: LibAAH_RTP: Properly handle EOS conditions.

* commit '092bae63':
  LibAAH_RTP: Properly handle EOS conditions.
parents ed45df91 092bae63
Loading
Loading
Loading
Loading
+30 −28
Original line number Diff line number Diff line
@@ -192,6 +192,7 @@ class AAH_RXPlayer : public MediaPlayerInterface {
        void processTSTransform(const LinearTransform& trans);

        bool     isAboutToUnderflow();
        void     signalEOS();
        uint32_t getSSRC()      const { return ssrc_; }
        uint8_t  getProgramID() const { return (ssrc_ >> 5) & 0x1F; }
        status_t getStatus() const { return status_; }
@@ -245,6 +246,7 @@ class AAH_RXPlayer : public MediaPlayerInterface {

        sp<AAH_DecoderPump>     decoder_;
        Timeout                 inactivity_timeout_;
        bool                    eos_reached_;

        static const int64_t    kAboutToUnderflowThreshold;
        static const int        kInactivityTimeoutMsec;
+16 −5
Original line number Diff line number Diff line
@@ -682,6 +682,7 @@ void AAH_RXPlayer::processCommandPacket(PacketBuffer* pb) {

    bool do_cleanup_pass = false;
    uint16_t command_id = U16_AT(data + offset);
    uint8_t  program_id = (U32_AT(data + 8) >> 5) & 0x1F;
    offset += 2;

    switch (command_id) {
@@ -692,13 +693,23 @@ void AAH_RXPlayer::processCommandPacket(PacketBuffer* pb) {
            break;

        case TRTPControlPacket::kCommandEOS:
            // TODO need to differentiate between flush and EOS.  Substreams
            // which have hit EOS need a chance to drain before being destroyed.
            // Flag the substreams which are a member of this program as having
            // hit EOS.  Once in the EOS state, it is not possible to get out.
            // It is possible to pause and unpause, but the only way out would
            // be to seek, or to stop completely.  Both of these operations
            // would involve a flush, which would destroy and (possibly)
            // recreate a new the substream, getting rid of the EOS flag in the
            // process.
            for (size_t i = 0; i < substreams_.size(); ++i) {
                const sp<Substream>& stream = substreams_.valueAt(i);
                if (stream->getProgramID() == program_id) {
                    stream->signalEOS();
                }
            }
            break;

        case TRTPControlPacket::kCommandFlush: {
            uint8_t program_id = (U32_AT(data + 8) >> 5) & 0x1F;
            LOGI("*** %s flushing program_id=%d",
                 __PRETTY_FUNCTION__, program_id);
            LOGI("Flushing program_id=%d", program_id);

            // Flag any programs with the given program ID for cleanup.
            for (size_t i = 0; i < substreams_.size(); ++i) {
+20 −0
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@ AAH_RXPlayer::Substream::Substream(uint32_t ssrc, OMXClient& omx) {
    buffer_in_progress_ = NULL;
    status_ = OK;
    codec_mime_type_ = "";
    eos_reached_ = false;

    decoder_ = new AAH_DecoderPump(omx);
    if (decoder_ == NULL) {
@@ -637,11 +638,30 @@ void AAH_RXPlayer::Substream::processTSTransform(const LinearTransform& trans) {
    }
}

void AAH_RXPlayer::Substream::signalEOS() {
    if (!eos_reached_) {
        LOGI("Substream with SSRC 0x%08x now at EOS", ssrc_);
        eos_reached_ = true;
    }

    // TODO: Be sure to signal EOS to our decoder so that it can flush out any
    // reordered samples.  Not supporting video right now, so its not super
    // important.
}

bool AAH_RXPlayer::Substream::isAboutToUnderflow() {
    // If we have no decoder, we cannot be about to underflow.
    if (decoder_ == NULL) {
        return false;
    }

    // If we have hit EOS, we will not be receiveing any new samples, so the
    // about-to-underflow hack/heuristic is no longer valid.  We should just
    // return false to be safe.
    if (eos_reached_) {
        return false;
    }

    return decoder_->isAboutToUnderflow(kAboutToUnderflowThreshold);
}

+91 −17
Original line number Diff line number Diff line
@@ -53,9 +53,11 @@ static const int64_t kAAHBufferTimeUs = 1000000LL;
const int64_t AAH_TXPlayer::kAAHRetryKeepAroundTimeNs =
    kAAHBufferTimeUs * 1100;

const int AAH_TXPlayer::kEOSResendTimeoutMsec = 100;
const int AAH_TXPlayer::kPauseTSUpdateResendTimeoutMsec = 250;
const int32_t AAH_TXPlayer::kInvokeGetCNCPort = 0xB33977;


sp<MediaPlayerBase> createAAH_TXPlayer() {
    sp<MediaPlayerBase> ret = new AAH_TXPlayer();
    return ret;
@@ -523,8 +525,9 @@ status_t AAH_TXPlayer::play_l() {

status_t AAH_TXPlayer::stop() {
    status_t ret = pause();
    mEOSResendTimeout.setTimeout(-1);
    mPauseTSUpdateResendTimeout.setTimeout(-1);
    sendEOS_l();
    sendFlush_l();
    return ret;
}

@@ -592,7 +595,9 @@ void AAH_TXPlayer::updateClockTransform_l(bool pause) {
    sendTSUpdateNop_l();

    // if we are paused, schedule a periodic resend of the TS update, JiC the
    // receiveing client misses it.
    // receiveing client misses it.  Don't bother setting the timer if we have
    // hit EOS; the EOS message will carry the update for us and serve the same
    // purpose as the pause updates.
    if (mPlayRateIsPaused) {
        mPauseTSUpdateResendTimeout.setTimeout(kPauseTSUpdateResendTimeoutMsec);
    } else {
@@ -604,12 +609,32 @@ void AAH_TXPlayer::sendEOS_l() {
    if (mAAH_TXGroup != NULL) {
        sp<TRTPControlPacket> packet = new TRTPControlPacket();
        if (packet != NULL) {
            if (mCurrentClockTransformValid) {
                packet->setClockTransform(mCurrentClockTransform);
            }
            packet->setCommandID(TRTPControlPacket::kCommandEOS);
            sendPacket_l(packet);
        } else {
            LOGD("Failed to allocate TRTP packet at %s:%d", __FILE__, __LINE__);
        }
    }

    // While we are waiting to reach the end of the actual presentation and have
    // the app clean us up, periodically resend the EOS message, just it case it
    // was dropped.
    mEOSResendTimeout.setTimeout(kEOSResendTimeoutMsec);
}

void AAH_TXPlayer::sendFlush_l() {
    if (mAAH_TXGroup != NULL) {
        sp<TRTPControlPacket> packet = new TRTPControlPacket();
        if (packet != NULL) {
            packet->setCommandID(TRTPControlPacket::kCommandFlush);
            sendPacket_l(packet);
        } else {
            LOGD("Failed to allocate TRTP packet at %s:%d", __FILE__, __LINE__);
        }
    }
}

void AAH_TXPlayer::sendTSUpdateNop_l() {
@@ -641,21 +666,13 @@ status_t AAH_TXPlayer::seekTo(int msec) {

status_t AAH_TXPlayer::seekTo_l(int64_t timeUs) {
    mIsSeeking = true;
    mEOSResendTimeout.setTimeout(-1);
    mSeekTimeUs = timeUs;

    mCurrentClockTransformValid = false;
    mLastQueuedMediaTimePTSValid = false;

    // send a flush command packet
    if (mAAH_TXGroup != NULL) {
        sp<TRTPControlPacket> packet = new TRTPControlPacket();
        if (packet != NULL) {
            packet->setCommandID(TRTPControlPacket::kCommandFlush);
            sendPacket_l(packet);
        } else {
            LOGD("Failed to allocate TRTP packet at %s:%d", __FILE__, __LINE__);
        }
    }
    sendFlush_l();

    return OK;
}
@@ -748,7 +765,7 @@ void AAH_TXPlayer::reset_l() {

    cancelPlayerEvents();

    sendEOS_l();
    sendFlush_l();

    mCachedSource.clear();

@@ -769,6 +786,7 @@ void AAH_TXPlayer::reset_l() {
    mIsSeeking = false;
    mSeekTimeUs = 0;

    mEOSResendTimeout.setTimeout(-1);
    mPauseTSUpdateResendTimeout.setTimeout(-1);

    mUri.setTo("");
@@ -1161,6 +1179,39 @@ void AAH_TXPlayer::onPumpAudio() {
            }
        }

        // If we have hit EOS, then we will have an EOS resend timeout set.
        int msecTillEOSResend = mEOSResendTimeout.msecTillTimeout();
        if (msecTillEOSResend >= 0) {
            // Resend the EOS message if its time.
            if (!msecTillEOSResend) {
                sendEOS_l();
            }

            // Declare playback complete to the app level if we have passed the
            // PTS of the last sample queued, then cancel the EOS resend timer.
            if (mediaTimeNowValid &&
                mLastQueuedMediaTimePTSValid &&
              ((mLastQueuedMediaTimePTS - mediaTimeNow) <= 0)) {
                LOGI("Sending playback complete");
                pause_l(false);
                notifyListener_l(MEDIA_PLAYBACK_COMPLETE);
                mEOSResendTimeout.setTimeout(-1);

                // Return directly from here to avoid rescheduling ourselves.
                return;
            }

            // Once we have hit EOS, we are done until we seek or are reset.
            break;
        }

        // Stop if we have reached our buffer threshold.
        if (mediaTimeNowValid &&
            mLastQueuedMediaTimePTSValid &&
           (mediaTimeNow + kAAHBufferTimeUs - mLastQueuedMediaTimePTS) <= 0) {
            break;
        }

        // Stop if we have reached our buffer threshold.
        if (mediaTimeNowValid &&
            mLastQueuedMediaTimePTSValid &&
@@ -1177,11 +1228,34 @@ void AAH_TXPlayer::onPumpAudio() {
        status_t err = mAudioSource->read(&mediaBuffer, &options);
        if (err != NO_ERROR) {
            if (err == ERROR_END_OF_STREAM) {
                LOGI("*** %s reached end of stream", __PRETTY_FUNCTION__);
                LOGI("Demux reached reached end of stream.");

                // Send an EOS message to our receivers so that they know there
                // is no more data coming and can behave appropriately.
                sendEOS_l();

                // One way or the other, we are "completely buffered" at this
                // point since we have hit the end of stream.
                notifyListener_l(MEDIA_BUFFERING_UPDATE, 100);
                notifyListener_l(MEDIA_PLAYBACK_COMPLETE);

                // Do not send the playback complete message yet.  Instead, wait
                // until we pass the presentation time of the last sample we
                // queued to report playback complete up to the higher levels of
                // code.
                //
                // It would be very odd to not have a last PTS at this point in
                // time, but if we don't (for whatever reason), just go ahead
                // and send the playback complete right now so we don't end up
                // stuck.
                if (!mLastQueuedMediaTimePTSValid) {
                    LOGW("Sending playback complete (no valid last PTS)");
                    pause_l(false);
                sendEOS_l();
                    notifyListener_l(MEDIA_PLAYBACK_COMPLETE);
                    mEOSResendTimeout.setTimeout(-1);
                } else {
                    // Break out of the loop to reschude ourselves.
                    break;
                }
            } else {
                LOGE("*** %s read failed err=%d", __PRETTY_FUNCTION__, err);
            }
+3 −0
Original line number Diff line number Diff line
@@ -106,6 +106,7 @@ class AAH_TXPlayer : public MediaPlayerHWInterface {
    status_t seekTo_l(int64_t timeUs);
    void updateClockTransform_l(bool pause);
    void sendEOS_l();
    void sendFlush_l();
    void sendTSUpdateNop_l();
    void cancelPlayerEvents(bool keepBufferingGoing = false);
    void reset_l();
@@ -143,6 +144,7 @@ class AAH_TXPlayer : public MediaPlayerHWInterface {
    bool mIsSeeking;
    int64_t mSeekTimeUs;

    Timeout mEOSResendTimeout;
    Timeout mPauseTSUpdateResendTimeout;

    sp<TimedEventQueue::Event> mPumpAudioEvent;
@@ -171,6 +173,7 @@ class AAH_TXPlayer : public MediaPlayerHWInterface {
    uint8_t mProgramID;
    uint8_t mTRTPVolume;

    static const int kEOSResendTimeoutMsec;
    static const int kPauseTSUpdateResendTimeoutMsec;

    DISALLOW_EVIL_CONSTRUCTORS(AAH_TXPlayer);