鸿蒙开发实战:【音频组件】

简介

音频组件用于实现音频相关的功能,包括音频播放,录制,音量管理和设备管理。

图 1 音频组件架构图

基本概念

  • 采样

采样是指将连续时域上的模拟信号按照一定的时间间隔采样,获取到离散时域上离散信号的过程。

  • 采样率

采样率为每秒从连续信号中提取并组成离散信号的采样次数,单位用赫兹(Hz)来表示。通常人耳能听到频率范围大约在20Hz~20kHz之间的声音。常用的音频采样频率有:8kHz、11.025kHz、22.05kHz、16kHz、37.8kHz、44.1kHz、48kHz、96kHz、192kHz等。

  • 声道

声道是指声音在录制或播放时在不同空间位置采集或回放的相互独立的音频信号,所以声道数也就是声音录制时的音源数量或回放时相应的扬声器数量。

  • 音频帧

音频数据是流式的,本身没有明确的一帧帧的概念,在实际的应用中,为了音频算法处理/传输的方便,一般约定俗成取2.5ms~60ms为单位的数据量为一帧音频。这个时间被称之为“采样时间”,其长度没有特别的标准,它是根据编解码器和具体应用的需求来决定的。

  • PCM

PCM(Pulse Code Modulation),即脉冲编码调制,是一种将模拟信号数字化的方法,是将时间连续、取值连续的模拟信号转换成时间离散、抽样值离散的数字信号的过程。

目录

仓目录结构如下:

/foundation/multimedia/audio_standard  # 音频组件业务代码
├── frameworks                         # 框架代码
│   ├── native                         # 内部接口实现
│   └── js                             # 外部接口实现
│       └── napi                       # napi 外部接口实现
├── interfaces                         # 接口代码
│   ├── inner_api                      # 内部接口
│   └── kits                           # 外部接口
├── sa_profile                         # 服务配置文件
├── services                           # 服务代码
├── LICENSE                            # 证书文件
└── bundle.json                        # 编译文件

使用说明

音频播放

可以使用此仓库内提供的接口将音频数据转换为音频模拟信号,使用输出设备播放音频信号,以及管理音频播放任务。以下步骤描述了如何使用 AudioRenderer 开发音频播放功能:

  1. 使用 Create 接口和所需流类型来获取 AudioRenderer 实例。

    AudioStreamType streamType = STREAM_MUSIC; // 流类型示例
    std::unique_ptr<AudioRenderer> audioRenderer = AudioRenderer::Create(streamType);
    
  2. (可选)静态接口 GetSupportedFormats(), GetSupportedChannels(), GetSupportedEncodingTypes(), GetSupportedSamplingRates() 可用于获取支持的参数。

  3. 准备设备,调用实例的 SetParams 。

    AudioRendererParams rendererParams;
    rendererParams.sampleFormat = SAMPLE_S16LE;
    rendererParams.sampleRate = SAMPLE_RATE_44100;
    rendererParams.channelCount = STEREO;
    rendererParams.encodingType = ENCODING_PCM;
    
    audioRenderer->SetParams(rendererParams);
    
  4. (可选)使用 audioRenderer->GetParams(rendererParams) 来验证 SetParams。

  5. (可选)使用 SetAudioEffectMode 和 GetAudioEffectMode 接口来设置和获取当前音频流的音效模式。

    AudioEffectMode effectMode = EFFECT_DEFAULT;
    int32_t result = audioRenderer->SetAudioEffectMode(effectMode);
    AudioEffectMode mode = audioRenderer->GetAudioEffectMode();
    
  6. AudioRenderer 实例调用 audioRenderer->Start() 函数来启动播放任务。

  7. 使用 GetBufferSize 接口获取要写入的缓冲区长度。

    audioRenderer->GetBufferSize(bufferLen);
    
  8. 从源(例如音频文件)读取要播放的音频数据并将其传输到字节流中。重复调用Write函数写入渲染数据。

    bytesToWrite = fread(buffer, 1, bufferLen, wavFile);
    while ((bytesWritten < bytesToWrite) && ((bytesToWrite - bytesWritten) > minBytes)) {
        bytesWritten += audioRenderer->Write(buffer + bytesWritten, bytesToWrite - bytesWritten);
        if (bytesWritten < 0)
            break;
    }
    
  9. 调用audioRenderer->Drain()来清空播放流。

  10. 调用audioRenderer->Stop()来停止输出。

  11. 播放任务完成后,调用AudioRenderer实例的audioRenderer->Release()函数来释放资源。

以上提供了基本音频播放使用场景。

  1. 使用 audioRenderer->SetVolume(float)  和 audioRenderer->GetVolume()  来设置和获取当前音频流音量, 可选范围为 0.0 到 1.0。

音频录制

可以使用此仓库内提供的接口,让应用程序可以完成使用输入设备进行声音录制,将语音转换为音频数据,并管理录制的任务。以下步骤描述了如何使用 AudioCapturer 开发音频录制功能:

  1. 使用Create接口和所需流类型来获取 AudioCapturer 实例。

    AudioStreamType streamType = STREAM_MUSIC;
    std::unique_ptr<AudioCapturer> audioCapturer = AudioCapturer::Create(streamType);
    
  2. (可选)静态接口 GetSupportedFormats(), GetSupportedChannels(), GetSupportedEncodingTypes(), GetSupportedSamplingRates() 可用于获取支持的参数。

  3. 准备设备,调用实例的 SetParams 。

    AudioCapturerParams capturerParams;
    capturerParams.sampleFormat = SAMPLE_S16LE;
    capturerParams.sampleRate = SAMPLE_RATE_44100;
    capturerParams.channelCount = STEREO;
    capturerParams.encodingType = ENCODING_PCM;
    
    audioCapturer->SetParams(capturerParams);
    
  4. (可选)使用 audioCapturer->GetParams(capturerParams) 来验证 SetParams()。

  5. AudioCapturer 实例调用 AudioCapturer->Start() 函数来启动录音任务。

  6. 使用 GetBufferSize 接口获取要写入的缓冲区长度。

    audioCapturer->GetBufferSize(bufferLen);
    
  7. 读取录制的音频数据并将其转换为字节流。重复调用read函数读取数据直到主动停止。

    // set isBlocking = true/false for blocking/non-blocking read
    bytesRead = audioCapturer->Read(*buffer, bufferLen, isBlocking);
    while (numBuffersToCapture) {
        bytesRead = audioCapturer->Read(*buffer, bufferLen, isBlockingRead);
        if (bytesRead <= 0) {
            break;
        } else if (bytesRead > 0) {
            fwrite(buffer, size, bytesRead, recFile); // example shows writes the recorded data into a file
            numBuffersToCapture--;
        }
    }
    
  8. (可选)audioCapturer->Flush() 来清空录音流缓冲区。

  9. AudioCapturer 实例调用 audioCapturer->Stop() 函数停止录音。

  10. 录音任务完成后,调用 AudioCapturer 实例的 audioCapturer->Release() 函数释放资源。

音频管理

可以使用 [audio_system_manager.h]内的接口来控制音量和设备。

  1. 使用 GetInstance 接口获取 AudioSystemManager 实例.

    AudioSystemManager *audioSystemMgr = AudioSystemManager::GetInstance();
    
音量控制
  1. 使用 GetMaxVolume 和 GetMinVolume 接口去查询音频流支持的最大和最小音量等级,在此范围内设置音量。

    AudioVolumeType streamType = AudioVolumeType::STREAM_MUSIC;
    int32_t maxVol = audioSystemMgr->GetMaxVolume(streamType);
    int32_t minVol = audioSystemMgr->GetMinVolume(streamType);
    
  2. 使用 SetVolume 和 GetVolume 接口来设置和获取指定音频流的音量等级。

    int32_t result = audioSystemMgr->SetVolume(streamType, 10);
    int32_t vol = audioSystemMgr->GetVolume(streamType);
    
  3. 使用 SetMute 和 IsStreamMute 接口来设置和获取指定音频流的静音状态。

    int32_t result = audioSystemMgr->SetMute(streamType, true);
    bool isMute = audioSystemMgr->IsStreamMute(streamType);
    
  4. 使用 SetRingerMode 和 GetRingerMode 接口来设置和获取铃声模式。参考在 [audio_info.h]定义的 AudioRingerMode 枚举来获取支持的铃声模式。

    int32_t result = audioSystemMgr->SetRingerMode(RINGER_MODE_SILENT);
    AudioRingerMode ringMode = audioSystemMgr->GetRingerMode();
    
  5. 使用 SetMicrophoneMute 和 IsMicrophoneMute 接口来设置和获取麦克风的静音状态。

    int32_t result = audioSystemMgr->SetMicrophoneMute(true);
    bool isMicMute = audioSystemMgr->IsMicrophoneMute();
    
设备控制
  1. 使用 GetDevicesdeviceType_  和 deviceRole_  接口来获取音频输入输出设备信息。 内定义的DeviceFlag, DeviceType 和 DeviceRole 枚举。

    DeviceFlag deviceFlag = OUTPUT_DEVICES_FLAG;
    vector<sptr<AudioDeviceDescriptor>> audioDeviceDescriptors
        = audioSystemMgr->GetDevices(deviceFlag);
    sptr<AudioDeviceDescriptor> audioDeviceDescriptor = audioDeviceDescriptors[0];
    cout << audioDeviceDescriptor->deviceType_;
    cout << audioDeviceDescriptor->deviceRole_;
    
  2. 使用 SetDeviceActive 和 IsDeviceActive 接口去激活/去激活音频设备和获取音频设备激活状态。

    ActiveDeviceType deviceType = SPEAKER;
    int32_t result = audioSystemMgr->SetDeviceActive(deviceType, true);
    bool isDevActive = audioSystemMgr->IsDeviceActive(deviceType);
    
  3. 提供其他用途的接口如 IsStreamActiveSetAudioParameter and GetAudioParameter

  4. 应用程序可以使用 AudioManagerNapi::On注册系统音量的更改。 在此,如果应用程序监听到系统音量更改的事件,就会用以下参数通知应用程序: volumeType : 更改的系统音量的类型 volume : 当前的音量等级 updateUi : 是否需要显示变化详细信息。(如果音量被增大/减小,将updateUi标志设置为true,在其他情况下,updateUi设置为false)。

    const audioManager = audio.getAudioManager();
    
    export default {
      onCreate() {
        audioManager.on('volumeChange', (volumeChange) ==> {
          console.info('volumeType = '+volumeChange.volumeType);
          console.info('volume = '+volumeChange.volume);
          console.info('updateUi = '+volumeChange.updateUi);
        }
      }
    }
    
音频场景
  1. 使用 SetAudioScene 和 getAudioScene 接口去更改和检查音频策略。

    int32_t result = audioSystemMgr->SetAudioScene(AUDIO_SCENE_PHONE_CALL);
    AudioScene audioScene = audioSystemMgr->GetAudioScene();
    

有关支持的音频场景,请参阅 AudioScene 中的枚举[audio_info.h]

音频流管理

可以使用[audio_stream_manager.h]提供的接口用于流管理功能。

  1. 使用 GetInstance 接口获得 AudioSystemManager 实例。

    AudioStreamManager *audioStreamMgr = AudioStreamManager::GetInstance();
    
  2. 使用 RegisterAudioRendererEventListener 为渲染器状态更改注册侦听器。渲染器状态更改回调,该回调将在渲染器流状态更改时调用, 通过重写 AudioRendererStateChangeCallback 类中的函数 OnRendererStateChange 。

    const int32_t clientPid;
    
    class RendererStateChangeCallback : public AudioRendererStateChangeCallback {
    public:
        RendererStateChangeCallback = default;
        ~RendererStateChangeCallback = default;
    void OnRendererStateChange(
        const std::vector<std::unique_ptr<AudioRendererChangeInfo>> &audioRendererChangeInfos) override
    {
        cout<<"OnRendererStateChange entered"<<endl;
    }
    };
    
    std::shared_ptr<AudioRendererStateChangeCallback> callback = std::make_shared<RendererStateChangeCallback>();
    int32_t state = audioStreamMgr->RegisterAudioRendererEventListener(clientPid, callback);
    int32_t result = audioStreamMgr->UnregisterAudioRendererEventListener(clientPid);
    
  3. 使用 RegisterAudioCapturerEventListener 为捕获器状态更改注册侦听器。 捕获器状态更改回调,该回调将在捕获器流状态更改时调用, 通过重写 AudioCapturerStateChangeCallback 类中的函数 OnCapturerStateChange 。

    const int32_t clientPid;
    
    class CapturerStateChangeCallback : public AudioCapturerStateChangeCallback {
    public:
        CapturerStateChangeCallback = default;
        ~CapturerStateChangeCallback = default;
    void OnCapturerStateChange(
        const std::vector<std::unique_ptr<AudioCapturerChangeInfo>> &audioCapturerChangeInfos) override
    {
        cout<<"OnCapturerStateChange entered"<<endl;
    }
    };
    
    std::shared_ptr<AudioCapturerStateChangeCallback> callback = std::make_shared<CapturerStateChangeCallback>();
    int32_t state = audioStreamMgr->RegisterAudioCapturerEventListener(clientPid, callback);
    int32_t result = audioStreamMgr->UnregisterAudioCapturerEventListener(clientPid);
    
  4. 使用 GetCurrentRendererChangeInfos 获取所有当前正在运行的流渲染器信息,包括clientuid、sessionid、renderinfo、renderstate和输出设备详细信息。

    std::vector<std::unique_ptr<AudioRendererChangeInfo>> audioRendererChangeInfos;
    int32_t currentRendererChangeInfo = audioStreamMgr->GetCurrentRendererChangeInfos(audioRendererChangeInfos);
    
  5. 使用 GetCurrentCapturerChangeInfos 获取所有当前正在运行的流捕获器信息,包括clientuid、sessionid、capturerInfo、capturerState和输入设备详细信息。

    std::vector<std::unique_ptr<AudioCapturerChangeInfo>> audioCapturerChangeInfos;
    int32_t currentCapturerChangeInfo = audioStreamMgr->GetCurrentCapturerChangeInfos(audioCapturerChangeInfos);
    
  6. 使用 IsAudioRendererLowLatencySupported 检查低延迟功能是否支持。

    const AudioStreamInfo &audioStreamInfo;
    bool isLatencySupport = audioStreamMgr->IsAudioRendererLowLatencySupported(audioStreamInfo);
    
  7. 使用 GetEffectInfoArray 接口查询指定[StreamUsage]下可以支持的音效模式。

    AudioSceneEffectInfo audioSceneEffectInfo;
    int32_t status = audioStreamMgr->GetEffectInfoArray(audioSceneEffectInfo,streamUsage);
    
JavaScript 用法:

JavaScript应用可以使用系统提供的音频管理接口,来控制音量和设备。
请参考 [js-apis-audio.md]来获取音量和设备管理相关JavaScript接口的用法。

蓝牙SCO呼叫

可以使用提供的接口 [audio_bluetooth_manager.h] 实现同步连接导向链路(SCO)的蓝牙呼叫。

  1. 为监听SCO状态更改,您可以使用 OnScoStateChanged.
const BluetoothRemoteDevice &device;
int state;
void OnScoStateChanged(const BluetoothRemoteDevice &device, int state);
  1. (可选) 静态接口 RegisterBluetoothScoAgListener(), UnregisterBluetoothScoAgListener(), 可用于注册蓝牙SCO的侦听器。

支持设备

以下是音频子系统支持的设备类型列表。

  1. USB Type-C Headset
    数字耳机,包括自己的DAC(数模转换器)和作为耳机一部分的放大器。

  2. WIRED Headset
    模拟耳机内部不包含任何DAC。它可以有3.5mm插孔或不带DAC的C型插孔。

  3. Bluetooth Headset
    蓝牙A2DP(高级音频分配模式)耳机,用于无线传输音频。

  4. Internal Speaker and MIC
    支持内置扬声器和麦克风,并将分别用作播放和录制的默认设备。

    鸿蒙OpenHarmony知识已更新←前往

5a94ffa1b62d74e6095eff0d95d75612.gif

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

数据仓库的设计开发应用(一)

目录 一、数据仓库设计的特点二、数据仓库系统开发过程三、数据仓库系统的规划 一、数据仓库设计的特点 1、“数据驱动” 的设计 数据仓库是从已有数据出发的设计方法&#xff0c;即从数据源抽取数据&#xff0c;经转换形成面向主题&#xff0c;支持决策的数据集合。 以全面了…

MapReduce的原理分析

1.概述 MapReduce的思想核心是“分而治之,先分再合”&#xff0c;适用于大量复杂任务处理场景(大规模数据处理场景)。 MapReduce分两个阶段: map阶段(分)&#xff1a;如果任何可以拆分并且没有依赖&#xff0c;那么就把复杂的任务拆分成小任务&#xff0c;拆分成小任务之后&a…

【云原生-kubernetes系列】--kubernetes日志收集

1、ELK架构 1.1、部署ES集群 https://mirrors.tuna.tsinghua.edu.cn/elasticstack/apt/7.x/pool/main/e/elasticsearch/ 1、下载软件包 rootes-server1:~# wget https://mirrors.tuna.tsinghua.edu.cn/elasticstack/apt/7.x/pool/main/e/elasticsearch/elasticsearch-7.12.0-…

QMI8658芯片I2C驱动开发指南

这个芯片纯国产挺好用的&#xff0c;电路很好设计&#xff0c;我这垃圾焊功&#xff0c;纯手焊&#xff0c;&#xff0c;居然能用。 第一部分 硬件连接 画的很简陋&#xff0c;看看就可以了&#xff0c;这里I2C总线需要接10K上拉没有画出来&#xff0c;这个需要注意一下。 …

【XR806开发板试用】基于WEBSOCKET实现人机交互(控制开关灯)以及开发问题记录

一、开发板编译、功能介绍 根据官方文档编译烧录成功后&#xff0c;我们修改下官方例子&#xff0c;进行开发来实现websocket。 整体流程&#xff1a;开发板先自动寻找指定的wifi并且连接&#xff0c;连接成功后&#xff0c;通过websocket来与服务端连接&#xff0c;连接成功后…

idea项目mapper.xml中的SQL语句黄色下划线去除

问题描述 当我们使用idea开发java项目时&#xff0c;经常会与数据库打交道&#xff0c;一般在使用mybatis的时候需要写一大堆的mapper.xml以及SQL语句&#xff0c;每当写完SQL语句的时候总是有黄色下划线&#xff0c;看着很不舒服。 解决方案&#xff1a; 修改idea的配置 Edi…

实验01 ASP.NET网站的建立及运行

【实验目的】 &#xff08;1&#xff09;能熟悉ASP.NET的开发环境Visual Studio Community 2019&#xff08;VSC 2019&#xff09;。 &#xff08;2&#xff09;能通过解决方案管理网站&#xff0c;会在解决方案中创建网站。 &#xff08;3&#xff09;会设置IIS 10中的网站…

Node.js(1)

跨平台的node.js运行环境&#xff0c;使开发者可以搭建服务器端的js应用程序 它可以编写服务器端程序&#xff1b; 编写数据接口&#xff1b;提供网页资源浏览功能 前端工程化&#xff1a;开发集成的所有工具和技术 与浏览器环境的区别 node.js环境中没有DOM和BOM fs模块-读…

Linux下安装多个nodejs并映射Jenkins

背景 需要Jenkins中切换多个Node&#xff0c;比如nodejs16和nodesjs18,所以在宿主机按照好这两个版本&#xff0c;然后再映射到Jenkins容器中 步骤 1.下载地址 https://nodejs.org/dist/ 放到 cd /opt/soft/2.解压 tar -xzvf node-v16.20.0-linux-x64.tar.gz tar -xzvf n…

SSM SpringBoot vue智能手机参数分析平台

SSM SpringBoot vue智能手机参数分析平台 系统功能 首页 图片轮播 新闻资讯 手机信息 手机百科 登录注册 个人中心 后台管理 登录注册 个人中心 手机百科管理 用户管理 手机对比管理 配置管理 新闻资讯管理 手机信息管理 对比信息管理 我的收藏管理 开发环境和技术 开发语言…

Kafka配置SASL_PLAINTEXT权限。常用操作命令,创建用户,topic授权

查看已经创建的topic ./bin/kafka-topics.sh --bootstrap-server localhost:9092 --list 创建topic 创建分区和副本数为1的topic ./bin/kafka-topics.sh --create --bootstrap-server localhost:9092 --topic acltest --partitions 1 --replication-factor 1 创建kafka用户 …

迷宫寻路[天梯赛 -- 栈]

文章目录 题目描述思路AC代码 题目描述 输入样例 8 8 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 0 0 1 1 0 0 0 1 1 1 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 1 0 0 0 1 1 1 0 1 1 0 1 0 0 0 0 0 0 0 4 4 0 0 1 0 0 0 0 0 0 0 1 1 0 1 0 0 -1 -1输出样例 1,1 2,1 3,1 4,1 5,1 5,2 5…

修复ElementUI中el-select与el-option无法通过v-model实现数据双向绑定的问题

1. 问题描述 需求&#xff1a;在使用ElementUI时&#xff0c;通过el-select和el-option标签实现下拉列表功能&#xff0c;当el-option中的选项被选中时&#xff0c;被选中的选项可以正确回显到已选择的列表中。 对于上面的下拉列表&#xff0c;当我们选中“超级管理员”的选项…

Tomcat的使用

1. Tomcat 1.1 Tomcat 是什么 Tomcat 就是基于 Java 实现的一个开源免费, 也是被广泛使用的 HTTP 服务器 1.2 下载安装 Tomcat官网选择其中的 zip 压缩包, 下载后解压缩即可&#xff0c;解压缩的目录最好不要带 “中文” 或者 特殊符号 进入 webapps 目录,每个文件夹都对应…

vue3项目随笔1

1,Eslint Prettier 报错情况&#xff1a; 解决办法&#xff1a; &#xff08;1&#xff09;下载Prettier - code formatter &#xff08;2&#xff09;配置setting.json文件 文件 -> 首选项 -> 设置 -> 用户 -> Eslint "editor.defaultFormatter":…

【Hadoop】Hadoop概述与核心组件

目录 Hadoop概述Hadoop 发展历史Hadoop 三大发行版本1.Apache Hadoop&#xff08;常用&#xff09;2.Cloudera Hadoop3.Hortonworks Hadoop优势优势总结——4高&#xff08;高可靠、高扩展、高效、高容错&#xff09; Hadoop组成1.HDFS管理者&#xff1a;NameNode&#xff08;n…

【计算机网络_传输层】UDP和TCP协议

文章目录 1. 重新理解端口号端口号划分netstat指令pidof 2. UDP协议2.1 UDP协议端格式2.2 UDP的特点2.3 UDP的注意事项2.4 基于UDP的应用层协议 3. TCP协议&#xff08;传输控制协议&#xff09;3.1 TCP协议的格式和报头字段3.2 如何解包和分用3.3 理解TCP协议报头3.4 TCP协议的…

解决electron打包vue-element-admin项目页面无法跳转的问题

解决electron打包vue-element-admin项目页面无法跳转的问题 说明之前通过这个教程已经打包成功&#xff0c;但是发现进行账号密码登录后页面无法跳转的问题。现在已经解决&#xff0c;所以记录一下。 1、检查路由模式是否为hash模式&#xff0c;如果不是改成hash模式。 new Ro…

【DL经典回顾】激活函数大汇总(十五)(LogSoftmax附代码和详细公式)

激活函数大汇总&#xff08;十五&#xff09;&#xff08;LogSoftmax附代码和详细公式&#xff09; 更多激活函数见激活函数大汇总列表 一、引言 欢迎来到我们深入探索神经网络核心组成部分——激活函数的系列博客。在人工智能的世界里&#xff0c;激活函数扮演着不可或缺的…

【矩阵】54. 螺旋矩阵【中等】

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