diff options
| author | Ophestra <cat@gensokyo.uk> | 2025-12-03 03:52:17 +0900 |
|---|---|---|
| committer | Ophestra <cat@gensokyo.uk> | 2025-12-03 03:52:17 +0900 |
| commit | 2c0b92771a95693af7f14a70ddeddc5371e73996 (patch) | |
| tree | 38c5e3cf06ecdee79db7d373c68dfbd4fe3b7e6b | |
| parent | 054c91879fccc22466da942462497e048c057a54 (diff) | |
internal/pipewire: relocate constants
This should make things easier to navigate, and possible to fully automatically generate the constants in the future.
Signed-off-by: Ophestra <cat@gensokyo.uk>
| -rw-r--r-- | internal/pipewire/pipewire.go | 354 | ||||
| -rw-r--r-- | internal/pipewire/pipewire_test.go | 53 | ||||
| -rw-r--r-- | internal/pipewire/pod.go | 120 | ||||
| -rw-r--r-- | internal/pipewire/spa.go | 477 | ||||
| -rw-r--r-- | internal/pipewire/spa_test.go | 59 |
5 files changed, 536 insertions, 527 deletions
diff --git a/internal/pipewire/pipewire.go b/internal/pipewire/pipewire.go index c3f57bfd..2046f626 100644 --- a/internal/pipewire/pipewire.go +++ b/internal/pipewire/pipewire.go @@ -652,357 +652,3 @@ func closeReceivedFiles(fds ...int) { // Close frees the underlying buffer and closes the connection. func (ctx *Context) Close() error { ctx.free(); return ctx.conn.Close() } - -/* pipewire/device.h */ - -const ( - PW_TYPE_INTERFACE_Device = PW_TYPE_INFO_INTERFACE_BASE + "Device" - PW_DEVICE_PERM_MASK = PW_PERM_RWXM - PW_VERSION_DEVICE = 3 -) - -const ( - PW_DEVICE_CHANGE_MASK_PROPS = 1 << iota - PW_DEVICE_CHANGE_MASK_PARAMS - - PW_DEVICE_CHANGE_MASK_ALL = 1<<iota - 1 -) - -const ( - PW_DEVICE_EVENT_INFO = iota - PW_DEVICE_EVENT_PARAM - PW_DEVICE_EVENT_NUM - - PW_VERSION_DEVICE_EVENTS = 0 -) - -const ( - PW_DEVICE_METHOD_ADD_LISTENER = iota - PW_DEVICE_METHOD_SUBSCRIBE_PARAMS - PW_DEVICE_METHOD_ENUM_PARAMS - PW_DEVICE_METHOD_SET_PARAM - PW_DEVICE_METHOD_NUM - - PW_VERSION_DEVICE_METHODS = 0 -) - -/* pipewire/factory.h */ - -const ( - PW_TYPE_INTERFACE_Factory = PW_TYPE_INFO_INTERFACE_BASE + "Factory" - PW_FACTORY_PERM_MASK = PW_PERM_R | PW_PERM_M - PW_VERSION_FACTORY = 3 -) - -const ( - PW_FACTORY_CHANGE_MASK_PROPS = 1 << iota - - PW_FACTORY_CHANGE_MASK_ALL = 1<<iota - 1 -) - -const ( - PW_FACTORY_EVENT_INFO = iota - PW_FACTORY_EVENT_NUM - - PW_VERSION_FACTORY_EVENTS = 0 -) - -const ( - PW_FACTORY_METHOD_ADD_LISTENER = iota - PW_FACTORY_METHOD_NUM - - PW_VERSION_FACTORY_METHODS = 0 -) - -/* pipewire/link.h */ - -const ( - PW_TYPE_INTERFACE_Link = PW_TYPE_INFO_INTERFACE_BASE + "Link" - PW_LINK_PERM_MASK = PW_PERM_R | PW_PERM_X - PW_VERSION_LINK = 3 -) - -const ( - PW_LINK_STATE_ERROR = iota - 2 // the link is in error - PW_LINK_STATE_UNLINKED // the link is unlinked - PW_LINK_STATE_INIT // the link is initialized - PW_LINK_STATE_NEGOTIATING // the link is negotiating formats - PW_LINK_STATE_ALLOCATING // the link is allocating buffers - PW_LINK_STATE_PAUSED // the link is paused - PW_LINK_STATE_ACTIVE // the link is active -) - -const ( - PW_LINK_CHANGE_MASK_STATE = (1 << iota) - PW_LINK_CHANGE_MASK_FORMAT - PW_LINK_CHANGE_MASK_PROPS - - PW_LINK_CHANGE_MASK_ALL = 1<<iota - 1 -) - -const ( - PW_LINK_EVENT_INFO = iota - PW_LINK_EVENT_NUM - - PW_VERSION_LINK_EVENTS = 0 -) - -const ( - PW_LINK_METHOD_ADD_LISTENER = iota - PW_LINK_METHOD_NUM - - PW_VERSION_LINK_METHODS = 0 -) - -/* pipewire/module.h */ - -const ( - PW_TYPE_INTERFACE_Module = PW_TYPE_INFO_INTERFACE_BASE + "Module" - PW_MODULE_PERM_MASK = PW_PERM_R | PW_PERM_M - PW_VERSION_MODULE = 3 -) - -const ( - PW_MODULE_CHANGE_MASK_PROPS = 1 << iota - - PW_MODULE_CHANGE_MASK_ALL = 1<<iota - 1 -) - -const ( - PW_MODULE_EVENT_INFO = iota - PW_MODULE_EVENT_NUM - - PW_VERSION_MODULE_EVENTS = 0 -) - -const ( - PW_MODULE_METHOD_ADD_LISTENER = iota - PW_MODULE_METHOD_NUM - - PW_VERSION_MODULE_METHODS = 0 -) - -/* pipewire/impl-module.h */ - -const ( - PIPEWIRE_SYMBOL_MODULE_INIT = "pipewire__module_init" - PIPEWIRE_MODULE_PREFIX = "libpipewire-" - - PW_VERSION_IMPL_MODULE_EVENTS = 0 -) - -/* pipewire/node.h */ - -const ( - PW_TYPE_INTERFACE_Node = PW_TYPE_INFO_INTERFACE_BASE + "Node" - PW_NODE_PERM_MASK = PW_PERM_RWXML - PW_VERSION_NODE = 3 -) - -const ( - PW_NODE_STATE_ERROR = iota - 1 // error state - PW_NODE_STATE_CREATING // the node is being created - PW_NODE_STATE_SUSPENDED // the node is suspended, the device might be closed - PW_NODE_STATE_IDLE // the node is running but there is no active port - PW_NODE_STATE_RUNNING // the node is running -) - -const ( - PW_NODE_CHANGE_MASK_INPUT_PORTS = 1 << iota - PW_NODE_CHANGE_MASK_OUTPUT_PORTS - PW_NODE_CHANGE_MASK_STATE - PW_NODE_CHANGE_MASK_PROPS - PW_NODE_CHANGE_MASK_PARAMS - - PW_NODE_CHANGE_MASK_ALL = 1<<iota - 1 -) - -const ( - PW_NODE_EVENT_INFO = iota - PW_NODE_EVENT_PARAM - PW_NODE_EVENT_NUM - - PW_VERSION_NODE_EVENTS = 0 -) - -const ( - PW_NODE_METHOD_ADD_LISTENER = iota - PW_NODE_METHOD_SUBSCRIBE_PARAMS - PW_NODE_METHOD_ENUM_PARAMS - PW_NODE_METHOD_SET_PARAM - PW_NODE_METHOD_SEND_COMMAND - PW_NODE_METHOD_NUM - - PW_VERSION_NODE_METHODS = 0 -) - -/* pipewire/permission.h */ - -const ( - PW_PERM_R = 0400 // object can be seen and events can be received - PW_PERM_W = 0200 // methods can be called that modify the object - PW_PERM_X = 0100 // methods can be called on the object. The W flag must be present in order to call methods that modify the object. - PW_PERM_M = 0010 // metadata can be set on object, Since 0.3.9 - PW_PERM_L = 0020 // a link can be made between a node that doesn't have permission to see the other node, Since 0.3.77 - - PW_PERM_RW = PW_PERM_R | PW_PERM_W - PW_PERM_RWX = PW_PERM_RW | PW_PERM_X - PW_PERM_RWXM = PW_PERM_RWX | PW_PERM_M - PW_PERM_RWXML = PW_PERM_RWXM | PW_PERM_L - - PW_PERM_ALL = PW_PERM_RWXM - PW_PERM_INVALID Word = 0xffffffff -) - -/* pipewire/port.h */ - -const ( - PW_TYPE_INTERFACE_Port = PW_TYPE_INFO_INTERFACE_BASE + "Port" - PW_PORT_PERM_MASK = PW_PERM_R | PW_PERM_X | PW_PERM_M - PW_VERSION_PORT = 3 -) - -const ( - PW_PORT_CHANGE_MASK_PROPS = 1 << iota - PW_PORT_CHANGE_MASK_PARAMS - - PW_PORT_CHANGE_MASK_ALL = 1<<iota - 1 -) - -const ( - PW_PORT_EVENT_INFO = iota - PW_PORT_EVENT_PARAM - PW_PORT_EVENT_NUM - - PW_VERSION_PORT_EVENTS = 0 -) - -const ( - PW_PORT_METHOD_ADD_LISTENER = iota - PW_PORT_METHOD_SUBSCRIBE_PARAMS - PW_PORT_METHOD_ENUM_PARAMS - PW_PORT_METHOD_NUM - - PW_VERSION_PORT_METHODS = 0 -) - -/* pipewire/extensions/client-node.h */ - -const ( - PW_TYPE_INTERFACE_ClientNode = PW_TYPE_INFO_INTERFACE_BASE + "ClientNode" - PW_VERSION_CLIENT_NODE = 6 - - PW_EXTENSION_MODULE_CLIENT_NODE = PIPEWIRE_MODULE_PREFIX + "module-client-node" -) - -const ( - PW_CLIENT_NODE_EVENT_TRANSPORT = iota - PW_CLIENT_NODE_EVENT_SET_PARAM - PW_CLIENT_NODE_EVENT_SET_IO - PW_CLIENT_NODE_EVENT_EVENT - PW_CLIENT_NODE_EVENT_COMMAND - PW_CLIENT_NODE_EVENT_ADD_PORT - PW_CLIENT_NODE_EVENT_REMOVE_PORT - PW_CLIENT_NODE_EVENT_PORT_SET_PARAM - PW_CLIENT_NODE_EVENT_PORT_USE_BUFFERS - PW_CLIENT_NODE_EVENT_PORT_SET_IO - PW_CLIENT_NODE_EVENT_SET_ACTIVATION - PW_CLIENT_NODE_EVENT_PORT_SET_MIX_INFO - PW_CLIENT_NODE_EVENT_NUM - - PW_VERSION_CLIENT_NODE_EVENTS = 1 -) - -const ( - PW_CLIENT_NODE_METHOD_ADD_LISTENER = iota - PW_CLIENT_NODE_METHOD_GET_NODE - PW_CLIENT_NODE_METHOD_UPDATE - PW_CLIENT_NODE_METHOD_PORT_UPDATE - PW_CLIENT_NODE_METHOD_SET_ACTIVE - PW_CLIENT_NODE_METHOD_EVENT - PW_CLIENT_NODE_METHOD_PORT_BUFFERS - PW_CLIENT_NODE_METHOD_NUM - - PW_VERSION_CLIENT_NODE_METHODS = 0 -) - -const ( - PW_CLIENT_NODE_UPDATE_PARAMS = 1 << iota - PW_CLIENT_NODE_UPDATE_INFO -) - -const ( - PW_CLIENT_NODE_PORT_UPDATE_PARAMS = 1 << iota - PW_CLIENT_NODE_PORT_UPDATE_INFO -) - -/* pipewire/extensions/metadata.h */ - -const ( - PW_TYPE_INTERFACE_Metadata = PW_TYPE_INFO_INTERFACE_BASE + "Metadata" - PW_METADATA_PERM_MASK = PW_PERM_RWX - PW_VERSION_METADATA = 3 - - PW_EXTENSION_MODULE_METADATA = PIPEWIRE_MODULE_PREFIX + "module-metadata" -) - -const ( - PW_METADATA_EVENT_PROPERTY = iota - PW_METADATA_EVENT_NUM - - PW_VERSION_METADATA_EVENTS = 0 -) - -const ( - PW_METADATA_METHOD_ADD_LISTENER = iota - PW_METADATA_METHOD_SET_PROPERTY - PW_METADATA_METHOD_CLEAR - PW_METADATA_METHOD_NUM - - PW_VERSION_METADATA_METHODS = 0 -) - -const ( - PW_KEY_METADATA_NAME = "metadata.name" - PW_KEY_METADATA_VALUES = "metadata.values" -) - -/* pipewire/extensions/profiler.h */ - -const ( - PW_TYPE_INTERFACE_Profiler = PW_TYPE_INFO_INTERFACE_BASE + "Profiler" - PW_VERSION_PROFILER = 3 - PW_PROFILER_PERM_MASK = PW_PERM_R - - PW_EXTENSION_MODULE_PROFILER = PIPEWIRE_MODULE_PREFIX + "module-profiler" -) - -const ( - PW_PROFILER_EVENT_PROFILE = iota - PW_PROFILER_EVENT_NUM - - PW_VERSION_PROFILER_EVENTS = 0 -) - -const ( - PW_PROFILER_METHOD_ADD_LISTENER = iota - PW_PROFILER_METHOD_NUM - - PW_VERSION_PROFILER_METHODS = 0 -) - -const ( - PW_KEY_PROFILER_NAME = "profiler.name" -) - -/* pipewire/type.h */ - -const ( - PW_TYPE_INFO_BASE = "PipeWire:" - - PW_TYPE_INFO_Object = PW_TYPE_INFO_BASE + "Object" - PW_TYPE_INFO_OBJECT_BASE = PW_TYPE_INFO_Object + ":" - - PW_TYPE_INFO_Interface = PW_TYPE_INFO_BASE + "Interface" - PW_TYPE_INFO_INTERFACE_BASE = PW_TYPE_INFO_Interface + ":" -) diff --git a/internal/pipewire/pipewire_test.go b/internal/pipewire/pipewire_test.go index f7df3ab1..f819dff8 100644 --- a/internal/pipewire/pipewire_test.go +++ b/internal/pipewire/pipewire_test.go @@ -1,8 +1,6 @@ package pipewire_test import ( - _ "embed" - "encoding/binary" "fmt" "net" "reflect" @@ -813,57 +811,6 @@ func (conn *stubUnixConn) Close() error { return nil } -var ( - //go:embed testdata/pw-container-00-sendmsg - samplePWContainer00 string - //go:embed testdata/pw-container-01-recvmsg - samplePWContainer01 string - //go:embed testdata/pw-container-03-sendmsg - samplePWContainer03 string - //go:embed testdata/pw-container-04-recvmsg - samplePWContainer04 string - //go:embed testdata/pw-container-06-sendmsg - samplePWContainer06 string - //go:embed testdata/pw-container-07-recvmsg - samplePWContainer07 string - - // samplePWContainer is a collection of messages from the pw-container sample. - samplePWContainer = [...][][3][]byte{ - splitMessages(samplePWContainer00), - splitMessages(samplePWContainer01), - nil, - splitMessages(samplePWContainer03), - splitMessages(samplePWContainer04), - nil, - splitMessages(samplePWContainer06), - splitMessages(samplePWContainer07), - nil, - } -) - -// splitMessages splits concatenated messages into groups of -// header, payload, footer of each individual message. -// splitMessages panics on any decoding error. -func splitMessages(iovec string) (messages [][3][]byte) { - data := []byte(iovec) - messages = make([][3][]byte, 0, 1<<7) - - var header pipewire.Header - for len(data) != 0 { - if err := header.UnmarshalBinary(data[:pipewire.SizeHeader]); err != nil { - panic(err) - } - size := pipewire.SizePrefix + binary.NativeEndian.Uint32(data[pipewire.SizeHeader:]) - messages = append(messages, [3][]byte{ - data[:pipewire.SizeHeader], - data[pipewire.SizeHeader : pipewire.SizeHeader+size], - data[pipewire.SizeHeader+size : pipewire.SizeHeader+header.Size], - }) - data = data[pipewire.SizeHeader+header.Size:] - } - return -} - func TestContextErrors(t *testing.T) { t.Parallel() diff --git a/internal/pipewire/pod.go b/internal/pipewire/pod.go index 9c74bf3e..13d2dc25 100644 --- a/internal/pipewire/pod.go +++ b/internal/pipewire/pod.go @@ -57,41 +57,6 @@ const ( SizeFd = SizeLong ) -/* Basic types */ -const ( - /* POD's can contain a number of basic SPA types: */ - - SPA_TYPE_START = 0x00000 + iota - SPA_TYPE_None // No value or a NULL pointer. - SPA_TYPE_Bool // A boolean value. - SPA_TYPE_Id // An enumerated value. - SPA_TYPE_Int // An integer value, 32-bit. - SPA_TYPE_Long // An integer value, 64-bit. - SPA_TYPE_Float // A floating point value, 32-bit. - SPA_TYPE_Double // A floating point value, 64-bit. - SPA_TYPE_String // A string. - SPA_TYPE_Bytes // A byte array. - SPA_TYPE_Rectangle // A rectangle with width and height. - SPA_TYPE_Fraction // A fraction with numerator and denominator. - SPA_TYPE_Bitmap // An array of bits. - - /* POD's can be grouped together in these container types: */ - - SPA_TYPE_Array // An array of equal sized objects. - SPA_TYPE_Struct // A collection of types and objects. - SPA_TYPE_Object // An object with properties. - SPA_TYPE_Sequence // A timed sequence of POD's. - - /* POD's can also contain some extra types: */ - - SPA_TYPE_Pointer // A typed pointer in memory. - SPA_TYPE_Fd // A file descriptor. - SPA_TYPE_Choice // A choice of values. - SPA_TYPE_Pod // A generic type for the POD itself. - - _SPA_TYPE_LAST // not part of ABI -) - // A KnownSize value has known POD encoded size before serialisation. type KnownSize interface { // Size returns the POD encoded size of the receiver. @@ -580,88 +545,3 @@ func (d *SPADict) UnmarshalPOD(data []byte) (Word, error) { } return wireSize, nil } - -/* Pointers */ -const ( - SPA_TYPE_POINTER_START = 0x10000 + iota - SPA_TYPE_POINTER_Buffer - SPA_TYPE_POINTER_Meta - SPA_TYPE_POINTER_Dict - - _SPA_TYPE_POINTER_LAST // not part of ABI -) - -/* Events */ -const ( - SPA_TYPE_EVENT_START = 0x20000 + iota - SPA_TYPE_EVENT_Device - SPA_TYPE_EVENT_Node - - _SPA_TYPE_EVENT_LAST // not part of ABI -) - -/* Commands */ -const ( - SPA_TYPE_COMMAND_START = 0x30000 + iota - SPA_TYPE_COMMAND_Device - SPA_TYPE_COMMAND_Node - - _SPA_TYPE_COMMAND_LAST // not part of ABI -) - -/* Objects */ -const ( - SPA_TYPE_OBJECT_START = 0x40000 + iota - SPA_TYPE_OBJECT_PropInfo - SPA_TYPE_OBJECT_Props - SPA_TYPE_OBJECT_Format - SPA_TYPE_OBJECT_ParamBuffers - SPA_TYPE_OBJECT_ParamMeta - SPA_TYPE_OBJECT_ParamIO - SPA_TYPE_OBJECT_ParamProfile - SPA_TYPE_OBJECT_ParamPortConfig - SPA_TYPE_OBJECT_ParamRoute - SPA_TYPE_OBJECT_Profiler - SPA_TYPE_OBJECT_ParamLatency - SPA_TYPE_OBJECT_ParamProcessLatency - SPA_TYPE_OBJECT_ParamTag - _SPA_TYPE_OBJECT_LAST // not part of ABI -) - -/* vendor extensions */ -const ( - SPA_TYPE_VENDOR_PipeWire = 0x02000000 - - SPA_TYPE_VENDOR_Other = 0x7f000000 -) - -const ( - SPA_TYPE_INFO_BASE = "Spa:" - - SPA_TYPE_INFO_Flags = SPA_TYPE_INFO_BASE + "Flags" - SPA_TYPE_INFO_FLAGS_BASE = SPA_TYPE_INFO_Flags + ":" - - SPA_TYPE_INFO_Enum = SPA_TYPE_INFO_BASE + "Enum" - SPA_TYPE_INFO_ENUM_BASE = SPA_TYPE_INFO_Enum + ":" - - SPA_TYPE_INFO_Pod = SPA_TYPE_INFO_BASE + "Pod" - SPA_TYPE_INFO_POD_BASE = SPA_TYPE_INFO_Pod + ":" - - SPA_TYPE_INFO_Struct = SPA_TYPE_INFO_POD_BASE + "Struct" - SPA_TYPE_INFO_STRUCT_BASE = SPA_TYPE_INFO_Struct + ":" - - SPA_TYPE_INFO_Object = SPA_TYPE_INFO_POD_BASE + "Object" - SPA_TYPE_INFO_OBJECT_BASE = SPA_TYPE_INFO_Object + ":" - - SPA_TYPE_INFO_Pointer = SPA_TYPE_INFO_BASE + "Pointer" - SPA_TYPE_INFO_POINTER_BASE = SPA_TYPE_INFO_Pointer + ":" - - SPA_TYPE_INFO_Interface = SPA_TYPE_INFO_POINTER_BASE + "Interface" - SPA_TYPE_INFO_INTERFACE_BASE = SPA_TYPE_INFO_Interface + ":" - - SPA_TYPE_INFO_Event = SPA_TYPE_INFO_OBJECT_BASE + "Event" - SPA_TYPE_INFO_EVENT_BASE = SPA_TYPE_INFO_Event + ":" - - SPA_TYPE_INFO_Command = SPA_TYPE_INFO_OBJECT_BASE + "Command" - SPA_TYPE_INFO_COMMAND_BASE = SPA_TYPE_INFO_Command + ":" -) diff --git a/internal/pipewire/spa.go b/internal/pipewire/spa.go new file mode 100644 index 00000000..32d6986f --- /dev/null +++ b/internal/pipewire/spa.go @@ -0,0 +1,477 @@ +package pipewire + +/* Basic types */ +const ( + /* POD's can contain a number of basic SPA types: */ + + SPA_TYPE_START = 0x00000 + iota + SPA_TYPE_None // No value or a NULL pointer. + SPA_TYPE_Bool // A boolean value. + SPA_TYPE_Id // An enumerated value. + SPA_TYPE_Int // An integer value, 32-bit. + SPA_TYPE_Long // An integer value, 64-bit. + SPA_TYPE_Float // A floating point value, 32-bit. + SPA_TYPE_Double // A floating point value, 64-bit. + SPA_TYPE_String // A string. + SPA_TYPE_Bytes // A byte array. + SPA_TYPE_Rectangle // A rectangle with width and height. + SPA_TYPE_Fraction // A fraction with numerator and denominator. + SPA_TYPE_Bitmap // An array of bits. + + /* POD's can be grouped together in these container types: */ + + SPA_TYPE_Array // An array of equal sized objects. + SPA_TYPE_Struct // A collection of types and objects. + SPA_TYPE_Object // An object with properties. + SPA_TYPE_Sequence // A timed sequence of POD's. + + /* POD's can also contain some extra types: */ + + SPA_TYPE_Pointer // A typed pointer in memory. + SPA_TYPE_Fd // A file descriptor. + SPA_TYPE_Choice // A choice of values. + SPA_TYPE_Pod // A generic type for the POD itself. + + _SPA_TYPE_LAST // not part of ABI +) + +/* Pointers */ +const ( + SPA_TYPE_POINTER_START = 0x10000 + iota + SPA_TYPE_POINTER_Buffer + SPA_TYPE_POINTER_Meta + SPA_TYPE_POINTER_Dict + + _SPA_TYPE_POINTER_LAST // not part of ABI +) + +/* Events */ +const ( + SPA_TYPE_EVENT_START = 0x20000 + iota + SPA_TYPE_EVENT_Device + SPA_TYPE_EVENT_Node + + _SPA_TYPE_EVENT_LAST // not part of ABI +) + +/* Commands */ +const ( + SPA_TYPE_COMMAND_START = 0x30000 + iota + SPA_TYPE_COMMAND_Device + SPA_TYPE_COMMAND_Node + + _SPA_TYPE_COMMAND_LAST // not part of ABI +) + +/* Objects */ +const ( + SPA_TYPE_OBJECT_START = 0x40000 + iota + SPA_TYPE_OBJECT_PropInfo + SPA_TYPE_OBJECT_Props + SPA_TYPE_OBJECT_Format + SPA_TYPE_OBJECT_ParamBuffers + SPA_TYPE_OBJECT_ParamMeta + SPA_TYPE_OBJECT_ParamIO + SPA_TYPE_OBJECT_ParamProfile + SPA_TYPE_OBJECT_ParamPortConfig + SPA_TYPE_OBJECT_ParamRoute + SPA_TYPE_OBJECT_Profiler + SPA_TYPE_OBJECT_ParamLatency + SPA_TYPE_OBJECT_ParamProcessLatency + SPA_TYPE_OBJECT_ParamTag + _SPA_TYPE_OBJECT_LAST // not part of ABI +) + +/* vendor extensions */ +const ( + SPA_TYPE_VENDOR_PipeWire = 0x02000000 + + SPA_TYPE_VENDOR_Other = 0x7f000000 +) + +/* spa/include/spa/utils/type.h */ + +const ( + SPA_TYPE_INFO_BASE = "Spa:" + + SPA_TYPE_INFO_Flags = SPA_TYPE_INFO_BASE + "Flags" + SPA_TYPE_INFO_FLAGS_BASE = SPA_TYPE_INFO_Flags + ":" + + SPA_TYPE_INFO_Enum = SPA_TYPE_INFO_BASE + "Enum" + SPA_TYPE_INFO_ENUM_BASE = SPA_TYPE_INFO_Enum + ":" + + SPA_TYPE_INFO_Pod = SPA_TYPE_INFO_BASE + "Pod" + SPA_TYPE_INFO_POD_BASE = SPA_TYPE_INFO_Pod + ":" + + SPA_TYPE_INFO_Struct = SPA_TYPE_INFO_POD_BASE + "Struct" + SPA_TYPE_INFO_STRUCT_BASE = SPA_TYPE_INFO_Struct + ":" + + SPA_TYPE_INFO_Object = SPA_TYPE_INFO_POD_BASE + "Object" + SPA_TYPE_INFO_OBJECT_BASE = SPA_TYPE_INFO_Object + ":" + + SPA_TYPE_INFO_Pointer = SPA_TYPE_INFO_BASE + "Pointer" + SPA_TYPE_INFO_POINTER_BASE = SPA_TYPE_INFO_Pointer + ":" + + SPA_TYPE_INFO_Interface = SPA_TYPE_INFO_POINTER_BASE + "Interface" + SPA_TYPE_INFO_INTERFACE_BASE = SPA_TYPE_INFO_Interface + ":" + + SPA_TYPE_INFO_Event = SPA_TYPE_INFO_OBJECT_BASE + "Event" + SPA_TYPE_INFO_EVENT_BASE = SPA_TYPE_INFO_Event + ":" + + SPA_TYPE_INFO_Command = SPA_TYPE_INFO_OBJECT_BASE + "Command" + SPA_TYPE_INFO_COMMAND_BASE = SPA_TYPE_INFO_Command + ":" +) + +/* pipewire/device.h */ + +const ( + PW_TYPE_INTERFACE_Device = PW_TYPE_INFO_INTERFACE_BASE + "Device" + PW_DEVICE_PERM_MASK = PW_PERM_RWXM + PW_VERSION_DEVICE = 3 +) + +const ( + PW_DEVICE_CHANGE_MASK_PROPS = 1 << iota + PW_DEVICE_CHANGE_MASK_PARAMS + + PW_DEVICE_CHANGE_MASK_ALL = 1<<iota - 1 +) + +const ( + PW_DEVICE_EVENT_INFO = iota + PW_DEVICE_EVENT_PARAM + PW_DEVICE_EVENT_NUM + + PW_VERSION_DEVICE_EVENTS = 0 +) + +const ( + PW_DEVICE_METHOD_ADD_LISTENER = iota + PW_DEVICE_METHOD_SUBSCRIBE_PARAMS + PW_DEVICE_METHOD_ENUM_PARAMS + PW_DEVICE_METHOD_SET_PARAM + PW_DEVICE_METHOD_NUM + + PW_VERSION_DEVICE_METHODS = 0 +) + +/* pipewire/factory.h */ + +const ( + PW_TYPE_INTERFACE_Factory = PW_TYPE_INFO_INTERFACE_BASE + "Factory" + PW_FACTORY_PERM_MASK = PW_PERM_R | PW_PERM_M + PW_VERSION_FACTORY = 3 +) + +const ( + PW_FACTORY_CHANGE_MASK_PROPS = 1 << iota + + PW_FACTORY_CHANGE_MASK_ALL = 1<<iota - 1 +) + +const ( + PW_FACTORY_EVENT_INFO = iota + PW_FACTORY_EVENT_NUM + + PW_VERSION_FACTORY_EVENTS = 0 +) + +const ( + PW_FACTORY_METHOD_ADD_LISTENER = iota + PW_FACTORY_METHOD_NUM + + PW_VERSION_FACTORY_METHODS = 0 +) + +/* pipewire/link.h */ + +const ( + PW_TYPE_INTERFACE_Link = PW_TYPE_INFO_INTERFACE_BASE + "Link" + PW_LINK_PERM_MASK = PW_PERM_R | PW_PERM_X + PW_VERSION_LINK = 3 +) + +const ( + PW_LINK_STATE_ERROR = iota - 2 // the link is in error + PW_LINK_STATE_UNLINKED // the link is unlinked + PW_LINK_STATE_INIT // the link is initialized + PW_LINK_STATE_NEGOTIATING // the link is negotiating formats + PW_LINK_STATE_ALLOCATING // the link is allocating buffers + PW_LINK_STATE_PAUSED // the link is paused + PW_LINK_STATE_ACTIVE // the link is active +) + +const ( + PW_LINK_CHANGE_MASK_STATE = (1 << iota) + PW_LINK_CHANGE_MASK_FORMAT + PW_LINK_CHANGE_MASK_PROPS + + PW_LINK_CHANGE_MASK_ALL = 1<<iota - 1 +) + +const ( + PW_LINK_EVENT_INFO = iota + PW_LINK_EVENT_NUM + + PW_VERSION_LINK_EVENTS = 0 +) + +const ( + PW_LINK_METHOD_ADD_LISTENER = iota + PW_LINK_METHOD_NUM + + PW_VERSION_LINK_METHODS = 0 +) + +/* pipewire/module.h */ + +const ( + PW_TYPE_INTERFACE_Module = PW_TYPE_INFO_INTERFACE_BASE + "Module" + PW_MODULE_PERM_MASK = PW_PERM_R | PW_PERM_M + PW_VERSION_MODULE = 3 +) + +const ( + PW_MODULE_CHANGE_MASK_PROPS = 1 << iota + + PW_MODULE_CHANGE_MASK_ALL = 1<<iota - 1 +) + +const ( + PW_MODULE_EVENT_INFO = iota + PW_MODULE_EVENT_NUM + + PW_VERSION_MODULE_EVENTS = 0 +) + +const ( + PW_MODULE_METHOD_ADD_LISTENER = iota + PW_MODULE_METHOD_NUM + + PW_VERSION_MODULE_METHODS = 0 +) + +/* pipewire/impl-module.h */ + +const ( + PIPEWIRE_SYMBOL_MODULE_INIT = "pipewire__module_init" + PIPEWIRE_MODULE_PREFIX = "libpipewire-" + + PW_VERSION_IMPL_MODULE_EVENTS = 0 +) + +/* pipewire/node.h */ + +const ( + PW_TYPE_INTERFACE_Node = PW_TYPE_INFO_INTERFACE_BASE + "Node" + PW_NODE_PERM_MASK = PW_PERM_RWXML + PW_VERSION_NODE = 3 +) + +const ( + PW_NODE_STATE_ERROR = iota - 1 // error state + PW_NODE_STATE_CREATING // the node is being created + PW_NODE_STATE_SUSPENDED // the node is suspended, the device might be closed + PW_NODE_STATE_IDLE // the node is running but there is no active port + PW_NODE_STATE_RUNNING // the node is running +) + +const ( + PW_NODE_CHANGE_MASK_INPUT_PORTS = 1 << iota + PW_NODE_CHANGE_MASK_OUTPUT_PORTS + PW_NODE_CHANGE_MASK_STATE + PW_NODE_CHANGE_MASK_PROPS + PW_NODE_CHANGE_MASK_PARAMS + + PW_NODE_CHANGE_MASK_ALL = 1<<iota - 1 +) + +const ( + PW_NODE_EVENT_INFO = iota + PW_NODE_EVENT_PARAM + PW_NODE_EVENT_NUM + + PW_VERSION_NODE_EVENTS = 0 +) + +const ( + PW_NODE_METHOD_ADD_LISTENER = iota + PW_NODE_METHOD_SUBSCRIBE_PARAMS + PW_NODE_METHOD_ENUM_PARAMS + PW_NODE_METHOD_SET_PARAM + PW_NODE_METHOD_SEND_COMMAND + PW_NODE_METHOD_NUM + + PW_VERSION_NODE_METHODS = 0 +) + +/* pipewire/permission.h */ + +const ( + PW_PERM_R = 0400 // object can be seen and events can be received + PW_PERM_W = 0200 // methods can be called that modify the object + PW_PERM_X = 0100 // methods can be called on the object. The W flag must be present in order to call methods that modify the object. + PW_PERM_M = 0010 // metadata can be set on object, Since 0.3.9 + PW_PERM_L = 0020 // a link can be made between a node that doesn't have permission to see the other node, Since 0.3.77 + + PW_PERM_RW = PW_PERM_R | PW_PERM_W + PW_PERM_RWX = PW_PERM_RW | PW_PERM_X + PW_PERM_RWXM = PW_PERM_RWX | PW_PERM_M + PW_PERM_RWXML = PW_PERM_RWXM | PW_PERM_L + + PW_PERM_ALL = PW_PERM_RWXM + PW_PERM_INVALID Word = 0xffffffff +) + +/* pipewire/port.h */ + +const ( + PW_TYPE_INTERFACE_Port = PW_TYPE_INFO_INTERFACE_BASE + "Port" + PW_PORT_PERM_MASK = PW_PERM_R | PW_PERM_X | PW_PERM_M + PW_VERSION_PORT = 3 +) + +const ( + PW_PORT_CHANGE_MASK_PROPS = 1 << iota + PW_PORT_CHANGE_MASK_PARAMS + + PW_PORT_CHANGE_MASK_ALL = 1<<iota - 1 +) + +const ( + PW_PORT_EVENT_INFO = iota + PW_PORT_EVENT_PARAM + PW_PORT_EVENT_NUM + + PW_VERSION_PORT_EVENTS = 0 +) + +const ( + PW_PORT_METHOD_ADD_LISTENER = iota + PW_PORT_METHOD_SUBSCRIBE_PARAMS + PW_PORT_METHOD_ENUM_PARAMS + PW_PORT_METHOD_NUM + + PW_VERSION_PORT_METHODS = 0 +) + +/* pipewire/extensions/client-node.h */ + +const ( + PW_TYPE_INTERFACE_ClientNode = PW_TYPE_INFO_INTERFACE_BASE + "ClientNode" + PW_VERSION_CLIENT_NODE = 6 + + PW_EXTENSION_MODULE_CLIENT_NODE = PIPEWIRE_MODULE_PREFIX + "module-client-node" +) + +const ( + PW_CLIENT_NODE_EVENT_TRANSPORT = iota + PW_CLIENT_NODE_EVENT_SET_PARAM + PW_CLIENT_NODE_EVENT_SET_IO + PW_CLIENT_NODE_EVENT_EVENT + PW_CLIENT_NODE_EVENT_COMMAND + PW_CLIENT_NODE_EVENT_ADD_PORT + PW_CLIENT_NODE_EVENT_REMOVE_PORT + PW_CLIENT_NODE_EVENT_PORT_SET_PARAM + PW_CLIENT_NODE_EVENT_PORT_USE_BUFFERS + PW_CLIENT_NODE_EVENT_PORT_SET_IO + PW_CLIENT_NODE_EVENT_SET_ACTIVATION + PW_CLIENT_NODE_EVENT_PORT_SET_MIX_INFO + PW_CLIENT_NODE_EVENT_NUM + + PW_VERSION_CLIENT_NODE_EVENTS = 1 +) + +const ( + PW_CLIENT_NODE_METHOD_ADD_LISTENER = iota + PW_CLIENT_NODE_METHOD_GET_NODE + PW_CLIENT_NODE_METHOD_UPDATE + PW_CLIENT_NODE_METHOD_PORT_UPDATE + PW_CLIENT_NODE_METHOD_SET_ACTIVE + PW_CLIENT_NODE_METHOD_EVENT + PW_CLIENT_NODE_METHOD_PORT_BUFFERS + PW_CLIENT_NODE_METHOD_NUM + + PW_VERSION_CLIENT_NODE_METHODS = 0 +) + +const ( + PW_CLIENT_NODE_UPDATE_PARAMS = 1 << iota + PW_CLIENT_NODE_UPDATE_INFO +) + +const ( + PW_CLIENT_NODE_PORT_UPDATE_PARAMS = 1 << iota + PW_CLIENT_NODE_PORT_UPDATE_INFO +) + +/* pipewire/extensions/metadata.h */ + +const ( + PW_TYPE_INTERFACE_Metadata = PW_TYPE_INFO_INTERFACE_BASE + "Metadata" + PW_METADATA_PERM_MASK = PW_PERM_RWX + PW_VERSION_METADATA = 3 + + PW_EXTENSION_MODULE_METADATA = PIPEWIRE_MODULE_PREFIX + "module-metadata" +) + +const ( + PW_METADATA_EVENT_PROPERTY = iota + PW_METADATA_EVENT_NUM + + PW_VERSION_METADATA_EVENTS = 0 +) + +const ( + PW_METADATA_METHOD_ADD_LISTENER = iota + PW_METADATA_METHOD_SET_PROPERTY + PW_METADATA_METHOD_CLEAR + PW_METADATA_METHOD_NUM + + PW_VERSION_METADATA_METHODS = 0 +) + +const ( + PW_KEY_METADATA_NAME = "metadata.name" + PW_KEY_METADATA_VALUES = "metadata.values" +) + +/* pipewire/extensions/profiler.h */ + +const ( + PW_TYPE_INTERFACE_Profiler = PW_TYPE_INFO_INTERFACE_BASE + "Profiler" + PW_VERSION_PROFILER = 3 + PW_PROFILER_PERM_MASK = PW_PERM_R + + PW_EXTENSION_MODULE_PROFILER = PIPEWIRE_MODULE_PREFIX + "module-profiler" +) + +const ( + PW_PROFILER_EVENT_PROFILE = iota + PW_PROFILER_EVENT_NUM + + PW_VERSION_PROFILER_EVENTS = 0 +) + +const ( + PW_PROFILER_METHOD_ADD_LISTENER = iota + PW_PROFILER_METHOD_NUM + + PW_VERSION_PROFILER_METHODS = 0 +) + +const ( + PW_KEY_PROFILER_NAME = "profiler.name" +) + +/* pipewire/type.h */ + +const ( + PW_TYPE_INFO_BASE = "PipeWire:" + + PW_TYPE_INFO_Object = PW_TYPE_INFO_BASE + "Object" + PW_TYPE_INFO_OBJECT_BASE = PW_TYPE_INFO_Object + ":" + + PW_TYPE_INFO_Interface = PW_TYPE_INFO_BASE + "Interface" + PW_TYPE_INFO_INTERFACE_BASE = PW_TYPE_INFO_Interface + ":" +) diff --git a/internal/pipewire/spa_test.go b/internal/pipewire/spa_test.go new file mode 100644 index 00000000..6bf7794b --- /dev/null +++ b/internal/pipewire/spa_test.go @@ -0,0 +1,59 @@ +package pipewire_test + +import ( + _ "embed" + "encoding/binary" + + "hakurei.app/internal/pipewire" +) + +// splitMessages splits concatenated messages into groups of +// header, payload, footer of each individual message. +// splitMessages panics on any decoding error. +func splitMessages(iovec string) (messages [][3][]byte) { + data := []byte(iovec) + messages = make([][3][]byte, 0, 1<<7) + + var header pipewire.Header + for len(data) != 0 { + if err := header.UnmarshalBinary(data[:pipewire.SizeHeader]); err != nil { + panic(err) + } + size := pipewire.SizePrefix + binary.NativeEndian.Uint32(data[pipewire.SizeHeader:]) + messages = append(messages, [3][]byte{ + data[:pipewire.SizeHeader], + data[pipewire.SizeHeader : pipewire.SizeHeader+size], + data[pipewire.SizeHeader+size : pipewire.SizeHeader+header.Size], + }) + data = data[pipewire.SizeHeader+header.Size:] + } + return +} + +var ( + //go:embed testdata/pw-container-00-sendmsg + samplePWContainer00 string + //go:embed testdata/pw-container-01-recvmsg + samplePWContainer01 string + //go:embed testdata/pw-container-03-sendmsg + samplePWContainer03 string + //go:embed testdata/pw-container-04-recvmsg + samplePWContainer04 string + //go:embed testdata/pw-container-06-sendmsg + samplePWContainer06 string + //go:embed testdata/pw-container-07-recvmsg + samplePWContainer07 string + + // samplePWContainer is a collection of messages from the pw-container sample. + samplePWContainer = [...][][3][]byte{ + splitMessages(samplePWContainer00), + splitMessages(samplePWContainer01), + nil, + splitMessages(samplePWContainer03), + splitMessages(samplePWContainer04), + nil, + splitMessages(samplePWContainer06), + splitMessages(samplePWContainer07), + nil, + } +) |
