1 /*****************************************************************************
2 * tizen_audio.c: Tizen audio output module
3 *****************************************************************************
4 * Copyright © 2015 VLC authors, VideoLAN and VideoLabs
6 * Authors: Thomas Guillem <thomas@gllm.fr>
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation; either version 2.1 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
30 #include <stdatomic.h>
32 #include <vlc_common.h>
33 #include <vlc_plugin.h>
37 #include "sound_manager.h"
39 static int Open( vlc_object_t
* );
40 static void Close( vlc_object_t
* );
51 atomic_bool interrupted_completed
;
54 audio_sample_type_e i_sample_type
;
55 audio_channel_e i_channel
;
57 int (*pf_audio_out_drain
)( audio_out_h output
);
58 int (*pf_audio_out_flush
)( audio_out_h output
);
61 /* Soft volume helper */
62 #include "audio_output/volume.h"
65 set_shortname( "Tizen audio" )
66 set_description( "Tizen audio output" )
67 set_capability( "audio output", 180 )
68 set_category( CAT_AUDIO
)
69 set_subcategory( SUBCAT_AUDIO_AOUT
)
71 add_shortcut( "tizen" )
72 set_callbacks( Open
, Close
)
76 AudioIO_Err2Str( audio_io_error_e e
)
80 case AUDIO_IO_ERROR_NONE
:
81 return "AUDIO_IO_ERROR_NONE";
82 case AUDIO_IO_ERROR_OUT_OF_MEMORY
:
83 return "AUDIO_IO_ERROR_OUT_OF_MEMORY";
84 case AUDIO_IO_ERROR_INVALID_PARAMETER
:
85 return "AUDIO_IO_ERROR_INVALID_PARAMETER";
86 case AUDIO_IO_ERROR_INVALID_OPERATION
:
87 return "AUDIO_IO_ERROR_INVALID_OPERATION";
88 case AUDIO_IO_ERROR_PERMISSION_DENIED
:
89 return "AUDIO_IO_ERROR_PERMISSION_DENIED";
90 case AUDIO_IO_ERROR_NOT_SUPPORTED
:
91 return "AUDIO_IO_ERROR_NOT_SUPPORTED";
92 case AUDIO_IO_ERROR_DEVICE_NOT_OPENED
:
93 return "AUDIO_IO_ERROR_DEVICE_NOT_OPENED";
94 case AUDIO_IO_ERROR_DEVICE_NOT_CLOSED
:
95 return "AUDIO_IO_ERROR_DEVICE_NOT_CLOSED";
96 case AUDIO_IO_ERROR_INVALID_BUFFER
:
97 return "AUDIO_IO_ERROR_INVALID_BUFFER";
98 case AUDIO_IO_ERROR_SOUND_POLICY
:
99 return "AUDIO_IO_ERROR_SOUND_POLICY";
101 return "UNKNOWN_ERROR";
106 AudioIO_VlcRet( audio_output_t
*p_aout
, const char *p_func
, int i_ret
)
108 if( i_ret
!= AUDIO_IO_ERROR_NONE
)
110 aout_sys_t
*p_sys
= p_aout
->sys
;
112 msg_Err( p_aout
, "%s failed: 0x%X, %s", p_func
,
113 i_ret
, AudioIO_Err2Str( i_ret
) );
115 /* Error could be recoverable if audio_out was interrupted. */
116 p_sys
->b_error
= true;
122 #define VLCRET( func ) AudioIO_VlcRet( p_aout, #func, func )
125 AudioIO_Prepare( audio_output_t
*p_aout
)
127 aout_sys_t
*p_sys
= p_aout
->sys
;
129 /* if no more interrupted, cancel error and try again */
130 if( atomic_exchange( &p_sys
->interrupted_completed
, false ) )
131 p_sys
->b_error
= false;
136 if( !p_sys
->b_prepared
)
138 if( VLCRET( audio_out_prepare( p_sys
->out
) ) )
140 p_sys
->b_prepared
= true;
146 AudioIO_Unprepare( audio_output_t
*p_aout
)
148 aout_sys_t
*p_sys
= p_aout
->sys
;
150 if( p_sys
->b_prepared
)
152 p_sys
->b_prepared
= false;
154 /* Unlocked to avoid deadlock with AudioIO_StreamCb */
155 if( VLCRET( audio_out_unprepare( p_sys
->out
) ) )
162 AudioIO_InterruptedCb(audio_io_interrupted_code_e code
, void *p_user_data
)
164 audio_output_t
*p_aout
= p_user_data
;
165 aout_sys_t
*p_sys
= p_aout
->sys
;
167 if( code
== AUDIO_IO_INTERRUPTED_COMPLETED
168 || code
== AUDIO_IO_INTERRUPTED_BY_EARJACK_UNPLUG
)
170 msg_Warn( p_aout
, "audio_out interrupted completed by %d", code
);
171 atomic_store( &p_sys
->interrupted_completed
, true );
175 msg_Warn( p_aout
, "audio_out interrupted by %d", code
);
176 atomic_store( &p_sys
->interrupted_completed
, false );
181 AudioIO_Start( audio_output_t
*p_aout
)
183 aout_sys_t
*p_sys
= p_aout
->sys
;
186 if( VLCRET( audio_out_create( p_sys
->i_rate
, p_sys
->i_channel
,
187 p_sys
->i_sample_type
, SOUND_TYPE_MEDIA
,
190 return VLCRET( audio_out_set_interrupted_cb( p_sys
->out
,
191 AudioIO_InterruptedCb
,
196 Start( audio_output_t
*p_aout
, audio_sample_format_t
*restrict p_fmt
)
198 aout_sys_t
*p_sys
= p_aout
->sys
;
200 if( aout_FormatNbChannels( p_fmt
) == 0 )
203 aout_FormatPrint( p_aout
, "Tizen audio is looking for:", p_fmt
);
205 /* Sample rate: tizen accept rate between 8000 and 48000 Hz */
206 p_sys
->i_rate
= p_fmt
->i_rate
= VLC_CLIP( p_fmt
->i_rate
, 8000, 48000 );
209 switch( p_fmt
->i_physical_channels
)
212 p_sys
->i_channel
= AUDIO_CHANNEL_MONO
;
215 case AOUT_CHANS_STEREO
:
216 p_fmt
->i_physical_channels
= AOUT_CHANS_STEREO
;
217 p_sys
->i_channel
= AUDIO_CHANNEL_STEREO
;
222 switch( p_fmt
->i_format
)
225 p_sys
->i_sample_type
= AUDIO_SAMPLE_TYPE_U8
;
229 p_fmt
->i_format
= VLC_CODEC_S16N
;
230 p_sys
->i_sample_type
= AUDIO_SAMPLE_TYPE_S16_LE
;
234 if( AudioIO_Start( p_aout
) != VLC_SUCCESS
)
237 p_fmt
->channel_type
= AUDIO_CHANNEL_TYPE_BITMAP
;
239 aout_FormatPrepare( p_fmt
);
240 aout_SoftVolumeStart( p_aout
);
242 aout_FormatPrint( p_aout
, "Tizen audio will output:", p_fmt
);
248 Stop( audio_output_t
*p_aout
)
250 aout_sys_t
*p_sys
= p_aout
->sys
;
254 AudioIO_Unprepare( p_aout
);
255 audio_out_unset_interrupted_cb( p_sys
->out
);
256 audio_out_destroy( p_sys
->out
);
259 p_sys
->b_error
= false;
260 atomic_store( &p_sys
->interrupted_completed
, false );
263 p_sys
->i_channel
= 0;
264 p_sys
->i_sample_type
= 0;
268 Play( audio_output_t
*p_aout
, block_t
*p_block
, vlc_tick_t date
)
270 aout_sys_t
*p_sys
= p_aout
->sys
;
272 if( !p_sys
->out
|| AudioIO_Prepare( p_aout
) )
274 block_Release( p_block
);
280 int i_ret
= audio_out_write( p_sys
->out
, p_block
->p_buffer
, p_block
->i_buffer
);
283 AudioIO_VlcRet( p_aout
, "audio_out_write", i_ret
);
284 block_Release( p_block
);
289 p_block
->i_buffer
-= i_ret
;
290 p_block
->p_buffer
+= i_ret
;
291 if( !p_block
->i_buffer
)
293 block_Release( p_block
);
302 Pause( audio_output_t
*p_aout
, bool b_pause
, vlc_tick_t i_date
)
304 aout_sys_t
*p_sys
= p_aout
->sys
;
311 AudioIO_Unprepare( p_aout
);
315 Flush( audio_output_t
*p_aout
, bool b_wait
)
317 aout_sys_t
*p_sys
= p_aout
->sys
;
322 if( p_sys
->pf_audio_out_drain
|| p_sys
->pf_audio_out_flush
)
325 VLCRET( p_sys
->pf_audio_out_drain( p_sys
->out
) );
327 VLCRET( p_sys
->pf_audio_out_flush( p_sys
->out
) );
332 if( AudioIO_Unprepare( p_aout
) )
334 audio_out_unset_interrupted_cb( p_sys
->out
);
335 audio_out_destroy( p_sys
->out
);
337 AudioIO_Start( p_aout
);
342 Open( vlc_object_t
*obj
)
344 audio_output_t
*p_aout
= (audio_output_t
*) obj
;
347 p_sys
= calloc( 1, sizeof (aout_sys_t
) );
348 if( unlikely( p_sys
== NULL
) )
352 p_aout
->start
= Start
;
355 p_aout
->pause
= Pause
;
356 p_aout
->flush
= Flush
;
357 /* p_aout->time_get = TimeGet; FIXME */
359 /* Available only on 2.4 */
360 p_sys
->pf_audio_out_drain
= dlsym( RTLD_DEFAULT
, "audio_out_drain" );
361 p_sys
->pf_audio_out_flush
= dlsym( RTLD_DEFAULT
, "audio_out_flush" );
363 aout_SoftVolumeInit( p_aout
);
365 atomic_init( &p_sys
->interrupted_completed
, false );
371 Close( vlc_object_t
*obj
)
373 audio_output_t
*p_aout
= (audio_output_t
*) obj
;
374 aout_sys_t
*p_sys
= p_aout
->sys
;