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 @@
* Copyright (C) 2006 the VideoLAN team
* $Id$
*
* Authors: Cyril Deguet <asmax@videolan.org>
* Authors: Cyril Deguet <asmax _at_ videolan.org>
* Jon Griffiths <jon_p_griffiths _At_ yahoo _DOT_ com>
*
* This program is free software; you can redistribute it and/or modify
......@@ -37,6 +37,8 @@
#include <jack/jack.h>
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 );
}
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