1/* This file is part of the KDE project
2 Copyright (C) 2005 Matthias Kretz <kretz@kde.org>
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) version 3, or any
8 later version accepted by the membership of KDE e.V. (or its
9 successor approved by the membership of KDE e.V.), Nokia Corporation
10 (or its successors, if any) and the KDE Free Qt Foundation, which shall
11 act as a proxy defined in Section 6 of version 3 of the license.
12
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public
19 License along with this library. If not, see <http://www.gnu.org/licenses/>.
20
21*/
22#ifndef Phonon_MEDIAOBJECT_H
23#define Phonon_MEDIAOBJECT_H
24
25#include "medianode.h"
26#include "mediasource.h"
27#include "phonon_export.h"
28#include "phonondefs.h"
29#include "phononnamespace.h"
30
31
32namespace Phonon
33{
34 class MediaObjectPrivate;
35
36 /** \class MediaObject mediaobject.h phonon/MediaObject
37 * \short Interface for media playback of a given URL.
38 *
39 * This class is the most important class in %Phonon. Use it to open a media
40 * file at an arbitrary location, a CD or DVD or to stream media data from
41 * the application to the backend.
42 *
43 * This class controls the state (play, pause, stop, seek)
44 * and you can use it to get a lot of information about the media data.
45 *
46 * Notice that most functions of this class are asynchronous.
47 * That means if you call play() the object only starts playing when the
48 * stateChanged() signal tells you that the object changed into PlayingState.
49 * The states you can expect are documented for those methods.
50 *
51 * A common usage example is the following:
52 * \code
53 * media = new MediaObject(this);
54 * connect(media, SIGNAL(finished()), SLOT(slotFinished());
55 * media->setCurrentSource("/home/username/music/filename.ogg");
56 * media->play();
57 * \endcode
58 *
59 * If you want to play more than one media file (one after another) you can
60 * either tell MediaObject about all those files
61 * \code
62 * media->setCurrentSource(":/sounds/startsound.ogg");
63 * media->enqueue("/home/username/music/song.mp3");
64 * media->enqueue(":/sounds/endsound.ogg");
65 * \endcode
66 * or provide the next file just in time:
67 * \code
68 * media->setCurrentSource(":/sounds/startsound.ogg");
69 * connect(media, SIGNAL(aboutToFinish()), SLOT(enqueueNextSource()));
70 * }
71 *
72 * void enqueueNextSource()
73 * {
74 * media->enqueue("/home/username/music/song.mp3");
75 * }
76 * \endcode
77 *
78 * This integration is opt-in only and can be enabled by setting the
79 * PlaybackTracking property to true:
80 * \code
81 * media->setProperty("PlaybackTracking", true);
82 * \endcode
83 *
84 * This kind of information is normally used to provide a universal history
85 * view to the user, such as what songs were played when, regardless of the
86 * media player. This is in addition to any emails read, IM conversations,
87 * websites viewed, etc.
88 *
89 * \ingroup Playback
90 * \ingroup Recording
91 * \author Matthias Kretz <kretz@kde.org>
92 */
93 class PHONON_EXPORT MediaObject : public QObject, public MediaNode
94 {
95 friend class FrontendInterfacePrivate;
96 Q_OBJECT
97 P_DECLARE_PRIVATE(MediaObject)
98 PHONON_OBJECT(MediaObject)
99 /**
100 * \brief Defines the time between media sources.
101 *
102 * A positive transition time defines a gap of silence between queued
103 * media sources.
104 *
105 * A transition time of 0 ms requests gapless playback (sample precise
106 * queueing of the next source).
107 *
108 * A negative transition time defines a crossfade between the queued
109 * media sources.
110 *
111 * Defaults to 0 (gapless playback).
112 *
113 * \warning This feature might not work reliably on every platform.
114 */
115 Q_PROPERTY(qint32 transitionTime READ transitionTime WRITE setTransitionTime)
116
117 /**
118 * \brief Get a signal before playback finishes.
119 *
120 * This property specifies the time in milliseconds the
121 * prefinishMarkReached signal is
122 * emitted before the playback finishes. A value of \c 0 disables the
123 * signal.
124 *
125 * Defaults to \c 0 (disabled).
126 *
127 * \warning For some media data the total time cannot be determined
128 * accurately, therefore the accuracy of the prefinishMarkReached signal
129 * can be bad sometimes. Still, it is better to use this method than to
130 * look at totalTime() and currentTime() to emulate the behaviour
131 * because the backend might have more information available than your
132 * application does through totalTime and currentTime.
133 *
134 * \see prefinishMarkReached
135 */
136 Q_PROPERTY(qint32 prefinishMark READ prefinishMark WRITE setPrefinishMark)
137
138 /**
139 * \brief The time interval in milliseconds between two ticks.
140 *
141 * The %tick interval is the time that elapses between the emission of two tick signals.
142 * If you set the interval to \c 0 the tick signal gets disabled.
143 *
144 * Defaults to \c 0 (disabled).
145 *
146 * \warning The back-end is free to choose a different tick interval close
147 * to what you asked for. This means that the following code \em may \em fail:
148 * \code
149 * int x = 200;
150 * media->setTickInterval(x);
151 * Q_ASSERT(x == producer->tickInterval());
152 * \endcode
153 * On the other hand the following is guaranteed:
154 * \code
155 * int x = 200;
156 * media->setTickInterval(x);
157 * Q_ASSERT(x >= producer->tickInterval() &&
158 * x <= 2 * producer->tickInterval());
159 * \endcode
160 *
161 * \see tick
162 */
163 Q_PROPERTY(qint32 tickInterval READ tickInterval WRITE setTickInterval)
164 public:
165 /**
166 * Destroys the MediaObject.
167 */
168 ~MediaObject() override;
169
170 /**
171 * Get the current state.
172 *
173 * @return The state of the object.
174 *
175 * @see State
176 * \see stateChanged
177 */
178 State state() const;
179
180 /**
181 * Check whether the media data includes a video stream.
182 *
183 * \warning This information cannot be known immediately. It is best
184 * to also listen to the hasVideoChanged signal.
185 *
186 * \code
187 * connect(media, SIGNAL(hasVideoChanged(bool)), hasVideoChanged(bool));
188 * media->setCurrentSource("somevideo.avi");
189 * media->hasVideo(); // returns false;
190 * }
191 *
192 * void hasVideoChanged(bool b)
193 * {
194 * // b == true
195 * media->hasVideo(); // returns true;
196 * }
197 * \endcode
198 *
199 * \return \c true if the media contains video data. \c false
200 * otherwise.
201 *
202 * \see hasVideoChanged
203 */
204 bool hasVideo() const;
205
206 /**
207 * Check whether the current media may be seeked.
208 *
209 * \warning This information cannot be known immediately. It is best
210 * to also listen to the seekableChanged signal.
211 *
212 * \code
213 * connect(media, SIGNAL(seekableChanged(bool)), seekableChanged(bool));
214 * media->setCurrentSource("somevideo.avi");
215 * media->isSeekable(); // returns false;
216 * }
217 *
218 * void seekableChanged(bool b)
219 * {
220 * // b == true
221 * media->isSeekable(); // returns true;
222 * }
223 * \endcode
224 *
225 * \return \c true when the current media may be seeked. \c false
226 * otherwise.
227 *
228 * \see seekableChanged()
229 */
230 bool isSeekable() const;
231
232 /**
233 * \brief The time interval in milliseconds between two ticks.
234 *
235 * The %tick interval is the time that elapses between the emission
236 * of two tick signals.
237 *
238 * \returns the tick interval in milliseconds
239 */
240 qint32 tickInterval() const;
241
242 /**
243 * Returns the strings associated with the given \p key.
244 *
245 * Backends should use the keys specified in the Ogg Vorbis
246 * documentation: http://xiph.org/vorbis/doc/v-comment.html
247 *
248 * Therefore the following should work with every backend:
249 *
250 * A typical usage looks like this:
251 * \code
252 * setMetaArtist (media->metaData("ARTIST" ));
253 * setMetaAlbum (media->metaData("ALBUM" ));
254 * setMetaTitle (media->metaData("TITLE" ));
255 * setMetaDate (media->metaData("DATE" ));
256 * setMetaGenre (media->metaData("GENRE" ));
257 * setMetaTrack (media->metaData("TRACKNUMBER"));
258 * setMetaComment(media->metaData("DESCRIPTION"));
259 * \endcode
260 *
261 * For Audio CDs you can query
262 * \code
263 * metaData("MUSICBRAINZ_DISCID");
264 * \endcode
265 * to get a DiscID hash that you can use with the MusicBrainz
266 * service:
267 * http://musicbrainz.org/doc/ClientHOWTO
268 */
269 QStringList metaData(const QString &key) const;
270
271 /**
272 * Returns the strings associated with the given \p key.
273 *
274 * Same as above except that the keys are defined in the
275 * Phonon::MetaData enum.
276 */
277 QStringList metaData(Phonon::MetaData key) const;
278
279 /**
280 * Returns all meta data.
281 */
282 QMultiMap<QString, QString> metaData() const;
283
284 /**
285 * Returns a human-readable description of the last error that occurred.
286 */
287 QString errorString() const;
288
289 /**
290 * Tells your program what to do about the error.
291 *
292 * \see Phonon::ErrorType
293 */
294 ErrorType errorType() const;
295
296 /**
297 * Returns the current media source.
298 *
299 * \see setCurrentSource
300 */
301 MediaSource currentSource() const;
302
303 /**
304 * Set the media source the MediaObject should use.
305 *
306 * \param source The MediaSource object to the media data. You can
307 * just as well use a QUrl or QString (for a local file) here.
308 * Setting an empty (invalid) source, will stop and remove the
309 * current source.
310 *
311 * \code
312 * QUrl url("http://www.example.com/music.ogg");
313 * media->setCurrentSource(url);
314 * \endcode
315 *
316 * \see currentSource
317 */
318 void setCurrentSource(const MediaSource &source);
319
320 /**
321 * Returns the queued media sources. This list does not include
322 * the current source (returned by currentSource).
323 */
324 QList<MediaSource> queue() const;
325
326 /**
327 * Set the MediaSources to play when the current media has finished.
328 *
329 * This function will overwrite the current queue.
330 *
331 * \see clearQueue
332 * \see enqueue
333 */
334 void setQueue(const QList<MediaSource> &sources);
335
336 /**
337 * Set the MediaSources to play when the current media has finished.
338 *
339 * This function overwrites the current queue.
340 *
341 * \see clearQueue
342 * \see enqueue
343 */
344 void setQueue(const QList<QUrl> &urls);
345
346 /**
347 * Appends one source to the queue. Use this function to provide
348 * the next source just in time after the aboutToFinish signal was
349 * emitted.
350 *
351 * \see aboutToFinish
352 * \see setQueue
353 * \see clearQueue
354 */
355 void enqueue(const MediaSource &source);
356
357 /**
358 * Appends multiple sources to the queue.
359 *
360 * \see setQueue
361 * \see clearQueue
362 */
363 void enqueue(const QList<MediaSource> &sources);
364
365 /**
366 * Appends multiple sources to the queue.
367 *
368 * \see setQueue
369 * \see clearQueue
370 */
371 void enqueue(const QList<QUrl> &urls);
372
373 /**
374 * Clears the queue of sources.
375 */
376 void clearQueue();
377
378 /**
379 * Get the current time (in milliseconds) of the file currently being played.
380 *
381 * \return The current time in milliseconds.
382 *
383 * \see tick
384 */
385 qint64 currentTime() const;
386
387 /**
388 * Get the total time (in milliseconds) of the file currently being played.
389 *
390 * \return The total time in milliseconds.
391 *
392 * \note The total time may change throughout playback as more accurate
393 * calculations become available, so it is recommended to connect
394 * and use the totalTimeChanged signal whenever possible unless
395 * best precision is not of importance.
396 *
397 * \warning The total time is undefined until the MediaObject entered
398 * the PlayingState. A valid total time is always indicated by
399 * emission of the totalTimeChanged signal.
400 * \see totalTimeChanged
401 */
402 qint64 totalTime() const;
403
404 /**
405 * Get the remaining time (in milliseconds) of the file currently being played.
406 *
407 * \return The remaining time in milliseconds.
408 */
409 qint64 remainingTime() const;
410
411 qint32 prefinishMark() const;
412 void setPrefinishMark(qint32 msecToEnd);
413
414 qint32 transitionTime() const;
415 void setTransitionTime(qint32 msec);
416
417 public Q_SLOTS:
418
419 /**
420 * Sets the tick interval in milliseconds.
421 *
422 * \param newTickInterval the new tick interval in milliseconds.
423 *
424 * \see tickInterval
425 */
426 void setTickInterval(qint32 newTickInterval);
427
428 /**
429 * Requests playback of the media data to start. Playback only
430 * starts when stateChanged() signals that it goes into PlayingState,
431 * though.
432 *
433 * \par Possible states right after this call:
434 * \li BufferingState
435 * \li PlayingState
436 * \li ErrorState
437 */
438 void play();
439
440 /**
441 * Requests playback to pause. If it was paused before nothing changes.
442 * If the media cannot be paused, some backends will internally call
443 * stop instead of pause.
444 *
445 * \par Possible states right after this call:
446 * \li PlayingState
447 * \li PausedState
448 * \li StoppedState
449 * \li ErrorState
450 */
451 void pause();
452
453 /**
454 * Requests playback to stop. If it was stopped before nothing changes.
455 *
456 * \par Possible states right after this call:
457 * \li the state it was in before (e.g. PlayingState)
458 * \li StoppedState
459 * \li ErrorState
460 */
461 void stop();
462
463 /**
464 * Requests a seek to the time indicated.
465 *
466 * You can only seek if state() == PlayingState, BufferingState or PausedState.
467 *
468 * The call is asynchronous, so currentTime can still be the old
469 * value right after this method was called. If all you need is a
470 * slider that shows the current position and allows the user to
471 * seek use the class SeekSlider.
472 *
473 * @param time The time in milliseconds where to continue playing.
474 *
475 * \par Possible states right after this call:
476 * \li BufferingState
477 * \li PlayingState
478 * \li ErrorState
479 *
480 * \see SeekSlider
481 */
482 void seek(qint64 time);
483
484 /**
485 * Stops and removes all playing and enqueued media sources.
486 *
487 * \see setCurrentSource
488 */
489 void clear();
490
491 Q_SIGNALS:
492 /**
493 * Emitted when the state of the MediaObject has changed.
494 *
495 * @param newstate The state the Player is in now.
496 * @param oldstate The state the Player was in before.
497 */
498 void stateChanged(Phonon::State newstate, Phonon::State oldstate);
499
500 /**
501 * This signal gets emitted every tickInterval milliseconds.
502 *
503 * @param time The position of the media file in milliseconds.
504 *
505 * @see setTickInterval, tickInterval
506 */
507 void tick(qint64 time);
508
509 /**
510 * This signal is emitted whenever the audio/video data that is
511 * being played is associated with new meta data. E.g. for radio
512 * streams this happens when the next song is played.
513 *
514 * You can get the new meta data with the metaData methods.
515 */
516 void metaDataChanged();
517
518 /**
519 * Emitted whenever the return value of isSeekable() changes.
520 *
521 * Normally you'll check isSeekable() first and then let this signal
522 * tell you whether seeking is possible now or not. That way you
523 * don't have to poll isSeekable().
524 *
525 * \param isSeekable \p true if the stream is seekable (i.e. calling
526 * seek() works)
527 * \p false if the stream is not seekable (i.e.
528 * all calls to seek() will be ignored)
529 */
530 void seekableChanged(bool isSeekable);
531
532 /**
533 * Emitted whenever the return value of hasVideo() changes.
534 *
535 * Normally you'll check hasVideo() first and then let this signal
536 * tell you whether video is available now or not. That way you
537 * don't have to poll hasVideo().
538 *
539 * \param hasVideo \p true The stream contains video and adding a
540 * VideoWidget will show a video.
541 * \p false There is no video data in the stream and
542 * adding a VideoWidget will show an empty (black)
543 * VideoWidget.
544 */
545#ifndef QT_NO_PHONON_VIDEO
546 void hasVideoChanged(bool hasVideo);
547#endif //QT_NO_PHONON_VIDEO
548
549 /**
550 * Tells about the status of the buffer.
551 *
552 * You can use this signal to show a progress bar to the user when
553 * in BufferingState:
554 *
555 * \code
556 * progressBar->setRange(0, 100); // this is the default
557 * connect(media, SIGNAL(bufferStatus(int)), progressBar, SLOT(setValue(int)));
558 * \endcode
559 *
560 * \param percentFilled A number between 0 and 100 telling you how
561 * much the buffer is filled.
562 */ // other names: bufferingProgress
563 void bufferStatus(int percentFilled);
564
565 /**
566 * Emitted when the object has finished playback.
567 * It is not emitted if you call stop(), pause() or
568 * load(), but only on end-of-queue or a critical error.
569 *
570 * \warning This signal is not emitted when the current source has
571 * finished and there's another source in the queue. It is only
572 * emitted when the queue is empty.
573 *
574 * \see currentSourceChanged
575 * \see aboutToFinish
576 * \see prefinishMarkReached
577 */
578 void finished();
579
580 /**
581 * Emitted when the MediaObject makes a transition to the next
582 * MediaSource in the queue().
583 *
584 * In other words, it is emitted when an individual MediaSource is
585 * finished.
586 *
587 * \param newSource The source that starts to play at the time the
588 * signal is emitted.
589 */
590 void currentSourceChanged(const Phonon::MediaSource &newSource);
591
592 /**
593 * Emitted before the playback of the whole queue stops. When this
594 * signal is emitted you still have time to provide the next
595 * MediaSource (using enqueue()) so that playback continues.
596 *
597 * This signal can be used to provide the next MediaSource just in
598 * time for the transition still to work.
599 *
600 * \see enqueue
601 */
602 void aboutToFinish();
603
604 /**
605 * Emitted when there are only \p msecToEnd milliseconds left
606 * for playback.
607 *
608 * \param msecToEnd The remaining time until the playback queue finishes.
609 *
610 * \warning This signal is not emitted when there is another source in the queue.
611 * It is only emitted when the queue is empty.
612 *
613 * \see setPrefinishMark
614 * \see prefinishMark
615 * \see aboutToFinish
616 * \see finished
617 */
618 void prefinishMarkReached(qint32 msecToEnd);
619
620 /**
621 * This signal is emitted as soon as the total time of the media file is
622 * known or has changed. For most non-local media data the total
623 * time of the media can only be known after some time. Initially the
624 * totalTime function can not return useful information. You have
625 * to wait for this signal to know the real total time.
626 *
627 * This signal may appear at any given point after a MediaSource was set.
628 * Namely in the LoadingState, BufferingState, PlayingState or PausedState.
629 *
630 * \note When changing the currentSource there is no signal emission until
631 * a reasonable value for the new source has been calculated.
632 *
633 * \param newTotalTime The length of the media file in milliseconds.
634 *
635 * \see totalTime
636 */
637 void totalTimeChanged(qint64 newTotalTime);
638
639 protected:
640 //MediaObject(Phonon::MediaObjectPrivate &dd, QObject *parent);
641
642 private:
643 Q_PRIVATE_SLOT(k_func(), void _k_resumePlay())
644 Q_PRIVATE_SLOT(k_func(), void _k_resumePause())
645 Q_PRIVATE_SLOT(k_func(), void _k_metaDataChanged(const QMultiMap<QString, QString> &))
646#ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
647 Q_PRIVATE_SLOT(k_func(), void _k_stateChanged(Phonon::State, Phonon::State))
648#endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
649 Q_PRIVATE_SLOT(k_func(), void _k_aboutToFinish())
650 Q_PRIVATE_SLOT(k_func(), void _k_currentSourceChanged(const MediaSource &))
651 Q_PRIVATE_SLOT(k_func(), void _k_stateChanged(Phonon::State, Phonon::State))
652 };
653
654 /**
655 * Convenience function to create a MediaObject and AudioOutput connected by
656 * a path.
657 */
658 PHONON_EXPORT MediaObject *createPlayer(Phonon::Category category, const MediaSource &source = MediaSource());
659} //namespace Phonon
660
661
662// vim: sw=4 ts=4 tw=80
663#endif // Phonon_MEDIAOBJECT_H
664

source code of phonon/phonon/mediaobject.h