Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions images/chromium-headful/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -360,8 +360,8 @@ COPY --from=xorg-deps /usr/local/lib/xorg/modules/drivers/dummy_drv.so /usr/lib/
COPY --from=xorg-deps /usr/local/lib/xorg/modules/input/neko_drv.so /usr/lib/xorg/modules/input/neko_drv.so

COPY images/chromium-headful/image-chromium/ /
COPY images/chromium-headful/start-pulseaudio.sh /images/chromium-headful/start-pulseaudio.sh
RUN chmod +x /images/chromium-headful/start-pulseaudio.sh
COPY shared/start-pulseaudio.sh /usr/local/bin/start-pulseaudio.sh
RUN chmod +x /usr/local/bin/start-pulseaudio.sh
COPY images/chromium-headful/supervisord.conf /etc/supervisor/supervisord.conf
COPY images/chromium-headful/supervisor/services/ /etc/supervisor/conf.d/services/
COPY shared/envoy/supervisor-envoy.conf /etc/supervisor/conf.d/services/envoy.conf
Expand Down
13 changes: 0 additions & 13 deletions images/chromium-headful/start-pulseaudio.sh

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[program:kernel-images-api]
command=/bin/bash -lc 'mkdir -p "${KERNEL_IMAGES_API_OUTPUT_DIR:-/recordings}" && PORT="${KERNEL_IMAGES_API_PORT:-10001}" FRAME_RATE="${KERNEL_IMAGES_API_FRAME_RATE:-10}" DISPLAY_NUM="${KERNEL_IMAGES_API_DISPLAY_NUM:-${DISPLAY_NUM:-1}}" MAX_SIZE_MB="${KERNEL_IMAGES_API_MAX_SIZE_MB:-500}" OUTPUT_DIR="${KERNEL_IMAGES_API_OUTPUT_DIR:-/recordings}" LOG_CDP_MESSAGES="${LOG_CDP_MESSAGES:-false}" S2_BASIN="${S2_BASIN:-}" S2_ACCESS_TOKEN="${S2_ACCESS_TOKEN:-}" S2_STREAM="${S2_STREAM:-}" exec /usr/local/bin/kernel-images-api'
command=/bin/bash -lc 'mkdir -p "${KERNEL_IMAGES_API_OUTPUT_DIR:-/recordings}" && PORT="${KERNEL_IMAGES_API_PORT:-10001}" FRAME_RATE="${KERNEL_IMAGES_API_FRAME_RATE:-10}" DISPLAY_NUM="${KERNEL_IMAGES_API_DISPLAY_NUM:-${DISPLAY_NUM:-1}}" MAX_SIZE_MB="${KERNEL_IMAGES_API_MAX_SIZE_MB:-500}" OUTPUT_DIR="${KERNEL_IMAGES_API_OUTPUT_DIR:-/recordings}" RECORD_AUDIO="${KERNEL_IMAGES_API_RECORD_AUDIO:-${RECORD_AUDIO:-true}}" AUDIO_SOURCE="${KERNEL_IMAGES_API_AUDIO_SOURCE:-${AUDIO_SOURCE:-KernelOutput.monitor}}" PULSE_SERVER="${PULSE_SERVER:-unix:/tmp/pulse/native}" PULSE_SINK="${PULSE_SINK:-KernelOutput}" LOG_CDP_MESSAGES="${LOG_CDP_MESSAGES:-false}" S2_BASIN="${S2_BASIN:-}" S2_ACCESS_TOKEN="${S2_ACCESS_TOKEN:-}" S2_STREAM="${S2_STREAM:-}" exec /usr/local/bin/kernel-images-api'
autostart=false
autorestart=true
startsecs=0
Expand Down
4 changes: 2 additions & 2 deletions images/chromium-headful/supervisor/services/pulseaudio.conf
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[program:pulseaudio]
command=/bin/bash -lc '/images/chromium-headful/start-pulseaudio.sh'
command=/bin/bash -lc '/usr/local/bin/start-pulseaudio.sh'
autostart=false
autorestart=false
autorestart=true
startsecs=0
exitcodes=0
stdout_logfile=/var/log/supervisord/pulseaudio
Expand Down
3 changes: 3 additions & 0 deletions images/chromium-headless/image/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked,id=$CACHEIDPREFIX-ap
gpg-agent \
dbus \
dbus-x11 \
pulseaudio \
xvfb \
x11-utils \
x11-xserver-utils \
Expand Down Expand Up @@ -229,6 +230,8 @@ RUN useradd -m -s /bin/bash kernel
# supervisor start scripts
COPY images/chromium-headless/image/start-xvfb.sh /images/chromium-headless/image/start-xvfb.sh
RUN chmod +x /images/chromium-headless/image/start-xvfb.sh
COPY shared/start-pulseaudio.sh /usr/local/bin/start-pulseaudio.sh
RUN chmod +x /usr/local/bin/start-pulseaudio.sh

# Container entrypoint wrapper (Go binary, replaces wrapper.sh)
COPY --from=server-builder /out/wrapper /wrapper
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[program:kernel-images-api]
command=/bin/bash -lc 'mkdir -p "${KERNEL_IMAGES_API_OUTPUT_DIR:-/recordings}" && PORT="${KERNEL_IMAGES_API_PORT:-10001}" FRAME_RATE="${KERNEL_IMAGES_API_FRAME_RATE:-10}" DISPLAY_NUM="${KERNEL_IMAGES_API_DISPLAY_NUM:-${DISPLAY_NUM:-1}}" MAX_SIZE_MB="${KERNEL_IMAGES_API_MAX_SIZE_MB:-500}" OUTPUT_DIR="${KERNEL_IMAGES_API_OUTPUT_DIR:-/recordings}" LOG_CDP_MESSAGES="${LOG_CDP_MESSAGES:-false}" S2_BASIN="${S2_BASIN:-}" S2_ACCESS_TOKEN="${S2_ACCESS_TOKEN:-}" S2_STREAM="${S2_STREAM:-}" exec /usr/local/bin/kernel-images-api'
command=/bin/bash -lc 'mkdir -p "${KERNEL_IMAGES_API_OUTPUT_DIR:-/recordings}" && PORT="${KERNEL_IMAGES_API_PORT:-10001}" FRAME_RATE="${KERNEL_IMAGES_API_FRAME_RATE:-10}" DISPLAY_NUM="${KERNEL_IMAGES_API_DISPLAY_NUM:-${DISPLAY_NUM:-1}}" MAX_SIZE_MB="${KERNEL_IMAGES_API_MAX_SIZE_MB:-500}" OUTPUT_DIR="${KERNEL_IMAGES_API_OUTPUT_DIR:-/recordings}" RECORD_AUDIO="${KERNEL_IMAGES_API_RECORD_AUDIO:-${RECORD_AUDIO:-true}}" AUDIO_SOURCE="${KERNEL_IMAGES_API_AUDIO_SOURCE:-${AUDIO_SOURCE:-KernelOutput.monitor}}" PULSE_SERVER="${PULSE_SERVER:-unix:/tmp/pulse/native}" PULSE_SINK="${PULSE_SINK:-KernelOutput}" LOG_CDP_MESSAGES="${LOG_CDP_MESSAGES:-false}" S2_BASIN="${S2_BASIN:-}" S2_ACCESS_TOKEN="${S2_ACCESS_TOKEN:-}" S2_STREAM="${S2_STREAM:-}" exec /usr/local/bin/kernel-images-api'
autostart=false
autorestart=true
startsecs=0
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[program:pulseaudio]
command=/bin/bash -lc '/usr/local/bin/start-pulseaudio.sh'
autostart=false
autorestart=true
startsecs=0
exitcodes=0
stdout_logfile=/var/log/supervisord/pulseaudio
redirect_stderr=true
2 changes: 2 additions & 0 deletions server/cmd/api/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ func main() {
FrameRate: &config.FrameRate,
MaxSizeInMB: &config.MaxSizeInMB,
OutputDir: &config.OutputDir,
RecordAudio: &config.RecordAudio,
AudioSource: &config.AudioSource,
}
if err := defaultParams.Validate(); err != nil {
slogger.Error("invalid default recording parameters", "err", err)
Expand Down
3 changes: 2 additions & 1 deletion server/cmd/chromium-launcher/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ func main() {
"env",
"DISPLAY=:1",
"DBUS_SESSION_BUS_ADDRESS=unix:path=/run/dbus/system_bus_socket",
"PULSE_SERVER=" + os.Getenv("PULSE_SERVER"),
"PULSE_SINK=" + os.Getenv("PULSE_SINK"),
"XDG_CONFIG_HOME=/home/kernel/.config",
"XDG_CACHE_HOME=/home/kernel/.cache",
"HOME=/home/kernel",
Expand All @@ -135,7 +137,6 @@ func main() {
}
}


// execLookPath helps satisfy syscall.Exec's requirement to pass an absolute path.
func execLookPath(file string) (string, error) {
if strings.ContainsRune(file, os.PathSeparator) {
Expand Down
7 changes: 7 additions & 0 deletions server/cmd/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ type Config struct {
DisplayNum int `envconfig:"DISPLAY_NUM" default:"1"`
MaxSizeInMB int `envconfig:"MAX_SIZE_MB" default:"500"`
OutputDir string `envconfig:"OUTPUT_DIR" default:"."`
RecordAudio bool `envconfig:"RECORD_AUDIO" default:"false"`
AudioSource string `envconfig:"AUDIO_SOURCE" default:"KernelOutput.monitor"`

// Absolute or relative path to the ffmpeg binary. If empty the code falls back to "ffmpeg" on $PATH.
PathToFFmpeg string `envconfig:"FFMPEG_PATH" default:"ffmpeg"`
Expand Down Expand Up @@ -55,6 +57,8 @@ func (c *Config) LogValue() slog.Value {
slog.Int("display_num", c.DisplayNum),
slog.Int("max_size_mb", c.MaxSizeInMB),
slog.String("output_dir", c.OutputDir),
slog.Bool("record_audio", c.RecordAudio),
slog.String("audio_source", c.AudioSource),
slog.String("ffmpeg_path", c.PathToFFmpeg),
slog.Int("devtools_proxy_port", c.DevToolsProxyPort),
slog.Bool("log_cdp_messages", c.LogCDPMessages),
Expand Down Expand Up @@ -100,6 +104,9 @@ func validate(config *Config) error {
if config.PathToFFmpeg == "" {
return fmt.Errorf("FFMPEG_PATH is required")
}
if config.RecordAudio && config.AudioSource == "" {
return fmt.Errorf("AUDIO_SOURCE is required when RECORD_AUDIO is true")
}
if config.ChromeDriverUpstreamAddr == "" {
return fmt.Errorf("CHROMEDRIVER_UPSTREAM_ADDR is required")
}
Expand Down
16 changes: 16 additions & 0 deletions server/cmd/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ func TestLoad(t *testing.T) {
DisplayNum: 1,
MaxSizeInMB: 500,
OutputDir: ".",
RecordAudio: false,
AudioSource: "KernelOutput.monitor",
PathToFFmpeg: "ffmpeg",
DevToolsProxyPort: 9222,
ScaleToZeroCooldown: time.Second,
Expand All @@ -39,6 +41,8 @@ func TestLoad(t *testing.T) {
"DISPLAY_NUM": "2",
"MAX_SIZE_MB": "250",
"OUTPUT_DIR": "/tmp",
"RECORD_AUDIO": "true",
"AUDIO_SOURCE": "CustomOutput.monitor",
"FFMPEG_PATH": "/usr/local/bin/ffmpeg",
"DEVTOOLS_PROXY_PORT": "9876",
"SCALE_TO_ZERO_COOLDOWN": "5s",
Expand All @@ -51,6 +55,8 @@ func TestLoad(t *testing.T) {
DisplayNum: 2,
MaxSizeInMB: 250,
OutputDir: "/tmp",
RecordAudio: true,
AudioSource: "CustomOutput.monitor",
PathToFFmpeg: "/usr/local/bin/ffmpeg",
DevToolsProxyPort: 9876,
ScaleToZeroCooldown: 5 * time.Second,
Expand All @@ -71,6 +77,8 @@ func TestLoad(t *testing.T) {
DisplayNum: 1,
MaxSizeInMB: 500,
OutputDir: ".",
RecordAudio: false,
AudioSource: "KernelOutput.monitor",
PathToFFmpeg: "ffmpeg",
DevToolsProxyPort: 7777,
ScaleToZeroCooldown: time.Second,
Expand Down Expand Up @@ -114,6 +122,14 @@ func TestLoad(t *testing.T) {
},
wantErr: true,
},
{
name: "missing audio source when recording audio",
env: map[string]string{
"RECORD_AUDIO": "true",
"AUDIO_SOURCE": "",
},
wantErr: true,
},
{
name: "missing chromedriver upstream addr (set to empty)",
env: map[string]string{
Expand Down
2 changes: 0 additions & 2 deletions server/cmd/wrapper/chromium.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ func applyHeadlessDefaultFlags() {
"--hide-crash-restore-bubble",
"--hide-scrollbars",
"--metrics-recording-only",
"--mute-audio",
"--no-default-browser-check",
"--no-first-run",
"--no-sandbox",
Expand All @@ -61,4 +60,3 @@ func applyHeadlessDefaultFlags() {
}, " ")
_ = os.Setenv("CHROMIUM_FLAGS", flags)
}

24 changes: 15 additions & 9 deletions server/cmd/wrapper/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const (
dbusSocket = "/run/dbus/system_bus_socket"
defaultDisplay = ":1"
defaultIntPort = "9223"
pulseSocket = "/tmp/pulse/native"
)

type profile int
Expand Down Expand Up @@ -119,6 +120,15 @@ func main() {
// starts so it captures the env for child services (notably chromium,
// which would otherwise spam autolaunch errors).
_ = os.Setenv("DBUS_SESSION_BUS_ADDRESS", "unix:path="+dbusSocket)
if os.Getenv("PULSE_SERVER") == "" {
_ = os.Setenv("PULSE_SERVER", "unix:"+pulseSocket)
}
if os.Getenv("PULSE_SINK") == "" {
_ = os.Setenv("PULSE_SINK", "KernelOutput")
}
if os.Getenv("AUDIO_SOURCE") == "" {
_ = os.Setenv("AUDIO_SOURCE", "KernelOutput.monitor")
}

// Stale X locks from prior runs.
_ = os.Remove("/tmp/.X1-lock")
Expand Down Expand Up @@ -172,11 +182,13 @@ func main() {
_ = os.WriteFile(filepath.Join(supervisordLogD, "chromium"), nil, 0o644)

browserStart := time.Now()
startAll(xServer, "dbus", "chromedriver", "chromium")
startAll(xServer, "dbus", "chromedriver", "pulseaudio")
waitForX(defaultDisplay, 20*time.Second)
if prof == profileHeadful {
startAll("mutter")
}
waitForSocket(pulseSocket, 10*time.Second)
startAll("chromium")
waitForSocket(dbusSocket, 10*time.Second)
if prof == profileHeadful && webrtc {
startAll("neko")
Expand Down Expand Up @@ -223,12 +235,6 @@ func main() {
identityDone.Sub(identityStart).Truncate(time.Millisecond),
formatProbeDurations(probeDurations))

// Cosmetic + non-critical services come up off the hot path. Headless has
// no audio stack.
if prof == profileHeadful {
go startAll("pulseaudio")
}

// Re-enable scale-to-zero now that the hot path is up — unless the caller
// asked to keep it disabled via ENABLE_STZ=false/0.
if stzManaged {
Expand All @@ -243,9 +249,9 @@ func main() {

// waitAllReady gates on all caller-visible ready signals concurrently:
// - cdp : HTTP /json/version on the public CDP port (proves api proxy is
// wired through to chromium's DevTools server)
// wired through to chromium's DevTools server)
// - chromedriver : TCP on chromedriver's internal port 9225 (api on 9224 is bound
// when api itself is up, which CDP readiness already implies)
// when api itself is up, which CDP readiness already implies)
// - neko : TCP on neko's HTTP port (8080), only when ENABLE_WEBRTC=true
// - envoy : TCP on envoy's listener (3128), only when envoy is enabled
func waitAllReady(t0 time.Time, webrtc bool) map[string]time.Duration {
Expand Down
Loading
Loading