I have made the following changes intended for : CE:Apps / voicecall Please review and accept or decline. BOSS has already run some checks on this request. See the "Messages from BOSS" section below.
https://build.pub.meego.com//request/show/6524 Thank You, tswindell [This message was auto-generated] --- Request # 6524: Messages from BOSS: State: review at 2012-08-31T14:32:58 by bossbot Reviews: accepted by bossbot : Prechecks succeeded. new for CE-maintainers : Please replace this text with a review and approve/reject the review (not the SR). BOSS will take care of the rest Changes: submit: home:tswindell:CE:Apps / voicecall -> CE:Apps / voicecall changes files: -------------- --- voicecall.changes +++ voicecall.changes @@ -0,0 +1,3 @@ +* Fri Aug 31 2012 Tom Swindell <[email protected]> - 0.2.0 +- Updated sources to latest upstream version. + old: ---- voicecall-0.1.4+git9.4b7b286.tar.gz new: ---- voicecall-0.2.0.tar.gz spec files: ----------- --- voicecall.spec +++ voicecall.spec @@ -1,26 +1,69 @@ Name: voicecall Summary: Voice Call Suite -Version: 0.1.4+git9.4b7b286 +Version: 0.2.0 Release: 1 Group: Communications/Telephony and IM License: Apache License, Version 2.0 URL: http://github.com/nemomobile/voicecall Source0: %{name}-%{version}.tar.gz Requires: tone-generator +Requires: voicecall-ui == %{version}-%{release} BuildRequires: pkgconfig(QtOpenGL) BuildRequires: pkgconfig(QtDeclarative) BuildRequires: pkgconfig(QtMultimediaKit) BuildRequires: pkgconfig(libresourceqt1) BuildRequires: pkgconfig(libpulse-mainloop-glib) BuildRequires: pkgconfig(ofono-qt) -BuildRequires: pkgconfig(TelepathyQt4) - -Obsoletes: meego-handset-dialer < 0.2.4 -Provides: meego-handset-dialer >= 0.2.4 +# May work with earlier version, but this is tested against in nemo. +# Requires header includes to be under TelepathyQt/ rather than TelepathyQt4/ +BuildRequires: pkgconfig(TelepathyQt4) >= 0.9.3 %description Next Generation Dialer Application for Nemo Mobile +%package libs +Summary: Core voicecall libraries +Group: Communications/Telephony and IM + +%description libs +Core voicecall libraries + +%package devel +Requires: voicecall-libs == %{version}-%{release} +Summary: Voicecall development package +Group: Communications/Telephony and IM + +%description devel +Voicecall development libraries and headers + +%package core +Requires: voicecall-libs == %{version}-%{release} +Summary: Core voicecall service and libraries +Group: Communications/Telephony and IM + +%description core +Core voicecall service executable, core plugins and library + +%package plugin-ofono +Requires: voicecall-core == %{version}-%{release} +Summary: Voicecall ofono plugin provider +Group: Communications/Telephony and IM + +%description plugin-ofono +Voicecall manager plugin for using ofono to make and receive calls. + +%package ui-reference +Provides: voicecall > 0.1.5 +Obsoletes: voicecall <= 0.1.5 +Provides: meego-handset-dialer >= 0.2.4 +Obsoletes: meego-handset-dialer < 0.2.4 +Requires: voicecall-core == %{version}-%{release} +Summary: Voicecall reference QML user interface +Group: Communications/Telephony and IM + +%description ui-reference +Voicecall reference QML phone application user interface + %prep %setup -q -n %{name}-%{version} @@ -33,29 +76,40 @@ rm -rf %{buildroot} %qmake_install -%post +%post libs /sbin/ldconfig -%postun +%postun libs /sbin/ldconfig -%files +%files libs %defattr(-,root,root,-) -%{_bindir}/voicecall-manager -%{_bindir}/voicecall-ui -%{_libdir}/libvoicecall.so %{_libdir}/libvoicecall.so.1 %{_libdir}/libvoicecall.so.1.0 %{_libdir}/libvoicecall.so.1.0.0 -%{_libdir}/voicecall/plugins/libvoicecall-ofono-plugin.so -%{_libdir}/voicecall/plugins/libvoicecall-pulseaudio-plugin.so -%{_libdir}/voicecall/plugins/libvoicecall-tonegend-plugin.so -%{_libdir}/voicecall/plugins/libvoicecall-telepathy-plugin.so %{_libdir}/qt4/imports/stage/rubyx/voicecall/libvoicecall.so %{_libdir}/qt4/imports/stage/rubyx/voicecall/qmldir + +%files core +%defattr(-,root,root,-) +%{_bindir}/voicecall-manager +%{_libdir}/voicecall/plugins/libvoicecall-pulseaudio-plugin.so +%{_libdir}/voicecall/plugins/libvoicecall-telepathy-plugin.so +%config %{_sysconfdir}/xdg/autostart/voicecall-manager.desktop %config %{_sysconfdir}/voicecall/modes.ini + +%files devel +%defattr(-,root,root,-) +%{_libdir}/libvoicecall.so + +%files plugin-ofono +%defattr(-,root,root,-) +%{_libdir}/voicecall/plugins/libvoicecall-ofono-plugin.so +#TODO: Add voicecall-manager -reconfigure to post/un when implemented in core. + +%files ui-reference +%defattr(-,root,root,-) +%{_bindir}/voicecall-ui %{_datadir}/voicecall-ui/qml %{_datadir}/applications/voicecall-ui.desktop -%config %{_sysconfdir}/xdg/autostart/voicecall-manager.desktop %config %{_sysconfdir}/xdg/autostart/voicecall-ui-prestart.desktop - other changes: -------------- ++++++ voicecall-0.1.4+git9.4b7b286.tar.gz -> voicecall-0.2.0.tar.gz --- lib/src/abstractvoicecallprovider.h +++ lib/src/abstractvoicecallprovider.h @@ -32,7 +32,7 @@ Q_PROPERTY(QString providerType READ providerType) Q_PROPERTY(QList<AbstractVoiceCallHandler*> voiceCalls READ voiceCalls NOTIFY voiceCallsChanged) - Q_PROPERTY(QString errorString READ errorString) + Q_PROPERTY(QString errorString READ errorString NOTIFY error) public: explicit AbstractVoiceCallProvider(QObject *parent = 0) : QObject(parent) {/* ... */} @@ -44,6 +44,8 @@ virtual QString errorString() const = 0; Q_SIGNALS: + void error(QString); + void voiceCallsChanged(); void voiceCallAdded(AbstractVoiceCallHandler *handler); void voiceCallRemoved(const QString &handlerId); --- packaging/voicecall.spec.in +++ packaging/voicecall.spec.in @@ -7,13 +7,16 @@ URL: http://github.com/nemomobile/voicecall Source0: %{name}-%{version}.tar.gz Requires: tone-generator +Requires: voicecall-ui == %{version}-%{release} BuildRequires: pkgconfig(QtOpenGL) BuildRequires: pkgconfig(QtDeclarative) BuildRequires: pkgconfig(QtMultimediaKit) BuildRequires: pkgconfig(libresourceqt1) BuildRequires: pkgconfig(libpulse-mainloop-glib) BuildRequires: pkgconfig(ofono-qt) -BuildRequires: pkgconfig(TelepathyQt4) +# May work with earlier version, but this is tested against in nemo. +# Requires header includes to be under TelepathyQt/ rather than TelepathyQt4/ +BuildRequires: pkgconfig(TelepathyQt4) >= 0.9.3 Obsoletes: meego-handset-dialer < 0.2.4 Provides: meego-handset-dialer >= 0.2.4 @@ -21,6 +24,47 @@ %description Next Generation Dialer Application for Nemo Mobile +%package libs +Summary: Core voicecall libraries +Group: Communications/Telephony and IM + +%description libs +Core voicecall libraries + +%package devel +Requires: voicecall-libs == %{version}-%{release} +Summary: Voicecall development package +Group: Communications/Telephony and IM + +%description devel +Voicecall development libraries and headers + +%package core +Requires: voicecall-libs == %{version}-%{release} +Summary: Core voicecall service and libraries +Group: Communications/Telephony and IM + +%description core +Core voicecall service executable, core plugins and library + +%package plugin-ofono +Requires: voicecall-core == %{version}-%{release} +Summary: Voicecall ofono plugin provider +Group: Communications/Telephony and IM + +%description plugin-ofono +Voicecall manager plugin for using ofono to make and receive calls. + +%package ui-reference +Provides: voicecall > 0.1.4 +Obsoletes: voicecall <= 0.1.4 +Requires: voicecall-core == %{version}-%{release} +Summary: Voicecall reference QML user interface +Group: Communications/Telephony and IM + +%description ui-reference +Voicecall reference QML phone application user interface + %prep %setup -q -n %{name}-%{version} @@ -33,29 +77,40 @@ rm -rf %{buildroot} %qmake_install -%post +%post libs /sbin/ldconfig -%postun +%postun libs /sbin/ldconfig -%files +%files libs %defattr(-,root,root,-) -%{_bindir}/voicecall-manager -%{_bindir}/voicecall-ui -%{_libdir}/libvoicecall.so %{_libdir}/libvoicecall.so.1 %{_libdir}/libvoicecall.so.1.0 %{_libdir}/libvoicecall.so.1.0.0 -%{_libdir}/voicecall/plugins/libvoicecall-ofono-plugin.so -%{_libdir}/voicecall/plugins/libvoicecall-pulseaudio-plugin.so -%{_libdir}/voicecall/plugins/libvoicecall-tonegend-plugin.so -%{_libdir}/voicecall/plugins/libvoicecall-telepathy-plugin.so %{_libdir}/qt4/imports/stage/rubyx/voicecall/libvoicecall.so %{_libdir}/qt4/imports/stage/rubyx/voicecall/qmldir + +%files core +%defattr(-,root,root,-) +%{_bindir}/voicecall-manager +%{_libdir}/voicecall/plugins/libvoicecall-pulseaudio-plugin.so +%{_libdir}/voicecall/plugins/libvoicecall-telepathy-plugin.so +%config %{_sysconfdir}/xdg/autostart/voicecall-manager.desktop %config %{_sysconfdir}/voicecall/modes.ini + +%files devel +%defattr(-,root,root,-) +%{_libdir}/libvoicecall.so + +%files plugin-ofono +%defattr(-,root,root,-) +%{_libdir}/voicecall/plugins/libvoicecall-ofono-plugin.so +#TODO: Add voicecall-manager -reconfigure to post/un when implemented in core. + +%files ui-reference +%defattr(-,root,root,-) +%{_bindir}/voicecall-ui %{_datadir}/voicecall-ui/qml %{_datadir}/applications/voicecall-ui.desktop -%config %{_sysconfdir}/xdg/autostart/voicecall-manager.desktop %config %{_sysconfdir}/xdg/autostart/voicecall-ui-prestart.desktop - --- plugins/plugins.pro +++ plugins/plugins.pro @@ -1,3 +1,3 @@ TEMPLATE = subdirs CONFIG = ordered -SUBDIRS = declarative ofono pulseaudio tonegend telepathy +SUBDIRS = declarative pulseaudio telepathy ofono --- plugins/telepathy/src/common.h +++ plugins/telepathy/src/common.h @@ -0,0 +1,35 @@ +/* + * This file is a part of the Voice Call Manager project + * + * Copyright (C) 2011-2012 Tom Swindell <[email protected]> + * + * 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, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ +#ifndef COMMON_H +#define COMMON_H + +#include <QDebug> + +#define DEBUG_T(message) qDebug() << QString("D:VCM: [%1] %2():%3: %4").arg(__FILE__).arg(__func__).arg(__LINE__).arg(message); +#define WARNING_T(message) qWarning() << QString("W:VCM: [%1] %2():%3: %4").arg(__FILE__).arg(__func__).arg(__LINE__).arg(message); + +#ifndef WANT_TRACE +# define TRACE +#else +# define TRACE qDebug() << QString("T:VCM: [%1] %2(): %3").arg(__FILE__).arg(__func__).arg(__LINE__); +#endif + +#endif // COMMON_H --- plugins/telepathy/src/src.pro +++ plugins/telepathy/src/src.pro @@ -9,11 +9,18 @@ PKGCONFIG += TelepathyQt4 +DEFINES += WANT_TRACE + HEADERS += \ - telepathyproviderplugin.h + common.h \ + telepathyproviderplugin.h \ + telepathyprovider.h \ + telepathyhandler.h SOURCES += \ - telepathyproviderplugin.cpp + telepathyproviderplugin.cpp \ + telepathyprovider.cpp \ + telepathyhandler.cpp DEFINES += PLUGIN_NAME=\\\"voicecall-telepathy-plugin\\\" DEFINES += PLUGIN_VERSION=\\\"0.0.0.1\\\" --- plugins/telepathy/src/telepathyhandler.cpp +++ plugins/telepathy/src/telepathyhandler.cpp @@ -0,0 +1,380 @@ +#include "common.h" +#include "telepathyhandler.h" + +#include "telepathyprovider.h" + +#include <TelepathyQt/Channel> +#include <TelepathyQt/CallChannel> +#include <TelepathyQt/PendingReady> + +#include <TelepathyQt/ChannelInterface> + +static const Tp::Features RequiredFeatures = Tp::Features() << Tp::StreamedMediaChannel::FeatureCore + << Tp::StreamedMediaChannel::FeatureLocalHoldState + << Tp::StreamedMediaChannel::FeatureStreams; + +class TelepathyHandlerPrivate +{ + Q_DECLARE_PUBLIC(TelepathyHandler) + +public: + TelepathyHandlerPrivate(TelepathyHandler *q, const QString &id, Tp::StreamedMediaChannelPtr c, const QDateTime &s, TelepathyProvider *p) + : q_ptr(q), handlerId(id), provider(p), startedAt(s), channel(c), + status(AbstractVoiceCallHandler::STATUS_NULL), + iCallState(NULL), iDtmf(NULL), iGroup(NULL), iHold(NULL), iServicePoint(NULL) + { /* ... */ } + + TelepathyHandler *q_ptr; + + QString handlerId; + TelepathyProvider *provider; + + QDateTime startedAt; + + AbstractVoiceCallHandler::VoiceCallStatus status; + + // TODO: This should use "CallChannel", and, handle "Farstream" usage. + // Which relies on telepathy-ring implementing these ... + + // Streamed media channel and interfaces. + Tp::StreamedMediaChannelPtr channel; + Tp::Client::ChannelInterfaceCallStateInterface *iCallState; + Tp::Client::ChannelInterfaceDTMFInterface *iDtmf; + Tp::Client::ChannelInterfaceGroupInterface *iGroup; + Tp::Client::ChannelInterfaceHoldInterface *iHold; + Tp::Client::ChannelInterfaceServicePointInterface *iServicePoint; + + void updateStatus(AbstractVoiceCallHandler::VoiceCallStatus status) + { + this->status = status; + emit q_ptr->statusChanged(); + } +}; + +TelepathyHandler::TelepathyHandler(const QString &id, Tp::StreamedMediaChannelPtr channel, const QDateTime &userActionTime, TelepathyProvider *provider) + : AbstractVoiceCallHandler(provider), d_ptr(new TelepathyHandlerPrivate(this, id, channel, userActionTime, provider)) +{ + TRACE + Q_D(const TelepathyHandler); + + QObject::connect(d->channel->becomeReady(RequiredFeatures), + SIGNAL(finished(Tp::PendingOperation*)), + SLOT(onChannelReady(Tp::PendingOperation*))); + + QObject::connect(d->channel.data(), + SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)), + SLOT(onChannelInvalidated(Tp::DBusProxy*,QString,QString))); +} + +TelepathyHandler::~TelepathyHandler() +{ + TRACE + delete this->d_ptr; +} + +AbstractVoiceCallProvider* TelepathyHandler::provider() const +{ + TRACE + Q_D(const TelepathyHandler); + return d->provider; +} + +QString TelepathyHandler::handlerId() const +{ + TRACE + Q_D(const TelepathyHandler); + return d->handlerId; +} + +QString TelepathyHandler::lineId() const +{ + TRACE + Q_D(const TelepathyHandler); + if(!d->channel->isReady()) return QString::null; + return d->channel->targetId(); +} + +QDateTime TelepathyHandler::startedAt() const +{ + TRACE + Q_D(const TelepathyHandler); + return d->startedAt; +} + +int TelepathyHandler::duration() const +{ + TRACE + Q_D(const TelepathyHandler); + return d->startedAt.secsTo(QDateTime()); +} + +bool TelepathyHandler::isMultiparty() const +{ + TRACE + Q_D(const TelepathyHandler); + if(!d->channel->isReady()) return false; + return d->channel->isConference(); +} + +bool TelepathyHandler::isEmergency() const +{ + TRACE + Q_D(const TelepathyHandler); + if(!d->channel->isReady()) return false; + return false; +} + +AbstractVoiceCallHandler::VoiceCallStatus TelepathyHandler::status() const +{ + TRACE + Q_D(const TelepathyHandler); + return d->status; +} + +//TODO: Move to AbstractVoiceCallHandler as this is generic. +QString TelepathyHandler::statusText() const +{ + TRACE + Q_D(const TelepathyHandler); + + switch(d->status) + { + case STATUS_ACTIVE: + return "active"; + case STATUS_HELD: + return "held"; + case STATUS_DIALING: + return "dialing"; + case STATUS_ALERTING: + return "alerting"; + case STATUS_INCOMING: + return "incoming"; + case STATUS_WAITING: + return "waiting"; + case STATUS_DISCONNECTED: + return "disconnected"; + + default: + return "null"; + } +} + +void TelepathyHandler::answer() +{ + TRACE + Q_D(TelepathyHandler); + QObject::connect(d->channel->acceptCall(), + SIGNAL(finished(Tp::PendingOperation*)), + SLOT(onAcceptCallFinished(Tp::PendingOperation*))); +} + +void TelepathyHandler::hangup() +{ + TRACE + Q_D(TelepathyHandler); + d->channel->hangupCall(); + QObject::connect(d->channel->hangupCall(), + SIGNAL(finished(Tp::PendingOperation*)), + SLOT(onHangupCallFinished(Tp::PendingOperation*))); +} + +//FIXME: Don't know what telepathy API provides this. +void TelepathyHandler::deflect(const QString &target) +{ + TRACE + Q_UNUSED(target) + emit this->error("NOT IMPLEMENTED YET!"); +} + +void TelepathyHandler::onChannelReady(Tp::PendingOperation *op) +{ + TRACE + Q_D(TelepathyHandler); + if(op->isError()) + { + WARNING_T(QString("Operation failed: ") + op->errorName() + ": " + op->errorMessage()); + emit this->error(QString("Telepathy Operation Failed: %1 - %2").arg(op->errorName(), op->errorMessage())); + return; + } + + DEBUG_T("Channel Ready:"); + qDebug() << "\tType:" << d->channel->channelType(); + qDebug() << "\tInterfaces:" << d->channel->interfaces(); + + //TODO: Implement handle for Splittable (DRAFT) interface? + if(d->channel->hasInterface(TP_QT_IFACE_CHANNEL_INTERFACE_CALL_STATE)) + { + DEBUG_T("Constructing call state interface."); + d->iCallState = new Tp::Client::ChannelInterfaceCallStateInterface(d->channel.data(), this); + QObject::connect(d->iCallState, + SIGNAL(CallStateChanged(uint,uint)), + SLOT(onCallStateChanged(uint,uint))); + //TODO: d->iCallState->GetCallStates(); + } + if(d->channel->hasInterface(TP_QT_IFACE_CHANNEL_INTERFACE_DTMF)) + { + DEBUG_T("Constructing dtmf interface."); + d->iDtmf = new Tp::Client::ChannelInterfaceDTMFInterface(d->channel.data()); + } + if(d->channel->hasInterface(TP_QT_IFACE_CHANNEL_INTERFACE_GROUP)) + { + DEBUG_T("Constructing group interface."); + d->iGroup = new Tp::Client::ChannelInterfaceGroupInterface(d->channel.data()); + } + if(d->channel->hasInterface(TP_QT_IFACE_CHANNEL_INTERFACE_HOLD)) + { + DEBUG_T("Constructing hold interface."); + d->iHold = new Tp::Client::ChannelInterfaceHoldInterface(d->channel.data()); + } + if(d->channel->hasInterface(TP_QT_IFACE_CHANNEL_INTERFACE_SERVICE_POINT)) + { + DEBUG_T("Constructing service point interface."); + d->iServicePoint = new Tp::Client::ChannelInterfaceServicePointInterface(d->channel.data()); + } + + QObject::connect(d->channel.data(), + SIGNAL(streamAdded(Tp::StreamedMediaStreamPtr)), + SLOT(onStreamAdded(Tp::StreamedMediaStreamPtr))); + + QObject::connect(d->channel.data(), + SIGNAL(streamRemoved(Tp::StreamedMediaStreamPtr)), + SLOT(onStreamRemoved(Tp::StreamedMediaStreamPtr))); + + QObject::connect(d->channel.data(), + SIGNAL(streamError(Tp::StreamedMediaStreamPtr,Tp::MediaStreamError,QString)), + SLOT(onStreamError(Tp::StreamedMediaStreamPtr,Tp::MediaStreamError,QString))); + + QObject::connect(d->channel.data(), + SIGNAL(streamStateChanged(Tp::StreamedMediaStreamPtr,Tp::MediaStreamState)), + SLOT(onStreamStateChanged(Tp::StreamedMediaStreamPtr,Tp::MediaStreamState))); + + //FIXME: Doesn't work, probably not the right way to do things anyway (interface access is better) + QObject::connect(d->channel.data(), SIGNAL(propertyChanged(QString)), SLOT(onChannelPropertyChanged(QString))); + + + if(d->channel->awaitingLocalAnswer()) + { + d->status = STATUS_INCOMING; + } + else if(d->channel->awaitingRemoteAnswer()) + { + d->status = STATUS_ALERTING; + } + + if(d->channel->handlerStreamingRequired()) + { + //TODO: Implement farsight support for SIP and Video calls. + } + + emit this->statusChanged(); +} + +void TelepathyHandler::onChannelPropertyChanged(const QString &property) +{ + TRACE + DEBUG_T(QString("Channel property changed: ") + property); +} + +void TelepathyHandler::onChannelInvalidated(Tp::DBusProxy *, const QString &errorName, const QString &errorMessage) +{ + TRACE + Q_D(TelepathyHandler); + + DEBUG_T(QString("Channel invalidated: ") + errorName + ": " + errorMessage); + + // It seems to get called twice. + QObject::disconnect(d->channel.data(), + SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)), + this, + SLOT(onChannelInvalidated(Tp::DBusProxy*,QString,QString))); + + emit this->invalidated(errorName, errorMessage); +} + +void TelepathyHandler::onStreamAdded(const Tp::StreamedMediaStreamPtr &stream) +{ + TRACE + Q_UNUSED(stream) +} + +void TelepathyHandler::onStreamRemoved(const Tp::StreamedMediaStreamPtr &stream) +{ + TRACE + Q_UNUSED(stream) +} + +void TelepathyHandler::onStreamError(const Tp::StreamedMediaStreamPtr &stream, Tp::MediaStreamError errorCode, const QString &errorMessage) +{ + TRACE + Q_UNUSED(stream) + Q_UNUSED(errorCode) + + emit this->error(QString("Telepathy Stream Error: %1").arg(errorMessage)); +} + +void TelepathyHandler::onStreamStateChanged(const Tp::StreamedMediaStreamPtr &stream, Tp::MediaStreamState state) +{ + TRACE + Q_UNUSED(stream) + Q_D(TelepathyHandler); + + switch(state) + { + case Tp::MediaStreamStateDisconnected: + DEBUG_T("Media stream state disconnected."); + d->status = STATUS_DISCONNECTED; + emit this->statusChanged(); + break; + + case Tp::MediaStreamStateConnecting: + DEBUG_T("Media stream state connecting."); + break; + + case Tp::MediaStreamStateConnected: + DEBUG_T("Media stream state connected."); + d->status = STATUS_ACTIVE; + emit this->statusChanged(); + break; + + default: + break; + } +} + +void TelepathyHandler::onAcceptCallFinished(Tp::PendingOperation *op) +{ + TRACE + Q_D(TelepathyHandler); + if(op->isError()) + { + WARNING_T(QString("Operation failed: ") + op->errorName() + ": " + op->errorMessage()); + emit this->error(QString("Telepathy Operation Failed: %1 - %2").arg(op->errorName(), op->errorMessage())); + return; + } + + d->status = STATUS_ACTIVE; + emit this->statusChanged(); +} + +void TelepathyHandler::onHangupCallFinished(Tp::PendingOperation *op) +{ + TRACE + Q_D(TelepathyHandler); + if(op->isError()) + { + WARNING_T(QString("Operation failed: ") + op->errorName() + ": " + op->errorMessage()); + emit this->error(QString("Telepathy Operation Failed: %1 - %2").arg(op->errorName(), op->errorMessage())); + return; + } + + d->status = STATUS_DISCONNECTED; + emit this->statusChanged(); + + emit this->invalidated("closed", "user"); +} + +void TelepathyHandler::onCallStateChanged(uint contact, uint state) +{ + TRACE + DEBUG_T(QString("Call state changed for contact %1 to state %2").arg(contact).arg(state)); +} --- plugins/telepathy/src/telepathyhandler.h +++ plugins/telepathy/src/telepathyhandler.h @@ -0,0 +1,66 @@ +#ifndef TELEPATHYHANDLER_H +#define TELEPATHYHANDLER_H + +#include <abstractvoicecallhandler.h> + +#include <TelepathyQt/StreamedMediaChannel> + +class TelepathyProvider; + +class TelepathyHandler : public AbstractVoiceCallHandler +{ + Q_OBJECT + +public: + explicit TelepathyHandler(const QString &id, Tp::StreamedMediaChannelPtr channel, const QDateTime &userActionTime, TelepathyProvider *provider = 0); + ~TelepathyHandler(); + + /*** AbstractVoiceCallHandler Implementation ***/ + AbstractVoiceCallProvider* provider() const; + QString handlerId() const; + QString lineId() const; + QDateTime startedAt() const; + int duration() const; + bool isMultiparty() const; + bool isEmergency() const; + + VoiceCallStatus status() const; + QString statusText() const; + + /*** TelepathyHandler Implementation ***/ + Tp::StreamedMediaChannel channel() const; + +Q_SIGNALS: + /*** TelepathyHandler Implementation ***/ + void error(const QString &errorMessage); + void invalidated(const QString &errorName, const QString &errorMessage); + +public Q_SLOTS: + /*** AbstractVoiceCallHandler Implementation ***/ + void answer(); + void hangup(); + void deflect(const QString &target); + +protected Q_SLOTS: + void onChannelReady(Tp::PendingOperation *op); + void onChannelPropertyChanged(const QString &property); + void onChannelInvalidated(Tp::DBusProxy*,const QString &errorName, const QString &errorMessage); + + void onStreamAdded(const Tp::StreamedMediaStreamPtr &stream); + void onStreamRemoved(const Tp::StreamedMediaStreamPtr &stream); + void onStreamStateChanged(const Tp::StreamedMediaStreamPtr &stream, Tp::MediaStreamState state); + void onStreamError(const Tp::StreamedMediaStreamPtr &stream, Tp::MediaStreamError errorCode, const QString &errorMessage); + + void onAcceptCallFinished(Tp::PendingOperation *op); + void onHangupCallFinished(Tp::PendingOperation *op); + + void onCallStateChanged(uint contact, uint state); + +private: + class TelepathyHandlerPrivate *d_ptr; + + Q_DISABLE_COPY(TelepathyHandler) + Q_DECLARE_PRIVATE(TelepathyHandler) +}; + +#endif // TELEPATHYHANDLER_H --- plugins/telepathy/src/telepathyprovider.cpp +++ plugins/telepathy/src/telepathyprovider.cpp @@ -0,0 +1,199 @@ +#include "common.h" + +#include "telepathyhandler.h" +#include "telepathyprovider.h" + +#include <TelepathyQt/AbstractClient> +#include <TelepathyQt/ClientRegistrar> +#include <TelepathyQt/ChannelClassSpec> + +#include <TelepathyQt/PendingReady> +#include <TelepathyQt/PendingChannel> +#include <TelepathyQt/PendingChannelRequest> + +class TelepathyProviderPrivate +{ + Q_DECLARE_PUBLIC(TelepathyProvider) + +public: + TelepathyProviderPrivate(Tp::AccountPtr a, VoiceCallManagerInterface *m, TelepathyProvider *q) + : q_ptr(q), manager(m), account(a), + errorString(QString::null), + tpClientHandler(NULL), tpClientRegistrar(NULL), tpPendingChannel(NULL) + { /* ... */ } + + TelepathyProvider *q_ptr; + VoiceCallManagerInterface *manager; + + Tp::AccountPtr account; + + QString errorString; + + QHash<QString,AbstractVoiceCallHandler*> voiceCalls; + + Tp::AbstractClientPtr tpClientHandler; + Tp::ClientRegistrarPtr tpClientRegistrar; + + Tp::PendingChannel *tpPendingChannel; + + static const Tp::ChannelClassSpecList CHANNEL_SPECS; +}; + +const Tp::ChannelClassSpecList TelepathyProviderPrivate::CHANNEL_SPECS = + (Tp::ChannelClassSpecList() + << Tp::ChannelClassSpec::audioCall() + << Tp::ChannelClassSpec::streamedMediaCall() + << Tp::ChannelClassSpec::unnamedStreamedMediaCall() + << Tp::ChannelClassSpec::streamedMediaAudioCall() + << Tp::ChannelClassSpec::unnamedStreamedMediaCall()); + +TelepathyProvider::TelepathyProvider(Tp::AccountPtr account, VoiceCallManagerInterface *manager, QObject *parent) + : AbstractVoiceCallProvider(parent), + Tp::AbstractClientHandler(TelepathyProviderPrivate::CHANNEL_SPECS), + d_ptr(new TelepathyProviderPrivate(account, manager, this)) +{ + TRACE + Q_D(TelepathyProvider); + + d->tpClientHandler = Tp::AbstractClientPtr(this); + d->tpClientRegistrar = Tp::ClientRegistrar::create(); + + if(!d->tpClientRegistrar->registerClient(d->tpClientHandler, "voicecall", true)) + { + WARNING_T("Failed to register telepathy client!"); + d->errorString = "Failed to register telepathy client!"; + emit this->error(d->errorString); + } +} + +TelepathyProvider::~TelepathyProvider() +{ + TRACE + Q_D(TelepathyProvider); + d->tpClientRegistrar->unregisterClient(d->tpClientHandler); + delete d; +} + +QString TelepathyProvider::errorString() const +{ + TRACE + Q_D(const TelepathyProvider); + return d->errorString; +} + +QString TelepathyProvider::providerId() const +{ + TRACE + Q_D(const TelepathyProvider); + return QString("telepathy-") + d->account->uniqueIdentifier(); +} + +QString TelepathyProvider::providerType() const +{ + TRACE + return "cellular"; +} + +QList<AbstractVoiceCallHandler*> TelepathyProvider::voiceCalls() const +{ + TRACE + Q_D(const TelepathyProvider); + return d->voiceCalls.values(); +} + +bool TelepathyProvider::dial(const QString &msisdn) +{ + TRACE + Q_D(TelepathyProvider); + if(d->tpPendingChannel) + { + d->errorString = "Can't initiate a call when one is pending!"; + WARNING_T(d->errorString); + emit this->error(d->errorString); + return false; + } + + d->tpPendingChannel = d->account->ensureAndHandleStreamedMediaAudioCall(msisdn); + QObject::connect(d->tpPendingChannel, + SIGNAL(finished(Tp::PendingOperation*)), + SLOT(onDialFinished(Tp::PendingOperation*))); + return true; +} + +void TelepathyProvider::handleChannels(const Tp::MethodInvocationContextPtr<> &context, + const Tp::AccountPtr &account, + const Tp::ConnectionPtr &connection, + const QList<Tp::ChannelPtr> &channels, + const QList<Tp::ChannelRequestPtr> &requestsSatisfied, + const QDateTime &userActionTime, + const HandlerInfo &handlerInfo) +{ + TRACE + Q_UNUSED(account) + Q_UNUSED(account) + Q_UNUSED(connection) + Q_UNUSED(requestsSatisfied) + Q_UNUSED(handlerInfo) + + DEBUG_T(QString("Found %1 channel/s.").arg(channels.size())); + + foreach(Tp::ChannelPtr ch, channels) + { + this->createHandler(ch, userActionTime); + } + + emit this->voiceCallsChanged(); + context->setFinished(); +} + +void TelepathyProvider::createHandler(Tp::ChannelPtr ch, const QDateTime &userActionTime) +{ + TRACE + Q_D(TelepathyProvider); + DEBUG_T(QString("\tProcessing channel: %1").arg(ch->objectPath())); + TelepathyHandler *handler = new TelepathyHandler(d->manager->generateHandlerId(), Tp::StreamedMediaChannelPtr::staticCast(ch), userActionTime, this); + d->voiceCalls.insert(handler->handlerId(), handler); + + QObject::connect(handler, SIGNAL(error(QString)), SIGNAL(error(QString))); + + QObject::connect(handler, + SIGNAL(invalidated(QString,QString)), + SLOT(onHandlerInvalidated(QString,QString))); + + emit this->voiceCallAdded(handler); +} + +void TelepathyProvider::onDialFinished(Tp::PendingOperation *op) +{ + TRACE + Q_D(TelepathyProvider); + if(op->isError()) + { + WARNING_T(QString("Operation failed: ") + op->errorName() + ": " + op->errorMessage()); + d->tpPendingChannel = NULL; + d->errorString = QString("Telepathy Operation Failed: %1 - %2").arg(op->errorName(), op->errorMessage()); + emit this->error(d->errorString); + return; + } + + this->createHandler(d->tpPendingChannel->channel(), QDateTime()); + d->tpPendingChannel = NULL; + + emit this->voiceCallsChanged(); +} + +void TelepathyProvider::onHandlerInvalidated(const QString &errorName, const QString &errorMessage) +{ + TRACE + Q_UNUSED(errorName) + Q_UNUSED(errorMessage) + Q_D(TelepathyProvider); + + TelepathyHandler *handler = qobject_cast<TelepathyHandler*>(QObject::sender()); + d->voiceCalls.remove(handler->handlerId()); + + emit this->voiceCallRemoved(handler->handlerId()); + emit this->voiceCallsChanged(); + + handler->deleteLater(); +} --- plugins/telepathy/src/telepathyprovider.h +++ plugins/telepathy/src/telepathyprovider.h @@ -0,0 +1,51 @@ +#ifndef TELEPATHYPROVIDER_H +#define TELEPATHYPROVIDER_H + +#include <abstractvoicecallprovider.h> +#include <voicecallmanagerinterface.h> + +#include <TelepathyQt/AbstractClientHandler> +#include <TelepathyQt/MethodInvocationContext> +#include <TelepathyQt/PendingOperation> + +class TelepathyProvider : public AbstractVoiceCallProvider, public Tp::AbstractClientHandler +{ + Q_OBJECT +public: + explicit TelepathyProvider(Tp::AccountPtr account, VoiceCallManagerInterface *manager, QObject *parent = 0); + ~TelepathyProvider(); + + QString errorString() const; + + QString providerId() const; + QString providerType() const; + + QList<AbstractVoiceCallHandler*> voiceCalls() const; + + bool bypassApproval() const {return true;} + void handleChannels(const Tp::MethodInvocationContextPtr<> &context, + const Tp::AccountPtr &account, + const Tp::ConnectionPtr &connection, + const QList<Tp::ChannelPtr> &channels, + const QList<Tp::ChannelRequestPtr> &requestsSatisfied, + const QDateTime &userActionTime, + const HandlerInfo &handlerInfo); + +public Q_SLOTS: + bool dial(const QString &msisdn); + +protected Q_SLOTS: + void onDialFinished(Tp::PendingOperation *op); + void onHandlerInvalidated(const QString &errorName, const QString &errorMessage); + +protected: + void createHandler(Tp::ChannelPtr ch, const QDateTime &userActionTime); + +private: + class TelepathyProviderPrivate *d_ptr; + + Q_DISABLE_COPY(TelepathyProvider) + Q_DECLARE_PRIVATE(TelepathyProvider) +}; + +#endif // TELEPATHYPROVIDER_H --- plugins/telepathy/src/telepathyproviderplugin.cpp +++ plugins/telepathy/src/telepathyproviderplugin.cpp @@ -19,10 +19,23 @@ * */ #include "common.h" + #include "telepathyproviderplugin.h" +#include "telepathyprovider.h" + +#include <voicecallmanagerinterface.h> #include <QtPlugin> +#include <TelepathyQt/Types> + +#include <TelepathyQt/Account> +#include <TelepathyQt/AccountSet> +#include <TelepathyQt/AccountManager> + +#include <TelepathyQt/PendingReady> +#include <TelepathyQt/PendingStringList> + class TelepathyProviderPluginPrivate { Q_DECLARE_PUBLIC(TelepathyProviderPlugin) @@ -32,13 +45,18 @@ : q_ptr(q), manager(NULL) {/* ... */} - TelepathyProviderPlugin *q_ptr; + TelepathyProviderPlugin *q_ptr; VoiceCallManagerInterface *manager; + + Tp::AccountManagerPtr am; + + QHash<QString,TelepathyProvider*> providers; }; TelepathyProviderPlugin::TelepathyProviderPlugin(QObject *parent) - : AbstractVoiceCallManagerPlugin(parent), d_ptr(new TelepathyProviderPluginPrivate(this)) + : AbstractVoiceCallManagerPlugin(parent), + d_ptr(new TelepathyProviderPluginPrivate(this)) { TRACE } @@ -46,8 +64,7 @@ TelepathyProviderPlugin::~TelepathyProviderPlugin() { TRACE - Q_D(TelepathyProviderPlugin); - delete d; + delete this->d_ptr; } QString TelepathyProviderPlugin::pluginId() const @@ -65,6 +82,9 @@ bool TelepathyProviderPlugin::initialize() { TRACE + Q_D(TelepathyProviderPlugin); + Tp::registerTypes(); + d->am = Tp::AccountManager::create(); return true; } @@ -72,8 +92,10 @@ { TRACE Q_D(TelepathyProviderPlugin); - d->manager = manager; + QObject::connect(d->am->becomeReady(), + SIGNAL(finished(Tp::PendingOperation*)), + SLOT(onAccountManagerReady(Tp::PendingOperation*))); return true; } @@ -101,4 +123,41 @@ TRACE } +void TelepathyProviderPlugin::onAccountManagerReady(Tp::PendingOperation *op) +{ + TRACE + Q_D(TelepathyProviderPlugin); + if(op->isError()) + { + WARNING_T(QString("Operation failed: ") + op->errorName() + ": " + op->errorMessage()); + return; + } + + foreach(Tp::AccountPtr account, d->am->allAccounts()) + { + qDebug() << "Found account:" << account->displayName(); + qDebug() << "\tManager Name:" << account->cmName(); + qDebug() << "\tProtocol Name:" << account->protocolName(); + qDebug() << "\tService Name:" << account->serviceName(); + + if(account->protocolName() == "tel") + { + if(d->providers.contains(account->uniqueIdentifier())) + { + DEBUG_T("Ignoring already registered account."); + continue; + } + + DEBUG_T(QString("Registering provider: ") + account->uniqueIdentifier()); + TelepathyProvider *tp = new TelepathyProvider(account, d->manager, this); + d->providers.insert(account->uniqueIdentifier(), tp); + d->manager->appendProvider(tp); + } + else + { + DEBUG_T("Ignoring account due to unrecognised protocol."); + } + } +} + Q_EXPORT_PLUGIN2(voicecall-telepathy-plugin, TelepathyProviderPlugin) --- plugins/telepathy/src/telepathyproviderplugin.h +++ plugins/telepathy/src/telepathyproviderplugin.h @@ -3,6 +3,8 @@ #include <abstractvoicecallmanagerplugin.h> +#include <TelepathyQt/PendingOperation> + class TelepathyProviderPlugin : public AbstractVoiceCallManagerPlugin { Q_OBJECT @@ -24,6 +26,9 @@ bool resume(); void finalize(); +protected Q_SLOTS: + void onAccountManagerReady(Tp::PendingOperation *op); + private: class TelepathyProviderPluginPrivate *d_ptr;
