10#include <private/qaudiodevice_p.h>
11#include <private/qaudioformat_p.h>
13#include <QtCore/qloggingcategory.h>
14#include <QtCore/qmutex.h>
15#include <QtCore/qspan.h>
17#include <ohaudio/native_audio_device_base.h>
18#include <ohaudio/native_audio_manager.h>
19#include <ohaudio/native_audio_routing_manager.h>
20#include <ohaudio/native_audiostream_base.h>
28Q_STATIC_LOGGING_CATEGORY(qLcOhosAudioDevices,
"qt.multimedia.ohos.audiodevices")
33Q_CONSTINIT QOhosAudioDevices *g_audioDevicesInstance =
nullptr;
37Q_CONSTINIT QBasicMutex g_callbackMutex;
47 namespace ranges = QtMultimediaPrivate::ranges;
50 QAudioFormat &format = info.preferredFormat;
55 constexpr int defaultSampleRate = 48000;
56 uint32_t *sampleRates =
nullptr;
57 uint32_t sampleRateCount = 0;
58 if (OH_AudioDeviceDescriptor_GetDeviceSampleRates(descriptor, &sampleRates, &sampleRateCount)
59 == AUDIOCOMMON_RESULT_SUCCESS
60 && sampleRateCount > 0) {
61 const QSpan<
const uint32_t> rates{ sampleRates, sampleRateCount };
63 QtMultimediaPrivate::findClosestSamplingRate(defaultSampleRate, rates));
65 format.setSampleRate(defaultSampleRate);
68 uint32_t *channelCounts =
nullptr;
69 uint32_t channelCountSize = 0;
70 if (OH_AudioDeviceDescriptor_GetDeviceChannelCounts(descriptor, &channelCounts, &channelCountSize)
71 == AUDIOCOMMON_RESULT_SUCCESS
72 && channelCountSize > 0) {
73 const QSpan<
const uint32_t> channels{ channelCounts, channelCountSize };
74 const uint32_t chosenChannels =
75 ranges::contains(channels, 2u) ? 2u : *ranges::max_element(channels);
76 format.setChannelConfig(
77 QAudioFormat::defaultChannelConfigForChannelCount(
static_cast<
int>(chosenChannels)));
78 info.maximumChannelCount =
static_cast<
int>(*ranges::max_element(channels));
80 format.setChannelConfig(QAudioFormat::ChannelConfigStereo);
83 format.setSampleFormat(QAudioFormat::Float);
90 case AUDIO_DEVICE_TYPE_EARPIECE:
91 return QStringLiteral(
"Earpiece");
92 case AUDIO_DEVICE_TYPE_SPEAKER:
93 return QStringLiteral(
"Speaker");
94 case AUDIO_DEVICE_TYPE_WIRED_HEADSET:
95 return QStringLiteral(
"Wired Headset");
96 case AUDIO_DEVICE_TYPE_WIRED_HEADPHONES:
97 return QStringLiteral(
"Wired Headphones");
98 case AUDIO_DEVICE_TYPE_BLUETOOTH_SCO:
99 return QStringLiteral(
"Bluetooth (SCO)");
100 case AUDIO_DEVICE_TYPE_BLUETOOTH_A2DP:
101 return QStringLiteral(
"Bluetooth (A2DP)");
102 case AUDIO_DEVICE_TYPE_MIC:
103 return QStringLiteral(
"Microphone");
104 case AUDIO_DEVICE_TYPE_USB_HEADSET:
105 case AUDIO_DEVICE_TYPE_USB_DEVICE:
106 return QStringLiteral(
"USB Audio");
115 char *name =
nullptr;
116 if (OH_AudioDeviceDescriptor_GetDeviceName(descriptor, &name) == AUDIOCOMMON_RESULT_SUCCESS
118 return QString::fromUtf8(name);
121 OH_AudioDevice_Type type{ AUDIO_DEVICE_TYPE_INVALID };
122 OH_AudioDeviceDescriptor_GetDeviceType(descriptor, &type);
123 const QString typeLabel = deviceTypeLabel(type);
126 char *rawDisplayName =
nullptr;
127 if (OH_AudioDeviceDescriptor_GetDeviceDisplayName(descriptor, &rawDisplayName)
128 == AUDIOCOMMON_RESULT_SUCCESS
129 && rawDisplayName && *rawDisplayName) {
130 displayName = QString::fromUtf8(rawDisplayName);
133 if (!displayName.isEmpty() && !typeLabel.isEmpty())
134 return displayName + u' ' + typeLabel;
135 if (!displayName.isEmpty())
137 if (!typeLabel.isEmpty())
139 return QStringLiteral(
"Audio Device");
144 OH_AudioDeviceDescriptorArray *preferred =
nullptr;
145 const OH_AudioCommon_Result result = (mode == QAudioDevice::Input)
146 ? OH_AudioRoutingManager_GetPreferredInputDevice(routing, AUDIOSTREAM_SOURCE_TYPE_MIC,
148 : OH_AudioRoutingManager_GetPreferredOutputDevice(routing, AUDIOSTREAM_USAGE_MUSIC,
150 if (result != AUDIOCOMMON_RESULT_SUCCESS || !preferred || preferred->size == 0) {
152 OH_AudioRoutingManager_ReleaseDevices(routing, preferred);
156 uint32_t deviceId = 0;
157 OH_AudioDeviceDescriptor_GetDeviceId(preferred->descriptors[0], &deviceId);
158 OH_AudioRoutingManager_ReleaseDevices(routing, preferred);
167 char *address =
nullptr;
168 if (OH_AudioDeviceDescriptor_GetDeviceAddress(descriptor, &address) == AUDIOCOMMON_RESULT_SUCCESS
169 && address && *address) {
170 return QByteArray{ address };
172 uint32_t deviceId = 0;
173 OH_AudioDeviceDescriptor_GetDeviceId(descriptor, &deviceId);
174 return QByteArray::number(deviceId);
179 OH_AudioManager *manager =
nullptr;
180 if (OH_GetAudioManager(&manager) != AUDIOCOMMON_RESULT_SUCCESS || !manager) {
181 qCWarning(qLcOhosAudioDevices) <<
"OH_GetAudioManager failed";
185 OH_AudioRoutingManager *routing =
nullptr;
186 if (OH_AudioManager_GetAudioRoutingManager(&routing) != AUDIOCOMMON_RESULT_SUCCESS || !routing) {
187 qCWarning(qLcOhosAudioDevices) <<
"OH_AudioManager_GetAudioRoutingManager failed";
191 const OH_AudioDevice_Flag flag = (mode == QAudioDevice::Input) ? AUDIO_DEVICE_FLAG_INPUT
192 : AUDIO_DEVICE_FLAG_OUTPUT;
193 OH_AudioDeviceDescriptorArray *descriptors =
nullptr;
194 if (OH_AudioRoutingManager_GetDevices(routing, flag, &descriptors)
195 != AUDIOCOMMON_RESULT_SUCCESS
197 qCWarning(qLcOhosAudioDevices) <<
"OH_AudioRoutingManager_GetDevices failed for"
198 << (mode == QAudioDevice::Input ?
"input" :
"output");
202 const std::optional<uint32_t> defaultDeviceId = preferredDeviceId(routing, mode);
204 QList<QAudioDevice> devices;
205 devices.reserve(descriptors->size);
206 for (uint32_t i = 0; i < descriptors->size; ++i) {
207 OH_AudioDeviceDescriptor *descriptor = descriptors->descriptors[i];
211 uint32_t deviceId = 0;
212 OH_AudioDeviceDescriptor_GetDeviceId(descriptor, &deviceId);
214 const QByteArray identifier = deviceIdentifier(descriptor);
216 const QString description = deviceDisplayDescription(descriptor);
217 const bool isDefault = defaultDeviceId ? deviceId == *defaultDeviceId : i == 0;
219 devices << QAudioDevicePrivate::createQAudioDevice(std::make_unique<QOhosAudioDevice>(
220 identifier, description, mode, formatInfo.preferredFormat, formatInfo.maximumChannelCount,
224 OH_AudioRoutingManager_ReleaseDevices(routing, descriptors);
230QOhosAudioDevices::QOhosAudioDevices() : QPlatformAudioDevices()
232 Q_ASSERT(!g_audioDevicesInstance);
233 g_audioDevicesInstance =
this;
234 registerDeviceChangeCallbacks();
237QOhosAudioDevices::~QOhosAudioDevices()
239 unregisterDeviceChangeCallbacks();
240 QMutexLocker guard{ &g_callbackMutex };
241 g_audioDevicesInstance =
nullptr;
244void QOhosAudioDevices::registerDeviceChangeCallbacks()
246 OH_AudioRoutingManager *routing =
nullptr;
247 if (OH_AudioManager_GetAudioRoutingManager(&routing) != AUDIOCOMMON_RESULT_SUCCESS || !routing) {
248 qCWarning(qLcOhosAudioDevices)
249 <<
"Cannot register device change callbacks: routing manager unavailable";
253 const OH_AudioCommon_Result inputResult = OH_AudioRoutingManager_RegisterDeviceChangeCallback(
254 routing, AUDIO_DEVICE_FLAG_INPUT, &QOhosAudioDevices::onInputDevicesChanged);
255 const OH_AudioCommon_Result outputResult = OH_AudioRoutingManager_RegisterDeviceChangeCallback(
256 routing, AUDIO_DEVICE_FLAG_OUTPUT, &QOhosAudioDevices::onOutputDevicesChanged);
258 if (inputResult != AUDIOCOMMON_RESULT_SUCCESS || outputResult != AUDIOCOMMON_RESULT_SUCCESS)
259 qCWarning(qLcOhosAudioDevices) <<
"Failed to register audio device change callbacks";
261 m_deviceChangeCallbacksRegistered =
262 inputResult == AUDIOCOMMON_RESULT_SUCCESS || outputResult == AUDIOCOMMON_RESULT_SUCCESS;
265void QOhosAudioDevices::unregisterDeviceChangeCallbacks()
267 if (!m_deviceChangeCallbacksRegistered)
270 OH_AudioRoutingManager *routing =
nullptr;
271 if (OH_AudioManager_GetAudioRoutingManager(&routing) != AUDIOCOMMON_RESULT_SUCCESS || !routing)
274 OH_AudioRoutingManager_UnregisterDeviceChangeCallback(
275 routing, &QOhosAudioDevices::onInputDevicesChanged);
276 OH_AudioRoutingManager_UnregisterDeviceChangeCallback(
277 routing, &QOhosAudioDevices::onOutputDevicesChanged);
283int32_t QOhosAudioDevices::onInputDevicesChanged(OH_AudioDevice_ChangeType ,
284 OH_AudioDeviceDescriptorArray * )
286 QMutexLocker guard{ &g_callbackMutex };
287 if (g_audioDevicesInstance)
288 g_audioDevicesInstance->onAudioInputsChanged();
292int32_t QOhosAudioDevices::onOutputDevicesChanged(OH_AudioDevice_ChangeType ,
293 OH_AudioDeviceDescriptorArray * )
295 QMutexLocker guard{ &g_callbackMutex };
296 if (g_audioDevicesInstance)
297 g_audioDevicesInstance->onAudioOutputsChanged();
301QList<QAudioDevice> QOhosAudioDevices::findAudioInputs()
const
303 return enumerateDevices(QAudioDevice::Input);
306QList<QAudioDevice> QOhosAudioDevices::findAudioOutputs()
const
308 return enumerateDevices(QAudioDevice::Output);
311QPlatformAudioSource *QOhosAudioDevices::createAudioSource(
const QAudioDevice &device,
312 const QAudioFormat &format,
315 return new QtOHAudio::QOhosAudioSource(device, format, parent);
318QPlatformAudioSink *QOhosAudioDevices::createAudioSink(
const QAudioDevice &device,
319 const QAudioFormat &format, QObject *parent)
321 return new QtOHAudio::QOhosAudioSink(device, format, parent);
DeviceFormatInfo deviceFormatInfo(OH_AudioDeviceDescriptor *descriptor)
std::optional< uint32_t > preferredDeviceId(OH_AudioRoutingManager *routing, QAudioDevice::Mode mode)
QByteArray deviceIdentifier(OH_AudioDeviceDescriptor *descriptor)
QString deviceTypeLabel(OH_AudioDevice_Type type)
QList< QAudioDevice > enumerateDevices(QAudioDevice::Mode mode)
QString deviceDisplayDescription(OH_AudioDeviceDescriptor *descriptor)