send and receive session terminates
This commit is contained in:
		
							parent
							
								
									00f273b0c0
								
							
						
					
					
						commit
						859bc0bef3
					
				| 
						 | 
					@ -164,6 +164,7 @@ public class RtpSessionActivity extends XmppActivity implements XmppConnectionSe
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            case DECLINED_OR_BUSY:
 | 
					            case DECLINED_OR_BUSY:
 | 
				
			||||||
                binding.status.setText(R.string.rtp_state_declined_or_busy);
 | 
					                binding.status.setText(R.string.rtp_state_declined_or_busy);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
            case CONNECTIVITY_ERROR:
 | 
					            case CONNECTIVITY_ERROR:
 | 
				
			||||||
                binding.status.setText(R.string.rtp_state_connectivity_error);
 | 
					                binding.status.setText(R.string.rtp_state_connectivity_error);
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -90,6 +90,7 @@ public abstract class AbstractJingleConnection {
 | 
				
			||||||
        REJECTED,
 | 
					        REJECTED,
 | 
				
			||||||
        RETRACTED,
 | 
					        RETRACTED,
 | 
				
			||||||
        SESSION_INITIALIZED, //equal to 'PENDING'
 | 
					        SESSION_INITIALIZED, //equal to 'PENDING'
 | 
				
			||||||
 | 
					        SESSION_INITIALIZED_PRE_APPROVED,
 | 
				
			||||||
        SESSION_ACCEPTED, //equal to 'ACTIVE'
 | 
					        SESSION_ACCEPTED, //equal to 'ACTIVE'
 | 
				
			||||||
        TERMINATED_SUCCESS, //equal to 'ENDED' (after successful call) ui will just close
 | 
					        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_DECLINED_OR_BUSY, //equal to 'ENDED' (after other party declined the call)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -33,8 +33,10 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
 | 
				
			||||||
        final ImmutableMap.Builder<State, Collection<State>> transitionBuilder = new ImmutableMap.Builder<>();
 | 
					        final ImmutableMap.Builder<State, Collection<State>> transitionBuilder = new ImmutableMap.Builder<>();
 | 
				
			||||||
        transitionBuilder.put(State.NULL, ImmutableList.of(State.PROPOSED, State.SESSION_INITIALIZED));
 | 
					        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.PROPOSED, ImmutableList.of(State.ACCEPTED, State.PROCEED, State.REJECTED, State.RETRACTED));
 | 
				
			||||||
        transitionBuilder.put(State.PROCEED, ImmutableList.of(State.SESSION_INITIALIZED));
 | 
					        transitionBuilder.put(State.PROCEED, ImmutableList.of(State.SESSION_INITIALIZED_PRE_APPROVED));
 | 
				
			||||||
        transitionBuilder.put(State.SESSION_INITIALIZED, ImmutableList.of(State.SESSION_ACCEPTED));
 | 
					        transitionBuilder.put(State.SESSION_INITIALIZED, ImmutableList.of(State.SESSION_ACCEPTED, State.TERMINATED_CANCEL_OR_TIMEOUT));
 | 
				
			||||||
 | 
					        transitionBuilder.put(State.SESSION_INITIALIZED_PRE_APPROVED, ImmutableList.of(State.SESSION_ACCEPTED, State.TERMINATED_CANCEL_OR_TIMEOUT));
 | 
				
			||||||
 | 
					        transitionBuilder.put(State.SESSION_ACCEPTED, ImmutableList.of(State.TERMINATED_SUCCESS, State.TERMINATED_CONNECTIVITY_ERROR));
 | 
				
			||||||
        VALID_TRANSITIONS = transitionBuilder.build();
 | 
					        VALID_TRANSITIONS = transitionBuilder.build();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -73,27 +75,33 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private void receiveSessionTerminate(final JinglePacket jinglePacket) {
 | 
					    private void receiveSessionTerminate(final JinglePacket jinglePacket) {
 | 
				
			||||||
        final Reason reason = jinglePacket.getReason();
 | 
					        final Reason reason = jinglePacket.getReason();
 | 
				
			||||||
        switch (reason) {
 | 
					        final State previous = this.state;
 | 
				
			||||||
            case SUCCESS:
 | 
					        Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": received session terminate reason=" + reason + " while in state " + previous);
 | 
				
			||||||
                transitionOrThrow(State.TERMINATED_SUCCESS);
 | 
					        webRTCWrapper.close();
 | 
				
			||||||
                break;
 | 
					        transitionOrThrow(reasonToState(reason));
 | 
				
			||||||
            case DECLINE:
 | 
					        if (previous == State.PROPOSED || previous == State.SESSION_INITIALIZED) {
 | 
				
			||||||
            case BUSY:
 | 
					            xmppConnectionService.getNotificationService().cancelIncomingCallNotification();
 | 
				
			||||||
                transitionOrThrow(State.TERMINATED_DECLINED_OR_BUSY);
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            case CANCEL:
 | 
					 | 
				
			||||||
            case TIMEOUT:
 | 
					 | 
				
			||||||
                transitionOrThrow(State.TERMINATED_CANCEL_OR_TIMEOUT);
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            default:
 | 
					 | 
				
			||||||
                transitionOrThrow(State.TERMINATED_CONNECTIVITY_ERROR);
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        jingleConnectionManager.finishConnection(this);
 | 
					        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) {
 | 
					    private void receiveTransportInfo(final JinglePacket jinglePacket) {
 | 
				
			||||||
        if (isInState(State.SESSION_INITIALIZED, State.SESSION_ACCEPTED)) {
 | 
					        if (isInState(State.SESSION_INITIALIZED, State.SESSION_INITIALIZED_PRE_APPROVED, State.SESSION_ACCEPTED)) {
 | 
				
			||||||
            final RtpContentMap contentMap;
 | 
					            final RtpContentMap contentMap;
 | 
				
			||||||
            try {
 | 
					            try {
 | 
				
			||||||
                contentMap = RtpContentMap.of(jinglePacket);
 | 
					                contentMap = RtpContentMap.of(jinglePacket);
 | 
				
			||||||
| 
						 | 
					@ -142,10 +150,15 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        Log.d(Config.LOGTAG, "processing session-init with " + contentMap.contents.size() + " contents");
 | 
					        Log.d(Config.LOGTAG, "processing session-init with " + contentMap.contents.size() + " contents");
 | 
				
			||||||
        final State oldState = this.state;
 | 
					        final State target;
 | 
				
			||||||
        if (transition(State.SESSION_INITIALIZED)) {
 | 
					        if (this.state == State.PROCEED) {
 | 
				
			||||||
 | 
					            target = State.SESSION_INITIALIZED_PRE_APPROVED;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            target = State.SESSION_INITIALIZED;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (transition(target)) {
 | 
				
			||||||
            this.initiatorRtpContentMap = contentMap;
 | 
					            this.initiatorRtpContentMap = contentMap;
 | 
				
			||||||
            if (oldState == State.PROCEED) {
 | 
					            if (target == State.SESSION_INITIALIZED_PRE_APPROVED) {
 | 
				
			||||||
                Log.d(Config.LOGTAG, "automatically accepting");
 | 
					                Log.d(Config.LOGTAG, "automatically accepting");
 | 
				
			||||||
                sendSessionAccept();
 | 
					                sendSessionAccept();
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
| 
						 | 
					@ -254,10 +267,10 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
 | 
				
			||||||
                this.xmppConnectionService.getNotificationService().cancelIncomingCallNotification();
 | 
					                this.xmppConnectionService.getNotificationService().cancelIncomingCallNotification();
 | 
				
			||||||
                this.jingleConnectionManager.finishConnection(this);
 | 
					                this.jingleConnectionManager.finishConnection(this);
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                Log.d(Config.LOGTAG,id.account.getJid().asBareJid()+": unable to transition to accept because already in state="+this.state);
 | 
					                Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": unable to transition to accept because already in state=" + this.state);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            Log.d(Config.LOGTAG,id.account.getJid().asBareJid()+": ignoring 'accept' from "+from);
 | 
					            Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": ignoring 'accept' from " + from);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -297,7 +310,7 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
 | 
				
			||||||
        if (from.equals(id.with)) {
 | 
					        if (from.equals(id.with)) {
 | 
				
			||||||
            if (isInitiator()) {
 | 
					            if (isInitiator()) {
 | 
				
			||||||
                if (transition(State.PROCEED)) {
 | 
					                if (transition(State.PROCEED)) {
 | 
				
			||||||
                    this.sendSessionInitiate();
 | 
					                    this.sendSessionInitiate(State.SESSION_INITIALIZED_PRE_APPROVED);
 | 
				
			||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
                    Log.d(Config.LOGTAG, String.format("%s: ignoring proceed because already in %s", id.account.getJid().asBareJid(), this.state));
 | 
					                    Log.d(Config.LOGTAG, String.format("%s: ignoring proceed because already in %s", id.account.getJid().asBareJid(), this.state));
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
| 
						 | 
					@ -331,7 +344,7 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private void sendSessionInitiate() {
 | 
					    private void sendSessionInitiate(final State targetState) {
 | 
				
			||||||
        Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": prepare session-initiate");
 | 
					        Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": prepare session-initiate");
 | 
				
			||||||
        setupWebRTC();
 | 
					        setupWebRTC();
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
| 
						 | 
					@ -339,21 +352,31 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
 | 
				
			||||||
            final SessionDescription sessionDescription = SessionDescription.parse(webRTCSessionDescription.description);
 | 
					            final SessionDescription sessionDescription = SessionDescription.parse(webRTCSessionDescription.description);
 | 
				
			||||||
            Log.d(Config.LOGTAG, "description: " + webRTCSessionDescription.description);
 | 
					            Log.d(Config.LOGTAG, "description: " + webRTCSessionDescription.description);
 | 
				
			||||||
            final RtpContentMap rtpContentMap = RtpContentMap.of(sessionDescription);
 | 
					            final RtpContentMap rtpContentMap = RtpContentMap.of(sessionDescription);
 | 
				
			||||||
            sendSessionInitiate(rtpContentMap);
 | 
					            sendSessionInitiate(rtpContentMap, targetState);
 | 
				
			||||||
            this.webRTCWrapper.setLocalDescription(webRTCSessionDescription).get();
 | 
					            this.webRTCWrapper.setLocalDescription(webRTCSessionDescription).get();
 | 
				
			||||||
        } catch (Exception e) {
 | 
					        } catch (Exception e) {
 | 
				
			||||||
            Log.d(Config.LOGTAG, "unable to sendSessionInitiate", e);
 | 
					            Log.d(Config.LOGTAG, "unable to sendSessionInitiate", e);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private void sendSessionInitiate(RtpContentMap rtpContentMap) {
 | 
					    private void sendSessionInitiate(RtpContentMap rtpContentMap, final State targetState) {
 | 
				
			||||||
        this.initiatorRtpContentMap = rtpContentMap;
 | 
					        this.initiatorRtpContentMap = rtpContentMap;
 | 
				
			||||||
        this.transitionOrThrow(State.SESSION_INITIALIZED);
 | 
					        this.transitionOrThrow(targetState);
 | 
				
			||||||
        final JinglePacket sessionInitiate = rtpContentMap.toJinglePacket(JinglePacket.Action.SESSION_INITIATE, id.sessionId);
 | 
					        final JinglePacket sessionInitiate = rtpContentMap.toJinglePacket(JinglePacket.Action.SESSION_INITIATE, id.sessionId);
 | 
				
			||||||
        Log.d(Config.LOGTAG, sessionInitiate.toString());
 | 
					        Log.d(Config.LOGTAG, sessionInitiate.toString());
 | 
				
			||||||
        send(sessionInitiate);
 | 
					        send(sessionInitiate);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void sendSessionTerminate(final Reason reason) {
 | 
				
			||||||
 | 
					        final State target = reasonToState(reason);
 | 
				
			||||||
 | 
					        transitionOrThrow(target);
 | 
				
			||||||
 | 
					        final JinglePacket jinglePacket = new JinglePacket(JinglePacket.Action.SESSION_TERMINATE, id.sessionId);
 | 
				
			||||||
 | 
					        jinglePacket.setReason(reason);
 | 
				
			||||||
 | 
					        send(jinglePacket);
 | 
				
			||||||
 | 
					        Log.d(Config.LOGTAG, jinglePacket.toString());
 | 
				
			||||||
 | 
					        jingleConnectionManager.finishConnection(this);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private void sendTransportInfo(final String contentName, IceUdpTransportInfo.Candidate candidate) {
 | 
					    private void sendTransportInfo(final String contentName, IceUdpTransportInfo.Candidate candidate) {
 | 
				
			||||||
        final RtpContentMap transportInfo;
 | 
					        final RtpContentMap transportInfo;
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
| 
						 | 
					@ -377,6 +400,7 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
 | 
				
			||||||
    public RtpEndUserState getEndUserState() {
 | 
					    public RtpEndUserState getEndUserState() {
 | 
				
			||||||
        switch (this.state) {
 | 
					        switch (this.state) {
 | 
				
			||||||
            case PROPOSED:
 | 
					            case PROPOSED:
 | 
				
			||||||
 | 
					            case SESSION_INITIALIZED:
 | 
				
			||||||
                if (isInitiator()) {
 | 
					                if (isInitiator()) {
 | 
				
			||||||
                    return RtpEndUserState.RINGING;
 | 
					                    return RtpEndUserState.RINGING;
 | 
				
			||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
| 
						 | 
					@ -388,7 +412,7 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
 | 
				
			||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
                    return RtpEndUserState.ACCEPTING_CALL;
 | 
					                    return RtpEndUserState.ACCEPTING_CALL;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            case SESSION_INITIALIZED:
 | 
					            case SESSION_INITIALIZED_PRE_APPROVED:
 | 
				
			||||||
                return RtpEndUserState.CONNECTING;
 | 
					                return RtpEndUserState.CONNECTING;
 | 
				
			||||||
            case SESSION_ACCEPTED:
 | 
					            case SESSION_ACCEPTED:
 | 
				
			||||||
                final PeerConnection.PeerConnectionState state = webRTCWrapper.getState();
 | 
					                final PeerConnection.PeerConnectionState state = webRTCWrapper.getState();
 | 
				
			||||||
| 
						 | 
					@ -446,20 +470,14 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public void endCall() {
 | 
					    public void endCall() {
 | 
				
			||||||
 | 
					        if (isInitiator() && isInState(State.SESSION_INITIALIZED)) {
 | 
				
			||||||
        //TODO from `propose` we call `retract`
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (isInState(State.SESSION_INITIALIZED, State.SESSION_ACCEPTED)) {
 | 
					 | 
				
			||||||
            //TODO during session_initialized we might not have a peer connection yet (if the session was initialized directly)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            //TODO from session_initialized we call `cancel`
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            //TODO from session_accepted we call `success`
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            webRTCWrapper.close();
 | 
					            webRTCWrapper.close();
 | 
				
			||||||
 | 
					            sendSessionTerminate(Reason.CANCEL);
 | 
				
			||||||
 | 
					        } else if (isInState(State.SESSION_INITIALIZED, State.SESSION_INITIALIZED_PRE_APPROVED, State.SESSION_ACCEPTED)) {
 | 
				
			||||||
 | 
					            webRTCWrapper.close();
 | 
				
			||||||
 | 
					            sendSessionTerminate(Reason.SUCCESS);
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            //TODO during earlier stages we want to retract the proposal etc
 | 
					            throw new IllegalStateException("called 'endCall' while in state " + this.state);
 | 
				
			||||||
            Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": called 'endCall' while in state " + this.state);
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -530,9 +548,12 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public void onConnectionChange(PeerConnection.PeerConnectionState newState) {
 | 
					    public void onConnectionChange(final PeerConnection.PeerConnectionState newState) {
 | 
				
			||||||
        Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": PeerConnectionState changed to " + newState);
 | 
					        Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": PeerConnectionState changed to " + newState);
 | 
				
			||||||
        updateEndUserState();
 | 
					        updateEndUserState();
 | 
				
			||||||
 | 
					        if (newState == PeerConnection.PeerConnectionState.FAILED) { //TODO guard this in isState(initiated,initated_approved,accepted) otherwise it might fire too late
 | 
				
			||||||
 | 
					            sendSessionTerminate(Reason.CONNECTIVITY_ERROR);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private void updateEndUserState() {
 | 
					    private void updateEndUserState() {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -207,10 +207,17 @@ public class WebRTCWrapper {
 | 
				
			||||||
        this.peerConnection = peerConnection;
 | 
					        this.peerConnection = peerConnection;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public void close() {
 | 
					    public void closeOrThrow() {
 | 
				
			||||||
        requirePeerConnection().close();
 | 
					        requirePeerConnection().close();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void close() {
 | 
				
			||||||
 | 
					        final PeerConnection peerConnection = this.peerConnection;
 | 
				
			||||||
 | 
					        if (peerConnection != null) {
 | 
				
			||||||
 | 
					            peerConnection.close();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public ListenableFuture<SessionDescription> createOffer() {
 | 
					    public ListenableFuture<SessionDescription> createOffer() {
 | 
				
			||||||
        return Futures.transformAsync(getPeerConnectionFuture(), peerConnection -> {
 | 
					        return Futures.transformAsync(getPeerConnectionFuture(), peerConnection -> {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -83,7 +83,7 @@ public class JinglePacket extends IqPacket {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public void setReason(final Reason reason) {
 | 
					    public void setReason(final Reason reason) {
 | 
				
			||||||
        final Element jingle = findChild("jingle", Namespace.JINGLE);
 | 
					        final Element jingle = findChild("jingle", Namespace.JINGLE);
 | 
				
			||||||
        jingle.addChild(new Element("reason").addChild(reason.toString()));
 | 
					        jingle.addChild("reason").addChild(reason.toString());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //RECOMMENDED for session-initiate, NOT RECOMMENDED otherwise
 | 
					    //RECOMMENDED for session-initiate, NOT RECOMMENDED otherwise
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue