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 <cstdint>
27 #include <map>
28 #include <memory>
29 #include <thread>
30 
31 namespace media = core::ubuntu::media;
32 
33 using namespace std;
34 
36 {
38  : resume_key(std::numeric_limits<std::uint32_t>::max())
39  {
40  bus = std::shared_ptr<dbus::Bus>(new dbus::Bus(core::dbus::WellKnownBus::session));
41  bus->install_executor(dbus::asio::make_executor(bus));
42  worker = std::move(std::thread([this]()
43  {
44  bus->run();
45  }));
46 
47  // Connect the property change signal that will allow media-hub to take appropriate action
48  // when the battery level reaches critical
49  auto stub_service = dbus::Service::use_service(bus, "com.canonical.indicator.power");
50  indicator_power_session = stub_service->object_for_path(dbus::types::ObjectPath("/com/canonical/indicator/power/Battery"));
51  power_level = indicator_power_session->get_property<core::IndicatorPower::PowerLevel>();
52  is_warning = indicator_power_session->get_property<core::IndicatorPower::IsWarning>();
53  }
54 
56  {
57  bus->stop();
58 
59  if (worker.joinable())
60  worker.join();
61  }
62 
63  // This holds the key of the multimedia role Player instance that was paused
64  // when the battery level reached 10% or 5%
66  std::thread worker;
67  dbus::Bus::Ptr bus;
68  std::shared_ptr<dbus::Object> indicator_power_session;
69  std::shared_ptr<core::dbus::Property<core::IndicatorPower::PowerLevel>> power_level;
70  std::shared_ptr<core::dbus::Property<core::IndicatorPower::IsWarning>> is_warning;
71 };
72 
74 {
75  cout << __PRETTY_FUNCTION__ << endl;
76 
77  d->power_level->changed().connect([this](const core::IndicatorPower::PowerLevel::ValueType &level)
78  {
79  // When the battery level hits 10% or 5%, pause all multimedia sessions.
80  // Playback will resume when the user clears the presented notification.
81  if (level == "low" || level == "very_low")
82  pause_all_multimedia_sessions();
83  });
84 
85  d->is_warning->changed().connect([this](const core::IndicatorPower::IsWarning::ValueType &notifying)
86  {
87  // If the low battery level notification is no longer being displayed,
88  // resume what the user was previously playing
89  if (!notifying)
90  resume_multimedia_session();
91  });
92 }
93 
95 {
96 }
97 
98 std::shared_ptr<media::Player> media::ServiceImplementation::create_session(
99  const media::Player::Configuration& conf)
100 {
101  auto player = std::make_shared<media::PlayerImplementation>(
102  conf.identity, conf.bus, conf.session, shared_from_this(), conf.key);
103 
104  auto key = conf.key;
105  player->on_client_disconnected().connect([this, key]()
106  {
108  });
109 
110  return player;
111 }
112 
114 {
115  if (not has_player_for_key(key))
116  {
117  cerr << "Could not find Player by key: " << key << endl;
118  return;
119  }
120 
121  auto current_player = player_for_key(key);
122 
123  // We immediately make the player known as new current player.
124  if (current_player->audio_stream_role() == media::Player::multimedia)
126 
127  enumerate_players([current_player, key](const media::Player::PlayerKey& other_key, const std::shared_ptr<media::Player>& other_player)
128  {
129  // Only pause a Player if all of the following criteria are met:
130  // 1) currently playing
131  // 2) not the same player as the one passed in my key
132  // 3) new Player has an audio stream role set to multimedia
133  // 4) has an audio stream role set to multimedia
134  if (other_player->playback_status() == Player::playing &&
135  other_key != key &&
136  current_player->audio_stream_role() == media::Player::multimedia &&
137  other_player->audio_stream_role() == media::Player::multimedia)
138  {
139  cout << "Pausing Player with key: " << other_key << endl;
140  other_player->pause();
141  }
142  });
143 }
144 
145 void media::ServiceImplementation::pause_all_multimedia_sessions()
146 {
147  enumerate_players([this](const media::Player::PlayerKey& key, const std::shared_ptr<media::Player>& player)
148  {
149  if (player->playback_status() == Player::playing
150  && player->audio_stream_role() == media::Player::multimedia)
151  {
152  d->resume_key = key;
153  cout << "Will resume playback of Player with key: " << d->resume_key << endl;
154  player->pause();
155  }
156  });
157 }
158 
159 void media::ServiceImplementation::resume_multimedia_session()
160 {
161  if (not has_player_for_key(d->resume_key))
162  return;
163 
164  auto player = player_for_key(d->resume_key);
165 
166  if (player->playback_status() == Player::paused)
167  {
168  cout << "Resuming playback of Player with key: " << d->resume_key << endl;
169  player->play();
170  d->resume_key = std::numeric_limits<std::uint32_t>::max();
171  }
172 }
void set_current_player_for_key(const Player::PlayerKey &key)
bool has_player_for_key(const Player::PlayerKey &key) const
STL namespace.
void enumerate_players(const PlayerEnumerator &enumerator) const
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 &)
void remove_player_for_key(const Player::PlayerKey &key)
std::shared_ptr< core::dbus::Property< core::IndicatorPower::IsWarning > > is_warning
std::shared_ptr< Player > player_for_key(const Player::PlayerKey &key) const
std::shared_ptr< dbus::Object > indicator_power_session