1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include <QtCore/qdebug.h>
41
42#include "qaudiosystem.h"
43#include "qaudiosystemplugin.h"
44#include "qaudiosystempluginext_p.h"
45
46#include "qmediapluginloader_p.h"
47#include "qaudiodevicefactory_p.h"
48
49QT_BEGIN_NAMESPACE
50
51static QString defaultKey()
52{
53 return QStringLiteral("default");
54}
55
56#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS)
57Q_GLOBAL_STATIC_WITH_ARGS(QMediaPluginLoader, audioLoader,
58 (QAudioSystemFactoryInterface_iid, QLatin1String("audio"), Qt::CaseInsensitive))
59#endif
60
61class QNullDeviceInfo : public QAbstractAudioDeviceInfo
62{
63public:
64 QAudioFormat preferredFormat() const override { qWarning()<<"using null deviceinfo, none available"; return QAudioFormat(); }
65 bool isFormatSupported(const QAudioFormat& ) const override { return false; }
66 QAudioFormat nearestFormat(const QAudioFormat& ) const { return QAudioFormat(); }
67 QString deviceName() const override { return QString(); }
68 QStringList supportedCodecs() override { return QStringList(); }
69 QList<int> supportedSampleRates() override { return QList<int>(); }
70 QList<int> supportedChannelCounts() override { return QList<int>(); }
71 QList<int> supportedSampleSizes() override { return QList<int>(); }
72 QList<QAudioFormat::Endian> supportedByteOrders() override { return QList<QAudioFormat::Endian>(); }
73 QList<QAudioFormat::SampleType> supportedSampleTypes() override { return QList<QAudioFormat::SampleType>(); }
74};
75
76class QNullInputDevice : public QAbstractAudioInput
77{
78public:
79 void start(QIODevice*) override { qWarning()<<"using null input device, none available";}
80 QIODevice *start() override { qWarning()<<"using null input device, none available"; return nullptr; }
81 void stop() override {}
82 void reset() override {}
83 void suspend() override {}
84 void resume() override {}
85 int bytesReady() const override { return 0; }
86 int periodSize() const override { return 0; }
87 void setBufferSize(int ) override {}
88 int bufferSize() const override { return 0; }
89 void setNotifyInterval(int ) override {}
90 int notifyInterval() const override { return 0; }
91 qint64 processedUSecs() const override { return 0; }
92 qint64 elapsedUSecs() const override { return 0; }
93 QAudio::Error error() const override { return QAudio::OpenError; }
94 QAudio::State state() const override { return QAudio::StoppedState; }
95 void setFormat(const QAudioFormat&) override {}
96 QAudioFormat format() const override { return QAudioFormat(); }
97 void setVolume(qreal) override {}
98 qreal volume() const override {return 1.0f;}
99};
100
101class QNullOutputDevice : public QAbstractAudioOutput
102{
103public:
104 void start(QIODevice*) override {qWarning()<<"using null output device, none available";}
105 QIODevice *start() override { qWarning()<<"using null output device, none available"; return nullptr; }
106 void stop() override {}
107 void reset() override {}
108 void suspend() override {}
109 void resume() override {}
110 int bytesFree() const override { return 0; }
111 int periodSize() const override { return 0; }
112 void setBufferSize(int ) override {}
113 int bufferSize() const override { return 0; }
114 void setNotifyInterval(int ) override {}
115 int notifyInterval() const override { return 0; }
116 qint64 processedUSecs() const override { return 0; }
117 qint64 elapsedUSecs() const override { return 0; }
118 QAudio::Error error() const override { return QAudio::OpenError; }
119 QAudio::State state() const override { return QAudio::StoppedState; }
120 void setFormat(const QAudioFormat&) override {}
121 QAudioFormat format() const override { return QAudioFormat(); }
122};
123
124QList<QAudioDeviceInfo> QAudioDeviceFactory::availableDevices(QAudio::Mode mode)
125{
126 QList<QAudioDeviceInfo> devices;
127#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS)
128 QMediaPluginLoader* l = audioLoader();
129 const auto keys = l->keys();
130 for (const QString& key : keys) {
131 QAudioSystemFactoryInterface* plugin = qobject_cast<QAudioSystemFactoryInterface*>(object: l->instance(key));
132 if (plugin) {
133 const auto availableDevices = plugin->availableDevices(mode);
134 for (const QByteArray& handle : availableDevices)
135 devices << QAudioDeviceInfo(key, handle, mode);
136 }
137 }
138#endif
139
140 return devices;
141}
142
143QAudioDeviceInfo QAudioDeviceFactory::defaultDevice(QAudio::Mode mode)
144{
145#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS)
146 QMediaPluginLoader* l = audioLoader();
147
148 // Check if there is a default plugin.
149 QAudioSystemFactoryInterface *plugin = qobject_cast<QAudioSystemFactoryInterface *>(object: l->instance(key: defaultKey()));
150 if (plugin) {
151 // Check if the plugin has the extension interface.
152 QAudioSystemPluginExtension *pluginExt = qobject_cast<QAudioSystemPluginExtension *>(object: l->instance(key: defaultKey()));
153 // Ask for the default device.
154 if (pluginExt) {
155 const QByteArray &device = pluginExt->defaultDevice(mode);
156 if (!device.isEmpty())
157 return QAudioDeviceInfo(defaultKey(), device, mode);
158 }
159
160 // If there were no default devices, e.g., if the plugin did not implement the extent-ion interface,
161 // then just pick the first device that's available.
162 const auto &devices = plugin->availableDevices(mode);
163 if (!devices.isEmpty())
164 return QAudioDeviceInfo(defaultKey(), devices.first(), mode);
165 }
166
167 // If no plugin is marked as default, check the other plugins.
168 // Note: We're going to prioritize plugins that report a default device.
169 const auto &keys = l->keys();
170 QAudioDeviceInfo fallbackDevice;
171 for (const auto &key : keys) {
172 if (key == defaultKey())
173 continue;
174 QAudioSystemFactoryInterface* plugin = qobject_cast<QAudioSystemFactoryInterface*>(object: l->instance(key));
175 if (plugin) {
176 // Check if the plugin has the extent-ion interface.
177 QAudioSystemPluginExtension *pluginExt = qobject_cast<QAudioSystemPluginExtension *>(object: l->instance(key));
178 if (pluginExt) {
179 const QByteArray &device = pluginExt->defaultDevice(mode);
180 if (!device.isEmpty())
181 return QAudioDeviceInfo(key, device, mode);
182 } else if (fallbackDevice.isNull()) {
183 const auto &devices = plugin->availableDevices(mode);
184 if (!devices.isEmpty())
185 fallbackDevice = QAudioDeviceInfo(key, devices.first(), mode);
186 }
187 }
188 }
189
190#endif
191
192 return QAudioDeviceInfo();
193}
194
195QAbstractAudioDeviceInfo* QAudioDeviceFactory::audioDeviceInfo(const QString &realm, const QByteArray &handle, QAudio::Mode mode)
196{
197 QAbstractAudioDeviceInfo *rc = nullptr;
198
199#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS)
200 QAudioSystemFactoryInterface* plugin =
201 qobject_cast<QAudioSystemFactoryInterface*>(object: audioLoader()->instance(key: realm));
202
203 if (plugin)
204 rc = plugin->createDeviceInfo(device: handle, mode);
205#endif
206
207 return rc == nullptr ? new QNullDeviceInfo() : rc;
208}
209
210QAbstractAudioInput* QAudioDeviceFactory::createDefaultInputDevice(QAudioFormat const &format)
211{
212 return createInputDevice(device: defaultDevice(mode: QAudio::AudioInput), format);
213}
214
215QAbstractAudioOutput* QAudioDeviceFactory::createDefaultOutputDevice(QAudioFormat const &format)
216{
217 return createOutputDevice(device: defaultDevice(mode: QAudio::AudioOutput), format);
218}
219
220QAbstractAudioInput* QAudioDeviceFactory::createInputDevice(QAudioDeviceInfo const& deviceInfo, QAudioFormat const &format)
221{
222 if (deviceInfo.isNull())
223 return new QNullInputDevice();
224
225#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS)
226 QAudioSystemFactoryInterface* plugin =
227 qobject_cast<QAudioSystemFactoryInterface*>(object: audioLoader()->instance(key: deviceInfo.realm()));
228
229 if (plugin) {
230 QAbstractAudioInput* p = plugin->createInput(device: deviceInfo.handle());
231 if (p) p->setFormat(format);
232 return p;
233 }
234#endif
235
236 return new QNullInputDevice();
237}
238
239QAbstractAudioOutput* QAudioDeviceFactory::createOutputDevice(QAudioDeviceInfo const& deviceInfo, QAudioFormat const &format)
240{
241 if (deviceInfo.isNull())
242 return new QNullOutputDevice();
243
244#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS)
245 QAudioSystemFactoryInterface* plugin =
246 qobject_cast<QAudioSystemFactoryInterface*>(object: audioLoader()->instance(key: deviceInfo.realm()));
247
248 if (plugin) {
249 QAbstractAudioOutput* p = plugin->createOutput(device: deviceInfo.handle());
250 if (p) p->setFormat(format);
251 return p;
252 }
253#endif
254
255 return new QNullOutputDevice();
256}
257
258QT_END_NAMESPACE
259
260

source code of qtmultimedia/src/multimedia/audio/qaudiodevicefactory.cpp