Use Rongyun CallPlus SDK to implement a 1V1 video application in one hour

On September 21st, Rongyun Live Class The shortest monetization path for social pan-entertainment to go global: How to quickly implement a 1V1 video application? Welcome to click on the mini program to register~

Rongyun CallPlus SDK, a powerful tool for realizing 1V1 audio and video and remote service applications, is online! Follow [Rongyun Global Internet Communication Cloud] to learn more

As a new generation audio and video call scene-based SDK, Rongyun CallPlus fully encapsulates the entire call process such as dialing, answering, and hanging up. It supports one-to-one and multi-person audio and video calls, with complete functions and smooth experience. Smooth and in line with the interaction preferences of overseas users.

This article will take Android integration as an example to share practical tutorials:

Use Rongyun CallPlus SDK to integrate 1V1 video calling capabilities in one hour.

An RTC real-time audio and video bottom layer developer with zero experience can easily implement audio and video with just 3 core APIs and 4 steps Calling ability. Moreover, Rongyun provides Quick Demo source code for developers to integrate for reference.

Precondition

Create a Rongyun developer account

Create a Rongyun developer account and obtain an App Key.

Before starting, you need to create a Rongyun developer account and obtain an App Key. In the developer backend, the system will automatically create an application for the new account. By default, the domestic data center is used and a development environment is provided. If you already have a Rongyun developer account, you can create a new application directly.

Import SDK

Open build.gradle in the root directory (the new version of Android studio is settings.gradle), and in the Project view, declare Rongyun’s Maven code library.

allprojects {
  repositories {
      ...
      //Rongyun maven warehouse address
      maven {url "https://maven.rongcloud.cn/repository/maven-releases/"}
  }
}

Add dependencies

In your app’s build.gradle, add the following remote dependencies.

Note: Rongyun CallPlus business relies on IM channels, so IMLibCore SDK must be integrated at the same time.

dependencies {
  // Please fill in the specific SDK version number. New integrated users are recommended to use the latest version. Here we take version 5.6.2 as an example.
  implementation 'cn.rongcloud.sdk:im_libcore:5.6.2' // Instant messaging basic capability library.
  implementation 'cn.rongcloud.sdk:callplus_lib:1.0.0'// Audio and video call capability library (including rtc_lib)
}

Permission Statement

Declare all permissions required by the SDK in AndroidManifest.xml.

<!-- Allow programs to access network connections -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- Allows the program to obtain network information status, such as whether the current network connection is valid -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<!-- Allows the program to obtain the current WiFi access status and WLAN hotspot information -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!-- Allow the program to access the camera to take pictures -->
<uses-permission android:name="android.permission.CAMERA" />
<!-- Allows the program to record sound through the microphone of the phone or headset -->
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<!-- Allow the program to modify sound setting information -->
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<!--Allow the program to access the phone status. For example, when receiving a call from the SIM card during a call, the SIM card call status will be notified to the remote user, so this permission is required-->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />

Note: If you develop an application that needs to support devices running Android 6.0 (API level 23) or higher, you also need to request camera (CAMERA) and microphone (RECORD_AUDIO) permissions when the App user uses corresponding functions (such as making calls and answering calls).

For details, see the official Android developer documentation for runtime permissions and workflow for requesting permissions.

Formal integration

Before embarking on implementation, we need to pay attention to the following key points:

? How to initiate a call
? How to receive incoming calls
? After the call is connected, how will the call interface of both parties be displayed?

To realize the call function, it must be based on that both ends have successfully connected to Rongyun. Refer to the process sequence diagram of the 1V1 calling end and the called end shown in the figure below.

Calling end timing diagram:

Called end timing diagram:

Initialize connection to Rongyun

CallPlus for Android relies on the Rongyun instant messaging client SDK to provide signaling channels, so IMLibCore needs to be initialized first, and it is recommended to put it in Application.

String appKey = "Your_AppKey"; // example: bos9p5rlcm2ba Create a Rongyun developer account and obtain the App Key.
InitOption initOption = new InitOption.Builder().build();
RongCoreClient.init(getApplicationContext(), appKey, initOption);

To make and receive one-to-one calls or start a multi-person call, you must first connect to the RongCloud server through the connect method of RongCoreClient.

Pass in the user identity token (Token) to verify the user identity with the Rongyun server; after the connection is successful, use the RCCallPlusClient.getInstance().init() method to initialize and configure the CallPlus SDK.

String token = "User Token"; // After you apply for a developer account, you can directly generate a user token at the Polaris location in the Rongyun backend.
RongCoreClient.connect(token, new IRongCoreCallback.ConnectCallback() {
   /**
    * Successful callback
    * @param userId current user ID
    */
   @Override
   public void onSuccess(String userId) {
      runOnUiThread(new Runnable() {
          @Override
          public void run() {
              //todo Although it is not necessary to initialize RCCallPlusClient in the main thread, considering that subsequent calls to RCCallPlusClient in the code example are all made in the main thread, we currently choose to initialize it in the main thread.
              //todo Please make sure to initialize, deinitialize and use RCCallPlusClient in the same thread to ensure consistency of operations.
              RCCallPlusConfig config = RCCallPlusConfig.Builder.create().build();
              /**
               * Initialize and set the global configuration of the call. When this method is called repeatedly, the SDK will be re-initialized internally.
               * @param config sets the global configuration of the call
               * @return The result is returned synchronously after the method is called. You can get whether the initialization is successful here.
               */
              RCCallPlusResultCode resultCode = RCCallPlusClient.getInstance().init(config);
          }
      });

   }
   /**
    * Error callback
    * @param errorCode error code
    */
   @Override
   public void onError(IRongCoreEnum.ConnectionErrorCode errorCode) {

   }

   /**
    * Database callback.
    * @param code Database open status. DATABASE_OPEN_SUCCESS The database is opened successfully; DATABASE_OPEN_ERROR The database is opened failed.
    */
   @Override
   public void onDatabaseOpened(DatabaseOpenStatus code) {

   }
});

Initiate a call and set local and remote views

Use the startCall method to initiate a one-to-one call.

This method will be executed asynchronously internally, and the result of the method will be obtained through the IRCCallPlusResultListener#onStartCall callback.

Before initiating a call, you need to set the local and remote views. When the other end answers the video call, the local end will automatically render the other end’s view.

Use the setCallPlusResultListener method to add a call API asynchronous result callback listener. This listener can receive result callbacks from methods such as startCall, accept, and hangup.

Make a call:

 private void startCall(String remoteUserId) {
        //todo to open camera collection, please complete the dynamic application for camera and microphone permissions in advance
        RCCallPlusClient.getInstance().startCamera();
        RCCallPlusClient.getInstance().enableMicrophone(true);

        //Set the local view
        setLocalVideoView();
        //Set the peer view
        setRemotVideoView(remoteUserId);

        List<String> userIds = new ArrayList<>();
        userIds.add(remoteUserId);//todo remoteUserId is the userId of the remote user being called
        RCCallPlusType callType = RCCallPlusType.PRIVATE;//PRIVATE: 1V1 call
        RCCallPlusMediaType mediaType = RCCallPlusMediaType.VIDEO;
        /**
         * Start making a call
         * This method is executed asynchronously internally, and the result callback is the registered {@link RCCallPlusClient#setCallPlusResultListener(IRCCallPlusResultListener)} listener {@link IRCCallPlusResultListener#onStartCall(RCCallPlusCode, String, List)} method<br>
         */
        RCCallPlusClient.getInstance().startCall(userIds, callType, mediaType);
    }

Initiator sets local view:

 /**
    * Set local video rendering view
    */
   private void setLocalVideoView() {
       //Create local view object
       RCCallPlusLocalVideoView localVideoView = new RCCallPlusLocalVideoView(this.getApplicationContext());
       //FIT: The video frame is scaled to fit the size of the view by maintaining the aspect ratio (possibly showing a black border)
       localVideoView.setRenderMode(RCCallPlusRenderMode.FIT);
       //Set local view to SDK
       RCCallPlusClient.getInstance().setVideoView(localVideoView);

       FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
       params.gravity = Gravity.CENTER_HORIZONTAL;//Display horizontally and centered in the parent layout
       //Add local view to XML for display
       //In the sample code, mLocalVideoViewFrameLayout is the android.widget.FrameLayout object
       mLocalVideoViewFrameLayout.removeAllViews();
       mLocalVideoViewFrameLayout.addView(localVideoView, params);
   }

The initiator sets the peer view:

 /**
    * Set the peer video rendering view when initiating a call
    */

private void setRemotVideoView(String remoteUserId) {
    //Create a remote view object remoteUserId is the remote user userId
    RCCallPlusRemoteVideoView remoteVideoView = new RCCallPlusRemoteVideoView(remoteUserId, this.getApplicationContext(), false);
    //FIT: The video frame is scaled to fit the size of the view by maintaining the aspect ratio (possibly showing a black border)
    remoteVideoView.setRenderMode(RCCallPlusRenderMode.FIT);
    //Because the remote view is displayed at the top level, in order to prevent the remote video view from being blocked by the bottom controls, add the following settings:
    remoteVideoView.setZOrderOnTop(true);
    remoteVideoView.setZOrderMediaOverlay(true);

    List<RCCallPlusRemoteVideoView> remoteVideoViewList = new ArrayList<>(); remoteVideoViewList.add(remoteVideoView);
    //Set the remote view to SDK
    RCCallPlusClient.getInstance().setVideoView(remoteVideoViewList);

    FrameLayout.LayoutParams remoteVideoViewParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
    remoteVideoViewParams.gravity = Gravity.CENTER_HORIZONTAL;
    //Add the remote view to XML for display
    //In the sample code, mRemoteVideoViewFrameLayout is the android.widget.FrameLayout object
    mRemoteVideoViewFrameLayout.removeAllViews();
    mRemoteVideoViewFrameLayout.addView(remoteVideoView, remoteVideoViewParams);
}

The receiving end answers the call and sets the local and remote views

You can choose to answer or hang up the call. To answer the call, use the accept method; to hang up the call, use the RCCallPlusClient.getInstance().hangup() method.

The CallId value required to perform answer and hang up operations can be obtained through the RCCallPlusSession#getCallId() method.

To receive remote call notification, you must ensure that you have registered IRCCallPlusEventListener and implemented the onReceivedCall(RCCallPlusSession callSession) method. The called user receives the incoming call notification through the connection with the Rongyun server or offline push notification (the offline push App must have integrated push from third-party manufacturers, see Push 2.0 Integration Overview for details).

Use the setCallPlusEventListener method to add call event monitoring and provide callbacks related to incoming call events, call status, call records and other events.

Add call event listener:

RCCallPlusClient.getInstance().setCallPlusEventListener(new IRCCallPlusEventListener() {

    /**
     * The user receives a call through this callback. In this callback, the call can be answered.
     *
     * @param callSession call entity information<br>
     */
    @Override
    public void onReceivedCall(RCCallPlusSession callSession) {
        RCCallPlusSession currentCallSession = RCCallPlusClient.getInstance().getCurrentCallSession();
        if (currentCallSession != null & amp; & amp; !TextUtils.equals(callSession.getCallId(), currentCallSession.getCallId())) {
            //You can use this method to determine whether there is a call in progress and a second call coming in.<br>
            //todo The second call can be answered directly by calling the RCCallPlusClient.getInstance().accept method. The SDK will hang up the first call internally.
        }

        //Todo SDK callbacks are all called by sub-threads. There are UI operations in the showDialog() method, so switch to the main thread for execution.
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                //todo to open camera collection, please complete the dynamic application for camera and microphone permissions in advance
                RCCallPlusClient.getInstance().startCamera();
                RCCallPlusClient.getInstance().enableMicrophone(true);

                setLocalVideoView();//Reuse the method of setting the local video rendering view in the logic of initiating a call

                showDialog(CallPlusActivity.this, "Received a call, do you want to answer it?", "Answer", new OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {
                        acceptCall(callSession);
                    }
                }, "Hang up", new OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {
                        RCCallPlusClient.getInstance().hangup();
                    }
                });
            }
        });
    }

    @Override
    public void onCallEnded(RCCallPlusSession session, RCCallPlusReason reason) {
        IRCCallPlusEventListener.super.onCallEnded(session, reason);
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(CallPlusActivity.this, "Call ended, callId: " + session.getCallId() + " Call ended reason: " + reason.getValue(), Toast.LENGTH_SHORT).show();
            }
        });
    }

    /**
     * Remote user status change monitoring<br>
     *
     * @param callId callId<br>
     * @param userId userId<br>
     * @param status The current status of the user<br>
     * @param reason The reason for the user's current status<br>
     */
    @Override
    public void onRemoteUserStateChanged(String callId, String userId, RCCallPlusUserSessionStatus status, RCCallPlusReason reason) {
        IRCCallPlusEventListener.super.onRemoteUserStateChanged(callId, userId, status, reason);
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                StringBuilder stringBuilder = new StringBuilder("call");
                stringBuilder.append(callId).append("Remote user in ").append(userId).append("The current status is ");
                switch (status) {
                    case CALLING:
                        stringBuilder.append("Calling");
                        break;
                    case INVITED:
                        stringBuilder.append("Invited");
                        break;
                    case CONNECTING:
                        stringBuilder.append("Received, connecting");
                        break;
                    case ON_CALL:
                        stringBuilder.append("Call in progress");
                        break;
                    case ENDED:
                        stringBuilder.append("The call has ended");
                        break;
                }
                Toast.makeText(CallPlusActivity.this, stringBuilder.toString(), Toast.LENGTH_SHORT).show();
            }
        });
    }
});

How to answer a call:

private void acceptCall(RCCallPlusSession callSession) {
    setRemoteUserVideoView(callSession.getRemoteUserList());
    /**
     * Start answering the call
     * This method is executed asynchronously internally, and the result callback is the registered {@link RCCallPlusClient#setCallPlusResultListener(IRCCallPlusResultListener)} listener {@link IRCCallPlusResultListener#onAccept(RCCallPlusCode, String)} method<br>
     */
    RCCallPlusClient.getInstance().accept(callSession.getCallId());
}

Set the local and remote views on the receiving end:

/**
 * The receiving party sets the remote user's video rendering view
 */
private void setRemoteUserVideoView(List<RCCallPlusUser> remoteUserList) {
    List<RCCallPlusRemoteVideoView> remoteVideoViewList = new ArrayList<>();
    for (RCCallPlusUser callPlusUser : remoteUserList) {
        RCCallPlusRemoteVideoView remoteVideoView = new RCCallPlusRemoteVideoView(callPlusUser.getUserId(), this.getApplicationContext(), false);
        //The video frame is scaled to fit the size of the view by maintaining the aspect ratio (possibly showing a black border)
        remoteVideoView.setRenderMode(RCCallPlusRenderMode.FIT);
        remoteVideoViewList.add(remoteVideoView);
        //In this sample code, because the remote view is displayed at the top level, in order to prevent the remote video view from being blocked by the bottom control (view), the following settings are added:
        remoteVideoView.setZOrderOnTop(true);
        remoteVideoView.setZOrderMediaOverlay(true);

        FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
        params.gravity = Gravity.CENTER_HORIZONTAL;
        //todo Add each remote view (remoteVideoView) to XML for display. When there are multiple people at the remote end, you need to add it to multiple controls for display. This sample code only shows one remote user.
        mRemoteVideoViewFrameLayout.removeAllViews();
        mRemoteVideoViewFrameLayout.addView(remoteVideoView, params);
    }
    /**
     * Set the remote user video stream rendering view to the SDK
     * If the video rendering view is not set for the remote user, there will be no downstream traffic for the user's video stream.
     */
    RCCallPlusClient.getInstance().setVideoView(remoteVideoViewList);
}
private AlertDialog showDialog(Context context, String content, String positiveBtn, final DialogInterface.OnClickListener positiveListener, final String negativeBtn, final DialogInterface.OnClickListener negativeListener) {
    AlertDialog.Builder builder = new AlertDialog.Builder(context);
    builder = builder.setMessage(content);
    builder.setCancelable(false);
    if (!TextUtils.isEmpty(positiveBtn)) {
        builder.setPositiveButton(positiveBtn, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                if (positiveListener != null) {
                    positiveListener.onClick(dialog, which);
                } else {
                    dialog.dismiss();
                }
            }
        });
    } if (!TextUtils.isEmpty(negativeBtn)) {
        builder.setNegativeButton(negativeBtn, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                if (negativeListener != null) {
                    negativeListener.onClick(dialog, which);
                } else {
                    dialog.dismiss();
                }
            }
        });
    } return builder.show();
}

Run the project to initiate a call. When the called end answers and the calling end can see the video of both parties, it means that the core capabilities of 1V1 audio and video calls have been implemented. The whole process only requires 4 steps and 3 core APIs.

Other functions

Switch front and rear cameras

After successfully opening the camera, you can use the switchCamera method to switch between the front and rear cameras.

The switchCamera method is called asynchronously and supports obtaining the call result through the onSwitchCamera callback of IRCCallPlusResultListener.

RCCallPlusClient.getInstance().switchCamera();
RCCallPlusClient.getInstance().setCallPlusResultListener(new IRCCallPlusResultListener() {
    /**
     * Switching front and rear camera method result callback<br>
     *
     * @param code method request result<br>
     * @param isFrontCamera Whether the currently turned on camera is the front camera<br>
     */
    @Override
    public void onSwitchCamera(RCCallPlusCode code, boolean isFrontCamera) {
        IRCCallPlusResultListener.super.onSwitchCamera(code, isFrontCamera);
    }
});

Beauty

Rongyun SDK has been connected to professional third-party beautification services, and the beautification function can be implemented in three steps.

  1. Add the following remote dependencies in your app’s build.gradle.

    implementation 'cn.rongcloud.sdk:fu_beautifier:5.6.2'
    implementation 'androidx.core:core-ktx:1.7.0'
  2. Provide a valid beauty authorization document (if interested, please contact Rongyun Business for detailed consultation: 131 6185 6839).
  3. Initialize the beauty plug-in. Please provide a valid beauty authorization file during initialization. It only needs to be called once during application running, and it is recommended to initialize it in Application#onCreate.

authpackNew in the code block below is the authorization file for the relevant beauty service.

RCRTCFUBeautifierEngine.getInstance()
        .register(
                getApplicationContext(),
                null,
                authpackNew.A(),
                new FUBeautifierResultCallback() {
                    @Override
                    public void onSuccess() {
                        setBeautyEnable();
                        SetBeautyParameters();
                    }

                    @Override
                    public void onFailed(int code) {
                    }
                });
private void setBeautyEnable() {
    // The beauty effect you set will take effect only after the beauty switch is turned on; the beauty effect will be invalid when the beauty switch is turned off.
    RCRTCFUBeautifierEngine.getInstance().setBeautyEnable(true, new FUBeautifierResultCallback() {
        @Override
        public void onSuccess() {
        }

        @Override
        public void onFailed(int code) {

        }
    });
}
//Set beauty parameters
private void SetBeautyParameters() {
    RCRTCFBeautifierEngine.getInstance().setBlurIntensity(6); Range[0-6]
    RCRTCFBeautifierEngine.getInstance().setColorIntensity(2); // Range [0-2]
    RCRTCFBeautifierEngine.getInstance().setRedIntensity(2);//Range [0-2]
    RCRTCFBeautifierEngine.getInstance().setSharpenIntensity(1);//Range [0-1]
    RCRTCFBeautifierEngine.getInstance().setEyeBrightIntensity(1); // Range [0-1]
    RCRTCFBeautifierEngine.getInstance().setToothIntensity(1);//Range [0-1]
    RCRTCFBeautifierEngine.getInstance().setRemovePouchIntensity(1);//Range [0-1]
    RCRTCFBeautifierEngine.getInstance().setRemoveLawPatternIntensity(1);//Range [0-1]
}

During the entire process of business development, integration, and online operations, Rongyun will provide full-process one-stop technical service support. Developers can submit work orders to communicate with Rongyun engineers. Welcome to call us for consultation: 131 6185 6839

Finally, callback the core advantages of Rongyun CallPlus SDK:

Complete package: Provides a complete call function solution, including connection, calling, answering, rejecting, hanging up, call status notification, etc.

Convenient integration: The interface design is business-friendly and concise. Combined with the Quick Demo source code, developers only need to use 3 core interfaces to implement the core functions of audio and video calls in one hour.

Comprehensive scenarios: Supports iOS, Android, Web and other platforms, and can be used in a variety of single and multi-person call scenarios such as socializing with strangers, online recruitment, telemedicine, online consultation, after-sales customer service, etc.

Stable service: 100% reliable audio and video call signaling capabilities to ensure a safe and reliable connection; Audio weak network withstands packet loss by 80%, and video weak network Anti-packet loss 60%and equipped with 3A algorithm to ensure clear and stable calls.

Peripheral perfection: Provides rich advanced functions required for business scenarios, including content review, cloud recording, advanced beautification, etc., making developers’ business operations worry-free and efficient.

High cost performance: The current monthly function fee is only 1,500 yuan/month, including 200,000 free minutes. The scene is highly flexible, with no restrictions on audio and video, and the highest video resolution can support 2K+; truly worry-free and transparent, it supports separate procurement of RTC and IM services, and does not charge separate call signaling fees.