Loading media/libaah_rtp/aah_rx_player.h +30 −28 Original line number Diff line number Diff line Loading @@ -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_; } Loading Loading @@ -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; Loading media/libaah_rtp/aah_rx_player_core.cpp +16 −5 Original line number Diff line number Diff line Loading @@ -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) { Loading @@ -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) { Loading media/libaah_rtp/aah_rx_player_substream.cpp +20 −0 Original line number Diff line number Diff line Loading @@ -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) { Loading Loading @@ -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); } Loading media/libaah_rtp/aah_tx_player.cpp +91 −17 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; } Loading Loading @@ -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 { Loading @@ -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() { Loading Loading @@ -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; } Loading Loading @@ -748,7 +765,7 @@ void AAH_TXPlayer::reset_l() { cancelPlayerEvents(); sendEOS_l(); sendFlush_l(); mCachedSource.clear(); Loading @@ -769,6 +786,7 @@ void AAH_TXPlayer::reset_l() { mIsSeeking = false; mSeekTimeUs = 0; mEOSResendTimeout.setTimeout(-1); mPauseTSUpdateResendTimeout.setTimeout(-1); mUri.setTo(""); Loading Loading @@ -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 && Loading @@ -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); } Loading media/libaah_rtp/aah_tx_player.h +3 −0 Original line number Diff line number Diff line Loading @@ -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(); Loading Loading @@ -143,6 +144,7 @@ class AAH_TXPlayer : public MediaPlayerHWInterface { bool mIsSeeking; int64_t mSeekTimeUs; Timeout mEOSResendTimeout; Timeout mPauseTSUpdateResendTimeout; sp<TimedEventQueue::Event> mPumpAudioEvent; Loading Loading @@ -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); Loading Loading
media/libaah_rtp/aah_rx_player.h +30 −28 Original line number Diff line number Diff line Loading @@ -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_; } Loading Loading @@ -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; Loading
media/libaah_rtp/aah_rx_player_core.cpp +16 −5 Original line number Diff line number Diff line Loading @@ -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) { Loading @@ -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) { Loading
media/libaah_rtp/aah_rx_player_substream.cpp +20 −0 Original line number Diff line number Diff line Loading @@ -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) { Loading Loading @@ -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); } Loading
media/libaah_rtp/aah_tx_player.cpp +91 −17 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; } Loading Loading @@ -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 { Loading @@ -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() { Loading Loading @@ -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; } Loading Loading @@ -748,7 +765,7 @@ void AAH_TXPlayer::reset_l() { cancelPlayerEvents(); sendEOS_l(); sendFlush_l(); mCachedSource.clear(); Loading @@ -769,6 +786,7 @@ void AAH_TXPlayer::reset_l() { mIsSeeking = false; mSeekTimeUs = 0; mEOSResendTimeout.setTimeout(-1); mPauseTSUpdateResendTimeout.setTimeout(-1); mUri.setTo(""); Loading Loading @@ -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 && Loading @@ -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); } Loading
media/libaah_rtp/aah_tx_player.h +3 −0 Original line number Diff line number Diff line Loading @@ -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(); Loading Loading @@ -143,6 +144,7 @@ class AAH_TXPlayer : public MediaPlayerHWInterface { bool mIsSeeking; int64_t mSeekTimeUs; Timeout mEOSResendTimeout; Timeout mPauseTSUpdateResendTimeout; sp<TimedEventQueue::Event> mPumpAudioEvent; Loading Loading @@ -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); Loading