情境:12 台頭顯,換場 3 分鐘
逐台確認吃掉整個換場
12 台逐台確認約需 10 分鐘,換場只有 3 分鐘。
每台戴上、看場景、摘下,約 50 秒。換場結束的時候,你手上是第 4 台,還有 8 台沒看。
01 現場的難題
頭顯會被觀眾摘下、退回主選單、掉 Wi-Fi,也會在你看不到的地方沒電。換場只有三分鐘。
情境:12 台頭顯,換場 3 分鐘
12 台逐台確認約需 10 分鐘,換場只有 3 分鐘。
每台戴上、看場景、摘下,約 50 秒。換場結束的時候,你手上是第 4 台,還有 8 台沒看。
觀眾按到 Home 鍵、應用當掉、電量歸零。在有人舉手之前,控台上看不到任何跡象。
同一個場地兩組觀眾、兩套流程,OSC 訊號走同一個埠。A 場的換場指令把 B 場一起換掉。
新版 APK 進來,就一台一台接線側載。12 台是 12 次插線、12 次拔線。
02 一場演出
12 台頭顯,兩場同時開:大群 A、B 各 6 台。以下照時間順序,看 DeviceHub 在每個時間點做了什麼。
T−15:00
USB 一插上,DeviceHub 就把頭顯切到 Wi-Fi:adb tcpip 5555、讀 wlan0 的位址、連線。拔掉線,它已經在清單上。之後每 3 秒讀一次每台的狀態,最多 8 台同時讀。
12 台讀完一輪 1.6 秒;一台接一台讀要 8.7 秒(程式註解內的實測)
T−10:00
每台頭顯分進大群、小群、編號。每個大群填 Photon 房名、密碼、region,按「驗證房間」交給 XRPR,通過後版本號加 1。頭顯下次來拉設定就拿到新版,並回傳 /show_assignment_ack。
房間密碼留在 DeviceHub,頭顯收到的是房名、region 和版本號。頭顯拿到名稱與小群前每 3 秒來拉一次,之後每 60 秒。
T−05:00
演出狀態頁每個大群一張卡:房間 · region · 驗證版本、OSC 進 → 出、頭顯/已確認/在線台數,每台一個 ✓ 或 ⚠。分到這個大群的頭顯全部確認收到,卡片才顯示「可開演」。
⚠ 代表這台還沒回報收到 rev.3
T−01:00
v0.3.8 把批次列搬到監控頁:刷新列表、全體啟動、全體關閉。全體啟動送出指令就結束,不等回覆;結果看狀態格,接下來幾次讀取,方塊一格一格轉綠。
綠方塊:前景是 ShowApp。紅方塊:不是。
T 00:00
每個大群有自己的 OSC 收訊埠。從 9002 進來的 cue 只轉給大群 A 的 6 台,9003 進來的只給 B。DeviceHub 先轉發,封包送出之後才寫這一行 log。
A:9002 進 → 9200 出 · B:9003 進 → 9201 出
T+12:00
按「開始」,每台在線頭顯的畫面排上同一面牆:scrcpy,每格 480 px、10 fps,最多 16 格。V-10 停在載入畫面,狀態格上它還是綠的。點那一格,開它的即時預覽,15 fps。
只看不控:scrcpy 不送任何輸入,也不會喚醒休眠的頭顯
T+18:00
連續兩次讀到 V-07 不在 ShowApp,右下角跳出通知。大群 B 開著「自動拉回」,DeviceHub 就把它拉回來,同一台 30 秒內不再拉第二次。
觀眾瞄一眼系統選單、只被讀到一次:不通知,也不拉回
T+45:00
按「結束演出並鎖定」,DeviceHub 結束這次授權並關閉,電視牆、預覽、OSC 接收埠一起收掉。下次開啟,要重新通過 XRPR 驗證。
授權只在啟動時驗證,演出中途不會被鎖
介面示意,資料皆為示範值。
03 多場並行
每一場演出是一個大群,各有一組 OSC 進出埠。控制軟體打進 9002,只有大群 A 的頭顯會動。
控制軟體送到
DeviceHub 監聽
DeviceHub Pro
頭顯從這個埠收到
等待 cue。
示意動畫。埠號是全新安裝的預設值。
| 通道 | 進:DeviceHub 收 | 出:頭顯收 |
|---|---|---|
| 全體 | 9001 | 每台所屬大群的出埠;沒有大群的頭顯走 9999 |
| A | 9002 | 9200 |
| B | 9003 | 9201 |
| C | 9004 | 9202 |
| D | 9005 | 9203 |
| 新增的大群 E | 9006 | 9204 · 自動取下一組空的埠 |
04 開演前檢查
演出狀態頁給每個大群一張卡:房間驗證到第幾版、OSC 進出埠、幾台頭顯回報收到編制。✓ 是頭顯自己送回來的,不是控台猜的。
判定順序:卡在哪一步,卡片就寫哪一步
大群已啟用否則:已停用
房間名稱、密碼、國碼齊全,且通過 XRPR 驗證否則:寫出缺的那一步
至少分配一台頭顯否則:房間就緒,但還沒有頭顯
每一台都回報確認否則:房間就緒,N 台尚未確認
可開演
頭顯 8 台 · 8 已確認 · 8 在線
看未就緒的樣子
05 監控
監控頁左半邊是 Unity 送出的畫面,右半邊是每一台頭顯的即時畫面。卡在載入、掉回大廳或整片黑的那一台,在牆上一眼就認得出來;點那一格,它的畫面就開在 Unity 畫面旁邊對照。
可以操作:點牆上任一格開預覽、按「全體截圖」、在下方切換 Unity 狀態列。
介面示意 · 資料為示範值
選好來源後按「連線畫面」,這裡會顯示 Unity 正在輸出的畫面。
按「開始」同時顯示所有在線頭顯的畫面。
NDI 收得到同一網路上任何一台電腦的畫面;Spout 只收同一台電腦,只有 Windows 版有。低頻寬預設開啟,NDI 改送代理串流。預設 15 fps、寬 960 px,只能在 config.json 改。畫面不會自動連線,要按「連線畫面」。
牆上 11/11 路全綠,每一台都在目標程序,V-07 卻卡在載入畫面。狀態格看不出這件事,畫面看得出來。
牆一律走 scrcpy,要按「開始」才會開,不會自己開。掉線的格子會寫出原因,不會停在最後一張畫面。
向每一台在線頭顯各要一張畫面,存成 captures\日期-時間\名稱.jpg,結果排成一片,失敗的排最前面。每張是單眼、16:9、1280×720。
scrcpy 只看不控:不開控制通道,不會喚醒休眠中的頭顯,頭顯上的 APK 也不用更新。
實測 · 11 台 Quest 3 · Wi-Fi
全體截圖,11 台
單台預覽 下方每一條直線是一張畫面,範圍是 6.5 秒。
06 連線與復原
DeviceHub 透過 ADB 管頭顯。USB 接上的頭顯自動改走 Wi-Fi;整場斷線時從 IP 歷史重連;拿到新的 IP,名稱、編號、大群照舊。
預設開啟。DeviceHub 對 USB 頭顯下 tcpip 5555,等 2 秒,讀 wlan0 的 IP,再從 Wi-Fi 連上。已經在 Wi-Fi 上的同一台會跳過。
在線台數從 1 台以上掉到 0 的那一輪,DeviceHub 依最近連線時間,對每個歷史 IP 下 adb connect。掉到 0 一次,只觸發一次;啟動時也跑一次。單台掉線不會觸發。
頭顯身分依序比對:序號 → UUID → IP 歷史。讀得到序號或 UUID,IP 就不影響身分。DHCP 換了租約,名稱、編號、大群都留著。
跑 QuestCenter 的電腦以 HOST-<機器 ID>#<1–8> 識別:一台電腦最多 8 份,埠 7908–7915。它每 60 秒回報一次,90 秒沒有訊息就標成離線。IP 變了,分組不變。
DeviceHub 重開後,主機要等下一次回報才轉回在線,最多約 60 秒。
圖為示意,位址與序號皆為示範值。
07 頭顯編制
一台頭顯同時只屬於一個大群。小群是它在這場演出裡的角色,編號是你在對講機裡喊的那個號碼。
頭顯管理點一台頭顯,在「設備設定」選大群和小群,再按「儲存設定」。ID 留白,就取該小群最小的空號。
AA · 演出 AOSC 9002 → 9200
小群 1
小群 2
小群 3
小群 4
BB · 演出 BOSC 9003 → 9201
小群 1
小群 2
小群 3
小群 4
未分組
介面示意,資料皆為示範值。App 裡沒有拖曳,分組都在每台頭顯的「編輯設定」對話框裡完成。
01
一場正在跑的演出:一個 Photon 房間、一組 OSC 進出埠,和這場的頭顯。預設 A–D 四個,可以再新增。
02
大群裡的角色分組。每個大群預設 4 個;新增時指定名稱與顏色,不用的可以刪。
03
頭顯在小群裡的號碼,小群內不重複。新分配的頭顯取最小的空號:1、2、4 有人,下一台就是 3。
PC
v0.3.4 起,PC 主機可以加入大群,收到該群的演出 OSC。音量、APK 安裝、截圖、電視牆只對頭顯有效。
08 批次維運
安裝軟體頁只列出在線的 Android 頭顯,PC 主機不在名單上。一開始全部勾選;取消勾選的頭顯不會被裝到。
DeviceHub 對勾選的頭顯逐台執行 adb install -r,不平行,每台最多等 120 秒。紀錄逐台寫出成功,或失敗與原因,最後統計成功與失敗台數。
清單更新時新上線的頭顯,只有在原本全選時才會自動勾上。你取消過任何一台,新來的就不會自己加進目標。
新 APK 的簽章和頭顯上的舊版不同時,DeviceHub 自動 adb uninstall 舊版再重裝,不會先問你。移除會清掉該 App 在那台頭顯上的所有資料。
192.168.10.101:5555192.168.10.102:5555192.168.10.103:5555192.168.10.104:5555192.168.10.105:5555192.168.10.106:5555192.168.10.107:5555安裝完成 - 成功: 6 台, 失敗: 1 台
[20:14:02] ===== 開始安裝 ===== [20:14:02] APK: show-build-1.4.2.apk [20:14:02] 選定裝置: 7 / 7 台 [20:14:02] [20:14:02] [1/7] 正在安裝到 V-01... [20:14:09] ✓ V-01 安裝成功 [20:14:09] [2/7] 正在安裝到 V-02... [20:14:16] ✓ V-02 安裝成功 [20:14:16] [3/7] 正在安裝到 V-03... [20:14:19] → 偵測到簽章不相容,正在移除舊版 com.example.showapp(會清除該 App 的本機資料)... [20:14:21] → 舊版 com.example.showapp 已移除,正在重新安裝... [20:14:28] ✓ V-03 安裝成功 [20:14:28] [4/7] 正在安裝到 V-04... [20:14:35] ✓ V-04 安裝成功 [20:14:35] [5/7] 正在安裝到 V-05... [20:14:42] ✓ V-05 安裝成功 [20:14:42] [6/7] 正在安裝到 V-06... [20:14:45] × V-06 安裝失敗: Failure [INSTALL_FAILED_INSUFFICIENT_STORAGE] [20:14:45] [7/7] 正在安裝到 V-07... [20:14:52] ✓ V-07 安裝成功 [20:14:52] [20:14:52] ===== 安裝完成 ===== [20:14:52] 成功: 6 台 | 失敗: 1 台
介面示意,資料皆為示範值。可以先取消幾台再按「開始安裝」。
一鍵對所有已知裝置送出啟動或關閉指令,不等回應,也不確認結果;狀態格在接下來的讀取裡反映。v0.3.8 起,這一列也放在監控頁。
每輪讀在線、電量、音量、前景 App、App 版本、IP、序號、型號,最多 8 台同時讀。讀取時間會加在 3 秒間隔上,所以一輪讀多快,決定狀態格有多即時。
09 自動拉回
頭顯離開演出 App,DeviceHub 可以把它拉回來。難的是判斷它是不是真的離開:Quest 的系統選單、Guardian 邊界警告會佔住前景幾秒,作品還在背後跑;ADB 有時也讀不到前景。把這些都當成離開,觀眾就會無緣無故被拉出作品。
每格一次讀取:間隔 3 秒,加上讀取時間
第 3 次讀到系統選單,第 4 次就回到 ShowApp。沒有連續兩次,不動作。
模擬示意:情境與畫面皆為示範;判斷規則照 devicehub_relaunch.py。
01
ADB 讀不到前景 App,是一次量測失敗,不是頭顯離開。計數不增加,也不歸零。頭顯離線則直接歸零:離開網路不等於離開作品。
02
預設要連續 2 次讀到不在演出 App 才算離開。讀取預設間隔 3 秒,所以大約是 6 秒加上讀取時間。在這之內回來的,不會觸發;場地需要更寬鬆,就把次數調高。
03
每台拉回後冷卻 30 秒。前一次啟動還沒生效,不會再疊一次上去。
自動拉回關著,頭顯離開時一樣會在右下角跳出通知,6 秒後消失;回到作品也會通知一次。你可以只看通知,自己走過去處理。
每個大群在系統設定裡有自己的「自動拉回」開關,預設關閉:這一場開,隔壁那場可以不開。兩個門檻只能改 config.json,在 monitoring_settings 底下:
"monitoring_settings": {
"relaunch_required_misses": 2,
"relaunch_cooldown_seconds": 30
}
能自動拉回的軟體不稀奇;知道什麼時候不該動的才難寫。
10 發行控管
作品交給策展人或國外營運團隊之後,會被跑幾場、合約結束後還跑不跑,原本沒有人管得到。XRPR 是我們的專案與授權平台:DeviceHub 每次啟動都要先向它驗證,授權由你發,也由你收回。
XRPR 四個字母有三種讀法,一種讀法是一層。工作人員只輸入一組授權房間名稱與密碼,三層在背後依序跑完。
路徑:DeviceHubPro / SHOW-A
有效期內 · 專案相符 · 放行
有效至 2027-06-30
房間已開啟 · SHOW-A · Jp
驗證通過。DeviceHub 啟動 ADB、OSC 與探索;已驗證的大群把房間名稱、區碼與版本號送到頭顯。
示意動畫,資料皆為示範值。
Router 把密語當成座標讀,在所有專案與房間裡找出它對應的那一條路徑。
在 DeviceHub 裡啟動時輸入的 DH 授權房間名稱與密碼;每個大群按「驗證房間」送出的 Photon 房間名稱與密碼。
Relay 是閘門:向資料庫確認這組密語在有效期內、屬於哪個專案、有沒有被撤銷。沒通過的請求停在這裡。
在 DeviceHub 裡開關在你手上。你在 XRPR 撤銷或改期,對方下一次啟動就在這一層被擋下。屬於其他專案的授權,DeviceHub 一律拒絕。
閘門打開,連線落進一個由 Photon 驅動的獨立房間。房外的訊號進不來。
在 DeviceHub 裡每個大群有自己的房間。房間密碼留在 DeviceHub;頭顯只拿到房間名稱、區碼與版本號,有房名和區碼就能加入。
工作人員只輸入一次。三層依序跑完,中間那一層的開關在你手上。
一檔展覽的授權,從開到收
你在 XRPR 為這檔展覽開一組授權,有效期設成展期,連同 DeviceHub 交出去。營運團隊每天開機、輸入授權、照常演出。展期一過,授權自動失效。提前解約的話,你在後台撤銷,他們下一次啟動就打不開。
提前解約:撤銷後,下一次啟動打不開
同一個機制的兩面:你隨時能收回權利,對方也不會在觀眾面前被鎖住。
11 介面
照 v0.3.8 的版面用 HTML 重畫。點側欄切換頁面,資料都是示範值。
介面示意 · 示範資料
| 連線 | ID | 名稱 | 電量 | 音量 | IP位址 | 序號 | 啟用的程序 | 程序版本 | 操作 |
|---|---|---|---|---|---|---|---|---|---|
| 1 | V-01 | 84% | 60% | 192.168.10.101 | DEMO0000A001 | ShowApp | 1.4.2 | 啟動關閉 | |
| 2 | V-02 | 77% | 60% | 192.168.10.102 | DEMO0000A002 | ShowApp | 1.4.2 | 啟動關閉 | |
| 1 | V-03 | 18% | 70% | 192.168.10.103 | DEMO0000A003 | ShowApp | 1.4.2 | 啟動關閉 | |
| 2 | V-06 | 66% | 40% | 192.168.10.106 | DEMO0000A006 | Meta大廳 | 1.4.2 | 啟動關閉 | |
| 2 | V-08 | — | 未知 | 192.168.10.108 | DEMO0000A008 | — | — | 啟動關閉 |
Unity 畫面NDI接收中 · 1920x1080 · 15 fps
頭顯電視牆停止7/7 路
A A · 主場演出可開演
房間 SHOW-A · Jp · 已驗證 rev.3
OSC 進 9002 → 出 9200
頭顯 4 台 · 4 已確認 · 4 在線
小群 11. V-01 ✓2. V-02 ✓
小群 21. V-03 ✓2. V-04 ✓
B B · 次場演出房間就緒,2 台尚未確認
房間 SHOW-B · Jp · 已驗證 rev.1
OSC 進 9003 → 出 9201
頭顯 4 台 · 2 已確認 · 3 在線
小群 11. V-05 ✓2. V-06 ✓
小群 21. V-07 ⚠2. V-08 ⚠
安裝完成 - 成功: 5 台, 失敗: 1 台
[20:14:02] ===== 開始安裝 ===== [20:14:02] APK: show-build-1.4.2.apk [20:14:02] 選定裝置: 6 / 7 台 [20:14:02] [20:14:02] [1/6] 正在安裝到 V-01... [20:14:09] ✓ V-01 安裝成功 [20:14:09] [2/6] 正在安裝到 V-02... [20:14:16] ✓ V-02 安裝成功 [20:14:16] [3/6] 正在安裝到 V-03... [20:14:23] ✓ V-03 安裝成功 [20:14:23] [4/6] 正在安裝到 V-05... [20:14:30] ✓ V-05 安裝成功 [20:14:30] [5/6] 正在安裝到 V-06... [20:14:33] × V-06 安裝失敗: INSTALL_FAILED_INSUFFICIENT_STORAGE [20:14:33] [6/6] 正在安裝到 V-07... [20:14:40] ✓ V-07 安裝成功 [20:14:40] [20:14:40] ===== 安裝完成 ===== [20:14:40] 成功: 5 台 | 失敗: 1 台
[20:11:40] Discovery Server 啟動,監聽端口: 9065 [20:11:40] OSC 監聽啟動:全體 埠 9001 [20:11:40] OSC 監聽啟動:大群 A 埠 9002 [20:11:40] OSC 監聽啟動:大群 B 埠 9003 [20:11:43] [裝置] V-01 (192.168.10.101:5555) 在線 | 群組: 1 | App: ShowApp | 電量: 84% [20:11:43] [裝置] V-02 (192.168.10.102:5555) 在線 | 群組: 1 | App: ShowApp | 電量: 77% [20:12:03] OSC Bypass[大群 A]: 接收 /scene/change (2) -> 轉發給 4 個設備 [20:12:31] [Assignment] V-07 已確認收到設定 [20:13:55] V-06 left ShowApp for Meta大廳 [20:15:30] 電視牆開始,7 台
套件名稱:com.example.showapp
顯示名稱:ShowApp
介面語言:繁體中文
ADB路徑:C:\platform-tools\adb.exe
更新間隔(秒):3
Anchor路徑:Anchors/Main
截圖來源:scrcpy 串流(最快,建議)
發送端口:9999
接收端口:9001
啟用 OSC Bypass
AA · 主場演出啟用自動拉回OSC 進: 9002 出: 92002 小群 · 4 台 · 4/4 已確認
房間名稱:SHOW-A房間密碼:••••••國碼:Jp驗證房間已驗證,可下發
BB · 次場演出啟用自動拉回OSC 進: 9003 出: 92012 小群 · 4 台 · 2/4 已確認
房間名稱:SHOW-B房間密碼:••••••國碼:Jp驗證房間已驗證,可下發
12 規格
● 預約 Demo
告訴我們你的場地規模與演出流程,我們用你的實際配置走一次 Demo。如果你正在規劃把作品授權給策展人或國外營運團隊,也可以一起看授權與交付的流程。