]> git.sesse.net Git - vlc/blob - plugins/win32/waveout.c
* ALL: the first libvlc commit.
[vlc] / plugins / win32 / waveout.c
1 /*****************************************************************************
2  * waveout.c : Windows waveOut plugin for vlc
3  *****************************************************************************
4  * Copyright (C) 2001 VideoLAN
5  * $Id: waveout.c,v 1.8 2002/06/01 12:32:00 sam Exp $
6  *
7  * Authors: Gildas Bazin <gbazin@netcourrier.com>
8  *      
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.
13  * 
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.
18  *
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
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <errno.h>                                                 /* ENOMEM */
28 #include <fcntl.h>                                       /* open(), O_WRONLY */
29 #include <string.h>                                            /* strerror() */
30
31 #include <stdlib.h>                            /* calloc(), malloc(), free() */
32
33 #include <vlc/vlc.h>
34 #include <vlc/aout.h>
35
36 #include <mmsystem.h>
37
38 /*****************************************************************************
39  * Local prototypes.
40  *****************************************************************************/
41 static void    aout_getfunctions( function_list_t * p_function_list );
42
43 static int     aout_Open        ( aout_thread_t *p_aout );
44 static int     aout_SetFormat   ( aout_thread_t *p_aout );
45 static int     aout_GetBufInfo  ( aout_thread_t *p_aout, int i_buffer_info );
46 static void    aout_Play        ( aout_thread_t *p_aout,
47                                   byte_t *buffer, int i_size );
48 static void    aout_Close       ( aout_thread_t *p_aout );
49
50 /* local functions */
51 static int     OpenWaveOutDevice( aout_thread_t *p_aout );
52
53 /*****************************************************************************
54  * Building configuration tree
55  *****************************************************************************/
56 MODULE_CONFIG_START
57 MODULE_CONFIG_STOP
58
59 MODULE_INIT_START
60     SET_DESCRIPTION( _("Win32 waveOut extension module") )
61     ADD_CAPABILITY( AOUT, 250 )
62 MODULE_INIT_STOP
63
64 MODULE_ACTIVATE_START
65     aout_getfunctions( &p_module->p_functions->aout );
66 MODULE_ACTIVATE_STOP
67
68 MODULE_DEACTIVATE_START
69 MODULE_DEACTIVATE_STOP
70
71 /*****************************************************************************
72  * aout_sys_t: waveOut audio output method descriptor
73  *****************************************************************************
74  * This structure is part of the audio output thread descriptor.
75  * It describes the waveOut specific properties of an audio device.
76  *****************************************************************************/
77
78 #define NUMBUF 3           /* We use triple buffering to be on the safe side */
79
80 struct aout_sys_s
81 {
82     HWAVEOUT h_waveout;                        /* handle to waveout instance */
83
84     WAVEFORMATEX waveformat;                                 /* Audio format */
85
86     WAVEHDR waveheader[NUMBUF];
87
88     int i_current_buffer;
89
90     DWORD dw_counter;              /* Number of bytes played since beginning */
91 };
92
93 /*****************************************************************************
94  * Functions exported as capabilities. They are declared as static so that
95  * we don't pollute the namespace too much.
96  *****************************************************************************/
97 static void aout_getfunctions( function_list_t * p_function_list )
98 {
99     p_function_list->functions.aout.pf_open = aout_Open;
100     p_function_list->functions.aout.pf_setformat = aout_SetFormat;
101     p_function_list->functions.aout.pf_getbufinfo = aout_GetBufInfo;
102     p_function_list->functions.aout.pf_play = aout_Play;
103     p_function_list->functions.aout.pf_close = aout_Close;
104 }
105
106 /*****************************************************************************
107  * aout_Open: open the audio device
108  *****************************************************************************
109  * This function opens and setups Win32 waveOut
110  *****************************************************************************/
111 static int aout_Open( aout_thread_t *p_aout )
112 {
113     int i;
114
115     /* Allocate structure */
116     p_aout->p_sys = malloc( sizeof( aout_sys_t ) );
117
118     if( p_aout->p_sys == NULL )
119     {
120         msg_Err( p_aout, "out of memory" );
121         return( 1 );
122     }
123
124
125     /* Initialize some variables */
126     p_aout->p_sys->i_current_buffer = 0;
127     for( i=0; i<NUMBUF; i++)
128         p_aout->p_sys->waveheader[i].lpData = malloc( 1 );
129
130     return OpenWaveOutDevice( p_aout );
131
132 }
133
134 /*****************************************************************************
135  * aout_SetFormat: reset the audio device and sets its format
136  *****************************************************************************
137  * This functions set a new audio format.
138  * For this we need to close the current device and create another
139  * one with the desired format.
140  *****************************************************************************/
141 static int aout_SetFormat( aout_thread_t *p_aout )
142 {
143     msg_Dbg( p_aout, "aout_SetFormat" );
144
145     /* Check if the format has changed */
146
147     if( (p_aout->p_sys->waveformat.nChannels != p_aout->i_channels) ||
148         (p_aout->p_sys->waveformat.nSamplesPerSec != p_aout->i_rate) )
149     {
150         /* Before calling waveOutClose we must reset the device */
151         waveOutReset( p_aout->p_sys->h_waveout );
152
153         if( waveOutClose( p_aout->p_sys->h_waveout ) != MMSYSERR_NOERROR )
154         {
155             msg_Err( p_aout, "waveOutClose failed" );
156         }
157
158         return OpenWaveOutDevice( p_aout );
159     }
160
161     return 0;
162 }
163
164 /*****************************************************************************
165  * aout_GetBufInfo: buffer status query
166  *****************************************************************************
167  * returns the number of bytes in the audio buffer that have not yet been
168  * sent to the sound device.
169  *****************************************************************************/
170 static int aout_GetBufInfo( aout_thread_t *p_aout, int i_buffer_limit )
171 {
172     MMTIME mmtime;
173
174     mmtime.wType = TIME_BYTES;
175     if( (waveOutGetPosition(p_aout->p_sys->h_waveout, &mmtime, sizeof(MMTIME)))
176         != MMSYSERR_NOERROR || (mmtime.wType != TIME_BYTES) )
177     {
178         msg_Warn( p_aout, "waveOutGetPosition failed" );
179         return i_buffer_limit;
180     }
181
182
183 #if 0
184     msg_Dbg( p_aout, "aout_GetBufInfo: %i",
185                       p_aout->p_sys->dw_counter - mmtime.u.cb );
186 #endif
187
188     return (p_aout->p_sys->dw_counter - mmtime.u.cb);
189 }
190
191 /*****************************************************************************
192  * aout_Play: play a sound buffer
193  *****************************************************************************
194  * This function writes a buffer of i_length bytes
195  *****************************************************************************/
196 static void aout_Play( aout_thread_t *p_aout, byte_t *p_buffer, int i_size )
197 {
198     MMRESULT result;
199     int current_buffer = p_aout->p_sys->i_current_buffer;
200
201     p_aout->p_sys->i_current_buffer = (current_buffer + 1) % NUMBUF;
202
203     /* Prepare the buffer */
204     p_aout->p_sys->waveheader[current_buffer].lpData =
205         realloc( p_aout->p_sys->waveheader[current_buffer].lpData, i_size );
206     if( !p_aout->p_sys->waveheader[current_buffer].lpData )
207     {
208         msg_Err( p_aout, "could not allocate buffer" );
209         return;
210     }
211     p_aout->p_sys->waveheader[current_buffer].dwBufferLength = i_size;
212     p_aout->p_sys->waveheader[current_buffer].dwFlags = 0;
213
214     result = waveOutPrepareHeader( p_aout->p_sys->h_waveout,
215                                    &p_aout->p_sys->waveheader[current_buffer],
216                                    sizeof(WAVEHDR) );
217     if( result != MMSYSERR_NOERROR )
218     {
219         msg_Err( p_aout, "waveOutPrepareHeader failed" );
220         return;
221     }
222
223     /* Send the buffer the waveOut queue */
224     p_aout->p_vlc->pf_memcpy( p_aout->p_sys->waveheader[current_buffer].lpData,
225                               p_buffer, i_size );
226     result = waveOutWrite( p_aout->p_sys->h_waveout,
227                            &p_aout->p_sys->waveheader[current_buffer],
228                            sizeof(WAVEHDR) );
229     if( result != MMSYSERR_NOERROR )
230     {
231         msg_Err( p_aout, "waveOutWrite failed" );
232         return;
233     }
234
235     /* keep track of number of bytes played */
236     p_aout->p_sys->dw_counter += i_size;
237
238 }
239
240 /*****************************************************************************
241  * aout_Close: close the audio device
242  *****************************************************************************/
243 static void aout_Close( aout_thread_t *p_aout )
244 {
245     int i;
246
247     /* Before calling waveOutClose we must reset the device */
248     waveOutReset( p_aout->p_sys->h_waveout );
249
250     /* Close the device */
251     if( waveOutClose( p_aout->p_sys->h_waveout ) != MMSYSERR_NOERROR )
252     {
253         msg_Err( p_aout, "waveOutClose failed" );
254     }
255
256     /* Deallocate memory */
257     for( i=0; i<NUMBUF; i++ )
258         free( p_aout->p_sys->waveheader[i].lpData );
259
260     if( p_aout->p_sys != NULL )
261     { 
262         free( p_aout->p_sys );
263         p_aout->p_sys = NULL;
264     }
265 }
266
267 /*****************************************************************************
268  * OpenWaveOutDevice: open the sound device
269  ****************************************************************************/
270 static int OpenWaveOutDevice( aout_thread_t *p_aout )
271 {
272     MMRESULT result;
273
274     /* initialize played bytes counter */
275     p_aout->p_sys->dw_counter = 0;
276
277     /* Set sound format */
278     p_aout->p_sys->waveformat.wFormatTag       = WAVE_FORMAT_PCM;
279     p_aout->p_sys->waveformat.nChannels        = p_aout->i_channels;
280     p_aout->p_sys->waveformat.nSamplesPerSec   = p_aout->i_rate;
281     p_aout->p_sys->waveformat.wBitsPerSample   = 16;
282     p_aout->p_sys->waveformat.nBlockAlign      =
283         p_aout->p_sys->waveformat.wBitsPerSample / 8 * p_aout->i_channels;
284     p_aout->p_sys->waveformat.nAvgBytesPerSec  =
285         p_aout->p_sys->waveformat.nSamplesPerSec *
286             p_aout->p_sys->waveformat.nBlockAlign;
287
288
289     /* Open the device */
290     result = waveOutOpen( &p_aout->p_sys->h_waveout, WAVE_MAPPER,
291                           &p_aout->p_sys->waveformat,
292                           0 /*callback*/, 0 /*callback data*/, CALLBACK_NULL );
293     if( result != MMSYSERR_NOERROR )
294     {
295         msg_Err( p_aout, "waveOutOpen failed" );
296         return( 1 );
297     }
298
299     return( 0 );
300 }