summaryrefslogtreecommitdiffstats
path: root/variablespeed/src
diff options
context:
space:
mode:
Diffstat (limited to 'variablespeed/src')
-rw-r--r--variablespeed/src/com/android/ex/variablespeed/EngineParameters.java158
-rw-r--r--variablespeed/src/com/android/ex/variablespeed/MediaPlayerDataSource.java68
-rw-r--r--variablespeed/src/com/android/ex/variablespeed/MediaPlayerProxy.java50
-rw-r--r--variablespeed/src/com/android/ex/variablespeed/SingleThreadedMediaPlayerProxy.java115
-rw-r--r--variablespeed/src/com/android/ex/variablespeed/VariableSpeed.java410
-rw-r--r--variablespeed/src/com/android/ex/variablespeed/VariableSpeedNative.java92
6 files changed, 0 insertions, 893 deletions
diff --git a/variablespeed/src/com/android/ex/variablespeed/EngineParameters.java b/variablespeed/src/com/android/ex/variablespeed/EngineParameters.java
deleted file mode 100644
index 1cc4012..0000000
--- a/variablespeed/src/com/android/ex/variablespeed/EngineParameters.java
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.ex.variablespeed;
-
-import android.media.AudioManager;
-
-import javax.annotation.concurrent.Immutable;
-import javax.annotation.concurrent.NotThreadSafe;
-
-/**
- * Encapsulates the parameters required to configure the audio engine.
- * <p>
- * You should not need to use this class directly, it exists for the benefit of
- * this package and the classes contained therein.
- */
-@Immutable
-/*package*/ final class EngineParameters {
- private final int mTargetFrames;
- private final int mMaxPlayBufferCount;
- private final float mWindowDuration;
- private final float mWindowOverlapDuration;
- private final float mInitialRate;
- private final int mDecodeBufferInitialSize;
- private final int mDecodeBufferMaxSize;
- private final int mStartPositionMillis;
- private final int mAudioStreamType;
-
- public int getTargetFrames() {
- return mTargetFrames;
- }
-
- public int getMaxPlayBufferCount() {
- return mMaxPlayBufferCount;
- }
-
- public float getWindowDuration() {
- return mWindowDuration;
- }
-
- public float getWindowOverlapDuration() {
- return mWindowOverlapDuration;
- }
-
- public float getInitialRate() {
- return mInitialRate;
- }
-
- public int getDecodeBufferInitialSize() {
- return mDecodeBufferInitialSize;
- }
-
- public int getDecodeBufferMaxSize() {
- return mDecodeBufferMaxSize;
- }
-
- public int getStartPositionMillis() {
- return mStartPositionMillis;
- }
-
- public int getAudioStreamType() {
- return mAudioStreamType;
- }
-
- private EngineParameters(int targetFrames, int maxPlayBufferCount, float windowDuration,
- float windowOverlapDuration, float initialRate, int decodeBufferInitialSize,
- int decodeBufferMaxSize, int startPositionMillis, int audioStreamType) {
- mTargetFrames = targetFrames;
- mMaxPlayBufferCount = maxPlayBufferCount;
- mWindowDuration = windowDuration;
- mWindowOverlapDuration = windowOverlapDuration;
- mInitialRate = initialRate;
- mDecodeBufferInitialSize = decodeBufferInitialSize;
- mDecodeBufferMaxSize = decodeBufferMaxSize;
- mStartPositionMillis = startPositionMillis;
- mAudioStreamType = audioStreamType;
- }
-
- /**
- * We use the builder pattern to construct an {@link EngineParameters}
- * object.
- * <p>
- * This class is not thread safe, you should confine its use to one thread
- * or provide your own synchronization.
- */
- @NotThreadSafe
- public static class Builder {
- private int mTargetFrames = 1000;
- private int mMaxPlayBufferCount = 2;
- private float mWindowDuration = 0.08f;
- private float mWindowOverlapDuration = 0.008f;
- private float mInitialRate = 1.0f;
- private int mDecodeBufferInitialSize = 5 * 1024;
- private int mDecodeBufferMaxSize = 20 * 1024;
- private int mStartPositionMillis = 0;
- private int mAudioStreamType = AudioManager.STREAM_MUSIC;
-
- public EngineParameters build() {
- return new EngineParameters(mTargetFrames, mMaxPlayBufferCount,
- mWindowDuration, mWindowOverlapDuration, mInitialRate,
- mDecodeBufferInitialSize, mDecodeBufferMaxSize, mStartPositionMillis,
- mAudioStreamType);
- }
-
- public Builder maxPlayBufferCount(int maxPlayBufferCount) {
- mMaxPlayBufferCount = maxPlayBufferCount;
- return this;
- }
-
- public Builder windowDuration(int windowDuration) {
- mWindowDuration = windowDuration;
- return this;
- }
-
- public Builder windowOverlapDuration(int windowOverlapDuration) {
- mWindowOverlapDuration = windowOverlapDuration;
- return this;
- }
-
- public Builder initialRate(float initialRate) {
- mInitialRate = initialRate;
- return this;
- }
-
- public Builder decodeBufferInitialSize(int decodeBufferInitialSize) {
- mDecodeBufferInitialSize = decodeBufferInitialSize;
- return this;
- }
-
- public Builder decodeBufferMaxSize(int decodeBufferMaxSize) {
- mDecodeBufferMaxSize = decodeBufferMaxSize;
- return this;
- }
-
- public Builder startPositionMillis(int startPositionMillis) {
- mStartPositionMillis = startPositionMillis;
- return this;
- }
-
- public Builder audioStreamType(int audioStreamType) {
- mAudioStreamType = audioStreamType;
- return this;
- }
- }
-}
diff --git a/variablespeed/src/com/android/ex/variablespeed/MediaPlayerDataSource.java b/variablespeed/src/com/android/ex/variablespeed/MediaPlayerDataSource.java
deleted file mode 100644
index 1c6a8cb..0000000
--- a/variablespeed/src/com/android/ex/variablespeed/MediaPlayerDataSource.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.ex.variablespeed;
-
-import android.content.Context;
-import android.media.MediaPlayer;
-import android.net.Uri;
-
-import java.io.IOException;
-
-import javax.annotation.concurrent.Immutable;
-
-/**
- * Encapsulates the data source for a media player.
- * <p>
- * Is used to make the setting of the data source for a
- * {@link android.media.MediaPlayer} easier, or the calling of the correct
- * {@link VariableSpeedNative} method done correctly. You should not use this class
- * directly, it is for the benefit of the {@link VariableSpeed} implementation.
- */
-@Immutable
-/*package*/ class MediaPlayerDataSource {
- private final Context mContext;
- private final Uri mUri;
- private final String mPath;
-
- public MediaPlayerDataSource(Context context, Uri intentUri) {
- mContext = context;
- mUri = intentUri;
- mPath = null;
- }
-
- public MediaPlayerDataSource(String path) {
- mContext = null;
- mUri = null;
- mPath = path;
- }
-
- public void setAsSourceFor(MediaPlayer mediaPlayer) throws IOException {
- if (mContext != null) {
- mediaPlayer.setDataSource(mContext, mUri);
- } else {
- mediaPlayer.setDataSource(mPath);
- }
- }
-
- public void playNative() throws IOException {
- if (mContext != null) {
- VariableSpeedNative.playFromContext(mContext, mUri);
- } else {
- VariableSpeedNative.playUri(mPath);
- }
- }
-}
diff --git a/variablespeed/src/com/android/ex/variablespeed/MediaPlayerProxy.java b/variablespeed/src/com/android/ex/variablespeed/MediaPlayerProxy.java
deleted file mode 100644
index 3b7b576..0000000
--- a/variablespeed/src/com/android/ex/variablespeed/MediaPlayerProxy.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.ex.variablespeed;
-
-import android.content.Context;
-import android.media.MediaPlayer;
-import android.net.Uri;
-
-import java.io.IOException;
-
-/**
- * Interface that supports a subset of the operations on {@link android.media.MediaPlayer}.
- *
- * <p>This subset is arbitrarily defined - at the moment it is the subset that the voicemail
- * playback requires.</p>
- *
- * <p>This interface exists to make alternate implementations to the standard media player
- * swappable, as well as making it much easier to test code that directly uses a media player.
- */
-public interface MediaPlayerProxy {
- void setOnErrorListener(MediaPlayer.OnErrorListener listener);
- void setOnCompletionListener(MediaPlayer.OnCompletionListener listener);
- void release();
- void reset();
- void setDataSource(String path) throws IllegalStateException, IOException;
- void setDataSource(Context context, Uri intentUri) throws IllegalStateException, IOException;
- void prepare() throws IOException;
- int getDuration();
- void seekTo(int startPosition);
- void start();
- boolean isReadyToPlay();
- boolean isPlaying();
- int getCurrentPosition();
- void pause();
- void setAudioStreamType(int streamType);
-}
diff --git a/variablespeed/src/com/android/ex/variablespeed/SingleThreadedMediaPlayerProxy.java b/variablespeed/src/com/android/ex/variablespeed/SingleThreadedMediaPlayerProxy.java
deleted file mode 100644
index c9a9741..0000000
--- a/variablespeed/src/com/android/ex/variablespeed/SingleThreadedMediaPlayerProxy.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.ex.variablespeed;
-
-import android.content.Context;
-import android.media.MediaPlayer;
-import android.net.Uri;
-
-import java.io.IOException;
-
-/**
- * Simple wrapper around a {@link MediaPlayerProxy}, guaranteeing that every call made to the
- * MediaPlayerProxy is single-threaded.
- */
-public class SingleThreadedMediaPlayerProxy implements MediaPlayerProxy {
- private final MediaPlayerProxy mDelegate;
-
- public SingleThreadedMediaPlayerProxy(MediaPlayerProxy delegate) {
- mDelegate = delegate;
- }
-
- @Override
- public synchronized void setOnErrorListener(MediaPlayer.OnErrorListener listener) {
- mDelegate.setOnErrorListener(listener);
- }
-
- @Override
- public synchronized void setOnCompletionListener(MediaPlayer.OnCompletionListener listener) {
- mDelegate.setOnCompletionListener(listener);
- }
-
- @Override
- public synchronized void release() {
- mDelegate.release();
- }
-
- @Override
- public synchronized void reset() {
- mDelegate.reset();
- }
-
- @Override
- public synchronized void setDataSource(String path) throws IllegalStateException, IOException {
- mDelegate.setDataSource(path);
- }
-
- @Override
- public synchronized void setDataSource(Context context, Uri intentUri)
- throws IllegalStateException, IOException {
- mDelegate.setDataSource(context, intentUri);
- }
-
- @Override
- public synchronized void prepare() throws IOException {
- mDelegate.prepare();
- }
-
- @Override
- public synchronized int getDuration() {
- return mDelegate.getDuration();
- }
-
- @Override
- public synchronized void seekTo(int startPosition) {
- mDelegate.seekTo(startPosition);
- }
-
- @Override
- public synchronized void start() {
- mDelegate.start();
- }
-
- @Override
- public synchronized boolean isReadyToPlay() {
- return mDelegate.isReadyToPlay();
- }
-
- @Override
- public synchronized boolean isPlaying() {
- return mDelegate.isPlaying();
- }
-
- @Override
- public synchronized int getCurrentPosition() {
- return mDelegate.getCurrentPosition();
- }
-
- public void setVariableSpeed(float rate) {
- ((VariableSpeed) mDelegate).setVariableSpeed(rate);
- }
-
- @Override
- public synchronized void pause() {
- mDelegate.pause();
- }
-
- @Override
- public void setAudioStreamType(int streamType) {
- mDelegate.setAudioStreamType(streamType);
- }
-}
diff --git a/variablespeed/src/com/android/ex/variablespeed/VariableSpeed.java b/variablespeed/src/com/android/ex/variablespeed/VariableSpeed.java
deleted file mode 100644
index e44a375..0000000
--- a/variablespeed/src/com/android/ex/variablespeed/VariableSpeed.java
+++ /dev/null
@@ -1,410 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.ex.variablespeed;
-
-import com.google.common.base.Preconditions;
-
-import android.content.Context;
-import android.media.MediaPlayer;
-import android.net.Uri;
-import android.util.Log;
-
-import java.io.IOException;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.Executor;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
-import javax.annotation.concurrent.GuardedBy;
-import javax.annotation.concurrent.ThreadSafe;
-
-/**
- * This class behaves in a similar fashion to the MediaPlayer, but by using
- * native code it is able to use variable-speed playback.
- * <p>
- * This class is thread-safe. It's not yet perfect though, see the unit tests
- * for details - there is insufficient testing for the concurrent logic. You are
- * probably best advised to use thread confinment until the unit tests are more
- * complete with regards to threading.
- * <p>
- * The easiest way to ensure that calls to this class are not made concurrently
- * (besides only ever accessing it from one thread) is to wrap it in a
- * {@link SingleThreadedMediaPlayerProxy}, designed just for this purpose.
- */
-@ThreadSafe
-public class VariableSpeed implements MediaPlayerProxy {
- private static final String TAG = "VariableSpeed";
-
- private final Executor mExecutor;
- private final Object lock = new Object();
- @GuardedBy("lock") private MediaPlayerDataSource mDataSource;
- @GuardedBy("lock") private boolean mIsPrepared;
- @GuardedBy("lock") private boolean mHasDuration;
- @GuardedBy("lock") private boolean mHasStartedPlayback;
- @GuardedBy("lock") private CountDownLatch mEngineInitializedLatch;
- @GuardedBy("lock") private CountDownLatch mPlaybackFinishedLatch;
- @GuardedBy("lock") private boolean mHasBeenReleased = true;
- @GuardedBy("lock") private boolean mIsReadyToReUse = true;
- @GuardedBy("lock") private boolean mSkipCompletionReport;
- @GuardedBy("lock") private int mStartPosition;
- @GuardedBy("lock") private float mCurrentPlaybackRate = 1.0f;
- @GuardedBy("lock") private int mDuration;
- @GuardedBy("lock") private MediaPlayer.OnCompletionListener mCompletionListener;
- @GuardedBy("lock") private int mAudioStreamType;
-
- private VariableSpeed(Executor executor) throws UnsupportedOperationException {
- Preconditions.checkNotNull(executor);
- mExecutor = executor;
- try {
- VariableSpeedNative.loadLibrary();
- } catch (UnsatisfiedLinkError e) {
- throw new UnsupportedOperationException("could not load library", e);
- } catch (SecurityException e) {
- throw new UnsupportedOperationException("could not load library", e);
- }
- reset();
- }
-
- public static MediaPlayerProxy createVariableSpeed(Executor executor)
- throws UnsupportedOperationException {
- return new SingleThreadedMediaPlayerProxy(new VariableSpeed(executor));
- }
-
- @Override
- public void setOnCompletionListener(MediaPlayer.OnCompletionListener listener) {
- synchronized (lock) {
- check(!mHasBeenReleased, "has been released, reset before use");
- mCompletionListener = listener;
- }
- }
-
- @Override
- public void setOnErrorListener(MediaPlayer.OnErrorListener listener) {
- synchronized (lock) {
- check(!mHasBeenReleased, "has been released, reset before use");
- // TODO: I haven't actually added any error listener code.
- }
- }
-
- @Override
- public void release() {
- synchronized (lock) {
- if (mHasBeenReleased) {
- return;
- }
- mHasBeenReleased = true;
- }
- stopCurrentPlayback();
- boolean requiresShutdown = false;
- synchronized (lock) {
- requiresShutdown = hasEngineBeenInitialized();
- }
- if (requiresShutdown) {
- VariableSpeedNative.shutdownEngine();
- }
- synchronized (lock) {
- mIsReadyToReUse = true;
- }
- }
-
- private boolean hasEngineBeenInitialized() {
- return mEngineInitializedLatch.getCount() <= 0;
- }
-
- private boolean hasPlaybackFinished() {
- return mPlaybackFinishedLatch.getCount() <= 0;
- }
-
- /**
- * Stops the current playback, returns once it has stopped.
- */
- private void stopCurrentPlayback() {
- boolean isPlaying;
- CountDownLatch engineInitializedLatch;
- CountDownLatch playbackFinishedLatch;
- synchronized (lock) {
- isPlaying = mHasStartedPlayback && !hasPlaybackFinished();
- engineInitializedLatch = mEngineInitializedLatch;
- playbackFinishedLatch = mPlaybackFinishedLatch;
- if (isPlaying) {
- mSkipCompletionReport = true;
- }
- }
- if (isPlaying) {
- waitForLatch(engineInitializedLatch);
- VariableSpeedNative.stopPlayback();
- waitForLatch(playbackFinishedLatch);
- }
- }
-
- private void waitForLatch(CountDownLatch latch) {
- try {
- boolean success = latch.await(1, TimeUnit.SECONDS);
- if (!success) {
- reportException(new TimeoutException("waited too long"));
- }
- } catch (InterruptedException e) {
- // Preserve the interrupt status, though this is unexpected.
- Thread.currentThread().interrupt();
- reportException(e);
- }
- }
-
- @Override
- public void setDataSource(Context context, Uri intentUri) {
- checkNotNull(context, "context");
- checkNotNull(intentUri, "intentUri");
- innerSetDataSource(new MediaPlayerDataSource(context, intentUri));
- }
-
- @Override
- public void setDataSource(String path) {
- checkNotNull(path, "path");
- innerSetDataSource(new MediaPlayerDataSource(path));
- }
-
- private void innerSetDataSource(MediaPlayerDataSource source) {
- checkNotNull(source, "source");
- synchronized (lock) {
- check(!mHasBeenReleased, "has been released, reset before use");
- check(mDataSource == null, "cannot setDataSource more than once");
- mDataSource = source;
- }
- }
-
- @Override
- public void reset() {
- boolean requiresRelease;
- synchronized (lock) {
- requiresRelease = !mHasBeenReleased;
- }
- if (requiresRelease) {
- release();
- }
- synchronized (lock) {
- check(mHasBeenReleased && mIsReadyToReUse, "to re-use, must call reset after release");
- mDataSource = null;
- mIsPrepared = false;
- mHasDuration = false;
- mHasStartedPlayback = false;
- mEngineInitializedLatch = new CountDownLatch(1);
- mPlaybackFinishedLatch = new CountDownLatch(1);
- mHasBeenReleased = false;
- mIsReadyToReUse = false;
- mSkipCompletionReport = false;
- mStartPosition = 0;
- mDuration = 0;
- }
- }
-
- @Override
- public void prepare() throws IOException {
- MediaPlayerDataSource dataSource;
- int audioStreamType;
- synchronized (lock) {
- check(!mHasBeenReleased, "has been released, reset before use");
- check(mDataSource != null, "must setDataSource before you prepare");
- check(!mIsPrepared, "cannot prepare more than once");
- mIsPrepared = true;
- dataSource = mDataSource;
- audioStreamType = mAudioStreamType;
- }
- // NYI This should become another executable that we can wait on.
- MediaPlayer mediaPlayer = new MediaPlayer();
- mediaPlayer.setAudioStreamType(audioStreamType);
- dataSource.setAsSourceFor(mediaPlayer);
- mediaPlayer.prepare();
- synchronized (lock) {
- check(!mHasDuration, "can't have duration, this is impossible");
- mHasDuration = true;
- mDuration = mediaPlayer.getDuration();
- }
- mediaPlayer.release();
- }
-
- @Override
- public int getDuration() {
- synchronized (lock) {
- check(!mHasBeenReleased, "has been released, reset before use");
- check(mHasDuration, "you haven't called prepare, can't get the duration");
- return mDuration;
- }
- }
-
- @Override
- public void seekTo(int startPosition) {
- boolean currentlyPlaying;
- MediaPlayerDataSource dataSource;
- synchronized (lock) {
- check(!mHasBeenReleased, "has been released, reset before use");
- check(mHasDuration, "you can't seek until you have prepared");
- currentlyPlaying = mHasStartedPlayback && !hasPlaybackFinished();
- mStartPosition = Math.min(startPosition, mDuration);
- dataSource = mDataSource;
- }
- if (currentlyPlaying) {
- stopAndStartPlayingAgain(dataSource);
- }
- }
-
- private void stopAndStartPlayingAgain(MediaPlayerDataSource source) {
- stopCurrentPlayback();
- reset();
- innerSetDataSource(source);
- try {
- prepare();
- } catch (IOException e) {
- reportException(e);
- return;
- }
- start();
- return;
- }
-
- private void reportException(Exception e) {
- Log.e(TAG, "playback error:", e);
- }
-
- @Override
- public void start() {
- MediaPlayerDataSource restartWithThisDataSource = null;
- synchronized (lock) {
- check(!mHasBeenReleased, "has been released, reset before use");
- check(mIsPrepared, "must have prepared before you can start");
- if (!mHasStartedPlayback) {
- // Playback has not started. Start it.
- mHasStartedPlayback = true;
- EngineParameters engineParameters = new EngineParameters.Builder()
- .initialRate(mCurrentPlaybackRate)
- .startPositionMillis(mStartPosition)
- .audioStreamType(mAudioStreamType)
- .build();
- VariableSpeedNative.initializeEngine(engineParameters);
- VariableSpeedNative.startPlayback();
- mEngineInitializedLatch.countDown();
- mExecutor.execute(new PlaybackRunnable(mDataSource));
- } else {
- // Playback has already started. Restart it, without holding the
- // lock.
- restartWithThisDataSource = mDataSource;
- }
- }
- if (restartWithThisDataSource != null) {
- stopAndStartPlayingAgain(restartWithThisDataSource);
- }
- }
-
- /** A Runnable capable of driving the native audio playback methods. */
- private final class PlaybackRunnable implements Runnable {
- private final MediaPlayerDataSource mInnerSource;
-
- public PlaybackRunnable(MediaPlayerDataSource source) {
- mInnerSource = source;
- }
-
- @Override
- public void run() {
- try {
- mInnerSource.playNative();
- } catch (IOException e) {
- Log.e(TAG, "error playing audio", e);
- }
- MediaPlayer.OnCompletionListener completionListener;
- boolean skipThisCompletionReport;
- synchronized (lock) {
- completionListener = mCompletionListener;
- skipThisCompletionReport = mSkipCompletionReport;
- mPlaybackFinishedLatch.countDown();
- }
- if (!skipThisCompletionReport && completionListener != null) {
- completionListener.onCompletion(null);
- }
- }
- }
-
- @Override
- public boolean isReadyToPlay() {
- synchronized (lock) {
- return !mHasBeenReleased && mHasDuration;
- }
- }
-
- @Override
- public boolean isPlaying() {
- synchronized (lock) {
- return isReadyToPlay() && mHasStartedPlayback && !hasPlaybackFinished();
- }
- }
-
- @Override
- public int getCurrentPosition() {
- synchronized (lock) {
- check(!mHasBeenReleased, "has been released, reset before use");
- if (!mHasStartedPlayback) {
- return 0;
- }
- if (!hasEngineBeenInitialized()) {
- return 0;
- }
- if (!hasPlaybackFinished()) {
- return VariableSpeedNative.getCurrentPosition();
- }
- return mDuration;
- }
- }
-
- @Override
- public void pause() {
- synchronized (lock) {
- check(!mHasBeenReleased, "has been released, reset before use");
- }
- stopCurrentPlayback();
- }
-
- public void setVariableSpeed(float rate) {
- // TODO: are there situations in which the engine has been destroyed, so
- // that this will segfault?
- synchronized (lock) {
- check(!mHasBeenReleased, "has been released, reset before use");
- // TODO: This too is wrong, once we've started preparing the variable speed set
- // will not be enough.
- if (mHasStartedPlayback) {
- VariableSpeedNative.setVariableSpeed(rate);
- }
- mCurrentPlaybackRate = rate;
- }
- }
-
- private void check(boolean condition, String exception) {
- if (!condition) {
- throw new IllegalStateException(exception);
- }
- }
-
- private void checkNotNull(Object argument, String argumentName) {
- if (argument == null) {
- throw new IllegalArgumentException(argumentName + " must not be null");
- }
- }
-
- @Override
- public void setAudioStreamType(int audioStreamType) {
- synchronized (lock) {
- mAudioStreamType = audioStreamType;
- }
- }
-}
diff --git a/variablespeed/src/com/android/ex/variablespeed/VariableSpeedNative.java b/variablespeed/src/com/android/ex/variablespeed/VariableSpeedNative.java
deleted file mode 100644
index 07195db..0000000
--- a/variablespeed/src/com/android/ex/variablespeed/VariableSpeedNative.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.ex.variablespeed;
-
-import com.android.common.io.MoreCloseables;
-
-import android.content.Context;
-import android.content.res.AssetFileDescriptor;
-import android.net.Uri;
-
-import java.io.FileDescriptor;
-import java.io.FileNotFoundException;
-import java.lang.reflect.Field;
-
-/**
- * Provides all the native calls through to the underlying audio library.
- * <p>
- * You should not use this class directly. Prefer to use the {@link VariableSpeed}
- * class instead.
- */
-/*package*/ class VariableSpeedNative {
- /*package*/ static void loadLibrary() throws UnsatisfiedLinkError, SecurityException {
- System.loadLibrary("variablespeed");
- }
-
- /*package*/ static boolean playFromContext(Context context, Uri uri)
- throws FileNotFoundException {
- AssetFileDescriptor afd = context.getContentResolver().openAssetFileDescriptor(uri, "r");
- try {
- FileDescriptor fileDescriptor = afd.getFileDescriptor();
- Field descriptorField = fileDescriptor.getClass().getDeclaredField("descriptor");
- descriptorField.setAccessible(true);
- int fd = descriptorField.getInt(fileDescriptor);
- VariableSpeedNative.playFileDescriptor(fd, afd.getStartOffset(), afd.getLength());
- return true;
- } catch (SecurityException e) {
- // Fall through.
- } catch (NoSuchFieldException e) {
- // Fall through.
- } catch (IllegalArgumentException e) {
- // Fall through.
- } catch (IllegalAccessException e) {
- // Fall through.
- } finally {
- MoreCloseables.closeQuietly(afd);
- }
- return false;
- }
-
- /*package*/ static native void playUri(String uri);
-
- /*package*/ static native void playFileDescriptor(int fd, long offset, long length);
-
- /*package*/ static native void setVariableSpeed(float speed);
-
- /*package*/ static native void startPlayback();
-
- /*package*/ static native void stopPlayback();
-
- /*package*/ static native void shutdownEngine();
-
- /*package*/ static native int getCurrentPosition();
-
- /*package*/ static native int getTotalDuration();
-
- /*package*/ static void initializeEngine(EngineParameters params) {
- initializeEngine(params.getTargetFrames(),
- params.getWindowDuration(), params.getWindowOverlapDuration(),
- params.getMaxPlayBufferCount(), params.getInitialRate(),
- params.getDecodeBufferInitialSize(), params.getDecodeBufferMaxSize(),
- params.getStartPositionMillis(), params.getAudioStreamType());
- }
-
- private static native void initializeEngine(int targetFrames,
- float windowDuration, float windowOverlapDuration, int maxPlayBufferCount,
- float initialRate, int decodeBufferInitialSize, int decodeBufferMaxSize,
- int startPositionMillis, int audioStreamType);
-}