~ubuntu-branches/ubuntu/vivid/media-hub/vivid-updates

« back to all changes in this revision

Viewing changes to src/core/media/call-monitor/call_monitor.cpp

  • Committer: Package Import Robot
  • Author(s): CI Train Bot, Thomas Voss, CI Train Bot, Jim Hodapp, Ricardo Mendoza, Ricardo Salveti de Araujo, thomas-voss
  • Date: 2015-03-20 13:16:48 UTC
  • mfrom: (1.1.34)
  • Revision ID: package-import@ubuntu.com-20150320131648-dv8aynyyjib9v2sr
Tags: 3.0.0+15.04.20150320-0ubuntu1
[ Thomas Voss ]
* Refactor client-facing interfaces to pull out explicit dependency on hybris-based media layer.

[ CI Train Bot ]
* New rebuild forced.

[ Jim Hodapp ]
* Disconnect playback_status_changed_signal in ~Private() to avoid a
  deadlock.
* Prevent a 0 position from being reported to the app which happens
  while seeking. Covers bad behavior that happens from GStreamer. Also
  expose the about_to_finish signal to the client. Enable playback
  again after manually seeking all the way to EOS. Also only send
  VideoDimensionsChanged signal only when necessary.

[ Ricardo Mendoza ]
* Add an interface apparmor::ubuntu::RequestAuthenticator that is used
  to authenticate incoming open uri requests. Add an interface
  apparmor::ubuntu::RequestContextResolver that is used to resolve a
  dbus name to an apparmor::ubuntu::Context. Provide an implementation
  apparmor::ubuntu::ExistingAuthenticator that takes the impl. from
  player_skeleton.cpp and uses it to implement the interface. Provide
  an implementation apparmor::ubuntu::RequestContextResolver that
  reaches out to the dbus daemon to resolve a given bus name to an
  apparmor profile. Remove obsolete query for the apparmor profile in
  ServiceSkeleton. Adjust the implementation in media::PlayerSkeleton
  to rely on Request{Authenticator, ContextResolver}. removed:
  src/core/media/apparmor.h added: src/core/media/apparmor/
  src/core/media/apparmor/context.cpp
  src/core/media/apparmor/context.h src/core/media/apparmor/dbus.h
  src/core/media/apparmor/ubuntu.cpp src/core/media/apparmor/ubuntu.h
* Introduce an interface media::audio::OutputObserver that allows the
  core classes to observer the state of external audio outputs
  (headphones/headsets). Provide an implementation of
  media::audio::OutputObserver that relies on Pulseaudio to monitor
  the availability of ports on the default sink. Adjust
  media::ServiceImplementation to use media::audio::OutputObserver,
  defaulting to media::audio::PulseAudioOutputObserver.
* Migrate all Player DBus methods to use transact_method() instead of
  invoke_method_synchronously(), to prevent bus executor deadlocks.

[ Ricardo Salveti de Araujo ]
* Add an interface apparmor::ubuntu::RequestAuthenticator that is used
  to authenticate incoming open uri requests. Add an interface
  apparmor::ubuntu::RequestContextResolver that is used to resolve a
  dbus name to an apparmor::ubuntu::Context. Provide an implementation
  apparmor::ubuntu::ExistingAuthenticator that takes the impl. from
  player_skeleton.cpp and uses it to implement the interface. Provide
  an implementation apparmor::ubuntu::RequestContextResolver that
  reaches out to the dbus daemon to resolve a given bus name to an
  apparmor profile. Remove obsolete query for the apparmor profile in
  ServiceSkeleton. Adjust the implementation in media::PlayerSkeleton
  to rely on Request{Authenticator, ContextResolver}. removed:
  src/core/media/apparmor.h added: src/core/media/apparmor/
  src/core/media/apparmor/context.cpp
  src/core/media/apparmor/context.h src/core/media/apparmor/dbus.h
  src/core/media/apparmor/ubuntu.cpp src/core/media/apparmor/ubuntu.h
* Move src/core/media/call-monitor to src/core/media/telephony.
  Introduce a proper interface media::telephony::CallMonitor. Slightly
  adjust existing implementation based on Qt. Adjust
  media::ServiceImplementation to account for changes in
  media::telephony::CallMonitor.

[ thomas-voss ]
* Add an interface apparmor::ubuntu::RequestAuthenticator that is used
  to authenticate incoming open uri requests. Add an interface
  apparmor::ubuntu::RequestContextResolver that is used to resolve a
  dbus name to an apparmor::ubuntu::Context. Provide an implementation
  apparmor::ubuntu::ExistingAuthenticator that takes the impl. from
  player_skeleton.cpp and uses it to implement the interface. Provide
  an implementation apparmor::ubuntu::RequestContextResolver that
  reaches out to the dbus daemon to resolve a given bus name to an
  apparmor profile. Remove obsolete query for the apparmor profile in
  ServiceSkeleton. Adjust the implementation in media::PlayerSkeleton
  to rely on Request{Authenticator, ContextResolver}. removed:
  src/core/media/apparmor.h added: src/core/media/apparmor/
  src/core/media/apparmor/context.cpp
  src/core/media/apparmor/context.h src/core/media/apparmor/dbus.h
  src/core/media/apparmor/ubuntu.cpp src/core/media/apparmor/ubuntu.h
* Add an interface media::ClientDeathObserver that abstracts away
  receiving key-based death notifications for clients associated to
  media::Player instances server-side Provide an implementation
  media::HybrisClientDeathObserver that relies on hybris and
  ultimately on Android's onBinderDied to receive death notifications.
  Adjust media::PlayerStub and media::PlayerImplementation to account
  for the new interface. Adjust the CMake setup for tests to link
  media-hub-service instead of recompiling large parts of the
  implementation classes.
* Decouple PlayerSkeleton and PlayerImplementation by making
  PlayerImplementation being able to inherit from arbitrary base
  classes, as long as they provide the set of properties and signals
  defined by media::Player.
* Decouple the ServiceSkeleton from the ServiceImplementation by
  introducing a common interface media::KeyedPlayerStore for storing
  running Player sessions indexed by the Player::Key. Provide a
  default implementation HashedKeyedPlayerStore relying on a hash map
  for keeping track of player instances. Adjust implementation to
  account for ServiceImplementation no longer inheriting from
  ServiceSkeleton.
* Introduce a common class media::helper::ExternalHelpers that
  provides a convenient way to:
* Introduce an interface media::RecorderObserver that allows the core
  classes to monitor the overall state of the system. Provide an
  implementation of media::RecorderObserver relying on Hybris to
  interface with the Android side. Adjust the ServiceImplementation to
  connect to the platform-default media::RecorderObserver.
* Introduce an interface media::audio::OutputObserver that allows the
  core classes to observer the state of external audio outputs
  (headphones/headsets). Provide an implementation of
  media::audio::OutputObserver that relies on Pulseaudio to monitor
  the availability of ports on the default sink. Adjust
  media::ServiceImplementation to use media::audio::OutputObserver,
  defaulting to media::audio::PulseAudioOutputObserver.
* Introduce an interface media::power::BatteryObserver to monitor the
  current battery level of the system. The core reacts to low/very low
  battery levels by pausing all multimedia playback sessions and
  resumes them whenever the user has been notified of the critical
  battery level. Provide an implementation of
  media::power::BatteryObserver using
  com.canonical.indicator.power.Battery. Adjust
  media::ServiceImplementation to use media::power::BatteryObserver.
* Move gstreamer::Playbin implementation to its own cpp file, thus
  internalizing the Hybris setup portions. Make sure that media-hub-
  service knows about
  media::Player::Error::OutOfProcessBufferStreamingNotSupported by
  linking with media-hub-client.
* Move src/core/media/call-monitor to src/core/media/telephony.
  Introduce a proper interface media::telephony::CallMonitor. Slightly
  adjust existing implementation based on Qt. Adjust
  media::ServiceImplementation to account for changes in
  media::telephony::CallMonitor.
* Replace home-grown mask type for the video size with a std::tuple,
  i.e., media::video::Dimensions. Introduce a simple TaggedInteger
  class to distinguish between Width, Height and other dimensions.
  Adjust interfaces of media::Player to rely on the new type. Adjust
  implementation classes to account for interface changes. Adjust
  Codec implementation for sending the tagged integer via the bus.
  Adjust gstreamer::Engine and gstreamer::Playbin to hand out the
  correct types.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Copyright (C) 2014 Canonical Ltd
3
 
 *
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.
7
 
 *
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.
12
 
 *
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/>.
15
 
 *
16
 
 *      Author: Justin McPherson <justin.mcpherson@canonical.com>
17
 
 */
18
 
 
19
 
 
20
 
#include "call_monitor.h"
21
 
 
22
 
#include "qtbridge.h"
23
 
#include <TelepathyQt/AccountManager>
24
 
#include <TelepathyQt/SimpleCallObserver>
25
 
#include <TelepathyQt/PendingOperation>
26
 
#include <TelepathyQt/PendingReady>
27
 
#include <TelepathyQt/PendingAccount>
28
 
 
29
 
#include <list>
30
 
#include <mutex>
31
 
 
32
 
 
33
 
namespace {
34
 
class TelepathyCallMonitor : public QObject
35
 
{
36
 
    Q_OBJECT
37
 
public:
38
 
    TelepathyCallMonitor(const Tp::AccountPtr& account):
39
 
        mAccount(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()));
45
 
    }
46
 
 
47
 
Q_SIGNALS:
48
 
    void offHook();
49
 
    void onHook();
50
 
 
51
 
private:
52
 
    Tp::AccountPtr mAccount;
53
 
    Tp::SimpleCallObserverPtr mCallObserver;
54
 
};
55
 
 
56
 
 
57
 
class TelepathyBridge : public QObject
58
 
{
59
 
    Q_OBJECT
60
 
public:
61
 
    TelepathyBridge():
62
 
        QObject(0) {
63
 
        Tp::registerTypes();
64
 
 
65
 
        QTimer::singleShot(0, this, SLOT(accountManagerSetup()));
66
 
    }
67
 
 
68
 
    ~TelepathyBridge() {
69
 
        for (std::list<TelepathyCallMonitor*>::iterator it = mCallMonitors.begin();
70
 
            it != mCallMonitors.end();
71
 
            ++it) {
72
 
            delete *it;
73
 
        }
74
 
    }
75
 
 
76
 
    void on_change(const std::function<void(CallMonitor::State)>& func) {
77
 
        std::lock_guard<std::mutex> l(cb_lock);
78
 
        cb = func;
79
 
    }
80
 
 
81
 
private Q_SLOTS:
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*)));
90
 
    }
91
 
 
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
96
 
            return;
97
 
        }
98
 
 
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*)));
103
 
        }
104
 
 
105
 
        connect(mAccountManager.data(), SIGNAL(newAccount(Tp::AccountPtr)), SLOT(newAccount(Tp::AccountPtr)));
106
 
    }
107
 
 
108
 
    void newAccount(const Tp::AccountPtr& account)
109
 
    {
110
 
        connect(account->becomeReady(Tp::Account::FeatureCapabilities),
111
 
                SIGNAL(finished(Tp::PendingOperation*)),
112
 
                SLOT(accountReady(Tp::PendingOperation*)));
113
 
    }
114
 
 
115
 
    void accountReady(Tp::PendingOperation* operation) {
116
 
        if (operation->isError()) {
117
 
            std::cerr << "TelepathyAccount: Operation failed (accountReady)" << std::endl;
118
 
            return;
119
 
        }
120
 
 
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;
124
 
            return;
125
 
        }
126
 
 
127
 
        checkAndAddAccount(Tp::AccountPtr::qObjectCast(pendingReady->proxy()));
128
 
    }
129
 
 
130
 
    void offHook()
131
 
    {
132
 
        std::lock_guard<std::mutex> l(cb_lock);
133
 
        if (cb)
134
 
            cb(CallMonitor::OffHook);
135
 
    }
136
 
 
137
 
    void onHook()
138
 
    {
139
 
        std::lock_guard<std::mutex> l(cb_lock);
140
 
        if (cb)
141
 
            cb(CallMonitor::OnHook);
142
 
    }
143
 
 
144
 
private:
145
 
    std::mutex cb_lock;
146
 
    std::function<void (CallMonitor::State)>   cb;
147
 
    Tp::AccountManagerPtr mAccountManager;
148
 
    std::list<TelepathyCallMonitor*> mCallMonitors;
149
 
 
150
 
    void checkAndAddAccount(const Tp::AccountPtr& account)
151
 
    {
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);
160
 
    }
161
 
};
162
 
}
163
 
 
164
 
class CallMonitorPrivate
165
 
{
166
 
public:
167
 
    CallMonitorPrivate() {
168
 
        mBridge = nullptr;
169
 
        try {
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();
175
 
                        cv.notify_all();
176
 
                    });
177
 
                });
178
 
            }).detach();
179
 
        } catch(const std::system_error& error) {
180
 
            std::cerr << "exception(std::system_error) in CallMonitor thread start" << error.what() << std::endl;
181
 
        } catch(...) {
182
 
            std::cerr << "exception(...) in CallMonitor thread start" << std::endl;
183
 
        }
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));
187
 
    }
188
 
 
189
 
    ~CallMonitorPrivate() {
190
 
        qt::core::world::destroy();
191
 
    }
192
 
 
193
 
    TelepathyBridge *mBridge;
194
 
 
195
 
private:
196
 
    std::mutex mtx;
197
 
    std::condition_variable cv;
198
 
};
199
 
 
200
 
 
201
 
CallMonitor::CallMonitor():
202
 
    d(new CallMonitorPrivate)
203
 
{
204
 
}
205
 
 
206
 
CallMonitor::~CallMonitor()
207
 
{
208
 
    delete d->mBridge;
209
 
    delete d;
210
 
}
211
 
 
212
 
void CallMonitor::on_change(const std::function<void(CallMonitor::State)>& func)
213
 
{
214
 
    if (d->mBridge != nullptr) {
215
 
        std::cout << "CallMonitor: Setting up callback for TelepathyBridge on_change" << std::endl;
216
 
        d->mBridge->on_change(func);
217
 
    } else
218
 
        std::cerr << "TelepathyBridge: Failed to hook on_change signal, bridge not yet set" << std::endl;
219
 
}
220
 
 
221
 
#include "call_monitor.moc"
222