[Windows] Remove redundant DirectSound error codes
[xbmc.git] / xbmc / application / Application.cpp
blob01f1c39ad0febf96b6cb17e59e9c93b8ee54d96a
1 /*
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.
7 */
9 #include "Application.h"
11 #include "Autorun.h"
12 #include "CompileInfo.h"
13 #include "DatabaseManager.h"
14 #include "FileItem.h"
15 #include "GUIInfoManager.h"
16 #include "GUILargeTextureManager.h"
17 #include "GUIPassword.h"
18 #include "GUIUserMessages.h"
19 #include "HDRStatus.h"
20 #include "LangInfo.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"
28 #include "URL.h"
29 #include "Util.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"
69 #endif
70 #include "filesystem/PluginDirectory.h"
71 #include "filesystem/SpecialProtocol.h"
72 #ifdef HAS_UPNP
73 #include "filesystem/UPnPDirectory.h"
74 #endif
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"
93 #ifdef HAS_PYTHON
94 #include "interfaces/python/XBPython.h"
95 #endif
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"
108 #ifdef HAS_UPNP
109 #include "network/upnp/UPnP.h"
110 #endif
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"
154 #endif
155 #include "windowing/WinSystem.h"
156 #include "windowing/WindowSystemFactory.h"
158 #if defined(TARGET_ANDROID)
159 #include "platform/android/activity/XBMCApp.h"
160 #endif
161 #ifdef TARGET_DARWIN
162 #include "platform/darwin/DarwinUtils.h"
163 #endif
164 #ifdef TARGET_DARWIN_OSX
165 #ifdef HAS_XBMCHELPER
166 #include "platform/darwin/osx/XBMCHelper.h"
167 #endif
168 #endif
169 #ifdef TARGET_POSIX
170 #include "platform/posix/PlatformPosix.h"
171 #include "platform/posix/XHandle.h"
172 #endif
173 #if defined(TARGET_POSIX) && defined(HAS_FILESYSTEM_SMB)
174 #include "platform/posix/filesystem/SMBFile.h"
175 #endif
176 #ifndef TARGET_POSIX
177 #include "platform/win32/threads/Win32Exception.h"
178 #endif
180 #include <cmath>
181 #include <memory>
182 #include <mutex>
184 #include <tinyxml.h>
186 //TODO: XInitThreads
187 #ifdef HAVE_X11
188 #include <X11/Xlib.h>
189 #endif
190 #ifdef HAS_OPTICAL_DRIVE
191 #include <cdio/logging.h>
192 #endif
194 using namespace ADDON;
195 using namespace XFILE;
196 #ifdef HAS_OPTICAL_DRIVE
197 using namespace MEDIA_DETECT;
198 #endif
199 using namespace MUSIC_INFO;
200 using namespace EVENTSERVER;
201 using namespace JSONRPC;
202 using namespace PVR;
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()),
221 #endif
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);
229 #ifdef HAVE_X11
230 XInitThreads();
231 #endif
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()
258 m_bStop = false;
260 RegisterSettings();
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())
282 return false;
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())
303 #endif
305 CDirectory::Create("special://xbmc/addons");
308 // Init our DllLoaders emu env
309 init_emu_environ();
311 PrintStartupLog();
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())
321 return false;
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;
326 CLog::Log(LOGINFO,
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()))
356 return false;
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");
369 return false;
372 // set user defined CA trust bundle
373 std::string caCert =
374 CSpecialProtocol::TranslatePath(settingsComponent->GetAdvancedSettings()->m_caTrustFile);
375 if (!caCert.empty())
377 if (XFILE::CFile::Exists(caCert))
379 CEnvironment::setenv("SSL_CERT_FILE", caCert, 1);
380 CLog::Log(LOGDEBUG, "CApplication::Create - SSL_CERT_FILE: {}", caCert);
382 else
384 CLog::Log(LOGDEBUG, "CApplication::Create - Error reading SSL_CERT_FILE: {} -> ignored",
385 caCert);
389 CUtil::InitRandomSeed();
391 m_lastRenderTime = std::chrono::steady_clock::now();
392 return true;
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__,
412 windowSystem);
413 m_pWinSystem = KODI::WINDOWING::CWindowSystemFactory::CreateWindowSystem(windowSystem);
415 if (!m_pWinSystem)
416 continue;
418 if (!windowing.empty() && windowing != windowSystem)
419 continue;
421 CServiceBroker::RegisterWinSystem(m_pWinSystem.get());
423 if (!m_pWinSystem->InitWindowSystem())
425 CLog::Log(LOGDEBUG, "CApplication::{} - unable to init {} windowing system", __FUNCTION__,
426 windowSystem);
427 m_pWinSystem->DestroyWindowSystem();
428 m_pWinSystem.reset();
429 CServiceBroker::UnregisterWinSystem();
430 continue;
432 else
434 CLog::Log(LOGINFO, "CApplication::{} - using the {} windowing system", __FUNCTION__,
435 windowSystem);
436 break;
440 if (!m_pWinSystem)
442 CLog::Log(LOGFATAL, "CApplication::{} - unable to init windowing system", __FUNCTION__);
443 CServiceBroker::UnregisterWinSystem();
444 return false;
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);
457 sav_res = true;
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);
468 sav_res = true;
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);
476 sav_res = true;
478 if (!InitWindow())
480 return false;
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("");
491 else
493 // If OS has no screen saver, use Kodi one by default
494 screensaverModeSetting->SetDefault("screensaver.xbmc.builtin.dim");
497 if (sav_res)
498 CDisplaySettings::GetInstance().SetCurrentResolution(RES_DESKTOP, true);
500 m_pGUI = std::make_unique<CGUIComponent>();
501 m_pGUI->Init();
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())
509 return false;
511 RESOLUTION_INFO info = CServiceBroker::GetWinSystem()->GetGfxContext().GetResInfo();
512 CLog::Log(LOGINFO, "GUI format {}x{}, Display {}", info.iWidth, info.iHeight, info.strMode);
514 return true;
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");
527 return false;
530 if (!CServiceBroker::GetRenderSystem()->InitRenderSystem())
532 CLog::Log(LOGFATAL, "CApplication::Create: Unable to init rendering system");
533 return false;
535 // set GUI res and force the clear of the screen
536 CServiceBroker::GetWinSystem()->GetGfxContext().SetVideoResolution(res, false);
537 return true;
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;
555 #endif
557 // load the language and its translated strings
558 if (!LoadLanguage(false))
559 return 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();
576 CEvent event(true);
577 CServiceBroker::GetJobManager()->Submit([&databaseManager, &event]() {
578 databaseManager.Initialize();
579 event.Set();
582 std::string localizedStr = g_localizeStrings.Get(24150);
583 int iDots = 1;
584 while (!event.Wait(1000ms))
586 if (databaseManager.IsUpgrading())
587 CServiceBroker::GetRenderSystem()->ShowSplash(std::string(iDots, ' ') + localizedStr + std::string(iDots, '.'));
589 if (iDots == 3)
590 iDots = 1;
591 else
592 ++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
598 event.Reset();
599 GUIFontManager& guiFontManager = g_fontManager;
600 CServiceBroker::GetJobManager()->Submit([&guiFontManager, &event]() {
601 guiFontManager.Initialize();
602 event.Set();
604 localizedStr = g_localizeStrings.Get(39175);
605 iDots = 1;
606 while (!event.Wait(1000ms))
608 if (g_fontManager.IsUpdating())
609 CServiceBroker::GetRenderSystem()->ShowSplash(std::string(iDots, ' ') + localizedStr +
610 std::string(iDots, '.'));
612 if (iDots == 3)
613 iDots = 1;
614 else
615 ++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;
635 event.Reset();
637 // Addon migration
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();
648 event.Set();
650 CJob::PRIORITY_DEDICATED);
651 localizedStr = g_localizeStrings.Get(24151);
652 iDots = 1;
653 while (!event.Wait(1000ms))
655 CServiceBroker::GetRenderSystem()->ShowSplash(std::string(iDots, ' ') + localizedStr +
656 std::string(iDots, '.'));
657 if (iDots == 3)
658 iDots = 1;
659 else
660 ++iDots;
662 m_incompatibleAddons = incompatibleAddons;
664 else
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);
677 if (!setting)
679 CLog::Log(LOGFATAL, "Failed to load setting for: {}", CSettings::SETTING_LOOKANDFEEL_SKIN);
680 return false;
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);
694 return false;
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);
715 else
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");
744 g_sysinfo.Refresh();
746 CLog::Log(LOGINFO, "removing tempfiles");
747 CUtil::RemoveTempFiles();
749 if (!profileManager->UsingLoginScreen())
751 UpdateLibraries();
752 SetLoggingIn(false);
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);
781 return true;
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
789 return !m_bStop;
792 void CApplication::Render()
794 // do not render if we are stopped or in background
795 if (m_bStop)
796 return;
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())
813 return;
815 // render gui layer
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);
830 else
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()
847 // isn't called)
848 CGUIInfoManager& infoMgr = CServiceBroker::GetGUI()->GetInfoManager();
849 infoMgr.ResetCache();
850 infoMgr.GetInfoProviders().GetGUIControlsInfoProvider().ResetContainerMovingCache();
852 if (hasRendered)
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();
869 if (gui)
871 if (gui->GetWindowManager().SwitchToFullScreen())
873 GetComponent<CApplicationPowerHandling>()->m_navigationTimer.StartZero();
874 return true;
879 const auto appPlayer = GetComponent<CApplicationPlayer>();
881 if (action.GetID() == ACTION_TOGGLE_FULLSCREEN)
883 CServiceBroker::GetWinSystem()->GetGfxContext().ToggleFullScreen();
884 appPlayer->TriggerUpdateResolution();
885 return true;
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));
908 else
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) )
916 // in normal case
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();
921 return true;
925 // handle extra global presses
927 // notify action listeners
928 if (GetComponent<CApplicationActionListeners>()->NotifyActionListeners(action))
929 return true;
931 // screenshot : take a screenshot :)
932 if (action.GetID() == ACTION_TAKE_SCREENSHOT)
934 CScreenShot::TakeScreenshot();
935 return true;
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())
942 return true;
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));
956 return true;
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())
963 return true;
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)
970 vs.m_ToneMapMethod =
971 static_cast<ETONEMAPMETHOD>(static_cast<int>(VS_TONEMAPMETHOD_OFF) + 1);
973 appPlayer->SetVideoSettings(vs);
975 int code = 0;
976 switch (vs.m_ToneMapMethod)
978 case VS_TONEMAPMETHOD_REINHARD:
979 code = 36555;
980 break;
981 case VS_TONEMAPMETHOD_ACES:
982 code = 36557;
983 break;
984 case VS_TONEMAPMETHOD_HABLE:
985 code = 36558;
986 break;
987 default:
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);
993 return true;
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();
1004 return true;
1007 // reload keymaps
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();
1015 return true;
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
1022 return true;
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);
1037 return true;
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);
1048 needsUpdate = true;
1050 else if (userrating < 10 && action.GetID() == ACTION_INCREASE_RATING)
1052 m_itemCurrentFile->GetMusicInfoTag()->SetUserrating(userrating + 1);
1053 needsUpdate = true;
1055 if (needsUpdate)
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);
1068 return true;
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;
1078 needsUpdate = true;
1080 else if (rating < 10 && action.GetID() == ACTION_INCREASE_RATING)
1082 m_itemCurrentFile->GetVideoInfoTag()->m_iUserRating = rating + 1;
1083 needsUpdate = true;
1085 if (needsUpdate)
1087 // Mirror changes to GUI item
1088 CServiceBroker::GetGUI()->GetInfoManager().SetCurrentItem(*m_itemCurrentFile);
1090 CVideoDatabase db;
1091 if (db.Open())
1093 db.SetVideoUserRating(m_itemCurrentFile->GetVideoInfoTag()->m_iDbId,
1094 m_itemCurrentFile->GetVideoInfoTag()->m_iUserRating,
1095 m_itemCurrentFile->GetVideoInfoTag()->m_type);
1096 db.Close();
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);
1102 return true;
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))
1111 return true;
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;
1135 break;
1136 default:
1137 break;
1140 else if (action.GetID() == ACTION_STOP)
1141 bNotifyPlayer = true;
1143 if (bNotifyPlayer)
1145 if (appPlayer->OnAction(action))
1146 return true;
1149 // stop : stops playing current audio song
1150 if (action.GetID() == ACTION_STOP)
1152 StopPlaying();
1153 return true;
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())
1160 SeekTime(0);
1161 appPlayer->SetPlaySpeed(1);
1162 return true;
1165 // forward action to graphic context and see if it can handle it
1166 if (CServiceBroker::GetGUI()->GetStereoscopicsManager().OnAction(action))
1167 return true;
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);
1175 return true;
1178 // pause : toggle pause action
1179 if (action.GetID() == ACTION_PAUSE)
1181 appPlayer->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();
1187 if (gui)
1188 gui->GetAudioManager().Enable(appPlayer->IsPaused());
1189 return true;
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);
1200 return true;
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
1209 playSpeed *= -2;
1210 else if (action.GetID() == ACTION_PLAYER_REWIND && playSpeed > 1) //goes down a notch if you're FFing
1211 playSpeed /= 2;
1212 else if (action.GetID() == ACTION_PLAYER_FORWARD && playSpeed < 1) //goes up a notch if you're RWing
1213 playSpeed /= 2;
1214 else
1215 playSpeed *= 2;
1217 if (action.GetID() == ACTION_PLAYER_FORWARD && playSpeed == -1) //sets iSpeed back to 1 if -1 (didn't plan for a -1)
1218 playSpeed = 1;
1219 if (playSpeed > 32 || playSpeed < -32)
1220 playSpeed = 1;
1222 appPlayer->SetPlaySpeed(playSpeed);
1223 return true;
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)
1235 iSpeed = -iSpeed;
1236 appPlayer->SetPlaySpeed(static_cast<float>(iSpeed));
1237 if (iSpeed == 1)
1238 CLog::Log(LOGDEBUG,"Resetting playspeed");
1239 return true;
1241 else if (action.GetID() == ACTION_PLAYER_INCREASE_TEMPO)
1243 CPlayerUtils::AdvanceTempoStep(appPlayer, TempoStepChange::INCREASE);
1244 return true;
1246 else if (action.GetID() == ACTION_PLAYER_DECREASE_TEMPO)
1248 CPlayerUtils::AdvanceTempoStep(appPlayer, TempoStepChange::DECREASE);
1249 return true;
1252 // allow play to unpause
1253 else
1255 if (action.GetID() == ACTION_PLAYER_PLAY)
1257 // unpause, and set the playspeed back to normal
1258 appPlayer->Pause();
1260 CGUIComponent *gui = CServiceBroker::GetGUI();
1261 if (gui)
1262 gui->GetAudioManager().Enable(appPlayer->IsPaused());
1264 appPlayer->SetPlaySpeed(1);
1265 return true;
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);
1287 else
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))
1300 return true;
1302 if (action.GetID() == ACTION_MUTE)
1304 const auto appVolume = GetComponent<CApplicationVolumeHandling>();
1305 appVolume->ToggleMute();
1306 appVolume->ShowVolumeBar(&action);
1307 return true;
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);
1321 return true;
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);
1334 // sanity check
1335 if (volumesteps == 0)
1336 volumesteps = 90;
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();
1343 #else
1344 float step = (CApplicationVolumeHandling::VOLUME_MAXIMUM -
1345 CApplicationVolumeHandling::VOLUME_MINIMUM) /
1346 volumesteps;
1348 if (action.GetRepeat())
1349 step *= action.GetRepeat() * 50; // 50 fps
1350 #endif
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;
1355 else
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);
1362 return true;
1365 if (action.GetID() == ACTION_GUIPROFILE_BEGIN)
1367 CGUIControlProfiler::Instance().SetOutputFile(CSpecialProtocol::TranslatePath("special://home/guiprofiler.xml"));
1368 CGUIControlProfiler::Instance().Start();
1369 return true;
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);
1385 return true;
1387 return false;
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
1402 else
1403 return; // no shutdown
1406 const auto appPlayer = GetComponent<CApplicationPlayer>();
1408 switch (msg)
1410 case TMSG_POWERDOWN:
1411 if (Stop(EXITCODE_POWERDOWN))
1412 CServiceBroker::GetPowerManager().Powerdown();
1413 break;
1415 case TMSG_QUIT:
1416 Stop(EXITCODE_QUIT);
1417 break;
1419 case TMSG_SHUTDOWN:
1420 GetComponent<CApplicationPowerHandling>()->HandleShutdownMessage();
1421 break;
1423 case TMSG_RENDERER_FLUSH:
1424 appPlayer->FlushRenderer();
1425 break;
1427 case TMSG_HIBERNATE:
1428 CServiceBroker::GetPowerManager().Hibernate();
1429 break;
1431 case TMSG_SUSPEND:
1432 CServiceBroker::GetPowerManager().Suspend();
1433 break;
1435 case TMSG_RESTART:
1436 case TMSG_RESET:
1437 if (Stop(EXITCODE_REBOOT))
1438 CServiceBroker::GetPowerManager().Reboot();
1439 break;
1441 case TMSG_RESTARTAPP:
1442 #if defined(TARGET_WINDOWS) || defined(TARGET_LINUX)
1443 Stop(EXITCODE_RESTARTAPP);
1444 #endif
1445 break;
1447 case TMSG_INHIBITIDLESHUTDOWN:
1448 GetComponent<CApplicationPowerHandling>()->InhibitIdleShutdown(pMsg->param1 != 0);
1449 break;
1451 case TMSG_INHIBITSCREENSAVER:
1452 GetComponent<CApplicationPowerHandling>()->InhibitScreenSaver(pMsg->param1 != 0);
1453 break;
1455 case TMSG_ACTIVATESCREENSAVER:
1456 GetComponent<CApplicationPowerHandling>()->ActivateScreenSaver();
1457 break;
1459 case TMSG_RESETSCREENSAVER:
1460 GetComponent<CApplicationPowerHandling>()->m_bResetScreenSaver = true;
1461 break;
1463 case TMSG_VOLUME_SHOW:
1465 CAction action(pMsg->param1);
1466 GetComponent<CApplicationVolumeHandling>()->ShowVolumeBar(&action);
1468 break;
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);
1475 break;
1477 case TMSG_DISPLAY_DESTROY:
1478 *static_cast<bool*>(pMsg->lpVoid) = CServiceBroker::GetWinSystem()->DestroyWindow();
1479 GetComponent<CApplicationPowerHandling>()->SetRenderGUI(false);
1480 break;
1481 #endif
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] : "");
1497 #endif
1499 break;
1501 case TMSG_NETWORKMESSAGE:
1502 m_ServiceManager->GetNetwork().NetworkMessage(static_cast<CNetworkBase::EMESSAGE>(pMsg->param1),
1503 pMsg->param2);
1504 break;
1506 case TMSG_SETLANGUAGE:
1507 SetLanguage(pMsg->strParam);
1508 break;
1511 case TMSG_SWITCHTOFULLSCREEN:
1513 CGUIComponent* gui = CServiceBroker::GetGUI();
1514 if (gui)
1515 gui->GetWindowManager().SwitchToFullScreen(true);
1516 break;
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();
1527 break;
1529 case TMSG_SETVIDEORESOLUTION:
1530 CServiceBroker::GetWinSystem()->GetGfxContext().SetVideoResolution(static_cast<RESOLUTION>(pMsg->param1), pMsg->param2 == 1);
1531 break;
1533 case TMSG_TOGGLEFULLSCREEN:
1534 CServiceBroker::GetWinSystem()->GetGfxContext().ToggleFullScreen();
1535 appPlayer->TriggerUpdateResolution();
1536 break;
1538 case TMSG_MOVETOSCREEN:
1539 CServiceBroker::GetWinSystem()->MoveToScreen(static_cast<int>(pMsg->param1));
1540 break;
1542 case TMSG_MINIMIZE:
1543 CServiceBroker::GetWinSystem()->Minimize();
1544 break;
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
1549 IAE *audioengine;
1550 audioengine = CServiceBroker::GetActiveAE();
1551 if (audioengine)
1553 if (!audioengine->Suspend())
1555 CLog::Log(LOGINFO, "{}: Failed to suspend AudioEngine before launching external program",
1556 __FUNCTION__);
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));
1565 #endif
1566 // Resume AE processing of XBMC native audio
1567 if (audioengine)
1569 if (!audioengine->Resume())
1571 CLog::Log(LOGFATAL, "{}: Failed to restart AudioEngine after return from external player",
1572 __FUNCTION__);
1575 break;
1577 case TMSG_EXECUTE_SCRIPT:
1578 CScriptInvocationManager::GetInstance().ExecuteAsync(pMsg->strParam);
1579 break;
1581 case TMSG_EXECUTE_BUILT_IN:
1582 CBuiltins::GetInstance().Execute(pMsg->strParam);
1583 break;
1585 case TMSG_PICTURE_SHOW:
1587 CSlideShowDelegator& slideShow = CServiceBroker::GetSlideShowDelegator();
1589 // stop playing file
1590 if (appPlayer->IsPlayingVideo())
1591 StopPlaying();
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;
1605 CURL pathToUrl;
1606 if (URIUtils::IsZIP(pMsg->strParam))
1607 pathToUrl = URIUtils::CreateArchivePath("zip", CURL(pMsg->strParam), "");
1608 else
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)
1614 slideShow.Reset();
1615 for (int i = 0; i<items.Size(); ++i)
1617 slideShow.Add(items[i].get());
1619 slideShow.Select(items[0]->GetPath());
1622 else
1624 CFileItem item(pMsg->strParam, false);
1625 slideShow.Reset();
1626 slideShow.Add(&item);
1627 slideShow.Select(pMsg->strParam);
1630 break;
1632 case TMSG_PICTURE_SLIDESHOW:
1634 CSlideShowDelegator& slideShow = CServiceBroker::GetSlideShowDelegator();
1636 if (appPlayer->IsPlayingVideo())
1637 StopPlaying();
1639 slideShow.Reset();
1641 CFileItemList items;
1642 std::string strPath = pMsg->strParam;
1643 std::string extensions = CServiceBroker::GetFileExtensionProvider().GetPictureExtensions();
1644 if (pMsg->param1)
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();
1662 else
1663 CServiceBroker::GetGUI()->GetWindowManager().ActivateWindow(WINDOW_SLIDESHOW);
1667 break;
1669 case TMSG_LOADPROFILE:
1671 const int profile = pMsg->param1;
1672 if (profile >= 0)
1673 CServiceBroker::GetSettingsComponent()->GetProfileManager()->LoadProfile(static_cast<unsigned int>(profile));
1676 break;
1678 case TMSG_EVENT:
1680 if (pMsg->lpVoid)
1682 XBMC_Event* event = static_cast<XBMC_Event*>(pMsg->lpVoid);
1683 m_pAppPort->OnEvent(*event);
1684 delete event;
1687 break;
1689 case TMSG_UPDATE_PLAYER_ITEM:
1691 std::unique_ptr<CFileItem> item{static_cast<CFileItem*>(pMsg->lpVoid)};
1692 if (item)
1694 m_itemCurrentFile->UpdateInfo(*item);
1695 CServiceBroker::GetGUI()->GetInfoManager().UpdateCurrentItem(*m_itemCurrentFile);
1698 break;
1700 case TMSG_SET_VOLUME:
1702 const float volumedB = static_cast<float>(pMsg->param3);
1703 GetComponent<CApplicationVolumeHandling>()->SetVolume(volumedB);
1705 break;
1707 case TMSG_SET_MUTE:
1709 GetComponent<CApplicationVolumeHandling>()->SetMute(pMsg->param3 == 1 ? true : false);
1711 break;
1713 default:
1714 CLog::Log(LOGERROR, "{}: Unhandled threadmessage sent, {}", __FUNCTION__, msg);
1715 break;
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();
1738 if (processEvents)
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)
1745 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())
1756 toast->Open();
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())
1781 max_sleep = 80;
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
1796 int fps = 0;
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);
1816 if (!m_bStop)
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();
1834 if (m_pGUI)
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);
1854 // Run the app
1855 while (!m_bStop)
1857 // Animate and render a frame
1859 lastFrameTime = std::chrono::steady_clock::now();
1860 Process();
1862 bool renderGUI = GetComponent<CApplicationPowerHandling>()->GetRenderGUI();
1863 if (!m_bStop)
1865 FrameMove(true, renderGUI);
1868 if (renderGUI && !m_bStop)
1870 Render();
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()));
1881 Cleanup();
1883 CLog::Log(LOGINFO, "Exiting the application...");
1884 return m_ExitCode;
1887 bool CApplication::Cleanup()
1891 ResetCurrentItem();
1892 StopPlaying();
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
1906 // unloading
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();
1914 if (renderSystem)
1915 renderSystem->DestroyRenderSystem();
1917 CWinSystemBase *winSystem = CServiceBroker::GetWinSystem();
1918 if (winSystem)
1919 winSystem->DestroyWindow();
1921 if (m_pGUI)
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();
1944 #ifdef TARGET_POSIX
1945 CXHandle::DumpObjectTracker();
1947 #ifdef HAS_OPTICAL_DRIVE
1948 CLibcdio::ReleaseInstance();
1949 #endif
1950 #endif
1951 #ifdef _CRTDBG_MAP_ALLOC
1952 _CrtDumpMemoryLeaks();
1953 while(1); // execution ends
1954 #endif
1956 if (m_pGUI)
1958 m_pGUI->Deinit();
1959 m_pGUI.reset();
1962 if (winSystem)
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;
1992 return true;
1994 catch (...)
1996 CLog::Log(LOGERROR, "Exception in CApplication::Cleanup()");
1997 return false;
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))
2007 return false;
2008 #endif
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");
2028 break;
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();
2056 else
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();
2066 m_bStop = true;
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);
2088 #ifdef HAS_ZEROCONF
2089 if(CZeroconfBrowser::IsInstantiated())
2091 CLog::Log(LOGINFO, "Stopping zeroconf browser");
2092 CZeroconfBrowser::GetInstance()->Stop();
2093 CZeroconfBrowser::ReleaseInstance();
2095 #endif
2097 for (const auto& vfsAddon : CServiceBroker::GetVFSAddonCache().GetAddonInstances())
2098 vfsAddon->DisconnectAll();
2100 #if defined(TARGET_POSIX) && defined(HAS_FILESYSTEM_SMB)
2101 smb.Deinit();
2102 #endif
2104 #if defined(TARGET_DARWIN_OSX) and defined(HAS_XBMCHELPER)
2105 if (XBMCHelper::GetInstance().IsAlwaysOn() == false)
2106 XBMCHelper::GetInstance().Stop();
2107 #endif
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();
2121 if (gui)
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");
2131 catch (...)
2133 CLog::Log(LOGERROR, "Exception in CApplication::Stop()");
2134 success = false;
2137 cleanup_emu_environ();
2139 KODI::TIME::Sleep(200ms);
2141 return success;
2144 namespace
2146 class CCreateAndLoadPlayList : public IRunnable
2148 public:
2149 CCreateAndLoadPlayList(CFileItem& item, std::unique_ptr<PLAYLIST::CPlayList>& playlist)
2150 : m_item(item), m_playlist(playlist)
2154 void Run() override
2156 const std::unique_ptr<PLAYLIST::CPlayList> playlist(PLAYLIST::CPlayListFactory::Create(m_item));
2157 if (playlist)
2159 if (playlist->Load(m_item.GetPath()))
2160 *m_playlist = *playlist;
2164 private:
2165 CFileItem& m_item;
2166 std::unique_ptr<PLAYLIST::CPlayList>& m_playlist;
2168 } // namespace
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))
2174 return false;
2176 if (PLAYLIST::IsSmartPlayList(item))
2178 CFileItemList items;
2179 CUtil::GetRecursiveListing(item.GetPath(), items, "", DIR_FLAG_NO_FILE_DIRS);
2180 if (items.Size())
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);
2207 if (dlgCache)
2209 dlgCache->Close();
2210 if (dlgCache->IsCanceled())
2211 cancelled = true;
2214 if (cancelled)
2215 return true;
2217 if (playlist)
2220 if (playlistId != PLAYLIST::Id::TYPE_NONE)
2222 int track=0;
2223 if (item.HasProperty("playlist_starting_track"))
2224 track = (int)item.GetProperty("playlist_starting_track").asInteger();
2225 return ProcessAndStartPlaylist(item.GetPath(), *playlist, playlistId, track);
2227 else
2229 CLog::Log(LOGWARNING,
2230 "CApplication::PlayMedia called to play a playlist {} but no idea which playlist "
2231 "to use, playing first item",
2232 item.GetPath());
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")
2246 AddonPtr addon;
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);
2259 // PlayStack()
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
2264 // substantially.
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))
2270 return false;
2272 std::optional<int64_t> startoffset = stackHelper->InitializeStackStartPartAndOffset(item);
2273 if (!startoffset)
2275 CLog::LogF(LOGERROR, "Failed to obtain start offset for stack {}. Aborting playback.",
2276 item.GetDynPath());
2277 return false;
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>();
2304 if (!bRestart)
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))
2322 return false;
2324 // Translate/Resolve the url if needed
2325 const std::unique_ptr<IDirectory> dir{CDirectoryFactory::Create(item)};
2326 if (dir && !dir->Resolve(item))
2328 return false;
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
2334 if (item.IsStack())
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());
2347 if (bRestart)
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
2360 CVideoDatabase dbs;
2361 dbs.Open();
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;
2387 else
2389 CBookmark bookmark;
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)
2409 CBookmark bookmark;
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)
2422 CBookmark bookmark;
2423 dbs.GetBookMarkForEpisode(*tag, bookmark);
2424 options.starttime = bookmark.timeInSeconds;
2425 options.state = bookmark.playerState;
2429 dbs.Close();
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)
2443 : player};
2444 const bool isExternalPlayer{
2445 m_ServiceManager->GetPlayerCoreFactory().IsExternalPlayer(defaulPlayer)};
2446 const bool isRemotePlayer{
2447 m_ServiceManager->GetPlayerCoreFactory().IsRemotePlayer(defaulPlayer)};
2448 return !isExternalPlayer && !isRemotePlayer;
2449 }();
2451 if (isSimpleMenuAllowed)
2453 // Check if we must show the simplified bd menu.
2454 if (!CGUIDialogSimpleMenu::ShowPlaySelection(item, forceSelection))
2455 return true;
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();
2485 else
2486 options.fullscreen = false;
2488 else
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]);
2516 if (dMsgCount > 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();
2527 if (gui)
2528 gui->GetAudioManager().Enable(false);
2529 #endif
2531 if (item.HasPVRChannelInfoTag())
2532 CServiceBroker::GetPlaylistPlayer().SetCurrentPlaylist(PLAYLIST::Id::TYPE_NONE);
2534 return true;
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();
2545 if (gui)
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();
2557 else
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);
2564 #endif
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)
2584 // yes, disable vis
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();
2618 if (gui)
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) &&
2630 !m_bStop)
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();
2648 if ( nRemoved > 0 )
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())
2655 StopPlaying();
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);
2704 break;
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());
2711 #endif
2712 m_itemCurrentFile =
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
2725 // so do nothing
2726 if (playList.size() <= m_nextPlaylistItem)
2727 return true;
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()),
2736 param, item);
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);
2744 #ifdef HAS_PYTHON
2745 // informs python script currently running playback has started
2746 // (does nothing if python is not loaded)
2747 CServiceBroker::GetXBPython().OnPlayBackStarted(*m_itemCurrentFile);
2748 #endif
2750 CVariant param;
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);
2770 return true;
2772 break;
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]);
2789 // handle plugin://
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();
2806 return true;
2809 #ifdef HAS_UPNP
2810 if (URIUtils::IsUPnP(file.GetDynPath()))
2812 if (!XFILE::CUPnPDirectory::GetResource(file.GetDynURL(), file))
2813 return true;
2815 #endif
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;
2823 else
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);
2830 return true;
2832 break;
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.");
2840 return false;
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()));
2853 else
2855 CServiceBroker::GetAppMessenger()->PostMsg(TMSG_MEDIA_PLAY, 1, 0,
2856 static_cast<void*>(trailerItem.release()));
2858 break;
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();
2871 ResetCurrentItem();
2872 PlaybackCleanup();
2873 #ifdef HAS_PYTHON
2874 CServiceBroker::GetXBPython().OnPlayBackStopped();
2875 #endif
2876 return true;
2879 case GUI_MSG_PLAYBACK_ENDED:
2881 CServiceBroker::GetPVRManager().OnPlaybackEnded(*m_itemCurrentFile);
2883 CVariant data(CVariant::VariantTypeObject);
2884 data["end"] = true;
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);
2893 return 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)};
2900 ResetCurrentItem();
2902 if (!isEpgPlaylistItem)
2904 if (!CServiceBroker::GetPlaylistPlayer().PlayNext(1, true))
2905 GetComponent<CApplicationPlayer>()->ClosePlayer();
2907 PlaybackCleanup();
2910 #ifdef HAS_PYTHON
2911 CServiceBroker::GetXBPython().OnPlayBackEnded();
2912 #endif
2913 return true;
2916 case GUI_MSG_PLAYLISTPLAYER_STOPPED:
2917 ResetCurrentItem();
2918 if (GetComponent<CApplicationPlayer>()->IsPlaying())
2919 StopPlaying();
2920 PlaybackCleanup();
2921 return true;
2923 case GUI_MSG_PLAYBACK_AVSTARTED:
2925 CVariant param;
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();
2932 #ifdef HAS_PYTHON
2933 // informs python script currently running playback has started
2934 // (does nothing if python is not loaded)
2935 CServiceBroker::GetXBPython().OnAVStarted(*m_itemCurrentFile);
2936 #endif
2937 return true;
2940 case GUI_MSG_PLAYBACK_AVCHANGE:
2942 #ifdef HAS_PYTHON
2943 // informs python script currently running playback has started
2944 // (does nothing if python is not loaded)
2945 CServiceBroker::GetXBPython().OnAVChange();
2946 #endif
2947 CVariant param;
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);
2953 return true;
2956 case GUI_MSG_PLAYBACK_PAUSED:
2958 CVariant param;
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);
2964 return true;
2967 case GUI_MSG_PLAYBACK_RESUMED:
2969 CVariant param;
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);
2975 return true;
2978 case GUI_MSG_PLAYBACK_SEEKED:
2980 CVariant param;
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));
2995 return true;
2998 case GUI_MSG_PLAYBACK_SPEED_CHANGED:
3000 CVariant param;
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);
3007 return true;
3010 case GUI_MSG_PLAYBACK_ERROR:
3011 HELPERS::ShowOKDialogText(CVariant{16026}, CVariant{16027});
3012 return true;
3014 case GUI_MSG_PLAYLISTPLAYER_STARTED:
3015 case GUI_MSG_PLAYLISTPLAYER_CHANGED:
3017 return true;
3019 break;
3020 case GUI_MSG_FULLSCREEN:
3021 { // Switch to fullscreen, if we can
3022 CGUIComponent* gui = CServiceBroker::GetGUI();
3023 if (gui)
3024 gui->GetWindowManager().SwitchToFullScreen();
3026 return true;
3028 break;
3029 case GUI_MSG_EXECUTE:
3030 if (message.GetNumStringParams())
3031 return ExecuteXBMCAction(message.GetStringParam(), message.GetItem());
3032 break;
3034 return false;
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);
3045 if (item)
3046 actionStr = GUILIB::GUIINFO::CGUIInfoLabel::GetItemLabel(actionStr, item.get());
3047 else
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);
3057 else
3059 // try translating the action from our ButtonTranslator
3060 unsigned int actionID;
3061 if (ACTION::CActionTranslator::TranslateString(actionStr, actionID))
3063 OnAction(CAction(actionID));
3064 return true;
3066 CFileItem item(actionStr, false);
3067 #ifdef HAS_PYTHON
3068 if (item.IsPythonScript())
3069 { // a python script
3070 CScriptInvocationManager::GetInstance().ExecuteAsync(item.GetPath());
3072 else
3073 #endif
3074 if (MUSIC::IsAudio(item) || VIDEO::IsVideo(item) || item.IsGame())
3075 { // an audio or video file
3076 PlayFile(item, "");
3078 else
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);
3083 return false;
3086 return true;
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());
3116 continue;
3119 if (addonMgr.IsAddonDisabledExcept(addon->ID(), ADDON::AddonDisabledReason::NONE) ||
3120 CAddonType::IsDependencyType(addon->MainType()))
3122 continue;
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());
3139 else
3141 addonMgr.EnableAddon(addon->ID());
3144 else
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();
3181 ProcessSlow();
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();
3201 else
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)
3214 #else
3215 if (CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_POWERMANAGEMENT_SHUTDOWNTIME))
3216 #endif
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);
3227 #endif
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();
3240 #endif
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();
3253 #endif
3255 // update upnp server/renderer states
3256 #ifdef HAS_UPNP
3257 if (CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_SERVICES_UPNP) && UPNP::CUPnP::IsInstantiated())
3258 UPNP::CUPnP::GetInstance()->UpdateState();
3259 #endif
3261 #if defined(TARGET_POSIX) && defined(HAS_FILESYSTEM_SMB)
3262 smb.CheckIfIdle();
3263 #endif
3265 #ifdef HAS_FILESYSTEM_NFS
3266 gNfsConnection.CheckIfIdle();
3267 #endif
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();
3292 Restart(true);
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())
3304 return ;
3306 if (!appPlayer->HasPlayer())
3307 return ;
3309 // do we want to return to the current position in the file
3310 if (!bSamePosition)
3312 // no, then just reopen the file and start at the beginning
3313 PlayFile(*m_itemCurrentFile, "", true);
3314 return ;
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));
3326 // reopen the file
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();
3352 else
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
3359 // SeekTime().
3360 double CApplication::GetTotalTime() const
3362 double rc = 0.0;
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;
3371 else
3372 rc = appPlayer->GetTotalTime() * 0.001;
3375 return rc;
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
3383 double rc = 0.0;
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;
3395 else
3396 rc = appPlayer->GetTime() * 0.001;
3399 return rc;
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())
3415 return;
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);
3428 else
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));
3437 return;
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);
3465 else
3466 return appPlayer->GetPercentage();
3468 return 0.0f;
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));
3488 else
3489 return std::min(100.0f, appPlayer->GetPercentage() + appPlayer->GetCachePercentage());
3491 return 0.0f;
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())
3502 return;
3503 if (stackHelper->IsPlayingRegularStack())
3504 SeekTime(static_cast<double>(percent) * 0.01 * GetTotalTime());
3505 else
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())
3539 return;
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,
3551 int track)
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)
3559 return false;
3561 // illegal playlist
3562 if (playlistId == PLAYLIST::Id::TYPE_NONE || playlistId == PLAYLIST::Id::TYPE_PICTURE)
3563 return false;
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())
3578 // start playing it
3579 CServiceBroker::GetPlaylistPlayer().SetCurrentPlaylist(playlistId);
3580 CServiceBroker::GetPlaylistPlayer().Reset();
3581 CServiceBroker::GetPlaylistPlayer().Play(track, "");
3582 return true;
3584 return false;
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))
3596 return true;
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))
3605 return false;
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));
3612 return true;
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;
3632 #if defined(_DEBUG)
3633 buildType = "Debug";
3634 #elif defined(NDEBUG)
3635 buildType = "Release";
3636 #else
3637 buildType = "Unknown";
3638 #endif
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());
3657 else
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");
3672 else
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"
3682 : "disabled");
3683 #endif
3684 CSpecialProtocol::LogPaths();
3686 #ifdef HAS_WEB_SERVER
3687 CLog::Log(LOGINFO, "Webserver extra whitelist paths: {}",
3688 StringUtils::Join(CCompileInfo::GetWebserverExtraWhitelist(), ", "));
3689 #endif
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]");
3699 firstRun = false;
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)
3717 smb.Deinit();
3718 #endif
3720 #ifdef HAS_FILESYSTEM_NFS
3721 gNfsConnection.Deinit();
3722 #endif
3724 for (const auto& vfsAddon : CServiceBroker::GetVFSAddonCache().GetAddonInstances())
3725 vfsAddon->DisconnectAll();