package com.infobiprtcreactnative import android.util.Log import com.facebook.react.bridge.* import com.facebook.react.module.annotations.ReactModule import com.infobip.webrtc.sdk.api.InfobipRTC import com.infobip.webrtc.sdk.api.call.* import com.infobip.webrtc.sdk.api.call.options.CallOptions import com.infobip.webrtc.sdk.api.call.options.CallPhoneNumberOptions import com.infobip.webrtc.sdk.api.call.options.RecordingOptions import com.infobip.webrtc.sdk.impl.util.AccessToken import com.infobiprtcreactnative.video.RTCVideoView import util.MapUtil @ReactModule(name = "InfobipRTCReactNative") class InfobipRTCModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) { private val views: MutableMap = HashMap() override fun getName(): String { return "InfobipRTCReactNative" } @ReactMethod fun call(token: String, destination: String, options: ReadableMap?, promise: Promise) { val callRequest = CallRequest(token, reactApplicationContext, destination, DefaultCallEventListener(reactApplicationContext)) try { val callOptions: CallOptions = getCallOptions(options) val call: OutgoingCall = InfobipRTC.call(callRequest, callOptions) promise.resolve(mapCall(call)) } catch (e: Exception) { Log.d("RTC", e.message, e) promise.reject(e) } } @ReactMethod fun callPhoneNumber( token: String, destination: String, callPhoneNumberOptions: ReadableMap?, promise: Promise ) { val callRequest = CallRequest( token, reactApplicationContext, destination, DefaultCallEventListener(reactApplicationContext) ) try { val options = getCallPhoneNumberOptions(callPhoneNumberOptions); val call: OutgoingCall = options.let { InfobipRTC.callPhoneNumber(callRequest, options) } ?: InfobipRTC.callPhoneNumber(callRequest) promise.resolve(mapCall(call)) } catch (e: Exception) { promise.reject(e) } } @ReactMethod fun callConversations(token: String, options: ReadableMap?, promise: Promise) { val callRequest = CallConversationsRequest(token, reactApplicationContext, DefaultCallEventListener(reactApplicationContext)) try { val callOptions: CallOptions = getCallOptions(options) val call: OutgoingCall = InfobipRTC.callConversations(callRequest, callOptions) promise.resolve(mapCall(call)) } catch (e: Exception) { Log.d("RTC", e.message, e) promise.reject(e) } } @ReactMethod fun callSIP(token: String, destination: String, options: ReadableMap?, promise: Promise) { val callRequest = CallRequest(token, reactApplicationContext, destination, DefaultCallEventListener(reactApplicationContext)) try { val callOptions: CallOptions = getCallOptions(options) val call: OutgoingCall = InfobipRTC.callSIP(callRequest, callOptions) promise.resolve(mapCall(call)) } catch (e: Exception) { Log.d("RTC", e.message, e) promise.reject(e) } } @ReactMethod fun callDynamicDestination(token: String, options: ReadableMap?, promise: Promise) { val callRequest = CallDynamicDestinationRequest(token, reactApplicationContext, DefaultCallEventListener(reactApplicationContext)) try { val callOptions: CallOptions = getCallOptions(options) val call: OutgoingCall = InfobipRTC.callDynamicDestination(callRequest, callOptions) promise.resolve(mapCall(call)) } catch (e: Exception) { Log.d("RTC", e.message, e) promise.reject(e) } } @ReactMethod fun hangup(promise: Promise) { val call = InfobipRTC.getActiveCall() if (call != null) { call.hangup() } promise.resolve(null) } @ReactMethod fun mute(mute: Boolean, promise: Promise) { val call = InfobipRTC.getActiveCall() if (call != null) { call.mute(mute) } promise.resolve(null) } @ReactMethod fun speakerphone(enabled: Boolean, promise: Promise) { val call = InfobipRTC.getActiveCall() if (call != null) { call.speakerphone(enabled) } promise.resolve(null) } @ReactMethod fun localVideo(localVideo: Boolean, promise: Promise) { val call = InfobipRTC.getActiveCall() if (call != null) { call.localVideo(localVideo) } promise.resolve(null) } @ReactMethod fun enablePushNotification(token: String, deviceToken: String?, debug: Boolean, promise: Promise) { InfobipRTC.enablePushNotification(token, reactApplicationContext, DefaultEventListener(promise)) } @ReactMethod fun handleIncomingCall(payload: ReadableMap, promise: Promise) { InfobipRTC.handleIncomingCall( MapUtil.toHashMap(payload), reactApplicationContext, DefaultIncomingCallEventListener(reactApplicationContext, promise, mapCallResponse(payload)) ) } @ReactMethod fun accept(options: ReadableMap?, promise: Promise) { val incomingCall = InfobipRTC.getActiveCall() if (incomingCall != null) { if (options == null || MapUtil.isEmpty(options)) { (incomingCall as IncomingCall).accept() } else { val video: Boolean = options.getBoolean("_video") val callOptions: CallOptions = CallOptions.builder().video(video).build() (incomingCall as IncomingCall).accept(callOptions) } } promise.resolve(null) } @ReactMethod fun decline(promise: Promise) { val incomingCall = InfobipRTC.getActiveCall() if (incomingCall != null) { (incomingCall as IncomingCall).decline() } promise.resolve(null) } @ReactMethod fun registerForActiveConnection(token: String, promise: Promise) { InfobipRTC.registerForActiveConnection(token, reactApplicationContext, SimulatorIncomingCallListener(reactApplicationContext)) promise.resolve(null) } private fun mapCall(call: OutgoingCall): WritableMap { val map: WritableMap = WritableNativeMap() call.id()?.let { map.putString("id", it) } call.correlationId()?.let { map.putString("correlationId", it) } call.hasLocalVideo().let { map.putBoolean("hasLocalVideo", it) } call.hasRemoteVideo().let { map.putBoolean("hasRemoteVideo", it) } val sourceMap = WritableNativeMap() call.source().identity?.let { sourceMap.putString("identity", it) } call.source().displayName?.let { sourceMap.putString("displayName", it) } map.putMap("source", sourceMap) val destinationMap = WritableNativeMap() call.destination().identity?.let { destinationMap.putString("identity", it) } call.destination().displayName?.let { destinationMap.putString("displayName", it) } map.putMap("destination", destinationMap) return map } private fun mapCallResponse(data: ReadableMap): WritableMap { val map = WritableNativeMap() data.getString("callId")?.let { map.putString("id", it) } data.getString("correlationId")?.let { map.putString("correlationId", it) } data.getString("hasVideo")?.let { map.putBoolean("hasRemoteVideo", it.toBoolean()) } map.putBoolean("hasLocalVideo", false) val sourceMap = WritableNativeMap() sourceMap.putString("identity", data.getString("source") ?: "") val displayName = if (data.hasKey("displayName")) data.getString("displayName") else "" sourceMap.putString("displayName", displayName) map.putMap("source", sourceMap) val destinationMap = WritableNativeMap() val accessToken = AccessToken(data.getString("token")) destinationMap.putString("identity", accessToken.identity ?: "") destinationMap.putString("displayName", accessToken.displayName ?: "") map.putMap("destination", destinationMap) return map } fun setView(id: String, view: RTCVideoView) { views[id] = view } fun getView(id: String): RTCVideoView? { return views[id] } fun clearViews() { views.values.forEach { it.release() } return views.clear() } private fun getCallPhoneNumberOptions(map: ReadableMap?): CallPhoneNumberOptions? { if (map == null) { return CallPhoneNumberOptions.builder().build(); } val builder = CallPhoneNumberOptions.builder().from(map.getString("from")) if (map.hasKey("recordingOptions")) { builder.recordingOptions(getRecordingOptions(map.getMap("recordingOptions"))) } return builder.build() } private fun getRecordingOptions(map: ReadableMap?): RecordingOptions { if (map == null) { return RecordingOptions.builder().build(); } return RecordingOptions.builder() .video(map.getBoolean("video")) .audio(map.getBoolean("audio")) .build() } private fun getCallOptions(options: ReadableMap?): CallOptions { if (options == null) { return CallOptions.builder().build() } val video: Boolean = options.getBoolean("_video") return CallOptions.builder().video(video).build() } }