公司其中一個主營業務是直播,目前主播直播會使用客戶端開播,客戶端中的用戶有觀眾和主播兩種身份。
  但客戶端開播并不方便,例如音質沒有 PC 的好,手機長時間直播發熱,模擬器操作沒有 PC 方便等。
  經過討論,讓我們組基于能跨平臺的[Electron](https://www.electronjs.org/zh/docs/latest/)開發 PC 客戶端版本的開播助手,購買的第三方聲網服務正好也有相關 demo。
:-: 
  我們在此 demo 的基礎上增加公司的業務邏輯,其技術原理可以分為以下幾個步驟:
1. 采集:通過攝像頭、麥克風等設備采集音頻和視頻數據。
2. 傳輸:通過網絡將編碼后的音頻和視頻數據傳輸給服務器。
3. 服務器處理:服務器對接收的數據進行處理和分發,將數據發送給各個客戶端。
4. 互動消息和消息信令:直播間的聊天消息傳輸以及各種業務消息指令(例如上麥、下麥等)。
  對應的技術實現會基于[聲網](https://docportal.shengwang.cn/cn/live-streaming-standard-legacy/landing-page)和騰訊[IM](https://cloud.tencent.com/document/product/269/75285),以及現有的客戶端邏輯,簡單的說就是將客戶端的邏輯搬到 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](https://webpack.electron.build/)dev。
~~~
npm start
~~~
  electron-webpack 的目標是通過一次簡單的安裝消除所有初步設置(項目結構、熱更新、TS、babel 等),以便重新開發應用程序。
**2)打包**
  開始打包,在背后執行的命令是 yarn compile &&[electron-builder](https://www.electron.build/index.html)。
~~~
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 的數據都會上報到服務器中。
~~~html
<!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](https://www.npmjs.com/package/electron-log/v/4.4.8)庫,將打印信息存儲在本地文件中。
  最新版本是 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 消息之后確認業務層功能沒問題再操作聲網層,聲網層收到回調確認功能成功再結束整個功能。
*****
> 原文出處:
[博客園-Node.js躬行記](https://www.cnblogs.com/strick/category/1688575.html)
[知乎專欄-Node.js躬行記](https://zhuanlan.zhihu.com/pwnode)
已建立一個微信前端交流群,如要進群,請先加微信號freedom20180706或掃描下面的二維碼,請求中需注明“看云加群”,在通過請求后就會把你拉進來。還搜集整理了一套[面試資料](https://github.com/pwstrick/daily),歡迎瀏覽。

推薦一款前端監控腳本:[shin-monitor](https://github.com/pwstrick/shin-monitor),不僅能監控前端的錯誤、通信、打印等行為,還能計算各類性能參數,包括 FMP、LCP、FP 等。
- ES6
- 1、let和const
- 2、擴展運算符和剩余參數
- 3、解構
- 4、模板字面量
- 5、對象字面量的擴展
- 6、Symbol
- 7、代碼模塊化
- 8、數字
- 9、字符串
- 10、正則表達式
- 11、對象
- 12、數組
- 13、類型化數組
- 14、函數
- 15、箭頭函數和尾調用優化
- 16、Set
- 17、Map
- 18、迭代器
- 19、生成器
- 20、類
- 21、類的繼承
- 22、Promise
- 23、Promise的靜態方法和應用
- 24、代理和反射
- HTML
- 1、SVG
- 2、WebRTC基礎實踐
- 3、WebRTC視頻通話
- 4、Web音視頻基礎
- CSS進階
- 1、CSS基礎拾遺
- 2、偽類和偽元素
- 3、CSS屬性拾遺
- 4、浮動形狀
- 5、漸變
- 6、濾鏡
- 7、合成
- 8、裁剪和遮罩
- 9、網格布局
- 10、CSS方法論
- 11、管理后臺響應式改造
- React
- 1、函數式編程
- 2、JSX
- 3、組件
- 4、生命周期
- 5、React和DOM
- 6、事件
- 7、表單
- 8、樣式
- 9、組件通信
- 10、高階組件
- 11、Redux基礎
- 12、Redux中間件
- 13、React Router
- 14、測試框架
- 15、React Hooks
- 16、React源碼分析
- 利器
- 1、npm
- 2、Babel
- 3、webpack基礎
- 4、webpack進階
- 5、Git
- 6、Fiddler
- 7、自制腳手架
- 8、VSCode插件研發
- 9、WebView中的頁面調試方法
- Vue.js
- 1、數據綁定
- 2、指令
- 3、樣式和表單
- 4、組件
- 5、組件通信
- 6、內容分發
- 7、渲染函數和JSX
- 8、Vue Router
- 9、Vuex
- TypeScript
- 1、數據類型
- 2、接口
- 3、類
- 4、泛型
- 5、類型兼容性
- 6、高級類型
- 7、命名空間
- 8、裝飾器
- Node.js
- 1、Buffer、流和EventEmitter
- 2、文件系統和網絡
- 3、命令行工具
- 4、自建前端監控系統
- 5、定時任務的調試
- 6、自制短鏈系統
- 7、定時任務的進化史
- 8、通用接口
- 9、微前端實踐
- 10、接口日志查詢
- 11、E2E測試
- 12、BFF
- 13、MySQL歸檔
- 14、壓力測試
- 15、活動規則引擎
- 16、活動配置化
- 17、UmiJS版本升級
- 18、半吊子的可視化搭建系統
- 19、KOA源碼分析(上)
- 20、KOA源碼分析(下)
- 21、花10分鐘入門Node.js
- 22、Node環境升級日志
- 23、Worker threads
- 24、低代碼
- 25、Web自動化測試
- 26、接口攔截和頁面回放實驗
- 27、接口管理
- 28、Cypress自動化測試實踐
- 29、基于Electron的開播助手
- Node.js精進
- 1、模塊化
- 2、異步編程
- 3、流
- 4、事件觸發器
- 5、HTTP
- 6、文件
- 7、日志
- 8、錯誤處理
- 9、性能監控(上)
- 10、性能監控(下)
- 11、Socket.IO
- 12、ElasticSearch
- 監控系統
- 1、SDK
- 2、存儲和分析
- 3、性能監控
- 4、內存泄漏
- 5、小程序
- 6、較長的白屏時間
- 7、頁面奔潰
- 8、shin-monitor源碼分析
- 前端性能精進
- 1、優化方法論之測量
- 2、優化方法論之分析
- 3、瀏覽器之圖像
- 4、瀏覽器之呈現
- 5、瀏覽器之JavaScript
- 6、網絡
- 7、構建
- 前端體驗優化
- 1、概述
- 2、基建
- 3、后端
- 4、數據
- 5、后臺
- Web優化
- 1、CSS優化
- 2、JavaScript優化
- 3、圖像和網絡
- 4、用戶體驗和工具
- 5、網站優化
- 6、優化閉環實踐
- 數據結構與算法
- 1、鏈表
- 2、棧、隊列、散列表和位運算
- 3、二叉樹
- 4、二分查找
- 5、回溯算法
- 6、貪心算法
- 7、分治算法
- 8、動態規劃
- 程序員之路
- 大學
- 2011年
- 2012年
- 2013年
- 2014年
- 項目反思
- 前端基礎學習分享
- 2015年
- 再一次項目反思
- 然并卵
- PC網站CSS分享
- 2016年
- 制造自己的榫卯
- PrimusUI
- 2017年
- 工匠精神
- 2018年
- 2019年
- 前端學習之路分享
- 2020年
- 2021年
- 2022年
- 2023年
- 2024年
- 日志
- 2020