Make dumpsys(media.player) more useful by having AwesomePlayer populate it.

Change-Id: I12ba7d542331a8293d67a0d47378b8be4f777759
diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h
index f0401cca..18e8a5f 100644
--- a/include/media/MediaPlayerInterface.h
+++ b/include/media/MediaPlayerInterface.h
@@ -168,6 +168,10 @@
         if (mNotify) mNotify(mCookie, msg, ext1, ext2, obj);
     }
 
+    virtual status_t dump(int fd, const Vector<String16> &args) const {
+        return INVALID_OPERATION;
+    }
+
 private:
     friend class MediaPlayerService;
 
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 54a6547..a77dff1 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -368,6 +368,9 @@
             mPid, mConnId, mStatus, mLoop?"true": "false");
     result.append(buffer);
     write(fd, result.string(), result.size());
+    if (mPlayer != NULL) {
+        mPlayer->dump(fd, args);
+    }
     if (mAudioOutput != 0) {
         mAudioOutput->dump(fd, args);
     }
diff --git a/media/libmediaplayerservice/StagefrightPlayer.cpp b/media/libmediaplayerservice/StagefrightPlayer.cpp
index 02ec911..870e290 100644
--- a/media/libmediaplayerservice/StagefrightPlayer.cpp
+++ b/media/libmediaplayerservice/StagefrightPlayer.cpp
@@ -214,4 +214,8 @@
     return OK;
 }
 
+status_t StagefrightPlayer::dump(int fd, const Vector<String16> &args) const {
+    return mPlayer->dump(fd, args);
+}
+
 }  // namespace android
diff --git a/media/libmediaplayerservice/StagefrightPlayer.h b/media/libmediaplayerservice/StagefrightPlayer.h
index ddd37e4..85a546d 100644
--- a/media/libmediaplayerservice/StagefrightPlayer.h
+++ b/media/libmediaplayerservice/StagefrightPlayer.h
@@ -61,6 +61,8 @@
     virtual status_t getMetadata(
             const media::Metadata::Filter& ids, Parcel *records);
 
+    virtual status_t dump(int fd, const Vector<String16> &args) const;
+
 private:
     AwesomePlayer *mPlayer;
 
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 3a58d3f..aa7edcc 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -265,7 +265,7 @@
             // This isn't something that should be passed to the server.
             mUriHeaders.removeItemsAt(index);
 
-            mFlags |= INCOGNITO;
+            modifyFlags(INCOGNITO, SET);
         }
     }
 
@@ -279,6 +279,12 @@
     // ::finishSetDataSource_l to avoid blocking the calling thread in
     // setDataSource for any significant time.
 
+    {
+        Mutex::Autolock autoLock(mStatsLock);
+        mStats.mFd = -1;
+        mStats.mURI = mUri;
+    }
+
     return OK;
 }
 
@@ -298,6 +304,12 @@
 
     mFileSource = dataSource;
 
+    {
+        Mutex::Autolock autoLock(mStatsLock);
+        mStats.mFd = fd;
+        mStats.mURI = String8();
+    }
+
     return setDataSource_l(dataSource);
 }
 
@@ -336,6 +348,10 @@
 
         int32_t bitrate;
         if (!meta->findInt32(kKeyBitRate, &bitrate)) {
+            const char *mime;
+            CHECK(meta->findCString(kKeyMIMEType, &mime));
+            LOGW("track of type '%s' does not publish bitrate", mime);
+
             totalBitRate = -1;
             break;
         }
@@ -347,6 +363,14 @@
 
     LOGV("mBitrate = %lld bits/sec", mBitrate);
 
+    {
+        Mutex::Autolock autoLock(mStatsLock);
+        mStats.mBitrate = mBitrate;
+        mStats.mTracks.clear();
+        mStats.mAudioTrackIndex = -1;
+        mStats.mVideoTrackIndex = -1;
+    }
+
     bool haveAudio = false;
     bool haveVideo = false;
     for (size_t i = 0; i < extractor->countTracks(); ++i) {
@@ -370,10 +394,27 @@
                 mDisplayHeight = displayHeight;
             }
 
+            {
+                Mutex::Autolock autoLock(mStatsLock);
+                mStats.mVideoTrackIndex = mStats.mTracks.size();
+                mStats.mTracks.push();
+                TrackStat *stat =
+                    &mStats.mTracks.editItemAt(mStats.mVideoTrackIndex);
+                stat->mMIME = mime;
+            }
         } else if (!haveAudio && !strncasecmp(mime, "audio/", 6)) {
             setAudioSource(extractor->getTrack(i));
             haveAudio = true;
 
+            {
+                Mutex::Autolock autoLock(mStatsLock);
+                mStats.mAudioTrackIndex = mStats.mTracks.size();
+                mStats.mTracks.push();
+                TrackStat *stat =
+                    &mStats.mTracks.editItemAt(mStats.mAudioTrackIndex);
+                stat->mMIME = mime;
+            }
+
             if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
                 // Only do this for vorbis audio, none of the other audio
                 // formats even support this ringtone specific hack and
@@ -383,7 +424,7 @@
                 int32_t loop;
                 if (fileMeta != NULL
                         && fileMeta->findInt32(kKeyAutoLoop, &loop) && loop != 0) {
-                    mFlags |= AUTO_LOOPING;
+                    modifyFlags(AUTO_LOOPING, SET);
                 }
             }
         } else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
@@ -431,7 +472,7 @@
     }
 
     if (mFlags & PREPARING) {
-        mFlags |= PREPARE_CANCELLED;
+        modifyFlags(PREPARE_CANCELLED, SET);
         if (mConnectingDataSource != NULL) {
             LOGI("interrupting the connection process");
             mConnectingDataSource->disconnect();
@@ -494,7 +535,7 @@
     }
 
     mDurationUs = -1;
-    mFlags = 0;
+    modifyFlags(0, ASSIGN);
     mExtractorFlags = 0;
     mTimeSourceDeltaUs = 0;
     mVideoTimeUs = 0;
@@ -510,6 +551,22 @@
 
     mBitrate = -1;
     mLastVideoTimeUs = -1;
+
+    {
+        Mutex::Autolock autoLock(mStatsLock);
+        mStats.mFd = -1;
+        mStats.mURI = String8();
+        mStats.mBitrate = -1;
+        mStats.mAudioTrackIndex = -1;
+        mStats.mVideoTrackIndex = -1;
+        mStats.mNumVideoFramesDecoded = 0;
+        mStats.mNumVideoFramesDropped = 0;
+        mStats.mVideoWidth = -1;
+        mStats.mVideoHeight = -1;
+        mStats.mFlags = 0;
+        mStats.mTracks.clear();
+    }
+
 }
 
 void AwesomePlayer::notifyListener_l(int msg, int ext1, int ext2) {
@@ -631,7 +688,7 @@
                         && (cachedDataRemaining < kLowWaterMarkBytes)) {
                     LOGI("cache is running low (< %d) , pausing.",
                          kLowWaterMarkBytes);
-                    mFlags |= CACHE_UNDERRUN;
+                    modifyFlags(CACHE_UNDERRUN, SET);
                     pause_l();
                     ensureCacheIsFetching_l();
                     sendCacheStats();
@@ -640,7 +697,7 @@
                     if (mFlags & CACHE_UNDERRUN) {
                         LOGI("cache has filled up (> %d), resuming.",
                              kHighWaterMarkBytes);
-                        mFlags &= ~CACHE_UNDERRUN;
+                        modifyFlags(CACHE_UNDERRUN, CLEAR);
                         play_l();
                         notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
                     } else if (mFlags & PREPARING) {
@@ -690,7 +747,7 @@
                 && (cachedDurationUs < kLowWaterMarkUs)) {
             LOGI("cache is running low (%.2f secs) , pausing.",
                  cachedDurationUs / 1E6);
-            mFlags |= CACHE_UNDERRUN;
+            modifyFlags(CACHE_UNDERRUN, SET);
             pause_l();
             ensureCacheIsFetching_l();
             sendCacheStats();
@@ -699,7 +756,7 @@
             if (mFlags & CACHE_UNDERRUN) {
                 LOGI("cache has filled up (%.2f secs), resuming.",
                      cachedDurationUs / 1E6);
-                mFlags &= ~CACHE_UNDERRUN;
+                modifyFlags(CACHE_UNDERRUN, CLEAR);
                 play_l();
                 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
             } else if (mFlags & PREPARING) {
@@ -742,7 +799,7 @@
 
         pause_l(true /* at eos */);
 
-        mFlags |= AT_EOS;
+        modifyFlags(AT_EOS, SET);
         return;
     }
 
@@ -766,20 +823,20 @@
 
         pause_l(true /* at eos */);
 
-        mFlags |= AT_EOS;
+        modifyFlags(AT_EOS, SET);
     }
 }
 
 status_t AwesomePlayer::play() {
     Mutex::Autolock autoLock(mLock);
 
-    mFlags &= ~CACHE_UNDERRUN;
+    modifyFlags(CACHE_UNDERRUN, CLEAR);
 
     return play_l();
 }
 
 status_t AwesomePlayer::play_l() {
-    mFlags &= ~SEEK_PREVIEW;
+    modifyFlags(SEEK_PREVIEW, CLEAR);
 
     if (mFlags & PLAYING) {
         return OK;
@@ -793,8 +850,8 @@
         }
     }
 
-    mFlags |= PLAYING;
-    mFlags |= FIRST_FRAME;
+    modifyFlags(PLAYING, SET);
+    modifyFlags(FIRST_FRAME, SET);
 
     if (mDecryptHandle != NULL) {
         int64_t position;
@@ -828,7 +885,7 @@
                 delete mAudioPlayer;
                 mAudioPlayer = NULL;
 
-                mFlags &= ~(PLAYING | FIRST_FRAME);
+                modifyFlags((PLAYING | FIRST_FRAME), CLEAR);
 
                 if (mDecryptHandle != NULL) {
                     mDrmManagerClient->setPlaybackStatus(
@@ -880,7 +937,7 @@
     }
 
     if (!(mFlags & AUDIOPLAYER_STARTED)) {
-        mFlags |= AUDIOPLAYER_STARTED;
+        modifyFlags(AUDIOPLAYER_STARTED, SET);
 
         bool wasSeeking = mAudioPlayer->isSeeking();
 
@@ -904,7 +961,7 @@
         mAudioPlayer->resume();
     }
 
-    mFlags |= AUDIO_RUNNING;
+    modifyFlags(AUDIO_RUNNING, SET);
 
     mWatchForAudioEOS = true;
 
@@ -951,6 +1008,12 @@
         usableHeight = mDisplayHeight;
     }
 
+    {
+        Mutex::Autolock autoLock(mStatsLock);
+        mStats.mVideoWidth = usableWidth;
+        mStats.mVideoHeight = usableHeight;
+    }
+
     int32_t rotationDegrees;
     if (!mVideoTrack->getFormat()->findInt32(
                 kKeyRotation, &rotationDegrees)) {
@@ -1013,7 +1076,7 @@
 status_t AwesomePlayer::pause() {
     Mutex::Autolock autoLock(mLock);
 
-    mFlags &= ~CACHE_UNDERRUN;
+    modifyFlags(CACHE_UNDERRUN, CLEAR);
 
     return pause_l();
 }
@@ -1035,15 +1098,15 @@
             mAudioPlayer->pause();
         }
 
-        mFlags &= ~AUDIO_RUNNING;
+        modifyFlags(AUDIO_RUNNING, CLEAR);
     }
 
     if (mFlags & TEXTPLAYER_STARTED) {
         mTextPlayer->pause();
-        mFlags &= ~TEXT_RUNNING;
+        modifyFlags(TEXT_RUNNING, CLEAR);
     }
 
-    mFlags &= ~PLAYING;
+    modifyFlags(PLAYING, CLEAR);
 
     if (mDecryptHandle != NULL) {
         mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
@@ -1125,7 +1188,7 @@
         mSeeking = SEEK;
         mSeekNotificationSent = true;
         mSeekTimeUs = mLastVideoTimeUs;
-        mFlags &= ~(AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS);
+        modifyFlags((AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS), CLEAR);
     }
 
     if (wasPlaying) {
@@ -1143,10 +1206,10 @@
 status_t AwesomePlayer::setLooping(bool shouldLoop) {
     Mutex::Autolock autoLock(mLock);
 
-    mFlags = mFlags & ~LOOPING;
+    modifyFlags(LOOPING, CLEAR);
 
     if (shouldLoop) {
-        mFlags |= LOOPING;
+        modifyFlags(LOOPING, SET);
     }
 
     return OK;
@@ -1200,15 +1263,15 @@
                 return err;
             }
 
-            mFlags |= TEXT_RUNNING;
-            mFlags |= TEXTPLAYER_STARTED;
+            modifyFlags(TEXT_RUNNING, SET);
+            modifyFlags(TEXTPLAYER_STARTED, SET);
             return OK;
         } else { // to turn off the text track display
             if (mFlags  & TEXT_RUNNING) {
-                mFlags &= ~TEXT_RUNNING;
+                modifyFlags(TEXT_RUNNING, CLEAR);
             }
             if (mFlags  & TEXTPLAYER_STARTED) {
-                mFlags &= ~TEXTPLAYER_STARTED;
+                modifyFlags(TEXTPLAYER_STARTED, CLEAR);
             }
 
             return mTextPlayer->setTimedTextTrackIndex(index);
@@ -1235,7 +1298,7 @@
     }
 
     if (mFlags & CACHE_UNDERRUN) {
-        mFlags &= ~CACHE_UNDERRUN;
+        modifyFlags(CACHE_UNDERRUN, CLEAR);
         play_l();
     }
 
@@ -1250,7 +1313,7 @@
     mSeeking = SEEK;
     mSeekNotificationSent = false;
     mSeekTimeUs = timeUs;
-    mFlags &= ~(AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS);
+    modifyFlags((AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS), CLEAR);
 
     seekAudioIfNecessary_l();
 
@@ -1266,7 +1329,7 @@
         mSeekNotificationSent = true;
 
         if ((mFlags & PREPARED) && mVideoSource != NULL) {
-            mFlags |= SEEK_PREVIEW;
+            modifyFlags(SEEK_PREVIEW, SET);
             postVideoEvent_l();
         }
     }
@@ -1344,6 +1407,19 @@
         return OK;
     }
 
+    if (mAudioSource != NULL) {
+        Mutex::Autolock autoLock(mStatsLock);
+        TrackStat *stat = &mStats.mTracks.editItemAt(mStats.mAudioTrackIndex);
+
+        const char *component;
+        if (!mAudioSource->getFormat()
+                ->findCString(kKeyDecoderComponent, &component)) {
+            component = "none";
+        }
+
+        stat->mDecoderName = component;
+    }
+
     return mAudioSource != NULL ? OK : UNKNOWN_ERROR;
 }
 
@@ -1423,6 +1499,17 @@
         }
     }
 
+    if (mVideoSource != NULL) {
+        Mutex::Autolock autoLock(mStatsLock);
+        TrackStat *stat = &mStats.mTracks.editItemAt(mStats.mVideoTrackIndex);
+
+        const char *component;
+        CHECK(mVideoSource->getFormat()
+                ->findCString(kKeyDecoderComponent, &component));
+
+        stat->mDecoderName = component;
+    }
+
     return mVideoSource != NULL ? OK : UNKNOWN_ERROR;
 }
 
@@ -1452,7 +1539,7 @@
         mSeekNotificationSent = true;
     }
 
-    mFlags |= FIRST_FRAME;
+    modifyFlags(FIRST_FRAME, SET);
     mSeeking = NO_SEEK;
 
     if (mDecryptHandle != NULL) {
@@ -1491,7 +1578,7 @@
             if (mAudioPlayer != NULL && (mFlags & AUDIO_RUNNING)) {
                 mAudioPlayer->pause();
 
-                mFlags &= ~AUDIO_RUNNING;
+                modifyFlags(AUDIO_RUNNING, CLEAR);
             }
             mAudioSource->pause();
         }
@@ -1540,7 +1627,7 @@
                     startAudioPlayer_l();
                 }
 
-                mFlags |= VIDEO_AT_EOS;
+                modifyFlags(VIDEO_AT_EOS, SET);
                 postStreamDoneEvent_l(err);
                 return;
             }
@@ -1556,6 +1643,11 @@
 
             break;
         }
+
+        {
+            Mutex::Autolock autoLock(mStatsLock);
+            ++mStats.mNumVideoFramesDecoded;
+        }
     }
 
     int64_t timeUs;
@@ -1588,13 +1680,13 @@
 
     if ((mFlags & TEXTPLAYER_STARTED) && !(mFlags & (TEXT_RUNNING | SEEK_PREVIEW))) {
         mTextPlayer->resume();
-        mFlags |= TEXT_RUNNING;
+        modifyFlags(TEXT_RUNNING, SET);
     }
 
     TimeSource *ts = (mFlags & AUDIO_AT_EOS) ? &mSystemTimeSource : mTimeSource;
 
     if (mFlags & FIRST_FRAME) {
-        mFlags &= ~FIRST_FRAME;
+        modifyFlags(FIRST_FRAME, CLEAR);
         mTimeSourceDeltaUs = ts->getRealTimeUs() - timeUs;
     }
 
@@ -1646,6 +1738,11 @@
             mVideoBuffer->release();
             mVideoBuffer = NULL;
 
+            {
+                Mutex::Autolock autoLock(mStatsLock);
+                ++mStats.mNumVideoFramesDropped;
+            }
+
             postVideoEvent_l();
             return;
         }
@@ -1672,7 +1769,7 @@
     mVideoBuffer = NULL;
 
     if (wasSeeking != NO_SEEK && (mFlags & SEEK_PREVIEW)) {
-        mFlags &= ~SEEK_PREVIEW;
+        modifyFlags(SEEK_PREVIEW, CLEAR);
         return;
     }
 
@@ -1746,8 +1843,8 @@
     status_t finalStatus;
     if (mWatchForAudioEOS && mAudioPlayer->reachedEOS(&finalStatus)) {
         mWatchForAudioEOS = false;
-        mFlags |= AUDIO_AT_EOS;
-        mFlags |= FIRST_FRAME;
+        modifyFlags(AUDIO_AT_EOS, SET);
+        modifyFlags(FIRST_FRAME, SET);
         postStreamDoneEvent_l(finalStatus);
     }
 }
@@ -1801,7 +1898,7 @@
         mQueueStarted = true;
     }
 
-    mFlags |= PREPARING;
+    modifyFlags(PREPARING, SET);
     mAsyncPrepareEvent = new AwesomeEvent(
             this, &AwesomePlayer::onPrepareAsyncEvent);
 
@@ -1988,7 +2085,7 @@
     }
 
     mPrepareResult = err;
-    mFlags &= ~(PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED);
+    modifyFlags((PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED), CLEAR);
     mAsyncPrepareEvent = NULL;
     mPreparedCondition.broadcast();
 }
@@ -2036,7 +2133,7 @@
         }
     }
 
-    mFlags |= PREPARING_CONNECTED;
+    modifyFlags(PREPARING_CONNECTED, SET);
 
     if (isStreamingHTTP() || mRTSPController != NULL) {
         postBufferingEvent_l();
@@ -2057,8 +2154,8 @@
     }
 
     mPrepareResult = OK;
-    mFlags &= ~(PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED);
-    mFlags |= PREPARED;
+    modifyFlags((PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED), CLEAR);
+    modifyFlags(PREPARED, SET);
     mAsyncPrepareEvent = NULL;
     mPreparedCondition.broadcast();
 }
@@ -2126,4 +2223,75 @@
     return mCachedSource != NULL || mWVMExtractor != NULL;
 }
 
+status_t AwesomePlayer::dump(int fd, const Vector<String16> &args) const {
+    Mutex::Autolock autoLock(mStatsLock);
+
+    FILE *out = fdopen(dup(fd), "w");
+
+    fprintf(out, " AwesomePlayer\n");
+    if (mStats.mFd < 0) {
+        fprintf(out, "  URI(%s)", mStats.mURI.string());
+    } else {
+        fprintf(out, "  fd(%d)", mStats.mFd);
+    }
+
+    fprintf(out, ", flags(0x%08x)", mStats.mFlags);
+
+    if (mStats.mBitrate >= 0) {
+        fprintf(out, ", bitrate(%lld bps)", mStats.mBitrate);
+    }
+
+    fprintf(out, "\n");
+
+    for (size_t i = 0; i < mStats.mTracks.size(); ++i) {
+        const TrackStat &stat = mStats.mTracks.itemAt(i);
+
+        fprintf(out, "  Track %d\n", i + 1);
+        fprintf(out, "   MIME(%s)", stat.mMIME.string());
+
+        if (!stat.mDecoderName.isEmpty()) {
+            fprintf(out, ", decoder(%s)", stat.mDecoderName.string());
+        }
+
+        fprintf(out, "\n");
+
+        if ((ssize_t)i == mStats.mVideoTrackIndex) {
+            fprintf(out,
+                    "   videoDimensions(%d x %d), "
+                    "numVideoFramesDecoded(%lld), "
+                    "numVideoFramesDropped(%lld)\n",
+                    mStats.mVideoWidth,
+                    mStats.mVideoHeight,
+                    mStats.mNumVideoFramesDecoded,
+                    mStats.mNumVideoFramesDropped);
+        }
+    }
+
+    fclose(out);
+    out = NULL;
+
+    return OK;
+}
+
+void AwesomePlayer::modifyFlags(unsigned value, FlagMode mode) {
+    switch (mode) {
+        case SET:
+            mFlags |= value;
+            break;
+        case CLEAR:
+            mFlags &= ~value;
+            break;
+        case ASSIGN:
+            mFlags = value;
+            break;
+        default:
+            TRESPASS();
+    }
+
+    {
+        Mutex::Autolock autoLock(mStatsLock);
+        mStats.mFlags = mFlags;
+    }
+}
+
 }  // namespace android
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index aebcdd1..f6df380 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -105,6 +105,8 @@
 
     status_t setTimedTextTrackIndex(int32_t index);
 
+    status_t dump(int fd, const Vector<String16> &args) const;
+
 private:
     friend struct AwesomeEvent;
     friend struct PreviewPlayer;
@@ -142,6 +144,7 @@
 
     mutable Mutex mLock;
     Mutex mMiscStateLock;
+    mutable Mutex mStatsLock;
 
     OMXClient mClient;
     TimedEventQueue mQueue;
@@ -294,6 +297,33 @@
     bool isStreamingHTTP() const;
     void sendCacheStats();
 
+    enum FlagMode {
+        SET,
+        CLEAR,
+        ASSIGN
+    };
+    void modifyFlags(unsigned value, FlagMode mode);
+
+    struct TrackStat {
+        String8 mMIME;
+        String8 mDecoderName;
+    };
+
+    // protected by mStatsLock
+    struct Stats {
+        int mFd;
+        String8 mURI;
+        int64_t mBitrate;
+        ssize_t mAudioTrackIndex;
+        ssize_t mVideoTrackIndex;
+        int64_t mNumVideoFramesDecoded;
+        int64_t mNumVideoFramesDropped;
+        int32_t mVideoWidth;
+        int32_t mVideoHeight;
+        uint32_t mFlags;
+        Vector<TrackStat> mTracks;
+    } mStats;
+
     AwesomePlayer(const AwesomePlayer &);
     AwesomePlayer &operator=(const AwesomePlayer &);
 };