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
qaudiosource.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#include "qaudiosource.h"
5
6#include <QtMultimedia/qaudio.h>
7#include <QtMultimedia/qaudiodevice.h>
8#include <QtMultimedia/private/qaudiosystem_p.h>
9#include <QtMultimedia/private/qaudiohelpers_p.h>
10#include <QtMultimedia/private/qplatformaudiodevices_p.h>
11#include <QtMultimedia/private/qplatformmediaintegration_p.h>
12
14
15/*!
16 \class QAudioSource
17 \brief The QAudioSource class provides an interface for receiving audio data from an audio input device.
18
19 \inmodule QtMultimedia
20 \ingroup multimedia
21 \ingroup multimedia_audio
22
23 You can construct an audio input with the system's
24 default audio input device. It is also possible to
25 create QAudioSource with a specific QAudioDevice. When
26 you create the audio input, you should also send in the
27 QAudioFormat to be used for the recording (see the QAudioFormat
28 class description for details).
29
30 To record to a file:
31
32 QAudioSource lets you record audio with an audio input device. The
33 default constructor of this class will use the systems default
34 audio device, but you can also specify a QAudioDevice for a
35 specific device. You also need to pass in the QAudioFormat in
36 which you wish to record.
37
38 Starting up the QAudioSource is simply a matter of calling start()
39 with a QIODevice opened for writing. For instance, to record to a
40 file, you can:
41
42 \snippet multimedia-snippets/audio.cpp Audio input class members
43
44 \snippet multimedia-snippets/audio.cpp Audio input setup
45
46 This will start recording if the format specified is supported by
47 the input device (you can check this with
48 QAudioDevice::isFormatSupported(). In case there are any
49 snags, use the error() function to check what went wrong. We stop
50 recording in the \c stopRecording() slot.
51
52 \snippet multimedia-snippets/audio.cpp Audio input stop recording
53
54 At any point in time, QAudioSource will be in one of four states:
55 active, suspended, stopped, or idle. These states are specified by
56 the QtAudio::State enum. You can request a state change directly through
57 suspend(), resume(), stop(), reset(), and start(). The current
58 state is reported by state(). QAudioSink will also signal you
59 when the state changes (stateChanged()).
60
61 QAudioSource provides several ways of measuring the time that has
62 passed since the start() of the recording. The \c processedUSecs()
63 function returns the length of the stream in microseconds written,
64 i.e., it leaves out the times the audio input was suspended or idle.
65 The elapsedUSecs() function returns the time elapsed since start() was called regardless of
66 which states the QAudioSource has been in.
67
68 If an error should occur, you can fetch its reason with error().
69 The possible error reasons are described by the QtAudio::Error
70 enum. The QAudioSource will enter the \l{QtAudio::}{StoppedState} when
71 an error is encountered. Connect to the stateChanged() signal to
72 handle the error:
73
74 \snippet multimedia-snippets/audio.cpp Audio input state changed
75
76 \sa QAudioSink, QAudioDevice
77*/
78
79/*!
80 Construct a new audio input and attach it to \a parent.
81 The default audio input device is used with the output
82 \a format parameters. If \a format is default-initialized,
83 the format will be set to the preferred format of the audio device.
84*/
85
86QAudioSource::QAudioSource(const QAudioFormat &format, QObject *parent)
87 : QAudioSource({}, format, parent)
88{
89}
90
91/*!
92 Construct a new audio input and attach it to \a parent.
93 The device referenced by \a audioDevice is used with the input
94 \a format parameters. If \a format is default-initialized,
95 the format will be set to the preferred format of \a audioDevice.
96*/
97
98QAudioSource::QAudioSource(const QAudioDevice &audioDevice, const QAudioFormat &format, QObject *parent):
99 QObject(parent)
100{
101 d = QPlatformMediaIntegration::instance()->audioDevices()->audioInputDevice(format, audioDevice,
102 this);
103 if (d)
104 connect(d, &QPlatformAudioSource::stateChanged, this, &QAudioSource::stateChanged);
105 else
106 qWarning("No audio device detected");
107}
108
109/*!
110 \fn bool QAudioSource::isNull() const
111
112 Returns \c true if the audio source is \c null, otherwise returns \c false.
113*/
114
115/*!
116 Destroy this audio input.
117*/
118
119QAudioSource::~QAudioSource()
120{
121 delete d;
122}
123
124static bool validateFormatAtStart(QPlatformAudioSource *d)
125{
126 if (!d->format().isValid()) {
127 qWarning() << "QAudioSource::start: QAudioFormat not valid";
128 d->setError(QAudio::OpenError);
129 return false;
130 }
131
132 if (!d->isFormatSupported(d->format())) {
133 qWarning() << "QAudioSource::start: QAudioFormat not supported by QAudioDevice";
134 d->setError(QAudio::OpenError);
135 return false;
136 }
137 return true;
138};
139
140/*!
141 Starts transferring audio data from the system's audio input to the \a device.
142 The \a device must have been opened in the \l{QIODevice::WriteOnly}{WriteOnly},
143 \l{QIODevice::Append}{Append} or \l{QIODevice::ReadWrite}{ReadWrite} modes.
144
145 If the QAudioSource is able to successfully get audio data, state() returns
146 either QtAudio::ActiveState or QtAudio::IdleState, error() returns QtAudio::NoError
147 and the stateChanged() signal is emitted.
148
149 If a problem occurs during this process, error() returns QtAudio::OpenError,
150 state() returns QtAudio::StoppedState and the stateChanged() signal is emitted.
151
152 \sa QIODevice
153*/
154
155void QAudioSource::start(QIODevice* device)
156{
157 if (!d)
158 return;
159
160 d->setError(QAudio::NoError);
161
162 if (!device->isWritable()) {
163 qWarning() << "QAudioSource::start: QIODevice is not writable";
164 d->setError(QAudio::OpenError);
165 return;
166 }
167
168 if (!validateFormatAtStart(d))
169 return;
170
171 d->elapsedTime.start();
172 d->start(device);
173}
174
175/*!
176 Returns a pointer to the internal QIODevice being used to transfer data from
177 the system's audio input. The device will already be open and
178 \l{QIODevice::read()}{read()} can read data directly from it.
179
180 \note The pointer will become invalid after the stream is stopped or
181 if you start another stream.
182
183 If the QAudioSource is able to access the system's audio device, state() returns
184 QtAudio::IdleState, error() returns QtAudio::NoError
185 and the stateChanged() signal is emitted.
186
187 If a problem occurs during this process, error() returns QtAudio::OpenError,
188 state() returns QtAudio::StoppedState and the stateChanged() signal is emitted.
189
190 \sa QIODevice
191*/
192
193QIODevice* QAudioSource::start()
194{
195 if (!d)
196 return nullptr;
197
198 d->setError(QAudio::NoError);
199
200 if (!validateFormatAtStart(d))
201 return nullptr;
202
203 d->elapsedTime.start();
204 return d->start();
205}
206
207/*!
208 Returns the QAudioFormat being used.
209*/
210
211QAudioFormat QAudioSource::format() const
212{
213 return d ? d->format() : QAudioFormat();
214}
215
216/*!
217 Stops the audio input, detaching from the system resource.
218
219 Sets error() to QtAudio::NoError, state() to QtAudio::StoppedState and
220 emit stateChanged() signal.
221*/
222
223void QAudioSource::stop()
224{
225 if (d)
226 d->stop();
227}
228
229/*!
230 Drops all audio data in the buffers, resets buffers to zero.
231*/
232
233void QAudioSource::reset()
234{
235 if (d)
236 d->reset();
237}
238
239/*!
240 Stops processing audio data, preserving buffered audio data.
241
242 Sets error() to QtAudio::NoError, state() to QtAudio::SuspendedState and
243 emit stateChanged() signal.
244*/
245
246void QAudioSource::suspend()
247{
248 if (d)
249 d->suspend();
250}
251
252/*!
253 Resumes processing audio data after a suspend().
254
255 Sets error() to QtAudio::NoError.
256 Sets state() to QtAudio::ActiveState if you previously called start(QIODevice*).
257 Sets state() to QtAudio::IdleState if you previously called start().
258 emits stateChanged() signal.
259*/
260
261void QAudioSource::resume()
262{
263 if (d)
264 d->resume();
265}
266
267/*!
268 Sets the audio buffer size to \a value bytes.
269
270 \note This function can be called anytime before start(), calls to this
271 are ignored after start(). It should not be assumed that the buffer size
272 set is the actual buffer size used, calling bufferSize() anytime after start()
273 will return the actual buffer size being used.
274
275 \sa setBufferFrameCount
276 \since 6.10
277*/
278
279void QAudioSource::setBufferSize(qsizetype value)
280{
281 if (d)
282 d->setBufferSize(value);
283}
284
285/*!
286 Returns the audio buffer size in bytes.
287
288 If called before \l start(), returns platform default value.
289 If called before \c start() but \l setBufferSize() or \l setBufferFrameCount() was called prior, returns
290 value set by \c setBufferSize() or \c setBufferFrameCount(). If called after \c start(), returns the actual
291 buffer size being used. This may not be what was set previously by
292 \c setBufferSize() or \c setBufferFrameCount().
293
294 \sa bufferFrameCount
295 \since 6.10
296*/
297
298qsizetype QAudioSource::bufferSize() const
299{
300 return d ? d->bufferSize() : 0;
301}
302
303/*!
304 Sets the audio buffer size to \a value in frame count.
305
306 \note This function can be called anytime before start(). Calls to this
307 are ignored after start(). It should not be assumed that the buffer size
308 set is the actual buffer size used - call bufferFrameCount() anytime
309 after start() to return the actual buffer size being used.
310
311 \sa setBufferSize
312*/
313
314void QAudioSource::setBufferFrameCount(qsizetype value)
315{
316 if (d)
317 setBufferSize(d->format().bytesForFrames(value));
318}
319
320/*!
321 Returns the audio buffer size in frames.
322
323 If called before \l start(), returns platform default value.
324 If called before \c start() but \l setBufferSize() or \l setBufferFrameCount() was called prior, returns
325 value set by \c setBufferSize() or \c setBufferFrameCount(). If called after \c start(), returns the actual
326 buffer size being used. This may not be what was set previously by
327 \c setBufferSize() or \c setBufferFrameCount().
328
329 \sa bufferSize
330*/
331
332qsizetype QAudioSource::bufferFrameCount() const
333{
334 return d ? d->format().framesForBytes(bufferSize()) : 0;
335}
336
337/*!
338 Returns the amount of audio data available to read in bytes.
339
340 \note returned value is only valid while in QtAudio::ActiveState or QtAudio::IdleState
341 state, otherwise returns zero.
342
343 \sa framesAvailable
344*/
345
346qsizetype QAudioSource::bytesAvailable() const
347{
348 return d ? d->bytesReady() : 0;
349}
350
351/*!
352 Returns the amount of audio data available to read in frames.
353
354 Note: returned value is only valid while in QtAudio::ActiveState or QtAudio::IdleState
355 state, otherwise returns zero.
356
357 \sa bytesAvailable
358 \since 6.10
359*/
360
361qsizetype QAudioSource::framesAvailable() const
362{
363
364 return d ? d->format().framesForBytes(bytesAvailable()) : 0;
365}
366
367/*!
368 Sets the input volume to \a volume.
369
370 The volume is scaled linearly from \c 0.0 (silence) to \c 1.0 (full volume). Values outside this
371 range will be clamped.
372
373 If the device does not support adjusting the input
374 volume then \a volume will be ignored and the input
375 volume will remain at 1.0.
376
377 The default volume is \c 1.0.
378
379 \note Adjustments to the volume will change the volume of this audio stream, not the global
380 volume.
381*/
382void QAudioSource::setVolume(qreal volume)
383{
384 if (!d)
385 return;
386
387 std::optional<float> newVolume = QAudioHelperInternal::sanitizeVolume(volume, this->volume());
388 if (newVolume)
389 d->setVolume(*newVolume);
390}
391
392/*!
393 Returns the input volume.
394
395 If the device does not support adjusting the input volume
396 the returned value will be 1.0.
397*/
398qreal QAudioSource::volume() const
399{
400 return d ? d->volume() : 1.0;
401}
402
403/*!
404 Returns the amount of audio data processed since start()
405 was called in microseconds.
406*/
407
408qint64 QAudioSource::processedUSecs() const
409{
410 return d ? d->processedUSecs() : 0;
411}
412
413/*!
414 Returns the microseconds since start() was called, including time in Idle and
415 Suspend states.
416*/
417
418qint64 QAudioSource::elapsedUSecs() const
419{
420 return state() == QAudio::StoppedState ? 0 : d->elapsedTime.nsecsElapsed()/1000;
421}
422
423/*!
424 Returns the error state.
425*/
426
427QtAudio::Error QAudioSource::error() const
428{
429 return d ? d->error() : QAudio::OpenError;
430}
431
432/*!
433 Returns the state of audio processing.
434*/
435
436QtAudio::State QAudioSource::state() const
437{
438 return d ? d->state() : QAudio::StoppedState;
439}
440
441/*!
442 \fn QAudioSource::stateChanged(QtAudio::State state)
443 This signal is emitted when the device \a state has changed.
444
445 \note The QtAudio namespace was named QAudio up to and including Qt 6.6.
446 String-based connections to this signal have to use \c{QAudio::State} as
447 the parameter type: \c{connect(source, SIGNAL(stateChanged(QAudio::State)), ...);}
448*/
449
450QT_END_NAMESPACE
451
452#include "moc_qaudiosource.cpp"
static bool validateFormatAtStart(QPlatformAudioSource *d)