Navigation Menu

Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PVR] Feature: Confirm shutdown if PVR backend is not idle. #4342

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
14 changes: 13 additions & 1 deletion language/English/strings.po
Expand Up @@ -9295,7 +9295,19 @@ msgctxt "#19684"
msgid "Adult" msgid "Adult"
msgstr "" msgstr ""


#empty strings from id 19685 to 19999 #. Title for shutdown confirmation dialog
#: xbmc/ApplicationMessenger.cpp
msgctxt "#19685"
msgid "Confirm shutdown"
msgstr ""

#. Text for shutdown confirmation dialog
#: xbmc/ApplicationMessenger.cpp
msgctxt "#19686"
msgid "The PVR backend is busy. Shutdown anyway?"
msgstr ""

#empty strings from id 19687 to 19999


#: system/settings/settings.xml #: system/settings/settings.xml
msgctxt "#20000" msgctxt "#20000"
Expand Down
20 changes: 15 additions & 5 deletions xbmc/Application.cpp
Expand Up @@ -734,7 +734,9 @@ bool CApplication::Create()


std::string executable = CUtil::ResolveExecutablePath(); std::string executable = CUtil::ResolveExecutablePath();
CLog::Log(LOGNOTICE, "The executable running is: %s", executable.c_str()); CLog::Log(LOGNOTICE, "The executable running is: %s", executable.c_str());
CLog::Log(LOGNOTICE, "Local hostname: %s", m_network->GetHostName().c_str()); std::string hostname("[unknown]");
m_network->GetHostName(hostname);
CLog::Log(LOGNOTICE, "Local hostname: %s", hostname.c_str());
std::string lowerAppName = CCompileInfo::GetAppName(); std::string lowerAppName = CCompileInfo::GetAppName();
StringUtils::ToLower(lowerAppName); StringUtils::ToLower(lowerAppName);
CLog::Log(LOGNOTICE, "Log File is located: %s%s.log", g_advancedSettings.m_logFolder.c_str(), lowerAppName.c_str()); CLog::Log(LOGNOTICE, "Log File is located: %s%s.log", g_advancedSettings.m_logFolder.c_str(), lowerAppName.c_str());
Expand Down Expand Up @@ -2589,8 +2591,12 @@ bool CApplication::OnAction(const CAction &action)
// built in functions : execute the built-in // built in functions : execute the built-in
if (action.GetID() == ACTION_BUILT_IN_FUNCTION) if (action.GetID() == ACTION_BUILT_IN_FUNCTION)
{ {
CBuiltins::Execute(action.GetName()); if (!CBuiltins::IsSystemPowerdownCommand(action.GetName()) ||
m_navigationTimer.StartZero(); g_PVRManager.CanSystemPowerdown())
{
CBuiltins::Execute(action.GetName());
m_navigationTimer.StartZero();
}
return true; return true;
} }


Expand Down Expand Up @@ -4723,7 +4729,7 @@ void CApplication::CheckShutdown()
|| m_musicInfoScanner->IsScanning() || m_musicInfoScanner->IsScanning()
|| m_videoInfoScanner->IsScanning() || m_videoInfoScanner->IsScanning()
|| g_windowManager.IsWindowActive(WINDOW_DIALOG_PROGRESS) // progress dialog is onscreen || g_windowManager.IsWindowActive(WINDOW_DIALOG_PROGRESS) // progress dialog is onscreen
|| (CSettings::Get().GetBool("pvrmanager.enabled") && !g_PVRManager.IsIdle())) || !g_PVRManager.CanSystemPowerdown(false))
{ {
m_shutdownTimer.StartZero(); m_shutdownTimer.StartZero();
return; return;
Expand Down Expand Up @@ -4999,7 +5005,11 @@ bool CApplication::ExecuteXBMCAction(std::string actionStr)


// user has asked for something to be executed // user has asked for something to be executed
if (CBuiltins::HasCommand(actionStr)) if (CBuiltins::HasCommand(actionStr))
CBuiltins::Execute(actionStr); {
if (!CBuiltins::IsSystemPowerdownCommand(actionStr) ||
g_PVRManager.CanSystemPowerdown())
CBuiltins::Execute(actionStr);
}
else else
{ {
// try translating the action from our ButtonTranslator // try translating the action from our ButtonTranslator
Expand Down
6 changes: 5 additions & 1 deletion xbmc/GUIInfoManager.cpp
Expand Up @@ -1921,7 +1921,11 @@ std::string CGUIInfoManager::GetLabel(int info, int contextWindow, std::string *
{ {
std::string friendlyName = CSettings::Get().GetString("services.devicename"); std::string friendlyName = CSettings::Get().GetString("services.devicename");
if (StringUtils::EqualsNoCase(friendlyName, CCompileInfo::GetAppName())) if (StringUtils::EqualsNoCase(friendlyName, CCompileInfo::GetAppName()))
strLabel = StringUtils::Format("%s (%s)", friendlyName.c_str(), g_application.getNetwork().GetHostName().c_str()); {
std::string hostname("[unknown]");
g_application.getNetwork().GetHostName(hostname);
strLabel = StringUtils::Format("%s (%s)", friendlyName.c_str(), hostname.c_str());
}
else else
strLabel = friendlyName; strLabel = friendlyName;
} }
Expand Down
8 changes: 4 additions & 4 deletions xbmc/URL.cpp
Expand Up @@ -19,6 +19,7 @@
*/ */


#include "URL.h" #include "URL.h"
#include "Application.h"
#include "utils/RegExp.h" #include "utils/RegExp.h"
#include "utils/log.h" #include "utils/log.h"
#include "utils/URIUtils.h" #include "utils/URIUtils.h"
Expand All @@ -29,6 +30,7 @@
#include "filesystem/StackDirectory.h" #include "filesystem/StackDirectory.h"
#include "addons/Addon.h" #include "addons/Addon.h"
#include "utils/StringUtils.h" #include "utils/StringUtils.h"
#include "network/Network.h"
#ifndef TARGET_POSIX #ifndef TARGET_POSIX
#include <sys\types.h> #include <sys\types.h>
#include <sys\stat.h> #include <sys\stat.h>
Expand Down Expand Up @@ -679,14 +681,12 @@ std::string CURL::GetRedacted(const std::string& path)


bool CURL::IsLocal() const bool CURL::IsLocal() const
{ {
return (IsLocalHost() || m_strProtocol.empty()); return (m_strProtocol.empty() || IsLocalHost());
} }


bool CURL::IsLocalHost() const bool CURL::IsLocalHost() const
{ {
// localhost is case-insensitive return g_application.getNetwork().IsLocalHost(m_strHostName);
return (StringUtils::EqualsNoCase(m_strHostName, "localhost") ||
m_strHostName == "127.0.0.1");
} }


bool CURL::IsFileOnly(const std::string &url) bool CURL::IsFileOnly(const std::string &url)
Expand Down
9 changes: 9 additions & 0 deletions xbmc/addons/include/xbmc_pvr_dll.h
Expand Up @@ -594,6 +594,13 @@ extern "C"
*/ */
time_t GetBufferTimeEnd(); time_t GetBufferTimeEnd();


/*!
* Get the hostname of the pvr backend server
* @return hostname as ip address or alias. If backend does not
* utilize a server, return empty string.
*/
const char* GetBackendHostname();

/*! /*!
* Called by XBMC to assign the function pointers of this add-on to pClient. * Called by XBMC to assign the function pointers of this add-on to pClient.
* @param pClient The struct to assign the function pointers to. * @param pClient The struct to assign the function pointers to.
Expand Down Expand Up @@ -674,6 +681,8 @@ extern "C"
pClient->GetPlayingTime = GetPlayingTime; pClient->GetPlayingTime = GetPlayingTime;
pClient->GetBufferTimeStart = GetBufferTimeStart; pClient->GetBufferTimeStart = GetBufferTimeStart;
pClient->GetBufferTimeEnd = GetBufferTimeEnd; pClient->GetBufferTimeEnd = GetBufferTimeEnd;

pClient->GetBackendHostname = GetBackendHostname;
}; };
}; };


Expand Down
5 changes: 3 additions & 2 deletions xbmc/addons/include/xbmc_pvr_types.h
Expand Up @@ -75,10 +75,10 @@ struct DemuxPacket;
#define PVR_STREAM_MAX_STREAMS 20 #define PVR_STREAM_MAX_STREAMS 20


/* current PVR API version */ /* current PVR API version */
#define XBMC_PVR_API_VERSION "1.9.2" #define XBMC_PVR_API_VERSION "1.9.3"


/* min. PVR API version */ /* min. PVR API version */
#define XBMC_PVR_MIN_API_VERSION "1.9.2" #define XBMC_PVR_MIN_API_VERSION "1.9.3"


#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
Expand Down Expand Up @@ -399,6 +399,7 @@ extern "C" {
time_t (__cdecl* GetPlayingTime)(void); time_t (__cdecl* GetPlayingTime)(void);
time_t (__cdecl* GetBufferTimeStart)(void); time_t (__cdecl* GetBufferTimeStart)(void);
time_t (__cdecl* GetBufferTimeEnd)(void); time_t (__cdecl* GetBufferTimeEnd)(void);
const char* (__cdecl* GetBackendHostname)(void);
} PVRClient; } PVRClient;


#ifdef __cplusplus #ifdef __cplusplus
Expand Down
34 changes: 34 additions & 0 deletions xbmc/interfaces/Builtins.cpp
Expand Up @@ -96,6 +96,7 @@
#include <vector> #include <vector>
#include "settings/AdvancedSettings.h" #include "settings/AdvancedSettings.h"
#include "settings/DisplaySettings.h" #include "settings/DisplaySettings.h"
#include "powermanagement/PowerManager.h"


using namespace std; using namespace std;
using namespace XFILE; using namespace XFILE;
Expand Down Expand Up @@ -244,6 +245,39 @@ bool CBuiltins::HasCommand(const std::string& execString)
return false; return false;
} }


bool CBuiltins::IsSystemPowerdownCommand(const std::string& execString)
{
std::string execute;
vector<string> params;
CUtil::SplitExecFunction(execString, execute, params);
StringUtils::ToLower(execute);

// Check if action is resulting in system powerdown.
if (execute == "reboot" ||
execute == "restart" ||
execute == "reset" ||
execute == "powerdown" ||
execute == "hibernate" ||
execute == "suspend" )
{
return true;
}
else if (execute == "shutdown")
{
switch (CSettings::Get().GetInt("powermanagement.shutdownstate"))
{
case POWERSTATE_SHUTDOWN:
case POWERSTATE_SUSPEND:
case POWERSTATE_HIBERNATE:
return true;

default:
return false;

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

}
}
return false;
}

void CBuiltins::GetHelp(std::string &help) void CBuiltins::GetHelp(std::string &help)
{ {
help.clear(); help.clear();
Expand Down
1 change: 1 addition & 0 deletions xbmc/interfaces/Builtins.h
Expand Up @@ -26,6 +26,7 @@ class CBuiltins
{ {
public: public:
static bool HasCommand(const std::string& execString); static bool HasCommand(const std::string& execString);
static bool IsSystemPowerdownCommand(const std::string& execString);
static void GetHelp(std::string &help); static void GetHelp(std::string &help);
static int Execute(const std::string& execString); static int Execute(const std::string& execString);
}; };
Expand Down
40 changes: 35 additions & 5 deletions xbmc/network/Network.cpp
Expand Up @@ -159,19 +159,49 @@ int CNetwork::ParseHex(char *str, unsigned char *addr)
return len; return len;
} }


std::string CNetwork::GetHostName(void) bool CNetwork::GetHostName(std::string& hostname)
{ {
char hostName[128]; char hostName[128];
if (gethostname(hostName, sizeof(hostName))) if (gethostname(hostName, sizeof(hostName)))
return "unknown"; return false;


std::string hostStr;
#ifdef TARGET_WINDOWS #ifdef TARGET_WINDOWS
std::string hostStr;
g_charsetConverter.systemToUtf8(hostName, hostStr); g_charsetConverter.systemToUtf8(hostName, hostStr);
hostname = hostStr;
#else #else
hostStr = hostName; hostname = hostName;
#endif #endif
return hostStr; return true;
}

bool CNetwork::IsLocalHost(const std::string& hostname)
{
if (hostname.empty())
return false;

if (StringUtils::StartsWith(hostname, "127.")
|| (hostname == "::1")
|| StringUtils::EqualsNoCase(hostname, "localhost"))
return true;

std::string myhostname;
if (GetHostName(myhostname)
&& StringUtils::EqualsNoCase(hostname, myhostname))
return true;

std::vector<CNetworkInterface*>& ifaces = GetInterfaceList();
std::vector<CNetworkInterface*>::const_iterator iter = ifaces.begin();
while (iter != ifaces.end())

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

{
CNetworkInterface* iface = *iter;
if (iface && iface->GetCurrentIPAddress() == hostname)
return true;

++iter;
}

return false;
} }


CNetworkInterface* CNetwork::GetFirstConnectedInterface() CNetworkInterface* CNetwork::GetFirstConnectedInterface()
Expand Down
5 changes: 4 additions & 1 deletion xbmc/network/Network.h
Expand Up @@ -110,7 +110,7 @@ class CNetwork
virtual ~CNetwork(); virtual ~CNetwork();


// Return our hostname // Return our hostname
virtual std::string GetHostName(void); virtual bool GetHostName(std::string& hostname);


// Return the list of interfaces // Return the list of interfaces
virtual std::vector<CNetworkInterface*>& GetInterfaceList(void) = 0; virtual std::vector<CNetworkInterface*>& GetInterfaceList(void) = 0;
Expand Down Expand Up @@ -146,6 +146,9 @@ class CNetwork
void StopServices(bool bWait); void StopServices(bool bWait);


static int ParseHex(char *str, unsigned char *addr); static int ParseHex(char *str, unsigned char *addr);

// Return true if given name or ip address corresponds to localhost
bool IsLocalHost(const std::string& hostname);
}; };


#ifdef HAS_LINUX_NETWORK #ifdef HAS_LINUX_NETWORK
Expand Down
4 changes: 2 additions & 2 deletions xbmc/peripherals/devices/PeripheralCecAdapter.cpp
Expand Up @@ -628,9 +628,9 @@ int CPeripheralCecAdapter::CecCommand(void *cbParam, const cec_command command)
{ {
adapter->m_bStarted = false; adapter->m_bStarted = false;
if (adapter->m_configuration.bPowerOffOnStandby == 1) if (adapter->m_configuration.bPowerOffOnStandby == 1)
CApplicationMessenger::Get().Suspend(); g_application.ExecuteXBMCAction("Suspend");
else if (adapter->m_configuration.bShutdownOnStandby == 1) else if (adapter->m_configuration.bShutdownOnStandby == 1)
CApplicationMessenger::Get().Shutdown(); g_application.ExecuteXBMCAction("Shutdown");
} }
break; break;
case CEC_OPCODE_SET_MENU_LANGUAGE: case CEC_OPCODE_SET_MENU_LANGUAGE:
Expand Down
20 changes: 20 additions & 0 deletions xbmc/pvr/PVRManager.cpp
Expand Up @@ -1414,6 +1414,26 @@ bool CPVRManager::IsIdle(void) const
return true; return true;
} }


bool CPVRManager::CanSystemPowerdown(bool bAskUser /*= true*/) const

This comment was marked as spam.

This comment was marked as spam.

{
bool bReturn(true);
if (IsStarted())
{
if (!m_addons->AllLocalBackendsIdle())
{
if (bAskUser)
{
// Inform user about PVR being busy. Ask if user wants to powerdown anyway.
bool bCanceled = false;
bReturn = CGUIDialogYesNo::ShowAndGetInput(19685, 19686, 0, 0, -1, -1, bCanceled, 10000);
}
else
bReturn = false; // do not powerdown (busy, but no user interaction requested).
}
}
return bReturn;
}

void CPVRManager::ShowPlayerInfo(int iTimeout) void CPVRManager::ShowPlayerInfo(int iTimeout)
{ {
if (IsStarted() && m_guiInfo) if (IsStarted() && m_guiInfo)
Expand Down
12 changes: 12 additions & 0 deletions xbmc/pvr/PVRManager.h
Expand Up @@ -371,6 +371,18 @@ namespace PVR
*/ */
bool IsIdle(void) const; bool IsIdle(void) const;


/*!
* @brief Check whether the system Kodi is running on can be powered down
* (shutdown/reboot/suspend/hibernate) without stopping any active
* recordings and/or without preventing the start of recordings
* sheduled for now + pvrpowermanagement.backendidletime.
* @param bAskUser True to informs user in case of potential
* data loss. User can decide to allow powerdown anyway. False to
* not to ask user and to not confirm power down.
* @return True if system can be safely powered down, false otherwise.
*/
bool CanSystemPowerdown(bool bAskUser = true) const;

/*! /*!
* @brief Set the current playing group, used to load the right channel. * @brief Set the current playing group, used to load the right channel.
* @param group The new group. * @param group The new group.
Expand Down
13 changes: 12 additions & 1 deletion xbmc/pvr/addons/PVRClient.cpp
Expand Up @@ -132,6 +132,7 @@ void CPVRClient::ResetProperties(int iClientId /* = PVR_INVALID_CLIENT_ID */)
m_strConnectionString = DEFAULT_INFO_STRING_VALUE; m_strConnectionString = DEFAULT_INFO_STRING_VALUE;
m_strFriendlyName = DEFAULT_INFO_STRING_VALUE; m_strFriendlyName = DEFAULT_INFO_STRING_VALUE;
m_strBackendName = DEFAULT_INFO_STRING_VALUE; m_strBackendName = DEFAULT_INFO_STRING_VALUE;
m_strBackendHostname.clear();
m_bIsPlayingTV = false; m_bIsPlayingTV = false;
m_bIsPlayingRecording = false; m_bIsPlayingRecording = false;
memset(&m_addonCapabilities, 0, sizeof(m_addonCapabilities)); memset(&m_addonCapabilities, 0, sizeof(m_addonCapabilities));
Expand Down Expand Up @@ -353,7 +354,7 @@ bool CPVRClient::CheckAPIVersion(void)


bool CPVRClient::GetAddonProperties(void) bool CPVRClient::GetAddonProperties(void)
{ {
std::string strBackendName, strConnectionString, strFriendlyName, strBackendVersion; std::string strBackendName, strConnectionString, strFriendlyName, strBackendVersion, strBackendHostname;
PVR_ADDON_CAPABILITIES addonCapabilities; PVR_ADDON_CAPABILITIES addonCapabilities;


/* get the capabilities */ /* get the capabilities */
Expand Down Expand Up @@ -384,12 +385,17 @@ bool CPVRClient::GetAddonProperties(void)
try { strBackendVersion = m_pStruct->GetBackendVersion(); } try { strBackendVersion = m_pStruct->GetBackendVersion(); }
catch (std::exception &e) { LogException(e, "GetBackendVersion()"); return false; } catch (std::exception &e) { LogException(e, "GetBackendVersion()"); return false; }


/* backend hostname */
try { strBackendHostname = m_pStruct->GetBackendHostname(); }
catch (std::exception &e) { LogException(e, "GetBackendHostname()"); return false; }

/* update the members */ /* update the members */
m_strBackendName = strBackendName; m_strBackendName = strBackendName;
m_strConnectionString = strConnectionString; m_strConnectionString = strConnectionString;
m_strFriendlyName = strFriendlyName; m_strFriendlyName = strFriendlyName;
m_strBackendVersion = strBackendVersion; m_strBackendVersion = strBackendVersion;
m_addonCapabilities = addonCapabilities; m_addonCapabilities = addonCapabilities;
m_strBackendHostname = strBackendHostname;


return true; return true;
} }
Expand All @@ -410,6 +416,11 @@ const std::string& CPVRClient::GetBackendVersion(void) const
return m_strBackendVersion; return m_strBackendVersion;
} }


const std::string& CPVRClient::GetBackendHostname(void) const
{
return m_strBackendHostname;
}

const std::string& CPVRClient::GetConnectionString(void) const const std::string& CPVRClient::GetConnectionString(void) const
{ {
return m_strConnectionString; return m_strConnectionString;
Expand Down