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 "qaudiosource.h"
9
10#include <private/qplatformmediadevices_p.h>
11#include <private/qplatformmediaintegration_p.h>
12
13QT_BEGIN_NAMESPACE
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 QAudio::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 QAudio::Error
70 enum. The QAudioSource will enter the \l{QAudio::}{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.
83*/
84
85QAudioSource::QAudioSource(const QAudioFormat &format, QObject *parent)
86 : QAudioSource({}, format, parent)
87{
88}
89
90/*!
91 Construct a new audio input and attach it to \a parent.
92 The device referenced by \a audioDevice is used with the input
93 \a format parameters.
94*/
95
96QAudioSource::QAudioSource(const QAudioDevice &audioDevice, const QAudioFormat &format, QObject *parent):
97 QObject(parent)
98{
99 d = QPlatformMediaDevices::instance()->audioInputDevice(format, deviceInfo: audioDevice, parent);
100 if (d) {
101 connect(sender: d, signal: &QPlatformAudioSource::stateChanged, context: this, slot: [this](QAudio::State state) {
102 // if the signal has been emitted from another thread,
103 // the state may be already changed by main one
104 if (state == d->state())
105 emit stateChanged(state);
106 });
107 }
108 else
109 qWarning() << ("No audio device detected");
110
111}
112
113/*!
114 \fn bool QAudioSource::isNull() const
115
116 Returns \c true if the audio source is \c null, otherwise returns \c false.
117*/
118
119/*!
120 Destroy this audio input.
121*/
122
123QAudioSource::~QAudioSource()
124{
125 delete d;
126}
127
128/*!
129 Starts transferring audio data from the system's audio input to the \a device.
130 The \a device must have been opened in the \l{QIODevice::WriteOnly}{WriteOnly},
131 \l{QIODevice::Append}{Append} or \l{QIODevice::ReadWrite}{ReadWrite} modes.
132
133 If the QAudioSource is able to successfully get audio data, state() returns
134 either QAudio::ActiveState or QAudio::IdleState, error() returns QAudio::NoError
135 and the stateChanged() signal is emitted.
136
137 If a problem occurs during this process, error() returns QAudio::OpenError,
138 state() returns QAudio::StoppedState and the stateChanged() signal is emitted.
139
140 \sa QIODevice
141*/
142
143void QAudioSource::start(QIODevice* device)
144{
145 if (!d)
146 return;
147 d->elapsedTime.start();
148 d->start(device);
149}
150
151/*!
152 Returns a pointer to the internal QIODevice being used to transfer data from
153 the system's audio input. The device will already be open and
154 \l{QIODevice::read()}{read()} can read data directly from it.
155
156 \note The pointer will become invalid after the stream is stopped or
157 if you start another stream.
158
159 If the QAudioSource is able to access the system's audio device, state() returns
160 QAudio::IdleState, error() returns QAudio::NoError
161 and the stateChanged() signal is emitted.
162
163 If a problem occurs during this process, error() returns QAudio::OpenError,
164 state() returns QAudio::StoppedState and the stateChanged() signal is emitted.
165
166 \sa QIODevice
167*/
168
169QIODevice* QAudioSource::start()
170{
171 if (!d)
172 return nullptr;
173 d->elapsedTime.start();
174 return d->start();
175}
176
177/*!
178 Returns the QAudioFormat being used.
179*/
180
181QAudioFormat QAudioSource::format() const
182{
183 return d ? d->format() : QAudioFormat();
184}
185
186/*!
187 Stops the audio input, detaching from the system resource.
188
189 Sets error() to QAudio::NoError, state() to QAudio::StoppedState and
190 emit stateChanged() signal.
191*/
192
193void QAudioSource::stop()
194{
195 if (d)
196 d->stop();
197}
198
199/*!
200 Drops all audio data in the buffers, resets buffers to zero.
201*/
202
203void QAudioSource::reset()
204{
205 if (d)
206 d->reset();
207}
208
209/*!
210 Stops processing audio data, preserving buffered audio data.
211
212 Sets error() to QAudio::NoError, state() to QAudio::SuspendedState and
213 emit stateChanged() signal.
214*/
215
216void QAudioSource::suspend()
217{
218 if (d)
219 d->suspend();
220}
221
222/*!
223 Resumes processing audio data after a suspend().
224
225 Sets error() to QAudio::NoError.
226 Sets state() to QAudio::ActiveState if you previously called start(QIODevice*).
227 Sets state() to QAudio::IdleState if you previously called start().
228 emits stateChanged() signal.
229*/
230
231void QAudioSource::resume()
232{
233 if (d)
234 d->resume();
235}
236
237/*!
238 Sets the audio buffer size to \a value bytes.
239
240 Note: This function can be called anytime before start(), calls to this
241 are ignored after start(). It should not be assumed that the buffer size
242 set is the actual buffer size used, calling bufferSize() anytime after start()
243 will return the actual buffer size being used.
244
245*/
246
247void QAudioSource::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*/
262
263qsizetype QAudioSource::bufferSize() const
264{
265 return d ? d->bufferSize() : 0;
266}
267
268/*!
269 Returns the amount of audio data available to read in bytes.
270
271 Note: returned value is only valid while in QAudio::ActiveState or QAudio::IdleState
272 state, otherwise returns zero.
273*/
274
275qsizetype QAudioSource::bytesAvailable() const
276{
277 /*
278 -If not ActiveState|IdleState, return 0
279 -return amount of audio data available to read
280 */
281 return d ? d->bytesReady() : 0;
282}
283
284/*!
285 Sets the input volume to \a volume.
286
287 The volume is scaled linearly from \c 0.0 (silence) to \c 1.0 (full volume). Values outside this
288 range will be clamped.
289
290 If the device does not support adjusting the input
291 volume then \a volume will be ignored and the input
292 volume will remain at 1.0.
293
294 The default volume is \c 1.0.
295
296 Note: Adjustments to the volume will change the volume of this audio stream, not the global volume.
297*/
298void QAudioSource::setVolume(qreal volume)
299{
300 if (!d)
301 return;
302 qreal v = qBound(min: qreal(0.0), val: volume, max: qreal(1.0));
303 d->setVolume(v);
304}
305
306/*!
307 Returns the input volume.
308
309 If the device does not support adjusting the input volume
310 the returned value will be 1.0.
311*/
312qreal QAudioSource::volume() const
313{
314 return d ? d->volume() : 1.0;
315}
316
317/*!
318 Returns the amount of audio data processed since start()
319 was called in microseconds.
320*/
321
322qint64 QAudioSource::processedUSecs() const
323{
324 return d ? d->processedUSecs() : 0;
325}
326
327/*!
328 Returns the microseconds since start() was called, including time in Idle and
329 Suspend states.
330*/
331
332#include <qdebug.h>
333
334qint64 QAudioSource::elapsedUSecs() const
335{
336 return state() == QAudio::StoppedState ? 0 : d->elapsedTime.nsecsElapsed()/1000;
337}
338
339/*!
340 Returns the error state.
341*/
342
343QAudio::Error QAudioSource::error() const
344{
345 return d ? d->error() : QAudio::OpenError;
346}
347
348/*!
349 Returns the state of audio processing.
350*/
351
352QAudio::State QAudioSource::state() const
353{
354 return d ? d->state() : QAudio::StoppedState;
355}
356
357/*!
358 \fn QAudioSource::stateChanged(QAudio::State state)
359 This signal is emitted when the device \a state has changed.
360*/
361
362QT_END_NAMESPACE
363
364#include "moc_qaudiosource.cpp"
365
366

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