Merge lp:~jhodapp/media-hub/fix-music-next into lp:media-hub

Proposed by Jim Hodapp
Status: Merged
Approved by: Manuel de la Peña
Approved revision: 50
Merged at revision: 51
Proposed branch: lp:~jhodapp/media-hub/fix-music-next
Merge into: lp:media-hub
Diff against target: 537 lines (+246/-34)
9 files modified
README (+4/-0)
src/core/media/CMakeLists.txt (+0/-1)
src/core/media/engine.h (+1/-0)
src/core/media/gstreamer/engine.cpp (+18/-1)
src/core/media/gstreamer/engine.h (+2/-1)
src/core/media/gstreamer/playbin.h (+3/-0)
src/core/media/player_implementation.cpp (+143/-29)
src/core/media/powerd_service.h (+2/-2)
src/core/media/util/timeout.h (+73/-0)
To merge this branch: bzr merge lp:~jhodapp/media-hub/fix-music-next
Reviewer Review Type Date Requested Status
Manuel de la Peña (community) Approve
PS Jenkins bot continuous-integration Needs Fixing
Review via email: mp+230326@code.launchpad.net

Commit message

Allow music to advance to the next song when the device is not charging

Description of the change

Allow music to advance to the next song when the device is not charging

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
lp:~jhodapp/media-hub/fix-music-next updated
50. By Jim Hodapp

Make sure the display wakelock is cleared after video playback stops.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Manuel de la Peña (mandel) :
review: Approve
lp:~jhodapp/media-hub/fix-music-next updated
51. By Jim Hodapp

Rework the system and display wakelock logic. Should take care of the edge case issues.

52. By Jim Hodapp

Make sure a display or system wakelock are not held if the client disconnects during playback

53. By Jim Hodapp

Remove some debugging statements and improve the code comments

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'README'
--- README 2014-01-13 21:51:14 +0000
+++ README 2014-08-13 01:41:13 +0000
@@ -6,6 +6,10 @@
6cmake ..6cmake ..
7make7make
88
9To Run From Console:
10--------------------
11CORE_UBUNTU_MEDIA_SERVICE_VIDEO_SINK_NAME=mirsink CORE_UBUNTU_MEDIA_SERVICE_AUDIO_SINK_NAME=pulsesink src/core/media/media-hub-server
12
9To Run Unit Tests:13To Run Unit Tests:
10------------------14------------------
1115
1216
=== modified file 'src/core/media/CMakeLists.txt'
--- src/core/media/CMakeLists.txt 2014-04-04 14:31:43 +0000
+++ src/core/media/CMakeLists.txt 2014-08-13 01:41:13 +0000
@@ -1,5 +1,4 @@
1pkg_check_modules(PC_GSTREAMER_1_0 REQUIRED gstreamer-1.0)1pkg_check_modules(PC_GSTREAMER_1_0 REQUIRED gstreamer-1.0)
2
3include_directories(${PC_GSTREAMER_1_0_INCLUDE_DIRS} ${HYBRIS_MEDIA_CFLAGS})2include_directories(${PC_GSTREAMER_1_0_INCLUDE_DIRS} ${HYBRIS_MEDIA_CFLAGS})
43
5add_library(4add_library(
65
=== modified file 'src/core/media/engine.h'
--- src/core/media/engine.h 2014-04-25 17:53:00 +0000
+++ src/core/media/engine.h 2014-08-13 01:41:13 +0000
@@ -118,6 +118,7 @@
118118
119 virtual const core::Signal<void>& about_to_finish_signal() const = 0;119 virtual const core::Signal<void>& about_to_finish_signal() const = 0;
120 virtual const core::Signal<uint64_t>& seeked_to_signal() const = 0;120 virtual const core::Signal<uint64_t>& seeked_to_signal() const = 0;
121 virtual const core::Signal<void>& client_disconnected_signal() const = 0;
121 virtual const core::Signal<void>& end_of_stream_signal() const = 0;122 virtual const core::Signal<void>& end_of_stream_signal() const = 0;
122 virtual const core::Signal<core::ubuntu::media::Player::PlaybackStatus>& playback_status_changed_signal() const = 0;123 virtual const core::Signal<core::ubuntu::media::Player::PlaybackStatus>& playback_status_changed_signal() const = 0;
123};124};
124125
=== modified file 'src/core/media/gstreamer/engine.cpp'
--- src/core/media/gstreamer/engine.cpp 2014-04-25 17:53:00 +0000
+++ src/core/media/gstreamer/engine.cpp 2014-08-13 01:41:13 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright © 2013 Canonical Ltd.2 * Copyright © 2013-2014 Canonical Ltd.
3 *3 *
4 * This program is free software: you can redistribute it and/or modify it4 * 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,5 * under the terms of the GNU Lesser General Public License version 3,
@@ -175,6 +175,11 @@
175 seeked_to(value);175 seeked_to(value);
176 }176 }
177177
178 void on_client_disconnected()
179 {
180 client_disconnected();
181 }
182
178 void on_end_of_stream()183 void on_end_of_stream()
179 {184 {
180 end_of_stream();185 end_of_stream();
@@ -214,6 +219,11 @@
214 &Private::on_seeked_to,219 &Private::on_seeked_to,
215 this,220 this,
216 std::placeholders::_1))),221 std::placeholders::_1))),
222 client_disconnected_connection(
223 playbin.signals.client_disconnected.connect(
224 std::bind(
225 &Private::on_client_disconnected,
226 this))),
217 on_end_of_stream_connection(227 on_end_of_stream_connection(
218 playbin.signals.on_end_of_stream.connect(228 playbin.signals.on_end_of_stream.connect(
219 std::bind(229 std::bind(
@@ -236,10 +246,12 @@
236 core::ScopedConnection on_tag_available_connection;246 core::ScopedConnection on_tag_available_connection;
237 core::ScopedConnection on_volume_changed_connection;247 core::ScopedConnection on_volume_changed_connection;
238 core::ScopedConnection on_seeked_to_connection;248 core::ScopedConnection on_seeked_to_connection;
249 core::ScopedConnection client_disconnected_connection;
239 core::ScopedConnection on_end_of_stream_connection;250 core::ScopedConnection on_end_of_stream_connection;
240251
241 core::Signal<void> about_to_finish;252 core::Signal<void> about_to_finish;
242 core::Signal<uint64_t> seeked_to;253 core::Signal<uint64_t> seeked_to;
254 core::Signal<void> client_disconnected;
243 core::Signal<void> end_of_stream;255 core::Signal<void> end_of_stream;
244 core::Signal<media::Player::PlaybackStatus> playback_status_changed;256 core::Signal<media::Player::PlaybackStatus> playback_status_changed;
245};257};
@@ -383,6 +395,11 @@
383 return d->seeked_to;395 return d->seeked_to;
384}396}
385397
398const core::Signal<void>& gstreamer::Engine::client_disconnected_signal() const
399{
400 return d->client_disconnected;
401}
402
386const core::Signal<void>& gstreamer::Engine::end_of_stream_signal() const403const core::Signal<void>& gstreamer::Engine::end_of_stream_signal() const
387{404{
388 return d->end_of_stream;405 return d->end_of_stream;
389406
=== modified file 'src/core/media/gstreamer/engine.h'
--- src/core/media/gstreamer/engine.h 2014-04-25 17:53:00 +0000
+++ src/core/media/gstreamer/engine.h 2014-08-13 01:41:13 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright © 2013 Canonical Ltd.2 * Copyright © 2013-2014 Canonical Ltd.
3 *3 *
4 * This program is free software: you can redistribute it and/or modify it4 * 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,5 * under the terms of the GNU Lesser General Public License version 3,
@@ -53,6 +53,7 @@
5353
54 const core::Signal<void>& about_to_finish_signal() const;54 const core::Signal<void>& about_to_finish_signal() const;
55 const core::Signal<uint64_t>& seeked_to_signal() const;55 const core::Signal<uint64_t>& seeked_to_signal() const;
56 const core::Signal<void>& client_disconnected_signal() const;
56 const core::Signal<void>& end_of_stream_signal() const;57 const core::Signal<void>& end_of_stream_signal() const;
57 const core::Signal<core::ubuntu::media::Player::PlaybackStatus>& playback_status_changed_signal() const;58 const core::Signal<core::ubuntu::media::Player::PlaybackStatus>& playback_status_changed_signal() const;
5859
5960
=== modified file 'src/core/media/gstreamer/playbin.h'
--- src/core/media/gstreamer/playbin.h 2014-04-25 21:23:10 +0000
+++ src/core/media/gstreamer/playbin.h 2014-08-13 01:41:13 +0000
@@ -116,6 +116,8 @@
116 // in a state that is ready for the next client that connects to the116 // in a state that is ready for the next client that connects to the
117 // service117 // service
118 reset_pipeline();118 reset_pipeline();
119 // Signal to the Player class that the client side has disconnected
120 signals.client_disconnected();
119 }121 }
120122
121 void reset_pipeline()123 void reset_pipeline()
@@ -411,6 +413,7 @@
411 core::Signal<uint64_t> on_seeked_to;413 core::Signal<uint64_t> on_seeked_to;
412 core::Signal<void> on_end_of_stream;414 core::Signal<void> on_end_of_stream;
413 core::Signal<media::Player::PlaybackStatus> on_playback_status_changed;415 core::Signal<media::Player::PlaybackStatus> on_playback_status_changed;
416 core::Signal<void> client_disconnected;
414 } signals;417 } signals;
415};418};
416}419}
417420
=== modified file 'src/core/media/player_implementation.cpp'
--- src/core/media/player_implementation.cpp 2014-06-24 17:03:27 +0000
+++ src/core/media/player_implementation.cpp 2014-08-13 01:41:13 +0000
@@ -13,9 +13,11 @@
13 * along with this program. If not, see <http://www.gnu.org/licenses/>.13 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 *14 *
15 * Authored by: Thomas Voß <thomas.voss@canonical.com>15 * Authored by: Thomas Voß <thomas.voss@canonical.com>
16 * Jim Hodapp <jim.hodapp@canonical.com>
16 */17 */
1718
18#include "player_implementation.h"19#include "player_implementation.h"
20#include "util/timeout.h"
1921
20#include <unistd.h>22#include <unistd.h>
2123
@@ -28,6 +30,7 @@
2830
29#include <exception>31#include <exception>
30#include <iostream>32#include <iostream>
33#include <mutex>
3134
32#define UNUSED __attribute__((unused))35#define UNUSED __attribute__((unused))
3336
@@ -38,6 +41,14 @@
3841
39struct media::PlayerImplementation::Private42struct media::PlayerImplementation::Private
40{43{
44 enum class wakelock_clear_t
45 {
46 WAKELOCK_CLEAR_INACTIVE,
47 WAKELOCK_CLEAR_DISPLAY,
48 WAKELOCK_CLEAR_SYSTEM,
49 WAKELOCK_CLEAR_INVALID
50 };
51
41 Private(PlayerImplementation* parent,52 Private(PlayerImplementation* parent,
42 const dbus::types::ObjectPath& session_path,53 const dbus::types::ObjectPath& session_path,
43 const std::shared_ptr<media::Service>& service,54 const std::shared_ptr<media::Service>& service,
@@ -51,7 +62,10 @@
51 session_path.as_string() + "/TrackList",62 session_path.as_string() + "/TrackList",
52 engine->meta_data_extractor())),63 engine->meta_data_extractor())),
53 sys_lock_name("media-hub-music-playback"),64 sys_lock_name("media-hub-music-playback"),
54 active_display_on_request(false),65 disp_cookie(-1),
66 system_wakelock_count(0),
67 display_wakelock_count(0),
68 previous_state(Engine::State::stopped),
55 key(key)69 key(key)
56 {70 {
57 auto bus = std::shared_ptr<dbus::Bus>(new dbus::Bus(core::dbus::WellKnownBus::system));71 auto bus = std::shared_ptr<dbus::Bus>(new dbus::Bus(core::dbus::WellKnownBus::system));
@@ -63,6 +77,14 @@
63 auto uscreen_stub_service = dbus::Service::use_service(bus, dbus::traits::Service<core::UScreen>::interface_name());77 auto uscreen_stub_service = dbus::Service::use_service(bus, dbus::traits::Service<core::UScreen>::interface_name());
64 uscreen_session = uscreen_stub_service->object_for_path(dbus::types::ObjectPath("/com/canonical/Unity/Screen"));78 uscreen_session = uscreen_stub_service->object_for_path(dbus::types::ObjectPath("/com/canonical/Unity/Screen"));
6579
80 /*
81 * Wakelock state logic:
82 *
83 * PLAYING->READY: delay 4 seconds and try to clear current wakelock type
84 * PLAYING->PAUSED or PLAYING->STOPPED: delay 4 seconds and try to clear current wakelock type
85 * READY->PAUSED: request a new wakelock (system or display)
86 * PLAYING->PAUSED: delay 4 seconds and try to clear current wakelock type
87 */
66 engine->state().changed().connect(88 engine->state().changed().connect(
67 [parent, this](const Engine::State& state)89 [parent, this](const Engine::State& state)
68 {90 {
@@ -71,97 +93,178 @@
71 case Engine::State::ready:93 case Engine::State::ready:
72 {94 {
73 parent->playback_status().set(media::Player::ready);95 parent->playback_status().set(media::Player::ready);
74 clear_power_state();96 if (previous_state == Engine::State::playing)
97 {
98 wakelock_timeout.reset(new timeout(4000, true, std::bind(&Private::clear_wakelock,
99 this, std::placeholders::_1), current_wakelock_type()));
100 }
75 break;101 break;
76 }102 }
77 case Engine::State::playing:103 case Engine::State::playing:
78 {104 {
79 parent->playback_status().set(media::Player::playing);105 parent->playback_status().set(media::Player::playing);
80 request_power_state();106 if (previous_state == Engine::State::stopped || previous_state == Engine::State::paused)
107 {
108 request_power_state();
109 }
81 break;110 break;
82 }111 }
83 case Engine::State::stopped:112 case Engine::State::stopped:
84 {113 {
85 parent->playback_status().set(media::Player::stopped);114 parent->playback_status().set(media::Player::stopped);
86 clear_power_state();
87 break;115 break;
88 }116 }
89 case Engine::State::paused:117 case Engine::State::paused:
90 {118 {
91 parent->playback_status().set(media::Player::paused);119 parent->playback_status().set(media::Player::paused);
92 clear_power_state();120 if (previous_state == Engine::State::ready)
121 {
122 request_power_state();
123 }
124 else if (previous_state == Engine::State::playing)
125 {
126 wakelock_timeout.reset(new timeout(4000, true, std::bind(&Private::clear_wakelock,
127 this, std::placeholders::_1), current_wakelock_type()));
128 }
93 break;129 break;
94 }130 }
95 default:131 default:
96 break;132 break;
97 };133 };
134
135 // Keep track of the previous Engine playback state:
136 previous_state = state;
98 });137 });
99138
100 }139 }
101140
141 ~Private()
142 {
143 // Make sure that we don't hold on to the wakelocks if media-hub-server
144 // ever gets restarted manually or automatically
145 clear_wakelocks();
146 }
147
102 void request_power_state()148 void request_power_state()
103 {149 {
104 try150 try
105 {151 {
106 if (parent->is_video_source())152 if (parent->is_video_source())
107 {153 {
108 if (!active_display_on_request)154 if (display_wakelock_count == 0)
109 {155 {
110 auto result = uscreen_session->invoke_method_synchronously<core::UScreen::keepDisplayOn, int>();156 auto result = uscreen_session->invoke_method_synchronously<core::UScreen::keepDisplayOn, int>();
111 if (result.is_error())157 if (result.is_error())
112 throw std::runtime_error(result.error().print());158 throw std::runtime_error(result.error().print());
113
114 disp_cookie = result.value();159 disp_cookie = result.value();
115 active_display_on_request = true;160 cout << "Requested new display wakelock" << endl;
161 }
162
163 {
164 // Keep track of how many display wakelocks have been requested
165 std::lock_guard<std::mutex> lock(wakelock_mutex);
166 ++display_wakelock_count;
116 }167 }
117 }168 }
118 else169 else
119 {170 {
120 if (sys_cookie.empty())171 if (system_wakelock_count == 0)
121 {172 {
122 auto result = powerd_session->invoke_method_synchronously<core::Powerd::requestSysState, std::string>(sys_lock_name, static_cast<int>(1));173 auto result = powerd_session->invoke_method_synchronously<core::Powerd::requestSysState, std::string>(sys_lock_name, static_cast<int>(1));
123 if (result.is_error())174 if (result.is_error())
124 throw std::runtime_error(result.error().print());175 throw std::runtime_error(result.error().print());
125
126 sys_cookie = result.value();176 sys_cookie = result.value();
177 cout << "Requested new system wakelock" << endl;
178 }
179
180 {
181 // Keep track of how many system wakelocks have been requested
182 std::lock_guard<std::mutex> lock(wakelock_mutex);
183 ++system_wakelock_count;
127 }184 }
128 }185 }
129 }186 }
130 catch(std::exception& e)187 catch(const std::exception& e)
131 {188 {
132 std::cerr << "Warning: failed to request power state: ";189 std::cerr << "Warning: failed to request power state: ";
133 std::cerr << e.what() << std::endl;190 std::cerr << e.what() << std::endl;
134 }191 }
135 }192 }
136193
137 void clear_power_state()194 void clear_wakelock(const wakelock_clear_t &wakelock)
138 {195 {
196 cout << __PRETTY_FUNCTION__ << endl;
139 try197 try
140 {198 {
141 if (parent->is_video_source())199 switch (wakelock)
142 {200 {
143 if (active_display_on_request)201 case wakelock_clear_t::WAKELOCK_CLEAR_INACTIVE:
144 {202 break;
145 uscreen_session->invoke_method_synchronously<core::UScreen::removeDisplayOnRequest, void>(disp_cookie);203 case wakelock_clear_t::WAKELOCK_CLEAR_SYSTEM:
146 active_display_on_request = false;204 {
147 }205 std::lock_guard<std::mutex> lock(wakelock_mutex);
148 }206 --system_wakelock_count;
149 else207 }
150 {208 // Only actually clear the system wakelock once the count reaches zero
151 if (!sys_cookie.empty())209 if (system_wakelock_count == 0)
152 {210 {
153 powerd_session->invoke_method_synchronously<core::Powerd::clearSysState, void>(sys_cookie);211 cout << "Clearing system wakelock" << endl;
154 sys_cookie.clear();212 powerd_session->invoke_method_synchronously<core::Powerd::clearSysState, void>(sys_cookie);
155 }213 sys_cookie.clear();
214 }
215 break;
216 case wakelock_clear_t::WAKELOCK_CLEAR_DISPLAY:
217 {
218 std::lock_guard<std::mutex> lock(wakelock_mutex);
219 --display_wakelock_count;
220 }
221 // Only actually clear the display wakelock once the count reaches zero
222 if (display_wakelock_count == 0)
223 {
224 cout << "Clearing display wakelock" << endl;
225 uscreen_session->invoke_method_synchronously<core::UScreen::removeDisplayOnRequest, void>(disp_cookie);
226 disp_cookie = -1;
227 }
228 break;
229 case wakelock_clear_t::WAKELOCK_CLEAR_INVALID:
230 default:
231 cerr << "Can't clear invalid wakelock type" << endl;
156 }232 }
157 }233 }
158 catch(std::exception& e)234 catch(const std::exception& e)
159 {235 {
160 std::cerr << "Warning: failed to clear power state: ";236 std::cerr << "Warning: failed to clear power state: ";
161 std::cerr << e.what() << std::endl;237 std::cerr << e.what() << std::endl;
162 }238 }
163 }239 }
164240
241 wakelock_clear_t current_wakelock_type() const
242 {
243 return (parent->is_video_source()) ?
244 wakelock_clear_t::WAKELOCK_CLEAR_DISPLAY : wakelock_clear_t::WAKELOCK_CLEAR_SYSTEM;
245 }
246
247 void clear_wakelocks()
248 {
249 // Clear both types of wakelocks (display and system)
250 if (system_wakelock_count > 0)
251 {
252 {
253 std::lock_guard<std::mutex> lock(wakelock_mutex);
254 system_wakelock_count = 1;
255 }
256 clear_wakelock(wakelock_clear_t::WAKELOCK_CLEAR_SYSTEM);
257 }
258 if (display_wakelock_count > 0)
259 {
260 {
261 std::lock_guard<std::mutex> lock(wakelock_mutex);
262 display_wakelock_count = 1;
263 }
264 clear_wakelock(wakelock_clear_t::WAKELOCK_CLEAR_DISPLAY);
265 }
266 }
267
165 PlayerImplementation* parent;268 PlayerImplementation* parent;
166 std::shared_ptr<Service> service;269 std::shared_ptr<Service> service;
167 std::shared_ptr<Engine> engine;270 std::shared_ptr<Engine> engine;
@@ -171,8 +274,12 @@
171 std::shared_ptr<dbus::Object> uscreen_session;274 std::shared_ptr<dbus::Object> uscreen_session;
172 std::string sys_lock_name;275 std::string sys_lock_name;
173 int disp_cookie;276 int disp_cookie;
174 bool active_display_on_request;
175 std::string sys_cookie;277 std::string sys_cookie;
278 std::mutex wakelock_mutex;
279 uint8_t system_wakelock_count;
280 uint8_t display_wakelock_count;
281 std::unique_ptr<timeout> wakelock_timeout;
282 Engine::State previous_state;
176 PlayerImplementation::PlayerKey key;283 PlayerImplementation::PlayerKey key;
177};284};
178285
@@ -240,6 +347,13 @@
240 }347 }
241 });348 });
242349
350 d->engine->client_disconnected_signal().connect([this]()
351 {
352 // If the client disconnects, make sure both wakelock types
353 // are cleared
354 d->clear_wakelocks();
355 });
356
243 d->engine->seeked_to_signal().connect([this](uint64_t value)357 d->engine->seeked_to_signal().connect([this](uint64_t value)
244 {358 {
245 seeked_to()(value);359 seeked_to()(value);
246360
=== modified file 'src/core/media/powerd_service.h'
--- src/core/media/powerd_service.h 2014-06-16 22:28:53 +0000
+++ src/core/media/powerd_service.h 2014-08-13 01:41:13 +0000
@@ -41,7 +41,7 @@
41 static std::string s = "com.canonical.powerd";41 static std::string s = "com.canonical.powerd";
42 return s;42 return s;
43 }43 }
44 44
45 struct requestSysState45 struct requestSysState
46 {46 {
47 static std::string name()47 static std::string name()
@@ -62,7 +62,7 @@
62 static std::string s = "clearSysState";62 static std::string s = "clearSysState";
63 return s;63 return s;
64 }64 }
65 65
66 static const std::chrono::milliseconds default_timeout() { return std::chrono::seconds{1}; }66 static const std::chrono::milliseconds default_timeout() { return std::chrono::seconds{1}; }
6767
68 typedef Powerd Interface;68 typedef Powerd Interface;
6969
=== added directory 'src/core/media/util'
=== added file 'src/core/media/util/timeout.h'
--- src/core/media/util/timeout.h 1970-01-01 00:00:00 +0000
+++ src/core/media/util/timeout.h 2014-08-13 01:41:13 +0000
@@ -0,0 +1,73 @@
1/*
2 *
3 * This program is free software: you can redistribute it and/or modify it
4 * under the terms of the GNU Lesser General Public License version 3,
5 * as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU Lesser General Public License for more details.
11 *
12 * You should have received a copy of the GNU Lesser General Public License
13 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 *
15 * Authored by: Jim Hodapp <jim.hodapp@canonical.com>
16 *
17 * Adapted from: http://stackoverflow.com/questions/14650885/how-to-create-timer-events-using-c-11
18 *
19 */
20
21#ifndef TIMEOUT_H_
22#define TIMEOUT_H_
23
24#include <functional>
25#include <chrono>
26#include <future>
27#include <cstdio>
28
29namespace core
30{
31namespace ubuntu
32{
33namespace media
34{
35
36class timeout
37{
38public:
39 /**
40 * @brief Start a timeout with millisecond resolution
41 * @param timeout_ms Timeout value in milliseconds
42 * @param async Whether to block while the timeout proceeds or not
43 * @param f The function to call when the timeout expires
44 * @param args Any arguments to pass to f when the timeout expires
45 */
46 template <class callable, class... arguments>
47 timeout(int timeout_ms, bool async, callable&& f, arguments&&... args)
48 {
49 std::function<typename std::result_of<callable(arguments...)>::type()>
50 task(std::bind(std::forward<callable>(f), std::forward<arguments>(args)...));
51
52 if (async)
53 {
54 // Timeout without blocking
55 std::thread([timeout_ms, task]() {
56 std::this_thread::sleep_for(std::chrono::milliseconds(timeout_ms));
57 task();
58 }).detach();
59 }
60 else
61 {
62 // Timeout with blocking
63 std::this_thread::sleep_for(std::chrono::milliseconds(timeout_ms));
64 task();
65 }
66 }
67};
68
69}
70}
71}
72
73#endif // TIMEOUT_H_

Subscribers

People subscribed via source and target branches