kclyu / rpi-webrtc-streamer

This repo's objective is providing something like Web Cam server on the most popular Raspberry PI hardware. By integrating [WebRTC](https://webrtc.org/native-code/) and Raspberry PI, we can stream the Raspberry camera feed to browser or native client which talks WebRTC.
Other
629 stars 108 forks source link

DirectRTC TURN server #72

Closed leofds closed 5 years ago

leofds commented 5 years ago

Hi, I have a STUN / TURN server and am trying to test the TURN. My TURN server works because I already tested it with another application. I configured the webrtc_streamer.conf file as below. But the program does not connect to the TURN server for authentication. TURN is running on RWS ? The configuration is the problem ?

websocket_enable=true
websocket_port=8889
media_config=etc/media_config.conf
motion_config=etc/motion_config.conf
direct_socket_enable=true
direct_socket_port=8888
disable_log_buffering=false
web_root=/home/pi/Workspace/rws/web-root
libwebsocket_debug=false
rws_ws_url=/rws/ws
srtp_enable=true
audio_enable=true
video_enable=true
ice_server_urls_0=stun:stun.myserver.com.br:3478
# ice_server_urls_0=stun:stun.l.google.com:19302,stun:stun1.l.google.com:19302,stun:stun2.l.google.com:19302,stun:stun3.l.google.com:19302,stun:stun4.l.google.com:19302
#
# * : default value
# ice_transports_type=  none | relay | nohost | *all
# bundle_policy=  *balanced | max-bundle | max-compat
# rtcp_mux_policy= *require | negotiate
#
ice_server_urls_?=turn:turn.myserver.com.br:3478
ice_server_username_?=***
ice_server_password_?=***
ice_server_hostname_?=turn.myserver.com.br
ice_server_tls_cert_policy_?= insecure
# ice_server_tls_alpn_protocols_?= # List of protocols to be used in the TLS ALPN extension.
# ice_server_tls_elliptic_curves_?= # List of elliptic curves to be used in the TLS elliptic curves extension.
kclyu commented 5 years ago

You can use a numeric id instead of '?' character.

ice_server_urls_0=turn:turn.myserver.com.br:3478
ice_server_username_0=***
ice_server_password_0=***
ice_server_hostname_0=turn.myserver.com.br

Use a different id when setting up multiple ice server config

ice_server_urls_0=stun:stun.l.google.com:19302
ice_server_urls_1=turn:public.internet.turn.ipaddress:3478?transport=udp
ice_server_username_1=username
ice_server_password_1=password

Please see #66 issues for more details.

leofds commented 5 years ago

Thanks Is now authenticating on the server I'm trying to force the turn

leofds commented 5 years ago

I used the last binary file webrtc-streamer.gz of #66 But it's not working for me. I did not succeed as @uCibar got, even the results were different.

I put Rpi purposely behind a proxy and nat that makes it difficult to connect srflx, relay required. Rpi is not sending srflx and relay candidates, only host candidates. Outside the proxy, host and srflx candidates are sent. With that last binary the connection srflx is not working, RWS is looped as below. (in the version i compiled of RWS was running) Only connect with host on the same network

...
(raspi_encoder_impl.cc:476): Error in passng EncodedImage
(port.cc:1756): Conn[7174d178:0:Net[eth0:2804:30c:908:x:x:x:x:x/64:Ethernet:id=2]:cufh/V04:1:0:local:udp:[2804:30c:908:x:x:x:x:x]:55966->y3QJVI2R:1:2122262783:local:udp:[2804:18:53:x:x:x:x:x]:41180|C--I|-|0|0|9115049250747470334|-]: Sent STUN ping, id=4a6863756d64427643413944, use_candidate=1, nomination=0
(port.cc:1756): Conn[7174d178:0:Net[eth0:2804:30c:908:x:x:x:x:x/64:Ethernet:id=2]:cufh/V04:1:0:local:udp:[2804:30c:908:x:x:x:x:x]:55966->y3QJVI2R:1:2122262783:local:udp:[2804:18:53:x:x:x:x:x]:41180|C--I|-|0|0|9115049250747470334|-]: Sent STUN ping, id=58583545392f466956483858, use_candidate=1, nomination=0
(raspi_encoder_impl.cc:476): Error in passng EncodedImage
(port.cc:1756): Conn[7174d178:0:Net[eth0:2804:30c:908:x:x:x:x:x/64:Ethernet:id=2]:cufh/V04:1:0:local:udp:[2804:30c:908:x:x:x:x:x]:55966->y3QJVI2R:1:2122262783:local:udp:[2804:18:53:x:x:x:x:x]:41180|C--I|-|0|0|9115049250747470334|-]: Sent STUN ping, id=67614b4e315251314a316b7a, use_candidate=1, nomination=0
(raspi_encoder_impl.cc:476): Error in passng EncodedImage
(port.cc:1756): Conn[7174d178:0:Net[eth0:2804:30c:908:x:x:x:x:x/64:Ethernet:id=2]:cufh/V04:1:0:local:udp:[2804:30c:908:x:x:x:x:x]:55966->y3QJVI2R:1:2122262783:local:udp:[2804:18:53:x:x:x:x:x]:41180|C--I|-|0|0|9115049250747470334|-]: Sent STUN ping, id=5659346455324a496a6e6636, use_candidate=1, nomination=0
(raspi_encoder_impl.cc:476): Error in passng EncodedImage
...

I even went back to using STUN's google server but it did not solve!

I'm using an AppRTCMobile based Android App on 4G connection.

leofds commented 5 years ago

I returned my binary, and now also srflx does not work, how strange!

kclyu commented 5 years ago

You can test it properly by testing through the external network with the turn server config setting using a browser that works well on the local network. In addition, the AppRTCMobile app does not have an interface to exchange singing messages with RWS. AppRTCMobile app should be tested on google's AppRTC site.

leofds commented 5 years ago

Let me explain my test better:

I am using AppRTCMobile with DirectSocket.

On the local network it works. To test the performance of the video through the 4g network I made a simple proxy in the RPI and public signaling server. This worked very well using App DirectSocket indicating the IP of my server. I could see the candidatod host and srflx being switched and the P2P connection occurred perfectly.

I then decided to test the video performance through the TURN (origin of this question). I put the RPI behind a proxy / nat that prevents it prevents P2P being required to use TURN. I set it up and tested it with the binary provided by #66 It did not work for me, maybe still some of my problem.

I returned to the previous state with the configuration and the binary, but now I am no longer successful through 4G as I had obtained with my signaling server, only on the local network. The message that appears is "ICE connection failed"

I know there is not much information for you to help me, I am redoing all the steps and trying to find answers or some more specific question

kclyu commented 5 years ago

To answer this I have to re-review the AppRTCMobile source code altogether again. And, I remember that DirectSocket did not have a settings to specify a STUN/TURN server, If I remember correctly. I think you need to check yourself to see if you can specify a Turn server setting of DirectSocket.

The AppRTC service uses iceServers configurations directly from the AppRTC server. And, since DirectSocket is used for the local network, it seems to be implemented without any special ICE server setting.

leofds commented 5 years ago

It had worked with the app you provide, but I also compiled the project, in the source code it is possible to specify the STUN / TURN server. I could see it working.

leofds commented 5 years ago

In the class DirectRTCClient.java on method public void onTCPMessage(String msg)

SignalingParameters parameters = new SignalingParameters(
            // Ice servers are not needed for direct connections.
            new ArrayList<>(),
            false, // This code will only be run on the client side. So, we are not the initiator.
            null, // clientId
            null, // wssUrl
            null, // wssPostUrl
            sdp, // offerSdp
            null // iceCandidates
            );

The empty arraylist must be replaced...

List<PeerConnection.IceServer> turnServers = new ArrayList<>();
PeerConnection.IceServer stun = PeerConnection.IceServer.builder("stun:stun.myserver.com.br:3478?transport=udp").setUsername("").setPassword("").createIceServer();
PeerConnection.IceServer turn = PeerConnection.IceServer.builder("turn:turn.myserver.com.br:3478?transport=udp").setUsername("******").setPassword("*****").createIceServer();
turnServers.add(stun);
turnServers.add(turn);
SignalingParameters parameters = new SignalingParameters(
                            // Ice servers are not needed for direct connections.
                            turnServers,
                            false, // This code will only be run on the client side. So, we are not the initiator.
                            null, // clientId
                            null, // wssUrl
                            null, // wssPostUrl
                            sdp, // offerSdp
                            null // iceCandidates
                    );
leofds commented 5 years ago

Leaving the APPRTCMobile out.

I made a test using the web-app copying web-root/native-peerconnection to my public web server. I just changed the URL in websocket_url to my already mentioned signaling server.

Success, worked through the browsing of my smartphone on the 4G connection. The RPI sent host and srflx candidates to the browser but the browser sent only host candidates. It was enough to work, but should not the browser have also sent srflx candidates?

Another detail I noticed (measured by @uCibar) using my cell phone with 4G hotspot, connecting to it with my laptop occurs ICE connection state failed, but in the mobile browser works. I may be wrong but I believe this is because WebRTC without TURN can not establish the P2P connection with two levels of NAT. My mobile service provider must have a NAT because the IP of my smartphone is not the same verified by myip.com and the hotspot creates another network with NAT.

I have not yet found an explanation of why AppRTCMobile in DirectSocket no longer works using the same signaling server. My goal is to have an application that works with the project. I'll keep trying to make it work.

leofds commented 5 years ago

I made a remote access to my laptop at home to access the web page that worked by the smartphone browser on the 4G, but on the laptop at home did not work. This time I could see a srflx candidate being sent by the browser.

The logs in RWS stop here:

(app_ws_client.cc:213): OnMessage(13)
(app_ws_client.cc:231): JSON Parsing Success: {"cmd":"send","msg":"{\"type\":\"candidate\",\"label\":0,\"id\":\"0\",\"candidate\":\"candidate:842163049 1 udp 1677729535 191.248.105.85 58813 typ srflx raddr 192.168.1.7 rport 58813 generation 0 ufrag lWvR network-cost 999\"}","error":""}
(streamer_observer.cc:101): MessageFromPeer
(streamer_observer.cc:271): MessageFromPeer
(streamer.cc:386): Unknown SDP type: candidate
(mmal_wrapper.cc:541): Starting component connection stage
(mmal_wrapper.cc:567): Connecting camera stills port to encoder input port
(mmal_wrapper.cc:585): Enabling encoder output port
(mmal_wrapper.cc:885): capture started.
(raspi_encoder_impl.cc:195): MMAL encoder drain thread initialized.
(mmal_wrapper.cc:330): EncoderDelay Status changed from WAIT to PASS

I noticed that Unknown SDP type: candidate occurs also in the call that I succeeded in the previous test

kclyu commented 5 years ago

Please show the "./webrtc-streamer --version" information.

The contents of the log you sent seem to use the binary that was built long ago. Please use binaries built with the latest source code.

leofds commented 5 years ago
RWS Version: v0.73-56-gb5b773a4ad6aa9372ca6a4767e0574ae
RWS (rpi-webrtc-streamer) is a WebRTC H.264 streamer designed to run on Raspberry PI
and Raspberry PI camera board hardware.
(Using WebRTC native package: 26451933c1f41b4870d41ed92222cf3e,Cr-Commit-Position:refs/heads/master@{#26800})

I'm having trouble compiling the latest version, I'm going to open a new topic soon about it.

kclyu commented 5 years ago

The current master is 'RWS Version: v0.73-73-g2978361ce391cce3c4693f38ecacd372-dirty'.

The binary you are testing supports turn server config, but it is a version with a singlaing issue. Did you compile it yourself? About v.073-65 there was a patch for signaling messages. Please use the latest binary.

kclyu commented 5 years ago

The compilation problem seems to be the problem with the custom compiled gcc version. Please use gcc-linaro-6.4.1-2018.10-x86_64_arm-linux-gnueabihf.tar.xz

leofds commented 5 years ago

I was having problems with compilation, deleting everything and did it again. Compiled successfully.

RWS Version: v0.73-74-g7171e8c88bfc3bc317a74ba11a68b948
RWS (rpi-webrtc-streamer) is a WebRTC H.264 streamer designed to run on Raspberry PI
and Raspberry PI camera board hardware.
(Using WebRTC native package: a7d8f19a7713c7866fed08e8e758664e,Cr-Commit-Position:refs/heads/master@{#27373})

Now it worked through my laptop on another distant network and on my smartphone on the 4G.

The TURN still did not work, I tested connecting the laptop to the 4G hotspot. I'm using numb turn server.

webrtc_streamer.conf:

ice_transports_type=relay
ice_server_urls_0=turn:numb.viagenie.ca:3478?transport=udp
ice_server_username_0=****
ice_server_password_0=****

perrconnection_client.js:

this.pcConfig_ = {"iceServers": [
{"urls": "stun:numb.viagenie.ca:3478"},
{"urls": "turn:numb.viagenie.ca:3478?transport=udp", "username": "****", "credential": "****"}
]};

I could see the relay ice candidates being sent:

RWS to Web:

(streamer.cc:542): Sending Message to Peer: {
   "candidate" : "candidate:1430845056 1 udp 41887999 2607:5300:201:3100::6a8f 64434 typ relay raddr :: rport 0 generation 0 ufrag ByxJ network-id 2",
   "id" : "0",
   "label" : 0,
   "type" : "candidate"
}
(streamer.cc:542): Sending Message to Peer: {
   "candidate" : "candidate:453802058 1 udp 41819903 158.69.221.198 59096 typ relay raddr 0.0.0.0 rport 0 generation 0 ufrag ByxJ network-id 1",
   "id" : "0",
   "label" : 0,
   "type" : "candidate"
}

Web to RWS:

{"type":"candidate","label":0,"id":"0","candidate":"candidate:556027248 1 udp 2113937151 
192.168.42.152 62635 typ host generation 0 ufrag 6l0W network-cost 999"}
kclyu commented 5 years ago

In my opinion, the signaling server you are using does not exchange signaling messages well.

Candidate messages must be shared among peers. What you create in peer A (Web) must be passed to peer B (RWS), and what is generated in peer B must be passed to peer A. I do not know whether the candidate message was correctly delivered to the signaling server and each peer.

Please check whether the candidate messages are shared correctly between peers and ice server configuration should use the same as the Web and RWS.

And, IP address and other turn credential information is sensitive information, so it would be better not to post it on the issue.

leofds commented 5 years ago

I'm watching the RWS log and web console, I can see the SDP offer, answer and candidates being exchanged between them. I'll take a closer look at this. Yes, I am using the same ICE server.

if I set ice_transports_type=relay the relay candidate sent by RWS is raddr 0.0.0.0 rport 0. But if I comment this ip and port are not zero. Is this behavior correct?

leofds commented 5 years ago

How do you test the TURN ?

kclyu commented 5 years ago

Only one TURN server config is set to RWS and client certification is used for authorization. my mobile will load the peerconnection or np2 page directly from the mobile wireless network. it means i am using current websocket signaling without modification. When the TURN connection is established, monitor traffic to and from the TURN server and monitor the CPU usage of TURN server.

My RWS configuration

ice_server_urls_0=turn:xxx.xxx.xxx.xxx:3478?transport=udp
ice_server_username_0=xxxx
ice_server_password_0=xxxx
leofds commented 5 years ago

I did not understand how you directly use the websocket signaling server without opening ports on the modem for example.

Maybe I missed something when I read your files, can you clarify me better?

kclyu commented 5 years ago

Yes, that's right. One is a local network and the other is a mobile network.

As you can see, issue posting is being talked like chat. I will delete some chat messages to manage issues. Raising an issue here brings messages to all monitored people. It would be better to reduce the message if possible.

leofds commented 5 years ago

Maybe I did not ask the question well. I know the connection occurs by websocket, and that it starts from mobile phone browser to RWS. But if I try to do this without configuring the modem the connection is not allowed without port redirection or DMZ.

My question is how do you do this without changing the modem configuration?

I also did not understand the part of client certification for authorization!

I'm new to github and apologize for the various messages.

kclyu commented 5 years ago

The local network with rws is opened externally only the https port, and the mobile or other device will connect to the RWS via nginx's `reverse proxy''.

If you googling nginx reverse proxy and client certificate, you will find a lot of information.

leofds commented 5 years ago

Thanks @kclyu, the turn worked.

My biggest problems are related to ICE candidates, depending on the mobile phone network or the network where the RPI is connected, the relay candidates were not being generated.

But in the cases that they were generated there was success in the connection by TURN, both by the web page of the project and by the AppRTCMobile. However in some cases the connection was terminated unexpectedly.

leofds commented 5 years ago

Can I use multiple different TURN servers as well as STUN? I know this does not depend on your project but rather on the behavior of WebRTC, but what you tell me about it.

kclyu commented 5 years ago

The '?' Stands for config id. 0 ~ 9 can be used.

ice_server_urls_?=turn:turn.myserver.com.br:3478
ice_server_username_?=***
ice_server_password_?=***
ice_server_hostname_?=turn.myserver.com.br
leofds commented 5 years ago

On the configuration file I understood, I am not referring to the configuration but to the operation of WebRTC. For example using 8 different TURN servers in different locations can make the connection difficult? Having only one TURN can be better ? I ask based on your experience, if you have already done any testing on this.

kclyu commented 5 years ago

The question now has nothing to do with this issue. If you have any questions about WebRTC Architecture, it would be better to look up the WebRTC Service Architecture or WebRTC Media server.