diff options
| author | Ophestra <cat@gensokyo.uk> | 2025-11-23 16:20:35 +0900 |
|---|---|---|
| committer | Ophestra <cat@gensokyo.uk> | 2025-11-23 16:20:35 +0900 |
| commit | 3e87187c4c4eb43ed1c9dc1c0c6613e5bed1dc6c (patch) | |
| tree | da6d0ef3c767482d1bf757478375625b583585a6 /internal/pipewire/header.go | |
| parent | b651d95e77c8bfe5c27f2d571fab6e706ef652d2 (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.go | 73 |
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 +} |
