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  auto key = uuid_player_map.at(uuid);
165 
166  if (player_owner_map.count(key) != 0) {
167  auto info = player_owner_map.at(key);
168  // Check if session is attached(1) and that the detachment
169  // request comes from the same peer(2) that created the session.
170  if (std::get<1>(info) && (std::get<2>(info) == msg->sender())) { // Player is attached
171  std::get<1>(info) = false; // Detached
172  std::get<2>(info).clear(); // Clear registered sender/peer
173  auto player = configuration.player_store->player_for_key(key);
174  player->lifetime().set(media::Player::Lifetime::resumable);
175  }
176  }
177 
178  auto reply = dbus::Message::make_method_return(msg);
179  impl->access_bus()->send(reply);
180 
181  } catch(const std::runtime_error& e)
182  {
183  auto reply = dbus::Message::make_error(
184  msg,
186  e.what());
187  impl->access_bus()->send(reply);
188  }
189  }
190 
191  void handle_reattach_session(const core::dbus::Message::Ptr& msg)
192  {
193  try
194  {
195  std::string uuid;
196  msg->reader() >> uuid;
197 
198  if (uuid_player_map.count(uuid) != 0) {
199  auto key = uuid_player_map.at(uuid);
200  if (not configuration.player_store->has_player_for_key(key)) {
201  auto reply = dbus::Message::make_error(
202  msg,
204  "Unable to locate player session");
205  impl->access_bus()->send(reply);
206  return;
207  }
208  std::stringstream ss;
209  ss << "/core/ubuntu/media/Service/sessions/" << key;
210  dbus::types::ObjectPath op{ss.str()};
211 
212  request_context_resolver->resolve_context_for_dbus_name_async(msg->sender(), [this, msg, key, op](const media::apparmor::ubuntu::Context& context)
213  {
214  auto info = player_owner_map.at(key);
215  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());
216  if (std::get<0>(info) == context.str()) {
217  std::get<1>(info) = true; // Set to Attached
218  std::get<2>(info) = msg->sender(); // Register new owner
219 
220  // Signal player reconnection
221  auto player = configuration.player_store->player_for_key(key);
222  player->reconnect();
223 
224  auto reply = dbus::Message::make_method_return(msg);
225  reply->writer() << op;
226 
227  impl->access_bus()->send(reply);
228  }
229  else {
230  auto reply = dbus::Message::make_error(
231  msg,
233  "Invalid permissions for the requested session");
234  impl->access_bus()->send(reply);
235  return;
236  }
237  });
238  }
239  else {
240  auto reply = dbus::Message::make_error(
241  msg,
243  "Invalid session");
244  impl->access_bus()->send(reply);
245  return;
246  }
247  } catch(const std::runtime_error& e)
248  {
249  auto reply = dbus::Message::make_error(
250  msg,
252  e.what());
253  impl->access_bus()->send(reply);
254  }
255  }
256 
257  void handle_destroy_session(const core::dbus::Message::Ptr& msg)
258  {
259 
260  try
261  {
262  std::string uuid;
263  msg->reader() >> uuid;
264 
265  if (uuid_player_map.count(uuid) != 0) {
266  auto key = uuid_player_map.at(uuid);
267  if (not configuration.player_store->has_player_for_key(key)) {
268  auto reply = dbus::Message::make_error(
269  msg,
271  "Unable to locate player session");
272  impl->access_bus()->send(reply);
273  return;
274  }
275 
276  // Remove control entries from the map, at this point
277  // the session is no longer usable.
278  uuid_player_map.erase(uuid);
279 
280  request_context_resolver->resolve_context_for_dbus_name_async(msg->sender(), [this, msg, key](const media::apparmor::ubuntu::Context& context)
281  {
282  auto info = player_owner_map.at(key);
283  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());
284  if (std::get<0>(info) == context.str()) {
285  player_owner_map.erase(key);
286 
287  // Reset lifecycle to non-resumable on the now-abandoned session
288  auto player = configuration.player_store->player_for_key(key);
289 
290  // Delete player instance by abandonment
291  player->lifetime().set(media::Player::Lifetime::normal);
292  player->abandon();
293 
294  auto reply = dbus::Message::make_method_return(msg);
295  impl->access_bus()->send(reply);
296  }
297  else {
298  auto reply = dbus::Message::make_error(
299  msg,
301  "Invalid permissions for the requested session");
302  impl->access_bus()->send(reply);
303  return;
304  }
305  });
306  }
307  else {
308  auto reply = dbus::Message::make_error(
309  msg,
311  "Invalid session");
312  impl->access_bus()->send(reply);
313  return;
314  }
315  } catch(const std::runtime_error& e)
316  {
317  auto reply = dbus::Message::make_error(
318  msg,
320  e.what());
321  impl->access_bus()->send(reply);
322  }
323  }
324 
325  void handle_create_fixed_session(const core::dbus::Message::Ptr& msg)
326  {
327  try
328  {
329  std::string name;
330  msg->reader() >> name;
331 
332  if (named_player_map.count(name) == 0) {
333  // Create new session
334  auto session_info = create_session_info();
335 
336  dbus::types::ObjectPath op{std::get<0>(session_info)};
337  media::Player::PlayerKey key{std::get<1>(session_info)};
338 
339  media::Player::Configuration config
340  {
341  key,
342  impl->access_bus(),
343  impl->access_service(),
344  impl->access_service()->add_object_for_path(op)
345  };
346 
347  auto session = impl->create_session(config);
348  session->lifetime().set(media::Player::Lifetime::resumable);
349 
350  configuration.player_store->add_player_for_key(key, session);
351 
352  named_player_map.insert(std::make_pair(name, key));
353 
354  auto reply = dbus::Message::make_method_return(msg);
355  reply->writer() << op;
356 
357  impl->access_bus()->send(reply);
358  }
359  else {
360  // Resume previous session
361  auto key = named_player_map.at(name);
362  if (not configuration.player_store->has_player_for_key(key)) {
363  auto reply = dbus::Message::make_error(
364  msg,
366  "Unable to locate player session");
367  impl->access_bus()->send(reply);
368  return;
369  }
370 
371  std::stringstream ss;
372  ss << "/core/ubuntu/media/Service/sessions/" << key;
373  dbus::types::ObjectPath op{ss.str()};
374 
375  auto reply = dbus::Message::make_method_return(msg);
376  reply->writer() << op;
377 
378  impl->access_bus()->send(reply);
379  }
380  } catch(const std::runtime_error& e)
381  {
382  auto reply = dbus::Message::make_error(
383  msg,
385  e.what());
386  impl->access_bus()->send(reply);
387  }
388  }
389 
390  void handle_resume_session(const core::dbus::Message::Ptr& msg)
391  {
392  try
393  {
394  Player::PlayerKey key;
395  msg->reader() >> key;
396 
397  if (not configuration.player_store->has_player_for_key(key)) {
398  auto reply = dbus::Message::make_error(
399  msg,
401  "Unable to locate player session");
402  impl->access_bus()->send(reply);
403  return;
404  }
405 
406  std::stringstream ss;
407  ss << "/core/ubuntu/media/Service/sessions/" << key;
408  dbus::types::ObjectPath op{ss.str()};
409 
410  auto reply = dbus::Message::make_method_return(msg);
411  reply->writer() << op;
412 
413  impl->access_bus()->send(reply);
414  } catch(const std::runtime_error& e)
415  {
416  auto reply = dbus::Message::make_error(
417  msg,
419  e.what());
420  impl->access_bus()->send(reply);
421  }
422  }
423 
424  void handle_pause_other_sessions(const core::dbus::Message::Ptr& msg)
425  {
426  std::cout << __PRETTY_FUNCTION__ << std::endl;
427  Player::PlayerKey key;
428  msg->reader() >> key;
429  impl->pause_other_sessions(key);
430 
431  auto reply = dbus::Message::make_method_return(msg);
432  impl->access_bus()->send(reply);
433  }
434 
435  media::apparmor::ubuntu::RequestContextResolver::Ptr request_context_resolver;
437  dbus::Object::Ptr object;
438 
439  // We remember all our creation time arguments.
440  ServiceSkeleton::Configuration configuration;
441  // We map named/fixed player instances to their respective keys.
442  std::map<std::string, media::Player::PlayerKey> named_player_map;
443  // We map UUIDs to their respective keys.
444  std::map<std::string, media::Player::PlayerKey> uuid_player_map;
445  // We keep a list of keys and their respective owners and states.
446  // value: (owner context, attached state, attached dbus name)
447  std::map<media::Player::PlayerKey, std::tuple<std::string, bool, std::string>> player_owner_map;
448 
449  boost::uuids::random_generator gen;
450 
451  // We expose the entire service as an MPRIS player.
452  struct Exported
453  {
455  {
457  // TODO(tvoss): These three elements really should be configurable.
458  defaults.identity = "core::media::Hub";
459  defaults.desktop_entry = "mediaplayer-app";
460  defaults.supported_mime_types = {"audio/mpeg3"};
461 
462  return defaults;
463  }
464 
466  {
468 
469  // Disabled as track list is not fully implemented yet.
470  defaults.can_go_next = false;
471  // Disabled as track list is not fully implemented yet.
472  defaults.can_go_previous = false;
473 
474  return defaults;
475  }
476 
477  static std::string service_name()
478  {
479  static const bool export_to_indicator_sound_via_mpris
480  {
481  core::posix::this_process::env::get("UBUNTU_MEDIA_HUB_EXPORT_TO_INDICATOR_VIA_MPRIS", "0") == "1"
482  };
483 
484  return export_to_indicator_sound_via_mpris ? "org.mpris.MediaPlayer2.MediaHub" :
485  "hidden.org.mpris.MediaPlayer2.MediaHub";
486  }
487 
488  explicit Exported(const dbus::Bus::Ptr& bus, const media::CoverArtResolver& cover_art_resolver)
489  : bus{bus},
490  service{dbus::Service::add_service(bus, service_name())},
491  object{service->add_object_for_path(dbus::types::ObjectPath{"/org/mpris/MediaPlayer2"})},
496  {
497  object->install_method_handler<core::dbus::interfaces::Properties::GetAll>([this](const core::dbus::Message::Ptr& msg)
498  {
499  // Extract the interface
500  std::string itf; msg->reader() >> itf;
501  core::dbus::Message::Ptr reply = core::dbus::Message::make_method_return(msg);
502 
503  if (itf == mpris::Player::name())
504  reply->writer() << player.get_all_properties();
505  else if (itf == mpris::MediaPlayer2::name())
506  reply->writer() << media_player.get_all_properties();
507  else if (itf == mpris::Playlists::name())
508  reply->writer() << playlists.get_all_properties();
509 
510  Exported::bus->send(reply);
511  });
512 
513  // Setup method handlers for mpris::Player methods.
514  auto next = [this](const core::dbus::Message::Ptr& msg)
515  {
516  auto sp = current_player.lock();
517 
518  if (sp)
519  sp->next();
520 
521  Exported::bus->send(core::dbus::Message::make_method_return(msg));
522  };
523  object->install_method_handler<mpris::Player::Next>(next);
524 
525  auto previous = [this](const core::dbus::Message::Ptr& msg)
526  {
527  auto sp = current_player.lock();
528 
529  if (sp)
530  sp->previous();
531 
532  Exported::bus->send(core::dbus::Message::make_method_return(msg));
533  };
534  object->install_method_handler<mpris::Player::Previous>(previous);
535 
536  auto pause = [this](const core::dbus::Message::Ptr& msg)
537  {
538  auto sp = current_player.lock();
539 
540  if (sp)
541  sp->pause();
542 
543  Exported::bus->send(core::dbus::Message::make_method_return(msg));
544  };
545  object->install_method_handler<mpris::Player::Pause>(pause);
546 
547  auto stop = [this](const core::dbus::Message::Ptr& msg)
548  {
549  auto sp = current_player.lock();
550 
551  if (sp)
552  sp->stop();
553 
554  Exported::bus->send(core::dbus::Message::make_method_return(msg));
555  };
556  object->install_method_handler<mpris::Player::Stop>(stop);
557 
558  auto play = [this](const core::dbus::Message::Ptr& msg)
559  {
560  auto sp = current_player.lock();
561 
562  if (sp)
563  sp->play();
564 
565  Exported::bus->send(core::dbus::Message::make_method_return(msg));
566  };
567  object->install_method_handler<mpris::Player::Play>(play);
568 
569  auto play_pause = [this](const core::dbus::Message::Ptr& msg)
570  {
571  auto sp = current_player.lock();
572 
573  if (sp)
574  {
575  if (sp->playback_status() == media::Player::PlaybackStatus::playing)
576  sp->pause();
577  else if (sp->playback_status() != media::Player::PlaybackStatus::null)
578  sp->play();
579  }
580 
581  Exported::bus->send(core::dbus::Message::make_method_return(msg));
582  };
583  object->install_method_handler<mpris::Player::PlayPause>(play_pause);
584  }
585 
586  void set_current_player(const std::shared_ptr<media::Player>& cp)
587  {
589 
590  // We will not keep the object alive.
591  current_player = cp;
592 
593  // And announce that we can be controlled again.
594  player.properties.can_control->set(false);
595 
596  // We wire up player state changes
597  connections.seeked_to = cp->seeked_to().connect([this](std::uint64_t position)
598  {
599  player.signals.seeked_to->emit(position);
600  });
601 
602  connections.duration_changed = cp->duration().changed().connect([this](std::uint64_t duration)
603  {
604  player.properties.duration->set(duration);
605  });
606 
607  connections.position_changed = cp->position().changed().connect([this](std::uint64_t position)
608  {
609  player.properties.position->set(position);
610  });
611 
612  connections.playback_status_changed = cp->playback_status().changed().connect([this](core::ubuntu::media::Player::PlaybackStatus status)
613  {
615  });
616 
617  connections.loop_status_changed = cp->loop_status().changed().connect([this](core::ubuntu::media::Player::LoopStatus status)
618  {
620  });
621 
622  connections.meta_data_changed = cp->meta_data_for_current_track().changed().connect([this](const core::ubuntu::media::Track::MetaData& md)
623  {
625 
626  bool has_title = md.count(xesam::Title::name) > 0;
627  bool has_album_name = md.count(xesam::Album::name) > 0;
628  bool has_artist_name = md.count(xesam::Artist::name) > 0;
629 
630  if (has_title)
631  dict[xesam::Title::name] = dbus::types::Variant::encode(md.get(xesam::Title::name));
632  if (has_album_name)
633  dict[xesam::Album::name] = dbus::types::Variant::encode(md.get(xesam::Album::name));
634  if (has_artist_name)
635  dict[xesam::Artist::name] = dbus::types::Variant::encode(md.get(xesam::Artist::name));
636 
637  dict[mpris::metadata::ArtUrl::name] = dbus::types::Variant::encode(
639  has_title ? md.get(xesam::Title::name) : "",
640  has_album_name ? md.get(xesam::Album::name) : "",
641  has_artist_name ? md.get(xesam::Artist::name) : ""));
642 
644  wrap[mpris::Player::Properties::Metadata::name()] = dbus::types::Variant::encode(dict);
645 
647  std::make_tuple(
648  dbus::traits::Service<mpris::Player::Properties::Metadata::Interface>::interface_name(),
649  wrap,
650  std::vector<std::string>()));
651  });
652  }
653 
655  {
656  current_player.reset();
657 
658  // We disconnect all previous event connections.
659  connections.seeked_to.disconnect();
660  connections.duration_changed.disconnect();
661  connections.position_changed.disconnect();
662  connections.playback_status_changed.disconnect();
663  connections.loop_status_changed.disconnect();
664  connections.meta_data_changed.disconnect();
665 
666  // And announce that we cannot be controlled anymore.
667  player.properties.can_control->set(false);
668  }
669 
670  void unset_if_current(const std::shared_ptr<media::Player>& cp)
671  {
672  if (cp == current_player.lock())
674  }
675 
676  dbus::Bus::Ptr bus;
677  dbus::Service::Ptr service;
678  dbus::Object::Ptr object;
679 
683 
684  // The CoverArtResolver used by the exported player.
686  // The actual player instance.
687  std::weak_ptr<media::Player> current_player;
688  // We track event connections.
689  struct
690  {
691  core::Connection seeked_to
692  {
693  the_empty_signal.connect([](){})
694  };
695  core::Connection duration_changed
696  {
697  the_empty_signal.connect([](){})
698  };
699  core::Connection position_changed
700  {
701  the_empty_signal.connect([](){})
702  };
703  core::Connection playback_status_changed
704  {
705  the_empty_signal.connect([](){})
706  };
707  core::Connection loop_status_changed
708  {
709  the_empty_signal.connect([](){})
710  };
711  core::Connection meta_data_changed
712  {
713  the_empty_signal.connect([](){})
714  };
715  } connections;
716  } exported;
717 };
718 
719 media::ServiceSkeleton::ServiceSkeleton(const Configuration& configuration)
720  : dbus::Skeleton<media::Service>(the_session_bus()),
721  d(new Private(this, configuration))
722 {
723 }
724 
726 {
727 }
728 
729 std::shared_ptr<media::Player> media::ServiceSkeleton::create_session(const media::Player::Configuration& config)
730 {
731  return d->configuration.impl->create_session(config);
732 }
733 
734 void media::ServiceSkeleton::detach_session(const std::string& uuid, const media::Player::Configuration& config)
735 {
736  return d->configuration.impl->detach_session(uuid, config);
737 }
738 
739 std::shared_ptr<media::Player> media::ServiceSkeleton::reattach_session(const std::string& uuid, const media::Player::Configuration& config)
740 {
741  return d->configuration.impl->reattach_session(uuid, config);
742 }
743 
744 void media::ServiceSkeleton::destroy_session(const std::string& uuid, const media::Player::Configuration& config)
745 {
746  return d->configuration.impl->destroy_session(uuid, config);
747 }
748 
749 std::shared_ptr<media::Player> media::ServiceSkeleton::create_fixed_session(const std::string& name, const media::Player::Configuration&config)
750 {
751  return d->configuration.impl->create_fixed_session(name, config);
752 }
753 
754 std::shared_ptr<media::Player> media::ServiceSkeleton::resume_session(media::Player::PlayerKey key)
755 {
756  return d->configuration.impl->resume_session(key);
757 }
758 
760 {
761  d->configuration.impl->pause_other_sessions(key);
762 }
763 
765 {
766  access_bus()->run();
767 }
768 
770 {
771  access_bus()->stop();
772 }
std::weak_ptr< media::Player > current_player
struct mpris::Player::Skeleton::@16 signals
struct media::ServiceSkeleton::Private::Exported::@27 connections
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 &)
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