]> git.sesse.net Git - vlc/blob - modules/audio_output/waveout.c
* modules/demux/mpeg: Added DVB stream type for A/52 streams (0x6),
[vlc] / modules / audio_output / waveout.c
1 /*****************************************************************************
2  * waveout.c : Windows waveOut plugin for vlc
3  *****************************************************************************
4  * Copyright (C) 2001 VideoLAN
5  * $Id: waveout.c,v 1.9 2002/10/20 12:23:47 massiot 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 #include "aout_internal.h"
36
37 #include <windows.h>
38 #include <mmsystem.h>
39
40 #define FRAME_SIZE 2048              /* The size is in samples, not in bytes */
41
42 /*****************************************************************************
43  * Local prototypes
44  *****************************************************************************/
45 static int  Open         ( vlc_object_t * );             
46 static void Close        ( vlc_object_t * );                   
47 static void Play         ( aout_instance_t * );
48
49 /* local functions */
50 static int OpenWaveOut   ( aout_instance_t *p_aout, int i_format,
51                            int i_channels, int i_rate );
52 static int PlayWaveOut   ( aout_instance_t *, HWAVEOUT, WAVEHDR *,
53                            aout_buffer_t * );
54 static void CALLBACK WaveOutCallback ( HWAVEOUT h_waveout, UINT uMsg,
55                                        DWORD _p_aout,
56                                        DWORD dwParam1, DWORD dwParam2 );
57
58 /*****************************************************************************
59  * Module descriptor
60  *****************************************************************************/
61 vlc_module_begin();
62     set_description( _("Win32 waveOut extension module") ); 
63     set_capability( "audio output", 50 );
64     set_callbacks( Open, Close );
65 vlc_module_end();
66
67 /*****************************************************************************
68  * aout_sys_t: waveOut audio output method descriptor
69  *****************************************************************************
70  * This structure is part of the audio output thread descriptor.
71  * It describes the waveOut specific properties of an audio device.
72  *****************************************************************************/
73 struct aout_sys_t
74 {
75     HWAVEOUT h_waveout;                        /* handle to waveout instance */
76
77     WAVEFORMATEX waveformat;                                 /* audio format */
78
79     WAVEHDR waveheader[2];
80
81     int i_buffer_size;
82
83     byte_t *p_silence_buffer;               /* buffer we use to play silence */
84 };
85
86 /*****************************************************************************
87  * Open: open the audio device
88  *****************************************************************************
89  * This function opens and setups Win32 waveOut
90  *****************************************************************************/
91 static int Open( vlc_object_t *p_this )
92 {   
93     aout_instance_t *p_aout = (aout_instance_t *)p_this;
94     aout_buffer_t *p_buffer;
95     int i_nb_channels;
96
97     /* Allocate structure */
98     p_aout->output.p_sys = malloc( sizeof( aout_sys_t ) );
99
100     if( p_aout->output.p_sys == NULL )
101     {
102         msg_Err( p_aout, "out of memory" );
103         return VLC_EGENERIC;
104     }
105
106     p_aout->output.pf_play = Play;
107     aout_VolumeSoftInit( p_aout );
108
109     i_nb_channels = aout_FormatNbChannels( &p_aout->output.output );
110     if ( i_nb_channels > 2 )
111     {
112         /* Waveout doesn't support more than two channels. */
113         i_nb_channels = 2;
114         p_aout->output.output.i_channels = AOUT_CHAN_STEREO;
115     }
116
117     /* We need to open the device with default values to be sure it is
118      * available */
119     if ( OpenWaveOut( p_aout, WAVE_FORMAT_PCM, i_nb_channels,
120                       p_aout->output.output.i_rate ) )
121     {
122         msg_Err( p_aout, "cannot open waveout audio device with output "
123                          "rate (%i)",
124                           p_aout->output.output.i_rate );
125         return VLC_EGENERIC;
126
127         if ( OpenWaveOut( p_aout, WAVE_FORMAT_PCM, i_nb_channels,
128                           44100 ) )
129         {
130             msg_Err( p_aout, "cannot open waveout audio device with output "
131                              "rate (44100)" );
132             return VLC_EGENERIC;
133         }
134         p_aout->output.output.i_rate = 44100;
135     }
136
137     waveOutReset( p_aout->output.p_sys->h_waveout );
138
139     /* Calculate the frame size in bytes */
140     p_aout->output.p_sys->i_buffer_size = FRAME_SIZE * sizeof(s16)
141                                   * p_aout->output.p_sys->waveformat.nChannels;
142     /* Allocate silence buffer */
143     p_aout->output.p_sys->p_silence_buffer =
144         calloc( p_aout->output.p_sys->i_buffer_size, 1 );
145     if( p_aout->output.p_sys->p_silence_buffer == NULL )
146     {
147         msg_Err( p_aout, "out of memory" );
148         return 1;
149     }
150
151     p_aout->output.output.i_format = AOUT_FMT_S16_NE;
152     p_aout->output.i_nb_samples = FRAME_SIZE;
153
154     /* We need to kick off the playback in order to have the callback properly
155      * working */
156     PlayWaveOut( p_aout, p_aout->output.p_sys->h_waveout,
157                  &p_aout->output.p_sys->waveheader[0], NULL );
158
159     p_buffer = aout_OutputNextBuffer( p_aout,
160         mdate() + 1000000 / p_aout->output.output.i_rate * FRAME_SIZE,
161         VLC_FALSE );
162     PlayWaveOut( p_aout, p_aout->output.p_sys->h_waveout,
163                  &p_aout->output.p_sys->waveheader[1], p_buffer );
164
165     return 0;
166 }
167
168 /*****************************************************************************
169  * Play: play a sound buffer
170  *****************************************************************************
171  * This doesn't actually play the buffer. This just stores the buffer so it
172  * can be played by the callback thread.
173  *****************************************************************************/
174 static void Play( aout_instance_t *p_aout )
175 {
176 }
177
178 /*****************************************************************************
179  * Close: close the audio device
180  *****************************************************************************/
181 static void Close( vlc_object_t *p_this )
182 {       
183     aout_instance_t *p_aout = (aout_instance_t *)p_this;
184
185     /* Before calling waveOutClose we must reset the device */
186     waveOutReset( p_aout->output.p_sys->h_waveout );
187
188     /* Close the device */
189     if( waveOutClose( p_aout->output.p_sys->h_waveout ) != MMSYSERR_NOERROR )
190     {
191         msg_Err( p_aout, "waveOutClose failed" );
192     }
193
194     /* Free silence buffer */
195     free( p_aout->output.p_sys->p_silence_buffer );
196
197     free( p_aout->output.p_sys );
198 }
199
200 /*****************************************************************************
201  * OpenWaveOut: open the waveout sound device
202  ****************************************************************************/
203 static int OpenWaveOut( aout_instance_t *p_aout, int i_format,
204                         int i_channels, int i_rate )
205 {
206     MMRESULT result;
207
208     /* Set sound format */
209     p_aout->output.p_sys->waveformat.wFormatTag = i_format;
210     p_aout->output.p_sys->waveformat.nChannels = i_channels;
211     p_aout->output.p_sys->waveformat.nSamplesPerSec = i_rate;
212     p_aout->output.p_sys->waveformat.wBitsPerSample = 16;
213     p_aout->output.p_sys->waveformat.nBlockAlign =
214         p_aout->output.p_sys->waveformat.wBitsPerSample / 8 * i_channels;
215     p_aout->output.p_sys->waveformat.nAvgBytesPerSec  =
216         p_aout->output.p_sys->waveformat.nSamplesPerSec *
217             p_aout->output.p_sys->waveformat.nBlockAlign;
218
219     /* Open the device */
220     result = waveOutOpen( &p_aout->output.p_sys->h_waveout, WAVE_MAPPER,
221                           &p_aout->output.p_sys->waveformat,
222                           (DWORD_PTR)WaveOutCallback, (DWORD_PTR)p_aout,
223                           CALLBACK_FUNCTION );
224     if( result == WAVERR_BADFORMAT )
225     {
226         msg_Err( p_aout, "waveOutOpen failed WAVERR_BADFORMAT" );
227         return( 1 );
228     }
229     if( result != MMSYSERR_NOERROR )
230     {
231         msg_Err( p_aout, "waveOutOpen failed" );
232         return 1;
233     }
234
235     return 0;
236 }
237
238 /*****************************************************************************
239  * PlayWaveOut: play a buffer through the WaveOut device
240  *****************************************************************************/
241 static int PlayWaveOut( aout_instance_t *p_aout, HWAVEOUT h_waveout,
242                         WAVEHDR *p_waveheader, aout_buffer_t *p_buffer )
243 {
244     MMRESULT result;
245
246     /* Prepare the buffer */
247     if( p_buffer != NULL )
248         p_waveheader->lpData = p_buffer->p_buffer;
249     else
250         /* Use silence buffer instead */
251         p_waveheader->lpData = p_aout->output.p_sys->p_silence_buffer;
252
253     p_waveheader->dwUser = (DWORD_PTR)p_buffer;
254     p_waveheader->dwBufferLength = p_aout->output.p_sys->i_buffer_size;
255     p_waveheader->dwFlags = 0;
256
257     result = waveOutPrepareHeader( h_waveout, p_waveheader, sizeof(WAVEHDR) );
258     if( result != MMSYSERR_NOERROR )
259     {
260         msg_Err( p_aout, "waveOutPrepareHeader failed" );
261         return 1;
262     }
263
264     /* Send the buffer to the waveOut queue */
265     result = waveOutWrite( h_waveout, p_waveheader, sizeof(WAVEHDR) );
266     if( result != MMSYSERR_NOERROR )
267     {
268         msg_Err( p_aout, "waveOutWrite failed" );
269         return 1;
270     }
271
272     return 0;
273 }
274
275 /*****************************************************************************
276  * WaveOutCallback: what to do once WaveOut has played its sound samples
277  *****************************************************************************/
278 static void CALLBACK WaveOutCallback( HWAVEOUT h_waveout, UINT uMsg,
279                                       DWORD _p_aout,
280                                       DWORD dwParam1, DWORD dwParam2 )
281 {
282     aout_instance_t *p_aout = (aout_instance_t *)_p_aout;
283     WAVEHDR *p_waveheader = (WAVEHDR *)dwParam1;
284     aout_buffer_t *p_buffer;
285
286     if( uMsg != WOM_DONE ) return;
287
288     /* Unprepare and free the buffer which has just been played */
289     waveOutUnprepareHeader( h_waveout, p_waveheader, sizeof(WAVEHDR) );
290     if( p_waveheader->dwUser )
291         aout_BufferFree( (aout_buffer_t *)p_waveheader->dwUser );
292
293     /* Take into account WaveOut latency instead of just mdate() */
294     p_buffer = aout_OutputNextBuffer( p_aout,
295         mdate() + 1000000 / p_aout->output.output.i_rate * FRAME_SIZE,
296         VLC_FALSE );
297
298     PlayWaveOut( p_aout, h_waveout, p_waveheader, p_buffer );
299 }