summaryrefslogtreecommitdiffstats
path: root/src/plugins/coreaudio/coreaudioinput.mm
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/coreaudio/coreaudioinput.mm')
-rw-r--r--src/plugins/coreaudio/coreaudioinput.mm1005
1 files changed, 0 insertions, 1005 deletions
diff --git a/src/plugins/coreaudio/coreaudioinput.mm b/src/plugins/coreaudio/coreaudioinput.mm
deleted file mode 100644
index 9f6a1f7bc..000000000
--- a/src/plugins/coreaudio/coreaudioinput.mm
+++ /dev/null
@@ -1,1005 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies).
-** 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 "coreaudioinput.h"
-#include "coreaudiosessionmanager.h"
-#include "coreaudiodeviceinfo.h"
-#include "coreaudioutils.h"
-
-#if defined(Q_OS_OSX)
-# include <AudioUnit/AudioComponent.h>
-#endif
-
-#if defined(Q_OS_IOS) || defined(Q_OS_TVOS)
-# include "coreaudiosessionmanager.h"
-#endif
-
-#include <QtMultimedia/private/qaudiohelpers_p.h>
-#include <QtCore/QDataStream>
-#include <QtCore/QDebug>
-
-QT_BEGIN_NAMESPACE
-
-static const int DEFAULT_BUFFER_SIZE = 4 * 1024;
-
-CoreAudioBufferList::CoreAudioBufferList(const AudioStreamBasicDescription &streamFormat)
- : m_owner(false)
- , m_streamDescription(streamFormat)
-{
- const bool isInterleaved = (m_streamDescription.mFormatFlags & kAudioFormatFlagIsNonInterleaved) == 0;
- const int numberOfBuffers = isInterleaved ? 1 : m_streamDescription.mChannelsPerFrame;
-
- m_dataSize = 0;
-
- m_bufferList = reinterpret_cast<AudioBufferList*>(malloc(sizeof(AudioBufferList) +
- (sizeof(AudioBuffer) * numberOfBuffers)));
-
- m_bufferList->mNumberBuffers = numberOfBuffers;
- for (int i = 0; i < numberOfBuffers; ++i) {
- m_bufferList->mBuffers[i].mNumberChannels = isInterleaved ? numberOfBuffers : 1;
- m_bufferList->mBuffers[i].mDataByteSize = 0;
- m_bufferList->mBuffers[i].mData = 0;
- }
-}
-
-CoreAudioBufferList::CoreAudioBufferList(const AudioStreamBasicDescription &streamFormat, char *buffer, int bufferSize)
- : m_owner(false)
- , m_streamDescription(streamFormat)
- , m_bufferList(0)
-{
- m_dataSize = bufferSize;
-
- m_bufferList = reinterpret_cast<AudioBufferList*>(malloc(sizeof(AudioBufferList) + sizeof(AudioBuffer)));
-
- m_bufferList->mNumberBuffers = 1;
- m_bufferList->mBuffers[0].mNumberChannels = 1;
- m_bufferList->mBuffers[0].mDataByteSize = m_dataSize;
- m_bufferList->mBuffers[0].mData = buffer;
-}
-
-CoreAudioBufferList::CoreAudioBufferList(const AudioStreamBasicDescription &streamFormat, int framesToBuffer)
- : m_owner(true)
- , m_streamDescription(streamFormat)
- , m_bufferList(0)
-{
- const bool isInterleaved = (m_streamDescription.mFormatFlags & kAudioFormatFlagIsNonInterleaved) == 0;
- const int numberOfBuffers = isInterleaved ? 1 : m_streamDescription.mChannelsPerFrame;
-
- m_dataSize = framesToBuffer * m_streamDescription.mBytesPerFrame;
-
- m_bufferList = reinterpret_cast<AudioBufferList*>(malloc(sizeof(AudioBufferList) +
- (sizeof(AudioBuffer) * numberOfBuffers)));
- m_bufferList->mNumberBuffers = numberOfBuffers;
- for (int i = 0; i < numberOfBuffers; ++i) {
- m_bufferList->mBuffers[i].mNumberChannels = isInterleaved ? numberOfBuffers : 1;
- m_bufferList->mBuffers[i].mDataByteSize = m_dataSize;
- m_bufferList->mBuffers[i].mData = malloc(m_dataSize);
- }
-}
-
-CoreAudioBufferList::~CoreAudioBufferList()
-{
- if (m_owner) {
- for (UInt32 i = 0; i < m_bufferList->mNumberBuffers; ++i)
- free(m_bufferList->mBuffers[i].mData);
- }
-
- free(m_bufferList);
-}
-
-char *CoreAudioBufferList::data(int buffer) const
-{
- return static_cast<char*>(m_bufferList->mBuffers[buffer].mData);
-}
-
-qint64 CoreAudioBufferList::bufferSize(int buffer) const
-{
- return m_bufferList->mBuffers[buffer].mDataByteSize;
-}
-
-int CoreAudioBufferList::frameCount(int buffer) const
-{
- return m_bufferList->mBuffers[buffer].mDataByteSize / m_streamDescription.mBytesPerFrame;
-}
-
-int CoreAudioBufferList::packetCount(int buffer) const
-{
- return m_bufferList->mBuffers[buffer].mDataByteSize / m_streamDescription.mBytesPerPacket;
-}
-
-int CoreAudioBufferList::packetSize() const
-{
- return m_streamDescription.mBytesPerPacket;
-}
-
-void CoreAudioBufferList::reset()
-{
- for (UInt32 i = 0; i < m_bufferList->mNumberBuffers; ++i) {
- m_bufferList->mBuffers[i].mDataByteSize = m_dataSize;
- m_bufferList->mBuffers[i].mData = 0;
- }
-}
-
-CoreAudioPacketFeeder::CoreAudioPacketFeeder(CoreAudioBufferList *abl)
- : m_audioBufferList(abl)
-{
- m_totalPackets = m_audioBufferList->packetCount();
- m_position = 0;
-}
-
-bool CoreAudioPacketFeeder::feed(AudioBufferList &dst, UInt32 &packetCount)
-{
- if (m_position == m_totalPackets) {
- dst.mBuffers[0].mDataByteSize = 0;
- packetCount = 0;
- return false;
- }
-
- if (m_totalPackets - m_position < packetCount)
- packetCount = m_totalPackets - m_position;
-
- dst.mBuffers[0].mDataByteSize = packetCount * m_audioBufferList->packetSize();
- dst.mBuffers[0].mData = m_audioBufferList->data() + (m_position * m_audioBufferList->packetSize());
-
- m_position += packetCount;
-
- return true;
-}
-
-bool CoreAudioPacketFeeder::empty() const
-{
- return m_position == m_totalPackets;
-}
-
-CoreAudioInputBuffer::CoreAudioInputBuffer(int bufferSize, int maxPeriodSize, const AudioStreamBasicDescription &inputFormat, const AudioStreamBasicDescription &outputFormat, QObject *parent)
- : QObject(parent)
- , m_deviceError(false)
- , m_device(0)
- , m_audioConverter(0)
- , m_inputFormat(inputFormat)
- , m_outputFormat(outputFormat)
- , m_volume(qreal(1.0f))
-{
- m_maxPeriodSize = maxPeriodSize;
- m_periodTime = m_maxPeriodSize / m_outputFormat.mBytesPerFrame * 1000 / m_outputFormat.mSampleRate;
-
- m_buffer = new CoreAudioRingBuffer(bufferSize);
-
- m_inputBufferList = new CoreAudioBufferList(m_inputFormat);
-
- m_flushTimer = new QTimer(this);
- connect(m_flushTimer, SIGNAL(timeout()), SLOT(flushBuffer()));
-
- if (CoreAudioUtils::toQAudioFormat(inputFormat) != CoreAudioUtils::toQAudioFormat(outputFormat)) {
- if (AudioConverterNew(&m_inputFormat, &m_outputFormat, &m_audioConverter) != noErr) {
- qWarning() << "QAudioInput: Unable to create an Audio Converter";
- m_audioConverter = 0;
- }
- }
-
- m_qFormat = CoreAudioUtils::toQAudioFormat(inputFormat); // we adjust volume before conversion
-}
-
-CoreAudioInputBuffer::~CoreAudioInputBuffer()
-{
- delete m_buffer;
-}
-
-qreal CoreAudioInputBuffer::volume() const
-{
- return m_volume;
-}
-
-void CoreAudioInputBuffer::setVolume(qreal v)
-{
- m_volume = v;
-}
-
-qint64 CoreAudioInputBuffer::renderFromDevice(AudioUnit audioUnit, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames)
-{
- const bool pullMode = m_device == 0;
-
- OSStatus err;
- qint64 framesRendered = 0;
-
- m_inputBufferList->reset();
- err = AudioUnitRender(audioUnit,
- ioActionFlags,
- inTimeStamp,
- inBusNumber,
- inNumberFrames,
- m_inputBufferList->audioBufferList());
-
- // adjust volume, if necessary
- if (!qFuzzyCompare(m_volume, qreal(1.0f))) {
- QAudioHelperInternal::qMultiplySamples(m_volume,
- m_qFormat,
- m_inputBufferList->data(), /* input */
- m_inputBufferList->data(), /* output */
- m_inputBufferList->bufferSize());
- }
-
- if (m_audioConverter != 0) {
- CoreAudioPacketFeeder feeder(m_inputBufferList);
-
- int copied = 0;
- const int available = m_buffer->free();
-
- while (err == noErr && !feeder.empty()) {
- CoreAudioRingBuffer::Region region = m_buffer->acquireWriteRegion(available - copied);
-
- if (region.second == 0)
- break;
-
- AudioBufferList output;
- output.mNumberBuffers = 1;
- output.mBuffers[0].mNumberChannels = 1;
- output.mBuffers[0].mDataByteSize = region.second;
- output.mBuffers[0].mData = region.first;
-
- UInt32 packetSize = region.second / m_outputFormat.mBytesPerPacket;
- err = AudioConverterFillComplexBuffer(m_audioConverter,
- converterCallback,
- &feeder,
- &packetSize,
- &output,
- 0);
- region.second = output.mBuffers[0].mDataByteSize;
- copied += region.second;
-
- m_buffer->releaseWriteRegion(region);
- }
-
- framesRendered += copied / m_outputFormat.mBytesPerFrame;
- }
- else {
- const int available = m_inputBufferList->bufferSize();
- bool wecan = true;
- int copied = 0;
-
- while (wecan && copied < available) {
- CoreAudioRingBuffer::Region region = m_buffer->acquireWriteRegion(available - copied);
-
- if (region.second > 0) {
- memcpy(region.first, m_inputBufferList->data() + copied, region.second);
- copied += region.second;
- }
- else
- wecan = false;
-
- m_buffer->releaseWriteRegion(region);
- }
-
- framesRendered = copied / m_outputFormat.mBytesPerFrame;
- }
-
- if (pullMode && framesRendered > 0)
- emit readyRead();
-
- return framesRendered;
-}
-
-qint64 CoreAudioInputBuffer::readBytes(char *data, qint64 len)
-{
- bool wecan = true;
- qint64 bytesCopied = 0;
-
- len -= len % m_maxPeriodSize;
- while (wecan && bytesCopied < len) {
- CoreAudioRingBuffer::Region region = m_buffer->acquireReadRegion(len - bytesCopied);
-
- if (region.second > 0) {
- memcpy(data + bytesCopied, region.first, region.second);
- bytesCopied += region.second;
- }
- else
- wecan = false;
-
- m_buffer->releaseReadRegion(region);
- }
-
- return bytesCopied;
-}
-
-void CoreAudioInputBuffer::setFlushDevice(QIODevice *device)
-{
- if (m_device != device)
- m_device = device;
-}
-
-void CoreAudioInputBuffer::startFlushTimer()
-{
- if (m_device != 0) {
- // We use the period time for the timer, since that's
- // around the buffer size (pre conversion >.>)
- m_flushTimer->start(qMax(1, m_periodTime));
- }
-}
-
-void CoreAudioInputBuffer::stopFlushTimer()
-{
- m_flushTimer->stop();
-}
-
-void CoreAudioInputBuffer::flush(bool all)
-{
- if (m_device == 0)
- return;
-
- const int used = m_buffer->used();
- const int readSize = all ? used : used - (used % m_maxPeriodSize);
-
- if (readSize > 0) {
- bool wecan = true;
- int flushed = 0;
-
- while (!m_deviceError && wecan && flushed < readSize) {
- CoreAudioRingBuffer::Region region = m_buffer->acquireReadRegion(readSize - flushed);
-
- if (region.second > 0) {
- int bytesWritten = m_device->write(region.first, region.second);
- if (bytesWritten < 0) {
- stopFlushTimer();
- m_deviceError = true;
- }
- else {
- region.second = bytesWritten;
- flushed += bytesWritten;
- wecan = bytesWritten != 0;
- }
- }
- else
- wecan = false;
-
- m_buffer->releaseReadRegion(region);
- }
- }
-}
-
-void CoreAudioInputBuffer::reset()
-{
- m_buffer->reset();
- m_deviceError = false;
-}
-
-int CoreAudioInputBuffer::available() const
-{
- return m_buffer->free();
-}
-
-int CoreAudioInputBuffer::used() const
-{
- return m_buffer->used();
-}
-
-void CoreAudioInputBuffer::flushBuffer()
-{
- flush();
-}
-
-OSStatus CoreAudioInputBuffer::converterCallback(AudioConverterRef inAudioConverter, UInt32 *ioNumberDataPackets, AudioBufferList *ioData, AudioStreamPacketDescription **outDataPacketDescription, void *inUserData)
-{
- Q_UNUSED(inAudioConverter);
- Q_UNUSED(outDataPacketDescription);
-
- CoreAudioPacketFeeder* feeder = static_cast<CoreAudioPacketFeeder*>(inUserData);
-
- if (!feeder->feed(*ioData, *ioNumberDataPackets))
- return as_empty;
-
- return noErr;
-}
-
-CoreAudioInputDevice::CoreAudioInputDevice(CoreAudioInputBuffer *audioBuffer, QObject *parent)
- : QIODevice(parent)
- , m_audioBuffer(audioBuffer)
-{
- open(QIODevice::ReadOnly | QIODevice::Unbuffered);
- connect(m_audioBuffer, SIGNAL(readyRead()), SIGNAL(readyRead()));
-}
-
-qint64 CoreAudioInputDevice::readData(char *data, qint64 len)
-{
- return m_audioBuffer->readBytes(data, len);
-}
-
-qint64 CoreAudioInputDevice::writeData(const char *data, qint64 len)
-{
- Q_UNUSED(data);
- Q_UNUSED(len);
-
- return 0;
-}
-
-CoreAudioInput::CoreAudioInput(const QByteArray &device)
- : m_isOpen(false)
- , m_internalBufferSize(DEFAULT_BUFFER_SIZE)
- , m_totalFrames(0)
- , m_audioUnit(0)
- , m_clockFrequency(CoreAudioUtils::frequency() / 1000)
- , m_startTime(0)
- , m_errorCode(QAudio::NoError)
- , m_stateCode(QAudio::StoppedState)
- , m_audioBuffer(0)
- , m_volume(1.0)
-{
-#if defined(Q_OS_OSX)
- quint32 deviceId;
- QDataStream dataStream(device);
- dataStream >> deviceId >> m_device;
- m_audioDeviceId = AudioDeviceID(deviceId);
-#else //iOS
- m_device = device;
-#endif
-
- m_audioDeviceInfo = new CoreAudioDeviceInfo(device, QAudio::AudioInput);
-
- m_intervalTimer = new QTimer(this);
- m_intervalTimer->setInterval(1000);
- connect(m_intervalTimer, SIGNAL(timeout()), this, SIGNAL(notify()));
-}
-
-
-CoreAudioInput::~CoreAudioInput()
-{
- close();
- delete m_audioDeviceInfo;
-}
-
-bool CoreAudioInput::open()
-{
-#if defined(Q_OS_IOS)
- CoreAudioSessionManager::instance().setCategory(CoreAudioSessionManager::PlayAndRecord, CoreAudioSessionManager::MixWithOthers);
- CoreAudioSessionManager::instance().setActive(true);
-#endif
-
- if (m_isOpen)
- return true;
-
- UInt32 size = 0;
-
- AudioComponentDescription componentDescription;
- componentDescription.componentType = kAudioUnitType_Output;
-#if defined(Q_OS_OSX)
- componentDescription.componentSubType = kAudioUnitSubType_HALOutput;
-#else
- componentDescription.componentSubType = kAudioUnitSubType_RemoteIO;
-#endif
- componentDescription.componentManufacturer = kAudioUnitManufacturer_Apple;
- componentDescription.componentFlags = 0;
- componentDescription.componentFlagsMask = 0;
-
- AudioComponent component = AudioComponentFindNext(0, &componentDescription);
- if (component == 0) {
- qWarning() << "QAudioInput: Failed to find Output component";
- return false;
- }
-
- if (AudioComponentInstanceNew(component, &m_audioUnit) != noErr) {
- qWarning() << "QAudioInput: Unable to Open Output Component";
- return false;
- }
-
- // Set mode
- // switch to input mode
- UInt32 enable = 1;
- if (AudioUnitSetProperty(m_audioUnit,
- kAudioOutputUnitProperty_EnableIO,
- kAudioUnitScope_Input,
- 1,
- &enable,
- sizeof(enable)) != noErr) {
- qWarning() << "QAudioInput: Unable to switch to input mode (Enable Input)";
- return false;
- }
-
- enable = 0;
- if (AudioUnitSetProperty(m_audioUnit,
- kAudioOutputUnitProperty_EnableIO,
- kAudioUnitScope_Output,
- 0,
- &enable,
- sizeof(enable)) != noErr) {
- qWarning() << "QAudioInput: Unable to switch to input mode (Disable output)";
- return false;
- }
-
- // register callback
- AURenderCallbackStruct callback;
- callback.inputProc = inputCallback;
- callback.inputProcRefCon = this;
-
- if (AudioUnitSetProperty(m_audioUnit,
- kAudioOutputUnitProperty_SetInputCallback,
- kAudioUnitScope_Global,
- 0,
- &callback,
- sizeof(callback)) != noErr) {
- qWarning() << "QAudioInput: Failed to set AudioUnit callback";
- return false;
- }
-
-#if defined(Q_OS_OSX)
- //Set Audio Device
- if (AudioUnitSetProperty(m_audioUnit,
- kAudioOutputUnitProperty_CurrentDevice,
- kAudioUnitScope_Global,
- 0,
- &m_audioDeviceId,
- sizeof(m_audioDeviceId)) != noErr) {
- qWarning() << "QAudioInput: Unable to use configured device";
- return false;
- }
-#endif
-
- //set format
- m_streamFormat = CoreAudioUtils::toAudioStreamBasicDescription(m_audioFormat);
-
-#if defined(Q_OS_OSX)
- if (m_audioFormat == m_audioDeviceInfo->preferredFormat()) {
-#endif
-
- m_deviceFormat = m_streamFormat;
- AudioUnitSetProperty(m_audioUnit,
- kAudioUnitProperty_StreamFormat,
- kAudioUnitScope_Output,
- 1,
- &m_deviceFormat,
- sizeof(m_deviceFormat));
-#if defined(Q_OS_OSX)
- } else {
- size = sizeof(m_deviceFormat);
- if (AudioUnitGetProperty(m_audioUnit,
- kAudioUnitProperty_StreamFormat,
- kAudioUnitScope_Input,
- 1,
- &m_deviceFormat,
- &size) != noErr) {
- qWarning() << "QAudioInput: Unable to retrieve device format";
- return false;
- }
-
- if (AudioUnitSetProperty(m_audioUnit,
- kAudioUnitProperty_StreamFormat,
- kAudioUnitScope_Output,
- 1,
- &m_deviceFormat,
- sizeof(m_deviceFormat)) != noErr) {
- qWarning() << "QAudioInput: Unable to set device format";
- return false;
- }
- }
-#endif
-
- //setup buffers
- UInt32 numberOfFrames;
-#if defined(Q_OS_OSX)
- size = sizeof(UInt32);
- if (AudioUnitGetProperty(m_audioUnit,
- kAudioDevicePropertyBufferFrameSize,
- kAudioUnitScope_Global,
- 0,
- &numberOfFrames,
- &size) != noErr) {
- qWarning() << "QAudioInput: Failed to get audio period size";
- return false;
- }
- //BUG: numberOfFrames gets ignored after this point
-
- AudioValueRange bufferRange;
- size = sizeof(AudioValueRange);
-
- if (AudioUnitGetProperty(m_audioUnit,
- kAudioDevicePropertyBufferFrameSizeRange,
- kAudioUnitScope_Global,
- 0,
- &bufferRange,
- &size) != noErr) {
- qWarning() << "QAudioInput: Failed to get audio period size range";
- return false;
- }
-
- // See if the requested buffer size is permissible
- numberOfFrames = qBound((UInt32)bufferRange.mMinimum, m_internalBufferSize / m_streamFormat.mBytesPerFrame, (UInt32)bufferRange.mMaximum);
-
- // Set it back
- if (AudioUnitSetProperty(m_audioUnit,
- kAudioDevicePropertyBufferFrameSize,
- kAudioUnitScope_Global,
- 0,
- &numberOfFrames,
- sizeof(UInt32)) != noErr) {
- qWarning() << "QAudioInput: Failed to set audio buffer size";
- return false;
- }
-#else //iOS
- Float32 bufferSize = CoreAudioSessionManager::instance().currentIOBufferDuration();
- bufferSize *= m_streamFormat.mSampleRate;
- numberOfFrames = bufferSize;
-#endif
-
- // Now allocate a few buffers to be safe.
- m_periodSizeBytes = m_internalBufferSize = numberOfFrames * m_streamFormat.mBytesPerFrame;
-
- m_audioBuffer = new CoreAudioInputBuffer(m_internalBufferSize * 4,
- m_periodSizeBytes,
- m_deviceFormat,
- m_streamFormat,
- this);
-
- m_audioBuffer->setVolume(m_volume);
- m_audioIO = new CoreAudioInputDevice(m_audioBuffer, this);
-
- // Init
- if (AudioUnitInitialize(m_audioUnit) != noErr) {
- qWarning() << "QAudioInput: Failed to initialize AudioUnit";
- return false;
- }
-
- m_isOpen = true;
-
- return m_isOpen;
-
-}
-
-void CoreAudioInput::close()
-{
- if (m_audioUnit != 0) {
- AudioOutputUnitStop(m_audioUnit);
- AudioUnitUninitialize(m_audioUnit);
- AudioComponentInstanceDispose(m_audioUnit);
- }
-
- delete m_audioBuffer;
-}
-
-void CoreAudioInput::start(QIODevice *device)
-{
- QIODevice* op = device;
-
- if (!m_audioDeviceInfo->isFormatSupported(m_audioFormat) || !open()) {
- m_stateCode = QAudio::StoppedState;
- m_errorCode = QAudio::OpenError;
- return;
- }
-
- reset();
- m_audioBuffer->reset();
- m_audioBuffer->setFlushDevice(op);
-
- if (op == 0)
- op = m_audioIO;
-
- // Start
- m_startTime = CoreAudioUtils::currentTime();
- m_totalFrames = 0;
-
- m_stateCode = QAudio::IdleState;
- m_errorCode = QAudio::NoError;
- emit stateChanged(m_stateCode);
-
- audioThreadStart();
-}
-
-
-QIODevice *CoreAudioInput::start()
-{
- QIODevice* op = 0;
-
- if (!m_audioDeviceInfo->isFormatSupported(m_audioFormat) || !open()) {
- m_stateCode = QAudio::StoppedState;
- m_errorCode = QAudio::OpenError;
- return m_audioIO;
- }
-
- reset();
- m_audioBuffer->reset();
- m_audioBuffer->setFlushDevice(op);
-
- if (op == 0)
- op = m_audioIO;
-
- // Start
- m_startTime = CoreAudioUtils::currentTime();
- m_totalFrames = 0;
-
- m_stateCode = QAudio::IdleState;
- m_errorCode = QAudio::NoError;
- emit stateChanged(m_stateCode);
-
- audioThreadStart();
-
- return op;
-}
-
-
-void CoreAudioInput::stop()
-{
- QMutexLocker lock(&m_mutex);
- if (m_stateCode != QAudio::StoppedState) {
- audioThreadStop();
- m_audioBuffer->flush(true);
-
- m_errorCode = QAudio::NoError;
- m_stateCode = QAudio::StoppedState;
- QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, Q_ARG(QAudio::State, m_stateCode));
- }
-}
-
-
-void CoreAudioInput::reset()
-{
- QMutexLocker lock(&m_mutex);
- if (m_stateCode != QAudio::StoppedState) {
- audioThreadStop();
-
- m_errorCode = QAudio::NoError;
- m_stateCode = QAudio::StoppedState;
- m_audioBuffer->reset();
- QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, Q_ARG(QAudio::State, m_stateCode));
- }
-}
-
-
-void CoreAudioInput::suspend()
-{
- QMutexLocker lock(&m_mutex);
- if (m_stateCode == QAudio::ActiveState || m_stateCode == QAudio::IdleState) {
- audioThreadStop();
-
- m_errorCode = QAudio::NoError;
- m_stateCode = QAudio::SuspendedState;
- QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, Q_ARG(QAudio::State, m_stateCode));
- }
-}
-
-
-void CoreAudioInput::resume()
-{
- QMutexLocker lock(&m_mutex);
- if (m_stateCode == QAudio::SuspendedState) {
- audioThreadStart();
-
- m_errorCode = QAudio::NoError;
- m_stateCode = QAudio::ActiveState;
- QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, Q_ARG(QAudio::State, m_stateCode));
- }
-}
-
-
-int CoreAudioInput::bytesReady() const
-{
- if (!m_audioBuffer)
- return 0;
- return m_audioBuffer->used();
-}
-
-
-int CoreAudioInput::periodSize() const
-{
- return m_periodSizeBytes;
-}
-
-
-void CoreAudioInput::setBufferSize(int value)
-{
- m_internalBufferSize = value;
-}
-
-
-int CoreAudioInput::bufferSize() const
-{
- return m_internalBufferSize;
-}
-
-
-void CoreAudioInput::setNotifyInterval(int milliSeconds)
-{
- if (m_intervalTimer->interval() == milliSeconds)
- return;
-
- if (milliSeconds <= 0)
- milliSeconds = 0;
-
- m_intervalTimer->setInterval(milliSeconds);
-}
-
-
-int CoreAudioInput::notifyInterval() const
-{
- return m_intervalTimer->interval();
-}
-
-
-qint64 CoreAudioInput::processedUSecs() const
-{
- return m_totalFrames * 1000000 / m_audioFormat.sampleRate();
-}
-
-
-qint64 CoreAudioInput::elapsedUSecs() const
-{
- if (m_stateCode == QAudio::StoppedState)
- return 0;
-
- return (CoreAudioUtils::currentTime() - m_startTime) / (m_clockFrequency / 1000);
-}
-
-
-QAudio::Error CoreAudioInput::error() const
-{
- return m_errorCode;
-}
-
-
-QAudio::State CoreAudioInput::state() const
-{
- return m_stateCode;
-}
-
-
-void CoreAudioInput::setFormat(const QAudioFormat &format)
-{
- if (m_stateCode == QAudio::StoppedState)
- m_audioFormat = format;
-}
-
-
-QAudioFormat CoreAudioInput::format() const
-{
- return m_audioFormat;
-}
-
-
-void CoreAudioInput::setVolume(qreal volume)
-{
- m_volume = volume;
- if (m_audioBuffer)
- m_audioBuffer->setVolume(m_volume);
-}
-
-
-qreal CoreAudioInput::volume() const
-{
- return m_volume;
-}
-
-void CoreAudioInput::deviceStoppped()
-{
- stopTimers();
- emit stateChanged(m_stateCode);
-}
-
-void CoreAudioInput::audioThreadStart()
-{
- startTimers();
- m_audioThreadState.storeRelaxed(Running);
- AudioOutputUnitStart(m_audioUnit);
-}
-
-void CoreAudioInput::audioThreadStop()
-{
- stopTimers();
- if (m_audioThreadState.testAndSetAcquire(Running, Stopped))
- m_threadFinished.wait(&m_mutex);
-}
-
-void CoreAudioInput::audioDeviceStop()
-{
- AudioOutputUnitStop(m_audioUnit);
- m_audioThreadState.storeRelaxed(Stopped);
- m_threadFinished.wakeOne();
-}
-
-void CoreAudioInput::audioDeviceActive()
-{
- if (m_stateCode == QAudio::IdleState) {
- QMutexLocker lock(&m_mutex);
- m_stateCode = QAudio::ActiveState;
- emit stateChanged(m_stateCode);
- }
-}
-
-void CoreAudioInput::audioDeviceFull()
-{
- if (m_stateCode == QAudio::ActiveState) {
- QMutexLocker lock(&m_mutex);
- m_errorCode = QAudio::UnderrunError;
- m_stateCode = QAudio::IdleState;
- emit stateChanged(m_stateCode);
- }
-}
-
-void CoreAudioInput::audioDeviceError()
-{
- if (m_stateCode == QAudio::ActiveState) {
- QMutexLocker lock(&m_mutex);
- audioDeviceStop();
-
- m_errorCode = QAudio::IOError;
- m_stateCode = QAudio::StoppedState;
- QMetaObject::invokeMethod(this, "deviceStopped", Qt::QueuedConnection);
- }
-}
-
-void CoreAudioInput::startTimers()
-{
- m_audioBuffer->startFlushTimer();
- if (m_intervalTimer->interval() > 0)
- m_intervalTimer->start();
-}
-
-void CoreAudioInput::stopTimers()
-{
- m_audioBuffer->stopFlushTimer();
- m_intervalTimer->stop();
-}
-
-OSStatus CoreAudioInput::inputCallback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData)
-{
- Q_UNUSED(ioData);
-
- CoreAudioInput* d = static_cast<CoreAudioInput*>(inRefCon);
-
- const int threadState = d->m_audioThreadState.loadAcquire();
- if (threadState == Stopped)
- d->audioDeviceStop();
- else {
- qint64 framesWritten;
-
- framesWritten = d->m_audioBuffer->renderFromDevice(d->m_audioUnit,
- ioActionFlags,
- inTimeStamp,
- inBusNumber,
- inNumberFrames);
-
- if (framesWritten > 0) {
- d->m_totalFrames += framesWritten;
- d->audioDeviceActive();
- } else if (framesWritten == 0)
- d->audioDeviceFull();
- else if (framesWritten < 0)
- d->audioDeviceError();
- }
-
- return noErr;
-}
-
-QT_END_NAMESPACE
-
-#include "moc_coreaudioinput.cpp"