1 /*************************************************************************** 2 * Copyright (C) 2003-2005 by Mark Kretschmann <markey@web.de> * 3 * Copyright (C) 2005 by Jakub Stachowski <qbast@go2.pl> * 4 * Copyright (C) 2006 Paul Cifarelli <paul@cifarelli.net> * 5 * Copyright (C) 2017-2021 Jonas Kvinge <jonas@jkvinge.net> * 6 * * 7 * This program is free software; you can redistribute it and/or modify * 8 * it under the terms of the GNU General Public License as published by * 9 * the Free Software Foundation; either version 2 of the License, or * 10 * (at your option) any later version. * 11 * * 12 * This program is distributed in the hope that it will be useful, * 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 15 * GNU General Public License for more details. * 16 * * 17 * You should have received a copy of the GNU General Public License * 18 * along with this program; if not, write to the * 19 * Free Software Foundation, Inc., * 20 * 51 Franklin Steet, Fifth Floor, Boston, MA 02111-1307, USA. * 21 ***************************************************************************/ 22 23 #ifndef GSTENGINE_H 24 #define GSTENGINE_H 25 26 #include "config.h" 27 28 #include <memory> 29 30 #include <gst/gst.h> 31 #include <gst/pbutils/pbutils.h> 32 33 #include <QtGlobal> 34 #include <QObject> 35 #include <QFuture> 36 #include <QByteArray> 37 #include <QList> 38 #include <QString> 39 #include <QUrl> 40 41 #include "core/timeconstants.h" 42 #include "engine_fwd.h" 43 #include "enginebase.h" 44 #include "gststartup.h" 45 #include "gstbufferconsumer.h" 46 47 class QTimer; 48 class QTimerEvent; 49 class TaskManager; 50 class GstEnginePipeline; 51 52 /** 53 * @class GstEngine 54 * @short GStreamer engine plugin 55 * @author Mark Kretschmann <markey@web.de> 56 */ 57 class GstEngine : public Engine::Base, public GstBufferConsumer { 58 Q_OBJECT 59 60 public: 61 explicit GstEngine(TaskManager *task_manager, QObject *parent = nullptr); 62 ~GstEngine() override; 63 64 bool Init() override; 65 Engine::State state() const override; 66 void StartPreloading(const QUrl &stream_url, const QUrl &original_url, const bool force_stop_at_end, const qint64 beginning_nanosec, const qint64 end_nanosec) override; 67 bool Load(const QUrl &stream_url, const QUrl &original_url, const Engine::TrackChangeFlags change, const bool force_stop_at_end, const quint64 beginning_nanosec, const qint64 end_nanosec) override; 68 bool Play(const quint64 offset_nanosec) override; 69 void Stop(const bool stop_after = false) override; 70 void Pause() override; 71 void Unpause() override; 72 void Seek(const quint64 offset_nanosec) override; 73 74 protected: 75 void SetVolumeSW(const uint percent) override; 76 77 public: 78 qint64 position_nanosec() const override; 79 qint64 length_nanosec() const override; 80 const Engine::Scope &scope(const int chunk_length) override; 81 82 OutputDetailsList GetOutputsList() const override; 83 bool ValidOutput(const QString &output) override; 84 QString DefaultOutput() override { return kAutoSink; } 85 bool CustomDeviceSupport(const QString &output) override; 86 bool ALSADeviceSupport(const QString &output) override; 87 88 void SetStartup(GstStartup *gst_startup) { gst_startup_ = gst_startup; } 89 void EnsureInitialized() { gst_startup_->EnsureInitialized(); } 90 91 GstElement *CreateElement(const QString &factoryName, GstElement *bin = nullptr, const bool showerror = true); 92 void ConsumeBuffer(GstBuffer *buffer, const int pipeline_id, const QString &format) override; 93 94 public slots: 95 void ReloadSettings() override; 96 97 // Set whether stereo balancer is enabled 98 void SetStereoBalancerEnabled(const bool enabled) override; 99 100 // Set Stereo balance, range -1.0f..1.0f 101 void SetStereoBalance(const float value) override; 102 103 // Set whether equalizer is enabled 104 void SetEqualizerEnabled(const bool) override; 105 106 // Set equalizer preamp and gains, range -100..100. Gains are 10 values. 107 void SetEqualizerParameters(const int preamp, const QList<int> &band_gains) override; 108 109 void AddBufferConsumer(GstBufferConsumer *consumer); 110 void RemoveBufferConsumer(GstBufferConsumer *consumer); 111 112 protected: 113 void timerEvent(QTimerEvent *e) override; 114 115 private slots: 116 void EndOfStreamReached(const int pipeline_id, const bool has_next_track); 117 void HandlePipelineError(const int pipeline_id, const QString &message, const int domain, const int error_code); 118 void NewMetaData(const int pipeline_id, const Engine::SimpleMetaBundle &bundle); 119 void AddBufferToScope(GstBuffer *buf, const int pipeline_id, const QString &format); 120 void FadeoutFinished(); 121 void FadeoutPauseFinished(); 122 void SeekNow(); 123 void PlayDone(const GstStateChangeReturn ret, const quint64, const int); 124 125 void BufferingStarted(); 126 void BufferingProgress(int percent); 127 void BufferingFinished(); 128 129 private: 130 PluginDetailsList GetPluginList(const QString &classname) const; 131 QByteArray FixupUrl(const QUrl &url); 132 133 void StartFadeout(); 134 void StartFadeoutPause(); 135 136 void StartTimers(); 137 void StopTimers(); 138 139 std::shared_ptr<GstEnginePipeline> CreatePipeline(); 140 std::shared_ptr<GstEnginePipeline> CreatePipeline(const QByteArray &gst_url, const QUrl &original_url, const qint64 end_nanosec); 141 142 void UpdateScope(int chunk_length); 143 144 static void StreamDiscovered(GstDiscoverer*, GstDiscovererInfo *info, GError*, gpointer self); 145 static void StreamDiscoveryFinished(GstDiscoverer*, gpointer); 146 static QString GSTdiscovererErrorMessage(GstDiscovererResult result); 147 148 private: 149 static const char *kAutoSink; 150 static const char *kALSASink; 151 static const char *kOpenALSASink; 152 static const char *kOSSSink; 153 static const char *kOSS4Sink; 154 static const char *kJackAudioSink; 155 static const char *kPulseSink; 156 static const char *kA2DPSink; 157 static const char *kAVDTPSink; 158 static const char *InterAudiosink; 159 static const char *kDirectSoundSink; 160 static const char *kOSXAudioSink; 161 static const int kDiscoveryTimeoutS; 162 static const qint64 kTimerIntervalNanosec = 1000 * kNsecPerMsec; // 1s 163 static const qint64 kPreloadGapNanosec = 5000 * kNsecPerMsec; // 5s 164 static const qint64 kSeekDelayNanosec = 100 * kNsecPerMsec; // 100msec 165 166 TaskManager *task_manager_; 167 GstStartup *gst_startup_; 168 GstDiscoverer *discoverer_; 169 170 int buffering_task_id_; 171 172 std::shared_ptr<GstEnginePipeline> current_pipeline_; 173 std::shared_ptr<GstEnginePipeline> fadeout_pipeline_; 174 std::shared_ptr<GstEnginePipeline> fadeout_pause_pipeline_; 175 QUrl preloaded_url_; 176 177 QList<GstBufferConsumer*> buffer_consumers_; 178 179 GstBuffer *latest_buffer_; 180 181 bool stereo_balancer_enabled_; 182 float stereo_balance_; 183 184 bool equalizer_enabled_; 185 int equalizer_preamp_; 186 QList<int> equalizer_gains_; 187 188 // Hack to stop seeks happening too often 189 QTimer *seek_timer_; 190 bool waiting_to_seek_; 191 quint64 seek_pos_; 192 193 int timer_id_; 194 int next_element_id_; 195 196 bool is_fading_out_to_pause_; 197 bool has_faded_out_; 198 199 int scope_chunk_; 200 bool have_new_buffer_; 201 int scope_chunks_; 202 QString buffer_format_; 203 204 int discovery_finished_cb_id_; 205 int discovery_discovered_cb_id_; 206 207 }; 208 209 #endif // GSTENGINE_H 210