From 31439d7a63b9405d551c527fda2ba330ee31c5bd Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Kempf Date: Wed, 25 Apr 2007 22:00:27 +0000 Subject: [PATCH] Jack patch by Jon Griffiths, fix crashes, improve debuging and use regexps. --- modules/audio_output/jack.c | 222 ++++++++++++++++++------------------ 1 file changed, 114 insertions(+), 108 deletions(-) diff --git a/modules/audio_output/jack.c b/modules/audio_output/jack.c index 9e006cbae3..a1a319f493 100644 --- a/modules/audio_output/jack.c +++ b/modules/audio_output/jack.c @@ -4,7 +4,7 @@ * Copyright (C) 2006 the VideoLAN team * $Id$ * - * Authors: Cyril Deguet + * Authors: Cyril Deguet * Jon Griffiths * * This program is free software; you can redistribute it and/or modify @@ -37,6 +37,8 @@ #include +typedef jack_default_audio_sample_t jack_sample_t; + /***************************************************************************** * aout_sys_t: JACK audio output method descriptor ***************************************************************************** @@ -45,9 +47,10 @@ *****************************************************************************/ struct aout_sys_t { - jack_client_t *p_jack_client; - jack_port_t **p_jack_ports; - unsigned int i_channels; + jack_client_t *p_jack_client; + jack_port_t **p_jack_ports; + jack_sample_t **p_jack_buffers; + unsigned int i_channels; }; /***************************************************************************** @@ -56,19 +59,19 @@ struct aout_sys_t static int Open ( vlc_object_t * ); static void Close ( vlc_object_t * ); static void Play ( aout_instance_t * ); -static int Process ( jack_nframes_t i_frames, void *p_arg ); +static int Process ( jack_nframes_t i_frames, void *p_arg ); #define AUTO_CONNECT_OPTION "jack-auto-connect" -#define AUTO_CONNECT_TEXT N_("Automatically connect to input devices") +#define AUTO_CONNECT_TEXT N_("Automatically connect to writable clients") #define AUTO_CONNECT_LONGTEXT N_( \ - "If enabled, this option will automatically connect output to the " \ - "first JACK inputs found." ) + "If enabled, this option will automatically connect sound output to the " \ + "first writable JACK clients found." ) -#define CONNECT_MATCH_OPTION "jack-connect-match" -#define CONNECT_MATCH_TEXT N_("Connect to outputs beginning with") -#define CONNECT_MATCH_LONGTEXT N_( \ - "If automatic connection is enabled, only JACK inputs whose names " \ - "begin with this prefix will be considered for connection." ) +#define CONNECT_REGEX_OPTION "jack-connect-regex" +#define CONNECT_REGEX_TEXT N_("Connect to clients matching") +#define CONNECT_REGEX_LONGTEXT N_( \ + "If automatic connection is enabled, only JACK clients whose names " \ + "match this regular expression will be considered for connection." ) /***************************************************************************** * Module descriptor @@ -81,8 +84,8 @@ vlc_module_begin(); set_subcategory( SUBCAT_AUDIO_AOUT ); add_bool( AUTO_CONNECT_OPTION, 0, NULL, AUTO_CONNECT_TEXT, AUTO_CONNECT_LONGTEXT, VLC_TRUE ); - add_string( CONNECT_MATCH_OPTION, NULL, NULL, CONNECT_MATCH_TEXT, - CONNECT_MATCH_LONGTEXT, VLC_TRUE ); + add_string( CONNECT_REGEX_OPTION, NULL, NULL, CONNECT_REGEX_TEXT, + CONNECT_REGEX_LONGTEXT, VLC_TRUE ); set_callbacks( Open, Close ); vlc_module_end(); @@ -91,15 +94,15 @@ vlc_module_end(); *****************************************************************************/ static int Open( vlc_object_t *p_this ) { + char psz_name[32]; aout_instance_t *p_aout = (aout_instance_t *)p_this; struct aout_sys_t *p_sys = NULL; - char **pp_match_ports = NULL; - char *psz_prefix = NULL; int status = VLC_SUCCESS; unsigned int i; + int i_error; /* Allocate structure */ - p_sys = malloc( sizeof( aout_sys_t ) ); + p_sys = calloc( 1, sizeof( aout_sys_t ) ); if( p_sys == NULL ) { msg_Err( p_aout, "out of memory" ); @@ -109,7 +112,9 @@ static int Open( vlc_object_t *p_this ) p_aout->output.p_sys = p_sys; /* Connect to the JACK server */ - p_sys->p_jack_client = jack_client_new( "vlc" ); + snprintf( psz_name, sizeof(psz_name), "vlc_%d", getpid()); + psz_name[sizeof(psz_name) - 1] = '\0'; + p_sys->p_jack_client = jack_client_new( psz_name ); if( p_sys->p_jack_client == NULL ) { msg_Err( p_aout, "failed to connect to JACK server" ); @@ -131,7 +136,8 @@ static int Open( vlc_object_t *p_this ) p_sys->i_channels = aout_FormatNbChannels( &p_aout->output.output ); - p_sys->p_jack_ports = malloc( p_sys->i_channels * sizeof(jack_port_t *) ); + p_sys->p_jack_ports = malloc( p_sys->i_channels * + sizeof(jack_port_t *) ); if( p_sys->p_jack_ports == NULL ) { msg_Err( p_aout, "out of memory" ); @@ -139,13 +145,22 @@ static int Open( vlc_object_t *p_this ) goto error_out; } + p_sys->p_jack_buffers = malloc( p_sys->i_channels * + sizeof(jack_sample_t *) ); + if( p_sys->p_jack_buffers == NULL ) + { + msg_Err( p_aout, "out of memory" ); + status = VLC_ENOMEM; + goto error_out; + } + /* Create the output ports */ for( i = 0; i < p_sys->i_channels; i++ ) { - char p_name[32]; - snprintf( p_name, 32, "out_%d", i + 1); + snprintf( psz_name, sizeof(psz_name), "out_%d", i + 1); + psz_name[sizeof(psz_name) - 1] = '\0'; p_sys->p_jack_ports[i] = jack_port_register( p_sys->p_jack_client, - p_name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0 ); + psz_name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0 ); if( p_sys->p_jack_ports[i] == NULL ) { @@ -156,10 +171,10 @@ static int Open( vlc_object_t *p_this ) } /* Tell the JACK server we are ready */ - if( jack_activate( p_sys->p_jack_client ) ) + i_error = jack_activate( p_sys->p_jack_client ); + if( i_error ) { - msg_Err( p_aout, "failed to activate JACK client" ); - jack_client_close( p_sys->p_jack_client ); + msg_Err( p_aout, "failed to activate JACK client (error %d)", i_error ); status = VLC_EGENERIC; goto error_out; } @@ -167,70 +182,40 @@ static int Open( vlc_object_t *p_this ) /* Auto connect ports if we were asked to */ if( config_GetInt( p_aout, AUTO_CONNECT_OPTION ) ) { - unsigned int i_in_ports, i_prefix_len; - const char **pp_in_ports; - - pp_in_ports = jack_get_ports( p_sys->p_jack_client, NULL, NULL, - JackPortIsInput ); - psz_prefix = config_GetPsz( p_aout, CONNECT_MATCH_OPTION ); - i_prefix_len = psz_prefix ? strlen(psz_prefix) : 0; - - /* Find JACK input ports to connect to */ - i = 0; + unsigned int i_in_ports; + char *psz_regex = config_GetPsz( p_aout, CONNECT_REGEX_OPTION ); + const char **pp_in_ports = jack_get_ports( p_sys->p_jack_client, + psz_regex, NULL, + JackPortIsInput ); + /* Count the number of returned ports */ i_in_ports = 0; - while( pp_in_ports && pp_in_ports[i] ) + while( pp_in_ports && pp_in_ports[i_in_ports] ) { - if( !psz_prefix || - !strncmp(psz_prefix, pp_in_ports[i], i_prefix_len) ) - { - i_in_ports++; /* Found one */ - } - i++; + i_in_ports++; } - /* Connect the output ports to input ports */ - if( i_in_ports > 0 ) + /* Tie the output ports to JACK input ports */ + for( i = 0; i_in_ports > 0 && i < p_sys->i_channels; i++ ) { - pp_match_ports = malloc( i_in_ports * sizeof(char*) ); - if( pp_match_ports == NULL ) - { - msg_Err( p_aout, "out of memory" ); - status = VLC_ENOMEM; - goto error_out; - } + const char* psz_in = pp_in_ports[i % i_in_ports]; + const char* psz_out = jack_port_name( p_sys->p_jack_ports[i] ); - /* populate list of matching ports */ - i = 0; - i_in_ports = 0; - while( pp_in_ports[i] ) + i_error = jack_connect( p_sys->p_jack_client, psz_out, psz_in ); + if( i_error ) { - if( !psz_prefix || - !strncmp(psz_prefix, pp_in_ports[i], i_prefix_len) ) - { - pp_match_ports[i_in_ports] = pp_in_ports[i]; - i_in_ports++; /* Found one */ - } - i++; + msg_Err( p_aout, "failed to connect port %s to port %s (error %d)", + psz_out, psz_in, i_error ); } - - /* Tie the output ports to JACK input ports */ - for( i = 0; i < p_sys->i_channels; i++ ) + else { - const char* psz_in = pp_match_ports[i % i_in_ports]; - const char* psz_out = jack_port_name( p_sys->p_jack_ports[i] ); - - if( jack_connect( p_sys->p_jack_client, psz_out, psz_in) ) - { - msg_Err( p_aout, "failed to connect port %s to port %s", - psz_out, psz_in ); - } - else - { - msg_Dbg( p_aout, "connecting port %s to port %s", - psz_out, psz_in ); - } + msg_Dbg( p_aout, "connecting port %s to port %s", + psz_out, psz_in ); } } + if( pp_in_ports ) + { + free( pp_in_ports ); + } } msg_Dbg( p_aout, "JACK audio output initialized (%d channels, buffer " @@ -238,19 +223,22 @@ static int Open( vlc_object_t *p_this ) p_aout->output.i_nb_samples, p_aout->output.output.i_rate ); error_out: - /* Clean up */ - if( psz_prefix ) - free( psz_prefix ); - - if( pp_match_ports ) - free( pp_match_ports ); - + /* Clean up, if an error occurred */ if( status != VLC_SUCCESS && p_sys != NULL) { - if( p_sys->p_jack_ports ) - free( p_sys->p_jack_ports ); if( p_sys->p_jack_client ) + { + jack_deactivate( p_sys->p_jack_client ); jack_client_close( p_sys->p_jack_client ); + } + if( p_sys->p_jack_ports ) + { + free( p_sys->p_jack_ports ); + } + if( p_sys->p_jack_buffers ) + { + free( p_sys->p_jack_buffers ); + } free( p_sys ); } return status; @@ -262,36 +250,44 @@ error_out: *****************************************************************************/ int Process( jack_nframes_t i_frames, void *p_arg ) { - aout_buffer_t *p_buffer; - jack_default_audio_sample_t *p_jack_buffer; unsigned int i, j, i_nb_samples = 0; aout_instance_t *p_aout = (aout_instance_t*) p_arg; - unsigned int i_nb_channels = p_aout->output.p_sys->i_channels; + struct aout_sys_t *p_sys = p_aout->output.p_sys; + jack_sample_t *p_src = NULL; /* Get the next audio data buffer */ - p_buffer = aout_FifoPop( p_aout, &p_aout->output.fifo ); - - if( p_buffer ) + aout_buffer_t *p_buffer = aout_FifoPop( p_aout, &p_aout->output.fifo ); + if( p_buffer != NULL ) { + p_src = (jack_sample_t *)p_buffer->p_buffer; i_nb_samples = p_buffer->i_nb_samples; } - for( i = 0; i < i_nb_channels; i++ ) + /* Get the JACK buffers to write to */ + for( i = 0; i < p_sys->i_channels; i++ ) { - /* Get an output buffer from JACK */ - p_jack_buffer = jack_port_get_buffer( - p_aout->output.p_sys->p_jack_ports[i], i_frames ); + p_sys->p_jack_buffers[i] = jack_port_get_buffer( p_sys->p_jack_ports[i], + i_frames ); + } - /* Fill the buffer with audio data */ - for( j = 0; j < i_nb_samples; j++ ) + /* Copy in the audio data */ + for( j = 0; j < i_nb_samples; j++ ) + { + for( i = 0; i < p_sys->i_channels; i++ ) { - p_jack_buffer[j] = ((float*)p_buffer->p_buffer)[i_nb_channels*j+i]; + jack_sample_t *p_dst = p_sys->p_jack_buffers[i]; + p_dst[j] = *p_src; + p_src++; } - if( i_nb_samples < i_frames ) + } + + /* Fill any remaining buffer with silence */ + if( i_nb_samples < i_frames ) + { + for( i = 0; i < p_sys->i_channels; i++ ) { - memset( p_jack_buffer + i_nb_samples, 0, - sizeof( jack_default_audio_sample_t ) * - (i_frames - i_nb_samples) ); + memset( p_sys->p_jack_buffers[i] + i_nb_samples, 0, + sizeof( jack_sample_t ) * (i_frames - i_nb_samples) ); } } @@ -299,7 +295,6 @@ int Process( jack_nframes_t i_frames, void *p_arg ) { aout_BufferFree( p_buffer ); } - return 0; } @@ -317,11 +312,22 @@ static void Play( aout_instance_t *p_aout ) *****************************************************************************/ static void Close( vlc_object_t *p_this ) { + int i_error; aout_instance_t *p_aout = (aout_instance_t *)p_this; struct aout_sys_t *p_sys = p_aout->output.p_sys; + i_error = jack_deactivate( p_sys->p_jack_client ); + if( i_error ) + { + msg_Err( p_aout, "jack_deactivate failed (error %d)", i_error ); + } + + i_error = jack_client_close( p_sys->p_jack_client ); + if( i_error ) + { + msg_Err( p_aout, "jack_client_close failed (error %d)", i_error ); + } free( p_sys->p_jack_ports ); - jack_client_close( p_sys->p_jack_client ); + free( p_sys->p_jack_buffers ); free( p_sys ); } - -- 2.39.2