]> git.sesse.net Git - mlt/blobdiff - src/modules/rtaudio/consumer_rtaudio.cpp
Move burningtv into plusgpl module.
[mlt] / src / modules / rtaudio / consumer_rtaudio.cpp
index de786450d98d1a1ed75d66c2080c6ca3700dd194..8b6e599e0cd60bf897666d243431480eaabbcd05 100644 (file)
@@ -50,18 +50,23 @@ public:
        pthread_cond_t        refresh_cond;
        pthread_mutex_t       refresh_mutex;
        int                   refresh_count;
+       bool                  is_purge;
 
        mlt_consumer getConsumer()
                { return &consumer; }
 
        RtAudioConsumer()
                : device_id(-1)
+               , queue(NULL)
                , joined(0)
                , running(0)
                , audio_avail(0)
                , playing(0)
                , refresh_count(0)
-               {}
+               , is_purge(false)
+       {
+               memset( &consumer, 0, sizeof( consumer ) );
+       }
 
        ~RtAudioConsumer()
        {
@@ -88,13 +93,10 @@ public:
                        return false;
                }
 
-               if ( !arg || !strcmp( arg, "" ) )
-               {
 #ifndef __LINUX_ALSA__
-                       device_id = rt.getDefaultOutputDevice();
+               device_id = rt.getDefaultOutputDevice();
 #endif
-               }
-               else if ( strcmp( arg, "default" ) )
+               if ( arg && strcmp( arg, "" ) && strcmp( arg, "default" ) )
                {
                        // Get device ID by name
                        unsigned int n = rt.getDeviceCount();
@@ -112,7 +114,7 @@ public:
                                        break;
                                }
                        }
-                       // Name selection failed, treat arg as numeric
+                       // Name selection failed, try arg as numeric
                        if ( i == n )
                                device_id = (int) strtol( arg, NULL, 0 );
                }
@@ -142,6 +144,9 @@ public:
                // Default audio buffer
                mlt_properties_set_int( properties, "audio_buffer", 1024 );
 
+               // Set the resource to the device name arg
+               mlt_properties_set( properties, "resource", arg );
+
                // Ensure we don't join on a non-running object
                joined = 1;
 
@@ -205,6 +210,24 @@ public:
                return 0;
        }
 
+       void purge()
+       {
+               if ( running )
+               {
+                       pthread_mutex_lock( &video_mutex );
+                       mlt_frame frame = MLT_FRAME( mlt_deque_peek_back( queue ) );
+                       // When playing rewind or fast forward then we need to keep one
+                       // frame in the queue to prevent playback stalling.
+                       double speed = frame? mlt_properties_get_double( MLT_FRAME_PROPERTIES(frame), "_speed" ) : 0;
+                       int n = ( speed == 0.0 || speed == 1.0 ) ? 0 : 1;
+                       while ( mlt_deque_count( queue ) > n )
+                               mlt_frame_close( MLT_FRAME( mlt_deque_pop_back( queue ) ) );
+                       is_purge = true;
+                       pthread_cond_broadcast( &video_cond );
+                       pthread_mutex_unlock( &video_mutex );
+               }
+       }
+
        void consumer_thread()
        {
                // Get the properties
@@ -222,7 +245,10 @@ public:
                int64_t playtime = 0;
                struct timespec tm = { 0, 100000 };
        //      int last_position = -1;
+
+               pthread_mutex_lock( &refresh_mutex );
                refresh_count = 0;
+               pthread_mutex_unlock( &refresh_mutex );
 
                // Loop until told not to
                while ( running )
@@ -270,8 +296,16 @@ public:
                                if ( running && speed )
                                {
                                        pthread_mutex_lock( &video_mutex );
-                                       mlt_deque_push_back( queue, frame );
-                                       pthread_cond_broadcast( &video_cond );
+                                       if ( is_purge && speed == 1.0 )
+                                       {
+                                               mlt_frame_close( frame );
+                                               is_purge = false;
+                                       }
+                                       else
+                                       {
+                                               mlt_deque_push_back( queue, frame );
+                                               pthread_cond_broadcast( &video_cond );
+                                       }
                                        pthread_mutex_unlock( &video_mutex );
 
                                        // Calculate the next playtime
@@ -389,6 +423,7 @@ public:
                // Set the preferred params of the test card signal
                int channels = mlt_properties_get_int( properties, "channels" );
                int frequency = mlt_properties_get_int( properties, "frequency" );
+               int scrub = mlt_properties_get_int( properties, "scrub_audio" );
                static int counter = 0;
                int samples = mlt_sample_calculator( mlt_properties_get_double( properties, "fps" ), frequency, counter++ );
                int16_t *pcm;
@@ -409,16 +444,20 @@ public:
                        parameters.nChannels = channels;
                        parameters.firstChannel = 0;
                        RtAudio::StreamOptions options;
-#ifdef __LINUX_ALSA__
+                       unsigned int bufferFrames = mlt_properties_get_int( properties, "audio_buffer" );
+
                        if ( device_id == -1 )
                        {
                                options.flags = RTAUDIO_ALSA_USE_DEFAULT;
                                parameters.deviceId = 0;
                        }
-#endif
-                       unsigned int bufferFrames = mlt_properties_get_int( properties, "audio_buffer" );
+                       if ( mlt_properties_get( properties, "resource" ) )
+                               parameters.deviceName = mlt_properties_get( properties, "resource" );
 
                        try {
+                               if ( rt.isStreamOpen() ) {
+                                   rt.closeStream();
+                               }
                                rt.openStream( &parameters, NULL, RTAUDIO_SINT16,
                                        frequency, &bufferFrames, &rtaudio_callback, this, &options );
                                rt.startStream();
@@ -440,7 +479,7 @@ public:
                                pthread_cond_wait( &audio_cond, &audio_mutex );
                        if ( running )
                        {
-                               if ( mlt_properties_get_double( properties, "_speed" ) == 1 )
+                               if ( scrub || mlt_properties_get_double( properties, "_speed" ) == 1 )
                                        memcpy( &audio_buffer[ audio_avail ], pcm, bytes );
                                else
                                        memset( &audio_buffer[ audio_avail ], 0, bytes );
@@ -611,6 +650,12 @@ static int is_stopped( mlt_consumer consumer )
        return !rtaudio->running;
 }
 
+static void purge( mlt_consumer consumer )
+{
+       RtAudioConsumer* rtaudio = (RtAudioConsumer*) consumer->child;
+       rtaudio->purge();
+}
+
 /** Close the consumer.
  */
 
@@ -639,7 +684,7 @@ mlt_consumer consumer_rtaudio_init( mlt_profile profile, mlt_service_type type,
        if ( rtaudio && !mlt_consumer_init( rtaudio->getConsumer(), rtaudio, profile ) )
        {
                // If initialises without error
-               if ( rtaudio->open( arg ) )
+               if ( rtaudio->open( arg? arg : getenv( "AUDIODEV" ) ) )
                {
                        // Setup callbacks
                        consumer = rtaudio->getConsumer();
@@ -647,6 +692,7 @@ mlt_consumer consumer_rtaudio_init( mlt_profile profile, mlt_service_type type,
                        consumer->start = start;
                        consumer->stop = stop;
                        consumer->is_stopped = is_stopped;
+                       consumer->purge = purge;
                }
                else
                {