36 #define UNUSED __attribute__((unused)) 43 template<
typename Parent>
45 public std::enable_shared_from_this<Private>
49 WAKELOCK_CLEAR_INACTIVE,
50 WAKELOCK_CLEAR_DISPLAY,
51 WAKELOCK_CLEAR_SYSTEM,
52 WAKELOCK_CLEAR_INVALID
58 display_state_lock(config.power_state_controller->display_state_lock()),
59 system_state_lock(config.power_state_controller->system_state_lock()),
61 track_list(
std::make_shared<TrackListImplementation>(
63 config.parent.service->add_object_for_path(
64 dbus::types::ObjectPath(config.parent.session->path().as_string() +
"/TrackList")),
65 engine->meta_data_extractor(),
66 config.parent.request_context_resolver,
67 config.parent.request_authenticator)),
68 system_wakelock_count(0),
69 display_wakelock_count(0),
70 previous_state(Engine::State::stopped),
71 engine_state_change_connection(engine->state().changed().connect(make_state_change_handler())),
72 engine_playback_status_change_connection(engine->playback_status_changed_signal().connect(make_playback_status_change_handler())),
78 std::cout <<
"Acquired new display state: " << state << std::endl;
83 std::cout <<
"Released display state: " << state << std::endl;
88 std::cout <<
"Acquired new system state: " << state << std::endl;
93 std::cout <<
"Released system state: " << state << std::endl;
106 engine_state_change_connection.disconnect();
111 engine_playback_status_change_connection.disconnect();
121 return [
this](
const Engine::State& state)
123 std::cout <<
"Setting state for parent: " << parent << std::endl;
126 case Engine::State::ready:
129 if (previous_state == Engine::State::playing)
131 timeout(4000,
true, make_clear_wakelock_functor());
135 case Engine::State::playing:
139 parent->meta_data_for_current_track().set(std::get<1>(engine->track_meta_data().get()));
142 std::cout <<
"Requesting power state" << std::endl;
143 request_power_state();
146 case Engine::State::stopped:
149 if (previous_state == Engine::State::playing)
151 timeout(4000,
true, make_clear_wakelock_functor());
155 case Engine::State::paused:
158 if (previous_state == Engine::State::playing)
160 timeout(4000,
true, make_clear_wakelock_functor());
169 previous_state = state;
177 std::cout <<
"Emiting playback_status_changed signal: " << status << std::endl;
178 parent->emit_playback_status_changed(status);
184 std::cout << __PRETTY_FUNCTION__ << std::endl;
187 if (parent->is_video_source())
189 if (++display_wakelock_count == 1)
191 std::cout <<
"Requesting new display wakelock." << std::endl;
192 display_state_lock->request_acquire(media::power::DisplayState::on);
193 std::cout <<
"Requested new display wakelock." << std::endl;
198 if (++system_wakelock_count == 1)
200 std::cout <<
"Requesting new system wakelock." << std::endl;
201 system_state_lock->request_acquire(media::power::SystemState::active);
202 std::cout <<
"Requested new system wakelock." << std::endl;
206 catch(
const std::exception& e)
208 std::cerr <<
"Warning: failed to request power state: ";
209 std::cerr << e.what() << std::endl;
215 cout << __PRETTY_FUNCTION__ << endl;
220 case wakelock_clear_t::WAKELOCK_CLEAR_INACTIVE:
222 case wakelock_clear_t::WAKELOCK_CLEAR_SYSTEM:
224 if (--system_wakelock_count == 0)
226 std::cout <<
"Clearing system wakelock." << std::endl;
227 system_state_lock->request_release(media::power::SystemState::active);
230 case wakelock_clear_t::WAKELOCK_CLEAR_DISPLAY:
232 if (--display_wakelock_count == 0)
234 std::cout <<
"Clearing display wakelock." << std::endl;
235 display_state_lock->request_release(media::power::DisplayState::on);
238 case wakelock_clear_t::WAKELOCK_CLEAR_INVALID:
240 cerr <<
"Can't clear invalid wakelock type" << endl;
243 catch(
const std::exception& e)
245 std::cerr <<
"Warning: failed to clear power state: ";
246 std::cerr << e.what() << std::endl;
252 return (parent->is_video_source()) ?
253 wakelock_clear_t::WAKELOCK_CLEAR_DISPLAY : wakelock_clear_t::WAKELOCK_CLEAR_SYSTEM;
259 if (system_wakelock_count.load() > 0)
261 system_wakelock_count = 1;
262 clear_wakelock(wakelock_clear_t::WAKELOCK_CLEAR_SYSTEM);
264 if (display_wakelock_count.load() > 0)
266 display_wakelock_count = 1;
267 clear_wakelock(wakelock_clear_t::WAKELOCK_CLEAR_DISPLAY);
277 std::weak_ptr<Private> weak_self{this->shared_from_this()};
278 auto wakelock_type = current_wakelock_type();
279 return [weak_self, wakelock_type] {
280 if (
auto self = weak_self.lock())
281 self->clear_wakelock(wakelock_type);
292 const Track::UriType uri = track_list->query_uri_for_track(
id);
297 std::cout <<
"Calling d->engine->open_resource_for_uri() for first track added only: " 299 std::cout <<
"\twith a Track::Id: " <<
id << std::endl;
300 static const bool do_pipeline_reset =
false;
301 engine->open_resource_for_uri(uri, do_pipeline_reset);
307 bool has_previous = track_list->has_previous()
308 or parent->Parent::loop_status() != Player::LoopStatus::none;
309 bool has_next = track_list->has_next()
310 or parent->Parent::loop_status() != Player::LoopStatus::none;
311 auto n_tracks = track_list->tracks()->size();
312 bool has_tracks = (n_tracks > 0) ?
true :
false;
314 std::cout <<
"Updating MPRIS TrackList properties" 315 <<
"; Tracks: " << n_tracks
316 <<
", has_previous: " << has_previous
317 <<
", has_next: " << has_next << std::endl;
320 parent->can_play().set(has_tracks);
321 parent->can_pause().set(has_tracks);
322 parent->can_go_previous().set(has_previous);
323 parent->can_go_next().set(has_next);
346 template<
typename Parent>
349 d{std::make_shared<Private>(
this,
config)}
352 Parent::can_play().set(
false);
353 Parent::can_pause().set(
false);
354 Parent::can_seek().set(
true);
355 Parent::can_go_previous().set(
false);
356 Parent::can_go_next().set(
false);
357 Parent::is_video_source().set(
false);
358 Parent::is_audio_source().set(
false);
359 Parent::shuffle().set(
false);
360 Parent::playback_rate().set(1.f);
361 Parent::playback_status().set(Player::PlaybackStatus::null);
362 Parent::loop_status().set(Player::LoopStatus::none);
363 Parent::position().set(0);
364 Parent::duration().set(0);
365 Parent::audio_stream_role().set(Player::AudioStreamRole::multimedia);
366 d->engine->audio_stream_role().set(Player::AudioStreamRole::multimedia);
367 Parent::orientation().set(Player::Orientation::rotate0);
368 Parent::lifetime().set(Player::Lifetime::normal);
369 d->engine->lifetime().set(Player::Lifetime::normal);
373 std::function<uint64_t()> position_getter = [
this]()
375 return d->engine->position().get();
377 Parent::position().install(position_getter);
379 d->engine->position().changed().connect([
this](uint64_t position)
381 d->track_list->on_position_changed(position);
386 std::function<uint64_t()> duration_getter = [
this]()
388 return d->engine->duration().get();
390 Parent::duration().install(duration_getter);
392 std::function<bool()> video_type_getter = [
this]()
394 return d->engine->is_video_source().get();
396 Parent::is_video_source().install(video_type_getter);
398 std::function<bool()> audio_type_getter = [
this]()
400 return d->engine->is_audio_source().get();
402 Parent::is_audio_source().install(audio_type_getter);
404 std::function<bool()> can_go_next_getter = [
this]()
407 return d->
track_list->has_next() or Parent::loop_status() != Player::LoopStatus::none;
409 Parent::can_go_next().install(can_go_next_getter);
411 std::function<bool()> can_go_previous_getter = [
this]()
414 return d->track_list->has_previous() or Parent::loop_status() != Player::LoopStatus::none;
416 Parent::can_go_previous().install(can_go_previous_getter);
421 std::cout <<
"LoopStatus: " << loop_status << std::endl;
422 d->track_list->on_loop_status_changed(loop_status);
426 Parent::shuffle().changed().connect([
this](
bool shuffle)
428 d->track_list->on_shuffle_changed(shuffle);
435 d->engine->audio_stream_role().set(new_role);
442 Parent::orientation().set(o);
447 d->engine->lifetime().set(lifetime);
450 d->engine->about_to_finish_signal().connect([
this]()
452 if (d->doing_abandon)
458 d->doing_go_to_track.lock();
460 Parent::about_to_finish()();
465 const Track::UriType uri = d->track_list->query_uri_for_track(d->track_list->next());
466 if (prev_track_id != d->track_list->current() && !uri.empty())
468 std::cout <<
"Advancing to next track on playbin: " << uri << std::endl;
469 static const bool do_pipeline_reset =
false;
470 d->engine->open_resource_for_uri(uri, do_pipeline_reset);
473 d->doing_go_to_track.unlock();
476 d->engine->client_disconnected_signal().connect([
this]()
480 d->clear_wakelocks();
481 d->track_list->reset();
483 d->on_client_disconnected();
486 d->engine->seeked_to_signal().connect([
this](uint64_t value)
488 Parent::seeked_to()(value);
491 d->engine->end_of_stream_signal().connect([
this]()
493 Parent::end_of_stream()();
498 Parent::video_dimension_changed()(dimensions);
501 d->engine->error_signal().connect([
this](
const Player::Error& e)
506 d->track_list->on_end_of_tracklist().connect([
this]()
511 std::cout <<
"End of tracklist reached, stopping playback" << std::endl;
519 const bool locked = d->doing_go_to_track.try_lock();
528 const Track::UriType uri = d->track_list->query_uri_for_track(
id);
531 std::cout <<
"Setting next track on playbin (on_go_to_track signal): " << uri << std::endl;
532 std::cout <<
"\twith a Track::Id: " <<
id << std::endl;
533 static const bool do_pipeline_reset =
true;
534 d->engine->open_resource_for_uri(uri, do_pipeline_reset);
539 std::cout <<
"Restoring playing state in on_go_to_track()" << std::endl;
543 d->doing_go_to_track.unlock();
548 std::cout <<
"** Track was added, handling in PlayerImplementation" << std::endl;
549 if (d->track_list->tracks()->size() == 1)
550 d->open_first_track_from_tracklist(
id);
552 d->update_mpris_properties();
557 std::cout <<
"** Track was added, handling in PlayerImplementation" << std::endl;
561 if (tracks.size() >= 1 and d->track_list->tracks()->size() == tracks.size())
562 d->open_first_track_from_tracklist(tracks.front());
564 d->update_mpris_properties();
569 d->update_mpris_properties();
572 d->track_list->on_track_list_reset().connect([
this](
void)
574 d->update_mpris_properties();
579 d->update_mpris_properties();
582 d->track_list->on_track_list_replaced().connect(
585 d->update_mpris_properties();
590 std::weak_ptr<Private> wp{d};
592 d->config.client_death_observer->register_for_death_notifications_with_key(
config.key);
595 if (
auto sp = wp.lock())
597 if (sp->doing_abandon)
600 if (died != sp->config.key)
603 static const std::chrono::milliseconds timeout{1000};
606 if (
auto sp = wp.lock())
607 sp->on_client_died();
613 template<
typename Parent>
619 std::function<uint64_t()> position_getter = [
this]()
621 return static_cast<uint64_t
>(0);
623 Parent::position().install(position_getter);
625 std::function<uint64_t()> duration_getter = [
this]()
627 return static_cast<uint64_t
>(0);
629 Parent::duration().install(duration_getter);
631 std::function<bool()> video_type_getter = [
this]()
635 Parent::is_video_source().install(video_type_getter);
637 std::function<bool()> audio_type_getter = [
this]()
641 Parent::is_audio_source().install(audio_type_getter);
644 template<
typename Parent>
648 return std::string{};
651 template<
typename Parent>
654 d->config.client_death_observer->register_for_death_notifications_with_key(d->config.key);
657 template<
typename Parent>
661 d->doing_abandon =
true;
665 template<
typename Parent>
668 return d->track_list;
672 template<
typename Parent>
675 return d->config.key;
678 template<
typename Parent>
681 d->engine->create_video_sink(texture_id);
682 return media::video::Sink::Ptr{};
685 template<
typename Parent>
688 d->track_list->reset();
692 cout << __PRETTY_FUNCTION__ <<
": resetting current media" << endl;
696 static const bool do_pipeline_reset =
false;
697 const bool ret = d->engine->open_resource_for_uri(uri, do_pipeline_reset);
699 static const bool make_current =
false;
704 template<
typename Parent>
707 return d->engine->open_resource_for_uri(uri, headers);
710 template<
typename Parent>
713 d->track_list->next();
716 template<
typename Parent>
719 d->track_list->previous();
722 template<
typename Parent>
728 template<
typename Parent>
734 template<
typename Parent>
737 std::cout << __PRETTY_FUNCTION__ << std::endl;
741 template<
typename Parent>
744 d->engine->seek_to(ms);
747 template<
typename Parent>
750 return d->on_client_disconnected;
753 template<
typename Parent>
756 Parent::playback_status_changed()(status);