1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qaudiodecoder.h"
41
42#include "qmediaobject_p.h"
43#include <qmediaservice.h>
44#include "qaudiodecodercontrol.h"
45#include <private/qmediaserviceprovider_p.h>
46
47#include <QtCore/qcoreevent.h>
48#include <QtCore/qmetaobject.h>
49#include <QtCore/qtimer.h>
50#include <QtCore/qdebug.h>
51#include <QtCore/qpointer.h>
52
53QT_BEGIN_NAMESPACE
54
55/*!
56 \class QAudioDecoder
57 \brief The QAudioDecoder class allows decoding audio.
58 \inmodule QtMultimedia
59 \ingroup multimedia
60 \ingroup multimedia_audio
61
62 \preliminary
63
64 The QAudioDecoder class is a high level class for decoding local
65 audio media files. It is similar to the QMediaPlayer class except
66 that audio is provided back through this API rather than routed
67 directly to audio hardware, and playlists and network and streaming
68 based media is not supported.
69
70 \sa QAudioBuffer
71*/
72
73static void qRegisterAudioDecoderMetaTypes()
74{
75 qRegisterMetaType<QAudioDecoder::State>(typeName: "QAudioDecoder::State");
76 qRegisterMetaType<QAudioDecoder::Error>(typeName: "QAudioDecoder::Error");
77}
78
79Q_CONSTRUCTOR_FUNCTION(qRegisterAudioDecoderMetaTypes)
80
81class QAudioDecoderPrivate : public QMediaObjectPrivate
82{
83 Q_DECLARE_NON_CONST_PUBLIC(QAudioDecoder)
84
85public:
86 QAudioDecoderPrivate()
87 : provider(nullptr)
88 , control(nullptr)
89 , state(QAudioDecoder::StoppedState)
90 , error(QAudioDecoder::NoError)
91 {}
92
93 QMediaServiceProvider *provider;
94 QAudioDecoderControl *control;
95 QAudioDecoder::State state;
96 QAudioDecoder::Error error;
97 QString errorString;
98
99 void _q_stateChanged(QAudioDecoder::State state);
100 void _q_error(int error, const QString &errorString);
101};
102
103void QAudioDecoderPrivate::_q_stateChanged(QAudioDecoder::State ps)
104{
105 Q_Q(QAudioDecoder);
106
107 if (ps != state) {
108 state = ps;
109
110 emit q->stateChanged(newState: ps);
111 }
112}
113
114void QAudioDecoderPrivate::_q_error(int error, const QString &errorString)
115{
116 Q_Q(QAudioDecoder);
117
118 this->error = QAudioDecoder::Error(error);
119 this->errorString = errorString;
120
121 emit q->error(error: this->error);
122}
123
124/*!
125 Construct an QAudioDecoder instance
126 parented to \a parent.
127*/
128QAudioDecoder::QAudioDecoder(QObject *parent)
129 : QMediaObject(*new QAudioDecoderPrivate,
130 parent,
131 QMediaServiceProvider::defaultServiceProvider()->requestService(Q_MEDIASERVICE_AUDIODECODER))
132{
133 Q_D(QAudioDecoder);
134
135 d->provider = QMediaServiceProvider::defaultServiceProvider();
136 if (d->service) {
137 d->control = qobject_cast<QAudioDecoderControl*>(object: d->service->requestControl(QAudioDecoderControl_iid));
138 if (d->control != nullptr) {
139 connect(asender: d->control, SIGNAL(stateChanged(QAudioDecoder::State)), SLOT(_q_stateChanged(QAudioDecoder::State)));
140 connect(asender: d->control, SIGNAL(error(int,QString)), SLOT(_q_error(int,QString)));
141
142 connect(asender: d->control, SIGNAL(formatChanged(QAudioFormat)), SIGNAL(formatChanged(QAudioFormat)));
143 connect(asender: d->control, SIGNAL(sourceChanged()), SIGNAL(sourceChanged()));
144 connect(sender: d->control, SIGNAL(bufferReady()), receiver: this, SIGNAL(bufferReady()));
145 connect(sender: d->control ,SIGNAL(bufferAvailableChanged(bool)), receiver: this, SIGNAL(bufferAvailableChanged(bool)));
146 connect(sender: d->control ,SIGNAL(finished()), receiver: this, SIGNAL(finished()));
147 connect(sender: d->control ,SIGNAL(positionChanged(qint64)), receiver: this, SIGNAL(positionChanged(qint64)));
148 connect(sender: d->control ,SIGNAL(durationChanged(qint64)), receiver: this, SIGNAL(durationChanged(qint64)));
149 }
150 }
151 if (!d->control) {
152 d->error = ServiceMissingError;
153 d->errorString = tr(s: "The QAudioDecoder object does not have a valid service");
154 }
155}
156
157
158/*!
159 Destroys the audio decoder object.
160*/
161QAudioDecoder::~QAudioDecoder()
162{
163 Q_D(QAudioDecoder);
164
165 if (d->service) {
166 if (d->control)
167 d->service->releaseControl(control: d->control);
168
169 d->provider->releaseService(service: d->service);
170 }
171}
172
173QAudioDecoder::State QAudioDecoder::state() const
174{
175 return d_func()->state;
176}
177
178/*!
179 Returns the current error state.
180*/
181
182QAudioDecoder::Error QAudioDecoder::error() const
183{
184 return d_func()->error;
185}
186
187QString QAudioDecoder::errorString() const
188{
189 return d_func()->errorString;
190}
191
192/*!
193 Starts decoding the audio resource.
194
195 As data gets decoded, the \l bufferReady() signal will be emitted
196 when enough data has been decoded. Calling \l read() will then return
197 an audio buffer without blocking.
198
199 If you call read() before a buffer is ready, an invalid buffer will
200 be returned, again without blocking.
201
202 \sa read()
203*/
204void QAudioDecoder::start()
205{
206 Q_D(QAudioDecoder);
207
208 if (d->control == nullptr) {
209 QMetaObject::invokeMethod(obj: this, member: "_q_error", type: Qt::QueuedConnection,
210 Q_ARG(int, QAudioDecoder::ServiceMissingError),
211 Q_ARG(QString, tr("The QAudioDecoder object does not have a valid service")));
212 return;
213 }
214
215 // Reset error conditions
216 d->error = NoError;
217 d->errorString.clear();
218
219 d->control->start();
220}
221
222/*!
223 Stop decoding audio. Calling \l start() again will resume decoding from the beginning.
224*/
225void QAudioDecoder::stop()
226{
227 Q_D(QAudioDecoder);
228
229 if (d->control != nullptr)
230 d->control->stop();
231}
232
233/*!
234 Returns the current file name to decode.
235 If \l setSourceDevice was called, this will
236 be empty.
237*/
238QString QAudioDecoder::sourceFilename() const
239{
240 Q_D(const QAudioDecoder);
241 if (d->control)
242 return d->control->sourceFilename();
243 return QString();
244}
245
246/*!
247 Sets the current audio file name to \a fileName.
248
249 When this property is set any current decoding is stopped,
250 and any audio buffers are discarded.
251
252 You can only specify either a source filename or
253 a source QIODevice. Setting one will unset the other.
254*/
255void QAudioDecoder::setSourceFilename(const QString &fileName)
256{
257 Q_D(QAudioDecoder);
258
259 if (d->control != nullptr)
260 d_func()->control->setSourceFilename(fileName);
261}
262
263/*!
264 Returns the current source QIODevice, if one was set.
265 If \l setSourceFilename() was called, this will be 0.
266*/
267QIODevice *QAudioDecoder::sourceDevice() const
268{
269 Q_D(const QAudioDecoder);
270 if (d->control)
271 return d->control->sourceDevice();
272 return nullptr;
273}
274
275/*!
276 Sets the current audio QIODevice to \a device.
277
278 When this property is set any current decoding is stopped,
279 and any audio buffers are discarded.
280
281 You can only specify either a source filename or
282 a source QIODevice. Setting one will unset the other.
283*/
284void QAudioDecoder::setSourceDevice(QIODevice *device)
285{
286 Q_D(QAudioDecoder);
287
288 if (d->control != nullptr)
289 d_func()->control->setSourceDevice(device);
290}
291
292/*!
293 Returns the current audio format of the decoded stream.
294
295 Any buffers returned should have this format.
296
297 \sa setAudioFormat(), formatChanged()
298*/
299QAudioFormat QAudioDecoder::audioFormat() const
300{
301 Q_D(const QAudioDecoder);
302 if (d->control)
303 return d->control->audioFormat();
304 return QAudioFormat();
305}
306
307/*!
308 Set the desired audio format for decoded samples to \a format.
309
310 This property can only be set while the decoder is stopped.
311 Setting this property at other times will be ignored.
312
313 If the decoder does not support this format, \l error() will
314 be set to \c FormatError.
315
316 If you do not specify a format, the format of the decoded
317 audio itself will be used. Otherwise, some format conversion
318 will be applied.
319
320 If you wish to reset the decoded format to that of the original
321 audio file, you can specify an invalid \a format.
322*/
323void QAudioDecoder::setAudioFormat(const QAudioFormat &format)
324{
325 Q_D(QAudioDecoder);
326
327 if (state() != QAudioDecoder::StoppedState)
328 return;
329
330 if (d->control != nullptr)
331 d_func()->control->setAudioFormat(format);
332}
333
334/*!
335 \internal
336*/
337
338bool QAudioDecoder::bind(QObject *obj)
339{
340 return QMediaObject::bind(obj);
341}
342
343/*!
344 \internal
345*/
346
347void QAudioDecoder::unbind(QObject *obj)
348{
349 QMediaObject::unbind(obj);
350}
351
352/*!
353 Returns the level of support an audio decoder has for a \a mimeType and a set of \a codecs.
354*/
355QMultimedia::SupportEstimate QAudioDecoder::hasSupport(const QString &mimeType,
356 const QStringList& codecs)
357{
358 return QMediaServiceProvider::defaultServiceProvider()->hasSupport(serviceType: QByteArray(Q_MEDIASERVICE_AUDIODECODER),
359 mimeType,
360 codecs);
361}
362
363/*!
364 Returns true if a buffer is available to be read,
365 and false otherwise. If there is no buffer available, calling
366 the \l read() function will return an invalid buffer.
367*/
368bool QAudioDecoder::bufferAvailable() const
369{
370 Q_D(const QAudioDecoder);
371 if (d->control)
372 return d->control->bufferAvailable();
373 return false;
374}
375
376/*!
377 Returns position (in milliseconds) of the last buffer read from
378 the decoder or -1 if no buffers have been read.
379*/
380
381qint64 QAudioDecoder::position() const
382{
383 Q_D(const QAudioDecoder);
384 if (d->control)
385 return d->control->position();
386 return -1;
387}
388
389/*!
390 Returns total duration (in milliseconds) of the audio stream or -1
391 if not available.
392*/
393
394qint64 QAudioDecoder::duration() const
395{
396 Q_D(const QAudioDecoder);
397 if (d->control)
398 return d->control->duration();
399 return -1;
400}
401
402/*!
403 Read a buffer from the decoder, if one is available. Returns an invalid buffer
404 if there are no decoded buffers currently available, or on failure. In both cases
405 this function will not block.
406
407 You should either respond to the \l bufferReady() signal or check the
408 \l bufferAvailable() function before calling read() to make sure
409 you get useful data.
410*/
411
412QAudioBuffer QAudioDecoder::read() const
413{
414 Q_D(const QAudioDecoder);
415
416 if (d->control) {
417 return d->control->read();
418 } else {
419 return QAudioBuffer();
420 }
421}
422
423// Enums
424/*!
425 \enum QAudioDecoder::State
426
427 Defines the current state of a media player.
428
429 \value StoppedState The decoder is not decoding. Decoding will
430 start at the start of the media.
431 \value DecodingState The audio player is currently decoding media.
432*/
433
434/*!
435 \enum QAudioDecoder::Error
436
437 Defines a media player error condition.
438
439 \value NoError No error has occurred.
440 \value ResourceError A media resource couldn't be resolved.
441 \value FormatError The format of a media resource isn't supported.
442 \value AccessDeniedError There are not the appropriate permissions to play a media resource.
443 \value ServiceMissingError A valid playback service was not found, playback cannot proceed.
444*/
445
446// Signals
447/*!
448 \fn QAudioDecoder::error(QAudioDecoder::Error error)
449
450 Signals that an \a error condition has occurred.
451
452 \sa errorString()
453*/
454
455/*!
456 \fn void QAudioDecoder::stateChanged(State state)
457
458 Signal the \a state of the decoder object has changed.
459*/
460
461/*!
462 \fn void QAudioDecoder::sourceChanged()
463
464 Signals that the current source of the decoder has changed.
465
466 \sa sourceFilename(), sourceDevice()
467*/
468
469/*!
470 \fn void QAudioDecoder::formatChanged(const QAudioFormat &format)
471
472 Signals that the current audio format of the decoder has changed to \a format.
473
474 \sa audioFormat(), setAudioFormat()
475*/
476
477/*!
478 \fn void QAudioDecoder::bufferReady()
479
480 Signals that a new decoded audio buffer is available to be read.
481
482 \sa read(), bufferAvailable()
483*/
484
485/*!
486 \fn void QAudioDecoder::bufferAvailableChanged(bool available)
487
488 Signals the availability (if \a available is true) of a new buffer.
489
490 If \a available is false, there are no buffers available.
491
492 \sa bufferAvailable(), bufferReady()
493*/
494
495/*!
496 \fn void QAudioDecoder::finished()
497
498 Signals that the decoding has finished successfully.
499 If decoding fails, error signal is emitted instead.
500
501 \sa start(), stop(), error()
502*/
503
504/*!
505 \fn void QAudioDecoder::positionChanged(qint64 position)
506
507 Signals that the current \a position of the decoder has changed.
508
509 \sa durationChanged()
510*/
511
512/*!
513 \fn void QAudioDecoder::durationChanged(qint64 duration)
514
515 Signals that the estimated \a duration of the decoded data has changed.
516
517 \sa positionChanged()
518*/
519
520
521// Properties
522/*!
523 \property QAudioDecoder::state
524 \brief the audio decoder's playback state.
525
526 By default this property is QAudioDecoder::Stopped
527
528 \sa start(), stop()
529*/
530
531/*!
532 \property QAudioDecoder::error
533 \brief a string describing the last error condition.
534
535 \sa error()
536*/
537
538/*!
539 \property QAudioDecoder::sourceFilename
540 \brief the active filename being decoded by the decoder object.
541*/
542
543/*!
544 \property QAudioDecoder::bufferAvailable
545 \brief whether there is a decoded audio buffer available
546*/
547
548QT_END_NAMESPACE
549
550#include "moc_qaudiodecoder.cpp"
551

source code of qtmultimedia/src/multimedia/audio/qaudiodecoder.cpp