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;
41 namespace ranges = QtMultimediaPrivate::ranges;
48 constexpr int defaultSampleRate = 48000;
49 uint32_t *sampleRates =
nullptr;
50 uint32_t sampleRateCount = 0;
51 if (OH_AudioDeviceDescriptor_GetDeviceSampleRates(descriptor, &sampleRates, &sampleRateCount)
52 == AUDIOCOMMON_RESULT_SUCCESS
53 && sampleRateCount > 0) {
54 format.setSampleRate(QtMultimediaPrivate::findClosestSamplingRate(
55 defaultSampleRate, QSpan<
const uint32_t>{ sampleRates, sampleRateCount }));
57 format.setSampleRate(defaultSampleRate);
60 uint32_t *channelCounts =
nullptr;
61 uint32_t channelCountSize = 0;
62 if (OH_AudioDeviceDescriptor_GetDeviceChannelCounts(descriptor, &channelCounts, &channelCountSize)
63 == AUDIOCOMMON_RESULT_SUCCESS
64 && channelCountSize > 0) {
65 const QSpan<
const uint32_t> channels{ channelCounts, channelCountSize };
66 const uint32_t chosenChannels =
67 ranges::contains(channels, 2u) ? 2u : *ranges::max_element(channels);
68 format.setChannelConfig(
69 QAudioFormat::defaultChannelConfigForChannelCount(
static_cast<
int>(chosenChannels)));
71 format.setChannelConfig(QAudioFormat::ChannelConfigStereo);
74 format.setSampleFormat(QAudioFormat::Float);
81 case AUDIO_DEVICE_TYPE_EARPIECE:
82 return QStringLiteral(
"Earpiece");
83 case AUDIO_DEVICE_TYPE_SPEAKER:
84 return QStringLiteral(
"Speaker");
85 case AUDIO_DEVICE_TYPE_WIRED_HEADSET:
86 return QStringLiteral(
"Wired Headset");
87 case AUDIO_DEVICE_TYPE_WIRED_HEADPHONES:
88 return QStringLiteral(
"Wired Headphones");
89 case AUDIO_DEVICE_TYPE_BLUETOOTH_SCO:
90 return QStringLiteral(
"Bluetooth (SCO)");
91 case AUDIO_DEVICE_TYPE_BLUETOOTH_A2DP:
92 return QStringLiteral(
"Bluetooth (A2DP)");
93 case AUDIO_DEVICE_TYPE_MIC:
94 return QStringLiteral(
"Microphone");
95 case AUDIO_DEVICE_TYPE_USB_HEADSET:
96 case AUDIO_DEVICE_TYPE_USB_DEVICE:
97 return QStringLiteral(
"USB Audio");
106 char *name =
nullptr;
107 if (OH_AudioDeviceDescriptor_GetDeviceName(descriptor, &name) == AUDIOCOMMON_RESULT_SUCCESS
109 return QString::fromUtf8(name);
112 OH_AudioDevice_Type type{ AUDIO_DEVICE_TYPE_INVALID };
113 OH_AudioDeviceDescriptor_GetDeviceType(descriptor, &type);
114 const QString typeLabel = deviceTypeLabel(type);
117 char *rawDisplayName =
nullptr;
118 if (OH_AudioDeviceDescriptor_GetDeviceDisplayName(descriptor, &rawDisplayName)
119 == AUDIOCOMMON_RESULT_SUCCESS
120 && rawDisplayName && *rawDisplayName) {
121 displayName = QString::fromUtf8(rawDisplayName);
124 if (!displayName.isEmpty() && !typeLabel.isEmpty())
125 return displayName + u' ' + typeLabel;
126 if (!displayName.isEmpty())
128 if (!typeLabel.isEmpty())
130 return QStringLiteral(
"Audio Device");
135 OH_AudioDeviceDescriptorArray *preferred =
nullptr;
136 const OH_AudioCommon_Result result = (mode == QAudioDevice::Input)
137 ? OH_AudioRoutingManager_GetPreferredInputDevice(routing, AUDIOSTREAM_SOURCE_TYPE_MIC,
139 : OH_AudioRoutingManager_GetPreferredOutputDevice(routing, AUDIOSTREAM_USAGE_MUSIC,
141 if (result != AUDIOCOMMON_RESULT_SUCCESS || !preferred || preferred->size == 0) {
143 OH_AudioRoutingManager_ReleaseDevices(routing, preferred);
147 uint32_t deviceId = 0;
148 OH_AudioDeviceDescriptor_GetDeviceId(preferred->descriptors[0], &deviceId);
149 OH_AudioRoutingManager_ReleaseDevices(routing, preferred);
158 char *address =
nullptr;
159 if (OH_AudioDeviceDescriptor_GetDeviceAddress(descriptor, &address) == AUDIOCOMMON_RESULT_SUCCESS
160 && address && *address) {
161 return QByteArray{ address };
163 uint32_t deviceId = 0;
164 OH_AudioDeviceDescriptor_GetDeviceId(descriptor, &deviceId);
165 return QByteArray::number(deviceId);
170 OH_AudioManager *manager =
nullptr;
171 if (OH_GetAudioManager(&manager) != AUDIOCOMMON_RESULT_SUCCESS || !manager) {
172 qCWarning(qLcOhosAudioDevices) <<
"OH_GetAudioManager failed";
176 OH_AudioRoutingManager *routing =
nullptr;
177 if (OH_AudioManager_GetAudioRoutingManager(&routing) != AUDIOCOMMON_RESULT_SUCCESS || !routing) {
178 qCWarning(qLcOhosAudioDevices) <<
"OH_AudioManager_GetAudioRoutingManager failed";
182 const OH_AudioDevice_Flag flag = (mode == QAudioDevice::Input) ? AUDIO_DEVICE_FLAG_INPUT
183 : AUDIO_DEVICE_FLAG_OUTPUT;
184 OH_AudioDeviceDescriptorArray *descriptors =
nullptr;
185 if (OH_AudioRoutingManager_GetDevices(routing, flag, &descriptors)
186 != AUDIOCOMMON_RESULT_SUCCESS
188 qCWarning(qLcOhosAudioDevices) <<
"OH_AudioRoutingManager_GetDevices failed for"
189 << (mode == QAudioDevice::Input ?
"input" :
"output");
193 const std::optional<uint32_t> defaultDeviceId = preferredDeviceId(routing, mode);
195 QList<QAudioDevice> devices;
196 devices.reserve(descriptors->size);
197 for (uint32_t i = 0; i < descriptors->size; ++i) {
198 OH_AudioDeviceDescriptor *descriptor = descriptors->descriptors[i];
202 uint32_t deviceId = 0;
203 OH_AudioDeviceDescriptor_GetDeviceId(descriptor, &deviceId);
205 const QByteArray identifier = deviceIdentifier(descriptor);
206 const QAudioFormat preferredFormat = preferredDeviceFormat(descriptor);
207 const QString description = deviceDisplayDescription(descriptor);
208 const bool isDefault = defaultDeviceId ? deviceId == *defaultDeviceId : i == 0;
210 devices << QAudioDevicePrivate::createQAudioDevice(std::make_unique<QOhosAudioDevice>(
211 identifier, description, mode, preferredFormat,
215 OH_AudioRoutingManager_ReleaseDevices(routing, descriptors);
221QOhosAudioDevices::QOhosAudioDevices() : QPlatformAudioDevices()
223 Q_ASSERT(!g_audioDevicesInstance);
224 g_audioDevicesInstance =
this;
225 registerDeviceChangeCallbacks();
228QOhosAudioDevices::~QOhosAudioDevices()
230 unregisterDeviceChangeCallbacks();
231 QMutexLocker guard{ &g_callbackMutex };
232 g_audioDevicesInstance =
nullptr;
235void QOhosAudioDevices::registerDeviceChangeCallbacks()
237 OH_AudioRoutingManager *routing =
nullptr;
238 if (OH_AudioManager_GetAudioRoutingManager(&routing) != AUDIOCOMMON_RESULT_SUCCESS || !routing) {
239 qCWarning(qLcOhosAudioDevices)
240 <<
"Cannot register device change callbacks: routing manager unavailable";
244 const OH_AudioCommon_Result inputResult = OH_AudioRoutingManager_RegisterDeviceChangeCallback(
245 routing, AUDIO_DEVICE_FLAG_INPUT, &QOhosAudioDevices::onInputDevicesChanged);
246 const OH_AudioCommon_Result outputResult = OH_AudioRoutingManager_RegisterDeviceChangeCallback(
247 routing, AUDIO_DEVICE_FLAG_OUTPUT, &QOhosAudioDevices::onOutputDevicesChanged);
249 if (inputResult != AUDIOCOMMON_RESULT_SUCCESS || outputResult != AUDIOCOMMON_RESULT_SUCCESS)
250 qCWarning(qLcOhosAudioDevices) <<
"Failed to register audio device change callbacks";
252 m_deviceChangeCallbacksRegistered =
253 inputResult == AUDIOCOMMON_RESULT_SUCCESS || outputResult == AUDIOCOMMON_RESULT_SUCCESS;
256void QOhosAudioDevices::unregisterDeviceChangeCallbacks()
258 if (!m_deviceChangeCallbacksRegistered)
261 OH_AudioRoutingManager *routing =
nullptr;
262 if (OH_AudioManager_GetAudioRoutingManager(&routing) != AUDIOCOMMON_RESULT_SUCCESS || !routing)
265 OH_AudioRoutingManager_UnregisterDeviceChangeCallback(
266 routing, &QOhosAudioDevices::onInputDevicesChanged);
267 OH_AudioRoutingManager_UnregisterDeviceChangeCallback(
268 routing, &QOhosAudioDevices::onOutputDevicesChanged);
274int32_t QOhosAudioDevices::onInputDevicesChanged(OH_AudioDevice_ChangeType ,
275 OH_AudioDeviceDescriptorArray * )
277 QMutexLocker guard{ &g_callbackMutex };
278 if (g_audioDevicesInstance)
279 g_audioDevicesInstance->onAudioInputsChanged();
283int32_t QOhosAudioDevices::onOutputDevicesChanged(OH_AudioDevice_ChangeType ,
284 OH_AudioDeviceDescriptorArray * )
286 QMutexLocker guard{ &g_callbackMutex };
287 if (g_audioDevicesInstance)
288 g_audioDevicesInstance->onAudioOutputsChanged();
292QList<QAudioDevice> QOhosAudioDevices::findAudioInputs()
const
294 return enumerateDevices(QAudioDevice::Input);
297QList<QAudioDevice> QOhosAudioDevices::findAudioOutputs()
const
299 return enumerateDevices(QAudioDevice::Output);
302QPlatformAudioSource *QOhosAudioDevices::createAudioSource(
const QAudioDevice &device,
303 const QAudioFormat &format,
306 return new QtOHAudio::QOhosAudioSource(device, format, parent);
309QPlatformAudioSink *QOhosAudioDevices::createAudioSink(
const QAudioDevice &device,
310 const QAudioFormat &format, QObject *parent)
312 return new QtOHAudio::QOhosAudioSink(device, format, parent);
std::optional< uint32_t > preferredDeviceId(OH_AudioRoutingManager *routing, QAudioDevice::Mode mode)
QByteArray deviceIdentifier(OH_AudioDeviceDescriptor *descriptor)
QString deviceTypeLabel(OH_AudioDevice_Type type)
QAudioFormat preferredDeviceFormat(OH_AudioDeviceDescriptor *descriptor)
QList< QAudioDevice > enumerateDevices(QAudioDevice::Mode mode)
QString deviceDisplayDescription(OH_AudioDeviceDescriptor *descriptor)