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> 53 core::Signal<void> the_empty_signal;
61 object(impl->access_service()->add_object_for_path(
62 dbus::traits::Service<
media::Service>::object_path())),
63 configuration(config),
64 exported(impl->access_bus(), config.cover_art_resolver, impl)
66 object->install_method_handler<mpris::Service::CreateSession>(
68 &Private::handle_create_session,
70 std::placeholders::_1));
71 object->install_method_handler<mpris::Service::DetachSession>(
73 &Private::handle_detach_session,
75 std::placeholders::_1));
76 object->install_method_handler<mpris::Service::ReattachSession>(
78 &Private::handle_reattach_session,
80 std::placeholders::_1));
81 object->install_method_handler<mpris::Service::DestroySession>(
83 &Private::handle_destroy_session,
85 std::placeholders::_1));
86 object->install_method_handler<mpris::Service::CreateFixedSession>(
88 &Private::handle_create_fixed_session,
90 std::placeholders::_1));
91 object->install_method_handler<mpris::Service::ResumeSession>(
93 &Private::handle_resume_session,
95 std::placeholders::_1));
96 object->install_method_handler<mpris::Service::SetCurrentPlayer>(
98 &Private::handle_set_current_player,
100 std::placeholders::_1));
101 object->install_method_handler<mpris::Service::PauseOtherSessions>(
103 &Private::handle_pause_other_sessions,
105 std::placeholders::_1));
110 static unsigned int session_counter = 0;
112 const unsigned int current_session = session_counter++;
113 boost::uuids::uuid uuid = gen();
115 std::stringstream ss;
116 ss <<
"/core/ubuntu/media/Service/sessions/" << current_session;
123 auto session_info = create_session_info();
125 dbus::types::ObjectPath op{std::get<0>(session_info)};
127 std::string uuid{std::get<2>(session_info)};
129 media::Player::Configuration config
133 impl->access_service(),
134 impl->access_service()->add_object_for_path(op)
137 cout <<
"Session created by request of: " << msg->sender()
138 <<
", key: " << key <<
", uuid: " << uuid
139 <<
", path:" << op << std::endl;
143 const std::shared_ptr<media::Player> player {
impl->create_session(config)};
144 configuration.player_store->add_player_for_key(key, player);
145 uuid_player_map.emplace(std::make_pair(uuid, key));
147 request_context_resolver->resolve_context_for_dbus_name_async(msg->sender(),
148 [
this, key, msg](
const media::apparmor::ubuntu::Context& context)
150 fprintf(stderr,
"%s():%d -- app_name='%s', attached\n", __func__, __LINE__, context.str().c_str());
151 player_owner_map.emplace(std::make_pair(key, std::make_tuple(context.str(),
true, msg->sender())));
154 auto reply = dbus::Message::make_method_return(msg);
155 reply->writer() << std::make_tuple(op, uuid);
157 impl->access_bus()->send(reply);
158 }
catch(
const std::runtime_error& e)
160 auto reply = dbus::Message::make_error(
164 impl->access_bus()->send(reply);
173 msg->reader() >> uuid;
176 if (!uuid_player_map.empty())
178 const auto key = uuid_player_map.at(uuid);
180 if (player_owner_map.count(key) != 0) {
181 auto info = player_owner_map.at(key);
184 if (std::get<1>(info) && (std::get<2>(info) == msg->sender())) {
185 std::get<1>(info) =
false;
186 std::get<2>(info).clear();
188 auto player = configuration.player_store->player_for_key(key);
189 player->lifetime().set(media::Player::Lifetime::resumable);
194 auto reply = dbus::Message::make_method_return(msg);
195 impl->access_bus()->send(reply);
197 }
catch(
const std::runtime_error& e)
199 auto reply = dbus::Message::make_error(
203 impl->access_bus()->send(reply);
212 msg->reader() >> uuid;
214 if (uuid_player_map.count(uuid) != 0)
216 const auto key = uuid_player_map.at(uuid);
217 if (not configuration.player_store->has_player_for_key(key))
219 auto reply = dbus::Message::make_error(
222 "Unable to locate player session");
223 impl->access_bus()->send(reply);
226 std::stringstream ss;
227 ss <<
"/core/ubuntu/media/Service/sessions/" << key;
228 dbus::types::ObjectPath op{ss.str()};
230 request_context_resolver->resolve_context_for_dbus_name_async(msg->sender(),
231 [
this, msg, key, op](
const media::apparmor::ubuntu::Context& context)
233 auto info = player_owner_map.at(key);
234 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());
235 if (std::get<0>(info) == context.str()) {
236 std::get<1>(info) =
true;
237 std::get<2>(info) = msg->sender();
240 auto player = configuration.player_store->player_for_key(key);
243 if (player->audio_stream_role() == media::Player::AudioStreamRole::multimedia)
245 std::cout <<
"Setting current_player" << std::endl;
246 exported.set_current_player(player);
249 auto reply = dbus::Message::make_method_return(msg);
250 reply->writer() << op;
252 impl->access_bus()->send(reply);
255 auto reply = dbus::Message::make_error(
258 "Invalid permissions for the requested session");
259 impl->access_bus()->send(reply);
265 auto reply = dbus::Message::make_error(
269 impl->access_bus()->send(reply);
272 }
catch(
const std::runtime_error& e)
274 auto reply = dbus::Message::make_error(
278 impl->access_bus()->send(reply);
287 msg->reader() >> uuid;
289 if (uuid_player_map.count(uuid) != 0) {
290 const auto key = uuid_player_map.at(uuid);
291 if (not configuration.player_store->has_player_for_key(key)) {
292 auto reply = dbus::Message::make_error(
295 "Unable to locate player session");
296 impl->access_bus()->send(reply);
302 uuid_player_map.erase(uuid);
304 request_context_resolver->resolve_context_for_dbus_name_async(msg->sender(),
305 [
this, msg, key](
const media::apparmor::ubuntu::Context& context)
307 auto info = player_owner_map.at(key);
308 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());
309 if (std::get<0>(info) == context.str()) {
310 player_owner_map.erase(key);
313 auto player = configuration.player_store->player_for_key(key);
316 player->lifetime().set(media::Player::Lifetime::normal);
319 auto reply = dbus::Message::make_method_return(msg);
320 impl->access_bus()->send(reply);
323 auto reply = dbus::Message::make_error(
326 "Invalid permissions for the requested session");
327 impl->access_bus()->send(reply);
333 auto reply = dbus::Message::make_error(
337 impl->access_bus()->send(reply);
340 }
catch(
const std::runtime_error& e)
342 auto reply = dbus::Message::make_error(
346 impl->access_bus()->send(reply);
355 msg->reader() >> name;
357 if (named_player_map.count(name) == 0) {
359 auto session_info = create_session_info();
361 dbus::types::ObjectPath op{std::get<0>(session_info)};
364 media::Player::Configuration config
368 impl->access_service(),
369 impl->access_service()->add_object_for_path(op)
372 auto session =
impl->create_session(config);
373 session->lifetime().set(media::Player::Lifetime::resumable);
375 configuration.player_store->add_player_for_key(key, session);
377 named_player_map.insert(std::make_pair(name, key));
379 auto reply = dbus::Message::make_method_return(msg);
380 reply->writer() << op;
382 impl->access_bus()->send(reply);
386 const auto key = named_player_map.at(name);
387 if (not configuration.player_store->has_player_for_key(key)) {
388 auto reply = dbus::Message::make_error(
391 "Unable to locate player session");
392 impl->access_bus()->send(reply);
396 std::stringstream ss;
397 ss <<
"/core/ubuntu/media/Service/sessions/" << key;
398 dbus::types::ObjectPath op{ss.str()};
400 auto reply = dbus::Message::make_method_return(msg);
401 reply->writer() << op;
403 impl->access_bus()->send(reply);
405 }
catch(
const std::runtime_error& e)
407 auto reply = dbus::Message::make_error(
411 impl->access_bus()->send(reply);
419 Player::PlayerKey key;
420 msg->reader() >> key;
422 if (not configuration.player_store->has_player_for_key(key)) {
423 auto reply = dbus::Message::make_error(
426 "Unable to locate player session");
427 impl->access_bus()->send(reply);
431 std::stringstream ss;
432 ss <<
"/core/ubuntu/media/Service/sessions/" << key;
433 dbus::types::ObjectPath op{ss.str()};
435 auto reply = dbus::Message::make_method_return(msg);
436 reply->writer() << op;
438 impl->access_bus()->send(reply);
439 }
catch(
const std::runtime_error& e)
441 auto reply = dbus::Message::make_error(
445 impl->access_bus()->send(reply);
451 Player::PlayerKey key;
452 msg->reader() >> key;
454 core::dbus::Message::Ptr reply;
455 if (not configuration.player_store->has_player_for_key(key))
457 std::cerr << __PRETTY_FUNCTION__ <<
" player key not found - " << key << std::endl;
458 reply = dbus::Message::make_error(
461 "Player key not found");
466 impl->set_current_player(key);
467 reply = dbus::Message::make_method_return(msg);
469 catch (
const std::out_of_range &e) {
470 std::cerr <<
"Failed to look up Player instance for key " << key
471 <<
", no valid Player instance for that key value and cannot set current player." 472 <<
" This most likely means that media-hub-server has crashed and restarted." 474 reply = dbus::Message::make_error(
477 "Player key not found");
481 impl->access_bus()->send(reply);
486 Player::PlayerKey key;
487 msg->reader() >> key;
488 core::dbus::Message::Ptr reply;
490 impl->pause_other_sessions(key);
491 reply = dbus::Message::make_method_return(msg);
493 catch (
const std::out_of_range &e) {
494 std::cerr <<
"Failed to look up Player instance for key " << key
495 <<
", no valid Player instance for that key value and cannot pause other Players." 496 <<
" This most likely means that media-hub-server has crashed and restarted." 498 reply = dbus::Message::make_error(
501 "Player key not found");
504 impl->access_bus()->send(reply);
519 std::map<media::Player::PlayerKey, std::tuple<std::string, bool, std::string>>
player_owner_map;
521 boost::uuids::random_generator
gen;
530 defaults.
identity =
"core::media::Hub";
548 service{dbus::Service::add_service(bus,
"org.mpris.MediaPlayer2.MediaHub")},
549 object{service->add_object_for_path(dbus::types::ObjectPath{
"/org/mpris/MediaPlayer2"})},
553 cover_art_resolver{cover_art_resolver},
556 object->install_method_handler<core::dbus::interfaces::Properties::GetAll>([
this](
const core::dbus::Message::Ptr& msg)
559 std::string interface;
560 msg->reader() >> interface;
561 core::dbus::Message::Ptr reply = core::dbus::Message::make_method_return(msg);
564 reply->writer() << player.get_all_properties();
566 reply->writer() << media_player.get_all_properties();
568 reply->writer() << playlists.get_all_properties();
570 Exported::bus->send(reply);
574 auto next = [
this](
const core::dbus::Message::Ptr& msg)
576 const auto sp = current_player.lock();
578 if (is_multimedia_role())
581 Exported::bus->send(core::dbus::Message::make_method_return(msg));
583 object->install_method_handler<mpris::Player::Next>(next);
585 auto previous = [
this](
const core::dbus::Message::Ptr& msg)
587 const auto sp = current_player.lock();
589 if (is_multimedia_role())
592 Exported::bus->send(core::dbus::Message::make_method_return(msg));
594 object->install_method_handler<mpris::Player::Previous>(previous);
596 auto pause = [
this](
const core::dbus::Message::Ptr& msg)
598 const auto sp = current_player.lock();
600 if (is_multimedia_role() and sp->can_pause())
603 Exported::bus->send(core::dbus::Message::make_method_return(msg));
605 object->install_method_handler<mpris::Player::Pause>(pause);
607 auto stop = [
this](
const core::dbus::Message::Ptr& msg)
609 const auto sp = current_player.lock();
611 if (is_multimedia_role())
614 Exported::bus->send(core::dbus::Message::make_method_return(msg));
616 object->install_method_handler<mpris::Player::Stop>(stop);
618 auto play = [
this, impl](
const core::dbus::Message::Ptr& msg)
620 const auto sp = current_player.lock();
622 if (is_multimedia_role() and sp->can_play())
632 Exported::bus->send(core::dbus::Message::make_method_return(msg));
634 object->install_method_handler<mpris::Player::Play>(play);
636 auto play_pause = [
this, impl](
const core::dbus::Message::Ptr& msg)
638 const auto sp = current_player.lock();
640 if (is_multimedia_role())
642 if (sp->playback_status() == media::Player::PlaybackStatus::playing
645 else if (sp->playback_status() != media::Player::PlaybackStatus::null
657 Exported::bus->send(core::dbus::Message::make_method_return(msg));
659 object->install_method_handler<mpris::Player::PlayPause>(play_pause);
664 const auto sp = current_player.lock();
666 return (sp ? sp->audio_stream_role() == media::Player::AudioStreamRole::multimedia :
false);
671 std::cout <<
"*** " << __PRETTY_FUNCTION__ << std::endl;
676 player.properties.can_control->set(
true);
679 connections.seeked_to = cp->seeked_to().connect([
this](std::uint64_t position)
681 player.signals.seeked_to->emit(position);
684 connections.duration_changed = cp->duration().changed().connect([
this](std::uint64_t duration)
686 player.properties.duration->set(duration);
689 connections.position_changed = cp->position().changed().connect([
this](std::uint64_t position)
691 player.properties.position->set(position);
694 connections.playback_status_changed = cp->playback_status().changed().connect(
700 connections.loop_status_changed = cp->loop_status().changed().connect(
706 connections.can_play_changed = cp->can_play().changed().connect(
707 [
this](
bool can_play)
709 player.properties.can_play->set(can_play);
712 connections.can_pause_changed = cp->can_pause().changed().connect(
713 [
this](
bool can_pause)
715 player.properties.can_pause->set(can_pause);
718 connections.can_go_previous_changed = cp->can_go_previous().changed().connect(
719 [
this](
bool can_go_previous)
721 player.properties.can_go_previous->set(can_go_previous);
724 connections.can_go_next_changed = cp->can_go_next().changed().connect(
725 [
this](
bool can_go_next)
727 player.properties.can_go_next->set(can_go_next);
736 player.properties.duration->set(cp->duration().get());
737 player.properties.position->set(cp->position().get());
739 cp->playback_status().get()));
741 cp->loop_status().get()));
742 player.properties.can_play->set(cp->can_play().get());
743 player.properties.can_pause->set(cp->can_pause().get());
744 player.properties.can_go_previous->set(cp->can_go_previous().get());
745 player.properties.can_go_next->set(cp->can_go_next().get());
749 connections.meta_data_changed = cp->meta_data_for_current_track().changed().connect(
754 bool has_title = md.
count(xesam::Title::name) > 0;
755 bool has_album_name = md.
count(xesam::Album::name) > 0;
756 bool has_artist_name = md.
count(xesam::Artist::name) > 0;
759 dict[xesam::Title::name] = dbus::types::Variant::encode(md.
get(xesam::Title::name));
761 dict[xesam::Album::name] = dbus::types::Variant::encode(md.
get(xesam::Album::name));
763 dict[xesam::Artist::name] = dbus::types::Variant::encode(md.
get(xesam::Artist::name));
767 has_title ? md.
get(xesam::Title::name) :
"",
768 has_album_name ? md.
get(xesam::Album::name) :
"",
769 has_artist_name ? md.
get(xesam::Artist::name) :
""));
772 wrap[mpris::Player::Properties::Metadata::name()] = dbus::types::Variant::encode(dict);
774 player.signals.properties_changed->emit(
776 dbus::traits::Service<
777 mpris::Player::Properties::Metadata::Interface>
780 std::vector<std::string>()));
787 std::cout << __PRETTY_FUNCTION__ << std::endl;
789 player.properties.can_control->set(
false);
790 current_player.reset();
811 core::Connection seeked_to
813 the_empty_signal.connect([](){})
815 core::Connection duration_changed
817 the_empty_signal.connect([](){})
819 core::Connection position_changed
821 the_empty_signal.connect([](){})
823 core::Connection playback_status_changed
825 the_empty_signal.connect([](){})
827 core::Connection loop_status_changed
829 the_empty_signal.connect([](){})
831 core::Connection can_play_changed
833 the_empty_signal.connect([](){})
835 core::Connection can_pause_changed
837 the_empty_signal.connect([](){})
839 core::Connection can_go_previous_changed
841 the_empty_signal.connect([](){})
843 core::Connection can_go_next_changed
845 the_empty_signal.connect([](){})
847 core::Connection meta_data_changed
849 the_empty_signal.connect([](){})
857 d(
new Private(
this, configuration))
867 return d->configuration.impl->create_session(config);
872 return d->configuration.impl->detach_session(uuid, config);
877 return d->configuration.impl->reattach_session(uuid, config);
882 return d->configuration.impl->destroy_session(uuid, config);
887 return d->configuration.impl->create_fixed_session(name, config);
892 return d->configuration.impl->resume_session(key);
897 const std::shared_ptr<media::Player> player =
898 d->configuration.player_store->player_for_key(key);
900 if (player->audio_stream_role() == media::Player::AudioStreamRole::multimedia)
901 d->exported.set_current_player(player);
906 d->configuration.impl->pause_other_sessions(key);
916 access_bus()->stop();
static const std::string & name()
static const std::string & name()
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)
static const std::string & name()
static const std::string & name()
static const std::string & name()
static const std::string & name()