{"id":49739,"date":"2023-12-29T17:39:48","date_gmt":"2023-12-29T12:09:48","guid":{"rendered":"https:\/\/www.oneclickitsolution.com\/blog\/?p=49739"},"modified":"2023-12-29T17:39:50","modified_gmt":"2023-12-29T12:09:50","slug":"live-streaming-in-android-application-using-agora","status":"publish","type":"post","link":"https:\/\/www.oneclickitsolution.com\/blog\/live-streaming-in-android-application-using-agora","title":{"rendered":"How to Add Live Streaming in Android Application Using Agora?"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">Introduction<\/h2>\n\n\n\n<p>Agora live Streaming platform is used for analytics tracking and one to many and many to many audio or video live streaming with Agora SDK. In video calling with audio interactive live streaming, users can be host or audience and the host can start live and the audience by joining that streaming.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-why-agora-live-streaming\">Why Agora Live Streaming?<\/h2>\n\n\n\n<p>Agora live Streaming platform is used to integrate SDK in your mobile app which can help you to explore all the features from Agore such as simple-to-use, <strong><a href=\"https:\/\/www.oneclickitsolution.com\/hire-dedicated-developers\/\" target=\"_blank\" rel=\"noreferrer noopener\">developer<\/a><\/strong>-friendly, customizable, securable, reliable, good quality audio, and video analytics tracking, customer support, video monetization, reduce cost. Kotlin is the preferred language for Android application development. It is a modern programming language that was introduced by JetBrains, the same company behind the popular IntelliJ IDEA IDE, which is widely used for Android development.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-prerequisite\">Prerequisite<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Android Device, Windows, Linux.<\/li>\n\n\n\n<li>Tech Stack, We\u2019re using: Kotlin, Java, XML language<\/li>\n\n\n\n<li>Tools we are using: Android studio<\/li>\n\n\n\n<li><a href=\"https:\/\/www.oracle.com\/java\/technologies\/javase-downloads.html\" target=\"_blank\" rel=\"noreferrer noopener nofollow\"><strong>Java Development Kit<\/strong><\/a>.<\/li>\n\n\n\n<li>Android Studio 3.0 or later.<\/li>\n\n\n\n<li>Android SDK API Level 16 or higher.<\/li>\n\n\n\n<li>A valid <strong><a href=\"https:\/\/console.agora.io\/\" target=\"_blank\" rel=\"noreferrer noopener nofollow\">Agora account<\/a><\/strong>. integrate the Agora project with an App ID and a temporary token. For details, see <a href=\"https:\/\/docs.agora.io\/en\/Agora%20Platform\/get_appid_token?platform=All%20Platforms\" target=\"_blank\" rel=\"noreferrer noopener nofollow\"><strong>Get Started with Agora<\/strong><\/a>.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Process of implementing Live Streaming in Android Application Using Agora<\/h2>\n\n\n\n<p>1. Register with Agora&nbsp; <a href=\"https:\/\/console.agora.io\/\" target=\"_blank\" rel=\"noreferrer noopener nofollow\"><strong>https:\/\/console.agora.io\/<\/strong><\/a><\/p>\n\n\n\n<p>2. Activate your project with app id and temporary token.<\/p>\n\n\n\n<p>3. Add the below dependency to your project.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"kotlin\" class=\"language-kotlin\">implementation 'io.agora.rtc:full-sdk:x.y.z'<\/code><\/pre>\n\n\n\n<p>4. Next Step you need to add the below permission in the android manifest<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"kotlin\" class=\"language-kotlin\">&lt;uses-permission android:name=\"android.permission.INTERNET\" \/&gt;\n&lt;uses-permission android:name=\"android.permission.CAMERA\" \/&gt;\n&lt;uses-permission android:name=\"android.permission.RECORD_AUDIO\" \/&gt;\n&lt;uses-permission android:name=\"android.permission.MODIFY_AUDIO_SETTINGS\" \/&gt;\n&lt;uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\" \/&gt;\n&lt;uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\" \/&gt;\n&lt;uses-permission android:name=\"android.permission.BLUETOOTH\" \/&gt;<\/code><\/pre>\n\n\n\n<p>The below Screenshot shows how live streaming actually works.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"https:\/\/www.oneclickitsolution.com\/blog\/wp-content\/uploads\/2022\/04\/live-streaming-actually-works.png\" alt=\"live streaming actually works\" class=\"wp-image-49744\"\/><\/figure>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"kotlin\" class=\"language-kotlin\">&lt;com.tyt.tytapp.ui.adapter.VideoGridContainer\n       android:id=\"@+id\/live_video_grid_layout\"\n       android:layout_width=\"match_parent\"\n       android:layout_height=\"match_parent\"\n       app:layout_constraintBottom_toBottomOf=\"parent\"\n       app:layout_constraintEnd_toEndOf=\"parent\"\n       app:layout_constraintStart_toStartOf=\"parent\"\n       app:layout_constraintTop_toTopOf=\"parent\"\/&gt;<\/code><\/pre>\n\n\n\n<p>5. Next step you need to create a live activity by extending another activity name is ActivityRtcLivebase.<\/p>\n\n\n\n<p>You need to pass both side join and live user bellow details compulsory from the agora.<\/p>\n\n\n\n<p><strong>Live user details<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Channel Profile=Constants.CLIENT_ROLE_BROADCASTER<\/li>\n\n\n\n<li>UID<\/li>\n\n\n\n<li>Token<\/li>\n\n\n\n<li>Room Name<\/li>\n<\/ul>\n\n\n\n<p><strong>Join user details<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Channel Profile=Constants.CLIENT_ROLE_AUDIENCE<\/li>\n\n\n\n<li>UID<\/li>\n\n\n\n<li>Token<\/li>\n\n\n\n<li>Room Name<\/li>\n<\/ul>\n\n\n\n<p><strong>ActivityLive.kt<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"java\" class=\"language-java\">       appLiveTokenIs =intent.getStringExtra(AppConstants.PREF_USER_APP_TOKEN_INTENT)\n       channelName = intent.getStringExtra(AppConstants.CHANNEL_MESSAGE)\n       userId=intent.getStringExtra(AppConstants.PREF_USERS_ID)\n       experienceId=intent.getIntExtra(AppConstants.PREF_EXPERIENCE_ID, -1)\n       channelProfile = intent.getIntExtra(AppConstants.PROFILE_MESSAGE,-1)\n       profileImage=intent.getStringExtra(AppConstants.PREF_USER_PROFILE_LIVE)\n       profilerName=intent.getStringExtra(AppConstants.PREF_USER_PROFILER_NAME)\n       uidIs=intent.getLongExtra(AppConstants.UID,0).toInt()\n       uidClode=intent.getIntExtra(AppConstants.CLOUD_UID,0)\n       cloudeUrl=intent.getStringExtra(AppConstants.CLOUD_URL)\n       sid=intent.getStringExtra(AppConstants.CLOUD_SID)\n       expAddress= intent.getStringExtra(AppConstants.LIVE_ADDRESS)\n       description= intent.getStringExtra(AppConstants.LIVE_DESCRIPTION)\n       createDate= intent.getStringExtra(AppConstants.LIVE_EXP_DATE)\n       screenUid=intent.getStringExtra(AppConstants.UID_SCREEN_SHOT)\n\n\n       if (intent.hasExtra(AppConstants.LIVE_EXPERIENCE_KEY)) {\n           intent.getParcelableExtra&lt;ModelResponseExperienceDetailsData&gt;(AppConstants.LIVE_EXPERIENCE_KEY)\n               ?.let {\n                   dataExperienceDetails= it\n                   Log.d(\"jigdata==\",\"live=\"+dataExperienceDetails)\n     \n        \n\n                   if(channelProfile==2){\n                       if(!appLiveTokenIs.isNullOrEmpty()){\n                           initUI()\n                           initData()\n                       }\n                   }\n\n               }\n       }\n       if(channelProfile==1){\n           if(!appLiveTokenIs.isNullOrEmpty()){\n               initUI()\n               initData()\n           }\n       }\n       if(channelProfile==2) {\n           \/\/toolbar\n           initToolbar()\n           baseActivityBinding.baseActivityToolbar.visibility=View.VISIBLE\n           baseActivityBinding.baseActivityToolbarTextviewTitleCenter.visibility = View.VISIBLE\n           baseActivityBinding.baseActivityToolbarTextviewTitleCenter.text = resources.getString(R.string.text_title_experience_title)\n           baseActivityBinding.baseActivityToolbarImageviewBack.visibility = View.VISIBLE\n\n       }\n       if(channelProfile==1)\n       {\n           baseActivityBinding.baseActivityToolbar.visibility=View.GONE\n       }\n\n\n\n\n\n       activityLiveBinding.activityLiveButtonLearnMore.setSafeOnClickListener {\n\n\n           if (wikiPediaKey.isNullOrEmpty()) {\n\n               showLocationCoordinatesInvalidDialogForWikiPedia()\n           }else{\n               val intent = Intent(this, ActivityWebView::class.java)\n               intent.putExtra(AppConstants.PREF_KEY_WIKI_PEDIA, wikiPediaKey)\n               startActivity(intent)\n           }\n       }\n\n\n   }\n<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"java\" class=\"language-java\">   override fun onStop() {\n       super.onStop()\n\n   }\n\n   override fun onResume() {\n       super.onResume()\n       if(cTimer!=null){\n           cTimer?.cancel()\n       }\n      \n   }\n\n\n   override fun onDestroy() {\n       super.onDestroy()\n       if(cTimer!=null){\n           cTimer?.cancel()\n       }\n   }\n\n   override fun onPause() {\n       super.onPause()\n       startOTPTimer()\n\n\n   }\n\n\n   private fun initUI() {\n      val roomName: TextView = findViewById(R.id.activity_live_text_view_text_name)\n       roomName.text =profilerName\n\n\n       if(channelProfile==2)\n       {\n           roomName.text = profilerName\n       }\n      roomName.isSelected = true\n       initUserIcon()\n       val role: Int = intent.getIntExtra(\n           Constants.KEY_CLIENT_ROLE,\n           Constants.CLIENT_ROLE_AUDIENCE\n       )\n       val isBroadcaster:Boolean = (channelProfile == Constants.CLIENT_ROLE_BROADCASTER)\n      mMuteVideoBtn = findViewById(R.id.live_btn_mute_video)\n       mMuteVideoBtn.setOnClickListener() {\n           onMuteVideoClicked(it)\n       }\n       mMuteVideoBtn.isActivated = isBroadcaster\n       mMuteAudioBtn = findViewById(R.id.live_btn_mute_audio)\n       mMuteAudioBtn.setOnClickListener() {\n           onMuteAudioClicked(it)\n       }\n       mMuteAudioBtn.isActivated = isBroadcaster\n       mLiveButton= findViewById(R.id.live_btn_switch_camera)\n\n       if(channelProfile==2){\n           activityLiveBinding.activityLiveBottomLayout.visibility=View.GONE\n           activityLiveBinding.activitLiveTopLayout.visibility=View.VISIBLE\n           activityLiveBinding.activityLiveBottomExploreAreaConstraintLayout.visibility=View.VISIBLE\n           \/\/toolbar\n           initToolbar()\n           baseActivityBinding.baseActivityToolbarTextviewTitleCenter.visibility = View.VISIBLE\n           baseActivityBinding.baseActivityToolbarTextviewTitleCenter.text = resources.getString(R.string.text_title_experience_title)\n           baseActivityBinding.baseActivityToolbarImageviewBack.visibility = View.VISIBLE\n           activityLiveBinding.activityLiveTextViewTextLocationDescription.text=dataExperienceDetails.experienceDetails.experienceDescription\n           activityLiveBinding.activityLiveTextViewTextLocationName.text=dataExperienceDetails.experienceDetails.experienceAddress\n           activityLiveBinding.activityLiveTextViewTextDate.text = AppDateFormatUtils.convertDate(\n               dataExperienceDetails.createdAt,\n               DateFormat.NUMERICAL_REVERSE_DATE_WITH_DASH_AND_TIME_MIDDLE_T,\n               DateFormat.FULL_DATE_AND_TIME,\n               true\n           )\n           if(dataExperienceDetails.isOriginal){\n\n               Glide.with(context)\n                   .load(dataExperienceDetails.owner)\n                   .error(R.drawable.ic_defaultpic)\n                   .placeholder(R.drawable.ic_defaultpic)\n                   .into(activityLiveBinding.liveProfileImage)\n           }else{\n\n               Glide.with(context)\n                   .load(dataExperienceDetails.originalOwner!!.profilePic)\n                   .error(R.drawable.ic_defaultpic)\n                   .placeholder(R.drawable.ic_defaultpic)\n                   .into(activityLiveBinding.liveProfileImage)\n           }\n\n\n\n           mMuteAudioBtn.visibility=View.GONE\n           mMuteVideoBtn.visibility=View.GONE\n           mLiveButton.visibility=View.GONE\n       }\n\n       if(channelProfile==1){\n           initToolbar()\n           baseActivityBinding.baseActivityToolbarTextviewTitleCenter.visibility = View.GONE\n           baseActivityBinding.baseActivityToolbarImageviewBack.visibility = View.GONE\n           activityLiveBinding.activitLiveTopLayout.visibility=View.GONE\n           mMuteAudioBtn.visibility=View.VISIBLE\n           mMuteVideoBtn.visibility=View.VISIBLE\n           mLiveButton.visibility=View.VISIBLE\n           Glide.with(context)\n               .load(appPreferences.getAppPrefString(AppConstants.PREF_USER_PROFILE_IMAGE))\n               .error(R.drawable.ic_defaultpic)\n               .placeholder(R.drawable.ic_defaultpic)\n               .into(activityLiveBinding.liveProfileImage)\n       }\n\n       mVideoGridContainer = findViewById(R.id.live_video_grid_layout)\n\n       mVideoGridContainer!!.setStatsManager(statsManager())\n       rtcEngine().setClientRole(channelProfile)\n       if (isBroadcaster) startBroadcast()\n   }\n\n\n\n   private fun initUserIcon() {\n       val origin = BitmapFactory.decodeResource(resources, R.drawable.fake_user_icon)\n       val drawable = RoundedBitmapDrawableFactory.create(resources, origin)\n       drawable.isCircular = true\n\n\n   }\n\n   private fun initData() {\n       mVideoDimension =\n           Constants.VIDEO_DIMENSIONS.get(config().videoDimenIndex)\n\n   }\n\n\n   private fun startBroadcast() {\n\n       rtcEngine().setClientRole(Constants.CLIENT_ROLE_BROADCASTER)\n       val surface: SurfaceView = prepareRtcVideo(uidIs, true)\n\n       surfaceViewCached = surface\n       executeAfterSomeTime(5000) {\n           takeScreenShotAndSend()\/\/07-03-22\n       }\n\n       mVideoGridContainer!!.addUserVideoSurface(uidIs.toInt(), surface, true)\n       mMuteAudioBtn.isActivated = true\/\/change\n   }\n\n   private fun stopBroadcast() {\n       rtcEngine().setClientRole(Constants.CLIENT_ROLE_AUDIENCE)\n        removeRtcVideo(uidIs.toInt(), true)\n       mVideoGridContainer!!.removeUserVideo(uidIs.toInt(), true)\n       mMuteAudioBtn.isActivated = true\n\n   }\n\n   override fun onJoinChannelSuccess(channel: String?, uid: Int, elapsed: Int) {\n       Log.d(\"==&gt;\",\"onJoinChannelSuccess\"+uid)\n\n       \/\/ Do nothing at the moment\n\n   }\n\n   override fun onUserJoined(uid: Int, elapsed: Int) {\n       Log.d(\"==&gt;\",\"onUserJoined=\"+uid)\n       \/\/ Do nothing at the moment\n   }\n<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"java\" class=\"language-java\">   override fun onUserOffline(uid: Int, reason: Int) {\n       runOnUiThread(Runnable { removeRemoteUser(uid)\n       if (reason == 0)\n       {\n           showLiveStreamOffDialog()\n       }\n       })\n   }\n\n   override fun onFirstRemoteVideoDecoded(uid: Int, width: Int, height: Int, elapsed: Int) {\n       runOnUiThread(Runnable { renderRemoteUser(uid) })\n   }\n\n   private fun renderRemoteUser(uid: Int) {\n       val surface: SurfaceView = prepareRtcVideo(uid, false)\n       Log.d(\"==&gt;\",\"surface=\"+surface)\n\n       surFaceIs = surface.toString()\n       surfaceViewCached = surface\n       if(channelProfile==2){\n           surfaceViewCachedJoin=surface\n       }\n\n       mVideoGridContainer!!.addUserVideoSurface(uid, surface, false)\n       if(channelProfile==2){\n           surfaceViewCachedJoin?.let { surfaceView -&gt;\n               LiveSuccess=true\n           }\n       }\n   }\n\n\n\n\n   private fun removeRemoteUser(uid: Int) {\n       removeRtcVideo(uid, false)\n       \/\/dashboardViewModel.endLiveApi(experienceId, userId)\n       mVideoGridContainer?.removeUserVideo(uid, false)\n   }\n   override   fun onLocalVideoStats(stats: LocalVideoStats?) {\n       Log.d(\"==&gt;\",\"LiveSuccessF=\"+LiveSuccess)\n       if(channelProfile==2){\n           surfaceViewCachedJoin?.let { surfaceView -&gt;\n               Log.d(\"==&gt;\",\"dooo=\"+surfaceView.toString())\n\n               if(surfaceView.toString().isEmpty()){\n                   if (intent.hasExtra(AppConstants.LIVE_EXPERIENCE_KEY)) {\n                       intent.getParcelableExtra&lt;ModelResponseExperienceDetailsData&gt;(AppConstants.LIVE_EXPERIENCE_KEY)\n                           ?.let {\n                               dataExperienceDetails= it\n                               initUI()\n                               initData()\n                               joinChannel()\n                            \n                           }\n                   }\n\n\n               }\n           }\n       }\n\n\n       if(!LiveSuccess){\n\n           if (intent.hasExtra(AppConstants.LIVE_EXPERIENCE_KEY)) {\n               LIVE_EXPERIENCE_KEY)\n                   ?.let {\n                       dataExperienceDetails= it\n                       Log.d(\"==&gt;\",\"dooo3=\"+intent.hasExtra(AppConstants.LIVE_EXPERIENCE_KEY))\n                       initUI()\n                       initData()\n                       joinChannel()\n\n\n                   }\n           }\n\n       }\n       if (!statsManager()!!.isEnabled) return\n       val data = statsManager()!!.getStatsData(uidIs.toInt()) as LocalStatsData ?: return\n       data.width = mVideoDimension.width\n       data.height = mVideoDimension.height\n       data.framerate = stats!!.sentFrameRate\n   }\n\n   override fun onBackPressed() {\n\n       if(backPress) {\n           super.onBackPressed()\n           if (channelProfile == 1) {\n            dashboardViewModel.endLiveApi(experienceId, userId, fileName)\n               setResult(RESULT_OK, Intent().putExtra(\"experienceId\",experienceId).putExtra(\"userId\",userId).putExtra(\"fileName\",fileName))\n               backPress=false\n           }\n       }\n      \/\/ finish()\n   }<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"java\" class=\"language-java\">   override fun onRtcStats(stats: RtcStats?) {\n       Log.d(\"==&gt;\",\"onRtcStats=\"+stats)\n       if (!statsManager()!!.isEnabled) return\n       val data = statsManager()!!.getStatsData(uidIs) as LocalStatsData ?: return\n       data.lastMileDelay = stats!!.lastmileDelay\n       data.videoSendBitrate = stats.txVideoKBitRate\n       data.videoRecvBitrate = stats.rxVideoKBitRate\n       data.audioSendBitrate = stats.txAudioKBitRate\n       data.audioRecvBitrate = stats.rxAudioKBitRate\n       data.cpuApp = stats.cpuAppUsage\n       data.cpuTotal = stats.cpuAppUsage\n       data.sendLoss = stats.txPacketLossRate\n       data.recvLoss = stats.rxPacketLossRate\n   }\n\n\n\n\n   override fun onNetworkQuality(uid: Int, txQuality: Int, rxQuality:Int) {\n       if (!statsManager()!!.isEnabled()) return\n       val data: StatsData = statsManager()!!.getStatsData(uid) ?: return\n       data.setSendQuality(statsManager()!!.qualityToString(txQuality))\n       data.setRecvQuality(statsManager()!!.qualityToString(rxQuality))\n   }\n\n   override fun onRemoteVideoStats(stats: RemoteVideoStats?) {\n       Log.d(\"==&gt;\",\"onRemoteVideoStats=\"+stats)\n       if (!statsManager()!!.isEnabled()) return\n       val data: RemoteStatsData = statsManager()!!.getStatsData(stats!!.uid) as RemoteStatsData ?: return\n       data.setWidth(stats.width)\n       data.setHeight(stats.height)\n       data.setFramerate(stats.rendererOutputFrameRate)\n       data.setVideoDelay(stats.delay)\n   }\n   override fun onRemoteAudioStats(stats: RemoteAudioStats?) {\n       if (!statsManager()!!.isEnabled) return\n       val data = statsManager()!!.getStatsData(stats!!.uid) as RemoteStatsData\n           ?: return\n       data.audioNetDelay = stats.networkTransportDelay\n       data.audioNetJitter = stats.jitterBufferDelay\n       data.audioLoss = stats.audioLossRate\n       data.audioQuality = statsManager()!!.qualityToString(stats.quality)\n   }\n<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"java\" class=\"language-java\">   \/\/start timer function\n   fun startOTPTimer() {\n       cancelTimer()\n\n\n       cTimer = object : CountDownTimer(60000, 1000) {\n           override fun onTick(millisUntilFinished: Long) {\n\n               val minutes: Long = millisUntilFinished \/ 1000 \/ 60\n               val seconds = (millisUntilFinished \/ 1000 % 60)\n\n           }\n           override fun onFinish() {\n               if(channelProfile==1) {\n                   dashboardViewModel.endLiveApi(experienceId, userId,fileName)\n               }\n\n           }\n       }\n       cTimer?.start()\n   }\n\n   private fun cancelTimer() {\n       if(cTimer!=null){\n           cTimer?.cancel()\n       }\n   }\n\n\n\n   override fun finish() {\n       statsManager()!!.clearAllData()\n       if(channelProfile==1) {\n\n       dashboardViewModel.endLiveApi(experienceId, userId, fileName)\n\n               endLiveSuccess=false\n               appLiveTokenIs=\"\"\n               channelName=\"\"\n               dashboardViewModel.booleanGoLiveSuccess.value=false\n           }\n\n\n\n       super.finish()\n\n\n   }\n\n\n\n   fun onLeaveClicked(view: View?) {\n\n          \/\/ finishLive()\n           finish()\n\n   }\n\n\n\n   fun onSwitchCameraClicked(view: View?) {\n       if (view!!.isActivated) {\n           mMuteVideoBtn.setImageResource(R.drawable.ic_videoofff)\n\n       } else {\n\n           mMuteVideoBtn.setImageResource(R.drawable.ic_videoonf)\n       }\n       rtcEngine().switchCamera()\n   }\n\n   fun onBeautyClicked(view: View) {\n       view.isActivated = !view.isActivated\n       rtcEngine().setBeautyEffectOptions(\n           view.isActivated,\n           Constants.DEFAULT_BEAUTY_OPTIONS\n       )\n   }\n\n\n\n   fun onMuteAudioClicked(view: View) {\n\/\/        if (!mMuteVideoBtn.isActivated) return\n\n       if (view.isActivated) {\n\n           mMuteAudioBtn.setImageResource(R.drawable.ic_mutemikef)\n\n       } else {\n           rtcEngine().enableVideo()\/\/ startBroadcast()\n           mMuteAudioBtn.setImageResource(R.drawable.ic_mikef)\n       }\n       rtcEngine().muteLocalAudioStream(view.isActivated)\n       view.isActivated = !view.isActivated\n   }\n\n   fun onMuteVideoClicked(view: View) {\n       if (view.isActivated) {\n           rtcEngine().disableVideo()\/\/stopBroadcast()\n           mMuteVideoBtn.setImageResource(R.drawable.ic_videoofff)\n\n       } else {\n           rtcEngine().enableVideo()\/\/ startBroadcast()\n           mMuteVideoBtn.setImageResource(R.drawable.ic_videoonf)\n       }\n       view.isActivated = !view.isActivated\n   }\n\n   companion object {\n       private val TAG = LiveActivity::class.java.simpleName\n   }}}\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-activityrtclivebase\"><em>ActivityRtcLivebase<\/em><\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"java\" class=\"language-java\">abstract class ActivityRtcLiveBase : LiveBaseActivity(), EventHandler {\n   var channelNameis: String? = null\n   var channelProfile:Int = 0\n   var uid:Long=0\n   var temp:Long=0\n   var appLiveToken: String? = null\n   private lateinit var dataExperienceDetails: ModelResponseExperienceDetailsData\n   private var surFaceIs:String?=null\n   private var liveSuccessFull:Boolean=false\n   private var surfaceViewJoin:SurfaceView?=null\n\n   override fun onCreate(savedInstanceState: Bundle?) {\n       super.onCreate(savedInstanceState)\n       registerRtcEventHandler(this)\n       val intent = intent\n      appLiveToken =intent.getStringExtra(AppConstants.PREF_USER_APP_TOKEN_INTENT)\n      channelNameis =intent.getStringExtra(AppConstants.CHANNEL_MESSAGE)\n      channelProfile = intent.getIntExtra(AppConstants.PROFILE_MESSAGE,-1)\n       uid=intent.getLongExtra(AppConstants.UID,0)\n\n       if (intent.hasExtra(AppConstants.LIVE_EXPERIENCE_KEY)) {\n           intent.getParcelableExtra&lt;ModelResponseExperienceDetailsData&gt;(AppConstants.LIVE_EXPERIENCE_KEY)\n               ?.let {\n                   if(it!=null){\n                       dataExperienceDetails= it\n                       Log.d(\"jigData==\",\"live=\"+dataExperienceDetails)\n\n                   }\n\n               }\n       }\n       if(!appLiveToken.isNullOrEmpty()){\n           joinChannel()\n       }\n\n   }\n\n   private fun configVideo() {\n       val configuration = VideoEncoderConfiguration(\n           Constants.VIDEO_DIMENSIONS.get(config().videoDimenIndex),\n           VideoEncoderConfiguration.FRAME_RATE.FRAME_RATE_FPS_15,\n           VideoEncoderConfiguration.STANDARD_BITRATE,\n           VideoEncoderConfiguration.ORIENTATION_MODE.ORIENTATION_MODE_FIXED_PORTRAIT\n       )\n\n       Log.d(\"==&gt;\",\"configuration=\"+configuration)\n       configuration.mirrorMode = Constants.VIDEO_MIRROR_MODES.get(config().mirrorEncodeIndex)\n       rtcEngine().setVideoEncoderConfiguration(configuration)\n\n   }\n\n   open fun joinChannel() {\n\n       var token=appLiveToken\n       if (TextUtils.isEmpty(token) || TextUtils.equals(token, \"#YOUR ACCESS TOKEN#\")) {\n           token = null \/\/ default, no token\n       }\n       rtcEngine().setChannelProfile(Constants.CHANNEL_PROFILE_LIVE_BROADCASTING)\n       rtcEngine().enableVideo()\n       configVideo()\n       rtcEngine().joinChannel(token,channelNameis, \"\", uid.toInt())\n\n\n   }\n\n   protected fun prepareRtcVideo(uid: Int, local: Boolean): SurfaceView {\n\n       val surface = RtcEngine.CreateRendererView(applicationContext)\n     surFaceIs= surface.toString()\n       surfaceViewJoin=surface\n       surfaceViewJoin?.let { surfaceView -&gt;\n           liveSuccessFull=true\n       } ?:\n       if(channelProfile==2){\n           if(surface==null)\n           {\n               joinChannel()\n           }\n\n       }\n       if(!liveSuccessFull){\n           if(channelProfile==2){\n               if(surface==null)\n               {\n                   joinChannel()\n               }\n\n           }\n       }\n\n       if (local) {\n           rtcEngine().setupLocalVideo(\n               VideoCanvas(\n                   surface,\n                   VideoCanvas.RENDER_MODE_HIDDEN,\n                   uid,\n                   Constants.VIDEO_MIRROR_MODES.get(config().mirrorLocalIndex)\n               )\n           )\n       } else {\n           Log.d(\"==&gt;\",\"surface=\"+surface)\n\n\n           rtcEngine().setupRemoteVideo(\n               VideoCanvas(\n                   surface,\n                   VideoCanvas.RENDER_MODE_HIDDEN,\n                   uid,\n                   Constants.VIDEO_MIRROR_MODES.get(config().mirrorRemoteIndex)\n               )\n           )\n\n\n       }\n       return surface\n   }\n\n   private fun reApiCallOfLive() {\n       intent.putExtra(AppConstants.LIVE_EXPERIENCE_KEY, dataExperienceDetails)\n       val channelProfile = io.agora.rtc.Constants.CLIENT_ROLE_AUDIENCE\n       val intent = Intent(this, LiveActivity::class.java)\n       val name = dataExperienceDetails.owner.firstName + \" \" + dataExperienceDetails.owner.lastName\n       intent.putExtra(\n           AppConstants.PREF_USER_APP_TOKEN_INTENT,\n           appPreferences.getAppPrefString(AppConstants.PREF_USER_JOIN_LIVE_APP_TOKEN)\n       )\n       intent.putExtra(\n           AppConstants.CHANNEL_MESSAGE, dataExperienceDetails.experienceDetails.roomName\n       )\n           intent.putExtra(\n           AppConstants.PREF_USER_PROFILE_LIVE,\n           appPreferences.getAppPrefString(AppConstants.PREF_USER_EXPERIENCE_USER_DETAILS_PROFILE_IMAGE)\n       )\n\n\n\n       intent.putExtra(\n           AppConstants.DATA_EXPERIENCE_DETAILS,\n           dataExperienceDetails\n       )\n       intent.putExtra(AppConstants.PREF_USER_PROFILER_NAME, name)\n       intent.putExtra(\n           AppConstants.PROFILE_MESSAGE,\n           channelProfile\n       ) \/\/Constants.CLIENT_ROLE_BROADCASTER;\/\/for host Constants.CLIENT_ROLE_AUDIENCE;\/\/for audience\n\n       intent.putExtra(\n           AppConstants.UID,\n           appPreferences.getAppPrefString(AppConstants.PREF_USER_DETAILS_Uid_JOIN_LIVE)!!\n               .toLongOrNull()\n       )\n       intent.putExtra(\n           AppConstants.LIVE_ADDRESS,\n           dataExperienceDetails.experienceDetails.experienceAddress\n       )\n       intent.putExtra(\n           AppConstants.LIVE_DESCRIPTION,\n           dataExperienceDetails.experienceDetails.experienceDescription\n       )\n       intent.putExtra(AppConstants.LIVE_EXP_DATE, dataExperienceDetails.createdAt)\n       shouldDoTopToBottomTransitionOnScreenChange = true\n       startActivity(intent)\n       finish()\n\n   }\n\n   protected fun removeRtcVideo(uid: Int, local: Boolean) {\n\n       if (local) {\n           rtcEngine().setupLocalVideo(null)\n       } else {\n           Log.d(\"==&gt;\",\"localrm=\"+local)\n\n           rtcEngine().setupRemoteVideo(VideoCanvas(null, VideoCanvas.RENDER_MODE_HIDDEN, uid))\n\n       }\n   }\n\n   override fun onDestroy() {\n       super.onDestroy()\n       removeRtcEventHandler(this)\n       rtcEngine().leaveChannel()\n   }\n}\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-livebaseactivity\"><em>LiveBaseActivity<\/em><\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"kotlin\" class=\"language-kotlin\">abstract class LiveBaseActivity : BaseActivity(), EventHandler {\n   protected var mDisplayMetrics = DisplayMetrics()\n   protected var mStatusBarHeight = 0\n   override fun onCreate(savedInstanceState: Bundle?) {\n       super.onCreate(savedInstanceState)\n       setGlobalLayoutListener()\n       displayMetrics\n       initStatusBarHeight()\n   }\n\n   private fun setGlobalLayoutListener() {\n       val layout = findViewById&lt;View&gt;(Window.ID_ANDROID_CONTENT)\n       val observer = layout.viewTreeObserver\n       observer.addOnGlobalLayoutListener(object : OnGlobalLayoutListener {\n           override fun onGlobalLayout() {\n               layout.viewTreeObserver.removeOnGlobalLayoutListener(this)\n               onGlobalLayoutCompleted()\n           }\n       })\n   }\n\n   protected open fun onGlobalLayoutCompleted() {}\n   private val displayMetrics: Unit\n       private get() {\n           windowManager.defaultDisplay.getMetrics(mDisplayMetrics)\n       }\n\n   private fun initStatusBarHeight() {\n       mStatusBarHeight = WindowUtil.getSystemStatusBarHeight(this)\n   }\n\n   protected fun application(): MyApplication {\n       return application as MyApplication\n   }\n\n   protected fun rtcEngine(): RtcEngine {\n       return application().rtcEngine()!!\n   }\n\n   protected fun config(): EngineConfig {\n       return application().engineConfig()!!\n   }\n\n   protected fun statsManager(): StatsManager? {\n       return application().statsManager()\n   }\n\n   protected fun registerRtcEventHandler(handler: EventHandler?) {\n       application().registerEventHandler(handler)\n   }\n\n   protected fun removeRtcEventHandler(handler: EventHandler?) {\n       application().removeEventHandler(handler)\n   }\n   override fun onFirstRemoteVideoDecoded(uid: Int, width: Int, height: Int, elapsed: Int) {}\n   override fun onJoinChannelSuccess(channel: String?, uid: Int, elapsed: Int) {\n   }\n\n\n   override fun onLeaveChannel(stats: RtcStats?) {}\n\n\n   override fun onUserOffline(uid: Int, reason: Int) {}\n   override fun onUserJoined(uid: Int, elapsed: Int) {\n   }\n   override fun onLastmileQuality(quality: Int) {}\n\n     override fun onLastmileProbeResult(result: LastmileProbeResult?) {}\n   override fun onLocalVideoStats(stats: LocalVideoStats?) {}\n\n    override fun onRtcStats(stats: RtcStats?) {}\n   override fun onNetworkQuality(uid: Int, txQuality: Int, rxQuality: Int) {}\n   override fun onRemoteVideoStats(stats: RemoteVideoStats?) {}\n   override fun onRemoteAudioStats(stats: RemoteAudioStats?) {}\n}\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-5-now-videogridcontainer-adapter-you-need-to-create\">5. Now VideoGridContainer Adapter you Need to Create.<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"java\" class=\"language-java\">public class VideoGridContainer extends RelativeLayout implements Runnable {\n   private static final int MAX_USER = 4;\n   private static final int STATS_REFRESH_INTERVAL = 2000;\n   private static final int STAT_LEFT_MARGIN = 34;\n   private static final int STAT_TEXT_SIZE = 10;\n\n   private SparseArray&lt;ViewGroup&gt; mUserViewList = new SparseArray&lt;&gt;(MAX_USER);\n   private List&lt;Integer&gt; mUidList = new ArrayList&lt;&gt;(MAX_USER);\n   private StatsManager mStatsManager;\n   private Handler mHandler;\n   private int mStatMarginBottom;\n\n   public VideoGridContainer(Context context) {\n       super(context);\n       init();\n   }\n\n   public VideoGridContainer(Context context, AttributeSet attrs) {\n       super(context, attrs);\n       init();\n   }\n\n   public VideoGridContainer(Context context, AttributeSet attrs, int defStyleAttr) {\n       super(context, attrs, defStyleAttr);\n       init();\n   }\n\n   private void init() {\n       setBackgroundResource(R.drawable.live_room_bg);\n       mStatMarginBottom = getResources().getDimensionPixelSize(\n               R.dimen.live_stat_margin_bottom);\n       mHandler = new Handler(getContext().getMainLooper());\n   }\n\n   public void setStatsManager(StatsManager manager) {\n       mStatsManager = manager;\n   }\n\n   public void addUserVideoSurface(int uid, SurfaceView surface, boolean isLocal) {\n       if (surface == null) {\n           return;\n       }\n\n       int id = -1;\n       if (isLocal) {\n           if (mUidList.contains(0)) {\n               mUidList.remove((Integer) 0);\n               mUserViewList.remove(0);\n           }\n\n           if (mUidList.size() == MAX_USER) {\n               mUidList.remove(0);\n               mUserViewList.remove(0);\n           }\n           id = 0;\n       } else {\n           if (mUidList.contains(uid)) {\n               mUidList.remove((Integer) uid);\n               mUserViewList.remove(uid);\n           }\n\n           if (mUidList.size() &lt; MAX_USER) {\n               id = uid;\n           }\n       }\n\n       if (id == 0) mUidList.add(0, uid);\n       else mUidList.add(uid);\n\n       if (id != -1) {\n           mUserViewList.append(uid, createVideoView(surface));\n\n           if (mStatsManager != null) {\n               mStatsManager.addUserStats(uid, isLocal);\n               if (mStatsManager.isEnabled()) {\n                   mHandler.removeCallbacks(this);\n                   mHandler.postDelayed(this, STATS_REFRESH_INTERVAL);\n               }\n           }\n\n           requestGridLayout();\n       }\n   }\n\n   private ViewGroup createVideoView(SurfaceView surface) {\n       RelativeLayout layout = new RelativeLayout(getContext());\n\n       layout.setId(surface.hashCode());\n\n       LayoutParams videoLayoutParams =\n               new LayoutParams(\n                       ViewGroup.LayoutParams.MATCH_PARENT,\n                       ViewGroup.LayoutParams.MATCH_PARENT);\n       layout.addView(surface, videoLayoutParams);\n\n       TextView text = new TextView(getContext());\n       text.setId(layout.hashCode());\n       LayoutParams textParams =\n               new LayoutParams(\n                       ViewGroup.LayoutParams.MATCH_PARENT,\n                       ViewGroup.LayoutParams.WRAP_CONTENT);\n       textParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.TRUE);\n       textParams.bottomMargin = mStatMarginBottom;\n       textParams.leftMargin = STAT_LEFT_MARGIN;\n       text.setTextColor(Color.WHITE);\n       text.setTextSize(STAT_TEXT_SIZE);\n\n       layout.addView(text, textParams);\n       return layout;\n   }\n\n   public void removeUserVideo(int uid, boolean isLocal) {\n       if (isLocal &amp;&amp; mUidList.contains(0)) {\n           mUidList.remove((Integer) 0);\n           mUserViewList.remove(0);\n       } else if (mUidList.contains(uid)) {\n           mUidList.remove((Integer) uid);\n           mUserViewList.remove(uid);\n       }\n\n       mStatsManager.removeUserStats(uid);\n       requestGridLayout();\n\n       if (getChildCount() == 0) {\n           mHandler.removeCallbacks(this);\n       }\n   }\n\n   private void requestGridLayout() {\n       removeAllViews();\n       layout(mUidList.size());\n   }\n\n   private void layout(int size) {\n       LayoutParams[] params = getParams(size);\n       for (int i = 0; i &lt; size; i++) {\n           addView(mUserViewList.get(mUidList.get(i)), params[i]);\n       }\n   }\n\n   private LayoutParams[] getParams(int size) {\n       int width = getMeasuredWidth();\n       int height = getMeasuredHeight();\n\n       LayoutParams[] array =\n               new LayoutParams[size];\n\n       for (int i = 0; i &lt; size; i++) {\n           if (i == 0) {\n               array[0] = new LayoutParams(\n                       LayoutParams.MATCH_PARENT,\n                       LayoutParams.MATCH_PARENT);\n               array[0].addRule(RelativeLayout.ALIGN_PARENT_TOP, RelativeLayout.TRUE);\n               array[0].addRule(RelativeLayout.ALIGN_PARENT_LEFT, RelativeLayout.TRUE);\n           } else if (i == 1) {\n               array[1] = new LayoutParams(width, height \/ 2);\n               array[0].height = array[1].height;\n               array[1].addRule(RelativeLayout.BELOW, mUserViewList.get(mUidList.get(0)).getId());\n               array[1].addRule(RelativeLayout.ALIGN_PARENT_LEFT, RelativeLayout.TRUE);\n           } else if (i == 2) {\n               array[i] = new LayoutParams(width \/ 2, height \/ 2);\n               array[i - 1].width = array[i].width;\n               array[i].addRule(RelativeLayout.RIGHT_OF, mUserViewList.get(mUidList.get(i - 1)).getId());\n               array[i].addRule(RelativeLayout.ALIGN_TOP, mUserViewList.get(mUidList.get(i - 1)).getId());\n           } else if (i == 3) {\n               array[i] = new LayoutParams(width \/ 2, height \/ 2);\n               array[0].width = width \/ 2;\n               array[1].addRule(RelativeLayout.BELOW, 0);\n               array[1].addRule(RelativeLayout.ALIGN_PARENT_LEFT, 0);\n               array[1].addRule(RelativeLayout.RIGHT_OF, mUserViewList.get(mUidList.get(0)).getId());\n               array[1].addRule(RelativeLayout.ALIGN_PARENT_TOP, RelativeLayout.TRUE);\n               array[2].addRule(RelativeLayout.ALIGN_PARENT_LEFT, RelativeLayout.TRUE);\n               array[2].addRule(RelativeLayout.RIGHT_OF, 0);\n               array[2].addRule(RelativeLayout.ALIGN_TOP, 0);\n               array[2].addRule(RelativeLayout.BELOW, mUserViewList.get(mUidList.get(0)).getId());\n               array[3].addRule(RelativeLayout.BELOW, mUserViewList.get(mUidList.get(1)).getId());\n               array[3].addRule(RelativeLayout.RIGHT_OF, mUserViewList.get(mUidList.get(2)).getId());\n           }\n       }\n\n       return array;\n   }\n\n   @Override\n   protected void onDetachedFromWindow() {\n       super.onDetachedFromWindow();\n       clearAllVideo();\n   }\n\n   private void clearAllVideo() {\n       removeAllViews();\n       mUserViewList.clear();\n       mUidList.clear();\n       mHandler.removeCallbacks(this);\n   }\n\n   @Override\n   public void run() {\n       if (mStatsManager != null &amp;&amp; mStatsManager.isEnabled()) {\n           int count = getChildCount();\n           for (int i = 0; i &lt; count; i++) {\n               RelativeLayout layout = (RelativeLayout) getChildAt(i);\n               TextView text = layout.findViewById(layout.hashCode());\n               if (text != null) {\n                   StatsData data = mStatsManager.getStatsData(mUidList.get(i));\n                   String info = data != null ? data.toString() : null;\n                   if (info != null) text.setText(info);\n               }\n           }\n\n           mHandler.postDelayed(this, STATS_REFRESH_INTERVAL);\n       }\n   }\n}\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">6. Now you need to create three util class below the name.<\/h2>\n\n\n\n<ol class=\"wp-block-list\">\n<li>AgoraEventHandler<\/li>\n\n\n\n<li>EngineConfig<\/li>\n\n\n\n<li>EventHandler<\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\">1. AgoraEventHandler util class<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"kotlin\" class=\"language-kotlin\">public class AgoraEventHandler extends IRtcEngineEventHandler {\n    private ArrayList&lt;EventHandler&gt; mHandler = new ArrayList&lt;&gt;();\n\n    public void addHandler(EventHandler handler) {\n        mHandler.add(handler);\n    }\n\n    public void removeHandler(EventHandler handler) {\n        mHandler.remove(handler);\n    }\n\n    @Override\n    public void onJoinChannelSuccess(String channel, int uid, int elapsed) {\n        for (EventHandler handler : mHandler) {\n            handler.onJoinChannelSuccess(channel, uid, elapsed);\n        }\n    }\n\n    @Override\n    public void onLeaveChannel(RtcStats stats) {\n        for (EventHandler handler : mHandler) {\n            handler.onLeaveChannel(stats);\n        }\n    }\n\n    @Override\n    public void onFirstRemoteVideoDecoded(int uid, int width, int height, int elapsed) {\n        for (EventHandler handler : mHandler) {\n            handler.onFirstRemoteVideoDecoded(uid, width, height, elapsed);\n        }\n    }\n\n    @Override\n    public void onUserJoined(int uid, int elapsed) {\n        for (EventHandler handler : mHandler) {\n            handler.onUserJoined(uid, elapsed);\n        }\n    }\n\n    @Override\n    public void onUserOffline(int uid, int reason) {\n        for (EventHandler handler : mHandler) {\n            handler.onUserOffline(uid, reason);\n        }\n\n\n    }\n\n    @Override\n    public void onLocalVideoStats(LocalVideoStats stats) {\n        for (EventHandler handler : mHandler) {\n            handler.onLocalVideoStats(stats);\n        }\n    }\n\n    @Override\n    public void onRtcStats(RtcStats stats) {\n        for (EventHandler handler : mHandler) {\n            handler.onRtcStats(stats);\n        }\n    }\n\n    @Override\n    public void onNetworkQuality(int uid, int txQuality, int rxQuality) {\n        for (EventHandler handler : mHandler) {\n            handler.onNetworkQuality(uid, txQuality, rxQuality);\n        }\n    }\n\n    @Override\n    public void onRemoteVideoStats(RemoteVideoStats stats) {\n        for (EventHandler handler : mHandler) {\n            handler.onRemoteVideoStats(stats);\n        }\n    }\n\n    @Override\n    public void onRemoteAudioStats(RemoteAudioStats stats) {\n        for (EventHandler handler : mHandler) {\n            handler.onRemoteAudioStats(stats);\n        }\n    }\n\n    @Override\n    public void onLastmileQuality(int quality) {\n        for (EventHandler handler : mHandler) {\n            handler.onLastmileQuality(quality);\n        }\n    }\n\n    @Override\n    public void onLastmileProbeResult(LastmileProbeResult result) {\n        for (EventHandler handler : mHandler) {\n            handler.onLastmileProbeResult(result);\n        }\n    }\n}\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">2. EngineConfig util class<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"html\" class=\"language-html\">public class EngineConfig {\n   \/\/ private static final int DEFAULT_UID = 0;\n   \/\/ private int mUid = DEFAULT_UID;\n\n   private String mChannelName;\n   private boolean mShowVideoStats;\n   private int mDimenIndex = Constants.DEFAULT_PROFILE_IDX;\n   private int mMirrorLocalIndex;\n   private int mMirrorRemoteIndex;\n   private int mMirrorEncodeIndex;\n\n\n   public int getVideoDimenIndex() {\n       return mDimenIndex;\n   }\n\n   public void setVideoDimenIndex(int index) {\n       mDimenIndex = index;\n   }\n\n   public String getChannelName() {\n       return mChannelName;\n   }\n\n   public void setChannelName(String mChannel) {\n       this.mChannelName = mChannel;\n   }\n\n   public boolean ifShowVideoStats() {\n       return mShowVideoStats;\n   }\n\n   public void setIfShowVideoStats(boolean show) {\n       mShowVideoStats = show;\n   }\n\n   public int getMirrorLocalIndex() {\n       return mMirrorLocalIndex;\n   }\n\n   public void setMirrorLocalIndex(int index) {\n       mMirrorLocalIndex = index;\n   }\n\n   public int getMirrorRemoteIndex() {\n       return mMirrorRemoteIndex;\n   }\n\n   public void setMirrorRemoteIndex(int index) {\n       mMirrorRemoteIndex = index;\n   }\n\n   public int getMirrorEncodeIndex() {\n       return mMirrorEncodeIndex;\n   }\n\n   public void setMirrorEncodeIndex(int index) {\n       mMirrorEncodeIndex = index;\n   }\n}\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">3. EventHandler util class<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"kotlin\" class=\"language-kotlin\">public interface EventHandler {\n   void onFirstRemoteVideoDecoded(int uid, int width, int height, int elapsed);\n\n   void onLeaveChannel(IRtcEngineEventHandler.RtcStats stats);\n\n   void onJoinChannelSuccess(String channel, int uid, int elapsed);\n\n   void onUserOffline(int uid, int reason);\n\n   void onUserJoined(int uid, int elapsed);\n\n   void onLastmileQuality(int quality);\n\n   void onLastmileProbeResult(IRtcEngineEventHandler.LastmileProbeResult result);\n\n   void onLocalVideoStats(IRtcEngineEventHandler.LocalVideoStats stats);\n\n   void onRtcStats(IRtcEngineEventHandler.RtcStats stats);\n\n   void onNetworkQuality(int uid, int txQuality, int rxQuality);\n\n   void onRemoteVideoStats(IRtcEngineEventHandler.RemoteVideoStats stats);\n\n   void onRemoteAudioStats(IRtcEngineEventHandler.RemoteAudioStats stats);\n\n}\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">7. Now you need to create below four utill class<\/h2>\n\n\n\n<ol class=\"wp-block-list\">\n<li>LocalStatsData<\/li>\n\n\n\n<li>RemoteStatsData<\/li>\n\n\n\n<li>StatsData<\/li>\n\n\n\n<li>StatsManager<\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\">1. LocalStatsData<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"kotlin\" class=\"language-kotlin\">public class LocalStatsData extends StatsData {\n   private static final String FORMAT = \"Local(%d)\\n\\n\" +\n           \"%dx%d %dfps\\n\" +\n           \"LastMile delay: %d ms\\n\" +\n           \"Video tx\/rx (kbps): %d\/%d\\n\" +\n           \"Audio tx\/rx (kbps): %d\/%d\\n\" +\n           \"CPU: app\/total %.1f%%\/%.1f%%\\n\" +\n           \"Quality tx\/rx: %s\/%s\\n\" +\n           \"Loss tx\/rx: %d%%\/%d%%\";\n\n   private int lastMileDelay;\n   private int videoSend;\n   private int videoRecv;\n   private int audioSend;\n   private int audioRecv;\n   private double cpuApp;\n   private double cpuTotal;\n   private int sendLoss;\n   private int recvLoss;\n\n   @Override\n   public String toString() {\n       return String.format(Locale.getDefault(), FORMAT,\n               getUid(),\n               getWidth(), getHeight(), getFramerate(),\n               getLastMileDelay(),\n               getVideoSendBitrate(), getVideoRecvBitrate(),\n               getAudioSendBitrate(), getAudioRecvBitrate(),\n               getCpuApp(), getCpuTotal(),\n               getSendQuality(), getRecvQuality(),\n               getSendLoss(), getRecvLoss());\n   }\n\n   public int getLastMileDelay() {\n       return lastMileDelay;\n   }\n\n   public void setLastMileDelay(int lastMileDelay) {\n       this.lastMileDelay = lastMileDelay;\n   }\n\n   public int getVideoSendBitrate() {\n       return videoSend;\n   }\n\n   public void setVideoSendBitrate(int videoSend) {\n       this.videoSend = videoSend;\n   }\n\n   public int getVideoRecvBitrate() {\n       return videoRecv;\n   }\n\n   public void setVideoRecvBitrate(int videoRecv) {\n       this.videoRecv = videoRecv;\n   }\n\n   public int getAudioSendBitrate() {\n       return audioSend;\n   }\n\n   public void setAudioSendBitrate(int audioSend) {\n       this.audioSend = audioSend;\n   }\n\n   public int getAudioRecvBitrate() {\n       return audioRecv;\n   }\n\n   public void setAudioRecvBitrate(int audioRecv) {\n       this.audioRecv = audioRecv;\n   }\n\n   public double getCpuApp() {\n       return cpuApp;\n   }\n\n   public void setCpuApp(double cpuApp) {\n       this.cpuApp = cpuApp;\n   }\n\n   public double getCpuTotal() {\n       return cpuTotal;\n   }\n\n   public void setCpuTotal(double cpuTotal) {\n       this.cpuTotal = cpuTotal;\n   }\n\n   public int getSendLoss() {\n       return sendLoss;\n   }\n\n   public void setSendLoss(int sendLoss) {\n       this.sendLoss = sendLoss;\n   }\n\n   public int getRecvLoss() {\n       return recvLoss;\n   }\n\n   public void setRecvLoss(int recvLoss) {\n       this.recvLoss = recvLoss;\n   }\n\n}\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">2. RemoteStatsData<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"kotlin\" class=\"language-kotlin\">public class RemoteStatsData extends StatsData {\n   private static final String FORMAT = \"Remote(%d)\\n\\n\" +\n           \"%dx%d %dfps\\n\" +\n           \"Quality tx\/rx: %s\/%s\\n\" +\n           \"Video delay: %d ms\\n\" +\n           \"Audio net delay\/jitter: %dms\/%dms\\n\" +\n           \"Audio loss\/quality: %d%%\/%s\";\n\n   private int videoDelay;\n   private int audioNetDelay;\n   private int audioNetJitter;\n   private int audioLoss;\n   private String audioQuality;\n\n   @Override\n   public String toString() {\n       return String.format(Locale.getDefault(), FORMAT,\n               getUid(),\n               getWidth(), getHeight(), getFramerate(),\n               getSendQuality(), getRecvQuality(),\n               getVideoDelay(),\n               getAudioNetDelay(), getAudioNetJitter(),\n               getAudioLoss(), getAudioQuality());\n   }\n\n   public static String getFORMAT() {\n       return FORMAT;\n   }\n\n   public int getVideoDelay() {\n       return videoDelay;\n   }\n\n   public void setVideoDelay(int videoDelay) {\n       this.videoDelay = videoDelay;\n   }\n\n   public int getAudioNetDelay() {\n       return audioNetDelay;\n   }\n\n   public void setAudioNetDelay(int audioNetDelay) {\n       this.audioNetDelay = audioNetDelay;\n   }\n\n   public int getAudioNetJitter() {\n       return audioNetJitter;\n   }\n\n   public void setAudioNetJitter(int audioNetJitter) {\n       this.audioNetJitter = audioNetJitter;\n   }\n\n   public int getAudioLoss() {\n       return audioLoss;\n   }\n\n   public void setAudioLoss(int audioLoss) {\n       this.audioLoss = audioLoss;\n   }\n\n   public String getAudioQuality() {\n       return audioQuality;\n   }\n\n   public void setAudioQuality(String audioQuality) {\n       this.audioQuality = audioQuality;\n   }\n}\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">3. StatsData<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"kotlin\" class=\"language-kotlin\">public class StatsData {\n   private long uid;\n   private int width;\n   private int height;\n   private int framerate;\n   private String recvQuality;\n   private String sendQuality;\n\n   public long getUid() {\n       return uid;\n   }\n\n   public void setUid(long uid) {\n       this.uid = uid;\n   }\n\n   public int getWidth() {\n       return width;\n   }\n\n   public void setWidth(int width) {\n       this.width = width;\n   }\n\n   public int getHeight() {\n       return height;\n   }\n\n   public void setHeight(int height) {\n       this.height = height;\n   }\n\n   public int getFramerate() {\n       return framerate;\n   }\n\n   public void setFramerate(int framerate) {\n       this.framerate = framerate;\n   }\n\n   public String getRecvQuality() {\n       return recvQuality;\n   }\n\n   public void setRecvQuality(String recvQuality) {\n       this.recvQuality = recvQuality;\n   }\n\n   public String getSendQuality() {\n       return sendQuality;\n   }\n\n   public void setSendQuality(String sendQuality) {\n       this.sendQuality = sendQuality;\n   }\n}\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">4. StatsManager<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"java\" class=\"language-java\">import java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport io.agora.rtc.Constants;\n\npublic class StatsManager {\n   private List&lt;Integer&gt; mUidList = new ArrayList&lt;&gt;();\n   private Map&lt;Integer, StatsData&gt; mDataMap = new HashMap&lt;&gt;();\n   private boolean mEnable = false;\n\n   public void addUserStats(int uid, boolean ifLocal) {\n       if (mUidList.contains(uid) &amp;&amp; mDataMap.containsKey(uid)) {\n           return;\n       }\n\n       StatsData data = ifLocal\n               ? new LocalStatsData()\n               : new RemoteStatsData();\n       \/\/ in case 32-bit unsigned integer uid is received\n       data.setUid(uid &amp; 0xFFFFFFFFL);\n\n       if (ifLocal) mUidList.add(0, uid);\n       else mUidList.add(uid);\n\n       mDataMap.put(uid, data);\n   }\n\n   public void removeUserStats(int uid) {\n       if (mUidList.contains(uid) &amp;&amp; mDataMap.containsKey(uid)) {\n           mUidList.remove((Integer) uid);\n           mDataMap.remove(uid);\n       }\n   }\n\n   public StatsData getStatsData(int uid) {\n       if (mUidList.contains(uid) &amp;&amp; mDataMap.containsKey(uid)) {\n           return mDataMap.get(uid);\n       } else {\n           return null;\n       }\n   }\n\n   public String qualityToString(int quality) {\n       switch (quality) {\n           case Constants.QUALITY_EXCELLENT:\n               return \"Exc\";\n           case Constants.QUALITY_GOOD:\n               return \"Good\";\n           case Constants.QUALITY_POOR:\n               return \"Poor\";\n           case Constants.QUALITY_BAD:\n               return \"Bad\";\n           case Constants.QUALITY_VBAD:\n               return \"VBad\";\n           case Constants.QUALITY_DOWN:\n               return \"Down\";\n           default:\n               return \"Unk\";\n       }\n   }\n\n   public void enableStats(boolean enabled) {\n       mEnable = enabled;\n   }\n\n   public boolean isEnabled() {\n       return mEnable;\n   }\n\n   public void clearAllData() {\n       mUidList.clear();\n       mDataMap.clear();\n\n   }\n}<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Why Agora is the Best Solution for Live Audio &amp; Video Streaming?<\/h2>\n\n\n\n<p>Agora live Streaming is used for analytics tracking, customer support, video monetization, and cost-effectiveness. Agora live Streaming is used for analytics tracking and one to many and many to many audio or video live streaming with agora SDK, in a video calling with audio interactive live streaming. users can be host or audiences, the host can start live and the audience joins that streaming one too many and many too many audio or video live streaming also possible.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/www.oneclickitsolution.com\/contact-us\/\" target=\"_blank\" rel=\"noopener\"><img decoding=\"async\" src=\"https:\/\/www.oneclickitsolution.com\/blog\/wp-content\/uploads\/2021\/12\/Android-Custom-Library-CTA1.png\" alt=\"Android Custom Library CTA1\" class=\"wp-image-46722\"\/><\/a><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p>I would like to conclude this blog is used for Live streaming which improves Ease Convenience and cost-effectiveness, used for analytics tracking, and one to many and many to many audio or <strong><a href=\"https:\/\/www.oneclickitsolution.com\/solutions\/cost-to-develop-a-video-streaming-application-like-netflix\/\" target=\"_blank\" rel=\"noreferrer noopener\">Video Live Streaming <\/a><\/strong>Using Agora SDK and Live Streaming Internet Video Can Whip Up Online Interaction.<\/p>\n\n\n\n<p>Social media and live streaming platforms have made it easy and effortless for anyone to live stream from their smart devices. With live streaming, building brands from new ideas can make it easier for their senior employees and team leads to communicate and exchange information with the team.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">FAQs<\/h2>\n\n\n\n<div class=\"schema-faq wp-block-yoast-faq-block\"><div class=\"schema-faq-section\" id=\"faq-question-1649763719667\"><strong class=\"schema-faq-question\">1. Can I Make a Custom UI?<\/strong> <p class=\"schema-faq-answer\">Yes, it is possible you can make it.<\/p> <\/div> <div class=\"schema-faq-section\" id=\"faq-question-1649763743523\"><strong class=\"schema-faq-question\">2. Can we use live streams on iOS and Apple both devices with the same app?<\/strong> <p class=\"schema-faq-answer\">Yes, it is possible on both devices.<\/p> <\/div> <div class=\"schema-faq-section\" id=\"faq-question-1649763769800\"><strong class=\"schema-faq-question\">3. Why does a blank screen come when a user joins a live stream?<\/strong> <p class=\"schema-faq-answer\">Sometimes the first time a live stream frame is not initialized because of some token invalid issue etc.<\/p> <\/div> <div class=\"schema-faq-section\" id=\"faq-question-1649764667674\"><strong class=\"schema-faq-question\">4. What is the channel?<\/strong> <p class=\"schema-faq-answer\">Channel used for transmitting real-time data in the agora<\/p> <\/div> <div class=\"schema-faq-section\" id=\"faq-question-1649764770493\"><strong class=\"schema-faq-question\">5. What is video SDK?<\/strong> <p class=\"schema-faq-answer\">It enables users to build unique live videos.<\/p> <\/div> <div class=\"schema-faq-section\" id=\"faq-question-1649764782858\"><strong class=\"schema-faq-question\">6. What is agora live streaming?<\/strong> <p class=\"schema-faq-answer\">It enables one-to-many and many-to-many audio or video live streaming.<\/p> <\/div> <\/div>\n","protected":false},"excerpt":{"rendered":"<p>Introduction Agora live Streaming platform is used for analytics tracking and one to many and many to many audio or video live streaming with Agora SDK. In video calling with audio interactive live streaming, users can be host or audience and the host can start live and the audience by joining that streaming. Why Agora &hellip;<\/p>\n","protected":false},"author":73,"featured_media":54636,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[516,838],"tags":[901,970],"class_list":["post-49739","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-mobile-apps","category-solutions","tag-android","tag-live-streaming"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v18.2.1 (Yoast SEO v24.8.1) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>How to Add Live Streaming in Android Application Using Agora?<\/title>\n<meta name=\"description\" content=\"Learn how to add live video streaming to an Android app using agora that is easy and effortless for anyone to live stream from their devices.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.oneclickitsolution.com\/blog\/live-streaming-in-android-application-using-agora\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"How to Add Live Streaming in Android Application Using Agora?\" \/>\n<meta property=\"og:description\" content=\"Learn how to add live video streaming to an Android app using agora that is easy and effortless for anyone to live stream from their devices.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.oneclickitsolution.com\/blog\/live-streaming-in-android-application-using-agora\" \/>\n<meta property=\"og:site_name\" content=\"OneClick IT Consultancy\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/oneclickconsultancy\" \/>\n<meta property=\"article:published_time\" content=\"2023-12-29T12:09:48+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2023-12-29T12:09:50+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.oneclickitsolution.com\/blog\/wp-content\/uploads\/2022\/04\/Live-Streaming-in-Android-Application-Using-Agora.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"628\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Jigar Viradiya\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@OneclickIT\" \/>\n<meta name=\"twitter:site\" content=\"@OneclickIT\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Jigar Viradiya\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"4 minutes\" \/>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"How to Add Live Streaming in Android Application Using Agora?","description":"Learn how to add live video streaming to an Android app using agora that is easy and effortless for anyone to live stream from their devices.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.oneclickitsolution.com\/blog\/live-streaming-in-android-application-using-agora","og_locale":"en_US","og_type":"article","og_title":"How to Add Live Streaming in Android Application Using Agora?","og_description":"Learn how to add live video streaming to an Android app using agora that is easy and effortless for anyone to live stream from their devices.","og_url":"https:\/\/www.oneclickitsolution.com\/blog\/live-streaming-in-android-application-using-agora","og_site_name":"OneClick IT Consultancy","article_publisher":"https:\/\/www.facebook.com\/oneclickconsultancy","article_published_time":"2023-12-29T12:09:48+00:00","article_modified_time":"2023-12-29T12:09:50+00:00","og_image":[{"width":1200,"height":628,"url":"https:\/\/www.oneclickitsolution.com\/blog\/wp-content\/uploads\/2022\/04\/Live-Streaming-in-Android-Application-Using-Agora.png","type":"image\/png"}],"author":"Jigar Viradiya","twitter_card":"summary_large_image","twitter_creator":"@OneclickIT","twitter_site":"@OneclickIT","twitter_misc":{"Written by":"Jigar Viradiya","Est. reading time":"4 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.oneclickitsolution.com\/blog\/live-streaming-in-android-application-using-agora#article","isPartOf":{"@id":"https:\/\/www.oneclickitsolution.com\/blog\/live-streaming-in-android-application-using-agora"},"author":{"name":"Jigar Viradiya","@id":"https:\/\/www.oneclickitsolution.com\/blog\/#\/schema\/person\/63dc606d4c5e594a3fdeab9994adf2b6"},"headline":"How to Add Live Streaming in Android Application Using Agora?","datePublished":"2023-12-29T12:09:48+00:00","dateModified":"2023-12-29T12:09:50+00:00","mainEntityOfPage":{"@id":"https:\/\/www.oneclickitsolution.com\/blog\/live-streaming-in-android-application-using-agora"},"wordCount":664,"commentCount":0,"publisher":{"@id":"https:\/\/www.oneclickitsolution.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.oneclickitsolution.com\/blog\/live-streaming-in-android-application-using-agora#primaryimage"},"thumbnailUrl":"https:\/\/www.oneclickitsolution.com\/blog\/wp-content\/uploads\/2022\/04\/Live-Streaming-in-Android-Application-Using-Agora.png","keywords":["Android","Live Streaming"],"articleSection":["Mobile Application","Solutions"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.oneclickitsolution.com\/blog\/live-streaming-in-android-application-using-agora#respond"]}]},{"@type":["WebPage","FAQPage"],"@id":"https:\/\/www.oneclickitsolution.com\/blog\/live-streaming-in-android-application-using-agora","url":"https:\/\/www.oneclickitsolution.com\/blog\/live-streaming-in-android-application-using-agora","name":"How to Add Live Streaming in Android Application Using Agora?","isPartOf":{"@id":"https:\/\/www.oneclickitsolution.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.oneclickitsolution.com\/blog\/live-streaming-in-android-application-using-agora#primaryimage"},"image":{"@id":"https:\/\/www.oneclickitsolution.com\/blog\/live-streaming-in-android-application-using-agora#primaryimage"},"thumbnailUrl":"https:\/\/www.oneclickitsolution.com\/blog\/wp-content\/uploads\/2022\/04\/Live-Streaming-in-Android-Application-Using-Agora.png","datePublished":"2023-12-29T12:09:48+00:00","dateModified":"2023-12-29T12:09:50+00:00","description":"Learn how to add live video streaming to an Android app using agora that is easy and effortless for anyone to live stream from their devices.","breadcrumb":{"@id":"https:\/\/www.oneclickitsolution.com\/blog\/live-streaming-in-android-application-using-agora#breadcrumb"},"mainEntity":[{"@id":"https:\/\/www.oneclickitsolution.com\/blog\/live-streaming-in-android-application-using-agora#faq-question-1649763719667"},{"@id":"https:\/\/www.oneclickitsolution.com\/blog\/live-streaming-in-android-application-using-agora#faq-question-1649763743523"},{"@id":"https:\/\/www.oneclickitsolution.com\/blog\/live-streaming-in-android-application-using-agora#faq-question-1649763769800"},{"@id":"https:\/\/www.oneclickitsolution.com\/blog\/live-streaming-in-android-application-using-agora#faq-question-1649764667674"},{"@id":"https:\/\/www.oneclickitsolution.com\/blog\/live-streaming-in-android-application-using-agora#faq-question-1649764770493"},{"@id":"https:\/\/www.oneclickitsolution.com\/blog\/live-streaming-in-android-application-using-agora#faq-question-1649764782858"}],"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.oneclickitsolution.com\/blog\/live-streaming-in-android-application-using-agora"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.oneclickitsolution.com\/blog\/live-streaming-in-android-application-using-agora#primaryimage","url":"https:\/\/www.oneclickitsolution.com\/blog\/wp-content\/uploads\/2022\/04\/Live-Streaming-in-Android-Application-Using-Agora.png","contentUrl":"https:\/\/www.oneclickitsolution.com\/blog\/wp-content\/uploads\/2022\/04\/Live-Streaming-in-Android-Application-Using-Agora.png","width":1200,"height":628,"caption":"Application Using Agora"},{"@type":"BreadcrumbList","@id":"https:\/\/www.oneclickitsolution.com\/blog\/live-streaming-in-android-application-using-agora#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Blog","item":"https:\/\/www.oneclickitsolution.com\/blog\/"},{"@type":"ListItem","position":2,"name":"How to Add Live Streaming in Android Application Using Agora?"}]},{"@type":"WebSite","@id":"https:\/\/www.oneclickitsolution.com\/blog\/#website","url":"https:\/\/www.oneclickitsolution.com\/blog\/","name":"OneClick IT Consultancy","description":"We Build Brands from Ideas","publisher":{"@id":"https:\/\/www.oneclickitsolution.com\/blog\/#organization"},"alternateName":"OneClick IT Solution","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.oneclickitsolution.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.oneclickitsolution.com\/blog\/#organization","name":"OneClick IT Consultancy","alternateName":"OneClick IT Solution","url":"https:\/\/www.oneclickitsolution.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.oneclickitsolution.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/www.oneclickitsolution.com\/blog\/wp-content\/uploads\/2022\/10\/oneclick-official-logo.png","contentUrl":"https:\/\/www.oneclickitsolution.com\/blog\/wp-content\/uploads\/2022\/10\/oneclick-official-logo.png","width":100,"height":100,"caption":"OneClick IT Consultancy"},"image":{"@id":"https:\/\/www.oneclickitsolution.com\/blog\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/oneclickconsultancy","https:\/\/x.com\/OneclickIT","https:\/\/www.instagram.com\/oneclick.it.consultancy\/","https:\/\/www.linkedin.com\/company\/one-click-it-consultancy\/","https:\/\/www.pinterest.com\/oneclickitconsultancy\/","https:\/\/www.youtube.com\/channel\/UCsEG6aiwOwvYrcZxMoP5xjg","https:\/\/oneclickit.tumblr.com\/","https:\/\/dribbble.com\/oneclickitconsultancy"]},{"@type":"Person","@id":"https:\/\/www.oneclickitsolution.com\/blog\/#\/schema\/person\/63dc606d4c5e594a3fdeab9994adf2b6","name":"Jigar Viradiya","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.oneclickitsolution.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/6c255f25a6583c5bd7d312ba36abb3f4?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/6c255f25a6583c5bd7d312ba36abb3f4?s=96&d=mm&r=g","caption":"Jigar Viradiya"},"description":"I am currently doing job as an Android developer in OneClick IT Consultancy past one year, I am very good in solving various types of problems to help our clients.","sameAs":["https:\/\/www.oneclickitsolution.com\/blog\/"],"jobTitle":"Software Engineer","url":"https:\/\/www.oneclickitsolution.com\/blog\/author\/jigar-viradiya"},{"@type":"Question","@id":"https:\/\/www.oneclickitsolution.com\/blog\/live-streaming-in-android-application-using-agora#faq-question-1649763719667","position":1,"url":"https:\/\/www.oneclickitsolution.com\/blog\/live-streaming-in-android-application-using-agora#faq-question-1649763719667","name":"1. Can I Make a Custom UI?","answerCount":1,"acceptedAnswer":{"@type":"Answer","text":"Yes, it is possible you can make it.","inLanguage":"en-US"},"inLanguage":"en-US"},{"@type":"Question","@id":"https:\/\/www.oneclickitsolution.com\/blog\/live-streaming-in-android-application-using-agora#faq-question-1649763743523","position":2,"url":"https:\/\/www.oneclickitsolution.com\/blog\/live-streaming-in-android-application-using-agora#faq-question-1649763743523","name":"2. Can we use live streams on iOS and Apple both devices with the same app?","answerCount":1,"acceptedAnswer":{"@type":"Answer","text":"Yes, it is possible on both devices.","inLanguage":"en-US"},"inLanguage":"en-US"},{"@type":"Question","@id":"https:\/\/www.oneclickitsolution.com\/blog\/live-streaming-in-android-application-using-agora#faq-question-1649763769800","position":3,"url":"https:\/\/www.oneclickitsolution.com\/blog\/live-streaming-in-android-application-using-agora#faq-question-1649763769800","name":"3. Why does a blank screen come when a user joins a live stream?","answerCount":1,"acceptedAnswer":{"@type":"Answer","text":"Sometimes the first time a live stream frame is not initialized because of some token invalid issue etc.","inLanguage":"en-US"},"inLanguage":"en-US"},{"@type":"Question","@id":"https:\/\/www.oneclickitsolution.com\/blog\/live-streaming-in-android-application-using-agora#faq-question-1649764667674","position":4,"url":"https:\/\/www.oneclickitsolution.com\/blog\/live-streaming-in-android-application-using-agora#faq-question-1649764667674","name":"4. What is the channel?","answerCount":1,"acceptedAnswer":{"@type":"Answer","text":"Channel used for transmitting real-time data in the agora","inLanguage":"en-US"},"inLanguage":"en-US"},{"@type":"Question","@id":"https:\/\/www.oneclickitsolution.com\/blog\/live-streaming-in-android-application-using-agora#faq-question-1649764770493","position":5,"url":"https:\/\/www.oneclickitsolution.com\/blog\/live-streaming-in-android-application-using-agora#faq-question-1649764770493","name":"5. What is video SDK?","answerCount":1,"acceptedAnswer":{"@type":"Answer","text":"It enables users to build unique live videos.","inLanguage":"en-US"},"inLanguage":"en-US"},{"@type":"Question","@id":"https:\/\/www.oneclickitsolution.com\/blog\/live-streaming-in-android-application-using-agora#faq-question-1649764782858","position":6,"url":"https:\/\/www.oneclickitsolution.com\/blog\/live-streaming-in-android-application-using-agora#faq-question-1649764782858","name":"6. What is agora live streaming?","answerCount":1,"acceptedAnswer":{"@type":"Answer","text":"It enables one-to-many and many-to-many audio or video live streaming.","inLanguage":"en-US"},"inLanguage":"en-US"}]}},"_links":{"self":[{"href":"https:\/\/www.oneclickitsolution.com\/blog\/wp-json\/wp\/v2\/posts\/49739"}],"collection":[{"href":"https:\/\/www.oneclickitsolution.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.oneclickitsolution.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.oneclickitsolution.com\/blog\/wp-json\/wp\/v2\/users\/73"}],"replies":[{"embeddable":true,"href":"https:\/\/www.oneclickitsolution.com\/blog\/wp-json\/wp\/v2\/comments?post=49739"}],"version-history":[{"count":0,"href":"https:\/\/www.oneclickitsolution.com\/blog\/wp-json\/wp\/v2\/posts\/49739\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.oneclickitsolution.com\/blog\/wp-json\/wp\/v2\/media\/54636"}],"wp:attachment":[{"href":"https:\/\/www.oneclickitsolution.com\/blog\/wp-json\/wp\/v2\/media?parent=49739"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.oneclickitsolution.com\/blog\/wp-json\/wp\/v2\/categories?post=49739"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.oneclickitsolution.com\/blog\/wp-json\/wp\/v2\/tags?post=49739"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}