5

Due to the breaking changes in Android WebRTC client's example, I'm looking for the code-example which shows how to add and work with DataChannel in Android. I need to just send "Hello Worlds" via DataChannel between 2 Android devices. Here's the old code:

https://chromium.googlesource.com/external/webrtc/stable/talk/+/master/examples/android/src/org/appspot/apprtc/AppRTCDemoActivity.java#177

It uses some classes and interfaces which don't exist in the new version anymore.

So how can I add support of DataChannel to my Android WebRTC application, send and receive a text through it?

Incerteza
  • 32,326
  • 47
  • 154
  • 261

2 Answers2

10

I added DataChannel in a project with an older version of webrtc. I looked at the most up to date classes and it seems the methods and callbacks are still there, so hopefully it will work for you.

Changes to PeerConnectionClient:

Create DataChannel in createPeerConnectionInternal after isInitiator = false;:

DataChannel.Init dcInit = new DataChannel.Init();
dcInit.id = 1;
dataChannel = pc.createDataChannel("1", dcInit);;
dataChannel.registerObserver(new DcObserver());

Changes to onDataChannel:

@Override 
public void onDataChannel(final DataChannel dc) {
    Log.d(TAG, "onDataChannel");
    executor.execute(new Runnable() {
        @Override
        public void run() {
            dataChannel = dc;
            String channelName = dataChannel.label();
            dataChannel.registerObserver(new DcObserver());
        }
    });
}

Add the channel observer:

private class DcObserver implements DataChannel.Observer {

    @Override 
    public void onMessage(final DataChannel.Buffer buffer) {

        ByteBuffer data = buffer.data; 
        byte[] bytes = new byte[data.remaining()];
        data.get(bytes);
        final String command = new String(bytes);

        executor.execute(new Runnable() {
            public void run() {
                events.onReceivedData(command);
            }
        });

    }

    @Override
    public void onStateChange() {
        Log.d(TAG, "DataChannel: onStateChange: " + dataChannel.state());
    }
}

I added onReceivedDataevents to PeerConnectionEvents interface and all the events are implemented in the CallActivity so I handle the data received on the channel from there.

To send data, from CallActivity:

public void sendData(final String data) {

    ByteBuffer buffer = ByteBuffer.wrap(data.getBytes());
    peerConnectionClient.getPCDataChannel().send(new DataChannel.Buffer(buffer, false));


}

I only took a quick look at the new classes and made minor changes to my code, I hope it will work for you with no more changes.

Good luck

Guy S
  • 1,424
  • 1
  • 15
  • 34
  • **after isInitiator = false;:** `if (isInitiator) {...` - that will never be executed. What did you mean? – Incerteza Apr 06 '15 at 08:53
  • My bad, like i said i made some adjustments to the code i was using to match the current class code. I am passing isInitiator value in peerConnectionClient constructor to see who initiated the call and create the data channel for initiator. (other peer gets the data channel in onDataChannel). poor choice of naming since the class already uses isInitiator, so you might want to change the variable name for the if statement (if (isInitiator) {...) – Guy S Apr 06 '15 at 10:44
  • so do I need to remove `isInitiator = false`? – Incerteza Apr 06 '15 at 11:46
  • keep isInitiator = false , remove the if statement. (I've edited the answer) – Guy S Apr 06 '15 at 12:28
  • Thanks, I'll try it shortly. – Incerteza Apr 06 '15 at 12:33
  • I put a button at CallFragment and added a handler for it. How can I call "sendData" from its handler as "sendData" is located in CallActivity? – Incerteza Apr 07 '15 at 03:04
  • Actually, I'm not quite sure, there was no CallFragment in the version i was using, maybe you can try the answer from here: http://stackoverflow.com/questions/12659747/call-an-activity-method-from-a-fragment, ((YourActivityClassName)getActivity()).yourPublicMethod(); – Guy S Apr 07 '15 at 06:07
  • there's a question for you below. – Incerteza Apr 09 '15 at 09:53
  • Well, I can send the message it seems, but I never receive it. – Incerteza Apr 10 '15 at 13:11
  • What's `channelName` for? – Incerteza Apr 10 '15 at 13:12
  • you don't need the channel name, it was there for logging purposes. I saw you had a discussion with Kevin Kuei in a different question regarding some bugs, did you get the DataChannel working? (send/receive) – Guy S Apr 12 '15 at 06:14
  • No, I didn't. Maybe you have an example which is working well? Which I take and without any changes launch? – Incerteza Apr 14 '15 at 04:58
  • Sorry, I don't have such an example. Try to create the DataChannel only for the peer who started the call, then the other peer is suppose to register to same channel in onDataChannel. also log DataChannel state in onStateChange to see if it's connecting/connected/open. – Guy S Apr 14 '15 at 06:33
  • The offer-side creates the DataChannel, but the answer-side never has "onDataChannel" triggered. When or where should I create DataChannel exactly on the offer-side? – Incerteza Apr 14 '15 at 06:44
  • in createPeerConnectionInternal – Guy S Apr 14 '15 at 07:17
  • What revision of webrtc are you using? Make sure your're using SCTPDataChannel and not RTPDataChannel. (I think SCTPDataChannel is default in the recent revisions) – Guy S Apr 14 '15 at 07:34
  • The latest one I believe. – Incerteza Apr 14 '15 at 08:53
  • Wny is it in `createPeerConnectionInternal` and not in `PeerConnectionClient#createOffer()`? – Incerteza Apr 14 '15 at 14:03
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/75206/discussion-between-guy-s-and-alexander-supertramp). – Guy S Apr 14 '15 at 14:33
  • @GuyS Can you help out with a fully working sample? or discuss privately ? – MaTriXy Jul 23 '15 at 08:18
  • @GuyS I'm having same problem but couldn't solved. Can you take a look at [This](http://stackoverflow.com/questions/33911149/datachannel-state-always-returns-connecting-webrtc-android) – Waqar Khan Dec 08 '15 at 08:26
  • hi, can i ask a problem that why u assign dataChannel and setObserver 2 times? – famfamfam Mar 22 '21 at 15:05
1

I'm sorry that I have a question to the code from Guy S.

In your code, there are two following statements in both createPeerConnectionInternal() and onDataChannel().

dataChannel.registerObserver(new DcObserver());

I think it may cause twice registrations. Is it correct??

I mean, before making a call, it created a dataChannal and registered an Observer. Then.. if there is a call comes in, the onDataChannel called, then the dataChannel point to dc and register again??

Kevin Kuei
  • 193
  • 2
  • 17
  • And I tried your code, when calling to dataChannel = pc.createDataChannel("1", dcInit); It shows following errors 04-09 18:01:59.458: E/libjingle(32109): Error(datachannel.cc:127): Failed to initialize the RTP data channel due to invalid DataChannelInit. 04-09 18:01:59.458: E/rtc(32109): # 04-09 18:01:59.458: E/rtc(32109): # Fatal error in ../../talk/app/webrtc/java/jni/peerconnection_jni.cc, line 1253 04-09 18:01:59.458: E/rtc(32109): # Check failed: nativeChannelPtr 04-09 18:01:59.458: E/rtc(32109): # Failed to create DataChannel – Kevin Kuei Apr 09 '15 at 10:05
  • you can open a question. – Incerteza Apr 10 '15 at 03:59
  • No, sorry, only the one with bugs. – Incerteza Apr 10 '15 at 06:01
  • I just removed the line "dcInit.id=1;" and run it again, it won't crashed now. but it failed in setting remoteDescription now. I will open a new question. – Kevin Kuei Apr 10 '15 at 07:45
  • I've open a new question over here: http://stackoverflow.com/questions/29556425/failed-to-make-webrtc-call-with-datachannel-from-chrome-web-app-to-android-app – Kevin Kuei Apr 10 '15 at 08:12