openvidu-ipcameras 🔗

Check it on GitHub

An OpenVidu application with a Java backend. It makes use of openvidu-java-client SDK to communicate with the OpenVidu deployment. It serves a single HTML page (generated with Thymeleaf) where users can subscribe and see a collection of IP cameras.

Running this tutorial 🔗

To run the tutorial you need the three components stated in OpenVidu application architecture: an OpenVidu deployment, your server application and your client application. In this order:

1. Run OpenVidu deployment 🔗

Using Docker Engine:

# WARNING: this container is not suitable for production deployments of OpenVidu
# Visit https://docs.openvidu.io/en/stable/deployment

docker run -p 4443:4443 --rm -e OPENVIDU_SECRET=MY_SECRET openvidu/openvidu-dev:2.23.0

2. Run the server application and the client application 🔗

You need Java and Maven. Check them with:

java --version
mvn --version

Clone the repo:

git clone https://github.com/OpenVidu/openvidu-tutorials.git -b v2.23.0

Run the application:

cd openvidu-tutorials/openvidu-ipcameras
mvn package exec:java

Go to https://localhost:8080 to test the app once the server is running.

To test the application with other devices in your network, visit this FAQ. Ignore step 2 and step 3, as the application already includes a backend and the frontend doesn't need to communicate with a different application server.

Understanding the code 🔗

This is a very basic web application with a pretty simple JS/HTML/CSS frontend and a straightforward Java backend that serves HTML files, building the templates with the help of Thymeleaf.

This application provides the...

  • Backend: SpringBoot app with the following classes (src/main/java path, io.openvidu.ipcameras package)

    • App.java : entrypoint for the app
    • MyRestController.java : controller for managing the OpenVidu session and publishing IP cameras

  • Frontend templates: Plain JS/HTML/CSS files served by the backend (src/main/resources/templates)

    • index.html : template with the subscribe / unsubscribe form

  • Frontend static files (src/main/resources/static)

    • openvidu-browser-VERSION.js : openvidu-browser library. You don't have to manipulate this file
    • style.css : some CSS classes to style the templates

The application allows subscribing to the IP cameras collection from the web page. Let's describe the code that goes into action.


1) Login 🔗

At path / a login form will be displayed, providing a very simple password authentication:

2) Subscribe to the IP cameras 🔗

Clicking on the subscribe button you will subscribe to the IP cameras collection. These cameras are initialized on the App.java file.

static Map<String, String> IP_CAMERAS = new HashMap<String, String>() {
    {
        put("Russian building", "rtsp://195.46.114.132/live/ch00_0");
        put("Wickenburg, Arizona", "rtsp://98.163.61.242/live/ch00_0");
        put("City", "rtsp://91.191.213.49:554/live_mpeg4.sdp");
    }
};

After the subscribe button is clicked, the subscribe method (hosted in MyRestController.java) is called. This method will:

  1. Create an OpenVidu Session.
  2. Publish the IP cameras defined in the IP_CAMERAS map.
  3. Create a Connection and return its token for the browser user.
@RequestMapping(value = "/")
public String subscribe(@RequestParam(name = "credentials", required = false) String credentials, Model model)
        throws OpenViduJavaClientException, OpenViduHttpException {

    if (credentials == null) {
        return "index";
    }
    try {
        checkCredentials(credentials);
    } catch (Exception e) {
        return generateError(model, "Wrong credentials");
    }

    // Create our surveillance session if not available yet
    if (OV == null || session == null) {
        try {
            createOpenViduSession();
            publishCameras();
        } catch (OpenViduJavaClientException | OpenViduHttpException e) {
            return generateError(model,
                    "Error sending request to OpenVidu Server: " + e.getCause() + ". " + e.getMessage());
        }
    }

    // Create a Connection for the client
    ConnectionProperties connectionProperties = new ConnectionProperties.Builder()
            .type(ConnectionType.WEBRTC)
            .role(OpenViduRole.SUBSCRIBER)
            .build();
    String token = null;
    try {
        token = this.session.createConnection(connectionProperties).getToken();
    } catch (OpenViduHttpException e) {
        if (e.getStatus() == 404) {
            // Session was closed in openvidu-server. Re-create it
            createOpenViduSession();
            publishCameras();
            token = this.session.createConnection().getToken();
        } else {
            return generateError(model,
                    "Error creating Connection for session " + SESSION_ID + ": " + e.getMessage());
        }
    } catch (OpenViduJavaClientException e) {
        return generateError(model,
                "Error creating Connection for session " + SESSION_ID + ": " + e.getMessage());
    }

    model.addAttribute("token", token);
    return "index";
}

The highlights of the code are the creation of the two Connection objects in the Session. To publish each IP camera in method publishCameras():

ConnectionProperties connectionProperties = new ConnectionProperties.Builder()
    .type(ConnectionType.IPCAM)
    .data(cameraName)
    .rtspUri(cameraUri)
    .adaptativeBitrate(true)
    .onlyPlayWithSubscribers(true)
    .build();
session.createConnection(connectionProperties);

To create a Connection for the browser user and return a token to the client side:

ConnectionProperties connectionProperties = new ConnectionProperties.Builder()
    .type(ConnectionType.WEBRTC)
    .role(OpenViduRole.SUBSCRIBER)
    .build();
String token = null;
try {
    token = this.session.createConnection(connectionProperties).getToken();
} catch ( ... )