Merge "resolved conflicts for merge of 242fa52b to master"
diff --git a/media/java/android/media/videoeditor/AudioTrack.java b/media/java/android/media/videoeditor/AudioTrack.java
index 468ba2a..96d55f1 100755
--- a/media/java/android/media/videoeditor/AudioTrack.java
+++ b/media/java/android/media/videoeditor/AudioTrack.java
@@ -18,12 +18,17 @@
import java.io.IOException;
+import android.util.Log;
+
/**
* This class allows to handle an audio track. This audio file is mixed with the
* audio samples of the MediaItems.
* {@hide}
*/
public class AudioTrack {
+ // Logging
+ private static final String TAG = "AudioTrack";
+
// Instance variables
private final String mUniqueId;
private final String mFilename;
@@ -47,6 +52,129 @@
// The audio waveform filename
private String mAudioWaveformFilename;
+ private PlaybackThread mPlaybackThread;
+
+ /**
+ * This listener interface is used by the AudioTrack to emit playback
+ * progress notifications.
+ */
+ public interface PlaybackProgressListener {
+ /**
+ * This method notifies the listener of the current time position while
+ * playing an audio track
+ *
+ * @param audioTrack The audio track
+ * @param timeMs The current playback position (expressed in milliseconds
+ * since the beginning of the audio track).
+ * @param end true if the end of the audio track was reached
+ */
+ public void onProgress(AudioTrack audioTrack, long timeMs, boolean end);
+ }
+
+ /**
+ * The playback thread
+ */
+ private class PlaybackThread extends Thread {
+ // Instance variables
+ private final PlaybackProgressListener mListener;
+ private final long mFromMs, mToMs;
+ private boolean mRun;
+ private final boolean mLoop;
+ private long mPositionMs;
+
+ /**
+ * Constructor
+ *
+ * @param fromMs The time (relative to the beginning of the audio track)
+ * at which the playback will start
+ * @param toMs The time (relative to the beginning of the audio track) at
+ * which the playback will stop. Use -1 to play to the end of
+ * the audio track
+ * @param loop true if the playback should be looped once it reaches the
+ * end
+ * @param listener The listener which will be notified of the playback
+ * progress
+ */
+ public PlaybackThread(long fromMs, long toMs, boolean loop,
+ PlaybackProgressListener listener) {
+ mPositionMs = mFromMs = fromMs;
+ if (toMs < 0) {
+ mToMs = mDurationMs;
+ } else {
+ mToMs = toMs;
+ }
+ mLoop = loop;
+ mListener = listener;
+ mRun = true;
+ }
+
+ /*
+ * {@inheritDoc}
+ */
+ @Override
+ public void run() {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "===> PlaybackThread.run enter");
+ }
+
+ while (mRun) {
+ try {
+ sleep(100);
+ } catch (InterruptedException ex) {
+ break;
+ }
+
+ mPositionMs += 100;
+
+ if (mPositionMs >= mToMs) {
+ if (!mLoop) {
+ if (mListener != null) {
+ mListener.onProgress(AudioTrack.this, mPositionMs, true);
+ }
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "PlaybackThread.run playback complete");
+ }
+ break;
+ } else {
+ // Fire a notification for the end of the clip
+ if (mListener != null) {
+ mListener.onProgress(AudioTrack.this, mToMs, false);
+ }
+
+ // Rewind
+ mPositionMs = mFromMs;
+ if (mListener != null) {
+ mListener.onProgress(AudioTrack.this, mPositionMs, false);
+ }
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "PlaybackThread.run playback complete");
+ }
+ }
+ } else {
+ if (mListener != null) {
+ mListener.onProgress(AudioTrack.this, mPositionMs, false);
+ }
+ }
+ }
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "===> PlaybackThread.run exit");
+ }
+ }
+
+ /**
+ * Stop the playback
+ *
+ * @return The stop position
+ */
+ public long stopPlayback() {
+ mRun = false;
+ try {
+ join();
+ } catch (InterruptedException ex) {
+ }
+ return mPositionMs;
+ }
+ };
/**
* An object of this type cannot be instantiated by using the default
@@ -99,7 +227,7 @@
}
/**
- * @return The id of the media item
+ * @return The id of the audio track
*/
public String getId() {
return mUniqueId;
@@ -312,6 +440,50 @@
}
/**
+ * Start the playback of this audio track. This method does not block (does
+ * not wait for the playback to complete).
+ *
+ * @param fromMs The time (relative to the beginning of the audio track) at
+ * which the playback will start
+ * @param toMs The time (relative to the beginning of the audio track) at
+ * which the playback will stop. Use -1 to play to the end of the
+ * audio track
+ * @param loop true if the playback should be looped once it reaches the end
+ * @param listener The listener which will be notified of the playback
+ * progress
+ * @throws IllegalArgumentException if fromMs or toMs is beyond the playback
+ * duration
+ * @throws IllegalStateException if a playback, preview or an export is
+ * already in progress
+ */
+ public void startPlayback(long fromMs, long toMs, boolean loop,
+ PlaybackProgressListener listener) {
+ if (fromMs >= mDurationMs) {
+ return;
+ }
+ mPlaybackThread = new PlaybackThread(fromMs, toMs, loop, listener);
+ mPlaybackThread.start();
+ }
+
+ /**
+ * Stop the audio track playback. This method blocks until the ongoing
+ * playback is stopped.
+ *
+ * @return The accurate current time when stop is effective expressed in
+ * milliseconds
+ */
+ public long stopPlayback() {
+ final long stopTimeMs;
+ if (mPlaybackThread != null) {
+ stopTimeMs = mPlaybackThread.stopPlayback();
+ mPlaybackThread = null;
+ } else {
+ stopTimeMs = 0;
+ }
+ return stopTimeMs;
+ }
+
+ /**
* This API allows to generate a file containing the sample volume levels of
* this audio track object. This function may take significant time and is
* blocking. The filename can be retrieved using getAudioWaveformFilename().
diff --git a/media/java/android/media/videoeditor/VideoEditorTestImpl.java b/media/java/android/media/videoeditor/VideoEditorTestImpl.java
index 16f9495..eb641db 100644
--- a/media/java/android/media/videoeditor/VideoEditorTestImpl.java
+++ b/media/java/android/media/videoeditor/VideoEditorTestImpl.java
@@ -537,16 +537,13 @@
* {@inheritDoc}
*/
public AudioTrack getAudioTrack(String audioTrackId) {
- if (mPreviewThread != null) {
- throw new IllegalStateException("Previewing is in progress");
+ for (AudioTrack at : mAudioTracks) {
+ if (at.getId().equals(audioTrackId)) {
+ return at;
+ }
}
- final AudioTrack audioTrack = getAudioTrack(audioTrackId);
- if (audioTrack != null) {
- mAudioTracks.remove(audioTrack);
- }
-
- return audioTrack;
+ return null;
}
/*