实现 AVAssetDownloadURLSession 下载 HLS 流时出错

2024-03-09

我正在尝试为流应用程序实现离线模式。 目标是能够在用户的设备上下载 HLS 流,以便即使用户离线时也可以观看流。

我最近偶然发现本教程 https://developer.apple.com/library/content/documentation/AudioVideo/Conceptual/MediaPlaybackGuide/Contents/Resources/en.lproj/HTTPLiveStreaming/HTTPLiveStreaming.html。 它似乎满足了我试图实现的确切要求,但我在尝试使其工作时遇到了问题。

我创建了一个小 DownloadManager 来应用本教程的逻辑。 这是我的单例类:

import AVFoundation

class DownloadManager:NSObject {

static var shared = DownloadManager()
private var config: URLSessionConfiguration!
private var downloadSession: AVAssetDownloadURLSession!

override private init() {
    super.init()
    config = URLSessionConfiguration.background(withIdentifier: "\(Bundle.main.bundleIdentifier!).background")
    downloadSession = AVAssetDownloadURLSession(configuration: config, assetDownloadDelegate: self, delegateQueue: OperationQueue.main)
}

func setupAssetDownload(_ url: URL) {
    let options = [AVURLAssetAllowsCellularAccessKey: false]

    let asset = AVURLAsset(url: url, options: options)

    // Create new AVAssetDownloadTask for the desired asset
    let downloadTask = downloadSession.makeAssetDownloadTask(asset: asset,
                                                             assetTitle: "Test Download",
                                                             assetArtworkData: nil,
                                                             options: nil)
    // Start task and begin download
    downloadTask?.resume()
}

func restorePendingDownloads() {
    // Grab all the pending tasks associated with the downloadSession
    downloadSession.getAllTasks { tasksArray in
        // For each task, restore the state in the app
        for task in tasksArray {
            guard let downloadTask = task as? AVAssetDownloadTask else { break }
            // Restore asset, progress indicators, state, etc...
            let asset = downloadTask.urlAsset
            downloadTask.resume()
        }
    }
}

func playOfflineAsset() -> AVURLAsset? {
    guard let assetPath = UserDefaults.standard.value(forKey: "assetPath") as? String else {
        // Present Error: No offline version of this asset available
        return nil
    }
    let baseURL = URL(fileURLWithPath: NSHomeDirectory())
    let assetURL = baseURL.appendingPathComponent(assetPath)
    let asset = AVURLAsset(url: assetURL)
    if let cache = asset.assetCache, cache.isPlayableOffline {
        return asset
        // Set up player item and player and begin playback
    } else {
        return  nil
        // Present Error: No playable version of this asset exists offline
    }
}

func getPath() -> String {
    return UserDefaults.standard.value(forKey: "assetPath") as? String ?? ""
}

func deleteOfflineAsset() {
    do {
        let userDefaults = UserDefaults.standard
        if let assetPath = userDefaults.value(forKey: "assetPath") as? String {
            let baseURL = URL(fileURLWithPath: NSHomeDirectory())
            let assetURL = baseURL.appendingPathComponent(assetPath)
            try FileManager.default.removeItem(at: assetURL)
            userDefaults.removeObject(forKey: "assetPath")
        }
    } catch {
        print("An error occured deleting offline asset: \(error)")
    }
}
}

extension DownloadManager: AVAssetDownloadDelegate {
    func urlSession(_ session: URLSession, assetDownloadTask: AVAssetDownloadTask, didLoad timeRange: CMTimeRange, totalTimeRangesLoaded loadedTimeRanges: [NSValue], timeRangeExpectedToLoad: CMTimeRange) {
        var percentComplete = 0.0
        // Iterate through the loaded time ranges
        for value in loadedTimeRanges {
        // Unwrap the CMTimeRange from the NSValue
        let loadedTimeRange = value.timeRangeValue
        // Calculate the percentage of the total expected asset duration
        percentComplete += loadedTimeRange.duration.seconds / timeRangeExpectedToLoad.duration.seconds
    }
        percentComplete *= 100

    debugPrint("Progress \( assetDownloadTask) \(percentComplete)")

    let params = ["percent": percentComplete]
    NotificationCenter.default.post(name: NSNotification.Name(rawValue: "completion"), object: nil, userInfo: params)
    // Update UI state: post notification, update KVO state, invoke callback, etc.
}

func urlSession(_ session: URLSession, assetDownloadTask: AVAssetDownloadTask, didFinishDownloadingTo location: URL) {
    // Do not move the asset from the download location
    UserDefaults.standard.set(location.relativePath, forKey: "assetPath")
}

func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
    debugPrint("Download finished: \(location)")
}

func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
    debugPrint("Task completed: \(task), error: \(String(describing: error))")

    guard error == nil else { return }
    guard let task = task as? AVAssetDownloadTask else { return }

    print("DOWNLOAD: FINISHED")
}
}

当我尝试打电话给我的时候,我的问题就出现了setupAssetDownload功能。 每次我尝试恢复 downloadTask 时,我都会在urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?)委托功能。

消息的日志是:

任务完成:<__nscfbackgroundavassetdownloadtask>{任务标识符:1},错误:可选(错误 Domain=AVFoundationErrorDomain Code=-11800 \"操作无法 已完成\" UserInfo={NSLocalizedFailureReason=未知错误 发生(-12780),NSLocalizedDescription=操作无法进行 完全的})

为了向您提供我通过的 URL 的所有相关信息setupAssetDownload函数的类型是URL(string: "https://bitdash-a.akamaihd.net/content/MI201109210084_1/m3u8s/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.m3u8")!

我一直在寻找这个错误的原因和解决方案,但我似乎暂时无法找到。 我将非常感谢有关如何解决此问题的任何提示或任何线索,或者我的单例实现中可以解释此行为的任何错误指示。

先感谢您。

Martin

EDIT:

看来这个bug是发生在模拟器上的。我在真实设备上启动我的应用程序,下载开始没有任何问题。希望这可以帮助。仍然不明白为什么我不能在模拟器上尝试这种行为。


None

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

实现 AVAssetDownloadURLSession 下载 HLS 流时出错 的相关文章

  • 选择 UITableViewCell 时 UIView 背景颜色消失

    我在界面生成器中构建了一个简单的 tableViewCell 它包含一个包含图像的 UIView 现在 当我选择单元格时 会显示默认的蓝色选择背景 但 UIView 的背景颜色消失了 我的 UITableViewCell 的实现文件没有做任
  • iOS WKWebView 处理文件下载

    我面临以下问题 在 Web 界面中 文件下载是通过锚标记触发的 如下所示 a href bla blabla a 虽然 Safari 浏览器可以处理此请求并打开一个对话框来处理文件 但 WKWebView 将此视为普通链接并且不对其执行任何
  • 如何在 iOS 中将 Firebase 对象持久保存到磁盘?

    看起来Firebase http www firebase comiOS 实现不支持客户端模型的离线缓存 这在实践中意味着 对于需要身份验证的 Firebase 应用程序 您需要首先进行身份验证并等待 Firebase 完成登录 检查用户身
  • 如何在应用程序项目中使用 Cocoa Touch 框架

    我熟悉构建单个 iOS 应用程序 但我坚持使用 Cocoa Touch 框架向多个应用程序共享通用代码 问题 框架的头文件不可见 无法链接到消费应用程序项目 我做了什么 1 我创建了一个名为 libTestFramework 的项目 Coc
  • 在 UITextView 中获取 HTML

    我在中显示htmlUITextView by self textView setValue b Content b forKey contentToHTMLString 编辑内容后UITextView 我想获取包含 html 的内容 所以我
  • SceneKit unproject Z 文档解释?

    我正在经历一些 SceneKit 概念 而我试图在脑海中巩固的一个概念是 unprojectPoint 我知道该函数将获取 2D 中的一个点并返回 3D 中的一个点 因此具有正确的 Z 值 当我阅读文档时 我读到了以下内容 method u
  • 使用自动布局、IB 和字体大小时表头视图高度错误

    我正在尝试为我的 uiTableView 创建一个标题视图 不是节标题 我已经有了 我已经在界面生成器中设置了一个 XIB 所有的连接都已连接好并且运行良好 除了桌子没有给它足够的空间 我的问题是表格顶部与表格标题有一点重叠 我的 XIB
  • 如何编辑应用程序包中的文件?

    在我的应用程序中 我从存储在捆绑资源中的 CSV 文件加载数据 但是 我希望能够在用户点击 更新 按钮时以编程方式更新此文件 有没有办法以编程方式更改应用程序包中的资源 这是我用来访问该文件的代码 NSString path NSBundl
  • Apple Developer 应用程序门户不再可以生成新的 Bundle Seed ID

    iOS 开发者门户中的新界面不再为您的应用程序 ID 提供 生成新的 按钮 取而代之的是 使用团队 ID 这将导致使用相同的种子 ID 任何人都知道为什么要进行更改以及您应该如何使用新的捆绑包种子 ID 随意补一些 不再可能生成新的种子 I
  • 二元运算符“/”不能应用于两个(Int)操作数[重复]

    这个问题在这里已经有答案了 我得到了Binary operator cannot be applied to two Int operands当我将以下代码放入 Xcode 中的 Swift Playground 时出错 func sumO
  • 是否可以使用UIPageControl来控制UITableView的移动?

    从Apple示例 PageControl 中我们可以知道UIPageControl可以用来控制scrollview中页面的移动 由于 UITableView 是 UIScrollView 的子类 我想使用 UIPageControl 来控制
  • NSURLCache 不缓存

    我正在使用 Xcode 6 1 6A1030 iOS7 和 iOS8 模拟器 NSURLCache 似乎没有缓存任何东西 我使用 Cache Control 标头 我的服务器返回带有 max age 6000 的 Cache Control
  • 为arm64或arm7s编译OpenSSL FIPS功能库时出现未知的cpu类型

    我可以成功 至少没有警告并生成 a 文件 针对 arm7 x86 64 和 i386 进行编译 当我编译arm64时 我得到Unknown cpu type 100000c no adjustments made 当我编译arm7s时 我得
  • 在 Swift 中以编程方式为 iOS 制作带有名字首字母的图像,例如 Gmail

    我需要在 UITableView 中显示与其姓名相对应的每个用户的个人资料图片 在下载图像之前 我需要显示一张带有他名字的第一个字母的图像 就像在 GMail 应用程序中一样 如何在 Swift for iOS 中以编程方式执行此操作 不需
  • UILabel 中的文本未垂直居中

    我使用以下代码创建了一个标签 func setupValueLabel valueLabel numberOfLines 1 valueLabel font UIFont name Avenir Black size 50 valueLab
  • iOS Swift 和 reloadRowsAtIndexPaths 编译错误

    我与 xCode Swift 陷入僵局并刷新 UITableView 的单行 这条线有效 self tableView reloadData 而这条线没有 self tableView reloadRowsAtIndexPaths curr
  • 领域:结果 和列表

    是否可以转换Results
  • 下载进度条在 iOS 企业发行版中没有改变进度

    我正在通过企业分发开发和分发 iPad 应用程序 它们下载并执行良好 因此一切正常 Web 链接 ipa 文件 plist 文件 配置 问题 是 当用户单击链接进行下载时 iPad 中显示下载进度的进度条显示 正在等待 但却是空的并且永远不
  • 如何将自定义 C 代码放入 SwiftPM 包中?

    我正在尝试将 C 代码打包到 Swift 模块中 我们称之为CModule 一旦我将其放入项目的基本文件夹中 Swift模块 并配置了搜索路径 我可以在 Swift 文件中自动完成工作 并检测错误 警告 问题是 导入时它无法识别该模块 并且
  • 如何观察UserDefaults的变化?

    我有一个 ObservedObject在我看来 struct HomeView View ObservedObject var station Station var body some View Text self station sta

随机推荐

  • 无法连接,因为目标机器主动拒绝 127.0.0.1:2382

    我正在尝试连接 SSAS 引擎 SQL Server Denali 但失败并出现以下错误 无法建立连接 因为目标计算机主动拒绝它 127 0 0 1 2382 SSAS 服务在网络服务帐户下运行 SQL 浏览器服务在本地系统帐户上运行 你运
  • 仅使用 Yocto/bitbake 快速重建设备树?

    因此 每次修改设备树时 我通常会更改自定义配方中的 dts 并重建映像 重建需要很长时间 因为它会重建整个内核 然后需要构建镜像 最后部署到目标设备 我是否缺少任何仅重建设备树的技巧 UPDATE 我已将 g0hl1n 的答案标记为正确答案
  • 面板数据中汇总回归模型的模型预测

    我正在尝试生成一个预测模型 在该模型中 我每年都会进行多次汇总回归 基于前几年 从而允许系数随时间变化 这在提供的示例数据中可能没有意义 但在我的示例中实际上是这样做的 这是我到目前为止的想法 我将代码调整为 plm 包中的可重现示例 数据
  • 不同文化信息之间的日期时间转换

    我想在国家 地区之间创建不同的转换 并且我正在使用 C 我正在尝试将日期时间转换为另一个日期时间 格式为 dd mmm yyyy CultureInfo ci CultureInfo CreateSpecificCulture langua
  • seq2seq 中的 TimeDistributed(Dense) 与 Dense

    鉴于下面的代码 encoder inputs Input shape 16 70 encoder LSTM latent dim return state True encoder outputs state h state c encod
  • 在 Maven 中设置注释处理器生成的源目录

    我正在尝试将使用注释处理器生成源的构建移动到 Maven 我尝试按如下方式配置 maven compiler plugin
  • Angular6 - 读取文本/纯文本的响应正文

    我正在执行注册操作 当用户成功注册时 我会在后端返回他的 ID 例如 105 当注册失败 用户已存在 时 我返回 USER EXISTS 我已经在 Postman 上检查了请求 响应正文是正确的 在这两种情况下 我都会返回 纯文本 文本 但
  • Django 双向ManyToMany - 如何防止在第二个模型上创建表?

    我有两个模型 每个模型都有一个共享的 ManyToMany 使用 db table 字段 但是如何防止syncdb 尝试为第二个模型创建共享表呢 class Model1 models Model othermodels ManyToMan
  • 您可以使用 Spark SQL/Hive/Presto 直接从 Parquet/S3 复制到 Redshift 吗?

    我们有大量的服务器数据存储在S3 很快将在Parquet格式 数据需要进行一些转换 因此它不能直接从 S3 复制 我将使用Spark访问数据 但我想知道是否可以跳过一个步骤并运行查询来提取 转换数据 然后复制它 而不是使用 Spark 操作
  • 如何将一个 xhtml 文档中的 div 部分提取到另一个 xhtml 文档中

    我正在尝试使用 xslt 将一个 xhtml 文档中的 div 部分提取到另一个 xhtml 文档中 然而 我没有成功 相反 xslt 转换产生了有线输出 假设要转换以下xhtml文档 some blabla div div class t
  • 无损分解与依赖关系保留

    其中任何一个都暗示另一个吗 我的逻辑是 如果保留所有依赖关系 则不会丢失信息 同样 如果分解是无损的 则一定不会违反功能依赖关系 因此本质上 依赖关系保存是确保分解无损的一种方法 我很难接受 否认它 那么这两者是否可以相互保证 或者是否存在
  • 如何从 URL 中排除单词或字符串 - 正则表达式

    我使用以下正则表达式来匹配 PHP 中的所有类型的 URL 效果非常好 reg exUrl b w www s lt gt w d punct s s 但现在 我想排除 Youtube youtu be 和 Vimeo URL 经过研究后我
  • 如何在实体框架中获取 SQL Server 序列的下一个值?

    我想使用 SQL Serversequence objects http msdn microsoft com en IN library ff878091 aspx在实体框架中显示编号规则 然后将其保存到数据库中 在当前场景中 我正在通过
  • 使用 Hotmail smtp 在 PHP 中发送邮件

    我正在尝试使用 Hotmail Smtp 以 PHP 发送邮件 但我收到如下错误 2014 03 13 06 59 01 CLIENT gt SERVER EHLO site com 2014 03 13 06 59 01 CLIENT g
  • 将数学表达式与正则表达式匹配?

    例如 这些是有效的数学表达式 a b c a b 1 50 apple 0 5 boy 1 这些是无效的数学表达式 a b 1 5 0 two consecutive signs two consecutive operators inva
  • 如何使元素对点击透明但仍然可见?

    我有兴趣在 iframe 之类的东西上放置一个嵌入框阴影 虽然将 div 覆盖在 iframe 上的策略可以提供预期的视觉显示 但 div 随后会阻止 iframe 本身上的点击 Sample http jsfiddle net YqXPg
  • GroupBy 列标题前缀上的列

    我有一个数据框 其列名以一组前缀列表开头 我想获取数据框中按以相同前缀开头的列分组的值的总和 df pd DataFrame 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 columns abc abd wxy wxz p
  • 无窗托盘图标应用程序

    好吧 我是 WPF 的新手 但我必须使用 wpf 开发标题中的内容 但不依赖 MVVM 我已经遵循了这个 仅具有托盘图标的 WPF 应用程序 https stackoverflow com questions 1472633 wpf app
  • 消除subst来证明平等

    我试图将 mod n 计数器表示为间隔的一部分 0 n 1 分为两部分 data Counter Set where cut i j Counter suc i j 使用它 定义两个关键操作很简单 为简洁起见 省略了一些证明 1 n Cou
  • 实现 AVAssetDownloadURLSession 下载 HLS 流时出错

    我正在尝试为流应用程序实现离线模式 目标是能够在用户的设备上下载 HLS 流 以便即使用户离线时也可以观看流 我最近偶然发现本教程 https developer apple com library content documentatio