Merge lp:~thomas-voss/media-hub/introduce-power-controller-interface into lp:media-hub

Proposed by Thomas Voß
Status: Merged
Approved by: Ricardo Mendoza
Approved revision: 119
Merged at revision: 119
Proposed branch: lp:~thomas-voss/media-hub/introduce-power-controller-interface
Merge into: lp:media-hub
Prerequisite: lp:~thomas-voss/media-hub/move-playbin-implementation-to-cpp-file
Diff against target: 1357 lines (+781/-284)
12 files modified
src/core/media/CMakeLists.txt (+4/-0)
src/core/media/external_services.h (+83/-0)
src/core/media/player_implementation.cpp (+50/-66)
src/core/media/player_implementation.h (+18/-6)
src/core/media/power/state_controller.cpp (+360/-0)
src/core/media/power/state_controller.h (+108/-0)
src/core/media/powerd_service.h (+0/-73)
src/core/media/server/server.cpp (+121/-8)
src/core/media/service_implementation.cpp (+28/-56)
src/core/media/service_implementation.h (+8/-2)
src/core/media/unity_screen_service.h (+0/-72)
tests/CMakeLists.txt (+1/-1)
To merge this branch: bzr merge lp:~thomas-voss/media-hub/introduce-power-controller-interface
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Approve
Jim Hodapp (community) code Needs Fixing
Review via email: mp+242905@code.launchpad.net

Commit message

Introduce a common class media::helper::ExternalHelpers that provides a convenient way to:

  * Access the system and session bus instances.
  * Prepares for integration testing scenarios as we can switch to private testing bus instances.
  * Dispatch execution of tasks to worker threads.
  * Requires only one external worker thread transparently shared by implementations requiring access to the respective bus instances.

Introduce interfaces media::power::StateController and media::power::StateController::Lock for acquiring and releasing locks on power-relevant system components, mainly:

  * The display subsystem.
  * The overall system power state.

Provide two implementations talking to the com.canonical.Unity.Screen and com.canonical.powerd
that implement media::power::StateController and media::power::StateController::Lock.

Adjust existing implementation to leverage power::StateController{::Lock}.
Adjust server setup to:

  * hand down an instance of media::helper::ExternalServices to media::ServiceImplementation.
  * spin up two threads running the actual service and the external service helper in an exception-safe way.

Disable compilation of acceptance tests until the end of the wave of merge proposals to avoid having to resync. All of them are disabled anyway.

Description of the change

Introduce a common class media::helper::ExternalHelpers that provides a convenient way to:

  * Access the system and session bus instances.
  * Prepares for integration testing scenarios as we can switch to private testing bus instances.
  * Dispatch execution of tasks to worker threads.
  * Requires only one external worker thread transparently shared by implementations requiring access to the respective bus instances.

Introduce interfaces media::power::StateController and media::power::StateController::Lock for acquiring and releasing locks on power-relevant system components, mainly:

  * The display subsystem.
  * The overall system power state.

Provide two implementations talking to the com.canonical.Unity.Screen and com.canonical.powerd
that implement media::power::StateController and media::power::StateController::Lock.

Adjust existing implementation to leverage power::StateController{::Lock}.
Adjust server setup to:

  * hand down an instance of media::helper::ExternalServices to media::ServiceImplementation.
  * spin up two threads running the actual service and the external service helper in an exception-safe way.

Disable compilation of acceptance tests until the end of the wave of merge proposals to avoid having to resync. All of them are disabled anyway.

To post a comment you must log in.
105. By Thomas Voß

Initialize media::RecorderObserver in the ctor's initializer list.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
106. By Thomas Voß

Remerge prereq branch.

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

There's a lot to this one and we'll want to test the wakelock parts extremely well since there have been issues in the past with race conditions. Looks good, several comments inline below:

review: Needs Fixing (code)
Revision history for this message
Thomas Voß (thomas-voss) :
107. By Thomas Voß

[ Jim Hodapp ]
* Resubmitting with prerequisite branch (LP: #1331041)
[ Justin McPherson ]
* Resubmitting with prerequisite branch (LP: #1331041)

108. By Thomas Voß

Address review comments.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
109. By Thomas Voß

Fix ftbfs.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
110. By Thomas Voß

[ Jim Hodapp ]
* Error reporting all the way up to the app level from the playbin
  pipeline.
[ Ubuntu daily release ]
* New rebuild forced
[ Jim Hodapp ]
* Don't auto-resume playback of videos after a phone call ends. (LP:
  #1411273)
[ Ubuntu daily release ]
* New rebuild forced
[ Ricardo Salveti de Araujo ]
* service_implementation: adding debug for call started/ended signals.
  Make sure account and connection are available when setting up
  account manager (patch from Gustavo Boiko). call_monitor: don't
  check caps when hooking up on/off signals, until bug 1409125 is
  fixed. Enable parallel building . (LP: #1409125)
[ Jim Hodapp ]
* Pause playback when recording begins. (LP: #1398047)
[ Ricardo Salveti de Araujo ]
* call_monitor.cpp: waiting for bridge to be up, and also protecting
  the on_change call (LP: #1408137)

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
111. By Thomas Voß

Merge prereq branch.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
112. By Thomas Voß

Fix init issue for assigning executors to buses.

113. By Thomas Voß

Merge prereq branch.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
114. By Thomas Voß

Make the default implementation more verbose.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
115. By Thomas Voß

Make sure that the system state lock instance is around long enough when reaching out via the bus.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
116. By Thomas Voß

We really should release the on request, not the off one.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
117. By Thomas Voß

Make sure that a DisplayStateLock is alive for long enough to always be able to complete a release operation.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
118. By Thomas Voß

* debian/control:
  - Removing pre-depends that are not required
  - Bumping standards-version to 3.9.6
[ Ricardo Salveti de Araujo ]
* Migrating tests to use ogg instead of mp3/avi removed:
  tests/h264.avi tests/test.mp3 added: tests/test-audio-1.ogg
  tests/test-video.ogg tests/test.mp3 renamed: tests/test.ogg =>
  tests/test-audio.ogg

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
119. By Thomas Voß

Tighten scope in StateController.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/core/media/CMakeLists.txt'
--- src/core/media/CMakeLists.txt 2015-03-19 20:49:44 +0000
+++ src/core/media/CMakeLists.txt 2015-03-19 20:49:45 +0000
@@ -90,8 +90,12 @@
90 hybris_client_death_observer.cpp90 hybris_client_death_observer.cpp
91 cover_art_resolver.cpp91 cover_art_resolver.cpp
92 engine.cpp92 engine.cpp
93
94 power/state_controller.cpp
95
93 recorder_observer.cpp96 recorder_observer.cpp
94 hybris_recorder_observer.cpp97 hybris_recorder_observer.cpp
98
95 gstreamer/engine.cpp99 gstreamer/engine.cpp
96 gstreamer/playbin.cpp100 gstreamer/playbin.cpp
97101
98102
=== added file 'src/core/media/external_services.h'
--- src/core/media/external_services.h 1970-01-01 00:00:00 +0000
+++ src/core/media/external_services.h 2015-03-19 20:49:45 +0000
@@ -0,0 +1,83 @@
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: Thomas Voß <thomas.voss@canonical.com>
17 */
18#ifndef CORE_UBUNTU_MEDIA_EXTERNAL_SERVICES_H_
19#define CORE_UBUNTU_MEDIA_EXTERNAL_SERVICES_H_
20
21#include <core/dbus/bus.h>
22
23#include <core/dbus/asio/executor.h>
24
25#include <boost/asio.hpp>
26
27namespace core
28{
29namespace ubuntu
30{
31namespace media
32{
33namespace helper
34{
35// A helper struct that bundles:
36// * a dispatcher, i.e., the io_service
37// * access to the system and session bus
38//
39// In addtion, it allows us to mock out services and
40// for acceptance testing purposes.
41struct ExternalServices
42{
43 ExternalServices(const core::dbus::Bus::Ptr& session, const core::dbus::Bus::Ptr& system)
44 : keep_alive{io_service},
45 session{session},
46 system{system}
47 {
48 }
49
50 ExternalServices()
51 : ExternalServices
52 {
53 core::dbus::Bus::Ptr{new core::dbus::Bus{core::dbus::WellKnownBus::session}},
54 core::dbus::Bus::Ptr{new core::dbus::Bus{core::dbus::WellKnownBus::system}}
55 }
56 {
57 session->install_executor(core::dbus::asio::make_executor(session, io_service));
58 system->install_executor(core::dbus::asio::make_executor(system, io_service));
59 }
60
61
62 void run()
63 {
64 io_service.run();
65 }
66
67 void stop()
68 {
69 io_service.stop();
70 }
71
72 boost::asio::io_service io_service;
73 boost::asio::io_service::work keep_alive;
74
75 core::dbus::Bus::Ptr session;
76 core::dbus::Bus::Ptr system;
77};
78}
79}
80}
81}
82
83#endif // CORE_UBUNTU_MEDIA_EXTERNAL_SERVICES_H_
084
=== modified file 'src/core/media/player_implementation.cpp'
--- src/core/media/player_implementation.cpp 2015-03-19 20:49:44 +0000
+++ src/core/media/player_implementation.cpp 2015-03-19 20:49:45 +0000
@@ -25,8 +25,6 @@
25#include "engine.h"25#include "engine.h"
26#include "track_list_implementation.h"26#include "track_list_implementation.h"
2727
28#include "powerd_service.h"
29#include "unity_screen_service.h"
30#include "gstreamer/engine.h"28#include "gstreamer/engine.h"
3129
32#include <memory>30#include <memory>
@@ -52,45 +50,50 @@
52 WAKELOCK_CLEAR_INVALID50 WAKELOCK_CLEAR_INVALID
53 };51 };
5452
55 Private(PlayerImplementation* parent,53 Private(PlayerImplementation* parent, const media::PlayerImplementation::Configuration& config)
56 const dbus::types::ObjectPath& session_path,
57 const std::shared_ptr<media::Service>& service,
58 PlayerImplementation::PlayerKey key)
59 : parent(parent),54 : parent(parent),
60 service(service),55 config(config),
56 display_state_lock(config.power_state_controller->display_state_lock()),
57 system_state_lock(config.power_state_controller->system_state_lock()),
61 engine(std::make_shared<gstreamer::Engine>()),58 engine(std::make_shared<gstreamer::Engine>()),
62 session_path(session_path),
63 track_list(59 track_list(
64 new media::TrackListImplementation(60 new media::TrackListImplementation(
65 session_path.as_string() + "/TrackList",61 config.session->path().as_string() + "/TrackList",
66 engine->meta_data_extractor())),62 engine->meta_data_extractor())),
67 sys_lock_name("media-hub-music-playback"),
68 disp_cookie(-1),
69 system_wakelock_count(0),63 system_wakelock_count(0),
70 display_wakelock_count(0),64 display_wakelock_count(0),
71 previous_state(Engine::State::stopped),65 previous_state(Engine::State::stopped),
72 key(key),
73 engine_state_change_connection(engine->state().changed().connect(make_state_change_handler()))66 engine_state_change_connection(engine->state().changed().connect(make_state_change_handler()))
74 {67 {
75 auto bus = std::shared_ptr<dbus::Bus>(new dbus::Bus(core::dbus::WellKnownBus::system));68 config.client_death_observer->register_for_death_notifications_with_key(config.key);
76 bus->install_executor(dbus::asio::make_executor(bus));69 config.client_death_observer->on_client_with_key_died().connect([this](const media::Player::PlayerKey& died)
77
78 auto stub_service = dbus::Service::use_service(bus, dbus::traits::Service<core::Powerd>::interface_name());
79 powerd_session = stub_service->object_for_path(dbus::types::ObjectPath("/com/canonical/powerd"));
80
81 auto uscreen_stub_service = dbus::Service::use_service(bus, dbus::traits::Service<core::UScreen>::interface_name());
82 uscreen_session = uscreen_stub_service->object_for_path(dbus::types::ObjectPath("/com/canonical/Unity/Screen"));
83
84 auto client_death_observer = media::platform_default_client_death_observer();
85
86 client_death_observer->register_for_death_notifications_with_key(key);
87 client_death_observer->on_client_with_key_died().connect([this](const media::Player::PlayerKey& died)
88 {70 {
89 if (died != this->key)71 if (died != this->config.key)
90 return;72 return;
9173
92 on_client_died();74 on_client_died();
93 });75 });
76
77 // Poor man's logging of release/acquire events.
78 display_state_lock->acquired().connect([](media::power::DisplayState state)
79 {
80 std::cout << "Acquired new display state: " << state << std::endl;
81 });
82
83 display_state_lock->released().connect([](media::power::DisplayState state)
84 {
85 std::cout << "Released display state: " << state << std::endl;
86 });
87
88 system_state_lock->acquired().connect([](media::power::SystemState state)
89 {
90 std::cout << "Acquired new system state: " << state << std::endl;
91 });
92
93 system_state_lock->released().connect([](media::power::SystemState state)
94 {
95 std::cout << "Released system state: " << state << std::endl;
96 });
94 }97 }
9598
96 ~Private()99 ~Private()
@@ -170,22 +173,16 @@
170 {173 {
171 if (++display_wakelock_count == 1)174 if (++display_wakelock_count == 1)
172 {175 {
173 auto result = uscreen_session->invoke_method_synchronously<core::UScreen::keepDisplayOn, int>();176 display_state_lock->request_acquire(media::power::DisplayState::on);
174 if (result.is_error())177 std::cout << "Requested new display wakelock." << std::endl;
175 throw std::runtime_error(result.error().print());
176 disp_cookie = result.value();
177 cout << "Requested new display wakelock" << endl;
178 }178 }
179 }179 }
180 else180 else
181 {181 {
182 if (++system_wakelock_count == 1)182 if (++system_wakelock_count == 1)
183 {183 {
184 auto result = powerd_session->invoke_method_synchronously<core::Powerd::requestSysState, std::string>(sys_lock_name, static_cast<int>(1));184 system_state_lock->request_acquire(media::power::SystemState::active);
185 if (result.is_error())185 std::cout << "Requested new system wakelock." << std::endl;
186 throw std::runtime_error(result.error().print());
187 sys_cookie = result.value();
188 cout << "Requested new system wakelock" << endl;
189 }186 }
190 }187 }
191 }188 }
@@ -209,18 +206,16 @@
209 // Only actually clear the system wakelock once the count reaches zero206 // Only actually clear the system wakelock once the count reaches zero
210 if (--system_wakelock_count == 0)207 if (--system_wakelock_count == 0)
211 {208 {
212 cout << "Clearing system wakelock" << endl;209 std::cout << "Clearing system wakelock." << std::endl;
213 powerd_session->invoke_method_synchronously<core::Powerd::clearSysState, void>(sys_cookie);210 system_state_lock->request_release(media::power::SystemState::active);
214 sys_cookie.clear();
215 }211 }
216 break;212 break;
217 case wakelock_clear_t::WAKELOCK_CLEAR_DISPLAY:213 case wakelock_clear_t::WAKELOCK_CLEAR_DISPLAY:
218 // Only actually clear the display wakelock once the count reaches zero214 // Only actually clear the display wakelock once the count reaches zero
219 if (--display_wakelock_count == 0)215 if (--display_wakelock_count == 0)
220 {216 {
221 cout << "Clearing display wakelock" << endl;217 std::cout << "Clearing display wakelock." << std::endl;
222 uscreen_session->invoke_method_synchronously<core::UScreen::removeDisplayOnRequest, void>(disp_cookie);218 display_state_lock->request_release(media::power::DisplayState::on);
223 disp_cookie = -1;
224 }219 }
225 break;220 break;
226 case wakelock_clear_t::WAKELOCK_CLEAR_INVALID:221 case wakelock_clear_t::WAKELOCK_CLEAR_INVALID:
@@ -275,44 +270,33 @@
275 engine->reset();270 engine->reset();
276 }271 }
277272
278 PlayerImplementation* parent;273 // Our link back to our parent.
279 std::shared_ptr<Service> service;274 media::PlayerImplementation* parent;
275 // We just store the parameters passed on construction.
276 media::PlayerImplementation::Configuration config;
277 media::power::StateController::Lock<media::power::DisplayState>::Ptr display_state_lock;
278 media::power::StateController::Lock<media::power::SystemState>::Ptr system_state_lock;
279
280 std::shared_ptr<Engine> engine;280 std::shared_ptr<Engine> engine;
281 dbus::types::ObjectPath session_path;
282 std::shared_ptr<TrackListImplementation> track_list;281 std::shared_ptr<TrackListImplementation> track_list;
283 std::shared_ptr<dbus::Object> powerd_session;
284 std::shared_ptr<dbus::Object> uscreen_session;
285 std::string sys_lock_name;
286 int disp_cookie;
287 std::string sys_cookie;
288 std::atomic<int> system_wakelock_count;282 std::atomic<int> system_wakelock_count;
289 std::atomic<int> display_wakelock_count;283 std::atomic<int> display_wakelock_count;
290 Engine::State previous_state;284 Engine::State previous_state;
291 PlayerImplementation::PlayerKey key;
292 core::Signal<> on_client_disconnected;285 core::Signal<> on_client_disconnected;
293 core::Connection engine_state_change_connection;286 core::Connection engine_state_change_connection;
294};287};
295288
296media::PlayerImplementation::PlayerImplementation(289media::PlayerImplementation::PlayerImplementation(const media::PlayerImplementation::Configuration& config)
297 const std::string& identity,
298 const std::shared_ptr<core::dbus::Bus>& bus,
299 const std::shared_ptr<core::dbus::Object>& session,
300 const std::shared_ptr<Service>& service,
301 PlayerKey key)
302 : media::PlayerSkeleton290 : media::PlayerSkeleton
303 {291 {
304 media::PlayerSkeleton::Configuration292 media::PlayerSkeleton::Configuration
305 {293 {
306 bus,294 config.bus,
307 session,295 config.session,
308 identity296 config.identity
309 }297 }
310 },298 },
311 d(make_shared<Private>(299 d{std::make_shared<Private>(this, config)}
312 this,
313 session->path(),
314 service,
315 key))
316{300{
317 // Initialize default values for Player interface properties301 // Initialize default values for Player interface properties
318 can_play().set(true);302 can_play().set(true);
@@ -464,7 +448,7 @@
464// TODO: Convert this to be a property instead of sync call448// TODO: Convert this to be a property instead of sync call
465media::Player::PlayerKey media::PlayerImplementation::key() const449media::Player::PlayerKey media::PlayerImplementation::key() const
466{450{
467 return d->key;451 return d->config.key;
468}452}
469453
470media::video::Sink::Ptr media::PlayerImplementation::create_gl_texture_video_sink(std::uint32_t texture_id)454media::video::Sink::Ptr media::PlayerImplementation::create_gl_texture_video_sink(std::uint32_t texture_id)
471455
=== modified file 'src/core/media/player_implementation.h'
--- src/core/media/player_implementation.h 2015-03-19 20:49:44 +0000
+++ src/core/media/player_implementation.h 2015-03-19 20:49:45 +0000
@@ -21,6 +21,9 @@
2121
22#include "player_skeleton.h"22#include "player_skeleton.h"
2323
24#include "client_death_observer.h"
25#include "power/state_controller.h"
26
24#include <memory>27#include <memory>
2528
26namespace core29namespace core
@@ -35,12 +38,21 @@
35class PlayerImplementation : public PlayerSkeleton38class PlayerImplementation : public PlayerSkeleton
36{39{
37public:40public:
38 PlayerImplementation(41 // All creation time arguments go here
39 const std::string& identity,42 struct Configuration
40 const std::shared_ptr<core::dbus::Bus>& bus,43 {
41 const std::shared_ptr<core::dbus::Object>& session,44 std::string identity;
42 const std::shared_ptr<Service>& service,45 std::shared_ptr<core::dbus::Bus> bus;
43 PlayerKey key);46 std::shared_ptr<core::dbus::Object> session;
47 std::shared_ptr<Service> service;
48 PlayerKey key;
49
50 // Functional dependencies
51 ClientDeathObserver::Ptr client_death_observer;
52 power::StateController::Ptr power_state_controller;
53 };
54
55 PlayerImplementation(const Configuration& configuration);
44 ~PlayerImplementation();56 ~PlayerImplementation();
4557
46 virtual std::shared_ptr<TrackList> track_list();58 virtual std::shared_ptr<TrackList> track_list();
4759
=== added directory 'src/core/media/power'
=== added file 'src/core/media/power/state_controller.cpp'
--- src/core/media/power/state_controller.cpp 1970-01-01 00:00:00 +0000
+++ src/core/media/power/state_controller.cpp 2015-03-19 20:49:45 +0000
@@ -0,0 +1,360 @@
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: Thomas Voß <thomas.voss@canonical.com>
17 */
18
19#include <core/media/power/state_controller.h>
20
21#include <core/dbus/macros.h>
22#include <core/dbus/object.h>
23
24#include <iostream>
25
26namespace media = core::ubuntu::media;
27
28namespace com { namespace canonical {
29struct Unity
30{
31 struct Screen
32 {
33 static const std::string& name()
34 {
35 static std::string s = "com.canonical.Unity.Screen";
36 return s;
37 }
38
39 static const core::dbus::types::ObjectPath& path()
40 {
41 static core::dbus::types::ObjectPath p{"/com/canonical/Unity/Screen"};
42 return p;
43 }
44
45 DBUS_CPP_METHOD_DEF(keepDisplayOn, Screen)
46 DBUS_CPP_METHOD_DEF(removeDisplayOnRequest, Screen)
47 };
48};
49namespace powerd {
50struct Interface
51{
52 static std::string& name()
53 {
54 static std::string s = "com.canonical.powerd";
55 return s;
56 }
57
58 static const core::dbus::types::ObjectPath& path()
59 {
60 static core::dbus::types::ObjectPath p{"/com/canonical/powerd"};
61 return p;
62 }
63
64 DBUS_CPP_METHOD_DEF(requestSysState, com::canonical::powerd::Interface)
65 DBUS_CPP_METHOD_DEF(clearSysState, com::canonical::powerd::Interface)
66};
67}}}
68
69namespace
70{
71namespace impl
72{
73struct DisplayStateLock : public media::power::StateController::Lock<media::power::DisplayState>,
74 public std::enable_shared_from_this<DisplayStateLock>
75{
76 // To safe us some typing
77 typedef std::shared_ptr<DisplayStateLock> Ptr;
78
79 // We postpone releasing the display for this amount of time.
80 static boost::posix_time::seconds timeout_for_release()
81 {
82 return boost::posix_time::seconds{4};
83 }
84
85 // The invalid cookie marker.
86 static constexpr const std::int32_t the_invalid_cookie{-1};
87
88 DisplayStateLock(const media::power::StateController::Ptr& parent,
89 boost::asio::io_service& io_service,
90 const core::dbus::Object::Ptr& object)
91 : parent{parent},
92 timeout{io_service},
93 object{object},
94 cookie{the_invalid_cookie}
95 {
96 }
97
98 // From core::ubuntu::media::power::StateController::Lock<DisplayState>
99 void request_acquire(media::power::DisplayState state) override
100 {
101 if (state == media::power::DisplayState::off)
102 return;
103
104 std::weak_ptr<DisplayStateLock> wp{shared_from_this()};
105
106 object->invoke_method_asynchronously_with_callback<com::canonical::Unity::Screen::keepDisplayOn, std::int32_t>(
107 [wp, state](const core::dbus::Result<std::int32_t>& result)
108 {
109 if (result.is_error())
110 {
111 std::cerr << result.error().print() << std::endl;
112 return;
113 }
114
115 if (auto sp = wp.lock())
116 {
117 sp->cookie = result.value();
118 sp->signals.acquired(state);
119 }
120 });
121 }
122
123 void request_release(media::power::DisplayState state) override
124 {
125 if (state == media::power::DisplayState::off)
126 return;
127
128 if (cookie == the_invalid_cookie)
129 return;
130
131 // We make sure that we keep ourselves alive to make sure
132 // that release requests are always correctly issued.
133 auto sp = shared_from_this();
134
135 auto current_cookie(cookie);
136
137 timeout.expires_from_now(timeout_for_release());
138 timeout.async_wait([sp, state, current_cookie](const boost::system::error_code& ec)
139 {
140 // We only return early from the timeout handler if the operation has been
141 // explicitly aborted before.
142 if (ec == boost::asio::error::operation_aborted)
143 return;
144
145 sp->object->invoke_method_asynchronously_with_callback<com::canonical::Unity::Screen::removeDisplayOnRequest, void>(
146 [sp, state, current_cookie](const core::dbus::Result<void>& result)
147 {
148 if (result.is_error())
149 {
150 std::cerr << result.error().print() << std::endl;
151 return;
152 }
153
154 sp->signals.released(state);
155
156 // We might have issued a different request before and
157 // only call the display state done if the original cookie
158 // corresponds to the one we just gave up.
159 if (sp->cookie == current_cookie)
160 sp->cookie = the_invalid_cookie;
161
162 }, current_cookie);
163 });
164 }
165
166 // Emitted whenever the acquire request completes.
167 const core::Signal<media::power::DisplayState>& acquired() const override
168 {
169 return signals.acquired;
170 }
171
172 // Emitted whenever the release request completes.
173 const core::Signal<media::power::DisplayState>& released() const override
174 {
175 return signals.released;
176 }
177
178 media::power::StateController::Ptr parent;
179 boost::asio::deadline_timer timeout;
180 core::dbus::Object::Ptr object;
181 std::int32_t cookie;
182
183 struct
184 {
185 core::Signal<media::power::DisplayState> acquired;
186 core::Signal<media::power::DisplayState> released;
187 } signals;
188};
189
190struct SystemStateLock : public media::power::StateController::Lock<media::power::SystemState>,
191 public std::enable_shared_from_this<SystemStateLock>
192{
193 static constexpr const char* wake_lock_name
194 {
195 "media-hub-playback_lock"
196 };
197
198 SystemStateLock(const media::power::StateController::Ptr& parent, const core::dbus::Object::Ptr& object)
199 : parent{parent},
200 object{object}
201 {
202 }
203
204 // Informs the system that the caller would like
205 // the system to stay active.
206 void request_acquire(media::power::SystemState state) override
207 {
208 if (state == media::power::SystemState::suspend)
209 return;
210
211 // Keep scope of this lock tight as to avoid
212 // deadlocks on PlayerImplementation destruction
213 {
214 std::lock_guard<std::mutex> lg{system_state_cookie_store_guard};
215 if (system_state_cookie_store.count(state) > 0)
216 return;
217 }
218
219 std::weak_ptr<SystemStateLock> wp{shared_from_this()};
220
221 object->invoke_method_asynchronously_with_callback<com::canonical::powerd::Interface::requestSysState, std::string>([wp, state](const core::dbus::Result<std::string>& result)
222 {
223 if (result.is_error()) // TODO(tvoss): We should log the error condition here.
224 return;
225
226 if (auto sp = wp.lock())
227 {
228 std::lock_guard<std::mutex> lg{sp->system_state_cookie_store_guard};
229
230 sp->system_state_cookie_store[state] = result.value();
231 sp->signals.acquired(state);
232 }
233 }, std::string{wake_lock_name}, static_cast<std::int32_t>(state));
234 }
235
236 // Informs the system that the caller does not
237 // require the system to stay active anymore.
238 void request_release(media::power::SystemState state) override
239 {
240 if (state == media::power::SystemState::suspend)
241 return;
242
243 std::lock_guard<std::mutex> lg{system_state_cookie_store_guard};
244
245 if (system_state_cookie_store.count(state) == 0)
246 return;
247
248 std::weak_ptr<SystemStateLock> wp{shared_from_this()};
249
250 object->invoke_method_asynchronously_with_callback<com::canonical::powerd::Interface::clearSysState, void>([wp, state](const core::dbus::Result<void>& result)
251 {
252 if (result.is_error())
253 std::cerr << result.error().print() << std::endl;
254
255 if (auto sp = wp.lock())
256 {
257 std::lock_guard<std::mutex> lg{sp->system_state_cookie_store_guard};
258
259 sp->system_state_cookie_store.erase(state);
260 sp->signals.released(state);
261 }
262 }, system_state_cookie_store.at(state));
263 }
264
265 // Emitted whenever the acquire request completes.
266 const core::Signal<media::power::SystemState>& acquired() const override
267 {
268 return signals.acquired;
269 }
270
271 // Emitted whenever the release request completes.
272 const core::Signal<media::power::SystemState>& released() const override
273 {
274 return signals.released;
275 }
276
277 // Guards concurrent accesses to the cookie store.
278 std::mutex system_state_cookie_store_guard;
279 // Maps previously requested system states to the cookies returned
280 // by the remote end. Used for keeping track of acquired states and
281 // associated cookies to be able to release previously granted acquisitions.
282 std::map<media::power::SystemState, std::string> system_state_cookie_store;
283 media::power::StateController::Ptr parent;
284 core::dbus::Object::Ptr object;
285 struct
286 {
287 core::Signal<media::power::SystemState> acquired;
288 core::Signal<media::power::SystemState> released;
289 } signals;
290};
291
292struct StateController : public media::power::StateController,
293 public std::enable_shared_from_this<impl::StateController>
294{
295 StateController(media::helper::ExternalServices& es)
296 : external_services{es},
297 powerd
298 {
299 core::dbus::Service::use_service<com::canonical::powerd::Interface>(external_services.system)
300 ->object_for_path(com::canonical::powerd::Interface::path())
301 },
302 unity_screen
303 {
304 core::dbus::Service::use_service<com::canonical::Unity::Screen>(external_services.system)
305 ->object_for_path(com::canonical::Unity::Screen::path())
306 }
307 {
308 }
309
310 media::power::StateController::Lock<media::power::SystemState>::Ptr system_state_lock() override
311 {
312 return std::make_shared<impl::SystemStateLock>(shared_from_this(), powerd);
313 }
314
315 media::power::StateController::Lock<media::power::DisplayState>::Ptr display_state_lock() override
316 {
317 return std::make_shared<impl::DisplayStateLock>(shared_from_this(), external_services.io_service, unity_screen);
318 }
319
320 media::helper::ExternalServices& external_services;
321 core::dbus::Object::Ptr powerd;
322 core::dbus::Object::Ptr unity_screen;
323};
324}
325}
326
327media::power::StateController::Ptr media::power::make_platform_default_state_controller(core::ubuntu::media::helper::ExternalServices& external_services)
328{
329 return std::make_shared<impl::StateController>(external_services);
330}
331
332// operator<< pretty prints the given display state to the given output stream.
333std::ostream& media::power::operator<<(std::ostream& out, media::power::DisplayState state)
334{
335 switch (state)
336 {
337 case media::power::DisplayState::off:
338 return out << "DisplayState::off";
339 case media::power::DisplayState::on:
340 return out << "DisplayState::on";
341 }
342
343 return out;
344}
345
346// operator<< pretty prints the given system state to the given output stream.
347std::ostream& media::power::operator<<(std::ostream& out, media::power::SystemState state)
348{
349 switch (state)
350 {
351 case media::power::SystemState::active:
352 return out << "SystemState::active";
353 case media::power::SystemState::blank_on_proximity:
354 return out << "SystemState::blank_on_proximity";
355 case media::power::SystemState::suspend:
356 return out << "SystemState::suspend";
357 }
358
359 return out;
360}
0361
=== added file 'src/core/media/power/state_controller.h'
--- src/core/media/power/state_controller.h 1970-01-01 00:00:00 +0000
+++ src/core/media/power/state_controller.h 2015-03-19 20:49:45 +0000
@@ -0,0 +1,108 @@
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: Thomas Voß <thomas.voss@canonical.com>
17 */
18#ifndef CORE_UBUNTU_MEDIA_POWER_STATE_CONTROLLER_H_
19#define CORE_UBUNTU_MEDIA_POWER_STATE_CONTROLLER_H_
20
21#include <core/media/external_services.h>
22
23#include <core/property.h>
24
25#include <iosfwd>
26#include <memory>
27
28namespace core
29{
30namespace ubuntu
31{
32namespace media
33{
34namespace power
35{
36// Enumerates all known power states of a display.
37enum class DisplayState
38{
39 // The display is off.
40 off = 0,
41 // The display is on.
42 on = 1
43};
44
45// Enumerates known power states of the system.
46enum class SystemState
47{
48 // Note that callers will be notified of suspend state changes
49 // but may not request this state.
50 suspend = 0,
51 // The Active state will prevent system suspend
52 active = 1,
53 // Substate of Active with disabled proximity based blanking
54 blank_on_proximity = 2
55};
56
57// Interface that enables observation of the system power state.
58struct StateController
59{
60 // To save us some typing.
61 typedef std::shared_ptr<StateController> Ptr;
62
63 // When acquired, ensures that the system stays active,
64 // and decreases the reference count when released.
65 template<typename State>
66 struct Lock
67 {
68 // To save us some typing.
69 typedef std::shared_ptr<Lock> Ptr;
70
71 Lock() = default;
72 virtual ~Lock() = default;
73
74 // Informs the system that the caller would like
75 // the system to stay active.
76 virtual void request_acquire(State state) = 0;
77 // Informs the system that the caller does not
78 // require the system to stay active anymore.
79 virtual void request_release(State state) = 0;
80
81 // Emitted whenever the acquire request completes.
82 virtual const core::Signal<State>& acquired() const = 0;
83 // Emitted whenever the release request completes.
84 virtual const core::Signal<State>& released() const = 0;
85 };
86
87 StateController() = default;
88 virtual ~StateController() = default;
89
90 // Returns a power::StateController::Lock<DisplayState> instance.
91 virtual Lock<DisplayState>::Ptr display_state_lock() = 0;
92 // Returns a power::StateController::Lock<SystemState> instance.
93 virtual Lock<SystemState>::Ptr system_state_lock() = 0;
94};
95
96// Creates a StateController instance that connects to the platform default
97// services to control system and display power states.
98StateController::Ptr make_platform_default_state_controller(core::ubuntu::media::helper::ExternalServices&);
99
100// operator<< pretty prints the given display state to the given output stream.
101std::ostream& operator<<(std::ostream& out, DisplayState state);
102// operator<< pretty prints the given system state to the given output stream.
103std::ostream& operator<<(std::ostream& out, SystemState state);
104}
105}
106}
107}
108#endif // CORE_UBUNTU_MEDIA_POWER_STATE_CONTROLLER_H_
0109
=== removed file 'src/core/media/powerd_service.h'
--- src/core/media/powerd_service.h 2014-08-08 14:36:29 +0000
+++ src/core/media/powerd_service.h 1970-01-01 00:00:00 +0000
@@ -1,73 +0,0 @@
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: Ricardo Mendoza <ricardo.mendoza@canonical.com>
17 */
18
19#include <core/dbus/dbus.h>
20#include <core/dbus/fixture.h>
21#include <core/dbus/object.h>
22#include <core/dbus/property.h>
23#include <core/dbus/service.h>
24#include <core/dbus/interfaces/properties.h>
25#include <core/dbus/types/stl/tuple.h>
26#include <core/dbus/types/stl/vector.h>
27
28#include <core/dbus/asio/executor.h>
29
30#include <string>
31#include <vector>
32#include <chrono>
33
34namespace core
35{
36
37struct Powerd
38{
39 static std::string& name()
40 {
41 static std::string s = "com.canonical.powerd";
42 return s;
43 }
44
45 struct requestSysState
46 {
47 static std::string name()
48 {
49 static std::string s = "requestSysState";
50 return s;
51 }
52
53 static const std::chrono::milliseconds default_timeout() { return std::chrono::seconds{1}; }
54
55 typedef Powerd Interface;
56 };
57
58 struct clearSysState
59 {
60 static std::string name()
61 {
62 static std::string s = "clearSysState";
63 return s;
64 }
65
66 static const std::chrono::milliseconds default_timeout() { return std::chrono::seconds{1}; }
67
68 typedef Powerd Interface;
69 };
70
71};
72
73}
740
=== modified file 'src/core/media/server/server.cpp'
--- src/core/media/server/server.cpp 2014-04-04 14:31:43 +0000
+++ src/core/media/server/server.cpp 2015-03-19 20:49:45 +0000
@@ -20,24 +20,137 @@
20#include <core/media/player.h>20#include <core/media/player.h>
21#include <core/media/track_list.h>21#include <core/media/track_list.h>
2222
23#include <hybris/media/media_codec_layer.h>
24
25#include "core/media/service_implementation.h"23#include "core/media/service_implementation.h"
2624
25#include <core/posix/signal.h>
26
27#include <iostream>27#include <iostream>
2828
29namespace media = core::ubuntu::media;29namespace media = core::ubuntu::media;
3030
31using namespace std;31using namespace std;
3232
33#if defined(MEDIA_HUB_HAVE_HYBRIS_MEDIA_COMPAT_LAYER)
34#include <hybris/media/media_codec_layer.h>
35
36namespace
37{
38// All platform-specific initialization routines go here.
39void platform_init()
40{
41 decoding_service_init();
42}
43}
44#else // MEDIA_HUB_HAVE_HYBRIS_MEDIA_COMPAT_LAYER
45namespace
46{
47// All platform-specific initialization routines go here.
48void platform_init()
49{
50 // Consciously left empty
51}
52}
53#endif // MEDIA_HUB_HAVE_HYBRIS_MEDIA_COMPAT_LAYER
54
33int main()55int main()
34{56{
35 // Init hybris-level DecodingService57 auto trap = core::posix::trap_signals_for_all_subsequent_threads(
36 decoding_service_init();58 {
37 cout << "Starting DecodingService..." << endl;59 core::posix::Signal::sig_int,
3860 core::posix::Signal::sig_term
39 auto service = std::make_shared<media::ServiceImplementation>();61 });
40 service->run();62
63 trap->signal_raised().connect([trap](core::posix::Signal)
64 {
65 trap->stop();
66 });
67
68 // Init platform-specific functionality.
69 platform_init();
70
71 // We keep track of our state.
72 bool shutdown_requested{false};
73
74 // Our helper for connecting to external services.
75 core::ubuntu::media::helper::ExternalServices external_services;
76
77 // We move communication with all external services to its own worker thread
78 // to keep the actual service thread free from such operations.
79 std::thread external_services_worker
80 {
81 // We keep on running until shutdown has been explicitly requested.
82 // All exceptions thrown on this thread are caught, and reported to
83 // the terminal for post-mortem debugging purposes.
84 [&shutdown_requested, &external_services]()
85 {
86 while (not shutdown_requested)
87 {
88 try
89 {
90 // Blocking call to the underlying reactor implementation.
91 // Only returns cleanly when explicitly stopped.
92 external_services.io_service.run();
93 }
94 catch (const std::exception& e)
95 {
96 std::cerr << "Error while executing the underlying io_service: " << e.what() << std::endl;
97 }
98 catch (...)
99 {
100 std::cerr << "Error while executing the underlying io_service." << std::endl;
101 }
102 }
103 }
104 };
105
106 // We assemble the configuration for executing the service now.
107 media::ServiceImplementation::Configuration service_config
108 {
109 external_services
110 };
111
112 auto service = std::make_shared<media::ServiceImplementation>(service_config);
113
114 std::thread service_worker
115 {
116 [&shutdown_requested, service]()
117 {
118 while (not shutdown_requested)
119 {
120 try
121 {
122 service->run();
123 }
124 catch (const std::exception& e)
125 {
126 std::cerr << "Recoverable error while executing the service: " << e.what() << std::endl;
127 }
128 catch (...)
129 {
130 std::cerr << "Recoverable error while executing the service." << std::endl;
131 }
132 }
133 }
134 };
135
136 // We block on waiting for signals telling us to gracefully shutdown.
137 // Incoming signals are handled in a lambda connected to signal_raised()
138 // which is setup at the beginning of main(...).
139 trap->run();
140
141 // Inform our workers that we should shutdown gracefully
142 shutdown_requested = true;
143
144 // And stop execution of helper and actual service.
145 service->stop();
146
147 if (service_worker.joinable())
148 service_worker.join();
149
150 external_services.stop();
151
152 if (external_services_worker.joinable())
153 external_services_worker.join();
41154
42 return 0;155 return 0;
43}156}
44157
=== modified file 'src/core/media/service_implementation.cpp'
--- src/core/media/service_implementation.cpp 2015-03-19 20:49:44 +0000
+++ src/core/media/service_implementation.cpp 2015-03-19 20:49:45 +0000
@@ -22,6 +22,7 @@
2222
23#include "service_implementation.h"23#include "service_implementation.h"
2424
25#include "client_death_observer.h"
25#include "indicator_power_service.h"26#include "indicator_power_service.h"
26#include "call-monitor/call_monitor.h"27#include "call-monitor/call_monitor.h"
27#include "player_configuration.h"28#include "player_configuration.h"
@@ -40,7 +41,6 @@
40#include <pulse/pulseaudio.h>41#include <pulse/pulseaudio.h>
4142
42#include "util/timeout.h"43#include "util/timeout.h"
43#include "unity_screen_service.h"
4444
45namespace media = core::ubuntu::media;45namespace media = core::ubuntu::media;
4646
@@ -48,10 +48,13 @@
4848
49struct media::ServiceImplementation::Private49struct media::ServiceImplementation::Private
50{50{
51 Private()51 Private(const ServiceImplementation::Configuration& configuration)
52 : resume_key(std::numeric_limits<std::uint32_t>::max()),52 : configuration(configuration),
53 keep_alive(io_service),53 resume_key(std::numeric_limits<std::uint32_t>::max()),
54 disp_cookie(0),54 power_state_controller(media::power::make_platform_default_state_controller(configuration.external_services)),
55 display_state_lock(power_state_controller->display_state_lock()),
56 client_death_observer(media::platform_default_client_death_observer()),
57 recorder_observer(media::make_platform_default_recorder_observer()),
55 pulse_mainloop_api(nullptr),58 pulse_mainloop_api(nullptr),
56 pulse_context(nullptr),59 pulse_context(nullptr),
57 headphones_connected(false),60 headphones_connected(false),
@@ -59,13 +62,6 @@
59 primary_idx(-1),62 primary_idx(-1),
60 call_monitor(new CallMonitor)63 call_monitor(new CallMonitor)
61 {64 {
62 bus = std::shared_ptr<dbus::Bus>(new dbus::Bus(core::dbus::WellKnownBus::session));
63 bus->install_executor(dbus::asio::make_executor(bus, io_service));
64 worker = std::move(std::thread([this]()
65 {
66 bus->run();
67 }));
68
69 // Spawn pulse watchdog65 // Spawn pulse watchdog
70 pulse_mainloop = nullptr;66 pulse_mainloop = nullptr;
71 pulse_worker = std::move(std::thread([this]()67 pulse_worker = std::move(std::thread([this]()
@@ -129,19 +125,11 @@
129125
130 // Connect the property change signal that will allow media-hub to take appropriate action126 // Connect the property change signal that will allow media-hub to take appropriate action
131 // when the battery level reaches critical127 // when the battery level reaches critical
132 auto stub_service = dbus::Service::use_service(bus, "com.canonical.indicator.power");128 auto stub_service = dbus::Service::use_service(configuration.external_services.session, "com.canonical.indicator.power");
133 indicator_power_session = stub_service->object_for_path(dbus::types::ObjectPath("/com/canonical/indicator/power/Battery"));129 indicator_power_session = stub_service->object_for_path(dbus::types::ObjectPath("/com/canonical/indicator/power/Battery"));
134 power_level = indicator_power_session->get_property<core::IndicatorPower::PowerLevel>();130 power_level = indicator_power_session->get_property<core::IndicatorPower::PowerLevel>();
135 is_warning = indicator_power_session->get_property<core::IndicatorPower::IsWarning>();131 is_warning = indicator_power_session->get_property<core::IndicatorPower::IsWarning>();
136132
137 // Obtain session with Unity.Screen so that we request state when doing recording
138 auto bus = std::shared_ptr<dbus::Bus>(new dbus::Bus(core::dbus::WellKnownBus::system));
139 bus->install_executor(dbus::asio::make_executor(bus));
140
141 auto uscreen_stub_service = dbus::Service::use_service(bus, dbus::traits::Service<core::UScreen>::interface_name());
142 uscreen_session = uscreen_stub_service->object_for_path(dbus::types::ObjectPath("/com/canonical/Unity/Screen"));
143
144 recorder_observer = media::make_platform_default_recorder_observer();
145 recorder_observer->recording_state().changed().connect([this](media::RecordingState state)133 recorder_observer->recording_state().changed().connect([this](media::RecordingState state)
146 {134 {
147 media_recording_state_changed(state);135 media_recording_state_changed(state);
@@ -159,42 +147,20 @@
159 pulse_mainloop = nullptr;147 pulse_mainloop = nullptr;
160 }148 }
161149
162 bus->stop();
163
164 if (worker.joinable())
165 worker.join();
166
167 if (pulse_worker.joinable())150 if (pulse_worker.joinable())
168 pulse_worker.join();151 pulse_worker.join();
169 }152 }
170153
171 void media_recording_state_changed(media::RecordingState state)154 void media_recording_state_changed(media::RecordingState state)
172 {155 {
173 if (uscreen_session == nullptr)
174 return;
175
176 if (state == media::RecordingState::started)156 if (state == media::RecordingState::started)
177 {157 {
178 if (disp_cookie > 0)158 display_state_lock->request_acquire(media::power::DisplayState::on);
179 return;
180
181 // Make sure we pause all playback sessions so that it doesn't interfere with recorded audio
182 pause_playback();159 pause_playback();
183
184 auto result = uscreen_session->invoke_method_synchronously<core::UScreen::keepDisplayOn, int>();
185 if (result.is_error())
186 throw std::runtime_error(result.error().print());
187 disp_cookie = result.value();
188 }160 }
189 else if (state == media::RecordingState::stopped)161 else if (state == media::RecordingState::stopped)
190 {162 {
191 if (disp_cookie != -1)163 display_state_lock->request_release(media::power::DisplayState::on);
192 {
193 timeout(4000, true, [this](){
194 this->uscreen_session->invoke_method_synchronously<core::UScreen::removeDisplayOnRequest, void>(this->disp_cookie);
195 this->disp_cookie = -1;
196 });
197 }
198 }164 }
199 }165 }
200166
@@ -441,18 +407,16 @@
441 }407 }
442 }408 }
443409
410 media::ServiceImplementation::Configuration configuration;
444 // This holds the key of the multimedia role Player instance that was paused411 // This holds the key of the multimedia role Player instance that was paused
445 // when the battery level reached 10% or 5%412 // when the battery level reached 10% or 5%
446 media::Player::PlayerKey resume_key;413 media::Player::PlayerKey resume_key;
447 std::thread worker;
448 dbus::Bus::Ptr bus;
449 boost::asio::io_service io_service;
450 boost::asio::io_service::work keep_alive;
451 std::shared_ptr<dbus::Object> indicator_power_session;414 std::shared_ptr<dbus::Object> indicator_power_session;
452 std::shared_ptr<core::dbus::Property<core::IndicatorPower::PowerLevel>> power_level;415 std::shared_ptr<core::dbus::Property<core::IndicatorPower::PowerLevel>> power_level;
453 std::shared_ptr<core::dbus::Property<core::IndicatorPower::IsWarning>> is_warning;416 std::shared_ptr<core::dbus::Property<core::IndicatorPower::IsWarning>> is_warning;
454 int disp_cookie;417 media::power::StateController::Ptr power_state_controller;
455 std::shared_ptr<dbus::Object> uscreen_session;418 media::power::StateController::Lock<media::power::DisplayState>::Ptr display_state_lock;
419 media::ClientDeathObserver::Ptr client_death_observer;
456 media::RecorderObserver::Ptr recorder_observer;420 media::RecorderObserver::Ptr recorder_observer;
457 // Pulse-specific421 // Pulse-specific
458 pa_mainloop_api *pulse_mainloop_api;422 pa_mainloop_api *pulse_mainloop_api;
@@ -474,7 +438,7 @@
474 std::list<media::Player::PlayerKey> paused_sessions;438 std::list<media::Player::PlayerKey> paused_sessions;
475};439};
476440
477media::ServiceImplementation::ServiceImplementation() : d(new Private())441media::ServiceImplementation::ServiceImplementation(const Configuration& configuration) : d(new Private(configuration))
478{442{
479 d->power_level->changed().connect([this](const core::IndicatorPower::PowerLevel::ValueType &level)443 d->power_level->changed().connect([this](const core::IndicatorPower::PowerLevel::ValueType &level)
480 {444 {
@@ -520,8 +484,16 @@
520std::shared_ptr<media::Player> media::ServiceImplementation::create_session(484std::shared_ptr<media::Player> media::ServiceImplementation::create_session(
521 const media::Player::Configuration& conf)485 const media::Player::Configuration& conf)
522{486{
523 auto player = std::make_shared<media::PlayerImplementation>(487 auto player = std::make_shared<media::PlayerImplementation>(media::PlayerImplementation::Configuration
524 conf.identity, conf.bus, conf.session, shared_from_this(), conf.key);488 {
489 conf.identity,
490 conf.bus,
491 conf.session,
492 shared_from_this(),
493 conf.key,
494 d->client_death_observer,
495 d->power_state_controller
496 });
525497
526 auto key = conf.key;498 auto key = conf.key;
527 player->on_client_disconnected().connect([this, key]()499 player->on_client_disconnected().connect([this, key]()
@@ -531,7 +503,7 @@
531 // remove_player_for_key can destroy the player instance which in turn503 // remove_player_for_key can destroy the player instance which in turn
532 // destroys the "on_client_disconnected" signal whose destructor will wait504 // destroys the "on_client_disconnected" signal whose destructor will wait
533 // until all dispatches are done505 // until all dispatches are done
534 d->io_service.post([this, key]()506 d->configuration.external_services.io_service.post([this, key]()
535 {507 {
536 if (!has_player_for_key(key))508 if (!has_player_for_key(key))
537 return;509 return;
538510
=== 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-19 20:49:45 +0000
@@ -20,6 +20,7 @@
20#define CORE_UBUNTU_MEDIA_SERVICE_IMPLEMENTATION_H_20#define CORE_UBUNTU_MEDIA_SERVICE_IMPLEMENTATION_H_
2121
22#include "service_skeleton.h"22#include "service_skeleton.h"
23#include "external_services.h"
2324
24namespace core25namespace core
25{26{
@@ -27,13 +28,18 @@
27{28{
28namespace media29namespace media
29{30{
30
31class Player;31class Player;
3232
33class ServiceImplementation : public ServiceSkeleton33class ServiceImplementation : public ServiceSkeleton
34{34{
35public:35public:
36 ServiceImplementation ();36 // All creation time arguments go here.
37 struct Configuration
38 {
39 helper::ExternalServices& external_services;
40 };
41
42 ServiceImplementation (const Configuration& configuration);
37 ~ServiceImplementation ();43 ~ServiceImplementation ();
3844
39 std::shared_ptr<Player> create_session(const Player::Configuration&);45 std::shared_ptr<Player> create_session(const Player::Configuration&);
4046
=== removed file 'src/core/media/unity_screen_service.h'
--- src/core/media/unity_screen_service.h 2014-06-16 22:28:53 +0000
+++ src/core/media/unity_screen_service.h 1970-01-01 00:00:00 +0000
@@ -1,72 +0,0 @@
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: Alberto Aguirre <alberto.aguirre@canonical.com>
17 */
18
19#include <core/dbus/dbus.h>
20#include <core/dbus/fixture.h>
21#include <core/dbus/object.h>
22#include <core/dbus/property.h>
23#include <core/dbus/service.h>
24#include <core/dbus/interfaces/properties.h>
25#include <core/dbus/types/stl/tuple.h>
26#include <core/dbus/types/stl/vector.h>
27
28#include <core/dbus/asio/executor.h>
29
30#include <string>
31#include <vector>
32#include <chrono>
33
34namespace core
35{
36
37struct UScreen
38{
39 static std::string& name()
40 {
41 static std::string s = "com.canonical.Unity.Screen";
42 return s;
43 }
44
45 struct keepDisplayOn
46 {
47 static std::string name()
48 {
49 static std::string s = "keepDisplayOn";
50 return s;
51 }
52
53 static const std::chrono::milliseconds default_timeout() { return std::chrono::seconds{1}; }
54
55 typedef UScreen Interface;
56 };
57
58 struct removeDisplayOnRequest
59 {
60 static std::string name()
61 {
62 static std::string s = "removeDisplayOnRequest";
63 return s;
64 }
65
66 static const std::chrono::milliseconds default_timeout() { return std::chrono::seconds{1}; }
67
68 typedef UScreen Interface;
69 };
70};
71
72}
730
=== modified file 'tests/CMakeLists.txt'
--- tests/CMakeLists.txt 2014-02-14 08:12:35 +0000
+++ tests/CMakeLists.txt 2015-03-19 20:49:45 +0000
@@ -50,5 +50,5 @@
50 "COM_UBUNTU_MEDIA_SERVICE_AUDIO_SINK_NAME=fakesink"50 "COM_UBUNTU_MEDIA_SERVICE_AUDIO_SINK_NAME=fakesink"
51)51)
5252
53add_subdirectory(acceptance-tests)53# add_subdirectory(acceptance-tests)
54add_subdirectory(unit-tests)54add_subdirectory(unit-tests)

Subscribers

People subscribed via source and target branches