diff --git a/dialer/CMakeLists.txt b/dialer/CMakeLists.txt index 1756e60a..0481b8f8 100644 --- a/dialer/CMakeLists.txt +++ b/dialer/CMakeLists.txt @@ -2,5 +2,7 @@ kpackage_install_package(package org.kde.phone.dialer genericqml) install(FILES package/metadata.desktop DESTINATION ${XDG_APPS_INSTALL_DIR} RENAME org.kde.phone.dialer.desktop) +include_directories(${TELEPATHY_QT5_INCLUDE_DIR}) + add_subdirectory(src) add_subdirectory(plugin) diff --git a/dialer/plugin/CMakeLists.txt b/dialer/plugin/CMakeLists.txt index c1b9f303..ca42c8a6 100644 --- a/dialer/plugin/CMakeLists.txt +++ b/dialer/plugin/CMakeLists.txt @@ -1,5 +1,3 @@ -include_directories(${TELEPATHY_QT5_INCLUDE_DIR}) - set(tpcallerplugin_SRCS tp-call-plugin.cpp tp-caller.cpp diff --git a/dialer/src/CMakeLists.txt b/dialer/src/CMakeLists.txt index c2980082..928a05ac 100644 --- a/dialer/src/CMakeLists.txt +++ b/dialer/src/CMakeLists.txt @@ -3,6 +3,8 @@ set(plasmaphonedialer_SRCS main.cpp dialerutils.cpp + call-handler.cpp + call-manager.cpp ) add_executable(plasmaphonedialer ${plasmaphonedialer_SRCS}) @@ -20,7 +22,15 @@ target_link_libraries(plasmaphonedialer KF5::QuickAddons KF5::DBusAddons KF5::Notifications + ${TELEPATHY_QT5_LIBRARIES} ) install(TARGETS plasmaphonedialer ${INSTALL_TARGETS_DEFAULT_ARGS}) install(FILES plasma_dialer.notifyrc DESTINATION ${KDE_INSTALL_KNOTIFY5RCDIR}) + +configure_file(org.freedesktop.Telepathy.Client.Plasma.Dialer.service.in + org.freedesktop.Telepathy.Client.Plasma.Dialer.service) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/org.freedesktop.Telepathy.Client.Plasma.Dialer.service + DESTINATION ${DBUS_SERVICES_INSTALL_DIR}) + +install(FILES Plasma.Dialer.client DESTINATION ${SHARE_INSTALL_PREFIX}/telepathy/clients/) diff --git a/dialer/src/Plasma.Dialer.client b/dialer/src/Plasma.Dialer.client new file mode 100644 index 00000000..257350cc --- /dev/null +++ b/dialer/src/Plasma.Dialer.client @@ -0,0 +1,27 @@ +[org.freedesktop.Telepathy.Client] +Interfaces=org.freedesktop.Telepathy.Client.Handler + +[org.freedesktop.Telepathy.Client.Handler.HandlerChannelFilter 0] +org.freedesktop.Telepathy.Channel.ChannelType s=org.freedesktop.Telepathy.Channel.Type.Call1 +org.freedesktop.Telepathy.Channel.TargetHandleType u=1 + +[org.freedesktop.Telepathy.Client.Handler.HandlerChannelFilter 1] +org.freedesktop.Telepathy.Channel.ChannelType s=org.freedesktop.Telepathy.Channel.Type.Call1 +org.freedesktop.Telepathy.Channel.TargetHandleType u=1 +org.freedesktop.Telepathy.Channel.Type.Call1.InitialAudio b=true + +[org.freedesktop.Telepathy.Client.Handler.HandlerChannelFilter 2] +org.freedesktop.Telepathy.Channel.ChannelType s=org.freedesktop.Telepathy.Channel.Type.Call1 +org.freedesktop.Telepathy.Channel.TargetHandleType u=1 +org.freedesktop.Telepathy.Channel.Type.Call1.InitialVideo b=true + +[org.freedesktop.Telepathy.Client.Handler] +BypassApproval=true + +[org.freedesktop.Telepathy.Client.Handler.Capabilities] +org.freedesktop.Telepathy.Channel.Type.Call1/audio=true +org.freedesktop.Telepathy.Channel.Type.Call1/video=true +org.freedesktop.Telepathy.Channel.Type.Call1/ice=true +org.freedesktop.Telepathy.Channel.Type.Call1/gtalk-p2p=true +org.freedesktop.Telepathy.Channel.Type.Call1/shm=true +org.freedesktop.Telepathy.Channel.Type.Call1/video/h264=true diff --git a/dialer/src/call-handler.cpp b/dialer/src/call-handler.cpp new file mode 100644 index 00000000..94a4dd35 --- /dev/null +++ b/dialer/src/call-handler.cpp @@ -0,0 +1,92 @@ +/* + Copyright (C) 2009-2012 George Kiagiadakis + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#include "call-handler.h" +#include "call-manager.h" +#include "dialerutils.h" + +#include +#include + +static inline Tp::ChannelClassSpecList channelClassSpecList() +{ + return Tp::ChannelClassSpecList() << Tp::ChannelClassSpec::audioCall(); +} + +static inline Tp::AbstractClientHandler::Capabilities capabilities() +{ + Tp::AbstractClientHandler::Capabilities caps; + + //we support both audio and video in calls + caps.setToken(TP_QT_IFACE_CHANNEL_TYPE_CALL + QLatin1String("/audio")); +// caps.setToken(TP_QT_IFACE_CHANNEL_TYPE_CALL + QLatin1String("/video")); + + //transport methods - farstream supports them all + caps.setToken(TP_QT_IFACE_CHANNEL_TYPE_CALL + QLatin1String("/ice")); + caps.setToken(TP_QT_IFACE_CHANNEL_TYPE_CALL + QLatin1String("/gtalk-p2p")); + caps.setToken(TP_QT_IFACE_CHANNEL_TYPE_CALL + QLatin1String("/shm")); + + //significant codecs + caps.setToken(TP_QT_IFACE_CHANNEL_TYPE_CALL + QLatin1String("/video/h264")); + + return caps; +} + +CallHandler::CallHandler(DialerUtils *utils) + : Tp::AbstractClientHandler(channelClassSpecList(), capabilities()) +{ + m_dialerUtils = utils; + qDebug() << "Call handler ready"; +} + +CallHandler::~CallHandler() +{ +} + +bool CallHandler::bypassApproval() const +{ + return true; +} + +void CallHandler::handleChannels(const Tp::MethodInvocationContextPtr<> & context, + const Tp::AccountPtr & account, + const Tp::ConnectionPtr & connection, + const QList & channels, + const QList & requestsSatisfied, + const QDateTime & userActionTime, + const Tp::AbstractClientHandler::HandlerInfo & handlerInfo) +{ + Q_UNUSED(account); + Q_UNUSED(connection); + Q_UNUSED(requestsSatisfied); + Q_UNUSED(userActionTime); + Q_UNUSED(handlerInfo); + + Q_FOREACH(const Tp::ChannelPtr & channel, channels) { + Tp::CallChannelPtr callChannel = Tp::CallChannelPtr::qObjectCast(channel); + if (!callChannel) { + qDebug() << "Channel is not a Call channel. Ignoring"; + continue; + } + //check if any call manager is already handling this channel + if (!handledCallChannels.contains(callChannel)) { + handledCallChannels.append(callChannel); + new CallManager(callChannel, m_dialerUtils, this); + } + } + + context->setFinished(); +} diff --git a/dialer/src/call-handler.h b/dialer/src/call-handler.h new file mode 100644 index 00000000..d2049a99 --- /dev/null +++ b/dialer/src/call-handler.h @@ -0,0 +1,44 @@ +/* + Copyright (C) 2009 George Kiagiadakis + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#ifndef CALL_HANDLER_H +#define CALL_HANDLER_H + +#include + +class DialerUtils; + +class CallHandler : public QObject, public Tp::AbstractClientHandler +{ + Q_OBJECT +public: + CallHandler(DialerUtils *utils); + virtual ~CallHandler(); + + virtual bool bypassApproval() const; + virtual void handleChannels(const Tp::MethodInvocationContextPtr<> & context, + const Tp::AccountPtr & account, + const Tp::ConnectionPtr & connection, + const QList & channels, + const QList & requestsSatisfied, + const QDateTime & userActionTime, + const Tp::AbstractClientHandler::HandlerInfo & handlerInfo); +private: + QList handledCallChannels; + DialerUtils *m_dialerUtils; +}; + +#endif diff --git a/dialer/src/call-manager.cpp b/dialer/src/call-manager.cpp new file mode 100644 index 00000000..de917d9a --- /dev/null +++ b/dialer/src/call-manager.cpp @@ -0,0 +1,182 @@ +/* + Copyright (C) 2012 George Kiagiadakis + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . +*/ +#include "call-manager.h" +#include "dialerutils.h" +// #include "call-window.h" +// #include "approver.h" +// #include "../libktpcall/call-channel-handler.h" +// #include "ktp_call_ui_debug.h" + +// #include + +struct CallManager::Private +{ + Tp::CallChannelPtr callChannel; +// CallChannelHandler *channelHandler; +// QPointer callWindow; +// QPointer approver; + DialerUtils *dialerUtils; +}; + +CallManager::CallManager(const Tp::CallChannelPtr &callChannel, DialerUtils *dialerUtils, QObject *parent) + : QObject(parent), d(new Private) +{ +// KTp::TelepathyHandlerApplication::newJob(); + + d->dialerUtils = dialerUtils; + d->callChannel = callChannel; + connect(callChannel.data(), SIGNAL(callStateChanged(Tp::CallState)), + SLOT(onCallStateChanged(Tp::CallState))); + + //create the channel handler +// d->channelHandler = new CallChannelHandler(callChannel, this); + + //delete the CallManager when the channel has closed + //and the farstream side has safely shut down. + //NOTE this MUST be used with Qt::QueuedConnection because of + // https://bugreports.qt-project.org/browse/QTBUG-24571 +// connect(d->channelHandler, SIGNAL(channelClosed()), +// this, SLOT(deleteLater()), Qt::QueuedConnection); + + //bring us up-to-date with the current call state + onCallStateChanged(d->callChannel->callState()); +} + +CallManager::~CallManager() +{ + qDebug() << "Deleting CallManager"; + + //delete the window just in case CallManager was deleted + //before the channel entered CallStateEnded +// delete d->callWindow.data(); +// delete d; + +// KTp::TelepathyHandlerApplication::jobFinished(); +} + +void CallManager::onCallStateChanged(Tp::CallState state) +{ + qDebug() << "new call state:" << state; + + switch (state) { + case Tp::CallStatePendingInitiator: + Q_ASSERT(d->callChannel->isRequested()); + (void) d->callChannel->accept(); + break; + case Tp::CallStateInitialising: + if (d->callChannel->isRequested()) { + d->dialerUtils->setCallState("dialing"); + + //show status that the call is conneting +// ensureCallWindow(); +// d->callWindow.data()->setStatus(CallWindow::StatusConnecting); + } else { + qDebug() << "Call is initialising"; + } + break; + case Tp::CallStateInitialised: + if (d->callChannel->isRequested()) { + d->dialerUtils->setCallState("dialing"); + //show status that the remote end is ringing +// ensureCallWindow(); +// d->callWindow.data()->setStatus(CallWindow::StatusRemoteRinging); + } else { + d->dialerUtils->setCallState("incoming"); + connect(d->dialerUtils, &DialerUtils::acceptCall, this, &CallManager::onCallAccepted); + connect(d->dialerUtils, &DialerUtils::rejectCall, this, &CallManager::onCallRejected); + //show approver; + (void) d->callChannel->setRinging(); + } + break; + case Tp::CallStateAccepted: + if (d->callChannel->isRequested()) { + d->dialerUtils->setCallState("answered"); + //show status that the remote end accepted the call +// ensureCallWindow(); +// d->callWindow.data()->setStatus(CallWindow::StatusRemoteAccepted); + } else { + //hide approver & show call window +// delete d->approver.data(); +// ensureCallWindow(); +// d->callWindow.data()->setStatus(CallWindow::StatusConnecting); + } + break; + case Tp::CallStateActive: + //normally the approver is already deleted and the call window + //already exists at this point, but we just want to be safe + //in case the CM decides to do a weird state jump + if (!d->callChannel->isRequested()) { +// delete d->approver.data(); + } + d->dialerUtils->setCallState("active"); +// ensureCallWindow(); +// d->callWindow.data()->setStatus(CallWindow::StatusActive); + break; + case Tp::CallStateEnded: + d->dialerUtils->setCallState("ended"); + //if we requested the call, make sure we have a window to show the error (if any) +// if (d->callChannel->isRequested()) { +// ensureCallWindow(); +// } + +// if (d->callWindow) { +// Tp::CallStateReason reason = d->callChannel->callStateReason(); +// d->callWindow.data()->setStatus(CallWindow::StatusDisconnected, reason); +// +// //kill the call manager when the call window is closed, +// //after shutting down the channelHandler +// connect(d->callWindow.data(), SIGNAL(destroyed()), d->channelHandler, SLOT(shutdown())); +// } else { +// //missed the call +// qCDebug(KTP_CALL_UI) << "missed call"; +// delete d->approver.data(); +// d->channelHandler->shutdown(); +// } + break; + default: + Q_ASSERT(false); + } +} + +void CallManager::onCallAccepted() +{ + (void) d->callChannel->accept(); +} + +void CallManager::onCallRejected() +{ + (void) d->callChannel->hangup(Tp::CallStateChangeReasonRejected, TP_QT_ERROR_REJECTED); +} + +void CallManager::ensureCallWindow() +{ +// if (!d->callWindow) { +// d->callWindow = new CallWindow(d->callChannel); +// d->callWindow.data()->show(); +// d->callWindow.data()->setAttribute(Qt::WA_DeleteOnClose); +// +// connect(d->channelHandler, SIGNAL(contentAdded(CallContentHandler*)), +// d->callWindow.data(), SLOT(onContentAdded(CallContentHandler*))); +// connect(d->channelHandler, SIGNAL(contentRemoved(CallContentHandler*)), +// d->callWindow.data(), SLOT(onContentRemoved(CallContentHandler*))); +// +// //inform the ui about already existing contents +// Q_FOREACH(CallContentHandler *content, d->channelHandler->contents()) { +// d->callWindow.data()->onContentAdded(content); +// } +// } +} diff --git a/dialer/src/call-manager.h b/dialer/src/call-manager.h new file mode 100644 index 00000000..ae35c103 --- /dev/null +++ b/dialer/src/call-manager.h @@ -0,0 +1,45 @@ +/* + Copyright (C) 2012 George Kiagiadakis + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . +*/ +#ifndef CALL_MANAGER_H +#define CALL_MANAGER_H + +#include +#include + +class DialerUtils; + +class CallManager : public QObject +{ + Q_OBJECT +public: + explicit CallManager(const Tp::CallChannelPtr &callChannel, DialerUtils *dialerUtils, QObject *parent = 0); + virtual ~CallManager(); + +private Q_SLOTS: + void onCallStateChanged(Tp::CallState state); + void onCallAccepted(); + void onCallRejected(); + +private: + void ensureCallWindow(); + +private: + struct Private; + Private *const d; +}; + +#endif // CALL_MANAGER_H diff --git a/dialer/src/main.cpp b/dialer/src/main.cpp index 623c4c95..bb851d8e 100644 --- a/dialer/src/main.cpp +++ b/dialer/src/main.cpp @@ -20,6 +20,14 @@ #include #include "dialerutils.h" +#include "call-handler.h" + +#include +#include +#include +#include +#include +#include #include #include @@ -125,6 +133,37 @@ int main(int argc, char **argv) qWarning() << "Error loading the ApplicationWindow"; } + Tp::AccountFactoryPtr accountFactory = Tp::AccountFactory::create(QDBusConnection::sessionBus(), + Tp::Features() << Tp::Account::FeatureCore + ); + + Tp::ConnectionFactoryPtr connectionFactory = Tp::ConnectionFactory::create(QDBusConnection::sessionBus(), + Tp::Features() << Tp::Connection::FeatureCore + << Tp::Connection::FeatureSelfContact + ); + + Tp::ChannelFactoryPtr channelFactory = Tp::ChannelFactory::create(QDBusConnection::sessionBus()); + channelFactory->addCommonFeatures(Tp::Channel::FeatureCore); + channelFactory->addFeaturesForCalls(Tp::Features() << Tp::CallChannel::FeatureContents + << Tp::CallChannel::FeatureCallState + << Tp::CallChannel::FeatureCallMembers + << Tp::CallChannel::FeatureLocalHoldState + ); + + Tp::ContactFactoryPtr contactFactory = Tp::ContactFactory::create(Tp::Features() << Tp::Contact::FeatureAlias + << Tp::Contact::FeatureAvatarData + ); + + +// app.setQuitOnLastWindowClosed(true); + + Tp::ClientRegistrarPtr registrar = + Tp::ClientRegistrar::create(accountFactory, connectionFactory, + channelFactory, contactFactory); + + Tp::SharedPtr callHandler(new CallHandler(dialerUtils)); + registrar->registerClient(Tp::AbstractClientPtr::dynamicCast(callHandler), "Phone.Dialer"); + return app.exec(); } diff --git a/dialer/src/org.freedesktop.Telepathy.Client.Plasma.Dialer.service.in b/dialer/src/org.freedesktop.Telepathy.Client.Plasma.Dialer.service.in new file mode 100644 index 00000000..80d0a5a1 --- /dev/null +++ b/dialer/src/org.freedesktop.Telepathy.Client.Plasma.Dialer.service.in @@ -0,0 +1,3 @@ +[D-BUS Service] +Name=org.freedesktop.Telepathy.Client.Plasma.Dialer +Exec=@CMAKE_INSTALL_PREFIX@/plasmaphonedialer