X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Faccess%2Fjack.c;h=a8fcec5c9e92e875688819f1242f0d3cf690d4f1;hb=c22f2d8b0115d2d1c65eb2af66f2e50990985eff;hp=fc0780fd62212eb0751880038ed9cfa6c1bbfb42;hpb=e40d134c69b144327fd1d2001e8b85640f5c7cb9;p=vlc diff --git a/modules/access/jack.c b/modules/access/jack.c index fc0780fd62..a8fcec5c9e 100644 --- a/modules/access/jack.c +++ b/modules/access/jack.c @@ -1,11 +1,13 @@ /***************************************************************************** * jack.c: JACK audio input module ***************************************************************************** - * Copyright (C) 2007 the VideoLAN team + * Copyright (C) 2007-2008 the VideoLAN team * Copyright (C) 2007 Société des arts technologiques + * Copyright (C) 2007 Savoir-faire Linux * * Authors: Arnaud Sala * Julien Plissonneau Duquene <... at savoirfairelinux.com> + * Pierre-Luc Beaudoin * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -30,12 +32,15 @@ /***************************************************************************** * Preamble *****************************************************************************/ -#include -#include +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include #include #include -#include #include #include #include @@ -43,8 +48,8 @@ #include #include -#include /* mlock() */ -#include +#include +#include /***************************************************************************** * Module descriptor @@ -54,7 +59,7 @@ static void Close( vlc_object_t * ); #define CACHING_TEXT N_("Caching value in ms") #define CACHING_LONGTEXT N_( \ - "Make VLC buffer audio data capturer from jack for the specified " \ + "Make VLC buffer audio data captured from jack for the specified " \ "length in milliseconds." ) #define PACE_TEXT N_( "Pace" ) #define PACE_LONGTEXT N_( \ @@ -63,23 +68,23 @@ static void Close( vlc_object_t * ); #define AUTO_CONNECT_LONGTEXT N_( \ "Automatically connect VLC input ports to available output ports." ) -vlc_module_begin(); - set_description( _("JACK audio input") ); - set_capability( "access_demux", 0 ); - set_shortname( _( "JACK Input" ) ); - set_category( CAT_INPUT ); - set_subcategory( SUBCAT_INPUT_ACCESS ); +vlc_module_begin () + set_description( N_("JACK audio input") ) + set_capability( "access_demux", 0 ) + set_shortname( N_( "JACK Input" ) ) + set_category( CAT_INPUT ) + set_subcategory( SUBCAT_INPUT_ACCESS ) add_integer( "jack-input-caching", DEFAULT_PTS_DELAY / 1000, NULL, - CACHING_TEXT, CACHING_LONGTEXT, VLC_TRUE ); - add_bool( "jack-input-use-vlc-pace", VLC_FALSE, NULL, - PACE_TEXT, PACE_LONGTEXT, VLC_TRUE ); - add_bool( "jack-input-auto-connect", VLC_FALSE, NULL, - PACE_TEXT, PACE_LONGTEXT, VLC_TRUE ); + CACHING_TEXT, CACHING_LONGTEXT, true ) + add_bool( "jack-input-use-vlc-pace", false, NULL, + PACE_TEXT, PACE_LONGTEXT, true ) + add_bool( "jack-input-auto-connect", false, NULL, + AUTO_CONNECT_TEXT, AUTO_CONNECT_LONGTEXT, true ) - add_shortcut( "jack" ); - set_callbacks( Open, Close ); -vlc_module_end(); + add_shortcut( "jack" ) + set_callbacks( Open, Close ) +vlc_module_end () /***************************************************************************** * Local prototypes @@ -105,12 +110,16 @@ struct demux_sys_t jack_nframes_t jack_buffer_size; jack_nframes_t jack_sample_rate; size_t jack_sample_size; + char *psz_ports; + char **pp_jack_port_table; + char i_match_ports; }; static int Demux( demux_t * ); static int Control( demux_t *p_demux, int i_query, va_list args ); static void Parse ( demux_t * ); +static void Port_finder( demux_t * ); static int Process( jack_nframes_t i_frames, void *p_arg ); static block_t *GrabJack( demux_t * ); @@ -124,17 +133,15 @@ static int Open( vlc_object_t *p_this ) demux_t *p_demux = ( demux_t* )p_this; demux_sys_t *p_sys; es_format_t fmt; + int i_out_ports = 0; + p_demux->pf_demux = Demux; p_demux->pf_control = Control; /* Allocate structure */ p_demux->p_sys = p_sys = calloc( 1, sizeof( demux_sys_t ) ); - if( p_sys == NULL ) - { - msg_Err( p_demux, "out of memory, cannot allocate structure" ); + if( !p_sys ) return VLC_ENOMEM; - } - memset( p_sys, 0, sizeof( demux_sys_t ) ); /* Parse MRL */ Parse( p_demux ); @@ -159,24 +166,38 @@ static int Open( vlc_object_t *p_this ) return VLC_EGENERIC; } + /* find some specifics ports if user entered a regexp */ + if( p_sys->psz_ports ) + { + Port_finder( p_demux ); + if( p_sys->i_channels == 0 ) + { + p_sys->i_channels = p_sys->i_match_ports; + } + } + /* allocate input ports */ - if( p_sys->i_channels == 0 || p_sys->i_channels > 8 ) - p_sys->i_channels = 2 ; /* default number of port */ + if( p_sys->i_channels == 0 ) p_sys->i_channels = 2 ; /* default number of port */ p_sys->pp_jack_port_input = malloc( p_sys->i_channels * sizeof( jack_port_t* ) ); if( p_sys->pp_jack_port_input == NULL ) { - msg_Err( p_demux, "out of memory, cannot allocate input ports" ); + jack_client_close( p_sys->p_jack_client ); + free( p_sys ); return VLC_ENOMEM; } /* allocate ringbuffer */ + /* The length of the ringbuffer is critical, it must be large enought + to keep all data between 2 GrabJack() calls. We assume 1 sec is ok */ p_sys->p_jack_ringbuffer = jack_ringbuffer_create( p_sys->i_channels - * jack_get_buffer_size( p_sys->p_jack_client ) - * sizeof( jack_default_audio_sample_t ) ); + * jack_get_sample_rate( p_sys->p_jack_client ) + * sizeof( jack_default_audio_sample_t ) ); if( p_sys->p_jack_ringbuffer == NULL ) { - msg_Err( p_demux, "out of memory, cannot allocate ringbuffer" ); + free( p_sys->pp_jack_port_input ); + jack_client_close( p_sys->p_jack_client ); + free( p_sys ); return VLC_ENOMEM; } @@ -191,10 +212,9 @@ static int Open( vlc_object_t *p_this ) if( p_sys->pp_jack_port_input[i] == NULL ) { msg_Err( p_demux, "failed to register a JACK port" ); - if( p_sys->p_jack_client) jack_client_close( p_sys->p_jack_client ); - if( p_sys->pp_jack_port_input ) free( p_sys->pp_jack_port_input ); - if( p_sys->p_jack_ringbuffer ) jack_ringbuffer_free( p_sys->p_jack_ringbuffer ); - if( p_sys->pp_jack_buffer ) free( p_sys->pp_jack_buffer ); + jack_ringbuffer_free( p_sys->p_jack_ringbuffer ); + free( p_sys->pp_jack_port_input ); + jack_client_close( p_sys->p_jack_client ); free( p_sys ); return VLC_EGENERIC; } @@ -205,7 +225,12 @@ static int Open( vlc_object_t *p_this ) * sizeof( jack_default_audio_sample_t * ) ); if( p_sys->pp_jack_buffer == NULL ) { - msg_Err( p_demux, "out of memory, cannot allocate input buffer" ); + for( i = 0; i < p_sys->i_channels; i++ ) + jack_port_unregister( p_sys->p_jack_client, p_sys->pp_jack_port_input[i] ); + jack_ringbuffer_free( p_sys->p_jack_ringbuffer ); + free( p_sys->pp_jack_port_input ); + jack_client_close( p_sys->p_jack_client ); + free( p_sys ); return VLC_ENOMEM; } @@ -216,23 +241,42 @@ static int Open( vlc_object_t *p_this ) if ( jack_activate( p_sys->p_jack_client ) ) { msg_Err( p_demux, "failed to activate JACK client" ); - if( p_sys->p_jack_client) jack_client_close( p_sys->p_jack_client ); - if( p_sys->pp_jack_port_input ) free( p_sys->pp_jack_port_input ); - if( p_sys->p_jack_ringbuffer ) jack_ringbuffer_free( p_sys->p_jack_ringbuffer ); - if( p_sys->pp_jack_buffer ) free( p_sys->pp_jack_buffer ); + free( p_sys->pp_jack_buffer ); + for( i = 0; i < p_sys->i_channels; i++ ) + jack_port_unregister( p_sys->p_jack_client, p_sys->pp_jack_port_input[i] ); + jack_ringbuffer_free( p_sys->p_jack_ringbuffer ); + free( p_sys->pp_jack_port_input ); + jack_client_close( p_sys->p_jack_client ); free( p_sys ); return VLC_EGENERIC; } - /* connect vlc input to jack output ports if requested */ - if( var_GetBool( p_demux, "jack-input-auto-connect" ) ) + /* connect vlc input to specifics jack output ports if requested */ + /* if( var_GetBool( p_demux, "jack-input-auto-connect" ) && p_sys->psz_ports ) */ + if( p_sys->psz_ports ) { - const char **pp_jack_port_output; - int i_out_ports = 0; - int i_in; + int i_input_ports; int j; - pp_jack_port_output = jack_get_ports( p_sys->p_jack_client, NULL, NULL, - JackPortIsOutput ); + + if( p_sys->i_match_ports > 0 ) + { + for( j = 0; j < p_sys->i_match_ports; j++ ) + { + i_input_ports = j % p_sys->i_channels; + jack_connect( p_sys->p_jack_client, p_sys->pp_jack_port_table[j], + jack_port_name( p_sys->pp_jack_port_input[i_input_ports] ) ); + } + } + } + + /* connect vlc input to all jack output ports if requested */ + if( var_GetBool( p_demux, "jack-input-auto-connect" ) && !p_sys->psz_ports ) + { + int i_input_ports; + int j; + const char **pp_jack_port_output; + + pp_jack_port_output = jack_get_ports( p_sys->p_jack_client, NULL, NULL, JackPortIsOutput ); while( pp_jack_port_output && pp_jack_port_output[i_out_ports] ) { @@ -242,12 +286,12 @@ static int Open( vlc_object_t *p_this ) { for( j = 0; j < i_out_ports; j++ ) { - i_in = j % p_sys->i_channels; + i_input_ports = j % p_sys->i_channels; jack_connect( p_sys->p_jack_client, pp_jack_port_output[j], - jack_port_name( p_sys->pp_jack_port_input[i_in] ) ); + jack_port_name( p_sys->pp_jack_port_input[i_input_ports] ) ); } } - if( pp_jack_port_output ) free( pp_jack_port_output ); + free( pp_jack_port_output ); } /* info about jack server */ @@ -259,7 +303,7 @@ static int Open( vlc_object_t *p_this ) p_sys->jack_sample_size = sizeof( jack_default_audio_sample_t ); /* Define output format */ - es_format_Init( &fmt, AUDIO_ES, VLC_FOURCC( 'f','l','3','2' ) ); + es_format_Init( &fmt, AUDIO_ES, VLC_CODEC_FL32 ); fmt.audio.i_channels = p_sys->i_channels; fmt.audio.i_rate = p_sys->jack_sample_rate; fmt.audio.i_bitspersample = p_sys->jack_sample_size * 8; @@ -287,8 +331,9 @@ static void Close( vlc_object_t *p_this ) if( p_sys->p_block_audio ) block_Release( p_sys->p_block_audio ); if( p_sys->p_jack_client ) jack_client_close( p_sys->p_jack_client ); if( p_sys->p_jack_ringbuffer ) jack_ringbuffer_free( p_sys->p_jack_ringbuffer ); - if( p_sys->pp_jack_port_input ) free( p_sys->pp_jack_port_input ); - if( p_sys->pp_jack_buffer ) free( p_sys->pp_jack_buffer ); + free( p_sys->pp_jack_port_input ); + free( p_sys->pp_jack_buffer ); + free( p_sys->pp_jack_port_table ); free( p_sys ); } @@ -298,7 +343,7 @@ static void Close( vlc_object_t *p_this ) *****************************************************************************/ static int Control( demux_t *p_demux, int i_query, va_list args ) { - vlc_bool_t *pb; + bool *pb; int64_t *pi64; demux_sys_t *p_sys = p_demux->p_sys; @@ -306,10 +351,15 @@ static int Control( demux_t *p_demux, int i_query, va_list args ) { /* Special for access_demux */ case DEMUX_CAN_PAUSE: + case DEMUX_CAN_SEEK: + pb = (bool *)va_arg( args, bool * ); + *pb = true; + return VLC_SUCCESS; + case DEMUX_SET_PAUSE_STATE: return VLC_SUCCESS; case DEMUX_CAN_CONTROL_PACE: - pb = ( vlc_bool_t* )va_arg( args, vlc_bool_t * ); + pb = ( bool* )va_arg( args, bool * ); *pb = var_GetBool( p_demux, "jack-input-use-vlc-pace" ); return VLC_SUCCESS; @@ -365,8 +415,8 @@ int Process( jack_nframes_t i_frames, void *p_arg ) demux_t *p_demux = ( demux_t* )p_arg; demux_sys_t *p_sys = p_demux->p_sys; unsigned int i, j; - size_t i_write; - + size_t i_write; + /* Get and interlace buffers */ for ( i = 0; i < p_sys->i_channels ; i++ ) { @@ -375,18 +425,25 @@ int Process( jack_nframes_t i_frames, void *p_arg ) } /* fill ring buffer with signal */ - for( j = 0; j < p_sys->jack_buffer_size; j++ ) + for( j = 0; j < i_frames; j++ ) { for( i = 0; i i_channels; i++ ) { - if( jack_ringbuffer_write_space( p_sys->p_jack_ringbuffer ) - < p_sys->jack_sample_size ) return 1; // buffer overflow + if( jack_ringbuffer_write_space( p_sys->p_jack_ringbuffer ) < + p_sys->jack_sample_size ) { + msg_Err( p_demux, "buffer overflow"); + return 0; // buffer overflow + } i_write = jack_ringbuffer_write( p_sys->p_jack_ringbuffer, - p_sys->pp_jack_buffer[i]+j, p_sys->jack_sample_size ); + ( char * ) (p_sys->pp_jack_buffer[i]+j), + p_sys->jack_sample_size ); + if (i_write != p_sys->jack_sample_size ) { + msg_Warn( p_demux, "error writing on ring buffer"); + } } } - return 1; + return 0; } @@ -404,6 +461,8 @@ static block_t *GrabJack( demux_t *p_demux ) if( i_read < 100 ) /* avoid small read */ { /* vlc has too much free time on its hands? */ +#undef msleep +#warning Hmm.... looks wrong msleep(1000); return NULL; } @@ -421,17 +480,80 @@ static block_t *GrabJack( demux_t *p_demux ) msg_Warn( p_demux, "cannot get block" ); return 0; } + + //Find the previous power of 2, this algo assumes size_t has the same size on all arch + i_read >>= 1; + i_read--; + i_read |= i_read >> 1; + i_read |= i_read >> 2; + i_read |= i_read >> 4; + i_read |= i_read >> 8; + i_read |= i_read >> 16; + i_read++; + + i_read = jack_ringbuffer_read( p_sys->p_jack_ringbuffer, ( char * ) p_block->p_buffer, i_read ); + + p_block->i_dts = p_block->i_pts = date_Increment( &p_sys->pts, + i_read/(p_sys->i_channels * p_sys->jack_sample_size) ); p_sys->p_block_audio = p_block; p_block->i_buffer = i_read; p_sys->p_block_audio = 0; + + return p_block; +} - jack_ringbuffer_read( p_sys->p_jack_ringbuffer, p_block->p_buffer, i_read ); - p_block->i_dts = p_block->i_pts = date_Increment( - &p_sys->pts, i_read/(p_sys->i_channels * p_sys->jack_sample_size) ); +/***************************************************************************** + * Port_finder: compare ports with the regexp entered + *****************************************************************************/ +static void Port_finder( demux_t *p_demux ) +{ - return p_block; + demux_sys_t *p_sys = p_demux->p_sys; + char *psz_expr = p_sys->psz_ports; + char *token = NULL; + char *state = NULL; + char *psz_uri = NULL; + const char **pp_jack_port_output = NULL; + int i_out_ports = 0; + int i_total_out_ports =0; + p_sys->pp_jack_port_table = NULL; + + /* parse the ports part of the MRL */ + for( token = strtok_r( psz_expr, ",", &state ); token; + token = strtok_r( NULL, ",", &state ) ) + { + psz_uri = decode_URI_duplicate( token ); + /* get the ports which match the regexp */ + pp_jack_port_output = jack_get_ports( p_sys->p_jack_client, + psz_uri, NULL, JackPortIsOutput ); + if( pp_jack_port_output == NULL ) + { + msg_Err( p_demux, "port(s) asked not found:%s", psz_uri ); + free( pp_jack_port_output ); + } + else + { + while( pp_jack_port_output && pp_jack_port_output[i_out_ports] ) + { + i_out_ports++; + } + /* alloc an array to store all the matched ports */ + p_sys->pp_jack_port_table = xrealloc( p_sys->pp_jack_port_table, + (i_out_ports * sizeof( char * ) + i_total_out_ports * sizeof( char * ) ) ); + + for(int i=0; ipp_jack_port_table[i_total_out_ports+i] = ( char * ) pp_jack_port_output[i]; + } + + i_total_out_ports += i_out_ports; + } + } + + free( pp_jack_port_output ); + p_sys->i_match_ports = i_total_out_ports; } @@ -449,6 +571,21 @@ static void Parse( demux_t *p_demux ) p_sys->i_channels = abs( strtol( psz_parser + strlen( "channels=" ), &psz_parser, 0 ) ); } + else if( !strncmp( psz_parser, "ports=", strlen( "ports=" ) ) ) + { + int i_len; + psz_parser += strlen( "ports=" ); + if( strchr( psz_parser, ':' ) ) + { + i_len = strchr( psz_parser, ':' ) - psz_parser; + } + else + { + i_len = strlen( psz_parser ); + } + p_sys->psz_ports = strndup( psz_parser, i_len ); + psz_parser += i_len; + } else { msg_Warn( p_demux, "unknown option" ); @@ -469,6 +606,21 @@ static void Parse( demux_t *p_demux ) p_sys->i_channels = abs( strtol( psz_parser + strlen( "channels=" ), &psz_parser, 0 ) ); } + else if( !strncmp( psz_parser, "ports=", strlen( "ports=" ) ) ) + { + int i_len; + psz_parser += strlen( "ports=" ); + if( strchr( psz_parser, ':' ) ) + { + i_len = strchr( psz_parser, ':' ) - psz_parser; + } + else + { + i_len = strlen( psz_parser ); + } + p_sys->psz_ports = strndup( psz_parser, i_len ); + psz_parser += i_len; + } else { msg_Warn( p_demux, "unknown option" );