21 const QAudioFormat::SampleFormat format = [&] {
22 const bool isFloat = sf.mFormatFlags & kAudioFormatFlagIsFloat;
23 switch (sf.mBitsPerChannel) {
25 return QAudioFormat::UInt8;
27 return QAudioFormat::Int16;
29 return isFloat ? QAudioFormat::Float : QAudioFormat::Int32;
31 return QAudioFormat::Float;
35 QAudioFormat audioFormat;
36 audioFormat.setSampleFormat(format);
37 audioFormat.setSampleRate(sf.mSampleRate);
38 audioFormat.setChannelCount(sf.mChannelsPerFrame);
105 auto channelConfig = format.channelConfig();
106 if (channelConfig == QAudioFormat::ChannelConfigUnknown)
107 channelConfig = QAudioFormat::defaultChannelConfigForChannelCount(format.channelCount());
109 *size =
sizeof(AudioChannelLayout) +
int(QAudioFormat::NChannelPositions)*
sizeof(AudioChannelDescription);
110 auto *layout =
static_cast<AudioChannelLayout *>(malloc(*size));
111 memset(layout, 0, *size);
112 layout->mChannelLayoutTag = kAudioChannelLayoutTag_UseChannelDescriptions;
114 for (
const auto &m : channelMap) {
115 if (channelConfig & QAudioFormat::channelConfig(m.pos))
116 layout->mChannelDescriptions[layout->mNumberChannelDescriptions++].mChannelLabel = m.label;
119 if (channelConfig & QAudioFormat::channelConfig(QAudioFormat::BottomFrontCenter)) {
120 auto &desc = layout->mChannelDescriptions[layout->mNumberChannelDescriptions++];
121 desc.mChannelLabel = kAudioChannelLabel_UseCoordinates;
122 desc.mChannelFlags = kAudioChannelFlags_SphericalCoordinates;
123 desc.mCoordinates[kAudioChannelCoordinates_Azimuth] = 0.f;
124 desc.mCoordinates[kAudioChannelCoordinates_Elevation] = -20.;
125 desc.mCoordinates[kAudioChannelCoordinates_Distance] = 1.f;
127 if (channelConfig & QAudioFormat::channelConfig(QAudioFormat::BottomFrontLeft)) {
128 auto &desc = layout->mChannelDescriptions[layout->mNumberChannelDescriptions++];
129 desc.mChannelLabel = kAudioChannelLabel_UseCoordinates;
130 desc.mChannelFlags = kAudioChannelFlags_SphericalCoordinates;
131 desc.mCoordinates[kAudioChannelCoordinates_Azimuth] = -45.f;
132 desc.mCoordinates[kAudioChannelCoordinates_Elevation] = -20.;
133 desc.mCoordinates[kAudioChannelCoordinates_Distance] = 1.f;
135 if (channelConfig & QAudioFormat::channelConfig(QAudioFormat::BottomFrontRight)) {
136 auto &desc = layout->mChannelDescriptions[layout->mNumberChannelDescriptions++];
137 desc.mChannelLabel = kAudioChannelLabel_UseCoordinates;
138 desc.mChannelFlags = kAudioChannelFlags_SphericalCoordinates;
139 desc.mCoordinates[kAudioChannelCoordinates_Azimuth] = 45.f;
140 desc.mCoordinates[kAudioChannelCoordinates_Elevation] = -20.;
141 desc.mCoordinates[kAudioChannelCoordinates_Distance] = 1.f;
144 return std::unique_ptr<AudioChannelLayout, QFreeDeleter>(layout);
192 for (
const auto &m : layoutTagMap) {
193 if (m.tag == layout->mChannelLayoutTag)
194 return m.channelConfig;
197 quint32 channels = 0;
198 if (layout->mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelDescriptions) {
200 if (layout->mNumberChannelDescriptions == 1
201 && (layout->mChannelDescriptions[0].mChannelLabel == kAudioChannelLabel_Unknown
202 || layout->mChannelDescriptions[0].mChannelLabel == kAudioChannelLabel_Mono))
203 return QAudioFormat::ChannelConfigMono;
204 if (layout->mNumberChannelDescriptions == 2 &&
205 layout->mChannelDescriptions[0].mChannelLabel == kAudioChannelLabel_Unknown &&
206 layout->mChannelDescriptions[1].mChannelLabel == kAudioChannelLabel_Unknown)
207 return QAudioFormat::ChannelConfigStereo;
209 for (uint i = 0; i < layout->mNumberChannelDescriptions; ++i) {
210 const auto channelLabel = layout->mChannelDescriptions[i].mChannelLabel;
211 if (channelLabel == kAudioChannelLabel_Unknown) {
217 const auto found = std::find_if(channelMap, std::end(channelMap),
218 [channelLabel](
const auto &labelWithPos) {
219 return labelWithPos.label == channelLabel;
222 if (found == std::end(channelMap))
223 qWarning() <<
"audio device has unrecognized channel, index:" << i
224 <<
"label:" << channelLabel;
226 channels |= QAudioFormat::channelConfig(found->pos);
229 qWarning() <<
"Channel layout uses unimplemented format, channelLayoutTag:"
230 << layout->mChannelLayoutTag;
232 return QAudioFormat::ChannelConfig(channels);
308 AudioComponentDescription componentDescription;
309 componentDescription.componentType = kAudioUnitType_Output;
310#if defined(Q_OS_MACOS)
311 componentDescription.componentSubType = kAudioUnitSubType_HALOutput;
313 componentDescription.componentSubType = kAudioUnitSubType_RemoteIO;
315 componentDescription.componentManufacturer = kAudioUnitManufacturer_Apple;
316 componentDescription.componentFlags = 0;
317 componentDescription.componentFlagsMask = 0;
319 AudioComponent component = AudioComponentFindNext(
nullptr, &componentDescription);
320 if (component ==
nullptr) {
321 qWarning() <<
"makeAudioUnitForIO: Failed to find Output component";
326 if (AudioComponentInstanceNew(component, &audioUnit) != noErr) {
327 qWarning() <<
"makeAudioUnitForIO: Unable to Open Output Component";
373 const AudioStreamBasicDescription &format)
375 OSStatus status = AudioUnitSetProperty(audioUnit.get(), kAudioUnitProperty_StreamFormat,
376 kAudioUnitScope_Input, element, &format,
sizeof(format));
377 if (status != noErr) {
378 qWarning() <<
"AudioUnit: Unable to set stream format" << status;
385 const AudioStreamBasicDescription &format)
387 if (AudioUnitSetProperty(audioUnit.get(), kAudioUnitProperty_StreamFormat,
388 kAudioUnitScope_Output, element, &format,
sizeof(format))
390 qWarning() <<
"AudioUnit: Unable to set stream format";
495 OSStatus status = AudioUnitSetProperty(audioUnit.get(), kAudioUnitProperty_SetRenderCallback,
496 kAudioUnitScope_Global, 0, &callback,
sizeof(callback));
498 if (status != noErr) {
499 qWarning() <<
"AudioUnitSetProperty: Failed to set AudioUnit "
500 "kAudioUnitProperty_SetRenderCallback"
521 AudioUnitElement element)
523 AudioStreamBasicDescription ret;
524 UInt32 size =
sizeof(AudioStreamBasicDescription);
526 if (AudioUnitGetProperty(audioUnit.get(), kAudioUnitProperty_StreamFormat,
527 kAudioUnitScope_Input, element, &ret, &size)
529 qWarning() <<
"QAudioSource: Unable to retrieve device format";