discover stun server
This commit is contained in:
parent
859bc0bef3
commit
ca9b95fc9c
|
@ -3,6 +3,7 @@ package eu.siacs.conversations.xml;
|
|||
public final class Namespace {
|
||||
public static final String DISCO_ITEMS = "http://jabber.org/protocol/disco#items";
|
||||
public static final String DISCO_INFO = "http://jabber.org/protocol/disco#info";
|
||||
public static final String EXTERNAL_SERVICE_DISCOVERY = "urn:xmpp:extdisco:2";
|
||||
public static final String BLOCKING = "urn:xmpp:blocking";
|
||||
public static final String ROSTER = "jabber:iq:roster";
|
||||
public static final String REGISTER = "jabber:iq:register";
|
||||
|
|
|
@ -1902,5 +1902,9 @@ public class XmppConnection implements Runnable {
|
|||
public boolean bookmarks2() {
|
||||
return Config.USE_BOOKMARKS2 /* || hasDiscoFeature(account.getJid().asBareJid(), Namespace.BOOKMARKS2_COMPAT)*/;
|
||||
}
|
||||
|
||||
public boolean extendedServiceDiscovery() {
|
||||
return hasDiscoFeature(Jid.of(account.getServer()),Namespace.EXTERNAL_SERVICE_DISCOVERY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,12 +16,15 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
|
||||
import eu.siacs.conversations.Config;
|
||||
import eu.siacs.conversations.entities.Account;
|
||||
import eu.siacs.conversations.xml.Element;
|
||||
import eu.siacs.conversations.xml.Namespace;
|
||||
import eu.siacs.conversations.xmpp.OnIqPacketReceived;
|
||||
import eu.siacs.conversations.xmpp.jingle.stanzas.Group;
|
||||
import eu.siacs.conversations.xmpp.jingle.stanzas.IceUdpTransportInfo;
|
||||
import eu.siacs.conversations.xmpp.jingle.stanzas.JinglePacket;
|
||||
import eu.siacs.conversations.xmpp.jingle.stanzas.Reason;
|
||||
import eu.siacs.conversations.xmpp.stanzas.IqPacket;
|
||||
import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
|
||||
import rocks.xmpp.addr.Jid;
|
||||
|
||||
|
@ -51,6 +54,21 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
|
|||
super(jingleConnectionManager, id, initiator);
|
||||
}
|
||||
|
||||
private static State reasonToState(Reason reason) {
|
||||
switch (reason) {
|
||||
case SUCCESS:
|
||||
return State.TERMINATED_SUCCESS;
|
||||
case DECLINE:
|
||||
case BUSY:
|
||||
return State.TERMINATED_DECLINED_OR_BUSY;
|
||||
case CANCEL:
|
||||
case TIMEOUT:
|
||||
return State.TERMINATED_CANCEL_OR_TIMEOUT;
|
||||
default:
|
||||
return State.TERMINATED_CONNECTIVITY_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void deliverPacket(final JinglePacket jinglePacket) {
|
||||
Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": packet delivered to JingleRtpConnection");
|
||||
|
@ -85,21 +103,6 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
|
|||
jingleConnectionManager.finishConnection(this);
|
||||
}
|
||||
|
||||
private static State reasonToState(Reason reason) {
|
||||
switch (reason) {
|
||||
case SUCCESS:
|
||||
return State.TERMINATED_SUCCESS;
|
||||
case DECLINE:
|
||||
case BUSY:
|
||||
return State.TERMINATED_DECLINED_OR_BUSY;
|
||||
case CANCEL:
|
||||
case TIMEOUT:
|
||||
return State.TERMINATED_CANCEL_OR_TIMEOUT;
|
||||
default:
|
||||
return State.TERMINATED_CONNECTIVITY_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
private void receiveTransportInfo(final JinglePacket jinglePacket) {
|
||||
if (isInState(State.SESSION_INITIALIZED, State.SESSION_INITIALIZED_PRE_APPROVED, State.SESSION_ACCEPTED)) {
|
||||
final RtpContentMap contentMap;
|
||||
|
@ -211,22 +214,24 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
|
|||
if (rtpContentMap == null) {
|
||||
throw new IllegalStateException("initiator RTP Content Map has not been set");
|
||||
}
|
||||
setupWebRTC();
|
||||
final org.webrtc.SessionDescription offer = new org.webrtc.SessionDescription(
|
||||
org.webrtc.SessionDescription.Type.OFFER,
|
||||
SessionDescription.of(rtpContentMap).toString()
|
||||
);
|
||||
try {
|
||||
this.webRTCWrapper.setRemoteDescription(offer).get();
|
||||
org.webrtc.SessionDescription webRTCSessionDescription = this.webRTCWrapper.createAnswer().get();
|
||||
final SessionDescription sessionDescription = SessionDescription.parse(webRTCSessionDescription.description);
|
||||
final RtpContentMap respondingRtpContentMap = RtpContentMap.of(sessionDescription);
|
||||
sendSessionAccept(respondingRtpContentMap);
|
||||
this.webRTCWrapper.setLocalDescription(webRTCSessionDescription);
|
||||
} catch (Exception e) {
|
||||
Log.d(Config.LOGTAG, "unable to send session accept", e);
|
||||
discoverIceServers(iceServers -> {
|
||||
setupWebRTC(iceServers);
|
||||
final org.webrtc.SessionDescription offer = new org.webrtc.SessionDescription(
|
||||
org.webrtc.SessionDescription.Type.OFFER,
|
||||
SessionDescription.of(rtpContentMap).toString()
|
||||
);
|
||||
try {
|
||||
this.webRTCWrapper.setRemoteDescription(offer).get();
|
||||
org.webrtc.SessionDescription webRTCSessionDescription = this.webRTCWrapper.createAnswer().get();
|
||||
final SessionDescription sessionDescription = SessionDescription.parse(webRTCSessionDescription.description);
|
||||
final RtpContentMap respondingRtpContentMap = RtpContentMap.of(sessionDescription);
|
||||
sendSessionAccept(respondingRtpContentMap);
|
||||
this.webRTCWrapper.setLocalDescription(webRTCSessionDescription);
|
||||
} catch (Exception e) {
|
||||
Log.d(Config.LOGTAG, "unable to send session accept", e);
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void sendSessionAccept(final RtpContentMap rtpContentMap) {
|
||||
|
@ -346,17 +351,19 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
|
|||
|
||||
private void sendSessionInitiate(final State targetState) {
|
||||
Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": prepare session-initiate");
|
||||
setupWebRTC();
|
||||
try {
|
||||
org.webrtc.SessionDescription webRTCSessionDescription = this.webRTCWrapper.createOffer().get();
|
||||
final SessionDescription sessionDescription = SessionDescription.parse(webRTCSessionDescription.description);
|
||||
Log.d(Config.LOGTAG, "description: " + webRTCSessionDescription.description);
|
||||
final RtpContentMap rtpContentMap = RtpContentMap.of(sessionDescription);
|
||||
sendSessionInitiate(rtpContentMap, targetState);
|
||||
this.webRTCWrapper.setLocalDescription(webRTCSessionDescription).get();
|
||||
} catch (Exception e) {
|
||||
Log.d(Config.LOGTAG, "unable to sendSessionInitiate", e);
|
||||
}
|
||||
discoverIceServers(iceServers -> {
|
||||
setupWebRTC(iceServers);
|
||||
try {
|
||||
org.webrtc.SessionDescription webRTCSessionDescription = this.webRTCWrapper.createOffer().get();
|
||||
final SessionDescription sessionDescription = SessionDescription.parse(webRTCSessionDescription.description);
|
||||
Log.d(Config.LOGTAG, "description: " + webRTCSessionDescription.description);
|
||||
final RtpContentMap rtpContentMap = RtpContentMap.of(sessionDescription);
|
||||
sendSessionInitiate(rtpContentMap, targetState);
|
||||
this.webRTCWrapper.setLocalDescription(webRTCSessionDescription).get();
|
||||
} catch (Exception e) {
|
||||
Log.d(Config.LOGTAG, "unable to sendSessionInitiate", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void sendSessionInitiate(RtpContentMap rtpContentMap, final State targetState) {
|
||||
|
@ -481,9 +488,9 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
|
|||
}
|
||||
}
|
||||
|
||||
private void setupWebRTC() {
|
||||
private void setupWebRTC(final List<PeerConnection.IceServer> iceServers) {
|
||||
this.webRTCWrapper.setup(this.xmppConnectionService);
|
||||
this.webRTCWrapper.initializePeerConnection();
|
||||
this.webRTCWrapper.initializePeerConnection(iceServers);
|
||||
}
|
||||
|
||||
private void acceptCallFromProposed() {
|
||||
|
@ -559,4 +566,51 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
|
|||
private void updateEndUserState() {
|
||||
xmppConnectionService.notifyJingleRtpConnectionUpdate(id.account, id.with, id.sessionId, getEndUserState());
|
||||
}
|
||||
|
||||
private void discoverIceServers(final OnIceServersDiscovered onIceServersDiscovered) {
|
||||
if (id.account.getXmppConnection().getFeatures().extendedServiceDiscovery()) {
|
||||
final IqPacket request = new IqPacket(IqPacket.TYPE.GET);
|
||||
request.setTo(Jid.of(id.account.getJid().getDomain()));
|
||||
request.addChild("services", Namespace.EXTERNAL_SERVICE_DISCOVERY);
|
||||
xmppConnectionService.sendIqPacket(id.account, request, (account, response) -> {
|
||||
ImmutableList.Builder<PeerConnection.IceServer> listBuilder = new ImmutableList.Builder<>();
|
||||
if (response.getType() == IqPacket.TYPE.RESULT) {
|
||||
final Element services = response.findChild("services", Namespace.EXTERNAL_SERVICE_DISCOVERY);
|
||||
final List<Element> children = services == null ? Collections.emptyList() : services.getChildren();
|
||||
for (final Element child : children) {
|
||||
if ("service".equals(child.getName())) {
|
||||
final String type = child.getAttribute("type");
|
||||
final String host = child.getAttribute("host");
|
||||
final String port = child.getAttribute("port");
|
||||
final String transport = child.getAttribute("transport");
|
||||
final String username = child.getAttribute("username");
|
||||
final String password = child.getAttribute("password");
|
||||
if (Arrays.asList("stun", "type").contains(type) && host != null && port != null && "udp".equals(transport)) {
|
||||
PeerConnection.IceServer.Builder iceServerBuilder = PeerConnection.IceServer.builder(String.format("%s:%s:%s", type, host, port));
|
||||
if (username != null && password != null) {
|
||||
iceServerBuilder.setUsername(username);
|
||||
iceServerBuilder.setPassword(password);
|
||||
}
|
||||
final PeerConnection.IceServer iceServer = iceServerBuilder.createIceServer();
|
||||
Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": discovered ICE Server: " + iceServer);
|
||||
listBuilder.add(iceServer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
List<PeerConnection.IceServer> iceServers = listBuilder.build();
|
||||
if (iceServers.size() == 0) {
|
||||
Log.w(Config.LOGTAG, id.account.getJid().asBareJid() + ": no ICE server found " + response);
|
||||
}
|
||||
onIceServersDiscovered.onIceServersDiscovered(iceServers);
|
||||
});
|
||||
} else {
|
||||
Log.w(Config.LOGTAG, id.account.getJid().asBareJid() + ": has no external service discovery");
|
||||
onIceServersDiscovered.onIceServersDiscovered(Collections.emptyList());
|
||||
}
|
||||
}
|
||||
|
||||
private interface OnIceServersDiscovered {
|
||||
void onIceServersDiscovered(List<PeerConnection.IceServer> iceServers);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -132,7 +132,7 @@ public class WebRTCWrapper {
|
|||
);
|
||||
}
|
||||
|
||||
public void initializePeerConnection() {
|
||||
public void initializePeerConnection(final List<PeerConnection.IceServer> iceServers) {
|
||||
PeerConnectionFactory peerConnectionFactory = PeerConnectionFactory.builder().createPeerConnectionFactory();
|
||||
|
||||
CameraVideoCapturer capturer = null;
|
||||
|
@ -193,10 +193,6 @@ public class WebRTCWrapper {
|
|||
|
||||
this.localVideoTrack = videoTrack;
|
||||
|
||||
|
||||
final List<PeerConnection.IceServer> iceServers = ImmutableList.of(
|
||||
PeerConnection.IceServer.builder("stun:xmpp.conversations.im:3478").createIceServer()
|
||||
);
|
||||
final PeerConnection peerConnection = peerConnectionFactory.createPeerConnection(iceServers, peerConnectionObserver);
|
||||
if (peerConnection == null) {
|
||||
throw new IllegalStateException("Unable to create PeerConnection");
|
||||
|
|
Loading…
Reference in New Issue