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