- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我第一次尝试制作视频通话应用。我在 android studio 中使用 Agora.io 进行视频通话。我面临的问题是我看不到我打电话的人的视频。我完美地从前置摄像头获得了我自己的。
我被这个问题困扰了好几天。
这里是 Dashboard.java 的代码。
public class Dashboard extends AppCompatActivity {
private static final String TAG = "1";
private static final int PERMISSION_REQ_ID = 22;
// Permission WRITE_EXTERNAL_STORAGE is not mandatory
// for Agora RTC SDK, just in case if you wanna save
// logs to external sdcard.
private static final String[] REQUESTED_PERMISSIONS = {
Manifest.permission.READ_PHONE_STATE,
Manifest.permission.RECORD_AUDIO,
Manifest.permission.CAMERA,
Manifest.permission.WRITE_EXTERNAL_STORAGE
};
private RtcEngine mRtcEngine;
private boolean mCallEnd;
private boolean mMuted;
private FrameLayout mLocalContainer;
private RelativeLayout mRemoteContainer;
private SurfaceView mLocalView;
private SurfaceView mRemoteView;
private ImageView mCallBtn;
private ImageView mMuteBtn;
private ImageView mSwitchCameraBtn;
/**
* Event handler registered into RTC engine for RTC callbacks.
* Note that UI operations needs to be in UI thread because RTC
* engine deals with the events in a separate thread.
*/
private final IRtcEngineEventHandler mRtcEventHandler = new IRtcEngineEventHandler() {
@Override
public void onJoinChannelSuccess(String channel, final int uid, int elapsed) {
runOnUiThread(new Runnable() {
@Override
public void run() {
}
});
}
@Override
public void onFirstRemoteVideoDecoded(final int uid, int width, int height, int elapsed) {
runOnUiThread(new Runnable() {
@Override
public void run() {
setupRemoteVideo(uid);
}
});
}
@Override
public void onUserOffline(final int uid, int reason) {
runOnUiThread(new Runnable() {
@Override
public void run() {
onRemoteUserLeft();
}
});
}
};
private void setupRemoteVideo(int uid) {
// Only one remote video view is available for this
// tutorial. Here we check if there exists a surface
// view tagged as this uid.
int count = mRemoteContainer.getChildCount();
View view = null;
for (int i = 0; i < count; i++) {
View v = mRemoteContainer.getChildAt(i);
if (v.getTag() instanceof Integer && ((int) v.getTag()) == uid) {
view = v;
}
}
if (view != null) {
return;
}
mRemoteView = RtcEngine.CreateRendererView(getBaseContext());
mRemoteContainer.addView(mRemoteView);
mRtcEngine.setupRemoteVideo(new VideoCanvas(mRemoteView, VideoCanvas.RENDER_MODE_HIDDEN, uid));
mRemoteView.setTag(uid);
}
private void onRemoteUserLeft() {
removeRemoteVideo();
}
private void removeRemoteVideo() {
if (mRemoteView != null) {
mRemoteContainer.removeView(mRemoteView);
}
mRemoteView = null;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dashboard);
initUI();
// Ask for permissions at runtime.
// This is just an example set of permissions. Other permissions
// may be needed, and please refer to our online documents.
if (checkSelfPermission(REQUESTED_PERMISSIONS[0], PERMISSION_REQ_ID) &&
checkSelfPermission(REQUESTED_PERMISSIONS[1], PERMISSION_REQ_ID) &&
checkSelfPermission(REQUESTED_PERMISSIONS[2], PERMISSION_REQ_ID) &&
checkSelfPermission(REQUESTED_PERMISSIONS[3], PERMISSION_REQ_ID)) {
initEngineAndJoinChannel();
}
}
private void initUI() {
mLocalContainer = findViewById(R.id.local_video_view_container);
mRemoteContainer = findViewById(R.id.remote_video_view_container);
mCallBtn = findViewById(R.id.btn_call);
mMuteBtn = findViewById(R.id.btn_mute);
mSwitchCameraBtn = findViewById(R.id.btn_switch_camera);
}
private boolean checkSelfPermission(String permission, int requestCode) {
if (ContextCompat.checkSelfPermission(this, permission) !=
PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, REQUESTED_PERMISSIONS, requestCode);
return false;
}
return true;
}
@Override
public void onRequestPermissionsResult(int requestCode,
@NonNull String[] permissions, @NonNull int[] grantResults) {
if (requestCode == PERMISSION_REQ_ID) {
if (grantResults[0] != PackageManager.PERMISSION_GRANTED ||
grantResults[1] != PackageManager.PERMISSION_GRANTED ||
grantResults[2] != PackageManager.PERMISSION_GRANTED ||
grantResults[3] != PackageManager.PERMISSION_GRANTED) {
showLongToast("Need permissions " + Manifest.permission.RECORD_AUDIO +
"/" + Manifest.permission.CAMERA + "/" + Manifest.permission.WRITE_EXTERNAL_STORAGE
+ "/" + Manifest.permission.READ_PHONE_STATE);
finish();
return;
}
// Here we continue only if all permissions are granted.
// The permissions can also be granted in the system settings manually.
initEngineAndJoinChannel();
}
}
private void showLongToast(final String msg) {
this.runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_LONG).show();
}
});
}
private void initEngineAndJoinChannel() {
// This is our usual steps for joining
// a channel and starting a call.
initializeEngine();
setupVideoConfig();
setupLocalVideo();
joinChannel();
}
private void initializeEngine() {
try {
mRtcEngine = RtcEngine.create(getBaseContext(), getString(R.string.app_id_agora), mRtcEventHandler);
} catch (Exception e) {
Log.e(TAG, Log.getStackTraceString(e));
throw new RuntimeException("NEED TO check rtc sdk init fatal error\n" + Log.getStackTraceString(e));
}
}
private void setupVideoConfig() {
// In simple use cases, we only need to enable video capturing
// and rendering once at the initialization step.
// Note: audio recording and playing is enabled by default.
mRtcEngine.enableVideo();
// Please go to this page for detailed explanation
// https://docs.agora.io/en/Video/API%20Reference/java/classio_1_1agora_1_1rtc_1_1_rtc_engine.html#af5f4de754e2c1f493096641c5c5c1d8f
mRtcEngine.setVideoEncoderConfiguration(new VideoEncoderConfiguration(
VideoEncoderConfiguration.VD_640x360,
VideoEncoderConfiguration.FRAME_RATE.FRAME_RATE_FPS_15,
VideoEncoderConfiguration.STANDARD_BITRATE,
VideoEncoderConfiguration.ORIENTATION_MODE.ORIENTATION_MODE_FIXED_PORTRAIT));
}
private void setupLocalVideo() {
// This is used to set a local preview.
// The steps setting local and remote view are very similar.
// But note that if the local user do not have a uid or do
// not care what the uid is, he can set his uid as ZERO.
// Our server will assign one and return the uid via the event
// handler callback function (onJoinChannelSuccess) after
// joining the channel successfully.
mLocalView = RtcEngine.CreateRendererView(getBaseContext());
mLocalView.setZOrderMediaOverlay(true);
mLocalContainer.addView(mLocalView);
mRtcEngine.setupLocalVideo(new VideoCanvas(mLocalView, VideoCanvas.RENDER_MODE_HIDDEN, 0));
}
private void joinChannel() {
// 1. Users can only see each other after they join the
// same channel successfully using the same app id.
// 2. One token is only valid for the channel name that
// you use to generate this token.
String token = "12312323123123wedsa";
mRtcEngine.joinChannel(token, "brolChannelbrobro", "Extra Optional Data", 0);
}
@Override
protected void onDestroy() {
super.onDestroy();
if (!mCallEnd) {
leaveChannel();
}
RtcEngine.destroy();
}
private void leaveChannel() {
mRtcEngine.leaveChannel();
}
public void onLocalAudioMuteClicked(View view) {
mMuted = !mMuted;
mRtcEngine.muteLocalAudioStream(mMuted);
int res = mMuted ? R.drawable.btn_mute : R.drawable.btn_unmute;
mMuteBtn.setImageResource(res);
}
public void onSwitchCameraClicked(View view) {
mRtcEngine.switchCamera();
}
public void onCallClicked(View view) {
if (mCallEnd) {
startCall();
mCallEnd = false;
mCallBtn.setImageResource(R.drawable.btn_endcall);
} else {
endCall();
mCallEnd = true;
mCallBtn.setImageResource(R.drawable.btn_startcall);
}
showButtons(!mCallEnd);
}
private void startCall() {
setupLocalVideo();
joinChannel();
}
private void endCall() {
removeLocalVideo();
removeRemoteVideo();
leaveChannel();
}
private void removeLocalVideo() {
if (mLocalView != null) {
mLocalContainer.removeView(mLocalView);
}
mLocalView = null;
}
private void showButtons(boolean show) {
int visibility = show ? View.VISIBLE : View.GONE;
mMuteBtn.setVisibility(visibility);
mSwitchCameraBtn.setVisibility(visibility);
}
最佳答案
我遇到了同样的问题。在我的例子中,这是一个布局问题,因为我没有让本地视频 View 消失而远程视频 View 可见。我不知道这些年后它是否仍然有帮助。
关于android-studio - 视频通话无法接通 - Agora.io,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57864966/
这与 What is call/cc? 有关,但我不想为了自己的目的劫持这个问题,并且它的一些论点(例如与 setjmp/longjmp 的类比)回避了我。 我想我对什么是延续有足够的了解,我认为它是
我一直在浏览 Skype 开发 API,并想知道是否有一种方法可以让我知道 Skype 是否正在通过某些 API 运行事件调用。 Skype.Client.IsRunning 告诉 Skype 应用程
这个问题的两个小部分希望能为我消除一些歧义。 首先,调用WCF服务哪个更好? using (var myService = new ServiceClient("httpBinding")){
我在我的 Objective-C 应用程序中使用 CallKit。 我可以使用 CallKit 调用电话。如果有第二个电话打进来,我成功地将其设置为保持状态。当我结束第二个电话时, - (void)p
是否可以使用 java(JME 或 Android)捕获语音音频流,对其进行自定义加密,然后通过常规 GSM 调用将其作为常规流发送?当然,在其他手机上解密密码。是否允许应用程序级别的 java 拦截
我正在为 iOS 进行个人调整。我想在电话显示任何内容之前断开/连接电话。我连接到类 SBUIFullscreenAlertAdapter 的 initWithAlertController: 方法。
我对 callkit 有疑问(但不是真的)。 我在我的应用程序中实现了 callkit,它运行良好。我可以接到我的应用程序的第二个电话,callkit 为我提供了结束并接受、拒绝或保留并接受的选项。如
我一直在寻找在两个同伴之间进行实时语音(通话)的方法,但只找到了如何录制语音并发送它们或发送照片和文本。但我想要的是两个同伴能够互相打电话。那么,在 Android 上使用 WiFi P2P 管理器是
怎么了伙计们!好久没问过关于SO的问题了,感觉有点脱节,哈哈。无论如何,我最近使用 VOIP 发现了美妙的网络语音通话世界。和 WebRTC 我正在为我的一个想法进行一些研发,并且我基本上会喜欢以下问
我正在制作一个可以调用电话的应用程序,但我需要帮助才能在不显示拨号界面的情况下调用电话,例如,如果我按下按钮调用,它会调用电话但会停留在同一位置: 这是我的应用程序界面: 我不需要这个拨号界面,当按下
我是 Android 开发的新手(例如,我知道在 iOS 中这是不可能的)。 我知道,我需要打电话: Intent intent = new Intent(Intent.ACTION_CALL); i
注意:事实证明,原始问题的假设是不正确的。在底部查看有关其编辑的更多详细信息。 现在是关于节电模式,而不是节电模式和打盹模式。它也不是关于 Service&BroadcastReceiver,而只是
我正在开发一个机器人,您可以通过 Skype 向其发送消息和调用。该机器人在 Azure 函数中运行。我的消息部分正在工作。我已在 Azure 中将机器人配置为具有调用功能,并且我可以调用该机器人,但
在我的应用中,用户可以选择 call 联系人簿中的其他人。启动 call 应用程序很容易,但是我想知道的是,在 call 发生时我们是否可以播放简短的音乐文件,因此用户可以通过直接 call 他们的
我正在开发一个机器人,您可以通过 Skype 向其发送消息和调用。该机器人在 Azure 函数中运行。我的消息部分正在工作。我已在 Azure 中将机器人配置为具有调用功能,并且我可以调用该机器人,但
在这个问题的某些版本中,OP 会说“我如何在下午 5 点在我的应用程序中触发方法调用?” 然后人们会回答“你怎么知道你的应用会在下午 5 点打开”?这变成了另一个问题,原来的问题消失了。 所以让我们避
我想在单击按钮时发起 Skype 通话。我查找了几种可用的解决方案,但我猜大多数都已经过时并且无法正常工作。有人可以帮我解决这个问题吗?我是 Android 编程的新手。我已经包含在下面的代码中。任何
在 iOS 上,是否可以通过 URI 启动 Skype 语音通话,同时将我的应用程序保持在前台? 如果是这样,是否也可以通过启用扬声器的 URI 启动 Skype? (为什么?我正在尝试支持语音通信,
我在 Play 商店中有十几个应用程序,它们都是相同的,但针对不同的客户端进行了 UI 调整。我最近收到一封来自 Google Play 的自动电子邮件,内容涉及我的 2 个应用程序(但不是其他应用程
我想在 android 中进行 SIP 点对点 VoIP 调用。此调用应在本地网络中进行,无需访问互联网。事实上,我不想使用任何外部服务器来注册配置文件。但是我不知道在配置文件生成器的 serverD
我是一名优秀的程序员,十分优秀!