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
=== modified file 'CMakeLists.txt'
=== modified file 'debian/changelog'
--- debian/changelog 2015-03-12 03:06:40 +0000
+++ debian/changelog 2015-03-31 21:19:24 +0000
@@ -1,3 +1,4 @@
1<<<<<<< TREE
1media-hub (2.0.0+15.04.20150303-0ubuntu2) vivid; urgency=medium2media-hub (2.0.0+15.04.20150303-0ubuntu2) vivid; urgency=medium
23
3 * debian/control:4 * debian/control:
@@ -122,6 +123,104 @@
122123
123 -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Tue, 04 Nov 2014 06:10:54 +0000124 -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Tue, 04 Nov 2014 06:10:54 +0000
124125
126=======
127media-hub (2.0.0+15.04.20150120~rtm-0ubuntu1) 14.09; urgency=low
128
129 [ Jim Hodapp ]
130 * Error reporting all the way up to the app level from the playbin
131 pipeline (LP: #1413824).
132
133 [ Ubuntu daily release ]
134 * New rebuild forced
135
136 -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Tue, 20 Jan 2015 01:21:47 +0000
137
138media-hub (2.0.0+15.04.20150116-0ubuntu1) vivid; urgency=low
139
140 [ Jim Hodapp ]
141 * Don't auto-resume playback of videos after a phone call ends. (LP:
142 #1411273)
143
144 -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Fri, 16 Jan 2015 18:17:56 +0000
145
146media-hub (2.0.0+15.04.20150112.2-0ubuntu1) vivid; urgency=low
147
148 [ Ubuntu daily release ]
149 * New rebuild forced
150
151 [ Ricardo Salveti de Araujo ]
152 * service_implementation: adding debug for call started/ended signals.
153 Make sure account and connection are available when setting up
154 account manager (patch from Gustavo Boiko). call_monitor: don't
155 check caps when hooking up on/off signals, until bug 1409125 is
156 fixed. Enable parallel building . (LP: #1409125)
157
158 -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Mon, 12 Jan 2015 21:38:39 +0000
159
160media-hub (2.0.0+15.04.20150108-0ubuntu1) vivid; urgency=low
161
162 [ Jim Hodapp ]
163 * Pause playback when recording begins. (LP: #1398047)
164
165 [ Ricardo Salveti de Araujo ]
166 * call_monitor.cpp: waiting for bridge to be up, and also protecting
167 the on_change call (LP: #1408137)
168
169 -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Thu, 08 Jan 2015 12:58:01 +0000
170
171media-hub (2.0.0+15.04.20141120.1-0ubuntu1) vivid; urgency=low
172
173 [ Jim Hodapp ]
174 * Pause playback when a headphone is unplugged or an A2DP device is
175 unpaired (LP: #1368300)
176
177 [ Ricardo Mendoza ]
178 * Pause playback when a headphone is unplugged or an A2DP device is
179 unpaired (LP: #1368300)
180
181 -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Thu, 20 Nov 2014 18:33:08 +0000
182
183media-hub (2.0.0+15.04.20141111-0ubuntu1) vivid; urgency=low
184
185 [ Ubuntu daily release ]
186 * New rebuild forced
187
188 [ Justin McPherson ]
189 * #1239432 Music fails to pause on incoming/outgoing calls (LP:
190 #1239432)
191
192 -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Tue, 11 Nov 2014 20:18:50 +0000
193
194media-hub (2.0.0+15.04.20141110.1-0ubuntu1) vivid; urgency=low
195
196 [ thomas-voss ]
197 * Bump build dependency on dbus-cpp to pull in exception safe dtor.
198 (LP: #1390618)
199
200 -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Mon, 10 Nov 2014 11:53:11 +0000
201
202media-hub (2.0.0+15.04.20141105.1-0ubuntu1) vivid; urgency=low
203
204 [ Ricardo Mendoza ]
205 * Use new hybris interface to correctly register for client deaths.
206 (LP: #1380848)
207
208 -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Wed, 05 Nov 2014 20:41:14 +0000
209
210media-hub (2.0.0+15.04.20141105-0ubuntu1) vivid; urgency=low
211
212 [ thomas-voss ]
213 * Disconnect signal translation layer on destruction. (LP: #1386803)
214
215 -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Wed, 05 Nov 2014 08:24:08 +0000
216
217media-hub (2.0.0+15.04.20141104-0ubuntu1) vivid; urgency=low
218
219 * New rebuild forced
220
221 -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Tue, 04 Nov 2014 06:10:54 +0000
222
223>>>>>>> MERGE-SOURCE
125media-hub (2.0.0+14.10.20141030~rtm-0ubuntu1) 14.09; urgency=low224media-hub (2.0.0+14.10.20141030~rtm-0ubuntu1) 14.09; urgency=low
126225
127 [ thomas-voss ]226 [ thomas-voss ]
128227
=== modified file 'debian/control'
--- debian/control 2015-03-12 03:06:29 +0000
+++ debian/control 2015-03-31 21:19:24 +0000
@@ -26,10 +26,17 @@
26 libproperties-cpp-dev,26 libproperties-cpp-dev,
27 libgstreamer1.0-dev,27 libgstreamer1.0-dev,
28 pkg-config,28 pkg-config,
29<<<<<<< TREE
29 libpulse-dev,30 libpulse-dev,
30 qtbase5-dev,31 qtbase5-dev,
31 libtelepathy-qt5-dev,32 libtelepathy-qt5-dev,
32Standards-Version: 3.9.633Standards-Version: 3.9.6
34=======
35 libpulse-dev,
36 qtbase5-dev,
37 libtelepathy-qt5-dev,
38Standards-Version: 3.9.5
39>>>>>>> MERGE-SOURCE
33Homepage: https://launchpad.net/media-hub40Homepage: https://launchpad.net/media-hub
34# If you aren't a member of ~phablet-team but need to upload packaging changes,41# If you aren't a member of ~phablet-team but need to upload packaging changes,
35# just go ahead. ~phablet-team will notice and sync up the code again.42# just go ahead. ~phablet-team will notice and sync up the code again.
3643
=== modified file 'include/core/media/player.h'
--- include/core/media/player.h 2015-01-19 21:48:01 +0000
+++ include/core/media/player.h 2015-03-31 21:19:24 +0000
@@ -95,6 +95,7 @@
95 rotate27095 rotate270
96 };96 };
9797
98<<<<<<< TREE
98 enum Lifetime99 enum Lifetime
99 {100 {
100 normal,101 normal,
@@ -111,6 +112,18 @@
111 service_missing_error112 service_missing_error
112 };113 };
113114
115=======
116 enum Error
117 {
118 no_error,
119 resource_error,
120 format_error,
121 network_error,
122 access_denied_error,
123 service_missing_error
124 };
125
126>>>>>>> MERGE-SOURCE
114 Player(const Player&) = delete;127 Player(const Player&) = delete;
115 virtual ~Player();128 virtual ~Player();
116129
117130
=== added directory 'src/core/media/call-monitor'
=== renamed directory 'src/core/media/call-monitor' => 'src/core/media/call-monitor.moved'
=== added file 'src/core/media/call-monitor/CMakeLists.txt'
--- src/core/media/call-monitor/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ src/core/media/call-monitor/CMakeLists.txt 2015-03-31 21:19:24 +0000
@@ -0,0 +1,23 @@
1SET (CMAKE_INCLUDE_CURRENT_DIR ON)
2SET (CMAKE_AUTOMOC ON)
3
4find_package(Qt5Core REQUIRED)
5find_package(PkgConfig REQUIRED)
6pkg_check_modules(TP_QT5 REQUIRED TelepathyQt5)
7
8#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -pedantic -Wextra -fPIC -pthread")
9
10include_directories(
11 ${TP_QT5_INCLUDE_DIRS}
12)
13
14add_library(call-monitor STATIC
15 call_monitor.cpp
16 qtbridge.cpp
17)
18
19target_link_libraries(call-monitor
20 ${TP_QT5_LIBRARIES}
21)
22
23qt5_use_modules(call-monitor Core DBus)
024
=== added file 'src/core/media/call-monitor/call_monitor.cpp'
--- src/core/media/call-monitor/call_monitor.cpp 1970-01-01 00:00:00 +0000
+++ src/core/media/call-monitor/call_monitor.cpp 2015-03-31 21:19:24 +0000
@@ -0,0 +1,222 @@
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
33namespace {
34class TelepathyCallMonitor : public QObject
35{
36 Q_OBJECT
37public:
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
47Q_SIGNALS:
48 void offHook();
49 void onHook();
50
51private:
52 Tp::AccountPtr mAccount;
53 Tp::SimpleCallObserverPtr mCallObserver;
54};
55
56
57class TelepathyBridge : public QObject
58{
59 Q_OBJECT
60public:
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
81private 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
144private:
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
164class CallMonitorPrivate
165{
166public:
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
195private:
196 std::mutex mtx;
197 std::condition_variable cv;
198};
199
200
201CallMonitor::CallMonitor():
202 d(new CallMonitorPrivate)
203{
204}
205
206CallMonitor::~CallMonitor()
207{
208 delete d->mBridge;
209 delete d;
210}
211
212void 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
0223
=== added file 'src/core/media/call-monitor/call_monitor.h'
--- src/core/media/call-monitor/call_monitor.h 1970-01-01 00:00:00 +0000
+++ src/core/media/call-monitor/call_monitor.h 2015-03-31 21:19:24 +0000
@@ -0,0 +1,41 @@
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#ifndef CALLMONITOR_H
21#define CALLMONITOR_H
22
23#include <functional>
24
25class CallMonitorPrivate;
26
27class CallMonitor
28{
29public:
30 enum State { OffHook, OnHook };
31
32 CallMonitor();
33 ~CallMonitor();
34
35 void on_change(const std::function<void(CallMonitor::State)>& func);
36
37private:
38 CallMonitorPrivate *d;
39};
40
41#endif // CALLMONITOR_H
042
=== added file 'src/core/media/call-monitor/qtbridge.cpp'
--- src/core/media/call-monitor/qtbridge.cpp 1970-01-01 00:00:00 +0000
+++ src/core/media/call-monitor/qtbridge.cpp 2015-03-31 21:19:24 +0000
@@ -0,0 +1,186 @@
1/*
2 * Copyright © 2014 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License version 3,
6 * as 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 * Authored by: Jussi Pakkanen <jussi.pakkanen@canonical.com>
17 * Thomas Voß <thomas.voss@canonical.com>
18 */
19
20#include "qtbridge.h"
21
22#include<QCoreApplication>
23#include<QNetworkAccessManager>
24#include<QNetworkRequest>
25#include<QNetworkReply>
26#include<QThread>
27#include<QDebug>
28
29#include <iostream>
30
31namespace
32{
33QCoreApplication* app = nullptr;
34}
35
36namespace qt
37{
38namespace core
39{
40namespace world
41{
42namespace detail
43{
44QEvent::Type qt_core_world_task_event_type()
45{
46 static QEvent::Type event_type = static_cast<QEvent::Type>(QEvent::registerEventType());
47 return event_type;
48}
49
50class TaskEvent : public QEvent
51{
52public:
53 TaskEvent(const std::function<void()>& task)
54 : QEvent(qt_core_world_task_event_type()),
55 task(task)
56 {
57 }
58
59 void run()
60 {
61 try
62 {
63 task();
64 promise.set_value();
65 } catch(...)
66 {
67 promise.set_exception(std::current_exception());
68 }
69 }
70
71 std::future<void> get_future()
72 {
73 return promise.get_future();
74 }
75
76private:
77 std::function<void()> task;
78 std::promise<void> promise;
79};
80
81class TaskHandler : public QObject
82{
83 Q_OBJECT
84
85public:
86 TaskHandler(QObject* parent) : QObject(parent)
87 {
88 }
89
90 bool event(QEvent* e);
91};
92
93
94
95void createCoreApplicationInstanceWithArgs(int argc, char** argv)
96{
97 app = new QCoreApplication(argc, argv);
98}
99
100void destroyCoreApplicationInstace()
101{
102 delete app;
103}
104
105QCoreApplication* coreApplicationInstance()
106{
107 return app;
108}
109
110TaskHandler* task_handler()
111{
112 static TaskHandler* instance = new TaskHandler(coreApplicationInstance());
113 return instance;
114}
115
116bool TaskHandler::event(QEvent *e)
117{
118 if (e->type() != qt_core_world_task_event_type())
119 return QObject::event(e);
120
121 auto te = dynamic_cast<TaskEvent*>(e);
122 if (te)
123 {
124 te->run();
125 return true;
126 }
127
128 return false;
129}
130}
131
132void build_and_run(int argc, char** argv, const std::function<void()>& ready)
133{
134 QThread::currentThread();
135 if (QCoreApplication::instance() != nullptr)
136 throw std::runtime_error(
137 "qt::core::world::build_and_run: "
138 "There is already a QCoreApplication running.");
139
140 detail::createCoreApplicationInstanceWithArgs(argc, argv);
141
142 detail::task_handler()->moveToThread(
143 detail::coreApplicationInstance()->thread());
144
145 // Signal to other worlds that we are good to go.
146 ready();
147
148 detail::coreApplicationInstance()->exec();
149
150 // Someone has called quit and we clean up on the correct thread here.
151 detail::destroyCoreApplicationInstace();
152}
153
154void destroy()
155{
156 enter_with_task([]()
157 {
158 // We make sure that all tasks have completed before quitting the app.
159 QEventLoopLocker locker;
160 }).wait_for(std::chrono::seconds{1});
161}
162
163std::future<void> enter_with_task(const std::function<void()>& task)
164{
165 QCoreApplication* instance = QCoreApplication::instance();
166
167 if (!instance)
168 {
169 throw std::runtime_error("Qt world has not been built before calling this function.");
170 }
171
172 detail::TaskEvent* te = new detail::TaskEvent(task);
173 auto future = te->get_future();
174
175 // We hand over ownership of te here. The event is deleted later after it has
176 // been processed by the event loop.
177 instance->postEvent(detail::task_handler(), te);
178
179 return future;
180}
181
182}
183}
184}
185
186#include "qtbridge.moc"
0187
=== added file 'src/core/media/call-monitor/qtbridge.h'
--- src/core/media/call-monitor/qtbridge.h 1970-01-01 00:00:00 +0000
+++ src/core/media/call-monitor/qtbridge.h 2015-03-31 21:19:24 +0000
@@ -0,0 +1,87 @@
1/*
2 * Copyright © 2014 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License version 3,
6 * as 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 * Authored by: Jussi Pakkanen <jussi.pakkanen@canonical.com>
17 * Thomas Voß <thomas.voss@canonical.com>
18 */
19
20#ifndef QT_CORE_WORLD_BRIDGE_H_
21#define QT_CORE_WORLD_BRIDGE_H_
22
23#include <QObject>
24
25#include <functional>
26#include <future>
27#include <iostream>
28
29namespace qt
30{
31namespace core
32{
33namespace world
34{
35/**
36 * @brief Sets up the Qt core world and executes its event loop. Blocks until destroy() is called.
37 * @param argc Number of arguments in argv.
38 * @param argv Array of command-line arguments.
39 * @param ready Functor be called when the world has been setup and is about to be executed.
40 * @throw std::runtime_error in case of errors.
41 */
42void build_and_run(int argc, char** argv, const std::function<void()>& ready);
43
44/**
45 * @brief Destroys the Qt core world and quits its event loop.
46 */
47void destroy();
48
49/**
50 * @brief Enters the Qt core world and schedules the given task for execution.
51 * @param task The task to be executed in the Qt core world.
52 * @return A std::future that can be waited for to synchronize to the world's internal event loop.
53 */
54std::future<void> enter_with_task(const std::function<void()>& task);
55
56
57/**
58 * @brief Enters the Qt core world and schedules the given task for execution.
59 * @param task The task to be executed in the Qt core world.
60 * @return A std::future that can be waited for to get hold of the result of the task.
61 */
62template<typename T>
63inline std::future<T> enter_with_task_and_expect_result(const std::function<T()>& task)
64{
65 std::shared_ptr<std::promise<T>> promise = std::make_shared<std::promise<T>>();
66 std::future<T> future = promise->get_future();
67
68 auto t = [promise, task]()
69 {
70 try
71 {
72 promise->set_value(task());
73 } catch(...)
74 {
75 promise->set_exception(std::current_exception());
76 }
77 };
78
79 enter_with_task(t);
80
81 return future;
82}
83}
84}
85}
86
87#endif // QT_CORE_WORLD_BRIDGE_H_
088
=== modified file 'src/core/media/codec.h'
--- src/core/media/codec.h 2015-01-13 14:18:59 +0000
+++ src/core/media/codec.h 2015-03-31 21:19:24 +0000
@@ -230,6 +230,7 @@
230 }230 }
231};231};
232232
233<<<<<<< TREE
233namespace helper234namespace helper
234{235{
235template<>236template<>
@@ -310,6 +311,48 @@
310 }311 }
311};312};
312313
314=======
315namespace helper
316{
317template<>
318struct TypeMapper<core::ubuntu::media::Player::Error>
319{
320 constexpr static ArgumentType type_value()
321 {
322 return core::dbus::ArgumentType::int16;
323 }
324 constexpr static bool is_basic_type()
325 {
326 return false;
327 }
328 constexpr static bool requires_signature()
329 {
330 return false;
331 }
332
333 static std::string signature()
334 {
335 static const std::string s = TypeMapper<std::int16_t>::signature();
336 return s;
337 }
338};
339}
340
341template<>
342struct Codec<core::ubuntu::media::Player::Error>
343{
344 static void encode_argument(core::dbus::Message::Writer& out, const core::ubuntu::media::Player::Error& in)
345 {
346 out.push_int16(static_cast<std::int16_t>(in));
347 }
348
349 static void decode_argument(core::dbus::Message::Reader& out, core::ubuntu::media::Player::Error& in)
350 {
351 in = static_cast<core::ubuntu::media::Player::Error>(out.pop_int16());
352 }
353};
354
355>>>>>>> MERGE-SOURCE
313}356}
314}357}
315358
316359
=== modified file 'src/core/media/engine.h'
=== modified file 'src/core/media/gstreamer/engine.cpp'
=== modified file 'src/core/media/gstreamer/engine.h'
=== modified file 'src/core/media/gstreamer/playbin.h'
--- src/core/media/gstreamer/playbin.h 2014-11-11 23:59:07 +0000
+++ src/core/media/gstreamer/playbin.h 2015-03-31 21:19:24 +0000
@@ -109,6 +109,7 @@
109 G_CALLBACK(about_to_finish),109 G_CALLBACK(about_to_finish),
110 this110 this
111 );111 );
112<<<<<<< TREE
112113
113 g_signal_connect(114 g_signal_connect(
114 pipeline,115 pipeline,
@@ -117,6 +118,8 @@
117 this118 this
118 );119 );
119120
121=======
122>>>>>>> MERGE-SOURCE
120 }123 }
121124
122 ~Playbin()125 ~Playbin()
123126
=== modified file 'src/core/media/mpris/player.h'
=== modified file 'src/core/media/player_implementation.cpp'
=== modified file 'src/core/media/player_implementation.h'
=== modified file 'src/core/media/player_skeleton.cpp'
=== modified file 'src/core/media/player_skeleton.h'
=== modified file 'src/core/media/player_stub.cpp'
=== modified file 'src/core/media/player_stub.h'
=== modified file 'src/core/media/service_implementation.cpp'
--- src/core/media/service_implementation.cpp 2015-01-16 17:17:30 +0000
+++ src/core/media/service_implementation.cpp 2015-03-31 21:19:24 +0000
@@ -35,6 +35,9 @@
35#include <map>35#include <map>
36#include <memory>36#include <memory>
37#include <thread>37#include <thread>
38#include <utility>
39
40#include <pulse/pulseaudio.h>
3841
39#include <pulse/pulseaudio.h>42#include <pulse/pulseaudio.h>
4043
@@ -460,6 +463,7 @@
460 int disp_cookie;463 int disp_cookie;
461 std::shared_ptr<dbus::Object> uscreen_session;464 std::shared_ptr<dbus::Object> uscreen_session;
462 MediaRecorderObserver *observer;465 MediaRecorderObserver *observer;
466<<<<<<< TREE
463467
464 // Pulse-specific468 // Pulse-specific
465 pa_mainloop_api *pulse_mainloop_api;469 pa_mainloop_api *pulse_mainloop_api;
@@ -479,6 +483,29 @@
479 core::Signal<void> pause_playback;483 core::Signal<void> pause_playback;
480 std::unique_ptr<CallMonitor> call_monitor;484 std::unique_ptr<CallMonitor> call_monitor;
481 std::list<media::Player::PlayerKey> paused_sessions;485 std::list<media::Player::PlayerKey> paused_sessions;
486=======
487
488 // Pulse-specific
489 pa_mainloop_api *pulse_mainloop_api;
490 pa_threaded_mainloop *pulse_mainloop;
491 pa_context *pulse_context;
492 std::thread pulse_worker;
493 std::mutex pulse_mutex;
494 std::condition_variable pcv;
495 bool headphones_connected;
496 bool a2dp_connected;
497 std::tuple<int, int, std::string> active_sink;
498 int primary_idx;
499
500 // Gets signaled when both the headphone jack is removed or an A2DP device is
501 // disconnected and playback needs pausing. Also gets signaled when recording
502 // begins.
503 core::Signal<void> pause_playback;
504 std::unique_ptr<CallMonitor> call_monitor;
505 // Holds a pair of a Player key denoting what player to resume playback, and a bool
506 // for if it should be resumed after a phone call is hung up
507 std::list<std::pair<media::Player::PlayerKey, bool>> paused_sessions;
508>>>>>>> MERGE-SOURCE
482};509};
483510
484media::ServiceImplementation::ServiceImplementation() : d(new Private())511media::ServiceImplementation::ServiceImplementation() : d(new Private())
@@ -488,7 +515,9 @@
488 // When the battery level hits 10% or 5%, pause all multimedia sessions.515 // When the battery level hits 10% or 5%, pause all multimedia sessions.
489 // Playback will resume when the user clears the presented notification.516 // Playback will resume when the user clears the presented notification.
490 if (level == "low" || level == "very_low")517 if (level == "low" || level == "very_low")
491 pause_all_multimedia_sessions();518 // Whatever player session is currently playing, make sure it is NOT resumed after
519 // a phonecall is hung up
520 pause_all_multimedia_sessions(false);
492 });521 });
493522
494 d->is_warning->changed().connect([this](const core::IndicatorPower::IsWarning::ValueType &notifying)523 d->is_warning->changed().connect([this](const core::IndicatorPower::IsWarning::ValueType &notifying)
@@ -498,6 +527,7 @@
498 if (!notifying)527 if (!notifying)
499 resume_multimedia_session();528 resume_multimedia_session();
500 });529 });
530<<<<<<< TREE
501531
502 d->pause_playback.connect([this]()532 d->pause_playback.connect([this]()
503 {533 {
@@ -518,6 +548,32 @@
518 break;548 break;
519 }549 }
520 });550 });
551=======
552
553 d->pause_playback.connect([this]()
554 {
555 std::cout << "Got pause_playback signal, pausing all multimedia sessions" << std::endl;
556 // Whatever player session is currently playing, make sure it is NOT resumed after
557 // a phonecall is hung up
558 pause_all_multimedia_sessions(false);
559 });
560
561 d->call_monitor->on_change([this](CallMonitor::State state) {
562 switch (state) {
563 case CallMonitor::OffHook:
564 std::cout << "Got call started signal, pausing all multimedia sessions" << std::endl;
565 // Whatever player session is currently playing, make sure it gets resumed after
566 // a phonecall is hung up
567 pause_all_multimedia_sessions(true);
568 break;
569 case CallMonitor::OnHook:
570 std::cout << "Got call ended signal, resuming paused multimedia sessions" << std::endl;
571 // Don't auto-resume any paused video playback sessions
572 resume_paused_multimedia_sessions(false);
573 break;
574 }
575 });
576>>>>>>> MERGE-SOURCE
521}577}
522578
523media::ServiceImplementation::~ServiceImplementation()579media::ServiceImplementation::~ServiceImplementation()
@@ -595,20 +651,27 @@
595 });651 });
596}652}
597653
598void media::ServiceImplementation::pause_all_multimedia_sessions()654void media::ServiceImplementation::pause_all_multimedia_sessions(bool resume_play_after_phonecall)
599{655{
600 enumerate_players([this](const media::Player::PlayerKey& key, const std::shared_ptr<media::Player>& player)656 enumerate_players([this, resume_play_after_phonecall](const media::Player::PlayerKey& key, const std::shared_ptr<media::Player>& player)
601 {657 {
602 if (player->playback_status() == Player::playing658 if (player->playback_status() == Player::playing
603 && player->audio_stream_role() == media::Player::multimedia)659 && player->audio_stream_role() == media::Player::multimedia)
604 {660 {
661<<<<<<< TREE
605 d->paused_sessions.push_back(key);662 d->paused_sessions.push_back(key);
606 std::cout << "Pausing Player with key: " << key << std::endl;663 std::cout << "Pausing Player with key: " << key << std::endl;
664=======
665 auto paused_player_pair = std::make_pair(key, resume_play_after_phonecall);
666 d->paused_sessions.push_back(paused_player_pair);
667 std::cout << "Pausing Player with key: " << key << std::endl;
668>>>>>>> MERGE-SOURCE
607 player->pause();669 player->pause();
608 }670 }
609 });671 });
610}672}
611673
674<<<<<<< TREE
612void media::ServiceImplementation::resume_paused_multimedia_sessions(bool resume_video_sessions)675void media::ServiceImplementation::resume_paused_multimedia_sessions(bool resume_video_sessions)
613{676{
614 std::for_each(d->paused_sessions.begin(), d->paused_sessions.end(), [this, resume_video_sessions](const media::Player::PlayerKey& key) {677 std::for_each(d->paused_sessions.begin(), d->paused_sessions.end(), [this, resume_video_sessions](const media::Player::PlayerKey& key) {
@@ -623,6 +686,25 @@
623 d->paused_sessions.clear();686 d->paused_sessions.clear();
624}687}
625688
689=======
690void media::ServiceImplementation::resume_paused_multimedia_sessions(bool resume_video_sessions)
691{
692 std::for_each(d->paused_sessions.begin(), d->paused_sessions.end(),
693 [this, resume_video_sessions](const std::pair<media::Player::PlayerKey, bool> &paused_player_pair) {
694 const media::Player::PlayerKey key = paused_player_pair.first;
695 const bool resume_play_after_phonecall = paused_player_pair.second;
696 auto player = player_for_key(key);
697 // Only resume video playback if explicitly desired
698 if ((resume_video_sessions || player->is_audio_source()) && resume_play_after_phonecall)
699 player->play();
700 else
701 std::cout << "Not auto-resuming video player session or other type of player session." << std::endl;
702 });
703
704 d->paused_sessions.clear();
705}
706
707>>>>>>> MERGE-SOURCE
626void media::ServiceImplementation::resume_multimedia_session()708void media::ServiceImplementation::resume_multimedia_session()
627{709{
628 if (not has_player_for_key(d->resume_key))710 if (not has_player_for_key(d->resume_key))
629711
=== modified file 'src/core/media/service_implementation.h'
--- src/core/media/service_implementation.h 2015-01-16 17:17:30 +0000
+++ src/core/media/service_implementation.h 2015-03-31 21:19:24 +0000
@@ -42,8 +42,13 @@
42 void pause_other_sessions(Player::PlayerKey key);42 void pause_other_sessions(Player::PlayerKey key);
4343
44private:44private:
45<<<<<<< TREE
45 void pause_all_multimedia_sessions();46 void pause_all_multimedia_sessions();
46 void resume_paused_multimedia_sessions(bool resume_video_sessions = true);47 void resume_paused_multimedia_sessions(bool resume_video_sessions = true);
48=======
49 void pause_all_multimedia_sessions(bool resume_play_after_phonecall);
50 void resume_paused_multimedia_sessions(bool resume_video_sessions = true);
51>>>>>>> MERGE-SOURCE
47 void resume_multimedia_session();52 void resume_multimedia_session();
4853
49 struct Private;54 struct Private;
5055
=== modified file 'src/core/media/service_skeleton.cpp'
=== modified file 'tests/unit-tests/CMakeLists.txt'
--- tests/unit-tests/CMakeLists.txt 2014-11-18 20:29:26 +0000
+++ tests/unit-tests/CMakeLists.txt 2015-03-31 21:19:24 +0000
@@ -41,8 +41,12 @@
41 ${PC_GSTREAMER_1_0_LIBRARIES}41 ${PC_GSTREAMER_1_0_LIBRARIES}
42 ${PROCESS_CPP_LDFLAGS}42 ${PROCESS_CPP_LDFLAGS}
43 ${GIO_LIBRARIES}43 ${GIO_LIBRARIES}
44<<<<<<< TREE
44 ${PROCESS_CPP_LIBRARIES}45 ${PROCESS_CPP_LIBRARIES}
45 ${PC_PULSE_AUDIO_LIBRARIES}46 ${PC_PULSE_AUDIO_LIBRARIES}
47=======
48 ${PC_PULSE_AUDIO_LIBRARIES}
49>>>>>>> MERGE-SOURCE
4650
47 gmock51 gmock
48 gmock_main52 gmock_main
4953
=== modified file 'tests/unit-tests/test-gstreamer-engine.cpp'
--- tests/unit-tests/test-gstreamer-engine.cpp 2015-03-03 22:41:22 +0000
+++ tests/unit-tests/test-gstreamer-engine.cpp 2015-03-31 21:19:24 +0000
@@ -155,6 +155,7 @@
155 std::chrono::seconds{10}));155 std::chrono::seconds{10}));
156}156}
157157
158<<<<<<< TREE
158TEST(GStreamerEngine, setting_uri_and_audio_playback_with_http_headers_works)159TEST(GStreamerEngine, setting_uri_and_audio_playback_with_http_headers_works)
159{160{
160 const std::string test_file{"/tmp/test-audio-1.ogg"};161 const std::string test_file{"/tmp/test-audio-1.ogg"};
@@ -222,6 +223,14 @@
222 const std::string test_file_uri{"file:///tmp/test-audio.ogg"};223 const std::string test_file_uri{"file:///tmp/test-audio.ogg"};
223 std::remove(test_file.c_str());224 std::remove(test_file.c_str());
224 ASSERT_TRUE(test::copy_test_media_file_to("test-audio.ogg", test_file));225 ASSERT_TRUE(test::copy_test_media_file_to("test-audio.ogg", test_file));
226=======
227TEST(GStreamerEngine, DISABLED_stop_pause_play_seek_audio_only_works)
228{
229 const std::string test_file{"/tmp/test.ogg"};
230 const std::string test_file_uri{"file:///tmp/test.ogg"};
231 std::remove(test_file.c_str());
232 ASSERT_TRUE(test::copy_test_mp3_file_to(test_file));
233>>>>>>> MERGE-SOURCE
225234
226 core::testing::WaitableStateTransition<core::ubuntu::media::Engine::State> wst(235 core::testing::WaitableStateTransition<core::ubuntu::media::Engine::State> wst(
227 core::ubuntu::media::Engine::State::ready);236 core::ubuntu::media::Engine::State::ready);

Subscribers

People subscribed via source and target branches