Main Page | Modules | Class Hierarchy | Class List | Directories | File List | Class Members | File Members | Related Pages

sdl.c

00001 /*****************************************************************************
00002  * sdl.c : SDL audio output plugin for vlc
00003  *****************************************************************************
00004  * Copyright (C) 2000-2002 the VideoLAN team
00005  * $Id: sdl.c 11664 2005-07-09 06:17:09Z courmisch $
00006  *
00007  * Authors: Michel Kaempf <[email protected]>
00008  *          Sam Hocevar <[email protected]>
00009  *          Pierre Baillet <[email protected]>
00010  *          Christophe Massiot <[email protected]>
00011  *
00012  * This program is free software; you can redistribute it and/or modify
00013  * it under the terms of the GNU General Public License as published by
00014  * the Free Software Foundation; either version 2 of the License, or
00015  * (at your option) any later version.
00016  *
00017  * This program is distributed in the hope that it will be useful,
00018  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00019  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020  * GNU General Public License for more details.
00021  *
00022  * You should have received a copy of the GNU General Public License
00023  * along with this program; if not, write to the Free Software
00024  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
00025  *****************************************************************************/
00026 
00027 /*****************************************************************************
00028  * Preamble
00029  *****************************************************************************/
00030 #include <errno.h>                                                 /* ENOMEM */
00031 #include <fcntl.h>                                       /* open(), O_WRONLY */
00032 #include <string.h>                                            /* strerror() */
00033 #include <unistd.h>                                      /* write(), close() */
00034 #include <stdlib.h>                            /* calloc(), malloc(), free() */
00035 
00036 #include <vlc/vlc.h>
00037 #include <vlc/aout.h>
00038 #include "aout_internal.h"
00039 
00040 #include SDL_INCLUDE_FILE
00041 
00042 #define FRAME_SIZE 2048
00043 
00044 /*****************************************************************************
00045  * aout_sys_t: SDL audio output method descriptor
00046  *****************************************************************************
00047  * This structure is part of the audio output thread descriptor.
00048  * It describes the specific properties of an audio device.
00049  *****************************************************************************/
00050 struct aout_sys_t
00051 {
00052     mtime_t next_date;
00053     mtime_t buffer_time;
00054 };
00055 
00056 /*****************************************************************************
00057  * Local prototypes
00058  *****************************************************************************/
00059 static int  Open        ( vlc_object_t * );
00060 static void Close       ( vlc_object_t * );
00061 static void Play        ( aout_instance_t * );
00062 static void SDLCallback ( void *, byte_t *, int );
00063 
00064 /*****************************************************************************
00065  * Module descriptor
00066  *****************************************************************************/
00067 vlc_module_begin();
00068     set_shortname( "SDL" );
00069     set_description( _("Simple DirectMedia Layer audio output") );
00070     set_capability( "audio output", 40 );
00071     set_category( CAT_AUDIO );
00072     set_subcategory( SUBCAT_AUDIO_AOUT );
00073     add_shortcut( "sdl" );
00074     set_callbacks( Open, Close );
00075 vlc_module_end();
00076 
00077 /*****************************************************************************
00078  * Open: open the audio device
00079  *****************************************************************************/
00080 static int Open ( vlc_object_t *p_this )
00081 {
00082     aout_instance_t *p_aout = (aout_instance_t *)p_this;
00083     SDL_AudioSpec desired, obtained;
00084     int i_nb_channels;
00085     vlc_value_t val, text;
00086 
00087     /* Check that no one uses the DSP. */
00088     uint32_t i_flags = SDL_INIT_AUDIO;
00089     if( SDL_WasInit( i_flags ) )
00090     {
00091         return VLC_EGENERIC;
00092     }
00093 
00094 #ifndef WIN32
00095     /* Win32 SDL implementation doesn't support SDL_INIT_EVENTTHREAD yet */
00096     i_flags |= SDL_INIT_EVENTTHREAD;
00097 #endif
00098 #ifdef DEBUG
00099     /* In debug mode you may want vlc to dump a core instead of staying
00100      * stuck */
00101     i_flags |= SDL_INIT_NOPARACHUTE;
00102 #endif
00103 
00104     /* Initialize library */
00105     if( SDL_Init( i_flags ) < 0 )
00106     {
00107         msg_Err( p_aout, "cannot initialize SDL (%s)", SDL_GetError() );
00108         return VLC_EGENERIC;
00109     }
00110 
00111     if ( var_Type( p_aout, "audio-device" ) != 0 )
00112     {
00113         /* The user has selected an audio device. */
00114         vlc_value_t val;
00115         var_Get( p_aout, "audio-device", &val );
00116         if ( val.i_int == AOUT_VAR_STEREO )
00117         {
00118             p_aout->output.output.i_physical_channels
00119                 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
00120         }
00121         else if ( val.i_int == AOUT_VAR_MONO )
00122         {
00123             p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER;
00124         }
00125     }
00126 
00127     i_nb_channels = aout_FormatNbChannels( &p_aout->output.output );
00128     if ( i_nb_channels > 2 )
00129     {
00130         /* SDL doesn't support more than two channels. */
00131         i_nb_channels = 2;
00132         p_aout->output.output.i_physical_channels
00133             = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
00134     }
00135     desired.freq       = p_aout->output.output.i_rate;
00136     desired.format     = AUDIO_S16SYS;
00137     desired.channels   = i_nb_channels;
00138     desired.callback   = SDLCallback;
00139     desired.userdata   = p_aout;
00140     desired.samples    = FRAME_SIZE;
00141 
00142     /* Open the sound device. */
00143     if( SDL_OpenAudio( &desired, &obtained ) < 0 )
00144     {
00145         return VLC_EGENERIC;
00146     }
00147 
00148     SDL_PauseAudio( 0 );
00149 
00150     /* Now have a look at what we got. */
00151     switch ( obtained.format )
00152     {
00153     case AUDIO_S16LSB:
00154         p_aout->output.output.i_format = VLC_FOURCC('s','1','6','l'); break;
00155     case AUDIO_S16MSB:
00156         p_aout->output.output.i_format = VLC_FOURCC('s','1','6','b'); break;
00157     case AUDIO_U16LSB:
00158         p_aout->output.output.i_format = VLC_FOURCC('u','1','6','l'); break;
00159     case AUDIO_U16MSB:
00160         p_aout->output.output.i_format = VLC_FOURCC('u','1','6','b'); break;
00161     case AUDIO_S8:
00162         p_aout->output.output.i_format = VLC_FOURCC('s','8',' ',' '); break;
00163     case AUDIO_U8:
00164         p_aout->output.output.i_format = VLC_FOURCC('u','8',' ',' '); break;
00165     }
00166     /* Volume is entirely done in software. */
00167     aout_VolumeSoftInit( p_aout );
00168 
00169     if ( obtained.channels != i_nb_channels )
00170     {
00171         p_aout->output.output.i_physical_channels = (obtained.channels == 2 ?
00172                                             AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT :
00173                                             AOUT_CHAN_CENTER);
00174 
00175         if ( var_Type( p_aout, "audio-device" ) == 0 )
00176         {
00177             var_Create( p_aout, "audio-device",
00178                         VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
00179             text.psz_string = _("Audio Device");
00180             var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
00181 
00182             val.i_int = (obtained.channels == 2) ? AOUT_VAR_STEREO :
00183                         AOUT_VAR_MONO;
00184             text.psz_string = (obtained.channels == 2) ? N_("Stereo") :
00185                               N_("Mono");
00186             var_Change( p_aout, "audio-device",
00187                         VLC_VAR_ADDCHOICE, &val, &text );
00188             var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart,
00189                              NULL );
00190         }
00191     }
00192     else if ( var_Type( p_aout, "audio-device" ) == 0 )
00193     {
00194         /* First launch. */
00195         var_Create( p_aout, "audio-device",
00196                     VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
00197         text.psz_string = _("Audio Device");
00198         var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
00199 
00200         val.i_int = AOUT_VAR_STEREO;
00201         text.psz_string = N_("Stereo");
00202         var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
00203         val.i_int = AOUT_VAR_MONO;
00204         text.psz_string = N_("Mono");
00205         var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
00206         if ( i_nb_channels == 2 )
00207         {
00208             val.i_int = AOUT_VAR_STEREO;
00209         }
00210         else
00211         {
00212             val.i_int = AOUT_VAR_MONO;
00213         }
00214         var_Change( p_aout, "audio-device", VLC_VAR_SETDEFAULT, &val, NULL );
00215         var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
00216     }
00217 
00218     val.b_bool = VLC_TRUE;
00219     var_Set( p_aout, "intf-change", val );
00220 
00221     p_aout->output.output.i_rate = obtained.freq;
00222     p_aout->output.i_nb_samples = obtained.samples;
00223     p_aout->output.pf_play = Play;
00224 
00225     return VLC_SUCCESS;
00226 }
00227 
00228 /*****************************************************************************
00229  * Play: play a sound samples buffer
00230  *****************************************************************************/
00231 static void Play( aout_instance_t * p_aout )
00232 {
00233 }
00234 
00235 /*****************************************************************************
00236  * Close: close the audio device
00237  *****************************************************************************/
00238 static void Close ( vlc_object_t *p_this )
00239 {
00240     SDL_PauseAudio( 1 );
00241     SDL_CloseAudio();
00242     SDL_QuitSubSystem( SDL_INIT_AUDIO );
00243 }
00244 
00245 /*****************************************************************************
00246  * SDLCallback: what to do once SDL has played sound samples
00247  *****************************************************************************/
00248 static void SDLCallback( void * _p_aout, byte_t * p_stream, int i_len )
00249 {
00250     aout_instance_t * p_aout = (aout_instance_t *)_p_aout;
00251     aout_buffer_t *   p_buffer;
00252 
00253     /* SDL is unable to call us at regular times, or tell us its current
00254      * hardware latency, or the buffer state. So we just pop data and throw
00255      * it at SDL's face. Nah. */
00256 
00257     vlc_mutex_lock( &p_aout->output_fifo_lock );
00258     p_buffer = aout_FifoPop( p_aout, &p_aout->output.fifo );
00259     vlc_mutex_unlock( &p_aout->output_fifo_lock );
00260 
00261     if ( p_buffer != NULL )
00262     {
00263         p_aout->p_vlc->pf_memcpy( p_stream, p_buffer->p_buffer, i_len );
00264         aout_BufferFree( p_buffer );
00265     }
00266     else
00267     {
00268         p_aout->p_vlc->pf_memset( p_stream, 0, i_len );
00269     }
00270 }
00271 

Generated on Tue Dec 20 10:14:28 2005 for vlc-0.8.4a by  doxygen 1.4.2