由于最近工作量非常饱和,所以这第七篇来的有点晚(创建时间是9月7日。。说出来都是泪)。
现在市面上的音乐播放器都支持iPod Library歌曲(俗称iPod音乐或者本地音乐)的播放,用户对于iPod音乐播放的需求也一直十分强烈。这篇要讲的是如何来播放iPod Library的歌曲。
概述
根据官方文档描述Apple从iOS 3.0开始允许开发者访问用户的iPod library来获取用户放在其中的歌曲等多媒体内容。
为此Apple提供了多种方法来访问和播放iPod中的音乐,下面我们来分别列举一下这些方法。
访问MediaLibrary
官方文档访问iPod Library的方法有两种,分别是MediaPicker和MediaQuery。
MediaPicker
MediaPicker是一个高度封装的iPod Library访问方式,通过使用MPMediaPickerController
类来访问iPod Library。这是一个UI控件,用户可以根据需要选择其中的音乐。这个类使用时非常方便,只需要生成一个“的实例,设置一下属性和delegate后present出来,接下来只要等待回调即可,在回调时需要手动dismiss picker。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | |
上面的代码将会得到如下的效果:
通过MediaPicker最终可以得到MPMediaItemCollection
,其中存放着所有在Picker中选中的歌曲,每一个歌曲使用一个MPMediaItem
对象表示。对于MediaPicker的使用也可以参考官方文档。
MediaQuery
如果你觉得MeidaPicker的功能或者UI不能满足你的要求那么可以使用MediaQuery。MediaQuery可以直接访问iPod Library的DB,并根据需要获取数据。官方文档给出了MediaQuery的示意图。
MediaQuery功能十分强大,它可以根据一个或多个条件查询满足需要的MediaItem。
你可以使用MPMediaQuery
的类方法来生成一些已经预置了条件的Query
1 2 3 4 5 6 7 8 9 10 11 | |
也可以自己生成MPMediaPredicate
设置条件,并把它加到Query中,最后通过items和collections访问查询到的结果,例如:
1 2 3 4 5 6 7 8 9 10 11 | |
这一过程可以表示为(图来自官方文档):
这里对于MediaQuery的用法就不再继续展开,关于这块内容并没有什么晦涩难懂的地方需要解释,大家可以通过阅读官方文档来详细了解其用法。
MediaCollection
MPMediaCollection
是MediaItem的合集,可以通过访问它的items属性来访问所有的MediaItem。
MPMediaPlaylist
是一个特殊的MPMediaCollection
代表用户创建的播放列表,它会比MediaCollection包含更多的信息,比如播放列表的名字等等。这些属性可以通过MPMediaEntity
的方法访问(MPMediaCollection是MPMediaEntity的子类,MPMediaItem也是)。
1 2 3 4 5 6 7 | |
MediaItem
通过MediaPicker和MediaQuery最终都会得到MPMediaItem
,这个item中包含了许多信息。这些信息都可以通过MPMediaEntity
的方法访问,其中参数非常多就不列举了具体可以参照MPMediaItem.h。
使用MPMusicPlayerController
拿到iPod Library中的歌曲后就可以开始播放了。播放的方式有很多种,先介绍一下MediaPlayer framework
中的MPMusicPlayerController
类。
通过MPMusicPlayerController
的类方法可以生成两种播放器,生成方法如下:
1 2 3 4 5 | |
这两个方法看似生成了一样的对象,但它们的行为却有很大不同。从Apple写的注释上我们可以很清楚的发现它们的区别。+applicationMusicPlayer
不会继承来自ios系统自带的iPod应用中的播放状态,同时也不会覆盖iPod的播放状态。而+iPodMusicPlayer
完全继承iPod应用的播放状态(甚至是播放时间),对其实例的任何操作也会覆盖到iPod应用。对+iPodMusicPlayer
方法command+点击后可以看到更详细的注释。
1 2 3 4 5 6 7 | |
说白了,当在使用iPodMusicPlayerv其实并不是你的程序在播放音频,而是你的程序在操纵iPod应用播放音频,即使你的程序crash了或者被kill了,音乐也不会因此停止。
而对于+applicationMusicPlayer
通过command+点击可以看到:
1 2 | |
从注释中可以知道这个方法返回的对象虽然不是调用iPod应用播放的也不会影响到iPod应用,但它有个很大的缺点:无法后台播放,即使你在active了audioSession并且在app的设置中设置了Background Audio同样不会奏效。
综上所述,一般在开发音乐软件时很少用到这两个接口来进行iPod Library的播放,大部分开发者都是用这个类中的volme来调整系统音量的(这个属性在SDK 7中也被deprecate掉了)。如果你想用到这个类进行播放的话,这里需要提个醒,给MPMusicPlayerController
设置需要播放的音乐时要使用下面两个方法:
1 2 3 | |
而不是这个属性:
1 2 3 | |
光看名字很容易被nowPlayingItem
这个属性迷惑,它的意思其实是说在设置了MediaQuery或者MediaCollection之后再设置这个nowPlayingItem可以让播放器从这个item开始播放,前提是这个item需要在MediaQuery或者MediaCollection的.items集合内。
使用AVAudioPlayer和AVPlayer
除了使用MediaPlayer中的类还有很多其他方法来进行iPod播放,其中做的比较出色的是AVFoundation
中的AVAudioPlayer
和AVPlayer
。
这两个类的都有通过NSURL生成实例的初始化方法:
1 2 3 4 5 6 | |
其中的NSURL正是来自于MPMediaItem
的MPMediaItemPropertyAssetURL
属性。
1 2 3 4 | |
上面讲到MPMediaItem
时已经提到了它是MPMediaEntity
子类,可以通过-valueForProperty:
方法访问其中的属性。通过传入MPMediaItemPropertyAssetURL
就可以得到当前MediaItem对应的URL(ipod-library://xxxxx),生成Player进行播放。大致代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | |
注意:这里我需要更正一下,之前我在第二篇讲到AudioSession时写了这样一段话在使用AVAudioPlayer/AVPlayer时可以不用关心AudioSession的相关问题,Apple已经把AudioSession的处理过程封装了...
。这段话不对,我把AVFoundation和Mediaplayer混淆了,在写的时候也没注意,应该是在使用MPMusicPlayerController播放时不需要关心AudioSession的问题。
读取和导出数据
前面说到使用MPMediaItem
的MPMediaItemPropertyAssetURL
属性可以得到一个表示当前MediaItem的NSURL,有了这个NSURL我们使用AVFoundation中的类进行播放。播放只是最基本的需求,有了这个URL我们可以做更多更有趣的事情。
在AVFoundation中还有两个有趣的类:AVAssetReader
和AVAssetExportSession
。它们可以把iPod Library中的指定歌曲以指定的音频格式导出到内存中或者硬盘中,这个指定的格式包括PCM。这是一个激动人心的特性,有了PCM数据我们就可以做很多很多其他的事情了。
这部分如果要展开的话还会有相当多的内容,国外的先辈们早在2010年就已经发掘了这两个类的用法,详细参见这里和这里。这两篇讲的比较详细并且附有Sample(其中还涉及了一些Extended Audio File Services的内容),如果里面Sample无法下载可以从点击MediaLibraryExportThrowaway1.zip和VTM_AViPodReader.zip下载。
需要注意的是在使用AVAssetReader
的过程中如果访问系统的相机或者照片可能会使AVAssetReader
产生AVErrorOperationInterrupted
错误,此时需要重新生成Reader后调用-startReading
才可以继续读取数据。
小结
本篇介绍了一些与iPod Library相关的内容,小结一下:
-
Apple提供两种方法来访问iPod Library,它们分别是
MPMediaPickerController
和MPMediaQuery
; -
MPMediaPickerController
和MPMediaQuery
最后输出给开发者的对象是MPMediaItem
,MPMediaItem
的属性需要通过-valueForProperty:
方法获取了; -
MPMusicPlayerController
可以用来播放MPMediaItem
,但有很多局限性,使用时需要根据不同的使用场景来决定用哪个类方法生成实例; -
AVAudioPlayer
和AVPlayer
也可以用来播放MPMediaItem
,这两个类的功能比较完善,推荐使用,在使用之前别忘记设置AudioSession; -
MPMediaItem
可以得到对应的URL,这个URL可以用来做很多事情,例如用AVAssetReader
和AVAssetExportSession
可以导出其中的数据;
下篇预告
下一篇会讲一些关于NowPlayingCenter和RemoteControl的内容(就是在锁屏界面和ControlCenter中显示的歌曲信息以及上面的那些播放控制按钮)。
参考资料
iPod Library Access Programming Guide
From iPhone Media Library to PCM Samples in Dozens of Confounding, Potentially Lossy Steps
From iPod Library to PCM Samples in Far Fewer Steps Than Were Previously Necessary