2 * Copyright (C) 2005-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 "Application.h"
12 #include "CompileInfo.h"
13 #include "DatabaseManager.h"
15 #include "GUIInfoManager.h"
16 #include "GUILargeTextureManager.h"
17 #include "GUIPassword.h"
18 #include "GUIUserMessages.h"
19 #include "HDRStatus.h"
21 #include "PartyModeManager.h"
22 #include "PlayListPlayer.h"
23 #include "SectionLoader.h"
24 #include "SeekHandler.h"
25 #include "ServiceBroker.h"
26 #include "ServiceManager.h"
27 #include "TextureCache.h"
30 #include "addons/AddonManager.h"
31 #include "addons/AddonSystemSettings.h"
32 #include "addons/RepositoryUpdater.h"
33 #include "addons/Service.h"
34 #include "addons/Skin.h"
35 #include "addons/VFSEntry.h"
36 #include "addons/addoninfo/AddonInfo.h"
37 #include "addons/addoninfo/AddonType.h"
38 #include "addons/gui/GUIDialogAddonSettings.h"
39 #include "application/AppInboundProtocol.h"
40 #include "application/AppParams.h"
41 #include "application/ApplicationActionListeners.h"
42 #include "application/ApplicationPlayer.h"
43 #include "application/ApplicationPowerHandling.h"
44 #include "application/ApplicationSkinHandling.h"
45 #include "application/ApplicationStackHelper.h"
46 #include "application/ApplicationVolumeHandling.h"
47 #include "cores/AudioEngine/Engines/ActiveAE/ActiveAE.h"
48 #include "cores/DataCacheCore.h"
49 #include "cores/FFmpeg.h"
50 #include "cores/IPlayer.h"
51 #include "cores/playercorefactory/PlayerCoreFactory.h"
52 #include "dialogs/GUIDialogBusy.h"
53 #include "dialogs/GUIDialogCache.h"
54 #include "dialogs/GUIDialogKaiToast.h"
55 #include "dialogs/GUIDialogSimpleMenu.h"
56 #include "events/EventLog.h"
57 #include "events/NotificationEvent.h"
58 #include "filesystem/Directory.h"
59 #include "filesystem/DirectoryCache.h"
60 #include "filesystem/DirectoryFactory.h"
61 #include "filesystem/DllLibCurl.h"
62 #include "filesystem/File.h"
63 #ifdef HAS_FILESYSTEM_NFS
64 #include "filesystem/NFSFile.h"
66 #include "filesystem/PluginDirectory.h"
67 #include "filesystem/SpecialProtocol.h"
69 #include "filesystem/UPnPDirectory.h"
71 #include "guilib/GUIAudioManager.h"
72 #include "guilib/GUIComponent.h"
73 #include "guilib/GUIControlProfiler.h"
74 #include "guilib/GUIFontManager.h"
75 #include "guilib/GUIWindowManager.h"
76 #include "guilib/LocalizeStrings.h"
77 #include "guilib/StereoscopicsManager.h"
78 #include "guilib/TextureManager.h"
79 #include "input/InertialScrollingHandler.h"
80 #include "input/InputManager.h"
81 #include "input/actions/Action.h"
82 #include "input/actions/ActionIDs.h"
83 #include "input/actions/ActionTranslator.h"
84 #include "input/keyboard/KeyboardLayoutManager.h"
85 #include "interfaces/AnnouncementManager.h"
86 #include "interfaces/builtins/Builtins.h"
87 #include "interfaces/generic/ScriptInvocationManager.h"
88 #include "interfaces/json-rpc/JSONRPC.h"
90 #include "interfaces/python/XBPython.h"
92 #include "messaging/ApplicationMessenger.h"
93 #include "messaging/ThreadMessage.h"
94 #include "messaging/helpers/DialogHelper.h"
95 #include "messaging/helpers/DialogOKHelper.h"
96 #include "music/MusicLibraryQueue.h"
97 #include "music/MusicThumbLoader.h"
98 #include "music/MusicUtils.h"
99 #include "music/infoscanner/MusicInfoScanner.h"
100 #include "music/tags/MusicInfoTag.h"
101 #include "network/EventServer.h"
102 #include "network/Network.h"
103 #include "network/ZeroconfBrowser.h"
105 #include "network/upnp/UPnP.h"
107 #include "peripherals/Peripherals.h"
108 #include "pictures/SlideShowDelegator.h"
109 #include "platform/Environment.h"
110 #include "playlists/PlayList.h"
111 #include "playlists/PlayListFactory.h"
112 #include "playlists/SmartPlayList.h"
113 #include "powermanagement/PowerManager.h"
114 #include "profiles/ProfileManager.h"
115 #include "pvr/PVRManager.h"
116 #include "pvr/guilib/PVRGUIActionsPlayback.h"
117 #include "pvr/guilib/PVRGUIActionsPowerManagement.h"
118 #include "settings/AdvancedSettings.h"
119 #include "settings/DisplaySettings.h"
120 #include "settings/MediaSettings.h"
121 #include "settings/Settings.h"
122 #include "settings/SettingsComponent.h"
123 #include "speech/ISpeechRecognition.h"
124 #include "storage/MediaManager.h"
125 #include "threads/SingleLock.h"
126 #include "threads/SystemClock.h"
127 #include "utils/AlarmClock.h"
128 #include "utils/CPUInfo.h"
129 #include "utils/CharsetConverter.h"
130 #include "utils/ContentUtils.h"
131 #include "utils/FileExtensionProvider.h"
132 #include "utils/JobManager.h"
133 #include "utils/LangCodeExpander.h"
134 #include "utils/PlayerUtils.h"
135 #include "utils/RegExp.h"
136 #include "utils/Screenshot.h"
137 #include "utils/StringUtils.h"
138 #include "utils/SystemInfo.h"
139 #include "utils/TimeUtils.h"
140 #include "utils/URIUtils.h"
141 #include "utils/Variant.h"
142 #include "utils/XTimeUtils.h"
143 #include "utils/log.h"
144 #include "video/Bookmark.h"
145 #include "video/PlayerController.h"
146 #include "video/VideoLibraryQueue.h"
147 #include "video/dialogs/GUIDialogVideoBookmarks.h"
148 #ifdef TARGET_WINDOWS
149 #include "win32util.h"
151 #include "windowing/WinSystem.h"
152 #include "windowing/WindowSystemFactory.h"
154 #if defined(TARGET_ANDROID)
155 #include "platform/android/activity/XBMCApp.h"
158 #include "platform/darwin/DarwinUtils.h"
160 #ifdef TARGET_DARWIN_OSX
161 #ifdef HAS_XBMCHELPER
162 #include "platform/darwin/osx/XBMCHelper.h"
166 #include "platform/posix/PlatformPosix.h"
167 #include "platform/posix/XHandle.h"
169 #if defined(TARGET_POSIX) && defined(HAS_FILESYSTEM_SMB)
170 #include "platform/posix/filesystem/SMBFile.h"
173 #include "platform/win32/threads/Win32Exception.h"
182 #include <X11/Xlib.h>
184 #ifdef HAS_OPTICAL_DRIVE
185 #include <cdio/logging.h>
188 using namespace ADDON
;
189 using namespace XFILE
;
190 #ifdef HAS_OPTICAL_DRIVE
191 using namespace MEDIA_DETECT
;
193 using namespace VIDEO
;
194 using namespace MUSIC_INFO
;
195 using namespace EVENTSERVER
;
196 using namespace JSONRPC
;
198 using namespace PERIPHERALS
;
199 using namespace KODI
;
200 using namespace KODI::MESSAGING
;
201 using namespace ActiveAE
;
203 using namespace XbmcThreads
;
204 using namespace std::chrono_literals
;
206 using KODI::MESSAGING::HELPERS::DialogResponse
;
208 using namespace std::chrono_literals
;
210 #define MAX_FFWD_SPEED 5
212 CApplication::CApplication(void)
214 #ifdef HAS_OPTICAL_DRIVE
215 m_Autorun(new CAutorun()),
217 m_pInertialScrollingHandler(new CInertialScrollingHandler()),
218 m_WaitingExternalCalls(0),
219 m_itemCurrentFile(std::make_shared
<CFileItem
>()),
220 m_playerEvent(true, true)
222 TiXmlBase::SetCondenseWhiteSpace(false);
228 // register application components
229 RegisterComponent(std::make_shared
<CApplicationActionListeners
>(m_critSection
));
230 RegisterComponent(std::make_shared
<CApplicationPlayer
>());
231 RegisterComponent(std::make_shared
<CApplicationPowerHandling
>());
232 RegisterComponent(std::make_shared
<CApplicationSkinHandling
>(this, this, m_bInitializing
));
233 RegisterComponent(std::make_shared
<CApplicationVolumeHandling
>());
234 RegisterComponent(std::make_shared
<CApplicationStackHelper
>());
237 CApplication::~CApplication(void)
239 DeregisterComponent(typeid(CApplicationStackHelper
));
240 DeregisterComponent(typeid(CApplicationVolumeHandling
));
241 DeregisterComponent(typeid(CApplicationSkinHandling
));
242 DeregisterComponent(typeid(CApplicationPowerHandling
));
243 DeregisterComponent(typeid(CApplicationPlayer
));
244 DeregisterComponent(typeid(CApplicationActionListeners
));
247 bool CApplication::OnEvent(XBMC_Event
& newEvent
)
249 std::unique_lock
<CCriticalSection
> lock(m_portSection
);
250 m_portEvents
.push_back(newEvent
);
254 void CApplication::HandlePortEvents()
256 std::unique_lock
<CCriticalSection
> lock(m_portSection
);
257 while (!m_portEvents
.empty())
259 auto newEvent
= m_portEvents
.front();
260 m_portEvents
.pop_front();
261 CSingleExit
lock(m_portSection
);
262 switch(newEvent
.type
)
266 CServiceBroker::GetAppMessenger()->PostMsg(TMSG_QUIT
);
268 case XBMC_VIDEORESIZE
:
269 if (CServiceBroker::GetGUI()->GetWindowManager().Initialized())
271 if (!CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_fullScreen
)
273 CServiceBroker::GetWinSystem()->GetGfxContext().ApplyWindowResize(newEvent
.resize
.w
, newEvent
.resize
.h
);
275 const std::shared_ptr
<CSettings
> settings
= CServiceBroker::GetSettingsComponent()->GetSettings();
276 settings
->SetInt(CSettings::SETTING_WINDOW_WIDTH
, newEvent
.resize
.w
);
277 settings
->SetInt(CSettings::SETTING_WINDOW_HEIGHT
, newEvent
.resize
.h
);
282 const auto& res_info
= CDisplaySettings::GetInstance().GetResolutionInfo(RES_DESKTOP
);
283 CServiceBroker::GetWinSystem()->ForceFullScreen(res_info
);
289 CServiceBroker::GetWinSystem()->OnMove(newEvent
.move
.x
, newEvent
.move
.y
);
292 case XBMC_MODECHANGE
:
293 CServiceBroker::GetWinSystem()->GetGfxContext().ApplyModeChange(newEvent
.mode
.res
);
295 case XBMC_SCREENCHANGE
:
296 CServiceBroker::GetWinSystem()->OnChangeScreen(newEvent
.screen
.screenIdx
);
299 CServiceBroker::GetAppMessenger()->PostMsg(static_cast<uint32_t>(newEvent
.user
.code
));
303 // Reset the screensaver
304 const auto appPower
= GetComponent
<CApplicationPowerHandling
>();
305 appPower
->ResetScreenSaver();
306 appPower
->WakeUpScreenSaverAndDPMS();
307 // Send a mouse motion event with no dx,dy for getting the current guiitem selected
308 OnAction(CAction(ACTION_MOUSE_MOVE
, 0, static_cast<float>(newEvent
.focus
.x
), static_cast<float>(newEvent
.focus
.y
), 0, 0));
312 CServiceBroker::GetInputManager().OnEvent(newEvent
);
317 extern "C" void __stdcall
init_emu_environ();
318 extern "C" void __stdcall
update_emu_environ();
319 extern "C" void __stdcall
cleanup_emu_environ();
321 bool CApplication::Create()
327 CServiceBroker::RegisterCPUInfo(CCPUInfo::GetCPUInfo());
329 // Register JobManager service
330 CServiceBroker::RegisterJobManager(std::make_shared
<CJobManager
>());
332 // Announcement service
333 m_pAnnouncementManager
= std::make_shared
<ANNOUNCEMENT::CAnnouncementManager
>();
334 m_pAnnouncementManager
->Start();
335 CServiceBroker::RegisterAnnouncementManager(m_pAnnouncementManager
);
337 const auto appMessenger
= std::make_shared
<CApplicationMessenger
>();
338 CServiceBroker::RegisterAppMessenger(appMessenger
);
340 const auto keyboardLayoutManager
= std::make_shared
<KEYBOARD::CKeyboardLayoutManager
>();
341 CServiceBroker::RegisterKeyboardLayoutManager(keyboardLayoutManager
);
343 m_ServiceManager
= std::make_unique
<CServiceManager
>();
345 if (!m_ServiceManager
->InitStageOne())
350 // here we register all global classes for the CApplicationMessenger,
351 // after that we can send messages to the corresponding modules
352 appMessenger
->RegisterReceiver(this);
353 appMessenger
->RegisterReceiver(&CServiceBroker::GetPlaylistPlayer());
354 appMessenger
->SetGUIThread(CThread::GetCurrentThreadId());
355 appMessenger
->SetProcessThread(CThread::GetCurrentThreadId());
357 // copy required files
358 CUtil::CopyUserDataIfNeeded("special://masterprofile/", "RssFeeds.xml");
359 CUtil::CopyUserDataIfNeeded("special://masterprofile/", "favourites.xml");
360 CUtil::CopyUserDataIfNeeded("special://masterprofile/", "Lircmap.xml");
362 CServiceBroker::GetLogging().Initialize(CSpecialProtocol::TranslatePath("special://logpath"));
364 #ifdef TARGET_POSIX //! @todo Win32 has no special://home/ mapping by default, so we
365 //! must create these here. Ideally this should be using special://home/ and
366 //! be platform agnostic (i.e. unify the InitDirectories*() functions)
367 if (!CServiceBroker::GetAppParams()->HasPlatformDirectories())
370 CDirectory::Create("special://xbmc/addons");
373 // Init our DllLoaders emu env
378 // initialize network protocols
379 avformat_network_init();
380 // set avutil callback
381 av_log_set_callback(ff_avutil_log
);
383 CLog::Log(LOGINFO
, "loading settings");
384 const auto settingsComponent
= CServiceBroker::GetSettingsComponent();
385 if (!settingsComponent
->Load())
388 // Log Cache GUI settings (replacement of cache in advancedsettings.xml)
389 const auto settings
= settingsComponent
->GetSettings();
390 const float readFactor
= settings
->GetInt(CSettings::SETTING_FILECACHE_READFACTOR
) / 100.0f
;
392 "New Cache GUI Settings (replacement of cache in advancedsettings.xml) are:\n Buffer "
393 "Mode: {}\n Memory Size: {} MB\n Read "
394 "Factor: {:.2f} x {}\n Chunk Size : {} bytes",
395 settings
->GetInt(CSettings::SETTING_FILECACHE_BUFFERMODE
),
396 settings
->GetInt(CSettings::SETTING_FILECACHE_MEMORYSIZE
), readFactor
,
397 (readFactor
< 1.0f
) ? "(adaptive)" : "",
398 settings
->GetInt(CSettings::SETTING_FILECACHE_CHUNKSIZE
));
400 CLog::Log(LOGINFO
, "creating subdirectories");
401 const std::shared_ptr
<CProfileManager
> profileManager
= settingsComponent
->GetProfileManager();
402 CLog::Log(LOGINFO
, "userdata folder: {}",
403 CURL::GetRedacted(profileManager
->GetProfileUserDataFolder()));
404 CLog::Log(LOGINFO
, "recording folder: {}",
405 CURL::GetRedacted(settings
->GetString(CSettings::SETTING_AUDIOCDS_RECORDINGPATH
)));
406 CLog::Log(LOGINFO
, "screenshots folder: {}",
407 CURL::GetRedacted(settings
->GetString(CSettings::SETTING_DEBUG_SCREENSHOTPATH
)));
408 CDirectory::Create(profileManager
->GetUserDataFolder());
409 CDirectory::Create(profileManager
->GetProfileUserDataFolder());
410 profileManager
->CreateProfileFolders();
412 update_emu_environ();//apply the GUI settings
414 // application inbound service
415 m_pAppPort
= std::make_shared
<CAppInboundProtocol
>(*this);
416 CServiceBroker::RegisterAppPort(m_pAppPort
);
418 if (!m_ServiceManager
->InitStageTwo(
419 settingsComponent
->GetProfileManager()->GetProfileUserDataFolder()))
424 m_pActiveAE
= std::make_unique
<ActiveAE::CActiveAE
>();
425 CServiceBroker::RegisterAE(m_pActiveAE
.get());
427 // initialize m_replayGainSettings
428 GetComponent
<CApplicationVolumeHandling
>()->CacheReplayGainSettings(*settings
);
430 // load the keyboard layouts
431 if (!keyboardLayoutManager
->Load())
433 CLog::Log(LOGFATAL
, "CApplication::Create: Unable to load keyboard layouts");
437 // set user defined CA trust bundle
439 CSpecialProtocol::TranslatePath(settingsComponent
->GetAdvancedSettings()->m_caTrustFile
);
442 if (XFILE::CFile::Exists(caCert
))
444 CEnvironment::setenv("SSL_CERT_FILE", caCert
, 1);
445 CLog::Log(LOGDEBUG
, "CApplication::Create - SSL_CERT_FILE: {}", caCert
);
449 CLog::Log(LOGDEBUG
, "CApplication::Create - Error reading SSL_CERT_FILE: {} -> ignored",
454 CUtil::InitRandomSeed();
456 m_lastRenderTime
= std::chrono::steady_clock::now();
460 bool CApplication::CreateGUI()
462 m_frameMoveGuard
.lock();
464 const auto appPower
= GetComponent
<CApplicationPowerHandling
>();
465 appPower
->SetRenderGUI(true);
467 auto windowSystems
= KODI::WINDOWING::CWindowSystemFactory::GetWindowSystems();
469 const std::string
& windowing
= CServiceBroker::GetAppParams()->GetWindowing();
471 if (!windowing
.empty())
472 windowSystems
= {windowing
};
474 for (auto& windowSystem
: windowSystems
)
476 CLog::Log(LOGDEBUG
, "CApplication::{} - trying to init {} windowing system", __FUNCTION__
,
478 m_pWinSystem
= KODI::WINDOWING::CWindowSystemFactory::CreateWindowSystem(windowSystem
);
483 if (!windowing
.empty() && windowing
!= windowSystem
)
486 CServiceBroker::RegisterWinSystem(m_pWinSystem
.get());
488 if (!m_pWinSystem
->InitWindowSystem())
490 CLog::Log(LOGDEBUG
, "CApplication::{} - unable to init {} windowing system", __FUNCTION__
,
492 m_pWinSystem
->DestroyWindowSystem();
493 m_pWinSystem
.reset();
494 CServiceBroker::UnregisterWinSystem();
499 CLog::Log(LOGINFO
, "CApplication::{} - using the {} windowing system", __FUNCTION__
,
507 CLog::Log(LOGFATAL
, "CApplication::{} - unable to init windowing system", __FUNCTION__
);
508 CServiceBroker::UnregisterWinSystem();
512 // Retrieve the matching resolution based on GUI settings
513 bool sav_res
= false;
514 CDisplaySettings::GetInstance().SetCurrentResolution(CDisplaySettings::GetInstance().GetDisplayResolution());
515 CLog::Log(LOGINFO
, "Checking resolution {}",
516 CDisplaySettings::GetInstance().GetCurrentResolution());
517 if (!CServiceBroker::GetWinSystem()->GetGfxContext().IsValidResolution(CDisplaySettings::GetInstance().GetCurrentResolution()))
519 CLog::Log(LOGINFO
, "Setting safe mode {}", RES_DESKTOP
);
520 // defer saving resolution after window was created
521 CDisplaySettings::GetInstance().SetCurrentResolution(RES_DESKTOP
);
525 // update the window resolution
526 const std::shared_ptr
<CSettings
> settings
= CServiceBroker::GetSettingsComponent()->GetSettings();
527 CServiceBroker::GetWinSystem()->SetWindowResolution(settings
->GetInt(CSettings::SETTING_WINDOW_WIDTH
), settings
->GetInt(CSettings::SETTING_WINDOW_HEIGHT
));
529 if (CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_startFullScreen
&& CDisplaySettings::GetInstance().GetCurrentResolution() == RES_WINDOW
)
531 // defer saving resolution after window was created
532 CDisplaySettings::GetInstance().SetCurrentResolution(RES_DESKTOP
);
536 if (!CServiceBroker::GetWinSystem()->GetGfxContext().IsValidResolution(CDisplaySettings::GetInstance().GetCurrentResolution()))
538 // Oh uh - doesn't look good for starting in their wanted screenmode
539 CLog::Log(LOGERROR
, "The screen resolution requested is not valid, resetting to a valid mode");
540 CDisplaySettings::GetInstance().SetCurrentResolution(RES_DESKTOP
);
548 // Set default screen saver mode
549 auto screensaverModeSetting
= std::static_pointer_cast
<CSettingString
>(settings
->GetSetting(CSettings::SETTING_SCREENSAVER_MODE
));
550 // Can only set this after windowing has been initialized since it depends on it
551 if (CServiceBroker::GetWinSystem()->GetOSScreenSaver())
553 // If OS has a screen saver, use it by default
554 screensaverModeSetting
->SetDefault("");
558 // If OS has no screen saver, use Kodi one by default
559 screensaverModeSetting
->SetDefault("screensaver.xbmc.builtin.dim");
563 CDisplaySettings::GetInstance().SetCurrentResolution(RES_DESKTOP
, true);
565 m_pGUI
= std::make_unique
<CGUIComponent
>();
568 // Splash requires gui component!!
569 CServiceBroker::GetRenderSystem()->ShowSplash("");
571 // The key mappings may already have been loaded by a peripheral
572 CLog::Log(LOGINFO
, "load keymapping");
573 if (!CServiceBroker::GetInputManager().LoadKeymaps())
576 RESOLUTION_INFO info
= CServiceBroker::GetWinSystem()->GetGfxContext().GetResInfo();
577 CLog::Log(LOGINFO
, "GUI format {}x{}, Display {}", info
.iWidth
, info
.iHeight
, info
.strMode
);
582 bool CApplication::InitWindow(RESOLUTION res
)
584 if (res
== RES_INVALID
)
585 res
= CDisplaySettings::GetInstance().GetCurrentResolution();
587 bool bFullScreen
= res
!= RES_WINDOW
;
588 if (!CServiceBroker::GetWinSystem()->CreateNewWindow(CSysInfo::GetAppName(),
589 bFullScreen
, CDisplaySettings::GetInstance().GetResolutionInfo(res
)))
591 CLog::Log(LOGFATAL
, "CApplication::Create: Unable to create window");
595 if (!CServiceBroker::GetRenderSystem()->InitRenderSystem())
597 CLog::Log(LOGFATAL
, "CApplication::Create: Unable to init rendering system");
600 // set GUI res and force the clear of the screen
601 CServiceBroker::GetWinSystem()->GetGfxContext().SetVideoResolution(res
, false);
605 bool CApplication::Initialize()
607 m_pActiveAE
->Start();
608 // restore AE's previous volume state
610 const auto appVolume
= GetComponent
<CApplicationVolumeHandling
>();
611 const auto level
= appVolume
->GetVolumeRatio();
612 const auto muted
= appVolume
->IsMuted();
613 appVolume
->SetHardwareVolume(level
);
614 CServiceBroker::GetActiveAE()->SetMute(muted
);
616 #if defined(HAS_OPTICAL_DRIVE) && \
617 !defined(TARGET_WINDOWS) // somehow this throws an "unresolved external symbol" on win32
618 // turn off cdio logging
619 cdio_loglevel_default
= CDIO_LOG_ERROR
;
622 // load the language and its translated strings
623 if (!LoadLanguage(false))
626 // load media manager sources (e.g. root addon type sources depend on language strings to be available)
627 CServiceBroker::GetMediaManager().LoadSources();
629 const std::shared_ptr
<CProfileManager
> profileManager
= CServiceBroker::GetSettingsComponent()->GetProfileManager();
631 profileManager
->GetEventLog().Add(EventPtr(new CNotificationEvent(
632 StringUtils::Format(g_localizeStrings
.Get(177), g_sysinfo
.GetAppName()),
633 StringUtils::Format(g_localizeStrings
.Get(178), g_sysinfo
.GetAppName()),
634 "special://xbmc/media/icon256x256.png", EventLevel::Basic
)));
636 m_ServiceManager
->GetNetwork().WaitForNet();
638 // initialize (and update as needed) our databases
639 CDatabaseManager
&databaseManager
= m_ServiceManager
->GetDatabaseManager();
642 CServiceBroker::GetJobManager()->Submit([&databaseManager
, &event
]() {
643 databaseManager
.Initialize();
647 std::string localizedStr
= g_localizeStrings
.Get(24150);
649 while (!event
.Wait(1000ms
))
651 if (databaseManager
.IsUpgrading())
652 CServiceBroker::GetRenderSystem()->ShowSplash(std::string(iDots
, ' ') + localizedStr
+ std::string(iDots
, '.'));
659 CServiceBroker::GetRenderSystem()->ShowSplash("");
661 // Initialize GUI font manager to build/update fonts cache
662 //! @todo Move GUIFontManager into service broker and drop the global reference
664 GUIFontManager
& guiFontManager
= g_fontManager
;
665 CServiceBroker::GetJobManager()->Submit([&guiFontManager
, &event
]() {
666 guiFontManager
.Initialize();
669 localizedStr
= g_localizeStrings
.Get(39175);
671 while (!event
.Wait(1000ms
))
673 if (g_fontManager
.IsUpdating())
674 CServiceBroker::GetRenderSystem()->ShowSplash(std::string(iDots
, ' ') + localizedStr
+
675 std::string(iDots
, '.'));
682 CServiceBroker::GetRenderSystem()->ShowSplash("");
684 // GUI depends on seek handler
685 GetComponent
<CApplicationPlayer
>()->GetSeekHandler().Configure();
687 const auto skinHandling
= GetComponent
<CApplicationSkinHandling
>();
689 bool uiInitializationFinished
= false;
691 if (CServiceBroker::GetGUI()->GetWindowManager().Initialized())
693 const auto settings
= CServiceBroker::GetSettingsComponent()->GetSettings();
695 CServiceBroker::GetGUI()->GetWindowManager().CreateWindows();
697 skinHandling
->m_confirmSkinChange
= false;
699 std::vector
<AddonInfoPtr
> incompatibleAddons
;
703 if (CServiceBroker::GetAddonMgr().GetIncompatibleEnabledAddonInfos(incompatibleAddons
))
705 if (CAddonSystemSettings::GetInstance().GetAddonAutoUpdateMode() == AUTO_UPDATES_ON
)
707 CServiceBroker::GetJobManager()->Submit(
708 [&event
, &incompatibleAddons
]() {
709 if (CServiceBroker::GetRepositoryUpdater().CheckForUpdates())
710 CServiceBroker::GetRepositoryUpdater().Await();
712 incompatibleAddons
= CServiceBroker::GetAddonMgr().MigrateAddons();
715 CJob::PRIORITY_DEDICATED
);
716 localizedStr
= g_localizeStrings
.Get(24151);
718 while (!event
.Wait(1000ms
))
720 CServiceBroker::GetRenderSystem()->ShowSplash(std::string(iDots
, ' ') + localizedStr
+
721 std::string(iDots
, '.'));
727 m_incompatibleAddons
= incompatibleAddons
;
731 // If no update is active disable all incompatible addons during start
732 m_incompatibleAddons
=
733 CServiceBroker::GetAddonMgr().DisableIncompatibleAddons(incompatibleAddons
);
737 // Start splashscreen and load skin
738 CServiceBroker::GetRenderSystem()->ShowSplash("");
739 skinHandling
->m_confirmSkinChange
= true;
741 auto setting
= settings
->GetSetting(CSettings::SETTING_LOOKANDFEEL_SKIN
);
744 CLog::Log(LOGFATAL
, "Failed to load setting for: {}", CSettings::SETTING_LOOKANDFEEL_SKIN
);
748 CServiceBroker::RegisterTextureCache(std::make_shared
<CTextureCache
>());
750 std::string skinId
= settings
->GetString(CSettings::SETTING_LOOKANDFEEL_SKIN
);
751 if (!skinHandling
->LoadSkin(skinId
))
753 CLog::Log(LOGERROR
, "Failed to load skin '{}'", skinId
);
754 std::string defaultSkin
=
755 std::static_pointer_cast
<const CSettingString
>(setting
)->GetDefault();
756 if (!skinHandling
->LoadSkin(defaultSkin
))
758 CLog::Log(LOGFATAL
, "Default skin '{}' could not be loaded! Terminating..", defaultSkin
);
763 // initialize splash window after splash screen disappears
764 // because we need a real window in the background which gets
765 // rendered while we load the main window or enter the master lock key
766 CServiceBroker::GetGUI()->GetWindowManager().ActivateWindow(WINDOW_SPLASH
);
768 if (settings
->GetBool(CSettings::SETTING_MASTERLOCK_STARTUPLOCK
) &&
769 profileManager
->GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE
&&
770 !profileManager
->GetMasterProfile().getLockCode().empty())
772 g_passwordManager
.CheckStartUpLock();
775 // check if we should use the login screen
776 if (profileManager
->UsingLoginScreen())
778 CServiceBroker::GetGUI()->GetWindowManager().ActivateWindow(WINDOW_LOGIN_SCREEN
);
782 // activate the configured start window
783 int firstWindow
= g_SkinInfo
->GetFirstWindow();
784 CServiceBroker::GetGUI()->GetWindowManager().ActivateWindow(firstWindow
);
786 if (CServiceBroker::GetGUI()->GetWindowManager().IsWindowActive(WINDOW_STARTUP_ANIM
))
788 CLog::Log(LOGWARNING
, "CApplication::Initialize - startup.xml taints init process");
791 // the startup window is considered part of the initialization as it most likely switches to the final window
792 uiInitializationFinished
= firstWindow
!= WINDOW_STARTUP_ANIM
;
795 else //No GUI Created
797 uiInitializationFinished
= true;
800 CJSONRPC::Initialize();
802 CServiceBroker::RegisterSpeechRecognition(speech::ISpeechRecognition::CreateInstance());
804 if (!m_ServiceManager
->InitStageThree(profileManager
))
806 CLog::Log(LOGERROR
, "Application - Init3 failed");
811 CLog::Log(LOGINFO
, "removing tempfiles");
812 CUtil::RemoveTempFiles();
814 if (!profileManager
->UsingLoginScreen())
820 m_slowTimer
.StartZero();
822 // register action listeners
823 const auto appListener
= GetComponent
<CApplicationActionListeners
>();
824 const auto appPlayer
= GetComponent
<CApplicationPlayer
>();
825 appListener
->RegisterActionListener(&appPlayer
->GetSeekHandler());
826 appListener
->RegisterActionListener(&CPlayerController::GetInstance());
828 CServiceBroker::GetRepositoryUpdater().Start();
829 if (!profileManager
->UsingLoginScreen())
830 CServiceBroker::GetServiceAddons().Start();
832 CLog::Log(LOGINFO
, "initialize done");
834 const auto appPower
= GetComponent
<CApplicationPowerHandling
>();
835 appPower
->CheckOSScreenSaverInhibitionSetting();
836 // reset our screensaver (starts timers etc.)
837 appPower
->ResetScreenSaver();
839 // if the user interfaces has been fully initialized let everyone know
840 if (uiInitializationFinished
)
842 CGUIMessage
msg(GUI_MSG_NOTIFY_ALL
, 0, 0, GUI_MSG_UI_READY
);
843 CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg
);
849 bool CApplication::OnSettingsSaving() const
851 // don't save settings when we're busy stopping the application
852 // a lot of screens try to save settings on deinit and deinit is
853 // called for every screen when the application is stopping
857 void CApplication::Render()
859 // do not render if we are stopped or in background
863 const auto appPlayer
= GetComponent
<CApplicationPlayer
>();
864 const auto appPower
= GetComponent
<CApplicationPowerHandling
>();
866 bool hasRendered
= false;
868 // Whether externalplayer is playing and we're unfocused
869 bool extPlayerActive
= appPlayer
->IsExternalPlaying() && !m_AppFocused
;
871 if (!extPlayerActive
&& CServiceBroker::GetWinSystem()->GetGfxContext().IsFullScreenVideo() &&
872 !appPlayer
->IsPausedPlayback())
874 appPower
->ResetScreenSaver();
877 if (!CServiceBroker::GetRenderSystem()->BeginRender())
881 if (appPower
->GetRenderGUI() && !m_skipGuiRender
)
883 if (CServiceBroker::GetWinSystem()->GetGfxContext().GetStereoMode())
885 CServiceBroker::GetWinSystem()->GetGfxContext().SetStereoView(RENDER_STEREO_VIEW_LEFT
);
886 hasRendered
|= CServiceBroker::GetGUI()->GetWindowManager().Render();
888 if (CServiceBroker::GetWinSystem()->GetGfxContext().GetStereoMode() != RENDER_STEREO_MODE_MONO
)
890 CServiceBroker::GetWinSystem()->GetGfxContext().SetStereoView(RENDER_STEREO_VIEW_RIGHT
);
891 hasRendered
|= CServiceBroker::GetGUI()->GetWindowManager().Render();
893 CServiceBroker::GetWinSystem()->GetGfxContext().SetStereoView(RENDER_STEREO_VIEW_OFF
);
897 hasRendered
|= CServiceBroker::GetGUI()->GetWindowManager().Render();
899 // execute post rendering actions (finalize window closing)
900 CServiceBroker::GetGUI()->GetWindowManager().AfterRender();
902 m_lastRenderTime
= std::chrono::steady_clock::now();
905 // render video layer
906 CServiceBroker::GetGUI()->GetWindowManager().RenderEx();
908 CServiceBroker::GetRenderSystem()->EndRender();
910 // reset our info cache - we do this at the end of Render so that it is
911 // fresh for the next process(), or after a windowclose animation (where process()
913 CGUIInfoManager
& infoMgr
= CServiceBroker::GetGUI()->GetInfoManager();
914 infoMgr
.ResetCache();
915 infoMgr
.GetInfoProviders().GetGUIControlsInfoProvider().ResetContainerMovingCache();
919 infoMgr
.GetInfoProviders().GetSystemInfoProvider().UpdateFPS();
922 CServiceBroker::GetWinSystem()->GetGfxContext().Flip(hasRendered
,
923 appPlayer
->IsRenderingVideoLayer());
925 CTimeUtils::UpdateFrameTime(hasRendered
);
928 bool CApplication::OnAction(const CAction
&action
)
930 // special case for switching between GUI & fullscreen mode.
931 if (action
.GetID() == ACTION_SHOW_GUI
)
932 { // Switch to fullscreen mode if we can
933 CGUIComponent
* gui
= CServiceBroker::GetGUI();
936 if (gui
->GetWindowManager().SwitchToFullScreen())
938 GetComponent
<CApplicationPowerHandling
>()->m_navigationTimer
.StartZero();
944 const auto appPlayer
= GetComponent
<CApplicationPlayer
>();
946 if (action
.GetID() == ACTION_TOGGLE_FULLSCREEN
)
948 CServiceBroker::GetWinSystem()->GetGfxContext().ToggleFullScreen();
949 appPlayer
->TriggerUpdateResolution();
953 if (action
.IsMouse())
954 CServiceBroker::GetInputManager().SetMouseActive(true);
956 if (action
.GetID() == ACTION_CREATE_EPISODE_BOOKMARK
)
958 CGUIDialogVideoBookmarks::OnAddEpisodeBookmark();
960 if (action
.GetID() == ACTION_CREATE_BOOKMARK
)
962 CGUIDialogVideoBookmarks::OnAddBookmark();
965 // The action PLAYPAUSE behaves as ACTION_PAUSE if we are currently
966 // playing or ACTION_PLAYER_PLAY if we are seeking (FF/RW) or not playing.
967 if (action
.GetID() == ACTION_PLAYER_PLAYPAUSE
)
969 CSlideShowDelegator
& slideShow
= CServiceBroker::GetSlideShowDelegator();
970 if ((appPlayer
->IsPlaying() && appPlayer
->GetPlaySpeed() == 1) ||
971 (slideShow
.InSlideShow() && !slideShow
.IsPaused()))
972 return OnAction(CAction(ACTION_PAUSE
));
974 return OnAction(CAction(ACTION_PLAYER_PLAY
));
977 //if the action would start or stop inertial scrolling
978 //by gesture - bypass the normal OnAction handler of current window
979 if( !m_pInertialScrollingHandler
->CheckForInertialScrolling(&action
) )
982 // just pass the action to the current window and let it handle it
983 if (CServiceBroker::GetGUI()->GetWindowManager().OnAction(action
))
985 GetComponent
<CApplicationPowerHandling
>()->ResetNavigationTimer();
990 // handle extra global presses
992 // notify action listeners
993 if (GetComponent
<CApplicationActionListeners
>()->NotifyActionListeners(action
))
996 // screenshot : take a screenshot :)
997 if (action
.GetID() == ACTION_TAKE_SCREENSHOT
)
999 CScreenShot::TakeScreenshot();
1002 // Display HDR : toggle HDR on/off
1003 if (action
.GetID() == ACTION_HDR_TOGGLE
)
1005 // Only enables manual HDR toggle if no video is playing or auto HDR switch is disabled
1006 if (appPlayer
->IsPlayingVideo() && CServiceBroker::GetWinSystem()->IsHDRDisplaySettingEnabled())
1009 HDR_STATUS hdrStatus
= CServiceBroker::GetWinSystem()->ToggleHDR();
1011 if (hdrStatus
== HDR_STATUS::HDR_OFF
)
1013 CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Info
, g_localizeStrings
.Get(34220),
1014 g_localizeStrings
.Get(34221));
1016 else if (hdrStatus
== HDR_STATUS::HDR_ON
)
1018 CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Info
, g_localizeStrings
.Get(34220),
1019 g_localizeStrings
.Get(34222));
1023 // Tone Mapping : switch to next tone map method
1024 if (action
.GetID() == ACTION_CYCLE_TONEMAP_METHOD
)
1026 // Only enables tone mapping switch if display is not HDR capable or HDR is not enabled
1027 if (CServiceBroker::GetWinSystem()->IsHDRDisplaySettingEnabled())
1030 if (appPlayer
->IsPlayingVideo())
1032 CVideoSettings vs
= appPlayer
->GetVideoSettings();
1033 vs
.m_ToneMapMethod
= static_cast<ETONEMAPMETHOD
>(static_cast<int>(vs
.m_ToneMapMethod
) + 1);
1034 if (vs
.m_ToneMapMethod
>= VS_TONEMAPMETHOD_MAX
)
1035 vs
.m_ToneMapMethod
=
1036 static_cast<ETONEMAPMETHOD
>(static_cast<int>(VS_TONEMAPMETHOD_OFF
) + 1);
1038 appPlayer
->SetVideoSettings(vs
);
1041 switch (vs
.m_ToneMapMethod
)
1043 case VS_TONEMAPMETHOD_REINHARD
:
1046 case VS_TONEMAPMETHOD_ACES
:
1049 case VS_TONEMAPMETHOD_HABLE
:
1053 throw std::logic_error("Tonemapping method not found. Did you forget to add a mapping?");
1055 CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Info
, g_localizeStrings
.Get(34224),
1056 g_localizeStrings
.Get(code
), 1000, false, 500);
1060 // built in functions : execute the built-in
1061 if (action
.GetID() == ACTION_BUILT_IN_FUNCTION
)
1063 if (!CBuiltins::GetInstance().IsSystemPowerdownCommand(action
.GetName()) ||
1064 CServiceBroker::GetPVRManager().Get
<PVR::GUI::PowerManagement
>().CanSystemPowerdown())
1066 CBuiltins::GetInstance().Execute(action
.GetName());
1067 GetComponent
<CApplicationPowerHandling
>()->ResetNavigationTimer();
1073 if (action
.GetID() == ACTION_RELOAD_KEYMAPS
)
1074 CServiceBroker::GetInputManager().ReloadKeymaps();
1076 // show info : Shows the current video or song information
1077 if (action
.GetID() == ACTION_SHOW_INFO
)
1079 CServiceBroker::GetGUI()->GetInfoManager().GetInfoProviders().GetPlayerInfoProvider().ToggleShowInfo();
1083 if (action
.GetID() == ACTION_SET_RATING
&& appPlayer
->IsPlayingAudio())
1085 int userrating
= MUSIC_UTILS::ShowSelectRatingDialog(m_itemCurrentFile
->GetMusicInfoTag()->GetUserrating());
1086 if (userrating
< 0) // Nothing selected, so user rating unchanged
1088 userrating
= std::min(userrating
, 10);
1089 if (userrating
!= m_itemCurrentFile
->GetMusicInfoTag()->GetUserrating())
1091 m_itemCurrentFile
->GetMusicInfoTag()->SetUserrating(userrating
);
1092 // Mirror changes to GUI item
1093 CServiceBroker::GetGUI()->GetInfoManager().SetCurrentItem(*m_itemCurrentFile
);
1095 // Asynchronously update song userrating in music library
1096 MUSIC_UTILS::UpdateSongRatingJob(m_itemCurrentFile
, userrating
);
1098 // Tell all windows (e.g. playlistplayer, media windows) to update the fileitem
1099 CGUIMessage
msg(GUI_MSG_NOTIFY_ALL
, 0, 0, GUI_MSG_UPDATE_ITEM
, 0, m_itemCurrentFile
);
1100 CServiceBroker::GetGUI()->GetWindowManager().SendMessage(msg
);
1105 else if ((action
.GetID() == ACTION_INCREASE_RATING
|| action
.GetID() == ACTION_DECREASE_RATING
) &&
1106 appPlayer
->IsPlayingAudio())
1108 int userrating
= m_itemCurrentFile
->GetMusicInfoTag()->GetUserrating();
1109 bool needsUpdate(false);
1110 if (userrating
> 0 && action
.GetID() == ACTION_DECREASE_RATING
)
1112 m_itemCurrentFile
->GetMusicInfoTag()->SetUserrating(userrating
- 1);
1115 else if (userrating
< 10 && action
.GetID() == ACTION_INCREASE_RATING
)
1117 m_itemCurrentFile
->GetMusicInfoTag()->SetUserrating(userrating
+ 1);
1122 // Mirror changes to current GUI item
1123 CServiceBroker::GetGUI()->GetInfoManager().SetCurrentItem(*m_itemCurrentFile
);
1125 // Asynchronously update song userrating in music library
1126 MUSIC_UTILS::UpdateSongRatingJob(m_itemCurrentFile
, m_itemCurrentFile
->GetMusicInfoTag()->GetUserrating());
1128 // send a message to all windows to tell them to update the fileitem (eg playlistplayer, media windows)
1129 CGUIMessage
msg(GUI_MSG_NOTIFY_ALL
, 0, 0, GUI_MSG_UPDATE_ITEM
, 0, m_itemCurrentFile
);
1130 CServiceBroker::GetGUI()->GetWindowManager().SendMessage(msg
);
1135 else if ((action
.GetID() == ACTION_INCREASE_RATING
|| action
.GetID() == ACTION_DECREASE_RATING
) &&
1136 appPlayer
->IsPlayingVideo())
1138 int rating
= m_itemCurrentFile
->GetVideoInfoTag()->m_iUserRating
;
1139 bool needsUpdate(false);
1140 if (rating
> 1 && action
.GetID() == ACTION_DECREASE_RATING
)
1142 m_itemCurrentFile
->GetVideoInfoTag()->m_iUserRating
= rating
- 1;
1145 else if (rating
< 10 && action
.GetID() == ACTION_INCREASE_RATING
)
1147 m_itemCurrentFile
->GetVideoInfoTag()->m_iUserRating
= rating
+ 1;
1152 // Mirror changes to GUI item
1153 CServiceBroker::GetGUI()->GetInfoManager().SetCurrentItem(*m_itemCurrentFile
);
1158 db
.SetVideoUserRating(m_itemCurrentFile
->GetVideoInfoTag()->m_iDbId
,
1159 m_itemCurrentFile
->GetVideoInfoTag()->m_iUserRating
,
1160 m_itemCurrentFile
->GetVideoInfoTag()->m_type
);
1163 // send a message to all windows to tell them to update the fileitem (eg playlistplayer, media windows)
1164 CGUIMessage
msg(GUI_MSG_NOTIFY_ALL
, 0, 0, GUI_MSG_UPDATE_ITEM
, 0, m_itemCurrentFile
);
1165 CServiceBroker::GetGUI()->GetWindowManager().SendMessage(msg
);
1170 // Now check with the playlist player if action can be handled.
1171 // In case of ACTION_PREV_ITEM, we only allow the playlist player to take it if we're less than ACTION_PREV_ITEM_THRESHOLD seconds into playback.
1172 if (!(action
.GetID() == ACTION_PREV_ITEM
&& appPlayer
->CanSeek() &&
1173 GetTime() > ACTION_PREV_ITEM_THRESHOLD
))
1175 if (CServiceBroker::GetPlaylistPlayer().OnAction(action
))
1179 // Now check with the player if action can be handled.
1180 bool bIsPlayingPVRChannel
= (CServiceBroker::GetPVRManager().IsStarted() &&
1181 CurrentFileItem().IsPVRChannel());
1183 bool bNotifyPlayer
= false;
1184 if (CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow() == WINDOW_FULLSCREEN_VIDEO
)
1185 bNotifyPlayer
= true;
1186 else if (CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow() == WINDOW_FULLSCREEN_GAME
)
1187 bNotifyPlayer
= true;
1188 else if (CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow() == WINDOW_VISUALISATION
&& bIsPlayingPVRChannel
)
1189 bNotifyPlayer
= true;
1190 else if (CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow() == WINDOW_DIALOG_VIDEO_OSD
||
1191 (CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow() == WINDOW_DIALOG_MUSIC_OSD
&& bIsPlayingPVRChannel
))
1193 switch (action
.GetID())
1195 case ACTION_NEXT_ITEM
:
1196 case ACTION_PREV_ITEM
:
1197 case ACTION_CHANNEL_UP
:
1198 case ACTION_CHANNEL_DOWN
:
1199 bNotifyPlayer
= true;
1205 else if (action
.GetID() == ACTION_STOP
)
1206 bNotifyPlayer
= true;
1210 if (appPlayer
->OnAction(action
))
1214 // stop : stops playing current audio song
1215 if (action
.GetID() == ACTION_STOP
)
1221 // In case the playlist player nor the player didn't handle PREV_ITEM, because we are past the ACTION_PREV_ITEM_THRESHOLD secs limit.
1222 // If so, we just jump to the start of the track.
1223 if (action
.GetID() == ACTION_PREV_ITEM
&& appPlayer
->CanSeek())
1226 appPlayer
->SetPlaySpeed(1);
1230 // forward action to graphic context and see if it can handle it
1231 if (CServiceBroker::GetGUI()->GetStereoscopicsManager().OnAction(action
))
1234 if (appPlayer
->IsPlaying())
1236 // forward channel switches to the player - he knows what to do
1237 if (action
.GetID() == ACTION_CHANNEL_UP
|| action
.GetID() == ACTION_CHANNEL_DOWN
)
1239 appPlayer
->OnAction(action
);
1243 // pause : toggle pause action
1244 if (action
.GetID() == ACTION_PAUSE
)
1247 // go back to normal play speed on unpause
1248 if (!appPlayer
->IsPaused() && appPlayer
->GetPlaySpeed() != 1)
1249 appPlayer
->SetPlaySpeed(1);
1251 CGUIComponent
*gui
= CServiceBroker::GetGUI();
1253 gui
->GetAudioManager().Enable(appPlayer
->IsPaused());
1256 // play: unpause or set playspeed back to normal
1257 if (action
.GetID() == ACTION_PLAYER_PLAY
)
1259 // if currently paused - unpause
1260 if (appPlayer
->IsPaused())
1261 return OnAction(CAction(ACTION_PAUSE
));
1262 // if we do a FF/RW then go back to normal speed
1263 if (appPlayer
->GetPlaySpeed() != 1)
1264 appPlayer
->SetPlaySpeed(1);
1267 if (!appPlayer
->IsPaused())
1269 if (action
.GetID() == ACTION_PLAYER_FORWARD
|| action
.GetID() == ACTION_PLAYER_REWIND
)
1271 float playSpeed
= appPlayer
->GetPlaySpeed();
1273 if (action
.GetID() == ACTION_PLAYER_REWIND
&& (playSpeed
== 1)) // Enables Rewinding
1275 else if (action
.GetID() == ACTION_PLAYER_REWIND
&& playSpeed
> 1) //goes down a notch if you're FFing
1277 else if (action
.GetID() == ACTION_PLAYER_FORWARD
&& playSpeed
< 1) //goes up a notch if you're RWing
1282 if (action
.GetID() == ACTION_PLAYER_FORWARD
&& playSpeed
== -1) //sets iSpeed back to 1 if -1 (didn't plan for a -1)
1284 if (playSpeed
> 32 || playSpeed
< -32)
1287 appPlayer
->SetPlaySpeed(playSpeed
);
1290 else if ((action
.GetAmount() || appPlayer
->GetPlaySpeed() != 1) &&
1291 (action
.GetID() == ACTION_ANALOG_REWIND
|| action
.GetID() == ACTION_ANALOG_FORWARD
))
1293 // calculate the speed based on the amount the button is held down
1294 int iPower
= (int)(action
.GetAmount() * MAX_FFWD_SPEED
+ 0.5f
);
1295 // amount can be negative, for example rewind and forward share the same axis
1296 iPower
= std::abs(iPower
);
1297 // returns 0 -> MAX_FFWD_SPEED
1298 int iSpeed
= 1 << iPower
;
1299 if (iSpeed
!= 1 && action
.GetID() == ACTION_ANALOG_REWIND
)
1301 appPlayer
->SetPlaySpeed(static_cast<float>(iSpeed
));
1303 CLog::Log(LOGDEBUG
,"Resetting playspeed");
1306 else if (action
.GetID() == ACTION_PLAYER_INCREASE_TEMPO
)
1308 CPlayerUtils::AdvanceTempoStep(appPlayer
, TempoStepChange::INCREASE
);
1311 else if (action
.GetID() == ACTION_PLAYER_DECREASE_TEMPO
)
1313 CPlayerUtils::AdvanceTempoStep(appPlayer
, TempoStepChange::DECREASE
);
1317 // allow play to unpause
1320 if (action
.GetID() == ACTION_PLAYER_PLAY
)
1322 // unpause, and set the playspeed back to normal
1325 CGUIComponent
*gui
= CServiceBroker::GetGUI();
1327 gui
->GetAudioManager().Enable(appPlayer
->IsPaused());
1329 appPlayer
->SetPlaySpeed(1);
1336 if (action
.GetID() == ACTION_SWITCH_PLAYER
)
1338 const CPlayerCoreFactory
&playerCoreFactory
= m_ServiceManager
->GetPlayerCoreFactory();
1340 if (appPlayer
->IsPlaying())
1342 std::vector
<std::string
> players
;
1343 CFileItem
item(*m_itemCurrentFile
.get());
1344 playerCoreFactory
.GetPlayers(item
, players
);
1345 std::string player
= playerCoreFactory
.SelectPlayerDialog(players
);
1346 if (!player
.empty())
1348 item
.SetStartOffset(CUtil::ConvertSecsToMilliSecs(GetTime()));
1349 PlayFile(item
, player
, true);
1354 std::vector
<std::string
> players
;
1355 playerCoreFactory
.GetRemotePlayers(players
);
1356 std::string player
= playerCoreFactory
.SelectPlayerDialog(players
);
1357 if (!player
.empty())
1359 PlayFile(CFileItem(), player
, false);
1364 if (CServiceBroker::GetPeripherals().OnAction(action
))
1367 if (action
.GetID() == ACTION_MUTE
)
1369 const auto appVolume
= GetComponent
<CApplicationVolumeHandling
>();
1370 appVolume
->ToggleMute();
1371 appVolume
->ShowVolumeBar(&action
);
1375 if (action
.GetID() == ACTION_TOGGLE_DIGITAL_ANALOG
)
1377 const std::shared_ptr
<CSettings
> settings
= CServiceBroker::GetSettingsComponent()->GetSettings();
1378 bool passthrough
= settings
->GetBool(CSettings::SETTING_AUDIOOUTPUT_PASSTHROUGH
);
1379 settings
->SetBool(CSettings::SETTING_AUDIOOUTPUT_PASSTHROUGH
, !passthrough
);
1381 if (CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow() == WINDOW_SETTINGS_SYSTEM
)
1383 CGUIMessage
msg(GUI_MSG_WINDOW_INIT
, 0,0,WINDOW_INVALID
,CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow());
1384 CServiceBroker::GetGUI()->GetWindowManager().SendMessage(msg
);
1389 // Check for global volume control
1390 if ((action
.GetAmount() && (action
.GetID() == ACTION_VOLUME_UP
|| action
.GetID() == ACTION_VOLUME_DOWN
)) || action
.GetID() == ACTION_VOLUME_SET
)
1392 const auto appVolume
= GetComponent
<CApplicationVolumeHandling
>();
1393 if (!appPlayer
->IsPassthrough())
1395 if (appVolume
->IsMuted())
1396 appVolume
->UnMute();
1397 float volume
= appVolume
->GetVolumeRatio();
1398 int volumesteps
= CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_AUDIOOUTPUT_VOLUMESTEPS
);
1400 if (volumesteps
== 0)
1403 // Android has steps based on the max available volume level
1404 #if defined(TARGET_ANDROID)
1405 float step
= (CApplicationVolumeHandling::VOLUME_MAXIMUM
-
1406 CApplicationVolumeHandling::VOLUME_MINIMUM
) /
1407 CXBMCApp::GetMaxSystemVolume();
1409 float step
= (CApplicationVolumeHandling::VOLUME_MAXIMUM
-
1410 CApplicationVolumeHandling::VOLUME_MINIMUM
) /
1413 if (action
.GetRepeat())
1414 step
*= action
.GetRepeat() * 50; // 50 fps
1416 if (action
.GetID() == ACTION_VOLUME_UP
)
1417 volume
+= action
.GetAmount() * action
.GetAmount() * step
;
1418 else if (action
.GetID() == ACTION_VOLUME_DOWN
)
1419 volume
-= action
.GetAmount() * action
.GetAmount() * step
;
1421 volume
= action
.GetAmount() * step
;
1422 if (volume
!= appVolume
->GetVolumeRatio())
1423 appVolume
->SetVolume(volume
, false);
1425 // show visual feedback of volume or passthrough indicator
1426 appVolume
->ShowVolumeBar(&action
);
1430 if (action
.GetID() == ACTION_GUIPROFILE_BEGIN
)
1432 CGUIControlProfiler::Instance().SetOutputFile(CSpecialProtocol::TranslatePath("special://home/guiprofiler.xml"));
1433 CGUIControlProfiler::Instance().Start();
1436 if (action
.GetID() == ACTION_SHOW_PLAYLIST
)
1438 const PLAYLIST::Id playlistId
= CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist();
1439 if (playlistId
== PLAYLIST::TYPE_VIDEO
&&
1440 CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow() != WINDOW_VIDEO_PLAYLIST
)
1442 CServiceBroker::GetGUI()->GetWindowManager().ActivateWindow(WINDOW_VIDEO_PLAYLIST
);
1444 else if (playlistId
== PLAYLIST::TYPE_MUSIC
&&
1445 CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow() !=
1446 WINDOW_MUSIC_PLAYLIST
)
1448 CServiceBroker::GetGUI()->GetWindowManager().ActivateWindow(WINDOW_MUSIC_PLAYLIST
);
1455 int CApplication::GetMessageMask()
1457 return TMSG_MASK_APPLICATION
;
1460 void CApplication::OnApplicationMessage(ThreadMessage
* pMsg
)
1462 uint32_t msg
= pMsg
->dwMessage
;
1463 if (msg
== TMSG_SYSTEM_POWERDOWN
)
1465 if (CServiceBroker::GetPVRManager().Get
<PVR::GUI::PowerManagement
>().CanSystemPowerdown())
1466 msg
= pMsg
->param1
; // perform requested shutdown action
1468 return; // no shutdown
1471 const auto appPlayer
= GetComponent
<CApplicationPlayer
>();
1475 case TMSG_POWERDOWN
:
1476 if (Stop(EXITCODE_POWERDOWN
))
1477 CServiceBroker::GetPowerManager().Powerdown();
1481 Stop(EXITCODE_QUIT
);
1485 GetComponent
<CApplicationPowerHandling
>()->HandleShutdownMessage();
1488 case TMSG_RENDERER_FLUSH
:
1489 appPlayer
->FlushRenderer();
1492 case TMSG_HIBERNATE
:
1493 CServiceBroker::GetPowerManager().Hibernate();
1497 CServiceBroker::GetPowerManager().Suspend();
1502 if (Stop(EXITCODE_REBOOT
))
1503 CServiceBroker::GetPowerManager().Reboot();
1506 case TMSG_RESTARTAPP
:
1507 #if defined(TARGET_WINDOWS) || defined(TARGET_LINUX)
1508 Stop(EXITCODE_RESTARTAPP
);
1512 case TMSG_INHIBITIDLESHUTDOWN
:
1513 GetComponent
<CApplicationPowerHandling
>()->InhibitIdleShutdown(pMsg
->param1
!= 0);
1516 case TMSG_INHIBITSCREENSAVER
:
1517 GetComponent
<CApplicationPowerHandling
>()->InhibitScreenSaver(pMsg
->param1
!= 0);
1520 case TMSG_ACTIVATESCREENSAVER
:
1521 GetComponent
<CApplicationPowerHandling
>()->ActivateScreenSaver();
1524 case TMSG_RESETSCREENSAVER
:
1525 GetComponent
<CApplicationPowerHandling
>()->m_bResetScreenSaver
= true;
1528 case TMSG_VOLUME_SHOW
:
1530 CAction
action(pMsg
->param1
);
1531 GetComponent
<CApplicationVolumeHandling
>()->ShowVolumeBar(&action
);
1535 #ifdef TARGET_ANDROID
1536 case TMSG_DISPLAY_SETUP
:
1537 // We might come from a refresh rate switch destroying the native window; use the context resolution
1538 *static_cast<bool*>(pMsg
->lpVoid
) = InitWindow(CServiceBroker::GetWinSystem()->GetGfxContext().GetVideoResolution());
1539 GetComponent
<CApplicationPowerHandling
>()->SetRenderGUI(true);
1542 case TMSG_DISPLAY_DESTROY
:
1543 *static_cast<bool*>(pMsg
->lpVoid
) = CServiceBroker::GetWinSystem()->DestroyWindow();
1544 GetComponent
<CApplicationPowerHandling
>()->SetRenderGUI(false);
1548 case TMSG_START_ANDROID_ACTIVITY
:
1550 #if defined(TARGET_ANDROID)
1551 if (pMsg
->params
.size())
1553 CXBMCApp::StartActivity(pMsg
->params
[0], pMsg
->params
.size() > 1 ? pMsg
->params
[1] : "",
1554 pMsg
->params
.size() > 2 ? pMsg
->params
[2] : "",
1555 pMsg
->params
.size() > 3 ? pMsg
->params
[3] : "",
1556 pMsg
->params
.size() > 4 ? pMsg
->params
[4] : "",
1557 pMsg
->params
.size() > 5 ? pMsg
->params
[5] : "",
1558 pMsg
->params
.size() > 6 ? pMsg
->params
[6] : "",
1559 pMsg
->params
.size() > 7 ? pMsg
->params
[7] : "",
1560 pMsg
->params
.size() > 8 ? pMsg
->params
[8] : "");
1566 case TMSG_NETWORKMESSAGE
:
1567 m_ServiceManager
->GetNetwork().NetworkMessage(static_cast<CNetworkBase::EMESSAGE
>(pMsg
->param1
),
1571 case TMSG_SETLANGUAGE
:
1572 SetLanguage(pMsg
->strParam
);
1576 case TMSG_SWITCHTOFULLSCREEN
:
1578 CGUIComponent
* gui
= CServiceBroker::GetGUI();
1580 gui
->GetWindowManager().SwitchToFullScreen(true);
1583 case TMSG_VIDEORESIZE
:
1585 XBMC_Event newEvent
= {};
1586 newEvent
.type
= XBMC_VIDEORESIZE
;
1587 newEvent
.resize
.w
= pMsg
->param1
;
1588 newEvent
.resize
.h
= pMsg
->param2
;
1590 CServiceBroker::GetGUI()->GetWindowManager().MarkDirty();
1594 case TMSG_SETVIDEORESOLUTION
:
1595 CServiceBroker::GetWinSystem()->GetGfxContext().SetVideoResolution(static_cast<RESOLUTION
>(pMsg
->param1
), pMsg
->param2
== 1);
1598 case TMSG_TOGGLEFULLSCREEN
:
1599 CServiceBroker::GetWinSystem()->GetGfxContext().ToggleFullScreen();
1600 appPlayer
->TriggerUpdateResolution();
1603 case TMSG_MOVETOSCREEN
:
1604 CServiceBroker::GetWinSystem()->MoveToScreen(static_cast<int>(pMsg
->param1
));
1608 CServiceBroker::GetWinSystem()->Minimize();
1611 case TMSG_EXECUTE_OS
:
1612 // Suspend AE temporarily so exclusive or hog-mode sinks
1613 // don't block external player's access to audio device
1615 audioengine
= CServiceBroker::GetActiveAE();
1618 if (!audioengine
->Suspend())
1620 CLog::Log(LOGINFO
, "{}: Failed to suspend AudioEngine before launching external program",
1624 #if defined(TARGET_DARWIN)
1625 CLog::Log(LOGINFO
, "ExecWait is not implemented on this platform");
1626 #elif defined(TARGET_POSIX)
1627 CUtil::RunCommandLine(pMsg
->strParam
, (pMsg
->param1
== 1));
1628 #elif defined(TARGET_WINDOWS)
1629 CWIN32Util::XBMCShellExecute(pMsg
->strParam
.c_str(), (pMsg
->param1
== 1));
1631 // Resume AE processing of XBMC native audio
1634 if (!audioengine
->Resume())
1636 CLog::Log(LOGFATAL
, "{}: Failed to restart AudioEngine after return from external player",
1642 case TMSG_EXECUTE_SCRIPT
:
1643 CScriptInvocationManager::GetInstance().ExecuteAsync(pMsg
->strParam
);
1646 case TMSG_EXECUTE_BUILT_IN
:
1647 CBuiltins::GetInstance().Execute(pMsg
->strParam
);
1650 case TMSG_PICTURE_SHOW
:
1652 CSlideShowDelegator
& slideShow
= CServiceBroker::GetSlideShowDelegator();
1654 // stop playing file
1655 if (appPlayer
->IsPlayingVideo())
1658 if (CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow() == WINDOW_FULLSCREEN_VIDEO
)
1659 CServiceBroker::GetGUI()->GetWindowManager().PreviousWindow();
1661 const auto appPower
= GetComponent
<CApplicationPowerHandling
>();
1662 appPower
->ResetScreenSaver();
1663 appPower
->WakeUpScreenSaverAndDPMS();
1665 if (CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow() != WINDOW_SLIDESHOW
)
1666 CServiceBroker::GetGUI()->GetWindowManager().ActivateWindow(WINDOW_SLIDESHOW
);
1667 if (URIUtils::IsZIP(pMsg
->strParam
) || URIUtils::IsRAR(pMsg
->strParam
)) // actually a cbz/cbr
1669 CFileItemList items
;
1671 if (URIUtils::IsZIP(pMsg
->strParam
))
1672 pathToUrl
= URIUtils::CreateArchivePath("zip", CURL(pMsg
->strParam
), "");
1674 pathToUrl
= URIUtils::CreateArchivePath("rar", CURL(pMsg
->strParam
), "");
1676 CUtil::GetRecursiveListing(pathToUrl
.Get(), items
, CServiceBroker::GetFileExtensionProvider().GetPictureExtensions(), XFILE::DIR_FLAG_NO_FILE_DIRS
);
1677 if (items
.Size() > 0)
1680 for (int i
= 0; i
<items
.Size(); ++i
)
1682 slideShow
.Add(items
[i
].get());
1684 slideShow
.Select(items
[0]->GetPath());
1689 CFileItem
item(pMsg
->strParam
, false);
1691 slideShow
.Add(&item
);
1692 slideShow
.Select(pMsg
->strParam
);
1697 case TMSG_PICTURE_SLIDESHOW
:
1699 CSlideShowDelegator
& slideShow
= CServiceBroker::GetSlideShowDelegator();
1701 if (appPlayer
->IsPlayingVideo())
1706 CFileItemList items
;
1707 std::string strPath
= pMsg
->strParam
;
1708 std::string extensions
= CServiceBroker::GetFileExtensionProvider().GetPictureExtensions();
1710 extensions
+= "|.tbn";
1711 CUtil::GetRecursiveListing(strPath
, items
, extensions
);
1713 if (items
.Size() > 0)
1715 for (int i
= 0; i
<items
.Size(); ++i
)
1716 slideShow
.Add(items
[i
].get());
1717 slideShow
.StartSlideShow(); //Start the slideshow!
1720 if (CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow() != WINDOW_SLIDESHOW
)
1722 if (items
.Size() == 0)
1724 CServiceBroker::GetSettingsComponent()->GetSettings()->SetString(CSettings::SETTING_SCREENSAVER_MODE
, "screensaver.xbmc.builtin.dim");
1725 GetComponent
<CApplicationPowerHandling
>()->ActivateScreenSaver();
1728 CServiceBroker::GetGUI()->GetWindowManager().ActivateWindow(WINDOW_SLIDESHOW
);
1734 case TMSG_LOADPROFILE
:
1736 const int profile
= pMsg
->param1
;
1738 CServiceBroker::GetSettingsComponent()->GetProfileManager()->LoadProfile(static_cast<unsigned int>(profile
));
1747 XBMC_Event
* event
= static_cast<XBMC_Event
*>(pMsg
->lpVoid
);
1754 case TMSG_UPDATE_PLAYER_ITEM
:
1756 std::unique_ptr
<CFileItem
> item
{static_cast<CFileItem
*>(pMsg
->lpVoid
)};
1759 m_itemCurrentFile
->UpdateInfo(*item
);
1760 CServiceBroker::GetGUI()->GetInfoManager().UpdateCurrentItem(*m_itemCurrentFile
);
1765 case TMSG_SET_VOLUME
:
1767 const float volumedB
= static_cast<float>(pMsg
->param3
);
1768 GetComponent
<CApplicationVolumeHandling
>()->SetVolume(volumedB
);
1774 GetComponent
<CApplicationVolumeHandling
>()->SetMute(pMsg
->param3
== 1 ? true : false);
1779 CLog::Log(LOGERROR
, "{}: Unhandled threadmessage sent, {}", __FUNCTION__
, msg
);
1784 void CApplication::LockFrameMoveGuard()
1786 ++m_WaitingExternalCalls
;
1787 m_frameMoveGuard
.lock();
1788 ++m_ProcessedExternalCalls
;
1789 CServiceBroker::GetWinSystem()->GetGfxContext().lock();
1792 void CApplication::UnlockFrameMoveGuard()
1794 --m_WaitingExternalCalls
;
1795 CServiceBroker::GetWinSystem()->GetGfxContext().unlock();
1796 m_frameMoveGuard
.unlock();
1799 void CApplication::FrameMove(bool processEvents
, bool processGUI
)
1801 const auto appPlayer
= GetComponent
<CApplicationPlayer
>();
1802 bool renderGUI
= GetComponent
<CApplicationPowerHandling
>()->GetRenderGUI();
1805 // currently we calculate the repeat time (ie time from last similar keypress) just global as fps
1806 float frameTime
= m_frameTime
.GetElapsedSeconds();
1807 m_frameTime
.StartZero();
1808 // never set a frametime less than 2 fps to avoid problems when debugging and on breaks
1809 if (frameTime
> 0.5f
)
1812 if (processGUI
&& renderGUI
)
1814 std::unique_lock
<CCriticalSection
> lock(CServiceBroker::GetWinSystem()->GetGfxContext());
1815 // check if there are notifications to display
1816 CGUIDialogKaiToast
*toast
= CServiceBroker::GetGUI()->GetWindowManager().GetWindow
<CGUIDialogKaiToast
>(WINDOW_DIALOG_KAI_TOAST
);
1817 if (toast
&& toast
->DoWork())
1819 if (!toast
->IsDialogRunning())
1827 CServiceBroker::GetInputManager().Process(CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindowOrDialog(), frameTime
);
1829 if (processGUI
&& renderGUI
)
1831 m_pInertialScrollingHandler
->ProcessInertialScroll(frameTime
);
1832 appPlayer
->GetSeekHandler().FrameMove();
1835 // Open the door for external calls e.g python exactly here.
1836 // Window size can be between 2 and 10ms and depends on number of continuous requests
1837 if (m_WaitingExternalCalls
)
1839 CSingleExit
ex(CServiceBroker::GetWinSystem()->GetGfxContext());
1840 m_frameMoveGuard
.unlock();
1842 // Calculate a window size between 2 and 10ms, 4 continuous requests let the window grow by 1ms
1843 // When not playing video we allow it to increase to 80ms
1844 unsigned int max_sleep
= 10;
1845 if (!appPlayer
->IsPlayingVideo() || appPlayer
->IsPausedPlayback())
1847 unsigned int sleepTime
= std::max(static_cast<unsigned int>(2), std::min(m_ProcessedExternalCalls
>> 2, max_sleep
));
1848 KODI::TIME::Sleep(std::chrono::milliseconds(sleepTime
));
1849 m_frameMoveGuard
.lock();
1850 m_ProcessedExternalDecay
= 5;
1852 if (m_ProcessedExternalDecay
&& --m_ProcessedExternalDecay
== 0)
1853 m_ProcessedExternalCalls
= 0;
1856 if (processGUI
&& renderGUI
)
1858 m_skipGuiRender
= false;
1860 /*! @todo look into the possibility to use this for GBM
1863 // This code reduces rendering fps of the GUI layer when playing videos in fullscreen mode
1864 // it makes only sense on architectures with multiple layers
1865 if (CServiceBroker::GetWinSystem()->GetGfxContext().IsFullScreenVideo() && !m_appPlayer.IsPausedPlayback() && m_appPlayer.IsRenderingVideoLayer())
1866 fps = CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_VIDEOPLAYER_LIMITGUIUPDATE);
1868 auto now = std::chrono::steady_clock::now();
1870 auto frameTime = std::chrono::duration_cast<std::chrono::milliseconds>(now - m_lastRenderTime).count();
1871 if (fps > 0 && frameTime * fps < 1000)
1872 m_skipGuiRender = true;
1875 if (CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_guiSmartRedraw
&& m_guiRefreshTimer
.IsTimePast())
1877 CServiceBroker::GetGUI()->GetWindowManager().SendMessage(GUI_MSG_REFRESH_TIMER
, 0, 0);
1878 m_guiRefreshTimer
.Set(500ms
);
1883 if (!m_skipGuiRender
)
1884 CServiceBroker::GetGUI()->GetWindowManager().Process(CTimeUtils::GetFrameTime());
1886 CServiceBroker::GetGUI()->GetWindowManager().FrameMove();
1889 appPlayer
->FrameMove();
1891 // this will go away when render systems gets its own thread
1892 CServiceBroker::GetWinSystem()->DriveRenderLoop();
1896 void CApplication::ResetCurrentItem()
1898 m_itemCurrentFile
->Reset();
1900 m_pGUI
->GetInfoManager().ResetCurrentItem();
1903 int CApplication::Run()
1905 CLog::Log(LOGINFO
, "Running the application...");
1907 std::chrono::time_point
<std::chrono::steady_clock
> lastFrameTime
;
1908 std::chrono::milliseconds frameTime
;
1909 const unsigned int noRenderFrameTime
= 15; // Simulates ~66fps
1911 CFileItemList
& playlist
= CServiceBroker::GetAppParams()->GetPlaylist();
1912 if (playlist
.Size() > 0)
1914 CServiceBroker::GetPlaylistPlayer().Add(PLAYLIST::TYPE_MUSIC
, playlist
);
1915 CServiceBroker::GetPlaylistPlayer().SetCurrentPlaylist(PLAYLIST::TYPE_MUSIC
);
1916 CServiceBroker::GetAppMessenger()->PostMsg(TMSG_PLAYLISTPLAYER_PLAY
, -1);
1922 // Animate and render a frame
1924 lastFrameTime
= std::chrono::steady_clock::now();
1927 bool renderGUI
= GetComponent
<CApplicationPowerHandling
>()->GetRenderGUI();
1930 FrameMove(true, renderGUI
);
1933 if (renderGUI
&& !m_bStop
)
1937 else if (!renderGUI
)
1939 auto now
= std::chrono::steady_clock::now();
1940 frameTime
= std::chrono::duration_cast
<std::chrono::milliseconds
>(now
- lastFrameTime
);
1941 if (frameTime
.count() < noRenderFrameTime
)
1942 KODI::TIME::Sleep(std::chrono::milliseconds(noRenderFrameTime
- frameTime
.count()));
1948 CLog::Log(LOGINFO
, "Exiting the application...");
1952 bool CApplication::Cleanup()
1959 if (m_ServiceManager
)
1960 m_ServiceManager
->DeinitStageThree();
1962 CServiceBroker::UnregisterSpeechRecognition();
1964 CLog::Log(LOGINFO
, "unload skin");
1965 GetComponent
<CApplicationSkinHandling
>()->UnloadSkin();
1967 CServiceBroker::UnregisterTextureCache();
1969 // stop all remaining scripts; must be done after skin has been unloaded,
1970 // not before some windows still need it when deinitializing during skin
1972 CScriptInvocationManager::GetInstance().Uninitialize();
1974 const auto appPower
= GetComponent
<CApplicationPowerHandling
>();
1975 appPower
->m_globalScreensaverInhibitor
.Release();
1976 appPower
->m_screensaverInhibitor
.Release();
1978 CRenderSystemBase
*renderSystem
= CServiceBroker::GetRenderSystem();
1980 renderSystem
->DestroyRenderSystem();
1982 CWinSystemBase
*winSystem
= CServiceBroker::GetWinSystem();
1984 winSystem
->DestroyWindow();
1987 m_pGUI
->GetWindowManager().DestroyWindows();
1989 CLog::Log(LOGINFO
, "unload sections");
1991 // Shutdown as much as possible of the
1992 // application, to reduce the leaks dumped
1993 // to the vc output window before calling
1994 // _CrtDumpMemoryLeaks(). Most of the leaks
1995 // shown are no real leaks, as parts of the app
1996 // are still allocated.
1998 g_localizeStrings
.Clear();
1999 g_LangCodeExpander
.Clear();
2000 g_charsetConverter
.clear();
2001 g_directoryCache
.Clear();
2002 //CServiceBroker::GetInputManager().ClearKeymaps(); //! @todo
2003 CEventServer::RemoveInstance();
2004 CServiceBroker::GetPlaylistPlayer().Clear();
2006 if (m_ServiceManager
)
2007 m_ServiceManager
->DeinitStageTwo();
2010 CXHandle::DumpObjectTracker();
2012 #ifdef HAS_OPTICAL_DRIVE
2013 CLibcdio::ReleaseInstance();
2016 #ifdef _CRTDBG_MAP_ALLOC
2017 _CrtDumpMemoryLeaks();
2018 while(1); // execution ends
2029 winSystem
->DestroyWindowSystem();
2030 CServiceBroker::UnregisterWinSystem();
2031 winSystem
= nullptr;
2032 m_pWinSystem
.reset();
2035 // Cleanup was called more than once on exit during my tests
2036 if (m_ServiceManager
)
2038 m_ServiceManager
->DeinitStageOne();
2039 m_ServiceManager
.reset();
2042 CServiceBroker::UnregisterKeyboardLayoutManager();
2044 CServiceBroker::UnregisterAppMessenger();
2046 CServiceBroker::UnregisterAnnouncementManager();
2047 m_pAnnouncementManager
->Deinitialize();
2048 m_pAnnouncementManager
.reset();
2050 CServiceBroker::UnregisterJobManager();
2051 CServiceBroker::UnregisterCPUInfo();
2053 UnregisterSettings();
2055 m_bInitializing
= true;
2061 CLog::Log(LOGERROR
, "Exception in CApplication::Cleanup()");
2066 bool CApplication::Stop(int exitCode
)
2068 #if defined(TARGET_ANDROID)
2069 // Note: On Android, the app must be stopped asynchronously, once Android has
2070 // signalled that the app shall be destroyed. See android_main() implementation.
2071 if (!CXBMCApp::Get().Stop(exitCode
))
2075 CLog::Log(LOGINFO
, "Stopping the application...");
2077 bool success
= true;
2079 CLog::Log(LOGINFO
, "Stopping player");
2080 const auto appPlayer
= GetComponent
<CApplicationPlayer
>();
2081 appPlayer
->ClosePlayer();
2084 // close inbound port
2085 CServiceBroker::UnregisterAppPort();
2086 XbmcThreads::EndTime
<> timer(1000ms
);
2087 while (m_pAppPort
.use_count() > 1)
2089 KODI::TIME::Sleep(100ms
);
2090 if (timer
.IsTimePast())
2092 CLog::Log(LOGERROR
, "CApplication::Stop - CAppPort still in use, app may crash");
2101 m_frameMoveGuard
.unlock();
2103 CVariant
vExitCode(CVariant::VariantTypeObject
);
2104 vExitCode
["exitcode"] = exitCode
;
2105 CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::System
, "OnQuit", vExitCode
);
2107 // Abort any active screensaver
2108 GetComponent
<CApplicationPowerHandling
>()->WakeUpScreenSaverAndDPMS();
2110 g_alarmClock
.StopThread();
2112 CLog::Log(LOGINFO
, "Storing total System Uptime");
2113 g_sysinfo
.SetTotalUptime(g_sysinfo
.GetTotalUptime() + (int)(CTimeUtils::GetFrameTime() / 60000));
2115 // Update the settings information (volume, uptime etc. need saving)
2116 if (CFile::Exists(CServiceBroker::GetSettingsComponent()->GetProfileManager()->GetSettingsFile()))
2118 CLog::Log(LOGINFO
, "Saving settings");
2119 CServiceBroker::GetSettingsComponent()->GetSettings()->Save();
2122 CLog::Log(LOGINFO
, "Not saving settings (settings.xml is not present)");
2124 // kodi may crash or deadlock during exit (shutdown / reboot) due to
2125 // either a bug in core or misbehaving addons. so try saving
2126 // skin settings early
2127 CLog::Log(LOGINFO
, "Saving skin settings");
2128 if (g_SkinInfo
!= nullptr)
2129 g_SkinInfo
->SaveSettings();
2132 // Add this here to keep the same ordering behaviour for now
2133 // Needs cleaning up
2134 CServiceBroker::GetAppMessenger()->Stop();
2135 m_AppFocused
= false;
2136 m_ExitCode
= exitCode
;
2137 CLog::Log(LOGINFO
, "Stopping all");
2139 // cancel any jobs from the jobmanager
2140 CServiceBroker::GetJobManager()->CancelJobs();
2142 // stop scanning before we kill the network and so on
2143 if (CMusicLibraryQueue::GetInstance().IsRunning())
2144 CMusicLibraryQueue::GetInstance().CancelAllJobs();
2146 if (CVideoLibraryQueue::GetInstance().IsRunning())
2147 CVideoLibraryQueue::GetInstance().CancelAllJobs();
2149 CServiceBroker::GetAppMessenger()->Cleanup();
2151 m_ServiceManager
->GetNetwork().NetworkMessage(CNetworkBase::SERVICES_DOWN
, 0);
2154 if(CZeroconfBrowser::IsInstantiated())
2156 CLog::Log(LOGINFO
, "Stopping zeroconf browser");
2157 CZeroconfBrowser::GetInstance()->Stop();
2158 CZeroconfBrowser::ReleaseInstance();
2162 for (const auto& vfsAddon
: CServiceBroker::GetVFSAddonCache().GetAddonInstances())
2163 vfsAddon
->DisconnectAll();
2165 #if defined(TARGET_POSIX) && defined(HAS_FILESYSTEM_SMB)
2169 #if defined(TARGET_DARWIN_OSX) and defined(HAS_XBMCHELPER)
2170 if (XBMCHelper::GetInstance().IsAlwaysOn() == false)
2171 XBMCHelper::GetInstance().Stop();
2174 // Stop services before unloading Python
2175 CServiceBroker::GetServiceAddons().Stop();
2177 // Stop any other python scripts that may be looping waiting for monitor.abortRequested()
2178 CScriptInvocationManager::GetInstance().StopRunningScripts();
2180 // unregister action listeners
2181 const auto appListener
= GetComponent
<CApplicationActionListeners
>();
2182 appListener
->UnregisterActionListener(&GetComponent
<CApplicationPlayer
>()->GetSeekHandler());
2183 appListener
->UnregisterActionListener(&CPlayerController::GetInstance());
2185 CGUIComponent
*gui
= CServiceBroker::GetGUI();
2187 gui
->GetAudioManager().DeInitialize();
2189 // shutdown the AudioEngine
2190 CServiceBroker::UnregisterAE();
2191 m_pActiveAE
->Shutdown();
2192 m_pActiveAE
.reset();
2194 CLog::Log(LOGINFO
, "Application stopped");
2198 CLog::Log(LOGERROR
, "Exception in CApplication::Stop()");
2202 cleanup_emu_environ();
2204 KODI::TIME::Sleep(200ms
);
2211 class CCreateAndLoadPlayList
: public IRunnable
2214 CCreateAndLoadPlayList(CFileItem
& item
, std::unique_ptr
<PLAYLIST::CPlayList
>& playlist
)
2215 : m_item(item
), m_playlist(playlist
)
2221 const std::unique_ptr
<PLAYLIST::CPlayList
> playlist(PLAYLIST::CPlayListFactory::Create(m_item
));
2224 if (playlist
->Load(m_item
.GetPath()))
2225 *m_playlist
= *playlist
;
2231 std::unique_ptr
<PLAYLIST::CPlayList
>& m_playlist
;
2235 bool CApplication::PlayMedia(CFileItem
& item
, const std::string
& player
, PLAYLIST::Id playlistId
)
2237 // if the item is a plugin we need to resolve the plugin paths
2238 if (URIUtils::HasPluginPath(item
) && !XFILE::CPluginDirectory::GetResolvedPluginResult(item
))
2241 if (item
.IsSmartPlayList())
2243 CFileItemList items
;
2244 CUtil::GetRecursiveListing(item
.GetPath(), items
, "", DIR_FLAG_NO_FILE_DIRS
);
2247 CSmartPlaylist smartpl
;
2248 //get name and type of smartplaylist, this will always succeed as GetDirectory also did this.
2249 smartpl
.OpenAndReadName(item
.GetURL());
2250 PLAYLIST::CPlayList playlist
;
2251 playlist
.Add(items
);
2252 PLAYLIST::Id smartplPlaylistId
= PLAYLIST::TYPE_VIDEO
;
2254 if (smartpl
.GetType() == "songs" || smartpl
.GetType() == "albums" ||
2255 smartpl
.GetType() == "artists")
2256 smartplPlaylistId
= PLAYLIST::TYPE_MUSIC
;
2258 return ProcessAndStartPlaylist(smartpl
.GetName(), playlist
, smartplPlaylistId
);
2261 else if (item
.IsPlayList() || item
.IsInternetStream())
2263 // Not owner. Dialog auto-deletes itself.
2264 CGUIDialogCache
* dlgCache
=
2265 new CGUIDialogCache(5s
, g_localizeStrings
.Get(10214), item
.GetLabel());
2267 //is or could be a playlist
2268 std::unique_ptr
<PLAYLIST::CPlayList
> playlist
;
2269 CCreateAndLoadPlayList
getPlaylist(item
, playlist
);
2270 bool cancelled
= !CGUIDialogBusy::Wait(&getPlaylist
, 100, true);
2275 if (dlgCache
->IsCanceled())
2285 if (playlistId
!= PLAYLIST::TYPE_NONE
)
2288 if (item
.HasProperty("playlist_starting_track"))
2289 track
= (int)item
.GetProperty("playlist_starting_track").asInteger();
2290 return ProcessAndStartPlaylist(item
.GetPath(), *playlist
, playlistId
, track
);
2294 CLog::Log(LOGWARNING
,
2295 "CApplication::PlayMedia called to play a playlist {} but no idea which playlist "
2296 "to use, playing first item",
2298 if (playlist
->size())
2299 return PlayFile(*(*playlist
)[0], "", false);
2303 else if (item
.IsPVR())
2305 return CServiceBroker::GetPVRManager().Get
<PVR::GUI::Playback
>().PlayMedia(item
);
2308 CURL
path(item
.GetPath());
2309 if (path
.GetProtocol() == "game")
2312 if (CServiceBroker::GetAddonMgr().GetAddon(path
.GetHostName(), addon
, AddonType::GAMEDLL
,
2313 OnlyEnabled::CHOICE_YES
))
2315 CFileItem
addonItem(addon
);
2316 return PlayFile(addonItem
, player
, false);
2320 //nothing special just play
2321 return PlayFile(item
, player
, false);
2325 // For playing a multi-file video. Particularly inefficient
2326 // on startup, as we are required to calculate the length
2327 // of each video, so we open + close each one in turn.
2328 // A faster calculation of video time would improve this
2330 // return value: same with PlayFile()
2331 bool CApplication::PlayStack(CFileItem
& item
, bool bRestart
)
2333 const auto stackHelper
= GetComponent
<CApplicationStackHelper
>();
2334 if (!stackHelper
->InitializeStack(item
))
2337 int startoffset
= stackHelper
->InitializeStackStartPartAndOffset(item
);
2339 CFileItem selectedStackPart
= stackHelper
->GetCurrentStackPartFileItem();
2340 selectedStackPart
.SetStartOffset(startoffset
);
2342 if (item
.HasProperty("savedplayerstate"))
2344 selectedStackPart
.SetProperty("savedplayerstate", item
.GetProperty("savedplayerstate")); // pass on to part
2345 item
.ClearProperty("savedplayerstate");
2348 return PlayFile(selectedStackPart
, "", true);
2351 bool CApplication::PlayFile(CFileItem item
, const std::string
& player
, bool bRestart
)
2353 // Ensure the MIME type has been retrieved for http:// and shout:// streams
2354 if (item
.GetMimeType().empty())
2355 item
.FillInMimeType();
2357 const auto appPlayer
= GetComponent
<CApplicationPlayer
>();
2358 const auto stackHelper
= GetComponent
<CApplicationStackHelper
>();
2362 // bRestart will be true when called from PlayStack(), skipping this block
2363 appPlayer
->SetPlaySpeed(1);
2365 m_nextPlaylistItem
= -1;
2366 stackHelper
->Clear();
2369 CUtil::ClearSubtitles();
2372 if (item
.IsDiscStub())
2374 return CServiceBroker::GetMediaManager().playStubFile(item
);
2377 if (item
.IsPlayList())
2380 // Translate/Resolve the url if needed
2381 const std::unique_ptr
<IDirectory
> dir
{CDirectoryFactory::Create(item
)};
2382 if (dir
&& !dir
->Resolve(item
))
2387 // if we have a stacked set of files, we need to setup our stack routines for
2388 // "seamless" seeking and total time of the movie etc.
2389 // will recall with restart set to true
2391 return PlayStack(item
, bRestart
);
2393 CPlayerOptions options
;
2395 if (item
.HasProperty("StartPercent"))
2397 options
.startpercent
= item
.GetProperty("StartPercent").asDouble();
2398 item
.SetStartOffset(0);
2401 options
.starttime
= CUtil::ConvertMilliSecsToSecs(item
.GetStartOffset());
2405 // have to be set here due to playstack using this for starting the file
2406 if (item
.HasVideoInfoTag())
2407 options
.state
= item
.GetVideoInfoTag()->GetResumePoint().playerState
;
2409 if (!bRestart
|| stackHelper
->IsPlayingISOStack())
2411 // the following code block is only applicable when bRestart is false OR to ISO stacks
2415 // open the d/b and retrieve the bookmarks for the current movie
2419 std::string path
= item
.GetPath();
2420 std::string
videoInfoTagPath(item
.GetVideoInfoTag()->m_strFileNameAndPath
);
2421 if (videoInfoTagPath
.find("removable://") == 0 || item
.IsVideoDb())
2422 path
= videoInfoTagPath
;
2424 // Note that we need to load the tag from database also if the item already has a tag,
2425 // because for example the (full) video info for strm files will be loaded here.
2426 dbs
.LoadVideoInfo(path
, *item
.GetVideoInfoTag());
2428 if (item
.HasProperty("savedplayerstate"))
2430 options
.starttime
= CUtil::ConvertMilliSecsToSecs(item
.GetStartOffset());
2431 options
.state
= item
.GetProperty("savedplayerstate").asString();
2432 item
.ClearProperty("savedplayerstate");
2434 else if (item
.GetStartOffset() == STARTOFFSET_RESUME
)
2436 options
.starttime
= 0.0;
2437 if (item
.IsResumePointSet())
2439 options
.starttime
= item
.GetCurrentResumeTime();
2440 if (item
.HasVideoInfoTag())
2441 options
.state
= item
.GetVideoInfoTag()->GetResumePoint().playerState
;
2446 std::string path
= item
.GetPath();
2447 if (item
.HasVideoInfoTag() && StringUtils::StartsWith(item
.GetVideoInfoTag()->m_strFileNameAndPath
, "removable://"))
2448 path
= item
.GetVideoInfoTag()->m_strFileNameAndPath
;
2449 else if (item
.HasProperty("original_listitem_url") && URIUtils::IsPlugin(item
.GetProperty("original_listitem_url").asString()))
2450 path
= item
.GetProperty("original_listitem_url").asString();
2451 if (dbs
.GetResumeBookMark(path
, bookmark
))
2453 options
.starttime
= bookmark
.timeInSeconds
;
2454 options
.state
= bookmark
.playerState
;
2458 if (options
.starttime
== 0.0 && item
.HasVideoInfoTag())
2460 // No resume point is set, but check if this item is part of a multi-episode file
2461 const CVideoInfoTag
*tag
= item
.GetVideoInfoTag();
2463 if (tag
->m_iBookmarkId
> 0)
2466 dbs
.GetBookMarkForEpisode(*tag
, bookmark
);
2467 options
.starttime
= bookmark
.timeInSeconds
;
2468 options
.state
= bookmark
.playerState
;
2472 else if (item
.HasVideoInfoTag())
2474 const CVideoInfoTag
*tag
= item
.GetVideoInfoTag();
2476 if (tag
->m_iBookmarkId
> 0)
2479 dbs
.GetBookMarkForEpisode(*tag
, bookmark
);
2480 options
.starttime
= bookmark
.timeInSeconds
;
2481 options
.state
= bookmark
.playerState
;
2489 // a disc image might be Blu-Ray disc
2490 if (!(options
.startpercent
> 0.0 || options
.starttime
> 0.0) &&
2491 (item
.IsBDFile() || item
.IsDiscImage()))
2493 // No video selection when using external or remote players (they handle it if supported)
2494 const bool isSimpleMenuAllowed
= [&]()
2496 const std::string defaulPlayer
{
2497 player
.empty() ? m_ServiceManager
->GetPlayerCoreFactory().GetDefaultPlayer(item
)
2499 const bool isExternalPlayer
{
2500 m_ServiceManager
->GetPlayerCoreFactory().IsExternalPlayer(defaulPlayer
)};
2501 const bool isRemotePlayer
{
2502 m_ServiceManager
->GetPlayerCoreFactory().IsRemotePlayer(defaulPlayer
)};
2503 return !isExternalPlayer
&& !isRemotePlayer
;
2506 if (isSimpleMenuAllowed
)
2508 // Check if we must show the simplified bd menu.
2509 if (!CGUIDialogSimpleMenu::ShowPlaySelection(item
))
2514 // this really aught to be inside !bRestart, but since PlayStack
2515 // uses that to init playback, we have to keep it outside
2516 const PLAYLIST::Id playlistId
= CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist();
2517 if (item
.IsAudio() && playlistId
== PLAYLIST::TYPE_MUSIC
)
2518 { // playing from a playlist by the looks
2519 // don't switch to fullscreen if we are not playing the first item...
2520 options
.fullscreen
= !CServiceBroker::GetPlaylistPlayer().HasPlayedFirstFile() &&
2521 CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(
2522 CSettings::SETTING_MUSICFILES_SELECTACTION
) &&
2523 !CMediaSettings::GetInstance().DoesMediaStartWindowed();
2525 else if (item
.IsVideo() && playlistId
== PLAYLIST::TYPE_VIDEO
&&
2526 CServiceBroker::GetPlaylistPlayer().GetPlaylist(playlistId
).size() > 1)
2527 { // playing from a playlist by the looks
2528 // don't switch to fullscreen if we are not playing the first item...
2529 options
.fullscreen
= !CServiceBroker::GetPlaylistPlayer().HasPlayedFirstFile() &&
2530 CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_fullScreenOnMovieStart
&&
2531 !CMediaSettings::GetInstance().DoesMediaStartWindowed();
2533 else if (stackHelper
->IsPlayingRegularStack())
2535 //! @todo - this will fail if user seeks back to first file in stack
2536 if (stackHelper
->GetCurrentPartNumber() == 0 ||
2537 stackHelper
->GetRegisteredStack(item
)->GetStartOffset() != 0)
2538 options
.fullscreen
= CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->
2539 m_fullScreenOnMovieStart
&& !CMediaSettings::GetInstance().DoesMediaStartWindowed();
2541 options
.fullscreen
= false;
2544 options
.fullscreen
= CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->
2545 m_fullScreenOnMovieStart
&& !CMediaSettings::GetInstance().DoesMediaStartWindowed();
2547 // stereo streams may have lower quality, i.e. 32bit vs 16 bit
2548 options
.preferStereo
= CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_videoPreferStereoStream
&&
2549 CServiceBroker::GetActiveAE()->HasStereoAudioChannelCount();
2551 // reset VideoStartWindowed as it's a temp setting
2552 CMediaSettings::GetInstance().SetMediaStartWindowed(false);
2555 // for playing a new item, previous playing item's callback may already
2556 // pushed some delay message into the threadmessage list, they are not
2557 // expected be processed after or during the new item playback starting.
2558 // so we clean up previous playing item's playback callback delay messages here.
2559 int previousMsgsIgnoredByNewPlaying
[] = {
2560 GUI_MSG_PLAYBACK_STARTED
,
2561 GUI_MSG_PLAYBACK_ENDED
,
2562 GUI_MSG_PLAYBACK_STOPPED
,
2563 GUI_MSG_PLAYLIST_CHANGED
,
2564 GUI_MSG_PLAYLISTPLAYER_STOPPED
,
2565 GUI_MSG_PLAYLISTPLAYER_STARTED
,
2566 GUI_MSG_PLAYLISTPLAYER_CHANGED
,
2567 GUI_MSG_QUEUE_NEXT_ITEM
,
2570 int dMsgCount
= CServiceBroker::GetGUI()->GetWindowManager().RemoveThreadMessageByMessageIds(&previousMsgsIgnoredByNewPlaying
[0]);
2572 CLog::LogF(LOGDEBUG
, "Ignored {} playback thread messages", dMsgCount
);
2575 const auto appVolume
= GetComponent
<CApplicationVolumeHandling
>();
2576 appPlayer
->OpenFile(item
, options
, m_ServiceManager
->GetPlayerCoreFactory(), player
, *this);
2577 appPlayer
->SetVolume(appVolume
->GetVolumeRatio());
2578 appPlayer
->SetMute(appVolume
->IsMuted());
2580 #if !defined(TARGET_POSIX)
2581 CGUIComponent
*gui
= CServiceBroker::GetGUI();
2583 gui
->GetAudioManager().Enable(false);
2586 if (item
.HasPVRChannelInfoTag())
2587 CServiceBroker::GetPlaylistPlayer().SetCurrentPlaylist(PLAYLIST::TYPE_NONE
);
2592 void CApplication::PlaybackCleanup()
2594 const auto appPlayer
= GetComponent
<CApplicationPlayer
>();
2595 const auto stackHelper
= GetComponent
<CApplicationStackHelper
>();
2597 if (!appPlayer
->IsPlaying())
2599 CGUIComponent
*gui
= CServiceBroker::GetGUI();
2601 CServiceBroker::GetGUI()->GetAudioManager().Enable(true);
2602 appPlayer
->OpenNext(m_ServiceManager
->GetPlayerCoreFactory());
2605 if (!appPlayer
->IsPlayingVideo())
2607 if(CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow() == WINDOW_FULLSCREEN_VIDEO
||
2608 CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow() == WINDOW_FULLSCREEN_GAME
)
2610 CServiceBroker::GetGUI()->GetWindowManager().PreviousWindow();
2614 // resets to res_desktop or look&feel resolution (including refreshrate)
2615 CServiceBroker::GetWinSystem()->GetGfxContext().SetFullScreenVideo(false);
2617 #ifdef TARGET_DARWIN_EMBEDDED
2618 CDarwinUtils::SetScheduling(false);
2622 const auto appPower
= GetComponent
<CApplicationPowerHandling
>();
2624 if (!appPlayer
->IsPlayingAudio() &&
2625 CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist() == PLAYLIST::TYPE_NONE
&&
2626 CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow() == WINDOW_VISUALISATION
)
2628 CServiceBroker::GetSettingsComponent()->GetSettings()->Save(); // save vis settings
2629 appPower
->WakeUpScreenSaverAndDPMS();
2630 CServiceBroker::GetGUI()->GetWindowManager().PreviousWindow();
2633 // DVD ejected while playing in vis ?
2634 if (!appPlayer
->IsPlayingAudio() &&
2635 (m_itemCurrentFile
->IsCDDA() || m_itemCurrentFile
->IsOnDVD()) &&
2636 !CServiceBroker::GetMediaManager().IsDiscInDrive() &&
2637 CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow() == WINDOW_VISUALISATION
)
2640 CServiceBroker::GetSettingsComponent()->GetSettings()->Save(); // save vis settings
2641 appPower
->WakeUpScreenSaverAndDPMS();
2642 CServiceBroker::GetGUI()->GetWindowManager().PreviousWindow();
2645 if (!appPlayer
->IsPlaying())
2647 stackHelper
->Clear();
2648 appPlayer
->ResetPlayer();
2651 if (CServiceBroker::GetAppParams()->IsTestMode())
2652 CServiceBroker::GetAppMessenger()->PostMsg(TMSG_QUIT
);
2655 bool CApplication::IsPlayingFullScreenVideo() const
2657 const auto appPlayer
= GetComponent
<CApplicationPlayer
>();
2658 return appPlayer
->IsPlayingVideo() &&
2659 CServiceBroker::GetWinSystem()->GetGfxContext().IsFullScreenVideo();
2662 bool CApplication::IsFullScreen()
2664 return IsPlayingFullScreenVideo() ||
2665 (CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow() == WINDOW_VISUALISATION
) ||
2666 CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow() == WINDOW_SLIDESHOW
;
2669 void CApplication::StopPlaying()
2671 CGUIComponent
*gui
= CServiceBroker::GetGUI();
2675 int iWin
= gui
->GetWindowManager().GetActiveWindow();
2676 const auto appPlayer
= GetComponent
<CApplicationPlayer
>();
2677 if (appPlayer
->IsPlaying())
2679 appPlayer
->ClosePlayer();
2681 // turn off visualisation window when stopping
2682 if ((iWin
== WINDOW_VISUALISATION
||
2683 iWin
== WINDOW_FULLSCREEN_VIDEO
||
2684 iWin
== WINDOW_FULLSCREEN_GAME
) &&
2686 gui
->GetWindowManager().PreviousWindow();
2688 g_partyModeManager
.Disable();
2693 bool CApplication::OnMessage(CGUIMessage
& message
)
2695 switch (message
.GetMessage())
2697 case GUI_MSG_NOTIFY_ALL
:
2699 if (message
.GetParam1()==GUI_MSG_REMOVED_MEDIA
)
2701 // Update general playlist: Remove DVD playlist items
2702 int nRemoved
= CServiceBroker::GetPlaylistPlayer().RemoveDVDItems();
2705 CGUIMessage
msg( GUI_MSG_PLAYLIST_CHANGED
, 0, 0 );
2706 CServiceBroker::GetGUI()->GetWindowManager().SendMessage( msg
);
2708 // stop the file if it's on dvd (will set the resume point etc)
2709 if (m_itemCurrentFile
->IsOnDVD())
2712 else if (message
.GetParam1() == GUI_MSG_UI_READY
)
2714 // remove splash window
2715 CServiceBroker::GetGUI()->GetWindowManager().Delete(WINDOW_SPLASH
);
2717 // show the volumebar if the volume is muted
2718 const auto appVolume
= GetComponent
<CApplicationVolumeHandling
>();
2719 if (appVolume
->IsMuted() ||
2720 appVolume
->GetVolumeRatio() <= CApplicationVolumeHandling::VOLUME_MINIMUM
)
2721 appVolume
->ShowVolumeBar();
2723 if (!m_incompatibleAddons
.empty())
2725 // filter addons that are not dependencies
2726 std::vector
<std::string
> disabledAddonNames
;
2727 for (const auto& addoninfo
: m_incompatibleAddons
)
2729 if (!CAddonType::IsDependencyType(addoninfo
->MainType()))
2730 disabledAddonNames
.emplace_back(addoninfo
->Name());
2733 // migration (incompatible addons) dialog
2734 auto addonList
= StringUtils::Join(disabledAddonNames
, ", ");
2735 auto msg
= StringUtils::Format(g_localizeStrings
.Get(24149), addonList
);
2736 HELPERS::ShowOKDialogText(CVariant
{24148}, CVariant
{std::move(msg
)});
2737 m_incompatibleAddons
.clear();
2740 // offer enabling addons at kodi startup that are disabled due to
2741 // e.g. os package manager installation on linux
2742 ConfigureAndEnableAddons();
2744 m_bInitializing
= false;
2746 if (message
.GetSenderId() == WINDOW_SETTINGS_PROFILES
)
2747 GetComponent
<CApplicationSkinHandling
>()->ReloadSkin(false);
2749 else if (message
.GetParam1() == GUI_MSG_UPDATE_ITEM
&& message
.GetItem())
2751 CFileItemPtr item
= std::static_pointer_cast
<CFileItem
>(message
.GetItem());
2752 if (m_itemCurrentFile
->IsSamePath(item
.get()))
2754 m_itemCurrentFile
->UpdateInfo(*item
);
2755 CServiceBroker::GetGUI()->GetInfoManager().UpdateCurrentItem(*item
);
2761 case GUI_MSG_PLAYBACK_STARTED
:
2763 #ifdef TARGET_DARWIN_EMBEDDED
2764 // @TODO move this away to platform code
2765 CDarwinUtils::SetScheduling(GetComponent
<CApplicationPlayer
>()->IsPlayingVideo());
2768 std::make_shared
<CFileItem
>(*std::static_pointer_cast
<CFileItem
>(message
.GetItem()));
2769 m_playerEvent
.Reset();
2771 CServiceBroker::GetPVRManager().OnPlaybackStarted(*m_itemCurrentFile
);
2773 PLAYLIST::CPlayList playList
= CServiceBroker::GetPlaylistPlayer().GetPlaylist(
2774 CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist());
2776 // Update our infoManager with the new details etc.
2777 if (m_nextPlaylistItem
>= 0)
2779 // playing an item which is not in the list - player might be stopped already
2781 if (playList
.size() <= m_nextPlaylistItem
)
2784 // we've started a previously queued item
2785 CFileItemPtr item
= playList
[m_nextPlaylistItem
];
2786 // update the playlist manager
2787 int currentSong
= CServiceBroker::GetPlaylistPlayer().GetCurrentItemIdx();
2788 int param
= ((currentSong
& 0xffff) << 16) | (m_nextPlaylistItem
& 0xffff);
2789 CGUIMessage
msg(GUI_MSG_PLAYLISTPLAYER_CHANGED
, 0, 0, CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist(), param
, item
);
2790 CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg
);
2791 CServiceBroker::GetPlaylistPlayer().SetCurrentItemIdx(m_nextPlaylistItem
);
2792 m_itemCurrentFile
= std::make_shared
<CFileItem
>(*item
);
2794 CServiceBroker::GetGUI()->GetInfoManager().SetCurrentItem(*m_itemCurrentFile
);
2795 g_partyModeManager
.OnSongChange(true);
2798 // informs python script currently running playback has started
2799 // (does nothing if python is not loaded)
2800 CServiceBroker::GetXBPython().OnPlayBackStarted(*m_itemCurrentFile
);
2804 param
["player"]["speed"] = 1;
2805 param
["player"]["playerid"] = CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist();
2807 CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::Player
, "OnPlay",
2808 m_itemCurrentFile
, param
);
2810 // we don't want a busy dialog when switching channels
2811 const auto appPlayer
= GetComponent
<CApplicationPlayer
>();
2812 if (!m_itemCurrentFile
->IsLiveTV() ||
2813 (!appPlayer
->IsPlayingVideo() && !appPlayer
->IsPlayingAudio()))
2815 CGUIDialogBusy
* dialog
=
2816 CServiceBroker::GetGUI()->GetWindowManager().GetWindow
<CGUIDialogBusy
>(
2817 WINDOW_DIALOG_BUSY
);
2818 if (dialog
&& !dialog
->IsDialogRunning())
2819 dialog
->WaitOnEvent(m_playerEvent
);
2826 case GUI_MSG_QUEUE_NEXT_ITEM
:
2828 // Check to see if our playlist player has a new item for us,
2829 // and if so, we check whether our current player wants the file
2830 int iNext
= CServiceBroker::GetPlaylistPlayer().GetNextItemIdx();
2831 PLAYLIST::CPlayList
& playlist
= CServiceBroker::GetPlaylistPlayer().GetPlaylist(
2832 CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist());
2833 if (iNext
< 0 || iNext
>= playlist
.size())
2835 GetComponent
<CApplicationPlayer
>()->OnNothingToQueueNotify();
2836 return true; // nothing to do
2839 // ok, grab the next song
2840 CFileItem
file(*playlist
[iNext
]);
2842 CURL
url(file
.GetDynPath());
2843 if (url
.IsProtocol("plugin"))
2844 XFILE::CPluginDirectory::GetPluginResult(url
.Get(), file
, false);
2846 // Don't queue if next media type is different from current one
2847 bool bNothingToQueue
= false;
2849 const auto appPlayer
= GetComponent
<CApplicationPlayer
>();
2850 if (!file
.IsVideo() && appPlayer
->IsPlayingVideo())
2851 bNothingToQueue
= true;
2852 else if ((!file
.IsAudio() || file
.IsVideo()) && appPlayer
->IsPlayingAudio())
2853 bNothingToQueue
= true;
2855 if (bNothingToQueue
)
2857 appPlayer
->OnNothingToQueueNotify();
2862 if (URIUtils::IsUPnP(file
.GetDynPath()))
2864 if (!XFILE::CUPnPDirectory::GetResource(file
.GetDynURL(), file
))
2869 // ok - send the file to the player, if it accepts it
2870 if (appPlayer
->QueueNextFile(file
))
2872 // player accepted the next file
2873 m_nextPlaylistItem
= iNext
;
2877 /* Player didn't accept next file: *ALWAYS* advance playlist in this case so the player can
2878 queue the next (if it wants to) and it doesn't keep looping on this song */
2879 CServiceBroker::GetPlaylistPlayer().SetCurrentItemIdx(iNext
);
2886 case GUI_MSG_PLAY_TRAILER
:
2888 const CFileItem
* item
= dynamic_cast<CFileItem
*>(message
.GetItem().get());
2889 if (item
== nullptr)
2891 CLog::LogF(LOGERROR
, "Supplied item is not a CFileItem! Trailer cannot be played.");
2895 std::unique_ptr
<CFileItem
> trailerItem
=
2896 ContentUtils::GeneratePlayableTrailerItem(*item
, g_localizeStrings
.Get(20410));
2898 if (item
->IsPlayList())
2900 std::unique_ptr
<CFileItemList
> fileitemList
= std::make_unique
<CFileItemList
>();
2901 fileitemList
->Add(std::move(trailerItem
));
2902 CServiceBroker::GetAppMessenger()->PostMsg(TMSG_MEDIA_PLAY
, -1, -1,
2903 static_cast<void*>(fileitemList
.release()));
2907 CServiceBroker::GetAppMessenger()->PostMsg(TMSG_MEDIA_PLAY
, 1, 0,
2908 static_cast<void*>(trailerItem
.release()));
2913 case GUI_MSG_PLAYBACK_STOPPED
:
2915 CServiceBroker::GetPVRManager().OnPlaybackStopped(*m_itemCurrentFile
);
2917 CVariant
data(CVariant::VariantTypeObject
);
2918 data
["end"] = false;
2919 CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::Player
, "OnStop",
2920 m_itemCurrentFile
, data
);
2922 m_playerEvent
.Set();
2926 CServiceBroker::GetXBPython().OnPlayBackStopped();
2931 case GUI_MSG_PLAYBACK_ENDED
:
2933 CServiceBroker::GetPVRManager().OnPlaybackEnded(*m_itemCurrentFile
);
2935 CVariant
data(CVariant::VariantTypeObject
);
2937 CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::Player
, "OnStop",
2938 m_itemCurrentFile
, data
);
2940 m_playerEvent
.Set();
2941 const auto stackHelper
= GetComponent
<CApplicationStackHelper
>();
2942 if (stackHelper
->IsPlayingRegularStack() && stackHelper
->HasNextStackPartFileItem())
2943 { // just play the next item in the stack
2944 PlayFile(stackHelper
->SetNextStackPartCurrentFileItem(), "", true);
2948 // For EPG playlist items we keep the player open to ensure continuous viewing experience.
2949 const bool isEpgPlaylistItem
{
2950 m_itemCurrentFile
->GetProperty("epg_playlist_item").asBoolean(false)};
2954 if (!isEpgPlaylistItem
)
2956 if (!CServiceBroker::GetPlaylistPlayer().PlayNext(1, true))
2957 GetComponent
<CApplicationPlayer
>()->ClosePlayer();
2963 CServiceBroker::GetXBPython().OnPlayBackEnded();
2968 case GUI_MSG_PLAYLISTPLAYER_STOPPED
:
2970 if (GetComponent
<CApplicationPlayer
>()->IsPlaying())
2975 case GUI_MSG_PLAYBACK_AVSTARTED
:
2978 param
["player"]["speed"] = 1;
2979 param
["player"]["playerid"] = CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist();
2980 CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::Player
, "OnAVStart",
2981 m_itemCurrentFile
, param
);
2982 m_playerEvent
.Set();
2984 // informs python script currently running playback has started
2985 // (does nothing if python is not loaded)
2986 CServiceBroker::GetXBPython().OnAVStarted(*m_itemCurrentFile
);
2991 case GUI_MSG_PLAYBACK_AVCHANGE
:
2994 // informs python script currently running playback has started
2995 // (does nothing if python is not loaded)
2996 CServiceBroker::GetXBPython().OnAVChange();
2999 param
["player"]["speed"] = 1;
3000 param
["player"]["playerid"] = CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist();
3001 CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::Player
, "OnAVChange",
3002 m_itemCurrentFile
, param
);
3006 case GUI_MSG_PLAYBACK_PAUSED
:
3009 param
["player"]["speed"] = 0;
3010 param
["player"]["playerid"] = CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist();
3011 CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::Player
, "OnPause",
3012 m_itemCurrentFile
, param
);
3016 case GUI_MSG_PLAYBACK_RESUMED
:
3019 param
["player"]["speed"] = 1;
3020 param
["player"]["playerid"] = CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist();
3021 CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::Player
, "OnResume",
3022 m_itemCurrentFile
, param
);
3026 case GUI_MSG_PLAYBACK_SEEKED
:
3029 const int64_t iTime
= message
.GetParam1AsI64();
3030 const int64_t seekOffset
= message
.GetParam2AsI64();
3031 JSONRPC::CJSONUtils::MillisecondsToTimeObject(iTime
, param
["player"]["time"]);
3032 JSONRPC::CJSONUtils::MillisecondsToTimeObject(seekOffset
, param
["player"]["seekoffset"]);
3033 param
["player"]["playerid"] = CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist();
3034 const auto& components
= CServiceBroker::GetAppComponents();
3035 const auto appPlayer
= components
.GetComponent
<CApplicationPlayer
>();
3036 param
["player"]["speed"] = static_cast<int>(appPlayer
->GetPlaySpeed());
3037 CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::Player
, "OnSeek",
3038 m_itemCurrentFile
, param
);
3040 CDataCacheCore::GetInstance().SeekFinished(static_cast<int>(seekOffset
));
3045 case GUI_MSG_PLAYBACK_SPEED_CHANGED
:
3048 param
["player"]["speed"] = message
.GetParam1();
3049 param
["player"]["playerid"] = CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist();
3050 CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::Player
, "OnSpeedChanged",
3051 m_itemCurrentFile
, param
);
3056 case GUI_MSG_PLAYBACK_ERROR
:
3057 HELPERS::ShowOKDialogText(CVariant
{16026}, CVariant
{16027});
3060 case GUI_MSG_PLAYLISTPLAYER_STARTED
:
3061 case GUI_MSG_PLAYLISTPLAYER_CHANGED
:
3066 case GUI_MSG_FULLSCREEN
:
3067 { // Switch to fullscreen, if we can
3068 CGUIComponent
* gui
= CServiceBroker::GetGUI();
3070 gui
->GetWindowManager().SwitchToFullScreen();
3075 case GUI_MSG_EXECUTE
:
3076 if (message
.GetNumStringParams())
3077 return ExecuteXBMCAction(message
.GetStringParam(), message
.GetItem());
3083 bool CApplication::ExecuteXBMCAction(std::string actionStr
,
3084 const std::shared_ptr
<CGUIListItem
>& item
/* = NULL */)
3086 // see if it is a user set string
3088 //We don't know if there is unsecure information in this yet, so we
3089 //postpone any logging
3090 const std::string
in_actionStr(actionStr
);
3092 actionStr
= GUILIB::GUIINFO::CGUIInfoLabel::GetItemLabel(actionStr
, item
.get());
3094 actionStr
= GUILIB::GUIINFO::CGUIInfoLabel::GetLabel(actionStr
, INFO::DEFAULT_CONTEXT
);
3096 // user has asked for something to be executed
3097 if (CBuiltins::GetInstance().HasCommand(actionStr
))
3099 if (!CBuiltins::GetInstance().IsSystemPowerdownCommand(actionStr
) ||
3100 CServiceBroker::GetPVRManager().Get
<PVR::GUI::PowerManagement
>().CanSystemPowerdown())
3101 CBuiltins::GetInstance().Execute(actionStr
);
3105 // try translating the action from our ButtonTranslator
3106 unsigned int actionID
;
3107 if (ACTION::CActionTranslator::TranslateString(actionStr
, actionID
))
3109 OnAction(CAction(actionID
));
3112 CFileItem
item(actionStr
, false);
3114 if (item
.IsPythonScript())
3115 { // a python script
3116 CScriptInvocationManager::GetInstance().ExecuteAsync(item
.GetPath());
3120 if (item
.IsAudio() || item
.IsVideo() || item
.IsGame())
3121 { // an audio or video file
3126 //At this point we have given up to translate, so even though
3127 //there may be insecure information, we log it.
3128 CLog::LogF(LOGDEBUG
, "Tried translating, but failed to understand {}", in_actionStr
);
3135 void CApplication::ConfigureAndEnableAddons()
3137 std::vector
<std::shared_ptr
<IAddon
>>
3138 disabledAddons
; /*!< Installed addons, but not auto-enabled via manifest */
3140 auto& addonMgr
= CServiceBroker::GetAddonMgr();
3142 if (addonMgr
.GetDisabledAddons(disabledAddons
) && !disabledAddons
.empty())
3144 // this applies to certain platforms only:
3145 // look at disabled addons with disabledReason == NONE, usually those are installed via package managers or manually.
3146 // also try to enable add-ons with disabledReason == INCOMPATIBLE at startup for all platforms.
3148 bool isConfigureAddonsAtStartupEnabled
=
3149 m_ServiceManager
->GetPlatform().IsConfigureAddonsAtStartupEnabled();
3151 for (const auto& addon
: disabledAddons
)
3153 if (addonMgr
.IsAddonDisabledWithReason(addon
->ID(), ADDON::AddonDisabledReason::INCOMPATIBLE
))
3155 auto addonInfo
= addonMgr
.GetAddonInfo(addon
->ID(), AddonType::UNKNOWN
);
3156 if (addonInfo
&& addonMgr
.IsCompatible(addonInfo
))
3158 CLog::Log(LOGDEBUG
, "CApplication::{}: enabling the compatible version of [{}].",
3159 __FUNCTION__
, addon
->ID());
3160 addonMgr
.EnableAddon(addon
->ID());
3165 if (addonMgr
.IsAddonDisabledExcept(addon
->ID(), ADDON::AddonDisabledReason::NONE
) ||
3166 CAddonType::IsDependencyType(addon
->MainType()))
3171 if (isConfigureAddonsAtStartupEnabled
)
3173 if (HELPERS::ShowYesNoDialogLines(CVariant
{24039}, // Disabled add-ons
3174 CVariant
{24059}, // Would you like to enable this add-on?
3175 CVariant
{addon
->Name()}) == DialogResponse::CHOICE_YES
)
3177 if (addon
->CanHaveAddonOrInstanceSettings())
3179 if (CGUIDialogAddonSettings::ShowForAddon(addon
))
3181 // only enable if settings dialog hasn't been cancelled
3182 addonMgr
.EnableAddon(addon
->ID());
3187 addonMgr
.EnableAddon(addon
->ID());
3192 // user chose not to configure/enable so we're not asking anymore
3193 addonMgr
.UpdateDisabledReason(addon
->ID(), ADDON::AddonDisabledReason::USER
);
3200 void CApplication::Process()
3202 // dispatch the messages generated by python or other threads to the current window
3203 CServiceBroker::GetGUI()->GetWindowManager().DispatchThreadMessages();
3205 // process messages which have to be send to the gui
3206 // (this can only be done after CServiceBroker::GetGUI()->GetWindowManager().Render())
3207 CServiceBroker::GetAppMessenger()->ProcessWindowMessages();
3209 // handle any active scripts
3212 // Allow processing of script threads to let them shut down properly.
3213 CSingleExit
ex(CServiceBroker::GetWinSystem()->GetGfxContext());
3214 m_frameMoveGuard
.unlock();
3215 CScriptInvocationManager::GetInstance().Process();
3216 m_frameMoveGuard
.lock();
3219 // process messages, even if a movie is playing
3220 CServiceBroker::GetAppMessenger()->ProcessMessages();
3221 if (m_bStop
) return; //we're done, everything has been unloaded
3223 // do any processing that isn't needed on each run
3224 if( m_slowTimer
.GetElapsedMilliseconds() > 500 )
3226 m_slowTimer
.Reset();
3231 // We get called every 500ms
3232 void CApplication::ProcessSlow()
3234 // process skin resources (skin timers)
3235 GetComponent
<CApplicationSkinHandling
>()->ProcessSkin();
3237 CServiceBroker::GetPowerManager().ProcessEvents();
3239 // Temporarily pause pausable jobs when viewing video/picture
3240 int currentWindow
= CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow();
3241 if (CurrentFileItem().IsVideo() ||
3242 CurrentFileItem().IsPicture() ||
3243 currentWindow
== WINDOW_FULLSCREEN_VIDEO
||
3244 currentWindow
== WINDOW_FULLSCREEN_GAME
||
3245 currentWindow
== WINDOW_SLIDESHOW
)
3247 CServiceBroker::GetJobManager()->PauseJobs();
3251 CServiceBroker::GetJobManager()->UnPauseJobs();
3254 // Check if we need to activate the screensaver / DPMS.
3255 const auto appPower
= GetComponent
<CApplicationPowerHandling
>();
3256 appPower
->CheckScreenSaverAndDPMS();
3258 // Check if we need to shutdown (if enabled).
3259 #if defined(TARGET_DARWIN)
3260 if (CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_POWERMANAGEMENT_SHUTDOWNTIME
) &&
3261 CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_fullScreen
)
3263 if (CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_POWERMANAGEMENT_SHUTDOWNTIME
))
3266 appPower
->CheckShutdown();
3269 #if defined(TARGET_POSIX)
3270 if (CPlatformPosix::TestQuitFlag())
3272 CLog::Log(LOGINFO
, "Quitting due to POSIX signal");
3273 CServiceBroker::GetAppMessenger()->PostMsg(TMSG_QUIT
);
3277 // check if we should restart the player
3278 CheckDelayedPlayerRestart();
3280 // check if we can unload any unreferenced dlls or sections
3281 const auto appPlayer
= GetComponent
<CApplicationPlayer
>();
3282 if (!appPlayer
->IsPlayingVideo())
3283 CSectionLoader::UnloadDelayed();
3285 #ifdef TARGET_ANDROID
3286 // Pass the slow loop to droid
3287 CXBMCApp::Get().ProcessSlow();
3290 // check for any idle curl connections
3291 g_curlInterface
.CheckIdle();
3293 CServiceBroker::GetGUI()->GetLargeTextureManager().CleanupUnusedImages();
3295 CServiceBroker::GetGUI()->GetTextureManager().FreeUnusedTextures(5000);
3297 #ifdef HAS_OPTICAL_DRIVE
3298 // checks whats in the DVD drive and tries to autostart the content (xbox games, dvd, cdda, avi files...)
3299 if (!appPlayer
->IsPlayingVideo())
3300 m_Autorun
->HandleAutorun();
3303 // update upnp server/renderer states
3305 if (CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_SERVICES_UPNP
) && UPNP::CUPnP::IsInstantiated())
3306 UPNP::CUPnP::GetInstance()->UpdateState();
3309 #if defined(TARGET_POSIX) && defined(HAS_FILESYSTEM_SMB)
3313 #ifdef HAS_FILESYSTEM_NFS
3314 gNfsConnection
.CheckIfIdle();
3317 for (const auto& vfsAddon
: CServiceBroker::GetVFSAddonCache().GetAddonInstances())
3318 vfsAddon
->ClearOutIdle();
3320 CServiceBroker::GetMediaManager().ProcessEvents();
3322 // if we don't render the gui there's no reason to start the screensaver.
3323 // that way the screensaver won't kick in if we maximize the XBMC window
3324 // after the screensaver start time.
3325 if (!appPower
->GetRenderGUI())
3326 appPower
->ResetScreenSaverTimer();
3329 void CApplication::DelayedPlayerRestart()
3331 m_restartPlayerTimer
.StartZero();
3334 void CApplication::CheckDelayedPlayerRestart()
3336 if (m_restartPlayerTimer
.GetElapsedSeconds() > 3)
3338 m_restartPlayerTimer
.Stop();
3339 m_restartPlayerTimer
.Reset();
3344 void CApplication::Restart(bool bSamePosition
)
3346 // this function gets called when the user changes a setting (like noninterleaved)
3347 // and which means we gotta close & reopen the current playing file
3349 // first check if we're playing a file
3350 const auto appPlayer
= GetComponent
<CApplicationPlayer
>();
3351 if (!appPlayer
->IsPlayingVideo() && !appPlayer
->IsPlayingAudio())
3354 if (!appPlayer
->HasPlayer())
3357 // do we want to return to the current position in the file
3360 // no, then just reopen the file and start at the beginning
3361 PlayFile(*m_itemCurrentFile
, "", true);
3365 // else get current position
3366 double time
= GetTime();
3368 // get player state, needed for dvd's
3369 std::string state
= appPlayer
->GetPlayerState();
3371 // set the requested starttime
3372 m_itemCurrentFile
->SetStartOffset(CUtil::ConvertSecsToMilliSecs(time
));
3375 if (PlayFile(*m_itemCurrentFile
, "", true))
3376 appPlayer
->SetPlayerState(state
);
3379 const std::string
& CApplication::CurrentFile()
3381 return m_itemCurrentFile
->GetPath();
3384 std::shared_ptr
<CFileItem
> CApplication::CurrentFileItemPtr()
3386 return m_itemCurrentFile
;
3389 CFileItem
& CApplication::CurrentFileItem()
3391 return *m_itemCurrentFile
;
3394 const CFileItem
& CApplication::CurrentUnstackedItem()
3396 const auto stackHelper
= GetComponent
<CApplicationStackHelper
>();
3398 if (stackHelper
->IsPlayingISOStack() || stackHelper
->IsPlayingRegularStack())
3399 return stackHelper
->GetCurrentStackPartFileItem();
3401 return *m_itemCurrentFile
;
3404 // Returns the total time in seconds of the current media. Fractional
3405 // portions of a second are possible - but not necessarily supported by the
3406 // player class. This returns a double to be consistent with GetTime() and
3408 double CApplication::GetTotalTime() const
3412 const auto appPlayer
= GetComponent
<CApplicationPlayer
>();
3413 const auto stackHelper
= GetComponent
<CApplicationStackHelper
>();
3415 if (appPlayer
->IsPlaying())
3417 if (stackHelper
->IsPlayingRegularStack())
3418 rc
= stackHelper
->GetStackTotalTimeMs() * 0.001;
3420 rc
= appPlayer
->GetTotalTime() * 0.001;
3426 // Returns the current time in seconds of the currently playing media.
3427 // Fractional portions of a second are possible. This returns a double to
3428 // be consistent with GetTotalTime() and SeekTime().
3429 double CApplication::GetTime() const
3433 const auto appPlayer
= GetComponent
<CApplicationPlayer
>();
3434 const auto stackHelper
= GetComponent
<CApplicationStackHelper
>();
3436 if (appPlayer
->IsPlaying())
3438 if (stackHelper
->IsPlayingRegularStack())
3440 uint64_t startOfCurrentFile
= stackHelper
->GetCurrentStackPartStartTimeMs();
3441 rc
= (startOfCurrentFile
+ appPlayer
->GetTime()) * 0.001;
3444 rc
= appPlayer
->GetTime() * 0.001;
3450 // Sets the current position of the currently playing media to the specified
3451 // time in seconds. Fractional portions of a second are valid. The passed
3452 // time is the time offset from the beginning of the file as opposed to a
3453 // delta from the current position. This method accepts a double to be
3454 // consistent with GetTime() and GetTotalTime().
3455 void CApplication::SeekTime( double dTime
)
3457 const auto appPlayer
= GetComponent
<CApplicationPlayer
>();
3458 const auto stackHelper
= GetComponent
<CApplicationStackHelper
>();
3460 if (appPlayer
->IsPlaying() && (dTime
>= 0.0))
3462 if (!appPlayer
->CanSeek())
3465 if (stackHelper
->IsPlayingRegularStack())
3467 // find the item in the stack we are seeking to, and load the new
3468 // file if necessary, and calculate the correct seek within the new
3469 // file. Otherwise, just fall through to the usual routine if the
3470 // time is higher than our total time.
3471 int partNumberToPlay
=
3472 stackHelper
->GetStackPartNumberAtTimeMs(static_cast<uint64_t>(dTime
* 1000.0));
3473 uint64_t startOfNewFile
= stackHelper
->GetStackPartStartTimeMs(partNumberToPlay
);
3474 if (partNumberToPlay
== stackHelper
->GetCurrentPartNumber())
3475 appPlayer
->SeekTime(static_cast<uint64_t>(dTime
* 1000.0) - startOfNewFile
);
3477 { // seeking to a new file
3478 stackHelper
->SetStackPartCurrentFileItem(partNumberToPlay
);
3479 CFileItem
* item
= new CFileItem(stackHelper
->GetCurrentStackPartFileItem());
3480 item
->SetStartOffset(static_cast<uint64_t>(dTime
* 1000.0) - startOfNewFile
);
3481 // don't just call "PlayFile" here, as we are quite likely called from the
3482 // player thread, so we won't be able to delete ourselves.
3483 CServiceBroker::GetAppMessenger()->PostMsg(TMSG_MEDIA_PLAY
, 1, 0, static_cast<void*>(item
));
3487 // convert to milliseconds and perform seek
3488 appPlayer
->SeekTime(static_cast<int64_t>(dTime
* 1000.0));
3492 float CApplication::GetPercentage() const
3494 const auto appPlayer
= GetComponent
<CApplicationPlayer
>();
3495 const auto stackHelper
= GetComponent
<CApplicationStackHelper
>();
3497 if (appPlayer
->IsPlaying())
3499 if (appPlayer
->GetTotalTime() == 0 && appPlayer
->IsPlayingAudio() &&
3500 m_itemCurrentFile
->HasMusicInfoTag())
3502 const CMusicInfoTag
& tag
= *m_itemCurrentFile
->GetMusicInfoTag();
3503 if (tag
.GetDuration() > 0)
3504 return (float)(GetTime() / tag
.GetDuration() * 100);
3507 if (stackHelper
->IsPlayingRegularStack())
3509 double totalTime
= GetTotalTime();
3510 if (totalTime
> 0.0)
3511 return (float)(GetTime() / totalTime
* 100);
3514 return appPlayer
->GetPercentage();
3519 float CApplication::GetCachePercentage() const
3521 const auto appPlayer
= GetComponent
<CApplicationPlayer
>();
3522 const auto stackHelper
= GetComponent
<CApplicationStackHelper
>();
3524 if (appPlayer
->IsPlaying())
3526 // Note that the player returns a relative cache percentage and we want an absolute percentage
3527 if (stackHelper
->IsPlayingRegularStack())
3529 float stackedTotalTime
= (float) GetTotalTime();
3530 // We need to take into account the stack's total time vs. currently playing file's total time
3531 if (stackedTotalTime
> 0.0f
)
3532 return std::min(100.0f
,
3533 GetPercentage() + (appPlayer
->GetCachePercentage() *
3534 appPlayer
->GetTotalTime() * 0.001f
/ stackedTotalTime
));
3537 return std::min(100.0f
, appPlayer
->GetPercentage() + appPlayer
->GetCachePercentage());
3542 void CApplication::SeekPercentage(float percent
)
3544 const auto appPlayer
= GetComponent
<CApplicationPlayer
>();
3545 const auto stackHelper
= GetComponent
<CApplicationStackHelper
>();
3547 if (appPlayer
->IsPlaying() && (percent
>= 0.0f
))
3549 if (!appPlayer
->CanSeek())
3551 if (stackHelper
->IsPlayingRegularStack())
3552 SeekTime(static_cast<double>(percent
) * 0.01 * GetTotalTime());
3554 appPlayer
->SeekPercentage(percent
);
3558 std::string
CApplication::GetCurrentPlayer()
3560 const auto appPlayer
= GetComponent
<CApplicationPlayer
>();
3561 return appPlayer
->GetCurrentPlayer();
3564 void CApplication::UpdateLibraries()
3566 const std::shared_ptr
<CSettings
> settings
= CServiceBroker::GetSettingsComponent()->GetSettings();
3567 if (settings
->GetBool(CSettings::SETTING_VIDEOLIBRARY_UPDATEONSTARTUP
))
3569 CLog::LogF(LOGINFO
, "Starting video library startup scan");
3570 CVideoLibraryQueue::GetInstance().ScanLibrary(
3571 "", false, !settings
->GetBool(CSettings::SETTING_VIDEOLIBRARY_BACKGROUNDUPDATE
));
3574 if (settings
->GetBool(CSettings::SETTING_MUSICLIBRARY_UPDATEONSTARTUP
))
3576 CLog::LogF(LOGINFO
, "Starting music library startup scan");
3577 CMusicLibraryQueue::GetInstance().ScanLibrary(
3578 "", MUSIC_INFO::CMusicInfoScanner::SCAN_NORMAL
,
3579 !settings
->GetBool(CSettings::SETTING_MUSICLIBRARY_BACKGROUNDUPDATE
));
3583 void CApplication::UpdateCurrentPlayArt()
3585 const auto appPlayer
= GetComponent
<CApplicationPlayer
>();
3586 if (!appPlayer
->IsPlayingAudio())
3588 //Clear and reload the art for the currently playing item to show updated art on OSD
3589 m_itemCurrentFile
->ClearArt();
3590 CMusicThumbLoader loader
;
3591 loader
.LoadItem(m_itemCurrentFile
.get());
3592 // Mirror changes to GUI item
3593 CServiceBroker::GetGUI()->GetInfoManager().SetCurrentItem(*m_itemCurrentFile
);
3596 bool CApplication::ProcessAndStartPlaylist(const std::string
& strPlayList
,
3597 PLAYLIST::CPlayList
& playlist
,
3598 PLAYLIST::Id playlistId
,
3601 CLog::Log(LOGDEBUG
, "CApplication::ProcessAndStartPlaylist({}, {})", strPlayList
, playlistId
);
3603 // initial exit conditions
3604 // no songs in playlist just return
3605 if (playlist
.size() == 0)
3609 if (playlistId
== PLAYLIST::TYPE_NONE
|| playlistId
== PLAYLIST::TYPE_PICTURE
)
3612 // setup correct playlist
3613 CServiceBroker::GetPlaylistPlayer().ClearPlaylist(playlistId
);
3615 // if the playlist contains an internet stream, this file will be used
3616 // to generate a thumbnail for musicplayer.cover
3617 m_strPlayListFile
= strPlayList
;
3619 // add the items to the playlist player
3620 CServiceBroker::GetPlaylistPlayer().Add(playlistId
, playlist
);
3622 // if we have a playlist
3623 if (CServiceBroker::GetPlaylistPlayer().GetPlaylist(playlistId
).size())
3626 CServiceBroker::GetPlaylistPlayer().SetCurrentPlaylist(playlistId
);
3627 CServiceBroker::GetPlaylistPlayer().Reset();
3628 CServiceBroker::GetPlaylistPlayer().Play(track
, "");
3634 bool CApplication::GetRenderGUI() const
3636 return GetComponent
<CApplicationPowerHandling
>()->GetRenderGUI();
3639 bool CApplication::SetLanguage(const std::string
&strLanguage
)
3641 // nothing to be done if the language hasn't changed
3642 if (strLanguage
== CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(CSettings::SETTING_LOCALE_LANGUAGE
))
3645 return CServiceBroker::GetSettingsComponent()->GetSettings()->SetString(CSettings::SETTING_LOCALE_LANGUAGE
, strLanguage
);
3648 bool CApplication::LoadLanguage(bool reload
)
3650 // load the configured language
3651 if (!g_langInfo
.SetLanguage("", reload
))
3654 // set the proper audio and subtitle languages
3655 const std::shared_ptr
<CSettings
> settings
= CServiceBroker::GetSettingsComponent()->GetSettings();
3656 g_langInfo
.SetAudioLanguage(settings
->GetString(CSettings::SETTING_LOCALE_AUDIOLANGUAGE
));
3657 g_langInfo
.SetSubtitleLanguage(settings
->GetString(CSettings::SETTING_LOCALE_SUBTITLELANGUAGE
));
3662 void CApplication::SetLoggingIn(bool switchingProfiles
)
3664 // don't save skin settings on unloading when logging into another profile
3665 // because in that case we have already loaded the new profile and
3666 // would therefore write the previous skin's settings into the new profile
3667 // instead of into the previous one
3668 GetComponent
<CApplicationSkinHandling
>()->m_saveSkinOnUnloading
= !switchingProfiles
;
3671 void CApplication::PrintStartupLog()
3673 CLog::Log(LOGINFO
, "-----------------------------------------------------------------------");
3674 CLog::Log(LOGINFO
, "Starting {} ({}). Platform: {} {} {}-bit", CSysInfo::GetAppName(),
3675 CSysInfo::GetVersion(), g_sysinfo
.GetBuildTargetPlatformName(),
3676 g_sysinfo
.GetBuildTargetCpuFamily(), g_sysinfo
.GetXbmcBitness());
3678 std::string buildType
;
3680 buildType
= "Debug";
3681 #elif defined(NDEBUG)
3682 buildType
= "Release";
3684 buildType
= "Unknown";
3687 CLog::Log(LOGINFO
, "Using {} {} x{}", buildType
, CSysInfo::GetAppName(),
3688 g_sysinfo
.GetXbmcBitness());
3689 CLog::Log(LOGINFO
, "{} compiled {} by {} for {} {} {}-bit {} ({})", CSysInfo::GetAppName(),
3690 CSysInfo::GetBuildDate(), g_sysinfo
.GetUsedCompilerNameAndVer(),
3691 g_sysinfo
.GetBuildTargetPlatformName(), g_sysinfo
.GetBuildTargetCpuFamily(),
3692 g_sysinfo
.GetXbmcBitness(), g_sysinfo
.GetBuildTargetPlatformVersionDecoded(),
3693 g_sysinfo
.GetBuildTargetPlatformVersion());
3695 std::string
deviceModel(g_sysinfo
.GetModelName());
3696 if (!g_sysinfo
.GetManufacturerName().empty())
3697 deviceModel
= g_sysinfo
.GetManufacturerName() + " " +
3698 (deviceModel
.empty() ? std::string("device") : deviceModel
);
3699 if (!deviceModel
.empty())
3700 CLog::Log(LOGINFO
, "Running on {} with {}, kernel: {} {} {}-bit version {}", deviceModel
,
3701 g_sysinfo
.GetOsPrettyNameWithVersion(), g_sysinfo
.GetKernelName(),
3702 g_sysinfo
.GetKernelCpuFamily(), g_sysinfo
.GetKernelBitness(),
3703 g_sysinfo
.GetKernelVersionFull());
3705 CLog::Log(LOGINFO
, "Running on {}, kernel: {} {} {}-bit version {}",
3706 g_sysinfo
.GetOsPrettyNameWithVersion(), g_sysinfo
.GetKernelName(),
3707 g_sysinfo
.GetKernelCpuFamily(), g_sysinfo
.GetKernelBitness(),
3708 g_sysinfo
.GetKernelVersionFull());
3710 CLog::Log(LOGINFO
, "FFmpeg version/source: {}", av_version_info());
3712 std::string
cpuModel(CServiceBroker::GetCPUInfo()->GetCPUModel());
3713 if (!cpuModel
.empty())
3715 CLog::Log(LOGINFO
, "Host CPU: {}, {} core{} available", cpuModel
,
3716 CServiceBroker::GetCPUInfo()->GetCPUCount(),
3717 (CServiceBroker::GetCPUInfo()->GetCPUCount() == 1) ? "" : "s");
3720 CLog::Log(LOGINFO
, "{} CPU core{} available", CServiceBroker::GetCPUInfo()->GetCPUCount(),
3721 (CServiceBroker::GetCPUInfo()->GetCPUCount() == 1) ? "" : "s");
3723 // Any system info logging that is unique to a platform
3724 m_ServiceManager
->GetPlatform().PlatformSyslog();
3726 #if defined(__arm__) || defined(__aarch64__)
3727 CLog::Log(LOGINFO
, "ARM Features: Neon {}",
3728 (CServiceBroker::GetCPUInfo()->GetCPUFeatures() & CPU_FEATURE_NEON
) ? "enabled"
3731 CSpecialProtocol::LogPaths();
3733 #ifdef HAS_WEB_SERVER
3734 CLog::Log(LOGINFO
, "Webserver extra whitelist paths: {}",
3735 StringUtils::Join(CCompileInfo::GetWebserverExtraWhitelist(), ", "));
3738 // Check, whether libkodi.so was reused (happens on Android, where the system does not unload
3739 // the lib on activity end, but keeps it loaded (as long as there is enough memory) and reuses
3740 // it on next activity start.
3741 static bool firstRun
= true;
3743 CLog::Log(LOGINFO
, "The executable running is: {}{}", CUtil::ResolveExecutablePath(),
3744 firstRun
? "" : " [reused]");
3748 std::string
hostname("[unknown]");
3749 m_ServiceManager
->GetNetwork().GetHostName(hostname
);
3750 CLog::Log(LOGINFO
, "Local hostname: {}", hostname
);
3751 std::string lowerAppName
= CCompileInfo::GetAppName();
3752 StringUtils::ToLower(lowerAppName
);
3753 CLog::Log(LOGINFO
, "Log File is located: {}.log",
3754 CSpecialProtocol::TranslatePath("special://logpath/" + lowerAppName
));
3755 CRegExp::LogCheckUtf8Support();
3756 CLog::Log(LOGINFO
, "-----------------------------------------------------------------------");
3759 void CApplication::CloseNetworkShares()
3761 CLog::Log(LOGDEBUG
,"CApplication::CloseNetworkShares: Closing all network shares");
3763 #if defined(HAS_FILESYSTEM_SMB) && !defined(TARGET_WINDOWS)
3767 #ifdef HAS_FILESYSTEM_NFS
3768 gNfsConnection
.Deinit();
3771 for (const auto& vfsAddon
: CServiceBroker::GetVFSAddonCache().GetAddonInstances())
3772 vfsAddon
->DisconnectAll();