我正在使用webrtc构建视频聊天应用程序。当我开始视频通话时,出现了一些错误。如何解决这个问题。
E/RoomRTCClient:Room连接错误:HTTP发送到https://appr.tc/join/E52U8KA错误:不可接受的证书:CN=COMODO RSA证书颁发机构,O=COMODO CA Limited,L=Salford,ST=Greater Manchester,C=GB。
E/WSRTCClient: HTTP POST到https://appr.tc/join/E52U8KA错误:不可接受的证书: CN=COMODO RSA认证机构, O=COMODO CA Limited, L=Salford, ST=大曼彻斯特, C=GB
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageButton;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.UiThread;
import com.skillatwill.skillatwill.R;
import org.appspot.apprtc.AppRTCClient;
import org.appspot.apprtc.PeerConnectionClient;
import org.appspot.apprtc.WebSocketRTCClient;
import org.webrtc.Camera2Enumerator;
import org.webrtc.CameraEnumerator;
import org.webrtc.IceCandidate;
import org.webrtc.Logging;
import org.webrtc.RendererCommon.ScalingType;
import org.webrtc.SessionDescription;
import org.webrtc.StatsReport;
import org.webrtc.SurfaceViewRenderer;
import org.webrtc.VideoCapturer;
import org.webrtc.VideoFrame;
import org.webrtc.VideoRenderer;
import org.webrtc.VideoSink;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.List;
/**
* Activity for peer connection call setup, call waiting
* and call view.
*/
public class CallActivity extends Activity implements AppRTCClient.SignalingEvents,
PeerConnectionClient.PeerConnectionEvents {
private static final String TAG = "CallActivity";
private static final String APPRTC_URL = "https://appr.tc";
private static final String UPPER_ALPHA_DIGITS = "ACEFGHJKLMNPQRUVWXY123456789";
// Peer connection statistics callback period in ms.
private static final int STAT_CALLBACK_PERIOD = 1000;
private final ProxyRenderer remoteProxyRenderer = new ProxyRenderer();
private final ProxyVideoSink localProxyVideoSink = new ProxyVideoSink();
private final List<VideoRenderer.Callbacks> remoteRenderers = new ArrayList<>();
private PeerConnectionClient peerConnectionClient = null;
private AppRTCClient appRtcClient;
private AppRTCClient.SignalingParameters signalingParameters;
private SurfaceViewRenderer pipRenderer;
private SurfaceViewRenderer fullscreenRenderer;
private Toast logToast;
private boolean activityRunning;
private AppRTCClient.RoomConnectionParameters roomConnectionParameters;
private PeerConnectionClient.PeerConnectionParameters peerConnectionParameters;
private boolean iceConnected;
private boolean isError;
private long callStartedTimeMs = 0;
private boolean micEnabled = true;
private boolean isSwappedFeeds;
// Control buttons for limited UI
private ImageButton disconnectButton;
private ImageButton cameraSwitchButton;
private ImageButton toggleMuteButton;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_call);
iceConnected = false;
signalingParameters = null;
// Create UI controls.
pipRenderer = findViewById(R.id.pip_video_view);
fullscreenRenderer = findViewById(R.id.fullscreen_video_view);
disconnectButton = findViewById(R.id.button_call_disconnect);
cameraSwitchButton = findViewById(R.id.button_call_switch_camera);
toggleMuteButton = findViewById(R.id.button_call_toggle_mic);
// Add buttons click events.
disconnectButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
onCallHangUp();
}
});
cameraSwitchButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
onCameraSwitch();
}
});
toggleMuteButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
boolean enabled = onToggleMic();
toggleMuteButton.setAlpha(enabled ? 1.0f : 0.3f);
}
});
// Swap feeds on pip view click.
pipRenderer.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
setSwappedFeeds(!isSwappedFeeds);
}
});
remoteRenderers.add(remoteProxyRenderer);
// Create peer connection client.
peerConnectionClient = new PeerConnectionClient();
// Create video renderers.
pipRenderer.init(peerConnectionClient.getRenderContext(), null);
pipRenderer.setScalingType(ScalingType.SCALE_ASPECT_FIT);
fullscreenRenderer.init(peerConnectionClient.getRenderContext(), null);
fullscreenRenderer.setScalingType(ScalingType.SCALE_ASPECT_FILL);
pipRenderer.setZOrderMediaOverlay(true);
pipRenderer.setEnableHardwareScaler(true /* enabled */);
fullscreenRenderer.setEnableHardwareScaler(true /* enabled */);
// Start with local feed in fullscreen and swap it to the pip when the call is connected.
setSwappedFeeds(true /* isSwappedFeeds */);
// Generate a random room ID with 7 uppercase letters and digits
String randomRoomID = randomString(7, UPPER_ALPHA_DIGITS);
// Show the random room ID so that another client can html" target="_blank">join from https://appr.tc
TextView roomIdTextView = findViewById(R.id.roomID);
roomIdTextView.setText(getString(R.string.room_id_caption) + randomRoomID);
Log.d(TAG, getString(R.string.room_id_caption) + randomRoomID);
// Connect video call to the random room
connectVideoCall(randomRoomID);
}
// Create a random string
private String randomString(int length, String characterSet) {
StringBuilder sb = new StringBuilder(); //consider using StringBuffer if needed
for (int i = 0; i < length; i++) {
int randomInt = new SecureRandom().nextInt(characterSet.length());
sb.append(characterSet.substring(randomInt, randomInt + 1));
}
return sb.toString();
}
// Join video call with randomly generated roomId
private void connectVideoCall(String roomId) {
Uri roomUri = Uri.parse(APPRTC_URL);
int videoWidth = 0;
int videoHeight = 0;
peerConnectionParameters =
new PeerConnectionClient.PeerConnectionParameters(true,
false,
false,
videoWidth,
videoHeight,
0,
Integer.parseInt(getString(R.string.pref_maxvideobitratevalue_default)),
getString(R.string.pref_videocodec_default),
true,
false,
Integer.parseInt(getString(R.string.pref_startaudiobitratevalue_default)),
getString(R.string.pref_audiocodec_default),
false,
false,
false,
false,
false,
false,
false,
false,
null);
// Create connection client. Use the standard WebSocketRTCClient.
// DirectRTCClient could be used for point-to-point connection
appRtcClient = new WebSocketRTCClient(this);
// Create connection parameters.
roomConnectionParameters =
new AppRTCClient.RoomConnectionParameters(
roomUri.toString(),
roomId,
false,
null);
peerConnectionClient.createPeerConnectionFactory(
getApplicationContext(), peerConnectionParameters, CallActivity.this);
startCall();
}
public void onCallHangUp() {
disconnect();
}
public void onCameraSwitch() {
if (peerConnectionClient != null) {
peerConnectionClient.switchCamera();
}
}
public boolean onToggleMic() {
if (peerConnectionClient != null) {
micEnabled = !micEnabled;
peerConnectionClient.setAudioEnabled(micEnabled);
}
return micEnabled;
}
private void startCall() {
if (appRtcClient == null) {
Log.e(TAG, "AppRTC client is not allocated for a call.");
return;
}
callStartedTimeMs = System.currentTimeMillis();
// Start room connection.
logAndToast(getString(R.string.connecting_to, roomConnectionParameters.roomUrl));
appRtcClient.connectToRoom(roomConnectionParameters);
}
@UiThread
private void callConnected() {
final long delta = System.currentTimeMillis() - callStartedTimeMs;
Log.i(TAG, "Call connected: delay=" + delta + "ms");
if (peerConnectionClient == null || isError) {
Log.w(TAG, "Call is connected in closed or error state");
return;
}
// Enable statistics callback.
peerConnectionClient.enableStatsEvents(true, STAT_CALLBACK_PERIOD);
setSwappedFeeds(false /* isSwappedFeeds */);
}
// Disconnect from remote resources, dispose of local resources, and exit.
private void disconnect() {
activityRunning = false;
remoteProxyRenderer.setTarget(null);
localProxyVideoSink.setTarget(null);
if (appRtcClient != null) {
appRtcClient.disconnectFromRoom();
appRtcClient = null;
}
if (pipRenderer != null) {
pipRenderer.release();
pipRenderer = null;
}
if (fullscreenRenderer != null) {
fullscreenRenderer.release();
fullscreenRenderer = null;
}
if (peerConnectionClient != null) {
peerConnectionClient.close();
peerConnectionClient = null;
}
if (iceConnected && !isError) {
setResult(RESULT_OK);
} else {
setResult(RESULT_CANCELED);
}
finish();
}
private void disconnectWithErrorMessage(final String errorMessage) {
if (!activityRunning) {
Log.e(TAG, "Critical error: " + errorMessage);
disconnect();
} else {
new AlertDialog.Builder(this)
.setTitle(getText(R.string.channel_error_title))
.setMessage(errorMessage)
.setCancelable(false)
.setNeutralButton(R.string.ok,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
disconnect();
}
})
.create()
.show();
}
}
// Log |msg| and Toast about it.
private void logAndToast(String msg) {
Log.d(TAG, msg);
if (logToast != null) {
logToast.cancel();
}
logToast = Toast.makeText(this, msg, Toast.LENGTH_SHORT);
logToast.show();
}
private void reportError(final String description) {
runOnUiThread(new Runnable() {
@Override
public void run() {
if (!isError) {
isError = true;
disconnectWithErrorMessage(description);
}
}
});
}
// Create VideoCapturer
private VideoCapturer createVideoCapturer() {
final VideoCapturer videoCapturer;
Logging.d(TAG, "Creating capturer using camera2 API.");
videoCapturer = createCameraCapturer(new Camera2Enumerator(this));
if (videoCapturer == null) {
reportError("Failed to open camera");
return null;
}
return videoCapturer;
}
// Create VideoCapturer from camera
private VideoCapturer createCameraCapturer(CameraEnumerator enumerator) {
final String[] deviceNames = enumerator.getDeviceNames();
// First, try to find front facing camera
Logging.d(TAG, "Looking for front facing cameras.");
for (String deviceName : deviceNames) {
if (enumerator.isFrontFacing(deviceName)) {
Logging.d(TAG, "Creating front facing camera capturer.");
VideoCapturer videoCapturer = enumerator.createCapturer(deviceName, null);
if (videoCapturer != null) {
return videoCapturer;
}
}
}
// Front facing camera not found, try something else
Logging.d(TAG, "Looking for other cameras.");
for (String deviceName : deviceNames) {
if (!enumerator.isFrontFacing(deviceName)) {
Logging.d(TAG, "Creating other camera capturer.");
VideoCapturer videoCapturer = enumerator.createCapturer(deviceName, null);
if (videoCapturer != null) {
return videoCapturer;
}
}
}
return null;
}
private void setSwappedFeeds(boolean isSwappedFeeds) {
Logging.d(TAG, "setSwappedFeeds: " + isSwappedFeeds);
this.isSwappedFeeds = isSwappedFeeds;
localProxyVideoSink.setTarget(isSwappedFeeds ? fullscreenRenderer : pipRenderer);
remoteProxyRenderer.setTarget(isSwappedFeeds ? pipRenderer : fullscreenRenderer);
fullscreenRenderer.setMirror(isSwappedFeeds);
pipRenderer.setMirror(!isSwappedFeeds);
}
// -----Implementation of AppRTCClient.AppRTCSignalingEvents ---------------
// All callbacks are invoked from websocket signaling looper thread and
// are routed to UI thread.
private void onConnectedToRoomInternal(final AppRTCClient.SignalingParameters params) {
final long delta = System.currentTimeMillis() - callStartedTimeMs;
signalingParameters = params;
logAndToast("Creating peer connection, delay=" + delta + "ms");
VideoCapturer videoCapturer = null;
if (peerConnectionParameters.videoCallEnabled) {
videoCapturer = createVideoCapturer();
}
peerConnectionClient.createPeerConnection(
localProxyVideoSink, remoteRenderers, videoCapturer, signalingParameters);
if (signalingParameters.initiator) {
logAndToast("Creating OFFER...");
// Create offer. Offer SDP will be sent to answering client in
// PeerConnectionEvents.onLocalDescription event.
peerConnectionClient.createOffer();
} else {
if (params.offerSdp != null) {
peerConnectionClient.setRemoteDescription(params.offerSdp);
logAndToast("Creating ANSWER...");
// Create answer. Answer SDP will be sent to offering client in
// PeerConnectionEvents.onLocalDescription event.
peerConnectionClient.createAnswer();
}
if (params.iceCandidates != null) {
// Add remote ICE candidates from room.
for (IceCandidate iceCandidate : params.iceCandidates) {
peerConnectionClient.addRemoteIceCandidate(iceCandidate);
}
}
}
}
@Override
public void onConnectedToRoom(final AppRTCClient.SignalingParameters params) {
runOnUiThread(new Runnable() {
@Override
public void run() {
onConnectedToRoomInternal(params);
}
});
}
@Override
public void onRemoteDescription(final SessionDescription sdp) {
final long delta = System.currentTimeMillis() - callStartedTimeMs;
runOnUiThread(new Runnable() {
@Override
public void run() {
if (peerConnectionClient == null) {
Log.e(TAG, "Received remote SDP for non-initilized peer connection.");
return;
}
logAndToast("Received remote " + sdp.type + ", delay=" + delta + "ms");
peerConnectionClient.setRemoteDescription(sdp);
if (!signalingParameters.initiator) {
logAndToast("Creating ANSWER...");
// Create answer. Answer SDP will be sent to offering client in
// PeerConnectionEvents.onLocalDescription event.
peerConnectionClient.createAnswer();
}
}
});
}
@Override
public void onRemoteIceCandidate(final IceCandidate candidate) {
runOnUiThread(new Runnable() {
@Override
public void run() {
if (peerConnectionClient == null) {
Log.e(TAG, "Received ICE candidate for a non-initialized peer connection.");
return;
}
peerConnectionClient.addRemoteIceCandidate(candidate);
}
});
}
@Override
public void onRemoteIceCandidatesRemoved(final IceCandidate[] candidates) {
runOnUiThread(new Runnable() {
@Override
public void run() {
if (peerConnectionClient == null) {
Log.e(TAG, "Received ICE candidate removals for a non-initialized peer connection.");
return;
}
peerConnectionClient.removeRemoteIceCandidates(candidates);
}
});
}
@Override
public void onChannelClose() {
runOnUiThread(new Runnable() {
@Override
public void run() {
logAndToast("Remote end hung up; dropping PeerConnection");
disconnect();
}
});
}
@Override
public void onChannelError(final String description) {
reportError(description);
}
// -----Implementation of PeerConnectionClient.PeerConnectionEvents.---------
// Send local peer connection SDP and ICE candidates to remote party.
// All callbacks are invoked from peer connection client looper thread and
// are routed to UI thread.
@Override
public void onLocalDescription(final SessionDescription sdp) {
final long delta = System.currentTimeMillis() - callStartedTimeMs;
runOnUiThread(new Runnable() {
@Override
public void run() {
if (appRtcClient != null) {
logAndToast("Sending " + sdp.type + ", delay=" + delta + "ms");
if (signalingParameters.initiator) {
appRtcClient.sendOfferSdp(sdp);
} else {
appRtcClient.sendAnswerSdp(sdp);
}
}
if (peerConnectionParameters.videoMaxBitrate > 0) {
Log.d(TAG, "Set video maximum bitrate: " + peerConnectionParameters.videoMaxBitrate);
peerConnectionClient.setVideoMaxBitrate(peerConnectionParameters.videoMaxBitrate);
}
}
});
}
@Override
public void onIceCandidate(final IceCandidate candidate) {
runOnUiThread(new Runnable() {
@Override
public void run() {
if (appRtcClient != null) {
appRtcClient.sendLocalIceCandidate(candidate);
}
}
});
}
@Override
public void onIceCandidatesRemoved(final IceCandidate[] candidates) {
runOnUiThread(new Runnable() {
@Override
public void run() {
if (appRtcClient != null) {
appRtcClient.sendLocalIceCandidateRemovals(candidates);
}
}
});
}
@Override
public void onIceConnected() {
final long delta = System.currentTimeMillis() - callStartedTimeMs;
runOnUiThread(new Runnable() {
@Override
public void run() {
logAndToast("ICE connected, delay=" + delta + "ms");
iceConnected = true;
callConnected();
}
});
}
@Override
public void onIceDisconnected() {
runOnUiThread(new Runnable() {
@Override
public void run() {
logAndToast("ICE disconnected");
iceConnected = false;
disconnect();
}
});
}
@Override
public void onPeerConnectionClosed() {
}
@Override
public void onPeerConnectionStatsReady(final StatsReport[] reports) {
}
@Override
public void onPeerConnectionError(final String description) {
reportError(description);
}
// Activity interfaces
@Override
public void onStop() {
super.onStop();
activityRunning = false;
if (peerConnectionClient != null) {
peerConnectionClient.stopVideoSource();
}
}
@Override
public void onStart() {
super.onStart();
activityRunning = true;
// Video is not paused for screencapture. See onPause.
if (peerConnectionClient != null) {
peerConnectionClient.startVideoSource();
}
}
@Override
protected void onDestroy() {
Thread.setDefaultUncaughtExceptionHandler(null);
disconnect();
if (logToast != null) {
logToast.cancel();
}
activityRunning = false;
super.onDestroy();
}
private static class ProxyRenderer implements VideoRenderer.Callbacks {
private VideoRenderer.Callbacks target;
@Override
synchronized public void renderFrame(VideoRenderer.I420Frame frame) {
if (target == null) {
Logging.d(TAG, "Dropping frame in proxy because target is null.");
VideoRenderer.renderFrameDone(frame);
return;
}
target.renderFrame(frame);
}
synchronized public void setTarget(VideoRenderer.Callbacks target) {
this.target = target;
}
}
private static class ProxyVideoSink implements VideoSink {
private VideoSink target;
@Override
synchronized public void onFrame(VideoFrame frame) {
if (target == null) {
Logging.d(TAG, "Dropping frame in proxy because target is null.");
return;
}
target.onFrame(frame);
}
synchronized public void setTarget(VideoSink target) {
this.target = target;
}
}
}
添加信任管理器以允许您的HttpURLConnection或Http客户端或改造中的所有不安全连接
AsyncHttpURLConnection.java
// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
}
};
// Install the all-trusting trust manager
try {
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (Exception e) {
}
您使用的是由实体(谷歌)操作的演示信令服务器,该实体不考虑该演示信令服务器为生产系统。证书一周前过期了。
运行自己的服务器,说明可以在这里找到:https://github.com/webrtc/apprtc
问题内容: 大约六个月前,我能够用PHP成功编写自己的WebSocket服务器脚本。这样,我就可以在本地主机上设置WebRTC视频聊天服务。在意识到要进行部署之前,我很高兴,我需要一个可以访问套接字的Web服务器。 不幸的是,没有共享的Web托管允许套接字,并且所有提供套接字的Web服务器都很昂贵。虽然这不是一个大规模的有效解决方案,但是为了建立一个演示来展示给人们看,我想将信令方法从WebSoc
我正在开发Android聊天应用程序,一切都很顺利。我已经设法将用户添加到解析数据库中,并在friends片段上显示用户。 但后来辛奇来了。我按照他们网站上的指示将SDK添加到我的项目中,并添加了一个服务类,我已经在清单中声明了如下内容: 在应用程序标记的内部。 java.lang.UnsatisfiedLinkError:Dalvik.System.PathClassLoader[dexPath
问题内容: 我想知道为数千名用户编写聊天应用程序的正确方法是什么。 我只是感到困惑,我如何才能每秒使用AJAX或更少的方法来对服务器执行ping操作,并检查MySQL中是否有新记录等,并且服务器负载可以接受。 我目前正在考虑使用jQuery,PHP和MySQL进行编码。 请指教。您的帮助将不胜感激。 问题答案: 客户端 对于需要轮询服务器的任何程序,我建议使用WebSockets。 我写了一个非常
我正在使用XMPP在app引擎上编写一个聊天应用程序。我的想法是允许用户互相聊天。我可以将消息发送到google talk帐户,方法是将登录的用户删除地址的@gmail.com部分,并将其替换为@appid.appspotchat.com)。例如,如果登录的用户是bob@gmail.com,则用于发送的jid将是bob@appid.appspotchat.com)。然后,您可以将消息发送到goog
现在我们已经熟悉了Socket.IO,让我们编写一个聊天应用程序,我们可以用它在不同的聊天室聊天。 我们将允许用户选择用户名并允许他们使用它们进行聊天。 首先,让我们设置我们的HTML文件来请求用户名 - <!DOCTYPE html> <html> <head> <title>Hello world</title> </head> <script src = "/s
问题内容: 在我目前正在从事的项目中,我们需要开发一个Web聊天应用程序,而不是一个非常复杂的聊天,仅是一种将两个人联系起来谈论一个非常具体的话题的方式,我们不需要任何身份验证对于这两个用户之一,我们不必支持表情符号,头像或类似的东西。 一些项目成员建议我们可以通过BOSH使用XMPP,我说这就像试图用船网抓鱼,并提出了一种更简单的方法,例如简单的Ajax / MySQL网络聊天,但是我们担心性能