问题有:
1. 关于网络上的数据流播放,之前是使用github上的AudioStream库进行网络歌曲的播放。但是这么做之后发现跟AVPlayer(播放ipod歌曲)发生冲突,于是AudioSteamer库就只能放弃了。
2. 关于ipod的歌曲播放,基本上无法操作ipod的歌曲,如果要通过dlna传送本机ipod的歌曲,那么必须先将ipod的歌转存到本地,这个过程比较麻烦,于是放弃了。
3. ipod的歌曲读取需要通过MediaPlayer、MediaItem来读取ipod的数据。
4. 在线音乐、流媒体、直播流都可以通过AVPlayer来播放,而不再使用AudioStreamer。
5. ipod的歌曲播放可以用MediaPlayer中的IpodPlayer来播放,但是保存方便还是使用AVPlayer。
6. AVPlayer可以播放本地歌曲,因此从网络下载的本地歌曲也可以是用这个来播放。
7. AVPlayer类有个子类,AVQueuePlayer,可以添加队列进行控制播放。
总结:音乐播放器必须使用AVPlayer,可以播放应用内保存的音乐,播放网络音乐,播放网络电台、播放ipod音乐,设置后台播放,设置封面,还可以创建播放队列。
关于AVPlayer的使用有几个问题:
1. 设置后台播放
在info.plist中需要添加Required background modes,并且添加值App plays audio
在应用的delegate中Launch函数里添加代码
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Override point for customization after application launch. { if([application respondsToSelector:@selector(beginReceivingRemoteControlEvents)]) [application beginReceivingRemoteControlEvents]; [self becomeFirstResponder]; // this enables listening for events [[AVAudioSessionsharedInstance] setCategory:AVAudioSessionCategory Playbackerror:nil]; [[AVAudioSessionsharedInstance] setActive: YES error: nil]; } return YES; } - (BOOL)canBecomeFirstResponder{ return YES; }
setCategory这个方法设定了这个应用的声音播放实例可以在后台播放,并且音频播放是可打断或被打断的。
delegate要继承UIResponser借口,beginReceivingControlEvents调用后就可以接受ipod control的消息。
becomeFirstResponder方法使用后会在ipod control有响应后将消失传递到这个类做响应。
2. 后台播放时,ipod control的点击事件响应。
在appdelegate中(因为设置成了响应者)加入响应代码
- (void)remoteControlReceivedWithEvent:(UIEvent *)event { switch (event.subtype) { case UIEventSubtypeRemoteControlTogglePlayPause: NSLog(@"play btn toggle"); break; case UIEventSubtypeRemoteControlPlay: NSLog(@"play event"); break; case UIEventSubtypeRemoteControlPause: NSLog(@"pause event"); break; case UIEventSubtypeRemoteControlStop: NSLog(@"stop event"); break; case UIEventSubtypeRemoteControlPreviousTrack: NSLog(@"prev event"); break; case UIEventSubtypeRemoteControlNextTrack: NSLog(@"next event"); break; default: break; } }
这里做音乐播放器后台ipod操作的响应控制。
3. 后台播放时,设置ipod control的封面图片,歌曲名等信息。通过设置当前媒体播放器的信息来实现。
在应用弹出去或者歌曲切换事件出发的时候调用该函数。
- (void)configNowPlayingInfoCenter { if (NSClassFromString(@"MPNowPlayingInfoCenter")) { MPNowPlayingInfoCenter *center = [MPNowPlayingInfoCenter defaultCenter]; UIImage *image = [UIImage imageNamed:@"figo.png"]; MPMediaItemArtwork *artwork = [[MPMediaItemArtwork alloc] initWithImage:image]; NSDictionary*songInfo = [NSDictionary dictionaryWithObjectsAndKeys: @"华哥", MPMediaItemPropertyArtist, @"嘿嘿", MPMediaItemPropertyTitle, artwork, MPMediaItemPropertyArtwork, @"嘿嘿", MPMediaItemPropertyAlbumTitle, nil]; center.nowPlayingInfo = songInfo; } }
在这些时候可以触发:
- (void)applicationDidEnterBackground:(UIApplication *)application { [self configNowPlayingInfoCenter]; }
-(void)playerItemDidReachEnd:(NSNotification *)notification { [self configNowPlayingInfoCenter]; }
4. 音乐播放队列的播放顺序是通过监听音乐播放结束或开始,再做相应的处理,在appdelegat中监听事件。这些事件需要Audio框架中开启。
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playerItemDidReachEnd:) name:AVPlayerItemDidPlayToEndTimeNotification object:[player currentItem]];
监听这些事件后,进行播放队列调整。或者是ipod control切换歌曲的时候调整ipod封面和歌名。
5. 使用AVPlayer播放歌曲
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playerItemDidReachEnd:) name:AVPlayerItemDidPlayToEndTimeNotification object:[player currentItem]]; AVPlayerItem *item1 = [AVPlayerItem playerItemWithURL:[NSURL URLWithString:@"http://192.168.1.127/5.mp3"]]; AVPlayerItem *item2 = [AVPlayerItem playerItemWithURL:[NSURL URLWithString:@"http://192.168.1.127/1.mp3"]]; AVPlayerItem *item3 = [AVPlayerItem playerItemWithAsset:[AVAsset assetWithURL:[NSURL URLWithString:@"http://shoutmedia.abc.net.au:10326"]]]; AVPlayerItem *item4 = [AVPlayerItem playerItemWithAsset:[AVAsset assetWithURL:[NSURL URLWithString:@"http://192.168.1.127/1.mp3"]]]; NSArray *items = @[item3,item4]; queuePlayer = [AVQueuePlayer queuePlayerWithItems:items];
[queuePlayer play];
有队列,通过事件回调控制封面和播放顺序的方式。
6. 播放ipod的歌曲
要使用Mediaplayer库,Audio库
MPMediaQuery *myPlaylistsQuery = [MPMediaQuery songsQuery]; NSArray *playlists = [myPlaylistsQuery collections]; GDSongNet *newSong; NSMutableArray *array = [[NSMutableArray alloc] init];; for (MPMediaPlaylist *playlist in playlists) { newSong = nil; newSong = [[GDSongNet alloc] init]; NSArray *songs = [playlist items]; for (MPMediaItem *song in songs) { newSong.songStatusType = [NSNumber numberWithInt:PLAYER_LOCAL]; newSong.songCoverUrl = @"/Public/Images/nopic_80x80.jpg"; newSong.songMusic_id = [song valueForProperty:MPMediaItemPropertyPersistentID];//MPMediaItemPropertyPersistentID newSong.songMusic_name = [song valueForProperty:MPMediaItemPropertyTitle]; newSong.songSinger = [song valueForProperty:MPMediaItemPropertyArtist];// newSong.songType_id = [NSNumber numberWithInt:1]; newSong.songUrl = [song valueForProperty:MPMediaItemPropertyAssetURL]; [array addObject:newSong]; } } self.localMusics = array;
7. AVPlayer检索元数据
元数据的数组:
NSArray *metaDatas = [[[mPlayercurrentItem] asset] commonMetadata];
遍历获取数据
for (AVMetadataItem* item in mMetadata) { NSString* commonKey = [item commonKey]; if ([commonKey isEqualToString:AVMetadataCommonKeyTitle]) { [mTitleLabel setText:[item stringValue]]; [mTitleLabel setHidden:NO]; } if ([commonKey isEqualToString:AVMetadataCommonKeyCopyrights]) { [mCopyrightLabel setText:[item stringValue]]; [mCopyrightLabel setHidden:NO]; } }
附件:测试项目