Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qaudiosink.cpp
Go to the documentation of this file.
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
5#include "qaudio.h"
6#include "qaudiodevice.h"
8#include "qaudiosink.h"
9
10#include <private/qplatformaudiodevices_p.h>
11#include <private/qplatformmediaintegration_p.h>
12
14
15/*!
16 \class QAudioSink
17 \brief The QAudioSink class provides an interface for sending audio data to
18 an audio output device.
19
20 \inmodule QtMultimedia
21 \ingroup multimedia
22 \ingroup multimedia_audio
23
24 You can construct an audio output with the system's
25 default audio output device. It is also possible to
26 create QAudioSink with a specific QAudioDevice. When
27 you create the audio output, you should also send in
28 the QAudioFormat to be used for the playback (see
29 the QAudioFormat class description for details).
30
31 To play a file:
32
33 Starting to play an audio stream is simply a matter of calling
34 start() with a QIODevice. QAudioSink will then fetch the data it
35 needs from the io device. So playing back an audio file is as
36 simple as:
37
38 \snippet multimedia-snippets/audio.cpp Audio output class members
39
40 \snippet multimedia-snippets/audio.cpp Audio output setup
41
42 The file will start playing assuming that the audio system and
43 output device support it. If you run out of luck, check what's
44 up with the error() function.
45
46 After the file has finished playing, we need to stop the device:
47
48 \snippet multimedia-snippets/audio.cpp Audio output stop
49
50 At any given time, the QAudioSink will be in one of four states:
51 active, suspended, stopped, or idle. These states are described
52 by the QtAudio::State enum.
53 State changes are reported through the stateChanged() signal. You
54 can use this signal to, for instance, update the GUI of the
55 application; the mundane example here being changing the state of
56 a \c { play/pause } button. You request a state change directly
57 with suspend(), stop(), reset(), resume(), and start().
58
59 If an error occurs, you can fetch the \l{QtAudio::Error}{error
60 type} with the error() function. Please see the QtAudio::Error enum
61 for a description of the possible errors that are reported. When
62 QtAudio::UnderrunError is encountered, the state changes to QtAudio::IdleState,
63 when another error is encountered, the state changes to QtAudio::StoppedState.
64 You can check for errors by connecting to the stateChanged()
65 signal:
66
67 \snippet multimedia-snippets/audio.cpp Audio output state changed
68
69 \sa QAudioSource, QAudioDevice
70*/
71
72/*!
73 Construct a new audio output and attach it to \a parent.
74 The default audio output device is used with the output
75 \a format parameters.
76*/
77QAudioSink::QAudioSink(const QAudioFormat &format, QObject *parent)
78 : QAudioSink({}, format, parent)
79{
80}
81
82/*!
83 Construct a new audio output and attach it to \a parent.
84 The device referenced by \a audioDevice is used with the output
85 \a format parameters.
86*/
87QAudioSink::QAudioSink(const QAudioDevice &audioDevice, const QAudioFormat &format, QObject *parent):
88 QObject(parent)
89{
90 d = QPlatformMediaIntegration::instance()->audioDevices()->audioOutputDevice(format, audioDevice, parent);
91 if (d)
92 connect(d, &QPlatformAudioSink::stateChanged, this, [this](QAudio::State state) {
93 // if the signal has been emitted from another thread,
94 // the state may be already changed by main one
95 if (state == d->state())
96 emit stateChanged(state);
97 });
98 else
99 qWarning() << ("No audio device detected");
100}
101
102/*!
103 \fn bool QAudioSink::isNull() const
104
105 Returns \c true is the QAudioSink instance is \c null, otherwise returns
106 \c false.
107*/
108
109/*!
110 Destroys this audio output.
111
112 This will release any system resources used and free any buffers.
113*/
114QAudioSink::~QAudioSink()
115{
116 delete d;
117}
118
119/*!
120 Returns the QAudioFormat being used.
121
122*/
123QAudioFormat QAudioSink::format() const
124{
125 return d ? d->format() : QAudioFormat();
126}
127
128/*!
129 Starts transferring audio data from the \a device to the system's audio output.
130 The \a device must have been opened in the \l{QIODevice::ReadOnly}{ReadOnly} or
131 \l{QIODevice::ReadWrite}{ReadWrite} modes.
132
133 If the QAudioSink is able to successfully output audio data, state() returns
134 QtAudio::ActiveState, error() returns QtAudio::NoError
135 and the stateChanged() signal is emitted.
136
137 If a problem occurs during this process, error() returns QtAudio::OpenError,
138 state() returns QtAudio::StoppedState and the stateChanged() signal is emitted.
139
140 \sa QIODevice
141*/
142void QAudioSink::start(QIODevice* device)
143{
144 if (!d)
145 return;
146
147 if (!device->isReadable()) {
148 qWarning() << "QAudioSink::start: QIODevice is not readable";
149 d->setError(QAudio::OpenError);
150 return;
151 }
152
153 d->elapsedTime.restart();
154 d->start(device);
155}
156
157/*!
158 Returns a pointer to the internal QIODevice being used to transfer data to
159 the system's audio output. The device will already be open and
160 \l{QIODevice::write()}{write()} can write data directly to it.
161
162 \note The pointer will become invalid after the stream is stopped or
163 if you start another stream.
164
165 If the QAudioSink is able to access the system's audio device, state() returns
166 QtAudio::IdleState, error() returns QtAudio::NoError
167 and the stateChanged() signal is emitted.
168
169 If a problem occurs during this process, error() returns QtAudio::OpenError,
170 state() returns QtAudio::StoppedState and the stateChanged() signal is emitted.
171
172 \sa QIODevice
173*/
174QIODevice* QAudioSink::start()
175{
176 if (!d)
177 return nullptr;
178 d->elapsedTime.restart();
179 return d->start();
180}
181
182/*!
183 Stops the audio output, detaching from the system resource.
184
185 Sets error() to QtAudio::NoError, state() to QtAudio::StoppedState and
186 emit stateChanged() signal.
187
188 \note On Linux, and Darwin, this operation synchronously drains the
189 underlying audio buffer, which may cause delays accordingly to the
190 buffer payload. To reset all the buffers immediately, use the method
191 \l reset instead.
192 \sa reset()
193*/
194void QAudioSink::stop()
195{
196 if (d)
197 d->stop();
198}
199
200/*!
201 Immediately halts audio output and discards any audio data currently in the buffers. All pending
202 audio data pushed to QIODevice is ignored.
203
204 \sa stop()
205*/
206void QAudioSink::reset()
207{
208 if (d)
209 d->reset();
210}
211
212/*!
213 Stops processing audio data, preserving buffered audio data.
214
215 Sets error() to QtAudio::NoError, state() to QtAudio::SuspendedState and
216 emits stateChanged() signal.
217*/
218void QAudioSink::suspend()
219{
220 if (d)
221 d->suspend();
222}
223
224/*!
225 Resumes processing audio data after a suspend().
226
227 Sets state() to the state the sink had when suspend() was called, and sets
228 error() to QAudioError::NoError. This function does nothing if the audio sink's
229 state is not QtAudio::SuspendedState.
230*/
231void QAudioSink::resume()
232{
233 if (d)
234 d->resume();
235}
236
237/*!
238 Returns the number of free bytes available in the audio buffer.
239
240 \note The returned value is only valid while in QtAudio::ActiveState or QtAudio::IdleState
241 state, otherwise returns zero.
242*/
243qsizetype QAudioSink::bytesFree() const
244{
245 return d ? d->bytesFree() : 0;
246}
247
248/*!
249 Sets the audio buffer size to \a value in bytes.
250
251 \note This function can be called anytime before start(). Calls to this
252 are ignored after start(). It should not be assumed that the buffer size
253 set is the actual buffer size used - call bufferSize() anytime after start()
254 to return the actual buffer size being used.
255*/
256void QAudioSink::setBufferSize(qsizetype value)
257{
258 if (d)
259 d->setBufferSize(value);
260}
261
262/*!
263 Returns the audio buffer size in bytes.
264
265 If called before start(), returns platform default value.
266 If called before start() but setBufferSize() was called prior, returns value set by setBufferSize().
267 If called after start(), returns the actual buffer size being used. This may not be what was set previously
268 by setBufferSize().
269
270*/
271qsizetype QAudioSink::bufferSize() const
272{
273 return d ? d->bufferSize() : 0;
274}
275
276/*!
277 Returns the amount of audio data processed since start()
278 was called (in microseconds).
279*/
280qint64 QAudioSink::processedUSecs() const
281{
282 return d ? d->processedUSecs() : 0;
283}
284
285/*!
286 Returns the microseconds since start() was called, including time in Idle and
287 Suspend states.
288*/
289qint64 QAudioSink::elapsedUSecs() const
290{
291 return state() == QAudio::StoppedState ? 0 : d->elapsedTime.nsecsElapsed()/1000;
292}
293
294/*!
295 Returns the error state.
296*/
297QtAudio::Error QAudioSink::error() const
298{
299 return d ? d->error() : QAudio::OpenError;
300}
301
302/*!
303 Returns the state of audio processing.
304*/
305QtAudio::State QAudioSink::state() const
306{
307 return d ? d->state() : QAudio::StoppedState;
308}
309
310/*!
311 Sets the output volume to \a volume.
312
313 The volume is scaled linearly from \c 0.0 (silence) to \c 1.0 (full volume).
314 Values outside this range will be clamped.
315
316 The default volume is \c 1.0.
317
318 \note Adjustments to the volume will change the volume of this audio stream,
319 not the global volume.
320
321 UI volume controls should usually be scaled non-linearly. For example, using
322 a logarithmic scale will produce linear changes in perceived loudness, which
323 is what a user would normally expect from a volume control. See
324 QtAudio::convertVolume() for more details.
325*/
326void QAudioSink::setVolume(qreal volume)
327{
328 if (!d)
329 return;
330 qreal v = qBound(qreal(0.0), volume, qreal(1.0));
331 d->setVolume(v);
332}
333
334/*!
335 Returns the volume between 0.0 and 1.0 inclusive.
336*/
337qreal QAudioSink::volume() const
338{
339 return d ? d->volume() : 1.0;
340}
341
342/*!
343 \fn QAudioSink::stateChanged(QtAudio::State state)
344 This signal is emitted when the device \a state has changed.
345 This is the current state of the audio output.
346
347 \note The QtAudio namespace was named QAudio up to and including Qt 6.6.
348 String-based connections to this signal have to use \c{QAudio::State} as
349 the parameter type: \c{connect(source, SIGNAL(stateChanged(QAudio::State)), ...);}
350*/
351
352QT_END_NAMESPACE
353
354#include "moc_qaudiosink.cpp"
Combined button and popup list for selecting options.