/** * Constructor * * @param parent IMS service * @param invite Initial INVITE request */ public TerminatingOne2OneChatSession(ImsService parent, SipRequest invite) { super(parent, PhoneUtils.extractNumberFromUri(SipUtils.getAssertedIdentity(invite))); // Set first message InstantMessage firstMsg = ChatUtils.getFirstMessage(invite); setFirstMesssage(firstMsg); // Create dialog path createTerminatingDialogPath(invite); // Set contribution ID String id = ChatUtils.getContributionId(invite); setContributionID(id); if (RcsSettings.getInstance().isCPMSupported()) { if (logger.isActivated()) { logger.info("TerminatingFOne2OneSession1 CPMS"); } setConversationID(ChatUtils.getCoversationId(invite)); setInReplyID(ChatUtils.getInReplyId(invite)); } if (logger.isActivated()) { logger.info("TerminatingOne2OneChatSession From: " + ChatUtils.getFromAias(invite)); logger.info("TerminatingOne2OneChatSession Display name: " + this.getRemoteDisplayName()); } setRemoteDisplayName(this.getRemoteDisplayName()); }
/** Interrupt session */ public void interruptSession() { if (logger.isActivated()) { logger.info("ABC Interrupt the session"); } try { // Unblock semaphore synchronized (waitUserAnswer) { waitUserAnswer.notifyAll(); } if (!isSessionInterrupted()) { if (logger.isActivated()) { logger.info("ABC Interrupt the session1"); } // Interrupt thread sessionInterrupted = true; interrupt(); } } catch (Exception e) { if (logger.isActivated()) { logger.error("Can't interrupt the session correctly", e); } } if (logger.isActivated()) { logger.debug("Session has been interrupted"); } }
/** Background processing */ public void run() { try { if (logger.isActivated()) { logger.info("Rejoin an existing group chat session"); } // Set setup mode String localSetup = createSetupOffer(); if (logger.isActivated()) { logger.debug("Local setup attribute is " + localSetup); } // Set local port int localMsrpPort; if ("active".equals(localSetup)) { localMsrpPort = 9; // See RFC4145, Page 4 } else { localMsrpPort = getMsrpMgr().getLocalMsrpPort(); } // Build SDP part String ipAddress = getDialogPath().getSipStack().getLocalIpAddress(); String sdp = SdpUtils.buildGroupChatSDP( ipAddress, localMsrpPort, getMsrpMgr().getLocalSocketProtocol(), getAcceptTypes(), getWrappedTypes(), localSetup, getMsrpMgr().getLocalMsrpPath(), SdpUtils.DIRECTION_SENDRECV); // Set the local SDP part in the dialog path getDialogPath().setLocalContent(sdp); // Create an INVITE request if (logger.isActivated()) { logger.info("Send INVITE"); } SipRequest invite = createInviteRequest(sdp); // Set the Authorization header getAuthenticationAgent().setAuthorizationHeader(invite); // Set initial request in the dialog path getDialogPath().setInvite(invite); // Send INVITE request sendInvite(invite); } catch (Exception e) { if (logger.isActivated()) { logger.error("Session initiation has failed", e); } // Unexpected error handleError(new ChatError(ChatError.UNEXPECTED_EXCEPTION, e.getMessage())); } }
/** * Receive CANCEL request * * @param cancel CANCEL request */ public void receiveCancel(SipRequest cancel) { if (logger.isActivated()) { logger.info("ABC Receive a CANCEL message from the remote"); } if (getDialogPath().isSigEstablished()) { if (logger.isActivated()) { logger.info( "Ignore the received CANCEL message from the remote (session already established)"); } return; } // Close media session closeMediaSession(); // Update dialog path getDialogPath().sessionCancelled(); // Send a 487 Request terminated try { if (logger.isActivated()) { logger.info("Send 487 Request terminated"); } SipResponse terminatedResp = SipMessageFactory.createResponse( getDialogPath().getInvite(), getDialogPath().getLocalTag(), 487); getImsService().getImsModule().getSipManager().sendSipResponse(terminatedResp); } catch (Exception e) { if (logger.isActivated()) { logger.error("Can't send 487 error response", e); } } // Remove the current session getImsService().removeSession(this); // Set invitation status invitationStatus = ImsServiceSession.INVITATION_CANCELED; // Unblock semaphore synchronized (waitUserAnswer) { waitUserAnswer.notifyAll(); } // Notify listeners for (int i = 0; i < getListeners().size(); i++) { getListeners().get(i).handleSessionTerminatedByRemote(); } // Request capabilities to the remote getImsService() .getImsModule() .getCapabilityService() .requestContactCapabilities(getDialogPath().getRemoteParty()); }
/** * Handle 422 response * * @param resp 422 response */ private void handle422SessionTooSmall(SipResponse resp) { try { // 422 response received if (logger.isActivated()) { logger.info("422 response received"); } // Extract the Min-SE value int minExpire = SipUtils.getMinSessionExpirePeriod(resp); if (minExpire == -1) { if (logger.isActivated()) { logger.error("Can't read the Min-SE value"); } handleError( new FileSharingError(FileSharingError.UNEXPECTED_EXCEPTION, "No Min-SE value found")); return; } // Set the min expire value getDialogPath().setMinSessionExpireTime(minExpire); // Set the expire value getDialogPath().setSessionExpireTime(minExpire); // Increment the Cseq number of the dialog path getDialogPath().incrementCseq(); // Create a new INVITE with the right expire period if (logger.isActivated()) { logger.info("Send new INVITE"); } SipRequest invite = SipMessageFactory.createInvite( getDialogPath(), InstantMessagingService.FT_FEATURE_TAGS, getDialogPath().getLocalContent()); // Set the Authorization header getAuthenticationAgent().setAuthorizationHeader(invite); // Reset initial request in the dialog path getDialogPath().setInvite(invite); // Send INVITE request sendInvite(invite); } catch (Exception e) { if (logger.isActivated()) { logger.error("Session initiation has failed", e); } // Unexpected error handleError(new FileSharingError(FileSharingError.UNEXPECTED_EXCEPTION, e.getMessage())); } }
/** * Returns a current session from its unique session ID * * @return Multimedia session or null if not found * @throws ServerApiException */ public IMultimediaSession getSession(String sessionId) throws ServerApiException { if (logger.isActivated()) { logger.info("Get multimedia session " + sessionId); } return sipSessions.get(sessionId); }
/** * Data transfer error * * @param error Error */ public void msrpTransferError(String error) { if (isInterrupted()) { return; } if (logger.isActivated()) { logger.info("Data transfer error: " + error); } // Close the media session closeMediaSession(); // Terminate session terminateSession(); // Remove the current session getImsService().removeSession(this); // Notify listeners if (!isInterrupted()) { for (int j = 0; j < getListeners().size(); j++) { ((FileSharingSessionListener) getListeners().get(j)) .handleTransferError( new FileSharingError(FileSharingError.MEDIA_TRANSFER_FAILED, error)); } } }
/** Stop core */ public synchronized void stopCore() { if (Core.getInstance() == null) { // Already stopped return; } if (logger.isActivated()) { logger.debug("Stop RCS core service"); } // Update GSMA client API GsmaUtils.setClientActivationState(getApplicationContext(), false); // Send service intent Intent intent = new Intent(ClientApiIntents.SERVICE_STATUS); intent.putExtra("status", ClientApiIntents.SERVICE_STATUS_STOPPING); getApplicationContext().sendBroadcast(intent); // Terminate the core in background Core.terminateCore(); // Close CPU manager cpuManager.close(); // Send service intent intent = new Intent(ClientApiIntents.SERVICE_STATUS); intent.putExtra("status", ClientApiIntents.SERVICE_STATUS_STOPPED); getApplicationContext().sendBroadcast(intent); if (logger.isActivated()) { logger.info("RCS core service stopped with success"); } }
/** * Sends a message in pager mode to a contact and for a given service. The message may be any type * of content. The parameter contact supports the following formats: MSISDN in national or * international format, SIP address, SIP-URI or Tel-URI. If the format of the contact is not * supported an exception is thrown. * * @param serviceId Service ID * @param contact Contact * @param content Message content * @return Returns true if sent successfully else returns false * @throws ServerApiException */ public boolean sendMessage(String serviceId, String contact, byte[] content) throws ServerApiException { if (logger.isActivated()) { logger.info("Send instant message to " + contact); } // Test IMS connection ServerApiUtils.testIms(); try { // Send instant message String featureTag = FeatureTags.FEATURE_RCSE + "=\"" + FeatureTags.FEATURE_RCSE_EXTENSION + "." + serviceId + "\""; return Core.getInstance().getSipService().sendInstantMessage(contact, featureTag, content); } catch (Exception e) { if (logger.isActivated()) { logger.error("Unexpected error", e); } throw new ServerApiException(e.getMessage()); } }
/** * Receive a new video sharing invitation * * @param session Video sharing session */ public void receiveVideoSharingInvitation(VideoStreamingSession session) { if (logger.isActivated()) { logger.info("Receive video sharing invitation from " + session.getRemoteContact()); } // Extract number from contact String number = PhoneUtils.extractNumberFromUri(session.getRemoteContact()); VideoContent content = (VideoContent) session.getContent(); // Update rich call history RichCall.getInstance() .addCall( number, session.getSessionID(), RichCallData.EVENT_INCOMING, content, RichCallData.STATUS_STARTED); // Add session in the list VideoSharingSession sessionApi = new VideoSharingSession(session); addVideoSharingSession(sessionApi); // Broadcast intent related to the received invitation Intent intent = new Intent(RichCallApiIntents.VIDEO_SHARING_INVITATION); intent.putExtra("contact", number); intent.putExtra("contactDisplayname", session.getRemoteDisplayName()); intent.putExtra("sessionId", session.getSessionID()); intent.putExtra("videotype", content.getEncoding()); intent.putExtra("videowidth", content.getWidth()); intent.putExtra("videoheight", content.getHeight()); AndroidFactory.getApplicationContext().sendBroadcast(intent); }
/** * Returns a current geoloc sharing from its unique ID * * @return Geoloc sharing * @throws ServerApiException */ public IGeolocSharing getGeolocSharing(String sharingId) throws ServerApiException { if (logger.isActivated()) { logger.info("Get geoloc sharing session " + sharingId); } return gshSessions.get(sharingId); }
/** * Returns a current video sharing from its unique ID * * @return Video sharing or null if not found * @throws ServerApiException */ public IVideoSharing getVideoSharing(String sharingId) throws ServerApiException { if (logger.isActivated()) { logger.info("Get video sharing session " + sharingId); } return videoSharingSessions.get(sharingId); }
/** * Receive a new geoloc sharing invitation * * @param session Geoloc sharing session */ public void receiveGeolocSharingInvitation(GeolocTransferSession session) { if (logger.isActivated()) { logger.info("Receive geoloc sharing invitation from " + session.getRemoteContact()); } // Extract number from contact String number = PhoneUtils.extractNumberFromUri(session.getRemoteContact()); // Update rich call history RichCall.getInstance() .addCall( number, session.getSessionID(), RichCallData.EVENT_INCOMING, session.getContent(), RichCallData.STATUS_STARTED); // Add session in the list GeolocSharingSession sessionApi = new GeolocSharingSession(session); addGeolocSharingSession(sessionApi); // Broadcast intent related to the received invitation Intent intent = new Intent(RichCallApiIntents.GEOLOC_SHARING_INVITATION); intent.putExtra("contact", number); intent.putExtra("contactDisplayname", session.getRemoteDisplayName()); intent.putExtra("sessionId", session.getSessionID()); AndroidFactory.getApplicationContext().sendBroadcast(intent); }
/** * Get list of current image sharing sessions with a contact * * @param contact Contact * @return List of sessions * @throws ServerApiException */ public List<IBinder> getImageSharingSessionsWith(String contact) throws ServerApiException { if (logger.isActivated()) { logger.info("Get image sharing sessions with " + contact); } // Check permission ServerApiUtils.testPermission(); // Test core availability ServerApiUtils.testCore(); try { Vector<ContentSharingSession> list = Core.getInstance().getRichcallService().getCShSessions(contact); ArrayList<IBinder> result = new ArrayList<IBinder>(list.size()); for (int i = 0; i < list.size(); i++) { ContentSharingSession session = list.elementAt(i); IImageSharingSession sessionApi = imageSharingSessions.get(session.getSessionID()); if (sessionApi != null) { result.add(sessionApi.asBinder()); } } return result; } catch (Exception e) { if (logger.isActivated()) { logger.error("Unexpected error", e); } throw new ServerApiException(e.getMessage()); } }
/** * Receive a new geoloc sharing invitation * * @param session Geoloc sharing session */ public void receiveGeolocSharingInvitation(GeolocTransferSession session) { if (logger.isActivated()) { logger.info("Receive geoloc sharing invitation from " + session.getRemoteContact()); } // Extract number from contact String number = PhoneUtils.extractNumberFromUri(session.getRemoteContact()); // Add session in the list GeolocSharingImpl sessionApi = new GeolocSharingImpl(session); GeolocSharingServiceImpl.addGeolocSharingSession(sessionApi); // Broadcast intent related to the received invitation Intent intent = new Intent(GeolocSharingIntent.ACTION_NEW_INVITATION); intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES); intent.putExtra(GeolocSharingIntent.EXTRA_CONTACT, number); intent.putExtra(GeolocSharingIntent.EXTRA_DISPLAY_NAME, session.getRemoteDisplayName()); intent.putExtra(GeolocSharingIntent.EXTRA_SHARING_ID, session.getSessionID()); AndroidFactory.getApplicationContext().sendBroadcast(intent); // Notify geoloc sharing invitation listeners synchronized (lock) { final int N = listeners.beginBroadcast(); for (int i = 0; i < N; i++) { try { listeners.getBroadcastItem(i).onNewGeolocSharing(session.getSessionID()); } catch (Exception e) { if (logger.isActivated()) { logger.error("Can't notify listener", e); } } } listeners.finishBroadcast(); } }
/** * Initiate a pre-recorded video sharing session * * @param contact Remote contact * @param content Video content to share * @param player Media player * @return CSh session * @throws CoreException */ public VideoStreamingSession initiatePreRecordedVideoSharingSession( String contact, VideoContent content, IMediaPlayer player) throws CoreException { if (logger.isActivated()) { logger.info( "Initiate a pre-recorded video sharing session with contact " + contact + ", file " + content.toString()); } // Test if call is established if (!getImsModule().getCallManager().isCallConnected()) { if (logger.isActivated()) { logger.debug("Rich call not established: cancel the initiation"); } throw new CoreException("Call not established"); } // Reject if there are already 2 bidirectional sessions with a given contact boolean rejectInvitation = false; Vector<ContentSharingSession> currentSessions = getCShSessions(); if (currentSessions.size() >= 2) { // Already a bidirectional session if (logger.isActivated()) { logger.debug("Max sessions reached"); } rejectInvitation = true; } else if (currentSessions.size() == 1) { ContentSharingSession currentSession = currentSessions.elementAt(0); if (!(currentSession instanceof TerminatingVideoStreamingSession)) { // Originating session already used if (logger.isActivated()) { logger.debug("Max originating sessions reached"); } rejectInvitation = true; } else if (!PhoneUtils.compareNumbers(contact, currentSession.getRemoteContact())) { // Not the same contact if (logger.isActivated()) { logger.debug("Only bidirectional session with same contact authorized"); } rejectInvitation = true; } } if (rejectInvitation) { if (logger.isActivated()) { logger.debug("The max number of sharing sessions is achieved: cancel the initiation"); } throw new CoreException("Max content sharing sessions achieved"); } // Create a new session OriginatingPreRecordedVideoStreamingSession session = new OriginatingPreRecordedVideoStreamingSession( this, player, content, PhoneUtils.formatNumberToSipUri(contact)); // Start the session session.startSession(); return session; }
/** Close API */ public void close() { // Clear list of sessions videoSharingSessions.clear(); if (logger.isActivated()) { logger.info("Video sharing service API is closed"); } }
/** * Registers an video sharing invitation listener * * @param listener New video sharing listener * @throws ServerApiException */ public void addNewVideoSharingListener(INewVideoSharingListener listener) throws ServerApiException { if (logger.isActivated()) { logger.info("Add an video sharing invitation listener"); } listeners.register(listener); }
/** Close API */ public void close() { // Clear list of sessions gshSessions.clear(); if (logger.isActivated()) { logger.info("Geoloc sharing service API is closed"); } }
/** * Unregisters a geoloc sharing invitation listener * * @param listener New geoloc sharing listener * @throws ServerApiException */ public void removeNewGeolocSharingListener(INewGeolocSharingListener listener) throws ServerApiException { if (logger.isActivated()) { logger.info("Remove a geoloc sharing invitation listener"); } listeners.unregister(listener); }
/** Close API */ public void close() { // Clear list of sessions sipSessions.clear(); if (logger.isActivated()) { logger.info("Multimedia session service API is closed"); } }
/** * Unregisters a listener on service registration events * * @param listener Service registration listener */ public void removeServiceRegistrationListener(IJoynServiceRegistrationListener listener) { synchronized (lock) { if (logger.isActivated()) { logger.info("Remove a service listener"); } serviceListeners.unregister(listener); } }
/** * Registers a listener on service registration events * * @param listener Service registration listener */ public void addServiceRegistrationListener(IJoynServiceRegistrationListener listener) { synchronized (lock) { if (logger.isActivated()) { logger.info("Add a service listener"); } serviceListeners.register(listener); } }
/** * Receive an image sharing invitation * * @param invite Initial invite */ public void receiveImageSharingInvitation(SipRequest invite) { if (logger.isActivated()) { logger.info("Receive an image sharing session invitation"); } // Test if call is established if (!getImsModule().getCallManager().isCallConnected()) { if (logger.isActivated()) { logger.debug("Rich call not established: reject the invitation"); } sendErrorResponse(invite, 606); return; } // Reject if there are already 2 bidirectional sessions with a given contact boolean rejectInvitation = false; String contact = SipUtils.getAssertedIdentity(invite); Vector<ContentSharingSession> currentSessions = getCShSessions(); if (currentSessions.size() >= 2) { // Already a bidirectional session if (logger.isActivated()) { logger.debug("Max sessions reached"); } rejectInvitation = true; } else if (currentSessions.size() == 1) { ContentSharingSession currentSession = currentSessions.elementAt(0); if (currentSession instanceof TerminatingImageTransferSession) { // Terminating session already used if (logger.isActivated()) { logger.debug("Max terminating sessions reached"); } rejectInvitation = true; } else if (!PhoneUtils.compareNumbers(contact, currentSession.getRemoteContact())) { // Not the same contact if (logger.isActivated()) { logger.debug("Only bidirectional session with same contact authorized"); } rejectInvitation = true; } } if (rejectInvitation) { if (logger.isActivated()) { logger.debug("The max number of sharing sessions is achieved: reject the invitation"); } sendErrorResponse(invite, 486); return; } // Create a new session ImageTransferSession session = new TerminatingImageTransferSession(this, invite); // Start the session session.startSession(); // Notify listener getImsModule().getCore().getListener().handleContentSharingTransferInvitation(session); }
/** * Handle 407 Proxy Authentication Required * * @param resp 407 response */ public void handle407Authentication(SipResponse resp) { try { if (logger.isActivated()) { logger.info("407 response received"); } // Set the remote tag getDialogPath().setRemoteTag(resp.getToTag()); // Update the authentication agent getAuthenticationAgent().readProxyAuthenticateHeader(resp); // Increment the Cseq number of the dialog path getDialogPath().incrementCseq(); // Create a second INVITE request with the right token if (logger.isActivated()) { logger.info("Send second INVITE"); } SipRequest invite = SipMessageFactory.createInvite( getDialogPath(), InstantMessagingService.FT_FEATURE_TAGS, getDialogPath().getLocalContent()); // Reset initial request in the dialog path getDialogPath().setInvite(invite); // Set the Proxy-Authorization header getAuthenticationAgent().setProxyAuthorizationHeader(invite); // Send INVITE request sendInvite(invite); } catch (Exception e) { if (logger.isActivated()) { logger.error("Session initiation has failed", e); } // Unexpected error handleError(new FileSharingError(FileSharingError.UNEXPECTED_EXCEPTION, e.getMessage())); } }
/** * Is session interrupted * * @return Boolean */ public boolean isSessionInterrupted() { if (sessionInterrupted) { if (logger.isActivated()) { logger.info("ABC isSessionInterrupted1"); } } if (isInterrupted()) { if (logger.isActivated()) { logger.info("ABC isSessionInterrupted2"); } } if (getDialogPath() != null && getDialogPath().isSessionTerminated()) { if (logger.isActivated()) { logger.info("ABC isSessionInterrupted3"); } } return sessionInterrupted || isInterrupted() || (getDialogPath() != null && getDialogPath().isSessionTerminated()); }
/** * Shares a geolocation with a contact. An exception if thrown if there is no ongoing CS call. The * parameter contact supports the following formats: MSISDN in national or international format, * SIP address, SIP-URI or Tel-URI. If the format of the contact is not supported an exception is * thrown. * * @param contact Contact * @param geoloc Geolocation info * @param listener Geoloc sharing event listener * @return Geoloc sharing * @throws ServerApiException */ public IGeolocSharing shareGeoloc(String contact, Geoloc geoloc, IGeolocSharingListener listener) throws ServerApiException { if (logger.isActivated()) { logger.info("Initiate a geoloc sharing session with " + contact); } // Test IMS connection ServerApiUtils.testIms(); try { // Create a geoloc content String msgId = ChatUtils.generateMessageId(); GeolocPush geolocPush = new GeolocPush( geoloc.getLabel(), geoloc.getLatitude(), geoloc.getLongitude(), geoloc.getExpiration(), geoloc.getAccuracy()); String geolocDoc = ChatUtils.buildGeolocDocument( geolocPush, ImsModule.IMS_USER_PROFILE.getPublicUri(), msgId); MmContent content = new GeolocContent("geoloc.xml", geolocDoc.getBytes().length, geolocDoc.getBytes()); // Initiate a sharing session final GeolocTransferSession session = Core.getInstance() .getRichcallService() .initiateGeolocSharingSession(contact, content, geolocPush); // Add session listener GeolocSharingImpl sessionApi = new GeolocSharingImpl(session); sessionApi.addEventListener(listener); // Start the session Thread t = new Thread() { public void run() { session.startSession(); } }; t.start(); // Add session in the list addGeolocSharingSession(sessionApi); return sessionApi; } catch (Exception e) { if (logger.isActivated()) { logger.error("Unexpected error", e); } throw new ServerApiException(e.getMessage()); } }
/** * Shares a live video with a contact. The parameter renderer contains the video player provided * by the application. An exception if thrown if there is no ongoing CS call. The parameter * contact supports the following formats: MSISDN in national or international format, SIP * address, SIP-URI or Tel-URI. If the format of the contact is not supported an exception is * thrown. * * @param contact Contact * @param player Video player * @param listener Video sharing event listener * @return Video sharing * @throws ServerApiException */ public IVideoSharing shareVideo( String contact, IVideoPlayer player, IVideoSharingListener listener) throws ServerApiException { if (logger.isActivated()) { logger.info("Initiate a live video session with " + contact); } // Test IMS connection ServerApiUtils.testIms(); // Test if at least the audio media is configured if (player == null) { throw new ServerApiException("Missing video player"); } try { // Initiate a new session final VideoStreamingSession session = Core.getInstance().getRichcallService().initiateLiveVideoSharingSession(contact, player); // Update rich call history RichCallHistory.getInstance() .addVideoSharing( contact, session.getSessionID(), VideoSharing.Direction.OUTGOING, session.getContent(), VideoSharing.State.INITIATED); // Add session listener VideoSharingImpl sessionApi = new VideoSharingImpl(session); sessionApi.addEventListener(listener); // Start the session Thread t = new Thread() { public void run() { session.startSession(); } }; t.start(); // Add session in the list addVideoSharingSession(sessionApi); return sessionApi; } catch (Exception e) { if (logger.isActivated()) { logger.error("Unexpected error", e); } throw new ServerApiException(e.getMessage()); } }
/** * Set call hold * * @param state State * @throws ServerApiException */ public void setCallHold(boolean state) throws ServerApiException { if (logger.isActivated()) { logger.info("Set call hold to " + state); } // Check permission ServerApiUtils.testPermission(); // Test core availability ServerApiUtils.testCore(); // Update call manager Core.getInstance().getImsModule().getCallManager().setCallHold(state); }
/** * Get current geoloc sharing session from its session ID * * @param id Session ID * @return Session * @throws ServerApiException */ public IGeolocSharingSession getGeolocSharingSession(String id) throws ServerApiException { if (logger.isActivated()) { logger.info("Get geoloc sharing session " + id); } // Check permission ServerApiUtils.testPermission(); // Test core availability ServerApiUtils.testCore(); // Return a session instance return geolocSharingSessions.get(id); }