@sendbird/calls-react-native
Version:
Sendbird Calls SDK for React Native: Empower React Native apps with seamless audio, video, and group calling. Build interactive communication easily.
148 lines (129 loc) • 6.04 kB
text/typescript
/* eslint-disable */
import { NativeEventEmitter, NativeModules } from 'react-native';
import type { AsNativeInterface, DirectCallProperties, RoomProperties, SendbirdCallsNativeSpec } from '../types';
import { LINKING_ERROR } from '../utils/constants';
import { convertDirectCallPropsNTJ, convertGroupCallPropsNTJ } from '../utils/converter';
import { Logger } from '../utils/logger';
import JSEventEmitter from './JSEventEmitter';
const MODULE_NAME = 'RNSendbirdCalls';
const NativeModule = NativeModules[MODULE_NAME]; //TurboModuleRegistry.get<SendbirdCallsSpec>(MODULE_NAME);
const NoopModuleProxy = new Proxy(
{},
{
get() {
throw new Error(LINKING_ERROR);
},
},
);
export enum CallsEvent {
DEFAULT = 'sendbird.call.default',
DIRECT_CALL = 'sendbird.call.direct',
GROUP_CALL = 'sendbird.call.group',
}
export enum DefaultEventType {
ON_RINGING = 'sendbird.call.default.onRinging',
}
export enum DirectCallEventType {
ON_ESTABLISHED = 'sendbird.call.direct.onEstablished',
ON_CONNECTED = 'sendbird.call.direct.onConnected',
ON_RECONNECTING = 'sendbird.call.direct.onReconnecting',
ON_RECONNECTED = 'sendbird.call.direct.onReconnected',
ON_ENDED = 'sendbird.call.direct.onEnded',
ON_REMOTE_AUDIO_SETTINGS_CHANGED = 'sendbird.call.direct.onRemoteAudioSettingsChanged',
ON_REMOTE_VIDEO_SETTINGS_CHANGED = 'sendbird.call.direct.onRemoteVideoSettingsChanged',
ON_LOCAL_VIDEO_SETTINGS_CHANGED = 'sendbird.call.direct.onLocalVideoSettingsChanged',
ON_REMOTE_RECORDING_STATUS_CHANGED = 'sendbird.call.direct.onRemoteRecordingStatusChanged',
ON_AUDIO_DEVICE_CHANGED = 'sendbird.call.direct.onAudioDeviceChanged',
ON_CUSTOM_ITEMS_UPDATED = 'sendbird.call.direct.onCustomItemsUpdated',
ON_CUSTOM_ITEMS_DELETED = 'sendbird.call.direct.onCustomItemsDeleted',
ON_USER_HOLD_STATUS_CHANGED = 'sendbird.call.direct.onUserHoldStatusChanged',
}
export enum GroupCallEventType {
ON_DELETED = 'sendbird.call.group.onDeleted',
ON_ERROR = 'sendbird.call.group.onError',
ON_LOCAL_PARTICIPANT_DISCONNECTED = 'sendbird.call.group.onLocalParticipantDisconnected',
ON_LOCAL_PARTICIPANT_RECONNECTED = 'sendbird.call.group.onLocalParticipantReconnected',
ON_REMOTE_PARTICIPANT_ENTERED = 'sendbird.call.group.onRemoteParticipantEntered',
ON_REMOTE_PARTICIPANT_EXITED = 'sendbird.call.group.onRemoteParticipantExited',
ON_REMOTE_PARTICIPANT_STREAM_STARTED = 'sendbird.call.group.onRemoteParticipantStreamStarted',
ON_AUDIO_DEVICE_CHANGED = 'sendbird.call.group.onAudioDeviceChanged',
ON_REMOTE_VIDEO_SETTINGS_CHANGED = 'sendbird.call.group.onRemoteVideoSettingsChanged',
ON_REMOTE_AUDIO_SETTINGS_CHANGED = 'sendbird.call.group.onRemoteAudioSettingsChanged',
ON_CUSTOM_ITEMS_UPDATED = 'sendbird.call.group.onCustomItemsUpdated',
ON_CUSTOM_ITEMS_DELETED = 'sendbird.call.group.onCustomItemsDeleted',
}
type MakeEventUnionMember<Type, Data> = {
eventType: Type;
data: AsNativeInterface<Data>;
convertedData: Data;
additionalData?: Record<string, any>;
};
type EventUnion =
| MakeEventUnionMember<DefaultEventType, DirectCallProperties>
| MakeEventUnionMember<DirectCallEventType, DirectCallProperties>
| MakeEventUnionMember<GroupCallEventType, RoomProperties>;
type EventType = EventUnion['eventType'];
type ExtractData<T extends EventType, U extends EventUnion = EventUnion> = U extends { eventType: T }
? U['convertedData']
: never;
export default class NativeBinder {
private _nativeModule: SendbirdCallsNativeSpec = NativeModule ?? NoopModuleProxy;
private _nativeEventEmitter = new NativeEventEmitter(this._nativeModule);
private _jsEventEmitter = new JSEventEmitter();
private _supportedNativeEvents = [CallsEvent.DEFAULT, CallsEvent.DIRECT_CALL, CallsEvent.GROUP_CALL];
public get nativeModule() {
return this._nativeModule;
}
public get jsEventEmitter() {
return this._jsEventEmitter;
}
constructor() {
/* for reduce redundant native event listeners */
this._supportedNativeEvents.forEach((event) => {
Logger.info('[NativeBinder] Add native event listener:', event);
// Native -> JS
this._nativeEventEmitter.addListener(
event,
({ eventType, data, additionalData }: Omit<EventUnion, 'convertedData'>) => {
Logger.info(
'[NativeBinder] Receive events from native module: ',
[
event,
eventType,
event === CallsEvent.GROUP_CALL
? (data as AsNativeInterface<RoomProperties>).roomId
: (data as AsNativeInterface<DirectCallProperties>).callId,
additionalData && JSON.stringify(additionalData).slice(0, 30) + '...',
].join(' ++ '),
);
if (event === CallsEvent.DIRECT_CALL || event === CallsEvent.DEFAULT) {
this.jsEventEmitter.emit(event, {
type: eventType,
data: convertDirectCallPropsNTJ(data as AsNativeInterface<DirectCallProperties>),
additionalData,
});
}
if (event === CallsEvent.GROUP_CALL) {
this.jsEventEmitter.emit(event, {
type: eventType,
data: convertGroupCallPropsNTJ(data as AsNativeInterface<RoomProperties>),
additionalData,
});
}
},
);
});
}
public addListener(eventName: CallsEvent.DEFAULT, callback: EventCallback<DefaultEventType>): () => void;
public addListener(eventName: CallsEvent.DIRECT_CALL, callback: EventCallback<DirectCallEventType>): () => void;
public addListener(eventName: CallsEvent.GROUP_CALL, callback: EventCallback<GroupCallEventType>): () => void;
public addListener(eventName: string, callback: (event: any) => void) {
Logger.info('[NativeBinder] Add javascript event listener:', eventName);
return this.jsEventEmitter.addListener(eventName, callback);
}
}
type EventCallback<T extends EventType> = (data: {
type: T;
data: ExtractData<T>;
additionalData?: Record<string, any>;
}) => void;