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