1 /*****************************************************************************
2 * opensles_android.c : audio output for android native code
3 *****************************************************************************
4 * Copyright © 2011 VideoLAN
6 * Authors: Dominique Martinet <asmadeus@codewreck.org>
7 * Hugo Beauzée-Luyssen <beauze.h@gmail.com>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
32 #include <vlc_common.h>
33 #include <vlc_plugin.h>
39 #include <SLES/OpenSLES.h>
40 #include <SLES/OpenSLES_Android.h>
42 // Maximum number of buffers to enqueue.
45 /*****************************************************************************
46 * aout_sys_t: audio output method descriptor
47 *****************************************************************************
48 * This structure is part of the audio output thread descriptor.
49 * It describes the direct sound specific properties of an audio device.
50 *****************************************************************************/
53 SLObjectItf engineObject;
54 SLEngineItf engineEngine;
55 SLObjectItf outputMixObject;
56 SLAndroidSimpleBufferQueueItf playerBufferQueue;
57 SLObjectItf playerObject;
59 aout_buffer_t * p_buffer_array[BUFF_QUEUE];
61 int i_toappend_buffer;
62 SLInterfaceID * SL_IID_ENGINE;
63 SLInterfaceID * SL_IID_ANDROIDSIMPLEBUFFERQUEUE;
64 SLInterfaceID * SL_IID_VOLUME;
65 SLInterfaceID * SL_IID_PLAY;
69 typedef SLresult (*slCreateEngine_t)(
70 SLObjectItf*, SLuint32, const SLEngineOption*, SLuint32,
71 const SLInterfaceID*, const SLboolean* );
73 /*****************************************************************************
75 *****************************************************************************/
76 static int Open ( vlc_object_t * );
77 static void Close ( vlc_object_t * );
78 static void Play ( audio_output_t *, block_t * );
79 static void PlayedCallback ( SLAndroidSimpleBufferQueueItf caller, void *pContext);
81 /*****************************************************************************
83 *****************************************************************************/
86 set_description( N_("OpenSLES audio output") )
87 set_shortname( N_("OpenSLES") )
88 set_category( CAT_AUDIO )
89 set_subcategory( SUBCAT_AUDIO_AOUT )
91 set_capability( "audio output", 170 )
92 add_shortcut( "opensles", "android" )
93 set_callbacks( Open, Close )
97 #define CHECK_OPENSL_ERROR( res, msg ) \
98 if( unlikely( res != SL_RESULT_SUCCESS ) ) \
100 msg_Err( p_aout, msg" (%lu)", res ); \
104 #define OPENSL_DLSYM( dest, handle, name ) \
105 dest = (typeof(dest))dlsym( handle, name ); \
108 msg_Err( p_aout, "Failed to load symbol %s", name ); \
112 static void Clear( aout_sys_t *p_sys )
114 // Destroy buffer queue audio player object
115 // and invalidate all associated interfaces
116 if( p_sys->playerObject != NULL )
117 (*p_sys->playerObject)->Destroy( p_sys->playerObject );
119 // destroy output mix object, and invalidate all associated interfaces
120 if( p_sys->outputMixObject != NULL )
121 (*p_sys->outputMixObject)->Destroy( p_sys->outputMixObject );
123 // destroy engine object, and invalidate all associated interfaces
124 if( p_sys->engineObject != NULL )
125 (*p_sys->engineObject)->Destroy( p_sys->engineObject );
127 if( p_sys->p_so_handle != NULL )
128 dlclose( p_sys->p_so_handle );
133 /*****************************************************************************
134 * Open: open a dummy audio device
135 *****************************************************************************/
136 static int Open( vlc_object_t * p_this )
138 audio_output_t *p_aout = (audio_output_t *)p_this;
141 /* Allocate structure */
142 p_aout->sys = malloc( sizeof( aout_sys_t ) );
143 if( unlikely( p_aout->sys == NULL ) )
146 aout_sys_t * p_sys = p_aout->sys;
148 p_sys->playerObject = NULL;
149 p_sys->engineObject = NULL;
150 p_sys->outputMixObject = NULL;
151 p_sys->i_toclean_buffer = 0;
152 p_sys->i_toappend_buffer= 0;
154 //Acquiring LibOpenSLES symbols :
155 p_sys->p_so_handle = dlopen( "libOpenSLES.so", RTLD_NOW );
156 if( p_sys->p_so_handle == NULL )
158 msg_Err( p_aout, "Failed to load libOpenSLES" );
162 slCreateEngine_t slCreateEnginePtr = NULL;
164 OPENSL_DLSYM( slCreateEnginePtr, p_sys->p_so_handle, "slCreateEngine" );
165 OPENSL_DLSYM( p_sys->SL_IID_ANDROIDSIMPLEBUFFERQUEUE, p_sys->p_so_handle,
166 "SL_IID_ANDROIDSIMPLEBUFFERQUEUE" );
167 OPENSL_DLSYM( p_sys->SL_IID_ENGINE, p_sys->p_so_handle, "SL_IID_ENGINE" );
168 OPENSL_DLSYM( p_sys->SL_IID_PLAY, p_sys->p_so_handle, "SL_IID_PLAY" );
169 OPENSL_DLSYM( p_sys->SL_IID_VOLUME, p_sys->p_so_handle, "SL_IID_VOLUME" );
172 result = slCreateEnginePtr( &p_sys->engineObject, 0, NULL, 0, NULL, NULL );
173 CHECK_OPENSL_ERROR( result, "Failed to create engine" );
175 // realize the engine in synchronous mode
176 result = (*p_sys->engineObject)->Realize( p_sys->engineObject,
178 CHECK_OPENSL_ERROR( result, "Failed to realize engine" );
180 // get the engine interface, needed to create other objects
181 result = (*p_sys->engineObject)->GetInterface( p_sys->engineObject,
182 *p_sys->SL_IID_ENGINE, &p_sys->engineEngine );
183 CHECK_OPENSL_ERROR( result, "Failed to get the engine interface" );
185 // create output mix, with environmental reverb specified as a non-required interface
186 const SLInterfaceID ids1[] = { *p_sys->SL_IID_VOLUME };
187 const SLboolean req1[] = { SL_BOOLEAN_FALSE };
188 result = (*p_sys->engineEngine)->CreateOutputMix( p_sys->engineEngine,
189 &p_sys->outputMixObject, 1, ids1, req1 );
190 CHECK_OPENSL_ERROR( result, "Failed to create output mix" );
192 // realize the output mix in synchronous mode
193 result = (*p_sys->outputMixObject)->Realize( p_sys->outputMixObject,
195 CHECK_OPENSL_ERROR( result, "Failed to realize output mix" );
198 // configure audio source - this defines the number of samples you can enqueue.
199 SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {
200 SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,
204 SLDataFormat_PCM format_pcm;
205 format_pcm.formatType = SL_DATAFORMAT_PCM;
206 format_pcm.numChannels = 2;
207 format_pcm.samplesPerSec = ((SLuint32) p_aout->format.i_rate * 1000) ;
208 format_pcm.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16;
209 format_pcm.containerSize = SL_PCMSAMPLEFORMAT_FIXED_16;
210 format_pcm.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
211 format_pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;
213 SLDataSource audioSrc = {&loc_bufq, &format_pcm};
215 // configure audio sink
216 SLDataLocator_OutputMix loc_outmix = {
217 SL_DATALOCATOR_OUTPUTMIX,
218 p_sys->outputMixObject
220 SLDataSink audioSnk = {&loc_outmix, NULL};
222 //create audio player
223 const SLInterfaceID ids2[] = { *p_sys->SL_IID_ANDROIDSIMPLEBUFFERQUEUE };
224 const SLboolean req2[] = { SL_BOOLEAN_TRUE };
225 result = (*p_sys->engineEngine)->CreateAudioPlayer( p_sys->engineEngine,
226 &p_sys->playerObject, &audioSrc,
227 &audioSnk, sizeof( ids2 ) / sizeof( *ids2 ),
229 CHECK_OPENSL_ERROR( result, "Failed to create audio player" );
231 // realize the player
232 result = (*p_sys->playerObject)->Realize( p_sys->playerObject,
234 CHECK_OPENSL_ERROR( result, "Failed to realize player object." );
236 // get the play interface
237 result = (*p_sys->playerObject)->GetInterface( p_sys->playerObject,
238 *p_sys->SL_IID_PLAY, &p_sys->playerPlay );
239 CHECK_OPENSL_ERROR( result, "Failed to get player interface." );
241 // get the buffer queue interface
242 result = (*p_sys->playerObject)->GetInterface( p_sys->playerObject,
243 *p_sys->SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
244 &p_sys->playerBufferQueue );
245 CHECK_OPENSL_ERROR( result, "Failed to get buff queue interface" );
247 result = (*p_sys->playerBufferQueue)->RegisterCallback( p_sys->playerBufferQueue,
250 CHECK_OPENSL_ERROR( result, "Failed to register buff queue callback." );
253 // set the player's state to playing
254 result = (*p_sys->playerPlay)->SetPlayState( p_sys->playerPlay,
255 SL_PLAYSTATE_PLAYING );
256 CHECK_OPENSL_ERROR( result, "Failed to switch to playing state" );
258 // we want 16bit signed data little endian.
259 p_aout->format.i_format = VLC_CODEC_S16L;
260 p_aout->format.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
261 p_aout->pf_play = Play;
262 p_aout->pf_pause = NULL;
263 p_aout->pf_flush = NULL;
265 aout_FormatPrepare( &p_aout->format );
273 /*****************************************************************************
274 * Close: close our file
275 *****************************************************************************/
276 static void Close( vlc_object_t * p_this )
278 audio_output_t *p_aout = (audio_output_t *)p_this;
279 aout_sys_t *p_sys = p_aout->sys;
281 msg_Dbg( p_aout, "Closing OpenSLES" );
283 (*p_sys->playerPlay)->SetPlayState( p_sys->playerPlay, SL_PLAYSTATE_STOPPED );
284 //Flush remaining buffers if any.
285 if( p_sys->playerBufferQueue != NULL )
286 (*p_sys->playerBufferQueue)->Clear( p_sys->playerBufferQueue );
290 /*****************************************************************************
292 *****************************************************************************/
293 static void Play( audio_output_t * p_aout, block_t *p_buffer )
295 aout_sys_t * p_sys = p_aout->sys;
300 result = (*p_sys->playerBufferQueue)->Enqueue(
301 p_sys->playerBufferQueue, p_buffer->p_buffer,
302 p_buffer->i_buffer );
303 if( result == SL_RESULT_SUCCESS )
305 if ( result != SL_RESULT_BUFFER_INSUFFICIENT )
307 msg_Warn( p_aout, "Dropping invalid buffer" );
308 aout_BufferFree( p_buffer );
312 msg_Err( p_aout, "write error (%lu)", result );
314 // Wait a bit to retry. might miss calls to *cancel
315 // but this is supposed to be rare anyway
318 p_sys->p_buffer_array[p_sys->i_toappend_buffer] = p_buffer;
319 if( ++p_sys->i_toappend_buffer == BUFF_QUEUE )
320 p_sys->i_toappend_buffer = 0;
323 static void PlayedCallback (SLAndroidSimpleBufferQueueItf caller, void *pContext )
325 aout_sys_t *p_sys = (aout_sys_t*)pContext;
327 assert (caller == p_sys->playerBufferQueue);
329 aout_BufferFree( p_sys->p_buffer_array[p_sys->i_toclean_buffer] );
330 if( ++p_sys->i_toclean_buffer == BUFF_QUEUE )
331 p_sys->i_toclean_buffer = 0;