How to: Manage Status and State

Managing integration status and heartbeats


Introduction

This guide covers how to manage status and keep a synchronous state with Frame.io. We use a websocket protocol, if that is un-familiar to you, that is okay, we will try our best to help you familiarize yourself with websockets and how to best implement them.

Websockets allow Frame.io to push messages back down to the device, and because a websocket maintains a persistent connection they're more efficient.

In this guide we will go over how to:

  • Open a socket connection to let Frame.io know the device is ‘online’.
  • Fetch information about a device connection.
  • Check if the Frame.io backend is reachable.

What will I need?

If you haven’t read the Implementing C2C: Setting Up guide, give it a quick glance before moving on!

You will also need the access_token you received during the hardware device or C2C Application authentication and authorization guide. Be aware, this lasts for 8 hours, so you will either need to refresh the token or go through the authorization process again.

For connecting to the socket in this guide we recommend the CLI websocat. It has great installation instructions for numerous operating systems.

MacOS

brew install websocat

Fetching connection information

The first thing your device should do after any new authorization or token refresh is use the identity endpoint. We can fetch information about our connection by making the following call:

Shell
curl -X GET https://api.frame.io/v2/devices/me \
    --header 'Authorization: Bearer [access_token]' \
    --header 'x-client-version: 2.0.0' \
    | python -m json.tool

We should get a response like so (some data elided):

{
    "_type": "project_device",
    "id": "a7e95254-8cd6-4d59-b54d-28c58570a8de",
    "asset_type": "video",
    "authorization": {
        "_type": "project_device_authorization",
        "creator": {
            "_type": "user",
            "id": "e7e96254-8bd6-4d59-b54d-28c58570a8de",
            "name": "Harry Potter"
        },
        "expires_at": null,
        "id": "7b2b68e5-788d-497c-8597-f9362cb1a75e",
        ...
        "project_device_id": "14856308-46e0-4d7d-8438-320262eec74e",
        "scopes": {
            ...
            "asset_create": true,
            ...
            "id": "0fe0accb-447f-44f6-b2af-177d913b3a29",
            "offline": true,
            ...
        }
    },
    ...
    "name": "Frameio-BPEAKE-TEST-DEVICE",
    "project": {
        "_type": "project",
        "id": "2ad59fe6-77b6-4fbc-a9d2-3dd0413ed4a3",
        "name": "Testbed"
    },
    "project_id": "2ad59fe6-77b6-4fbc-a9d2-3dd0413ed4a3",
    "status": "online",
    ...
}

We can use this endpoint to verify the project we are connected to, as well as who originally authorized the device. We should display the following to the user:

  • project.name - The name of the project we are connected to.
  • authorization.creator.name - The user who originally paired / authorized the device.
  • authorization.expires_at (optional) - When the device connection expires (can be set at any time).
  • status (optional) - The status of the device. Can be:

    • online - The device is online and paired.
    • offline - The device has not emitted any activity in more than 5 minutes, although the act of invoking this endpoint will cause the status to change to online as soon as the response is returned.
    • paused - The device has been paused in the C2C Connections tab of Frame.io.

Because expiration time / paused state can be set at any point in Frame.io, it’s a good idea to periodically poll this information if you wish to display it to the user. We ask that you do not poll this endpoint more than once every 60 seconds.

id

You will need the id key for the next section

Connecting to socket

In the C2C Connections tab of your Frame.io project, you will see that your device has an online or offline status. When the device is online, a small green indicator will light up in the top-left corner of the device card. When the device is offline, the UI of the card will become greyed-out.

When a device has an active socket connection, the status will be online and when a device does not have an active socket connection, the status will be offline.

The socket connection will terminate via our servers protocols if no ‘heartbeat’ has been heard from the device every 60 seconds. These messages are very light, so it is our recommendation to emit them every 15 seconds. If the socket connection closes for some unforeseen reason, no worries, just re-open the connection and start from the beginning.

Opening the socket connection to Frame.io is a two step process:

  1. Establish the TCP/IP handshake and open the physical websocket connection.
  2. Join the devices channel — this channel is what tells our backend which device we are communicating with so we can handle and send messages correctly.

To Open the websocket connection make the following call:

Shell
websocat -n "wss://api.frame.io/devices/websocket?Authorization=Bearer ACCESS_TOKEN"
The Authorization Header

For every end point that requires authorization, we need to add the access_token to the Authorization header. For the websocket connection, the token does not go in the header but is rather appended as a url encoded query string. Notice that we still need to pre-append Bearer (with a space!) to our access token as the value. NOTE: in url encoded strings a space is represented by %20 so this is not uncommon to see as some libraries do not play nicely with spaces.

You should get a 101 response code, which simply means you are switching protocols to wss and the socket connection was accepted. Your internal websocket library might handle all this for you. If your token is expired you will see a 403 response code.

Next we need to join the device's channel. With the active socket connection to from above, Simply send a json message like the following, using the id from your connection information for the topic string. NOTE: websocat requires the message is on a single line, the server will accept formatted json.

JSON
{"topic":"devices:YOUR_DEVICE_ID", "event":"phx_join", "payload":"", "ref":"channel_connect"}

You’ll see a reply like this:

JSON
{"event":"phx_reply","payload":{"response":{},"status":"ok"},"ref":"channel_connect","topic":"devices:YOUR_DEVICE_ID"}
The ref and payload fields

The ref field is used to delineate which responses belong to which event. In practice, event ordering is not guaranteed, the ref is used to pair responses from our server with the event that it is responding to. The Frame.io server does not use the ref field for incoming events, it is purely a tool used by the caller. The payload field must always be present, but in many cases it can just always be an empty string ( we will go over any events that need the payload field in more detail ).

That’s it, check the C2C dashboard and you should see your device online! We recommend launching a thread / async task / cron job in your integration to make this call, or the socket connection will close after 60 seconds of inactivity:

Python
def heartbeat_task():
    """
    Task that emits heartbeats every 15 seconds.
    """

    while True:
        c2c.emit_socket_heartbeat()
        sleep(15)

The payload for heartbeat can look exactly like this:

JSON
{"topic":"phoenix", "event":"heartbeat", "payload":"", "ref":"heartbeat"}

You’ll see a reply like this:

JSON
{"event":"phx_reply","payload":{"response":{},"status":"ok"},"ref":"heartbeat","topic":"phoenix"}

Notice with the active socket connection and join on a channel, the device in the C2C Connections tab, where you entered the 6 digit code, within Frame.io will show your device as online. Disconnect from the socket and the device will appear as offline.

Displaying the device status

The status returned in the identity payload should not be displayed directly. online or offline is not meaningful to the end user, as it only indicates whether the device has communicated to our backend within the last 5 minutes.

Status should really be broken into two fields:

  • Paused: true / false - If the status field above is paused, the should display true, otherwise false.
  • Connected: true / false - Whether the device can reach the backend (see backend connection status below).

Handling the paused status

You are not required to display the paused status to the user, but if you choose to do so, it is important you understand how this status works.

The paused status is meant to block sensitive content created during a window of time. It is not designed to block network traffic. Imagine you are on set and about to film a scene that contains nudity. An Actor, Director, or Producer might request that this footage not make its way to Frame.io to protect the actors’ privacy. Instead of completely disconnecting your C2C devices, you can simply pause them, and any footage created between the time the device is paused to the time it is unpaused will be rejected from upload.

Pausing a device is done in the Frame.io UI on our end, and is not an input you as an integrator are responsible for.

While a device is paused, if there is queued media that was created during an unpaused window, such media can still be uploaded.

You should not use the identity endpoint to validate whether you can upload a piece of media. Our backend does that for you! We’ll go over handling the paused status for uploads in the uploading guide. In this guide, we simply want to know how to display the status:

  • If you recieve an event from your socket connection. The event will be "status_updated" and the payload will either be "paused" or "resumed".
  • Events can help you as an integrator, but events can be missed and can be delivered out of order. So if you try to upload an asset while paused you will get a 409 error. You may get a 409 for an older piece of media that was made during a past pause window. Don't assume that because you get a 409, the device is currently paused. We use the offset parameter when creating an asset to ensure assets created during the paused window don't upload after the device has been unpaused.
  • If you are currently displaying a paused status, and are able to create a new asset, fetch the connection info and see if you have been unpaused (status will be online or offline), and update the status for the user. Don't assume that because you are able to upload a new piece of media, your device is unpaused. You may have just uploaded a piece of media that was created during an unpaused window.

Backend connection status

If you want to check whether or not you can communicate to Frame.io, you can make a call to the following endpoint:

curl -X GET https://api.frame.io/health \
    | python -m json.tool

This endpoint does not require authorization. If you are able to communicate to the server, you should get:

{
    "ok": true
}

Using https://api.frame.io/health can be useful for checking connected status since it ensures you can communicate with Frame.io specifically. There may be cases where your network is up and connected, but Frame.io is unreachable, either due to a problem on our end or because a portion of the internet is down that Frame.io relies on.

Next up

If you haven’t already, we encourage you to reach out to our team, then continue to the next guide. We look forward to hearing from you!