# Realize One-to-One Video Calling
This guide introduces how to achieve one-to-one video calling. API call sequence for one-to-one call is as shown below:
# Initialize
Extend the JCMediaDeviceCallback (opens new window) object and JCCallCallback (opens new window) object, and implement the pure virtual functions in these two objects:
class JCManager : public JCMediaDeviceCallback, public JCCallCallback
{
public:
//This callback triggers when the callItem is added
virtual void onCallItemAdd(JCCallItem* item);
//This callback triggers when the callItem is removed
virtual void onCallItemRemove(JCCallItem* item, JCCallReason reason, const char* description);
//This callback triggers when the callItem‘s status is updated
virtual void onCallItemUpdate(JCCallItem* item, JCCallItemChangeParam changeParam);
//This callback triggers when messages are received
virtual void onMessageReceive(const char* type, const char* content, JCCallItem* item);
//This callback triggers when get missed calls
virtual void onMissedCallItem(JCCallItem* item);
//This callback triggers when the camera is switched
virtual void onCameraUpdate();
public:
//JCMediaDevice object
JCMediaDevice* mediaDevice;
//JCCall object
JCCall* call;
};
TIP
The object in the callback can only be used in the callback and cannot be saved. The upper layer can obtain the call object through the corresponding method.
Call createJCMediaDevice (opens new window) and createJCCall (opens new window) to initialize the modules needed for one-to-one calling:
bool JCManager::initialize()
{
//1. Media class
mediaDevice = createJCMediaDevice(client, this);
//2. Call class
call = createJCCall(client, mediaDevice, this);
}
Among them:
This in the JCMediaDevice create method is a derived class of JCMediaDeviceCallback (opens new window) , which is used to notify the upper layer of media device-related events. Therefore, you need to create a derived class of JCMediaDeviceCallback, and then implement the pure virtual function of JCMediaDeviceCallback in the derived class.
This in the JCCall create method is a derived class of JCCallCallback (opens new window), which is used to notify call-related events to the upper layer. Therefore, you need to create a derived class of JCCallback, and then implement the pure virtual function of JCCallCallback in the derived class.
# Make a call
To call call (opens new window) to initiate a video call, the parameters to be filled are:
userID
Fill in the user ID of the other party.video
Select whether to call a video call, and true means to make a video call, while false means to make a voice call.extraParam
is a custom pass-through string, which can be obtained through the extraParam property in the JCCallItem object.
// Initiate a video call
void JCSampleDlg::OnBnClickedButtonVideocall()
{
JCManager::shared()->call->call("userID", true, "custom pass-through string");
}
After making a call, both the caller and the called party will receive the callback onCallItemAdd (opens new window) for the new call, and the call state will change to JCCallStatePending. You can implement the onCallItemAdd (opens new window) method in the upper layer and process related logic:
// Receive a new call callback
void JCManager::onCallItemAdd(JCCallItem* item) {
// Business logic
if (item->direction == JCCallDirectionIn) {
// If it is an incoming call
...
} else {
// If it is an outgoing call
...
}
}
TIP
The object in the callback can only be used in the callback and cannot be saved. The upper layer can obtain the call object through the corresponding method. If the caller wants to cancel the call, he/she can go directly to the hang up part. After calling the hang up interface, the call status becomes the JCCallStateCancel.
# Create local video images
After initiating a call, call the startSelfVideo (opens new window) in the JCCallItem (opens new window) class to create a local video image. This method returns a JCMediaDeviceVideoCanvas (opens new window) object. This object is used to render the video to the canvas and manage the rendering method. (Calling this method will open the camera):
void JCManager::onCallItemAdd(JCCallItem* item) {
JCMediaDeviceVideoCanvas* mCallLocalCanvas;
if (mCallLocalCanvas == NULL && item->getUploadVideoStreamSelf())
{
// Create local and remote video images
mCallLocalCanvas = item->startSelfVideo((void*)mWndCallLocalVideo.m_hWnd, (JCMediaDeviceRenderMode)JCMediaDeviceRenderModeFullContent);
}
}
# Answer a call
After the caller initiates the call successfully, the called party will receive the onCallItemAdd (opens new window) callback. At this time, the getVideo() method and getDirection() method in the JCCallItem (opens new window) object in the callback can be used to determine whether it is a video call or a voice call. Deal with it accordingly:
void JCManager::onCallItemAdd(JCCallItem* item) { // 1. If it is a video call and is ringing if (item->getDirection() == JCCallDirectionIn && item->getState() == JCCallStatePending) { // 2. Make corresponding processing, such as "ringing" on the interface ... } }
Call answer (opens new window) to answer the call, the video call can be answered by voice or video:
// Get active calls JCCallItem* item = JCManager::shared()->call->getActiveCallItem(); // Answer the call JCManager::shared()->call->answer(item, item->getVideo());
After the call is answered, the call status changes to JCCallStateConnecting.
TIP
If you want to reject the call at this time, you can go directly to the hang up part. After calling the hang up interface, the call state becomes JCCallStateCanceled.
# Create remote video images
After the called party answers the call, the two parties will establish a connection. At this time, both the caller and the called party will receive the updated callback of the call (onCallItemUpdate), and the call state will change to the JCCallStateTalking.
Call the startOtherVideo (opens new window) in the JCCallItem (opens new window) class to create a remote video streaming. This method returns a JCMediaDeviceVideoCanvas (opens new window) object, which is used to render the video to the canvas and manage the rendering method:
void JCManager::onCallItemUpdate(JCCallItem* item, JCCallItemChangeParam changeParam) {
JCMediaDeviceVideoCanvas *mCallRemoteCanvas;
// If the peer is uploading a video streaming (uploadVideoStreamOther)
if (mCallRemoteCanvas == NULL && item->getUploadVideoStreamOther())
{
// Remote video rendering
mCallRemoteCanvas = item->startOtherVideo(mWndCallRemoteVideo.m_hWnd, (JCMediaDeviceRenderMode)JCMediaDeviceRenderModeFullContent);
}
}
# Hang up a call
Both the calling party and the called party can hang up the call.
First call getActiveCallItem (opens new window) to get the currently active call object;
After obtaining the current active call object, call term (opens new window) to hang up the current active call:
void JCSampleDlg::OnBnClickedButtonTermcall() { // 1. Get the current active call JCCallItem* item = JCManager::shared()->call->getActiveCallItem(); if (item != NULL) { // 2. Hang up the current active call JCManager::shared()->call->term(item, JCCallReasonNone, "term"); } }
# Destroy local and remote video images
After the call is hung up, the onCallItemRemove callback in JCCallCallback (opens new window) will be triggered, and the call state will change to JCCallStateOk. At this time, you need to call the stopSelfVideo (opens new window) and stopOtherVideo (opens new window) methods to destroy the local and remote video images:
void JCManager::onCallItemRemove(JCCallItem* item, JCCallReason reason, const char* description) { //This callback triggers when the call is removed callback
// Local video destruction
if (mCallLocalCanvas != NULL && !item->getUploadVideoStreamSelf())
{
item->stopSelfVideo();
mCallLocalCanvas = NULL;
mWndCallLocalVideo.Invalidate();
}
// Remote video destruction
if (mCallRemoteCanvas != NULL && !item->getUploadVideoStreamOther())
{
item->stopOtherVideo();
mCallRemoteCanvas = NULL;
mWndCallRemoteVideo.Invalidate();
}
}
Now, you have completed the basic function of one-to-one video calling.