@@ -0,0 +1,318 @@
1+/*
2+ * Copyright (C) 2013-2016 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Author: Michael Zanetti <michael.zanetti@canonical.com>
17+ */
18+
19+#include "mediaplayer.h"
20+
21+#include <QDebug>
22+#include <QSize>
23+
24+class MetaDataObject: public QObject
25+{
26+ Q_OBJECT
27+ Q_PROPERTY(QVariant title READ title NOTIFY metaDataChanged)
28+ Q_PROPERTY(QVariant resolution READ resolution NOTIFY metaDataChanged)
29+public:
30+ MetaDataObject(MediaPlayer* parent = nullptr)
31+ : QObject(parent)
32+ , m_source(parent)
33+ {
34+ }
35+
36+ QVariant title() const { return getProperty("title"); }
37+ QVariant resolution() const { return getProperty("resolution", QSize(640, 640)); }
38+
39+ QVariant getProperty(const QString& property, QVariant defaultValue = QVariant()) const {
40+ MediaDataSource* sourceData = MediaPlayerDataController::instance()->dataForSource(m_source->source());
41+ QVariant metaData = sourceData->metaData();
42+ return metaData.toMap().value(property, defaultValue);
43+ }
44+
45+Q_SIGNALS:
46+ void metaDataChanged();
47+
48+private:
49+ MediaPlayer* m_source;
50+};
51+
52+MediaPlayer::MediaPlayer(QObject* parent)
53+ : QObject(parent)
54+ , m_playbackState(StoppedState)
55+ , m_status(NoMedia)
56+ , m_metaData(new MetaDataObject(this))
57+ , m_playlist(nullptr)
58+{
59+ qsrand(time(nullptr));
60+ m_timer.setInterval(100);
61+ connect(&m_timer, &QTimer::timeout, this, &MediaPlayer::timerEvent);
62+
63+ connect(MediaPlayerDataController::instance(), &MediaPlayerDataController::sourceAboutToBeRemoved,
64+ this, [this](const QUrl& source) {
65+ MediaDataSource* dataSource = MediaPlayerDataController::instance()->dataForSource(source);
66+ if (!dataSource) return;
67+
68+ disconnect(dataSource, &MediaDataSource::durationChanged, this, &MediaPlayer::durationChanged);
69+ disconnect(dataSource, &MediaDataSource::seekableChanged, this, &MediaPlayer::seekableChanged);
70+ disconnect(dataSource, &MediaDataSource::availabilityChanged, this, &MediaPlayer::availabilityChanged);
71+ disconnect(dataSource, &MediaDataSource::metaDataChanged, m_metaData, &MetaDataObject::metaDataChanged);
72+ });
73+
74+ connect(MediaPlayerDataController::instance(), &MediaPlayerDataController::sourceAdded,
75+ this, [this](const QUrl& source) {
76+ MediaDataSource* dataSource = MediaPlayerDataController::instance()->dataForSource(source);
77+ if (!dataSource) return;
78+
79+ connect(dataSource, &MediaDataSource::durationChanged, this, &MediaPlayer::durationChanged);
80+ connect(dataSource, &MediaDataSource::seekableChanged,this, &MediaPlayer::seekableChanged);
81+ connect(dataSource, &MediaDataSource::availabilityChanged,this, &MediaPlayer::availabilityChanged);
82+ connect(dataSource, &MediaDataSource::metaDataChanged, m_metaData, &MetaDataObject::metaDataChanged);
83+ });
84+}
85+
86+QUrl MediaPlayer::source() const
87+{
88+ return m_source;
89+}
90+
91+void MediaPlayer::setSource(const QUrl &source)
92+{
93+ if (m_source != source) {
94+ m_source = source;
95+ Q_EMIT sourceChanged(source);
96+ Q_EMIT durationChanged(duration());
97+ Q_EMIT seekableChanged(isSeekable());
98+ Q_EMIT availabilityChanged(availability());
99+
100+ m_position = 0;
101+ Q_EMIT positionChanged(m_position);
102+ Q_EMIT m_metaData->metaDataChanged();
103+
104+ m_status = availability()==Available ? Loaded : InvalidMedia;
105+ Q_EMIT statusChanged();
106+ }
107+}
108+
109+DeclarativePlaylist *MediaPlayer::playlist() const
110+{
111+ return m_playlist;
112+}
113+
114+void MediaPlayer::setPlaylist(DeclarativePlaylist *playlist)
115+{
116+ if (playlist == m_playlist)
117+ return;
118+
119+ m_playlist = playlist;
120+ Q_EMIT playlistChanged();
121+}
122+
123+MediaPlayer::PlaybackState MediaPlayer::playbackState() const
124+{
125+ return m_playbackState;
126+}
127+
128+int MediaPlayer::position() const
129+{
130+ return m_position;
131+}
132+
133+int MediaPlayer::duration() const
134+{
135+ MediaDataSource* dataSource = MediaPlayerDataController::instance()->dataForSource(source());
136+ if (dataSource) return dataSource->duration();
137+ return 0;
138+}
139+
140+MediaPlayer::Error MediaPlayer::error() const
141+{
142+ return NoError;
143+}
144+
145+QString MediaPlayer::errorString() const
146+{
147+ return QString();
148+}
149+
150+void MediaPlayer::pause()
151+{
152+ if (m_playbackState == PlayingState) {
153+ m_playbackState = PausedState;
154+ Q_EMIT playbackStateChanged(m_playbackState);
155+ m_timer.stop();
156+ }
157+}
158+
159+void MediaPlayer::play()
160+{
161+ if (m_playbackState != PlayingState) {
162+ m_playbackState = PlayingState;
163+ Q_EMIT playbackStateChanged(m_playbackState);
164+
165+ m_timer.start();
166+ }
167+}
168+
169+void MediaPlayer::stop()
170+{
171+ if (m_playbackState != StoppedState) {
172+ m_playbackState = StoppedState;
173+ Q_EMIT playbackStateChanged(m_playbackState);
174+ m_timer.stop();
175+ m_position = 0;
176+ Q_EMIT positionChanged(m_position);
177+ }
178+}
179+
180+void MediaPlayer::seek(int position)
181+{
182+ if (status() != Loaded) return;
183+ int newPosition = qMin(qMax(0, position), duration());
184+ if (newPosition != m_position) {
185+ m_position = newPosition;
186+ Q_EMIT positionChanged(m_position);
187+ }
188+}
189+
190+void MediaPlayer::timerEvent()
191+{
192+ if (m_position + m_timer.interval() < duration()) {
193+ m_position += m_timer.interval();
194+ Q_EMIT positionChanged(m_position);
195+ } else {
196+ pause();
197+ }
198+}
199+
200+MediaPlayer::AudioRole MediaPlayer::audioRole() const
201+{
202+ return MediaPlayer::MusicRole;
203+}
204+
205+void MediaPlayer::setAudioRole(MediaPlayer::AudioRole audioRole)
206+{
207+ Q_UNUSED(audioRole);
208+}
209+
210+bool MediaPlayer::isSeekable() const
211+{
212+ MediaDataSource* dataSource = MediaPlayerDataController::instance()->dataForSource(source());
213+ if (dataSource) return dataSource->isSeekable();
214+ return true;
215+}
216+
217+MediaPlayer::Availability MediaPlayer::availability() const
218+{
219+ MediaDataSource* dataSource = MediaPlayerDataController::instance()->dataForSource(source());
220+ if (dataSource) return dataSource->availability();
221+ return Available;
222+}
223+
224+QObject *MediaPlayer::metaData() const
225+{
226+ return m_metaData;
227+}
228+
229+
230+MediaDataSource::MediaDataSource(QObject *parent)
231+ : QObject(parent)
232+ , m_seekable(true)
233+ , m_duration((qrand() % 20000) + 10000)
234+ , m_availability(MediaPlayer::Available)
235+{
236+}
237+
238+MediaDataSource::~MediaDataSource()
239+{
240+ if (!m_source.isEmpty()) MediaPlayerDataController::instance()->unregisterDataSource(this);
241+}
242+
243+void MediaDataSource::setSource(const QUrl &source)
244+{
245+ if (m_source != source) {
246+ if (!m_source.isEmpty()) MediaPlayerDataController::instance()->unregisterDataSource(this);
247+
248+ m_source = source;
249+
250+ if (!m_source.isEmpty()) MediaPlayerDataController::instance()->registerDataSource(this);
251+ Q_EMIT sourceChanged();
252+ }
253+}
254+
255+void MediaDataSource::setSeekable(bool seekable)
256+{
257+ if (m_seekable != seekable) {
258+ m_seekable = seekable;
259+ Q_EMIT seekableChanged(m_seekable);
260+ }
261+}
262+
263+void MediaDataSource::setDuration(int duration)
264+{
265+ if (m_duration != duration) {
266+ m_duration = duration;
267+ Q_EMIT durationChanged(m_duration);
268+ }
269+}
270+
271+void MediaDataSource::setAvailability(MediaPlayer::Availability availability)
272+{
273+ if (m_availability != availability) {
274+ m_availability = availability;
275+ Q_EMIT availabilityChanged(m_availability);
276+ }
277+}
278+
279+void MediaDataSource::setMetaData(const QVariant& metaData)
280+{
281+ if (m_metaData != metaData) {
282+ m_metaData = metaData;
283+ Q_EMIT metaDataChanged();
284+ }
285+}
286+
287+MediaPlayerDataController *MediaPlayerDataController::instance()
288+{
289+ static MediaPlayerDataController* instance = nullptr;
290+ if (!instance) { instance = new MediaPlayerDataController(); }
291+ return instance;
292+}
293+
294+void MediaPlayerDataController::registerDataSource(MediaDataSource *dataSource)
295+{
296+ m_dataSources[dataSource->source()] = dataSource;
297+ Q_EMIT sourceAdded(dataSource->source());
298+}
299+
300+void MediaPlayerDataController::unregisterDataSource(MediaDataSource *dataSource)
301+{
302+ QList<QUrl> keys = m_dataSources.keys(dataSource);
303+ Q_FOREACH(const QUrl& key, keys) {
304+ Q_EMIT sourceAboutToBeRemoved(key);
305+ m_dataSources.remove(key);
306+ }
307+}
308+
309+MediaDataSource *MediaPlayerDataController::dataForSource(const QUrl &source)
310+{
311+ if (!m_dataSources.contains(source)) {
312+ static MediaDataSource defaultSource;
313+ return &defaultSource;
314+ }
315+ return m_dataSources[source];
316+}
317+
318+#include "mediaplayer.moc"