1 /*
2  * Strawberry Music Player
3  * This file was part of Clementine.
4  * Copyright 2010, David Sansome <me@davidsansome.com>
5  * Copyright 2018-2021, Jonas Kvinge <jonas@jkvinge.net>
6  *
7  * Strawberry 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 3 of the License, or
10  * (at your option) any later version.
11  *
12  * Strawberry 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 Strawberry.  If not, see <http://www.gnu.org/licenses/>.
19  *
20  */
21 
22 #ifndef SONGLOADER_H
23 #define SONGLOADER_H
24 
25 #include "config.h"
26 
27 #include <memory>
28 #include <functional>
29 #include <glib.h>
30 
31 #ifdef HAVE_GSTREAMER
32 #  include <gst/gst.h>
33 #endif
34 
35 #include <QtGlobal>
36 #include <QObject>
37 #include <QThreadPool>
38 #include <QByteArray>
39 #include <QSet>
40 #include <QString>
41 #include <QStringList>
42 #include <QUrl>
43 
44 #include "song.h"
45 
46 class QTimer;
47 class Player;
48 class CollectionBackendInterface;
49 class PlaylistParser;
50 class ParserBase;
51 class CueParser;
52 
53 #if defined(HAVE_AUDIOCD) && defined(HAVE_GSTREAMER)
54 class CddaSongLoader;
55 #endif
56 
57 class SongLoader : public QObject {
58   Q_OBJECT
59  public:
60   explicit SongLoader(CollectionBackendInterface *collection, const Player *player, QObject *parent = nullptr);
61   ~SongLoader() override;
62 
63   enum Result {
64     Success,
65     Error,
66     BlockingLoadRequired,
67   };
68 
69   static const int kDefaultTimeout;
70 
url()71   const QUrl &url() const { return url_; }
songs()72   const SongList &songs() const { return songs_; }
73 
timeout()74   int timeout() const { return timeout_; }
set_timeout(int msec)75   void set_timeout(int msec) { timeout_ = msec; }
76 
77   // If Success is returned the songs are fully loaded. If BlockingLoadRequired is returned LoadFilenamesBlocking() needs to be called next.
78   Result Load(const QUrl &url);
79   // Loads the files with only filenames. When finished, songs() contains a complete list of all Song objects, but without metadata.
80   // This method is blocking, do not call it from the UI thread.
81   SongLoader::Result LoadFilenamesBlocking();
82   // Completely load songs previously loaded with LoadFilenamesBlocking().
83   // When finished, the Song objects in songs() contain metadata now. This method is blocking, do not call it from the UI thread.
84   void LoadMetadataBlocking();
85   Result LoadAudioCD();
86 
errors()87   QStringList errors() { return errors_; }
88 
89  signals:
90   void AudioCDTracksLoadFinished();
91   void LoadAudioCDFinished(bool success);
92   void LoadRemoteFinished();
93 
94  private slots:
95   void ScheduleTimeout();
96   void Timeout();
97   void StopTypefind();
98 #if defined(HAVE_AUDIOCD) && defined(HAVE_GSTREAMER)
99   void AudioCDTracksLoadFinishedSlot(const SongList &songs, const QString &error);
100   void AudioCDTracksTagsLoaded(const SongList &songs);
101 #endif  // HAVE_AUDIOCD && HAVE_GSTREAMER
102 
103  private:
104   enum State { WaitingForType, WaitingForMagic, WaitingForData, Finished };
105 
106   Result LoadLocal(const QString &filename);
107   SongLoader::Result LoadLocalAsync(const QString &filename);
108   void EffectiveSongLoad(Song *song);
109   Result LoadLocalPartial(const QString &filename);
110   void LoadLocalDirectory(const QString &filename);
111   void LoadPlaylist(ParserBase *parser, const QString &filename);
112 
113   void AddAsRawStream();
114 
115 #ifdef HAVE_GSTREAMER
116   Result LoadRemote();
117 
118   // GStreamer callbacks
119   static void TypeFound(GstElement *typefind, uint probability, GstCaps *caps, void *self);
120   static GstPadProbeReturn DataReady(GstPad*, GstPadProbeInfo *info, gpointer self);
121   static GstBusSyncReply BusCallbackSync(GstBus*, GstMessage*, gpointer);
122   static gboolean BusCallback(GstBus*, GstMessage*, gpointer);
123 
124   void StopTypefindAsync(bool success);
125   void ErrorMessageReceived(GstMessage *msg);
126   void EndOfStreamReached();
127   void MagicReady();
128   bool IsPipelinePlaying();
129 #endif
130 
131   void ScheduleTimeoutAsync();
132 
133  private:
134   static QSet<QString> sRawUriSchemes;
135 
136   QUrl url_;
137   SongList songs_;
138 
139   QTimer *timeout_timer_;
140   PlaylistParser *playlist_parser_;
141   CueParser *cue_parser_;
142 
143   // For async loads
144   std::function<Result()> preload_func_;
145   int timeout_;
146   State state_;
147   bool success_;
148   ParserBase *parser_;
149   QString mime_type_;
150   QByteArray buffer_;
151   CollectionBackendInterface *collection_;
152   const Player *player_;
153 
154 #ifdef HAVE_GSTREAMER
155   std::shared_ptr<GstElement> pipeline_;
156 #endif
157 
158   QThreadPool thread_pool_;
159 
160   QStringList errors_;
161 
162 };
163 
164 #endif  // SONGLOADER_H
165