webrtc 服務器 janus android使用教程1:Echo Test

1.編譯帶ws接口的janus v0.7.6

官方文檔地址  https://github.com/meetecho/janus-gateway  

由於官方提供的andorid demo 是基於http c++的實現(https://github.com/meetecho/janus-mobile-sdk)對於android 過於複雜和有bug  所有使用ws 要簡單的多

ws 安裝後有以下日誌會輸出爲成功

[WARN] libwebsockets has been built without IPv6 support, will bind to IPv4 only
libwebsockets logging: 0
WebSockets server started (port 8188)...
 

2.android studio 導入webrtc和websoket庫 

implementation 'org.webrtc:google-webrtc:1.0.26131' 可以用最新的
implementation 'com.github.dfqin:grantor:2.5'
implementation "org.java-websocket:Java-WebSocket:1.3.8"

如果不熟悉android webrtc的開發的可以參考https://www.jianshu.com/p/8c10146afd6c

3.實現webscoket

主要對webscoket 的消息進行發送和接收  並把sdp信息給webrtc peerconntion

package com.liiln.janus5.echo;

import android.util.Log;


import com.liiln.janus5.janus.MyTools;

import org.java_websocket.client.WebSocketClient;
import org.java_websocket.drafts.Draft;
import org.java_websocket.drafts.Draft_6455;
import org.java_websocket.extensions.IExtension;
import org.java_websocket.handshake.ServerHandshake;
import org.java_websocket.protocols.IProtocol;
import org.java_websocket.protocols.Protocol;
import org.json.JSONException;
import org.json.JSONObject;
import org.webrtc.IceCandidate;
import org.webrtc.SessionDescription;

import java.math.BigInteger;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.concurrent.ConcurrentHashMap;


public class EchoWebSocketChannel  extends WebSocketClient {
    private ConcurrentHashMap<BigInteger, PlugHandle> attachedPlugins = new ConcurrentHashMap();
    private ConcurrentHashMap<String, ITransaction> transactions = new ConcurrentHashMap();
    private BigInteger sessionId = null;
    private Delegate _delegate = null;
    public EchoWebSocketChannel(URI serverUri, Draft protocolDraft) {
        super(serverUri, protocolDraft);
    }

    @Override
    public void onOpen(ServerHandshake handshakedata) {
        //
        createSession();
    }

    @Override
    public void onMessage(String message) {
        Log.e("提示收到消息》》》",message);
        //
        try {
            JSONObject msg  = new JSONObject(message);
            String janus = msg.getString("janus");
            if(janus.equals("success")){
                String tid = msg.getString("transaction");
                ITransaction transaction = transactions.get(tid);
                if(transaction!=null){
                    transactions.remove(tid);
                    transaction.onSuccess(msg);
                }
            }else if(janus.equals("error")){
                String tid = msg.getString("transaction");
                ITransaction transaction = transactions.get(tid);
                if(transaction!=null){
                    transactions.remove(tid);
                    transaction.onError();
                }
            }else if(janus.equals("ack")){
            }else{
                if(msg.has("sender")) {
                    BigInteger sender = new BigInteger(msg.getString("sender"));
                    PlugHandle handle = attachedPlugins.get(sender);
                    if (handle != null) {
                        if (janus.equals("event")) {
                            JSONObject data = msg.getJSONObject("plugindata").getJSONObject("data");
                            JSONObject jsep = null;
                            if(msg.has("jsep")){
                                jsep = msg.getJSONObject("jsep");
                            }
                            _delegate.onMessage(sender, data, jsep); //
                        } else if (janus.equals("detached")) {
                            _delegate.onLeaving(sender);//
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }



    }

    @Override
    public void onClose(int code, String reason, boolean remote) {

    }

    @Override
    public void onError(Exception ex) {

    }

    public interface Delegate{
        void onMessage(BigInteger handleId, JSONObject msg, JSONObject jsep);
        void onLeaving(BigInteger handleId);
        void onAttached(BigInteger handleId);
    }
    public void setDelegate(Delegate delegate){
        _delegate =delegate;
    }

    public static EchoWebSocketChannel init(String url) {
        EchoWebSocketChannel websocket = null;
        try {
            ArrayList<IProtocol> protocols = new ArrayList<IProtocol>();
            protocols.add(new Protocol("janus-protocol"));
            Draft_6455 proto_janus = new Draft_6455(Collections.<IExtension>emptyList(), protocols);
            websocket = new EchoWebSocketChannel(new URI(url),proto_janus);
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }
        websocket.connect();
        return websocket;
    }

    public void disconnect(){
        stopKeepAliveTimer();
        super.close();
    }
    public void sendmessage(String message){
        Log.e("提示","send==>>"+message);
        send(message);
    }

    private volatile Thread keep_alive = null;
    boolean connected = false;
    private void startKeepAliveTimer(){
        connected = true;
        keep_alive = new Thread(new Runnable() {
            @Override
            public void run() {
                Thread thisThread = Thread.currentThread();
                while (keep_alive == thisThread) {
                    try {
                        thisThread.sleep(25000);
                    } catch (InterruptedException ex) {
                    }
                    if (!connected) {
                        return;
                    }
                    JSONObject obj = new JSONObject();
                    try {
                        obj.put("janus", "keepalive");
                        obj.put("session_id", sessionId);
                        obj.put("transaction", MyTools.randomString(12));
                        sendmessage(obj.toString());
                    } catch (JSONException e) {
                        connected = false;
                        return;
                    }
                }
            }
        }, "KeepAlive");
        Log.e("提示","socket end");
        keep_alive.start();
    }
    private void stopKeepAliveTimer(){
        keep_alive = null;
        connected = false;
    }
    private void createSession(){
        String tid = MyTools.randomString(12);
        transactions.put(tid, new ITransaction(tid) {
            @Override
            public void onSuccess(JSONObject msg) throws Exception{
                JSONObject data = msg.getJSONObject("data");
                sessionId = new BigInteger(data.getString("id"));
                Log.e("===>","收到sessionId"+sessionId);
                startKeepAliveTimer();
                createHandle();
                /**
                 JSONObject objx = new JSONObject();
                 objx.put("janus", "info");
                 objx.put("transaction",  stringGenerator.randomString(12));
                 sendmessage(objx.toString());
                 **/
            }
        });
        try{
            JSONObject obj = new JSONObject();
            obj.put("janus", "create");
            obj.put("transaction", tid);
            sendmessage(obj.toString());
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    private void createHandle(){
        String tid = MyTools.randomString(12);
        transactions.put(tid, new ITransaction(tid) {
            @Override
            public void onSuccess(JSONObject msg) throws Exception{
                JSONObject data = msg.getJSONObject("data");
                BigInteger handleId = new BigInteger(data.getString("id"));
                Log.e("===>","handleId="+handleId);
                _delegate.onAttached(handleId);
                PlugHandle handle = new PlugHandle(handleId);
                attachedPlugins.put(handleId,handle);
                //registerUsrname(handleId);
            }
        });

        try{
            JSONObject obj = new JSONObject();
            obj.put("janus", "attach");
            obj.put("transaction", tid);
            obj.put("plugin", "janus.plugin.echotest");
            obj.put("session_id",sessionId);
            sendmessage(obj.toString());
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    public void publisherCreateOffer(final BigInteger handleId, final SessionDescription sdp) {
        JSONObject publish = new JSONObject();
        JSONObject jsep = new JSONObject();
        JSONObject message = new JSONObject();
        try {
            publish.putOpt("request", "configure");
            publish.putOpt("audio", true);
            publish.putOpt("video", true);

            jsep.putOpt("type", sdp.type);
            jsep.putOpt("sdp", sdp.description);

            message.putOpt("janus", "message");
            message.putOpt("body", publish);
            message.putOpt("jsep", jsep);
            message.putOpt("transaction", MyTools.randomString(12)  );
            message.putOpt("session_id", sessionId);
            message.putOpt("handle_id", handleId);
        } catch (JSONException e) {
            e.printStackTrace();
        }
        sendmessage(message.toString());
    }


    public void trickleCandidate(final BigInteger handleId, final IceCandidate iceCandidate) {
        JSONObject candidate = new JSONObject();
        JSONObject message = new JSONObject();
        try {
            candidate.putOpt("candidate", iceCandidate.sdp);
            candidate.putOpt("sdpMid", iceCandidate.sdpMid);
            candidate.putOpt("sdpMLineIndex", iceCandidate.sdpMLineIndex);

            message.putOpt("janus", "trickle");
            message.putOpt("candidate", candidate);
            message.putOpt("transaction", MyTools.randomString(12));
            message.putOpt("session_id", sessionId);
            message.putOpt("handle_id", handleId);
        } catch (JSONException e) {
            e.printStackTrace();
        }
        sendmessage(message.toString());
    }

    public void trickleCandidateComplete(final BigInteger handleId) {
        JSONObject candidate = new JSONObject();
        JSONObject message = new JSONObject();
        try {
            candidate.putOpt("completed", true);

            message.putOpt("janus", "trickle");
            message.putOpt("candidate", candidate);
            message.putOpt("transaction", MyTools.randomString(12));
            message.putOpt("session_id", sessionId);
            message.putOpt("handle_id", handleId);
        } catch (JSONException e) {
            e.printStackTrace();
        }
        sendmessage(message.toString());
    }
 

}

//額外類

public abstract class ITransaction {
    public String _tid = null;
    public ITransaction(String tid){
        _tid = tid;
    }
    public void onError(){};
    public void onSuccess(JSONObject data)throws Exception{};
}
public class PlugHandle {
    private BigInteger _handleId = null;
    public PlugHandle(BigInteger handleId){
        _handleId = handleId;
    }
}

3 、結合webrtc庫使用 參考上面的android webrtc 連接

1.創建PeerConnectionFactory 、PeerConnection

  2.peerConnection.addStream(mediaStream);

  3.peerConnection.createOffer 成功後將sdp 發送

_websocket.publisherCreateOffer(handleId,sdp);

 4.發送後webscoket會收到anwer的sdp信息設置給peerConnection

peerConnection.setRemoteDescription

5.設置後peerConnection 的onAddStream會返回 video數據 用webrtc.SurfaceViewRenderer顯示就行了

VideoTrack remoteVideoTrack = mediaStream.videoTracks.get(0);
runOnUiThread(() -> {
    if(remoteVideoTrack!=null) remoteVideoTrack.addSink(remoteView);
});

6.ice的調用

trickleCandidate(handleId, candidate);和trickleCandidateComplete(handleId); 發送

4、測試

  

其他demo 比如會議、對話等可以參考博客列表

交流羣261074724 

 

 

 

 

 

 

發佈了92 篇原創文章 · 獲贊 8 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章