Music Hub ..
A session-wide music playback service
 
Loading...
Searching...
No Matches
call_monitor.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2014 Canonical Ltd
3 * Copyright © 2022 UBports Foundation.
4 *
5 * Contact: Alberto Mardegan <mardy@users.sourceforge.net>
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License version 3 as
9 * published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 * Author: Justin McPherson <justin.mcpherson@canonical.com>
20 */
21
22
23#include "call_monitor.h"
24
25#include "logging.h"
26
27#include <TelepathyQt/AccountManager>
28#include <TelepathyQt/SimpleCallObserver>
29#include <TelepathyQt/PendingOperation>
30#include <TelepathyQt/PendingReady>
31#include <TelepathyQt/PendingAccount>
32
34
35using namespace media::telephony;
36
37namespace lomiri {
38namespace MediaHubService {
39
41{
42 Q_OBJECT
43public:
44 TelepathyCallMonitor(const Tp::AccountPtr& account):
45 mAccount(account),
46 mCallObserver(Tp::SimpleCallObserver::create(mAccount)) {
47 connect(mCallObserver.data(), SIGNAL(callStarted(Tp::CallChannelPtr)), SIGNAL(offHook()));
48 connect(mCallObserver.data(), SIGNAL(callEnded(Tp::CallChannelPtr,QString,QString)), SIGNAL(onHook()));
49 connect(mCallObserver.data(), SIGNAL(streamedMediaCallStarted(Tp::StreamedMediaChannelPtr)), SIGNAL(offHook()));
50 connect(mCallObserver.data(), SIGNAL(streamedMediaCallEnded(Tp::StreamedMediaChannelPtr,QString,QString)), SIGNAL(onHook()));
51 }
52
53Q_SIGNALS:
54 void offHook();
55 void onHook();
56
57private:
58 Tp::AccountPtr mAccount;
59 Tp::SimpleCallObserverPtr mCallObserver;
60};
61
62namespace telephony {
63
64class CallMonitorPrivate: public QObject
65{
66 Q_OBJECT
67 Q_DECLARE_PUBLIC(CallMonitor)
68
69public:
70 CallMonitorPrivate(CallMonitor *q):
71 QObject(0),
72 m_callState(CallMonitor::State::OffHook),
73 q_ptr(q)
74 {
75 Tp::registerTypes();
76
77 QTimer::singleShot(0, this, SLOT(accountManagerSetup()));
78 }
79
80 ~CallMonitorPrivate() {
81 for (std::list<TelepathyCallMonitor*>::iterator it = mCallMonitors.begin();
82 it != mCallMonitors.end();
83 ++it) {
84 delete *it;
85 }
86 }
87
88private Q_SLOTS:
89 void accountManagerSetup() {
90 mAccountManager = Tp::AccountManager::create(Tp::AccountFactory::create(QDBusConnection::sessionBus(),
91 Tp::Account::FeatureCore),
92 Tp::ConnectionFactory::create(QDBusConnection::sessionBus(),
93 Tp::Connection::FeatureCore));
94 connect(mAccountManager->becomeReady(),
95 SIGNAL(finished(Tp::PendingOperation*)),
96 SLOT(accountManagerReady(Tp::PendingOperation*)));
97 }
98
99 void accountManagerReady(Tp::PendingOperation* operation) {
100 static uint8_t retries = 0;
101 if (operation->isError()) {
102 MH_ERROR("TelepathyBridge: Operation failed (accountManagerReady)");
103 if (retries < 10) {
104 QTimer::singleShot(1000, this, SLOT(accountManagerSetup())); // again
105 ++retries;
106 }
107 return;
108 }
109
110 Q_FOREACH(const Tp::AccountPtr& account, mAccountManager->allAccounts()) {
111 connect(account->becomeReady(Tp::Account::FeatureCapabilities),
112 SIGNAL(finished(Tp::PendingOperation*)),
113 SLOT(accountReady(Tp::PendingOperation*)));
114 }
115
116 connect(mAccountManager.data(), SIGNAL(newAccount(Tp::AccountPtr)), SLOT(newAccount(Tp::AccountPtr)));
117 }
118
119 void newAccount(const Tp::AccountPtr& account)
120 {
121 connect(account->becomeReady(Tp::Account::FeatureCapabilities),
122 SIGNAL(finished(Tp::PendingOperation*)),
123 SLOT(accountReady(Tp::PendingOperation*)));
124 }
125
126 void accountReady(Tp::PendingOperation* operation) {
127 if (operation->isError()) {
128 MH_ERROR("TelepathyAccount: Operation failed (accountReady)");
129 return;
130 }
131
132 Tp::PendingReady* pendingReady = qobject_cast<Tp::PendingReady*>(operation);
133 if (pendingReady == 0) {
134 MH_ERROR("Rejecting account because could not understand ready status");
135 return;
136 }
137
138 checkAndAddAccount(Tp::AccountPtr::qObjectCast(pendingReady->proxy()));
139 }
140
141 void offHook()
142 {
143 Q_Q(CallMonitor);
144 m_callState = media::telephony::CallMonitor::State::OffHook;
145 Q_EMIT q->callStateChanged();
146 }
147
148 void onHook()
149 {
150 Q_Q(CallMonitor);
151 m_callState = media::telephony::CallMonitor::State::OnHook;
152 Q_EMIT q->callStateChanged();
153 }
154
155private:
156 Tp::AccountManagerPtr mAccountManager;
157 std::list<TelepathyCallMonitor*> mCallMonitors;
158 media::telephony::CallMonitor::State m_callState;
159 CallMonitor *q_ptr;
160
161 void checkAndAddAccount(const Tp::AccountPtr& account)
162 {
163 Tp::ConnectionCapabilities caps = account->capabilities();
164 // TODO: Later on we will need to filter for the right capabilities, and also allow dynamic account detection
165 // Don't check caps for now as a workaround for https://bugs.launchpad.net/ubuntu/+source/media-hub/+bug/1409125
166 // at least until we are able to find out the root cause of it (check rev 107 for the caps check)
167 auto tcm = new TelepathyCallMonitor(account);
168 connect(tcm, SIGNAL(offHook()), SLOT(offHook()));
169 connect(tcm, SIGNAL(onHook()), SLOT(onHook()));
170 mCallMonitors.push_back(tcm);
171 }
172};
173
174} // namespace
175}} // namespace
176
177CallMonitor::CallMonitor(QObject *parent):
178 QObject(parent),
179 d_ptr(new CallMonitorPrivate(this))
180{
181}
182
183CallMonitor::~CallMonitor() = default;
184
186{
187 Q_D(const CallMonitor);
188 return d->m_callState;
189}
190
191#include "call_monitor.moc"
192
TelepathyCallMonitor(const Tp::AccountPtr &account)
#define MH_ERROR(...)
Definition logging.h:41