I implemented video call in my app using quick box
Let me guide you to implement video calling using the quick box.
Step 1:-
Use latest version of quickblox
compile 'com.quickblox:quickblox-android-sdk-core:3.3.0@aar'
compile 'com.quickblox:quickblox-android-sdk-videochat-webrtc:3.3.0'
Step2:-
Login to chat service as specified in quickblox to use video call functions
create an Activity to handle outgoing calls
I used two intent extras is outgoing and service to know outgoing or incoming connections and act for the situation also you need user quickblox id that you are going to call
package com.dev.trueme;
import android.media.MediaPlayer;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.inputmethod.InputMethod;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.quickblox.auth.session.QBSession;
import com.quickblox.auth.session.QBSessionManager;
import com.quickblox.chat.QBChatService;
import com.quickblox.chat.QBSignaling;
import com.quickblox.chat.QBWebRTCSignaling;
import com.quickblox.chat.listeners.QBVideoChatSignalingManagerListener;
import com.quickblox.videochat.webrtc.QBMediaStreamManager;
import com.quickblox.videochat.webrtc.QBRTCCameraVideoCapturer;
import com.quickblox.videochat.webrtc.QBRTCClient;
import com.quickblox.videochat.webrtc.QBRTCSession;
import com.quickblox.videochat.webrtc.QBRTCTypes;
import com.quickblox.videochat.webrtc.callbacks.QBRTCClientSessionCallbacks;
import com.quickblox.videochat.webrtc.callbacks.QBRTCClientVideoTracksCallbacks;
import com.quickblox.videochat.webrtc.view.QBRTCSurfaceView;
import com.quickblox.videochat.webrtc.view.QBRTCVideoTrack;
import org.webrtc.VideoRenderer;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static android.R.attr.action;
import static com.quickblox.videochat.webrtc.QBRTCTypes.QBConferenceType.QB_CONFERENCE_TYPE_VIDEO;
public class VideoCallActivity extends AppCompatActivity implements QBRTCClientSessionCallbacks,QBRTCClientVideoTracksCallbacks {
private int userid;
private Boolean isOutgoing,micE=true,vidE=true;
private QBRTCSurfaceView surfaceView,remoteview;
private MediaPlayer mp;
private QBRTCSession currentsession;
private QBMediaStreamManager mediaStreamManager;
private ImageView mic,video;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_video_call);
userid=getIntent().getIntExtra("user",1);
isOutgoing=getIntent().getBooleanExtra("isoutgoing",false);
ProcessCalls();
InitSignalling();
if (isOutgoing) {
CallUser();
SetCallerName(userid);
}
if(getIntent().getBooleanExtra("service",false)){
SetLayoutForReceiveCall(DataHolder.getInstance().getSession(),DataHolder.getInstance().getUserInfo());
SetCallerName(DataHolder.getInstance().getSession().getCallerID());
Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE);
mp = MediaPlayer.create(getApplicationContext(), notification);
mp.start();
}
mic=(ImageView)findViewById(R.id.mic);
mic.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(micE){
micE=false;
AudioManage();
}else {
micE=true;
AudioManage();
}
}
});
video=(ImageView)findViewById(R.id.video);
video.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(vidE){
vidE=false;
VideoManage();
}else {
vidE=true;
VideoManage();
}
}
});
surfaceView =(QBRTCSurfaceView)findViewById(R.id.localView);
surfaceView.setMirror(true);
surfaceView.requestLayout();
remoteview=(QBRTCSurfaceView)findViewById(R.id.opponentView);
remoteview.requestLayout();
QBRTCClient.getInstance(this).addSessionCallbacksListener(this);
}
private void SetCallerName(Integer callerID) {
TextView callerName=(TextView)findViewById(R.id.callername);
TextView callertime=(TextView)findViewById(R.id.callTime);
callerName.setText(callerID+"");
if(isOutgoing){
callertime.setText("Calling...");
}
}
private void InitSignalling() {
QBChatService.getInstance().getVideoChatWebRTCSignalingManager()
.addSignalingManagerListener(new QBVideoChatSignalingManagerListener() {
@Override
public void signalingCreated(QBSignaling qbSignaling, boolean createdLocally) {
if (!createdLocally) {
QBRTCClient.getInstance(VideoCallActivity.this).addSignaling((QBWebRTCSignaling) qbSignaling);
}
}
});
}
private void ProcessCalls() {
QBRTCClient.getInstance(this).prepareToProcessCalls();
}
private void CallUser() {
//Set conference type
// There are two types of calls:
// - QB_CONFERENCE_TYPE_VIDEO - for video call;
// - QB_CONFERENCE_TYPE_AUDIO - for audio call;
QBRTCTypes.QBConferenceType qbConferenceType = QB_CONFERENCE_TYPE_VIDEO;
//Initiate opponents list
List<Integer> opponents = new ArrayList<Integer>();
opponents.add(userid); //12345 - QBUser ID
//Set user information
// User can set any string key and value in user info
// Then retrieve this data from sessions which is returned in callbacks
// and parse them as he wish
Map<String, String> userInfo = new HashMap<>();
userInfo.put("key", "value");
//Init session
QBRTCSession session =
QBRTCClient.getInstance(this).createNewSessionWithOpponents(opponents, qbConferenceType);
//Start call
session.startCall(userInfo);
SetCallButtonsDialing(session,userInfo);
StartDialRinging();
}
private void SetCallButtonsDialing(final QBRTCSession session, final Map<String, String> userInfo) {
FrameLayout call=(FrameLayout)findViewById(R.id.CallerLayout);
call.setVisibility(View.VISIBLE);
findViewById(R.id.Endcall).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
session.hangUp(userInfo);
VideoCallActivity.this.finish();
}
});
}
public void AudioManage(){
if(mediaStreamManager!=null) {
if (mediaStreamManager.isAudioEnabled()) {
mediaStreamManager.setAudioEnabled(false);
mic.setImageResource(R.drawable.ic_mic_off_black_24dp);
} else {
mediaStreamManager.setAudioEnabled(true);
mic.setImageResource(R.drawable.ic_mic_black_24dp);
}
}
}
public void VideoManage(){
if(mediaStreamManager!=null) {
if (mediaStreamManager.isVideoEnabled()) {
mediaStreamManager.setVideoEnabled(false);
video.setImageResource(R.drawable.ic_videocam_off_black_24dp);
} else {
mediaStreamManager.setVideoEnabled(true);
video.setImageResource(R.drawable.ic_videocam_black_24dp);
}
}
}
@Override
public void onReceiveNewSession(QBRTCSession qbrtcSession) {
qbrtcSession.addVideoTrackCallbacksListener(this);
Map<String,String> userInfo = qbrtcSession.getUserInfo();
SetLayoutForReceiveCall(qbrtcSession,userInfo);
}
private void SetLayoutForReceiveCall(final QBRTCSession qbrtcSession,final Map<String, String> userInfo) {
final FrameLayout receive=(FrameLayout)findViewById(R.id.answerlayout);
receive.setVisibility(View.VISIBLE);
qbrtcSession.addVideoTrackCallbacksListener(this);
final ImageView calll=(ImageView)findViewById(R.id.answerCall);
calll.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Accept incoming call
qbrtcSession.acceptCall(userInfo);
receive.setVisibility(View.GONE);
SetCallButtonsDialing(qbrtcSession,userInfo);
StartTimer();
if(mp!=null&&mp.isPlaying())
{
mp.stop();
}
}
});
findViewById(R.id.rejectcall).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
qbrtcSession.rejectCall(userInfo);
VideoCallActivity.this.finish();
if(mp!=null&&mp.isPlaying())
{
mp.stop();
}
}
});
}
private void StartTimer() {
final TextView timer=(TextView)findViewById(R.id.callTime);
timer.setText("00:00");
final Handler handler = new Handler();
Runnable runnable = new Runnable() {
private long startTime = System.currentTimeMillis();
public void run() {
while (true) {
try {
Thread.sleep(1000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
handler.post(new Runnable(){
public void run() {
int millis=(int)(System.currentTimeMillis() - startTime)/1000;
int min=millis/60;
int sec=millis%60;
timer.setText((min<10?"0"+min:min)+":"+(sec<10?"0"+sec:sec));
}
});
}
}
};
new Thread(runnable).start();
}
@Override
public void onUserNoActions(QBRTCSession qbrtcSession, Integer integer) {
Toast.makeText(this, "no action by user", Toast.LENGTH_SHORT).show();
if(mp!=null&&mp.isPlaying())
{
mp.stop();
}
}
@Override
public void onSessionStartClose(QBRTCSession qbrtcSession) {
qbrtcSession.addVideoTrackCallbacksListener(this);
try {
qbrtcSession.getMediaStreamManager().setVideoCapturer(new QBRTCCameraVideoCapturer(this, null));
mediaStreamManager = qbrtcSession.getMediaStreamManager();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onUserNotAnswer(QBRTCSession qbrtcSession, Integer integer) {
Toast.makeText(this, "No answer", Toast.LENGTH_SHORT).show();
if(mp!=null&&mp.isPlaying())
{
mp.stop();
}
finish();
}
@Override
public void onCallRejectByUser(QBRTCSession qbrtcSession, Integer integer, Map<String, String> map) {
Toast.makeText(this, "Call rejected", Toast.LENGTH_SHORT).show();
if(mp!=null&&mp.isPlaying())
{
mp.stop();
}
finish();
}
@Override
public void onCallAcceptByUser(QBRTCSession qbrtcSession, Integer integer, Map<String, String> map) {
qbrtcSession.addVideoTrackCallbacksListener(this);
if(mp!=null&&mp.isPlaying())
{
mp.stop();
}
StartTimer();
}
@Override
public void onReceiveHangUpFromUser(QBRTCSession qbrtcSession, Integer integer, Map<String, String> map) {
if(mp!=null&&mp.isPlaying())
{
mp.stop();
}
Toast.makeText(this, "Call ended by user", Toast.LENGTH_SHORT).show();
finish();
}
@Override
public void onSessionClosed(QBRTCSession qbrtcSession) {
if(mp!=null&&mp.isPlaying())
{
mp.stop();
}
}
@Override
public void onLocalVideoTrackReceive(QBRTCSession qbrtcSession, QBRTCVideoTrack qbrtcVideoTrack) {
qbrtcVideoTrack.addRenderer(new VideoRenderer(surfaceView));
surfaceView.setMirror(true);
surfaceView.requestLayout();
}
@Override
public void onRemoteVideoTrackReceive(QBRTCSession qbrtcSession, QBRTCVideoTrack qbrtcVideoTrack, Integer integer) {
qbrtcVideoTrack.addRenderer(new VideoRenderer(remoteview));
mediaStreamManager = qbrtcSession.getMediaStreamManager();
remoteview.requestLayout();
}
public void StartDialRinging(){
try {
mp = MediaPlayer.create(getApplicationContext(), R.raw.beep);
mp.setLooping(true);
mp.start();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Step 3:-
XML code for above activity
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.dev.trueme.VideoCallActivity">
<com.quickblox.videochat.webrtc.view.QBRTCSurfaceView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res-auto"
android:id="@+id/localView"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_width="100dp"
android:layout_height="100dp" />
<com.quickblox.videochat.webrtc.view.QBRTCSurfaceView
android:id="@+id/opponentView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<FrameLayout
android:layout_width="match_parent"
android:layout_alignParentTop="true"
android:background="#59777777"
android:layout_height="100dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:id="@+id/callername"
android:layout_margin="20dp"
android:text="msdkbjdshbs"
android:textColor="@color/white"
android:layout_height="wrap_content" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginStart="20dp"
android:id="@+id/callTime"
android:textColor="@color/white"
android:layout_below="@+id/callername"/>
</RelativeLayout>
</FrameLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_alignParentBottom="true"
android:layout_marginBottom="20dp"
android:visibility="gone"
android:id="@+id/answerlayout"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:weightSum="2"
android:orientation="horizontal"
android:layout_height="wrap_content">
<RelativeLayout
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content">
<ImageView
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_centerInParent="true"
android:id="@+id/answerCall"
android:background="@drawable/shape_oval_white_green"
android:src="@drawable/ic_phone_black_24dp"/>
</RelativeLayout>
<RelativeLayout
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content">
<ImageView
android:layout_width="60dp"
android:layout_height="60dp"
android:id="@+id/rejectcall"
android:tint="@color/white"
android:layout_centerInParent="true"
android:background="@drawable/shape_oval_white_red"
android:src="@drawable/ic_call_end_black_24dp"/>
</RelativeLayout>
</LinearLayout>
</FrameLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_alignParentBottom="true"
android:visibility="visible"
android:background="#33000000"
android:id="@+id/CallerLayout"
android:layout_height="wrap_content">
<RelativeLayout
android:layout_width="match_parent"
android:layout_marginBottom="20dp"
android:layout_height="wrap_content">
<ImageView
android:layout_width="60dp"
android:layout_height="60dp"
android:id="@+id/mic"
android:layout_toLeftOf="@+id/Endcall"
android:layout_toStartOf="@+id/Endcall"
android:layout_marginRight="20dp"
android:layout_marginEnd="20dp"
android:src="@drawable/ic_mic_black_24dp"/>
<ImageView
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_centerInParent="true"
android:id="@+id/Endcall"
android:tint="@color/white"
android:background="@drawable/shape_oval_white_red"
android:src="@drawable/ic_call_end_black_24dp"/>
<ImageView
android:layout_width="60dp"
android:layout_height="60dp"
android:id="@+id/video"
android:layout_toRightOf="@+id/Endcall"
android:layout_toEndOf="@+id/Endcall"
android:layout_marginLeft="20dp"
android:layout_marginStart="20dp"
android:src="@drawable/ic_videocam_black_24dp"/>
</RelativeLayout>
</FrameLayout>
</RelativeLayout>
Step 4:-
You need to create a service that listens for incoming call.
package com.dev.trueme;
import android.app.Service;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Handler;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;
import com.quickblox.chat.QBChatService;
import com.quickblox.chat.QBSignaling;
import com.quickblox.chat.QBWebRTCSignaling;
import com.quickblox.chat.listeners.QBVideoChatSignalingManagerListener;
import com.quickblox.users.model.QBUser;
import com.quickblox.videochat.webrtc.QBRTCClient;
import com.quickblox.videochat.webrtc.QBRTCSession;
import com.quickblox.videochat.webrtc.callbacks.QBRTCClientSessionCallbacks;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import static com.dev.trueme.TrueMeConstants.TRUE_ME_USERNEME;
public class VideoCallService extends Service implements QBRTCClientSessionCallbacks {
private Timer mTimer = null;
private Handler mHandler = new Handler();
public static final int notify = 300000;
public VideoCallService() {
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
try {
Log.wtf("service", "start");
if (mTimer != null) {
// mTimer.cancel();
Log.wtf("service", "All ready started");
} else {
mTimer = new Timer(); //recreate new
mTimer.scheduleAtFixedRate(new TimeDisplay(), 0, notify);
LoginChatService();
ProcessCalls();
InitSignalling();
QBRTCClient.getInstance(this).addSessionCallbacksListener(this);
}
}catch (Exception e){
Log.wtf("ex",""+e);
}
return START_NOT_STICKY;
}
private class TimeDisplay extends TimerTask {
@Override
public void run() {
// run on another thread
mHandler.post(new Runnable() {
@Override
public void run() {
// display toast
Toast.makeText(VideoCallService.this, "Service is running", Toast.LENGTH_SHORT).show();
}
});
}
}
private void InitSignalling() {
QBChatService.getInstance().getVideoChatWebRTCSignalingManager()
.addSignalingManagerListener(new QBVideoChatSignalingManagerListener() {
@Override
public void signalingCreated(QBSignaling qbSignaling, boolean createdLocally) {
if (!createdLocally) {
QBRTCClient.getInstance(VideoCallService.this).addSignaling((QBWebRTCSignaling) qbSignaling);
}
}
});
}
public void LoginChatService()
{
Thread thread = new Thread() {
@Override
public void run() {
try {
SharedPreferences logins = getSharedPreferences("LoginPref", 0);
QBUser user = new QBUser(logins.getString(TRUE_ME_USERNEME, ""), logins.getString("password", ""));
SharedPreferences s=getSharedPreferences("QBid",0);
user.setId(Integer.valueOf(s.getString("id","")));
if(!QBChatService.getInstance().isLoggedIn()) {
QBChatService.getInstance().login(user);
}
} catch (Exception e) {
e.printStackTrace();
}
}
};
thread.start();
}
private void ProcessCalls() {
QBRTCClient.getInstance(this).prepareToProcessCalls();
}
@Override
public void onReceiveNewSession(QBRTCSession qbrtcSession) {
DataHolder.getInstance().setServiceData(qbrtcSession,qbrtcSession.getUserInfo());
startActivity(new Intent(this,VideoCallActivity.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK).putExtra("service",true));
}
@Override
public void onUserNoActions(QBRTCSession qbrtcSession, Integer integer) {
}
@Override
public void onSessionStartClose(QBRTCSession qbrtcSession) {
}
@Override
public void onUserNotAnswer(QBRTCSession qbrtcSession, Integer integer) {
}
@Override
public void onCallRejectByUser(QBRTCSession qbrtcSession, Integer integer, Map<String, String> map) {
}
@Override
public void onCallAcceptByUser(QBRTCSession qbrtcSession, Integer integer, Map<String, String> map) {
}
@Override
public void onReceiveHangUpFromUser(QBRTCSession qbrtcSession, Integer integer, Map<String, String> map) {
}
@Override
public void onSessionClosed(QBRTCSession qbrtcSession) {
}
}