~ubuntu-branches/ubuntu/lucid/lastfm/lucid

« back to all changes in this revision

Viewing changes to src/AudioController.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Pedro Fragoso
  • Date: 2007-12-31 09:49:54 UTC
  • mfrom: (1.1.5 upstream)
  • Revision ID: james.westby@ubuntu.com-20071231094954-ix1amvcsj9pk61ya
Tags: 1:1.4.1.57486.dfsg-1ubuntu1
* Merge from Debian unstable (LP: #180254), remaining changes:
  - debian/rules;
    - Added dh_icons
  - Modify Maintainer value to match Debian-Maintainer-Field Spec

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
 *   You should have received a copy of the GNU General Public License     *
17
17
 *   along with this program; if not, write to the                         *
18
18
 *   Free Software Foundation, Inc.,                                       *
19
 
 *   51 Franklin Steet, Fifth Floor, Boston, MA  02111-1307, USA.          *
 
19
 *   51 Franklin Steet, Fifth Floor, Boston, MA  02110-1301, USA.          *
20
20
 ***************************************************************************/
21
21
 
22
22
#include "AudioController.h"
23
 
#include "lastfm_common.h"
24
23
 
25
24
#include "interfaces/InputInterface.h"
26
25
#include "interfaces/TranscodeInterface.h"
27
26
#include "interfaces/OutputInterface.h"
28
 
#include "utils.h"
29
 
#include "containerutils.h"
30
 
#include "Settings.h"
 
27
#include "MooseCommon.h"
 
28
#include "LastFmSettings.h"
31
29
#include "Radio.h"
 
30
#include "logger.h"
 
31
#include "ProxyOutput.h"
32
32
 
33
33
#include "output/RtAudio/rtaudioplayback.h"
34
34
 
35
35
#include <QFileInfo>
 
36
#include <QMutexLocker>
36
37
#include <QPluginLoader>
37
38
 
38
39
// RADIO STREAMING CONSTANTS
54
55
 
55
56
// Min size of buffer holding decoded audio data, i.e the size the buffer
56
57
// needs to be to not return true from the needsData() call.
57
 
const int kDecodedBufferMinSize = 4 * kUncompressedPacketSize;
 
58
static const int kDecodedBufferMinSize = 4 * kUncompressedPacketSize;
58
59
//static const int kDecodedBufferMinSize = 400000;
59
60
 
60
61
// Min size of buffer in the output, i.e the size the buffer
61
62
// needs to be to not return true from the needsData() call.
62
 
const int kOutputBufferMinSize = kDecodedBufferMinSize; 
 
63
static const int kOutputBufferMinSize = kDecodedBufferMinSize; 
63
64
//static const int kOutputBufferMinSize = 400000; 
64
65
 
 
66
// Max number of errors in a row before we abort
 
67
static const int k_streamerErrorLimit = 5;
65
68
 
66
69
AudioControllerThread::AudioControllerThread( QObject* parent ) :
67
70
        QThread( parent ),
68
71
        m_input( 0 ),
69
72
        m_transcode( 0 ),
70
73
        m_output( 0 ),
71
 
        m_state( State_Stopped ),    
 
74
        m_proxyOutput( 0 ),
 
75
        m_state( State_Stopped ),
72
76
        m_timeElapsedAtLastPause( 0 ),
73
77
        m_automaticBufferHandling( true )
74
78
{
75
 
 
76
79
}
77
80
 
78
81
 
79
82
void
80
83
AudioControllerThread::run()
81
84
{
 
85
    // This weird-looking bit of code is there to make this thread not
 
86
    // initialise until the parent thread has entered wait.
 
87
    static_cast<AudioController*>( parent() )->m_mutex.lock();
 
88
    static_cast<AudioController*>( parent() )->m_mutex.unlock();
 
89
 
82
90
    // Initialise our in-thread services
83
91
    m_handler = new AudioControllerEventHandler( this );
84
92
 
96
104
    m_output->setParent( m_handler );
97
105
 
98
106
    m_timer = new QTimer( m_handler );
99
 
    
 
107
 
100
108
    // For some utterly perverse reason, we have to specify DirectConnection
101
109
    // here. If I leave it as Auto, the input class will on emit think that
102
110
    // it needs to post a message to us and that message somehow ends up
137
145
 
138
146
    // Start our own event loop
139
147
    exec();
140
 
    
 
148
 
 
149
    // This makes the loaded services auto-delete
141
150
    delete m_handler;
 
151
    delete m_proxyOutput;
142
152
}
143
153
 
144
154
 
149
159
    // plugins and then flip between them at track play time
150
160
    m_input = qobject_cast<InputInterface*>( loadPlugin( "httpinput" ) );
151
161
    if ( m_input == 0 )
152
 
    {
153
162
        return false;
154
 
    }
155
 
    m_input->setBufferCapacity( Constants::kHttpBufferMinSize );
156
163
 
157
 
    m_transcode = qobject_cast<TranscodeInterface*>( loadPlugin( "mp3transcode" ) );
 
164
    m_input->setBufferCapacity( MooseConstants::kHttpBufferMinSize );
 
165
    m_transcode = qobject_cast<TranscodeInterface*>( loadPlugin( "madtranscode" ) );
158
166
    if ( m_transcode == 0 )
159
 
    {
160
167
        return false;
161
 
    }
 
168
 
162
169
    m_transcode->setBufferCapacity( kDecodedBufferMinSize );
163
 
    
 
170
 
164
171
    #ifdef WIN32
165
172
        m_output = qobject_cast<OutputInterface*>( loadPlugin( "rtaudioplayback" ) );
166
173
    #elif defined LINUX
170
177
    #endif
171
178
 
172
179
    if ( m_output == 0 )
173
 
    {
174
180
        return false;
175
 
    }
 
181
 
176
182
    m_output->setBufferCapacity( kOutputBufferMinSize );
177
 
    
 
183
    m_output->setDevice( The::settings().soundCard() );
 
184
 
 
185
    m_proxyOutput = new ProxyOutput();
 
186
 
178
187
    return true;
179
188
}
180
189
 
182
191
QObject*
183
192
AudioControllerThread::loadPlugin( QString name )
184
193
{
185
 
    QString path = pluginPath( name );
 
194
    QString path = MooseUtils::servicePath( name );
186
195
    QObject* plugin = QPluginLoader( path ).instance();
187
196
 
 
197
    qDebug() << path;
 
198
 
188
199
    Q_ASSERT( plugin );
189
200
    if ( plugin == 0 )
190
201
    {
212
223
    else if ( newAuto && !m_automaticBufferHandling )
213
224
    {
214
225
        // Switched on automatic
215
 
        m_input->setBufferCapacity( Constants::kHttpBufferMinSize );
 
226
        m_input->setBufferCapacity( MooseConstants::kHttpBufferMinSize );
216
227
    }
217
228
 
218
229
    m_automaticBufferHandling = newAuto;
219
230
}
220
231
 
221
 
    
 
232
 
222
233
bool
223
234
AudioControllerThread::event( QEvent* e )
224
235
{
233
244
            LOGL( 1, "Somehow got a play event when not in stopped state. This is bad." );
234
245
            return true;
235
246
        }
236
 
        
 
247
 
237
248
        PlayEvent* playEvent = static_cast<PlayEvent*>( e );
238
249
        play( playEvent->m_url, playEvent->m_session );
239
250
        return true;
254
265
            // Each stop command must get a response even if we're not playing
255
266
            emit stateChanged( State_Stopped );
256
267
        }
257
 
        
 
268
 
258
269
        return true;
259
270
    }
260
271
    else if ( e->type() == (QEvent::Type)Event_Volume )
263
274
        m_output->setVolume( volumeEvent->m_volume );
264
275
        return true;
265
276
    }
266
 
        else if ( e->type() == (QEvent::Type)Event_ResetBufferSize )
267
 
        {
268
 
                if ( m_automaticBufferHandling )
269
 
                {
270
 
                        m_input->setBufferCapacity( Constants::kHttpBufferMinSize );            
271
 
                }
272
 
        }
273
 
    
 
277
    else if ( e->type() == (QEvent::Type)Event_ResetBufferSize )
 
278
    {
 
279
        if ( m_automaticBufferHandling )
 
280
        {
 
281
            m_input->setBufferCapacity( MooseConstants::kHttpBufferMinSize );
 
282
        }
 
283
    }
 
284
 
274
285
    return QThread::event( e );
275
286
}
276
287
 
 
288
 
277
289
void
278
 
AudioControllerThread::setStreamData( long sampleRate, int channels )
 
290
AudioControllerThread::setStreamData( long /*sampleRate*/, int /*channels*/ )
279
291
{
280
292
    // EJ: got rid of this because RtAudio occasionally fails to initialise
281
293
    // for no particular reason. In our case, we only deal with 44k stereo
283
295
    //m_output->initAudio( sampleRate, channels );
284
296
 
285
297
    m_output->startPlayback();
 
298
    m_proxyOutput->startPlayback();
286
299
 
287
300
    emit trackStarted();
288
301
}
289
302
 
 
303
 
290
304
void
291
305
AudioControllerThread::play( const QString& url, const QString& session )
292
306
{
299
313
    m_input->setSession( session );
300
314
    m_input->load( url );
301
315
    m_input->startStreaming();
302
 
    
 
316
 
303
317
    m_timeElapsedAtLastPause = 0;
304
318
    startTimer();
305
319
 
306
320
    playLoop();
307
321
}
308
322
 
309
 
void 
 
323
 
 
324
void
310
325
AudioControllerThread::playLoop()
311
326
{
312
327
    forever
317
332
            LOGL( 4, "Natural end detected" );
318
333
            setState( State_Stopping );
319
334
        }
320
 
        
 
335
 
321
336
        // Have we been told to stop?
322
337
        if ( state() == State_Stopping )
323
338
        {
333
348
                QByteArray data;
334
349
                m_input->data( data, kCompressedPacketSize );
335
350
 
 
351
                m_proxyOutput->processData( data );
336
352
                bool fine = m_transcode->processData( data );
337
 
                
 
353
 
338
354
                if ( !fine )
339
355
                {
340
356
                    LOGL( 2, "MP3 decoding failed, stopping." );
343
359
                }
344
360
            }
345
361
        }
346
 
        
 
362
 
347
363
        // Check transcode -> output step of pipe
348
364
        if ( m_output->needsData() )
349
365
        {
352
368
                QByteArray data;
353
369
                m_transcode->data( data, kUncompressedPacketSize );
354
370
 
355
 
                m_output->processData( data );
 
371
                if ( !m_proxyOutput || !m_proxyOutput->isActive() )
 
372
                    m_output->processData( data );
356
373
            }
357
374
        }
358
375
 
359
 
        #ifdef MONITOR_STREAMING
360
 
            emit httpBufferSizeChanged( m_input->bufferSize() );
361
 
            emit decodedBufferSizeChanged( m_transcode->bufferSize() );
362
 
            emit outputBufferSizeChanged( m_output->bufferSize() );
363
 
        #endif // MONITOR_STREAMING
 
376
        emit httpBufferSizeChanged( m_input->bufferSize() );
 
377
        emit decodedBufferSizeChanged( m_transcode->bufferSize() );
 
378
        emit outputBufferSizeChanged( m_output->bufferSize() );
364
379
 
365
380
        // This will process events for the current thread only
366
381
        QCoreApplication::processEvents();
371
386
    endTrack();
372
387
}
373
388
 
 
389
 
374
390
void
375
391
AudioControllerThread::endTrack()
376
392
{
379
395
    stopTimer();
380
396
    m_input->stopStreaming();
381
397
    m_output->stopPlayback();
 
398
    m_proxyOutput->stopPlayback();
382
399
 
383
400
    m_transcode->clearBuffers();
384
401
    m_output->clearBuffers();
385
402
 
386
 
    #ifdef MONITOR_STREAMING
387
 
        emit httpBufferSizeChanged( 0 );
388
 
        emit decodedBufferSizeChanged( 0 );
389
 
        emit outputBufferSizeChanged( 0 );
390
 
    #endif // MONITOR_STREAMING
 
403
  #ifdef MONITOR_STREAMING
 
404
    emit httpBufferSizeChanged( 0 );
 
405
    emit decodedBufferSizeChanged( 0 );
 
406
    emit outputBufferSizeChanged( 0 );
 
407
  #endif
391
408
 
392
409
    int elapsed = ( m_timeElapsedAtLastPause + m_timeSinceLastPause.elapsed() ) / 1000;
393
410
    emit trackEnded( elapsed );
395
412
    setState( State_Stopped );
396
413
}
397
414
 
 
415
 
398
416
void
399
417
AudioControllerThread::startTimer()
400
418
{
435
453
    {
436
454
        // We're still streaming, don't change state to stopped until the 
437
455
        // output is done streaming. Done in playLoop.
438
 
        
 
456
 
439
457
        // TODO: start prebuffering the next track in httpinput
440
458
    }
441
459
    else if ( newState == State_Stopped )
450
468
        {
451
469
            // We ran out of buffer, increase it
452
470
            int newSize = (int)( m_input->bufferCapacity() * 1.5f );
453
 
            newSize = qMin( Constants::kHttpBufferMaxSize, newSize );
 
471
            newSize = qMin( MooseConstants::kHttpBufferMaxSize, newSize );
454
472
            m_input->setBufferCapacity( newSize );
455
473
 
456
474
            LOGL( 3, "Automatically increased buffer size to: " << newSize );
474
492
 
475
493
    if ( newState != state() )
476
494
    {
477
 
        LOGL( 4, "AudioControllerThread state: " << CUtils::radioState2String( newState ) );
 
495
        LOGL( 4, "AudioControllerThread state: " << radioState2String( newState ) );
478
496
 
479
 
        m_mutex.lock();
 
497
        QMutexLocker locker( &m_mutex );
480
498
        m_state = newState;
481
 
        m_mutex.unlock();
 
499
        locker.unlock();
482
500
 
483
501
        emit stateChanged( newState );
484
502
    }
487
505
 
488
506
AudioController::AudioController() :
489
507
        m_state( State_Stopped ),
490
 
        m_lastTrackNotFound( false ),
491
 
        m_thread( this )
 
508
        m_thread( this ),
 
509
        m_streamerErrorCounter( 0 ),
 
510
        m_retryNextTrack( false )
492
511
{
493
512
    connect( &m_thread, SIGNAL( stateChanged( RadioState ) ),
494
513
             this,      SLOT  ( onThreadStateChanged( RadioState ) ),
506
525
             this,      SLOT  ( onStreamingError( int, const QString& ) ),
507
526
             Qt::QueuedConnection );
508
527
 
509
 
    m_thread.start( QThread::HighestPriority );
510
 
 
511
528
    // To avoid nasty surprises, let's wait until our worker thread is
512
529
    // initialised before we let the GUI thread carry on.
513
 
    m_mutex.lock();
 
530
    // We lock m_mutex here and make the thread wait for it to prevent
 
531
    // the thread from finishing initialisation before we have had
 
532
    // time to enter wait. Otherwise wait could wait forever.
 
533
    QMutexLocker locker( &m_mutex );
 
534
    m_thread.start( QThread::HighestPriority );
 
535
 
 
536
    // Once waiting, the m_mutex will be unlocked
514
537
    m_thread.m_initialised.wait( &m_mutex );
515
 
    m_mutex.unlock();
 
538
    locker.unlock();
516
539
 
517
540
    if ( m_thread.m_output != 0 )
518
541
    {
520
543
        m_soundSystems = m_thread.m_output->soundSystems();
521
544
        m_devices = m_thread.m_output->devices();
522
545
    }
523
 
 
524
 
#ifdef MONITOR_STREAMING
525
 
    m_monitor.setAudioController( this );
526
 
#endif    
527
546
}
528
547
 
529
548
 
556
575
    m_playlist = &playlist;
557
576
    loadNext();
558
577
 
559
 
        // We reset the automatically managed buffer size on station change
560
 
        AudioControllerThread::ResetBufferSizeEvent* e =
561
 
                new AudioControllerThread::ResetBufferSizeEvent();
 
578
    // We reset the automatically managed buffer size on station change
 
579
    AudioControllerThread::ResetBufferSizeEvent* e =
 
580
        new AudioControllerThread::ResetBufferSizeEvent();
562
581
    QCoreApplication::postEvent( m_thread.eventHandler(), e );
563
582
}
564
583
 
578
597
AudioController::play( const TrackInfo& track )
579
598
{
580
599
    m_playlist = 0;
581
 
    
 
600
 
582
601
    doPlay( track );
583
602
}
584
603
 
587
606
void
588
607
AudioController::doPlay( const TrackInfo& track )
589
608
{
590
 
    m_lastTrackNotFound = false;
591
 
    
 
609
    m_retryNextTrack = false;
 
610
 
592
611
    if ( !m_pendingTrack.isEmpty() )
593
612
    {
594
613
        // We will make no attempt at handling a queue of tracks coming in in
639
658
            setState( State_FetchingStream );
640
659
        }
641
660
        break;
642
 
        
 
661
 
643
662
        case State_FetchingStream:
644
663
        case State_StreamFetched:
645
664
        case State_Buffering:
682
701
    }
683
702
}
684
703
 
 
704
 
685
705
void
686
706
AudioController::loadNext()
687
707
{
697
717
    else
698
718
    {
699
719
        LOGL( 3, "AudioController ran out of playlist" );
700
 
        
 
720
 
701
721
        emit error( Radio_OutOfPlaylist,
702
722
            tr( "Sorry, there is no more content available for this station. Please choose a different one." ) );
703
723
 
704
 
                // Don't stop until after emitting the error as then the stopping state
705
 
                // won't be propagated up to the GUI just before the radio goes to
706
 
                // fetching stream state again.
707
 
                stop();
708
 
        }
 
724
        // Don't stop until after emitting the error as then the stopping state
 
725
        // won't be propagated up to the GUI just before the radio goes to
 
726
        // fetching stream state again.
 
727
        stop();
 
728
    }
709
729
}
710
730
 
 
731
 
711
732
void
712
733
AudioController::stop()
713
734
{
756
777
            if ( newState == State_Stopped )
757
778
            {
758
779
                LOGL( Logger::Debug, "Calling doPlay due to pending track" );
759
 
                
 
780
 
760
781
                setState( State_Stopped );
761
782
 
762
783
                // We started a new track before the previous one had finished
766
787
            }
767
788
        }
768
789
        break;
769
 
        
 
790
 
770
791
        case State_Stopping:
771
792
        {
772
793
            if ( newState == State_Stopped )
791
812
                    // Don't let this override
792
813
                }
793
814
                break;
794
 
                
 
815
 
795
816
                case State_Stopped:
796
817
                {
797
818
                    setState( State_Stopped );
798
819
 
799
 
                    if ( m_lastTrackNotFound && m_currentTrack.hasMorePaths() )
 
820
                    if ( m_retryNextTrack )
800
821
                    {
801
 
                        LOGL( Logger::Debug, "Got TrackNotFound and track has more "
802
 
                            "locations, trying next one." );
803
 
                        doPlay( m_currentTrack );
 
822
                        if ( m_currentTrack.hasMorePaths() )
 
823
                        {
 
824
                            LOGL( Logger::Debug, "Got TrackNotFound and track has more "
 
825
                                "locations, trying next one." );
 
826
                            doPlay( m_currentTrack );
 
827
                        }
 
828
                        else
 
829
                        {
 
830
                            LOGL( Logger::Debug, "Got TrackNotFound and track has no more "
 
831
                                "locations, calling loadNext." );
 
832
                            loadNext();
 
833
                        }
804
834
                    }
805
835
                    else
806
836
                    {
807
 
                        LOGL( Logger::Debug, "Calling loadNext due to thread "
808
 
                            "emitting Stopped when we weren't in a skipping "
809
 
                            "or a stopping state." );
 
837
                        LOGL( Logger::Debug, "Calling loadNext, thread emitted Stopped." );
810
838
                        loadNext();
811
839
                    }
812
840
                }
813
841
                break;
814
 
                
 
842
 
815
843
                default:
816
844
                {
817
845
                    setState( newState );
818
 
                }    
 
846
                }
819
847
            }
820
848
        }
821
849
    }
826
854
AudioController::onStreamingError( int error,
827
855
                                   const QString& reason )
828
856
{
 
857
    // This slot receives errors from not just the HttpInput, but also the
 
858
    // ACThread and the output.
 
859
 
829
860
    RadioError err = static_cast<RadioError>( error );
830
861
 
831
 
    if ( err == Radio_TrackNotFound  )
832
 
    {
833
 
        LOGL( Logger::Debug, "Got RadioTrackNotFound, setting m_lastTrackNotFound" );
834
 
 
835
 
        // I introduced this in order to fix a bug where the http input
836
 
        // emitted a TrackNotFound error and then a state change Stopped
837
 
        // error. Preciously I called doPlay/loadNext here but we can't do
838
 
        // that as the state change will then come along and do the same
839
 
        // thing. Only one slot in this class should be allowed to take
840
 
        // controlling actions. So we just note that we got a track not found
841
 
        // error here and take appropriate action once we get the state change.
842
 
        m_lastTrackNotFound = true;
843
 
    }
844
 
    else
845
 
    {
846
 
        stop();
847
 
        emit this->error( err, reason );
848
 
    }
 
862
    // These are the errors from the HttpInput on which we want to retry to
 
863
    // avoid disrupting radio stations if we can.
 
864
    if ( error == Radio_InvalidUrl ||
 
865
         error == Radio_InvalidAuth ||
 
866
         error == Radio_TrackNotFound ||
 
867
         error == Radio_UnknownError ||
 
868
         error == Radio_ConnectionRefused )
 
869
    {
 
870
        if ( ++m_streamerErrorCounter < k_streamerErrorLimit )
 
871
        {
 
872
            LOGL( Logger::Debug, "Got retryable radio error " << error << " from streamer, setting m_retryNextTrack" );
 
873
 
 
874
            // I introduced this in order to fix a bug where the http input
 
875
            // emitted a TrackNotFound error and then a state change Stopped
 
876
            // error. Preciously I called doPlay/loadNext here but we can't do
 
877
            // that as the state change will then come along and do the same
 
878
            // thing. Only one slot in this class should be allowed to take
 
879
            // controlling actions. So we just note that we got a track not found
 
880
            // error here and take appropriate action once we get the state change.
 
881
            m_retryNextTrack = true;
 
882
            return;
 
883
        }
 
884
    }
 
885
 
 
886
    // If it wasn't a retryable error, tell the world
 
887
    stop();
 
888
    emit this->error( err, reason );
 
889
    m_streamerErrorCounter = 0;
849
890
}
850
891
 
851
892
 
863
904
 
864
905
    if ( newState != m_state )
865
906
    {
866
 
        LOGL( 4, "AudioController state: " << CUtils::radioState2String( newState ) );
 
907
        LOGL( 4, "AudioController state: " << radioState2String( newState ) );
867
908
 
868
909
        m_state = newState;
869
910
 
870
911
        emit stateChanged( newState );
871
912
    }
 
913
 
 
914
    if ( m_state == State_Streaming )
 
915
    {
 
916
        m_streamerErrorCounter = 0;
 
917
    }
872
918
}