gpt4 book ai didi

swift - 直播流中的 AVPlayer 音频缓冲

转载 作者:搜寻专家 更新时间:2023-10-31 08:33:24 25 4
gpt4 key购买 nike

我正在制作一个使用 AVPlayer(单个播放/暂停按钮)流式传输实时音频的应用程序。应用程序工作正常,但是由于这是实时音频,如果出现轻微的网络问题,音频会停止并且播放器不会继续播放,即使按下播放/暂停按钮。恢复应用程序的唯一方法是终止它并每次重启。

有人可以建议 AVPlayer 的任何东西或替代品,或者我如何缓冲音频以便在连接丢失时播放器会同时缓冲它?我是IOS编程的新手。赞赏

最佳答案

我遇到了同样的问题。答案是创建一个错误委托(delegate),每次播放器停止时都会启动一个选择器(当网络连接中断或流未正确加载时,错误会发生变化):

这是我的代表,就在我的 RadioPlayer 类之外和上方:

protocol errorMessageDelegate {
func errorMessageChanged(newVal: String)
}

protocol sharedInstanceDelegate {
func sharedInstanceChanged(newVal: Bool)
}

现在我的课:

import Foundation
import AVFoundation
import UIKit

class RadioPlayer : NSObject {

static let sharedInstance = RadioPlayer()
var instanceDelegate:sharedInstanceDelegate? = nil
var sharedInstanceBool = false {
didSet {
if let delegate = self.instanceDelegate {
delegate.sharedInstanceChanged(self.sharedInstanceBool)
}
}
}
private var player = AVPlayer(URL: NSURL(string: Globals.radioURL)!)
private var playerItem = AVPlayerItem?()
private var isPlaying = false

var errorDelegate:errorMessageDelegate? = nil
var errorMessage = "" {
didSet {
if let delegate = self.errorDelegate {
delegate.errorMessageChanged(self.errorMessage)
}
}
}

override init() {
super.init()

errorMessage = ""

let asset: AVURLAsset = AVURLAsset(URL: NSURL(string: Globals.radioURL)!, options: nil)

let statusKey = "tracks"

asset.loadValuesAsynchronouslyForKeys([statusKey], completionHandler: {
var error: NSError? = nil

dispatch_async(dispatch_get_main_queue(), {
let status: AVKeyValueStatus = asset.statusOfValueForKey(statusKey, error: &error)

if status == AVKeyValueStatus.Loaded{

let playerItem = AVPlayerItem(asset: asset)

self.player = AVPlayer(playerItem: playerItem)
self.sharedInstanceBool = true

} else {
self.errorMessage = error!.localizedDescription
print(error!)
}

})


})

NSNotificationCenter.defaultCenter().addObserverForName(
AVPlayerItemFailedToPlayToEndTimeNotification,
object: nil,
queue: nil,
usingBlock: { notification in
print("Status: Failed to continue")
self.errorMessage = "Stream was interrupted"
})

print("Initializing new player")

}

func resetPlayer() {
errorMessage = ""

let asset: AVURLAsset = AVURLAsset(URL: NSURL(string: Globals.radioURL)!, options: nil)

let statusKey = "tracks"

asset.loadValuesAsynchronouslyForKeys([statusKey], completionHandler: {
var error: NSError? = nil

dispatch_async(dispatch_get_main_queue(), {
let status: AVKeyValueStatus = asset.statusOfValueForKey(statusKey, error: &error)

if status == AVKeyValueStatus.Loaded{

let playerItem = AVPlayerItem(asset: asset)
//playerItem.addObserver(self, forKeyPath: "status", options: NSKeyValueObservingOptions.New, context: &ItemStatusContext)

self.player = AVPlayer(playerItem: playerItem)
self.sharedInstanceBool = true

} else {
self.errorMessage = error!.localizedDescription
print(error!)
}

})
})
}

func bufferFull() -> Bool {
return bufferAvailableSeconds() > 45.0
}

func bufferAvailableSeconds() -> NSTimeInterval {
// Check if there is a player instance
if ((player.currentItem) != nil) {

// Get current AVPlayerItem
let item: AVPlayerItem = player.currentItem!
if (item.status == AVPlayerItemStatus.ReadyToPlay) {

let timeRangeArray: NSArray = item.loadedTimeRanges
if timeRangeArray.count < 1 { return(CMTimeGetSeconds(kCMTimeInvalid)) }
let aTimeRange: CMTimeRange = timeRangeArray.objectAtIndex(0).CMTimeRangeValue
//let startTime = CMTimeGetSeconds(aTimeRange.end)
let loadedDuration = CMTimeGetSeconds(aTimeRange.duration)

return (NSTimeInterval)(loadedDuration);
}
else {
return(CMTimeGetSeconds(kCMTimeInvalid))
}
}
else {
return(CMTimeGetSeconds(kCMTimeInvalid))
}
}

func play() {
player.play()
isPlaying = true
print("Radio is \(isPlaying ? "" : "not ")playing")
}

func pause() {
player.pause()
isPlaying = false
print("Radio is \(isPlaying ? "" : "not ")playing")
}

func currentlyPlaying() -> Bool {
return isPlaying
}

}

现在,在 RadioViewController 中:

import UIKit
import AVFoundation

class RadioViewController: UIViewController, errorMessageDelegate, sharedInstanceDelegate {

// MARK: Properties

var firstErrorSkip = true
var firstInstanceSkip = true

@IBOutlet weak var listenLabel: UILabel!
@IBOutlet weak var radioSwitch: UIImageView!

@IBAction func back(sender: AnyObject) {
print("Dismissing radio view")
if let navigationController = self.navigationController
{
navigationController.popViewControllerAnimated(true)
}
}

@IBAction func switched(sender: AnyObject) {
toggle()
}

override func viewDidLoad() {
super.viewDidLoad()

do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
print("AVAudioSession Category Playback OK")
do {
try AVAudioSession.sharedInstance().setActive(true)
print("AVAudioSession is Active")

} catch let error as NSError {
print(error.localizedDescription)
}
} catch let error as NSError {
print(error.localizedDescription)
}

RadioPlayer.sharedInstance.errorDelegate = self
RadioPlayer.sharedInstance.instanceDelegate = self

if RadioPlayer.sharedInstance.currentlyPlaying() {
radioSwitch.image = UIImage(named: "Radio_Switch_Active")
listenLabel.text = "Click to Pause Radio Stream:"
}

}

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}

func toggle() {
if RadioPlayer.sharedInstance.currentlyPlaying() {
pauseRadio()
} else {
playRadio()
}
}

func playRadio() {
firstErrorSkip = false
firstInstanceSkip = false

if RadioPlayer.sharedInstance.errorMessage != "" || RadioPlayer.sharedInstance.bufferFull() {
resetStream()
} else {
radioSwitch.image = UIImage(named: "Radio_Switch_Active")
listenLabel.text = "Click to Pause Radio Stream:"
RadioPlayer.sharedInstance.play()
}
}

func pauseRadio() {
RadioPlayer.sharedInstance.pause()
radioSwitch.image = UIImage(named: "Radio_Switch_Inactive")
listenLabel.text = "Click to Play Radio Stream:"
}

func resetStream() {
print("Reloading interrupted stream");
RadioPlayer.sharedInstance.resetPlayer()
//RadioPlayer.sharedInstance = RadioPlayer();
RadioPlayer.sharedInstance.errorDelegate = self
RadioPlayer.sharedInstance.instanceDelegate = self
if RadioPlayer.sharedInstance.bufferFull() {
radioSwitch.image = UIImage(named: "Radio_Switch_Active")
listenLabel.text = "Click to Pause Radio Stream:"
RadioPlayer.sharedInstance.play()
} else {
playRadio()
}
}

func errorMessageChanged(newVal: String) {
if !firstErrorSkip {
print("Error changed to '\(newVal)'")
if RadioPlayer.sharedInstance.errorMessage != "" {
print("Showing Error Message")
let alertController = UIAlertController(title: "Stream Failure", message: RadioPlayer.sharedInstance.errorMessage, preferredStyle: UIAlertControllerStyle.Alert)
alertController.addAction(UIAlertAction(title: "Dismiss", style: UIAlertActionStyle.Default, handler: nil))

self.presentViewController(alertController, animated: true, completion: nil)

pauseRadio()

}
} else {
print("Skipping first init")
firstErrorSkip = false
}
}

func sharedInstanceChanged(newVal: Bool) {
if !firstInstanceSkip {
print("Detected New Instance")
if newVal {
RadioPlayer.sharedInstance.play()
}
} else {
firstInstanceSkip = false
}
}

}

关于swift - 直播流中的 AVPlayer 音频缓冲,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32614060/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com