proper iq tracing (handling of errors); responding to all iqs
This commit is contained in:
parent
15a2491d7b
commit
268eedad89
|
@ -169,6 +169,9 @@ public class RtpSessionActivity extends XmppActivity implements XmppConnectionSe
|
|||
case CONNECTIVITY_ERROR:
|
||||
binding.status.setText(R.string.rtp_state_connectivity_error);
|
||||
break;
|
||||
case APPLICATION_ERROR:
|
||||
binding.status.setText(R.string.rtp_state_application_failure);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -191,7 +194,7 @@ public class RtpSessionActivity extends XmppActivity implements XmppConnectionSe
|
|||
this.binding.endCall.setImageResource(R.drawable.ic_clear_white_48dp);
|
||||
this.binding.endCall.show();
|
||||
this.binding.acceptCall.hide();
|
||||
} else if (state == RtpEndUserState.CONNECTIVITY_ERROR) {
|
||||
} else if (state == RtpEndUserState.CONNECTIVITY_ERROR || state == RtpEndUserState.APPLICATION_ERROR) {
|
||||
this.binding.rejectCall.setOnClickListener(this::exit);
|
||||
this.binding.rejectCall.setImageResource(R.drawable.ic_clear_white_48dp);
|
||||
this.binding.rejectCall.show();
|
||||
|
|
|
@ -95,6 +95,7 @@ public abstract class AbstractJingleConnection {
|
|||
TERMINATED_SUCCESS, //equal to 'ENDED' (after successful call) ui will just close
|
||||
TERMINATED_DECLINED_OR_BUSY, //equal to 'ENDED' (after other party declined the call)
|
||||
TERMINATED_CONNECTIVITY_ERROR, //equal to 'ENDED' (but after network failures; ui will display retry button)
|
||||
TERMINATED_CANCEL_OR_TIMEOUT //more or less the same as retracted; caller pressed end call before session was accepted
|
||||
TERMINATED_CANCEL_OR_TIMEOUT, //more or less the same as retracted; caller pressed end call before session was accepted
|
||||
TERMINATED_APPLICATION_FAILURE
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,22 +55,27 @@ public class JingleConnectionManager extends AbstractConnectionManager {
|
|||
} else if (Namespace.JINGLE_APPS_RTP.equals(descriptionNamespace)) {
|
||||
connection = new JingleRtpConnection(this, id, from);
|
||||
} else {
|
||||
//TODO return feature-not-implemented
|
||||
respondWithJingleError(account, packet, "unsupported-info", "feature-not-implemented", "cancel");
|
||||
return;
|
||||
}
|
||||
connections.put(id, connection);
|
||||
connection.deliverPacket(packet);
|
||||
} else {
|
||||
Log.d(Config.LOGTAG, "unable to route jingle packet: " + packet);
|
||||
final IqPacket response = packet.generateResponse(IqPacket.TYPE.ERROR);
|
||||
final Element error = response.addChild("error");
|
||||
error.setAttribute("type", "cancel");
|
||||
error.addChild("item-not-found", "urn:ietf:params:xml:ns:xmpp-stanzas");
|
||||
error.addChild("unknown-session", "urn:xmpp:jingle:errors:1");
|
||||
account.getXmppConnection().sendIqPacket(response, null);
|
||||
respondWithJingleError(account, packet, "unknown-session", "item-not-found", "cancel");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void respondWithJingleError(final Account account, final IqPacket original, String jingleCondition, String condition, String conditionType) {
|
||||
final IqPacket response = original.generateResponse(IqPacket.TYPE.ERROR);
|
||||
final Element error = response.addChild("error");
|
||||
error.setAttribute("type", conditionType);
|
||||
error.addChild(condition, "urn:ietf:params:xml:ns:xmpp-stanzas");
|
||||
error.addChild(jingleCondition, "urn:xmpp:jingle:errors:1");
|
||||
account.getXmppConnection().sendIqPacket(response, null);
|
||||
}
|
||||
|
||||
public void deliverMessage(final Account account, final Jid to, final Jid from, final Element message) {
|
||||
Preconditions.checkArgument(Namespace.JINGLE_MESSAGE.equals(message.getNamespace()));
|
||||
final String sessionId = message.getAttribute("id");
|
||||
|
|
|
@ -34,12 +34,40 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
|
|||
|
||||
static {
|
||||
final ImmutableMap.Builder<State, Collection<State>> transitionBuilder = new ImmutableMap.Builder<>();
|
||||
transitionBuilder.put(State.NULL, ImmutableList.of(State.PROPOSED, State.SESSION_INITIALIZED));
|
||||
transitionBuilder.put(State.PROPOSED, ImmutableList.of(State.ACCEPTED, State.PROCEED, State.REJECTED, State.RETRACTED));
|
||||
transitionBuilder.put(State.PROCEED, ImmutableList.of(State.SESSION_INITIALIZED_PRE_APPROVED, State.TERMINATED_SUCCESS));
|
||||
transitionBuilder.put(State.SESSION_INITIALIZED, ImmutableList.of(State.SESSION_ACCEPTED, State.TERMINATED_CANCEL_OR_TIMEOUT, State.TERMINATED_DECLINED_OR_BUSY));
|
||||
transitionBuilder.put(State.SESSION_INITIALIZED_PRE_APPROVED, ImmutableList.of(State.SESSION_ACCEPTED, State.TERMINATED_CANCEL_OR_TIMEOUT, State.TERMINATED_DECLINED_OR_BUSY));
|
||||
transitionBuilder.put(State.SESSION_ACCEPTED, ImmutableList.of(State.TERMINATED_SUCCESS, State.TERMINATED_CONNECTIVITY_ERROR));
|
||||
transitionBuilder.put(State.NULL, ImmutableList.of(
|
||||
State.PROPOSED,
|
||||
State.SESSION_INITIALIZED,
|
||||
State.TERMINATED_APPLICATION_FAILURE
|
||||
));
|
||||
transitionBuilder.put(State.PROPOSED, ImmutableList.of(
|
||||
State.ACCEPTED,
|
||||
State.PROCEED,
|
||||
State.REJECTED,
|
||||
State.RETRACTED,
|
||||
State.TERMINATED_APPLICATION_FAILURE
|
||||
));
|
||||
transitionBuilder.put(State.PROCEED, ImmutableList.of(
|
||||
State.SESSION_INITIALIZED_PRE_APPROVED,
|
||||
State.TERMINATED_SUCCESS,
|
||||
State.TERMINATED_APPLICATION_FAILURE
|
||||
));
|
||||
transitionBuilder.put(State.SESSION_INITIALIZED, ImmutableList.of(
|
||||
State.SESSION_ACCEPTED,
|
||||
State.TERMINATED_CANCEL_OR_TIMEOUT,
|
||||
State.TERMINATED_DECLINED_OR_BUSY,
|
||||
State.TERMINATED_APPLICATION_FAILURE
|
||||
));
|
||||
transitionBuilder.put(State.SESSION_INITIALIZED_PRE_APPROVED, ImmutableList.of(
|
||||
State.SESSION_ACCEPTED,
|
||||
State.TERMINATED_CANCEL_OR_TIMEOUT,
|
||||
State.TERMINATED_DECLINED_OR_BUSY,
|
||||
State.TERMINATED_APPLICATION_FAILURE
|
||||
));
|
||||
transitionBuilder.put(State.SESSION_ACCEPTED, ImmutableList.of(
|
||||
State.TERMINATED_SUCCESS,
|
||||
State.TERMINATED_CONNECTIVITY_ERROR,
|
||||
State.TERMINATED_APPLICATION_FAILURE
|
||||
));
|
||||
VALID_TRANSITIONS = transitionBuilder.build();
|
||||
}
|
||||
|
||||
|
@ -64,6 +92,8 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
|
|||
case CANCEL:
|
||||
case TIMEOUT:
|
||||
return State.TERMINATED_CANCEL_OR_TIMEOUT;
|
||||
case FAILED_APPLICATION:
|
||||
return State.TERMINATED_APPLICATION_FAILURE;
|
||||
default:
|
||||
return State.TERMINATED_CONNECTIVITY_ERROR;
|
||||
}
|
||||
|
@ -86,12 +116,14 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
|
|||
receiveSessionTerminate(jinglePacket);
|
||||
break;
|
||||
default:
|
||||
respondOk(jinglePacket);
|
||||
Log.d(Config.LOGTAG, String.format("%s: received unhandled jingle action %s", id.account.getJid().asBareJid(), jinglePacket.getAction()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void receiveSessionTerminate(final JinglePacket jinglePacket) {
|
||||
respondOk(jinglePacket);
|
||||
final Reason reason = jinglePacket.getReason();
|
||||
final State previous = this.state;
|
||||
Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": received session terminate reason=" + reason + " while in state " + previous);
|
||||
|
@ -105,11 +137,12 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
|
|||
|
||||
private void receiveTransportInfo(final JinglePacket jinglePacket) {
|
||||
if (isInState(State.SESSION_INITIALIZED, State.SESSION_INITIALIZED_PRE_APPROVED, State.SESSION_ACCEPTED)) {
|
||||
respondOk(jinglePacket);
|
||||
final RtpContentMap contentMap;
|
||||
try {
|
||||
contentMap = RtpContentMap.of(jinglePacket);
|
||||
} catch (IllegalArgumentException | NullPointerException e) {
|
||||
Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": improperly formatted contents", e);
|
||||
Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": improperly formatted contents; ignoring", e);
|
||||
return;
|
||||
}
|
||||
final RtpContentMap rtpContentMap = isInitiator() ? this.responderRtpContentMap : this.initiatorRtpContentMap;
|
||||
|
@ -136,13 +169,14 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
|
|||
}
|
||||
} else {
|
||||
Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": received transport info while in state=" + this.state);
|
||||
respondWithOutOfOrder(jinglePacket);
|
||||
}
|
||||
}
|
||||
|
||||
private void receiveSessionInitiate(final JinglePacket jinglePacket) {
|
||||
if (isInitiator()) {
|
||||
Log.d(Config.LOGTAG, String.format("%s: received session-initiate even though we were initiating", id.account.getJid().asBareJid()));
|
||||
//TODO respond with out-of-order
|
||||
respondWithOutOfOrder(jinglePacket);
|
||||
return;
|
||||
}
|
||||
final RtpContentMap contentMap;
|
||||
|
@ -150,6 +184,8 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
|
|||
contentMap = RtpContentMap.of(jinglePacket);
|
||||
contentMap.requireContentDescriptions();
|
||||
} catch (IllegalArgumentException | IllegalStateException | NullPointerException e) {
|
||||
respondOk(jinglePacket);
|
||||
sendSessionTerminate(Reason.FAILED_APPLICATION);
|
||||
Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": improperly formatted contents", e);
|
||||
return;
|
||||
}
|
||||
|
@ -161,6 +197,7 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
|
|||
target = State.SESSION_INITIALIZED;
|
||||
}
|
||||
if (transition(target)) {
|
||||
respondOk(jinglePacket);
|
||||
this.initiatorRtpContentMap = contentMap;
|
||||
if (target == State.SESSION_INITIALIZED_PRE_APPROVED) {
|
||||
Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": automatically accepting session-initiate");
|
||||
|
@ -171,13 +208,14 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
|
|||
}
|
||||
} else {
|
||||
Log.d(Config.LOGTAG, String.format("%s: received session-initiate while in state %s", id.account.getJid().asBareJid(), state));
|
||||
respondWithOutOfOrder(jinglePacket);
|
||||
}
|
||||
}
|
||||
|
||||
private void receiveSessionAccept(final JinglePacket jinglePacket) {
|
||||
if (!isInitiator()) {
|
||||
Log.d(Config.LOGTAG, String.format("%s: received session-accept even though we were responding", id.account.getJid().asBareJid()));
|
||||
//TODO respond with out-of-order
|
||||
respondWithOutOfOrder(jinglePacket);
|
||||
return;
|
||||
}
|
||||
final RtpContentMap contentMap;
|
||||
|
@ -185,28 +223,43 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
|
|||
contentMap = RtpContentMap.of(jinglePacket);
|
||||
contentMap.requireContentDescriptions();
|
||||
} catch (IllegalArgumentException | IllegalStateException | NullPointerException e) {
|
||||
Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": improperly formatted contents", e);
|
||||
respondOk(jinglePacket);
|
||||
Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": improperly formatted contents in session-accept", e);
|
||||
webRTCWrapper.close();
|
||||
sendSessionTerminate(Reason.FAILED_APPLICATION);
|
||||
return;
|
||||
}
|
||||
Log.d(Config.LOGTAG, "processing session-accept with " + contentMap.contents.size() + " contents");
|
||||
if (transition(State.SESSION_ACCEPTED)) {
|
||||
respondOk(jinglePacket);
|
||||
receiveSessionAccept(contentMap);
|
||||
} else {
|
||||
Log.d(Config.LOGTAG, String.format("%s: received session-accept while in state %s", id.account.getJid().asBareJid(), state));
|
||||
//TODO out-of-order
|
||||
respondOk(jinglePacket);
|
||||
}
|
||||
}
|
||||
|
||||
private void receiveSessionAccept(final RtpContentMap contentMap) {
|
||||
this.responderRtpContentMap = contentMap;
|
||||
final SessionDescription sessionDescription;
|
||||
try {
|
||||
sessionDescription = SessionDescription.of(contentMap);
|
||||
} catch (IllegalArgumentException e) {
|
||||
Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": unable convert offer from session-accept to SDP", e);
|
||||
webRTCWrapper.close();
|
||||
sendSessionTerminate(Reason.FAILED_APPLICATION);
|
||||
return;
|
||||
}
|
||||
org.webrtc.SessionDescription answer = new org.webrtc.SessionDescription(
|
||||
org.webrtc.SessionDescription.Type.ANSWER,
|
||||
SessionDescription.of(contentMap).toString()
|
||||
sessionDescription.toString()
|
||||
);
|
||||
try {
|
||||
this.webRTCWrapper.setRemoteDescription(answer).get();
|
||||
} catch (Exception e) {
|
||||
Log.d(Config.LOGTAG, "unable to receive session accept", e);
|
||||
Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": unable to set remote description after receiving session-accept", e);
|
||||
webRTCWrapper.close();
|
||||
sendSessionTerminate(Reason.FAILED_APPLICATION);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -219,8 +272,10 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
|
|||
try {
|
||||
offer = SessionDescription.of(rtpContentMap);
|
||||
} catch (final IllegalArgumentException e) {
|
||||
Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": unable to process offer", e);
|
||||
//TODO terminate session with application error
|
||||
Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": unable convert offer from session-initiate to SDP", e);
|
||||
webRTCWrapper.close();
|
||||
sendSessionTerminate(Reason.FAILED_APPLICATION);
|
||||
;
|
||||
return;
|
||||
}
|
||||
sendSessionAccept(offer);
|
||||
|
@ -228,7 +283,12 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
|
|||
|
||||
private void sendSessionAccept(SessionDescription offer) {
|
||||
discoverIceServers(iceServers -> {
|
||||
try {
|
||||
setupWebRTC(iceServers);
|
||||
} catch (WebRTCWrapper.InitializationException e) {
|
||||
sendSessionTerminate(Reason.FAILED_APPLICATION);
|
||||
return;
|
||||
}
|
||||
final org.webrtc.SessionDescription sdp = new org.webrtc.SessionDescription(
|
||||
org.webrtc.SessionDescription.Type.OFFER,
|
||||
offer.toString()
|
||||
|
@ -351,7 +411,6 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
|
|||
this.jingleConnectionManager.finishConnection(this);
|
||||
}
|
||||
} else {
|
||||
//TODO a carbon copied proceed from another client of mine has the same logic as `accept`
|
||||
Log.d(Config.LOGTAG, String.format("%s: ignoring proceed from %s. was expected from %s", id.account.getJid().asBareJid(), from, id.with));
|
||||
}
|
||||
}
|
||||
|
@ -374,7 +433,13 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
|
|||
private void sendSessionInitiate(final State targetState) {
|
||||
Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": prepare session-initiate");
|
||||
discoverIceServers(iceServers -> {
|
||||
try {
|
||||
setupWebRTC(iceServers);
|
||||
} catch (WebRTCWrapper.InitializationException e) {
|
||||
Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": unable to initialize webrtc");
|
||||
transitionOrThrow(State.TERMINATED_APPLICATION_FAILURE);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
org.webrtc.SessionDescription webRTCSessionDescription = this.webRTCWrapper.createOffer().get();
|
||||
final SessionDescription sessionDescription = SessionDescription.parse(webRTCSessionDescription.description);
|
||||
|
@ -382,8 +447,14 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
|
|||
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);
|
||||
} catch (final Exception e) {
|
||||
Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": unable to sendSessionInitiate", e);
|
||||
webRTCWrapper.close();
|
||||
if (isInState(targetState)) {
|
||||
sendSessionTerminate(Reason.FAILED_APPLICATION);
|
||||
} else {
|
||||
transitionOrThrow(State.TERMINATED_APPLICATION_FAILURE);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -422,8 +493,43 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
|
|||
|
||||
private void send(final JinglePacket jinglePacket) {
|
||||
jinglePacket.setTo(id.with);
|
||||
//TODO track errors
|
||||
xmppConnectionService.sendIqPacket(id.account, jinglePacket, null);
|
||||
xmppConnectionService.sendIqPacket(id.account, jinglePacket, (account, response) -> {
|
||||
if (response.getType() == IqPacket.TYPE.ERROR) {
|
||||
final String errorCondition = response.getErrorCondition();
|
||||
Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": received IQ-error from " + response.getFrom() + " in RTP session. " + errorCondition);
|
||||
this.webRTCWrapper.close();
|
||||
final State target;
|
||||
if (Arrays.asList(
|
||||
"service-unavailable",
|
||||
"recipient-unavailable",
|
||||
"remote-server-not-found",
|
||||
"remote-server-timeout"
|
||||
).contains(errorCondition)) {
|
||||
target = State.TERMINATED_CONNECTIVITY_ERROR;
|
||||
} else {
|
||||
target = State.TERMINATED_APPLICATION_FAILURE;
|
||||
}
|
||||
if (transition(target)) {
|
||||
Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": terminated session with " + id.with);
|
||||
} else {
|
||||
Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": not transitioning because already at state=" + this.state);
|
||||
}
|
||||
|
||||
} else if (response.getType() == IqPacket.TYPE.TIMEOUT) {
|
||||
this.webRTCWrapper.close();
|
||||
Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": received IQ timeout in RTP session with " + id.with + ". terminating with connectivity error");
|
||||
transition(State.TERMINATED_CONNECTIVITY_ERROR);
|
||||
this.jingleConnectionManager.finishConnection(this);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void respondWithOutOfOrder(final JinglePacket jinglePacket) {
|
||||
jingleConnectionManager.respondWithJingleError(id.account, jinglePacket, "out-of-order", "unexpected-request", "wait");
|
||||
}
|
||||
|
||||
private void respondOk(final JinglePacket jinglePacket) {
|
||||
xmppConnectionService.sendIqPacket(id.account, jinglePacket.generateResponse(IqPacket.TYPE.RESULT), null);
|
||||
}
|
||||
|
||||
public RtpEndUserState getEndUserState() {
|
||||
|
@ -474,6 +580,8 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
|
|||
return RtpEndUserState.ENDED;
|
||||
case TERMINATED_CONNECTIVITY_ERROR:
|
||||
return RtpEndUserState.CONNECTIVITY_ERROR;
|
||||
case TERMINATED_APPLICATION_FAILURE:
|
||||
return RtpEndUserState.APPLICATION_ERROR;
|
||||
}
|
||||
throw new IllegalStateException(String.format("%s has no equivalent EndUserState", this.state));
|
||||
}
|
||||
|
@ -526,7 +634,7 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
|
|||
throw new IllegalStateException("called 'endCall' while in state " + this.state);
|
||||
}
|
||||
|
||||
private void setupWebRTC(final List<PeerConnection.IceServer> iceServers) {
|
||||
private void setupWebRTC(final List<PeerConnection.IceServer> iceServers) throws WebRTCWrapper.InitializationException {
|
||||
this.webRTCWrapper.setup(this.xmppConnectionService);
|
||||
this.webRTCWrapper.initializePeerConnection(iceServers);
|
||||
}
|
||||
|
|
|
@ -6,10 +6,10 @@ public enum RtpEndUserState {
|
|||
CONNECTED, //session-accepted and webrtc peer connection is connected
|
||||
FINDING_DEVICE, //'propose' has been sent out; no 184 ack yet
|
||||
RINGING, //'propose' has been sent out and it has been 184 acked
|
||||
ACCEPTED_ON_OTHER_DEVICE, //received 'accept' from one of our own devices
|
||||
ACCEPTING_CALL, //'proceed' message has been sent; but no session-initiate has been received
|
||||
ENDING_CALL, //libwebrt says 'closed' but session-terminate hasnt gone through
|
||||
ENDED, //close UI
|
||||
DECLINED_OR_BUSY, //other party declined; no retry button
|
||||
CONNECTIVITY_ERROR //network error; retry button
|
||||
CONNECTIVITY_ERROR, //network error; retry button
|
||||
APPLICATION_ERROR //something rather bad happened; libwebrtc failed or we got in IQ-error
|
||||
}
|
||||
|
|
|
@ -132,7 +132,7 @@ public class WebRTCWrapper {
|
|||
);
|
||||
}
|
||||
|
||||
public void initializePeerConnection(final List<PeerConnection.IceServer> iceServers) {
|
||||
public void initializePeerConnection(final List<PeerConnection.IceServer> iceServers) throws InitializationException {
|
||||
PeerConnectionFactory peerConnectionFactory = PeerConnectionFactory.builder().createPeerConnectionFactory();
|
||||
|
||||
CameraVideoCapturer capturer = null;
|
||||
|
@ -195,7 +195,7 @@ public class WebRTCWrapper {
|
|||
|
||||
final PeerConnection peerConnection = peerConnectionFactory.createPeerConnection(iceServers, peerConnectionObserver);
|
||||
if (peerConnection == null) {
|
||||
throw new IllegalStateException("Unable to create PeerConnection");
|
||||
throw new InitializationException("Unable to create PeerConnection");
|
||||
}
|
||||
peerConnection.addStream(stream);
|
||||
peerConnection.setAudioPlayout(true);
|
||||
|
@ -344,6 +344,13 @@ public class WebRTCWrapper {
|
|||
}
|
||||
}
|
||||
|
||||
public static class InitializationException extends Exception {
|
||||
|
||||
private InitializationException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
|
||||
public interface EventCallback {
|
||||
void onIceCandidate(IceCandidate iceCandidate);
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ import android.support.annotation.NonNull;
|
|||
import com.google.common.base.CaseFormat;
|
||||
|
||||
public enum Reason {
|
||||
SUCCESS, DECLINE, BUSY, CANCEL, CONNECTIVITY_ERROR, FAILED_TRANSPORT, TIMEOUT, UNKNOWN;
|
||||
SUCCESS, DECLINE, BUSY, CANCEL, CONNECTIVITY_ERROR, FAILED_TRANSPORT, FAILED_APPLICATION, TIMEOUT, UNKNOWN;
|
||||
|
||||
public static Reason of(final String value) {
|
||||
try {
|
||||
|
|
|
@ -31,6 +31,18 @@ abstract public class AbstractAcknowledgeableStanza extends AbstractStanza {
|
|||
return null;
|
||||
}
|
||||
|
||||
public String getErrorCondition() {
|
||||
Element error = findChild("error");
|
||||
if (error != null) {
|
||||
for(Element element : error.getChildren()) {
|
||||
if (!element.getName().equals("text")) {
|
||||
return element.getName();
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean valid() {
|
||||
return InvalidJid.isValid(getFrom()) && InvalidJid.isValid(getTo());
|
||||
}
|
||||
|
|
|
@ -898,6 +898,7 @@
|
|||
<string name="rtp_state_ringing">Ringing</string>
|
||||
<string name="rtp_state_declined_or_busy">Busy</string>
|
||||
<string name="rtp_state_connectivity_error">Unable to connect call</string>
|
||||
<string name="rtp_state_application_failure">Application failure</string>
|
||||
<plurals name="view_users">
|
||||
<item quantity="one">View %1$d Participant</item>
|
||||
<item quantity="other">View %1$d Participants</item>
|
||||
|
|
Loading…
Reference in a new issue