Merge lp:~thomas-voss/media-hub/decouple-service-skeleton-and-implementation into lp:media-hub

Proposed by Thomas Voß
Status: Superseded
Proposed branch: lp:~thomas-voss/media-hub/decouple-service-skeleton-and-implementation
Merge into: lp:media-hub
Prerequisite: lp:~thomas-voss/media-hub/introduce-apparmor-interfaces
Diff against target: 668 lines (+325/-112)
9 files modified
src/core/media/CMakeLists.txt (+2/-1)
src/core/media/hashed_keyed_player_store.cpp (+80/-0)
src/core/media/hashed_keyed_player_store.h (+76/-0)
src/core/media/keyed_player_store.h (+83/-0)
src/core/media/server/server.cpp (+19/-4)
src/core/media/service_implementation.cpp (+11/-11)
src/core/media/service_implementation.h (+2/-1)
src/core/media/service_skeleton.cpp (+38/-70)
src/core/media/service_skeleton.h (+14/-25)
To merge this branch: bzr merge lp:~thomas-voss/media-hub/decouple-service-skeleton-and-implementation
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Approve
Jim Hodapp (community) code Needs Fixing
Review via email: mp+243283@code.launchpad.net

This proposal has been superseded by a proposal from 2015-03-04.

Commit message

Decouple the ServiceSkeleton from the ServiceImplementation by introducing a common interface media::KeyedPlayerStore for storing running Player sessions indexed by the Player::Key.
Provide a default implementation HashedKeyedPlayerStore relying on a hash map for keeping track of player instances.
Adjust implementation to account for ServiceImplementation no longer inheriting from ServiceSkeleton.

Description of the change

Decouple the ServiceSkeleton from the ServiceImplementation by introducing a common interface media::KeyedPlayerStore for storing running Player sessions indexed by the Player::Key.
Provide a default implementation HashedKeyedPlayerStore relying on a hash map for keeping track of player instances.
Adjust implementation to account for ServiceImplementation no longer inheriting from ServiceSkeleton.

To post a comment you must log in.
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 :

One simple change listed below.

review: Needs Fixing (code)
113. By Thomas Voß

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

Revision history for this message
Thomas Voß (thomas-voss) :
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
114. 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)
Revision history for this message
Francis Ginther (fginther) wrote :

The jenkins node for the amd64 build failed, I've restarted a new ci run.

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

Merge prereq branch.

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

Merge prereq branch.

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

Merge prereq branch.

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

Unmerged revisions

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-04 16:37:33 +0000
+++ src/core/media/CMakeLists.txt 2015-03-04 16:37:33 +0000
@@ -87,7 +87,8 @@
87 ${MPRIS_HEADERS}87 ${MPRIS_HEADERS}
8888
89 client_death_observer.cpp89 client_death_observer.cpp
90 hybris_client_death_observer.cpp90 hashed_keyed_player_store.cpp
91 hybris_client_death_observer.cpp
91 cover_art_resolver.cpp92 cover_art_resolver.cpp
92 engine.cpp93 engine.cpp
9394
9495
=== added file 'src/core/media/hashed_keyed_player_store.cpp'
--- src/core/media/hashed_keyed_player_store.cpp 1970-01-01 00:00:00 +0000
+++ src/core/media/hashed_keyed_player_store.cpp 2015-03-04 16:37:33 +0000
@@ -0,0 +1,80 @@
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/hashed_keyed_player_store.h>
20
21namespace media = core::ubuntu::media;
22
23media::HashedKeyedPlayerStore::HashedKeyedPlayerStore()
24{
25}
26
27const core::Property<std::shared_ptr<media::Player>>& media::HashedKeyedPlayerStore::current_player() const
28{
29 return prop_current_player;
30}
31
32bool media::HashedKeyedPlayerStore::has_player_for_key(const media::Player::PlayerKey& key) const
33{
34 std::lock_guard<std::mutex> lg{guard};
35 return map.count(key) > 0;
36}
37
38std::shared_ptr<media::Player> media::HashedKeyedPlayerStore::player_for_key(const media::Player::PlayerKey& key) const
39{
40 std::lock_guard<std::mutex> lg{guard};
41 auto it = map.find(key);
42
43 if (it == map.end()) throw std::out_of_range
44 {
45 "HashedKeyedPlayerStore::player_for_key: No player known for " + std::to_string(key)
46 };
47
48 return it->second;
49}
50
51void media::HashedKeyedPlayerStore::enumerate_players(const media::KeyedPlayerStore::PlayerEnumerator& enumerator) const
52{
53 std::lock_guard<std::mutex> lg{guard};
54 for (const auto& pair : map)
55 enumerator(pair.first, pair.second);
56}
57
58void media::HashedKeyedPlayerStore::add_player_for_key(const media::Player::PlayerKey& key, const std::shared_ptr<media::Player>& player)
59{
60 std::lock_guard<std::mutex> lg{guard};
61 map[key] = player;
62}
63
64void media::HashedKeyedPlayerStore::remove_player_for_key(const media::Player::PlayerKey& key)
65{
66 std::lock_guard<std::mutex> lg{guard};
67 auto it = map.find(key);
68 if (it != map.end())
69 {
70 if (prop_current_player == it->second)
71 prop_current_player = nullptr;
72
73 map.erase(it);
74 }
75}
76
77void media::HashedKeyedPlayerStore::set_current_player_for_key(const media::Player::PlayerKey& key)
78{
79 prop_current_player = player_for_key(key);
80}
081
=== added file 'src/core/media/hashed_keyed_player_store.h'
--- src/core/media/hashed_keyed_player_store.h 1970-01-01 00:00:00 +0000
+++ src/core/media/hashed_keyed_player_store.h 2015-03-04 16:37:33 +0000
@@ -0,0 +1,76 @@
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#ifndef CORE_UBUNTU_MEDIA_HASHED_KEYED_PLAYER_STORE_H_
20#define CORE_UBUNTU_MEDIA_HASHED_KEYED_PLAYER_STORE_H_
21
22#include <core/media/keyed_player_store.h>
23
24#include <mutex>
25#include <unordered_map>
26
27namespace core
28{
29namespace ubuntu
30{
31namespace media
32{
33// Implements KeyedPlayerStore using a std::unordered_map.
34class HashedKeyedPlayerStore : public KeyedPlayerStore
35{
36public:
37 HashedKeyedPlayerStore();
38 // We keep track of the "current" player, that is, the one
39 // that has been created most recently, or has been explicitly foregrounded, or has been enabled for
40 // background playback. We provide a getable/observable access to that designated instance.
41 const core::Property<std::shared_ptr<media::Player>>& current_player() const override;
42
43 // We keep track of all known player sessions here and render them accessible via
44 // the key. All of these functions are thread-safe but not reentrant.
45 // Returns true iff a player is known for the given key.
46 bool has_player_for_key(const Player::PlayerKey& key) const override;
47
48 // Returns the player for the given key or throws std::out_of_range if no player is known
49 // for the given key.
50 // Throws std::out_of_range if no player is known for the key.
51 std::shared_ptr<Player> player_for_key(const Player::PlayerKey& key) const override;
52
53 // Enumerates all known players and invokes the given enumerator for each
54 // (key, player) pair.
55 void enumerate_players(const PlayerEnumerator& enumerator) const override;
56
57 // Adds the given player with the given key.
58 void add_player_for_key(const Player::PlayerKey& key, const std::shared_ptr<Player>& player) override;
59
60 // Removes the player for the given key, and unsets it if it is the current one.
61 void remove_player_for_key(const Player::PlayerKey& key) override;
62
63 // Makes the player known under the given key current.
64 // Throws std::out_of_range if no player is known for the key.
65 void set_current_player_for_key(const Player::PlayerKey& key) override;
66
67private:
68 core::Property<std::shared_ptr<Player>> prop_current_player;
69 mutable std::mutex guard;
70 std::unordered_map<Player::PlayerKey, std::shared_ptr<Player>> map;
71};
72}
73}
74}
75
76#endif // CORE_UBUNTU_MEDIA_KEYED_PLAYER_STORE_H_
077
=== added file 'src/core/media/keyed_player_store.cpp'
=== added file 'src/core/media/keyed_player_store.h'
--- src/core/media/keyed_player_store.h 1970-01-01 00:00:00 +0000
+++ src/core/media/keyed_player_store.h 2015-03-04 16:37:33 +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
19#ifndef CORE_UBUNTU_MEDIA_KEYED_PLAYER_STORE_H_
20#define CORE_UBUNTU_MEDIA_KEYED_PLAYER_STORE_H_
21
22#include <core/media/player.h>
23
24#include <core/property.h>
25
26#include <functional>
27#include <memory>
28
29namespace core
30{
31namespace ubuntu
32{
33namespace media
34{
35// An interface abstracting keyed lookups of known Player instances.
36class KeyedPlayerStore
37{
38public:
39 // Save us some typing.
40 typedef std::shared_ptr<KeyedPlayerStore> Ptr;
41 // Functor for enumerating all known (key, player) pairs.
42 typedef std::function
43 <
44 void(
45 // The key of the player.
46 const Player::PlayerKey&,
47 // The actual player instance.
48 const std::shared_ptr<Player>&
49 )
50 > PlayerEnumerator;
51 // We keep track of the "current" player, that is, the one
52 // that has been created most recently and provide a getable/observable
53 // access to that designated instance.
54 virtual const core::Property<std::shared_ptr<Player>>& current_player() const = 0;
55
56 // We keep track of all known player sessions here and render them accessible via
57 // the key. All of these functions are thread-safe but not reentrant.
58 // Returns true iff a player is known for the given key.
59 virtual bool has_player_for_key(const Player::PlayerKey& key) const = 0;
60 // Returns the player for the given key or throws std::out_of_range if no player is known
61 // for the given key.
62 virtual std::shared_ptr<Player> player_for_key(const Player::PlayerKey& key) const = 0;
63 // Enumerates all known players and invokes the given enumerator for each
64 // (key, player) pair.
65 virtual void enumerate_players(const PlayerEnumerator& enumerator) const = 0;
66 // Adds the given player with the given key.
67 virtual void add_player_for_key(const Player::PlayerKey& key, const std::shared_ptr<Player>& player) = 0;
68 // Removes the player for the given key, and unsets it if it is the current one.
69 virtual void remove_player_for_key(const Player::PlayerKey& key) = 0;
70 // Makes the player known under the given key current.
71 virtual void set_current_player_for_key(const Player::PlayerKey& key) = 0;
72
73protected:
74 KeyedPlayerStore() = default;
75 KeyedPlayerStore(const KeyedPlayerStore&) = delete;
76 virtual ~KeyedPlayerStore() = default;
77 KeyedPlayerStore& operator=(const KeyedPlayerStore&) = delete;
78};
79}
80}
81}
82
83#endif // CORE_UBUNTU_MEDIA_KEYED_PLAYER_STORE_H_
084
=== modified file 'src/core/media/server/server.cpp'
--- src/core/media/server/server.cpp 2015-03-04 16:37:33 +0000
+++ src/core/media/server/server.cpp 2015-03-04 16:37:33 +0000
@@ -20,6 +20,7 @@
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 "core/media/hashed_keyed_player_store.h"
23#include "core/media/service_implementation.h"24#include "core/media/service_implementation.h"
2425
25#include <core/posix/signal.h>26#include <core/posix/signal.h>
@@ -103,23 +104,37 @@
103 }104 }
104 };105 };
105106
107 // Our common player store instance for tracking player instances.
108 auto player_store = std::make_shared<media::HashedKeyedPlayerStore>();
106 // We assemble the configuration for executing the service now.109 // We assemble the configuration for executing the service now.
107 media::ServiceImplementation::Configuration service_config110 media::ServiceImplementation::Configuration service_config
108 {111 {
112 std::make_shared<media::HashedKeyedPlayerStore>(),
109 external_services113 external_services
110 };114 };
111115
112 auto service = std::make_shared<media::ServiceImplementation>(service_config);116 auto impl = std::make_shared<media::ServiceImplementation>(media::ServiceImplementation::Configuration
117 {
118 player_store,
119 external_services
120 });
121
122 auto skeleton = std::make_shared<media::ServiceSkeleton>(media::ServiceSkeleton::Configuration
123 {
124 impl,
125 player_store,
126
127 });
113128
114 std::thread service_worker129 std::thread service_worker
115 {130 {
116 [&shutdown_requested, service]()131 [&shutdown_requested, skeleton]()
117 {132 {
118 while (not shutdown_requested)133 while (not shutdown_requested)
119 {134 {
120 try135 try
121 {136 {
122 service->run();137 skeleton->run();
123 }138 }
124 catch (const std::exception& e)139 catch (const std::exception& e)
125 {140 {
@@ -142,7 +157,7 @@
142 shutdown_requested = true;157 shutdown_requested = true;
143158
144 // And stop execution of helper and actual service.159 // And stop execution of helper and actual service.
145 service->stop();160 skeleton->stop();
146161
147 if (service_worker.joinable())162 if (service_worker.joinable())
148 service_worker.join();163 service_worker.join();
149164
=== modified file 'src/core/media/service_implementation.cpp'
--- src/core/media/service_implementation.cpp 2015-03-04 16:37:33 +0000
+++ src/core/media/service_implementation.cpp 2015-03-04 16:37:33 +0000
@@ -188,11 +188,11 @@
188 // until all dispatches are done188 // until all dispatches are done
189 d->configuration.external_services.io_service.post([this, key]()189 d->configuration.external_services.io_service.post([this, key]()
190 {190 {
191 if (!has_player_for_key(key))191 if (!d->configuration.player_store->has_player_for_key(key))
192 return;192 return;
193193
194 if (player_for_key(key)->lifetime() == Player::Lifetime::normal)194 if (d->configuration.player_store->player_for_key(key)->lifetime() == Player::Lifetime::normal)
195 remove_player_for_key(key);195 d->configuration.player_store->remove_player_for_key(key);
196 });196 });
197 });197 });
198198
@@ -213,19 +213,19 @@
213213
214void media::ServiceImplementation::pause_other_sessions(media::Player::PlayerKey key)214void media::ServiceImplementation::pause_other_sessions(media::Player::PlayerKey key)
215{215{
216 if (not has_player_for_key(key))216 if (not d->configuration.player_store->has_player_for_key(key))
217 {217 {
218 cerr << "Could not find Player by key: " << key << endl;218 cerr << "Could not find Player by key: " << key << endl;
219 return;219 return;
220 }220 }
221221
222 auto current_player = player_for_key(key);222 auto current_player = d->configuration.player_store->player_for_key(key);
223223
224 // We immediately make the player known as new current player.224 // We immediately make the player known as new current player.
225 if (current_player->audio_stream_role() == media::Player::multimedia)225 if (current_player->audio_stream_role() == media::Player::multimedia)
226 set_current_player_for_key(key);226 d->configuration.player_store->set_current_player_for_key(key);
227227
228 enumerate_players([current_player, key](const media::Player::PlayerKey& other_key, const std::shared_ptr<media::Player>& other_player)228 d->configuration.player_store->enumerate_players([current_player, key](const media::Player::PlayerKey& other_key, const std::shared_ptr<media::Player>& other_player)
229 {229 {
230 // Only pause a Player if all of the following criteria are met:230 // Only pause a Player if all of the following criteria are met:
231 // 1) currently playing231 // 1) currently playing
@@ -245,7 +245,7 @@
245245
246void media::ServiceImplementation::pause_all_multimedia_sessions()246void media::ServiceImplementation::pause_all_multimedia_sessions()
247{247{
248 enumerate_players([this](const media::Player::PlayerKey& key, const std::shared_ptr<media::Player>& player)248 d->configuration.player_store->enumerate_players([this](const media::Player::PlayerKey& key, const std::shared_ptr<media::Player>& player)
249 {249 {
250 if (player->playback_status() == Player::playing250 if (player->playback_status() == Player::playing
251 && player->audio_stream_role() == media::Player::multimedia)251 && player->audio_stream_role() == media::Player::multimedia)
@@ -260,7 +260,7 @@
260void media::ServiceImplementation::resume_paused_multimedia_sessions(bool resume_video_sessions)260void media::ServiceImplementation::resume_paused_multimedia_sessions(bool resume_video_sessions)
261{261{
262 std::for_each(d->paused_sessions.begin(), d->paused_sessions.end(), [this, resume_video_sessions](const media::Player::PlayerKey& key) {262 std::for_each(d->paused_sessions.begin(), d->paused_sessions.end(), [this, resume_video_sessions](const media::Player::PlayerKey& key) {
263 auto player = player_for_key(key);263 auto player = d->configuration.player_store->player_for_key(key);
264 // Only resume video playback if explicitly desired264 // Only resume video playback if explicitly desired
265 if (resume_video_sessions || player->is_audio_source())265 if (resume_video_sessions || player->is_audio_source())
266 player->play();266 player->play();
@@ -273,10 +273,10 @@
273273
274void media::ServiceImplementation::resume_multimedia_session()274void media::ServiceImplementation::resume_multimedia_session()
275{275{
276 if (not has_player_for_key(d->resume_key))276 if (not d->configuration.player_store->has_player_for_key(d->resume_key))
277 return;277 return;
278278
279 auto player = player_for_key(d->resume_key);279 auto player = d->configuration.player_store->player_for_key(d->resume_key);
280280
281 if (player->playback_status() == Player::paused)281 if (player->playback_status() == Player::paused)
282 {282 {
283283
=== modified file 'src/core/media/service_implementation.h'
--- src/core/media/service_implementation.h 2015-03-04 16:37:33 +0000
+++ src/core/media/service_implementation.h 2015-03-04 16:37:33 +0000
@@ -30,12 +30,13 @@
30{30{
31class Player;31class Player;
3232
33class ServiceImplementation : public ServiceSkeleton33class ServiceImplementation : public Service
34{34{
35public:35public:
36 // All creation time arguments go here.36 // All creation time arguments go here.
37 struct Configuration37 struct Configuration
38 {38 {
39 KeyedPlayerStore::Ptr player_store;
39 helper::ExternalServices& external_services;40 helper::ExternalServices& external_services;
40 };41 };
4142
4243
=== modified file 'src/core/media/service_skeleton.cpp'
--- src/core/media/service_skeleton.cpp 2015-03-04 16:37:33 +0000
+++ src/core/media/service_skeleton.cpp 2015-03-04 16:37:33 +0000
@@ -49,11 +49,12 @@
4949
50struct media::ServiceSkeleton::Private50struct media::ServiceSkeleton::Private
51{51{
52 Private(media::ServiceSkeleton* impl, const media::CoverArtResolver& resolver)52 Private(media::ServiceSkeleton* impl, const ServiceSkeleton::Configuration& config)
53 : impl(impl),53 : impl(impl),
54 object(impl->access_service()->add_object_for_path(54 object(impl->access_service()->add_object_for_path(
55 dbus::traits::Service<media::Service>::object_path())),55 dbus::traits::Service<media::Service>::object_path())),
56 exported(impl->access_bus(), resolver)56 exported(impl->access_bus(), config.cover_art_resolver),
57 configuration(config)
57 {58 {
58 object->install_method_handler<mpris::Service::CreateSession>(59 object->install_method_handler<mpris::Service::CreateSession>(
59 std::bind(60 std::bind(
@@ -105,15 +106,7 @@
105106
106 try107 try
107 {108 {
108 auto session = impl->create_session(config);109 configuration.player_store->add_player_for_key(key, impl->create_session(config));
109
110 bool inserted = false;
111 std::tie(std::ignore, inserted)
112 = session_store.insert(std::make_pair(key, session));
113
114 if (!inserted)
115 throw std::runtime_error("Problem persisting session in session store.");
116
117 auto reply = dbus::Message::make_method_return(msg);110 auto reply = dbus::Message::make_method_return(msg);
118 reply->writer() << op;111 reply->writer() << op;
119112
@@ -135,7 +128,7 @@
135 std::string name;128 std::string name;
136 msg->reader() >> name;129 msg->reader() >> name;
137130
138 if (fixed_session_store.count(name) == 0) {131 if (named_player_map.count(name) == 0) {
139 // Create new session132 // Create new session
140 auto session_info = create_session_info();133 auto session_info = create_session_info();
141134
@@ -152,14 +145,10 @@
152 auto session = impl->create_session(config);145 auto session = impl->create_session(config);
153 session->lifetime().set(media::Player::Lifetime::resumable);146 session->lifetime().set(media::Player::Lifetime::resumable);
154147
155 bool inserted = false;148 configuration.player_store->add_player_for_key(key, session);
156 std::tie(std::ignore, inserted)149
157 = session_store.insert(std::make_pair(key, session));150
158151 named_player_map.insert(std::make_pair(name, key));
159 if (!inserted)
160 throw std::runtime_error("Problem persisting session in session store.");
161
162 fixed_session_store.insert(std::make_pair(name, key));
163152
164 auto reply = dbus::Message::make_method_return(msg);153 auto reply = dbus::Message::make_method_return(msg);
165 reply->writer() << op;154 reply->writer() << op;
@@ -168,8 +157,8 @@
168 }157 }
169 else {158 else {
170 // Resume previous session159 // Resume previous session
171 auto key = fixed_session_store[name];160 auto key = named_player_map.at(name);
172 if (session_store.count(key) == 0) {161 if (not configuration.player_store->has_player_for_key(key)) {
173 auto reply = dbus::Message::make_error(162 auto reply = dbus::Message::make_error(
174 msg,163 msg,
175 mpris::Service::Errors::CreatingFixedSession::name(),164 mpris::Service::Errors::CreatingFixedSession::name(),
@@ -204,7 +193,7 @@
204 Player::PlayerKey key;193 Player::PlayerKey key;
205 msg->reader() >> key;194 msg->reader() >> key;
206195
207 if (session_store.count(key) == 0) {196 if (not configuration.player_store->has_player_for_key(key)) {
208 auto reply = dbus::Message::make_error(197 auto reply = dbus::Message::make_error(
209 msg,198 msg,
210 mpris::Service::Errors::ResumingSession::name(),199 mpris::Service::Errors::ResumingSession::name(),
@@ -245,9 +234,10 @@
245 media::ServiceSkeleton* impl;234 media::ServiceSkeleton* impl;
246 dbus::Object::Ptr object;235 dbus::Object::Ptr object;
247236
248 // We track all running player instances.237 // We remember all our creation time arguments.
249 std::map<media::Player::PlayerKey, std::shared_ptr<media::Player>> session_store;238 ServiceSkeleton::Configuration configuration;
250 std::map<std::string, media::Player::PlayerKey> fixed_session_store;239 // We map named/fixed player instances to their respective keys.
240 std::map<std::string, media::Player::PlayerKey> named_player_map;
251 // We expose the entire service as an MPRIS player.241 // We expose the entire service as an MPRIS player.
252 struct Exported242 struct Exported
253 {243 {
@@ -481,7 +471,7 @@
481 mpris::Player::Skeleton player;471 mpris::Player::Skeleton player;
482 mpris::Playlists::Skeleton playlists;472 mpris::Playlists::Skeleton playlists;
483473
484 // Helper to resolve (title, artist, album) tuples to cover art.474 // The CoverArtResolver used by the exported player.
485 media::CoverArtResolver cover_art_resolver;475 media::CoverArtResolver cover_art_resolver;
486 // The actual player instance.476 // The actual player instance.
487 std::weak_ptr<media::Player> current_player;477 std::weak_ptr<media::Player> current_player;
@@ -516,9 +506,9 @@
516 } exported;506 } exported;
517};507};
518508
519media::ServiceSkeleton::ServiceSkeleton(const media::CoverArtResolver& resolver)509media::ServiceSkeleton::ServiceSkeleton(const Configuration& configuration)
520 : dbus::Skeleton<media::Service>(the_session_bus()),510 : dbus::Skeleton<media::Service>(the_session_bus()),
521 d(new Private(this, resolver))511 d(new Private(this, configuration))
522{512{
523}513}
524514
@@ -526,46 +516,24 @@
526{516{
527}517}
528518
529bool media::ServiceSkeleton::has_player_for_key(const media::Player::PlayerKey& key) const519std::shared_ptr<media::Player> media::ServiceSkeleton::create_session(const media::Player::Configuration& config)
530{520{
531 return d->session_store.count(key) > 0;521 return d->configuration.impl->create_session(config);
532}522}
533523
534std::shared_ptr<media::Player> media::ServiceSkeleton::player_for_key(const media::Player::PlayerKey& key) const524std::shared_ptr<media::Player> media::ServiceSkeleton::create_fixed_session(const std::string& name, const media::Player::Configuration&config)
535{525{
536 return d->session_store.at(key);526 return d->configuration.impl->create_fixed_session(name, config);
537}527}
538528
539void media::ServiceSkeleton::enumerate_players(const media::ServiceSkeleton::PlayerEnumerator& enumerator) const529std::shared_ptr<media::Player> media::ServiceSkeleton::resume_session(media::Player::PlayerKey key)
540{530{
541 for (const auto& pair : d->session_store)531 return d->configuration.impl->resume_session(key);
542 enumerator(pair.first, pair.second);532}
543}533
544534void media::ServiceSkeleton::pause_other_sessions(media::Player::PlayerKey key)
545void media::ServiceSkeleton::set_current_player_for_key(const media::Player::PlayerKey& key)535{
546{536 d->configuration.impl->pause_other_sessions(key);
547 if (not has_player_for_key(key))
548 return;
549
550 d->exported.set_current_player(player_for_key(key));
551}
552
553void media::ServiceSkeleton::remove_player_for_key(const media::Player::PlayerKey& key)
554{
555 if (not has_player_for_key(key))
556 return;
557
558 auto player = player_for_key(key);
559
560 d->session_store.erase(key);
561 d->exported.unset_if_current(player);
562 // All non-durable fixed sessions are also removed
563 for (auto it: d->fixed_session_store) {
564 if (it.second == key) {
565 d->fixed_session_store.erase(it.first);
566 break;
567 }
568 }
569}537}
570538
571void media::ServiceSkeleton::run()539void media::ServiceSkeleton::run()
572540
=== modified file 'src/core/media/service_skeleton.h'
--- src/core/media/service_skeleton.h 2014-09-09 21:27:29 +0000
+++ src/core/media/service_skeleton.h 2015-03-04 16:37:33 +0000
@@ -22,6 +22,7 @@
22#include <core/media/service.h>22#include <core/media/service.h>
2323
24#include "cover_art_resolver.h"24#include "cover_art_resolver.h"
25#include "keyed_player_store.h"
25#include "service_traits.h"26#include "service_traits.h"
2627
27#include <core/dbus/skeleton.h>28#include <core/dbus/skeleton.h>
@@ -37,34 +38,22 @@
37class ServiceSkeleton : public core::dbus::Skeleton<core::ubuntu::media::Service>38class ServiceSkeleton : public core::dbus::Skeleton<core::ubuntu::media::Service>
38{39{
39public:40public:
40 // Functor for enumerating all known (key, player) pairs.41 // Creation time arguments go here.
41 typedef std::function42 struct Configuration
42 <43 {
43 void(44 std::shared_ptr<Service> impl;
44 // The key of the player.45 KeyedPlayerStore::Ptr player_store;
45 const core::ubuntu::media::Player::PlayerKey&,46 CoverArtResolver cover_art_resolver;
46 // The actual player instance.47 };
47 const std::shared_ptr<core::ubuntu::media::Player>&
48 )
49 > PlayerEnumerator;
5048
51 ServiceSkeleton(const CoverArtResolver& cover_art_resolver = always_missing_cover_art_resolver());49 ServiceSkeleton(const Configuration& configuration);
52 ~ServiceSkeleton();50 ~ServiceSkeleton();
5351
54 // We keep track of all known player sessions here and render them accessible via52 // From media::Service
55 // the key. All of these functions are thread-safe but not reentrant.53 std::shared_ptr<Player> create_session(const Player::Configuration&);
56 // Returns true iff a player is known for the given key.54 std::shared_ptr<Player> create_fixed_session(const std::string& name, const Player::Configuration&);
57 bool has_player_for_key(const Player::PlayerKey& key) const;55 std::shared_ptr<Player> resume_session(Player::PlayerKey);
58 // Returns the player for the given key or throws std::out_of_range if no player is known56 void pause_other_sessions(Player::PlayerKey key);
59 // for the given key.
60 std::shared_ptr<Player> player_for_key(const Player::PlayerKey& key) const;
61 // Enumerates all known players and invokes the given enumerator for each
62 // (key, player) pair.
63 void enumerate_players(const PlayerEnumerator& enumerator) const;
64 // Removes the player for the given key, and unsets it if it is the current one.
65 void remove_player_for_key(const Player::PlayerKey& key);
66 // Makes the player known under the given key current.
67 void set_current_player_for_key(const Player::PlayerKey& key);
6857
69 void run();58 void run();
70 void stop();59 void stop();

Subscribers

People subscribed via source and target branches