Skip to main content
GlobalTV runs a background connectivity check loop to detect network loss or server unreachability while the app is in use. The result is written to global state so any screen can react without performing its own HTTP probes.

ConnectivityTask

components/tasks/ConnectivityTask.brs is a background Task node that runs an infinite polling loop. It wakes up on a 10-second timer tick and calls DoCheck(), which performs an HTTP probe against the active server’s health endpoint.
sub RunConnectivityTask()
    GTV_Log("ConnectivityTask", "Started - checking internet every 10s")

    port     = CreateObject("roMessagePort")
    interval = 10000

    m.top.observeFieldScoped("checkNow", port)
    m.top.observeFieldScoped("control",  port)

    DoCheck()

    while true
        msg = wait(interval, port)

        if msg <> invalid
            msgType = type(msg)
            if msgType = "roSGNodeEvent"
                field = msg.GetField()
                if field = "checkNow"
                    GTV_Log("ConnectivityTask", "Immediate check triggered")
                    m.top.checkNow = false
                    DoCheck()
                else if field = "control"
                    if m.top.control = "stop" then return
                end if
            end if
        else
            DoCheck()
        end if
    end while
end sub
The checkNow field allows other parts of the app to trigger an immediate check outside the normal 10-second cadence — for example, when the player encounters a stream error.

Retry interval

The constant NET_RETRY_MS = 30000 in AppConstants.brs defines the interval used by higher-level retry logic (e.g., the player’s reconnection policy). The task’s own internal polling cycle runs at 10 seconds, independent of NET_RETRY_MS.

Online/offline state in DoCheck()

DoCheck() writes the result of each probe to both the task’s own output field and to m.global:
sub DoCheck()
    server = GTV_ServerNormalizeBaseUrl(m.global.activeServer)
    if server = "" or server = invalid
        server = GTV_ServerPrimaryConnectivityUrl()
    end if

    if server = "" or server = invalid
        m.top.hasInternet = false
        m.global.hasInternet = false
        m.global.isOnline = GTV_IsOnline()
        if m.lastConnectivityState <> "missing_server"
            GTV_Warn("ConnectivityTask", "Connectivity check unavailable: no control server")
            m.lastConnectivityState = "missing_server"
        end if
        return
    end if

    result = GTV_PingServer(server)

    m.top.hasInternet      = result
    m.global.hasInternet   = result
    m.global.isOnline      = GTV_IsOnline()

    if result
        if m.lastConnectivityState <> "online"
            GTV_Log("ConnectivityTask", "Internet OK")
            m.lastConnectivityState = "online"
        end if
    else
        if m.lastConnectivityState <> "offline"
            GTV_Warn("ConnectivityTask", "No internet reachability")
            m.lastConnectivityState = "offline"
        end if
    end if
end sub

Log spam suppression

The task tracks the previous state in m.lastConnectivityState. A log or warning is only emitted when the state changes — not on every poll tick. A device that stays offline for minutes will produce a single "No internet reachability" warning rather than one every 10 seconds.

Global state fields written

FieldTypeDescription
m.global.hasInternetBooleantrue if the health probe succeeded
m.global.isOnlineBooleantrue if the device has any network interface (from GTV_IsOnline())
m.top.hasInternetBooleanTask output field; mirrors m.global.hasInternet

NetworkDetector utility

source/utils/NetworkDetector.brs provides two low-level functions that DoCheck() and other utilities use:
function GTV_IsOnline() as Boolean
    di = CreateObject("roDeviceInfo")
    connType = di.GetConnectionType()
    return (connType <> "")
end function

function GTV_HasInternet(activeServer as String) as Boolean
    if not GTV_IsOnline()
        return false
    end if

    serverToCheck = activeServer
    if serverToCheck = ""
        serverToCheck = GTV_ServerPrimaryConnectivityUrl()
    end if

    if serverToCheck = "" then return false
    return GTV_PingServer(serverToCheck)
end function
GTV_IsOnline() uses the Roku roDeviceInfo API — it only confirms that a network interface exists (Wi-Fi or Ethernet is connected), not that the internet is reachable. GTV_HasInternet() adds a server probe on top of that, making it suitable for callers that need confirmed reachability rather than just interface presence.

HealthCheck utility

source/utils/HealthCheck.brs contains the GTV_PingServer() function used by all connectivity probes:
function GTV_PingServer(baseUrl as String) as Boolean
    c   = AppConstants()
    url = baseUrl + c.PATH_HEALTH

    http = CreateObject("roUrlTransfer")
    http.SetUrl(url)

    if Left(url, 5) = "https"
        http.SetCertificatesFile(c.CERTS)
    end if
    http.RetainBodyOnError(true)

    port = CreateObject("roMessagePort")
    http.SetMessagePort(port)

    if not http.AsyncGetToString()
        return false
    end if

    msg = wait(c.TIMEOUT_HEALTH, port)
    if msg = invalid
        http.AsyncCancel()
        return false
    end if

    if type(msg) = "roUrlEvent"
        code = msg.GetResponseCode()
        return (code >= 200 and code < 500)
    end if

    return false
end function
Key details:
  • The endpoint probed is baseUrl + "/health" (PATH_HEALTH = "/health" in AppConstants.brs).
  • The timeout is TIMEOUT_HEALTH = 2500 ms — fast enough to not block the UI.
  • Any HTTP response code in the range 200–499 is treated as success. This means a 404 or 401 from the server still counts as “reachable”; only network-level failures or a 5xx cause the probe to return false.
  • HTTPS connections use the Roku CA bundle at common:/certs/ca-bundle.crt.

How the app responds to connectivity loss

The PlayerScreen monitors m.global.hasInternet. When it goes false, the player shows an offline error modal and pauses stream attempts. It does not immediately stop the video — if the stream buffer holds, playback may continue briefly. Once the modal is visible, the player retries reconnection on a NET_RETRY_MS = 30000 ms interval.
If AUTH_REASON_NETWORK_DOWN is returned from an auth or playlist HTTP call (HTTP code -1), MainScene shows an OfflineDialog with a retry button rather than logging the user out. The retry re-runs the handshake flow from the beginning.
The periodic session re-auth timer (SESSION_AUTH_CHECK_MS = 420000 ms) skips its check when m.global.isOnline or m.global.hasInternet is false, avoiding spurious session-expiry dialogs during a network outage.
The task continues polling regardless of state. As soon as the probe succeeds again, m.global.hasInternet returns to true, and any subscriber that observes that field can resume normal operation.