diff options
Diffstat (limited to 'internal')
| -rw-r--r-- | internal/outcome/outcome.go | 4 | ||||
| -rw-r--r-- | internal/outcome/run_test.go | 10 | ||||
| -rw-r--r-- | internal/outcome/shim.go | 75 | ||||
| -rw-r--r-- | internal/outcome/sppipewire.go | 4 |
4 files changed, 88 insertions, 5 deletions
diff --git a/internal/outcome/outcome.go b/internal/outcome/outcome.go index 45ef4431..3516eaef 100644 --- a/internal/outcome/outcome.go +++ b/internal/outcome/outcome.go @@ -257,6 +257,10 @@ type outcomeStateParams struct { // Populated by spRuntimeOp. runtimeDir *check.Absolute + // Path to pipewire-pulse server. + // Populated by spPipeWireOp if DirectPipeWire is false. + pipewirePulsePath *check.Absolute + as hst.ApplyState *outcomeState } diff --git a/internal/outcome/run_test.go b/internal/outcome/run_test.go index db18e02c..0f58dec6 100644 --- a/internal/outcome/run_test.go +++ b/internal/outcome/run_test.go @@ -100,7 +100,6 @@ func TestOutcomeRun(t *testing.T) { "GOOGLE_DEFAULT_CLIENT_ID=77185425430.apps.googleusercontent.com", "GOOGLE_DEFAULT_CLIENT_SECRET=OTJgUOQcT7lO7GsGZq2G4IlT", "HOME=/data/data/org.chromium.Chromium", - "PIPEWIRE_REMOTE=/run/user/1971/pipewire-0", "SHELL=/run/current-system/sw/bin/zsh", "TERM=xterm-256color", "USER=chronos", @@ -150,9 +149,6 @@ func TestOutcomeRun(t *testing.T) { // spWaylandOp Bind(m("/tmp/hakurei.0/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/wayland"), m("/run/user/1971/wayland-0"), 0). - // spPipeWireOp - Bind(m("/tmp/hakurei.0/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/pipewire"), m("/run/user/1971/pipewire-0"), 0). - // spDBusOp Bind(m("/tmp/hakurei.0/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bus"), m("/run/user/1971/bus"), 0). Bind(m("/tmp/hakurei.0/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/system_bus_socket"), m("/var/run/dbus/system_bus_socket"), 0). @@ -174,7 +170,7 @@ func TestOutcomeRun(t *testing.T) { Remount(fhs.AbsRoot, syscall.MS_RDONLY), }}, - {"nixos permissive defaults no enablements", new(stubNixOS), &hst.Config{Container: &hst.ContainerConfig{ + {"nixos permissive defaults no enablements", new(stubNixOS), &hst.Config{DirectPipeWire: true, Container: &hst.ContainerConfig{ Filesystem: []hst.FilesystemConfigJSON{ {FilesystemConfig: &hst.FSBind{ Target: fhs.AbsRoot, @@ -256,6 +252,8 @@ func TestOutcomeRun(t *testing.T) { }}, {"nixos permissive defaults chromium", new(stubNixOS), &hst.Config{ + DirectPipeWire: true, + ID: "org.chromium.Chromium", Identity: 9, Groups: []string{"video"}, @@ -426,6 +424,8 @@ func TestOutcomeRun(t *testing.T) { }}, {"nixos chromium direct wayland", new(stubNixOS), &hst.Config{ + DirectPipeWire: true, + ID: "org.chromium.Chromium", Enablements: hst.NewEnablements(hst.EWayland | hst.EDBus | hst.EPipeWire | hst.EPulse), Container: &hst.ContainerConfig{ diff --git a/internal/outcome/shim.go b/internal/outcome/shim.go index 59b1236c..a569e7a6 100644 --- a/internal/outcome/shim.go +++ b/internal/outcome/shim.go @@ -15,9 +15,11 @@ import ( "hakurei.app/container" "hakurei.app/container/check" + "hakurei.app/container/fhs" "hakurei.app/container/seccomp" "hakurei.app/container/std" "hakurei.app/hst" + "hakurei.app/internal/pipewire" "hakurei.app/message" ) @@ -266,6 +268,79 @@ func shimEntrypoint(k syscallDispatcher) { // bounds and default enforced in finalise.go z.WaitDelay = state.Shim.WaitDelay + if stateParams.pipewirePulsePath != nil { + zpw := container.NewCommand(ctx, msg, stateParams.pipewirePulsePath, pipewirePulseName) + zpw.Hostname = "hakurei-" + pipewirePulseName + zpw.SeccompFlags |= seccomp.AllowMultiarch + zpw.SeccompPresets |= std.PresetStrict + zpw.Env = []string{ + // pipewire SecurityContext socket path + pipewire.Remote + "=" + stateParams.instancePath().Append("pipewire").String(), + // pipewire-pulse socket directory path + envXDGRuntimeDir + "=" + sp.String(), + } + if msg.IsVerbose() { + zpw.Stdin, zpw.Stdout, zpw.Stderr = os.Stdin, os.Stdout, os.Stderr + } + zpw. + Bind(fhs.AbsRoot, fhs.AbsRoot, 0). + Bind(sp.unwrap(), sp.unwrap(), std.BindWritable). + Proc(fhs.AbsProc).Dev(fhs.AbsDev, true) + socketPath := sp.unwrap().Append("pulse", "native") + innerSocketPath := stateParams.runtimeDir.Append("pulse", "native") + + if err := k.containerStart(zpw); err != nil { + sp.destroy() + printMessageError(func(v ...any) { k.fatal(fmt.Sprintln(v...)) }, + "cannot start "+pipewirePulseName+" container:", err) + } + if err := k.containerServe(zpw); err != nil { + sp.destroy() + printMessageError(func(v ...any) { k.fatal(fmt.Sprintln(v...)) }, + "cannot configure "+pipewirePulseName+" container:", err) + } + + done := make(chan error, 1) + k.new(func(k syscallDispatcher, msg message.Msg) { done <- k.containerWait(zpw) }) + + socketTimer := time.NewTimer(shimPipeWireTimeout) + for { + select { + case <-socketTimer.C: + sp.destroy() + k.fatal(pipewirePulseName + " exceeded deadline before socket appeared") + break + + case err := <-done: + var exitError *exec.ExitError + if !errors.As(err, &exitError) { + msg.Verbosef("cannot wait: %v", err) + k.exit(127) + } + sp.destroy() + k.fatal(pipewirePulseName + " " + exitError.ProcessState.String()) + break + + default: + if _, err := k.stat(socketPath.String()); err != nil { + if !errors.Is(err, os.ErrNotExist) { + sp.destroy() + k.fatal(err) + break + } + + time.Sleep(500 * time.Microsecond) + continue + } + } + + break + } + + z.Bind(socketPath, innerSocketPath, 0) + z.Env = append(z.Env, "PULSE_SERVER=unix:"+innerSocketPath.String()) + } + if err := k.containerStart(z); err != nil { var f func(v ...any) if logger := msg.GetLogger(); logger != nil { diff --git a/internal/outcome/sppipewire.go b/internal/outcome/sppipewire.go index fd99d514..8c5760bd 100644 --- a/internal/outcome/sppipewire.go +++ b/internal/outcome/sppipewire.go @@ -41,9 +41,13 @@ func (s *spPipeWireOp) toSystem(state *outcomeStateSys) error { } func (s *spPipeWireOp) toContainer(state *outcomeStateParams) error { + if s.CompatServerPath == nil { innerPath := state.runtimeDir.Append(pipewire.PW_DEFAULT_REMOTE) state.env[pipewire.Remote] = innerPath.String() state.params.Bind(state.instancePath().Append("pipewire"), innerPath, 0) + } + // pipewire-pulse behaviour implemented in shim.go + state.pipewirePulsePath = s.CompatServerPath return nil } |
