22

I am trying to receive information about the currently played track in a iOS app. This works pretty fine while the iPhone is not connected to an accessory. If I connect it to my car (Opel Astra, iPhone jack), the following code stops to work as described in the documentation:

If you create an iPod music player and the user plays an item from another library using Home Sharing, the value of this property is nil.

Code:

// nil while connected to an accessory
MPMediaItem *nowPlayingMediaItem =
                 [[MPMusicPlayerController iPodMusicPlayer] nowPlayingItem];

// Works while not connected to an accessory
NSString *title = [nowPlayingMediaItem valueForProperty:MPMediaItemPropertyTitle];

I even tried "hacky" stuff like to access "private" properties (original code):

MPMediaQuery *query=nil; 
MPMediaItemCollection *collection=nil; 
id internalPlayer=nil; 
Ivar internalPlayeriVar = object_getInstanceVariable(iPod, "_internal", NULL); 
internalPlayer = object_getIvar(iPod, internalPlayeriVar); 
NSLog(@"internalPlayer: %@", internalPlayer);
Ivar queryIvar = object_getInstanceVariable(internalPlayer, "_query", NULL); 
query = object_getIvar(internalPlayer, queryIvar); // nil everytime
Ivar collectionIvar = object_getInstanceVariable(internalPlayer, 
                                                 "_itemCollection", NULL); 
collection = object_getIvar(internalPlayer, collectionIvar); // nil everytime

or to call private methods:

// Same behaviour like [iPod nowPlayingItem], works 
// only while no accessory is connected
MPMediaItem *nowPlayingMediaItem =
                 [iPod nowPlayingItemAtIndex:[iPod indexOfNowPlayingItem]];

// Works while not connected to an accessory
NSString *title = [nowPlayingMediaItem valueForProperty:MPMediaItemPropertyTitle];

Its also no solution to access the new MPNowPlayingInfoCenter, its nil all the time.

[MPNowPlayingInfoCenter defaultCenter].nowPlayingInfo

My car plays my music directly without using a iPhone app and it seems my iPhone knows what the car is currently playing because it displays the title, artist and cover icon on the lock screen (and only there). Also the internal play count gets increased.

If I check the playback state, it returns also YES if the car plays music:

[[MPMusicPlayerController iPodMusicPlayer] playbackState] == MPMusicPlaybackStatePlaying 

So, is there any way (may be through calling private methods) to access the song, the car is currently playing?

Thomas Kekeisen
  • 4,192
  • 4
  • 32
  • 50
  • 11
    OT: I had to smile when I read that you see your car as an accessory to your phone and not the other way round :-) – Matthias Feb 22 '12 at 14:53
  • Can you explain if you are connecting via the headphone jack or the iPhone jack? I am also assuming that your car is playing music from your iPhone? If the iPhone is displaying the song then I assume that the iPhone is actually the one playing the music instead of the car. Are you wanting to play the music through your app while it is connected to the car so it comes out the car speakers? – Bot Feb 23 '12 at 00:52
  • I connect the iPhone via the iPhone jack. I don't know who is acutually playing the music, but I am able to select the music from the info display in my car. I just want to know in a third party app what song is currently played. (To play music with a third party app is also possible, but the car audio controls only work with the real "music" app) – Thomas Kekeisen Feb 23 '12 at 08:18
  • @Blauesocke besure to use `@person` so that we get notified when you comment. Can you confirm if your car is opening the Music app on your phone? Also if you open the music app while not connected to the car does your application detect what is playing in your music app? From what I have seen, your code should be able to detect the songs being played by the Music.app – Bot Feb 23 '12 at 18:29
  • @Computer Yes, the music app shows "connected to accessory" when I connect it to my car. When the car plays a song, the 3rd party app gets "nil" when calling "[[MPMusicPlayerController iPodMusicPlayer] nowPlayingItem]", BUT when I unplug the iPhone, the information about the last track the car played appears. So, it seems this is only a (non-jailbreak) software restriction. – Thomas Kekeisen Feb 24 '12 at 07:41
  • @Blauesocke are you jail broken? If so I wonder if that is what is causing the issue. The way you have everything programmed looks right and should be working. – Bot Feb 24 '12 at 15:05

4 Answers4

2

Apple just "fixed that" in iOS 6.1 after I reported it as a bug. The following code now works while my iPhone is connected to my car:

MPMediaItem *nowPlayingMediaItem = [iPod nowPlayingItem];

NSString *title = [nowPlayingMediaItem valueForProperty:MPMediaItemPropertyTitle];

NSLog(@"Playing title: %@", title);

And, what I really like: It is also possible to change the playing track using the iPod app - the app appears as you expect it, instead of the big white "connected to an accessory" screen. So this may also work programatically.

Thomas Kekeisen
  • 4,192
  • 4
  • 32
  • 50
2

Are you using threads? If so run the code on the main thread. If not then register for the MPMusicPlayerController notifications for item change. That way when the song changes your app will know what the new song is. Also be sure this runs on the main thread as well.

If your playback state is updating while connected but your nowPlayingItem isn't, this would confirm it is a bug. I would submit a bug report for this issue.

EDIT: Visit https://developer.apple.com/support/resources/bug-reporting.html and scroll to the bottom. The last question says you can contact TSI for bug work arounds. You get 2 TSI requests for being a developer for free so you can use one of those to ask them if they have a work around using a private library until the bug is fixed.

Community
  • 1
  • 1
Bot
  • 11,620
  • 10
  • 68
  • 127
  • How to access the information about the played song? Like the documentation says, there is no userInfo dictionary so I have still to use [[MPMusicPlayerController iPodMusicPlayer] nowPlayingItem] what is nil all the time? – Thomas Kekeisen Feb 24 '12 at 07:37
  • No, I don't think that this matters :-) – Thomas Kekeisen Feb 24 '12 at 16:06
  • @Blauesocke are you jail broken? – Bot Feb 27 '12 at 20:39
  • No, but it would be no problem to use private api calls (if there are some with matching functionality). – Thomas Kekeisen Feb 27 '12 at 21:20
  • @Blauesocke I only ask because it is possible for a jail broken phone to have overrides on some of the API's. It sounds to me like this is a bug for the `nowPlayingItem` as it only occurs when the iPhone is plugged in. As a test can you close ALL applications on your iPhone then plug it into the car and play a song. I would like to know if the car is actually opening the Music.app application and playing it from there or if it is accessing the music directly from the device. – Bot Feb 27 '12 at 21:34
  • Thanks, I already reported a bug, maybe I will request a workaround. – Thomas Kekeisen Feb 29 '12 at 08:24
0

I am pretty sure the answer is no, you can't with any public api's at least but you should file a bug with apple for two reasons:

The reason MPNowPlayingInfoCenter does not give you the info is because it has to be specifically implemented by the app playing the music, if apple's app playing then it should have been implemented so file a bug.

Now if you say [[MPMusicPlayerController iPodMusicPlayer] playbackState] reflects playback changes then that would mean iPodMusicPlayer is still the app in charge of playback so giving you nil for MPMediaItemPropertyTitle should also be reported to apple as a bug.

Additionally non public information on the topic is likely covered by the MFi NDA and nobody is going to risk his ass.

valexa
  • 4,245
  • 28
  • 48
0

Actually you won't get any MPMediaItem because your iPhone isn't playing the songs but your car's accessory connected to the iPhone is accessing the media library. In doing so, it is responsible to update all the metadata of the accessed objects (songs), especially incrementing the playcount and updating the last accessed date of the song. It also stores some information of where in the song it is (position) in the iTunes library.

This information is read by the lock screen to update the cover. This is also what helps the iPod app to continue where your car's accessory left.

So tap into the library and get the latest information from there. Have a look at the TopSongs example project to get started.

Heiko
  • 1