summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
authorRachad <rachad@google.com>2015-04-15 19:38:28 -0700
committerRachad <rachad@google.com>2015-04-17 18:26:31 -0700
commitcfe964a09ca05778e5dd84f2fd24119b89401696 (patch)
tree4a51c27cce6fd6530d641e0ef3fd4a6c423e4018 /media
parent1c146c78af00f30f6fa71c4577a66f27a5981aa2 (diff)
downloadframeworks_base-cfe964a09ca05778e5dd84f2fd24119b89401696.zip
frameworks_base-cfe964a09ca05778e5dd84f2fd24119b89401696.tar.gz
frameworks_base-cfe964a09ca05778e5dd84f2fd24119b89401696.tar.bz2
AudioTrack.write() with timestamp support
Add AudioTrack.write() method that supports timestamps for HW_AV_SYNC tracks Bug: 19384172 Change-Id: I6a452ae94f1da253c1b1118dece5b3073b941c09
Diffstat (limited to 'media')
-rw-r--r--media/java/android/media/AudioTrack.java94
1 files changed, 94 insertions, 0 deletions
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 4c5fb40..9a105cd 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -19,7 +19,9 @@ package android.media;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
+import java.lang.Math;
import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
import java.nio.NioUtils;
import android.annotation.IntDef;
@@ -271,6 +273,14 @@ public class AudioTrack
* Reference to the app-ops service.
*/
private final IAppOpsService mAppOps;
+ /**
+ * HW_AV_SYNC track AV Sync Header
+ */
+ private ByteBuffer mAvSyncHeader = null;
+ /**
+ * HW_AV_SYNC track audio data bytes remaining to write after current AV sync header
+ */
+ private int mAvSyncBytesRemaining = 0;
//--------------------------------
// Used exclusively by native code
@@ -1390,6 +1400,8 @@ public class AudioTrack
synchronized(mPlayStateLock) {
native_stop();
mPlayState = PLAYSTATE_STOPPED;
+ mAvSyncHeader = null;
+ mAvSyncBytesRemaining = 0;
}
}
@@ -1434,6 +1446,8 @@ public class AudioTrack
if (mState == STATE_INITIALIZED) {
// flush the data in native layer
native_flush();
+ mAvSyncHeader = null;
+ mAvSyncBytesRemaining = 0;
}
}
@@ -1673,6 +1687,86 @@ public class AudioTrack
}
/**
+ * Writes the audio data to the audio sink for playback (streaming mode) on a HW_AV_SYNC track.
+ * In streaming mode, the blocking behavior will depend on the write mode.
+ * @param audioData the buffer that holds the data to play, starting at the position reported
+ * by <code>audioData.position()</code>.
+ * <BR>Note that upon return, the buffer position (<code>audioData.position()</code>) will
+ * have been advanced to reflect the amount of data that was successfully written to
+ * the AudioTrack.
+ * @param sizeInBytes number of bytes to write.
+ * <BR>Note this may differ from <code>audioData.remaining()</code>, but cannot exceed it.
+ * @param writeMode one of {@link #WRITE_BLOCKING}, {@link #WRITE_NON_BLOCKING}.
+ * <BR>With {@link #WRITE_BLOCKING}, the write will block until all data has been written
+ * to the audio sink.
+ * <BR>With {@link #WRITE_NON_BLOCKING}, the write will return immediately after
+ * queuing as much audio data for playback as possible without blocking.
+ * @param timestamp The timestamp of the first decodable audio frame in the provided audioData.
+ * @return 0 or a positive number of bytes that were written, or
+ * {@link #ERROR_BAD_VALUE}, {@link #ERROR_INVALID_OPERATION}, or
+ * {@link AudioManager#ERROR_DEAD_OBJECT} if the AudioTrack is not valid anymore and
+ * needs to be recreated.
+ */
+ public int write(ByteBuffer audioData, int sizeInBytes,
+ @WriteMode int writeMode, long timestamp) {
+
+ if ((mAttributes.getFlags() & AudioAttributes.FLAG_HW_AV_SYNC) == 0) {
+ Log.d(TAG, "AudioTrack.write() called on a regular AudioTrack. Ignoring pts...");
+ return write(audioData, sizeInBytes, writeMode);
+ }
+
+ if ((audioData == null) || (sizeInBytes < 0) || (sizeInBytes > audioData.remaining())) {
+ Log.e(TAG, "AudioTrack.write() called with invalid size (" + sizeInBytes + ") value");
+ return ERROR_BAD_VALUE;
+ }
+
+ // create timestamp header if none exists
+ if (mAvSyncHeader == null) {
+ mAvSyncHeader = ByteBuffer.allocate(16);
+ mAvSyncHeader.order(ByteOrder.BIG_ENDIAN);
+ mAvSyncHeader.putInt(0x55550001);
+ mAvSyncHeader.putInt(sizeInBytes);
+ mAvSyncHeader.putLong(timestamp);
+ mAvSyncHeader.position(0);
+ mAvSyncBytesRemaining = sizeInBytes;
+ }
+
+ // write timestamp header if not completely written already
+ int ret = 0;
+ if (mAvSyncHeader.remaining() != 0) {
+ ret = write(mAvSyncHeader, mAvSyncHeader.remaining(), writeMode);
+ if (ret < 0) {
+ Log.e(TAG, "AudioTrack.write() could not write timestamp header!");
+ mAvSyncHeader = null;
+ mAvSyncBytesRemaining = 0;
+ return ret;
+ }
+ if (mAvSyncHeader.remaining() > 0) {
+ Log.v(TAG, "AudioTrack.write() partial timestamp header written.");
+ return 0;
+ }
+ }
+
+ // write audio data
+ int sizeToWrite = Math.min(mAvSyncBytesRemaining, sizeInBytes);
+ ret = write(audioData, sizeToWrite, writeMode);
+ if (ret < 0) {
+ Log.e(TAG, "AudioTrack.write() could not write audio data!");
+ mAvSyncHeader = null;
+ mAvSyncBytesRemaining = 0;
+ return ret;
+ }
+
+ mAvSyncBytesRemaining -= ret;
+ if (mAvSyncBytesRemaining == 0) {
+ mAvSyncHeader = null;
+ }
+
+ return ret;
+ }
+
+
+ /**
* Sets the playback head position within the static buffer to zero,
* that is it rewinds to start of static buffer.
* The track must be stopped or paused, and