Search in sources :

Example 1 with IceCandidate

use of org.webrtc.IceCandidate in project Conversations by siacs.

the class JingleRtpConnection method processCandidate.

private void processCandidate(final Map.Entry<String, RtpContentMap.DescriptionTransport> content) {
    final RtpContentMap rtpContentMap = getRemoteContentMap();
    final List<String> indices = toIdentificationTags(rtpContentMap);
    // aka content name
    final String sdpMid = content.getKey();
    final IceUdpTransportInfo transport = content.getValue().transport;
    final IceUdpTransportInfo.Credentials credentials = transport.getCredentials();
    for (final IceUdpTransportInfo.Candidate candidate : transport.getCandidates()) {
        final String sdp;
        try {
            sdp = candidate.toSdpAttribute(credentials.ufrag);
        } catch (final IllegalArgumentException e) {
            Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": ignoring invalid ICE candidate " + e.getMessage());
            continue;
        }
        final int mLineIndex = indices.indexOf(sdpMid);
        if (mLineIndex < 0) {
            Log.w(Config.LOGTAG, "mLineIndex not found for " + sdpMid + ". available indices " + indices);
        }
        final IceCandidate iceCandidate = new IceCandidate(sdpMid, mLineIndex, sdp);
        Log.d(Config.LOGTAG, "received candidate: " + iceCandidate);
        this.webRTCWrapper.addIceCandidate(iceCandidate);
    }
}
Also used : IceUdpTransportInfo(eu.siacs.conversations.xmpp.jingle.stanzas.IceUdpTransportInfo) IceCandidate(org.webrtc.IceCandidate)

Example 2 with IceCandidate

use of org.webrtc.IceCandidate in project Signal-Android by signalapp.

the class WebRtcCallService method handleIncomingCall.

// Handlers
private void handleIncomingCall(final Intent intent) {
    Log.w(TAG, "handleIncomingCall()");
    if (callState != CallState.STATE_IDLE)
        throw new IllegalStateException("Incoming on non-idle");
    final String offer = intent.getStringExtra(EXTRA_REMOTE_DESCRIPTION);
    this.callState = CallState.STATE_ANSWERING;
    this.callId = intent.getLongExtra(EXTRA_CALL_ID, -1);
    this.pendingIncomingIceUpdates = new LinkedList<>();
    this.recipient = getRemoteRecipient(intent);
    if (isIncomingMessageExpired(intent)) {
        insertMissedCall(this.recipient, true);
        terminate();
        return;
    }
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        setCallInProgressNotification(TYPE_INCOMING_CONNECTING, this.recipient);
    }
    timeoutExecutor.schedule(new TimeoutRunnable(this.callId), 2, TimeUnit.MINUTES);
    initializeVideo();
    retrieveTurnServers().addListener(new SuccessOnlyListener<List<PeerConnection.IceServer>>(this.callState, this.callId) {

        @Override
        public void onSuccessContinue(List<PeerConnection.IceServer> result) {
            try {
                boolean isSystemContact = false;
                if (Permissions.hasAny(WebRtcCallService.this, Manifest.permission.READ_CONTACTS, Manifest.permission.WRITE_CONTACTS)) {
                    isSystemContact = ContactAccessor.getInstance().isSystemContact(WebRtcCallService.this, recipient.getAddress().serialize());
                }
                boolean isAlwaysTurn = TextSecurePreferences.isTurnOnly(WebRtcCallService.this);
                WebRtcCallService.this.peerConnection = new PeerConnectionWrapper(WebRtcCallService.this, peerConnectionFactory, WebRtcCallService.this, localRenderer, result, !isSystemContact || isAlwaysTurn);
                WebRtcCallService.this.peerConnection.setRemoteDescription(new SessionDescription(SessionDescription.Type.OFFER, offer));
                WebRtcCallService.this.lockManager.updatePhoneState(LockManager.PhoneState.PROCESSING);
                SessionDescription sdp = WebRtcCallService.this.peerConnection.createAnswer(new MediaConstraints());
                Log.w(TAG, "Answer SDP: " + sdp.description);
                WebRtcCallService.this.peerConnection.setLocalDescription(sdp);
                ListenableFutureTask<Boolean> listenableFutureTask = sendMessage(recipient, SignalServiceCallMessage.forAnswer(new AnswerMessage(WebRtcCallService.this.callId, sdp.description)));
                for (IceCandidate candidate : pendingIncomingIceUpdates) WebRtcCallService.this.peerConnection.addIceCandidate(candidate);
                WebRtcCallService.this.pendingIncomingIceUpdates = null;
                listenableFutureTask.addListener(new FailureListener<Boolean>(WebRtcCallService.this.callState, WebRtcCallService.this.callId) {

                    @Override
                    public void onFailureContinue(Throwable error) {
                        Log.w(TAG, error);
                        insertMissedCall(recipient, true);
                        terminate();
                    }
                });
            } catch (PeerConnectionException e) {
                Log.w(TAG, e);
                terminate();
            }
        }
    });
}
Also used : SessionDescription(org.webrtc.SessionDescription) PeerConnection(org.webrtc.PeerConnection) AnswerMessage(org.whispersystems.signalservice.api.messages.calls.AnswerMessage) IceCandidate(org.webrtc.IceCandidate) PeerConnectionWrapper(org.thoughtcrime.securesms.webrtc.PeerConnectionWrapper) MediaConstraints(org.webrtc.MediaConstraints) ListenableFutureTask(org.thoughtcrime.securesms.util.ListenableFutureTask) PeerConnectionException(org.thoughtcrime.securesms.webrtc.PeerConnectionWrapper.PeerConnectionException) List(java.util.List) LinkedList(java.util.LinkedList)

Example 3 with IceCandidate

use of org.webrtc.IceCandidate in project matrix-android-sdk by matrix-org.

the class MXWebRtcCall method createLocalStream.

/**
 * create the local stream
 */
private void createLocalStream() {
    Log.d(LOG_TAG, "## createLocalStream(): IN");
    // check there is at least one stream to start a call
    if ((null == mLocalVideoTrack) && (null == mLocalAudioTrack)) {
        Log.d(LOG_TAG, "## createLocalStream(): CALL_ERROR_CALL_INIT_FAILED");
        dispatchOnCallError(CALL_ERROR_CALL_INIT_FAILED);
        hangup("no_stream");
        terminate(IMXCall.END_CALL_REASON_UNDEFINED);
        return;
    }
    // create our local stream to add our audio and video tracks
    mLocalMediaStream = mPeerConnectionFactory.createLocalMediaStream("ARDAMS");
    // add video track to local stream
    if (null != mLocalVideoTrack) {
        mLocalMediaStream.addTrack(mLocalVideoTrack);
    }
    // add audio track to local stream
    if (null != mLocalAudioTrack) {
        mLocalMediaStream.addTrack(mLocalAudioTrack);
    }
    if (null != mFullScreenRTCView) {
        mFullScreenRTCView.setStream(mLocalMediaStream);
        mFullScreenRTCView.setVisibility(View.VISIBLE);
    }
    // build ICE servers list
    ArrayList<PeerConnection.IceServer> iceServers = new ArrayList<>();
    if (null != mTurnServer) {
        try {
            String username = null;
            String password = null;
            JsonObject object = mTurnServer.getAsJsonObject();
            if (object.has("username")) {
                username = object.get("username").getAsString();
            }
            if (object.has("password")) {
                password = object.get("password").getAsString();
            }
            JsonArray uris = object.get("uris").getAsJsonArray();
            for (int index = 0; index < uris.size(); index++) {
                String url = uris.get(index).getAsString();
                if ((null != username) && (null != password)) {
                    iceServers.add(new PeerConnection.IceServer(url, username, password));
                } else {
                    iceServers.add(new PeerConnection.IceServer(url));
                }
            }
        } catch (Exception e) {
            Log.e(LOG_TAG, "## createLocalStream(): Exception in ICE servers list Msg=" + e.getMessage());
        }
    }
    Log.d(LOG_TAG, "## createLocalStream(): " + iceServers.size() + " known ice servers");
    // define at least on server
    if (iceServers.isEmpty()) {
        Log.d(LOG_TAG, "## createLocalStream(): use the default google server");
        iceServers.add(new PeerConnection.IceServer("stun:stun.l.google.com:19302"));
    }
    // define constraints
    MediaConstraints pcConstraints = new MediaConstraints();
    pcConstraints.optional.add(new MediaConstraints.KeyValuePair("RtpDataChannels", "true"));
    // start connecting to the other peer by creating the peer connection
    mPeerConnection = mPeerConnectionFactory.createPeerConnection(iceServers, pcConstraints, new PeerConnection.Observer() {

        @Override
        public void onSignalingChange(PeerConnection.SignalingState signalingState) {
            Log.d(LOG_TAG, "## mPeerConnection creation: onSignalingChange state=" + signalingState);
        }

        @Override
        public void onIceConnectionChange(final PeerConnection.IceConnectionState iceConnectionState) {
            Log.d(LOG_TAG, "## mPeerConnection creation: onIceConnectionChange " + iceConnectionState);
            mUIThreadHandler.post(new Runnable() {

                @Override
                public void run() {
                    if (iceConnectionState == PeerConnection.IceConnectionState.CONNECTED) {
                        if ((null != mLocalVideoTrack) && mUsingLargeLocalRenderer && isVideo()) {
                            mLocalVideoTrack.setEnabled(false);
                            // the local attendee video is sent by the server among the others conference attendees.
                            if (!isConference()) {
                                // add local preview, only for 1:1 call
                                // mLocalVideoTrack.addRenderer(mSmallLocalRenderer);
                                mPipRTCView.setStream(mLocalMediaStream);
                                mPipRTCView.setVisibility(View.VISIBLE);
                                // to be able to display the avatar video above the large one
                                mPipRTCView.setZOrder(1);
                            }
                            mLocalVideoTrack.setEnabled(true);
                            mUsingLargeLocalRenderer = false;
                            mCallView.post(new Runnable() {

                                @Override
                                public void run() {
                                    if (null != mCallView) {
                                        mCallView.invalidate();
                                    }
                                }
                            });
                        }
                        dispatchOnStateDidChange(IMXCall.CALL_STATE_CONNECTED);
                    } else /*else if (iceConnectionState == PeerConnection.IceConnectionState.DISCONNECTED) {
                                    // TODO warn the user ?
                                    hangup(null);
                                } else if (iceConnectionState == PeerConnection.IceConnectionState.CLOSED) {
                                    // TODO warn the user ?
                                    terminate();
                                }*/
                    if (iceConnectionState == PeerConnection.IceConnectionState.FAILED) {
                        dispatchOnCallError(CALL_ERROR_ICE_FAILED);
                        hangup("ice_failed");
                    }
                }
            });
        }

        @Override
        public void onIceConnectionReceivingChange(boolean var1) {
            Log.d(LOG_TAG, "## mPeerConnection creation: onIceConnectionReceivingChange " + var1);
        }

        @Override
        public void onIceCandidatesRemoved(IceCandidate[] var1) {
            Log.d(LOG_TAG, "## mPeerConnection creation: onIceCandidatesRemoved " + var1);
        }

        @Override
        public void onIceGatheringChange(PeerConnection.IceGatheringState iceGatheringState) {
            Log.d(LOG_TAG, "## mPeerConnection creation: onIceGatheringChange " + iceGatheringState);
        }

        @Override
        public void onAddTrack(RtpReceiver var1, MediaStream[] var2) {
            Log.d(LOG_TAG, "## mPeerConnection creation: onAddTrack " + var1 + " -- " + var2);
        }

        @Override
        public void onIceCandidate(final IceCandidate iceCandidate) {
            Log.d(LOG_TAG, "## mPeerConnection creation: onIceCandidate " + iceCandidate);
            mUIThreadHandler.post(new Runnable() {

                @Override
                public void run() {
                    if (!isCallEnded()) {
                        JsonObject content = new JsonObject();
                        content.addProperty("version", 0);
                        content.addProperty("call_id", mCallId);
                        JsonArray candidates = new JsonArray();
                        JsonObject cand = new JsonObject();
                        cand.addProperty("sdpMLineIndex", iceCandidate.sdpMLineIndex);
                        cand.addProperty("sdpMid", iceCandidate.sdpMid);
                        cand.addProperty("candidate", iceCandidate.sdp);
                        candidates.add(cand);
                        content.add("candidates", candidates);
                        boolean addIt = true;
                        // merge candidates
                        if (mPendingEvents.size() > 0) {
                            try {
                                Event lastEvent = mPendingEvents.get(mPendingEvents.size() - 1);
                                if (TextUtils.equals(lastEvent.getType(), Event.EVENT_TYPE_CALL_CANDIDATES)) {
                                    // return the content cast as a JsonObject
                                    // it is not a copy
                                    JsonObject lastContent = lastEvent.getContentAsJsonObject();
                                    JsonArray lastContentCandidates = lastContent.get("candidates").getAsJsonArray();
                                    JsonArray newContentCandidates = content.get("candidates").getAsJsonArray();
                                    Log.d(LOG_TAG, "Merge candidates from " + lastContentCandidates.size() + " to " + (lastContentCandidates.size() + newContentCandidates.size() + " items."));
                                    lastContentCandidates.addAll(newContentCandidates);
                                    // replace the candidates list
                                    lastContent.remove("candidates");
                                    lastContent.add("candidates", lastContentCandidates);
                                    // don't need to save anything, lastContent is a reference not a copy
                                    addIt = false;
                                }
                            } catch (Exception e) {
                                Log.e(LOG_TAG, "## createLocalStream(): createPeerConnection - onIceCandidate() Exception Msg=" + e.getMessage());
                            }
                        }
                        if (addIt) {
                            Event event = new Event(Event.EVENT_TYPE_CALL_CANDIDATES, content, mSession.getCredentials().userId, mCallSignalingRoom.getRoomId());
                            mPendingEvents.add(event);
                            sendNextEvent();
                        }
                    }
                }
            });
        }

        @Override
        public void onAddStream(final MediaStream mediaStream) {
            Log.d(LOG_TAG, "## mPeerConnection creation: onAddStream " + mediaStream);
            mUIThreadHandler.post(new Runnable() {

                @Override
                public void run() {
                    if ((mediaStream.videoTracks.size() == 1) && !isCallEnded()) {
                        mRemoteVideoTrack = mediaStream.videoTracks.get(0);
                        mRemoteVideoTrack.setEnabled(true);
                        mFullScreenRTCView.setStream(mediaStream);
                        mFullScreenRTCView.setVisibility(View.VISIBLE);
                    }
                }
            });
        }

        @Override
        public void onRemoveStream(final MediaStream mediaStream) {
            Log.d(LOG_TAG, "## mPeerConnection creation: onRemoveStream " + mediaStream);
            mUIThreadHandler.post(new Runnable() {

                @Override
                public void run() {
                    if (null != mRemoteVideoTrack) {
                        mRemoteVideoTrack.dispose();
                        mRemoteVideoTrack = null;
                        mediaStream.videoTracks.get(0).dispose();
                    }
                }
            });
        }

        @Override
        public void onDataChannel(DataChannel dataChannel) {
            Log.d(LOG_TAG, "## mPeerConnection creation: onDataChannel " + dataChannel);
        }

        @Override
        public void onRenegotiationNeeded() {
            Log.d(LOG_TAG, "## mPeerConnection creation: onRenegotiationNeeded");
        }
    });
    if (null == mPeerConnection) {
        dispatchOnCallError(CALL_ERROR_ICE_FAILED);
        hangup("cannot create peer connection");
        return;
    }
    // send our local video and audio stream to make it seen by the other part
    mPeerConnection.addStream(mLocalMediaStream);
    MediaConstraints constraints = new MediaConstraints();
    constraints.mandatory.add(new MediaConstraints.KeyValuePair("OfferToReceiveAudio", "true"));
    constraints.mandatory.add(new MediaConstraints.KeyValuePair("OfferToReceiveVideo", isVideo() ? "true" : "false"));
    // call createOffer only for outgoing calls
    if (!isIncoming()) {
        Log.d(LOG_TAG, "## createLocalStream(): !isIncoming() -> createOffer");
        mPeerConnection.createOffer(new SdpObserver() {

            @Override
            public void onCreateSuccess(SessionDescription sessionDescription) {
                Log.d(LOG_TAG, "createOffer onCreateSuccess");
                final SessionDescription sdp = new SessionDescription(sessionDescription.type, sessionDescription.description);
                mUIThreadHandler.post(new Runnable() {

                    @Override
                    public void run() {
                        if (mPeerConnection != null) {
                            // must be done to before sending the invitation message
                            mPeerConnection.setLocalDescription(new SdpObserver() {

                                @Override
                                public void onCreateSuccess(SessionDescription sessionDescription) {
                                    Log.d(LOG_TAG, "setLocalDescription onCreateSuccess");
                                }

                                @Override
                                public void onSetSuccess() {
                                    Log.d(LOG_TAG, "setLocalDescription onSetSuccess");
                                    sendInvite(sdp);
                                    dispatchOnStateDidChange(IMXCall.CALL_STATE_INVITE_SENT);
                                }

                                @Override
                                public void onCreateFailure(String s) {
                                    Log.e(LOG_TAG, "setLocalDescription onCreateFailure " + s);
                                    dispatchOnCallError(CALL_ERROR_CAMERA_INIT_FAILED);
                                    hangup(null);
                                }

                                @Override
                                public void onSetFailure(String s) {
                                    Log.e(LOG_TAG, "setLocalDescription onSetFailure " + s);
                                    dispatchOnCallError(CALL_ERROR_CAMERA_INIT_FAILED);
                                    hangup(null);
                                }
                            }, sdp);
                        }
                    }
                });
            }

            @Override
            public void onSetSuccess() {
                Log.d(LOG_TAG, "createOffer onSetSuccess");
            }

            @Override
            public void onCreateFailure(String s) {
                Log.d(LOG_TAG, "createOffer onCreateFailure " + s);
                dispatchOnCallError(CALL_ERROR_CAMERA_INIT_FAILED);
            }

            @Override
            public void onSetFailure(String s) {
                Log.d(LOG_TAG, "createOffer onSetFailure " + s);
                dispatchOnCallError(CALL_ERROR_CAMERA_INIT_FAILED);
            }
        }, constraints);
        dispatchOnStateDidChange(IMXCall.CALL_STATE_WAIT_CREATE_OFFER);
    }
}
Also used : RtpReceiver(org.webrtc.RtpReceiver) SessionDescription(org.webrtc.SessionDescription) PeerConnection(org.webrtc.PeerConnection) ArrayList(java.util.ArrayList) JsonObject(com.google.gson.JsonObject) IceCandidate(org.webrtc.IceCandidate) MediaConstraints(org.webrtc.MediaConstraints) SdpObserver(org.webrtc.SdpObserver) SuppressLint(android.annotation.SuppressLint) JsonArray(com.google.gson.JsonArray) DataChannel(org.webrtc.DataChannel) MediaStream(org.webrtc.MediaStream) Event(org.matrix.androidsdk.rest.model.Event) SdpObserver(org.webrtc.SdpObserver)

Example 4 with IceCandidate

use of org.webrtc.IceCandidate in project matrix-android-sdk by matrix-org.

the class MXWebRtcCall method onNewCandidates.

/**
 * A new Ice candidate is received
 *
 * @param candidates the channel candidates
 */
private void onNewCandidates(final JsonArray candidates) {
    Log.d(LOG_TAG, "## onNewCandidates(): call state " + getCallState() + " with candidates " + candidates);
    if (!CALL_STATE_CREATED.equals(getCallState()) && (null != mPeerConnection)) {
        ArrayList<IceCandidate> candidatesList = new ArrayList<>();
        // convert the JSON to IceCandidate
        for (int index = 0; index < candidates.size(); index++) {
            JsonObject item = candidates.get(index).getAsJsonObject();
            try {
                String candidate = item.get("candidate").getAsString();
                String sdpMid = item.get("sdpMid").getAsString();
                int sdpLineIndex = item.get("sdpMLineIndex").getAsInt();
                candidatesList.add(new IceCandidate(sdpMid, sdpLineIndex, candidate));
            } catch (Exception e) {
                Log.e(LOG_TAG, "## onNewCandidates(): Exception Msg=" + e.getMessage());
            }
        }
        for (IceCandidate cand : candidatesList) {
            Log.d(LOG_TAG, "## onNewCandidates(): addIceCandidate " + cand);
            mPeerConnection.addIceCandidate(cand);
        }
    }
}
Also used : ArrayList(java.util.ArrayList) JsonObject(com.google.gson.JsonObject) IceCandidate(org.webrtc.IceCandidate) SuppressLint(android.annotation.SuppressLint)

Aggregations

IceCandidate (org.webrtc.IceCandidate)4 SuppressLint (android.annotation.SuppressLint)2 JsonObject (com.google.gson.JsonObject)2 ArrayList (java.util.ArrayList)2 MediaConstraints (org.webrtc.MediaConstraints)2 PeerConnection (org.webrtc.PeerConnection)2 SessionDescription (org.webrtc.SessionDescription)2 JsonArray (com.google.gson.JsonArray)1 IceUdpTransportInfo (eu.siacs.conversations.xmpp.jingle.stanzas.IceUdpTransportInfo)1 LinkedList (java.util.LinkedList)1 List (java.util.List)1 Event (org.matrix.androidsdk.rest.model.Event)1 ListenableFutureTask (org.thoughtcrime.securesms.util.ListenableFutureTask)1 PeerConnectionWrapper (org.thoughtcrime.securesms.webrtc.PeerConnectionWrapper)1 PeerConnectionException (org.thoughtcrime.securesms.webrtc.PeerConnectionWrapper.PeerConnectionException)1 DataChannel (org.webrtc.DataChannel)1 MediaStream (org.webrtc.MediaStream)1 RtpReceiver (org.webrtc.RtpReceiver)1 SdpObserver (org.webrtc.SdpObserver)1 AnswerMessage (org.whispersystems.signalservice.api.messages.calls.AnswerMessage)1