Merge lp:~justinmcp/media-hub/1239432 into lp:media-hub

Proposed by Justin McPherson
Status: Merged
Approved by: Jim Hodapp
Approved revision: 77
Merged at revision: 95
Proposed branch: lp:~justinmcp/media-hub/1239432
Merge into: lp:media-hub
Diff against target: 723 lines (+579/-6)
11 files modified
CMakeLists.txt (+2/-2)
debian/control (+2/-0)
src/core/media/CMakeLists.txt (+4/-1)
src/core/media/call-monitor/CMakeLists.txt (+23/-0)
src/core/media/call-monitor/call_monitor.cpp (+206/-0)
src/core/media/call-monitor/call_monitor.h (+41/-0)
src/core/media/call-monitor/qtbridge.cpp (+186/-0)
src/core/media/call-monitor/qtbridge.h (+87/-0)
src/core/media/service_implementation.cpp (+26/-3)
src/core/media/service_implementation.h (+1/-0)
tests/unit-tests/CMakeLists.txt (+1/-0)
To merge this branch: bzr merge lp:~justinmcp/media-hub/1239432
Reviewer Review Type Date Requested Status
Jim Hodapp (community) code Approve
PS Jenkins bot continuous-integration Needs Fixing
Review via email: mp+240387@code.launchpad.net

Commit message

#1239432 Music fails to pause on incoming/outgoing calls

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
lp:~justinmcp/media-hub/1239432 updated
76. By Justin McPherson <justin@phablet-dev>

Merge from trunk.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Jim Hodapp (jhodapp) wrote :

Have you seen this example that gets used by the telephony service to monitor the same call signals? http://bazaar.launchpad.net/~phablet-team/telephony-service/trunk/view/head:/libtelephonyservice/channelobserver.cpp

Revision history for this message
Jim Hodapp (jhodapp) wrote :

Looks really good. Only one minor inline comment to address. Would like to help you test it after you get it built in a silo.

review: Needs Fixing (code)
lp:~justinmcp/media-hub/1239432 updated
77. By Justin McPherson <justin@phablet-dev>

Removed not needed #include

Revision history for this message
Jim Hodapp (jhodapp) wrote :

Looks good, thanks

review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2014-10-14 16:21:47 +0000
3+++ CMakeLists.txt 2014-11-04 23:38:46 +0000
4@@ -6,8 +6,8 @@
5 set(UBUNTU_MEDIA_HUB_VERSION_MINOR 0)
6 set(UBUNTU_MEDIA_HUB_VERSION_PATCH 0)
7
8-set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror -Wall -pedantic -Wextra -fPIC -pthread")
9-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Werror -Wall -fno-strict-aliasing -pedantic -Wextra -fPIC -pthread")
10+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -fPIC -pthread")
11+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -fno-strict-aliasing -Wextra -fPIC -pthread")
12
13 set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
14
15
16=== modified file 'debian/control'
17--- debian/control 2014-10-23 21:25:38 +0000
18+++ debian/control 2014-11-04 23:38:46 +0000
19@@ -28,6 +28,8 @@
20 gstreamer1.0-libav,
21 libgstreamer1.0-dev,
22 pkg-config,
23+ qtbase5-dev,
24+ libtelepathy-qt5-dev,
25 Standards-Version: 3.9.5
26 Homepage: https://launchpad.net/media-hub
27 # If you aren't a member of ~phablet-team but need to upload packaging changes,
28
29=== modified file 'src/core/media/CMakeLists.txt'
30--- src/core/media/CMakeLists.txt 2014-10-14 16:21:47 +0000
31+++ src/core/media/CMakeLists.txt 2014-11-04 23:38:46 +0000
32@@ -7,6 +7,8 @@
33
34 file(GLOB MPRIS_HEADERS mpris/ *.h)
35
36+add_subdirectory(call-monitor)
37+
38 add_library(
39 media-hub-common SHARED
40
41@@ -90,7 +92,7 @@
42 media-hub-service
43
44 media-hub-common
45-
46+ call-monitor
47 ${DBUS_LIBRARIES}
48 ${DBUS_CPP_LDFLAGS}
49 ${GLog_LIBRARY}
50@@ -113,6 +115,7 @@
51
52 media-hub-service
53 media-hub-client
54+ call-monitor
55
56 ${DBUS_LIBRARIES}
57 ${DBUS_CPP_LDFLAGS}
58
59=== added directory 'src/core/media/call-monitor'
60=== added file 'src/core/media/call-monitor/CMakeLists.txt'
61--- src/core/media/call-monitor/CMakeLists.txt 1970-01-01 00:00:00 +0000
62+++ src/core/media/call-monitor/CMakeLists.txt 2014-11-04 23:38:46 +0000
63@@ -0,0 +1,23 @@
64+SET (CMAKE_INCLUDE_CURRENT_DIR ON)
65+SET (CMAKE_AUTOMOC ON)
66+
67+find_package(Qt5Core REQUIRED)
68+find_package(PkgConfig REQUIRED)
69+pkg_check_modules(TP_QT5 REQUIRED TelepathyQt5)
70+
71+#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -pedantic -Wextra -fPIC -pthread")
72+
73+include_directories(
74+ ${TP_QT5_INCLUDE_DIRS}
75+)
76+
77+add_library(call-monitor STATIC
78+ call_monitor.cpp
79+ qtbridge.cpp
80+)
81+
82+target_link_libraries(call-monitor
83+ ${TP_QT5_LIBRARIES}
84+)
85+
86+qt5_use_modules(call-monitor Core DBus)
87
88=== added file 'src/core/media/call-monitor/call_monitor.cpp'
89--- src/core/media/call-monitor/call_monitor.cpp 1970-01-01 00:00:00 +0000
90+++ src/core/media/call-monitor/call_monitor.cpp 2014-11-04 23:38:46 +0000
91@@ -0,0 +1,206 @@
92+/*
93+ * Copyright (C) 2014 Canonical Ltd
94+ *
95+ * This program is free software: you can redistribute it and/or modify
96+ * it under the terms of the GNU Lesser General Public License version 3 as
97+ * published by the Free Software Foundation.
98+ *
99+ * This program is distributed in the hope that it will be useful,
100+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
101+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
102+ * GNU Lesser General Public License for more details.
103+ *
104+ * You should have received a copy of the GNU Lesser General Public License
105+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
106+ *
107+ * Author: Justin McPherson <justin.mcpherson@canonical.com>
108+ */
109+
110+
111+#include "call_monitor.h"
112+
113+#include "qtbridge.h"
114+#include <TelepathyQt/AccountManager>
115+#include <TelepathyQt/SimpleCallObserver>
116+#include <TelepathyQt/PendingOperation>
117+#include <TelepathyQt/PendingReady>
118+#include <TelepathyQt/PendingAccount>
119+
120+#include <list>
121+#include <mutex>
122+
123+
124+namespace {
125+class TelepathyCallMonitor : public QObject
126+{
127+ Q_OBJECT
128+public:
129+ TelepathyCallMonitor(const Tp::AccountPtr& account):
130+ mAccount(account),
131+ mCallObserver(Tp::SimpleCallObserver::create(mAccount)) {
132+ connect(mCallObserver.data(), SIGNAL(callStarted(Tp::CallChannelPtr)), SIGNAL(offHook()));
133+ connect(mCallObserver.data(), SIGNAL(callEnded(Tp::CallChannelPtr,QString,QString)), SIGNAL(onHook()));
134+ connect(mCallObserver.data(), SIGNAL(streamedMediaCallStarted(Tp::StreamedMediaChannelPtr)), SIGNAL(offHook()));
135+ connect(mCallObserver.data(), SIGNAL(streamedMediaCallEnded(Tp::StreamedMediaChannelPtr,QString,QString)), SIGNAL(onHook()));
136+ }
137+
138+Q_SIGNALS:
139+ void offHook();
140+ void onHook();
141+
142+private:
143+ Tp::AccountPtr mAccount;
144+ Tp::SimpleCallObserverPtr mCallObserver;
145+};
146+
147+
148+class TelepathyBridge : public QObject
149+{
150+ Q_OBJECT
151+public:
152+ TelepathyBridge():
153+ QObject(0) {
154+ Tp::registerTypes();
155+
156+ QTimer::singleShot(0, this, SLOT(accountManagerSetup()));
157+ }
158+
159+ ~TelepathyBridge() {
160+ for (std::list<TelepathyCallMonitor*>::iterator it = mCallMonitors.begin();
161+ it != mCallMonitors.end();
162+ ++it) {
163+ delete *it;
164+ }
165+ }
166+
167+ void on_change(const std::function<void(CallMonitor::State)>& func) {
168+ std::lock_guard<std::mutex> l(cb_lock);
169+ cb = func;
170+ }
171+
172+private Q_SLOTS:
173+ void accountManagerSetup() {
174+ mAccountManager = Tp::AccountManager::create();
175+ connect(mAccountManager->becomeReady(),
176+ SIGNAL(finished(Tp::PendingOperation*)),
177+ SLOT(accountManagerReady(Tp::PendingOperation*)));
178+ }
179+
180+ void accountManagerReady(Tp::PendingOperation* operation) {
181+ if (operation->isError()) {
182+ std::cerr << "TelepathyBridge: Operation failed (accountManagerReady)" << std::endl;
183+ QTimer::singleShot(1000, this, SLOT(accountManagerSetup())); // again
184+ return;
185+ }
186+
187+ Q_FOREACH(const Tp::AccountPtr& account, mAccountManager->allAccounts()) {
188+ connect(account->becomeReady(Tp::Account::FeatureCapabilities),
189+ SIGNAL(finished(Tp::PendingOperation*)),
190+ SLOT(accountReady(Tp::PendingOperation*)));
191+ }
192+
193+ connect(mAccountManager.data(), SIGNAL(newAccount(Tp::AccountPtr)), SLOT(newAccount(Tp::AccountPtr)));
194+ }
195+
196+ void newAccount(const Tp::AccountPtr& account)
197+ {
198+ connect(account->becomeReady(Tp::Account::FeatureCapabilities),
199+ SIGNAL(finished(Tp::PendingOperation*)),
200+ SLOT(accountReady(Tp::PendingOperation*)));
201+ }
202+
203+ void accountReady(Tp::PendingOperation* operation) {
204+ if (operation->isError()) {
205+ std::cerr << "TelepathyAccount: Operation failed (accountReady)" << std::endl;
206+ return;
207+ }
208+
209+ Tp::PendingReady* pendingReady = qobject_cast<Tp::PendingReady*>(operation);
210+ if (pendingReady == 0) {
211+ std::cerr << "Rejecting account because could not understand ready status" << std::endl;
212+ return;
213+ }
214+
215+ checkAndAddAccount(Tp::AccountPtr::qObjectCast(pendingReady->proxy()));
216+ }
217+
218+ void offHook()
219+ {
220+ std::lock_guard<std::mutex> l(cb_lock);
221+ if (cb)
222+ cb(CallMonitor::OffHook);
223+ }
224+
225+ void onHook()
226+ {
227+ std::lock_guard<std::mutex> l(cb_lock);
228+ if (cb)
229+ cb(CallMonitor::OnHook);
230+ }
231+
232+private:
233+ std::mutex cb_lock;
234+ std::function<void (CallMonitor::State)> cb;
235+ Tp::AccountManagerPtr mAccountManager;
236+ std::list<TelepathyCallMonitor*> mCallMonitors;
237+
238+ void checkAndAddAccount(const Tp::AccountPtr& account)
239+ {
240+ Tp::ConnectionCapabilities caps = account->capabilities();
241+
242+ // anything call like, perhaps overkill?
243+ if (caps.audioCalls() || caps.videoCalls() || caps.videoCallsWithAudio() || caps.streamedMediaCalls()) {
244+ auto tcm = new TelepathyCallMonitor(account);
245+ connect(tcm, SIGNAL(offHook()), SLOT(offHook()));
246+ connect(tcm, SIGNAL(onHook()), SLOT(onHook()));
247+ mCallMonitors.push_back(tcm);
248+ }
249+ }
250+};
251+}
252+
253+class CallMonitorPrivate
254+{
255+public:
256+ CallMonitorPrivate() {
257+ try {
258+ std::thread([this]() {
259+ qt::core::world::build_and_run(0, nullptr, [this]() {
260+ qt::core::world::enter_with_task([this]() {
261+ mBridge = new TelepathyBridge();
262+ });
263+ });
264+ }).detach();
265+ } catch(const std::system_error& error) {
266+ std::cerr << "exception(std::system_error) in CallMonitor thread start" << error.what() << std::endl;
267+ } catch(...) {
268+ std::cerr << "exception(...) in CallMonitor thread start" << std::endl;
269+ }
270+ }
271+
272+ ~CallMonitorPrivate() {
273+ qt::core::world::destroy();
274+ }
275+
276+ TelepathyBridge *mBridge;
277+};
278+
279+
280+CallMonitor::CallMonitor():
281+ d(new CallMonitorPrivate)
282+{
283+}
284+
285+CallMonitor::~CallMonitor()
286+{
287+ delete d->mBridge;
288+ delete d;
289+}
290+
291+void CallMonitor::on_change(const std::function<void(CallMonitor::State)>& func)
292+{
293+ d->mBridge->on_change(func);
294+}
295+
296+#include "call_monitor.moc"
297+
298
299=== added file 'src/core/media/call-monitor/call_monitor.h'
300--- src/core/media/call-monitor/call_monitor.h 1970-01-01 00:00:00 +0000
301+++ src/core/media/call-monitor/call_monitor.h 2014-11-04 23:38:46 +0000
302@@ -0,0 +1,41 @@
303+/*
304+ * Copyright (C) 2014 Canonical Ltd
305+ *
306+ * This program is free software: you can redistribute it and/or modify
307+ * it under the terms of the GNU Lesser General Public License version 3 as
308+ * published by the Free Software Foundation.
309+ *
310+ * This program is distributed in the hope that it will be useful,
311+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
312+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
313+ * GNU Lesser General Public License for more details.
314+ *
315+ * You should have received a copy of the GNU Lesser General Public License
316+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
317+ *
318+ * Author: Justin McPherson <justin.mcpherson@canonical.com>
319+ */
320+
321+
322+#ifndef CALLMONITOR_H
323+#define CALLMONITOR_H
324+
325+#include <functional>
326+
327+class CallMonitorPrivate;
328+
329+class CallMonitor
330+{
331+public:
332+ enum State { OffHook, OnHook };
333+
334+ CallMonitor();
335+ ~CallMonitor();
336+
337+ void on_change(const std::function<void(CallMonitor::State)>& func);
338+
339+private:
340+ CallMonitorPrivate *d;
341+};
342+
343+#endif // CALLMONITOR_H
344
345=== added file 'src/core/media/call-monitor/qtbridge.cpp'
346--- src/core/media/call-monitor/qtbridge.cpp 1970-01-01 00:00:00 +0000
347+++ src/core/media/call-monitor/qtbridge.cpp 2014-11-04 23:38:46 +0000
348@@ -0,0 +1,186 @@
349+/*
350+ * Copyright © 2014 Canonical Ltd.
351+ *
352+ * This program is free software: you can redistribute it and/or modify it
353+ * under the terms of the GNU Lesser General Public License version 3,
354+ * as published by the Free Software Foundation.
355+ *
356+ * This program is distributed in the hope that it will be useful,
357+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
358+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
359+ * GNU Lesser General Public License for more details.
360+ *
361+ * You should have received a copy of the GNU Lesser General Public License
362+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
363+ *
364+ * Authored by: Jussi Pakkanen <jussi.pakkanen@canonical.com>
365+ * Thomas Voß <thomas.voss@canonical.com>
366+ */
367+
368+#include "qtbridge.h"
369+
370+#include<QCoreApplication>
371+#include<QNetworkAccessManager>
372+#include<QNetworkRequest>
373+#include<QNetworkReply>
374+#include<QThread>
375+#include<QDebug>
376+
377+#include <iostream>
378+
379+namespace
380+{
381+QCoreApplication* app = nullptr;
382+}
383+
384+namespace qt
385+{
386+namespace core
387+{
388+namespace world
389+{
390+namespace detail
391+{
392+QEvent::Type qt_core_world_task_event_type()
393+{
394+ static QEvent::Type event_type = static_cast<QEvent::Type>(QEvent::registerEventType());
395+ return event_type;
396+}
397+
398+class TaskEvent : public QEvent
399+{
400+public:
401+ TaskEvent(const std::function<void()>& task)
402+ : QEvent(qt_core_world_task_event_type()),
403+ task(task)
404+ {
405+ }
406+
407+ void run()
408+ {
409+ try
410+ {
411+ task();
412+ promise.set_value();
413+ } catch(...)
414+ {
415+ promise.set_exception(std::current_exception());
416+ }
417+ }
418+
419+ std::future<void> get_future()
420+ {
421+ return promise.get_future();
422+ }
423+
424+private:
425+ std::function<void()> task;
426+ std::promise<void> promise;
427+};
428+
429+class TaskHandler : public QObject
430+{
431+ Q_OBJECT
432+
433+public:
434+ TaskHandler(QObject* parent) : QObject(parent)
435+ {
436+ }
437+
438+ bool event(QEvent* e);
439+};
440+
441+
442+
443+void createCoreApplicationInstanceWithArgs(int argc, char** argv)
444+{
445+ app = new QCoreApplication(argc, argv);
446+}
447+
448+void destroyCoreApplicationInstace()
449+{
450+ delete app;
451+}
452+
453+QCoreApplication* coreApplicationInstance()
454+{
455+ return app;
456+}
457+
458+TaskHandler* task_handler()
459+{
460+ static TaskHandler* instance = new TaskHandler(coreApplicationInstance());
461+ return instance;
462+}
463+
464+bool TaskHandler::event(QEvent *e)
465+{
466+ if (e->type() != qt_core_world_task_event_type())
467+ return QObject::event(e);
468+
469+ auto te = dynamic_cast<TaskEvent*>(e);
470+ if (te)
471+ {
472+ te->run();
473+ return true;
474+ }
475+
476+ return false;
477+}
478+}
479+
480+void build_and_run(int argc, char** argv, const std::function<void()>& ready)
481+{
482+ QThread::currentThread();
483+ if (QCoreApplication::instance() != nullptr)
484+ throw std::runtime_error(
485+ "qt::core::world::build_and_run: "
486+ "There is already a QCoreApplication running.");
487+
488+ detail::createCoreApplicationInstanceWithArgs(argc, argv);
489+
490+ detail::task_handler()->moveToThread(
491+ detail::coreApplicationInstance()->thread());
492+
493+ // Signal to other worlds that we are good to go.
494+ ready();
495+
496+ detail::coreApplicationInstance()->exec();
497+
498+ // Someone has called quit and we clean up on the correct thread here.
499+ detail::destroyCoreApplicationInstace();
500+}
501+
502+void destroy()
503+{
504+ enter_with_task([]()
505+ {
506+ // We make sure that all tasks have completed before quitting the app.
507+ QEventLoopLocker locker;
508+ }).wait_for(std::chrono::seconds{1});
509+}
510+
511+std::future<void> enter_with_task(const std::function<void()>& task)
512+{
513+ QCoreApplication* instance = QCoreApplication::instance();
514+
515+ if (!instance)
516+ {
517+ throw std::runtime_error("Qt world has not been built before calling this function.");
518+ }
519+
520+ detail::TaskEvent* te = new detail::TaskEvent(task);
521+ auto future = te->get_future();
522+
523+ // We hand over ownership of te here. The event is deleted later after it has
524+ // been processed by the event loop.
525+ instance->postEvent(detail::task_handler(), te);
526+
527+ return future;
528+}
529+
530+}
531+}
532+}
533+
534+#include "qtbridge.moc"
535
536=== added file 'src/core/media/call-monitor/qtbridge.h'
537--- src/core/media/call-monitor/qtbridge.h 1970-01-01 00:00:00 +0000
538+++ src/core/media/call-monitor/qtbridge.h 2014-11-04 23:38:46 +0000
539@@ -0,0 +1,87 @@
540+/*
541+ * Copyright © 2014 Canonical Ltd.
542+ *
543+ * This program is free software: you can redistribute it and/or modify it
544+ * under the terms of the GNU Lesser General Public License version 3,
545+ * as published by the Free Software Foundation.
546+ *
547+ * This program is distributed in the hope that it will be useful,
548+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
549+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
550+ * GNU Lesser General Public License for more details.
551+ *
552+ * You should have received a copy of the GNU Lesser General Public License
553+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
554+ *
555+ * Authored by: Jussi Pakkanen <jussi.pakkanen@canonical.com>
556+ * Thomas Voß <thomas.voss@canonical.com>
557+ */
558+
559+#ifndef QT_CORE_WORLD_BRIDGE_H_
560+#define QT_CORE_WORLD_BRIDGE_H_
561+
562+#include <QObject>
563+
564+#include <functional>
565+#include <future>
566+#include <iostream>
567+
568+namespace qt
569+{
570+namespace core
571+{
572+namespace world
573+{
574+/**
575+ * @brief Sets up the Qt core world and executes its event loop. Blocks until destroy() is called.
576+ * @param argc Number of arguments in argv.
577+ * @param argv Array of command-line arguments.
578+ * @param ready Functor be called when the world has been setup and is about to be executed.
579+ * @throw std::runtime_error in case of errors.
580+ */
581+void build_and_run(int argc, char** argv, const std::function<void()>& ready);
582+
583+/**
584+ * @brief Destroys the Qt core world and quits its event loop.
585+ */
586+void destroy();
587+
588+/**
589+ * @brief Enters the Qt core world and schedules the given task for execution.
590+ * @param task The task to be executed in the Qt core world.
591+ * @return A std::future that can be waited for to synchronize to the world's internal event loop.
592+ */
593+std::future<void> enter_with_task(const std::function<void()>& task);
594+
595+
596+/**
597+ * @brief Enters the Qt core world and schedules the given task for execution.
598+ * @param task The task to be executed in the Qt core world.
599+ * @return A std::future that can be waited for to get hold of the result of the task.
600+ */
601+template<typename T>
602+inline std::future<T> enter_with_task_and_expect_result(const std::function<T()>& task)
603+{
604+ std::shared_ptr<std::promise<T>> promise = std::make_shared<std::promise<T>>();
605+ std::future<T> future = promise->get_future();
606+
607+ auto t = [promise, task]()
608+ {
609+ try
610+ {
611+ promise->set_value(task());
612+ } catch(...)
613+ {
614+ promise->set_exception(std::current_exception());
615+ }
616+ };
617+
618+ enter_with_task(t);
619+
620+ return future;
621+}
622+}
623+}
624+}
625+
626+#endif // QT_CORE_WORLD_BRIDGE_H_
627
628=== modified file 'src/core/media/service_implementation.cpp'
629--- src/core/media/service_implementation.cpp 2014-10-15 14:20:03 +0000
630+++ src/core/media/service_implementation.cpp 2014-11-04 23:38:46 +0000
631@@ -20,6 +20,7 @@
632 #include "service_implementation.h"
633
634 #include "indicator_power_service.h"
635+#include "call-monitor/call_monitor.h"
636 #include "player_configuration.h"
637 #include "player_implementation.h"
638
639@@ -43,7 +44,8 @@
640 Private()
641 : resume_key(std::numeric_limits<std::uint32_t>::max()),
642 keep_alive(io_service),
643- disp_cookie(0)
644+ disp_cookie(0),
645+ call_monitor(new CallMonitor)
646 {
647 bus = std::shared_ptr<dbus::Bus>(new dbus::Bus(core::dbus::WellKnownBus::session));
648 bus->install_executor(dbus::asio::make_executor(bus, io_service));
649@@ -127,6 +129,8 @@
650 int disp_cookie;
651 std::shared_ptr<dbus::Object> uscreen_session;
652 MediaRecorderObserver *observer;
653+ std::unique_ptr<CallMonitor> call_monitor;
654+ std::list<media::Player::PlayerKey> paused_sessions;
655 };
656
657 media::ServiceImplementation::ServiceImplementation() : d(new Private())
658@@ -148,6 +152,17 @@
659 if (!notifying)
660 resume_multimedia_session();
661 });
662+
663+ d->call_monitor->on_change([this](CallMonitor::State state) {
664+ switch (state) {
665+ case CallMonitor::OffHook:
666+ pause_all_multimedia_sessions();
667+ break;
668+ case CallMonitor::OnHook:
669+ resume_paused_multimedia_sessions();
670+ break;
671+ }
672+ });
673 }
674
675 media::ServiceImplementation::~ServiceImplementation()
676@@ -216,13 +231,21 @@
677 if (player->playback_status() == Player::playing
678 && player->audio_stream_role() == media::Player::multimedia)
679 {
680- d->resume_key = key;
681- cout << "Will resume playback of Player with key: " << d->resume_key << endl;
682+ d->paused_sessions.push_back(key);
683 player->pause();
684 }
685 });
686 }
687
688+void media::ServiceImplementation::resume_paused_multimedia_sessions()
689+{
690+ std::for_each(d->paused_sessions.begin(), d->paused_sessions.end(), [this](const media::Player::PlayerKey& key) {
691+ player_for_key(key)->play();
692+ });
693+
694+ d->paused_sessions.clear();
695+}
696+
697 void media::ServiceImplementation::resume_multimedia_session()
698 {
699 if (not has_player_for_key(d->resume_key))
700
701=== modified file 'src/core/media/service_implementation.h'
702--- src/core/media/service_implementation.h 2014-09-09 14:48:51 +0000
703+++ src/core/media/service_implementation.h 2014-11-04 23:38:46 +0000
704@@ -42,6 +42,7 @@
705
706 private:
707 void pause_all_multimedia_sessions();
708+ void resume_paused_multimedia_sessions();
709 void resume_multimedia_session();
710
711 struct Private;
712
713=== modified file 'tests/unit-tests/CMakeLists.txt'
714--- tests/unit-tests/CMakeLists.txt 2014-10-14 16:21:47 +0000
715+++ tests/unit-tests/CMakeLists.txt 2014-11-04 23:38:46 +0000
716@@ -25,6 +25,7 @@
717
718 media-hub-common
719 media-hub-client
720+ call-monitor
721 media-hub-test-framework
722
723 ${CMAKE_THREAD_LIBS_INIT}

Subscribers

People subscribed via source and target branches