• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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```