This page describes the RESTful API supported by UV4L. The API is available if the Streaming Server module is installed. Before starting to describe this API, remember that each uv4l process is associated with exactly one audio-video input device (e.g. a camera and/or a mic.) and with an independent instance of the server, so if you want to control two or more devices with this API you will have to run two or more uv4l processes, accordingly, each one driven by their specific configurations (e.g. listening to different ports).
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 this API:
Request bodies must be in JSON format. Each request must also contain the appropriate authentication headers if HTTP(S) authentication is enabled in the Streaming Server.
There are various resources which is possible to interact with through these requests. Each resource is identified with an endpoint in the list below:
- /api/videodev/settings
At any time, this resource represents all the settings of the video4linux2 input device handled by uv4l, 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 sub-object and the current_value property in the control list. You can set the apply_only_if_changed field to true in order to apply each setting only if its values has changed.
- /api/webrtc/settings
This resource represents all the settings related to WebRTC 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 “global” WebRTC setting (see /api/webrtc/settings) 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 later with an example.
- /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 or plug-in’s you intend to exploit (videoroom in this case). This is essentially the endpoint to which you post messages to e.g. discover the list of the existing rooms on the server, join a room and interact with other participants in the room. Allowed methods are GET and POST. In the future other plug-in’s than videoroom might be supported, like videocall, textroom or audiobridge. All the possible messages that you can send to this resource 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 status of 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 implicitly applied in the request, respectively. You can specify a timeout of 0 seconds to avoid to block on the request.
All the above resources support the OPTIONS method as well, which can be used to obtain, in the allow header of the response, the list of all possible methods supported.
Example of Janus session driven by the UV4L RESTful API
Before we start we obviously need a Janus Gateway deployed somewhere. We will be profiting by the RESTful API Panel mentioned 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 (you’ll have to replace the janusgateway and myraspberrypi with the real IP addresses or host names specific to your network environment):
- the UV4L Streaming Server at http://myraspberrypi:8080
- the Janus Gateway at http://janusgateway: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://janusgateway: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.