Skip to content

requests.proto

syntax = "proto3";

import "models.proto";
import "google/protobuf/timestamp.proto";

option csharp_namespace = "TSS.Gateway.Sdk.Requests";

// Payload messages for the requests published on tss-requests-publish and the queries published on
// tss-api-publish, plus the Response envelope every query answer is wrapped in.
//
// Conventions used throughout:
// - Assets and scenes are addressed by either their uuid or their integration id (a oneof).
// - Positions and sizes are in pixels on the screen's canvas, origin at the bottom-left, y up.
// - Volumes and progress are normalized: 0 to 1.

// The envelope of every query response: either the error or the field matching the query.
message Response {
    oneof response {
        Error error = 1;
        Ok Ok = 2;
        StoryStatusResponse storyStatus = 3;
        AvailableStoriesResponse availableStories = 4;
        AvailableScenesResponse availableScenes = 5;
        CurrentStateResponse currentState = 6;
        InstanceInfo instanceInfo = 7;
        CorruptedAssetsResponse corruptedAssets = 8;
        StoryDataResponse storyData = 9;
        AvailableStory availableStory = 10;
        UrlAssetStreamAnswer urlAssetStreamAnswer = 11;
    };
}

message Ok {
}

// The player rejected the request or query.
message Error {
    string message = 1; // Human-readable reason.
    int32 code = 2;
}

// Answer to story.status.
message StoryStatusResponse {
    State status = 1;
    string storyTitle = 2;
    int32 storyVersion = 3;
    int32 transitionDurationMs = 4; // Duration of the running scene transition, 0 outside one.
    string storyUuid = 5;
}

// Answer to story.available-stories.
message AvailableStoriesResponse {
    repeated AvailableStory stories = 1;
    int32 count = 2; // Number of stories matching the search, before offset and limit are applied; the total to page through.
}

// One story that is synced to this player. Also the answer to story.available-story.
message AvailableStory {
    string uuid = 1;
    string name = 2;
    string author = 3;
    google.protobuf.Timestamp authoredAt = 4;
    google.protobuf.Timestamp compiledAt = 5;
    string description = 6;
    AvailableStoryStatus status = 7;
    google.protobuf.Timestamp lastPlayedAt = 8;
    repeated int32 availableVersions = 9; // Versions on this player; StoryStartRequest.version must be one of these.
    Thumbnails thumbnails = 10;
}

// Answer to story.available-scenes: the scenes of the running story.
message AvailableScenesResponse {
    repeated AvailableScene scenes = 1;
    optional string screensaverUuid = 2;
}

message AvailableScene {
    string uuid = 1;
    string title = 2;
    Thumbnails thumbnails = 10;
}

message StoryStartRequest {
    string storyUuid = 1;
    optional int32 version = 2; // Specific version to start; absent starts the newest version on the player.
    bool suppressPlaybackTracking = 3; // True skips the last-played bookkeeping, meant for automated smoke tests.
}

message VolumeChangeRequest {
    float volume = 1; // Master volume, 0 to 1. Values outside that range are rejected.
}

// Answer to scene.status: the active scene and the current state of its assets.
message CurrentStateResponse {
    Scene scene = 1;
    repeated Asset assets = 2;
    string storyTitle = 3;
    float volume = 4; // Master volume, 0 to 1.
}

// Addresses the scene by uuid, integrationId, or sceneIndex. The screensaver scene is index 0, the
// other scenes count from 1 in story order; index 0 is an error when the story has no screensaver.
message SceneChangeRequest {
    oneof scene {
        string uuid = 1;
        string integrationId = 2;
        int32 sceneIndex = 3;
    }
}

// Addresses one asset by uuid, or every asset carrying the integration id.
message AssetRequest{
    oneof asset {
        string uuid = 1;
        string integrationId = 2;
    }
}

message AssetSeekRequest {
    oneof asset {
        string uuid = 1;
        string integrationId = 2;
    }
    float normalizedProgress = 3; // Target position in the media, 0 (start) to 1 (end).
}

message AssetVolumeChangeRequest {
    oneof asset {
        string uuid = 1;
        string integrationId = 2;
    }
    float normalizedVolume = 3; // 0 to 1. Values outside that range are rejected.
}

// Moves the asset's bottom-left corner, in canvas pixels.
message AssetMoveRequest {
    oneof asset {
        string uuid = 1;
        string integrationId = 2;
    }
    float left = 3;
    float bottom = 4;
}

message AssetPageChangeRequest {
    oneof asset {
        string uuid = 1;
        string integrationId = 2;
    }
    int32 page = 3; // Zero-based page index, 0 to pageCount - 1. Out-of-range values are rejected.
}

message AssetContentChangeRequest
{
    oneof asset {
        string uuid = 1;
        string integrationId = 2;
    }
    string content = 3; // New text (text asset) or image uri (image asset). Rejected when it equals the current content.
}

// Crops the asset by moving its edges inward. Margins are pixels measured from the asset's
// original edges, must be 0 or positive, and fields left out keep their current value.
message AssetCropRequest {
    oneof asset {
        string uuid = 1;
        string integrationId = 2;
    }
    optional int32 left = 3;
    optional int32 top = 4;
    optional int32 right = 5;
    optional int32 bottom = 6;
}

// Animates the asset to a new rectangle over animationTimeInMs. Fields left out keep their
// current value. Position and size in canvas pixels, x/y is the bottom-left corner.
message AssetAnimateRectRequest {
    oneof asset {
        string uuid = 1;
        string integrationId = 2;
    }
    optional float height = 3;
    optional float width = 4;
    optional float x = 5;
    optional float y = 6;
    int32 animationTimeInMs = 7;
}

// Resizes and/or repositions the asset immediately. Fields left out keep their current value.
// Position and size in canvas pixels, left/bottom is the bottom-left corner.
message AssetResizeRequest {
    oneof asset {
        string uuid = 1;
        string integrationId = 2;
    }
    optional float left = 3;
    optional float bottom = 4;
    optional float width = 5;
    optional float height = 6;
}

message UrlAssetInputRequest{
    oneof asset {
        string uuid = 1;
        string integrationId = 2;
    }
    string key = 3; // The key to send to the page, a character or a key name such as "Enter".
}

message UrlAssetTouchRequest{
    oneof asset {
        string uuid = 1;
        string integrationId = 2;
    }
    UrlTouch touch = 3;
}

// Loads another page in a url asset for the rest of the scene. The authored url stays the asset's
// home, so back and home still return to it, and leaving the scene restores it.
message AssetUrlChangeRequest {
    oneof asset {
        string uuid = 1;
        string integrationId = 2;
    }
    string url = 3; // Rejected when it is not a http or https url, or when it is the page already loaded.
}

// Query asset.stream-offer: starts a WebRTC stream of a URL asset for one viewer, sent straight to the
// viewer over the local network; the gateway only carries the handshake. The stream is H.264 at up to
// 30 fps without audio. It keeps the asset's aspect ratio and fits in maxWidth x maxHeight, never above
// the asset's own size, 3840 on either side or the pixel count of 3840x2160.
// The player runs up to maxUrlStreams streams at a time (default 4), over all its URL assets, and
// rejects the offer with code 716 once that limit is reached. A stream ends when the asset unloads, on
// asset.stream-stop, or a few seconds after the viewer disappears.
message UrlAssetStreamOfferRequest {
    string uuid = 1; // One asset only, so there is no integration id.
    string sdp = 2; // Complete offer SDP with ICE gathering finished; candidates are not sent separately.
    optional int32 maxWidth = 3; // Largest size the viewer shows the stream at, in device pixels; absent leaves it to the other limits.
    optional int32 maxHeight = 4;
    optional int32 maxBitrateKbps = 5; // Encoder bitrate cap; absent scales with the stream size, 8000 at 1920x1080 up to 30000 at 3840x2160.
}

// Answer to asset.stream-offer.
message UrlAssetStreamAnswer {
    string sdp = 1; // Complete answer SDP with ICE gathering finished.
    string sessionId = 2; // Identifies this viewer's stream; asset.stream-resize and asset.stream-stop take it.
}

// Request asset.stream-resize: the room the viewer shows the stream in changed. The player changes the
// running stream's size, and its bitrate cap when the offer set none, without a new offer. Resizes
// closer together than half a second are applied once, with the latest size.
message UrlAssetStreamResizeRequest {
    string uuid = 1; // The streamed asset.
    string sessionId = 2; // From UrlAssetStreamAnswer.
    int32 maxWidth = 3; // In device pixels, same rules as UrlAssetStreamOfferRequest.
    int32 maxHeight = 4;
}

// Request asset.stream-stop: stops one viewer's stream; other viewers of the asset keep streaming.
message UrlAssetStreamStopRequest {
    string uuid = 1; // The streamed asset.
    string sessionId = 2; // From UrlAssetStreamAnswer.
}

message TriggerFireRequest {
    string triggerUuid = 1;
    optional bool state = 2; // For toggle actions: true forces show, false forces hide, absent toggles.
    string sourceAssetUuid = 3; // The pressed asset when the player fires an on-click trigger; empty for other firers.
    string sourceAssetIntegrationId = 4;
}

// Answer to instance.info.
message InstanceInfo {
    string screenName = 1;
    string setupName = 2;
    int32 width = 3; // Screen resolution in pixels.
    int32 height = 4;
    string setupUuid = 5;
    int32 screenId = 6;
}

// Answer to story.corrupted-assets: assets of the running story that failed to load, per scene.
message CorruptedAssetsResponse {
    repeated CorruptedScene scenes = 1;
}

message CorruptedScene {
    string uuid = 1;
    string integrationId = 2;
    string name = 3;
    repeated CorruptedAsset assets = 4;
    int32 index = 5; // Zero-based position of the scene in the story's scene order.
}

message CorruptedAsset {
    string uuid = 1;
    string integrationId = 2;
    string name = 3;
    int32 code = 4; // Player error code describing why the asset failed to load.
    CorruptedAssetType type = 5;
}

message StoryDataRequest {
    string uuid = 1;
    int32 version = 2;
}

// Answer to story.data: the full story structure, see models.proto.
message StoryDataResponse {
    Story story = 1;
}

enum CorruptedAssetType
{
    UNDEFINED = 0;
    VIDEO = 1;
    IMAGE = 2;
    TEXT = 3;
    SOUND = 4;
    URL = 5;
    NDI = 6;
    PDF = 7;
}

// Query for story.available-stories.
message AvailableStoriesRequest {
    SortDirection sortDir = 1;
    StorySortBy sortBy = 2;
    string search = 3; // Filters on the story name, description and author, tolerating typos and partial words; "quoted text" matches as a phrase. Empty returns every story.
    int32 offset = 4;
    int32 limit = 5; // Maximum number of stories returned. The protobuf default of 0 returns none, so always set it.
}

message AvailableStoryRequest {
    string uuid = 1;
}

enum AvailableStoryStatus
{
    UNKNOWN = 0;
    INITIALIZING = 1;
    READY = 2;
    IN_USE = 3;
    INITIALIZATION_ERROR = 4;
    DRAFT = 5;
    UPDATING = 6;
}

// Playback state of the player.
enum State
{
    NONE = 0;
    STARTING = 1;
    RUNNING = 2;
    CLOSING = 3;
    TRANSITIONING = 4;
    ERROR = 5;
    PREPARING_TRANSITION = 6;
}

enum SortDirection
{
    ASC = 0;
    DESC = 1;
}

enum StorySortBy
{
    NAME = 0;
    AUTHOR = 1;
    AUTHORED_AT = 2;
    COMPILED_AT = 3;
    LAST_PLAYED_AT = 4;
}