Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qdarwinaudiodevice.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies).
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
5
6#include <QtCore/private/qcore_mac_p.h>
7
8#include <QtMultimedia/private/qcoreaudioutils_p.h>
9#include <QtMultimedia/private/qaudioformat_p.h>
10#ifdef Q_OS_MACOS
11#include <QtMultimedia/private/qmacosaudiodatautils_p.h>
12#endif
13
14#include <optional>
15
16QT_BEGIN_NAMESPACE
17
18namespace {
19
21 QAudioDevice::Mode mode,
22 QAudioFormat::ChannelConfig channelConfig)
23{
24 QAudioFormat format;
25 format.setSampleRate(44100);
26 format.setSampleFormat(QAudioFormat::Int16);
27 format.setChannelCount(mode == QAudioDevice::Input ? 1 : 2);
28 format.setChannelConfig(channelConfig);
29 return format;
30}
31
32[[nodiscard]] QAudioFormat::ChannelConfig qGetDefaultChannelLayout(QAudioDevice::Mode mode)
33{
34 return (mode == QAudioDevice::Input) ? QAudioFormat::ChannelConfigMono : QAudioFormat::ChannelConfigStereo;
35}
36
37[[nodiscard]] QString qGetDefaultDescription(const QByteArray &id)
38{
39 return QString::fromUtf8(id);
40}
41
42#ifdef Q_OS_MACOS
43
44[[nodiscard]] std::optional<QAudioFormat> qGetPreferredFormatForCoreAudioDevice(
45 QAudioDevice::Mode mode,
46 AudioDeviceID deviceId)
47{
48 using namespace QCoreAudioUtils;
49
50 const auto audioDevicePropertyStreamsAddress =
51 makePropertyAddress(kAudioDevicePropertyStreams, mode);
52 const auto audioDevicePhysicalFormatPropertyAddress =
53 makePropertyAddress(kAudioStreamPropertyPhysicalFormat, mode);
54
55 auto streamIDs =
56 getAudioPropertyList<AudioStreamID>(deviceId, audioDevicePropertyStreamsAddress);
57 if (!streamIDs || streamIDs->empty())
58 return std::nullopt;
59
60 for (auto streamID : *streamIDs) {
61 auto streamDescription = getAudioProperty<AudioStreamBasicDescription>(
62 streamID, audioDevicePhysicalFormatPropertyAddress);
63 if (!streamDescription)
64 continue;
65
66 QAudioFormat fmt = QCoreAudioUtils::toPreferredQAudioFormat(*streamDescription);
67 if (fmt.isValid())
68 return fmt;
69 }
70 return std::nullopt;
71}
72
73[[nodiscard]] std::optional<QAudioFormat::ChannelConfig> qGetChannelLayoutForCoreAudioDevice(
74 QAudioDevice::Mode mode,
75 AudioDeviceID deviceId)
76{
77 using namespace QCoreAudioUtils;
78
79 const auto propertyAddress =
80 makePropertyAddress(kAudioDevicePropertyPreferredChannelLayout, mode);
81
82 if (auto layout = getAudioPropertyWithFlexibleArrayMember<AudioChannelLayout>(deviceId, propertyAddress))
83 return QCoreAudioUtils::fromAudioChannelLayout(layout.get());
84
85 return std::nullopt;
86}
87
88[[nodiscard]] std::optional<QString> qGetDescriptionForCoreAudioDevice(
89 QAudioDevice::Mode mode,
90 AudioDeviceID deviceId)
91{
92 using namespace QCoreAudioUtils;
93
94 const auto propertyAddress = makePropertyAddress(kAudioObjectPropertyName, mode);
95 if (auto name = getAudioProperty<QCFString>(deviceId, propertyAddress))
96 return name;
97
98 return std::nullopt;
99}
100
101[[nodiscard]] std::optional<int> qSupportedNumberOfChannels(
102 QAudioDevice::Mode mode,
103 AudioDeviceID deviceId)
104{
105 using namespace QCoreAudioUtils;
106
107 const auto audioDevicePropertyStreamsAddress =
108 makePropertyAddress(kAudioDevicePropertyStreams, mode);
109
110 auto streamIDs = getAudioPropertyList<AudioStreamID>(deviceId, audioDevicePropertyStreamsAddress);
111 if (!streamIDs)
112 return std::nullopt;
113
114 const auto propVirtualFormat = makePropertyAddress(kAudioStreamPropertyVirtualFormat, mode);
115
116 int ret{};
117
118 for (auto streamID : *streamIDs) {
119 auto streamDescription = getAudioProperty<AudioStreamBasicDescription>(streamID, propVirtualFormat);
120 if (!streamDescription)
121 continue;
122 ret += streamDescription->mChannelsPerFrame;
123 }
124
125 return ret;
126}
127
128QAudioDevicePrivate::AudioDeviceFormat probeCoreAudioDeviceFormat(AudioDeviceID id,
129 QAudioDevice::Mode mode)
130{
131 QAudioDevicePrivate::AudioDeviceFormat format;
132
133 const std::optional<QAudioFormat::ChannelConfig> channelConfigOpt =
134 qGetChannelLayoutForCoreAudioDevice(mode, id);
135 if (channelConfigOpt.has_value())
136 format.channelConfiguration = channelConfigOpt.value();
137 else
138 format.channelConfiguration = qGetDefaultChannelLayout(mode);
139
140 const std::optional<QAudioFormat> preferredFormatOpt =
141 qGetPreferredFormatForCoreAudioDevice(mode, id);
142 if (preferredFormatOpt.has_value())
143 format.preferredFormat = preferredFormatOpt.value();
144 else
145 format.preferredFormat = qDefaultPreferredFormat(mode, format.channelConfiguration);
146
147 format.minimumSampleRate = QtMultimediaPrivate::allSupportedSampleRates.front();
148 format.maximumSampleRate = QtMultimediaPrivate::allSupportedSampleRates.back();
149 format.minimumChannelCount = 1;
150 format.maximumChannelCount = qSupportedNumberOfChannels(mode, id).value_or(16);
151
152 format.supportedSampleFormats = qAllSupportedSampleFormats();
153
154 return format;
155}
156
157#else
158
160{
161 QAudioDevicePrivate::AudioDeviceFormat format;
162
163 format.channelConfiguration = qGetDefaultChannelLayout(mode);
164 format.preferredFormat = qDefaultPreferredFormat(mode, format.channelConfiguration);
165
166 format.minimumSampleRate = 1;
167 format.maximumSampleRate = 96000;
168 format.minimumChannelCount = 1;
169 format.maximumChannelCount = 16;
170 format.supportedSampleFormats = qAllSupportedSampleFormats();
171
172 return format;
173}
174
175#endif
176
177} // namespace
178
179#ifdef Q_OS_MACOS
180
181static QString getDescription(AudioDeviceID id, const QByteArray &device, QAudioDevice::Mode mode)
182{
183 if (auto optionalDescription = qGetDescriptionForCoreAudioDevice(mode, id))
184 return *optionalDescription;
185 return qGetDefaultDescription(device);
186}
187
188QCoreAudioDeviceInfo::QCoreAudioDeviceInfo(AudioDeviceID id, const QByteArray &device,
189 QAudioDevice::Mode mode)
190 : QAudioDevicePrivate(device, mode, getDescription(id, device, mode), false,
191 probeCoreAudioDeviceFormat(id, mode))
192{
193}
194
195#else
196
197QCoreAudioDeviceInfo::QCoreAudioDeviceInfo(const QByteArray &device, QAudioDevice::Mode mode)
198 : QAudioDevicePrivate(device, mode, qGetDefaultDescription(device), false,
199 createDefaultCoreAudioDeviceFormat(mode))
200{
201}
202
203#endif
204
205QT_END_NAMESPACE
QAudioDevicePrivate::AudioDeviceFormat createDefaultCoreAudioDeviceFormat(QAudioDevice::Mode mode)
QAudioFormat::ChannelConfig qGetDefaultChannelLayout(QAudioDevice::Mode mode)
QAudioFormat qDefaultPreferredFormat(QAudioDevice::Mode mode, QAudioFormat::ChannelConfig channelConfig)
QString qGetDefaultDescription(const QByteArray &id)