2 * Copyright (C) 2012-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 "PVRGUITimesInfo.h"
11 #include "ServiceBroker.h"
12 #include "cores/DataCacheCore.h"
13 #include "pvr/PVRManager.h"
14 #include "pvr/PVRPlaybackState.h"
15 #include "pvr/channels/PVRChannel.h"
16 #include "pvr/channels/PVRChannelGroupsContainer.h"
17 #include "pvr/epg/EpgInfoTag.h"
18 #include "pvr/recordings/PVRRecording.h"
19 #include "settings/AdvancedSettings.h"
20 #include "settings/SettingsComponent.h"
21 #include "utils/MathUtils.h"
22 #include "utils/StringUtils.h"
32 CPVRGUITimesInfo::CPVRGUITimesInfo()
37 void CPVRGUITimesInfo::Reset()
39 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
43 m_iTimeshiftStartTime
= 0;
44 m_iTimeshiftEndTime
= 0;
45 m_iTimeshiftPlayTime
= 0;
46 m_iTimeshiftOffset
= 0;
48 m_iTimeshiftProgressStartTime
= 0;
49 m_iTimeshiftProgressEndTime
= 0;
50 m_iTimeshiftProgressDuration
= 0;
52 m_playingEpgTag
.reset();
53 m_playingChannel
.reset();
56 void CPVRGUITimesInfo::UpdatePlayingTag()
58 const std::shared_ptr
<const CPVRChannel
> currentChannel
=
59 CServiceBroker::GetPVRManager().PlaybackState()->GetPlayingChannel();
60 std::shared_ptr
<CPVREpgInfoTag
> currentTag
= CServiceBroker::GetPVRManager().PlaybackState()->GetPlayingEpgTag();
62 if (currentChannel
|| currentTag
)
64 if (currentChannel
&& !currentTag
)
65 currentTag
= currentChannel
->GetEPGNow();
67 const std::shared_ptr
<const CPVRChannelGroupsContainer
> groups
=
68 CServiceBroker::GetPVRManager().ChannelGroups();
70 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
72 const std::shared_ptr
<const CPVRChannel
> playingChannel
=
73 m_playingEpgTag
? groups
->GetChannelForEpgTag(m_playingEpgTag
) : nullptr;
75 if (!m_playingEpgTag
|| !currentTag
|| !playingChannel
|| !currentChannel
||
76 m_playingEpgTag
->StartAsUTC() != currentTag
->StartAsUTC() ||
77 m_playingEpgTag
->EndAsUTC() != currentTag
->EndAsUTC() || *playingChannel
!= *currentChannel
)
81 m_playingEpgTag
= currentTag
;
82 m_iDuration
= m_playingEpgTag
->GetDuration();
84 else if (m_iTimeshiftEndTime
> m_iTimeshiftStartTime
)
86 m_playingEpgTag
.reset();
87 std::chrono::duration
<unsigned int> duration
{m_iTimeshiftEndTime
- m_iTimeshiftStartTime
};
88 m_iDuration
= duration
.count();
92 m_playingEpgTag
.reset();
99 const std::shared_ptr
<const CPVRRecording
> recording
=
100 CServiceBroker::GetPVRManager().PlaybackState()->GetPlayingRecording();
103 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
104 m_playingEpgTag
.reset();
105 m_iDuration
= recording
->GetDuration();
110 void CPVRGUITimesInfo::UpdateTimeshiftData()
112 if (!CServiceBroker::GetPVRManager().PlaybackState()->IsPlayingTV() && !CServiceBroker::GetPVRManager().PlaybackState()->IsPlayingRadio())
114 // If nothing is playing (anymore), there is no need to update data.
119 time_t now
= std::time(nullptr);
121 int64_t iPlayTime
, iMinTime
, iMaxTime
;
122 CServiceBroker::GetDataCacheCore().GetPlayTimes(iStartTime
, iPlayTime
, iMinTime
, iMaxTime
);
123 bool bPlaying
= CServiceBroker::GetDataCacheCore().GetSpeed() == 1.0f
;
124 const std::shared_ptr
<const CPVRChannel
> playingChannel
=
125 CServiceBroker::GetPVRManager().PlaybackState()->GetPlayingChannel();
127 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
129 if (playingChannel
!= m_playingChannel
)
131 // playing channel changed. we need to reset offset and playtime.
132 m_iTimeshiftOffset
= 0;
133 m_iTimeshiftPlayTime
= 0;
134 m_playingChannel
= playingChannel
;
139 if (m_iStartTime
== 0)
142 iStartTime
= m_iStartTime
;
144 iMinTime
= iPlayTime
;
145 iMaxTime
= iPlayTime
;
148 m_iStartTime
= iStartTime
;
149 m_iTimeshiftStartTime
= iStartTime
+ iMinTime
/ 1000;
150 m_iTimeshiftEndTime
= iStartTime
+ iMaxTime
/ 1000;
152 if (m_iTimeshiftEndTime
> m_iTimeshiftStartTime
)
154 // timeshifting supported
155 m_iTimeshiftPlayTime
= iStartTime
+ iPlayTime
/ 1000;
156 if (iMaxTime
> iPlayTime
)
157 m_iTimeshiftOffset
= (iMaxTime
- iPlayTime
) / 1000;
159 m_iTimeshiftOffset
= 0;
163 // timeshifting not supported
165 m_iTimeshiftPlayTime
= now
- m_iTimeshiftOffset
;
167 m_iTimeshiftOffset
= now
- m_iTimeshiftPlayTime
;
170 UpdateTimeshiftProgressData();
173 void CPVRGUITimesInfo::UpdateTimeshiftProgressData()
175 // Note: General idea of the ts progress is always to be able to visualise both the complete
176 // ts buffer and the complete playing epg event (if any) side by side with the same time
177 // scale. TS progress start and end times will be calculated accordingly.
178 // + Start is usually ts buffer start, except if start time of playing epg event is
179 // before ts buffer start, then progress start is epg event start.
180 // + End is usually ts buffer end, except if end time of playing epg event is
181 // after ts buffer end, then progress end is epg event end.
182 // In simple timeshift mode (settings value), progress start is always the start time of
183 // playing epg event and progress end is always the end time of playing epg event.
185 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
187 //////////////////////////////////////////////////////////////////////////////////////
189 //////////////////////////////////////////////////////////////////////////////////////
190 bool bUpdatedStartTime
= false;
194 m_playingEpgTag
->StartAsUTC().GetAsTime(start
);
195 if (start
< m_iTimeshiftStartTime
||
196 CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_bPVRTimeshiftSimpleOSD
)
198 // playing event started before start of ts buffer or simple ts osd to be used
199 m_iTimeshiftProgressStartTime
= start
;
200 bUpdatedStartTime
= true;
204 if (!bUpdatedStartTime
)
206 // default to ts buffer start
207 m_iTimeshiftProgressStartTime
= m_iTimeshiftStartTime
;
210 //////////////////////////////////////////////////////////////////////////////////////
212 //////////////////////////////////////////////////////////////////////////////////////
213 bool bUpdatedEndTime
= false;
217 m_playingEpgTag
->EndAsUTC().GetAsTime(end
);
218 if (end
> m_iTimeshiftEndTime
||
219 CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_bPVRTimeshiftSimpleOSD
)
221 // playing event will end after end of ts buffer or simple ts osd to be used
222 m_iTimeshiftProgressEndTime
= end
;
223 bUpdatedEndTime
= true;
227 if (!bUpdatedEndTime
)
229 // default to ts buffer end
230 m_iTimeshiftProgressEndTime
= m_iTimeshiftEndTime
;
233 //////////////////////////////////////////////////////////////////////////////////////
235 //////////////////////////////////////////////////////////////////////////////////////
236 std::chrono::duration
<unsigned int> duration
{m_iTimeshiftProgressEndTime
-
237 m_iTimeshiftProgressStartTime
};
238 m_iTimeshiftProgressDuration
= duration
.count();
241 void CPVRGUITimesInfo::Update()
244 UpdateTimeshiftData();
247 std::string
CPVRGUITimesInfo::TimeToTimeString(time_t datetime
, TIME_FORMAT format
, bool withSeconds
)
250 time
.SetFromUTCDateTime(datetime
);
251 return time
.GetAsLocalizedTime(format
, withSeconds
);
254 std::string
CPVRGUITimesInfo::GetTimeshiftStartTime(TIME_FORMAT format
) const
256 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
257 return TimeToTimeString(m_iTimeshiftStartTime
, format
, false);
260 std::string
CPVRGUITimesInfo::GetTimeshiftEndTime(TIME_FORMAT format
) const
262 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
263 return TimeToTimeString(m_iTimeshiftEndTime
, format
, false);
266 std::string
CPVRGUITimesInfo::GetTimeshiftPlayTime(TIME_FORMAT format
) const
268 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
269 return TimeToTimeString(m_iTimeshiftPlayTime
, format
, true);
272 std::string
CPVRGUITimesInfo::GetTimeshiftOffset(TIME_FORMAT format
) const
274 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
275 return StringUtils::SecondsToTimeString(m_iTimeshiftOffset
, format
);
278 std::string
CPVRGUITimesInfo::GetTimeshiftProgressDuration(TIME_FORMAT format
) const
280 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
281 return StringUtils::SecondsToTimeString(m_iTimeshiftProgressDuration
, format
);
284 std::string
CPVRGUITimesInfo::GetTimeshiftProgressStartTime(TIME_FORMAT format
) const
286 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
287 return TimeToTimeString(m_iTimeshiftProgressStartTime
, format
, false);
290 std::string
CPVRGUITimesInfo::GetTimeshiftProgressEndTime(TIME_FORMAT format
) const
292 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
293 return TimeToTimeString(m_iTimeshiftProgressEndTime
, format
, false);
296 std::string
CPVRGUITimesInfo::GetEpgEventDuration(
297 const std::shared_ptr
<const CPVREpgInfoTag
>& epgTag
, TIME_FORMAT format
) const
299 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
300 return StringUtils::SecondsToTimeString(GetEpgEventDuration(epgTag
), format
);
303 std::string
CPVRGUITimesInfo::GetEpgEventElapsedTime(
304 const std::shared_ptr
<const CPVREpgInfoTag
>& epgTag
, TIME_FORMAT format
) const
307 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
308 if (epgTag
&& m_playingEpgTag
&& *epgTag
!= *m_playingEpgTag
)
309 iElapsed
= epgTag
->Progress();
311 iElapsed
= GetElapsedTime();
313 return StringUtils::SecondsToTimeString(iElapsed
, format
);
316 std::string
CPVRGUITimesInfo::GetEpgEventRemainingTime(
317 const std::shared_ptr
<const CPVREpgInfoTag
>& epgTag
, TIME_FORMAT format
) const
319 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
320 return StringUtils::SecondsToTimeString(GetRemainingTime(epgTag
), format
);
323 std::string
CPVRGUITimesInfo::GetEpgEventFinishTime(
324 const std::shared_ptr
<const CPVREpgInfoTag
>& epgTag
, TIME_FORMAT format
) const
326 CDateTime finish
= CDateTime::GetCurrentDateTime();
327 finish
+= CDateTimeSpan(0, 0, 0, GetRemainingTime(epgTag
));
328 return finish
.GetAsLocalizedTime(format
);
331 std::string
CPVRGUITimesInfo::GetEpgEventSeekTime(int iSeekSize
, TIME_FORMAT format
) const
333 return StringUtils::SecondsToTimeString(GetElapsedTime() + iSeekSize
, format
);
336 int CPVRGUITimesInfo::GetElapsedTime() const
338 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
339 if (m_playingEpgTag
|| m_iTimeshiftStartTime
)
341 CDateTime
current(m_iTimeshiftPlayTime
);
342 CDateTime start
= m_playingEpgTag
? m_playingEpgTag
->StartAsUTC() : CDateTime(m_iTimeshiftStartTime
);
343 CDateTimeSpan time
= current
> start
? current
- start
: CDateTimeSpan(0, 0, 0, 0);
344 return time
.GetSecondsTotal();
352 int CPVRGUITimesInfo::GetRemainingTime(const std::shared_ptr
<const CPVREpgInfoTag
>& epgTag
) const
354 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
355 if (epgTag
&& m_playingEpgTag
&& *epgTag
!= *m_playingEpgTag
)
356 return epgTag
->GetDuration() - epgTag
->Progress();
358 return static_cast<int>(m_iDuration
- GetElapsedTime());
361 int CPVRGUITimesInfo::GetTimeshiftProgress() const
363 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
364 const std::chrono::duration
<double> total
{m_iTimeshiftEndTime
- m_iTimeshiftStartTime
};
367 const std::chrono::duration
<double> current
{m_iTimeshiftPlayTime
- m_iTimeshiftStartTime
};
368 return MathUtils::round_int(current
.count() / total
.count() * 100.0);
373 int CPVRGUITimesInfo::GetTimeshiftProgressDuration() const
375 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
376 return static_cast<int>(m_iTimeshiftProgressDuration
);
379 int CPVRGUITimesInfo::GetTimeshiftProgressPlayPosition() const
381 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
382 if (m_iTimeshiftProgressDuration
)
384 const std::chrono::duration
<double> duration
{m_iTimeshiftPlayTime
-
385 m_iTimeshiftProgressStartTime
};
386 return MathUtils::round_int(duration
.count() / m_iTimeshiftProgressDuration
* 100.0);
391 int CPVRGUITimesInfo::GetTimeshiftProgressEpgStart() const
393 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
394 if (m_playingEpgTag
&& m_iTimeshiftProgressDuration
)
397 m_playingEpgTag
->StartAsUTC().GetAsTime(epgStart
);
398 const std::chrono::duration
<double> duration
{epgStart
- m_iTimeshiftProgressStartTime
};
399 return MathUtils::round_int(duration
.count() / m_iTimeshiftProgressDuration
* 100.0);
404 int CPVRGUITimesInfo::GetTimeshiftProgressEpgEnd() const
406 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
407 if (m_playingEpgTag
&& m_iTimeshiftProgressDuration
)
410 m_playingEpgTag
->EndAsUTC().GetAsTime(epgEnd
);
411 const std::chrono::duration
<double> duration
{epgEnd
- m_iTimeshiftProgressStartTime
};
412 return MathUtils::round_int(duration
.count() / m_iTimeshiftProgressDuration
* 100.0);
417 int CPVRGUITimesInfo::GetTimeshiftProgressBufferStart() const
419 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
420 if (m_iTimeshiftProgressDuration
)
422 const std::chrono::duration
<double> duration
{m_iTimeshiftStartTime
-
423 m_iTimeshiftProgressStartTime
};
424 return MathUtils::round_int(duration
.count() / m_iTimeshiftProgressDuration
* 100.0);
429 int CPVRGUITimesInfo::GetTimeshiftProgressBufferEnd() const
431 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
432 if (m_iTimeshiftProgressDuration
)
434 const std::chrono::duration
<double> duration
{m_iTimeshiftEndTime
-
435 m_iTimeshiftProgressStartTime
};
436 return MathUtils::round_int(duration
.count() / m_iTimeshiftProgressDuration
* 100.0);
441 int CPVRGUITimesInfo::GetEpgEventDuration(const std::shared_ptr
<const CPVREpgInfoTag
>& epgTag
) const
443 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
444 if (epgTag
&& m_playingEpgTag
&& *epgTag
!= *m_playingEpgTag
)
445 return epgTag
->GetDuration();
447 return static_cast<int>(m_iDuration
);
450 int CPVRGUITimesInfo::GetEpgEventProgress(const std::shared_ptr
<const CPVREpgInfoTag
>& epgTag
) const
452 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
453 if (epgTag
&& m_playingEpgTag
&& *epgTag
!= *m_playingEpgTag
)
454 return MathUtils::round_int(epgTag
->ProgressPercentage());
455 else if (m_iDuration
)
456 return MathUtils::round_int(static_cast<double>(GetElapsedTime()) / m_iDuration
* 100.0);
461 bool CPVRGUITimesInfo::IsTimeshifting() const
463 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
464 return (m_iTimeshiftOffset
> static_cast<unsigned int>(CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_iPVRTimeshiftThreshold
));