什么是AVAudioPlayer
AVAudioPlayer是AVFoundation框架里面提供的类,专门用于播放本地或者内存数据中的音频数据。它支持循环播放、多文件同时播放、定点播放等功能。 详情参考这里
基本使用
初始化
self.player = try AVAudioPlayer(data: data)
self.player = try AVAudioPlayer(contentsOf: localFileUrl)
播放/暂停
[player play];
[player pause];
播放完成回调
设置player的代理并实现AVAudioPlayerDelegate协议
self.player?.delegate = self
// MARK: AVAudioPlayerDelegate
extension AudioPlayer: AVAudioPlayerDelegate {
func audioPlayerDecodeErrorDidOccur(_ player: AVAudioPlayer, error: Error?) {
progressTimer.invalidate()
}
func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
progressTimer.invalidate()
playFinished?(flag)
}
}
播放网络音频文件
由于AVAudioPlayer只可以通过文件或者data实例化,因此可以先下载缓存本地再播放。推荐使用NSURLCache进行文件缓存管理,因为NSURLCache提供了一套API进行缓存保存和读取,方便使用。
/// 播放器管理及数据缓存管理
class AudioPlayerManager: NSObject {
static let shared = AudioPlayerManager()
private override init() {
super.init()
}
/// about cache
private lazy var downloadQueue = DispatchQueue.global()
private let allowedDiskSize = 100 * 1024 * 1024
private let diskCachePath = "mp3Cache"
private lazy var cache = URLCache(memoryCapacity: 0, diskCapacity: allowedDiskSize, diskPath: diskCachePath)
private lazy var playerHash = [String: AudioPlayer]()
func prepareDataForPlay(_ path: String, ready: ((AudioPlayer?)->Void)? = nil) {
guard !IsNilOrEmptyString(path) else {
ready?(nil)
return
}
downloadQueue.async {
self.downloadContent(fromUrlString: path, completionHandler: { (result) in
switch result {
case .success(let data):
// handle data
let audioPlayer = AudioPlayer(data: data)
DispatchQueue.main.async {
self.playerHash[path] = audioPlayer
if ready == nil {
audioPlayer.play()
}
ready?(audioPlayer)
}
case .failure(let error):
debugPrint(error.localizedDescription)
DispatchQueue.main.async {
ready?(nil)
}
}
})
}
}
func stopPlayers() {
playerHash.values.forEach { (player) in
player.stop()
}
}
}
// MARK: cache
extension AudioPlayerManager {
typealias DownloadCompletionHandler = (Result<Data, Error>) -> Void
private func createAndRetrieveURLSession() -> URLSession {
let sessionConfiguration = URLSessionConfiguration.default
sessionConfiguration.requestCachePolicy = .returnCacheDataElseLoad
sessionConfiguration.urlCache = cache
return URLSession(configuration: sessionConfiguration)
}
private func downloadContent(fromUrlString: String, completionHandler: @escaping DownloadCompletionHandler) {
guard let downloadUrl = URL(string: fromUrlString) else { return }
let urlRequest = URLRequest(url: downloadUrl)
// First try to fetching cached data if exist
if let cachedData = self.cache.cachedResponse(for: urlRequest) {
print("Cached data in bytes:", cachedData.data)
completionHandler(.success(cachedData.data))
} else {
// No cached data, download content than cache the data
createAndRetrieveURLSession().dataTask(with: urlRequest) { (data, response, error) in
if let error = error {
completionHandler(.failure(error))
} else {
let cachedData = CachedURLResponse(response: response!, data: data!)
self.cache.storeCachedResponse(cachedData, for: urlRequest)
completionHandler(.success(data!))
}
}.resume()
}
}
}