6#include "private/qaudiodevice_p.h"
11#include <qloggingcategory.h>
15#if defined(QT_PLATFORM_UIKIT)
16#include "qcoreaudiosessionmanager_p.h"
17#import <AVFoundation/AVFoundation.h>
22#if defined(Q_OS_MACOS)
28template<
typename... Args>
29QAudioDevice createAudioDevice(
bool isDefault, Args &&...args)
31 auto dev = std::make_unique<QCoreAudioDeviceInfo>(std::forward<Args>(args)...);
32 dev->isDefault = isDefault;
33 return QAudioDevicePrivate::createQAudioDevice(std::move(dev));
36#if defined(Q_OS_MACOS)
38static AudioDeviceID defaultAudioDevice(QAudioDevice::Mode mode)
40 const AudioObjectPropertySelector selector = (mode == QAudioDevice::Output) ? kAudioHardwarePropertyDefaultOutputDevice
41 : kAudioHardwarePropertyDefaultInputDevice;
42 const AudioObjectPropertyAddress propertyAddress = {
44 kAudioObjectPropertyScopeGlobal,
45 kAudioObjectPropertyElementMain,
48 if (
auto audioDevice = QCoreAudioUtils::getAudioProperty<AudioDeviceID>(kAudioObjectSystemObject, propertyAddress)) {
55static QList<QAudioDevice> availableAudioDevices(QAudioDevice::Mode mode)
57 using namespace QCoreAudioUtils;
59 QList<QAudioDevice> devices;
61 AudioDeviceID defaultDevice = defaultAudioDevice(mode);
62 if (defaultDevice != 0)
63 devices << createAudioDevice(
66 QCoreAudioUtils::readPersistentDeviceId(defaultDevice, mode),
69 const AudioObjectPropertyAddress audioDevicesPropertyAddress = {
70 kAudioHardwarePropertyDevices, kAudioObjectPropertyScopeGlobal,
71 kAudioObjectPropertyElementMain
74 if (
auto audioDevices = getAudioPropertyList<AudioDeviceID>(
75 kAudioObjectSystemObject, audioDevicesPropertyAddress)) {
76 const AudioObjectPropertyAddress audioDeviceStreamFormatPropertyAddress =
77 makePropertyAddress(kAudioDevicePropertyStreamFormat, mode);
79 for (
const auto &device : *audioDevices) {
80 if (device == defaultDevice)
83 if (getAudioProperty<AudioStreamBasicDescription>(device,
84 audioDeviceStreamFormatPropertyAddress,
86 devices << createAudioDevice(
false,
88 QCoreAudioUtils::readPersistentDeviceId(device, mode),
97static OSStatus audioDeviceChangeListener(AudioObjectID id, UInt32,
98 const AudioObjectPropertyAddress *address,
void *ptr)
103 QDarwinAudioDevices *instance =
static_cast<QDarwinAudioDevices *>(ptr);
105 qCDebug(qLcDarwinMediaDevices)
106 <<
"audioDeviceChangeListener: id:" << id <<
"address: " << address->mSelector
107 << address->mScope << address->mElement;
109 switch (address->mSelector) {
110 case kAudioHardwarePropertyDefaultInputDevice:
111 instance->updateAudioInputsCache();
113 case kAudioHardwarePropertyDefaultOutputDevice:
114 instance->updateAudioOutputsCache();
117 instance->updateAudioInputsCache();
118 instance->updateAudioOutputsCache();
125static constexpr AudioObjectPropertyAddress listenerAddresses[] = {
126 { kAudioHardwarePropertyDefaultInputDevice, kAudioObjectPropertyScopeGlobal,
127 kAudioObjectPropertyElementMain },
128 { kAudioHardwarePropertyDefaultOutputDevice, kAudioObjectPropertyScopeGlobal,
129 kAudioObjectPropertyElementMain },
130 { kAudioHardwarePropertyDevices, kAudioObjectPropertyScopeGlobal,
131 kAudioObjectPropertyElementMain }
134static void setAudioListeners(QDarwinAudioDevices &instance)
136 for (
const auto &address : listenerAddresses) {
137 const auto err = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &address,
138 audioDeviceChangeListener, &instance);
141 qWarning() <<
"Fail to add listener. mSelector:" << address.mSelector
142 <<
"mScope:" << address.mScope <<
"mElement:" << address.mElement
147static void removeAudioListeners(QDarwinAudioDevices &instance)
149 for (
const auto &address : listenerAddresses) {
150 const auto err = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &address,
151 audioDeviceChangeListener, &instance);
154 qWarning() <<
"Fail to remove listener. mSelector:" << address.mSelector
155 <<
"mScope:" << address.mScope <<
"mElement:" << address.mElement
160#elif defined(QT_PLATFORM_UIKIT)
162static QList<QAudioDevice> availableAudioDevices(QAudioDevice::Mode mode)
164 QList<QAudioDevice> devices;
166 if (mode == QAudioDevice::Output) {
167 devices.append(createAudioDevice(
true,
"default", QAudioDevice::Output));
169#if !defined(Q_OS_VISIONOS)
170 AVCaptureDevice *defaultDevice =
171 [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];
174 AVCaptureDeviceDiscoverySession *captureDeviceDiscoverySession =
175 [AVCaptureDeviceDiscoverySession
176 discoverySessionWithDeviceTypes:@[ AVCaptureDeviceTypeBuiltInMicrophone ]
177 mediaType:AVMediaTypeAudio
178 position:AVCaptureDevicePositionUnspecified];
180 NSArray *captureDevices = [captureDeviceDiscoverySession devices];
181 for (AVCaptureDevice *device in captureDevices) {
182 const bool isDefault =
183 defaultDevice && [defaultDevice.uniqueID isEqualToString:device.uniqueID];
184 devices.append(createAudioDevice(isDefault,
185 QString::fromNSString(device.uniqueID).toUtf8(),
186 QAudioDevice::Input));
194static void setAudioListeners(QDarwinAudioDevices &)
199static void removeAudioListeners(QDarwinAudioDevices &)
210 updateAudioInputsCache();
211 updateAudioOutputsCache();
214 setAudioListeners(*
this);
219 removeAudioListeners(*
this);
224 return availableAudioDevices(QAudioDevice::Input);
229 return availableAudioDevices(QAudioDevice::Output);
233 const QAudioFormat &fmt,
236 return new QDarwinAudioSource(info, fmt, parent);
240 const QAudioFormat &fmt, QObject *parent)
242 return new QDarwinAudioSink(info, fmt, parent);
QList< QAudioDevice > findAudioOutputs() const override
QList< QAudioDevice > findAudioInputs() const override
~QDarwinAudioDevices() override