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```