[Windows] Fix driver version detection of AMD RDNA+ GPU on Windows 10
[xbmc.git] / xbmc / pvr / guilib / PVRGUIActionsPlayback.cpp
bloba0bc877a604b404ac88f5f6fbbf4ba187ffff992
1 /*
2 * Copyright (C) 2016-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.
7 */
9 #include "PVRGUIActionsPlayback.h"
11 #include "FileItem.h"
12 #include "FileItemList.h"
13 #include "ServiceBroker.h"
14 #include "application/ApplicationEnums.h"
15 #include "cores/DataCacheCore.h"
16 #include "dialogs/GUIDialogKaiToast.h"
17 #include "dialogs/GUIDialogYesNo.h"
18 #include "guilib/GUIComponent.h"
19 #include "guilib/GUIWindowManager.h"
20 #include "guilib/LocalizeStrings.h"
21 #include "guilib/WindowIDs.h"
22 #include "messaging/ApplicationMessenger.h"
23 #include "pvr/PVRItem.h"
24 #include "pvr/PVRManager.h"
25 #include "pvr/PVRPlaybackState.h"
26 #include "pvr/PVRStreamProperties.h"
27 #include "pvr/addons/PVRClient.h"
28 #include "pvr/channels/PVRChannel.h"
29 #include "pvr/channels/PVRChannelGroup.h"
30 #include "pvr/channels/PVRChannelGroupMember.h"
31 #include "pvr/channels/PVRChannelGroups.h"
32 #include "pvr/channels/PVRChannelGroupsContainer.h"
33 #include "pvr/epg/EpgInfoTag.h"
34 #include "pvr/guilib/PVRGUIActionsChannels.h"
35 #include "pvr/guilib/PVRGUIActionsParentalControl.h"
36 #include "pvr/recordings/PVRRecording.h"
37 #include "pvr/recordings/PVRRecordings.h"
38 #include "settings/MediaSettings.h"
39 #include "settings/Settings.h"
40 #include "utils/StringUtils.h"
41 #include "utils/URIUtils.h"
42 #include "utils/Variant.h"
43 #include "utils/log.h"
44 #include "video/VideoUtils.h"
45 #include "video/guilib/VideoGUIUtils.h"
46 #include "video/guilib/VideoSelectActionProcessor.h"
48 #include <memory>
49 #include <string>
50 #include <vector>
52 using namespace KODI;
53 using namespace PVR;
54 using namespace KODI::MESSAGING;
56 CPVRGUIActionsPlayback::CPVRGUIActionsPlayback()
57 : m_settings({CSettings::SETTING_LOOKANDFEEL_STARTUPACTION,
58 CSettings::SETTING_PVRPLAYBACK_SWITCHTOFULLSCREENCHANNELTYPES})
62 bool CPVRGUIActionsPlayback::CheckResumeRecording(const CFileItem& item) const
64 bool bPlayIt(true);
66 const VIDEO::GUILIB::Action action =
67 VIDEO::GUILIB::CVideoSelectActionProcessorBase::ChoosePlayOrResume(item);
68 if (action == VIDEO::GUILIB::ACTION_RESUME)
70 const_cast<CFileItem*>(&item)->SetStartOffset(STARTOFFSET_RESUME);
72 else if (action == VIDEO::GUILIB::ACTION_PLAY_FROM_BEGINNING)
74 const_cast<CFileItem*>(&item)->SetStartOffset(0);
76 else
78 // The Resume dialog was closed without any choice
79 bPlayIt = false;
82 return bPlayIt;
85 bool CPVRGUIActionsPlayback::ResumePlayRecording(const CFileItem& item, bool bFallbackToPlay) const
87 if (VIDEO::UTILS::GetItemResumeInformation(item).isResumable)
89 const_cast<CFileItem*>(&item)->SetStartOffset(STARTOFFSET_RESUME);
91 else
93 if (bFallbackToPlay)
94 const_cast<CFileItem*>(&item)->SetStartOffset(0);
95 else
96 return false;
99 return PlayRecording(item, false /* skip resume check */);
102 void CPVRGUIActionsPlayback::CheckAndSwitchToFullscreen(bool bFullscreen) const
104 CMediaSettings::GetInstance().SetMediaStartWindowed(!bFullscreen);
106 if (bFullscreen)
108 CGUIMessage msg(GUI_MSG_FULLSCREEN, 0,
109 CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow());
110 CServiceBroker::GetGUI()->GetWindowManager().SendMessage(msg);
114 bool CPVRGUIActionsPlayback::PlayRecording(const CFileItem& item, bool bCheckResume) const
116 const std::shared_ptr<CPVRRecording> recording(CPVRItem(item).GetRecording());
117 if (!recording)
118 return false;
120 if (CServiceBroker::GetPVRManager().PlaybackState()->IsPlayingRecording(recording))
122 CGUIMessage msg(GUI_MSG_FULLSCREEN, 0,
123 CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow());
124 CServiceBroker::GetGUI()->GetWindowManager().SendMessage(msg);
125 return true;
128 if (!bCheckResume || CheckResumeRecording(item))
130 if (!item.m_bIsFolder && VIDEO::UTILS::IsAutoPlayNextItem(item))
132 // recursively add items located in the same folder as item to play list, starting with item
133 std::string parentPath = item.GetProperty("ParentPath").asString();
134 if (parentPath.empty())
135 URIUtils::GetParentPath(item.GetPath(), parentPath);
137 if (parentPath.empty())
139 CLog::LogF(LOGERROR, "Unable to obtain parent path for '{}'", item.GetPath());
140 return false;
143 const auto parentItem = std::make_shared<CFileItem>(parentPath, true);
144 if (item.GetStartOffset() == STARTOFFSET_RESUME)
145 parentItem->SetStartOffset(STARTOFFSET_RESUME);
147 auto queuedItems = std::make_unique<CFileItemList>();
148 VIDEO::UTILS::GetItemsForPlayList(parentItem, *queuedItems);
150 // figure out where to start playback
151 int pos = 0;
152 for (const std::shared_ptr<CFileItem>& queuedItem : *queuedItems)
154 if (queuedItem->IsSamePath(&item))
155 break;
157 pos++;
160 CServiceBroker::GetAppMessenger()->PostMsg(TMSG_MEDIA_PLAY, pos, -1,
161 static_cast<void*>(queuedItems.release()));
163 else
165 CFileItem* itemToPlay = new CFileItem(recording);
166 itemToPlay->SetStartOffset(item.GetStartOffset());
167 CServiceBroker::GetPVRManager().PlaybackState()->StartPlayback(itemToPlay);
169 CheckAndSwitchToFullscreen(true);
171 return true;
174 bool CPVRGUIActionsPlayback::PlayRecordingFolder(const CFileItem& item, bool bCheckResume) const
176 if (!item.m_bIsFolder)
177 return false;
179 if (!bCheckResume || CheckResumeRecording(item))
181 // recursively add items to list
182 const auto itemToQueue = std::make_shared<CFileItem>(item);
183 auto queuedItems = std::make_unique<CFileItemList>();
184 VIDEO::UTILS::GetItemsForPlayList(itemToQueue, *queuedItems);
186 CServiceBroker::GetAppMessenger()->PostMsg(TMSG_MEDIA_PLAY, 0, -1,
187 static_cast<void*>(queuedItems.release()));
188 CheckAndSwitchToFullscreen(true);
190 return true;
193 bool CPVRGUIActionsPlayback::PlayEpgTag(
194 const CFileItem& item,
195 ContentUtils::PlayMode mode /* = ContentUtils::PlayMode::CHECK_AUTO_PLAY_NEXT_ITEM */) const
197 const std::shared_ptr<CPVREpgInfoTag> epgTag(CPVRItem(item).GetEpgInfoTag());
198 if (!epgTag)
199 return false;
201 if (CServiceBroker::GetPVRManager().PlaybackState()->IsPlayingEpgTag(epgTag))
203 CGUIMessage msg(GUI_MSG_FULLSCREEN, 0,
204 CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow());
205 CServiceBroker::GetGUI()->GetWindowManager().SendMessage(msg);
206 return true;
209 // Obtain dynamic playback url and properties from the respective pvr client
210 const std::shared_ptr<const CPVRClient> client =
211 CServiceBroker::GetPVRManager().GetClient(epgTag->ClientID());
212 if (!client)
213 return false;
215 CPVRStreamProperties props;
216 client->GetEpgTagStreamProperties(epgTag, props);
218 CFileItem* itemToPlay = nullptr;
219 if (props.EPGPlaybackAsLive())
221 const std::shared_ptr<CPVRChannelGroupMember> groupMember =
222 CServiceBroker::GetPVRManager().Get<PVR::GUI::Channels>().GetChannelGroupMember(item);
223 if (!groupMember)
224 return false;
226 itemToPlay = new CFileItem(groupMember);
228 else
230 itemToPlay = new CFileItem(epgTag);
233 CServiceBroker::GetPVRManager().PlaybackState()->StartPlayback(itemToPlay, mode);
234 CheckAndSwitchToFullscreen(true);
235 return true;
238 bool CPVRGUIActionsPlayback::SwitchToChannel(const CFileItem& item, bool bCheckResume) const
240 if (item.m_bIsFolder)
241 return false;
243 std::shared_ptr<CPVRRecording> recording;
244 const std::shared_ptr<const CPVRChannel> channel(CPVRItem(item).GetChannel());
245 if (channel)
247 bool bSwitchToFullscreen =
248 CServiceBroker::GetPVRManager().PlaybackState()->IsPlayingChannel(channel);
250 if (!bSwitchToFullscreen)
252 recording =
253 CServiceBroker::GetPVRManager().Recordings()->GetRecordingForEpgTag(channel->GetEPGNow());
254 bSwitchToFullscreen =
255 recording &&
256 CServiceBroker::GetPVRManager().PlaybackState()->IsPlayingRecording(recording);
259 if (bSwitchToFullscreen)
261 CGUIMessage msg(GUI_MSG_FULLSCREEN, 0,
262 CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow());
263 CServiceBroker::GetGUI()->GetWindowManager().SendMessage(msg);
264 return true;
268 ParentalCheckResult result =
269 channel ? CServiceBroker::GetPVRManager().Get<PVR::GUI::Parental>().CheckParentalLock(channel)
270 : ParentalCheckResult::FAILED;
271 if (result == ParentalCheckResult::SUCCESS)
273 // switch to channel or if recording present, ask whether to switch or play recording...
274 if (!recording)
275 recording =
276 CServiceBroker::GetPVRManager().Recordings()->GetRecordingForEpgTag(channel->GetEPGNow());
278 if (recording)
280 bool bCancel(false);
281 bool bPlayRecording = CGUIDialogYesNo::ShowAndGetInput(
282 CVariant{19687}, // "Play recording"
283 CVariant{""}, CVariant{12021}, // "Play from beginning"
284 CVariant{recording->m_strTitle}, bCancel, CVariant{19000}, // "Switch to channel"
285 CVariant{19687}, // "Play recording"
286 0); // no autoclose
287 if (bCancel)
288 return false;
290 if (bPlayRecording)
291 return PlayRecording(CFileItem(recording), bCheckResume);
294 bool bFullscreen;
295 switch (m_settings.GetIntValue(CSettings::SETTING_PVRPLAYBACK_SWITCHTOFULLSCREENCHANNELTYPES))
297 case 0: // never
298 bFullscreen = false;
299 break;
300 case 1: // TV channels
301 bFullscreen = !channel->IsRadio();
302 break;
303 case 2: // Radio channels
304 bFullscreen = channel->IsRadio();
305 break;
306 case 3: // TV and radio channels
307 default:
308 bFullscreen = true;
309 break;
311 const std::shared_ptr<CPVRChannelGroupMember> groupMember =
312 CServiceBroker::GetPVRManager().Get<PVR::GUI::Channels>().GetChannelGroupMember(item);
313 if (!groupMember)
314 return false;
316 CServiceBroker::GetPVRManager().PlaybackState()->StartPlayback(new CFileItem(groupMember));
317 CheckAndSwitchToFullscreen(bFullscreen);
318 return true;
320 else if (result == ParentalCheckResult::FAILED)
322 const std::string channelName =
323 channel ? channel->ChannelName() : g_localizeStrings.Get(19029); // Channel
324 const std::string msg = StringUtils::Format(
325 g_localizeStrings.Get(19035),
326 channelName); // CHANNELNAME could not be played. Check the log for details.
328 CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Error, g_localizeStrings.Get(19166),
329 msg); // PVR information
332 return false;
335 bool CPVRGUIActionsPlayback::SwitchToChannel(PlaybackType type) const
337 std::shared_ptr<CPVRChannelGroupMember> groupMember;
338 bool bIsRadio(false);
340 // check if the desired PlaybackType is already playing,
341 // and if not, try to grab the last played channel of this type
342 switch (type)
344 case PlaybackTypeRadio:
346 if (CServiceBroker::GetPVRManager().PlaybackState()->IsPlayingRadio())
347 return true;
349 const std::shared_ptr<CPVRChannelGroup> allGroup =
350 CServiceBroker::GetPVRManager().ChannelGroups()->GetGroupAllRadio();
351 if (allGroup)
352 groupMember = allGroup->GetLastPlayedChannelGroupMember();
354 bIsRadio = true;
355 break;
357 case PlaybackTypeTV:
359 if (CServiceBroker::GetPVRManager().PlaybackState()->IsPlayingTV())
360 return true;
362 const std::shared_ptr<const CPVRChannelGroup> allGroup =
363 CServiceBroker::GetPVRManager().ChannelGroups()->GetGroupAllTV();
364 if (allGroup)
365 groupMember = allGroup->GetLastPlayedChannelGroupMember();
367 break;
369 default:
370 if (CServiceBroker::GetPVRManager().PlaybackState()->IsPlaying())
371 return true;
373 groupMember =
374 CServiceBroker::GetPVRManager().ChannelGroups()->GetLastPlayedChannelGroupMember();
375 break;
378 // if we have a last played channel, start playback
379 if (groupMember)
381 return SwitchToChannel(CFileItem(groupMember), true);
383 else
385 // if we don't, find the active channel group of the demanded type and play it's first channel
386 const std::shared_ptr<const CPVRChannelGroup> channelGroup =
387 CServiceBroker::GetPVRManager().PlaybackState()->GetActiveChannelGroup(bIsRadio);
388 if (channelGroup)
390 // try to start playback of first channel in this group
391 const std::vector<std::shared_ptr<CPVRChannelGroupMember>> groupMembers =
392 channelGroup->GetMembers();
393 if (!groupMembers.empty())
395 return SwitchToChannel(CFileItem(*groupMembers.begin()), true);
400 CLog::LogF(LOGERROR,
401 "Could not determine {} channel to playback. No last played channel found, and "
402 "first channel of active group could also not be determined.",
403 bIsRadio ? "Radio" : "TV");
405 CGUIDialogKaiToast::QueueNotification(
406 CGUIDialogKaiToast::Error,
407 g_localizeStrings.Get(19166), // PVR information
408 StringUtils::Format(
409 g_localizeStrings.Get(19035),
410 g_localizeStrings.Get(
411 bIsRadio ? 19021
412 : 19020))); // Radio/TV could not be played. Check the log for details.
413 return false;
416 bool CPVRGUIActionsPlayback::PlayChannelOnStartup() const
418 int iAction = m_settings.GetIntValue(CSettings::SETTING_LOOKANDFEEL_STARTUPACTION);
419 if (iAction != STARTUP_ACTION_PLAY_TV && iAction != STARTUP_ACTION_PLAY_RADIO)
420 return false;
422 bool playRadio = (iAction == STARTUP_ACTION_PLAY_RADIO);
424 // get the last played channel or fallback to first channel of all channels group
425 std::shared_ptr<CPVRChannelGroupMember> groupMember =
426 CServiceBroker::GetPVRManager().PlaybackState()->GetLastPlayedChannelGroupMember(playRadio);
428 if (!groupMember)
430 const std::shared_ptr<const CPVRChannelGroup> group =
431 CServiceBroker::GetPVRManager().ChannelGroups()->Get(playRadio)->GetGroupAll();
432 auto channels = group->GetMembers();
433 if (channels.empty())
434 return false;
436 groupMember = channels.front();
437 if (!groupMember)
438 return false;
441 CLog::Log(LOGINFO, "PVR is starting playback of channel '{}'",
442 groupMember->Channel()->ChannelName());
443 return SwitchToChannel(CFileItem(groupMember), true);
446 bool CPVRGUIActionsPlayback::PlayMedia(const CFileItem& item) const
448 std::unique_ptr<CFileItem> pvrItem = std::make_unique<CFileItem>(item);
449 if (URIUtils::IsPVRChannel(item.GetPath()) && !item.HasPVRChannelInfoTag())
451 const std::shared_ptr<CPVRChannelGroupMember> groupMember =
452 CServiceBroker::GetPVRManager().ChannelGroups()->GetChannelGroupMemberByPath(
453 item.GetPath());
454 if (groupMember)
455 pvrItem = std::make_unique<CFileItem>(groupMember);
457 else if (URIUtils::IsPVRRecording(item.GetPath()) && !item.HasPVRRecordingInfoTag())
459 const std::shared_ptr<CPVRRecording> recording =
460 CServiceBroker::GetPVRManager().Recordings()->GetByPath(item.GetPath());
461 if (recording)
463 pvrItem = std::make_unique<CFileItem>(recording);
464 pvrItem->SetStartOffset(item.GetStartOffset());
467 bool bCheckResume = true;
468 if (item.HasProperty("check_resume"))
469 bCheckResume = item.GetProperty("check_resume").asBoolean();
471 if (pvrItem && pvrItem->HasPVRChannelInfoTag())
473 return SwitchToChannel(*pvrItem, bCheckResume);
475 else if (pvrItem && pvrItem->HasPVRRecordingInfoTag())
477 return PlayRecording(*pvrItem, bCheckResume);
480 return false;
483 void CPVRGUIActionsPlayback::SeekForward()
485 time_t playbackStartTime = CServiceBroker::GetDataCacheCore().GetStartTime();
486 if (playbackStartTime > 0)
488 const std::shared_ptr<const CPVRChannel> playingChannel =
489 CServiceBroker::GetPVRManager().PlaybackState()->GetPlayingChannel();
490 if (playingChannel)
492 time_t nextTime = 0;
493 std::shared_ptr<CPVREpgInfoTag> next = playingChannel->GetEPGNext();
494 if (next)
496 next->StartAsUTC().GetAsTime(nextTime);
498 else
500 // if there is no next event, jump to end of currently playing event
501 next = playingChannel->GetEPGNow();
502 if (next)
503 next->EndAsUTC().GetAsTime(nextTime);
506 int64_t seekTime = 0;
507 if (nextTime != 0)
509 seekTime = (nextTime - playbackStartTime) * 1000;
511 else
513 // no epg; jump to end of buffer
514 seekTime = CServiceBroker::GetDataCacheCore().GetMaxTime();
516 CServiceBroker::GetAppMessenger()->PostMsg(TMSG_MEDIA_SEEK_TIME, seekTime);
521 void CPVRGUIActionsPlayback::SeekBackward(unsigned int iThreshold)
523 time_t playbackStartTime = CServiceBroker::GetDataCacheCore().GetStartTime();
524 if (playbackStartTime > 0)
526 const std::shared_ptr<const CPVRChannel> playingChannel =
527 CServiceBroker::GetPVRManager().PlaybackState()->GetPlayingChannel();
528 if (playingChannel)
530 time_t prevTime = 0;
531 std::shared_ptr<CPVREpgInfoTag> prev = playingChannel->GetEPGNow();
532 if (prev)
534 prev->StartAsUTC().GetAsTime(prevTime);
536 // if playback time of current event is above threshold jump to start of current event
537 int64_t playTime = CServiceBroker::GetDataCacheCore().GetPlayTime() / 1000;
538 if ((playbackStartTime + playTime - prevTime) <= iThreshold)
540 // jump to start of previous event
541 prevTime = 0;
542 prev = playingChannel->GetEPGPrevious();
543 if (prev)
544 prev->StartAsUTC().GetAsTime(prevTime);
548 int64_t seekTime = 0;
549 if (prevTime != 0)
551 seekTime = (prevTime - playbackStartTime) * 1000;
553 else
555 // no epg; jump to begin of buffer
556 seekTime = CServiceBroker::GetDataCacheCore().GetMinTime();
558 CServiceBroker::GetAppMessenger()->PostMsg(TMSG_MEDIA_SEEK_TIME, seekTime);