diff options
Diffstat (limited to 'internal/pipewire/core.go')
| -rw-r--r-- | internal/pipewire/core.go | 72 |
1 files changed, 72 insertions, 0 deletions
diff --git a/internal/pipewire/core.go b/internal/pipewire/core.go index 6adcac1d..517ef2c3 100644 --- a/internal/pipewire/core.go +++ b/internal/pipewire/core.go @@ -382,6 +382,41 @@ func (s *removable) mustCheckDestroy() { } } +// destructible is embedded by proxies that can be targeted by the [CoreRemoveId] event and the +// [CoreDestroy] method and requires no cleanup. destructible purposefully does not override +// removable.mustCheckDestroy because it is used by unexported methods called during event handling +// and are exempt from the destruction check. +type destructible struct { + destroyed bool + + removable +} + +// checkDestroy overrides removable.checkDestroy to also check the destroyed field. +func (s *destructible) checkDestroy() error { + if s.destroyed { + return ErrProxyDestroyed + } + if err := s.removable.checkDestroy(); err != nil { + return err + } + return nil +} + +// destroy calls removable.checkDestroy then queues a [CoreDestroy] event if it succeeds. +func (s *destructible) destroy(ctx *Context, id Int) error { + if err := s.checkDestroy(); err != nil { + return err + } + l := len(ctx.pendingDestruction) + ctx.pendingDestruction[id] = struct{}{} + if len(ctx.pendingDestruction) != l+1 { + return ErrProxyDestroyed + } + s.destroyed = true + return ctx.GetCore().destroy(id) +} + // An InconsistentIdError describes an inconsistent state where the server claims an impossible // proxy or global id. This is only generated by the [CoreBoundProps] event. type InconsistentIdError struct { @@ -504,6 +539,10 @@ func (core *Core) Sync() error { core.ctx.closeReceivedFiles() return &ProxyFatalError{Err: UnacknowledgedProxyError(slices.Collect(maps.Keys(core.ctx.pendingIds))), ProxyErrs: core.ctx.cloneAsProxyErrors()} } + if len(core.ctx.pendingDestruction) != 0 { + core.ctx.closeReceivedFiles() + return &ProxyFatalError{Err: UnacknowledgedProxyDestructionError(slices.Collect(maps.Keys(core.ctx.pendingDestruction))), ProxyErrs: core.ctx.cloneAsProxyErrors()} + } return core.ctx.doSyncComplete() } @@ -624,6 +663,37 @@ func (core *Core) createObject(factoryName, typeName String, version Int, props ) } +// CoreDestroy is sent when the client requests to destroy an object. +type CoreDestroy struct { + // The proxy id of the object to destroy. + ID Int `json:"id"` +} + +// Opcode satisfies [Message] with a constant value. +func (c *CoreDestroy) Opcode() byte { return PW_CORE_METHOD_DESTROY } + +// FileCount satisfies [Message] with a constant value. +func (c *CoreDestroy) FileCount() Int { return 0 } + +// Size satisfies [KnownSize] with a constant value. +func (c *CoreDestroy) Size() Word { return SizePrefix + Size(SizeInt) } + +// MarshalBinary satisfies [encoding.BinaryMarshaler] via [Marshal]. +func (c *CoreDestroy) MarshalBinary() ([]byte, error) { return Marshal(c) } + +// UnmarshalBinary satisfies [encoding.BinaryUnmarshaler] via [Unmarshal]. +func (c *CoreDestroy) UnmarshalBinary(data []byte) error { return Unmarshal(data, c) } + +// destroy queues a [CoreDestroy] message for the PipeWire server. +// This is not safe to use directly, callers should use the exported method +// on the proxy implementation instead. +func (core *Core) destroy(id Int) error { + return core.ctx.writeMessage( + PW_ID_CORE, + &CoreDestroy{id}, + ) +} + // A RegistryGlobal event is emitted to notify a client about a new global object. type RegistryGlobal struct { // The global id. @@ -889,6 +959,8 @@ func (core *Core) consume(opcode byte, files []int, unmarshal func(v any)) error panic(&UnknownProxyIdError[*CoreRemoveId]{Id: coreRemoveId.ID, Event: &coreRemoveId}) } else { delete(core.ctx.proxy, coreRemoveId.ID) + // not always populated so this is not checked + delete(core.ctx.pendingDestruction, coreRemoveId.ID) return proxy.remove() } |
