24 const QAudioFormat::SampleFormat format = [&] {
25 const bool isFloat = sf.mFormatFlags & kAudioFormatFlagIsFloat;
26 switch (sf.mBitsPerChannel) {
28 return QAudioFormat::UInt8;
30 return QAudioFormat::Int16;
32 return isFloat ? QAudioFormat::Float : QAudioFormat::Int32;
34 return QAudioFormat::Float;
38 QAudioFormat audioFormat;
39 audioFormat.setSampleFormat(format);
40 audioFormat.setSampleRate(sf.mSampleRate);
41 audioFormat.setChannelCount(sf.mChannelsPerFrame);
108 auto channelConfig = format.channelConfig();
109 if (channelConfig == QAudioFormat::ChannelConfigUnknown)
110 channelConfig = QAudioFormat::defaultChannelConfigForChannelCount(format.channelCount());
112 *size =
sizeof(AudioChannelLayout) +
int(QAudioFormat::NChannelPositions)*
sizeof(AudioChannelDescription);
113 auto *layout =
static_cast<AudioChannelLayout *>(malloc(*size));
114 memset(layout, 0, *size);
115 layout->mChannelLayoutTag = kAudioChannelLayoutTag_UseChannelDescriptions;
117 for (
const auto &m : channelMap) {
118 if (channelConfig & QAudioFormat::channelConfig(m.pos))
119 layout->mChannelDescriptions[layout->mNumberChannelDescriptions++].mChannelLabel = m.label;
122 if (channelConfig & QAudioFormat::channelConfig(QAudioFormat::BottomFrontCenter)) {
123 auto &desc = layout->mChannelDescriptions[layout->mNumberChannelDescriptions++];
124 desc.mChannelLabel = kAudioChannelLabel_UseCoordinates;
125 desc.mChannelFlags = kAudioChannelFlags_SphericalCoordinates;
126 desc.mCoordinates[kAudioChannelCoordinates_Azimuth] = 0.f;
127 desc.mCoordinates[kAudioChannelCoordinates_Elevation] = -20.;
128 desc.mCoordinates[kAudioChannelCoordinates_Distance] = 1.f;
130 if (channelConfig & QAudioFormat::channelConfig(QAudioFormat::BottomFrontLeft)) {
131 auto &desc = layout->mChannelDescriptions[layout->mNumberChannelDescriptions++];
132 desc.mChannelLabel = kAudioChannelLabel_UseCoordinates;
133 desc.mChannelFlags = kAudioChannelFlags_SphericalCoordinates;
134 desc.mCoordinates[kAudioChannelCoordinates_Azimuth] = -45.f;
135 desc.mCoordinates[kAudioChannelCoordinates_Elevation] = -20.;
136 desc.mCoordinates[kAudioChannelCoordinates_Distance] = 1.f;
138 if (channelConfig & QAudioFormat::channelConfig(QAudioFormat::BottomFrontRight)) {
139 auto &desc = layout->mChannelDescriptions[layout->mNumberChannelDescriptions++];
140 desc.mChannelLabel = kAudioChannelLabel_UseCoordinates;
141 desc.mChannelFlags = kAudioChannelFlags_SphericalCoordinates;
142 desc.mCoordinates[kAudioChannelCoordinates_Azimuth] = 45.f;
143 desc.mCoordinates[kAudioChannelCoordinates_Elevation] = -20.;
144 desc.mCoordinates[kAudioChannelCoordinates_Distance] = 1.f;
147 return std::unique_ptr<AudioChannelLayout, QFreeDeleter>(layout);
195 for (
const auto &m : layoutTagMap) {
196 if (m.tag == layout->mChannelLayoutTag)
197 return m.channelConfig;
200 quint32 channels = 0;
201 if (layout->mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelDescriptions) {
203 if (layout->mNumberChannelDescriptions == 1
204 && (layout->mChannelDescriptions[0].mChannelLabel == kAudioChannelLabel_Unknown
205 || layout->mChannelDescriptions[0].mChannelLabel == kAudioChannelLabel_Mono))
206 return QAudioFormat::ChannelConfigMono;
207 if (layout->mNumberChannelDescriptions == 2 &&
208 layout->mChannelDescriptions[0].mChannelLabel == kAudioChannelLabel_Unknown &&
209 layout->mChannelDescriptions[1].mChannelLabel == kAudioChannelLabel_Unknown)
210 return QAudioFormat::ChannelConfigStereo;
212 for (uint i = 0; i < layout->mNumberChannelDescriptions; ++i) {
213 const auto channelLabel = layout->mChannelDescriptions[i].mChannelLabel;
214 if (channelLabel == kAudioChannelLabel_Unknown) {
220 const auto found = ranges::find_if(channelMap, [&](
const auto &labelWithPos) {
221 return labelWithPos.label == channelLabel;
224 if (found == std::end(channelMap))
225 qWarning() <<
"audio device has unrecognized channel, index:" << i
226 <<
"label:" << channelLabel;
228 channels |= QAudioFormat::channelConfig(found->pos);
231 qWarning() <<
"Channel layout uses unimplemented format, channelLayoutTag:"
232 << layout->mChannelLayoutTag;
234 return QAudioFormat::ChannelConfig(channels);
239 AudioComponentDescription componentDescription;
240 componentDescription.componentType = kAudioUnitType_Output;
241#if defined(Q_OS_MACOS)
242 componentDescription.componentSubType = kAudioUnitSubType_HALOutput;
244 componentDescription.componentSubType = kAudioUnitSubType_RemoteIO;
246 componentDescription.componentManufacturer = kAudioUnitManufacturer_Apple;
247 componentDescription.componentFlags = 0;
248 componentDescription.componentFlagsMask = 0;
250 AudioComponent component = AudioComponentFindNext(
nullptr, &componentDescription);
251 if (component ==
nullptr) {
252 qWarning() <<
"makeAudioUnitForIO: Failed to find Output component";
257 if (AudioComponentInstanceNew(component, &audioUnit) != noErr) {
258 qWarning() <<
"makeAudioUnitForIO: Unable to Open Output Component";
304 const AudioStreamBasicDescription &format)
306 OSStatus status = AudioUnitSetProperty(audioUnit.get(), kAudioUnitProperty_StreamFormat,
307 kAudioUnitScope_Input, element, &format,
sizeof(format));
308 if (status != noErr) {
309 qWarning() <<
"AudioUnit: Unable to set stream format" << status;
316 const AudioStreamBasicDescription &format)
318 if (AudioUnitSetProperty(audioUnit.get(), kAudioUnitProperty_StreamFormat,
319 kAudioUnitScope_Output, element, &format,
sizeof(format))
321 qWarning() <<
"AudioUnit: Unable to set stream format";
446 OSStatus status = AudioUnitSetProperty(audioUnit.get(), kAudioUnitProperty_SetRenderCallback,
447 kAudioUnitScope_Global, 0, &callback,
sizeof(callback));
449 if (status != noErr) {
450 qWarning() <<
"AudioUnitSetProperty: Failed to set AudioUnit "
451 "kAudioUnitProperty_SetRenderCallback"
472 AudioUnitElement element)
474 AudioStreamBasicDescription ret;
475 UInt32 size =
sizeof(AudioStreamBasicDescription);
477 if (AudioUnitGetProperty(audioUnit.get(), kAudioUnitProperty_StreamFormat,
478 kAudioUnitScope_Input, element, &ret, &size)
480 qWarning() <<
"QAudioSource: Unable to retrieve device format";