File indexing completed on 2024-04-14 14:17:19

0001 /*
0002  * SPDX-FileCopyrightText: 2019 Manuel Weichselbaumer <mincequi@web.de>
0003  *
0004  * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0005  */
0006 
0007 #include "mediatransporttest.h"
0008 #include "a2dp-codecs.h"
0009 #include "autotests.h"
0010 #include "initmanagerjob.h"
0011 #include "pendingcall.h"
0012 #include "services.h"
0013 
0014 #include <QSignalSpy>
0015 #include <QTest>
0016 
0017 namespace BluezQt
0018 {
0019 extern void bluezqt_initFakeBluezTestRun();
0020 }
0021 
0022 using namespace BluezQt;
0023 
0024 Q_DECLARE_METATYPE(MediaTransport::State)
0025 
0026 static a2dp_sbc_t sbcConfiguration;
0027 static a2dp_aac_t aacConfiguration;
0028 
0029 static AudioCodec charToCodec(uchar value)
0030 {
0031     switch (value) {
0032     case A2DP_CODEC_SBC:
0033         return AudioCodec::Sbc;
0034         break;
0035     case A2DP_CODEC_MPEG24:
0036         return AudioCodec::Aac;
0037         break;
0038     }
0039 
0040     return AudioCodec::Invalid;
0041 }
0042 
0043 static AudioSampleRate byteArrayToSampleRate(AudioCodec codec, const QByteArray &buffer)
0044 {
0045     switch (codec) {
0046     case AudioCodec::Sbc: {
0047         if (buffer.size() != sizeof(a2dp_sbc_t)) {
0048             return AudioSampleRate::Invalid;
0049         }
0050 
0051         a2dp_sbc_t sbcConfig = *reinterpret_cast<const a2dp_sbc_t *>(buffer.constData());
0052         switch (sbcConfig.frequency) {
0053         case SBC_SAMPLING_FREQ_44100:
0054             return AudioSampleRate::Rate44100;
0055             break;
0056         case SBC_SAMPLING_FREQ_48000:
0057             return AudioSampleRate::Rate48000;
0058             break;
0059         }
0060         break;
0061     }
0062     case AudioCodec::Aac: {
0063         if (buffer.size() != sizeof(a2dp_aac_t)) {
0064             return AudioSampleRate::Invalid;
0065         }
0066 
0067         a2dp_aac_t aacConfig = *reinterpret_cast<const a2dp_aac_t *>(buffer.constData());
0068         switch (AAC_GET_FREQUENCY(aacConfig)) {
0069         case AAC_SAMPLING_FREQ_44100:
0070             return AudioSampleRate::Rate44100;
0071             break;
0072         case AAC_SAMPLING_FREQ_48000:
0073             return AudioSampleRate::Rate48000;
0074             break;
0075         }
0076         break;
0077     }
0078     }
0079 
0080     return AudioSampleRate::Invalid;
0081 }
0082 
0083 QString stateString(MediaTransport::State state)
0084 {
0085     switch (state) {
0086     case MediaTransport::State::Idle:
0087         return QStringLiteral("idle");
0088     case MediaTransport::State::Pending:
0089         return QStringLiteral("pending");
0090     case MediaTransport::State::Active:
0091         return QStringLiteral("active");
0092     }
0093 
0094     return {};
0095 }
0096 
0097 MediaTransportTest::MediaTransportTest()
0098     : m_manager(nullptr)
0099 {
0100     Autotests::registerMetatypes();
0101 
0102     qRegisterMetaType<MediaTransport::State>("State");
0103 
0104     sbcConfiguration.frequency = SBC_SAMPLING_FREQ_44100;
0105     AAC_SET_FREQUENCY(aacConfiguration, AAC_SAMPLING_FREQ_48000);
0106 }
0107 
0108 void MediaTransportTest::initTestCase()
0109 {
0110     bluezqt_initFakeBluezTestRun();
0111 
0112     FakeBluez::start();
0113     FakeBluez::runTest(QStringLiteral("bluez-standard"));
0114 
0115     // Create adapter
0116     QString adapter = QStringLiteral("/org/bluez/hci0");
0117     QVariantMap adapterProps;
0118     adapterProps[QStringLiteral("Path")] = QVariant::fromValue(QDBusObjectPath(adapter));
0119     adapterProps[QStringLiteral("Address")] = QStringLiteral("1C:E5:C3:BC:94:7E");
0120     adapterProps[QStringLiteral("Name")] = QStringLiteral("TestAdapter");
0121     FakeBluez::runAction(QStringLiteral("devicemanager"), QStringLiteral("create-adapter"), adapterProps);
0122 
0123     // Create devices
0124     QVariantMap deviceProps;
0125     QVariantMap mediaTransportProps;
0126 
0127     QString device1 = adapter + QLatin1String("/dev_40_79_6A_0C_39_75");
0128     deviceProps[QStringLiteral("Path")] = QVariant::fromValue(QDBusObjectPath(device1));
0129     deviceProps[QStringLiteral("Adapter")] = QVariant::fromValue(QDBusObjectPath(adapter));
0130     deviceProps[QStringLiteral("Address")] = QStringLiteral("40:79:6A:0C:39:75");
0131     deviceProps[QStringLiteral("Name")] = QStringLiteral("TestDevice");
0132     deviceProps[QStringLiteral("UUIDs")] = QStringList(Services::AudioSink);
0133     mediaTransportProps[QStringLiteral("Path")] = QVariant::fromValue(QDBusObjectPath(device1 + QLatin1String("/fd0")));
0134     mediaTransportProps[QStringLiteral("Device")] = QVariant::fromValue(QDBusObjectPath(device1));
0135     mediaTransportProps[QStringLiteral("UUID")] = Services::AudioSink;
0136     mediaTransportProps[QStringLiteral("Codec")] = QVariant::fromValue(quint8(A2DP_CODEC_SBC)); // SBC
0137     mediaTransportProps[QStringLiteral("Configuration")] =
0138         QVariant::fromValue(QByteArray(reinterpret_cast<const char *>(&sbcConfiguration), sizeof(sbcConfiguration)));
0139     mediaTransportProps[QStringLiteral("State")] = QStringLiteral("pending");
0140     mediaTransportProps[QStringLiteral("Volume")] = QVariant::fromValue(quint16(63));
0141     deviceProps[QStringLiteral("MediaTransport")] = mediaTransportProps;
0142     FakeBluez::runAction(QStringLiteral("devicemanager"), QStringLiteral("create-device"), deviceProps);
0143 
0144     QString device2 = adapter + QLatin1String("/dev_50_79_6A_0C_39_75");
0145     deviceProps[QStringLiteral("Path")] = QVariant::fromValue(QDBusObjectPath(device2));
0146     deviceProps[QStringLiteral("Adapter")] = QVariant::fromValue(QDBusObjectPath(adapter));
0147     deviceProps[QStringLiteral("Address")] = QStringLiteral("50:79:6A:0C:39:75");
0148     deviceProps[QStringLiteral("Name")] = QStringLiteral("TestDevice2");
0149     deviceProps[QStringLiteral("UUIDs")] = QStringList(Services::AudioSink);
0150     mediaTransportProps[QStringLiteral("Path")] = QVariant::fromValue(QDBusObjectPath(device2 + QLatin1String("/fd0")));
0151     mediaTransportProps[QStringLiteral("Device")] = QVariant::fromValue(QDBusObjectPath(device2));
0152     mediaTransportProps[QStringLiteral("UUID")] = Services::AudioSink;
0153     mediaTransportProps[QStringLiteral("Codec")] = QVariant::fromValue(quint8(A2DP_CODEC_MPEG24)); // AAC
0154     mediaTransportProps[QStringLiteral("Configuration")] =
0155         QVariant::fromValue(QByteArray(reinterpret_cast<const char *>(&aacConfiguration), sizeof(aacConfiguration)));
0156     mediaTransportProps[QStringLiteral("State")] = QStringLiteral("active");
0157     mediaTransportProps[QStringLiteral("Volume")] = QVariant::fromValue(quint16(127));
0158     deviceProps[QStringLiteral("MediaTransport")] = mediaTransportProps;
0159     FakeBluez::runAction(QStringLiteral("devicemanager"), QStringLiteral("create-device"), deviceProps);
0160 
0161     m_manager = new Manager();
0162     InitManagerJob *initJob = m_manager->init();
0163     initJob->exec();
0164     QVERIFY(!initJob->error());
0165 
0166     QCOMPARE(m_manager->adapters().count(), 1);
0167     QCOMPARE(m_manager->devices().count(), 2);
0168 }
0169 
0170 void MediaTransportTest::cleanupTestCase()
0171 {
0172     for (const MediaTransportUnit &unit : m_units) {
0173         delete unit.dbusMediaTransport;
0174         delete unit.dbusProperties;
0175     }
0176 
0177     delete m_manager;
0178 
0179     FakeBluez::stop();
0180 }
0181 
0182 void MediaTransportTest::connectTest()
0183 {
0184     for (DevicePtr device : m_manager->devices()) {
0185         QVERIFY(!device->ubi().isEmpty());
0186         QVERIFY(!device->mediaTransport());
0187 
0188         QSignalSpy deviceSpy(device.data(), SIGNAL(mediaTransportChanged(MediaTransportPtr)));
0189 
0190         device->connectToDevice();
0191         QTRY_COMPARE(deviceSpy.count(), 1);
0192         QVERIFY(device->mediaTransport());
0193     }
0194 }
0195 
0196 void MediaTransportTest::disconnectTest()
0197 {
0198     for (DevicePtr device : m_manager->devices()) {
0199         QVERIFY(device->mediaTransport());
0200 
0201         QSignalSpy deviceSpy(device.data(), SIGNAL(mediaTransportChanged(MediaTransportPtr)));
0202 
0203         device->disconnectFromDevice();
0204         QTRY_COMPARE(deviceSpy.count(), 1);
0205         QVERIFY(!device->mediaTransport());
0206     }
0207 }
0208 
0209 void MediaTransportTest::connectProfileTest()
0210 {
0211     QDBusConnection connection = QDBusConnection::sessionBus();
0212     QString service = QStringLiteral("org.kde.bluezqt.fakebluez");
0213 
0214     for (DevicePtr device : m_manager->devices()) {
0215         QVERIFY(!device->ubi().isEmpty());
0216         QVERIFY(!device->mediaTransport());
0217 
0218         QSignalSpy deviceSpy(device.data(), SIGNAL(mediaTransportChanged(MediaTransportPtr)));
0219 
0220         device->connectProfile(Services::AudioSink);
0221         QTRY_COMPARE(deviceSpy.count(), 1);
0222         QVERIFY(device->mediaTransport());
0223 
0224         QString path = device->ubi() + QLatin1String("/fd0");
0225 
0226         MediaTransportUnit unit;
0227         unit.device = device;
0228         unit.dbusMediaTransport = new org::bluez::MediaTransport1(service, path, connection, this);
0229         unit.dbusProperties = new org::freedesktop::DBus::Properties(service, path, connection, this);
0230         m_units.append(unit);
0231     }
0232 }
0233 
0234 void MediaTransportTest::getPropertiesTest()
0235 {
0236     for (const MediaTransportUnit &unit : m_units) {
0237         QCOMPARE(unit.device->mediaTransport()->audioConfiguration().codec, charToCodec(unit.dbusMediaTransport->codec()));
0238         QCOMPARE(unit.device->mediaTransport()->audioConfiguration().sampleRate,
0239                  byteArrayToSampleRate(unit.device->mediaTransport()->audioConfiguration().codec, unit.dbusMediaTransport->configuration()));
0240         QCOMPARE(stateString(unit.device->mediaTransport()->state()), unit.dbusMediaTransport->state());
0241         QCOMPARE(unit.device->mediaTransport()->volume(), unit.dbusMediaTransport->volume());
0242     }
0243 }
0244 
0245 void MediaTransportTest::disconnectProfileTest()
0246 {
0247     for (const MediaTransportUnit &unit : m_units) {
0248         QVERIFY(unit.device->mediaTransport());
0249 
0250         QSignalSpy deviceSpy(unit.device.data(), SIGNAL(mediaTransportChanged(MediaTransportPtr)));
0251 
0252         unit.device->disconnectProfile(Services::AudioSink);
0253         QTRY_COMPARE(deviceSpy.count(), 1);
0254         QVERIFY(!unit.device->mediaTransport());
0255     }
0256 }
0257 
0258 QTEST_MAIN(MediaTransportTest)
0259 
0260 #include "moc_mediatransporttest.cpp"