How to detect if an MPMediaItem represents a DRM-protected audio track on iOS
Asked Answered
D

7

18

I would like to know if an MPMediaItem that represents a music track is for a Fairplay/DRM-protected item. Any way to do this?

Darceydarci answered 6/4, 2011 at 18:13 Comment(0)
C
10

Here's how I do it:

MPMediaItem* item;

NSURL* assetURL = [item valueForProperty:MPMediaItemPropertyAssetURL];
NSString *title=[item valueForProperty:MPMediaItemPropertyTitle];

if (!assetURL) {
    /*
     * !!!: When MPMediaItemPropertyAssetURL is nil, it typically means the file
     * in question is protected by DRM. (old m4p files)
     */
    NSLog(@"%@ has DRM",title);
}
Copious answered 13/9, 2011 at 22:11 Comment(5)
Hi Guys, Could you please suggest how can we play these DRM protected files using AVPlayer?Molina
AVPlayer cannot play old DRM. You need to get the user to upgrade the audio files with iTunes Plus to convert the tracks to open DRM which is what all songs are sold as now.Frenetic
I checked a few songs I bought from iTunes in the last year and they exhibit the same problem -- MPMediaItemPropertyAssetURL returns (null). The files are shown in iTunes as "Purchased AAC audio file" and have an extension of .m4a. So it seems like this problem still exists, or went away and came back again since the comments above...?Brynne
To your comment on DRM, I've also seen MPMediaItemPropertyAssetURL return nil for tracks that were not completely downloaded from iTunes/iCloud. Fixed it by forcing the download in the Apple Music app.Scrutable
This is not the correct way to check because MPMediaItemPropertyAssetURL is not nil on iOS 11 at least for songs saved offline via Apple Music but they are definitely DRM protected and AVPlayer too is unable to play them. Please check my answer below for details on this.Lipase
E
6

Since iOS 4.2 there is a way. There may be a more effective way then the example here (but for my app I needed to create AVPlayerItems anyway).

MPMediaItem item;
NSURL *assetURL = [item valueForProperty:MPMediaItemPropertyAssetURL];
AVPlayerItem *avItem = [[AVPlayerItem alloc] initWithURL:assetURL];
BOOL fairplayed = avItem.asset.hasProtectedContent;
Ephialtes answered 19/6, 2011 at 8:21 Comment(5)
Since [item valueForProperty:MPMediaItemPropertyAssetURL] returns nil for a DRM, your AVPlayerItem will be created with nil ?Carolyncarolyne
Possibly. Is it a safe assumption that the asset url returned is always nil for protected content?Ephialtes
I got the issue by not checking if assetURL is nil, an with a device with iOS > 4.2 (4.3.4 exactly)Carolyncarolyne
Unprotected items which are not currently playable will also return nil. Most commonly items in iTunes Match which are not local to the device.Hrvatska
This is the correct way to check. Also, MPMediaItemPropertyAssetURL is not nil on iOS 11 at least for songs saved offline via Apple Music but AVPlayer is unable to play them since they are DRM protected. Check my answer below for details on this.Lipase
R
5

From iOS 4.2 the AVAsset class has a property hasProtectedContent so you can check:

NSURL *assetURL = [item valueForProperty:MPMediaItemPropertyAssetURL];
AVAsset *asset = [AVAsset assetWithURL:assetURL];

if ([asset hasProtectedContent] == NO) {..do your stuff..}
Receptor answered 22/5, 2012 at 13:30 Comment(2)
Note that this hasProtectedContent call is relatively slowing; calling it on about 100 non-DRMed songs was taking around 4 seconds on an iphone 4S.Profundity
Of course but that is only way to make it work. Adding that code in background queue solves the problem and you can display progress bar so user can know that operation will last a little bit longer that other operations.Receptor
L
3

MPMediaItemPropertyAssetURL is not nil on iPhone X running iOS 11 for songs saved offline via Apple Music but AVPlayer is unable to play them since they are DRM protected. The same song returns MPMediaItemPropertyAssetURL nil on iOS 9.

MPMediaItemPropertyAssetURL returns nil for songs added to Library via Apple Music but not available offline - both on iOS 9 & 11.

Thus, @voidStern's answer (and not Justin Kent's) is the correct way to test for DRM-protected asset.

Swift 4 version of voidStern's answer (works perfectly for me on iOS 9 to 11):

let itemUrl = targetMPMediaItem?.value(forProperty: MPMediaItemPropertyAssetURL) as? URL
if itemUrl != nil {
    let theAsset = AVAsset(url: itemUrl!)
    if theAsset.hasProtectedContent {
        //Asset is protected
        //Must be played only via MPPlayer
    } else {
        //Asset is not protected
        //Can be played both via AVPlayer & MPPlayer\
    }
} else {
    //probably the asset is not avilable offline
    //Must be played only via MPPlayer
}

Another correct way of checking for DRM-protected asset is by making use of protectedAsset property of MPMediaItem - an answer by @weirdyu. But, this property is available only on iOS 9.2 and above.

Swift 4 solution for this method (works perfectly for me on iOS 9.2 and above):

if #available(iOS 9.2, *) {
    if (targetMPMediaItem?.hasProtectedAsset)! {
        //asset is protected
        //Must be played only via MPMusicPlayer
    } else {
        //asset is not protected
        //Can be played both via AVPlayer & MPMusicPlayer
    }
} else {
    //Fallback on earlier versions
    //Probably use the method explained earlier
}
Lipase answered 7/12, 2017 at 11:49 Comment(0)
B
1

iOS9.2+: Please use MPMediaItem "protectedAsset" property

iOS9.2-: Judge MPMediaItem"assetURL"property is nil or not

Broaddus answered 7/11, 2017 at 12:25 Comment(2)
this property is available only on iOS 9.2 and aboveLipase
@Mohit Singh Thanks for your comment, I have add something.Broaddus
C
0

Justin Kents' solution works great. I recommend using blocks though or else the UX will suffer if you deal with a bunch of songs:

-(void)checkDRMprotectionForItem:(MPMediaItem*)item OnCompletion:(void (^)(BOOL drmProtected))completionBlock
{
    dispatch_async(_drmCheckQueue, ^{
        BOOL drmStatus;
        NSURL* assetURL = [item valueForProperty:MPMediaItemPropertyAssetURL];
        if (!assetURL) {
            drmStatus = YES;
        }

        dispatch_async(dispatch_get_main_queue(), ^{
            if (completionBlock) {
                completionBlock(drmStatus);
            }
    });
    });
}
Codeine answered 19/5, 2014 at 8:44 Comment(0)
D
0

Now I'm building on swift 2 for ios 9, I found my code broken using hasProtectedContent or using nil url test. I've found the following code work:

    let playerItem = AVPlayerItem(URL: mpMediaItem.assetURL!)
    playableByAVPlayer = (playerItem.status == .ReadyToPlay) ? true : false

If the item is not playable by AV Player, then it's a DRM item and should be played by iPod Player (now called SystemMusicPlayer).

Decurved answered 4/10, 2015 at 5:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.