Harmony Native开发-我的OpenSL ES录音机
2022/1/6 23:05:00
本文主要是介绍Harmony Native开发-我的OpenSL ES录音机,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
零、写在前面
最早我是在Android上开发的OpenSL ES。但最近看了下鸿蒙的文档,发现它的底层库也支持OpenSL ES,这我的兴致就来了。简单了解了一下鸿蒙的Native开发,就着手开发起来。移植过程中发现其实对Android程序员还是相当友好的,从Android上移植到鸿蒙并没有太大的改动。这篇文章主要讲的是通以OpenSL ES开发为切入点,鸿蒙怎么进行基本的Native开发。Demo是实现一个录音机,完成录音和播放录音功能。
一、创建我的鸿蒙Native APP
鸿蒙的开发工具和AndroidStudio及其类似,毕竟来自同一家公司的开源,所以使用上也大致差不多,入门成本不高。创建一个native app和AndroidStuio的也类似,在创建项目模板的界面选择Native C++,完成一系列的的项目类型、名称、路径等等配置后就创建了我们的第一个Native C++
如果你是第一次创建Native项目可能会要你下载开发工具包,那么请你去设置里检查你的这三个选项是否都勾选上了并安装了,主要是第三个选项Native
项目结构和Android类似,在main路径下比普通的项目多出一个cpp,里面有一个CMakeList和一个返回helloworld的CPP文件,这里就涉及到JNI的内容,如果对JNI不熟悉的可以先去看看我的上一篇博文JNI常用开发技巧,在这我就不再讲CMakeList怎么编写和JNI的流程规范了。
二、开始OpenSL开发
2.1、引入底层库
我在这里主要引入一个OpenSL ES库和一个鸿蒙的日志库,日志库默认已经引入了,我们新建一个C++类OpenSLESRecord
,功能全在里面实现,通过它默认创建的那个hello.CPP进行调用.
CMakeList申明OpenSLESRecord库并将它OpenSL ES链接起来,不然找不到OpenSL ES库。
add_library( # Sets the name of the library. OpenSLESRecord # Sets the library as a shared library. SHARED # Provides a relative path to your source file(s). OpenSLESRecord.cpp) target_link_libraries( # Specifies the target library. OpenSLESRecord # Links the target library to the log library # included in the NDK. OpenSLES libhilog_ndk.z.so)
2.2、音频录制背景
讲几个音频的简单概念
- PCM
中文叫脉冲编码调制,说人话就是音频模拟量转成数字量,把麦克风采集到的电信号转化为byte数据。我们的录音文件就是xxx.pcm。但是有一点一般的播放器是无法播放PCM的,因为PCM是纯音频数据,没有音频格式信息,无法进行解码,所以只能我们自己的写一个,或者用Adobe Audition
播放,但是也要指定音频格式才能播放。 - 采样格式
采样格式常见的有8bit,16bit,24bit,32bit。就是数字可以表达的音频信息的范围,比如我们的音频模拟量最高电压为5V,采样格式为8位,那我们最多把模拟信号分成255等分,那每等分中间的电压就是误差。所以采样格式位数越大,误差越小精度越高。 - 声道
常见的就是我们平常理解的单声道和双声道还有什么3.1、5.1 - 声道布局
就是声道输出的方向,常见的有左耳,右耳,左右耳 - 采样率
采样率是设备每秒采集音频信号的速度,常见采样率有8000,16000,44100,96000等,如采样率8000就是每秒采样音频信号8000次 - 比特率
是指单位时间内传送的比特(bit)数,单位是bit/s,计算公式是采样格式* 声道数 * 采样率
那么从上面可以得出,一个PCM录音文件的大小就是
(采样格式* 声道数 * 采样率 * 时间 / 8)bytes
录音和播放过程中我们都需要设置这些东西,下面是我录音的PCM格式,SLDataFormat_PCM 结构体就是用于保存这些信息。SLDataFormat_PCM slDataFormatPcm = { SL_DATAFORMAT_PCM, //输出PCM格式的数据 (SLuint32) 2, //输出的声道数量 SL_SAMPLINGRATE_44_1, //输出的采样频率,这里是44100Hz SL_PCMSAMPLEFORMAT_FIXED_16, //输出的采样格式,这里是16bit SL_PCMSAMPLEFORMAT_FIXED_16, //一般来说,跟随上一个参数 SL_SPEAKER_FRONT_LEFT |SL_SPEAKER_FRONT_RIGHT, //双声道配置,如果单声道可以用 SL_SPEAKER_FRONT_CENTER SL_BYTEORDER_LITTLEENDIAN //PCM数据的大小端排列 };
2.2、录音开发流程
其实把上面的流程再放大了看,其实可以把创建对象->实例化对象->获取接口看做一个流程。下面是前三步的代码
SLresult sLresult= slCreateEngine(&engineObject, 0, NULL, 0, NULL, 0); LOGE("slCreateEngine..."); if (SL_RESULT_SUCCESS != sLresult){ return; } sLresult=(*engineObject)->Realize(engineObject, 0); LOGE("slCreateEngine Realize..."); if (SL_RESULT_SUCCESS != sLresult){ return; } sLresult=(*engineObject)->GetInterface(engineObject,SL_IID_ENGINE,&audioEngine); LOGE("slCreateEngine GetInterface..."); if (SL_RESULT_SUCCESS != sLresult){ return; }
如果说我们Android开发从C语言角度难以理解,那就从Java角度看一看,(当然只是为了让Java开发的有个大致的概念,实际并非完全如此此)。我们把C的结构体
和Java的对象
的概念做一个替换。其实这就像是一个建造者模式代码,创建对象像是把需要构建的参数传进去,实例化对象像是调用build,我们到这一步才算是拿到了对象。而这个对象的属性里又有其它子模块对象,分别有各自的功能,我们这里是根据ID拿到这个对象的。我们前三步的目的就是为了拿到引擎接口,因为它有实际的方法。
看看它的方法结构体构成,以本文用到的三个方法为例,来自OpenSL ES的头文件:
...... SLresult (*CreateAudioPlayer) ( SLEngineItf self, SLObjectItf * pPlayer, SLDataSource *pAudioSrc, SLDataSink *pAudioSnk, SLuint32 numInterfaces, const SLInterfaceID * pInterfaceIds, const SLboolean * pInterfaceRequired ); SLresult (*CreateAudioRecorder) ( SLEngineItf self, SLObjectItf * pRecorder, SLDataSource *pAudioSrc, SLDataSink *pAudioSnk, SLuint32 numInterfaces, const SLInterfaceID * pInterfaceIds, const SLboolean * pInterfaceRequired ); SLresult (*CreateOutputMix) ( SLEngineItf self, SLObjectItf * pMix, SLuint32 numInterfaces, const SLInterfaceID * pInterfaceIds, const SLboolean * pInterfaceRequired ); ......
理解了前三步,那接下来的三步也是一样的了,最终目的是为了拿到我们的录制接口,调用它的方法,把缓存队列设置好,再给缓存队列设置一个回调,每次队列满了就把数据回调回来,数据处理就在这个回调方法里,我们这里把它写入文件。最好调用录制方法就万事大吉了。
2.3、播放开发流程
播放流程相对录制流程就多了一个创建混响器,其实也是因为我们的播放器需要这个东西。创建混响器的流程也一样理解就是啦。
2.4 小总结
这里讲的只是一个大致流程,这些大的流程中会需要传入一些参数,这些参数怎么设置基本上也就是一个固定的参数,比如输入设备Id、输出设备Id、PCM格式等等。所以这里不做详解,如果有兴趣可以去github上看我的demo,demo路径会放在文末。
三、上层应用开发
3.1、权限申请
- 录音权限(麦克风权限)
- 读写文件权限
其中录音和写文件权限需要动态申请
在config.json的里面申明需要的权限
"reqPermissions": [ { "name": "ohos.permission.MICROPHONE" }, { "name": "ohos.permission.WRITE_USER_STORAGE" }, { "name": "ohos.permission.READ_USER_STORAGE" } ]
Java层动态请求权限
private void requestPermission() { String[] permissions = { SystemPermission.WRITE_USER_STORAGE, SystemPermission.MICROPHONE }; requestPermissionsFromUser(Arrays.stream(permissions) .filter(permission -> verifySelfPermission(permission) != IBundleManager.PERMISSION_GRANTED).toArray(String[]::new), 0); }
3.2、界面编写
三个按钮分别 录音 暂停 和播放
<DirectionalLayout xmlns:ohos="http://schemas.huawei.com/res/ohos" ohos:height="match_parent" ohos:width="match_parent" ohos:orientation="vertical"> <Button ohos:background_element="#0099cc" ohos:text_color="#ffffff" ohos:id="$+id:start_record_button" ohos:height="match_content" ohos:width="match_parent" ohos:start_padding="14vp" ohos:end_padding="0vp" ohos:padding="10vp" ohos:text="开始录音" ohos:text_size="16vp" ohos:top_margin="30vp"/> <Button ohos:background_element="#0099cc" ohos:text_color="#ffffff" ohos:id="$+id:stop_record_button" ohos:height="match_content" ohos:width="match_parent" ohos:start_padding="14vp" ohos:end_padding="0vp" ohos:padding="10vp" ohos:text="停止录音" ohos:text_size="16vp" ohos:top_margin="10vp"/> <Button ohos:background_element="#0099cc" ohos:text_color="#ffffff" ohos:id="$+id:play_record_button" ohos:height="match_content" ohos:width="match_parent" ohos:start_padding="14vp" ohos:end_padding="0vp" ohos:padding="10vp" ohos:text="播放录音" ohos:text_size="16vp" ohos:top_margin="10vp"/> </DirectionalLayout>
Java层的就不继续凑字数了,看不懂的可以先看看鸿蒙的官方文档。
四、总结
如果你会Android端的OpenSL ES开发,那么鸿蒙端的其实并不难。所以你也可以先从Android或iOS入手OpenSL ES,因为他们的相关文档更多。Native端主要稍微不同的点就是Android端有它自己的BufferQueue,而鸿蒙端是没有的,因为鸿蒙端没有SLES/OpenSLES_Android.h
这个头文件,但是问题不大,用自带的BufferQueue-SLBufferQueueItf
就行。而上层的话虽说和Android端有不同,但是流程上都是相同的,都有对应的实现方法。主要是在真机上运行那个签名麻烦一点,还要去开发者平台注册应用那些。鸿蒙的IDE正式版2.0的Native开发还有bug,莫名奇妙的爆红和警告,跑起来没任何问题,我换了beta版3.0后就没这个问题的。下面是我写的录音Demo,有兴趣的可以clone下来玩一玩,在它的基础上再发展一下,比如把PCM文件转为wav格式的文件,这样我们的手机就能直接播放了。如果觉得有帮到你也可以点个小星星。欢迎大家讨论和批评指正。
鸿蒙环境下的OpenSL ES开发 GitHub地址
这篇关于Harmony Native开发-我的OpenSL ES录音机的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23Springboot应用的多环境打包入门
- 2024-11-23Springboot应用的生产发布入门教程
- 2024-11-23Python编程入门指南
- 2024-11-23Java创业入门:从零开始的编程之旅
- 2024-11-23Java创业入门:新手必读的Java编程与创业指南
- 2024-11-23Java对接阿里云智能语音服务入门详解
- 2024-11-23Java对接阿里云智能语音服务入门教程
- 2024-11-23JAVA对接阿里云智能语音服务入门教程
- 2024-11-23Java副业入门:初学者的简单教程
- 2024-11-23JAVA副业入门:初学者的实战指南