美文网首页iOS Developer
AVPlayer循环播放音频、锁屏界面远程控制、

AVPlayer循环播放音频、锁屏界面远程控制、

作者: 波罗超人 | 来源:发表于2017-08-24 14:52 被阅读0次

    AVPlayer可以用来播放音频和视频,今天要说的就是用AVPlayer的一个子类 AVQueuePlayer来播放音频、这个类可以用来播放队列,当前AVPlayerItem播放完了,如果nextItem存在就会自动播放下一个Item,比AVPlayer要方便一点。

    一、后台播放设置
    先导入两个框架

    #import <AVFoundation/AVFoundation.h>
    #import <MediaPlayer/MediaPlayer.h>
    

    设置后台播放

       AVAudioSession *session = [AVAudioSession sharedInstance];
        [session setActive:YES error:nil];
        [session setCategory:AVAudioSessionCategoryPlayback error:nil];
    
    屏幕快照 2017-08-24 下午2.09.25.png

    二、AVQueuePlayer初始化

    -(void)initPlayer{
        //准备数据 一个本地MP3和一个URL MP3
        AVPlayerItem*firstItem = [AVPlayerItem playerItemWithURL:[NSURL fileURLWithPath: [[NSBundle mainBundle] pathForResource:@"那些花儿" ofType:@"mp3"]]];
        AVPlayerItem*secondItem = [AVPlayerItem playerItemWithURL:[NSURL URLWithString:@"http://sc1.111ttt.com/2015/1/06/06/99060941326.mp3"]];
        
        SongModel*firstModel = [[SongModel alloc]init];
        firstModel.songName = @"那些花儿";
        firstModel.singer = @"朴树";
        firstModel.picture = [UIImage imageNamed:@"pushu.jpg"];
        firstModel.duration = 294;
        firstModel.item = firstItem;
        
        SongModel*secondModel = [[SongModel alloc]init];
        secondModel.songName = @"演员";
        secondModel.singer = @"薛之谦";
        secondModel.picture = [UIImage imageNamed:@"xue.png"];
        secondModel.duration = 262;
        secondModel.item = secondItem;
        _songInfoArray = @[firstModel,secondModel];
        
    //这里初始化设置一个或多个都是可以的,这里我设置一个的原因主要是上一曲和下一曲的时候会清空items
        self.player = [[AVQueuePlayer alloc]initWithItems:@[firstItem]];
        
        _index = 0;
    // item和player都有status 属性 通常我们观察item的status 是因为可以检测资源是否可以播放,当然这里直接调用play方法也是可以直接播放的
        [firstItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playeyEnd:) name:AVPlayerItemDidPlayToEndTimeNotification object:nil];
    }
    

    初始化完成之后直接调用[AVPlayer play]也是可以直接播放的,但是资源出现问题的话还是需要手动处理的所以我们在这里对Item添加了一个观察者,并对AVPlayer播放完成添加了一个通知。

    通知和观察者模式实现代码

    ///播放结束
    -(void)playeyEnd:(NSNotification*)notify{
        NSLog(@"end");
        [self nextSong];
        
    }
    
    ///AVPlayerItem observer
    -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
        AVPlayerItem*item = (AVPlayerItem*)object;
        if ([keyPath isEqualToString:@"status"]) {
            if (item.status==AVPlayerItemStatusReadyToPlay) {
                NSLog(@"play");
                
                [self setLockScreenNowPlayingInfo];
                
                [item removeObserver:self forKeyPath:@"status"];
                
                [self.player play];
    
            }
            
            if (item.status==AVPlayerItemStatusFailed) {
                
                NSLog(@"filad");
                
                [self setLockScreenNowPlayingInfo];
                
                [item removeObserver:self forKeyPath:@"status"];
                
                [self nextSong];
            }
        }
    }
    

    切歌控制

    #warning 在同一时间内一个item只能占用一个位置、所以这里是先删除,再添加
    -(void)nextSong{
        //下一首
        if (_index==_songInfoArray.count-1) {
            _index =0;
        }else{
            _index++;
        }
        SongModel*model = _songInfoArray[_index];
        [model.item addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];
        [self.player removeAllItems];
        [self.player insertItem:model.item afterItem:nil];
        [self.player seekToTime:kCMTimeZero];
        
        [self setLockScreenNowPlayingInfo]; 
    }
    
    -(void)lastSong{
        //上一首
        if (_index==0) {
            _index =_songInfoArray.count-1;
            
        }else{
            _index--;  
        }
        SongModel*model = _songInfoArray[_index];
        [model.item addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];
        [self.player removeAllItems];
        [self.player insertItem:model.item afterItem:nil];
        [self.player seekToTime:kCMTimeZero];
        [self setLockScreenNowPlayingInfo];
    }
    

    这里有一个小坑、AVQueuePlayer提供了跳转到下一个Item的方法

    - (void)advanceToNextItem;
    

    却没有提供LastItem的方法,所以要实现LastItem的方法我是通过来实现的

    [self.player insertItem:model.item afterItem:nil]; 
    

    特别提醒在同一时间同一个Item只能加入一次,所以在insert之前需要将之前的Item删除掉、我选择了删除全部、这样同一时间PlayerQueue中就只存在一个Item了、我觉得这样更容易控制一点。而关于 [self.player seekToTime:kCMTimeZero]; 这个是为了让Item上一次的播放时间置零,如果不置零就会继续播放(感觉这个功能播放视频的时候这个还是比较好用的);

    三、注册远程控制(锁屏界面控制和耳机控制)

    需要先让应用能够接受远程控制,并成为第一响应者

    屏幕快照 2017-08-24 下午2.11.29.png
    #pragma mark - 远程控制接收方法的设置
    - (void)remoteControlReceivedWithEvent:(UIEvent *)event {
        if (event.type == UIEventTypeRemoteControl) {  //判断是否为远程控制
            switch (event.subtype) {
                case  UIEventSubtypeRemoteControlPlay:
                {
                    if (!_isPlaying) {
                        [self.player play];
                    }
                    _isPlaying=!_isPlaying;
                }
                    break;
                case UIEventSubtypeRemoteControlPause:
                {
                    if (_isPlaying) {
                        [self.player pause];
                    }
                    _isPlaying = !_isPlaying;
                }
                    break;
                case UIEventSubtypeRemoteControlNextTrack:
                {
                    [self nextSong];
                }
                    break;
                case UIEventSubtypeRemoteControlPreviousTrack:
                {
                    [self lastSong];
                }
                    break;
                default:
                    break;
            }
        }
    }
    

    四、设置锁屏信息
    期间我看了网易云音乐的锁屏效果、设置了lyrics,结果我这里设置了并没有什么效果。。。

    ///设置锁屏信息
    - (void)setLockScreenNowPlayingInfo
    {
        SongModel*model = self.songInfoArray[_index];
        //更新锁屏时的歌曲信息
        MPMediaItemArtwork *artWork = [[MPMediaItemArtwork alloc] initWithImage:model.picture];
        
        NSDictionary *dic = @{MPMediaItemPropertyTitle:model.songName,
                              MPMediaItemPropertyArtist:model.singer,
                              //                          MPMediaItemPropertyLyrics:@"hello lyrics break ",
                              //                          MPMediaItemPropertyReleaseDate:@"2017-08-23",//唱片发布日期
                              MPMediaItemPropertyPlaybackDuration:@(model.duration),//设置锁屏界面歌曲时间
                              MPMediaItemPropertyArtwork:artWork//锁屏界面图片
                              };
        [[MPNowPlayingInfoCenter defaultCenter] setNowPlayingInfo:dic];
    }
    

    最后附上真机锁屏的效果以及Demo地址
    https://github.com/LuoCongMing/AVQueuePlayerDemo.git

    IMG_1878.PNG

    相关文章

      网友评论

        本文标题:AVPlayer循环播放音频、锁屏界面远程控制、

        本文链接:https://www.haomeiwen.com/subject/jtepvttx.html