diff --git a/app/mediamanager.cpp b/app/mediamanager.cpp index c6788e8..c1062f2 100644 --- a/app/mediamanager.cpp +++ b/app/mediamanager.cpp @@ -43,11 +43,23 @@ void MediaManager::addInterface(QString name, QObject *object){ for(int i = pluginMeta->methodOffset(); i < pluginMeta->methodCount(); ++i){ if(pluginMeta->method(i).methodSignature() == "playbackStarted()"){ connect(object, SIGNAL(playbackStarted()), this, SLOT(playbackStartedHandler())); + } else if(pluginMeta->method(i).methodSignature() == "trackChanged(QVariantMap)") { + connect(object, SIGNAL(trackChanged(QVariantMap)), this, SLOT(onTrackChanged(QVariantMap))); + } else if(pluginMeta->method(i).methodSignature() == "mediaPositionChanged(uint)") { + connect(object, SIGNAL(mediaPositionChanged(uint)), this, SLOT(onMediaPositionChanged(uint))); } } } } +void MediaManager::onTrackChanged(QVariantMap track) { + emit message("MediaInput", "track", track); +} + +void MediaManager::onMediaPositionChanged(quint32 position) { + emit message("MediaInput", "position", position); +} + void MediaManager::playbackStartedHandler(){ MediaInterface * sender = dynamic_cast(QObject::sender()); if(sender){ diff --git a/app/mediamanager.h b/app/mediamanager.h index f4bc5d8..92da1f6 100644 --- a/app/mediamanager.h +++ b/app/mediamanager.h @@ -29,6 +29,8 @@ class MediaManager : public QObject signals: void intefacesChanged(); void activeMediaPlayerChanged(); + void message(QString sender, QString message, QVariant parameter); + public slots: void setActiveMediaPlayer(QString name); void start(); @@ -36,6 +38,8 @@ public slots: void prevTrack(); void nextTrack(); void setVolume(uint8_t volume); + void onMediaPositionChanged(quint32 position); + void onTrackChanged(QVariantMap track); private slots: void setVoiceVolume(QString interface, QVariant value); diff --git a/app/pluginmanager.cpp b/app/pluginmanager.cpp index 152710f..e655096 100644 --- a/app/pluginmanager.cpp +++ b/app/pluginmanager.cpp @@ -44,8 +44,11 @@ bool PluginManager::loadPlugins(QStringList filterList) connect(plugin, &PluginObject::action, this, &PluginManager::actionHandler); connect(plugin, &PluginObject::message, this, &PluginManager::messageHandler); - } + + //Connect media manager to Message Handler + connect(m_mediaManager, &MediaManager::message, this, &PluginManager::messageHandler); + //Load QML plugins if(pluginsDir.cd("qml")){ for (const QString &fileName : pluginsDir.entryList(QDir::Files)) { diff --git a/includes/mediainterface.h b/includes/mediainterface.h index 3d66819..5a9b2af 100644 --- a/includes/mediainterface.h +++ b/includes/mediainterface.h @@ -16,7 +16,8 @@ class MediaInterface virtual void nextTrack() = 0; virtual void setMediaVolume(uint8_t volume) {}; virtual void setVoiceVolume(uint8_t volume) {}; - + virtual void mediaPositionChanged(quint32 position) {}; + virtual void trackChanged(QVariantMap track) {}; virtual void playbackStarted() = 0; MediaInterfaceSettings getSettings() { diff --git a/modules/phone-bluetooth/telephonymanager.cpp b/modules/phone-bluetooth/telephonymanager.cpp index 8363ac3..df2fdd3 100755 --- a/modules/phone-bluetooth/telephonymanager.cpp +++ b/modules/phone-bluetooth/telephonymanager.cpp @@ -6,7 +6,7 @@ Q_LOGGING_CATEGORY(HEADUNIT, "telephony") Q_LOGGING_CATEGORY(OFONO, "telephony [qoFono]") Q_LOGGING_CATEGORY(BLUEZ, "telephony [BluezQt]") TelephonyManager::TelephonyManager(QObject *parent) : QObject(parent), - m_bluez_manager(this), m_obexManager(this), m_ofonoManagerClass(this), m_phonebookModel(this), m_callHistoryModel(this) + m_bluez_manager(this), m_obexManager(this), m_ofonoManagerClass(this), m_phonebookModel(this), m_callHistoryModel(this), m_mediaTrackTimer(this) { m_contactsFolder = QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation) + "/contacts"; @@ -14,15 +14,22 @@ TelephonyManager::TelephonyManager(QObject *parent) : QObject(parent), m_pluginSettings.eventListeners = QStringList() << "AndroidAuto::connected"; + reconnectTimer.setSingleShot(true); + connect(&reconnectTimer, &QTimer::timeout, this, &TelephonyManager::connectToNextDevice); + BluezQt::InitManagerJob *job = m_bluez_manager.init(); job->start(); connect(job, &BluezQt::InitManagerJob::result, this, &TelephonyManager::initBluez); qDBusRegisterMetaType(); qDBusRegisterMetaType(); + + connect(&m_mediaTrackTimer, &QTimer::timeout, this, &TelephonyManager::mediaTrackTimerElapsed); + } TelephonyManager::~TelephonyManager(){ // delete m_activeDevice; + m_mediaTrackTimer.stop(); } QObject *TelephonyManager::getContextProperty(){ @@ -224,6 +231,7 @@ void TelephonyManager::setBluezDevice(BluezQt::Device *device) { qCDebug(BLUEZ) << "Device set : NULL"; } m_activeDevice = device; + initMediaPlayer(); emit activeDeviceChanged(); emit pairedDevicesChanged(); } @@ -250,6 +258,82 @@ void TelephonyManager::deviceRemoved(BluezQt::DevicePtr device){ emit pairedDevicesChanged(); } +void TelephonyManager::onMediaPosition(quint32 position) { + //TODO: Investigate why this only gets triggered sporadically or when the track changes or status changes + // Have implemented a 2Hz timer instead to get around this + m_mediaTrackPosition = position; + emit mediaPositionChanged(position); + m_mediaTrackGotPosition = true; + m_mediaTrackTimer.start(500); +} + +void TelephonyManager::mediaTrackTimerElapsed() { + if(m_activeDevice) { + if(m_mediaTrackGotPosition) { + m_mediaTrackPosition += 500; + emit mediaPositionChanged(m_mediaTrackPosition); + } + } else { + m_mediaTrackPosition = 0; + m_mediaTrackGotPosition = false; + m_mediaTrackTimer.stop(); + emit mediaPositionChanged(m_mediaTrackPosition); + } +} + +void TelephonyManager::onMediaStatus(BluezQt::MediaPlayer::Status status) { + qCDebug(BLUEZ) << "Media player status: " << status; + switch(status) { + case BluezQt::MediaPlayer::Playing: + if(!m_androidAutoConnected) + emit playbackStarted(); + break; + default: + m_mediaTrackTimer.stop(); + m_mediaTrackGotPosition = false; + break; + } +} + +void TelephonyManager::onMediaTrack(BluezQt::MediaPlayerTrack track) { + qCDebug(BLUEZ) << "Media player track: #" << track.trackNumber() << " | " << track.artist() << track.title(); + m_mediaTrackGotPosition = false; + + QVariantMap vTrack; + vTrack.insert("number",track.trackNumber()); + vTrack.insert("artist",track.artist()); + vTrack.insert("title",track.title()); + vTrack.insert("duration",track.duration()); + emit trackChanged(vTrack); +} + +void TelephonyManager::onMediaPlayer(BluezQt::MediaPlayerPtr mediaPlayer) { + if(!mediaPlayer.isNull()) { + connect(mediaPlayer.get(), &BluezQt::MediaPlayer::positionChanged, this, &TelephonyManager::onMediaPosition); + connect(mediaPlayer.get(), &BluezQt::MediaPlayer::trackChanged, this, &TelephonyManager::onMediaTrack); + connect(mediaPlayer.get(), &BluezQt::MediaPlayer::statusChanged, this, &TelephonyManager::onMediaStatus); + } else { + disconnect(mediaPlayer.get(), &BluezQt::MediaPlayer::positionChanged, this, &TelephonyManager::onMediaPosition); + disconnect(mediaPlayer.get(), &BluezQt::MediaPlayer::trackChanged, this, &TelephonyManager::onMediaTrack); + disconnect(mediaPlayer.get(), &BluezQt::MediaPlayer::statusChanged, this, &TelephonyManager::onMediaStatus); + } +} + +void TelephonyManager::initMediaPlayer() { + if(m_activeDevice) { + BluezQt::MediaPlayerPtr mediaPlayer = m_activeDevice->mediaPlayer(); + if(!mediaPlayer.isNull()) { + connect(m_activeDevice, &BluezQt::Device::mediaPlayerChanged, this, &TelephonyManager::onMediaPlayer); + onMediaPlayer(mediaPlayer); + onMediaTrack(mediaPlayer->track()); + onMediaPosition(mediaPlayer->position()); + onMediaStatus(mediaPlayer->status()); + } else { + disconnect(m_activeDevice, &BluezQt::Device::mediaPlayerChanged, this, &TelephonyManager::onMediaPlayer); + } + } +} + void TelephonyManager::deviceConnectionChanged(bool connected){ BluezQt::Device* device = dynamic_cast(QObject::sender()); if(connected){ @@ -265,11 +349,18 @@ void TelephonyManager::deviceConnectionChanged(bool connected){ } setBluezDevice(device); + initMediaPlayer(); getPhonebooks(m_activeDevice->address()); + } else { qCDebug(BLUEZ) << "Device disconnected : " << device->name(); if(m_activeDevice == device){ setBluezDevice(nullptr); + qCDebug(BLUEZ) << "Trying again : " << device->name(); + m_previouslyTriedDevice = device; + BluezQt::PendingCall * connectCall = device->connectToDevice(); + connectCall->setUserData(device->ubi()); + connect(connectCall, &BluezQt::PendingCall::finished, this, &TelephonyManager::connectToDeviceCallback); } } } @@ -301,12 +392,18 @@ void TelephonyManager::connectToNextDevice(){ } } } + m_previouslyTriedDevice = device; + if(device){ qCDebug(BLUEZ) << "Connecting to : " << device->name(); BluezQt::PendingCall * connectCall = device->connectToDevice(); connectCall->setUserData(device->ubi()); connect(connectCall, &BluezQt::PendingCall::finished, this, &TelephonyManager::connectToDeviceCallback); + } else { + if(activeDeviceFound) { + reconnectTimer.start(10000); + } } } @@ -358,6 +455,7 @@ void TelephonyManager::mediaPlaybackStarted() { emit playbackStarted(); } } + void TelephonyManager::eventMessage(QString id, QVariant message) { if(id == "AndroidAuto::connected"){ m_androidAutoConnected = message.toBool(); @@ -380,15 +478,23 @@ void TelephonyManager::actionMessage(QString id, QVariant message) { } void TelephonyManager::showOverlay(){ - QVariantMap map; - map["source"] = "qrc:/PhoneBluetooth/CallNotification.qml"; - - emit action("GUI::OpenOverlay", map); + if(m_androidAutoConnected) { + emit action("GUI::changePageIndex", 0); + } else { + QVariantMap map; + map["source"] = "qrc:/PhoneBluetooth/CallNotification.qml"; + emit action("GUI::OpenOverlay", map); + } } void TelephonyManager::hideOverlay() { - emit action("GUI::CloseOverlay", QVariant()); + if(m_androidAutoConnected) { + emit action("GUI::changePagePrevIndex", 0); + } else { + emit action("GUI::CloseOverlay", QVariant()); + } } + void TelephonyManager::pullCallHistory() { getPhonebooks(m_activeDevice->address(), true); } diff --git a/modules/phone-bluetooth/telephonymanager.h b/modules/phone-bluetooth/telephonymanager.h index 6135002..d1d4efa 100644 --- a/modules/phone-bluetooth/telephonymanager.h +++ b/modules/phone-bluetooth/telephonymanager.h @@ -28,6 +28,7 @@ #include #include +#include #include "ofonomanager.h" #include "bluezagent.h" @@ -92,8 +93,9 @@ class TelephonyManager : public QObject, PluginInterface, public MediaInterface void prevTrack() override; void nextTrack() override; void setMediaVolume(uint8_t volume) override; - void playbackStarted() override; + void trackChanged(QVariantMap track) override; + void mediaPositionChanged(quint32 position) override; public slots: void enablePairing(); @@ -124,8 +126,19 @@ private slots: void contactsFolderChanged(const QString &path); void contactsChanged(const QString &path); + + void onMediaPosition(quint32 position); + void onMediaTrack(BluezQt::MediaPlayerTrack track); + void onMediaPlayer(BluezQt::MediaPlayerPtr mediaPlayer); + void onMediaStatus(BluezQt::MediaPlayer::Status status); + void mediaTrackTimerElapsed(); + private: QString m_contactsFolder = "contacts/"; + QTimer m_mediaTrackTimer; + + quint32 m_mediaTrackPosition = 0; + bool m_mediaTrackGotPosition = false; BluezQt::Manager m_bluez_manager; BluezQt::Device* m_activeDevice = nullptr; @@ -141,12 +154,13 @@ private slots: void setBluezDevice(BluezQt::Device* device); void initAdapter(BluezQt::AdapterPtr adapter); void pullPhonebook (QString path, QString type, QString output); - + void initMediaPlayer(); QVariantMap m_pairedDevices; QStringList m_adapters; void updateAdapters(); void connectToNextDevice(); + QTimer reconnectTimer; OfonoManager m_ofonoManagerClass; PhonebookModel m_phonebookModel; PhonebookModel m_callHistoryModel;