/**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** 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 Digia. For licensing terms and ** conditions see http://qt.digia.com/licensing. For further information ** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Digia gives you certain additional ** rights. These rights are described in the Digia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3.0 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU General Public License version 3.0 requirements will be ** met: http://www.gnu.org/copyleft/gpl.html. ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef IOSAUDIOINPUT_H #define IOSAUDIOINPUT_H #include #include #include #include #include #include #include QT_BEGIN_NAMESPACE class CoreAudioRingBuffer; class CoreAudioPacketFeeder; class CoreAudioInputBuffer; class CoreAudioInputDevice; class CoreAudioBufferList { public: CoreAudioBufferList(AudioStreamBasicDescription const& streamFormat); CoreAudioBufferList(AudioStreamBasicDescription const& streamFormat, char *buffer, int bufferSize); CoreAudioBufferList(AudioStreamBasicDescription const& streamFormat, int framesToBuffer); ~CoreAudioBufferList(); AudioBufferList* audioBufferList() const { return m_bufferList; } char *data(int buffer = 0) const; qint64 bufferSize(int buffer = 0) const; int frameCount(int buffer = 0) const; int packetCount(int buffer = 0) const; int packetSize() const; void reset(); private: bool m_owner; int m_dataSize; AudioStreamBasicDescription m_streamDescription; AudioBufferList *m_bufferList; }; class CoreAudioPacketFeeder { public: CoreAudioPacketFeeder(CoreAudioBufferList *abl); bool feed(AudioBufferList& dst, UInt32& packetCount); bool empty() const; private: UInt32 m_totalPackets; UInt32 m_position; CoreAudioBufferList *m_audioBufferList; }; class CoreAudioInputBuffer : public QObject { Q_OBJECT public: CoreAudioInputBuffer(int bufferSize, int maxPeriodSize, AudioStreamBasicDescription const& inputFormat, AudioStreamBasicDescription const& outputFormat, QObject *parent); ~CoreAudioInputBuffer(); qreal volume() const; void setVolume(qreal v); qint64 renderFromDevice(AudioUnit audioUnit, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames); qint64 readBytes(char *data, qint64 len); void setFlushDevice(QIODevice *device); void startFlushTimer(); void stopFlushTimer(); void flush(bool all = false); void reset(); int available() const; int used() const; signals: void readyRead(); private slots: void flushBuffer(); private: bool m_deviceError; int m_maxPeriodSize; int m_periodTime; QIODevice *m_device; QTimer *m_flushTimer; CoreAudioRingBuffer *m_buffer; CoreAudioBufferList *m_inputBufferList; AudioConverterRef m_audioConverter; AudioStreamBasicDescription m_inputFormat; AudioStreamBasicDescription m_outputFormat; QAudioFormat m_qFormat; qreal m_volume; const static OSStatus as_empty = 'qtem'; // Converter callback static OSStatus converterCallback(AudioConverterRef inAudioConverter, UInt32 *ioNumberDataPackets, AudioBufferList *ioData, AudioStreamPacketDescription **outDataPacketDescription, void *inUserData); }; class CoreAudioInputDevice : public QIODevice { Q_OBJECT public: CoreAudioInputDevice(CoreAudioInputBuffer *audioBuffer, QObject *parent); qint64 readData(char *data, qint64 len); qint64 writeData(const char *data, qint64 len); bool isSequential() const { return true; } private: CoreAudioInputBuffer *m_audioBuffer; }; class CoreAudioInput : public QAbstractAudioInput { Q_OBJECT public: CoreAudioInput(const QByteArray &device); ~CoreAudioInput(); void start(QIODevice *device); QIODevice *start(); void stop(); void reset(); void suspend(); void resume(); int bytesReady() const; int periodSize() const; void setBufferSize(int value); int bufferSize() const; void setNotifyInterval(int milliSeconds); int notifyInterval() const; qint64 processedUSecs() const; qint64 elapsedUSecs() const; QAudio::Error error() const; QAudio::State state() const; void setFormat(const QAudioFormat &format); QAudioFormat format() const; void setVolume(qreal volume); qreal volume() const; private slots: void deviceStoppped(); private: enum { Running, Stopped }; bool open(); void close(); void audioThreadStart(); void audioThreadStop(); void audioDeviceStop(); void audioDeviceActive(); void audioDeviceFull(); void audioDeviceError(); void startTimers(); void stopTimers(); // Input callback static OSStatus inputCallback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData); QByteArray m_device; bool m_isOpen; int m_periodSizeBytes; int m_internalBufferSize; qint64 m_totalFrames; QAudioFormat m_audioFormat; QIODevice *m_audioIO; AudioUnit m_audioUnit; #if defined(Q_OS_OSX) AudioDeviceID m_audioDeviceId; #endif Float64 m_clockFrequency; UInt64 m_startTime; QAudio::Error m_errorCode; QAudio::State m_stateCode; CoreAudioInputBuffer *m_audioBuffer; QMutex m_mutex; QWaitCondition m_threadFinished; QAtomicInt m_audioThreadState; QTimer *m_intervalTimer; AudioStreamBasicDescription m_streamFormat; AudioStreamBasicDescription m_deviceFormat; QAbstractAudioDeviceInfo *m_audioDeviceInfo; qreal m_volume; }; QT_END_NAMESPACE #endif // IOSAUDIOINPUT_H