WebRTC ICE candidate 在 setRemoteDescription 后未生成。

huangapple go评论109阅读模式
英文:

WebRTC ICE candidate not generating after setRemoteDescription

问题

I see that you have provided a detailed log of SDP offers, answers, and ICE candidates in your WebRTC implementation. Based on the information you've provided, here are some answers to your questions:

  1. SDP Offer/Answer and ICE Candidates:

    • In the SDP you've shown, it includes both SDP (Session Description Protocol) information and ICE (Interactive Connectivity Establishment) candidate information. SDP is used for session negotiation (offer and answer), while ICE candidates are used for establishing the network connection.
    • When receiving SDP from another user, you should treat it as SDP for session negotiation. Use peerConnection.setRemoteDescription() to set the remote description with the received SDP.
    • ICE candidates should be gathered and exchanged separately. In WebRTC, ICE candidates are gathered as part of the connection setup process. These ICE candidates should be sent to the remote peer using your signaling channel (e.g., via WebSocket) so that both peers can exchange their ICE candidates. This helps establish the network connection by finding the best possible route.
  2. Handling ICE Candidates:

    • The onIceCandidate callback is called multiple times as ICE candidates are gathered. You should indeed send these ICE candidates to the remote peer through your signaling channel each time this callback is triggered. This allows both peers to exchange their candidates and establish a connection.
    • Keep in mind that ICE candidates can change dynamically as the network conditions change, so it's essential to keep sending them until the ICE negotiation process is complete.
  3. Initiating the Call:

    • After setting the remote description and exchanging ICE candidates, you can initiate the call by creating an SDP answer using peerConnection.createAnswer(). Once the answer is created, you can set it as the local description using peerConnection.setLocalDescription().
    • Send the answer SDP to the remote peer through your signaling channel, and they should set it as their remote description using peerConnection.setRemoteDescription().
    • Continue exchanging ICE candidates as needed until both peers have gathered enough candidates, and the ICE negotiation process is complete.

Remember that WebRTC communication involves bidirectional communication of SDP offers, answers, and ICE candidates between both peers. Proper synchronization and handling of these components are crucial for a successful WebRTC call setup.

英文:

I am trying to setup WebRTC ( implementation 'org.webrtc:google-webrtc:1.0.32006' )for video and voice call. I can see the exchange of SDP via websocket by creating offer then receive the answer from other user. However, after successfully receiving SDP answer from user, I save it via peerConnection.setRemoteDescription().

  1. SessionDescription sessionDescription = new SessionDescription(SessionDescription.Type.ANSWER,sdp_ice_VALUE);
  2. peerConnection.setRemoteDescription(new SdpObserver() {
  3. @Override
  4. public void onCreateSuccess(SessionDescription sessionDescription) {
  5. Log.d(TAG, "onCreateSuccess: ");
  6. }
  7. @Override
  8. public void onSetSuccess() {
  9. Log.d(TAG, "onSetSuccess: ");
  10. }
  11. @Override
  12. public void onCreateFailure(String s) {
  13. Log.d(TAG, "onCreateFailure: ");
  14. }
  15. @Override
  16. public void onSetFailure(String s) {
  17. Log.d(TAG, "onSetFailure: ");
  18. }}, sessionDescription);

I can see the onSetSuccess call in logcat, which means the remote description is set successfully. However, ICE candidate is not generating.

I have checked the code several times and I can't find any obvious errors. Could anyone help me to debug this issue?

Here is the complete code/fragment

  1. public class Video_Voice_Call_Fragment extends Fragment {
  2. @Override
  3. public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
  4. super.onViewCreated(view, savedInstanceState);
  5. greenCallButton = view.findViewById(R.id.call_connect);
  6. redCallButton = view.findViewById(R.id.call_disconnect);
  7. initializeWebRTC();
  8. startCall();
  9. }
  10. private void initializeWebRTC() {
  11. rootEglBase = EglBase.create();
  12. // Initialize PeerConnectionFactory
  13. PeerConnectionFactory.initialize(PeerConnectionFactory.InitializationOptions.builder(requireContext())
  14. .setEnableInternalTracer(true)
  15. .createInitializationOptions());
  16. DefaultVideoEncoderFactory videoEncoderFactory = new DefaultVideoEncoderFactory(rootEglBase.getEglBaseContext(),true,true);
  17. DefaultVideoDecoderFactory videoDecoderFactory = new DefaultVideoDecoderFactory(rootEglBase.getEglBaseContext());
  18. PeerConnectionFactory.Options options = new PeerConnectionFactory.Options();
  19. peerConnectionFactory = PeerConnectionFactory.builder()
  20. .setVideoDecoderFactory(videoDecoderFactory)
  21. .setVideoEncoderFactory(videoEncoderFactory)
  22. .setOptions(options)
  23. .createPeerConnectionFactory();
  24. }
  25. private void startCall() {
  26. // Create an offer and set local description
  27. peerConnection = generateICE();
  28. peerConnection.createOffer(new SimpleSdpObserver() {
  29. @Override
  30. public void onCreateSuccess(SessionDescription sessionDescription) {
  31. Log.d(TAG, "onCreateSuccess: " + sessionDescription.description);
  32. peerConnection.setLocalDescription(new SimpleSdpObserver(), sessionDescription);
  33. Websocket.connectWebSocket(new WebSocketCallback() {
  34. @Override
  35. public void onConnectionSuccess() {
  36. //Websocket Connected
  37. Log.d(TAG, "onConnectionSuccess: Websocket Connected");
  38. String message = generateJSON(sessionDescription.description,true,"offer");
  39. Websocket.sendMessage(message);
  40. }
  41. @Override
  42. public void onConnectionFailure(String message) {
  43. Log.d(TAG, "onConnectionFailure: Message = "+message);
  44. }
  45. @Override
  46. public void onConnectionClosed(String reason) {
  47. Log.d(TAG, "onConnectionClosed: Reason = "+reason);
  48. }
  49. @Override
  50. public void onConnectionsMessage(String message) {
  51. Log.d(TAG, "onConnectionsMessage: Message = "+message);
  52. // Here User will receive the message from the websocket
  53. try{
  54. JSONObject socketMessage = new JSONObject(message);
  55. String type = socketMessage.getString("type");
  56. String sdp_ice_VALUE = socketMessage.getString("SDP_ICE_info");
  57. if (type.equals("SDP")){
  58. Log.d(TAG, "onConnectionsMessage: Type SDP");
  59. SessionDescription sessionDescription = new SessionDescription(SessionDescription.Type.ANSWER,sdp_ice_VALUE);
  60. peerConnection.setRemoteDescription(new SdpObserver() {
  61. @Override
  62. public void onCreateSuccess(SessionDescription sessionDescription) {
  63. Log.d(TAG, "onCreateSuccess: ");
  64. }
  65. @Override
  66. public void onSetSuccess() {
  67. Log.d(TAG, "onSetSuccess: ");
  68. }
  69. @Override
  70. public void onCreateFailure(String s) {
  71. Log.d(TAG, "onCreateFailure: ");
  72. }
  73. @Override
  74. public void onSetFailure(String s) {
  75. Log.d(TAG, "onSetFailure: ");
  76. }
  77. }, sessionDescription);
  78. }else {
  79. // Received ICE from server as answer, This is the last step in exchanging info
  80. WebRTCUtils.addIceCandidate(peerConnection,sdp_ice_VALUE);
  81. }
  82. }catch (JSONException e){
  83. Log.d(TAG, "onMessage: Error "+e.getMessage());
  84. }
  85. }
  86. });
  87. // Send the offer to the remote peer
  88. // Example code for sending the offer
  89. }
  90. @Override
  91. public void onCreateFailure(String s) {
  92. Log.e(TAG, "onCreateFailure: " + s);
  93. }
  94. }, new MediaConstraints());
  95. }
  96. private PeerConnection generateICE (){
  97. Log.d(TAG, "generateICE: ");
  98. ArrayList<PeerConnection.IceServer> iceServers = new ArrayList<>();
  99. List<String> STUNList= Arrays.asList(
  100. "stun:stun.l.google.com:19302",
  101. "stun:stun1.l.google.com:19302",
  102. "stun:stun2.l.google.com:19302",
  103. "stun:stun3.l.google.com:19302",
  104. "stun:stun4.l.google.com:19302",
  105. "stun:stun.vodafone.ro:3478",
  106. "stun:stun.samsungsmartcam.com:3478",
  107. "stun:stun.services.mozilla.com:3478"
  108. );
  109. for(String i:STUNList){
  110. PeerConnection.IceServer.Builder iceServerBuilder = PeerConnection.IceServer.builder(i);
  111. iceServerBuilder.setTlsCertPolicy(PeerConnection.TlsCertPolicy.TLS_CERT_POLICY_INSECURE_NO_CHECK); //this does the magic.
  112. PeerConnection.IceServer iceServer = iceServerBuilder.createIceServer();
  113. iceServers.add(iceServer);
  114. }
  115. PeerConnection.RTCConfiguration rtcConfig = new PeerConnection.RTCConfiguration(iceServers);
  116. PeerConnection.Observer observer = new PeerConnection.Observer() {
  117. @Override
  118. public void onSignalingChange(PeerConnection.SignalingState signalingState) {
  119. Log.d(TAG, "onSignalingChange: "+signalingState);
  120. }
  121. @Override
  122. public void onIceConnectionChange(PeerConnection.IceConnectionState iceConnectionState) {
  123. Log.d(TAG, "onIceConnectionChange: "+iceConnectionState);
  124. }
  125. @Override
  126. public void onIceConnectionReceivingChange(boolean b) {
  127. Log.d(TAG, "onIceConnectionReceivingChange: Boolean = "+b);
  128. }
  129. @Override
  130. public void onIceGatheringChange(PeerConnection.IceGatheringState iceGatheringState) {
  131. Log.d(TAG, "onIceGatheringChange: "+iceGatheringState);
  132. }
  133. @Override
  134. public void onIceCandidate(IceCandidate iceCandidate) {
  135. Log.d(TAG, "onIceCandidate: "+iceCandidate);
  136. }
  137. @Override
  138. public void onIceCandidatesRemoved(IceCandidate[] iceCandidates) {
  139. Log.d(TAG, "onIceCandidatesRemoved: "+iceCandidates);
  140. }
  141. @Override
  142. public void onAddStream(MediaStream mediaStream) {
  143. Log.d(TAG, "onAddStream: "+mediaStream);
  144. }
  145. @Override
  146. public void onRemoveStream(MediaStream mediaStream) {
  147. Log.d(TAG, "onRemoveStream: "+mediaStream);
  148. }
  149. @Override
  150. public void onDataChannel(DataChannel dataChannel) {
  151. Log.d(TAG, "onDataChannel: "+dataChannel);
  152. }
  153. @Override
  154. public void onRenegotiationNeeded() {
  155. Log.d(TAG, "onRenegotiationNeeded: ");
  156. }
  157. @Override
  158. public void onAddTrack(RtpReceiver rtpReceiver, MediaStream[] mediaStreams) {
  159. Log.d(TAG, "onAddTrack: "+rtpReceiver+"--- "+mediaStreams);
  160. }
  161. };
  162. Log.d(TAG, "generateICE: ");
  163. return peerConnectionFactory.createPeerConnection(rtcConfig,observer);
  164. }
  165. }

Update:- With the suggestions from @PhilippHancke. I edit my code:-

  1. private void setupLocalTracks() {
  2. // Create video capturer
  3. videoCapturer = createVideoCapturer();
  4. // Create video source
  5. videoSource = peerConnectionFactory.createVideoSource(false);
  6. localVideoTrack = peerConnectionFactory.createVideoTrack("local_video", videoSource);
  7. // Create audio source and track
  8. AudioSource audioSource = peerConnectionFactory.createAudioSource(new MediaConstraints());
  9. localAudioTrack = peerConnectionFactory.createAudioTrack("local_audio", audioSource);
  10. // Create local media stream
  11. localMediaStream = peerConnectionFactory.createLocalMediaStream("local_stream");
  12. localMediaStream.addTrack(localVideoTrack);
  13. localMediaStream.addTrack(localAudioTrack);
  14. peerConnection.addStream(localMediaStream);
  15. }

Now i can see much more details in log which has SDP offer/answer and ice too.I first call peerConnection.createOffer(new SimpleSdpObserver()which generate SessionDescription for User ID 4.

  1. Message Received From User ID == 4 Message = v=0
  2. o=- 5794866635417549132 2 IN IP4 127.0.0.1
  3. s=-
  4. t=0 0
  5. a=group:BUNDLE audio video
  6. a=msid-semantic: WMS local_stream
  7. m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 102 0 8 106 105 13 110 112 113 126
  8. c=IN IP4 0.0.0.0
  9. a=rtcp:9 IN IP4 0.0.0.0
  10. a=ice-ufrag:EXXZ
  11. a=ice-pwd:NuOsEt2YVDiZkxFomvHPhUW+
  12. a=ice-options:trickle renomination
  13. a=fingerprint:sha-256 F2:1E:77:5D:21:00:15:65:00:CA:24:BE:65:66:95:09:B4:10:4C:80:C0:16:90:4A:22:E7:ED:BA:D4:A8:F5:56
  14. a=setup:actpass
  15. a=mid:audio
  16. a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
  17. a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
  18. a=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
  19. a=sendrecv
  20. a=rtcp-mux
  21. a=rtpmap:111 opus/48000/2
  22. a=rtcp-fb:111 transport-cc
  23. a=fmtp:111 minptime=10;useinbandfec=1
  24. a=rtpmap:103 ISAC/16000
  25. a=rtpmap:104 ISAC/32000
  26. a=rtpmap:9 G722/8000
  27. a=rtpmap:102 ILBC/8000
  28. a=rtpmap:0 PCMU/8000
  29. a=rtpmap:8 PCMA/8000
  30. a=rtpmap:106 CN/32000
  31. a=rtpmap:105 CN/16000
  32. a=rtpmap:13 CN/8000
  33. a=rtpmap:110 telephone-event/48000
  34. a=rtpmap:112 telephone-event/32000
  35. a=rtpmap:113 telephone-event/16000
  36. a=rtpmap:126 telephone-event/8000
  37. a=ssrc:473446091 cname:WQlLPNcKBxol0kL2
  38. a=ssrc:473446091 msid:local_stream local_audio
  39. a=ssrc:473446091 mslabel:local_stream
  40. a=ssrc:473446091 label:local_audio
  41. m=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 127 123 125
  42. c=IN IP4 0.0.0.0
  43. a=rtcp:9 IN IP4 0.0.0.0
  44. a=ice-ufrag:EXXZ
  45. a=ice-pwd:NuOsEt2YVDiZkxFomvHPhUW+
  46. a=ice-options:trickle renomination
  47. a=fingerprint:sha-256 F2:1E:77:5D:21:00:15:65:00:CA:24:BE:65:66:95:09:B4:10:4C:80:C0:16:90:4A:22:E7:ED:BA:D4:A8:F5:56
  48. a=setup:actpass
  49. a=mid:video
  50. a=extmap:14 urn:ietf:params:rtp-hdrext:toffset
  51. a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
  52. a=extmap:13 urn:3gpp:video-orientation
  53. a=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
  54. a=extmap:5 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay
  55. a=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type
  56. a=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-timing
  57. a=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/color-space
  58. a=sendrecv
  59. a=rtcp-mux
  60. a=rtcp-rsize
  61. a=rtpmap:96 VP8/90000
  62. a=rtcp-fb:96 goog-remb
  63. a=rtcp-fb:96 transport-cc
  64. a=rtcp-fb:96 ccm fir
  65. a=rtcp-fb:96 nack
  66. a=rtcp-fb:96 nack pli
  67. a=rtpmap:97 rtx/90000
  68. a=fmtp:97 apt=96
  69. a=rtpmap:98 VP9/90000
  70. a=rtcp-fb:98 goog-remb
  71. a=rtcp-fb:98 transport-cc
  72. a=rtcp-fb:98 ccm fir
  73. a=rtcp-fb:98 nack
  74. a=rtcp-fb:98 nack pli
  75. a=rtpmap:99 rtx/90000
  76. a=fmtp:99 apt=98
  77. a=rtpmap:100 H264/90000
  78. a=rtcp-fb:100 goog-remb
  79. a=rtcp-fb:100 transport-cc
  80. a=rtcp-fb:100 ccm fir
  81. a=rtcp-fb:100 nack
  82. a=rtcp-fb:100 nack pli
  83. a=fmtp:100 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f
  84. a=rtpmap:101 rtx/90000
  85. a=fmtp:101 apt=100
  86. a=rtpmap:127 red/90000
  87. a=rtpmap:123 rtx/90000
  88. a=fmtp:123 apt=127
  89. a=rtpmap:125 ulpfec/90000
  90. a=ssrc-group:FID 1370797121 3619002051
  91. a=ssrc:1370797121 cname:WQlLPNcKBxol0kL2
  92. a=ssrc:1370797121 msid:local_stream local_video
  93. a=ssrc:1370797121 mslabel:local_stream
  94. a=ssrc:1370797121 label:local_video
  95. a=ssrc:3619002051 cname:WQlLPNcKBxol0kL2
  96. a=ssrc:3619002051 msid:local_stream local_video
  97. a=ssrc:3619002051 mslabel:local_stream
  98. a=ssrc:3619002051 label:local_video
  99. Message Received From User ID == 206 Message = v=0
  100. o=- 3655990368999828607 2 IN IP4 127.0.0.1
  101. s=-
  102. t=0 0
  103. a=group:BUNDLE audio video
  104. a=msid-semantic: WMS remote_stream
  105. m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 102 0 8 106 105 13 110 112 113 126
  106. c=IN IP4 0.0.0.0
  107. a=rtcp:9 IN IP4 0.0.0.0
  108. a=ice-ufrag:0O57
  109. a=ice-pwd:FSyUVENoJglSvKVpeih/bzXA
  110. a=ice-options:trickle renomination
  111. a=fingerprint:sha-256 B8:43:6B:EE:38:08:19:85:DA:97:AA:45:2D:46:17:90:9E:8B:D2:D8:D7:9D:04:97:22:DE:C9:CB:FC:A1:DB:5B
  112. a=setup:active
  113. a=mid:audio
  114. a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
  115. a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
  116. a=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
  117. a=sendrecv
  118. a=rtcp-mux
  119. a=rtpmap:111 opus/48000/2
  120. a=rtcp-fb:111 transport-cc
  121. a=fmtp:111 minptime=10;useinbandfec=1
  122. a=rtpmap:103 ISAC/16000
  123. a=rtpmap:104 ISAC/32000
  124. a=rtpmap:9 G722/8000
  125. a=rtpmap:102 ILBC/8000
  126. a=rtpmap:0 PCMU/8000
  127. a=rtpmap:8 PCMA/8000
  128. a=rtpmap:106 CN/32000
  129. a=rtpmap:105 CN/16000
  130. a=rtpmap:13 CN/8000
  131. a=rtpmap:110 telephone-event/48000
  132. a=rtpmap:112 telephone-event/32000
  133. a=rtpmap:113 telephone-event/16000
  134. a=rtpmap:126 telephone-event/8000
  135. a=ssrc:624557633 cname:PYJF7YMAd+hgS7Zk
  136. a=ssrc:624557633 msid:remote_stream remote_audio
  137. a=ssrc:624557633 mslabel:remote_stream
  138. a=ssrc:624557633 label:remote_audio
  139. m=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 127 123 125
  140. c=IN IP4 0.0.0.0
  141. a=rtcp:9 IN IP4 0.0.0.0
  142. a=ice-ufrag:0O57
  143. a=ice-pwd:FSyUVENoJglSvKVpeih/bzXA
  144. a=ice-options:trickle renomination
  145. a=fingerprint:sha-256 B8:43:6B:EE:38:08:19:85:DA:97:AA:45:2D:46:17:90:9E:8B:D2:D8:D7:9D:04:97:22:DE:C9:CB:FC:A1:DB:5B
  146. a=setup:active
  147. a=mid:video
  148. a=extmap:14 urn:ietf:params:rtp-hdrext:toffset
  149. a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
  150. a=extmap:13 urn:3gpp:video-orientation
  151. a=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
  152. a=extmap:5 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay
  153. a=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type
  154. a=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-timing
  155. a=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/color-space
  156. a=sendrecv
  157. a=rtcp-mux
  158. a=rtcp-rsize
  159. a=rtpmap:96 VP8/90000
  160. a=rtcp-fb:96 goog-remb
  161. a=rtcp-fb:96 transport-cc
  162. a=rtcp-fb:96 ccm fir
  163. a=rtcp-fb:96 nack
  164. a=rtcp-fb:96 nack pli
  165. a=rtpmap:97 rtx/90000
  166. a=fmtp:97 apt=96
  167. a=rtpmap:98 VP9/90000
  168. a=rtcp-fb:98 goog-remb
  169. a=rtcp-fb:98 transport-cc
  170. a=rtcp-fb:98 ccm fir
  171. a=rtcp-fb:98 nack
  172. a=rtcp-fb:98 nack pli
  173. a=rtpmap:99 rtx/90000
  174. a=fmtp:99 apt=98
  175. a=rtpmap:100 H264/90000
  176. a=rtcp-fb:100 goog-remb
  177. a=rtcp-fb:100 transport-cc
  178. a=rtcp-fb:100 ccm fir
  179. a=rtcp-fb:100 nack
  180. a=rtcp-fb:100 nack pli
  181. a=fmtp:100 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f
  182. a=rtpmap:101 rtx/90000
  183. a=fmtp:101 apt=100
  184. a=rtpmap:127 red/90000
  185. a=rtpmap:123 rtx/90000
  186. a=fmtp:123 apt=127
  187. a=rtpmap:125 ulpfec/90000
  188. a=ssrc-group:FID 2171330257 4072720398
  189. a=ssrc:2171330257 cname:PYJF7YMAd+hgS7Zk
  190. a=ssrc:2171330257 msid:remote_stream remote_video
  191. a=ssrc:2171330257 mslabel:remote_stream
  192. a=ssrc:2171330257 label:remote_video
  193. a=ssrc:4072720398 cname:PYJF7YMAd+hgS7Zk
  194. a=ssrc:4072720398 msid:remote_stream remote_video
  195. a=ssrc:4072720398 mslabel:remote_stream
  196. a=ssrc:4072720398 label:remote_video

In the SDP above i can ICE candidates too which creates confusion for me because when other receive this SDP then how user would save it, as SDP (setRemoteDescription) or treat it as ICE candidates beucase it contains both.

Also i can see in log that onIceCandidate calls multiples times with these kinds of values

  1. audio:0:candidate:1587269880 1 udp 2122262783 2406:b400:52:820d:70e0:90ff:fe12:3352 35364 typ host generation 0 ufrag B/Tc network-id 4 network-cost 10::UNKNOWN
  2. audio:0:candidate:393917512 1 udp 2122194687 192.168.0.123 42552 typ host generation 0 ufrag B/Tc network-id 3 network-cost 10::UNKNOWN
  3. audio:0:candidate:559267639 1 udp 2122136831 ::1 50036 typ host generation 0 ufrag B/Tc network-id 2::UNKNOWN

Do i need to send these information to other user as ICE (it calls around 10 times approx) every time it calls onIceCandidate?

After these exchange which method should i call to initiate the call?

答案1

得分: 1

ICE candidates are only generated after you call setLocalDescription, see https://w3c.github.io/webrtc-pc/#set-the-session-description step 4 substep 2.

(please also note that org.webrtc:google-webrtc:1.0.32006 is an outdated version that has known security vulnerabilities)

英文:

ICE candidates are only generated after you call setLocalDescription, see https://w3c.github.io/webrtc-pc/#set-the-session-description step 4 substep 2.

(please also note that org.webrtc:google-webrtc:1.0.32006 is an outdated version that has known security vulnerabilities)

huangapple
  • 本文由 发表于 2023年6月26日 23:15:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/76558014.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定