7#include <private/qaudiohelpers_p.h>
13#include <SLES/OpenSLES_AndroidConfiguration.h>
14#include <QtCore/qcoreapplication.h>
15#include <QtCore/qpermissions.h>
23#define DEFAULT_PERIOD_TIME_MS 50
24#define MINIMUM_PERIOD_TIME_MS 5
27static bool hasRecordingPermission()
33 qCWarning(qLcAndroidAudioSource,
"Missing microphone permission!");
38static void bufferQueueCallback(SLAndroidSimpleBufferQueueItf,
void *
context)
40static void bufferQueueCallback(SLBufferQueueItf,
void *
context)
59 , m_deviceState(
QAudio::StoppedState)
68 m_recorderPreset = SL_ANDROID_RECORDING_PRESET_CAMCORDER;
69 else if (
qstrcmp(
device, QT_ANDROID_PRESET_VOICE_RECOGNITION) == 0)
70 m_recorderPreset = SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION;
71 else if (
qstrcmp(
device, QT_ANDROID_PRESET_VOICE_COMMUNICATION) == 0)
72 m_recorderPreset = SL_ANDROID_RECORDING_PRESET_VOICE_COMMUNICATION;
74 m_recorderPreset = SL_ANDROID_RECORDING_PRESET_GENERIC;
81 (*m_recorderObject)->Destroy(m_recorderObject);
111 if (!m_pullMode && m_bufferIODevice) {
112 m_bufferIODevice->
close();
113 delete m_bufferIODevice;
114 m_bufferIODevice = 0;
120 if (startRecording()) {
137 if (!m_pullMode && m_bufferIODevice) {
138 m_bufferIODevice->
close();
139 delete m_bufferIODevice;
143 m_pushBuffer.
clear();
144 m_bufferIODevice =
new QBuffer(&m_pushBuffer,
this);
147 if (startRecording()) {
152 m_bufferIODevice->
close();
153 delete m_bufferIODevice;
154 m_bufferIODevice = 0;
158 return m_bufferIODevice;
161bool QAndroidAudioSource::startRecording()
163 if (!hasRecordingPermission())
166 m_processedBytes = 0;
167 m_lastNotifyTime = 0;
172 SLDataLocator_IODevice loc_dev = { SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT,
173 SL_DEFAULTDEVICEID_AUDIOINPUT, NULL };
174 SLDataSource audioSrc = { &loc_dev, NULL };
178 SLDataLocator_AndroidSimpleBufferQueue loc_bq = { SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,
181 SLDataLocator_BufferQueue loc_bq = { SL_DATALOCATOR_BUFFERQUEUE,
NUM_BUFFERS };
185 SLDataSink audioSnk = { &loc_bq, &format_pcm };
190 const SLInterfaceID
id[2] = { SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_ANDROIDCONFIGURATION };
191 const SLboolean req[2] = { SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE };
193 const SLInterfaceID
id[1] = { SL_IID_BUFFERQUEUE };
194 const SLboolean req[1] = { SL_BOOLEAN_TRUE };
198 &audioSrc, &audioSnk,
199 sizeof(req) /
sizeof(SLboolean),
id, req);
200 if (
result != SL_RESULT_SUCCESS) {
207 SLAndroidConfigurationItf configItf;
208 result = (*m_recorderObject)->GetInterface(m_recorderObject, SL_IID_ANDROIDCONFIGURATION,
210 if (
result != SL_RESULT_SUCCESS) {
215 result = (*configItf)->SetConfiguration(configItf, SL_ANDROID_KEY_RECORDING_PRESET,
216 &m_recorderPreset,
sizeof(SLuint32));
218 SLuint32 presetValue = SL_ANDROID_RECORDING_PRESET_NONE;
219 SLuint32 presetSize = 2*
sizeof(SLuint32);
220 result = (*configItf)->GetConfiguration(configItf, SL_ANDROID_KEY_RECORDING_PRESET,
221 &presetSize, (
void*)&presetValue);
223 if (
result != SL_RESULT_SUCCESS || presetValue == SL_ANDROID_RECORDING_PRESET_NONE) {
230 result = (*m_recorderObject)->Realize(m_recorderObject, SL_BOOLEAN_FALSE);
231 if (
result != SL_RESULT_SUCCESS) {
237 result = (*m_recorderObject)->GetInterface(m_recorderObject, SL_IID_RECORD, &m_recorder);
238 if (
result != SL_RESULT_SUCCESS) {
245 SLInterfaceID bufferqueueItfID = SL_IID_ANDROIDSIMPLEBUFFERQUEUE;
247 SLInterfaceID bufferqueueItfID = SL_IID_BUFFERQUEUE;
249 result = (*m_recorderObject)->GetInterface(m_recorderObject, bufferqueueItfID, &m_bufferQueue);
250 if (
result != SL_RESULT_SUCCESS) {
256 result = (*m_bufferQueue)->RegisterCallback(m_bufferQueue, bufferQueueCallback,
this);
257 if (
result != SL_RESULT_SUCCESS) {
262 if (m_bufferSize <= 0) {
266 if (m_bufferSize < minimumBufSize)
267 m_bufferSize = minimumBufSize;
272 m_buffers[
i].
resize(m_bufferSize);
274 result = (*m_bufferQueue)->Enqueue(m_bufferQueue, m_buffers[
i].
data(), m_bufferSize);
275 if (
result != SL_RESULT_SUCCESS) {
282 result = (*m_recorder)->SetRecordState(m_recorder, SL_RECORDSTATE_RECORDING);
283 if (
result != SL_RESULT_SUCCESS) {
306void QAndroidAudioSource::stopRecording()
310 (*m_recorder)->SetRecordState(m_recorder, SL_RECORDSTATE_STOPPED);
311 (*m_bufferQueue)->Clear(m_bufferQueue);
313 (*m_recorderObject)->Destroy(m_recorderObject);
314 m_recorderObject = 0;
320 if (!m_pullMode && m_bufferIODevice) {
321 m_bufferIODevice->
close();
322 delete m_bufferIODevice;
323 m_bufferIODevice = 0;
324 m_pushBuffer.
clear();
334 (*m_recorder)->SetRecordState(m_recorder, SL_RECORDSTATE_PAUSED);
341 (*m_recorder)->SetRecordState(m_recorder, SL_RECORDSTATE_RECORDING);
359 QByteArray *processedBuffer = &m_buffers[m_currentBuffer];
360 writeDataToDevice(processedBuffer->constData(), processedBuffer->size());
367 SLresult
result = (*m_bufferQueue)->Enqueue(m_bufferQueue,
368 processedBuffer->data(),
369 processedBuffer->size());
371 m_currentBuffer = (m_currentBuffer + 1) %
NUM_BUFFERS;
375 SLAndroidSimpleBufferQueueState
state;
377 SLBufferQueueState
state;
379 result = (*m_bufferQueue)->GetState(m_bufferQueue, &
state);
380 if (
result != SL_RESULT_SUCCESS ||
state.count == 0) {
387void QAndroidAudioSource::writeDataToDevice(
const char *
data,
int size)
389 m_processedBytes +=
size;
394 if (m_volume < 1.0f) {
403 if (m_audioSource->
write(outData) < 0) {
410 if (m_bufferIODevice != 0) {
411 m_pushBuffer.
append(outData);
417void QAndroidAudioSource::flushBuffers()
419 SLmillisecond recorderPos;
420 (*m_recorder)->GetPosition(m_recorder, &recorderPos);
423 qint64 delta = recorderPos * 1000 - devicePos;
426 const int writeSize =
qMin(m_buffers[m_currentBuffer].
size(),
428 writeDataToDevice(m_buffers[m_currentBuffer].constData(), writeSize);
435 return m_bufferIODevice ? m_bufferIODevice->
bytesAvailable() : m_bufferSize;
442 m_bufferSize =
value;
IOBluetoothDevice * device
void setBufferSize(qsizetype value)
void setFormat(const QAudioFormat &format)
QAudioFormat format() const
QAudio::Error error() const
qsizetype bufferSize() const
void setVolume(qreal volume)
qsizetype bytesReady() const
qint64 processedUSecs() const
QAndroidAudioSource(const QByteArray &device, QObject *parent)
QAudio::State state() const
void stateChanged(QAudio::State state)
void errorChanged(QAudio::Error error)
\inmodule QtCore \reentrant
bool open(OpenMode openMode) override
\reimp
void close() override
\reimp
void clear()
Clears the contents of the byte array and makes it null.
void resize(qsizetype size)
Sets the size of the byte array to size bytes.
QByteArray & append(char c)
This is an overloaded member function, provided for convenience. It differs from the above function o...
\inmodule QtCore \reentrant
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.
Access the microphone for monitoring or recording sound.
SLEngineItf slEngine() const
static SLAndroidDataFormat_PCM_EX audioFormatToSLFormatPCM(const QAudioFormat &format)
void qMultiplySamples(qreal factor, const QAudioFormat &format, const void *src, void *dest, int len)
Combined button and popup list for selecting options.
#define MINIMUM_PERIOD_TIME_MS
#define DEFAULT_PERIOD_TIME_MS
Q_CORE_EXPORT int qstrcmp(const char *str1, const char *str2)
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
#define Q_LOGGING_CATEGORY(name,...)
#define qCWarning(category,...)
constexpr const T & qMin(const T &a, const T &b)
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLint GLsizei GLsizei GLenum format