mirror of
				https://github.com/TeamNewPipe/NewPipe
				synced 2025-10-31 07:13:00 +00:00 
			
		
		
		
	Add PlaybackState broadcast messages
They can be used to retrieve the current playback * Duration * Played time * If the media player is playing
This commit is contained in:
		| @@ -14,6 +14,8 @@ import android.media.AudioManager; | ||||
| import android.media.MediaPlayer; | ||||
| import android.net.wifi.WifiManager; | ||||
| import android.os.IBinder; | ||||
| import android.os.Parcel; | ||||
| import android.os.Parcelable; | ||||
| import android.os.PowerManager; | ||||
| import android.support.v7.app.NotificationCompat; | ||||
| import android.util.Log; | ||||
| @@ -27,6 +29,7 @@ import org.schabi.newpipe.detail.VideoItemDetailActivity; | ||||
| import org.schabi.newpipe.detail.VideoItemDetailFragment; | ||||
|  | ||||
| import java.io.IOException; | ||||
| import java.util.Arrays; | ||||
|  | ||||
| /** | ||||
|  * Created by Adam Howard on 08/11/15. | ||||
| @@ -51,10 +54,13 @@ import java.io.IOException; | ||||
| /**Plays the audio stream of videos in the background.*/ | ||||
| public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPreparedListener*/ { | ||||
|  | ||||
|     private static final String TAG = BackgroundPlayer.class.toString(); | ||||
|     private static final String ACTION_STOP = TAG + ".STOP"; | ||||
|     private static final String ACTION_PLAYPAUSE = TAG + ".PLAYPAUSE"; | ||||
|     private static final String ACTION_REWIND = TAG + ".REWIND"; | ||||
|     private static final String TAG = "BackgroundPlayer"; | ||||
|     private static final String CLASSNAME = "org.schabi.newpipe.player.BackgroundPlayer"; | ||||
|     private static final String ACTION_STOP = CLASSNAME + ".STOP"; | ||||
|     private static final String ACTION_PLAYPAUSE = CLASSNAME + ".PLAYPAUSE"; | ||||
|     private static final String ACTION_REWIND = CLASSNAME + ".REWIND"; | ||||
|     private static final String ACTION_PLAYBACK_STATE = CLASSNAME + ".PLAYBACK_STATE"; | ||||
|     private static final String EXTRA_PLAYBACK_STATE = CLASSNAME + ".extras.EXTRA_PLAYBACK_STATE"; | ||||
|  | ||||
|     // Extra intent arguments | ||||
|     public static final String TITLE = "title"; | ||||
| @@ -114,6 +120,7 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare | ||||
|         isRunning = false; | ||||
|     } | ||||
|  | ||||
|  | ||||
|     private class PlayerThread extends Thread { | ||||
|         MediaPlayer mediaPlayer; | ||||
|         private String source; | ||||
| @@ -124,6 +131,7 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare | ||||
|         private WifiManager.WifiLock wifiLock; | ||||
|         private Bitmap videoThumbnail; | ||||
|         private NoteBuilder noteBuilder; | ||||
|         private volatile boolean donePlaying = false; | ||||
|  | ||||
|         public PlayerThread(String src, String title, BackgroundPlayer owner) { | ||||
|             this.source = src; | ||||
| @@ -133,6 +141,43 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare | ||||
|             mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); | ||||
|         } | ||||
|  | ||||
|         public boolean isDonePlaying() { | ||||
|             return donePlaying; | ||||
|         } | ||||
|  | ||||
|         private boolean isPlaying() { | ||||
|             try { | ||||
|                 return mediaPlayer.isPlaying(); | ||||
|             } catch (IllegalStateException e) { | ||||
|                 Log.w(TAG, "Unable to retrieve playing state", e); | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         private void setDonePlaying() { | ||||
|             donePlaying = true; | ||||
|             synchronized (PlayerThread.this) { | ||||
|                 PlayerThread.this.notifyAll(); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         private PlaybackState getPlaybackState() { | ||||
|             try { | ||||
|                 return new PlaybackState(mediaPlayer.getDuration(), mediaPlayer.getCurrentPosition(), isPlaying()); | ||||
|             } catch (IllegalStateException e) { | ||||
|                 // This isn't that nice way to handle this. | ||||
|                 // maybe there is a better way | ||||
|                 return PlaybackState.UNPREPARED; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         private void broadcastState() { | ||||
|             PlaybackState state = getPlaybackState(); | ||||
|             Intent intent = new Intent(ACTION_PLAYBACK_STATE); | ||||
|             intent.putExtra(EXTRA_PLAYBACK_STATE, state); | ||||
|             sendBroadcast(intent); | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void run() { | ||||
|             mediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);//cpu lock | ||||
| @@ -180,6 +225,7 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare | ||||
|             filter.addAction(ACTION_PLAYPAUSE); | ||||
|             filter.addAction(ACTION_STOP); | ||||
|             filter.addAction(ACTION_REWIND); | ||||
|             filter.addAction(ACTION_PLAYBACK_STATE); | ||||
|             registerReceiver(broadcastReceiver, filter); | ||||
|  | ||||
|             initNotificationBuilder(); | ||||
| @@ -188,18 +234,20 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare | ||||
|             //currently decommissioned progressbar looping update code - works, but doesn't fit inside | ||||
|             //Notification.MediaStyle Notification layout. | ||||
|             noteMgr = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); | ||||
|             /* | ||||
|  | ||||
|             //update every 2s or 4 times in the video, whichever is shorter | ||||
|             int sleepTime = Math.min(2000, (int)((double)vidLength/4)); | ||||
|             while(mediaPlayer.isPlaying()) { | ||||
|                 noteBuilder.setProgress(vidLength, mediaPlayer.getCurrentPosition(), false); | ||||
|                 noteMgr.notify(noteID, noteBuilder.build()); | ||||
|             int vidLength = mediaPlayer.getDuration(); | ||||
|             int sleepTime = Math.min(2000, (int)(vidLength / 4)); | ||||
|             while(!isDonePlaying()) { | ||||
|                 broadcastState(); | ||||
|                 try { | ||||
|                     Thread.sleep(sleepTime); | ||||
|                     synchronized (this) { | ||||
|                         wait(sleepTime); | ||||
|                     } | ||||
|                 } catch (InterruptedException e) { | ||||
|                     Log.d(TAG, "sleep failure"); | ||||
|                     Log.e(TAG, "sleep failure", e); | ||||
|                 } | ||||
|             }*/ | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         /**Handles button presses from the notification. */ | ||||
| @@ -208,26 +256,46 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare | ||||
|             public void onReceive(Context context, Intent intent) { | ||||
|                 String action = intent.getAction(); | ||||
|                 //Log.i(TAG, "received broadcast action:"+action); | ||||
|                 if(action.equals(ACTION_PLAYPAUSE)) { | ||||
|                     boolean isPlaying = mediaPlayer.isPlaying(); | ||||
|                     if(isPlaying) { | ||||
|                         mediaPlayer.pause(); | ||||
|                     } else { | ||||
|                         //reacquire CPU lock after auto-releasing it on pause | ||||
|                         mediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK); | ||||
|                         mediaPlayer.start(); | ||||
|                 switch (action) { | ||||
|                     case ACTION_PLAYPAUSE: { | ||||
|                         boolean isPlaying = mediaPlayer.isPlaying(); | ||||
|                         if(isPlaying) { | ||||
|                             mediaPlayer.pause(); | ||||
|                         } else { | ||||
|                             //reacquire CPU lock after auto-releasing it on pause | ||||
|                             mediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK); | ||||
|                             mediaPlayer.start(); | ||||
|                         } | ||||
|                         noteBuilder.setIsPlaying(isPlaying); | ||||
|                         noteMgr.notify(noteID, noteBuilder.build()); | ||||
|                         break; | ||||
|                     } | ||||
|                     noteBuilder.setIsPlaying(isPlaying); | ||||
|                     noteMgr.notify(noteID, noteBuilder.build()); | ||||
|                 } | ||||
|                 else if(action.equals(ACTION_REWIND)) { | ||||
|                     mediaPlayer.seekTo(0); | ||||
|                     case ACTION_REWIND: | ||||
|                         mediaPlayer.seekTo(0); | ||||
|                         synchronized (PlayerThread.this) { | ||||
|                             PlayerThread.this.notifyAll(); | ||||
|                         } | ||||
| //                    noteMgr.notify(noteID, note); | ||||
|                 } | ||||
|                 else if(action.equals(ACTION_STOP)) { | ||||
|                     //this auto-releases CPU lock | ||||
|                     mediaPlayer.stop(); | ||||
|                     afterPlayCleanup(); | ||||
|                         break; | ||||
|                     case ACTION_STOP: | ||||
|                         //this auto-releases CPU lock | ||||
|                         mediaPlayer.stop(); | ||||
|                         afterPlayCleanup(); | ||||
|                         break; | ||||
|                     case ACTION_PLAYBACK_STATE: { | ||||
|                         PlaybackState playbackState = intent.getParcelableExtra(EXTRA_PLAYBACK_STATE); | ||||
|                         Log.d(TAG, "playback state recieved: " + playbackState); | ||||
|                         Log.d(TAG, "is unprepared: " + playbackState.equals(PlaybackState.UNPREPARED)); | ||||
|                         Log.d(TAG, "playing: " + playbackState.getPlayedTime()); | ||||
|                         if(!playbackState.equals(PlaybackState.UNPREPARED)) { | ||||
|                             noteBuilder.setProgress(playbackState.getDuration(), playbackState.getPlayedTime(), false); | ||||
|                             noteBuilder.setIsPlaying(playbackState.isPlaying()); | ||||
|                         } else { | ||||
|                             noteBuilder.setProgress(0, 0, true); | ||||
|                         } | ||||
|                         noteMgr.notify(noteID, noteBuilder.build()); | ||||
|                         break; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         }; | ||||
| @@ -258,7 +326,9 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare | ||||
|  | ||||
|             @Override | ||||
|             public void onCompletion(MediaPlayer mp) { | ||||
|                 setDonePlaying(); | ||||
|                 afterPlayCleanup(); | ||||
|  | ||||
|             } | ||||
|         } | ||||
|  | ||||
| @@ -390,9 +460,9 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare | ||||
|                 RemoteViews views = getContentView(), bigViews = getBigContentView(); | ||||
|                 int imageSrc; | ||||
|                 if(isPlaying) { | ||||
|                     imageSrc = R.drawable.ic_play_circle_filled_white_24dp; | ||||
|                 } else { | ||||
|                     imageSrc = R.drawable.ic_pause_white_24dp; | ||||
|                 } else { | ||||
|                     imageSrc = R.drawable.ic_play_circle_filled_white_24dp; | ||||
|                 } | ||||
|                 views.setImageViewResource(R.id.notificationPlayPause, imageSrc); | ||||
|                 bigViews.setImageViewResource(R.id.notificationPlayPause, imageSrc); | ||||
| @@ -401,4 +471,111 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare | ||||
|  | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Represents the state of the player. | ||||
|      */ | ||||
|     public static class PlaybackState implements Parcelable { | ||||
|  | ||||
|         private static final int INDEX_IS_PLAYING = 0; | ||||
|         private static final int INDEX_IS_PREPARED= 1; | ||||
|         private static final int INDEX_HAS_ERROR  = 2; | ||||
|         private final int duration; | ||||
|         private final int played; | ||||
|         private final boolean[] booleanValues = new boolean[3]; | ||||
|  | ||||
|         static final PlaybackState UNPREPARED = new PlaybackState(false, false, false); | ||||
|         static final PlaybackState FAILED = new PlaybackState(false, false, true); | ||||
|  | ||||
|  | ||||
|         PlaybackState(Parcel in) { | ||||
|             duration = in.readInt(); | ||||
|             played = in.readInt(); | ||||
|             in.readBooleanArray(booleanValues); | ||||
|         } | ||||
|  | ||||
|         PlaybackState(int duration, int played, boolean isPlaying) { | ||||
|             this.played = played; | ||||
|             this.duration = duration; | ||||
|             this.booleanValues[INDEX_IS_PLAYING] = isPlaying; | ||||
|             this.booleanValues[INDEX_IS_PREPARED] = true; | ||||
|             this.booleanValues[INDEX_HAS_ERROR] = false; | ||||
|         } | ||||
|  | ||||
|         private PlaybackState(boolean isPlaying, boolean isPrepared, boolean hasErrors) { | ||||
|             this.played = 0; | ||||
|             this.duration = 0; | ||||
|             this.booleanValues[INDEX_IS_PLAYING] = isPlaying; | ||||
|             this.booleanValues[INDEX_IS_PREPARED] = isPrepared; | ||||
|             this.booleanValues[INDEX_HAS_ERROR] = hasErrors; | ||||
|         } | ||||
|  | ||||
|         int getDuration() { | ||||
|             return duration; | ||||
|         } | ||||
|  | ||||
|         int getPlayedTime() { | ||||
|             return played; | ||||
|         } | ||||
|  | ||||
|         boolean isPlaying() { | ||||
|             return booleanValues[INDEX_IS_PLAYING]; | ||||
|         } | ||||
|  | ||||
|         boolean isPrepared() { | ||||
|             return booleanValues[INDEX_IS_PREPARED]; | ||||
|         } | ||||
|  | ||||
|         boolean hasErrors() { | ||||
|             return booleanValues[INDEX_HAS_ERROR]; | ||||
|         } | ||||
|  | ||||
|  | ||||
|         @Override | ||||
|         public void writeToParcel(Parcel dest, int flags) { | ||||
|             dest.writeInt(duration); | ||||
|             dest.writeInt(played); | ||||
|             dest.writeBooleanArray(booleanValues); | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public int describeContents() { | ||||
|             return 0; | ||||
|         } | ||||
|  | ||||
|         public static final Creator<PlaybackState> CREATOR = new Creator<PlaybackState>() { | ||||
|             @Override | ||||
|             public PlaybackState createFromParcel(Parcel in) { | ||||
|                 return new PlaybackState(in); | ||||
|             } | ||||
|  | ||||
|             @Override | ||||
|             public PlaybackState[] newArray(int size) { | ||||
|                 return new PlaybackState[size]; | ||||
|             } | ||||
|         }; | ||||
|  | ||||
|         @Override | ||||
|         public boolean equals(Object o) { | ||||
|             if (this == o) return true; | ||||
|             if (o == null || getClass() != o.getClass()) return false; | ||||
|  | ||||
|             PlaybackState that = (PlaybackState) o; | ||||
|  | ||||
|             if (duration != that.duration) return false; | ||||
|             if (played != that.played) return false; | ||||
|             return Arrays.equals(booleanValues, that.booleanValues); | ||||
|  | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public int hashCode() { | ||||
|             if(this == UNPREPARED) return 1; | ||||
|             if(this == FAILED) return 2; | ||||
|             int result = duration; | ||||
|             result = 31 * result + played; | ||||
|             result = 31 * result + Arrays.hashCode(booleanValues); | ||||
|             return result + 2; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Coffeemakr
					Coffeemakr