使用DataChannel的WebRTC Android多用户文本聊天

使用DataChannel的WebRTC Android多用户文本聊天,webrtc,webrtc-android,Webrtc,Webrtc Android,我正在为多用户使用webRTC应用程序的mesh架构,视频聊天对多用户来说效果很好,对于文本聊天,我在创建报价的对等方上创建了一个数据通道,onDataChannel处理程序在另一对等方上创建了一个数据通道。文本聊天适用于2个用户,但当有3个用户时,第一个客户端(要加入)可以看到所有其他客户端的消息,但只能向第二个客户端(要加入)发送消息,第二个客户端(要加入)可以看到来自第一个客户端的消息并只发送给第一个客户端,第三个客户端从none接收消息,但可以发送给第一个客户端 PeerConnecti

我正在为多用户使用webRTC应用程序的mesh架构,视频聊天对多用户来说效果很好,对于文本聊天,我在创建报价的对等方上创建了一个数据通道,onDataChannel处理程序在另一对等方上创建了一个数据通道。文本聊天适用于2个用户,但当有3个用户时,第一个客户端(要加入)可以看到所有其他客户端的消息,但只能向第二个客户端(要加入)发送消息,第二个客户端(要加入)可以看到来自第一个客户端的消息并只发送给第一个客户端,第三个客户端从none接收消息,但可以发送给第一个客户端

PeerConnection.Observer中的onDataChannel事件处理程序

            @Override
            public void onDataChannel(DataChannel dataChannel) {
                Log.d("DataChannel", "onDataChannel" + " , state: " + dataChannel.state());
                DataChannel.Observer dcObserver = new DcObserver(){
                    @Override
                    public void onStateChange() {
                        Log.d(TAG, "onStateChange: remote data channel state: " + dChannel.state().toString());
                    }

                    @Override
                    public void onMessage(DataChannel.Buffer buffer) {
                        Log.d(TAG, "onMessage: got message");
                        readMessage(buffer.data);
                    }
                };
                dataChannel.registerObserver(dcObserver);
                dataChannels.add(dataChannel);
                dcObservers.add(dcObserver);
            }
        });
创建对等连接时创建数据通道

@Override
    public void onNewPeerJoined(String socketId, boolean createOffer) {
        showToast("Remote Peer Joined");
        PeerConnection peerConnection = getOrCreatePeerConnection(socketId);
        if (createOffer) {
            dChannel = peerConnection.createDataChannel("DataChannel",new DataChannel.Init());
            DataChannel.Observer dcObserver = new DcObserver(){
                @Override
                public void onStateChange() {
                    Log.d(TAG, "onStateChange: remote data channel state: " + dChannel.state().toString());
                }

                @Override
                public void onMessage(DataChannel.Buffer buffer) {
                    Log.d(TAG, "onMessage: got message");
                    readMessage(buffer.data);
                }
            };
            dChannel.registerObserver(dcObserver);
            dcObservers.add(dcObserver);
            dataChannels.add(dChannel);
            sdpConstraints = new MediaConstraints();
            sdpConstraints.mandatory.add(
                    new MediaConstraints.KeyValuePair("OfferToReceiveAudio", "true"));
            sdpConstraints.mandatory.add(
                    new MediaConstraints.KeyValuePair("OfferToReceiveVideo", "true"));
            //sdpConstraints.optional.add(new MediaConstraints.KeyValuePair("DtlsSrtpKeyAgreement", "true"));
            peerConnection.createOffer(new CustomSdpObserver("localCreateOffer") {
                @Override
                public void onCreateSuccess(SessionDescription sessionDescription) {
                    super.onCreateSuccess(sessionDescription);
                    peerConnection.setLocalDescription(new CustomSdpObserver("localSetLocalDesc"), sessionDescription);
                    Log.d("onCreateSuccess", "SignallingClient emit ");
                    SignallingClient.getInstance(roomName).emitSessionDescription(sessionDescription, socketId);
                }
            }, sdpConstraints);

        }
    }
发送消息

public void sendMessage() {
        String message = editText.getText().toString();
        if (message.isEmpty()) {
            return;
        }
        editText.setText("");
        textView.append(HtmlCompat.fromHtml("<b>" + userName + "</b>",HtmlCompat.FROM_HTML_MODE_LEGACY));
        textView.append(": " + message + "\n");
        String str = "<b>" + userName + "</b> : " + message;
        ByteBuffer data = stringToByteBuffer("-s" + str, Charset.defaultCharset());
        for (int i = 0; i < dataChannels.size(); i++){
            Log.d("info","send_data dataChannel" + i);
            dataChannels.get(i).send(new DataChannel.Buffer(data, false));
        }
    }
public void sendMessage(){
String message=editText.getText().toString();
if(message.isEmpty()){
返回;
}
editText.setText(“”);
extview.append(HtmlCompat.fromHtml(“+userName+”,HtmlCompat.FROM_HTML_MODE_LEGACY));
textView.append(“:”+消息+“\n”);
字符串str=“”+用户名+”:“+消息;
ByteBuffer data=stringToByteBuffer(“-s”+str,Charset.defaultCharset());
对于(int i=0;i
数据频道不适合聊天,甚至不适合一对一聊天。想象一下这样一个场景:当
a
B
发送消息,而
B
不在线接收消息
A
可以等待
B
再次联机,但如果
B
再次联机时
A
未联机,该怎么办。现在将此场景扩展到多用户,它只是不能提供正确的体验


你需要一些更可靠的东西来进行具有存储转发功能的多方聊天——看看这里,它有多用户视频/语音会议、1对1和群组聊天。源代码在这里。尽管本演示使用了mesibo API,但您可以使用您选择的任何API。

数据频道不用于聊天,甚至不用于1对1聊天。想象一下这样一个场景:当
a
B
发送消息,而
B
不在线接收消息
A
可以等待
B
再次联机,但如果
B
再次联机时
A
未联机,该怎么办。现在将此场景扩展到多用户,它只是不能提供正确的体验


你需要一些更可靠的东西来进行具有存储转发功能的多方聊天——看看这里,它有多用户视频/语音会议、1对1和群组聊天。源代码在这里。尽管本演示使用的是mesibo API,但您可以使用您选择的任何API。

2点建议:

  • dChannel将只保存您在对等机上打开的最后一个数据通道。考虑使它成为数组并保存所有数据通道。
  • 向SDPConstraints DtlsSrtpKeyAgreement=true和InternalSCTPDataChannel=true添加可选约束

  • 我可以建议两件事:

  • dChannel将只保存您在对等机上打开的最后一个数据通道。考虑使它成为数组并保存所有数据通道。
  • 向SDPConstraints DtlsSrtpKeyAgreement=true和InternalSCTPDataChannel=true添加可选约束

  • 我不仅仅是在聊天时使用dataChannel,我也会在文件传输时使用它,我只是在聊天时尝试看看dataChannel如何用于多个对等方,如果这个问题解决了,那么上述两个功能都能正常工作,你能帮我解决这个问题吗?我不仅仅是在聊天时使用dataChannel,我也会将其用于文件传输,我只是尝试将其用于聊天,以了解如何将数据通道用于多个对等方,如果此问题得到解决,则上述两个功能都无法正常工作,您能否帮助我解决此问题?实际上,我正在将数据通道存储在数据通道列表中。我还尝试添加两个可选约束,但问题仍然存在。此外,每当我在PeerConnection.Observer中实现OnRenegotiationRequired方法时(我将接口实现为一个类,并在主活动中创建这些对象时使用override实现方法的附加功能),它都会被多次调用,并使AppActual崩溃,我正在数据通道列表中存储数据通道。我还尝试添加两个可选约束,但问题仍然存在。此外,每当我在PeerConnection.Observer中实现OnRenegotiationRequired方法时(我将接口实现为类,并在主活动中创建这些对象时使用override实现方法的附加功能),它会被多次调用并使应用程序崩溃