dbusclient.cpp 10.5 KB
Newer Older
1
/*
2
 *  Copyright (C) 2014-2015 Savoir-Faire Linux Inc.
3
 *  Author: Philippe Proulx <philippe.proulx@savoirfairelinux.com>
4
 *  Author: Guillaume Roguez <Guillaume.Roguez@savoirfairelinux.com>
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
 *
 *  Additional permission under GNU GPL version 3 section 7:
 *
 *  If you modify this program, or any covered work, by linking or
 *  combining it with the OpenSSL project's OpenSSL library (or a
 *  modified version of that library), containing parts covered by the
 *  terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
 *  grants you additional permission to convey the resulting work.
 *  Corresponding Source for a non-source form of such a combination
 *  shall include the source code for the parts of OpenSSL used as well
 *  as that of the covered work.
 */
Guillaume Roguez's avatar
Guillaume Roguez committed
31 32 33

#ifdef HAVE_CONFIG_H
#include "config.h"
Guillaume Roguez's avatar
Guillaume Roguez committed
34
#endif // HAVE_CONFIG_H
Guillaume Roguez's avatar
Guillaume Roguez committed
35

36 37 38 39 40 41 42 43 44
#include <cstdlib>
#include <iostream>
#include <cstring>
#include <stdexcept>

#include "dbusclient.h"
#include "dbus_cpp.h"

#include "dbusinstance.h"
45 46

#include "callmanager_interface.h"
47
#include "dbuscallmanager.h"
48

49
#include "dbusconfigurationmanager.h"
50 51
#include "configurationmanager_interface.h"

52
#include "dbuspresencemanager.h"
53
#include "presencemanager_interface.h"
54

Adrien Béraud's avatar
Adrien Béraud committed
55
#ifdef RING_VIDEO
56
#include "dbusvideomanager.h"
57
#include "videomanager_interface.h"
58 59
#endif

60 61
class EventCallback :
    public DBus::Callback_Base<void, DBus::DefaultTimeout&>
62
{
63 64 65 66
    public:
        EventCallback(const std::function<void()>&& func)
            : callback_ {std::forward<const std::function<void()>>(func)}
            {}
67

68 69 70
        void call(DBus::DefaultTimeout&) const {
            callback_();
        }
71

72 73
    private:
        const std::function<void()> callback_;
74 75
};

76
DBusClient::DBusClient(int flags, bool persistent)
77
    : dispatcher_(new DBus::BusDispatcher)
78 79 80
{
    try {
        DBus::_init_threading();
81
        DBus::default_dispatcher = dispatcher_.get();
82 83 84

        // timeout and expired are deleted internally by dispatcher_'s
        // destructor, so we must NOT delete them ourselves.
85 86
        timeout_.reset(new DBus::DefaultTimeout {10 /* ms */, true, dispatcher_.get()});
        // Poll for Deamon events
Guillaume Roguez's avatar
Guillaume Roguez committed
87
        timeout_->expired = new EventCallback {DRing::pollEvents};
88

89
        DBus::Connection sessionConnection {DBus::Connection::SessionBus()};
Adrien Béraud's avatar
Adrien Béraud committed
90
        sessionConnection.request_name("cx.ring.Ring");
91

92 93 94
        callManager_.reset(new DBusCallManager {sessionConnection});
        configurationManager_.reset(new DBusConfigurationManager {sessionConnection});
        presenceManager_.reset(new DBusPresenceManager {sessionConnection});
95 96

        DBusInstance::OnNoMoreClientFunc onNoMoreClientFunc;
97 98
        if (!persistent)
            onNoMoreClientFunc = [this] {this->exit();};
99

100
        instanceManager_.reset(new DBusInstance {sessionConnection, onNoMoreClientFunc});
101

Adrien Béraud's avatar
Adrien Béraud committed
102
#ifdef RING_VIDEO
103
        videoManager_.reset(new DBusVideoManager {sessionConnection});
104 105
#endif
    } catch (const DBus::Error &err) {
106
        throw std::runtime_error {"cannot initialize DBus stuff"};
107 108
    }

109
    if (initLibrary(flags) < 0)
110
        throw std::runtime_error {"cannot initialize libring"};
111 112 113 114 115 116

    instanceManager_->started();
}

DBusClient::~DBusClient()
{
117 118 119 120 121 122 123 124 125 126 127
    // instances destruction order is important
    // so we enforce it here

#ifdef RING_VIDEO
    videoManager_.reset();
#endif
    instanceManager_.reset();
    presenceManager_.reset();
    configurationManager_.reset();
    callManager_.reset();
    timeout_.reset();
128 129
}

Guillaume Roguez's avatar
Guillaume Roguez committed
130
int
131
DBusClient::initLibrary(int flags)
132
{
133
    using namespace std::placeholders;
134

135 136 137 138 139
    using std::bind;
    using DRing::exportable_callback;
    using DRing::CallSignal;
    using DRing::ConfigurationSignal;
    using DRing::PresenceSignal;
Guillaume Roguez's avatar
Guillaume Roguez committed
140

141 142 143 144 145
    using SharedCallback = std::shared_ptr<DRing::CallbackWrapperBase>;

    auto callM = callManager_.get();
    auto confM = configurationManager_.get();
    auto presM = presenceManager_.get();
Guillaume Roguez's avatar
Guillaume Roguez committed
146 147 148

#ifdef RING_VIDEO
    using DRing::VideoSignal;
149
    auto videoM = videoManager_.get();
Guillaume Roguez's avatar
Guillaume Roguez committed
150
#endif
151

Guillaume Roguez's avatar
Guillaume Roguez committed
152 153
    // Call event handlers
    const std::map<std::string, SharedCallback> callEvHandlers = {
154
        exportable_callback<CallSignal::StateChange>(bind(&DBusCallManager::callStateChanged, callM, _1, _2, _3)),
Guillaume Roguez's avatar
Guillaume Roguez committed
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
        exportable_callback<CallSignal::TransferFailed>(bind(&DBusCallManager::transferFailed, callM)),
        exportable_callback<CallSignal::TransferSucceeded>(bind(&DBusCallManager::transferSucceeded, callM)),
        exportable_callback<CallSignal::RecordPlaybackStopped>(bind(&DBusCallManager::recordPlaybackStopped, callM, _1)),
        exportable_callback<CallSignal::VoiceMailNotify>(bind(&DBusCallManager::voiceMailNotify, callM, _1, _2)),
        exportable_callback<CallSignal::IncomingMessage>(bind(&DBusCallManager::incomingMessage, callM, _1, _2, _3)),
        exportable_callback<CallSignal::IncomingCall>(bind(&DBusCallManager::incomingCall, callM, _1, _2, _3)),
        exportable_callback<CallSignal::RecordPlaybackFilepath>(bind(&DBusCallManager::recordPlaybackFilepath, callM, _1, _2)),
        exportable_callback<CallSignal::ConferenceCreated>(bind(&DBusCallManager::conferenceCreated, callM, _1)),
        exportable_callback<CallSignal::ConferenceChanged>(bind(&DBusCallManager::conferenceChanged, callM, _1, _2)),
        exportable_callback<CallSignal::UpdatePlaybackScale>(bind(&DBusCallManager::updatePlaybackScale, callM, _1, _2, _3)),
        exportable_callback<CallSignal::ConferenceRemoved>(bind(&DBusCallManager::conferenceRemoved, callM, _1)),
        exportable_callback<CallSignal::NewCallCreated>(bind(&DBusCallManager::newCallCreated, callM, _1, _2, _3)),
        exportable_callback<CallSignal::RecordingStateChanged>(bind(&DBusCallManager::recordingStateChanged, callM, _1, _2)),
        exportable_callback<CallSignal::SecureSdesOn>(bind(&DBusCallManager::secureSdesOn, callM, _1)),
        exportable_callback<CallSignal::SecureSdesOff>(bind(&DBusCallManager::secureSdesOff, callM, _1)),
        exportable_callback<CallSignal::SecureZrtpOn>(bind(&DBusCallManager::secureZrtpOn, callM, _1, _2)),
        exportable_callback<CallSignal::SecureZrtpOff>(bind(&DBusCallManager::secureZrtpOff, callM, _1)),
        exportable_callback<CallSignal::ShowSAS>(bind(&DBusCallManager::showSAS, callM, _1, _2, _3)),
        exportable_callback<CallSignal::ZrtpNotSuppOther>(bind(&DBusCallManager::zrtpNotSuppOther, callM, _1)),
        exportable_callback<CallSignal::ZrtpNegotiationFailed>(bind(&DBusCallManager::zrtpNegotiationFailed, callM, _1, _2, _3)),
        exportable_callback<CallSignal::RtcpReportReceived>(bind(&DBusCallManager::onRtcpReportReceived, callM, _1, _2)),
176
        exportable_callback<CallSignal::PeerHold>(bind(&DBusCallManager::peerHold, callM, _1, _2))
Guillaume Roguez's avatar
Guillaume Roguez committed
177 178 179 180 181 182 183
    };

    // Configuration event handlers
    const std::map<std::string, SharedCallback> configEvHandlers = {
        exportable_callback<ConfigurationSignal::VolumeChanged>(bind(&DBusConfigurationManager::volumeChanged, confM, _1, _2)),
        exportable_callback<ConfigurationSignal::AccountsChanged>(bind(&DBusConfigurationManager::accountsChanged, confM)),
        exportable_callback<ConfigurationSignal::StunStatusFailed>(bind(&DBusConfigurationManager::stunStatusFailure, confM, _1)),
184
        exportable_callback<ConfigurationSignal::RegistrationStateChanged>(bind(&DBusConfigurationManager::registrationStateChanged, confM, _1, _2, _3, _4)),
Guillaume Roguez's avatar
Guillaume Roguez committed
185 186 187 188 189 190 191 192 193 194 195 196
        exportable_callback<ConfigurationSignal::VolatileDetailsChanged>(bind(&DBusConfigurationManager::volatileAccountDetailsChanged, confM, _1, _2)),
        exportable_callback<ConfigurationSignal::Error>(bind(&DBusConfigurationManager::errorAlert, confM, _1)),
    };

    // Presence event handlers
    const std::map<std::string, SharedCallback> presEvHandlers = {
        exportable_callback<PresenceSignal::NewServerSubscriptionRequest>(bind(&DBusPresenceManager::newServerSubscriptionRequest, presM, _1)),
        exportable_callback<PresenceSignal::ServerError>(bind(&DBusPresenceManager::serverError, presM, _1, _2, _3)),
        exportable_callback<PresenceSignal::NewBuddyNotification>(bind(&DBusPresenceManager::newBuddyNotification, presM, _1, _2, _3, _4)),
        exportable_callback<PresenceSignal::SubscriptionStateChanged>(bind(&DBusPresenceManager::subscriptionStateChanged, presM, _1, _2, _3)),
    };

Adrien Béraud's avatar
Adrien Béraud committed
197
#ifdef RING_VIDEO
Guillaume Roguez's avatar
Guillaume Roguez committed
198 199 200 201 202
    // Video event handlers
    const std::map<std::string, SharedCallback> videoEvHandlers = {
        exportable_callback<VideoSignal::DeviceEvent>(bind(&DBusVideoManager::deviceEvent, videoM)),
        exportable_callback<VideoSignal::DecodingStarted>(bind(&DBusVideoManager::startedDecoding, videoM, _1, _2, _3, _4, _5)),
        exportable_callback<VideoSignal::DecodingStopped>(bind(&DBusVideoManager::stoppedDecoding, videoM, _1, _2, _3)),
203
    };
Guillaume Roguez's avatar
Guillaume Roguez committed
204
#endif
205

206
    if (!DRing::init(static_cast<DRing::InitFlag>(flags)))
Guillaume Roguez's avatar
Guillaume Roguez committed
207 208 209 210 211 212 213 214 215 216 217 218
        return -1;

    registerCallHandlers(callEvHandlers);
    registerConfHandlers(configEvHandlers);
    registerPresHandlers(presEvHandlers);
#ifdef RING_VIDEO
    registerVideoHandlers(videoEvHandlers);
#endif

    if (!DRing::start())
        return -1;
    return 0;
219 220
}

221 222
void
DBusClient::finiLibrary() noexcept
223
{
224
    DRing::fini();
225 226
}

227 228
int
DBusClient::event_loop() noexcept
229 230 231
{
    try {
        dispatcher_->enter();
232
    } catch (const DBus::Error& err) {
233 234
        std::cerr << "quitting: " << err.name() << ": " << err.what() << std::endl;
        return 1;
235
    } catch (const std::exception& err) {
236 237 238 239 240 241 242
        std::cerr << "quitting: " << err.what() << std::endl;
        return 1;
    }

    return 0;
}

243 244
int
DBusClient::exit() noexcept
245 246 247
{
    try {
        dispatcher_->leave();
248 249
        timeout_->expired = new EventCallback([] {});
        finiLibrary();
250
    } catch (const DBus::Error& err) {
251 252
        std::cerr << "quitting: " << err.name() << ": " << err.what() << std::endl;
        return 1;
253
    } catch (const std::exception& err) {
254 255 256 257 258 259
        std::cerr << "quitting: " << err.what() << std::endl;
        return 1;
    }

    return 0;
}