音频

概述

音频框架是一个完整的音频架构,旨在为应用程序提供不同层次的音频接口。这些接口涉及音频硬件抽象层(Audio HAL)和音频框架(Audio Framework)。

  • 音频硬件抽象层:定义统一的音频硬件接口。它与音频驱动交互以进行音频流或音频设置。

  • 音频框架:提供音频流、音量和其他设置的接口。

    音频框架提供两种架构以满足不同的音频需求。不同的架构有不同的实现,但接口是相同的。

  • 音频混音架构:支持音频录制和音频播放。对于音频播放,该架构提供音频混音功能,并将格式、采样率和声道转换为统一格式以进行混音。

  • 音频直通架构:支持音频录制和音频播放。该架构没有音频混音功能,同一时刻只允许一个音频播放。

音频混音器概述

音频接口和整体实现如下所示。

../../_images/audio_mixer_overview.svg

音频混音架构

整个音频混音架构包括以下子模块:

  • 应用接口

    • RTAudioTrack 提供播放音频流接口。

    • RTAudioRecord 提供录音接口。

    • RTAudioControl 提供控制接口,包括音量,静音控制等。

  • 音频框架接口

    • 音频框架为音频流播放提供音频格式转换、重采样、音量和混音功能。

  • 音频硬件抽象层接口

    • AudioHwManager 管理声卡驱动程序的接口,使得用户获取各个声卡信息,并根据需求打开相应的声卡。

    • AudioHwCard 提供管理声卡功能的接口,包括初始化端口、创建输出流和输入流。

    • AudioHwControl 提供接口给RTAudioControl使用,并向音频驱动程序发送音频设置命令。

    • AudioHwStreamOut 从上层获取数据,并将数据流传递给音频驱动程序。

    • AudioHwStreamIn 从音频驱动程序录音数据,并将数据传送到上层接口。

  • 音频驱动

    • AUDIO_SP 提供接口,配置音频SPORT。

    • AUDIO_CODEC 提供接口,配置音频CODEC。

音频直通概述

音频接口和整个实现如下所示。

../../_images/audio_passthrough_overview.svg

音频直通架构

与音频混音器架构相比,音频直通架构没有音频框架层,其他部分几乎相同。

架构选择

以上部分描述了两种音频架构:混音器和直通。用户可以根据项目要求选择合适的架构。以下是这两种架构的对比:

架构

内存占用情况

代码大小

播放功能

录音功能

基础功能

混音功能

播放延迟

混音架构

相对较多

相对较多

相近

支持

相对较大

相同

直通架构

相对较少

相对较少

相近

不支持

相对较小

相同

  • 在录音实现方面,这两种架构是相同的。两种架构都可以满足用户的录音功能需求。

  • 在播放实现方面,这两种架构是不同的。如果用户需要同时播放两个声音,应选择混音器架构,因为只有混音器架构可以进行混音。

混音器架构占用更多的内存,并且代码体积更大。如果用户希望节省内存和代码体积,并且没有音频混音的需求,应选择直通架构。

音频术语

在本章中,一些常用音频术语的含义列出如下。

术语

简介

PCM

脉冲编码调制(Pulse Code Modulation,PCM)是一种音频信号的数字表示方法。

声道

声道是指在不同位置录音或播放的独立音频信号,因此声道的数量就是声源的数量。

mono

单声道。

stereo

双声道。

bit depth

位深表示在音频信号处理过程中使用的有效位数。

采样深度表示声音的分辨率。值越大,分辨率越高。

采样点

音频采样点是指从连续的模拟音频信号中,按照固定的时间间隔取样得到的离散数据点。

采样率

音频采样率指的是每秒对信号进行采样的帧数。采样率越高,音频品质越好。

帧是一个声音单元,其长度是样本长度乘以通道数量。

增益

音频信号增益控制用于调整信号幅度。

交错的

这是一种音频数据的录制方法。在交错模式下,数据以连续的方式存储,首先存储第一帧的所有通道样本,然后存储第二帧的数据。

延迟

信号通过整个系统时的时间延迟。

overrun

缓冲区过满,使得缓冲区生产者无法写入更多数据。

underrun

缓冲区生产者写入数据的速度太慢,导致当消费者想要消费数据时缓冲区是空的。

xrun

overrun 或者 underrun。

音量

声音强度和响度。

硬件音量

音频codec的音量。

软件音量

软件算法中的音量。

重采样

音频采样率转换。

格式转换

音频位深转换。

混音

将多个音频流混音在一起。用户可以听到多个音频流同时播放。

音频codec

芯片内部的数模转换器(DAC)和模数转换器(ADC)控制器。

音频格式

本节描述了音频框架和音频硬件抽象层(HAL)支持的数据格式。音频框架和音频HAL的共同部分将在这里进行描述,而不同的部分将在各自的章节中进行描述。

音频框架和音频硬件抽象层(HAL)都支持交错的流数据。

两声道交错数据示例如下: 两声道交错,四声道交错数据的示例如下: 四声道交错

../../_images/audio_two_channels_interleaved.svg

两声道交错

../../_images/audio_four_channels_interleaved.svg

四声道交错

音频架构

播放架构

音频混音器播放架构的框图如下所示。

../../_images/audio_playback_mixer_architecture.svg

播放混音架构

音频直通播放架构的框图如下所示。

../../_images/audio_playback_passthrough_architecture.svg

播放直通架构

音频播放架构包括以下子模块:

  • 音频框架层 (仅针对混音架构)

    • 音频框架负责音频播放声音混音。

    • 在混音之前,所有声音将被转换为一种统一的音频格式,默认是16位,44100Hz,2声道。音频框架中还有音量模块,用于调整不同音频类型的音量,例如,音乐和语音可能有不同的音量。

    • 音频框架支持从8k到96k的采样率,单声道/立体声,格式包括8位、16位、24位和32位浮点。

  • 硬件抽象层

    • 音频HAL从音频框架获取播放数据,并将数据发送到音频驱动程序。

  • 音频驱动

    • 音频驱动程序从音频HAL获取播放数据,并将数据发送到音频硬件。

录音架构

音频混音和直通架构具有相同的录音架构。音频录制的框图如下所示。

../../_images/audio_record_architecture.svg

录音架构

音频录制架构包含以下子模块:

  • RTAudioRecord: 从音频HAL录音,并将数据提供给需要录制数据的音频应用程序。

  • Audio HAL: 从音频驱动程序获取录制数据,并将数据发送到 RTAudioRecord。

  • Audio Driver: 从音频硬件获取录制数据,并将数据发送到音频HAL。

控制架构

音频混音和直通具有相同的控制架构。音频控制的框图如下所示。

../../_images/audio_control_architecture.svg

控制架构

音频控制架构包括以下子模块:

  • RTAudioControl: 由应用程序调用,并与HAL交互进行音频控制设置。

  • Audio HAL: 通过调用驱动程序API,进行音频控制设置。

  • Audio Driver: 控制音频CODEC硬件。

RTAudioControl 提供用于设置和获取硬件音量的接口。

#include "audio/audio_control.h"
int32_t RTAudioControl_SetHardwareVolume(float left_volume, float right_volume)

用户将左右声道的音量设置为0.0到1.0,这一设定线性映射到-65.625到最大分贝。

音频配置

菜单配置

如果用户想要使用音频接口,请选择下列音频配置,并根据该章节选择合适的音频架构: 架构选择

../../_images/audio_menuconfig.svg

音频配置菜单

框架配置

音频配置文件在: {SDK}/component/audio/configs/ameba_audio_mixer_usrcfg.cpp

如果用户想要更改音频HAL周期缓冲区大小,或音频混音器的缓冲策略,根据.h的描述 {SDK}/component/audio/configs/include/ameba_audio_mixer_usrcfg.h,修改 kPrimaryAudioConfig

配置 out_min_frames_stage 仅支持 RTAUDIO_OUT_MIN_FRAMES_STAGE1RTAUDIO_OUT_MIN_ FRAMES_STAGE2

  • RTAUDIO_OUT_MIN_FRAMES_STAGE1 意味着单次有更多的数据写入音频HAL。

  • RTAUDIO_OUT_MIN_FRAMES_STAGE2 意味着单次有较少的数据写入音频HAL。

RTAUDIO_OUT_MIN_FRAMES_STAGE2 使用该配置可以减少音频框架层的延迟,但是可能会因为用户送数据速度跟不上,更容易xrun引入noise. 用户可根据实验结果选择适合的配置。

HAL配置

硬件配置文件在: {SDK}/component/soc/amebaxx/usrcfg/include/ameba_audio_hw_usrcfg.h

不同的板子有不同的配置。例如,有些板子需要使用放大器,而有些则不需要。不同的板子可能使用不同的引脚来启用放大器;不同放大器的启动时间也有所不同。此外,每个板子使用的数字麦克风 (DMIC) 引脚可能不同,数字麦克风的稳定时间也可能不同。所有这些信息都需要在配置文件中进行配置。

文件 ameba_audio_hw_usrcfg.h 当中有各个配置的描述,请根据描述进行配置。

音频接口

音频组件提供了三层接口。

接口层级

介绍

音频驱动接口

提供音频硬件接口。

音频硬件抽象层接口

隔离操作系统和硬件设备,使得应用程序可以通过统一的接口访问音频硬件资源。

音频框架层接口

用户层接口,用来播放音频流,录制音频流,控制音频音量等。

接口层如下所示。

../../_images/audio_interfaces.svg

音频接口

驱动接口

  • SPORT接口,请参考: {SDK}/component/soc/amebadplus/fwlib/include/ameba_sport.h

  • CODEC接口,请参考: {SDK}/component/soc/amebadplus/fwlib/include/ameba_audio.h

I2S PLL APIs

有两种方式来生成I2S PLL:

  • 如果系统时钟是98.304M或者45.1584M的整数倍,我们可以在*SocClk_Info*数组中添加时钟,然后在 bootloader_km4.c 修改*SocClk_Info*数组中的索引. 如果您想要高品质的音频,您需要选择这种做法。

  • 如果系统时钟不是98.304M或者45.1584M的整数倍,在这种情况下,我们可以自动获取98.304M或者45.1584M。

具体细节如图所示。

../../_images/audio_i2s_pll_interfaces.svg

I2S PLL接口使用流程

HAL接口

音频HAL提供AudioHwStreamOut/AudioHwStreamIn/AudioHwControl接口来控制音频硬件。接口在于: {SDK}/component/audio/interfaces/hardware/audio。 这些接口中包含具体描述,使用前请阅读。

  • AudioHwStreamOut: 从上层接收PCM数据,通过音频驱动写入数据以将PCM数据发送到硬件,并提供关于音频输出硬件驱动的信息。

  • AudioHwStreamIn: 通过音频驱动接收PCM数据并发送到上层。

  • AudioHwControl: 接收来自上层的控制调用,并将控制信息设置给驱动程序。

AudioHwStreamOut/AudioHwStreamIn由AudioHwCard接口管理. 他们负责创建/销毁 AudioHwStreamOut/AudioHwStreamIn实例。 AudioHwCard是用于处理音频流的声卡。它包含一组端口和设备,具体如图所示。

  • Port – 声卡的输入/输出流称作:port。

  • Device – 声卡的输入/输出设备称作:device。

../../_images/audio_hal_architecture.svg

AudioHwCard 示例

AudioHwManager管理系统中所有的AudioHwCard,并根据给定的音频卡描述符打开指定的声卡驱动。

使用 AudioHwStreamOut

用户可以查看AudioHwStreamOut的示例,详情请见 {SDK}/component/example/audio/audio_hal_render。 以下描述了如何使用音频HAL接口播放音频原始数据(PCM格式):

  1. 使用 CreateAudioHwManager() 获取AudioHwManager句柄:

    struct AudioHwManager *audio_manager = CreateAudioHwManager();
    
  2. 使用 GetCards() 获取声卡描述符:

    int32_t cards_size = audio_manager->GetCardsCount(audio_manager);
    struct AudioHwCardDescriptor *card_descs = audio_manager->GetCards(audio_manager);
    
  3. 选择一个特定的声卡来播放音频(当前音频管理器仅支持主音频卡):

    struct AudioHwCardDescriptor *audio_card_desc;
    for (int32_t index = 0; index < cards_size; index++) {
       struct AudioHwCardDescriptor *desc = &card_descs[index];
       for (uint32_t port = 0; (desc != NULL && port < desc->port_num); port++) {
          printf("check for audio port \n");
          if (desc->ports[port].role == AUDIO_HW_PORT_ROLE_OUT &&
             (audio_card = audio_manager->OpenCard(audio_manager, desc))) {
             audio_port = desc->ports[port];
             audio_card_desc = desc;
             break;
          }
       }
    }
    
  4. 根据采样率,声道,格式,和AudioHwPathDescriptor,创建AudioHwConfig,然后使用 CreateStreamOut() 来基于选中的声卡创建AudioHwStreamOut:

    struct AudioHwConfig audio_config;
    audio_config.sample_rate = 48000;
    audio_config.channel_count = 2;
    audio_config.format = AUDIO_HW_FORMAT_PCM_16_BIT;
    struct AudioHwPathDescriptor path_desc;
    path_desc.port_index = audio_port.port_index;
    path_desc.devices = AUDIO_HW_DEVICE_OUT_SPEAKER;
    path_desc.flags = AUDIO_HW_INPUT_FLAG_NONE;
    audio_stream_out = audio_card->CreateStreamOut(audio_card, &path_desc, &audio_config);
    
  5. 重复写入PCM数据到AudioHwStreamOut。用户可以自定义写入的size大小。用户需要确保 size/frame_size 是整数。

    int32_t bytes = audio_stream_out->Write(audio_stream_out, buffer, size, true);
    
  6. 使用 DestroyStreamOut() 来关闭AudioHwStreamOut,以结束播放:

    audio_card->DestroyStreamOut(audio_card, audio_stream_out);
    
  7. 使用 CloseCard() 来销毁AudioHwCard,并使用DestoryAudioHwManager来释放AudioHwManager句柄:

    audio_manager->CloseCard(audio_manager, audio_card, audio_card_desc);
    DestoryAudioHwManager(audio_manager);
    

使用 AudioHwStreamIn

用户可以在如下目录找到AudioHwStreamOut的使用范例: {SDK}/component/example/audio/audio_hal_capture

以下是关于如何使用音频HAL接口录制音频原始数据的描述:

  1. 使用 CreateAudioHwManager() 来获取AudioHwManager实例:

    struct AudioHwManager *audio_manager = CreateAudioHwManager();
    
  2. 使用 GetCards() 来获取所有声卡描述符:

    int32_t cards_size = audio_manager->GetCardsCount(audio_manager);
    struct AudioHwCardDescriptor *card_descs = audio_manager->GetCards(audio_manager);
    
  3. 选择特定的录音卡进行录音(当前音频管理器仅支持主音频卡):

    struct AudioHwCardDescriptor *audio_card_in_desc = NULL;
    for (int32_t index = 0; index < cards_size; index++) {
       struct AudioHwCardDescriptor *desc = &card_descs[index];
       for (uint32_t port = 0; (desc != NULL && port < desc->port_num); port++) {
          if (desc->ports[port].role == AUDIO_HW_PORT_ROLE_IN &&
             (audio_card_in = audio_manager->OpenCard(audio_manager, desc))) {
             audio_port_in = desc->ports[port];
             audio_card_in_desc = desc;
             break;
          }
       }
    }
    
  4. 根据采样率、通道、格式和AudioHwPathDescriptor创建AudioHwConfig。然后使用 CreateStreamIn() 来基于声卡创建AudioHwStreamIn:

    struct AudioHwConfig audio_config;
    audio_config.sample_rate = 48000;
    audio_config.channel_count = 2;
    audio_config.format = AUDIO_HW_FORMAT_PCM_16_BIT;
    struct AudioHwPathDescriptor path_desc_in;
    path_desc_in.port_index = audio_port_in.port_index;
    path_desc_in.devices = AUDIO_HW_DEVICE_IN_MIC;
    path_desc_in.flags = AUDIO_HW_INPUT_FLAG_NONE;
    audio_stream_in = audio_card_in->CreateStreamIn(audio_card_in, &path_desc_in, &audio_config);
    
  5. 重复从AudioHwStreamIn中读取PCM数据。此大小可以由用户定义。用户需要确保 size/frame_size 是整数。

    audio_stream_in->Read(audio_stream_in, buffer, size);
    
  6. 使用 DestroyStreamIn() 来关闭AudioHwStreamIn,以结束录音:

    audio_card_in->DestroyStreamIn(audio_card_in, audio_stream_in);
    
  7. 使用 CloseCard() 来释放AudioHwCard,并调用函数 DestoryAudioHwManager() 释放AudioHwManager句柄。

    audio_manager->CloseCard(audio_manager, audio_card_in, audio_card_in_desc);
    DestoryAudioHwManager(audio_manager);
    

使用 AudioHwControl

以下是一个示例,展示了如何使用音频 HAL 接口来控制音频CODEC:

AudioHwControl 始终是线程安全的,调用非常方便。要使用 AudioHwControl,函数调用的第一个参数应该始终是 GetAudioHwControl()。 以PLL clock设定为例:

GetAudioHwControl()->AdjustPLLClock(GetAudioHwControl(), rate, ppm, action);

音频框架接口

音频流接口

音频流接口包括 RTAudioTrack 和 RTAudioRecord 接口。这些接口位于: {SDK}/component/audio/interfaces/audio. 这些接口中有具体的说明,请在使用前阅读。

  • RTAudioTrack: 初始化框架中播放数据流的格式,从应用程序接收PCM数据,并将数据写入音频框架(混音器)或音频HAL(直通)。

  • RTAudioRecord: 初始化框架中录制数据流的格式,从音频HAL接收PCM数据,并将数据发送到应用程序。

使用 RTAudioTrack

RTAudioTrack RTAudioTrack 支持播放多种常见的音频原始格式类型,以便音频可以轻松集成到应用程序中。

音频框架具有以下音频播放流类型。应用程序可以使用这些类型来初始化 RTAudioTrack。框架获取流类型并根据这些类型进行音量混合。

  • RTAUDIO_CATEGORY_MEDIA - 如果应用程序想要播放音乐,那么其类型为 RTAUDIO_CATEGORY_MEDIA,可以使用此类型来初始化RTAudioTrack. 音频框架会识别它的类型,并将其与媒体音量混合。

  • RTAUDIO_CATEGORY_COMMUNICATION - 如果应用程序想要进行电话通话并输出通话声音,声音的类型应为 RTAUDIO_CATEGORY_COMMUNICATION

  • RTAUDIO_CATEGORY_SPEECH - 输出语音声音。

  • RTAUDIO_CATEGORY_BEEP - 如果声音是按键音或其他哔声,则其类型为**RTAUDIO_CATEGORY_BEEP**。

RTAudioTrack的测试demo在:{SDK}/component/example/audio/audio_track

以下是一个演示如何播放音频原始数据的示例:

  1. 在使用RTAudioTrack之前,RTAudioService需要先进行初始化:

    RTAudioService_Init();
    
  2. 创建RTAudioTrack来播放音频:

    struct RTAudioTrack* audio_track = RTAudioTrack_Create();
    

    应用程序可以使用音频配置 API 提供有关特定音频播放源的详细音频信息,包括流类型(播放源类型)、格式、声道数、采样率和 RTAudioTrack环形缓冲区大小。语法如下:

    typedef struct {
    uint32_t category_type;
    uint32_t sample_rate;
    uint32_t channel_count;
    uint32_t format;
    uint32_t buffer_bytes;
    } RTAudioTrackConfig;
    

    这里:

    category_type:

    定义播放数据源的流类型。

    sample_rate:

    播放源原始数据的采样率。

    channel_count:

    播放源原始数据的声道数。

    format:

    播放源原始数据的位深。

    buffer_bytes:

    RTAudioTrack的环形缓冲区大小,以避免xrun。

    备注

    RTAudioTrackConfig 中的 buffer_bytes 非常重要。缓冲区大小应始终大于音频框架计算出的最小缓冲区大小,否则将会发生溢出。

  3. 使用该接口获取最小的 RTAudioTrack 缓冲区字节数,并以此作为参考来定义 RTAudioTrack 的缓冲区大小:

    例如,您可以将最小缓冲区大小*4作为缓冲区大小。 您使用的缓冲区越大,播放就会越流畅,但可能会导致较高的延迟。缓冲区大小由您自行决定。

    int track_buf_size = RTAudioTrack_GetMinBufferBytes(audio_track, type, rate, format, channels) * 4;
    
  4. 使用此缓冲区大小和其他音频参数来创建 RTAudioTrackConfig 对象,以下是一个示例:

    RTAudioTrackConfig track_config;
    track_config.category_type = RTAUDIO_CATEGORY_MEDIA;
    track_config.sample_rate = rate;
    track_config.format = format;
    track_config.buffer_bytes = track_buf_size;
    track_config.channel_count = channel_count;
    

    通过 RTAudioTrackConfig 对象,我们可以初始化 RTAudioTrack。在此步骤中,将根据缓冲区字节数创建一个环形缓冲区。

    RTAudioTrack_Init(audio_track, &track_config);
    
  5. 当所有准备工作完成后,启动 RTAudioTrack 并检查是否成功启动。

    if(RTAudioTrack_Start(audio_track) != 0){
       //track start fail
       return;
    }
    

    RTAudioTrack 的默认音量是最大值 1.0,您可以使用以下 API 调整音量。

    RTAudioTrack_SetVolume(audio_track, 1.0, 1.0);
    

    备注

    • 在混音器架构中,此 API 设置当前 audio_track 的软件音量。

    • 在直通架构中,此 API 不支持。

  6. 将音频数据写入框架。用户可以自定义write_size,但需要确保 write_size/frame_size 为整数。

    RTAudioTrack_Write(audio_track, buffer, write_size, true);
    
  7. 如果用户想要暂停并停止写入数据,可以调用以下 API 来通知框架执行暂停操作:

    RTAudioTrack_Pause(audio_track);
    RTAudioTrack_Flush(audio_track);
    
  8. 如果用户想要停止播放音频,可以停止写入数据,然后调用API RTAudioTrack_Stop()

    RTAudioTrack_Stop(audio_track);
    
  9. 在audio_track指针无用时将其删除。

    RTAudioTrack_Destroy(audio_track);
    
使用 RTAudioRecord

RTAudioRecord 支持多种常见的音频原始格式类型,因此您可以轻松地将录音集成到应用程序中。

RTAudioRecord 支持以下音频输入源:

  • RTDEVICE_IN_MIC - 如果应用程序想要从麦克风录音,请选择此输入源。

  • RTDEVICE_IN_I2S - 如果应用程序想要从I2S录音,请选择此输入源。

RTAudioRecord测试范例在: {SDK}/component/example/audio/audio_record

以下是一个展示如何录制音频原始数据的示例:

  1. 创建RTAudioRecord

    struct RTAudioRecord *audio_record = RTAudioRecord_Create();
    
  2. 应用程序可以使用音频配置API来提供有关特定音频记录源的详细音频信息,包括记录设备源、格式、声道数量和采样率。

    语法如下:

    typedef struct {
    uint32_t sample_rate;
    uint32_t channel_count;
    uint32_t format;
    uint32_t device;
    uint32_t buffer_bytes;
    } RTAudioRecordConfig;
    

    这里

    sample_rate:

    原始数据的采样率。

    channel_count:

    原始数据的声道数。

    format:

    原始数据的位深。

    device:

    音频输入设备。

    buffer_bytes:

    框架中的音频缓冲字节数。设置为0使用默认值。用户也可以设置其他值,较大的 buffer_bytes 意味着较大的延迟。

    以下是一个展示如何创建 RTAudioRecord 的 RTAudioRecordConfig 对象的示例:

    RTAudioRecordConfig record_config;
    record_config.sample_rate = rate;
    record_config.format = RTAUDIO_FORMAT_PCM_16_BIT;
    record_config.channel_count = channels;
    record_config.device = RTDEVICE_IN_MIC;
    record_config.buffer_bytes = 0;
    
  3. 创建 RTAudioRecordConfig 对象后,初始化 RTAudioRecord。在此步骤中,将根据音频输入设备源打开音频HAL的AudioHwCard:

    RTAudioRecord_Init(audio_record, &record_config);
    
  4. 当所有准备工作完成后,开始音频录制:

    RTAudioRecord_Start(audio_record);
    
  5. 读取音频麦克风数据。读取的大小可以由用户定义。用户需要确保 size/frame_size 是整数。

    RTAudioRecord_Read(audio_record, buffer, size, true);
    
  6. 当录音结束时,停止录音:

    RTAudioRecord_Stop(audio_record);
    
  7. 当 audio_record 不再使用时,销毁它以避免内存泄漏:

    RTAudioRecord_Destroy(audio_record);
    

音频控制接口

音频控制接口包括 RTAudioControl 接口,用于与音频控制 HAL 交互。 RTAudioControl 提供了用于设置和获取硬件音量、设置输出设备等的接口。这些接口位于 SDK/component/audio/interfaces/audio/audio_control.h 这些接口有具体的描述,在使用前请阅读。

使用 RTAudioControl

要使用 RTAudioControl,请调用RTAudioControl设置DAC的音频硬件音量:

RTAudioControl_SetHardwareVolume(0.5, 0.5);

对于播放和录音情况,大多数 RTAudioControl API 可以随时随地调用,它们可以直接工作。 只有 RTAudioControl_SetPlaybackDevice() 混音架构中需要在函数 RTAudioService_Init() 之前调用,直通架构需要在 RTAudioTrack_Start() 函数之前调用。