Merge "Added audio track playback API"

This commit is contained in:
Gil Dobjanschi
2010-10-04 15:49:26 -07:00
committed by Android (Google) Code Review
2 changed files with 178 additions and 9 deletions

View File

@@ -18,12 +18,17 @@ package android.media.videoeditor;
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 @@ public class AudioTrack {
// 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 @@ public class AudioTrack {
}
/**
* @return The id of the media item
* @return The id of the audio track
*/
public String getId() {
return mUniqueId;
@@ -311,6 +439,50 @@ public class AudioTrack {
return mDuckingLowVolume;
}
/**
* 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

View File

@@ -537,16 +537,13 @@ public class VideoEditorTestImpl implements VideoEditor {
* {@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;
}
/*