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