]> git.sesse.net Git - vlc/blob - plugins/win32/waveout.c
8dfd2b94a0e405ac33867924882d2882ad31072d
[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.7 2002/04/19 13:56:11 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 <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         /* Before calling waveOutClose we must reset the device */
159         waveOutReset( p_aout->p_sys->h_waveout );
160
161         if( waveOutClose( p_aout->p_sys->h_waveout ) != MMSYSERR_NOERROR )
162         {
163             intf_ErrMsg( "aout error: waveOutClose failed" );
164         }
165
166         return OpenWaveOutDevice( p_aout );
167     }
168
169     return 0;
170 }
171
172 /*****************************************************************************
173  * aout_GetBufInfo: buffer status query
174  *****************************************************************************
175  * returns the number of bytes in the audio buffer that have not yet been
176  * sent to the sound device.
177  *****************************************************************************/
178 static int aout_GetBufInfo( aout_thread_t *p_aout, int i_buffer_limit )
179 {
180     MMTIME mmtime;
181
182     mmtime.wType = TIME_BYTES;
183     if( (waveOutGetPosition(p_aout->p_sys->h_waveout, &mmtime, sizeof(MMTIME)))
184         != MMSYSERR_NOERROR || (mmtime.wType != TIME_BYTES) )
185     {
186         intf_WarnMsg( 3, "aout: aout_GetBufInfo waveOutGetPosition failed");
187         return i_buffer_limit;
188     }
189
190
191 #if 0
192     intf_WarnMsg( 3, "aout: waveOut aout_GetBufInfo: %i",
193                   p_aout->p_sys->dw_counter - mmtime.u.cb );
194 #endif
195
196     return (p_aout->p_sys->dw_counter - mmtime.u.cb);
197 }
198
199 /*****************************************************************************
200  * aout_Play: play a sound buffer
201  *****************************************************************************
202  * This function writes a buffer of i_length bytes
203  *****************************************************************************/
204 static void aout_Play( aout_thread_t *p_aout, byte_t *p_buffer, int i_size )
205 {
206     MMRESULT result;
207     int current_buffer = p_aout->p_sys->i_current_buffer;
208
209     p_aout->p_sys->i_current_buffer = (current_buffer + 1) % NUMBUF;
210
211     /* Prepare the buffer */
212     p_aout->p_sys->waveheader[current_buffer].lpData =
213         realloc( p_aout->p_sys->waveheader[current_buffer].lpData, i_size );
214     if( !p_aout->p_sys->waveheader[current_buffer].lpData )
215     {
216         intf_ErrMsg( "aout error: aou_Play couldn't alloc buffer" );
217         return;
218     }
219     p_aout->p_sys->waveheader[current_buffer].dwBufferLength = i_size;
220     p_aout->p_sys->waveheader[current_buffer].dwFlags = 0;
221
222     result = waveOutPrepareHeader( p_aout->p_sys->h_waveout,
223                                    &p_aout->p_sys->waveheader[current_buffer],
224                                    sizeof(WAVEHDR) );
225     if( result != MMSYSERR_NOERROR )
226     {
227         intf_ErrMsg( "aout error: waveOutPrepareHeader failed" );
228         return;
229     }
230
231     /* Send the buffer the waveOut queue */
232     FAST_MEMCPY( p_aout->p_sys->waveheader[current_buffer].lpData,
233                  p_buffer, i_size );
234     result = waveOutWrite( p_aout->p_sys->h_waveout,
235                            &p_aout->p_sys->waveheader[current_buffer],
236                            sizeof(WAVEHDR) );
237     if( result != MMSYSERR_NOERROR )
238     {
239         intf_ErrMsg( "aout error: waveOutWrite failed" );
240         return;
241     }
242
243     /* keep track of number of bytes played */
244     p_aout->p_sys->dw_counter += i_size;
245
246 }
247
248 /*****************************************************************************
249  * aout_Close: close the audio device
250  *****************************************************************************/
251 static void aout_Close( aout_thread_t *p_aout )
252 {
253     int i;
254
255     intf_WarnMsg( 3, "aout: waveOut aout_Close ");
256
257     /* Before calling waveOutClose we must reset the device */
258     waveOutReset( p_aout->p_sys->h_waveout );
259
260     /* Close the device */
261     if( waveOutClose( p_aout->p_sys->h_waveout ) != MMSYSERR_NOERROR )
262     {
263         intf_ErrMsg( "aout error: waveOutClose failed" );
264     }
265
266     /* Deallocate memory */
267     for( i=0; i<NUMBUF; i++ )
268         free( p_aout->p_sys->waveheader[i].lpData );
269
270     if( p_aout->p_sys != NULL )
271     { 
272         free( p_aout->p_sys );
273         p_aout->p_sys = NULL;
274     }
275 }
276
277 /*****************************************************************************
278  * OpenWaveOutDevice: open the sound device
279  ****************************************************************************/
280 static int OpenWaveOutDevice( aout_thread_t *p_aout )
281 {
282     MMRESULT result;
283
284     /* initialize played bytes counter */
285     p_aout->p_sys->dw_counter = 0;
286
287     /* Set sound format */
288     p_aout->p_sys->waveformat.wFormatTag       = WAVE_FORMAT_PCM;
289     p_aout->p_sys->waveformat.nChannels        = p_aout->i_channels;
290     p_aout->p_sys->waveformat.nSamplesPerSec   = p_aout->i_rate;
291     p_aout->p_sys->waveformat.wBitsPerSample   = 16;
292     p_aout->p_sys->waveformat.nBlockAlign      =
293         p_aout->p_sys->waveformat.wBitsPerSample / 8 * p_aout->i_channels;
294     p_aout->p_sys->waveformat.nAvgBytesPerSec  =
295         p_aout->p_sys->waveformat.nSamplesPerSec *
296             p_aout->p_sys->waveformat.nBlockAlign;
297
298
299     /* Open the device */
300     result = waveOutOpen( &p_aout->p_sys->h_waveout, WAVE_MAPPER,
301                           &p_aout->p_sys->waveformat,
302                           0 /*callback*/, 0 /*callback data*/, CALLBACK_NULL );
303     if( result != MMSYSERR_NOERROR )
304     {
305         intf_ErrMsg( "aout error: waveOutOpen failed" );
306         return( 1 );
307     }
308
309     return( 0 );
310 }