【鸿蒙实战开发】基于OHAudio的音频操作

169 篇文章 1 订阅
169 篇文章 1 订阅

1:场景描述

场景:基于OHAudio模块实现音频录制和播放功能,带监听音频打断实现使用OH_AudioCapturer接口录制音频生成PCM文件写入到文件保存到沙箱路径,再使用OH_AudioRenderer接口播放音频文件,并监听音频打断

使用的核心API:

AudioCapturer :音频采集,用于录制PCM音频数据。

AudioRenderer :音频渲染,用于播放PCM音频数据。

OHAudio: 提供音频模块C接口定义。

2:方案描述

场景一:普通录制和播放实现

Step1:导入audio模块, 引入OHAudio头文件, 提供播放和录制能力的API

Step2:使用OH_AudioCapturer接口录制功能实现

Step3:使用OH_AudioRenderer接口播放功能实现

Step4:监听音频打断实现

场景二:低时延模式录制和低时延播放实现

可以将普通录制和播放切换为低时延录制和低时延播放

效果如下:

场景:普通录制和播放实现

具体步骤如下:

步骤一:导入audio模块, 引入OHAudio头文件, 提供播放和录制能力的API

引入音频库和动态链接库


import { BusinessError } from '@ohos.base';

import audioPlayer from 'libentry.so'

动态链接库audioPlayer里面声明相关函数定义


export const audioCapturerLowLatencyInit: () => void;

export const audioCapturerStart: () => void;

export const audioCapturerPause: () => void;

export const audioCapturerStop: () => void;

export const audioCapturerRelease: () => void;

export const audioRendererInit: () => void;

export const audioRendererLowLatencyInit: () => void;

export const audioRendererStart: () => void;

export const audioRendererPause: () => void;

export const audioRendererStop: () => void;

export const audioRendererRelease: () => void;

export const getRendererState: () => number;

export const getFileState: () => number;

export const getFramesWritten: () => number;

export const getFileSize: () => number;

export const closeFile: () => number;

native侧接口映射,native侧和JS侧方法交互


{

napi_property_descriptor desc[] = {

{"closeFile", nullptr, CloseFile, nullptr, nullptr, nullptr, napi_default, nullptr},

{"audioCapturerLowLatencyInit", nullptr, AudioCapturerLowLatencyInit, nullptr, nullptr, nullptr, napi_default,

nullptr},

{"audioCapturerInit", nullptr, AudioCapturerInit, nullptr, nullptr, nullptr, napi_default, nullptr},

{"audioCapturerStart", nullptr, AudioCapturerStart, nullptr, nullptr, nullptr, napi_default, nullptr},

{"audioCapturerPause", nullptr, AudioCapturerPause, nullptr, nullptr, nullptr, napi_default, nullptr},

{"audioCapturerRelease", nullptr, AudioCapturerRelease, nullptr, nullptr, nullptr, napi_default, nullptr},

{"audioCapturerStop", nullptr, AudioCapturerStop, nullptr, nullptr, nullptr, napi_default, nullptr},

{"audioRendererLowLatencyInit", nullptr, AudioRendererLowLatencyInit, nullptr, nullptr, nullptr, napi_default,

nullptr},

{"audioRendererInit", nullptr, AudioRendererInit, nullptr, nullptr, nullptr, napi_default, nullptr},

{"audioRendererStart", nullptr, AudioRendererStart, nullptr, nullptr, nullptr, napi_default, nullptr},

{"audioRendererPause", nullptr, AudioRendererPause, nullptr, nullptr, nullptr, napi_default, nullptr},

{"audioRendererRelease", nullptr, AudioRendererRelease, nullptr, nullptr, nullptr, napi_default, nullptr},

{"getRendererState", nullptr, GetRendererState, nullptr, nullptr, nullptr, napi_default, nullptr},

{"getFileSize", nullptr, GetFileSize, nullptr, nullptr, nullptr, napi_default, nullptr},

{"getFramesWritten", nullptr, GetFramesWritten, nullptr, nullptr, nullptr, napi_default, nullptr},

{"getFileState", nullptr, GetFileState, nullptr, nullptr, nullptr, napi_default, nullptr},

{"audioRendererStop", nullptr, AudioRendererStop, nullptr, nullptr, nullptr, napi_default, nullptr}};

napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);

return exports;

}

EXTERN_C_END

步骤二:录制实现

Step1:创建录制和播放构造器


static OH_AudioRenderer *audioRenderer;

static OH_AudioStreamBuilder *builder;

static OH_AudioStreamBuilder *rendererBuilder;

Step2:构造录制音频流,设置音频流参数和音频回调函数


{

if (audioCapturer) {

OH_AudioCapturer_Release(audioCapturer);

OH_AudioStreamBuilder_Destroy(builder);

fclose(g_file);

g_file = nullptr;

audioCapturer = nullptr;

builder = nullptr;

}

g_file = fopen(g_filePath.c_str(), "wb");

// create builder

OH_AudioStream_Type type = AUDIOSTREAM_TYPE_CAPTURER;

OH_AudioStreamBuilder_Create(&builder, type);

// set params and callbacks

OH_AudioStreamBuilder_SetSamplingRate(builder, g_samplingRate);

OH_AudioStreamBuilder_SetChannelCount(builder, g_channelCount);

callbacks.OH_AudioCapturer_OnReadData = AudioCapturerOnReadData;

OH_AudioStreamBuilder_SetCapturerCallback(builder, callbacks, nullptr);

// create OH_AudioCapturer

OH_AudioStreamBuilder_GenerateCapturer(builder, &audioCapturer);

return nullptr;

}

// 低时延录制实现只需在普通录制的基础上切换成低时延模式

static napi_value AudioCapturerLowLatencyInit(napi_env env, napi_callback_info info)

{

...

OH_AudioStreamBuilder_SetLatencyMode(builder, (OH_AudioStream_LatencyMode)g_latencyMode);

...

}

Step3:开始录制,暂停录制,停止录制


{

// start

OH_AudioCapturer_Start(audioCapturer);

return nullptr;

}

static napi_value AudioCapturerPause(napi_env env, napi_callback_info info)

{

OH_AudioCapturer_Pause(audioCapturer);

return nullptr;

}

static napi_value AudioCapturerStop(napi_env env, napi_callback_info info)

{

OH_AudioCapturer_Stop(audioCapturer);

return nullptr;

}

Step4:将采集到的音频数据写入文件中


{

size_t count = 1;

if (fwrite(buffer, bufferLen, count, g_file) != count) {

printf("buffer fwrite err");

}

return 0;

}

// 文件路径

static std::string g_filePath = "/data/storage/el2/base/haps/entry/files/oh_test_audio.pcm";

Step5:释放构造器


{

if (audioCapturer) {

OH_AudioCapturer_Release(audioCapturer);

OH_AudioStreamBuilder_Destroy(builder);

audioCapturer = nullptr;

builder = nullptr;

}

return nullptr;

}

步骤三:播放实现

Step1:构造播放音频流,设置音频流参数和音频回调函数


{

if (audioRenderer) {

OH_AudioRenderer_Release(audioRenderer);

OH_AudioStreamBuilder_Destroy(rendererBuilder);

fclose(g_file);

g_file = nullptr;

audioRenderer = nullptr;

rendererBuilder = nullptr;

}

g_file = fopen(g_filePath.c_str(), "rb");

if (g_file == nullptr) {

return 0;

}

// create builder

OH_AudioStream_Type type = AUDIOSTREAM_TYPE_RENDERER;

OH_AudioStreamBuilder_Create(&rendererBuilder, type);

// set params and callbacks

OH_AudioStreamBuilder_SetSamplingRate(rendererBuilder, g_samplingRate);

OH_AudioStreamBuilder_SetChannelCount(rendererBuilder, g_channelCount);

rendererCallbacks.OH_AudioRenderer_OnWriteData = AudioRendererOnWriteData;

OH_AudioStreamBuilder_SetRendererCallback(rendererBuilder, rendererCallbacks, nullptr);

OH_AudioRenderer_Callbacks callbacks;

// 配置回调函数

callbacks.OH_AudioRenderer_OnWriteData = MyOnWriteData;

callbacks.OH_AudioRenderer_OnStreamEvent = MyOnStreamEvent;

callbacks.OH_AudioRenderer_OnInterruptEvent = MyOnInterruptEvent;

callbacks.OH_AudioRenderer_OnError = MyOnError;

OH_AudioStreamBuilder_GenerateRenderer(rendererBuilder, &audioRenderer);

g_readEnd = false;

g_rendererLowLatency = false;

return nullptr;

}

// 低时延播放实现只需在普通播放的基础上切换成低时延模式

static napi_value AudioRendererLowLatencyInit(napi_env env, napi_callback_info info)

{

...

OH_AudioStreamBuilder_SetLatencyMode(rendererBuilder, (OH_AudioStream_LatencyMode)g_latencyMode);

...

}

Step2:读取音频文件进行渲染


{

size_t readCount = fread(buffer, bufferLen, 1, g_file);

if (!readCount) {

if (ferror(g_file)) {

printf("Error reading myfile");

} else if (feof(g_file)) {

OH_AudioRenderer_Stop(audioRenderer);

OH_AudioRenderer_Release(audioRenderer);

OH_AudioStreamBuilder_Destroy(rendererBuilder);

fclose(g_file);

g_file = fopen(g_filePath.c_str(), "rb");

// 1\. create builder

OH_AudioStream_Type type = AUDIOSTREAM_TYPE_RENDERER;

OH_AudioStreamBuilder_Create(&rendererBuilder, type);

// 2\. set params and callbacks

OH_AudioStreamBuilder_SetSamplingRate(rendererBuilder, g_samplingRate);

OH_AudioStreamBuilder_SetChannelCount(rendererBuilder, g_channelCount);

if (g_rendererLowLatency) {

OH_AudioStreamBuilder_SetLatencyMode(rendererBuilder, (OH_AudioStream_LatencyMode)g_latencyMode);

}

rendererCallbacks.OH_AudioRenderer_OnWriteData = AudioRendererOnWriteData;

OH_AudioStreamBuilder_SetRendererCallback(rendererBuilder, rendererCallbacks, nullptr);

// 3\. create OH_AudioRenderer

OH_AudioStreamBuilder_GenerateRenderer(rendererBuilder, &audioRenderer);

g_readEnd = true;

}

}

return 0;

}

Step3:开始播放,暂停播放,停止播放


{

g_readEnd = false;

// start

OH_AudioRenderer_Start(audioRenderer);

return nullptr;

}

static napi_value AudioRendererPause(napi_env env, napi_callback_info info)

{

g_readEnd = false;

OH_AudioRenderer_Pause(audioRenderer);

return nullptr;

}

static napi_value AudioRendererStop(napi_env env, napi_callback_info info)

{

g_readEnd = false;

OH_AudioRenderer_Stop(audioRenderer);

return nullptr;

}

Step4:释放构造器


{

if (audioRenderer) {

OH_AudioRenderer_Release(audioRenderer);

OH_AudioStreamBuilder_Destroy(rendererBuilder);

audioRenderer = nullptr;

rendererBuilder = nullptr;

}

return nullptr;

}

步骤四:OHAudio监听音频打断实现


int32_t MyOnWriteData(OH_AudioRenderer *renderer, void *userData, void *buffer, int32_t length) {

// 将待播放的数据,按length长度写入buffer

if (g_file == nullptr) {

LOGI("MyOnWriteData length fopen");

g_file = fopen(g_filePath.c_str(), "r");

} else if (feof(g_file)) {

LOGI("MyOnWriteData length fseek");

fseek(g_file, 0, SEEK_SET);

}

LOGI("MyOnWriteData length %{public}d", length);

size_t readCount = fread(buffer, length, 1, g_file);

return 0;

}

// 自定义音频流事件函数

int32_t MyOnStreamEvent(OH_AudioRenderer *renderer, void *userData, OH_AudioStream_Event event) {

// 根据event表示的音频流事件信息,更新播放器状态和界面

LOGI("MyOnStreamEvent");

return 0;

}

// 自定义音频中断事件函数

int32_t MyOnInterruptEvent(OH_AudioRenderer *renderer, void *userData, OH_AudioInterrupt_ForceType type,

OH_AudioInterrupt_Hint hint) {

// 根据type和hint表示的音频中断信息,更新播放器状态和界面

LOGI("MyOnInterruptEvent ForceType: %{public}d, Hint: %{public}d", type, hint);

switch (hint) {

case AUDIOSTREAM_INTERRUPT_HINT_NONE:

break;

case AUDIOSTREAM_INTERRUPT_HINT_RESUME:

OH_AudioRenderer_Start(audioRenderer);

break;

case AUDIOSTREAM_INTERRUPT_HINT_PAUSE:

OH_AudioRenderer_Pause(audioRenderer);

break;

case AUDIOSTREAM_INTERRUPT_HINT_STOP:

OH_AudioRenderer_Stop(audioRenderer);

break;

case AUDIOSTREAM_INTERRUPT_HINT_DUCK:

break;

case AUDIOSTREAM_INTERRUPT_HINT_UNDUCK:

break;

default:

LOGI("无法识别中断事件");

}

return 0;

}

// 自定义异常回调函数

int32_t MyOnError(OH_AudioRenderer *renderer, void *userData, OH_AudioStream_Result error) {

// 根据error表示的音频异常信息,做出相应的处理

LOGI("MyOnError");

return 0;

}

鸿蒙全栈开发全新学习指南

有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?而且学习时频繁踩坑,最终浪费大量时间。所以要有一份实用的鸿蒙(HarmonyOS NEXT)学习路线与学习文档用来跟着学习是非常有必要的。

针对一些列因素,整理了一套纯血版鸿蒙(HarmonyOS Next)全栈开发技术的学习路线,包含了鸿蒙开发必掌握的核心知识要点,内容有(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、WebGL、元服务、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、OpenHarmony驱动开发、系统定制移植等等)鸿蒙(HarmonyOS NEXT)技术知识点。

本路线共分为四个阶段

第一阶段:鸿蒙初中级开发必备技能

在这里插入图片描述

第二阶段:鸿蒙南北双向高工技能基础:gitee.com/MNxiaona/733GH

在这里插入图片描述

第三阶段:应用开发中高级就业技术

第四阶段:全网首发-工业级南向设备开发就业技术:gitee.com/MNxiaona/733GH

在这里插入图片描述

《鸿蒙 (Harmony OS)开发学习手册》(共计892页)

如何快速入门?

1.基本概念
2.构建第一个ArkTS应用
3.……

开发基础知识:gitee.com/MNxiaona/733GH

1.应用基础知识
2.配置文件
3.应用数据管理
4.应用安全管理
5.应用隐私保护
6.三方应用调用管控机制
7.资源分类与访问
8.学习ArkTS语言
9.……

在这里插入图片描述

基于ArkTS 开发

1.Ability开发
2.UI开发
3.公共事件与通知
4.窗口管理
5.媒体
6.安全
7.网络与链接
8.电话服务
9.数据管理
10.后台任务(Background Task)管理
11.设备管理
12.设备使用信息统计
13.DFX
14.国际化开发
15.折叠屏系列
16.……

在这里插入图片描述

鸿蒙开发面试真题(含参考答案):gitee.com/MNxiaona/733GH

在这里插入图片描述

鸿蒙入门教学视频:

美团APP实战开发教学:gitee.com/MNxiaona/733GH

写在最后

  • 如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙:
  • 点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
  • 关注小编,同时可以期待后续文章ing🚀,不定期分享原创知识。
  • 想要获取更多完整鸿蒙最新学习资源,请移步前往小编:gitee.com/MNxiaona/733GH

  • 24
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值