8#include "private/qqnxsndaudiosource_p.h"
9#include "private/qqnxsndaudiosink_p.h"
10#include "private/qqnxsndaudiodevice_p.h"
12#include <alsa/asoundlib.h>
14#include <QtCore/qdir.h>
15#include <QtCore/qdebug.h>
16#include <QtCore/qloggingcategory.h>
29 void operator()(
char *c)
const { ::free(c); }
32using unique_str =
std::unique_ptr<
char, free_char>;
34bool operator==(
const unique_str &str, std::string_view sv)
36 return str && std::string_view{ str.get() } == sv;
38bool operator!=(
const unique_str &str, std::string_view sv)
43QList<QAudioDevice> availableDevicesViaHints(QAudioDevice::Mode mode)
45 QList<QAudioDevice> devices;
48 if (snd_device_name_hint(-1,
"pcm", &rawHints) < 0) {
49 qCWarning(lcQnxSndDevices) <<
"snd_device_name_hint failed";
54 std::string_view filter = (mode == QAudioDevice::Input) ?
"Input" :
"Output";
56 auto makeDeviceInfo = [filter, mode](
void *entry) -> std::unique_ptr<QQnxSndAudioDeviceInfo> {
57 unique_str name(snd_device_name_get_hint(entry,
"NAME"));
58 if (name && name !=
"null") {
59 unique_str descr(snd_device_name_get_hint(entry,
"DESC"));
60 unique_str io(snd_device_name_get_hint(entry,
"IOID"));
62 if (descr && (!io || (io == filter))) {
63 auto info = std::make_unique<QQnxSndAudioDeviceInfo>(
64 name.get(), QString::fromUtf8(descr.get()), mode);
73 std::vector<std::unique_ptr<QQnxSndAudioDeviceInfo>> pending;
75 for (
void **n = hints.get(); *n !=
nullptr; ++n) {
76 if (
auto info = makeDeviceInfo(*n))
77 pending.push_back(std::move(info));
85 std::sort(pending.begin(), pending.end(),
86 [](
const auto &a,
const auto &b) {
return a->id < b->id; });
88 qsizetype defaultIdx = -1;
89 qsizetype preferredIdx = -1;
90 for (qsizetype i = 0; i <
static_cast<qsizetype>(pending.size()); ++i) {
91 if (defaultIdx < 0 && pending[i]->id.startsWith(
"default"))
93 if (preferredIdx < 0 && pending[i]->id.contains(
"pcmPreferred"))
97 const qsizetype chosen = defaultIdx >= 0 ? defaultIdx
98 : preferredIdx >= 0 ? preferredIdx
99 : pending.empty() ? -1
102 pending[chosen]->isDefault =
true;
104 devices.reserve(pending.size());
106 for (
auto &&info : pending)
107 devices.append(QAudioDevicePrivate::createQAudioDevice(std::move(info)));
112bool hasDeviceFilesForMode(QAudioDevice::Mode mode)
114 QDir dir(QStringLiteral(
"/dev/snd"));
115 const char16_t suffix = mode == QAudioDevice::Input ? u'c' : u'p';
116 for (
const QString &entry : dir.entryList(QDir::Files)) {
117 if (entry.startsWith(QStringLiteral(
"pcm")) && entry.back() == suffix)
125QQnxSndAudioDevices::QQnxSndAudioDevices() =
default;
129 QList<QAudioDevice> devices = availableDevicesViaHints(mode);
135 if (!devices.isEmpty() && !hasDeviceFilesForMode(mode)) {
136 qCDebug(lcQnxSndDevices) <<
"No /dev/snd/ device files for"
137 << (mode == QAudioDevice::Input ?
"capture" :
"playback")
138 <<
"- discarding" << devices.size() <<
"hint-reported device(s)";
142 if (devices.isEmpty())
143 qCWarning(lcQnxSndDevices) <<
"No audio devices found for"
144 << (mode == QAudioDevice::Input ?
"input" :
"output");
148QList<QAudioDevice> QQnxSndAudioDevices::findAudioInputs()
const
150 return availableDevices(QAudioDevice::Input);
153QList<QAudioDevice> QQnxSndAudioDevices::findAudioOutputs()
const
155 return availableDevices(QAudioDevice::Output);
158QPlatformAudioSource *QQnxSndAudioDevices::createAudioSource(
const QAudioDevice &deviceInfo,
159 const QAudioFormat &fmt,
162 return new QQnxSndAudioSource(deviceInfo, fmt, parent);
165QPlatformAudioSink *QQnxSndAudioDevices::createAudioSink(
const QAudioDevice &deviceInfo,
166 const QAudioFormat &fmt,
169 return new QQnxSndAudioSink(deviceInfo, fmt, parent);
std::unique_ptr< void *, HintsDeleter > HintsGuard
Q_LOGGING_CATEGORY(lcEventDispatcher, "qt.eventdispatcher")
static QList< QAudioDevice > availableDevices(QAudioDevice::Mode mode)