androidkotlintokenagora.iovideochat

1v1 video chat using token authentication in agora.io for android


I am trying to implement 1v1 video chat in my android app using token based authentication. I can generate the token and use it in my app. But it is not working. I wonder that when I generate the token will I use 1 uid for the 2 user or will I use 2 different uid for the 2 user. If I use 1 uid and then will I use the same token for this 2 user. if I use 2 uid and then 2 different token is being created for this 2 user. I can not solve this token based authentication. how does it work? can you help me please?

For example, 1 user is trying to make a video call. I can generate token using this user's uid. When the other user join this video call, will the second user use the same token or the second user will generate another token using its uid. I am confusied in this part. how the second user will join the call? thanks

My code for video call:

class VideoCallActivity : AppCompatActivity() {

private val db = Firebase.firestore

// Kotlin
// Fill the App ID of your project generated on Agora Console.
private val APP_ID = "app_id"

// Fill the channel name.
private val CHANNEL = "appointment"


private var TOKEN =

private var mRtcEngine: RtcEngine? = null

private lateinit var localContainer: FrameLayout
private lateinit var remoteContainer: FrameLayout

private var uniqueUserUidLocal: Int = 0
private var uniqueUserUidRemote: Int = 0

private val mRtcEventHandler = object : IRtcEngineEventHandler() {
    // Listen for the remote user joining the channel to get the uid of the user.
    override fun onUserJoined(uniqueUserUidRemote: Int, elapsed: Int) {
        runOnUiThread {
            // Call setupRemoteVideo to set the remote video view after getting uid from the onUserJoined callback.

            setupRemoteVideo(uniqueUserUidRemote)

            
        }
    }
   
}


override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_video_call)

    localContainer = findViewById<FrameLayout>(R.id.local_video_view_container)
    remoteContainer = findViewById<FrameLayout>(R.id.remote_video_view_container)

    val userId = intent.getStringExtra("chaplainUniqueUserId").toString()
    uniqueUserUidRemote = userId.toInt(10)

    getToken()
    //initializeAndJoinChannel()


    video_page_finnish_call_imageButton.setOnClickListener {
        mRtcEngine?.stopPreview()
        mRtcEngine?.leaveChannel()
        RtcEngine.destroy()
        finish()
    }

}

private fun getToken(){
    //getting token info from rest api
    val retrofit = Retrofit.Builder()
        .baseUrl("https://kadir.webprogrammer.fi/")
        .addConverterFactory(GsonConverterFactory.create())
        .build()

    val api = retrofit.create(TokenApiInterface::class.java)

    //this part is not clear. which uid should be used remote uid or local uid
    api.fetchAllData(uid = uniqueUserUidRemote.toString()).enqueue(object : Callback<TokenModelClass> {
        override fun onResponse(
            call: Call<TokenModelClass>,
            response: Response<TokenModelClass>
        ) {
            TOKEN = response.body()?.token ?: TOKEN
            Log.e("TOKEN_1: ", TOKEN)
            Log.e("TOKEN_2: ", uniqueUserUidRemote.toString())
            initializeAndJoinChannel(TOKEN)
        }

        override fun onFailure(call: Call<TokenModelClass>, t: Throwable) {
            Log.e("TOKEN: ", t.message.toString())
        }

    })

}


private fun initializeAndJoinChannel(TOKEN: String) {
    try {
        mRtcEngine = RtcEngine.create(baseContext, APP_ID, mRtcEventHandler)
    } catch (e: Exception) {

    }

    // By default, video is disabled, and you need to call enableVideo to start a video stream.
    mRtcEngine!!.enableVideo()
    // Call CreateRendererView to create a SurfaceView object and add it as a child to the FrameLayout.
    val localFrame = RtcEngine.CreateRendererView(baseContext)
    localFrame.setZOrderMediaOverlay(true)
    localContainer.addView(localFrame)
    // Pass the SurfaceView object to Agora so that it renders the local video.
    mRtcEngine!!.setupLocalVideo(VideoCanvas(localFrame, VideoCanvas.RENDER_MODE_FIT, 0))
    //this uid is the local user uid, not the remote user uid

    // Join the channel with a token.
    mRtcEngine!!.joinChannel(TOKEN, CHANNEL, "", 0)

}

private fun setupRemoteVideo(uniqueUserUidRemote: Int) {

    val remoteFrame = RtcEngine.CreateRendererView(baseContext)
    //remoteFrame.setZOrderMediaOverlay(true)
    remoteContainer.addView(remoteFrame)
    mRtcEngine!!.setupRemoteVideo(
        VideoCanvas(
            remoteFrame,
            VideoCanvas.RENDER_MODE_FIT,
            uniqueUserUidRemote
        )
    )
}

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

}


Solution

  • Every token that you generate is unique to a channel and UID. So when your app loads it should load the network request. Using the token returned from the token server you can call the joinChannel method, make sure you pass the same UID and channel name to the joinChannel parameter that you used while generating the token.

    You can read more about it over here: https://www.agora.io/en/blog/connecting-to-agora-with-tokens-android/