]> git.sesse.net Git - vlc/blob - src/audio_output/audio_output.c
649fd945288e7f446112a3ade2c190f11c32ee25
[vlc] / src / audio_output / audio_output.c
1 /*****************************************************************************
2  * audio_output.c : audio output thread
3  *****************************************************************************
4  * Copyright (C) 1999-2001 VideoLAN
5  * $Id: audio_output.c,v 1.89 2002/08/04 20:04:11 sam Exp $
6  *
7  * Authors: Michel Kaempf <maxx@via.ecp.fr>
8  *          Cyril Deguet <asmax@via.ecp.fr>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  * 
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #include <stdlib.h>                            /* calloc(), malloc(), free() */
29 #include <string.h>
30
31 #include <vlc/vlc.h>
32
33 #ifdef HAVE_UNISTD_H
34 #   include <unistd.h>                                           /* getpid() */
35 #endif
36
37 #ifdef WIN32                   /* getpid() for win32 is located in process.h */
38 #   include <process.h>
39 #endif
40
41 #include "audio_output.h"
42
43 #include "aout_pcm.h"
44 #include "aout_spdif.h"
45
46 /*****************************************************************************
47  * Local prototypes
48  *****************************************************************************/
49 static int  aout_SpawnThread ( aout_thread_t * p_aout );
50
51 /*****************************************************************************
52  * aout_CreateThread: initialize audio thread
53  *****************************************************************************/
54 aout_thread_t *aout_CreateThread( vlc_object_t *p_parent,
55                                   int i_channels, int i_rate )
56 {
57     aout_thread_t * p_aout;                             /* thread descriptor */
58     int             i_format;
59
60     /* Allocate descriptor */
61     p_aout = vlc_object_create( p_parent, VLC_OBJECT_AOUT );
62     if( p_aout == NULL )
63     {
64         return NULL;
65     }
66
67     p_aout->i_latency = 0;
68     p_aout->i_rate = config_GetInt( p_aout, "rate" );
69     p_aout->i_channels = config_GetInt( p_aout, "mono" ) ? 1 : 2;
70
71     i_format = config_GetInt( p_aout, "audio-format" );
72     if( ( !i_format ) || ( i_format > 8 ) )
73     {
74         p_aout->i_format = AOUT_FMT_S16_NE;
75     }
76     else
77     {
78         p_aout->i_format = 1 << ( i_format + 2 );
79     }
80
81     if( p_aout->i_rate == 0 )
82     {
83         msg_Err( p_aout, "null sample rate" );
84         vlc_object_destroy( p_aout );
85         return NULL;
86     }
87
88     /* Choose the best module */
89     p_aout->p_module = module_Need( p_aout, "audio output", "$aout" );
90     if( p_aout->p_module == NULL )
91     {
92         msg_Err( p_aout, "no suitable aout module" );
93         vlc_object_destroy( p_aout );
94         return NULL;
95     }
96
97     /*
98      * Initialize audio device
99      */
100     if ( p_aout->pf_setformat( p_aout ) )
101     {
102         module_Unneed( p_aout, p_aout->p_module );
103         vlc_object_destroy( p_aout );
104         return NULL;
105     }
106
107     /* Initialize the volume level */
108     p_aout->i_volume = config_GetInt( p_aout, "volume" );
109     p_aout->i_savedvolume = 0;
110     
111     /* FIXME: maybe it would be cleaner to change SpawnThread prototype
112      * see vout to handle status correctly ?? however, it is not critical since
113      * this thread is only called in main and all calls are blocking */
114     if( aout_SpawnThread( p_aout ) )
115     {
116         module_Unneed( p_aout, p_aout->p_module );
117         vlc_object_destroy( p_aout );
118         return NULL;
119     }
120
121     vlc_object_attach( p_aout, p_parent->p_vlc );
122
123     return p_aout;
124 }
125
126 /*****************************************************************************
127  * aout_SpawnThread
128  *****************************************************************************/
129 static int aout_SpawnThread( aout_thread_t * p_aout )
130 {
131     int     i_index, i_bytes;
132     void (* pf_aout_thread)( aout_thread_t * ) = NULL;
133     char   *psz_format;
134
135     /* Initialize the fifos lock */
136     vlc_mutex_init( p_aout, &p_aout->fifos_lock );
137
138     /* Initialize audio fifos : set all fifos as empty and initialize locks */
139     for ( i_index = 0; i_index < AOUT_MAX_FIFOS; i_index++ )
140     {
141         p_aout->fifo[i_index].i_format = AOUT_FIFO_NONE;
142         vlc_mutex_init( p_aout, &p_aout->fifo[i_index].data_lock );
143         vlc_cond_init( p_aout, &p_aout->fifo[i_index].data_wait );
144     }
145
146     /* Compute the size (in audio units) of the audio output buffer. Although
147      * AOUT_BUFFER_DURATION is given in microseconds, the output rate is given
148      * in Hz, that's why we need to divide by 10^6 microseconds (1 second) */
149     p_aout->i_units = (s64)p_aout->i_rate * AOUT_BUFFER_DURATION / 1000000;
150
151     /* Make pf_aout_thread point to the right thread function, and compute the
152      * byte size of the audio output buffer */
153     switch ( p_aout->i_format )
154     {
155         case AOUT_FMT_U8:
156             pf_aout_thread = aout_PCMThread;
157             psz_format = "unsigned 8 bits";
158             i_bytes = p_aout->i_units * p_aout->i_channels;
159             break;
160
161         case AOUT_FMT_S8:
162             pf_aout_thread = aout_PCMThread;
163             psz_format = "signed 8 bits";
164             i_bytes = p_aout->i_units * p_aout->i_channels;
165             break;
166
167         case AOUT_FMT_U16_LE:
168         case AOUT_FMT_U16_BE:
169             pf_aout_thread = aout_PCMThread;
170             psz_format = "unsigned 16 bits";
171             i_bytes = 2 * p_aout->i_units * p_aout->i_channels;
172             break;
173
174         case AOUT_FMT_S16_LE:
175         case AOUT_FMT_S16_BE:
176             pf_aout_thread = aout_PCMThread;
177             psz_format = "signed 16 bits";
178             i_bytes = 2 * p_aout->i_units * p_aout->i_channels;
179             break;
180
181         case AOUT_FMT_A52:
182             pf_aout_thread = aout_SpdifThread;
183             psz_format = "A52 pass-through";
184             i_bytes = SPDIF_FRAME_SIZE;
185             break;
186
187         default:
188             msg_Err( p_aout, "unknown audio output format %i",
189                              p_aout->i_format );
190             return( -1 );
191     }
192
193     /* Allocate the memory needed by the audio output buffers, and set to zero
194      * the s32 buffer's memory */
195     p_aout->buffer = malloc( i_bytes );
196     if ( p_aout->buffer == NULL )
197     {
198         msg_Err( p_aout, "out of memory" );
199         return( -1 );
200     }
201
202     p_aout->s32_buffer = (s32 *)calloc( p_aout->i_units,
203                                         sizeof(s32) * p_aout->i_channels );
204     if ( p_aout->s32_buffer == NULL )
205     {
206         msg_Err( p_aout, "out of memory" );
207         free( p_aout->buffer );
208         return( -1 );
209     }
210
211     /* Rough estimate of the playing date */
212     p_aout->date = mdate() + p_aout->p_vlc->i_desync;
213
214     /* Launch the thread */
215     if ( vlc_thread_create( p_aout, "audio output", pf_aout_thread, 0 ) )
216     {
217         msg_Err( p_aout, "cannot spawn audio output thread" );
218         free( p_aout->buffer );
219         free( p_aout->s32_buffer );
220         return( -1 );
221     }
222
223     msg_Dbg( p_aout, "%s thread spawned, %i channels, rate %i",
224                      psz_format, p_aout->i_channels, p_aout->i_rate );
225     return( 0 );
226 }
227
228 /*****************************************************************************
229  * aout_DestroyThread
230  *****************************************************************************/
231 void aout_DestroyThread( aout_thread_t * p_aout )
232 {
233     int i_index;
234     
235     /* Ask thread to kill itself and wait until it's done */
236     p_aout->b_die = 1;
237
238     vlc_thread_join( p_aout );
239
240     /* Free the allocated memory */
241     free( p_aout->buffer );
242     free( p_aout->s32_buffer );
243
244     /* Destroy the condition and mutex locks */
245     for ( i_index = 0; i_index < AOUT_MAX_FIFOS; i_index++ )
246     {
247         vlc_mutex_destroy( &p_aout->fifo[i_index].data_lock );
248         vlc_cond_destroy( &p_aout->fifo[i_index].data_wait );
249     }
250     vlc_mutex_destroy( &p_aout->fifos_lock );
251     
252     /* Release the aout module */
253     module_Unneed( p_aout, p_aout->p_module );
254
255     /* Free structure */
256     vlc_object_destroy( p_aout );
257 }
258