2
2
* portaudio.c : portaudio (v19) audio output plugin
3
3
*****************************************************************************
4
4
* Copyright (C) 2002, 2006 the VideoLAN team
5
* $Id: da2758aadbae32248fc3adf871604aa7e5936bb2 $
5
* $Id: 3a8764063d76ff4a2d99377b69fa764dc0fd998d $
7
7
* Authors: Frederic Ruget <frederic.ruget@free.fr>
8
8
* Gildas Bazin <gbazin@videolan.org>
11
11
* it under the terms of the GNU General Public License as published by
12
12
* the Free Software Foundation; either version 2 of the License, or
13
13
* (at your option) any later version.
15
15
* This program is distributed in the hope that it will be useful,
16
16
* but WITHOUT ANY WARRANTY; without even the implied warranty of
17
17
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25
25
/*****************************************************************************
27
27
*****************************************************************************/
33
#include <vlc_common.h>
34
#include <vlc_plugin.h>
33
38
#include <portaudio.h>
35
#include "aout_internal.h"
37
40
#define FRAME_SIZE 1024 /* The size is in samples, not in bytes */
67
70
PaDeviceIndex i_device_id;
68
71
const PaDeviceInfo *deviceInfo;
70
vlc_bool_t b_chan_reorder; /* do we need channel reordering */
73
bool b_chan_reorder; /* do we need channel reordering */
71
74
int pi_chan_table[AOUT_CHAN_MAX];
72
75
uint32_t i_channel_mask;
73
76
uint32_t i_bits_per_sample;
74
77
uint32_t i_channels;
77
static const uint32_t pi_channels_in[] =
78
{ AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT,
79
AOUT_CHAN_MIDDLELEFT, AOUT_CHAN_MIDDLERIGHT,
80
AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT,
81
AOUT_CHAN_CENTER, AOUT_CHAN_LFE, 0 };
82
80
static const uint32_t pi_channels_out[] =
83
81
{ AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT,
84
82
AOUT_CHAN_CENTER, AOUT_CHAN_LFE,
85
AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT,
83
AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT, AOUT_CHAN_REARCENTER,
86
84
AOUT_CHAN_MIDDLELEFT, AOUT_CHAN_MIDDLERIGHT, 0 };
88
86
#ifdef PORTAUDIO_IS_SERIOUSLY_BROKEN
89
static vlc_bool_t b_init = 0;
87
static bool b_init = 0;
90
88
static pa_thread_t *pa_thread;
91
static void PORTAUDIOThread( pa_thread_t * );
89
static void* PORTAUDIOThread( vlc_object_t * );
94
92
/*****************************************************************************
110
108
vlc_module_begin();
111
109
set_shortname( "PortAudio" );
112
set_description( _("PORTAUDIO audio output") );
110
set_description( N_("PORTAUDIO audio output") );
113
111
set_category( CAT_AUDIO );
114
112
set_subcategory( SUBCAT_AUDIO_AOUT );
115
113
add_integer( "portaudio-device", 0, NULL,
116
DEVICE_TEXT, DEVICE_LONGTEXT, VLC_FALSE );
114
DEVICE_TEXT, DEVICE_LONGTEXT, false );
117
115
set_capability( "audio output", 0 );
118
116
set_callbacks( Open, Close );
119
117
vlc_module_end();
135
133
out_date = mdate() + (mtime_t) ( 1000000 *
136
134
( paDate->outputBufferDacTime - paDate->currentTime ) );
137
p_buffer = aout_OutputNextBuffer( p_aout, out_date, VLC_TRUE );
135
p_buffer = aout_OutputNextBuffer( p_aout, out_date, true );
139
137
if ( p_buffer != NULL )
145
143
p_sys->i_channels, p_sys->pi_chan_table,
146
144
p_sys->i_bits_per_sample );
148
p_aout->p_vlc->pf_memcpy( outputBuffer, p_buffer->p_buffer,
149
framesPerBuffer * p_sys->i_sample_size );
146
vlc_memcpy( outputBuffer, p_buffer->p_buffer,
147
framesPerBuffer * p_sys->i_sample_size );
150
148
/* aout_BufferFree may be dangereous here, but then so is
151
149
* aout_OutputNextBuffer (calls aout_BufferFree internally).
152
150
* one solution would be to link the no longer useful buffers
159
157
/* Audio output buffer shortage -> stop the fill process and wait */
161
p_aout->p_vlc->pf_memset( outputBuffer, 0,
162
framesPerBuffer * p_sys->i_sample_size );
159
vlc_memset( outputBuffer, 0, framesPerBuffer * p_sys->i_sample_size );
179
176
/* Allocate p_sys structure */
180
177
p_sys = (aout_sys_t *)malloc( sizeof(aout_sys_t) );
181
178
if( p_sys == NULL )
183
msg_Err( p_aout, "out of memory" );
184
179
return VLC_ENOMEM;
186
180
p_sys->p_aout = p_aout;
187
181
p_sys->p_stream = 0;
188
182
p_aout->output.p_sys = p_sys;
210
204
msg_Err( p_aout, "closing the device returned %d", i_err );
215
209
/* Now we need to setup our DirectSound play notification structure */
216
210
pa_thread = vlc_object_create( p_aout, sizeof(pa_thread_t) );
217
211
pa_thread->p_aout = p_aout;
218
pa_thread->b_error = VLC_FALSE;
219
vlc_mutex_init( p_aout, &pa_thread->lock_wait );
212
pa_thread->b_error = false;
213
vlc_mutex_init( &pa_thread->lock_wait );
220
214
vlc_cond_init( p_aout, &pa_thread->wait );
221
pa_thread->b_wait = VLC_FALSE;
222
vlc_mutex_init( p_aout, &pa_thread->lock_signal );
215
pa_thread->b_wait = false;
216
vlc_mutex_init( &pa_thread->lock_signal );
223
217
vlc_cond_init( p_aout, &pa_thread->signal );
224
pa_thread->b_signal = VLC_FALSE;
218
pa_thread->b_signal = false;
226
220
/* Create PORTAUDIOThread */
227
221
if( vlc_thread_create( pa_thread, "aout", PORTAUDIOThread,
228
VLC_THREAD_PRIORITY_OUTPUT, VLC_FALSE ) )
222
VLC_THREAD_PRIORITY_OUTPUT, false ) )
230
224
msg_Err( p_aout, "cannot create PORTAUDIO thread" );
231
225
return VLC_EGENERIC;
236
230
pa_thread->p_aout = p_aout;
237
pa_thread->b_wait = VLC_FALSE;
238
pa_thread->b_signal = VLC_FALSE;
239
pa_thread->b_error = VLC_FALSE;
231
pa_thread->b_wait = false;
232
pa_thread->b_signal = false;
233
pa_thread->b_error = false;
242
236
/* Signal start of stream */
243
237
vlc_mutex_lock( &pa_thread->lock_signal );
244
pa_thread->b_signal = VLC_TRUE;
238
pa_thread->b_signal = true;
245
239
vlc_cond_signal( &pa_thread->signal );
246
240
vlc_mutex_unlock( &pa_thread->lock_signal );
250
244
if( !pa_thread->b_wait )
251
245
vlc_cond_wait( &pa_thread->wait, &pa_thread->lock_wait );
252
246
vlc_mutex_unlock( &pa_thread->lock_wait );
253
pa_thread->b_wait = VLC_FALSE;
247
pa_thread->b_wait = false;
255
249
if( pa_thread->b_error )
296
290
/* Signal end of stream */
297
291
vlc_mutex_lock( &pa_thread->lock_signal );
298
pa_thread->b_signal = VLC_TRUE;
292
pa_thread->b_signal = true;
299
293
vlc_cond_signal( &pa_thread->signal );
300
294
vlc_mutex_unlock( &pa_thread->lock_signal );
304
298
if( !pa_thread->b_wait )
305
299
vlc_cond_wait( &pa_thread->wait, &pa_thread->lock_wait );
306
300
vlc_mutex_unlock( &pa_thread->lock_wait );
307
pa_thread->b_wait = VLC_FALSE;
301
pa_thread->b_wait = false;
441
435
var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
443
val.b_bool = VLC_TRUE;
444
438
var_Set( p_aout, "intf-change", val );
516
510
p_aout->output.p_sys->i_channels = i_channels;
518
512
p_aout->output.p_sys->b_chan_reorder =
519
aout_CheckChannelReorder( pi_channels_in, pi_channels_out,
513
aout_CheckChannelReorder( NULL, pi_channels_out,
520
514
i_channel_mask, i_channels,
521
515
p_aout->output.p_sys->pi_chan_table );
573
567
* PORTAUDIOThread: all interactions with libportaudio.a are handled
574
568
* in this single thread. Otherwise libportaudio.a is _not_ happy :-(
575
569
*****************************************************************************/
576
static void PORTAUDIOThread( pa_thread_t *pa_thread )
570
static void* PORTAUDIOThread( vlc_object_t *p_this )
572
pa_thread_t *pa_thread = (pa_thread_t*)p_this;
578
573
aout_instance_t *p_aout;
579
574
aout_sys_t *p_sys;
582
while( !pa_thread->b_die )
577
while( vlc_object_alive (pa_thread) )
584
579
/* Wait for start of stream */
585
580
vlc_mutex_lock( &pa_thread->lock_signal );
586
581
if( !pa_thread->b_signal )
587
582
vlc_cond_wait( &pa_thread->signal, &pa_thread->lock_signal );
588
583
vlc_mutex_unlock( &pa_thread->lock_signal );
589
pa_thread->b_signal = VLC_FALSE;
584
pa_thread->b_signal = false;
591
586
p_aout = pa_thread->p_aout;
592
587
p_sys = p_aout->output.p_sys;
594
589
if( PAOpenDevice( p_aout ) != VLC_SUCCESS )
596
591
msg_Err( p_aout, "cannot open portaudio device" );
597
pa_thread->b_error = VLC_TRUE;
592
pa_thread->b_error = true;
600
595
if( !pa_thread->b_error && PAOpenStream( p_aout ) != VLC_SUCCESS )
602
597
msg_Err( p_aout, "cannot open portaudio device" );
603
pa_thread->b_error = VLC_TRUE;
598
pa_thread->b_error = true;
605
600
i_err = Pa_Terminate();
606
601
if( i_err != paNoError )
613
608
/* Tell the main thread that we are ready */
614
609
vlc_mutex_lock( &pa_thread->lock_wait );
615
pa_thread->b_wait = VLC_TRUE;
610
pa_thread->b_wait = true;
616
611
vlc_cond_signal( &pa_thread->wait );
617
612
vlc_mutex_unlock( &pa_thread->lock_wait );
621
616
if( !pa_thread->b_signal )
622
617
vlc_cond_wait( &pa_thread->signal, &pa_thread->lock_signal );
623
618
vlc_mutex_unlock( &pa_thread->lock_signal );
624
pa_thread->b_signal = VLC_FALSE;
619
pa_thread->b_signal = false;
626
621
if( pa_thread->b_error ) continue;
647
642
/* Tell the main thread that we are ready */
648
643
vlc_mutex_lock( &pa_thread->lock_wait );
649
pa_thread->b_wait = VLC_TRUE;
644
pa_thread->b_wait = true;
650
645
vlc_cond_signal( &pa_thread->wait );
651
646
vlc_mutex_unlock( &pa_thread->lock_wait );