Better transport stream timestamp handling.

Properly emit PCR and PMT/PAT updates every 0.1 secs.
Don't stream RTCP unless requested by the dongle.

related-to-bug: 7232540
Change-Id: Ie9a6949a074d86ab022adfab5d2811294ba746aa
diff --git a/media/libstagefright/wifi-display/source/PlaybackSession.cpp b/media/libstagefright/wifi-display/source/PlaybackSession.cpp
index be9b159..99b3051 100644
--- a/media/libstagefright/wifi-display/source/PlaybackSession.cpp
+++ b/media/libstagefright/wifi-display/source/PlaybackSession.cpp
@@ -70,6 +70,9 @@
     status_t start();
     status_t stop();
 
+    void queueAccessUnit(const sp<ABuffer> &accessUnit);
+    sp<ABuffer> dequeueAccessUnit();
+
 protected:
     virtual ~Track();
 
@@ -82,6 +85,7 @@
     bool mStarted;
     ssize_t mPacketizerTrackIndex;
     bool mIsAudio;
+    List<sp<ABuffer> > mQueuedAccessUnits;
 
     static bool IsAudioFormat(const sp<AMessage> &format);
 
@@ -182,6 +186,24 @@
     return err;
 }
 
+void WifiDisplaySource::PlaybackSession::Track::queueAccessUnit(
+        const sp<ABuffer> &accessUnit) {
+    mQueuedAccessUnits.push_back(accessUnit);
+}
+
+sp<ABuffer> WifiDisplaySource::PlaybackSession::Track::dequeueAccessUnit() {
+    if (mQueuedAccessUnits.empty()) {
+        return NULL;
+    }
+
+    sp<ABuffer> accessUnit = *mQueuedAccessUnits.begin();
+    CHECK(accessUnit != NULL);
+
+    mQueuedAccessUnits.erase(mQueuedAccessUnits.begin());
+
+    return accessUnit;
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 
 WifiDisplaySource::PlaybackSession::PlaybackSession(
@@ -198,6 +220,7 @@
       mTSQueue(new ABuffer(12 + kMaxNumTSPacketsPerRTPPacket * 188)),
       mPrevTimeUs(-1ll),
       mTransportMode(TRANSPORT_UDP),
+      mAllTracksHavePacketizerIndex(false),
       mRTPChannel(0),
       mRTCPChannel(0),
       mRTPPort(0),
@@ -675,129 +698,49 @@
             if (what == Converter::kWhatAccessUnit) {
                 const sp<Track> &track = mTracks.valueFor(trackIndex);
 
-                uint32_t flags = 0;
-
                 ssize_t packetizerTrackIndex = track->packetizerTrackIndex();
-                if (packetizerTrackIndex < 0) {
-                    flags = TSPacketizer::EMIT_PAT_AND_PMT;
 
+                if (packetizerTrackIndex < 0) {
                     packetizerTrackIndex =
                         mPacketizer->addTrack(track->getFormat());
 
-                    if (packetizerTrackIndex >= 0) {
-                        track->setPacketizerTrackIndex(packetizerTrackIndex);
-                    }
-                }
+                    CHECK_GE(packetizerTrackIndex, 0);
 
-                if (packetizerTrackIndex >= 0) {
-                    sp<ABuffer> accessUnit;
-                    CHECK(msg->findBuffer("accessUnit", &accessUnit));
+                    track->setPacketizerTrackIndex(packetizerTrackIndex);
 
-                    bool isHDCPEncrypted = false;
-                    uint64_t inputCTR;
-                    uint8_t HDCP_private_data[16];
-                    if (mHDCP != NULL && !track->isAudio()) {
-                        isHDCPEncrypted = true;
-
-                        status_t err = mHDCP->encrypt(
-                                accessUnit->data(), accessUnit->size(),
-                                trackIndex  /* streamCTR */,
-                                &inputCTR,
-                                accessUnit->data());
+                    if (allTracksHavePacketizerIndex()) {
+                        status_t err = packetizeQueuedAccessUnits();
 
                         if (err != OK) {
-                            ALOGI("Failed to HDCP-encrypt media data (err %d)",
-                                  err);
-
                             // Inform WifiDisplaySource of our premature death
                             // (wish).
                             sp<AMessage> notify = mNotify->dup();
                             notify->setInt32("what", kWhatSessionDead);
                             notify->post();
+
                             break;
                         }
-
-                        HDCP_private_data[0] = 0x00;
-
-                        HDCP_private_data[1] =
-                            (((trackIndex >> 30) & 3) << 1) | 1;
-
-                        HDCP_private_data[2] = (trackIndex >> 22) & 0xff;
-
-                        HDCP_private_data[3] =
-                            (((trackIndex >> 15) & 0x7f) << 1) | 1;
-
-                        HDCP_private_data[4] = (trackIndex >> 7) & 0xff;
-
-                        HDCP_private_data[5] =
-                            ((trackIndex & 0x7f) << 1) | 1;
-
-                        HDCP_private_data[6] = 0x00;
-
-                        HDCP_private_data[7] =
-                            (((inputCTR >> 60) & 0x0f) << 1) | 1;
-
-                        HDCP_private_data[8] = (inputCTR >> 52) & 0xff;
-
-                        HDCP_private_data[9] =
-                            (((inputCTR >> 45) & 0x7f) << 1) | 1;
-
-                        HDCP_private_data[10] = (inputCTR >> 37) & 0xff;
-
-                        HDCP_private_data[11] =
-                            (((inputCTR >> 30) & 0x7f) << 1) | 1;
-
-                        HDCP_private_data[12] = (inputCTR >> 22) & 0xff;
-
-                        HDCP_private_data[13] =
-                            (((inputCTR >> 15) & 0x7f) << 1) | 1;
-
-                        HDCP_private_data[14] = (inputCTR >> 7) & 0xff;
-
-                        HDCP_private_data[15] =
-                            ((inputCTR & 0x7f) << 1) | 1;
-
-                        flags |= TSPacketizer::IS_ENCRYPTED;
                     }
-
-                    int64_t timeUs;
-                    CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs));
-
-                    if (mPrevTimeUs < 0ll || mPrevTimeUs + 100000ll >= timeUs) {
-                        flags |= TSPacketizer::EMIT_PCR;
-                        mPrevTimeUs = timeUs;
-                    }
-
-                    sp<ABuffer> packets;
-                    mPacketizer->packetize(
-                            packetizerTrackIndex, accessUnit, &packets, flags,
-                            isHDCPEncrypted ? NULL : HDCP_private_data,
-                            isHDCPEncrypted ? 0 : sizeof(HDCP_private_data));
-
-                    for (size_t offset = 0;
-                            offset < packets->size(); offset += 188) {
-                        bool lastTSPacket = (offset + 188 >= packets->size());
-
-                        // We're only going to flush video, audio packets are
-                        // much more frequent and would waste all that space
-                        // available in a full sized UDP packet.
-                        bool flush =
-                            lastTSPacket
-                                && ((ssize_t)trackIndex == mVideoTrackIndex);
-
-                        appendTSData(
-                                packets->data() + offset,
-                                188,
-                                true /* timeDiscontinuity */,
-                                flush);
-                    }
-
-#if LOG_TRANSPORT_STREAM
-                    if (mLogFile != NULL) {
-                        fwrite(packets->data(), 1, packets->size(), mLogFile);
-                    }
-#endif
                 }
+
+                sp<ABuffer> accessUnit;
+                CHECK(msg->findBuffer("accessUnit", &accessUnit));
+
+                if (!allTracksHavePacketizerIndex()) {
+                    track->queueAccessUnit(accessUnit);
+                    break;
+                }
+
+                status_t err = packetizeAccessUnit(trackIndex, accessUnit);
+
+                if (err != OK) {
+                    // Inform WifiDisplaySource of our premature death
+                    // (wish).
+                    sp<AMessage> notify = mNotify->dup();
+                    notify->setInt32("what", kWhatSessionDead);
+                    notify->post();
+                }
+                break;
             } else if (what == Converter::kWhatEOS) {
                 CHECK_EQ(what, Converter::kWhatEOS);
 
@@ -1338,5 +1281,157 @@
     return mNetSession->sendRequest(sessionID, data, size);
 }
 
+bool WifiDisplaySource::PlaybackSession::allTracksHavePacketizerIndex() {
+    if (mAllTracksHavePacketizerIndex) {
+        return true;
+    }
+
+    for (size_t i = 0; i < mTracks.size(); ++i) {
+        if (mTracks.valueAt(i)->packetizerTrackIndex() < 0) {
+            return false;
+        }
+    }
+
+    mAllTracksHavePacketizerIndex = true;
+
+    return true;
+}
+
+status_t WifiDisplaySource::PlaybackSession::packetizeAccessUnit(
+        size_t trackIndex, const sp<ABuffer> &accessUnit) {
+    const sp<Track> &track = mTracks.valueFor(trackIndex);
+
+    uint32_t flags = 0;
+
+    bool isHDCPEncrypted = false;
+    uint64_t inputCTR;
+    uint8_t HDCP_private_data[16];
+    if (mHDCP != NULL && !track->isAudio()) {
+        isHDCPEncrypted = true;
+
+        status_t err = mHDCP->encrypt(
+                accessUnit->data(), accessUnit->size(),
+                trackIndex  /* streamCTR */,
+                &inputCTR,
+                accessUnit->data());
+
+        if (err != OK) {
+            ALOGE("Failed to HDCP-encrypt media data (err %d)",
+                  err);
+
+            return err;
+        }
+
+        HDCP_private_data[0] = 0x00;
+
+        HDCP_private_data[1] =
+            (((trackIndex >> 30) & 3) << 1) | 1;
+
+        HDCP_private_data[2] = (trackIndex >> 22) & 0xff;
+
+        HDCP_private_data[3] =
+            (((trackIndex >> 15) & 0x7f) << 1) | 1;
+
+        HDCP_private_data[4] = (trackIndex >> 7) & 0xff;
+
+        HDCP_private_data[5] =
+            ((trackIndex & 0x7f) << 1) | 1;
+
+        HDCP_private_data[6] = 0x00;
+
+        HDCP_private_data[7] =
+            (((inputCTR >> 60) & 0x0f) << 1) | 1;
+
+        HDCP_private_data[8] = (inputCTR >> 52) & 0xff;
+
+        HDCP_private_data[9] =
+            (((inputCTR >> 45) & 0x7f) << 1) | 1;
+
+        HDCP_private_data[10] = (inputCTR >> 37) & 0xff;
+
+        HDCP_private_data[11] =
+            (((inputCTR >> 30) & 0x7f) << 1) | 1;
+
+        HDCP_private_data[12] = (inputCTR >> 22) & 0xff;
+
+        HDCP_private_data[13] =
+            (((inputCTR >> 15) & 0x7f) << 1) | 1;
+
+        HDCP_private_data[14] = (inputCTR >> 7) & 0xff;
+
+        HDCP_private_data[15] =
+            ((inputCTR & 0x7f) << 1) | 1;
+
+        flags |= TSPacketizer::IS_ENCRYPTED;
+    }
+
+    int64_t timeUs = ALooper::GetNowUs();
+    if (mPrevTimeUs < 0ll || mPrevTimeUs + 100000ll <= timeUs) {
+        flags |= TSPacketizer::EMIT_PCR;
+        flags |= TSPacketizer::EMIT_PAT_AND_PMT;
+
+        mPrevTimeUs = timeUs;
+    }
+
+    sp<ABuffer> packets;
+    mPacketizer->packetize(
+            track->packetizerTrackIndex(), accessUnit, &packets, flags,
+            isHDCPEncrypted ? NULL : HDCP_private_data,
+            isHDCPEncrypted ? 0 : sizeof(HDCP_private_data));
+
+    for (size_t offset = 0;
+            offset < packets->size(); offset += 188) {
+        bool lastTSPacket = (offset + 188 >= packets->size());
+
+        // We're only going to flush video, audio packets are
+        // much more frequent and would waste all that space
+        // available in a full sized UDP packet.
+        bool flush =
+            lastTSPacket
+                && ((ssize_t)trackIndex == mVideoTrackIndex);
+
+        appendTSData(
+                packets->data() + offset,
+                188,
+                true /* timeDiscontinuity */,
+                flush);
+    }
+
+#if LOG_TRANSPORT_STREAM
+    if (mLogFile != NULL) {
+        fwrite(packets->data(), 1, packets->size(), mLogFile);
+    }
+#endif
+
+    return OK;
+}
+
+status_t WifiDisplaySource::PlaybackSession::packetizeQueuedAccessUnits() {
+    for (;;) {
+        bool gotMoreData = false;
+        for (size_t i = 0; i < mTracks.size(); ++i) {
+            size_t trackIndex = mTracks.keyAt(i);
+            const sp<Track> &track = mTracks.valueAt(i);
+
+            sp<ABuffer> accessUnit = track->dequeueAccessUnit();
+            if (accessUnit != NULL) {
+                status_t err = packetizeAccessUnit(trackIndex, accessUnit);
+
+                if (err != OK) {
+                    return err;
+                }
+
+                gotMoreData = true;
+            }
+        }
+
+        if (!gotMoreData) {
+            break;
+        }
+    }
+
+    return OK;
+}
+
 }  // namespace android
 
diff --git a/media/libstagefright/wifi-display/source/PlaybackSession.h b/media/libstagefright/wifi-display/source/PlaybackSession.h
index f2090b4..6f74382 100644
--- a/media/libstagefright/wifi-display/source/PlaybackSession.h
+++ b/media/libstagefright/wifi-display/source/PlaybackSession.h
@@ -123,6 +123,8 @@
 
     AString mClientIP;
 
+    bool mAllTracksHavePacketizerIndex;
+
     // in TCP mode
     int32_t mRTPChannel;
     int32_t mRTCPChannel;
@@ -196,6 +198,13 @@
     status_t onFinishPlay();
     status_t onFinishPlay2();
 
+    bool allTracksHavePacketizerIndex();
+
+    status_t packetizeAccessUnit(
+            size_t trackIndex, const sp<ABuffer> &accessUnit);
+
+    status_t packetizeQueuedAccessUnits();
+
     DISALLOW_EVIL_CONSTRUCTORS(PlaybackSession);
 };
 
diff --git a/media/libstagefright/wifi-display/source/TSPacketizer.cpp b/media/libstagefright/wifi-display/source/TSPacketizer.cpp
index 613cc28..bd2f0c3 100644
--- a/media/libstagefright/wifi-display/source/TSPacketizer.cpp
+++ b/media/libstagefright/wifi-display/source/TSPacketizer.cpp
@@ -283,15 +283,15 @@
         const uint8_t *PES_private_data, size_t PES_private_data_len) {
     sp<ABuffer> accessUnit = _accessUnit;
 
+    int64_t timeUs;
+    CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs));
+
     packets->clear();
 
     if (trackIndex >= mTracks.size()) {
         return -ERANGE;
     }
 
-    int64_t timeUs;
-    CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs));
-
     const sp<Track> &track = mTracks.itemAt(trackIndex);
 
     if (track->isH264() && !(flags & IS_ENCRYPTED)) {
@@ -531,11 +531,7 @@
         // reserved = b111111
         // program_clock_reference_extension = b?????????
 
-#if 0
         int64_t nowUs = ALooper::GetNowUs();
-#else
-        int64_t nowUs = timeUs;
-#endif
 
         uint64_t PCR = nowUs * 27;  // PCR based on a 27MHz clock
         uint64_t PCR_base = PCR / 300;
@@ -560,7 +556,7 @@
         packetDataStart += 188;
     }
 
-    uint32_t PTS = (timeUs * 9ll) / 100ll;
+    uint64_t PTS = (timeUs * 9ll) / 100ll;
 
     bool padding = (PES_packet_length < (188 - 10));
 
diff --git a/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp b/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
index 787ccc0..7f7aeac 100644
--- a/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
+++ b/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
@@ -876,7 +876,6 @@
         } else if (sscanf(clientPort.c_str(), "%d", &clientRtp) == 1) {
             // No RTCP.
             clientRtcp = -1;
-            clientRtcp = clientRtp + 1;  // XXX
         } else {
             badRequest = true;
         }
@@ -889,7 +888,7 @@
     // The older LG dongles doesn't specify client_port=xxx apparently.
     } else if (transport == "RTP/AVP/UDP;unicast") {
         clientRtp = 19000;
-        clientRtcp = clientRtp + 1;
+        clientRtcp = -1;
 #endif
     } else {
         sendErrorResponse(sessionID, "461 Unsupported Transport", cseq);