1 /**************************************************************************** 2 ** 3 ** Copyright (C) 2016 The Qt Company Ltd. 4 ** Contact: https://www.qt.io/licensing/ 5 ** 6 ** This file is part of the Qt Toolkit. 7 ** 8 ** $QT_BEGIN_LICENSE:LGPL$ 9 ** Commercial License Usage 10 ** Licensees holding valid commercial Qt licenses may use this file in 11 ** accordance with the commercial license agreement provided with the 12 ** Software or, alternatively, in accordance with the terms contained in 13 ** a written agreement between you and The Qt Company. For licensing terms 14 ** and conditions see https://www.qt.io/terms-conditions. For further 15 ** information use the contact form at https://www.qt.io/contact-us. 16 ** 17 ** GNU Lesser General Public License Usage 18 ** Alternatively, this file may be used under the terms of the GNU Lesser 19 ** General Public License version 3 as published by the Free Software 20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the 21 ** packaging of this file. Please review the following information to 22 ** ensure the GNU Lesser General Public License version 3 requirements 23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. 24 ** 25 ** GNU General Public License Usage 26 ** Alternatively, this file may be used under the terms of the GNU 27 ** General Public License version 2.0 or (at your option) the GNU General 28 ** Public license version 3 or any later version approved by the KDE Free 29 ** Qt Foundation. The licenses are as published by the Free Software 30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 31 ** included in the packaging of this file. Please review the following 32 ** information to ensure the GNU General Public License requirements will 33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and 34 ** https://www.gnu.org/licenses/gpl-3.0.html. 35 ** 36 ** $QT_END_LICENSE$ 37 ** 38 ****************************************************************************/ 39 #ifndef IOSAUDIOINPUT_H 40 #define IOSAUDIOINPUT_H 41 42 #include <qaudiosystem.h> 43 #include <AudioUnit/AudioUnit.h> 44 #include <CoreAudio/CoreAudioTypes.h> 45 #include <AudioToolbox/AudioToolbox.h> 46 47 #include <QtCore/QIODevice> 48 #include <QtCore/QWaitCondition> 49 #include <QtCore/QMutex> 50 #include <QtCore/QTimer> 51 52 QT_BEGIN_NAMESPACE 53 54 class CoreAudioRingBuffer; 55 class CoreAudioPacketFeeder; 56 class CoreAudioInputBuffer; 57 class CoreAudioInputDevice; 58 59 class CoreAudioBufferList 60 { 61 public: 62 CoreAudioBufferList(AudioStreamBasicDescription const& streamFormat); 63 CoreAudioBufferList(AudioStreamBasicDescription const& streamFormat, char *buffer, int bufferSize); 64 CoreAudioBufferList(AudioStreamBasicDescription const& streamFormat, int framesToBuffer); 65 66 ~CoreAudioBufferList(); 67 audioBufferList()68 AudioBufferList* audioBufferList() const { return m_bufferList; } 69 char *data(int buffer = 0) const; 70 qint64 bufferSize(int buffer = 0) const; 71 int frameCount(int buffer = 0) const; 72 int packetCount(int buffer = 0) const; 73 int packetSize() const; 74 void reset(); 75 76 private: 77 bool m_owner; 78 int m_dataSize; 79 AudioStreamBasicDescription m_streamDescription; 80 AudioBufferList *m_bufferList; 81 }; 82 83 class CoreAudioPacketFeeder 84 { 85 public: 86 CoreAudioPacketFeeder(CoreAudioBufferList *abl); 87 88 bool feed(AudioBufferList& dst, UInt32& packetCount); 89 bool empty() const; 90 91 private: 92 UInt32 m_totalPackets; 93 UInt32 m_position; 94 CoreAudioBufferList *m_audioBufferList; 95 }; 96 97 class CoreAudioInputBuffer : public QObject 98 { 99 Q_OBJECT 100 101 public: 102 CoreAudioInputBuffer(int bufferSize, 103 int maxPeriodSize, 104 AudioStreamBasicDescription const& inputFormat, 105 AudioStreamBasicDescription const& outputFormat, 106 QObject *parent); 107 108 ~CoreAudioInputBuffer(); 109 110 qreal volume() const; 111 void setVolume(qreal v); 112 113 qint64 renderFromDevice(AudioUnit audioUnit, 114 AudioUnitRenderActionFlags *ioActionFlags, 115 const AudioTimeStamp *inTimeStamp, 116 UInt32 inBusNumber, 117 UInt32 inNumberFrames); 118 119 qint64 readBytes(char *data, qint64 len); 120 121 void setFlushDevice(QIODevice *device); 122 123 void startFlushTimer(); 124 void stopFlushTimer(); 125 126 void flush(bool all = false); 127 void reset(); 128 int available() const; 129 int used() const; 130 131 signals: 132 void readyRead(); 133 134 private slots: 135 void flushBuffer(); 136 137 private: 138 bool m_deviceError; 139 int m_maxPeriodSize; 140 int m_periodTime; 141 QIODevice *m_device; 142 QTimer *m_flushTimer; 143 CoreAudioRingBuffer *m_buffer; 144 CoreAudioBufferList *m_inputBufferList; 145 AudioConverterRef m_audioConverter; 146 AudioStreamBasicDescription m_inputFormat; 147 AudioStreamBasicDescription m_outputFormat; 148 QAudioFormat m_qFormat; 149 qreal m_volume; 150 151 const static OSStatus as_empty = 'qtem'; 152 153 // Converter callback 154 static OSStatus converterCallback(AudioConverterRef inAudioConverter, 155 UInt32 *ioNumberDataPackets, 156 AudioBufferList *ioData, 157 AudioStreamPacketDescription **outDataPacketDescription, 158 void *inUserData); 159 }; 160 161 class CoreAudioInputDevice : public QIODevice 162 { 163 Q_OBJECT 164 165 public: 166 CoreAudioInputDevice(CoreAudioInputBuffer *audioBuffer, QObject *parent); 167 168 qint64 readData(char *data, qint64 len); 169 qint64 writeData(const char *data, qint64 len); 170 isSequential()171 bool isSequential() const { return true; } 172 173 private: 174 CoreAudioInputBuffer *m_audioBuffer; 175 }; 176 177 class CoreAudioInput : public QAbstractAudioInput 178 { 179 Q_OBJECT 180 181 public: 182 CoreAudioInput(const QByteArray &device); 183 ~CoreAudioInput(); 184 185 void start(QIODevice *device); 186 QIODevice *start(); 187 void stop(); 188 void reset(); 189 void suspend(); 190 void resume(); 191 int bytesReady() const; 192 int periodSize() const; 193 void setBufferSize(int value); 194 int bufferSize() const; 195 void setNotifyInterval(int milliSeconds); 196 int notifyInterval() const; 197 qint64 processedUSecs() const; 198 qint64 elapsedUSecs() const; 199 QAudio::Error error() const; 200 QAudio::State state() const; 201 void setFormat(const QAudioFormat &format); 202 QAudioFormat format() const; 203 204 void setVolume(qreal volume); 205 qreal volume() const; 206 207 private slots: 208 void deviceStoppped(); 209 210 private: 211 enum { 212 Running, 213 Stopped 214 }; 215 216 bool open(); 217 void close(); 218 219 void audioThreadStart(); 220 void audioThreadStop(); 221 222 void audioDeviceStop(); 223 void audioDeviceActive(); 224 void audioDeviceFull(); 225 void audioDeviceError(); 226 227 void startTimers(); 228 void stopTimers(); 229 230 // Input callback 231 static OSStatus inputCallback(void *inRefCon, 232 AudioUnitRenderActionFlags *ioActionFlags, 233 const AudioTimeStamp *inTimeStamp, 234 UInt32 inBusNumber, 235 UInt32 inNumberFrames, 236 AudioBufferList *ioData); 237 238 QByteArray m_device; 239 bool m_isOpen; 240 int m_periodSizeBytes; 241 int m_internalBufferSize; 242 qint64 m_totalFrames; 243 QAudioFormat m_audioFormat; 244 QIODevice *m_audioIO; 245 AudioUnit m_audioUnit; 246 #if defined(Q_OS_OSX) 247 AudioDeviceID m_audioDeviceId; 248 #endif 249 Float64 m_clockFrequency; 250 UInt64 m_startTime; 251 QAudio::Error m_errorCode; 252 QAudio::State m_stateCode; 253 CoreAudioInputBuffer *m_audioBuffer; 254 QMutex m_mutex; 255 QWaitCondition m_threadFinished; 256 QAtomicInt m_audioThreadState; 257 QTimer *m_intervalTimer; 258 AudioStreamBasicDescription m_streamFormat; 259 AudioStreamBasicDescription m_deviceFormat; 260 QAbstractAudioDeviceInfo *m_audioDeviceInfo; 261 qreal m_volume; 262 }; 263 264 QT_END_NAMESPACE 265 266 #endif // IOSAUDIOINPUT_H 267