Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qqnxaudiosource.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 Research In Motion
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 "qqnxaudiosource_p.h"
5
6#include <private/qaudiohelpers_p.h>
7
8#include <QDebug>
9
11
13 : QPlatformAudioSource(parent)
14 , m_audioSource(0)
15 , m_pcmNotifier(0)
16 , m_error(QAudio::NoError)
17 , m_state(QAudio::StoppedState)
18 , m_bytesRead(0)
19 , m_elapsedTimeOffset(0)
20 , m_totalTimeValue(0)
21 , m_volume(qreal(1.0f))
22 , m_bytesAvailable(0)
23 , m_bufferSize(0)
24 , m_periodSize(0)
25 , m_deviceInfo(deviceInfo)
26 , m_pullMode(true)
27{
28}
29
34
36{
37 if (m_state != QAudio::StoppedState)
38 close();
39
40 if (!m_pullMode && m_audioSource)
41 delete m_audioSource;
42
43 m_pullMode = true;
44 m_audioSource = device;
45
46 if (open())
48 else
50}
51
53{
54 if (m_state != QAudio::StoppedState)
55 close();
56
57 if (!m_pullMode && m_audioSource)
58 delete m_audioSource;
59
60 m_pullMode = false;
61 m_audioSource = new InputPrivate(this);
63
64 if (open()) {
66 } else {
67 delete m_audioSource;
68 m_audioSource = 0;
69
71 }
72
73 return m_audioSource;
74}
75
77{
78 if (m_state == QAudio::StoppedState)
79 return;
80
82 close();
83}
84
86{
87 stop();
88 m_bytesAvailable = 0;
89}
90
92{
93 if (m_state == QAudio::StoppedState)
94 return;
95
96 snd_pcm_capture_pause(m_pcmHandle.get());
97
98 if (m_pcmNotifier)
99 m_pcmNotifier->setEnabled(false);
100
102}
103
105{
106 if (m_state == QAudio::StoppedState)
107 return;
108
109 snd_pcm_capture_resume(m_pcmHandle.get());
110
111 if (m_pcmNotifier)
112 m_pcmNotifier->setEnabled(true);
113
114 if (m_pullMode)
116 else
118}
119
121{
122 return qMax(m_bytesAvailable, 0);
123}
124
126{
127 m_bufferSize = bufferSize;
128}
129
131{
132 return m_bufferSize;
133}
134
136{
137 return qint64(1000000) * m_format.framesForBytes(m_bytesRead) / m_format.sampleRate();
138}
139
141{
142 return m_error;
143}
144
146{
147 return m_state;
148}
149
151{
152 if (m_state == QAudio::StoppedState)
153 m_format = format;
154}
155
157{
158 return m_format;
159}
160
162{
163 m_volume = qBound(qreal(0.0), volume, qreal(1.0));
164}
165
167{
168 return m_volume;
169}
170
171void QQnxAudioSource::userFeed()
172{
173 if (m_state == QAudio::StoppedState || m_state == QAudio::SuspendedState)
174 return;
175
176 deviceReady();
177}
178
179bool QQnxAudioSource::deviceReady()
180{
181 if (m_pullMode) {
182 // reads some audio data and writes it to QIODevice
183 read(0, 0);
184 } else {
185 m_bytesAvailable = m_periodSize;
186
187 // emits readyRead() so user will call read() on QIODevice to get some audio data
188 if (m_audioSource != 0) {
189 InputPrivate *input = qobject_cast<InputPrivate*>(m_audioSource);
190 input->trigger();
191 }
192 }
193
194 if (m_state != QAudio::ActiveState)
195 return true;
196
197 return true;
198}
199
200bool QQnxAudioSource::open()
201{
202 if (!m_format.isValid() || m_format.sampleRate() <= 0) {
203 if (!m_format.isValid())
204 qWarning("QQnxAudioSource: open error, invalid format.");
205 else
206 qWarning("QQnxAudioSource: open error, invalid sample rate (%d).", m_format.sampleRate());
207
208 return false;
209 }
210
211 m_pcmHandle = QnxAudioUtils::openPcmDevice(m_deviceInfo.id(), QAudioDevice::Input);
212
213 if (!m_pcmHandle)
214 return false;
215
216 int errorCode = 0;
217
218 // Necessary so that bytesFree() which uses the "free" member of the status struct works
219 snd_pcm_plugin_set_disable(m_pcmHandle.get(), PLUGIN_MMAP);
220
221 const std::optional<snd_pcm_channel_info_t> info = QnxAudioUtils::pcmChannelInfo(
222 m_pcmHandle.get(), QAudioDevice::Input);
223
224 if (!info) {
225 close();
226 return false;
227 }
228
229 snd_pcm_channel_params_t params = QnxAudioUtils::formatToChannelParams(m_format,
230 QAudioDevice::Input, info->max_fragment_size);
231
232 if ((errorCode = snd_pcm_plugin_params(m_pcmHandle.get(), &params)) < 0) {
233 qWarning("QQnxAudioSource: open error, couldn't set channel params (0x%x)", -errorCode);
234 close();
235 return false;
236 }
237
238 if ((errorCode = snd_pcm_plugin_prepare(m_pcmHandle.get(), SND_PCM_CHANNEL_CAPTURE)) < 0) {
239 qWarning("QQnxAudioSource: open error, couldn't prepare channel (0x%x)", -errorCode);
240 close();
241 return false;
242 }
243
244 const std::optional<snd_pcm_channel_setup_t> setup = QnxAudioUtils::pcmChannelSetup(
245 m_pcmHandle.get(), QAudioDevice::Input);
246
247 m_periodSize = qMin(2048, setup->buf.block.frag_size);
248
249 m_elapsedTimeOffset = 0;
250 m_totalTimeValue = 0;
251 m_bytesRead = 0;
252
253 m_pcmNotifier = new QSocketNotifier(snd_pcm_file_descriptor(m_pcmHandle.get(), SND_PCM_CHANNEL_CAPTURE),
255 connect(m_pcmNotifier, SIGNAL(activated(QSocketDescriptor)), this, SLOT(userFeed()));
256
257 return true;
258}
259
260void QQnxAudioSource::close()
261{
262 if (m_pcmHandle) {
263#if SND_PCM_VERSION < SND_PROTOCOL_VERSION('P',3,0,2)
264 snd_pcm_plugin_flush(m_pcmHandle.get(), SND_PCM_CHANNEL_CAPTURE);
265#else
266 snd_pcm_plugin_drop(m_pcmHandle.get(), SND_PCM_CHANNEL_CAPTURE);
267#endif
268 m_pcmHandle = nullptr;
269 }
270
271 if (m_pcmNotifier) {
272 delete m_pcmNotifier;
273 m_pcmNotifier = 0;
274 }
275
276 if (!m_pullMode && m_audioSource) {
277 delete m_audioSource;
278 m_audioSource = 0;
279 }
280}
281
282qint64 QQnxAudioSource::read(char *data, qint64 len)
283{
284 if (!m_pullMode && m_bytesAvailable == 0)
285 return 0;
286
287 int errorCode = 0;
288 QByteArray tempBuffer(m_periodSize, 0);
289
290 const int actualRead = snd_pcm_plugin_read(m_pcmHandle.get(), tempBuffer.data(), m_periodSize);
291 if (actualRead < 1) {
292 snd_pcm_channel_status_t status;
293 memset(&status, 0, sizeof(status));
294 status.channel = SND_PCM_CHANNEL_CAPTURE;
295 if ((errorCode = snd_pcm_plugin_status(m_pcmHandle.get(), &status)) < 0) {
296 qWarning("QQnxAudioSource: read error, couldn't get plugin status (0x%x)", -errorCode);
297 close();
299 return -1;
300 }
301
302 if (status.status == SND_PCM_STATUS_READY
303 || status.status == SND_PCM_STATUS_OVERRUN) {
304 if ((errorCode = snd_pcm_plugin_prepare(m_pcmHandle.get(), SND_PCM_CHANNEL_CAPTURE)) < 0) {
305 qWarning("QQnxAudioSource: read error, couldn't prepare plugin (0x%x)", -errorCode);
306 close();
308 return -1;
309 }
310 }
311 } else {
313 }
314
315 if (m_volume < 1.0f)
316 QAudioHelperInternal::qMultiplySamples(m_volume, m_format, tempBuffer.data(), tempBuffer.data(), actualRead);
317
318 m_bytesRead += actualRead;
319
320 if (m_pullMode) {
321 m_audioSource->write(tempBuffer.data(), actualRead);
322 } else {
323 memcpy(data, tempBuffer.data(), qMin(static_cast<qint64>(actualRead), len));
324 }
325
326 m_bytesAvailable = 0;
327
328 return actualRead;
329}
330
331void QQnxAudioSource::changeState(QAudio::State state, QAudio::Error error)
332{
333 if (m_state != state) {
334 m_state = state;
336 }
337
338 if (m_error != error) {
339 m_error = error;
341 }
342}
343
345 : m_audioDevice(audio)
346{
347}
348
350{
351 return m_audioDevice->read(data, len);
352}
353
355{
356 Q_UNUSED(data);
357 Q_UNUSED(len);
358 return 0;
359}
360
362{
363 return m_audioDevice->m_bytesAvailable + QIODevice::bytesAvailable();
364}
365
367{
368 return true;
369}
370
372{
373 emit readyRead();
374}
375
IOBluetoothDevice * device
bool isSequential() const override
Returns true if this device is sequential; otherwise returns false.
qint64 writeData(const char *data, qint64 len) override
Writes up to maxSize bytes from data to the device.
InputPrivate(QQnxAudioSource *audio)
qint64 readData(char *data, qint64 len) override
Reads up to maxSize bytes from the device into data, and returns the number of bytes read or -1 if an...
qint64 bytesAvailable() const override
Returns the number of bytes that are available for reading.
The QAudioDevice class provides an information about audio devices and their functionality.
QByteArray id
\qmlproperty string QtMultimedia::audioDevice::id
The QAudioFormat class stores audio stream parameter information.
constexpr int sampleRate() const noexcept
Returns the current sample rate in Hertz.
constexpr bool isValid() const noexcept
Returns true if all of the parameters are valid.
Q_MULTIMEDIA_EXPORT qint32 framesForBytes(qint32 byteCount) const
Returns the number of frames represented by byteCount in this format.
void stateChanged(QAudio::State state)
void errorChanged(QAudio::Error error)
\inmodule QtCore
Definition qbytearray.h:57
\inmodule QtCore \reentrant
Definition qiodevice.h:34
virtual bool open(QIODeviceBase::OpenMode mode)
Opens the device and sets its OpenMode to mode.
void readyRead()
This signal is emitted once every time new data is available for reading from the device's current re...
qint64 write(const char *data, qint64 len)
Writes at most maxSize bytes of data from data to the device.
virtual qint64 bytesAvailable() const
Returns the number of bytes that are available for reading.
\inmodule QtCore
Definition qobject.h:103
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
void suspend() override
qsizetype bytesReady() const override
QAudio::State state() const override
void setFormat(const QAudioFormat &) override
QAudio::Error error() const override
void setVolume(qreal) override
QIODevice * start() override
QQnxAudioSource(const QAudioDevice &deviceInfo, QObject *parent)
void resume() override
friend class InputPrivate
void setBufferSize(qsizetype) override
QAudioFormat format() const override
void stop() override
qsizetype bufferSize() const override
qreal volume() const override
void reset() override
qint64 processedUSecs() const override
\inmodule QtCore
\inmodule QtCore
void setEnabled(bool)
If enable is true, the notifier is enabled; otherwise the notifier is disabled.
else opt state
[0]
void qMultiplySamples(qreal factor, const QAudioFormat &format, const void *src, void *dest, int len)
State
Definition qaudio.h:29
@ StoppedState
Definition qaudio.h:29
@ SuspendedState
Definition qaudio.h:29
@ IdleState
Definition qaudio.h:29
@ ActiveState
Definition qaudio.h:29
Error
Definition qaudio.h:28
@ FatalError
Definition qaudio.h:28
@ OpenError
Definition qaudio.h:28
@ NoError
Definition qaudio.h:28
Combined button and popup list for selecting options.
std::optional< snd_pcm_channel_info_t > pcmChannelInfo(snd_pcm_t *handle, QAudioDevice::Mode mode)
std::optional< snd_pcm_channel_setup_t > pcmChannelSetup(snd_pcm_t *handle, QAudioDevice::Mode mode)
HandleUniquePtr openPcmDevice(const QByteArray &id, QAudioDevice::Mode mode)
snd_pcm_channel_params_t formatToChannelParams(const QAudioFormat &format, QAudioDevice::Mode mode, int fragmentSize)
DBusConnection const char DBusError * error
#define qWarning
Definition qlogging.h:166
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qBound(const T &min, const T &val, const T &max)
Definition qminmax.h:44
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
#define SLOT(a)
Definition qobjectdefs.h:52
#define SIGNAL(a)
Definition qobjectdefs.h:53
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLint GLsizei GLsizei GLenum format
void ** params
GLenum GLsizei len
GLenum GLenum GLenum input
@ NoError
Definition main.cpp:34
#define emit
#define Q_UNUSED(x)
ptrdiff_t qsizetype
Definition qtypes.h:165
long long qint64
Definition qtypes.h:60
double qreal
Definition qtypes.h:187
QHostInfo info
[0]