diff --git a/plugins/providers/telepathy/src/callchannelhandler.cpp b/plugins/providers/telepathy/src/callchannelhandler.cpp new file mode 100644 index 0000000..a25b5b5 --- /dev/null +++ b/plugins/providers/telepathy/src/callchannelhandler.cpp @@ -0,0 +1,504 @@ +/* + * This file is a part of the Voice Call Manager project + * + * Copyright (C) 2011-2015 Tom Swindell + * + * 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. + * + */ +#include "common.h" +#include "callchannelhandler.h" + +#include "farstreamchannel.h" +#include "telepathyprovider.h" + +#include +#include +#include + +#include +#include +#include + +#include +#include + +static quint64 get_tick() +{ +#if defined(CLOCK_BOOTTIME) + int id = CLOCK_BOOTTIME; +#else + int id = CLOCK_MONOTONIC; +#endif + + quint64 res = 0; + + struct timespec ts; + + if(clock_gettime(id, &ts) == 0) { + res = ts.tv_sec; + res *= 1000; + res += ts.tv_nsec / 1000000; + } + + return res; +} + +class CallChannelHandlerPrivate +{ + Q_DECLARE_PUBLIC(CallChannelHandler) + +public: + CallChannelHandlerPrivate(CallChannelHandler *q, const QString &id, Tp::CallChannelPtr c, const QDateTime &s, TelepathyProvider *p) + : q_ptr(q), handlerId(id), provider(p), startedAt(s), status(AbstractVoiceCallHandler::STATUS_NULL), + channel(c), fsChannel(NULL), duration(0), durationTimerId(-1), isEmergency(false), + isForwarded(false), isIncoming(false) + { /* ... */ } + + CallChannelHandler *q_ptr; + + QString handlerId; + TelepathyProvider *provider; + + QDateTime startedAt; + + AbstractVoiceCallHandler::VoiceCallStatus status; + + Tp::CallChannelPtr channel; // CallChannel or StreamedMediaChannel + FarstreamChannel *fsChannel; + + quint64 duration; + quint64 connectedAt; + int durationTimerId; + QElapsedTimer elapsedTimer; + bool isEmergency; + bool isForwarded; + bool isIncoming; +}; + +CallChannelHandler::CallChannelHandler(const QString &id, Tp::CallChannelPtr channel, const QDateTime &userActionTime, TelepathyProvider *provider) + : AbstractVoiceCallHandler(provider), d_ptr(new CallChannelHandlerPrivate(this, id, channel, userActionTime, provider)) +{ + TRACE + Q_D(CallChannelHandler); + + QObject::connect(this, SIGNAL(statusChanged(VoiceCallStatus)), SLOT(onStatusChanged())); + + QObject::connect(d->channel->becomeReady(), + SIGNAL(finished(Tp::PendingOperation*)), + SLOT(onCallChannelChannelReady(Tp::PendingOperation*))); + + QObject::connect(d->channel.data(), + SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)), + SLOT(onCallChannelChannelInvalidated(Tp::DBusProxy*,QString,QString))); + + emit this->startedAtChanged(startedAt()); +} + +CallChannelHandler::~CallChannelHandler() +{ + TRACE + delete this->d_ptr; +} + +AbstractVoiceCallProvider* CallChannelHandler::provider() const +{ + TRACE + Q_D(const CallChannelHandler); + return d->provider; +} + +QString CallChannelHandler::handlerId() const +{ + TRACE + Q_D(const CallChannelHandler); + return d->handlerId; +} + +QString CallChannelHandler::lineId() const +{ + TRACE + Q_D(const CallChannelHandler); + if(!d->channel->isReady()) return QString::null; + return d->channel->targetId(); +} + +QDateTime CallChannelHandler::startedAt() const +{ + TRACE + Q_D(const CallChannelHandler); + return d->startedAt; +} + +int CallChannelHandler::duration() const +{ + TRACE + Q_D(const CallChannelHandler); + return int(qRound(d->duration/1000.0)); +} + +bool CallChannelHandler::isIncoming() const +{ + TRACE + Q_D(const CallChannelHandler); + return d->isIncoming; +} + +bool CallChannelHandler::isMultiparty() const +{ + TRACE + Q_D(const CallChannelHandler); + if(!d->channel->isReady()) return false; + return d->channel->isConference(); +} + +bool CallChannelHandler::isEmergency() const +{ + TRACE + Q_D(const CallChannelHandler); + if(!d->channel->isReady()) return false; + return d->isEmergency; +} + +bool CallChannelHandler::isForwarded() const +{ + TRACE + Q_D(const CallChannelHandler); + if(!d->channel->isReady()) return false; + return d->isForwarded; +} + +AbstractVoiceCallHandler::VoiceCallStatus CallChannelHandler::status() const +{ + TRACE + Q_D(const CallChannelHandler); + return d->status; +} + +void CallChannelHandler::answer() +{ + TRACE + Q_D(CallChannelHandler); + + QObject::connect(d->channel.data()->accept(), + SIGNAL(finished(Tp::PendingOperation*)), + SLOT(onCallChannelAcceptCallFinished(Tp::PendingOperation*))); + + setStatus(STATUS_ACTIVE); +} + +void CallChannelHandler::hangup() +{ + TRACE + Q_D(CallChannelHandler); + + QObject::connect(d->channel.data()->hangup(), + SIGNAL(finished(Tp::PendingOperation*)), + SLOT(onCallChannelHangupCallFinished(Tp::PendingOperation*))); +} + +void CallChannelHandler::hold(bool on) +{ + TRACE + Q_D(CallChannelHandler); + Tp::Client::ChannelInterfaceHoldInterface *holdIface = new Tp::Client::ChannelInterfaceHoldInterface(d->channel.data(), this); + holdIface->RequestHold(on); +} + +//FIXME: Don't know what telepathy API provides this. +void CallChannelHandler::deflect(const QString &target) +{ + TRACE + Q_UNUSED(target) + emit this->error("NOT IMPLEMENTED YET!"); +} + +void CallChannelHandler::sendDtmf(const QString &tones) +{ + TRACE + Q_D(CallChannelHandler); + Tp::Client::ChannelInterfaceDTMFInterface *dtmfIface = new Tp::Client::ChannelInterfaceDTMFInterface(d->channel.data(), this); + + bool ok = true; + unsigned int toneId = tones.toInt(&ok); + + if(!ok) + { + if (tones == "*") toneId = 10; + else if(tones == "#") toneId = 11; + else if(tones == "A") toneId = 12; + else if(tones == "B") toneId = 13; + else if(tones == "C") toneId = 14; + else if(tones == "D") toneId = 15; + else return; + } + + dtmfIface->StartTone(1, toneId, 0); +} + +void CallChannelHandler::onCallChannelChannelReady(Tp::PendingOperation *op) +{ + TRACE + Q_D(CallChannelHandler); + 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("CallChannel Ready:"); + qDebug() << "\tType:" << d->channel->channelType(); + qDebug() << "\tInterfaces:" << d->channel->interfaces(); + + DEBUG_T(QString("\tTransport: %1").arg(d->channel->initialTransportType())); + DEBUG_T(QString("\tInitial Audio: %1").arg(d->channel->hasInitialAudio())); + DEBUG_T(QString("\tAudio Name: %1").arg(d->channel->initialAudioName())); + DEBUG_T(QString("\tInitial Video: %1").arg(d->channel->hasInitialVideo())); + DEBUG_T(QString("\tVideo Name: %1").arg(d->channel->initialVideoName())); + + QObject::connect(d->channel.data(), + SIGNAL(contentAdded(Tp::CallContentPtr)), + SLOT(onCallChannelCallContentAdded(Tp::CallContentPtr))); + QObject::connect(d->channel.data(), + SIGNAL(contentRemoved(Tp::CallContentPtr,Tp::CallStateReason)), + SLOT(onCallChannelCallContentRemoved(Tp::CallContentPtr,Tp::CallStateReason))); + QObject::connect(d->channel.data(), + SIGNAL(callStateChanged(Tp::CallState)), + SLOT(onCallChannelCallStateChanged(Tp::CallState))); + QObject::connect(d->channel.data(), + SIGNAL(localHoldStateChanged(Tp::LocalHoldState,Tp::LocalHoldStateReason)), + SLOT(onCallChannelCallLocalHoldStateChanged(Tp::LocalHoldState,Tp::LocalHoldStateReason))); + + if(d->channel->hasInitialAudio()) + { + DEBUG_T("Processing channel initial content."); + Tp::CallContentPtr audioContent = d->channel->contentByName(d->channel->initialAudioName()); + if(!audioContent || audioContent.isNull()) + { + DEBUG_T("Audio content unavailable."); + } + } + + if(d->channel->handlerStreamingRequired()) + { + DEBUG_T("Handler streaming is required, setting up farstream channels."); + QObject::connect(Tp::Farstream::createChannel(d->channel), + SIGNAL(finished(Tp::PendingOperation*)), + SLOT(onFarstreamCreateChannelFinished(Tp::PendingOperation*))); + } + + Tp::CallContents contents = d->channel->contents(); + DEBUG_T(QString("number of contents: %1").arg(contents.size())); + if (contents.size() > 0) { + foreach (const Tp::CallContentPtr &content, contents) { + Q_ASSERT(!content.isNull()); + DEBUG_T("Call Content"); + Tp::CallStreams streams = content->streams(); + foreach (const Tp::CallStreamPtr &stream, streams) { + DEBUG_T(QString(" Call stream: localSendingState=%1").arg(stream->localSendingState())); + DEBUG_T(QString(" members: %1").arg(stream.data()->remoteMembers().size())); + foreach(const Tp::ContactPtr contact, stream.data()->remoteMembers()) { + DEBUG_T(QString(" member %1").arg(contact->id()) + " remoteSendingState=" + stream->remoteSendingState(contact)); + } + //onStreamAdded(stream); + } + } + } + + d->channel->setRinging(); + + emit lineIdChanged(lineId()); + emit multipartyChanged(isMultiparty()); + emit emergencyChanged(isEmergency()); + emit forwardedChanged(isForwarded()); + + if(d->channel->isRequested()) + { + setStatus(STATUS_ALERTING); + } + else + { + setStatus(STATUS_INCOMING); + } + + d->isIncoming = !d->channel->isRequested(); +} + +void CallChannelHandler::onCallChannelChannelInvalidated(Tp::DBusProxy *, const QString &errorName, const QString &errorMessage) +{ + TRACE + Q_D(CallChannelHandler); + + 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(onCallChannelChannelInvalidated(Tp::DBusProxy*,QString,QString))); + + setStatus(STATUS_NULL); + emit this->invalidated(errorName, errorMessage); +} + +void CallChannelHandler::onCallChannelCallStateChanged(Tp::CallState state) +{ + TRACE + + switch(state) + { + case Tp::CallStateUnknown: + setStatus(STATUS_NULL); + break; + + case Tp::CallStatePendingInitiator: + setStatus(STATUS_DIALING); + break; + + case Tp::CallStateInitialising: + setStatus(STATUS_DIALING); + break; + + case Tp::CallStateInitialised: + setStatus(STATUS_ALERTING); + break; + + case Tp::CallStateAccepted: + setStatus(STATUS_ALERTING); + break; + + case Tp::CallStateActive: + setStatus(STATUS_ACTIVE); + break; + + case Tp::CallStateEnded: + setStatus(STATUS_DISCONNECTED); + this->invalidated(QString::null, QString::null); + break; + + default: + break; + } +} + +void CallChannelHandler::onCallChannelCallContentAdded(Tp::CallContentPtr content) +{ + TRACE + Q_UNUSED(content) +} + +void CallChannelHandler::onCallChannelCallContentRemoved(Tp::CallContentPtr content, Tp::CallStateReason reason) +{ + TRACE + Q_UNUSED(content) + Q_UNUSED(reason) +} + +void CallChannelHandler::onCallChannelAcceptCallFinished(Tp::PendingOperation *op) +{ + TRACE + 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())); + emit this->invalidated(op->errorName(), op->errorMessage()); + return; + } + + setStatus(STATUS_ACTIVE); +} + +void CallChannelHandler::onCallChannelHangupCallFinished(Tp::PendingOperation *op) +{ + TRACE + 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())); + emit this->invalidated(op->errorName(), op->errorMessage()); + return; + } + + setStatus(STATUS_DISCONNECTED); +} + +void CallChannelHandler::onFarstreamCreateChannelFinished(Tp::PendingOperation *op) +{ + TRACE + Q_D(CallChannelHandler); + + 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())); + this->hangup(); + return; + } + + Tp::Farstream::PendingChannel *pendingChannel = static_cast(op); + if(!pendingChannel) + { + WARNING_T("Failed to cast pending channel."); + this->hangup(); + return; + } + + d->fsChannel = new FarstreamChannel(pendingChannel->tfChannel(), this); + d->fsChannel->init(); +} + +void CallChannelHandler::timerEvent(QTimerEvent *event) +{ + TRACE + Q_D(CallChannelHandler); + + if(isOngoing() && event->timerId() == d->durationTimerId) + { + d->duration = get_tick() - d->connectedAt; + emit this->durationChanged(duration()); + } +} + +void CallChannelHandler::onStatusChanged() +{ + TRACE + Q_D(CallChannelHandler); + + if(isOngoing()) + { + if (d->durationTimerId == -1) { + d->durationTimerId = this->startTimer(1000); + d->elapsedTimer.start(); + d->connectedAt = get_tick(); + } + } + else if (d->durationTimerId != -1) + { + this->killTimer(d->durationTimerId); + d->durationTimerId = -1; + } +} + +void CallChannelHandler::setStatus(VoiceCallStatus newStatus) +{ + TRACE + Q_D(CallChannelHandler); + if (newStatus == d->status) + return; + + d->status = newStatus; + emit statusChanged(d->status); +} diff --git a/plugins/providers/telepathy/src/callchannelhandler.h b/plugins/providers/telepathy/src/callchannelhandler.h new file mode 100644 index 0000000..4b63ac4 --- /dev/null +++ b/plugins/providers/telepathy/src/callchannelhandler.h @@ -0,0 +1,100 @@ +/* + * This file is a part of the Voice Call Manager project + * + * Copyright (C) 2011-2015 Tom Swindell + * + * 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 CALLCHANNELHANDLER_H +#define CALLCHANNELHANDLER_H + +#include + +#include +#include + +class TelepathyProvider; + +class CallChannelHandler : public AbstractVoiceCallHandler +{ + Q_OBJECT + +public: + explicit CallChannelHandler(const QString &id, Tp::CallChannelPtr channel, const QDateTime &userActionTime, TelepathyProvider *provider = 0); + ~CallChannelHandler(); + + /*** AbstractVoiceCallHandler Implementation ***/ + AbstractVoiceCallProvider* provider() const; + QString handlerId() const; + QString lineId() const; + QDateTime startedAt() const; + int duration() const; + bool isIncoming() const; + bool isMultiparty() const; + bool isEmergency() const; + bool isForwarded() const; + + VoiceCallStatus status() const; + + /*** CallChannelHandler Implementation ***/ + Tp::CallChannel channel() const; + +Q_SIGNALS: + /*** CallChannelHandler Implementation ***/ + void error(const QString &errorMessage); + void invalidated(const QString &errorName, const QString &errorMessage); + +public Q_SLOTS: + /*** AbstractVoiceCallHandler Implementation ***/ + void answer(); + void hangup(); + void hold(bool on); + void deflect(const QString &target); + + void sendDtmf(const QString &tones); + +protected Q_SLOTS: + void onStatusChanged(); + + // CallChannel Interface Handling + void onCallChannelChannelReady(Tp::PendingOperation *op); + void onCallChannelChannelInvalidated(Tp::DBusProxy*,const QString &errorName, const QString &errorMessage); + + void onCallChannelCallStateChanged(Tp::CallState state); + + void onCallChannelCallContentAdded(Tp::CallContentPtr content); + void onCallChannelCallContentRemoved(Tp::CallContentPtr content, Tp::CallStateReason reason); + void onCallChannelCallLocalHoldStateChanged(Tp::LocalHoldState state,Tp::LocalHoldStateReason reason); + + void onCallChannelAcceptCallFinished(Tp::PendingOperation *op); + void onCallChannelHangupCallFinished(Tp::PendingOperation *op); + + // Telepathy Farstream Interface Handling + void onFarstreamCreateChannelFinished(Tp::PendingOperation *op); + +protected: + void timerEvent(QTimerEvent *event); + +private: + void setStatus(VoiceCallStatus newStatus); + + class CallChannelHandlerPrivate *d_ptr; + + Q_DISABLE_COPY(CallChannelHandler) + Q_DECLARE_PRIVATE(CallChannelHandler) +}; + +#endif // CALLCHANNELHANDLER_H diff --git a/plugins/providers/telepathy/src/src.pro b/plugins/providers/telepathy/src/src.pro index 92838f9..f646164 100644 --- a/plugins/providers/telepathy/src/src.pro +++ b/plugins/providers/telepathy/src/src.pro @@ -8,13 +8,15 @@ PKGCONFIG += TelepathyQt5 TelepathyQt5Farstream HEADERS += \ telepathyproviderplugin.h \ telepathyprovider.h \ - telepathyhandler.h \ - farstreamchannel.h + farstreamchannel.h \ + callchannelhandler.h \ + streamchannelhandler.h SOURCES += \ telepathyproviderplugin.cpp \ telepathyprovider.cpp \ - telepathyhandler.cpp \ - farstreamchannel.cpp + farstreamchannel.cpp \ + callchannelhandler.cpp \ + streamchannelhandler.cpp DEFINES += PLUGIN_NAME=\\\"voicecall-telepathy-plugin\\\" diff --git a/plugins/providers/telepathy/src/streamchannelhandler.cpp b/plugins/providers/telepathy/src/streamchannelhandler.cpp new file mode 100644 index 0000000..e8fbd5f --- /dev/null +++ b/plugins/providers/telepathy/src/streamchannelhandler.cpp @@ -0,0 +1,571 @@ +/* + * This file is a part of the Voice Call Manager project + * + * Copyright (C) 2011-2015 Tom Swindell + * + * 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. + * + */ +#include "common.h" +#include "streamchannelhandler.h" + +#include "telepathyprovider.h" + +#include + +#include +#include + +#include + +#include +#include + +static quint64 get_tick() +{ +#if defined(CLOCK_BOOTTIME) + int id = CLOCK_BOOTTIME; +#else + int id = CLOCK_MONOTONIC; +#endif + + quint64 res = 0; + + struct timespec ts; + + if(clock_gettime(id, &ts) == 0) { + res = ts.tv_sec; + res *= 1000; + res += ts.tv_nsec / 1000000; + } + + return res; +} + +class StreamChannelHandlerPrivate +{ + Q_DECLARE_PUBLIC(StreamChannelHandler) + +public: + StreamChannelHandlerPrivate(StreamChannelHandler *q, const QString &id, Tp::StreamedMediaChannelPtr c, const QDateTime &s, TelepathyProvider *p) + : q_ptr(q), handlerId(id), provider(p), startedAt(s), status(AbstractVoiceCallHandler::STATUS_NULL), + channel(c), servicePointInterface(NULL), duration(0), durationTimerId(-1), isEmergency(false), + isForwarded(false), isIncoming(false) + { /* ... */ } + + void listenToEmergencyStatus() + { + TRACE + if (channel && channel->isReady() && !servicePointInterface) { + servicePointInterface = channel->optionalInterface(); + if (servicePointInterface) { + // listen to changes in emergency call state, dictated by service point type + q_ptr->connect(servicePointInterface, SIGNAL(ServicePointChanged(const Tp::ServicePoint &)), + q_ptr, SLOT(updateEmergencyStatus(const Tp::ServicePoint &))); + + // fetch initial emergency call status + QString initialServicePointProperty = TP_QT_IFACE_CHANNEL_INTERFACE_SERVICE_POINT+QLatin1String(".InitialServicePoint"); + QVariant servicePointProperty = channel->immutableProperties().value(initialServicePointProperty); + if (servicePointProperty.isValid()) { + const Tp::ServicePoint servicePoint = qdbus_cast(servicePointProperty); + q_ptr->updateEmergencyStatus(servicePoint); + } else { + const Tp::ServicePoint servicePoint = servicePointInterface->property("CurrentServicePoint").value(); + q_ptr->updateEmergencyStatus(servicePoint); + } + } + } + } + + StreamChannelHandler *q_ptr; + + QString handlerId; + TelepathyProvider *provider; + + QDateTime startedAt; + + AbstractVoiceCallHandler::VoiceCallStatus status; + + Tp::StreamedMediaChannelPtr channel; + Tp::Client::ChannelInterfaceServicePointInterface *servicePointInterface; + + quint64 duration; + quint64 connectedAt; + int durationTimerId; + QElapsedTimer elapsedTimer; + bool isEmergency; + bool isForwarded; + bool isIncoming; +}; + +StreamChannelHandler::StreamChannelHandler(const QString &id, Tp::StreamedMediaChannelPtr channel, const QDateTime &userActionTime, TelepathyProvider *provider) + : AbstractVoiceCallHandler(provider), d_ptr(new StreamChannelHandlerPrivate(this, id, channel, userActionTime, provider)) +{ + TRACE + Q_D(StreamChannelHandler); + + QObject::connect(this, SIGNAL(statusChanged(VoiceCallStatus)), SLOT(onStatusChanged())); + + QObject::connect(d->channel->becomeReady(), + SIGNAL(finished(Tp::PendingOperation*)), + SLOT(onStreamedMediaChannelReady(Tp::PendingOperation*))); + + QObject::connect(d->channel.data(), + SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)), + SLOT(onStreamedMediaChannelInvalidated(Tp::DBusProxy*,QString,QString))); + + d->listenToEmergencyStatus(); + emit this->startedAtChanged(startedAt()); +} + +StreamChannelHandler::~StreamChannelHandler() +{ + TRACE + delete this->d_ptr; +} + +AbstractVoiceCallProvider* StreamChannelHandler::provider() const +{ + TRACE + Q_D(const StreamChannelHandler); + return d->provider; +} + +QString StreamChannelHandler::handlerId() const +{ + TRACE + Q_D(const StreamChannelHandler); + return d->handlerId; +} + +QString StreamChannelHandler::lineId() const +{ + TRACE + Q_D(const StreamChannelHandler); + if(!d->channel->isReady()) return QString::null; + return d->channel->targetId(); +} + +QDateTime StreamChannelHandler::startedAt() const +{ + TRACE + Q_D(const StreamChannelHandler); + return d->startedAt; +} + +int StreamChannelHandler::duration() const +{ + TRACE + Q_D(const StreamChannelHandler); + return int(qRound(d->duration/1000.0)); +} + +bool StreamChannelHandler::isIncoming() const +{ + TRACE + Q_D(const StreamChannelHandler); + return d->isIncoming; +} + +bool StreamChannelHandler::isMultiparty() const +{ + TRACE + Q_D(const StreamChannelHandler); + if(!d->channel->isReady()) return false; + return d->channel->isConference(); +} + +bool StreamChannelHandler::isEmergency() const +{ + TRACE + Q_D(const StreamChannelHandler); + if(!d->channel->isReady()) return false; + return d->isEmergency; +} + +bool StreamChannelHandler::isForwarded() const +{ + TRACE + Q_D(const StreamChannelHandler); + if(!d->channel->isReady()) return false; + return d->isForwarded; +} + +AbstractVoiceCallHandler::VoiceCallStatus StreamChannelHandler::status() const +{ + TRACE + Q_D(const StreamChannelHandler); + return d->status; +} + +void StreamChannelHandler::answer() +{ + TRACE + Q_D(StreamChannelHandler); + + QObject::connect(d->channel.data()->acceptCall(), + SIGNAL(finished(Tp::PendingOperation*)), + SLOT(onStreamedMediaChannelAcceptCallFinished(Tp::PendingOperation*))); + + setStatus(STATUS_ACTIVE); +} + +void StreamChannelHandler::hangup() +{ + TRACE + Q_D(StreamChannelHandler); + + QObject::connect(d->channel.data()->hangupCall(), + SIGNAL(finished(Tp::PendingOperation*)), + SLOT(onStreamedMediaChannelHangupCallFinished(Tp::PendingOperation*))); +} + +void StreamChannelHandler::hold(bool on) +{ + TRACE + Q_D(StreamChannelHandler); + Tp::Client::ChannelInterfaceHoldInterface *holdIface = new Tp::Client::ChannelInterfaceHoldInterface(d->channel.data(), this); + holdIface->RequestHold(on); +} + +//FIXME: Don't know what telepathy API provides this. +void StreamChannelHandler::deflect(const QString &target) +{ + TRACE + Q_UNUSED(target) + emit this->error("NOT IMPLEMENTED YET!"); +} + +void StreamChannelHandler::sendDtmf(const QString &tones) +{ + TRACE + Q_D(StreamChannelHandler); + Tp::Client::ChannelInterfaceDTMFInterface *dtmfIface = new Tp::Client::ChannelInterfaceDTMFInterface(d->channel.data(), this); + + bool ok = true; + unsigned int toneId = tones.toInt(&ok); + + if(!ok) + { + if (tones == "*") toneId = 10; + else if(tones == "#") toneId = 11; + else if(tones == "A") toneId = 12; + else if(tones == "B") toneId = 13; + else if(tones == "C") toneId = 14; + else if(tones == "D") toneId = 15; + else return; + } + + dtmfIface->StartTone(1, toneId, 0); + //dtmfIface->MultipleTones(tones); +} + +void StreamChannelHandler::updateEmergencyStatus(const Tp::ServicePoint& servicePoint) +{ + TRACE + Q_D(StreamChannelHandler); + bool isEmergency = (servicePoint.servicePointType == Tp::ServicePointTypeEmergency); + + if (d->isEmergency != isEmergency) { + d->isEmergency = isEmergency; + emit emergencyChanged(d->isEmergency); + } +} + +void StreamChannelHandler::onStreamedMediaChannelReady(Tp::PendingOperation *op) +{ + TRACE + Q_D(StreamChannelHandler); + 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("StreamedMediaChannel Ready:"); + qDebug() << "\tType:" << d->channel->channelType(); + qDebug() << "\tInterfaces:" << d->channel->interfaces(); + + QObject::connect(d->channel.data(), + SIGNAL(streamAdded(Tp::StreamedMediaStreamPtr)), + SLOT(onStreamedMediaChannelStreamAdded(Tp::StreamedMediaStreamPtr))); + + QObject::connect(d->channel.data(), + SIGNAL(streamRemoved(Tp::StreamedMediaStreamPtr)), + SLOT(onStreamedMediaChannelStreamRemoved(Tp::StreamedMediaStreamPtr))); + + QObject::connect(d->channel.data(), + SIGNAL(streamError(Tp::StreamedMediaStreamPtr,Tp::MediaStreamError,QString)), + SLOT(onStreamedMediaChannelStreamError(Tp::StreamedMediaStreamPtr,Tp::MediaStreamError,QString))); + + QObject::connect(d->channel.data(), + SIGNAL(streamStateChanged(Tp::StreamedMediaStreamPtr,Tp::MediaStreamState)), + SLOT(onStreamedMediaChannelStreamStateChanged(Tp::StreamedMediaStreamPtr,Tp::MediaStreamState))); + + if(d->channel->hasInterface(TP_QT_IFACE_CHANNEL_INTERFACE_CALL_STATE)) + { + DEBUG_T("Creating CallState interface"); + Tp::Client::ChannelInterfaceCallStateInterface *csIface = new Tp::Client::ChannelInterfaceCallStateInterface(d->channel.data(), this); + QDBusPendingReply reply = csIface->GetCallStates(); + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this); + QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), + SLOT(onStreamedMediaChannelCallGetCallStatesFinished(QDBusPendingCallWatcher*))); + QObject::connect(csIface, + SIGNAL(CallStateChanged(uint,uint)), + SLOT(onStreamedMediaChannelCallStateChanged(uint,uint))); + } + + if(d->channel->hasInterface(TP_QT_IFACE_CHANNEL_INTERFACE_GROUP)) + { + DEBUG_T("Creating Group interface"); + Tp::Client::ChannelInterfaceGroupInterface *groupIface = new Tp::Client::ChannelInterfaceGroupInterface(d->channel.data(), this); + QObject::connect(groupIface, SIGNAL(MembersChanged(QString,Tp::UIntList,Tp::UIntList,Tp::UIntList,Tp::UIntList,uint,uint)), + SLOT(onStreamedMediaChannelGroupMembersChanged(QString,Tp::UIntList,Tp::UIntList,Tp::UIntList,Tp::UIntList,uint,uint))); + } + + if(d->channel->hasInterface(TP_QT_IFACE_CHANNEL_INTERFACE_HOLD)) + { + DEBUG_T("Creating Hold interface"); + Tp::Client::ChannelInterfaceHoldInterface *holdIface = new Tp::Client::ChannelInterfaceHoldInterface(d->channel.data(), this); + QObject::connect(holdIface, + SIGNAL(HoldStateChanged(uint,uint)), + SLOT(onStreamedMediaChannelHoldStateChanged(uint,uint))); + } + d->listenToEmergencyStatus(); + + emit lineIdChanged(lineId()); + emit multipartyChanged(isMultiparty()); + emit emergencyChanged(isEmergency()); + emit forwardedChanged(isForwarded()); + + if(d->channel->isRequested()) + { + setStatus(STATUS_DIALING); + } + else + { + setStatus(STATUS_INCOMING); + } + + d->isIncoming = !d->channel->isRequested(); +} + +void StreamChannelHandler::onStreamedMediaChannelInvalidated(Tp::DBusProxy *, const QString &errorName, const QString &errorMessage) +{ + TRACE + Q_D(StreamChannelHandler); + 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(onStreamedMediaChannelInvalidated(Tp::DBusProxy*,QString,QString))); + + setStatus(STATUS_NULL); + emit this->invalidated(errorName, errorMessage); +} + +void StreamChannelHandler::onStreamedMediaChannelStreamAdded(const Tp::StreamedMediaStreamPtr &stream) +{ + TRACE + Q_UNUSED(stream) +} + +void StreamChannelHandler::onStreamedMediaChannelStreamRemoved(const Tp::StreamedMediaStreamPtr &stream) +{ + TRACE + Q_UNUSED(stream) +} + +void StreamChannelHandler::onStreamedMediaChannelStreamError(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 StreamChannelHandler::onStreamedMediaChannelStreamStateChanged(const Tp::StreamedMediaStreamPtr &stream, Tp::MediaStreamState state) +{ + TRACE + Q_UNUSED(stream) + + switch(state) + { + case Tp::MediaStreamStateDisconnected: + DEBUG_T("Media stream state disconnected."); + setStatus(STATUS_DISCONNECTED); + break; + + case Tp::MediaStreamStateConnecting: + DEBUG_T("Media stream state connecting."); + break; + + case Tp::MediaStreamStateConnected: + DEBUG_T("Media stream state connected."); + setStatus(STATUS_ALERTING); + break; + + default: + break; + } +} + +void StreamChannelHandler::onStreamedMediaChannelAcceptCallFinished(Tp::PendingOperation *op) +{ + TRACE + 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())); + this->hangup(); + return; + } + + setStatus(STATUS_ACTIVE); +} + +void StreamChannelHandler::onStreamedMediaChannelHangupCallFinished(Tp::PendingOperation *op) +{ + TRACE + 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())); + this->hangup(); + return; + } + + setStatus(STATUS_DISCONNECTED); +} + +void StreamChannelHandler::onStreamedMediaChannelCallStateChanged(uint, uint state) +{ + TRACE + Q_D(StreamChannelHandler); + bool forwarded = state & Tp::ChannelCallStateForwarded; + if (forwarded != d->isForwarded) { + d->isForwarded = forwarded; + DEBUG_T(QString("Call forwarded: ") + (forwarded ? "true" : "false")); + emit forwardedChanged(d->isForwarded); + } +} + +void StreamChannelHandler::onStreamedMediaChannelCallGetCallStatesFinished(QDBusPendingCallWatcher *call) +{ + TRACE + QDBusPendingReply reply = *call; + if (!reply.isError()) { + QMap states = reply.value(); + for (QMap::Iterator it = states.begin(); it != states.end(); ++it) { + onStreamedMediaChannelCallStateChanged(it.key(), it.value()); + } + } + call->deleteLater(); +} + +void StreamChannelHandler::onStreamedMediaChannelGroupMembersChanged(QString message, Tp::UIntList added, Tp::UIntList removed, Tp::UIntList localPending, Tp::UIntList remotePending, uint actor, uint reason) +{ + Q_UNUSED(message) + Q_UNUSED(added) + Q_UNUSED(removed) + Q_UNUSED(localPending) + Q_UNUSED(remotePending) + Q_UNUSED(actor) + Q_UNUSED(reason) + TRACE + Q_D(StreamChannelHandler); + + Tp::Client::ChannelInterfaceGroupInterface *groupIface = new Tp::Client::ChannelInterfaceGroupInterface(d->channel.data(), this); + + QDBusPendingReply reply = groupIface->GetMembers(); + reply.waitForFinished(); + + if(reply.isValid()) + { + if(reply.value().count() == 0) + { + setStatus(STATUS_DISCONNECTED); + } + else + { + setStatus(STATUS_ACTIVE); + } + } +} + +void StreamChannelHandler::onStreamedMediaChannelHoldStateChanged(uint state, uint reason) +{ + TRACE + Q_UNUSED(reason) + + switch(state) + { + case Tp::LocalHoldStateUnheld: + DEBUG_T("Hold state unheld"); + setStatus(STATUS_ACTIVE); + break; + case Tp::LocalHoldStateHeld: + DEBUG_T("Hold state held"); + setStatus(STATUS_HELD); + break; + } +} + +void StreamChannelHandler::timerEvent(QTimerEvent *event) +{ + TRACE + Q_D(StreamChannelHandler); + + if(isOngoing() && event->timerId() == d->durationTimerId) + { + d->duration = get_tick() - d->connectedAt; + emit this->durationChanged(duration()); + } +} + +void StreamChannelHandler::onStatusChanged() +{ + TRACE + Q_D(StreamChannelHandler); + + if(isOngoing()) + { + if (d->durationTimerId == -1) { + d->durationTimerId = this->startTimer(1000); + d->elapsedTimer.start(); + d->connectedAt = get_tick(); + } + } + else if (d->durationTimerId != -1) + { + this->killTimer(d->durationTimerId); + d->durationTimerId = -1; + } +} + +void StreamChannelHandler::setStatus(VoiceCallStatus newStatus) +{ + TRACE + Q_D(StreamChannelHandler); + if (newStatus == d->status) + return; + + d->status = newStatus; + emit statusChanged(d->status); +} diff --git a/plugins/providers/telepathy/src/telepathyhandler.h b/plugins/providers/telepathy/src/streamchannelhandler.h similarity index 71% rename from plugins/providers/telepathy/src/telepathyhandler.h rename to plugins/providers/telepathy/src/streamchannelhandler.h index 3d7ec8e..2b6dd4b 100644 --- a/plugins/providers/telepathy/src/telepathyhandler.h +++ b/plugins/providers/telepathy/src/streamchannelhandler.h @@ -18,23 +18,22 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * */ -#ifndef TELEPATHYHANDLER_H -#define TELEPATHYHANDLER_H +#ifndef STREAMCHANNELHANDLER_H +#define STREAMCHANNELHANDLER_H #include #include -#include class TelepathyProvider; -class TelepathyHandler : public AbstractVoiceCallHandler +class StreamChannelHandler : public AbstractVoiceCallHandler { Q_OBJECT public: - explicit TelepathyHandler(const QString &id, Tp::ChannelPtr channel, const QDateTime &userActionTime, TelepathyProvider *provider = 0); - ~TelepathyHandler(); + explicit StreamChannelHandler(const QString &id, Tp::StreamedMediaChannelPtr channel, const QDateTime &userActionTime, TelepathyProvider *provider = 0); + ~StreamChannelHandler(); /*** AbstractVoiceCallHandler Implementation ***/ AbstractVoiceCallProvider* provider() const; @@ -49,11 +48,11 @@ class TelepathyHandler : public AbstractVoiceCallHandler VoiceCallStatus status() const; - /*** TelepathyHandler Implementation ***/ + /*** StreamedMediaChannelHandler Implementation ***/ Tp::Channel channel() const; Q_SIGNALS: - /*** TelepathyHandler Implementation ***/ + /*** StreamedMediaChannelHandler Implementation ***/ void error(const QString &errorMessage); void invalidated(const QString &errorName, const QString &errorMessage); @@ -93,22 +92,6 @@ protected Q_SLOTS: // StreamedMediaChannel Hold Interface Handling void onStreamedMediaChannelHoldStateChanged(uint state, uint reason); - // CallChannel Interface Handling - void onCallChannelChannelReady(Tp::PendingOperation *op); - void onCallChannelChannelInvalidated(Tp::DBusProxy*,const QString &errorName, const QString &errorMessage); - - void onCallChannelCallStateChanged(Tp::CallState state); - - void onCallChannelCallContentAdded(Tp::CallContentPtr content); - void onCallChannelCallContentRemoved(Tp::CallContentPtr content, Tp::CallStateReason reason); - void onCallChannelCallLocalHoldStateChanged(Tp::LocalHoldState state,Tp::LocalHoldStateReason reason); - - void onCallChannelAcceptCallFinished(Tp::PendingOperation *op); - void onCallChannelHangupCallFinished(Tp::PendingOperation *op); - - // Telepathy Farstream Interface Handling - void onFarstreamCreateChannelFinished(Tp::PendingOperation *op); - void updateEmergencyStatus(const Tp::ServicePoint& servicePoint); protected: @@ -117,10 +100,10 @@ protected Q_SLOTS: private: void setStatus(VoiceCallStatus newStatus); - class TelepathyHandlerPrivate *d_ptr; + class StreamChannelHandlerPrivate *d_ptr; - Q_DISABLE_COPY(TelepathyHandler) - Q_DECLARE_PRIVATE(TelepathyHandler) + Q_DISABLE_COPY(StreamChannelHandler) + Q_DECLARE_PRIVATE(StreamChannelHandler) }; -#endif // TELEPATHYHANDLER_H +#endif // STREAMCHANNELHANDLER_H diff --git a/plugins/providers/telepathy/src/telepathyhandler.cpp b/plugins/providers/telepathy/src/telepathyhandler.cpp deleted file mode 100644 index 3c33a75..0000000 --- a/plugins/providers/telepathy/src/telepathyhandler.cpp +++ /dev/null @@ -1,854 +0,0 @@ -/* - * This file is a part of the Voice Call Manager project - * - * Copyright (C) 2011-2012 Tom Swindell - * - * 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. - * - */ -#include "common.h" -#include "telepathyhandler.h" - -#include "farstreamchannel.h" -#include "telepathyprovider.h" - -#include -#include -#include - -#include - -#include -#include -#include - -#include -#include - -static quint64 get_tick() -{ -#if defined(CLOCK_BOOTTIME) - int id = CLOCK_BOOTTIME; -#else - int id = CLOCK_MONOTONIC; -#endif - - quint64 res = 0; - - struct timespec ts; - - if(clock_gettime(id, &ts) == 0) { - res = ts.tv_sec; - res *= 1000; - res += ts.tv_nsec / 1000000; - } - - return res; -} - -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::ChannelPtr c, const QDateTime &s, TelepathyProvider *p) - : q_ptr(q), handlerId(id), provider(p), startedAt(s), status(AbstractVoiceCallHandler::STATUS_NULL), - channel(c), fsChannel(NULL), servicePointInterface(NULL), duration(0), durationTimerId(-1), isEmergency(false), - isForwarded(false), isIncoming(false) - { /* ... */ } - - void listenToEmergencyStatus() - { - TRACE - if (channel && channel->isReady() && !servicePointInterface) { - servicePointInterface = channel->optionalInterface(); - if (servicePointInterface) { - // listen to changes in emergency call state, dictated by service point type - q_ptr->connect(servicePointInterface, SIGNAL(ServicePointChanged(const Tp::ServicePoint &)), - q_ptr, SLOT(updateEmergencyStatus(const Tp::ServicePoint &))); - - // fetch initial emergency call status - QString initialServicePointProperty = TP_QT_IFACE_CHANNEL_INTERFACE_SERVICE_POINT+QLatin1String(".InitialServicePoint"); - QVariant servicePointProperty = channel->immutableProperties().value(initialServicePointProperty); - if (servicePointProperty.isValid()) { - const Tp::ServicePoint servicePoint = qdbus_cast(servicePointProperty); - q_ptr->updateEmergencyStatus(servicePoint); - } else { - const Tp::ServicePoint servicePoint = servicePointInterface->property("CurrentServicePoint").value(); - q_ptr->updateEmergencyStatus(servicePoint); - } - } - } - } - - TelepathyHandler *q_ptr; - - QString handlerId; - TelepathyProvider *provider; - - QDateTime startedAt; - - AbstractVoiceCallHandler::VoiceCallStatus status; - - Tp::ChannelPtr channel; // CallChannel or StreamedMediaChannel - FarstreamChannel *fsChannel; - Tp::Client::ChannelInterfaceServicePointInterface *servicePointInterface; - - quint64 duration; - quint64 connectedAt; - int durationTimerId; - QElapsedTimer elapsedTimer; - bool isEmergency; - bool isForwarded; - bool isIncoming; -}; - -TelepathyHandler::TelepathyHandler(const QString &id, Tp::ChannelPtr channel, const QDateTime &userActionTime, TelepathyProvider *provider) - : AbstractVoiceCallHandler(provider), d_ptr(new TelepathyHandlerPrivate(this, id, channel, userActionTime, provider)) -{ - TRACE - Q_D(TelepathyHandler); - - QObject::connect(this, SIGNAL(statusChanged(VoiceCallStatus)), SLOT(onStatusChanged())); - - Tp::CallChannelPtr callChannel = Tp::CallChannelPtr::dynamicCast(channel); - if(callChannel && !callChannel.isNull()) - { - DEBUG_T("Found CallChannel interface."); - Tp::Features features; - features << Tp::CallChannel::FeatureCore; - features << Tp::CallChannel::FeatureContents; - - QObject::connect(d->channel->becomeReady(features), - SIGNAL(finished(Tp::PendingOperation*)), - SLOT(onCallChannelChannelReady(Tp::PendingOperation*))); - - QObject::connect(d->channel.data(), - SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)), - SLOT(onCallChannelChannelInvalidated(Tp::DBusProxy*,QString,QString))); - } - - //TODO: Remove when tp-ring is updated - Tp::StreamedMediaChannelPtr streamChannel = Tp::StreamedMediaChannelPtr::dynamicCast(channel); - if(streamChannel && !streamChannel.isNull()) - { - DEBUG_T("Found StreamedMediaChannel interface."); - Tp::Features features; - features << Tp::StreamedMediaChannel::FeatureCore; - features << Tp::StreamedMediaChannel::FeatureStreams; - - QObject::connect(d->channel->becomeReady(features), - SIGNAL(finished(Tp::PendingOperation*)), - SLOT(onStreamedMediaChannelReady(Tp::PendingOperation*))); - - QObject::connect(d->channel.data(), - SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)), - SLOT(onStreamedMediaChannelInvalidated(Tp::DBusProxy*,QString,QString))); - } - d->listenToEmergencyStatus(); - emit this->startedAtChanged(startedAt()); -} - -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 int(qRound(d->duration/1000.0)); -} - -bool TelepathyHandler::isIncoming() const -{ - TRACE - Q_D(const TelepathyHandler); - return d->isIncoming; -} - -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 d->isEmergency; -} - -bool TelepathyHandler::isForwarded() const -{ - TRACE - Q_D(const TelepathyHandler); - if(!d->channel->isReady()) return false; - return d->isForwarded; -} - -AbstractVoiceCallHandler::VoiceCallStatus TelepathyHandler::status() const -{ - TRACE - Q_D(const TelepathyHandler); - return d->status; -} - -void TelepathyHandler::answer() -{ - TRACE - Q_D(TelepathyHandler); - - Tp::CallChannelPtr callChannel = Tp::CallChannelPtr::dynamicCast(d->channel); - if(callChannel && !callChannel.isNull()) - { - DEBUG_T("Found CallChannel interface."); - QObject::connect(callChannel.data()->accept(), - SIGNAL(finished(Tp::PendingOperation*)), - SLOT(onCallChannelAcceptCallFinished(Tp::PendingOperation*))); - } - - Tp::StreamedMediaChannelPtr streamChannel = Tp::StreamedMediaChannelPtr::dynamicCast(d->channel); - if(streamChannel && !streamChannel.isNull()) - { - DEBUG_T("Found StreamedMediaChannel interface."); - QObject::connect(streamChannel.data()->acceptCall(), - SIGNAL(finished(Tp::PendingOperation*)), - SLOT(onStreamedMediaChannelAcceptCallFinished(Tp::PendingOperation*))); - } - - setStatus(STATUS_ACTIVE); -} - -void TelepathyHandler::hangup() -{ - TRACE - Q_D(TelepathyHandler); - - Tp::CallChannelPtr callChannel = Tp::CallChannelPtr::dynamicCast(d->channel); - if(callChannel && !callChannel.isNull()) - { - DEBUG_T("Found CallChannel interface."); - QObject::connect(callChannel.data()->hangup(), - SIGNAL(finished(Tp::PendingOperation*)), - SLOT(onCallChannelHangupCallFinished(Tp::PendingOperation*))); - } - - Tp::StreamedMediaChannelPtr streamChannel = Tp::StreamedMediaChannelPtr::dynamicCast(d->channel); - if(streamChannel && !streamChannel.isNull()) - { - DEBUG_T("Found StreamedMediaChannel interface."); - QObject::connect(streamChannel.data()->hangupCall(), - SIGNAL(finished(Tp::PendingOperation*)), - SLOT(onStreamedMediaChannelHangupCallFinished(Tp::PendingOperation*))); - } -} - -void TelepathyHandler::hold(bool on) -{ - TRACE - Q_D(TelepathyHandler); - Tp::Client::ChannelInterfaceHoldInterface *holdIface = new Tp::Client::ChannelInterfaceHoldInterface(d->channel.data(), this); - holdIface->RequestHold(on); -} - -//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::sendDtmf(const QString &tones) -{ - TRACE - Q_D(TelepathyHandler); - Tp::Client::ChannelInterfaceDTMFInterface *dtmfIface = new Tp::Client::ChannelInterfaceDTMFInterface(d->channel.data(), this); - - bool ok = true; - unsigned int toneId = tones.toInt(&ok); - - if(!ok) - { - if (tones == "*") toneId = 10; - else if(tones == "#") toneId = 11; - else if(tones == "A") toneId = 12; - else if(tones == "B") toneId = 13; - else if(tones == "C") toneId = 14; - else if(tones == "D") toneId = 15; - else return; - } - - dtmfIface->StartTone(1, toneId, 0); - //dtmfIface->MultipleTones(tones); -} - -void TelepathyHandler::onCallChannelChannelReady(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; - } - - Tp::CallChannelPtr callChannel = Tp::CallChannelPtr::dynamicCast(d->channel); - DEBUG_T("CallChannel Ready:"); - qDebug() << "\tType:" << d->channel->channelType(); - qDebug() << "\tInterfaces:" << d->channel->interfaces(); - - DEBUG_T(QString("\tTransport: %1").arg(callChannel->initialTransportType())); - DEBUG_T(QString("\tInitial Audio: %1").arg(callChannel->hasInitialAudio())); - DEBUG_T(QString("\tAudio Name: %1").arg(callChannel->initialAudioName())); - DEBUG_T(QString("\tInitial Video: %1").arg(callChannel->hasInitialVideo())); - DEBUG_T(QString("\tVideo Name: %1").arg(callChannel->initialVideoName())); - - QObject::connect(callChannel.data(), - SIGNAL(contentAdded(Tp::CallContentPtr)), - SLOT(onCallChannelCallContentAdded(Tp::CallContentPtr))); - QObject::connect(callChannel.data(), - SIGNAL(contentRemoved(Tp::CallContentPtr,Tp::CallStateReason)), - SLOT(onCallChannelCallContentRemoved(Tp::CallContentPtr,Tp::CallStateReason))); - QObject::connect(callChannel.data(), - SIGNAL(callStateChanged(Tp::CallState)), - SLOT(onCallChannelCallStateChanged(Tp::CallState))); - QObject::connect(callChannel.data(), - SIGNAL(localHoldStateChanged(Tp::LocalHoldState,Tp::LocalHoldStateReason)), - SLOT(onCallChannelCallLocalHoldStateChanged(Tp::LocalHoldState,Tp::LocalHoldStateReason))); - - if(callChannel->hasInitialAudio()) - { - DEBUG_T("Processing channel initial content."); - Tp::CallContentPtr audioContent = callChannel->contentByName(callChannel->initialAudioName()); - if(!audioContent || audioContent.isNull()) - { - DEBUG_T("Audio content unavailable."); - } - - } - - if(callChannel->handlerStreamingRequired()) - { - DEBUG_T("Handler streaming is required, setting up farstream channels."); - QObject::connect(Tp::Farstream::createChannel(callChannel), - SIGNAL(finished(Tp::PendingOperation*)), - SLOT(onFarstreamCreateChannelFinished(Tp::PendingOperation*))); - } - - Tp::CallContents contents = callChannel->contents(); - DEBUG_T(QString("number of contents: %1").arg(contents.size())); - if (contents.size() > 0) { - foreach (const Tp::CallContentPtr &content, contents) { - Q_ASSERT(!content.isNull()); - DEBUG_T("Call Content"); - Tp::CallStreams streams = content->streams(); - foreach (const Tp::CallStreamPtr &stream, streams) { - DEBUG_T(QString(" Call stream: localSendingState=%1").arg(stream->localSendingState())); - DEBUG_T(QString(" members: %1").arg(stream.data()->remoteMembers().size())); - foreach(const Tp::ContactPtr contact, stream.data()->remoteMembers()) { - DEBUG_T(QString(" member %1").arg(contact->id()) + " remoteSendingState=" + stream->remoteSendingState(contact)); - } - //onStreamAdded(stream); - } - } - } - - callChannel->setRinging(); - - d->listenToEmergencyStatus(); - - emit lineIdChanged(lineId()); - emit multipartyChanged(isMultiparty()); - emit emergencyChanged(isEmergency()); - emit forwardedChanged(isForwarded()); - - if(d->channel->isRequested()) - { - setStatus(STATUS_ALERTING); - } - else - { - setStatus(STATUS_INCOMING); - } - - d->isIncoming = !d->channel->isRequested(); -} - -void TelepathyHandler::onCallChannelChannelInvalidated(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(onCallChannelChannelInvalidated(Tp::DBusProxy*,QString,QString))); - - setStatus(STATUS_NULL); - emit this->invalidated(errorName, errorMessage); -} - -void TelepathyHandler::onCallChannelCallStateChanged(Tp::CallState state) -{ - TRACE - - switch(state) - { - case Tp::CallStateUnknown: - setStatus(STATUS_NULL); - break; - - case Tp::CallStatePendingInitiator: - setStatus(STATUS_DIALING); - break; - - case Tp::CallStateInitialising: - setStatus(STATUS_DIALING); - break; - - case Tp::CallStateInitialised: - setStatus(STATUS_ALERTING); - break; - - case Tp::CallStateAccepted: - setStatus(STATUS_ALERTING); - break; - - case Tp::CallStateActive: - setStatus(STATUS_ACTIVE); - break; - - case Tp::CallStateEnded: - setStatus(STATUS_DISCONNECTED); - break; - - default: - break; - } -} - -void TelepathyHandler::onCallChannelCallContentAdded(Tp::CallContentPtr content) -{ - TRACE - Q_UNUSED(content) -} - -void TelepathyHandler::onCallChannelCallContentRemoved(Tp::CallContentPtr content, Tp::CallStateReason reason) -{ - TRACE - Q_UNUSED(content) - Q_UNUSED(reason) -} - -void TelepathyHandler::onCallChannelAcceptCallFinished(Tp::PendingOperation *op) -{ - TRACE - 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())); - this->hangup(); - return; - } - - setStatus(STATUS_ACTIVE); -} - -void TelepathyHandler::onCallChannelHangupCallFinished(Tp::PendingOperation *op) -{ - TRACE - 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())); - this->hangup(); - return; - } - - setStatus(STATUS_DISCONNECTED); -} - -void TelepathyHandler::onFarstreamCreateChannelFinished(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())); - this->hangup(); - return; - } - - Tp::Farstream::PendingChannel *pendingChannel = static_cast(op); - if(!pendingChannel) - { - WARNING_T("Failed to cast pending channel."); - this->hangup(); - return; - } - - d->fsChannel = new FarstreamChannel(pendingChannel->tfChannel(), this); - d->fsChannel->init(); -} - -void TelepathyHandler::updateEmergencyStatus(const Tp::ServicePoint& servicePoint) -{ - TRACE - Q_D(TelepathyHandler); - bool isEmergency = (servicePoint.servicePointType == Tp::ServicePointTypeEmergency); - - if (d->isEmergency != isEmergency) { - d->isEmergency = isEmergency; - emit emergencyChanged(d->isEmergency); - } -} - -void TelepathyHandler::onStreamedMediaChannelReady(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; - } - - Tp::StreamedMediaChannelPtr streamChannel = Tp::StreamedMediaChannelPtr::dynamicCast(d->channel); - DEBUG_T("StreamedMediaChannel Ready:"); - qDebug() << "\tType:" << d->channel->channelType(); - qDebug() << "\tInterfaces:" << d->channel->interfaces(); - - if(streamChannel.data()->handlerStreamingRequired()) - { - WARNING_T("NOT IMPLEMENTED - Handler streaming is required."); - } - - QObject::connect(streamChannel.data(), - SIGNAL(streamAdded(Tp::StreamedMediaStreamPtr)), - SLOT(onStreamedMediaChannelStreamAdded(Tp::StreamedMediaStreamPtr))); - - QObject::connect(streamChannel.data(), - SIGNAL(streamRemoved(Tp::StreamedMediaStreamPtr)), - SLOT(onStreamedMediaChannelStreamRemoved(Tp::StreamedMediaStreamPtr))); - - QObject::connect(streamChannel.data(), - SIGNAL(streamError(Tp::StreamedMediaStreamPtr,Tp::MediaStreamError,QString)), - SLOT(onStreamedMediaChannelStreamError(Tp::StreamedMediaStreamPtr,Tp::MediaStreamError,QString))); - - QObject::connect(streamChannel.data(), - SIGNAL(streamStateChanged(Tp::StreamedMediaStreamPtr,Tp::MediaStreamState)), - SLOT(onStreamedMediaChannelStreamStateChanged(Tp::StreamedMediaStreamPtr,Tp::MediaStreamState))); - - if(d->channel->hasInterface(TP_QT_IFACE_CHANNEL_INTERFACE_CALL_STATE)) - { - DEBUG_T("Creating CallState interface"); - Tp::Client::ChannelInterfaceCallStateInterface *csIface = new Tp::Client::ChannelInterfaceCallStateInterface(d->channel.data(), this); - QDBusPendingReply reply = csIface->GetCallStates(); - QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this); - QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), - SLOT(onStreamedMediaChannelCallGetCallStatesFinished(QDBusPendingCallWatcher*))); - QObject::connect(csIface, - SIGNAL(CallStateChanged(uint,uint)), - SLOT(onStreamedMediaChannelCallStateChanged(uint,uint))); - } - - if(d->channel->hasInterface(TP_QT_IFACE_CHANNEL_INTERFACE_GROUP)) - { - DEBUG_T("Creating Group interface"); - Tp::Client::ChannelInterfaceGroupInterface *groupIface = new Tp::Client::ChannelInterfaceGroupInterface(d->channel.data(), this); - QObject::connect(groupIface, SIGNAL(MembersChanged(QString,Tp::UIntList,Tp::UIntList,Tp::UIntList,Tp::UIntList,uint,uint)), - SLOT(onStreamedMediaChannelGroupMembersChanged(QString,Tp::UIntList,Tp::UIntList,Tp::UIntList,Tp::UIntList,uint,uint))); - } - - if(d->channel->hasInterface(TP_QT_IFACE_CHANNEL_INTERFACE_HOLD)) - { - DEBUG_T("Creating Hold interface"); - Tp::Client::ChannelInterfaceHoldInterface *holdIface = new Tp::Client::ChannelInterfaceHoldInterface(d->channel.data(), this); - QObject::connect(holdIface, - SIGNAL(HoldStateChanged(uint,uint)), - SLOT(onStreamedMediaChannelHoldStateChanged(uint,uint))); - } - d->listenToEmergencyStatus(); - - emit lineIdChanged(lineId()); - emit multipartyChanged(isMultiparty()); - emit emergencyChanged(isEmergency()); - emit forwardedChanged(isForwarded()); - - if(d->channel->isRequested()) - { - setStatus(STATUS_DIALING); - } - else - { - setStatus(STATUS_INCOMING); - } - - d->isIncoming = !d->channel->isRequested(); -} - -void TelepathyHandler::onStreamedMediaChannelInvalidated(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(onStreamedMediaChannelInvalidated(Tp::DBusProxy*,QString,QString))); - - setStatus(STATUS_NULL); - emit this->invalidated(errorName, errorMessage); -} - -void TelepathyHandler::onStreamedMediaChannelStreamAdded(const Tp::StreamedMediaStreamPtr &stream) -{ - TRACE - Q_UNUSED(stream) -} - -void TelepathyHandler::onStreamedMediaChannelStreamRemoved(const Tp::StreamedMediaStreamPtr &stream) -{ - TRACE - Q_UNUSED(stream) -} - -void TelepathyHandler::onStreamedMediaChannelStreamError(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::onStreamedMediaChannelStreamStateChanged(const Tp::StreamedMediaStreamPtr &stream, Tp::MediaStreamState state) -{ - TRACE - Q_UNUSED(stream) - - switch(state) - { - case Tp::MediaStreamStateDisconnected: - DEBUG_T("Media stream state disconnected."); - setStatus(STATUS_DISCONNECTED); - break; - - case Tp::MediaStreamStateConnecting: - DEBUG_T("Media stream state connecting."); - break; - - case Tp::MediaStreamStateConnected: - DEBUG_T("Media stream state connected."); - setStatus(STATUS_ALERTING); - break; - - default: - break; - } -} - -void TelepathyHandler::onStreamedMediaChannelAcceptCallFinished(Tp::PendingOperation *op) -{ - TRACE - 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())); - this->hangup(); - return; - } - - setStatus(STATUS_ACTIVE); -} - -void TelepathyHandler::onStreamedMediaChannelHangupCallFinished(Tp::PendingOperation *op) -{ - TRACE - 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())); - this->hangup(); - return; - } - - setStatus(STATUS_DISCONNECTED); -} - -void TelepathyHandler::onStreamedMediaChannelCallStateChanged(uint, uint state) -{ - TRACE - Q_D(TelepathyHandler); - bool forwarded = state & Tp::ChannelCallStateForwarded; - if (forwarded != d->isForwarded) { - d->isForwarded = forwarded; - DEBUG_T(QString("Call forwarded: ") + (forwarded ? "true" : "false")); - emit forwardedChanged(d->isForwarded); - } -} - -void TelepathyHandler::onStreamedMediaChannelCallGetCallStatesFinished(QDBusPendingCallWatcher *call) -{ - TRACE - QDBusPendingReply reply = *call; - if (!reply.isError()) { - QMap states = reply.value(); - for (QMap::Iterator it = states.begin(); it != states.end(); ++it) { - onStreamedMediaChannelCallStateChanged(it.key(), it.value()); - } - } - call->deleteLater(); -} - -void TelepathyHandler::onStreamedMediaChannelGroupMembersChanged(QString message, Tp::UIntList added, Tp::UIntList removed, Tp::UIntList localPending, Tp::UIntList remotePending, uint actor, uint reason) -{ - Q_UNUSED(message) - Q_UNUSED(added) - Q_UNUSED(removed) - Q_UNUSED(localPending) - Q_UNUSED(remotePending) - Q_UNUSED(actor) - Q_UNUSED(reason) - TRACE - Q_D(TelepathyHandler); - - Tp::Client::ChannelInterfaceGroupInterface *groupIface = new Tp::Client::ChannelInterfaceGroupInterface(d->channel.data(), this); - - QDBusPendingReply reply = groupIface->GetMembers(); - reply.waitForFinished(); - - if(reply.isValid()) - { - if(reply.value().count() == 0) - { - setStatus(STATUS_DISCONNECTED); - } - else - { - setStatus(STATUS_ACTIVE); - } - } -} - -void TelepathyHandler::onStreamedMediaChannelHoldStateChanged(uint state, uint reason) -{ - TRACE - Q_UNUSED(reason) - - switch(state) - { - case Tp::LocalHoldStateUnheld: - DEBUG_T("Hold state unheld"); - setStatus(STATUS_ACTIVE); - break; - case Tp::LocalHoldStateHeld: - DEBUG_T("Hold state held"); - setStatus(STATUS_HELD); - break; - } -} - -void TelepathyHandler::timerEvent(QTimerEvent *event) -{ - TRACE - Q_D(TelepathyHandler); - - if(isOngoing() && event->timerId() == d->durationTimerId) - { - d->duration = get_tick() - d->connectedAt; - emit this->durationChanged(duration()); - } -} - -void TelepathyHandler::onStatusChanged() -{ - TRACE - Q_D(TelepathyHandler); - - if(isOngoing()) - { - if (d->durationTimerId == -1) { - d->durationTimerId = this->startTimer(1000); - d->elapsedTimer.start(); - d->connectedAt = get_tick(); - } - } - else if (d->durationTimerId != -1) - { - this->killTimer(d->durationTimerId); - d->durationTimerId = -1; - } -} - -void TelepathyHandler::setStatus(VoiceCallStatus newStatus) -{ - TRACE - Q_D(TelepathyHandler); - if (newStatus == d->status) - return; - - d->status = newStatus; - emit statusChanged(d->status); -} diff --git a/plugins/providers/telepathy/src/telepathyprovider.cpp b/plugins/providers/telepathy/src/telepathyprovider.cpp index dd099a6..408251f 100644 --- a/plugins/providers/telepathy/src/telepathyprovider.cpp +++ b/plugins/providers/telepathy/src/telepathyprovider.cpp @@ -1,7 +1,7 @@ /* * This file is a part of the Voice Call Manager project * - * Copyright (C) 2011-2012 Tom Swindell + * Copyright (C) 2011-2015 Tom Swindell * * 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 @@ -19,10 +19,13 @@ * */ #include "common.h" - -#include "telepathyhandler.h" #include "telepathyprovider.h" +#include "callchannelhandler.h" +#include "streamchannelhandler.h" + +#include +#include #include #include #include @@ -174,15 +177,30 @@ void TelepathyProvider::createHandler(Tp::ChannelPtr ch, const QDateTime &userAc { TRACE Q_D(TelepathyProvider); + AbstractVoiceCallHandler *handler = 0; + DEBUG_T(QString("\tProcessing channel: %1").arg(ch->objectPath())); - TelepathyHandler *handler = new TelepathyHandler(d->manager->generateHandlerId(), ch, userActionTime, this); + + Tp::CallChannelPtr callChannel = Tp::CallChannelPtr::dynamicCast(ch); + if(callChannel && !callChannel.isNull()) + { + DEBUG_T("Found CallChannel interface."); + handler = new CallChannelHandler(d->manager->generateHandlerId(), callChannel, userActionTime, this); + } + + Tp::StreamedMediaChannelPtr streamChannel = Tp::StreamedMediaChannelPtr::dynamicCast(ch); + if(streamChannel && !streamChannel.isNull()) + { + DEBUG_T("Found StreamedMediaChannel interface."); + handler = new StreamChannelHandler(d->manager->generateHandlerId(), streamChannel, userActionTime, this); + } + + if(!handler) return; + 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))); + QObject::connect(handler, SIGNAL(invalidated(QString,QString)), SLOT(onHandlerInvalidated(QString,QString))); emit this->voiceCallAdded(handler); emit this->voiceCallsChanged(); @@ -209,8 +227,6 @@ void TelepathyProvider::onPendingRequestFinished(Tp::PendingOperation *op) void TelepathyProvider::onChannelRequestCreated(const Tp::ChannelRequestPtr &request) { TRACE - Q_D(TelepathyProvider); - // There is no need to watch for success; the channel will be delivered to the handler. // pendingRequestFinished (emitted after the request succeeds) will clean up the rest. connect(request.data(), SIGNAL(failed(QString,QString)), @@ -234,7 +250,7 @@ void TelepathyProvider::onHandlerInvalidated(const QString &errorName, const QSt TRACE Q_D(TelepathyProvider); - TelepathyHandler *handler = qobject_cast(QObject::sender()); + AbstractVoiceCallHandler *handler = qobject_cast(QObject::sender()); d->voiceCalls.remove(handler->handlerId()); emit this->voiceCallRemoved(handler->handlerId()); diff --git a/plugins/providers/telepathy/src/telepathyproviderplugin.cpp b/plugins/providers/telepathy/src/telepathyproviderplugin.cpp index 35ce904..c0d481e 100644 --- a/plugins/providers/telepathy/src/telepathyproviderplugin.cpp +++ b/plugins/providers/telepathy/src/telepathyproviderplugin.cpp @@ -41,6 +41,8 @@ #endif #include +#include +#include #include #include @@ -119,7 +121,49 @@ bool TelepathyProviderPlugin::initialize() gst_init(&argc, &argv); d->am = Tp::AccountManager::create(); - d->tpClientRegistrar = Tp::ClientRegistrar::create(d->am); + + 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 + ); + channelFactory->addFeaturesForStreamedMediaCalls( + Tp::Features() + << Tp::StreamedMediaChannel::FeatureStreams + << Tp::StreamedMediaChannel::FeatureLocalHoldState + ); + + + Tp::ContactFactoryPtr contactFactory = Tp::ContactFactory::create( + Tp::Features() + << Tp::Contact::FeatureAlias + << Tp::Contact::FeatureAvatarData + ); + + d->tpClientRegistrar = Tp::ClientRegistrar::create(accountFactory, + connectionFactory, + channelFactory, + contactFactory); + d->tpClientHandler = Tp::AbstractClientPtr(this); if(!d->tpClientRegistrar->registerClient(d->tpClientHandler, "voicecall")) @@ -270,6 +314,9 @@ void TelepathyProviderPlugin::onNewAccount(Tp::AccountPtr account) void TelepathyProviderPlugin::onAccountInvalidated(Tp::DBusProxy *proxy, const QString &errorName, const QString &errorMessage) { TRACE + Q_UNUSED(errorName); + Q_UNUSED(errorMessage); + Tp::AccountPtr account = Tp::AccountPtr(qobject_cast(proxy)); QObject::disconnect(account.data(), SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)), this, SLOT(onAccountInvalidated(Tp::DBusProxy*,QString,QString)));