如何解决无法让 agora 工作本地给我黑屏,远程永远连接不上
我同时在手机和模拟器上运行 Android Studio 中的代码。 两者都有适当的权限。我检查了系统设置。
这是我制作的 AgoraVideoChat 类:
package com.example.dnaire.camera
import android.Manifest
import android.annotation.SuppressLint
import android.content.pm.PackageManager
import android.graphics.PorterDuff
import android.os.Bundle
import android.util.Log
import android.view.SurfaceView
import android.view.View
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import com.example.dnaire.R
import com.example.dnaire.databinding.VideoCallingBinding
import com.example.dnaire.firebase.firebase
import com.google.firebase.database.FirebaseDatabase
import io.agora.rtc.IRtcEngineEventHandler
import io.agora.rtc.RtcEngine
import io.agora.rtc.video.VideoCanvas
import io.agora.rtc.video.VideoEncoderConfiguration
class VideoChatViewActivity: AppCompatActivity() {
lateinit var binding : VideoCallingBinding
private var mRtcEngine: RtcEngine? = null
companion object {
private val LOG_TAG = VideoChatViewActivity::class.java.simpleName
private val PERMISSION_REQ_ID_RECORD_AUDIO = 22
private val PERMISSION_REQ_ID_CAMERA = PERMISSION_REQ_ID_RECORD_AUDIO + 1
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = VideoCallingBinding.inflate(layoutInflater)
setContentView(binding.root)
if (checkSelfPermission(Manifest.permission.RECORD_AUDIO,PERMISSION_REQ_ID_RECORD_AUDIO) && checkSelfPermission(
Manifest.permission.CAMERA,PERMISSION_REQ_ID_CAMERA
)) {
initAgoraEngineAndJoinChannel()
}
firebase()
}
fun checkSelfPermission(permission: String,requestCode: Int): Boolean {
Log.i(LOG_TAG,"checkSelfPermission $permission $requestCode")
if (ContextCompat.checkSelfPermission(
this,permission
) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(
this,arrayOf(permission),requestCode
)
return false
}
return true
}
@SuppressLint("MissingSuperCall")
override fun onRequestPermissionsResult(
requestCode: Int,permissions: Array<String>,grantResults: IntArray
) {
Log.i(LOG_TAG,"onRequestPermissionsResult " + grantResults[0] + " " + requestCode)
when (requestCode) {
PERMISSION_REQ_ID_RECORD_AUDIO -> {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
checkSelfPermission(Manifest.permission.CAMERA,PERMISSION_REQ_ID_CAMERA)
} else {
showLongToast("No permission for " + Manifest.permission.RECORD_AUDIO)
finish()
}
}
PERMISSION_REQ_ID_CAMERA -> {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
initAgoraEngineAndJoinChannel()
} else {
showLongToast("No permission for " + Manifest.permission.CAMERA)
finish()
}
}
}
}
fun showLongToast(msg: String) {
this.runOnUiThread { Toast.makeText(applicationContext,msg,Toast.LENGTH_LONG).show() }
}
private fun initAgoraEngineAndJoinChannel() {
initializeAgoraEngine()
setupLocalVideo()
joinChannel()
}
private val mRtcEventHandler = object : IRtcEngineEventHandler() {
// Listen for the onFirstRemoteVideoDecoded callback.
// This callback occurs when the first video frame of a remote user is received and decoded after the remote user successfully joins the channel.
// You can call the setupRemoteVideo method in this callback to set up the remote video view.
override fun onFirstRemoteVideoDecoded(uid: Int,width: Int,height: Int,elapsed: Int) {
Log.i("testen","VideoChatViewActivity/onFireRemoteVideoDecoded called")
runOnUiThread { setupRemoteVideo(uid) }
}
// Listen for the onUserOffline callback.
// This callback occurs when the remote user leaves the channel or drops offline.
override fun onUserOffline(uid: Int,reason: Int) {
runOnUiThread { onRemoteUserLeft() }
}
}
// Initialize the RtcEngine object.
private fun initializeAgoraEngine() {
try {
mRtcEngine = RtcEngine.create(baseContext,getString(R.string.agora_app_id),mRtcEventHandler)
} catch (e: Exception) {
Log.e(LOG_TAG,Log.getStackTraceString(e))
throw RuntimeException("NEED TO check rtc sdk init fatal error\n" + Log.getStackTraceString(e))
}
}
private fun setupLocalVideo() {
mRtcEngine!!.enableVideo()
val container = binding.localVideoViewContainer
val surfaceView = RtcEngine.CreateRendererView(baseContext)
surfaceView.setZOrderMediaOverlay(true)
container.addView(surfaceView)
mRtcEngine!!.setupLocalVideo(VideoCanvas(surfaceView,VideoCanvas.RENDER_MODE_FIT,0))
}
private fun joinChannel() {
Log.i("testen","joinChannel called")
mRtcEngine!!.joinChannel(
"<credential>","SeriChannel","Extra Optional Data",0) // if you do not specify the uid,we will generate the uid for you
}
private fun setupRemoteVideo(uid: Int) {
val container = binding.remoteVideoViewContainer
if (container.childCount >= 1) {
return
}
val surfaceView = RtcEngine.CreateRendererView(baseContext)
container.addView(surfaceView)
mRtcEngine!!.setupRemoteVideo(VideoCanvas(surfaceView,uid))
surfaceView.tag = uid // for mark purpose
val tipMsg = binding.uidText
tipMsg.visibility = View.GONE
}
private fun onRemoteUserLeft() {
val container = binding.remoteVideoViewContainer
container.removeAllViews()
val tipMsg = binding.uidText
tipMsg.visibility = View.VISIBLE
}
private fun onRemoteUserVideoMuted(uid: Int,muted: Boolean) {
val container = binding.remoteVideoViewContainer
val surfaceView = container.getChildAt(0) as SurfaceView
val tag = surfaceView.tag
if (tag != null && tag as Int == uid) {
surfaceView.visibility = if (muted) View.GONE else View.VISIBLE
}
}
override fun onDestroy() {
super.onDestroy()
leaveChannel()
RtcEngine.destroy()
mRtcEngine = null
}
// Button ClickListeners in .xml
private fun leaveChannel() {
mRtcEngine!!.leaveChannel()
}
fun onEncCallClicked(view: View) {
finish()
}
fun onSwitchCameraClicked(view: View) {
mRtcEngine!!.switchCamera()
}
fun onLocalAudioMuteClicked(view: View) {
val iv = view as ImageView
if (iv.isSelected) {
iv.isSelected = false
iv.clearColorFilter()
} else {
iv.isSelected = true
iv.setColorFilter(resources.getColor(R.color.black),PorterDuff.Mode.MULTIPLY)
}
mRtcEngine!!.muteLocalAudioStream(iv.isSelected)
}
fun onLocalVideoMuteClicked(view: View) {
val iv = view as ImageView
if (iv.isSelected) {
iv.isSelected = false
iv.clearColorFilter()
} else {
iv.isSelected = true
iv.setColorFilter(resources.getColor(R.color.black),PorterDuff.Mode.MULTIPLY)
}
mRtcEngine!!.muteLocalVideoStream(iv.isSelected)
val container = binding.localVideoViewContainer
val surfaceView = container.getChildAt(0) as SurfaceView
surfaceView.setZOrderMediaOverlay(!iv.isSelected)
surfaceView.visibility = if (iv.isSelected) View.GONE else View.VISIBLE
}
}
这是相应的(不是很漂亮)布局 XML 文件:
<?xml version="1.0" encoding="UTF-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/activity_video_chat_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="@+id/remote_video_view_container"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginTop="8dp"
android:layout_width="400dp"
android:layout_height="400dp"
android:background="@color/remoteBackground">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@id/icon_padding">
<ImageView
android:layout_width="@dimen/remote_back_icon_size"
android:layout_height="@dimen/remote_back_icon_size"
android:layout_centerInParent="true"
android:src="@drawable/icon_agora_largest" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/icon_padding"
android:layout_width="match_parent"
android:layout_height="@dimen/remote_back_icon_margin_bottom"
android:layout_alignParentBottom="true" />
</FrameLayout>
<TextView
android:id="@+id/uidText"
android:layout_width="180dp"
android:layout_height="30dp"
android:layout_marginBottom="32dp"
app:layout_constraintBottom_toTopOf="@+id/control_panel"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.483"
app:layout_constraintStart_toEndOf="@+id/local_video_view_container" />
<FrameLayout
android:id="@+id/local_video_view_container"
android:layout_marginBottom="24dp"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:background="@color/localBackground"
android:onClick="onLocalContainerClick"
app:layout_constraintBottom_toTopOf="@+id/control_panel"
app:layout_constraintStart_toStartOf="parent">
<ImageView
android:layout_width="@dimen/local_back_icon_size"
android:layout_height="@dimen/local_back_icon_size"
android:layout_gravity="center"
android:scaleType="centerCrop"
android:src="@drawable/icon_agora_large" />
</FrameLayout>
<RelativeLayout
android:id="@+id/control_panel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginBottom="16dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent">
<ImageView
android:id="@+id/btn_call"
android:layout_width="@dimen/call_button_size"
android:layout_height="@dimen/call_button_size"
android:layout_centerInParent="true"
android:onClick="onEncCallClicked"
android:scaleType="centerCrop"
android:src="@drawable/btn_end_call" />
<ImageView
android:id="@+id/btn_switch_camera"
android:layout_width="@dimen/other_button_size"
android:layout_height="@dimen/other_button_size"
android:layout_centerVertical="true"
android:layout_marginLeft="@dimen/control_bottom_horizontal_margin"
android:layout_toEndOf="@id/btn_call"
android:layout_toRightOf="@id/btn_call"
android:onClick="onSwitchCameraClicked"
android:scaleType="centerCrop"
android:src="@drawable/btn_switch_camera" />
<ImageView
android:id="@+id/btn_mute"
android:layout_width="@dimen/other_button_size"
android:layout_height="@dimen/other_button_size"
android:layout_centerVertical="true"
android:layout_marginRight="@dimen/control_bottom_horizontal_margin"
android:layout_toStartOf="@id/btn_call"
android:layout_toLeftOf="@id/btn_call"
android:onClick="onLocalAudioMuteClicked"
android:scaleType="centerCrop"
android:src="@drawable/btn_unmute_normal" />
<ImageView
android:id="@+id/btn_video_mute"
android:layout_width="@dimen/other_button_size"
android:layout_height="@dimen/other_button_size"
android:layout_toStartOf="@id/btn_mute"
android:layout_marginEnd="8dp"
android:layout_weight="20"
android:onClick="onLocalVideoMuteClicked"
android:scaleType="centerInside"
android:src="@drawable/btn_voice" />
</RelativeLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
它启动了,我可以连接而没有任何错误消息; 该活动的日志向我显示了这一点:
2021-01-12 02:21:30.175 516-516/? I/SurfaceFlinger: Display 0 HWC layers:
type | handle | flag | format | source crop (l,t,r,b) | frame | name
------------+--------------+------+-----------+----------------------------+---------------------+------
DEVICE | 0x75196ad080 | 0002 | RGB_565 | 0.0 0.0 600.0 600.0 | 0 1176 600 1776 | SurfaceView - com.example.dnaire/com[...]ra.VideoChatViewActivity@10775c1@0#0
DEVICE | 0x74fbd49880 | 0000 | RGBA_8888 | 0.0 0.0 1080.0 2220.0 | 0 0 1080 2220 | com.example.dnaire/com.example.dnaire.camera.VideoChatViewActivity$_24379#0
DEVICE | 0x75196abf00 | 0000 | RGBA_8888 | 0.0 0.0 1080.0 72.0 | 0 0 1080 72 | StatusBar$_8073#0
DEVICE | 0x75196ad940 | 0000 | RGBA_8888 | 0.0 0.0 67.0 408.0 | 1013 328 1080 736 | com.samsung.android.app.cocktailbars[...]rservice.CocktailBarService$_13359#0
DEVICE | 0x75196ac680 | 0000 | RGBA_8888 | 0.0 0.0 1080.0 144.0 | 0 2076 1080 2220 | NavigationBar0$_8073#0
但我不知道那值多少钱。
我添加了一张照片,展示了它的实际效果。它在两种设备上完全相同。 是的,我在“项目”>“编辑”>“生成临时令牌”下生成了一个令牌,并启用了主证书和二级证书。
解决方法
请务必检查以下内容:
-
您正在使用资源 R.string.agora_app_id 作为您的应用 ID。确保您在 xml 文件中添加了正确的 App ID。
-
在您的 joinChannel 方法中,应该提供的第一个参数是您的令牌,它应该与您的 App ID 不同。出于开发目的,您可以对 generate a temporary token 执行以下操作。将您的应用程序投入生产时,请确保setup a token server
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。