RESTful API

This page describes the RESTful API supported by UV4L. More specifically, the API is deployed by the UV4L Streaming Server (optional) module. If not already clear from the list of features, keep in mind that you can have exactly one server instance for each handled audio-video input device (e.g. two or more cameras or pseudo devices will have two or more dedicate servers, respectively, with their own configurations (e.g. listening to different ports) and running in the context of their own system processes).

Clients can exploit this interface via either HTTP or HTTPS depending on what protocol has been configured for the Streaming Server (see the uv4l-server manual for more details). The Streaming Server also provides an handful panel for developers at the web page under /restapi-panel path that allows to test every single request supported by the API:

REST Panel

Request bodies must be in JSON format. Each request must also contain the appropriate authentication headers if HTTP authentication is enabled in the Streaming Server.

There are various resources which is possible to interact with through these requests, each one identified by one of the endpoints in this list:

  • /api/videodev/settings

At any time this resource provides all the setting informations about the video4linux2 input device in use, that is the supported image controls (such as brightness, contrast, vertical mirror, etc…), the allowed resolutions and pixel formats and some other generic informations. Allowed methods on this resource are GET to read the actual settings and PUT to change the resolution and the image properties on the fly: namely the current_format subobject and the current_value property in the control list. You can also update apply_only_if_changed to true to apply each new setting only if it is different from the current value.

  • /api/webrtc/settings

This resource represents all the WebRTC settings in use by UV4L at a given moment. Allowed methods on this resource are GET to read the actual settings and PUT to update them. Keep in mind that partial updates with PUT are never supported by this API, as they are not RESTful. The default values of many of these settings are taken by the corresponding options specified in the UV4L configuration file or via command line when uv4l starts. See the uv4l-server manual for a description of each setting.

  • /api/janus/client/settings

This resource represents all the settings affecting a Janus session. When a session begins, both the WebRTC settings and the session settings above are cached internally for the whole lifetime of the session itself. The allowed methods on this resource are GET and PUT. While you are still allowed to update the resource during the session lifetime, the updated settings won’t take any effect until the next session starts. Many of the default values are still taken from the UV4L configuration file or passed by command line at boot. Some of these settings have a description in the uv4l-server manual, while the others should be self-explanatory. Note that a WebRTC setting might supersede a session setting in some circumstances. For example, if you want to publish your video to the room but you have disabled sending video in the WebRTC settings, then no video will be published.

  • /api/janus/client

This represents a Janus session. There can be only one active session (at most) at a given time. Allowed methods are GET to get the status informations of the session and POST to create a new session, by attaching a plug-in to it (see below), or to destroy the current session. The session protocol will be better described with an example later.

  • /api/janus/client/videoroom

This resource represents a plug-in and belongs to the session resource. In facts, in a create session message, you must specify what group of features (or plug-in’s) you intend to exploit (videoroom in this case). This is essentially the endpoint to which you send messages to discover the list of the exisisting rooms on the server, join a room and interact with other participants in the room. Allowed methods are GET and POST. In the future more plug-in’s might be supported, like videocall, textroom or audiobridge. All the possible messages that you can send through a POST will be mentioned later.

  • /api/janus/client/events

As the name suggests this resource represents a first-in first-out queue of asynchronous event notifications that may be generated during a session (e.g. arrival of a new participant in the room). As for videoroom, the events resource belongs to the current session. The only allowed method is GET. In your application you typically want to periodically poll this resource to monitor the session. In a GET request you can optionally specify two query string parameters which are timeout_s and maxev. The former is a timeout in seconds before returning from the (blocking) request in case no event notification is present in the queue, the latter is the number of event notifications you want to receive at most from the queue (0 means all events in the queue). Once an event notification has been received, it is dequeued and no longer available. If these two parameters are omitted, then a default value of 30 seconds and a default value of 1 event notification are applied respectively. You can specify a timeout of 0 seconds to avoid to block on the request.

Each of the above resources support the OPTIONS method as well which can be used to get a list of (other) allowed methods in the allow header of the response.

Example of Janus session driven by the UV4L RESTful API

Before we start we obviously need a Janus Gateway deployed somewhere. To make the things easy here is the VideoConference DEMO OS image available for download. In this example, we will be assuming we have it installed and running on a Raspberry Pi with a camera, speakers and a display attached. This OS provides both a Janus Gateway and the UV4L Streaming Server on the same host (let’s call it myraspberrypi). We will be profiting by the RESTful API Panel introduced before to send all the necessary requests to the UV4L Streaming Server in order to initiate an audio/video conference between a browser and the Raspberry Pi itself.

To summarize there are three actors in this example:

  • the UV4L Streaming Server at http://myraspberrypi:8080
  • the Janus Gateway at http://myraspberrypi:8088
  • the browser

Let’s start. With the browser access the panel at http://myraspberrypi:8080/restapi-panel.

The first step is to check the Janus settings and eventually set the correct URL of the gateway before creating a session:

Endpoint: /api/janus/client/settings
Method: GET
Body:
{
   "gateway": {
      "apisecret": "",
      "auth_token": "",
      "root": "/janus",
      "url": "https://janus.conf.meetecho.com"
   },
   "http_proxy": {
[etc]

The url shown in the body of the response has to be updated (specifically, that one points to a public Janus Gateway on Internet). In our example, we need “url”: “http://myraspberrypi:8088” instead. So what we will do now is to update this settings with a PUT request. As said above, we cannot partially update a resource, so we need to include all the settings (both changed and unchanged) in the content of the PUT request:

Endpoint: /api/janus/client/settings
Method: PUT
Body:
{
   "gateway": {
      "apisecret": "",
      "auth_token": "",
      "root": "/janus",
      "url": "http://myraspberrypi:8088"
[etc]

GET, PUT and OPTIONS are always synchronous requests on any resource and the response always contains the result of the request, both in the body and in the headers. POST are slightly different. With a POST you actually send a message (the body of the request) to the UV4L Streaming Server. Some messages require some time to be processed, so the final result has to be postponed to the future. In other words, the result can be either synchronous or asynchronous depending on the message sent. In case of synchronous message, you immediately get the result in the response body. In case of an asynchronous message, you first synchronously get the response for the POST request itself, but the final result will only be notified via GET requests on the events resource later, after the message has been processed.

The response to a successful PUT is the following:

Status: 200
Reason: OK
Body:
{
   "response": {
      "code": 200,
      "reason": "OK"
   },
   "what": "response"
}

If you try to partially update a resource, or if the submitted values are invalid for some reasons, you will get an error in the response body. For example, this response occurs if you try to submit a “aString” as value of a setting that expects a number instead:

Status: 400
Reason: Syntax error: Not a valid unsigned integer: aString
Body:
{
   "response": {
      "code": 400,
      "reason": "Syntax error: Not a valid unsigned integer: aString"
   },
   "what": "response"
}

BAD REQUEST (400) is the HTTP Status Code set in the response. There is another kind of error that includes the line “what”: “error” in the response body instead. This happens when the request content is valid in terms of JSON format or the request does not violate the REST style, but is not valid, semantically speaking, from the application (UV4L) point of view. Be prepared to handle all these error cases.

Now we are ready to create a session:

Endpoint: /api/janus/client
Method: POST
Body:
{
   "what": "create",
   "plugin": "videoroom",
   "transaction": "a4a9eb9b-8d4e-f562-a879-5f7819b2661b"
}

Every message in a POST request must include an unique transaction identifier, be it synchronous or asynchronous. For asynchronous messages this is essential in that it allows to correctly identify the corresponding result in the future among the notifications received through the events queue. The identifier can be anything (e.g. a random number), but you should make sure it will be unique for the whole session lifetime. All the fields are mandatory. videoroom is the only plug-in supported at the moment. You can “create” or “destroy” a session. These are synchronous messages. Should you find yourself in an unrecoverable condition during the session for some reasons, destroying it guarantees that all the resources are freed properly and that you can try to restart a new session.

The response in case of success is:

[...]
{
   "plugins": [
      {
         "id": "596112791999497",
         "name": "videoroom",
         "status": "attached"
      }
   ],
   "session_id": "924953281133518",
   "transaction": "a4a9eb9b-8d4e-f562-a879-5f7819b2661b",
   "what": "success"
}

Now if you send a GET request to the session endpoint, you will essentially obtain the status informations as above (except transaction). Pay attention to the plug-in “status” value. It is included in every response to a POST. A “detached” plug-in can not be recovered and invalidates the session: you can only destroy it. This happens, for example, if the room you have joined is suddenly destroyed by somebody.

We can now list the existing rooms and join one at our choice. Here the videoroom resource comes into the game:

Endpoint: /api/janus/client/videoroom
Method: POST
Body:
{
   "what": "list",
   "transaction": "d3f23f22-f02e-e1ed-c821-514f17776162"
}

This is a possible response:

{
   "janus": {
      "list": [
         {
            "audiocodec": "opus",
            "bitrate": 0,
            "description": "my room",
            "fir_freq": 0,
            "max_publishers": 5,
            "num_participants": 0,
            "record": false,
            "room": 2146946532127888,
            "videocodec": "vp8"
         },
         {
            "audiocodec": "opus",
            "bitrate": 128000,
            "description": "Demo Room",
            "fir_freq": 10,
            "max_publishers": 6,
            "num_participants": 1,
            "record": false,
            "room": 1234,
            "videocodec": "vp8"
         }
      ],
      "videoroom": "success"
   },
   "plugin": {
      "id": "2768177907372570",
      "name": "videoroom",
      "status": "attached"
   },
   "session_id": "7600588332267912",
   "transaction": "d3f23f22-f02e-e1ed-c821-514f17776162",
   "what": "success"
}

The “janus” property in the above JSON block envelops the answer from the Janus Gateway with the list of rooms. Let’s join the room 1234:

{
   "what": "join",
   "transaction": "02d47d07-c3dc-d0c0-73ba-74745afc2557",
   "body": {
      "room": 1234,
      "username": "My Name",
      "room_pin": ""
   }
}

join is an asynchronous message. All the options specified in the message (room, username, room_pin) can be omitted. When omitted, default values for these options are taken from the “global” Janus settings discussed before. In substance, you have a chance to override the options relevant to the message right before sending the message itself. This applies to all the messages sent in a POST request to the videoroom resource.

Let’s go ahead. This is the response:

{
   "plugin": {
      "id": "5207724196031894",
      "name": "videoroom",
      "status": "attached"
   },
   "session_id": "2749068522481484",
   "transaction": "02d47d07-c3dc-d0c0-73ba-74745afc2557",
   "what": "ack"
}

“what”: “ack” indicates that the final result will be notified through the events resource (that you are supposedly periodically polling):

Endpoint: /api/janus/client/events
Method: GET
Status: 200
Body:
[
   {
      "janus": {
         "description": "Demo Room",
         "id": 2903949700694175,
         "publishers": [
            {
               "display": "MyFriend",
               "id": 235889395822437
            }
         ],
         "room": 1234,
         "videoroom": "joined"
      },
      "plugin": {
         "id": "5207724196031894",
         "name": "videoroom",
         "status": "attached"
      },
      "session_id": "2749068522481484",
      "transaction": "02d47d07-c3dc-d0c0-73ba-74745afc2557"
   }
]

On the other hand, see what the result would have been if we had tried to join a non-existing room:

[...]
Method: GET
Status: 200
Body:
[
   {
      "error": {
         "code": 1080,
         "janus": {
            "error": "No such room (123467)",
            "error_code": 426,
            "videoroom": "event"
         },
         "reason": "janus error"
      },
      "plugin": {
         "id": "5157052428839023",
         "name": "videoroom",
         "status": "attached"
      },
      "session_id": "5880520435943847",
      "transaction": "02d47d07-c3dc-d0c0-73ba-74745afc2557",
      "what": "error"
   }
]

Synchronous messages are: create, destroy (a room), list, listparticipants, remove (a listener). Asynchronous messages are: join, publish, unpublish, configure and listen.

Now we are in a room with only one participant (MyFriend) identified by a unique id number 235889395822437. We want to see and talk with him or her. To do this we publish our audio and video (from the microphone and a camera) and listen to her audio and video. When we have done, we can finally unpublish and remove the listener respectively. We will see the first two messages for simplicity:

{
   "what": "publish",
   "transaction": "e0bdab10-e69b-2045-2003-0d8617d74d55",
   "body": {
      "audio": true,
      "video": true,
      "data": true,
      "adjust_max_bitrate_for_hardware_videocodec": true,
      "max_bitrate_bits": 0,
      "use_hardware_videocodec": false,
      "video_format_id": 60,
      "record": false,
      "rec_filename": "myrecording"
   }
}
{
   "what": "listen",
   "transaction": "6d6dc2f6-c7f2-6d58-a798-fe77a51af654",
   "body": {
      "feed": 235889395822437,
      "audio": true,
      "video": true,
      "data": true
   }
}

Check the results in the events queue. If everything went well you should now be conferencing with MyFriend.

configure is another useful message that can be used to instantaneously mute/unmute the audio stream or start/stop the video stream, adjust the bitrate or instruct the Janus Gateway to turn on or off audio and video recording at any time while the talk is alive and the connections have already been established.

There is no clean way to just leave a room, sorry, as this is not well supported by Janus Gateway  at the moment. The only equivalent way to leave it is to destroy the session and recreate a new one. After a session has been destroyed, the videoroom and events resources are no longer available.