Intereting Posts
Android.os.TransactionTooLargeException выбрано случайно Android: изменить URL-адрес пути без "/" Невозможно использовать onDismiss () при использовании настраиваемых диалогов – Android Voice Matcher для сопоставления голосового пароля в Android (сравнить голос) Как центрировать вид внутри макета Android? Анимация ListView элементов в notifyDataSetChanged () Как получить процент буферизации VideoView на Android Как сделать макет прокручиваемым? Android Почему tinyALSA предпочитает libasound? Для Android требуется уровень соответствия компилятора 5.0 или 6.0. Вместо этого найдено «1.7». Используйте Android Tools> Fix Project Properties Событие Touchstart никогда не запускается на Android Chrome при первом загрузке страницы Стиль не применяется в пользовательских флажках и радиообменах Как обращаться с Touch вне представления в Android? Не удалось подключиться к телефону LG с помощью adb (Mac OS X 10.7.5) Как предотвратить андроидную форму от пропусков разделов в форме?

DataChannel.state () всегда возвращает CONNECTING webRTC Android

У меня есть приложение для Android, работающее как клиент сервера WebRTC, работающего на сервере Node.js. Текущее состояние приложения – я могу совершать видеозвонки, но не могу отправить сообщение в DataChannel.

Вот мой полный код для приложения для Android.

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); } } } 

Любые замечания и предложения приветствуются;)

Канал данных WebRTC теперь работает через SCTP, поэтому вы можете удалить ограничение RtpDataChannels.