Add IAudioTrack::getTimestamp()

with dummy implementation in AudioFlinger::TrackHandle, and
implement AudioTrack::getTimestamp() using IAudioTrack.

Also document invariant that mAudioTrack and control block are always
non-0 after successful initialization.

Change-Id: I9861d1454cff7decf795d5d5898ac7999a9f3b7e
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index d90e733..78ae37e 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -148,10 +148,8 @@
             mAudioTrackThread->requestExitAndWait();
             mAudioTrackThread.clear();
         }
-        if (mAudioTrack != 0) {
-            mAudioTrack->asBinder()->unlinkToDeath(mDeathNotifier, this);
-            mAudioTrack.clear();
-        }
+        mAudioTrack->asBinder()->unlinkToDeath(mDeathNotifier, this);
+        mAudioTrack.clear();
         IPCThreadState::self()->flushCommands();
         AudioSystem::releaseAudioSessionId(mSessionId);
     }
@@ -222,6 +220,7 @@
 
     AutoMutex lock(mLock);
 
+    // invariant that mAudioTrack != 0 is true only after set() returns successfully
     if (mAudioTrack != 0) {
         ALOGE("Track already in use");
         return INVALID_OPERATION;
@@ -965,6 +964,7 @@
         ALOGE("Could not get control block");
         return NO_INIT;
     }
+    // invariant that mAudioTrack != 0 is true only after set() returns successfully
     if (mAudioTrack != 0) {
         mAudioTrack->asBinder()->unlinkToDeath(mDeathNotifier, this);
         mDeathNotifier.clear();
@@ -1705,16 +1705,13 @@
 status_t AudioTrack::setParameters(const String8& keyValuePairs)
 {
     AutoMutex lock(mLock);
-    if (mAudioTrack != 0) {
-        return mAudioTrack->setParameters(keyValuePairs);
-    } else {
-        return NO_INIT;
-    }
+    return mAudioTrack->setParameters(keyValuePairs);
 }
 
 status_t AudioTrack::getTimestamp(AudioTimestamp& timestamp)
 {
-    return INVALID_OPERATION;
+    AutoMutex lock(mLock);
+    return mAudioTrack->getTimestamp(timestamp);
 }
 
 String8 AudioTrack::getParameters(const String8& keys)
diff --git a/media/libmedia/IAudioTrack.cpp b/media/libmedia/IAudioTrack.cpp
index a2b49a3..f0d75ba 100644
--- a/media/libmedia/IAudioTrack.cpp
+++ b/media/libmedia/IAudioTrack.cpp
@@ -39,7 +39,8 @@
     ALLOCATE_TIMED_BUFFER,
     QUEUE_TIMED_BUFFER,
     SET_MEDIA_TIME_TRANSFORM,
-    SET_PARAMETERS
+    SET_PARAMETERS,
+    GET_TIMESTAMP,
 };
 
 class BpAudioTrack : public BpInterface<IAudioTrack>
@@ -166,6 +167,21 @@
         }
         return status;
     }
+
+    virtual status_t getTimestamp(AudioTimestamp& timestamp) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
+        status_t status = remote()->transact(GET_TIMESTAMP, data, &reply);
+        if (status == NO_ERROR) {
+            status = reply.readInt32();
+            if (status == NO_ERROR) {
+                timestamp.mPosition = reply.readInt32();
+                timestamp.mTime.tv_sec = reply.readInt32();
+                timestamp.mTime.tv_nsec = reply.readInt32();
+            }
+        }
+        return status;
+    }
 };
 
 IMPLEMENT_META_INTERFACE(AudioTrack, "android.media.IAudioTrack");
@@ -241,6 +257,18 @@
             reply->writeInt32(setParameters(keyValuePairs));
             return NO_ERROR;
         } break;
+        case GET_TIMESTAMP: {
+            CHECK_INTERFACE(IAudioTrack, data, reply);
+            AudioTimestamp timestamp;
+            status_t status = getTimestamp(timestamp);
+            reply->writeInt32(status);
+            if (status == NO_ERROR) {
+                reply->writeInt32(timestamp.mPosition);
+                reply->writeInt32(timestamp.mTime.tv_sec);
+                reply->writeInt32(timestamp.mTime.tv_nsec);
+            }
+            return NO_ERROR;
+        } break;
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }