]> git.sesse.net Git - vlc/blob - modules/audio_output/jack.c
JACK patch from Jon Griffiths
[vlc] / modules / audio_output / jack.c
1 /*****************************************************************************
2  * jack : JACK audio output module
3  *****************************************************************************
4  * Copyright (C) 2006 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Cyril Deguet <asmax@videolan.org>
8  *          Jon Griffiths <jon_p_griffiths _At_ yahoo _DOT_ com>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24 /**
25  * \file modules/audio_output/jack.c
26  * \brief JACK audio output functions
27  */
28 /*****************************************************************************
29  * Preamble
30  *****************************************************************************/
31 #include <string.h>                                            /* strerror() */
32 #include <unistd.h>                                      /* write(), close() */
33 #include <stdlib.h>                            /* calloc(), malloc(), free() */
34
35 #include <vlc/vlc.h>
36 #include <vlc_aout.h>
37
38 #include <jack/jack.h>
39
40 /*****************************************************************************
41  * aout_sys_t: JACK audio output method descriptor
42  *****************************************************************************
43  * This structure is part of the audio output thread descriptor.
44  * It describes some JACK specific variables.
45  *****************************************************************************/
46 struct aout_sys_t
47 {
48     jack_client_t *p_jack_client;
49     jack_port_t  **p_jack_ports;
50     unsigned int  i_channels;
51 };
52
53 /*****************************************************************************
54  * Local prototypes
55  *****************************************************************************/
56 static int  Open         ( vlc_object_t * );
57 static void Close        ( vlc_object_t * );
58 static void Play         ( aout_instance_t * );
59 static int Process       ( jack_nframes_t i_frames, void *p_arg );
60
61 #define AUTO_CONNECT_OPTION "jack-auto-connect"
62 #define AUTO_CONNECT_TEXT N_("Automatically connect to input devices")
63 #define AUTO_CONNECT_LONGTEXT N_( \
64     "If enabled, this option will automatically connect output to the " \
65     "first JACK inputs found." )
66
67 #define CONNECT_MATCH_OPTION "jack-connect-match"
68 #define CONNECT_MATCH_TEXT N_("Connect to outputs beginning with")
69 #define CONNECT_MATCH_LONGTEXT N_( \
70     "If automatic connection is enabled, only JACK inputs whose names " \
71     "begin with this prefix will be considered for connection." )
72
73 /*****************************************************************************
74  * Module descriptor
75  *****************************************************************************/
76 vlc_module_begin();
77     set_shortname( "JACK" );
78     set_description( _("JACK audio output") );
79     set_capability( "audio output", 100 );
80     set_category( CAT_AUDIO );
81     set_subcategory( SUBCAT_AUDIO_AOUT );
82     add_bool( AUTO_CONNECT_OPTION, 0, NULL, AUTO_CONNECT_TEXT,
83               AUTO_CONNECT_LONGTEXT, VLC_TRUE );
84     add_string( CONNECT_MATCH_OPTION, NULL, NULL, CONNECT_MATCH_TEXT,
85                 CONNECT_MATCH_LONGTEXT, VLC_TRUE );
86     set_callbacks( Open, Close );
87 vlc_module_end();
88
89 /*****************************************************************************
90  * Open: create a JACK client
91  *****************************************************************************/
92 static int Open( vlc_object_t *p_this )
93 {
94     aout_instance_t *p_aout = (aout_instance_t *)p_this;
95     struct aout_sys_t *p_sys = NULL;
96     char **pp_match_ports = NULL;
97     char *psz_prefix = NULL;
98     int status = VLC_SUCCESS;
99     unsigned int i;
100
101     /* Allocate structure */
102     p_sys = malloc( sizeof( aout_sys_t ) );
103     if( p_sys == NULL )
104     {
105         msg_Err( p_aout, "out of memory" );
106         status = VLC_ENOMEM;
107         goto error_out;
108     }
109     p_aout->output.p_sys = p_sys;
110
111     /* Connect to the JACK server */
112     p_sys->p_jack_client = jack_client_new( "vlc" );
113     if( p_sys->p_jack_client == NULL )
114     {
115         msg_Err( p_aout, "failed to connect to JACK server" );
116         status = VLC_EGENERIC;
117         goto error_out;
118     }
119
120     /* Set the process callback */
121     jack_set_process_callback( p_sys->p_jack_client, Process, p_aout );
122
123     p_aout->output.pf_play = Play;
124     aout_VolumeSoftInit( p_aout );
125
126     /* JACK only supports fl32 format */
127     p_aout->output.output.i_format = VLC_FOURCC('f','l','3','2');
128     // TODO add buffer size callback
129     p_aout->output.i_nb_samples = jack_get_buffer_size( p_sys->p_jack_client );
130     p_aout->output.output.i_rate = jack_get_sample_rate( p_sys->p_jack_client );
131
132     p_sys->i_channels = aout_FormatNbChannels( &p_aout->output.output );
133
134     p_sys->p_jack_ports = malloc( p_sys->i_channels * sizeof(jack_port_t  *) );
135     if( p_sys->p_jack_ports == NULL )
136     {
137         msg_Err( p_aout, "out of memory" );
138         status = VLC_ENOMEM;
139         goto error_out;
140     }
141
142     /* Create the output ports */
143     for( i = 0; i < p_sys->i_channels; i++ )
144     {
145         char p_name[32];
146         snprintf( p_name, 32, "out_%d", i + 1);
147         p_sys->p_jack_ports[i] = jack_port_register( p_sys->p_jack_client,
148                 p_name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0 );
149
150         if( p_sys->p_jack_ports[i] == NULL )
151         {
152             msg_Err( p_aout, "failed to register a JACK port" );
153             status = VLC_EGENERIC;
154             goto error_out;
155         }
156     }
157
158     /* Tell the JACK server we are ready */
159     if( jack_activate( p_sys->p_jack_client ) )
160     {
161         msg_Err( p_aout, "failed to activate JACK client" );
162         jack_client_close( p_sys->p_jack_client );
163         status = VLC_EGENERIC;
164         goto error_out;
165     }
166
167     /* Auto connect ports if we were asked to */
168     if( config_GetInt( p_aout, AUTO_CONNECT_OPTION ) )
169     {
170         unsigned int i_in_ports, i_prefix_len;
171         const char **pp_in_ports;
172
173         pp_in_ports = jack_get_ports( p_sys->p_jack_client, NULL, NULL,
174                                       JackPortIsInput );
175         psz_prefix = config_GetPsz( p_aout, CONNECT_MATCH_OPTION );
176         i_prefix_len = psz_prefix ? strlen(psz_prefix) : 0;
177
178         /* Find JACK input ports to connect to */
179         i = 0;
180         i_in_ports = 0;
181         while( pp_in_ports && pp_in_ports[i] )
182         {
183             if( !psz_prefix ||
184                 !strncmp(psz_prefix, pp_in_ports[i], i_prefix_len) )
185             {
186                 i_in_ports++; /* Found one */
187             }
188             i++;
189         }
190
191         /* Connect the output ports to input ports */
192         if( i_in_ports > 0 )
193         {
194             pp_match_ports = malloc( i_in_ports * sizeof(char*) );
195             if( pp_match_ports == NULL )
196             {
197                 msg_Err( p_aout, "out of memory" );
198                 status = VLC_ENOMEM;
199                 goto error_out;
200             }
201
202             /* populate list of matching ports */
203             i = 0;
204             i_in_ports = 0;
205             while( pp_in_ports[i] )
206             {
207                 if( !psz_prefix ||
208                      !strncmp(psz_prefix, pp_in_ports[i], i_prefix_len) )
209                 {
210                     pp_match_ports[i_in_ports] = pp_in_ports[i];
211                     i_in_ports++;  /* Found one */
212                 }
213                 i++;
214             }
215
216             /* Tie the output ports to JACK input ports */
217             for( i = 0; i < p_sys->i_channels; i++ )
218             {
219                 const char* psz_in = pp_match_ports[i % i_in_ports];
220                 const char* psz_out = jack_port_name( p_sys->p_jack_ports[i] );
221
222                 if( jack_connect( p_sys->p_jack_client, psz_out, psz_in) )
223                 {
224                     msg_Err( p_aout, "failed to connect port %s to port %s",
225                              psz_out, psz_in );
226                 }
227                 else
228                 {
229                     msg_Dbg( p_aout, "connecting port %s to port %s",
230                              psz_out, psz_in );
231                 }
232             }
233         }
234     }
235
236     msg_Dbg( p_aout, "JACK audio output initialized (%d channels, buffer "
237              "size=%d, rate=%d)", p_sys->i_channels,
238              p_aout->output.i_nb_samples, p_aout->output.output.i_rate );
239
240 error_out:
241     /* Clean up */
242     if( psz_prefix )
243         free( psz_prefix );
244
245     if( pp_match_ports )
246         free( pp_match_ports );
247
248     if( status != VLC_SUCCESS && p_sys != NULL)
249     {
250         if( p_sys->p_jack_ports )
251             free( p_sys->p_jack_ports );
252         if( p_sys->p_jack_client )
253             jack_client_close( p_sys->p_jack_client );
254         free( p_sys );
255     }
256     return status;
257 }
258
259
260 /*****************************************************************************
261  * Process: callback for JACK
262  *****************************************************************************/
263 int Process( jack_nframes_t i_frames, void *p_arg )
264 {
265     aout_buffer_t *p_buffer;
266     jack_default_audio_sample_t *p_jack_buffer;
267     unsigned int i, j, i_nb_samples = 0;
268     aout_instance_t *p_aout = (aout_instance_t*) p_arg;
269     unsigned int i_nb_channels = p_aout->output.p_sys->i_channels;
270
271     /* Get the next audio data buffer */
272     p_buffer = aout_FifoPop( p_aout, &p_aout->output.fifo );
273
274     if( p_buffer )
275     {
276         i_nb_samples = p_buffer->i_nb_samples;
277     }
278
279     for( i = 0; i < i_nb_channels; i++ )
280     {
281         /* Get an output buffer from JACK */
282         p_jack_buffer = jack_port_get_buffer(
283             p_aout->output.p_sys->p_jack_ports[i], i_frames );
284
285         /* Fill the buffer with audio data */
286         for( j = 0; j < i_nb_samples; j++ )
287         {
288             p_jack_buffer[j] = ((float*)p_buffer->p_buffer)[i_nb_channels*j+i];
289         }
290         if( i_nb_samples < i_frames )
291         {
292             memset( p_jack_buffer + i_nb_samples, 0,
293                     sizeof( jack_default_audio_sample_t ) *
294                     (i_frames - i_nb_samples) );
295         }
296     }
297
298     if( p_buffer )
299     {
300         aout_BufferFree( p_buffer );
301     }
302
303     return 0;
304 }
305
306
307 /*****************************************************************************
308  * Play: nothing to do
309  *****************************************************************************/
310 static void Play( aout_instance_t *p_aout )
311 {
312     aout_FifoFirstDate( p_aout, &p_aout->output.fifo );
313 }
314
315 /*****************************************************************************
316  * Close: close the JACK client
317  *****************************************************************************/
318 static void Close( vlc_object_t *p_this )
319 {
320     aout_instance_t *p_aout = (aout_instance_t *)p_this;
321     struct aout_sys_t *p_sys = p_aout->output.p_sys;
322
323     free( p_sys->p_jack_ports );
324     jack_client_close( p_sys->p_jack_client );
325     free( p_sys );
326 }
327