# [實作篇]Signaling Server - Socket.io Events

# 目標

本章將使用socket來完成 WebRTC 中基本的Signaling交換,包含offer,answer,icecandidate

使用情境:

  • Client A / B 會進入相同房間(如聊天室)
  • Client A / B 會發起視訊聊天的請求
  • Client A / B 會交換彼此SDP offer/answer
  • Client A / B 會交換彼此ICE
  • Client A / B 某一方離開房間

# 實作

附上完整程式碼 - github

依照需求擬定了以下幾個Events。

const onConnection = (socket) => {
  // Listening for joining a room (joinRoom event)
  socket.on("joinRoom", /** 加入房間 */);
  socket.on("disconnect", /** 離線 */);

  // for peer to peer communicate
  socket.on("offer", /** SDP offer */);
  socket.on("answer", /** SDP answer */);
  socket.on("icecandidate", /** ICE */);
};

接下來將邏輯的部份拆分封裝到同一包檔案中( event.js )。

  1. 資料緩存及其結構

    // ./event.js
    
    // 緩存使用者資訊
    // 資料結構:使用者.房間名稱(目前先寫死一間)
    const users = {
      general: {},
    };
    
  2. joinRoom 加入房間

    // ./event.js
    
    const joinRoom = (socket) => ({ username, room }) => {
      socket.join(room, () => {
          // push user for the suitable room
          users[room][socket.client.id] = { username: username, id: socket.client.id }
          // Notify all the users in the same room
          socket.broadcast.in(room).emit('newUser', users[room]);
      });
    }
    
  3. leaveRoom 離線

    // ./event.js
    
    const leaveRoom = (socket) => ({ room, username }) => {
      socket.leave(room, () => {
          delete  users[room][socket.client.id]
          // Notify all the users in the same room
          socket.broadcast.in(room).emit('userLeave', users[room]);
      })
    }
    
  4. SDP Offer

    // ./event.js
    
    const offer = (socket) => ({room, offer}) => {
      console.log('switch offer')
      // Notify all the users in the same room
      socket.broadcast.in(room).emit('offer', offer);
    }
    
  5. SDP Answer

    // ./event.js
    
    const answer = (socket) => ({room, answer}) => {
      console.log('switch answer')
      // Notify all the users in the same room
      socket.broadcast.in(room).emit('answer', answer);
    }
    
  6. ICE

    // ./event.js
    
    const icecandidate = (socket) => ({room, candidate}) => {
      console.log('switch icecandidate')
      // Notify all the users in the same room
      socket.broadcast.in(room).emit('icecandidate', candidate);
    }
    
  7. 最後

完成所有邏輯處理後,改寫一下原本的函式。

const onConnection = (socket) => {
  // Listening for joining a room (joinRoom event)
  socket.on("joinRoom", events.joinRoom(socket));
  socket.on("disconnect", () =>
    events.leaveRoom(socket)({ room: "general" })
  );

  // for peer to peer communicate
  socket.on("offer", (offer) => events.offer(socket)({room: "general", offer}));
  socket.on("answer", (answer) => events.answer(socket)({room: "general", answer}));
  socket.on("icecandidate", (candidate) => events.icecandidate(socket)({room: "general", candidate}));
};

# 總結

實作Signaling Server 基本需要的幾個功能

  • 驗證/保存使用者身份(這邊是實作簡單的加入同間房間而已)
  • SDP offer/answer
  • ICE

接下來會將之前靜態單頁的概念實作,改為用Signaling server作為中介層,讓實作起來的感覺更接近實務應用~

# 參考