X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fmodules%2Fjackrack%2Ffilter_jackrack.c;h=43898d5590aa302cc6d8c61e2d7d93e6d9f3658e;hb=11ceb3a29fd27c05bfac2b05463eff1790309a81;hp=37c75da6e7d2a57ff3fa9a9ed2455900f15dbc6f;hpb=25ca9db8aaf529bf0d16fdd7e4e135c0f112d7ae;p=mlt diff --git a/src/modules/jackrack/filter_jackrack.c b/src/modules/jackrack/filter_jackrack.c index 37c75da6..43898d55 100644 --- a/src/modules/jackrack/filter_jackrack.c +++ b/src/modules/jackrack/filter_jackrack.c @@ -18,37 +18,103 @@ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include "filter_jackrack.h" - -#include +#include #include #include #include #include +#include #include #include -#include #include -#include "ui.h" +#include "jack_rack.h" -#define BUFFER_LEN 2048 * 3 +extern pthread_mutex_t g_activate_mutex; -static void *jackrack_thread( void *arg ) +#define BUFFER_LEN 204800 * 6 + +static void jack_started_transmitter( mlt_listener listener, mlt_properties owner, mlt_service service, void **args ) { - mlt_properties properties = arg; - ui_t *jackrack = mlt_properties_get_data( properties, "jackrack", NULL ); - - while ( mlt_properties_get_int( properties, "_done" ) == 0 ) - if ( ui_loop_iterate( jackrack ) ) - break; - - ui_quit( jackrack ); - ui_destroy( jackrack ); - - return NULL; + listener( owner, service, (mlt_position*) args[0] ); +} + +static void jack_stopped_transmitter( mlt_listener listener, mlt_properties owner, mlt_service service, void **args ) +{ + listener( owner, service, (mlt_position*) args[0] ); +} + +static void jack_seek_transmitter( mlt_listener listener, mlt_properties owner, mlt_service service, void **args ) +{ + listener( owner, service, (mlt_position*) args[0] ); +} + +#define JACKSTATE(x) (x==JackTransportStopped?"stopped":x==JackTransportStarting?"starting":x==JackTransportRolling?"rolling":"unknown") + +static int jack_sync( jack_transport_state_t state, jack_position_t *jack_pos, void *arg ) +{ + mlt_filter filter = (mlt_filter) arg; + mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); + mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE(filter) ); + mlt_position position = mlt_profile_fps( profile ) * jack_pos->frame / jack_pos->frame_rate + 0.5; + int result = 1; + + mlt_log_debug( MLT_FILTER_SERVICE(filter), "%s frame %u rate %u pos %d last_pos %d\n", + JACKSTATE(state), jack_pos->frame, jack_pos->frame_rate, position, + mlt_properties_get_position( properties, "_last_pos" ) ); + if ( state == JackTransportStopped ) + { + mlt_events_fire( properties, "jack-stopped", &position, NULL ); + mlt_properties_set_int( properties, "_sync_guard", 0 ); + } + else if ( state == JackTransportStarting ) + { + result = 0; + if ( !mlt_properties_get_int( properties, "_sync_guard" ) ) + { + mlt_properties_set_int( properties, "_sync_guard", 1 ); + mlt_events_fire( properties, "jack-started", &position, NULL ); + } + else if ( position >= mlt_properties_get_position( properties, "_last_pos" ) - 2 ) + { + mlt_properties_set_int( properties, "_sync_guard", 0 ); + result = 1; + } + } + else + { + mlt_properties_set_int( properties, "_sync_guard", 0 ); + } + + return result; +} + +static void on_jack_start( mlt_properties owner, mlt_properties properties ) +{ + mlt_log_verbose( NULL, "%s\n", __FUNCTION__ ); + jack_client_t *jack_client = mlt_properties_get_data( properties, "jack_client", NULL ); + jack_transport_start( jack_client ); +} + +static void on_jack_stop( mlt_properties owner, mlt_properties properties ) +{ + mlt_log_verbose( NULL, "%s\n", __FUNCTION__ ); + jack_client_t *jack_client = mlt_properties_get_data( properties, "jack_client", NULL ); + jack_transport_stop( jack_client ); +} + +static void on_jack_seek( mlt_properties owner, mlt_filter filter, mlt_position *position ) +{ + mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); + mlt_log_verbose( MLT_FILTER_SERVICE(filter), "%s: %d\n", __FUNCTION__, *position ); + mlt_properties_set_int( properties, "_sync_guard", 1 ); + mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( filter ) ); + jack_client_t *jack_client = mlt_properties_get_data( properties, "jack_client", NULL ); + jack_nframes_t jack_frame = jack_get_sample_rate( jack_client ); + jack_frame *= *position / mlt_profile_fps( profile ); + jack_transport_locate( jack_client, jack_frame ); } static void initialise_jack_ports( mlt_properties properties ) @@ -65,18 +131,18 @@ static void initialise_jack_ports( mlt_properties properties ) // Start JackRack if ( mlt_properties_get( properties, "src" ) ) { - pthread_t *jackrack_pthread = mlt_pool_alloc( sizeof( pthread_t ) ); - snprintf( rack_name, sizeof( rack_name ), "jackrack%d", getpid() ); - ui_t *jackrack = ui_new( rack_name, mlt_properties_get_int( properties, "channels" ), 0, 0 ); + jack_rack_t *jackrack = jack_rack_new( rack_name, mlt_properties_get_int( properties, "channels" ) ); jack_rack_open_file( jackrack, mlt_properties_get( properties, "src" ) ); - mlt_properties_set_data( properties, "jackrack", jackrack, 0, NULL, NULL ); + mlt_properties_set_data( properties, "jackrack", jackrack, 0, + (mlt_destructor) jack_rack_destroy, NULL ); mlt_properties_set( properties, "_rack_client_name", rack_name ); - mlt_properties_set_int( properties, "_done", 0 ); - mlt_properties_set_data( properties, "jackrack_pthread", jackrack_pthread, 0, NULL, NULL ); - - pthread_create( jackrack_pthread, NULL, jackrack_thread, properties ); + } + else + { + // We have to set this to something to prevent re-initialization. + mlt_properties_set_data( properties, "jackrack", jack_client, 0, NULL, NULL ); } // Allocate buffers and ports @@ -88,15 +154,18 @@ static void initialise_jack_ports( mlt_properties properties ) float **jack_input_buffers = mlt_pool_alloc( sizeof(float *) * jack_buffer_size ); // Set properties - released inside filter_close - mlt_properties_set_data( properties, "output_buffers", output_buffers, sizeof( jack_ringbuffer_t *) * channels, NULL, NULL ); - mlt_properties_set_data( properties, "input_buffers", input_buffers, sizeof( jack_ringbuffer_t *) * channels, NULL, NULL ); - mlt_properties_set_data( properties, "jack_output_ports", jack_output_ports, sizeof( jack_port_t *) * channels, NULL, NULL ); - mlt_properties_set_data( properties, "jack_input_ports", jack_input_ports, sizeof( jack_port_t *) * channels, NULL, NULL ); - mlt_properties_set_data( properties, "jack_output_buffers", jack_output_buffers, sizeof( float *) * channels, NULL, NULL ); - mlt_properties_set_data( properties, "jack_input_buffers", jack_input_buffers, sizeof( float *) * channels, NULL, NULL ); - - // Start Jack processing - required before registering ports - jack_activate( jack_client ); + mlt_properties_set_data( properties, "output_buffers", output_buffers, + sizeof( jack_ringbuffer_t *) * channels, mlt_pool_release, NULL ); + mlt_properties_set_data( properties, "input_buffers", input_buffers, + sizeof( jack_ringbuffer_t *) * channels, mlt_pool_release, NULL ); + mlt_properties_set_data( properties, "jack_output_ports", jack_output_ports, + sizeof( jack_port_t *) * channels, mlt_pool_release, NULL ); + mlt_properties_set_data( properties, "jack_input_ports", jack_input_ports, + sizeof( jack_port_t *) * channels, mlt_pool_release, NULL ); + mlt_properties_set_data( properties, "jack_output_buffers", jack_output_buffers, + sizeof( float *) * channels, mlt_pool_release, NULL ); + mlt_properties_set_data( properties, "jack_input_buffers", jack_input_buffers, + sizeof( float *) * channels, mlt_pool_release, NULL ); // Register Jack ports for ( i = 0; i < channels; i++ ) @@ -106,9 +175,11 @@ static void initialise_jack_ports( mlt_properties properties ) output_buffers[i] = jack_ringbuffer_create( BUFFER_LEN * sizeof(float) ); input_buffers[i] = jack_ringbuffer_create( BUFFER_LEN * sizeof(float) ); snprintf( mlt_name, sizeof( mlt_name ), "obuf%d", i ); - mlt_properties_set_data( properties, mlt_name, output_buffers[i], BUFFER_LEN * sizeof(float), NULL, NULL ); + mlt_properties_set_data( properties, mlt_name, output_buffers[i], + BUFFER_LEN * sizeof(float), (mlt_destructor) jack_ringbuffer_free, NULL ); snprintf( mlt_name, sizeof( mlt_name ), "ibuf%d", i ); - mlt_properties_set_data( properties, mlt_name, input_buffers[i], BUFFER_LEN * sizeof(float), NULL, NULL ); + mlt_properties_set_data( properties, mlt_name, input_buffers[i], + BUFFER_LEN * sizeof(float), (mlt_destructor) jack_ringbuffer_free, NULL ); for ( in = 0; in < 2; in++ ) { @@ -120,6 +191,11 @@ static void initialise_jack_ports( mlt_properties properties ) } } + // Start Jack processing + pthread_mutex_lock( &g_activate_mutex ); + jack_activate( jack_client ); + pthread_mutex_unlock( &g_activate_mutex ); + // Establish connections for ( i = 0; i < channels; i++ ) { @@ -139,12 +215,12 @@ static void initialise_jack_ports( mlt_properties properties ) if ( in ) { - fprintf( stderr, "jack connect %s to %s\n", rack_name, mlt_name ); + mlt_log_verbose( NULL, "JACK connect %s to %s\n", rack_name, mlt_name ); jack_connect( jack_client, rack_name, mlt_name ); } else { - fprintf( stderr, "jack connect %s to %s\n", mlt_name, rack_name ); + mlt_log_verbose( NULL, "JACK connect %s to %s\n", mlt_name, rack_name ); jack_connect( jack_client, mlt_name, rack_name ); } } @@ -182,18 +258,20 @@ static int jack_process (jack_nframes_t frames, void * data) jack_output_buffers[i] = jack_port_get_buffer( jack_output_ports[i], frames ); if ( ! jack_output_buffers[i] ) { - fprintf( stderr, "%s: no jack buffer for output port %d\n", __FUNCTION__, i ); + mlt_log_error( MLT_FILTER_SERVICE(filter), "no buffer for output port %d\n", i ); err = 1; break; } ring_size = jack_ringbuffer_read_space( output_buffers[i] ); jack_ringbuffer_read( output_buffers[i], ( char * )jack_output_buffers[i], ring_size < jack_size ? ring_size : jack_size ); + if ( ring_size < jack_size ) + memset( &jack_output_buffers[i][ring_size], 0, jack_size - ring_size ); // Return audio through in port jack_input_buffers[i] = jack_port_get_buffer( jack_input_ports[i], frames ); if ( ! jack_input_buffers[i] ) { - fprintf( stderr, "%s: no jack buffer for input port %d\n", __FUNCTION__, i ); + mlt_log_error( MLT_FILTER_SERVICE(filter), "no buffer for input port %d\n", i ); err = 1; break; } @@ -201,7 +279,7 @@ static int jack_process (jack_nframes_t frames, void * data) // Do not start returning audio until we have sent first mlt frame if ( sync && i == 0 && frame_size > 0 ) total_size += ring_size; - //fprintf(stderr, "sync %d frame_size %d ring_size %d jack_size %d\n", sync, frame_size, ring_size, jack_size ); + mlt_log_debug( MLT_FILTER_SERVICE(filter), "sync %d frame_size %d ring_size %zu jack_size %zu\n", sync, frame_size, ring_size, jack_size ); if ( ! sync || ( frame_size > 0 && total_size >= frame_size ) ) { @@ -221,6 +299,18 @@ static int jack_process (jack_nframes_t frames, void * data) } } + // Often jackd does not send the stopped event through the JackSyncCallback + jack_client_t *jack_client = mlt_properties_get_data( properties, "jack_client", NULL ); + jack_position_t jack_pos; + jack_transport_state_t state = jack_transport_query( jack_client, &jack_pos ); + int transport_state = mlt_properties_get_int( properties, "_transport_state" ); + if ( state != transport_state ) + { + mlt_properties_set_int( properties, "_transport_state", state ); + if ( state == JackTransportStopped ) + jack_sync( state, &jack_pos, filter ); + } + return err; } @@ -228,7 +318,7 @@ static int jack_process (jack_nframes_t frames, void * data) /** Get the audio. */ -static int jackrack_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) +static int jackrack_get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { // Get the filter service mlt_filter filter = mlt_frame_pop_audio( frame ); @@ -236,17 +326,16 @@ static int jackrack_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_form // Get the filter properties mlt_properties filter_properties = MLT_FILTER_PROPERTIES( filter ); - // Restore the original get_audio - frame->get_audio = mlt_frame_pop_audio( frame ); - int jack_frequency = mlt_properties_get_int( filter_properties, "_sample_rate" ); // Get the producer's audio + *format = mlt_audio_float; mlt_frame_get_audio( frame, buffer, format, &jack_frequency, channels, samples ); // TODO: Deal with sample rate differences if ( *frequency != jack_frequency ) - fprintf( stderr, "mismatching frequencies in filter jackrack\n" ); + mlt_log_error( MLT_FILTER_SERVICE( filter ), "mismatching frequencies JACK = %d actual = %d\n", + jack_frequency, *frequency ); *frequency = jack_frequency; // Initialise Jack ports and connections if needed @@ -256,54 +345,37 @@ static int jackrack_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_form // Get the filter-specific properties jack_ringbuffer_t **output_buffers = mlt_properties_get_data( filter_properties, "output_buffers", NULL ); jack_ringbuffer_t **input_buffers = mlt_properties_get_data( filter_properties, "input_buffers", NULL ); - pthread_mutex_t *output_lock = mlt_properties_get_data( filter_properties, "output_lock", NULL ); - pthread_cond_t *output_ready = mlt_properties_get_data( filter_properties, "output_ready", NULL ); +// pthread_mutex_t *output_lock = mlt_properties_get_data( filter_properties, "output_lock", NULL ); +// pthread_cond_t *output_ready = mlt_properties_get_data( filter_properties, "output_ready", NULL ); // Process the audio - int16_t *q = *buffer; - float sample; - int i, j; + float *q = (float*) *buffer; + size_t size = *samples * sizeof(float); + int j; +// struct timespec tm = { 0, 0 }; - // Convert to floats and write into output ringbuffer - if ( jack_ringbuffer_write_space( output_buffers[0] ) >= ( *samples * sizeof(float) ) ) + // Write into output ringbuffer + for ( j = 0; j < *channels; j++ ) { - for ( i = 0; i < *samples; i++ ) - for ( j = 0; j < *channels; j++ ) - { - sample = ( float )( *q ++ ) / 32768.0; - jack_ringbuffer_write( output_buffers[j], ( char * )&sample, sizeof(float) ); - } + if ( jack_ringbuffer_write_space( output_buffers[j] ) >= size ) + jack_ringbuffer_write( output_buffers[j], (char*)( q + j * *samples ), size ); } // Synchronization phase - wait for signal from Jack process - while ( mlt_properties_get_int( filter_properties, "_sync" ) - && jack_ringbuffer_read_space( input_buffers[ *channels - 1 ] ) < ( *samples * sizeof(float) ) ) - pthread_cond_wait( output_ready, output_lock ); + while ( jack_ringbuffer_read_space( input_buffers[ *channels - 1 ] ) < size ) ; + //pthread_cond_wait( output_ready, output_lock ); - // Read from input ringbuffer and convert from floats - //if ( jack_ringbuffer_read_space( input_buffers[0] ) >= ( *samples * sizeof(float) ) ) + // Read from input ringbuffer + for ( j = 0; j < *channels; j++, q++ ) { - // Initialise to silence, but repeat last frame if available in case of - // buffer underrun - sample = 0; - q = *buffer; - for ( i = 0; i < *samples; i++ ) - for ( j = 0; j < *channels; j++ ) - { - jack_ringbuffer_read( input_buffers[j], ( char * )&sample, sizeof(float) ); - - if ( sample > 1.0 ) - sample = 1.0; - else if ( sample < -1.0 ) - sample = -1.0; - - if ( sample > 0 ) - *q ++ = 32767 * sample; - else - *q ++ = 32768 * sample; - } + if ( jack_ringbuffer_read_space( input_buffers[j] ) >= size ) + jack_ringbuffer_read( input_buffers[j], (char*)( q + j * *samples ), size ); } + // help jack_sync() indicate when we are rolling + mlt_position pos = mlt_frame_get_position( frame ); + mlt_properties_set_position( filter_properties, "_last_pos", pos ); + return 0; } @@ -313,14 +385,12 @@ static int jackrack_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_form static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) { - if ( frame->get_audio != NULL ) { mlt_properties properties = MLT_FILTER_PROPERTIES( this ); - mlt_frame_push_audio( frame, frame->get_audio ); mlt_frame_push_audio( frame, this ); - frame->get_audio = jackrack_get_audio; + mlt_frame_push_audio( frame, jackrack_get_audio ); - if ( mlt_properties_get_int( properties, "_sync" ) ) + if ( !mlt_properties_get_data( properties, "jackrack", NULL ) ) initialise_jack_ports( properties ); } @@ -328,39 +398,12 @@ static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) } -void filter_close( mlt_filter this ) +static void filter_close( mlt_filter this ) { - int i; - char mlt_name[20]; mlt_properties properties = MLT_FILTER_PROPERTIES( this ); jack_client_t *jack_client = mlt_properties_get_data( properties, "jack_client", NULL ); - jack_deactivate( jack_client ); jack_client_close( jack_client ); - for ( i = 0; i < mlt_properties_get_int( properties, "channels" ); i++ ) - { - snprintf( mlt_name, sizeof( mlt_name ), "obuf%d", i ); - jack_ringbuffer_free( mlt_properties_get_data( properties, mlt_name, NULL ) ); - snprintf( mlt_name, sizeof( mlt_name ), "ibuf%d", i ); - jack_ringbuffer_free( mlt_properties_get_data( properties, mlt_name, NULL ) ); - } - mlt_pool_release( mlt_properties_get_data( properties, "output_buffers", NULL ) ); - mlt_pool_release( mlt_properties_get_data( properties, "input_buffers", NULL ) ); - mlt_pool_release( mlt_properties_get_data( properties, "jack_output_ports", NULL ) ); - mlt_pool_release( mlt_properties_get_data( properties, "jack_input_ports", NULL ) ); - mlt_pool_release( mlt_properties_get_data( properties, "jack_output_buffers", NULL ) ); - mlt_pool_release( mlt_properties_get_data( properties, "jack_input_buffers", NULL ) ); - mlt_pool_release( mlt_properties_get_data( properties, "output_lock", NULL ) ); - mlt_pool_release( mlt_properties_get_data( properties, "output_ready", NULL ) ); - - pthread_t *jackrack_pthread = mlt_properties_get_data( properties, "jackrack_thread", NULL ); - if ( jackrack_pthread != NULL ) - { - mlt_properties_set_int( properties, "_done", 1 ); - pthread_join( *jackrack_pthread, NULL ); - mlt_pool_release( jackrack_pthread ); - } - this->parent.close = NULL; mlt_service_close( &this->parent ); } @@ -368,22 +411,32 @@ void filter_close( mlt_filter this ) /** Constructor for the filter. */ -mlt_filter filter_jackrack_init( char *arg ) +mlt_filter filter_jackrack_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter this = mlt_filter_new( ); if ( this != NULL ) { - char name[14]; - + char name[16]; + char *jack_client_name; + jack_status_t status = 0; + snprintf( name, sizeof( name ), "mlt%d", getpid() ); - jack_client_t *jack_client = jack_client_new( name ); + jack_client_t *jack_client = jack_client_open( name, JackNullOption, &status, NULL ); if ( jack_client ) { + if ( status & JackNameNotUnique ) + { + jack_client_name = jack_get_client_name ( jack_client ); + strcpy( name, jack_client_name ); + } + mlt_properties properties = MLT_FILTER_PROPERTIES( this ); pthread_mutex_t *output_lock = mlt_pool_alloc( sizeof( pthread_mutex_t ) ); pthread_cond_t *output_ready = mlt_pool_alloc( sizeof( pthread_cond_t ) ); jack_set_process_callback( jack_client, jack_process, this ); + jack_set_sync_callback( jack_client, jack_sync, this ); + jack_set_sync_timeout( jack_client, 5000000 ); //TODO: jack_on_shutdown( jack_client, jack_shutdown_cb, this ); this->process = filter_process; this->close = filter_close; @@ -394,10 +447,26 @@ mlt_filter filter_jackrack_init( char *arg ) mlt_properties_set( properties, "_client_name", name ); mlt_properties_set_data( properties, "jack_client", jack_client, 0, NULL, NULL ); mlt_properties_set_int( properties, "_sample_rate", jack_get_sample_rate( jack_client ) ); - mlt_properties_set_data( properties, "output_lock", output_lock, 0, NULL, NULL ); - mlt_properties_set_data( properties, "output_ready", output_ready, 0, NULL, NULL ); + mlt_properties_set_data( properties, "output_lock", output_lock, 0, mlt_pool_release, NULL ); + mlt_properties_set_data( properties, "output_ready", output_ready, 0, mlt_pool_release, NULL ); mlt_properties_set_int( properties, "_sync", 1 ); mlt_properties_set_int( properties, "channels", 2 ); + + mlt_events_register( properties, "jack-started", (mlt_transmitter) jack_started_transmitter ); + mlt_events_register( properties, "jack-stopped", (mlt_transmitter) jack_stopped_transmitter ); + mlt_events_register( properties, "jack-start", NULL ); + mlt_events_register( properties, "jack-stop", NULL ); + mlt_events_register( properties, "jack-seek", (mlt_transmitter) jack_seek_transmitter ); + mlt_events_listen( properties, properties, "jack-start", (mlt_listener) on_jack_start ); + mlt_events_listen( properties, properties, "jack-stop", (mlt_listener) on_jack_stop ); + mlt_events_listen( properties, this, "jack-seek", (mlt_listener) on_jack_seek ); + mlt_properties_set_position( properties, "_jack_seek", -1 ); + } + else + { + mlt_log_error( NULL, "Failed to connect to JACK server\n" ); + mlt_filter_close( this ); + this = NULL; } } return this;