在 webrtc入门教学的第5章中, 5.websockets下传递sdp和ice,就是一个信令服务器,信令服务器的作用就是用来传输对方的sd
p和ice
。
apprtc
下的信令服务器collider
,做的也是这些事情,只不过apprtc
有房间号的需求,第一个用户需要先创建一个房间,把这个房间号发给对方,对方就能通过这个房间号来找到自己。
collider
虽然实现了很多形式的服务,https和wss,通常在信令服务器中用的是wss
因为需要互换信息。
func (c *Collider) wsHandler(ws *websocket.Conn) {
var rid, cid string
registered := false
var msg wsClientMsg
loop:
for {
err := ws.SetReadDeadline(time.Now().Add(time.Duration(wsReadTimeoutSec) * time.Second))
if err != nil {
c.wsError("ws.SetReadDeadline error: "+err.Error(), ws)
break
}
err = websocket.JSON.Receive(ws, &msg)
if err != nil {
if err.Error() != "EOF" {
c.wsError("websocket.JSON.Receive error: "+err.Error(), ws)
}
break
}
switch msg.Cmd {
//进入房间(不存在先创建)
case "register":
if registered {
c.wsError("Duplicated register request", ws)
break loop
}
if msg.RoomID == "" || msg.ClientID == "" {
c.wsError("Invalid register request: missing 'clientid' or 'roomid'", ws)
break loop
}
if err = c.roomTable.register(msg.RoomID, msg.ClientID, ws); err != nil {
c.wsError(err.Error(), ws)
break loop
}
registered, rid, cid = true, msg.RoomID, msg.ClientID
c.dash.incrWs()
defer c.roomTable.deregister(rid, cid)
break
case "send":
if !registered {
c.wsError("Client not registered", ws)
break loop
}
if msg.Msg == "" {
c.wsError("Invalid send request: missing 'msg'", ws)
break loop
}
c.roomTable.send(rid, cid, msg.Msg)
break
default:
c.wsError("Invalid message: unexpected 'cmd'", ws)
break
}
}
// This should be unnecessary but just be safe.
ws.Close()
}
在一个房间中,有一个用户列表,房间号。clients
用来厨房用户列表,当一个用户连接到信令服务器,如果他没有带房间号,那么就给他创建一个房间号,并成为里面的一员,如果用户进入信令服务器的时候带了一个房间号,会进入这个房间,并和这个房间的成员进行通讯。比较需要注意的是,collider
默认的房间最多人数是两个,const maxRoomCapacity = 2
。
type room struct {
parent *roomTable
id string
// A mapping from the client ID to the client object.
clients map[string]*client
registerTimeout time.Duration
roomSrvUrl string
}
第一个用户进来创建房间:
// roomLocked gets or creates the room without acquiring the lock. Used when the caller already acquired the lock.
func (rt *roomTable) roomLocked(id string) *room {
if r, ok := rt.rooms[id]; ok {
return r
}
rt.rooms[id] = newRoom(rt, id, rt.registerTimeout, rt.roomSrvUrl)
log.Printf("Created room %s", id)
return rt.rooms[id]
}
接着创建client
,
func (rm *room) client(clientID string) (*client, error) {
if c, ok := rm.clients[clientID]; ok {
return c, nil
}
if len(rm.clients) >= maxRoomCapacity {
log.Printf("Room %s is full, not adding client %s", rm.id, clientID)
return nil, errors.New("Max room capacity reached")
}
var timer *time.Timer
if rm.parent != nil {
timer = time.AfterFunc(rm.registerTimeout, func() {
if c := rm.clients[clientID]; c != nil {
rm.parent.removeIfUnregistered(rm.id, c)
}
})
}
rm.clients[clientID] = newClient(clientID, timer)
log.Printf("Added client %s to room %s", clientID, rm.id)
return rm.clients[clientID], nil
}
值得注意的是,一开始第一个用法发送的消息会先放在缓存中,等第二个用户来的时候,把信息发给第二个用户。
func (rm *room) register(clientID string, rwc io.ReadWriteCloser) error {
c, err := rm.client(clientID)
if err != nil {
return err
}
if err = c.register(rwc); err != nil {
return err
}
log.Printf("Client %s registered in room %s", clientID, rm.id)
// Sends the queued messages from the other client of the room.
if len(rm.clients) > 1 {
for _, otherClient := range rm.clients {
otherClient.sendQueued(c)
}
}
return nil
}
整个过程如log所示:
2022/05/13 01:49:40 Created room 902551569
2022/05/13 01:49:40 Added client 28470778 to room 902551569
2022/05/13 01:49:40 Client 28470778 registered in room 902551569
2022/05/13 01:49:48 Added client 19348598 to room 902551569
2022/05/13 01:49:48 Client 19348598 registered in room 902551569
2022/05/13 01:49:48 Sent queued messages from 28470778 to 19348598
这以后,房间里就存在两个用户,以后发的消息都是通过case "send":
的分支。
这样就完成了整个sdp
和ice
的交换过程了。一般就能够进行视频通话。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)