Skip to content

Commit 976e659

Browse files
johngroAndroid Git Automerger
authored andcommitted
am 092bae6: LibAAH_RTP: Properly handle EOS conditions.
* commit '092bae63f14eac9538a5d4e60a528af255471a6f': LibAAH_RTP: Properly handle EOS conditions.
2 parents ed45df9 + 092bae6 commit 976e659

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)