53 #include <QtCore/qendian.h> 54 #include <QtCore/qtimer.h> 55 #include <QtCore/qdebug.h> 57 #include <QtMultimedia/qaudioinput.h> 78 const bool isInterleaved = (
sf.mFormatFlags & kAudioFormatFlagIsNonInterleaved) == 0;
79 const int numberOfBuffers = isInterleaved ? 1 :
sf.mChannelsPerFrame;
83 bfs =
reinterpret_cast<AudioBufferList*
>(
qMalloc(
sizeof(AudioBufferList) +
84 (
sizeof(AudioBuffer) * numberOfBuffers)));
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;
101 bfs =
reinterpret_cast<AudioBufferList*
>(
qMalloc(
sizeof(AudioBufferList) +
sizeof(AudioBuffer)));
103 bfs->mNumberBuffers = 1;
104 bfs->mBuffers[0].mNumberChannels = 1;
106 bfs->mBuffers[0].mData = buffer;
114 const bool isInterleaved = (
sf.mFormatFlags & kAudioFormatFlagIsNonInterleaved) == 0;
115 const int numberOfBuffers = isInterleaved ? 1 :
sf.mChannelsPerFrame;
117 dataSize = framesToBuffer *
sf.mBytesPerFrame;
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;
132 for (UInt32 i = 0; i <
bfs->mNumberBuffers; ++i)
144 char*
data(
int buffer = 0)
const 146 return static_cast<char*
>(
bfs->mBuffers[buffer].mData);
151 return bfs->mBuffers[buffer].mDataByteSize;
156 return bfs->mBuffers[buffer].mDataByteSize /
sf.mBytesPerFrame;
161 return bfs->mBuffers[buffer].mDataByteSize /
sf.mBytesPerPacket;
166 return sf.mBytesPerPacket;
171 for (UInt32 i = 0; i <
bfs->mNumberBuffers; ++i) {
173 bfs->mBuffers[i].mData = 0;
180 AudioStreamBasicDescription
sf;
197 dst.mBuffers[0].mDataByteSize = 0;
202 if (totalPackets -
position < packetCount)
203 packetCount = totalPackets -
position;
205 dst.mBuffers[0].mDataByteSize = packetCount *
audioBufferList->packetSize();
231 AudioStreamBasicDescription
const& inputFormat,
232 AudioStreamBasicDescription
const& outputFormat,
235 m_deviceError(false),
237 m_inputFormat(inputFormat),
238 m_outputFormat(outputFormat)
240 m_maxPeriodSize = maxPeriodSize;
241 m_periodTime = m_maxPeriodSize / m_outputFormat.mBytesPerFrame * 1000 / m_outputFormat.mSampleRate;
242 m_buffer =
new QAudioRingBuffer(bufferSize + (bufferSize % maxPeriodSize == 0 ? 0 : maxPeriodSize - (bufferSize % maxPeriodSize)));
245 m_flushTimer =
new QTimer(
this);
246 connect(m_flushTimer,
SIGNAL(timeout()),
SLOT(flushBuffer()));
249 if (AudioConverterNew(&m_inputFormat, &m_outputFormat, &m_audioConverter) != noErr) {
250 qWarning() <<
"QAudioInput: Unable to create an Audio Converter";
251 m_audioConverter = 0;
262 AudioUnitRenderActionFlags* ioActionFlags,
263 const AudioTimeStamp* inTimeStamp,
265 UInt32 inNumberFrames)
267 const bool pullMode = m_device == 0;
270 qint64 framesRendered = 0;
272 m_inputBufferList->reset();
273 err = AudioUnitRender(audioUnit,
278 m_inputBufferList->audioBufferList());
280 if (m_audioConverter != 0) {
284 const int available = m_buffer->free();
286 while (err == noErr && !feeder.
empty()) {
292 AudioBufferList output;
293 output.mNumberBuffers = 1;
294 output.mBuffers[0].mNumberChannels = 1;
295 output.mBuffers[0].mDataByteSize = region.
second;
296 output.mBuffers[0].mData = region.
first;
299 err = AudioConverterFillComplexBuffer(m_audioConverter,
305 region.
second = output.mBuffers[0].mDataByteSize;
308 m_buffer->releaseWriteRegion(region);
311 framesRendered += copied / m_outputFormat.mBytesPerFrame;
314 const int available = m_inputBufferList->bufferSize();
318 while (wecan && copied < available) {
322 memcpy(region.
first, m_inputBufferList->data() + copied, region.
second);
328 m_buffer->releaseWriteRegion(region);
331 framesRendered = copied / m_outputFormat.mBytesPerFrame;
334 if (pullMode && framesRendered > 0)
337 return framesRendered;
345 len -= len % m_maxPeriodSize;
346 while (wecan && bytesCopied < len) {
350 memcpy(data + bytesCopied, region.
first, region.
second);
351 bytesCopied += region.
second;
356 m_buffer->releaseReadRegion(region);
364 if (m_device != device)
371 m_flushTimer->start((m_buffer->size() - (m_maxPeriodSize * 2)) / m_maxPeriodSize * m_periodTime);
377 m_flushTimer->stop();
385 const int used = m_buffer->used();
386 const int readSize =
all ? used : used - (used % m_maxPeriodSize);
392 while (!m_deviceError && wecan && flushed < readSize) {
396 int bytesWritten = m_device->write(region.
first, region.
second);
397 if (bytesWritten < 0) {
399 m_deviceError =
true;
402 region.
second = bytesWritten;
403 flushed += bytesWritten;
404 wecan = bytesWritten != 0;
410 m_buffer->releaseReadRegion(region);
418 m_deviceError =
false;
423 return m_buffer->free();
428 return m_buffer->used();
456 UInt32* ioNumberDataPackets,
457 AudioBufferList* ioData,
458 AudioStreamPacketDescription** outDataPacketDescription,
466 if (!feeder->
feed(*ioData, *ioNumberDataPackets))
481 m_audioBuffer(audioBuffer)
484 connect(m_audioBuffer,
SIGNAL(readyRead()),
SIGNAL(readyRead()));
489 return m_audioBuffer->readBytes(data, len);
525 audioDeviceId = AudioDeviceID(did);
531 clockFrequency = AudioGetHostClockFrequency() / 1000;
535 intervalTimer =
new QTimer(
this);
536 intervalTimer->setInterval(1000);
544 delete audioDeviceInfo;
554 ComponentDescription cd;
555 cd.componentType = kAudioUnitType_Output;
556 cd.componentSubType = kAudioUnitSubType_HALOutput;
557 cd.componentManufacturer = kAudioUnitManufacturer_Apple;
558 cd.componentFlags = 0;
559 cd.componentFlagsMask = 0;
562 Component cp = FindNextComponent(NULL, &cd);
564 qWarning() <<
"QAudioInput: Failed to find HAL Output component";
568 if (OpenAComponent(cp, &audioUnit) != noErr) {
569 qWarning() <<
"QAudioInput: Unable to Open Output Component";
576 if (AudioUnitSetProperty(audioUnit,
577 kAudioOutputUnitProperty_EnableIO,
578 kAudioUnitScope_Input,
581 sizeof(enable)) != noErr) {
582 qWarning() <<
"QAudioInput: Unable to switch to input mode (Enable Input)";
587 if (AudioUnitSetProperty(audioUnit,
588 kAudioOutputUnitProperty_EnableIO,
589 kAudioUnitScope_Output,
592 sizeof(enable)) != noErr) {
593 qWarning() <<
"QAudioInput: Unable to switch to input mode (Disable output)";
598 AURenderCallbackStruct cb;
599 cb.inputProc = inputCallback;
600 cb.inputProcRefCon =
this;
602 if (AudioUnitSetProperty(audioUnit,
603 kAudioOutputUnitProperty_SetInputCallback,
604 kAudioUnitScope_Global,
607 sizeof(cb)) != noErr) {
608 qWarning() <<
"QAudioInput: Failed to set AudioUnit callback";
613 if (AudioUnitSetProperty(audioUnit,
614 kAudioOutputUnitProperty_CurrentDevice,
615 kAudioUnitScope_Global,
618 sizeof(audioDeviceId)) != noErr) {
619 qWarning() <<
"QAudioInput: Unable to use configured device";
628 if (audioFormat == audioDeviceInfo->preferredFormat()) {
629 deviceFormat = streamFormat;
630 AudioUnitSetProperty(audioUnit,
631 kAudioUnitProperty_StreamFormat,
632 kAudioUnitScope_Output,
635 sizeof(deviceFormat));
638 size =
sizeof(deviceFormat);
639 if (AudioUnitGetProperty(audioUnit,
640 kAudioUnitProperty_StreamFormat,
641 kAudioUnitScope_Input,
645 qWarning() <<
"QAudioInput: Unable to retrieve device format";
649 if (AudioUnitSetProperty(audioUnit,
650 kAudioUnitProperty_StreamFormat,
651 kAudioUnitScope_Output,
654 sizeof(deviceFormat)) != noErr) {
655 qWarning() <<
"QAudioInput: Unable to set device format";
661 UInt32 numberOfFrames;
662 size =
sizeof(UInt32);
663 if (AudioUnitGetProperty(audioUnit,
664 kAudioDevicePropertyBufferFrameSize,
665 kAudioUnitScope_Global,
669 qWarning() <<
"QAudioInput: Failed to get audio period size";
674 periodSizeBytes = numberOfFrames * streamFormat.mBytesPerFrame;
676 if (internalBufferSize < periodSizeBytes * 2)
677 internalBufferSize = periodSizeBytes * 2;
679 internalBufferSize -= internalBufferSize % streamFormat.mBytesPerFrame;
690 if (AudioUnitInitialize(audioUnit) != noErr) {
691 qWarning() <<
"QAudioInput: Failed to initialize AudioUnit";
702 if (audioUnit != 0) {
703 AudioOutputUnitStop(audioUnit);
704 AudioUnitUninitialize(audioUnit);
705 CloseComponent(audioUnit);
720 if (!audioDeviceInfo->isFormatSupported(audioFormat) || !
open()) {
727 audioBuffer->reset();
728 audioBuffer->setFlushDevice(op);
734 startTime = AudioGetCurrentHostTime();
741 emit stateChanged(stateCode);
751 audioBuffer->flush(
true);
797 return audioBuffer->used();
802 return periodSizeBytes;
807 internalBufferSize = bs;
812 return internalBufferSize;
817 if (intervalTimer->interval() == milliSeconds)
820 if (milliSeconds <= 0)
823 intervalTimer->setInterval(milliSeconds);
828 return intervalTimer->interval();
833 return totalFrames * 1000000 / audioFormat.frequency();
841 return (AudioGetCurrentHostTime() - startTime) / (clockFrequency / 1000);
857 if (audioThreadState.testAndSetAcquire(Running, Stopped))
858 threadFinished.wait(&mutex);
864 audioThreadState = Running;
865 AudioOutputUnitStart(audioUnit);
870 AudioOutputUnitStop(audioUnit);
871 audioThreadState = Stopped;
872 threadFinished.wakeOne();
901 audioBuffer->startFlushTimer();
902 if (intervalTimer->interval() > 0)
903 intervalTimer->start();
908 audioBuffer->stopFlushTimer();
909 intervalTimer->stop();
915 emit stateChanged(stateCode);
920 AudioUnitRenderActionFlags* ioActionFlags,
921 const AudioTimeStamp* inTimeStamp,
923 UInt32 inNumberFrames,
924 AudioBufferList* ioData)
931 if (threadState == Stopped)
942 if (framesWritten > 0)
944 else if (framesWritten == 0)
946 else if (framesWritten < 0)
956 #include "qaudioinput_mac_p.moc"
virtual qint64 size() const
For open random-access devices, this function returns the size of the device.
#define QT_END_NAMESPACE
This macro expands to.
virtual void close()
First emits aboutToClose(), then closes the device and sets its OpenMode to NotOpen.
Q_CORE_EXPORT void qFree(void *ptr)
The QByteArray class provides an array of bytes.
static qreal position(QGraphicsObject *item, QDeclarativeAnchorLine::AnchorLine anchorLine)
#define Q_ARG(type, data)
Q_CORE_EXPORT void * qMalloc(size_t size)
The QObject class is the base class of all Qt objects.
QAudioFormat toQAudioFormat(AudioStreamBasicDescription const &sf)
#define QT_BEGIN_NAMESPACE
This macro expands to.
bool isOpen() const
Returns true if the device is open; otherwise returns false.
static bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
Creates a connection of the given type from the signal in the sender object to the method in the rece...
Q_CORE_EXPORT void qWarning(const char *,...)
AudioStreamBasicDescription toAudioStreamBasicDescription(QAudioFormat const &audioFormat)
The Component element encapsulates a QML component definition.
int fetchAndAddAcquire(int valueToAdd)
Atomic fetch-and-add.
The QMutexLocker class is a convenience class that simplifies locking and unlocking mutexes...
static QReadWriteLock lock
virtual bool reset()
Seeks to the start of input for random-access devices.
virtual bool open(OpenMode mode)
Opens the device and sets its OpenMode to mode.
Q_CORE_EXPORT QTextStream & flush(QTextStream &s)
The QDataStream class provides serialization of binary data to a QIODevice.
The QTimer class provides repetitive and single-shot timers.
The QIODevice class is the base interface class of all I/O devices in Qt.
#define Q_UNUSED(x)
Indicates to the compiler that the parameter with the specified name is not used in the body of a fun...
int open(const char *, int,...)