]> git.sesse.net Git - vlc/blob - modules/access/jack.c
input options whitelisting, step 2 (refs #1371)
[vlc] / modules / access / jack.c
1 /*****************************************************************************
2  * jack.c: JACK audio input module
3  *****************************************************************************
4  * Copyright (C) 2007 the VideoLAN team
5  * Copyright (C) 2007 Société des arts technologiques
6  * Copyright (C) 2007 Savoir-faire Linux
7  *
8  * Authors: Arnaud Sala <arnaud.sala at savoirfairelinux.com>
9  *          Julien Plissonneau Duquene <... at savoirfairelinux.com>
10  *          Pierre-Luc Beaudoin <pierre-luc.beaudoin at savoirfairelinux.com>
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
25  *****************************************************************************/
26
27 /**
28  * \file modules/access/jack.c
29  * \brief JACK audio input functions
30  */
31
32 /*****************************************************************************
33  * Preamble
34  *****************************************************************************/
35
36 #include <vlc/vlc.h>
37 #include <vlc_input.h>
38 #include <vlc_demux.h>
39 #include <vlc_vout.h>
40 #include <vlc_codecs.h>
41 #include <vlc_url.h>
42 #include <vlc_strings.h>
43
44 #include <jack/jack.h>
45 #include <jack/ringbuffer.h>
46
47 #include <errno.h>
48 #include <sys/types.h>
49 #include <unistd.h>
50
51 /*****************************************************************************
52  * Module descriptor
53  *****************************************************************************/
54 static int  Open ( vlc_object_t * );
55 static void Close( vlc_object_t * );
56
57 #define CACHING_TEXT N_("Caching value in ms")
58 #define CACHING_LONGTEXT N_( \
59     "Make VLC buffer audio data capturer from jack for the specified " \
60     "length in milliseconds." )
61 #define PACE_TEXT N_( "Pace" )
62 #define PACE_LONGTEXT N_( \
63     "Read the audio stream at VLC pace rather than Jack pace." )
64 #define AUTO_CONNECT_TEXT N_( "Auto Connection" )
65 #define AUTO_CONNECT_LONGTEXT N_( \
66     "Automatically connect VLC input ports to available output ports." )
67
68 vlc_module_begin();
69      set_description( _("JACK audio input") );
70      set_capability( "access_demux", 0 );
71      set_shortname( _( "JACK Input" ) );
72      set_category( CAT_INPUT );
73      set_subcategory( SUBCAT_INPUT_ACCESS );
74
75      add_integer( "jack-input-caching", DEFAULT_PTS_DELAY / 1000, NULL,
76          CACHING_TEXT, CACHING_LONGTEXT, VLC_TRUE );
77         change_safe();
78      add_bool( "jack-input-use-vlc-pace", VLC_FALSE, NULL,
79          PACE_TEXT, PACE_LONGTEXT, VLC_TRUE );
80         change_safe();
81      add_bool( "jack-input-auto-connect", VLC_FALSE, NULL,
82          PACE_TEXT, PACE_LONGTEXT, VLC_TRUE );
83         change_safe();
84
85      add_shortcut( "jack" );
86      set_callbacks( Open, Close );
87 vlc_module_end();
88
89 /*****************************************************************************
90  * Local prototypes
91  *****************************************************************************/
92
93 struct demux_sys_t
94 {
95     /* Audio properties */
96     vlc_fourcc_t                i_acodec_raw;
97     unsigned int                i_channels;
98     int                         i_sample_rate;
99     int                         i_audio_max_frame_size;
100     int                         i_frequency;
101     block_t                     *p_block_audio;
102     es_out_id_t                 *p_es_audio;
103     date_t                      pts;
104
105     /* Jack properties */
106     jack_client_t               *p_jack_client;
107     jack_port_t                 **pp_jack_port_input;
108     jack_default_audio_sample_t **pp_jack_buffer;
109     jack_ringbuffer_t           *p_jack_ringbuffer;
110     jack_nframes_t              jack_buffer_size;
111     jack_nframes_t              jack_sample_rate;
112     size_t                      jack_sample_size;
113     char                        *psz_ports;
114     char                        **pp_jack_port_table;
115     char                        i_match_ports;
116 };
117
118 static int Demux( demux_t * );
119 static int Control( demux_t *p_demux, int i_query, va_list args );
120
121 static void Parse ( demux_t * );
122 static void Port_finder( demux_t * );
123 static int Process( jack_nframes_t i_frames, void *p_arg );
124
125 static block_t *GrabJack( demux_t * );
126
127 /*****************************************************************************
128  * Open: Connect to the JACK server
129  *****************************************************************************/
130 static int Open( vlc_object_t *p_this )
131 {
132     unsigned int i;
133     demux_t             *p_demux = ( demux_t* )p_this;
134     demux_sys_t         *p_sys;
135     es_format_t         fmt;
136     int i_out_ports = 0;
137
138     p_demux->pf_demux = Demux;
139     p_demux->pf_control = Control;
140
141     /* Allocate structure */
142     p_demux->p_sys = p_sys = calloc( 1, sizeof( demux_sys_t ) );
143     if( p_sys == NULL )
144     {
145         msg_Err( p_demux, "out of memory, cannot allocate structure" );
146         return VLC_ENOMEM;
147     }
148     memset( p_sys, 0, sizeof( demux_sys_t ) );
149
150     /* Parse MRL */
151     Parse( p_demux );
152
153     /* Create var */
154     var_Create( p_demux, "jack-input-caching",
155         VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
156     var_Create( p_demux, "jack-input-use-vlc-pace",
157         VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
158     var_Create( p_demux, "jack-input-auto-connect",
159         VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
160
161     /* JACK connexions */
162     /* define name and connect to jack server */
163     char p_vlc_client_name[32];
164     sprintf( p_vlc_client_name, "vlc-input-%d", getpid() );
165     p_sys->p_jack_client = jack_client_new( p_vlc_client_name );
166     if( p_sys->p_jack_client == NULL )
167     {
168         msg_Err( p_demux, "failed to connect to JACK server" );
169         free( p_sys );
170         return VLC_EGENERIC;
171     }
172
173     /* find some specifics ports if user entered a regexp */
174     if( p_sys->psz_ports)
175     {
176         Port_finder( p_demux );
177         if( p_sys->i_channels == 0 )
178         {
179             p_sys->i_channels = p_sys->i_match_ports;
180         }
181     }
182
183     /* allocate input ports */
184     if( p_sys->i_channels == 0 ) p_sys->i_channels = 2 ; /* default number of port */
185     p_sys->pp_jack_port_input = malloc(
186         p_sys->i_channels * sizeof( jack_port_t* ) );
187     if( p_sys->pp_jack_port_input == NULL )
188     {
189         msg_Err( p_demux, "out of memory, cannot allocate input ports" );
190         return VLC_ENOMEM;
191     }
192
193     /* allocate ringbuffer */
194     /* The length of the ringbuffer is critical, it must be large enought
195        to keep all data between 2 GrabJack() calls.  We assume 1 sec is ok */
196     p_sys->p_jack_ringbuffer = jack_ringbuffer_create( p_sys->i_channels
197          * jack_get_sample_rate( p_sys->p_jack_client )
198          * sizeof( jack_default_audio_sample_t ) );
199     if( p_sys->p_jack_ringbuffer == NULL )
200     {
201         msg_Err( p_demux, "out of memory, cannot allocate ringbuffer" );
202         return VLC_ENOMEM;
203     }
204
205     /* register input ports */
206     for( i = 0; i <  p_sys->i_channels; i++ )
207     {
208         char p_input_name[32];
209         snprintf( p_input_name, 32, "vlc_in_%d", i+1 );
210         p_sys->pp_jack_port_input[i] = jack_port_register(
211             p_sys->p_jack_client, p_input_name, JACK_DEFAULT_AUDIO_TYPE,
212             JackPortIsInput, 0 );
213         if( p_sys->pp_jack_port_input[i] == NULL )
214         {
215             msg_Err( p_demux, "failed to register a JACK port" );
216             if( p_sys->p_jack_client) jack_client_close( p_sys->p_jack_client );
217             if( p_sys->pp_jack_port_input ) free( p_sys->pp_jack_port_input );
218             if( p_sys->p_jack_ringbuffer ) jack_ringbuffer_free( p_sys->p_jack_ringbuffer );
219             if( p_sys->pp_jack_buffer ) free( p_sys->pp_jack_buffer );
220             free( p_sys );
221             return VLC_EGENERIC;
222         }
223     }
224
225     /* allocate buffer for input ports */
226     p_sys->pp_jack_buffer = malloc ( p_sys->i_channels
227         * sizeof( jack_default_audio_sample_t * ) );
228     if( p_sys->pp_jack_buffer == NULL )
229     {
230         msg_Err( p_demux, "out of memory, cannot allocate input buffer" );
231         return VLC_ENOMEM;
232     }
233
234     /* set process callback */
235     jack_set_process_callback( p_sys->p_jack_client, Process, p_demux );
236
237     /* tell jack server we are ready */
238     if ( jack_activate( p_sys->p_jack_client ) )
239     {
240         msg_Err( p_demux, "failed to activate JACK client" );
241         if( p_sys->p_jack_client) jack_client_close( p_sys->p_jack_client );
242         if( p_sys->pp_jack_port_input ) free( p_sys->pp_jack_port_input );
243         if( p_sys->p_jack_ringbuffer ) jack_ringbuffer_free( p_sys->p_jack_ringbuffer );
244         if( p_sys->pp_jack_buffer ) free( p_sys->pp_jack_buffer );
245         free( p_sys );
246         return VLC_EGENERIC;
247     }
248
249     /* connect vlc input to specifics jack output ports if requested */
250    /*  if( var_GetBool( p_demux, "jack-input-auto-connect" ) && p_sys->psz_ports ) */
251     if( p_sys->psz_ports )
252     {
253         int        i_input_ports;
254         int        j;
255  
256     if( p_sys->i_match_ports > 0 )
257         {
258             for( j = 0; j < p_sys->i_match_ports; j++ )
259             {
260                 i_input_ports = j % p_sys->i_channels;
261                 jack_connect( p_sys->p_jack_client, p_sys->pp_jack_port_table[j],
262                     jack_port_name( p_sys->pp_jack_port_input[i_input_ports] ) );
263             }
264         }
265     }
266
267     /* connect vlc input to all jack output ports if requested */
268     if( var_GetBool( p_demux, "jack-input-auto-connect" ) && !p_sys->psz_ports )
269     {
270         int        i_input_ports;
271         int        j;
272         const char **pp_jack_port_output;
273
274         pp_jack_port_output = jack_get_ports( p_sys->p_jack_client, NULL, NULL, JackPortIsOutput );
275
276         while( pp_jack_port_output && pp_jack_port_output[i_out_ports] )
277         {
278             i_out_ports++;
279         }
280         if( i_out_ports > 0 )
281         {
282             for( j = 0; j < i_out_ports; j++ )
283             {
284                 i_input_ports = j % p_sys->i_channels;
285                 jack_connect( p_sys->p_jack_client, pp_jack_port_output[j],
286                     jack_port_name( p_sys->pp_jack_port_input[i_input_ports] ) );
287             }
288         }
289     if( pp_jack_port_output ) free( pp_jack_port_output );
290     }
291
292     /* info about jack server */
293     /* get buffers size */
294     p_sys->jack_buffer_size = jack_get_buffer_size( p_sys->p_jack_client );
295     /* get sample rate */
296     p_sys->jack_sample_rate = jack_get_sample_rate( p_sys->p_jack_client );
297     /* get sample size */
298     p_sys->jack_sample_size = sizeof( jack_default_audio_sample_t );
299
300     /* Define output format */
301     es_format_Init( &fmt, AUDIO_ES, VLC_FOURCC( 'f','l','3','2' ) );
302     fmt.audio.i_channels =  p_sys->i_channels;
303     fmt.audio.i_rate =  p_sys->jack_sample_rate;
304     fmt.audio.i_bitspersample =  p_sys->jack_sample_size * 8;
305     fmt.audio.i_blockalign = fmt.audio.i_bitspersample / 8;
306     fmt.i_bitrate = fmt.audio.i_rate * fmt.audio.i_bitspersample
307         * fmt.audio.i_channels;
308
309     p_sys->p_es_audio = es_out_Add( p_demux->out, &fmt );
310     date_Init( &p_sys->pts, fmt.audio.i_rate, 1 );
311     date_Set( &p_sys->pts, 1 );
312
313     return VLC_SUCCESS;
314 }
315
316
317 /*****************************************************************************
318  * Close: Disconnect from jack server and release associated resources
319  *****************************************************************************/
320 static void Close( vlc_object_t *p_this )
321 {
322     demux_t    *p_demux = ( demux_t* )p_this;
323     demux_sys_t    *p_sys = p_demux->p_sys;
324
325     msg_Dbg( p_demux,"Module unloaded" );
326     if( p_sys->p_block_audio ) block_Release( p_sys->p_block_audio );
327     if( p_sys->p_jack_client ) jack_client_close( p_sys->p_jack_client );
328     if( p_sys->p_jack_ringbuffer ) jack_ringbuffer_free( p_sys->p_jack_ringbuffer );
329     if( p_sys->pp_jack_port_input ) free( p_sys->pp_jack_port_input );
330     if( p_sys->pp_jack_buffer ) free( p_sys->pp_jack_buffer );
331     if( p_sys->pp_jack_port_table ) free( p_sys->pp_jack_port_table );
332     free( p_sys );
333 }
334
335
336 /*****************************************************************************
337  * Control
338  *****************************************************************************/
339 static int Control( demux_t *p_demux, int i_query, va_list args )
340 {
341     vlc_bool_t  *pb;
342     int64_t     *pi64;
343     demux_sys_t *p_sys = p_demux->p_sys;
344
345     switch( i_query )
346     {
347     /* Special for access_demux */
348     case DEMUX_CAN_PAUSE:
349     case DEMUX_CAN_SEEK:
350         pb = (vlc_bool_t *)va_arg( args, vlc_bool_t * );
351         *pb = VLC_TRUE;
352         return VLC_SUCCESS;
353
354     case DEMUX_SET_PAUSE_STATE:
355         return VLC_SUCCESS;
356     case DEMUX_CAN_CONTROL_PACE:
357         pb = ( vlc_bool_t* )va_arg( args, vlc_bool_t * );
358         *pb = var_GetBool( p_demux, "jack-input-use-vlc-pace" );
359         return VLC_SUCCESS;
360
361     case DEMUX_GET_PTS_DELAY:
362         pi64 = ( int64_t* )va_arg( args, int64_t * );
363         *pi64 = ( int64_t )var_GetInteger( p_demux, "jack-input-caching" )
364             * 1000;
365         return VLC_SUCCESS;
366
367     case DEMUX_GET_TIME:
368         pi64 = ( int64_t* )va_arg( args, int64_t * );
369         *pi64 =  date_Get(&p_sys->pts);
370             return VLC_SUCCESS;
371
372     /* TODO implement others */
373     default:
374         return VLC_EGENERIC;
375     }
376
377     return VLC_EGENERIC;
378 }
379
380
381 /*****************************************************************************
382  * Demux
383  *****************************************************************************/
384 static int Demux( demux_t *p_demux )
385 {
386
387     demux_sys_t *p_sys;
388     es_out_id_t  *p_es;
389     block_t *p_block;
390
391     p_sys = p_demux->p_sys;
392     p_es = p_sys->p_es_audio;
393     p_block = GrabJack( p_demux );
394
395     if( p_block )
396     {
397         es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_block->i_pts );
398         es_out_Send( p_demux->out, p_es, p_block );
399     }
400
401     return 1;
402 }
403
404
405 /*****************************************************************************
406  * Process Callback : fill ringbuffer with Jack audio data
407  *****************************************************************************/
408 int Process( jack_nframes_t i_frames, void *p_arg )
409 {
410     demux_t            *p_demux = ( demux_t* )p_arg;
411     demux_sys_t        *p_sys = p_demux->p_sys;
412     unsigned int        i, j;
413     size_t              i_write;
414  
415     /* Get and interlace buffers */
416     for ( i = 0; i < p_sys->i_channels ; i++ )
417     {
418         p_sys->pp_jack_buffer[i] = jack_port_get_buffer(
419             p_sys->pp_jack_port_input[i], i_frames );
420     }
421
422     /* fill ring buffer with signal */
423     for( j = 0; j < i_frames; j++ )
424     {
425         for( i = 0; i <p_sys->i_channels; i++ )
426         {
427             if( jack_ringbuffer_write_space( p_sys->p_jack_ringbuffer ) <
428                 p_sys->jack_sample_size ) {
429                 msg_Err( p_demux, "buffer overflow");
430                 return 0; // buffer overflow
431             }
432             i_write = jack_ringbuffer_write( p_sys->p_jack_ringbuffer,
433                                              ( char * ) (p_sys->pp_jack_buffer[i]+j),
434                                              p_sys->jack_sample_size );
435             if (i_write != p_sys->jack_sample_size ) {
436                 msg_Warn( p_demux, "error writing on ring buffer");
437             }
438         }
439     }
440
441     return 1;
442 }
443
444
445 /*****************************************************************************
446  * GrabJack: grab audio data in the Jack buffer
447  *****************************************************************************/
448 static block_t *GrabJack( demux_t *p_demux )
449 {
450     size_t      i_read;
451     demux_sys_t *p_sys = p_demux->p_sys;
452     block_t     *p_block;
453
454     /* read signal from ring buffer */
455     i_read = jack_ringbuffer_read_space( p_sys->p_jack_ringbuffer );
456
457     if( i_read < 100 ) /* avoid small read */
458     {   /* vlc has too much free time on its hands? */
459         msleep(1000);
460         return NULL;
461     }
462
463     if( p_sys->p_block_audio )
464     {
465         p_block = p_sys->p_block_audio;
466     }
467     else
468     {
469         p_block = block_New( p_demux, i_read );
470     }
471     if( !p_block )
472     {
473         msg_Warn( p_demux, "cannot get block" );
474         return 0;
475     }
476  
477     //Find the previous power of 2, this algo assumes size_t has the same size on all arch
478     i_read >>= 1;
479     i_read--;
480     i_read |= i_read >> 1;
481     i_read |= i_read >> 2;
482     i_read |= i_read >> 4;
483     i_read |= i_read >> 8;
484     i_read |= i_read >> 16;
485     i_read++;
486  
487     i_read = jack_ringbuffer_read( p_sys->p_jack_ringbuffer, ( char * ) p_block->p_buffer, i_read );
488  
489     p_block->i_dts = p_block->i_pts =    date_Increment( &p_sys->pts,
490          i_read/(p_sys->i_channels * p_sys->jack_sample_size) );
491
492     p_sys->p_block_audio = p_block;
493     p_block->i_buffer = i_read;
494     p_sys->p_block_audio = 0;
495  
496     return p_block;
497 }
498
499
500 /*****************************************************************************
501  * Port_finder: compare ports with the regexp entered
502  *****************************************************************************/
503 static void Port_finder( demux_t *p_demux )
504 {
505
506     demux_sys_t *p_sys = p_demux->p_sys;
507     char *psz_expr = p_sys->psz_ports;
508     char *token = NULL;
509     char *state = NULL;
510     char *psz_uri = NULL;
511     const char **pp_jack_port_output = NULL;
512     int i_out_ports = 0;
513     int i_total_out_ports =0;
514     p_sys->pp_jack_port_table = NULL;
515
516     /* parse the ports part of the MRL */
517     for( token = strtok_r( psz_expr, ",", &state ); token;
518             token = strtok_r( NULL, ",", &state ) )
519     {
520         psz_uri = decode_URI_duplicate( token );
521         /* get the ports which match the regexp */
522         pp_jack_port_output = jack_get_ports( p_sys->p_jack_client,
523            psz_uri, NULL, JackPortIsOutput );
524         if( pp_jack_port_output == NULL )
525         {
526             msg_Err( p_demux, "port(s) asked not found:%s", psz_uri );
527             free( pp_jack_port_output );
528         }
529         else
530         {
531             while( pp_jack_port_output && pp_jack_port_output[i_out_ports] )
532             {
533                 i_out_ports++;
534             }
535             /* alloc an array to store all the matched ports */
536             p_sys->pp_jack_port_table = realloc( p_sys->pp_jack_port_table,
537                 (i_out_ports * sizeof( char * ) + i_total_out_ports * sizeof( char * ) ) );
538
539             for(int i=0; i<i_out_ports;i++)
540             {
541                 p_sys->pp_jack_port_table[i_total_out_ports+i] = ( char * ) pp_jack_port_output[i];
542             }
543
544             i_total_out_ports += i_out_ports;
545         }
546     }
547
548     if( pp_jack_port_output ) free( pp_jack_port_output );
549     p_sys->i_match_ports = i_total_out_ports;
550 }
551
552
553 /*****************************************************************************
554  * Parse: Parse the MRL
555  *****************************************************************************/
556 static void Parse( demux_t *p_demux )
557 {
558     demux_sys_t *p_sys = p_demux->p_sys;
559     char *psz_dup = strdup( p_demux->psz_path );
560     char *psz_parser = psz_dup;
561
562     if( !strncmp( psz_parser, "channels=", strlen( "channels=" ) ) )
563     {
564         p_sys->i_channels = abs( strtol( psz_parser + strlen( "channels=" ),
565             &psz_parser, 0 ) );
566     }
567     else if( !strncmp( psz_parser, "ports=", strlen( "ports=" ) ) )
568     {
569         int i_len;
570         psz_parser += strlen( "ports=" );
571         if( strchr( psz_parser, ':' ) )
572         {
573             i_len = strchr( psz_parser, ':' ) - psz_parser;
574         }
575         else
576         {
577             i_len = strlen( psz_parser );
578         }
579         p_sys->psz_ports = strndup( psz_parser, i_len );
580         psz_parser += i_len;
581     }
582     else
583     {
584         msg_Warn( p_demux, "unknown option" );
585     }
586
587     while( *psz_parser && *psz_parser != ':' )
588     {
589         psz_parser++;
590     }
591
592     if( *psz_parser == ':' )
593     {
594         for( ;; )
595         {
596             *psz_parser++ = '\0';
597             if( !strncmp( psz_parser, "channels=", strlen( "channels=" ) ) )
598             {
599                 p_sys->i_channels = abs( strtol(
600                     psz_parser + strlen( "channels=" ), &psz_parser, 0 ) );
601             }
602             else if( !strncmp( psz_parser, "ports=", strlen( "ports=" ) ) )
603             {
604                 int i_len;
605                 psz_parser += strlen( "ports=" );
606                 if( strchr( psz_parser, ':' ) )
607                 {
608                     i_len = strchr( psz_parser, ':' ) - psz_parser;
609                 }
610                 else
611                 {
612                     i_len = strlen( psz_parser );
613                 }
614                 p_sys->psz_ports = strndup( psz_parser, i_len );
615                 psz_parser += i_len;
616             }
617             else
618             {
619                 msg_Warn( p_demux, "unknown option" );
620             }
621             while( *psz_parser && *psz_parser != ':' )
622             {
623                 psz_parser++;
624             }
625
626             if( *psz_parser == '\0' )
627             {
628                 break;
629             }
630         }
631     }
632 }
633