三個核心元件,一個目標
Timmy 的底層設計相當務實: Flutter 用於 App, WebRTC 用於即時音訊與視訊,而 Firebase 則用於協調。 我不想打造一個把所有資料都送進雲端的大型平台。每個部分都應盡量少知道資料內容,同時仍能和其他部分可靠地運作。
WebRTC:直接連線,預設加密
WebRTC(Web Real-Time Communication)負責在寶寶裝置與家長裝置之間傳送音訊和視訊。 最理想的情況下,資料會 直接在兩台裝置之間傳送,採點對點連線,中間不需要媒體伺服器。
每一個 WebRTC 連線預設都使用 DTLS-SRTP。即使有人擷取網路封包,也無法取得可讀取的音訊或視訊。這項加密是協定的一部分,無法在 WebRTC 中隨意關閉。
這對我來說很重要:嬰兒房的影音資料不該放在我的伺服器上,而是留在你的裝置之間。
透過 Firebase Firestore 傳送信令
在 WebRTC 開始前,兩台裝置必須先找到彼此,並協商可用的連線方式。 這個部分稱為 信令。Timmy 使用 Google 的雲端資料庫 Firebase Firestore 來處理這件事。
交換的只有技術性連線資料:
- SDP 提議(offer)與回應(answer): 說明裝置的能力(支援的編解碼器、解析度等)。
- ICE 候選項: 裝置彼此可透過哪些網路路徑連線。
音訊和視訊不會進入 Firebase。Firestore 只傳送技術性連線資料。 Timmy 也會加密這個信令層,因此 Firestore 不會成為存放明文 SDP 與 ICE 資料的地方。
TURN 伺服器:直接路徑行不通時
有些網路會封鎖直接連線,例如嚴格的防火牆或某些行動電信業者。 這時 WebRTC 就需要 TURN 中繼 (Traversal Using Relays around NAT)。
Timmy 會先嘗試本地 TURN 伺服器;若本地中繼無法使用或負載過高,則以 Cloudflare 作為備援。 中繼只會轉送加密封包,並不會取得音訊或視訊的金鑰;WebRTC 加密仍會完整保留。
TURN 認證資訊由 Firebase Cloud Function 提供,有效期限只有 24 小時。 對我而言,將永久認證資訊放在嬰兒監視器 App 裡風險太高。
Nearby Connections:裝置會自動找到彼此
為了避免在寶寶裝置和家長裝置之間進行繁瑣設定,Timmy 使用 Nearby Connections。 Google 透過藍牙與 Wi‑Fi 提供這層探索功能。
Timmy 的自動配對 不需要手動輸入代碼:裝置會自動找到彼此,並找到同一個用於交換金鑰的會合點。 若配對失敗,則可以輸入 4 個字元的代碼。 配對代碼絕不會離開裝置;Firestore 只會看到作為文件識別碼的密碼學雜湊值(SHA-256)。
匿名驗證
Timmy 使用 Firebase 匿名驗證。首次啟動時,每台裝置都會取得一個暫時的匿名 ID。 不需要帳號、電子郵件地址或密碼。這個 ID 的用途僅是套用 Firestore 規則:只有已驗證的裝置能讀取或寫入工作階段資料。
系統架構:誰傳送、誰接收
Timmy 有兩種模式:
- 寶寶模式(傳送端): 裝置透過麥克風收錄聲音,並經由 WebRTC 傳送至家長裝置。也可選擇啟用相機;視訊同樣會直接傳送。
- 家長模式(接收端): 裝置接收音訊和視訊、顯示相機畫面,並提供按鍵通話功能,可向寶寶裝置傳送簡短語音訊息。
按鍵通話、相機開關等控制功能會使用 DataChannel,這是另一個 WebRTC 通道,可直接在裝置間傳送小型加密訊息。
為什麼選擇 Flutter?
Flutter 是 Google 推出的跨平台 App 框架。對 Timmy 而言,這代表我可以一次撰寫大量邏輯,並用於 Android 和 iOS。 Timmy 已在 Android 上推出,iOS 版本也接近發布。重複程式碼更少,代表可能出現錯誤的地方也更少。
總結
技術原則很簡單:Timmy 只應接觸真正需要的資料。 WebRTC 保護影音內容,Firebase 協調連線設定,TURN 只能看到加密封包,而 Nearby Connections 讓配對更省事。
好的技術會自然融入日常生活。它能好好運作,不必把嬰兒房變成一個雲端專案。