Skip to content


Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files


  • Loading branch information...
commit eea2bc29ad35a24f4f01d8410c2ef2b08e471d2d 1 parent 597e66d
Chris Rhoden chrisrhoden authored
Showing with 124 additions and 79 deletions.
  1. +124 −79
@@ -1,15 +1,47 @@
+# PlayerHater
-Android Audio Playback. You hear rumblings of a 2.0 release in the distance.
-The earth moves slightly beneath your feet. It is coming.
+PlayerHater is an Android library for playing audio in the background of your app. You can use it for:
+* Podcasts!
+* Music!
+* Radio!
-Everything is changing. We're getting leaner and faster and much, much easier to deal with.
+You probably shouldn't use it for:
-How about this?
+* Fart sounds
+* Game sound effects
+There's a whole lot that PlayerHater does for you right out of the box and you can add your own functionality through the use of plugins. PlayerHater even ships with plugins that will do the following automatically:
+* Show a regular notification on on Android 2.3 or lower, a notification with player controls on Android 3.0+, and an expandable notification on Android 4.2+!
+* Handle audio focus changes in all of the weird and different ways for pre-2.2 and post-2.2 versions!
+* Add lock screen controls on Android 4.0+!
+* Pebble support!
+All of this is configurable if you like, and you can write your own plugins to run alongside these.
+But the best thing about PlayerHater is that there are no ServiceConnection callbacks, MediaPlayer state diagrams, or setup and teardown code for you to write. It's all taken care of in the library.
+## Quick Start
+### Important, temporary information
+ Everything's going into Maven Central soon using the new aar format
+ that's part of the new Android build system that uses Gradle. If
+ you're not comfortable using the sonatpe OSS snapshot server (or if
+ you don't know what that is) or you haven't moved to Gradle yet, you
+ can check out the project repository and use the files in
+ legacyLibraryProject/PlayerHater
+ as if they were a normal android library project. They are, in fact
+ symlinks.
+ Note that doing this will require you to add entries to your
+ AndroidManifest.xml file, while the new build system allows us to
+ automatically do this for you if you're using Gradle.
+Once you've imported the project into your android application and added the `Service` and `BroadcastReceiver` to your `AndroidManifest.xml` file, getting a handle on the player is as easy as:
@@ -21,86 +53,99 @@ class MyApplicationActivity extends Activity {
public void onResume(Bundle savedInstanceState) {
- mPlayerHater = PlayerHater.get(this);
+ mPlayerHater = PlayerHater.bind(this);
public void onPause() {
- PlayerHater.release(this);
+ mPlayerHater.release();
- // All your crazy stuff happens here.
-Lots of changes to the way this works since last time. Many more files. Plugins. Docs coming soon.
-The PlayerHater Object
-It's a singleton that automatically binds and tears down the service that you're attached to.
-It also lets you start working immediately, and will send the stuff you've asked for along to the
-service once it's ready.
-All public methods conform to this interface:
-public interface AudioPlaybackInterface {
- // Controls
- boolean pause();
- boolean stop();
- // Playback
- boolean play();
- boolean play(int startTime);
- boolean play(Uri url);
- boolean play(Uri url, int startTime);
- boolean play(Song song);
- boolean play(Song song, int startTime);
- // Queuing
- void enqueue(Song song);
- boolean skipTo(int position);
- void emptyQueue();
- // For sound effects
- TransientPlayer playEffect(Uri url);
- TransientPlayer playEffect(Uri url, boolean isDuckable);
- // Notification data
- void setAlbumArt(int resourceId);
- void setAlbumArt(Uri url);
- void setTitle(String title);
- void setArtist(String artist);
- void setActivity(Activity activity);
- // Scubber-related data
- int getCurrentPosition();
- int getDuration();
- // Media Player listeners
- void setOnBufferingUpdateListener(OnBufferingUpdateListener listener);
- void setOnCompletionListener(OnCompletionListener listener);
- void setOnInfoListener(OnInfoListener listener);
- void setOnSeekCompleteListener(OnSeekCompleteListener listener);
- void setOnErrorListener(OnErrorListener listener);
- void setOnPreparedListener(OnPreparedListener listener);
- // PlayerHater listener
- void setListener(PlayerHaterListener listener);
- void setListener(PlayerHaterListener listener, boolean withEcho);
- // Other Getters
- Song nowPlaying();
- boolean isPlaying();
- boolean isLoading();
- int getState();
+When you've bound to a `PlayerHater`, you're ready to start playing stuff - music, podcasts, or whatever new thing the kids are listening to these days.
+### The PlayerHater API
+ abstract void emptyQueue()
+ Removes all songs from the queue.
+ abstract int enqueue(Song song)
+ Puts a song on the end of the play queue.
+ abstract int getCurrentPosition()
+ Gets the location of the playhead in milliseconds.
+ abstract int getDuration()
+ Gets the duration of the currently loaded Song in milliseconds.
+ abstract int getQueueLength()
+ Returns the number of items in the queue.
+ abstract int getQueuePosition()
+ Returns the number of clips in the queue which are at least partially behind the playhead.
+ abstract int getState()
+ Gets the state of the PlayerHater, represented as an int.
+ abstract boolean isLoading()
+ Checks to see if the player is currently loading audio.
+ abstract boolean isPlaying()
+ Checks to see if the player is currently playing back audio.
+ abstract Song nowPlaying()
+ Gets the Song representation of the track that is currently loaded in the player.
+ abstract boolean pause()
+ Pauses the player.
+ abstract boolean play(Song song, int startTime)
+ Begins playback of song at startTime
+ abstract boolean play(Song song)
+ Begins playback of a song at the beginning.
+ abstract boolean play(int startTime)
+ Begins playback of the currently loaded Song at startTime in the track.
+ abstract boolean play()
+ Begins playback of the currently loaded Song.
+ abstract boolean removeFromQueue(int position)
+ Removes the element at position from the play queue.
+ abstract boolean seekTo(int startTime)
+ Moves the playhead to startTime
+ abstract void setPendingIntent(PendingIntent intent)
+ Sets the intent to be used by the plugins.
+ abstract void setTransportControlFlags(int transportControlFlags)
+ Sets the visible buttons for plugins.
+ abstract void skip()
+ Moves to the next song in the play queue.
+ abstract void skipBack()
+ Moves back in the play queue.
+ abstract boolean skipTo(int position)
+ Moves to a new position in the play queue.
+ abstract boolean stop()
+ Stops the player.
+## Changelog
+### v0.3.0
+We refactored everything to make more sense and run faster. Large parts of the codebase have been written from scratch using knowledge we gained in versions 0.1.0 and 0.2.0 and many class and method names have been changed to make more sense.
+0.3.0 is a breaking upgrade from 0.2.0 and is still considered beta software until a 1.0.0 release.
+#### Highlights
+* The Service is now aggressively bound whenever you are interacting with PlayerHater. It's still released when appropriate so that Android can GC the process automatically and it will not show up in the Android Running Services list.
+* getState() will now return one of `PlayerHater.IDLE`, `PlayerHater.PLAYING`, `PlayerHater.LOADING`, or `PlayerHater.PAUSED` instead of one of the lower-level MediaPlayer states.
+* `public Bundle getExtra()` and `public String getAlbumTitle()` have been added to the `Song` interface. `void onAlbumTitleChanged(String albumTitle)` has been added to the `PlayerHaterPlugin` interface.
+* `void onServiceStarted(IPlayerHaterBinder binder)` has been removed from the `PlayerHaterPlugin` interface. If you need access to Service-only methods, check to see if the `PlayerHater` passed to `onPlayerHaterLoaded()` is a `ServicePlayerHater`, cast, and then call the methods needed.
+* Song data is loaded just in time, even across the IPC boundary. This means that if you enqueue a `Song` and then the return values for the various Song methods change, those changes will be propagated. Please note that if your Activity-side application is terminated the Song data will be serialized at that moment and passed across the barier to permit garbage collection.
+### v0.2.0
+* No service callbacks to deal with - Service is automatically started as needed when `play()` is called. You can immediately work with PlayerHater and all commands sent to it will be forwarded to the Service once it is started.
+* It is no longer the developer's responsibility to remember when to and when not to stop the service.
+* The service is now runnable on a separate Android process through the use of AIDL IPC.
+* Too many changes to enumerate. Refer to documentation.
+0.2.0 is a breaking upgrade from 0.1.0 and is still considered beta software until a 1.0.0 release.
Please sign in to comment.
Something went wrong with that request. Please try again.