1 | /* |
2 | * SPDX-FileCopyrightText: 2019 Manuel Weichselbaumer <mincequi@web.de> |
3 | * |
4 | * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL |
5 | */ |
6 | |
7 | #include "mediatransporttest.h" |
8 | #include "a2dp-codecs.h" |
9 | #include "autotests.h" |
10 | #include "initmanagerjob.h" |
11 | #include "pendingcall.h" |
12 | #include "services.h" |
13 | |
14 | #include <QSignalSpy> |
15 | #include <QTest> |
16 | |
17 | namespace BluezQt |
18 | { |
19 | extern void bluezqt_initFakeBluezTestRun(); |
20 | } |
21 | |
22 | using namespace BluezQt; |
23 | |
24 | Q_DECLARE_METATYPE(MediaTransport::State) |
25 | |
26 | static a2dp_sbc_t sbcConfiguration; |
27 | static a2dp_aac_t aacConfiguration; |
28 | |
29 | static AudioCodec charToCodec(uchar value) |
30 | { |
31 | switch (value) { |
32 | case A2DP_CODEC_SBC: |
33 | return AudioCodec::Sbc; |
34 | break; |
35 | case A2DP_CODEC_MPEG24: |
36 | return AudioCodec::Aac; |
37 | break; |
38 | } |
39 | |
40 | return AudioCodec::Invalid; |
41 | } |
42 | |
43 | static AudioSampleRate byteArrayToSampleRate(AudioCodec codec, const QByteArray &buffer) |
44 | { |
45 | switch (codec) { |
46 | case AudioCodec::Sbc: { |
47 | if (buffer.size() != sizeof(a2dp_sbc_t)) { |
48 | return AudioSampleRate::Invalid; |
49 | } |
50 | |
51 | a2dp_sbc_t sbcConfig = *reinterpret_cast<const a2dp_sbc_t *>(buffer.constData()); |
52 | switch (sbcConfig.frequency) { |
53 | case SBC_SAMPLING_FREQ_44100: |
54 | return AudioSampleRate::Rate44100; |
55 | break; |
56 | case SBC_SAMPLING_FREQ_48000: |
57 | return AudioSampleRate::Rate48000; |
58 | break; |
59 | } |
60 | break; |
61 | } |
62 | case AudioCodec::Aac: { |
63 | if (buffer.size() != sizeof(a2dp_aac_t)) { |
64 | return AudioSampleRate::Invalid; |
65 | } |
66 | |
67 | a2dp_aac_t aacConfig = *reinterpret_cast<const a2dp_aac_t *>(buffer.constData()); |
68 | switch (AAC_GET_FREQUENCY(aacConfig)) { |
69 | case AAC_SAMPLING_FREQ_44100: |
70 | return AudioSampleRate::Rate44100; |
71 | break; |
72 | case AAC_SAMPLING_FREQ_48000: |
73 | return AudioSampleRate::Rate48000; |
74 | break; |
75 | } |
76 | break; |
77 | } |
78 | } |
79 | |
80 | return AudioSampleRate::Invalid; |
81 | } |
82 | |
83 | QString stateString(MediaTransport::State state) |
84 | { |
85 | switch (state) { |
86 | case MediaTransport::State::Idle: |
87 | return QStringLiteral("idle" ); |
88 | case MediaTransport::State::Pending: |
89 | return QStringLiteral("pending" ); |
90 | case MediaTransport::State::Active: |
91 | return QStringLiteral("active" ); |
92 | } |
93 | |
94 | return {}; |
95 | } |
96 | |
97 | MediaTransportTest::MediaTransportTest() |
98 | : m_manager(nullptr) |
99 | { |
100 | Autotests::registerMetatypes(); |
101 | |
102 | qRegisterMetaType<MediaTransport::State>("State" ); |
103 | |
104 | sbcConfiguration.frequency = SBC_SAMPLING_FREQ_44100; |
105 | AAC_SET_FREQUENCY(aacConfiguration, AAC_SAMPLING_FREQ_48000); |
106 | } |
107 | |
108 | void MediaTransportTest::initTestCase() |
109 | { |
110 | bluezqt_initFakeBluezTestRun(); |
111 | |
112 | FakeBluez::start(); |
113 | FakeBluez::runTest(QStringLiteral("bluez-standard" )); |
114 | |
115 | // Create adapter |
116 | QString adapter = QStringLiteral("/org/bluez/hci0" ); |
117 | QVariantMap adapterProps; |
118 | adapterProps[QStringLiteral("Path" )] = QVariant::fromValue(QDBusObjectPath(adapter)); |
119 | adapterProps[QStringLiteral("Address" )] = QStringLiteral("1C:E5:C3:BC:94:7E" ); |
120 | adapterProps[QStringLiteral("Name" )] = QStringLiteral("TestAdapter" ); |
121 | FakeBluez::runAction(QStringLiteral("devicemanager" ), QStringLiteral("create-adapter" ), adapterProps); |
122 | |
123 | // Create devices |
124 | QVariantMap deviceProps; |
125 | QVariantMap mediaTransportProps; |
126 | |
127 | QString device1 = adapter + QLatin1String("/dev_40_79_6A_0C_39_75" ); |
128 | deviceProps[QStringLiteral("Path" )] = QVariant::fromValue(QDBusObjectPath(device1)); |
129 | deviceProps[QStringLiteral("Adapter" )] = QVariant::fromValue(QDBusObjectPath(adapter)); |
130 | deviceProps[QStringLiteral("Address" )] = QStringLiteral("40:79:6A:0C:39:75" ); |
131 | deviceProps[QStringLiteral("Name" )] = QStringLiteral("TestDevice" ); |
132 | deviceProps[QStringLiteral("UUIDs" )] = QStringList(Services::AudioSink); |
133 | mediaTransportProps[QStringLiteral("Path" )] = QVariant::fromValue(QDBusObjectPath(device1 + QLatin1String("/fd0" ))); |
134 | mediaTransportProps[QStringLiteral("Device" )] = QVariant::fromValue(QDBusObjectPath(device1)); |
135 | mediaTransportProps[QStringLiteral("UUID" )] = Services::AudioSink; |
136 | mediaTransportProps[QStringLiteral("Codec" )] = QVariant::fromValue(quint8(A2DP_CODEC_SBC)); // SBC |
137 | mediaTransportProps[QStringLiteral("Configuration" )] = |
138 | QVariant::fromValue(QByteArray(reinterpret_cast<const char *>(&sbcConfiguration), sizeof(sbcConfiguration))); |
139 | mediaTransportProps[QStringLiteral("State" )] = QStringLiteral("pending" ); |
140 | mediaTransportProps[QStringLiteral("Volume" )] = QVariant::fromValue(quint16(63)); |
141 | deviceProps[QStringLiteral("MediaTransport" )] = mediaTransportProps; |
142 | FakeBluez::runAction(QStringLiteral("devicemanager" ), QStringLiteral("create-device" ), deviceProps); |
143 | |
144 | QString device2 = adapter + QLatin1String("/dev_50_79_6A_0C_39_75" ); |
145 | deviceProps[QStringLiteral("Path" )] = QVariant::fromValue(QDBusObjectPath(device2)); |
146 | deviceProps[QStringLiteral("Adapter" )] = QVariant::fromValue(QDBusObjectPath(adapter)); |
147 | deviceProps[QStringLiteral("Address" )] = QStringLiteral("50:79:6A:0C:39:75" ); |
148 | deviceProps[QStringLiteral("Name" )] = QStringLiteral("TestDevice2" ); |
149 | deviceProps[QStringLiteral("UUIDs" )] = QStringList(Services::AudioSink); |
150 | mediaTransportProps[QStringLiteral("Path" )] = QVariant::fromValue(QDBusObjectPath(device2 + QLatin1String("/fd0" ))); |
151 | mediaTransportProps[QStringLiteral("Device" )] = QVariant::fromValue(QDBusObjectPath(device2)); |
152 | mediaTransportProps[QStringLiteral("UUID" )] = Services::AudioSink; |
153 | mediaTransportProps[QStringLiteral("Codec" )] = QVariant::fromValue(quint8(A2DP_CODEC_MPEG24)); // AAC |
154 | mediaTransportProps[QStringLiteral("Configuration" )] = |
155 | QVariant::fromValue(QByteArray(reinterpret_cast<const char *>(&aacConfiguration), sizeof(aacConfiguration))); |
156 | mediaTransportProps[QStringLiteral("State" )] = QStringLiteral("active" ); |
157 | mediaTransportProps[QStringLiteral("Volume" )] = QVariant::fromValue(quint16(127)); |
158 | deviceProps[QStringLiteral("MediaTransport" )] = mediaTransportProps; |
159 | FakeBluez::runAction(QStringLiteral("devicemanager" ), QStringLiteral("create-device" ), deviceProps); |
160 | |
161 | m_manager = new Manager(); |
162 | InitManagerJob *initJob = m_manager->init(); |
163 | initJob->exec(); |
164 | QVERIFY(!initJob->error()); |
165 | |
166 | QCOMPARE(m_manager->adapters().count(), 1); |
167 | QCOMPARE(m_manager->devices().count(), 2); |
168 | } |
169 | |
170 | void MediaTransportTest::cleanupTestCase() |
171 | { |
172 | for (const MediaTransportUnit &unit : m_units) { |
173 | delete unit.dbusMediaTransport; |
174 | delete unit.dbusProperties; |
175 | } |
176 | |
177 | delete m_manager; |
178 | |
179 | FakeBluez::stop(); |
180 | } |
181 | |
182 | void MediaTransportTest::connectTest() |
183 | { |
184 | for (DevicePtr device : m_manager->devices()) { |
185 | QVERIFY(!device->ubi().isEmpty()); |
186 | QVERIFY(!device->mediaTransport()); |
187 | |
188 | QSignalSpy deviceSpy(device.data(), SIGNAL(mediaTransportChanged(MediaTransportPtr))); |
189 | |
190 | device->connectToDevice(); |
191 | QTRY_COMPARE(deviceSpy.count(), 1); |
192 | QVERIFY(device->mediaTransport()); |
193 | } |
194 | } |
195 | |
196 | void MediaTransportTest::disconnectTest() |
197 | { |
198 | for (DevicePtr device : m_manager->devices()) { |
199 | QVERIFY(device->mediaTransport()); |
200 | |
201 | QSignalSpy deviceSpy(device.data(), SIGNAL(mediaTransportChanged(MediaTransportPtr))); |
202 | |
203 | device->disconnectFromDevice(); |
204 | QTRY_COMPARE(deviceSpy.count(), 1); |
205 | QVERIFY(!device->mediaTransport()); |
206 | } |
207 | } |
208 | |
209 | void MediaTransportTest::connectProfileTest() |
210 | { |
211 | QDBusConnection connection = QDBusConnection::sessionBus(); |
212 | QString service = QStringLiteral("org.kde.bluezqt.fakebluez" ); |
213 | |
214 | for (DevicePtr device : m_manager->devices()) { |
215 | QVERIFY(!device->ubi().isEmpty()); |
216 | QVERIFY(!device->mediaTransport()); |
217 | |
218 | QSignalSpy deviceSpy(device.data(), SIGNAL(mediaTransportChanged(MediaTransportPtr))); |
219 | |
220 | device->connectProfile(Services::AudioSink); |
221 | QTRY_COMPARE(deviceSpy.count(), 1); |
222 | QVERIFY(device->mediaTransport()); |
223 | |
224 | QString path = device->ubi() + QLatin1String("/fd0" ); |
225 | |
226 | MediaTransportUnit unit; |
227 | unit.device = device; |
228 | unit.dbusMediaTransport = new org::bluez::MediaTransport1(service, path, connection, this); |
229 | unit.dbusProperties = new org::freedesktop::DBus::Properties(service, path, connection, this); |
230 | m_units.append(unit); |
231 | } |
232 | } |
233 | |
234 | void MediaTransportTest::getPropertiesTest() |
235 | { |
236 | for (const MediaTransportUnit &unit : m_units) { |
237 | QCOMPARE(unit.device->mediaTransport()->audioConfiguration().codec, charToCodec(unit.dbusMediaTransport->codec())); |
238 | QCOMPARE(unit.device->mediaTransport()->audioConfiguration().sampleRate, |
239 | byteArrayToSampleRate(unit.device->mediaTransport()->audioConfiguration().codec, unit.dbusMediaTransport->configuration())); |
240 | QCOMPARE(stateString(unit.device->mediaTransport()->state()), unit.dbusMediaTransport->state()); |
241 | QCOMPARE(unit.device->mediaTransport()->volume(), unit.dbusMediaTransport->volume()); |
242 | } |
243 | } |
244 | |
245 | void MediaTransportTest::disconnectProfileTest() |
246 | { |
247 | for (const MediaTransportUnit &unit : m_units) { |
248 | QVERIFY(unit.device->mediaTransport()); |
249 | |
250 | QSignalSpy deviceSpy(unit.device.data(), SIGNAL(mediaTransportChanged(MediaTransportPtr))); |
251 | |
252 | unit.device->disconnectProfile(Services::AudioSink); |
253 | QTRY_COMPARE(deviceSpy.count(), 1); |
254 | QVERIFY(!unit.device->mediaTransport()); |
255 | } |
256 | } |
257 | |
258 | QTEST_MAIN(MediaTransportTest) |
259 | |
260 | #include "moc_mediatransporttest.cpp" |
261 | |