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