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
qffmpegaudioinput.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 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
4
5#include <QtCore/qatomic.h>
6#include <QtCore/qdebug.h>
7#include <QtCore/qiodevice.h>
8#include <QtCore/qmetaobject.h>
9#include <QtMultimedia/qaudiobuffer.h>
10#include <QtMultimedia/qaudiosource.h>
11
13
14namespace QFFmpeg {
15
17{
19public:
27
29 {
30 // QAudioSource may invoke QIODevice::writeData in the destructor.
31 // Let's reset the audio source to get around the case.
32 if (m_audioSource)
34 }
35
37 {
40 if (m_device == device)
41 return;
43 QMetaObject::invokeMethod(this, [this] {
46 });
47 }
54 void setRunning(bool r) {
57 if (m_running == r)
58 return;
59 m_running = r;
61 }
62
75
76 int bufferSize() const { return m_bufferSize.loadAcquire(); }
77
78protected:
80 {
81 return 0;
82 }
84 {
86
87 int l = len;
88 while (len > 0) {
89 const auto bufferSize = m_bufferSize.loadAcquire();
90
91 while (m_pcm.size() > bufferSize) {
92 // bufferSize has been reduced. Send data until m_pcm
93 // can hold more data.
96 }
97
98 // Size of m_pcm is always <= bufferSize
101 data += toAppend;
102 len -= toAppend;
103 if (m_pcm.size() == bufferSize) {
105 m_pcm.clear();
106 }
107 }
108
109 return l;
110 }
111
112private Q_SLOTS:
113 void updateVolume()
114 {
115 if (m_audioSource)
117 }
118 void updateRunning()
119 {
121 if (m_running) {
122 if (!m_audioSource)
124 else
125 m_audioSource->start(this);
126 } else {
128 }
129 }
130
131private:
133 {
136 if (std::exchange(m_audioSource, nullptr))
137 m_pcm.clear();
138
140 updateVolume();
141 if (m_running)
142 m_audioSource->start(this);
143 }
144
145 void sendBuffer(const QByteArray &pcmData)
146 {
152 }
153
155 QAudioDevice m_device;
156 float m_volume = 1.;
157 bool m_muted = false;
158 bool m_running = false;
159
160 QFFmpegAudioInput *m_input = nullptr;
161 std::unique_ptr<QAudioSource> m_audioSource;
162 QAudioFormat m_format;
163 QAtomicInt m_bufferSize = DefaultAudioInputBufferSize;
164 qint64 m_processed = 0;
165 QByteArray m_pcm;
166};
167
168} // namespace QFFmpeg
169
170QFFmpegAudioInput::QFFmpegAudioInput(QAudioInput *qq)
171 : QPlatformAudioInput(qq)
172{
173 qRegisterMetaType<QAudioBuffer>();
174
175 m_inputThread = std::make_unique<QThread>();
176 m_inputThread->setObjectName(QStringLiteral("QFFmpegAudioInputThread"));
177 m_audioIO = new QFFmpeg::AudioSourceIO(this);
178 m_audioIO->moveToThread(m_inputThread.get());
179 m_inputThread->start();
180}
181
183{
184 // Ensure that COM is uninitialized by nested QWindowsResampler
185 // on the same thread that initialized it.
186 m_audioIO->deleteLater();
187 m_inputThread->exit();
188 m_inputThread->wait();
189}
190
191void QFFmpegAudioInput::setAudioDevice(const QAudioDevice &device)
192{
193 m_audioIO->setDevice(device);
194}
195
197{
198 m_audioIO->setMuted(muted);
199}
200
201void QFFmpegAudioInput::setVolume(float volume)
202{
203 m_audioIO->setVolume(volume);
204}
205
206void QFFmpegAudioInput::setBufferSize(int bufferSize)
207{
208 m_audioIO->setBufferSize(bufferSize);
209}
210
212{
213 return m_audioIO->bufferSize();
214}
215
216void QFFmpegAudioInput::connectNotify(const QMetaMethod &signal)
217{
218 // threading considerations:
219 // AudioSourceIO::setRunning doesn't reenter
220 // the internal QObject's mutex of the audio input instance
221 if (signal == QMetaMethod::fromSignal(&QFFmpegAudioInput::newAudioBuffer))
222 m_audioIO->setRunning(true);
223}
224
225void QFFmpegAudioInput::disconnectNotify(const QMetaMethod &signal)
226{
227 if (!signal.isValid()
228 || signal == QMetaMethod::fromSignal(&QFFmpegAudioInput::newAudioBuffer)) {
229 auto stopIOifNeeded = [this]() {
230 // if the signal disconnectNotify is not
231 if (!isSignalConnected(QMetaMethod::fromSignal(&QFFmpegAudioInput::newAudioBuffer)))
232 m_audioIO->setRunning(false);
233 };
234
235 // threading considerations:
236 // QMetaObject::invokeMethod doesn't reenter
237 // the internal QObject's mutex of the audio input instance.
238 // Instead, QMetaObject::invokeMethod locks ThreadData::postEventMutex
239
240 // postpone update to avoid redundant QAudioSource restarts upon reconnection
241 QMetaObject::invokeMethod(this, stopIOifNeeded, Qt::QueuedConnection);
242 }
243}
244
245QT_END_NAMESPACE
246
247#include "moc_qffmpegaudioinput_p.cpp"
248
249#include "qffmpegaudioinput.moc"
void setAudioDevice(const QAudioDevice &) override
void setVolume(float) override
void setMuted(bool) override
void setBufferSize(int bufferSize)
void connectNotify(const QMetaMethod &signal) override
void disconnectNotify(const QMetaMethod &signal) override
std::conditional_t< QT_FFMPEG_AVIO_WRITE_CONST, const uint8_t *, uint8_t * > AvioWriteBufferType