iOS 音视频播放

栏目: IOS · 发布时间: 5年前

内容简介:按公司需求需要对音频文件进行后台播放,借此机会对音频播放做了个总结.主要针对 AVPlayer 进行详细说明.AVPlayer 是iOS上常用的视频播放器组件,支持常见的音视频格式,支持流播放,可以播放在线音乐.支持视频格式: WMV,AVI,MKV,RMVB,RM,XVID,MP4,3GP,MPG等。

按公司需求需要对音频文件进行后台播放,借此机会对音频播放做了个总结.主要针对 AVPlayer 进行详细说明.

iOS 各播放器比较

名称 使用环境 优点 确点
System Sound Services AVFoundation C语言的底层写法,节省内存 支持的格式有限,音量无法通过音量键控制,而且播放方式单一。
AVAudioPlayer AVFoundation 抒写效率更高,基本上支持所有的音频格式,对播放的控制,如循环播放,声音大小,暂停等比较方便。 对内存的消耗会多些。不支持流式,即无法播放在线音乐。
AVPlayer AVFoundation 可以播放音视频,可播放在线音乐,使用灵活
MPMoviePlayerController MediaPlayer 简单易用 不可定制
AVPlayerViewController AVKit 简单易用 不可定制
IJKPlayer IJKMediaFramework 定制度高,支持流媒体播放 使用稍复杂

AVPlayer 使用

简介

AVPlayer 是iOS上常用的视频播放器组件,支持常见的音视频格式,支持流播放,可以播放在线音乐.

支持视频格式: WMV,AVI,MKV,RMVB,RM,XVID,MP4,3GP,MPG等。

支持音频格式:MP3,WMA,RM,ACC,OGG,APE,FLAC,FLV等。

相关类

  • AVPlayer:播放器,控制播放器的播放,暂停,播放速度.
  • AVURLAsset : AVAsset 的一个子类,使用 URL 进行实例化,实例化对象包换 URL 对应视频资源的所有信息.
  • AVPlayerItem:管理资源对象,提供播放数据源.
  • AVPlayerLayer:负责显示视频,如果没有添加该类,只有声音没有画面.

简单使用

使用 url 创建 AVPlayer

let player = AVPlayer(url: URL(string: "http://www.xxxx.mp3"))
复制代码

使用 AVPlayerItem 创建 AVPlayer

if let url = URL(string: "http://www.***.mp3") {
    let asset = AVAsset(url: url)
    guard asset.isPlayable else{
        // 检测文件是否可播放
        return
    }
    let playItem = AVPlayerItem(asset: asset)
    let player = AVPlayer(playerItem: playItem)
    player.play()
}
复制代码

AVPlayer 控制播放

player.play() // 播放
player.pause() //暂停
player.rate = 1.0 // 播放速度 
复制代码

通过通知监听播放状态变化

//播放完成
AVPlayerItemDidPlayToEndTimeNotification
//播放失败
AVPlayerItemFailedToPlayToEndTimeNotification
//异常中断
AVPlayerItemPlaybackStalledNotification

// eg: 播放结束通知
NotificationCenter.default.addObserver(self, selector: #selector(finish(_:)), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: nil)
复制代码

监听播放进度

// 添加周期时间观察者 一秒执行一次 block
let timeObserver = player.addPeriodicTimeObserver(forInterval: CMTime(seconds: 1, preferredTimescale: 1), queue: DispatchQueue.main, using: { [weak self] (cmTime) in
    if let totalTime = self?.currentPlayItem?.duration {
        self?.delegate?.player(self!, currentTime: cmTime.seconds, totalTime: totalTime.seconds)
    }
})
// 不要忘记移除
player.removeTimeObserver(observer)
复制代码

AVPlayerItem 创建

// 使用 AVAsset 创建
if let url = URL(string: "http://www.***.mp3") {
    let asset = AVAsset(url: url)
    guard asset.isPlayable else{
        // 检测文件是否可播放
        return
    }
    let playItem = AVPlayerItem(asset: asset)
}

// 使用 URL 创建
if let url = URL(string: "http://www.***.mp3") {
    let playItem = AVPlayerItem(url: url)
}
复制代码

监听 AVPlayerItem 状态和缓存进度

// 监听 playerItem 状态变化
playItem.addObserver(self, forKeyPath: "status", options: .new, context: nil)
// 监听缓存时间
playItem.addObserver(self, forKeyPath: "loadedTimeRanges", options: .new, context: nil)

// 移除监听
currentPlayItem?.removeObserver(self, forKeyPath: "status")
currentPlayItem?.removeObserver(self, forKeyPath: "loadedTimeRanges")
复制代码
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    
    if object is AVPlayerItem {
        if keyPath == "status" {
            if let playerItem = object as? AVPlayerItem {
                switch playerItem.status {
                case .readyToPlay:
                    // 准备播放
                case .failed:
                    // 加载失败                    
                default:
                    // 未知状态
                }
            }
        }
        
        if keyPath == "loadedTimeRanges" {
            if let playerItem = object as? AVPlayerItem {
                if let timeRange = playerItem.loadedTimeRanges.first as? CMTimeRange {
                    let cache = timeRange.start.seconds + timeRange.duration.seconds // 缓存总时长
                }
            }
        }
    }
复制代码

音频后台播放

开启所需后台模式

利用 AVAudioSession 申请后台播放权限

let session = AVAudioSession.sharedInstance()
do {
    try session.setActive(true)
    try session.setCategory(AVAudioSessionCategoryPlayback)
} catch {
    print(error)
}
复制代码

在播放控制界面接受远程控制(Remote Control)

开启远程控制

// 声明接收Remote Control事件
UIApplication.shared.beginReceivingRemoteControlEvents()
复制代码

设置 Remote Control 响应

// 响应 Remote Control事件
MPRemoteCommandCenter.shared().playCommand.addTarget(self, action: #selector(play))
MPRemoteCommandCenter.shared().nextTrackCommand.addTarget(self, action: #selector(next))
MPRemoteCommandCenter.shared().pauseCommand.addTarget(self, action: #selector(pause))
MPRemoteCommandCenter.shared().previousTrackCommand.addTarget(self, action: #selector(previous))
复制代码

移除 Remote Control 响应

// 在关闭播放页面时记得移除
MPRemoteCommandCenter.shared().playCommand.removeTarget(self, action: #selector(play))
MPRemoteCommandCenter.shared().nextTrackCommand.removeTarget(self, action: #selector(next))
MPRemoteCommandCenter.shared().pauseCommand.removeTarget(self, action: #selector(pause))
MPRemoteCommandCenter.shared().previousTrackCommand.removeTarget(self, action: #selector(previous))
// 停止响应 Remote Control
UIApplication.shared.endReceivingRemoteControlEvents()
复制代码

通过重写父类方法响应外部事件

  • 开启接受远程控制

  • 使当前页面成为第一响应者

  • 重写 remoteControlReceivedWithEvent 方法. UIEvent Type 取值:

    • UIEventSubtypeRemoteControlTogglePlayPause // 暂停
    • UIEventSubtypeRemoteControlPreviousTrack // 上一首
    • UIEventSubtypeRemoteControlNextTrack // 下一首
    • UIEventSubtypeRemoteControlPlay // 播放
    • UIEventSubtypeRemoteControlPause // 暂停
  • 关闭接受远程控制

锁屏页面显示播放信息(Now Playing Center)

使用 MPNowPlayingInfoCenter 设置锁屏页面音乐信息.

func setLockScreenPlayingInfo(_ info: YTTMediaInfo) {
    // Now Playing Center可以在锁屏界面展示音乐的信息,也达到增强用户体验的作用。
    // https://www.jianshu.com/p/458b67f84f27
    var infoDic: [String : Any] = [:]
    infoDic[MPMediaItemPropertyTitle] = info.title // 歌曲名
    infoDic[MPMediaItemPropertyArtist] = info.singer // 歌手
    if let img = info.image {
        infoDic[MPMediaItemPropertyArtwork] = MPMediaItemArtwork(image: img) // 专辑图片
    }
    infoDic[MPMediaItemPropertyPlaybackDuration] = info.totalTime // 歌曲总时长
    infoDic[MPNowPlayingInfoPropertyElapsedPlaybackTime] = info.currentTime // 当前播放时间
    infoDic[MPNowPlayingInfoPropertyPlaybackRate] = 1.0 // 播放速度
    MPNowPlayingInfoCenter.default().nowPlayingInfo = infoDic
}
复制代码

注意: MPNowPlayingInfoPropertyElapsedPlaybackTime 设置的并不是时时的,他是根据你设置的值进行计时的,如果想要在锁屏页面得到准确的时间,请及时刷新 MPNowPlayingInfoPropertyElapsedPlaybackTime 的值.当暂停时要暂停播放时间,只需将 MPNowPlayingInfoPropertyPlaybackRate 设置为 0.播放时设置回 1.

补充说明

iOS 对后台管理十分严格,任何 app 都有大约3分钟或者10分钟的后台执行时间.3分钟或者10分钟后, app 就会被强制挂起.使用 AVAudioSession 申请后台权限时,可以保证播放本地音乐能在后台长久播放,当播放网络音乐时就会出现不能播放情况,针对这情况使用了 beginBackgroundTask 设置后台任务 ID,通过这种方式我们大约可以获得额外的 10 分钟来执行后台任务.为了能无限后台播放网络音乐添加计时器,当即将挂起时再次申请后台任务 ID.

func applicationDidEnterBackground(_ application: UIApplication) {
    
    // 这样做,可以在按home键进入后台后 ,播放一段时间,几分钟吧。但是不能持续播放网络歌曲,若需要持续播放网络歌曲,还需要申请后台任务id
    bgTask = application.beginBackgroundTask(expirationHandler: nil)
    timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(timerAction), userInfo: nil, repeats: true)
}

@objc func timerAction() {
    timerCount = timerCount + 1
    if timerCount < 500 {
        return
    }
    timerCount = 0
    let newTask = UIApplication.shared.beginBackgroundTask(expirationHandler: nil)
    if bgTask != UIBackgroundTaskInvalid && newTask != UIBackgroundTaskInvalid {
        UIApplication.shared.endBackgroundTask(bgTask)
        bgTask = newTask
    }
    
}
复制代码

其他


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

商业的常识

商业的常识

申音 / 山西经济出版社 / 2011-7-1 / 35.00元

★为什么美国没有史玉柱,中国没有乔布斯? ★什么是“对的行业”、“错的行业”? ★我们需要什么样的营销? ★老板为什么要读商学院? ★山寨公司还需要管理吗? ★资源问题是个“伪问题”? ★别把商业模式当成葵花宝典 ★给海归技术创业兄弟的九个忠告 ★在一个不伟大的行业里,做一个伟大的公司 ★是什么让互联网遭遇了有史以来最鸡犬不宁的一战?一起来看看 《商业的常识》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具