2
* Copyright (C) 2014 Canonical Ltd
4
* This program is free software: you can redistribute it and/or modify
5
* it under the terms of the GNU Lesser General Public License version 3 as
6
* published by the Free Software Foundation.
8
* This program is distributed in the hope that it will be useful,
9
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
* GNU Lesser General Public License for more details.
13
* You should have received a copy of the GNU Lesser General Public License
14
* along with this program. If not, see <http://www.gnu.org/licenses/>.
16
* Author: Justin McPherson <justin.mcpherson@canonical.com>
20
#include "call_monitor.h"
23
#include <TelepathyQt/AccountManager>
24
#include <TelepathyQt/SimpleCallObserver>
25
#include <TelepathyQt/PendingOperation>
26
#include <TelepathyQt/PendingReady>
27
#include <TelepathyQt/PendingAccount>
34
class TelepathyCallMonitor : public QObject
38
TelepathyCallMonitor(const Tp::AccountPtr& account):
40
mCallObserver(Tp::SimpleCallObserver::create(mAccount)) {
41
connect(mCallObserver.data(), SIGNAL(callStarted(Tp::CallChannelPtr)), SIGNAL(offHook()));
42
connect(mCallObserver.data(), SIGNAL(callEnded(Tp::CallChannelPtr,QString,QString)), SIGNAL(onHook()));
43
connect(mCallObserver.data(), SIGNAL(streamedMediaCallStarted(Tp::StreamedMediaChannelPtr)), SIGNAL(offHook()));
44
connect(mCallObserver.data(), SIGNAL(streamedMediaCallEnded(Tp::StreamedMediaChannelPtr,QString,QString)), SIGNAL(onHook()));
52
Tp::AccountPtr mAccount;
53
Tp::SimpleCallObserverPtr mCallObserver;
57
class TelepathyBridge : public QObject
65
QTimer::singleShot(0, this, SLOT(accountManagerSetup()));
69
for (std::list<TelepathyCallMonitor*>::iterator it = mCallMonitors.begin();
70
it != mCallMonitors.end();
76
void on_change(const std::function<void(CallMonitor::State)>& func) {
77
std::lock_guard<std::mutex> l(cb_lock);
82
void accountManagerSetup() {
83
mAccountManager = Tp::AccountManager::create(Tp::AccountFactory::create(QDBusConnection::sessionBus(),
84
Tp::Account::FeatureCore),
85
Tp::ConnectionFactory::create(QDBusConnection::sessionBus(),
86
Tp::Connection::FeatureCore));
87
connect(mAccountManager->becomeReady(),
88
SIGNAL(finished(Tp::PendingOperation*)),
89
SLOT(accountManagerReady(Tp::PendingOperation*)));
92
void accountManagerReady(Tp::PendingOperation* operation) {
93
if (operation->isError()) {
94
std::cerr << "TelepathyBridge: Operation failed (accountManagerReady)" << std::endl;
95
QTimer::singleShot(1000, this, SLOT(accountManagerSetup())); // again
99
Q_FOREACH(const Tp::AccountPtr& account, mAccountManager->allAccounts()) {
100
connect(account->becomeReady(Tp::Account::FeatureCapabilities),
101
SIGNAL(finished(Tp::PendingOperation*)),
102
SLOT(accountReady(Tp::PendingOperation*)));
105
connect(mAccountManager.data(), SIGNAL(newAccount(Tp::AccountPtr)), SLOT(newAccount(Tp::AccountPtr)));
108
void newAccount(const Tp::AccountPtr& account)
110
connect(account->becomeReady(Tp::Account::FeatureCapabilities),
111
SIGNAL(finished(Tp::PendingOperation*)),
112
SLOT(accountReady(Tp::PendingOperation*)));
115
void accountReady(Tp::PendingOperation* operation) {
116
if (operation->isError()) {
117
std::cerr << "TelepathyAccount: Operation failed (accountReady)" << std::endl;
121
Tp::PendingReady* pendingReady = qobject_cast<Tp::PendingReady*>(operation);
122
if (pendingReady == 0) {
123
std::cerr << "Rejecting account because could not understand ready status" << std::endl;
127
checkAndAddAccount(Tp::AccountPtr::qObjectCast(pendingReady->proxy()));
132
std::lock_guard<std::mutex> l(cb_lock);
134
cb(CallMonitor::OffHook);
139
std::lock_guard<std::mutex> l(cb_lock);
141
cb(CallMonitor::OnHook);
146
std::function<void (CallMonitor::State)> cb;
147
Tp::AccountManagerPtr mAccountManager;
148
std::list<TelepathyCallMonitor*> mCallMonitors;
150
void checkAndAddAccount(const Tp::AccountPtr& account)
152
Tp::ConnectionCapabilities caps = account->capabilities();
153
// TODO: Later on we will need to filter for the right capabilities, and also allow dynamic account detection
154
// Don't check caps for now as a workaround for https://bugs.launchpad.net/ubuntu/+source/media-hub/+bug/1409125
155
// at least until we are able to find out the root cause of it (check rev 107 for the caps check)
156
auto tcm = new TelepathyCallMonitor(account);
157
connect(tcm, SIGNAL(offHook()), SLOT(offHook()));
158
connect(tcm, SIGNAL(onHook()), SLOT(onHook()));
159
mCallMonitors.push_back(tcm);
164
class CallMonitorPrivate
167
CallMonitorPrivate() {
170
std::thread([this]() {
171
qt::core::world::build_and_run(0, nullptr, [this]() {
172
qt::core::world::enter_with_task([this]() {
173
std::cout << "CallMonitor: Creating TelepathyBridge" << std::endl;
174
mBridge = new TelepathyBridge();
179
} catch(const std::system_error& error) {
180
std::cerr << "exception(std::system_error) in CallMonitor thread start" << error.what() << std::endl;
182
std::cerr << "exception(...) in CallMonitor thread start" << std::endl;
184
// Wait until telepathy bridge is set, so we can hook up the change signals
185
std::unique_lock<std::mutex> lck(mtx);
186
cv.wait_for(lck, std::chrono::seconds(3));
189
~CallMonitorPrivate() {
190
qt::core::world::destroy();
193
TelepathyBridge *mBridge;
197
std::condition_variable cv;
201
CallMonitor::CallMonitor():
202
d(new CallMonitorPrivate)
206
CallMonitor::~CallMonitor()
212
void CallMonitor::on_change(const std::function<void(CallMonitor::State)>& func)
214
if (d->mBridge != nullptr) {
215
std::cout << "CallMonitor: Setting up callback for TelepathyBridge on_change" << std::endl;
216
d->mBridge->on_change(func);
218
std::cerr << "TelepathyBridge: Failed to hook on_change signal, bridge not yet set" << std::endl;
221
#include "call_monitor.moc"