diff --git a/CMakeLists.txt b/CMakeLists.txt index fa5a28bf2..4e56401d3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -850,7 +850,6 @@ set(HEADERS src/engine/enginebase.h src/engine/devicefinders.h - src/engine/gststartup.h src/engine/gstengine.h src/engine/gstenginepipeline.h diff --git a/src/core/application.cpp b/src/core/application.cpp index ee52e8110..a0325d5a9 100644 --- a/src/core/application.cpp +++ b/src/core/application.cpp @@ -3,7 +3,7 @@ * This file was part of Clementine. * Copyright 2012, David Sansome * Copyright 2012, 2014, John Maguire - * Copyright 2018-2021, Jonas Kvinge + * Copyright 2018-2024, Jonas Kvinge * * Strawberry is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,9 +28,14 @@ #include #include +#include + #include #include #include +#include +#include +#include #include "core/logging.h" @@ -241,10 +246,17 @@ class ApplicationImpl { }; Application::Application(QObject *parent) - : QObject(parent), p_(new ApplicationImpl(this)) { + : QObject(parent), + p_(new ApplicationImpl(this)), + g_thread_(nullptr) { setObjectName(QLatin1String(metaObject()->className())); + const QMetaObject *mo = QAbstractEventDispatcher::instance(QCoreApplication::instance()->thread())->metaObject(); + if (mo && strcmp(mo->className(), "QEventDispatcherGlib") != 0 && strcmp(mo->superClass()->className(), "QEventDispatcherGlib") != 0) { + g_thread_ = g_thread_new(nullptr, Application::GLibMainLoopThreadFunc, nullptr); + } + device_finders()->Init(); collection()->Init(); tagreader_client(); @@ -264,6 +276,22 @@ Application::~Application() { thread->deleteLater(); } + if (g_thread_) g_thread_unref(g_thread_); + +} + +gpointer Application::GLibMainLoopThreadFunc(gpointer data) { + + Q_UNUSED(data) + + qLog(Info) << "Creating GLib main event loop."; + + GMainLoop *gloop = g_main_loop_new(nullptr, false); + g_main_loop_run(gloop); + g_main_loop_unref(gloop); + + return nullptr; + } QThread *Application::MoveToNewThread(QObject *object) { diff --git a/src/core/application.h b/src/core/application.h index 901d45533..38185fa73 100644 --- a/src/core/application.h +++ b/src/core/application.h @@ -3,7 +3,7 @@ * This file was part of Clementine. * Copyright 2012, David Sansome * Copyright 2012, 2014, John Maguire - * Copyright 2018-2021, Jonas Kvinge + * Copyright 2018-2024, Jonas Kvinge * * Strawberry is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,6 +25,8 @@ #include "config.h" +#include + #include #include #include @@ -114,8 +116,12 @@ class Application : public QObject { Q_SIGNALS: void ExitFinished(); + private: + static gpointer GLibMainLoopThreadFunc(gpointer data); + private: ScopedPtr p_; + GThread *g_thread_; QList threads_; QList wait_for_exit_; }; diff --git a/src/core/player.cpp b/src/core/player.cpp index 1c0f57cfc..ec49fb872 100644 --- a/src/core/player.cpp +++ b/src/core/player.cpp @@ -53,7 +53,6 @@ #include "engine/enginebase.h" #include "engine/gstengine.h" -#include "engine/gststartup.h" #include "collection/collectionbackend.h" #include "playlist/playlist.h" @@ -80,7 +79,6 @@ Player::Player(const SharedPtr task_manager, const SharedPtr gst_engine(new GstEngine(task_manager_)); - gst_engine->SetStartup(gst_startup_); engine_.reset(gst_engine.release()); break; } diff --git a/src/core/player.h b/src/core/player.h index ec6c3aeb1..db0dbc747 100644 --- a/src/core/player.h +++ b/src/core/player.h @@ -47,7 +47,6 @@ class UrlHandlers; class PlaylistManager; class AnalyzerContainer; class Equalizer; -class GstStartup; class Player : public PlayerInterface { Q_OBJECT @@ -144,7 +143,6 @@ class Player : public PlayerInterface { const SharedPtr url_handlers_; const SharedPtr playlist_manager_; SharedPtr engine_; - GstStartup *gst_startup_; AnalyzerContainer *analyzer_; SharedPtr equalizer_; QTimer *timer_save_volume_; diff --git a/src/engine/gstengine.cpp b/src/engine/gstengine.cpp index 37ecf6e3f..4cfae4558 100644 --- a/src/engine/gstengine.cpp +++ b/src/engine/gstengine.cpp @@ -2,7 +2,7 @@ * Copyright (C) 2003-2005 by Mark Kretschmann * * Copyright (C) 2005 by Jakub Stachowski * * Copyright (C) 2006 Paul Cifarelli * - * Copyright (C) 2017-2021 Jonas Kvinge * + * Copyright (C) 2017-2024 Jonas Kvinge * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -97,7 +97,6 @@ constexpr qint64 kSeekDelayNanosec = 100 * kNsecPerMsec; // 100msec GstEngine::GstEngine(SharedPtr task_manager, QObject *parent) : EngineBase(parent), task_manager_(task_manager), - gst_startup_(nullptr), discoverer_(nullptr), buffering_task_id_(-1), latest_buffer_(nullptr), @@ -129,7 +128,6 @@ GstEngine::GstEngine(SharedPtr task_manager, QObject *parent) GstEngine::~GstEngine() { - EnsureInitialized(); current_pipeline_.reset(); if (latest_buffer_) { @@ -181,8 +179,6 @@ 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_nanosec, const qint64 end_nanosec) { - EnsureInitialized(); - const QByteArray gst_url = FixupUrl(stream_url); // No crossfading, so we can just queue the new URL in the existing pipeline and get gapless playback (hopefully) @@ -200,8 +196,6 @@ void GstEngine::StartPreloading(const QUrl &media_url, const QUrl &stream_url, c bool GstEngine::Load(const QUrl &media_url, const QUrl &stream_url, const EngineBase::TrackChangeFlags change, const bool force_stop_at_end, const quint64 beginning_nanosec, const qint64 end_nanosec, const std::optional ebur128_integrated_loudness_lufs) { - EnsureInitialized(); - EngineBase::Load(media_url, stream_url, change, force_stop_at_end, beginning_nanosec, end_nanosec, ebur128_integrated_loudness_lufs); const QByteArray gst_url = FixupUrl(stream_url); @@ -270,8 +264,6 @@ bool GstEngine::Load(const QUrl &media_url, const QUrl &stream_url, const Engine bool GstEngine::Play(const bool pause, const quint64 offset_nanosec) { - EnsureInitialized(); - if (!current_pipeline_ || current_pipeline_->is_buffering() || current_pipeline_->state() == GstState::GST_STATE_PLAYING) return false; if (OldExclusivePipelineActive()) { @@ -458,8 +450,6 @@ const EngineBase::Scope &GstEngine::scope(const int chunk_length) { EngineBase::OutputDetailsList GstEngine::GetOutputsList() const { - const_cast(this)->EnsureInitialized(); - OutputDetailsList outputs; GstRegistry *registry = gst_registry_get(); @@ -498,8 +488,6 @@ EngineBase::OutputDetailsList GstEngine::GetOutputsList() const { bool GstEngine::ValidOutput(const QString &output) { - EnsureInitialized(); - const OutputDetailsList output_details = GetOutputsList(); return std::any_of(output_details.begin(), output_details.end(), [output](const OutputDetails &output_detail) { return output_detail.name == output; }); @@ -804,8 +792,6 @@ void GstEngine::BufferingFinished() { QByteArray GstEngine::FixupUrl(const QUrl &url) { - EnsureInitialized(); - QByteArray uri; // It's a file:// url with a hostname set. @@ -901,8 +887,6 @@ void GstEngine::StopTimers() { GstEnginePipelinePtr GstEngine::CreatePipeline() { - EnsureInitialized(); - GstEnginePipelinePtr pipeline = make_shared(); pipeline->set_output_device(output_, device_); pipeline->set_exclusive_mode(exclusive_mode_); diff --git a/src/engine/gstengine.h b/src/engine/gstengine.h index da2003773..b76eea5fd 100644 --- a/src/engine/gstengine.h +++ b/src/engine/gstengine.h @@ -2,7 +2,7 @@ * Copyright (C) 2003-2005 by Mark Kretschmann * * Copyright (C) 2005 by Jakub Stachowski * * Copyright (C) 2006 Paul Cifarelli * - * Copyright (C) 2017-2021 Jonas Kvinge * + * Copyright (C) 2017-2024 Jonas Kvinge * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -41,7 +41,6 @@ #include "includes/shared_ptr.h" #include "enginebase.h" -#include "gststartup.h" #include "gstenginepipeline.h" #include "gstbufferconsumer.h" @@ -85,9 +84,6 @@ class GstEngine : public EngineBase, public GstBufferConsumer { bool ALSADeviceSupport(const QString &output) const override; bool ExclusiveModeSupport(const QString &output) const override; - void SetStartup(GstStartup *gst_startup) { gst_startup_ = gst_startup; } - void EnsureInitialized() { gst_startup_->EnsureInitialized(); } - void ConsumeBuffer(GstBuffer *buffer, const int pipeline_id, const QString &format) override; public Q_SLOTS: @@ -153,7 +149,6 @@ class GstEngine : public EngineBase, public GstBufferConsumer { private: SharedPtr task_manager_; - GstStartup *gst_startup_; GstDiscoverer *discoverer_; int buffering_task_id_; diff --git a/src/engine/gstenginepipeline.cpp b/src/engine/gstenginepipeline.cpp index 548f6142a..f442a72f6 100644 --- a/src/engine/gstenginepipeline.cpp +++ b/src/engine/gstenginepipeline.cpp @@ -2,7 +2,7 @@ * Strawberry Music Player * This file was part of Clementine. * Copyright 2010, David Sansome - * Copyright 2018-2021, Jonas Kvinge + * Copyright 2018-2024, Jonas Kvinge * * Strawberry is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/engine/gstenginepipeline.h b/src/engine/gstenginepipeline.h index a91c04fe4..4ba32356b 100644 --- a/src/engine/gstenginepipeline.h +++ b/src/engine/gstenginepipeline.h @@ -2,7 +2,7 @@ * Strawberry Music Player * This file was part of Clementine. * Copyright 2010, David Sansome - * Copyright 2018-2021, Jonas Kvinge + * Copyright 2018-2024, Jonas Kvinge * * Strawberry is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/engine/gststartup.cpp b/src/engine/gststartup.cpp index c56702840..b34108fe9 100644 --- a/src/engine/gststartup.cpp +++ b/src/engine/gststartup.cpp @@ -1,6 +1,6 @@ /* * Strawberry Music Player - * Copyright 2018-2021, Jonas Kvinge + * Copyright 2018-2024, Jonas Kvinge * * Strawberry is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,15 +25,11 @@ #include #include -#include -#include #include #include -#include #include #include #include -#include #include "core/logging.h" #include "utilities/envutils.h" @@ -46,38 +42,9 @@ using namespace Qt::Literals::StringLiterals; -GThread *GstStartup::kGThread = nullptr; +namespace GstStartup { -gpointer GstStartup::GLibMainLoopThreadFunc(gpointer data) { - - Q_UNUSED(data) - - qLog(Info) << "Creating GLib main event loop."; - - GMainLoop *gloop = g_main_loop_new(nullptr, false); - g_main_loop_run(gloop); - g_main_loop_unref(gloop); - - return nullptr; - -} - -GstStartup::GstStartup(QObject *parent) : QObject(parent) { - - initializing_ = QtConcurrent::run(&GstStartup::InitializeGStreamer); - - const QMetaObject *mo = QAbstractEventDispatcher::instance(qApp->thread())->metaObject(); - if (mo && strcmp(mo->className(), "QEventDispatcherGlib") != 0 && strcmp(mo->superClass()->className(), "QEventDispatcherGlib") != 0) { - kGThread = g_thread_new(nullptr, GstStartup::GLibMainLoopThreadFunc, nullptr); - } - -} - -GstStartup::~GstStartup() { - if (kGThread) g_thread_unref(kGThread); -} - -void GstStartup::InitializeGStreamer() { +void Initialize() { SetEnvironment(); @@ -110,7 +77,7 @@ void GstStartup::InitializeGStreamer() { } -void GstStartup::SetEnvironment() { +void SetEnvironment() { #ifdef USE_BUNDLE @@ -177,7 +144,6 @@ void GstStartup::SetEnvironment() { #endif // USE_BUNDLE - #if defined(Q_OS_WIN32) || defined(Q_OS_MACOS) QString gst_registry_filename = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + QStringLiteral("/gst-registry-%1-bin").arg(QCoreApplication::applicationVersion()); qLog(Debug) << "Setting GStreamer registry file to" << gst_registry_filename; @@ -185,3 +151,5 @@ void GstStartup::SetEnvironment() { #endif } + +} // namespace GstStartup diff --git a/src/engine/gststartup.h b/src/engine/gststartup.h index e080c3ecb..5d132d7d4 100644 --- a/src/engine/gststartup.h +++ b/src/engine/gststartup.h @@ -1,6 +1,6 @@ /* * Strawberry Music Player - * Copyright 2018-2021, Jonas Kvinge + * Copyright 2018-2024, Jonas Kvinge * * Strawberry is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,32 +20,9 @@ #ifndef GSTSTARTUP_H #define GSTSTARTUP_H -#include "config.h" - -#include -#include - -#include -#include -#include - -class GstStartup : public QObject { - Q_OBJECT - - public: - explicit GstStartup(QObject *parent = nullptr); - ~GstStartup() override; - - void EnsureInitialized() { initializing_.waitForFinished(); } - - private: - static GThread *kGThread; - static gpointer GLibMainLoopThreadFunc(gpointer data); - - static void InitializeGStreamer(); - static void SetEnvironment(); - - QFuture initializing_; -}; +namespace GstStartup { +void Initialize(); +void SetEnvironment(); +} // namespace #endif // GSTSTARTUP_H diff --git a/src/main.cpp b/src/main.cpp index 575d56ccc..888404e87 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -118,6 +118,8 @@ # include "osd/osdbase.h" #endif +#include "engine/gststartup.h" + using namespace Qt::Literals::StringLiterals; using std::make_shared; @@ -191,6 +193,8 @@ int main(int argc, char *argv[]) { QGuiApplication::setDesktopFileName(u"org.strawberrymusicplayer.strawberry"_s); QGuiApplication::setQuitOnLastWindowClosed(false); + GstStartup::Initialize(); + QApplication a(argc, argv); KDSingleApplication single_app(QCoreApplication::applicationName(), KDSingleApplication::Option::IncludeUsernameInSocketName); if (!single_app.isPrimaryInstance()) {