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 #include "music/MusicFileItemClassify.h"
64 #include "network/NetworkFileItemClassify.h"
65 #include "playlists/PlayListFileItemClassify.h"
66 #include "video/VideoFileItemClassify.h"
67 #ifdef HAS_FILESYSTEM_NFS
68 #include "filesystem/NFSFile.h"
70 #include "filesystem/PluginDirectory.h"
71 #include "filesystem/SpecialProtocol.h"
73 #include "filesystem/UPnPDirectory.h"
75 #include "guilib/GUIAudioManager.h"
76 #include "guilib/GUIComponent.h"
77 #include "guilib/GUIControlProfiler.h"
78 #include "guilib/GUIFontManager.h"
79 #include "guilib/GUIWindowManager.h"
80 #include "guilib/LocalizeStrings.h"
81 #include "guilib/StereoscopicsManager.h"
82 #include "guilib/TextureManager.h"
83 #include "input/InertialScrollingHandler.h"
84 #include "input/InputManager.h"
85 #include "input/actions/Action.h"
86 #include "input/actions/ActionIDs.h"
87 #include "input/actions/ActionTranslator.h"
88 #include "input/keyboard/KeyboardLayoutManager.h"
89 #include "interfaces/AnnouncementManager.h"
90 #include "interfaces/builtins/Builtins.h"
91 #include "interfaces/generic/ScriptInvocationManager.h"
92 #include "interfaces/json-rpc/JSONRPC.h"
94 #include "interfaces/python/XBPython.h"
96 #include "messaging/ApplicationMessenger.h"
97 #include "messaging/ThreadMessage.h"
98 #include "messaging/helpers/DialogHelper.h"
99 #include "messaging/helpers/DialogOKHelper.h"
100 #include "music/MusicLibraryQueue.h"
101 #include "music/MusicThumbLoader.h"
102 #include "music/MusicUtils.h"
103 #include "music/infoscanner/MusicInfoScanner.h"
104 #include "music/tags/MusicInfoTag.h"
105 #include "network/EventServer.h"
106 #include "network/Network.h"
107 #include "network/ZeroconfBrowser.h"
109 #include "network/upnp/UPnP.h"
111 #include "peripherals/Peripherals.h"
112 #include "pictures/SlideShowDelegator.h"
113 #include "platform/Environment.h"
114 #include "playlists/PlayList.h"
115 #include "playlists/PlayListFactory.h"
116 #include "playlists/SmartPlayList.h"
117 #include "powermanagement/PowerManager.h"
118 #include "profiles/ProfileManager.h"
119 #include "pvr/PVRManager.h"
120 #include "pvr/guilib/PVRGUIActionsPlayback.h"
121 #include "pvr/guilib/PVRGUIActionsPowerManagement.h"
122 #include "settings/AdvancedSettings.h"
123 #include "settings/DisplaySettings.h"
124 #include "settings/MediaSettings.h"
125 #include "settings/Settings.h"
126 #include "settings/SettingsComponent.h"
127 #include "speech/ISpeechRecognition.h"
128 #include "storage/MediaManager.h"
129 #include "threads/SingleLock.h"
130 #include "threads/SystemClock.h"
131 #include "utils/AlarmClock.h"
132 #include "utils/CPUInfo.h"
133 #include "utils/CharsetConverter.h"
134 #include "utils/ContentUtils.h"
135 #include "utils/FileExtensionProvider.h"
136 #include "utils/JobManager.h"
137 #include "utils/LangCodeExpander.h"
138 #include "utils/PlayerUtils.h"
139 #include "utils/RegExp.h"
140 #include "utils/Screenshot.h"
141 #include "utils/StringUtils.h"
142 #include "utils/SystemInfo.h"
143 #include "utils/TimeUtils.h"
144 #include "utils/URIUtils.h"
145 #include "utils/Variant.h"
146 #include "utils/XTimeUtils.h"
147 #include "utils/log.h"
148 #include "video/Bookmark.h"
149 #include "video/PlayerController.h"
150 #include "video/VideoLibraryQueue.h"
151 #include "video/dialogs/GUIDialogVideoBookmarks.h"
152 #ifdef TARGET_WINDOWS
153 #include "win32util.h"
155 #include "windowing/WinSystem.h"
156 #include "windowing/WindowSystemFactory.h"
158 #if defined(TARGET_ANDROID)
159 #include "platform/android/activity/XBMCApp.h"
162 #include "platform/darwin/DarwinUtils.h"
164 #ifdef TARGET_DARWIN_OSX
165 #ifdef HAS_XBMCHELPER
166 #include "platform/darwin/osx/XBMCHelper.h"
170 #include "platform/posix/PlatformPosix.h"
171 #include "platform/posix/XHandle.h"
173 #if defined(TARGET_POSIX) && defined(HAS_FILESYSTEM_SMB)
174 #include "platform/posix/filesystem/SMBFile.h"
177 #include "platform/win32/threads/Win32Exception.h"
188 #include <X11/Xlib.h>
190 #ifdef HAS_OPTICAL_DRIVE
191 #include <cdio/logging.h>
194 using namespace ADDON
;
195 using namespace XFILE
;
196 #ifdef HAS_OPTICAL_DRIVE
197 using namespace MEDIA_DETECT
;
199 using namespace MUSIC_INFO
;
200 using namespace EVENTSERVER
;
201 using namespace JSONRPC
;
203 using namespace PERIPHERALS
;
204 using namespace KODI
;
205 using namespace KODI::MESSAGING
;
206 using namespace ActiveAE
;
208 using namespace XbmcThreads
;
209 using namespace std::chrono_literals
;
211 using KODI::MESSAGING::HELPERS::DialogResponse
;
213 using namespace std::chrono_literals
;
215 #define MAX_FFWD_SPEED 5
217 CApplication::CApplication(void)
219 #ifdef HAS_OPTICAL_DRIVE
220 m_Autorun(new CAutorun()),
222 m_pInertialScrollingHandler(new CInertialScrollingHandler()),
223 m_WaitingExternalCalls(0),
224 m_itemCurrentFile(std::make_shared
<CFileItem
>()),
225 m_playerEvent(true, true)
227 TiXmlBase::SetCondenseWhiteSpace(false);
233 // register application components
234 RegisterComponent(std::make_shared
<CApplicationActionListeners
>(m_critSection
));
235 RegisterComponent(std::make_shared
<CApplicationPlayer
>());
236 RegisterComponent(std::make_shared
<CApplicationPowerHandling
>());
237 RegisterComponent(std::make_shared
<CApplicationSkinHandling
>(this, this, m_bInitializing
));
238 RegisterComponent(std::make_shared
<CApplicationVolumeHandling
>());
239 RegisterComponent(std::make_shared
<CApplicationStackHelper
>());
242 CApplication::~CApplication(void)
244 DeregisterComponent(typeid(CApplicationStackHelper
));
245 DeregisterComponent(typeid(CApplicationVolumeHandling
));
246 DeregisterComponent(typeid(CApplicationSkinHandling
));
247 DeregisterComponent(typeid(CApplicationPowerHandling
));
248 DeregisterComponent(typeid(CApplicationPlayer
));
249 DeregisterComponent(typeid(CApplicationActionListeners
));
252 extern "C" void __stdcall
init_emu_environ();
253 extern "C" void __stdcall
update_emu_environ();
254 extern "C" void __stdcall
cleanup_emu_environ();
256 bool CApplication::Create()
262 CServiceBroker::RegisterCPUInfo(CCPUInfo::GetCPUInfo());
264 // Register JobManager service
265 CServiceBroker::RegisterJobManager(std::make_shared
<CJobManager
>());
267 // Announcement service
268 m_pAnnouncementManager
= std::make_shared
<ANNOUNCEMENT::CAnnouncementManager
>();
269 m_pAnnouncementManager
->Start();
270 CServiceBroker::RegisterAnnouncementManager(m_pAnnouncementManager
);
272 const auto appMessenger
= std::make_shared
<CApplicationMessenger
>();
273 CServiceBroker::RegisterAppMessenger(appMessenger
);
275 const auto keyboardLayoutManager
= std::make_shared
<KEYBOARD::CKeyboardLayoutManager
>();
276 CServiceBroker::RegisterKeyboardLayoutManager(keyboardLayoutManager
);
278 m_ServiceManager
= std::make_unique
<CServiceManager
>();
280 if (!m_ServiceManager
->InitStageOne())
285 // here we register all global classes for the CApplicationMessenger,
286 // after that we can send messages to the corresponding modules
287 appMessenger
->RegisterReceiver(this);
288 appMessenger
->RegisterReceiver(&CServiceBroker::GetPlaylistPlayer());
289 appMessenger
->SetGUIThread(CThread::GetCurrentThreadId());
290 appMessenger
->SetProcessThread(CThread::GetCurrentThreadId());
292 // copy required files
293 CUtil::CopyUserDataIfNeeded("special://masterprofile/", "RssFeeds.xml");
294 CUtil::CopyUserDataIfNeeded("special://masterprofile/", "favourites.xml");
295 CUtil::CopyUserDataIfNeeded("special://masterprofile/", "Lircmap.xml");
297 CServiceBroker::GetLogging().Initialize(CSpecialProtocol::TranslatePath("special://logpath"));
299 #ifdef TARGET_POSIX //! @todo Win32 has no special://home/ mapping by default, so we
300 //! must create these here. Ideally this should be using special://home/ and
301 //! be platform agnostic (i.e. unify the InitDirectories*() functions)
302 if (!CServiceBroker::GetAppParams()->HasPlatformDirectories())
305 CDirectory::Create("special://xbmc/addons");
308 // Init our DllLoaders emu env
313 // initialize network protocols
314 avformat_network_init();
315 // set avutil callback
316 av_log_set_callback(ff_avutil_log
);
318 CLog::Log(LOGINFO
, "loading settings");
319 const auto settingsComponent
= CServiceBroker::GetSettingsComponent();
320 if (!settingsComponent
->Load())
323 // Log Cache GUI settings (replacement of cache in advancedsettings.xml)
324 const auto settings
= settingsComponent
->GetSettings();
325 const float readFactor
= settings
->GetInt(CSettings::SETTING_FILECACHE_READFACTOR
) / 100.0f
;
327 "New Cache GUI Settings (replacement of cache in advancedsettings.xml) are:\n Buffer "
328 "Mode: {}\n Memory Size: {} MB\n Read "
329 "Factor: {:.2f} x {}\n Chunk Size : {} bytes",
330 settings
->GetInt(CSettings::SETTING_FILECACHE_BUFFERMODE
),
331 settings
->GetInt(CSettings::SETTING_FILECACHE_MEMORYSIZE
), readFactor
,
332 (readFactor
< 1.0f
) ? "(adaptive)" : "",
333 settings
->GetInt(CSettings::SETTING_FILECACHE_CHUNKSIZE
));
335 CLog::Log(LOGINFO
, "creating subdirectories");
336 const std::shared_ptr
<CProfileManager
> profileManager
= settingsComponent
->GetProfileManager();
337 CLog::Log(LOGINFO
, "userdata folder: {}",
338 CURL::GetRedacted(profileManager
->GetProfileUserDataFolder()));
339 CLog::Log(LOGINFO
, "recording folder: {}",
340 CURL::GetRedacted(settings
->GetString(CSettings::SETTING_AUDIOCDS_RECORDINGPATH
)));
341 CLog::Log(LOGINFO
, "screenshots folder: {}",
342 CURL::GetRedacted(settings
->GetString(CSettings::SETTING_DEBUG_SCREENSHOTPATH
)));
343 CDirectory::Create(profileManager
->GetUserDataFolder());
344 CDirectory::Create(profileManager
->GetProfileUserDataFolder());
345 profileManager
->CreateProfileFolders();
347 update_emu_environ();//apply the GUI settings
349 // application inbound service
350 m_pAppPort
= std::make_shared
<CAppInboundProtocol
>(*this);
351 CServiceBroker::RegisterAppPort(m_pAppPort
);
353 if (!m_ServiceManager
->InitStageTwo(
354 settingsComponent
->GetProfileManager()->GetProfileUserDataFolder()))
359 m_pActiveAE
= std::make_unique
<ActiveAE::CActiveAE
>();
360 CServiceBroker::RegisterAE(m_pActiveAE
.get());
362 // initialize m_replayGainSettings
363 GetComponent
<CApplicationVolumeHandling
>()->CacheReplayGainSettings(*settings
);
365 // load the keyboard layouts
366 if (!keyboardLayoutManager
->Load())
368 CLog::Log(LOGFATAL
, "CApplication::Create: Unable to load keyboard layouts");
372 // set user defined CA trust bundle
374 CSpecialProtocol::TranslatePath(settingsComponent
->GetAdvancedSettings()->m_caTrustFile
);
377 if (XFILE::CFile::Exists(caCert
))
379 CEnvironment::setenv("SSL_CERT_FILE", caCert
, 1);
380 CLog::Log(LOGDEBUG
, "CApplication::Create - SSL_CERT_FILE: {}", caCert
);
384 CLog::Log(LOGDEBUG
, "CApplication::Create - Error reading SSL_CERT_FILE: {} -> ignored",
389 CUtil::InitRandomSeed();
391 m_lastRenderTime
= std::chrono::steady_clock::now();
395 bool CApplication::CreateGUI()
397 m_frameMoveGuard
.lock();
399 const auto appPower
= GetComponent
<CApplicationPowerHandling
>();
400 appPower
->SetRenderGUI(true);
402 auto windowSystems
= KODI::WINDOWING::CWindowSystemFactory::GetWindowSystems();
404 const std::string
& windowing
= CServiceBroker::GetAppParams()->GetWindowing();
406 if (!windowing
.empty())
407 windowSystems
= {windowing
};
409 for (auto& windowSystem
: windowSystems
)
411 CLog::Log(LOGDEBUG
, "CApplication::{} - trying to init {} windowing system", __FUNCTION__
,
413 m_pWinSystem
= KODI::WINDOWING::CWindowSystemFactory::CreateWindowSystem(windowSystem
);
418 if (!windowing
.empty() && windowing
!= windowSystem
)
421 CServiceBroker::RegisterWinSystem(m_pWinSystem
.get());
423 if (!m_pWinSystem
->InitWindowSystem())
425 CLog::Log(LOGDEBUG
, "CApplication::{} - unable to init {} windowing system", __FUNCTION__
,
427 m_pWinSystem
->DestroyWindowSystem();
428 m_pWinSystem
.reset();
429 CServiceBroker::UnregisterWinSystem();
434 CLog::Log(LOGINFO
, "CApplication::{} - using the {} windowing system", __FUNCTION__
,
442 CLog::Log(LOGFATAL
, "CApplication::{} - unable to init windowing system", __FUNCTION__
);
443 CServiceBroker::UnregisterWinSystem();
447 // Retrieve the matching resolution based on GUI settings
448 bool sav_res
= false;
449 CDisplaySettings::GetInstance().SetCurrentResolution(CDisplaySettings::GetInstance().GetDisplayResolution());
450 CLog::Log(LOGINFO
, "Checking resolution {}",
451 CDisplaySettings::GetInstance().GetCurrentResolution());
452 if (!CServiceBroker::GetWinSystem()->GetGfxContext().IsValidResolution(CDisplaySettings::GetInstance().GetCurrentResolution()))
454 CLog::Log(LOGINFO
, "Setting safe mode {}", RES_DESKTOP
);
455 // defer saving resolution after window was created
456 CDisplaySettings::GetInstance().SetCurrentResolution(RES_DESKTOP
);
460 // update the window resolution
461 const std::shared_ptr
<CSettings
> settings
= CServiceBroker::GetSettingsComponent()->GetSettings();
462 CServiceBroker::GetWinSystem()->SetWindowResolution(settings
->GetInt(CSettings::SETTING_WINDOW_WIDTH
), settings
->GetInt(CSettings::SETTING_WINDOW_HEIGHT
));
464 if (CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_startFullScreen
&& CDisplaySettings::GetInstance().GetCurrentResolution() == RES_WINDOW
)
466 // defer saving resolution after window was created
467 CDisplaySettings::GetInstance().SetCurrentResolution(RES_DESKTOP
);
471 if (!CServiceBroker::GetWinSystem()->GetGfxContext().IsValidResolution(CDisplaySettings::GetInstance().GetCurrentResolution()))
473 // Oh uh - doesn't look good for starting in their wanted screenmode
474 CLog::Log(LOGERROR
, "The screen resolution requested is not valid, resetting to a valid mode");
475 CDisplaySettings::GetInstance().SetCurrentResolution(RES_DESKTOP
);
483 // Set default screen saver mode
484 auto screensaverModeSetting
= std::static_pointer_cast
<CSettingString
>(settings
->GetSetting(CSettings::SETTING_SCREENSAVER_MODE
));
485 // Can only set this after windowing has been initialized since it depends on it
486 if (CServiceBroker::GetWinSystem()->GetOSScreenSaver())
488 // If OS has a screen saver, use it by default
489 screensaverModeSetting
->SetDefault("");
493 // If OS has no screen saver, use Kodi one by default
494 screensaverModeSetting
->SetDefault("screensaver.xbmc.builtin.dim");
498 CDisplaySettings::GetInstance().SetCurrentResolution(RES_DESKTOP
, true);
500 m_pGUI
= std::make_unique
<CGUIComponent
>();
503 // Splash requires gui component!!
504 CServiceBroker::GetRenderSystem()->ShowSplash("");
506 // The key mappings may already have been loaded by a peripheral
507 CLog::Log(LOGINFO
, "load keymapping");
508 if (!CServiceBroker::GetInputManager().LoadKeymaps())
511 RESOLUTION_INFO info
= CServiceBroker::GetWinSystem()->GetGfxContext().GetResInfo();
512 CLog::Log(LOGINFO
, "GUI format {}x{}, Display {}", info
.iWidth
, info
.iHeight
, info
.strMode
);
517 bool CApplication::InitWindow(RESOLUTION res
)
519 if (res
== RES_INVALID
)
520 res
= CDisplaySettings::GetInstance().GetCurrentResolution();
522 bool bFullScreen
= res
!= RES_WINDOW
;
523 if (!CServiceBroker::GetWinSystem()->CreateNewWindow(CSysInfo::GetAppName(),
524 bFullScreen
, CDisplaySettings::GetInstance().GetResolutionInfo(res
)))
526 CLog::Log(LOGFATAL
, "CApplication::Create: Unable to create window");
530 if (!CServiceBroker::GetRenderSystem()->InitRenderSystem())
532 CLog::Log(LOGFATAL
, "CApplication::Create: Unable to init rendering system");
535 // set GUI res and force the clear of the screen
536 CServiceBroker::GetWinSystem()->GetGfxContext().SetVideoResolution(res
, false);
540 bool CApplication::Initialize()
542 m_pActiveAE
->Start();
543 // restore AE's previous volume state
545 const auto appVolume
= GetComponent
<CApplicationVolumeHandling
>();
546 const auto level
= appVolume
->GetVolumeRatio();
547 const auto muted
= appVolume
->IsMuted();
548 appVolume
->SetHardwareVolume(level
);
549 CServiceBroker::GetActiveAE()->SetMute(muted
);
551 #if defined(HAS_OPTICAL_DRIVE) && \
552 !defined(TARGET_WINDOWS) // somehow this throws an "unresolved external symbol" on win32
553 // turn off cdio logging
554 cdio_loglevel_default
= CDIO_LOG_ERROR
;
557 // load the language and its translated strings
558 if (!LoadLanguage(false))
561 // load media manager sources (e.g. root addon type sources depend on language strings to be available)
562 CServiceBroker::GetMediaManager().LoadSources();
564 const std::shared_ptr
<CProfileManager
> profileManager
= CServiceBroker::GetSettingsComponent()->GetProfileManager();
566 profileManager
->GetEventLog().Add(EventPtr(new CNotificationEvent(
567 StringUtils::Format(g_localizeStrings
.Get(177), g_sysinfo
.GetAppName()),
568 StringUtils::Format(g_localizeStrings
.Get(178), g_sysinfo
.GetAppName()),
569 "special://xbmc/media/icon256x256.png", EventLevel::Basic
)));
571 m_ServiceManager
->GetNetwork().WaitForNet();
573 // initialize (and update as needed) our databases
574 CDatabaseManager
&databaseManager
= m_ServiceManager
->GetDatabaseManager();
577 CServiceBroker::GetJobManager()->Submit([&databaseManager
, &event
]() {
578 databaseManager
.Initialize();
582 std::string localizedStr
= g_localizeStrings
.Get(24150);
584 while (!event
.Wait(1000ms
))
586 if (databaseManager
.IsUpgrading())
587 CServiceBroker::GetRenderSystem()->ShowSplash(std::string(iDots
, ' ') + localizedStr
+ std::string(iDots
, '.'));
594 CServiceBroker::GetRenderSystem()->ShowSplash("");
596 // Initialize GUI font manager to build/update fonts cache
597 //! @todo Move GUIFontManager into service broker and drop the global reference
599 GUIFontManager
& guiFontManager
= g_fontManager
;
600 CServiceBroker::GetJobManager()->Submit([&guiFontManager
, &event
]() {
601 guiFontManager
.Initialize();
604 localizedStr
= g_localizeStrings
.Get(39175);
606 while (!event
.Wait(1000ms
))
608 if (g_fontManager
.IsUpdating())
609 CServiceBroker::GetRenderSystem()->ShowSplash(std::string(iDots
, ' ') + localizedStr
+
610 std::string(iDots
, '.'));
617 CServiceBroker::GetRenderSystem()->ShowSplash("");
619 // GUI depends on seek handler
620 GetComponent
<CApplicationPlayer
>()->GetSeekHandler().Configure();
622 const auto skinHandling
= GetComponent
<CApplicationSkinHandling
>();
624 bool uiInitializationFinished
= false;
626 if (CServiceBroker::GetGUI()->GetWindowManager().Initialized())
628 const auto settings
= CServiceBroker::GetSettingsComponent()->GetSettings();
630 CServiceBroker::GetGUI()->GetWindowManager().CreateWindows();
632 skinHandling
->m_confirmSkinChange
= false;
634 std::vector
<AddonInfoPtr
> incompatibleAddons
;
638 if (CServiceBroker::GetAddonMgr().GetIncompatibleEnabledAddonInfos(incompatibleAddons
))
640 if (CAddonSystemSettings::GetInstance().GetAddonAutoUpdateMode() == AUTO_UPDATES_ON
)
642 CServiceBroker::GetJobManager()->Submit(
643 [&event
, &incompatibleAddons
]() {
644 if (CServiceBroker::GetRepositoryUpdater().CheckForUpdates())
645 CServiceBroker::GetRepositoryUpdater().Await();
647 incompatibleAddons
= CServiceBroker::GetAddonMgr().MigrateAddons();
650 CJob::PRIORITY_DEDICATED
);
651 localizedStr
= g_localizeStrings
.Get(24151);
653 while (!event
.Wait(1000ms
))
655 CServiceBroker::GetRenderSystem()->ShowSplash(std::string(iDots
, ' ') + localizedStr
+
656 std::string(iDots
, '.'));
662 m_incompatibleAddons
= incompatibleAddons
;
666 // If no update is active disable all incompatible addons during start
667 m_incompatibleAddons
=
668 CServiceBroker::GetAddonMgr().DisableIncompatibleAddons(incompatibleAddons
);
672 // Start splashscreen and load skin
673 CServiceBroker::GetRenderSystem()->ShowSplash("");
674 skinHandling
->m_confirmSkinChange
= true;
676 auto setting
= settings
->GetSetting(CSettings::SETTING_LOOKANDFEEL_SKIN
);
679 CLog::Log(LOGFATAL
, "Failed to load setting for: {}", CSettings::SETTING_LOOKANDFEEL_SKIN
);
683 CServiceBroker::RegisterTextureCache(std::make_shared
<CTextureCache
>());
685 std::string skinId
= settings
->GetString(CSettings::SETTING_LOOKANDFEEL_SKIN
);
686 if (!skinHandling
->LoadSkin(skinId
))
688 CLog::Log(LOGERROR
, "Failed to load skin '{}'", skinId
);
689 std::string defaultSkin
=
690 std::static_pointer_cast
<const CSettingString
>(setting
)->GetDefault();
691 if (!skinHandling
->LoadSkin(defaultSkin
))
693 CLog::Log(LOGFATAL
, "Default skin '{}' could not be loaded! Terminating..", defaultSkin
);
698 // initialize splash window after splash screen disappears
699 // because we need a real window in the background which gets
700 // rendered while we load the main window or enter the master lock key
701 CServiceBroker::GetGUI()->GetWindowManager().ActivateWindow(WINDOW_SPLASH
);
703 if (settings
->GetBool(CSettings::SETTING_MASTERLOCK_STARTUPLOCK
) &&
704 profileManager
->GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE
&&
705 !profileManager
->GetMasterProfile().getLockCode().empty())
707 g_passwordManager
.CheckStartUpLock();
710 // check if we should use the login screen
711 if (profileManager
->UsingLoginScreen())
713 CServiceBroker::GetGUI()->GetWindowManager().ActivateWindow(WINDOW_LOGIN_SCREEN
);
717 // activate the configured start window
718 int firstWindow
= g_SkinInfo
->GetFirstWindow();
719 CServiceBroker::GetGUI()->GetWindowManager().ActivateWindow(firstWindow
);
721 if (CServiceBroker::GetGUI()->GetWindowManager().IsWindowActive(WINDOW_STARTUP_ANIM
))
723 CLog::Log(LOGWARNING
, "CApplication::Initialize - startup.xml taints init process");
726 // the startup window is considered part of the initialization as it most likely switches to the final window
727 uiInitializationFinished
= firstWindow
!= WINDOW_STARTUP_ANIM
;
730 else //No GUI Created
732 uiInitializationFinished
= true;
735 CJSONRPC::Initialize();
737 CServiceBroker::RegisterSpeechRecognition(speech::ISpeechRecognition::CreateInstance());
739 if (!m_ServiceManager
->InitStageThree(profileManager
))
741 CLog::Log(LOGERROR
, "Application - Init3 failed");
746 CLog::Log(LOGINFO
, "removing tempfiles");
747 CUtil::RemoveTempFiles();
749 if (!profileManager
->UsingLoginScreen())
755 m_slowTimer
.StartZero();
757 // register action listeners
758 const auto appListener
= GetComponent
<CApplicationActionListeners
>();
759 const auto appPlayer
= GetComponent
<CApplicationPlayer
>();
760 appListener
->RegisterActionListener(&appPlayer
->GetSeekHandler());
761 appListener
->RegisterActionListener(&CPlayerController::GetInstance());
763 CServiceBroker::GetRepositoryUpdater().Start();
764 if (!profileManager
->UsingLoginScreen())
765 CServiceBroker::GetServiceAddons().Start();
767 CLog::Log(LOGINFO
, "initialize done");
769 const auto appPower
= GetComponent
<CApplicationPowerHandling
>();
770 appPower
->CheckOSScreenSaverInhibitionSetting();
771 // reset our screensaver (starts timers etc.)
772 appPower
->ResetScreenSaver();
774 // if the user interfaces has been fully initialized let everyone know
775 if (uiInitializationFinished
)
777 CGUIMessage
msg(GUI_MSG_NOTIFY_ALL
, 0, 0, GUI_MSG_UI_READY
);
778 CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg
);
784 bool CApplication::OnSettingsSaving() const
786 // don't save settings when we're busy stopping the application
787 // a lot of screens try to save settings on deinit and deinit is
788 // called for every screen when the application is stopping
792 void CApplication::Render()
794 // do not render if we are stopped or in background
798 const auto appPlayer
= GetComponent
<CApplicationPlayer
>();
799 const auto appPower
= GetComponent
<CApplicationPowerHandling
>();
801 bool hasRendered
= false;
803 // Whether externalplayer is playing and we're unfocused
804 bool extPlayerActive
= appPlayer
->IsExternalPlaying() && !m_AppFocused
;
806 if (!extPlayerActive
&& CServiceBroker::GetWinSystem()->GetGfxContext().IsFullScreenVideo() &&
807 !appPlayer
->IsPausedPlayback())
809 appPower
->ResetScreenSaver();
812 if (!CServiceBroker::GetRenderSystem()->BeginRender())
816 if (appPower
->GetRenderGUI() && !m_skipGuiRender
)
818 if (CServiceBroker::GetWinSystem()->GetGfxContext().GetStereoMode())
820 CServiceBroker::GetWinSystem()->GetGfxContext().SetStereoView(RENDER_STEREO_VIEW_LEFT
);
821 hasRendered
|= CServiceBroker::GetGUI()->GetWindowManager().Render();
823 if (CServiceBroker::GetWinSystem()->GetGfxContext().GetStereoMode() != RENDER_STEREO_MODE_MONO
)
825 CServiceBroker::GetWinSystem()->GetGfxContext().SetStereoView(RENDER_STEREO_VIEW_RIGHT
);
826 hasRendered
|= CServiceBroker::GetGUI()->GetWindowManager().Render();
828 CServiceBroker::GetWinSystem()->GetGfxContext().SetStereoView(RENDER_STEREO_VIEW_OFF
);
832 hasRendered
|= CServiceBroker::GetGUI()->GetWindowManager().Render();
834 // execute post rendering actions (finalize window closing)
835 CServiceBroker::GetGUI()->GetWindowManager().AfterRender();
837 m_lastRenderTime
= std::chrono::steady_clock::now();
840 // render video layer
841 CServiceBroker::GetGUI()->GetWindowManager().RenderEx();
843 CServiceBroker::GetRenderSystem()->EndRender();
845 // reset our info cache - we do this at the end of Render so that it is
846 // fresh for the next process(), or after a windowclose animation (where process()
848 CGUIInfoManager
& infoMgr
= CServiceBroker::GetGUI()->GetInfoManager();
849 infoMgr
.ResetCache();
850 infoMgr
.GetInfoProviders().GetGUIControlsInfoProvider().ResetContainerMovingCache();
854 infoMgr
.GetInfoProviders().GetSystemInfoProvider().UpdateFPS();
857 CServiceBroker::GetWinSystem()->GetGfxContext().Flip(hasRendered
,
858 appPlayer
->IsRenderingVideoLayer());
860 CTimeUtils::UpdateFrameTime(hasRendered
);
863 bool CApplication::OnAction(const CAction
&action
)
865 // special case for switching between GUI & fullscreen mode.
866 if (action
.GetID() == ACTION_SHOW_GUI
)
867 { // Switch to fullscreen mode if we can
868 CGUIComponent
* gui
= CServiceBroker::GetGUI();
871 if (gui
->GetWindowManager().SwitchToFullScreen())
873 GetComponent
<CApplicationPowerHandling
>()->m_navigationTimer
.StartZero();
879 const auto appPlayer
= GetComponent
<CApplicationPlayer
>();
881 if (action
.GetID() == ACTION_TOGGLE_FULLSCREEN
)
883 CServiceBroker::GetWinSystem()->GetGfxContext().ToggleFullScreen();
884 appPlayer
->TriggerUpdateResolution();
888 if (action
.IsMouse())
889 CServiceBroker::GetInputManager().SetMouseActive(true);
891 if (action
.GetID() == ACTION_CREATE_EPISODE_BOOKMARK
)
893 CGUIDialogVideoBookmarks::OnAddEpisodeBookmark();
895 if (action
.GetID() == ACTION_CREATE_BOOKMARK
)
897 CGUIDialogVideoBookmarks::OnAddBookmark();
900 // The action PLAYPAUSE behaves as ACTION_PAUSE if we are currently
901 // playing or ACTION_PLAYER_PLAY if we are seeking (FF/RW) or not playing.
902 if (action
.GetID() == ACTION_PLAYER_PLAYPAUSE
)
904 CSlideShowDelegator
& slideShow
= CServiceBroker::GetSlideShowDelegator();
905 if ((appPlayer
->IsPlaying() && appPlayer
->GetPlaySpeed() == 1) ||
906 (slideShow
.InSlideShow() && !slideShow
.IsPaused()))
907 return OnAction(CAction(ACTION_PAUSE
));
909 return OnAction(CAction(ACTION_PLAYER_PLAY
));
912 //if the action would start or stop inertial scrolling
913 //by gesture - bypass the normal OnAction handler of current window
914 if( !m_pInertialScrollingHandler
->CheckForInertialScrolling(&action
) )
917 // just pass the action to the current window and let it handle it
918 if (CServiceBroker::GetGUI()->GetWindowManager().OnAction(action
))
920 GetComponent
<CApplicationPowerHandling
>()->ResetNavigationTimer();
925 // handle extra global presses
927 // notify action listeners
928 if (GetComponent
<CApplicationActionListeners
>()->NotifyActionListeners(action
))
931 // screenshot : take a screenshot :)
932 if (action
.GetID() == ACTION_TAKE_SCREENSHOT
)
934 CScreenShot::TakeScreenshot();
937 // Display HDR : toggle HDR on/off
938 if (action
.GetID() == ACTION_HDR_TOGGLE
)
940 // Only enables manual HDR toggle if no video is playing or auto HDR switch is disabled
941 if (appPlayer
->IsPlayingVideo() && CServiceBroker::GetWinSystem()->IsHDRDisplaySettingEnabled())
944 HDR_STATUS hdrStatus
= CServiceBroker::GetWinSystem()->ToggleHDR();
946 if (hdrStatus
== HDR_STATUS::HDR_OFF
)
948 CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Info
, g_localizeStrings
.Get(34220),
949 g_localizeStrings
.Get(34221));
951 else if (hdrStatus
== HDR_STATUS::HDR_ON
)
953 CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Info
, g_localizeStrings
.Get(34220),
954 g_localizeStrings
.Get(34222));
958 // Tone Mapping : switch to next tone map method
959 if (action
.GetID() == ACTION_CYCLE_TONEMAP_METHOD
)
961 // Only enables tone mapping switch if display is not HDR capable or HDR is not enabled
962 if (CServiceBroker::GetWinSystem()->IsHDRDisplaySettingEnabled())
965 if (appPlayer
->IsPlayingVideo())
967 CVideoSettings vs
= appPlayer
->GetVideoSettings();
968 vs
.m_ToneMapMethod
= static_cast<ETONEMAPMETHOD
>(static_cast<int>(vs
.m_ToneMapMethod
) + 1);
969 if (vs
.m_ToneMapMethod
>= VS_TONEMAPMETHOD_MAX
)
971 static_cast<ETONEMAPMETHOD
>(static_cast<int>(VS_TONEMAPMETHOD_OFF
) + 1);
973 appPlayer
->SetVideoSettings(vs
);
976 switch (vs
.m_ToneMapMethod
)
978 case VS_TONEMAPMETHOD_REINHARD
:
981 case VS_TONEMAPMETHOD_ACES
:
984 case VS_TONEMAPMETHOD_HABLE
:
988 throw std::logic_error("Tonemapping method not found. Did you forget to add a mapping?");
990 CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Info
, g_localizeStrings
.Get(34224),
991 g_localizeStrings
.Get(code
), 1000, false, 500);
995 // built in functions : execute the built-in
996 if (action
.GetID() == ACTION_BUILT_IN_FUNCTION
)
998 if (!CBuiltins::GetInstance().IsSystemPowerdownCommand(action
.GetName()) ||
999 CServiceBroker::GetPVRManager().Get
<PVR::GUI::PowerManagement
>().CanSystemPowerdown())
1001 CBuiltins::GetInstance().Execute(action
.GetName());
1002 GetComponent
<CApplicationPowerHandling
>()->ResetNavigationTimer();
1008 if (action
.GetID() == ACTION_RELOAD_KEYMAPS
)
1009 CServiceBroker::GetInputManager().ReloadKeymaps();
1011 // show info : Shows the current video or song information
1012 if (action
.GetID() == ACTION_SHOW_INFO
)
1014 CServiceBroker::GetGUI()->GetInfoManager().GetInfoProviders().GetPlayerInfoProvider().ToggleShowInfo();
1018 if (action
.GetID() == ACTION_SET_RATING
&& appPlayer
->IsPlayingAudio())
1020 int userrating
= MUSIC_UTILS::ShowSelectRatingDialog(m_itemCurrentFile
->GetMusicInfoTag()->GetUserrating());
1021 if (userrating
< 0) // Nothing selected, so user rating unchanged
1023 userrating
= std::min(userrating
, 10);
1024 if (userrating
!= m_itemCurrentFile
->GetMusicInfoTag()->GetUserrating())
1026 m_itemCurrentFile
->GetMusicInfoTag()->SetUserrating(userrating
);
1027 // Mirror changes to GUI item
1028 CServiceBroker::GetGUI()->GetInfoManager().SetCurrentItem(*m_itemCurrentFile
);
1030 // Asynchronously update song userrating in music library
1031 MUSIC_UTILS::UpdateSongRatingJob(m_itemCurrentFile
, userrating
);
1033 // Tell all windows (e.g. playlistplayer, media windows) to update the fileitem
1034 CGUIMessage
msg(GUI_MSG_NOTIFY_ALL
, 0, 0, GUI_MSG_UPDATE_ITEM
, 0, m_itemCurrentFile
);
1035 CServiceBroker::GetGUI()->GetWindowManager().SendMessage(msg
);
1040 else if ((action
.GetID() == ACTION_INCREASE_RATING
|| action
.GetID() == ACTION_DECREASE_RATING
) &&
1041 appPlayer
->IsPlayingAudio())
1043 int userrating
= m_itemCurrentFile
->GetMusicInfoTag()->GetUserrating();
1044 bool needsUpdate(false);
1045 if (userrating
> 0 && action
.GetID() == ACTION_DECREASE_RATING
)
1047 m_itemCurrentFile
->GetMusicInfoTag()->SetUserrating(userrating
- 1);
1050 else if (userrating
< 10 && action
.GetID() == ACTION_INCREASE_RATING
)
1052 m_itemCurrentFile
->GetMusicInfoTag()->SetUserrating(userrating
+ 1);
1057 // Mirror changes to current GUI item
1058 CServiceBroker::GetGUI()->GetInfoManager().SetCurrentItem(*m_itemCurrentFile
);
1060 // Asynchronously update song userrating in music library
1061 MUSIC_UTILS::UpdateSongRatingJob(m_itemCurrentFile
, m_itemCurrentFile
->GetMusicInfoTag()->GetUserrating());
1063 // send a message to all windows to tell them to update the fileitem (eg playlistplayer, media windows)
1064 CGUIMessage
msg(GUI_MSG_NOTIFY_ALL
, 0, 0, GUI_MSG_UPDATE_ITEM
, 0, m_itemCurrentFile
);
1065 CServiceBroker::GetGUI()->GetWindowManager().SendMessage(msg
);
1070 else if ((action
.GetID() == ACTION_INCREASE_RATING
|| action
.GetID() == ACTION_DECREASE_RATING
) &&
1071 appPlayer
->IsPlayingVideo())
1073 int rating
= m_itemCurrentFile
->GetVideoInfoTag()->m_iUserRating
;
1074 bool needsUpdate(false);
1075 if (rating
> 1 && action
.GetID() == ACTION_DECREASE_RATING
)
1077 m_itemCurrentFile
->GetVideoInfoTag()->m_iUserRating
= rating
- 1;
1080 else if (rating
< 10 && action
.GetID() == ACTION_INCREASE_RATING
)
1082 m_itemCurrentFile
->GetVideoInfoTag()->m_iUserRating
= rating
+ 1;
1087 // Mirror changes to GUI item
1088 CServiceBroker::GetGUI()->GetInfoManager().SetCurrentItem(*m_itemCurrentFile
);
1093 db
.SetVideoUserRating(m_itemCurrentFile
->GetVideoInfoTag()->m_iDbId
,
1094 m_itemCurrentFile
->GetVideoInfoTag()->m_iUserRating
,
1095 m_itemCurrentFile
->GetVideoInfoTag()->m_type
);
1098 // send a message to all windows to tell them to update the fileitem (eg playlistplayer, media windows)
1099 CGUIMessage
msg(GUI_MSG_NOTIFY_ALL
, 0, 0, GUI_MSG_UPDATE_ITEM
, 0, m_itemCurrentFile
);
1100 CServiceBroker::GetGUI()->GetWindowManager().SendMessage(msg
);
1105 // Now check with the playlist player if action can be handled.
1106 // 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.
1107 if (!(action
.GetID() == ACTION_PREV_ITEM
&& appPlayer
->CanSeek() &&
1108 GetTime() > ACTION_PREV_ITEM_THRESHOLD
))
1110 if (CServiceBroker::GetPlaylistPlayer().OnAction(action
))
1114 // Now check with the player if action can be handled.
1115 bool bIsPlayingPVRChannel
= (CServiceBroker::GetPVRManager().IsStarted() &&
1116 CurrentFileItem().IsPVRChannel());
1118 bool bNotifyPlayer
= false;
1119 if (CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow() == WINDOW_FULLSCREEN_VIDEO
)
1120 bNotifyPlayer
= true;
1121 else if (CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow() == WINDOW_FULLSCREEN_GAME
)
1122 bNotifyPlayer
= true;
1123 else if (CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow() == WINDOW_VISUALISATION
&& bIsPlayingPVRChannel
)
1124 bNotifyPlayer
= true;
1125 else if (CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow() == WINDOW_DIALOG_VIDEO_OSD
||
1126 (CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow() == WINDOW_DIALOG_MUSIC_OSD
&& bIsPlayingPVRChannel
))
1128 switch (action
.GetID())
1130 case ACTION_NEXT_ITEM
:
1131 case ACTION_PREV_ITEM
:
1132 case ACTION_CHANNEL_UP
:
1133 case ACTION_CHANNEL_DOWN
:
1134 bNotifyPlayer
= true;
1140 else if (action
.GetID() == ACTION_STOP
)
1141 bNotifyPlayer
= true;
1145 if (appPlayer
->OnAction(action
))
1149 // stop : stops playing current audio song
1150 if (action
.GetID() == ACTION_STOP
)
1156 // In case the playlist player nor the player didn't handle PREV_ITEM, because we are past the ACTION_PREV_ITEM_THRESHOLD secs limit.
1157 // If so, we just jump to the start of the track.
1158 if (action
.GetID() == ACTION_PREV_ITEM
&& appPlayer
->CanSeek())
1161 appPlayer
->SetPlaySpeed(1);
1165 // forward action to graphic context and see if it can handle it
1166 if (CServiceBroker::GetGUI()->GetStereoscopicsManager().OnAction(action
))
1169 if (appPlayer
->IsPlaying())
1171 // forward channel switches to the player - he knows what to do
1172 if (action
.GetID() == ACTION_CHANNEL_UP
|| action
.GetID() == ACTION_CHANNEL_DOWN
)
1174 appPlayer
->OnAction(action
);
1178 // pause : toggle pause action
1179 if (action
.GetID() == ACTION_PAUSE
)
1182 // go back to normal play speed on unpause
1183 if (!appPlayer
->IsPaused() && appPlayer
->GetPlaySpeed() != 1)
1184 appPlayer
->SetPlaySpeed(1);
1186 CGUIComponent
*gui
= CServiceBroker::GetGUI();
1188 gui
->GetAudioManager().Enable(appPlayer
->IsPaused());
1191 // play: unpause or set playspeed back to normal
1192 if (action
.GetID() == ACTION_PLAYER_PLAY
)
1194 // if currently paused - unpause
1195 if (appPlayer
->IsPaused())
1196 return OnAction(CAction(ACTION_PAUSE
));
1197 // if we do a FF/RW then go back to normal speed
1198 if (appPlayer
->GetPlaySpeed() != 1)
1199 appPlayer
->SetPlaySpeed(1);
1202 if (!appPlayer
->IsPaused())
1204 if (action
.GetID() == ACTION_PLAYER_FORWARD
|| action
.GetID() == ACTION_PLAYER_REWIND
)
1206 float playSpeed
= appPlayer
->GetPlaySpeed();
1208 if (action
.GetID() == ACTION_PLAYER_REWIND
&& (playSpeed
== 1)) // Enables Rewinding
1210 else if (action
.GetID() == ACTION_PLAYER_REWIND
&& playSpeed
> 1) //goes down a notch if you're FFing
1212 else if (action
.GetID() == ACTION_PLAYER_FORWARD
&& playSpeed
< 1) //goes up a notch if you're RWing
1217 if (action
.GetID() == ACTION_PLAYER_FORWARD
&& playSpeed
== -1) //sets iSpeed back to 1 if -1 (didn't plan for a -1)
1219 if (playSpeed
> 32 || playSpeed
< -32)
1222 appPlayer
->SetPlaySpeed(playSpeed
);
1225 else if ((action
.GetAmount() || appPlayer
->GetPlaySpeed() != 1) &&
1226 (action
.GetID() == ACTION_ANALOG_REWIND
|| action
.GetID() == ACTION_ANALOG_FORWARD
))
1228 // calculate the speed based on the amount the button is held down
1229 int iPower
= (int)(action
.GetAmount() * MAX_FFWD_SPEED
+ 0.5f
);
1230 // amount can be negative, for example rewind and forward share the same axis
1231 iPower
= std::abs(iPower
);
1232 // returns 0 -> MAX_FFWD_SPEED
1233 int iSpeed
= 1 << iPower
;
1234 if (iSpeed
!= 1 && action
.GetID() == ACTION_ANALOG_REWIND
)
1236 appPlayer
->SetPlaySpeed(static_cast<float>(iSpeed
));
1238 CLog::Log(LOGDEBUG
,"Resetting playspeed");
1241 else if (action
.GetID() == ACTION_PLAYER_INCREASE_TEMPO
)
1243 CPlayerUtils::AdvanceTempoStep(appPlayer
, TempoStepChange::INCREASE
);
1246 else if (action
.GetID() == ACTION_PLAYER_DECREASE_TEMPO
)
1248 CPlayerUtils::AdvanceTempoStep(appPlayer
, TempoStepChange::DECREASE
);
1252 // allow play to unpause
1255 if (action
.GetID() == ACTION_PLAYER_PLAY
)
1257 // unpause, and set the playspeed back to normal
1260 CGUIComponent
*gui
= CServiceBroker::GetGUI();
1262 gui
->GetAudioManager().Enable(appPlayer
->IsPaused());
1264 appPlayer
->SetPlaySpeed(1);
1271 if (action
.GetID() == ACTION_SWITCH_PLAYER
)
1273 const CPlayerCoreFactory
&playerCoreFactory
= m_ServiceManager
->GetPlayerCoreFactory();
1275 if (appPlayer
->IsPlaying())
1277 std::vector
<std::string
> players
;
1278 CFileItem
item(*m_itemCurrentFile
.get());
1279 playerCoreFactory
.GetPlayers(item
, players
);
1280 std::string player
= playerCoreFactory
.SelectPlayerDialog(players
);
1281 if (!player
.empty())
1283 item
.SetStartOffset(CUtil::ConvertSecsToMilliSecs(GetTime()));
1284 PlayFile(item
, player
, true);
1289 std::vector
<std::string
> players
;
1290 playerCoreFactory
.GetRemotePlayers(players
);
1291 std::string player
= playerCoreFactory
.SelectPlayerDialog(players
);
1292 if (!player
.empty())
1294 PlayFile(CFileItem(), player
, false);
1299 if (CServiceBroker::GetPeripherals().OnAction(action
))
1302 if (action
.GetID() == ACTION_MUTE
)
1304 const auto appVolume
= GetComponent
<CApplicationVolumeHandling
>();
1305 appVolume
->ToggleMute();
1306 appVolume
->ShowVolumeBar(&action
);
1310 if (action
.GetID() == ACTION_TOGGLE_DIGITAL_ANALOG
)
1312 const std::shared_ptr
<CSettings
> settings
= CServiceBroker::GetSettingsComponent()->GetSettings();
1313 bool passthrough
= settings
->GetBool(CSettings::SETTING_AUDIOOUTPUT_PASSTHROUGH
);
1314 settings
->SetBool(CSettings::SETTING_AUDIOOUTPUT_PASSTHROUGH
, !passthrough
);
1316 if (CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow() == WINDOW_SETTINGS_SYSTEM
)
1318 CGUIMessage
msg(GUI_MSG_WINDOW_INIT
, 0,0,WINDOW_INVALID
,CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow());
1319 CServiceBroker::GetGUI()->GetWindowManager().SendMessage(msg
);
1324 // Check for global volume control
1325 if ((action
.GetAmount() && (action
.GetID() == ACTION_VOLUME_UP
|| action
.GetID() == ACTION_VOLUME_DOWN
)) || action
.GetID() == ACTION_VOLUME_SET
)
1327 const auto appVolume
= GetComponent
<CApplicationVolumeHandling
>();
1328 if (!appPlayer
->IsPassthrough())
1330 if (appVolume
->IsMuted())
1331 appVolume
->UnMute();
1332 float volume
= appVolume
->GetVolumeRatio();
1333 int volumesteps
= CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_AUDIOOUTPUT_VOLUMESTEPS
);
1335 if (volumesteps
== 0)
1338 // Android has steps based on the max available volume level
1339 #if defined(TARGET_ANDROID)
1340 float step
= (CApplicationVolumeHandling::VOLUME_MAXIMUM
-
1341 CApplicationVolumeHandling::VOLUME_MINIMUM
) /
1342 CXBMCApp::GetMaxSystemVolume();
1344 float step
= (CApplicationVolumeHandling::VOLUME_MAXIMUM
-
1345 CApplicationVolumeHandling::VOLUME_MINIMUM
) /
1348 if (action
.GetRepeat())
1349 step
*= action
.GetRepeat() * 50; // 50 fps
1351 if (action
.GetID() == ACTION_VOLUME_UP
)
1352 volume
+= action
.GetAmount() * action
.GetAmount() * step
;
1353 else if (action
.GetID() == ACTION_VOLUME_DOWN
)
1354 volume
-= action
.GetAmount() * action
.GetAmount() * step
;
1356 volume
= action
.GetAmount() * step
;
1357 if (volume
!= appVolume
->GetVolumeRatio())
1358 appVolume
->SetVolume(volume
, false);
1360 // show visual feedback of volume or passthrough indicator
1361 appVolume
->ShowVolumeBar(&action
);
1365 if (action
.GetID() == ACTION_GUIPROFILE_BEGIN
)
1367 CGUIControlProfiler::Instance().SetOutputFile(CSpecialProtocol::TranslatePath("special://home/guiprofiler.xml"));
1368 CGUIControlProfiler::Instance().Start();
1371 if (action
.GetID() == ACTION_SHOW_PLAYLIST
)
1373 const PLAYLIST::Id playlistId
= CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist();
1374 if (playlistId
== PLAYLIST::Id::TYPE_VIDEO
&&
1375 CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow() != WINDOW_VIDEO_PLAYLIST
)
1377 CServiceBroker::GetGUI()->GetWindowManager().ActivateWindow(WINDOW_VIDEO_PLAYLIST
);
1379 else if (playlistId
== PLAYLIST::Id::TYPE_MUSIC
&&
1380 CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow() !=
1381 WINDOW_MUSIC_PLAYLIST
)
1383 CServiceBroker::GetGUI()->GetWindowManager().ActivateWindow(WINDOW_MUSIC_PLAYLIST
);
1390 int CApplication::GetMessageMask()
1392 return TMSG_MASK_APPLICATION
;
1395 void CApplication::OnApplicationMessage(ThreadMessage
* pMsg
)
1397 uint32_t msg
= pMsg
->dwMessage
;
1398 if (msg
== TMSG_SYSTEM_POWERDOWN
)
1400 if (CServiceBroker::GetPVRManager().Get
<PVR::GUI::PowerManagement
>().CanSystemPowerdown())
1401 msg
= pMsg
->param1
; // perform requested shutdown action
1403 return; // no shutdown
1406 const auto appPlayer
= GetComponent
<CApplicationPlayer
>();
1410 case TMSG_POWERDOWN
:
1411 if (Stop(EXITCODE_POWERDOWN
))
1412 CServiceBroker::GetPowerManager().Powerdown();
1416 Stop(EXITCODE_QUIT
);
1420 GetComponent
<CApplicationPowerHandling
>()->HandleShutdownMessage();
1423 case TMSG_RENDERER_FLUSH
:
1424 appPlayer
->FlushRenderer();
1427 case TMSG_HIBERNATE
:
1428 CServiceBroker::GetPowerManager().Hibernate();
1432 CServiceBroker::GetPowerManager().Suspend();
1437 if (Stop(EXITCODE_REBOOT
))
1438 CServiceBroker::GetPowerManager().Reboot();
1441 case TMSG_RESTARTAPP
:
1442 #if defined(TARGET_WINDOWS) || defined(TARGET_LINUX)
1443 Stop(EXITCODE_RESTARTAPP
);
1447 case TMSG_INHIBITIDLESHUTDOWN
:
1448 GetComponent
<CApplicationPowerHandling
>()->InhibitIdleShutdown(pMsg
->param1
!= 0);
1451 case TMSG_INHIBITSCREENSAVER
:
1452 GetComponent
<CApplicationPowerHandling
>()->InhibitScreenSaver(pMsg
->param1
!= 0);
1455 case TMSG_ACTIVATESCREENSAVER
:
1456 GetComponent
<CApplicationPowerHandling
>()->ActivateScreenSaver();
1459 case TMSG_RESETSCREENSAVER
:
1460 GetComponent
<CApplicationPowerHandling
>()->m_bResetScreenSaver
= true;
1463 case TMSG_VOLUME_SHOW
:
1465 CAction
action(pMsg
->param1
);
1466 GetComponent
<CApplicationVolumeHandling
>()->ShowVolumeBar(&action
);
1470 #ifdef TARGET_ANDROID
1471 case TMSG_DISPLAY_SETUP
:
1472 // We might come from a refresh rate switch destroying the native window; use the context resolution
1473 *static_cast<bool*>(pMsg
->lpVoid
) = InitWindow(CServiceBroker::GetWinSystem()->GetGfxContext().GetVideoResolution());
1474 GetComponent
<CApplicationPowerHandling
>()->SetRenderGUI(true);
1477 case TMSG_DISPLAY_DESTROY
:
1478 *static_cast<bool*>(pMsg
->lpVoid
) = CServiceBroker::GetWinSystem()->DestroyWindow();
1479 GetComponent
<CApplicationPowerHandling
>()->SetRenderGUI(false);
1483 case TMSG_START_ANDROID_ACTIVITY
:
1485 #if defined(TARGET_ANDROID)
1486 if (pMsg
->params
.size())
1488 CXBMCApp::StartActivity(pMsg
->params
[0], pMsg
->params
.size() > 1 ? pMsg
->params
[1] : "",
1489 pMsg
->params
.size() > 2 ? pMsg
->params
[2] : "",
1490 pMsg
->params
.size() > 3 ? pMsg
->params
[3] : "",
1491 pMsg
->params
.size() > 4 ? pMsg
->params
[4] : "",
1492 pMsg
->params
.size() > 5 ? pMsg
->params
[5] : "",
1493 pMsg
->params
.size() > 6 ? pMsg
->params
[6] : "",
1494 pMsg
->params
.size() > 7 ? pMsg
->params
[7] : "",
1495 pMsg
->params
.size() > 8 ? pMsg
->params
[8] : "");
1501 case TMSG_NETWORKMESSAGE
:
1502 m_ServiceManager
->GetNetwork().NetworkMessage(static_cast<CNetworkBase::EMESSAGE
>(pMsg
->param1
),
1506 case TMSG_SETLANGUAGE
:
1507 SetLanguage(pMsg
->strParam
);
1511 case TMSG_SWITCHTOFULLSCREEN
:
1513 CGUIComponent
* gui
= CServiceBroker::GetGUI();
1515 gui
->GetWindowManager().SwitchToFullScreen(true);
1518 case TMSG_VIDEORESIZE
:
1520 XBMC_Event newEvent
= {};
1521 newEvent
.type
= XBMC_VIDEORESIZE
;
1522 newEvent
.resize
.w
= pMsg
->param1
;
1523 newEvent
.resize
.h
= pMsg
->param2
;
1524 m_pAppPort
->OnEvent(newEvent
);
1525 CServiceBroker::GetGUI()->GetWindowManager().MarkDirty();
1529 case TMSG_SETVIDEORESOLUTION
:
1530 CServiceBroker::GetWinSystem()->GetGfxContext().SetVideoResolution(static_cast<RESOLUTION
>(pMsg
->param1
), pMsg
->param2
== 1);
1533 case TMSG_TOGGLEFULLSCREEN
:
1534 CServiceBroker::GetWinSystem()->GetGfxContext().ToggleFullScreen();
1535 appPlayer
->TriggerUpdateResolution();
1538 case TMSG_MOVETOSCREEN
:
1539 CServiceBroker::GetWinSystem()->MoveToScreen(static_cast<int>(pMsg
->param1
));
1543 CServiceBroker::GetWinSystem()->Minimize();
1546 case TMSG_EXECUTE_OS
:
1547 // Suspend AE temporarily so exclusive or hog-mode sinks
1548 // don't block external player's access to audio device
1550 audioengine
= CServiceBroker::GetActiveAE();
1553 if (!audioengine
->Suspend())
1555 CLog::Log(LOGINFO
, "{}: Failed to suspend AudioEngine before launching external program",
1559 #if defined(TARGET_DARWIN)
1560 CLog::Log(LOGINFO
, "ExecWait is not implemented on this platform");
1561 #elif defined(TARGET_POSIX)
1562 CUtil::RunCommandLine(pMsg
->strParam
, (pMsg
->param1
== 1));
1563 #elif defined(TARGET_WINDOWS)
1564 CWIN32Util::XBMCShellExecute(pMsg
->strParam
.c_str(), (pMsg
->param1
== 1));
1566 // Resume AE processing of XBMC native audio
1569 if (!audioengine
->Resume())
1571 CLog::Log(LOGFATAL
, "{}: Failed to restart AudioEngine after return from external player",
1577 case TMSG_EXECUTE_SCRIPT
:
1578 CScriptInvocationManager::GetInstance().ExecuteAsync(pMsg
->strParam
);
1581 case TMSG_EXECUTE_BUILT_IN
:
1582 CBuiltins::GetInstance().Execute(pMsg
->strParam
);
1585 case TMSG_PICTURE_SHOW
:
1587 CSlideShowDelegator
& slideShow
= CServiceBroker::GetSlideShowDelegator();
1589 // stop playing file
1590 if (appPlayer
->IsPlayingVideo())
1593 if (CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow() == WINDOW_FULLSCREEN_VIDEO
)
1594 CServiceBroker::GetGUI()->GetWindowManager().PreviousWindow();
1596 const auto appPower
= GetComponent
<CApplicationPowerHandling
>();
1597 appPower
->ResetScreenSaver();
1598 appPower
->WakeUpScreenSaverAndDPMS();
1600 if (CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow() != WINDOW_SLIDESHOW
)
1601 CServiceBroker::GetGUI()->GetWindowManager().ActivateWindow(WINDOW_SLIDESHOW
);
1602 if (URIUtils::IsZIP(pMsg
->strParam
) || URIUtils::IsRAR(pMsg
->strParam
)) // actually a cbz/cbr
1604 CFileItemList items
;
1606 if (URIUtils::IsZIP(pMsg
->strParam
))
1607 pathToUrl
= URIUtils::CreateArchivePath("zip", CURL(pMsg
->strParam
), "");
1609 pathToUrl
= URIUtils::CreateArchivePath("rar", CURL(pMsg
->strParam
), "");
1611 CUtil::GetRecursiveListing(pathToUrl
.Get(), items
, CServiceBroker::GetFileExtensionProvider().GetPictureExtensions(), XFILE::DIR_FLAG_NO_FILE_DIRS
);
1612 if (items
.Size() > 0)
1615 for (int i
= 0; i
<items
.Size(); ++i
)
1617 slideShow
.Add(items
[i
].get());
1619 slideShow
.Select(items
[0]->GetPath());
1624 CFileItem
item(pMsg
->strParam
, false);
1626 slideShow
.Add(&item
);
1627 slideShow
.Select(pMsg
->strParam
);
1632 case TMSG_PICTURE_SLIDESHOW
:
1634 CSlideShowDelegator
& slideShow
= CServiceBroker::GetSlideShowDelegator();
1636 if (appPlayer
->IsPlayingVideo())
1641 CFileItemList items
;
1642 std::string strPath
= pMsg
->strParam
;
1643 std::string extensions
= CServiceBroker::GetFileExtensionProvider().GetPictureExtensions();
1645 extensions
+= "|.tbn";
1646 CUtil::GetRecursiveListing(strPath
, items
, extensions
);
1648 if (items
.Size() > 0)
1650 for (int i
= 0; i
<items
.Size(); ++i
)
1651 slideShow
.Add(items
[i
].get());
1652 slideShow
.StartSlideShow(); //Start the slideshow!
1655 if (CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow() != WINDOW_SLIDESHOW
)
1657 if (items
.Size() == 0)
1659 CServiceBroker::GetSettingsComponent()->GetSettings()->SetString(CSettings::SETTING_SCREENSAVER_MODE
, "screensaver.xbmc.builtin.dim");
1660 GetComponent
<CApplicationPowerHandling
>()->ActivateScreenSaver();
1663 CServiceBroker::GetGUI()->GetWindowManager().ActivateWindow(WINDOW_SLIDESHOW
);
1669 case TMSG_LOADPROFILE
:
1671 const int profile
= pMsg
->param1
;
1673 CServiceBroker::GetSettingsComponent()->GetProfileManager()->LoadProfile(static_cast<unsigned int>(profile
));
1682 XBMC_Event
* event
= static_cast<XBMC_Event
*>(pMsg
->lpVoid
);
1683 m_pAppPort
->OnEvent(*event
);
1689 case TMSG_UPDATE_PLAYER_ITEM
:
1691 std::unique_ptr
<CFileItem
> item
{static_cast<CFileItem
*>(pMsg
->lpVoid
)};
1694 m_itemCurrentFile
->UpdateInfo(*item
);
1695 CServiceBroker::GetGUI()->GetInfoManager().UpdateCurrentItem(*m_itemCurrentFile
);
1700 case TMSG_SET_VOLUME
:
1702 const float volumedB
= static_cast<float>(pMsg
->param3
);
1703 GetComponent
<CApplicationVolumeHandling
>()->SetVolume(volumedB
);
1709 GetComponent
<CApplicationVolumeHandling
>()->SetMute(pMsg
->param3
== 1 ? true : false);
1714 CLog::Log(LOGERROR
, "{}: Unhandled threadmessage sent, {}", __FUNCTION__
, msg
);
1719 void CApplication::LockFrameMoveGuard()
1721 ++m_WaitingExternalCalls
;
1722 m_frameMoveGuard
.lock();
1723 ++m_ProcessedExternalCalls
;
1724 CServiceBroker::GetWinSystem()->GetGfxContext().lock();
1727 void CApplication::UnlockFrameMoveGuard()
1729 --m_WaitingExternalCalls
;
1730 CServiceBroker::GetWinSystem()->GetGfxContext().unlock();
1731 m_frameMoveGuard
.unlock();
1734 void CApplication::FrameMove(bool processEvents
, bool processGUI
)
1736 const auto appPlayer
= GetComponent
<CApplicationPlayer
>();
1737 bool renderGUI
= GetComponent
<CApplicationPowerHandling
>()->GetRenderGUI();
1740 // currently we calculate the repeat time (ie time from last similar keypress) just global as fps
1741 float frameTime
= m_frameTime
.GetElapsedSeconds();
1742 m_frameTime
.StartZero();
1743 // never set a frametime less than 2 fps to avoid problems when debugging and on breaks
1744 if (frameTime
> 0.5f
)
1747 if (processGUI
&& renderGUI
)
1749 std::unique_lock
<CCriticalSection
> lock(CServiceBroker::GetWinSystem()->GetGfxContext());
1750 // check if there are notifications to display
1751 CGUIDialogKaiToast
*toast
= CServiceBroker::GetGUI()->GetWindowManager().GetWindow
<CGUIDialogKaiToast
>(WINDOW_DIALOG_KAI_TOAST
);
1752 if (toast
&& toast
->DoWork())
1754 if (!toast
->IsDialogRunning())
1761 m_pAppPort
->HandleEvents();
1762 CServiceBroker::GetInputManager().Process(CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindowOrDialog(), frameTime
);
1764 if (processGUI
&& renderGUI
)
1766 m_pInertialScrollingHandler
->ProcessInertialScroll(frameTime
);
1767 appPlayer
->GetSeekHandler().FrameMove();
1770 // Open the door for external calls e.g python exactly here.
1771 // Window size can be between 2 and 10ms and depends on number of continuous requests
1772 if (m_WaitingExternalCalls
)
1774 CSingleExit
ex(CServiceBroker::GetWinSystem()->GetGfxContext());
1775 m_frameMoveGuard
.unlock();
1777 // Calculate a window size between 2 and 10ms, 4 continuous requests let the window grow by 1ms
1778 // When not playing video we allow it to increase to 80ms
1779 unsigned int max_sleep
= 10;
1780 if (!appPlayer
->IsPlayingVideo() || appPlayer
->IsPausedPlayback())
1782 unsigned int sleepTime
= std::max(static_cast<unsigned int>(2), std::min(m_ProcessedExternalCalls
>> 2, max_sleep
));
1783 KODI::TIME::Sleep(std::chrono::milliseconds(sleepTime
));
1784 m_frameMoveGuard
.lock();
1785 m_ProcessedExternalDecay
= 5;
1787 if (m_ProcessedExternalDecay
&& --m_ProcessedExternalDecay
== 0)
1788 m_ProcessedExternalCalls
= 0;
1791 if (processGUI
&& renderGUI
)
1793 m_skipGuiRender
= false;
1795 /*! @todo look into the possibility to use this for GBM
1798 // This code reduces rendering fps of the GUI layer when playing videos in fullscreen mode
1799 // it makes only sense on architectures with multiple layers
1800 if (CServiceBroker::GetWinSystem()->GetGfxContext().IsFullScreenVideo() && !m_appPlayer.IsPausedPlayback() && m_appPlayer.IsRenderingVideoLayer())
1801 fps = CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_VIDEOPLAYER_LIMITGUIUPDATE);
1803 auto now = std::chrono::steady_clock::now();
1805 auto frameTime = std::chrono::duration_cast<std::chrono::milliseconds>(now - m_lastRenderTime).count();
1806 if (fps > 0 && frameTime * fps < 1000)
1807 m_skipGuiRender = true;
1810 if (CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_guiSmartRedraw
&& m_guiRefreshTimer
.IsTimePast())
1812 CServiceBroker::GetGUI()->GetWindowManager().SendMessage(GUI_MSG_REFRESH_TIMER
, 0, 0);
1813 m_guiRefreshTimer
.Set(500ms
);
1818 if (!m_skipGuiRender
)
1819 CServiceBroker::GetGUI()->GetWindowManager().Process(CTimeUtils::GetFrameTime());
1821 CServiceBroker::GetGUI()->GetWindowManager().FrameMove();
1824 appPlayer
->FrameMove();
1826 // this will go away when render systems gets its own thread
1827 CServiceBroker::GetWinSystem()->DriveRenderLoop();
1831 void CApplication::ResetCurrentItem()
1833 m_itemCurrentFile
->Reset();
1835 m_pGUI
->GetInfoManager().ResetCurrentItem();
1838 int CApplication::Run()
1840 CLog::Log(LOGINFO
, "Running the application...");
1842 std::chrono::time_point
<std::chrono::steady_clock
> lastFrameTime
;
1843 std::chrono::milliseconds frameTime
;
1844 const unsigned int noRenderFrameTime
= 15; // Simulates ~66fps
1846 CFileItemList
& playlist
= CServiceBroker::GetAppParams()->GetPlaylist();
1847 if (playlist
.Size() > 0)
1849 CServiceBroker::GetPlaylistPlayer().Add(PLAYLIST::Id::TYPE_MUSIC
, playlist
);
1850 CServiceBroker::GetPlaylistPlayer().SetCurrentPlaylist(PLAYLIST::Id::TYPE_MUSIC
);
1851 CServiceBroker::GetAppMessenger()->PostMsg(TMSG_PLAYLISTPLAYER_PLAY
, -1);
1857 // Animate and render a frame
1859 lastFrameTime
= std::chrono::steady_clock::now();
1862 bool renderGUI
= GetComponent
<CApplicationPowerHandling
>()->GetRenderGUI();
1865 FrameMove(true, renderGUI
);
1868 if (renderGUI
&& !m_bStop
)
1872 else if (!renderGUI
)
1874 auto now
= std::chrono::steady_clock::now();
1875 frameTime
= std::chrono::duration_cast
<std::chrono::milliseconds
>(now
- lastFrameTime
);
1876 if (frameTime
.count() < noRenderFrameTime
)
1877 KODI::TIME::Sleep(std::chrono::milliseconds(noRenderFrameTime
- frameTime
.count()));
1883 CLog::Log(LOGINFO
, "Exiting the application...");
1887 bool CApplication::Cleanup()
1894 if (m_ServiceManager
)
1895 m_ServiceManager
->DeinitStageThree();
1897 CServiceBroker::UnregisterSpeechRecognition();
1899 CLog::Log(LOGINFO
, "unload skin");
1900 GetComponent
<CApplicationSkinHandling
>()->UnloadSkin();
1902 CServiceBroker::UnregisterTextureCache();
1904 // stop all remaining scripts; must be done after skin has been unloaded,
1905 // not before some windows still need it when deinitializing during skin
1907 CScriptInvocationManager::GetInstance().Uninitialize();
1909 const auto appPower
= GetComponent
<CApplicationPowerHandling
>();
1910 appPower
->m_globalScreensaverInhibitor
.Release();
1911 appPower
->m_screensaverInhibitor
.Release();
1913 CRenderSystemBase
*renderSystem
= CServiceBroker::GetRenderSystem();
1915 renderSystem
->DestroyRenderSystem();
1917 CWinSystemBase
*winSystem
= CServiceBroker::GetWinSystem();
1919 winSystem
->DestroyWindow();
1922 m_pGUI
->GetWindowManager().DestroyWindows();
1924 CLog::Log(LOGINFO
, "unload sections");
1926 // Shutdown as much as possible of the
1927 // application, to reduce the leaks dumped
1928 // to the vc output window before calling
1929 // _CrtDumpMemoryLeaks(). Most of the leaks
1930 // shown are no real leaks, as parts of the app
1931 // are still allocated.
1933 g_localizeStrings
.Clear();
1934 g_LangCodeExpander
.Clear();
1935 g_charsetConverter
.clear();
1936 g_directoryCache
.Clear();
1937 //CServiceBroker::GetInputManager().ClearKeymaps(); //! @todo
1938 CEventServer::RemoveInstance();
1939 CServiceBroker::GetPlaylistPlayer().Clear();
1941 if (m_ServiceManager
)
1942 m_ServiceManager
->DeinitStageTwo();
1945 CXHandle::DumpObjectTracker();
1947 #ifdef HAS_OPTICAL_DRIVE
1948 CLibcdio::ReleaseInstance();
1951 #ifdef _CRTDBG_MAP_ALLOC
1952 _CrtDumpMemoryLeaks();
1953 while(1); // execution ends
1964 winSystem
->DestroyWindowSystem();
1965 CServiceBroker::UnregisterWinSystem();
1966 winSystem
= nullptr;
1967 m_pWinSystem
.reset();
1970 // Cleanup was called more than once on exit during my tests
1971 if (m_ServiceManager
)
1973 m_ServiceManager
->DeinitStageOne();
1974 m_ServiceManager
.reset();
1977 CServiceBroker::UnregisterKeyboardLayoutManager();
1979 CServiceBroker::UnregisterAppMessenger();
1981 CServiceBroker::UnregisterAnnouncementManager();
1982 m_pAnnouncementManager
->Deinitialize();
1983 m_pAnnouncementManager
.reset();
1985 CServiceBroker::UnregisterJobManager();
1986 CServiceBroker::UnregisterCPUInfo();
1988 UnregisterSettings();
1990 m_bInitializing
= true;
1996 CLog::Log(LOGERROR
, "Exception in CApplication::Cleanup()");
2001 bool CApplication::Stop(int exitCode
)
2003 #if defined(TARGET_ANDROID)
2004 // Note: On Android, the app must be stopped asynchronously, once Android has
2005 // signalled that the app shall be destroyed. See android_main() implementation.
2006 if (!CXBMCApp::Get().Stop(exitCode
))
2010 CLog::Log(LOGINFO
, "Stopping the application...");
2012 bool success
= true;
2014 CLog::Log(LOGINFO
, "Stopping player");
2015 const auto appPlayer
= GetComponent
<CApplicationPlayer
>();
2016 appPlayer
->ClosePlayer();
2019 // close inbound port
2020 CServiceBroker::UnregisterAppPort();
2021 XbmcThreads::EndTime
<> timer(1000ms
);
2022 while (m_pAppPort
.use_count() > 1)
2024 KODI::TIME::Sleep(100ms
);
2025 if (timer
.IsTimePast())
2027 CLog::Log(LOGERROR
, "CApplication::Stop - CAppPort still in use, app may crash");
2031 m_pAppPort
->Close();
2036 m_frameMoveGuard
.unlock();
2038 CVariant
vExitCode(CVariant::VariantTypeObject
);
2039 vExitCode
["exitcode"] = exitCode
;
2040 CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::System
, "OnQuit", vExitCode
);
2042 // Abort any active screensaver
2043 GetComponent
<CApplicationPowerHandling
>()->WakeUpScreenSaverAndDPMS();
2045 g_alarmClock
.StopThread();
2047 CLog::Log(LOGINFO
, "Storing total System Uptime");
2048 g_sysinfo
.SetTotalUptime(g_sysinfo
.GetTotalUptime() + (int)(CTimeUtils::GetFrameTime() / 60000));
2050 // Update the settings information (volume, uptime etc. need saving)
2051 if (CFile::Exists(CServiceBroker::GetSettingsComponent()->GetProfileManager()->GetSettingsFile()))
2053 CLog::Log(LOGINFO
, "Saving settings");
2054 CServiceBroker::GetSettingsComponent()->GetSettings()->Save();
2057 CLog::Log(LOGINFO
, "Not saving settings (settings.xml is not present)");
2059 // kodi may crash or deadlock during exit (shutdown / reboot) due to
2060 // either a bug in core or misbehaving addons. so try saving
2061 // skin settings early
2062 CLog::Log(LOGINFO
, "Saving skin settings");
2063 if (g_SkinInfo
!= nullptr)
2064 g_SkinInfo
->SaveSettings();
2067 // Add this here to keep the same ordering behaviour for now
2068 // Needs cleaning up
2069 CServiceBroker::GetAppMessenger()->Stop();
2070 m_AppFocused
= false;
2071 m_ExitCode
= exitCode
;
2072 CLog::Log(LOGINFO
, "Stopping all");
2074 // cancel any jobs from the jobmanager
2075 CServiceBroker::GetJobManager()->CancelJobs();
2077 // stop scanning before we kill the network and so on
2078 if (CMusicLibraryQueue::GetInstance().IsRunning())
2079 CMusicLibraryQueue::GetInstance().CancelAllJobs();
2081 if (CVideoLibraryQueue::GetInstance().IsRunning())
2082 CVideoLibraryQueue::GetInstance().CancelAllJobs();
2084 CServiceBroker::GetAppMessenger()->Cleanup();
2086 m_ServiceManager
->GetNetwork().NetworkMessage(CNetworkBase::SERVICES_DOWN
, 0);
2089 if(CZeroconfBrowser::IsInstantiated())
2091 CLog::Log(LOGINFO
, "Stopping zeroconf browser");
2092 CZeroconfBrowser::GetInstance()->Stop();
2093 CZeroconfBrowser::ReleaseInstance();
2097 for (const auto& vfsAddon
: CServiceBroker::GetVFSAddonCache().GetAddonInstances())
2098 vfsAddon
->DisconnectAll();
2100 #if defined(TARGET_POSIX) && defined(HAS_FILESYSTEM_SMB)
2104 #if defined(TARGET_DARWIN_OSX) and defined(HAS_XBMCHELPER)
2105 if (XBMCHelper::GetInstance().IsAlwaysOn() == false)
2106 XBMCHelper::GetInstance().Stop();
2109 // Stop services before unloading Python
2110 CServiceBroker::GetServiceAddons().Stop();
2112 // Stop any other python scripts that may be looping waiting for monitor.abortRequested()
2113 CScriptInvocationManager::GetInstance().StopRunningScripts();
2115 // unregister action listeners
2116 const auto appListener
= GetComponent
<CApplicationActionListeners
>();
2117 appListener
->UnregisterActionListener(&GetComponent
<CApplicationPlayer
>()->GetSeekHandler());
2118 appListener
->UnregisterActionListener(&CPlayerController::GetInstance());
2120 CGUIComponent
*gui
= CServiceBroker::GetGUI();
2122 gui
->GetAudioManager().DeInitialize();
2124 // shutdown the AudioEngine
2125 CServiceBroker::UnregisterAE();
2126 m_pActiveAE
->Shutdown();
2127 m_pActiveAE
.reset();
2129 CLog::Log(LOGINFO
, "Application stopped");
2133 CLog::Log(LOGERROR
, "Exception in CApplication::Stop()");
2137 cleanup_emu_environ();
2139 KODI::TIME::Sleep(200ms
);
2146 class CCreateAndLoadPlayList
: public IRunnable
2149 CCreateAndLoadPlayList(CFileItem
& item
, std::unique_ptr
<PLAYLIST::CPlayList
>& playlist
)
2150 : m_item(item
), m_playlist(playlist
)
2156 const std::unique_ptr
<PLAYLIST::CPlayList
> playlist(PLAYLIST::CPlayListFactory::Create(m_item
));
2159 if (playlist
->Load(m_item
.GetPath()))
2160 *m_playlist
= *playlist
;
2166 std::unique_ptr
<PLAYLIST::CPlayList
>& m_playlist
;
2170 bool CApplication::PlayMedia(CFileItem
& item
, const std::string
& player
, PLAYLIST::Id playlistId
)
2172 // if the item is a plugin we need to resolve the plugin paths
2173 if (URIUtils::HasPluginPath(item
) && !XFILE::CPluginDirectory::GetResolvedPluginResult(item
))
2176 if (PLAYLIST::IsSmartPlayList(item
))
2178 CFileItemList items
;
2179 CUtil::GetRecursiveListing(item
.GetPath(), items
, "", DIR_FLAG_NO_FILE_DIRS
);
2182 PLAYLIST::CSmartPlaylist smartpl
;
2183 //get name and type of smartplaylist, this will always succeed as GetDirectory also did this.
2184 smartpl
.OpenAndReadName(item
.GetURL());
2185 PLAYLIST::CPlayList playlist
;
2186 playlist
.Add(items
);
2187 PLAYLIST::Id smartplPlaylistId
= PLAYLIST::Id::TYPE_VIDEO
;
2189 if (smartpl
.GetType() == "songs" || smartpl
.GetType() == "albums" ||
2190 smartpl
.GetType() == "artists")
2191 smartplPlaylistId
= PLAYLIST::Id::TYPE_MUSIC
;
2193 return ProcessAndStartPlaylist(smartpl
.GetName(), playlist
, smartplPlaylistId
);
2196 else if (PLAYLIST::IsPlayList(item
) || NETWORK::IsInternetStream(item
))
2198 // Not owner. Dialog auto-deletes itself.
2199 CGUIDialogCache
* dlgCache
=
2200 new CGUIDialogCache(5s
, g_localizeStrings
.Get(10214), item
.GetLabel());
2202 //is or could be a playlist
2203 std::unique_ptr
<PLAYLIST::CPlayList
> playlist
;
2204 CCreateAndLoadPlayList
getPlaylist(item
, playlist
);
2205 bool cancelled
= !CGUIDialogBusy::Wait(&getPlaylist
, 100, true);
2210 if (dlgCache
->IsCanceled())
2220 if (playlistId
!= PLAYLIST::Id::TYPE_NONE
)
2223 if (item
.HasProperty("playlist_starting_track"))
2224 track
= (int)item
.GetProperty("playlist_starting_track").asInteger();
2225 return ProcessAndStartPlaylist(item
.GetPath(), *playlist
, playlistId
, track
);
2229 CLog::Log(LOGWARNING
,
2230 "CApplication::PlayMedia called to play a playlist {} but no idea which playlist "
2231 "to use, playing first item",
2233 if (playlist
->size())
2234 return PlayFile(*(*playlist
)[0], "", false);
2238 else if (item
.IsPVR())
2240 return CServiceBroker::GetPVRManager().Get
<PVR::GUI::Playback
>().PlayMedia(item
);
2243 CURL
path(item
.GetPath());
2244 if (path
.GetProtocol() == "game")
2247 if (CServiceBroker::GetAddonMgr().GetAddon(path
.GetHostName(), addon
, AddonType::GAMEDLL
,
2248 OnlyEnabled::CHOICE_YES
))
2250 CFileItem
addonItem(addon
);
2251 return PlayFile(addonItem
, player
, false);
2255 //nothing special just play
2256 return PlayFile(item
, player
, false);
2260 // For playing a multi-file video. Particularly inefficient
2261 // on startup, as we are required to calculate the length
2262 // of each video, so we open + close each one in turn.
2263 // A faster calculation of video time would improve this
2265 // return value: same with PlayFile()
2266 bool CApplication::PlayStack(CFileItem
& item
, bool bRestart
)
2268 const auto stackHelper
= GetComponent
<CApplicationStackHelper
>();
2269 if (!stackHelper
->InitializeStack(item
))
2272 std::optional
<int64_t> startoffset
= stackHelper
->InitializeStackStartPartAndOffset(item
);
2275 CLog::LogF(LOGERROR
, "Failed to obtain start offset for stack {}. Aborting playback.",
2280 CFileItem selectedStackPart
= stackHelper
->GetCurrentStackPartFileItem();
2281 selectedStackPart
.SetStartOffset(startoffset
.value());
2283 if (item
.HasProperty("savedplayerstate"))
2285 selectedStackPart
.SetProperty("savedplayerstate", item
.GetProperty("savedplayerstate")); // pass on to part
2286 item
.ClearProperty("savedplayerstate");
2289 return PlayFile(selectedStackPart
, "", true);
2292 bool CApplication::PlayFile(CFileItem item
,
2293 const std::string
& player
,
2294 bool bRestart
/* = false */,
2295 bool forceSelection
/* = false */)
2297 // Ensure the MIME type has been retrieved for http:// and shout:// streams
2298 if (item
.GetMimeType().empty())
2299 item
.FillInMimeType();
2301 const auto appPlayer
= GetComponent
<CApplicationPlayer
>();
2302 const auto stackHelper
= GetComponent
<CApplicationStackHelper
>();
2306 // bRestart will be true when called from PlayStack(), skipping this block
2307 appPlayer
->SetPlaySpeed(1);
2309 m_nextPlaylistItem
= -1;
2310 stackHelper
->Clear();
2312 if (VIDEO::IsVideo(item
))
2313 CUtil::ClearSubtitles();
2316 if (VIDEO::IsDiscStub(item
))
2318 return CServiceBroker::GetMediaManager().playStubFile(item
);
2321 if (PLAYLIST::IsPlayList(item
))
2324 // Translate/Resolve the url if needed
2325 const std::unique_ptr
<IDirectory
> dir
{CDirectoryFactory::Create(item
)};
2326 if (dir
&& !dir
->Resolve(item
))
2331 // if we have a stacked set of files, we need to setup our stack routines for
2332 // "seamless" seeking and total time of the movie etc.
2333 // will recall with restart set to true
2335 return PlayStack(item
, bRestart
);
2337 CPlayerOptions options
;
2339 if (item
.HasProperty("StartPercent"))
2341 options
.startpercent
= item
.GetProperty("StartPercent").asDouble();
2342 item
.SetStartOffset(0);
2345 options
.starttime
= CUtil::ConvertMilliSecsToSecs(item
.GetStartOffset());
2349 // have to be set here due to playstack using this for starting the file
2350 if (item
.HasVideoInfoTag())
2351 options
.state
= item
.GetVideoInfoTag()->GetResumePoint().playerState
;
2353 if (!bRestart
|| stackHelper
->IsPlayingISOStack())
2355 // the following code block is only applicable when bRestart is false OR to ISO stacks
2357 if (VIDEO::IsVideo(item
))
2359 // open the d/b and retrieve the bookmarks for the current movie
2363 std::string path
= item
.GetPath();
2364 std::string
videoInfoTagPath(item
.GetVideoInfoTag()->m_strFileNameAndPath
);
2365 if (videoInfoTagPath
.starts_with("removable://") || VIDEO::IsVideoDb(item
))
2366 path
= videoInfoTagPath
;
2368 // Note that we need to load the tag from database also if the item already has a tag,
2369 // because for example the (full) video info for strm files will be loaded here.
2370 dbs
.LoadVideoInfo(path
, *item
.GetVideoInfoTag());
2372 if (item
.HasProperty("savedplayerstate"))
2374 options
.starttime
= CUtil::ConvertMilliSecsToSecs(item
.GetStartOffset());
2375 options
.state
= item
.GetProperty("savedplayerstate").asString();
2376 item
.ClearProperty("savedplayerstate");
2378 else if (item
.GetStartOffset() == STARTOFFSET_RESUME
)
2380 options
.starttime
= 0.0;
2381 if (item
.IsResumePointSet())
2383 options
.starttime
= item
.GetCurrentResumeTime();
2384 if (item
.HasVideoInfoTag())
2385 options
.state
= item
.GetVideoInfoTag()->GetResumePoint().playerState
;
2390 std::string path
= item
.GetPath();
2391 if (item
.HasVideoInfoTag() && StringUtils::StartsWith(item
.GetVideoInfoTag()->m_strFileNameAndPath
, "removable://"))
2392 path
= item
.GetVideoInfoTag()->m_strFileNameAndPath
;
2393 else if (item
.HasProperty("original_listitem_url") && URIUtils::IsPlugin(item
.GetProperty("original_listitem_url").asString()))
2394 path
= item
.GetProperty("original_listitem_url").asString();
2395 if (dbs
.GetResumeBookMark(path
, bookmark
))
2397 options
.starttime
= bookmark
.timeInSeconds
;
2398 options
.state
= bookmark
.playerState
;
2402 if (options
.starttime
== 0.0 && item
.HasVideoInfoTag())
2404 // No resume point is set, but check if this item is part of a multi-episode file
2405 const CVideoInfoTag
*tag
= item
.GetVideoInfoTag();
2407 if (tag
->m_iBookmarkId
> 0)
2410 dbs
.GetBookMarkForEpisode(*tag
, bookmark
);
2411 options
.starttime
= bookmark
.timeInSeconds
;
2412 options
.state
= bookmark
.playerState
;
2416 else if (item
.HasVideoInfoTag())
2418 const CVideoInfoTag
*tag
= item
.GetVideoInfoTag();
2420 if (tag
->m_iBookmarkId
> 0)
2423 dbs
.GetBookMarkForEpisode(*tag
, bookmark
);
2424 options
.starttime
= bookmark
.timeInSeconds
;
2425 options
.state
= bookmark
.playerState
;
2433 // a disc image might be Blu-Ray disc
2434 if (!(options
.startpercent
> 0.0 || options
.starttime
> 0.0) &&
2435 (VIDEO::IsBDFile(item
) || item
.IsDiscImage() ||
2436 (forceSelection
&& VIDEO::IsBlurayPlaylist(item
))))
2438 // No video selection when using external or remote players (they handle it if supported)
2439 const bool isSimpleMenuAllowed
= [&]()
2441 const std::string defaulPlayer
{
2442 player
.empty() ? m_ServiceManager
->GetPlayerCoreFactory().GetDefaultPlayer(item
)
2444 const bool isExternalPlayer
{
2445 m_ServiceManager
->GetPlayerCoreFactory().IsExternalPlayer(defaulPlayer
)};
2446 const bool isRemotePlayer
{
2447 m_ServiceManager
->GetPlayerCoreFactory().IsRemotePlayer(defaulPlayer
)};
2448 return !isExternalPlayer
&& !isRemotePlayer
;
2451 if (isSimpleMenuAllowed
)
2453 // Check if we must show the simplified bd menu.
2454 if (!CGUIDialogSimpleMenu::ShowPlaySelection(item
, forceSelection
))
2459 // this really aught to be inside !bRestart, but since PlayStack
2460 // uses that to init playback, we have to keep it outside
2461 const PLAYLIST::Id playlistId
= CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist();
2462 if (MUSIC::IsAudio(item
) && playlistId
== PLAYLIST::Id::TYPE_MUSIC
)
2463 { // playing from a playlist by the looks
2464 // don't switch to fullscreen if we are not playing the first item...
2465 options
.fullscreen
= !CServiceBroker::GetPlaylistPlayer().HasPlayedFirstFile() &&
2466 CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(
2467 CSettings::SETTING_MUSICFILES_SELECTACTION
) &&
2468 !CMediaSettings::GetInstance().DoesMediaStartWindowed();
2470 else if (VIDEO::IsVideo(item
) && playlistId
== PLAYLIST::Id::TYPE_VIDEO
&&
2471 CServiceBroker::GetPlaylistPlayer().GetPlaylist(playlistId
).size() > 1)
2472 { // playing from a playlist by the looks
2473 // don't switch to fullscreen if we are not playing the first item...
2474 options
.fullscreen
= !CServiceBroker::GetPlaylistPlayer().HasPlayedFirstFile() &&
2475 CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_fullScreenOnMovieStart
&&
2476 !CMediaSettings::GetInstance().DoesMediaStartWindowed();
2478 else if (stackHelper
->IsPlayingRegularStack())
2480 //! @todo - this will fail if user seeks back to first file in stack
2481 if (stackHelper
->GetCurrentPartNumber() == 0 ||
2482 stackHelper
->GetRegisteredStack(item
)->GetStartOffset() != 0)
2483 options
.fullscreen
= CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->
2484 m_fullScreenOnMovieStart
&& !CMediaSettings::GetInstance().DoesMediaStartWindowed();
2486 options
.fullscreen
= false;
2489 options
.fullscreen
= CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->
2490 m_fullScreenOnMovieStart
&& !CMediaSettings::GetInstance().DoesMediaStartWindowed();
2492 // stereo streams may have lower quality, i.e. 32bit vs 16 bit
2493 options
.preferStereo
= CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_videoPreferStereoStream
&&
2494 CServiceBroker::GetActiveAE()->HasStereoAudioChannelCount();
2496 // reset VideoStartWindowed as it's a temp setting
2497 CMediaSettings::GetInstance().SetMediaStartWindowed(false);
2500 // for playing a new item, previous playing item's callback may already
2501 // pushed some delay message into the threadmessage list, they are not
2502 // expected be processed after or during the new item playback starting.
2503 // so we clean up previous playing item's playback callback delay messages here.
2504 int previousMsgsIgnoredByNewPlaying
[] = {
2505 GUI_MSG_PLAYBACK_STARTED
,
2506 GUI_MSG_PLAYBACK_ENDED
,
2507 GUI_MSG_PLAYBACK_STOPPED
,
2508 GUI_MSG_PLAYLIST_CHANGED
,
2509 GUI_MSG_PLAYLISTPLAYER_STOPPED
,
2510 GUI_MSG_PLAYLISTPLAYER_STARTED
,
2511 GUI_MSG_PLAYLISTPLAYER_CHANGED
,
2512 GUI_MSG_QUEUE_NEXT_ITEM
,
2515 int dMsgCount
= CServiceBroker::GetGUI()->GetWindowManager().RemoveThreadMessageByMessageIds(&previousMsgsIgnoredByNewPlaying
[0]);
2517 CLog::LogF(LOGDEBUG
, "Ignored {} playback thread messages", dMsgCount
);
2520 const auto appVolume
= GetComponent
<CApplicationVolumeHandling
>();
2521 appPlayer
->OpenFile(item
, options
, m_ServiceManager
->GetPlayerCoreFactory(), player
, *this);
2522 appPlayer
->SetVolume(appVolume
->GetVolumeRatio());
2523 appPlayer
->SetMute(appVolume
->IsMuted());
2525 #if !defined(TARGET_POSIX)
2526 CGUIComponent
*gui
= CServiceBroker::GetGUI();
2528 gui
->GetAudioManager().Enable(false);
2531 if (item
.HasPVRChannelInfoTag())
2532 CServiceBroker::GetPlaylistPlayer().SetCurrentPlaylist(PLAYLIST::Id::TYPE_NONE
);
2537 void CApplication::PlaybackCleanup()
2539 const auto appPlayer
= GetComponent
<CApplicationPlayer
>();
2540 const auto stackHelper
= GetComponent
<CApplicationStackHelper
>();
2542 if (!appPlayer
->IsPlaying())
2544 CGUIComponent
*gui
= CServiceBroker::GetGUI();
2546 CServiceBroker::GetGUI()->GetAudioManager().Enable(true);
2547 appPlayer
->OpenNext(m_ServiceManager
->GetPlayerCoreFactory());
2550 if (!appPlayer
->IsPlayingVideo())
2552 if(CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow() == WINDOW_FULLSCREEN_VIDEO
||
2553 CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow() == WINDOW_FULLSCREEN_GAME
)
2555 CServiceBroker::GetGUI()->GetWindowManager().PreviousWindow();
2559 // resets to res_desktop or look&feel resolution (including refreshrate)
2560 CServiceBroker::GetWinSystem()->GetGfxContext().SetFullScreenVideo(false);
2562 #ifdef TARGET_DARWIN_EMBEDDED
2563 CDarwinUtils::SetScheduling(false);
2567 const auto appPower
= GetComponent
<CApplicationPowerHandling
>();
2569 if (!appPlayer
->IsPlayingAudio() &&
2570 CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist() == PLAYLIST::Id::TYPE_NONE
&&
2571 CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow() == WINDOW_VISUALISATION
)
2573 CServiceBroker::GetSettingsComponent()->GetSettings()->Save(); // save vis settings
2574 appPower
->WakeUpScreenSaverAndDPMS();
2575 CServiceBroker::GetGUI()->GetWindowManager().PreviousWindow();
2578 // DVD ejected while playing in vis ?
2579 if (!appPlayer
->IsPlayingAudio() &&
2580 (MUSIC::IsCDDA(*m_itemCurrentFile
) || m_itemCurrentFile
->IsOnDVD()) &&
2581 !CServiceBroker::GetMediaManager().IsDiscInDrive() &&
2582 CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow() == WINDOW_VISUALISATION
)
2585 CServiceBroker::GetSettingsComponent()->GetSettings()->Save(); // save vis settings
2586 appPower
->WakeUpScreenSaverAndDPMS();
2587 CServiceBroker::GetGUI()->GetWindowManager().PreviousWindow();
2590 if (!appPlayer
->IsPlaying())
2592 stackHelper
->Clear();
2593 appPlayer
->ResetPlayer();
2596 if (CServiceBroker::GetAppParams()->IsTestMode())
2597 CServiceBroker::GetAppMessenger()->PostMsg(TMSG_QUIT
);
2600 bool CApplication::IsPlayingFullScreenVideo() const
2602 const auto appPlayer
= GetComponent
<CApplicationPlayer
>();
2603 return appPlayer
->IsPlayingVideo() &&
2604 CServiceBroker::GetWinSystem()->GetGfxContext().IsFullScreenVideo();
2607 bool CApplication::IsFullScreen()
2609 return IsPlayingFullScreenVideo() ||
2610 (CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow() == WINDOW_VISUALISATION
) ||
2611 CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow() == WINDOW_SLIDESHOW
;
2614 void CApplication::StopPlaying()
2616 CGUIComponent
*gui
= CServiceBroker::GetGUI();
2620 int iWin
= gui
->GetWindowManager().GetActiveWindow();
2621 const auto appPlayer
= GetComponent
<CApplicationPlayer
>();
2622 if (appPlayer
->IsPlaying())
2624 appPlayer
->ClosePlayer();
2626 // turn off visualisation window when stopping
2627 if ((iWin
== WINDOW_VISUALISATION
||
2628 iWin
== WINDOW_FULLSCREEN_VIDEO
||
2629 iWin
== WINDOW_FULLSCREEN_GAME
) &&
2631 gui
->GetWindowManager().PreviousWindow();
2633 g_partyModeManager
.Disable();
2638 bool CApplication::OnMessage(CGUIMessage
& message
)
2640 switch (message
.GetMessage())
2642 case GUI_MSG_NOTIFY_ALL
:
2644 if (message
.GetParam1()==GUI_MSG_REMOVED_MEDIA
)
2646 // Update general playlist: Remove DVD playlist items
2647 int nRemoved
= CServiceBroker::GetPlaylistPlayer().RemoveDVDItems();
2650 CGUIMessage
msg( GUI_MSG_PLAYLIST_CHANGED
, 0, 0 );
2651 CServiceBroker::GetGUI()->GetWindowManager().SendMessage( msg
);
2653 // stop the file if it's on dvd (will set the resume point etc)
2654 if (m_itemCurrentFile
->IsOnDVD())
2657 else if (message
.GetParam1() == GUI_MSG_UI_READY
)
2659 // remove splash window
2660 CServiceBroker::GetGUI()->GetWindowManager().Delete(WINDOW_SPLASH
);
2662 // show the volumebar if the volume is muted
2663 const auto appVolume
= GetComponent
<CApplicationVolumeHandling
>();
2664 if (appVolume
->IsMuted() ||
2665 appVolume
->GetVolumeRatio() <= CApplicationVolumeHandling::VOLUME_MINIMUM
)
2666 appVolume
->ShowVolumeBar();
2668 if (!m_incompatibleAddons
.empty())
2670 // filter addons that are not dependencies
2671 std::vector
<std::string
> disabledAddonNames
;
2672 for (const auto& addoninfo
: m_incompatibleAddons
)
2674 if (!CAddonType::IsDependencyType(addoninfo
->MainType()))
2675 disabledAddonNames
.emplace_back(addoninfo
->Name());
2678 // migration (incompatible addons) dialog
2679 auto addonList
= StringUtils::Join(disabledAddonNames
, ", ");
2680 auto msg
= StringUtils::Format(g_localizeStrings
.Get(24149), addonList
);
2681 HELPERS::ShowOKDialogText(CVariant
{24148}, CVariant
{std::move(msg
)});
2682 m_incompatibleAddons
.clear();
2685 // offer enabling addons at kodi startup that are disabled due to
2686 // e.g. os package manager installation on linux
2687 ConfigureAndEnableAddons();
2689 m_bInitializing
= false;
2691 if (message
.GetSenderId() == WINDOW_SETTINGS_PROFILES
)
2692 GetComponent
<CApplicationSkinHandling
>()->ReloadSkin(false);
2694 else if (message
.GetParam1() == GUI_MSG_UPDATE_ITEM
&& message
.GetItem())
2696 CFileItemPtr item
= std::static_pointer_cast
<CFileItem
>(message
.GetItem());
2697 if (m_itemCurrentFile
->IsSamePath(item
.get()))
2699 m_itemCurrentFile
->UpdateInfo(*item
);
2700 CServiceBroker::GetGUI()->GetInfoManager().UpdateCurrentItem(*item
);
2706 case GUI_MSG_PLAYBACK_STARTED
:
2708 #ifdef TARGET_DARWIN_EMBEDDED
2709 // @TODO move this away to platform code
2710 CDarwinUtils::SetScheduling(GetComponent
<CApplicationPlayer
>()->IsPlayingVideo());
2713 std::make_shared
<CFileItem
>(*std::static_pointer_cast
<CFileItem
>(message
.GetItem()));
2714 m_playerEvent
.Reset();
2716 CServiceBroker::GetPVRManager().OnPlaybackStarted(*m_itemCurrentFile
);
2718 PLAYLIST::CPlayList playList
= CServiceBroker::GetPlaylistPlayer().GetPlaylist(
2719 CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist());
2721 // Update our infoManager with the new details etc.
2722 if (m_nextPlaylistItem
>= 0)
2724 // playing an item which is not in the list - player might be stopped already
2726 if (playList
.size() <= m_nextPlaylistItem
)
2729 // we've started a previously queued item
2730 CFileItemPtr item
= playList
[m_nextPlaylistItem
];
2731 // update the playlist manager
2732 int currentSong
= CServiceBroker::GetPlaylistPlayer().GetCurrentItemIdx();
2733 int param
= ((currentSong
& 0xffff) << 16) | (m_nextPlaylistItem
& 0xffff);
2734 CGUIMessage
msg(GUI_MSG_PLAYLISTPLAYER_CHANGED
, 0, 0,
2735 static_cast<int>(CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist()),
2737 CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg
);
2738 CServiceBroker::GetPlaylistPlayer().SetCurrentItemIdx(m_nextPlaylistItem
);
2739 m_itemCurrentFile
= std::make_shared
<CFileItem
>(*item
);
2741 CServiceBroker::GetGUI()->GetInfoManager().SetCurrentItem(*m_itemCurrentFile
);
2742 g_partyModeManager
.OnSongChange(true);
2745 // informs python script currently running playback has started
2746 // (does nothing if python is not loaded)
2747 CServiceBroker::GetXBPython().OnPlayBackStarted(*m_itemCurrentFile
);
2751 param
["player"]["speed"] = 1;
2752 param
["player"]["playerid"] =
2753 static_cast<int>(CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist());
2755 CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::Player
, "OnPlay",
2756 m_itemCurrentFile
, param
);
2758 // we don't want a busy dialog when switching channels
2759 const auto appPlayer
= GetComponent
<CApplicationPlayer
>();
2760 if (!m_itemCurrentFile
->IsLiveTV() ||
2761 (!appPlayer
->IsPlayingVideo() && !appPlayer
->IsPlayingAudio()))
2763 CGUIDialogBusy
* dialog
=
2764 CServiceBroker::GetGUI()->GetWindowManager().GetWindow
<CGUIDialogBusy
>(
2765 WINDOW_DIALOG_BUSY
);
2766 if (dialog
&& !dialog
->IsDialogRunning())
2767 dialog
->WaitOnEvent(m_playerEvent
);
2774 case GUI_MSG_QUEUE_NEXT_ITEM
:
2776 // Check to see if our playlist player has a new item for us,
2777 // and if so, we check whether our current player wants the file
2778 int iNext
= CServiceBroker::GetPlaylistPlayer().GetNextItemIdx();
2779 PLAYLIST::CPlayList
& playlist
= CServiceBroker::GetPlaylistPlayer().GetPlaylist(
2780 CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist());
2781 if (iNext
< 0 || iNext
>= playlist
.size())
2783 GetComponent
<CApplicationPlayer
>()->OnNothingToQueueNotify();
2784 return true; // nothing to do
2787 // ok, grab the next song
2788 CFileItem
file(*playlist
[iNext
]);
2790 CURL
url(file
.GetDynPath());
2791 if (url
.IsProtocol("plugin"))
2792 XFILE::CPluginDirectory::GetPluginResult(url
.Get(), file
, false);
2794 // Don't queue if next media type is different from current one
2795 bool bNothingToQueue
= false;
2797 const auto appPlayer
= GetComponent
<CApplicationPlayer
>();
2798 if (!VIDEO::IsVideo(file
) && appPlayer
->IsPlayingVideo())
2799 bNothingToQueue
= true;
2800 else if ((!MUSIC::IsAudio(file
) || VIDEO::IsVideo(file
)) && appPlayer
->IsPlayingAudio())
2801 bNothingToQueue
= true;
2803 if (bNothingToQueue
)
2805 appPlayer
->OnNothingToQueueNotify();
2810 if (URIUtils::IsUPnP(file
.GetDynPath()))
2812 if (!XFILE::CUPnPDirectory::GetResource(file
.GetDynURL(), file
))
2817 // ok - send the file to the player, if it accepts it
2818 if (appPlayer
->QueueNextFile(file
))
2820 // player accepted the next file
2821 m_nextPlaylistItem
= iNext
;
2825 /* Player didn't accept next file: *ALWAYS* advance playlist in this case so the player can
2826 queue the next (if it wants to) and it doesn't keep looping on this song */
2827 CServiceBroker::GetPlaylistPlayer().SetCurrentItemIdx(iNext
);
2834 case GUI_MSG_PLAY_TRAILER
:
2836 const CFileItem
* item
= dynamic_cast<CFileItem
*>(message
.GetItem().get());
2837 if (item
== nullptr)
2839 CLog::LogF(LOGERROR
, "Supplied item is not a CFileItem! Trailer cannot be played.");
2843 std::unique_ptr
<CFileItem
> trailerItem
=
2844 ContentUtils::GeneratePlayableTrailerItem(*item
, g_localizeStrings
.Get(20410));
2846 if (PLAYLIST::IsPlayList(*item
))
2848 std::unique_ptr
<CFileItemList
> fileitemList
= std::make_unique
<CFileItemList
>();
2849 fileitemList
->Add(std::move(trailerItem
));
2850 CServiceBroker::GetAppMessenger()->PostMsg(TMSG_MEDIA_PLAY
, -1, -1,
2851 static_cast<void*>(fileitemList
.release()));
2855 CServiceBroker::GetAppMessenger()->PostMsg(TMSG_MEDIA_PLAY
, 1, 0,
2856 static_cast<void*>(trailerItem
.release()));
2861 case GUI_MSG_PLAYBACK_STOPPED
:
2863 CServiceBroker::GetPVRManager().OnPlaybackStopped(*m_itemCurrentFile
);
2865 CVariant
data(CVariant::VariantTypeObject
);
2866 data
["end"] = false;
2867 CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::Player
, "OnStop",
2868 m_itemCurrentFile
, data
);
2870 m_playerEvent
.Set();
2874 CServiceBroker::GetXBPython().OnPlayBackStopped();
2879 case GUI_MSG_PLAYBACK_ENDED
:
2881 CServiceBroker::GetPVRManager().OnPlaybackEnded(*m_itemCurrentFile
);
2883 CVariant
data(CVariant::VariantTypeObject
);
2885 CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::Player
, "OnStop",
2886 m_itemCurrentFile
, data
);
2888 m_playerEvent
.Set();
2889 const auto stackHelper
= GetComponent
<CApplicationStackHelper
>();
2890 if (stackHelper
->IsPlayingRegularStack() && stackHelper
->HasNextStackPartFileItem())
2891 { // just play the next item in the stack
2892 PlayFile(stackHelper
->SetNextStackPartCurrentFileItem(), "", true);
2896 // For EPG playlist items we keep the player open to ensure continuous viewing experience.
2897 const bool isEpgPlaylistItem
{
2898 m_itemCurrentFile
->GetProperty("epg_playlist_item").asBoolean(false)};
2902 if (!isEpgPlaylistItem
)
2904 if (!CServiceBroker::GetPlaylistPlayer().PlayNext(1, true))
2905 GetComponent
<CApplicationPlayer
>()->ClosePlayer();
2911 CServiceBroker::GetXBPython().OnPlayBackEnded();
2916 case GUI_MSG_PLAYLISTPLAYER_STOPPED
:
2918 if (GetComponent
<CApplicationPlayer
>()->IsPlaying())
2923 case GUI_MSG_PLAYBACK_AVSTARTED
:
2926 param
["player"]["speed"] = 1;
2927 param
["player"]["playerid"] =
2928 static_cast<int>(CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist());
2929 CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::Player
, "OnAVStart",
2930 m_itemCurrentFile
, param
);
2931 m_playerEvent
.Set();
2933 // informs python script currently running playback has started
2934 // (does nothing if python is not loaded)
2935 CServiceBroker::GetXBPython().OnAVStarted(*m_itemCurrentFile
);
2940 case GUI_MSG_PLAYBACK_AVCHANGE
:
2943 // informs python script currently running playback has started
2944 // (does nothing if python is not loaded)
2945 CServiceBroker::GetXBPython().OnAVChange();
2948 param
["player"]["speed"] = 1;
2949 param
["player"]["playerid"] =
2950 static_cast<int>(CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist());
2951 CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::Player
, "OnAVChange",
2952 m_itemCurrentFile
, param
);
2956 case GUI_MSG_PLAYBACK_PAUSED
:
2959 param
["player"]["speed"] = 0;
2960 param
["player"]["playerid"] =
2961 static_cast<int>(CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist());
2962 CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::Player
, "OnPause",
2963 m_itemCurrentFile
, param
);
2967 case GUI_MSG_PLAYBACK_RESUMED
:
2970 param
["player"]["speed"] = 1;
2971 param
["player"]["playerid"] =
2972 static_cast<int>(CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist());
2973 CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::Player
, "OnResume",
2974 m_itemCurrentFile
, param
);
2978 case GUI_MSG_PLAYBACK_SEEKED
:
2981 const int64_t iTime
= message
.GetParam1AsI64();
2982 const int64_t seekOffset
= message
.GetParam2AsI64();
2983 JSONRPC::CJSONUtils::MillisecondsToTimeObject(iTime
, param
["player"]["time"]);
2984 JSONRPC::CJSONUtils::MillisecondsToTimeObject(seekOffset
, param
["player"]["seekoffset"]);
2985 param
["player"]["playerid"] =
2986 static_cast<int>(CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist());
2987 const auto& components
= CServiceBroker::GetAppComponents();
2988 const auto appPlayer
= components
.GetComponent
<CApplicationPlayer
>();
2989 param
["player"]["speed"] = static_cast<int>(appPlayer
->GetPlaySpeed());
2990 CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::Player
, "OnSeek",
2991 m_itemCurrentFile
, param
);
2993 CDataCacheCore::GetInstance().SeekFinished(static_cast<int>(seekOffset
));
2998 case GUI_MSG_PLAYBACK_SPEED_CHANGED
:
3001 param
["player"]["speed"] = message
.GetParam1();
3002 param
["player"]["playerid"] =
3003 static_cast<int>(CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist());
3004 CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::Player
, "OnSpeedChanged",
3005 m_itemCurrentFile
, param
);
3010 case GUI_MSG_PLAYBACK_ERROR
:
3011 HELPERS::ShowOKDialogText(CVariant
{16026}, CVariant
{16027});
3014 case GUI_MSG_PLAYLISTPLAYER_STARTED
:
3015 case GUI_MSG_PLAYLISTPLAYER_CHANGED
:
3020 case GUI_MSG_FULLSCREEN
:
3021 { // Switch to fullscreen, if we can
3022 CGUIComponent
* gui
= CServiceBroker::GetGUI();
3024 gui
->GetWindowManager().SwitchToFullScreen();
3029 case GUI_MSG_EXECUTE
:
3030 if (message
.GetNumStringParams())
3031 return ExecuteXBMCAction(message
.GetStringParam(), message
.GetItem());
3037 bool CApplication::ExecuteXBMCAction(std::string actionStr
,
3038 const std::shared_ptr
<CGUIListItem
>& item
/* = NULL */)
3040 // see if it is a user set string
3042 //We don't know if there is unsecure information in this yet, so we
3043 //postpone any logging
3044 const std::string
in_actionStr(actionStr
);
3046 actionStr
= GUILIB::GUIINFO::CGUIInfoLabel::GetItemLabel(actionStr
, item
.get());
3048 actionStr
= GUILIB::GUIINFO::CGUIInfoLabel::GetLabel(actionStr
, INFO::DEFAULT_CONTEXT
);
3050 // user has asked for something to be executed
3051 if (CBuiltins::GetInstance().HasCommand(actionStr
))
3053 if (!CBuiltins::GetInstance().IsSystemPowerdownCommand(actionStr
) ||
3054 CServiceBroker::GetPVRManager().Get
<PVR::GUI::PowerManagement
>().CanSystemPowerdown())
3055 CBuiltins::GetInstance().Execute(actionStr
);
3059 // try translating the action from our ButtonTranslator
3060 unsigned int actionID
;
3061 if (ACTION::CActionTranslator::TranslateString(actionStr
, actionID
))
3063 OnAction(CAction(actionID
));
3066 CFileItem
item(actionStr
, false);
3068 if (item
.IsPythonScript())
3069 { // a python script
3070 CScriptInvocationManager::GetInstance().ExecuteAsync(item
.GetPath());
3074 if (MUSIC::IsAudio(item
) || VIDEO::IsVideo(item
) || item
.IsGame())
3075 { // an audio or video file
3080 //At this point we have given up to translate, so even though
3081 //there may be insecure information, we log it.
3082 CLog::LogF(LOGDEBUG
, "Tried translating, but failed to understand {}", in_actionStr
);
3089 void CApplication::ConfigureAndEnableAddons()
3091 std::vector
<std::shared_ptr
<IAddon
>>
3092 disabledAddons
; /*!< Installed addons, but not auto-enabled via manifest */
3094 auto& addonMgr
= CServiceBroker::GetAddonMgr();
3096 if (addonMgr
.GetDisabledAddons(disabledAddons
) && !disabledAddons
.empty())
3098 // this applies to certain platforms only:
3099 // look at disabled addons with disabledReason == NONE, usually those are installed via package managers or manually.
3100 // also try to enable add-ons with disabledReason == INCOMPATIBLE at startup for all platforms.
3102 bool isConfigureAddonsAtStartupEnabled
=
3103 m_ServiceManager
->GetPlatform().IsConfigureAddonsAtStartupEnabled();
3105 for (const auto& addon
: disabledAddons
)
3107 if (addonMgr
.IsAddonDisabledWithReason(addon
->ID(), ADDON::AddonDisabledReason::INCOMPATIBLE
))
3109 auto addonInfo
= addonMgr
.GetAddonInfo(addon
->ID(), AddonType::UNKNOWN
);
3110 if (addonInfo
&& addonMgr
.IsCompatible(addonInfo
))
3112 CLog::Log(LOGDEBUG
, "CApplication::{}: enabling the compatible version of [{}].",
3113 __FUNCTION__
, addon
->ID());
3114 addonMgr
.EnableAddon(addon
->ID());
3119 if (addonMgr
.IsAddonDisabledExcept(addon
->ID(), ADDON::AddonDisabledReason::NONE
) ||
3120 CAddonType::IsDependencyType(addon
->MainType()))
3125 if (isConfigureAddonsAtStartupEnabled
)
3127 if (HELPERS::ShowYesNoDialogLines(CVariant
{24039}, // Disabled add-ons
3128 CVariant
{24059}, // Would you like to enable this add-on?
3129 CVariant
{addon
->Name()}) == DialogResponse::CHOICE_YES
)
3131 if (addon
->CanHaveAddonOrInstanceSettings())
3133 if (CGUIDialogAddonSettings::ShowForAddon(addon
))
3135 // only enable if settings dialog hasn't been cancelled
3136 addonMgr
.EnableAddon(addon
->ID());
3141 addonMgr
.EnableAddon(addon
->ID());
3146 // user chose not to configure/enable so we're not asking anymore
3147 addonMgr
.UpdateDisabledReason(addon
->ID(), ADDON::AddonDisabledReason::USER
);
3154 void CApplication::Process()
3156 // dispatch the messages generated by python or other threads to the current window
3157 CServiceBroker::GetGUI()->GetWindowManager().DispatchThreadMessages();
3159 // process messages which have to be send to the gui
3160 // (this can only be done after CServiceBroker::GetGUI()->GetWindowManager().Render())
3161 CServiceBroker::GetAppMessenger()->ProcessWindowMessages();
3163 // handle any active scripts
3166 // Allow processing of script threads to let them shut down properly.
3167 CSingleExit
ex(CServiceBroker::GetWinSystem()->GetGfxContext());
3168 m_frameMoveGuard
.unlock();
3169 CScriptInvocationManager::GetInstance().Process();
3170 m_frameMoveGuard
.lock();
3173 // process messages, even if a movie is playing
3174 CServiceBroker::GetAppMessenger()->ProcessMessages();
3175 if (m_bStop
) return; //we're done, everything has been unloaded
3177 // do any processing that isn't needed on each run
3178 if( m_slowTimer
.GetElapsedMilliseconds() > 500 )
3180 m_slowTimer
.Reset();
3185 // We get called every 500ms
3186 void CApplication::ProcessSlow()
3188 // process skin resources (skin timers)
3189 GetComponent
<CApplicationSkinHandling
>()->ProcessSkin();
3191 CServiceBroker::GetPowerManager().ProcessEvents();
3193 // Temporarily pause pausable jobs when viewing video/picture
3194 int currentWindow
= CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow();
3195 if (VIDEO::IsVideo(CurrentFileItem()) || CurrentFileItem().IsPicture() ||
3196 currentWindow
== WINDOW_FULLSCREEN_VIDEO
|| currentWindow
== WINDOW_FULLSCREEN_GAME
||
3197 currentWindow
== WINDOW_SLIDESHOW
)
3199 CServiceBroker::GetJobManager()->PauseJobs();
3203 CServiceBroker::GetJobManager()->UnPauseJobs();
3206 // Check if we need to activate the screensaver / DPMS.
3207 const auto appPower
= GetComponent
<CApplicationPowerHandling
>();
3208 appPower
->CheckScreenSaverAndDPMS();
3210 // Check if we need to shutdown (if enabled).
3211 #if defined(TARGET_DARWIN)
3212 if (CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_POWERMANAGEMENT_SHUTDOWNTIME
) &&
3213 CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_fullScreen
)
3215 if (CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_POWERMANAGEMENT_SHUTDOWNTIME
))
3218 appPower
->CheckShutdown();
3221 #if defined(TARGET_POSIX)
3222 if (CPlatformPosix::TestQuitFlag())
3224 CLog::Log(LOGINFO
, "Quitting due to POSIX signal");
3225 CServiceBroker::GetAppMessenger()->PostMsg(TMSG_QUIT
);
3229 // check if we should restart the player
3230 CheckDelayedPlayerRestart();
3232 // check if we can unload any unreferenced dlls or sections
3233 const auto appPlayer
= GetComponent
<CApplicationPlayer
>();
3234 if (!appPlayer
->IsPlayingVideo())
3235 CSectionLoader::UnloadDelayed();
3237 #ifdef TARGET_ANDROID
3238 // Pass the slow loop to droid
3239 CXBMCApp::Get().ProcessSlow();
3242 // check for any idle curl connections
3243 g_curlInterface
.CheckIdle();
3245 CServiceBroker::GetGUI()->GetLargeTextureManager().CleanupUnusedImages();
3247 CServiceBroker::GetGUI()->GetTextureManager().FreeUnusedTextures(5000);
3249 #ifdef HAS_OPTICAL_DRIVE
3250 // checks whats in the DVD drive and tries to autostart the content (xbox games, dvd, cdda, avi files...)
3251 if (!appPlayer
->IsPlayingVideo())
3252 m_Autorun
->HandleAutorun();
3255 // update upnp server/renderer states
3257 if (CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_SERVICES_UPNP
) && UPNP::CUPnP::IsInstantiated())
3258 UPNP::CUPnP::GetInstance()->UpdateState();
3261 #if defined(TARGET_POSIX) && defined(HAS_FILESYSTEM_SMB)
3265 #ifdef HAS_FILESYSTEM_NFS
3266 gNfsConnection
.CheckIfIdle();
3269 for (const auto& vfsAddon
: CServiceBroker::GetVFSAddonCache().GetAddonInstances())
3270 vfsAddon
->ClearOutIdle();
3272 CServiceBroker::GetMediaManager().ProcessEvents();
3274 // if we don't render the gui there's no reason to start the screensaver.
3275 // that way the screensaver won't kick in if we maximize the XBMC window
3276 // after the screensaver start time.
3277 if (!appPower
->GetRenderGUI())
3278 appPower
->ResetScreenSaverTimer();
3281 void CApplication::DelayedPlayerRestart()
3283 m_restartPlayerTimer
.StartZero();
3286 void CApplication::CheckDelayedPlayerRestart()
3288 if (m_restartPlayerTimer
.GetElapsedSeconds() > 3)
3290 m_restartPlayerTimer
.Stop();
3291 m_restartPlayerTimer
.Reset();
3296 void CApplication::Restart(bool bSamePosition
)
3298 // this function gets called when the user changes a setting (like noninterleaved)
3299 // and which means we gotta close & reopen the current playing file
3301 // first check if we're playing a file
3302 const auto appPlayer
= GetComponent
<CApplicationPlayer
>();
3303 if (!appPlayer
->IsPlayingVideo() && !appPlayer
->IsPlayingAudio())
3306 if (!appPlayer
->HasPlayer())
3309 // do we want to return to the current position in the file
3312 // no, then just reopen the file and start at the beginning
3313 PlayFile(*m_itemCurrentFile
, "", true);
3317 // else get current position
3318 double time
= GetTime();
3320 // get player state, needed for dvd's
3321 std::string state
= appPlayer
->GetPlayerState();
3323 // set the requested starttime
3324 m_itemCurrentFile
->SetStartOffset(CUtil::ConvertSecsToMilliSecs(time
));
3327 if (PlayFile(*m_itemCurrentFile
, "", true))
3328 appPlayer
->SetPlayerState(state
);
3331 const std::string
& CApplication::CurrentFile()
3333 return m_itemCurrentFile
->GetPath();
3336 std::shared_ptr
<CFileItem
> CApplication::CurrentFileItemPtr()
3338 return m_itemCurrentFile
;
3341 CFileItem
& CApplication::CurrentFileItem()
3343 return *m_itemCurrentFile
;
3346 const CFileItem
& CApplication::CurrentUnstackedItem()
3348 const auto stackHelper
= GetComponent
<CApplicationStackHelper
>();
3350 if (stackHelper
->IsPlayingISOStack() || stackHelper
->IsPlayingRegularStack())
3351 return stackHelper
->GetCurrentStackPartFileItem();
3353 return *m_itemCurrentFile
;
3356 // Returns the total time in seconds of the current media. Fractional
3357 // portions of a second are possible - but not necessarily supported by the
3358 // player class. This returns a double to be consistent with GetTime() and
3360 double CApplication::GetTotalTime() const
3364 const auto appPlayer
= GetComponent
<CApplicationPlayer
>();
3365 const auto stackHelper
= GetComponent
<CApplicationStackHelper
>();
3367 if (appPlayer
->IsPlaying())
3369 if (stackHelper
->IsPlayingRegularStack())
3370 rc
= stackHelper
->GetStackTotalTimeMs() * 0.001;
3372 rc
= appPlayer
->GetTotalTime() * 0.001;
3378 // Returns the current time in seconds of the currently playing media.
3379 // Fractional portions of a second are possible. This returns a double to
3380 // be consistent with GetTotalTime() and SeekTime().
3381 double CApplication::GetTime() const
3385 const auto appPlayer
= GetComponent
<CApplicationPlayer
>();
3386 const auto stackHelper
= GetComponent
<CApplicationStackHelper
>();
3388 if (appPlayer
->IsPlaying())
3390 if (stackHelper
->IsPlayingRegularStack())
3392 uint64_t startOfCurrentFile
= stackHelper
->GetCurrentStackPartStartTimeMs();
3393 rc
= (startOfCurrentFile
+ appPlayer
->GetTime()) * 0.001;
3396 rc
= appPlayer
->GetTime() * 0.001;
3402 // Sets the current position of the currently playing media to the specified
3403 // time in seconds. Fractional portions of a second are valid. The passed
3404 // time is the time offset from the beginning of the file as opposed to a
3405 // delta from the current position. This method accepts a double to be
3406 // consistent with GetTime() and GetTotalTime().
3407 void CApplication::SeekTime( double dTime
)
3409 const auto appPlayer
= GetComponent
<CApplicationPlayer
>();
3410 const auto stackHelper
= GetComponent
<CApplicationStackHelper
>();
3412 if (appPlayer
->IsPlaying() && (dTime
>= 0.0))
3414 if (!appPlayer
->CanSeek())
3417 if (stackHelper
->IsPlayingRegularStack())
3419 // find the item in the stack we are seeking to, and load the new
3420 // file if necessary, and calculate the correct seek within the new
3421 // file. Otherwise, just fall through to the usual routine if the
3422 // time is higher than our total time.
3423 int partNumberToPlay
=
3424 stackHelper
->GetStackPartNumberAtTimeMs(static_cast<uint64_t>(dTime
* 1000.0));
3425 uint64_t startOfNewFile
= stackHelper
->GetStackPartStartTimeMs(partNumberToPlay
);
3426 if (partNumberToPlay
== stackHelper
->GetCurrentPartNumber())
3427 appPlayer
->SeekTime(static_cast<uint64_t>(dTime
* 1000.0) - startOfNewFile
);
3429 { // seeking to a new file
3430 stackHelper
->SetStackPartCurrentFileItem(partNumberToPlay
);
3431 CFileItem
* item
= new CFileItem(stackHelper
->GetCurrentStackPartFileItem());
3432 item
->SetStartOffset(static_cast<uint64_t>(dTime
* 1000.0) - startOfNewFile
);
3433 // don't just call "PlayFile" here, as we are quite likely called from the
3434 // player thread, so we won't be able to delete ourselves.
3435 CServiceBroker::GetAppMessenger()->PostMsg(TMSG_MEDIA_PLAY
, 1, 0, static_cast<void*>(item
));
3439 // convert to milliseconds and perform seek
3440 appPlayer
->SeekTime(static_cast<int64_t>(dTime
* 1000.0));
3444 float CApplication::GetPercentage() const
3446 const auto appPlayer
= GetComponent
<CApplicationPlayer
>();
3447 const auto stackHelper
= GetComponent
<CApplicationStackHelper
>();
3449 if (appPlayer
->IsPlaying())
3451 if (appPlayer
->GetTotalTime() == 0 && appPlayer
->IsPlayingAudio() &&
3452 m_itemCurrentFile
->HasMusicInfoTag())
3454 const CMusicInfoTag
& tag
= *m_itemCurrentFile
->GetMusicInfoTag();
3455 if (tag
.GetDuration() > 0)
3456 return (float)(GetTime() / tag
.GetDuration() * 100);
3459 if (stackHelper
->IsPlayingRegularStack())
3461 double totalTime
= GetTotalTime();
3462 if (totalTime
> 0.0)
3463 return (float)(GetTime() / totalTime
* 100);
3466 return appPlayer
->GetPercentage();
3471 float CApplication::GetCachePercentage() const
3473 const auto appPlayer
= GetComponent
<CApplicationPlayer
>();
3474 const auto stackHelper
= GetComponent
<CApplicationStackHelper
>();
3476 if (appPlayer
->IsPlaying())
3478 // Note that the player returns a relative cache percentage and we want an absolute percentage
3479 if (stackHelper
->IsPlayingRegularStack())
3481 float stackedTotalTime
= (float) GetTotalTime();
3482 // We need to take into account the stack's total time vs. currently playing file's total time
3483 if (stackedTotalTime
> 0.0f
)
3484 return std::min(100.0f
,
3485 GetPercentage() + (appPlayer
->GetCachePercentage() *
3486 appPlayer
->GetTotalTime() * 0.001f
/ stackedTotalTime
));
3489 return std::min(100.0f
, appPlayer
->GetPercentage() + appPlayer
->GetCachePercentage());
3494 void CApplication::SeekPercentage(float percent
)
3496 const auto appPlayer
= GetComponent
<CApplicationPlayer
>();
3497 const auto stackHelper
= GetComponent
<CApplicationStackHelper
>();
3499 if (appPlayer
->IsPlaying() && (percent
>= 0.0f
))
3501 if (!appPlayer
->CanSeek())
3503 if (stackHelper
->IsPlayingRegularStack())
3504 SeekTime(static_cast<double>(percent
) * 0.01 * GetTotalTime());
3506 appPlayer
->SeekPercentage(percent
);
3510 std::string
CApplication::GetCurrentPlayer()
3512 const auto appPlayer
= GetComponent
<CApplicationPlayer
>();
3513 return appPlayer
->GetCurrentPlayer();
3516 void CApplication::UpdateLibraries()
3518 const std::shared_ptr
<CSettings
> settings
= CServiceBroker::GetSettingsComponent()->GetSettings();
3519 if (settings
->GetBool(CSettings::SETTING_VIDEOLIBRARY_UPDATEONSTARTUP
))
3521 CLog::LogF(LOGINFO
, "Starting video library startup scan");
3522 CVideoLibraryQueue::GetInstance().ScanLibrary(
3523 "", false, !settings
->GetBool(CSettings::SETTING_VIDEOLIBRARY_BACKGROUNDUPDATE
));
3526 if (settings
->GetBool(CSettings::SETTING_MUSICLIBRARY_UPDATEONSTARTUP
))
3528 CLog::LogF(LOGINFO
, "Starting music library startup scan");
3529 CMusicLibraryQueue::GetInstance().ScanLibrary(
3530 "", MUSIC_INFO::CMusicInfoScanner::SCAN_NORMAL
,
3531 !settings
->GetBool(CSettings::SETTING_MUSICLIBRARY_BACKGROUNDUPDATE
));
3535 void CApplication::UpdateCurrentPlayArt()
3537 const auto appPlayer
= GetComponent
<CApplicationPlayer
>();
3538 if (!appPlayer
->IsPlayingAudio())
3540 //Clear and reload the art for the currently playing item to show updated art on OSD
3541 m_itemCurrentFile
->ClearArt();
3542 CMusicThumbLoader loader
;
3543 loader
.LoadItem(m_itemCurrentFile
.get());
3544 // Mirror changes to GUI item
3545 CServiceBroker::GetGUI()->GetInfoManager().SetCurrentItem(*m_itemCurrentFile
);
3548 bool CApplication::ProcessAndStartPlaylist(const std::string
& strPlayList
,
3549 PLAYLIST::CPlayList
& playlist
,
3550 PLAYLIST::Id playlistId
,
3553 CLog::Log(LOGDEBUG
, "CApplication::ProcessAndStartPlaylist({}, {})", strPlayList
,
3554 static_cast<int>(playlistId
));
3556 // initial exit conditions
3557 // no songs in playlist just return
3558 if (playlist
.size() == 0)
3562 if (playlistId
== PLAYLIST::Id::TYPE_NONE
|| playlistId
== PLAYLIST::Id::TYPE_PICTURE
)
3565 // setup correct playlist
3566 CServiceBroker::GetPlaylistPlayer().ClearPlaylist(playlistId
);
3568 // if the playlist contains an internet stream, this file will be used
3569 // to generate a thumbnail for musicplayer.cover
3570 m_strPlayListFile
= strPlayList
;
3572 // add the items to the playlist player
3573 CServiceBroker::GetPlaylistPlayer().Add(playlistId
, playlist
);
3575 // if we have a playlist
3576 if (CServiceBroker::GetPlaylistPlayer().GetPlaylist(playlistId
).size())
3579 CServiceBroker::GetPlaylistPlayer().SetCurrentPlaylist(playlistId
);
3580 CServiceBroker::GetPlaylistPlayer().Reset();
3581 CServiceBroker::GetPlaylistPlayer().Play(track
, "");
3587 bool CApplication::GetRenderGUI() const
3589 return GetComponent
<CApplicationPowerHandling
>()->GetRenderGUI();
3592 bool CApplication::SetLanguage(const std::string
&strLanguage
)
3594 // nothing to be done if the language hasn't changed
3595 if (strLanguage
== CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(CSettings::SETTING_LOCALE_LANGUAGE
))
3598 return CServiceBroker::GetSettingsComponent()->GetSettings()->SetString(CSettings::SETTING_LOCALE_LANGUAGE
, strLanguage
);
3601 bool CApplication::LoadLanguage(bool reload
)
3603 // load the configured language
3604 if (!g_langInfo
.SetLanguage("", reload
))
3607 // set the proper audio and subtitle languages
3608 const std::shared_ptr
<CSettings
> settings
= CServiceBroker::GetSettingsComponent()->GetSettings();
3609 g_langInfo
.SetAudioLanguage(settings
->GetString(CSettings::SETTING_LOCALE_AUDIOLANGUAGE
));
3610 g_langInfo
.SetSubtitleLanguage(settings
->GetString(CSettings::SETTING_LOCALE_SUBTITLELANGUAGE
));
3615 void CApplication::SetLoggingIn(bool switchingProfiles
)
3617 // don't save skin settings on unloading when logging into another profile
3618 // because in that case we have already loaded the new profile and
3619 // would therefore write the previous skin's settings into the new profile
3620 // instead of into the previous one
3621 GetComponent
<CApplicationSkinHandling
>()->m_saveSkinOnUnloading
= !switchingProfiles
;
3624 void CApplication::PrintStartupLog()
3626 CLog::Log(LOGINFO
, "-----------------------------------------------------------------------");
3627 CLog::Log(LOGINFO
, "Starting {} ({}). Platform: {} {} {}-bit", CSysInfo::GetAppName(),
3628 CSysInfo::GetVersion(), g_sysinfo
.GetBuildTargetPlatformName(),
3629 g_sysinfo
.GetBuildTargetCpuFamily(), g_sysinfo
.GetXbmcBitness());
3631 std::string buildType
;
3633 buildType
= "Debug";
3634 #elif defined(NDEBUG)
3635 buildType
= "Release";
3637 buildType
= "Unknown";
3640 CLog::Log(LOGINFO
, "Using {} {} x{}", buildType
, CSysInfo::GetAppName(),
3641 g_sysinfo
.GetXbmcBitness());
3642 CLog::Log(LOGINFO
, "{} compiled {} by {} for {} {} {}-bit {} ({})", CSysInfo::GetAppName(),
3643 CSysInfo::GetBuildDate(), g_sysinfo
.GetUsedCompilerNameAndVer(),
3644 g_sysinfo
.GetBuildTargetPlatformName(), g_sysinfo
.GetBuildTargetCpuFamily(),
3645 g_sysinfo
.GetXbmcBitness(), g_sysinfo
.GetBuildTargetPlatformVersionDecoded(),
3646 g_sysinfo
.GetBuildTargetPlatformVersion());
3648 std::string
deviceModel(g_sysinfo
.GetModelName());
3649 if (!g_sysinfo
.GetManufacturerName().empty())
3650 deviceModel
= g_sysinfo
.GetManufacturerName() + " " +
3651 (deviceModel
.empty() ? std::string("device") : deviceModel
);
3652 if (!deviceModel
.empty())
3653 CLog::Log(LOGINFO
, "Running on {} with {}, kernel: {} {} {}-bit version {}", deviceModel
,
3654 g_sysinfo
.GetOsPrettyNameWithVersion(), g_sysinfo
.GetKernelName(),
3655 g_sysinfo
.GetKernelCpuFamily(), g_sysinfo
.GetKernelBitness(),
3656 g_sysinfo
.GetKernelVersionFull());
3658 CLog::Log(LOGINFO
, "Running on {}, kernel: {} {} {}-bit version {}",
3659 g_sysinfo
.GetOsPrettyNameWithVersion(), g_sysinfo
.GetKernelName(),
3660 g_sysinfo
.GetKernelCpuFamily(), g_sysinfo
.GetKernelBitness(),
3661 g_sysinfo
.GetKernelVersionFull());
3663 CLog::Log(LOGINFO
, "FFmpeg version/source: {}", av_version_info());
3665 std::string
cpuModel(CServiceBroker::GetCPUInfo()->GetCPUModel());
3666 if (!cpuModel
.empty())
3668 CLog::Log(LOGINFO
, "Host CPU: {}, {} core{} available", cpuModel
,
3669 CServiceBroker::GetCPUInfo()->GetCPUCount(),
3670 (CServiceBroker::GetCPUInfo()->GetCPUCount() == 1) ? "" : "s");
3673 CLog::Log(LOGINFO
, "{} CPU core{} available", CServiceBroker::GetCPUInfo()->GetCPUCount(),
3674 (CServiceBroker::GetCPUInfo()->GetCPUCount() == 1) ? "" : "s");
3676 // Any system info logging that is unique to a platform
3677 m_ServiceManager
->GetPlatform().PlatformSyslog();
3679 #if defined(__arm__) || defined(__aarch64__)
3680 CLog::Log(LOGINFO
, "ARM Features: Neon {}",
3681 (CServiceBroker::GetCPUInfo()->GetCPUFeatures() & CPU_FEATURE_NEON
) ? "enabled"
3684 CSpecialProtocol::LogPaths();
3686 #ifdef HAS_WEB_SERVER
3687 CLog::Log(LOGINFO
, "Webserver extra whitelist paths: {}",
3688 StringUtils::Join(CCompileInfo::GetWebserverExtraWhitelist(), ", "));
3691 // Check, whether libkodi.so was reused (happens on Android, where the system does not unload
3692 // the lib on activity end, but keeps it loaded (as long as there is enough memory) and reuses
3693 // it on next activity start.
3694 static bool firstRun
= true;
3696 CLog::Log(LOGINFO
, "The executable running is: {}{}", CUtil::ResolveExecutablePath(),
3697 firstRun
? "" : " [reused]");
3701 std::string
hostname("[unknown]");
3702 m_ServiceManager
->GetNetwork().GetHostName(hostname
);
3703 CLog::Log(LOGINFO
, "Local hostname: {}", hostname
);
3704 std::string lowerAppName
= CCompileInfo::GetAppName();
3705 StringUtils::ToLower(lowerAppName
);
3706 CLog::Log(LOGINFO
, "Log File is located: {}.log",
3707 CSpecialProtocol::TranslatePath("special://logpath/" + lowerAppName
));
3708 CRegExp::LogCheckUtf8Support();
3709 CLog::Log(LOGINFO
, "-----------------------------------------------------------------------");
3712 void CApplication::CloseNetworkShares()
3714 CLog::Log(LOGDEBUG
,"CApplication::CloseNetworkShares: Closing all network shares");
3716 #if defined(HAS_FILESYSTEM_SMB) && !defined(TARGET_WINDOWS)
3720 #ifdef HAS_FILESYSTEM_NFS
3721 gNfsConnection
.Deinit();
3724 for (const auto& vfsAddon
: CServiceBroker::GetVFSAddonCache().GetAddonInstances())
3725 vfsAddon
->DisconnectAll();