August 31st, 2009, by alex

Android - binding to the Music app service to find currently playing song

For an Android app I’m working on I need to find out what song, if any, is playing in the background on the device. Turns out there’s no documented way to do this on Android - but it also turns out that using an open source platform is great. After a few hours of poking around I had a working proof of concept, and I’m sure someone more familiar with Android would’ve figured it out much faster.

IMPORTANT: I’m using an undocumented interface. While this works on Android 1.5R3 and T-Mobile G1 (HTC Magic), and likely on other versions/devices, there is no guarantee it’ll keep working in future releases - use at your own risk.

The default way to play music on the G1 is the Music app. Since it can play music in the background, it seemed likely there is some way to interact with the service it uses. This of course doesn’t help if the user is using some other music player, but it should be good enough.

First step was to figure out exactly what service that is - I used something like the following code to find out what services are running while I’m playing music:

		ActivityManager am = (ActivityManager)this.getSystemService(ACTIVITY_SERVICE);

		List<ActivityManager.RunningServiceInfo> rs = am.getRunningServices(50);

		for (int i=0; i<rs.size(); i++) {
			ActivityManager.RunningServiceInfo rsi = rs.get(i);
			Log.i("Service", "Process " + rsi.process + " with component " + rsi.service.getClassName());
		}

This prints up to 50 running services. The interesting line in the output is

process com.android.music with component com.android.music.MediaPlaybackService

OK, now to figure out how to interact with MediaPlaybackService. It turns out to be surprisingly simple.

First, get a copy of IMediaPlaybackService.aidl from the source code of the Music app, and include it in your Android app. The contents of this file are the methods we have access to in MediaPlaybackService. Of course, if the Music app on the device changes, and our copy of the .aidl file is inaccurate, we have a problem - hence the warning above.

Next, implement a ServiceConnection we can use to connect to MediaPlaybackService.

	private class MediaPlayerServiceConnection implements ServiceConnection {

		public IMediaPlaybackService mService;

		public void onServiceConnected(ComponentName name, IBinder service) {
			Log.i("MediaPlayerServiceConnection", "Connected! Name: " + name.getClassName());

			// This is the important line
			mService = IMediaPlaybackService.Stub.asInterface(service);

			// If all went well, now we can use the interface
			try {
				Log.i("MediaPlayerServiceConnection", "Playing track: " + mService.getTrackName());
				Log.i("MediaPlayerServiceConnection", "By artist: " + mService.getArtistName());
				if (mService.isPlaying()) {
					Log.i("MediaPlayerServiceConnection", "Music player is playing.");
				} else {
					Log.i("MediaPlayerServiceConnection", "Music player is not playing.");
				}
			} catch (Exception e) {
	    		e.printStackTrace();
	    		throw new RuntimeException(e);
			}
		}

		public void onServiceDisconnected(ComponentName name) {
			Log.i("MediaPlayerServiceConnection", "Disconnected!");
		}
	}

Finally, bind the service:

		Intent i = new Intent();
		i.setClassName("com.android.music", "com.android.music.MediaPlaybackService");
		ServiceConnection conn = new MediaPlayerServiceConnection();
		this.bindService(i, conn, 0);

That’s it! From here on it should be possible to use the MediaPlaybackService like any other service.


34 comments Subscribe Comments

  1. First thank you for your article! It helped me a lot! Got my program to connect just perfect to the Android Music Player.

    Question now. Do you know how to get for example the aidl file for the HTC Music player (com.htc.music)? And for other Music Players that are out there? What would be the easiest or best way to get my hands on those?

    Have a great day!

  2. Good question. I haven’t worked with the other players, so I can’t give you a specific answer.

    If the players are open-source, it should be simple - the aidl files should be in the source…

    If not, the only option I can think of is to grab the player’s .apk file from the device (might have to root it first!), and see if you can extract the .aidl file from it somehow. I’m not sure what the legal implications would be for this method.

  3. By adam on November 3rd 2009

    Hey there Alex, great article! Helped me a lot.

    Although I’m having some trouble with my implementation. I have a MediaPlayerServiceConnection class with the above code, but instead of printing to the Log I wrote getter methods to be used by my main class, where the bind service code is in.

    The problem I have is that, every time I call any of the methods used in the aidl, i get a NullPointerException. Further investigation revealed that onServiceConnected was never called. What could I be doing wrong?

    I’m developing using Eclipse (Galileo) and android SDK 1.5 (api level 3) with ADT/emulator.

    Thanks in advanced!

  4. By adam on November 4th 2009

    Hello, please disregard the previous post. It was just a silly mistake I made. =)

  5. By dghgh on November 8th 2009

    what was the silly mistake? I keep getting the NullPointerException when i call my services method and i prettymuch followed the tutorials.

  6. @adam..
    plz tell ur silly mistake.. i m getting the same NullPtrExp. Im calling bindService(xx) before using the methods in service. but still getting the exception.
    The main thing is that, when i call some methods on some button click, it works fine. But when I call the same methods in onStart() or onCreate() of Activity, I get NullptrExp. :(
    any help???

  7. By music on November 17th 2009

    Thanks for this article! It describes just, what I am about to try. But I ran into a problem:
    The catch clause catches a Security Exception “Binder invocation to an incorrect interface”

    I copied the aidl file to my project and changed the package to my package. When I run my test app in the emulator it connects to the service, but when I try tu use it I get the mentioned exception.

    Any idea what might be the problem? Am I using the wrong aidl file?

  8. By music on November 17th 2009

    @ud

    bindService is asynchronous. You can only use the service after onServiceConnected was called.

  9. By Sathya on November 20th 2009

    Hi,

    Thanks for the artcile..It really helped us to start the application. But when I tried the example in emulator I am getting an exception on trying to use the interface functions…It throws the exception “Binder invocation to an incorrect interface”

    The following are the steps followed
    1) Copied the AIDL file (IMediaPlayBackService.aidl) to my package folder
    2) Renamed the package in teh aidl file to my application(As it shown error when include to the package folder)
    3) Bind a service.
    4) And tried to use the service in the onServiceCOnnected callback function after getting the interface using the code
    mService = IMediaPlaybackService.Stub.asInterface((IBinder)service);

    But exception is thrown on trying to use the interface functions.

    Could you please let me know what might be the problem?

    Thanks in advance for the reply.

  10. By Sathya on November 20th 2009

    Hi,

    Thanks for the article..It really helped us to start the application. But when I tried the example in emulator I am getting an exception on trying to use the interface functions…It throws the exception “Binder invocation to an incorrect interface”

    The following are the steps followed
    1) Copied the AIDL file (IMediaPlayBackService.aidl) to my package folder
    2) Renamed the package in teh aidl file to my application(As it shown error when include to the package folder)
    3) Bind a service.
    4) And tried to use the service in the onServiceCOnnected callback function after getting the interface using the code
    mService = IMediaPlaybackService.Stub.asInterface((IBinder)service);

    But exception is thrown on trying to use the interface functions.

    Could you please let me know what might be the problem?

    Thanks in advance for the reply.

  11. By MarGau on November 20th 2009

    The problem is that the IMediaPlaybackService needs to be defined within package com.android.music you cannot change this as you then experience the security exception.
    The exception basically says that the expected interface is “com.android.music.IMediaPlaybackService” whereas you defined something else.

    In order to fix this you need to have in your source tree:
    src\com\android\music\IMediaPlaybackService.aidl
    parallel to your code. Then you don’t have to rename the package and everything works fine.

  12. By Sathya on November 30th 2009

    Hi MarGau,

    Thanks for the reply. It worked.. :-)

  13. By NPS on December 5th 2009

    Hi can you pls give us a working example ,
    What we are trying to do is tag the currently playing song so for that we need to get the info like the actual path to the song and also the artist info and all some how i cannot find the IMediaPlaybackService.aidl file in my android sdk

    could you direct me towards that

  14. By Jorge Rivera on December 10th 2009

    Hi,

    Thanks a lot for the post, it was really helpful!

    Has anyone tried to enqueue a list of songs using the .enqueue method? I have a little problem with it: I send a bunch of songs and only the first HALF of the songs get added to the list. I tried using the NOW, NEXT and LAST position options, and various sizes of lists of songs. For an odd number of songs, it adds half of (list+1).

    Any ideas?

  15. Hi friends,
    Any body have idea How cna i play music file over coming call.
    Pls reply ,
    thanks in advance.

  16. By chopcsu on July 5th 2010

    Does anyone if there are any other mechanisms to detect a song change other than just polling?

  17. By mytharak on July 20th 2010

    Cool article!

    You should be able to access the media player’s service from your app without including it manually.

    Have you tried “import com.android.music.IMediaPlaybackService” instead of manually including the aidl file?

  18. By chopcsu on August 3rd 2010

    So found out HTC have started using their own music player, as well as Sony Ericsson, so this method will not work on X10’s & Legends..will post other phones I come across that do not have the default android music player

  19. By Grzegorz Madajczak on August 15th 2010

    Hello!
    First of all - thank you for nice article. It’s clear and very usefull.
    I tried to implement this method in my project, but always I have exception: java.lang.RuntimeException: java.lang.SecurityException: Binder invocation to an incorrect interface.
    My pastebin with whole exception is: http://android.pastebin.com/Xj7WpiJ3.

    I will be appreciated for advice, how to resolve this problem…
    I will add, that this is the same problem as in #10 post by Sathya.

  20. By Grzegorz Madajczak on August 15th 2010

    mytharak :
    Cool article!
    You should be able to access the media player’s service from your app without including it manually.
    Have you tried “import com.android.music.IMediaPlaybackService” instead of manually including the aidl file?

    It is impossible, because com.android.music is not in android SDK.

  21. By jaumard on September 24th 2010

    Hello,

    I try your code and it work only on the connection service?
    How can know if music is playing after start this service?
    It’s possible to put a register to listen music state?

    Thanks
    Cheers
    Jim

  22. i am also trying your code and working to do lot better.

  23. By Gaurav on October 11th 2010

    Isn’t the SoundPool class useful for such things… Just a guess !!!

  24. By Jern on November 9th 2010

    Got the code to work, but Im not that good at coding so I get another problem.

    How do i get the information returned to my main class? (i.e. mService.getTrackName())

  25. By veeresh on November 11th 2010

    To bind to the MediaPlayer service, is it required that service is running?
    case1)
    If service is not running, after running if use any of the interfaces such as play() or stop() it throwing null pointer exception.
    case2)
    If Music player is started and stopped and the play() and stop() are working fine.
    What is the way to address case1.

    Thanks in advance.

  26. By veeresh on November 11th 2010

    Got the solution for case 2
    Silly mistake frm my side.
    this.bindService(i, conn, 0);
    0 has to be replaced by Context.BIND_AUTO_CREATE on which if service is not running it’ll be started.

    Thanks again.

  27. By Subu on November 19th 2010

    Nice Article !!!!!!!!!

    But anyone tried the same means “import com.android.music.IMediaPlaybackService” instead of manually including the aidl file to your own Application ?
    Because I tried to import the IMediaPlaybackService using getSystemProperty, but it is not working for me.

    Can anyone let me know the answer how to import the IMediaPlaybackService instead of adding manually. Some way should be there to be access remotly……

  28. By GolemNagesh on February 3rd 2011

    Hello Experts,

    now i am working on one android application which needs
    1) to play an audio song to callee when call is lifted.
    2) call has to be disconnected after audio playing completed.

    please help me experts if you have any suggestions for me …

    thank you in advance, please do reply

  29. By GolemNagesh on February 4th 2011

    shubham :
    Hi friends,
    Any body have idea How cna i play music file over coming call.
    Pls reply ,
    thanks in advance.

  30. By Balu on September 26th 2011

    Hi, why are you using aidl files when you can use messenger class?

  31. thanks for the post! great explanation and instructions.

    unfortunately, it looks like the music app stopped exporting this service in gingerbread by marking it exported=”false”:

    https://github.com/android/platform_packages_apps_music/blob/6b507de7beda7f4a8b969b437dfbf81f5ecd5e5e/AndroidManifest.xml#L267

    which breaks this technique, since it’s no longer available outside the music app’s process. specifically, bindService() now raises java.lang.SecurityException: “Not allowed to bind to service Intent.”

    oh well. i guess it was nice while it lasted. off to find other workarounds…

  32. just for completeness, here are a few variations i tried. they all failed, as i expected, which at least confirms that exported=”false” works as intended and can’t be trivially worked around.

    1) i tried putting my entire app into the com.android.music package, including the contents of AndroidManifest.xml. it compiled OK, but gave me this error when i tried to install it in an emulator device:

    [exec] Failure [INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES]

    2) i went the other direction, moved IMediaPlaybackService.aidl and MediaPlayerServiceConnection.java into my own package, and updated the package names everywhere, including the intent used in bindService(), to use my own. as expected, android thought i wanted to use an entirely new service of my own, and complained that it couldn’t find an implementation:

    java.lang.RuntimeException: Unable to instantiate service org.snarfed.android.localemusic.MediaPlaybackService: java.lang.ClassNotFoundException: org.snarfed.android.localemusic.MediaPlaybackService in loader dalvik.system.PathClassLoader[/data/app/org.snarfed.android.localemusic-1.apk]

    3) i finally tried keeping the files and service in my own package, but using com.android.music in the intent’s class name. no luck, this gave the same original error:

    java.lang.SecurityException: “Not allowed to bind to service Intent.”

  33. By Douglas on February 1st 2012

    Same problem “Not allowed to bind to service Intent.”
    Does anyone have more ideas?


Add your comment