• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1page.title=OpenSL ES Programming Notes
2@jd:body
3
4<div id="qv-wrapper">
5    <div id="qv">
6      <h2>On this page</h2>
7
8      <ol>
9        <li><a href="#init">Objects and Interface Initialization</a></li>
10        <li><a href="#prefetch">Audio Player Prefetch</a></li>
11        <li><a href="#destroy">Destroy</a></li>
12        <li><a href="#panning">Stereo Panning</a></li>
13        <li><a href="#callbacks">Callbacks and Threads</a></li>
14        <li><a href="#perform">Performance</a></li>
15        <li><a href="#sandp">Security and Permissions</a></li>
16      </ol>
17    </div>
18</div>
19
20<p>
21The notes in this section supplement the
22<a class="external-link" href="https://www.khronos.org/registry/sles/">OpenSL ES 1.0.1
23specification</a>.
24</p>
25
26<h2 id="init">Objects and Interface Initialization</h2>
27
28<p>
29Two aspects of the OpenSL ES programming model that may be unfamiliar to new developers are the
30distinction between objects and interfaces, and the initialization sequence.
31</p>
32
33<p>
34Briefly, an OpenSL ES object is similar to the object concept in
35 programming languages such as Java
36and C++, except an OpenSL ES object is only visible via its associated interfaces.
37 This includes
38the initial interface for all objects, called {@code SLObjectItf}.
39 There is no handle for an object
40itself, only a handle to the {@code SLObjectItf} interface of the object.
41</p>
42
43<p>
44An OpenSL ES object is first <em>created</em>, which returns an {@code SLObjectItf}, then
45<em>realized</em>. This is similar to the common programming pattern of first constructing an
46object (which should never fail other than for lack of memory or invalid parameters), and then
47completing initialization (which may fail due to lack of resources). The realize step gives the
48implementation a logical place to allocate additional resources if needed.
49</p>
50
51<p>
52As part of the API to create an object, an application specifies an array of desired interfaces
53that it plans to acquire later. Note that this array does not automatically
54 acquire the interfaces;
55it merely indicates a future intention to acquire them. Interfaces are distinguished as
56<em>implicit</em> or <em>explicit</em>. An explicit interface must be listed in the array if it
57will be acquired later. An implicit interface need not be listed in the
58 object create array, but
59there is no harm in listing it there. OpenSL ES has one more kind of interface called
60<em>dynamic</em>, which does not need to be specified in the object
61 create array and can be added
62later after the object is created. The Android implementation provides
63 a convenience feature to
64avoid this complexity, which is described in
65 <a href="{@docRoot}ndk/guides/audio/opensl-for-android.html#dynamic-interfaces">Dynamic interfaces at object creation</a>.
66</p>
67
68<p>
69After the object is created and realized, the application should acquire interfaces for each
70feature it needs, using {@code GetInterface} on the initial {@code SLObjectItf}.
71</p>
72
73<p>
74Finally, the object is available for use via its interfaces, though note that
75 some objects require
76further setup. In particular, an audio player with URI data source needs a bit
77 more preparation in
78order to detect connection errors. See the
79 <a href="#prefetch">Audio player prefetch</a> section for details.
80</p>
81
82<p>
83After your application is done with the object, you should explicitly destroy it; see the
84<a href="#destroy">Destroy</a> section below.
85</p>
86
87<h2 id="prefetch">Audio Player Prefetch</h2>
88
89<p>
90For an audio player with URI data source, {@code Object::Realize} allocates
91 resources but does not
92connect to the data source (<em>prepare</em>) or begin pre-fetching data. These occur once the
93player state is set to either {@code SL_PLAYSTATE_PAUSED} or {@code SL_PLAYSTATE_PLAYING}.
94</p>
95
96<p>
97Some information may still be unknown until relatively late in this sequence. In
98particular, initially {@code Player::GetDuration} returns {@code SL_TIME_UNKNOWN} and
99{@code MuteSolo::GetChannelCount} either returns successfully with channel count zero or the
100error result {@code SL_RESULT_PRECONDITIONS_VIOLATED}. These APIs return the proper values
101once they are known.
102</p>
103
104<p>
105Other properties that are initially unknown include the sample rate and
106 actual media content type
107based on examining the content's header (as opposed to the
108 application-specified MIME type and
109container type). These are also determined later during
110 prepare/prefetch, but there are no APIs to
111retrieve them.
112</p>
113
114<p>
115The prefetch status interface is useful for detecting when all information
116 is available, or your
117application can poll periodically. Note that some information, such as the
118 duration of a streaming
119MP3, may <em>never</em> be known.
120</p>
121
122<p>
123The prefetch status interface is also useful for detecting errors. Register a callback
124 and enable
125at least the {@code SL_PREFETCHEVENT_FILLLEVELCHANGE} and {@code SL_PREFETCHEVENT_STATUSCHANGE}
126events. If both of these events are delivered simultaneously, and
127{@code PrefetchStatus::GetFillLevel} reports a zero level, and
128{@code PrefetchStatus::GetPrefetchStatus} reports {@code SL_PREFETCHSTATUS_UNDERFLOW},
129 then this
130indicates a non-recoverable error in the data source. This includes the inability to
131 connect to the
132data source because the local filename does not exist or the network URI is invalid.
133</p>
134
135<p>
136The next version of OpenSL ES is expected to add more explicit support for
137 handling errors in the
138data source. However, for future binary compatibility, we intend to continue
139 to support the current
140method for reporting a non-recoverable error.
141</p>
142
143<p>
144In summary, a recommended code sequence is:
145</p>
146
147<ol>
148  <li>{@code Engine::CreateAudioPlayer}</li>
149  <li>{@code Object:Realize}</li>
150  <li>{@code Object::GetInterface} for {@code SL_IID_PREFETCHSTATUS}</li>
151  <li>{@code PrefetchStatus::SetCallbackEventsMask}</li>
152  <li>{@code PrefetchStatus::SetFillUpdatePeriod}</li>
153  <li>{@code PrefetchStatus::RegisterCallback}</li>
154  <li>{@code Object::GetInterface} for {@code SL_IID_PLAY}</li>
155  <li>{@code Play::SetPlayState} to {@code SL_PLAYSTATE_PAUSED}, or
156  {@code SL_PLAYSTATE_PLAYING}</li>
157</ol>
158
159<p class="note"><strong>Note: </strong>
160Preparation and prefetching occur here; during this time your callback is called with
161periodic status updates.
162</p>
163
164<h2 id="destroy">Destroy</h2>
165
166<p>
167Be sure to destroy all objects when exiting from your application.
168 Objects should be destroyed in
169reverse order of their creation, as it is not safe to destroy an object that has any dependent
170objects. For example, destroy in this order: audio players and recorders, output mix, and then
171finally the engine.
172</p>
173
174<p>
175OpenSL ES does not support automatic garbage collection or
176<a class="external-link" href="http://en.wikipedia.org/wiki/Reference_counting">reference
177counting</a> of interfaces. After you call {@code Object::Destroy}, all extant
178 interfaces that are
179derived from the associated object become undefined.
180</p>
181
182<p>
183The Android OpenSL ES implementation does not detect the incorrect use of such interfaces.
184Continuing to use such interfaces after the object is destroyed can cause your application to
185crash or behave in unpredictable ways.
186</p>
187
188<p>
189We recommend that you explicitly set both the primary object interface and all associated
190interfaces to NULL as part of your object destruction sequence, which prevents the accidental
191misuse of a stale interface handle.
192</p>
193
194<h2 id="panning">Stereo Panning</h2>
195
196<p>
197When {@code Volume::EnableStereoPosition} is used to enable stereo panning of a mono source,
198 there is a 3-dB reduction in total
199<a class="external-link" href="http://en.wikipedia.org/wiki/Sound_power_level">sound power
200level</a>. This is needed to permit the total sound power level to remain constant as
201 the source is
202panned from one channel to the other. Therefore, only enable stereo positioning if you need
203it. See the Wikipedia article on
204<a class="external-link" href="http://en.wikipedia.org/wiki/Panning_(audio)">audio panning</a>
205 for more information.
206</p>
207
208<h2 id="callbacks">Callbacks and Threads</h2>
209
210<p>
211Callback handlers are generally called synchronously with respect to the event. That is, at the
212moment and location that the event is detected by the implementation. This point is
213asynchronous with respect to the application, so you should use a non-blocking synchronization
214mechanism to control access to any variables shared between the application and the callback
215handler. In the example code, such as for buffer queues, we have either omitted this
216synchronization or used blocking synchronization in the interest of simplicity. However, proper
217non-blocking synchronization is critical for any production code.
218</p>
219
220<p>
221Callback handlers are called from internal non-application threads that are not attached to the
222Android runtime, so they are ineligible to use JNI. Because these internal threads are
223critical to
224the integrity of the OpenSL ES implementation, a callback handler should also not block
225 or perform
226excessive work.
227</p>
228
229<p>
230If your callback handler needs to use JNI or execute work that is not proportional to the
231callback, the handler should instead post an event for another thread to process. Examples of
232acceptable callback workload include rendering and enqueuing the next output buffer
233(for an AudioPlayer), processing the just-filled input buffer and enqueueing the next
234 empty buffer
235(for an AudioRecorder), or simple APIs such as most of the <em>Get</em> family. See the
236<a href="#perform">Performance</a> section below regarding the workload.
237</p>
238
239<p>
240Note that the converse is safe: an Android application thread that has entered JNI
241 is allowed to
242directly call OpenSL ES APIs, including those that block. However, blocking calls are not
243recommended from the main thread, as they may result in
244 <em>Application Not Responding</em> (ANR).
245</p>
246
247<p>
248The determination regarding the thread that calls a callback handler is largely left up to the
249implementation. The reason for this flexibility is to permit future optimizations,
250 especially on
251multi-core devices.
252</p>
253
254<p>
255The thread on which the callback handler runs is not guaranteed to have the same
256 identity across
257different calls. Therefore, do not rely on the {@code pthread_t returned by pthread_self()}
258 or the
259{@code pid_t returned by gettid()} to be consistent across calls. For the same reason,
260 do not use
261the thread local storage (TLS) APIs such as {@code pthread_setspecific()} and
262{@code pthread_getspecific()} from a callback.
263</p>
264
265<p>
266The implementation guarantees that concurrent callbacks of the same kind, for the
267 same object, does
268not occur. However, concurrent callbacks of different kinds for the same object are possible on
269different threads.
270</p>
271
272<h2 id="perform">Performance</h2>
273
274<p>
275As OpenSL ES is a native C API, non-runtime application threads that call OpenSL ES have no
276runtime-related overhead such as garbage collection pauses. With one exception described below,
277there is no additional performance benefit to the use of OpenSL ES other than this.
278 In particular,
279the use of OpenSL ES does not guarantee enhancements such as lower audio latency and higher
280scheduling priority over that which the platform generally provides. On the other hand, as the
281Android platform and specific device implementations continue to evolve, an OpenSL ES application
282can expect to benefit from any future system performance improvements.
283</p>
284
285<p>
286One such evolution is support for reduced
287<a href="{@docRoot}ndk/guides/audio/output-latency.html">audio output latency</a>.
288The underpinnings for reduced
289output latency were first included in Android 4.1 (API level 16), and then
290continued progress occurred in Android 4.2 (API level 17). These improvements are available via
291OpenSL ES for device implementations that
292 claim feature {@code android.hardware.audio.low_latency}.
293If the device doesn't claim this feature but supports Android 2.3 (API level 9)
294or later, then you can still use the OpenSL ES APIs but the output latency may be higher.
295 The lower
296output latency path is used only if the application requests a buffer size and sample rate
297 that are
298compatible with the device's native output configuration. These parameters are
299 device-specific and
300should be obtained as described below.
301</p>
302
303<p>
304Beginning with Android 4.2 (API level 17), an application can query for the
305platform native or optimal output sample rate and buffer size for the device's primary output
306stream. When combined with the feature test just mentioned, an app can now configure itself
307appropriately for lower latency output on devices that claim support.
308</p>
309
310<p>
311For Android 4.2 (API level 17) and earlier, a buffer count of two or more is
312required for lower latency. Beginning with Android 4.3 (API level 18), a buffer
313count of one is sufficient for lower latency.
314</p>
315
316<p>
317All OpenSL ES interfaces for output effects preclude the lower latency path.
318</p>
319
320<p>
321The recommended sequence is as follows:
322</p>
323
324<ol>
325  <li>Check for API level 9 or higher to confirm the use of OpenSL ES.</li>
326  <li>Check for the {@code android.hardware.audio.low_latency} feature using code such as this:
327    <pre>import android.content.pm.PackageManager;
328...
329PackageManager pm = getContext().getPackageManager();
330boolean claimsFeature = pm.hasSystemFeature(PackageManager.FEATURE_AUDIO_LOW_LATENCY);
331    </pre></li>
332  <li>Check for API level 17 or higher to confirm the use of
333  {@code android.media.AudioManager.getProperty()}.</li>
334  <li>Get the native or optimal output sample rate and buffer size for this device's
335  primary output
336  stream using code such as this:
337    <pre>import android.media.AudioManager;
338...
339AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
340String sampleRate = am.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE));
341String framesPerBuffer = am.getProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER));
342    </pre>
343  Note that {@code sampleRate} and {@code framesPerBuffer} are <em>strings</em>. First check for
344  null and then convert to int using {@code Integer.parseInt()}.</li>
345    <li>Now use OpenSL ES to create an AudioPlayer with PCM buffer queue data locator.</li>
346</ol>
347
348<p class="note"><strong>Note: </strong>
349You can use the
350<a class="external-link"
351 href="https://play.google.com/store/apps/details?id=com.levien.audiobuffersize">
352 Audio Buffer Size</a>
353test app to determine the native buffer size and sample rate for OpenSL ES audio
354applications on your audio device. You can also visit GitHub to view <a class="external-link"
355href="https://github.com/gkasten/high-performance-audio/tree/master/audio-buffer-size">
356audio-buffer-size</a> samples.
357
358<p>
359The number of lower latency audio players is limited. If your application requires more
360than a few
361audio sources, consider mixing your audio at the application level. Be sure to destroy your audio
362players when your activity is paused, as they are a global resource shared with other apps.
363</p>
364
365<p>
366To avoid audible glitches, the buffer queue callback handler must execute within a small and
367predictable time window. This typically implies no unbounded blocking on mutexes, conditions,
368or I/O operations. Instead consider <em>try locks</em>, locks and waits with timeouts, and
369<a class="external-link"
370 href="https://source.android.com/devices/audio/avoiding_pi.html#nonBlockingAlgorithms">
371 non-blocking algorithms</a>.
372</p>
373
374<p>
375The computation required to render the next buffer (for AudioPlayer) or consume the previous
376buffer (for AudioRecord) should take approximately the same amount of time for each callback.
377Avoid algorithms that execute in a non-deterministic amount of time or are <em>bursty</em> in
378their computations. A callback computation is bursty if the CPU time spent in any given callback
379is significantly larger than the average. In summary, the ideal is for the CPU execution time of
380the handler to have variance near zero, and for the handler to not block for unbounded times.
381</p>
382
383<p>
384Lower latency audio is possible for these outputs only:
385</p>
386
387<ul>
388  <li>On-device speakers.</li>
389  <li>Wired headphones.</li>
390  <li>Wired headsets.</li>
391  <li>Line out.</li>
392  <li><a class="external-link" href="https://source.android.com/devices/audio/usb.html">
393  USB digital
394  audio</a>.</li>
395</ul>
396
397<p>
398On some devices, speaker latency is higher than other paths due to digital signal processing for
399speaker correction and protection.
400</p>
401
402<p>
403As of API level 21,
404<a href="{@docRoot}ndk/guides/audio/input-latency.html">lower latency audio input</a>
405 is supported
406on select devices. To take advantage of
407this feature, first confirm that lower latency output is available as described above. The
408capability for lower latency output is a prerequisite for the lower latency input feature. Then,
409create an AudioRecorder with the same sample rate and buffer size as would be used for output.
410OpenSL ES interfaces for input effects preclude the lower latency path. The record preset
411{@code SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION} must be used for lower latency; this preset
412disables device-specific digital signal processing that may add latency to the input path. For
413more information on record presets, see the <a href="#configuration-interface">Android
414configuration interface</a> section above.
415</p>
416
417<p>
418For simultaneous input and output, separate buffer queue completion handlers are used for each
419side. There is no guarantee of the relative order of these callbacks, or the synchronization of
420the audio clocks, even when both sides use the same sample rate. Your application
421 should buffer the
422data with proper buffer synchronization.
423</p>
424
425<p>
426One consequence of potentially independent audio clocks is the need for asynchronous sample rate
427conversion. A simple (though not ideal for audio quality) technique for asynchronous sample rate
428conversion is to duplicate or drop samples as needed near a zero-crossing point.
429 More sophisticated
430conversions are possible.
431</p>
432
433<h2 id="sandp">Security and Permissions</h2>
434
435<p>
436As far as who can do what, security in Android is done at the process level. Java programming
437language code cannot do anything more than native code, nor can native code do anything more than
438Java programming language code. The only differences between them are the available APIs.
439</p>
440
441<p>
442Applications using OpenSL ES must request the permissions that they would need for similar
443non-native APIs. For example, if your application records audio, then it needs the
444{@code android.permission.RECORD_AUDIO} permission. Applications that use audio effects need
445{@code android.permission.MODIFY_AUDIO_SETTINGS}. Applications that play network URI resources
446need {@code android.permission.NETWORK}. See
447<a href="https://developer.android.com/training/permissions/index.html">Working with System
448Permissions</a> for more information.
449</p>
450
451<p>
452Depending on the platform version and implementation, media content parsers and
453 software codecs may
454run within the context of the Android application that calls OpenSL ES (hardware codecs are
455abstracted but are device-dependent). Malformed content designed to exploit parser and codec
456vulnerabilities is a known attack vector. We recommend that you play media only from trustworthy
457sources or that you partition your application such that code that handles media from
458untrustworthy sources runs in a relatively <em>sandboxed</em> environment. For example, you could
459process media from untrustworthy sources in a separate process. Though both processes would still
460run under the same UID, this separation does make an attack more difficult.
461</p>
462