From 6da5f1039ed113dcf11b0347e6d2dbd5432c3d33 Mon Sep 17 00:00:00 2001 From: Andrew Branson Date: Sun, 19 Apr 2015 18:17:02 +0200 Subject: Support option for system volume control Add support for direct PulseAudio volume control instead of through MPRIS, which doesn't currently work. Default enabled, added setting to disable. --- app/qml/pages/ManagerPage.qml | 10 +++ app/translations/pebble-es.ts | 70 +++++++++------- app/translations/pebble-pl.ts | 70 +++++++++------- app/translations/pebble.ts | 70 +++++++++------- daemon/manager.cpp | 2 +- daemon/musicmanager.cpp | 184 ++++++++++++++++++++++++++++++------------ daemon/musicmanager.h | 7 +- daemon/settings.h | 3 + 8 files changed, 273 insertions(+), 143 deletions(-) diff --git a/app/qml/pages/ManagerPage.qml b/app/qml/pages/ManagerPage.qml index 894797d..7fb7369 100644 --- a/app/qml/pages/ManagerPage.qml +++ b/app/qml/pages/ManagerPage.qml @@ -11,6 +11,7 @@ Page { path: "/org/pebbled/settings" property bool silentWhenConnected: false property bool transliterateMessage: false + property bool useSystemVolume: true property bool incomingCallNotification: true property bool notificationsCommhistoryd: true property bool notificationsMissedCall: true @@ -132,6 +133,15 @@ Page { settings.silentWhenConnected = !settings.silentWhenConnected; } } + TextSwitch { + text: qsTr("Control main volume") + description: qsTr("Pebble music volume buttons change the main phone volume directly instead of through the music player.") + checked: settings.useSystemVolume + automaticCheck: true + onClicked: { + settings.useSystemVolume = !settings.useSystemVolume; + } + } TextSwitch { text: qsTr("Transliterate messages") description: qsTr("Messages are transliterated to ASCII before sending to Pebble") diff --git a/app/translations/pebble-es.ts b/app/translations/pebble-es.ts index 6bdb778..38a8cc4 100644 --- a/app/translations/pebble-es.ts +++ b/app/translations/pebble-es.ts @@ -174,154 +174,164 @@ ManagerPage - + Pebble Appstore - + About Acerca de - + Pebble Manager - + Waiting for watch... If it can't be found please check it's available and paired in Bluetooth settings. Buscando el reloj Si esto tarda mucho, comprueba que el reloj esté emparejado correctamente. - + Service Servicio - + Enabled Habilitado - + Automatic startup Inicio automático - + Manual startup Inicio manual - + Active Activo - + Running Ejecutándose - + Dead Detenido - + Connection Conexión - + Connected Conectado - + Disconnected Desconectado - + Settings Configuración - + Forward phone calls Transferir llamadas - + Silent when connected Modo silencio automático - + Sets phone profile to "silent" when Pebble is connected Activa el modo silencio cuando se conecte un Pebble - + + Control main volume + + + + + Pebble music volume buttons change the main phone volume directly instead of through the music player. + + + + Transliterate messages Transliterar mensajes - + Messages are transliterated to ASCII before sending to Pebble Codifica los mensajes entrates a ASCII antes de enviarlos a Pebble - + Notifications Notificaciones - + Messaging Mensajería - + SMS and IM SMS y chat - + Missed call Llamadas perdidas - + Emails Correos electrónicos - + Mitakuuluu - + Twitter Twitter - + Facebook Facebook - + Other notifications Resto de notificaciones - + All notifications Todas las notificaciones diff --git a/app/translations/pebble-pl.ts b/app/translations/pebble-pl.ts index ebe4f1a..11285ee 100644 --- a/app/translations/pebble-pl.ts +++ b/app/translations/pebble-pl.ts @@ -194,154 +194,164 @@ ManagerPage - + Pebble Appstore Pebble Appstore - + About Informacje - + Pebble Manager Pebble Manager - + Waiting for watch... If it can't be found please check it's available and paired in Bluetooth settings. Oczekiwanie na zegarek... Jeśli nie zostaje znaleziony sprawdź czy jest w zasięgu i czy jest sparowany w ustawieniach Bluetooth. - + Service Usługa - + Enabled Włączona - + Automatic startup Start automatyczny - + Manual startup Start ręczny - + Active Aktywna - + Running Pracuje - + Dead Martwa - + Connection Połączenie - + Connected Połączony - + Disconnected Rozłączony - + Settings Ustawienia - + Forward phone calls Przekazuj telefony - + Silent when connected Cichy gdy połączony - + Sets phone profile to "silent" when Pebble is connected Ustawia "cichy" profil telefonu gdy Pebble jest połączony - + + Control main volume + + + + + Pebble music volume buttons change the main phone volume directly instead of through the music player. + + + + Transliterate messages Transliteracja wiadomości - + Messages are transliterated to ASCII before sending to Pebble Wiadomości są transliterowane do ASCII przed wysłaniem do Pebble - + Notifications Powiadomienia - + Messaging Wiadomości - + SMS and IM SMS i IM - + Missed call Ominięte telefony - + Emails Emaile - + Mitakuuluu Mitakuuluu - + Twitter Twitter - + Facebook Facebook - + Other notifications Pozostałe powiadomienia - + All notifications Wszystkie powiadomienia diff --git a/app/translations/pebble.ts b/app/translations/pebble.ts index 24f2352..cd7ba8b 100644 --- a/app/translations/pebble.ts +++ b/app/translations/pebble.ts @@ -162,153 +162,163 @@ ManagerPage - + Pebble Appstore - + About - + Pebble Manager - + Waiting for watch... If it can't be found please check it's available and paired in Bluetooth settings. - + Service - + Enabled - + Automatic startup - + Manual startup - + Active - + Running - + Dead - + Connection - + Connected - + Disconnected - + Settings - + Forward phone calls - + Silent when connected - + Sets phone profile to "silent" when Pebble is connected - + + Control main volume + + + + + Pebble music volume buttons change the main phone volume directly instead of through the music player. + + + + Transliterate messages - + Messages are transliterated to ASCII before sending to Pebble - + Notifications - + Messaging - + SMS and IM - + Missed call - + Emails - + Mitakuuluu - + Twitter - + Facebook - + Other notifications - + All notifications diff --git a/daemon/manager.cpp b/daemon/manager.cpp index 02a4021..567316e 100644 --- a/daemon/manager.cpp +++ b/daemon/manager.cpp @@ -16,7 +16,7 @@ Manager::Manager(Settings *settings, QObject *parent) : bank(new BankManager(watch, upload, apps, this)), voice(new VoiceCallManager(settings, this)), notifications(new NotificationManager(settings, this)), - music(new MusicManager(watch, this)), + music(new MusicManager(watch, settings, this)), datalog(new DataLogManager(watch, this)), appmsg(new AppMsgManager(apps, watch, this)), js(new JSKitManager(watch, apps, appmsg, settings, this)), diff --git a/daemon/musicmanager.cpp b/daemon/musicmanager.cpp index 385abbf..11ff6fd 100644 --- a/daemon/musicmanager.cpp +++ b/daemon/musicmanager.cpp @@ -1,10 +1,11 @@ #include #include #include "musicmanager.h" +#include "settings.h" -MusicManager::MusicManager(WatchConnector *watch, QObject *parent) +MusicManager::MusicManager(WatchConnector *watch, Settings *settings, QObject *parent) : QObject(parent), l(metaObject()->className()), - watch(watch), _watcher(new QDBusServiceWatcher(this)) + watch(watch), _watcher(new QDBusServiceWatcher(this)), _pulseBus(NULL), settings(settings),_maxVolume(0) { QDBusConnection bus = QDBusConnection::sessionBus(); QDBusConnectionInterface *bus_iface = bus.interface(); @@ -33,6 +34,33 @@ MusicManager::MusicManager(WatchConnector *watch, QObject *parent) bus.connect("", "/org/mpris/MediaPlayer2", "org.freedesktop.DBus.Properties", "PropertiesChanged", this, SLOT(handleMprisPropertiesChanged(QString,QMap,QStringList))); + // Locate and connect to the PulseAudio DBus to control system volume + // Look up PulseAudio P2P Bus address + QDBusMessage call = QDBusMessage::createMethodCall("org.PulseAudio1", "/org/pulseaudio/server_lookup1", "org.freedesktop.DBus.Properties", "Get" ); + call << "org.PulseAudio.ServerLookup1" << "Address"; + QDBusReply lookupReply = bus.call(call); + if (lookupReply.isValid()) { + // + qCDebug(l) << "PulseAudio Bus address: " << lookupReply.value().variant().toString(); + _pulseBus = new QDBusConnection(QDBusConnection::connectToPeer(lookupReply.value().variant().toString(), "org.PulseAudio1")); + } + else { + qCDebug(l) << "Cannot find PulseAudio Bus address, cannot control system volume."; + } + + // Query max volume + call = QDBusMessage::createMethodCall("com.Meego.MainVolume2", "/com/meego/mainvolume2", + "org.freedesktop.DBus.Properties", "Get"); + call << "com.Meego.MainVolume2" << "StepCount"; + QDBusReply volumeMaxReply = _pulseBus->call(call); + if (volumeMaxReply.isValid()) { + _maxVolume = volumeMaxReply.value().variant().toUInt(); + qCDebug(l) << "Max volume: " << _maxVolume; + } + else { + qCWarning(l) << "Could not read volume max, cannot adjust volume: " << volumeMaxReply.error().message(); + } + // Now set up the Pebble endpoint handler for music control commands watch->setEndpointHandler(WatchConnector::watchMUSIC_CONTROL, [this](const QByteArray& data) { handleMusicControl(WatchConnector::MusicControl(data.at(0))); @@ -44,6 +72,15 @@ MusicManager::MusicManager(WatchConnector *watch, QObject *parent) this, &MusicManager::handleWatchConnected); } +MusicManager::~MusicManager() +{ + if (_pulseBus != NULL) { + qCDebug(l) << "Disconnecting from PulseAudio P2P DBus"; + QDBusConnection::disconnectFromBus("org.PulseAudio1"); + delete(_pulseBus); + } +} + void MusicManager::switchToService(const QString &service) { if (_curService != service) { @@ -111,66 +148,111 @@ void MusicManager::callMprisMethod(const QString &method) void MusicManager::handleMusicControl(WatchConnector::MusicControl operation) { qCDebug(l) << "operation from watch:" << operation; - - if (_curService.isEmpty()) { - qCDebug(l) << "can't do any music operation, no mpris interface active"; - return; - } - - switch (operation) { - case WatchConnector::musicPLAY_PAUSE: - callMprisMethod("PlayPause"); - break; - case WatchConnector::musicPAUSE: - callMprisMethod("Pause"); - break; - case WatchConnector::musicPLAY: - callMprisMethod("Play"); - break; - case WatchConnector::musicNEXT: - callMprisMethod("Next"); - break; - case WatchConnector::musicPREVIOUS: - callMprisMethod("Previous"); - break; - - case WatchConnector::musicVOLUME_UP: - case WatchConnector::musicVOLUME_DOWN: { - QDBusConnection bus = QDBusConnection::sessionBus(); - QDBusMessage call = QDBusMessage::createMethodCall(_curService, "/org/mpris/MediaPlayer2", - "org.freedesktop.DBus.Properties", "Get"); - call << "org.mpris.MediaPlayer2.Player" << "Volume"; - QDBusReply volumeReply = bus.call(call); + QVariant useSystemVolumeVar = settings->property("useSystemVolume"); + bool useSystemVolume = (useSystemVolumeVar.isValid() && useSystemVolumeVar.toBool()); + + // System volume controls + if (useSystemVolume && _pulseBus != NULL && + (operation == WatchConnector::musicVOLUME_UP || operation == WatchConnector::musicVOLUME_DOWN)) { + // Query current volume + QDBusMessage call = QDBusMessage::createMethodCall("com.Meego.MainVolume2", "/com/meego/mainvolume2", + "org.freedesktop.DBus.Properties", "Get"); + call << "com.Meego.MainVolume2" << "CurrentStep"; + + QDBusReply volumeReply = _pulseBus->call(call); if (volumeReply.isValid()) { - double volume = volumeReply.value().variant().toDouble(); - if (operation == WatchConnector::musicVOLUME_UP) { - volume += 0.1; + // Decide the new value for volume, taking limits into account + uint volume = volumeReply.value().variant().toUInt(); + uint newVolume; + qCDebug(l) << "Current volume: " << volumeReply.value().variant().toUInt(); + if (operation == WatchConnector::musicVOLUME_UP && volume < _maxVolume-1 ) { + newVolume = volume + 1; + } + else if (operation == WatchConnector::musicVOLUME_DOWN && volume > 0) { + newVolume = volume - 1; } else { - volume -= 0.1; + qCDebug(l) << "Volume already at limit"; + newVolume = volume; } - qCDebug(l) << "Setting volume" << volume; - call = QDBusMessage::createMethodCall(_curService, "/org/mpris/MediaPlayer2", "org.freedesktop.DBus.Properties", "Set"); - call << "org.mpris.MediaPlayer2.Player" << "Volume" << QVariant::fromValue(QDBusVariant(volume)); + // If we have a new volume level, change it + if (newVolume != volume) { + qCDebug(l) << "Setting volume: " << newVolume; - QDBusError err = QDBusConnection::sessionBus().call(call); - if (err.isValid()) { - qCWarning(l) << err.message(); + call = QDBusMessage::createMethodCall("com.Meego.MainVolume2", "/com/meego/mainvolume2", + "org.freedesktop.DBus.Properties", "Set"); + call << "com.Meego.MainVolume2" << "CurrentStep" << QVariant::fromValue(QDBusVariant(newVolume)); + + QDBusError err = _pulseBus->call(call); + if (err.isValid()) { + qCWarning(l) << err.message(); + } } - } else { - qCWarning(l) << volumeReply.error().message(); } + } + + //Don't allow any music operations if there's no MPRIS player, unless we are allowed to control the system volume and it's a volume command + else if (_curService.isEmpty()) { + qCDebug(l) << "can't do any music operation, no mpris interface active"; + return; + } + else { + switch (operation) { + case WatchConnector::musicPLAY_PAUSE: + callMprisMethod("PlayPause"); + break; + case WatchConnector::musicPAUSE: + callMprisMethod("Pause"); + break; + case WatchConnector::musicPLAY: + callMprisMethod("Play"); + break; + case WatchConnector::musicNEXT: + callMprisMethod("Next"); + break; + case WatchConnector::musicPREVIOUS: + callMprisMethod("Previous"); + break; + + case WatchConnector::musicVOLUME_UP: + case WatchConnector::musicVOLUME_DOWN: { + QDBusConnection bus = QDBusConnection::sessionBus(); + QDBusMessage call = QDBusMessage::createMethodCall(_curService, "/org/mpris/MediaPlayer2", + "org.freedesktop.DBus.Properties", "Get"); + call << "org.mpris.MediaPlayer2.Player" << "Volume"; + QDBusReply volumeReply = bus.call(call); + if (volumeReply.isValid()) { + double volume = volumeReply.value().variant().toDouble(); + if (operation == WatchConnector::musicVOLUME_UP) { + volume += 0.1; + } + else { + volume -= 0.1; + } + qCDebug(l) << "Setting volume" << volume; + + call = QDBusMessage::createMethodCall(_curService, "/org/mpris/MediaPlayer2", "org.freedesktop.DBus.Properties", "Set"); + call << "org.mpris.MediaPlayer2.Player" << "Volume" << QVariant::fromValue(QDBusVariant(volume)); + + QDBusError err = QDBusConnection::sessionBus().call(call); + if (err.isValid()) { + qCWarning(l) << err.message(); + } + } else { + qCWarning(l) << volumeReply.error().message(); + } + break; } - break; - case WatchConnector::musicGET_NOW_PLAYING: - sendCurrentMprisMetadata(); - break; + case WatchConnector::musicGET_NOW_PLAYING: + sendCurrentMprisMetadata(); + break; - default: - qCWarning(l) << "Operation" << operation << "not supported"; - break; + default: + qCWarning(l) << "Operation" << operation << "not supported"; + break; + } } } diff --git a/daemon/musicmanager.h b/daemon/musicmanager.h index 14aa6fb..81947e9 100644 --- a/daemon/musicmanager.h +++ b/daemon/musicmanager.h @@ -5,6 +5,7 @@ #include #include #include "watchconnector.h" +#include "settings.h" class MusicManager : public QObject, protected QDBusContext { @@ -12,7 +13,8 @@ class MusicManager : public QObject, protected QDBusContext QLoggingCategory l; public: - explicit MusicManager(WatchConnector *watch, QObject *parent = 0); + explicit MusicManager(WatchConnector *watch, Settings *settings, QObject *parent = 0); + virtual ~MusicManager(); private: void switchToService(const QString &service); @@ -31,6 +33,9 @@ private: QDBusServiceWatcher *_watcher; QString _curService; QVariantMap _curMetadata; + QDBusConnection *_pulseBus; + Settings *settings; + uint _maxVolume; }; #endif // MUSICMANAGER_H diff --git a/daemon/settings.h b/daemon/settings.h index 90e25e2..688b211 100644 --- a/daemon/settings.h +++ b/daemon/settings.h @@ -9,6 +9,7 @@ class Settings : public MDConfGroup Q_PROPERTY(bool silentWhenConnected MEMBER silentWhenConnected NOTIFY silentWhenConnectedChanged) Q_PROPERTY(bool transliterateMessage MEMBER transliterateMessage NOTIFY transliterateMessageChanged) + Q_PROPERTY(bool useSystemVolume MEMBER useSystemVolume NOTIFY useSystemVolumeChanged) Q_PROPERTY(bool incomingCallNotification MEMBER incomingCallNotification NOTIFY incomingCallNotificationChanged) Q_PROPERTY(bool notificationsCommhistoryd MEMBER notificationsCommhistoryd NOTIFY notificationsCommhistorydChanged) Q_PROPERTY(bool notificationsMissedCall MEMBER notificationsMissedCall NOTIFY notificationsMissedCallChanged) @@ -22,6 +23,7 @@ class Settings : public MDConfGroup bool silentWhenConnected; bool transliterateMessage; + bool useSystemVolume; bool incomingCallNotification; bool notificationsCommhistoryd; bool notificationsMissedCall; @@ -41,6 +43,7 @@ public: signals: void silentWhenConnectedChanged(); void transliterateMessageChanged(); + void useSystemVolumeChanged(); void incomingCallNotificationChanged(); void notificationsCommhistorydChanged(); void notificationsMissedCallChanged(); -- cgit v1.2.3