Signed-off-by: Mario Danic <mario@lovelyhq.com>
This commit is contained in:
Mario Danic 2017-11-14 11:12:31 +01:00
parent 846defc52c
commit de538437d1
5 changed files with 128 additions and 39 deletions

View File

@ -48,7 +48,7 @@ import com.nextcloud.talk.api.models.json.signaling.NCSignalingMessage;
import com.nextcloud.talk.api.models.json.signaling.Signaling; import com.nextcloud.talk.api.models.json.signaling.Signaling;
import com.nextcloud.talk.api.models.json.signaling.SignalingOverall; import com.nextcloud.talk.api.models.json.signaling.SignalingOverall;
import com.nextcloud.talk.application.NextcloudTalkApplication; import com.nextcloud.talk.application.NextcloudTalkApplication;
import com.nextcloud.talk.events.SessionDescriptionSend; import com.nextcloud.talk.events.SessionDescriptionSendEvent;
import com.nextcloud.talk.persistence.entities.UserEntity; import com.nextcloud.talk.persistence.entities.UserEntity;
import com.nextcloud.talk.webrtc.MagicPeerConnectionObserver; import com.nextcloud.talk.webrtc.MagicPeerConnectionObserver;
import com.nextcloud.talk.webrtc.MagicSdpObserver; import com.nextcloud.talk.webrtc.MagicSdpObserver;
@ -423,21 +423,24 @@ public class CallActivity extends AppCompatActivity {
PeerConnectionWrapper peerConnectionWrapper = alwaysGetPeerConnectionWrapperForSessionId PeerConnectionWrapper peerConnectionWrapper = alwaysGetPeerConnectionWrapperForSessionId
(ncSignalingMessage.getFrom(), ncSignalingMessage.getFrom().equals(callSession)); (ncSignalingMessage.getFrom(), ncSignalingMessage.getFrom().equals(callSession));
Log.d("MARIO_RECEIVING", ncSignalingMessage.getType());
switch (ncSignalingMessage.getType()) { switch (ncSignalingMessage.getType()) {
case "offer": case "offer":
case "answer": case "answer":
peerConnectionWrapper.setNick(ncSignalingMessage.getPayload().getNick()); peerConnectionWrapper.setNick(ncSignalingMessage.getPayload().getNick());
peerConnectionWrapper.getPeerConnection().setLocalDescription(new MagicSdpObserver(), peerConnectionWrapper.getPeerConnection().setRemoteDescription(new MagicSdpObserver(),
new SessionDescription(SessionDescription.Type.valueOf(ncSignalingMessage.getType() new SessionDescription(SessionDescription.Type.fromCanonicalForm(ncSignalingMessage.getType()),
.toUpperCase()),
ncSignalingMessage ncSignalingMessage
.getPayload().getSdp())); .getPayload().getSdp()));
if (ncSignalingMessage.getType().equals("offer")) {
peerConnectionWrapper.sendMessage(true);
}
break; break;
case "candidate": case "candidate":
NCIceCandidate ncIceCandidate = ncSignalingMessage.getPayload().getIceCandidate(); NCIceCandidate ncIceCandidate = ncSignalingMessage.getPayload().getIceCandidate();
IceCandidate iceCandidate = new IceCandidate(ncIceCandidate.getSdpMid(), IceCandidate iceCandidate = new IceCandidate(ncIceCandidate.getSdpMid(),
ncIceCandidate.getSdpMLineIndex(), ncIceCandidate.getCandidate()); ncIceCandidate.getSdpMLineIndex(), ncIceCandidate.getCandidate());
peerConnectionWrapper.getPeerConnection().addIceCandidate(iceCandidate); peerConnectionWrapper.addCandidate(iceCandidate);
break; break;
default: default:
break; break;
@ -480,10 +483,10 @@ public class CallActivity extends AppCompatActivity {
for (String sessionId : newSessions) { for (String sessionId : newSessions) {
if (getPeerConnectionWrapperForSessionId(sessionId) == null) { if (getPeerConnectionWrapperForSessionId(sessionId) == null) {
if (sessionId.compareTo(callSession) > 0) { if (sessionId.compareTo(callSession) < 0) {
PeerConnectionWrapper connectionWrapper = alwaysGetPeerConnectionWrapperForSessionId(sessionId, PeerConnectionWrapper connectionWrapper = alwaysGetPeerConnectionWrapperForSessionId(sessionId,
false); false);
connectionWrapper.sendOffer(); connectionWrapper.sendMessage(false);
} else { } else {
Log.d(TAG, "Waiting for offer"); Log.d(TAG, "Waiting for offer");
} }
@ -537,7 +540,7 @@ public class CallActivity extends AppCompatActivity {
} }
peerConnectionWrapper = new PeerConnectionWrapper(peerConnectionFactory, peerConnectionWrapper = new PeerConnectionWrapper(peerConnectionFactory,
iceServers, sdpConstraints, magicPeerConnectionObserver, sessionId, isLocalPeer); iceServers, sdpConstraints, magicPeerConnectionObserver, sessionId, isLocalPeer, callSession);
peerConnectionWrapperList.add(peerConnectionWrapper); peerConnectionWrapperList.add(peerConnectionWrapper);
return peerConnectionWrapper; return peerConnectionWrapper;
} }
@ -666,7 +669,8 @@ public class CallActivity extends AppCompatActivity {
} }
@Subscribe(threadMode = ThreadMode.BACKGROUND) @Subscribe(threadMode = ThreadMode.BACKGROUND)
public void onMessageEvent(SessionDescriptionSend sessionDescriptionSend) { public void onMessageEvent(SessionDescriptionSendEvent sessionDescriptionSend) {
Log.d("MARIO SENDING", sessionDescriptionSend.getType());
String credentials = ApiHelper.getCredentials(userEntity.getUsername(), userEntity.getToken()); String credentials = ApiHelper.getCredentials(userEntity.getUsername(), userEntity.getToken());
NCMessageWrapper ncMessageWrapper = new NCMessageWrapper(); NCMessageWrapper ncMessageWrapper = new NCMessageWrapper();
ncMessageWrapper.setEv("message"); ncMessageWrapper.setEv("message");

View File

@ -0,0 +1,34 @@
/*
* Nextcloud Talk application
*
* @author Mario Danic
* Copyright (C) 2017 Mario Danic <mario@lovelyhq.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.nextcloud.talk.events;
import org.webrtc.MediaStream;
import lombok.Data;
@Data
public class MediaStreamEvent {
private final MediaStream mediaStream;
public MediaStreamEvent(MediaStream mediaStream) {
this.mediaStream = mediaStream;
}
}

View File

@ -29,14 +29,14 @@ import org.webrtc.SessionDescription;
import lombok.Data; import lombok.Data;
@Data @Data
public class SessionDescriptionSend { public class SessionDescriptionSendEvent {
@Nullable private final SessionDescription sessionDescription; @Nullable private final SessionDescription sessionDescription;
private final String peerId; private final String peerId;
private final String type; private final String type;
@Nullable private final NCIceCandidate ncIceCandidate; @Nullable private final NCIceCandidate ncIceCandidate;
public SessionDescriptionSend(@Nullable SessionDescription sessionDescription, String peerId, String type, public SessionDescriptionSendEvent(@Nullable SessionDescription sessionDescription, String peerId, String type,
@Nullable NCIceCandidate ncIceCandidate) { @Nullable NCIceCandidate ncIceCandidate) {
this.sessionDescription = sessionDescription; this.sessionDescription = sessionDescription;
this.peerId = peerId; this.peerId = peerId;
this.type = type; this.type = type;

View File

@ -20,6 +20,8 @@
package com.nextcloud.talk.webrtc; package com.nextcloud.talk.webrtc;
import android.util.Log;
import org.webrtc.DataChannel; import org.webrtc.DataChannel;
import org.webrtc.IceCandidate; import org.webrtc.IceCandidate;
import org.webrtc.MediaStream; import org.webrtc.MediaStream;
@ -33,7 +35,7 @@ public class MagicPeerConnectionObserver implements PeerConnection.Observer {
@Override @Override
public void onSignalingChange(PeerConnection.SignalingState signalingState) { public void onSignalingChange(PeerConnection.SignalingState signalingState) {
Log.d("MARIO", signalingState.name());
} }
@Override @Override
@ -54,6 +56,7 @@ public class MagicPeerConnectionObserver implements PeerConnection.Observer {
@Override @Override
public void onIceCandidate(IceCandidate iceCandidate) { public void onIceCandidate(IceCandidate iceCandidate) {
} }
@Override @Override

View File

@ -20,9 +20,10 @@
package com.nextcloud.talk.webrtc; package com.nextcloud.talk.webrtc;
import android.util.Log;
import com.nextcloud.talk.api.models.json.signaling.DataChannelMessage; import com.nextcloud.talk.api.models.json.signaling.DataChannelMessage;
import com.nextcloud.talk.api.models.json.signaling.NCIceCandidate; import com.nextcloud.talk.events.SessionDescriptionSendEvent;
import com.nextcloud.talk.events.SessionDescriptionSend;
import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.EventBus;
import org.webrtc.DataChannel; import org.webrtc.DataChannel;
@ -33,61 +34,102 @@ import org.webrtc.PeerConnectionFactory;
import org.webrtc.SessionDescription; import org.webrtc.SessionDescription;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List; import java.util.List;
public class PeerConnectionWrapper { public class PeerConnectionWrapper {
private static PeerConnection peerConnection; private static PeerConnection peerConnection;
private String sessionId; private String sessionId;
private String callToken;
private String nick; private String nick;
private boolean local; private boolean local;
private MediaConstraints mediaConstraints; private MediaConstraints mediaConstraints;
private DataChannel dataChannel; private DataChannel dataChannel;
private MagicSdpObserver magicSdpObserver;
List<IceCandidate> iceCandidates = new ArrayList<>();
public PeerConnectionWrapper(PeerConnectionFactory peerConnectionFactory, public PeerConnectionWrapper(PeerConnectionFactory peerConnectionFactory,
List<PeerConnection.IceServer> iceServerList, List<PeerConnection.IceServer> iceServerList,
MediaConstraints mediaConstraints, MediaConstraints mediaConstraints,
MagicPeerConnectionObserver magicPeerConnectionObserver, MagicPeerConnectionObserver magicPeerConnectionObserver,
String sessionId, boolean isLocalPeer) { String sessionId, boolean isLocalPeer, String callToken) {
peerConnection = peerConnectionFactory.createPeerConnection(iceServerList, mediaConstraints, peerConnection = peerConnectionFactory.createPeerConnection(iceServerList, mediaConstraints,
magicPeerConnectionObserver); magicPeerConnectionObserver);
this.sessionId = sessionId; this.sessionId = sessionId;
this.local = isLocalPeer; this.local = isLocalPeer;
this.mediaConstraints = mediaConstraints; this.mediaConstraints = mediaConstraints;
this.callToken = callToken;
boolean isInitiator = this.sessionId.compareTo(callToken) < 0;
magicSdpObserver = new MagicSdpObserver() {
public void onCreateSuccess(SessionDescription sessionDescription) {
super.onCreateSuccess(sessionDescription);
peerConnection.setLocalDescription(magicSdpObserver, sessionDescription);
}
@Override
public void onSetSuccess() {
if (isInitiator) {
// For offering peer connection we first create offer and set
// local SDP, then after receiving answer set remote SDP.
if (peerConnection.getRemoteDescription() == null) {
// We've just set our local SDP so time to send it.
EventBus.getDefault().post(new SessionDescriptionSendEvent(peerConnection.getLocalDescription(), sessionId,
"offer", null));
} else {
// We've just set remote description, so drain remote
// and send local ICE candidates.
drainIceCandidates();
}
} else {
// For answering peer connection we set remote SDP and then
// create answer and set local SDP.
if (peerConnection.getLocalDescription() != null) {
// We've just set our local SDP so time to send it, drain
// remote and send local ICE candidates.
EventBus.getDefault().post(new SessionDescriptionSendEvent(peerConnection.getLocalDescription(), sessionId,
"answer", null));
drainIceCandidates();
} else {
// We've just set remote SDP - do nothing for now -
// answer will be created soon.
}
}
}
};
}
private void drainIceCandidates() {
for (IceCandidate iceCandidate : iceCandidates) {
peerConnection.addIceCandidate(iceCandidate);
}
iceCandidates = new ArrayList<>();
} }
public void addCandidate(IceCandidate iceCandidate) { public void addCandidate(IceCandidate iceCandidate) {
if (peerConnection.getRemoteDescription() != null) { if (peerConnection.getRemoteDescription() != null) {
// queue // queue
} else {
peerConnection.addIceCandidate(iceCandidate); peerConnection.addIceCandidate(iceCandidate);
} else {
iceCandidates.add(iceCandidate);
} }
peerConnection.addIceCandidate(iceCandidate);
NCIceCandidate ncIceCandidate = new NCIceCandidate();
ncIceCandidate.setType("candidate");
ncIceCandidate.setSdpMid(iceCandidate.sdpMid);
ncIceCandidate.setSdpMLineIndex(iceCandidate.sdpMLineIndex);
ncIceCandidate.setCandidate(iceCandidate.sdp);
EventBus.getDefault().post(new SessionDescriptionSend(null, sessionId, "candidate",
ncIceCandidate));
} }
public void sendAnswer() { public void sendMessage(boolean isAnswer) {
MagicSdpObserver magicSdpObserver = new MagicSdpObserver() { Log.d("MARIO", "PREPARING " + isAnswer);
public void onCreateSuccess(SessionDescription sessionDescription) { if (!isAnswer) {
super.onCreateSuccess(sessionDescription); peerConnection.createOffer(magicSdpObserver, mediaConstraints);
peerConnection.setLocalDescription(new MagicSdpObserver(), sessionDescription); } else {
EventBus.getDefault().post(new SessionDescriptionSend(sessionDescription, sessionId, "answer", peerConnection.createAnswer(magicSdpObserver, mediaConstraints);
null)); }
}
};
peerConnection.createAnswer(magicSdpObserver, mediaConstraints);
} }
private void sendChannelData(DataChannelMessage dataChannelMessage) { private void sendChannelData(DataChannelMessage dataChannelMessage) {
ByteBuffer buffer = ByteBuffer.wrap(dataChannelMessage.toString().getBytes()); ByteBuffer buffer = ByteBuffer.wrap(dataChannelMessage.toString().getBytes());
dataChannel.send(new DataChannel.Buffer(buffer, false)); dataChannel.send(new DataChannel.Buffer(buffer, false));
} }
@ -128,8 +170,14 @@ public class PeerConnectionWrapper {
public void onCreateSuccess(SessionDescription sessionDescription) { public void onCreateSuccess(SessionDescription sessionDescription) {
super.onCreateSuccess(sessionDescription); super.onCreateSuccess(sessionDescription);
peerConnection.setLocalDescription(new MagicSdpObserver(), sessionDescription); peerConnection.setLocalDescription(new MagicSdpObserver(), sessionDescription);
EventBus.getDefault().post(new SessionDescriptionSend(sessionDescription, sessionId, "offer", null));
} }
@Override
public void onSetSuccess() {
EventBus.getDefault().post(new SessionDescriptionSendEvent(peerConnection.getLocalDescription(), sessionId,
"offer", null));
}
}; };
peerConnection.createOffer(magicSdpObserver, mediaConstraints); peerConnection.createOffer(magicSdpObserver, mediaConstraints);