Merge lp:~boiko/telephony-service/voip_support into lp:telephony-service

Proposed by Gustavo Pichorim Boiko
Status: Rejected
Rejected by: Renato Araujo Oliveira Filho
Proposed branch: lp:~boiko/telephony-service/voip_support
Merge into: lp:telephony-service
Diff against target: 1266 lines (+855/-43)
18 files modified
CMakeLists.txt (+4/-2)
handler/CMakeLists.txt (+8/-0)
handler/TelephonyServiceHandler.client (+9/-0)
handler/callagent.cpp (+118/-0)
handler/callagent.h (+52/-0)
handler/callhandler.cpp (+164/-27)
handler/callhandler.h (+8/-1)
handler/farstreamchannel.cpp (+330/-0)
handler/farstreamchannel.h (+80/-0)
handler/handler.cpp (+23/-4)
handler/handler.h (+1/-0)
handler/main.cpp (+2/-0)
libtelephonyservice/accountentry.cpp (+17/-4)
libtelephonyservice/callentry.cpp (+15/-3)
libtelephonyservice/callentry.h (+1/-1)
libtelephonyservice/tonegenerator.cpp (+11/-0)
libtelephonyservice/tonegenerator.h (+5/-1)
protocols/sip.protocol (+7/-0)
To merge this branch: bzr merge lp:~boiko/telephony-service/voip_support
Reviewer Review Type Date Requested Status
Renato Araujo Oliveira Filho (community) Disapprove
Review via email: mp+312872@code.launchpad.net

Commit message

Add VOIP support to telephony-service.

Description of the change

Add VOIP support to telephony-service.

To post a comment you must log in.
967. By Gustavo Pichorim Boiko

Remove not needed dependencies

968. By Gustavo Pichorim Boiko

Fix DTMF, add more gstreamer debugging and add a protocol file for SIP.

969. By Gustavo Pichorim Boiko

Implement mute for CMs that don't use hardware streaming.

970. By Gustavo Pichorim Boiko

Play a tone when the call is ringing on the other end.

971. By Gustavo Pichorim Boiko

Play the correct tone when the call is ringing.

972. By Gustavo Pichorim Boiko

Play the dialing tone before the ringing one.

Revision history for this message
Renato Araujo Oliveira Filho (renatofilho) wrote :
review: Disapprove

Unmerged revisions

978. By Gustavo Pichorim Boiko

Expose the modem name.

977. By Gustavo Pichorim Boiko

Select VOIP accounts by default

976. By Gustavo Pichorim Boiko

When matching SIP contacts, extract the phone number from the SIP URI

975. By Gustavo Pichorim Boiko

stop the ringing tone when the call ends

974. By Gustavo Pichorim Boiko

Iterate over the phone accounts only to set the name

973. By Gustavo Pichorim Boiko

Merge staging

972. By Gustavo Pichorim Boiko

Play the dialing tone before the ringing one.

971. By Gustavo Pichorim Boiko

Play the correct tone when the call is ringing.

970. By Gustavo Pichorim Boiko

Play a tone when the call is ringing on the other end.

969. By Gustavo Pichorim Boiko

Implement mute for CMs that don't use hardware streaming.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2016-10-06 19:41:33 +0000
3+++ CMakeLists.txt 2016-12-17 13:33:18 +0000
4@@ -35,10 +35,8 @@
5
6 find_package(Qt5Contacts)
7 find_package(Qt5DBus)
8-#find_package(Qt5Gui)
9 find_package(Qt5Multimedia)
10 find_package(Qt5Qml)
11-#find_package(Qt5Quick)
12 find_package(Qt5Test)
13 find_package(Qt5Feedback)
14 find_package(Qt5Network)
15@@ -71,10 +69,14 @@
16
17 find_package(PkgConfig REQUIRED)
18 pkg_check_modules(TP_QT5 REQUIRED TelepathyQt5)
19+pkg_check_modules(TP_QT5_FS REQUIRED TelepathyQt5Farstream)
20 pkg_check_modules(NOTIFY REQUIRED libnotify)
21 pkg_check_modules(MESSAGING_MENU REQUIRED messaging-menu)
22 pkg_check_modules(UserMetrics REQUIRED libusermetricsinput-1)
23 pkg_check_modules(HISTORY REQUIRED history-service)
24+pkg_check_modules(TPFS REQUIRED telepathy-farstream)
25+pkg_check_modules(GST REQUIRED gstreamer-1.0)
26+pkg_check_modules(FS REQUIRED farstream-0.2)
27
28 add_definitions(-DQT_NO_KEYWORDS)
29
30
31=== modified file 'handler/CMakeLists.txt'
32--- handler/CMakeLists.txt 2016-07-07 22:16:11 +0000
33+++ handler/CMakeLists.txt 2016-12-17 13:33:18 +0000
34@@ -1,7 +1,9 @@
35
36 set(qt_SRCS
37+ callagent.cpp
38 callhandler.cpp
39 chatstartingjob.cpp
40+ farstreamchannel.cpp
41 handler.cpp
42 handlerdbus.cpp
43 messagejob.cpp
44@@ -16,6 +18,9 @@
45
46 include_directories(
47 ${TP_QT5_INCLUDE_DIRS}
48+ ${TPFS_INCLUDE_DIRS}
49+ ${FS_INCLUDE_DIRS}
50+ ${GST_INCLUDE_DIRS}
51 ${CMAKE_SOURCE_DIR}/libtelephonyservice
52 ${CMAKE_CURRENT_BINARY_DIR}
53 )
54@@ -25,6 +30,9 @@
55
56 target_link_libraries(telephony-service-handler
57 ${TP_QT5_LIBRARIES}
58+ ${TP_QT5_FS_LIBRARIES}
59+ ${TPFS_LIBRARIES}
60+ ${FS_LIBRARIES}
61 telephonyservice
62 )
63
64
65=== modified file 'handler/TelephonyServiceHandler.client'
66--- handler/TelephonyServiceHandler.client 2016-04-15 22:25:51 +0000
67+++ handler/TelephonyServiceHandler.client 2016-12-17 13:33:18 +0000
68@@ -6,3 +6,12 @@
69
70 [org.freedesktop.Telepathy.Client.Handler.HandlerChannelFilter 3]
71 org.freedesktop.Telepathy.Channel.ChannelType s=org.freedesktop.Telepathy.Channel.Type.Call1
72+
73+[org.freedesktop.Telepathy.Client.Handler.HandlerChannelFilter 1]
74+org.freedesktop.Telepathy.Channel.ChannelType s=org.freedesktop.Telepathy.Channel.Type.Call1
75+org.freedesktop.Telepathy.Channel.Type.Call1.InitialAudio b=true
76+
77+[org.freedesktop.Telepathy.Client.Handler.Capabilities]
78+org.freedesktop.Telepathy.Channel.Type.Call1/audio=true
79+org.freedesktop.Telepathy.Channel.Type.Call1/ice=true
80+org.freedesktop.Telepathy.Channel.Type.Call1/gtalk-p2p=true
81
82=== added file 'handler/callagent.cpp'
83--- handler/callagent.cpp 1970-01-01 00:00:00 +0000
84+++ handler/callagent.cpp 2016-12-17 13:33:18 +0000
85@@ -0,0 +1,118 @@
86+/*
87+ * Copyright (C) 2014 Canonical, Ltd.
88+ *
89+ * Authors:
90+ * Gustavo Pichorim Boiko <gustavo.boiko@canonical.com>
91+ *
92+ * This file is part of telephony-service.
93+ *
94+ * telephony-service is free software; you can redistribute it and/or modify
95+ * it under the terms of the GNU General Public License as published by
96+ * the Free Software Foundation; version 3.
97+ *
98+ * telephony-service is distributed in the hope that it will be useful,
99+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
100+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
101+ * GNU General Public License for more details.
102+ *
103+ * You should have received a copy of the GNU General Public License
104+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
105+ */
106+
107+#include "callagent.h"
108+#include <TelepathyQt/CallContent>
109+#include <TelepathyQt/Contact>
110+#include <TelepathyQt/Farstream/Channel>
111+#include <QDebug>
112+
113+CallAgent::CallAgent(const Tp::CallChannelPtr &channel, QObject *parent) :
114+ QObject(parent), mChannel(channel), mFarstreamChannel(0)
115+{
116+ connect(mChannel.data(),
117+ SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)),
118+ SLOT(onCallChannelInvalidated()));
119+ connect(mChannel.data(),
120+ SIGNAL(callStateChanged(Tp::CallState)),
121+ SLOT(onCallStateChanged(Tp::CallState)));
122+ connect(mChannel.data(),
123+ SIGNAL(contentAdded(Tp::CallContentPtr)),
124+ SLOT(onContentAdded(Tp::CallContentPtr)));
125+
126+ Q_FOREACH(const Tp::CallContentPtr &content, mChannel->contents()) {
127+ onContentAdded(content);
128+ }
129+
130+ if (!mChannel->handlerStreamingRequired()) {
131+ return;
132+ }
133+
134+ Tp::Farstream::PendingChannel *pendingChannel = Tp::Farstream::createChannel(mChannel);
135+ connect(pendingChannel,
136+ SIGNAL(finished(Tp::PendingOperation*)),
137+ SLOT(onFarstreamChannelCreated(Tp::PendingOperation*)));
138+}
139+
140+CallAgent::~CallAgent()
141+{
142+ if (mFarstreamChannel) {
143+ mFarstreamChannel->deleteLater();
144+ }
145+}
146+
147+void CallAgent::setMute(bool mute)
148+{
149+ if (!mFarstreamChannel) {
150+ return;
151+ }
152+
153+ mFarstreamChannel->setMute(mute);
154+}
155+
156+void CallAgent::onCallChannelInvalidated()
157+{
158+ deleteLater();
159+}
160+
161+void CallAgent::onCallStateChanged(Tp::CallState state)
162+{
163+ if (state == Tp::CallStatePendingInitiator) {
164+ mChannel->accept();
165+ }
166+}
167+
168+void CallAgent::onContentAdded(const Tp::CallContentPtr &content)
169+{
170+ if (!mChannel->handlerStreamingRequired()) {
171+ return;
172+ }
173+
174+ qDebug() << "Content Added, name: " << content->name() << " type: " << content->type();
175+
176+ connect(content.data(),
177+ SIGNAL(streamAdded(Tp::CallStreamPtr)),
178+ SLOT(onStreamAdded(Tp::CallStreamPtr)));
179+
180+ Q_FOREACH(const Tp::CallStreamPtr &stream, content->streams()) {
181+ onStreamAdded(stream);
182+ }
183+}
184+
185+void CallAgent::onStreamAdded(const Tp::CallStreamPtr &stream)
186+{
187+ qDebug() << "Stream present: " << stream->localSendingState();
188+
189+ qDebug() << " members " << stream->remoteMembers().size();
190+ Q_FOREACH(const Tp::ContactPtr contact, stream->remoteMembers()) {
191+ qDebug() << " member " << contact->id() << " remoteSendingState=" << stream->remoteSendingState(contact);
192+ }
193+}
194+
195+void CallAgent::onFarstreamChannelCreated(Tp::PendingOperation *op)
196+{
197+ Tp::Farstream::PendingChannel *pendingChannel = qobject_cast<Tp::Farstream::PendingChannel*>(op);
198+ if (!pendingChannel) {
199+ return;
200+ }
201+
202+ mFarstreamChannel = new FarstreamChannel(pendingChannel->tfChannel(), this);
203+}
204
205=== added file 'handler/callagent.h'
206--- handler/callagent.h 1970-01-01 00:00:00 +0000
207+++ handler/callagent.h 2016-12-17 13:33:18 +0000
208@@ -0,0 +1,52 @@
209+/*
210+ * Copyright (C) 2014 Canonical, Ltd.
211+ *
212+ * Authors:
213+ * Gustavo Pichorim Boiko <gustavo.boiko@canonical.com>
214+ *
215+ * This file is part of telephony-service.
216+ *
217+ * telephony-service is free software; you can redistribute it and/or modify
218+ * it under the terms of the GNU General Public License as published by
219+ * the Free Software Foundation; version 3.
220+ *
221+ * telephony-service is distributed in the hope that it will be useful,
222+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
223+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
224+ * GNU General Public License for more details.
225+ *
226+ * You should have received a copy of the GNU General Public License
227+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
228+ */
229+
230+#ifndef CALLAGENT_H
231+#define CALLAGENT_H
232+
233+#include <QObject>
234+#include <TelepathyQt/CallChannel>
235+#include <TelepathyQt/Farstream/Channel>
236+#include "farstreamchannel.h"
237+
238+class CallAgent : public QObject
239+{
240+ Q_OBJECT
241+public:
242+ explicit CallAgent(const Tp::CallChannelPtr &channel, QObject *parent = 0);
243+ ~CallAgent();
244+
245+ void setMute(bool mute);
246+
247+protected Q_SLOTS:
248+ void onCallChannelInvalidated();
249+ void onCallStateChanged(Tp::CallState state);
250+ void onContentAdded(const Tp::CallContentPtr &content);
251+ void onStreamAdded(const Tp::CallStreamPtr &stream);
252+
253+ void onFarstreamChannelCreated(Tp::PendingOperation *op);
254+
255+private:
256+ Tp::CallChannelPtr mChannel;
257+ FarstreamChannel *mFarstreamChannel;
258+};
259+
260+#endif // CALLAGENT_H
261
262=== modified file 'handler/callhandler.cpp'
263--- handler/callhandler.cpp 2015-07-06 23:32:13 +0000
264+++ handler/callhandler.cpp 2016-12-17 13:33:18 +0000
265@@ -20,15 +20,18 @@
266 * along with this program. If not, see <http://www.gnu.org/licenses/>.
267 */
268
269+#include "callagent.h"
270 #include "callhandler.h"
271-#include "phoneutils.h"
272 #include "telepathyhelper.h"
273 #include "accountentry.h"
274 #include "tonegenerator.h"
275 #include "greetercontacts.h"
276+#include "phoneutils.h"
277 #include <TelepathyQt/ContactManager>
278 #include <TelepathyQt/PendingContacts>
279 #include <TelepathyQt/PendingChannelRequest>
280+#include <TelepathyQt/PendingVariant>
281+#include <memory>
282
283 #define TELEPATHY_MUTE_IFACE "org.freedesktop.Telepathy.Call1.Interface.Mute"
284 #define DBUS_PROPERTIES_IFACE "org.freedesktop.DBus.Properties"
285@@ -72,8 +75,7 @@
286 bool hasActiveCalls = false;
287
288 Q_FOREACH(const Tp::CallChannelPtr channel, mCallChannels) {
289- AccountEntry *accountEntry = TelepathyHelper::instance()->accountForConnection(channel->connection());
290- bool incoming = channel->initiatorContact() != accountEntry->account()->connection()->selfContact();
291+ bool incoming = isIncoming(channel);
292 bool dialing = !incoming && (channel->callState() == Tp::CallStateInitialised);
293 bool active = channel->callState() == Tp::CallStateActive;
294
295@@ -94,6 +96,7 @@
296
297 void CallHandler::startCall(const QString &targetId, const QString &accountId)
298 {
299+ QString finalId = targetId;
300 // Request the contact to start audio call
301 AccountEntry *accountEntry = TelepathyHelper::instance()->accountForId(accountId);
302 if (!accountEntry) {
303@@ -105,7 +108,20 @@
304 return;
305 }
306
307- connect(connection->contactManager()->contactsForIdentifiers(QStringList() << targetId),
308+ // FIXME: this is a workaround, there might be a better way of handling this.
309+ // One idea is to implement the Addressing interface on the SIP connection manager such that
310+ // we can request a handle based on the vCard field "tel"
311+ if (accountEntry->protocolInfo()->name() == "sip") {
312+ // in case this is a SIP call, replace the numbers by a SIP URI
313+ QString domain = accountEntry->account()->parameters()["account"].toString();
314+ if (domain.contains("@")) {
315+ domain = domain.split("@")[1];
316+
317+ finalId = QString("sip:%1@%2").arg(PhoneUtils::normalizePhoneNumber(targetId)).arg(domain);
318+ }
319+ }
320+
321+ connect(connection->contactManager()->contactsForIdentifiers(QStringList() << finalId),
322 SIGNAL(finished(Tp::PendingOperation*)),
323 SLOT(onContactsAvailable(Tp::PendingOperation*)));
324 }
325@@ -146,9 +162,17 @@
326 return;
327 }
328
329- // FIXME: replace by a proper TpQt implementation of mute
330- QDBusInterface muteInterface(channel->busName(), channel->objectPath(), TELEPATHY_MUTE_IFACE);
331- muteInterface.call("RequestMuted", muted);
332+ if (channel->handlerStreamingRequired()) {
333+ CallAgent *agent = mCallAgents[channel.data()];
334+ if (!agent) {
335+ return;
336+ }
337+ agent->setMute(muted);
338+ } else {
339+ // FIXME: replace by a proper TpQt implementation of mute
340+ QDBusInterface muteInterface(channel->busName(), channel->objectPath(), TELEPATHY_MUTE_IFACE);
341+ muteInterface.call("RequestMuted", muted);
342+ }
343 }
344
345 void CallHandler::setActiveAudioOutput(const QString &objectPath, const QString &id)
346@@ -161,26 +185,15 @@
347
348 void CallHandler::sendDTMF(const QString &objectPath, const QString &key)
349 {
350- bool ok;
351- Tp::DTMFEvent event = (Tp::DTMFEvent)key.toInt(&ok);
352- if (!ok) {
353- if (!key.compare("*")) {
354- event = Tp::DTMFEventAsterisk;
355- } else if (!key.compare("#")) {
356- event = Tp::DTMFEventHash;
357- } else {
358- qWarning() << "Tone not recognized. DTMF failed";
359- return;
360- }
361- }
362 /*
363- * play locally (via tone generator) only if we are on a call, or if this is
364+ * play locally (via tone generator) only if we are on a call, or if this is
365 * dialpad sounds
366 */
367- if (GreeterContacts::instance()->dialpadSoundsEnabled() &&
368+ int event = toDTMFEvent(key);
369+ if (GreeterContacts::instance()->dialpadSoundsEnabled() &&
370 !GreeterContacts::instance()->silentMode() && objectPath.isEmpty()
371 || !objectPath.isEmpty()) {
372- ToneGenerator::instance()->playDTMFTone((uint)event);
373+ ToneGenerator::instance()->playDTMFTone(event);
374 }
375
376 Tp::CallChannelPtr channel = callFromObjectPath(objectPath);
377@@ -190,14 +203,15 @@
378
379 // save the dtmfString to send to clients that request it
380 QString dtmfString = channel->property("dtmfString").toString();
381+ QString pendingDTMF = channel->property("pendingDTMF").toString();
382+ pendingDTMF += key;
383 dtmfString += key;
384 channel->setProperty("dtmfString", dtmfString);
385+ channel->setProperty("pendingDTMF", pendingDTMF);
386
387- Q_FOREACH(const Tp::CallContentPtr &content, channel->contents()) {
388- if (content->supportsDTMF()) {
389- /* send DTMF to network (via telepathy and oFono) */
390- content->startDTMFTone(event);
391- }
392+ // if there is only one pending DTMF event, start playing it
393+ if (pendingDTMF.length() == 1) {
394+ playNextDTMFTone(channel);
395 }
396
397 Q_EMIT callPropertiesChanged(channel->objectPath(), getCallProperties(channel->objectPath()));
398@@ -273,6 +287,8 @@
399
400 if (channel->callState() == Tp::CallStateActive) {
401 channel->setProperty("activeTimestamp", QDateTime::currentDateTimeUtc());
402+ } else if (channel->callState() == Tp::CallStatePendingInitiator) {
403+ channel->accept();
404 }
405
406 connect(channel.data(),
407@@ -282,6 +298,10 @@
408 SIGNAL(callStateChanged(Tp::CallState)),
409 SLOT(onCallStateChanged(Tp::CallState)));
410
411+ // FIXME: save this to a list
412+ CallAgent *agent = new CallAgent(channel, this);
413+ mCallAgents[channel.data()] = agent;
414+
415 mCallChannels.append(channel);
416 Q_EMIT callPropertiesChanged(channel->objectPath(), getCallProperties(channel->objectPath()));
417 }
418@@ -331,6 +351,10 @@
419 }
420
421 mCallChannels.removeAll(channel);
422+ if (mCallAgents.contains(channel.data())) {
423+ CallAgent *agent = mCallAgents.take(channel.data());
424+ agent->deleteLater();
425+ }
426
427 if (mCallChannels.isEmpty() && !mHangupRequested) {
428 ToneGenerator::instance()->playCallEndedTone();
429@@ -346,7 +370,22 @@
430 }
431
432 switch (state) {
433+ case Tp::CallStatePendingInitiator:
434+ case Tp::CallStateInitialising:
435+ if (!isIncoming(channel) && channel->handlerStreamingRequired()) {
436+ ToneGenerator::instance()->playDialingTone();
437+ }
438+ break;
439+ case Tp::CallStateInitialised:
440+ if (!isIncoming(channel) && channel->handlerStreamingRequired()) {
441+ ToneGenerator::instance()->stopTone();
442+ ToneGenerator::instance()->playRingingTone();
443+ }
444+ break;
445 case Tp::CallStateActive:
446+ if (channel->handlerStreamingRequired()) {
447+ ToneGenerator::instance()->stopTone();
448+ }
449 channel->setProperty("activeTimestamp", QDateTime::currentDateTimeUtc());
450 Q_EMIT callPropertiesChanged(channel->objectPath(), getCallProperties(channel->objectPath()));
451 break;
452@@ -387,3 +426,101 @@
453
454 return channel;
455 }
456+
457+void CallHandler::playNextDTMFTone(Tp::CallChannelPtr channel)
458+{
459+ // the channel might have been closed already
460+ if (!channel) {
461+ return;
462+ }
463+
464+ QString pendingDTMF = channel->property("pendingDTMF").toString();
465+ QString key = "";
466+ if (!pendingDTMF.isEmpty()) {
467+ key = pendingDTMF[0];
468+ }
469+
470+ int event = toDTMFEvent(key);
471+
472+ Q_FOREACH(const Tp::CallContentPtr &content, channel->contents()) {
473+ if (content->supportsDTMF()) {
474+
475+ /* stop any previous DTMF tone before sending the new one*/
476+ connect(content->stopDTMFTone(), &Tp::PendingOperation::finished, [=](Tp::PendingOperation *op){
477+ // in case stopDTMFTone, it might mean the service automatically stops the tone,
478+ // so try playing the next one
479+ if (op->isError()) {
480+ /* send DTMF to network (via telepathy) */
481+ if (event >= 0) {
482+ content->startDTMFTone((Tp::DTMFEvent)event);
483+ }
484+ triggerNextDTMFTone(channel);
485+ return;
486+ }
487+
488+ Tp::Client::CallContentInterfaceDTMFInterface *dtmfInterface = content->interface<Tp::Client::CallContentInterfaceDTMFInterface>();
489+ Tp::PendingVariant *pv = dtmfInterface->requestPropertyCurrentlySendingTones();
490+ connect(pv, &Tp::PendingOperation::finished, [=](){
491+ bool sendingTones = pv->result().toBool();
492+ // if we already stopped sending tones, we can send the next one
493+ if (!sendingTones) {
494+ /* send DTMF to network (via telepathy) */
495+ if (event >= 0) {
496+ content->startDTMFTone((Tp::DTMFEvent)event);
497+ }
498+ triggerNextDTMFTone(channel);
499+ return;
500+ }
501+
502+ // in case the previous tone is not finished, we need to wait for it
503+ auto conn = std::make_shared<QMetaObject::Connection>();
504+ *conn = connect(dtmfInterface, &Tp::Client::CallContentInterfaceDTMFInterface::StoppedTones, [=](){
505+ QObject::disconnect(*conn);
506+
507+ /* send DTMF to network (via telepathy) */
508+ if (event >= 0) {
509+ content->startDTMFTone((Tp::DTMFEvent)event);
510+ }
511+ triggerNextDTMFTone(channel);
512+ });
513+ });
514+
515+ });
516+ }
517+ }
518+}
519+
520+void CallHandler::triggerNextDTMFTone(Tp::CallChannelPtr channel)
521+{
522+ QTimer::singleShot(250, [=](){
523+ QString pendingDTMF = channel->property("pendingDTMF").toString();
524+ if (pendingDTMF.isEmpty()) {
525+ return;
526+ }
527+ pendingDTMF.remove(0, 1);
528+ channel->setProperty("pendingDTMF", pendingDTMF);
529+ playNextDTMFTone(channel);
530+ });
531+}
532+
533+int CallHandler::toDTMFEvent(const QString &key)
534+{
535+ bool ok;
536+ int ev = key.toInt(&ok);
537+ if (!ok) {
538+ if (key == "*") {
539+ ev = Tp::DTMFEventAsterisk;
540+ } else if (key == "#") {
541+ ev = Tp::DTMFEventHash;
542+ } else {
543+ ev = -1;
544+ }
545+ }
546+ return ev;
547+}
548+
549+bool CallHandler::isIncoming(const Tp::CallChannelPtr &channel) const
550+{
551+ AccountEntry *accountEntry = TelepathyHelper::instance()->accountForConnection(channel->connection());
552+ return channel->initiatorContact() != accountEntry->account()->connection()->selfContact();
553+}
554
555=== modified file 'handler/callhandler.h'
556--- handler/callhandler.h 2015-03-04 18:02:13 +0000
557+++ handler/callhandler.h 2016-12-17 13:33:18 +0000
558@@ -1,5 +1,5 @@
559 /*
560- * Copyright (C) 2012-2013 Canonical, Ltd.
561+ * Copyright (C) 2012-2014 Canonical, Ltd.
562 *
563 * Authors:
564 * Gustavo Pichorim Boiko <gustavo.boiko@canonical.com>
565@@ -28,6 +28,7 @@
566 #include <TelepathyQt/CallChannel>
567
568 class TelepathyHelper;
569+class CallAgent;
570
571 class CallHandler : public QObject
572 {
573@@ -61,6 +62,11 @@
574 Tp::CallChannelPtr existingCall(const QString &targetId);
575 Tp::CallChannelPtr callFromObjectPath(const QString &objectPath);
576
577+ void playNextDTMFTone(Tp::CallChannelPtr channel);
578+ void triggerNextDTMFTone(Tp::CallChannelPtr channel);
579+ static int toDTMFEvent(const QString &key);
580+ bool isIncoming(const Tp::CallChannelPtr &channel) const;
581+
582 protected Q_SLOTS:
583 void onContactsAvailable(Tp::PendingOperation *op);
584 void onCallHangupFinished(Tp::PendingOperation *op);
585@@ -72,6 +78,7 @@
586
587 QMap<QString, Tp::ContactPtr> mContacts;
588 QList<Tp::CallChannelPtr> mCallChannels;
589+ QMap<Tp::CallChannel*,CallAgent*> mCallAgents;
590 QMap<Tp::PendingOperation*,Tp::CallChannelPtr> mClosingChannels;
591 bool mHangupRequested;
592 };
593
594=== added file 'handler/farstreamchannel.cpp'
595--- handler/farstreamchannel.cpp 1970-01-01 00:00:00 +0000
596+++ handler/farstreamchannel.cpp 2016-12-17 13:33:18 +0000
597@@ -0,0 +1,330 @@
598+/*
599+ * Copyright (C) 2014 Canonical, Ltd.
600+ *
601+ * Authors:
602+ * Gustavo Pichorim Boiko <gustavo.boiko@canonical.com>
603+ *
604+ * This file is part of telephony-service.
605+ *
606+ * telephony-service is free software; you can redistribute it and/or modify
607+ * it under the terms of the GNU General Public License as published by
608+ * the Free Software Foundation; version 3.
609+ *
610+ * telephony-service is distributed in the hope that it will be useful,
611+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
612+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
613+ * GNU General Public License for more details.
614+ *
615+ * You should have received a copy of the GNU General Public License
616+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
617+ */
618+
619+#include "farstreamchannel.h"
620+#include <farstream/fs-utils.h>
621+#include <QDebug>
622+
623+FarstreamChannel::FarstreamChannel(TfChannel *channel, QObject *parent) :
624+ mChannel(channel), QObject(parent), mPipeline(0), mBus(0), mBusSource(0),
625+ mConferenceAddedSignal(0), mConferenceRemovedSignal(0), mContentAddedSignal(0),
626+ mContentRemovedSignal(0), mAudioInput(0), mAudioOutput(0)
627+{
628+ qDebug() << __PRETTY_FUNCTION__;
629+ initialize();
630+}
631+
632+FarstreamChannel::~FarstreamChannel()
633+{
634+ // stop audio input and output
635+ if (mAudioInput) {
636+ setState(mAudioInput, GST_STATE_NULL);
637+ gst_object_unref(mAudioInput);
638+ }
639+
640+ if (mAudioOutput) {
641+ setState(mAudioOutput, GST_STATE_NULL);
642+ gst_object_unref(mAudioOutput);
643+ }
644+
645+ // now clear the notifiers
646+ Q_FOREACH(FsElementAddedNotifier *notifier, mNotifiers) {
647+ fs_element_added_notifier_remove(notifier, GST_BIN(mPipeline));
648+ g_object_unref(notifier);
649+ }
650+ mNotifiers.clear();
651+
652+ // clear the bus stuff
653+ if (mBusSource) {
654+ g_source_remove(mBusSource);
655+ }
656+
657+ if (mBus) {
658+ gst_object_unref(mBus);
659+ }
660+
661+ // and finally the pipeline
662+ if (mPipeline) {
663+ setState(mPipeline, GST_STATE_NULL);
664+ gst_object_unref(mPipeline);
665+ }
666+}
667+
668+void FarstreamChannel::setMute(bool mute)
669+{
670+ GstElement *input_volume = gst_bin_get_by_name(GST_BIN(mPipeline), "input_volume");
671+ g_object_set(input_volume, "mute", mute, NULL);
672+ g_object_unref(input_volume);
673+}
674+
675+void FarstreamChannel::initialize()
676+{
677+ qDebug() << __PRETTY_FUNCTION__;
678+ // connect all the signals
679+ mConferenceAddedSignal = g_signal_connect(mChannel, "fs-conference-added",
680+ G_CALLBACK(&FarstreamChannel::onConferenceAdded),
681+ this);
682+ mConferenceRemovedSignal = g_signal_connect(mChannel, "fs-conference-removed",
683+ G_CALLBACK(&FarstreamChannel::onConferenceRemoved),
684+ this);
685+ mContentAddedSignal = g_signal_connect(mChannel, "content-added",
686+ G_CALLBACK(&FarstreamChannel::onContentAdded),
687+ this);
688+ mContentRemovedSignal = g_signal_connect(mChannel, "content-removed",
689+ G_CALLBACK(&FarstreamChannel::onContentRemoved),
690+ this);
691+
692+ // and initialize the gstreamer pipeline
693+ mPipeline = gst_pipeline_new(NULL);
694+ if (!mPipeline) {
695+ qCritical() << "Failed to create GStreamer pipeline.";
696+ return;
697+ }
698+
699+ mBus = gst_pipeline_get_bus(GST_PIPELINE(mPipeline));
700+ if (!mBus) {
701+ qCritical() << "Failed to get GStreamer pipeline bus.";
702+ return;
703+ }
704+
705+ mBusSource = gst_bus_add_watch(mBus, (GstBusFunc) &FarstreamChannel::onBusWatch, this);
706+
707+ if (!setState(mPipeline, GST_STATE_PLAYING)) {
708+ return;
709+ }
710+}
711+
712+GstElement *FarstreamChannel::initializeAudioSource(TfContent *content)
713+{
714+ qDebug() << __PRETTY_FUNCTION__;
715+ GstElement *element = gst_parse_bin_from_description ("pulsesrc ! audio/x-raw, rate=8000 ! queue"
716+ " ! audioconvert ! audioresample"
717+ " ! volume name=input_volume ! audioconvert ",
718+ TRUE, NULL);
719+ gint input_volume = 0;
720+ g_object_get (content, "requested-input-volume", &input_volume, NULL);
721+
722+ if (input_volume >= 0) {
723+ GstElement *volume = gst_bin_get_by_name (GST_BIN (element), "input_volume");
724+ g_object_set (volume, "volume", (double)input_volume / 255.0, NULL);
725+ gst_object_unref (volume);
726+ }
727+
728+ // FIXME: we probably need to handle input volume request changes
729+ mAudioOutput = element;
730+ return element;
731+}
732+
733+bool FarstreamChannel::addToPipeline(GstElement *element)
734+{
735+ qDebug() << __PRETTY_FUNCTION__ << GST_ELEMENT_NAME(element);
736+ if (!mPipeline) {
737+ qWarning() << "No gstreamer pipeline found.";
738+ return false;
739+ }
740+
741+ if (!gst_bin_add(GST_BIN(mPipeline), element)) {
742+ qCritical() << "Failed to add bin" << GST_ELEMENT_NAME(element) << "to pipeline.";
743+ return false;
744+ }
745+ qDebug() << "Succeeded adding to pipeline!";
746+ return true;
747+}
748+
749+void FarstreamChannel::removeFromPipeline(GstElement *element)
750+{
751+ qDebug() << __PRETTY_FUNCTION__ << GST_ELEMENT_NAME(element);
752+ gst_element_set_locked_state(element, TRUE);
753+ setState(element, GST_STATE_NULL);
754+ gst_bin_remove (GST_BIN (mPipeline), element);
755+}
756+
757+bool FarstreamChannel::setState(GstElement *element, GstState state)
758+{
759+ qDebug() << __PRETTY_FUNCTION__ << GST_ELEMENT_NAME(element) << gst_element_state_get_name(state);
760+ GstStateChangeReturn result = gst_element_set_state(element, state);
761+ if (result == GST_STATE_CHANGE_FAILURE) {
762+ qCritical() << "Failed to set GStreamer element" << GST_ELEMENT_NAME(element) << "state to" << gst_element_state_get_name(state);
763+ return false;
764+ }
765+ qDebug() << "Succeeded playing!";
766+ return true;
767+}
768+
769+gboolean FarstreamChannel::onBusWatch(GstBus *bus, GstMessage *message, FarstreamChannel *self)
770+{
771+ Q_UNUSED(bus)
772+ if (!self->mChannel) {
773+ return TRUE;
774+ }
775+
776+ // FIXME: maybe we need to do some error handling here?
777+ tf_channel_bus_message(self->mChannel, message);
778+ return TRUE;
779+}
780+
781+void FarstreamChannel::onConferenceAdded(TfChannel *channel, FsConference *conference, FarstreamChannel *self)
782+{
783+ qDebug() << __PRETTY_FUNCTION__;
784+ Q_UNUSED(channel)
785+
786+ /* Add notifier to set the various element properties as needed */
787+ GKeyFile *keyfile = fs_utils_get_default_element_properties (GST_ELEMENT(conference));
788+ if (keyfile != NULL) {
789+ qDebug() << "Loaded default properties for" << GST_ELEMENT_NAME(conference);
790+ FsElementAddedNotifier *notifier = fs_element_added_notifier_new();
791+ fs_element_added_notifier_set_properties_from_keyfile(notifier, keyfile);
792+ fs_element_added_notifier_add(notifier, GST_BIN(self->mPipeline));
793+
794+ // FIXME: right now we are leaking the notifiers, check when to remove them
795+ self->mNotifiers.append(notifier);
796+ }
797+
798+ if (!self->addToPipeline(GST_ELEMENT(conference))) {
799+ return;
800+ }
801+
802+ self->setState(GST_ELEMENT(conference), GST_STATE_PLAYING);
803+}
804+
805+void FarstreamChannel::onConferenceRemoved(TfChannel *channel, FsConference *conference, FarstreamChannel *self)
806+{
807+ qDebug() << __PRETTY_FUNCTION__;
808+ Q_UNUSED(channel);
809+
810+ // just remove the conference from the pipeline
811+ self->removeFromPipeline(GST_ELEMENT(conference));
812+}
813+
814+void FarstreamChannel::onContentAdded(TfChannel *channel, TfContent *content, FarstreamChannel *self)
815+{
816+ qDebug() << __PRETTY_FUNCTION__;
817+ Q_UNUSED(channel)
818+
819+ g_signal_connect(content, "src-pad-added",
820+ G_CALLBACK(&FarstreamChannel::onSrcPadAdded), self);
821+ g_signal_connect(content, "start-sending",
822+ G_CALLBACK(&FarstreamChannel::onStartSending), self);
823+ g_signal_connect(content, "stop-sending",
824+ G_CALLBACK(&FarstreamChannel::onStopSending), self);
825+}
826+
827+void FarstreamChannel::onContentRemoved(TfChannel *channel, TfContent *content, FarstreamChannel *self)
828+{
829+ qDebug() << __PRETTY_FUNCTION__;
830+ // FIXME: implement
831+}
832+
833+bool FarstreamChannel::onStartSending(TfContent *content, FarstreamChannel *self)
834+{
835+ qDebug() << __PRETTY_FUNCTION__;
836+ GstPad *sinkPad;
837+ FsMediaType mediaType;
838+ GstElement *element;
839+
840+ g_object_get (content, "sink-pad", &sinkPad, "media-type", &mediaType, NULL);
841+
842+ switch (mediaType) {
843+ case FS_MEDIA_TYPE_AUDIO:
844+ element = self->initializeAudioSource(content);
845+ break;
846+ // FIXME: add video support
847+ default:
848+ qWarning() << "Unsupported media type:" << mediaType;
849+ g_object_unref(sinkPad);
850+ return false;
851+ }
852+
853+ if (!self->addToPipeline(element)) {
854+ g_object_unref(sinkPad);
855+ return false;
856+ }
857+
858+ GstPad *sourcePad = gst_element_get_static_pad (element, "src");
859+ if (GST_PAD_LINK_FAILED (gst_pad_link (sourcePad, sinkPad))) {
860+ qCritical() << "Failed to link source pad to content's sink pad";
861+ g_object_unref(sinkPad);
862+ g_object_unref(sourcePad);
863+ return false;
864+ }
865+
866+ self->setState(element, GST_STATE_PLAYING);
867+ self->mAudioInput = element;
868+
869+ g_object_unref(sinkPad);
870+ g_object_unref(sourcePad);
871+
872+ qDebug() << "BLABLA generating dot file";
873+ GST_DEBUG_BIN_TO_DOT_FILE (GST_BIN (self->mPipeline),
874+ GST_DEBUG_GRAPH_SHOW_ALL, "telephony-service-gst");
875+ qDebug() << "BLABLA done!";
876+ return true;
877+}
878+
879+void FarstreamChannel::onStopSending(TfContent *content, FarstreamChannel *self)
880+{
881+ qDebug() << __PRETTY_FUNCTION__;
882+ // FIXME: implement
883+}
884+
885+void FarstreamChannel::onSrcPadAdded(TfContent *content, uint handle, FsStream *stream, GstPad *pad, FsCodec *codec, FarstreamChannel *self)
886+{
887+ qDebug() << __PRETTY_FUNCTION__;
888+ gchar *codecString = fs_codec_to_string (codec);
889+ qDebug() << __PRETTY_FUNCTION__ << "Codec:" << codecString;
890+
891+ FsMediaType mediaType;
892+ GstElement *element;
893+
894+ g_object_get (content, "media-type", &mediaType, NULL);
895+
896+ switch (mediaType) {
897+ case FS_MEDIA_TYPE_AUDIO: {
898+ QString outputVolume = QString("output_volume%1").arg(codecString);
899+ QString description = QString("audioconvert ! audioresample "
900+ "! volume name=\"%1\" "
901+ "! audioconvert ! autoaudiosink").arg(outputVolume);
902+ element = gst_parse_bin_from_description (description.toUtf8().data(), TRUE, NULL);
903+ GstElement *volume = gst_bin_get_by_name (GST_BIN (element), outputVolume.toUtf8().data());
904+
905+ // FIXME: we need to handle volume request changes in the volume element
906+ gst_object_unref (volume);
907+ break;
908+ }
909+ // FIXME: handle video
910+ default:
911+ qWarning() << "Unsupported media type:" << mediaType;
912+ return;
913+ }
914+
915+ if (!self->addToPipeline(element)) {
916+ return;
917+ }
918+
919+ GstPad *sinkPad = gst_element_get_static_pad (element, "sink");
920+ if (GST_PAD_LINK_FAILED (gst_pad_link (pad, sinkPad))) {
921+ qCritical() << "Failed to link content's source pad to local sink pad";
922+ }
923+
924+ self->setState(element, GST_STATE_PLAYING);
925+
926+ g_object_unref (sinkPad);
927+}
928
929=== added file 'handler/farstreamchannel.h'
930--- handler/farstreamchannel.h 1970-01-01 00:00:00 +0000
931+++ handler/farstreamchannel.h 2016-12-17 13:33:18 +0000
932@@ -0,0 +1,80 @@
933+/*
934+ * Copyright (C) 2014 Canonical, Ltd.
935+ *
936+ * Authors:
937+ * Gustavo Pichorim Boiko <gustavo.boiko@canonical.com>
938+ *
939+ * This file is part of telephony-service.
940+ *
941+ * telephony-service is free software; you can redistribute it and/or modify
942+ * it under the terms of the GNU General Public License as published by
943+ * the Free Software Foundation; version 3.
944+ *
945+ * telephony-service is distributed in the hope that it will be useful,
946+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
947+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
948+ * GNU General Public License for more details.
949+ *
950+ * You should have received a copy of the GNU General Public License
951+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
952+ */
953+
954+#ifndef FARSTREAMCHANNEL_H
955+#define FARSTREAMCHANNEL_H
956+
957+#include <QObject>
958+#include <QList>
959+#include <telepathy-farstream/telepathy-farstream.h>
960+#include <farstream/fs-conference.h>
961+#include <farstream/fs-stream.h>
962+#include <farstream/fs-element-added-notifier.h>
963+
964+class FarstreamChannel : public QObject
965+{
966+ Q_OBJECT
967+public:
968+ explicit FarstreamChannel(TfChannel *channel, QObject *parent = 0);
969+ ~FarstreamChannel();
970+
971+ void setMute(bool mute);
972+
973+protected:
974+ void initialize();
975+ GstElement *initializeAudioSource(TfContent *content);
976+
977+ // gstreamer helpers
978+ bool addToPipeline(GstElement *element);
979+ void removeFromPipeline(GstElement *bin);
980+ bool setState(GstElement *element, GstState state);
981+
982+ // glib signal handlers
983+ static gboolean onBusWatch(GstBus *bus, GstMessage *message, FarstreamChannel *self);
984+ static void onConferenceAdded(TfChannel *channel, FsConference *conference, FarstreamChannel *self);
985+ static void onConferenceRemoved(TfChannel *channel, FsConference *conference, FarstreamChannel *self);
986+ static void onContentAdded(TfChannel *channel, TfContent * content, FarstreamChannel *self);
987+ static void onContentRemoved(TfChannel *channel, TfContent * content, FarstreamChannel *self);
988+ static bool onStartSending(TfContent *content, FarstreamChannel *self);
989+ static void onStopSending(TfContent *content, FarstreamChannel *self);
990+ static void onSrcPadAdded(TfContent *content, uint handle, FsStream *stream, GstPad *pad, FsCodec *codec, FarstreamChannel *self);
991+
992+private:
993+ TfChannel *mChannel;
994+
995+ // gstreamer stuff
996+ GstElement *mPipeline;
997+ GstBus *mBus;
998+ uint mBusSource;
999+ GstElement *mAudioInput;
1000+ GstElement *mAudioOutput;
1001+
1002+ // signal IDs
1003+ gulong mConferenceAddedSignal;
1004+ gulong mConferenceRemovedSignal;
1005+ gulong mContentAddedSignal;
1006+ gulong mContentRemovedSignal;
1007+
1008+ // farstream stuff
1009+ QList<FsElementAddedNotifier*> mNotifiers;
1010+};
1011+
1012+#endif // FARSTREAMCHANNEL_H
1013
1014=== modified file 'handler/handler.cpp'
1015--- handler/handler.cpp 2016-11-23 19:28:18 +0000
1016+++ handler/handler.cpp 2016-12-17 13:33:18 +0000
1017@@ -32,7 +32,7 @@
1018 #include <TelepathyQt/PendingReady>
1019
1020 Handler::Handler(QObject *parent)
1021- : QObject(parent), Tp::AbstractClientHandler(channelFilters())
1022+ : QObject(parent), Tp::AbstractClientHandler(channelFilters(), capabilities())
1023 {
1024 }
1025
1026@@ -102,9 +102,22 @@
1027 specList << Tp::ChannelClassSpec::textChatroom();
1028 specList << Tp::ChannelClassSpec::unnamedTextChat();
1029
1030+ QVariantMap props;
1031+ props[TP_QT_IFACE_CHANNEL_TYPE_CALL + ".InitialAudio"] = true;
1032+ specList << Tp::ChannelClassSpec::audioCall(props);
1033+
1034 return specList;
1035 }
1036
1037+Tp::AbstractClientHandler::Capabilities Handler::capabilities()
1038+{
1039+ QStringList caps;
1040+ caps << TP_QT_IFACE_CHANNEL_TYPE_CALL + "/shm"
1041+ << TP_QT_IFACE_CHANNEL_TYPE_CALL + "/ice"
1042+ << TP_QT_IFACE_CHANNEL_TYPE_CALL + "/gtalk-p2p";
1043+ return Tp::AbstractClientHandler::Capabilities(caps);
1044+}
1045+
1046 void Handler::onTextChannelReady(Tp::PendingOperation *op)
1047 {
1048 Tp::PendingReady *pr = qobject_cast<Tp::PendingReady*>(op);
1049@@ -133,6 +146,7 @@
1050
1051 void Handler::onCallChannelReady(Tp::PendingOperation *op)
1052 {
1053+ qDebug() << "BLABLA" << __PRETTY_FUNCTION__;
1054 Tp::PendingReady *pr = qobject_cast<Tp::PendingReady*>(op);
1055
1056 if (!pr) {
1057@@ -155,11 +169,16 @@
1058 // if the call is neither Accepted nor Active, it means it got dispatched directly to the handler without passing
1059 // through any approver. For phone calls, this would mean calls getting auto-accepted which is not desirable
1060 // so we return an error here
1061- bool incoming = false;
1062+ bool incoming = !callChannel->isRequested();
1063+ qDebug() << "BLABLA Is requested:" << !incoming;
1064 AccountEntry *accountEntry = TelepathyHelper::instance()->accountForConnection(callChannel->connection());
1065- if (accountEntry) {
1066- incoming = callChannel->initiatorContact() != accountEntry->account()->connection()->selfContact();
1067+ qDebug() << "BLABLA accountEntry:" << accountEntry;
1068+ if (accountEntry &&
1069+ !callChannel->initiatorContact().isNull() &&
1070+ callChannel->initiatorContact() != accountEntry->account()->connection()->selfContact()) {
1071+ incoming = true;
1072 }
1073+ qDebug() << "BLABLA incoming:" << incoming;
1074 if (incoming && callChannel->callState() != Tp::CallStateAccepted && callChannel->callState() != Tp::CallStateActive) {
1075 qWarning() << "Available channel was not approved by telephony-service-approver, ignoring it.";
1076 if (context) {
1077
1078=== modified file 'handler/handler.h'
1079--- handler/handler.h 2015-07-01 22:04:30 +0000
1080+++ handler/handler.h 2016-12-17 13:33:18 +0000
1081@@ -45,6 +45,7 @@
1082 const QDateTime &userActionTime,
1083 const Tp::AbstractClientHandler::HandlerInfo &handlerInfo);
1084 Tp::ChannelClassSpecList channelFilters();
1085+ Tp::AbstractClientHandler::Capabilities capabilities();
1086
1087 Q_SIGNALS:
1088 void textChannelAvailable(Tp::TextChannelPtr textChannel);
1089
1090=== modified file 'handler/main.cpp'
1091--- handler/main.cpp 2016-11-23 19:28:18 +0000
1092+++ handler/main.cpp 2016-12-17 13:33:18 +0000
1093@@ -30,6 +30,7 @@
1094 #include <TelepathyQt/AbstractClient>
1095 #include <TelepathyQt/AccountManager>
1096 #include <TelepathyQt/Contact>
1097+#include <telepathy-farstream/telepathy-farstream.h>
1098
1099 int main(int argc, char **argv)
1100 {
1101@@ -37,6 +38,7 @@
1102 QCoreApplication::setApplicationName("telephony-service-handler");
1103
1104 Tp::registerTypes();
1105+ gst_init(&argc, &argv);
1106
1107 // check if there is already an instance of the handler running
1108 if (ApplicationUtils::checkApplicationRunning(TP_QT_IFACE_CLIENT + ".TelephonyServiceHandler")) {
1109
1110=== modified file 'libtelephonyservice/accountentry.cpp'
1111--- libtelephonyservice/accountentry.cpp 2016-10-05 19:15:39 +0000
1112+++ libtelephonyservice/accountentry.cpp 2016-12-17 13:33:18 +0000
1113@@ -28,6 +28,10 @@
1114
1115 Q_DECLARE_METATYPE(Tp::ConnectionPtr);
1116
1117+namespace C {
1118+#include <libintl.h>
1119+}
1120+
1121 AccountEntry::AccountEntry(const Tp::AccountPtr &account, QObject *parent) :
1122 QObject(parent), mAccount(account), mReady(false), mProtocol(0)
1123 {
1124@@ -51,10 +55,19 @@
1125
1126 bool AccountEntry::active() const
1127 {
1128- return (!mAccount.isNull() &&
1129- !mAccount->connection().isNull() &&
1130- !mAccount->connection()->selfContact().isNull() &&
1131- mAccount->connection()->selfContact()->presence().type() != Tp::ConnectionPresenceTypeOffline);
1132+ if (mAccount.isNull() || mAccount->connection().isNull() || mAccount->connection()->status() != Tp::ConnectionStatusConnected) {
1133+ return false;
1134+ }
1135+
1136+ // we have to check if the account supports simple presence. In case it does, we use the self contact presence to determine
1137+ // if this account is active.
1138+ if (mAccount->connection()->hasInterface(TP_QT_IFACE_CONNECTION_INTERFACE_SIMPLE_PRESENCE)) {
1139+ return (!mAccount->connection()->selfContact().isNull() &&
1140+ mAccount->connection()->selfContact()->presence().type() != Tp::ConnectionPresenceTypeOffline);
1141+ }
1142+
1143+ // if it doesn't support simple presence, we consider it online by having a connection in connected state
1144+ return true;
1145 }
1146
1147 QString AccountEntry::displayName() const
1148
1149=== modified file 'libtelephonyservice/callentry.cpp'
1150--- libtelephonyservice/callentry.cpp 2015-06-09 21:59:29 +0000
1151+++ libtelephonyservice/callentry.cpp 2016-12-17 13:33:18 +0000
1152@@ -281,11 +281,15 @@
1153
1154 bool CallEntry::incoming() const
1155 {
1156- if (!mAccount) {
1157- return false;
1158+ bool isIncoming = !mChannel->isRequested();
1159+
1160+ if (mAccount &&
1161+ !mChannel->initiatorContact().isNull() &&
1162+ mChannel->initiatorContact() != mAccount->account()->connection()->selfContact()) {
1163+ isIncoming = true;
1164 }
1165
1166- return mChannel->initiatorContact() != mAccount->account()->connection()->selfContact();
1167+ return isIncoming;
1168 }
1169
1170 bool CallEntry::ringing() const
1171@@ -428,10 +432,18 @@
1172 {
1173 QDBusInterface *phoneAppHandler = TelepathyHelper::instance()->handlerInterface();
1174 phoneAppHandler->call("SetMuted", mChannel->objectPath(), value);
1175+
1176+ // FIXME: maybe we should retrieve the property from the handler instead of relying on telepathy
1177+ // for that, because on channels that are not using hardware streaming we handle the mute internally
1178+ // with no participation of the Telepathy mute interface
1179+ if (mChannel->handlerStreamingRequired()) {
1180+ onMutedChanged(value ? 1 : 0);
1181+ }
1182 }
1183
1184 void CallEntry::onCallStateChanged(Tp::CallState state)
1185 {
1186+ qDebug() << __PRETTY_FUNCTION__ << state;
1187 // fetch the channel properties from the handler
1188 updateChannelProperties();
1189
1190
1191=== modified file 'libtelephonyservice/callentry.h'
1192--- libtelephonyservice/callentry.h 2015-03-04 18:02:13 +0000
1193+++ libtelephonyservice/callentry.h 2016-12-17 13:33:18 +0000
1194@@ -46,7 +46,7 @@
1195 READ isVoicemail
1196 WRITE setVoicemail
1197 NOTIFY voicemailChanged)
1198- Q_PROPERTY(AccountEntry *account READ account)
1199+ Q_PROPERTY(AccountEntry *account READ account CONSTANT)
1200
1201 // FIXME: replace this by a more generic identifier to support accounts not based on phone numbers
1202 // this property is only filled for 1-1 calls
1203
1204=== modified file 'libtelephonyservice/tonegenerator.cpp'
1205--- libtelephonyservice/tonegenerator.cpp 2015-04-16 21:39:16 +0000
1206+++ libtelephonyservice/tonegenerator.cpp 2016-12-17 13:33:18 +0000
1207@@ -69,6 +69,7 @@
1208
1209 void ToneGenerator::playDTMFTone(uint key)
1210 {
1211+ qDebug() << __PRETTY_FUNCTION__ << key;
1212 if (key > 11) {
1213 qDebug() << "Invalid DTMF tone, ignore.";
1214 return;
1215@@ -124,3 +125,13 @@
1216 startEventTone(CALL_ENDED_TONE);
1217 QTimer::singleShot(2000, this, SLOT(stopTone()));
1218 }
1219+
1220+void ToneGenerator::playDialingTone()
1221+{
1222+ startEventTone(DIALING_TONE);
1223+}
1224+
1225+void ToneGenerator::playRingingTone()
1226+{
1227+ startEventTone(RINGING_TONE);
1228+}
1229
1230=== modified file 'libtelephonyservice/tonegenerator.h'
1231--- libtelephonyservice/tonegenerator.h 2015-04-16 21:39:16 +0000
1232+++ libtelephonyservice/tonegenerator.h 2016-12-17 13:33:18 +0000
1233@@ -31,6 +31,8 @@
1234 static const int WAITING_PLAYBACK_DURATION = 8000; /* in milliseconds */
1235 static const uint WAITING_TONE = 79;
1236 static const uint CALL_ENDED_TONE = 257;
1237+static const uint DIALING_TONE = 66;
1238+static const uint RINGING_TONE = 70;
1239
1240 class ToneGenerator : public QObject
1241 {
1242@@ -47,9 +49,11 @@
1243 void playWaitingTone();
1244 void stopWaitingTone();
1245 void playCallEndedTone();
1246+ void playDialingTone();
1247+ void playRingingTone();
1248+ void stopTone();
1249
1250 private Q_SLOTS:
1251- void stopTone();
1252 void stopDTMFTone();
1253 bool startEventTone(uint key);
1254
1255
1256=== added file 'protocols/sip.protocol'
1257--- protocols/sip.protocol 1970-01-01 00:00:00 +0000
1258+++ protocols/sip.protocol 2016-12-17 13:33:18 +0000
1259@@ -0,0 +1,7 @@
1260+[Protocol]
1261+Name=sip
1262+Features=voice
1263+FallbackProtocol=
1264+BackgroundImage=/usr/share/telephony-service/assets/message_watermark.png
1265+ShowOnSelector=1
1266+ServiceDisplayName=SIP

Subscribers

People subscribed via source and target branches