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"
7#include "qaudiosystem_p.h"
8#include "qaudiosink.h"
9
10#include <private/qplatformmediadevices_p.h>
11#include <private/qplatformmediaintegration_p.h>
12
13QT_BEGIN_NAMESPACE
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()->mediaDevices()->audioOutputDevice(format, deviceInfo: audioDevice, parent);
91 if (d)
92 connect(sender: d, signal: &QPlatformAudioSink::stateChanged, context: this, slot: [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 d->elapsedTime.restart();
147 d->start(device);
148}
149
150/*!
151 Returns a pointer to the internal QIODevice being used to transfer data to
152 the system's audio output. The device will already be open and
153 \l{QIODevice::write()}{write()} can write data directly to it.
154
155 \note The pointer will become invalid after the stream is stopped or
156 if you start another stream.
157
158 If the QAudioSink is able to access the system's audio device, state() returns
159 QtAudio::IdleState, error() returns QtAudio::NoError
160 and the stateChanged() signal is emitted.
161
162 If a problem occurs during this process, error() returns QtAudio::OpenError,
163 state() returns QtAudio::StoppedState and the stateChanged() signal is emitted.
164
165 \sa QIODevice
166*/
167QIODevice* QAudioSink::start()
168{
169 if (!d)
170 return nullptr;
171 d->elapsedTime.restart();
172 return d->start();
173}
174
175/*!
176 Stops the audio output, detaching from the system resource.
177
178 Sets error() to QtAudio::NoError, state() to QtAudio::StoppedState and
179 emit stateChanged() signal.
180
181 \note On Linux, and Darwin, this operation synchronously drains the
182 underlying audio buffer, which may cause delays accordingly to the
183 buffer payload. To reset all the buffers immediately, use the method
184 \l reset instead.
185 \sa reset()
186*/
187void QAudioSink::stop()
188{
189 if (d)
190 d->stop();
191}
192
193/*!
194 Drops all audio data in the buffers, resets buffers to zero.
195
196*/
197void QAudioSink::reset()
198{
199 if (d)
200 d->reset();
201}
202
203/*!
204 Stops processing audio data, preserving buffered audio data.
205
206 Sets error() to QtAudio::NoError, state() to QtAudio::SuspendedState and
207 emits stateChanged() signal.
208*/
209void QAudioSink::suspend()
210{
211 if (d)
212 d->suspend();
213}
214
215/*!
216 Resumes processing audio data after a suspend().
217
218 Sets state() to the state the sink had when suspend() was called, and sets
219 error() to QAudioError::NoError. This function does nothing if the audio sink's
220 state is not QtAudio::SuspendedState.
221*/
222void QAudioSink::resume()
223{
224 if (d)
225 d->resume();
226}
227
228/*!
229 Returns the number of free bytes available in the audio buffer.
230
231 \note The returned value is only valid while in QtAudio::ActiveState or QtAudio::IdleState
232 state, otherwise returns zero.
233*/
234qsizetype QAudioSink::bytesFree() const
235{
236 return d ? d->bytesFree() : 0;
237}
238
239/*!
240 Sets the audio buffer size to \a value in bytes.
241
242 \note This function can be called anytime before start(). Calls to this
243 are ignored after start(). It should not be assumed that the buffer size
244 set is the actual buffer size used - call bufferSize() anytime after start()
245 to return the actual buffer size being used.
246*/
247void QAudioSink::setBufferSize(qsizetype value)
248{
249 if (d)
250 d->setBufferSize(value);
251}
252
253/*!
254 Returns the audio buffer size in bytes.
255
256 If called before start(), returns platform default value.
257 If called before start() but setBufferSize() was called prior, returns value set by setBufferSize().
258 If called after start(), returns the actual buffer size being used. This may not be what was set previously
259 by setBufferSize().
260
261*/
262qsizetype QAudioSink::bufferSize() const
263{
264 return d ? d->bufferSize() : 0;
265}
266
267/*!
268 Returns the amount of audio data processed since start()
269 was called (in microseconds).
270*/
271qint64 QAudioSink::processedUSecs() const
272{
273 return d ? d->processedUSecs() : 0;
274}
275
276/*!
277 Returns the microseconds since start() was called, including time in Idle and
278 Suspend states.
279*/
280qint64 QAudioSink::elapsedUSecs() const
281{
282 return state() == QAudio::StoppedState ? 0 : d->elapsedTime.nsecsElapsed()/1000;
283}
284
285/*!
286 Returns the error state.
287*/
288QtAudio::Error QAudioSink::error() const
289{
290 return d ? d->error() : QAudio::OpenError;
291}
292
293/*!
294 Returns the state of audio processing.
295*/
296QtAudio::State QAudioSink::state() const
297{
298 return d ? d->state() : QAudio::StoppedState;
299}
300
301/*!
302 Sets the output volume to \a volume.
303
304 The volume is scaled linearly from \c 0.0 (silence) to \c 1.0 (full volume).
305 Values outside this range will be clamped.
306
307 The default volume is \c 1.0.
308
309 \note Adjustments to the volume will change the volume of this audio stream,
310 not the global volume.
311
312 UI volume controls should usually be scaled non-linearly. For example, using
313 a logarithmic scale will produce linear changes in perceived loudness, which
314 is what a user would normally expect from a volume control. See
315 QtAudio::convertVolume() for more details.
316*/
317void QAudioSink::setVolume(qreal volume)
318{
319 if (!d)
320 return;
321 qreal v = qBound(min: qreal(0.0), val: volume, max: qreal(1.0));
322 d->setVolume(v);
323}
324
325/*!
326 Returns the volume between 0.0 and 1.0 inclusive.
327*/
328qreal QAudioSink::volume() const
329{
330 return d ? d->volume() : 1.0;
331}
332
333/*!
334 \fn QAudioSink::stateChanged(QtAudio::State state)
335 This signal is emitted when the device \a state has changed.
336 This is the current state of the audio output.
337
338 \note The QtAudio namespace was named QAudio up to and including Qt 6.6.
339 String-based connections to this signal have to use \c{QAudio::State} as
340 the parameter type: \c{connect(source, SIGNAL(stateChanged(QAudio::State)), ...);}
341*/
342
343QT_END_NAMESPACE
344
345#include "moc_qaudiosink.cpp"
346

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

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