AVAudioPlayer、AVPlayer和AVQueuePl

作者: TigerManBoy | 来源:发表于2018-07-23 15:45 被阅读163次

    AVAudioPlayer 简述

    AVAudioPlayer是属于 AVFundation.framework 的一个类,它的功能类似于一个功能强大的播放器,AVAudioPlayer每次播放都需要将上一个player对象释放掉,然后重新创建一个player来进行播放,AVAudioPlayer 支持广泛的音频格式,主要是以下这些格式。

    • ACC
    • AMR(Adaptive multi-Rate,一种语音格式)
    • ALAC (Apple lossless Audio Codec)
    • iLBC (internet Low Bitrate Codec,另一种语音格式)
    • IMA4 (IMA/ADPCM)
    • linearPCM (uncompressed)
    • u-law 和 a-law
    • MP3 (MPEG-Laudio Layer 3)

    AVAudioPlayer 使用

    AVAudioPlayer 初始化
     1. initWithContentsOfURL: error: 从URL加载音频,返回 AVAudioPlayer 对象
     2. initWithData: error: 加载NSdata对象的音频文件,返回 AVAudioPlayer 对象
    
    AVAudioPlayer 方法调用
     //准备播放 可以判断player创建成功之后调用,调用[player play]则可以节省播放之前的间隔时间。
    - (BOOL)prepareToPlay;
    //异步播放
    - (BOOL)play; 
    //在某个时间点播放
    - (BOOL)playAtTime:(NSTimeInterval)time NS_AVAILABLE(10_7, 4_0); 
    //暂停播放,但仍然可以播放
    - (void)pause; 
    //停止播放,不再准备播放了
    - (void)stop; 
    //更新音频测量值,注意如果要更新音频测量值必须设置meteringEnabled为YES,通过音频测量值可以即时获得音频分贝等信息
    - (void)updateMeters; 
    //返回给定通道的分贝峰值功率
    - (float)peakPowerForChannel:(NSUInteger)channelNumber; 
    //获得指定声道的分贝峰值,注意如果要获得分贝峰值必须在此之前调用updateMeters方法
    - (float)averagePowerForChannel:(NSUInteger)channelNumber;
    
    AVAudioPlayer 属性设置
    playing //播放器是否正在播放 获取通过isPlaying
    numberOfChannels //该音频的声道次数,只读
    duration //该音频播放时长
    url //音频文件路径, 只读
    data //音频数据,只读
    pan NS_AVAILABLE(10_7, 4_0) //立体声设置 设为 -1.0 则左边播放 设为 0.0 则中央播放 设为 1.0 则右边播放
    enableRate NS_AVAILABLE(10_8, 5_0);  //是否允许改变播放速率
    rate NS_AVAILABLE(10_8, 5_0); //播放速率 0.5 (半速播放) ~ 2.0(倍速播放) 注1.0 是正常速度
    currentTime //该音频的播放点
    deviceCurrentTime //输出设备播放音频的时间,注意如果播放中被暂停此时间也会继续累加
    numberOfLoops  //循环次数,如果要单曲循环,设置为负数
    volume //播放器的音频增益,值:0.0~1.0
    channelAssignments //获得或设置播放声道
    
    AVAudioPlayer 代理方法
    //音频播放完成
    - (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag;
    //音频解码发生错误
    - (void)audioPlayerDecodeErrorDidOccur:(AVAudioPlayer *)player error:(NSError * __nullable)error
    //如果音频被中断,比如有电话呼入,该方法就会被回调,该方法可以保存当前播放信息,以便恢复继续播放的进度
    - (void)audioPlayerBeginInterruption:(AVAudioPlayer *)player
    

    AVPlayer 简述

    AVPlayer支持播放本地、分步下载、或在线流媒体音视频,不仅可以播放音频,配合AVPlayerLayer类可实现视频播放。另外支持播放进度监听。
    AVPlayer只支持单个媒体资源播放。

    AVPlayer需要配合AVPlayerItem关联来进行媒体播放。

    AVPlayer 使用

    AVPlayer 初始化
    //类方法,从url加载音频
    + (instancetype)playerWithURL:(NSURL *)URL
    //类方法,配合AVPlayerItem使用
    + (instancetype)playerWithPlayerItem:(nullable AVPlayerItem *)item
    //实例方法,从url加载音频
    - (instancetype)initWithURL:(NSURL *)URL
    //实例方法,配合AVPlayerItem使用
    - (instancetype)initWithPlayerItem:(nullable AVPlayerItem *)item
    
    AVPlayer KVO添加监听

    1.播放状态改变监听

    //KVO监听播放状态
    [self.player.currentItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];
    

    处理KVO回调事件

    //处理KVO回调事件
    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
        if ([keyPath isEqualToString:@"status"]) {
            switch (self.player.status) {
                case AVPlayerStatusUnknown:
                    NSLog(@"未知转态");
                    break;
                case AVPlayerStatusReadyToPlay:
                    NSLog(@"准备播放");
                    break;
                case AVPlayerStatusFailed:
                    NSLog(@"加载失败");
                    break;
                    
                default:
                    break;
            }
        }
    }
    

    2.KVO监听音乐缓冲状态

    //KVO监听音乐缓冲状态
    [self.player.currentItem addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil];
    

    处理KVO回调事件

    //处理KVO回调事件
    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
        if ([keyPath isEqualToString:@"loadedTimeRanges"]) {
            
            NSArray *timeRanges = self.player.currentItem.loadedTimeRanges;
            //本次缓冲的时间范围
            CMTimeRange timeRange = [timeRanges.firstObject CMTimeRangeValue];
            //缓冲总长度
            NSTimeInterval totalLoadTime = CMTimeGetSeconds(timeRange.start) + CMTimeGetSeconds(timeRange.duration);
            //音乐的总时间
            NSTimeInterval duration = CMTimeGetSeconds(self.player.currentItem.duration);
            //计算缓冲百分比例
            NSTimeInterval scale = totalLoadTime/duration;
            NSLog(@"---%f,---%f,---%f",totalLoadTime,duration,scale);
            //更新缓冲进度条
            //        self.loadProgress.progress = scale;
            
        }
    }
    
    1. 播放结束事件的监听
    //播放结束事件的监听
    [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(playFinied:) name:AVPlayerItemDidPlayToEndTimeNotification
                                                   object:self.player.currentItem];
    

    处理KVO回调事件

    //播放结束回调
    - (void)playFinied:(AVPlayerItem *)item {
        NSLog(@"播放结束");
        self.slider.value = 0;
    }
    
    1. 开始播放时,通过AVPlayer的方法监听播放进度,并更新进度条(定期监听的方法)
    //开始播放时,通过AVPlayer的方法监听播放进度,并更新进度条(定期监听的方法)
    __weak typeof(self) weakSelf = self;
        [self.player addPeriodicTimeObserverForInterval:CMTimeMake(1.0, 1.0) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {
            //当前播放的时间
            float current = CMTimeGetSeconds(time);
            //总时间
            float total = CMTimeGetSeconds(item.duration);
            if (current) {
                float progress = current / total;
                //更新播放进度条
                weakSelf.slider.value = progress;
            }
        }];
    
    1. 拖动进度条改变播放进度
    //拖动进度条改变播放进度
    - (void)playValueChange:(UISlider *)sender {
        //计算时间
        float time = sender.value * CMTimeGetSeconds(self.player.currentItem.duration);
        //跳到当前指定时间
        [self.player seekToTime:CMTimeMake(time, 1)];
    }
    

    AVQueuePlayer 简述

    AVPlayer只支持单个媒体资源的播放,我们可以使用AVPlayer的子类AVQueuePlayer实现列表播放。在AVPlayer的基础上,增加以下方法:

    //通过给定的AVPlayerItem数组创建一个AVQueuePlayer实例
    + (instancetype)queuePlayerWithItems:(NSArray<AVPlayerItem *> *)items;
    //通过给定的AVPlayerItem数组初始化一个AVQueuePlayer实例
    - (AVQueuePlayer *)initWithItems:(NSArray<AVPlayerItem *> *)items;
    //获取当前播放队列数组
    - (NSArray<AVPlayerItem *> *)items;
    //停止当前播放的,播放队列中的下一首
    - (void)advanceToNextItem;
    //判断是否可以插入AVPlayerItem
    - (BOOL)canInsertItem:(AVPlayerItem *)item afterItem:(nullable AVPlayerItem *)afterItem;
    //往播放队列中插入新的AVPlayerItem
    - (void)insertItem:(AVPlayerItem *)item afterItem:(nullable AVPlayerItem *)afterItem;
    //移除指定的AVPlayerItem
    - (void)removeItem:(AVPlayerItem *)item;
    //移除所有播放队列中的AVPlayerItem
    - (void)removeAllItems;
    

    *官方API中没找到播放上一首的方法,所以其实直接用AVPlayer做列表播放也是可以的,自己维护一个播放列表数组,监听用户点击上一首和下一首按钮,并监听播放结束事件,调用 AVPlayer 实例的replaceCurrentItemWithPlayerItem:方法传入播放列表中的上一首或下一首就行。

    后台播放

    首先在AppDelegate.m的- (BOOL)application:didFinishLaunchingWithOptions:方法中添加代码:

     //设置后台播放功能
    AVAudioSession *session = [AVAudioSession sharedInstance];
    [session setCategory:AVAudioSessionCategoryPlayback error:nil];
    [session setActive:YES error:nil];
    

    然后在info.plist里面配置:

    <key>UIBackgroundModes</key>
    <array>
        <string>audio</string>
    </array>
    

    锁屏信息

    1、在播放控制界面接受远程控制

    - (void)viewWillAppear:(BOOL)animated
    {
        [super viewWillAppear:YES];
        // 开始接受远程控制
        [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
        [self resignFirstResponder];  
    }
    
    - (void)viewWillDisappear:(BOOL)animated
    {
    // 接触远程控制
        [[UIApplication sharedApplication] endReceivingRemoteControlEvents];
        [self becomeFirstResponder];
    }
    // 重写父类成为响应者方法
    - (BOOL)canBecomeFirstResponder
    {
        return YES;
    }
    

    2、对远程控制事件做出相应的操作

    //重写父类方法,接受外部事件的处理
    - (void) remoteControlReceivedWithEvent: (UIEvent *) receivedEvent {
        NSLog(@"remote");
        if (receivedEvent.type == UIEventTypeRemoteControl) {
            
            switch (receivedEvent.subtype) { // 得到事件类型
                    
                case UIEventSubtypeRemoteControlTogglePlayPause: // 暂停 ios6
                    [self.player pause]; // 调用你所在项目的暂停按钮的响应方法 下面的也是如此
                    break;
                    
                case UIEventSubtypeRemoteControlPreviousTrack:  // 上一首
                    
                    [self lastMusic:nil];
                    break;
                    
                case UIEventSubtypeRemoteControlNextTrack: // 下一首
                    [self nextMusic:nil];
                    break;
                    
                case UIEventSubtypeRemoteControlPlay: //播放
                    [self playMusic:nil];
                    break;
                    
                case UIEventSubtypeRemoteControlPause: // 暂停 ios7
                    [self playMusic:nil];
                    break;
                    
                default:
                    break;
            }
        }
    }
    

    3、设置锁屏主题

    //锁屏信息
        NSMutableDictionary *songInfo = [ [NSMutableDictionary alloc] init];
        //锁屏图片
        UIImage *img = [UIImage imageNamed:@"iPhoneX"];
        if (img) {
            MPMediaItemArtwork *albumArt = [[MPMediaItemArtwork alloc]initWithImage:img];
            [songInfo setObject: albumArt forKey:MPMediaItemPropertyArtwork ];
        }
        //锁屏标题
        NSString *title = @"music";
        [songInfo setObject:[NSNumber numberWithFloat:100] forKey:MPMediaItemPropertyPlaybackDuration];
        [songInfo setObject:title forKey:MPMediaItemPropertyTitle];
        [songInfo setObject:title forKey:MPMediaItemPropertyAlbumTitle];
        [[MPNowPlayingInfoCenter defaultCenter] setNowPlayingInfo:songInfo ];
    

    通过耳机、锁屏界面控制

    // 直接使用sharedCommandCenter来获取MPRemoteCommandCenter的shared实例
    MPRemoteCommandCenter *commandCenter = [MPRemoteCommandCenter sharedCommandCenter];
    
    // 启用播放命令 (锁屏界面和上拉快捷功能菜单处的播放按钮触发的命令)
    commandCenter.playCommand.enabled = YES;
    // 为播放命令添加响应事件, 在点击后触发
    [commandCenter.playCommand addTarget:self action:@selector(playAction:)];
    
    // 播放, 暂停, 上下曲的命令默认都是启用状态, 即enabled默认为YES
    // 为暂停, 上一曲, 下一曲分别添加对应的响应事件
    [commandCenter.pauseCommand addTarget:self action:@selector(pauseAction:)];
    [commandCenter.previousTrackCommand addTarget:self action:@selector(previousTrackAction:)];
    [commandCenter.nextTrackCommand addTarget:self action:@selector(nextTrackAction:)];
    
    // 启用耳机的播放/暂停命令 (耳机上的播放按钮触发的命令)
    commandCenter.togglePlayPauseCommand.enabled = YES;
    // 为耳机的按钮操作添加相关的响应事件
    [commandCenter.togglePlayPauseCommand addTarget:self action:@selector(playOrPauseAction:)];
    

    相关文章

      网友评论

        本文标题:AVAudioPlayer、AVPlayer和AVQueuePl

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