From 3d3d641e1cab1590dd45c523dae13e5640bde12f Mon Sep 17 00:00:00 2001 From: Jonas Kvinge Date: Sun, 22 Sep 2019 22:47:07 +0200 Subject: [PATCH] Fix player not using preloaded stream url breaking gapless playback Fixes #26 --- src/core/player.cpp | 12 ++++++------ src/core/song.cpp | 2 +- src/engine/gstenginepipeline.h | 2 +- src/playlist/playlistitem.h | 7 ++++++- 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/core/player.cpp b/src/core/player.cpp index a600404c5..2145fc0ae 100644 --- a/src/core/player.cpp +++ b/src/core/player.cpp @@ -352,12 +352,12 @@ void Player::HandleLoadResult(const UrlHandler::LoadResult &result) { if (is_current) { qLog(Debug) << "Playing song" << item->Metadata().title() << result.stream_url_; - engine_->Play(result.stream_url_, result.original_url_, stream_change_type_, item->Metadata().has_cue(), item->Metadata().beginning_nanosec(), item->Metadata().end_nanosec()); + engine_->Play(result.stream_url_, result.original_url_, stream_change_type_, song.has_cue(), song.beginning_nanosec(), song.end_nanosec()); current_item_ = item; } else if (is_next) { qLog(Debug) << "Preloading next song" << next_item->Metadata().title() << result.stream_url_; - engine_->StartPreloading(result.stream_url_, next_item->Url(), next_item->Metadata().has_cue(), next_item->Metadata().beginning_nanosec(), next_item->Metadata().end_nanosec()); + engine_->StartPreloading(result.stream_url_, next_item->Url(), song.has_cue(), song.beginning_nanosec(), song.end_nanosec()); } break; @@ -596,7 +596,7 @@ void Player::PlayAt(int index, Engine::TrackChangeFlags change, bool reshuffle) } current_item_ = app_->playlist_manager()->active()->current_item(); - const QUrl url = (current_item_->StreamUrl().isValid() ? current_item_->StreamUrl() : current_item_->Url()); + const QUrl url = current_item_->StreamUrl(); if (url_handlers_.contains(url.scheme())) { // It's already loading @@ -610,7 +610,7 @@ void Player::PlayAt(int index, Engine::TrackChangeFlags change, bool reshuffle) if (current_item_->HasTemporaryMetadata()) { app_->playlist_manager()->active()->InformOfCurrentSongChange(); } - engine_->Play(url, current_item_->Url(), change, current_item_->Metadata().has_cue(), current_item_->Metadata().beginning_nanosec(), current_item_->Metadata().end_nanosec()); + engine_->Play(url, current_item_->Url(), change, current_item_->Metadata().has_cue(), current_item_->effective_beginning_nanosec(), current_item_->effective_end_nanosec()); } } @@ -750,7 +750,7 @@ void Player::TrackAboutToEnd() { // Crossfade is off, so start preloading the next track so we don't get a gap between songs. if (!has_next_row || !next_item) return; - QUrl url = (next_item->StreamUrl().isValid() ? next_item->StreamUrl() : next_item->Url()); + QUrl url = next_item->StreamUrl(); // Get the actual track URL rather than the stream URL. if (url_handlers_.contains(url.scheme())) { @@ -771,7 +771,7 @@ void Player::TrackAboutToEnd() { } } - engine_->StartPreloading(url, next_item->Url(), next_item->Metadata().has_cue(), next_item->Metadata().beginning_nanosec(), next_item->Metadata().end_nanosec()); + engine_->StartPreloading(url, next_item->Url(), next_item->Metadata().has_cue(), next_item->effective_beginning_nanosec(), next_item->effective_end_nanosec()); } diff --git a/src/core/song.cpp b/src/core/song.cpp index 2c4830a24..938e88779 100644 --- a/src/core/song.cpp +++ b/src/core/song.cpp @@ -339,7 +339,7 @@ bool Song::has_embedded_cover() const { return d->art_automatic_.path() == kEmbe void Song::set_embedded_cover() { d->art_automatic_ = QUrl::fromLocalFile(kEmbeddedCover); } const QUrl &Song::stream_url() const { return d->stream_url_; } -const QUrl &Song::effective_stream_url() const { return d->stream_url_.isEmpty() ? d->url_ : d->stream_url_; } +const QUrl &Song::effective_stream_url() const { return !d->stream_url_.isEmpty() && d->stream_url_.isValid() ? d->stream_url_ : d->url_; } const QImage &Song::image() const { return d->image_; } const QString &Song::cue_path() const { return d->cue_path_; } diff --git a/src/engine/gstenginepipeline.h b/src/engine/gstenginepipeline.h index 9a292c255..e3f2cc9d9 100644 --- a/src/engine/gstenginepipeline.h +++ b/src/engine/gstenginepipeline.h @@ -94,7 +94,7 @@ class GstEnginePipeline : public QObject { // If this is set then it will be loaded automatically when playback finishes for gapless playback void SetNextUrl(const QByteArray &stream_url, const QUrl &original_url, qint64 beginning_nanosec, qint64 end_nanosec); - bool has_next_valid_url() const { return !next_stream_url_.isNull() && !next_stream_url_.isEmpty(); } + bool has_next_valid_url() const { return !next_stream_url_.isEmpty(); } void SetSourceDevice(QString device) { source_device_ = device; } diff --git a/src/playlist/playlistitem.h b/src/playlist/playlistitem.h index 9cafda690..1e1a03ad3 100644 --- a/src/playlist/playlistitem.h +++ b/src/playlist/playlistitem.h @@ -81,7 +81,12 @@ class PlaylistItem : public std::enable_shared_from_this { void SetTemporaryMetadata(const Song &metadata); void ClearTemporaryMetadata(); bool HasTemporaryMetadata() const { return temp_metadata_.is_valid(); } - QUrl StreamUrl() const { return HasTemporaryMetadata() && temp_metadata_.is_valid() && temp_metadata_.url().isValid() ? temp_metadata_.url() : QUrl(); } + + Song StreamMetadata() { return HasTemporaryMetadata() ? temp_metadata_ : Metadata(); } + QUrl StreamUrl() const { return HasTemporaryMetadata() && temp_metadata_.effective_stream_url().isValid() ? temp_metadata_.effective_stream_url() : Url(); } + + qint64 effective_beginning_nanosec() const { return HasTemporaryMetadata() && temp_metadata_.is_valid() && temp_metadata_.beginning_nanosec() != -1 ? temp_metadata_.beginning_nanosec() : Metadata().beginning_nanosec(); } + qint64 effective_end_nanosec() const { return HasTemporaryMetadata() && temp_metadata_.is_valid() && temp_metadata_.end_nanosec() != -1 ? temp_metadata_.end_nanosec() : Metadata().end_nanosec(); } // Background colors. void SetBackgroundColor(short priority, const QColor &color);