Using Data Channel API to send text messages using WebRTC

Posted By : Sunidhi Sharma | 25-Dec-2018

Overview:

WebRTC is an open source project which enables a real-time communication of media as well as data across peers. WebRTC establishes a peer to peer connection framework which is used to share high-quality video among Android, iOS, and Web. For web, WebRTC is quite simple. There is a certain set of APIs which one can call to get user's media and data.

However, in Android, for this to work, we need to make an addition, i.e.; add the peer connection library in your project and connect the devices using peer connection.

This blog-post discusses how can one send data across the devices connected with WebRTC which will easily let them develop chat applications or to send messages even when the call is taking place without breaking the connection.

 

Prerequisites:

  • Android Studio with Gradle > 3.0

 

Example:

Step 1: Adding the dependencies

Add the following dependencies in your project level build.gradle file:

api(name:'libwebrtc', ext:'aar')

You can also import this library as a module in the project.

Step 2: Adding the UI for the application.

<android.support.design.widget.CoordinatorLayout 
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
       <LinearLayout
           android:layout_width="match_parent"
           android:layout_height="match_parent"
           android:orientation="vertical"
           android:padding="16dp"
           app:layout_behavior="@string/appbar_scrolling_view_behavior">
           <LinearLayout
               android:layout_width="match_parent"
               android:layout_height="wrap_content">
               <EditText
                   android:layout_width="0dp"
                   android:layout_height="wrap_content"
                   android:id="@+id/text_input"
                   android:layout_weight="1" />
               <Button
                   android:layout_width="wrap_content"
                   android:layout_height="wrap_content"
                   android:layout_marginStart="16dp"
                   android:enabled="false"
                   android:onClick="sendMessage"
                   android:text="Send"
                   android:id="@+id/send_button"
                   android:textColor="@color/colorPrimary" />
           </LinearLayout>
           <TextView
               android:id="@+id/remote_text"
               android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:layout_marginTop="16dp" />
</LinearLayout>

 

Step 3: Initializing the Peer Connections.

Before proceeding forward, we need to know what a peer connection is. Firstly, a peer is a device which is connected to a network and peer to peer connection is an architecture which helps and connects two or more devices so that they can share their resources without going through the trouble of connecting to a separate server.

private void initializePeerConnections() {                                                                    
   localPeerConnection = createPeerConnection(factory, true);                                                
   remotePeerConnection = createPeerConnection(factory, false);                                              
   localDataChannel = localPeerConnection.createDataChannel("sendDataChannel", new DataChannel.Init());      
   localDataChannel.registerObserver(new DataChannel.Observer() {                                            
       @Override                                                                                             
       public void onBufferedAmountChange(long l) {                                                          
       //this is fired when there is some data sent from datachannel                                     
       }                                                                                                                                                                                
       @Override                                                                                             
       public void onStateChange() {                                                                                                     
       //this is fired when there's some change in 
           runOnUiThread(() -> {                                                                             
               if (localDataChannel.state() == DataChannel.State.OPEN) {
            sendButton.setEnable(true);                                                                                                 
               } else {                                                                              
            sendButton.setEnable(false);
               }                                                                              
           });                                                                                      
       }                                                                                              
                                                                                                             
       @Override                                                                                             
       public void onMessage(DataChannel.Buffer buffer){
       //this  is fired when you receive any message from data channel                                                                                                       
       }                                                                                              
   });                                                                                                      
}

 

Step 4: Sending and Receiving the text messages

Sharing of data can only be possible when the network through which they are connected allows it, to facilitate this we use STUN and TURN server. Generally, we need signaling to connect two or more devices. Signaling is used to let peers know that there is a connection between them. Since, we are not using any signaling server this time so we just use the same device as both peers, we will send the data to the same device using Data Channel API. What we are going to do is:

  1. Send the data from our device to the data channel. For connecting peers, we need signaling to connect two or more devices. Since we are not using signaling server in this demo, we will send the data to the same device using Data Channel API.
  2. Display the data received from the data channel to a text box.

 

Sending text messages

public void sendMessage(View view) {                                                   
   String message = binding.textInput.getText().toString();                                                                                                                                                                                                                                                                                      
   ByteBuffer data = stringToByteBuffer(message, Charset.defaultCharset());           
   localDataChannel.send(new DataChannel.Buffer(data, false));                        
}                                                                                      

private ByteBuffer stringToByteBuffer(String msg, Charset charset) {                
   return ByteBuffer.wrap(msg.getBytes(charset));                                        
}

 

Receiving text messages

private PeerConnection createPeerConnection(PeerConnectionFactory factory, boolean isLocal) {                  
   PeerConnection.RTCConfiguration rtcConfig = new PeerConnection.RTCConfiguration(new ArrayList<>());        
   MediaConstraints pcConstraints = new MediaConstraints();                                                                                                                                                           
   PeerConnection.Observer pcObserver = new PeerConnection.Observer() {                                                                                                                                                                                                                                                           
       @Override                                                                                              
       public void onDataChannel(DataChannel dataChannel) {                                                   
           ...
           dataChannel.registerObserver(new DataChannel.Observer() {                                          
               @Override                                                                               
               public void onBufferedAmountChange(long l) {                                                                                                                                                   
               }                                                                               
                                                                                                              
               @Override                                                                               
               public void onStateChange() {                                                                  
               }                                                                               
                                                                                                              
               @Override                                                                               
               public void onMessage(DataChannel.Buffer buffer) {                                             
                   Log.d(TAG, "onMessage: got message");                                                      
                   String message = byteBufferToString(buffer.data, Charset.defaultCharset());                
                   runOnUiThread(() -> remoteText.setText(message));                                  
               }                                                                               
           });                                                                                       
       }                                                                                                                                                                                                                                                                                                                 
   };                                                                                                       
                                                                                                              
   return factory.createPeerConnection(rtcConfig, pcConstraints, pcObserver);                                 
}            
//method to convert byte buffer to String characters
private String byteBufferToString(ByteBuffer buffer, Charset charset) {               
   byte[] bytes;                                                                      
   if (buffer.hasArray()) {                                                           
       bytes = buffer.array();                                                        
   } else {                                                                           
       bytes = new byte[buffer.remaining()];                                          
       buffer.get(bytes);                                                             
   }                                                                               
   return new String(bytes, charset);                                                 
}

 

Summary:

To summarize, we can easily send texts as well as files using the webRTC’s data channel API. Since there’s no signaling server used you are just looping the messages back to yourself. But, once you use this code with some signaling server (choice for signaling is yours: you can either use API’s or WebSocket) you can easily send data to all the different devices connected across the network in the same room (aka peers).

Request for Proposal

Recaptcha is required.

Sending message..