m.global is a special roSGNode provided by the Roku SceneGraph runtime. Unlike local m fields, m.global is shared across all components and tasks simultaneously — reads and writes are thread-safe and changes are immediately visible to any observer registered with observeField.
GTV_InitGlobalState() in source/AppState.brs calls m.global.addFields({...}) once at startup inside MainScene.init() to declare every field with its initial value.
Reading and writing global fields
From a component (render thread):
' Write
m.global.playerState = "playing"
m.global.currentChannelIndex = 3
' Read
channels = m.global.channelList
if m.global.isAuthenticated = true
' ...
end if
From a Task node (background thread) — Tasks access m.global through the same m.global reference available in their script scope:
' Task writes result back to a task field, not directly to m.global
' MainScene then reads the task field and updates m.global
m.global.activeServer ' readable from tasks
Observing changes — components can react to global field changes:
' In PlayerScreen.init()
m.global.observeField("channelList", "OnChannelListChanged")
Tasks should write to their own output fields (e.g., done, result) rather than writing directly to m.global. MainScene reads task output and updates m.global on the render thread. This avoids race conditions between the render thread and task threads.
Field reference
Server and connectivity
| Field | Type | Default | Description |
|---|
activeServer | string | "" | Base URL of the currently active backend server, e.g. "https://admin.globaltv.lat". Set by HandshakeTask or when the user applies a server from Settings. |
realtimeMode | string | "polling" | Reserved for future realtime transport selection. Currently always "polling". |
isOnline | boolean | true | Whether a network interface is available (GTV_IsOnline()). Updated by PlayerScreen on each netCheckTimer fire. |
hasInternet | boolean | true | Whether the network interface has verified internet reachability. Updated by ConnectivityTask and PlayerScreen. |
Authentication
| Field | Type | Default | Description |
|---|
isAuthenticated | boolean | false | Set to true by AuthTask on success; cleared to false on logout, session invalidation, or playlist failure. |
username | string | "" | The authenticated user’s username. Written by MainScene after successful login. |
rokuEmail | string | "" | Roku account email obtained via ChannelStore.getUserData. Written by LoginScreen and passed to MainScene. |
userId | string | "" | Backend user ID returned by the auth endpoint. |
subscriberActive | boolean | false | Whether the subscriber account is active. Used by GTV_AuthLooksInactive() to classify inactive-account failures. |
userInactiveReason | string | "" | Human-readable message shown in the inactivity or session-issue dialog. |
authNotice | string | "" | One-time notice displayed on the LoginScreen after a forced logout. Consumed and cleared immediately on login init. |
authReasonCode | integer | 0 | Current failure classification: 0 = none, 460 = network down, 401 = credentials, 470 = inactive, 471 = password changed. |
authReasonCode constants are defined in AppConstants() as AUTH_REASON_NONE, AUTH_REASON_NETWORK_DOWN, AUTH_REASON_CREDENTIALS, AUTH_REASON_INACTIVE, and AUTH_REASON_PASSWORD_CHANGED.
Channel list and selection
| Field | Type | Default | Description |
|---|
channelList | array | [] | Flat array of channel objects parsed from the M3U8 playlist. Each entry contains contentId, name, number, url, group, and logo. |
categories | array | [] | Array of category labels derived from M3U8 group-title tags. |
currentChannelIndex | integer | 0 | Zero-based index into channelList for the channel currently being played. Written by PlayerScreen.PlayChannel() and updated on every channel switch. |
currentChannelId | string | "" | contentId of the current channel. Used by the ad system to match snapshots and by MetricsTask for event attribution. |
overlaySelectedChannelIndex | integer | -1 | Flat index of the channel highlighted in the overlay grid. Kept in sync by MainScreen.UpdateOverlaySelectedFlatIndex(). |
overlayHasManualContext | boolean | false | true when the user has manually navigated to a different category in the overlay. Used by MainScene to restore the exact category and row when re-opening the overlay. |
overlaySelectedCategoryIndex | integer | 0 | Category tab index remembered for overlay restoration. |
overlaySelectedRowIndex | integer | -1 | Row index within the selected category, remembered for overlay restoration. |
Player state
| Field | Type | Default | Description |
|---|
playerState | string | "stopped" | Mirror of m.video.state. Updated on every OnVideoStateChanged() event. Values: "stopped", "buffering", "playing", "paused", "finished", "error". |
isOverlayActive | boolean | false | true while the channel-selection overlay is visible on top of the player. Written by SetOverlayActive() in MainScene and read by PlayerScreen to route key events. |
Ad state
| Field | Type | Default | Description |
|---|
adsVersion | integer | 0 | Version counter incremented by AdsPollingTask on each successful poll response. Cleared to 0 on logout or session reset. |
adsNextCheckAt | integer | 0 | Unix timestamp (seconds) of the next scheduled ad poll. Used by the task to enforce ADS_POLL_MS intervals. |
Device info
| Field | Type | Default | Description |
|---|
deviceId | string | "" | Roku device serial or unique identifier. Populated during handshake. |
deviceModel | string | "" | Roku model name, e.g. "3900X". |
osVersion | string | "" | Roku OS version string. |
rida | string | "" | Roku ID for Advertisers (RIDA). Used by the ad system for targeting. |
lat | boolean | false | Limit Ad Tracking flag. true means the user has opted out of ad tracking. |
deviceIp | string | "" | LAN IP address of the device. |
deviceTimezone | integer | 0 | UTC offset in seconds. |
Deep links and beacons
| Field | Type | Default | Description |
|---|
launchDeepLink | assocarray | invalid | The raw deep link args from Main(args) when mediaType = "live". Set on MainScene (not m.global) and triggers onLaunchDeepLink() via onChange. |
inputDeepLink | assocarray | invalid | Warm-start deep link received as roInputEvent. Set on MainScene (not m.global) and triggers onInputDeepLink() via onChange. |
appLaunchBeaconSent | boolean | false | Prevents duplicate AppLaunchComplete beacons. Set to true the first time MainScreen.SignalAppLaunchCompleteOnce() fires. Never reset during the session. |
launchDeepLink and inputDeepLink are fields on m.top (the MainScene node), not on m.global. They are declared in MainScene.xml with onChange handlers and appear here for completeness.
Complete initialisation listing
The full addFields call from source/AppState.brs:
sub GTV_InitGlobalState()
m.global.addFields({
activeServer : "",
realtimeMode : "polling",
isOnline : true,
hasInternet : true,
isAuthenticated : false,
username : "",
rokuEmail : "",
userId : "",
subscriberActive : false,
userInactiveReason : "",
authNotice : "",
authReasonCode : 0,
channelList : [],
categories : [],
currentChannelIndex : 0,
currentChannelId : "",
overlaySelectedChannelIndex : -1,
overlayHasManualContext : false,
overlaySelectedCategoryIndex : 0,
overlaySelectedRowIndex : -1,
playerState : "stopped",
isOverlayActive : false,
adsVersion : 0,
adsNextCheckAt : 0,
deviceId : "",
deviceModel : "",
osVersion : "",
rida : "",
lat : false,
deviceIp : "",
deviceTimezone : 0,
launchDeepLink : invalid,
inputDeepLink : invalid,
appLaunchBeaconSent : false
})
end sub
Registry fields
Some state is persisted across sessions in the Roku Registry (roRegistrySection named "GlobalTV"). These values survive channel updates and device reboots.
Registry key (AppConstants) | Constant | Description |
|---|
REG_KEY_USER | "username" | Saved username for auto-login. Written by MainScene after successful login; cleared on logout or credential failure. |
REG_KEY_PASS | "password" | Saved password for auto-login. Stored alongside username; cleared on the same conditions. |
REG_KEY_SERVER | "lastServer" | Base URL of the last successfully used server. Written by HandshakeTask and by the server-apply action in Settings. |
REG_KEY_CHANNEL | "lastChannelIndex" | Zero-based index of the last channel played. Written by PlayerScreen.PlayChannel() on every channel switch. Used by ResolveStartupChannelIndex() to resume where the user left off. |
REG_KEY_SAFE_MARGIN | "uiSafeMarginPct" | Integer percentage (0–10) for the UI safe-area margin. Written by SettingsScreen.AdjustSafeArea() and read by GTV_GetSafeMarginPct() on every layout pass. |
REG_KEY_SERVER_PROFILES | "serverProfiles" | JSON-encoded array of server profile objects. Managed by ServerManager.brs functions (GTV_LoadServerProfiles, GTV_SaveServerProfiles). |
' Reading registry credentials
creds = GTV_RegLoadCredentials()
if creds <> invalid
' creds.username and creds.password are available
RunAutoLogin(creds.username, creds.password)
end if
' Saving after successful login
GTV_RegSaveCredentials(creds.username, creds.password)
GTV_RegSaveLastServer(serverUrl)
GTV_RegSaveLastChannelIndex(channelIndex)
Credentials are stored in plaintext in the Roku Registry. The registry is device-local and not accessible to other channels, but you should not store sensitive data beyond what is required for auto-login.
State lifecycle
The following events reset or clear portions of global state:
| Event | Fields cleared |
|---|
| Logout | isAuthenticated, userId, rokuEmail, channelList, categories, currentChannelIndex, currentChannelId, playerState, adsVersion, adsNextCheckAt, subscriberActive, username, activeServer |
| Session invalidation (credentials) | Same as logout; also clears registry credentials |
| Session invalidation (inactive account) | Same as logout; registry credentials preserved to allow retry |
| Server switch (Settings → Apply now) | activeServer, realtimeMode, hasInternet, isOnline, authReasonCode, userInactiveReason; then restarts handshake |
| Playlist refresh | channelList and categories are replaced with fresh data; currentChannelIndex is re-resolved by content ID |