Skip to main content

Introducing the API meeting observer!

· 5 min read
Stefan Benicke

Picture of a man looking through binoculars

We're adding a new way for developers to receive information about a meeting in real-time!

Introducing the "Meeting Observer", a one-way WebSocket connection that allows to boost your application's meeting controls.

It is easier to use than the existing WebHooks and even more powerful, since a lot more information can be observed.

If you want to skip the introduction and get your hands on, head over to the observer documentation.

Setup

The WebSocket connection is based on the rails actioncable protocol.

To connect to the observer, you need to authenticate with your API key. If you don't have it already, here's how to get your API key. Depending on your preferred programming language, you might already find a useful library for "Actioncable" or its successor "AnyCable".

The URL is the API's origin "https://api.eyeson.team", followed by "/rt" (for "realtime") and "room_id" as query parameter.

https://api.eyeson.team/rt?room_id=651b0c4c3ae7400ea35db31fs

room_id is required, since each observer connects to a single meeting room and receives all events related to the given room_id.

There are 3 ways to include the API key.

  • "Authorization" header
  • API key as WebSocket protocol
  • Query parameter "api_key=<YOUR_API_KEY>"

And last but not least, you have to subscribe to the RoomChannel to make it work.

As soon as the meeting shuts down, the connection is closed automatically.

Events

In contrast to WebHooks, the observer provides a lot more event types. Besides room_update and recording_update you will get notified for

  • snapshots,
  • broadcasts,
  • participants,
  • chat messages,
  • playbacks,
  • and layout changes.

All events, including examples, are listed in the documentation.

Here are some examples to give you an idea.

Room update

All meeting room options and its ready and shutdown states are included in the room_update event.

{
"type": "room_update",
"content": {
"id": "6576daef1f138900153d0762",
"name": "Observer demo",
"ready": true,
"started_at": "2023-12-11T09:48:32.031Z",
"shutdown": false,
"guest_token": "jCWzhzCWONkbIubUYF7PD3hP",
"options": {
"show_names": true,
"show_label": true,
"exit_url": null,
"recording_available": true,
"broadcast_available": true,
"layout_available": true,
"layout": "auto",
"reaction_available": true,
"suggest_guest_names": true,
"lock_available": true,
"kick_available": true,
"sfu_mode": "ptp",
"layout_users": null,
"layout_name": null,
"layout_map": null,
"voice_activation": false,
"custom_fields": {},
"widescreen": true,
"background_color": "#121212"
},
"participants": [],
"playbacks": [],
"presentation": null,
"broadcasts": [],
"recording": null
}
}

Example room_update event where ready state is true

Participant update

You can find out when a participant joins or leaves the meeting in real-time. With the given participant ids, you can easily adjust the meeting layout, for example.

{
"type": "participant_update",
"participant": {
"id": "test@observer.com",
"room_id": "6576daef1f138900153d0762",
"name": "Observer",
"avatar": null,
"guest": false,
"online": true
}
}

Example participant_update event with online state true

Chat message

Messages via messages API are forwarded to the observer. With this in place, your app can log the chat, or even react to it.

{
"type": "chat",
"content": "Hello world!",
"cid": "6576daf01f138900153d0764",
"user_id": "test@observer.com",
"created_at": "2023-12-11T09:59:33.892Z"
}

Example chat event

Podium update

There's even one more incredibly useful event, called podium_update, that provides all information about the current video podium. The exact position and size of each of the layout boxes and its current content. So you know which user or playback is visible and on which position.

{
"type": "podium_update",
"podium": [
{
"user_id": null,
"play_id": "presentation-video",
"width": 1280,
"height": 600,
"left": 0,
"top": 0,
"z-index": 0
},
{
"user_id": "userA@myawesomeapp.com",
"play_id": null,
"width": 214,
"height": 120,
"left": 0,
"top": 600,
"z-index": 1
},
{
"user_id": "userB@myawesomeapp.com",
"play_id": null,
"width": 213,
"height": 120,
"left": 214,
"top": 600,
"z-index": 2
},
{
"user_id": "userC@myawesomeapp.com",
"play_id": null,
"width": 213,
"height": 120,
"left": 427,
"top": 600,
"z-index": 3
},
{
"user_id": "userD@myawesomeapp.com",
"play_id": null,
"width": 213,
"height": 120,
"left": 640,
"top": 600,
"z-index": 4
},
{
"user_id": "userE@myawesomeapp.com",
"play_id": null,
"width": 213,
"height": 120,
"left": 853,
"top": 600,
"z-index": 5
},
{
"user_id": "userF@myawesomeapp.com",
"play_id": null,
"width": 214,
"height": 120,
"left": 1066,
"top": 600,
"z-index": 6
}
]
}

Example podium_update event with layout "present-upper-6" including a playback

note

The complete list of events is in the documentation.

Example code

Here are simplified examples that demonstrate the usage of the meeting observer.

import WebSocket from 'ws';
import { createCable } from '@anycable/core';

let cable = null;

const connect = (room_id) => {
const url = `https://api.eyeson.team/rt?room_id=${room_id}`;
cable = createCable(url, {
websocketImplementation: WebSocket,
websocketOptions: {
headers: {
'Authorization': process.env.API_KEY,
},
},
});
const channel = cable.subscribeTo('RoomChannel');
channel.on('message', onMessage);
channel.on('connect', onConnected);
channel.on('disconnect', onDisconnected);
};

const disconnect = () => {
if (cable) {
cable.disconnect();
cable = null;
}
};

const onMessage = message => {
if (message.type === 'room_update') {
if (message.content.ready === true) {
console.log('Meeting ready');
}
if (message.content.shutdown === true) {
console.log('Meeting shutdown - disconnect');
disconnect();
}
}
};

const onConnected = () => {
console.log('Connected');
};

const onDisconnected = ({ name, message, reason }) => {
console.log('Disconnected', name, message, reason);
if (reason === 'unauthorized') {
disconnect();
}
};

Contact

We'll be happy to hear from you!

If you have a question or want to share any feedback, do not hesitate to create a ticket on GitHub.