英文:
Can you tell me which webrtc is wrong using websocket in the Go code?
问题
我在进行一个简单的webrtc项目时遇到了以下错误。我应该如何处理它?我将一起参考前端和后端代码。
这是错误信息:
处理答案时出错:DOMException: 在 'RTCPeerConnection' 上执行 'setRemoteDescription' 失败:无法设置远程答案 sdp:在错误的状态下调用:stable
前端代码:
<!DOCTYPE html>
<html>
<head>
<title>WebRTC示例</title>
</head>
<body>
<h1>WebRTC示例</h1>
<video id="localVideo" autoplay></video>
<video id="remoteVideo" autoplay></video>
<script>
const ws = new WebSocket('ws://localhost:8080/ws');
const localVideo = document.getElementById('localVideo');
const remoteVideo = document.getElementById('remoteVideo');
navigator.mediaDevices.getUserMedia({ video: true, audio: true })
.then(stream => {
localVideo.srcObject = stream;
const pc = new RTCPeerConnection();
// 将本地流添加到RTCPeerConnection对象
stream.getTracks().forEach(track => {
pc.addTrack(track, stream);
});
// 处理由其他对等方发送的ICE候选项
ws.addEventListener('message', async (event) => {
let message = event.data;
if (typeof message === 'string') {
message = JSON.parse(message);
} else if (message instanceof Blob) {
message = await message.text();
message = JSON.parse(message);
}
if (message.type === 'candidate') {
try {
await pc.addIceCandidate(message.candidate);
} catch (error) {
console.error('添加ICE候选项时出错:', error);
}
} else if (message.type === 'offer') {
try {
await pc.setRemoteDescription(new RTCSessionDescription(message));
const answer = await pc.createAnswer();
await pc.setLocalDescription(answer);
ws.send(JSON.stringify({
type: 'answer',
sdp: pc.localDescription.sdp
}));
} catch (error) {
console.error('处理offer时出错:', error);
}
} else if (message.type === 'answer') {
try {
await pc.setRemoteDescription(new RTCSessionDescription(message));
} catch (error) {
console.error('处理答案时出错:', error);
}
}
});
// 将ICE候选项发送给其他对等方
pc.addEventListener('icecandidate', (event) => {
if (event.candidate) {
ws.send(JSON.stringify({
type: 'candidate',
candidate: event.candidate,
}));
}
});
// 当可用时显示远程视频流
pc.addEventListener('track', (event) => {
remoteVideo.srcObject = event.streams[0];
});
// 创建offer并将其发送给其他对等方
pc.createOffer()
.then(offer => {
pc.setLocalDescription(offer);
ws.send(JSON.stringify({
type: 'offer',
sdp: pc.localDescription.sdp
}));
})
.catch(error => {
console.error('创建offer时出错:', error);
});
})
.catch(error => {
console.error('获取用户媒体时出错:', error);
});
</script>
</body>
</html>
后端代码:
package main
import (
"github.com/gin-gonic/gin"
"github.com/gorilla/websocket"
"log"
"net/http"
)
func main() {
r := gin.Default()
r.LoadHTMLFiles("index.html")
r.GET("/", func(c *gin.Context) {
c.HTML(200, "index.html", nil)
})
r.GET("/ws", func(c *gin.Context) {
echo(c.Writer, c.Request)
})
r.Run(":8080")
}
var upgrader = websocket.Upgrader{} // 使用默认选项
func echo(w http.ResponseWriter, r *http.Request) {
c, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Print("升级错误:", err)
return
}
defer c.Close()
for {
mt, message, err := c.ReadMessage()
if err != nil {
log.Println("读取错误:", err)
break
}
log.Printf("接收到消息:%s", message)
err = c.WriteMessage(mt, message)
if err != nil {
log.Println("写入错误:", err)
break
}
}
}
我尝试在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:
<!DOCTYPE html>
<html>
<head>
<title>WebRTC Example</title>
</head>
<body>
<h1>WebRTC Example</h1>
<video id="localVideo" autoplay></video>
<video id="remoteVideo" autoplay></video>
<script>
const ws = new WebSocket('ws://localhost:8080/ws');
const localVideo = document.getElementById('localVideo');
const remoteVideo = document.getElementById('remoteVideo');
navigator.mediaDevices.getUserMedia({ video: true, audio: true })
.then(stream => {
localVideo.srcObject = stream;
const pc = new RTCPeerConnection();
// Add local stream to RTCPeerConnection object
stream.getTracks().forEach(track => {
pc.addTrack(track, stream);
});
// Handle ICE candidates sent by the other peer
ws.addEventListener('message', async (event) => {
let message = event.data;
if (typeof message === 'string') {
message = JSON.parse(message);
} else if (message instanceof Blob) {
message = await message.text();
message = JSON.parse(message);
}
if (message.type === 'candidate') {
try {
await pc.addIceCandidate(message.candidate);
} catch (error) {
console.error('Error adding ICE candidate:', error);
}
} else if (message.type === 'offer') {
try {
await pc.setRemoteDescription(new RTCSessionDescription(message));
const answer = await pc.createAnswer();
await pc.setLocalDescription(answer);
ws.send(JSON.stringify({
type: 'answer',
sdp: pc.localDescription.sdp
}));
} catch (error) {
console.error('Error handling offer:', error);
}
} else if (message.type === 'answer') {
try {
await pc.setRemoteDescription(new RTCSessionDescription(message));
} catch (error) {
console.error('Error handling answer:', error);
}
}
});
// Send ICE candidates to the other peer
pc.addEventListener('icecandidate', (event) => {
if (event.candidate) {
ws.send(JSON.stringify({
type: 'candidate',
candidate: event.candidate,
}));
}
});
// Display remote video stream when available
pc.addEventListener('track', (event) => {
remoteVideo.srcObject = event.streams[0];
});
// Create offer and send it to the other peer
pc.createOffer()
.then(offer => {
pc.setLocalDescription(offer);
ws.send(JSON.stringify({
type: 'offer',
sdp: pc.localDescription.sdp
}));
})
.catch(error => {
console.error('Error creating offer:', error);
});
})
.catch(error => {
console.error('Error getting user media:', error);
});
</script>
</body>
</html>
Backend code:
package main
import (
"github.com/gin-gonic/gin"
"github.com/gorilla/websocket"
"log"
"net/http"
)
func main() {
r := gin.Default()
r.LoadHTMLFiles("index.html")
r.GET("/", func(c *gin.Context) {
c.HTML(200, "index.html", nil)
})
r.GET("/ws", func(c *gin.Context) {
echo(c.Writer, c.Request)
})
r.Run(":8080")
}
var upgrader = websocket.Upgrader{} // use default options
func echo(w http.ResponseWriter, r *http.Request) {
c, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Print("upgrade:", err)
return
}
defer c.Close()
for {
mt, message, err := c.ReadMessage()
if err != nil {
log.Println("read:", err)
break
}
log.Printf("recv: %s", message)
err = c.WriteMessage(mt, message)
if err != nil {
log.Println("write:", err)
break
}
}
}
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包,并添加以下代码:
import (
"github.com/gin-contrib/cors"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
r.Use(cors.Default())
}
在尝试使用程序之前,使用"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:
import (
"github.com/gin-contrib/cors"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
r.Use(cors.Default())
}
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!
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论