Establish Live WebRTC WebSockets Channel

Start a long lived WebRTC control channel that can be used to support Trickle ICE.

This call establishes a long term encrypted WebSockets control channel for WebRTC and is designed to be used when you want a persistent control channel with support for Trickle ICE, instead of the REST API's provided in the other WebRTC endpoints. The channel established is pegged to a single AccessoryAccessory - A unique device within the system. An accessory can be any of type and is represented by a unique Accessory Id. An accessory is linked to an account via an accountId. Within this API, a singular Circle camera is an Accessory., but can live over multiple sessions.

🚧

Your WebRTC client must support Trickle ICE if you use this API call.

This call starts as an HTTP GET, but will get upgraded into a WebSockets connection either directly via a 301 Redirect or a response header.

The primary reason to use this function over the REST API based WebRTC calls is too support Trickle ICE which results in faster call establishment in most network scenarios. The WebSockets based transport will allow for streaming of the ICE candidates from the camera as they are generated.

The WebSockets channel uses a message framing layer to transport actions and their data. The actions are the same basic WebRTC commands implemented in the REST API endpoints of Get Live WebRTC Offer, Provide Live WebRTC Answer Async, Provide Live WebRTC Offer and Get Answer, and Stop Live WebRTC.

Important Notes

  • Your WebSockets client MUST send Ping frames at least once an hour or the connection may drop due to the Firewall or NATs. If you are using a browser implementation this is handled automatically for you.
  • If the WebSockets connection drops, timeouts or is disconnected by the server, you must reinitiate via this main API call, not the redirected URL provided.
  • If you do reconnect, you must maintain any sessionId's for active calls that are still ongoing. It is possible and likely the WebControl channel can drop and re-establish without the underlying peer-to-peer call failing.

Permissions

Requires a Permissions scope of: circle:live

WebSockets Protocol

This protocol MUST be indicated using the WebSockets sub-protocol value of com.logi.circle.webrtc uisng the text type.

Every WebSockets message of type com.logi.circle.webrtc is comprised of a serialized JSON object with two required keys: action and sessionId. Additional keys may be present based on the specific action.

Name

Type

Description

action

string

The action name of the message being sent or received. See the Action Types section for details.

sessionId

string

The session Id this message applies too. This field is always present and contains a value except in the requestOffer action where it is an empty string.

Action Types

The table below lists all of the supported action types. The Sendable column means that your client can send this message. The Receivable column indicates if your client can receive this message.

Action Name

Sendable

Receivable

Description

requestOffer

yes

yes

If you send this, or set requestOffer query param, this will requests the camera to generate an offer. If you receive this command, the Circle system wants your client to initiate the Offer/Answer process.

offer

yes

yes

A WebRTC Offer object is contained within this message.

answer

yes

yes

A WebRTC Answer is contained within this message.

iceCandidate

yes

yes

A WebRTC candidate is contained within this message.

end

yes

yes

Request to end an established WebRTC call.

requestOffer Action Type

The requestOffer action type requests the receiver to begin the process of generating an offer. This action is implied automatically at the server if the query param requestOffer is true. Using the query param is highly encouraged as it reduces the overall call setup latency when having the camera generate the initial Offer. The additional keys of this call contain the same audio and video entries as the query param list.

In battery powered cameras that have a wake-up delay, the Circle servers may respond to this message with its own requestOffer to your client so that your client can begin the ICE candidate generation process while the camera is waking up from low-power sleep. This leads to a significant lower latency during call setup.

The other reason your client may send this action is to establish a new call to the same AccessoryAccessory - A unique device within the system. An accessory can be any of type and is represented by a unique Accessory Id. An accessory is linked to an account via an accountId. Within this API, a singular Circle camera is an Accessory. after an end action already occured.

Name

Type

Sendable

Receivable

Description

audio

string

yes

yes

What directionality should the audio stream have. Valid values are:
sendrecv - The camera should send audio and support receiving push-to-talk audio content.
sendonly - The camera should send audio. No support for push-to-talk is requested.
none - Indicates no audio stream is requested.

video

string

yes

yes

What directionality should the video stream have. Valid values are:
sendonly - The camera should send video.
none - Indicates no video stream is requested. This allows for an audio-only low bitrate stream.

iceTransportPolicy

string

no

yes

See iceTransportPolicy under the offer for full details and use of this data.

iceServers

array of objects

no

yes

See iceServers under the offer for full details and use of this data.

offer Action Type

The offer action type is used to convey the WebRTC Offer. The same payload fields as the response for Get Live WebRTC Offer. If your client side is providing the offer as is done in Provide Live WebRTC Offer and Get Answer, then you must provide valid iceServers or otherwise only host candidates can be generated. Logitech does not export an API for just requesting iceServers, and they are only returned when using the requestOffer action type.

A session renegotiation can be initiated by sending a new offer action type for an existing sessionId. This is equivalent to the Renegotiate Live WebRTC REST call.

If offer is the first message in the call sequence (from either side), then the sessionId value it presents will be used for the rest of the sessions life-cycle. If your client originates the offer, you can pass whatever string based value you want for sessionId.

Name

Type

Description

sdp

string

The full WebRTC compliant SDP blob. This should be passed directly to the Javascript or Native API's which consume Offers such as RTCPeerConnection.setRemoteDescription()

iceTransportPolicy

string

The current ICE transport policy. This field must be set as the iceTransportPolicy key within the RTCConfiguration object passed to the RTCPeerConnection() constructor in your WebRTC stack.Valid values are:

all - (default) All ICE candidates will be considered.
relay - Only ICE candidates from TURN servers, will be considered.

iceServers

array of objects

An array of iceServers and its configuration. This field must be set as the iceServers key within the RTCConfiguration object passed to the RTCPeerConnection() constructor in your WebRTC stack.

answer Action Type

The answer action type is used to convey the WebRTC Answer. The payload contains the same fields as the request in Provide Live WebRTC Answer Async

Name

Type

Description

sdp

string

The full WebRTC compliant SDP blob.

iceCandidate Action Type

The iceCandidate action type is used to transmit a new ICE Candidate as part of the Trickle ICE process. This message serves as a conduit for both sides to exchange new candidates as they become available. The object contains the same members as the RTCIceCandidateInit object and is meant to be fed directly to the RTCPeerConnection.addIceCandidate() function in Javascript.

Name

Type

Description

candidate

string

The ICE candidate value.

sdpMLineIndex

integer or null

The ICE SDP Media Line Index this candidate belongs to.

sdpMid

string or null

The ICE SDP media ID this candidate refers too.

usernameFragment

string or null

The ICE username fragment for this candidate.

end Action Type

The end action type is used to indicate a request to terminate the call. If you receive this message, the far side initiated the termination. If you send this message you must supply a reason field. This action type is equivalent to calling Stop Live WebRTC.

Name

Type

Description

reason

string

The reason for the call ending. Must be one of:
none - No specified reason.
hangup - The user initiated a hangup of the call.
peer_connection_failed - The underlying ICE stack reported a failure on the PeerConnection.

Sample Messages

websocket = new WebSocket("wss://api.circle.logi.com/api/accessories/70e3e6f9-70c3-45b2-62e4-ace3d027988a/live/webrtc/session?requestOffer=true", "com.logi.circle.webrtc");
            
websocket.onopen = function(evt) {
  console.log("Socket is open");
};
    
websocket.onerror = function(evt) {
  console.log("Socket Error: " + evt.data);
};

websocket.onmessage = function(event) {
  if(typeOf event.data != "string" ) {
    console.log("Error. Bad message received. No data: " + event);
    return;
  }
  
  //create a JSON object
  var jsonObject = JSON.parse(event.data);
  if (typeOf jsonObject.action != 'string' || typeOf jsonObject.sessionId != 'string')
  {
    console.log("Error. Bad message received. Missing required keys: " + event.data);
    return;
  }
  
  // Valid object found with the required keys.
  var action = jsonObject.action;
  var sessionId = jsonObject.sessionId;
  console.log("Received the message: " + jsonObject);
}

function sendMessage(actionName, sessionId, actionData) {
  var dataToSend = {
    action:actionName, 
    sessionId: sessionId,
    ...actionData
  }
    websocket.send(JSON.stringify(dataToSend));
}

function closeSocket() {
    websocket.close();
}
// 1. requestOffer - Sent from your client to the server. 
{
  "action":"requestOffer",
  "sessionId": "",
  "audio": "sendrecv",
  "video": "sendonly"
}


// 2. requestOffer - Sent back from our server because the camera is in deep-sleep.
{
  "action":"requestOffer",
  "sessionId": "",
  "audio": "sendrecv",
  "video": "sendonly",
  "iceTransportPolicy": "all",
  "iceServers": [
    {
      "urls": ["stun:stun.video.logi.com:19302"]
    },
    {
      "urls": ["turns:node-i-0af43d950d489ce80.video.logi.com:443?transport=tcp"],
      "username": "fasf09832t78yasdnmskjhasd",
      "credential": "aslkjfs83qn6nkangjsddsd"
    }
  ],
}
// offer sent from the camera
{
  "action": "offer",
  "sessionId": "623837789654644768",
  "sdp": "v=0 .... Rest of SDP Payload ....",
  "iceTransportPolicy": "all",
  "iceServers": [
    {
      "urls": ["stun:stun.video.logi.com:19302"]
    },
    {
      "urls": ["turns:node-i-0af43d950d489ce80.video.logi.com:443?transport=tcp"],
      "username": "fasf09832t78yasdnmskjhasd",
      "credential": "aslkjfs83qn6nkangjsddsd"
    }
  ]
}
// new candidate with the data being the Opaque RTCIceCandidate dictionary
{
  "action": "iceCandidate",
  "sessionId": "623837789654644768",
  "candidate":"candidate:829056235 1 udp 2122260223 192.168.100.28 53618 typ host generation 0 ufrag NgCj network-id 1 network-cost 10",
  "sdpMLineIndex":0,
  "sdpMid":"audio",
  "usernameFragment": "NgCj"
}
// answer sent from your client
{
  "action": "answer",
  "sessionId": "623837789654644768",
  "sdp": "v=0 .... Rest of SDP Payload ...."
}
// close sent from your client
{
  "action": "end",
  "sessionId": "623837789654644768",
  "reason": "hangup" 
}

WebSockets Close Event

The com.logi.circle.webrtc WebSockets sub-protocol defines some application level close status codes that your client must implement properly.

Code

Sendable

Receivable

Description

1013

no

yes

The server wants you to reconnect after a few seconds of delay since the camera is moving to a new server. This is the WebSockets equivalent of the 410 - Gone.

4000

no

yes

Bad request - Your client sent a malformed message or bad JSON frame. This is the WebSockets equivalent of the 400 - Bad Request. This doesn't invalidate any established sessionId's.

4001

yes

no

Your client is disconnecting, but don't implicitly disconnect any underlying sessions that you started.

4002

yes

yes

Normal user initiated close.

Language
Authentication
OAuth2