GstEngine: Make sure device is set for pipeline

Fixes #1852
This commit is contained in:
Jonas Kvinge
2025-12-18 00:21:00 +01:00
parent 9a513a9a56
commit ca2e802239
3 changed files with 58 additions and 17 deletions

View File

@@ -57,6 +57,7 @@
#include "core/enginemetadata.h"
#include "constants/timeconstants.h"
#include "enginebase.h"
#include "gsturl.h"
#include "gstengine.h"
#include "gstenginepipeline.h"
#include "gstbufferconsumer.h"
@@ -179,15 +180,18 @@ EngineBase::State GstEngine::state() const {
void GstEngine::StartPreloading(const QUrl &media_url, const QUrl &stream_url, const bool force_stop_at_end, const qint64 beginning_offset_nanosec, const qint64 end_offset_nanosec) {
const QByteArray gst_url = FixupUrl(stream_url);
const GstUrl gst_url = FixupUrl(stream_url);
// No crossfading, so we can just queue the new URL in the existing pipeline and get gapless playback (hopefully)
if (current_pipeline_) {
current_pipeline_->PrepareNextUrl(media_url, stream_url, gst_url, beginning_offset_nanosec, force_stop_at_end ? end_offset_nanosec : 0);
if (!gst_url.source_device.isEmpty()) {
current_pipeline_->SetSourceDevice(gst_url.source_device);
}
current_pipeline_->PrepareNextUrl(media_url, stream_url, gst_url.url, beginning_offset_nanosec, force_stop_at_end ? end_offset_nanosec : 0);
// Add request to discover the stream
if (discoverer_ && media_url.scheme() != u"spotify"_s) {
if (!gst_discoverer_discover_uri_async(discoverer_, gst_url.constData())) {
qLog(Error) << "Failed to start stream discovery for" << gst_url;
if (!gst_discoverer_discover_uri_async(discoverer_, gst_url.url.constData())) {
qLog(Error) << "Failed to start stream discovery for" << gst_url.url;
}
}
}
@@ -198,7 +202,7 @@ bool GstEngine::Load(const QUrl &media_url, const QUrl &stream_url, const Engine
EngineBase::Load(media_url, stream_url, change, force_stop_at_end, beginning_offset_nanosec, end_offset_nanosec, ebur128_integrated_loudness_lufs);
const QByteArray gst_url = FixupUrl(stream_url);
const GstUrl gst_url = FixupUrl(stream_url);
bool crossfade = current_pipeline_ && ((crossfade_enabled_ && change & EngineBase::TrackChangeType::Manual) || (autocrossfade_enabled_ && change & EngineBase::TrackChangeType::Auto) || ((crossfade_enabled_ || autocrossfade_enabled_) && change & EngineBase::TrackChangeType::Intro));
@@ -215,9 +219,14 @@ bool GstEngine::Load(const QUrl &media_url, const QUrl &stream_url, const Engine
}
}
GstEnginePipelinePtr pipeline = CreatePipeline(media_url, stream_url, gst_url, static_cast<qint64>(beginning_offset_nanosec), force_stop_at_end ? end_offset_nanosec : 0, ebur128_loudness_normalizing_gain_db_);
GstEnginePipelinePtr pipeline = CreatePipeline(media_url, stream_url, gst_url.url, static_cast<qint64>(beginning_offset_nanosec), force_stop_at_end ? end_offset_nanosec : 0, ebur128_loudness_normalizing_gain_db_);
if (!pipeline) return false;
// Set the source device if one was extracted from the URL
if (!gst_url.source_device.isEmpty()) {
pipeline->SetSourceDevice(gst_url.source_device);
}
GstEnginePipelinePtr old_pipeline = current_pipeline_;
current_pipeline_ = pipeline;
@@ -253,8 +262,8 @@ bool GstEngine::Load(const QUrl &media_url, const QUrl &stream_url, const Engine
// Add request to discover the stream
if (discoverer_ && media_url.scheme() != u"spotify"_s) {
if (!gst_discoverer_discover_uri_async(discoverer_, gst_url.constData())) {
qLog(Error) << "Failed to start stream discovery for" << gst_url;
if (!gst_discoverer_discover_uri_async(discoverer_, gst_url.url.constData())) {
qLog(Error) << "Failed to start stream discovery for" << gst_url.url;
}
}
@@ -814,16 +823,16 @@ void GstEngine::BufferingFinished() {
}
QByteArray GstEngine::FixupUrl(const QUrl &url) {
GstUrl GstEngine::FixupUrl(const QUrl &url) {
QByteArray uri;
GstUrl gst_url;
// It's a file:// url with a hostname set.
// QUrl::fromLocalFile does this when given a \\host\share\file path on Windows.
// Munge it back into a path that gstreamer will recognise.
if (url.isLocalFile() && !url.host().isEmpty()) {
QString str = "file:////"_L1 + url.host() + url.path();
uri = str.toUtf8();
gst_url.url = str.toUtf8();
}
else if (url.scheme() == "cdda"_L1) {
QString str;
@@ -837,16 +846,15 @@ QByteArray GstEngine::FixupUrl(const QUrl &url) {
// We keep the device in mind, and we will set it later using SourceSetupCallback
QStringList path = url.path().split(u'/');
str = QStringLiteral("cdda://%1").arg(path.takeLast());
QString device = path.join(u'/');
if (current_pipeline_) current_pipeline_->SetSourceDevice(device);
gst_url.source_device = path.join(u'/');
}
uri = str.toUtf8();
gst_url.url = str.toUtf8();
}
else {
uri = url.toEncoded();
gst_url.url = url.toEncoded();
}
return uri;
return gst_url;
}

View File

@@ -41,6 +41,7 @@
#include "includes/shared_ptr.h"
#include "enginebase.h"
#include "gsturl.h"
#include "gstenginepipeline.h"
#include "gstbufferconsumer.h"
@@ -123,7 +124,7 @@ class GstEngine : public EngineBase, public GstBufferConsumer {
void PipelineFinished(const int pipeline_id);
private:
QByteArray FixupUrl(const QUrl &url);
GstUrl FixupUrl(const QUrl &url);
void StartFadeout(GstEnginePipelinePtr pipeline);
void StartFadeoutPause();

32
src/engine/gsturl.h Normal file
View File

@@ -0,0 +1,32 @@
/*
* Strawberry Music Player
* Copyright 2025, Jonas Kvinge <jonas@jkvinge.net>
*
* Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Strawberry is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef GSTURL_H
#define GSTURL_H
#include <QByteArray>
#include <QString>
class GstUrl {
public:
QByteArray url;
QString source_device;
};
#endif // GSTURL_H