Add send session recording summary report to application

Change-Id: I9c63ddae432f0c93486c39776ed0a058a8649602
diff --git a/include/media/mediarecorder.h b/include/media/mediarecorder.h
index 089577d..59093c9 100644
--- a/include/media/mediarecorder.h
+++ b/include/media/mediarecorder.h
@@ -161,8 +161,24 @@
     MEDIA_RECORDER_TRACK_INFO_PROGRESS_IN_TIME     = 1001,
     MEDIA_RECORDER_TRACK_INFO_TYPE                 = 1002,
     MEDIA_RECORDER_TRACK_INFO_DURATION_MS          = 1003,
+
+    // The time to measure the max chunk duration
     MEDIA_RECORDER_TRACK_INFO_MAX_CHUNK_DUR_MS     = 1004,
+
     MEDIA_RECORDER_TRACK_INFO_ENCODED_FRAMES       = 1005,
+
+    // The time to measure how well the audio and video
+    // track data is interleaved.
+    MEDIA_RECORDER_TRACK_INTER_CHUNK_TIME_MS       = 1006,
+
+    // The time to measure system response. Note that
+    // the delay does not include the intentional delay
+    // we use to eliminate the recording sound.
+    MEDIA_RECORDER_TRACK_INFO_INITIAL_DELAY_MS     = 1007,
+
+    // The time used to compensate for initial A/V sync.
+    MEDIA_RECORDER_TRACK_INFO_START_OFFSET_MS      = 1008,
+
     MEDIA_RECORDER_TRACK_INFO_LIST_END             = 2000,
 };
 
diff --git a/include/media/stagefright/MPEG4Writer.h b/include/media/stagefright/MPEG4Writer.h
index 57624e9..4b5674e 100644
--- a/include/media/stagefright/MPEG4Writer.h
+++ b/include/media/stagefright/MPEG4Writer.h
@@ -108,6 +108,13 @@
     struct ChunkInfo {
         Track               *mTrack;        // Owner
         List<Chunk>         mChunks;        // Remaining chunks to be written
+
+        // Previous chunk timestamp that has been written
+        int64_t mPrevChunkTimestampUs;
+
+        // Max time interval between neighboring chunks
+        int64_t mMaxInterChunkDurUs;
+
     };
 
     bool            mIsFirstChunk;
@@ -162,6 +169,7 @@
     void writeMvhdBox(int64_t durationUs);
     void writeMoovBox(int64_t durationUs);
     void writeFtypBox(const MetaData *param);
+    void sendSessionSummary();
 
     MPEG4Writer(const MPEG4Writer &);
     MPEG4Writer &operator=(const MPEG4Writer &);
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 9ed08a3..fd60f06 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -45,6 +45,7 @@
 static const int64_t kMax32BitFileSize = 0x007fffffffLL;
 static const uint8_t kNalUnitTypeSeqParamSet = 0x07;
 static const uint8_t kNalUnitTypePicParamSet = 0x08;
+static const int64_t kInitialDelayTimeUs     = 700000LL;
 
 // Using longer adjustment period to suppress fluctuations in
 // the audio encoding paths
@@ -69,6 +70,7 @@
     bool isAudio() const { return mIsAudio; }
     bool isMPEG4() const { return mIsMPEG4; }
     void addChunkOffset(off64_t offset);
+    int32_t getTrackId() const { return mTrackId; }
     status_t dump(int fd, const Vector<String16>& args) const;
 
 private:
@@ -157,6 +159,8 @@
 
     bool mReachedEOS;
     int64_t mStartTimestampUs;
+    int64_t mStartTimeRealUs;
+    int64_t mFirstSampleTimeRealUs;
     int64_t mPreviousTrackTimeUs;
     int64_t mTrackEveryTimeDurationUs;
 
@@ -688,6 +692,7 @@
     mFd = -1;
     mInitCheck = NO_INIT;
     mStarted = false;
+
     return err;
 }
 
@@ -744,6 +749,16 @@
     endBox();
 }
 
+void MPEG4Writer::sendSessionSummary() {
+    for (List<ChunkInfo>::iterator it = mChunkInfos.begin();
+         it != mChunkInfos.end(); ++it) {
+        int trackNum = it->mTrack->getTrackId() << 28;
+        notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
+                trackNum | MEDIA_RECORDER_TRACK_INTER_CHUNK_TIME_MS,
+                it->mMaxInterChunkDurUs);
+    }
+}
+
 status_t MPEG4Writer::setInterleaveDuration(uint32_t durationUs) {
     mInterleaveDurationUs = durationUs;
     return OK;
@@ -1188,18 +1203,13 @@
 void MPEG4Writer::writeAllChunks() {
     LOGV("writeAllChunks");
     size_t outstandingChunks = 0;
-    while (!mChunkInfos.empty()) {
-        List<ChunkInfo>::iterator it = mChunkInfos.begin();
-        while (!it->mChunks.empty()) {
-            Chunk chunk;
-            if (findChunkToWrite(&chunk)) {
-                writeChunkToFile(&chunk);
-                ++outstandingChunks;
-            }
-        }
-        it->mTrack = NULL;
-        mChunkInfos.erase(it);
+    Chunk chunk;
+    while (findChunkToWrite(&chunk)) {
+        ++outstandingChunks;
     }
+
+    sendSessionSummary();
+
     mChunkInfos.clear();
     LOGD("%d chunks are written in the last batch", outstandingChunks);
 }
@@ -1207,8 +1217,6 @@
 bool MPEG4Writer::findChunkToWrite(Chunk *chunk) {
     LOGV("findChunkToWrite");
 
-    // Find the smallest timestamp, and write that chunk out
-    // XXX: What if some track is just too slow?
     int64_t minTimestampUs = 0x7FFFFFFFFFFFFFFFLL;
     Track *track = NULL;
     for (List<ChunkInfo>::iterator it = mChunkInfos.begin();
@@ -1237,6 +1245,13 @@
             *chunk = *(it->mChunks.begin());
             it->mChunks.erase(it->mChunks.begin());
             CHECK_EQ(chunk->mTrack, track);
+
+            int64_t interChunkTimeUs =
+                chunk->mTimeStampUs - it->mPrevChunkTimestampUs;
+            if (interChunkTimeUs > it->mPrevChunkTimestampUs) {
+                it->mMaxInterChunkDurUs = interChunkTimeUs;
+            }
+
             return true;
         }
     }
@@ -1280,6 +1295,8 @@
          it != mTracks.end(); ++it) {
         ChunkInfo info;
         info.mTrack = *it;
+        info.mPrevChunkTimestampUs = 0;
+        info.mMaxInterChunkDurUs = 0;
         mChunkInfos.push_back(info);
     }
 
@@ -1303,6 +1320,7 @@
     if (params == NULL || !params->findInt64(kKeyTime, &startTimeUs)) {
         startTimeUs = 0;
     }
+    mStartTimeRealUs = startTimeUs;
 
     int32_t rotationDegrees;
     if (!mIsAudio && params && params->findInt32(kKeyRotation, &rotationDegrees)) {
@@ -1330,7 +1348,7 @@
          * Ideally, this platform-specific value should be defined
          * in media_profiles.xml file
          */
-        startTimeUs += 700000;
+        startTimeUs += kInitialDelayTimeUs;
     }
 
     meta->setInt64(kKeyTime, startTimeUs);
@@ -1937,7 +1955,8 @@
         LOGV("%s timestampUs: %lld", mIsAudio? "Audio": "Video", timestampUs);
 
 ////////////////////////////////////////////////////////////////////////////////
-        if (mSampleSizes.empty()) {
+        if (mNumSamples == 0) {
+            mFirstSampleTimeRealUs = systemTime() / 1000;
             mStartTimestampUs = timestampUs;
             mOwner->setStartTimestampUs(mStartTimestampUs);
             previousPausedDurationUs = mStartTimestampUs;
@@ -2135,10 +2154,26 @@
                     trackNum | MEDIA_RECORDER_TRACK_INFO_ENCODED_FRAMES,
                     mNumSamples);
 
+    // The system delay time excluding the requested initial delay that
+    // is used to eliminate the recording sound.
+    int64_t initialDelayUs =
+        mFirstSampleTimeRealUs - mStartTimeRealUs - kInitialDelayTimeUs;
+    mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
+                    trackNum | MEDIA_RECORDER_TRACK_INFO_INITIAL_DELAY_MS,
+                    (initialDelayUs) / 1000);
+
     if (hasMultipleTracks) {
         mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
                     trackNum | MEDIA_RECORDER_TRACK_INFO_MAX_CHUNK_DUR_MS,
                     mMaxChunkDurationUs / 1000);
+
+        int64_t moovStartTimeUs = mOwner->getStartTimestampUs();
+        if (mStartTimestampUs != moovStartTimeUs) {
+            int64_t startTimeOffsetUs = mStartTimestampUs - moovStartTimeUs;
+            mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
+                    trackNum | MEDIA_RECORDER_TRACK_INFO_START_OFFSET_MS,
+                    startTimeOffsetUs / 1000);
+        }
     }
 }
 
@@ -2604,6 +2639,7 @@
     mOwner->beginBox("stts");
     mOwner->writeInt32(0);  // version=0, flags=0
     mOwner->writeInt32(mNumSttsTableEntries);
+
     // Compensate for small start time difference from different media tracks
     int64_t trackStartTimeOffsetUs = 0;
     int64_t moovStartTimeUs = mOwner->getStartTimestampUs();