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
***************************************************************************/
22
22
#include "AudioController.h"
23
#include "lastfm_common.h"
25
24
#include "interfaces/InputInterface.h"
26
25
#include "interfaces/TranscodeInterface.h"
27
26
#include "interfaces/OutputInterface.h"
29
#include "containerutils.h"
27
#include "MooseCommon.h"
28
#include "LastFmSettings.h"
31
#include "ProxyOutput.h"
33
33
#include "output/RtAudio/rtaudioplayback.h"
35
35
#include <QFileInfo>
36
#include <QMutexLocker>
36
37
#include <QPluginLoader>
38
39
// RADIO STREAMING CONSTANTS
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;
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;
66
// Max number of errors in a row before we abort
67
static const int k_streamerErrorLimit = 5;
66
69
AudioControllerThread::AudioControllerThread( QObject* parent ) :
71
m_state( State_Stopped ),
75
m_state( State_Stopped ),
72
76
m_timeElapsedAtLastPause( 0 ),
73
77
m_automaticBufferHandling( true )
80
83
AudioControllerThread::run()
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();
82
90
// Initialise our in-thread services
83
91
m_handler = new AudioControllerEventHandler( this );
96
104
m_output->setParent( m_handler );
98
106
m_timer = new QTimer( m_handler );
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
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 )
155
m_input->setBufferCapacity( Constants::kHttpBufferMinSize );
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 )
162
169
m_transcode->setBufferCapacity( kDecodedBufferMinSize );
165
172
m_output = qobject_cast<OutputInterface*>( loadPlugin( "rtaudioplayback" ) );
166
173
#elif defined LINUX
212
223
else if ( newAuto && !m_automaticBufferHandling )
214
225
// Switched on automatic
215
m_input->setBufferCapacity( Constants::kHttpBufferMinSize );
226
m_input->setBufferCapacity( MooseConstants::kHttpBufferMinSize );
218
229
m_automaticBufferHandling = newAuto;
223
234
AudioControllerThread::event( QEvent* e )
263
274
m_output->setVolume( volumeEvent->m_volume );
266
else if ( e->type() == (QEvent::Type)Event_ResetBufferSize )
268
if ( m_automaticBufferHandling )
270
m_input->setBufferCapacity( Constants::kHttpBufferMinSize );
277
else if ( e->type() == (QEvent::Type)Event_ResetBufferSize )
279
if ( m_automaticBufferHandling )
281
m_input->setBufferCapacity( MooseConstants::kHttpBufferMinSize );
274
285
return QThread::event( e );
278
AudioControllerThread::setStreamData( long sampleRate, int channels )
290
AudioControllerThread::setStreamData( long /*sampleRate*/, int /*channels*/ )
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 );
285
297
m_output->startPlayback();
298
m_proxyOutput->startPlayback();
287
300
emit trackStarted();
291
305
AudioControllerThread::play( const QString& url, const QString& session )
334
349
m_input->data( data, kCompressedPacketSize );
351
m_proxyOutput->processData( data );
336
352
bool fine = m_transcode->processData( data );
340
356
LOGL( 2, "MP3 decoding failed, stopping." );
353
369
m_transcode->data( data, kUncompressedPacketSize );
355
m_output->processData( data );
371
if ( !m_proxyOutput || !m_proxyOutput->isActive() )
372
m_output->processData( data );
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() );
365
380
// This will process events for the current thread only
366
381
QCoreApplication::processEvents();
380
396
m_input->stopStreaming();
381
397
m_output->stopPlayback();
398
m_proxyOutput->stopPlayback();
383
400
m_transcode->clearBuffers();
384
401
m_output->clearBuffers();
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 );
392
409
int elapsed = ( m_timeElapsedAtLastPause + m_timeSinceLastPause.elapsed() ) / 1000;
393
410
emit trackEnded( elapsed );
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 );
456
474
LOGL( 3, "Automatically increased buffer size to: " << newSize );
475
493
if ( newState != state() )
477
LOGL( 4, "AudioControllerThread state: " << CUtils::radioState2String( newState ) );
495
LOGL( 4, "AudioControllerThread state: " << radioState2String( newState ) );
497
QMutexLocker locker( &m_mutex );
480
498
m_state = newState;
483
501
emit stateChanged( newState );
488
506
AudioController::AudioController() :
489
507
m_state( State_Stopped ),
490
m_lastTrackNotFound( false ),
509
m_streamerErrorCounter( 0 ),
510
m_retryNextTrack( false )
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 );
509
m_thread.start( QThread::HighestPriority );
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.
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 );
536
// Once waiting, the m_mutex will be unlocked
514
537
m_thread.m_initialised.wait( &m_mutex );
517
540
if ( m_thread.m_output != 0 )
556
575
m_playlist = &playlist;
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 );
588
607
AudioController::doPlay( const TrackInfo& track )
590
m_lastTrackNotFound = false;
609
m_retryNextTrack = false;
592
611
if ( !m_pendingTrack.isEmpty() )
594
613
// We will make no attempt at handling a queue of tracks coming in in
699
719
LOGL( 3, "AudioController ran out of playlist" );
701
721
emit error( Radio_OutOfPlaylist,
702
722
tr( "Sorry, there is no more content available for this station. Please choose a different one." ) );
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.
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.
712
733
AudioController::stop()
791
812
// Don't let this override
795
816
case State_Stopped:
797
818
setState( State_Stopped );
799
if ( m_lastTrackNotFound && m_currentTrack.hasMorePaths() )
820
if ( m_retryNextTrack )
801
LOGL( Logger::Debug, "Got TrackNotFound and track has more "
802
"locations, trying next one." );
803
doPlay( m_currentTrack );
822
if ( m_currentTrack.hasMorePaths() )
824
LOGL( Logger::Debug, "Got TrackNotFound and track has more "
825
"locations, trying next one." );
826
doPlay( m_currentTrack );
830
LOGL( Logger::Debug, "Got TrackNotFound and track has no more "
831
"locations, calling loadNext." );
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." );
817
845
setState( newState );
826
854
AudioController::onStreamingError( int error,
827
855
const QString& reason )
857
// This slot receives errors from not just the HttpInput, but also the
858
// ACThread and the output.
829
860
RadioError err = static_cast<RadioError>( error );
831
if ( err == Radio_TrackNotFound )
833
LOGL( Logger::Debug, "Got RadioTrackNotFound, setting m_lastTrackNotFound" );
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;
847
emit this->error( err, reason );
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 )
870
if ( ++m_streamerErrorCounter < k_streamerErrorLimit )
872
LOGL( Logger::Debug, "Got retryable radio error " << error << " from streamer, setting m_retryNextTrack" );
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;
886
// If it wasn't a retryable error, tell the world
888
emit this->error( err, reason );
889
m_streamerErrorCounter = 0;
864
905
if ( newState != m_state )
866
LOGL( 4, "AudioController state: " << CUtils::radioState2String( newState ) );
907
LOGL( 4, "AudioController state: " << radioState2String( newState ) );
868
909
m_state = newState;
870
911
emit stateChanged( newState );
914
if ( m_state == State_Streaming )
916
m_streamerErrorCounter = 0;