summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordaniel oeh <daniel.oeh@gmail.com>2014-03-22 18:05:51 +0100
committerdaniel oeh <daniel.oeh@gmail.com>2014-03-22 18:05:51 +0100
commite1b1338840f8a5c75c1911085af03975422116db (patch)
treed2a3bb41cc31c48908562a4fe3f64d0bf5bef9be
parentdc0d2738a1782155071c19fcd2822193daefdfaf (diff)
downloadAntennaPod-e1b1338840f8a5c75c1911085af03975422116db.zip
Added presto client dependency as source code
-rw-r--r--build.gradle6
-rw-r--r--src/com/aocate/media/AndroidMediaPlayer.java470
-rw-r--r--src/com/aocate/media/MediaPlayer.java1294
-rw-r--r--src/com/aocate/media/MediaPlayerImpl.java118
-rw-r--r--src/com/aocate/media/ServiceBackedMediaPlayer.java1170
-rw-r--r--src/com/aocate/media/SpeedAdjustmentAlgorithm.java31
-rw-r--r--src/com/aocate/presto/service/IDeathCallback_0_8.aidl18
-rw-r--r--src/com/aocate/presto/service/IOnBufferingUpdateListenerCallback_0_8.aidl19
-rw-r--r--src/com/aocate/presto/service/IOnCompletionListenerCallback_0_8.aidl19
-rw-r--r--src/com/aocate/presto/service/IOnErrorListenerCallback_0_8.aidl19
-rw-r--r--src/com/aocate/presto/service/IOnInfoListenerCallback_0_8.aidl19
-rw-r--r--src/com/aocate/presto/service/IOnPitchAdjustmentAvailableChangedListenerCallback_0_8.aidl19
-rw-r--r--src/com/aocate/presto/service/IOnPreparedListenerCallback_0_8.aidl19
-rw-r--r--src/com/aocate/presto/service/IOnSeekCompleteListenerCallback_0_8.aidl19
-rw-r--r--src/com/aocate/presto/service/IOnSpeedAdjustmentAvailableChangedListenerCallback_0_8.aidl19
-rw-r--r--src/com/aocate/presto/service/IPlayMedia_0_8.aidl75
16 files changed, 3328 insertions, 6 deletions
diff --git a/build.gradle b/build.gradle
index 20f0d6fdb..8c12c60fd 100644
--- a/build.gradle
+++ b/build.gradle
@@ -17,11 +17,6 @@ dependencies {
println "Creating libs directory"
libsdir.mkdir()
}
- def prestoLib = new File('libs/presto_client-0.8.5.jar')
- if (!prestoLib.exists()) {
- println "Downloading presto library into libs folder"
- new URL('http://www.aocate.com/presto/client/presto_client-0.8.5.jar').withInputStream{ i -> prestoLib.withOutputStream{ it << i }}
- }
compile 'com.android.support:appcompat-v7:19.0.+'
compile 'org.apache.commons:commons-lang3:3.2.1'
@@ -33,7 +28,6 @@ dependencies {
compile 'commons-io:commons-io:2.4'
compile 'com.nineoldandroids:library:2.4.0'
compile project(':submodules:dslv:library')
- compile files('libs/presto_client-0.8.5.jar')
}
android {
diff --git a/src/com/aocate/media/AndroidMediaPlayer.java b/src/com/aocate/media/AndroidMediaPlayer.java
new file mode 100644
index 000000000..17ee74a13
--- /dev/null
+++ b/src/com/aocate/media/AndroidMediaPlayer.java
@@ -0,0 +1,470 @@
+// Copyright 2011, Aocate, Inc.
+//
+// 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.aocate.media;
+
+import java.io.IOException;
+
+import android.content.Context;
+import android.media.MediaPlayer;
+import android.net.Uri;
+import android.util.Log;
+
+public class AndroidMediaPlayer extends MediaPlayerImpl {
+ private final static String AMP_TAG = "AocateAndroidMediaPlayer";
+
+ // private static final long TIMEOUT_DURATION_MS = 500;
+
+ android.media.MediaPlayer mp = null;
+
+ private android.media.MediaPlayer.OnBufferingUpdateListener onBufferingUpdateListener = new android.media.MediaPlayer.OnBufferingUpdateListener() {
+ public void onBufferingUpdate(android.media.MediaPlayer mp, int percent) {
+ if (owningMediaPlayer != null) {
+ owningMediaPlayer.lock.lock();
+ try {
+ if ((owningMediaPlayer.onBufferingUpdateListener != null)
+ && (owningMediaPlayer.mpi == AndroidMediaPlayer.this)) {
+ owningMediaPlayer.onBufferingUpdateListener.onBufferingUpdate(owningMediaPlayer, percent);
+ }
+ }
+ finally {
+ owningMediaPlayer.lock.unlock();
+ }
+ }
+
+ }
+ };
+
+ private android.media.MediaPlayer.OnCompletionListener onCompletionListener = new android.media.MediaPlayer.OnCompletionListener() {
+ public void onCompletion(android.media.MediaPlayer mp) {
+ Log.d(AMP_TAG, "onCompletionListener being called");
+ if (owningMediaPlayer != null) {
+ owningMediaPlayer.lock.lock();
+ try {
+ if (owningMediaPlayer.onCompletionListener != null) {
+ owningMediaPlayer.onCompletionListener.onCompletion(owningMediaPlayer);
+ }
+ }
+ finally {
+ owningMediaPlayer.lock.unlock();
+ }
+ }
+ }
+ };
+
+ private android.media.MediaPlayer.OnErrorListener onErrorListener = new android.media.MediaPlayer.OnErrorListener() {
+ public boolean onError(android.media.MediaPlayer mp, int what, int extra) {
+ // Once we're in errored state, any received messages are going to be junked
+ if (owningMediaPlayer != null) {
+ owningMediaPlayer.lock.lock();
+ try {
+ if (owningMediaPlayer.onErrorListener != null) {
+ return owningMediaPlayer.onErrorListener.onError(owningMediaPlayer, what, extra);
+ }
+ }
+ finally {
+ owningMediaPlayer.lock.unlock();
+ }
+ }
+ return false;
+ }
+ };
+
+ private android.media.MediaPlayer.OnInfoListener onInfoListener = new android.media.MediaPlayer.OnInfoListener() {
+ public boolean onInfo(android.media.MediaPlayer mp, int what, int extra) {
+ if (owningMediaPlayer != null) {
+ owningMediaPlayer.lock.lock();
+ try {
+ if ((owningMediaPlayer.onInfoListener != null)
+ && (owningMediaPlayer.mpi == AndroidMediaPlayer.this)) {
+ return owningMediaPlayer.onInfoListener.onInfo(owningMediaPlayer, what, extra);
+ }
+ }
+ finally {
+ owningMediaPlayer.lock.unlock();
+ }
+ }
+ return false;
+ }
+ };
+
+ // We have to assign this.onPreparedListener because the
+ // onPreparedListener in owningMediaPlayer sets the state
+ // to PREPARED. Due to prepareAsync, that's the only
+ // reasonable place to do it
+ // The others it just didn't make sense to have a setOnXListener that didn't use the parameter
+ private android.media.MediaPlayer.OnPreparedListener onPreparedListener = new android.media.MediaPlayer.OnPreparedListener() {
+ public void onPrepared(android.media.MediaPlayer mp) {
+ Log.d(AMP_TAG, "Calling onPreparedListener.onPrepared()");
+ if (AndroidMediaPlayer.this.owningMediaPlayer != null) {
+ AndroidMediaPlayer.this.lockMuteOnPreparedCount.lock();
+ try {
+ if (AndroidMediaPlayer.this.muteOnPreparedCount > 0) {
+ AndroidMediaPlayer.this.muteOnPreparedCount--;
+ }
+ else {
+ AndroidMediaPlayer.this.muteOnPreparedCount = 0;
+ if (AndroidMediaPlayer.this.owningMediaPlayer.onPreparedListener != null) {
+ Log.d(AMP_TAG, "Invoking AndroidMediaPlayer.this.owningMediaPlayer.onPreparedListener.onPrepared");
+ AndroidMediaPlayer.this.owningMediaPlayer.onPreparedListener.onPrepared(AndroidMediaPlayer.this.owningMediaPlayer);
+ }
+ }
+ }
+ finally {
+ AndroidMediaPlayer.this.lockMuteOnPreparedCount.unlock();
+ }
+ if (owningMediaPlayer.mpi != AndroidMediaPlayer.this) {
+ Log.d(AMP_TAG, "owningMediaPlayer has changed implementation");
+ }
+ }
+ }
+ };
+
+ private android.media.MediaPlayer.OnSeekCompleteListener onSeekCompleteListener = new android.media.MediaPlayer.OnSeekCompleteListener() {
+ public void onSeekComplete(android.media.MediaPlayer mp) {
+ if (owningMediaPlayer != null) {
+ owningMediaPlayer.lock.lock();
+ try {
+ lockMuteOnSeekCount.lock();
+ try {
+ if (AndroidMediaPlayer.this.muteOnSeekCount > 0) {
+ AndroidMediaPlayer.this.muteOnSeekCount--;
+ }
+ else {
+ AndroidMediaPlayer.this.muteOnSeekCount = 0;
+ if (AndroidMediaPlayer.this.owningMediaPlayer.onSeekCompleteListener != null) {
+ owningMediaPlayer.onSeekCompleteListener.onSeekComplete(owningMediaPlayer);
+ }
+ }
+ }
+ finally {
+ lockMuteOnSeekCount.unlock();
+ }
+ }
+ finally {
+ owningMediaPlayer.lock.unlock();
+ }
+ }
+ }
+ };
+
+ public AndroidMediaPlayer(com.aocate.media.MediaPlayer owningMediaPlayer, Context context) {
+ super(owningMediaPlayer, context);
+
+ mp = new MediaPlayer();
+
+// final ReentrantLock lock = new ReentrantLock();
+// Handler handler = new Handler(Looper.getMainLooper()) {
+// @Override
+// public void handleMessage(Message msg) {
+// Log.d(AMP_TAG, "Instantiating new AndroidMediaPlayer from Handler");
+// lock.lock();
+// if (mp == null) {
+// mp = new MediaPlayer();
+// }
+// lock.unlock();
+// }
+// };
+//
+// long endTime = System.currentTimeMillis() + TIMEOUT_DURATION_MS;
+//
+// while (true) {
+// // Retry messages until mp isn't null or it's time to give up
+// handler.sendMessage(handler.obtainMessage());
+// if ((mp != null)
+// || (endTime < System.currentTimeMillis())) {
+// break;
+// }
+// try {
+// Thread.sleep(50);
+// } catch (InterruptedException e) {
+// // TODO Auto-generated catch block
+// e.printStackTrace();
+// }
+// }
+
+ if (mp == null) {
+ throw new IllegalStateException("Did not instantiate android.media.MediaPlayer successfully");
+ }
+
+ mp.setOnBufferingUpdateListener(this.onBufferingUpdateListener);
+ mp.setOnCompletionListener(this.onCompletionListener);
+ mp.setOnErrorListener(this.onErrorListener);
+ mp.setOnInfoListener(this.onInfoListener);
+ Log.d(AMP_TAG, " ++++++++++++++++++++++++++++++++ Setting prepared listener to this.onPreparedListener");
+ mp.setOnPreparedListener(this.onPreparedListener);
+ mp.setOnSeekCompleteListener(this.onSeekCompleteListener);
+ }
+
+ @Override
+ public boolean canSetPitch() {
+ return false;
+ }
+
+ @Override
+ public boolean canSetSpeed() {
+ return false;
+ }
+
+ @Override
+ public float getCurrentPitchStepsAdjustment() {
+ return 0;
+ }
+
+ @Override
+ public int getCurrentPosition() {
+ owningMediaPlayer.lock.lock();
+ try {
+ return mp.getCurrentPosition();
+ }
+ finally {
+ owningMediaPlayer.lock.unlock();
+ }
+ }
+
+ @Override
+ public float getCurrentSpeedMultiplier() {
+ return 1f;
+ }
+
+ @Override
+ public int getDuration() {
+ owningMediaPlayer.lock.lock();
+ try {
+ return mp.getDuration();
+ }
+ finally {
+ owningMediaPlayer.lock.unlock();
+ }
+ }
+
+ @Override
+ public float getMaxSpeedMultiplier() {
+ return 1f;
+ }
+
+ @Override
+ public float getMinSpeedMultiplier() {
+ return 1f;
+ }
+
+ @Override
+ public boolean isLooping() {
+ owningMediaPlayer.lock.lock();
+ try {
+ return mp.isLooping();
+ }
+ finally {
+ owningMediaPlayer.lock.unlock();
+ }
+ }
+
+ @Override
+ public boolean isPlaying() {
+ owningMediaPlayer.lock.lock();
+ try {
+ return mp.isPlaying();
+ }
+ finally {
+ owningMediaPlayer.lock.unlock();
+ }
+ }
+
+ @Override
+ public void pause() {
+ owningMediaPlayer.lock.lock();
+ try {
+ mp.pause();
+ }
+ finally {
+ owningMediaPlayer.lock.unlock();
+ }
+ }
+
+ @Override
+ public void prepare() throws IllegalStateException, IOException {
+ owningMediaPlayer.lock.lock();
+ Log.d(AMP_TAG, "prepare()");
+ try {
+ mp.prepare();
+ Log.d(AMP_TAG, "Finish prepare()");
+ }
+ finally {
+ owningMediaPlayer.lock.unlock();
+ }
+ }
+
+ @Override
+ public void prepareAsync() {
+ mp.prepareAsync();
+ }
+
+ @Override
+ public void release() {
+ owningMediaPlayer.lock.lock();
+ try {
+ if (mp != null) {
+ Log.d(AMP_TAG, "mp.release()");
+ mp.release();
+ }
+ }
+ finally {
+ owningMediaPlayer.lock.unlock();
+ }
+ }
+
+ @Override
+ public void reset() {
+ owningMediaPlayer.lock.lock();
+ try {
+ mp.reset();
+ }
+ finally {
+ owningMediaPlayer.lock.unlock();
+ }
+ }
+
+ @Override
+ public void seekTo(int msec) throws IllegalStateException {
+ owningMediaPlayer.lock.lock();
+ try {
+ mp.setOnSeekCompleteListener(this.onSeekCompleteListener);
+ mp.seekTo(msec);
+ }
+ finally {
+ owningMediaPlayer.lock.unlock();
+ }
+ }
+
+ @Override
+ public void setAudioStreamType(int streamtype) {
+ owningMediaPlayer.lock.lock();
+ try {
+ mp.setAudioStreamType(streamtype);
+ }
+ finally {
+ owningMediaPlayer.lock.unlock();
+ }
+ }
+
+ @Override
+ public void setDataSource(Context context, Uri uri)
+ throws IllegalArgumentException, IllegalStateException, IOException {
+ owningMediaPlayer.lock.lock();
+ try {
+ Log.d(AMP_TAG, "setDataSource(context, " + uri.toString() + ")");
+ mp.setDataSource(context, uri);
+ }
+ finally {
+ owningMediaPlayer.lock.unlock();
+ }
+ }
+
+ @Override
+ public void setDataSource(String path) throws IllegalArgumentException,
+ IllegalStateException, IOException {
+ owningMediaPlayer.lock.lock();
+ try {
+ Log.d(AMP_TAG, "setDataSource(" + path + ")");
+ mp.setDataSource(path);
+ }
+ finally {
+ owningMediaPlayer.lock.unlock();
+ }
+ }
+
+ @Override
+ public void setEnableSpeedAdjustment(boolean enableSpeedAdjustment) {
+ // Can't!
+ }
+
+ @Override
+ public void setLooping(boolean loop) {
+ owningMediaPlayer.lock.lock();
+ try {
+ mp.setLooping(loop);
+ }
+ finally {
+ owningMediaPlayer.lock.unlock();
+ }
+ }
+
+ @Override
+ public void setPitchStepsAdjustment(float pitchSteps) {
+ // Can't!
+ }
+
+ @Override
+ public void setPlaybackPitch(float f) {
+ // Can't!
+ }
+
+ @Override
+ public void setPlaybackSpeed(float f) {
+ // Can't!
+ Log.d(AMP_TAG, "setPlaybackSpeed(" + f + ")");
+ }
+
+ @Override
+ public void setSpeedAdjustmentAlgorithm(int algorithm) {
+ // Can't!
+ Log.d(AMP_TAG, "setSpeedAdjustmentAlgorithm(" + algorithm + ")");
+ }
+
+ @Override
+ public void setVolume(float leftVolume, float rightVolume) {
+ owningMediaPlayer.lock.lock();
+ try {
+ mp.setVolume(leftVolume, rightVolume);
+ }
+ finally {
+ owningMediaPlayer.lock.unlock();
+ }
+ }
+
+ @Override
+ public void setWakeMode(Context context, int mode) {
+ owningMediaPlayer.lock.lock();
+ try {
+ if (mode != 0) {
+ mp.setWakeMode(context, mode);
+ }
+ }
+ finally {
+ owningMediaPlayer.lock.unlock();
+ }
+ }
+
+ @Override
+ public void start() {
+ owningMediaPlayer.lock.lock();
+ try {
+ mp.start();
+ }
+ finally {
+ owningMediaPlayer.lock.unlock();
+ }
+ }
+
+ @Override
+ public void stop() {
+ owningMediaPlayer.lock.lock();
+ try {
+ mp.stop();
+ }
+ finally {
+ owningMediaPlayer.lock.unlock();
+ }
+ }
+}
diff --git a/src/com/aocate/media/MediaPlayer.java b/src/com/aocate/media/MediaPlayer.java
new file mode 100644
index 000000000..995dbbc51
--- /dev/null
+++ b/src/com/aocate/media/MediaPlayer.java
@@ -0,0 +1,1294 @@
+// Copyright 2011, Aocate, Inc.
+//
+// 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.aocate.media;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.concurrent.locks.ReentrantLock;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.media.AudioManager;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.Handler.Callback;
+import android.util.Log;
+
+public class MediaPlayer {
+ public interface OnBufferingUpdateListener {
+ public abstract void onBufferingUpdate(MediaPlayer arg0, int percent);
+ }
+
+ public interface OnCompletionListener {
+ public abstract void onCompletion(MediaPlayer arg0);
+ }
+
+ public interface OnErrorListener {
+ public abstract boolean onError(MediaPlayer arg0, int what, int extra);
+ }
+
+ public interface OnInfoListener {
+ public abstract boolean onInfo(MediaPlayer arg0, int what, int extra);
+ }
+
+ public interface OnPitchAdjustmentAvailableChangedListener {
+ /**
+ *
+ * @param arg0
+ * The owning media player
+ * @param pitchAdjustmentAvailable
+ * True if pitch adjustment is available, false if not
+ */
+ public abstract void onPitchAdjustmentAvailableChanged(
+ MediaPlayer arg0, boolean pitchAdjustmentAvailable);
+ }
+
+ public interface OnPreparedListener {
+ public abstract void onPrepared(MediaPlayer arg0);
+ }
+
+ public interface OnSeekCompleteListener {
+ public abstract void onSeekComplete(MediaPlayer arg0);
+ }
+
+ public interface OnSpeedAdjustmentAvailableChangedListener {
+ /**
+ *
+ * @param arg0
+ * The owning media player
+ * @param speedAdjustmentAvailable
+ * True if speed adjustment is available, false if not
+ */
+ public abstract void onSpeedAdjustmentAvailableChanged(
+ MediaPlayer arg0, boolean speedAdjustmentAvailable);
+ }
+
+ public enum State {
+ IDLE, INITIALIZED, PREPARED, STARTED, PAUSED, STOPPED, PREPARING, PLAYBACK_COMPLETED, END, ERROR
+ }
+
+ private static Uri SPEED_ADJUSTMENT_MARKET_URI = Uri
+ .parse("market://details?id=com.aocate.presto");
+
+ private static Intent prestoMarketIntent = null;
+
+ public static final int MEDIA_ERROR_SERVER_DIED = android.media.MediaPlayer.MEDIA_ERROR_SERVER_DIED;
+ public static final int MEDIA_ERROR_UNKNOWN = android.media.MediaPlayer.MEDIA_ERROR_UNKNOWN;
+ public static final int MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK = android.media.MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK;
+
+ /**
+ * Indicates whether the specified action can be used as an intent. This
+ * method queries the package manager for installed packages that can
+ * respond to an intent with the specified action. If no suitable package is
+ * found, this method returns false.
+ *
+ * @param context
+ * The application's environment.
+ * @param action
+ * The Intent action to check for availability.
+ *
+ * @return True if an Intent with the specified action can be sent and
+ * responded to, false otherwise.
+ */
+ public static boolean isIntentAvailable(Context context, String action) {
+ final PackageManager packageManager = context.getPackageManager();
+ final Intent intent = new Intent(action);
+ List<ResolveInfo> list = packageManager.queryIntentServices(intent,
+ PackageManager.MATCH_DEFAULT_ONLY);
+ return list.size() > 0;
+ }
+
+ /**
+ * Indicates whether the Presto library is installed
+ *
+ * @param context
+ * The context to use to query the package manager.
+ * @return True if the Presto library is installed, false if not.
+ */
+ public static boolean isPrestoLibraryInstalled(Context context) {
+ return isIntentAvailable(context, ServiceBackedMediaPlayer.INTENT_NAME);
+ }
+
+ /**
+ * Return an Intent that opens the Android Market page for the speed
+ * alteration library
+ *
+ * @return The Intent for the Presto library on the Android Market
+ */
+ public static Intent getPrestoMarketIntent() {
+ if (prestoMarketIntent == null) {
+ prestoMarketIntent = new Intent(Intent.ACTION_VIEW,
+ SPEED_ADJUSTMENT_MARKET_URI);
+ }
+ return prestoMarketIntent;
+ }
+
+ /**
+ * Open the Android Market page for the Presto library
+ *
+ * @param context
+ * The context from which to open the Android Market page
+ */
+ public static void openPrestoMarketIntent(Context context) {
+ context.startActivity(getPrestoMarketIntent());
+ }
+
+ private static final String MP_TAG = "AocateReplacementMediaPlayer";
+
+ private static final double PITCH_STEP_CONSTANT = 1.0594630943593;
+
+ private AndroidMediaPlayer amp = null;
+ // This is whether speed adjustment should be enabled (by the Service)
+ // To avoid the Service entirely, set useService to false
+ protected boolean enableSpeedAdjustment = true;
+ private int lastKnownPosition = 0;
+ // In some cases, we're going to have to replace the
+ // android.media.MediaPlayer on the fly, and we don't want to touch the
+ // wrong media player, so lock it way too much.
+ ReentrantLock lock = new ReentrantLock();
+ private int mAudioStreamType = AudioManager.STREAM_MUSIC;
+ private Context mContext;
+ private boolean mIsLooping = false;
+ private float mLeftVolume = 1f;
+ private float mPitchStepsAdjustment = 0f;
+ private float mRightVolume = 1f;
+ private float mSpeedMultiplier = 1f;
+ private int mWakeMode = 0;
+ MediaPlayerImpl mpi = null;
+ protected boolean pitchAdjustmentAvailable = false;
+ private ServiceBackedMediaPlayer sbmp = null;
+ protected boolean speedAdjustmentAvailable = false;
+
+ private Handler mServiceDisconnectedHandler = null;
+
+ // Some parts of state cannot be found by calling MediaPlayerImpl functions,
+ // so store our own state. This also helps copy state when changing
+ // implementations
+ State state = State.INITIALIZED;
+ String stringDataSource = null;
+ Uri uriDataSource = null;
+ private boolean useService = false;
+
+ // Naming Convention for Listeners
+ // Most listeners can both be set by clients and called by MediaPlayImpls
+ // There are a few that have to do things in this class as well as calling
+ // the function. In all cases, onX is what is called by MediaPlayerImpl
+ // If there is work to be done in this class, then the listener that is
+ // set by setX is X (with the first letter lowercase).
+ OnBufferingUpdateListener onBufferingUpdateListener = null;
+ OnCompletionListener onCompletionListener = null;
+ OnErrorListener onErrorListener = null;
+ OnInfoListener onInfoListener = null;
+
+ // Special case. Pitch adjustment ceases to be available when we switch
+ // to the android.media.MediaPlayer (though it is not guaranteed to be
+ // available when using the ServiceBackedMediaPlayer)
+ OnPitchAdjustmentAvailableChangedListener onPitchAdjustmentAvailableChangedListener = new OnPitchAdjustmentAvailableChangedListener() {
+ public void onPitchAdjustmentAvailableChanged(MediaPlayer arg0,
+ boolean pitchAdjustmentAvailable) {
+ lock.lock();
+ try {
+ Log
+ .d(
+ MP_TAG,
+ "onPitchAdjustmentAvailableChangedListener.onPitchAdjustmentAvailableChanged being called");
+ if (MediaPlayer.this.pitchAdjustmentAvailable != pitchAdjustmentAvailable) {
+ Log.d(MP_TAG, "Pitch adjustment state has changed from "
+ + MediaPlayer.this.pitchAdjustmentAvailable
+ + " to " + pitchAdjustmentAvailable);
+ MediaPlayer.this.pitchAdjustmentAvailable = pitchAdjustmentAvailable;
+ if (MediaPlayer.this.pitchAdjustmentAvailableChangedListener != null) {
+ MediaPlayer.this.pitchAdjustmentAvailableChangedListener
+ .onPitchAdjustmentAvailableChanged(arg0,
+ pitchAdjustmentAvailable);
+ }
+ }
+ } finally {
+ lock.unlock();
+ }
+ }
+ };
+ OnPitchAdjustmentAvailableChangedListener pitchAdjustmentAvailableChangedListener = null;
+
+ MediaPlayer.OnPreparedListener onPreparedListener = new MediaPlayer.OnPreparedListener() {
+ public void onPrepared(MediaPlayer arg0) {
+ Log.d(MP_TAG, "onPreparedListener 242 setting state to PREPARED");
+ MediaPlayer.this.state = State.PREPARED;
+ if (MediaPlayer.this.preparedListener != null) {
+ Log.d(MP_TAG, "Calling preparedListener");
+ MediaPlayer.this.preparedListener.onPrepared(arg0);
+ }
+ Log.d(MP_TAG, "Wrap up onPreparedListener");
+ }
+ };
+
+ OnPreparedListener preparedListener = null;
+ OnSeekCompleteListener onSeekCompleteListener = null;
+
+ // Special case. Speed adjustment ceases to be available when we switch
+ // to the android.media.MediaPlayer (though it is not guaranteed to be
+ // available when using the ServiceBackedMediaPlayer)
+ OnSpeedAdjustmentAvailableChangedListener onSpeedAdjustmentAvailableChangedListener = new OnSpeedAdjustmentAvailableChangedListener() {
+ public void onSpeedAdjustmentAvailableChanged(MediaPlayer arg0,
+ boolean speedAdjustmentAvailable) {
+ lock.lock();
+ try {
+ Log
+ .d(
+ MP_TAG,
+ "onSpeedAdjustmentAvailableChangedListener.onSpeedAdjustmentAvailableChanged being called");
+ if (MediaPlayer.this.speedAdjustmentAvailable != speedAdjustmentAvailable) {
+ Log.d(MP_TAG, "Speed adjustment state has changed from "
+ + MediaPlayer.this.speedAdjustmentAvailable
+ + " to " + speedAdjustmentAvailable);
+ MediaPlayer.this.speedAdjustmentAvailable = speedAdjustmentAvailable;
+ if (MediaPlayer.this.speedAdjustmentAvailableChangedListener != null) {
+ MediaPlayer.this.speedAdjustmentAvailableChangedListener
+ .onSpeedAdjustmentAvailableChanged(arg0,
+ speedAdjustmentAvailable);
+ }
+ }
+ } finally {
+ lock.unlock();
+ }
+ }
+ };
+ OnSpeedAdjustmentAvailableChangedListener speedAdjustmentAvailableChangedListener = null;
+
+ private int speedAdjustmentAlgorithm = SpeedAdjustmentAlgorithm.SONIC;
+
+ public MediaPlayer(final Context context) {
+ this(context, true);
+ }
+
+ public MediaPlayer(final Context context, boolean useService) {
+ this.mContext = context;
+ this.useService = useService;
+
+ // So here's the major problem
+ // Sometimes the service won't exist or won't be connected,
+ // so start with an android.media.MediaPlayer, and when
+ // the service is connected, use that from then on
+ this.mpi = this.amp = new AndroidMediaPlayer(this, context);
+
+ // setupMpi will go get the Service, if it can, then bring that
+ // implementation into sync
+ Log.d(MP_TAG, "setupMpi");
+ setupMpi(context);
+ }
+
+ private boolean invalidServiceConnectionConfiguration() {
+ if (!(this.mpi instanceof ServiceBackedMediaPlayer)) {
+ if (this.useService && isPrestoLibraryInstalled()) {
+ // In this case, the Presto library has been installed
+ // or something while playing sound
+ // We could be using the service, but we're not
+ Log.d(MP_TAG, "We could be using the service, but we're not 316");
+ return true;
+ }
+ // If useService is false, then we shouldn't be using the SBMP
+ // If the Presto library isn't installed, ditto
+ Log.d(MP_TAG, "this.mpi is not a ServiceBackedMediaPlayer, but we couldn't use it anyway 321");
+ return false;
+ } else {
+ assert (this.mpi instanceof ServiceBackedMediaPlayer);
+ if (this.useService && isPrestoLibraryInstalled()) {
+ // We should be using the service, and we are. Great!
+ Log.d(MP_TAG, "We could be using a ServiceBackedMediaPlayer and we are 327");
+ return false;
+ }
+ // We're trying to use the service when we shouldn't,
+ // that's an invalid configuration
+ Log.d(MP_TAG, "We're trying to use a ServiceBackedMediaPlayer but we shouldn't be 332");
+ return true;
+ }
+ }
+
+ private void setupMpi(final Context context) {
+ lock.lock();
+ try {
+ Log.d(MP_TAG, "setupMpi 336");
+ // Check if the client wants to use the service at all,
+ // then if we're already using the right kind of media player
+ if (this.useService && isPrestoLibraryInstalled()) {
+ if ((this.mpi != null)
+ && (this.mpi instanceof ServiceBackedMediaPlayer)) {
+ Log.d(MP_TAG, "Already using ServiceBackedMediaPlayer");
+ return;
+ }
+ if (this.sbmp == null) {
+ Log.d(MP_TAG, "Instantiating new ServiceBackedMediaPlayer 346");
+ this.sbmp = new ServiceBackedMediaPlayer(this, context,
+ new ServiceConnection() {
+ public void onServiceConnected(
+ ComponentName className,
+ final IBinder service) {
+ Thread t = new Thread(new Runnable() {
+ public void run() {
+ // This lock probably isn't granular
+ // enough
+ MediaPlayer.this.lock.lock();
+ Log.d(MP_TAG,
+ "onServiceConnected 257");
+ try {
+ MediaPlayer.this
+ .switchMediaPlayerImpl(
+ MediaPlayer.this.amp,
+ MediaPlayer.this.sbmp);
+ Log.d(MP_TAG, "End onServiceConnected 362");
+ } finally {
+ MediaPlayer.this.lock.unlock();
+ }
+ }
+ });
+ t.start();
+ }
+
+ public void onServiceDisconnected(
+ ComponentName className) {
+ MediaPlayer.this.lock.lock();
+ try {
+ // Can't get any more useful information
+ // out of sbmp
+ if (MediaPlayer.this.sbmp != null) {
+ MediaPlayer.this.sbmp.release();
+ }
+ // Unlike most other cases, sbmp gets set
+ // to null since there's nothing useful
+ // backing it now
+ MediaPlayer.this.sbmp = null;
+
+ if (mServiceDisconnectedHandler == null) {
+ mServiceDisconnectedHandler = new Handler(new Callback() {
+ public boolean handleMessage(Message msg) {
+ // switchMediaPlayerImpl won't try to
+ // clone anything from null
+ lock.lock();
+ try {
+ if (MediaPlayer.this.amp == null) {
+ // This should never be in this state
+ MediaPlayer.this.amp = new AndroidMediaPlayer(
+ MediaPlayer.this,
+ MediaPlayer.this.mContext);
+ }
+ // Use sbmp instead of null in case by some miracle it's
+ // been restored in the meantime
+ MediaPlayer.this.switchMediaPlayerImpl(
+ MediaPlayer.this.sbmp,
+ MediaPlayer.this.amp);
+ return true;
+ }
+ finally {
+ lock.unlock();
+ }
+ }
+ });
+ }
+
+ // This code needs to execute on the
+ // original thread to instantiate
+ // the new object in the right place
+ mServiceDisconnectedHandler
+ .sendMessage(
+ mServiceDisconnectedHandler
+ .obtainMessage());
+ // Note that we do NOT want to set
+ // useService. useService is about
+ // what the user wants, not what they
+ // get
+ } finally {
+ MediaPlayer.this.lock.unlock();
+ }
+ }
+ }
+ );
+ }
+ switchMediaPlayerImpl(this.amp, this.sbmp);
+ } else {
+ if ((this.mpi != null)
+ && (this.mpi instanceof AndroidMediaPlayer)) {
+ Log.d(MP_TAG, "Already using AndroidMediaPlayer");
+ return;
+ }
+ if (this.amp == null) {
+ Log.d(MP_TAG, "Instantiating new AndroidMediaPlayer (this should be impossible)");
+ this.amp = new AndroidMediaPlayer(this, context);
+ }
+ switchMediaPlayerImpl(this.sbmp, this.amp);
+ }
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ private void switchMediaPlayerImpl(MediaPlayerImpl from, MediaPlayerImpl to) {
+ lock.lock();
+ try {
+ Log.d(MP_TAG, "switchMediaPlayerImpl");
+ if ((from == to)
+ // Same object, nothing to synchronize
+ || (to == null)
+ // Nothing to copy to (maybe this should throw an error?)
+ || ((to instanceof ServiceBackedMediaPlayer) && !((ServiceBackedMediaPlayer) to).isConnected())
+ // ServiceBackedMediaPlayer hasn't yet connected, onServiceConnected will take care of the transition
+ || (MediaPlayer.this.state == State.END)) {
+ // State.END is after a release(), no further functions should
+ // be called on this class and from is likely to have problems
+ // retrieving state that won't be used anyway
+ return;
+ }
+ // Extract all that we can from the existing implementation
+ // and copy it to the new implementation
+
+ Log.d(MP_TAG, "switchMediaPlayerImpl(), current state is "
+ + this.state.toString());
+
+ to.reset();
+
+ // Do this first so we don't have to prepare the same
+ // data file twice
+ to.setEnableSpeedAdjustment(MediaPlayer.this.enableSpeedAdjustment);
+
+ // This is a reasonable place to set all of these,
+ // none of them require prepare() or the like first
+ to.setAudioStreamType(this.mAudioStreamType);
+ to.setSpeedAdjustmentAlgorithm(this.speedAdjustmentAlgorithm);
+ to.setLooping(this.mIsLooping);
+ to.setPitchStepsAdjustment(this.mPitchStepsAdjustment);
+ Log.d(MP_TAG, "Setting playback speed to " + this.mSpeedMultiplier);
+ to.setPlaybackSpeed(this.mSpeedMultiplier);
+ to.setVolume(MediaPlayer.this.mLeftVolume,
+ MediaPlayer.this.mRightVolume);
+ to.setWakeMode(this.mContext, this.mWakeMode);
+
+ Log.d(MP_TAG, "asserting at least one data source is null");
+ assert ((MediaPlayer.this.stringDataSource == null) || (MediaPlayer.this.uriDataSource == null));
+
+ if (uriDataSource != null) {
+ Log.d(MP_TAG, "switchMediaPlayerImpl(): uriDataSource != null");
+ try {
+ to.setDataSource(this.mContext, uriDataSource);
+ } catch (IllegalArgumentException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (IllegalStateException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ if (stringDataSource != null) {
+ Log.d(MP_TAG,
+ "switchMediaPlayerImpl(): stringDataSource != null");
+ try {
+ to.setDataSource(stringDataSource);
+ } catch (IllegalArgumentException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (IllegalStateException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ if ((this.state == State.PREPARED)
+ || (this.state == State.PREPARING)
+ || (this.state == State.PAUSED)
+ || (this.state == State.STOPPED)
+ || (this.state == State.STARTED)
+ || (this.state == State.PLAYBACK_COMPLETED)) {
+ Log.d(MP_TAG, "switchMediaPlayerImpl(): prepare and seek");
+ // Use prepare here instead of prepareAsync so that
+ // we wait for it to be ready before we try to use it
+ try {
+ to.muteNextOnPrepare();
+ to.prepare();
+ } catch (IllegalStateException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+ int seekPos = 0;
+ if (from != null) {
+ seekPos = from.getCurrentPosition();
+ } else if (this.lastKnownPosition < to.getDuration()) {
+ // This can happen if the Service unexpectedly
+ // disconnected. Because it would result in too much
+ // information being passed around, we don't constantly
+ // poll for the lastKnownPosition, but we'll save it
+ // when getCurrentPosition is called
+ seekPos = this.lastKnownPosition;
+ }
+ to.muteNextSeek();
+ to.seekTo(seekPos);
+ }
+ if ((from != null)
+ && from.isPlaying()) {
+ from.pause();
+ }
+ if ((this.state == State.STARTED)
+ || (this.state == State.PAUSED)
+ || (this.state == State.STOPPED)) {
+ Log.d(MP_TAG, "switchMediaPlayerImpl(): start");
+ if (to != null) {
+ to.start();
+ }
+ }
+
+ if (this.state == State.PAUSED) {
+ Log.d(MP_TAG, "switchMediaPlayerImpl(): paused");
+ if (to != null) {
+ to.pause();
+ }
+ } else if (this.state == State.STOPPED) {
+ Log.d(MP_TAG, "switchMediaPlayerImpl(): stopped");
+ if (to != null) {
+ to.stop();
+ }
+ }
+
+ this.mpi = to;
+
+ // Cheating here by relying on the side effect in
+ // on(Pitch|Speed)AdjustmentAvailableChanged
+ if ((to.canSetPitch() != this.pitchAdjustmentAvailable)
+ && (this.onPitchAdjustmentAvailableChangedListener != null)) {
+ this.onPitchAdjustmentAvailableChangedListener
+ .onPitchAdjustmentAvailableChanged(this, to
+ .canSetPitch());
+ }
+ if ((to.canSetSpeed() != this.speedAdjustmentAvailable)
+ && (this.onSpeedAdjustmentAvailableChangedListener != null)) {
+ this.onSpeedAdjustmentAvailableChangedListener
+ .onSpeedAdjustmentAvailableChanged(this, to
+ .canSetSpeed());
+ }
+ Log.d(MP_TAG, "switchMediaPlayerImpl() 625 " + this.state.toString());
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Returns true if pitch can be changed at this moment
+ *
+ * @return True if pitch can be changed
+ */
+ public boolean canSetPitch() {
+ lock.lock();
+ try {
+ return this.mpi.canSetPitch();
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Returns true if speed can be changed at this moment
+ *
+ * @return True if speed can be changed
+ */
+ public boolean canSetSpeed() {
+ lock.lock();
+ try {
+ return this.mpi.canSetSpeed();
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ protected void finalize() throws Throwable {
+ lock.lock();
+ try {
+ Log.d(MP_TAG, "finalize() 626");
+ this.release();
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Returns the number of steps (in a musical scale) by which playback is
+ * currently shifted. When greater than zero, pitch is shifted up. When less
+ * than zero, pitch is shifted down.
+ *
+ * @return The number of steps pitch is currently shifted by
+ */
+ public float getCurrentPitchStepsAdjustment() {
+ lock.lock();
+ try {
+ return this.mpi.getCurrentPitchStepsAdjustment();
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Functions identically to android.media.MediaPlayer.getCurrentPosition()
+ * Accurate only to frame size of encoded data (26 ms for MP3s)
+ *
+ * @return Current position (in milliseconds)
+ */
+ public int getCurrentPosition() {
+ lock.lock();
+ try {
+ return (this.lastKnownPosition = this.mpi.getCurrentPosition());
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Returns the current speed multiplier. Defaults to 1.0 (normal speed)
+ *
+ * @return The current speed multiplier
+ */
+ public float getCurrentSpeedMultiplier() {
+ lock.lock();
+ try {
+ return this.mpi.getCurrentSpeedMultiplier();
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Functions identically to android.media.MediaPlayer.getDuration()
+ *
+ * @return Length of the track (in milliseconds)
+ */
+ public int getDuration() {
+ lock.lock();
+ try {
+ return this.mpi.getDuration();
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Get the maximum value that can be passed to setPlaybackSpeed
+ *
+ * @return The maximum speed multiplier
+ */
+ public float getMaxSpeedMultiplier() {
+ lock.lock();
+ try {
+ return this.mpi.getMaxSpeedMultiplier();
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Get the minimum value that can be passed to setPlaybackSpeed
+ *
+ * @return The minimum speed multiplier
+ */
+ public float getMinSpeedMultiplier() {
+ lock.lock();
+ try {
+ return this.mpi.getMinSpeedMultiplier();
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Gets the version code of the backing service
+ * @return -1 if ServiceBackedMediaPlayer is not used, 0 if the service is not
+ * connected, otherwise the version code retrieved from the service
+ */
+ public int getServiceVersionCode() {
+ lock.lock();
+ try {
+ if (this.mpi instanceof ServiceBackedMediaPlayer) {
+ return ((ServiceBackedMediaPlayer) this.mpi).getServiceVersionCode();
+ }
+ else {
+ return -1;
+ }
+ }
+ finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Gets the version name of the backing service
+ * @return null if ServiceBackedMediaPlayer is not used, empty string if
+ * the service is not connected, otherwise the version name retrieved from
+ * the service
+ */
+ public String getServiceVersionName() {
+ lock.lock();
+ try {
+ if (this.mpi instanceof ServiceBackedMediaPlayer) {
+ return ((ServiceBackedMediaPlayer) this.mpi).getServiceVersionName();
+ }
+ else {
+ return null;
+ }
+ }
+ finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Functions identically to android.media.MediaPlayer.isLooping()
+ *
+ * @return True if the track is looping
+ */
+ public boolean isLooping() {
+ lock.lock();
+ try {
+ return this.mpi.isLooping();
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Functions identically to android.media.MediaPlayer.isPlaying()
+ *
+ * @return True if the track is playing
+ */
+ public boolean isPlaying() {
+ lock.lock();
+ try {
+ return this.mpi.isPlaying();
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Returns true if this MediaPlayer has access to the Presto
+ * library
+ *
+ * @return True if the Presto library is installed
+ */
+ public boolean isPrestoLibraryInstalled() {
+ if ((this.mpi == null) || (this.mpi.mContext == null)) {
+ return false;
+ }
+ return isPrestoLibraryInstalled(this.mpi.mContext);
+ }
+
+ /**
+ * Open the Android Market page in the same context as this MediaPlayer
+ */
+ public void openPrestoMarketIntent() {
+ if ((this.mpi != null) && (this.mpi.mContext != null)) {
+ openPrestoMarketIntent(this.mpi.mContext);
+ }
+ }
+
+ /**
+ * Functions identically to android.media.MediaPlayer.pause() Pauses the
+ * track
+ */
+ public void pause() {
+ lock.lock();
+ try {
+ if (invalidServiceConnectionConfiguration()) {
+ setupMpi(this.mpi.mContext);
+ }
+ this.state = State.PAUSED;
+ this.mpi.pause();
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Functions identically to android.media.MediaPlayer.prepare() Prepares the
+ * track. This or prepareAsync must be called before start()
+ */
+ public void prepare() throws IllegalStateException, IOException {
+ lock.lock();
+ try {
+ Log.d(MP_TAG, "prepare() 746 using " + ((this.mpi == null) ? "null (this shouldn't happen)" : this.mpi.getClass().toString()) + " state " + this.state.toString());
+ Log.d(MP_TAG, "onPreparedListener is: " + ((this.onPreparedListener == null) ? "null" : "non-null"));
+ Log.d(MP_TAG, "preparedListener is: " + ((this.preparedListener == null) ? "null" : "non-null"));
+ if (invalidServiceConnectionConfiguration()) {
+ setupMpi(this.mpi.mContext);
+ }
+ this.mpi.prepare();
+ this.state = State.PREPARED;
+ Log.d(MP_TAG, "prepare() finished 778");
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Functions identically to android.media.MediaPlayer.prepareAsync()
+ * Prepares the track. This or prepare must be called before start()
+ */
+ public void prepareAsync() {
+ lock.lock();
+ try {
+ Log.d(MP_TAG, "prepareAsync() 779");
+ if (invalidServiceConnectionConfiguration()) {
+ setupMpi(this.mpi.mContext);
+ }
+ this.state = State.PREPARING;
+ this.mpi.prepareAsync();
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Functions identically to android.media.MediaPlayer.release() Releases the
+ * underlying resources used by the media player.
+ */
+ public void release() {
+ lock.lock();
+ try {
+ Log.d(MP_TAG, "Releasing MediaPlayer 791");
+
+ this.state = State.END;
+ if (this.amp != null) {
+ this.amp.release();
+ }
+ if (this.sbmp != null) {
+ this.sbmp.release();
+ }
+
+ this.onBufferingUpdateListener = null;
+ this.onCompletionListener = null;
+ this.onErrorListener = null;
+ this.onInfoListener = null;
+ this.preparedListener = null;
+ this.onPitchAdjustmentAvailableChangedListener = null;
+ this.pitchAdjustmentAvailableChangedListener = null;
+ Log.d(MP_TAG, "Setting onSeekCompleteListener to null 871");
+ this.onSeekCompleteListener = null;
+ this.onSpeedAdjustmentAvailableChangedListener = null;
+ this.speedAdjustmentAvailableChangedListener = null;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Functions identically to android.media.MediaPlayer.reset() Resets the
+ * track to idle state
+ */
+ public void reset() {
+ lock.lock();
+ try {
+ this.state = State.IDLE;
+ this.stringDataSource = null;
+ this.uriDataSource = null;
+ this.mpi.reset();
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Functions identically to android.media.MediaPlayer.seekTo(int msec) Seeks
+ * to msec in the track
+ */
+ public void seekTo(int msec) throws IllegalStateException {
+ lock.lock();
+ try {
+ this.mpi.seekTo(msec);
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Functions identically to android.media.MediaPlayer.setAudioStreamType(int
+ * streamtype) Sets the audio stream type.
+ */
+ public void setAudioStreamType(int streamtype) {
+ lock.lock();
+ try {
+ this.mAudioStreamType = streamtype;
+ this.mpi.setAudioStreamType(streamtype);
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Functions identically to android.media.MediaPlayer.setDataSource(Context
+ * context, Uri uri) Sets uri as data source in the context given
+ */
+ public void setDataSource(Context context, Uri uri)
+ throws IllegalArgumentException, IllegalStateException, IOException {
+ lock.lock();
+ try {
+ Log.d(MP_TAG, "In setDataSource(context, " + uri.toString() + "), using " + this.mpi.getClass().toString());
+ if (invalidServiceConnectionConfiguration()) {
+ setupMpi(this.mpi.mContext);
+ }
+ this.state = State.INITIALIZED;
+ this.stringDataSource = null;
+ this.uriDataSource = uri;
+ this.mpi.setDataSource(context, uri);
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Functions identically to android.media.MediaPlayer.setDataSource(String
+ * path) Sets the data source of the track to a file given.
+ */
+ public void setDataSource(String path) throws IllegalArgumentException,
+ IllegalStateException, IOException {
+ lock.lock();
+ try {
+ Log.d(MP_TAG, "In setDataSource(context, " + path + ")");
+ if (invalidServiceConnectionConfiguration()) {
+ setupMpi(this.mpi.mContext);
+ }
+ this.state = State.INITIALIZED;
+ this.stringDataSource = path;
+ this.uriDataSource = null;
+ this.mpi.setDataSource(path);
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Sets whether to use speed adjustment or not. Speed adjustment on is more
+ * computation-intensive than with it off.
+ *
+ * @param enableSpeedAdjustment
+ * Whether speed adjustment should be supported.
+ */
+ public void setEnableSpeedAdjustment(boolean enableSpeedAdjustment) {
+ lock.lock();
+ try {
+ this.enableSpeedAdjustment = enableSpeedAdjustment;
+ this.mpi.setEnableSpeedAdjustment(enableSpeedAdjustment);
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Functions identically to android.media.MediaPlayer.setLooping(boolean
+ * loop) Sets the track to loop infinitely if loop is true, play once if
+ * loop is false
+ */
+ public void setLooping(boolean loop) {
+ lock.lock();
+ try {
+ this.mIsLooping = loop;
+ this.mpi.setLooping(loop);
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Sets the number of steps (in a musical scale) by which playback is
+ * currently shifted. When greater than zero, pitch is shifted up. When less
+ * than zero, pitch is shifted down.
+ *
+ * @param pitchSteps
+ * The number of steps by which to shift playback
+ */
+ public void setPitchStepsAdjustment(float pitchSteps) {
+ lock.lock();
+ try {
+ this.mPitchStepsAdjustment = pitchSteps;
+ this.mpi.setPitchStepsAdjustment(pitchSteps);
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Set the algorithm to use for changing the speed and pitch of audio
+ * See SpeedAdjustmentAlgorithm constants for more details
+ * @param algorithm The algorithm to use.
+ */
+ public void setSpeedAdjustmentAlgorithm(int algorithm) {
+ lock.lock();
+ try {
+ this.speedAdjustmentAlgorithm = algorithm;
+ if (this.mpi != null) {
+ this.mpi.setSpeedAdjustmentAlgorithm(algorithm);
+ }
+ }
+ finally {
+ lock.unlock();
+ }
+ }
+
+ private static float getPitchStepsAdjustment(float pitch) {
+ return (float) (Math.log(pitch) / (2 * Math.log(PITCH_STEP_CONSTANT)));
+ }
+
+ /**
+ * Sets the percentage by which pitch is currently shifted. When greater
+ * than zero, pitch is shifted up. When less than zero, pitch is shifted
+ * down
+ *
+ * @param f
+ * The percentage to shift pitch
+ */
+ public void setPlaybackPitch(float pitch) {
+ lock.lock();
+ try {
+ this.mPitchStepsAdjustment = getPitchStepsAdjustment(pitch);
+ this.mpi.setPlaybackPitch(pitch);
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Set playback speed. 1.0 is normal speed, 2.0 is double speed, and so on.
+ * Speed should never be set to 0 or below.
+ *
+ * @param f
+ * The speed multiplier to use for further playback
+ */
+ public void setPlaybackSpeed(float f) {
+ lock.lock();
+ try {
+ this.mSpeedMultiplier = f;
+ this.mpi.setPlaybackSpeed(f);
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Sets whether to use speed adjustment or not. Speed adjustment on is more
+ * computation-intensive than with it off.
+ *
+ * @param enableSpeedAdjustment
+ * Whether speed adjustment should be supported.
+ */
+ public void setUseService(boolean useService) {
+ lock.lock();
+ try {
+ this.useService = useService;
+ setupMpi(this.mpi.mContext);
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Functions identically to android.media.MediaPlayer.setVolume(float
+ * leftVolume, float rightVolume) Sets the stereo volume
+ */
+ public void setVolume(float leftVolume, float rightVolume) {
+ lock.lock();
+ try {
+ this.mLeftVolume = leftVolume;
+ this.mRightVolume = rightVolume;
+ this.mpi.setVolume(leftVolume, rightVolume);
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Functions identically to android.media.MediaPlayer.setWakeMode(Context
+ * context, int mode) Acquires a wake lock in the context given. You must
+ * request the appropriate permissions in your AndroidManifest.xml file.
+ */
+ public void setWakeMode(Context context, int mode) {
+ lock.lock();
+ try {
+ this.mWakeMode = mode;
+ this.mpi.setWakeMode(context, mode);
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Functions identically to
+ * android.media.MediaPlayer.setOnCompletionListener(OnCompletionListener
+ * listener) Sets a listener to be used when a track completes playing.
+ */
+ public void setOnBufferingUpdateListener(OnBufferingUpdateListener listener) {
+ lock.lock();
+ try {
+ this.onBufferingUpdateListener = listener;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Functions identically to
+ * android.media.MediaPlayer.setOnCompletionListener(OnCompletionListener
+ * listener) Sets a listener to be used when a track completes playing.
+ */
+ public void setOnCompletionListener(OnCompletionListener listener) {
+ lock.lock();
+ try {
+ this.onCompletionListener = listener;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Functions identically to
+ * android.media.MediaPlayer.setOnErrorListener(OnErrorListener listener)
+ * Sets a listener to be used when a track encounters an error.
+ */
+ public void setOnErrorListener(OnErrorListener listener) {
+ lock.lock();
+ try {
+ this.onErrorListener = listener;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Functions identically to
+ * android.media.MediaPlayer.setOnInfoListener(OnInfoListener listener) Sets
+ * a listener to be used when a track has info.
+ */
+ public void setOnInfoListener(OnInfoListener listener) {
+ lock.lock();
+ try {
+ this.onInfoListener = listener;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Sets a listener that will fire when pitch adjustment becomes available or
+ * stops being available
+ */
+ public void setOnPitchAdjustmentAvailableChangedListener(
+ OnPitchAdjustmentAvailableChangedListener listener) {
+ lock.lock();
+ try {
+ this.pitchAdjustmentAvailableChangedListener = listener;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Functions identically to
+ * android.media.MediaPlayer.setOnPreparedListener(OnPreparedListener
+ * listener) Sets a listener to be used when a track finishes preparing.
+ */
+ public void setOnPreparedListener(OnPreparedListener listener) {
+ lock.lock();
+ Log.d(MP_TAG, " ++++++++++++++++++++++++++++++++++++++++++++ setOnPreparedListener");
+ try {
+ this.preparedListener = listener;
+ // For this one, we do not explicitly set the MediaPlayer or the
+ // Service listener. This is because in addition to calling the
+ // listener provided by the client, it's necessary to change
+ // state to PREPARED. See prepareAsync for implementation details
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Functions identically to
+ * android.media.MediaPlayer.setOnSeekCompleteListener
+ * (OnSeekCompleteListener listener) Sets a listener to be used when a track
+ * finishes seeking.
+ */
+ public void setOnSeekCompleteListener(OnSeekCompleteListener listener) {
+ lock.lock();
+ try {
+ this.onSeekCompleteListener = listener;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Sets a listener that will fire when speed adjustment becomes available or
+ * stops being available
+ */
+ public void setOnSpeedAdjustmentAvailableChangedListener(
+ OnSpeedAdjustmentAvailableChangedListener listener) {
+ lock.lock();
+ try {
+ this.speedAdjustmentAvailableChangedListener = listener;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Functions identically to android.media.MediaPlayer.start() Starts a track
+ * playing
+ */
+ public void start() {
+ lock.lock();
+ try {
+ Log.d(MP_TAG, "start() 1149");
+ if (invalidServiceConnectionConfiguration()) {
+ setupMpi(this.mpi.mContext);
+ }
+ this.state = State.STARTED;
+ Log.d(MP_TAG, "start() 1154");
+ this.mpi.start();
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Functions identically to android.media.MediaPlayer.stop() Stops a track
+ * playing and resets its position to the start.
+ */
+ public void stop() {
+ lock.lock();
+ try {
+ if (invalidServiceConnectionConfiguration()) {
+ setupMpi(this.mpi.mContext);
+ }
+ this.state = State.STOPPED;
+ this.mpi.stop();
+ } finally {
+ lock.unlock();
+ }
+ }
+} \ No newline at end of file
diff --git a/src/com/aocate/media/MediaPlayerImpl.java b/src/com/aocate/media/MediaPlayerImpl.java
new file mode 100644
index 000000000..856ab47ce
--- /dev/null
+++ b/src/com/aocate/media/MediaPlayerImpl.java
@@ -0,0 +1,118 @@
+// Copyright 2011, Aocate, Inc.
+//
+// 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.aocate.media;
+
+import java.io.IOException;
+import java.util.concurrent.locks.ReentrantLock;
+
+import android.content.Context;
+import android.net.Uri;
+import android.util.Log;
+
+public abstract class MediaPlayerImpl {
+ private static final String MPI_TAG = "AocateMediaPlayerImpl";
+ protected final MediaPlayer owningMediaPlayer;
+ protected final Context mContext;
+ protected int muteOnPreparedCount = 0;
+ protected int muteOnSeekCount = 0;
+
+ public MediaPlayerImpl(MediaPlayer owningMediaPlayer, Context context) {
+ this.owningMediaPlayer = owningMediaPlayer;
+
+ this.mContext = context;
+ }
+
+ public abstract boolean canSetPitch();
+
+ public abstract boolean canSetSpeed();
+
+ public abstract float getCurrentPitchStepsAdjustment();
+
+ public abstract int getCurrentPosition();
+
+ public abstract float getCurrentSpeedMultiplier();
+
+ public abstract int getDuration();
+
+ public abstract float getMaxSpeedMultiplier();
+
+ public abstract float getMinSpeedMultiplier();
+
+ public abstract boolean isLooping();
+
+ public abstract boolean isPlaying();
+
+ public abstract void pause();
+
+ public abstract void prepare() throws IllegalStateException, IOException;
+
+ public abstract void prepareAsync();
+
+ public abstract void release();
+
+ public abstract void reset();
+
+ public abstract void seekTo(int msec) throws IllegalStateException;
+
+ public abstract void setAudioStreamType(int streamtype);
+
+ public abstract void setDataSource(Context context, Uri uri) throws IllegalArgumentException, IllegalStateException, IOException;
+
+ public abstract void setDataSource(String path) throws IllegalArgumentException, IllegalStateException, IOException;
+
+ public abstract void setEnableSpeedAdjustment(boolean enableSpeedAdjustment);
+
+ public abstract void setLooping(boolean loop);
+
+ public abstract void setPitchStepsAdjustment(float pitchSteps);
+
+ public abstract void setPlaybackPitch(float f);
+
+ public abstract void setPlaybackSpeed(float f);
+
+ public abstract void setSpeedAdjustmentAlgorithm(int algorithm);
+
+ public abstract void setVolume(float leftVolume, float rightVolume);
+
+ public abstract void setWakeMode(Context context, int mode);
+
+ public abstract void start();
+
+ public abstract void stop();
+
+ protected ReentrantLock lockMuteOnPreparedCount = new ReentrantLock();
+ public void muteNextOnPrepare() {
+ lockMuteOnPreparedCount.lock();
+ Log.d(MPI_TAG, "muteNextOnPrepare()");
+ try {
+ this.muteOnPreparedCount++;
+ }
+ finally {
+ lockMuteOnPreparedCount.unlock();
+ }
+ }
+
+ protected ReentrantLock lockMuteOnSeekCount = new ReentrantLock();
+ public void muteNextSeek() {
+ lockMuteOnSeekCount.lock();
+ Log.d(MPI_TAG, "muteNextOnSeek()");
+ try {
+ this.muteOnSeekCount++;
+ }
+ finally {
+ lockMuteOnSeekCount.unlock();
+ }
+ }
+}
diff --git a/src/com/aocate/media/ServiceBackedMediaPlayer.java b/src/com/aocate/media/ServiceBackedMediaPlayer.java
new file mode 100644
index 000000000..ef4572d33
--- /dev/null
+++ b/src/com/aocate/media/ServiceBackedMediaPlayer.java
@@ -0,0 +1,1170 @@
+// Copyright 2011, Aocate, Inc.
+//
+// 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.aocate.media;
+
+import java.io.IOException;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.media.AudioManager;
+import android.net.Uri;
+import android.os.IBinder;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.os.PowerManager.WakeLock;
+import android.util.Log;
+
+import com.aocate.media.MediaPlayer.State;
+import com.aocate.presto.service.IDeathCallback_0_8;
+import com.aocate.presto.service.IOnBufferingUpdateListenerCallback_0_8;
+import com.aocate.presto.service.IOnCompletionListenerCallback_0_8;
+import com.aocate.presto.service.IOnErrorListenerCallback_0_8;
+import com.aocate.presto.service.IOnInfoListenerCallback_0_8;
+import com.aocate.presto.service.IOnPitchAdjustmentAvailableChangedListenerCallback_0_8;
+import com.aocate.presto.service.IOnPreparedListenerCallback_0_8;
+import com.aocate.presto.service.IOnSeekCompleteListenerCallback_0_8;
+import com.aocate.presto.service.IOnSpeedAdjustmentAvailableChangedListenerCallback_0_8;
+import com.aocate.presto.service.IPlayMedia_0_8;
+
+/**
+ * Class for connecting to remote speed-altering, media playing Service
+ * Note that there is unusually high coupling between MediaPlayer and this
+ * class. This is an unfortunate compromise, since the alternative was to
+ * track state in two different places in this code (plus the internal state
+ * of the remote media player).
+ * @author aocate
+ *
+ */
+public class ServiceBackedMediaPlayer extends MediaPlayerImpl {
+ static final String INTENT_NAME = "com.aocate.intent.PLAY_AUDIO_ADJUST_SPEED_0_8";
+
+ private static final String SBMP_TAG = "AocateServiceBackedMediaPlayer";
+
+ private ServiceConnection mPlayMediaServiceConnection = null;
+ protected IPlayMedia_0_8 pmInterface = null;
+ private Intent playMediaServiceIntent = null;
+ // In some cases, we're going to have to replace the
+ // android.media.MediaPlayer on the fly, and we don't want to touch the
+ // wrong media player.
+
+ private long sessionId = 0;
+ private boolean isErroring = false;
+ private int mAudioStreamType = AudioManager.STREAM_MUSIC;
+
+ private WakeLock mWakeLock = null;
+
+ // So here's the major problem
+ // Sometimes the service won't exist or won't be connected,
+ // so start with an android.media.MediaPlayer, and when
+ // the service is connected, use that from then on
+ public ServiceBackedMediaPlayer(MediaPlayer owningMediaPlayer, final Context context, final ServiceConnection serviceConnection) {
+ super(owningMediaPlayer, context);
+ Log.d(SBMP_TAG, "Instantiating ServiceBackedMediaPlayer 87");
+ this.playMediaServiceIntent =
+ new Intent(INTENT_NAME);
+ this.mPlayMediaServiceConnection = new ServiceConnection() {
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ IPlayMedia_0_8 tmpPlayMediaInterface = IPlayMedia_0_8.Stub.asInterface((IBinder) service);
+
+ Log.d(SBMP_TAG, "Setting up pmInterface 94");
+ if (ServiceBackedMediaPlayer.this.sessionId == 0) {
+ try {
+ // The IDeathCallback isn't a conventional callback.
+ // It exists so that if the client ceases to exist,
+ // the Service becomes aware of that and can shut
+ // down whatever it needs to shut down
+ ServiceBackedMediaPlayer.this.sessionId = tmpPlayMediaInterface.startSession(new IDeathCallback_0_8.Stub() {
+ });
+ // This is really bad if this fails
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+
+ Log.d(SBMP_TAG, "Assigning pmInterface");
+
+ ServiceBackedMediaPlayer.this.setOnBufferingUpdateCallback(tmpPlayMediaInterface);
+ ServiceBackedMediaPlayer.this.setOnCompletionCallback(tmpPlayMediaInterface);
+ ServiceBackedMediaPlayer.this.setOnErrorCallback(tmpPlayMediaInterface);
+ ServiceBackedMediaPlayer.this.setOnInfoCallback(tmpPlayMediaInterface);
+ ServiceBackedMediaPlayer.this.setOnPitchAdjustmentAvailableChangedListener(tmpPlayMediaInterface);
+ ServiceBackedMediaPlayer.this.setOnPreparedCallback(tmpPlayMediaInterface);
+ ServiceBackedMediaPlayer.this.setOnSeekCompleteCallback(tmpPlayMediaInterface);
+ ServiceBackedMediaPlayer.this.setOnSpeedAdjustmentAvailableChangedCallback(tmpPlayMediaInterface);
+
+ // In order to avoid race conditions from the sessionId or listener not being assigned
+ pmInterface = tmpPlayMediaInterface;
+
+ Log.d(SBMP_TAG, "Invoking onServiceConnected");
+ serviceConnection.onServiceConnected(name, service);
+ }
+
+ public void onServiceDisconnected(ComponentName name) {
+ Log.d(SBMP_TAG, "onServiceDisconnected 114");
+
+ pmInterface = null;
+
+ sessionId = 0;
+
+ serviceConnection.onServiceDisconnected(name);
+ }
+ };
+
+ Log.d(SBMP_TAG, "Connecting PlayMediaService 124");
+ if (!ConnectPlayMediaService()) {
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+
+ private boolean ConnectPlayMediaService() {
+ Log.d(SBMP_TAG, "ConnectPlayMediaService()");
+
+ if (MediaPlayer.isIntentAvailable(mContext, INTENT_NAME)) {
+ Log.d(SBMP_TAG, INTENT_NAME + " is available");
+ if (pmInterface == null) {
+ try {
+ Log.d(SBMP_TAG, "Binding service");
+ return mContext.bindService(playMediaServiceIntent, mPlayMediaServiceConnection, Context.BIND_AUTO_CREATE);
+ } catch (Exception e) {
+ return false;
+ }
+ } else {
+ Log.d(SBMP_TAG, "Service already bound");
+ return true;
+ }
+ }
+ else {
+ Log.d(SBMP_TAG, INTENT_NAME + " is not available");
+ return false;
+ }
+ }
+
+ /**
+ * Returns true if pitch can be changed at this moment
+ * @return True if pitch can be changed
+ */
+ @Override
+ public boolean canSetPitch() {
+ Log.d(SBMP_TAG, "canSetPitch() 155");
+
+ if (pmInterface == null) {
+ if (!ConnectPlayMediaService()) {
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+ if (pmInterface != null) {
+ // Can't set pitch if the service isn't connected
+ try {
+ return pmInterface.canSetPitch(ServiceBackedMediaPlayer.this.sessionId);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if speed can be changed at this moment
+ * @return True if speed can be changed
+ */
+ @Override
+ public boolean canSetSpeed() {
+ Log.d(SBMP_TAG, "canSetSpeed() 180");
+ if (pmInterface == null) {
+ if (!ConnectPlayMediaService()) {
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+ if (pmInterface != null) {
+ // Can't set speed if the service isn't connected
+ try {
+ return pmInterface.canSetSpeed(ServiceBackedMediaPlayer.this.sessionId);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+ return false;
+ }
+
+ void error(int what, int extra) {
+ owningMediaPlayer.lock.lock();
+ Log.e(SBMP_TAG, "error(" + what + ", " + extra + ")");
+ try {
+ if (!this.isErroring) {
+ this.isErroring = true;
+ owningMediaPlayer.state = State.ERROR;
+ if (owningMediaPlayer.onErrorListener != null) {
+ if (owningMediaPlayer.onErrorListener.onError(owningMediaPlayer, what, extra)) {
+ return;
+ }
+ }
+ if (owningMediaPlayer.onCompletionListener != null) {
+ owningMediaPlayer.onCompletionListener.onCompletion(owningMediaPlayer);
+ }
+ }
+ }
+ finally {
+ this.isErroring = false;
+ owningMediaPlayer.lock.unlock();
+ }
+ }
+
+ protected void finalize() throws Throwable {
+ owningMediaPlayer.lock.lock();
+ try {
+ Log.d(SBMP_TAG, "finalize() 224");
+ this.release();
+ }
+ finally {
+ owningMediaPlayer.lock.unlock();
+ }
+ }
+
+ /**
+ * Returns the number of steps (in a musical scale) by which playback is
+ * currently shifted. When greater than zero, pitch is shifted up.
+ * When less than zero, pitch is shifted down.
+ * @return The number of steps pitch is currently shifted by
+ */
+ @Override
+ public float getCurrentPitchStepsAdjustment() {
+ Log.d(SBMP_TAG, "getCurrentPitchStepsAdjustment() 240");
+ if (pmInterface == null) {
+ if (!ConnectPlayMediaService()) {
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+ if (pmInterface != null) {
+ // Can't set pitch if the service isn't connected
+ try {
+ return pmInterface.getCurrentPitchStepsAdjustment(
+ ServiceBackedMediaPlayer.this.sessionId);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+ return 0f;
+ }
+
+ /**
+ * Functions identically to android.media.MediaPlayer.getCurrentPosition()
+ * @return Current position (in milliseconds)
+ */
+ @Override
+ public int getCurrentPosition() {
+ if (pmInterface == null) {
+ if (!ConnectPlayMediaService()) {
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+ try {
+ return pmInterface.getCurrentPosition(
+ ServiceBackedMediaPlayer.this.sessionId);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ return 0;
+ }
+
+ /**
+ * Returns the current speed multiplier. Defaults to 1.0 (normal speed)
+ * @return The current speed multiplier
+ */
+ @Override
+ public float getCurrentSpeedMultiplier() {
+ Log.d(SBMP_TAG, "getCurrentSpeedMultiplier() 286");
+ if (pmInterface == null) {
+ if (!ConnectPlayMediaService()) {
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+ if (pmInterface != null) {
+ // Can't set speed if the service isn't connected
+ try {
+ return pmInterface.getCurrentSpeedMultiplier(
+ ServiceBackedMediaPlayer.this.sessionId);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+ return 1;
+ }
+
+ /**
+ * Functions identically to android.media.MediaPlayer.getDuration()
+ * @return Length of the track (in milliseconds)
+ */
+ @Override
+ public int getDuration() {
+ Log.d(SBMP_TAG, "getDuration() 311");
+ if (pmInterface == null) {
+ if (!ConnectPlayMediaService()) {
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+ try {
+ return pmInterface.getDuration(ServiceBackedMediaPlayer.this.sessionId);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ return 0;
+ }
+
+ /**
+ * Get the maximum value that can be passed to setPlaybackSpeed
+ * @return The maximum speed multiplier
+ */
+ @Override
+ public float getMaxSpeedMultiplier() {
+ Log.d(SBMP_TAG, "getMaxSpeedMultiplier() 332");
+ if (pmInterface == null) {
+ if (!ConnectPlayMediaService()) {
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+ if (pmInterface != null) {
+ // Can't set speed if the Service isn't connected
+ try {
+ return pmInterface.getMaxSpeedMultiplier(
+ ServiceBackedMediaPlayer.this.sessionId);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+ return 1f;
+ }
+
+ /**
+ * Get the minimum value that can be passed to setPlaybackSpeed
+ * @return The minimum speed multiplier
+ */
+ @Override
+ public float getMinSpeedMultiplier() {
+ Log.d(SBMP_TAG, "getMinSpeedMultiplier() 357");
+ if (pmInterface == null) {
+ if (!ConnectPlayMediaService()) {
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+ if (pmInterface != null) {
+ // Can't set speed if the Service isn't connected
+ try {
+ return pmInterface.getMinSpeedMultiplier(
+ ServiceBackedMediaPlayer.this.sessionId);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+ return 1f;
+ }
+
+ public int getServiceVersionCode() {
+ Log.d(SBMP_TAG, "getVersionCode");
+ if (pmInterface == null) {
+ if (!ConnectPlayMediaService()) {
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+ try {
+ return pmInterface.getVersionCode();
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ return 0;
+ }
+
+ public String getServiceVersionName() {
+ Log.d(SBMP_TAG, "getVersionName");
+ if (pmInterface == null) {
+ if (!ConnectPlayMediaService()) {
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+ try {
+ return pmInterface.getVersionName();
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ return "";
+ }
+
+ public boolean isConnected() {
+ return (pmInterface != null);
+ }
+
+ /**
+ * Functions identically to android.media.MediaPlayer.isLooping()
+ * @return True if the track is looping
+ */
+ @Override
+ public boolean isLooping() {
+ Log.d(SBMP_TAG, "isLooping() 382");
+ if (pmInterface == null) {
+ if (!ConnectPlayMediaService()) {
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+ try {
+ return pmInterface.isLooping(ServiceBackedMediaPlayer.this.sessionId);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ return false;
+ }
+
+ /**
+ * Functions identically to android.media.MediaPlayer.isPlaying()
+ * @return True if the track is playing
+ */
+ @Override
+ public boolean isPlaying() {
+ if (pmInterface == null) {
+ if (!ConnectPlayMediaService()) {
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+ if (pmInterface != null) {
+ try {
+ return pmInterface.isPlaying(ServiceBackedMediaPlayer.this.sessionId);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Functions identically to android.media.MediaPlayer.pause()
+ * Pauses the track
+ */
+ @Override
+ public void pause() {
+ Log.d(SBMP_TAG, "pause() 424");
+ if (pmInterface == null) {
+ if (!ConnectPlayMediaService()) {
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+ try {
+ pmInterface.pause(ServiceBackedMediaPlayer.this.sessionId);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+
+ /**
+ * Functions identically to android.media.MediaPlayer.prepare()
+ * Prepares the track. This or prepareAsync must be called before start()
+ */
+ @Override
+ public void prepare() throws IllegalStateException, IOException {
+ Log.d(SBMP_TAG, "prepare() 444");
+ Log.d(SBMP_TAG, "onPreparedCallback is: " + ((this.mOnPreparedCallback == null) ? "null" : "non-null"));
+ if (pmInterface == null) {
+ Log.d(SBMP_TAG, "prepare: pmInterface is null");
+ if (!ConnectPlayMediaService()) {
+ Log.d(SBMP_TAG, "prepare: Failed to connect play media service");
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+ if (pmInterface != null) {
+ Log.d(SBMP_TAG, "prepare: pmInterface isn't null");
+ try {
+ Log.d(SBMP_TAG, "prepare: Remote invoke pmInterface.prepare(" + ServiceBackedMediaPlayer.this.sessionId + ")");
+ pmInterface.prepare(ServiceBackedMediaPlayer.this.sessionId);
+ Log.d(SBMP_TAG, "prepare: prepared");
+ } catch (RemoteException e) {
+ Log.d(SBMP_TAG, "prepare: RemoteException");
+ e.printStackTrace();
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+ Log.d(SBMP_TAG, "Done with prepare()");
+ }
+
+ /**
+ * Functions identically to android.media.MediaPlayer.prepareAsync()
+ * Prepares the track. This or prepare must be called before start()
+ */
+ @Override
+ public void prepareAsync() {
+ Log.d(SBMP_TAG, "prepareAsync() 469");
+ if (pmInterface == null) {
+ if (!ConnectPlayMediaService()) {
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+ try {
+ pmInterface.prepareAsync(ServiceBackedMediaPlayer.this.sessionId);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+
+ /**
+ * Functions identically to android.media.MediaPlayer.release()
+ * Releases the underlying resources used by the media player.
+ */
+ @Override
+ public void release() {
+ Log.d(SBMP_TAG, "release() 492");
+ if (pmInterface == null) {
+ if (!ConnectPlayMediaService()) {
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+ if (pmInterface != null) {
+ Log.d(SBMP_TAG, "release() 500");
+ try {
+ pmInterface.release(ServiceBackedMediaPlayer.this.sessionId);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ mContext.unbindService(this.mPlayMediaServiceConnection);
+ // Don't try to keep awake (if we were)
+ this.setWakeMode(mContext, 0);
+ pmInterface = null;
+ this.sessionId = 0;
+ }
+
+ if ((this.mWakeLock != null) && this.mWakeLock.isHeld()) {
+ Log.d(SBMP_TAG, "Releasing wakelock");
+ this.mWakeLock.release();
+ }
+ }
+
+ /**
+ * Functions identically to android.media.MediaPlayer.reset()
+ * Resets the track to idle state
+ */
+ @Override
+ public void reset() {
+ Log.d(SBMP_TAG, "reset() 523");
+ if (pmInterface == null) {
+ if (!ConnectPlayMediaService()) {
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+ try {
+ pmInterface.reset(ServiceBackedMediaPlayer.this.sessionId);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+
+ /**
+ * Functions identically to android.media.MediaPlayer.seekTo(int msec)
+ * Seeks to msec in the track
+ */
+ @Override
+ public void seekTo(int msec) throws IllegalStateException {
+ Log.d(SBMP_TAG, "seekTo(" + msec + ")");
+ if (pmInterface == null) {
+ if (!ConnectPlayMediaService()) {
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+ try {
+ pmInterface.seekTo(ServiceBackedMediaPlayer.this.sessionId, msec);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+
+ /**
+ * Functions identically to android.media.MediaPlayer.setAudioStreamType(int streamtype)
+ * Sets the audio stream type.
+ */
+ @Override
+ public void setAudioStreamType(int streamtype) {
+ Log.d(SBMP_TAG, "setAudioStreamType(" + streamtype + ")");
+ if (pmInterface == null) {
+ if (!ConnectPlayMediaService()) {
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+ try {
+ pmInterface.setAudioStreamType(
+ ServiceBackedMediaPlayer.this.sessionId,
+ this.mAudioStreamType);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+
+
+ /**
+ * Functions identically to android.media.MediaPlayer.setDataSource(Context context, Uri uri)
+ * Sets uri as data source in the context given
+ */
+ @Override
+ public void setDataSource(Context context, Uri uri) throws IllegalArgumentException, IllegalStateException, IOException {
+ Log.d(SBMP_TAG, "setDataSource(context, uri)");
+ if (pmInterface == null) {
+ if (!ConnectPlayMediaService()) {
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+ try {
+ pmInterface.setDataSourceUri(
+ ServiceBackedMediaPlayer.this.sessionId,
+ uri);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+
+ /**
+ * Functions identically to android.media.MediaPlayer.setDataSource(String path)
+ * Sets the data source of the track to a file given.
+ */
+ @Override
+ public void setDataSource(String path) throws IllegalArgumentException, IllegalStateException, IOException {
+ Log.d(SBMP_TAG, "setDataSource(path)");
+ if (pmInterface == null) {
+ if (!ConnectPlayMediaService()) {
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+ if (pmInterface == null) {
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ else {
+ try {
+ pmInterface.setDataSourceString(
+ ServiceBackedMediaPlayer.this.sessionId,
+ path);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+ }
+
+ /**
+ * Sets whether to use speed adjustment or not. Speed adjustment on is
+ * more computation-intensive than with it off.
+ * @param enableSpeedAdjustment Whether speed adjustment should be supported.
+ */
+ @Override
+ public void setEnableSpeedAdjustment(boolean enableSpeedAdjustment) {
+ // TODO: This has no business being here, I think
+ owningMediaPlayer.lock.lock();
+ Log.d(SBMP_TAG, "setEnableSpeedAdjustment(enableSpeedAdjustment)");
+ try {
+ if (pmInterface == null) {
+ if (!ConnectPlayMediaService()) {
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+ if (pmInterface != null) {
+ // Can't set speed if the Service isn't connected
+ try {
+ pmInterface.setEnableSpeedAdjustment(
+ ServiceBackedMediaPlayer.this.sessionId,
+ enableSpeedAdjustment);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+ }
+ finally {
+ owningMediaPlayer.lock.unlock();
+ }
+ }
+
+
+ /**
+ * Functions identically to android.media.MediaPlayer.setLooping(boolean loop)
+ * Sets the track to loop infinitely if loop is true, play once if loop is false
+ */
+ @Override
+ public void setLooping(boolean loop) {
+ Log.d(SBMP_TAG, "setLooping(" + loop + ")");
+ if (pmInterface == null) {
+ if (!ConnectPlayMediaService()) {
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+ try {
+ pmInterface.setLooping(ServiceBackedMediaPlayer.this.sessionId, loop);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+
+ /**
+ * Sets the number of steps (in a musical scale) by which playback is
+ * currently shifted. When greater than zero, pitch is shifted up.
+ * When less than zero, pitch is shifted down.
+ *
+ * @param pitchSteps The number of steps by which to shift playback
+ */
+ @Override
+ public void setPitchStepsAdjustment(float pitchSteps) {
+ Log.d(SBMP_TAG, "setPitchStepsAdjustment(" + pitchSteps + ")");
+ if (pmInterface == null) {
+ if (!ConnectPlayMediaService()) {
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+ if (pmInterface != null) {
+ // Can't set speed if the Service isn't connected
+ try {
+ pmInterface.setPitchStepsAdjustment(
+ ServiceBackedMediaPlayer.this.sessionId,
+ pitchSteps);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+ }
+
+ /**
+ * Sets the percentage by which pitch is currently shifted. When
+ * greater than zero, pitch is shifted up. When less than zero, pitch
+ * is shifted down
+ * @param f The percentage to shift pitch
+ */
+ @Override
+ public void setPlaybackPitch(float f) {
+ Log.d(SBMP_TAG, "setPlaybackPitch(" + f + ")");
+ if (pmInterface == null) {
+ if (!ConnectPlayMediaService()) {
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+ if (pmInterface != null) {
+ // Can't set speed if the Service isn't connected
+ try {
+ pmInterface.setPlaybackPitch(
+ ServiceBackedMediaPlayer.this.sessionId,
+ f);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+ }
+
+ /**
+ * Set playback speed. 1.0 is normal speed, 2.0 is double speed, and so
+ * on. Speed should never be set to 0 or below.
+ * @param f The speed multiplier to use for further playback
+ */
+ @Override
+ public void setPlaybackSpeed(float f) {
+ Log.d(SBMP_TAG, "setPlaybackSpeed(" + f + ")");
+ if (pmInterface == null) {
+ if (!ConnectPlayMediaService()) {
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+ if (pmInterface != null) {
+ // Can't set speed if the Service isn't connected
+ try {
+ pmInterface.setPlaybackSpeed(
+ ServiceBackedMediaPlayer.this.sessionId,
+ f);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+ }
+
+ @Override
+ public void setSpeedAdjustmentAlgorithm(int algorithm) {
+ if (pmInterface == null) {
+ if (!ConnectPlayMediaService()) {
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+ try {
+ pmInterface.setSpeedAdjustmentAlgorithm(
+ ServiceBackedMediaPlayer.this.sessionId,
+ algorithm);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+
+ /**
+ * Functions identically to android.media.MediaPlayer.setVolume(float leftVolume, float rightVolume)
+ * Sets the stereo volume
+ */
+ @Override
+ public void setVolume(float leftVolume, float rightVolume) {
+ Log.d(SBMP_TAG, "setVolume(" + leftVolume + ", " + rightVolume + ")");
+ if (pmInterface == null) {
+ if (!ConnectPlayMediaService()) {
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+ try {
+ pmInterface.setVolume(
+ ServiceBackedMediaPlayer.this.sessionId,
+ leftVolume,
+ rightVolume);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+
+ /**
+ * Functions identically to android.media.MediaPlayer.setWakeMode(Context context, int mode)
+ * Acquires a wake lock in the context given. You must request the appropriate permissions
+ * in your AndroidManifest.xml file.
+ */
+ @Override
+ // This does not just call .setWakeMode() in the Service because doing so
+ // would add a permission requirement to the Service. Do it here, and it's
+ // the client app's responsibility to request that permission
+ public void setWakeMode(Context context, int mode) {
+ Log.d(SBMP_TAG, "setWakeMode(context, " + mode + ")");
+ if ((this.mWakeLock != null)
+ && (this.mWakeLock.isHeld())) {
+ this.mWakeLock.release();
+ }
+ if (mode != 0) {
+ if (this.mWakeLock == null) {
+ PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+ // Since mode can't be changed on the fly, we have to allocate a new one
+ this.mWakeLock = pm.newWakeLock(mode, this.getClass().getName());
+ }
+
+ this.mWakeLock.acquire();
+ }
+ }
+
+ private IOnBufferingUpdateListenerCallback_0_8.Stub mOnBufferingUpdateCallback = null;
+ private void setOnBufferingUpdateCallback(IPlayMedia_0_8 iface) {
+ try {
+ if (this.mOnBufferingUpdateCallback == null) {
+ mOnBufferingUpdateCallback = new IOnBufferingUpdateListenerCallback_0_8.Stub() {
+ public void onBufferingUpdate(int percent)
+ throws RemoteException {
+ owningMediaPlayer.lock.lock();
+ try {
+ if ((owningMediaPlayer.onBufferingUpdateListener != null)
+ && (owningMediaPlayer.mpi == ServiceBackedMediaPlayer.this)) {
+ owningMediaPlayer.onBufferingUpdateListener.onBufferingUpdate(owningMediaPlayer, percent);
+ }
+ }
+ finally {
+ owningMediaPlayer.lock.unlock();
+ }
+ }
+ };
+ }
+ iface.registerOnBufferingUpdateCallback(
+ ServiceBackedMediaPlayer.this.sessionId,
+ mOnBufferingUpdateCallback);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+
+ private IOnCompletionListenerCallback_0_8.Stub mOnCompletionCallback = null;
+ private void setOnCompletionCallback(IPlayMedia_0_8 iface) {
+ try {
+ if (this.mOnCompletionCallback == null) {
+ this.mOnCompletionCallback = new IOnCompletionListenerCallback_0_8.Stub() {
+ public void onCompletion() throws RemoteException {
+ owningMediaPlayer.lock.lock();
+ Log.d(SBMP_TAG, "onCompletionListener being called");
+ try {
+ if (owningMediaPlayer.onCompletionListener != null) {
+ owningMediaPlayer.onCompletionListener.onCompletion(owningMediaPlayer);
+ }
+ }
+ finally {
+ owningMediaPlayer.lock.unlock();
+ }
+ }
+ };
+ }
+ iface.registerOnCompletionCallback(
+ ServiceBackedMediaPlayer.this.sessionId,
+ this.mOnCompletionCallback);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+
+ private IOnErrorListenerCallback_0_8.Stub mOnErrorCallback = null;
+ private void setOnErrorCallback(IPlayMedia_0_8 iface) {
+ try {
+ if (this.mOnErrorCallback == null) {
+ this.mOnErrorCallback = new IOnErrorListenerCallback_0_8.Stub() {
+ public boolean onError(int what, int extra) throws RemoteException {
+ owningMediaPlayer.lock.lock();
+ try {
+ if (owningMediaPlayer.onErrorListener != null) {
+ return owningMediaPlayer.onErrorListener.onError(owningMediaPlayer, what, extra);
+ }
+ return false;
+ }
+ finally {
+ owningMediaPlayer.lock.unlock();
+ }
+ }
+ };
+ }
+ iface.registerOnErrorCallback(
+ ServiceBackedMediaPlayer.this.sessionId,
+ this.mOnErrorCallback);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+
+ private IOnInfoListenerCallback_0_8.Stub mOnInfoCallback = null;
+ private void setOnInfoCallback(IPlayMedia_0_8 iface) {
+ try {
+ if (this.mOnInfoCallback == null) {
+ this.mOnInfoCallback = new IOnInfoListenerCallback_0_8.Stub() {
+ public boolean onInfo(int what, int extra) throws RemoteException {
+ owningMediaPlayer.lock.lock();
+ try {
+ if ((owningMediaPlayer.onInfoListener != null)
+ && (owningMediaPlayer.mpi == ServiceBackedMediaPlayer.this)) {
+ return owningMediaPlayer.onInfoListener.onInfo(owningMediaPlayer, what, extra);
+ }
+ }
+ finally {
+ owningMediaPlayer.lock.unlock();
+ }
+ return false;
+ }
+ };
+ }
+ iface.registerOnInfoCallback(
+ ServiceBackedMediaPlayer.this.sessionId,
+ this.mOnInfoCallback);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+
+ private IOnPitchAdjustmentAvailableChangedListenerCallback_0_8.Stub mOnPitchAdjustmentAvailableChangedCallback = null;
+ private void setOnPitchAdjustmentAvailableChangedListener(IPlayMedia_0_8 iface) {
+ try {
+ if (this.mOnPitchAdjustmentAvailableChangedCallback == null) {
+ this.mOnPitchAdjustmentAvailableChangedCallback = new IOnPitchAdjustmentAvailableChangedListenerCallback_0_8.Stub() {
+ public void onPitchAdjustmentAvailableChanged(
+ boolean pitchAdjustmentAvailable)
+ throws RemoteException {
+ owningMediaPlayer.lock.lock();
+ try {
+ if (owningMediaPlayer.onPitchAdjustmentAvailableChangedListener != null) {
+ owningMediaPlayer.onPitchAdjustmentAvailableChangedListener.onPitchAdjustmentAvailableChanged(owningMediaPlayer, pitchAdjustmentAvailable);
+ }
+ }
+ finally {
+ owningMediaPlayer.lock.unlock();
+ }
+ }
+ };
+ }
+ iface.registerOnPitchAdjustmentAvailableChangedCallback(
+ ServiceBackedMediaPlayer.this.sessionId,
+ this.mOnPitchAdjustmentAvailableChangedCallback);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+
+ private IOnPreparedListenerCallback_0_8.Stub mOnPreparedCallback = null;
+ private void setOnPreparedCallback(IPlayMedia_0_8 iface) {
+ try {
+ if (this.mOnPreparedCallback == null) {
+ this.mOnPreparedCallback = new IOnPreparedListenerCallback_0_8.Stub() {
+ public void onPrepared() throws RemoteException {
+ owningMediaPlayer.lock.lock();
+ Log.d(SBMP_TAG, "setOnPreparedCallback.mOnPreparedCallback.onPrepared 1050");
+ try {
+ Log.d(SBMP_TAG, "owningMediaPlayer.onPreparedListener is " + ((owningMediaPlayer.onPreparedListener == null) ? "null" : "non-null"));
+ Log.d(SBMP_TAG, "owningMediaPlayer.mpi is " + ((owningMediaPlayer.mpi == ServiceBackedMediaPlayer.this) ? "this" : "not this"));
+ ServiceBackedMediaPlayer.this.lockMuteOnPreparedCount.lock();
+ try {
+ if (ServiceBackedMediaPlayer.this.muteOnPreparedCount > 0) {
+ ServiceBackedMediaPlayer.this.muteOnPreparedCount--;
+ }
+ else {
+ ServiceBackedMediaPlayer.this.muteOnPreparedCount = 0;
+ if (ServiceBackedMediaPlayer.this.owningMediaPlayer.onPreparedListener != null) {
+ owningMediaPlayer.onPreparedListener.onPrepared(owningMediaPlayer);
+ }
+ }
+ }
+ finally {
+ ServiceBackedMediaPlayer.this.lockMuteOnPreparedCount.unlock();
+ }
+ }
+ finally {
+ owningMediaPlayer.lock.unlock();
+ }
+ }
+ };
+ }
+ iface.registerOnPreparedCallback(
+ ServiceBackedMediaPlayer.this.sessionId,
+ this.mOnPreparedCallback);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+
+ private IOnSeekCompleteListenerCallback_0_8.Stub mOnSeekCompleteCallback = null;
+ private void setOnSeekCompleteCallback(IPlayMedia_0_8 iface) {
+ try {
+ if (this.mOnSeekCompleteCallback == null) {
+ this.mOnSeekCompleteCallback = new IOnSeekCompleteListenerCallback_0_8.Stub() {
+ public void onSeekComplete() throws RemoteException {
+ Log.d(SBMP_TAG, "onSeekComplete() 941");
+ owningMediaPlayer.lock.lock();
+ try {
+ if (ServiceBackedMediaPlayer.this.muteOnSeekCount > 0) {
+ Log.d(SBMP_TAG, "The next " + ServiceBackedMediaPlayer.this.muteOnSeekCount + " seek events are muted (counting this one)");
+ ServiceBackedMediaPlayer.this.muteOnSeekCount--;
+ }
+ else {
+ ServiceBackedMediaPlayer.this.muteOnSeekCount = 0;
+ Log.d(SBMP_TAG, "Attempting to invoke next seek event");
+ if (ServiceBackedMediaPlayer.this.owningMediaPlayer.onSeekCompleteListener != null) {
+ Log.d(SBMP_TAG, "Invoking onSeekComplete");
+ owningMediaPlayer.onSeekCompleteListener.onSeekComplete(owningMediaPlayer);
+ }
+ }
+ }
+ finally {
+ owningMediaPlayer.lock.unlock();
+ }
+ }
+ };
+ }
+ iface.registerOnSeekCompleteCallback(
+ ServiceBackedMediaPlayer.this.sessionId,
+ this.mOnSeekCompleteCallback);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+
+ private IOnSpeedAdjustmentAvailableChangedListenerCallback_0_8.Stub mOnSpeedAdjustmentAvailableChangedCallback = null;
+ private void setOnSpeedAdjustmentAvailableChangedCallback(IPlayMedia_0_8 iface) {
+ try {
+ Log.d(SBMP_TAG, "Setting the service of on speed adjustment available changed");
+ if (this.mOnSpeedAdjustmentAvailableChangedCallback == null) {
+ this.mOnSpeedAdjustmentAvailableChangedCallback = new IOnSpeedAdjustmentAvailableChangedListenerCallback_0_8.Stub() {
+ public void onSpeedAdjustmentAvailableChanged(
+ boolean speedAdjustmentAvailable)
+ throws RemoteException {
+ owningMediaPlayer.lock.lock();
+ try {
+ if (owningMediaPlayer.onSpeedAdjustmentAvailableChangedListener != null) {
+ owningMediaPlayer.onSpeedAdjustmentAvailableChangedListener.onSpeedAdjustmentAvailableChanged(owningMediaPlayer, speedAdjustmentAvailable);
+ }
+ }
+ finally {
+ owningMediaPlayer.lock.unlock();
+ }
+ }
+ };
+ }
+ iface.registerOnSpeedAdjustmentAvailableChangedCallback(
+ ServiceBackedMediaPlayer.this.sessionId,
+ this.mOnSpeedAdjustmentAvailableChangedCallback);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+
+ /**
+ * Functions identically to android.media.MediaPlayer.start()
+ * Starts a track playing
+ */
+ @Override
+ public void start() {
+ Log.d(SBMP_TAG, "start()");
+ if (pmInterface == null) {
+ if (!ConnectPlayMediaService()) {
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+ try {
+ pmInterface.start(ServiceBackedMediaPlayer.this.sessionId);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+
+ /**
+ * Functions identically to android.media.MediaPlayer.stop()
+ * Stops a track playing and resets its position to the start.
+ */
+ @Override
+ public void stop() {
+ Log.d(SBMP_TAG, "stop()");
+ if (pmInterface == null) {
+ if (!ConnectPlayMediaService()) {
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+ try {
+ pmInterface.stop(ServiceBackedMediaPlayer.this.sessionId);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+} \ No newline at end of file
diff --git a/src/com/aocate/media/SpeedAdjustmentAlgorithm.java b/src/com/aocate/media/SpeedAdjustmentAlgorithm.java
new file mode 100644
index 000000000..d337a0452
--- /dev/null
+++ b/src/com/aocate/media/SpeedAdjustmentAlgorithm.java
@@ -0,0 +1,31 @@
+// Copyright 2011, Aocate, Inc.
+//
+// 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.aocate.media;
+
+public class SpeedAdjustmentAlgorithm {
+ /**
+ * Use this to use the user-specified algorithm
+ */
+ public static int DEFAULT = 0;
+
+ /**
+ * Better for voice audio
+ */
+ public static int SONIC = 1;
+ /**
+ * Better for music audio
+ */
+ public static int WSOLA = 2;
+}
diff --git a/src/com/aocate/presto/service/IDeathCallback_0_8.aidl b/src/com/aocate/presto/service/IDeathCallback_0_8.aidl
new file mode 100644
index 000000000..6bdc76801
--- /dev/null
+++ b/src/com/aocate/presto/service/IDeathCallback_0_8.aidl
@@ -0,0 +1,18 @@
+// Copyright 2011, Aocate, Inc.
+//
+// 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.aocate.presto.service;
+
+oneway interface IDeathCallback_0_8 {
+} \ No newline at end of file
diff --git a/src/com/aocate/presto/service/IOnBufferingUpdateListenerCallback_0_8.aidl b/src/com/aocate/presto/service/IOnBufferingUpdateListenerCallback_0_8.aidl
new file mode 100644
index 000000000..7357e402e
--- /dev/null
+++ b/src/com/aocate/presto/service/IOnBufferingUpdateListenerCallback_0_8.aidl
@@ -0,0 +1,19 @@
+// Copyright 2011, Aocate, Inc.
+//
+// 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.aocate.presto.service;
+
+interface IOnBufferingUpdateListenerCallback_0_8 {
+ void onBufferingUpdate(int percent);
+} \ No newline at end of file
diff --git a/src/com/aocate/presto/service/IOnCompletionListenerCallback_0_8.aidl b/src/com/aocate/presto/service/IOnCompletionListenerCallback_0_8.aidl
new file mode 100644
index 000000000..d5edea729
--- /dev/null
+++ b/src/com/aocate/presto/service/IOnCompletionListenerCallback_0_8.aidl
@@ -0,0 +1,19 @@
+// Copyright 2011, Aocate, Inc.
+//
+// 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.aocate.presto.service;
+
+interface IOnCompletionListenerCallback_0_8 {
+ void onCompletion();
+} \ No newline at end of file
diff --git a/src/com/aocate/presto/service/IOnErrorListenerCallback_0_8.aidl b/src/com/aocate/presto/service/IOnErrorListenerCallback_0_8.aidl
new file mode 100644
index 000000000..2c4f2df3e
--- /dev/null
+++ b/src/com/aocate/presto/service/IOnErrorListenerCallback_0_8.aidl
@@ -0,0 +1,19 @@
+// Copyright 2011, Aocate, Inc.
+//
+// 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.aocate.presto.service;
+
+interface IOnErrorListenerCallback_0_8 {
+ boolean onError(int what, int extra);
+}
diff --git a/src/com/aocate/presto/service/IOnInfoListenerCallback_0_8.aidl b/src/com/aocate/presto/service/IOnInfoListenerCallback_0_8.aidl
new file mode 100644
index 000000000..9dbd1d260
--- /dev/null
+++ b/src/com/aocate/presto/service/IOnInfoListenerCallback_0_8.aidl
@@ -0,0 +1,19 @@
+// Copyright 2011, Aocate, Inc.
+//
+// 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.aocate.presto.service;
+
+interface IOnInfoListenerCallback_0_8 {
+ boolean onInfo(int what, int extra);
+} \ No newline at end of file
diff --git a/src/com/aocate/presto/service/IOnPitchAdjustmentAvailableChangedListenerCallback_0_8.aidl b/src/com/aocate/presto/service/IOnPitchAdjustmentAvailableChangedListenerCallback_0_8.aidl
new file mode 100644
index 000000000..41223a97b
--- /dev/null
+++ b/src/com/aocate/presto/service/IOnPitchAdjustmentAvailableChangedListenerCallback_0_8.aidl
@@ -0,0 +1,19 @@
+// Copyright 2011, Aocate, Inc.
+//
+// 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.aocate.presto.service;
+
+interface IOnPitchAdjustmentAvailableChangedListenerCallback_0_8 {
+ void onPitchAdjustmentAvailableChanged(boolean pitchAdjustmentAvailable);
+} \ No newline at end of file
diff --git a/src/com/aocate/presto/service/IOnPreparedListenerCallback_0_8.aidl b/src/com/aocate/presto/service/IOnPreparedListenerCallback_0_8.aidl
new file mode 100644
index 000000000..7be8f1237
--- /dev/null
+++ b/src/com/aocate/presto/service/IOnPreparedListenerCallback_0_8.aidl
@@ -0,0 +1,19 @@
+// Copyright 2011, Aocate, Inc.
+//
+// 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.aocate.presto.service;
+
+interface IOnPreparedListenerCallback_0_8 {
+ void onPrepared();
+} \ No newline at end of file
diff --git a/src/com/aocate/presto/service/IOnSeekCompleteListenerCallback_0_8.aidl b/src/com/aocate/presto/service/IOnSeekCompleteListenerCallback_0_8.aidl
new file mode 100644
index 000000000..5bdda98b6
--- /dev/null
+++ b/src/com/aocate/presto/service/IOnSeekCompleteListenerCallback_0_8.aidl
@@ -0,0 +1,19 @@
+// Copyright 2011, Aocate, Inc.
+//
+// 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.aocate.presto.service;
+
+interface IOnSeekCompleteListenerCallback_0_8 {
+ void onSeekComplete();
+} \ No newline at end of file
diff --git a/src/com/aocate/presto/service/IOnSpeedAdjustmentAvailableChangedListenerCallback_0_8.aidl b/src/com/aocate/presto/service/IOnSpeedAdjustmentAvailableChangedListenerCallback_0_8.aidl
new file mode 100644
index 000000000..a69c1cf34
--- /dev/null
+++ b/src/com/aocate/presto/service/IOnSpeedAdjustmentAvailableChangedListenerCallback_0_8.aidl
@@ -0,0 +1,19 @@
+// Copyright 2011, Aocate, Inc.
+//
+// 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.aocate.presto.service;
+
+interface IOnSpeedAdjustmentAvailableChangedListenerCallback_0_8 {
+ void onSpeedAdjustmentAvailableChanged(boolean speedAdjustmentAvailable);
+} \ No newline at end of file
diff --git a/src/com/aocate/presto/service/IPlayMedia_0_8.aidl b/src/com/aocate/presto/service/IPlayMedia_0_8.aidl
new file mode 100644
index 000000000..12a6047de
--- /dev/null
+++ b/src/com/aocate/presto/service/IPlayMedia_0_8.aidl
@@ -0,0 +1,75 @@
+// Copyright 2011, Aocate, Inc.
+//
+// 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.aocate.presto.service;
+
+import com.aocate.presto.service.IDeathCallback_0_8;
+import com.aocate.presto.service.IOnBufferingUpdateListenerCallback_0_8;
+import com.aocate.presto.service.IOnCompletionListenerCallback_0_8;
+import com.aocate.presto.service.IOnErrorListenerCallback_0_8;
+import com.aocate.presto.service.IOnPitchAdjustmentAvailableChangedListenerCallback_0_8;
+import com.aocate.presto.service.IOnPreparedListenerCallback_0_8;
+import com.aocate.presto.service.IOnSeekCompleteListenerCallback_0_8;
+import com.aocate.presto.service.IOnSpeedAdjustmentAvailableChangedListenerCallback_0_8;
+import com.aocate.presto.service.IOnInfoListenerCallback_0_8;
+
+interface IPlayMedia_0_8 {
+ boolean canSetPitch(long sessionId);
+ boolean canSetSpeed(long sessionId);
+ float getCurrentPitchStepsAdjustment(long sessionId);
+ int getCurrentPosition(long sessionId);
+ float getCurrentSpeedMultiplier(long sessionId);
+ int getDuration(long sessionId);
+ float getMaxSpeedMultiplier(long sessionId);
+ float getMinSpeedMultiplier(long sessionId);
+ int getVersionCode();
+ String getVersionName();
+ boolean isLooping(long sessionId);
+ boolean isPlaying(long sessionId);
+ void pause(long sessionId);
+ void prepare(long sessionId);
+ void prepareAsync(long sessionId);
+ void registerOnBufferingUpdateCallback(long sessionId, IOnBufferingUpdateListenerCallback_0_8 cb);
+ void registerOnCompletionCallback(long sessionId, IOnCompletionListenerCallback_0_8 cb);
+ void registerOnErrorCallback(long sessionId, IOnErrorListenerCallback_0_8 cb);
+ void registerOnInfoCallback(long sessionId, IOnInfoListenerCallback_0_8 cb);
+ void registerOnPitchAdjustmentAvailableChangedCallback(long sessionId, IOnPitchAdjustmentAvailableChangedListenerCallback_0_8 cb);
+ void registerOnPreparedCallback(long sessionId, IOnPreparedListenerCallback_0_8 cb);
+ void registerOnSeekCompleteCallback(long sessionId, IOnSeekCompleteListenerCallback_0_8 cb);
+ void registerOnSpeedAdjustmentAvailableChangedCallback(long sessionId, IOnSpeedAdjustmentAvailableChangedListenerCallback_0_8 cb);
+ void release(long sessionId);
+ void reset(long sessionId);
+ void seekTo(long sessionId, int msec);
+ void setAudioStreamType(long sessionId, int streamtype);
+ void setDataSourceString(long sessionId, String path);
+ void setDataSourceUri(long sessionId, in Uri uri);
+ void setEnableSpeedAdjustment(long sessionId, boolean enableSpeedAdjustment);
+ void setLooping(long sessionId, boolean looping);
+ void setPitchStepsAdjustment(long sessionId, float pitchSteps);
+ void setPlaybackPitch(long sessionId, float f);
+ void setPlaybackSpeed(long sessionId, float f);
+ void setSpeedAdjustmentAlgorithm(long sessionId, int algorithm);
+ void setVolume(long sessionId, float left, float right);
+ void start(long sessionId);
+ long startSession(IDeathCallback_0_8 cb);
+ void stop(long sessionId);
+ void unregisterOnBufferingUpdateCallback(long sessionId, IOnBufferingUpdateListenerCallback_0_8 cb);
+ void unregisterOnCompletionCallback(long sessionId, IOnCompletionListenerCallback_0_8 cb);
+ void unregisterOnErrorCallback(long sessionId, IOnErrorListenerCallback_0_8 cb);
+ void unregisterOnInfoCallback(long sessionId, IOnInfoListenerCallback_0_8 cb);
+ void unregisterOnPitchAdjustmentAvailableChangedCallback(long sessionId, IOnPitchAdjustmentAvailableChangedListenerCallback_0_8 cb);
+ void unregisterOnPreparedCallback(long sessionId, IOnPreparedListenerCallback_0_8 cb);
+ void unregisterOnSeekCompleteCallback(long sessionId, IOnSeekCompleteListenerCallback_0_8 cb);
+ void unregisterOnSpeedAdjustmentAvailableChangedCallback(long sessionId, IOnSpeedAdjustmentAvailableChangedListenerCallback_0_8 cb);
+} \ No newline at end of file