Merge "Send client / device format in recording callback" into nyc-dev
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 4ee8d6c..dbc6e6e 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -197,6 +197,7 @@
     BatteryNotifier::getInstance().noteResetAudio();
 
 #ifdef TEE_SINK
+    char value[PROPERTY_VALUE_MAX];
     (void) property_get("ro.debuggable", value, "0");
     int debuggable = atoi(value);
     int teeEnabled = 0;
@@ -2878,7 +2879,7 @@
         // failures at unlink() which are ignored.  It's also unlikely since
         // normally dumpsys is only done by bugreport or from the command line.
         char teePath[32+256];
-        strcpy(teePath, "/data/misc/media");
+        strcpy(teePath, "/data/misc/audioserver");
         size_t teePathLen = strlen(teePath);
         DIR *dir = opendir(teePath);
         teePath[teePathLen++] = '/';
@@ -2920,7 +2921,8 @@
             }
         } else {
             if (fd >= 0) {
-                dprintf(fd, "unable to rotate tees in %s: %s\n", teePath, strerror(errno));
+                dprintf(fd, "unable to rotate tees in %.*s: %s\n", teePathLen, teePath,
+                        strerror(errno));
             }
         }
         char teeTime[16];
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index e0d8f75..e056ef2 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -1565,6 +1565,7 @@
         mEffectBufferFormat(AUDIO_FORMAT_INVALID),
         mEffectBufferValid(false),
         mSuspended(0), mBytesWritten(0),
+        mFramesWritten(0),
         mActiveTracksGeneration(0),
         // mStreamTypes[] initialized in constructor body
         mOutput(output),
@@ -2863,6 +2864,7 @@
             // and associate with the sink frames written out.  We need
             // this to convert the sink timestamp to the track timestamp.
             if (mNormalSink != 0) {
+                // Note: The DuplicatingThread may not have a mNormalSink.
                 // We always fetch the timestamp here because often the downstream
                 // sink will block whie writing.
                 ExtendedTimestamp timestamp; // use private copy to fetch
@@ -2872,23 +2874,20 @@
                         timestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL];
                 mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL] =
                         timestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL];
-
-                // sinkFramesWritten for non-offloaded tracks are contiguous
-                // even after standby() is called. This is useful for the track frame
-                // to sink frame mapping.
-                const int64_t sinkFramesWritten = mNormalSink->framesWritten();
-                mTimestamp.mPosition[ExtendedTimestamp::LOCATION_SERVER] = sinkFramesWritten;
-                mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_SERVER] = systemTime();
-
-                const size_t size = mActiveTracks.size();
-                for (size_t i = 0; i < size; ++i) {
-                    sp<Track> t = mActiveTracks[i].promote();
-                    if (t != 0 && !t->isFastTrack()) {
-                        t->updateTrackFrameInfo(
-                                t->mAudioTrackServerProxy->framesReleased(),
-                                sinkFramesWritten,
-                                mTimestamp);
-                    }
+            }
+            // mFramesWritten for non-offloaded tracks are contiguous
+            // even after standby() is called. This is useful for the track frame
+            // to sink frame mapping.
+            mTimestamp.mPosition[ExtendedTimestamp::LOCATION_SERVER] = mFramesWritten;
+            mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_SERVER] = systemTime();
+            const size_t size = mActiveTracks.size();
+            for (size_t i = 0; i < size; ++i) {
+                sp<Track> t = mActiveTracks[i].promote();
+                if (t != 0 && !t->isFastTrack()) {
+                    t->updateTrackFrameInfo(
+                            t->mAudioTrackServerProxy->framesReleased(),
+                            mFramesWritten,
+                            mTimestamp);
                 }
             }
 
@@ -3026,6 +3025,7 @@
                 mSleepTimeUs = suspendSleepTimeUs();
                 // simulate write to HAL when suspended
                 mBytesWritten += mSinkBufferSize;
+                mFramesWritten += mSinkBufferSize / mFrameSize;
                 mBytesRemaining = 0;
             }
 
@@ -3076,6 +3076,7 @@
                     } else {
                         mBytesWritten += ret;
                         mBytesRemaining -= ret;
+                        mFramesWritten += ret / mFrameSize;
                     }
                 } else if ((mMixerStatus == MIXER_DRAIN_TRACK) ||
                         (mMixerStatus == MIXER_DRAIN_ALL)) {
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 507f197..42b3266 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -693,6 +693,7 @@
     volatile int32_t                mSuspended;
 
     int64_t                         mBytesWritten;
+    int64_t                         mFramesWritten; // not reset on standby
 private:
     // mMasterMute is in both PlaybackThread and in AudioFlinger.  When a
     // PlaybackThread needs to find out if master-muted, it checks it's local
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index a67693f..e684fc2 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -960,9 +960,17 @@
                 (long long)mPresentationCompleteFrames, audioHalFrames);
     }
 
-    if ((!isOffloaded() && !isDirect() && !isFastTrack()
-            && framesWritten >= mPresentationCompleteFrames
-            && mAudioTrackServerProxy->isDrained()) || isOffloaded()) {
+    bool complete;
+    if (isOffloaded()) {
+        complete = true;
+    } else if (isDirect() || isFastTrack()) { // these do not go through linear map
+        complete = framesWritten >= mPresentationCompleteFrames;
+    } else {  // Normal tracks, OutputTracks, and PatchTracks
+        complete = framesWritten >= mPresentationCompleteFrames
+                && mAudioTrackServerProxy->isDrained();
+    }
+
+    if (complete) {
         triggerEvents(AudioSystem::SYNC_EVENT_PRESENTATION_COMPLETE);
         mAudioTrackServerProxy->setStreamEndDone();
         return true;