summaryrefslogtreecommitdiffstats
path: root/xbmc/pvr/guilib/guiinfo/PVRGUITimesInfo.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'xbmc/pvr/guilib/guiinfo/PVRGUITimesInfo.cpp')
-rw-r--r--xbmc/pvr/guilib/guiinfo/PVRGUITimesInfo.cpp424
1 files changed, 424 insertions, 0 deletions
diff --git a/xbmc/pvr/guilib/guiinfo/PVRGUITimesInfo.cpp b/xbmc/pvr/guilib/guiinfo/PVRGUITimesInfo.cpp
new file mode 100644
index 0000000..e5dfdb9
--- /dev/null
+++ b/xbmc/pvr/guilib/guiinfo/PVRGUITimesInfo.cpp
@@ -0,0 +1,424 @@
+/*
+ * Copyright (C) 2012-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 "PVRGUITimesInfo.h"
+
+#include "ServiceBroker.h"
+#include "cores/DataCacheCore.h"
+#include "pvr/PVRManager.h"
+#include "pvr/PVRPlaybackState.h"
+#include "pvr/channels/PVRChannel.h"
+#include "pvr/channels/PVRChannelGroupsContainer.h"
+#include "pvr/epg/EpgInfoTag.h"
+#include "pvr/recordings/PVRRecording.h"
+#include "settings/AdvancedSettings.h"
+#include "settings/SettingsComponent.h"
+#include "utils/StringUtils.h"
+
+#include <cmath>
+#include <ctime>
+#include <memory>
+#include <mutex>
+
+using namespace PVR;
+
+CPVRGUITimesInfo::CPVRGUITimesInfo()
+{
+ Reset();
+}
+
+void CPVRGUITimesInfo::Reset()
+{
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+
+ m_iStartTime = 0;
+ m_iDuration = 0;
+ m_iTimeshiftStartTime = 0;
+ m_iTimeshiftEndTime = 0;
+ m_iTimeshiftPlayTime = 0;
+ m_iTimeshiftOffset = 0;
+
+ m_iTimeshiftProgressStartTime = 0;
+ m_iTimeshiftProgressEndTime = 0;
+ m_iTimeshiftProgressDuration = 0;
+
+ m_playingEpgTag.reset();
+ m_playingChannel.reset();
+}
+
+void CPVRGUITimesInfo::UpdatePlayingTag()
+{
+ const std::shared_ptr<CPVRChannel> currentChannel = CServiceBroker::GetPVRManager().PlaybackState()->GetPlayingChannel();
+ std::shared_ptr<CPVREpgInfoTag> currentTag = CServiceBroker::GetPVRManager().PlaybackState()->GetPlayingEpgTag();
+
+ if (currentChannel || currentTag)
+ {
+ if (currentChannel && !currentTag)
+ currentTag = currentChannel->GetEPGNow();
+
+ const std::shared_ptr<CPVRChannelGroupsContainer> groups = CServiceBroker::GetPVRManager().ChannelGroups();
+
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+
+ const std::shared_ptr<CPVRChannel> playingChannel =
+ m_playingEpgTag ? groups->GetChannelForEpgTag(m_playingEpgTag) : nullptr;
+
+ if (!m_playingEpgTag || !currentTag || !playingChannel || !currentChannel ||
+ m_playingEpgTag->StartAsUTC() != currentTag->StartAsUTC() ||
+ m_playingEpgTag->EndAsUTC() != currentTag->EndAsUTC() || *playingChannel != *currentChannel)
+ {
+ if (currentTag)
+ {
+ m_playingEpgTag = currentTag;
+ m_iDuration = m_playingEpgTag->GetDuration();
+ }
+ else if (m_iTimeshiftEndTime > m_iTimeshiftStartTime)
+ {
+ m_playingEpgTag.reset();
+ m_iDuration = m_iTimeshiftEndTime - m_iTimeshiftStartTime;
+ }
+ else
+ {
+ m_playingEpgTag.reset();
+ m_iDuration = 0;
+ }
+ }
+ }
+ else
+ {
+ const std::shared_ptr<CPVRRecording> recording = CServiceBroker::GetPVRManager().PlaybackState()->GetPlayingRecording();
+ if (recording)
+ {
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+ m_playingEpgTag.reset();
+ m_iDuration = recording->GetDuration();
+ }
+ }
+}
+
+void CPVRGUITimesInfo::UpdateTimeshiftData()
+{
+ if (!CServiceBroker::GetPVRManager().PlaybackState()->IsPlayingTV() && !CServiceBroker::GetPVRManager().PlaybackState()->IsPlayingRadio())
+ {
+ // If nothing is playing (anymore), there is no need to update data.
+ Reset();
+ return;
+ }
+
+ time_t now = std::time(nullptr);
+ time_t iStartTime;
+ int64_t iPlayTime, iMinTime, iMaxTime;
+ CServiceBroker::GetDataCacheCore().GetPlayTimes(iStartTime, iPlayTime, iMinTime, iMaxTime);
+ bool bPlaying = CServiceBroker::GetDataCacheCore().GetSpeed() == 1.0f;
+ const std::shared_ptr<CPVRChannel> playingChannel = CServiceBroker::GetPVRManager().PlaybackState()->GetPlayingChannel();
+
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+
+ if (playingChannel != m_playingChannel)
+ {
+ // playing channel changed. we need to reset offset and playtime.
+ m_iTimeshiftOffset = 0;
+ m_iTimeshiftPlayTime = 0;
+ m_playingChannel = playingChannel;
+ }
+
+ if (!iStartTime)
+ {
+ if (m_iStartTime == 0)
+ iStartTime = now;
+ else
+ iStartTime = m_iStartTime;
+
+ iMinTime = iPlayTime;
+ iMaxTime = iPlayTime;
+ }
+
+ m_iStartTime = iStartTime;
+ m_iTimeshiftStartTime = iStartTime + iMinTime / 1000;
+ m_iTimeshiftEndTime = iStartTime + iMaxTime / 1000;
+
+ if (m_iTimeshiftEndTime > m_iTimeshiftStartTime)
+ {
+ // timeshifting supported
+ m_iTimeshiftPlayTime = iStartTime + iPlayTime / 1000;
+ if (iMaxTime > iPlayTime)
+ m_iTimeshiftOffset = (iMaxTime - iPlayTime) / 1000;
+ else
+ m_iTimeshiftOffset = 0;
+ }
+ else
+ {
+ // timeshifting not supported
+ if (bPlaying)
+ m_iTimeshiftPlayTime = now - m_iTimeshiftOffset;
+
+ m_iTimeshiftOffset = now - m_iTimeshiftPlayTime;
+ }
+
+ UpdateTimeshiftProgressData();
+}
+
+void CPVRGUITimesInfo::UpdateTimeshiftProgressData()
+{
+ // Note: General idea of the ts progress is always to be able to visualise both the complete
+ // ts buffer and the complete playing epg event (if any) side by side with the same time
+ // scale. TS progress start and end times will be calculated accordingly.
+ // + Start is usually ts buffer start, except if start time of playing epg event is
+ // before ts buffer start, then progress start is epg event start.
+ // + End is usually ts buffer end, except if end time of playing epg event is
+ // after ts buffer end, then progress end is epg event end.
+ // In simple timeshift mode (settings value), progress start is always the start time of
+ // playing epg event and progress end is always the end time of playing epg event.
+
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // start time
+ //////////////////////////////////////////////////////////////////////////////////////
+ bool bUpdatedStartTime = false;
+ if (m_playingEpgTag)
+ {
+ time_t start = 0;
+ m_playingEpgTag->StartAsUTC().GetAsTime(start);
+ if (start < m_iTimeshiftStartTime ||
+ CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_bPVRTimeshiftSimpleOSD)
+ {
+ // playing event started before start of ts buffer or simple ts osd to be used
+ m_iTimeshiftProgressStartTime = start;
+ bUpdatedStartTime = true;
+ }
+ }
+
+ if (!bUpdatedStartTime)
+ {
+ // default to ts buffer start
+ m_iTimeshiftProgressStartTime = m_iTimeshiftStartTime;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // end time
+ //////////////////////////////////////////////////////////////////////////////////////
+ bool bUpdatedEndTime = false;
+ if (m_playingEpgTag)
+ {
+ time_t end = 0;
+ m_playingEpgTag->EndAsUTC().GetAsTime(end);
+ if (end > m_iTimeshiftEndTime ||
+ CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_bPVRTimeshiftSimpleOSD)
+ {
+ // playing event will end after end of ts buffer or simple ts osd to be used
+ m_iTimeshiftProgressEndTime = end;
+ bUpdatedEndTime = true;
+ }
+ }
+
+ if (!bUpdatedEndTime)
+ {
+ // default to ts buffer end
+ m_iTimeshiftProgressEndTime = m_iTimeshiftEndTime;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // duration
+ //////////////////////////////////////////////////////////////////////////////////////
+ m_iTimeshiftProgressDuration = m_iTimeshiftProgressEndTime - m_iTimeshiftProgressStartTime;
+}
+
+void CPVRGUITimesInfo::Update()
+{
+ UpdatePlayingTag();
+ UpdateTimeshiftData();
+}
+
+std::string CPVRGUITimesInfo::TimeToTimeString(time_t datetime, TIME_FORMAT format, bool withSeconds)
+{
+ CDateTime time;
+ time.SetFromUTCDateTime(datetime);
+ return time.GetAsLocalizedTime(format, withSeconds);
+}
+
+std::string CPVRGUITimesInfo::GetTimeshiftStartTime(TIME_FORMAT format) const
+{
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+ return TimeToTimeString(m_iTimeshiftStartTime, format, false);
+}
+
+std::string CPVRGUITimesInfo::GetTimeshiftEndTime(TIME_FORMAT format) const
+{
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+ return TimeToTimeString(m_iTimeshiftEndTime, format, false);
+}
+
+std::string CPVRGUITimesInfo::GetTimeshiftPlayTime(TIME_FORMAT format) const
+{
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+ return TimeToTimeString(m_iTimeshiftPlayTime, format, true);
+}
+
+std::string CPVRGUITimesInfo::GetTimeshiftOffset(TIME_FORMAT format) const
+{
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+ return StringUtils::SecondsToTimeString(m_iTimeshiftOffset, format);
+}
+
+std::string CPVRGUITimesInfo::GetTimeshiftProgressDuration(TIME_FORMAT format) const
+{
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+ return StringUtils::SecondsToTimeString(m_iTimeshiftProgressDuration, format);
+}
+
+std::string CPVRGUITimesInfo::GetTimeshiftProgressStartTime(TIME_FORMAT format) const
+{
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+ return TimeToTimeString(m_iTimeshiftProgressStartTime, format, false);
+}
+
+std::string CPVRGUITimesInfo::GetTimeshiftProgressEndTime(TIME_FORMAT format) const
+{
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+ return TimeToTimeString(m_iTimeshiftProgressEndTime, format, false);
+}
+
+std::string CPVRGUITimesInfo::GetEpgEventDuration(const std::shared_ptr<CPVREpgInfoTag>& epgTag, TIME_FORMAT format) const
+{
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+ return StringUtils::SecondsToTimeString(GetEpgEventDuration(epgTag), format);
+}
+
+std::string CPVRGUITimesInfo::GetEpgEventElapsedTime(const std::shared_ptr<CPVREpgInfoTag>& epgTag, TIME_FORMAT format) const
+{
+ int iElapsed = 0;
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+ if (epgTag && m_playingEpgTag && *epgTag != *m_playingEpgTag)
+ iElapsed = epgTag->Progress();
+ else
+ iElapsed = GetElapsedTime();
+
+ return StringUtils::SecondsToTimeString(iElapsed, format);
+}
+
+std::string CPVRGUITimesInfo::GetEpgEventRemainingTime(const std::shared_ptr<CPVREpgInfoTag>& epgTag, TIME_FORMAT format) const
+{
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+ return StringUtils::SecondsToTimeString(GetRemainingTime(epgTag), format);
+}
+
+std::string CPVRGUITimesInfo::GetEpgEventFinishTime(const std::shared_ptr<CPVREpgInfoTag>& epgTag, TIME_FORMAT format) const
+{
+ CDateTime finish = CDateTime::GetCurrentDateTime();
+ finish += CDateTimeSpan(0, 0, 0, GetRemainingTime(epgTag));
+ return finish.GetAsLocalizedTime(format);
+}
+
+std::string CPVRGUITimesInfo::GetEpgEventSeekTime(int iSeekSize, TIME_FORMAT format) const
+{
+ return StringUtils::SecondsToTimeString(GetElapsedTime() + iSeekSize, format);
+}
+
+int CPVRGUITimesInfo::GetElapsedTime() const
+{
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+ if (m_playingEpgTag || m_iTimeshiftStartTime)
+ {
+ CDateTime current(m_iTimeshiftPlayTime);
+ CDateTime start = m_playingEpgTag ? m_playingEpgTag->StartAsUTC() : CDateTime(m_iTimeshiftStartTime);
+ CDateTimeSpan time = current > start ? current - start : CDateTimeSpan(0, 0, 0, 0);
+ return time.GetSecondsTotal();
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+int CPVRGUITimesInfo::GetRemainingTime(const std::shared_ptr<CPVREpgInfoTag>& epgTag) const
+{
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+ if (epgTag && m_playingEpgTag && *epgTag != *m_playingEpgTag)
+ return epgTag->GetDuration() - epgTag->Progress();
+ else
+ return m_iDuration - GetElapsedTime();
+}
+
+int CPVRGUITimesInfo::GetTimeshiftProgress() const
+{
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+ return std::lrintf(static_cast<float>(m_iTimeshiftPlayTime - m_iTimeshiftStartTime) / (m_iTimeshiftEndTime - m_iTimeshiftStartTime) * 100);
+}
+
+int CPVRGUITimesInfo::GetTimeshiftProgressDuration() const
+{
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+ return m_iTimeshiftProgressDuration;
+}
+
+int CPVRGUITimesInfo::GetTimeshiftProgressPlayPosition() const
+{
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+ return std::lrintf(static_cast<float>(m_iTimeshiftPlayTime - m_iTimeshiftProgressStartTime) / m_iTimeshiftProgressDuration * 100);
+}
+
+int CPVRGUITimesInfo::GetTimeshiftProgressEpgStart() const
+{
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+ if (m_playingEpgTag)
+ {
+ time_t epgStart = 0;
+ m_playingEpgTag->StartAsUTC().GetAsTime(epgStart);
+ return std::lrintf(static_cast<float>(epgStart - m_iTimeshiftProgressStartTime) / m_iTimeshiftProgressDuration * 100);
+ }
+ return 0;
+}
+
+int CPVRGUITimesInfo::GetTimeshiftProgressEpgEnd() const
+{
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+ if (m_playingEpgTag)
+ {
+ time_t epgEnd = 0;
+ m_playingEpgTag->EndAsUTC().GetAsTime(epgEnd);
+ return std::lrintf(static_cast<float>(epgEnd - m_iTimeshiftProgressStartTime) / m_iTimeshiftProgressDuration * 100);
+ }
+ return 0;
+}
+
+int CPVRGUITimesInfo::GetTimeshiftProgressBufferStart() const
+{
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+ return std::lrintf(static_cast<float>(m_iTimeshiftStartTime - m_iTimeshiftProgressStartTime) / m_iTimeshiftProgressDuration * 100);
+}
+
+int CPVRGUITimesInfo::GetTimeshiftProgressBufferEnd() const
+{
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+ return std::lrintf(static_cast<float>(m_iTimeshiftEndTime - m_iTimeshiftProgressStartTime) / m_iTimeshiftProgressDuration * 100);
+}
+
+int CPVRGUITimesInfo::GetEpgEventDuration(const std::shared_ptr<CPVREpgInfoTag>& epgTag) const
+{
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+ if (epgTag && m_playingEpgTag && *epgTag != *m_playingEpgTag)
+ return epgTag->GetDuration();
+ else
+ return m_iDuration;
+}
+
+int CPVRGUITimesInfo::GetEpgEventProgress(const std::shared_ptr<CPVREpgInfoTag>& epgTag) const
+{
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+ if (epgTag && m_playingEpgTag && *epgTag != *m_playingEpgTag)
+ return std::lrintf(epgTag->ProgressPercentage());
+ else
+ return std::lrintf(static_cast<float>(GetElapsedTime()) / m_iDuration * 100);
+}
+
+bool CPVRGUITimesInfo::IsTimeshifting() const
+{
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+ return (m_iTimeshiftOffset > static_cast<unsigned int>(CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_iPVRTimeshiftThreshold));
+}