@@ -0,0 +1,288 @@
1+/*
2+ * Copyright (C) 2013 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(160, 90)); }
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+{
58+ qsrand(time(nullptr));
59+ m_timer.setInterval(100);
60+ connect(&m_timer, SIGNAL(timeout()), SLOT(timerEvent()));
61+
62+ connect(MediaPlayerDataController::instance(), &MediaPlayerDataController::sourceRemoved,
63+ this, [this](const QUrl&) {
64+ disconnect(0, &MediaDataSource::durationChanged, this, &MediaPlayer::durationChanged);
65+ disconnect(0, &MediaDataSource::seekableChanged, this, &MediaPlayer::seekableChanged);
66+ disconnect(0, &MediaDataSource::availabilityChanged, this, &MediaPlayer::availabilityChanged);
67+ });
68+
69+ connect(MediaPlayerDataController::instance(), &MediaPlayerDataController::sourceAdded,
70+ this, [this](const QUrl& source) {
71+ MediaDataSource* dataSource = MediaPlayerDataController::instance()->dataForSource(source);
72+ if (!dataSource) return;
73+
74+ connect(dataSource, &MediaDataSource::durationChanged, this, &MediaPlayer::durationChanged);
75+ connect(dataSource, &MediaDataSource::seekableChanged,this, &MediaPlayer::seekableChanged);
76+ connect(dataSource, &MediaDataSource::availabilityChanged,this, &MediaPlayer::availabilityChanged);
77+ });
78+}
79+
80+QUrl MediaPlayer::source() const
81+{
82+ return m_source;
83+}
84+
85+void MediaPlayer::setSource(const QUrl &source)
86+{
87+ if (m_source != source) {
88+ m_source = source;
89+ Q_EMIT sourceChanged(source);
90+ Q_EMIT durationChanged(duration());
91+ Q_EMIT seekableChanged(isSeekable());
92+ Q_EMIT availabilityChanged(availability());
93+
94+ m_position = 0;
95+ Q_EMIT positionChanged(m_position);
96+
97+ m_status = availability()==Available ? Loaded : InvalidMedia;
98+ Q_EMIT statusChanged();
99+ }
100+}
101+
102+MediaPlayer::PlaybackState MediaPlayer::playbackState() const
103+{
104+ return m_playbackState;
105+}
106+
107+int MediaPlayer::position() const
108+{
109+ return m_position;
110+}
111+
112+int MediaPlayer::duration() const
113+{
114+ MediaDataSource* dataSource = MediaPlayerDataController::instance()->dataForSource(source());
115+ if (dataSource) return dataSource->duration();
116+ return 0;
117+}
118+
119+QString MediaPlayer::errorString() const
120+{
121+ return QString();
122+}
123+
124+void MediaPlayer::pause()
125+{
126+ if (m_playbackState == PlayingState) {
127+ m_playbackState = PausedState;
128+ Q_EMIT playbackStateChanged(m_playbackState);
129+ m_timer.stop();
130+ }
131+}
132+
133+void MediaPlayer::play()
134+{
135+ if (m_playbackState != PlayingState) {
136+ m_playbackState = PlayingState;
137+ Q_EMIT playbackStateChanged(m_playbackState);
138+
139+ m_timer.start();
140+ }
141+}
142+
143+void MediaPlayer::stop()
144+{
145+ if (m_playbackState != StoppedState) {
146+ m_playbackState = StoppedState;
147+ Q_EMIT playbackStateChanged(m_playbackState);
148+ m_timer.stop();
149+ m_position = 0;
150+ Q_EMIT positionChanged(m_position);
151+ }
152+}
153+
154+void MediaPlayer::seek(int position)
155+{
156+ if (status() != Loaded) return;
157+ int newPosition = qMin(qMax(0, position), duration());
158+ if (newPosition != m_position) {
159+ m_position = newPosition;
160+ Q_EMIT positionChanged(m_position);
161+ }
162+
163+}
164+
165+void MediaPlayer::timerEvent()
166+{
167+ if (m_position + m_timer.interval() < duration()) {
168+ m_position += m_timer.interval();
169+ Q_EMIT positionChanged(m_position);
170+ } else {
171+ pause();
172+ }
173+}
174+
175+MediaPlayer::AudioRole MediaPlayer::audioRole() const
176+{
177+ return MediaPlayer::MultimediaRole;
178+}
179+
180+void MediaPlayer::setAudioRole(MediaPlayer::AudioRole audioRole)
181+{
182+ Q_UNUSED(audioRole);
183+}
184+
185+bool MediaPlayer::isSeekable() const
186+{
187+ MediaDataSource* dataSource = MediaPlayerDataController::instance()->dataForSource(source());
188+ if (dataSource) return dataSource->isSeekable();
189+ return true;
190+}
191+
192+MediaPlayer::Availability MediaPlayer::availability() const
193+{
194+ MediaDataSource* dataSource = MediaPlayerDataController::instance()->dataForSource(source());
195+ if (dataSource) return dataSource->availability();
196+ return Available;
197+}
198+
199+
200+MediaDataSource::MediaDataSource(QObject *parent)
201+ : QObject(parent)
202+ , m_seekable(true)
203+ , m_duration((qrand() % 20000) + 10000)
204+ , m_availability(MediaPlayer::Available)
205+{
206+}
207+
208+MediaDataSource::~MediaDataSource()
209+{
210+ if (!m_source.isEmpty()) MediaPlayerDataController::instance()->unregisterDataSource(this);
211+}
212+
213+void MediaDataSource::setSource(const QUrl &source)
214+{
215+ if (m_source != source) {
216+ if (!m_source.isEmpty()) MediaPlayerDataController::instance()->unregisterDataSource(this);
217+
218+ m_source = source;
219+
220+ if (!m_source.isEmpty()) MediaPlayerDataController::instance()->registerDataSource(this);
221+ Q_EMIT sourceChanged();
222+ }
223+}
224+
225+void MediaDataSource::setSeekable(bool seekable)
226+{
227+ if (m_seekable != seekable) {
228+ m_seekable = seekable;
229+ Q_EMIT seekableChanged(m_seekable);
230+ }
231+}
232+
233+void MediaDataSource::setDuration(int duration)
234+{
235+ if (m_duration != duration) {
236+ m_duration = duration;
237+ Q_EMIT durationChanged(m_duration);
238+ }
239+}
240+
241+void MediaDataSource::setAvailability(MediaPlayer::Availability availability)
242+{
243+ if (m_availability != availability) {
244+ m_availability = availability;
245+ Q_EMIT availabilityChanged(m_availability);
246+ }
247+}
248+
249+void MediaDataSource::setMetaData(const QVariant& metaData)
250+{
251+ if (m_metaData != metaData) {
252+ m_metaData = metaData;
253+ Q_EMIT metaDataChanged();
254+ }
255+}
256+
257+MediaPlayerDataController *MediaPlayerDataController::instance()
258+{
259+ static MediaPlayerDataController* instance = nullptr;
260+ if (!instance) { instance = new MediaPlayerDataController(); }
261+ return instance;
262+}
263+
264+void MediaPlayerDataController::registerDataSource(MediaDataSource *dataSource)
265+{
266+ m_dataSources[dataSource->source()] = dataSource;
267+ Q_EMIT sourceAdded(dataSource->source());
268+}
269+
270+void MediaPlayerDataController::unregisterDataSource(MediaDataSource *dataSource)
271+{
272+ QList<QUrl> keys = m_dataSources.keys(dataSource);
273+ Q_FOREACH(const QUrl& key, keys) {
274+ m_dataSources.remove(key);
275+ Q_EMIT sourceRemoved(key);
276+ }
277+}
278+
279+MediaDataSource *MediaPlayerDataController::dataForSource(const QUrl &source)
280+{
281+ if (!m_dataSources.contains(source)) {
282+ static MediaDataSource defaultSource;
283+ return &defaultSource;
284+ }
285+ return m_dataSources[source];
286+}
287+
288+#include "mediaplayer.moc"