1/*
2 * BluezQt - Asynchronous Bluez wrapper library
3 *
4 * SPDX-FileCopyrightText: 2019 Manuel Weichselbaumer <mincequi@web.de>
5 *
6 * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
7 */
8
9#include "mediatransport_p.h"
10#include "a2dp-codecs.h"
11#include "macros.h"
12#include "utils.h"
13
14namespace BluezQt
15{
16static MediaTransport::State stringToState(const QString &state)
17{
18 if (state == QLatin1String("pending")) {
19 return MediaTransport::State::Pending;
20 } else if (state == QLatin1String("active")) {
21 return MediaTransport::State::Active;
22 }
23 return MediaTransport::State::Idle;
24}
25
26static AudioCodec intToCodec(int value)
27{
28 switch (value) {
29 case A2DP_CODEC_SBC:
30 return AudioCodec::Sbc;
31 break;
32 case A2DP_CODEC_MPEG24:
33 return AudioCodec::Aac;
34 break;
35 }
36
37 return AudioCodec::Invalid;
38}
39
40static AudioSampleRate byteArrayToSampleRate(AudioCodec codec, const QByteArray &buffer)
41{
42 switch (codec) {
43 case AudioCodec::Sbc: {
44 if (buffer.size() != sizeof(a2dp_sbc_t)) {
45 return AudioSampleRate::Invalid;
46 }
47
48 a2dp_sbc_t sbcConfig = *reinterpret_cast<const a2dp_sbc_t *>(buffer.constData());
49 switch (sbcConfig.frequency) {
50 case SBC_SAMPLING_FREQ_44100:
51 return AudioSampleRate::Rate44100;
52 break;
53 case SBC_SAMPLING_FREQ_48000:
54 return AudioSampleRate::Rate48000;
55 break;
56 }
57 break;
58 }
59 case AudioCodec::Aac: {
60 if (buffer.size() != sizeof(a2dp_aac_t)) {
61 return AudioSampleRate::Invalid;
62 }
63
64 a2dp_aac_t aacConfig = *reinterpret_cast<const a2dp_aac_t *>(buffer.constData());
65 switch (AAC_GET_FREQUENCY(aacConfig)) {
66 case AAC_SAMPLING_FREQ_44100:
67 return AudioSampleRate::Rate44100;
68 break;
69 case AAC_SAMPLING_FREQ_48000:
70 return AudioSampleRate::Rate48000;
71 break;
72 }
73 break;
74 }
75 default:
76 break;
77 }
78
79 return AudioSampleRate::Invalid;
80}
81
82MediaTransportPrivate::MediaTransportPrivate(const QString &path, const QVariantMap &properties)
83 : QObject()
84 , m_dbusInterface(Strings::orgBluez(), path, DBusConnection::orgBluez())
85 , m_dbusProperties(nullptr)
86 , m_path(path)
87{
88 DBusConnection::orgBluez().connect(Strings::orgBluez(),
89 path,
90 Strings::orgFreedesktopDBusProperties(),
91 QStringLiteral("PropertiesChanged"),
92 this,
93 SLOT(onPropertiesChanged(QString, QVariantMap, QStringList)));
94 init(properties);
95}
96
97void MediaTransportPrivate::init(const QVariantMap &properties)
98{
99 m_dbusProperties = new DBusProperties(Strings::orgBluez(), m_path, DBusConnection::orgBluez(), this);
100
101 m_volume = properties.value(QStringLiteral("Volume")).toUInt();
102 m_state = stringToState(properties.value(QStringLiteral("State")).toString());
103 m_configuration.codec = intToCodec(properties.value(QStringLiteral("Codec")).toInt());
104 m_configuration.sampleRate = byteArrayToSampleRate(m_configuration.codec, properties.value(QStringLiteral("Configuration")).toByteArray());
105}
106
107void MediaTransportPrivate::onPropertiesChanged(const QString &interface, const QVariantMap &changed, const QStringList &invalidated)
108{
109 if (interface != Strings::orgBluezMediaTransport1()) {
110 return;
111 }
112
113 for (auto it = changed.constBegin(); it != changed.constEnd(); ++it) {
114 const QString &key = it.key();
115 const QVariant &value = it.value();
116
117 if (key == QLatin1String("Volume")) {
118 m_volume = value.toUInt();
119 Q_EMIT q.lock()->volumeChanged(m_volume);
120 } else if (key == QLatin1String("State")) {
121 m_state = stringToState(value.toString());
122 Q_EMIT q.lock()->stateChanged(m_state);
123 }
124 }
125
126 for (const QString &property : invalidated) {
127 if (property == QLatin1String("Volume")) {
128 m_volume = 0;
129 Q_EMIT q.lock()->volumeChanged(m_volume);
130 } else if (property == QLatin1String("State")) {
131 PROPERTY_INVALIDATED(m_state, MediaTransport::State::Idle, stateChanged);
132 }
133 }
134}
135
136} // namespace BluezQt
137
138#include "moc_mediatransport_p.cpp"
139

source code of bluez-qt/src/mediatransport_p.cpp