File indexing completed on 2024-04-28 15:17:55

0001 /*
0002  * BluezQt - Asynchronous Bluez wrapper library
0003  *
0004  * SPDX-FileCopyrightText: 2019 Manuel Weichselbaumer <mincequi@web.de>
0005  *
0006  * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0007  */
0008 
0009 #include "mediatransport_p.h"
0010 #include "a2dp-codecs.h"
0011 #include "macros.h"
0012 #include "utils.h"
0013 
0014 namespace BluezQt
0015 {
0016 static MediaTransport::State stringToState(const QString &state)
0017 {
0018     if (state == QLatin1String("pending")) {
0019         return MediaTransport::State::Pending;
0020     } else if (state == QLatin1String("active")) {
0021         return MediaTransport::State::Active;
0022     }
0023     return MediaTransport::State::Idle;
0024 }
0025 
0026 static AudioCodec intToCodec(int value)
0027 {
0028     switch (value) {
0029     case A2DP_CODEC_SBC:
0030         return AudioCodec::Sbc;
0031         break;
0032     case A2DP_CODEC_MPEG24:
0033         return AudioCodec::Aac;
0034         break;
0035     }
0036 
0037     return AudioCodec::Invalid;
0038 }
0039 
0040 static AudioSampleRate byteArrayToSampleRate(AudioCodec codec, const QByteArray &buffer)
0041 {
0042     switch (codec) {
0043     case AudioCodec::Sbc: {
0044         if (buffer.size() != sizeof(a2dp_sbc_t)) {
0045             return AudioSampleRate::Invalid;
0046         }
0047 
0048         a2dp_sbc_t sbcConfig = *reinterpret_cast<const a2dp_sbc_t *>(buffer.constData());
0049         switch (sbcConfig.frequency) {
0050         case SBC_SAMPLING_FREQ_44100:
0051             return AudioSampleRate::Rate44100;
0052             break;
0053         case SBC_SAMPLING_FREQ_48000:
0054             return AudioSampleRate::Rate48000;
0055             break;
0056         }
0057         break;
0058     }
0059     case AudioCodec::Aac: {
0060         if (buffer.size() != sizeof(a2dp_aac_t)) {
0061             return AudioSampleRate::Invalid;
0062         }
0063 
0064         a2dp_aac_t aacConfig = *reinterpret_cast<const a2dp_aac_t *>(buffer.constData());
0065         switch (AAC_GET_FREQUENCY(aacConfig)) {
0066         case AAC_SAMPLING_FREQ_44100:
0067             return AudioSampleRate::Rate44100;
0068             break;
0069         case AAC_SAMPLING_FREQ_48000:
0070             return AudioSampleRate::Rate48000;
0071             break;
0072         }
0073         break;
0074     }
0075     default:
0076         break;
0077     }
0078 
0079     return AudioSampleRate::Invalid;
0080 }
0081 
0082 MediaTransportPrivate::MediaTransportPrivate(const QString &path, const QVariantMap &properties)
0083     : QObject()
0084     , m_dbusInterface(Strings::orgBluez(), path, DBusConnection::orgBluez())
0085     , m_dbusProperties(nullptr)
0086     , m_path(path)
0087 {
0088     DBusConnection::orgBluez().connect(Strings::orgBluez(),
0089                                        path,
0090                                        Strings::orgFreedesktopDBusProperties(),
0091                                        QStringLiteral("PropertiesChanged"),
0092                                        this,
0093                                        SLOT(onPropertiesChanged(QString, QVariantMap, QStringList)));
0094     init(properties);
0095 }
0096 
0097 void MediaTransportPrivate::init(const QVariantMap &properties)
0098 {
0099     m_dbusProperties = new DBusProperties(Strings::orgBluez(), m_path, DBusConnection::orgBluez(), this);
0100 
0101     m_volume = properties.value(QStringLiteral("Volume")).toUInt();
0102     m_state = stringToState(properties.value(QStringLiteral("State")).toString());
0103     m_configuration.codec = intToCodec(properties.value(QStringLiteral("Codec")).toInt());
0104     m_configuration.sampleRate = byteArrayToSampleRate(m_configuration.codec, properties.value(QStringLiteral("Configuration")).toByteArray());
0105 }
0106 
0107 void MediaTransportPrivate::onPropertiesChanged(const QString &interface, const QVariantMap &changed, const QStringList &invalidated)
0108 {
0109     if (interface != Strings::orgBluezMediaTransport1()) {
0110         return;
0111     }
0112 
0113     for (auto it = changed.constBegin(); it != changed.constEnd(); ++it) {
0114         const QString &key = it.key();
0115         const QVariant &value = it.value();
0116 
0117         if (key == QLatin1String("Volume")) {
0118             m_volume = value.toUInt();
0119             Q_EMIT q.lock()->volumeChanged(m_volume);
0120         } else if (key == QLatin1String("State")) {
0121             m_state = stringToState(value.toString());
0122             Q_EMIT q.lock()->stateChanged(m_state);
0123         }
0124     }
0125 
0126     for (const QString &property : invalidated) {
0127         if (property == QLatin1String("Volume")) {
0128             m_volume = 0;
0129             Q_EMIT q.lock()->volumeChanged(m_volume);
0130         } else if (property == QLatin1String("State")) {
0131             PROPERTY_INVALIDATED(m_state, MediaTransport::State::Idle, stateChanged);
0132         }
0133     }
0134 }
0135 
0136 } // namespace BluezQt
0137 
0138 #include "moc_mediatransport_p.cpp"