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