1 /* 2 * Copyright (C) 2015-2019 Jean-Luc Barriere 3 * 4 * This file is part of Noson-App 5 * 6 * Noson is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation, either version 3 of the License, or 9 * (at your option) any later version. 10 * 11 * Noson is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with Noson. If not, see <http://www.gnu.org/licenses/>. 18 * 19 */ 20 21 #ifndef NOSONAPPSONOS_H 22 #define NOSONAPPSONOS_H 23 24 #include <noson/sonossystem.h> 25 26 #include "tools.h" 27 #include "locked.h" 28 #include "future.h" 29 #include "zonesmodel.h" 30 #include "roomsmodel.h" 31 #include "albumsmodel.h" 32 #include "artistsmodel.h" 33 #include "composersmodel.h" 34 #include "genresmodel.h" 35 #include "tracksmodel.h" 36 #include "queuemodel.h" 37 #include "playlistsmodel.h" 38 #include "favoritesmodel.h" 39 #include "servicesmodel.h" 40 #include "mediamodel.h" 41 #include "allservicesmodel.h" 42 43 #include <QObject> 44 #include <QString> 45 #include <QQmlEngine> 46 #include <QThread> 47 #include <QThreadPool> 48 49 namespace nosonapp 50 { 51 52 class Sonos : public QObject, public ContentProvider<Sonos> 53 { 54 Q_OBJECT 55 Q_PROPERTY(int jobCount READ jobCount NOTIFY jobCountChanged) 56 Q_PROPERTY(QString systemLocalURI READ systemLocalURI CONSTANT) 57 58 public: 59 explicit Sonos(QObject *parent = 0); 60 ~Sonos(); 61 62 Q_INVOKABLE void debug(int debug); 63 64 /////////////////////////////////////////////////////////////////////////////// 65 /// 66 /// About futures 67 68 Q_INVOKABLE Future* tryInit(int debug = 0); 69 Q_INVOKABLE Future* tryRenewSubscriptions(); 70 Q_INVOKABLE Future* tryJoinZones(const QVariantList& zonePayloads, const QVariant& toZonePayload); 71 Q_INVOKABLE Future* tryUnjoinZone(const QVariant& zonePayload); 72 Q_INVOKABLE Future* tryUnjoinRooms(const QVariantList& roomPayloads); 73 Q_INVOKABLE Future* tryCreateAlarm(const QVariant& alarmPayload); 74 Q_INVOKABLE Future* tryUpdateAlarm(const QVariant& alarmPayload); 75 Q_INVOKABLE Future* tryDestroyAlarm(const QString& id); 76 Q_INVOKABLE Future* tryRefreshShareIndex(); 77 Q_INVOKABLE Future* tryDestroySavedQueue(const QString& SQid); 78 Q_INVOKABLE Future* tryAddItemToFavorites(const QVariant& payload, const QString& description, const QString& artURI); 79 Q_INVOKABLE Future* tryDestroyFavorite(const QString& FVid); 80 81 /////////////////////////////////////////////////////////////////////////////// 82 /// 83 /// Synchonous 84 85 Q_INVOKABLE bool init(int debug = 0); 86 Q_INVOKABLE bool init(int debug, const QString& url); 87 88 Q_INVOKABLE void setLocale(const QString& locale); 89 90 Q_INVOKABLE QString getLocale(); 91 92 Q_INVOKABLE QString getLibVersion(); 93 94 Q_INVOKABLE void addServiceOAuth(const QString& type, const QString& sn, const QString& key, const QString& token, const QString& username); 95 Q_INVOKABLE void deleteServiceOAuth(const QString& type, const QString& sn); 96 97 Q_INVOKABLE void renewSubscriptions(); 98 99 Q_INVOKABLE QVariantList getZones(); 100 101 Q_INVOKABLE bool isConnected(); 102 103 Q_INVOKABLE QVariantList getZoneRooms(const QString& zoneId); 104 105 Q_INVOKABLE bool joinRoom(const QVariant& roomPayload, const QVariant& toZonePayload); 106 107 Q_INVOKABLE bool joinZone(const QVariant& zonePayload, const QVariant& toZonePayload); 108 Q_INVOKABLE bool joinZones(const QVariantList& zonePayloads, const QVariant& toZonePayload); 109 110 Q_INVOKABLE bool unjoinRoom(const QVariant& roomPayload); 111 Q_INVOKABLE bool unjoinRooms(const QVariantList& roomPayloads); 112 113 Q_INVOKABLE bool unjoinZone(const QVariant& zonePayload); 114 115 Q_INVOKABLE bool createAlarm(const QVariant& alarmPayload); 116 Q_INVOKABLE bool updateAlarm(const QVariant& alarmPayload); 117 Q_INVOKABLE bool destroyAlarm(const QString& id); 118 119 Q_INVOKABLE bool refreshShareIndex(); 120 Q_INVOKABLE bool destroySavedQueue(const QString& SQid); 121 Q_INVOKABLE bool addItemToFavorites(const QVariant& payload, const QString& description, const QString& artURI); 122 Q_INVOKABLE bool destroyFavorite(const QString& FVid); 123 124 Q_INVOKABLE QString getObjectIDFromUriMetadata(const QVariant& itemPayload); 125 126 Q_INVOKABLE bool isItemFromService(const QVariant& itemPayload); 127 128 SONOS::System& getSystem(); 129 SONOS::ZonePtr findZone(const QString& zoneName); 130 131 Q_INVOKABLE void runLoader(); 132 133 // Implements ContentProvider 134 void beforeLoad(); 135 void afterLoad(); 136 void runContentLoader(ListModel<Sonos>* model); 137 void loadContent(ListModel<Sonos>* model); 138 void loadAllContent(); 139 void runContentLoaderForContext(ListModel<Sonos>* model, int id); 140 void loadContentForContext(ListModel<Sonos>* model, int id); 141 const char* getHost() const; 142 unsigned getPort() const; 143 QString getBaseUrl() const; 144 void registerContent(ListModel<Sonos>* model, const QString& root); 145 void unregisterContent(ListModel<Sonos>* model); 146 147 // About jobs 148 bool startJob(QRunnable* worker); jobCount()149 int jobCount() { return *(m_jobCount.Get()); } 150 void beginJob(); 151 void endJob(); 152 systemLocalURI()153 const QString& systemLocalURI() { return m_systemLocalURI; } 154 155 // Define singleton provider functions sonos_provider(QQmlEngine * engine,QJSEngine * scriptEngine)156 static QObject* sonos_provider(QQmlEngine *engine, QJSEngine *scriptEngine) 157 { 158 Q_UNUSED(engine) 159 Q_UNUSED(scriptEngine) 160 return new Sonos; 161 } 162 allZonesModel_provider(QQmlEngine * engine,QJSEngine * scriptEngine)163 static QObject* allZonesModel_provider(QQmlEngine *engine, QJSEngine *scriptEngine) 164 { 165 Q_UNUSED(engine) 166 Q_UNUSED(scriptEngine) 167 return new ZonesModel; 168 } 169 allAlbumsModel_provider(QQmlEngine * engine,QJSEngine * scriptEngine)170 static QObject* allAlbumsModel_provider(QQmlEngine *engine, QJSEngine *scriptEngine) 171 { 172 Q_UNUSED(engine) 173 Q_UNUSED(scriptEngine) 174 return new AlbumsModel; 175 } 176 allArtistsModel_provider(QQmlEngine * engine,QJSEngine * scriptEngine)177 static QObject* allArtistsModel_provider(QQmlEngine *engine, QJSEngine *scriptEngine) 178 { 179 Q_UNUSED(engine) 180 Q_UNUSED(scriptEngine) 181 return new ArtistsModel; 182 } 183 allComposersModel_provider(QQmlEngine * engine,QJSEngine * scriptEngine)184 static QObject* allComposersModel_provider(QQmlEngine *engine, QJSEngine *scriptEngine) 185 { 186 Q_UNUSED(engine) 187 Q_UNUSED(scriptEngine) 188 return new ComposersModel; 189 } 190 allGenresModel_provider(QQmlEngine * engine,QJSEngine * scriptEngine)191 static QObject* allGenresModel_provider(QQmlEngine *engine, QJSEngine *scriptEngine) 192 { 193 Q_UNUSED(engine) 194 Q_UNUSED(scriptEngine) 195 return new GenresModel; 196 } 197 allPlaylistsModel_provider(QQmlEngine * engine,QJSEngine * scriptEngine)198 static QObject* allPlaylistsModel_provider(QQmlEngine *engine, QJSEngine *scriptEngine) 199 { 200 Q_UNUSED(engine) 201 Q_UNUSED(scriptEngine) 202 return new PlaylistsModel; 203 } 204 allFavoritesModel_provider(QQmlEngine * engine,QJSEngine * scriptEngine)205 static QObject* allFavoritesModel_provider(QQmlEngine *engine, QJSEngine *scriptEngine) 206 { 207 Q_UNUSED(engine) 208 Q_UNUSED(scriptEngine) 209 return new FavoritesModel; 210 } 211 allServicesModel_provider(QQmlEngine * engine,QJSEngine * scriptEngine)212 static QObject* allServicesModel_provider(QQmlEngine *engine, QJSEngine *scriptEngine) 213 { 214 Q_UNUSED(engine) 215 Q_UNUSED(scriptEngine) 216 return new AllServicesModel; 217 } 218 MyServicesModel_provider(QQmlEngine * engine,QJSEngine * scriptEngine)219 static QObject* MyServicesModel_provider(QQmlEngine *engine, QJSEngine *scriptEngine) 220 { 221 Q_UNUSED(engine) 222 Q_UNUSED(scriptEngine) 223 return new ServicesModel; 224 } 225 226 // Helpers normalizedInputString(const QString & str)227 Q_INVOKABLE static QString normalizedInputString(const QString& str) 228 { 229 return nosonapp::normalizedString(str); 230 } 231 havePulseAudio()232 Q_INVOKABLE static bool havePulseAudio() 233 { 234 return SONOS::System::HavePulseAudio(); 235 } 236 237 signals: 238 void initDone(bool succeeded); 239 void loadingStarted(); 240 void loadingFinished(); 241 void transportChanged(); 242 void renderingControlChanged(); 243 void topologyChanged(); 244 void alarmClockChanged(); 245 void shareIndexInProgress(); 246 void shareIndexFinished(); 247 248 void jobCountChanged(); 249 250 private: 251 typedef QList<RegisteredContent<Sonos> > ManagedContents; 252 Locked<ManagedContents> m_library; 253 unsigned m_shareUpdateID; // Current updateID of SONOS shares 254 bool m_shareIndexInProgess; 255 unsigned m_savedQueuesUpdateID; // Current updatedID of SONOS Playlists 256 257 SONOS::System m_system; 258 QThreadPool m_workerPool; 259 LockedNumber<int> m_jobCount; 260 QString m_systemLocalURI; 261 262 Locked<QString> m_locale; // language_COUNTRY 263 264 static void systemEventCB(void *handle); 265 266 static void unregisterContent(ManagedContents& mc, ListModel<Sonos> *model); 267 268 /////////////////////////////////////////////////////////////////////////////// 269 /// 270 /// About promises 271 272 class PromiseInit : public Promise 273 { 274 public: PromiseInit(Sonos & sonos,int debug)275 PromiseInit(Sonos& sonos, int debug) 276 : m_sonos(sonos), m_debug(debug) { } 277 void run() override; 278 private: 279 Sonos& m_sonos; 280 int m_debug; 281 }; 282 283 class PromiseRenewSubscriptions : public Promise 284 { 285 public: PromiseRenewSubscriptions(Sonos & sonos)286 PromiseRenewSubscriptions(Sonos& sonos) 287 : m_sonos(sonos) { } 288 void run() override; 289 private: 290 Sonos& m_sonos; 291 }; 292 293 class PromiseJoinZones : public Promise 294 { 295 public: PromiseJoinZones(Sonos & sonos,const QVariantList & zonePayloads,const QVariant & toZonePayload)296 PromiseJoinZones(Sonos& sonos, const QVariantList& zonePayloads, const QVariant& toZonePayload) 297 : m_sonos(sonos), m_zonePayloads(zonePayloads), m_toZonePayload(toZonePayload) { } 298 void run() override; 299 private: 300 Sonos& m_sonos; 301 const QVariantList m_zonePayloads; 302 const QVariant m_toZonePayload; 303 }; 304 305 class PromiseUnjoinZone : public Promise 306 { 307 public: PromiseUnjoinZone(Sonos & sonos,const QVariant & zonePayload)308 PromiseUnjoinZone(Sonos& sonos, const QVariant& zonePayload) 309 : m_sonos(sonos), m_zonePayload(zonePayload) { } 310 void run() override; 311 private: 312 Sonos& m_sonos; 313 const QVariant m_zonePayload; 314 }; 315 316 class PromiseUnjoinRooms : public Promise 317 { 318 public: PromiseUnjoinRooms(Sonos & sonos,const QVariantList & roomPayloads)319 PromiseUnjoinRooms(Sonos& sonos, const QVariantList& roomPayloads) 320 : m_sonos(sonos), m_roomPayloads(roomPayloads) { } 321 void run() override; 322 private: 323 Sonos& m_sonos; 324 const QVariantList m_roomPayloads; 325 }; 326 327 class PromiseCreateAlarm : public Promise 328 { 329 public: PromiseCreateAlarm(Sonos & sonos,const QVariant & alarmPayload)330 PromiseCreateAlarm(Sonos& sonos, const QVariant& alarmPayload) 331 : m_sonos(sonos), m_alarmPayload(alarmPayload) { } 332 void run() override; 333 private: 334 Sonos& m_sonos; 335 const QVariant m_alarmPayload; 336 }; 337 338 class PromiseUpdateAlarm : public Promise 339 { 340 public: PromiseUpdateAlarm(Sonos & sonos,const QVariant & alarmPayload)341 PromiseUpdateAlarm(Sonos& sonos, const QVariant& alarmPayload) 342 : m_sonos(sonos), m_alarmPayload(alarmPayload) { } 343 void run() override; 344 private: 345 Sonos& m_sonos; 346 const QVariant m_alarmPayload; 347 }; 348 349 class PromiseDestroyAlarm : public Promise 350 { 351 public: PromiseDestroyAlarm(Sonos & sonos,const QString & id)352 PromiseDestroyAlarm(Sonos& sonos, const QString& id) 353 : m_sonos(sonos), m_id(id) { } 354 void run() override; 355 private: 356 Sonos& m_sonos; 357 const QString m_id; 358 }; 359 360 class PromiseRefreshShareIndex : public Promise 361 { 362 public: PromiseRefreshShareIndex(Sonos & sonos)363 PromiseRefreshShareIndex(Sonos& sonos) 364 : m_sonos(sonos) { } 365 void run() override; 366 private: 367 Sonos& m_sonos; 368 }; 369 370 class PromiseDestroySavedQueue : public Promise 371 { 372 public: PromiseDestroySavedQueue(Sonos & sonos,const QString & SQid)373 PromiseDestroySavedQueue(Sonos& sonos, const QString& SQid) 374 : m_sonos(sonos), m_SQid(SQid) { } 375 void run() override; 376 private: 377 Sonos& m_sonos; 378 const QString m_SQid; 379 }; 380 381 class PromiseAddItemToFavorites : public Promise 382 { 383 public: PromiseAddItemToFavorites(Sonos & sonos,const QVariant & payload,const QString & description,const QString & artURI)384 PromiseAddItemToFavorites(Sonos& sonos, const QVariant& payload, const QString& description, const QString& artURI) 385 : m_sonos(sonos), m_payload(payload), m_description(description), m_artURI(artURI) { } 386 void run() override; 387 private: 388 Sonos& m_sonos; 389 QVariant m_payload; 390 const QString m_description; 391 const QString m_artURI; 392 }; 393 394 class PromiseDestroyFavorite : public Promise 395 { 396 public: PromiseDestroyFavorite(Sonos & sonos,const QString & FVid)397 PromiseDestroyFavorite(Sonos& sonos, const QString& FVid) 398 : m_sonos(sonos), m_FVid(FVid) { } 399 void run() override; 400 private: 401 Sonos& m_sonos; 402 const QString m_FVid; 403 }; 404 405 }; 406 407 } 408 409 #endif // NOSONAPPSONOS_H 410