- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
所以我试图通过 webRTC 通过 socket.io 和 libjingle 将 Android 连接到浏览器,并且服务器在 Node.js 上运行。我面临的问题很奇怪。当 1 个客户端使用 Android( native 应用程序)而其他客户端使用 Ipad( native 应用程序)时,一切正常。当 1 个客户端使用 iPad( native 应用程序)而其他客户端使用 Web 应用程序时,Everyting 工作正常。但是,当 1 个客户端位于 Android( native 应用程序)而其他客户端位于网页时,除了音频和视频未流向该端外,一切正常。
以下是我为此目的使用的两个主要类:
PS。按钮调用的方法makeOffer(View v)
。
MainActivity.java
public List<PeerConnection.IceServer> iceServers;
private GLSurfaceView videoView;
public static SocketIO socket;
ArrayList<String> userIDs = new ArrayList<>();
private static final String FIELD_TRIAL_VP9 = "WebRTC-SupportVP9/Enabled/";
String RoomId = "";
String sreverURL = "http://xx.xx.xx.xx:xxxx/";
private EditText roomid;
private VideoRenderer.Callbacks localRender;
private VideoRenderer.Callbacks remoteRender;
protected PeerConnectionFactory factory;
PeerConnectionFactory.Options options = null;
Events pc_events;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
videoView = (GLSurfaceView) findViewById(R.id.glview_call);
VideoRendererGui.setView(videoView, new Runnable() {
@Override
public void run() {
createPeerConnectionFactory();
}
});
remoteRender = VideoRendererGui.create(0, 0, 100, 100, ScalingType.SCALE_ASPECT_FILL, false);
localRender = VideoRendererGui.create(0, 0, 100, 100, ScalingType.SCALE_ASPECT_FILL, true);
iceServers = new ArrayList<>();
IceServer icc = new IceServer("stun:stun.l.google.com:19302", "", "");
iceServers.add(icc);
roomid = (EditText) findViewById(R.id.roomId);
Random rand = new Random();
roomid.setText("" + rand.nextInt(9999));
pc_events = new peerEventHandler();
}
private void createPeerConnectionFactory() {
runOnUiThread(new Runnable() {
@Override
public void run() {
PeerConnectionFactory.initializeFieldTrials(FIELD_TRIAL_VP9);
PeerConnectionFactory.initializeAndroidGlobals(Home.this, true, true, true, VideoRendererGui.getEGLContext());
try {
factory = new PeerConnectionFactory();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public void ondail(View view) {
try {
try {
SocketIO.setDefaultSSLSocketFactory(SSLContext.getDefault());
} catch (NoSuchAlgorithmException e1) {
e1.printStackTrace();
}
socket = new SocketIO();
socket.connect(sreverURL, new IOCallback() {
@Override
public void onMessage(JSONObject json, IOAcknowledge ack) {
Log.e("json Object", json.toString());
}
@Override
public void onMessage(String data, IOAcknowledge ack) {
Log.e("json Object", data.toString());
}
@Override
public void onError(SocketIOException socketIOException) {
socketIOException.printStackTrace();
System.out.println(socketIOException.toString());
}
@Override
public void onDisconnect() {
}
@Override
public void onConnect() {
showToast("Connected to " + sreverURL);
startCall("");
}
@Override
public void on(final String event, IOAcknowledge ack, final Object... args) {
Log.e("Socked.on", event + ", " + args);
switch (getEvent(event)) {
case LOG :
break;
case MESSAGE :
if (args instanceof Object[]) {
if (args[0].toString().contains("offer")) {
// startCall("");
}
pc_events.setMessage(args[0].toString());
} else {
pc_events.setMessage(args.toString());
}
break;
case CREATED :
runOnUiThread(new Runnable() {
public void run() {
showToast("Room Created " + args[0]);
}
});
break;
case BROADCAST :
Log.e("Socked.onBROADCAST", args.toString());
break;
case JOIN :
Log.e("Socked.onJOIN", args.toString());
break;
case EMIT :
Log.e("Socked.onEMIT", args.toString());
Log.e("Socked.onBROADCOST", args.toString());
break;
case ERROR :
Log.e("Socked.onERROR", args.toString());
break;
default :
break;
}
}
});
try {
RoomId = roomid.getText().toString();
} catch (Exception e) {
}
socket.emit("create or join", RoomId);
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
public void oncancel(View view) {
}
public SocketEvent getEvent(String eventString) {
SocketEvent eventType;
try {
if (eventString.contains("log")) {
eventType = SocketEvent.LOG;
} else if (eventString.contains("created")) {
eventType = SocketEvent.CREATED;
} else if (eventString.contains("emit():")) {
eventType = SocketEvent.EMIT;
}
else if (eventString.contains("broadcast():")) {
eventType = SocketEvent.BROADCAST;
} else if (eventString.contains("message")) {
eventType = SocketEvent.MESSAGE;
} else if (eventString.toLowerCase().substring(0, 20).contains("join")) {
eventType = SocketEvent.JOIN;
} else {
eventType = SocketEvent.ERROR;
}
} catch (Exception e) {
eventType = SocketEvent.ERROR;
}
return eventType;
}
public static interface Events {
public void peerConnectionEvent(String clintID, VideoRenderer.Callbacks localRender, VideoRenderer.Callbacks remoteRender);
public void setFactory(PeerConnectionFactory factory);
public void setMessage(String message);
public void createOffer();
}
private void startCall(String clientID) {
pc_events.setFactory(factory);
pc_events.peerConnectionEvent(clientID, localRender, remoteRender);
}
public void showToast(final String message) {
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(Home.this, message, Toast.LENGTH_SHORT).show();
}
});
}
public void makeOffer(View v) {
pc_events.createOffer();
}
}
PeerEventHandler.java
public class peerEventHandler implements Events {
private PeerConnection peerConnection;
private PeerConnectionFactory factory;
PCObserver pcObserver = new PCObserver();
public LooperExecutor executor;
private MediaStream mediaStream;
private VideoSource videoSource;
public static final String VIDEO_TRACK_ID = "ARDAMSv0";
public static final String AUDIO_TRACK_ID = "ARDAMSa0";
private VideoCapturerAndroid videoCapturer;
private VideoTrack localVideoTrack;
private VideoTrack remoteVideoTrack;
public boolean preferIsac = false;
public boolean videoCallEnabled = true;
public boolean preferH264 = true;
private static final String VIDEO_CODEC_H264 = "VP8";
private static final String AUDIO_CODEC_ISAC = "ISAC";
private SessionDescription localSdp;
private final SDPObserver sdpObserver = new SDPObserver();
private LinkedList<IceCandidate> queuedRemoteCandidates;
public boolean isInitiator = false;
private MediaConstraints sdpMediaConstraints;
private VideoRenderer.Callbacks localRender;
private VideoRenderer.Callbacks remoteRender;
@Override
public void peerConnectionEvent(String clintID, Callbacks localRender, Callbacks remoteRender) {
this.localRender = localRender;
this.remoteRender = remoteRender;
creatPeerConnection();
}
public void creatPeerConnection() {
queuedRemoteCandidates = new LinkedList<IceCandidate>();
executor = new LooperExecutor();
executor.requestStart();
MediaConstraints pcConstraints = new MediaConstraints();
MediaConstraints videoConstraints = new MediaConstraints();
MediaConstraints audioConstraints = new MediaConstraints();
sdpMediaConstraints = new MediaConstraints();
creatPcConstrains(pcConstraints);
creatvideoConstraints(videoConstraints);
creatsdpMediaConstraints(sdpMediaConstraints);
List<PeerConnection.IceServer> iceServers = new ArrayList<PeerConnection.IceServer>();
IceServer iceServer = new IceServer("stun:stun.l.google.com:19302", "", "");
iceServers.add(iceServer);
PeerConnection.RTCConfiguration rtcConfig = new PeerConnection.RTCConfiguration(iceServers);
// TCP candidates are only useful when connecting to a server that
// supports
// ICE-TCP.
rtcConfig.tcpCandidatePolicy = PeerConnection.TcpCandidatePolicy.DISABLED;
rtcConfig.bundlePolicy = PeerConnection.BundlePolicy.BALANCED;
rtcConfig.rtcpMuxPolicy = PeerConnection.RtcpMuxPolicy.NEGOTIATE;
peerConnection = factory.createPeerConnection(rtcConfig, pcConstraints, pcObserver);
Logging.enableTracing("logcat:", EnumSet.of(Logging.TraceLevel.TRACE_DEFAULT), Logging.Severity.LS_WARNING);
mediaStream = factory.createLocalMediaStream("ARDAMS");
String cameraDeviceName = CameraEnumerationAndroid.getDeviceName(0);
String frontCameraDeviceName = CameraEnumerationAndroid.getNameOfFrontFacingDevice();
cameraDeviceName = frontCameraDeviceName;
videoCapturer = VideoCapturerAndroid.create(cameraDeviceName, null);
videoSource = factory.createVideoSource(videoCapturer, videoConstraints);
localVideoTrack = factory.createVideoTrack(VIDEO_TRACK_ID, videoSource);
localVideoTrack.setEnabled(true);
localVideoTrack.addRenderer(new VideoRenderer(localRender));
mediaStream.addTrack(factory.createAudioTrack(AUDIO_TRACK_ID, factory.createAudioSource(audioConstraints)));
mediaStream.addTrack(localVideoTrack);
peerConnection.addStream(mediaStream);
}
@Override
public void createOffer() {
executor.execute(new Runnable() {
@Override
public void run() {
if (peerConnection != null) {
isInitiator = true;
peerConnection.createOffer(sdpObserver, sdpMediaConstraints);
}
}
});
}
public void createAnswer() {
executor.execute(new Runnable() {
@Override
public void run() {
if (peerConnection != null) {
isInitiator = false;
peerConnection.createAnswer(sdpObserver, sdpMediaConstraints);
}
}
});
}
private class PCObserver implements PeerConnection.Observer {
@Override
public void onAddStream(final MediaStream stream) {
Log.e("onAddStream", "onAddStream");
executor.execute(new Runnable() {
@Override
public void run() {
if (peerConnection == null) {
return;
}
if (stream.audioTracks.size() > 1 || stream.videoTracks.size() > 1) {
// /reportError("Weird-looking stream: " + stream);
return;
}
if (stream.videoTracks.size() == 1) {
remoteVideoTrack = stream.videoTracks.get(0);
remoteVideoTrack.setEnabled(true);
remoteVideoTrack.addRenderer(new VideoRenderer(remoteRender));
}
}
});
}
@Override
public void onDataChannel(DataChannel arg0) {
Log.e("On data channel", "Data Channel");
}
@Override
public void onIceCandidate(IceCandidate candidate) {
SocketIO socket = Home.socket;
JSONObject json = new JSONObject();
try {
json.putOpt("type", "candidate");
json.putOpt("label", candidate.sdpMLineIndex);
json.putOpt("id", candidate.sdpMid);
json.putOpt("candidate", candidate.sdp);
} catch (JSONException e) {
}
socket.emit("message", json);
}
@Override
public void onIceConnectionChange(IceConnectionState arg0) {
Log.e("onIceConnectionChange", "onIceConnectionChange");
}
@Override
public void onIceConnectionReceivingChange(boolean arg0) {
Log.e("onIceConnectionReceivingChange", "onIceConnectionReceivingChange");
}
@Override
public void onIceGatheringChange(IceGatheringState arg0) {
Log.e("onIceGatheringChange", "onIceGatheringChange");
}
@Override
public void onRemoveStream(MediaStream arg0) {
Log.e("onRemoveStream", "onRemoveStream");
}
@Override
public void onRenegotiationNeeded() {
Log.e("onRenegotiationNeeded", "onRenegotiationNeeded");
}
@Override
public void onSignalingChange(SignalingState arg0) {
Log.e("onSignalingChange", "onSignalingChange");
}
}
public void creatPcConstrains(MediaConstraints pcConstraints) {
pcConstraints.optional.add(new KeyValuePair("DtlsSrtpKeyAgreement", "true"));
pcConstraints.optional.add(new KeyValuePair("RtpDataChannels", "true"));
}
public void creatvideoConstraints(MediaConstraints videoConstraints) {
String MAX_VIDEO_WIDTH_CONSTRAINT = "maxWidth";
String MIN_VIDEO_WIDTH_CONSTRAINT = "minWidth";
String MAX_VIDEO_HEIGHT_CONSTRAINT = "maxHeight";
String MIN_VIDEO_HEIGHT_CONSTRAINT = "minHeight";
String MAX_VIDEO_FPS_CONSTRAINT = "maxFrameRate";
String MIN_VIDEO_FPS_CONSTRAINT = "minFrameRate";
int videoWidth = 0;
int videoHeight = 0;
// If VP8 HW video encoder is supported and video resolution is not
// specified force it to HD.
if ((videoWidth == 0 || videoHeight == 0) && true && MediaCodecVideoEncoder.isVp8HwSupported()) {
videoWidth = 1280;
videoHeight = 1280;
}
// Add video resolution constraints.
if (videoWidth > 0 && videoHeight > 0) {
videoWidth = Math.min(videoWidth, 1280);
videoHeight = Math.min(videoHeight, 1280);
videoConstraints.mandatory.add(new KeyValuePair(MIN_VIDEO_WIDTH_CONSTRAINT, Integer.toString(videoWidth)));
videoConstraints.mandatory.add(new KeyValuePair(MAX_VIDEO_WIDTH_CONSTRAINT, Integer.toString(videoWidth)));
videoConstraints.mandatory.add(new KeyValuePair(MIN_VIDEO_HEIGHT_CONSTRAINT, Integer.toString(videoHeight)));
videoConstraints.mandatory.add(new KeyValuePair(MAX_VIDEO_HEIGHT_CONSTRAINT, Integer.toString(videoHeight)));
}
// Add fps constraints.
int videoFps = 30;
videoConstraints.mandatory.add(new KeyValuePair(MIN_VIDEO_FPS_CONSTRAINT, Integer.toString(videoFps)));
videoConstraints.mandatory.add(new KeyValuePair(MAX_VIDEO_FPS_CONSTRAINT, Integer.toString(videoFps)));
}
public void creataudioConstraints(MediaConstraints pcConstraints) {
pcConstraints.optional.add(new KeyValuePair("DtlsSrtpKeyAgreement", "true"));
pcConstraints.optional.add(new KeyValuePair("RtpDataChannels", "true"));
}
public void creatsdpMediaConstraints(MediaConstraints sdpMediaConstraints) {
sdpMediaConstraints.mandatory.add(new KeyValuePair("OfferToReceiveAudio", "true"));
sdpMediaConstraints.mandatory.add(new KeyValuePair("OfferToReceiveVideo", "true"));
}
private class SDPObserver implements SdpObserver {
@Override
public void onCreateFailure(String arg0) {
System.out.print(arg0);
}
@Override
public void onCreateSuccess(SessionDescription origSdp) {
if (localSdp != null) {
return;
}
String sdpDescription = origSdp.description;
if (preferIsac) {
sdpDescription = preferCodec(sdpDescription, AUDIO_CODEC_ISAC, true);
}
if (videoCallEnabled && preferH264) {
sdpDescription = preferCodec(sdpDescription, VIDEO_CODEC_H264, false);
}
final SessionDescription sdp = new SessionDescription(origSdp.type, sdpDescription);
localSdp = sdp;
executor.execute(new Runnable() {
@Override
public void run() {
if (peerConnection != null) {
JSONObject json = new JSONObject();
try {
// peerConnection.setLocalDescription(null, localSdp);
json.putOpt("type", "offer");
json.putOpt("sdp", localSdp.description);
} catch (JSONException e) {
e.printStackTrace();
}
Home.socket.emit("message", json);
}
}
});
}
@Override
public void onSetFailure(String arg0) {
Log.e("onSetFailure", arg0);
}
@Override
public void onSetSuccess() {
executor.execute(new Runnable() {
@Override
public void run() {
if (peerConnection == null) {
return;
}
if (isInitiator) {
createOffer();
} else {
createAnswer();
}
}
});
}
}
private static String preferCodec(String sdpDescription, String codec, boolean isAudio) {
String[] lines = sdpDescription.split("\r\n");
int mLineIndex = -1;
String codecRtpMap = null;
// a=rtpmap:<payload type> <encoding name>/<clock rate> [/<encoding
// parameters>]
String regex = "^a=rtpmap:(\\d+) " + codec + "(/\\d+)+[\r]?$";
Pattern codecPattern = Pattern.compile(regex);
String mediaDescription = "m=video ";
if (isAudio) {
mediaDescription = "m=audio ";
}
for (int i = 0; (i < lines.length) && (mLineIndex == -1 || codecRtpMap == null); i++) {
if (lines[i].startsWith(mediaDescription)) {
mLineIndex = i;
continue;
}
Matcher codecMatcher = codecPattern.matcher(lines[i]);
if (codecMatcher.matches()) {
codecRtpMap = codecMatcher.group(1);
continue;
}
}
if (mLineIndex == -1) {
// Log.w(TAG, "No " + mediaDescription + " line, so can't prefer " +
// codec);
return sdpDescription;
}
if (codecRtpMap == null) {
// Log.w(TAG, "No rtpmap for " + codec);
return sdpDescription;
}
// Log.d(TAG, "Found " + codec + " rtpmap " + codecRtpMap +
// ", prefer at "
// + lines[mLineIndex]);
String[] origMLineParts = lines[mLineIndex].split(" ");
if (origMLineParts.length > 3) {
StringBuilder newMLine = new StringBuilder();
int origPartIndex = 0;
// Format is: m=<media> <port> <proto> <fmt> ...
newMLine.append(origMLineParts[origPartIndex++]).append(" ");
newMLine.append(origMLineParts[origPartIndex++]).append(" ");
newMLine.append(origMLineParts[origPartIndex++]).append(" ");
newMLine.append(codecRtpMap);
for (; origPartIndex < origMLineParts.length; origPartIndex++) {
if (!origMLineParts[origPartIndex].equals(codecRtpMap)) {
newMLine.append(" ").append(origMLineParts[origPartIndex]);
}
}
lines[mLineIndex] = newMLine.toString();
// Log.d(TAG, "Change media description: " + lines[mLineIndex]);
} else {
// Log.e(TAG, "Wrong SDP media description format: " +
// lines[mLineIndex]);
}
StringBuilder newSdpDescription = new StringBuilder();
for (String line : lines) {
newSdpDescription.append(line).append("\r\n");
}
return newSdpDescription.toString();
}
private void drainCandidates() {
if (queuedRemoteCandidates != null) {
// Log.d(TAG, "Add " + queuedRemoteCandidates.size() +
// " remote candidates");
for (IceCandidate candidate : queuedRemoteCandidates) {
// if(!candidate.sdpMid.contains("video"))
peerConnection.addIceCandidate(candidate);
}
queuedRemoteCandidates = null;
}
}
public void addRemoteIceCandidate(final IceCandidate candidate) {
executor.execute(new Runnable() {
@Override
public void run() {
if (peerConnection != null) {
if (queuedRemoteCandidates != null) {
queuedRemoteCandidates.add(candidate);
} else {
peerConnection.addIceCandidate(candidate);
}
}
}
});
}
public void setRemoteDescription(final SessionDescription sdp) {
executor.execute(new Runnable() {
@Override
public void run() {
if (peerConnection == null) {
return;
}
String sdpDescription = sdp.description;
if (preferIsac) {
sdpDescription = preferCodec(sdpDescription, AUDIO_CODEC_ISAC, true);
}
if (videoCallEnabled && preferH264) {
sdpDescription = preferCodec(sdpDescription, VIDEO_CODEC_H264, false);
}
SessionDescription sdpRemote = new SessionDescription(sdp.type, sdpDescription);
peerConnection.setRemoteDescription(sdpObserver, sdpRemote);
}
});
}
@Override
public void setFactory(PeerConnectionFactory factory) {
this.factory = factory;
}
public void onWebSocketMessage(final String msg) {
try {
Log.e("onWebSocketMessage", msg);
JSONObject json = new JSONObject(msg);
json = new JSONObject(msg);
String type = json.optString("type");
if (type.equals("candidate")) {
IceCandidate candidate = new IceCandidate(json.getString("id"), json.getInt("label"), json.getString("candidate"));
addRemoteIceCandidate(candidate);
} else if (type.equals("answer")) {
if (isInitiator) {
SessionDescription sdp = new SessionDescription(SessionDescription.Type.fromCanonicalForm(type), json.getString("sdp"));
setRemoteDescription(sdp);
} else {
}
} else if (type.equals("offer")) {
if (!isInitiator) {
SessionDescription sdp = new SessionDescription(SessionDescription.Type.fromCanonicalForm(type), json.getString("sdp"));
setRemoteDescription(sdp);
} else {
}
} else if (type.equals("bye")) {
} else {
}
} catch (JSONException e) {
}
}
@Override
public void setMessage(String message) {
if (message.toString().contains("got user media") || message.toString().contains("bye")) {
} else
onWebSocketMessage(message);
}
}
最佳答案
我不知道为什么,但我将 target=android-19
更改为 target=android-21
并且一切都按预期正常工作(数据通道除外)。
最终工作代码
PS:您可以使用此代码,无需任何版税和保证:p
Home.java
public class Home extends Activity {
public List<PeerConnection.IceServer> iceServers;
private GLSurfaceView videoView;
public static SocketIO socket;
ArrayList<String> userIDs = new ArrayList<>();
private static final String FIELD_TRIAL_VP9 = "WebRTC-SupportVP9/Enabled/";
String RoomId = "";
String sreverURL = "http://xx.xx.xx.xx:xxxx/";
private EditText roomid;
private VideoRenderer.Callbacks remote_view;
private VideoRenderer.Callbacks local_view;
protected PeerConnectionFactory factory;
PeerConnectionFactory.Options options = null;
Events pc_events;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
videoView = (GLSurfaceView) findViewById(R.id.glview_call_remote);
VideoRendererGui.setView(videoView, new Runnable() {
@Override
public void run() {
createPeerConnectionFactory();
}
});
remote_view = VideoRendererGui.create(0, 0, 100, 100, ScalingType.SCALE_ASPECT_FIT, false);
local_view = VideoRendererGui.create(0, 0, 100, 100, ScalingType.SCALE_ASPECT_FILL, true);
iceServers = new ArrayList<>();
IceServer icc = new IceServer("stun:stun.l.google.com:19302", "", "");
iceServers.add(icc);
roomid = (EditText) findViewById(R.id.roomId);
Random rand = new Random();
roomid.setText("" + rand.nextInt(9999));
pc_events = new peerEventHandler();
}
private void createPeerConnectionFactory() {
runOnUiThread(new Runnable() {
@Override
public void run() {
PeerConnectionFactory.initializeFieldTrials(FIELD_TRIAL_VP9);
PeerConnectionFactory.initializeAndroidGlobals(Home.this, true, true, true, VideoRendererGui.getEGLContext());
try {
factory = new PeerConnectionFactory();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public void ondail(View view) {
try {
try {
SocketIO.setDefaultSSLSocketFactory(SSLContext.getDefault());
} catch (NoSuchAlgorithmException e1) {
e1.printStackTrace();
}
socket = new SocketIO();
socket.connect(sreverURL, new IOCallback() {
@Override
public void onMessage(JSONObject json, IOAcknowledge ack) {
}
@Override
public void onMessage(String data, IOAcknowledge ack) {
}
@Override
public void onError(SocketIOException socketIOException) {
socketIOException.printStackTrace();
}
@Override
public void onDisconnect() {
}
@Override
public void onConnect() {
showToast("Connected to " + sreverURL);
}
@Override
public void on(final String event, IOAcknowledge ack, final Object... args) {
Log.e("Socked.on", event + ", " + args);
switch (getEvent(event)) {
case LOG :
break;
case MESSAGE :
if (args instanceof Object[]) {
pc_events.setMessage(args[0].toString());
} else {
pc_events.setMessage(args.toString());
}
break;
case CREATED :
runOnUiThread(new Runnable() {
public void run() {
showToast("Room Created " + args[0]);
}
});
break;
case BROADCAST :
break;
case JOIN :
break;
case EMIT :
Log.e("Socked.onEMIT", args.toString());
startCall();
pc_events.createOffer();
break;
case ERROR :
Log.e("Socked.onERROR", args.toString());
break;
default :
break;
}
}
});
try {
RoomId = roomid.getText().toString();
} catch (Exception e) {
}
socket.emit("create or join", RoomId);
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
public void oncancel(View view) {
}
public SocketEvent getEvent(String eventString) {
SocketEvent eventType;
try {
if (eventString.contains("log")) {
eventType = SocketEvent.LOG;
} else if (eventString.contains("created")) {
eventType = SocketEvent.CREATED;
} else if (eventString.contains("emit():")) {
eventType = SocketEvent.EMIT;
}
else if (eventString.contains("broadcast():")) {
eventType = SocketEvent.BROADCAST;
} else if (eventString.contains("message")) {
eventType = SocketEvent.MESSAGE;
} else if (eventString.toLowerCase().substring(0, 20).contains("join")) {
eventType = SocketEvent.JOIN;
} else {
eventType = SocketEvent.ERROR;
}
} catch (Exception e) {
eventType = SocketEvent.ERROR;
}
return eventType;
}
public static interface Events {
public void peerConnectionEvent(VideoRenderer.Callbacks localRender, VideoRenderer.Callbacks remoteRender);
public void setFactory(PeerConnectionFactory factory);
public void setMessage(String message);
public void createOffer();
public void sendMessage(String msg);
}
private void startCall() {
pc_events.setFactory(factory);
pc_events.peerConnectionEvent(remote_view, local_view);
}
public void showToast(final String message) {
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(Home.this, message, Toast.LENGTH_SHORT).show();
}
});
}
public void makeOffer(View v) {
pc_events.sendMessage("Hello");
}
}
peerEventHandler.java
public class peerEventHandler implements Events {
private PeerConnection peerConnection;
private PeerConnectionFactory factory;
PCObserver pcObserver = new PCObserver();
public LooperExecutor executor;
private MediaStream mediaStream;
private VideoSource videoSource;
private DcObserver dc_observer;
public static final String VIDEO_TRACK_ID = "ARDAMSv0";
public static final String AUDIO_TRACK_ID = "ARDAMSa0";
private VideoCapturerAndroid videoCapturer;
private VideoTrack localVideoTrack;
private VideoTrack remoteVideoTrack;
public boolean preferIsac = false;
public boolean videoCallEnabled = true;
public boolean preferH264 = false;
private SessionDescription localSdp;
private final SDPObserver sdpObserver = new SDPObserver();
public boolean isInitiator = false;
private MediaConstraints sdpMediaConstraints;
private VideoRenderer.Callbacks remote_view;
private VideoRenderer.Callbacks local_view;
private DataChannel dataChannel;
@Override
public void peerConnectionEvent(Callbacks remoteRender, Callbacks localRender) {
this.remote_view = remoteRender;
this.local_view = localRender;
creatPeerConnection();
}
public void creatPeerConnection() {
executor = new LooperExecutor();
executor.requestStart();
MediaConstraints pcConstraints = new MediaConstraints();
MediaConstraints videoConstraints = new MediaConstraints();
MediaConstraints audioConstraints = new MediaConstraints();
sdpMediaConstraints = new MediaConstraints();
creatPcConstrains(pcConstraints);
creatvideoConstraints(videoConstraints);
creatsdpMediaConstraints(sdpMediaConstraints);
List<PeerConnection.IceServer> iceServers = new ArrayList<PeerConnection.IceServer>();
IceServer iceServer = new IceServer("stun:stun.l.google.com:19302", "", "");
iceServers.add(iceServer);
PeerConnection.RTCConfiguration rtcConfig = new PeerConnection.RTCConfiguration(iceServers);
rtcConfig.tcpCandidatePolicy = PeerConnection.TcpCandidatePolicy.DISABLED;
rtcConfig.bundlePolicy = PeerConnection.BundlePolicy.BALANCED;
rtcConfig.rtcpMuxPolicy = PeerConnection.RtcpMuxPolicy.NEGOTIATE;
peerConnection = factory.createPeerConnection(rtcConfig, pcConstraints, pcObserver);
Logging.enableTracing("logcat:", EnumSet.of(Logging.TraceLevel.TRACE_DEFAULT), Logging.Severity.LS_WARNING);
mediaStream = factory.createLocalMediaStream("ARDAMS");
String cameraDeviceName = CameraEnumerationAndroid.getDeviceName(0);
String frontCameraDeviceName = CameraEnumerationAndroid.getNameOfFrontFacingDevice();
cameraDeviceName = frontCameraDeviceName;
videoCapturer = VideoCapturerAndroid.create(cameraDeviceName, null);
videoSource = factory.createVideoSource(videoCapturer, videoConstraints);
localVideoTrack = factory.createVideoTrack(VIDEO_TRACK_ID, videoSource);
localVideoTrack.setEnabled(true);
localVideoTrack.addRenderer(new VideoRenderer(local_view));
mediaStream.addTrack(factory.createAudioTrack(AUDIO_TRACK_ID, factory.createAudioSource(audioConstraints)));
mediaStream.addTrack(localVideoTrack);
peerConnection.addStream(mediaStream);
dataChannel = peerConnection.createDataChannel("sendDataChannel", new DataChannel.Init());
dc_observer = new DcObserver();
dataChannel.registerObserver(dc_observer);
}
@Override
public void createOffer() {
executor.execute(new Runnable() {
@Override
public void run() {
if (peerConnection != null) {
isInitiator = true;
peerConnection.createOffer(sdpObserver, sdpMediaConstraints);
}
}
});
}
public void createAnswer() {
executor.execute(new Runnable() {
@Override
public void run() {
if (peerConnection != null) {
isInitiator = false;
peerConnection.createAnswer(sdpObserver, sdpMediaConstraints);
}
}
});
}
private class PCObserver implements PeerConnection.Observer {
@Override
public void onAddStream(final MediaStream stream) {
Log.e("onAddStream", "onAddStream");
executor.execute(new Runnable() {
@Override
public void run() {
if (peerConnection == null) {
return;
}
if (stream.audioTracks.size() > 1 || stream.videoTracks.size() > 1) {
// /reportError("Weird-looking stream: " + stream);
return;
}
if (stream.videoTracks.size() == 1) {
remoteVideoTrack = stream.videoTracks.get(0);
remoteVideoTrack.setEnabled(true);
remoteVideoTrack.addRenderer(new VideoRenderer(remote_view));
VideoRendererGui.update(local_view, 75, 70, 60, 60, ScalingType.SCALE_ASPECT_FIT, true);
VideoRendererGui.update(remote_view, 0, 0, 200, 200, ScalingType.SCALE_ASPECT_FILL, false);
}
}
});
}
@Override
public void onDataChannel(final DataChannel dc) {
executor.execute(new Runnable() {
@Override
public void run() {
dataChannel = dc;
String channelName = dataChannel.label();
dataChannel.registerObserver(new DcObserver());
}
});
}
@Override
public void onIceCandidate(IceCandidate candidate) {
SocketIO socket = Home.socket;
JSONObject json = new JSONObject();
try {
json.putOpt("type", "candidate");
json.putOpt("label", candidate.sdpMLineIndex);
json.putOpt("id", candidate.sdpMid);
json.putOpt("candidate", candidate.sdp);
} catch (JSONException e) {
e.printStackTrace();
}
socket.emit("message", json);
}
@Override
public void onIceConnectionChange(IceConnectionState arg0) {
}
@Override
public void onIceConnectionReceivingChange(boolean arg0) {
}
@Override
public void onIceGatheringChange(IceGatheringState arg0) {
}
@Override
public void onRemoveStream(MediaStream arg0) {
}
@Override
public void onRenegotiationNeeded() {
}
@Override
public void onSignalingChange(SignalingState arg0) {
}
}
public void creatPcConstrains(MediaConstraints pcConstraints) {
pcConstraints.optional.add(new KeyValuePair("DtlsSrtpKeyAgreement", "true"));
pcConstraints.optional.add(new KeyValuePair("RtpDataChannels", "true"));
pcConstraints.optional.add(new KeyValuePair("internalSctpDataChannels", "true"));
}
public void creatvideoConstraints(MediaConstraints videoConstraints) {
String MAX_VIDEO_WIDTH_CONSTRAINT = "maxWidth";
String MIN_VIDEO_WIDTH_CONSTRAINT = "minWidth";
String MAX_VIDEO_HEIGHT_CONSTRAINT = "maxHeight";
String MIN_VIDEO_HEIGHT_CONSTRAINT = "minHeight";
String MAX_VIDEO_FPS_CONSTRAINT = "maxFrameRate";
String MIN_VIDEO_FPS_CONSTRAINT = "minFrameRate";
int videoWidth = 0;
int videoHeight = 0;
if ((videoWidth == 0 || videoHeight == 0) && true && MediaCodecVideoEncoder.isVp8HwSupported()) {
videoWidth = 1280;
videoHeight = 1280;
}
if (videoWidth > 0 && videoHeight > 0) {
videoWidth = Math.min(videoWidth, 1280);
videoHeight = Math.min(videoHeight, 1280);
videoConstraints.mandatory.add(new KeyValuePair(MIN_VIDEO_WIDTH_CONSTRAINT, Integer.toString(videoWidth)));
videoConstraints.mandatory.add(new KeyValuePair(MAX_VIDEO_WIDTH_CONSTRAINT, Integer.toString(videoWidth)));
videoConstraints.mandatory.add(new KeyValuePair(MIN_VIDEO_HEIGHT_CONSTRAINT, Integer.toString(videoHeight)));
videoConstraints.mandatory.add(new KeyValuePair(MAX_VIDEO_HEIGHT_CONSTRAINT, Integer.toString(videoHeight)));
}
int videoFps = 30;
videoConstraints.mandatory.add(new KeyValuePair(MIN_VIDEO_FPS_CONSTRAINT, Integer.toString(videoFps)));
videoConstraints.mandatory.add(new KeyValuePair(MAX_VIDEO_FPS_CONSTRAINT, Integer.toString(videoFps)));
}
public void creataudioConstraints(MediaConstraints pcConstraints) {
pcConstraints.optional.add(new KeyValuePair("DtlsSrtpKeyAgreement", "true"));
pcConstraints.optional.add(new KeyValuePair("RtpDataChannels", "true"));
pcConstraints.optional.add(new KeyValuePair("internalSctpDataChannels", "true"));
}
public void creatsdpMediaConstraints(MediaConstraints sdpMediaConstraints) {
sdpMediaConstraints.mandatory.add(new KeyValuePair("OfferToReceiveAudio", "true"));
sdpMediaConstraints.mandatory.add(new KeyValuePair("OfferToReceiveVideo", "true"));
}
private class SDPObserver implements SdpObserver {
@Override
public void onCreateFailure(String arg0) {
System.out.print(arg0);
}
@Override
public void onCreateSuccess(SessionDescription origSdp) {
if (localSdp != null) {
return;
}
localSdp = origSdp;
setLocalDescription(origSdp);
}
@Override
public void onSetFailure(String arg0) {
}
@Override
public void onSetSuccess() {
executor.execute(new Runnable() {
@Override
public void run() {
if (peerConnection == null) {
return;
}
if (isInitiator) {
if (peerConnection != null) {
JSONObject json = new JSONObject();
try {
json.putOpt("type", localSdp.type.toString().toLowerCase());
json.putOpt("sdp", localSdp.description);
} catch (JSONException e) {
e.printStackTrace();
}
Home.socket.emit("message", json);
}
} else {
// createAnswer();
}
}
});
}
}
public void addRemoteIceCandidate(final IceCandidate candidate) {
executor.execute(new Runnable() {
@Override
public void run() {
peerConnection.addIceCandidate(candidate);
}
});
}
public void setLocalDescription(final SessionDescription sdp) {
executor.execute(new Runnable() {
@Override
public void run() {
if (peerConnection == null) {
return;
}
peerConnection.setLocalDescription(sdpObserver, sdp);
}
});
}
public void setRemoteDescription(final SessionDescription sdp) {
executor.execute(new Runnable() {
@Override
public void run() {
if (peerConnection == null) {
return;
}
peerConnection.setRemoteDescription(sdpObserver, sdp);
}
});
}
@Override
public void setFactory(PeerConnectionFactory factory) {
this.factory = factory;
}
public void onWebSocketMessage(final String msg) {
try {
Log.e("onWebSocketMessage", msg);
JSONObject json = new JSONObject(msg);
json = new JSONObject(msg);
String type = json.optString("type");
if (type.equals("candidate")) {
IceCandidate candidate = new IceCandidate(json.getString("id"), json.getInt("label"), json.getString("candidate"));
addRemoteIceCandidate(candidate);
} else if (type.equals("answer")) {
isInitiator = false;
SessionDescription sdp = new SessionDescription(SessionDescription.Type.fromCanonicalForm(type), json.getString("sdp"));
setRemoteDescription(sdp);
} else if (type.equals("offer")) {
SessionDescription sdp = new SessionDescription(SessionDescription.Type.fromCanonicalForm(type), json.getString("sdp"));
setRemoteDescription(sdp);
} else if (type.equals("bye")) {
} else {
}
} catch (JSONException e) {
}
}
@Override
public void setMessage(String message) {
if (message.toString().contains("got user media") || message.toString().contains("bye")) {
} else
onWebSocketMessage(message);
}
private class DcObserver implements DataChannel.Observer {
@Override
public void onMessage(DataChannel.Buffer buffer) {
ByteBuffer data = buffer.data;
byte[] bytes = new byte[data.remaining()];
data.get(bytes);
String command = new String(bytes);
Log.e("onMessage ", command);
}
@Override
public void onStateChange() {
Log.e("onStateChange ", "onStateChange");
}
@Override
public void onBufferedAmountChange(long arg0) {
Log.e("onMessage ", "" + arg0);
}
}
@Override
public void sendMessage(String msg) {
ByteBuffer buffer = ByteBuffer.wrap(msg.getBytes());
boolean sent = dataChannel.send(new DataChannel.Buffer(buffer, false));
if (sent) {
Log.e("Message sent", "" + sent);
}
}
}
关于android - 通过 socket.io-client 和 libjingle 从 Android 应用程序流式传输到浏览器客户端应用程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33868418/
我遇到了一个错误,我不知道如何解决。我有以下代码(来自 Eliom Graffiti 教程),我正在尝试使用 make test.byte 进行测试。 open Eliom_content.Html5
我阅读文档的理解是这样的: 客户端是测试用例的子类。当我们运行 manage.py test 时,会为每个以“test_”开头的方法创建一个 SimpleTest 类的实例(它继承自 TestCase
我已经编写了一个用于接收多个客户端的服务器,它可以分别与客户端通信。在这里,我可以列出服务器中已连接的客户端,但是当客户端断开连接时,它不会从服务器中删除客户端。 Server.py import s
我正在制作一个社交网站。当任何用户在站点上更新或创建新内容时,我需要查看站点的任何其他用户来查看更改更新。 我有一些需要低延迟的评论,因此建议为此订阅。 我也有事件,但这些不需要这么低的延迟。每 10
我想在突变后使用乐观 UI 更新:https://www.apollographql.com/docs/react/basics/mutations.html 我对“乐观响应”和“更新”之间的关系感到
我想了解 Dask 在本地机器上的使用模式。 具体而言, 我有一个适合内存的数据集 我想做一些 pandas 操作 分组依据... 日期解析 等等 Pandas 通过单核执行这些操作,这些操作对我来说
我使用 Apollo、React 和 Graphcool。我有一个查询来获取登录的用户 ID: const LoginServerQuery = gql` query LoginServerQ
在本指南的帮助下,我最近在几个设备的应用程序中设置了 P2P 通信:http://developer.android.com/training/connect-devices-wirelessly/n
注意:我在节点项目中使用@twilio/conversations 1.1.0 版。我正在从使用可编程聊天过渡到对话。 我看到对 Client.getConversationByUniqueName
我对服务客户端和设备客户端库有点困惑。谁能解答我对此的疑问。 问题:当我通过 deviceClient 发送数据时,我无法接收数据,但当我使用服务客户端发送数据时,相同的代码可以工作。现在,xamar
我对服务客户端和设备客户端库有点困惑。谁能解答我对此的疑问。 问题:当我通过 deviceClient 发送数据时,我无法接收数据,但当我使用服务客户端发送数据时,相同的代码可以工作。现在,xamar
假设我有一个简单的应用程序。 如何设置 OAuth2 以允许其他应用程序访问我的应用程序的某些部分。 例如,当开发人员想要使用 Facebook API 时,他们会使用 Facebook API 用户
我有两个模块: 在一个模块中,我从另一个模块run 中引用了一个函数: @myorg/server import { Client } from '.' import { Middleware } f
我在通过服务器从客户端向客户端发送数据时遇到了一些问题(以避免监听客户端上的端口)。 我有一个这样的服务器: var net = require("net"); var server = net.cr
我正在使用 django.test.client.Client 来测试用户登录时是否显示某些文本。但是,我的 Client 对象似乎并没有让我保持登录状态。 如果使用 Firefox 手动完成,则此测
有两个我制作的程序无法运行。有服务器和客户端。服务器通过给用户一个 ID(从 0 开始)来接受许多客户端。服务器根据服务器的 ID 将命令发送到特定的客户端。 (示例:200 个客户端连接到 1 个服
今天,我在 Windows 10 的“程序和功能”列表中看到了 2 个不同版本的 ARC,因此我选择卸载旧版本,因为我需要一些空间。在卸载结束时,它们都消失了! 所以,我从 https://insta
在每个新的客户端连接上 fork 服务器进程 不同的进程(服务器的其他子进程,即 exec)无法识别在 fork 子进程中使用相同 fd 的客户端。 如何在其他进程上区分客户端? 如果文件描述符为新
a和b有什么区别? >>> import boto3 >>> a = boto3.Session().client("s3") >>> b = boto3.client("s3") >>> a ==
a和b有什么区别? >>> import boto3 >>> a = boto3.Session().client("s3") >>> b = boto3.client("s3") >>> a ==
我是一名优秀的程序员,十分优秀!