1# 从OpenSL ES切换到OHAudio(C/C++) 2<!--Kit: Audio Kit--> 3<!--Subsystem: Multimedia--> 4<!--Owner: @songshenke--> 5<!--Designer: @caixuejiang; @hao-liangfei; @zhanganxiang--> 6<!--Tester: @Filger--> 7<!--Adviser: @zengyawen--> 8 9由于OpenSL ES无法满足音频系统的能力拓展,建议开发者使用OHAudio替代OpenSL ES开发音频业务。本文将介绍如何从使用OpenSL ES接口开发音频业务,切换为使用OHAudio接口。 10 11## 支持的功能差异 12 13两者支持的功能范围略有差异,OHAudio增加支持低时延播放/录制、监听业务变化等功能。 14 15具体差异如下表所示。 16 17| | OpenSL ES| OHAudio | 18| --- | --- | --- | 19| 音频流式播放 | √ | √ | 20| 音频流式录制 | √ | √ | 21| 音频低时延播放 | × | √ | 22| 音频低时延录制 | × | √ | 23| 播放对象状态切换 | √ | √ | 24| 录制对象状态切换 | √ | √ | 25| 获取音频流对象状态 | √ | √ | 26| 清理播放缓存 | × | √ | 27| 监听音频打断事件 | × | √ | 28| 监听音频流事件 | × | √ | 29| 监听流异常事件 | × | √ | 30| 监听播放设备变化事件 | × | √ | 31 32## 开发模式差异 33 34此小节将结合开发步骤,对比介绍OHAudio和OpenSL ES在开发模式上的差异。 35 36音频播放和录制的实现类似,此处以音频播放为例说明。 37 38### 构造实例 39 40OpenSL ES: 41 42通过全局接口获取到Engine对象,基于Engine结合不同输入输出配置参数,构造出不同音频播放对象。 43 44```cpp 45// 生成Engine Inteface对象。 46SLEngineItf engine; 47// ... 48 49// 按需配置音频输入slSource。 50SLDataSource slSource; 51// ... 52 53// 按需配置音频输出slSink。 54SLDataSink slSink; 55// ... 56 57// 生成音频播放对象。 58SLObjectItf playerObject; 59(*engine)->CreateAudioPlayer(engine, 60 &playerObject, 61 &slSource, 62 &slSink, 63 0, 64 nullptr, 65 nullptr); 66 67(*playerObject)->Realize(playerObject, 68 SL_BOOLEAN_FALSE); 69``` 70 71OHAudio: 72 73采用建造器模式,通过建造器,配合自定义参数设置,生成音频播放对象。 74 75```cpp 76// 创建建造器。 77OH_AudioStreamBuilder *builder; 78OH_AudioStreamBuilder_Create(&builder, AUDIOSTREAM_TYPE_RENDERER); 79 80// 设置自定义参数,否则会使用默认参数。 81OH_AudioStreamBuilder_SetSamplingRate(builder, 48000); 82OH_AudioStreamBuilder_SetChannelCount(builder, 2); 83OH_AudioStreamBuilder_SetSampleFormat(builder, AUDIOSTREAM_SAMPLE_S16LE); 84OH_AudioStreamBuilder_SetEncodingType(builder, AUDIOSTREAM_ENCODING_TYPE_RAW); 85// 关键参数,仅OHAudio支持,根据音频用途设置,系统会根据此参数实现音频策略自适应。 86OH_AudioStreamBuilder_SetRendererInfo(builder, AUDIOSTREAM_USAGE_MUSIC); 87// ... 88 89// 生成音频播放对象。 90OH_AudioRenderer *audioRenderer; 91OH_AudioStreamBuilder_GenerateRenderer(builder, &audioRenderer); 92``` 93 94### 状态切换 95 96OpenSL ES: 97 98基于Object获取状态切换Interface,使用Interface接口切换状态,只有SL_PLAYSTATE_STOPPED、SL_PLAYSTATE_PAUSED、SL_PLAYSTATE_PLAYING三种状态。 99 100```cpp 101// 基于播放对象,获取播放操作Interface。 102SLPlayItf playItf = nullptr; 103(*playerObject)->GetInterface(playerObject, SL_IID_PLAY, &playItf); 104// 状态切换。 105(*playItf)->SetPlayState(playItf, SL_PLAYSTATE_PLAYING); 106(*playItf)->SetPlayState(playItf, SL_PLAYSTATE_PAUSED); 107(*playItf)->SetPlayState(playItf, SL_PLAYSTATE_STOPPED); 108``` 109 110OHAudio: 111 112有独立的状态切换接口,基于状态机进行状态切换,共6个OH_AudioStream_State状态,主要在AUDIOSTREAM_STATE_PREPARED、AUDIOSTREAM_STATE_RUNNING、AUDIOSTREAM_STATE_STOPPED、AUDIOSTREAM_STATE_PAUSED、AUDIOSTREAM_STATE_RELEASED状态间切换。 113 114```cpp 115// 状态切换。 116OH_AudioRenderer_Start(audioRenderer); 117OH_AudioRenderer_Pause(audioRenderer); 118OH_AudioRenderer_Stop(audioRenderer); 119``` 120 121### 数据处理 122 123OpenSL ES: 124 125基于扩展的OHBufferQueue接口,通过注册自定义的Callback函数,根据数据请求时机,将待播放数据填入系统内提供的缓冲区中。 126 127```cpp 128static void MyBufferQueueCallback(SLOHBufferQueueItf bufferQueueItf, void *pContext, SLuint32 size) 129{ 130 SLuint8 *buffer = nullptr; 131 SLuint32 bufferSize; 132 // 获取系统内提供的buffer。 133 (*bufferQueueItf)->GetBuffer(bufferQueueItf, &buffer, &bufferSize); 134 // 将待播放音频数据写入buffer。 135 // ... 136 // 将buffer输入系统。 137 (*bufferQueueItf)->Enqueue(bufferQueueItf, buffer, bufferSize); 138} 139 140// 获取OHBufferQueue接口。 141SLOHBufferQueueItf bufferQueueItf; 142(*playerObject)->GetInterface(playerObject, SL_IID_OH_BUFFERQUEUE, &bufferQueueItf); 143// 可传入自定义的上下文信息,会在Callback内收到。 144void *pContext; 145(*bufferQueueItf)->RegisterCallback(bufferQueueItf, MyBufferQueueCallback, pContext); 146``` 147 148OHAudio: 149 150统一使用回调模式,在构造时注册数据输入回调,实现自定义的数据填充函数,在播放过程中会跟随系统调度和时延配置情况,自动在合适时机触发数据请求回调。 151 152```cpp 153static int32_t MyOnWriteData( 154 OH_AudioRenderer *renderer, 155 void *userData, 156 void *buffer, 157 int32_t bufferLen) 158{ 159 // 将待播放数据按照请求的bufferLen长度,填入buffer。 160 // 函数返回后,系统会自动从buffer取出数据输出。 161} 162 163OH_AudioRenderer_Callbacks callbacks; 164callbacks.OH_AudioRenderer_OnWriteData = MyOnWriteData; 165 166// 设置输出音频流的回调,在生成音频播放对象时自动注册。 167void *userData = nullptr; 168OH_AudioStreamBuilder_SetRendererCallback(builder, callbacks, userData); 169``` 170 171### 资源释放 172 173OpenSL ES: 174 175使用SLObjectItf接口实现对象资源释放。 176 177```cpp 178// 释放播放对象资源。 179(*playerObject)->Destroy(playerObject); 180``` 181 182OHAudio: 183 184使用对应模块的释放接口实现对象资源释放。 185 186```cpp 187// 释放建造器资源。 188OH_AudioStreamBuilder_Destroy(builder); 189 190// 释放播放对象资源。 191OH_AudioRenderer_Release(audioRenderer); 192```