Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions app/gui/SettingsView.qml
Original file line number Diff line number Diff line change
Expand Up @@ -1279,6 +1279,58 @@ Flickable {
ToolTip.visible: hovered
ToolTip.text: qsTr("Prevents the screensaver from starting or the display from going to sleep while streaming.")
}

CheckBox {
id: inactivityTimeoutCheck
width: parent.width
text: qsTr("Disconnect after inactivity")
font.pointSize: 12
checked: StreamingPreferences.inactivityTimeoutEnabled
onCheckedChanged: {
StreamingPreferences.inactivityTimeoutEnabled = checked
}

ToolTip.delay: 1000
ToolTip.timeout: 5000
ToolTip.visible: hovered
ToolTip.text: qsTr("Automatically disconnects if no input is received for the selected duration.")
}

Column {
width: parent.width
spacing: 4
opacity: inactivityTimeoutCheck.checked ? 1.0 : 0.6

Label {
width: parent.width
text: qsTr("Inactivity timeout duration")
font.pointSize: 11
wrapMode: Text.Wrap
}

Row {
width: parent.width
spacing: 8

SpinBox {
id: inactivityTimeoutMinutes
enabled: inactivityTimeoutCheck.checked
from: 5
to: 240
stepSize: 5
value: StreamingPreferences.inactivityTimeoutMinutes
onValueModified: {
StreamingPreferences.inactivityTimeoutMinutes = value
}
}

Label {
text: qsTr("minutes")
font.pointSize: 11
verticalAlignment: Text.AlignVCenter
}
}
}
}
}
}
Expand Down
6 changes: 6 additions & 0 deletions app/settings/streamingpreferences.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@
#define SER_SWAPFACEBUTTONS "swapfacebuttons"
#define SER_CAPTURESYSKEYS "capturesyskeys"
#define SER_KEEPAWAKE "keepawake"
#define SER_INACTIVITY_TIMEOUT_ENABLED "inactivityTimeoutEnabled"
#define SER_INACTIVITY_TIMEOUT_MINUTES "inactivityTimeoutMinutes"
#define SER_LANGUAGE "language"

#define CURRENT_DEFAULT_VER 2
Expand Down Expand Up @@ -150,6 +152,8 @@ void StreamingPreferences::reload()
reverseScrollDirection = settings.value(SER_REVERSESCROLL, false).toBool();
swapFaceButtons = settings.value(SER_SWAPFACEBUTTONS, false).toBool();
keepAwake = settings.value(SER_KEEPAWAKE, true).toBool();
inactivityTimeoutEnabled = settings.value(SER_INACTIVITY_TIMEOUT_ENABLED, false).toBool();
inactivityTimeoutMinutes = settings.value(SER_INACTIVITY_TIMEOUT_MINUTES, 30).toInt();
enableHdr = settings.value(SER_HDR, false).toBool();
captureSysKeysMode = static_cast<CaptureSysKeysMode>(settings.value(SER_CAPTURESYSKEYS,
static_cast<int>(CaptureSysKeysMode::CSK_OFF)).toInt());
Expand Down Expand Up @@ -358,6 +362,8 @@ void StreamingPreferences::save()
settings.setValue(SER_SWAPFACEBUTTONS, swapFaceButtons);
settings.setValue(SER_CAPTURESYSKEYS, captureSysKeysMode);
settings.setValue(SER_KEEPAWAKE, keepAwake);
settings.setValue(SER_INACTIVITY_TIMEOUT_ENABLED, inactivityTimeoutEnabled);
settings.setValue(SER_INACTIVITY_TIMEOUT_MINUTES, inactivityTimeoutMinutes);
}

int StreamingPreferences::getDefaultBitrate(int width, int height, int fps, bool yuv444)
Expand Down
6 changes: 6 additions & 0 deletions app/settings/streamingpreferences.h
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,8 @@ class StreamingPreferences : public QObject
Q_PROPERTY(bool reverseScrollDirection MEMBER reverseScrollDirection NOTIFY reverseScrollDirectionChanged)
Q_PROPERTY(bool swapFaceButtons MEMBER swapFaceButtons NOTIFY swapFaceButtonsChanged)
Q_PROPERTY(bool keepAwake MEMBER keepAwake NOTIFY keepAwakeChanged)
Q_PROPERTY(bool inactivityTimeoutEnabled MEMBER inactivityTimeoutEnabled NOTIFY inactivityTimeoutEnabledChanged)
Q_PROPERTY(int inactivityTimeoutMinutes MEMBER inactivityTimeoutMinutes NOTIFY inactivityTimeoutMinutesChanged)
Q_PROPERTY(CaptureSysKeysMode captureSysKeysMode MEMBER captureSysKeysMode NOTIFY captureSysKeysModeChanged)
Q_PROPERTY(Language language MEMBER language NOTIFY languageChanged);

Expand Down Expand Up @@ -176,6 +178,8 @@ class StreamingPreferences : public QObject
bool reverseScrollDirection;
bool swapFaceButtons;
bool keepAwake;
bool inactivityTimeoutEnabled;
int inactivityTimeoutMinutes;
int packetSize;
AudioConfig audioConfig;
VideoCodecConfig videoCodecConfig;
Expand Down Expand Up @@ -223,6 +227,8 @@ class StreamingPreferences : public QObject
void swapFaceButtonsChanged();
void captureSysKeysModeChanged();
void keepAwakeChanged();
void inactivityTimeoutEnabledChanged();
void inactivityTimeoutMinutesChanged();
void languageChanged();

private:
Expand Down
66 changes: 65 additions & 1 deletion app/streaming/session.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -580,7 +580,11 @@ Session::Session(NvComputer* computer, NvApp& app, StreamingPreferences *prefere
m_OpusDecoder(nullptr),
m_AudioRenderer(nullptr),
m_AudioSampleCount(0),
m_DropAudioEndTime(0)
m_DropAudioEndTime(0),
m_LastInputTime(0),
m_InactivityTimeoutMs((m_Preferences->inactivityTimeoutMinutes > 0 ?
m_Preferences->inactivityTimeoutMinutes : 30) * 60 * 1000),
m_InactivityTimeoutEnabled(m_Preferences->inactivityTimeoutEnabled)
{
}

Expand All @@ -592,6 +596,31 @@ Session::~Session()
SDL_DestroyMutex(m_DecoderLock);
}

void Session::resetInactivityTimer()
{
if (m_InactivityTimeoutEnabled) {
m_LastInputTime = SDL_GetTicks();
}
}

void Session::checkInactivityTimeout()
{
if (m_InactivityTimeoutEnabled) {
Uint32 currentTime = SDL_GetTicks();
if (currentTime - m_LastInputTime > m_InactivityTimeoutMs) {
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
"Disconnecting due to %d minutes of inactivity",
m_InactivityTimeoutMs / 60000);

// Push a quit event to trigger cleanup
SDL_Event quitEvent;
quitEvent.type = SDL_QUIT;
quitEvent.quit.timestamp = SDL_GetTicks();
SDL_PushEvent(&quitEvent);
}
}
}

bool Session::initialize(QQuickWindow* qtWindow)
{
m_QtWindow = qtWindow;
Expand Down Expand Up @@ -1998,6 +2027,11 @@ void Session::exec()
// Switch to async logging mode when we enter the SDL loop
StreamUtils::enterAsyncLoggingMode();

// Initialize inactivity timer (if enabled)
if (m_InactivityTimeoutEnabled) {
resetInactivityTimer();
}

// Hijack this thread to be the SDL main thread. We have to do this
// because we want to suspend all Qt processing until the stream is over.
SDL_Event event;
Expand All @@ -2014,6 +2048,9 @@ void Session::exec()
// and other problems.
if (!SDL_WaitEventTimeout(&event, 1000)) {
presence.runCallbacks();
if (m_InactivityTimeoutEnabled) {
checkInactivityTimeout();
}
continue;
}
#else
Expand All @@ -2030,6 +2067,9 @@ void Session::exec()
SDL_Delay(10);
#endif
presence.runCallbacks();
if (m_InactivityTimeoutEnabled) {
checkInactivityTimeout();
}
continue;
}
#endif
Expand Down Expand Up @@ -2287,25 +2327,43 @@ void Session::exec()
case SDL_KEYUP:
case SDL_KEYDOWN:
presence.runCallbacks();
if (m_InactivityTimeoutEnabled) {
resetInactivityTimer();
}
m_InputHandler->handleKeyEvent(&event.key);
break;
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP:
presence.runCallbacks();
if (m_InactivityTimeoutEnabled) {
resetInactivityTimer();
}
m_InputHandler->handleMouseButtonEvent(&event.button);
break;
case SDL_MOUSEMOTION:
if (m_InactivityTimeoutEnabled) {
resetInactivityTimer();
}
m_InputHandler->handleMouseMotionEvent(&event.motion);
break;
case SDL_MOUSEWHEEL:
if (m_InactivityTimeoutEnabled) {
resetInactivityTimer();
}
m_InputHandler->handleMouseWheelEvent(&event.wheel);
break;
case SDL_CONTROLLERAXISMOTION:
if (m_InactivityTimeoutEnabled) {
resetInactivityTimer();
}
m_InputHandler->handleControllerAxisEvent(&event.caxis);
break;
case SDL_CONTROLLERBUTTONDOWN:
case SDL_CONTROLLERBUTTONUP:
presence.runCallbacks();
if (m_InactivityTimeoutEnabled) {
resetInactivityTimer();
}
m_InputHandler->handleControllerButtonEvent(&event.cbutton);
break;
#if SDL_VERSION_ATLEAST(2, 0, 14)
Expand All @@ -2315,6 +2373,9 @@ void Session::exec()
case SDL_CONTROLLERTOUCHPADDOWN:
case SDL_CONTROLLERTOUCHPADUP:
case SDL_CONTROLLERTOUCHPADMOTION:
if (m_InactivityTimeoutEnabled) {
resetInactivityTimer();
}
m_InputHandler->handleControllerTouchpadEvent(&event.ctouchpad);
break;
#endif
Expand All @@ -2333,6 +2394,9 @@ void Session::exec()
case SDL_FINGERDOWN:
case SDL_FINGERMOTION:
case SDL_FINGERUP:
if (m_InactivityTimeoutEnabled) {
resetInactivityTimer();
}
m_InputHandler->handleTouchFingerEvent(&event.tfinger);
break;
case SDL_DISPLAYEVENT:
Expand Down
8 changes: 8 additions & 0 deletions app/streaming/session.h
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,15 @@ class Session : public QObject

Overlay::OverlayManager m_OverlayManager;

// Inactivity timeout tracking
Uint32 m_LastInputTime;
Uint32 m_InactivityTimeoutMs;
bool m_InactivityTimeoutEnabled;

static CONNECTION_LISTENER_CALLBACKS k_ConnCallbacks;
static Session* s_ActiveSession;
static QSemaphore s_ActiveSessionSemaphore;

void checkInactivityTimeout();
void resetInactivityTimer();
};