ALSA Compress-Offload API

概述

从 ALSA API 的早期开始,它就被定义为支持 PCM,或考虑到了 IEC61937 等固定比特率的载荷。参数和返回值以帧计算是常态,这使得扩展已有的 API 以支持压缩数据流充满挑战。

最近这些年,音频数字信号处理器 (DSP) 常常被集成进片上系统 (SoC) 设计中,且 DSPs 也常被集成进音频编解码器 (这里的音频编解码器与 AAC 之类的音频数据压缩方案不同,它是指主要用于完成模拟信号和数字信号转换的器件) 中。与基于主机的处理相比,在 DSP 这样的处理器上处理压缩数据可以显著降低功耗。Linux 对这类硬件的支持不是很好,主要是因为主线内核中缺乏可用的通用 API。

不是要求更改 ALSA PCM 接口的 API 而破坏兼容性,而是引入了一个新的 “压缩数据” API,为音频 DSP 提供控制和数据流接口。

这个 API 的设计灵感来自于 Intel Moorestown SOC 的 2 年经验,通过许多必须的更正把 API 上传到主线内核而不是 staging 树中,使其可供其他人使用。

需求

主要的需求包括如下这些:

  • 字节计数和时间之间的分离。压缩的格式可能每个文件都有一个文件头,或者完全没有文件头。帧和帧之间的载荷大小可能会变化。因此,当处理压缩数据时,可靠地估计音频缓冲区的时长是不可能的。需要专门的机制来实现可靠的音频-视频同步,这需要精确地报告给定时间点,已经渲染的采样数。

  • 处理多种格式。PCM 数据只需要采样率、通道数和位宽的规范。相反地,压缩数据可能是各种各样的格式。音频 DSP 也可以在固件中嵌入对有限数量的音频编码器和解码器的支持,或者可以通过库的动态下载支持更多选择。

  • 聚焦于主要的格式。这个 API 可以为用于音频和视频采集和播放的最流行的格式提供支持。它可能随着音频压缩技术的进步,而添加新的格式。

  • 处理多种配置。即使对于像 AAC 这样给定的格式,一些实现可能支持 AAC 多通道而不是 HE-AAC 立体声。同样,WMA10 M3 级别可能需要许多内存和 CPU 周期。新的 API 需要提供一个通用的方式来列出这些格式。

  • 仅渲染/获取。这个 API 不提供任何硬件加速方法,其中 PCM 采样被返回给用户空间,以做更多处理。这个 API 聚焦于给 DSP 提供压缩数据流,并假设解码之后的数据被路由给一个物理输出或逻辑后端。

  • 复杂性隐藏。对于每个压缩格式,现有的用户空间多媒体框架都具有现成的枚举/结构体。这个新 API 假设有一个平台特有的兼容性层,转换并利用音频 DSP 的能力,如 Android HAL 或 PulseAudio sinks。根据构造,常规的应用程序不应该使用此 API。

设计

新 API 在流控制方面与 PCM API 有许多相同的概念。无论内容是什么,启动 (start),暂停 (pause),恢复 (resume),排空 (drain),和停止 (stop) 命令具有相同的语义。

内存环形缓冲区被分割为一系列片段的概念借鉴自 ALSA PCM API。然而,只能指定字节大小。

拖动/trick 模式假定由主机处理。

不支持快退/快进的概念。提交到环形缓冲区的数据不能失效,除非删除所有缓冲区。

压缩数据 API 对于数据如何被提交给音频 DSP 不做任何假设。从主存储器传输到嵌入式音频集群或外部 DSP 的 SPI 接口的 DMA 传输都是可能的。与在 ALSA PCM 的情况中一样,暴露了一组核心例程;每个驱动程序实现者都必须编写对一组强制例程的支持,并可能使用可选例程。

主要补充内容是

get_caps

这个例程返回支持的音频格式列表。在采集流上查询 codecs 将返回编码器,对播放流则将列出解码器。

get_codec_caps

对于每个 codec,这个例程返回能力 (capabilities) 的列表。这个例程的意图是确保所有的能力都对应于有效的设置,并最小化配置失败的风险。例如,对于诸如 AAC 之类的复杂编解码器,支持的通道数可能取决于特定的配置 (profile)。如果通过单个描述符来暴露能力 (capabilities),可能发生配置 (profile)/通道数/格式的特定结合无法支持的情况。同样,嵌入式 DSP 的内存和 CPU 周期有限,某些实现可能会使能力 (capabilities) 列表变得动态并依赖于现有工作负载。除了编解码器设置之外,此例程还返回实现处理的最小缓冲区大小。该信息可以是 DMA 缓冲区大小、同步所需的字节数等的函数,并且可以由用户空间使用来定义在开始播放之前需要在环形缓冲区中写入多少内容。

set_params

这个例程设置为特定编解码器选择的配置。参数中最重要的字段是编解码器类型;在大多数情况下解码器将忽略其它参数,而编码器将与设置保持严格一致。

get_params

这个例程返回 DSP 使用的实际设置。对设置的更改应该仍然是例外。

get_timestamp

时间戳变成多字段结构。它列出了传输的字节数、处理的采样数以及渲染/采集的采样数。所有这些值均可用于确定平均比特率、确定环形缓冲区是否需要重新填充或由于 DSP 上的解码/编码/IO 导致的延迟。

请注意,编解码器/配置 (profile)/模式列表源自 OpenMAX AL 规范,而不是重新发明轮子。修改包括:

  • 添加 FLAC 和 IEC 格式
  • 编码器/解码器能力 (capabilities) 的合并
  • 配置 (profile)/模式列表为位掩码,使描述符更加紧凑
  • 为解码器添加 set_params (在 OpenMAX AL 中缺失)
  • 添加 AMR/AMR-WB 编码模式 (在 OpenMAX AL 中缺失)
  • 为 WMA 添加格式信息
  • 需要时添加编码选项 (源自 OpenMAX AL)
  • 添加 rateControlSupported (在 OpenMAX AL 中缺失)

状态机

压缩音频流状态机描述如下

                                      +----------+|          ||   OPEN   ||          |+----------+||| compr_set_params()|vcompr_free()                  +----------+
+------------------------------------|          |
|                                    |   SETUP  |
|          +-------------------------|          |<-------------------------+
|          |       compr_write()     +----------+                          |
|          |                              ^                                |
|          |                              | compr_drain_notify()           |
|          |                              |        or                      |
|          |                              |     compr_stop()               |
|          |                              |                                |
|          |                         +----------+                          |
|          |                         |          |                          |
|          |                         |   DRAIN  |                          |
|          |                         |          |                          |
|          |                         +----------+                          |
|          |                              ^                                |
|          |                              |                                |
|          |                              | compr_drain()                  |
|          |                              |                                |
|          v                              |                                |
|    +----------+                    +----------+                          |
|    |          |    compr_start()   |          |        compr_stop()      |
|    | PREPARE  |------------------->|  RUNNING |--------------------------+
|    |          |                    |          |                          |
|    +----------+                    +----------+                          |
|          |                            |    ^                             |
|          |compr_free()                |    |                             |
|          |              compr_pause() |    | compr_resume()              |
|          |                            |    |                             |
|          v                            v    |                             |
|    +----------+                   +----------+                           |
|    |          |                   |          |         compr_stop()      |
+--->|   FREE   |                   |  PAUSE   |---------------------------+|          |                   |          |+----------+                   +----------+

无缝播放

当播放唱片时,解码器能够跳过编码器延迟和填充,并直接从一个曲目内容移动到另一个曲目内容。最终用户可以将其视为无缝播放,因为我们在从一个曲目切换到另一个曲目时没有静音。

此外,由于编码可能会产生低强度噪声。所有类型的压缩数据都很难达到完美的无缝效果,但对于大多数音乐内容来说效果很好。解码器需要知道编码器延迟和编码器填充。所以我们需要将其传递给 DSP。该元数据是从 ID3/MP4 头中提取的,默认情况下不存在于比特流中,因此需要一个新的接口来将此信息传递给 DSP。此外,DSP 和用户空间需要从一个曲目切换到另一个曲目,并开始使用第二个曲目的数据。

主要补充内容是:

set_metadata

该例程设置编码器延迟和编码器填充。解码器可以使用它来去除静音。这需要在写入曲目中的数据之前进行设置。

set_next_track

该例程告诉 DSP,在此之后发送的元数据和写入操作将对应于后续曲目。

partial_drain

当到达文件末尾时调用此函数。用户空间可以通知 DSP 已达到 EOF,现在 DSP 可以开始跳过填充延迟。下一次写入数据也将属于下一个曲目。

无缝播放的顺序流程为:

  • 打开
  • 获得能力 (caps)/编解码器能力 (caps)
  • 设置参数
  • 设置第一首曲目的元数据
  • 填充第一首曲目的数据
  • 触发启动
  • 用户空间结束所有的发送,
  • 通过发送 set_next_track 指示下一首曲目的数据,
  • 设置下一首曲目的元数据
  • 然后调用 partial_drain 刷新 DSP 中缓冲区的大部分
  • 填充下一首曲目的数据
  • DSP 切换到第二首曲目

(注意:partial_drain 和写入下一首曲目的数据的顺序也可以反过来)

无缝播放状态机

对于无缝播放,我们从运行状态转移到部分耗尽状态并返回,同时设置元数据和下一首曲目的信号

                          +----------+compr_drain_notify()    |          |
+------------------------>|  RUNNING |
|                         |          |
|                         +----------+
|                              |
|                              |
|                              | compr_next_track()
|                              |
|                              V
|                         +----------+
|    compr_set_params()   |          |
|             +-----------|NEXT_TRACK|
|             |           |          |
|             |           +--+-------+
|             |              | |
|             +--------------+ |
|                              |
|                              | compr_partial_drain()
|                              |
|                              V
|                         +----------+
|                         |          |
+------------------------ | PARTIAL_ ||  DRAIN   |+----------+

不支持

  • 支持 VoIP/电路交换呼叫不是此 API 的目标。支持动态比特率变化需要 DSP 和主机堆栈之间的紧密耦合,从而限制了节能。

  • 不支持丢包隐藏。这将需要一个额外的接口,以便解码器在传输过程中丢失帧时合成数据。将来可能会添加此功能。

  • 这个 API 不处理音量控制/路由。公开压缩数据接口的设备将被视为常规 ALSA 设备;改变音量和路由信息将通过常规 ALSA kcontrol 提供。

  • 嵌入式音效。无论输入是 PCM 还是压缩的,都应以相同的方式启用此类音效。

  • 多通道 IEC 编码。不清楚是否需要这样做。

  • 如上所述,不支持编码/解码加速。可以将解码器的输出路由到采集流,甚至实现转码功能。此路由将通过 ALSA kcontrol 启用。

  • 音频策略/资源管理。该 API 不提供任何挂钩来查询音频 DSP 的利用率,也不提供任何抢占机制。

  • 没有 underrun/overrun 的概念。由于写入的字节本质上是压缩的,并且写入/读取的数据不会及时直接转换为渲染输出,因此这不会处理 underrun/overrun 问题,可能会在用户库中处理

作者

  • Mark Brown 和 Liam Girdwood 讨论了此 API 的需求
  • Harsha Priya 在 intel_sst 压缩 API 方面的工作
  • Rakesh Ughreja 提供了宝贵的反馈
  • Sing Nallasellan、Sikkandar Madar 和 Prasanna Samaga 在真实平台上演示并量化了音频卸载的优势。

原文

Done.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/209336.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

git如何配置多个远程仓库,并且进行切换

一、配置多个远程仓库并进行切换&#xff0c;请按照以下步骤进行操作&#xff1a; 打开命令行终端&#xff0c;并进入您的 Git 仓库所在的目录。添加第一个远程仓库&#xff0c;使用以下命令&#xff1a;git remote add origin <第一个远程仓库的 URL>这里将远程仓库命名…

C# .NET平台提取PDF表格数据,并转换为txt、CSV和Excel表格文件

处理PDF文件中的内容是比较麻烦的事情&#xff0c;特别是以表格形式呈现的各种数据。为了充分利用这些宝贵的数据资源&#xff0c;我们可以通过程序提取PDF文件中的表格&#xff0c;并将其保存为更易于处理和分析的格式&#xff0c;如txt、csv、xlsx&#xff0c;从而更方便地对…

leetcode面试经典150题——35 螺旋矩阵

题目&#xff1a; 螺旋矩阵 描述&#xff1a; 给你一个 m 行 n 列的矩阵 matrix &#xff0c;请按照 顺时针螺旋顺序 &#xff0c;返回矩阵中的所有元素。 示例&#xff1a; 输入&#xff1a;matrix [[1,2,3],[4,5,6],[7,8,9]] 输出&#xff1a;[1,2,3,6,9,8,7,4,5] 提示&…

Redis Geo操作地理位置

Redis Geo 使用场景API列表名词API列表Springboot使用mavenyamlTest 注意事项 Redis Geo 是Redis在3.2版本中新增的功能&#xff0c;用于存储和操作地理位置信息 使用场景 滴滴打车&#xff1a;这是一个对地理位置精度要求较高的场景。通过使用Redis的GEO功能&#xff0c;滴滴…

12月8日作业

使用手动连接&#xff0c;将登录框中的取消按钮使用qt4版本的连接到自定义的槽函数中&#xff0c;在自定义的槽函数中调用关闭函数&#xff1b;将登录按钮使用qt5版本的连接到自定义的槽函数中&#xff0c;在槽函数中判断u界面上输入的账号是否为"admin"&#xff0c;…

kafka学习笔记--安装部署、简单操作

本文内容来自尚硅谷B站公开教学视频&#xff0c;仅做个人总结、学习、复习使用&#xff0c;任何对此文章的引用&#xff0c;应当说明源出处为尚硅谷&#xff0c;不得用于商业用途。 如有侵权、联系速删 视频教程链接&#xff1a;【尚硅谷】Kafka3.x教程&#xff08;从入门到调优…

Day54力扣打卡

打卡记录 出租车的最大盈利&#xff08;动态规划&#xff09; 链接 class Solution:def maxTaxiEarnings(self, n: int, rides: List[List[int]]) -> int:d defaultdict(list)for start, end, w in rides:d[end].append((start, end - start w))f [0] * (n 1)for i in…

文章解读与仿真程序复现思路——电力自动化设备EI\CSCD\北大核心《考虑源网荷效益的峰谷电价与峰谷时段双层优化模型》

这个标题涉及到电力定价和能源效益的优化模型。让我来分解一下&#xff1a; 峰谷电价&#xff1a;这是一种电力定价策略&#xff0c;即在一天内不同时间段设定不同的电价。通常&#xff0c;高峰时段&#xff08;需求高&#xff09;的电价相对较高&#xff0c;而低谷时段&#x…

人工智能学习9(LightGBM)

编译工具&#xff1a;PyCharm 文章目录 编译工具&#xff1a;PyCharm lightGBM原理lightGBM的基础使用案例1&#xff1a;鸢尾花案例2&#xff1a;绝对求生玩家排名预测一、数据处理部分1.数据获取及分析2.缺失数据处理3.数据规范化4.规范化输出部分数据5.异常数据处理5.1删除开…

利用私域运营的四大策略实现企业营销目标

私域运营指的是企业利用各种网络技术和工具&#xff0c;以自己的平台为基础&#xff0c;建立、维护、更新和升级与用户的私人关系。这种运营模式让企业能更准确地了解客户需求和喜好&#xff0c;通过定制化服务、优惠政策、个性化体验等方式&#xff0c;获取更多的客户价值。相…

Child Mind Institute - Detect Sleep States(2023年第一次Kaggle拿到了银牌总结)

感谢 感谢艾兄&#xff08;大佬带队&#xff09;、rich师弟&#xff08;师弟通过这次比赛机械转码成功、耐心学习&#xff09;、张同学&#xff08;也很有耐心的在学习&#xff09;&#xff0c;感谢开源方案&#xff08;开源就是银牌&#xff09;&#xff0c;在此基础上一个月…

基于Lucene的全文检索系统的实现与应用

文章目录 一、概念二、引入案例1、数据库搜索2、数据分类3、非结构化数据查询方法1&#xff09; 顺序扫描法(Serial Scanning)2&#xff09;全文检索(Full-text Search) 4、如何实现全文检索 三、Lucene实现全文检索的流程1、索引和搜索流程图2、创建索引1&#xff09;获取原始…

模板与泛型编程

函数模板 显示实例化 区别定义与声明 T是模板形参 int是模板实参 inpunt是函数形参 3是函数实参 显示实例化 模板必须实例化可见 翻译单元一处定义原则 与内联函数异同 引入原因&#xff1a;函数模板是为了编译器两个阶段的处理 内联函数是为了能在编译期展开 模板实参的类…

Android Kotlin语言下的文件存储

目录 将数据存储到文件中 创建文件和保存数据 读取文件 SharedPreferences存储 存储数据到SharedPreferences中 Context类中的getSharedPreferences()方法 Activity类中的getPreferences()方法 从SharedPreferences中读取数据 SQLite数据库存储 创建数据库 调用数据…

Java导出word

原文地址 传入的值不能为null,否则会报错&#xff0c;IXDocReport 有自己的判null规则&#xff0c;比较麻烦&#xff0c;建议代码直接把null替换成"" public void exportWord1(WeeklyMeetDataDto dto, HttpServletResponse response) {ServletOutputStream downLoad…

Ignis - Interactive Fire System

Ignis - 点火、蔓延、熄灭、定制! 全方位火焰系统。 这个插件在21年的项目中使用过很好用值使用概述 想玩火吗?如果想的话,那么Ignis就是你的最佳工具。有了Ignis,你可以把任何物体、植被或带皮带骨的网状物转换为可燃物体,它就会自动着火。然后,火焰可以蔓延,点燃其他物…

Java 一对多

前言 Internet 协议集支持一个无连接的传输协议&#xff0c;该协议称为用户数据报协议&#xff08;UDP&#xff0c;User Datagram Protocol&#xff09;。UDP 为应用程序提供了一种无需建立连接就可以发送封装的 IP 数据包的方法。 此代码就是基于UDP协议编写。 通常把一对多的…

【docker 】centOS 安装docker

官网 docker官网 github源码 卸载旧版本 sudo yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-logrotate \docker-logrotate \docker-engine 安装软件包 yum install -y yum-utils \device-mapper-persistent-data…

【优选算法系列】【专题二滑动窗口】第四节.30. 串联所有单词的子串和76. 最小覆盖子串

文章目录 前言一、串联所有单词的子串 1.1 题目描述 1.2 题目解析 1.2.1 算法原理 1.2.2 代码编写 1.2.3 题目总结二、最小覆盖子串 2.1 题目描述 2.2 题目解析 2.2.1 算法原理 2.2.2 代码编写 …

【Docker】进阶之路:(四)操作容器

【Docker】进阶之路&#xff1a;&#xff08;四&#xff09;Docker容器 容器的生命周期创建容器docker createdocker run 管理容器查看运行的容器&#xff1a;查看所有容器&#xff1a; 启动与终止启动容器终止容器 进入容器docker attachdocker exec 导出和导入导出导入 容器的…