Android Client Example

Before going through this Android Client example it is recommended to get familiar with the Nabto WebRTC platform using one of the getting started guides which do not require coding.

Example Android App

You may find the example client app in Nabto WebRTC SDK for Android. Simply clone the repository to your local drive and open it in Android Studio. The code we are interested in is located in the “app” application module. Follow the “run the example test application” instructions in the README.md file to test the application.

Android does not come with a standard WebRTC implementation. As such the application uses a dependency on GetStream Android WebRTC. This is the standard WebRTC implementation precompiled for Android. This is the same WebRTC library which is also used in Chrome etc.

The other dependency that the application has is of course the Nabto WebRTC SDK. The application is written in Java and is only about ~500 lines of code total, split among the following 4 files.

LoggingMessageTransportObserverAdapter.java
LoggingMessageTransportObserverAdapter.java
LoggingSignalingClientObserverAdapter.java
MainActivity.java

The first three classes simply implement Observer interfaces. MainActivity.java contains the one and only MainActivity class for the whole app.

Note: It is not recommended to structure your own Android applications in this way. We skip many good practices in order to have a very short and simple to understand example.

It is important to understand the following

  • The Nabto SDK for Android primarily handles the signaling aspect of WebRTC. We do not provide a complete WebRTC solution.
  • As stated above, this app uses a standard WebRTC implementation for everything other than signaling.

You may want to use the example app to understand how to use a standard WebRTC library such as Google’s WebRTC. This is out of scope for this guide and may be done at your own discretion. This guide will mostly focus on the usage of the Nabto WebRTC SDK for signaling purposes.

Core concepts

The Nabto WebRTC SDK for Android is split into three modules, core, util and util-org-webrtc. The core module contains code that directly interfaces with the Nabto WebRTC platform to establish client connections to devices.

The util module contains code built on top of the core module, including helper classes, classes for signing JSON messages and a standardized signaling message format. You are not required to use our signaling message format, the core module can send any arbitrary JSON across the line. However, this would require you to create a custom message format that your devices and clients agree on. Since we’re using a standard device implementation, we will also be using the standard message format.

The util-org-webrtc module has code which is used with the org.webrtc classes which comes from the standard webrc.org implementation. There are several providers of the org.webrtc code, we list a few of them below.

SignalingClient

In the core module, a SignalingClient represents a single logical client connection. A SignalingClient object is created using the SignalingClientFactory utility class. In the MainActivity.java file you can see how to set up a SignalingClient object the onCreate method of the MainActivity class.

After creating a SignalingClient, it will be in an inactive state. You should create a class that implements the SignalingClient.Observer interface and add it to the client. After that you call the start method to connect the client to the Nabto platform so you can begin to send and receive signaling messages.

The following code snippet gives a rough sketch of how to create client and start it. MyObserver is your own class that implements SignalingClient.Observer.

SignalingClientFactory.Options options = new SignalingClientFactory.Options();
options.setProductId("pr-xxxxxx");
options.setDeviceId("de-xxxxxx");
SignalingClient client = SignalingClientFactory.createSignalingClient(options);
MyObserver observer = new MyObserver();
client.addObserver(observer);
client.start();

Now you may send JSON messages back and forth with the device using the sendMessage method on the client object.

ClientMessageTransport

In the util module there is a ClientMessageTransport class that is made to automate a lot of details away when using our standard message format. This class handles signing messages and sending them through the SignalingClient object. In the same MainActivity.onCreate method from earlier you can see how it’s set up together with the SignalingClient object. This makes the complete setup code in the example app the following:

var opts = new SignalingClientFactory.Options()
        .setProductId(productId)
        .setDeviceId(deviceId);

client = SignalingClientFactory.createSignalingClient(opts);
messageTransport = ClientMessageTransport.createSharedSecretMessageTransport(client, sharedSecret);
messageTransport.addObserver(new LoggingMessageTransportObserverAdapter() {
    @Override
    public void onWebrtcSignalingMessage(WebrtcSignalingMessageUnion message) {
        super.onWebrtcSignalingMessage(message);
        perfectNegotiation.onMessage(message);
    }

    @Override
    public void onSetupDone(List<SignalingIceServer> iceServers) {
        super.onSetupDone(iceServers);
        setupPeerConnection(iceServers);
    }
});
client.addObserver(new LoggingSignalingClientObserverAdapter());
client.start();

In particular, pay attention to the observer added to the messageTransport object.

The ClientMessageTransport object receives a message from the device, it will parse that message into a WebrtcSignalingMessage object which represents any possible signaling message adhering to the message format. The parsed message is then sent to all observers through the onWebrtcSignalingMessage method. In our case we pass it on to the PerfectNegotiation object.

The second observer method, onSetupDone, is simply called when the device and client have exchanged “setup” message, notifying each other that they’re both ready to establish a WebRTC connection. onSetupDone carries a list of ICE servers which can be used with e.g. Google’s WebRTC to create the actual WebRTC peer connection. In our case this is done in MainActivity.setupPeerConnection.

ClientMessageTransport also has a method called sendWebrtcSignalingMessage. Think of this method as being a wrapper around SignalingClient.sendMessage, and think of the observer onWebrtcSignalingMessage as being a wrapper around the onMessage method in SignalingClient.Observer.

In this way, the ClientMessageTransport object helps to ensure that messages are sent and arrive in the same standard format.

The PerfectNegotiation object is responsible for handling and sending WebrtcSignalingMessages, these are the Descriptions and Candidates which are exchanged between WebRTC peers. For example, when the WebRTC peer connection produces an SDP description that must be sent to the device.

What’s next

With this, the guide is concluded. You may use SignalingClient and ClientMessageTransport in your own project as outlined above for a simple on the rails implementation, or you may decide to familiarize yourself more with the SDK and implement your own message format on top of the core module.