]> git.sesse.net Git - mlt/commitdiff
Add first draft of JACK transport sync.
authorDan Dennedy <dan@dennedy.org>
Sun, 15 May 2011 20:55:53 +0000 (13:55 -0700)
committerDan Dennedy <dan@dennedy.org>
Sun, 15 May 2011 22:24:03 +0000 (15:24 -0700)
src/melt/melt.c
src/modules/jackrack/filter_jackrack.c
src/modules/jackrack/process.c

index 6028a4391461ede2fb13fbd9344f182244637db5..177ab5af36c45f399aa391a4763470badcbb51f2 100644 (file)
@@ -42,6 +42,8 @@ static void transport_action( mlt_producer producer, char *value )
        mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer );
        mlt_multitrack multitrack = mlt_properties_get_data( properties, "multitrack", NULL );
        mlt_consumer consumer = mlt_properties_get_data( properties, "transport_consumer", NULL );
+       mlt_properties jack = mlt_properties_get_data( MLT_CONSUMER_PROPERTIES( consumer ), "jack_filter", NULL );
+       mlt_position position = mlt_producer_position( producer );
 
        mlt_properties_set_int( properties, "stats_off", 1 );
 
@@ -52,10 +54,14 @@ static void transport_action( mlt_producer producer, char *value )
                        case 'q':
                        case 'Q':
                                mlt_properties_set_int( properties, "done", 1 );
+                               mlt_events_fire( jack, "jack-stop", NULL );
                                break;
                        case '0':
+                               position = 0;
                                mlt_producer_set_speed( producer, 1 );
-                               mlt_producer_seek( producer, 0 );
+                               mlt_producer_seek( producer, position );
+                               mlt_consumer_purge( consumer );
+                               mlt_events_fire( jack, "jack-seek", &position, NULL );
                                break;
                        case '1':
                                mlt_producer_set_speed( producer, -10 );
@@ -71,10 +77,15 @@ static void transport_action( mlt_producer producer, char *value )
                                break;
                        case '5':
                                mlt_producer_set_speed( producer, 0 );
+                               mlt_consumer_purge( consumer );
+                               mlt_events_fire( jack, "jack-stop", NULL );
                                break;
                        case '6':
                        case ' ':
-                               mlt_producer_set_speed( producer, 1 );
+                               if ( !jack || mlt_producer_get_speed( producer ) != 0 )
+                                       mlt_producer_set_speed( producer, 1 );
+                               mlt_consumer_purge( consumer );
+                               mlt_events_fire( jack, "jack-start", NULL );
                                break;
                        case '7':
                                mlt_producer_set_speed( producer, 2 );
@@ -93,11 +104,11 @@ static void transport_action( mlt_producer producer, char *value )
                                        fprintf( stderr, "\n" );
                                        for ( i = 0; 1; i ++ )
                                        {
-                                               mlt_position time = mlt_multitrack_clip( multitrack, mlt_whence_relative_start, i );
-                                               if ( time == last )
+                                               position = mlt_multitrack_clip( multitrack, mlt_whence_relative_start, i );
+                                               if ( position == last )
                                                        break;
-                                               last = time;
-                                               fprintf( stderr, "%d: %d\n", i, (int)time );
+                                               last = position;
+                                               fprintf( stderr, "%d: %d\n", i, (int)position );
                                        }
                                }
                                break;
@@ -105,54 +116,74 @@ static void transport_action( mlt_producer producer, char *value )
                        case 'g':
                                if ( multitrack != NULL )
                                {
-                                       mlt_position time = mlt_multitrack_clip( multitrack, mlt_whence_relative_current, 0 );
-                                       mlt_producer_seek( producer, time );
+                                       position = mlt_multitrack_clip( multitrack, mlt_whence_relative_current, 0 );
+                                       mlt_producer_seek( producer, position );
+                                       mlt_consumer_purge( consumer );
+                                       mlt_events_fire( jack, "jack-seek", &position, NULL );
                                }
                                break;
                        case 'H':
                                if ( producer != NULL )
                                {
-                                       mlt_position position = mlt_producer_position( producer );
-                                       mlt_producer_seek( producer, position - ( mlt_producer_get_fps( producer ) * 60 ) );
+                                       position -= mlt_producer_get_fps( producer ) * 60;
+                                       mlt_consumer_purge( consumer );
+                                       mlt_producer_seek( producer, position );
+                                       mlt_events_fire( jack, "jack-seek", &position, NULL );
                                }
                                break;
                        case 'h':
                                if ( producer != NULL )
                                {
-                                       mlt_position position = mlt_producer_position( producer );
+                                       position--;
                                        mlt_producer_set_speed( producer, 0 );
-                                       mlt_producer_seek( producer, position - 1 );
+                                       mlt_consumer_purge( consumer );
+                                       mlt_producer_seek( producer, position );
+                                       mlt_events_fire( jack, "jack-stop", NULL );
+                                       mlt_events_fire( jack, "jack-seek", &position, NULL );
                                }
                                break;
                        case 'j':
                                if ( multitrack != NULL )
                                {
-                                       mlt_position time = mlt_multitrack_clip( multitrack, mlt_whence_relative_current, 1 );
-                                       mlt_producer_seek( producer, time );
+                                       position = mlt_multitrack_clip( multitrack, mlt_whence_relative_current, 1 );
+                                       mlt_consumer_purge( consumer );
+                                       mlt_producer_seek( producer, position );
+                                       mlt_events_fire( jack, "jack-seek", &position, NULL );
                                }
                                break;
                        case 'k':
                                if ( multitrack != NULL )
                                {
-                                       mlt_position time = mlt_multitrack_clip( multitrack, mlt_whence_relative_current, -1 );
-                                       mlt_producer_seek( producer, time );
+                                       position = mlt_multitrack_clip( multitrack, mlt_whence_relative_current, -1 );
+                                       mlt_consumer_purge( consumer );
+                                       mlt_producer_seek( producer, position );
+                                       mlt_events_fire( jack, "jack-seek", &position, NULL );
                                }
                                break;
                        case 'l':
                                if ( producer != NULL )
                                {
-                                       mlt_position position = mlt_producer_position( producer );
+                                       position++;
+                                       mlt_consumer_purge( consumer );
                                        if ( mlt_producer_get_speed( producer ) != 0 )
+                                       {
                                                mlt_producer_set_speed( producer, 0 );
+                                               mlt_events_fire( jack, "jack-stop", NULL );
+                                       }
                                        else
-                                               mlt_producer_seek( producer, position + 1 );
+                                       {
+                                               mlt_producer_seek( producer, position );
+                                               mlt_events_fire( jack, "jack-seek", &position, NULL );
+                                       }
                                }
                                break;
                        case 'L':
                                if ( producer != NULL )
                                {
-                                       mlt_position position = mlt_producer_position( producer );
-                                       mlt_producer_seek( producer, position + ( mlt_producer_get_fps( producer ) * 60 ) );
+                                       position += mlt_producer_get_fps( producer ) * 60;
+                                       mlt_consumer_purge( consumer );
+                                       mlt_producer_seek( producer, position );
+                                       mlt_events_fire( jack, "jack-seek", &position, NULL );
                                }
                                break;
                }
@@ -163,6 +194,53 @@ static void transport_action( mlt_producer producer, char *value )
        mlt_properties_set_int( properties, "stats_off", 0 );
 }
 
+static void on_jack_started( mlt_properties owner, mlt_consumer consumer, mlt_position *position )
+{
+       mlt_producer producer = mlt_properties_get_data( MLT_CONSUMER_PROPERTIES(consumer), "transport_producer", NULL );
+       if ( producer )
+       {
+               if ( mlt_producer_get_speed( producer ) != 0 )
+               {
+                       mlt_properties jack = mlt_properties_get_data( MLT_CONSUMER_PROPERTIES( consumer ), "jack_filter", NULL );
+                       mlt_events_fire( jack, "jack-stop", NULL );
+               }
+               else
+               {
+                       mlt_producer_set_speed( producer, 1 );
+                       mlt_consumer_purge( consumer );
+                       mlt_producer_seek( producer, *position );
+                       mlt_properties_set_int( MLT_CONSUMER_PROPERTIES( consumer ), "refresh", 1 );
+               }
+       }
+}
+
+static void on_jack_stopped( mlt_properties owner, mlt_consumer consumer, mlt_position *position )
+{
+       mlt_producer producer = mlt_properties_get_data( MLT_CONSUMER_PROPERTIES(consumer), "transport_producer", NULL );
+       if ( producer )
+       {
+               mlt_producer_set_speed( producer, 0 );
+               mlt_consumer_purge( consumer );
+               mlt_producer_seek( producer, *position );
+               mlt_properties_set_int( MLT_CONSUMER_PROPERTIES( consumer ), "refresh", 1 );
+       }
+}
+
+static void setup_jack_transport( mlt_consumer consumer, mlt_profile profile )
+{
+       mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer );
+       mlt_filter jack = mlt_factory_filter( profile, "jackrack", NULL );
+       mlt_properties jack_properties = MLT_FILTER_PROPERTIES(jack);
+
+       mlt_service_attach( MLT_CONSUMER_SERVICE(consumer), jack );
+       mlt_properties_set_int( properties, "audio_off", 1 );
+       mlt_properties_set_data( properties, "jack_filter", jack, 0, (mlt_destructor) mlt_filter_close, NULL );
+//     mlt_properties_set( jack_properties, "out_1", "system:playback_1" );
+//     mlt_properties_set( jack_properties, "out_2", "system:playback_2" );
+       mlt_events_listen( jack_properties, consumer, "jack-started", (mlt_listener) on_jack_started );
+       mlt_events_listen( jack_properties, consumer, "jack-stopped", (mlt_listener) on_jack_stopped );
+}
+
 static mlt_consumer create_consumer( mlt_profile profile, char *id )
 {
        char *myid = id ? strdup( id ) : NULL;
@@ -736,7 +814,11 @@ query_all:
                // Parse the arguments
                for ( i = 1; i < argc; i ++ )
                {
-                       if ( !strcmp( argv[ i ], "-serialise" ) )
+                       if ( !strcmp( argv[ i ], "-jack" ) )
+                       {
+                               setup_jack_transport( consumer, profile );
+                       }
+                       else if ( !strcmp( argv[ i ], "-serialise" ) )
                        {
                                if ( store != stdout )
                                        i ++;
index 9015bf4a0105455172dbd3bb800eefccd56fbd9d..f9e1b76e1a2372cf31783cad786187c66a8d16d6 100644 (file)
@@ -18,9 +18,7 @@
  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
-#include <framework/mlt_filter.h>
-#include <framework/mlt_frame.h>
-#include <framework/mlt_log.h>
+#include <framework/mlt.h>
 
 #include <stdio.h>
 #include <stdlib.h>
 
 #define BUFFER_LEN 204800 * 6
 
+static void jack_started_transmitter( mlt_listener listener, mlt_properties owner, mlt_service service, void **args )
+{
+       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_verbose( 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 )
+{
+       fprintf(stderr, "%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 )
+{
+       fprintf(stderr, "%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_properties_set_int( properties, "_sync_guard", 1 );
+       mlt_properties_set_position( properties, "_jack_seek", *position );
+       return;
+
+
+       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 );
+
+       fprintf(stderr, "%s: %d\n", __FUNCTION__, *position);
+       jack_transport_locate( jack_client, jack_frame );
+}
+
 static void initialise_jack_ports( mlt_properties properties )
 {
        int i;
@@ -275,6 +361,20 @@ static int jackrack_get_audio( mlt_frame frame, void **buffer, mlt_audio_format
                        jack_ringbuffer_read( input_buffers[j], (char*)( q + j * *samples ), size );
        }
 
+       // Do JACK seeking if requested
+       mlt_position pos = mlt_frame_get_position( frame );
+       mlt_properties_set_position( filter_properties, "_last_pos", pos );
+       if ( pos == mlt_properties_get_position( filter_properties, "_jack_seek" ) )
+       {
+               jack_client_t *jack_client = mlt_properties_get_data( filter_properties, "jack_client", NULL );
+               jack_position_t jack_pos;
+               jack_transport_query( jack_client, &jack_pos );
+               double fps = mlt_profile_fps( mlt_service_profile( MLT_FILTER_SERVICE(filter) ) );
+               jack_nframes_t jack_frame = jack_pos.frame_rate * pos / fps;
+               jack_transport_locate( jack_client, jack_frame );
+               mlt_properties_set_position( filter_properties, "_jack_seek", -1 );
+       }
+
        return 0;
 }
 
@@ -318,7 +418,7 @@ mlt_filter filter_jackrack_init( mlt_profile profile, mlt_service_type type, con
                char name[14];
                
                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, NULL );
                if ( jack_client )
                {
                        mlt_properties properties = MLT_FILTER_PROPERTIES( this );
@@ -326,6 +426,8 @@ mlt_filter filter_jackrack_init( mlt_profile profile, mlt_service_type type, con
                        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;
@@ -340,6 +442,16 @@ mlt_filter filter_jackrack_init( mlt_profile profile, mlt_service_type type, con
                        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 );
                }
        }
        return this;
index 1b62755c13f7dae2b2e2121bb3434b53caeb99c1..08eecf6d7e4cffb4daae78d32fe189a10c346761 100644 (file)
@@ -378,7 +378,7 @@ process_info_connect_jack (process_info_t * procinfo)
 {
   mlt_log_info( NULL, _("Connecting to JACK server with client name '%s'\n"), procinfo->jack_client_name);
 
-  procinfo->jack_client = jack_client_new (procinfo->jack_client_name);
+  procinfo->jack_client = jack_client_open (procinfo->jack_client_name, JackNullOption, NULL);
 
   if (!procinfo->jack_client)
     {