10#if defined(Q_OS_MACOS)
11# include <AudioUnit/AudioComponent.h>
14#if defined(Q_OS_IOS) || defined(Q_OS_TVOS)
18#include <QtMultimedia/private/qaudiohelpers_p.h>
19#include <QtCore/QDataStream>
20#include <QtCore/QDebug>
28 , m_streamDescription(streamFormat)
30 const bool isInterleaved = (m_streamDescription.mFormatFlags & kAudioFormatFlagIsNonInterleaved) == 0;
31 const int numberOfBuffers = isInterleaved ? 1 : m_streamDescription.mChannelsPerFrame;
35 m_bufferList =
reinterpret_cast<AudioBufferList*
>(malloc(
sizeof(AudioBufferList) +
36 (
sizeof(AudioBuffer) * numberOfBuffers)));
38 m_bufferList->mNumberBuffers = numberOfBuffers;
39 for (
int i = 0;
i < numberOfBuffers; ++
i) {
40 m_bufferList->mBuffers[
i].mNumberChannels = isInterleaved ? numberOfBuffers : 1;
41 m_bufferList->mBuffers[
i].mDataByteSize = 0;
42 m_bufferList->mBuffers[
i].mData = 0;
48 , m_streamDescription(streamFormat)
53 m_bufferList =
reinterpret_cast<AudioBufferList*
>(malloc(
sizeof(AudioBufferList) +
sizeof(AudioBuffer)));
55 m_bufferList->mNumberBuffers = 1;
56 m_bufferList->mBuffers[0].mNumberChannels = 1;
57 m_bufferList->mBuffers[0].mDataByteSize = m_dataSize;
58 m_bufferList->mBuffers[0].mData =
buffer;
63 , m_streamDescription(streamFormat)
66 const bool isInterleaved = (m_streamDescription.mFormatFlags & kAudioFormatFlagIsNonInterleaved) == 0;
67 const int numberOfBuffers = isInterleaved ? 1 : m_streamDescription.mChannelsPerFrame;
69 m_dataSize = framesToBuffer * m_streamDescription.mBytesPerFrame;
71 m_bufferList =
reinterpret_cast<AudioBufferList*
>(malloc(
sizeof(AudioBufferList) +
72 (
sizeof(AudioBuffer) * numberOfBuffers)));
73 m_bufferList->mNumberBuffers = numberOfBuffers;
74 for (
int i = 0;
i < numberOfBuffers; ++
i) {
75 m_bufferList->mBuffers[
i].mNumberChannels = isInterleaved ? numberOfBuffers : 1;
76 m_bufferList->mBuffers[
i].mDataByteSize = m_dataSize;
77 m_bufferList->mBuffers[
i].mData = malloc(m_dataSize);
84 for (UInt32
i = 0;
i < m_bufferList->mNumberBuffers; ++
i)
85 free(m_bufferList->mBuffers[
i].mData);
93 return static_cast<char*
>(m_bufferList->mBuffers[
buffer].mData);
98 return m_bufferList->mBuffers[
buffer].mDataByteSize;
103 return m_bufferList->mBuffers[
buffer].mDataByteSize / m_streamDescription.mBytesPerFrame;
108 return m_bufferList->mBuffers[
buffer].mDataByteSize / m_streamDescription.mBytesPerPacket;
113 return m_streamDescription.mBytesPerPacket;
118 for (UInt32
i = 0;
i < m_bufferList->mNumberBuffers; ++
i) {
119 m_bufferList->mBuffers[
i].mDataByteSize = m_dataSize;
120 m_bufferList->mBuffers[
i].mData = 0;
125 : m_audioBufferList(abl)
133 if (m_position == m_totalPackets) {
134 dst.mBuffers[0].mDataByteSize = 0;
139 if (m_totalPackets - m_position < packetCount)
140 packetCount = m_totalPackets - m_position;
142 dst.mBuffers[0].mDataByteSize = packetCount * m_audioBufferList->
packetSize();
143 dst.mBuffers[0].mData = m_audioBufferList->
data() + (m_position * m_audioBufferList->
packetSize());
145 m_position += packetCount;
152 return m_position == m_totalPackets;
157 , m_deviceError(
false)
159 , m_audioConverter(0)
160 , m_inputFormat(inputFormat)
161 , m_outputFormat(outputFormat)
162 , m_volume(
qreal(1.0f))
164 m_maxPeriodSize = maxPeriodSize;
165 m_periodTime = m_maxPeriodSize / m_outputFormat.mBytesPerFrame * 1000 / m_outputFormat.mSampleRate;
171 m_flushTimer =
new QTimer(
this);
175 if (AudioConverterNew(&m_inputFormat, &m_outputFormat, &m_audioConverter) != noErr) {
176 qWarning() <<
"QAudioSource: Unable to create an Audio Converter";
177 m_audioConverter = 0;
201 const bool pullMode = m_device == 0;
204 qint64 framesRendered = 0;
206 m_inputBufferList->
reset();
207 err = AudioUnitRender(audioUnit,
218 m_inputBufferList->
data(),
219 m_inputBufferList->
data(),
223 if (m_audioConverter != 0) {
229 while (err == noErr && !feeder.
empty()) {
232 if (region.second == 0)
236 output.mNumberBuffers = 1;
237 output.mBuffers[0].mNumberChannels = 1;
238 output.mBuffers[0].mDataByteSize = region.second;
239 output.mBuffers[0].mData = region.first;
241 UInt32
packetSize = region.second / m_outputFormat.mBytesPerPacket;
242 err = AudioConverterFillComplexBuffer(m_audioConverter,
248 region.second =
output.mBuffers[0].mDataByteSize;
249 copied += region.second;
254 framesRendered += copied / m_outputFormat.mBytesPerFrame;
264 if (region.second > 0) {
265 memcpy(region.first, m_inputBufferList->
data() + copied, region.second);
266 copied += region.second;
274 framesRendered = copied / m_outputFormat.mBytesPerFrame;
277 if (pullMode && framesRendered > 0)
280 return framesRendered;
288 len -=
len % m_maxPeriodSize;
289 while (wecan && bytesCopied <
len) {
292 if (region.second > 0) {
293 memcpy(
data + bytesCopied, region.first, region.second);
294 bytesCopied += region.second;
316 m_flushTimer->
start(
qMax(1, m_periodTime));
322 m_flushTimer->
stop();
331 const int readSize = all ?
used :
used - (
used % m_maxPeriodSize);
337 while (!m_deviceError && wecan && flushed < readSize) {
340 if (region.second > 0) {
344 m_deviceError =
true;
363 m_deviceError =
false;
368 return m_buffer->
free();
373 return m_buffer->
used();
376void QDarwinAudioSourceBuffer::flushBuffer()
381OSStatus QDarwinAudioSourceBuffer::converterCallback(AudioConverterRef inAudioConverter, UInt32 *ioNumberDataPackets, AudioBufferList *ioData, AudioStreamPacketDescription **outDataPacketDescription,
void *inUserData)
388 if (!feeder->
feed(*ioData, *ioNumberDataPackets))
396 , m_audioBuffer(audioBuffer)
417 , m_audioDeviceInfo(
device)
424 , m_stateCode(
QAudio::StoppedState)
431#if defined(Q_OS_MACOS)
434 m_audioDeviceId =
info->deviceID();
445bool QDarwinAudioSource::open()
455 AudioComponentDescription componentDescription;
456 componentDescription.componentType = kAudioUnitType_Output;
457#if defined(Q_OS_MACOS)
458 componentDescription.componentSubType = kAudioUnitSubType_HALOutput;
460 componentDescription.componentSubType = kAudioUnitSubType_RemoteIO;
462 componentDescription.componentManufacturer = kAudioUnitManufacturer_Apple;
463 componentDescription.componentFlags = 0;
464 componentDescription.componentFlagsMask = 0;
466 AudioComponent
component = AudioComponentFindNext(0, &componentDescription);
468 qWarning() <<
"QAudioSource: Failed to find Output component";
472 if (AudioComponentInstanceNew(
component, &m_audioUnit) != noErr) {
473 qWarning() <<
"QAudioSource: Unable to Open Output Component";
480 if (AudioUnitSetProperty(m_audioUnit,
481 kAudioOutputUnitProperty_EnableIO,
482 kAudioUnitScope_Input,
485 sizeof(
enable)) != noErr) {
486 qWarning() <<
"QAudioSource: Unable to switch to input mode (Enable Input)";
491 if (AudioUnitSetProperty(m_audioUnit,
492 kAudioOutputUnitProperty_EnableIO,
493 kAudioUnitScope_Output,
496 sizeof(
enable)) != noErr) {
497 qWarning() <<
"QAudioSource: Unable to switch to input mode (Disable output)";
502 AURenderCallbackStruct callback;
503 callback.inputProc = inputCallback;
504 callback.inputProcRefCon =
this;
506 if (AudioUnitSetProperty(m_audioUnit,
507 kAudioOutputUnitProperty_SetInputCallback,
508 kAudioUnitScope_Global,
511 sizeof(callback)) != noErr) {
512 qWarning() <<
"QAudioSource: Failed to set AudioUnit callback";
516#if defined(Q_OS_MACOS)
518 if (AudioUnitSetProperty(m_audioUnit,
519 kAudioOutputUnitProperty_CurrentDevice,
520 kAudioUnitScope_Global,
523 sizeof(m_audioDeviceId)) != noErr) {
524 qWarning() <<
"QAudioSource: Unable to use configured device";
532#if defined(Q_OS_MACOS)
538 m_deviceFormat = m_streamFormat;
539 AudioUnitSetProperty(m_audioUnit,
540 kAudioUnitProperty_StreamFormat,
541 kAudioUnitScope_Output,
544 sizeof(m_deviceFormat));
545#if defined(Q_OS_MACOS)
547 size =
sizeof(m_deviceFormat);
548 if (AudioUnitGetProperty(m_audioUnit,
549 kAudioUnitProperty_StreamFormat,
550 kAudioUnitScope_Input,
554 qWarning() <<
"QAudioSource: Unable to retrieve device format";
558 if (AudioUnitSetProperty(m_audioUnit,
559 kAudioUnitProperty_StreamFormat,
560 kAudioUnitScope_Output,
563 sizeof(m_deviceFormat)) != noErr) {
564 qWarning() <<
"QAudioSource: Unable to set device format";
571 UInt32 numberOfFrames;
572#if defined(Q_OS_MACOS)
573 size =
sizeof(UInt32);
574 if (AudioUnitGetProperty(m_audioUnit,
575 kAudioDevicePropertyBufferFrameSize,
576 kAudioUnitScope_Global,
580 qWarning() <<
"QAudioSource: Failed to get audio period size";
585 AudioValueRange bufferRange;
586 size =
sizeof(AudioValueRange);
588 if (AudioUnitGetProperty(m_audioUnit,
589 kAudioDevicePropertyBufferFrameSizeRange,
590 kAudioUnitScope_Global,
594 qWarning() <<
"QAudioSource: Failed to get audio period size range";
599 numberOfFrames =
qBound((UInt32)bufferRange.mMinimum, m_internalBufferSize / m_streamFormat.mBytesPerFrame, (UInt32)bufferRange.mMaximum);
602 if (AudioUnitSetProperty(m_audioUnit,
603 kAudioDevicePropertyBufferFrameSize,
604 kAudioUnitScope_Global,
607 sizeof(UInt32)) != noErr) {
608 qWarning() <<
"QAudioSource: Failed to set audio buffer size";
618 m_periodSizeBytes = m_internalBufferSize = numberOfFrames * m_streamFormat.mBytesPerFrame;
633 if (AudioUnitInitialize(m_audioUnit) != noErr) {
634 qWarning() <<
"QAudioSource: Failed to initialize AudioUnit";
644void QDarwinAudioSource::close()
647 if (m_audioUnit != 0) {
648 AudioOutputUnitStop(m_audioUnit);
649 AudioUnitUninitialize(m_audioUnit);
650 AudioComponentInstanceDispose(m_audioUnit);
653 delete m_audioBuffer;
654 m_audioBuffer =
nullptr;
671 m_audioBuffer->
reset();
702 m_audioBuffer->
reset();
727 m_audioBuffer->
flush(
true);
744 m_audioBuffer->
reset();
781 return m_audioBuffer->
used();
786 m_internalBufferSize =
value;
792 return m_internalBufferSize;
797 return m_totalFrames * 1000000 / m_audioFormat.
sampleRate();
821 return m_audioFormat;
839void QDarwinAudioSource::deviceStoppped()
845void QDarwinAudioSource::audioThreadStart()
849 AudioOutputUnitStart(m_audioUnit);
852void QDarwinAudioSource::audioThreadStop()
856 m_audioBuffer->
wait();
859void QDarwinAudioSource::audioDeviceStop()
861 AudioOutputUnitStop(m_audioUnit);
863 m_audioBuffer->
wake();
866void QDarwinAudioSource::audioDeviceActive()
875void QDarwinAudioSource::audioDeviceFull()
885void QDarwinAudioSource::audioDeviceError()
897void QDarwinAudioSource::startTimers()
902void QDarwinAudioSource::stopTimers()
907OSStatus QDarwinAudioSource::inputCallback(
void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData)
913 const int threadState =
d->m_audioThreadState.loadAcquire();
914 if (threadState == Stopped)
915 d->audioDeviceStop();
921 framesWritten =
d->m_audioBuffer->renderFromDevice(
d->m_audioUnit,
928 if (framesWritten > 0) {
929 d->m_totalFrames += framesWritten;
930 d->audioDeviceActive();
931 }
else if (framesWritten == 0)
932 d->audioDeviceFull();
933 else if (framesWritten < 0)
934 d->audioDeviceError();
942#include "moc_qdarwinaudiosource_p.cpp"
IOBluetoothDevice * device
void releaseWriteRegion(Region const ®ion)
Region acquireWriteRegion(int size)
Region acquireReadRegion(int size)
void releaseReadRegion(Region const ®ion)
QPair< char *, int > Region
bool setCategory(AudioSessionCategorys category, AudioSessionCategoryOptions options=None)
bool setActive(bool active)
static CoreAudioSessionManager & instance()
float currentIOBufferDuration()
static Q_MULTIMEDIA_EXPORT QAudioFormat toQAudioFormat(const AudioStreamBasicDescription &streamFormat)
static AudioStreamBasicDescription toAudioStreamBasicDescription(QAudioFormat const &audioFormat)
The QAudioDevice class provides an information about audio devices and their functionality.
bool isFormatSupported(const QAudioFormat &format) const
Returns true if the supplied settings are supported by the audio device described by this QAudioDevic...
QByteArray id
\qmlproperty string QtMultimedia::audioDevice::id
QAudioFormat preferredFormat() const
Returns the default audio format settings for this device.
const QAudioDevicePrivate * handle() const
bool isNull() const
Returns whether this QAudioDevice object holds a valid device definition.
void storeRelaxed(T newValue) noexcept
bool testAndSetAcquire(T expectedValue, T newValue) noexcept
QCoreAudioBufferList(AudioStreamBasicDescription const &streamFormat)
AudioBufferList * audioBufferList() const
int frameCount(int buffer=0) const
char * data(int buffer=0) const
qint64 bufferSize(int buffer=0) const
int packetCount(int buffer=0) const
QCoreAudioPacketFeeder(QCoreAudioBufferList *abl)
bool feed(AudioBufferList &dst, UInt32 &packetCount)
qint64 renderFromDevice(AudioUnit audioUnit, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames)
qint64 readBytes(char *data, qint64 len)
QDarwinAudioSourceBuffer(int bufferSize, int maxPeriodSize, AudioStreamBasicDescription const &inputFormat, AudioStreamBasicDescription const &outputFormat, QObject *parent)
~QDarwinAudioSourceBuffer()
void flush(bool all=false)
void setFlushDevice(QIODevice *device)
QDarwinAudioSourceDevice(QDarwinAudioSourceBuffer *audioBuffer, QObject *parent)
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...
qint64 writeData(const char *data, qint64 len)
Writes up to maxSize bytes from data to the device.
QDarwinAudioSource(const QAudioDevice &device, QObject *parent)
qsizetype bufferSize() const
void setVolume(qreal volume)
qint64 processedUSecs() const
qsizetype bytesReady() const
QAudio::Error error() const
void setBufferSize(qsizetype value)
void setFormat(const QAudioFormat &format)
QAudioFormat format() const
QAudio::State state() const
\inmodule QtCore \reentrant
virtual bool open(QIODeviceBase::OpenMode mode)
Opens the device and sets its OpenMode to mode.
void readyRead()
This signal is emitted once every time new data is available for reading from the device's current re...
qint64 write(const char *data, qint64 len)
Writes at most maxSize bytes of data from data to the device.
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
void start(int msec)
Starts or restarts the timer with a timeout interval of msec milliseconds.
void stop()
Stops the timer.
void qMultiplySamples(qreal factor, const QAudioFormat &format, const void *src, void *dest, int len)
The QAudio namespace contains enums used by the audio classes.
State
\value ActiveState Audio data is being processed, this state is set after start() is called and while...
Error
\value NoError No errors have occurred \value OpenError An error occurred opening the audio device \v...
Combined button and popup list for selecting options.
static const size_t packetSize
static QT_BEGIN_NAMESPACE const int DEFAULT_BUFFER_SIZE
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
bool qFuzzyCompare(qfloat16 p1, qfloat16 p2) noexcept
constexpr const T & qBound(const T &min, const T &val, const T &max)
constexpr const T & qMax(const T &a, const T &b)
#define Q_ARG(Type, data)
GLenum GLsizei GLuint GLint * bytesWritten
GLsizei const GLfloat * v
[13]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLbitfield GLuint64 timeout
[4]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLint GLsizei GLsizei GLenum format
static qreal component(const QPointF &point, unsigned int i)
QT_BEGIN_NAMESPACE typedef uchar * output
QFileInfo info(fileName)
[8]
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent