Agora Video Audio Call Example kotlin

29-Dec-2024

Agora Video Audio Call Example kotlin


Output:

























1/ Create an account on Agora:


link to Agora login page: https://sso2.agora.io/en/login







You can login or sign up here. I recommend Google sign in. it is easy and one-click login



2/ After Login you will be redirected to the console dashboard page. 
   

   or you can proceed with this link: https://console.agora.io/v2/project-management


 Click on the project and then click on the Create New button 







after creating the project you will see your project here and notice here given your App ID







Now you need to create a token with the name of your channel.



3/ Go to overview and click on your created app configure link as shown in the picture below








4/ Now you will see your project info and a button Generate Temp Token Click on it







5/ Now Generate a token and copy it will be needed for our app.








Now let's start the coding journey together.


We need a total of 3 Activities:

 1. MainActivity ( for choosing audio or video call )

 2. AudioActivity ( Join for audio call )

 3. VideoActivity ( Join for video call )




6/Add dependency to your build.gradle (app module ) and sync your project




implementation("io.agora.rtc:full-sdk:4.1.1")



7/ Check Your settings.gradle file is there mentioned the mavenCentral()

   if not mentioned then add this


8/ Add the Below Permission to your AndroidManifest.xml file




<uses-feature
android:name="android.hardware.camera"
android:required="false" />

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />




9/  Modify your MainActivity


   9.1/ Modify activity_main.xml




<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:layout_gravity="center"
android:gravity="center"
>
<Button
android:id="@+id/btn_audio"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Join Audio Call" />

<Button
android:id="@+id/btn_video"
android:layout_marginStart="16dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Join Video Call"/>
</LinearLayout>
</LinearLayout>



   9.2/ MainActivity.kt




package com.zissofworks.agoraaudiovideokotlin

import android.content.Intent
import android.content.pm.PackageManager
import android.os.Bundle
import android.widget.Button
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat


class MainActivity : AppCompatActivity() {
private val PERMISSION_REQ_ID = 22

private val REQUESTED_PERMISSIONS = arrayOf(
android.Manifest.permission.CAMERA,
android.Manifest.permission.RECORD_AUDIO
)

private lateinit var joinAudioCall: Button
private lateinit var joinVideoCall:Button


override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContentView(R.layout.activity_main)
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}

if (!checkPermissions()) {
requestPermissions()
}

joinAudioCall = findViewById(R.id.btn_audio)
joinVideoCall = findViewById(R.id.btn_video)


joinAudioCall.setOnClickListener{startActivity(Intent(this@MainActivity, AudioActivity::class.java))}
joinVideoCall.setOnClickListener{startActivity(Intent(this@MainActivity, AudioActivity::class.java))}
}

private fun checkPermissions(): Boolean {
for (permission in REQUESTED_PERMISSIONS) {
if (ContextCompat.checkSelfPermission(
this,
permission
) != PackageManager.PERMISSION_GRANTED
) {
return false
}
}
return true
}

private fun requestPermissions() {
ActivityCompat.requestPermissions(this, REQUESTED_PERMISSIONS, PERMISSION_REQ_ID)
}
}




10/  Modify your AudioActivity


   10.1/ Modify activity_audio.xml




<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">


<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_margin="16dp"
android:gravity="center"
>
<Button
android:id="@+id/btn_join"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Join Channel" />

<Button
android:id="@+id/btn_leave"
android:layout_marginStart="16dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Leave Channel"
android:visibility="gone"/>
</LinearLayout>
</LinearLayout>



   10.2/ AudioActivity.kt




package com.zissofworks.agoraaudiovideokotlin

import android.os.Bundle
import android.view.View
import android.widget.Button
import android.widget.Toast
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import io.agora.rtc2.ChannelMediaOptions
import io.agora.rtc2.Constants
import io.agora.rtc2.IRtcEngineEventHandler
import io.agora.rtc2.RtcEngine
import io.agora.rtc2.RtcEngineConfig


class AudioActivity : AppCompatActivity() {

private String appId = "paste here your app id within the quotation";
    private String channelName = "agora_audio_video";
private String token = "paste here your token you genareted within the quotation";

private lateinit var mRtcEngine: RtcEngine

private lateinit var btn_join: Button
private lateinit var btn_leave: Button

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContentView(R.layout.activity_audio)
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}

btn_join = findViewById(R.id.btn_join)
btn_leave = findViewById(R.id.btn_leave)

val mRtcEventHandler: IRtcEngineEventHandler = object : IRtcEngineEventHandler() {
override fun onJoinChannelSuccess(channel: String, uid: Int, elapsed: Int) {
super.onJoinChannelSuccess(channel, uid, elapsed)
runOnUiThread {
Toast.makeText(
this@AudioActivity,
"Join channel success",
Toast.LENGTH_SHORT
).show()
}
}

override fun onUserJoined(uid: Int, elapsed: Int) {
super.onUserJoined(uid, elapsed)
runOnUiThread {
Toast.makeText(this@AudioActivity, "User joined.. ", Toast.LENGTH_SHORT)
.show()
}
}

override fun onUserOffline(uid: Int, reason: Int) {
super.onUserOffline(uid, reason)
runOnUiThread {
Toast.makeText(this@AudioActivity, "User offline ", Toast.LENGTH_SHORT)
.show()
}
}
}

val config = RtcEngineConfig()
config.mContext = baseContext
config.mAppId = appId
config.mEventHandler = mRtcEventHandler
try {
mRtcEngine = RtcEngine.create(config)
} catch (e: Exception) {
throw RuntimeException(e)
}


val options = ChannelMediaOptions()
options.clientRoleType = Constants.CLIENT_ROLE_BROADCASTER
options.channelProfile = Constants.CHANNEL_PROFILE_LIVE_BROADCASTING
options.publishMicrophoneTrack = true
options.autoSubscribeAudio = true

btn_join.setOnClickListener {
mRtcEngine.joinChannel(token, channelName, 0, options)
btn_leave.visibility = View.VISIBLE
}

btn_leave.setOnClickListener {
mRtcEngine.leaveChannel()
RtcEngine.destroy()
finish()
}
}

override fun onDestroy() {
super.onDestroy()
mRtcEngine.leaveChannel()
RtcEngine.destroy()
finish()
}
}




11/  Modify your VideoActivity


   11.1/ Modify activity_video.xml




<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<FrameLayout
android:id="@+id/local_video_view_container"
android:layout_width="match_parent"
android:layout_height="300dp"
android:layout_weight="1"/>

<View
android:layout_width="1dp"
android:layout_height="1dp"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
/>
<FrameLayout
android:id="@+id/remote_video_view_container"
android:layout_width="match_parent"
android:layout_height="300dp"
android:layout_weight="1"/>

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_margin="16dp"
>
<Button
android:id="@+id/btn_join"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Join Channel" />

<Button
android:id="@+id/btn_leave"
android:layout_marginStart="16dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Leave Channel"
android:visibility="gone"/>
</LinearLayout>
</LinearLayout>



   11.2/ VideoActivity.kt




package com.zissofworks.agoraaudiovideokotlin

import android.os.Bundle
import android.view.SurfaceView
import android.view.View
import android.widget.Button
import android.widget.FrameLayout
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import io.agora.rtc2.ChannelMediaOptions
import io.agora.rtc2.Constants
import io.agora.rtc2.IRtcEngineEventHandler
import io.agora.rtc2.RtcEngine
import io.agora.rtc2.RtcEngineConfig
import io.agora.rtc2.video.VideoCanvas


class VideoActivity : AppCompatActivity() {
private val appId = "363a9d8bc224485b8266023b215872cf"
private val channelName = "agora_audio_vedio_with_kotlin"
private val token = "007eJxTYNiTZX/UKlGsoff09Rsfs/+knT54QiVGvvUg08q6BzcXLO9SYDA2M060TLFISjYyMjGxME2yMDIzMzAyTjIyNLUwN0pOk6gpTG8IZGRY0y3OysgAgSC+LENien5RYnxiaUpmfnxZKogszyzJiM/OL8nJzGNgAACbByrO"

private lateinit var mRtcEngine: RtcEngine
private lateinit var btn_join: Button
private lateinit var btn_leave: Button

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContentView(R.layout.activity_video)
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}

btn_join = findViewById(R.id.btn_join)
btn_leave = findViewById(R.id.btn_leave)

val mRtcEventHandler: IRtcEngineEventHandler = object : IRtcEngineEventHandler() {
override fun onUserJoined(uid: Int, elapsed: Int) {
runOnUiThread { setupRemoteVideo(uid) }
}
}


val config = RtcEngineConfig()
config.mContext = baseContext
config.mAppId = appId
config.mEventHandler = mRtcEventHandler
try {
mRtcEngine = RtcEngine.create(config)
} catch (e:Exception ) {
throw RuntimeException(e)
}


mRtcEngine.enableVideo()

mRtcEngine.startPreview()

val container = findViewById<FrameLayout>(R.id.local_video_view_container)
val surfaceView = SurfaceView (baseContext)
container.addView(surfaceView)
mRtcEngine.setupLocalVideo(VideoCanvas(surfaceView, VideoCanvas.RENDER_MODE_FIT, 0))

val options = ChannelMediaOptions()
options.clientRoleType = Constants.CLIENT_ROLE_BROADCASTER
options.channelProfile = Constants.CHANNEL_PROFILE_COMMUNICATION

btn_join.setOnClickListener{
mRtcEngine.joinChannel(token, channelName, 0, options)
btn_leave.visibility = View.VISIBLE
}

btn_leave.setOnClickListener {
mRtcEngine.stopPreview()
mRtcEngine.leaveChannel()
finish()
}
}
private fun setupRemoteVideo(uid:Int) {
val container = findViewById<FrameLayout>(R.id.remote_video_view_container)
val surfaceView = SurfaceView (baseContext)
surfaceView.setZOrderMediaOverlay(true)
container.addView(surfaceView)
mRtcEngine.setupRemoteVideo(VideoCanvas(surfaceView, VideoCanvas.RENDER_MODE_FIT, uid))
}

override fun onDestroy() {
super.onDestroy()
mRtcEngine.stopPreview()
mRtcEngine.leaveChannel()
}
}





Comments