Skip to content

Commit 092bae6

Browse files
committed
LibAAH_RTP: Properly handle EOS conditions.
EOS was being treated as a flush operation which was causing problems. In particular, the transmitter was delcaring that playback was complete early (by the clock lead time of the system, which was 1 second in this case). Also, the receiver was treating the EOS message just like the flush message, immediately destroying the substreams associated with the program without letting them play out first. Change the transmitter to send the EOS message like it always does, but have it wait until the media time of the last sample has arrived before reporting playback complete to the app level of things. On the receiver side of things, don't treat the EOS message like the flush message. Instead, have the EOS message simply put the substream into EOS mode, allowing it to signal EOS to its decoder and shut off the isAboutToUnderflow hack. Change-Id: Ibe3ac01044373f83edb7a5f4b70478bd78c16d11
1 parent fa9ea48 commit 092bae6

File tree

5 files changed

+160
-50
lines changed

5 files changed

+160
-50
lines changed

media/libaah_rtp/aah_rx_player.h

Lines changed: 30 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ class AAH_RXPlayer : public MediaPlayerInterface {
192192
void processTSTransform(const LinearTransform& trans);
193193

194194
bool isAboutToUnderflow();
195+
void signalEOS();
195196
uint32_t getSSRC() const { return ssrc_; }
196197
uint8_t getProgramID() const { return (ssrc_ >> 5) & 0x1F; }
197198
status_t getStatus() const { return status_; }
@@ -217,34 +218,35 @@ class AAH_RXPlayer : public MediaPlayerInterface {
217218
virtual ~Substream();
218219

219220
private:
220-
void cleanupDecoder();
221-
bool shouldAbort(const char* log_tag);
222-
void processCompletedBuffer();
223-
bool setupSubstreamMeta();
224-
bool setupMP3SubstreamMeta();
225-
bool setupAACSubstreamMeta();
226-
bool setupSubstreamType(uint8_t substream_type,
227-
uint8_t codec_type);
228-
229-
uint32_t ssrc_;
230-
bool waiting_for_rap_;
231-
status_t status_;
232-
233-
bool substream_details_known_;
234-
uint8_t substream_type_;
235-
uint8_t codec_type_;
236-
const char* codec_mime_type_;
237-
sp<MetaData> substream_meta_;
238-
239-
MediaBuffer* buffer_in_progress_;
240-
uint32_t expected_buffer_size_;
241-
uint32_t buffer_filled_;
242-
243-
Vector<uint8_t> aux_data_in_progress_;
244-
uint32_t aux_data_expected_size_;
245-
246-
sp<AAH_DecoderPump> decoder_;
247-
Timeout inactivity_timeout_;
221+
void cleanupDecoder();
222+
bool shouldAbort(const char* log_tag);
223+
void processCompletedBuffer();
224+
bool setupSubstreamMeta();
225+
bool setupMP3SubstreamMeta();
226+
bool setupAACSubstreamMeta();
227+
bool setupSubstreamType(uint8_t substream_type,
228+
uint8_t codec_type);
229+
230+
uint32_t ssrc_;
231+
bool waiting_for_rap_;
232+
status_t status_;
233+
234+
bool substream_details_known_;
235+
uint8_t substream_type_;
236+
uint8_t codec_type_;
237+
const char* codec_mime_type_;
238+
sp<MetaData> substream_meta_;
239+
240+
MediaBuffer* buffer_in_progress_;
241+
uint32_t expected_buffer_size_;
242+
uint32_t buffer_filled_;
243+
244+
Vector<uint8_t> aux_data_in_progress_;
245+
uint32_t aux_data_expected_size_;
246+
247+
sp<AAH_DecoderPump> decoder_;
248+
Timeout inactivity_timeout_;
249+
bool eos_reached_;
248250

249251
static const int64_t kAboutToUnderflowThreshold;
250252
static const int kInactivityTimeoutMsec;

media/libaah_rtp/aah_rx_player_core.cpp

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -682,6 +682,7 @@ void AAH_RXPlayer::processCommandPacket(PacketBuffer* pb) {
682682

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

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

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

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

703714
// Flag any programs with the given program ID for cleanup.
704715
for (size_t i = 0; i < substreams_.size(); ++i) {

media/libaah_rtp/aah_rx_player_substream.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ AAH_RXPlayer::Substream::Substream(uint32_t ssrc, OMXClient& omx) {
4343
buffer_in_progress_ = NULL;
4444
status_ = OK;
4545
codec_mime_type_ = "";
46+
eos_reached_ = false;
4647

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

641+
void AAH_RXPlayer::Substream::signalEOS() {
642+
if (!eos_reached_) {
643+
LOGI("Substream with SSRC 0x%08x now at EOS", ssrc_);
644+
eos_reached_ = true;
645+
}
646+
647+
// TODO: Be sure to signal EOS to our decoder so that it can flush out any
648+
// reordered samples. Not supporting video right now, so its not super
649+
// important.
650+
}
651+
640652
bool AAH_RXPlayer::Substream::isAboutToUnderflow() {
653+
// If we have no decoder, we cannot be about to underflow.
641654
if (decoder_ == NULL) {
642655
return false;
643656
}
644657

658+
// If we have hit EOS, we will not be receiveing any new samples, so the
659+
// about-to-underflow hack/heuristic is no longer valid. We should just
660+
// return false to be safe.
661+
if (eos_reached_) {
662+
return false;
663+
}
664+
645665
return decoder_->isAboutToUnderflow(kAboutToUnderflowThreshold);
646666
}
647667

media/libaah_rtp/aah_tx_player.cpp

Lines changed: 91 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,11 @@ static const int64_t kAAHBufferTimeUs = 1000000LL;
5353
const int64_t AAH_TXPlayer::kAAHRetryKeepAroundTimeNs =
5454
kAAHBufferTimeUs * 1100;
5555

56+
const int AAH_TXPlayer::kEOSResendTimeoutMsec = 100;
5657
const int AAH_TXPlayer::kPauseTSUpdateResendTimeoutMsec = 250;
5758
const int32_t AAH_TXPlayer::kInvokeGetCNCPort = 0xB33977;
5859

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

524526
status_t AAH_TXPlayer::stop() {
525527
status_t ret = pause();
528+
mEOSResendTimeout.setTimeout(-1);
526529
mPauseTSUpdateResendTimeout.setTimeout(-1);
527-
sendEOS_l();
530+
sendFlush_l();
528531
return ret;
529532
}
530533

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

594597
// if we are paused, schedule a periodic resend of the TS update, JiC the
595-
// receiveing client misses it.
598+
// receiveing client misses it. Don't bother setting the timer if we have
599+
// hit EOS; the EOS message will carry the update for us and serve the same
600+
// purpose as the pause updates.
596601
if (mPlayRateIsPaused) {
597602
mPauseTSUpdateResendTimeout.setTimeout(kPauseTSUpdateResendTimeoutMsec);
598603
} else {
@@ -604,12 +609,32 @@ void AAH_TXPlayer::sendEOS_l() {
604609
if (mAAH_TXGroup != NULL) {
605610
sp<TRTPControlPacket> packet = new TRTPControlPacket();
606611
if (packet != NULL) {
612+
if (mCurrentClockTransformValid) {
613+
packet->setClockTransform(mCurrentClockTransform);
614+
}
607615
packet->setCommandID(TRTPControlPacket::kCommandEOS);
608616
sendPacket_l(packet);
609617
} else {
610618
LOGD("Failed to allocate TRTP packet at %s:%d", __FILE__, __LINE__);
611619
}
612620
}
621+
622+
// While we are waiting to reach the end of the actual presentation and have
623+
// the app clean us up, periodically resend the EOS message, just it case it
624+
// was dropped.
625+
mEOSResendTimeout.setTimeout(kEOSResendTimeoutMsec);
626+
}
627+
628+
void AAH_TXPlayer::sendFlush_l() {
629+
if (mAAH_TXGroup != NULL) {
630+
sp<TRTPControlPacket> packet = new TRTPControlPacket();
631+
if (packet != NULL) {
632+
packet->setCommandID(TRTPControlPacket::kCommandFlush);
633+
sendPacket_l(packet);
634+
} else {
635+
LOGD("Failed to allocate TRTP packet at %s:%d", __FILE__, __LINE__);
636+
}
637+
}
613638
}
614639

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

642667
status_t AAH_TXPlayer::seekTo_l(int64_t timeUs) {
643668
mIsSeeking = true;
669+
mEOSResendTimeout.setTimeout(-1);
644670
mSeekTimeUs = timeUs;
645671

646672
mCurrentClockTransformValid = false;
647673
mLastQueuedMediaTimePTSValid = false;
648674

649-
// send a flush command packet
650-
if (mAAH_TXGroup != NULL) {
651-
sp<TRTPControlPacket> packet = new TRTPControlPacket();
652-
if (packet != NULL) {
653-
packet->setCommandID(TRTPControlPacket::kCommandFlush);
654-
sendPacket_l(packet);
655-
} else {
656-
LOGD("Failed to allocate TRTP packet at %s:%d", __FILE__, __LINE__);
657-
}
658-
}
675+
sendFlush_l();
659676

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

749766
cancelPlayerEvents();
750767

751-
sendEOS_l();
768+
sendFlush_l();
752769

753770
mCachedSource.clear();
754771

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

789+
mEOSResendTimeout.setTimeout(-1);
772790
mPauseTSUpdateResendTimeout.setTimeout(-1);
773791

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

1182+
// If we have hit EOS, then we will have an EOS resend timeout set.
1183+
int msecTillEOSResend = mEOSResendTimeout.msecTillTimeout();
1184+
if (msecTillEOSResend >= 0) {
1185+
// Resend the EOS message if its time.
1186+
if (!msecTillEOSResend) {
1187+
sendEOS_l();
1188+
}
1189+
1190+
// Declare playback complete to the app level if we have passed the
1191+
// PTS of the last sample queued, then cancel the EOS resend timer.
1192+
if (mediaTimeNowValid &&
1193+
mLastQueuedMediaTimePTSValid &&
1194+
((mLastQueuedMediaTimePTS - mediaTimeNow) <= 0)) {
1195+
LOGI("Sending playback complete");
1196+
pause_l(false);
1197+
notifyListener_l(MEDIA_PLAYBACK_COMPLETE);
1198+
mEOSResendTimeout.setTimeout(-1);
1199+
1200+
// Return directly from here to avoid rescheduling ourselves.
1201+
return;
1202+
}
1203+
1204+
// Once we have hit EOS, we are done until we seek or are reset.
1205+
break;
1206+
}
1207+
1208+
// Stop if we have reached our buffer threshold.
1209+
if (mediaTimeNowValid &&
1210+
mLastQueuedMediaTimePTSValid &&
1211+
(mediaTimeNow + kAAHBufferTimeUs - mLastQueuedMediaTimePTS) <= 0) {
1212+
break;
1213+
}
1214+
11641215
// Stop if we have reached our buffer threshold.
11651216
if (mediaTimeNowValid &&
11661217
mLastQueuedMediaTimePTSValid &&
@@ -1177,11 +1228,34 @@ void AAH_TXPlayer::onPumpAudio() {
11771228
status_t err = mAudioSource->read(&mediaBuffer, &options);
11781229
if (err != NO_ERROR) {
11791230
if (err == ERROR_END_OF_STREAM) {
1180-
LOGI("*** %s reached end of stream", __PRETTY_FUNCTION__);
1181-
notifyListener_l(MEDIA_BUFFERING_UPDATE, 100);
1182-
notifyListener_l(MEDIA_PLAYBACK_COMPLETE);
1183-
pause_l(false);
1231+
LOGI("Demux reached reached end of stream.");
1232+
1233+
// Send an EOS message to our receivers so that they know there
1234+
// is no more data coming and can behave appropriately.
11841235
sendEOS_l();
1236+
1237+
// One way or the other, we are "completely buffered" at this
1238+
// point since we have hit the end of stream.
1239+
notifyListener_l(MEDIA_BUFFERING_UPDATE, 100);
1240+
1241+
// Do not send the playback complete message yet. Instead, wait
1242+
// until we pass the presentation time of the last sample we
1243+
// queued to report playback complete up to the higher levels of
1244+
// code.
1245+
//
1246+
// It would be very odd to not have a last PTS at this point in
1247+
// time, but if we don't (for whatever reason), just go ahead
1248+
// and send the playback complete right now so we don't end up
1249+
// stuck.
1250+
if (!mLastQueuedMediaTimePTSValid) {
1251+
LOGW("Sending playback complete (no valid last PTS)");
1252+
pause_l(false);
1253+
notifyListener_l(MEDIA_PLAYBACK_COMPLETE);
1254+
mEOSResendTimeout.setTimeout(-1);
1255+
} else {
1256+
// Break out of the loop to reschude ourselves.
1257+
break;
1258+
}
11851259
} else {
11861260
LOGE("*** %s read failed err=%d", __PRETTY_FUNCTION__, err);
11871261
}

media/libaah_rtp/aah_tx_player.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ class AAH_TXPlayer : public MediaPlayerHWInterface {
106106
status_t seekTo_l(int64_t timeUs);
107107
void updateClockTransform_l(bool pause);
108108
void sendEOS_l();
109+
void sendFlush_l();
109110
void sendTSUpdateNop_l();
110111
void cancelPlayerEvents(bool keepBufferingGoing = false);
111112
void reset_l();
@@ -143,6 +144,7 @@ class AAH_TXPlayer : public MediaPlayerHWInterface {
143144
bool mIsSeeking;
144145
int64_t mSeekTimeUs;
145146

147+
Timeout mEOSResendTimeout;
146148
Timeout mPauseTSUpdateResendTimeout;
147149

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

176+
static const int kEOSResendTimeoutMsec;
174177
static const int kPauseTSUpdateResendTimeoutMsec;
175178

176179
DISALLOW_EVIL_CONSTRUCTORS(AAH_TXPlayer);

0 commit comments

Comments
 (0)