1 /* 2 * Copyright (C) 2017-2018 Team Kodi 3 * This file is part of Kodi - https://kodi.tv 4 * 5 * SPDX-License-Identifier: GPL-2.0-or-later 6 * See LICENSES/README.md for more information. 7 */ 8 9 #include "PVRGUIChannelNavigator.h" 10 11 #include "FileItem.h" 12 #include "GUIInfoManager.h" 13 #include "ServiceBroker.h" 14 #include "guilib/GUIComponent.h" 15 #include "pvr/PVRManager.h" 16 #include "pvr/PVRPlaybackState.h" 17 #include "pvr/channels/PVRChannelGroup.h" 18 #include "pvr/guilib/PVRGUIActions.h" 19 #include "settings/Settings.h" 20 #include "settings/SettingsComponent.h" 21 #include "threads/SingleLock.h" 22 #include "utils/Job.h" 23 #include "utils/JobManager.h" 24 #include "utils/XTimeUtils.h" 25 26 namespace 27 { 28 class CPVRChannelTimeoutJobBase : public CJob, public IJobCallback 29 { 30 public: 31 CPVRChannelTimeoutJobBase() = delete; CPVRChannelTimeoutJobBase(PVR::CPVRGUIChannelNavigator & channelNavigator,int iTimeout)32 CPVRChannelTimeoutJobBase(PVR::CPVRGUIChannelNavigator& channelNavigator, int iTimeout) 33 : m_channelNavigator(channelNavigator) 34 { 35 m_delayTimer.Set(iTimeout); 36 } 37 38 ~CPVRChannelTimeoutJobBase() override = default; 39 40 virtual void OnTimeout() = 0; 41 OnJobComplete(unsigned int iJobID,bool bSuccess,CJob * job)42 void OnJobComplete(unsigned int iJobID, bool bSuccess, CJob* job) override {} 43 DoWork()44 bool DoWork() override 45 { 46 while (!ShouldCancel(0, 0)) 47 { 48 if (m_delayTimer.IsTimePast()) 49 { 50 OnTimeout(); 51 return true; 52 } 53 KODI::TIME::Sleep(10); 54 } 55 return false; 56 } 57 58 protected: 59 PVR::CPVRGUIChannelNavigator& m_channelNavigator; 60 61 private: 62 XbmcThreads::EndTime m_delayTimer; 63 }; 64 65 class CPVRChannelEntryTimeoutJob : public CPVRChannelTimeoutJobBase 66 { 67 public: CPVRChannelEntryTimeoutJob(PVR::CPVRGUIChannelNavigator & channelNavigator,int iTimeout)68 CPVRChannelEntryTimeoutJob(PVR::CPVRGUIChannelNavigator& channelNavigator, int iTimeout) 69 : CPVRChannelTimeoutJobBase(channelNavigator, iTimeout) {} 70 ~CPVRChannelEntryTimeoutJob() override = default; GetType() const71 const char* GetType() const override { return "pvr-channel-entry-timeout-job"; } OnTimeout()72 void OnTimeout() override { m_channelNavigator.SwitchToCurrentChannel(); } 73 }; 74 75 class CPVRChannelInfoTimeoutJob : public CPVRChannelTimeoutJobBase 76 { 77 public: CPVRChannelInfoTimeoutJob(PVR::CPVRGUIChannelNavigator & channelNavigator,int iTimeout)78 CPVRChannelInfoTimeoutJob(PVR::CPVRGUIChannelNavigator& channelNavigator, int iTimeout) 79 : CPVRChannelTimeoutJobBase(channelNavigator, iTimeout) {} 80 ~CPVRChannelInfoTimeoutJob() override = default; GetType() const81 const char* GetType() const override { return "pvr-channel-info-timeout-job"; } OnTimeout()82 void OnTimeout() override { m_channelNavigator.HideInfo(); } 83 }; 84 } // unnamed namespace 85 86 namespace PVR 87 { SelectNextChannel(ChannelSwitchMode eSwitchMode)88 void CPVRGUIChannelNavigator::SelectNextChannel(ChannelSwitchMode eSwitchMode) 89 { 90 if (!CServiceBroker::GetGUI()->GetInfoManager().GetInfoProviders().GetPlayerInfoProvider().GetShowInfo() && eSwitchMode == ChannelSwitchMode::NO_SWITCH) 91 { 92 // show info for current channel on first next channel selection. 93 ShowInfo(false); 94 return; 95 } 96 97 const std::shared_ptr<CPVRChannel> nextChannel = GetNextOrPrevChannel(true); 98 if (nextChannel) 99 SelectChannel(nextChannel, eSwitchMode); 100 } 101 SelectPreviousChannel(ChannelSwitchMode eSwitchMode)102 void CPVRGUIChannelNavigator::SelectPreviousChannel(ChannelSwitchMode eSwitchMode) 103 { 104 if (!CServiceBroker::GetGUI()->GetInfoManager().GetInfoProviders().GetPlayerInfoProvider().GetShowInfo() && eSwitchMode == ChannelSwitchMode::NO_SWITCH) 105 { 106 // show info for current channel on first previous channel selection. 107 ShowInfo(false); 108 return; 109 } 110 111 const std::shared_ptr<CPVRChannel> prevChannel = GetNextOrPrevChannel(false); 112 if (prevChannel) 113 SelectChannel(prevChannel, eSwitchMode); 114 } 115 GetNextOrPrevChannel(bool bNext)116 std::shared_ptr<CPVRChannel> CPVRGUIChannelNavigator::GetNextOrPrevChannel(bool bNext) 117 { 118 const bool bPlayingRadio = CServiceBroker::GetPVRManager().PlaybackState()->IsPlayingRadio(); 119 const bool bPlayingTV = CServiceBroker::GetPVRManager().PlaybackState()->IsPlayingTV(); 120 121 if (bPlayingTV || bPlayingRadio) 122 { 123 const std::shared_ptr<CPVRChannelGroup> group = CServiceBroker::GetPVRManager().PlaybackState()->GetPlayingGroup(bPlayingRadio); 124 if (group) 125 { 126 CSingleLock lock(m_critSection); 127 return bNext ? group->GetNextChannel(m_currentChannel) : group->GetPreviousChannel(m_currentChannel); 128 } 129 } 130 return {}; 131 } 132 SelectChannel(const std::shared_ptr<CPVRChannel> & channel,ChannelSwitchMode eSwitchMode)133 void CPVRGUIChannelNavigator::SelectChannel(const std::shared_ptr<CPVRChannel>& channel, 134 ChannelSwitchMode eSwitchMode) 135 { 136 CServiceBroker::GetGUI()->GetInfoManager().SetCurrentItem(CFileItem(channel)); 137 138 CSingleLock lock(m_critSection); 139 m_currentChannel = channel; 140 ShowInfo(false); 141 142 if (IsPreview() && eSwitchMode == ChannelSwitchMode::INSTANT_OR_DELAYED_SWITCH) 143 { 144 int iTimeout = CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_PVRPLAYBACK_CHANNELENTRYTIMEOUT); 145 if (iTimeout > 0) 146 { 147 // delayed switch 148 if (m_iChannelEntryJobId >= 0) 149 CJobManager::GetInstance().CancelJob(m_iChannelEntryJobId); 150 151 CPVRChannelEntryTimeoutJob* job = new CPVRChannelEntryTimeoutJob(*this, iTimeout); 152 m_iChannelEntryJobId = CJobManager::GetInstance().AddJob(job, dynamic_cast<IJobCallback*>(job)); 153 } 154 else 155 { 156 // instant switch 157 SwitchToCurrentChannel(); 158 } 159 } 160 } 161 SwitchToCurrentChannel()162 void CPVRGUIChannelNavigator::SwitchToCurrentChannel() 163 { 164 CFileItemPtr item; 165 166 { 167 CSingleLock lock(m_critSection); 168 169 if (m_iChannelEntryJobId >= 0) 170 { 171 CJobManager::GetInstance().CancelJob(m_iChannelEntryJobId); 172 m_iChannelEntryJobId = -1; 173 } 174 175 item.reset(new CFileItem(m_currentChannel)); 176 } 177 178 if (item) 179 CServiceBroker::GetPVRManager().GUIActions()->SwitchToChannel(item, false); 180 } 181 IsPreview() const182 bool CPVRGUIChannelNavigator::IsPreview() const 183 { 184 CSingleLock lock(m_critSection); 185 return m_currentChannel != m_playingChannel; 186 } 187 IsPreviewAndShowInfo() const188 bool CPVRGUIChannelNavigator::IsPreviewAndShowInfo() const 189 { 190 return IsPreview() && CServiceBroker::GetGUI()->GetInfoManager().GetInfoProviders().GetPlayerInfoProvider().GetShowInfo(); 191 } 192 ShowInfo()193 void CPVRGUIChannelNavigator::ShowInfo() 194 { 195 ShowInfo(true); 196 } 197 ShowInfo(bool bForce)198 void CPVRGUIChannelNavigator::ShowInfo(bool bForce) 199 { 200 int iTimeout = CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_PVRMENU_DISPLAYCHANNELINFO); 201 202 if (bForce || iTimeout > 0) 203 { 204 CServiceBroker::GetGUI()->GetInfoManager().GetInfoProviders().GetPlayerInfoProvider().SetShowInfo(true); 205 206 CSingleLock lock(m_critSection); 207 208 if (m_iChannelInfoJobId >= 0) 209 { 210 CJobManager::GetInstance().CancelJob(m_iChannelInfoJobId); 211 m_iChannelInfoJobId = -1; 212 } 213 214 if (!bForce && iTimeout > 0) 215 { 216 CPVRChannelInfoTimeoutJob* job = new CPVRChannelInfoTimeoutJob(*this, iTimeout * 1000); 217 m_iChannelInfoJobId = CJobManager::GetInstance().AddJob(job, dynamic_cast<IJobCallback*>(job)); 218 } 219 } 220 } 221 HideInfo()222 void CPVRGUIChannelNavigator::HideInfo() 223 { 224 CServiceBroker::GetGUI()->GetInfoManager().GetInfoProviders().GetPlayerInfoProvider().SetShowInfo(false); 225 226 CFileItemPtr item; 227 228 { 229 CSingleLock lock(m_critSection); 230 231 if (m_iChannelInfoJobId >= 0) 232 { 233 CJobManager::GetInstance().CancelJob(m_iChannelInfoJobId); 234 m_iChannelInfoJobId = -1; 235 } 236 237 if (m_currentChannel != m_playingChannel) 238 { 239 m_currentChannel = m_playingChannel; 240 if (m_playingChannel) 241 item.reset(new CFileItem(m_playingChannel)); 242 } 243 } 244 245 if (item) 246 CServiceBroker::GetGUI()->GetInfoManager().SetCurrentItem(*item); 247 } 248 ToggleInfo()249 void CPVRGUIChannelNavigator::ToggleInfo() 250 { 251 if (CServiceBroker::GetGUI()->GetInfoManager().GetInfoProviders().GetPlayerInfoProvider().GetShowInfo()) 252 HideInfo(); 253 else 254 ShowInfo(); 255 } 256 SetPlayingChannel(const std::shared_ptr<CPVRChannel> & channel)257 void CPVRGUIChannelNavigator::SetPlayingChannel(const std::shared_ptr<CPVRChannel>& channel) 258 { 259 CFileItemPtr item; 260 261 if (channel) 262 { 263 CSingleLock lock(m_critSection); 264 265 m_playingChannel = channel; 266 if (m_currentChannel != m_playingChannel) 267 { 268 m_currentChannel = m_playingChannel; 269 if (m_playingChannel) 270 item.reset(new CFileItem(m_playingChannel)); 271 } 272 } 273 274 if (item) 275 CServiceBroker::GetGUI()->GetInfoManager().SetCurrentItem(*item); 276 277 ShowInfo(false); 278 } 279 ClearPlayingChannel()280 void CPVRGUIChannelNavigator::ClearPlayingChannel() 281 { 282 CSingleLock lock(m_critSection); 283 m_playingChannel.reset(); 284 HideInfo(); 285 } 286 287 } // namespace PVR 288