How to create audio and video call app in android studio using Sinch SDK

audio and video call in android studio

In this post, I will create simple android app for audio calling and video call (app to app) using Sinch SDK. Before going forward, I want to tell you something important that is logic, I will be using for video call services for both audio and video call the difference is that i will not allow to video streaming for audio call initially, later user can allow video streaming. The benefit of using this logic is that you can easily switch from audio to video call during a call. If you use ordinary way, like for audio call you use audio services and for video call you use video service, so the problem of doing that is no switching from audio to video call during a call, Sinch SDK not allowing you that.

 

Advantage of using Sinch SDK for Audio and Video calling

 

Sinch is basically a product which is used for video, audio calling and instant messaging over 150 countries and it is supported in android, IOS and web. The good thing about it, is that it saves a lot of time in writing a code for audio management, handling complexity of signals, video management and networking, it contain build in functions to use loud speaker as on or off and mute the your voice or unmute, also you can handle your camera in video call, you can do all these complicated things in just 2 line of code. The other good thing about it is that it give 2500+ minutes free per month, which is very good for testing and also use.

 

How to Install Sinch SDK in your Android Studio (Sep 2019 method)

 

1. First Download (Sinch ARR File for android) this file and put this file lib directory  of your android studio project.

2.Open build gradle and add this line of code in dependency ( “implementation(name: ‘sinch-android-rtc’,version: ‘+’, ext:’aar’)”)
audio and video in android part2

3.Open build gradle as project and add this line of code in repositories ( ” flatDir { dirs ‘libs’} “).

audio and video in android part3

4. Now Sync your android project to install Sinch sdk successfully.

 

 

Importants things you must know about Sinch SDK.

 

First, in order to use Sinch services, you must bounded background services otherwise it will not work properly, background service will help you to run app functionality when your app is sleeping or destroyed. Other important thing is that sinch have its own database of user id. Suppose if your app have 5 users then you have initialize 5 different user id during creating sinch service, the best way is that when user login to app then initialize unique id for that user. You can call to other user this unique id, it is identifier for different users.

 

View Code 

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;

import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.ValueEventListener;
import com.saifyproduction.sunupayApp.view.Incoming_voice_call;
import com.saifyproduction.sunupayApp.view.incoming_video_call;
import com.sinch.android.rtc.AudioController;
import com.sinch.android.rtc.ClientRegistration;
import com.sinch.android.rtc.Sinch;
import com.sinch.android.rtc.SinchClient;
import com.sinch.android.rtc.SinchClientListener;
import com.sinch.android.rtc.SinchError;
import com.sinch.android.rtc.calling.Call;
import com.sinch.android.rtc.calling.CallClient;
import com.sinch.android.rtc.calling.CallClientListener;
import com.sinch.android.rtc.video.VideoController;

import androidx.annotation.NonNull;

public class SinchService extends Service {

    private static final String APP_KEY = "";
    private static final String APP_SECRET = "";
    private static final String ENVIRONMENT = "";
    static int state  ;


    public static final String CALL_ID = "CALL_ID";
    static final String TAG = SinchService.class.getSimpleName();

    private SinchServiceInterface mSinchServiceInterface = new SinchServiceInterface();
    private SinchClient mSinchClient;
    private String mUserId;

    private StartFailedListener mListener;

    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Override
    public void onDestroy() {
        if (mSinchClient != null && mSinchClient.isStarted()) {
            mSinchClient.terminate();
        }
        super.onDestroy();
    }

    private void start(String userName) {
        if (mSinchClient == null) {
            mUserId = userName;
            mSinchClient = Sinch.getSinchClientBuilder().context(getApplicationContext()).userId(userName)
                    .applicationKey(APP_KEY)
                    .applicationSecret(APP_SECRET)
                    .environmentHost(ENVIRONMENT).build();

            mSinchClient.setSupportCalling(true);
            mSinchClient.startListeningOnActiveConnection();

            mSinchClient.addSinchClientListener(new MySinchClientListener());
            mSinchClient.getCallClient().addCallClientListener(new SinchCallClientListener());
            mSinchClient.start();
        }
    }

    private void stop() {
        if (mSinchClient != null) {
            mSinchClient.terminate();
            mSinchClient = null;
        }
    }

    private boolean isStarted() {
        return (mSinchClient != null && mSinchClient.isStarted());
    }

    @Override
    public IBinder onBind(Intent intent) {
        return mSinchServiceInterface;
    }

    public class SinchServiceInterface extends Binder {

        public Call callUserVideo(String userId, int i ) {

            state  = i;
            return mSinchClient.getCallClient().callUserVideo(userId);
        }


        public Call callUseraudio(String userId) {

            return mSinchClient.getCallClient().callUser(userId);
        }




        public String getUserName() {
            return mUserId;
        }

        public boolean isStarted() {
            return SinchService.this.isStarted();
        }

        public void startClient(String userName) {
            start(userName);
        }

        public void stopClient() {
            stop();
        }

        public void setStartListener(StartFailedListener listener) {
            mListener = listener;
        }

        public Call getCall(String callId) {
            return mSinchClient.getCallClient().getCall(callId);
        }

        public VideoController getVideoController() {
            if (!isStarted()) {
                return null;
            }
            return mSinchClient.getVideoController();
        }

        public AudioController getAudioController() {
            if (!isStarted()) {
                return null;
            }
            return mSinchClient.getAudioController();
        }
    }

    public interface StartFailedListener {

        void onStartFailed(SinchError error);

        void onStarted();
    }

    private class MySinchClientListener implements SinchClientListener {

        @Override
        public void onClientFailed(SinchClient client, SinchError error) {
            if (mListener != null) {
                mListener.onStartFailed(error);
            }
            mSinchClient.terminate();
            mSinchClient = null;
        }

        @Override
        public void onClientStarted(SinchClient client) {
            Log.d(TAG, "SinchClient started");
            if (mListener != null) {
                mListener.onStarted();
            }
        }

        @Override
        public void onClientStopped(SinchClient client) {
            Log.d(TAG, "SinchClient stopped");
        }

        @Override
        public void onLogMessage(int level, String area, String message) {
            switch (level) {
                case Log.DEBUG:
                    Log.d(area, message);
                    break;
                case Log.ERROR:
                    Log.e(area, message);
                    break;
                case Log.INFO:
                    Log.i(area, message);
                    break;
                case Log.VERBOSE:
                    Log.v(area, message);
                    break;
                case Log.WARN:
                    Log.w(area, message);
                    break;
            }
        }

        @Override
        public void onRegistrationCredentialsRequired(SinchClient client,
                                                      ClientRegistration clientRegistration) {
        }
    }

    private class SinchCallClientListener implements CallClientListener {

        @Override
        public void onIncomingCall(CallClient callClient, final Call call) {


            FirebaseAuth auth = FirebaseAuth.getInstance();
            DatabaseReference cal = FirebaseDatabase.getInstance().getReference().child("call_detail").child(auth.getCurrentUser().getUid()).child(call.getCallId());


            cal.addListenerForSingleValueEvent(new ValueEventListener() {
                @Override
                public void onDataChange(@NonNull DataSnapshot dataSnapshot) {



                    if(dataSnapshot.exists()){

                       String cl = dataSnapshot.child("calltype").getValue(String.class);

                        if( cl.equalsIgnoreCase("audio") ){


                            Log.d(TAG, "Incoming call");
                            Intent intent = new Intent(SinchService.this, Incoming_voice_call.class);
                            intent.putExtra(CALL_ID, call.getCallId());
                            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                            SinchService.this.startActivity(intent);



                        }
                        else{


                            Log.d(TAG, "Incoming call");
                            Intent intent = new Intent(SinchService.this, incoming_video_call.class);
                            intent.putExtra(CALL_ID, call.getCallId());
                            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                            SinchService.this.startActivity(intent);



                        }


                    }


                }

                @Override
                public void onCancelled(@NonNull DatabaseError databaseError) {

                }
            });



        }
    }

}
 

Important Points

 

Create account in Sinch, and get three detail from there and put in your code in Sinch Service class

 

private static final String APP_KEY = “”;
private static final String APP_SECRET = “”;
private static final String ENVIRONMENT = “”;

 

Thats it, any question and issue you can ask in comment section. Thank you.

Whole Project source code is not free, you need to buy it and its cost is 10$, if you are interested to buy text on Facebook Page so I will provide you downloadable link after payment. Thank you