AudioTrack: error reporting for getTimestamp()

Add a new getTimestamp() method that returns an error code.

Bug: 21886109.
Bug: 22202349.
Bug: 17548098.

Change-Id: Ib072dd3442de79bab9aca77c3c33b0790b492154
(cherry picked from commit 4e1ccd370fc268f3207c5baee08ac8c943c3fdf9)
diff --git a/core/jni/android_media_AudioErrors.h b/core/jni/android_media_AudioErrors.h
index 4907830..c17a020 100644
--- a/core/jni/android_media_AudioErrors.h
+++ b/core/jni/android_media_AudioErrors.h
@@ -32,6 +32,7 @@
     AUDIO_JAVA_PERMISSION_DENIED  = -4,
     AUDIO_JAVA_NO_INIT            = -5,
     AUDIO_JAVA_DEAD_OBJECT        = -6,
+    AUDIO_JAVA_WOULD_BLOCK        = -7,
 };
 
 static inline jint nativeToJavaStatus(status_t status) {
@@ -46,6 +47,8 @@
         return AUDIO_JAVA_PERMISSION_DENIED;
     case NO_INIT:
         return AUDIO_JAVA_NO_INIT;
+    case WOULD_BLOCK:
+        return AUDIO_JAVA_WOULD_BLOCK;
     case DEAD_OBJECT:
         return AUDIO_JAVA_DEAD_OBJECT;
     default:
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index e99a37a..c59d1c7 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -279,6 +279,7 @@
     public static final int PERMISSION_DENIED  = -4;
     public static final int NO_INIT            = -5;
     public static final int DEAD_OBJECT        = -6;
+    public static final int WOULD_BLOCK        = -7;
 
     /*
      * AudioPolicyService methods
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 8880dad..bb4f7d9 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -158,6 +158,18 @@
      * Denotes a failure due to the improper use of a method.
      */
     public  static final int ERROR_INVALID_OPERATION               = AudioSystem.INVALID_OPERATION;
+    /**
+     * An error code indicating that the object reporting it is no longer valid and needs to
+     * be recreated.
+     * @hide
+     */
+    public  static final int ERROR_DEAD_OBJECT                     = AudioSystem.DEAD_OBJECT;
+    /**
+     * {@link #getTimestampWithStatus(AudioTimestamp)} is called in STOPPED or FLUSHED state,
+     * or immediately after start/ACTIVE.
+     * @hide
+     */
+    public  static final int ERROR_WOULD_BLOCK                     = AudioSystem.WOULD_BLOCK;
 
     // Error codes:
     // to keep in sync with frameworks/base/core/jni/android_media_AudioTrack.cpp
@@ -1225,6 +1237,44 @@
         return true;
     }
 
+    /**
+     * Poll for a timestamp on demand.
+     * <p>
+     * Same as {@link #getTimestamp(AudioTimestamp)} but with a more useful return code.
+     *
+     * @param timestamp a reference to a non-null AudioTimestamp instance allocated
+     *        and owned by caller.
+     * @return {@link #SUCCESS} if a timestamp is available
+     *         {@link #ERROR_WOULD_BLOCK} if called in STOPPED or FLUSHED state, or if called
+     *         immediately after start/ACTIVE, when the number of frames consumed is less than the
+     *         overall hardware latency to physical output. In WOULD_BLOCK cases, one might poll
+     *         again, or use {@link #getPlaybackHeadPosition}, or use 0 position and current time
+     *         for the timestamp.
+     *         {@link #ERROR_DEAD_OBJECT} if the AudioTrack is not valid anymore and
+     *         needs to be recreated.
+     *         {@link #ERROR_INVALID_OPERATION} if current route does not support
+     *         timestamps. In this case, the approximate frame position can be obtained
+     *         using {@link #getPlaybackHeadPosition}.
+     *
+     *         The AudioTimestamp instance is filled in with a position in frame units, together
+     *         with the estimated time when that frame was presented or is committed to
+     *         be presented.
+     * @hide
+     */
+     // Add this text when the "on new timestamp" API is added:
+     //   Use if you need to get the most recent timestamp outside of the event callback handler.
+     public int getTimestampWithStatus(AudioTimestamp timestamp)
+     {
+         if (timestamp == null) {
+             throw new IllegalArgumentException();
+         }
+         // It's unfortunate, but we have to either create garbage every time or use synchronized
+         long[] longArray = new long[2];
+         int ret = native_get_timestamp(longArray);
+         timestamp.framePosition = longArray[0];
+         timestamp.nanoTime = longArray[1];
+         return ret;
+     }
 
     //--------------------------------------------------------------------------
     // Initialization / configuration