com.reactirislibrary.RNIrisSdkModule.java Source code

Java tutorial

Introduction

Here is the source code for com.reactirislibrary.RNIrisSdkModule.java

Source

// Copyright (c) 2017 Comcast

// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

package com.reactirislibrary;

import com.comcast.irisrtcsdk.IrisRtcSdk.Smack.Listener.IrisChatMessage;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.modules.core.DeviceEventManagerModule;

import android.content.Intent;
import android.support.annotation.Nullable;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;

import org.json.JSONObject;
import org.webrtc.EglBase;

import com.comcast.irisrtcsdk.*;
import com.comcast.irisrtcsdk.IrisRtcSdk.*;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

public class RNIrisSdkModule extends ReactContextBaseJavaModule
        implements IrisRtcConnection.IrisRtcConnectionObserver, IrisRtcStream.IrisRtcStreamObserver,
        IrisRtcAudioSession.IrisRtcAudioSessionObserver, IrisRtcSession.IrisRtcSessionObserver,
        IrisRtcVideoSession.IrisRtcVideoSessionObserver, IrisRtcChatSession.IrisRtcChatSessionObserver {

    private final ReactApplicationContext reactContext;
    private static final String TAG_RNIRISSDK = "React--IrisRtcSdk";

    // Constant string for sending events
    private static final String IrisEventOnConnected = "onConnected";
    private static final String IrisEventOnDisconnected = "onDisconnected";
    private static final String IrisEventOnConnectionError = "onConnectionError";
    private static final String IrisEventOnNotification = "onNotification";

    // Audio Session events
    private static final String IrisEventOnSessionCreated = "onSessionCreated";
    private static final String IrisEventOnSessionJoined = "onSessionJoined";

    private static final String IrisEventOnSessionConnected = "onSessionConnected";
    private static final String IrisEventOnSessionDisconnected = "onSessionDisconnected";
    private static final String IrisEventOnSessionSIPStatus = "onSessionSIPStatus";
    private static final String IrisEventOnSessionError = "onSessionError";

    private static final String IrisEventOnChatMessage = "onChatMessage";
    private static final String IrisEventOnChatMessageAck = "onChatMessageAck";
    private static final String IrisEventOnChatMessageState = "onChatMessageState";
    private static final String IrisEventOnChatMessageError = "onChatMessageError";

    // Video Session events
    private static final String IrisEventOnSessionParticipantJoined = "onSessionParticipantJoined";
    private static final String IrisEventOnSessionParticipantLeft = "onSessionParticipantLeft";
    private static final String IrisEventOnSessionTypeChanged = "onSessionTypeChanged";
    private static final String IrisEventOnSessionParticipantConnected = "onSessionParticipantConnected";
    private static final String IrisEventOnSessionDominantSpeakerChanged = "onSessionDominantSpeakerChanged";
    private static final String IrisEventOnSessionRemoteParticipantActivated = "onSessionRemoteParticipantActivated";
    private static final String IrisEventOnSessionParticipantVideoMuted = "onSessionParticipantVideoMuted";
    private static final String IrisEventOnSessionParticipantAudioMuted = "onSessionParticipantAudioMuted";
    private static final String IrisEventOnSessionParticipantProfile = "onSessionParticipantProfile";
    private static final String IrisEventOnSessionParticipantNotResponding = "onSessionParticipantNotResponding";

    // Video Stream events
    private static final String IrisEventOnStreamError = "onStreamError";
    private static final String IrisEventOnLocalStream = "onLocalStream";
    private static final String IrisEventOnRemoteAddStream = "onRemoteAddStream";
    private static final String IrisEventOnRemoteRemoveStream = "onRemoteRemoveStream";

    // Local variables
    private IrisRtcStream audioStream;
    private IrisRtcStream videoStream;
    private static EglBase rootEglBase;
    private Map<String, IrisRtcAudioSession> audioSessionArray = new HashMap<String, IrisRtcAudioSession>();
    private Map<String, IrisRtcChatSession> chatSessionArray = new HashMap<String, IrisRtcChatSession>();
    private Map<String, IrisRtcSession> sessionArray = new HashMap<String, IrisRtcSession>();
    private Map<String, IrisRtcVideoSession> videoSessionArray = new HashMap<String, IrisRtcVideoSession>();
    private String localStreamId;

    public RNIrisSdkModule(ReactApplicationContext reactContext) {
        super(reactContext);
        this.reactContext = reactContext;
        rootEglBase = EglBase.create();
    }

    @Override
    public String getName() {
        return "IrisRtcSdk";
    }

    /**
     * Private method to send an event
     *
     * @param eventName name of the event
     * @param params    event parameters
     */
    private void sendEvent(String eventName, @Nullable WritableMap params) {
        this.reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit(eventName, params);
    }

    /**
     * To get the EGL base
     *
     * @return egl base
     */
    public static EglBase getEglBase() {
        return rootEglBase;
    }

    /**
     * Create the websocket connection with XMPP server
     *
     * @param mucId      The event manager URL
     * @param timeStamp  Timestamp when token was created
     * @param xmppToken  Xmpp token as retrieved from register call.
     * @param xmppServer Xmpp server name
     */
    @ReactMethod
    public void connectUsingServer(String serverUrl, String irisToken, String routingId) {

        Log.i(TAG_RNIRISSDK, " Calling connectUsingServer with " + serverUrl + " routingId " + routingId);
        if (IrisRtcConnection.getInstance()
                .getState() != IrisRtcConnection.IrisRtcConnectionState.kConnectionStateDisconnected) {
            IrisRtcConnection.getInstance().disconnect();
        }

        try {
            IrisRtcConnection.getInstance().connect(serverUrl, irisToken, routingId, this);
        } catch (IrisRtcSDKException e) {
            e.printStackTrace();
        }

    }

    /**
     * Observer invoked when the rtc connection is done
     */
    @Override
    public void onConnected() {
        Log.i(TAG_RNIRISSDK, " IrisRtcConnection -- onConnected ");
        this.sendEvent(IrisEventOnConnected, null);
    }

    /**
     * Observer invoked when the rtc connection is disconnected
     */
    @Override
    public void onDisconnect() {
        Log.i(TAG_RNIRISSDK, " IrisRtcConnection -- onDisconnect ");
        this.sendEvent(IrisEventOnDisconnected, null);
    }

    /**
     * Observer invoked when there is an error during the connection
     */
    @Override
    public void onError(WebRTCError.ErrorCode error, JSONObject additionalInfo) {
        Log.i(TAG_RNIRISSDK, " IrisRtcConnection -- onError with error " + error.getValue() + " - "
                + error.getErorDescription());

        WritableMap event = Arguments.createMap();
        event.putString("Details", additionalInfo.toString());
        event.putInt("ErrorCode", error.getValue());
        event.putString("Error", error.getErorDescription());

        this.sendEvent(IrisEventOnConnectionError, event);
    }

    /**
     * Observer invoked when there is a notification
     */
    @Override
    public void onNotification(IrisRtcConnection.IrisNotificationPayload irisNotificationPayload) {
        WritableMap event = Arguments.createMap();

        //this.sendEvent(IrisEventOnNotification, null);
    }

    /**
     * This method is called to create a audio stream
     */
    @ReactMethod
    public void createAudioStream() {

        Log.i(TAG_RNIRISSDK, " Calling createAudioStream ");

        // Check if the stream is already created
        if (audioStream == null) {
            audioStream = new IrisRtcStream(IrisRtcStream.IrisRtcSdkStreamType.kStreamTypeAudio,
                    IrisRtcStream.IrisRtcSdkStreamQuality.kStreamQuality_FullHD,
                    IrisRtcStream.IrisRtcCameraType.kCameraTypeFront, this,
                    this.reactContext.getApplicationContext());
        } else {
            Log.w(TAG_RNIRISSDK, " Audio stream is already created !!! ");
        }
    }

    /**
     * This method is called to create a video stream
     */
    @ReactMethod
    public void createVideoStream(boolean useBackCamera, boolean useHD) {

        Log.i(TAG_RNIRISSDK,
                " createVideoStream called with " + "useBackCamera:" + useBackCamera + "useHD:" + useHD);

        // Check if the stream is already created
        if (videoStream == null) {
            IrisRtcStream.IrisRtcSdkStreamQuality quality = useHD
                    ? IrisRtcStream.IrisRtcSdkStreamQuality.kStreamQuality_FullHD
                    : IrisRtcStream.IrisRtcSdkStreamQuality.kStreamQuality_VGA;
            IrisRtcStream.IrisRtcCameraType type = useBackCamera ? IrisRtcStream.IrisRtcCameraType.kCameraTypeBack
                    : IrisRtcStream.IrisRtcCameraType.kCameraTypeFront;

            videoStream = new IrisRtcStream(IrisRtcStream.IrisRtcSdkStreamType.kStreamTypeVideo, quality, type,
                    this, this.reactContext.getApplicationContext());
            videoStream.startPreview(rootEglBase.getEglBaseContext()); // To get the EGL base context from renderers
        } else {
            Log.w(TAG_RNIRISSDK, " Video stream is already created !!! ");
        }
    }

    /**
     * This method is called to start a local preview
     */
    @ReactMethod
    public void startPreview() {

        Log.i(TAG_RNIRISSDK, " startPreview called ");

        // Check if the stream is already created
        if (videoStream != null) {
            videoStream.startPreview(rootEglBase.getEglBaseContext()); // To get the EGL base context from renderers
        }
    }

    /**
     * This method is called to stop a local preview
     */
    @ReactMethod
    public void stopPreview() {

        Log.i(TAG_RNIRISSDK, " stopPreview called ");

        // Check if the stream is already created
        if (videoStream != null) {
            videoStream.stopPreview();
        }
    }

    /**
     * This method is called to close the stream
     */
    @ReactMethod
    public void closeStream() {

        Log.i(TAG_RNIRISSDK, " closeStream called ");

        // Check if the stream is already created
        if (videoStream != null) {
            videoStream.stopPreview();
            videoStream.close();
        }

        // Code to propagate that a local stream is closed
        if (localStreamId != null) {
            // Send a notification to delete the renderer/videoview
            Intent intent = new Intent("onTrackDeleted");
            intent.putExtra("TrackId", localStreamId);
            LocalBroadcastManager.getInstance(reactContext).sendBroadcast(intent);
        }
    }

    /**
     * This method is called to mute audio
     */
    @ReactMethod
    public void mute() {

        Log.i(TAG_RNIRISSDK, " mute called ");

        // Check if the stream is already created
        if (videoStream != null) {
            videoStream.mute();
        }
    }

    /**
     * This method is called to unmute audio
     */
    @ReactMethod
    public void unmute() {

        Log.i(TAG_RNIRISSDK, " unmute called ");

        // Check if the stream is already created
        if (videoStream != null) {
            videoStream.unmute();
        }
    }

    /**
     * This method is called to flip camera
     */
    @ReactMethod
    public void flip() {

        Log.i(TAG_RNIRISSDK, " flip called ");

        // Check if the stream is already created
        if (videoStream != null) {
            videoStream.flip();
        }
    }

    /**
     * Callback: This is called when the local preview is available.
     *
     * @param mediaTrack media track that is associated with camera instance.
     */
    @Override
    public void onLocalStream(IrisRtcMediaTrack mediaTrack) {
        Log.i(TAG_RNIRISSDK, " onLocalStream ");

        // Create a unique id for track
        String uuid = UUID.randomUUID().toString();

        // Add track
        RNIrisSdkStreamManager.getInstance().addTrack(mediaTrack, uuid);

        WritableMap event = Arguments.createMap();
        event.putString("StreamId", uuid);

        this.sendEvent(IrisEventOnLocalStream, event);

        localStreamId = uuid;

    }

    /**
     * Callback: This is called when there in an error during camera capture processs.
     *
     * @param errorCode      The basic error code details
     * @param additionalData Additional error details including description
     */
    @Override
    public void onStreamError(WebRTCError.ErrorCode errorCode, JSONObject additionalData) {
        Log.i(TAG_RNIRISSDK, " onStreamError ");
        WritableMap event = Arguments.createMap();
        event.putString("description", errorCode.getErorDescription());
        event.putString("value", String.valueOf(errorCode.getValue()));

        this.sendEvent(IrisEventOnStreamError, event);
    }

    /**
     * To create audio session
     *
     * @param roomId           Room id
     * @param participantId    Participant id
     * @param sourceTN         Source TN
     * @param targetTN         Target TN
     * @param notificationData Notification data
     */
    @ReactMethod
    public void createAudioSession(String roomId, String participantId, String sourceTN, String targetTN,
            String notificationData) {
        Log.i(TAG_RNIRISSDK, " createAudioSession called with " + roomId + ":" + participantId + ":" + sourceTN
                + ":" + targetTN + ":" + notificationData);

        // Call createaudiostream() just in case audio stream is not already created
        createAudioStream();

        // Create the audio session
        IrisRtcAudioSession mSession = new IrisRtcAudioSession(reactContext);

        // Set the session properties
        mSession.isVideoBridge = true;

        // Create the actual session
        try {
            mSession.create(roomId, participantId, sourceTN, targetTN, notificationData, audioStream, this);
        } catch (IrisRtcSDKException e) {
            Log.e(TAG_RNIRISSDK, e.getStackTrace().toString());
        }
    }

    /**
     * This method is called to join pstn/audio session which involves joining the room using the room id recieved in notification.
     *
     * @param roomId          room name that needs to be joined which is recieved in notification.
     * @param roomToken       Room token as available in notification
     * @param roomTokenExpiry Token expiry time
     * @param rtcServer       Rtc server as available in the notification
     */
    @ReactMethod
    public void joinAudioSession(String roomId, String roomToken, int roomTokenExpiry, String rtcServer) {
        Log.i(TAG_RNIRISSDK, " joinAudioSession called with " + roomId + ":" + roomToken + ":" + roomTokenExpiry
                + ":" + rtcServer);

        // Call createaudiostream() just in case audio stream is not already created
        createAudioStream();

        // Create the audio session
        IrisRtcAudioSession mSession = new IrisRtcAudioSession(reactContext);

        // Set the session properties
        mSession.isVideoBridge = true;

        // Join the actual session
        try {
            mSession.join(roomId, roomToken, String.valueOf(roomTokenExpiry), audioStream, rtcServer, this);
        } catch (IrisRtcSDKException e) {
            Log.e(TAG_RNIRISSDK, e.getStackTrace().toString());
        }
        audioSessionArray.put(roomId, mSession);
    }

    /**
     * To hold a session
     *
     * @param sessionId Session id
     */
    @ReactMethod
    public void hold(String sessionId) {
        Log.i(TAG_RNIRISSDK, " hold called with " + sessionId);

        // Check if we have this key
        if (audioSessionArray.containsKey(sessionId)) {
            IrisRtcAudioSession mSession = audioSessionArray.get(sessionId);
            mSession.hold();
        }
    }

    /**
     * To unhold a session
     *
     * @param sessionId Session id
     */
    @ReactMethod
    public void unhold(String sessionId) {
        Log.i(TAG_RNIRISSDK, " unhold called with " + sessionId);

        // Check if we have this key
        if (audioSessionArray.containsKey(sessionId)) {
            IrisRtcAudioSession mSession = audioSessionArray.get(sessionId);
            mSession.unhold();
        }
    }

    /**
     * To merge the call
     *
     * @param sessionId Session id
     */
    @ReactMethod
    public void mergeCall(String sessionId, String sessionToBeMerged) {
        Log.i(TAG_RNIRISSDK, " mergeCall called with " + sessionId + ":" + sessionToBeMerged);

        // Check if we have this key
        if (audioSessionArray.containsKey(sessionId) && audioSessionArray.containsKey(sessionToBeMerged)) {
            IrisRtcAudioSession mSession = audioSessionArray.get(sessionId);
            mSession.mergeSession(audioSessionArray.get(sessionToBeMerged));
        }
    }

    /**
     * This method is used for sending dtmf tones.
     *
     * @param sessionId Session Identifier
     * @param tone      Tone to be sent
     */
    @ReactMethod
    public void sendDTMF(String sessionId, String tone) {
        Log.i(TAG_RNIRISSDK, " sendDTMF called with " + sessionId + ":" + tone);

        // Check if we have this key
        if (audioSessionArray.containsKey(sessionId)) {
            IrisRtcAudioSession mSession = audioSessionArray.get(sessionId);
            mSession.inserDTMFTone(tone);
        }
    }

    /**
     * This method is called to close the session
     *
     * @param sessionId Session Identifier
     */
    @ReactMethod
    public void endAudioSession(String sessionId) {
        Log.i(TAG_RNIRISSDK, " endAudioSession called with " + sessionId);

        // Check if we have this key
        if (audioSessionArray.containsKey(sessionId)) {
            IrisRtcAudioSession mSession = audioSessionArray.get(sessionId);
            mSession.close();
            audioSessionArray.remove(mSession);
        }
    }

    /**
     * To create a session
     * @param roomId Room Id
     * @param sessionConfig Session Config
     */
    @ReactMethod
    public void createSession(String roomId, ReadableMap sessionConfig) {
        Log.i(TAG_RNIRISSDK, " createSession called with " + roomId);

        // Check the room id
        if (sessionArray.containsKey(roomId)) {
            Log.e(TAG_RNIRISSDK, "A  session with RoomId " + roomId + " is already created");
            return;
        }

        // Get the notification data
        String notificationData = sessionConfig.getString("notificationData");
        IrisRtcSession mSession = new IrisRtcSession(reactContext);
        mSession.isVideoBridge = true;

        // Create the session
        try {
            mSession.create(roomId, notificationData, this);
            sessionArray.put(roomId, mSession);
        } catch (IrisRtcSDKException e) {
            Log.e(TAG_RNIRISSDK, e.getStackTrace().toString());
        }
    }

    /**
     * To join a session
     * @param roomId
     * @param sessionConfig
     */
    @ReactMethod
    public void joinSession(String roomId, ReadableMap sessionConfig) {
        Log.i(TAG_RNIRISSDK, " joinSession called with " + roomId);

        // Check the room id
        if (sessionArray.containsKey(roomId)) {
            Log.e(TAG_RNIRISSDK, "A  session with RoomId " + roomId + " is already created");
            return;
        }

        // Check the parameters
        if (sessionConfig.getString("roomToken") == null || sessionConfig.getString("roomTokenExpiry") == null
                || sessionConfig.getString("rtcServer") == null) {
            WritableMap event = Arguments.createMap();
            event.putString("description",
                    "React::IrisRtcSdk Missing mandatory parameters, check whether you have passed roomToken, roomTokenExpiry and rtcServer !!!");
            event.putInt("code ", -1); // To match with ios : TBD

            this.sendEvent(IrisEventOnSessionError, event);
            return;
        }

        // Get the notification data
        String notificationData = sessionConfig.getString("notificationData");
        IrisRtcSession mSession = new IrisRtcSession(reactContext);
        mSession.isVideoBridge = true;

        // Join the session
        try {
            mSession.join(roomId, sessionConfig.getString("roomToken"), sessionConfig.getString("roomTokenExpiry"),
                    videoStream, sessionConfig.getString("rtcServer"), this);
            sessionArray.put(roomId, mSession);
        } catch (IrisRtcSDKException e) {
            Log.e(TAG_RNIRISSDK, e.getStackTrace().toString());
        }

    }

    /**
     * This method is called to upgrade to video session from chat.
     * @param sessionId : Session Id
     * @param sessionConfig : Config
     */
    @ReactMethod
    public void upgradeToVideo(String sessionId, ReadableMap sessionConfig) {
        Log.i(TAG_RNIRISSDK, " upgradeToVideo called with " + sessionId);

        // Check the room id
        if (!sessionArray.containsKey(sessionId)) {
            Log.e(TAG_RNIRISSDK, "A  session with RoomId " + sessionId + " is not created yet");
            return;
        }
        IrisRtcSession mSession = sessionArray.get(sessionId);
        mSession.upgradeToVideo(sessionConfig.getString("notificationData"), videoStream);
    }

    /**
     * This method is called to downgrade from video session to chat.
     * @param sessionId
     */
    @ReactMethod
    public void downgradeToChat(String sessionId) {
        Log.i(TAG_RNIRISSDK, " downgradeToChat called with " + sessionId);

        // Check the room id
        if (!sessionArray.containsKey(sessionId)) {
            Log.e(TAG_RNIRISSDK, "A  session with RoomId " + sessionId + " is not created yet");
            return;
        }
        IrisRtcSession mSession = sessionArray.get(sessionId);
        mSession.downgradeToChat();

        // Send a notification to delete the renderer/videoview
        Intent intent = new Intent("onAllTracksDeleted");
        LocalBroadcastManager.getInstance(reactContext).sendBroadcast(intent);
    }

    /**
     * To end the session
     * @param sessionId Session Id
     */
    @ReactMethod
    public void endSession(String sessionId) {
        Log.i(TAG_RNIRISSDK, " endSession called with " + sessionId);

        // Check the room id
        if (!sessionArray.containsKey(sessionId)) {
            Log.e(TAG_RNIRISSDK, "A  session with RoomId " + sessionId + " is not created yet");
            return;
        }

        IrisRtcSession mSession = sessionArray.get(sessionId);
        mSession.closeSession();
        sessionArray.remove(mSession);

        // TBD: Broadcast a notification to delete the renderers
        // Send a notification to delete the renderer/videoview
        Intent intent = new Intent("onAllTracksDeleted");
        LocalBroadcastManager.getInstance(reactContext).sendBroadcast(intent);
    }

    /**
     * To create a session
     * @param roomId Room Id
     * @param sessionConfig Session Config
     */
    @ReactMethod
    public void createVideoSession(String roomId, ReadableMap sessionConfig) {
        Log.i(TAG_RNIRISSDK, " createVideoSession called with " + roomId);

        // Check the room id
        if (videoSessionArray.containsKey(roomId)) {
            Log.e(TAG_RNIRISSDK, "A  session with RoomId " + roomId + " is already created");
            return;
        }

        // Init the session
        IrisRtcVideoSession mSession = new IrisRtcVideoSession(reactContext);
        mSession.isVideoBridge = true;

        // Create the session
        try {
            mSession.create(roomId, sessionConfig.getString("notificationData"), videoStream, this);
            videoSessionArray.put(roomId, mSession);
        } catch (IrisRtcSDKException e) {
            Log.e(TAG_RNIRISSDK, e.getStackTrace().toString());
        }
    }

    /**
     * To join a session
     * @param roomId Room Id
     * @param sessionConfig Session Config
     */
    @ReactMethod
    public void joinVideoSession(String roomId, ReadableMap sessionConfig) {
        Log.i(TAG_RNIRISSDK, " joinVideoSession called with " + roomId);

        // Check the room id
        if (videoSessionArray.containsKey(roomId)) {
            Log.e(TAG_RNIRISSDK, "A  session with RoomId " + roomId + " is already created");
            return;
        }

        // Check the parameters
        if (sessionConfig.getString("roomToken") == null || sessionConfig.getString("roomTokenExpiry") == null
                || sessionConfig.getString("rtcServer") == null) {
            WritableMap event = Arguments.createMap();
            event.putString("description",
                    "React::IrisRtcSdk Missing mandatory parameters, check whether you have passed roomToken, roomTokenExpiry and rtcServer !!!");
            event.putInt("code ", -1); // To match with ios : TBD

            this.sendEvent(IrisEventOnSessionError, event);
            return;
        }

        // Get the notification data
        IrisRtcVideoSession mSession = new IrisRtcVideoSession(reactContext);
        mSession.isVideoBridge = true;

        // Join the session
        try {
            mSession.join(roomId, sessionConfig.getString("roomToken"), sessionConfig.getString("roomTokenExpiry"),
                    videoStream, sessionConfig.getString("rtcServer"), this);
            videoSessionArray.put(roomId, mSession);
        } catch (IrisRtcSDKException e) {
            Log.e(TAG_RNIRISSDK, e.getStackTrace().toString());
        }
    }

    /**
     * To end a video session
     * @param roomId Room Id
     */
    @ReactMethod
    public void endVideoSession(String roomId) {
        Log.i(TAG_RNIRISSDK, " endVideoSession called with " + roomId);

        // Check the room id
        if (!videoSessionArray.containsKey(roomId)) {
            Log.e(TAG_RNIRISSDK, "A  session with RoomId " + roomId + " is not created yet");
            return;
        }

        // Get the video session
        IrisRtcVideoSession mSession = videoSessionArray.get(roomId);
        mSession.closeSession();
        videoSessionArray.remove(mSession);

        // TBD: Broadcast a notification to delete the renderers
        // Send a notification to delete the renderer/videoview
        Intent intent = new Intent("onAllTracksDeleted");
        LocalBroadcastManager.getInstance(reactContext).sendBroadcast(intent);
    }

    /**
     * To create a chat session
     * @param roomId Room Id
     * @param name Name
     */
    @ReactMethod
    public void createChatSession(String roomId, String name) {
        Log.i(TAG_RNIRISSDK, " createChatSession called with " + roomId + ":" + name);

        // Check the room id
        if (chatSessionArray.containsKey(roomId)) {
            Log.e(TAG_RNIRISSDK, "A  session with RoomId " + roomId + " is already created");
            return;
        }

        // Init the session
        IrisRtcChatSession mSession = new IrisRtcChatSession(reactContext);
        mSession.isVideoBridge = true;

        // Create the session
        try {
            mSession.create(roomId, "", this);
            chatSessionArray.put(roomId, mSession);

            // TBD profile
        } catch (IrisRtcSDKException e) {
            Log.e(TAG_RNIRISSDK, e.getStackTrace().toString());
        }
    }

    /**
     * To end a chat session
     * @param roomId Room Id
     */
    @ReactMethod
    public void endChatSession(String roomId) {
        Log.i(TAG_RNIRISSDK, " endChatSession called with " + roomId);

        // Check the room id
        if (!chatSessionArray.containsKey(roomId)) {
            Log.e(TAG_RNIRISSDK, "A  session with RoomId " + roomId + " is not found");
            return;
        }

        // Init the session
        IrisRtcChatSession mSession = chatSessionArray.get(roomId);
        mSession.close();
    }

    /**
     * To send a chat message
     * @param roomId Room Id
     */
    @ReactMethod
    public void sendChatMessage(String roomId, String message, String id) {
        Log.i(TAG_RNIRISSDK, " sendChatMessage called with " + roomId + ":" + message + ":" + id);

        // Check the room id
        if (chatSessionArray.containsKey(roomId)) {
            Log.e(TAG_RNIRISSDK, " Sending message through chatsession ");
            // Init the session
            IrisRtcChatSession mSession = chatSessionArray.get(roomId);
            IrisChatMessage mMessage = new IrisChatMessage(message, id);
            mSession.sendChatMessage(mMessage);
        }
        // Check the room id
        if (videoSessionArray.containsKey(roomId)) {
            Log.e(TAG_RNIRISSDK, " Sending message through videosession ");
            // Init the session
            IrisRtcVideoSession mSession = videoSessionArray.get(roomId);
            IrisChatMessage mMessage = new IrisChatMessage(message, id);
            mSession.sendChatMessage(mMessage);
        }
        // Check the room id
        if (sessionArray.containsKey(roomId)) {
            Log.e(TAG_RNIRISSDK, " Sending message through video+chat session ");
            // Init the session
            IrisRtcSession mSession = sessionArray.get(roomId);
            IrisChatMessage mMessage = new IrisChatMessage(message, id);
            mSession.sendChatMessage(mMessage);
        }
    }

    /**
     * To send chat state
     * @param roomId Room id
     * @param state chat state
     */
    @ReactMethod
    public void sendChatState(String roomId, String state) {
        Log.i(TAG_RNIRISSDK, " sendChatState called with " + roomId + ":" + state);

        // Check the room id
        if (!chatSessionArray.containsKey(roomId)) {
            Log.e(TAG_RNIRISSDK, "A  session with RoomId " + roomId + " is not found");
            return;
        }

        // Init the session
        IrisRtcChatSession mSession = chatSessionArray.get(roomId);
        IrisChatState chatstate;

        // Check chat state
        if (state == "composing") {
            chatstate = IrisChatState.COMPOSING;
        } else if (state == "inactive") {
            chatstate = IrisChatState.INACTIVE;
        } else if (state == "paused") {
            chatstate = IrisChatState.PAUSED;
        } else if (state == "gone") {
            chatstate = IrisChatState.GONE;
        } else if (state == "active") {
            chatstate = IrisChatState.ACTIVE;
        } else {
            Log.e(TAG_RNIRISSDK, " Invalid state ");
            return;
        }

        // Send chat state
        mSession.sendChatState(chatstate);
    }

    /**
     * Callback: This is called to notify SIP status during session.
     *
     * @param status Iris sip status
     * @param roomId
     */
    @Override
    public void onSessionSIPStatus(IrisRtcAudioSession.IrisSIPStatus status, String roomId) {
        Log.i(TAG_RNIRISSDK, " onSessionSIPStatus called with " + String.valueOf(status));

        WritableMap event = Arguments.createMap();
        event.putString("SessionId", roomId);

        int mStatus = 0;
        switch (status) {
        case kInitializing:
            mStatus = 0;
            break;
        case kConnecting:
            mStatus = 1;
            break;
        case kConnected:
            mStatus = 2;
            break;
        case kDisconnected:
            mStatus = 3;
            break;
        }
        event.putInt("status", mStatus);
        this.sendEvent(IrisEventOnSessionSIPStatus, event);
    }

    /**
     * Callback: This is called when merging of active session with the held session for PSTN call.
     *
     * @param roomId room id recieved from Iris backend.
     */
    @Override
    public void onSessionMerged(String roomId) {
        Log.i(TAG_RNIRISSDK, " onSessionMerged called with " + roomId);

    }

    /**
     * Callback: This is called when the Ice connection state that is,session is connected.
     *
     * @param roomId room id.
     */
    @Override
    public void onSessionConnected(String roomId) {
        Log.i(TAG_RNIRISSDK, " onSessionConnected called with " + roomId);

        WritableMap event = Arguments.createMap();
        event.putString("SessionId", roomId);

        this.sendEvent(IrisEventOnSessionConnected, event);
    }

    /**
     * Callback: This is called when dominant speaker is changed in multiple stream.
     *
     * @param participantId participant id.
     * @param roomId        room id.
     */
    @Override
    public void onSessionDominantSpeakerChanged(String participantId, String roomId) {
        Log.i(TAG_RNIRISSDK, " onSessionDominantSpeakerChanged called with " + participantId + ":" + roomId);

        WritableMap event = Arguments.createMap();
        event.putString("SessionId", roomId);
        event.putString("RoutingId", participantId);

        this.sendEvent(IrisEventOnSessionDominantSpeakerChanged, event);
    }

    /**
     * Callback: This is called when stream of particular participant is activated/viewed in multiple stream.
     *
     * @param participantId participant id.
     * @param roomId        room id.
     */
    @Override
    public void onSessionRemoteParticipantActivated(String participantId, String roomId) {
        Log.i(TAG_RNIRISSDK, " onSessionRemoteParticipantActivated called with " + participantId + ":" + roomId);

        WritableMap event = Arguments.createMap();
        event.putString("SessionId", roomId);
        event.putString("RoutingId", participantId);

        this.sendEvent(IrisEventOnSessionRemoteParticipantActivated, event);
    }

    /**
     * Callback: This is called when video of remote participant muted or unmuted.
     *
     * @param mute          video state mute or unmute.
     * @param participantId participant id.
     * @param roomId        room id.
     */
    @Override
    public void onSessionParticipantVideoMuted(boolean mute, String participantId, String roomId) {
        Log.i(TAG_RNIRISSDK, " onSessionParticipantVideoMuted called with " + participantId + ":" + roomId);

        WritableMap event = Arguments.createMap();
        event.putString("SessionId", roomId);
        event.putString("RoutingId", participantId);
        event.putBoolean("Mute", mute);

        this.sendEvent(IrisEventOnSessionParticipantVideoMuted, event);
    }

    /**
     * Callback: This is called when audio of remote participant muted or unmuted.
     *
     * @param mute          audio state mute or unmute.
     * @param participantId paritcipant id.
     * @param roomId        room id.
     */
    @Override
    public void onSessionParticipantAudioMuted(boolean mute, String participantId, String roomId) {
        Log.i(TAG_RNIRISSDK, " onSessionParticipantAudioMuted called with " + participantId + ":" + roomId);

        WritableMap event = Arguments.createMap();
        event.putString("SessionId", roomId);
        event.putString("RoutingId", participantId);
        event.putBoolean("Mute", mute);

        this.sendEvent(IrisEventOnSessionParticipantAudioMuted, event);
    }

    /**
     * Callback: This is called when the room is created successfully.
     *
     * @param roomId room id.
     */
    @Override
    public void onSessionCreated(String roomId) {
        Log.i(TAG_RNIRISSDK, " onSessionCreated called with " + roomId);

        WritableMap event = Arguments.createMap();
        event.putString("SessionId", roomId);

        this.sendEvent(IrisEventOnSessionCreated, event);
    }

    /**
     * Callback: This is called when the room is joined successfully from Initiator.
     *
     * @param roomId room id.
     */
    @Override
    public void onSessionJoined(String roomId) {
        Log.i(TAG_RNIRISSDK, " onSessionJoined called with " + roomId);

        WritableMap event = Arguments.createMap();
        event.putString("SessionId", roomId);

        this.sendEvent(IrisEventOnSessionJoined, event);
    }

    /**
     * Callback: This is called at the sender side when the remote participant joins the room.
     *
     * @param participantId remote participant Id.
     * @param roomId        room id.
     */
    @Override
    public void onSessionParticipantJoined(String participantId, String roomId) {
        Log.i(TAG_RNIRISSDK, " onSessionParticipantJoined called with " + participantId + ":" + roomId);

        WritableMap event = Arguments.createMap();
        event.putString("SessionId", roomId);
        event.putString("RoutingId", participantId);

        this.sendEvent(IrisEventOnSessionParticipantJoined, event);
    }

    /**
     * Callback: This is called when the session ends.
     *
     * @param roomId room id.
     */
    @Override
    public void onSessionEnded(String roomId) {
        Log.i(TAG_RNIRISSDK, " onSessionEnded called with " + roomId);

        WritableMap event = Arguments.createMap();
        event.putString("SessionId", roomId);

        this.sendEvent(IrisEventOnSessionDisconnected, event);
    }

    /**
     * Callback: This is called when the participant leaves the room.
     *
     * @param participantId Id of the participant who left the room .
     * @param roomId        room id.
     */
    @Override
    public void onSessionParticipantLeft(String participantId, String roomId) {
        Log.i(TAG_RNIRISSDK, " onSessionParticipantLeft called with " + participantId + ":" + roomId);

        WritableMap event = Arguments.createMap();
        event.putString("SessionId", roomId);
        event.putString("RoutingId", participantId);

        this.sendEvent(IrisEventOnSessionParticipantLeft, event);
    }

    /**
     * Callback: This is called when there is error while the session is active.
     *
     * @param error          The basic error code details.
     * @param additionalInfo Additional error details including description.
     * @param roomId         room id.
     */
    @Override
    public void onSessionError(WebRTCError.ErrorCode error, JSONObject additionalInfo, String roomId) {
        Log.i(TAG_RNIRISSDK, " onSessionError called with " + error.getErorDescription() + ":" + roomId);

        WritableMap event = Arguments.createMap();
        event.putString("SessionId", roomId);
        event.putString("description", error.getErorDescription());
        event.putInt("value", error.getValue());

        this.sendEvent(IrisEventOnSessionError, event);
    }

    /**
     * Callback: This is called when there is any message is to be convey to the app.
     *
     * @param log    message to the app.
     * @param roomId room id.
     */
    @Override
    public void onLogAnalytics(String log, String roomId) {
        Log.i(TAG_RNIRISSDK, " onLogAnalytics called with " + roomId + ":" + log);
    }

    /**
     * Callback: This is called when participant profile is received.
     *
     * @param userProfile   IrisRtcUserProfile instance
     * @param participantId id of participant
     * @param roomId        room id.
     */
    @Override
    public void onSessionParticipantProfile(IrisRtcUserProfile userProfile, String participantId, String roomId) {
        Log.i(TAG_RNIRISSDK, " onSessionParticipantProfile called with " + participantId + ":" + roomId + ":"
                + userProfile.getName() + ":" + userProfile.getAvatarUrl());

        WritableMap event = Arguments.createMap();
        event.putString("SessionId", roomId);
        event.putString("RoutingId", participantId);
        event.putString("Name", userProfile.getName());
        event.putString("AvatarUrl", userProfile.getAvatarUrl());

        this.sendEvent(IrisEventOnSessionParticipantProfile, event);
    }

    /**
     * Callback: This is called when remote participant is not responding.
     *
     * @param participantId paritcipant id.
     * @param roomId        room id.
     */
    @Override
    public void onSessionParticipantNotResponding(String participantId, String roomId) {
        Log.i(TAG_RNIRISSDK, " onSessionParticipantNotResponding called with " + participantId + ":" + roomId);

        WritableMap event = Arguments.createMap();
        event.putString("SessionId", roomId);
        event.putString("RoutingId", participantId);

        this.sendEvent(IrisEventOnSessionParticipantNotResponding, event);
    }

    /**
     * Callback: This is called when session type is changed by upgrading to video/downgrading to chat.
     *
     * @param sessionType   changed session type.
     * @param participantId id of participant.
     * @param roomId        room id.
     */
    @Override
    public void onSessionTypeChanged(String sessionType, String participantId, String roomId) {
        Log.i(TAG_RNIRISSDK,
                " onSessionTypeChanged called with " + sessionType + ":" + participantId + ":" + roomId);

        WritableMap event = Arguments.createMap();
        event.putString("SessionId", roomId);
        event.putString("RoutingId", participantId);
        event.putString("SessionType", sessionType);

        this.sendEvent(IrisEventOnSessionTypeChanged, event);
    }

    /**
     * Callback: This is called when the remote stream is added to peerconnection.
     *
     * @param mediaTrack    IrisRtcMediaTrack containing remote track.
     * @param participantId Participant Id.
     * @param roomId        Room Id.
     */
    @Override
    public void onAddRemoteStream(IrisRtcMediaTrack mediaTrack, String participantId, String roomId) {
        Log.i(TAG_RNIRISSDK, " onAddRemoteStream called with " + participantId + ":" + roomId);

        // Create a unique id for track
        String uuid = participantId;
        if (participantId.length() == 0) {
            uuid = UUID.randomUUID().toString();
        }

        // Add track
        RNIrisSdkStreamManager.getInstance().addTrack(mediaTrack, uuid);

        WritableMap event = Arguments.createMap();
        event.putString("StreamId", uuid);
        event.putString("RoutingId", participantId);
        event.putString("SessionId", roomId);

        this.sendEvent(IrisEventOnRemoteAddStream, event);

        // TBD broadcast notification
    }

    /**
     * Callback: This is called when the remote stream is removed from peerconnection.
     *
     * @param mediaTrack    IrisRtcMediaTrack containing remote track
     * @param participantId Participant Id.
     * @param roomId        Room Id.
     */
    @Override
    public void onRemoveRemoteStream(IrisRtcMediaTrack mediaTrack, String participantId, String roomId) {
        Log.i(TAG_RNIRISSDK, " onRemoveRemoteStream called with " + participantId + ":" + roomId);

        WritableMap event = Arguments.createMap();
        event.putString("StreamId", participantId);
        event.putString("SessionId", roomId);

        this.sendEvent(IrisEventOnRemoteRemoveStream, event);

        // Send a notification to delete the renderer/videoview
        Intent intent = new Intent("onTrackDeleted");
        intent.putExtra("TrackId", participantId);
        LocalBroadcastManager.getInstance(reactContext).sendBroadcast(intent);
    }

    /**
     * This method is called when the remote stream is added to peerconnection.
     *
     * @param chatMessage   message string
     * @param participantId Id sending the chat message
     * @param roomId        Identifier for the allocated  chat room for the participants
     */
    @Override
    public void onSessionParticipantMessage(IrisChatMessage chatMessage, String participantId, String roomId) {
        Log.i(TAG_RNIRISSDK, " onSessionParticipantMessage called with " + participantId + ":" + roomId + ":"
                + chatMessage.getMessageBody());

        WritableMap event = Arguments.createMap();
        event.putString("participantId", participantId);
        event.putString("roomId", roomId);
        event.putString("childNodeId", chatMessage.getChildNodeId());
        event.putString("rootNodeId", chatMessage.getRootNodeId());
        event.putString("messageId", chatMessage.getMessageId());
        event.putString("data", chatMessage.getMessageBody());

        this.sendEvent(IrisEventOnChatMessage, event);
    }

    /**
     * Callback: This is called when chat message is sent successfully.
     *
     * @param message chat message.
     * @param roomId  Identifier for the allocated  chat room for the participants.
     */
    @Override
    public void onChatMessageSuccess(IrisChatMessage message, String roomId) {
        Log.i(TAG_RNIRISSDK, " onChatMessageSuccess called with " + roomId + ":" + message.getMessageId());

        WritableMap event = Arguments.createMap();
        event.putString("SessionId", roomId);
        event.putString("childNodeId", message.getChildNodeId());
        event.putString("rootNodeId", message.getRootNodeId());
        event.putString("timeReceived", message.getTimeReceived());
        event.putString("messageId", message.getMessageId());

        this.sendEvent(IrisEventOnChatMessageAck, event);

    }

    /**
     * Callback: This is called when chat message sending fails.
     *
     * @param messageId message id.
     * @param errorInfo error info.
     * @param roomId    Identifier for the allocated  chat room for the participants.
     */
    @Override
    public void onChatMessageError(String messageId, JSONObject errorInfo, String roomId) {
        Log.i(TAG_RNIRISSDK, " onChatMessageError called with " + roomId + ":" + messageId);

        WritableMap event = Arguments.createMap();
        event.putString("messageId", messageId);
        event.putString("info", errorInfo.toString());
        event.putString("SessionId", roomId);

        this.sendEvent(IrisEventOnChatMessageError, event);
    }

    /**
     * This method is called when chat state change for the remote participant
     *
     * @param state         chat state.
     * @param participantId Id sending the chat message.
     * @param roomId        Identifier for the allocated  chat room for the participants.
     */
    @Override
    public void onChatMessageState(IrisChatState state, String participantId, String roomId) {
        Log.i(TAG_RNIRISSDK, " onChatMessageState called with " + state + ":" + participantId + ":" + roomId);

        String chatstate;

        // check the state
        if (state == IrisChatState.ACTIVE) {
            chatstate = "active";
        } else if (state == IrisChatState.COMPOSING) {
            chatstate = "composing";
        } else if (state == IrisChatState.GONE) {
            chatstate = "gone";
        } else if (state == IrisChatState.INACTIVE) {
            chatstate = "inactive";
        } else if (state == IrisChatState.PAUSED) {
            chatstate = "paused";
        } else {
            return;
        }

        WritableMap event = Arguments.createMap();
        event.putString("RoutingId", participantId);
        event.putString("SessionId", roomId);
        event.putString("state", chatstate);

        this.sendEvent(IrisEventOnChatMessageState, event);
    }

}