Alex Khotiun
Alex Khotiun

Reputation: 431

Can not send video and audio in webrtc on android

Hi) I have some truble with webrtc on android. I read many manual and tutorial to resolve my issue. I saw many question like mine, but it could'n help. We create our own signaling server and I want to join with my android client. Browser client get my offer and android get browser answer and candidate. After that my app close without crash and no message in the logcat. Please, can someboby help me? Thanks in advance. My code

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN
            | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
            | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
            | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
            | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
    mWifiManager = (WifiManager)getSystemService(Context.WIFI_SERVICE);
    strengthWifiIcon.add(getResources().getDrawable(R.drawable.signal_0));
    strengthWifiIcon.add(getResources().getDrawable(R.drawable.signal_1));
    strengthWifiIcon.add(getResources().getDrawable(R.drawable.signal_2));
    strengthWifiIcon.add(getResources().getDrawable(R.drawable.signal_3));
    strengthWifiIcon.add(getResources().getDrawable(R.drawable.signal_4));
    strengthWifiIcon.add(getResources().getDrawable(R.drawable.signal_5));
    setContentView(R.layout.video_chat_layout);
    sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
    sid = sharedPreferences.getString("sessionId", null);
    peerId = getIntent().getStringArrayListExtra("peerId");
    Log.d("myLogs", "peerId" + peerId);
    videoView = (GLSurfaceView) findViewById(R.id.gl_surface);
    pbBatteryIndicator = (ProgressBar) findViewById(R.id.batteryIndicator);
    tvPercentIndicator = (TextView) findViewById(R.id.percentIndicator);
    ivStrengthSignal = (ImageView) findViewById(R.id.wifiStrength);
    chronometer = (Chronometer) findViewById(R.id.chronometer);
    finishCall = (Button) findViewById(R.id.finishCall);
    finishCall.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            finish();
        }
    });
    chronometer.start();
    videoView.setPreserveEGLContextOnPause(true);
    videoView.setKeepScreenOn(true);
    VideoRendererGui.setView(videoView, new Runnable() {
        @Override
        public void run() {
        }
    });
    try {
        remoteRender = VideoRendererGui.create(
                REMOTE_X, REMOTE_Y,
                REMOTE_WIDTH, REMOTE_HEIGHT, scalingType, false);//for remote video
        localRender = VideoRendererGui.create(
                LOCAL_X_CONNECTING, LOCAL_Y_CONNECTING,
                LOCAL_WIDTH_CONNECTING, LOCAL_HEIGHT_CONNECTING, scalingType, true);//for local video
    } catch (Exception e) {
        e.printStackTrace();
    }
    initSocket(getResources().getString(R.string.endpointSocketURL), getResources().getString(R.string.endpointSocketPath), sid);
    Log.d("myLogs", "get stun servers");
    MainActivity.textClock.setVisibility(View.VISIBLE);
    MainActivity.relativeLayout.setVisibility(View.GONE);
}

private void initSocket(String address, String path, String sessionId){
    SocketService.socket.disconnect();
    IO.Options opts= new IO.Options();
    opts.transports = new String[] {PollingXHR.NAME};
    try {
        opts.path = path;
        opts.query="sessionId="+sessionId;
        socket = IO.socket(new URI(address), opts);
    } catch (URISyntaxException e) {
        e.printStackTrace();
    }
    socket.on(Socket.EVENT_ERROR, new Emitter.Listener() {
        @Override
        public void call(Object... args) {
            Log.d("myLogs","error" + args[0]);
        }
    });

    socket.on(Socket.EVENT_CONNECT_ERROR, new Emitter.Listener() {
        @Override
        public void call(Object... args) {
            Log.d("myLogs", "error" + args[0]);
        }
    });
    socket.on(Socket.EVENT_CONNECT, new Emitter.Listener() {
        @Override
        public void call(Object... args) {
            Log.d("myLogs", "socket connected");
            socket.emit("stunservers", new Ack() {
                @Override
                public void call(Object... args) {
                    if (args[0] == null) {
                        try {
                            JSONArray array = new JSONArray(args[1].toString());
                            Log.d("myLogs", "array stun servers length" + array.length());
                            for (int i = 0; i < array.length(); i++) {
                                JSONObject url = array.getJSONObject(i);
                                Log.d("myLogs", "stun " + url.getString("url"));
                                iceServers.add(new PeerConnection.IceServer(url.getString("url")));
                            }
                        } catch (JSONException e) {
                            e.printStackTrace();
                        }
                        SocketService.socket.emit("turnservers", new Ack() {
                            @Override
                            public void call(Object... args) {
                                if (args[0] == null) {
                                    try {
                                        JSONArray array = new JSONArray(args[1].toString());
                                        for (int i = 0; i < array.length(); i++) {
                                            JSONObject url = array.getJSONObject(i);
                                            Log.d("myLogs", "turn " + url.getString("url"));
                                            iceServers.add(new PeerConnection.IceServer(url.getString("url"), url.getString("username"), url.getString("credential")));
                                        }
                                        init();

                                    } catch (JSONException e) {
                                        e.printStackTrace();
                                    }
                                } else {
                                    Log.d("myLogs", "turn servers emit" + args[0]);
                                }
                            }
                        });
                    } else {
                        Log.d("myLogs", "error stunservers emit" + args[0]);
                    }
                }
            });

        }
        // this is the emit from the server
    }).on(Socket.EVENT_DISCONNECT, new Emitter.Listener() {

        @Override
        public void call(Object... args) {
            Log.d("ActivityName: ", "socket disconnected");
        }
    });
    socket.on("message", messageHandler.onMessage);
    socket.connect();
}

private void init(){
    Log.d("myLogs", "init");
    boolean peerConnection = PeerConnectionFactory.initializeAndroidGlobals(this, true, true,
            false);
    Log.d("myLogs", "peerConnection android globals" + peerConnection);
    factory = new PeerConnectionFactory();
    pcConstraints.mandatory.add(new MediaConstraints.KeyValuePair("OfferToReceiveAudio", "true"));
    pcConstraints.mandatory.add(new MediaConstraints.KeyValuePair("OfferToReceiveVideo", "true"));
    pcConstraints.optional.add(new MediaConstraints.KeyValuePair("DtlsSrtpKeyAgreement", "true"));
    Point displaySize = new Point();
    getWindowManager().getDefaultDisplay().getSize(displaySize);
    lMS = factory.createLocalMediaStream("ARDAMS");
    MediaConstraints videoConstraints = new MediaConstraints();
    videoConstraints.mandatory.add(new MediaConstraints.KeyValuePair("maxHeight",Integer.toString(displaySize.x)));
    videoConstraints.mandatory.add(new MediaConstraints.KeyValuePair("maxWidth", Integer.toString(displaySize.y)));
    videoSource = factory.createVideoSource(getVideoCapturer(), videoConstraints);
    AudioSource audioSource = factory.createAudioSource(new MediaConstraints());
    VideoTrack localVideoTrack = factory.createVideoTrack("ARDAMSv0", videoSource);
    AudioTrack localAudioTrack =factory.createAudioTrack("ARDAMSa0", audioSource);
    localVideoTrack.addRenderer(new VideoRenderer(localRender));
    localVideoTrack.addRenderer(new VideoRenderer(remoteRender));
    lMS.addTrack(localAudioTrack);
    lMS.addTrack(localVideoTrack);
    Peer peer = new Peer(peerId.get(0));
    Log.d("myLogs","create offer from init");
    peer.pc.createOffer(peer, pcConstraints);
    //sendMessage();
}

@Override
public void onPause() {
    super.onPause();
    /*videoView.onPause();
    if(client != null) {
        client.onPause();
    }*/
}

@Override
public void onStop() {
    /*if(client != null) {
        client.onDestroy();
    }*/
    unregisterReceiver(this.mBatInfoReceiver);
    unregisterReceiver(this.mWifiInfoReceiver);
    chronometer.stop();
    for (Peer peer : peers.values()) {
        peer.pc.dispose();
    }
    socket.disconnect();
    SocketService.socket.connect();
    super.onStop();
}

@Override
public void onResume() {
    super.onResume();
    /*videoView.onResume();
    if(client != null) {
        client.onResume();
    }*/
    registerReceiver(this.mBatInfoReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
    registerReceiver(this.mWifiInfoReceiver, new IntentFilter(WifiManager.RSSI_CHANGED_ACTION));
}

/**
 * All class and function data fo WebRTC
 */
public interface Command{
    void execute(String peerId, JSONObject payload) throws JSONException;
}

public class CreateAnswerCommand implements Command{
    @Override
    public void execute(String peerId, JSONObject payload) throws JSONException {
        Log.d("myLogs","CreateAnswerCommand");
        Peer peer = peers.get(peerId);
        SessionDescription sdp = new SessionDescription(
                SessionDescription.Type.fromCanonicalForm(payload.getString("type")),
                payload.getString("sdp")
        );
        peer.pc.setRemoteDescription(peer, sdp);
        peer.pc.createAnswer(peer, pcConstraints);
    }
}

public class SetRemoteSDPCommand implements Command{
    public void execute(String peerId, JSONObject json) throws JSONException {
        try {
            Log.d("myLogs","SetRemoteSdpCommand " + json.getJSONObject("payload"));
            json.getJSONObject("payload");
        }catch (JSONException e){
            Log.d("myLogs", "error in set remote sdp can not get payload and stacktrace ");
            e.printStackTrace();
        }
        Peer peer = peers.get(peerId);
        SessionDescription sdp = new SessionDescription(SessionDescription.Type.fromCanonicalForm(json.getJSONObject("payload").getString("type")),
                json.getJSONObject("payload").getString("sdp"));
        peer.pc.setRemoteDescription(peer, sdp);
    }
}

public class LeaveCommand implements Command {
    public void execute(String peerId, JSONObject payload) throws JSONException {
        Log.d("myLogs", "LeaveCommand");
        sendMessage(peerId, "leave", payload);
    }
}

public class AddIceCandidateCommand implements Command{
    public void execute(String peerId, JSONObject json) throws JSONException {
        Log.d("myLogs","AddIceCandidateCommand");
        JSONObject jsonCandidate = json.getJSONObject("payload").getJSONObject("candidate");
        Log.d("myLogs", "AddIceCandidateCommand");
        PeerConnection pc = peers.get(to).pc;
        if (pc.getRemoteDescription() != null) {
            IceCandidate candidate = new IceCandidate(
                    jsonCandidate.getString("sdpMid"),
                    jsonCandidate.getInt("sdpMLineIndex"),
                    jsonCandidate.getString("candidate")
            );
            pc.addIceCandidate(candidate);
        }
    }
}

private void sendMessage(String to, String type, JSONObject payload) throws JSONException {
    Log.d("myLogs","sendMessage" + " " + type + " " + payload.toString());
    if(type.equals("leave")){
        SocketService.socket.emit(type);
    }
    JSONObject message = new JSONObject();
    message.put("to", to);
    message.put("sid", sid);
    message.put("roomType", roomType);
    message.put("type", type);
    message.put("payload", payload);
    message.put("prefix",prefix);
    /*if(type.equals("answer")){
        message.put("from",from);
    }*/
    Log.d("myLogs","send message with type" + type);
    SocketService.socket.emit("message", message);
}

private class MessageHandler {
    private HashMap<String, Command> commandMap;

    private MessageHandler() {
        this.commandMap = new HashMap<>();
        commandMap.put("offer", new CreateAnswerCommand());
        commandMap.put("answer", new SetRemoteSDPCommand());
        commandMap.put("candidate", new AddIceCandidateCommand());
        commandMap.put("leave", new LeaveCommand());
    }

    private Emitter.Listener onMessage = new Emitter.Listener() {
        @Override
        public void call(Object... args) {
            if (args[0] != null) {
                JSONObject data = (JSONObject) args[0];
                try {
                    type = data.getString("type");
                    from = data.getString("from");
                    Log.d("myLogs", "onMessage " + type + " " + data.toString());
                    if (type.equalsIgnoreCase("offer")) {
                        //parseJsonOfferAnswer(data);
                        commandMap.get(type).execute(to, payload);
                        Log.d("myLogs", "command map "+ type);
                    }
                    if (type.equalsIgnoreCase("answer")) {
                        //parseJsonOfferAnswer(data);
                        Log.d("myLogs", "command map " + type + "peers " + peers + peers.containsValue(from) + peers.containsKey(from));
                        //if peer is unknown, add him
                        if(!peers.containsValue(from)) {
                            addPeer(from);
                        }
                        commandMap.get(type).execute(from, payload);
                    }
                    if (type.equalsIgnoreCase("candidate")) {
                        Log.d("myLogs", "command map "+ type);
                        commandMap.get(type).execute(from, payload);
                        parseJsonCandidate(data.getJSONObject("payload").getJSONObject("candidate"));
                    }
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
            else {
                Log.d("myLogs", "error " + args[0]);
            }
        }
    };
}

private void parseJsonOfferAnswer(JSONObject json) throws JSONException {
    to = json.getString("to");
    type = json.getString("type");
    sid = json.getString("sid");
    roomType = json.getString("roomType");
    from = json.getString("from");
    payload = json.getJSONObject("payload");
    sdpPayload = payload.getString("sdp");
    typePayload = payload.getString("type");
    if(type.equals("answer")){
        from = json.getString("from");
    }
}

private void parseJsonCandidate(JSONObject candidate) throws JSONException {
    this.candidate  = candidate.getString("candidate");
    this.sdpMid = candidate.getString("sdpMid");
    this.sdpMLineIndex = candidate.getString("sdpMLineIndex");
}

private class Peer implements SdpObserver, PeerConnection.Observer{
    private PeerConnection pc;
    private String id;

    @Override
    public void onIceConnectionReceivingChange(boolean b) {

    }

    @Override
    public void onCreateSuccess(final SessionDescription sdp) {
        Log.d("myLogs","onCreateSuccess " + sdp.type.canonicalForm());
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                try {
                    JSONObject message = new JSONObject();
                    JSONObject payload = new JSONObject();
                    payload.put("type", sdp.type.canonicalForm());
                    payload.put("sdp", sdp.description);
                    message.put("payload", payload);
                    sendMessage(id, sdp.type.canonicalForm(), payload);
                    pc.setLocalDescription(Peer.this, sdp);
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
        });
    }

    @Override
    public void onSetSuccess() {
        Log.d("myLogs","onSetSuccess");
        runOnUiThread(new Runnable() {
            public void run() {
                //pc.createAnswer(Peer.this, pcConstraints);
            }
        });
    }

    @Override
    public void onCreateFailure(String s) {
        Log.d("myLogs", "onCreateFailure " + s);
    }

    @Override
    public void onSetFailure(String s) {
        Log.d("myLogs", "onSetFailure " + s);
    }

    @Override
    public void onSignalingChange(PeerConnection.SignalingState signalingState) {
        Log.d("myLogs","onSignalChange " + signalingState);
        if(signalingState == PeerConnection.SignalingState.CLOSED) {
            removePeer(id);
        }

    }

    @Override
    public void onIceConnectionChange(PeerConnection.IceConnectionState iceConnectionState) {
        Log.d("myLogs","onIceConnectionChange " + iceConnectionState);
    }

    @Override
    public void onIceGatheringChange(PeerConnection.IceGatheringState iceGatheringState) {
        Log.d("myLogs","onIceGatheringChange " + iceGatheringState);
    }

    @Override
    public void onIceCandidate(final IceCandidate candidate) {
        Log.d("myLogs","onIceCandidate ");
        pc.addIceCandidate(candidate);
        runOnUiThread(new Runnable() {
            public void run() {
                try {
                    JSONObject payload = new JSONObject();
                    JSONObject candidateJson = new JSONObject();
                    candidateJson.put("candidate", candidate.sdp);
                    payload.put("candidate", candidateJson);
                    payload.put("sdpMid", candidate.sdpMid);
                    payload.put("sdpMLineIndex", candidate.sdpMLineIndex);
                    sendMessage(id, "candidate", payload);
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
        });
    }


    @Override
    public void onDataChannel(DataChannel dataChannel) {
        Log.d("myLogs","onDataChannel");
    }

    @Override
    public void onRenegotiationNeeded() {
        Log.d("myLogs","onRenegotiationNeeded");
    }

    @Override
    public void onAddStream(MediaStream mediaStream) {
        Log.d("myLogs","onAddStream");
        mediaStream.videoTracks.get(0).addRenderer(new VideoRenderer(remoteRender));
        VideoRendererGui.update(remoteRender,
                REMOTE_X, REMOTE_Y,
                REMOTE_WIDTH, REMOTE_HEIGHT, scalingType,false);
        VideoRendererGui.update(localRender,
                LOCAL_X_CONNECTED, LOCAL_Y_CONNECTED,
                LOCAL_WIDTH_CONNECTED, LOCAL_HEIGHT_CONNECTED,
                scalingType, true);
    }

    @Override
    public void onRemoveStream(MediaStream mediaStream) {
        Log.d("myLogs","onRemoveStream");
        removePeer(id);
    }

    public Peer(String id) {
        Log.d("myLogs","initialize peer id");
        if(SocketService.iceServers.size()>0)
            this.pc = factory.createPeerConnection(SocketService.iceServers, pcConstraints, this);
        else{
            Log.d("myLogs","error to get turn and stun servers ");
        }
        pc.createOffer(this,pcConstraints);
        this.id = id;
    }
}

public VideoCapturer getVideoCapturer() {
    Log.d("myLogs", "getVideoCapture");
    /*String name;
    // Returns the number of camera devices
    VideoCapturerAndroid.getDeviceCount();
    // Returns the front face device name
    name = VideoCapturerAndroid.getNameOfFrontFacingDevice();
    // Creates a VideoCapturerAndroid instance for the device name*/
    String cameraDeviceName;
    String frontCameraDeviceName = CameraEnumerationAndroid.getNameOfFrontFacingDevice();
    VideoCapturer videoCapturer;
    cameraDeviceName = frontCameraDeviceName;
    videoCapturer = VideoCapturerAndroid.create(cameraDeviceName);
    return videoCapturer;
}

public void addPeer(String id) {
    Log.d("myLogs","addPeer" + id);
    Peer peer = new Peer(id);
    peer.pc.addStream(lMS);
    peers.put(id, peer);
}

public void removePeer(String id) {
    Log.d("myLogs","removePeer" + id);
    Peer peer = peers.get(id);
    peer.pc.close();
    peer.pc.dispose();
    peers.remove(peer.id);
}

Upvotes: 1

Views: 2608

Answers (1)

Alex Khotiun
Alex Khotiun

Reputation: 431

I resolve my issue. Its absolutely working code)

private ProgressBar pbBatteryIndicator;
private TextView tvPercentIndicator;
private Button finishCall;
private ImageView ivStrengthSignal;
private Chronometer chronometer;
private WifiManager mWifiManager;
private ArrayList<Drawable> strengthWifiIcon = new ArrayList<>();
// Local preview screen position before call is connected.
private static final int LOCAL_X_CONNECTING = 0;
private static final int LOCAL_Y_CONNECTING = 0;
private static final int LOCAL_WIDTH_CONNECTING = 100;
private static final int LOCAL_HEIGHT_CONNECTING = 100;
// Local preview screen position after call is connected.
private static final int LOCAL_X_CONNECTED = 72;
private static final int LOCAL_Y_CONNECTED = 72;
private static final int LOCAL_WIDTH_CONNECTED = 25;
private static final int LOCAL_HEIGHT_CONNECTED = 25;
// Remote video screen position
private static final int REMOTE_X = 0;
private static final int REMOTE_Y = 0;
private static final int REMOTE_WIDTH = 100;
private static final int REMOTE_HEIGHT = 100;
private RendererCommon.ScalingType scalingType = RendererCommon.ScalingType.SCALE_ASPECT_FILL;
private VideoRenderer.Callbacks localRender;
private VideoRenderer.Callbacks remoteRender;
//private String mSocketAddress;
private GLSurfaceView videoView;
private ArrayList<String> peerId = new ArrayList<>();
public String roomType="video",to,from,sid,type,prefix = "webkit";
private JSONObject payload;
private HashMap<String, Peer> peers = new HashMap<>();
private MediaConstraints pcConstraints = new MediaConstraints();
private MediaStream lMS;
private PeerConnectionFactory factory;
private final MessageHandler messageHandler = new MessageHandler();
private SharedPreferences sharedPreferences;
private VideoSource videoSource;
public  LinkedList<PeerConnection.IceServer> iceServers = new LinkedList<>();


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN
            | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
            | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
            | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
            | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
    mWifiManager = (WifiManager)getSystemService(Context.WIFI_SERVICE);
    strengthWifiIcon.add(getResources().getDrawable(R.drawable.signal_0));
    strengthWifiIcon.add(getResources().getDrawable(R.drawable.signal_1));
    strengthWifiIcon.add(getResources().getDrawable(R.drawable.signal_2));
    strengthWifiIcon.add(getResources().getDrawable(R.drawable.signal_3));
    strengthWifiIcon.add(getResources().getDrawable(R.drawable.signal_4));
    strengthWifiIcon.add(getResources().getDrawable(R.drawable.signal_5));
    setContentView(R.layout.video_chat_layout);
    sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
    sid = sharedPreferences.getString("sessionId", null);
    peerId = getIntent().getStringArrayListExtra("peerId");
    Log.d("myLogs", "peerId" + peerId);
    videoView = (GLSurfaceView) findViewById(R.id.gl_surface);
    pbBatteryIndicator = (ProgressBar) findViewById(R.id.batteryIndicator);
    tvPercentIndicator = (TextView) findViewById(R.id.percentIndicator);
    ivStrengthSignal = (ImageView) findViewById(R.id.wifiStrength);
    chronometer = (Chronometer) findViewById(R.id.chronometer);
    finishCall = (Button) findViewById(R.id.finishCall);
    finishCall.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            /*socket.emit("leave", new Ack() {
                @Override
                public void call(Object... args) {
                    finish();
                }
            });*/
            finish();
        }
    });
    chronometer.start();
    videoView.setPreserveEGLContextOnPause(true);
    videoView.setKeepScreenOn(true);
    VideoRendererGui.setView(videoView, new Runnable() {
        @Override
        public void run() {
        }
    });
    try {
        remoteRender = VideoRendererGui.create(
                REMOTE_X, REMOTE_Y,
                REMOTE_WIDTH, REMOTE_HEIGHT, scalingType, false);//for remote video
        localRender = VideoRendererGui.create(
                LOCAL_X_CONNECTING, LOCAL_Y_CONNECTING,
                LOCAL_WIDTH_CONNECTING, LOCAL_HEIGHT_CONNECTING, scalingType, true);//for local video
    } catch (Exception e) {
        e.printStackTrace();
    }
    Log.d("myLogs", "get stun servers");
    getStunTurnServers();
    MainActivity.textClock.setVisibility(View.VISIBLE);
    MainActivity.relativeLayout.setVisibility(View.GONE);
}

private void getStunTurnServers(){
    SocketService.socket.on("message",messageHandler.onMessage);
    SocketService.socket.emit("stunservers", new Ack() {
        @Override
        public void call(Object... args) {
            if (args[0] == null) {
                try {
                    JSONArray array = new JSONArray(args[1].toString());
                    Log.d("myLogs", "array stun servers length" + array.length());
                    for (int i = 0; i < 50; i++) {
                        JSONObject url = array.getJSONObject(i);
                        Log.d("myLogs", "stun " + url.getString("url"));
                        iceServers.add(new PeerConnection.IceServer(url.getString("url")));
                    }
                } catch (JSONException e) {
                    e.printStackTrace();
                }
                SocketService.socket.emit("turnservers", new Ack() {
                    @Override
                    public void call(Object... args) {
                        if (args[0] == null) {
                            try {
                                JSONArray array = new JSONArray(args[1].toString());
                                for (int i = 0; i < array.length(); i++) {
                                    JSONObject url = array.getJSONObject(i);
                                    Log.d("myLogs", "turn " + url.getString("url"));
                                    iceServers.add(new PeerConnection.IceServer(url.getString("url"), url.getString("username"), url.getString("credential")));
                                }
                                init();
                            } catch (JSONException e) {
                                e.printStackTrace();
                            }
                        } else {
                            Log.d("myLogs", "turn servers emit" + args[0]);
                        }
                    }
                });
            } else {
                Log.d("myLogs", "error stunservers emit" + args[0]);
            }
        }
    });
}

private void init(){
    Log.d("myLogs", "init");
    boolean peerConnection = PeerConnectionFactory.initializeAndroidGlobals(this, true, true, true);
    Log.d("myLogs", "peerConnection android globals " + peerConnection);
    factory = new PeerConnectionFactory();
    pcConstraints.mandatory.add(new MediaConstraints.KeyValuePair("OfferToReceiveAudio", "true"));
    pcConstraints.mandatory.add(new MediaConstraints.KeyValuePair("OfferToReceiveVideo", "true"));
    pcConstraints.optional.add(new MediaConstraints.KeyValuePair("DtlsSrtpKeyAgreement", "true"));
    Point displaySize = new Point();
    getWindowManager().getDefaultDisplay().getSize(displaySize);
    lMS = factory.createLocalMediaStream("ARDAMS");
    MediaConstraints videoConstraints = new MediaConstraints();
    videoConstraints.mandatory.add(new MediaConstraints.KeyValuePair("maxHeight",Integer.toString(displaySize.x)));
    videoConstraints.mandatory.add(new MediaConstraints.KeyValuePair("maxWidth", Integer.toString(displaySize.y)));
    videoConstraints.mandatory.add(new MediaConstraints.KeyValuePair("maxFrameRate", Integer.toString(30)));
    videoConstraints.mandatory.add(new MediaConstraints.KeyValuePair("minFrameRate", Integer.toString(30)));
    videoSource = factory.createVideoSource(getVideoCapturer(), videoConstraints);
    AudioSource audioSource = factory.createAudioSource(new MediaConstraints());
    VideoTrack localVideoTrack = factory.createVideoTrack("ARDAMSv0", videoSource);
    AudioTrack localAudioTrack =factory.createAudioTrack("ARDAMSa0", audioSource);
    lMS.addTrack(localAudioTrack);
    lMS.addTrack(localVideoTrack);
    onLocalStream(lMS);
    for(int i=0;i<peerId.size();i++){
        Peer peer = new Peer(peerId.get(i));
        peers.put(peerId.get(i), peer);
        Log.d("myLogs", "create offer from init");
        peer.pc.createOffer(peer, pcConstraints);
    }

}

@Override
public void onPause() {
    super.onPause();
}

@Override
public void onStop() {
    unregisterReceiver(this.mBatInfoReceiver);
    unregisterReceiver(this.mWifiInfoReceiver);
    chronometer.stop();
    /*for (Peer peer : peers.values()) {
        peer.pc.dispose();
    }*/
    //videoSource.dispose();
    //factory.dispose();
    SocketService.socket.disconnect();
    SocketService.socket.connect();
    super.onStop();
}

@Override
public void onResume() {
    super.onResume();
    registerReceiver(this.mBatInfoReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
    registerReceiver(this.mWifiInfoReceiver, new IntentFilter(WifiManager.RSSI_CHANGED_ACTION));
}

/**
 * All class and function data for WebRTC
 */
public interface Command{
    void execute(String peerId, JSONObject payload) throws JSONException;
}

public class CreateAnswerCommand implements Command{
    @Override
    public void execute(String peerId, JSONObject payload) throws JSONException {
        Log.d("myLogs", "CreateAnswerCommand");
        Peer peer = peers.get(peerId);
        SessionDescription sdp = new SessionDescription(SessionDescription.Type.fromCanonicalForm(payload.getString("type")),
                payload.getString("sdp")
        );
        peer.pc.setRemoteDescription(peer, sdp);
        peer.pc.createAnswer(peer, pcConstraints);
    }
}

public class SetRemoteSDPCommand implements Command{
    public void execute(String peerId, JSONObject payload) throws JSONException {
        Log.d("myLogs", "SetRemoteSdpCommand ");
        Peer peer = peers.get(peerId);
        SessionDescription sdp = new SessionDescription(SessionDescription.Type.fromCanonicalForm(payload.getString("type")), payload.getString("sdp"));
        peer.pc.setRemoteDescription(peer, sdp);
        if(payload.getString("type").equalsIgnoreCase("answer")){
            //peer.pc.createAnswer(peer, pcConstraints);
        }
    }
}

public class AddIceCandidateCommand implements Command{
    public void execute(String peerId, JSONObject payload) throws JSONException {
        JSONObject jsonCandidate = payload.getJSONObject("candidate");
        Log.d("myLogs", "AddIceCandidateCommand");
        PeerConnection pc = peers.get(peerId).pc;
        if (pc.getRemoteDescription() != null) {
            Log.d("myLogs", "AddIceCandidateCommand "+jsonCandidate.toString());
            IceCandidate candidate = new IceCandidate(
                    jsonCandidate.getString("sdpMid"),
                    jsonCandidate.getInt("sdpMLineIndex"),
                    jsonCandidate.getString("candidate")
            );
            pc.addIceCandidate(candidate);
        }
    }
}

private void sendMessage(String to, String type, JSONObject payload) throws JSONException {
    Log.d("myLogs","sendMessage" + " " + type + " " + payload.toString());
    if(type.equals("leave")){
        SocketService.socket.emit(type);
    }
    JSONObject message = new JSONObject();
    message.put("to", to);
    message.put("sid", sid);
    message.put("roomType", roomType);
    message.put("type", type);
    message.put("payload", payload);
    message.put("prefix",prefix);
    Log.d("myLogs", "send message with type" + type);
    SocketService.socket.emit("message", message);
}

private class MessageHandler {
    private HashMap<String, Command> commandMap;

    private MessageHandler() {
        this.commandMap = new HashMap<>();
        commandMap.put("offer", new CreateAnswerCommand());
        commandMap.put("answer", new SetRemoteSDPCommand());
        commandMap.put("candidate", new AddIceCandidateCommand());
    }

    private Emitter.Listener onMessage = new Emitter.Listener() {
        @Override
        public void call(Object... args) {
            Log.d("myLogs", "on message listener");
            if (args[0] != null) {
                JSONObject data = (JSONObject) args[0];
                try {
                    type = data.getString("type");
                    payload = data.getJSONObject("payload");
                    Log.d("myLogs", "onMessage " + type + " " + data.toString());
                    if(type.equalsIgnoreCase("answer")) {
                        from = data.getString("from");
                        Log.d("myLogs", "equals ignore case answer" + from);
                    }
                    if(!peers.containsKey(from)) {
                        addPeer(from);
                        commandMap.get(type).execute(from, payload);
                    }
                    else{
                        commandMap.get(type).execute(from, payload);
                    }
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
        }
    };
}


private class Peer implements SdpObserver, PeerConnection.Observer{
    private PeerConnection pc;
    private String id;

    @Override
    public void onIceConnectionReceivingChange(boolean b) {

    }

    @Override
    public void onCreateSuccess(final SessionDescription sdp) {
        Log.d("myLogs","onCreateSuccess " + sdp.type.canonicalForm());
        try {
            JSONObject payload = new JSONObject();
            payload.put("type", sdp.type.canonicalForm());
            payload.put("sdp", sdp.description);
            sendMessage(id, sdp.type.canonicalForm(), payload);
            pc.setLocalDescription(Peer.this, sdp);
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onSetSuccess() {
        Log.d("myLogs","onSetSuccess");
        //pc.createAnswer(this,pcConstraints);
    }

    @Override
    public void onCreateFailure(String s) {
        Log.d("myLogs", "onCreateFailure " + s);
    }

    @Override
    public void onSetFailure(String s) {
        Log.d("myLogs", "onSetFailure " + s);
    }

    @Override
    public void onSignalingChange(PeerConnection.SignalingState signalingState) {
        Log.d("myLogs", "onSignalChange " + signalingState);
        if(signalingState == PeerConnection.SignalingState.CLOSED) {
            removePeer(id);
        }
    }

    @Override
    public void onIceConnectionChange(PeerConnection.IceConnectionState iceConnectionState) {
        Log.d("myLogs", "onIceConnectionChange " + iceConnectionState);
    }

    @Override
    public void onIceGatheringChange(PeerConnection.IceGatheringState iceGatheringState) {
        Log.d("myLogs","onIceGatheringChange " + iceGatheringState);
    }

    @Override
    public void onIceCandidate(final IceCandidate candidate) {
        Log.d("myLogs","onIceCandidate " + candidate.sdp);
        if(candidate.sdp.isEmpty()){
            Log.d("myLogs","candidate is empty");
        }
        try {
            JSONObject payload = new JSONObject();
            JSONObject candidateJson = new JSONObject();
            candidateJson.put("candidate", candidate.sdp);
            candidateJson.put("sdpMid", candidate.sdpMid);
            candidateJson.put("sdpMLineIndex", candidate.sdpMLineIndex);
            payload.put("candidate", candidateJson);
            sendMessage(id, "candidate", payload);
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onDataChannel(DataChannel dataChannel) {
        Log.d("myLogs","onDataChannel");
    }

    @Override
    public void onRenegotiationNeeded() {
        Log.d("myLogs","onRenegotiationNeeded");
    }

    @Override
    public void onAddStream(MediaStream mediaStream) {
        Log.d("myLogs", "onAddRemoteStream " + mediaStream.label());
        onAddRemoteStream(mediaStream);
    }

    @Override
    public void onRemoveStream(MediaStream mediaStream) {
        Log.d("myLogs", "onRemoveStream "+mediaStream.label());
        removePeer(id);
    }

    public Peer(String id) {
        Log.d("myLog    s", "initialize peer id");
        if(iceServers.size()>0)
            this.pc = factory.createPeerConnection(iceServers, pcConstraints, this);
        else{
            Log.d("myLogs","error to get turn and stun servers ");
        }
        this.id = id;
    }
}

public VideoCapturer getVideoCapturer() {
    Log.d("myLogs", "getVideoCapture");
    String cameraDeviceName;
    String frontCameraDeviceName = CameraEnumerationAndroid.getNameOfFrontFacingDevice();
    VideoCapturer videoCapturer;
    cameraDeviceName = frontCameraDeviceName;
    videoCapturer = VideoCapturerAndroid.create(cameraDeviceName);
    return videoCapturer;
}

public void addPeer(String id) {
    Log.d("myLogs","addPeer" + id);
    Peer peer = new Peer(id);
    peer.pc.addStream(lMS);
    peers.put(id, peer);
}

public void removePeer(String id) {
    Log.d("myLogs","removePeer" + id);
    Peer peer = peers.get(id);
    peer.pc.close();
    peer.pc.dispose();
    peers.remove(peer.id);
}

private void onLocalStream(MediaStream localStream){
    localStream.videoTracks.get(0).addRenderer(new VideoRenderer(localRender));
    VideoRendererGui.update(localRender,
            LOCAL_X_CONNECTED, LOCAL_Y_CONNECTED,
            LOCAL_WIDTH_CONNECTED, LOCAL_HEIGHT_CONNECTED,
            scalingType,true);
}

private void onAddRemoteStream(MediaStream remoteStream){
    remoteStream.videoTracks.get(0).addRenderer(new VideoRenderer(remoteRender));
    VideoRendererGui.update(remoteRender,
            REMOTE_X, REMOTE_Y,
            REMOTE_WIDTH, REMOTE_HEIGHT, scalingType,false);
    VideoRendererGui.update(localRender,
            LOCAL_X_CONNECTED, LOCAL_Y_CONNECTED,
            LOCAL_WIDTH_CONNECTED, LOCAL_HEIGHT_CONNECTED,
            scalingType,true);
}

Upvotes: 1

Related Questions