机器翻译结果,仅用于学习,不喜勿喷,原文档链接。
任何从事音频spec工作的人都可能会告诉您,他们的大部分时间都花在了有关音量控制的讨论上。这是一个比音频质量产生更多争论的话题。原因是双重的。第一个是关于音量感知以及如何定义最小和最大之间的步骤的永无止境的学术讨论。二是如何应对多种不同的音量控制方式。当您的电视或放大器上只有一个音量旋钮时,第二个问题就不存在了。但是,一旦您拥有多个远程遥控,用户就很难弄清楚如何设置音量。
经过数百小时的必要辩论后,Bluetooth® LE Audio 工作组决定或多或少地跳过第一个问题而专注于第二个问题——如何协调多个不同的控制点。所以,这一章都是关于音量控制的,只是简单地提到了音量是如何解释的,因为那是留给实现的。我们还将介绍麦克风控制,因为它是类似的,但涉及音频的输入,而不是其输出。所有这些功能都设计用于非编码音频信号。在音量的情况下,这意味着在接收和解码之后;对于麦克风控制服务和profile,它是在传输之前。
10.1 音量和输入控制
在前面的章节之后,这应该是一帆风顺的。3个涉及volume的service和一个profile:
- Volume Control Service(VCS),可以看作是主音量控制旋钮
- Volume Offset Control Service (VOCS),可被视为“平衡”控制
- Audio Input Control Service (AICS),它允许对任意数量的音频输入进行单独的增益控制和静音,不需要蓝牙音频流,以及
- Audio Input Control Service (VCP),它允许多个client控制这些服务。
虽然大部分都有“volume”的名字,但实际上做的是调整增益,
即,音频信号的放大。
图 10.1 显示了一副耳机或带状助听器的典型实现,它具有三种可能的音频输入——蓝牙音频流、Telecoil 音频输入和麦克风输入。这些输入混合在一起,使用音频输入控制服务设置各自的增益,并有选择地静音和取消静音。结果流的增益由音量控制服务设置控制。如果流是立体声流,则一旦将其拆分为左右分量,音量偏移控制服务的单独实例就可以调整进入每个扬声器的增益。 (该图是硬件表示。实际上,VCS 和 VOCS 增益设置的总和应用于每个音频通道。)以不同的方式一起使用,它们模拟了平衡控制的效果。它们还可以单独用于调整每个扬声器中的相对声音级别,以适应左右耳不同程度的听力损失。
10.1.1 应对多个音量控制
从一开始,在LE audio 开发过程中,很明显用户希望从多个不同的位置控制耳塞和耳机的音量。假设是耳塞上有本地控制,音频源(通常是手机)有音量控制,智能手表和其他专用遥控设备有单独的音量控制。
要使这种级别的分布式控制发挥作用,您希望在渲染音频的设备上保留主要的音量控制。如果您不这样做,但也让它在音频源上进行控制,您最终可能会得到一个controller在源级别上运行,而另一个controller在接收器级别上运行。这会导致源增益被调低,而宿增益被调高以进行补偿的情况。这意味着用户不能再增加耳朵的音量,并且音频质量会降低,因为编解码器正在对幅度非常低的信号进行采样和编码。这降低了最重要的信噪比,因为在解码和放大时,噪声也会被放大。
为了解决这个问题,增益发生在音频链的末端很重要,但要让它发挥作用,所有的音量控制client都需要跟踪它的值,所以他们总是知道自己在哪里。这有点像一个老笑话,司机停下来问路人能否给他去都柏林的路线,路人回答说:“如果我要去都柏林,我不会从这里”。幸运的是,GATT client-server模型有通知,因此我们可以利用这些通知来确保每个音量控制client都知道server上的当前增益级别。但可以肯定的是,音量控制服务包括一个名为 Change_Counter 的额外保护措施,我们将在下面进行探讨。
回顾图 10.1,它还解释了架构,其中音量控制状态尽可能接近渲染的最终点。这将我们带到了单独的音量控制服务。这些是非常薄的文档,因此我们可以相当快速地浏览它们。
10.2 音量控制服务
就像我们之前看到的控制服务一样,所有的艰苦工作都是由两个特点完成的:
- 音量控制点,client用于设置音量级别,以及
- 音量状态,server用于在写入音量控制点特征后通知当前音量级别。
我们应该严格地谈论增益,而不是音量,但由于每个人都习惯于口语使用音量,我会坚持下去。第三个特征——音量标志,用于让客户了解当前音量设置的历史。
Volume State 特征有三个字段,都是一个八位字节长,如图10.2. Acceptor 上只有一个 Volume State 特性的实例。
Volume_Setting 定义为从 0(最小音量)到 255(最大)的值,没有规定这些数字与输出音量的关系。由实现者将这些值映射到实际输出量,期望用户感知近似线性。即,如果 Volume_Setting 值设置为 127,则结果输出听起来好像是最大值的一半。这让我们回到了关于如何感知音量的辩论。我们的听力通常是对数的,这就是为什么声音强度以分贝来衡量的原因,但这可能会受到我们正在听的内容的影响。把它留给制造商确实意味着如果将不同制造商的扬声器或耳塞一起使用,其音量的变化可能与听众的期望不一致。在某些设置下,一个可能会显得比另一个响亮。解决这个问题属于“太难”的类别,因此留待实施。
Volume_Setting 字段的值由于对音量控制点特性 (qv) 的操作(修改当前值)或设备用户界面上的本地操作而改变。 Volume_Setting 中存储的值不受任何静音操作的影响。
Mute 指示音频流是否已被静音。这与 Volume_Setting 值无关,因此当设备取消静音时,音频音量将恢复到之前的级别。
Change_Counter 就是上面提到的功能,它确保所有的音量控制client都是同步的。当实现 VCS 的 Acceptor 上电时,Server 用 0 到 255 之间的随机值初始化 Change_Counter。随后对 Volume Control Point 特性或设备本地控制的每一次操作,无论是改变音量还是静音,都会导致更改为Volume_Setting 或 Mute 字段值将导致 Change_Counter 将其值增加 1。一旦达到 255 的值,它将滚动到 0 并继续增加。
Change_Counter 的目的是确保任何尝试更改当前音量或静音设置的client都知道它们当前是什么。这是通过要求client的每个写入过程包括他们持有的 Change_Counter 的当前值来检查的。除非与 Volume State Characteristic 中的值匹配,否则假定它们不同步。该命令将被忽略,并且不会发送任何通知。在这种情况下,client应该认识到缺少通知,读取卷状态特征并重试。
要更改音量或使设备静音,音量控制client使用音量控制点过程之一写入音量控制服务的音量控制点特征。该命令包含一个操作码、一个 Change_Counter 值,在 Set Absolute Volume 命令的情况下,还包含一个 Volume_Setting 值。表 10.1 列出了六个操作码。
Opcode | Operation | Operands |
---|---|---|
0x00 | 相对音量降低 | Change_Counter |
0x01 | 相对音量增加 | Change_Counter |
0x02 | 取消静音/相对音量降低 | Change_Counter |
0x03 | 取消静音/相对音量增加 | Change_Counter |
0x04 | 设置绝对音量 | Change_Counter, Volume_Setting |
0x05 | 取消静音 | Change_Counter |
0x06 | 静音 | Change_Counter |
0x07-0xFF | Reserved for Future Use | Reserved for Future Use |
其中大部分是不言自明的。 Relative Volume Down 和 Up 更改音量设置,而不影响静音状态,因此可用于更改将在设备最终取消静音时应用的音量级别。操作码 0x05 和 0x06 在不影响音量的情况下取消静音和静音,而操作码 0x02 和 0x03 在静音或取消静音的同时应用相对音量步进。 Set Absolute Volume 需要一个附加参数,即所需的绝对音量级别。
尽管所有设备的 Volume_Setting 范围从 0 到 255,但很少有可能包含超过 21个离散音量级别。这需要server定义步长,每当发出音量设置命令时都会应用该步长。步长实际上是 256 ÷ 步数。server使用以下等式计算写入 Volume State 特性的 Volume_Setting 值的新值。
相对降低音量:Volume_Setting = Max (Volume_Setting – Step Size, 0)
相对音量提高:Volume_Setting = Min (Volume_Setting + Step Size, 255)
10.2.1 持续音量
最后一个特征是 Volume Flags 特征,它是一个位域,其中只定义了一个位。这是位 0,即 Volume_Setting_Persisted 字段。如果设置为 0,它指示client通过写入操作码 0x04 的音量控制点特征来重置音量。这会设置一个绝对音量,它可以是由应用程序或client设备确定的默认值。它也可能是上次使用该应用程序时记住的值。
如果该值为 1,则表明 Volume Control Server 仍具有其上次会话的 Volume_Setting,应继续用于该会话。 Volume Client 应该通过通知或读取该值来检索此值,并将其用作此会话的初始值。通过从以前使用的相同音量设置开始,这可以改善用户体验。
10.3 音量偏移控制服务
如果您只有一个单声道扬声器,那么音量控制服务就是您所需要的。一旦您处理多个音频流,无论是发送到单个acceptor还是多个acceptor,您都需要为每个渲染的音频位置包含一个音量偏移控制服务的实例。使用音量控制profile中的程序访问所有特征。
体积偏移控制服务包括四个特征,如表 10.2 所示。这四个都是强制性的。
Characteristic | Mandatory Properties | Optional Properties |
---|---|---|
Volume Offset State | Read, Notify | None |
Volume Offset Control Point | Write | None |
Audio Location | Read, Notify | Write without response |
Audio Output Description | Read, Notify | Write without response |
音量偏移状态和音量偏移控制以正常方式工作。 Volume Offset State 包括两个字段——Volume_Offset 和 Change_Counter
Field | Size |
---|---|
Volume_Offset | 2 octets |
Change_Counter | 1 octet |
Volume_Offset 有两个八位字节长,因为它允许从 -255 到 255 的值。Volume_Offset 的值与 Volume_State 的值相加,以提供用于渲染的总体积值。
Change_Counter 与我们在音量控制服务中看到的概念相同,用于确保任何发出音量偏移命令的client都知道音量偏移的当前状态。请注意,虽然它是相同的概念并且具有相同的名称,但它是一个单独的实例。 VOCS 的每个实例以及 VCS 的单个实例都维护自己的 Change_Counter 值,当它们的 Volume_Offset 或 Volume_State 字段值发生任何更改时,该值会更新。
为了实现更改,client使用以下参数写入音量偏移控制点特征:
Parameter | Size (octets) | Value |
---|---|---|
Opcode | 1 | 0x01 = Set Volume Offset |
Change_Counter | 1 | 0 to 255 |
Volume_Offset | 2 | -255 to 255 |
10.3.1 音频定位特性
音量偏移控制服务包含与应用偏移的音频位置相关的两个特征。
其中第一个是音频位置特性。这是一个 4 个八位字节的位图,它使用来自 Generic Audio 分配的数字的音频位置的格式定义应应用偏移的音频位置。通常,这将包含一个位置,因为一个单独的 VOCS 实例应用于每个音频位置。这通常是在制造时设置的只读特性,但也可以使其可写。
音频输出描述特性允许将文本字符串分配给每个音频位置,以便为应用程序(例如卧室左扬声器)提供更多信息。它可以在制造时分配,或者让用户可以访问以分配友好名称。
10.4 音频输入控制服务
呈现三重服务的最后一部分是音频输入控制服务。这承认许多产品,如助听器、耳塞和耳机,包含不止一种音频流源,并且可能同时使用不止一种。最常见的示例是同时使用外部麦克风和蓝牙流。对于助听器来说,这一直是它们的工作方式。最近,随着透明模式的出现,它已成为耳塞和耳机中越来越受欢迎的功能,让佩戴者可以了解周围世界的声音。
音频输入控制服务的实例通常包含在要在该设备上呈现的每个单独的音频路径中。如果有单个LE audio 路径,它不会比 VCS 提供任何优势,因此不需要包括在内。不直接馈送到输出的音频输入,例如提供降噪输入的麦克风,不会有自己的实例,因为它们将用于处理另一个音频流(可能有自己的 AICS 实例)。
音频输入控制服务包含六个特性,如表 10.5 所示。所有这些都是必须支持的。
Name | Mandatory Properties | Optional Properties |
---|---|---|
Audio Input State | Read, Notify | None |
Audio Input Control Point | Write | None |
Audio Input Type | Read | None |
Audio Input Status | Read, Notify | None |
Audio Input Description | Read, Notify | Write without response |
Gain Setting Properties | Read | None |
在进入这些之前,我们需要了解 AICS 如何定义增益。对于音量,VCS 和 VOCS 只是定义了一个从 0 到 255 的线性刻度,很像 Hi-Fi 设备上的旋钮,从 0 到 10,然后由制造商将其转换为通常基于分贝的值,内部映射。对于 AICS,假设增益将基于分贝,因此增益的数字以分贝为单位。然而,为了提供更多的灵活性,增益值的实际步长可以定义为 0.1 dB 的倍数。这些倍数是制造商特定的选择,它显示在增益设置属性特性中,以及允许的最小值和最大值,如表 10.6 所示。
Name | Size (octets) | Description |
---|---|---|
Gain_Setting_Units | 1 | 增量,以 0.1db 为步长,应用于所有Gain_Setting 值 |
Gain_Setting_Minimum | 1 | Gain_Setting的最小允许值 |
Gain_Setting_Maximum | 1 | Gain_Setting的最大允许值 |
在更复杂的情况下,AICS 允许音频流自动控制其增益(传统上称为自动增益控制或 AGC)或手动控制,这可以由音量控制client或本地用户控制,并暴露更改的值在音频输入状态特性中。当控制是自动的时,server不支持client所做的任何更改。server可以使用表 10.7 中显示的值,通过音频输入状态特性的 Gain_Mode 字段公开是否允许client将模式从自动更改为手动,反之亦然。
整理好之后,我们可以继续讨论音频输入状态和音频输入控制点,它们的工作方式与我们预期的一样。音频输入状态包含四个字段,如表 10.8 中所述。
Name | Size (octets) |
---|---|
Gain_Setting | 1 |
Mute | 1 |
Gain_Mode | 1 |
Change_Counter | 1 |
Gain_Setting 在 Gain_Setting_Units 中公开当前的增益值。将值 0 写入 Mute 不会影响当前的 Gain_Setting 值,因此通过向 Mute 写入 1 将其取消静音会将增益返回到 Gain_Setting 中的先前值。如果server处于自动增益模式,它将忽略写入 Gain_Setting 字段的任何内容。
静音表示音频流是静音(值 = 0)还是未静音(值 = 1)。 AICS 为我们提供了一个附加选项,其中值 2 表示禁用静音功能。最终的音频流仍然可以使用 VCS Mute 静音,但通过执行此选项,单个输入流不能单独静音。
Gain_Mode 和 Change_Counter 的行为与 VCS 和 VOCS 完全相同。同样,它是每个 AICS 实例的独立实例化。
通过写入音频输入状态控制点特性来设置 AICS 参数,使用表 10.9 中列出的五个操作码之一
Opcode | Opcode Name | Description |
---|---|---|
0x01 | Set Gain Setting | 以 Gain_Setting_Units x 0.1dB 为增量设置增益 |
0x02 | Unmute | Unmutes(除非静音被禁用) |
0x03 | Mute | Mutes(除非静音被禁用) |
0x04 | Set Manual Gain Mode | 从手动更改为自动增益(如果允许) |
0x05 | Set Automatic Gain Mode | 从自动增益更改为手动增益(如果允许) |
这些几乎都像它的名字所说的那样,尽管正如我们已经发现的那样,有很多警告server可以忽略它们,特别是如果它不准备放弃对增益和静音功能的控制.
设置增益设置操作码 (0x01) 采用表 10.10 中所示的形式。
Parameter | Size (Octets) | Value |
---|---|---|
Opcode | 1 | 0x01 |
Change_Counter | 1 | 0 to 255 |
Gain_Setting | 1 | -128 to 127 |
所有其他过程都使用相同的、更短的参数格式,如表 10.11 所示。
Parameter | Size (Octets) | Value |
---|---|---|
Opcode | 1 | 0x02 = Unmute 0x03 = Mute 0x04 = Set Manual Gain Mode 0x05 = Set Automatic Gain Mode |
Change_Counter | 1 | 0 to 255 |
与 VOCS 一样,还有一些额外的特性可以帮助用户界面。
音频输入类型用于识别具有只读文本描述的音频输入流,可用于 UI。典型值(英文)为 Microphone、HDMI、Bluetooth 等。这些由制造商设置。
音频输入状态显示每个 AICS 音频流的当前状态。如果该值设置为 0,则 Audio Stream 处于非活动状态;如果设置为 1,则音频流处于活动状态。
音频输入描述允许对音频输入进行更详细的描述,这在有多个相同类型的输入时很有用,例如多个蓝牙或 HDMI 输入。它可以由制造商设置或可选地使其可写以允许用户对其进行更新。
10.5 将音量控制放在一起
开场图显示了这三个服务如何协同工作。图 10.3 显示了一对立体声耳机的典型实现,它支持蓝牙连接和本地麦克风。
每只耳朵的音量是通过将 VCS 中的单个值与每只耳朵的 VOCS 实例化的音频位置特定值相结合来设置的。任何一个传入的音频流都可以单独静音或控制其增益(如果server允许),而 VCS 提供全局静音功能。
图 10.4 显示了立体声对的左侧助听器的类似方法。因为只渲染一个通道,所以只有一个 VOCS 实例,服务于左助听器。右耳中的另一个助听器将是相同的,但具有用于正确音频位置的 VOCS 实例。
10.6 麦克风控制
尽管上面的示例包括麦克风,但它们都将麦克风用作本地输入,选择或与要渲染的其他音频输入混合。但是,麦克风也用作音频输入,这些输入被捕获并发送回Initiator 。麦克风控制服务和profile(MICS 和 MICP)的存在是为了提供对麦克风的设备范围控制。
麦克风控制服务可能是所有LE audio spec中最简单的服务,它包含一个特性,可为麦克风提供设备范围的静音。其最简单的用法如图 10.5 所示。
没有相应的控制点特性。相反,静音特性可以直接写入,也可以读取和通知。它与 AICS Audio State 特性中的 Mute 字段具有相同的功能,即:
Description | Value |
---|---|
Not Muted | 0x00 |
Muted | 0x01 |
Mute Disabled | 0x02 |
如果需要控制麦克风增益,MICS 应该与 AICS 的实例结合使用(图 10.7),尽管在这种情况下,MICS 与仅使用 AICS 相比并没有提供太多优势。然而,大多数客户希望使用 MICS 来执行麦克风静音,因此保留 MICS 的原因。
当存在多个麦克风时,AICS 和 MICS 的组合更有意义,因为 MICS 为麦克风提供了设备范围内的静音,这是它的真正目的(图 10.8)。
最后,MICS 可用于为多个麦克风提供设备范围的静音,作为音量控制方案的一部分,如图 10.9 所示。但是,在大多数情况下,Acceptor 中的多个麦克风将直接馈入音频处理模块,因此不太可能需要对单个麦克风进行外部控制。图10.9 确实展示了LE audio 中音量和麦克风控制服务的灵活性。
10.7 术语附录
在本书中,我一直在使用 Initiator、Acceptor 和 Commander 来描述LE audio 生态系统中的三种主要设备类型。正如我在第 3 章中所述,这些术语在 CAP 中被定义为角色,因此纯粹主义者可能会反对我将它们与设备混为一谈。我仍然觉得融合可以更清楚地理解所有事物是如何组合在一起的。
Commander(作为设备)与 Initiator 和 Acceptor 交互的方式存在混淆的可能性。作为角色,Commander 可以与 Initiator 搭配使用,但作为设备,它与 Initiator 及其每个 Acceptor 的交互可能会令人困惑。尽管所有这些交互都包含在 CAP 程序中,但它们是独立的。图 10.10 以 Initiator、Acceptor 和独立 Commander 的简单案例说明了本章中描述的一些profile和服务。
在这种情况下,Commander 中实现了三个profile。其中两个——呼叫控制和媒体控制作用于Initiator 中的补充服务,而音量控制作用于Acceptor中的 VCS、VOCS 和 AICS 实例。对于语法倾向,Commander 中的profile和 Initiator 中的服务位于同一位置; Acceptor 中的服务是并置的。
这使我们结束了 GAF spec。LE audio 中唯一的其他spec是我们即将讨论的上层profile。