Music Hub  ..
A session-wide music playback service
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 
33 namespace media = lomiri::MediaHubService;
34 
35 using namespace media::telephony;
36 
37 namespace lomiri {
38 namespace MediaHubService {
39 
41 {
42  Q_OBJECT
43 public:
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 
53 Q_SIGNALS:
54  void offHook();
55  void onHook();
56 
57 private:
58  Tp::AccountPtr mAccount;
59  Tp::SimpleCallObserverPtr mCallObserver;
60 };
61 
62 namespace telephony {
63 
65 {
66  Q_OBJECT
67  Q_DECLARE_PUBLIC(CallMonitor)
68 
69 public:
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 
81  for (std::list<TelepathyCallMonitor*>::iterator it = mCallMonitors.begin();
82  it != mCallMonitors.end();
83  ++it) {
84  delete *it;
85  }
86  }
87 
88 private 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 
155 private:
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 
177 CallMonitor::CallMonitor(QObject *parent):
178  QObject(parent),
179  d_ptr(new CallMonitorPrivate(this))
180 {
181 }
182 
183 CallMonitor::~CallMonitor() = default;
184 
186 {
187  Q_D(const CallMonitor);
188  return d->m_callState;
189 }
190 
191 #include "call_monitor.moc"
192 
QObject
lomiri::MediaHubService::telephony::CallMonitor
Definition: call_monitor.h:38
lomiri::MediaHubService::telephony::CallMonitorPrivate::~CallMonitorPrivate
~CallMonitorPrivate()
Definition: call_monitor.cpp:80
lomiri::MediaHubService::TelepathyCallMonitor::TelepathyCallMonitor
TelepathyCallMonitor(const Tp::AccountPtr &account)
Definition: call_monitor.cpp:44
lomiri::MediaHubService::telephony::CallMonitor::callState
State callState() const
Definition: call_monitor.cpp:185
call_monitor.h
lomiri::MediaHubService::telephony::CallMonitor::State
State
Definition: call_monitor.h:44
lomiri::MediaHubService::telephony::CallMonitor::~CallMonitor
virtual ~CallMonitor()
MH_ERROR
#define MH_ERROR(...)
Definition: logging.h:41
lomiri::MediaHubService::telephony::CallMonitorPrivate
Definition: call_monitor.cpp:64
lomiri::MediaHubService
Definition: context.h:28
lomiri::MediaHubService::telephony::CallMonitorPrivate::CallMonitorPrivate
CallMonitorPrivate(CallMonitor *q)
Definition: call_monitor.cpp:70
lomiri::MediaHubService::TelepathyCallMonitor
Definition: call_monitor.cpp:40
lomiri
Definition: dbus_utils.h:24