Commit 31439d7a authored by Jean-Baptiste Kempf's avatar Jean-Baptiste Kempf

Jack patch by Jon Griffiths, fix crashes, improve debuging and use regexps.

parent 9397093e
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* Copyright (C) 2006 the VideoLAN team * Copyright (C) 2006 the VideoLAN team
* $Id$ * $Id$
* *
* Authors: Cyril Deguet <asmax@videolan.org> * Authors: Cyril Deguet <asmax _at_ videolan.org>
* Jon Griffiths <jon_p_griffiths _At_ yahoo _DOT_ com> * Jon Griffiths <jon_p_griffiths _At_ yahoo _DOT_ com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -37,6 +37,8 @@ ...@@ -37,6 +37,8 @@
#include <jack/jack.h> #include <jack/jack.h>
typedef jack_default_audio_sample_t jack_sample_t;
/***************************************************************************** /*****************************************************************************
* aout_sys_t: JACK audio output method descriptor * aout_sys_t: JACK audio output method descriptor
***************************************************************************** *****************************************************************************
...@@ -47,6 +49,7 @@ struct aout_sys_t ...@@ -47,6 +49,7 @@ struct aout_sys_t
{ {
jack_client_t *p_jack_client; jack_client_t *p_jack_client;
jack_port_t **p_jack_ports; jack_port_t **p_jack_ports;
jack_sample_t **p_jack_buffers;
unsigned int i_channels; unsigned int i_channels;
}; };
...@@ -59,16 +62,16 @@ static void Play ( aout_instance_t * ); ...@@ -59,16 +62,16 @@ 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_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_( \ #define AUTO_CONNECT_LONGTEXT N_( \
"If enabled, this option will automatically connect output to the " \ "If enabled, this option will automatically connect sound output to the " \
"first JACK inputs found." ) "first writable JACK clients found." )
#define CONNECT_MATCH_OPTION "jack-connect-match" #define CONNECT_REGEX_OPTION "jack-connect-regex"
#define CONNECT_MATCH_TEXT N_("Connect to outputs beginning with") #define CONNECT_REGEX_TEXT N_("Connect to clients matching")
#define CONNECT_MATCH_LONGTEXT N_( \ #define CONNECT_REGEX_LONGTEXT N_( \
"If automatic connection is enabled, only JACK inputs whose names " \ "If automatic connection is enabled, only JACK clients whose names " \
"begin with this prefix will be considered for connection." ) "match this regular expression will be considered for connection." )
/***************************************************************************** /*****************************************************************************
* Module descriptor * Module descriptor
...@@ -81,8 +84,8 @@ vlc_module_begin(); ...@@ -81,8 +84,8 @@ vlc_module_begin();
set_subcategory( SUBCAT_AUDIO_AOUT ); set_subcategory( SUBCAT_AUDIO_AOUT );
add_bool( AUTO_CONNECT_OPTION, 0, NULL, AUTO_CONNECT_TEXT, add_bool( AUTO_CONNECT_OPTION, 0, NULL, AUTO_CONNECT_TEXT,
AUTO_CONNECT_LONGTEXT, VLC_TRUE ); AUTO_CONNECT_LONGTEXT, VLC_TRUE );
add_string( CONNECT_MATCH_OPTION, NULL, NULL, CONNECT_MATCH_TEXT, add_string( CONNECT_REGEX_OPTION, NULL, NULL, CONNECT_REGEX_TEXT,
CONNECT_MATCH_LONGTEXT, VLC_TRUE ); CONNECT_REGEX_LONGTEXT, VLC_TRUE );
set_callbacks( Open, Close ); set_callbacks( Open, Close );
vlc_module_end(); vlc_module_end();
...@@ -91,15 +94,15 @@ vlc_module_end(); ...@@ -91,15 +94,15 @@ vlc_module_end();
*****************************************************************************/ *****************************************************************************/
static int Open( vlc_object_t *p_this ) static int Open( vlc_object_t *p_this )
{ {
char psz_name[32];
aout_instance_t *p_aout = (aout_instance_t *)p_this; aout_instance_t *p_aout = (aout_instance_t *)p_this;
struct aout_sys_t *p_sys = NULL; struct aout_sys_t *p_sys = NULL;
char **pp_match_ports = NULL;
char *psz_prefix = NULL;
int status = VLC_SUCCESS; int status = VLC_SUCCESS;
unsigned int i; unsigned int i;
int i_error;
/* Allocate structure */ /* Allocate structure */
p_sys = malloc( sizeof( aout_sys_t ) ); p_sys = calloc( 1, sizeof( aout_sys_t ) );
if( p_sys == NULL ) if( p_sys == NULL )
{ {
msg_Err( p_aout, "out of memory" ); msg_Err( p_aout, "out of memory" );
...@@ -109,7 +112,9 @@ static int Open( vlc_object_t *p_this ) ...@@ -109,7 +112,9 @@ static int Open( vlc_object_t *p_this )
p_aout->output.p_sys = p_sys; p_aout->output.p_sys = p_sys;
/* Connect to the JACK server */ /* 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 ) if( p_sys->p_jack_client == NULL )
{ {
msg_Err( p_aout, "failed to connect to JACK server" ); msg_Err( p_aout, "failed to connect to JACK server" );
...@@ -131,7 +136,8 @@ static int Open( vlc_object_t *p_this ) ...@@ -131,7 +136,8 @@ static int Open( vlc_object_t *p_this )
p_sys->i_channels = aout_FormatNbChannels( &p_aout->output.output ); 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 ) if( p_sys->p_jack_ports == NULL )
{ {
msg_Err( p_aout, "out of memory" ); msg_Err( p_aout, "out of memory" );
...@@ -139,13 +145,22 @@ static int Open( vlc_object_t *p_this ) ...@@ -139,13 +145,22 @@ static int Open( vlc_object_t *p_this )
goto error_out; 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 */ /* Create the output ports */
for( i = 0; i < p_sys->i_channels; i++ ) for( i = 0; i < p_sys->i_channels; i++ )
{ {
char p_name[32]; snprintf( psz_name, sizeof(psz_name), "out_%d", i + 1);
snprintf( p_name, 32, "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_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 ) if( p_sys->p_jack_ports[i] == NULL )
{ {
...@@ -156,10 +171,10 @@ static int Open( vlc_object_t *p_this ) ...@@ -156,10 +171,10 @@ static int Open( vlc_object_t *p_this )
} }
/* Tell the JACK server we are ready */ /* 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" ); msg_Err( p_aout, "failed to activate JACK client (error %d)", i_error );
jack_client_close( p_sys->p_jack_client );
status = VLC_EGENERIC; status = VLC_EGENERIC;
goto error_out; goto error_out;
} }
...@@ -167,62 +182,29 @@ static int Open( vlc_object_t *p_this ) ...@@ -167,62 +182,29 @@ static int Open( vlc_object_t *p_this )
/* Auto connect ports if we were asked to */ /* Auto connect ports if we were asked to */
if( config_GetInt( p_aout, AUTO_CONNECT_OPTION ) ) if( config_GetInt( p_aout, AUTO_CONNECT_OPTION ) )
{ {
unsigned int i_in_ports, i_prefix_len; unsigned int i_in_ports;
const char **pp_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,
pp_in_ports = jack_get_ports( p_sys->p_jack_client, NULL, NULL, psz_regex, NULL,
JackPortIsInput ); JackPortIsInput );
psz_prefix = config_GetPsz( p_aout, CONNECT_MATCH_OPTION ); /* Count the number of returned ports */
i_prefix_len = psz_prefix ? strlen(psz_prefix) : 0;
/* Find JACK input ports to connect to */
i = 0;
i_in_ports = 0;
while( pp_in_ports && pp_in_ports[i] )
{
if( !psz_prefix ||
!strncmp(psz_prefix, pp_in_ports[i], i_prefix_len) )
{
i_in_ports++; /* Found one */
}
i++;
}
/* Connect the output ports to input ports */
if( i_in_ports > 0 )
{
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;
}
/* populate list of matching ports */
i = 0;
i_in_ports = 0; i_in_ports = 0;
while( pp_in_ports[i] ) while( pp_in_ports && pp_in_ports[i_in_ports] )
{ {
if( !psz_prefix || i_in_ports++;
!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++;
} }
/* Tie the output ports to JACK input ports */ /* Tie the output ports to JACK input ports */
for( i = 0; i < p_sys->i_channels; i++ ) for( i = 0; i_in_ports > 0 && i < p_sys->i_channels; i++ )
{ {
const char* psz_in = pp_match_ports[i % i_in_ports]; const char* psz_in = pp_in_ports[i % i_in_ports];
const char* psz_out = jack_port_name( p_sys->p_jack_ports[i] ); 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) ) i_error = jack_connect( p_sys->p_jack_client, psz_out, psz_in );
if( i_error )
{ {
msg_Err( p_aout, "failed to connect port %s to port %s", msg_Err( p_aout, "failed to connect port %s to port %s (error %d)",
psz_out, psz_in ); psz_out, psz_in, i_error );
} }
else else
{ {
...@@ -230,6 +212,9 @@ static int Open( vlc_object_t *p_this ) ...@@ -230,6 +212,9 @@ static int Open( vlc_object_t *p_this )
psz_out, psz_in ); psz_out, psz_in );
} }
} }
if( pp_in_ports )
{
free( pp_in_ports );
} }
} }
...@@ -238,19 +223,22 @@ static int Open( vlc_object_t *p_this ) ...@@ -238,19 +223,22 @@ static int Open( vlc_object_t *p_this )
p_aout->output.i_nb_samples, p_aout->output.output.i_rate ); p_aout->output.i_nb_samples, p_aout->output.output.i_rate );
error_out: error_out:
/* Clean up */ /* Clean up, if an error occurred */
if( psz_prefix )
free( psz_prefix );
if( pp_match_ports )
free( pp_match_ports );
if( status != VLC_SUCCESS && p_sys != NULL) 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 ) if( p_sys->p_jack_client )
{
jack_deactivate( p_sys->p_jack_client );
jack_client_close( 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 ); free( p_sys );
} }
return status; return status;
...@@ -262,36 +250,44 @@ error_out: ...@@ -262,36 +250,44 @@ error_out:
*****************************************************************************/ *****************************************************************************/
int Process( jack_nframes_t i_frames, void *p_arg ) 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; unsigned int i, j, i_nb_samples = 0;
aout_instance_t *p_aout = (aout_instance_t*) p_arg; 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 */ /* Get the next audio data buffer */
p_buffer = aout_FifoPop( p_aout, &p_aout->output.fifo ); aout_buffer_t *p_buffer = aout_FifoPop( p_aout, &p_aout->output.fifo );
if( p_buffer != NULL )
if( p_buffer )
{ {
p_src = (jack_sample_t *)p_buffer->p_buffer;
i_nb_samples = p_buffer->i_nb_samples; 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_sys->p_jack_buffers[i] = jack_port_get_buffer( p_sys->p_jack_ports[i],
p_jack_buffer = jack_port_get_buffer( i_frames );
p_aout->output.p_sys->p_jack_ports[i], i_frames ); }
/* Fill the buffer with audio data */ /* Copy in the audio data */
for( j = 0; j < i_nb_samples; j++ ) for( j = 0; j < i_nb_samples; j++ )
{ {
p_jack_buffer[j] = ((float*)p_buffer->p_buffer)[i_nb_channels*j+i]; for( i = 0; i < p_sys->i_channels; i++ )
{
jack_sample_t *p_dst = p_sys->p_jack_buffers[i];
p_dst[j] = *p_src;
p_src++;
} }
}
/* Fill any remaining buffer with silence */
if( i_nb_samples < i_frames ) if( i_nb_samples < i_frames )
{ {
memset( p_jack_buffer + i_nb_samples, 0, for( i = 0; i < p_sys->i_channels; i++ )
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 ) ...@@ -299,7 +295,6 @@ int Process( jack_nframes_t i_frames, void *p_arg )
{ {
aout_BufferFree( p_buffer ); aout_BufferFree( p_buffer );
} }
return 0; return 0;
} }
...@@ -317,11 +312,22 @@ static void Play( aout_instance_t *p_aout ) ...@@ -317,11 +312,22 @@ static void Play( aout_instance_t *p_aout )
*****************************************************************************/ *****************************************************************************/
static void Close( vlc_object_t *p_this ) static void Close( vlc_object_t *p_this )
{ {
int i_error;
aout_instance_t *p_aout = (aout_instance_t *)p_this; aout_instance_t *p_aout = (aout_instance_t *)p_this;
struct aout_sys_t *p_sys = p_aout->output.p_sys; 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 ); free( p_sys->p_jack_ports );
jack_client_close( p_sys->p_jack_client ); free( p_sys->p_jack_buffers );
free( p_sys ); free( p_sys );
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment