diff options
Diffstat (limited to 'core/src/main/java/com/aocate/media/ServiceBackedMediaPlayer.java')
-rw-r--r-- | core/src/main/java/com/aocate/media/ServiceBackedMediaPlayer.java | 1201 |
1 files changed, 1201 insertions, 0 deletions
diff --git a/core/src/main/java/com/aocate/media/ServiceBackedMediaPlayer.java b/core/src/main/java/com/aocate/media/ServiceBackedMediaPlayer.java new file mode 100644 index 000000000..702a23b0f --- /dev/null +++ b/core/src/main/java/com/aocate/media/ServiceBackedMediaPlayer.java @@ -0,0 +1,1201 @@ +// 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. +// +// ----------------------------------------------------------------------- +// Compared to the original version, this class been slightly modified so +// that any acquired WakeLocks are only held while the MediaPlayer is +// playing (see the stayAwake method for more details). + + +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; + +import de.danoeh.antennapod.core.BuildConfig; + +/** + * 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 + ")"); + stayAwake(false); + 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); + } + stayAwake(false); + } + + /** + * 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); + } + stayAwake(false); + } + + /** + * 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.setReferenceCounted(false); + } + + this.mWakeLock.acquire(); + } + } + + /** + * Changes the state of the WakeLock if it has been acquired. + * If no WakeLock has been acquired with setWakeMode, this method does nothing. + * */ + private void stayAwake(boolean awake) { + if (BuildConfig.DEBUG) Log.d(SBMP_TAG, "stayAwake(" + awake + ")"); + if (mWakeLock != null) { + if (awake && !mWakeLock.isHeld()) { + mWakeLock.acquire(); + } else if (!awake && mWakeLock.isHeld()) { + mWakeLock.release(); + } + } + } + + 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"); + stayAwake(false); + 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(); + stayAwake(false); + 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); + } + stayAwake(true); + } + + /** + * 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); + } + stayAwake(false); + } +}
\ No newline at end of file |