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

简介

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

图 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 filenumBuffersToCapture--;}
    }
    
  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.mzph.cn/news/747658.shtml

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

相关文章

Hystrix的原理及应用:构建微服务容错体系的利器(二)

本系列文章简介&#xff1a; 本系列文章旨在深入剖析Hystrix的原理及应用&#xff0c;帮助大家理解其如何在微服务容错体系中发挥关键作用。我们将从Hystrix的核心原理出发&#xff0c;探讨其隔离、熔断、降级等机制的实现原理&#xff1b;接着&#xff0c;我们将结合实际应用场…

鸿蒙Harmony应用开发—ArkTS声明式开发(容器组件:RelativeContainer)

相对布局组件&#xff0c;用于复杂场景中元素对齐的布局。 说明&#xff1a; 该组件从API Version 9开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 规则说明 容器内子组件区分水平方向&#xff0c;垂直方向&#xff1a; 水平方向为left&…

华为云计算hcie认证考什么?华为hciie认证好考吗

1.理论知识&#xff1a;HCIE认证首先要求考生具备扎实的云计算理论基础&#xff0c;包括云计算的基本概念、架构、关键技术、安全管理等方面的知识。考生需要深入理解云计算的核心原理&#xff0c;以及华为云计算产品的特点和优势。 2.实践技能&#xff1a;除了理论知识外&…

HTTPS的工作过程

一、HTTPS 是什么 HTTPS 也是⼀个应用层协议&#xff0c;是在 HTTP 协议的基础上引入了⼀个加密层. HTTP 协议内容都是按照文本的方式明文传输的。这就导致在传输过程中出现⼀些被篡改的情况. 在互联网上, 明文传输是比较危险的事情!!! HTTPS 就是在 HTTP 的基础上进行了加密…

platform设备注册驱动模块的测试

一. 简介 上一篇文章编写了 platform设备注册代码&#xff0c;文章地址如下&#xff1a; 无设备树platform驱动实验&#xff1a;platform设备注册代码实现-CSDN博客 本文继续无设备树platform驱动实验&#xff0c;本文对编译好的 设备注册程序进行测试&#xff0c;测试所实…

(二)丶RabbitMQ的六大核心

一丶什么是MQ Message Queue(消息队列&#xff09;简称MQ&#xff0c;是一种应用程序对应用程序的消息通信机制。在MQ中&#xff0c;消息以队列形式存储&#xff0c;以便于异步传输&#xff0c;在MQ中&#xff0c;发布者&#xff08;生产者&#xff09;将消息放入队列&#xff…

LeetCode 面试经典150题 80.删除有序数组中的重复项II

题目&#xff1a; 给你一个有序数组 nums &#xff0c;请你 原地 删除重复出现的元素&#xff0c;使得出现次数超过两次的元素只出现两次 &#xff0c;返回删除后数组的新长度。 不要使用额外的数组空间&#xff0c;你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件…

百度paddleocr GPU版部署

显卡&#xff1a;NVIDIA GeForce RTX 4070&#xff0c;Nvidia驱动程序版本&#xff1a;537.13 Nvidia驱动程序能支持的最高cuda版本&#xff1a;12.2.138 Python&#xff1a;python3.10.11。试过python3.12&#xff0c;安装paddleocr失败&#xff0c;找不到相关模块。 飞桨版本…

Linux从0到1——Linux第一个小程序:进度条

Linux从0到1——Linux第一个小程序&#xff1a;进度条 1. 输出缓冲区2. 回车和换行的本质3. 实现进度条3.1 简单原理版本3.2 实际工程版本 1. 输出缓冲区 1. 小实验&#xff1a; 编写一个test.c文件&#xff0c;&#xff1a; #include <stdio.h> #include <unistd.h…

老电脑装什么系统流畅

对于一些老旧电脑来说&#xff0c;重装系统是提升电脑性能的最佳选择。那么&#xff0c;老电脑装什么系统流畅呢&#xff1f;推荐Windows 7系统&#xff0c;它对硬件的需求相对较低。配置较低的电脑运行Windows 7可以更好地利用系统资源&#xff0c;提高电脑的运行速度和响应能…

【学习】目标检测中的anchor

参考知乎&#xff1a;anchor 简单理解 每个网格都会有一个自己的中心&#xff0c;每个小格子都可以抽象成为在自己的中心生成了一个指定大小为16个像素的矩形框&#xff0c;在这里&#xff0c;我们把这些中心称之为”锚点“&#xff0c;把每个锚点处的框称之为”锚框“。 锚…

ZooKeeper 概述

定义和功能 ZooKeeper 是一个开源的分布式协调服务&#xff0c;由 Apache 软件基金会托管。它主要用于解决分布式应用中遇到的一些复杂问题&#xff0c;如命名服务、状态同步服务、集群管理、分布式锁和队列管理等。 核心特性 一致性: ZooKeeper 保证了客户端之间的数据一致性…

c语言实现https客户端 源码+详细注释(OpenSSL下载,visual studio编译器环境配置)

OpenSSL的下载和环境配置 请参考&#xff1a;openssl下载安装教程 步骤&#xff1a;官网下载->安装到选定目录->配置环境变量->打开命令窗口检查是否安装成功 注意&#xff1a; 打开命令窗口&#xff08;快捷键winr,在弹出窗口内输入cmd按回车&#xff09;&#xff0…

ChatGPT解决hmm...something seems to have gone wrong.

ChatGPT解决hmm…something seems to have gone wrong. 这里是官方社区的一种workaround办法。仅仅只是mark一下。 我这边遇到的现象是&#xff0c;ChatGPT 3.5是正常的&#xff0c;但是使用ChatGPT 4就会频繁的出现这样的输出。而且恶心的是&#xff0c;即使是这种输出&…

安卓性能优化面试题 11-15

11. 简述APK安装包瘦身方案 ?(1):剔 除掉冗余的代码与不必要的jar包;具体来讲的话,我们可以使用SDK集成的ProGuard混淆工具,它可以在编译时检查并删除未使用的类、字段、方法 和属性,它会遍历所有代码找到无用处的代码,所有那些不可达的代码都会在生成最终apk文件之前被…

(三)丶RabbitMQ的四种类型交换机

前言&#xff1a;四大交换机工作原理及实战应用 1.交换机的概念 交换机可以理解成具有路由表的路由程序&#xff0c;仅此而已。每个消息都有一个称为路由键&#xff08;routing key&#xff09;的属性&#xff0c;就是一个简单的字符串。最新版本的RabbitMQ有四种交换机类型&a…

java高可用系统之降级 + 熔断

服务降级&#xff1a;服务器压力太大&#xff0c;根据当前业务及流量对一些服务和页面有策略的降级&#xff0c;保证核心任务事务正常运行。 降级方式包括&#xff1a; 延迟服务&#xff1a;发表评论是重要服务&#xff0c;要保证正常运行&#xff0c;但是给用户加积分&#…

音频数据如果在中断中会随机给的那就放入队列或者缓冲区;队列缓冲区对音频的作用

回采的数据是在中断函数au0_dma_isr_data_output里面给的&#xff0c;而给算法的时候是在主程序karaok_sdadc_process&#xff0c;这样子就会出现中断给的数据和当前的mic帧不匹配&#xff0c;或者说每次的差值不一定&#xff0c;算法就会有问题&#xff0c;解决办法是讲回采数…

云计算2主从数据库

设置主从数据库的目的是将数据库1和数据库2分别建在两个虚拟机上&#xff0c;并实现数据互通访问 首先准备两个虚拟机&#xff0c;这里示例ip分别为&#xff1a; 192.168.200.10&#xff1b;192.168.200.20 修改主机名&#xff0c;一个是mysql1&#xff0c;一个是mysql2&#x…

vscode 运行 java 项目之解决“Build failed, do you want to continue”的问题

Visual Studio Code运行 java 起来似乎比 IDEA 更轻量、比 eclipse 更友好&#xff0c;是不可多得的现代编译法宝。 安装好官方推荐的 java 扩展包后&#xff0c;就可以运行 java 代码了。功能 比 code runner 强&#xff0c;支持 gradle、maven、普通java项目&#xff0c;运行…