2015-11-25 22 views
7

Tôi có một ứng dụng Android đang chạy với tư cách máy khách WebRTC đang chạy trên máy chủ Node.js. Trạng thái hiện tại của ứng dụng là tôi có thể thực hiện cuộc gọi điện video nhưng không thể gửi tin nhắn trên DataChannel.DataChannel.state() luôn trả về CONNECTING webRTC Android

Đây là mã hoàn chỉnh của tôi cho ứng dụng 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); 
     } 
    } 
} 

Bất kỳ ý kiến ​​đóng góp đều được hoan nghênh;) kênh dữ liệu

+1

Mã để thêm kênh dữ liệu có vẻ ổn với tôi, ngoại trừ bạn có thể xóa các hạn chế RtpDataChannels. Khi tôi nhớ lại kênh dữ liệu hoạt động thông qua SCTP ngay bây giờ –

+0

Cảm ơn @GuyS Tôi sẽ cố gắng và cho bạn biết sớm –

+0

Cảm ơn @GuyS Nó hoạt động rất tốt, mặc dù đã có một chút thay đổi trong Server nhưng mẹo của bạn đã hoạt động. Bạn có thể đăng nó như là câu trả lời để tôi chấp nhận nó và có thể giúp đỡ người khác. –

Trả lời

2

WebRTC của hoạt động thông qua SCTP bây giờ để bạn có thể loại bỏ ràng buộc RtpDataChannels.

Các vấn đề liên quan