Node.js躬行記(29)——基於Electron的開播助手

  公司其中一個主營業務是直播,目前主播直播會使用客戶端開播,客戶端中的用戶有觀衆和主播兩種身份。

  但客戶端開播並不方便,例如音質沒有 PC 的好,手機長時間直播發熱,模擬器操作沒有 PC 方便等。

  經過討論,讓我們組基於能跨平臺的 Electron 開發 PC 客戶端版本的開播助手,購買的第三方聲網服務正好也有相關 demo。

  

  我們在此 demo 的基礎上增加公司的業務邏輯,其技術原理可以分爲以下幾個步驟:

  1. 採集:通過攝像頭、麥克風等設備採集音頻和視頻數據。
  2. 傳輸:通過網絡將編碼後的音頻和視頻數據傳輸給服務器。
  3. 服務器處理:服務器對接收的數據進行處理和分發,將數據發送給各個客戶端。
  4. 互動消息和消息信令:直播間的聊天消息傳輸以及各種業務消息指令(例如上麥、下麥等)。

  對應的技術實現會基於聲網和騰訊 IM,以及現有的客戶端邏輯,簡單的說就是將客戶端的邏輯搬到 PC 端實現。

  1. 採集編解碼部分可由聲網的 SDK 方案進行 PC 端的音視頻採集。
  2. 傳輸部分基於聲網的 RTC 協議進行採集後的音視頻數據推流。
  3. 業務服務器基於現有直播業務模型進行適配,如開播流程,各種業務消息流程。
  4. 互動消息以及消息信令通過現有的三方服務商騰訊 IM 接入適配當前的直播業務流程。

  一開始比較疑惑,爲什麼直播間中的交互要通過 IM 完成,後面瞭解到主播和觀衆需要用長連接綁定在一起,這樣有交互才能通知到各個人員的界面中。

  這個工作量是非常巨大的,但是我們計劃分成多期完成,第一期就做最簡單的音頻上麥和下麥。

一、分工

  在拿到原始的 Electron 項目後,一開始還沒想好如何分工,大家對 Electron 都比較陌生。

  前後也討論了兩次,最後決定邊做邊調整分工內容,首先需要了解下 Electron 項目。

1)項目說明

  當前的 Electron 項目其實就是將頁面打包到瀏覽器中發佈成一個客戶端,這是一個特殊的瀏覽器,可以不受限制的使用更多的功能。

  而我們的大部分開發其實和普通網頁開發無差別,代碼存儲在下圖的 renderer 目錄中,分工的主要內容也是此目錄中。

  

  main 目錄的文件會控制主進程,負責管理應用的生命週期,顯示原生界面,執行特殊操作並管理渲染器進程。

  下面的代碼就是在打開一個瀏覽器窗口,可配置其寬高,並且能自動打開控制檯。

  開發環境與線上環境 loadURL() 調用的參數有所不同。

function createMainWindow() {
  const window = new BrowserWindow({
    width: 1200,
    height: 720,
    autoHideMenuBar: true,
    webPreferences: {
      nodeIntegration: true,
      contextIsolation: false,
      webSecurity: false,
    },
    //titleBarStyle: 'hidden',
    //titleBarOverlay: false,
  });
  window.setMinimumSize(1200,720)
  window.setBackgroundColor('#000000')
  window.webContents.openDevTools({
    mode: 'detach',
    activate: true,
  });
  if (isDevelopment) {
    window.loadURL(`http://localhost:${process.env.ELECTRON_WEBPACK_WDS_PORT}`);
  } else {
    window.loadURL(
      formatUrl({
        pathname: path.join(__dirname, 'index.html'),
        protocol: 'file',
        slashes: true,
      })
    );
  }
  window.on('closed', () => {
    mainWindow = null;
  });
  window.webContents.on('devtools-opened', () => {
    window.focus();
    setImmediate(() => {
      window.focus();
    });
  });

  return window;
}

2)明確範圍

  初次分工是讓組內的一名成員負責登錄功能,我去完成主界面的邏輯和項目基礎功能。

  項目基礎功能包括通信、常量、緩存等功能的封裝,其中最重要的是通信功能。

  爲了能和客戶端使用相同的接口,需要在通信時也加上與客戶端相同的鑑權邏輯,並且還得帶上所有接口都需要的必傳參數。

  同事的登錄邏輯也會依賴通信,所以通信模塊極爲重要,也就最先完成封裝,其次是對騰訊 IM 的封裝。

  官方文檔寫的比較清晰,但是在實際集成時,還是遇到不少問題,期間與客戶端的同事沒少打交道,他們也提供了很大的支持。

  直播間的交互依賴 IM,IM 基於 websocket 長連接,目前已將 IM 的操作封裝到 utils/chat.ts 中,簡化初始化、發送消息、接收消息、加入直播間等功能。

  下面是一條發送上麥的消息,其中 reqId 和 user-agent 是必傳項。

{
  code:"audio", 
  body:{
    reqId:1,
    "user-agent": ""
    method:"onSeat", 
    seatNum:-1, 
    auto: true
  }
}

  下面是一條接收進入直播間的消息,如果是響應消息,那麼會包含 reqId;如果是主動推送的消息,那麼就不會包含此屬性。

  注意,有些響應還會包含 method 字段,並且如果是響應消息,那麼 code 都將是 req。

{
  toUserId: "443343545",
  code: "req",
  roomId: "88434342",
  data: {
    userId: "546657523",
    nickName: "211",
method: "onSeat", reqId: 1
}, print: true }

  如果要對某個響應做回調,可以根據 code 和 method 的組合來設計回調方法的名稱,然後註冊到一個哈希對象中。

  public addReceiveCallback(name:string, callback:any) {
    this.hashReceive[name] = callback;
  }

  不過,由於響應消息的 code 都是 req,所以在發送消息時,需要將 reqId 與 code 映射,這樣就能在響應時通過 reqId 讀取 code。

  經過這類基礎封裝後,分工就明確了,直播間中的交互以及登錄都交由另一個同事完成,大家也能做到互不干擾。

二、研發

  客戶端需要將軟件安裝到本地電腦中,所以需要有簽名和更新機制。

  以 MacOS 爲例,默認是不能安裝非應用市場的軟件,如果要將軟件發佈應用市場,那麼就必須簽名。

  而更新是爲了能讓用戶享受最新版本的功能和優化。由於第一階段,用戶都是運營能控制的,所以就省去了簽名和更新。

1)啓動

  啓動項目,在背後執行的命令是 electron-webpack dev。

npm start

  electron-webpack 的目標是通過一次簡單的安裝消除所有初步設置(項目結構、熱更新、TS、babel 等),以便重新開發應用程序。

2)打包

  開始打包,在背後執行的命令是 yarn compile && electron-builder

npm run dist

  electron-builder 用於打包和構建適用於 macOS、Windows 和 Linux 的 Electron 應用程序。

  注意,打包成 Windows 軟件時,需要在 Windows 系統中完成打包。

  在 Windows 上安裝環境時,發現 Node.js、VSCode 等軟件,最新版都不再支持 Win7。

{
    "compile": "electron-webpack",
    "dist": "yarn compile && electron-builder",
    "dist:mac": "yarn dist --dir -c.compression=store -c.mac.identity=null",
    "dist:win32": "yarn compile && electron-builder --publish never --win --ia32",
    "dist:win64": "yarn compile && electron-builder --publish never --win --x64"
}

  在第一次打包時,會下載依賴的 electron-v.xxxx.zip 文件,由於國內的網絡環境,下載速度緩慢,經常會失敗。

  在提示的錯誤中,會包含下載地址,最簡單的辦法是放到瀏覽器中下載,下載完成後放到 Mac 的指定目錄。

open ~/Library/Caches/electron/

  Windows 目錄可以參考 C:\Users\Administrator\AppData\Local\electron\Cache,其中Administrator是登錄的賬號,有可能不同。

  

  在打包 Windows 時,也要下載相關的 Electron 壓縮包(下載地址可從錯誤提示中獲取),例如 electron-v18.2.3-darwin-x64.zip。

⨯ Get "https://npmmirror.com/mirrors/electron-builder-binaries/winCodeSign-2.6.0/winCodeSign-2.6.0.7z": 
proxyconnect tcp: dial tcp :0: connectex: The requested address is not valid in
its context.github.com/develar/app-builder/pkg/download.(*Downloader).follow.func1......

  在打包時還會出現其他的包不能安裝,按照提示將包下載到本地,然後複製到指定位置。

  例如將 winCodeSign.gz 複製到 ~/Library/Caches/electron-builder/winCodeSign 中並解壓縮。

  最後按照各種提示進行操作即可,例如開放權限等。

  

3)IM

  直播間的通信基於騰訊 IM,以上麥爲例,在上麥時客戶端會向 IM 服務器發送上麥消息。

  服務端在完成上麥處理後,讓 IM 服務端發送響應消息給客戶端。

  上麥初始化後,需要加入聲網的頻道,再進行座位下發消息,經由 IM 服務器中轉給客戶端。

4)日誌

  在模板 src/index.ejs 頁面中,已經加載自研的監控 SDK,console.log 和 console.error 的數據都會上報到服務器中。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>PC直播助手</title>
    <script src="https://www.xxx.com/js/shin.js" crossorigin="anonymous"></script>
    <script>
      shin.setParam({
        token: "pc-live",
        version: '1.0.0',
        src: 'https://api.xxx.com/ma.gif'
      });
    </script>
  </head>
  <body>
    <div id="app"></div>
  </body>
</html>

  除此之外,還可以引入 electron-log 庫,將打印信息存儲在本地文件中。

  最新版本是 5.X,但是每次引入會報錯,所以就選用了 4.4.8 版本,內置了 error、warn、info 和 debug 等方法。

import logger from 'electron-log';

logger.info('第二條測試日誌', {
  userId: '657676',
  userSig: 'eJwszc3K*wsAAP--qFMw4w__',
  groupId: '88434345'
})

  在調用日誌方法後,默認就會在指定目錄中生成 renderer.log 文件,其中 live-assistant 是在 package.json 中配置的 name 屬性。

open ~/Library/Logs/live-assistant/

  renderer.log 文件中的默認日誌格式如下,格式可自定義。

[2024-02-22 18:02:20.549] [info]  第二條測試日誌 {
  userId: '5456565',
  userSig: 'eJwszc3K*wsAAP--qFMw4w__',
  groupId: '885657564'
}
[2024-02-22 18:18:14.223] [info]  第三條測試日誌 {
  userId: '34545656',
  userSig: 'eJwszc3K*wsAAP--qFMw4w__',
  groupId: '88567688'
}

5)聲網

  整個直播間功能依賴聲網和 IM 共同作用,IM 是展示 UI 層,可以讓觀衆在直播間內看到主播是否上麥、開閉麥狀態。

  聲網是功能層,實際控制主播是否進入頻道,是否能發流。

  所以整個流程應該是先發送 IM 消息,接收到服務端 IM 消息之後確認業務層功能沒問題再操作聲網層,聲網層收到回調確認功能成功再結束整個功能。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章