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);
}
}
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();
}
}
});
}
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);
}
}
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);
}
}
}
Aggregations