bluetooth: populate data for existing avrcp/a2dp connection
[apps/mediaplayer.git] / app / dbus.cpp
1 /*
2  * Copyright (C) 2017 Konsulko Group
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "dbus.h"
18
19
20 DbusService::DbusService(QObject *parent) : QObject(parent)
21 {
22 }
23
24 /*
25  * Light Media Scanner
26  */
27
28 bool DbusService::enableLMS()
29 {
30     QDBusConnection session_bus = QDBusConnection::sessionBus();
31
32     if (!session_bus.isConnected())
33         return false;
34
35     return session_bus.connect(QString("org.lightmediascanner"), QString("/org/lightmediascanner/Scanner1"), "org.freedesktop.DBus.Properties", "PropertiesChanged", this, SLOT(lmsUpdate(QString,QVariantMap,QStringList)));
36 }
37
38 #if defined(HAVE_LIGHTMEDIASCANNER)
39 void DbusService::lmsUpdate(const QString&, const QVariantMap& map, const QStringList&)
40 {
41     QVariantList mediaFiles;
42     QString music;
43
44     if (!map.contains("IsScanning") && !map.contains("WriteLocked"))
45         return;
46
47     if (map["IsScanning"].toBool() || map["WriteLocked"].toBool())
48         return;
49
50     mediaFiles = LightMediaScanner::processLightMediaScanner();
51
52     if (!mediaFiles.isEmpty())
53         emit processPlaylistUpdate(mediaFiles);
54     else
55         emit processPlaylistHide();
56 }
57 #else
58 void DbusService::lmsUpdate(const QString&, const QVariantMap&, const QStringList&)
59 {
60 }
61 #endif
62
63 /*
64  * Bluetooth
65  */
66
67 void DbusService::setBluezPath(const QString& path)
68 {
69     this->bluezPath = path;
70 }
71
72 QString DbusService::getBluezPath() const
73 {
74     return this->bluezPath;
75 }
76
77 bool DbusService::enableBluetooth()
78 {
79     QDBusConnection system_bus = QDBusConnection::systemBus();
80     QString interface = "org.freedesktop.DBus.ObjectManager";
81     bool ret;
82
83     if (!system_bus.isConnected())
84         return false;
85
86     if (deviceConnected(system_bus))
87         initialBluetoothData(system_bus);
88
89     ret = system_bus.connect(QString("org.bluez"), QString("/"), interface, "InterfacesAdded", this, SLOT(newBluetoothDevice(QDBusObjectPath,QVariantMap)));
90
91     if (!ret)
92         return false;
93
94     ret = system_bus.connect(QString("org.bluez"), QString("/"), interface, "InterfacesRemoved", this, SLOT(removeBluetoothDevice(QDBusObjectPath,QStringList)));
95
96     /*
97      * Unregister InterfacesAdded on error condition
98      */
99     if (!ret)
100         system_bus.disconnect(QString("org.bluez"), QString("/"), interface, "InterfacesAdded", this, SLOT(newBluetoothDevice(QString,QVariantMap)));
101
102     return ret;
103 }
104
105 bool DbusService::checkIfPlayer(const QString& path) const
106 {
107     QRegExp regex("^.*/player\\d$");
108     if (regex.exactMatch(path))
109         return true;
110
111     return false;
112 }
113
114 bool DbusService::deviceConnected(const QDBusConnection& system_bus)
115 {
116     QDBusInterface interface("org.bluez", "/", "org.freedesktop.DBus.ObjectManager", system_bus);
117     QDBusMessage result = interface.call("GetManagedObjects");
118     const QDBusArgument argument = result.arguments().at(0).value<QDBusArgument>();
119     bool ret = false;
120
121     if (argument.currentType() != QDBusArgument::MapType)
122         return false;
123
124     argument.beginMap();
125
126     while (!argument.atEnd()) {
127         QString key;
128
129         argument.beginMapEntry();
130         argument >> key;
131         argument.endMapEntry();
132
133         ret = checkIfPlayer(key);
134
135         if (ret) {
136             newBluetoothDevice(QDBusObjectPath(key), QVariantMap());
137             break;
138         }
139     }
140
141     argument.endMap();
142
143     return ret;
144 }
145
146 void DbusService::initialBluetoothData(const QDBusConnection& system_bus)
147 {
148     QDBusInterface interface("org.bluez", getBluezPath(), "org.freedesktop.DBus.Properties", system_bus);
149
150     QDBusMessage result = interface.call("GetAll", "org.bluez.MediaPlayer1");
151     const QDBusArgument argument = result.arguments().at(0).value<QDBusArgument>();
152     QString status, artist, title;
153     int position = 0, duration = 0;
154
155     if (argument.currentType() != QDBusArgument::MapType)
156         return;
157
158     argument.beginMap();
159
160     while (!argument.atEnd()) {
161         QString key;
162         QVariant value;
163
164         argument.beginMapEntry();
165         argument >> key >> value;
166
167         if (key == "Position") {
168             position = value.toInt();
169         } else if (key == "Status") {
170             status = value.toString();
171         } else if (key == "Track") {
172             const QDBusArgument argument1 = qvariant_cast<QDBusArgument>(value);
173             QString key1;
174             QVariant value1;
175
176             argument1.beginMap();
177
178             while (!argument1.atEnd()) {
179                 argument1.beginMapEntry();
180                 argument1 >> key1 >> value1;
181                 if (key1 == "Artist")
182                     artist = value1.toString();
183                 else if (key1 == "Title")
184                     title = value1.toString();
185                 else if (key1 == "Duration")
186                     duration = value1.toInt();
187                 argument1.endMapEntry();
188             }
189             argument1.endMap();
190         }
191         argument.endMapEntry();
192     }
193     argument.endMap();
194
195     emit processPlaylistHide();
196     emit displayBluetoothMetadata(artist, title, duration);
197     emit updatePlayerStatus(status);
198     emit updatePosition(position);
199 }
200
201 void DbusService::newBluetoothDevice(const QDBusObjectPath& item, const QVariantMap&)
202 {
203     QString path = item.path();
204     if (!checkIfPlayer(path))
205         return;
206
207     if (!getBluezPath().isEmpty()) {
208         qWarning() << "Another Bluetooth Player already connected";
209         return;
210     }
211
212     emit processPlaylistHide();
213
214     QDBusConnection system_bus = QDBusConnection::systemBus();
215     system_bus.connect(QString("org.bluez"), path, "org.freedesktop.DBus.Properties", "PropertiesChanged", this, SLOT(processBluetoothEvent(QString,QVariantMap,QStringList)));
216
217     setBluezPath(path);
218 }
219
220 void DbusService::removeBluetoothDevice(const QDBusObjectPath& item, const QStringList&)
221 {
222     QString path = item.path();
223     if (!checkIfPlayer(path))
224         return;
225
226     if (getBluezPath().isEmpty()) {
227         qWarning() << "No Bluetooth Player connected";
228         return;
229     }
230
231     QDBusConnection system_bus = QDBusConnection::systemBus();
232     system_bus.disconnect(QString("org.bluez"), path, "org.freedesktop.DBus.Properties", "PropertiesChanged", this, SLOT(processBluetoothEvent(QString,QVariantMap,QStringList)));
233
234     setBluezPath(QString());
235     emit processPlaylistShow();
236 }
237
238 void DbusService::processBluetoothEvent(const QString&, const QVariantMap& map, const QStringList&)
239 {
240     if (map.contains("Track")) {
241         QVariantMap track;
242         map["Track"].value<QDBusArgument>() >> track;
243         emit displayBluetoothMetadata(track["Artist"].toString(), track["Title"].toString(), track["Duration"].toInt());
244     }
245
246     if (map.contains("Position"))
247         emit updatePosition(map["Position"].toInt());
248
249     if (map.contains("Status"))
250         emit updatePlayerStatus(map["Status"].toString());
251 }
252
253 void DbusService::processQMLEvent(const QString& state)
254 {
255     QDBusInterface interface("org.bluez", getBluezPath(), "org.bluez.MediaPlayer1", QDBusConnection::systemBus());
256     interface.call(state);
257 }
258
259 long DbusService::getCurrentPosition()
260 {
261     QDBusInterface interface("org.bluez", getBluezPath(), "org.bluez.MediaPlayer1", QDBusConnection::systemBus());
262     return interface.property("Position").toInt();
263 }