diff options
Diffstat (limited to 'src/plugins/opensles/qopenslesaudioinput.cpp')
-rw-r--r-- | src/plugins/opensles/qopenslesaudioinput.cpp | 548 |
1 files changed, 0 insertions, 548 deletions
diff --git a/src/plugins/opensles/qopenslesaudioinput.cpp b/src/plugins/opensles/qopenslesaudioinput.cpp deleted file mode 100644 index 9105fca4c..000000000 --- a/src/plugins/opensles/qopenslesaudioinput.cpp +++ /dev/null @@ -1,548 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qopenslesaudioinput.h" - -#include "qopenslesengine.h" -#include <qbuffer.h> -#include <private/qaudiohelpers_p.h> -#include <qdebug.h> - -#ifdef ANDROID -#include <SLES/OpenSLES_AndroidConfiguration.h> -#include <QtCore/private/qjnihelpers_p.h> -#include <QtCore/private/qjni_p.h> -#endif - -QT_BEGIN_NAMESPACE - -#define NUM_BUFFERS 2 -#define DEFAULT_PERIOD_TIME_MS 50 -#define MINIMUM_PERIOD_TIME_MS 5 - -#ifdef ANDROID -static bool hasRecordingPermission() -{ - using namespace QtAndroidPrivate; - if (androidSdkVersion() < 23) - return true; - - const QString key(QLatin1String("android.permission.RECORD_AUDIO")); - PermissionsResult res = checkPermission(key); - if (res == PermissionsResult::Granted) // Permission already granted? - return true; - - QJNIEnvironmentPrivate env; - const auto &results = requestPermissionsSync(env, QStringList() << key); - if (!results.contains(key)) { - qWarning("No permission found for key: %s", qPrintable(key)); - return false; - } - - if (results[key] == PermissionsResult::Denied) { - qDebug("%s - Permission denied by user!", qPrintable(key)); - return false; - } - - return true; -} - -static void bufferQueueCallback(SLAndroidSimpleBufferQueueItf, void *context) -#else -static void bufferQueueCallback(SLBufferQueueItf, void *context) -#endif -{ - // Process buffer in main thread - QMetaObject::invokeMethod(reinterpret_cast<QOpenSLESAudioInput*>(context), "processBuffer"); -} - -QOpenSLESAudioInput::QOpenSLESAudioInput(const QByteArray &device) - : m_device(device) - , m_engine(QOpenSLESEngine::instance()) - , m_recorderObject(0) - , m_recorder(0) - , m_bufferQueue(0) - , m_pullMode(true) - , m_processedBytes(0) - , m_audioSource(0) - , m_bufferIODevice(0) - , m_errorState(QAudio::NoError) - , m_deviceState(QAudio::StoppedState) - , m_lastNotifyTime(0) - , m_volume(1.0) - , m_bufferSize(0) - , m_periodSize(0) - , m_intervalTime(1000) - , m_buffers(new QByteArray[NUM_BUFFERS]) - , m_currentBuffer(0) -{ -#ifdef ANDROID - if (qstrcmp(device, QT_ANDROID_PRESET_CAMCORDER) == 0) - m_recorderPreset = SL_ANDROID_RECORDING_PRESET_CAMCORDER; - else if (qstrcmp(device, QT_ANDROID_PRESET_VOICE_RECOGNITION) == 0) - m_recorderPreset = SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION; - else if (qstrcmp(device, QT_ANDROID_PRESET_VOICE_COMMUNICATION) == 0) - m_recorderPreset = SL_ANDROID_RECORDING_PRESET_VOICE_COMMUNICATION; - else - m_recorderPreset = SL_ANDROID_RECORDING_PRESET_GENERIC; -#endif -} - -QOpenSLESAudioInput::~QOpenSLESAudioInput() -{ - if (m_recorderObject) - (*m_recorderObject)->Destroy(m_recorderObject); - delete[] m_buffers; -} - -QAudio::Error QOpenSLESAudioInput::error() const -{ - return m_errorState; -} - -QAudio::State QOpenSLESAudioInput::state() const -{ - return m_deviceState; -} - -void QOpenSLESAudioInput::setFormat(const QAudioFormat &format) -{ - if (m_deviceState == QAudio::StoppedState) - m_format = format; -} - -QAudioFormat QOpenSLESAudioInput::format() const -{ - return m_format; -} - -void QOpenSLESAudioInput::start(QIODevice *device) -{ - if (m_deviceState != QAudio::StoppedState) - stopRecording(); - - if (!m_pullMode && m_bufferIODevice) { - m_bufferIODevice->close(); - delete m_bufferIODevice; - m_bufferIODevice = 0; - } - - m_pullMode = true; - m_audioSource = device; - - if (startRecording()) { - m_deviceState = QAudio::ActiveState; - } else { - m_deviceState = QAudio::StoppedState; - Q_EMIT errorChanged(m_errorState); - } - - Q_EMIT stateChanged(m_deviceState); -} - -QIODevice *QOpenSLESAudioInput::start() -{ - if (m_deviceState != QAudio::StoppedState) - stopRecording(); - - m_audioSource = 0; - - if (!m_pullMode && m_bufferIODevice) { - m_bufferIODevice->close(); - delete m_bufferIODevice; - } - - m_pullMode = false; - m_pushBuffer.clear(); - m_bufferIODevice = new QBuffer(&m_pushBuffer); - m_bufferIODevice->open(QIODevice::ReadOnly); - - if (startRecording()) { - m_deviceState = QAudio::IdleState; - } else { - m_deviceState = QAudio::StoppedState; - Q_EMIT errorChanged(m_errorState); - m_bufferIODevice->close(); - delete m_bufferIODevice; - m_bufferIODevice = 0; - } - - Q_EMIT stateChanged(m_deviceState); - return m_bufferIODevice; -} - -bool QOpenSLESAudioInput::startRecording() -{ - if (!hasRecordingPermission()) - return false; - - m_processedBytes = 0; - m_clockStamp.restart(); - m_lastNotifyTime = 0; - - SLresult result; - - // configure audio source - SLDataLocator_IODevice loc_dev = { SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT, - SL_DEFAULTDEVICEID_AUDIOINPUT, NULL }; - SLDataSource audioSrc = { &loc_dev, NULL }; - - // configure audio sink -#ifdef ANDROID - SLDataLocator_AndroidSimpleBufferQueue loc_bq = { SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, - NUM_BUFFERS }; -#else - SLDataLocator_BufferQueue loc_bq = { SL_DATALOCATOR_BUFFERQUEUE, NUM_BUFFERS }; -#endif - - SLDataFormat_PCM format_pcm = QOpenSLESEngine::audioFormatToSLFormatPCM(m_format); - SLDataSink audioSnk = { &loc_bq, &format_pcm }; - - // create audio recorder - // (requires the RECORD_AUDIO permission) -#ifdef ANDROID - const SLInterfaceID id[2] = { SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_ANDROIDCONFIGURATION }; - const SLboolean req[2] = { SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE }; -#else - const SLInterfaceID id[1] = { SL_IID_BUFFERQUEUE }; - const SLboolean req[1] = { SL_BOOLEAN_TRUE }; -#endif - - result = (*m_engine->slEngine())->CreateAudioRecorder(m_engine->slEngine(), &m_recorderObject, - &audioSrc, &audioSnk, - sizeof(req) / sizeof(SLboolean), id, req); - if (result != SL_RESULT_SUCCESS) { - m_errorState = QAudio::OpenError; - return false; - } - -#ifdef ANDROID - // configure recorder source - SLAndroidConfigurationItf configItf; - result = (*m_recorderObject)->GetInterface(m_recorderObject, SL_IID_ANDROIDCONFIGURATION, - &configItf); - if (result != SL_RESULT_SUCCESS) { - m_errorState = QAudio::OpenError; - return false; - } - - result = (*configItf)->SetConfiguration(configItf, SL_ANDROID_KEY_RECORDING_PRESET, - &m_recorderPreset, sizeof(SLuint32)); - - SLuint32 presetValue = SL_ANDROID_RECORDING_PRESET_NONE; - SLuint32 presetSize = 2*sizeof(SLuint32); // intentionally too big - result = (*configItf)->GetConfiguration(configItf, SL_ANDROID_KEY_RECORDING_PRESET, - &presetSize, (void*)&presetValue); - - if (result != SL_RESULT_SUCCESS || presetValue == SL_ANDROID_RECORDING_PRESET_NONE) { - m_errorState = QAudio::OpenError; - return false; - } -#endif - - // realize the audio recorder - result = (*m_recorderObject)->Realize(m_recorderObject, SL_BOOLEAN_FALSE); - if (result != SL_RESULT_SUCCESS) { - m_errorState = QAudio::OpenError; - return false; - } - - // get the record interface - result = (*m_recorderObject)->GetInterface(m_recorderObject, SL_IID_RECORD, &m_recorder); - if (result != SL_RESULT_SUCCESS) { - m_errorState = QAudio::FatalError; - return false; - } - - // get the buffer queue interface -#ifdef ANDROID - SLInterfaceID bufferqueueItfID = SL_IID_ANDROIDSIMPLEBUFFERQUEUE; -#else - SLInterfaceID bufferqueueItfID = SL_IID_BUFFERQUEUE; -#endif - result = (*m_recorderObject)->GetInterface(m_recorderObject, bufferqueueItfID, &m_bufferQueue); - if (result != SL_RESULT_SUCCESS) { - m_errorState = QAudio::FatalError; - return false; - } - - // register callback on the buffer queue - result = (*m_bufferQueue)->RegisterCallback(m_bufferQueue, bufferQueueCallback, this); - if (result != SL_RESULT_SUCCESS) { - m_errorState = QAudio::FatalError; - return false; - } - - if (m_bufferSize <= 0) { - m_bufferSize = m_format.bytesForDuration(DEFAULT_PERIOD_TIME_MS * 1000); - } else { - int minimumBufSize = m_format.bytesForDuration(MINIMUM_PERIOD_TIME_MS * 1000); - if (m_bufferSize < minimumBufSize) - m_bufferSize = minimumBufSize; - } - - m_periodSize = m_bufferSize; - - // enqueue empty buffers to be filled by the recorder - for (int i = 0; i < NUM_BUFFERS; ++i) { - m_buffers[i].resize(m_periodSize); - - result = (*m_bufferQueue)->Enqueue(m_bufferQueue, m_buffers[i].data(), m_periodSize); - if (result != SL_RESULT_SUCCESS) { - m_errorState = QAudio::FatalError; - return false; - } - } - - // start recording - result = (*m_recorder)->SetRecordState(m_recorder, SL_RECORDSTATE_RECORDING); - if (result != SL_RESULT_SUCCESS) { - m_errorState = QAudio::FatalError; - return false; - } - - m_errorState = QAudio::NoError; - - return true; -} - -void QOpenSLESAudioInput::stop() -{ - if (m_deviceState == QAudio::StoppedState) - return; - - m_deviceState = QAudio::StoppedState; - - stopRecording(); - - m_errorState = QAudio::NoError; - Q_EMIT stateChanged(m_deviceState); -} - -void QOpenSLESAudioInput::stopRecording() -{ - flushBuffers(); - - (*m_recorder)->SetRecordState(m_recorder, SL_RECORDSTATE_STOPPED); - (*m_bufferQueue)->Clear(m_bufferQueue); - - (*m_recorderObject)->Destroy(m_recorderObject); - m_recorderObject = 0; - - for (int i = 0; i < NUM_BUFFERS; ++i) - m_buffers[i].clear(); - m_currentBuffer = 0; - - if (!m_pullMode && m_bufferIODevice) { - m_bufferIODevice->close(); - delete m_bufferIODevice; - m_bufferIODevice = 0; - m_pushBuffer.clear(); - } -} - -void QOpenSLESAudioInput::suspend() -{ - if (m_deviceState == QAudio::ActiveState) { - m_deviceState = QAudio::SuspendedState; - emit stateChanged(m_deviceState); - - (*m_recorder)->SetRecordState(m_recorder, SL_RECORDSTATE_PAUSED); - } -} - -void QOpenSLESAudioInput::resume() -{ - if (m_deviceState == QAudio::SuspendedState || m_deviceState == QAudio::IdleState) { - (*m_recorder)->SetRecordState(m_recorder, SL_RECORDSTATE_RECORDING); - - m_deviceState = QAudio::ActiveState; - emit stateChanged(m_deviceState); - } -} - -void QOpenSLESAudioInput::processBuffer() -{ - if (m_deviceState == QAudio::StoppedState || m_deviceState == QAudio::SuspendedState) - return; - - if (m_deviceState != QAudio::ActiveState) { - m_errorState = QAudio::NoError; - m_deviceState = QAudio::ActiveState; - emit stateChanged(m_deviceState); - } - - QByteArray *processedBuffer = &m_buffers[m_currentBuffer]; - writeDataToDevice(processedBuffer->constData(), processedBuffer->size()); - - // Re-enqueue the buffer - SLresult result = (*m_bufferQueue)->Enqueue(m_bufferQueue, - processedBuffer->data(), - processedBuffer->size()); - - m_currentBuffer = (m_currentBuffer + 1) % NUM_BUFFERS; - - // If the buffer queue is empty (shouldn't happen), stop recording. -#ifdef ANDROID - SLAndroidSimpleBufferQueueState state; -#else - SLBufferQueueState state; -#endif - result = (*m_bufferQueue)->GetState(m_bufferQueue, &state); - if (result != SL_RESULT_SUCCESS || state.count == 0) { - stop(); - m_errorState = QAudio::FatalError; - Q_EMIT errorChanged(m_errorState); - } -} - -void QOpenSLESAudioInput::writeDataToDevice(const char *data, int size) -{ - m_processedBytes += size; - - QByteArray outData; - - // Apply volume - if (m_volume < 1.0f) { - outData.resize(size); - QAudioHelperInternal::qMultiplySamples(m_volume, m_format, data, outData.data(), size); - } else { - outData.append(data, size); - } - - if (m_pullMode) { - // write buffer to the QIODevice - if (m_audioSource->write(outData) < 0) { - stop(); - m_errorState = QAudio::IOError; - Q_EMIT errorChanged(m_errorState); - } - } else { - // emits readyRead() so user will call read() on QIODevice to get some audio data - if (m_bufferIODevice != 0) { - m_pushBuffer.append(outData); - Q_EMIT m_bufferIODevice->readyRead(); - } - } - - // Send notify signal if needed - qint64 processedMsecs = processedUSecs() / 1000; - if (m_intervalTime && (processedMsecs - m_lastNotifyTime) >= m_intervalTime) { - Q_EMIT notify(); - m_lastNotifyTime = processedMsecs; - } -} - -void QOpenSLESAudioInput::flushBuffers() -{ - SLmillisecond recorderPos; - (*m_recorder)->GetPosition(m_recorder, &recorderPos); - qint64 devicePos = processedUSecs(); - - qint64 delta = recorderPos * 1000 - devicePos; - - if (delta > 0) { - const int writeSize = qMin(m_buffers[m_currentBuffer].size(), - m_format.bytesForDuration(delta)); - writeDataToDevice(m_buffers[m_currentBuffer].constData(), writeSize); - } -} - -int QOpenSLESAudioInput::bytesReady() const -{ - if (m_deviceState == QAudio::ActiveState || m_deviceState == QAudio::SuspendedState) - return m_bufferIODevice ? m_bufferIODevice->bytesAvailable() : m_periodSize; - - return 0; -} - -void QOpenSLESAudioInput::setBufferSize(int value) -{ - m_bufferSize = value; -} - -int QOpenSLESAudioInput::bufferSize() const -{ - return m_bufferSize; -} - -int QOpenSLESAudioInput::periodSize() const -{ - return m_periodSize; -} - -void QOpenSLESAudioInput::setNotifyInterval(int ms) -{ - m_intervalTime = qMax(0, ms); -} - -int QOpenSLESAudioInput::notifyInterval() const -{ - return m_intervalTime; -} - -qint64 QOpenSLESAudioInput::processedUSecs() const -{ - return m_format.durationForBytes(m_processedBytes); -} - -qint64 QOpenSLESAudioInput::elapsedUSecs() const -{ - if (m_deviceState == QAudio::StoppedState) - return 0; - - return m_clockStamp.elapsed() * qint64(1000); -} - -void QOpenSLESAudioInput::setVolume(qreal vol) -{ - m_volume = vol; -} - -qreal QOpenSLESAudioInput::volume() const -{ - return m_volume; -} - -void QOpenSLESAudioInput::reset() -{ - stop(); -} - -QT_END_NAMESPACE |