1 | // Copyright (C) 2016 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | #include "qaudiodecoder.h" |
5 | |
6 | #include <private/qaudiodecoder_p.h> |
7 | #include <private/qmultimediautils_p.h> |
8 | #include <private/qplatformaudiodecoder_p.h> |
9 | #include <private/qplatformmediaintegration_p.h> |
10 | |
11 | #include <QtCore/qcoreevent.h> |
12 | #include <QtCore/qdebug.h> |
13 | #include <QtCore/qmetaobject.h> |
14 | #include <QtCore/qpointer.h> |
15 | #include <QtCore/qtimer.h> |
16 | #include <QtCore/qurl.h> |
17 | |
18 | QT_BEGIN_NAMESPACE |
19 | |
20 | /*! |
21 | \class QAudioDecoder |
22 | \brief The QAudioDecoder class implements decoding audio. |
23 | \inmodule QtMultimedia |
24 | \ingroup multimedia |
25 | \ingroup multimedia_audio |
26 | |
27 | \preliminary |
28 | |
29 | The QAudioDecoder class is a high level class for decoding |
30 | audio media files. It is similar to the QMediaPlayer class except |
31 | that audio is provided back through this API rather than routed |
32 | directly to audio hardware. |
33 | |
34 | \sa QAudioBuffer |
35 | */ |
36 | |
37 | /*! |
38 | Construct an QAudioDecoder instance with \a parent. |
39 | */ |
40 | QAudioDecoder::QAudioDecoder(QObject *parent) : QObject{ *new QAudioDecoderPrivate, parent } |
41 | { |
42 | QT6_ONLY(Q_UNUSED(unused)) |
43 | |
44 | Q_D(QAudioDecoder); |
45 | |
46 | auto maybeDecoder = QPlatformMediaIntegration::instance()->createAudioDecoder(this); |
47 | if (maybeDecoder) { |
48 | d->decoder.reset(p: maybeDecoder.value()); |
49 | } else { |
50 | qWarning() << "Failed to initialize QAudioDecoder" << maybeDecoder.error(); |
51 | } |
52 | } |
53 | |
54 | /*! |
55 | Destroys the audio decoder object. |
56 | */ |
57 | QAudioDecoder::~QAudioDecoder() = default; |
58 | |
59 | /*! |
60 | Returns true is audio decoding is supported on this platform. |
61 | */ |
62 | bool QAudioDecoder::isSupported() const |
63 | { |
64 | Q_D(const QAudioDecoder); |
65 | |
66 | return bool(d->decoder); |
67 | } |
68 | |
69 | /*! |
70 | \property QAudioDecoder::isDecoding |
71 | \brief \c true if the decoder is currently running and decoding audio data. |
72 | */ |
73 | bool QAudioDecoder::isDecoding() const |
74 | { |
75 | Q_D(const QAudioDecoder); |
76 | |
77 | return d->decoder && d->decoder->isDecoding(); |
78 | } |
79 | |
80 | /*! |
81 | |
82 | Returns the current error state of the QAudioDecoder. |
83 | */ |
84 | QAudioDecoder::Error QAudioDecoder::error() const |
85 | { |
86 | Q_D(const QAudioDecoder); |
87 | return d->decoder ? d->decoder->error() : NotSupportedError; |
88 | } |
89 | |
90 | /*! |
91 | \property QAudioDecoder::error |
92 | |
93 | Returns a human readable description of the current error, or |
94 | an empty string is there is no error. |
95 | */ |
96 | QString QAudioDecoder::errorString() const |
97 | { |
98 | Q_D(const QAudioDecoder); |
99 | if (!d->decoder) |
100 | return tr(s: "QAudioDecoder not supported." ); |
101 | return d->decoder->errorString(); |
102 | } |
103 | |
104 | /*! |
105 | Starts decoding the audio resource. |
106 | |
107 | As data gets decoded, the \l bufferReady() signal will be emitted |
108 | when enough data has been decoded. Calling \l read() will then return |
109 | an audio buffer without blocking. |
110 | |
111 | If you call read() before a buffer is ready, an invalid buffer will |
112 | be returned, again without blocking. |
113 | |
114 | \sa read() |
115 | */ |
116 | void QAudioDecoder::start() |
117 | { |
118 | Q_D(QAudioDecoder); |
119 | |
120 | if (!d->decoder) |
121 | return; |
122 | |
123 | // Reset error conditions |
124 | d->decoder->clearError(); |
125 | d->decoder->start(); |
126 | } |
127 | |
128 | /*! |
129 | Stop decoding audio. Calling \l start() again will resume decoding from the beginning. |
130 | */ |
131 | void QAudioDecoder::stop() |
132 | { |
133 | Q_D(QAudioDecoder); |
134 | |
135 | if (d->decoder) |
136 | d->decoder->stop(); |
137 | } |
138 | |
139 | /*! |
140 | Returns the current file name to decode. |
141 | If \l setSourceDevice was called, this will |
142 | be empty. |
143 | */ |
144 | QUrl QAudioDecoder::source() const |
145 | { |
146 | Q_D(const QAudioDecoder); |
147 | return d->unresolvedUrl; |
148 | } |
149 | |
150 | /*! |
151 | Sets the current audio file name to \a fileName. |
152 | |
153 | When this property is set any current decoding is stopped, |
154 | and any audio buffers are discarded. |
155 | |
156 | You can only specify either a source filename or |
157 | a source QIODevice. Setting one will unset the other. |
158 | */ |
159 | void QAudioDecoder::setSource(const QUrl &fileName) |
160 | { |
161 | Q_D(QAudioDecoder); |
162 | |
163 | if (!d->decoder) |
164 | return; |
165 | |
166 | d->decoder->clearError(); |
167 | d->unresolvedUrl = fileName; |
168 | d->decoder->setSourceDevice(nullptr); |
169 | QUrl url = qMediaFromUserInput(fileName); |
170 | d->decoder->setSource(url); |
171 | } |
172 | |
173 | /*! |
174 | Returns the current source QIODevice, if one was set. |
175 | If \l setSource() was called, this will be a nullptr. |
176 | */ |
177 | QIODevice *QAudioDecoder::sourceDevice() const |
178 | { |
179 | Q_D(const QAudioDecoder); |
180 | return d->decoder ? d->decoder->sourceDevice() : nullptr; |
181 | } |
182 | |
183 | /*! |
184 | Sets the current audio QIODevice to \a device. |
185 | |
186 | When this property is set any current decoding is stopped, |
187 | and any audio buffers are discarded. |
188 | |
189 | You can only specify either a source filename or |
190 | a source QIODevice. Setting one will unset the other. |
191 | */ |
192 | void QAudioDecoder::setSourceDevice(QIODevice *device) |
193 | { |
194 | Q_D(QAudioDecoder); |
195 | if (d->decoder) { |
196 | d->unresolvedUrl = QUrl{}; |
197 | d->decoder->setSourceDevice(device); |
198 | } |
199 | } |
200 | |
201 | /*! |
202 | Returns the audio format the decoder is set to. |
203 | |
204 | \note This may be different than the format of the decoded |
205 | samples, if the audio format was set to an invalid one. |
206 | |
207 | \sa setAudioFormat(), formatChanged() |
208 | */ |
209 | QAudioFormat QAudioDecoder::audioFormat() const |
210 | { |
211 | Q_D(const QAudioDecoder); |
212 | return d->decoder ? d->decoder->audioFormat() : QAudioFormat{}; |
213 | } |
214 | |
215 | /*! |
216 | Set the desired audio format for decoded samples to \a format. |
217 | |
218 | This property can only be set while the decoder is stopped. |
219 | Setting this property at other times will be ignored. |
220 | |
221 | If the decoder does not support this format, \l error() will |
222 | be set to \c FormatError. |
223 | |
224 | If you do not specify a format, the format of the decoded |
225 | audio itself will be used. Otherwise, some format conversion |
226 | will be applied. |
227 | |
228 | If you wish to reset the decoded format to that of the original |
229 | audio file, you can specify an invalid \a format. |
230 | |
231 | \warning Setting a desired audio format is not yet supported |
232 | on the Android backend. It does work with the default FFMPEG |
233 | backend. |
234 | */ |
235 | void QAudioDecoder::setAudioFormat(const QAudioFormat &format) |
236 | { |
237 | if (isDecoding()) |
238 | return; |
239 | |
240 | Q_D(QAudioDecoder); |
241 | |
242 | if (d->decoder) |
243 | d->decoder->setAudioFormat(format); |
244 | } |
245 | |
246 | /*! |
247 | Returns true if a buffer is available to be read, |
248 | and false otherwise. If there is no buffer available, calling |
249 | the \l read() function will return an invalid buffer. |
250 | */ |
251 | bool QAudioDecoder::bufferAvailable() const |
252 | { |
253 | Q_D(const QAudioDecoder); |
254 | return d->decoder && d->decoder->bufferAvailable(); |
255 | } |
256 | |
257 | /*! |
258 | Returns position (in milliseconds) of the last buffer read from |
259 | the decoder or -1 if no buffers have been read. |
260 | */ |
261 | |
262 | qint64 QAudioDecoder::position() const |
263 | { |
264 | Q_D(const QAudioDecoder); |
265 | return d->decoder ? d->decoder->position() : -1; |
266 | } |
267 | |
268 | /*! |
269 | Returns total duration (in milliseconds) of the audio stream or -1 |
270 | if not available. |
271 | */ |
272 | |
273 | qint64 QAudioDecoder::duration() const |
274 | { |
275 | Q_D(const QAudioDecoder); |
276 | return d->decoder ? d->decoder->duration() : -1; |
277 | } |
278 | |
279 | /*! |
280 | Read a buffer from the decoder, if one is available. Returns an invalid buffer |
281 | if there are no decoded buffers currently available, or on failure. In both cases |
282 | this function will not block. |
283 | |
284 | You should either respond to the \l bufferReady() signal or check the |
285 | \l bufferAvailable() function before calling read() to make sure |
286 | you get useful data. |
287 | */ |
288 | |
289 | QAudioBuffer QAudioDecoder::read() const |
290 | { |
291 | Q_D(const QAudioDecoder); |
292 | return d->decoder ? d->decoder->read() : QAudioBuffer{}; |
293 | } |
294 | |
295 | // Enums |
296 | /*! |
297 | \enum QAudioDecoder::Error |
298 | |
299 | Defines a media player error condition. |
300 | |
301 | \value NoError No error has occurred. |
302 | \value ResourceError A media resource couldn't be resolved. |
303 | \value FormatError The format of a media resource isn't supported. |
304 | \value AccessDeniedError There are not the appropriate permissions to play a media resource. |
305 | \value NotSupportedError QAudioDecoder is not supported on this platform |
306 | */ |
307 | |
308 | // Signals |
309 | /*! |
310 | \fn void QAudioDecoder::error(QAudioDecoder::Error error) |
311 | |
312 | Signals that an \a error condition has occurred. |
313 | |
314 | \sa errorString() |
315 | */ |
316 | |
317 | /*! |
318 | \fn void QAudioDecoder::sourceChanged() |
319 | |
320 | Signals that the current source of the decoder has changed. |
321 | |
322 | \sa source(), sourceDevice() |
323 | */ |
324 | |
325 | /*! |
326 | \fn void QAudioDecoder::formatChanged(const QAudioFormat &format) |
327 | |
328 | Signals that the current audio format of the decoder has changed to \a format. |
329 | |
330 | \sa audioFormat(), setAudioFormat() |
331 | */ |
332 | |
333 | /*! |
334 | \fn void QAudioDecoder::bufferReady() |
335 | |
336 | Signals that a new decoded audio buffer is available to be read. |
337 | |
338 | \sa read(), bufferAvailable() |
339 | */ |
340 | |
341 | /*! |
342 | \fn void QAudioDecoder::bufferAvailableChanged(bool available) |
343 | |
344 | Signals the availability (if \a available is true) of a new buffer. |
345 | |
346 | If \a available is false, there are no buffers available. |
347 | |
348 | \sa bufferAvailable(), bufferReady() |
349 | */ |
350 | |
351 | /*! |
352 | \fn void QAudioDecoder::finished() |
353 | |
354 | Signals that the decoding has finished successfully. |
355 | If decoding fails, error signal is emitted instead. |
356 | |
357 | \sa start(), stop(), error() |
358 | */ |
359 | |
360 | /*! |
361 | \fn void QAudioDecoder::positionChanged(qint64 position) |
362 | |
363 | Signals that the current \a position of the decoder has changed. |
364 | |
365 | \sa durationChanged() |
366 | */ |
367 | |
368 | /*! |
369 | \fn void QAudioDecoder::durationChanged(qint64 duration) |
370 | |
371 | Signals that the estimated \a duration of the decoded data has changed. |
372 | |
373 | \sa positionChanged() |
374 | */ |
375 | |
376 | // Properties |
377 | /*! |
378 | \property QAudioDecoder::source |
379 | \brief the active filename being decoded by the decoder object. |
380 | */ |
381 | |
382 | /*! |
383 | \property QAudioDecoder::bufferAvailable |
384 | \brief whether there is a decoded audio buffer available |
385 | */ |
386 | |
387 | QT_END_NAMESPACE |
388 | |
389 | #include "moc_qaudiodecoder.cpp" |
390 | |