发布时间:2025-06-24 19:31:50 作者:北方职教升学中心 阅读量:222
📝往期推文全新看点(文中附带最新·鸿蒙全栈学习笔记)
🚩 鸿蒙(HarmonyOS)北向开发知识点记录~
🚩 鸿蒙(OpenHarmony)南向开发保姆级知识点汇总~
🚩 鸿蒙应用开发与鸿蒙系统开发哪个更有前景?
🚩 嵌入式开发适不适合做鸿蒙南向开发?看完这篇你就了解了~
🚩 对于大前端开发来说,转鸿蒙开发究竟是福还是祸?
🚩 鸿蒙岗位需求突增!移动端、OHAudio依赖libohaudio.so动态库,通过引入<native_audiostreambuilder.h>
和<native_audiocapturer.h)>头文件,使用音频录制相关API。
AudioCapture
使用AudioCapturer录制音频涉及到AudioCapturer实例的创建、
权限申请
音频采集需要动态申请权限,现在module.json5中声明权限:
"requestPermissions": [ { "name": "ohos.permission.MICROPHONE", "reason": "$string:reason", "usedScene": { "abilities": [ "FormAbility" ], "when": "inuse" } } ],
动态申请权限:
function reqPermissionsFromUser(permissions: Array<Permissions>, context: common.UIAbilityContext): void { let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager(); // requestPermissionsFromUser会判断权限的授权状态来决定是否唤起弹窗 atManager.requestPermissionsFromUser(context, permissions).then((data) => { let grantStatus: Array<number> = data.authResults; let length: number = grantStatus.length; for (let i = 0; i < length; i++) { if (grantStatus[i] === 0) { // 用户授权,可以继续访问目标操作 } else { // 用户拒绝授权,提示用户必须授权才能访问当前页面的功能,并引导用户到系统设置中打开相应的权限 return; } } // 授权成功 }).catch((err: BusinessError) => { console.error(`Failed to request permissions from user. Code is ${err.code}, message is ${err.message}`); }) }
在aboutToAppera中调用申请权限方法,在授权成功后启动录音
const context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext; reqPermissionsFromUser(permissions, context); }
配置C++项目
创建C++模块后,配置ohaudio动态库依赖:
cmake_minimum_required(VERSION 3.5.0) project(audiorecorderdemo) set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR}) if(DEFINED PACKAGE_FIND_FILE) include(${PACKAGE_FIND_FILE}) endif() include_directories(${NATIVERENDER_ROOT_PATH} ${NATIVERENDER_ROOT_PATH}/include) add_library(capture SHARED napi_init.cpp) target_link_libraries(capture PUBLIC libace_napi.z.so) target_link_libraries(capture PUBLIC libohaudio.so)
配置napi方法:
static napi_value start(napi_env env, napi_callback_info info) { return nullptr; } static napi_value stop(napi_env env, napi_callback_info info) { return nullptr; } EXTERN_C_START static napi_value Init(napi_env env, napi_value exports) { napi_property_descriptor desc[] = { { "start", nullptr, start, nullptr, nullptr, nullptr, napi_default, nullptr }, { "stop", nullptr, stop, nullptr, nullptr, nullptr, napi_default, nullptr } }; napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); return exports; }
实现启动录制
// 自定义写入数据函数 int32_t MyOnReadData( OH_AudioCapturer* capturer, void* userData, void* buffer, int32_t length) { //TODO 从buffer中取出length长度的录音数据 return 0; } // 自定义音频流事件函数 int32_t MyOnStreamEvent( OH_AudioCapturer* capturer, void* userData, OH_AudioStream_Event event) { //TODO 根据event表示的音频流事件信息,更新播放器状态和界面 return 0; } // 自定义音频中断事件函数 int32_t MyOnInterruptEvent( OH_AudioCapturer* capturer, void* userData, OH_AudioInterrupt_ForceType type, OH_AudioInterrupt_Hint hint) { //TODO 根据type和hint表示的音频中断信息,更新录制器状态和界面 return 0; } // 自定义异常回调函数 int32_t MyOnError( OH_AudioCapturer* capturer, void* userData, OH_AudioStream_Result error) { //TODO 根据error表示的音频异常信息,做出相应的处理 return 0; } static napi_value start(napi_env env, napi_callback_info info) { OH_AudioStreamBuilder* builder; OH_AudioStreamBuilder_Create(&builder, AUDIOSTREAM_TYPE_CAPTURER); // 设置音频采样率 OH_AudioStreamBuilder_SetSamplingRate(builder, 48000); // 设置音频声道 OH_AudioStreamBuilder_SetChannelCount(builder, 2); // 设置音频采样格式 OH_AudioStreamBuilder_SetSampleFormat(builder, AUDIOSTREAM_SAMPLE_S16LE); // 设置音频流的编码类型 OH_AudioStreamBuilder_SetEncodingType(builder, AUDIOSTREAM_ENCODING_TYPE_RAW); // 设置输入音频流的工作场景 OH_AudioStreamBuilder_SetCapturerInfo(builder, AUDIOSTREAM_SOURCE_TYPE_MIC); OH_AudioCapturer_Callbacks callbacks; // 配置回调函数 callbacks.OH_AudioCapturer_OnReadData = MyOnReadData; callbacks.OH_AudioCapturer_OnStreamEvent = MyOnStreamEvent; callbacks.OH_AudioCapturer_OnInterruptEvent = MyOnInterruptEvent; callbacks.OH_AudioCapturer_OnError = MyOnError; // 设置音频输入流的回调 OH_AudioStreamBuilder_SetCapturerCallback(builder, callbacks, nullptr); OH_AudioCapturer* audioCapturer; OH_AudioStreamBuilder_GenerateCapturer(builder, &audioCapturer); return nullptr; }
最佳实践一:
为了避免不可预期的行为,在设置音频回调函数时,请确保OH_AudioCapturer_Callbacks的每一个回调都被自定义的回调方法或空指针初始化,比如:
OH_AudioCapturer_Callbacks callbacks;// 配置回调函数,如果需要监听,则赋值callbacks.OH_AudioCapturer_OnReadData = MyOnReadData;callbacks.OH_AudioCapturer_OnInterruptEvent = MyOnInterruptEvent;// (必选)如果不需要监听,使用空指针初始化callbacks.OH_AudioCapturer_OnStreamEvent = nullptr;callbacks.OH_AudioCapturer_OnError = nullptr;
最佳实践二:
对于支持低延时模式的设备,对于延时要求比较高的场景(比如语音通话)可以使用低时延模式创建音频录制构造器,获得更高质量的音频体验:
OH_AudioStream_LatencyMode latencyMode = AUDIOSTREAM_LATENCY_MODE_FAST;OH_AudioStreamBuilder_SetLatencyMode(builder, latencyMode);
音频文件处理
在音频回调中我们对音频数据就行处理,可以交给ASR也可以直接写入文件,下一篇我们实现编码成mp3并写入文件的实践。
<native_audiostreambuilder.h>
和<native_audiocapturer.h)>头文件,使用音频录制相关API。"requestPermissions": [ { "name": "ohos.permission.MICROPHONE", "reason": "$string:reason", "usedScene": { "abilities": [ "FormAbility" ], "when": "inuse" } } ],
function reqPermissionsFromUser(permissions: Array<Permissions>, context: common.UIAbilityContext): void { let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager(); // requestPermissionsFromUser会判断权限的授权状态来决定是否唤起弹窗 atManager.requestPermissionsFromUser(context, permissions).then((data) => { let grantStatus: Array<number> = data.authResults; let length: number = grantStatus.length; for (let i = 0; i < length; i++) { if (grantStatus[i] === 0) { // 用户授权,可以继续访问目标操作 } else { // 用户拒绝授权,提示用户必须授权才能访问当前页面的功能,并引导用户到系统设置中打开相应的权限 return; } } // 授权成功 }).catch((err: BusinessError) => { console.error(`Failed to request permissions from user. Code is ${err.code}, message is ${err.message}`); }) }
const context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext; reqPermissionsFromUser(permissions, context); }
cmake_minimum_required(VERSION 3.5.0) project(audiorecorderdemo) set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR}) if(DEFINED PACKAGE_FIND_FILE) include(${PACKAGE_FIND_FILE}) endif() include_directories(${NATIVERENDER_ROOT_PATH} ${NATIVERENDER_ROOT_PATH}/include) add_library(capture SHARED napi_init.cpp) target_link_libraries(capture PUBLIC libace_napi.z.so) target_link_libraries(capture PUBLIC libohaudio.so)
static napi_value start(napi_env env, napi_callback_info info) { return nullptr; } static napi_value stop(napi_env env, napi_callback_info info) { return nullptr; } EXTERN_C_START static napi_value Init(napi_env env, napi_value exports) { napi_property_descriptor desc[] = { { "start", nullptr, start, nullptr, nullptr, nullptr, napi_default, nullptr }, { "stop", nullptr, stop, nullptr, nullptr, nullptr, napi_default, nullptr } }; napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); return exports; }
// 自定义写入数据函数 int32_t MyOnReadData( OH_AudioCapturer* capturer, void* userData, void* buffer, int32_t length) { //TODO 从buffer中取出length长度的录音数据 return 0; } // 自定义音频流事件函数 int32_t MyOnStreamEvent( OH_AudioCapturer* capturer, void* userData, OH_AudioStream_Event event) { //TODO 根据event表示的音频流事件信息,更新播放器状态和界面 return 0; } // 自定义音频中断事件函数 int32_t MyOnInterruptEvent( OH_AudioCapturer* capturer, void* userData, OH_AudioInterrupt_ForceType type, OH_AudioInterrupt_Hint hint) { //TODO 根据type和hint表示的音频中断信息,更新录制器状态和界面 return 0; } // 自定义异常回调函数 int32_t MyOnError( OH_AudioCapturer* capturer, void* userData, OH_AudioStream_Result error) { //TODO 根据error表示的音频异常信息,做出相应的处理 return 0; } static napi_value start(napi_env env, napi_callback_info info) { OH_AudioStreamBuilder* builder; OH_AudioStreamBuilder_Create(&builder, AUDIOSTREAM_TYPE_CAPTURER); // 设置音频采样率 OH_AudioStreamBuilder_SetSamplingRate(builder, 48000); // 设置音频声道 OH_AudioStreamBuilder_SetChannelCount(builder, 2); // 设置音频采样格式 OH_AudioStreamBuilder_SetSampleFormat(builder, AUDIOSTREAM_SAMPLE_S16LE); // 设置音频流的编码类型 OH_AudioStreamBuilder_SetEncodingType(builder, AUDIOSTREAM_ENCODING_TYPE_RAW); // 设置输入音频流的工作场景 OH_AudioStreamBuilder_SetCapturerInfo(builder, AUDIOSTREAM_SOURCE_TYPE_MIC); OH_AudioCapturer_Callbacks callbacks; // 配置回调函数 callbacks.OH_AudioCapturer_OnReadData = MyOnReadData; callbacks.OH_AudioCapturer_OnStreamEvent = MyOnStreamEvent; callbacks.OH_AudioCapturer_OnInterruptEvent = MyOnInterruptEvent; callbacks.OH_AudioCapturer_OnError = MyOnError; // 设置音频输入流的回调 OH_AudioStreamBuilder_SetCapturerCallback(builder, callbacks, nullptr); OH_AudioCapturer* audioCapturer; OH_AudioStreamBuilder_GenerateCapturer(builder, &audioCapturer); return nullptr; }
为了避免不可预期的行为,在设置音频回调函数时,请确保OH_AudioCapturer_Callbacks的每一个回调都被自定义的回调方法或空指针初始化,比如:
OH_AudioCapturer_Callbacks callbacks;// 配置回调函数,如果需要监听,则赋值callbacks.OH_AudioCapturer_OnReadData = MyOnReadData;callbacks.OH_AudioCapturer_OnInterruptEvent = MyOnInterruptEvent;// (必选)如果不需要监听,使用空指针初始化callbacks.OH_AudioCapturer_OnStreamEvent = nullptr;callbacks.OH_AudioCapturer_OnError = nullptr;
对于支持低延时模式的设备,对于延时要求比较高的场景(比如语音通话)可以使用低时延模式创建音频录制构造器,获得更高质量的音频体验:
OH_AudioStream_LatencyMode latencyMode = AUDIOSTREAM_LATENCY_MODE_FAST;OH_AudioStreamBuilder_SetLatencyMode(builder, latencyMode);
构造录制音频流
OH_AudioCapturer* audioCapturer;OH_AudioStreamBuilder_GenerateCapturer(builder, &audioCapturer);
使用音频流
- OH_AudioStream_Result OH_AudioCapturer_Start(OH_AudioCapturer* capturer):开始录制
- OH_AudioStream_Result OH_AudioCapturer_Pause(OH_AudioCapturer* capturer):暂停录制
- OH_AudioStream_Result OH_AudioCapturer_Stop(OH_AudioCapturer* capturer):停止录制
- OH_AudioStream_Result OH_AudioCapturer_Flush(OH_AudioCapturer* capturer):释放缓存数据
- OH_AudioStream_Result OH_AudioCapturer_Release(OH_AudioCapturer* capturer):释放录制实例
释放构造器
OH_AudioStreamBuilder_Destroy(builder);
音频录制最佳实践
我们以录制MP3为例来实现音频采集的全流程实践。
设置音频回调函数
// 自定义写入数据函数int32_t MyOnReadData( OH_AudioCapturer* capturer, void* userData, void* buffer, int32_t length){ // 从buffer中取出length长度的录音数据 return 0;}// 自定义音频流事件函数int32_t MyOnStreamEvent( OH_AudioCapturer* capturer, void* userData, OH_AudioStream_Event event){ // 根据event表示的音频流事件信息,更新播放器状态和界面 return 0;}// 自定义音频中断事件函数int32_t MyOnInterruptEvent( OH_AudioCapturer* capturer, void* userData, OH_AudioInterrupt_ForceType type, OH_AudioInterrupt_Hint hint){ // 根据type和hint表示的音频中断信息,更新录制器状态和界面 return 0;}// 自定义异常回调函数int32_t MyOnError( OH_AudioCapturer* capturer, void* userData, OH_AudioStream_Result error){ // 根据error表示的音频异常信息,做出相应的处理 return 0;}OH_AudioCapturer_Callbacks callbacks;// 配置回调函数callbacks.OH_AudioCapturer_OnReadData = MyOnReadData;callbacks.OH_AudioCapturer_OnStreamEvent = MyOnStreamEvent;callbacks.OH_AudioCapturer_OnInterruptEvent = MyOnInterruptEvent;callbacks.OH_AudioCapturer_OnError = MyOnError;// 设置音频输入流的回调OH_AudioStreamBuilder_SetCapturerCallback(builder, callbacks, nullptr);
通过OH_AudioStreamBuilder_SetCapturerCallback函数配置回调函数。
创建构造器
OH_AudioStreamBuilder* builder;OH_AudioStreamBuilder_Create(&builder, AUDIOSTREAM_TYPE_CAPTURER);
配置音频流参数
可参考如下示例:
// 设置音频采样率OH_AudioStreamBuilder_SetSamplingRate(builder, 48000);// 设置音频声道OH_AudioStreamBuilder_SetChannelCount(builder, 2);// 设置音频采样格式OH_AudioStreamBuilder_SetSampleFormat(builder, AUDIOSTREAM_SAMPLE_S16LE);// 设置音频流的编码类型OH_AudioStreamBuilder_SetEncodingType(builder, AUDIOSTREAM_ENCODING_TYPE_RAW);// 设置输入音频流的工作场景OH_AudioStreamBuilder_SetCapturerInfo(builder, AUDIOSTREAM_SOURCE_TYPE_MIC);
参数作用于AudioCapture类似。很多音频编码库都是C/C++实现的,在迁移到 鸿蒙 平台后,采集侧也使用OHAudio C++接口,可以减少数据在TS层与C++层传递的消耗,提高效率。在Android和iOS端,系统提供了两种形式:
- 实时音频流采集
- 音频文件录制
系统还提供了不同形式的API,比如Android:
- AudioRecorder Java接口
- MediaRecorder Java接口
- OpenSLES C++接口
- AAudio C++接口
在 鸿蒙 化适配的过程中也有音频采集的需求,本文我们一步一步实现音频采集功能。资源的释放等,下面官方给出的状态示意图将方法和状态切换标记的很清晰:
createAudioCapture
创建capture主要涉及到参数配置:
import { audio } from '@kit.AudioKit'; let audioStreamInfo: audio.AudioStreamInfo = { samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_48000, // 采样率 channels: audio.AudioChannel.CHANNEL_2, // 通道 sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE, // 采样格式 encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW // 编码格式 }; let audioCapturerInfo: audio.AudioCapturerInfo = { source: audio.SourceType.SOURCE_TYPE_MIC, capturerFlags: 0 }; let audioCapturerOptions: audio.AudioCapturerOptions = { streamInfo: audioStreamInfo, capturerInfo: audioCapturerInfo }; audio.createAudioCapturer(audioCapturerOptions, (err, data) => { if (err) { } else { let audioCapturer = data; } });
参数包含两大块:
- AudioStreamInfo:音频格式配置信息
- samplingRate:采样率
- channels:声道数
- sampleFormat:采样格式
- encodingType:音频编码类型,目前只支持PCM的ENCODING_TYPE_RAW配置
- AudioCapturerInfo:采集配置信息
- source:音源类型,包含:
- SOURCE_TYPE_INVALID:无效的音频源
- SOURCE_TYPE_MIC:Mic音频源
- SOURCE_TYPE_VOICE_RECOGNITION:语音识别源
- SOURCE_TYPE_PLAYBACK_CAPTURE:播放音频流(内录)录制音频源
- SOURCE_TYPE_VOICE_COMMUNICATION:语音通话场景的音频源
- SOURCE_TYPE_VOICE_MESSAGE:短语音消息的音频源
- capturerFlags:音频采集器标志,0代表音频采集器
- source:音源类型,包含:
on(‘readData’)
on(‘readData’)方法用来订阅监听音频数据读入回调:
let readDataCallback = (buffer: ArrayBuffer) => {//处理音频流}audioCapturer.on('readData', readDataCallback);
start
start方法用来开始录制:
import { BusinessError } from '@kit.BasicServicesKit'; audioCapturer.start((err: BusinessError) => { if (err) { } else { } });
stop
stop用来停止录制:
import { BusinessError } from '@kit.BasicServicesKit'; audioCapturer.stop((err: BusinessError) => { if (err) { } else { } });
release
release销毁实例,释放资源
import { BusinessError } from '@kit.BasicServicesKit'; audioCapturer.release((err: BusinessError) => { if (err) { } else { } });
OHAudio
OHAudio是系统在API version 10中引入的一套C API,此API在设计上实现归一,同时支持普通音频通路和低时延通路。PC端、IoT到底该怎么选?
🚩 记录一场鸿蒙开发岗位面试经历~
📃 持续更新中……
背景
应用开发过程中很多场景都有音频采集需求,比如聊天功能的发送语音功能,实时语音转文本功能,实时语音通话,实时视频通话等。
音频录制接口介绍
HarmonyOS 提供了TS与C++两种音频采集接口:
- AudioCapture
- OHAudio
分别介绍这两种语言的API。采集的开始与停止、
停止播放销毁实例
OH_AudioCapturer_Stop(builder, &audioCapturer);OH_AudioStreamBuilder_Destroy(builder);
总结
本文介绍了HarmonyOS 提供的两种音频采集方式:TS层的AudioCapture和C++层的OHAudio,并以OHAudio接口实现了实时音频采集功能。音频采集参数的配置、仅支持PCM格式,适用于依赖Native层实现音频输入功能的场景。