2 * Copyright (C) 2017-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
9 #include "PVRGUIChannelNavigator.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/PVRGUIActionsPlayback.h"
19 #include "settings/Settings.h"
20 #include "settings/SettingsComponent.h"
21 #include "threads/SystemClock.h"
22 #include "utils/Job.h"
23 #include "utils/JobManager.h"
24 #include "utils/XTimeUtils.h"
29 using namespace KODI::GUILIB::GUIINFO
;
31 using namespace std::chrono_literals
;
35 class CPVRChannelTimeoutJobBase
: public CJob
, public IJobCallback
38 CPVRChannelTimeoutJobBase() = delete;
39 CPVRChannelTimeoutJobBase(PVR::CPVRGUIChannelNavigator
& channelNavigator
,
40 std::chrono::milliseconds timeout
)
41 : m_channelNavigator(channelNavigator
)
43 m_delayTimer
.Set(timeout
);
46 ~CPVRChannelTimeoutJobBase() override
= default;
48 virtual void OnTimeout() = 0;
50 void OnJobComplete(unsigned int iJobID
, bool bSuccess
, CJob
* job
) override
{}
52 bool DoWork() override
54 while (!ShouldCancel(0, 0))
56 if (m_delayTimer
.IsTimePast())
61 KODI::TIME::Sleep(10ms
);
67 PVR::CPVRGUIChannelNavigator
& m_channelNavigator
;
70 XbmcThreads::EndTime
<> m_delayTimer
;
73 class CPVRChannelEntryTimeoutJob
: public CPVRChannelTimeoutJobBase
76 CPVRChannelEntryTimeoutJob(PVR::CPVRGUIChannelNavigator
& channelNavigator
,
77 std::chrono::milliseconds timeout
)
78 : CPVRChannelTimeoutJobBase(channelNavigator
, timeout
)
81 ~CPVRChannelEntryTimeoutJob() override
= default;
82 const char* GetType() const override
{ return "pvr-channel-entry-timeout-job"; }
83 void OnTimeout() override
{ m_channelNavigator
.SwitchToCurrentChannel(); }
86 class CPVRChannelInfoTimeoutJob
: public CPVRChannelTimeoutJobBase
89 CPVRChannelInfoTimeoutJob(PVR::CPVRGUIChannelNavigator
& channelNavigator
,
90 std::chrono::milliseconds timeout
)
91 : CPVRChannelTimeoutJobBase(channelNavigator
, timeout
)
94 ~CPVRChannelInfoTimeoutJob() override
= default;
95 const char* GetType() const override
{ return "pvr-channel-info-timeout-job"; }
96 void OnTimeout() override
{ m_channelNavigator
.HideInfo(); }
98 } // unnamed namespace
100 CPVRGUIChannelNavigator::CPVRGUIChannelNavigator()
102 // Note: we cannot subscribe to PlayerInfoProvider here, as we're getting constructed
103 // before the info providers. We will subscribe once our first subscriber appears.
106 CPVRGUIChannelNavigator::~CPVRGUIChannelNavigator()
108 const auto gui
= CServiceBroker::GetGUI();
112 gui
->GetInfoManager().GetInfoProviders().GetPlayerInfoProvider().Events().Unsubscribe(this);
115 void CPVRGUIChannelNavigator::SubscribeToShowInfoEventStream()
117 CServiceBroker::GetGUI()
120 .GetPlayerInfoProvider()
122 .Subscribe(this, &CPVRGUIChannelNavigator::Notify
);
125 void CPVRGUIChannelNavigator::CheckAndPublishPreviewAndPlayerShowInfoChangedEvent()
127 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
129 const bool currentValue
= IsPreview() && m_playerShowInfo
;
130 if (m_previewAndPlayerShowInfo
!= currentValue
)
132 m_previewAndPlayerShowInfo
= currentValue
;
134 // inform subscribers
135 m_events
.Publish(PVRPreviewAndPlayerShowInfoChangedEvent(currentValue
));
139 void CPVRGUIChannelNavigator::Notify(const PlayerShowInfoChangedEvent
& event
)
141 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
143 m_playerShowInfo
= event
.m_showInfo
;
144 CheckAndPublishPreviewAndPlayerShowInfoChangedEvent();
147 void CPVRGUIChannelNavigator::SelectNextChannel(ChannelSwitchMode eSwitchMode
)
149 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
151 if (!m_playerShowInfo
&& eSwitchMode
== ChannelSwitchMode::NO_SWITCH
)
153 // show info for current channel on first next channel selection.
158 const std::shared_ptr
<CPVRChannelGroupMember
> nextMember
= GetNextOrPrevChannel(true);
160 SelectChannel(nextMember
, eSwitchMode
);
163 void CPVRGUIChannelNavigator::SelectPreviousChannel(ChannelSwitchMode eSwitchMode
)
165 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
167 if (!m_playerShowInfo
&& eSwitchMode
== ChannelSwitchMode::NO_SWITCH
)
169 // show info for current channel on first previous channel selection.
174 const std::shared_ptr
<CPVRChannelGroupMember
> prevMember
= GetNextOrPrevChannel(false);
176 SelectChannel(prevMember
, eSwitchMode
);
179 std::shared_ptr
<CPVRChannelGroupMember
> CPVRGUIChannelNavigator::GetNextOrPrevChannel(bool bNext
)
181 const bool bPlayingRadio
= CServiceBroker::GetPVRManager().PlaybackState()->IsPlayingRadio();
182 const bool bPlayingTV
= CServiceBroker::GetPVRManager().PlaybackState()->IsPlayingTV();
184 if (bPlayingTV
|| bPlayingRadio
)
186 const std::shared_ptr
<const CPVRChannelGroup
> group
=
187 CServiceBroker::GetPVRManager().PlaybackState()->GetActiveChannelGroup(bPlayingRadio
);
190 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
191 return bNext
? group
->GetNextChannelGroupMember(m_currentChannel
)
192 : group
->GetPreviousChannelGroupMember(m_currentChannel
);
198 void CPVRGUIChannelNavigator::SelectChannel(
199 const std::shared_ptr
<CPVRChannelGroupMember
>& groupMember
, ChannelSwitchMode eSwitchMode
)
201 CServiceBroker::GetGUI()->GetInfoManager().SetCurrentItem(CFileItem(groupMember
));
203 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
205 m_currentChannel
= groupMember
;
208 CheckAndPublishPreviewAndPlayerShowInfoChangedEvent();
210 if (IsPreview() && eSwitchMode
== ChannelSwitchMode::INSTANT_OR_DELAYED_SWITCH
)
213 std::chrono::milliseconds(CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(
214 CSettings::SETTING_PVRPLAYBACK_CHANNELENTRYTIMEOUT
));
218 if (m_iChannelEntryJobId
>= 0)
219 CServiceBroker::GetJobManager()->CancelJob(m_iChannelEntryJobId
);
221 CPVRChannelEntryTimeoutJob
* job
= new CPVRChannelEntryTimeoutJob(*this, timeout
);
222 m_iChannelEntryJobId
=
223 CServiceBroker::GetJobManager()->AddJob(job
, dynamic_cast<IJobCallback
*>(job
));
228 SwitchToCurrentChannel();
233 void CPVRGUIChannelNavigator::SwitchToCurrentChannel()
235 std::unique_ptr
<CFileItem
> item
;
238 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
240 if (m_iChannelEntryJobId
>= 0)
242 CServiceBroker::GetJobManager()->CancelJob(m_iChannelEntryJobId
);
243 m_iChannelEntryJobId
= -1;
246 item
= std::make_unique
<CFileItem
>(m_currentChannel
);
249 CServiceBroker::GetPVRManager().Get
<PVR::GUI::Playback
>().SwitchToChannel(*item
, false);
252 bool CPVRGUIChannelNavigator::IsPreview() const
254 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
255 return m_currentChannel
!= m_playingChannel
;
258 bool CPVRGUIChannelNavigator::IsPreviewAndShowInfo() const
260 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
261 return m_previewAndPlayerShowInfo
;
264 void CPVRGUIChannelNavigator::ShowInfo()
269 void CPVRGUIChannelNavigator::ShowInfo(bool bForce
)
271 auto timeout
= std::chrono::seconds(CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(
272 CSettings::SETTING_PVRMENU_DISPLAYCHANNELINFO
));
274 if (bForce
|| timeout
> 0s
)
276 CServiceBroker::GetGUI()
279 .GetPlayerInfoProvider()
282 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
284 if (m_iChannelInfoJobId
>= 0)
286 CServiceBroker::GetJobManager()->CancelJob(m_iChannelInfoJobId
);
287 m_iChannelInfoJobId
= -1;
290 if (!bForce
&& timeout
> 0s
)
292 CPVRChannelInfoTimeoutJob
* job
= new CPVRChannelInfoTimeoutJob(*this, timeout
);
293 m_iChannelInfoJobId
=
294 CServiceBroker::GetJobManager()->AddJob(job
, dynamic_cast<IJobCallback
*>(job
));
299 void CPVRGUIChannelNavigator::HideInfo()
301 CServiceBroker::GetGUI()->GetInfoManager().GetInfoProviders().GetPlayerInfoProvider().SetShowInfo(
307 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
309 if (m_iChannelInfoJobId
>= 0)
311 CServiceBroker::GetJobManager()->CancelJob(m_iChannelInfoJobId
);
312 m_iChannelInfoJobId
= -1;
315 if (m_currentChannel
!= m_playingChannel
)
317 m_currentChannel
= m_playingChannel
;
318 if (m_playingChannel
)
319 item
= std::make_shared
<CFileItem
>(m_playingChannel
);
322 CheckAndPublishPreviewAndPlayerShowInfoChangedEvent();
326 CServiceBroker::GetGUI()->GetInfoManager().SetCurrentItem(*item
);
329 void CPVRGUIChannelNavigator::ToggleInfo()
331 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
333 if (m_playerShowInfo
)
339 void CPVRGUIChannelNavigator::SetPlayingChannel(
340 const std::shared_ptr
<CPVRChannelGroupMember
>& groupMember
)
346 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
348 m_playingChannel
= groupMember
;
349 if (m_currentChannel
!= m_playingChannel
)
351 m_currentChannel
= m_playingChannel
;
352 if (m_playingChannel
)
353 item
= std::make_shared
<CFileItem
>(m_playingChannel
);
356 CheckAndPublishPreviewAndPlayerShowInfoChangedEvent();
360 CServiceBroker::GetGUI()->GetInfoManager().SetCurrentItem(*item
);
365 void CPVRGUIChannelNavigator::ClearPlayingChannel()
367 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
369 m_playingChannel
.reset();
372 CheckAndPublishPreviewAndPlayerShowInfoChangedEvent();