Files
comrelay/livekit/visual-test.ps1
T
2026-06-30 18:20:33 +09:00

139 lines
6.2 KiB
PowerShell

<#
.SYNOPSIS
화상회의 "화면 띄우기" 시각 테스트 러너 (Windows 네이티브 lk)
.DESCRIPTION
livekit-cli(lk)로 가상 video publisher 를 대량 접속시켜, 운영(또는 지정) LiveKit
서버의 특정 방(code)에 합성 영상을 발행한다. 사용자가 같은 방에 브라우저로 입장하면
그 가상 참가자들이 실제 영상 타일로 화면에 표시된다(=50명 화면 띄우기 검증).
⚠️ 왜 Docker(load-test.sh) 가 아니라 네이티브 lk 인가:
Docker Desktop(Windows)은 컨테이너 UDP/ICE NAT 한계로 WebRTC 미디어 연결이
타임아웃된다. 브라우저와 동일한 네트워크 경로를 쓰려면 호스트 네이티브 lk 가 필요하다.
설치: winget install --id LiveKit.LiveKitCLI
자격증명/URL 은 루트 .env.{APP_ENV} 에서 읽는다(기본 .env.production).
- LIVEKIT_API_KEY / LIVEKIT_API_SECRET : lk 가 방 토큰 서명에 사용(브라우저 백엔드와 동일 키)
- LIVEKIT_WS_URL : 브라우저가 접속하는 공개 wss URL (백엔드용 LIVEKIT_URL=내부주소 가 아님!)
(.env 의 "==" 오타나 CRLF 는 자동 보정한다)
.PARAMETER Room
대상 방의 입장 code. 앱(relay)에서 방을 먼저 생성한 뒤 /meeting/<code> 의 code 를 넣는다.
생략 시 임의 이름으로 들어가지만, 그 경우 브라우저는 해당 code 의 DB 방이 없어 입장 불가하다.
.EXAMPLE
# 운영 서버, 특정 방에 50명 저해상도 10분
.\livekit\visual-test.ps1 -Room a1b2c3d4e5 -Publishers 50 -Duration 10m
.EXAMPLE
# 화질을 올리되 업로드 대역폭 절약 위해 simulcast 끄기
.\livekit\visual-test.ps1 -Room a1b2c3d4e5 -Publishers 30 -Resolution medium -NoSimulcast
#>
[CmdletBinding()]
param(
[string] $Room,
[int] $Publishers = 50,
[int] $Subscribers = 0,
[string] $Duration = '10m',
[ValidateSet('low', 'medium', 'high')] [string] $Resolution = 'low',
[int] $NumPerSecond = 5,
[switch] $NoSimulcast,
[switch] $WithAudio, # 각 가상 유저가 마이크(오디오)도 발행 (영상 인원만큼)
[int] $AudioPublishers = 0, # 오디오 발행 인원 직접 지정(고급). -WithAudio 보다 우선
[string] $IdentityPrefix = 'load',
[string] $EnvFile
)
$ErrorActionPreference = 'Stop'
# 인원/방 코드를 인자로 안 넘기면 대화형으로 입력받는다(매번 플래그 외울 필요 없음).
if (-not $PSBoundParameters.ContainsKey('Room') -or [string]::IsNullOrWhiteSpace($Room)) {
$Room = (Read-Host '입장할 방 코드(code) 입력 (앱 /meeting/<code> 의 code)').Trim()
}
if ([string]::IsNullOrWhiteSpace($Room)) { throw '방 코드(code)가 필요합니다.' }
$promptedCount = $false
if (-not $PSBoundParameters.ContainsKey('Publishers')) {
$promptedCount = $true
$ans = (Read-Host "입장시킬 가상 인원 수 [기본 $Publishers]").Trim()
if ($ans) {
if ($ans -as [int]) { $Publishers = [int]$ans }
else { throw "인원 수는 숫자여야 합니다: $ans" }
}
}
if ($Publishers -lt 1) { throw "인원 수는 1명 이상이어야 합니다: $Publishers" }
# 마이크(오디오) 처리.
# - -AudioPublishers N : 그 값 그대로 사용(고급).
# - -WithAudio : 영상 인원만큼 오디오도 발행(각 가상 유저가 캠+마이크).
# - 둘 다 없고 대화형이면 켤지 물어본다(스크립트 인자모드에서는 안 물어봐 멈춤 없음).
if (-not $PSBoundParameters.ContainsKey('AudioPublishers')) {
if ($WithAudio) {
$AudioPublishers = $Publishers
}
elseif ($promptedCount) {
$a = (Read-Host '마이크(오디오)도 켤까요? 각 가상 유저가 마이크 발행 [y/N]').Trim()
if ($a -match '^(y|yes)$') { $AudioPublishers = $Publishers }
}
}
if ($AudioPublishers -lt 0) { $AudioPublishers = 0 }
# 루트 경로 / env 파일 결정
$root = Split-Path -Parent $PSScriptRoot
if (-not $EnvFile) {
$appEnv = if ($env:APP_ENV) { $env:APP_ENV } else { 'production' }
$EnvFile = Join-Path $root ".env.$appEnv"
}
if (-not (Test-Path $EnvFile)) { throw "env 파일을 찾을 수 없습니다: $EnvFile" }
# .env 에서 필요한 값만 읽기(주석/CRLF 무시, 마지막 정의 우선)
function Read-EnvValue([string]$key) {
$line = Get-Content $EnvFile | Where-Object { $_ -match "^\s*$([regex]::Escape($key))=" } | Select-Object -Last 1
if (-not $line) { return $null }
$val = ($line -split '=', 2)[1]
return ($val -replace "`r", '').Trim()
}
$apiKey = Read-EnvValue 'LIVEKIT_API_KEY'
$apiSecret = Read-EnvValue 'LIVEKIT_API_SECRET'
# 브라우저 접속용 공개 WS URL. .env 의 "==" 오타(앞 등호) 자동 보정.
$wsUrl = Read-EnvValue 'LIVEKIT_WS_URL'
if ($wsUrl) { $wsUrl = $wsUrl.TrimStart('=').Trim() }
if (-not $apiKey -or -not $apiSecret -or -not $wsUrl) {
throw "LIVEKIT_API_KEY / LIVEKIT_API_SECRET / LIVEKIT_WS_URL 를 $EnvFile 에서 찾을 수 없습니다."
}
# lk 실행 파일 경로 해석 (PATH 우선, 없으면 winget Links 폴백)
$lk = (Get-Command lk -ErrorAction SilentlyContinue).Source
if (-not $lk) { $lk = Join-Path $env:LOCALAPPDATA 'Microsoft\WinGet\Links\lk.exe' }
if (-not (Test-Path $lk)) {
throw "lk(livekit-cli) 를 찾을 수 없습니다. 설치: winget install --id LiveKit.LiveKitCLI"
}
# 자격증명은 환경변수로만 전달(명령줄 노출 금지)
$env:LIVEKIT_URL = $wsUrl
$env:LIVEKIT_API_KEY = $apiKey
$env:LIVEKIT_API_SECRET = $apiSecret
Write-Host "▶ LiveKit 시각 테스트 (네이티브 lk)" -ForegroundColor Cyan
Write-Host " URL=$wsUrl ROOM=$Room"
Write-Host " publishers=$Publishers audio=$AudioPublishers subscribers=$Subscribers duration=$Duration resolution=$Resolution simulcast=$([bool](-not $NoSimulcast))"
Write-Host " 브라우저에서 같은 방(code=$Room)에 입장하면 가상 참가자 영상이 타일로 보입니다. 중단: Ctrl+C" -ForegroundColor DarkGray
Write-Host ""
$lkArgs = @(
'load-test',
'--room', $Room,
'--duration', $Duration,
'--video-publishers', $Publishers,
'--audio-publishers', $AudioPublishers,
'--subscribers', $Subscribers,
'--video-resolution', $Resolution,
'--num-per-second', $NumPerSecond,
'--identity-prefix', $IdentityPrefix
)
if ($NoSimulcast) { $lkArgs += '--no-simulcast' }
& $lk @lkArgs