25 const QAudioFormat::SampleFormat format = [&] {
26 const bool isFloat = sf.mFormatFlags & kAudioFormatFlagIsFloat;
27 switch (sf.mBitsPerChannel) {
29 return QAudioFormat::UInt8;
31 return QAudioFormat::Int16;
33 return isFloat ? QAudioFormat::Float : QAudioFormat::Int32;
35 return QAudioFormat::Float;
39 QAudioFormat audioFormat;
40 audioFormat.setSampleFormat(format);
41 audioFormat.setSampleRate(sf.mSampleRate);
42 audioFormat.setChannelCount(sf.mChannelsPerFrame);
109 auto channelConfig = format.channelConfig();
110 if (channelConfig == QAudioFormat::ChannelConfigUnknown)
111 channelConfig = QAudioFormat::defaultChannelConfigForChannelCount(format.channelCount());
113 *size =
sizeof(AudioChannelLayout) +
int(QAudioFormat::NChannelPositions)*
sizeof(AudioChannelDescription);
114 auto *layout =
static_cast<AudioChannelLayout *>(malloc(*size));
115 memset(layout, 0, *size);
116 layout->mChannelLayoutTag = kAudioChannelLayoutTag_UseChannelDescriptions;
118 for (
const auto &m : channelMap) {
119 if (channelConfig & QAudioFormat::channelConfig(m.pos))
120 layout->mChannelDescriptions[layout->mNumberChannelDescriptions++].mChannelLabel = m.label;
123 if (channelConfig & QAudioFormat::channelConfig(QAudioFormat::BottomFrontCenter)) {
124 auto &desc = layout->mChannelDescriptions[layout->mNumberChannelDescriptions++];
125 desc.mChannelLabel = kAudioChannelLabel_UseCoordinates;
126 desc.mChannelFlags = kAudioChannelFlags_SphericalCoordinates;
127 desc.mCoordinates[kAudioChannelCoordinates_Azimuth] = 0.f;
128 desc.mCoordinates[kAudioChannelCoordinates_Elevation] = -20.;
129 desc.mCoordinates[kAudioChannelCoordinates_Distance] = 1.f;
131 if (channelConfig & QAudioFormat::channelConfig(QAudioFormat::BottomFrontLeft)) {
132 auto &desc = layout->mChannelDescriptions[layout->mNumberChannelDescriptions++];
133 desc.mChannelLabel = kAudioChannelLabel_UseCoordinates;
134 desc.mChannelFlags = kAudioChannelFlags_SphericalCoordinates;
135 desc.mCoordinates[kAudioChannelCoordinates_Azimuth] = -45.f;
136 desc.mCoordinates[kAudioChannelCoordinates_Elevation] = -20.;
137 desc.mCoordinates[kAudioChannelCoordinates_Distance] = 1.f;
139 if (channelConfig & QAudioFormat::channelConfig(QAudioFormat::BottomFrontRight)) {
140 auto &desc = layout->mChannelDescriptions[layout->mNumberChannelDescriptions++];
141 desc.mChannelLabel = kAudioChannelLabel_UseCoordinates;
142 desc.mChannelFlags = kAudioChannelFlags_SphericalCoordinates;
143 desc.mCoordinates[kAudioChannelCoordinates_Azimuth] = 45.f;
144 desc.mCoordinates[kAudioChannelCoordinates_Elevation] = -20.;
145 desc.mCoordinates[kAudioChannelCoordinates_Distance] = 1.f;
148 return std::unique_ptr<AudioChannelLayout, QFreeDeleter>(layout);
196 for (
const auto &m : layoutTagMap) {
197 if (m.tag == layout->mChannelLayoutTag)
198 return m.channelConfig;
201 quint32 channels = 0;
202 if (layout->mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelDescriptions) {
204 if (layout->mNumberChannelDescriptions == 1
205 && (layout->mChannelDescriptions[0].mChannelLabel == kAudioChannelLabel_Unknown
206 || layout->mChannelDescriptions[0].mChannelLabel == kAudioChannelLabel_Mono))
207 return QAudioFormat::ChannelConfigMono;
208 if (layout->mNumberChannelDescriptions == 2 &&
209 layout->mChannelDescriptions[0].mChannelLabel == kAudioChannelLabel_Unknown &&
210 layout->mChannelDescriptions[1].mChannelLabel == kAudioChannelLabel_Unknown)
211 return QAudioFormat::ChannelConfigStereo;
213 for (uint i = 0; i < layout->mNumberChannelDescriptions; ++i) {
214 const auto channelLabel = layout->mChannelDescriptions[i].mChannelLabel;
215 if (channelLabel == kAudioChannelLabel_Unknown) {
221 const auto found = ranges::find_if(channelMap, [&](
const auto &labelWithPos) {
222 return labelWithPos.label == channelLabel;
225 if (found == std::end(channelMap))
226 qWarning() <<
"audio device has unrecognized channel, index:" << i
227 <<
"label:" << channelLabel;
229 channels |= QAudioFormat::channelConfig(found->pos);
232 qWarning() <<
"Channel layout uses unimplemented format, channelLayoutTag:"
233 << layout->mChannelLayoutTag;
235 return QAudioFormat::ChannelConfig(channels);
240 AudioComponentDescription componentDescription;
241 componentDescription.componentType = kAudioUnitType_Output;
242#if defined(Q_OS_MACOS)
243 componentDescription.componentSubType = kAudioUnitSubType_HALOutput;
245 componentDescription.componentSubType = kAudioUnitSubType_RemoteIO;
247 componentDescription.componentManufacturer = kAudioUnitManufacturer_Apple;
248 componentDescription.componentFlags = 0;
249 componentDescription.componentFlagsMask = 0;
251 AudioComponent component = AudioComponentFindNext(
nullptr, &componentDescription);
252 if (component ==
nullptr) {
253 qWarning() <<
"makeAudioUnitForIO: Failed to find Output component";
258 if (AudioComponentInstanceNew(component, &audioUnit) != noErr) {
259 qWarning() <<
"makeAudioUnitForIO: Unable to Open Output Component";
305 const AudioStreamBasicDescription &format)
307 OSStatus status = AudioUnitSetProperty(audioUnit.get(), kAudioUnitProperty_StreamFormat,
308 kAudioUnitScope_Input, element, &format,
sizeof(format));
309 if (status != noErr) {
310 qWarning() <<
"AudioUnit: Unable to set stream format" << QtMultimediaPrivate::QOSStatus(status);
317 const AudioStreamBasicDescription &format)
319 if (AudioUnitSetProperty(audioUnit.get(), kAudioUnitProperty_StreamFormat,
320 kAudioUnitScope_Output, element, &format,
sizeof(format))
322 qWarning() <<
"AudioUnit: Unable to set stream format";
431 UInt32 isRunning = 0;
432 UInt32 size =
sizeof(isRunning);
434 OSStatus status = AudioUnitGetProperty(audioUnit.get(), kAudioOutputUnitProperty_IsRunning,
435 kAudioUnitScope_Global, 0, &isRunning, &size);
437 if (status != noErr) {
438 qDebug() <<
"AudioUnitGetProperty failed" << QtMultimediaPrivate::QOSStatus(status);
442 return bool(isRunning);
447 OSStatus status = AudioUnitSetProperty(audioUnit.get(), kAudioUnitProperty_SetRenderCallback,
448 kAudioUnitScope_Global, 0, &callback,
sizeof(callback));
450 if (status != noErr) {
451 qWarning() <<
"AudioUnitSetProperty: Failed to set AudioUnit "
452 "kAudioUnitProperty_SetRenderCallback"
453 << QtMultimediaPrivate::QOSStatus(status);
473 AudioUnitElement element)
475 AudioStreamBasicDescription ret;
476 UInt32 size =
sizeof(AudioStreamBasicDescription);
478 if (AudioUnitGetProperty(audioUnit.get(), kAudioUnitProperty_StreamFormat,
479 kAudioUnitScope_Input, element, &ret, &size)
481 qWarning() <<
"QAudioSource: Unable to retrieve device format";