Merge "Unhide audio offload for android.media.AudioTrack"
diff --git a/api/current.txt b/api/current.txt
index bb4c383..3d8c5a6 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -21751,7 +21751,13 @@
     field public static final int CHANNEL_OUT_STEREO = 12; // 0xc
     field public static final int CHANNEL_OUT_SURROUND = 1052; // 0x41c
     field public static final android.os.Parcelable.Creator<android.media.AudioFormat> CREATOR;
+    field public static final int ENCODING_AAC_ELD = 15; // 0xf
+    field public static final int ENCODING_AAC_HE_V1 = 11; // 0xb
+    field public static final int ENCODING_AAC_HE_V2 = 12; // 0xc
+    field public static final int ENCODING_AAC_LC = 10; // 0xa
+    field public static final int ENCODING_AAC_XHE = 16; // 0x10
     field public static final int ENCODING_AC3 = 5; // 0x5
+    field public static final int ENCODING_AC4 = 17; // 0x11
     field public static final int ENCODING_DEFAULT = 1; // 0x1
     field public static final int ENCODING_DOLBY_TRUEHD = 14; // 0xe
     field public static final int ENCODING_DTS = 7; // 0x7
@@ -21759,6 +21765,7 @@
     field public static final int ENCODING_E_AC3 = 6; // 0x6
     field public static final int ENCODING_IEC61937 = 13; // 0xd
     field public static final int ENCODING_INVALID = 0; // 0x0
+    field public static final int ENCODING_MP3 = 9; // 0x9
     field public static final int ENCODING_PCM_16BIT = 2; // 0x2
     field public static final int ENCODING_PCM_8BIT = 3; // 0x3
     field public static final int ENCODING_PCM_FLOAT = 4; // 0x4
@@ -21801,6 +21808,7 @@
     method public boolean isBluetoothScoOn();
     method public boolean isMicrophoneMute();
     method public boolean isMusicActive();
+    method public boolean isOffloadedPlaybackSupported(android.media.AudioFormat);
     method public boolean isSpeakerphoneOn();
     method public boolean isStreamMute(int);
     method public boolean isVolumeFixed();
@@ -22101,6 +22109,7 @@
     method public int reloadStaticData();
     method public void removeOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener);
     method public deprecated void removeOnRoutingChangedListener(android.media.AudioTrack.OnRoutingChangedListener);
+    method public void removeStreamEventCallback();
     method public int setAuxEffectSendLevel(float);
     method public int setBufferSizeInFrames(int);
     method public int setLoopPoints(int, int, int);
@@ -22114,6 +22123,7 @@
     method public boolean setPreferredDevice(android.media.AudioDeviceInfo);
     method protected deprecated void setState(int);
     method public deprecated int setStereoVolume(float, float);
+    method public void setStreamEventCallback(java.util.concurrent.Executor, android.media.AudioTrack.StreamEventCallback);
     method public int setVolume(float);
     method public void stop() throws java.lang.IllegalStateException;
     method public int write(byte[], int, int);
@@ -22149,6 +22159,7 @@
     method public android.media.AudioTrack.Builder setAudioAttributes(android.media.AudioAttributes) throws java.lang.IllegalArgumentException;
     method public android.media.AudioTrack.Builder setAudioFormat(android.media.AudioFormat) throws java.lang.IllegalArgumentException;
     method public android.media.AudioTrack.Builder setBufferSizeInBytes(int) throws java.lang.IllegalArgumentException;
+    method public android.media.AudioTrack.Builder setOffloadedPlayback(boolean);
     method public android.media.AudioTrack.Builder setPerformanceMode(int);
     method public android.media.AudioTrack.Builder setSessionId(int) throws java.lang.IllegalArgumentException;
     method public android.media.AudioTrack.Builder setTransferMode(int) throws java.lang.IllegalArgumentException;
@@ -22164,6 +22175,12 @@
     method public default void onRoutingChanged(android.media.AudioRouting);
   }
 
+  public static abstract class AudioTrack.StreamEventCallback {
+    method public void onStreamDataRequest(android.media.AudioTrack);
+    method public void onStreamPresentationEnd(android.media.AudioTrack);
+    method public void onTearDown(android.media.AudioTrack);
+  }
+
   public class CamcorderProfile {
     method public static android.media.CamcorderProfile get(int);
     method public static android.media.CamcorderProfile get(int, int);
diff --git a/core/jni/android_media_AudioFormat.h b/core/jni/android_media_AudioFormat.h
index 51cefb9..c79f5bd 100644
--- a/core/jni/android_media_AudioFormat.h
+++ b/core/jni/android_media_AudioFormat.h
@@ -35,6 +35,7 @@
 #define ENCODING_DOLBY_TRUEHD   14
 #define ENCODING_AAC_ELD        15
 #define ENCODING_AAC_XHE        16
+#define ENCODING_AC4            17
 
 #define ENCODING_INVALID    0
 #define ENCODING_DEFAULT    1
@@ -77,6 +78,8 @@
         return AUDIO_FORMAT_AAC_ELD;
     case ENCODING_AAC_XHE:
         return AUDIO_FORMAT_AAC; // FIXME temporary value, needs addition of xHE-AAC
+    case ENCODING_AC4:
+        return AUDIO_FORMAT_AC4;
     case ENCODING_DEFAULT:
         return AUDIO_FORMAT_DEFAULT;
     default:
@@ -125,6 +128,8 @@
     // FIXME needs addition of AUDIO_FORMAT_AAC_XHE
     //case AUDIO_FORMAT_AAC_XHE:
     //    return ENCODING_AAC_XHE;
+    case AUDIO_FORMAT_AC4:
+        return ENCODING_AC4;
     case AUDIO_FORMAT_DEFAULT:
         return ENCODING_DEFAULT;
     default:
diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java
index 46fe89a..b07d042 100644
--- a/media/java/android/media/AudioFormat.java
+++ b/media/java/android/media/AudioFormat.java
@@ -238,25 +238,13 @@
     public static final int ENCODING_DTS = 7;
     /** Audio data format: DTS HD compressed */
     public static final int ENCODING_DTS_HD = 8;
-    /** Audio data format: MP3 compressed
-     * @hide
-     * TODO unhide and add to @Encoding (intentional white space   
-     * */
+    /** Audio data format: MP3 compressed */
     public static final int ENCODING_MP3 = 9;
-    /** Audio data format: AAC LC compressed
-     * @hide
-     * TODO unhide and add to @Encoding (intentional white space   
-     * */
+    /** Audio data format: AAC LC compressed */
     public static final int ENCODING_AAC_LC = 10;
-    /** Audio data format: AAC HE V1 compressed
-     * @hide
-     * TODO unhide and add to @Encoding (intentional white space   
-     * */
+    /** Audio data format: AAC HE V1 compressed */
     public static final int ENCODING_AAC_HE_V1 = 11;
-    /** Audio data format: AAC HE V2 compressed
-     * @hide
-     * TODO unhide and add to @Encoding (intentional white space   
-     * */
+    /** Audio data format: AAC HE V2 compressed */
     public static final int ENCODING_AAC_HE_V2 = 12;
 
     /** Audio data format: compressed audio wrapped in PCM for HDMI
@@ -271,16 +259,12 @@
     /** Audio data format: DOLBY TRUEHD compressed
      **/
     public static final int ENCODING_DOLBY_TRUEHD = 14;
-    /** Audio data format: AAC ELD compressed
-     * @hide
-     * TODO unhide and add to @Encoding (intentional white space   
-     * */
+    /** Audio data format: AAC ELD compressed */
     public static final int ENCODING_AAC_ELD = 15;
-    /** Audio data format: AAC xHE compressed
-     * @hide
-     * TODO unhide and add to @Encoding (intentional white space   
-     * */
+    /** Audio data format: AAC xHE compressed */
     public static final int ENCODING_AAC_XHE = 16;
+    /** Audio data format: AC-4 sync frame transport format */
+    public static final int ENCODING_AC4 = 17;
 
     /** @hide */
     public static String toLogFriendlyEncoding(int enc) {
@@ -317,6 +301,8 @@
                 return "ENCODING_AAC_ELD";
             case ENCODING_AAC_XHE:
                 return "ENCODING_AAC_XHE";
+            case ENCODING_AC4:
+                return "ENCODING_AC4";
             default :
                 return "invalid encoding " + enc;
         }
@@ -535,6 +521,7 @@
         case ENCODING_IEC61937:
         case ENCODING_AAC_ELD:
         case ENCODING_AAC_XHE:
+        case ENCODING_AC4:
             return true;
         default:
             return false;
@@ -553,13 +540,13 @@
         case ENCODING_DTS:
         case ENCODING_DTS_HD:
         case ENCODING_IEC61937:
-            //TODO not true yet (intended white space     
         case ENCODING_MP3:
         case ENCODING_AAC_LC:
         case ENCODING_AAC_HE_V1:
         case ENCODING_AAC_HE_V2:
         case ENCODING_AAC_ELD:
         case ENCODING_AAC_XHE:
+        case ENCODING_AC4:
             return true;
         default:
             return false;
@@ -586,6 +573,7 @@
         case ENCODING_IEC61937: // wrapped in PCM but compressed
         case ENCODING_AAC_ELD:
         case ENCODING_AAC_XHE:
+        case ENCODING_AC4:
             return false;
         case ENCODING_INVALID:
         default:
@@ -613,6 +601,7 @@
         case ENCODING_AAC_HE_V2:
         case ENCODING_AAC_ELD:
         case ENCODING_AAC_XHE:
+        case ENCODING_AC4:
             return false;
         case ENCODING_INVALID:
         default:
@@ -849,6 +838,7 @@
                 case ENCODING_AAC_HE_V2:
                 case ENCODING_AAC_ELD:
                 case ENCODING_AAC_XHE:
+                case ENCODING_AC4:
                     mEncoding = encoding;
                     break;
                 case ENCODING_INVALID:
@@ -1056,7 +1046,13 @@
         ENCODING_E_AC3,
         ENCODING_DTS,
         ENCODING_DTS_HD,
-        ENCODING_IEC61937 }
+        ENCODING_IEC61937,
+        ENCODING_AAC_HE_V1,
+        ENCODING_AAC_HE_V2,
+        ENCODING_AAC_LC,
+        ENCODING_AAC_ELD,
+        ENCODING_AAC_XHE,
+        ENCODING_AC4 }
     )
     @Retention(RetentionPolicy.SOURCE)
     public @interface Encoding {}
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 4d5343c..2ac4063 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1331,15 +1331,13 @@
     //====================================================================
     // Offload query
     /**
-     * @hide
-     * TODO unhide (intentional white space to attract attention:    
      * Returns whether offloaded playback of an audio format is supported on the device.
      * Offloaded playback is where the decoding of an audio stream is not competing with other
      * software resources. In general, it is supported by dedicated hardware, such as audio DSPs.
      * @param format the audio format (codec, sample rate, channels) being checked.
      * @return true if the given audio format can be offloaded.
      */
-    public static boolean isOffloadedPlaybackSupported(@NonNull AudioFormat format) {
+    public boolean isOffloadedPlaybackSupported(@NonNull AudioFormat format) {
         return AudioSystem.isOffloadSupported(format);
     }
 
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 6add381..5928d03 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -755,8 +755,8 @@
      * <code>MODE_STREAM</code> will be used.
      * <br>If the session ID is not specified with {@link #setSessionId(int)}, a new one will
      * be generated.
+     * <br>Offload is false by default.
      */
-    // TODO add that offload is false by default (intended white space   
     public static class Builder {
         private AudioAttributes mAttributes;
         private AudioFormat mFormat;
@@ -895,14 +895,11 @@
         }
 
         /**
-         * @hide
-         * TODO unhide (intentional whitespace    
-         * TODO should offload require POWER_SAVING?    
          * Sets whether this track will play through the offloaded audio path.
          * When set to true, at build time, the audio format will be checked against
          * {@link AudioManager#isOffloadedPlaybackSupported(AudioFormat)} to verify the audio format
          * used by this track is supported on the device's offload path (if any).
-         * <br>Offload is only supported for media audio data, and therefore require that
+         * <br>Offload is only supported for media audio streams, and therefore requires that
          * the usage be {@link AudioAttributes#USAGE_MEDIA}.
          * @param offload true to require the offload path for playback.
          * @return the same Builder instance.
@@ -962,7 +959,7 @@
                     throw new UnsupportedOperationException(
                             "Cannot create AudioTrack, offload requires USAGE_MEDIA");
                 }
-                if (!AudioManager.isOffloadedPlaybackSupported(mFormat)) {
+                if (!AudioSystem.isOffloadSupported(mFormat)) {
                     throw new UnsupportedOperationException(
                             "Cannot create AudioTrack, offload format not supported");
                 }
@@ -2942,14 +2939,31 @@
     }
 
     /**
-     * @hide
-     * TODO unhide (intentional white space to attract attention:    
      * Abstract class to receive event notification about the stream playback.
+     * See {@link AudioTrack#setStreamEventCallback(Executor, StreamEventCallback)} to register
+     * the callback on the given {@link AudioTrack} instance.
      */
     public abstract static class StreamEventCallback {
-        // TODO rename if supported for non offload tracks
+        /** @hide */ // add hidden empty constructor so it doesn't show in SDK
+        public StreamEventCallback() { }
+        /**
+         * Called when an offloaded track is no longer valid and has been discarded by the system.
+         * An example of this happening is when an offloaded track has been paused too long, and
+         * gets invalidated by the system to prevent any other offload.
+         * @param track the {@link AudioTrack} on which the event happened
+         */
         public void onTearDown(AudioTrack track) { }
+        /**
+         * Called when all the buffers of an offloaded track that were queued in the audio system
+         * (e.g. the combination of the Android audio framework and the device's audio hardware)
+         * have been played after {@link AudioTrack#stop()} has been called.
+         * @param track the {@link AudioTrack} on which the event happened
+         */
         public void onStreamPresentationEnd(AudioTrack track) { }
+        /**
+         * Called when more audio data can be written without blocking on an offloaded track.
+         * @param track the {@link AudioTrack} on which the event happened
+         */
         public void onStreamDataRequest(AudioTrack track) { }
     }
 
@@ -2958,11 +2972,9 @@
     private final Object mStreamEventCbLock = new Object();
 
     /**
-     * @hide
-     * TODO unhide (intentional white space to attract attention:    
-     * Registers a callback for notification of stream events.
+     * Sets the callback for the notification of stream events.
      * @param executor {@link Executor} to handle the callbacks
-     * @param eventCallback the callback to receive the stream events
+     * @param eventCallback the callback to receive the stream event notifications
      */
     public void setStreamEventCallback(@NonNull @CallbackExecutor Executor executor,
             @NonNull StreamEventCallback eventCallback) {
@@ -2979,9 +2991,8 @@
     }
 
     /**
-     * @hide
      * Unregisters the callback for notification of stream events, previously set
-     * by {@link #setStreamEventCallback(StreamEventCallback, Executor)}.
+     * by {@link #setStreamEventCallback(Executor, StreamEventCallback)}.
      */
     public void removeStreamEventCallback() {
         synchronized (mStreamEventCbLock) {