你能告诉我在Go代码中使用WebSocket时哪个WebRTC出错了吗?

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

Can you tell me which webrtc is wrong using websocket in the Go code?

问题

我在进行一个简单的webrtc项目时遇到了以下错误。我应该如何处理它?我将一起参考前端和后端代码。

这是错误信息:

处理答案时出错:DOMException: 在 'RTCPeerConnection' 上执行 'setRemoteDescription' 失败:无法设置远程答案 sdp:在错误的状态下调用:stable

前端代码:

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <title>WebRTC示例</title>
  5. </head>
  6. <body>
  7. <h1>WebRTC示例</h1>
  8. <video id="localVideo" autoplay></video>
  9. <video id="remoteVideo" autoplay></video>
  10. <script>
  11. const ws = new WebSocket('ws://localhost:8080/ws');
  12. const localVideo = document.getElementById('localVideo');
  13. const remoteVideo = document.getElementById('remoteVideo');
  14. navigator.mediaDevices.getUserMedia({ video: true, audio: true })
  15. .then(stream => {
  16. localVideo.srcObject = stream;
  17. const pc = new RTCPeerConnection();
  18. // 将本地流添加到RTCPeerConnection对象
  19. stream.getTracks().forEach(track => {
  20. pc.addTrack(track, stream);
  21. });
  22. // 处理由其他对等方发送的ICE候选项
  23. ws.addEventListener('message', async (event) => {
  24. let message = event.data;
  25. if (typeof message === 'string') {
  26. message = JSON.parse(message);
  27. } else if (message instanceof Blob) {
  28. message = await message.text();
  29. message = JSON.parse(message);
  30. }
  31. if (message.type === 'candidate') {
  32. try {
  33. await pc.addIceCandidate(message.candidate);
  34. } catch (error) {
  35. console.error('添加ICE候选项时出错:', error);
  36. }
  37. } else if (message.type === 'offer') {
  38. try {
  39. await pc.setRemoteDescription(new RTCSessionDescription(message));
  40. const answer = await pc.createAnswer();
  41. await pc.setLocalDescription(answer);
  42. ws.send(JSON.stringify({
  43. type: 'answer',
  44. sdp: pc.localDescription.sdp
  45. }));
  46. } catch (error) {
  47. console.error('处理offer时出错:', error);
  48. }
  49. } else if (message.type === 'answer') {
  50. try {
  51. await pc.setRemoteDescription(new RTCSessionDescription(message));
  52. } catch (error) {
  53. console.error('处理答案时出错:', error);
  54. }
  55. }
  56. });
  57. // 将ICE候选项发送给其他对等方
  58. pc.addEventListener('icecandidate', (event) => {
  59. if (event.candidate) {
  60. ws.send(JSON.stringify({
  61. type: 'candidate',
  62. candidate: event.candidate,
  63. }));
  64. }
  65. });
  66. // 当可用时显示远程视频流
  67. pc.addEventListener('track', (event) => {
  68. remoteVideo.srcObject = event.streams[0];
  69. });
  70. // 创建offer并将其发送给其他对等方
  71. pc.createOffer()
  72. .then(offer => {
  73. pc.setLocalDescription(offer);
  74. ws.send(JSON.stringify({
  75. type: 'offer',
  76. sdp: pc.localDescription.sdp
  77. }));
  78. })
  79. .catch(error => {
  80. console.error('创建offer时出错:', error);
  81. });
  82. })
  83. .catch(error => {
  84. console.error('获取用户媒体时出错:', error);
  85. });
  86. </script>
  87. </body>
  88. </html>

后端代码:

  1. package main
  2. import (
  3. "github.com/gin-gonic/gin"
  4. "github.com/gorilla/websocket"
  5. "log"
  6. "net/http"
  7. )
  8. func main() {
  9. r := gin.Default()
  10. r.LoadHTMLFiles("index.html")
  11. r.GET("/", func(c *gin.Context) {
  12. c.HTML(200, "index.html", nil)
  13. })
  14. r.GET("/ws", func(c *gin.Context) {
  15. echo(c.Writer, c.Request)
  16. })
  17. r.Run(":8080")
  18. }
  19. var upgrader = websocket.Upgrader{} // 使用默认选项
  20. func echo(w http.ResponseWriter, r *http.Request) {
  21. c, err := upgrader.Upgrade(w, r, nil)
  22. if err != nil {
  23. log.Print("升级错误:", err)
  24. return
  25. }
  26. defer c.Close()
  27. for {
  28. mt, message, err := c.ReadMessage()
  29. if err != nil {
  30. log.Println("读取错误:", err)
  31. break
  32. }
  33. log.Printf("接收到消息:%s", message)
  34. err = c.WriteMessage(mt, message)
  35. if err != nil {
  36. log.Println("写入错误:", err)
  37. break
  38. }
  39. }
  40. }

我尝试在JavaScript中更改顺序,去掉了"await",但没有成功。我将后端更改为Node.js并进行了处理,没有出现任何错误,所以我认为后端部分可能存在问题,但我不确定。

英文:

I encountered the following error while working on a simple webrtc project. How should I deal with it? I'll refer to the front and back end codes together.

This is error Message:

> Error handling answer: DOMException: Failed to execute
> 'setRemoteDescription' on 'RTCPeerConnection': Failed to set remote
> answer sdp: Called in wrong state: stable

Frontend code:

  1. &lt;!DOCTYPE html&gt;
  2. &lt;html&gt;
  3. &lt;head&gt;
  4. &lt;title&gt;WebRTC Example&lt;/title&gt;
  5. &lt;/head&gt;
  6. &lt;body&gt;
  7. &lt;h1&gt;WebRTC Example&lt;/h1&gt;
  8. &lt;video id=&quot;localVideo&quot; autoplay&gt;&lt;/video&gt;
  9. &lt;video id=&quot;remoteVideo&quot; autoplay&gt;&lt;/video&gt;
  10. &lt;script&gt;
  11. const ws = new WebSocket(&#39;ws://localhost:8080/ws&#39;);
  12. const localVideo = document.getElementById(&#39;localVideo&#39;);
  13. const remoteVideo = document.getElementById(&#39;remoteVideo&#39;);
  14. navigator.mediaDevices.getUserMedia({ video: true, audio: true })
  15. .then(stream =&gt; {
  16. localVideo.srcObject = stream;
  17. const pc = new RTCPeerConnection();
  18. // Add local stream to RTCPeerConnection object
  19. stream.getTracks().forEach(track =&gt; {
  20. pc.addTrack(track, stream);
  21. });
  22. // Handle ICE candidates sent by the other peer
  23. ws.addEventListener(&#39;message&#39;, async (event) =&gt; {
  24. let message = event.data;
  25. if (typeof message === &#39;string&#39;) {
  26. message = JSON.parse(message);
  27. } else if (message instanceof Blob) {
  28. message = await message.text();
  29. message = JSON.parse(message);
  30. }
  31. if (message.type === &#39;candidate&#39;) {
  32. try {
  33. await pc.addIceCandidate(message.candidate);
  34. } catch (error) {
  35. console.error(&#39;Error adding ICE candidate:&#39;, error);
  36. }
  37. } else if (message.type === &#39;offer&#39;) {
  38. try {
  39. await pc.setRemoteDescription(new RTCSessionDescription(message));
  40. const answer = await pc.createAnswer();
  41. await pc.setLocalDescription(answer);
  42. ws.send(JSON.stringify({
  43. type: &#39;answer&#39;,
  44. sdp: pc.localDescription.sdp
  45. }));
  46. } catch (error) {
  47. console.error(&#39;Error handling offer:&#39;, error);
  48. }
  49. } else if (message.type === &#39;answer&#39;) {
  50. try {
  51. await pc.setRemoteDescription(new RTCSessionDescription(message));
  52. } catch (error) {
  53. console.error(&#39;Error handling answer:&#39;, error);
  54. }
  55. }
  56. });
  57. // Send ICE candidates to the other peer
  58. pc.addEventListener(&#39;icecandidate&#39;, (event) =&gt; {
  59. if (event.candidate) {
  60. ws.send(JSON.stringify({
  61. type: &#39;candidate&#39;,
  62. candidate: event.candidate,
  63. }));
  64. }
  65. });
  66. // Display remote video stream when available
  67. pc.addEventListener(&#39;track&#39;, (event) =&gt; {
  68. remoteVideo.srcObject = event.streams[0];
  69. });
  70. // Create offer and send it to the other peer
  71. pc.createOffer()
  72. .then(offer =&gt; {
  73. pc.setLocalDescription(offer);
  74. ws.send(JSON.stringify({
  75. type: &#39;offer&#39;,
  76. sdp: pc.localDescription.sdp
  77. }));
  78. })
  79. .catch(error =&gt; {
  80. console.error(&#39;Error creating offer:&#39;, error);
  81. });
  82. })
  83. .catch(error =&gt; {
  84. console.error(&#39;Error getting user media:&#39;, error);
  85. });
  86. &lt;/script&gt;
  87. &lt;/body&gt;
  88. &lt;/html&gt;

Backend code:

  1. package main
  2. import (
  3. &quot;github.com/gin-gonic/gin&quot;
  4. &quot;github.com/gorilla/websocket&quot;
  5. &quot;log&quot;
  6. &quot;net/http&quot;
  7. )
  8. func main() {
  9. r := gin.Default()
  10. r.LoadHTMLFiles(&quot;index.html&quot;)
  11. r.GET(&quot;/&quot;, func(c *gin.Context) {
  12. c.HTML(200, &quot;index.html&quot;, nil)
  13. })
  14. r.GET(&quot;/ws&quot;, func(c *gin.Context) {
  15. echo(c.Writer, c.Request)
  16. })
  17. r.Run(&quot;:8080&quot;)
  18. }
  19. var upgrader = websocket.Upgrader{} // use default options
  20. func echo(w http.ResponseWriter, r *http.Request) {
  21. c, err := upgrader.Upgrade(w, r, nil)
  22. if err != nil {
  23. log.Print(&quot;upgrade:&quot;, err)
  24. return
  25. }
  26. defer c.Close()
  27. for {
  28. mt, message, err := c.ReadMessage()
  29. if err != nil {
  30. log.Println(&quot;read:&quot;, err)
  31. break
  32. }
  33. log.Printf(&quot;recv: %s&quot;, message)
  34. err = c.WriteMessage(mt, message)
  35. if err != nil {
  36. log.Println(&quot;write:&quot;, err)
  37. break
  38. }
  39. }
  40. }

I tried to change the order without "await" in JavaScript, but it didn't work out. I changed the backend to Node.js and proceeded it, and it was handed over without any errors, so I think there will be a problem with the backend part, but I'm not sure.

答案1

得分: 1

这表明您正在尝试在已经设置了远程描述的连接上设置远程答案。基本上,您可能会遇到提供/答案的冲突,双方都在创建提供和答案。

基本上,您需要找到一种解决这些冲突的方法,以便在需要在两个 WebRTC 对等方之间建立连接时,一个对等方创建提供,另一个对等方创建答案。一种方法是让新加入会议的对等方创建提供。Mozilla 在这里详细说明了一个场景:https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API/Perfect_negotiation

英文:

To me, this indicates that you are trying to set a remote answer on a connection that already has a remote description set. Basically, you are likely getting a collision of offers/answers, where both sides are creating offers and answers.

Basically, you need a way to resolve these conflicts so that when you need to establish a connection between two webrtc peers, you will have one creating an offer and the other one creating an answer. One way of doing it is to let a new peer joining a conference create an offer. Mozilla has a detailed scenario spelled out here: https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API/Perfect_negotiation

答案2

得分: 0

我不是专家,但我可以尝试帮助你!
这可能是一个CORS问题,意味着你的前端和后端代码之间没有通信。
要解决这个问题,你可以使用github.com/gin-contrib/cors包,并添加以下代码:

  1. import (
  2. "github.com/gin-contrib/cors"
  3. "github.com/gin-gonic/gin"
  4. )
  5. func main() {
  6. r := gin.Default()
  7. r.Use(cors.Default())
  8. }

在尝试使用程序之前,使用"go get"命令安装它。就像我说的,我是新手,不太懂,但希望这可以帮到你!

英文:

I'm not an expert, but I can try to help you!
This could be a CORS issue, meaning that there is no communication between your front-end and back-end code.
To solve this problem, you can use the package github.com/gin-contrib/cors and add this code:

  1. import (
  2. &quot;github.com/gin-contrib/cors&quot;
  3. &quot;github.com/gin-gonic/gin&quot;
  4. )
  5. func main() {
  6. r := gin.Default()
  7. r.Use(cors.Default())
  8. }

Use the "go get" command to install it before trying to use your program. As I said, I'm new and don't understand much, but I hope this helps!

huangapple
  • 本文由 发表于 2023年3月7日 07:21:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/75656707.html
匿名

发表评论

匿名网友

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

确定