diff options
| -rw-r--r-- | src/plugins/Input/cue/decoder_cue.cpp | 27 | ||||
| -rw-r--r-- | src/qmmp/decoder.cpp | 25 | ||||
| -rw-r--r-- | src/qmmp/decoder.h | 57 | ||||
| -rw-r--r-- | src/qmmp/soundcore.cpp | 20 | ||||
| -rw-r--r-- | src/qmmp/soundcore.h | 18 | ||||
| -rw-r--r-- | src/qmmp/statehandler.cpp | 2 | ||||
| -rw-r--r-- | src/qmmp/statehandler.h | 2 | ||||
| -rw-r--r-- | src/qmmpui/mediaplayer.cpp | 41 | ||||
| -rw-r--r-- | src/qmmpui/mediaplayer.h | 2 |
9 files changed, 118 insertions, 76 deletions
diff --git a/src/plugins/Input/cue/decoder_cue.cpp b/src/plugins/Input/cue/decoder_cue.cpp index f65e17f79..6064025e6 100644 --- a/src/plugins/Input/cue/decoder_cue.cpp +++ b/src/plugins/Input/cue/decoder_cue.cpp @@ -122,6 +122,7 @@ bool DecoderCUE::initialize() connect(stateHandler(), SIGNAL(aboutToFinish()), SLOT(proccessFinish())); //prepare decoder and ouput objects m_decoder->initialize(); + qDebug("%lld == %lld", m_offset, m_length); m_decoder->setFragment(m_offset, m_length); //send metadata QMap<Qmmp::MetaData, QString> metaData = parser.info(track)->metaData(); @@ -257,34 +258,23 @@ void DecoderCUE::run() void DecoderCUE::proccessFinish() { - qDebug("==>%s", qPrintable(SoundCore::instance()->nextUrl())); - qDebug("==>%s", qPrintable(m_nextUrl)); - if(!SoundCore::instance()->nextUrl().isEmpty() - && !m_nextUrl.isEmpty() - && SoundCore::instance()->nextUrl() == m_nextUrl) + if(nextUrlRequest(m_nextUrl)) { - qDebug("prefinish"); - qDebug("next url: %s", qPrintable(m_nextUrl)); + qDebug("DecoderCUE: using next url"); int track = m_nextUrl.section("#", -1).toInt(); + qDebug("==%d", track); QString p = QUrl(m_nextUrl).path(); p.replace(QString(QUrl::toPercentEncoding("#")), "#"); p.replace(QString(QUrl::toPercentEncoding("%")), "%"); - + //update decoder's fragment CUEParser parser(p); m_length = parser.length(track); m_offset = parser.offset(track); m_decoder->mutex()->lock(); + qDebug("%lld == %lld", m_offset, m_length); m_decoder->setFragment(m_offset, m_length); m_output2->seek(0); m_decoder->mutex()->unlock(); - - //stateHandler()->dispatch(Qmmp::Stopped); - //stateHandler()->dispatch(Qmmp::Buffering); - //stateHandler()->dispatch(Qmmp::Playing); - //m_decoder->mutex()->lock(); - //m_output2->seek(0); - //m_decoder->mutex()->unlock(); - // find next track if(track <= parser.count() - 1) m_nextUrl = parser.info(track + 1)->path(); @@ -293,10 +283,11 @@ void DecoderCUE::proccessFinish() //is it track of another file? if(QUrl(m_nextUrl).path() != p) m_nextUrl.clear(); + //change track emit playbackFinished(); + QMap<Qmmp::MetaData, QString> metaData = parser.info(track)->metaData(); + stateHandler()->dispatch(metaData); } - else - Decoder::stop(); } CUEStateHandler::CUEStateHandler(QObject *parent): StateHandler(parent){} diff --git a/src/qmmp/decoder.cpp b/src/qmmp/decoder.cpp index ebbd2528b..f6a9b95f9 100644 --- a/src/qmmp/decoder.cpp +++ b/src/qmmp/decoder.cpp @@ -95,6 +95,7 @@ void Decoder::init() _m_length_in_bytes = 0; _m_offset = 0; _m_totalBytes = 0; + _m_useNextUrl = FALSE; } DecoderFactory *Decoder::factory() const @@ -193,9 +194,26 @@ void Decoder::setFragment(qint64 offset, qint64 length) void Decoder::stop() { + _m_nextUrl.clear(); _m_user_stop = TRUE; } +void Decoder::setNextUrl(const QString &url) +{ + _m_nextUrl = url; +} + +void Decoder::clearNextUrl() +{ + _m_nextUrl.clear(); + _m_useNextUrl = FALSE; +} + +bool Decoder::nextUrlAccepted() +{ + return _m_useNextUrl; +} + qint64 Decoder::produceSound(char *data, qint64 size, quint32 brate, int chan) { ulong sz = size < _blksize ? size : _blksize; @@ -310,7 +328,6 @@ void Decoder::run() else if (len == 0) { flush(TRUE); - if (output()) { output()->recycler()->mutex()->lock (); @@ -370,6 +387,12 @@ void Decoder::flush(bool final) } } +bool Decoder::nextUrlRequest(const QString &url) +{ + _m_useNextUrl = !_m_nextUrl.isEmpty() && (_m_nextUrl == url); + return _m_useNextUrl; +} + // static methods QList<DecoderFactory*> *Decoder::m_factories = 0; DecoderFactory *Decoder::m_lastFactory = 0; diff --git a/src/qmmp/decoder.h b/src/qmmp/decoder.h index a0a311da9..73506a3ad 100644 --- a/src/qmmp/decoder.h +++ b/src/qmmp/decoder.h @@ -67,26 +67,42 @@ public: virtual qint64 totalTime() = 0; /*! * Requests a seek to the time \b time indicated, specified in milliseconds. - * Subclass should reimplement this function. */ virtual void seek(qint64 time); /*! * Requests playback to stop - * Subclass should reimplement this function. */ virtual void stop(); - + /*! + * Returns current bitrate (in kbps). + * Subclass should reimplement this function. + */ virtual int bitrate(); - /*! * Requests playback to pause. If it was paused already, playback should resume. * Subclass with own output should reimplement this function. */ virtual void pause(); - - + /*! + * Tells decoder about next track. It may be useful for gapless playback. + * @param url Url of the next item in the playlist + */ + void setNextUrl(const QString &url); + /*! + * Removes information about next url + */ + void clearNextUrl(); + /*! + * Return \b true if the decoder can play next url without reinitialization; + * otherwise returns \b false + */ + bool nextUrlAccepted(); + /*! + * Setups fragment for playback. + * @param offset Fragment offset in milliseconds + * @param length Fragment duration in milliseconds + */ void setFragment(qint64 offset, qint64 length); - /*! * Returns decoder's factory object. */ @@ -182,8 +198,6 @@ public: */ static bool isEnabled(DecoderFactory* factory); - bool isFinished(){return _m_user_stop;} - signals: /*! * Emitted when the decoder has finished playback. @@ -191,10 +205,21 @@ signals: void playbackFinished(); protected: + /*! + * Reads up to \b maxSize bytes of decoded audio to \b data + * Returns the number of bytes read, or -1 if an error occurred. + * In most cases subclass should reimplement this function. + */ virtual qint64 readAudio(char *data, qint64 maxSize); - + /*! + * Sets current playback position. + * In most cases subclass should reimplement this function. + * @param time New position for playback in milliseconds + */ virtual void seekAudio(qint64 time); - + /*! + * The starting point for the decoding thread. + */ virtual void run(); /*! * Use this function inside initialize() reimplementation to tell other plugins about audio parameters. @@ -211,8 +236,11 @@ protected: * @param chan Number of channels. */ qint64 produceSound(char *data, qint64 size, quint32 brate, int chan); - - + /*! + * Use this function to check next url. + * Returns \b true if url of the next playlist item same as \b url; otherwise returns \b false + */ + bool nextUrlRequest(const QString &url); protected slots: /*! @@ -237,6 +265,9 @@ private: bool _m_eqInited; bool _m_useEQ; bool _m_done, _m_finish, _m_user_stop; + bool _m_useNextUrl; + + QString _m_nextUrl; ulong _m_bks; qint64 _m_totalTime, _m_seekTime, _m_totalBytes; diff --git a/src/qmmp/soundcore.cpp b/src/qmmp/soundcore.cpp index e335d1580..0684fec42 100644 --- a/src/qmmp/soundcore.cpp +++ b/src/qmmp/soundcore.cpp @@ -73,18 +73,18 @@ SoundCore::~SoundCore() bool SoundCore::play(const QString &source) { - qDebug("==%s", qPrintable(source)); - qDebug("==%s",qPrintable(m_next)); - if((m_next == source) && m_decoder && !m_decoder->isFinished() - && m_decoder->factory()->properties().noOutput) + if(m_decoder && m_decoder->nextUrlAccepted()) //decoder can play next url { + //fake stop/start cycle m_handler->dispatch(Qmmp::Stopped); m_handler->dispatch(Qmmp::Playing); m_handler->dispatch(Qmmp::Buffering); m_handler->dispatch(Qmmp::Playing); m_source = source; + m_decoder->clearNextUrl(); return TRUE; } + qDebug("stop!"); stop(); m_source = source; @@ -145,15 +145,21 @@ bool SoundCore::play(const QString &source) return FALSE; } -void SoundCore::setNext(const QString &source) +void SoundCore::setNextUrl(const QString &source) { - m_next = source; + if(m_decoder) + m_decoder->setNextUrl(source); +} + +void SoundCore::clearNextUrl() +{ + if(m_decoder) + m_decoder->clearNextUrl(); } void SoundCore::stop() { m_factory = 0; - //m_next.clear(); m_source.clear(); if (m_decoder /*&& m_decoder->isRunning()*/) { diff --git a/src/qmmp/soundcore.h b/src/qmmp/soundcore.h index b39fab1d2..f099318e3 100644 --- a/src/qmmp/soundcore.h +++ b/src/qmmp/soundcore.h @@ -127,8 +127,15 @@ public slots: * otherwise returns \b false. Useful for invalid files skipping. */ bool play(const QString &source); - - void setNext(const QString &source); + /*! + * Tells decoder about next track. It may be useful for gapless playback. + * @param source Url of the next item in the playlist + */ + void setNextUrl(const QString &source); + /*! + * Removes information about next url + */ + void clearNextUrl(); /*! * Stops playback */ @@ -146,8 +153,6 @@ public slots: */ const QString url(); - const QString nextUrl(){return m_next;} - signals: /*! * This signal is emitted when the stream reader fills it's buffer. @@ -198,8 +203,7 @@ signals: */ void volumeChanged(int left, int right); /*! - * Emitted before the playback ends. Use this signal to tell decoder about next track. - * This may be useful for multitrack formats like CDA or cue sheets. + * Emitted before the playback ends. */ void aboutToFinish(); @@ -209,8 +213,6 @@ private slots: private: Decoder* m_decoder; DecoderFactory* m_factory; - //QUrl m_url; - QString m_next; QString m_source; Output* m_output; QIODevice* m_input; diff --git a/src/qmmp/statehandler.cpp b/src/qmmp/statehandler.cpp index 1086e477b..8ccd46e82 100644 --- a/src/qmmp/statehandler.cpp +++ b/src/qmmp/statehandler.cpp @@ -24,7 +24,7 @@ #include "statehandler.h" #define TICK_INTERVAL 250 -#define PREFINISH_TIME 5000 +#define PREFINISH_TIME 2000 StateHandler* StateHandler::m_instance = 0; diff --git a/src/qmmp/statehandler.h b/src/qmmp/statehandler.h index 0e64b0a7e..3eb3c2036 100644 --- a/src/qmmp/statehandler.h +++ b/src/qmmp/statehandler.h @@ -139,7 +139,7 @@ signals: */ void finished(); /*! - * Emitted before the playback ends. Use this signal to tell decoder about next track. + * Emitted before the playback ends. Use this signal inside decoder to check next url. * This may be useful for multitrack formats like CDA or cue sheets. */ void aboutToFinish(); diff --git a/src/qmmpui/mediaplayer.cpp b/src/qmmpui/mediaplayer.cpp index 3f7545091..42a0cf6b8 100644 --- a/src/qmmpui/mediaplayer.cpp +++ b/src/qmmpui/mediaplayer.cpp @@ -64,7 +64,7 @@ void MediaPlayer::initialize(SoundCore *core, PlayListModel *model) m_model = model; m_repeat = FALSE; connect(m_core, SIGNAL(finished()), SLOT(next())); - connect(m_core, SIGNAL(aboutToFinish()), SLOT(sendNext())); + //connect(m_model, SIGNAL(listChanged()), SLOT(updateNextUrl())); } PlayListModel *MediaPlayer::playListModel() @@ -79,9 +79,8 @@ bool MediaPlayer::isRepeatable() const void MediaPlayer::play() { - qDebug("+1"); + disconnect(m_model, SIGNAL(listChanged()), this, SLOT(updateNextUrl())); m_model->doCurrentVisibleRequest(); - qDebug("+2"); if (m_core->state() == Qmmp::Paused) { m_core->pause(); @@ -90,15 +89,13 @@ void MediaPlayer::play() if (m_model->count() == 0) return; - qDebug("+3"); + QString s = m_model->currentItem()->url(); if (s.isEmpty()) return; - qDebug("+4"); - //m_core->setNext (m_model->nextItem()->url()); + if (!m_core->play(s)) { - qDebug("+5"); //find out the reason why playback failed switch ((int) m_core->state()) { @@ -134,17 +131,9 @@ void MediaPlayer::play() } else { - qDebug("1"); m_skips = 0; - qDebug("2"); - if(m_model->nextItem()) - { - qDebug("3"); - m_core->setNext (m_model->nextItem()->url()); - qDebug("MediaPlayer: current item: %s",qPrintable(m_core->url())); - qDebug("MediaPlayer: next item: %s",qPrintable(m_core->nextUrl())); - qDebug("4"); - } + updateNextUrl(); + connect(m_model, SIGNAL(listChanged()), this, SLOT(updateNextUrl())); } } @@ -155,6 +144,7 @@ void MediaPlayer::stop() void MediaPlayer::next() { + disconnect(m_model, SIGNAL(listChanged()), this, SLOT(updateNextUrl())); if (!m_model->isEmptyQueue()) { m_model->setCurrentToQueued(); @@ -164,7 +154,7 @@ void MediaPlayer::next() stop(); return; } - //m_playlist->update(); + if (m_core->state() != Qmmp::Stopped) { if (m_core->state() == Qmmp::Paused) @@ -175,22 +165,19 @@ void MediaPlayer::next() void MediaPlayer::previous() { + disconnect(m_model, SIGNAL(listChanged()), this, SLOT(updateNextUrl())); if (!m_model->previous()) { stop(); - //display->hideTimeDisplay(); return; } - //m_playlist->update(); if (m_core->state() != Qmmp::Stopped) { if (m_core->state() == Qmmp::Paused) stop(); play(); } - /*else - display->hideTimeDisplay();*/ } void MediaPlayer::setRepeatable(bool r) @@ -207,11 +194,13 @@ void MediaPlayer::setRepeatable(bool r) } m_repeat = r; emit repeatableChanged(r); + updateNextUrl(); } -void MediaPlayer::sendNext() +void MediaPlayer::updateNextUrl() { - /*if(m_model->nextItem()) - qDebug("MediaPlayer: next item: %s",qPrintable(m_model->nextItem()->url()));*/ + if(m_model->nextItem() && !isRepeatable()) + m_core->setNextUrl(m_model->nextItem()->url()); + else + m_core->clearNextUrl(); } - diff --git a/src/qmmpui/mediaplayer.h b/src/qmmpui/mediaplayer.h index c4f5d5bdd..327b9c980 100644 --- a/src/qmmpui/mediaplayer.h +++ b/src/qmmpui/mediaplayer.h @@ -91,7 +91,7 @@ signals: void repeatableChanged(bool enabled); private slots: - void sendNext(); + void updateNextUrl(); private: PlayListModel *m_model; |
