iOS AVPlayer音频开发

前言

AVPlayer属于AVFoundation框架,不仅能够播放音频,还可以播放视频,支持播放本地和网络音视频,更加接近底层,定制也更加灵活。

首先了解一下音频播放的实现级别:

(1)离线播放:这里并不是指应用不联网,而是指播放本地音频文件,包括先下完完成音频文件在进行播放的情况,这种使用AVFoundation里的AVAudioPlayer可以满足。

(2)在线播放:使用AVFoundation的AVPlayer可以满足。

(3)在线播放同时储存文件:使用AudioFileStreamer + AudioQueue可以满足。

(4)在线播放且带有音效处理:使用AudioFileStreamer + AudioQueue + 音效模块(系统自带或者自行开发)来满足。

本文主要针对第二种级别,介绍如何使用AVPlayer实现网络音频的播放。

什么是AVPlayer

AVPlayer继承NSObject,存在于AVFoundation,单独使用AVPlayer时是无法显示视频的,必须将视频图层添加到AVPlayerLayer中方能显示视频。使用AVPlayer首先了解一下几个常用的类:

1、AVAsset:AVAsset类专门用于获取多媒体的相关信息,包括获取多媒体的画面、声音等信息,属于一个抽象类,不能直接使用。
2、AVURLAsset:AVAsset的子类,可以根据一个URL路径创建一个包含媒体信息的AVURLAsset对象。
3、AVPlayerItem:一个媒体资源管理对象,管理者视频的一些基本信息和状态,一个AVPlayerItem对应着一个视频资源。
4、AVPlayer:播放器。
5、CMTime:是一个结构体,里面存储着当前的播放进度,总的播放时长。

AVPlayer的使用

1.实例化一个AVPlayer:

- (AVPlayer *)player {
    if (_player == nil) {
        _player = [[AVPlayer alloc] init];
        _player.volume = 1.0; // 默认最大音量
    }
    return _player;
}

2.播放一个音频:

@property (nonatomic, strong) AVPlayerItem   *currentPlayerItem;
#pragma mark - play
- (void)playWithURL:(NSString *)playItemURL{
    //缓存实现播放,可自行查找AVAssetResourceLoader资料,或采用AudioQueue实现
    _currentPlayerItem = [AVPlayerItem playerItemWithURL:playItemURL];
    _player = [[AVPlayer alloc]initWithPlayerItem:_currentPlayerItem];
    [self addMusicTimeMake]; //监听时间变化
    _isPlay = YES;
    [_player play];  //需要注意的是初始化完player之后不一定会马上开始播放,需要等待player的状态变为ReadyToPlay才会进行播放。
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playbackFinished:) name:AVPlayerItemDidPlayToEndTimeNotification object:_currentPlayerItem];  //播放完后进行回调。播放完后一般都会进行播放下一首的操作。
    
}



3.监听self.player.currentItem:

1、监听status有三种状态:
typedef NS_ENUM(NSInteger, AVPlayerStatus) {
	AVPlayerStatusUnknown,
	AVPlayerStatusReadyToPlay,
	AVPlayerStatusFailed
};
2、监听loadedTimeRanges(缓冲进度),可以进行缓冲进度条的设置

注意:一般初始化player到播放都会经历Unknown到ReadyToPlay这个过程,网络情况良好时可能不会出现Unknown状态的提示,网络情况差的时候Unknown的状态可能会持续比较久甚至可能不进入ReadyToPlay状态,针对这种情况我们要做特殊的处理。

状态查询代码:

/** 状态查询 */
- (NSInteger )playerStatus{
    if (_currentPlayerItem.status == AVPlayerItemStatusReadyToPlay) {
        return 1;
    }else{
        return 0;
    }
}

清空播放器监听属性代码:

//清空播放器监听属性
- (void)releasePlayer{
    
    if (!self.currentPlayerItem) {
        return;
    }
    
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    [self.player removeObserver:self forKeyPath:@"status"];
    
    self.currentPlayerItem = nil;
}

4.播放器的常用操作:

暂停:

[_player pause];

上一首、下一首:

这里我们有两种方式可以实现,一种是有你自行控制下一首歌曲的item,将其替换到当前播放的item:

/** 播放下一曲 */
- (void)playNextMusic{
    if (_currentPlayerItem) {
        if (_indexPathRow < _rowNumber-1) {
            _indexPathRow++;
        }else{
            _indexPathRow = 0;
        }
    }
    NSURL *musicURL = [self.tracksVM playURLForRow:_indexPathRow];
    _currentPlayerItem = [AVPlayerItem playerItemWithURL:musicURL];
    _player = [[AVPlayer alloc]initWithPlayerItem:_currentPlayerItem];
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    
    [self addMusicTimeMake];
    _isPlay = YES;
    [_player play];
    
    [self.delegate changeMusic];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playbackFinished:) name:AVPlayerItemDidPlayToEndTimeNotification object:[self.player currentItem]];
}

另一种是使用AVPlayer的子类AVQueuePlayer来播放多个item,调用 advanceToNextItem来播放下一首:

NSArray * items = @[item1, item2, item3 ....];
AVQueuePlayer * queuePlayer = [[AVQueuePlayer alloc]initWithItems:items];

5.NowPlayingCenter

NowPlayingCenter可以在锁屏界面展示音乐的信息,达到增强用户体验的作用,他可以控制的范围包括:

锁屏界面上显示的歌曲播放信息和图片

iOS7之后控制中心上显示的歌曲播放信息

iOS7之前双击home键后出现的进程中向左滑动出现的歌曲播放信息

AppleTV,AirPlay中显示的播放信息

车载系统中显示的播放信息

这些信息的显示都由MPNowPlayingInfoCenter类来控制。

#pragma mark - 锁屏时候的设置,效果需要在真机上才可以看到
- (void)updateLockedScreenMusic{
    
    // 播放信息中心
    MPNowPlayingInfoCenter *center = [MPNowPlayingInfoCenter defaultCenter];
    
    // 初始化播放信息
    NSMutableDictionary *info = [NSMutableDictionary dictionary];
    // 专辑名称
    info[MPMediaItemPropertyAlbumTitle] = [self playMusicName];
    // 歌手
    info[MPMediaItemPropertyArtist] = [self playSinger];
    // 歌曲名称
    info[MPMediaItemPropertyTitle] = [self playMusicTitle];
    // 设置图片
    info[MPMediaItemPropertyArtwork] = [[MPMediaItemArtwork alloc] initWithImage:[self playCoverImage]];
    // 设置持续时间(歌曲的总时间)
    [info setObject:[NSNumber numberWithFloat:CMTimeGetSeconds([self.player.currentItem duration])] forKey:MPMediaItemPropertyPlaybackDuration];
    // 设置当前播放进度
    [info setObject:[NSNumber numberWithFloat:CMTimeGetSeconds([self.player.currentItem currentTime])] forKey:MPNowPlayingInfoPropertyElapsedPlaybackTime];
    
    // 切换播放信息
    center.nowPlayingInfo = info;
 
}

NowPlayingCenter并不需要每一秒都去刷新(设置),它是根据你设置的PlaybackRate来计算进度条展示的进度,比如你PlaybackRate传1,那就是1秒刷新一次进度显示,当然暂停播放的时候它也会自动暂停。那什么时候设置Now Playing Center比较合适呢?对于播放网络音乐来说,需要刷新的有几个时间点:当前播放的歌曲变化时(如切换到下一首)、当前歌曲信息变化时(如从Unknown到ReadyToPlay)、当前歌曲拖动进度时。如果有读者是使用百度音乐听歌的话,会发现其带有锁屏歌词,其实它是采用“将歌词和封面合成新的图片设置为NowPlayingCenter的封面 + 歌词跃进时刷新NowPlayingCenter来实现的。

6.Remote Control控制音乐的播放

Remote Control可以让你在不打开APP的情况下控制其播放,最常见的出现于锁屏界面、从屏幕底部上拉、耳机线控、Apple TV和AirPlay中显示的播放操作区域和车载系统的设置,可以达到增强用户体验的作用。
我们在AppDelegate里去设置Remote Control:
声明接收Remote Control事件:
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
重写方法,成为第一响应者:
- (BOOL)canBecomeFirstResponder {    
    return YES;
}
对事件进行处理:
- (void)remoteControlReceivedWithEvent:(UIEvent *)event {       
    switch (event.subtype)    {        
        case UIEventSubtypeRemoteControlPlay:
            //播放
            [self.player startPlay];
         
            break;        
        case UIEventSubtypeRemoteControlPause:    
            //暂停        
            [self.player pausePlay];
           
            break;        
        case UIEventSubtypeRemoteControlNextTrack:
            //下一首
            [self.player playNextSong];

            break;        
        case UIEventSubtypeRemoteControlTogglePlayPause:  
            //耳机的播放或暂停          
            self.player.isPlaying ? [self.player pausePlay] : [self.player startPlay];           
            
            break;        
        default:            
            break;    }
}



示例代码

本文demo



后记

对于AVPlayer的简单介绍就到这吧!有啥疑问大家可以评论留言都能看到或者指正我的错误。我会及时改正。











评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值