32 #include <core/dbus/message.h>
33 #include <core/dbus/object.h>
34 #include <core/dbus/types/object_path.h>
36 #include <core/posix/this_process.h>
38 #include <boost/uuid/uuid.hpp>
39 #include <boost/uuid/uuid_generators.hpp>
40 #include <boost/uuid/uuid_io.hpp>
51 core::Signal<void> the_empty_signal;
59 object(impl->access_service()->add_object_for_path(
60 dbus::traits::Service<
media::Service>::object_path())),
62 exported(impl->access_bus(), config.cover_art_resolver)
64 object->install_method_handler<mpris::Service::CreateSession>(
68 std::placeholders::_1));
69 object->install_method_handler<mpris::Service::DetachSession>(
73 std::placeholders::_1));
74 object->install_method_handler<mpris::Service::ReattachSession>(
78 std::placeholders::_1));
79 object->install_method_handler<mpris::Service::DestroySession>(
83 std::placeholders::_1));
84 object->install_method_handler<mpris::Service::CreateFixedSession>(
88 std::placeholders::_1));
89 object->install_method_handler<mpris::Service::ResumeSession>(
93 std::placeholders::_1));
94 object->install_method_handler<mpris::Service::PauseOtherSessions>(
98 std::placeholders::_1));
103 static unsigned int session_counter = 0;
105 unsigned int current_session = session_counter++;
106 boost::uuids::uuid uuid =
gen();
108 std::stringstream ss;
109 ss <<
"/core/ubuntu/media/Service/sessions/" << current_session;
118 dbus::types::ObjectPath op{std::get<0>(session_info)};
120 std::string uuid{std::get<2>(session_info)};
122 media::Player::Configuration config
126 impl->access_service(),
127 impl->access_service()->add_object_for_path(op)
130 std::cout <<
"Session created by request of: " << msg->sender() <<
", uuid: " << uuid <<
", path:" << op << std::endl;
134 configuration.player_store->add_player_for_key(key,
impl->create_session(config));
137 request_context_resolver->resolve_context_for_dbus_name_async(msg->sender(), [
this, key, msg](
const media::apparmor::ubuntu::Context& context)
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())));
143 auto reply = dbus::Message::make_method_return(msg);
144 reply->writer() << std::make_tuple(op, uuid);
146 impl->access_bus()->send(reply);
147 }
catch(
const std::runtime_error& e)
149 auto reply = dbus::Message::make_error(
153 impl->access_bus()->send(reply);
162 msg->reader() >> uuid;
170 if (std::get<1>(info) && (std::get<2>(info) == msg->sender())) {
171 std::get<1>(info) =
false;
172 std::get<2>(info).clear();
173 auto player =
configuration.player_store->player_for_key(key);
174 player->lifetime().set(media::Player::Lifetime::resumable);
178 auto reply = dbus::Message::make_method_return(msg);
179 impl->access_bus()->send(reply);
181 }
catch(
const std::runtime_error& e)
183 auto reply = dbus::Message::make_error(
187 impl->access_bus()->send(reply);
196 msg->reader() >> uuid;
200 if (not
configuration.player_store->has_player_for_key(key)) {
201 auto reply = dbus::Message::make_error(
204 "Unable to locate player session");
205 impl->access_bus()->send(reply);
208 std::stringstream ss;
209 ss <<
"/core/ubuntu/media/Service/sessions/" << key;
210 dbus::types::ObjectPath op{ss.str()};
212 request_context_resolver->resolve_context_for_dbus_name_async(msg->sender(), [
this, msg, key, op](
const media::apparmor::ubuntu::Context& context)
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;
218 std::get<2>(info) = msg->sender();
221 auto player =
configuration.player_store->player_for_key(key);
224 auto reply = dbus::Message::make_method_return(msg);
225 reply->writer() << op;
227 impl->access_bus()->send(reply);
230 auto reply = dbus::Message::make_error(
233 "Invalid permissions for the requested session");
234 impl->access_bus()->send(reply);
240 auto reply = dbus::Message::make_error(
244 impl->access_bus()->send(reply);
247 }
catch(
const std::runtime_error& e)
249 auto reply = dbus::Message::make_error(
253 impl->access_bus()->send(reply);
263 msg->reader() >> uuid;
267 if (not
configuration.player_store->has_player_for_key(key)) {
268 auto reply = dbus::Message::make_error(
271 "Unable to locate player session");
272 impl->access_bus()->send(reply);
280 request_context_resolver->resolve_context_for_dbus_name_async(msg->sender(), [
this, msg, key](
const media::apparmor::ubuntu::Context& context)
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()) {
288 auto player =
configuration.player_store->player_for_key(key);
291 player->lifetime().set(media::Player::Lifetime::normal);
294 auto reply = dbus::Message::make_method_return(msg);
295 impl->access_bus()->send(reply);
298 auto reply = dbus::Message::make_error(
301 "Invalid permissions for the requested session");
302 impl->access_bus()->send(reply);
308 auto reply = dbus::Message::make_error(
312 impl->access_bus()->send(reply);
315 }
catch(
const std::runtime_error& e)
317 auto reply = dbus::Message::make_error(
321 impl->access_bus()->send(reply);
330 msg->reader() >> name;
336 dbus::types::ObjectPath op{std::get<0>(session_info)};
339 media::Player::Configuration config
343 impl->access_service(),
344 impl->access_service()->add_object_for_path(op)
347 auto session =
impl->create_session(config);
348 session->lifetime().set(media::Player::Lifetime::resumable);
350 configuration.player_store->add_player_for_key(key, session);
354 auto reply = dbus::Message::make_method_return(msg);
355 reply->writer() << op;
357 impl->access_bus()->send(reply);
362 if (not
configuration.player_store->has_player_for_key(key)) {
363 auto reply = dbus::Message::make_error(
366 "Unable to locate player session");
367 impl->access_bus()->send(reply);
371 std::stringstream ss;
372 ss <<
"/core/ubuntu/media/Service/sessions/" << key;
373 dbus::types::ObjectPath op{ss.str()};
375 auto reply = dbus::Message::make_method_return(msg);
376 reply->writer() << op;
378 impl->access_bus()->send(reply);
380 }
catch(
const std::runtime_error& e)
382 auto reply = dbus::Message::make_error(
386 impl->access_bus()->send(reply);
395 msg->reader() >> key;
397 if (not
configuration.player_store->has_player_for_key(key)) {
398 auto reply = dbus::Message::make_error(
401 "Unable to locate player session");
402 impl->access_bus()->send(reply);
406 std::stringstream ss;
407 ss <<
"/core/ubuntu/media/Service/sessions/" << key;
408 dbus::types::ObjectPath op{ss.str()};
410 auto reply = dbus::Message::make_method_return(msg);
411 reply->writer() << op;
413 impl->access_bus()->send(reply);
414 }
catch(
const std::runtime_error& e)
416 auto reply = dbus::Message::make_error(
420 impl->access_bus()->send(reply);
426 std::cout << __PRETTY_FUNCTION__ << std::endl;
428 msg->reader() >> key;
429 impl->pause_other_sessions(key);
431 auto reply = dbus::Message::make_method_return(msg);
432 impl->access_bus()->send(reply);
447 std::map<media::Player::PlayerKey, std::tuple<std::string, bool, std::string>>
player_owner_map;
449 boost::uuids::random_generator
gen;
458 defaults.
identity =
"core::media::Hub";
479 static const bool export_to_indicator_sound_via_mpris
481 core::posix::this_process::env::get(
"UBUNTU_MEDIA_HUB_EXPORT_TO_INDICATOR_VIA_MPRIS",
"0") ==
"1"
484 return export_to_indicator_sound_via_mpris ?
"org.mpris.MediaPlayer2.MediaHub" :
485 "hidden.org.mpris.MediaPlayer2.MediaHub";
491 object{
service->add_object_for_path(dbus::types::ObjectPath{
"/org/mpris/MediaPlayer2"})},
497 object->install_method_handler<core::dbus::interfaces::Properties::GetAll>([
this](
const core::dbus::Message::Ptr& msg)
500 std::string itf; msg->reader() >> itf;
501 core::dbus::Message::Ptr reply = core::dbus::Message::make_method_return(msg);
514 auto next = [
this](
const core::dbus::Message::Ptr& msg)
521 Exported::bus->send(core::dbus::Message::make_method_return(msg));
523 object->install_method_handler<mpris::Player::Next>(next);
525 auto previous = [
this](
const core::dbus::Message::Ptr& msg)
532 Exported::bus->send(core::dbus::Message::make_method_return(msg));
534 object->install_method_handler<mpris::Player::Previous>(previous);
536 auto pause = [
this](
const core::dbus::Message::Ptr& msg)
543 Exported::bus->send(core::dbus::Message::make_method_return(msg));
545 object->install_method_handler<mpris::Player::Pause>(pause);
547 auto stop = [
this](
const core::dbus::Message::Ptr& msg)
554 Exported::bus->send(core::dbus::Message::make_method_return(msg));
556 object->install_method_handler<mpris::Player::Stop>(
stop);
558 auto play = [
this](
const core::dbus::Message::Ptr& msg)
565 Exported::bus->send(core::dbus::Message::make_method_return(msg));
567 object->install_method_handler<mpris::Player::Play>(play);
569 auto play_pause = [
this](
const core::dbus::Message::Ptr& msg)
575 if (sp->playback_status() == media::Player::PlaybackStatus::playing)
577 else if (sp->playback_status() != media::Player::PlaybackStatus::null)
581 Exported::bus->send(core::dbus::Message::make_method_return(msg));
583 object->install_method_handler<mpris::Player::PlayPause>(play_pause);
597 connections.seeked_to = cp->seeked_to().connect([
this](std::uint64_t position)
602 connections.duration_changed = cp->duration().changed().connect([
this](std::uint64_t duration)
607 connections.position_changed = cp->position().changed().connect([
this](std::uint64_t position)
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;
631 dict[xesam::Title::name] = dbus::types::Variant::encode(md.
get(xesam::Title::name));
633 dict[xesam::Album::name] = dbus::types::Variant::encode(md.
get(xesam::Album::name));
635 dict[xesam::Artist::name] = dbus::types::Variant::encode(md.
get(xesam::Artist::name));
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) :
""));
644 wrap[mpris::Player::Properties::Metadata::name()] = dbus::types::Variant::encode(dict);
648 dbus::traits::Service<mpris::Player::Properties::Metadata::Interface>::interface_name(),
650 std::vector<std::string>()));
693 the_empty_signal.connect([](){})
697 the_empty_signal.connect([](){})
701 the_empty_signal.connect([](){})
705 the_empty_signal.connect([](){})
709 the_empty_signal.connect([](){})
713 the_empty_signal.connect([](){})
721 d(new
Private(this, configuration))
731 return d->configuration.impl->create_session(config);
736 return d->configuration.impl->detach_session(uuid, config);
741 return d->configuration.impl->reattach_session(uuid, config);
746 return d->configuration.impl->destroy_session(uuid, config);
751 return d->configuration.impl->create_fixed_session(name, config);
756 return d->configuration.impl->resume_session(key);
761 d->configuration.impl->pause_other_sessions(key);
771 access_bus()->stop();
struct mpris::Player::Skeleton::@16 signals
std::shared_ptr< core::dbus::Property< Properties::Duration > > duration
Properties::CanGoPrevious::ValueType can_go_previous
std::shared_ptr< core::dbus::Property< Properties::LoopStatus > > loop_status
static const std::string & name()
Properties::CanGoNext::ValueType can_go_next
struct mpris::Player::Skeleton::@15 properties
static const char * from(core::ubuntu::media::Player::PlaybackStatus status)
static const std::string & name()
static const std::string & name()
std::map< std::string, core::dbus::types::Variant > Dictionary
static const std::string & name()
static const char * from(core::ubuntu::media::Player::LoopStatus status)
std::map< std::string, core::dbus::types::Variant > get_all_properties()
Dictionary get_all_properties()
static const std::string & name()
core::dbus::Signal< Signals::Seeked, Signals::Seeked::ArgumentType >::Ptr seeked_to
static const std::string & name()
std::shared_ptr< core::dbus::Property< Properties::PlaybackStatus > > playback_status
std::shared_ptr< core::dbus::Property< Properties::CanControl > > can_control
std::shared_ptr< core::dbus::Property< Properties::Position > > position
static const std::string & name()
dbus::Signal< core::dbus::interfaces::Properties::Signals::PropertiesChanged, core::dbus::interfaces::Properties::Signals::PropertiesChanged::ArgumentType >::Ptr properties_changed
static const std::string & name()