diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 18:07:22 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 18:07:22 +0000 |
commit | c04dcc2e7d834218ef2d4194331e383402495ae1 (patch) | |
tree | 7333e38d10d75386e60f336b80c2443c1166031d /xbmc/pvr/guilib/PVRGUIChannelNavigator.cpp | |
parent | Initial commit. (diff) | |
download | kodi-c04dcc2e7d834218ef2d4194331e383402495ae1.tar.xz kodi-c04dcc2e7d834218ef2d4194331e383402495ae1.zip |
Adding upstream version 2:20.4+dfsg.upstream/2%20.4+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'xbmc/pvr/guilib/PVRGUIChannelNavigator.cpp')
-rw-r--r-- | xbmc/pvr/guilib/PVRGUIChannelNavigator.cpp | 373 |
1 files changed, 373 insertions, 0 deletions
diff --git a/xbmc/pvr/guilib/PVRGUIChannelNavigator.cpp b/xbmc/pvr/guilib/PVRGUIChannelNavigator.cpp new file mode 100644 index 0000000..0ccfdf8 --- /dev/null +++ b/xbmc/pvr/guilib/PVRGUIChannelNavigator.cpp @@ -0,0 +1,373 @@ +/* + * Copyright (C) 2017-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "PVRGUIChannelNavigator.h" + +#include "FileItem.h" +#include "GUIInfoManager.h" +#include "ServiceBroker.h" +#include "guilib/GUIComponent.h" +#include "pvr/PVRManager.h" +#include "pvr/PVRPlaybackState.h" +#include "pvr/channels/PVRChannelGroup.h" +#include "pvr/guilib/PVRGUIActionsPlayback.h" +#include "settings/Settings.h" +#include "settings/SettingsComponent.h" +#include "threads/SystemClock.h" +#include "utils/Job.h" +#include "utils/JobManager.h" +#include "utils/XTimeUtils.h" + +#include <mutex> + +using namespace KODI::GUILIB::GUIINFO; +using namespace PVR; +using namespace std::chrono_literals; + +namespace +{ +class CPVRChannelTimeoutJobBase : public CJob, public IJobCallback +{ +public: + CPVRChannelTimeoutJobBase() = delete; + CPVRChannelTimeoutJobBase(PVR::CPVRGUIChannelNavigator& channelNavigator, + std::chrono::milliseconds timeout) + : m_channelNavigator(channelNavigator) + { + m_delayTimer.Set(timeout); + } + + ~CPVRChannelTimeoutJobBase() override = default; + + virtual void OnTimeout() = 0; + + void OnJobComplete(unsigned int iJobID, bool bSuccess, CJob* job) override {} + + bool DoWork() override + { + while (!ShouldCancel(0, 0)) + { + if (m_delayTimer.IsTimePast()) + { + OnTimeout(); + return true; + } + KODI::TIME::Sleep(10ms); + } + return false; + } + +protected: + PVR::CPVRGUIChannelNavigator& m_channelNavigator; + +private: + XbmcThreads::EndTime<> m_delayTimer; +}; + +class CPVRChannelEntryTimeoutJob : public CPVRChannelTimeoutJobBase +{ +public: + CPVRChannelEntryTimeoutJob(PVR::CPVRGUIChannelNavigator& channelNavigator, + std::chrono::milliseconds timeout) + : CPVRChannelTimeoutJobBase(channelNavigator, timeout) + { + } + ~CPVRChannelEntryTimeoutJob() override = default; + const char* GetType() const override { return "pvr-channel-entry-timeout-job"; } + void OnTimeout() override { m_channelNavigator.SwitchToCurrentChannel(); } +}; + +class CPVRChannelInfoTimeoutJob : public CPVRChannelTimeoutJobBase +{ +public: + CPVRChannelInfoTimeoutJob(PVR::CPVRGUIChannelNavigator& channelNavigator, + std::chrono::milliseconds timeout) + : CPVRChannelTimeoutJobBase(channelNavigator, timeout) + { + } + ~CPVRChannelInfoTimeoutJob() override = default; + const char* GetType() const override { return "pvr-channel-info-timeout-job"; } + void OnTimeout() override { m_channelNavigator.HideInfo(); } +}; +} // unnamed namespace + +CPVRGUIChannelNavigator::CPVRGUIChannelNavigator() +{ + // Note: we cannot subscribe to PlayerInfoProvider here, as we're getting constructed + // before the info providers. We will subscribe once our first subscriber appears. +} + +CPVRGUIChannelNavigator::~CPVRGUIChannelNavigator() +{ + const auto gui = CServiceBroker::GetGUI(); + if (!gui) + return; + + gui->GetInfoManager().GetInfoProviders().GetPlayerInfoProvider().Events().Unsubscribe(this); +} + +void CPVRGUIChannelNavigator::SubscribeToShowInfoEventStream() +{ + CServiceBroker::GetGUI() + ->GetInfoManager() + .GetInfoProviders() + .GetPlayerInfoProvider() + .Events() + .Subscribe(this, &CPVRGUIChannelNavigator::Notify); +} + +void CPVRGUIChannelNavigator::CheckAndPublishPreviewAndPlayerShowInfoChangedEvent() +{ + std::unique_lock<CCriticalSection> lock(m_critSection); + + const bool currentValue = IsPreview() && m_playerShowInfo; + if (m_previewAndPlayerShowInfo != currentValue) + { + m_previewAndPlayerShowInfo = currentValue; + + // inform subscribers + m_events.Publish(PVRPreviewAndPlayerShowInfoChangedEvent(currentValue)); + } +} + +void CPVRGUIChannelNavigator::Notify(const PlayerShowInfoChangedEvent& event) +{ + std::unique_lock<CCriticalSection> lock(m_critSection); + + m_playerShowInfo = event.m_showInfo; + CheckAndPublishPreviewAndPlayerShowInfoChangedEvent(); +} + +void CPVRGUIChannelNavigator::SelectNextChannel(ChannelSwitchMode eSwitchMode) +{ + std::unique_lock<CCriticalSection> lock(m_critSection); + + if (!m_playerShowInfo && eSwitchMode == ChannelSwitchMode::NO_SWITCH) + { + // show info for current channel on first next channel selection. + ShowInfo(false); + return; + } + + const std::shared_ptr<CPVRChannelGroupMember> nextMember = GetNextOrPrevChannel(true); + if (nextMember) + SelectChannel(nextMember, eSwitchMode); +} + +void CPVRGUIChannelNavigator::SelectPreviousChannel(ChannelSwitchMode eSwitchMode) +{ + std::unique_lock<CCriticalSection> lock(m_critSection); + + if (!m_playerShowInfo && eSwitchMode == ChannelSwitchMode::NO_SWITCH) + { + // show info for current channel on first previous channel selection. + ShowInfo(false); + return; + } + + const std::shared_ptr<CPVRChannelGroupMember> prevMember = GetNextOrPrevChannel(false); + if (prevMember) + SelectChannel(prevMember, eSwitchMode); +} + +std::shared_ptr<CPVRChannelGroupMember> CPVRGUIChannelNavigator::GetNextOrPrevChannel(bool bNext) +{ + const bool bPlayingRadio = CServiceBroker::GetPVRManager().PlaybackState()->IsPlayingRadio(); + const bool bPlayingTV = CServiceBroker::GetPVRManager().PlaybackState()->IsPlayingTV(); + + if (bPlayingTV || bPlayingRadio) + { + const std::shared_ptr<CPVRChannelGroup> group = + CServiceBroker::GetPVRManager().PlaybackState()->GetActiveChannelGroup(bPlayingRadio); + if (group) + { + std::unique_lock<CCriticalSection> lock(m_critSection); + return bNext ? group->GetNextChannelGroupMember(m_currentChannel) + : group->GetPreviousChannelGroupMember(m_currentChannel); + } + } + return {}; +} + +void CPVRGUIChannelNavigator::SelectChannel( + const std::shared_ptr<CPVRChannelGroupMember>& groupMember, ChannelSwitchMode eSwitchMode) +{ + CServiceBroker::GetGUI()->GetInfoManager().SetCurrentItem(CFileItem(groupMember)); + + std::unique_lock<CCriticalSection> lock(m_critSection); + + m_currentChannel = groupMember; + ShowInfo(false); + + CheckAndPublishPreviewAndPlayerShowInfoChangedEvent(); + + if (IsPreview() && eSwitchMode == ChannelSwitchMode::INSTANT_OR_DELAYED_SWITCH) + { + auto timeout = + std::chrono::milliseconds(CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt( + CSettings::SETTING_PVRPLAYBACK_CHANNELENTRYTIMEOUT)); + if (timeout > 0ms) + { + // delayed switch + if (m_iChannelEntryJobId >= 0) + CServiceBroker::GetJobManager()->CancelJob(m_iChannelEntryJobId); + + CPVRChannelEntryTimeoutJob* job = new CPVRChannelEntryTimeoutJob(*this, timeout); + m_iChannelEntryJobId = + CServiceBroker::GetJobManager()->AddJob(job, dynamic_cast<IJobCallback*>(job)); + } + else + { + // instant switch + SwitchToCurrentChannel(); + } + } +} + +void CPVRGUIChannelNavigator::SwitchToCurrentChannel() +{ + std::unique_ptr<CFileItem> item; + + { + std::unique_lock<CCriticalSection> lock(m_critSection); + + if (m_iChannelEntryJobId >= 0) + { + CServiceBroker::GetJobManager()->CancelJob(m_iChannelEntryJobId); + m_iChannelEntryJobId = -1; + } + + item = std::make_unique<CFileItem>(m_currentChannel); + } + + if (item) + CServiceBroker::GetPVRManager().Get<PVR::GUI::Playback>().SwitchToChannel(*item, false); +} + +bool CPVRGUIChannelNavigator::IsPreview() const +{ + std::unique_lock<CCriticalSection> lock(m_critSection); + return m_currentChannel != m_playingChannel; +} + +bool CPVRGUIChannelNavigator::IsPreviewAndShowInfo() const +{ + std::unique_lock<CCriticalSection> lock(m_critSection); + return m_previewAndPlayerShowInfo; +} + +void CPVRGUIChannelNavigator::ShowInfo() +{ + ShowInfo(true); +} + +void CPVRGUIChannelNavigator::ShowInfo(bool bForce) +{ + auto timeout = std::chrono::seconds(CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt( + CSettings::SETTING_PVRMENU_DISPLAYCHANNELINFO)); + + if (bForce || timeout > 0s) + { + CServiceBroker::GetGUI() + ->GetInfoManager() + .GetInfoProviders() + .GetPlayerInfoProvider() + .SetShowInfo(true); + + std::unique_lock<CCriticalSection> lock(m_critSection); + + if (m_iChannelInfoJobId >= 0) + { + CServiceBroker::GetJobManager()->CancelJob(m_iChannelInfoJobId); + m_iChannelInfoJobId = -1; + } + + if (!bForce && timeout > 0s) + { + CPVRChannelInfoTimeoutJob* job = new CPVRChannelInfoTimeoutJob(*this, timeout); + m_iChannelInfoJobId = + CServiceBroker::GetJobManager()->AddJob(job, dynamic_cast<IJobCallback*>(job)); + } + } +} + +void CPVRGUIChannelNavigator::HideInfo() +{ + CServiceBroker::GetGUI()->GetInfoManager().GetInfoProviders().GetPlayerInfoProvider().SetShowInfo( + false); + + CFileItemPtr item; + + { + std::unique_lock<CCriticalSection> lock(m_critSection); + + if (m_iChannelInfoJobId >= 0) + { + CServiceBroker::GetJobManager()->CancelJob(m_iChannelInfoJobId); + m_iChannelInfoJobId = -1; + } + + if (m_currentChannel != m_playingChannel) + { + m_currentChannel = m_playingChannel; + if (m_playingChannel) + item.reset(new CFileItem(m_playingChannel)); + } + + CheckAndPublishPreviewAndPlayerShowInfoChangedEvent(); + } + + if (item) + CServiceBroker::GetGUI()->GetInfoManager().SetCurrentItem(*item); +} + +void CPVRGUIChannelNavigator::ToggleInfo() +{ + std::unique_lock<CCriticalSection> lock(m_critSection); + + if (m_playerShowInfo) + HideInfo(); + else + ShowInfo(); +} + +void CPVRGUIChannelNavigator::SetPlayingChannel( + const std::shared_ptr<CPVRChannelGroupMember>& groupMember) +{ + CFileItemPtr item; + + if (groupMember) + { + std::unique_lock<CCriticalSection> lock(m_critSection); + + m_playingChannel = groupMember; + if (m_currentChannel != m_playingChannel) + { + m_currentChannel = m_playingChannel; + if (m_playingChannel) + item.reset(new CFileItem(m_playingChannel)); + } + + CheckAndPublishPreviewAndPlayerShowInfoChangedEvent(); + } + + if (item) + CServiceBroker::GetGUI()->GetInfoManager().SetCurrentItem(*item); + + ShowInfo(false); +} + +void CPVRGUIChannelNavigator::ClearPlayingChannel() +{ + std::unique_lock<CCriticalSection> lock(m_critSection); + + m_playingChannel.reset(); + HideInfo(); + + CheckAndPublishPreviewAndPlayerShowInfoChangedEvent(); +} |