Room

Televisit Room

Configuring Room Triggers

There are three special trigger events for the room object: room.after, participant.after and track.after. Each occurs in response to a web hook call from the video provider. These events are also recorded in the room's events[] list.

Note recording.after and composition.after will be implemented in future versions.

To handle events triggered by the remote room provider, insert these Cortex script triggers.

org.objects.scripts.insertMany([{
  type: 'trigger',
  active: true,
  configuration: {
    event: 'room.after',
    object: 'room',
  },
  description: 'c_room_room_event',
  label: 'c_room_room_event',
  name: 'c_room_room_event',
  principal: null,
  script: `
    const { arguments: { event, old: room }, context } = script 
    require('logger').trace(event)
  `
},{
  type: 'trigger',
  active: true,
  configuration: {
    event: 'participant.after',
    object: 'room',
  },
  description: 'c_room_participant_event',
  label: 'c_room_participant_event',
  name: 'c_room_participant_event',
  principal: null,
  script: `
    const { arguments: { event, old: room }, context } = script 
    require('logger').trace(event)
  `
},{
  type: 'trigger',
  active: true,
  configuration: {
    event: 'track.after',
    object: 'room',
  },
  description: 'c_room_track_event',
  label: 'c_room_track_event',
  name: 'c_room_track_event',
  principal: null,
  script: `
    const { arguments: { event, old: room }, context } = script 
    require('logger').trace(event)
  `
}]).execute()

Room Events

All room events share the following properties:

  • type { String } Indexed room event type [room, participant, track]

  • name { String } Indexed room event name. created, ended, connected, etc.

  • order { Number } Indexed integer representing the order in which the remote event was fired. It's possible that

    events are called and written out of order. The order property may be used to present the remote timeline.

  • roomId { ObjectID } Indexed originating local room identifier.

room.after :: room.created - Room is open and available for connection.

{
  type: 'room',
  name: 'created',
  order: 0,
  roomId: '5df02d890535377c38cfdeef'
}

room.after :: room.ended - Room is closed, or ended due to a timeout (empty for 5 minutes).

  • duration { Number } The number of seconds the room was active.

{
  type: 'room',
  name: 'ended',
  order: 12,
  roomId: '5df02d890535377c38cfdeef',
  duration: 156 
}

participant.after :: participant.connected - Participant entered a room

  • status { String } The current status of the participant generating this event - either connected or disconnected.

  • accountId { ObjectID } The id of the account generating the event.

{
  type: 'participant',
  name: 'connected',
  order: 1,
  roomId: '5df02d890535377c38cfdeef',
  status: 'connected',
  accountId: '58c87b958b8f160100812b70'
}

participant.after :: participant.disconnected - Participant left a room

  • status { String } The current status of the participant generating this event - either connected or disconnected.

  • accountId { ObjectID } The id of the account generating the event.

  • duration { Number } The number of seconds the participant was connected to the room.

{
  type: 'participant',
  name: 'disconnected',
  order: 8,
  roomId: '5df02d890535377c38cfdeef',
  status: 'disconnected',
  accountId: '58c87b958b8f160100812b70',
  duration: 101 
}

track.after :: track.added - Participant added a track

  • status { String } The current status of the participant generating this event - either connected or disconnected.

  • accountId { ObjectID } The id of the account generating the event.

  • trackKind { String } The kind of track - data, audio or video.

  • trackName { String } The track name. Currently unused and set to a uuid.

{
  type: 'track',
  name: 'added',
  order: 2,
  roomId: '5df02d890535377c38cfdeef',
  status: 'connected',
  accountId: '58c87b958b8f160100812b70',
  trackKind: 'audio',
  trackName: '613ef5df-cdee-4fd6-8f19-7140deb08b81'  
}

track.after :: track.removed - Participant removed a track

  • status { String } The current status of the participant generating this event - either connected or disconnected.

  • accountId { ObjectID } The id of the account generating the event.

  • trackKind { String } The kind of track - data, audio or video.

  • trackName { String } The track name. Currently unused and set to a uuid.

{
  type: 'track',
  name: 'removed',
  order: 21,
  roomId: '5df02d890535377c38cfdeef',
  status: 'connected',
  accountId: '58c87b958b8f160100812b70',
  trackKind: 'video',
  trackName: '8bd80b33-34ab-4ac6-b2fd-23d51cfe9156'  

}

track.after :: track.enabled - Participant un-paused a track

  • status { String } The current status of the participant generating this event - either connected or disconnected.

  • accountId { ObjectID } The id of the account generating the event.

  • trackKind { String } The kind of track - data, audio or video.

  • trackName { String } The track name. Currently unused and set to a uuid.

{
  type: 'track',
  name: 'enabled',
  order: 22,
  roomId: '5df02d890535377c38cfdeef',
  status: 'connected',
  accountId: '58c87b958b8f160100812b70',
  trackKind: 'video',
  trackName: '8bd80b33-34ab-4ac6-b2fd-23d51cfe9156'  

}

track.after :: track.disabled - Participant paused a track

  • status { String } The current status of the participant generating this event - either connected or disconnected.

  • accountId { ObjectID } The id of the account generating the event.

  • trackKind { String } The kind of track - data, audio or video.

  • trackName { String } The track name. Currently unused and set to a uuid.

{
  type: 'track',
  name: 'enabled',
  order: 21,
  roomId: '5df02d890535377c38cfdeef',
  status: 'connected',
  accountId: '58c87b958b8f160100812b70',
  trackKind: 'video',
  trackName: '8bd80b33-34ab-4ac6-b2fd-23d51cfe9156'  

}

Configuring Access

The Room definition defaultAcl is owner.delete and there is no createAcl defined for Rooms; Rooms must be created in-script using bypassCreateAcl().

Alternatively, the Room definition may be extended with overriding createAcl, defaultAcl and - incidentally - custom properties.

org.objects.objects.insertOne({
  label: 'Room',
  name: 'room',
  createAcl: 'account.public', // any user can create rooms.
  properties: [{
    name: 'c_ustom',
    label: 'Custom',
    type: 'String'
  }]
})

Access to instances is provided using explicit acl writing. the shorthand import/export format can be used as well as the standard type, target, allow properties. Anyone with read access to the room instance is provided a token when reading the token property. For example:

org.objects.rooms.insertOne({  
  acl: [
    'account.public.read', // any logged in account
    'account.anonymous.read', // anyone anywhere
    'role.developer.read', // developer role
    `account.${emailToId('sample@medable.com')}.read`, // specific account (by id)           
    { type: 1, target: emailToId('sample@medable.com'), allow: 4 } // long form
  ]
})
.bypassCreateAcl()
.execute()

function emailToId(email) {
  return org.objects.accounts.readOne({ email }).skipAcl().grant('read').execute()._id
}

Creating Rooms

Some environment-level options are required to create rooms.

  • org.configuration.televisit.roomsEnabled must be true in order to create rooms in an environment.

  • org.configuration.televisit.maxConcurrentRooms determines how many open rooms are allowed in a given environment.

To see current values for the above read current environment as an administrator (return org.read('configuration.televisit'))

To create a room instance, write an acl and insert a room instance:

return org.objects.rooms.insertOne({
  acl: [   
    `role.developer.read` // example.
  ]
}).lean(false).execute()

The Cortex room instance is now created and the state is "new". The provider room to which clients connect is opened asynchronously. Once this process has completed, the room's state property will be set to "open" and fire any room.after script triggers ({type: 'room', name: 'created', ...}).

Participant may now use their tokens to connect to the remote room.

Participant Status

Current participant status is updated in the Room instance to reflect the state of connected participants as they connect, disconnect, add and pause tracks, etc. Participant status is updated prior to script triggers so the latest is available in room event triggers.

Example participants list where both are connected and streaming audio and video.

const doc = org.objects.room
  .readOne('5df2cb2a020fd46a6351e66b')
  .paths('participants.status', 'participants.audio', 'participants.video', 'participants.account.name')
  .execute()

let json = {
  "_id": "5df2cb2a020fd46a6351e66b",
  "object": "room",
  "participants": [
    {
      "_id": "5df2cb3d020fd46a6351e70b",
      "account": {
        "_id": "58c87b958b8f160100812b70",
        "name": {
          "additional": [],
          "first": "Jane",
          "last": "Doe"
        },
        "object": "account"       
      },
      "audio": [
        "connected"
      ],
      "status": "connected",
      "video": [
        "connected"
      ]
    },
    {
      "_id": "5df2cce5020fd46a6351ef86",
      "account": {
        "_id": "5da9ff0fff5c5eb553a557f1",
        "name": {
          "additional": [],
          "first": "John",
          "last": "Doe"
        },
        "object": "account"       
      },
      "audio": [
        "connected"
      ],
      "status": "connected",
      "video": [
        "connected"
      ]
    }
  ]
}
  • The status of the participant is connected when they are connected to the room.

  • The audio and video are arrays that contain connected and/or paused.

    • When either of these tracks are removed, connected will no longer appear in the array, but paused may linger and

      should be ignored.

  • When a participant status is disconnected:

    • Ignore the values inaudio and video.

    • The participant remains in the list.

Last updated