aboutsummaryrefslogtreecommitdiffhomepage
path: root/internal/pipewire/header.go
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2025-11-23 16:20:35 +0900
committerOphestra <cat@gensokyo.uk>2025-11-23 16:20:35 +0900
commit3e87187c4c4eb43ed1c9dc1c0c6613e5bed1dc6c (patch)
treeda6d0ef3c767482d1bf757478375625b583585a6 /internal/pipewire/header.go
parentb651d95e77c8bfe5c27f2d571fab6e706ef652d2 (diff)
internal/pipewire: implement message header
Test cases are from interactions between pw-container and PipeWire. Results are validated against corresponding body. Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'internal/pipewire/header.go')
-rw-r--r--internal/pipewire/header.go73
1 files changed, 73 insertions, 0 deletions
diff --git a/internal/pipewire/header.go b/internal/pipewire/header.go
new file mode 100644
index 00000000..ceb4cde6
--- /dev/null
+++ b/internal/pipewire/header.go
@@ -0,0 +1,73 @@
+package pipewire
+
+import (
+ "encoding/binary"
+ "errors"
+)
+
+const (
+ // HeaderSize is the fixed size of [Header].
+ HeaderSize = 16
+ // SizeMax is the largest value of [Header.Size] that can be represented in its 3-byte segment.
+ SizeMax = 0x00ffffff
+)
+
+var (
+ // ErrSizeRange indicates that the value of [Header.Size] cannot be represented in its 3-byte segment.
+ ErrSizeRange = errors.New("size out of range")
+ // ErrBadHeader indicates that the header slice does not have length [HeaderSize].
+ ErrBadHeader = errors.New("incorrect header size")
+)
+
+// A Header is the fixed-size message header described in protocol native.
+type Header struct {
+ // The message id this is the destination resource/proxy id.
+ ID uint32 `json:"Id"`
+ // The opcode on the resource/proxy interface.
+ Opcode byte `json:"opcode"`
+ // The size of the payload and optional footer of the message.
+ // Note: this value is only 24 bits long in the format.
+ Size uint32 `json:"size"`
+ // An increasing sequence number for each message.
+ Sequence uint32 `json:"seq"`
+ // Number of file descriptors in this message.
+ FileCount uint32 `json:"n_fds"`
+}
+
+// append appends the protocol native message header to data.
+//
+// Callers must perform bounds check on [Header.Size].
+func (h *Header) append(data []byte) []byte {
+ data = binary.NativeEndian.AppendUint32(data, h.ID)
+ data = binary.NativeEndian.AppendUint32(data, uint32(h.Opcode)<<24|h.Size)
+ data = binary.NativeEndian.AppendUint32(data, h.Sequence)
+ data = binary.NativeEndian.AppendUint32(data, h.FileCount)
+ return data
+}
+
+// MarshalBinary encodes the protocol native message header.
+func (h *Header) MarshalBinary() (data []byte, err error) {
+ if h.Size&^SizeMax != 0 {
+ return nil, ErrSizeRange
+ }
+ return h.append(make([]byte, 0, HeaderSize)), nil
+}
+
+// unmarshalBinary decodes the protocol native message header.
+func (h *Header) unmarshalBinary(data [HeaderSize]byte) {
+ h.ID = binary.NativeEndian.Uint32(data[0:4])
+ h.Size = binary.NativeEndian.Uint32(data[4:8])
+ h.Opcode = byte(h.Size >> 24)
+ h.Size &= SizeMax
+ h.Sequence = binary.NativeEndian.Uint32(data[8:])
+ h.FileCount = binary.NativeEndian.Uint32(data[12:])
+}
+
+// UnmarshalBinary decodes the protocol native message header.
+func (h *Header) UnmarshalBinary(data []byte) error {
+ if len(data) != HeaderSize {
+ return ErrBadHeader
+ }
+ h.unmarshalBinary(([HeaderSize]byte)(data))
+ return nil
+}