1

我正在尝试将我的网络摄像头从计算机上的网页本地流式传输到 Android 应用程序(本机 WebRTC)。我使用 WebRTC 进行对等连接,使用带有 Socket.io 的 NodeJS 进行信号传输。当我启动视频流时,所有 sdp 似乎都已正确设置,但在我的 Andorid 表面视图上没有播放任何曲目。我得到的只是一个黑屏和这个控制台输出:

2020-08-19 13:23:19.667 30492-31575/com.example.demowebrtcclient I/org.webrtc.Logging: EglRenderer: video_viewDuration: 4050 ms. Frames received: 0. Dropped: 0. Rendered: 0. Render fps: .0. Average render time: NA. Average swapBuffer time: NA.

这是我的代码,对不起,我只是不知道问题的根源在哪里。

Peer 1(网页,JS)

 navigator.mediaDevices.getUserMedia({audio: true, video: true})
    .then(function(s) {
      stream = s;
      video.srcObject = stream;
      video.play();
    });

  function startStream() {

    socket.emit('broadcaster');
  }

  socket.on('answer', function(id, description) {
    let RTCDescription = description;

    if (isAndroid) {
      RTCDescription = new RTCSessionDescription();
      RTCDescription.sdp = description;
      RTCDescription.type = "answer";
      console.log("Answer received");
    }

    console.log(RTCDescription);
    peerConnection.setRemoteDescription(RTCDescription); 
  });

  socket.on('watcher', function(id) {
    peerConnection = new RTCPeerConnection(config);
    // peerConnections[id] = peerConnection;
    stream.getTracks().forEach(track => peerConnection.addTrack(track, stream));
    peerConnection.createOffer()
    .then(function(sdp) {
      peerConnection.setLocalDescription(sdp);
    }) 
    .then(function() {
      socket.emit('offer', id, peerConnection.localDescription);
    })
    peerConnection.onicecandidate = function(event) {
      if (event.candidate) {
        socket.emit('candidate', id, event.candidate);
      }
    };
  });

  socket.on('candidate', function(id, candidate) {
    console.log("Candidate recieved");
    peerConnection.addIceCandidate(new RTCIceCandidate(candidate));
  });

  socket.on('close', function(id) {
    peerConnection.close();
    delete peerConnection;
  });

对等 2(Android、Java)

private void initializePeerConnectionFactory() {
    PeerConnectionFactory.InitializationOptions initOptions = PeerConnectionFactory.InitializationOptions.builder(getApplicationContext())
        .setEnableInternalTracer(true)
        .setFieldTrials("WebRTC-H264HighProfile/Enabled/")
        .createInitializationOptions();

    PeerConnectionFactory.initialize(initOptions);
    VideoEncoderFactory defaultVideoEncoderFactory = new DefaultVideoEncoderFactory(rootEglBaseContext,  /* enableIntelVp8Encoder */true,  /* enableH264HighProfile */true);
    VideoDecoderFactory defaultVideoDecoderFactory = new DefaultVideoDecoderFactory(rootEglBaseContext);

    PeerConnectionFactory.Options options = new PeerConnectionFactory.Options();
    options.disableEncryption = true;
    options.disableNetworkMonitor = true;

    factory = PeerConnectionFactory.builder()
            .setVideoEncoderFactory(defaultVideoEncoderFactory)
            .setVideoDecoderFactory(defaultVideoDecoderFactory)
            .setOptions(options)
            .createPeerConnectionFactory();
}



@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    rootEglBase = EglBase.create();
    rootEglBaseContext = rootEglBase.getEglBaseContext();
    videoView = findViewById(R.id.video_view);
    videoView.setMirror(true);
    videoView.setEnableHardwareScaler(true);
    videoView.init(rootEglBaseContext, null);

    videoSink = new ProxyVideoSink();

    iceServers = new ArrayList<>();

    stunServer = (PeerConnection.IceServer.builder("stun:stun.l.google.com:19302").createIceServer());
    iceServers.add(stunServer);



    executor = Executors.newSingleThreadScheduledExecutor();

    mediaConstraints = new MediaConstraints();
    mSocket.on(Socket.EVENT_CONNECT, onConnect);
    mSocket.on("offer", handleOffer);
    mSocket.on("broadcaster", onBroadcast);
    mSocket.on("candidate", onCandidate);

    mSocket.connect();

    initializePeerConnectionFactory();
}


private Emitter.Listener handleOffer = new Emitter.Listener() {
    @Override
    public void call(final Object... args) {
        Log.d("socket", "Offer recieved");
        peerConnection = factory.createPeerConnection(iceServers, observer);
        String id = (String) args[0];
        JSONObject data = (JSONObject) args[1];
        peerConnection.setRemoteDescription(new SdpAdapter("setremote") {
            @Override
            public void onSetSuccess() {
                peerConnection.createAnswer(new SdpAdapter("createanswer") {
                    @Override
                    public void onCreateSuccess(final SessionDescription sdp) {
                        super.onCreateSuccess(sdp);
                        Log.d("socket", "Session description " + sdp.toString() + " created");
                        SdpAdapter local = new SdpAdapter("setlocal") {
                            @Override
                            public void onSetSuccess() {
                                super.onSetSuccess();
                                mSocket.emit("answer" , id, peerConnection.getLocalDescription().description);
                            }
                        };
                        peerConnection.setLocalDescription(local, sdp);
                    }
                }, mediaConstraints);
            }
        }, new SessionDescription(SessionDescription.Type.OFFER, data.optString("sdp")));
    }
};


private Emitter.Listener onConnect = new Emitter.Listener() {
    @Override
    public void call(final Object... args) {
        Log.d("socket", "Socket connected");
        mSocket.emit("watcher");
    }
};

private Emitter.Listener onBroadcast = new Emitter.Listener() {
    @Override
    public void call(final Object... args) {
        Log.d("socket", "Received broadcast request");
        mSocket.emit("watcher");
    }
};

private Emitter.Listener onCandidate = new Emitter.Listener() {
    @Override
    public void call(final Object... args) {
        Log.d("ice", "New ice candidate recieved");

        JSONObject data = (JSONObject) args[1];
        IceCandidate candidate = new IceCandidate(data.optString("sdpMid"), Integer.parseInt(data.optString("sdpMLineIndex")), data.optString("candidate"));
        peerConnection.addIceCandidate(candidate);
    }
};

public class SdpAdapter implements SdpObserver {
    private String name;

    public SdpAdapter(String name) {
        this.name = name;
    }

    @Override
    public void onCreateSuccess(SessionDescription sessionDescription) {
        Log.d("socket", "SDP create success for " + name );
    }

    @Override
    public void onSetSuccess() {
        Log.d("socket", "SDP set success for " + name);
    }

    @Override
    public void onCreateFailure(String s) {
        Log.d("socket", "SDP create failure for" + s);
    }

    @Override
    public void onSetFailure(String s) {
        Log.d("socket", "SDP set failure for" + s);
    }
};


public static class ProxyVideoSink implements VideoSink {
    private VideoSink mTarget;
    @Override
    synchronized public void onFrame(VideoFrame frame) {
        if (mTarget == null) {
            Log.d("socket", "Dropping frame in proxy because target is null.");
            return;
        }
        mTarget.onFrame(frame);
    }
    synchronized void setTarget(VideoSink target) {
        this.mTarget = target;
    }
}

Observer observer = new Observer() {
    @Override
    public void onIceCandidate(IceCandidate iceCandidate) {
        Log.d("ice", iceCandidate.toString());
        mSocket.emit("candidate", iceCandidate);

    }

    @Override
    public void onAddStream(MediaStream stream) {
        executor.execute(new Runnable() {
            @Override
            public void run() {
                Log.d("socket", "Stream added");
                Log.d("tracks", "Getting  tracks");
                VideoTrack remoteVideoTrack = (VideoTrack)stream.videoTracks.get(0);
                AudioTrack remoteAudioTrack = (AudioTrack)stream.audioTracks.get(0);
                Log.d("tracks", "Enabling tracks");
                remoteAudioTrack.setEnabled(true);
                remoteVideoTrack.setEnabled(true);
                Log.d("tracks", "Adding sink");
                videoSink.setTarget(videoView);
                remoteVideoTrack.addSink(videoSink);
                peerConnection.getStats(reports -> {
                    for (StatsReport report : reports) {
                        Log.d("Stats", "Stats: " + report.toString());
                    }
                }, null);



            }
        });
    }



};

}

4

1 回答 1

1

在 Android 中禁用加密会破坏与浏览器的互操作性,除非您以特殊(不安全)模式启动它们。

options.disableEncryption = true;

开始使用 Android 原生 WebRTC API 的一个好点是查看示例应用程序代码: https ://chromium.googlesource.com/external/webrtc/+/refs/heads/master/examples/androidapp/src/org /appspot/apprtc/PeerConnectionClient.java

我会建议添加更多日志并扩展描述/问题。

调试 WebRTC 问题时的推荐过程:

  1. ICE成功了吗?(iceConnectionState已连接)如果没有,请查看收集和接收的候选人。检查涉及的防火墙配置、NAT 和 TURN。
  2. 您是否收到数据包但无法渲染帧?检查您的编解码器和编码器/解码器。
于 2021-01-07T20:26:38.290 回答