如何在 iOS 中使用 AVPlayer 缓冲音频?

2024-05-07

我想播放来自互联网的流音频。我编写了播放流的代码,但它没有任何缓冲区,因此如果信号较弱,应用程序将停止播放音频。这是我的代码:

import UIKit
import AVFoundation
import MediaPlayer
import AudioToolbox

class ViewController: UIViewController {

var playerItem:AVPlayerItem?
var player:AVPlayer?

@IBOutlet weak var PlayButton: UIButton!

override func viewDidLoad() {
    super.viewDidLoad()

    var buffer = AVAudioBuffer ()
    let url = NSURL (string: "http://radio.afera.com.pl/afera64.aac")
    playerItem = AVPlayerItem(URL: url!)
    player = AVPlayer(playerItem: playerItem!)

}

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

@IBAction func PlayButtonTapped(sender: AnyObject)
{
    if ((player!.rate != 0) && (player!.error == nil))
    {
        player!.pause()
        PlayButton.setImage(UIImage(named:"Play"), forState: UIControlState.Normal)
    }
    else
    {
        player!.play()
        PlayButton.setImage(UIImage(named:"Stop"), forState:UIControlState.Normal)
    }
}
}

我不知道如何缓冲这个流。我搜索了苹果文档,但在 Swift 中找不到任何内容。

我发现类似的东西AVAudioBuffer但我不知道如何使用它,也不知道它是否可以正确解决这个问题。

P.S. C#有文档MSDN,Apple 上的 Swift 是否有类似的情况?


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

以下是代表,位于我的 RadioPlayer 类的外部和上方:

protocol errorMessageDelegate {
func errorMessageChanged(newVal: String)
}

class:

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
}

}
protocol sharedInstanceDelegate {
func sharedInstanceChanged(newVal: Bool)
}

无线电视图控制器:

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
    }
}

}

希望这会有所帮助:)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在 iOS 中使用 AVPlayer 缓冲音频? 的相关文章

  • 将 UIToolBar 添加到所有键盘(swift)

    我正在尝试以尽可能少的重复次数将自定义 UIToolBar 添加到我的所有键盘中 我目前的做法要求我将代码添加到所有 viewDidLoads 中 并将每个文本字段的委托分配给我正在使用的 viewController 我尝试创建自己的 U
  • 从 Nodejs 提供二进制/缓冲区/base64 数据

    我在从节点提供二进制数据时遇到问题 我开发了一个名为的节点模块节点说话它执行 TTS 文本到语音 并返回 Base64 编码的音频文件 到目前为止 我这样做是为了转换base64到缓冲区 二进制文件 然后提供它 var src Base64
  • Flutter 应用程序在 iOS 平台的 firebase 电话身份验证中崩溃

    我在我的项目中实现了 Firebase Phone auth 在 Android 端 一切正常 但对于 iOS 端 当我尝试从我的端发送验证码时 应用程序崩溃并失去连接 我已在下面提交了我的代码 主程序 dart class MyApp e
  • 有没有办法在 Firebase 中等待查询完成?

    我正在使用 TableView 在 Viewcontroller 中的 iOS 应用程序中进行查询 我想确保在继续加载 TableView 之前我的查询已经返回 有没有办法保证查询已经完成 None
  • 我的 UICollectionView 无法使用 Swift 平滑滚动

    我有一个CollectionView它使单元出队取决于message类型 例如 文本 图像 我遇到的问题是当我向上 向下滚动时滚动确实很不稳定 因此用户体验不是很好 这仅在第一次加载单元格时发生 之后滚动就会平滑 我有什么想法可以解决这个问
  • SwiftUI:隐藏键盘但显示光标

    我想使用自定义按钮将文本输入到TextField 但仍显示并移动光标 有没有办法隐藏默认键盘 同时仍然显示光标 我希望有这样的事情 TextField text text keyboardType none 这是它目前的样子 您可以使用UI
  • 在 java 类和 android 活动之间传输时音频不清晰

    我有一个android活动 它连接到一个java类并以套接字的形式向它发送数据包 该类接收声音数据包并将它们扔到 PC 扬声器 该代码运行良好 但在 PC 扬声器中播放声音时会出现持续的抖动 中断 安卓活动 public class Sen
  • 在 iOS 上使用 RNCryptor 异步解密大文件

    我需要在 iOS 上使用 RNCryptor 异步解密一个大文件 以便显示进度条 我在任何地方都找不到示例 因此尝试了我猜对的方法 但是 我想出的方法不起作用 解密器的处理程序从未被调用 并且线程在发送所有数据后因 EXC BAD ADDR
  • 关闭捕获上下文 Swift

    当我尝试更改闭包中的变量时出现此错误 A C function pointer cannot be formed from a closure that captures context 是否有解决方法或者仍然可以更改闭包内的变量 My C
  • Android MediaExtractor seek() 对 MP3 音频文件的准确性

    我在使用 Android 时无法在eek 上获得合理的准确度MediaExtractor 对于某些文件 例如this one http www archive org download emma solo librivox emma 01
  • NSPredicate IN 从数组元素查询

    对于一个古怪的标题表示歉意 我有一个 Int 数组 我想定义一个 NSPredicate 来过滤掉 connectionType 等于数组中包含的值的项目 所以基本上是这样的 fetchRequest predicate NSPredica
  • 根据内容自动更改单元格高度 - Swift

    在 Swift 中使用 UITableView 有人可以帮我根据标签 图片和描述自动更改单元格的高度吗 所有信息都正确传递 我只需要帮助格式化它 我尝试使用调整它cell frame size height 但这没有效果 我可以更改故事板中
  • 通过 Button Swift 中的标签发送行和部分

    我里面有这个cellForRowAtIndexPath cell plusBut tag indexPath row cell plusBut addTarget self action plusHit forControlEvents U
  • Xcode 异步单元测试在主线程上等待

    我正在尝试使用 Xcode 中的单元测试来测试一些异步代码 但主线程被阻塞 问题在于 某些正在测试的代码期望从 iOS 类 AVFoundation 接收回调 但是 AVFoundation 类似乎只会在主线程上回调 问题是 如果我正在进行
  • UICollectionView setLayout:animated: 不保留 zIndex

    我注意到打电话时setLayout animated in a UICollectionView要在两个布局之间切换 当前可见的单元格不遵循zIndex它的布局属性已设置在layoutAttributesForItemAtIndexPath
  • 如何在 Swift 2.0 中使用 stringByAddingPercentEncodingWithAllowedCharacters() 作为 URL

    我在 Swift 1 2 中使用过这个 let urlwithPercentEscapes myurlstring stringByAddingPercentEscapesUsingEncoding NSUTF8StringEncoding
  • 有没有办法在 onclick 触发时禁用 iPad/iPhone 上的闪烁/闪烁?

    所以我有一个有 onclick 事件的区域 在常规浏览器上单击时 它不会显示任何视觉变化 但在 iPad iPhone 上单击时 它会闪烁 闪烁 有什么办法可以阻止它在 iPad iPhone 上执行此操作吗 这是一个与我正在做的类似的示例
  • 诊断和仪器均缺少“僵尸”选项

    运行 Xcode 4 0 2 Zombie 选项丢失 其他 SO 帖子建议找到它的两个地方 Product gt Run looks like this Product gt Profile looks like this 奇怪的是 我之前
  • Mac 上的 Delphi - 可能吗? [关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我负责一个 Delphi Win32 项目管理应用程序 我刚刚完成了向 Delphi 2009 的迁移
  • 在 Object 子类及其自己的子类上实现ignoreProperties()

    我是领域新手 我正在使用继承自 Object 的基类以及该基类的自定义子类创建模型 我的模型要求基类通过覆盖静态来声明一些属性被忽略ignoredProperties 方法 当尝试在某些基类子类上重写该方法时 我收到一个 Swift 编译器

随机推荐

  • 打印 HTML 时删除默认浏览器页眉和页脚

    我得到了一个带有以下内容的 HTML 我想问的问题是 有什么方法可以删除网络浏览器添加到打印页面的字符串吗 Such as 打印页面的网站 页数 网页标题 印刷日期 这些通常是浏览器特定的打印设置 例如 在 IE 和 FireFox 中 您
  • Sweetalert 2 异步文本区域

    我尝试使用这个简单的文档示例https sweetalert2 github io https sweetalert2 github io 但我收到错误消息 未捕获的语法错误 await 仅在异步函数中有效 document ready f
  • Hibernate save() 和事务回滚

    在休眠状态下 当我save 事务中的一个对象 然后我回滚它 保存的对象仍然保留在数据库中 这很奇怪 因为这个问题不会发生在update or delete 方法 只需用save 这是我正在使用的代码 DbEntity dbEntity ge
  • 按升序选择最后 20 个顺序 - PHP/MySQL

    这是我的表结构 MyTable ID P K auto increment TopicID UID Comment 现在我想获取某个 TopicID 的最后 20 条评论 但它应该按升序排序 就像 Facebook 默认只显示最后 20 条
  • Angular刷新页面重复url中的页面

    我是一名 Angular 新手 正在构建一个简单的寻呼机 我设置了路由器 以便空 URL 重定向到仪表板组件 因此localhost 4200会自动路由到localhost 4200 dashboard完美的 但是 如果我单击刷新按钮 它会
  • mysql 更新或插入多条记录(如果表中尚不存在)

    mysql 数据库中有一个名为 inventory item 的表 id product id 和 quantity 是表的列 id 是主键 在插入记录时自动生成 当用户提交要向表中插入多条记录的表单时 可以在 foreach 循环中收集所
  • C4533 警告:为什么 goto 会跳过变量初始化?

    我越来越 警告 C4533 goto FreeDC 跳过了 b 的初始化 但是如果代码到达标签FreeDC in WM CREATE b 未初始化 如果在这种情况下未初始化 如何跳过其初始化 我只是不明白这个警告 include
  • iOS 6 模拟器卡在启动画面上

    我正在使用 Mac os 10 8 2 和 Xcode 4 5 2 当我尝试在 ios 5 5 1 模拟器中运行我的应用程序时 它工作正常 但是当我尝试在 ios 6 模拟器中运行应用程序时 它会卡在空白屏幕上 谁能让我知道我的问题的解决方
  • Gradle 构建错误:aidl.exe 以非零退出值 1 完成

    这是我的 build gradle 文件 点击查看截图 https i stack imgur com ENTbh png 和我的错误 错误 任务 app compileDebugAidl 执行失败 com android ide comm
  • 为 schtasks.exe 指定日期参数的独立于语言的方法

    我正在尝试将新任务添加到 Windows 任务计划程序schtasks exe 我现在遇到的问题是指定任务应该在一周中的哪一天运行 据我所知 愚蠢的程序坚持将该参数作为日期名称的字符串缩写 本地化为操作系统语言 其他参数可以很好地接受英语字
  • 普通的 x86 或 AMD PC 是直接从 ROM 运行启动/BIOS 代码,还是先将其复制到 RAM? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我知道现代计算机已经修改了哈佛架构 它们可以从保存数据的地方以外的地方读取指令 这一事实是否允许它们直接从 ROM 芯片获取指令 他们是先
  • 使用 Proguard 混淆 ActionBarSherlock

    我正在尝试使用混淆我的 Android 应用程序proguard and ant eclipse proguard从来不工作 总是失败error 1 但我越来越class file unexpectedly contains class 到
  • 高性能 C# 服务器套接字的提示/技术

    我有一个 NET 2 0 服务器似乎遇到了扩展问题 可能是由于套接字处理代码的设计不佳 我正在寻找有关如何重新设计它以提高性能的指导 使用场景 50 150 个客户端 每个客户端以高速率 高达 100 秒 秒 发送小消息 每条 10 字节
  • PostgreSQL函数中如何返回查询结果行?

    我按照教程尝试了很多次 但都失败了 有人可以给我一些例子吗 这是我的代码 它提示 ERROR invalid type name SETOF RECORD create or replace function find returns SE
  • Java-&& 评估

    任何人都可以帮助我解决以下问题 我有这样的代码 if cond1 cond2 cond10 这里 cond1 是昂贵的操作 其输出是布尔值 现在我的问题是 当 cond2 输出为 false 时 JAVAC 会做什么 具体来说 它是评估 c
  • 在 RESTful WCF 中混合 XML 和 JSON,无需单独的方法

    我有一个 RESTful WCF 服务 可以返回 XML JSON 或 JSONP 具体取决于参数 例如 service svc stuff format xml or service svc stuff format json callb
  • jQuery 如何修复无法设置未定义的属性“_DT_CellIndex”?

    我是 Jquery 的新手 我希望一旦用户添加新行并在单击 Ajouter 按钮后提供重要信息 它将添加到数据库中 然后自动重新加载表 一旦我运行 我发现数据已成功添加到数据库 但是 tablebqup 不再重新加载 并且我发现了此错误 U
  • SyntaxError: JSON.parse: JSON 数据第 1 行第 1 列出现意外字符

    我花了 6 个多小时在代码中查找异常或特殊字符 但我找不到 我检查了这里所有类似的消息 我正在发送带有放大弹出窗口的表格 首先 我使用内联弹出窗口打开表单 然后将所有输入发送到 main js 进行验证 所以 我只需要第三只眼 我有 ind
  • 如何在 React-Native 中停止触摸事件传播

    我有一个带有图像网格的滚动视图 当我长按图像时 我想停止将鼠标事件传播到滚动视图并仅监视移动 目的是在按下时重新初始化传播 有人知道怎么做吗 将以下内容添加到
  • 如何在 iOS 中使用 AVPlayer 缓冲音频?

    我想播放来自互联网的流音频 我编写了播放流的代码 但它没有任何缓冲区 因此如果信号较弱 应用程序将停止播放音频 这是我的代码 import UIKit import AVFoundation import MediaPlayer impor