qtmobility/src/multimedia/audio/qaudioinput_mac_p.cpp
changeset 14 6fbed849b4f4
child 15 1f895d8a5b2b
equal deleted inserted replaced
11:06b8e2af4411 14:6fbed849b4f4
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the Qt Mobility Components.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 //
       
    43 //  W A R N I N G
       
    44 //  -------------
       
    45 //
       
    46 // This file is not part of the Qt API.  It exists for the convenience
       
    47 // of other Qt classes.  This header file may change from version to
       
    48 // version without notice, or even be removed.
       
    49 //
       
    50 // We mean it.
       
    51 //
       
    52 
       
    53 #include <QtCore/qendian.h>
       
    54 #include <QtCore/qtimer.h>
       
    55 #include <QtCore/qdebug.h>
       
    56 
       
    57 #include <qaudioinput.h>
       
    58 
       
    59 #include "qaudio_mac_p.h"
       
    60 #include "qaudioinput_mac_p.h"
       
    61 #include "qaudiodeviceinfo_mac_p.h"
       
    62 
       
    63 QT_BEGIN_NAMESPACE
       
    64 
       
    65 
       
    66 namespace QtMultimediaInternal
       
    67 {
       
    68 
       
    69 static const int default_buffer_size = 4 * 1024;
       
    70 
       
    71 class QAudioBufferList
       
    72 {
       
    73 public:
       
    74     QAudioBufferList(AudioStreamBasicDescription const& streamFormat):
       
    75         owner(false),
       
    76         sf(streamFormat)
       
    77     {
       
    78         const bool isInterleaved = (sf.mFormatFlags & kAudioFormatFlagIsNonInterleaved) == 0;
       
    79         const int numberOfBuffers = isInterleaved ? 1 : sf.mChannelsPerFrame;
       
    80 
       
    81         dataSize = 0;
       
    82 
       
    83         bfs = reinterpret_cast<AudioBufferList*>(qMalloc(sizeof(AudioBufferList) +
       
    84                                                                 (sizeof(AudioBuffer) * numberOfBuffers)));
       
    85 
       
    86         bfs->mNumberBuffers = numberOfBuffers;
       
    87         for (int i = 0; i < numberOfBuffers; ++i) {
       
    88             bfs->mBuffers[i].mNumberChannels = isInterleaved ? numberOfBuffers : 1;
       
    89             bfs->mBuffers[i].mDataByteSize = 0;
       
    90             bfs->mBuffers[i].mData = 0;
       
    91         }
       
    92     }
       
    93 
       
    94     QAudioBufferList(AudioStreamBasicDescription const& streamFormat, char* buffer, int bufferSize):
       
    95         owner(false),
       
    96         sf(streamFormat),
       
    97         bfs(0)
       
    98     {
       
    99         dataSize = bufferSize;
       
   100 
       
   101         bfs = reinterpret_cast<AudioBufferList*>(qMalloc(sizeof(AudioBufferList) + sizeof(AudioBuffer)));
       
   102 
       
   103         bfs->mNumberBuffers = 1;
       
   104         bfs->mBuffers[0].mNumberChannels = 1;
       
   105         bfs->mBuffers[0].mDataByteSize = dataSize;
       
   106         bfs->mBuffers[0].mData = buffer;
       
   107     }
       
   108 
       
   109     QAudioBufferList(AudioStreamBasicDescription const& streamFormat, int framesToBuffer):
       
   110         owner(true),
       
   111         sf(streamFormat),
       
   112         bfs(0)
       
   113     {
       
   114         const bool isInterleaved = (sf.mFormatFlags & kAudioFormatFlagIsNonInterleaved) == 0;
       
   115         const int numberOfBuffers = isInterleaved ? 1 : sf.mChannelsPerFrame;
       
   116 
       
   117         dataSize = framesToBuffer * sf.mBytesPerFrame;
       
   118 
       
   119         bfs = reinterpret_cast<AudioBufferList*>(qMalloc(sizeof(AudioBufferList) +
       
   120                                                                 (sizeof(AudioBuffer) * numberOfBuffers)));
       
   121         bfs->mNumberBuffers = numberOfBuffers;
       
   122         for (int i = 0; i < numberOfBuffers; ++i) {
       
   123             bfs->mBuffers[i].mNumberChannels = isInterleaved ? numberOfBuffers : 1;
       
   124             bfs->mBuffers[i].mDataByteSize = dataSize;
       
   125             bfs->mBuffers[i].mData = qMalloc(dataSize);
       
   126         }
       
   127     }
       
   128 
       
   129     ~QAudioBufferList()
       
   130     {
       
   131         if (owner) {
       
   132             for (UInt32 i = 0; i < bfs->mNumberBuffers; ++i)
       
   133                 qFree(bfs->mBuffers[i].mData);
       
   134         }
       
   135 
       
   136         qFree(bfs);
       
   137     }
       
   138 
       
   139     AudioBufferList* audioBufferList() const
       
   140     {
       
   141         return bfs;
       
   142     }
       
   143 
       
   144     char* data(int buffer = 0) const
       
   145     {
       
   146         return static_cast<char*>(bfs->mBuffers[buffer].mData);
       
   147     }
       
   148 
       
   149     qint64 bufferSize(int buffer = 0) const
       
   150     {
       
   151         return bfs->mBuffers[buffer].mDataByteSize;
       
   152     }
       
   153 
       
   154     int frameCount(int buffer = 0) const
       
   155     {
       
   156         return bfs->mBuffers[buffer].mDataByteSize / sf.mBytesPerFrame;
       
   157     }
       
   158 
       
   159     int packetCount(int buffer = 0) const
       
   160     {
       
   161         return bfs->mBuffers[buffer].mDataByteSize / sf.mBytesPerPacket;
       
   162     }
       
   163 
       
   164     int packetSize() const
       
   165     {
       
   166         return sf.mBytesPerPacket;
       
   167     }
       
   168 
       
   169     void reset()
       
   170     {
       
   171         for (UInt32 i = 0; i < bfs->mNumberBuffers; ++i) {
       
   172             bfs->mBuffers[i].mDataByteSize = dataSize;
       
   173             bfs->mBuffers[i].mData = 0;
       
   174         }
       
   175     }
       
   176 
       
   177 private:
       
   178     bool    owner;
       
   179     int     dataSize;
       
   180     AudioStreamBasicDescription sf;
       
   181     AudioBufferList* bfs;
       
   182 };
       
   183 
       
   184 class QAudioPacketFeeder
       
   185 {
       
   186 public:
       
   187     QAudioPacketFeeder(QAudioBufferList* abl):
       
   188         audioBufferList(abl)
       
   189     {
       
   190         totalPackets = audioBufferList->packetCount();
       
   191         position = 0;
       
   192     }
       
   193 
       
   194     bool feed(AudioBufferList& dst, UInt32& packetCount)
       
   195     {
       
   196         if (position == totalPackets) {
       
   197             dst.mBuffers[0].mDataByteSize = 0;
       
   198             packetCount = 0;
       
   199             return false;
       
   200         }
       
   201 
       
   202         if (totalPackets - position < packetCount)
       
   203             packetCount = totalPackets - position;
       
   204 
       
   205         dst.mBuffers[0].mDataByteSize = packetCount * audioBufferList->packetSize();
       
   206         dst.mBuffers[0].mData = audioBufferList->data() + (position * audioBufferList->packetSize());
       
   207 
       
   208         position += packetCount;
       
   209 
       
   210         return true;
       
   211     }
       
   212 
       
   213 private:
       
   214     UInt32 totalPackets;
       
   215     UInt32 position;
       
   216     QAudioBufferList*   audioBufferList;
       
   217 };
       
   218 
       
   219 class QAudioInputBuffer : public QObject
       
   220 {
       
   221     Q_OBJECT
       
   222 
       
   223 public:
       
   224     QAudioInputBuffer(int bufferSize,
       
   225                         int maxPeriodSize,
       
   226                         AudioStreamBasicDescription const& inputFormat,
       
   227                         AudioStreamBasicDescription const& outputFormat,
       
   228                         QObject* parent):
       
   229         QObject(parent),
       
   230         m_deviceError(false),
       
   231         m_audioConverter(0),
       
   232         m_inputFormat(inputFormat),
       
   233         m_outputFormat(outputFormat)
       
   234     {
       
   235         m_maxPeriodSize = maxPeriodSize;
       
   236         m_periodTime = m_maxPeriodSize / m_outputFormat.mBytesPerFrame * 1000 / m_outputFormat.mSampleRate;
       
   237         m_buffer = new QAudioRingBuffer(bufferSize + (bufferSize % maxPeriodSize == 0 ? 0 : maxPeriodSize - (bufferSize % maxPeriodSize)));
       
   238         m_inputBufferList = new QAudioBufferList(m_inputFormat);
       
   239 
       
   240         m_flushTimer = new QTimer(this);
       
   241         connect(m_flushTimer, SIGNAL(timeout()), SLOT(flushBuffer()));
       
   242 
       
   243         if (toQAudioFormat(inputFormat) != toQAudioFormat(outputFormat)) {
       
   244             if (AudioConverterNew(&m_inputFormat, &m_outputFormat, &m_audioConverter) != noErr) {
       
   245                 qWarning() << "QAudioInput: Unable to create an Audio Converter";
       
   246                 m_audioConverter = 0;
       
   247             }
       
   248         }
       
   249     }
       
   250 
       
   251     ~QAudioInputBuffer()
       
   252     {
       
   253         delete m_buffer;
       
   254     }
       
   255 
       
   256     qint64 renderFromDevice(AudioUnit audioUnit,
       
   257                              AudioUnitRenderActionFlags* ioActionFlags,
       
   258                              const AudioTimeStamp* inTimeStamp,
       
   259                              UInt32 inBusNumber,
       
   260                              UInt32 inNumberFrames)
       
   261     {
       
   262         const bool  wasEmpty = m_buffer->used() == 0;
       
   263 
       
   264         OSStatus    err;
       
   265         qint64      framesRendered = 0;
       
   266 
       
   267         m_inputBufferList->reset();
       
   268         err = AudioUnitRender(audioUnit,
       
   269                                 ioActionFlags,
       
   270                                 inTimeStamp,
       
   271                                 inBusNumber,
       
   272                                 inNumberFrames,
       
   273                                 m_inputBufferList->audioBufferList());
       
   274 
       
   275         if (m_audioConverter != 0) {
       
   276             QAudioPacketFeeder  feeder(m_inputBufferList);
       
   277 
       
   278             bool    wecan = true;
       
   279             int     copied = 0;
       
   280 
       
   281             const int available = m_buffer->free();
       
   282 
       
   283             while (err == noErr && wecan) {
       
   284                 QAudioRingBuffer::Region region = m_buffer->acquireWriteRegion(available);
       
   285 
       
   286                 if (region.second > 0) {
       
   287                     AudioBufferList     output;
       
   288                     output.mNumberBuffers = 1;
       
   289                     output.mBuffers[0].mNumberChannels = 1;
       
   290                     output.mBuffers[0].mDataByteSize = region.second;
       
   291                     output.mBuffers[0].mData = region.first;
       
   292 
       
   293                     UInt32  packetSize = region.second / m_outputFormat.mBytesPerPacket;
       
   294                     err = AudioConverterFillComplexBuffer(m_audioConverter,
       
   295                                                           converterCallback,
       
   296                                                           &feeder,
       
   297                                                           &packetSize,
       
   298                                                           &output,
       
   299                                                           0);
       
   300 
       
   301                     region.second = output.mBuffers[0].mDataByteSize;
       
   302                     copied += region.second;
       
   303 
       
   304                     m_buffer->releaseWriteRegion(region);
       
   305                 }
       
   306                 else
       
   307                     wecan = false;
       
   308             }
       
   309 
       
   310             framesRendered += copied / m_outputFormat.mBytesPerFrame;
       
   311         }
       
   312         else {
       
   313             const int available = m_inputBufferList->bufferSize();
       
   314             bool    wecan = true;
       
   315             int     copied = 0;
       
   316 
       
   317             while (wecan && copied < available) {
       
   318                 QAudioRingBuffer::Region region = m_buffer->acquireWriteRegion(available - copied);
       
   319 
       
   320                 if (region.second > 0) {
       
   321                     memcpy(region.first, m_inputBufferList->data() + copied, region.second);
       
   322                     copied += region.second;
       
   323                 }
       
   324                 else
       
   325                     wecan = false;
       
   326 
       
   327                 m_buffer->releaseWriteRegion(region);
       
   328             }
       
   329 
       
   330             framesRendered = copied / m_outputFormat.mBytesPerFrame;
       
   331         }
       
   332 
       
   333         if (wasEmpty && framesRendered > 0)
       
   334             emit readyRead();
       
   335 
       
   336         return framesRendered;
       
   337     }
       
   338 
       
   339     qint64 readBytes(char* data, qint64 len)
       
   340     {
       
   341         bool    wecan = true;
       
   342         qint64  bytesCopied = 0;
       
   343 
       
   344         len -= len % m_maxPeriodSize;
       
   345         while (wecan && bytesCopied < len) {
       
   346             QAudioRingBuffer::Region region = m_buffer->acquireReadRegion(len - bytesCopied);
       
   347 
       
   348             if (region.second > 0) {
       
   349                 memcpy(data + bytesCopied, region.first, region.second);
       
   350                 bytesCopied += region.second;
       
   351             }
       
   352             else
       
   353                 wecan = false;
       
   354 
       
   355             m_buffer->releaseReadRegion(region);
       
   356         }
       
   357 
       
   358         return bytesCopied;
       
   359     }
       
   360 
       
   361     void setFlushDevice(QIODevice* device)
       
   362     {
       
   363         if (m_device != device)
       
   364             m_device = device;
       
   365     }
       
   366 
       
   367     void startFlushTimer()
       
   368     {
       
   369         if (m_device != 0) {
       
   370             m_flushTimer->start((m_buffer->size() - (m_maxPeriodSize * 2)) / m_maxPeriodSize * m_periodTime);
       
   371         }
       
   372     }
       
   373 
       
   374     void stopFlushTimer()
       
   375     {
       
   376         m_flushTimer->stop();
       
   377     }
       
   378 
       
   379     void flush(bool all = false)
       
   380     {
       
   381         if (m_device == 0)
       
   382             return;
       
   383 
       
   384         const int used = m_buffer->used();
       
   385         const int readSize = all ? used : used - (used % m_maxPeriodSize);
       
   386 
       
   387         if (readSize > 0) {
       
   388             bool    wecan = true;
       
   389             int     flushed = 0;
       
   390 
       
   391             while (!m_deviceError && wecan && flushed < readSize) {
       
   392                 QAudioRingBuffer::Region region = m_buffer->acquireReadRegion(readSize - flushed);
       
   393 
       
   394                 if (region.second > 0) {
       
   395                     int bytesWritten = m_device->write(region.first, region.second);
       
   396                     if (bytesWritten < 0) {
       
   397                         stopFlushTimer();
       
   398                         m_deviceError = true;
       
   399                     }
       
   400                     else {
       
   401                         region.second = bytesWritten;
       
   402                         flushed += bytesWritten;
       
   403                         wecan = bytesWritten != 0;
       
   404                     }
       
   405                 }
       
   406                 else
       
   407                     wecan = false;
       
   408 
       
   409                 m_buffer->releaseReadRegion(region);
       
   410             }
       
   411         }
       
   412     }
       
   413 
       
   414     void reset()
       
   415     {
       
   416         m_buffer->reset();
       
   417         m_deviceError = false;
       
   418     }
       
   419 
       
   420     int available() const
       
   421     {
       
   422         return m_buffer->free();
       
   423     }
       
   424 
       
   425     int used() const
       
   426     {
       
   427         return m_buffer->used();
       
   428     }
       
   429 
       
   430 signals:
       
   431     void readyRead();
       
   432 
       
   433 private slots:
       
   434     void flushBuffer()
       
   435     {
       
   436         flush();
       
   437     }
       
   438 
       
   439 private:
       
   440     bool        m_deviceError;
       
   441     int         m_maxPeriodSize;
       
   442     int         m_periodTime;
       
   443     QIODevice*  m_device;
       
   444     QTimer*     m_flushTimer;
       
   445     QAudioRingBuffer*   m_buffer;
       
   446     QAudioBufferList*   m_inputBufferList;
       
   447     AudioConverterRef   m_audioConverter;
       
   448     AudioStreamBasicDescription m_inputFormat;
       
   449     AudioStreamBasicDescription m_outputFormat;
       
   450 
       
   451     const static OSStatus as_empty = 'qtem';
       
   452 
       
   453     // Converter callback
       
   454     static OSStatus converterCallback(AudioConverterRef inAudioConverter,
       
   455                                 UInt32* ioNumberDataPackets,
       
   456                                 AudioBufferList* ioData,
       
   457                                 AudioStreamPacketDescription** outDataPacketDescription,
       
   458                                 void* inUserData)
       
   459     {
       
   460         Q_UNUSED(inAudioConverter);
       
   461         Q_UNUSED(outDataPacketDescription);
       
   462 
       
   463         QAudioPacketFeeder* feeder = static_cast<QAudioPacketFeeder*>(inUserData);
       
   464 
       
   465         if (!feeder->feed(*ioData, *ioNumberDataPackets))
       
   466             return as_empty;
       
   467 
       
   468         return noErr;
       
   469     }
       
   470 };
       
   471 
       
   472 
       
   473 class MacInputDevice : public QIODevice
       
   474 {
       
   475     Q_OBJECT
       
   476 
       
   477 public:
       
   478     MacInputDevice(QAudioInputBuffer* audioBuffer, QObject* parent):
       
   479         QIODevice(parent),
       
   480         m_audioBuffer(audioBuffer)
       
   481     {
       
   482         open(QIODevice::ReadOnly | QIODevice::Unbuffered);
       
   483         connect(m_audioBuffer, SIGNAL(readyRead()), SIGNAL(readyRead()));
       
   484     }
       
   485 
       
   486     qint64 readData(char* data, qint64 len)
       
   487     {
       
   488         return m_audioBuffer->readBytes(data, len);
       
   489     }
       
   490 
       
   491     qint64 writeData(const char* data, qint64 len)
       
   492     {
       
   493         Q_UNUSED(data);
       
   494         Q_UNUSED(len);
       
   495 
       
   496         return 0;
       
   497     }
       
   498 
       
   499     bool isSequential() const
       
   500     {
       
   501         return true;
       
   502     }
       
   503 
       
   504 private:
       
   505     QAudioInputBuffer*   m_audioBuffer;
       
   506 };
       
   507 
       
   508 }
       
   509 
       
   510 
       
   511 QAudioInputPrivate::QAudioInputPrivate(const QByteArray& device)
       
   512 {
       
   513     QDataStream ds(device);
       
   514     quint32 did, mode;
       
   515 
       
   516     ds >> did >> mode;
       
   517 
       
   518     if (QAudio::Mode(mode) == QAudio::AudioOutput)
       
   519         errorCode = QAudio::OpenError;
       
   520     else {
       
   521         audioDeviceInfo = new QAudioDeviceInfoInternal(device, QAudio::AudioInput);
       
   522         isOpen = false;
       
   523         audioDeviceId = AudioDeviceID(did);
       
   524         audioUnit = 0;
       
   525         startTime = 0;
       
   526         totalFrames = 0;
       
   527         audioBuffer = 0;
       
   528         internalBufferSize = QtMultimediaInternal::default_buffer_size;
       
   529         clockFrequency = AudioGetHostClockFrequency() / 1000;
       
   530         errorCode = QAudio::NoError;
       
   531         stateCode = QAudio::StoppedState;
       
   532 
       
   533         intervalTimer = new QTimer(this);
       
   534         intervalTimer->setInterval(1000);
       
   535         connect(intervalTimer, SIGNAL(timeout()), SIGNAL(notify()));
       
   536     }
       
   537 }
       
   538 
       
   539 QAudioInputPrivate::~QAudioInputPrivate()
       
   540 {
       
   541     close();
       
   542     delete audioDeviceInfo;
       
   543 }
       
   544 
       
   545 bool QAudioInputPrivate::open()
       
   546 {
       
   547     UInt32  size = 0;
       
   548 
       
   549     if (isOpen)
       
   550         return true;
       
   551 
       
   552     ComponentDescription    cd;
       
   553     cd.componentType = kAudioUnitType_Output;
       
   554     cd.componentSubType = kAudioUnitSubType_HALOutput;
       
   555     cd.componentManufacturer = kAudioUnitManufacturer_Apple;
       
   556     cd.componentFlags = 0;
       
   557     cd.componentFlagsMask = 0;
       
   558 
       
   559     // Open
       
   560     Component cp = FindNextComponent(NULL, &cd);
       
   561     if (cp == 0) {
       
   562         qWarning() << "QAudioInput: Failed to find HAL Output component";
       
   563         return false;
       
   564     }
       
   565 
       
   566     if (OpenAComponent(cp, &audioUnit) != noErr) {
       
   567         qWarning() << "QAudioInput: Unable to Open Output Component";
       
   568         return false;
       
   569     }
       
   570 
       
   571     // Set mode
       
   572     // switch to input mode
       
   573     UInt32 enable = 1;
       
   574     if (AudioUnitSetProperty(audioUnit,
       
   575                                kAudioOutputUnitProperty_EnableIO,
       
   576                                kAudioUnitScope_Input,
       
   577                                1,
       
   578                                &enable,
       
   579                                sizeof(enable)) != noErr) {
       
   580         qWarning() << "QAudioInput: Unable to switch to input mode (Enable Input)";
       
   581         return false;
       
   582     }
       
   583 
       
   584     enable = 0;
       
   585     if (AudioUnitSetProperty(audioUnit,
       
   586                             kAudioOutputUnitProperty_EnableIO,
       
   587                             kAudioUnitScope_Output,
       
   588                             0,
       
   589                             &enable,
       
   590                             sizeof(enable)) != noErr) {
       
   591         qWarning() << "QAudioInput: Unable to switch to input mode (Disable output)";
       
   592         return false;
       
   593     }
       
   594 
       
   595     // register callback
       
   596     AURenderCallbackStruct cb;
       
   597     cb.inputProc = inputCallback;
       
   598     cb.inputProcRefCon = this;
       
   599 
       
   600     if (AudioUnitSetProperty(audioUnit,
       
   601                                kAudioOutputUnitProperty_SetInputCallback,
       
   602                                kAudioUnitScope_Global,
       
   603                                0,
       
   604                                &cb,
       
   605                                sizeof(cb)) != noErr) {
       
   606         qWarning() << "QAudioInput: Failed to set AudioUnit callback";
       
   607         return false;
       
   608     }
       
   609 
       
   610     // Set Audio Device
       
   611     if (AudioUnitSetProperty(audioUnit,
       
   612                                 kAudioOutputUnitProperty_CurrentDevice,
       
   613                                 kAudioUnitScope_Global,
       
   614                                 0,
       
   615                                 &audioDeviceId,
       
   616                                 sizeof(audioDeviceId)) != noErr) {
       
   617         qWarning() << "QAudioInput: Unable to use configured device";
       
   618         return false;
       
   619     }
       
   620 
       
   621     // Set format
       
   622     // Wanted
       
   623     streamFormat = toAudioStreamBasicDescription(audioFormat);
       
   624 
       
   625     // Required on unit
       
   626     if (audioFormat == audioDeviceInfo->preferredFormat()) {
       
   627         deviceFormat = streamFormat;
       
   628         AudioUnitSetProperty(audioUnit,
       
   629                                kAudioUnitProperty_StreamFormat,
       
   630                                kAudioUnitScope_Output,
       
   631                                1,
       
   632                                &deviceFormat,
       
   633                                sizeof(deviceFormat));
       
   634     }
       
   635     else {
       
   636         size = sizeof(deviceFormat);
       
   637         if (AudioUnitGetProperty(audioUnit,
       
   638                                     kAudioUnitProperty_StreamFormat,
       
   639                                     kAudioUnitScope_Input,
       
   640                                     1,
       
   641                                     &deviceFormat,
       
   642                                     &size) != noErr) {
       
   643             qWarning() << "QAudioInput: Unable to retrieve device format";
       
   644             return false;
       
   645         }
       
   646 
       
   647         if (AudioUnitSetProperty(audioUnit,
       
   648                                    kAudioUnitProperty_StreamFormat,
       
   649                                    kAudioUnitScope_Output,
       
   650                                    1,
       
   651                                    &deviceFormat,
       
   652                                    sizeof(deviceFormat)) != noErr) {
       
   653             qWarning() << "QAudioInput: Unable to set device format";
       
   654             return false;
       
   655         }
       
   656     }
       
   657 
       
   658     // Setup buffers
       
   659     UInt32 numberOfFrames;
       
   660     size = sizeof(UInt32);
       
   661     if (AudioUnitGetProperty(audioUnit,
       
   662                                 kAudioDevicePropertyBufferFrameSize,
       
   663                                 kAudioUnitScope_Global,
       
   664                                 0,
       
   665                                 &numberOfFrames,
       
   666                                 &size) != noErr) {
       
   667         qWarning() << "QAudioInput: Failed to get audio period size";
       
   668         return false;
       
   669     }
       
   670 
       
   671     // Allocate buffer
       
   672     periodSizeBytes = numberOfFrames * streamFormat.mBytesPerFrame;
       
   673 
       
   674     if (internalBufferSize < periodSizeBytes * 2)
       
   675         internalBufferSize = periodSizeBytes * 2;
       
   676     else
       
   677         internalBufferSize -= internalBufferSize % streamFormat.mBytesPerFrame;
       
   678 
       
   679     audioBuffer = new QtMultimediaInternal::QAudioInputBuffer(internalBufferSize,
       
   680                                         periodSizeBytes,
       
   681                                         deviceFormat,
       
   682                                         streamFormat,
       
   683                                         this);
       
   684 
       
   685     audioIO = new QtMultimediaInternal::MacInputDevice(audioBuffer, this);
       
   686 
       
   687     // Init
       
   688     if (AudioUnitInitialize(audioUnit) != noErr) {
       
   689         qWarning() << "QAudioInput: Failed to initialize AudioUnit";
       
   690         return false;
       
   691     }
       
   692 
       
   693     isOpen = true;
       
   694 
       
   695     return isOpen;
       
   696 }
       
   697 
       
   698 void QAudioInputPrivate::close()
       
   699 {
       
   700     if (audioUnit != 0) {
       
   701         AudioOutputUnitStop(audioUnit);
       
   702         AudioUnitUninitialize(audioUnit);
       
   703         CloseComponent(audioUnit);
       
   704     }
       
   705 
       
   706     delete audioBuffer;
       
   707 }
       
   708 
       
   709 QAudioFormat QAudioInputPrivate::format() const
       
   710 {
       
   711     return audioFormat;
       
   712 }
       
   713 
       
   714 void QAudioInputPrivate::setFormat(const QAudioFormat& fmt)
       
   715 {
       
   716     if (stateCode == QAudio::StoppedState)
       
   717         audioFormat = fmt;
       
   718 }
       
   719 
       
   720 void QAudioInputPrivate::start(QIODevice* device)
       
   721 {
       
   722     QIODevice*  op = device;
       
   723 
       
   724     if (!audioFormat.isValid() || !open()) {
       
   725         stateCode = QAudio::StoppedState;
       
   726         errorCode = QAudio::OpenError;
       
   727         return;
       
   728     }
       
   729 
       
   730     reset();
       
   731     audioBuffer->reset();
       
   732     audioBuffer->setFlushDevice(op);
       
   733 
       
   734     if (op == 0)
       
   735         op = audioIO;
       
   736 
       
   737     // Start
       
   738     startTime = AudioGetCurrentHostTime();
       
   739     totalFrames = 0;
       
   740 
       
   741     audioThreadStart();
       
   742 
       
   743     stateCode = QAudio::ActiveState;
       
   744     errorCode = QAudio::NoError;
       
   745     emit stateChanged(stateCode);
       
   746 }
       
   747 
       
   748 QIODevice* QAudioInputPrivate::start()
       
   749 {
       
   750     QIODevice*  op = 0;
       
   751 
       
   752     if (!audioFormat.isValid() || !open()) {
       
   753         stateCode = QAudio::StoppedState;
       
   754         errorCode = QAudio::OpenError;
       
   755         return audioIO;
       
   756     }
       
   757 
       
   758     reset();
       
   759     audioBuffer->reset();
       
   760     audioBuffer->setFlushDevice(op);
       
   761 
       
   762     if (op == 0)
       
   763         op = audioIO;
       
   764 
       
   765     // Start
       
   766     startTime = AudioGetCurrentHostTime();
       
   767     totalFrames = 0;
       
   768 
       
   769     audioThreadStart();
       
   770 
       
   771     stateCode = QAudio::ActiveState;
       
   772     errorCode = QAudio::NoError;
       
   773     emit stateChanged(stateCode);
       
   774 
       
   775     return op;
       
   776 }
       
   777 
       
   778 void QAudioInputPrivate::stop()
       
   779 {
       
   780     QMutexLocker    lock(&mutex);
       
   781     if (stateCode != QAudio::StoppedState) {
       
   782         audioThreadStop();
       
   783         audioBuffer->flush(true);
       
   784 
       
   785         errorCode = QAudio::NoError;
       
   786         stateCode = QAudio::StoppedState;
       
   787         QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, Q_ARG(QAudio::State, stateCode));
       
   788     }
       
   789 }
       
   790 
       
   791 void QAudioInputPrivate::reset()
       
   792 {
       
   793     QMutexLocker    lock(&mutex);
       
   794     if (stateCode != QAudio::StoppedState) {
       
   795         audioThreadStop();
       
   796 
       
   797         errorCode = QAudio::NoError;
       
   798         stateCode = QAudio::StoppedState;
       
   799         QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, Q_ARG(QAudio::State, stateCode));
       
   800     }
       
   801 }
       
   802 
       
   803 void QAudioInputPrivate::suspend()
       
   804 {
       
   805     QMutexLocker    lock(&mutex);
       
   806     if (stateCode == QAudio::ActiveState || stateCode == QAudio::IdleState) {
       
   807         audioThreadStop();
       
   808 
       
   809         errorCode = QAudio::NoError;
       
   810         stateCode = QAudio::SuspendedState;
       
   811         QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, Q_ARG(QAudio::State, stateCode));
       
   812     }
       
   813 }
       
   814 
       
   815 void QAudioInputPrivate::resume()
       
   816 {
       
   817     QMutexLocker    lock(&mutex);
       
   818     if (stateCode == QAudio::SuspendedState) {
       
   819         audioThreadStart();
       
   820 
       
   821         errorCode = QAudio::NoError;
       
   822         stateCode = QAudio::ActiveState;
       
   823         QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, Q_ARG(QAudio::State, stateCode));
       
   824     }
       
   825 }
       
   826 
       
   827 int QAudioInputPrivate::bytesReady() const
       
   828 {
       
   829     return audioBuffer->used();
       
   830 }
       
   831 
       
   832 int QAudioInputPrivate::periodSize() const
       
   833 {
       
   834     return periodSizeBytes;
       
   835 }
       
   836 
       
   837 void QAudioInputPrivate::setBufferSize(int bs)
       
   838 {
       
   839     internalBufferSize = bs;
       
   840 }
       
   841 
       
   842 int QAudioInputPrivate::bufferSize() const
       
   843 {
       
   844     return internalBufferSize;
       
   845 }
       
   846 
       
   847 void QAudioInputPrivate::setNotifyInterval(int milliSeconds)
       
   848 {
       
   849     if (intervalTimer->interval() == milliSeconds)
       
   850         return;
       
   851 
       
   852     if (milliSeconds <= 0)
       
   853         milliSeconds = 0;
       
   854 
       
   855     intervalTimer->setInterval(milliSeconds);
       
   856 }
       
   857 
       
   858 int QAudioInputPrivate::notifyInterval() const
       
   859 {
       
   860     return intervalTimer->interval();
       
   861 }
       
   862 
       
   863 qint64 QAudioInputPrivate::processedUSecs() const
       
   864 {
       
   865     return totalFrames * 1000000 / audioFormat.frequency();
       
   866 }
       
   867 
       
   868 qint64 QAudioInputPrivate::elapsedUSecs() const
       
   869 {
       
   870     if (stateCode == QAudio::StoppedState)
       
   871         return 0;
       
   872 
       
   873     return (AudioGetCurrentHostTime() - startTime) / (clockFrequency / 1000);
       
   874 }
       
   875 
       
   876 QAudio::Error QAudioInputPrivate::error() const
       
   877 {
       
   878     return errorCode;
       
   879 }
       
   880 
       
   881 QAudio::State QAudioInputPrivate::state() const
       
   882 {
       
   883     return stateCode;
       
   884 }
       
   885 
       
   886 void QAudioInputPrivate::audioThreadStop()
       
   887 {
       
   888     stopTimers();
       
   889     if (audioThreadState.testAndSetAcquire(Running, Stopped))
       
   890         threadFinished.wait(&mutex);
       
   891 }
       
   892 
       
   893 void QAudioInputPrivate::audioThreadStart()
       
   894 {
       
   895     startTimers();
       
   896     audioThreadState = Running;
       
   897     AudioOutputUnitStart(audioUnit);
       
   898 }
       
   899 
       
   900 void QAudioInputPrivate::audioDeviceStop()
       
   901 {
       
   902     AudioOutputUnitStop(audioUnit);
       
   903     audioThreadState = Stopped;
       
   904     threadFinished.wakeOne();
       
   905 }
       
   906 
       
   907 void QAudioInputPrivate::audioDeviceFull()
       
   908 {
       
   909     QMutexLocker    lock(&mutex);
       
   910     if (stateCode == QAudio::ActiveState) {
       
   911         audioDeviceStop();
       
   912 
       
   913         errorCode = QAudio::UnderrunError;
       
   914         stateCode = QAudio::IdleState;
       
   915         QMetaObject::invokeMethod(this, "deviceStopped", Qt::QueuedConnection);
       
   916     }
       
   917 }
       
   918 
       
   919 void QAudioInputPrivate::audioDeviceError()
       
   920 {
       
   921     QMutexLocker    lock(&mutex);
       
   922     if (stateCode == QAudio::ActiveState) {
       
   923         audioDeviceStop();
       
   924 
       
   925         errorCode = QAudio::IOError;
       
   926         stateCode = QAudio::StoppedState;
       
   927         QMetaObject::invokeMethod(this, "deviceStopped", Qt::QueuedConnection);
       
   928     }
       
   929 }
       
   930 
       
   931 void QAudioInputPrivate::startTimers()
       
   932 {
       
   933     audioBuffer->startFlushTimer();
       
   934     if (intervalTimer->interval() > 0)
       
   935         intervalTimer->start();
       
   936 }
       
   937 
       
   938 void QAudioInputPrivate::stopTimers()
       
   939 {
       
   940     audioBuffer->stopFlushTimer();
       
   941     intervalTimer->stop();
       
   942 }
       
   943 
       
   944 void QAudioInputPrivate::deviceStopped()
       
   945 {
       
   946     stopTimers();
       
   947     emit stateChanged(stateCode);
       
   948 }
       
   949 
       
   950 // Input callback
       
   951 OSStatus QAudioInputPrivate::inputCallback(void* inRefCon,
       
   952                                 AudioUnitRenderActionFlags* ioActionFlags,
       
   953                                 const AudioTimeStamp* inTimeStamp,
       
   954                                 UInt32 inBusNumber,
       
   955                                 UInt32 inNumberFrames,
       
   956                                 AudioBufferList* ioData)
       
   957 {
       
   958     Q_UNUSED(ioData);
       
   959 
       
   960     QAudioInputPrivate* d = static_cast<QAudioInputPrivate*>(inRefCon);
       
   961 
       
   962     const int threadState = d->audioThreadState.fetchAndAddAcquire(0);
       
   963     if (threadState == Stopped)
       
   964         d->audioDeviceStop();
       
   965     else {
       
   966         qint64      framesWritten;
       
   967 
       
   968         framesWritten = d->audioBuffer->renderFromDevice(d->audioUnit,
       
   969                                                          ioActionFlags,
       
   970                                                          inTimeStamp,
       
   971                                                          inBusNumber,
       
   972                                                          inNumberFrames);
       
   973 
       
   974         if (framesWritten > 0)
       
   975             d->totalFrames += framesWritten;
       
   976         else if (framesWritten == 0)
       
   977             d->audioDeviceFull();
       
   978         else if (framesWritten < 0)
       
   979             d->audioDeviceError();
       
   980     }
       
   981 
       
   982     return noErr;
       
   983 }
       
   984 
       
   985 
       
   986 QT_END_NAMESPACE
       
   987 
       
   988 #include "qaudioinput_mac_p.moc"
       
   989