Music Hub  ..
A session-wide music playback service
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
service_implementation.cpp
Go to the documentation of this file.
1 /*
2  * Copyright © 2013-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  * Jim Hodapp <jim.hodapp@canonical.com>
18  */
19 
20 #include "service_implementation.h"
21 
23 #include "player_configuration.h"
24 #include "player_implementation.h"
25 
26 #include <map>
27 #include <memory>
28 #include <stdint.h>
29 #include <thread>
30 
31 namespace media = core::ubuntu::media;
32 
33 using namespace std;
34 
36 {
37  typedef map<media::Player::PlayerKey, std::shared_ptr<media::Player>> player_map_t;
38 
40  : key_(0),
41  resume_key(UINT32_MAX)
42  {
43  bus = std::shared_ptr<dbus::Bus>(new dbus::Bus(core::dbus::WellKnownBus::session));
44  bus->install_executor(dbus::asio::make_executor(bus));
45  worker = std::move(std::thread([this]()
46  {
47  bus->run();
48  }));
49 
50  // Connect the property change signal that will allow media-hub to take appropriate action
51  // when the battery level reaches critical
52  auto stub_service = dbus::Service::use_service(bus, "com.canonical.indicator.power");
53  indicator_power_session = stub_service->object_for_path(dbus::types::ObjectPath("/com/canonical/indicator/power/Battery"));
54  power_level = indicator_power_session->get_property<core::IndicatorPower::PowerLevel>();
55  power_level->changed().connect([this](const core::IndicatorPower::PowerLevel::ValueType &level)
56  {
57  // When the battery level hits 10% or 5%, pause all multimedia sessions.
58  // Playback will resume when the user clears the presented notification.
59  if (level == "low" || level == "very_low")
60  pause_all_multimedia_sessions();
61  });
62 
63  is_warning = indicator_power_session->get_property<core::IndicatorPower::IsWarning>();
64  is_warning->changed().connect([this](const core::IndicatorPower::IsWarning::ValueType &notifying)
65  {
66  // If the low battery level notification is no longer being displayed,
67  // resume what the user was previously playing
68  if (!notifying)
69  resume_multimedia_session();
70  });
71  }
72 
74  {
75  bus->stop();
76 
77  if (worker.joinable())
78  worker.join();
79  }
80 
81  void track_player(const std::shared_ptr<media::Player>& player)
82  {
83  player_map.insert(
84  std::pair<media::Player::PlayerKey,
85  std::shared_ptr<media::Player>>(key_, player));
86 
87  ++key_;
88  }
89 
91  {
92  return key_;
93  }
94 
96  {
97  auto player_it = player_map.find(key);
98  if (player_it != player_map.end())
99  {
100  auto &current_player = (*player_it).second;
101  for (auto& player_pair : player_map)
102  {
103  // Only pause a Player if all of the following criteria are met:
104  // 1) currently playing
105  // 2) not the same player as the one passed in my key
106  // 3) new Player has an audio stream role set to multimedia
107  // 4) has an audio stream role set to multimedia
108  if (player_pair.second->playback_status() == Player::playing
109  && player_pair.first != key
110  && current_player->audio_stream_role() == media::Player::multimedia
111  && player_pair.second->audio_stream_role() == media::Player::multimedia)
112  {
113  cout << "Pausing Player with key: " << player_pair.first << endl;
114  player_pair.second->pause();
115  }
116  }
117  }
118  else
119  cerr << "Could not find Player by key: " << key << endl;
120  }
121 
122  // Pauses all multimedia audio stream role type Players
124  {
125  for (auto& player_pair : player_map)
126  {
127  if (player_pair.second->playback_status() == Player::playing
128  && player_pair.second->audio_stream_role() == media::Player::multimedia)
129  {
130  resume_key = player_pair.first;
131  cout << "Will resume playback of Player with key: " << resume_key << endl;
132  player_pair.second->pause();
133  }
134  }
135  }
136 
138  {
139  auto player_it = player_map.find(resume_key);
140  if (player_it != player_map.end())
141  {
142  auto &player = (*player_it).second;
143  if (player->playback_status() == Player::paused)
144  {
145  cout << "Resuming playback of Player with key: " << resume_key << endl;
146  player->play();
147  resume_key = UINT32_MAX;
148  }
149  }
150  }
151 
152  // Used for Player instance management
153  player_map_t player_map;
155  // This holds the key of the multimedia role Player instance that was paused
156  // when the battery level reached 10% or 5%
158  std::thread worker;
159  dbus::Bus::Ptr bus;
160  std::shared_ptr<dbus::Object> indicator_power_session;
161  std::shared_ptr<core::dbus::Property<core::IndicatorPower::PowerLevel>> power_level;
162  std::shared_ptr<core::dbus::Property<core::IndicatorPower::IsWarning>> is_warning;
163 
164 };
165 
167 {
168  cout << __PRETTY_FUNCTION__ << endl;
169 }
170 
172 {
173 }
174 
175 std::shared_ptr<media::Player> media::ServiceImplementation::create_session(
176  const media::Player::Configuration& conf)
177 {
178  std::shared_ptr<media::Player> player = std::make_shared<media::PlayerImplementation>(
179  conf.object_path, shared_from_this(), d->key());
180  d->track_player(player);
181  return player;
182 }
183 
185 {
186  d->pause_other_sessions(key);
187 }
void track_player(const std::shared_ptr< media::Player > &player)
void pause_other_sessions(media::Player::PlayerKey key)
STL namespace.
std::shared_ptr< core::dbus::Property< core::IndicatorPower::PowerLevel > > power_level
void pause_other_sessions(Player::PlayerKey key)
std::shared_ptr< Player > create_session(const Player::Configuration &)
media::Player::PlayerKey key() const
std::shared_ptr< core::dbus::Property< core::IndicatorPower::IsWarning > > is_warning
std::shared_ptr< dbus::Object > indicator_power_session
map< media::Player::PlayerKey, std::shared_ptr< media::Player > > player_map_t