Music Hub  ..
A session-wide music playback service
service_skeleton.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_skeleton.h"
21 
22 #include "mpris/media_player2.h"
23 #include "mpris/metadata.h"
24 #include "mpris/player.h"
25 #include "mpris/playlists.h"
26 #include "mpris/service.h"
27 
28 #include "player_configuration.h"
29 #include "the_session_bus.h"
30 #include "xesam.h"
31 
32 #include <core/dbus/message.h>
33 #include <core/dbus/object.h>
34 #include <core/dbus/types/object_path.h>
35 
36 #include <core/posix/this_process.h>
37 
38 #include <boost/uuid/uuid.hpp>
39 #include <boost/uuid/uuid_generators.hpp>
40 #include <boost/uuid/uuid_io.hpp>
41 
42 #include <map>
43 #include <regex>
44 #include <sstream>
45 
46 namespace dbus = core::dbus;
47 namespace media = core::ubuntu::media;
48 
49 namespace
50 {
51 core::Signal<void> the_empty_signal;
52 }
53 
55 {
56  Private(media::ServiceSkeleton* impl, const ServiceSkeleton::Configuration& config)
58  impl(impl),
59  object(impl->access_service()->add_object_for_path(
60  dbus::traits::Service<media::Service>::object_path())),
61  configuration(config),
62  exported(impl->access_bus(), config.cover_art_resolver)
63  {
64  object->install_method_handler<mpris::Service::CreateSession>(
65  std::bind(
67  this,
68  std::placeholders::_1));
69  object->install_method_handler<mpris::Service::DetachSession>(
70  std::bind(
72  this,
73  std::placeholders::_1));
74  object->install_method_handler<mpris::Service::ReattachSession>(
75  std::bind(
77  this,
78  std::placeholders::_1));
79  object->install_method_handler<mpris::Service::DestroySession>(
80  std::bind(
82  this,
83  std::placeholders::_1));
84  object->install_method_handler<mpris::Service::CreateFixedSession>(
85  std::bind(
87  this,
88  std::placeholders::_1));
89  object->install_method_handler<mpris::Service::ResumeSession>(
90  std::bind(
92  this,
93  std::placeholders::_1));
94  object->install_method_handler<mpris::Service::PauseOtherSessions>(
95  std::bind(
97  this,
98  std::placeholders::_1));
99  }
100 
101  std::tuple<std::string, media::Player::PlayerKey, std::string> create_session_info()
102  {
103  static unsigned int session_counter = 0;
104 
105  unsigned int current_session = session_counter++;
106  boost::uuids::uuid uuid = gen();
107 
108  std::stringstream ss;
109  ss << "/core/ubuntu/media/Service/sessions/" << current_session;
110 
111  return std::make_tuple(ss.str(), media::Player::PlayerKey(current_session), to_string(uuid));
112  }
113 
114  void handle_create_session(const core::dbus::Message::Ptr& msg)
115  {
116  auto session_info = create_session_info();
117 
118  dbus::types::ObjectPath op{std::get<0>(session_info)};
119  media::Player::PlayerKey key{std::get<1>(session_info)};
120  std::string uuid{std::get<2>(session_info)};
121 
122  media::Player::Configuration config
123  {
124  key,
125  impl->access_bus(),
126  impl->access_service(),
127  impl->access_service()->add_object_for_path(op)
128  };
129 
130  std::cout << "Session created by request of: " << msg->sender() << ", uuid: " << uuid << ", path:" << op << std::endl;
131 
132  try
133  {
134  configuration.player_store->add_player_for_key(key, impl->create_session(config));
135  uuid_player_map.insert(std::make_pair(uuid, key));
136 
137  request_context_resolver->resolve_context_for_dbus_name_async(msg->sender(), [this, key, msg](const media::apparmor::ubuntu::Context& context)
138  {
139  fprintf(stderr, "%s():%d -- app_name='%s', attached\n", __func__, __LINE__, context.str().c_str());
140  player_owner_map.insert(std::make_pair(key, std::make_tuple(context.str(), true, msg->sender())));
141  });
142 
143  auto reply = dbus::Message::make_method_return(msg);
144  reply->writer() << std::make_tuple(op, uuid);
145 
146  impl->access_bus()->send(reply);
147  } catch(const std::runtime_error& e)
148  {
149  auto reply = dbus::Message::make_error(
150  msg,
152  e.what());
153  impl->access_bus()->send(reply);
154  }
155  }
156 
157  void handle_detach_session(const core::dbus::Message::Ptr& msg)
158  {
159  try
160  {
161  std::string uuid;
162  msg->reader() >> uuid;
163 
164  // Make sure we don't try to do a lookup if the map is empty
165  if (!uuid_player_map.empty())
166  {
167  const auto key = uuid_player_map.at(uuid);
168 
169  if (player_owner_map.count(key) != 0) {
170  auto info = player_owner_map.at(key);
171  // Check if session is attached(1) and that the detachment
172  // request comes from the same peer(2) that created the session.
173  if (std::get<1>(info) && (std::get<2>(info) == msg->sender())) { // Player is attached
174  std::get<1>(info) = false; // Detached
175  std::get<2>(info).clear(); // Clear registered sender/peer
176  auto player = configuration.player_store->player_for_key(key);
177  player->lifetime().set(media::Player::Lifetime::resumable);
178  }
179  }
180  }
181 
182  auto reply = dbus::Message::make_method_return(msg);
183  impl->access_bus()->send(reply);
184 
185  } catch(const std::runtime_error& e)
186  {
187  auto reply = dbus::Message::make_error(
188  msg,
190  e.what());
191  impl->access_bus()->send(reply);
192  }
193  }
194 
195  void handle_reattach_session(const core::dbus::Message::Ptr& msg)
196  {
197  try
198  {
199  std::string uuid;
200  msg->reader() >> uuid;
201 
202  if (uuid_player_map.count(uuid) != 0) {
203  auto key = uuid_player_map.at(uuid);
204  if (not configuration.player_store->has_player_for_key(key)) {
205  auto reply = dbus::Message::make_error(
206  msg,
208  "Unable to locate player session");
209  impl->access_bus()->send(reply);
210  return;
211  }
212  std::stringstream ss;
213  ss << "/core/ubuntu/media/Service/sessions/" << key;
214  dbus::types::ObjectPath op{ss.str()};
215 
216  request_context_resolver->resolve_context_for_dbus_name_async(msg->sender(), [this, msg, key, op](const media::apparmor::ubuntu::Context& context)
217  {
218  auto info = player_owner_map.at(key);
219  fprintf(stderr, "%s():%d -- reattach app_name='%s', info='%s', '%s'\n", __func__, __LINE__, context.str().c_str(), std::get<0>(info).c_str(), std::get<2>(info).c_str());
220  if (std::get<0>(info) == context.str()) {
221  std::get<1>(info) = true; // Set to Attached
222  std::get<2>(info) = msg->sender(); // Register new owner
223 
224  // Signal player reconnection
225  auto player = configuration.player_store->player_for_key(key);
226  player->reconnect();
227 
228  auto reply = dbus::Message::make_method_return(msg);
229  reply->writer() << op;
230 
231  impl->access_bus()->send(reply);
232  }
233  else {
234  auto reply = dbus::Message::make_error(
235  msg,
237  "Invalid permissions for the requested session");
238  impl->access_bus()->send(reply);
239  return;
240  }
241  });
242  }
243  else {
244  auto reply = dbus::Message::make_error(
245  msg,
247  "Invalid session");
248  impl->access_bus()->send(reply);
249  return;
250  }
251  } catch(const std::runtime_error& e)
252  {
253  auto reply = dbus::Message::make_error(
254  msg,
256  e.what());
257  impl->access_bus()->send(reply);
258  }
259  }
260 
261  void handle_destroy_session(const core::dbus::Message::Ptr& msg)
262  {
263  try
264  {
265  std::string uuid;
266  msg->reader() >> uuid;
267 
268  if (uuid_player_map.count(uuid) != 0) {
269  auto key = uuid_player_map.at(uuid);
270  if (not configuration.player_store->has_player_for_key(key)) {
271  auto reply = dbus::Message::make_error(
272  msg,
274  "Unable to locate player session");
275  impl->access_bus()->send(reply);
276  return;
277  }
278 
279  // Remove control entries from the map, at this point
280  // the session is no longer usable.
281  uuid_player_map.erase(uuid);
282 
283  request_context_resolver->resolve_context_for_dbus_name_async(msg->sender(), [this, msg, key](const media::apparmor::ubuntu::Context& context)
284  {
285  auto info = player_owner_map.at(key);
286  fprintf(stderr, "%s():%d -- Destroying app_name='%s', info='%s', '%s'\n", __func__, __LINE__, context.str().c_str(), std::get<0>(info).c_str(), std::get<2>(info).c_str());
287  if (std::get<0>(info) == context.str()) {
288  player_owner_map.erase(key);
289 
290  // Reset lifecycle to non-resumable on the now-abandoned session
291  auto player = configuration.player_store->player_for_key(key);
292 
293  // Delete player instance by abandonment
294  player->lifetime().set(media::Player::Lifetime::normal);
295  player->abandon();
296 
297  auto reply = dbus::Message::make_method_return(msg);
298  impl->access_bus()->send(reply);
299  }
300  else {
301  auto reply = dbus::Message::make_error(
302  msg,
304  "Invalid permissions for the requested session");
305  impl->access_bus()->send(reply);
306  return;
307  }
308  });
309  }
310  else {
311  auto reply = dbus::Message::make_error(
312  msg,
314  "Invalid session");
315  impl->access_bus()->send(reply);
316  return;
317  }
318  } catch(const std::runtime_error& e)
319  {
320  auto reply = dbus::Message::make_error(
321  msg,
323  e.what());
324  impl->access_bus()->send(reply);
325  }
326  }
327 
328  void handle_create_fixed_session(const core::dbus::Message::Ptr& msg)
329  {
330  try
331  {
332  std::string name;
333  msg->reader() >> name;
334 
335  if (named_player_map.count(name) == 0) {
336  // Create new session
337  auto session_info = create_session_info();
338 
339  dbus::types::ObjectPath op{std::get<0>(session_info)};
340  media::Player::PlayerKey key{std::get<1>(session_info)};
341 
342  media::Player::Configuration config
343  {
344  key,
345  impl->access_bus(),
346  impl->access_service(),
347  impl->access_service()->add_object_for_path(op)
348  };
349 
350  auto session = impl->create_session(config);
351  session->lifetime().set(media::Player::Lifetime::resumable);
352 
353  configuration.player_store->add_player_for_key(key, session);
354 
355  named_player_map.insert(std::make_pair(name, key));
356 
357  auto reply = dbus::Message::make_method_return(msg);
358  reply->writer() << op;
359 
360  impl->access_bus()->send(reply);
361  }
362  else {
363  // Resume previous session
364  auto key = named_player_map.at(name);
365  if (not configuration.player_store->has_player_for_key(key)) {
366  auto reply = dbus::Message::make_error(
367  msg,
369  "Unable to locate player session");
370  impl->access_bus()->send(reply);
371  return;
372  }
373 
374  std::stringstream ss;
375  ss << "/core/ubuntu/media/Service/sessions/" << key;
376  dbus::types::ObjectPath op{ss.str()};
377 
378  auto reply = dbus::Message::make_method_return(msg);
379  reply->writer() << op;
380 
381  impl->access_bus()->send(reply);
382  }
383  } catch(const std::runtime_error& e)
384  {
385  auto reply = dbus::Message::make_error(
386  msg,
388  e.what());
389  impl->access_bus()->send(reply);
390  }
391  }
392 
393  void handle_resume_session(const core::dbus::Message::Ptr& msg)
394  {
395  try
396  {
397  Player::PlayerKey key;
398  msg->reader() >> key;
399 
400  if (not configuration.player_store->has_player_for_key(key)) {
401  auto reply = dbus::Message::make_error(
402  msg,
404  "Unable to locate player session");
405  impl->access_bus()->send(reply);
406  return;
407  }
408 
409  std::stringstream ss;
410  ss << "/core/ubuntu/media/Service/sessions/" << key;
411  dbus::types::ObjectPath op{ss.str()};
412 
413  auto reply = dbus::Message::make_method_return(msg);
414  reply->writer() << op;
415 
416  impl->access_bus()->send(reply);
417  } catch(const std::runtime_error& e)
418  {
419  auto reply = dbus::Message::make_error(
420  msg,
422  e.what());
423  impl->access_bus()->send(reply);
424  }
425  }
426 
427  void handle_pause_other_sessions(const core::dbus::Message::Ptr& msg)
428  {
429  std::cout << __PRETTY_FUNCTION__ << std::endl;
430  Player::PlayerKey key;
431  msg->reader() >> key;
432  impl->pause_other_sessions(key);
433 
434  auto reply = dbus::Message::make_method_return(msg);
435  impl->access_bus()->send(reply);
436  }
437 
438  media::apparmor::ubuntu::RequestContextResolver::Ptr request_context_resolver;
440  dbus::Object::Ptr object;
441 
442  // We remember all our creation time arguments.
443  ServiceSkeleton::Configuration configuration;
444  // We map named/fixed player instances to their respective keys.
445  std::map<std::string, media::Player::PlayerKey> named_player_map;
446  // We map UUIDs to their respective keys.
447  std::map<std::string, media::Player::PlayerKey> uuid_player_map;
448  // We keep a list of keys and their respective owners and states.
449  // value: (owner context, attached state, attached dbus name)
450  std::map<media::Player::PlayerKey, std::tuple<std::string, bool, std::string>> player_owner_map;
451 
452  boost::uuids::random_generator gen;
453 
454  // We expose the entire service as an MPRIS player.
455  struct Exported
456  {
458  {
460  // TODO(tvoss): These three elements really should be configurable.
461  defaults.identity = "core::media::Hub";
462  defaults.desktop_entry = "mediaplayer-app";
463  defaults.supported_mime_types = {"audio/mpeg3"};
464 
465  return defaults;
466  }
467 
469  {
471 
472  // Disabled as track list is not fully implemented yet.
473  defaults.can_go_next = false;
474  // Disabled as track list is not fully implemented yet.
475  defaults.can_go_previous = false;
476 
477  return defaults;
478  }
479 
480  static std::string service_name()
481  {
482  static const bool export_to_indicator_sound_via_mpris
483  {
484  core::posix::this_process::env::get("UBUNTU_MEDIA_HUB_EXPORT_TO_INDICATOR_VIA_MPRIS", "0") == "1"
485  };
486 
487  return export_to_indicator_sound_via_mpris ? "org.mpris.MediaPlayer2.MediaHub" :
488  "hidden.org.mpris.MediaPlayer2.MediaHub";
489  }
490 
491  explicit Exported(const dbus::Bus::Ptr& bus, const media::CoverArtResolver& cover_art_resolver)
492  : bus{bus},
493  service{dbus::Service::add_service(bus, service_name())},
494  object{service->add_object_for_path(dbus::types::ObjectPath{"/org/mpris/MediaPlayer2"})},
499  {
500  object->install_method_handler<core::dbus::interfaces::Properties::GetAll>([this](const core::dbus::Message::Ptr& msg)
501  {
502  // Extract the interface
503  std::string itf; msg->reader() >> itf;
504  core::dbus::Message::Ptr reply = core::dbus::Message::make_method_return(msg);
505 
506  if (itf == mpris::Player::name())
507  reply->writer() << player.get_all_properties();
508  else if (itf == mpris::MediaPlayer2::name())
509  reply->writer() << media_player.get_all_properties();
510  else if (itf == mpris::Playlists::name())
511  reply->writer() << playlists.get_all_properties();
512 
513  Exported::bus->send(reply);
514  });
515 
516  // Setup method handlers for mpris::Player methods.
517  auto next = [this](const core::dbus::Message::Ptr& msg)
518  {
519  auto sp = current_player.lock();
520 
521  if (sp)
522  sp->next();
523 
524  Exported::bus->send(core::dbus::Message::make_method_return(msg));
525  };
526  object->install_method_handler<mpris::Player::Next>(next);
527 
528  auto previous = [this](const core::dbus::Message::Ptr& msg)
529  {
530  auto sp = current_player.lock();
531 
532  if (sp)
533  sp->previous();
534 
535  Exported::bus->send(core::dbus::Message::make_method_return(msg));
536  };
537  object->install_method_handler<mpris::Player::Previous>(previous);
538 
539  auto pause = [this](const core::dbus::Message::Ptr& msg)
540  {
541  auto sp = current_player.lock();
542 
543  if (sp)
544  sp->pause();
545 
546  Exported::bus->send(core::dbus::Message::make_method_return(msg));
547  };
548  object->install_method_handler<mpris::Player::Pause>(pause);
549 
550  auto stop = [this](const core::dbus::Message::Ptr& msg)
551  {
552  auto sp = current_player.lock();
553 
554  if (sp)
555  sp->stop();
556 
557  Exported::bus->send(core::dbus::Message::make_method_return(msg));
558  };
559  object->install_method_handler<mpris::Player::Stop>(stop);
560 
561  auto play = [this](const core::dbus::Message::Ptr& msg)
562  {
563  auto sp = current_player.lock();
564 
565  if (sp)
566  sp->play();
567 
568  Exported::bus->send(core::dbus::Message::make_method_return(msg));
569  };
570  object->install_method_handler<mpris::Player::Play>(play);
571 
572  auto play_pause = [this](const core::dbus::Message::Ptr& msg)
573  {
574  auto sp = current_player.lock();
575 
576  if (sp)
577  {
578  if (sp->playback_status() == media::Player::PlaybackStatus::playing)
579  sp->pause();
580  else if (sp->playback_status() != media::Player::PlaybackStatus::null)
581  sp->play();
582  }
583 
584  Exported::bus->send(core::dbus::Message::make_method_return(msg));
585  };
586  object->install_method_handler<mpris::Player::PlayPause>(play_pause);
587  }
588 
589  void set_current_player(const std::shared_ptr<media::Player>& cp)
590  {
592 
593  // We will not keep the object alive.
594  current_player = cp;
595 
596  // And announce that we can be controlled again.
597  player.properties.can_control->set(false);
598 
599  // We wire up player state changes
600  connections.seeked_to = cp->seeked_to().connect([this](std::uint64_t position)
601  {
602  player.signals.seeked_to->emit(position);
603  });
604 
605  connections.duration_changed = cp->duration().changed().connect([this](std::uint64_t duration)
606  {
607  player.properties.duration->set(duration);
608  });
609 
610  connections.position_changed = cp->position().changed().connect([this](std::uint64_t position)
611  {
612  player.properties.position->set(position);
613  });
614 
615  connections.playback_status_changed = cp->playback_status().changed().connect([this](core::ubuntu::media::Player::PlaybackStatus status)
616  {
618  });
619 
620  connections.loop_status_changed = cp->loop_status().changed().connect([this](core::ubuntu::media::Player::LoopStatus status)
621  {
623  });
624 
625  connections.meta_data_changed = cp->meta_data_for_current_track().changed().connect([this](const core::ubuntu::media::Track::MetaData& md)
626  {
628 
629  bool has_title = md.count(xesam::Title::name) > 0;
630  bool has_album_name = md.count(xesam::Album::name) > 0;
631  bool has_artist_name = md.count(xesam::Artist::name) > 0;
632 
633  if (has_title)
634  dict[xesam::Title::name] = dbus::types::Variant::encode(md.get(xesam::Title::name));
635  if (has_album_name)
636  dict[xesam::Album::name] = dbus::types::Variant::encode(md.get(xesam::Album::name));
637  if (has_artist_name)
638  dict[xesam::Artist::name] = dbus::types::Variant::encode(md.get(xesam::Artist::name));
639 
640  dict[mpris::metadata::ArtUrl::name] = dbus::types::Variant::encode(
642  has_title ? md.get(xesam::Title::name) : "",
643  has_album_name ? md.get(xesam::Album::name) : "",
644  has_artist_name ? md.get(xesam::Artist::name) : ""));
645 
647  wrap[mpris::Player::Properties::Metadata::name()] = dbus::types::Variant::encode(dict);
648 
650  std::make_tuple(
651  dbus::traits::Service<mpris::Player::Properties::Metadata::Interface>::interface_name(),
652  wrap,
653  std::vector<std::string>()));
654  });
655  }
656 
658  {
659  current_player.reset();
660 
661  // We disconnect all previous event connections.
662  connections.seeked_to.disconnect();
663  connections.duration_changed.disconnect();
664  connections.position_changed.disconnect();
665  connections.playback_status_changed.disconnect();
666  connections.loop_status_changed.disconnect();
667  connections.meta_data_changed.disconnect();
668 
669  // And announce that we cannot be controlled anymore.
670  player.properties.can_control->set(false);
671  }
672 
673  void unset_if_current(const std::shared_ptr<media::Player>& cp)
674  {
675  if (cp == current_player.lock())
677  }
678 
679  dbus::Bus::Ptr bus;
680  dbus::Service::Ptr service;
681  dbus::Object::Ptr object;
682 
686 
687  // The CoverArtResolver used by the exported player.
689  // The actual player instance.
690  std::weak_ptr<media::Player> current_player;
691  // We track event connections.
692  struct
693  {
694  core::Connection seeked_to
695  {
696  the_empty_signal.connect([](){})
697  };
698  core::Connection duration_changed
699  {
700  the_empty_signal.connect([](){})
701  };
702  core::Connection position_changed
703  {
704  the_empty_signal.connect([](){})
705  };
706  core::Connection playback_status_changed
707  {
708  the_empty_signal.connect([](){})
709  };
710  core::Connection loop_status_changed
711  {
712  the_empty_signal.connect([](){})
713  };
714  core::Connection meta_data_changed
715  {
716  the_empty_signal.connect([](){})
717  };
718  } connections;
719  } exported;
720 };
721 
722 media::ServiceSkeleton::ServiceSkeleton(const Configuration& configuration)
723  : dbus::Skeleton<media::Service>(the_session_bus()),
724  d(new Private(this, configuration))
725 {
726 }
727 
729 {
730 }
731 
732 std::shared_ptr<media::Player> media::ServiceSkeleton::create_session(const media::Player::Configuration& config)
733 {
734  return d->configuration.impl->create_session(config);
735 }
736 
737 void media::ServiceSkeleton::detach_session(const std::string& uuid, const media::Player::Configuration& config)
738 {
739  return d->configuration.impl->detach_session(uuid, config);
740 }
741 
742 std::shared_ptr<media::Player> media::ServiceSkeleton::reattach_session(const std::string& uuid, const media::Player::Configuration& config)
743 {
744  return d->configuration.impl->reattach_session(uuid, config);
745 }
746 
747 void media::ServiceSkeleton::destroy_session(const std::string& uuid, const media::Player::Configuration& config)
748 {
749  return d->configuration.impl->destroy_session(uuid, config);
750 }
751 
752 std::shared_ptr<media::Player> media::ServiceSkeleton::create_fixed_session(const std::string& name, const media::Player::Configuration&config)
753 {
754  return d->configuration.impl->create_fixed_session(name, config);
755 }
756 
757 std::shared_ptr<media::Player> media::ServiceSkeleton::resume_session(media::Player::PlayerKey key)
758 {
759  return d->configuration.impl->resume_session(key);
760 }
761 
763 {
764  d->configuration.impl->pause_other_sessions(key);
765 }
766 
768 {
769  access_bus()->run();
770 }
771 
773 {
774  access_bus()->stop();
775 }
std::weak_ptr< media::Player > current_player
struct mpris::Player::Skeleton::@16 signals
std::shared_ptr< core::dbus::Property< Properties::Duration > > duration
Definition: player.h:375
void handle_reattach_session(const core::dbus::Message::Ptr &msg)
Properties::CanGoPrevious::ValueType can_go_previous
Definition: player.h:200
media::ServiceSkeleton * impl
std::map< std::string, media::Player::PlayerKey > uuid_player_map
std::shared_ptr< core::dbus::Property< Properties::LoopStatus > > loop_status
Definition: player.h:365
Private(media::ServiceSkeleton *impl, const ServiceSkeleton::Configuration &config)
static const std::string & name()
Definition: player.h:53
void handle_create_fixed_session(const core::dbus::Message::Ptr &msg)
static mpris::MediaPlayer2::Skeleton::Configuration::Defaults media_player_defaults()
Properties::SupportedMimeTypes::ValueType supported_mime_types
void handle_create_session(const core::dbus::Message::Ptr &msg)
std::map< media::Player::PlayerKey, std::tuple< std::string, bool, std::string > > player_owner_map
Properties::CanGoNext::ValueType can_go_next
Definition: player.h:199
static const std::string & name()
Definition: media_player2.h:38
void unset_if_current(const std::shared_ptr< media::Player > &cp)
struct mpris::Player::Skeleton::@15 properties
static const char * from(core::ubuntu::media::Player::PlaybackStatus status)
Definition: player.h:87
static const std::string & name()
Definition: service.h:77
Tag::ValueType get() const
Definition: track.h:70
void handle_resume_session(const core::dbus::Message::Ptr &msg)
mpris::MediaPlayer2::Skeleton media_player
void set_current_player(const std::shared_ptr< media::Player > &cp)
static const std::string & name()
Definition: service.h:53
std::map< std::string, core::dbus::types::Variant > Dictionary
Definition: player.h:121
static const std::string & name()
Definition: service.h:101
static const char * from(core::ubuntu::media::Player::LoopStatus status)
Definition: player.h:63
static mpris::Player::Skeleton::Configuration::Defaults player_defaults()
std::shared_ptr< Player > resume_session(Player::PlayerKey)
std::map< std::string, core::dbus::types::Variant > get_all_properties()
Definition: playlists.h:192
void handle_destroy_session(const core::dbus::Message::Ptr &msg)
RequestContextResolver::Ptr make_platform_default_request_context_resolver(helper::ExternalServices &es)
ServiceSkeleton(const Configuration &configuration)
Exported(const dbus::Bus::Ptr &bus, const media::CoverArtResolver &cover_art_resolver)
std::shared_ptr< Player > reattach_session(const std::string &, const Player::Configuration &)
struct media::ServiceSkeleton::Private::Exported::@26 connections
void pause_other_sessions(Player::PlayerKey key)
std::tuple< std::string, media::Player::PlayerKey, std::string > create_session_info()
std::function< std::string(const std::string &, const std::string &, const std::string &)> CoverArtResolver
ServiceSkeleton::Configuration configuration
void handle_detach_session(const core::dbus::Message::Ptr &msg)
Dictionary get_all_properties()
Definition: player.h:323
static const std::string & name()
Definition: service.h:41
Properties::DesktopEntry::ValueType desktop_entry
core::dbus::Bus::Ptr the_session_bus()
core::dbus::Signal< Signals::Seeked, Signals::Seeked::ArgumentType >::Ptr seeked_to
Definition: player.h:382
static const std::string & name()
Definition: service.h:65
void detach_session(const std::string &, const Player::Configuration &)
static constexpr const char * name
Definition: metadata.h:49
std::size_t count() const
Definition: track.h:57
std::shared_ptr< core::dbus::Property< Properties::PlaybackStatus > > playback_status
Definition: player.h:363
media::apparmor::ubuntu::RequestContextResolver::Ptr request_context_resolver
std::shared_ptr< core::dbus::Property< Properties::CanControl > > can_control
Definition: player.h:357
void destroy_session(const std::string &, const media::Player::Configuration &)
std::map< std::string, media::Player::PlayerKey > named_player_map
std::shared_ptr< core::dbus::Property< Properties::Position > > position
Definition: player.h:374
std::shared_ptr< Player > create_fixed_session(const std::string &name, const Player::Configuration &)
struct media::ServiceSkeleton::Private::Exported exported
void handle_pause_other_sessions(const core::dbus::Message::Ptr &msg)
static const std::string & name()
Definition: service.h:89
std::map< std::string, core::dbus::types::Variant > get_all_properties()
dbus::Signal< core::dbus::interfaces::Properties::Signals::PropertiesChanged, core::dbus::interfaces::Properties::Signals::PropertiesChanged::ArgumentType >::Ptr properties_changed
Definition: player.h:393
static const std::string & name()
Definition: playlists.h:54
std::shared_ptr< Player > create_session(const Player::Configuration &)
boost::uuids::random_generator gen