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