1 /*****************************************************************************
2 * portaudio.c : portaudio audio output plugin
3 *****************************************************************************
4 * Copyright (C) 2002 VideoLAN
7 * Authors: Frederic Ruget <frederic.ruget@free.fr>
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.
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.
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 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
32 #include <portaudio.h>
34 #include "aout_internal.h"
36 #define FRAME_SIZE 1024 /* The size is in samples, not in bytes */
39 /*****************************************************************************
40 * aout_sys_t: portaudio audio output method descriptor
41 *****************************************************************************/
44 aout_instance_t *p_aout;
45 PortAudioStream *p_stream;
48 PaSampleFormat sampleFormat;
50 PaDeviceID i_deviceId;
51 PaDeviceInfo deviceInfo;
54 /*****************************************************************************
56 *****************************************************************************/
57 static int Open ( vlc_object_t * );
58 static void Close ( vlc_object_t * );
59 static void Play ( aout_instance_t * );
60 static int i_once = 0;
62 /*****************************************************************************
64 *****************************************************************************/
65 #define DEVICE_TEXT N_("Output device")
66 #define DEVICE_LONGTEXT N_("Portaudio identifier for the output device")
69 set_description( N_("PORTAUDIO audio output") );
70 add_integer( "portaudio-device", 0, NULL,
71 DEVICE_TEXT, DEVICE_LONGTEXT, VLC_FALSE );
72 set_capability( "audio output", 40 );
73 set_callbacks( Open, Close );
76 /* This routine will be called by the PortAudio engine when audio is needed.
77 ** It may called at interrupt level on some machines so don't do anything
78 ** that could mess up the system like calling malloc() or free().
80 static int paCallback( void *inputBuffer, void *outputBuffer,
81 unsigned long framesPerBuffer,
82 PaTimestamp outTime, void *p_cookie )
84 struct aout_sys_t* p_sys = (struct aout_sys_t*) p_cookie;
85 aout_instance_t * p_aout = p_sys->p_aout;
86 aout_buffer_t * p_buffer;
88 vlc_mutex_lock( &p_aout->output_fifo_lock );
89 p_buffer = aout_FifoPop( p_aout, &p_aout->output.fifo );
90 vlc_mutex_unlock( &p_aout->output_fifo_lock );
92 if ( p_buffer != NULL )
94 p_aout->p_vlc->pf_memcpy( outputBuffer, p_buffer->p_buffer,
95 framesPerBuffer * p_sys->i_sampleSize );
96 aout_BufferFree( p_buffer );
100 p_aout->p_vlc->pf_memset( outputBuffer, 0,
101 framesPerBuffer * p_sys->i_sampleSize );
106 /*****************************************************************************
107 * Open: open the audio device
108 *****************************************************************************/
109 static int Open ( vlc_object_t * p_this )
111 aout_instance_t *p_aout = (aout_instance_t *)p_this;
112 struct aout_sys_t * p_sys;
113 PortAudioStream *p_stream;
117 const PaDeviceInfo *p_pdi;
120 msg_Dbg( p_aout, "Entering Open()");
122 /* Allocate p_sys structure */
123 p_sys = (struct aout_sys_t*) malloc( sizeof( aout_sys_t ) );
126 msg_Err( p_aout, "out of memory" );
129 p_sys->p_aout = p_aout;
130 p_aout->output.p_sys = p_sys;
132 /* Output device id */
133 var_Create( p_this, "portaudio-device",
134 VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
135 var_Get( p_this, "portaudio-device", &val );
136 p_sys->i_deviceId = val.i_int;
141 i_err = Pa_Initialize();
142 if ( i_err != paNoError )
144 msg_Err( p_aout, "Pa_Initialize returned %d : %s", i_err, Pa_GetErrorText( i_err ));
148 p_sys->i_numDevices = Pa_CountDevices();
149 if( p_sys->i_numDevices < 0 )
151 i_err = p_sys->i_numDevices;
152 msg_Err( p_aout, "Pa_CountDevices returned %d : %s", i_err, Pa_GetErrorText( i_err ));
153 (void) Pa_Terminate();
156 msg_Info( p_aout, "Number of devices = %d", p_sys->i_numDevices );
157 if ( p_sys->i_deviceId >= p_sys->i_numDevices )
159 msg_Err( p_aout, "Device %d does not exist", p_sys->i_deviceId );
160 (void) Pa_Terminate();
163 for( i = 0; i < p_sys->i_numDevices; i++ )
165 p_pdi = Pa_GetDeviceInfo( i );
166 if ( i == p_sys->i_deviceId )
168 p_sys->deviceInfo = *p_pdi;
170 msg_Info( p_aout, "---------------------------------------------- #%d", i );
171 msg_Info( p_aout, "Name = %s", p_pdi->name );
172 msg_Info( p_aout, "Max Inputs = %d, Max Outputs = %d",
173 p_pdi->maxInputChannels, p_pdi->maxOutputChannels );
174 if( p_pdi->numSampleRates == -1 )
176 msg_Info( p_aout, "Sample Rate Range = %f to %f", p_pdi->sampleRates[0], p_pdi->sampleRates[1] );
180 msg_Info( p_aout, "Sample Rates =");
181 for( j = 0; j < p_pdi->numSampleRates; j++ )
183 msg_Info( p_aout, " %8.2f,", p_pdi->sampleRates[j] );
186 msg_Info( p_aout, "Native Sample Formats = ");
187 if( p_pdi->nativeSampleFormats & paInt8 ) msg_Info( p_aout, "paInt8");
188 if( p_pdi->nativeSampleFormats & paUInt8 ) msg_Info( p_aout, "paUInt8");
189 if( p_pdi->nativeSampleFormats & paInt16 ) msg_Info( p_aout, "paInt16");
190 if( p_pdi->nativeSampleFormats & paInt32 ) msg_Info( p_aout, "paInt32");
191 if( p_pdi->nativeSampleFormats & paFloat32 ) msg_Info( p_aout, "paFloat32");
192 if( p_pdi->nativeSampleFormats & paInt24 ) msg_Info( p_aout, "paInt24");
193 if( p_pdi->nativeSampleFormats & paPackedInt24 ) msg_Info( p_aout, "paPackedInt24");
196 msg_Info( p_aout, "----------------------------------------------");
200 portaudio warning: Number of devices = 3
201 portaudio warning: ---------------------------------------------- #0 DefaultInput DefaultOutput
202 portaudio warning: Name = PORTAUDIO DirectX Full Duplex Driver
203 portaudio warning: Max Inputs = 2, Max Outputs = 2
204 portaudio warning: Sample Rates =
205 portaudio warning: 11025.00,
206 portaudio warning: 22050.00,
207 portaudio warning: 32000.00,
208 portaudio warning: 44100.00,
209 portaudio warning: 48000.00,
210 portaudio warning: 88200.00,
211 portaudio warning: 96000.00,
212 portaudio warning: Native Sample Formats =
213 portaudio warning: paInt16
214 portaudio warning: ---------------------------------------------- #1
215 portaudio warning: Name = PORTAUDIO Multimedia Driver
216 portaudio warning: Max Inputs = 2, Max Outputs = 2
217 portaudio warning: Sample Rates =
218 portaudio warning: 11025.00,
219 portaudio warning: 22050.00,
220 portaudio warning: 32000.00,
221 portaudio warning: 44100.00,
222 portaudio warning: 48000.00,
223 portaudio warning: 88200.00,
224 portaudio warning: 96000.00,
225 portaudio warning: Native Sample Formats =
226 portaudio warning: paInt16
227 portaudio warning: ---------------------------------------------- #2
228 portaudio warning: Name = E-MU PORTAUDIO
229 portaudio warning: Max Inputs = 0, Max Outputs = 4
230 portaudio warning: Sample Rates =
231 portaudio warning: 44100.00,
232 portaudio warning: 48000.00,
233 portaudio warning: 96000.00,
234 portaudio warning: Native Sample Formats =
235 portaudio warning: paInt16
236 portaudio warning: ----------------------------------------------
239 p_aout->output.pf_play = Play;
240 aout_VolumeSoftInit( p_aout );
242 /* select audio format */
243 if( p_sys->deviceInfo.nativeSampleFormats & paFloat32 )
245 p_sys->sampleFormat = paFloat32;
246 p_aout->output.output.i_format = VLC_FOURCC('f','l','3','2');
247 p_sys->i_sampleSize = 4;
249 else if( p_sys->deviceInfo.nativeSampleFormats & paInt16 )
251 p_sys->sampleFormat = paInt16;
252 p_aout->output.output.i_format = AOUT_FMT_S16_NE;
253 p_sys->i_sampleSize = 2;
257 msg_Err( p_aout, "Audio format not supported" );
258 (void) Pa_Terminate();
262 i_nb_channels = aout_FormatNbChannels( &p_aout->output.output );
263 msg_Info( p_aout, "nb_channels = %d", i_nb_channels );
264 if ( i_nb_channels > p_sys->deviceInfo.maxOutputChannels )
266 if ( p_sys->deviceInfo.maxOutputChannels < 1 )
268 msg_Err( p_aout, "No channel available" );
269 (void) Pa_Terminate();
272 else if ( p_sys->deviceInfo.maxOutputChannels < 2 )
274 p_sys->i_nbChannels = 1;
275 p_aout->output.output.i_physical_channels
278 else if ( p_sys->deviceInfo.maxOutputChannels < 4 )
280 p_sys->i_nbChannels = 2;
281 p_aout->output.output.i_physical_channels
282 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
284 else if ( p_sys->deviceInfo.maxOutputChannels < 6 )
286 p_sys->i_nbChannels = 4;
287 p_aout->output.output.i_physical_channels
288 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
289 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
293 p_sys->i_nbChannels = 6;
294 p_aout->output.output.i_physical_channels
295 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
296 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
300 p_sys->i_sampleSize *= p_sys->i_nbChannels;
302 /* Open portaudio stream */
303 p_aout->output.i_nb_samples = FRAME_SIZE;
304 msg_Info( p_aout, "rate = %d", p_aout->output.output.i_rate );
305 msg_Info( p_aout, "samples = %d", p_aout->output.i_nb_samples );
307 i_err = Pa_OpenStream(
309 paNoDevice, 0, 0, 0, /* no input device */
310 p_sys->i_deviceId, /* output device */
314 (double) p_aout->output.output.i_rate,
315 (unsigned long) p_aout->output.i_nb_samples, /* FRAMES_PER_BUFFER */
316 FRAMES_NUM, /* number of buffers, if zero then use default minimum */
317 paClipOff, /* we won't output out of range samples so don't bother clipping them */
319 if( i_err != paNoError )
321 msg_Err( p_aout, "Pa_OpenStream returns %d : %s", i_err,
322 Pa_GetErrorText( i_err ) );
323 (void) Pa_Terminate();
327 p_sys->p_stream = p_stream;
328 i_err = Pa_StartStream( p_stream );
329 if( i_err != paNoError )
331 (void) Pa_CloseStream( p_stream);
332 (void) Pa_Terminate();
336 msg_Dbg( p_aout, "Leaving Open()" );
340 /*****************************************************************************
341 * Close: close the audio device
342 *****************************************************************************/
343 static void Close ( vlc_object_t *p_this )
345 aout_instance_t *p_aout = (aout_instance_t *)p_this;
346 struct aout_sys_t * p_sys = p_aout->output.p_sys;
347 PortAudioStream *p_stream = p_sys->p_stream;
350 msg_Dbg( p_aout, "Entering Close()");
352 i_err = Pa_AbortStream( p_stream );
353 if ( i_err != paNoError )
355 msg_Err( p_aout, "Pa_AbortStream: %d (%s)", i_err, Pa_GetErrorText( i_err ) );
357 i_err = Pa_CloseStream( p_stream );
358 if ( i_err != paNoError )
360 msg_Err( p_aout, "Pa_CloseStream: %d (%s)", i_err, Pa_GetErrorText( i_err ) );
362 i_err = Pa_Terminate();
363 if ( i_err != paNoError )
365 msg_Err( p_aout, "Pa_Terminate: %d (%s)", i_err, Pa_GetErrorText( i_err ) );
367 msg_Dbg( p_aout, "Leaving Close()");
370 /*****************************************************************************
372 *****************************************************************************/
373 static void Play( aout_instance_t * p_aout )