How To Make A Video Call Using Sendbird in React Js

In this article, we will learn how to make a video call using sendbird in react js.

first, we will login and create an application in sendbird and as per the below dashboard, u can see the application details.

You can start making a 1-to-1 call by installing Sendbird Calls for JavaScript.

step 1

Install sendbird-calls dependency to the package.json file in your project.

# npm
npm install sendbird-calls

#yarn
yarn add sendbird-calls

step 2

Import and initialize with appid as shown below:

import SendBirdCall from "sendbird-calls";

SendBirdCall.init(APP_ID)

step 3

To make and receive a 1-to-1 call or start a group call, create a user and authenticate a user to the Sendbird server by using their user ID through the authenticate() method. To receive calls, the SendBirdCall instance should be connected with the Sendbird server. Connect socket by using the SendBirdCall.connectWebSocket() method after a user’s authentication has been completed.

// The USER_ID below should be unique to your Sendbird application.
const authOption = { userId: USER_ID, accessToken: ACCESS_TOKEN };

SendBirdCall.authenticate(authOption, (result, error) => {
    if (error) {
        // Handle authentication failure.
    } else {
        // The user has been successfully authenticated and is connected to Sendbird server.
        ...
    }
});

// Establishing websocket connection.
SendBirdCall.connectWebSocket()
    .then(/* Succeeded to connect */)
    .catch(/* Failed to connect */);

step 4

Sendbird Calls provides SendBirdCallListener event handler for events related to Direct calls. It is used to manage device-specific events such as incoming calls.

// The UNIQUE_HANDLER_ID below is a unique user-defined ID for a specific event handler.
SendBirdCall.addListener(UNIQUE_HANDLER_ID, {
    onRinging: (call) => {
        ...
    }
});

step 5

You are now ready to make your first 1-to-1 call. To make a call, provide the callee’s user ID into the SendBirdCall.dial() method. To choose initial call configuration such as audio or video capabilities, video settings, and mute settings, use the CallOption object.

After making a call, add the call-specific DirectCallListener event handler to the call object. It allows the callee’s app to respond to events happening during the call through its callback methods.

const dialParams = {
    userId: CALLEE_ID,
    isVideoCall: true,
    callOption: {
        localMediaView: document.getElementById('local_video_element_id'),
        remoteMediaView: document.getElementById('remote_video_element_id'),
        audioEnabled: true,
        videoEnabled: true
    }
};


const call = SendBirdCall.dial(dialParams, (call, error) => {
    if (error) {
        // Dialing failed.
    }

    // Dialing succeeded.
});

call.onEstablished = (call) => {
    ...
};

call.onConnected = (call) => {
    ...
};

call.onEnded = (call) => {
    ...
};

call.onRemoteAudioSettingsChanged = (call) => {
    ...
};

call.onRemoteVideoSettingsChanged = (call) => {
    ...
};

step 6

You can accept or decline an incoming call. To accept an incoming call, use the directCall.accept(). To decline a call, use the directCall.end() method.

const acceptParams = {
          callOption: {
              localMediaView: document.getElementById('local_video_element_id'),
              remoteMediaView: document.getElementById('remote_video_element_id'),
              audioEnabled: true,
              videoEnabled: true
          }
      };

      call.accept(acceptParams);

you can see the video call code below

import React, { useState, useEffect } from 'react'
import SendBirdCall from "sendbird-calls";
function Home() {
    const [userId, setuserId] = useState('him')
    const [appId, setappId] = useState('412F3DBD-3AFC-40FE-8C38-8CB43F3AA7D8')
    const [display, setdisplay] = useState(false)
    const [callView, setcallView] = useState(false)
    const [currentCall, setcurrentCall] = useState()
    const [acceptCalls, setacceptCall] = useState(false)
    const [callEnds, setcallEnd] = useState(false)
    const [disabled, setdisabled] = useState(true)
    const [callerName, setcallerName] = useState(null)
    const [hold, sethold] = useState(false)
    const [fullWidth, setFullWidth] = useState(false)
    const [RemortVideo, setRemortVideo] = useState(false)
    const [muteMicro, setMuteMicro] = useState(false)
    const [remortOnHold, setRemortOnHold] = useState(false)
    const [unholdflag, setunholdflag] = useState(false)
    const [holdflag, setholdflag] = useState(false)
    const [ab, setab] = useState()

    const login = () => {
        const option = { userId }
        SendBirdCall.init(appId)

        return SendBirdCall.authenticate(option)
            .then(user => {
                setab(userId)
                localStorage.setItem('userId', userId)
                setdisplay(true)
            })
            .catch(error => {
                alert("please check details")
            })

    }

    function getCallOption(callOption) {
        console.log(callOption, "callOption")
        setcallView(true)
        return {
            localMediaView:
                document.getElementById('local_video_element_id'),
            remoteMediaView:
                document.getElementById('remote_video_element_id'),
            audioEnabled: true,
            videoEnabled: true,
            nickname: "dbsfkjsdbf",
            ...callOption
        }

    }
    const dial = (isVideoCall) => {
        SendBirdCall.connectWebSocket()
            .then((re) => {
                console.log("connect")
                const call = SendBirdCall.dial({ userId, isVideoCall, callOption: getCallOption({ dial }) })
                console.log(call, "me")
                call.onEnded = (call) => {
                    console.log('onEnded')
                    setcallView(false)

                };
                setcurrentCall(call)
            }).catch((err) => {
                console.log(err)
            })
    }

    const callEnd = (call) => {
        console.log("call end")
        setcallEnd(true)
        currentCall.end()
    }

    const acceptCall = () => {
        setacceptCall(false)
        const acceptParams = {
            callOption: {
                localMediaView:
                    document.getElementById('local_video_element_id'),
                remoteMediaView:
                    document.getElementById('remote_video_element_id'),
                audioEnabled: true,
                videoEnabled: true
            }
        };
        currentCall.accept(acceptParams)
    }

    const stopVideo = () => {
        setdisabled(!disabled)
        if (!disabled) {
            currentCall.startVideo()
        } else {
            currentCall.stopVideo()
        }
    }

    const holeCall = () => {
        try {
            setholdflag(true)
            console.log('call hold')
            currentCall.hold()
            sethold(true)
        } catch (error) {
            console.log("another call is already on hold")
        }

    }

    const unholdCall = () => {
        try {
            currentCall.unhold()
            console.log('call unhold')
            sethold(false)
            setunholdflag(true)
        } catch (error) {
            console.log("another call is already on hold")
        }

    }

    const handleVideoClick = () => {
        setFullWidth(!fullWidth)
    }

    const handleMute = () => {
        if (muteMicro) {
            currentCall.unmuteMicrophone()
            setMuteMicro(false)
        } else {
            currentCall.muteMicrophone()
            setMuteMicro(true)
        }
    }

    useEffect(() => {

        if (currentCall) {
            currentCall.unmuteMicrophone()
            currentCall.onRemoteVideoSettingsChanged = (call) => {
                if (call.isRemoteVideoEnabled) {
                    setRemortVideo(false)
                } else {
                    setRemortVideo(true)
                }
            }
            currentCall.onUserHoldStatusChanged = (call, isLocalUser, isUserOnHold) => {
                if (!(holdflag && unholdflag)) {
                    if (isUserOnHold && !holdflag) {
                        setRemortOnHold(true)
                        console.log("remot call hold")
                    }
                    else {
                        setRemortOnHold(false)
                        console.log("remot call unhold")
                        setunholdflag(false)
                        setholdflag(false)
                    }
                }
            }
        }
    }, [currentCall, hold])

    useEffect(() => {
        if (display) {
            SendBirdCall.addDirectCallSound(SendBirdCall.SoundType.DIALING, "horse.mp3")
            SendBirdCall.init(appId)
            const option = { userId }

            return SendBirdCall.authenticate(option)
                .then(user => {
                    SendBirdCall.connectWebSocket()
                        .then((result) => {
                            SendBirdCall.addListener('ANY UNIQUE_HANDLER_ID HERE', {
                                onRinging: (call) => {
                                    setcallView(true)
                                    setcurrentCall(call)
                                    setacceptCall(true)
                                    call.onEstablished = (call) => {
                                        console.log("trueeee")
                                    };
                                    call.onConnected = (call) => {
                                        setcurrentCall(call)
                                    };
                                    call.onEnded = (call) => {
                                        setcallView(false)
                                        setcurrentCall(call)
                                    };
                                    call.unmuteMicrophone()
                                    for (const key in call._caller) {
                                        if (Object.hasOwnProperty.call(call._caller, key)) {
                                            setcallerName(call.caller.userId)
                                        }
                                    }
                                }
                            })
                        }).catch((err) => {
                            console.log(err)
                        })
                })
                .catch(error => {
                    console.log(error)
                })
        }
    }, [display])

    return (
        <div className='main-root'>
            {
                display ?
                    <>
                        <div className='main-root'>
                            {
                                callView ?
                                    <>
                                        <div className="call_view">
                                            <div className={fullWidth ? `local_video_full` : `local_video`} onClick={() => handleVideoClick()}>
                                                <video id="local_video_element_id" className="localdevice" autoPlay={true} muted>

                                                </video>
                                                {disabled ? <><div className={fullWidth ? `active_vcall_lfull` : `active_vcall`}><div className={fullWidth ? `video-none1-lfull` : `video-none`}>{localStorage.getItem('userId').charAt(0).toUpperCase()}
                                                </div></div>
                                                    {acceptCalls ?
                                                        <div className="callername">
                                                            <p>{callerName} calling...</p>
                                                        </div>
                                                        : ''}
                                                </>
                                                    : <div className={fullWidth ? 'video-none-lfull' : 'video-none1'}>{localStorage.getItem('userId').charAt(0).toUpperCase()}
                                                    </div>}
                                            </div>
                                            <div className={fullWidth ? `remort_video_full` : `remort_video`} onClick={() => handleVideoClick()}>
                                                <video id='remote_video_element_id' className="remotedevice" autoPlay={true} onClick={() => handleVideoClick()}></video>
                                                {RemortVideo ? <div className={fullWidth ? 'video-none1' : 'video-none-lfull'}>{callerName ? callerName.charAt(0).toUpperCase() : userId.charAt(0).toUpperCase()}
                                                </div> : <div className={fullWidth ? `active_vcall` : `active_vcall_lfull`}><div className={fullWidth ? `video-none` : `video-none1-lfull`}>{callerName ? callerName.charAt(0).toUpperCase() : userId.charAt(0).toUpperCase()}
                                                </div></div>
                                                }
                                            </div>
                                            <div className="calls">
                                                {
                                                    acceptCalls &&
                                                    <>
                                                        <div className="acceptcall" onClick={() => acceptCall()}>
                                                            <i class="fa fa-phone"></i>
                                                        </div>
                                                    </>
                                                }

                                                <div className={disabled ? "mutevideo" : 'unmute'} onClick={() => stopVideo()} >
                                                    <i class="fa fa-video-camera" ></i>
                                                </div>

                                                {hold ? <>{remortOnHold ?
                                                    <div className="unhold another" >
                                                        <i class="fa fa-pause"></i>
                                                    </div> : <div className="unhold" onClick={() => unholdCall()} >
                                                        <i class="fa fa-pause"></i>
                                                    </div>}</> : <>{remortOnHold ?
                                                        <div className="hold another" >
                                                            <i class="fa fa-pause"></i>
                                                        </div> :
                                                        <div className="hold" onClick={() => holeCall()} >
                                                            <i class="fa fa-pause"></i>
                                                        </div>} </>}


                                                <div className="endcalls" onClick={() => callEnd()}>
                                                    <i class="fa fa-phone" ></i>
                                                </div>
                                                <div className='microphone-active' onClick={() => handleMute()} >
                                                    <i class={muteMicro ? "fa fa-microphone-slash" : "fa fa-microphone"}></i>
                                                </div>
                                            </div>
                                        </div>
                                    </>
                                    :
                                    <>
                                        <div className="container">
                                            <div>{`${localStorage.getItem('userId')} Login`}</div>
                                            <h5>Make a Call</h5>
                                            <input className="mb-2" type="text" placeholder="enter caller name" onChange={(e) => setuserId(e.target.value)} /><br />
                                            <i class="fa fa-phone makecall" onClick={() => dial(true)}></i>
                                        </div>
                                    </>
                            }
                        </div>

                    </>

                    :
                    <>
                        <div className="container">
                            <h5>Login</h5>
                            <input type="text" className="mb-2" placeholder="enter your name" onChange={(e) => setuserId(e.target.value)} />
                            <button onClick={() => login()} type="button" class="btn btn-warning">Login</button>
                        </div>
                    </>
            }
        </div>
    )
}

export default Home

you can see the output below…

 

 

 

 

Submit a Comment

Your email address will not be published.

Subscribe

Select Categories