Sample code

package com.cylan.artcsdk;

import android.util.Log;

import org.java_websocket.client.WebSocketClient;
import org.java_websocket.drafts.Draft_6455;
import org.java_websocket.handshake.ServerHandshake;
import org.json.JSONException;
import org.json.JSONObject;

import java.lang.ref.WeakReference;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;


public class ARtcService {
    private static final String TAG = "ARtcService";
    private String mServerUrl;
    private String mUid;
    private ARtcState mState = ARtcState.none;
    private Observer mObserver;
    private WebSocketClient mSignal;
    Timer time;
    private final HashMap<String, SessionInfo> mSessions;

    private static class SessionInfo {
        public List<String> queueCandidates;
        public WeakReference<ARtcSession> wkSession;

        public SessionInfo() {
            queueCandidates = new ArrayList<>();
        }
    }

    public interface Observer {
        void onRemoteCall(String peerId, String peerCallInfo, String permitCode);

        void onStateChanged(ARtcState state, int value, String msg);
    }

    public ARtcService() {
        mSessions = new HashMap<>();
    }

    public void connectToServer(String url, Observer observer) {
        this.mObserver = observer;
        mServerUrl = url + "/im";
        if (mSignal != null) {
            Log.d(TAG, "signal not empty");
            return;
        }
        Log.i(TAG, "connect to " + url);
        mState = ARtcState.connecting;

        connectInternal(mServerUrl);

    }

    public void close(String peerId) {
        if (mSignal == null) {
            return;
        }
        mSessions.get(peerId).wkSession.get().closePeer(); //webrtc对端关闭连接
        try {
            JSONObject json = new JSONObject();
            json.put("opcode", "signout");
            if (mState == ARtcState.connected) {
                mSignal.send(json.toString());
            }

        } catch (JSONException e) {
            e.printStackTrace();
        }
        mState = ARtcState.closed;
        mSignal.close();
        mSignal = null;
        time.cancel();
        time = null;
    }

    public ARtcState getState() {
        return mState;
    }

    public String getUid() {
        return mUid;
    }

    public void addSession(String peerId, ARtcSession session) {
        synchronized (mSessions) {
            //if(mSessions.containsKey(peerId)) {
            //    Log.e(TAG, "add session with peerId:" + peerId + " failed, already exist");
            //    return ;
            //}
            SessionInfo si = new SessionInfo();
            si.wkSession = new WeakReference<>(session);
            mSessions.put(peerId, si);
            for (int i = 0; i < si.queueCandidates.size(); i++) {
                session.addRemoteCandidate(si.queueCandidates.get(i));
            }
            si.queueCandidates.clear();
        }
    }

    public void removeSession(String peerId) {
        synchronized (mSessions) {
            if (!mSessions.containsKey(peerId)) {
                mSessions.remove(peerId);
                return;
            }
            Log.e(TAG, "remove session with peerId:" + peerId + " failed");
        }
    }


    public void sendMessage(String message) {
        if (mState != ARtcState.connected) {
            Log.w(TAG, "sendMessage failed, state:" + mState);
            return;
        }
        mSignal.send(message);
    }

    private void reportState(ARtcState state) {
        mObserver.onStateChanged(state, 0, "");
    }

    private void reportError(int errCode, String msg) {
        mObserver.onStateChanged(ARtcState.failed, errCode, msg);
    }

    private void connectInternal(String url) {
        try {
            URI uri = new URI(url);
            Map<String, String> map = new HashMap<>();
            String originUrl = "http" + url.substring(url.indexOf(':'));
            map.put("Origin", originUrl);
            Log.i(TAG, "originUrl is:" + originUrl);

            mSignal = new WebSocketClient(uri, new Draft_6455(), map) {

                @Override
                public void onOpen(ServerHandshake handshakedata) {
                    Log.i(TAG, "Connected to server");
                    keepHeartBeatAlive();
                    try {
                        JSONObject json = new JSONObject();
                        json.put("opcode", "signin");
                        json.put("key", Constants.key);
                        json.put("secret", Constants.secrect);
                        json.put("loginType", 0);
                        mSignal.send(json.toString());
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                }

                @Override
                public void onMessage(String message) {
                    Log.i(TAG, "Received message: " + message);

                    boolean ret = handleMessage(message);
                    if (!ret) {
                        mState = ARtcState.failed;
                        Log.e(TAG, "JSON parse failed. " + message);
                        mObserver.onStateChanged(mState, -1, "JSON parse failed");
                    }
                }

                @Override
                public void onClose(int code, String reason, boolean remote) {
                    if (code != 0) {
                        if (mState != ARtcState.closed) { //客户端单向关闭连接
                            connectInternal(url);
                            Log.i(TAG, "Connection error reconnecting....., code: " + code + " reason:" + reason);
                        }
                        mState = ARtcState.failed;
                        Log.i(TAG, "Connection error, code: " + code + " reason:" + reason);

                    } else {
                        mState = ARtcState.closed; //正常回调的关闭
                        Log.i(TAG, "Connection closed, code: " + code + " reason:" + reason);
                    }
                    mObserver.onStateChanged(mState, code, reason);
                }

                @Override
                public void onError(Exception ex) {
                    Log.i(TAG, "Connected Error");
                }
            };
            mSignal.connect();
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }


    }

    private static volatile long lastHeartBeat;

    private void keepHeartBeatAlive() {
        time = new Timer();
        time.schedule(new TimerTask() {
            @Override
            public void run() {
                while (mSignal != null) {
                    if (System.currentTimeMillis() - lastHeartBeat > 60 * 1000L) {
                        lastHeartBeat = System.currentTimeMillis();
                        sendHeartBeat();
                    }

                }
            }
        }, 0L);


    }

    private void sendHeartBeat() {
        try {
            JSONObject json = new JSONObject();
            json.put("opcode", "heartbeat");
            mSignal.send(json.toString());
            Log.i(TAG, "client send heart beat------> ");
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    /**
     * Received message: {"opcode":"signin","code":0,"msg":"ok","sid":31,"stunAddr":["stun:yf.jfgou.com:3478"],"turnAddr":["turn:yf.jfgou.com:3478?transport=udp"],"turnUser":["test"],"turnPass":["123456"]}
     *
     * @param payload
     * @return
     */
    private boolean handleMessage(String payload) {
        try {
            JSONObject root = new JSONObject(payload);
            String opcode = root.getString("opcode");
            if (opcode.equals("signin")) {
                mUid = root.getString("sid");
                if (mUid.isEmpty()) {
                    return false;
                }
                Log.i(TAG, "signin successed, GOT local uid " + mUid);
                mState = ARtcState.connected;
                mObserver.onStateChanged(mState, 0, "");
            } else if (opcode.equals("message")) {
                String peerId = root.getString("serialCode");
                String message = root.getString("message");
                String messageType = root.getString("messageType");
                // 强制中转视频流
//                boolean relayOnly = root.has("relayOnly");
                if (messageType.equals("callRequest")) {
                    String permitCode = root.getString("permitCode");
                    mObserver.onRemoteCall(peerId, message, permitCode);
                } else if (messageType.equals("callResponse")) {
                    handleAnswer(peerId, message);
                } else if (messageType.equals("remoteCandidate")) {
                    handleRemoteCandidate(peerId, message);
                } else if (messageType.equals("hangup")) {
                    handleHangUp(peerId, message);
                    return true;
                } else {
                    Log.w(TAG, "unkown messageType: " + messageType);
                    return false;
                }
            } else if (opcode.equals("heartbeat")) {
                if (root.getInt("code") == 0) {
                    Log.i(TAG, "Server response heart ------>");
                }
            } else {
                Log.w(TAG, "unkown opcode: " + opcode);
                return false;
            }
            return true;
        } catch (JSONException e) {
            e.printStackTrace();
        }
        return false;
    }

    private void handleAnswer(String peerId, String message) {
        ARtcSession session = getPeerSession(peerId);
        if (session == null) {
            Log.d(TAG, "session not found for: " + peerId);
            return;
        }
        session.setRemoteAnswer(message);
    }

    private void handleHangUp(String peerId, String message) {
        ARtcSession session = getPeerSession(peerId);
        session.onDisconnected();

    }

    private void handleRemoteCandidate(String peerId, String message) {
        ARtcSession session = null;
        synchronized (mSessions) {
            SessionInfo si = getSessionInfo(peerId);
            if (si.wkSession == null) {
                si.queueCandidates.add(message);
                return;
            }
            session = si.wkSession.get();
            if (session == null) {
                mSessions.remove(peerId);
                Log.d(TAG, "remove invalid session of peerId: " + peerId);
                return;
            }
        }
        session.addRemoteCandidate(message);
    }

    private SessionInfo getSessionInfo(String peerId) {
        SessionInfo si = mSessions.get(peerId);
        if (si == null) {
            si = new SessionInfo();
            mSessions.put(peerId, si);
        }
        return si;
    }

    private ARtcSession getPeerSession(String peerId) {
        synchronized (mSessions) {
            SessionInfo si = mSessions.get(peerId);
            if (si == null) {
                si = new SessionInfo();
                mSessions.put(peerId, si);
            }
            if (si.wkSession == null) {
                return null;
            }
            ARtcSession session = si.wkSession.get();
            if (session == null) {
                mSessions.remove(peerId);
                Log.d(TAG, "remove invalid session of peerId: " + peerId);
                return null;
            }
            return session;
        }
    }

}

results matching ""

    No results matching ""