Merge lp:~jhodapp/media-hub/fix-1421620-rtm into lp:media-hub

Proposed by Jim Hodapp
Status: Superseded
Proposed branch: lp:~jhodapp/media-hub/fix-1421620-rtm
Merge into: lp:media-hub
Diff against target: 1068 lines (+827/-3) (has conflicts)
14 files modified
debian/changelog (+99/-0)
debian/control (+7/-0)
include/core/media/player.h (+13/-0)
src/core/media/call-monitor/CMakeLists.txt (+23/-0)
src/core/media/call-monitor/call_monitor.cpp (+222/-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/codec.h (+43/-0)
src/core/media/gstreamer/playbin.h (+3/-0)
src/core/media/service_implementation.cpp (+85/-3)
src/core/media/service_implementation.h (+5/-0)
tests/unit-tests/CMakeLists.txt (+4/-0)
tests/unit-tests/test-gstreamer-engine.cpp (+9/-0)
Text conflict in debian/changelog
Text conflict in debian/control
Text conflict in include/core/media/player.h
Conflict adding file src/core/media/call-monitor.  Moved existing file to src/core/media/call-monitor.moved.
Text conflict in src/core/media/codec.h
Text conflict in src/core/media/gstreamer/playbin.h
Text conflict in src/core/media/service_implementation.cpp
Text conflict in src/core/media/service_implementation.h
Text conflict in tests/unit-tests/CMakeLists.txt
Text conflict in tests/unit-tests/test-gstreamer-engine.cpp
To merge this branch: bzr merge lp:~jhodapp/media-hub/fix-1421620-rtm
Reviewer Review Type Date Requested Status
Ubuntu Phablet Team Pending
Review via email: mp+254840@code.launchpad.net

Commit message

Fix the bug which caused music playback to start playing again after a phonecall hung up after being auto-paused by disconnecting a headphone jack

Description of the change

Fix the bug which caused music playback to start playing again after a phonecall hung up after being auto-paused by disconnecting a headphone jack

To post a comment you must log in.

Unmerged revisions

88. By Jim Hodapp

Fix the bug which caused music playback to start playing again after a phonecall hung up after being auto-paused by disconnecting a headphone jack.

87. By Ricardo Salveti

releasing package media-hub version 2.0.0+15.04.20150120~rtm-0ubuntu1

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2=== modified file 'debian/changelog'
3--- debian/changelog 2015-03-12 03:06:40 +0000
4+++ debian/changelog 2015-03-31 21:19:24 +0000
5@@ -1,3 +1,4 @@
6+<<<<<<< TREE
7 media-hub (2.0.0+15.04.20150303-0ubuntu2) vivid; urgency=medium
8
9 * debian/control:
10@@ -122,6 +123,104 @@
11
12 -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Tue, 04 Nov 2014 06:10:54 +0000
13
14+=======
15+media-hub (2.0.0+15.04.20150120~rtm-0ubuntu1) 14.09; urgency=low
16+
17+ [ Jim Hodapp ]
18+ * Error reporting all the way up to the app level from the playbin
19+ pipeline (LP: #1413824).
20+
21+ [ Ubuntu daily release ]
22+ * New rebuild forced
23+
24+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Tue, 20 Jan 2015 01:21:47 +0000
25+
26+media-hub (2.0.0+15.04.20150116-0ubuntu1) vivid; urgency=low
27+
28+ [ Jim Hodapp ]
29+ * Don't auto-resume playback of videos after a phone call ends. (LP:
30+ #1411273)
31+
32+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Fri, 16 Jan 2015 18:17:56 +0000
33+
34+media-hub (2.0.0+15.04.20150112.2-0ubuntu1) vivid; urgency=low
35+
36+ [ Ubuntu daily release ]
37+ * New rebuild forced
38+
39+ [ Ricardo Salveti de Araujo ]
40+ * service_implementation: adding debug for call started/ended signals.
41+ Make sure account and connection are available when setting up
42+ account manager (patch from Gustavo Boiko). call_monitor: don't
43+ check caps when hooking up on/off signals, until bug 1409125 is
44+ fixed. Enable parallel building . (LP: #1409125)
45+
46+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Mon, 12 Jan 2015 21:38:39 +0000
47+
48+media-hub (2.0.0+15.04.20150108-0ubuntu1) vivid; urgency=low
49+
50+ [ Jim Hodapp ]
51+ * Pause playback when recording begins. (LP: #1398047)
52+
53+ [ Ricardo Salveti de Araujo ]
54+ * call_monitor.cpp: waiting for bridge to be up, and also protecting
55+ the on_change call (LP: #1408137)
56+
57+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Thu, 08 Jan 2015 12:58:01 +0000
58+
59+media-hub (2.0.0+15.04.20141120.1-0ubuntu1) vivid; urgency=low
60+
61+ [ Jim Hodapp ]
62+ * Pause playback when a headphone is unplugged or an A2DP device is
63+ unpaired (LP: #1368300)
64+
65+ [ Ricardo Mendoza ]
66+ * Pause playback when a headphone is unplugged or an A2DP device is
67+ unpaired (LP: #1368300)
68+
69+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Thu, 20 Nov 2014 18:33:08 +0000
70+
71+media-hub (2.0.0+15.04.20141111-0ubuntu1) vivid; urgency=low
72+
73+ [ Ubuntu daily release ]
74+ * New rebuild forced
75+
76+ [ Justin McPherson ]
77+ * #1239432 Music fails to pause on incoming/outgoing calls (LP:
78+ #1239432)
79+
80+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Tue, 11 Nov 2014 20:18:50 +0000
81+
82+media-hub (2.0.0+15.04.20141110.1-0ubuntu1) vivid; urgency=low
83+
84+ [ thomas-voss ]
85+ * Bump build dependency on dbus-cpp to pull in exception safe dtor.
86+ (LP: #1390618)
87+
88+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Mon, 10 Nov 2014 11:53:11 +0000
89+
90+media-hub (2.0.0+15.04.20141105.1-0ubuntu1) vivid; urgency=low
91+
92+ [ Ricardo Mendoza ]
93+ * Use new hybris interface to correctly register for client deaths.
94+ (LP: #1380848)
95+
96+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Wed, 05 Nov 2014 20:41:14 +0000
97+
98+media-hub (2.0.0+15.04.20141105-0ubuntu1) vivid; urgency=low
99+
100+ [ thomas-voss ]
101+ * Disconnect signal translation layer on destruction. (LP: #1386803)
102+
103+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Wed, 05 Nov 2014 08:24:08 +0000
104+
105+media-hub (2.0.0+15.04.20141104-0ubuntu1) vivid; urgency=low
106+
107+ * New rebuild forced
108+
109+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Tue, 04 Nov 2014 06:10:54 +0000
110+
111+>>>>>>> MERGE-SOURCE
112 media-hub (2.0.0+14.10.20141030~rtm-0ubuntu1) 14.09; urgency=low
113
114 [ thomas-voss ]
115
116=== modified file 'debian/control'
117--- debian/control 2015-03-12 03:06:29 +0000
118+++ debian/control 2015-03-31 21:19:24 +0000
119@@ -26,10 +26,17 @@
120 libproperties-cpp-dev,
121 libgstreamer1.0-dev,
122 pkg-config,
123+<<<<<<< TREE
124 libpulse-dev,
125 qtbase5-dev,
126 libtelepathy-qt5-dev,
127 Standards-Version: 3.9.6
128+=======
129+ libpulse-dev,
130+ qtbase5-dev,
131+ libtelepathy-qt5-dev,
132+Standards-Version: 3.9.5
133+>>>>>>> MERGE-SOURCE
134 Homepage: https://launchpad.net/media-hub
135 # If you aren't a member of ~phablet-team but need to upload packaging changes,
136 # just go ahead. ~phablet-team will notice and sync up the code again.
137
138=== modified file 'include/core/media/player.h'
139--- include/core/media/player.h 2015-01-19 21:48:01 +0000
140+++ include/core/media/player.h 2015-03-31 21:19:24 +0000
141@@ -95,6 +95,7 @@
142 rotate270
143 };
144
145+<<<<<<< TREE
146 enum Lifetime
147 {
148 normal,
149@@ -111,6 +112,18 @@
150 service_missing_error
151 };
152
153+=======
154+ enum Error
155+ {
156+ no_error,
157+ resource_error,
158+ format_error,
159+ network_error,
160+ access_denied_error,
161+ service_missing_error
162+ };
163+
164+>>>>>>> MERGE-SOURCE
165 Player(const Player&) = delete;
166 virtual ~Player();
167
168
169=== added directory 'src/core/media/call-monitor'
170=== renamed directory 'src/core/media/call-monitor' => 'src/core/media/call-monitor.moved'
171=== added file 'src/core/media/call-monitor/CMakeLists.txt'
172--- src/core/media/call-monitor/CMakeLists.txt 1970-01-01 00:00:00 +0000
173+++ src/core/media/call-monitor/CMakeLists.txt 2015-03-31 21:19:24 +0000
174@@ -0,0 +1,23 @@
175+SET (CMAKE_INCLUDE_CURRENT_DIR ON)
176+SET (CMAKE_AUTOMOC ON)
177+
178+find_package(Qt5Core REQUIRED)
179+find_package(PkgConfig REQUIRED)
180+pkg_check_modules(TP_QT5 REQUIRED TelepathyQt5)
181+
182+#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -pedantic -Wextra -fPIC -pthread")
183+
184+include_directories(
185+ ${TP_QT5_INCLUDE_DIRS}
186+)
187+
188+add_library(call-monitor STATIC
189+ call_monitor.cpp
190+ qtbridge.cpp
191+)
192+
193+target_link_libraries(call-monitor
194+ ${TP_QT5_LIBRARIES}
195+)
196+
197+qt5_use_modules(call-monitor Core DBus)
198
199=== added file 'src/core/media/call-monitor/call_monitor.cpp'
200--- src/core/media/call-monitor/call_monitor.cpp 1970-01-01 00:00:00 +0000
201+++ src/core/media/call-monitor/call_monitor.cpp 2015-03-31 21:19:24 +0000
202@@ -0,0 +1,222 @@
203+/*
204+ * Copyright (C) 2014 Canonical Ltd
205+ *
206+ * This program is free software: you can redistribute it and/or modify
207+ * it under the terms of the GNU Lesser General Public License version 3 as
208+ * published by the Free Software Foundation.
209+ *
210+ * This program is distributed in the hope that it will be useful,
211+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
212+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
213+ * GNU Lesser General Public License for more details.
214+ *
215+ * You should have received a copy of the GNU Lesser General Public License
216+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
217+ *
218+ * Author: Justin McPherson <justin.mcpherson@canonical.com>
219+ */
220+
221+
222+#include "call_monitor.h"
223+
224+#include "qtbridge.h"
225+#include <TelepathyQt/AccountManager>
226+#include <TelepathyQt/SimpleCallObserver>
227+#include <TelepathyQt/PendingOperation>
228+#include <TelepathyQt/PendingReady>
229+#include <TelepathyQt/PendingAccount>
230+
231+#include <list>
232+#include <mutex>
233+
234+
235+namespace {
236+class TelepathyCallMonitor : public QObject
237+{
238+ Q_OBJECT
239+public:
240+ TelepathyCallMonitor(const Tp::AccountPtr& account):
241+ mAccount(account),
242+ mCallObserver(Tp::SimpleCallObserver::create(mAccount)) {
243+ connect(mCallObserver.data(), SIGNAL(callStarted(Tp::CallChannelPtr)), SIGNAL(offHook()));
244+ connect(mCallObserver.data(), SIGNAL(callEnded(Tp::CallChannelPtr,QString,QString)), SIGNAL(onHook()));
245+ connect(mCallObserver.data(), SIGNAL(streamedMediaCallStarted(Tp::StreamedMediaChannelPtr)), SIGNAL(offHook()));
246+ connect(mCallObserver.data(), SIGNAL(streamedMediaCallEnded(Tp::StreamedMediaChannelPtr,QString,QString)), SIGNAL(onHook()));
247+ }
248+
249+Q_SIGNALS:
250+ void offHook();
251+ void onHook();
252+
253+private:
254+ Tp::AccountPtr mAccount;
255+ Tp::SimpleCallObserverPtr mCallObserver;
256+};
257+
258+
259+class TelepathyBridge : public QObject
260+{
261+ Q_OBJECT
262+public:
263+ TelepathyBridge():
264+ QObject(0) {
265+ Tp::registerTypes();
266+
267+ QTimer::singleShot(0, this, SLOT(accountManagerSetup()));
268+ }
269+
270+ ~TelepathyBridge() {
271+ for (std::list<TelepathyCallMonitor*>::iterator it = mCallMonitors.begin();
272+ it != mCallMonitors.end();
273+ ++it) {
274+ delete *it;
275+ }
276+ }
277+
278+ void on_change(const std::function<void(CallMonitor::State)>& func) {
279+ std::lock_guard<std::mutex> l(cb_lock);
280+ cb = func;
281+ }
282+
283+private Q_SLOTS:
284+ void accountManagerSetup() {
285+ mAccountManager = Tp::AccountManager::create(Tp::AccountFactory::create(QDBusConnection::sessionBus(),
286+ Tp::Account::FeatureCore),
287+ Tp::ConnectionFactory::create(QDBusConnection::sessionBus(),
288+ Tp::Connection::FeatureCore));
289+ connect(mAccountManager->becomeReady(),
290+ SIGNAL(finished(Tp::PendingOperation*)),
291+ SLOT(accountManagerReady(Tp::PendingOperation*)));
292+ }
293+
294+ void accountManagerReady(Tp::PendingOperation* operation) {
295+ if (operation->isError()) {
296+ std::cerr << "TelepathyBridge: Operation failed (accountManagerReady)" << std::endl;
297+ QTimer::singleShot(1000, this, SLOT(accountManagerSetup())); // again
298+ return;
299+ }
300+
301+ Q_FOREACH(const Tp::AccountPtr& account, mAccountManager->allAccounts()) {
302+ connect(account->becomeReady(Tp::Account::FeatureCapabilities),
303+ SIGNAL(finished(Tp::PendingOperation*)),
304+ SLOT(accountReady(Tp::PendingOperation*)));
305+ }
306+
307+ connect(mAccountManager.data(), SIGNAL(newAccount(Tp::AccountPtr)), SLOT(newAccount(Tp::AccountPtr)));
308+ }
309+
310+ void newAccount(const Tp::AccountPtr& account)
311+ {
312+ connect(account->becomeReady(Tp::Account::FeatureCapabilities),
313+ SIGNAL(finished(Tp::PendingOperation*)),
314+ SLOT(accountReady(Tp::PendingOperation*)));
315+ }
316+
317+ void accountReady(Tp::PendingOperation* operation) {
318+ if (operation->isError()) {
319+ std::cerr << "TelepathyAccount: Operation failed (accountReady)" << std::endl;
320+ return;
321+ }
322+
323+ Tp::PendingReady* pendingReady = qobject_cast<Tp::PendingReady*>(operation);
324+ if (pendingReady == 0) {
325+ std::cerr << "Rejecting account because could not understand ready status" << std::endl;
326+ return;
327+ }
328+
329+ checkAndAddAccount(Tp::AccountPtr::qObjectCast(pendingReady->proxy()));
330+ }
331+
332+ void offHook()
333+ {
334+ std::lock_guard<std::mutex> l(cb_lock);
335+ if (cb)
336+ cb(CallMonitor::OffHook);
337+ }
338+
339+ void onHook()
340+ {
341+ std::lock_guard<std::mutex> l(cb_lock);
342+ if (cb)
343+ cb(CallMonitor::OnHook);
344+ }
345+
346+private:
347+ std::mutex cb_lock;
348+ std::function<void (CallMonitor::State)> cb;
349+ Tp::AccountManagerPtr mAccountManager;
350+ std::list<TelepathyCallMonitor*> mCallMonitors;
351+
352+ void checkAndAddAccount(const Tp::AccountPtr& account)
353+ {
354+ Tp::ConnectionCapabilities caps = account->capabilities();
355+ // TODO: Later on we will need to filter for the right capabilities, and also allow dynamic account detection
356+ // Don't check caps for now as a workaround for https://bugs.launchpad.net/ubuntu/+source/media-hub/+bug/1409125
357+ // at least until we are able to find out the root cause of it (check rev 107 for the caps check)
358+ auto tcm = new TelepathyCallMonitor(account);
359+ connect(tcm, SIGNAL(offHook()), SLOT(offHook()));
360+ connect(tcm, SIGNAL(onHook()), SLOT(onHook()));
361+ mCallMonitors.push_back(tcm);
362+ }
363+};
364+}
365+
366+class CallMonitorPrivate
367+{
368+public:
369+ CallMonitorPrivate() {
370+ mBridge = nullptr;
371+ try {
372+ std::thread([this]() {
373+ qt::core::world::build_and_run(0, nullptr, [this]() {
374+ qt::core::world::enter_with_task([this]() {
375+ std::cout << "CallMonitor: Creating TelepathyBridge" << std::endl;
376+ mBridge = new TelepathyBridge();
377+ cv.notify_all();
378+ });
379+ });
380+ }).detach();
381+ } catch(const std::system_error& error) {
382+ std::cerr << "exception(std::system_error) in CallMonitor thread start" << error.what() << std::endl;
383+ } catch(...) {
384+ std::cerr << "exception(...) in CallMonitor thread start" << std::endl;
385+ }
386+ // Wait until telepathy bridge is set, so we can hook up the change signals
387+ std::unique_lock<std::mutex> lck(mtx);
388+ cv.wait_for(lck, std::chrono::seconds(3));
389+ }
390+
391+ ~CallMonitorPrivate() {
392+ qt::core::world::destroy();
393+ }
394+
395+ TelepathyBridge *mBridge;
396+
397+private:
398+ std::mutex mtx;
399+ std::condition_variable cv;
400+};
401+
402+
403+CallMonitor::CallMonitor():
404+ d(new CallMonitorPrivate)
405+{
406+}
407+
408+CallMonitor::~CallMonitor()
409+{
410+ delete d->mBridge;
411+ delete d;
412+}
413+
414+void CallMonitor::on_change(const std::function<void(CallMonitor::State)>& func)
415+{
416+ if (d->mBridge != nullptr) {
417+ std::cout << "CallMonitor: Setting up callback for TelepathyBridge on_change" << std::endl;
418+ d->mBridge->on_change(func);
419+ } else
420+ std::cerr << "TelepathyBridge: Failed to hook on_change signal, bridge not yet set" << std::endl;
421+}
422+
423+#include "call_monitor.moc"
424+
425
426=== added file 'src/core/media/call-monitor/call_monitor.h'
427--- src/core/media/call-monitor/call_monitor.h 1970-01-01 00:00:00 +0000
428+++ src/core/media/call-monitor/call_monitor.h 2015-03-31 21:19:24 +0000
429@@ -0,0 +1,41 @@
430+/*
431+ * Copyright (C) 2014 Canonical Ltd
432+ *
433+ * This program is free software: you can redistribute it and/or modify
434+ * it under the terms of the GNU Lesser General Public License version 3 as
435+ * published by the Free Software Foundation.
436+ *
437+ * This program is distributed in the hope that it will be useful,
438+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
439+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
440+ * GNU Lesser General Public License for more details.
441+ *
442+ * You should have received a copy of the GNU Lesser General Public License
443+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
444+ *
445+ * Author: Justin McPherson <justin.mcpherson@canonical.com>
446+ */
447+
448+
449+#ifndef CALLMONITOR_H
450+#define CALLMONITOR_H
451+
452+#include <functional>
453+
454+class CallMonitorPrivate;
455+
456+class CallMonitor
457+{
458+public:
459+ enum State { OffHook, OnHook };
460+
461+ CallMonitor();
462+ ~CallMonitor();
463+
464+ void on_change(const std::function<void(CallMonitor::State)>& func);
465+
466+private:
467+ CallMonitorPrivate *d;
468+};
469+
470+#endif // CALLMONITOR_H
471
472=== added file 'src/core/media/call-monitor/qtbridge.cpp'
473--- src/core/media/call-monitor/qtbridge.cpp 1970-01-01 00:00:00 +0000
474+++ src/core/media/call-monitor/qtbridge.cpp 2015-03-31 21:19:24 +0000
475@@ -0,0 +1,186 @@
476+/*
477+ * Copyright © 2014 Canonical Ltd.
478+ *
479+ * This program is free software: you can redistribute it and/or modify it
480+ * under the terms of the GNU Lesser General Public License version 3,
481+ * as published by the Free Software Foundation.
482+ *
483+ * This program is distributed in the hope that it will be useful,
484+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
485+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
486+ * GNU Lesser General Public License for more details.
487+ *
488+ * You should have received a copy of the GNU Lesser General Public License
489+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
490+ *
491+ * Authored by: Jussi Pakkanen <jussi.pakkanen@canonical.com>
492+ * Thomas Voß <thomas.voss@canonical.com>
493+ */
494+
495+#include "qtbridge.h"
496+
497+#include<QCoreApplication>
498+#include<QNetworkAccessManager>
499+#include<QNetworkRequest>
500+#include<QNetworkReply>
501+#include<QThread>
502+#include<QDebug>
503+
504+#include <iostream>
505+
506+namespace
507+{
508+QCoreApplication* app = nullptr;
509+}
510+
511+namespace qt
512+{
513+namespace core
514+{
515+namespace world
516+{
517+namespace detail
518+{
519+QEvent::Type qt_core_world_task_event_type()
520+{
521+ static QEvent::Type event_type = static_cast<QEvent::Type>(QEvent::registerEventType());
522+ return event_type;
523+}
524+
525+class TaskEvent : public QEvent
526+{
527+public:
528+ TaskEvent(const std::function<void()>& task)
529+ : QEvent(qt_core_world_task_event_type()),
530+ task(task)
531+ {
532+ }
533+
534+ void run()
535+ {
536+ try
537+ {
538+ task();
539+ promise.set_value();
540+ } catch(...)
541+ {
542+ promise.set_exception(std::current_exception());
543+ }
544+ }
545+
546+ std::future<void> get_future()
547+ {
548+ return promise.get_future();
549+ }
550+
551+private:
552+ std::function<void()> task;
553+ std::promise<void> promise;
554+};
555+
556+class TaskHandler : public QObject
557+{
558+ Q_OBJECT
559+
560+public:
561+ TaskHandler(QObject* parent) : QObject(parent)
562+ {
563+ }
564+
565+ bool event(QEvent* e);
566+};
567+
568+
569+
570+void createCoreApplicationInstanceWithArgs(int argc, char** argv)
571+{
572+ app = new QCoreApplication(argc, argv);
573+}
574+
575+void destroyCoreApplicationInstace()
576+{
577+ delete app;
578+}
579+
580+QCoreApplication* coreApplicationInstance()
581+{
582+ return app;
583+}
584+
585+TaskHandler* task_handler()
586+{
587+ static TaskHandler* instance = new TaskHandler(coreApplicationInstance());
588+ return instance;
589+}
590+
591+bool TaskHandler::event(QEvent *e)
592+{
593+ if (e->type() != qt_core_world_task_event_type())
594+ return QObject::event(e);
595+
596+ auto te = dynamic_cast<TaskEvent*>(e);
597+ if (te)
598+ {
599+ te->run();
600+ return true;
601+ }
602+
603+ return false;
604+}
605+}
606+
607+void build_and_run(int argc, char** argv, const std::function<void()>& ready)
608+{
609+ QThread::currentThread();
610+ if (QCoreApplication::instance() != nullptr)
611+ throw std::runtime_error(
612+ "qt::core::world::build_and_run: "
613+ "There is already a QCoreApplication running.");
614+
615+ detail::createCoreApplicationInstanceWithArgs(argc, argv);
616+
617+ detail::task_handler()->moveToThread(
618+ detail::coreApplicationInstance()->thread());
619+
620+ // Signal to other worlds that we are good to go.
621+ ready();
622+
623+ detail::coreApplicationInstance()->exec();
624+
625+ // Someone has called quit and we clean up on the correct thread here.
626+ detail::destroyCoreApplicationInstace();
627+}
628+
629+void destroy()
630+{
631+ enter_with_task([]()
632+ {
633+ // We make sure that all tasks have completed before quitting the app.
634+ QEventLoopLocker locker;
635+ }).wait_for(std::chrono::seconds{1});
636+}
637+
638+std::future<void> enter_with_task(const std::function<void()>& task)
639+{
640+ QCoreApplication* instance = QCoreApplication::instance();
641+
642+ if (!instance)
643+ {
644+ throw std::runtime_error("Qt world has not been built before calling this function.");
645+ }
646+
647+ detail::TaskEvent* te = new detail::TaskEvent(task);
648+ auto future = te->get_future();
649+
650+ // We hand over ownership of te here. The event is deleted later after it has
651+ // been processed by the event loop.
652+ instance->postEvent(detail::task_handler(), te);
653+
654+ return future;
655+}
656+
657+}
658+}
659+}
660+
661+#include "qtbridge.moc"
662
663=== added file 'src/core/media/call-monitor/qtbridge.h'
664--- src/core/media/call-monitor/qtbridge.h 1970-01-01 00:00:00 +0000
665+++ src/core/media/call-monitor/qtbridge.h 2015-03-31 21:19:24 +0000
666@@ -0,0 +1,87 @@
667+/*
668+ * Copyright © 2014 Canonical Ltd.
669+ *
670+ * This program is free software: you can redistribute it and/or modify it
671+ * under the terms of the GNU Lesser General Public License version 3,
672+ * as published by the Free Software Foundation.
673+ *
674+ * This program is distributed in the hope that it will be useful,
675+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
676+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
677+ * GNU Lesser General Public License for more details.
678+ *
679+ * You should have received a copy of the GNU Lesser General Public License
680+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
681+ *
682+ * Authored by: Jussi Pakkanen <jussi.pakkanen@canonical.com>
683+ * Thomas Voß <thomas.voss@canonical.com>
684+ */
685+
686+#ifndef QT_CORE_WORLD_BRIDGE_H_
687+#define QT_CORE_WORLD_BRIDGE_H_
688+
689+#include <QObject>
690+
691+#include <functional>
692+#include <future>
693+#include <iostream>
694+
695+namespace qt
696+{
697+namespace core
698+{
699+namespace world
700+{
701+/**
702+ * @brief Sets up the Qt core world and executes its event loop. Blocks until destroy() is called.
703+ * @param argc Number of arguments in argv.
704+ * @param argv Array of command-line arguments.
705+ * @param ready Functor be called when the world has been setup and is about to be executed.
706+ * @throw std::runtime_error in case of errors.
707+ */
708+void build_and_run(int argc, char** argv, const std::function<void()>& ready);
709+
710+/**
711+ * @brief Destroys the Qt core world and quits its event loop.
712+ */
713+void destroy();
714+
715+/**
716+ * @brief Enters the Qt core world and schedules the given task for execution.
717+ * @param task The task to be executed in the Qt core world.
718+ * @return A std::future that can be waited for to synchronize to the world's internal event loop.
719+ */
720+std::future<void> enter_with_task(const std::function<void()>& task);
721+
722+
723+/**
724+ * @brief Enters the Qt core world and schedules the given task for execution.
725+ * @param task The task to be executed in the Qt core world.
726+ * @return A std::future that can be waited for to get hold of the result of the task.
727+ */
728+template<typename T>
729+inline std::future<T> enter_with_task_and_expect_result(const std::function<T()>& task)
730+{
731+ std::shared_ptr<std::promise<T>> promise = std::make_shared<std::promise<T>>();
732+ std::future<T> future = promise->get_future();
733+
734+ auto t = [promise, task]()
735+ {
736+ try
737+ {
738+ promise->set_value(task());
739+ } catch(...)
740+ {
741+ promise->set_exception(std::current_exception());
742+ }
743+ };
744+
745+ enter_with_task(t);
746+
747+ return future;
748+}
749+}
750+}
751+}
752+
753+#endif // QT_CORE_WORLD_BRIDGE_H_
754
755=== modified file 'src/core/media/codec.h'
756--- src/core/media/codec.h 2015-01-13 14:18:59 +0000
757+++ src/core/media/codec.h 2015-03-31 21:19:24 +0000
758@@ -230,6 +230,7 @@
759 }
760 };
761
762+<<<<<<< TREE
763 namespace helper
764 {
765 template<>
766@@ -310,6 +311,48 @@
767 }
768 };
769
770+=======
771+namespace helper
772+{
773+template<>
774+struct TypeMapper<core::ubuntu::media::Player::Error>
775+{
776+ constexpr static ArgumentType type_value()
777+ {
778+ return core::dbus::ArgumentType::int16;
779+ }
780+ constexpr static bool is_basic_type()
781+ {
782+ return false;
783+ }
784+ constexpr static bool requires_signature()
785+ {
786+ return false;
787+ }
788+
789+ static std::string signature()
790+ {
791+ static const std::string s = TypeMapper<std::int16_t>::signature();
792+ return s;
793+ }
794+};
795+}
796+
797+template<>
798+struct Codec<core::ubuntu::media::Player::Error>
799+{
800+ static void encode_argument(core::dbus::Message::Writer& out, const core::ubuntu::media::Player::Error& in)
801+ {
802+ out.push_int16(static_cast<std::int16_t>(in));
803+ }
804+
805+ static void decode_argument(core::dbus::Message::Reader& out, core::ubuntu::media::Player::Error& in)
806+ {
807+ in = static_cast<core::ubuntu::media::Player::Error>(out.pop_int16());
808+ }
809+};
810+
811+>>>>>>> MERGE-SOURCE
812 }
813 }
814
815
816=== modified file 'src/core/media/engine.h'
817=== modified file 'src/core/media/gstreamer/engine.cpp'
818=== modified file 'src/core/media/gstreamer/engine.h'
819=== modified file 'src/core/media/gstreamer/playbin.h'
820--- src/core/media/gstreamer/playbin.h 2014-11-11 23:59:07 +0000
821+++ src/core/media/gstreamer/playbin.h 2015-03-31 21:19:24 +0000
822@@ -109,6 +109,7 @@
823 G_CALLBACK(about_to_finish),
824 this
825 );
826+<<<<<<< TREE
827
828 g_signal_connect(
829 pipeline,
830@@ -117,6 +118,8 @@
831 this
832 );
833
834+=======
835+>>>>>>> MERGE-SOURCE
836 }
837
838 ~Playbin()
839
840=== modified file 'src/core/media/mpris/player.h'
841=== modified file 'src/core/media/player_implementation.cpp'
842=== modified file 'src/core/media/player_implementation.h'
843=== modified file 'src/core/media/player_skeleton.cpp'
844=== modified file 'src/core/media/player_skeleton.h'
845=== modified file 'src/core/media/player_stub.cpp'
846=== modified file 'src/core/media/player_stub.h'
847=== modified file 'src/core/media/service_implementation.cpp'
848--- src/core/media/service_implementation.cpp 2015-01-16 17:17:30 +0000
849+++ src/core/media/service_implementation.cpp 2015-03-31 21:19:24 +0000
850@@ -35,6 +35,9 @@
851 #include <map>
852 #include <memory>
853 #include <thread>
854+#include <utility>
855+
856+#include <pulse/pulseaudio.h>
857
858 #include <pulse/pulseaudio.h>
859
860@@ -460,6 +463,7 @@
861 int disp_cookie;
862 std::shared_ptr<dbus::Object> uscreen_session;
863 MediaRecorderObserver *observer;
864+<<<<<<< TREE
865
866 // Pulse-specific
867 pa_mainloop_api *pulse_mainloop_api;
868@@ -479,6 +483,29 @@
869 core::Signal<void> pause_playback;
870 std::unique_ptr<CallMonitor> call_monitor;
871 std::list<media::Player::PlayerKey> paused_sessions;
872+=======
873+
874+ // Pulse-specific
875+ pa_mainloop_api *pulse_mainloop_api;
876+ pa_threaded_mainloop *pulse_mainloop;
877+ pa_context *pulse_context;
878+ std::thread pulse_worker;
879+ std::mutex pulse_mutex;
880+ std::condition_variable pcv;
881+ bool headphones_connected;
882+ bool a2dp_connected;
883+ std::tuple<int, int, std::string> active_sink;
884+ int primary_idx;
885+
886+ // Gets signaled when both the headphone jack is removed or an A2DP device is
887+ // disconnected and playback needs pausing. Also gets signaled when recording
888+ // begins.
889+ core::Signal<void> pause_playback;
890+ std::unique_ptr<CallMonitor> call_monitor;
891+ // Holds a pair of a Player key denoting what player to resume playback, and a bool
892+ // for if it should be resumed after a phone call is hung up
893+ std::list<std::pair<media::Player::PlayerKey, bool>> paused_sessions;
894+>>>>>>> MERGE-SOURCE
895 };
896
897 media::ServiceImplementation::ServiceImplementation() : d(new Private())
898@@ -488,7 +515,9 @@
899 // When the battery level hits 10% or 5%, pause all multimedia sessions.
900 // Playback will resume when the user clears the presented notification.
901 if (level == "low" || level == "very_low")
902- pause_all_multimedia_sessions();
903+ // Whatever player session is currently playing, make sure it is NOT resumed after
904+ // a phonecall is hung up
905+ pause_all_multimedia_sessions(false);
906 });
907
908 d->is_warning->changed().connect([this](const core::IndicatorPower::IsWarning::ValueType &notifying)
909@@ -498,6 +527,7 @@
910 if (!notifying)
911 resume_multimedia_session();
912 });
913+<<<<<<< TREE
914
915 d->pause_playback.connect([this]()
916 {
917@@ -518,6 +548,32 @@
918 break;
919 }
920 });
921+=======
922+
923+ d->pause_playback.connect([this]()
924+ {
925+ std::cout << "Got pause_playback signal, pausing all multimedia sessions" << std::endl;
926+ // Whatever player session is currently playing, make sure it is NOT resumed after
927+ // a phonecall is hung up
928+ pause_all_multimedia_sessions(false);
929+ });
930+
931+ d->call_monitor->on_change([this](CallMonitor::State state) {
932+ switch (state) {
933+ case CallMonitor::OffHook:
934+ std::cout << "Got call started signal, pausing all multimedia sessions" << std::endl;
935+ // Whatever player session is currently playing, make sure it gets resumed after
936+ // a phonecall is hung up
937+ pause_all_multimedia_sessions(true);
938+ break;
939+ case CallMonitor::OnHook:
940+ std::cout << "Got call ended signal, resuming paused multimedia sessions" << std::endl;
941+ // Don't auto-resume any paused video playback sessions
942+ resume_paused_multimedia_sessions(false);
943+ break;
944+ }
945+ });
946+>>>>>>> MERGE-SOURCE
947 }
948
949 media::ServiceImplementation::~ServiceImplementation()
950@@ -595,20 +651,27 @@
951 });
952 }
953
954-void media::ServiceImplementation::pause_all_multimedia_sessions()
955+void media::ServiceImplementation::pause_all_multimedia_sessions(bool resume_play_after_phonecall)
956 {
957- enumerate_players([this](const media::Player::PlayerKey& key, const std::shared_ptr<media::Player>& player)
958+ enumerate_players([this, resume_play_after_phonecall](const media::Player::PlayerKey& key, const std::shared_ptr<media::Player>& player)
959 {
960 if (player->playback_status() == Player::playing
961 && player->audio_stream_role() == media::Player::multimedia)
962 {
963+<<<<<<< TREE
964 d->paused_sessions.push_back(key);
965 std::cout << "Pausing Player with key: " << key << std::endl;
966+=======
967+ auto paused_player_pair = std::make_pair(key, resume_play_after_phonecall);
968+ d->paused_sessions.push_back(paused_player_pair);
969+ std::cout << "Pausing Player with key: " << key << std::endl;
970+>>>>>>> MERGE-SOURCE
971 player->pause();
972 }
973 });
974 }
975
976+<<<<<<< TREE
977 void media::ServiceImplementation::resume_paused_multimedia_sessions(bool resume_video_sessions)
978 {
979 std::for_each(d->paused_sessions.begin(), d->paused_sessions.end(), [this, resume_video_sessions](const media::Player::PlayerKey& key) {
980@@ -623,6 +686,25 @@
981 d->paused_sessions.clear();
982 }
983
984+=======
985+void media::ServiceImplementation::resume_paused_multimedia_sessions(bool resume_video_sessions)
986+{
987+ std::for_each(d->paused_sessions.begin(), d->paused_sessions.end(),
988+ [this, resume_video_sessions](const std::pair<media::Player::PlayerKey, bool> &paused_player_pair) {
989+ const media::Player::PlayerKey key = paused_player_pair.first;
990+ const bool resume_play_after_phonecall = paused_player_pair.second;
991+ auto player = player_for_key(key);
992+ // Only resume video playback if explicitly desired
993+ if ((resume_video_sessions || player->is_audio_source()) && resume_play_after_phonecall)
994+ player->play();
995+ else
996+ std::cout << "Not auto-resuming video player session or other type of player session." << std::endl;
997+ });
998+
999+ d->paused_sessions.clear();
1000+}
1001+
1002+>>>>>>> MERGE-SOURCE
1003 void media::ServiceImplementation::resume_multimedia_session()
1004 {
1005 if (not has_player_for_key(d->resume_key))
1006
1007=== modified file 'src/core/media/service_implementation.h'
1008--- src/core/media/service_implementation.h 2015-01-16 17:17:30 +0000
1009+++ src/core/media/service_implementation.h 2015-03-31 21:19:24 +0000
1010@@ -42,8 +42,13 @@
1011 void pause_other_sessions(Player::PlayerKey key);
1012
1013 private:
1014+<<<<<<< TREE
1015 void pause_all_multimedia_sessions();
1016 void resume_paused_multimedia_sessions(bool resume_video_sessions = true);
1017+=======
1018+ void pause_all_multimedia_sessions(bool resume_play_after_phonecall);
1019+ void resume_paused_multimedia_sessions(bool resume_video_sessions = true);
1020+>>>>>>> MERGE-SOURCE
1021 void resume_multimedia_session();
1022
1023 struct Private;
1024
1025=== modified file 'src/core/media/service_skeleton.cpp'
1026=== modified file 'tests/unit-tests/CMakeLists.txt'
1027--- tests/unit-tests/CMakeLists.txt 2014-11-18 20:29:26 +0000
1028+++ tests/unit-tests/CMakeLists.txt 2015-03-31 21:19:24 +0000
1029@@ -41,8 +41,12 @@
1030 ${PC_GSTREAMER_1_0_LIBRARIES}
1031 ${PROCESS_CPP_LDFLAGS}
1032 ${GIO_LIBRARIES}
1033+<<<<<<< TREE
1034 ${PROCESS_CPP_LIBRARIES}
1035 ${PC_PULSE_AUDIO_LIBRARIES}
1036+=======
1037+ ${PC_PULSE_AUDIO_LIBRARIES}
1038+>>>>>>> MERGE-SOURCE
1039
1040 gmock
1041 gmock_main
1042
1043=== modified file 'tests/unit-tests/test-gstreamer-engine.cpp'
1044--- tests/unit-tests/test-gstreamer-engine.cpp 2015-03-03 22:41:22 +0000
1045+++ tests/unit-tests/test-gstreamer-engine.cpp 2015-03-31 21:19:24 +0000
1046@@ -155,6 +155,7 @@
1047 std::chrono::seconds{10}));
1048 }
1049
1050+<<<<<<< TREE
1051 TEST(GStreamerEngine, setting_uri_and_audio_playback_with_http_headers_works)
1052 {
1053 const std::string test_file{"/tmp/test-audio-1.ogg"};
1054@@ -222,6 +223,14 @@
1055 const std::string test_file_uri{"file:///tmp/test-audio.ogg"};
1056 std::remove(test_file.c_str());
1057 ASSERT_TRUE(test::copy_test_media_file_to("test-audio.ogg", test_file));
1058+=======
1059+TEST(GStreamerEngine, DISABLED_stop_pause_play_seek_audio_only_works)
1060+{
1061+ const std::string test_file{"/tmp/test.ogg"};
1062+ const std::string test_file_uri{"file:///tmp/test.ogg"};
1063+ std::remove(test_file.c_str());
1064+ ASSERT_TRUE(test::copy_test_mp3_file_to(test_file));
1065+>>>>>>> MERGE-SOURCE
1066
1067 core::testing::WaitableStateTransition<core::ubuntu::media::Engine::State> wst(
1068 core::ubuntu::media::Engine::State::ready);

Subscribers

People subscribed via source and target branches