53 #include <CoreServices/CoreServices.h> 54 #include <CoreAudio/CoreAudio.h> 55 #include <AudioUnit/AudioUnit.h> 56 #include <AudioToolbox/AudioToolbox.h> 58 #include <QtCore/qendian.h> 59 #include <QtCore/qbuffer.h> 60 #include <QtCore/qtimer.h> 61 #include <QtCore/qdebug.h> 63 #include <QtMultimedia/qaudiooutput.h> 89 m_buffer =
new QAudioRingBuffer(bufferSize + (bufferSize % maxPeriodSize == 0 ? 0 : maxPeriodSize - (bufferSize % maxPeriodSize)));
107 while (wecan && framesRead < maxFrames) {
112 memcpy(data + (framesRead * m_bytesPerFrame), region.
first, region.
second);
133 while (wecan && bytesWritten < maxSize) {
137 memcpy(region.
first, data + bytesWritten, region.
second);
138 bytesWritten += region.
second;
146 if (bytesWritten > 0)
203 else if (region.
second == 0)
205 else if (region.
second < 0) {
242 m_audioBuffer(audioBuffer)
257 return m_audioBuffer->writeBytes(data, len);
283 audioDeviceId = AudioDeviceID(did);
290 clockFrequency = AudioGetHostClockFrequency() / 1000;
293 audioThreadState = Stopped;
295 intervalTimer =
new QTimer(
this);
296 intervalTimer->setInterval(1000);
303 delete audioDeviceInfo;
315 ComponentDescription cd;
316 cd.componentType = kAudioUnitType_Output;
317 cd.componentSubType = kAudioUnitSubType_HALOutput;
318 cd.componentManufacturer = kAudioUnitManufacturer_Apple;
319 cd.componentFlags = 0;
320 cd.componentFlagsMask = 0;
323 Component cp = FindNextComponent(NULL, &cd);
325 qWarning() <<
"QAudioOutput: Failed to find HAL Output component";
329 if (OpenAComponent(cp, &audioUnit) != noErr) {
330 qWarning() <<
"QAudioOutput: Unable to Open Output Component";
335 AURenderCallbackStruct cb;
336 cb.inputProc = renderCallback;
337 cb.inputProcRefCon =
this;
339 if (AudioUnitSetProperty(audioUnit,
340 kAudioUnitProperty_SetRenderCallback,
341 kAudioUnitScope_Global,
344 sizeof(cb)) != noErr) {
345 qWarning() <<
"QAudioOutput: Failed to set AudioUnit callback";
350 if (AudioUnitSetProperty(audioUnit,
351 kAudioOutputUnitProperty_CurrentDevice,
352 kAudioUnitScope_Global,
355 sizeof(audioDeviceId)) != noErr) {
356 qWarning() <<
"QAudioOutput: Unable to use configured device";
363 UInt32
size =
sizeof(streamFormat);
364 if (AudioUnitSetProperty(audioUnit,
365 kAudioUnitProperty_StreamFormat,
366 kAudioUnitScope_Input,
369 sizeof(streamFormat)) != noErr) {
370 qWarning() <<
"QAudioOutput: Unable to Set Stream information";
375 UInt32 numberOfFrames = 0;
376 size =
sizeof(UInt32);
377 if (AudioUnitGetProperty(audioUnit,
378 kAudioDevicePropertyBufferFrameSize,
379 kAudioUnitScope_Global,
383 qWarning() <<
"QAudioInput: Failed to get audio period size";
387 periodSizeBytes = numberOfFrames * streamFormat.mBytesPerFrame;
388 if (internalBufferSize < periodSizeBytes * 2)
389 internalBufferSize = periodSizeBytes * 2;
391 internalBufferSize -= internalBufferSize % streamFormat.mBytesPerFrame;
399 if (AudioUnitInitialize(audioUnit)) {
400 qWarning() <<
"QAudioOutput: Failed to initialize AudioUnit";
411 if (audioUnit != 0) {
412 AudioOutputUnitStop(audioUnit);
413 AudioUnitUninitialize(audioUnit);
414 CloseComponent(audioUnit);
429 if (!audioDeviceInfo->isFormatSupported(audioFormat) || !
open()) {
436 audioBuffer->reset();
437 audioBuffer->setPrefetchDevice(op);
449 startTime = AudioGetCurrentHostTime();
454 emit stateChanged(stateCode);
509 return audioBuffer->available();
514 return periodSizeBytes;
520 internalBufferSize = bs;
525 return internalBufferSize;
530 if (intervalTimer->interval() == milliSeconds)
533 if (milliSeconds <= 0)
536 intervalTimer->setInterval(milliSeconds);
541 return intervalTimer->interval();
546 return totalFrames * 1000000 / audioFormat.frequency();
554 return (AudioGetCurrentHostTime() - startTime) / (clockFrequency / 1000);
570 audioThreadState = Running;
571 AudioOutputUnitStart(audioUnit);
577 if (audioThreadState.testAndSetAcquire(Running, Stopped))
578 threadFinished.wait(&mutex);
584 if (audioThreadState.testAndSetAcquire(Running, Draining))
585 threadFinished.wait(&mutex);
590 AudioOutputUnitStop(audioUnit);
591 audioThreadState = Stopped;
592 threadFinished.wakeOne();
621 audioBuffer->startFillTimer();
622 if (intervalTimer->interval() > 0)
623 intervalTimer->start();
628 audioBuffer->stopFillTimer();
629 intervalTimer->stop();
635 intervalTimer->stop();
636 emit stateChanged(stateCode);
654 AudioUnitRenderActionFlags* ioActionFlags,
655 const AudioTimeStamp* inTimeStamp,
657 UInt32 inNumberFrames,
658 AudioBufferList* ioData)
668 if (threadState == Stopped) {
669 ioData->mBuffers[0].mDataByteSize = 0;
673 const UInt32 bytesPerFrame = d->
streamFormat.mBytesPerFrame;
676 framesRead = d->
audioBuffer->readFrames((
char*)ioData->mBuffers[0].mData,
677 ioData->mBuffers[0].mDataByteSize / bytesPerFrame);
679 if (framesRead > 0) {
680 ioData->mBuffers[0].mDataByteSize = framesRead * bytesPerFrame;
684 ioData->mBuffers[0].mDataByteSize = 0;
685 if (framesRead == 0) {
686 if (threadState == Draining)
702 #include "qaudiooutput_mac_p.moc"
virtual qint64 size() const
For open random-access devices, this function returns the size of the device.
MacOutputDevice(QtMultimediaInternal::QAudioOutputBuffer *audioBuffer, QObject *parent)
Region acquireReadRegion(int size)
#define QT_END_NAMESPACE
This macro expands to.
qint64 readData(char *data, qint64 len)
Reads up to maxSize bytes from the device into data, and returns the number of bytes read or -1 if an...
AudioStreamBasicDescription streamFormat
virtual void close()
First emits aboutToClose(), then closes the device and sets its OpenMode to NotOpen.
QAudio::State state() const
Returns the state of audio processing.
The QByteArray class provides an array of bytes.
void resume()
Resumes processing audio data after a suspend()
static OSStatus renderCallback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData)
#define Q_ARG(type, data)
void releaseWriteRegion(Region const ®ion)
The QObject class is the base class of all Qt objects.
QAudio::Error error() const
Returns the error state.
void reset()
Drops all audio data in the buffers, resets buffers to zero.
qint64 read(char *data, qint64 maxlen)
Reads at most maxSize bytes from the device into data, and returns the number of bytes read...
void setBufferSize(int value)
Sets the audio buffer size to value in bytes.
#define QT_BEGIN_NAMESPACE
This macro expands to.
QAudioOutputPrivate(const QByteArray &device, const QAudioFormat &audioFormat)
bool isOpen() const
Returns true if the device is open; otherwise returns false.
int notifyInterval() const
Returns the notify interval in milliseconds.
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)
static const char * data(const QByteArray &arr)
qint64 elapsedUSecs() const
Returns the milliseconds since start() was called, including time in Idle and suspend states...
qint64 processedUSecs() const
Returns the amount of audio data processed since start() was called in milliseconds.
void suspend()
Stops processing audio data, preserving buffered audio data.
The Component element encapsulates a QML component definition.
int fetchAndAddAcquire(int valueToAdd)
Atomic fetch-and-add.
int periodSize() const
Returns the period size in bytes.
QAudioFormat format() const
Returns the QAudioFormat being used.
The QMutexLocker class is a convenience class that simplifies locking and unlocking mutexes...
int bytesFree() const
Returns the free space available in bytes in the audio buffer.
QObject * parent() const
Returns a pointer to the parent object.
void setNotifyInterval(int milliSeconds)
Sets the interval for notify() signal to be emitted.
static QReadWriteLock lock
virtual bool reset()
Seeks to the start of input for random-access devices.
int bufferSize() const
Returns the audio buffer size in bytes.
virtual bool open(OpenMode mode)
Opens the device and sets its OpenMode to mode.
Region acquireWriteRegion(int size)
The QDataStream class provides serialization of binary data to a QIODevice.
QIODevice * start(QIODevice *device=0)
Uses the device as the QIODevice to transfer data.
void stop()
Stops the audio output.
void releaseReadRegion(Region const ®ion)
The QTimer class provides repetitive and single-shot timers.
qint64 writeData(const char *data, qint64 len)
Writes up to maxSize bytes from data to the device.
void readyRead()
This signal is emitted once every time new data is available for reading from the device...
The QIODevice class is the base interface class of all I/O devices in Qt.
void stop()
Stops the timer.
void start(int msec)
Starts or restarts the timer with a timeout interval of msec milliseconds.
#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,...)
bool isSequential() const
Returns true if this device is sequential; otherwise returns false.
QAtomicInt audioThreadState
QtMultimediaInternal::QAudioOutputBuffer * m_audioBuffer