All checks were successful
Test / Create distribution (push) Successful in 36s
Test / Sandbox (push) Successful in 2m35s
Test / Sandbox (race detector) (push) Successful in 4m45s
Test / Hakurei (push) Successful in 5m0s
Test / Hpkg (push) Successful in 5m7s
Test / Hakurei (race detector) (push) Successful in 6m37s
Test / Flake checks (push) Successful in 1m34s
This consumes the entire sample, is validated to send identical messages and correctly handle received messages. Signed-off-by: Ophestra <cat@gensokyo.uk>
865 lines
29 KiB
Go
865 lines
29 KiB
Go
package pipewire_test
|
|
|
|
import (
|
|
_ "embed"
|
|
"encoding/binary"
|
|
"fmt"
|
|
"net"
|
|
"reflect"
|
|
. "syscall"
|
|
"testing"
|
|
"time"
|
|
|
|
"hakurei.app/internal/pipewire"
|
|
)
|
|
|
|
func TestContext(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var (
|
|
// Underlying connection stub holding test data.
|
|
conn = stubUnixConn{samples: []stubUnixConnSample{
|
|
{SYS_SENDMSG, samplePWContainer00, MSG_DONTWAIT | MSG_NOSIGNAL, nil, 0},
|
|
{SYS_RECVMSG, samplePWContainer01, MSG_DONTWAIT | MSG_CMSG_CLOEXEC, nil, 0},
|
|
{SYS_RECVMSG, "", MSG_DONTWAIT | MSG_CMSG_CLOEXEC, nil, EAGAIN},
|
|
{SYS_SENDMSG, samplePWContainer03, MSG_DONTWAIT | MSG_NOSIGNAL, nil, 0},
|
|
{SYS_RECVMSG, samplePWContainer04, MSG_DONTWAIT | MSG_CMSG_CLOEXEC, nil, 0},
|
|
{SYS_RECVMSG, "", MSG_DONTWAIT | MSG_CMSG_CLOEXEC, nil, EAGAIN},
|
|
{SYS_SENDMSG, samplePWContainer06, MSG_DONTWAIT | MSG_NOSIGNAL, []int{20, 21}, 0},
|
|
{SYS_RECVMSG, samplePWContainer07, MSG_DONTWAIT | MSG_CMSG_CLOEXEC, nil, 0},
|
|
{SYS_RECVMSG, "", MSG_DONTWAIT | MSG_CMSG_CLOEXEC, nil, EAGAIN},
|
|
}}
|
|
|
|
// Context instance under testing.
|
|
ctx = pipewire.MustNew(&conn, pipewire.SPADict{
|
|
{Key: "remote.intention", Value: "manager"},
|
|
{Key: "application.name", Value: "pw-container"},
|
|
{Key: "application.process.binary", Value: "pw-container"},
|
|
{Key: "application.language", Value: "en_US.UTF-8"},
|
|
{Key: "application.process.id", Value: "1443"},
|
|
{Key: "application.process.user", Value: "alice"},
|
|
{Key: "application.process.host", Value: "nixos"},
|
|
{Key: "application.process.session-id", Value: "1"},
|
|
{Key: "window.x11.display", Value: ":0"},
|
|
{Key: "cpu.vm.name", Value: "qemu"},
|
|
{Key: "log.level", Value: "0"},
|
|
{Key: "cpu.max-align", Value: "32"},
|
|
{Key: "default.clock.rate", Value: "48000"},
|
|
{Key: "default.clock.quantum", Value: "1024"},
|
|
{Key: "default.clock.min-quantum", Value: "32"},
|
|
{Key: "default.clock.max-quantum", Value: "2048"},
|
|
{Key: "default.clock.quantum-limit", Value: "8192"},
|
|
{Key: "default.clock.quantum-floor", Value: "4"},
|
|
{Key: "default.video.width", Value: "640"},
|
|
{Key: "default.video.height", Value: "480"},
|
|
{Key: "default.video.rate.num", Value: "25"},
|
|
{Key: "default.video.rate.denom", Value: "1"},
|
|
{Key: "clock.power-of-two-quantum", Value: "true"},
|
|
{Key: "link.max-buffers", Value: "64"},
|
|
{Key: "mem.warn-mlock", Value: "false"},
|
|
{Key: "mem.allow-mlock", Value: "true"},
|
|
{Key: "settings.check-quantum", Value: "false"},
|
|
{Key: "settings.check-rate", Value: "false"},
|
|
{Key: "core.version", Value: "1.4.7"},
|
|
{Key: "core.name", Value: "pipewire-alice-1443"},
|
|
})
|
|
)
|
|
|
|
var registry *pipewire.Registry
|
|
const wantRegistryId = 2
|
|
if r, err := ctx.GetRegistry(); err != nil {
|
|
t.Fatalf("GetRegistry: error = %v", err)
|
|
} else {
|
|
if r.ID != wantRegistryId {
|
|
t.Fatalf("GetRegistry: ID = %d, want %d", r.ID, wantRegistryId)
|
|
}
|
|
registry = r
|
|
}
|
|
if err := ctx.GetCore().Sync(); err != nil {
|
|
t.Fatalf("Sync: error = %v", err)
|
|
}
|
|
|
|
wantCoreInfo0 := pipewire.CoreInfo{
|
|
ID: 0,
|
|
Cookie: -2069267610,
|
|
UserName: "alice",
|
|
HostName: "nixos",
|
|
Version: "1.4.7",
|
|
Name: "pipewire-0",
|
|
ChangeMask: pipewire.PW_CORE_CHANGE_MASK_PROPS,
|
|
Properties: &pipewire.SPADict{
|
|
{Key: "config.name", Value: "pipewire.conf"},
|
|
{Key: "application.name", Value: "pipewire"},
|
|
{Key: "application.process.binary", Value: "pipewire"},
|
|
{Key: "application.language", Value: "en_US.UTF-8"},
|
|
{Key: "application.process.id", Value: "1446"},
|
|
{Key: "application.process.user", Value: "alice"},
|
|
{Key: "application.process.host", Value: "nixos"},
|
|
{Key: "window.x11.display", Value: ":0"},
|
|
{Key: "cpu.vm.name", Value: "qemu"},
|
|
{Key: "link.max-buffers", Value: "16"},
|
|
{Key: "core.daemon", Value: "true"},
|
|
{Key: "core.name", Value: "pipewire-0"},
|
|
{Key: "default.clock.min-quantum", Value: "1024"},
|
|
{Key: "cpu.max-align", Value: "32"},
|
|
{Key: "default.clock.rate", Value: "48000"},
|
|
{Key: "default.clock.quantum", Value: "1024"},
|
|
{Key: "default.clock.max-quantum", Value: "2048"},
|
|
{Key: "default.clock.quantum-limit", Value: "8192"},
|
|
{Key: "default.clock.quantum-floor", Value: "4"},
|
|
{Key: "default.video.width", Value: "640"},
|
|
{Key: "default.video.height", Value: "480"},
|
|
{Key: "default.video.rate.num", Value: "25"},
|
|
{Key: "default.video.rate.denom", Value: "1"},
|
|
{Key: "log.level", Value: "2"},
|
|
{Key: "clock.power-of-two-quantum", Value: "true"},
|
|
{Key: "mem.warn-mlock", Value: "false"},
|
|
{Key: "mem.allow-mlock", Value: "true"},
|
|
{Key: "settings.check-quantum", Value: "false"},
|
|
{Key: "settings.check-rate", Value: "false"},
|
|
{Key: "object.id", Value: "0"},
|
|
{Key: "object.serial", Value: "0"}},
|
|
}
|
|
|
|
wantClient0 := pipewire.Client{
|
|
Info: &pipewire.ClientInfo{
|
|
ID: 34,
|
|
ChangeMask: pipewire.PW_CLIENT_CHANGE_MASK_PROPS,
|
|
Properties: &pipewire.SPADict{
|
|
{Key: "pipewire.protocol", Value: "protocol-native"},
|
|
{Key: "core.name", Value: "pipewire-alice-1443"},
|
|
{Key: "pipewire.sec.socket", Value: "pipewire-0-manager"},
|
|
{Key: "pipewire.sec.pid", Value: "1443"},
|
|
{Key: "pipewire.sec.uid", Value: "1000"},
|
|
{Key: "pipewire.sec.gid", Value: "100"},
|
|
{Key: "module.id", Value: "2"},
|
|
{Key: "object.id", Value: "34"},
|
|
{Key: "object.serial", Value: "34"},
|
|
{Key: "remote.intention", Value: "manager"},
|
|
{Key: "application.name", Value: "pw-container"},
|
|
{Key: "application.process.binary", Value: "pw-container"},
|
|
{Key: "application.language", Value: "en_US.UTF-8"},
|
|
{Key: "application.process.id", Value: "1443"},
|
|
{Key: "application.process.user", Value: "alice"},
|
|
{Key: "application.process.host", Value: "nixos"},
|
|
{Key: "application.process.session-id", Value: "1"},
|
|
{Key: "window.x11.display", Value: ":0"},
|
|
{Key: "cpu.vm.name", Value: "qemu"},
|
|
{Key: "log.level", Value: "0"},
|
|
{Key: "cpu.max-align", Value: "32"},
|
|
{Key: "default.clock.rate", Value: "48000"},
|
|
{Key: "default.clock.quantum", Value: "1024"},
|
|
{Key: "default.clock.min-quantum", Value: "32"},
|
|
{Key: "default.clock.max-quantum", Value: "2048"},
|
|
{Key: "default.clock.quantum-limit", Value: "8192"},
|
|
{Key: "default.clock.quantum-floor", Value: "4"},
|
|
{Key: "default.video.width", Value: "640"},
|
|
{Key: "default.video.height", Value: "480"},
|
|
{Key: "default.video.rate.num", Value: "25"},
|
|
{Key: "default.video.rate.denom", Value: "1"},
|
|
{Key: "clock.power-of-two-quantum", Value: "true"},
|
|
{Key: "link.max-buffers", Value: "64"},
|
|
{Key: "mem.warn-mlock", Value: "false"},
|
|
{Key: "mem.allow-mlock", Value: "true"},
|
|
{Key: "settings.check-quantum", Value: "false"},
|
|
{Key: "settings.check-rate", Value: "false"},
|
|
{Key: "core.version", Value: "1.4.7"},
|
|
{Key: "pipewire.access", Value: "unrestricted"},
|
|
},
|
|
},
|
|
Properties: pipewire.SPADict{
|
|
{Key: "object.serial", Value: "34"},
|
|
{Key: "module.id", Value: "2"},
|
|
{Key: "pipewire.protocol", Value: "protocol-native"},
|
|
{Key: "pipewire.sec.pid", Value: "1443"},
|
|
{Key: "pipewire.sec.uid", Value: "1000"},
|
|
{Key: "pipewire.sec.gid", Value: "100"},
|
|
{Key: "pipewire.sec.socket", Value: "pipewire-0-manager"},
|
|
},
|
|
}
|
|
|
|
wantRegistry0 := pipewire.Registry{
|
|
ID: wantRegistryId,
|
|
Objects: map[pipewire.Int]pipewire.RegistryGlobal{
|
|
pipewire.PW_ID_CORE: {
|
|
ID: pipewire.PW_ID_CORE,
|
|
Permissions: pipewire.PW_CORE_PERM_MASK,
|
|
Type: pipewire.PW_TYPE_INTERFACE_Core,
|
|
Version: pipewire.PW_VERSION_CORE,
|
|
Properties: &pipewire.SPADict{
|
|
{Key: "object.serial", Value: "0"},
|
|
{Key: "core.name", Value: "pipewire-0"},
|
|
},
|
|
},
|
|
|
|
1: {
|
|
ID: 1,
|
|
Permissions: pipewire.PW_MODULE_PERM_MASK,
|
|
Type: pipewire.PW_TYPE_INTERFACE_Module,
|
|
Version: pipewire.PW_VERSION_MODULE,
|
|
Properties: &pipewire.SPADict{
|
|
{Key: "object.serial", Value: "1"},
|
|
{Key: "module.name", Value: pipewire.PIPEWIRE_MODULE_PREFIX + "module-rt"},
|
|
},
|
|
},
|
|
|
|
3: {
|
|
ID: 3,
|
|
Permissions: pipewire.PW_SECURITY_CONTEXT_PERM_MASK,
|
|
Type: pipewire.PW_TYPE_INTERFACE_SecurityContext,
|
|
Version: pipewire.PW_VERSION_SECURITY_CONTEXT,
|
|
Properties: &pipewire.SPADict{
|
|
{Key: "object.serial", Value: "3"},
|
|
},
|
|
},
|
|
|
|
2: {
|
|
ID: 2,
|
|
Permissions: pipewire.PW_MODULE_PERM_MASK,
|
|
Type: pipewire.PW_TYPE_INTERFACE_Module,
|
|
Version: pipewire.PW_VERSION_MODULE,
|
|
Properties: &pipewire.SPADict{
|
|
{Key: "object.serial", Value: "2"},
|
|
{Key: "module.name", Value: pipewire.PIPEWIRE_MODULE_PREFIX + "module-protocol-native"},
|
|
},
|
|
},
|
|
|
|
5: {
|
|
ID: 5,
|
|
Permissions: pipewire.PW_PROFILER_PERM_MASK,
|
|
Type: pipewire.PW_TYPE_INTERFACE_Profiler,
|
|
Version: pipewire.PW_VERSION_PROFILER,
|
|
Properties: &pipewire.SPADict{
|
|
{Key: "object.serial", Value: "5"},
|
|
},
|
|
},
|
|
|
|
4: {
|
|
ID: 4,
|
|
Permissions: pipewire.PW_MODULE_PERM_MASK,
|
|
Type: pipewire.PW_TYPE_INTERFACE_Module,
|
|
Version: pipewire.PW_VERSION_MODULE,
|
|
Properties: &pipewire.SPADict{
|
|
{Key: "object.serial", Value: "4"},
|
|
{Key: "module.name", Value: pipewire.PIPEWIRE_MODULE_PREFIX + "module-profiler"},
|
|
},
|
|
},
|
|
|
|
6: {
|
|
ID: 6,
|
|
Permissions: pipewire.PW_MODULE_PERM_MASK,
|
|
Type: pipewire.PW_TYPE_INTERFACE_Module,
|
|
Version: pipewire.PW_VERSION_MODULE,
|
|
Properties: &pipewire.SPADict{
|
|
{Key: "object.serial", Value: "6"},
|
|
{Key: "module.name", Value: pipewire.PIPEWIRE_MODULE_PREFIX + "module-metadata"},
|
|
},
|
|
},
|
|
|
|
7: {
|
|
ID: 7,
|
|
Permissions: pipewire.PW_FACTORY_PERM_MASK,
|
|
Type: pipewire.PW_TYPE_INTERFACE_Factory,
|
|
Version: pipewire.PW_VERSION_FACTORY,
|
|
Properties: &pipewire.SPADict{
|
|
{Key: "object.serial", Value: "7"},
|
|
{Key: "module.id", Value: "6"},
|
|
{Key: "factory.name", Value: "metadata"},
|
|
{Key: "factory.type.name", Value: pipewire.PW_TYPE_INTERFACE_Metadata},
|
|
{Key: "factory.type.version", Value: "3"},
|
|
},
|
|
},
|
|
|
|
8: {
|
|
ID: 8,
|
|
Permissions: pipewire.PW_MODULE_PERM_MASK,
|
|
Type: pipewire.PW_TYPE_INTERFACE_Module,
|
|
Version: pipewire.PW_VERSION_MODULE,
|
|
Properties: &pipewire.SPADict{
|
|
{Key: "object.serial", Value: "8"},
|
|
{Key: "module.name", Value: pipewire.PIPEWIRE_MODULE_PREFIX + "module-spa-device-factory"},
|
|
},
|
|
},
|
|
|
|
9: {
|
|
ID: 9,
|
|
Permissions: pipewire.PW_FACTORY_PERM_MASK,
|
|
Type: pipewire.PW_TYPE_INTERFACE_Factory,
|
|
Version: pipewire.PW_VERSION_FACTORY,
|
|
Properties: &pipewire.SPADict{
|
|
{Key: "object.serial", Value: "9"},
|
|
{Key: "module.id", Value: "8"},
|
|
{Key: "factory.name", Value: "spa-device-factory"},
|
|
{Key: "factory.type.name", Value: pipewire.PW_TYPE_INTERFACE_Device},
|
|
{Key: "factory.type.version", Value: "3"},
|
|
},
|
|
},
|
|
|
|
10: {
|
|
ID: 10,
|
|
Permissions: pipewire.PW_MODULE_PERM_MASK,
|
|
Type: pipewire.PW_TYPE_INTERFACE_Module,
|
|
Version: pipewire.PW_VERSION_MODULE,
|
|
Properties: &pipewire.SPADict{
|
|
{Key: "object.serial", Value: "10"},
|
|
{Key: "module.name", Value: pipewire.PIPEWIRE_MODULE_PREFIX + "module-spa-node-factory"},
|
|
},
|
|
},
|
|
|
|
11: {
|
|
ID: 11,
|
|
Permissions: pipewire.PW_FACTORY_PERM_MASK,
|
|
Type: pipewire.PW_TYPE_INTERFACE_Factory,
|
|
Version: pipewire.PW_VERSION_FACTORY,
|
|
Properties: &pipewire.SPADict{
|
|
{Key: "object.serial", Value: "11"},
|
|
{Key: "module.id", Value: "10"},
|
|
{Key: "factory.name", Value: "spa-node-factory"},
|
|
{Key: "factory.type.name", Value: pipewire.PW_TYPE_INTERFACE_Node},
|
|
{Key: "factory.type.version", Value: "3"},
|
|
},
|
|
},
|
|
|
|
12: {
|
|
ID: 12,
|
|
Permissions: pipewire.PW_MODULE_PERM_MASK,
|
|
Type: pipewire.PW_TYPE_INTERFACE_Module,
|
|
Version: pipewire.PW_VERSION_MODULE,
|
|
Properties: &pipewire.SPADict{
|
|
{Key: "object.serial", Value: "12"},
|
|
{Key: "module.name", Value: pipewire.PIPEWIRE_MODULE_PREFIX + "module-client-node"},
|
|
},
|
|
},
|
|
|
|
13: {
|
|
ID: 13,
|
|
Permissions: pipewire.PW_FACTORY_PERM_MASK,
|
|
Type: pipewire.PW_TYPE_INTERFACE_Factory,
|
|
Version: pipewire.PW_VERSION_FACTORY,
|
|
Properties: &pipewire.SPADict{
|
|
{Key: "object.serial", Value: "13"},
|
|
{Key: "module.id", Value: "12"},
|
|
{Key: "factory.name", Value: "client-node"},
|
|
{Key: "factory.type.name", Value: pipewire.PW_TYPE_INTERFACE_ClientNode},
|
|
{Key: "factory.type.version", Value: "6"},
|
|
},
|
|
},
|
|
|
|
14: {
|
|
ID: 14,
|
|
Permissions: pipewire.PW_MODULE_PERM_MASK,
|
|
Type: pipewire.PW_TYPE_INTERFACE_Module,
|
|
Version: pipewire.PW_VERSION_MODULE,
|
|
Properties: &pipewire.SPADict{
|
|
{Key: "object.serial", Value: "14"},
|
|
{Key: "module.name", Value: pipewire.PIPEWIRE_MODULE_PREFIX + "module-client-device"},
|
|
},
|
|
},
|
|
|
|
15: {
|
|
ID: 15,
|
|
Permissions: pipewire.PW_FACTORY_PERM_MASK,
|
|
Type: pipewire.PW_TYPE_INTERFACE_Factory,
|
|
Version: pipewire.PW_VERSION_FACTORY,
|
|
Properties: &pipewire.SPADict{
|
|
{Key: "object.serial", Value: "15"},
|
|
{Key: "module.id", Value: "14"},
|
|
{Key: "factory.name", Value: "client-device"},
|
|
{Key: "factory.type.name", Value: "Spa:Pointer:Interface:Device"},
|
|
{Key: "factory.type.version", Value: "0"},
|
|
},
|
|
},
|
|
|
|
16: {
|
|
ID: 16,
|
|
Permissions: pipewire.PW_MODULE_PERM_MASK,
|
|
Type: pipewire.PW_TYPE_INTERFACE_Module,
|
|
Version: pipewire.PW_VERSION_MODULE,
|
|
Properties: &pipewire.SPADict{
|
|
{Key: "object.serial", Value: "16"},
|
|
{Key: "module.name", Value: pipewire.PIPEWIRE_MODULE_PREFIX + "module-portal"},
|
|
},
|
|
},
|
|
|
|
17: {
|
|
ID: 17,
|
|
Permissions: pipewire.PW_MODULE_PERM_MASK,
|
|
Type: pipewire.PW_TYPE_INTERFACE_Module,
|
|
Version: pipewire.PW_VERSION_MODULE,
|
|
Properties: &pipewire.SPADict{
|
|
{Key: "object.serial", Value: "17"},
|
|
{Key: "module.name", Value: pipewire.PIPEWIRE_MODULE_PREFIX + "module-access"},
|
|
},
|
|
},
|
|
|
|
18: {
|
|
ID: 18,
|
|
Permissions: pipewire.PW_MODULE_PERM_MASK,
|
|
Type: pipewire.PW_TYPE_INTERFACE_Module,
|
|
Version: pipewire.PW_VERSION_MODULE,
|
|
Properties: &pipewire.SPADict{
|
|
{Key: "object.serial", Value: "18"},
|
|
{Key: "module.name", Value: pipewire.PIPEWIRE_MODULE_PREFIX + "module-adapter"},
|
|
},
|
|
},
|
|
|
|
19: {
|
|
ID: 19,
|
|
Permissions: pipewire.PW_FACTORY_PERM_MASK,
|
|
Type: pipewire.PW_TYPE_INTERFACE_Factory,
|
|
Version: pipewire.PW_VERSION_FACTORY,
|
|
Properties: &pipewire.SPADict{
|
|
{Key: "object.serial", Value: "19"},
|
|
{Key: "module.id", Value: "18"},
|
|
{Key: "factory.name", Value: "adapter"},
|
|
{Key: "factory.type.name", Value: pipewire.PW_TYPE_INTERFACE_Node},
|
|
{Key: "factory.type.version", Value: "3"},
|
|
},
|
|
},
|
|
|
|
20: {
|
|
ID: 20,
|
|
Permissions: pipewire.PW_MODULE_PERM_MASK,
|
|
Type: pipewire.PW_TYPE_INTERFACE_Module,
|
|
Version: pipewire.PW_VERSION_MODULE,
|
|
Properties: &pipewire.SPADict{
|
|
{Key: "object.serial", Value: "20"},
|
|
{Key: "module.name", Value: pipewire.PIPEWIRE_MODULE_PREFIX + "module-link-factory"},
|
|
},
|
|
},
|
|
|
|
21: {
|
|
ID: 21,
|
|
Permissions: pipewire.PW_FACTORY_PERM_MASK,
|
|
Type: pipewire.PW_TYPE_INTERFACE_Factory,
|
|
Version: pipewire.PW_VERSION_FACTORY,
|
|
Properties: &pipewire.SPADict{
|
|
{Key: "object.serial", Value: "21"},
|
|
{Key: "module.id", Value: "20"},
|
|
{Key: "factory.name", Value: "link-factory"},
|
|
{Key: "factory.type.name", Value: pipewire.PW_TYPE_INTERFACE_Link},
|
|
{Key: "factory.type.version", Value: "3"},
|
|
},
|
|
},
|
|
|
|
22: {
|
|
ID: 22,
|
|
Permissions: pipewire.PW_MODULE_PERM_MASK,
|
|
Type: pipewire.PW_TYPE_INTERFACE_Module,
|
|
Version: pipewire.PW_VERSION_MODULE,
|
|
Properties: &pipewire.SPADict{
|
|
{Key: "object.serial", Value: "22"},
|
|
{Key: "module.name", Value: pipewire.PIPEWIRE_MODULE_PREFIX + "module-session-manager"},
|
|
},
|
|
},
|
|
|
|
23: {
|
|
ID: 23,
|
|
Permissions: pipewire.PW_FACTORY_PERM_MASK,
|
|
Type: pipewire.PW_TYPE_INTERFACE_Factory,
|
|
Version: pipewire.PW_VERSION_FACTORY,
|
|
Properties: &pipewire.SPADict{
|
|
{Key: "object.serial", Value: "23"},
|
|
{Key: "module.id", Value: "22"},
|
|
{Key: "factory.name", Value: "client-endpoint"},
|
|
{Key: "factory.type.name", Value: "PipeWire:Interface:ClientEndpoint"},
|
|
{Key: "factory.type.version", Value: "0"},
|
|
},
|
|
},
|
|
|
|
24: {
|
|
ID: 24,
|
|
Permissions: pipewire.PW_FACTORY_PERM_MASK,
|
|
Type: pipewire.PW_TYPE_INTERFACE_Factory,
|
|
Version: pipewire.PW_VERSION_FACTORY,
|
|
Properties: &pipewire.SPADict{
|
|
{Key: "object.serial", Value: "24"},
|
|
{Key: "module.id", Value: "22"},
|
|
{Key: "factory.name", Value: "client-session"},
|
|
{Key: "factory.type.name", Value: "PipeWire:Interface:ClientSession"},
|
|
{Key: "factory.type.version", Value: "0"},
|
|
},
|
|
},
|
|
|
|
25: {
|
|
ID: 25,
|
|
Permissions: pipewire.PW_FACTORY_PERM_MASK,
|
|
Type: pipewire.PW_TYPE_INTERFACE_Factory,
|
|
Version: pipewire.PW_VERSION_FACTORY,
|
|
Properties: &pipewire.SPADict{
|
|
{Key: "object.serial", Value: "25"},
|
|
{Key: "module.id", Value: "22"},
|
|
{Key: "factory.name", Value: "session"},
|
|
{Key: "factory.type.name", Value: "PipeWire:Interface:Session"},
|
|
{Key: "factory.type.version", Value: "0"},
|
|
},
|
|
},
|
|
|
|
26: {
|
|
ID: 26,
|
|
Permissions: pipewire.PW_FACTORY_PERM_MASK,
|
|
Type: pipewire.PW_TYPE_INTERFACE_Factory,
|
|
Version: pipewire.PW_VERSION_FACTORY,
|
|
Properties: &pipewire.SPADict{
|
|
{Key: "object.serial", Value: "26"},
|
|
{Key: "module.id", Value: "22"},
|
|
{Key: "factory.name", Value: "endpoint"},
|
|
{Key: "factory.type.name", Value: "PipeWire:Interface:Endpoint"},
|
|
{Key: "factory.type.version", Value: "0"},
|
|
},
|
|
},
|
|
|
|
27: {
|
|
ID: 27,
|
|
Permissions: pipewire.PW_FACTORY_PERM_MASK,
|
|
Type: pipewire.PW_TYPE_INTERFACE_Factory,
|
|
Version: pipewire.PW_VERSION_FACTORY,
|
|
Properties: &pipewire.SPADict{
|
|
{Key: "object.serial", Value: "27"},
|
|
{Key: "module.id", Value: "22"},
|
|
{Key: "factory.name", Value: "endpoint-stream"},
|
|
{Key: "factory.type.name", Value: "PipeWire:Interface:EndpointStream"},
|
|
{Key: "factory.type.version", Value: "0"},
|
|
},
|
|
},
|
|
|
|
28: {
|
|
ID: 28,
|
|
Permissions: pipewire.PW_FACTORY_PERM_MASK,
|
|
Type: pipewire.PW_TYPE_INTERFACE_Factory,
|
|
Version: pipewire.PW_VERSION_FACTORY,
|
|
Properties: &pipewire.SPADict{
|
|
{Key: "object.serial", Value: "28"},
|
|
{Key: "module.id", Value: "22"},
|
|
{Key: "factory.name", Value: "endpoint-link"},
|
|
{Key: "factory.type.name", Value: "PipeWire:Interface:EndpointLink"},
|
|
{Key: "factory.type.version", Value: "0"},
|
|
},
|
|
},
|
|
|
|
29: {
|
|
ID: 29,
|
|
Permissions: pipewire.PW_MODULE_PERM_MASK,
|
|
Type: pipewire.PW_TYPE_INTERFACE_Module,
|
|
Version: pipewire.PW_VERSION_MODULE,
|
|
Properties: &pipewire.SPADict{
|
|
{Key: "object.serial", Value: "29"},
|
|
{Key: "module.name", Value: pipewire.PIPEWIRE_MODULE_PREFIX + "module-x11-bell"},
|
|
},
|
|
},
|
|
|
|
30: {
|
|
ID: 30,
|
|
Permissions: pipewire.PW_MODULE_PERM_MASK,
|
|
Type: pipewire.PW_TYPE_INTERFACE_Module,
|
|
Version: pipewire.PW_VERSION_MODULE,
|
|
Properties: &pipewire.SPADict{
|
|
{Key: "object.serial", Value: "30"},
|
|
{Key: "module.name", Value: pipewire.PIPEWIRE_MODULE_PREFIX + "module-jackdbus-detect"},
|
|
},
|
|
},
|
|
|
|
31: {
|
|
ID: 31,
|
|
Permissions: pipewire.PW_PERM_RWXM, // why is this not PW_NODE_PERM_MASK?
|
|
Type: pipewire.PW_TYPE_INTERFACE_Node,
|
|
Version: pipewire.PW_VERSION_NODE,
|
|
Properties: &pipewire.SPADict{
|
|
{Key: "object.serial", Value: "31"},
|
|
{Key: "factory.id", Value: "11"},
|
|
{Key: "priority.driver", Value: "200000"},
|
|
{Key: "node.name", Value: "Dummy-Driver"},
|
|
},
|
|
},
|
|
|
|
32: {
|
|
ID: 32,
|
|
Permissions: pipewire.PW_PERM_RWXM, // why is this not PW_NODE_PERM_MASK?
|
|
Type: pipewire.PW_TYPE_INTERFACE_Node,
|
|
Version: pipewire.PW_VERSION_NODE,
|
|
Properties: &pipewire.SPADict{
|
|
{Key: "object.serial", Value: "32"},
|
|
{Key: "factory.id", Value: "11"},
|
|
{Key: "priority.driver", Value: "190000"},
|
|
{Key: "node.name", Value: "Freewheel-Driver"},
|
|
},
|
|
},
|
|
|
|
33: {
|
|
ID: 33,
|
|
Permissions: pipewire.PW_METADATA_PERM_MASK,
|
|
Type: pipewire.PW_TYPE_INTERFACE_Metadata,
|
|
Version: pipewire.PW_VERSION_METADATA,
|
|
Properties: &pipewire.SPADict{
|
|
{Key: "object.serial", Value: "33"},
|
|
{Key: "metadata.name", Value: "settings"},
|
|
},
|
|
},
|
|
|
|
34: {
|
|
ID: 34,
|
|
Permissions: pipewire.PW_CLIENT_PERM_MASK,
|
|
Type: pipewire.PW_TYPE_INTERFACE_Client,
|
|
Version: pipewire.PW_VERSION_CLIENT,
|
|
Properties: &pipewire.SPADict{
|
|
{Key: "object.serial", Value: "34"},
|
|
{Key: "module.id", Value: "2"},
|
|
{Key: "pipewire.protocol", Value: "protocol-native"},
|
|
{Key: "pipewire.sec.pid", Value: "1443"},
|
|
{Key: "pipewire.sec.uid", Value: "1000"},
|
|
{Key: "pipewire.sec.gid", Value: "100"},
|
|
{Key: "pipewire.sec.socket", Value: "pipewire-0-manager"},
|
|
{Key: "pipewire.access", Value: "unrestricted"},
|
|
{Key: "application.name", Value: "pw-container"},
|
|
},
|
|
},
|
|
|
|
35: {
|
|
ID: 35,
|
|
Permissions: pipewire.PW_CLIENT_PERM_MASK,
|
|
Type: pipewire.PW_TYPE_INTERFACE_Client,
|
|
Version: pipewire.PW_VERSION_CLIENT,
|
|
Properties: &pipewire.SPADict{
|
|
{Key: "object.serial", Value: "35"},
|
|
{Key: "module.id", Value: "2"},
|
|
{Key: "pipewire.protocol", Value: "protocol-native"},
|
|
{Key: "pipewire.sec.pid", Value: "1447"},
|
|
{Key: "pipewire.sec.uid", Value: "1000"},
|
|
{Key: "pipewire.sec.gid", Value: "100"},
|
|
{Key: "pipewire.sec.socket", Value: "pipewire-0-manager"},
|
|
{Key: "pipewire.access", Value: "unrestricted"},
|
|
{Key: "application.name", Value: "WirePlumber"},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
if coreInfo := ctx.GetCore().Info; !reflect.DeepEqual(coreInfo, &wantCoreInfo0) {
|
|
t.Fatalf("New: CoreInfo = %s, want %s", mustMarshalJSON(coreInfo), mustMarshalJSON(&wantCoreInfo0))
|
|
}
|
|
if client := ctx.GetClient(); !reflect.DeepEqual(client, &wantClient0) {
|
|
t.Fatalf("New: Client = %s, want %s", mustMarshalJSON(client), mustMarshalJSON(&wantClient0))
|
|
}
|
|
if registry.ID != wantRegistry0.ID {
|
|
t.Fatalf("GetRegistry: ID = %d, want %d", registry.ID, wantRegistry0.ID)
|
|
}
|
|
if !reflect.DeepEqual(registry.Objects, wantRegistry0.Objects) {
|
|
t.Fatalf("GetRegistry: Objects = %s, want %s", mustMarshalJSON(registry.Objects), mustMarshalJSON(wantRegistry0.Objects))
|
|
}
|
|
|
|
var securityContext *pipewire.SecurityContext
|
|
const wantSecurityContextId = 3
|
|
if c, err := registry.GetSecurityContext(); err != nil {
|
|
t.Fatalf("GetSecurityContext: error = %v", err)
|
|
} else {
|
|
if c.ID != wantSecurityContextId {
|
|
t.Fatalf("GetSecurityContext: ID = %d, want %d", c.ID, wantSecurityContextId)
|
|
}
|
|
securityContext = c
|
|
}
|
|
if err := ctx.Roundtrip(); err != nil {
|
|
t.Fatalf("Roundtrip: error = %v", err)
|
|
}
|
|
|
|
// none of these should change
|
|
if coreInfo := ctx.GetCore().Info; !reflect.DeepEqual(coreInfo, &wantCoreInfo0) {
|
|
t.Fatalf("Roundtrip: CoreInfo = %s, want %s", mustMarshalJSON(coreInfo), mustMarshalJSON(&wantCoreInfo0))
|
|
}
|
|
if client := ctx.GetClient(); !reflect.DeepEqual(client, &wantClient0) {
|
|
t.Fatalf("Roundtrip: Client = %s, want %s", mustMarshalJSON(client), mustMarshalJSON(&wantClient0))
|
|
}
|
|
if registry.ID != wantRegistry0.ID {
|
|
t.Fatalf("Roundtrip: ID = %d, want %d", registry.ID, wantRegistry0.ID)
|
|
}
|
|
if !reflect.DeepEqual(registry.Objects, wantRegistry0.Objects) {
|
|
t.Fatalf("Roundtrip: Objects = %s, want %s", mustMarshalJSON(registry.Objects), mustMarshalJSON(wantRegistry0.Objects))
|
|
}
|
|
|
|
if err := securityContext.Create(21, 20, pipewire.SPADict{
|
|
{Key: "pipewire.sec.engine", Value: "org.flatpak"},
|
|
{Key: "pipewire.access", Value: "restricted"},
|
|
}); err != nil {
|
|
t.Fatalf("SecurityContext.Create: error = %v", err)
|
|
}
|
|
if err := ctx.GetCore().Sync(); err != nil {
|
|
t.Fatalf("Sync: error = %v", err)
|
|
}
|
|
|
|
// none of these should change
|
|
if coreInfo := ctx.GetCore().Info; !reflect.DeepEqual(coreInfo, &wantCoreInfo0) {
|
|
t.Fatalf("Roundtrip: CoreInfo = %s, want %s", mustMarshalJSON(coreInfo), mustMarshalJSON(&wantCoreInfo0))
|
|
}
|
|
if client := ctx.GetClient(); !reflect.DeepEqual(client, &wantClient0) {
|
|
t.Fatalf("Roundtrip: Client = %s, want %s", mustMarshalJSON(client), mustMarshalJSON(&wantClient0))
|
|
}
|
|
if registry.ID != wantRegistry0.ID {
|
|
t.Fatalf("Roundtrip: ID = %d, want %d", registry.ID, wantRegistry0.ID)
|
|
}
|
|
if !reflect.DeepEqual(registry.Objects, wantRegistry0.Objects) {
|
|
t.Fatalf("Roundtrip: Objects = %s, want %s", mustMarshalJSON(registry.Objects), mustMarshalJSON(wantRegistry0.Objects))
|
|
}
|
|
|
|
if err := ctx.Close(); err != nil {
|
|
t.Fatalf("Close: error = %v", err)
|
|
}
|
|
}
|
|
|
|
// stubUnixConnSample is sample data held by stubUnixConn.
|
|
type stubUnixConnSample struct {
|
|
nr uintptr
|
|
iovec string
|
|
flags uintptr
|
|
files []int
|
|
errno Errno
|
|
}
|
|
|
|
// stubUnixConn implements [pipewire.Conn] and checks the behaviour of [pipewire.Context].
|
|
type stubUnixConn struct {
|
|
samples []stubUnixConnSample
|
|
current int
|
|
|
|
deadline *time.Time
|
|
}
|
|
|
|
// checkDeadline checks whether deadline is set reasonably.
|
|
func (conn *stubUnixConn) checkDeadline() error {
|
|
if conn.deadline == nil || conn.deadline.Before(time.Now()) {
|
|
return fmt.Errorf("invalid deadline %v", conn.deadline)
|
|
}
|
|
conn.deadline = nil
|
|
return nil
|
|
}
|
|
|
|
// nextSample returns the current sample and increments the counter.
|
|
func (conn *stubUnixConn) nextSample(nr uintptr) (sample *stubUnixConnSample, wantOOB []byte, err error) {
|
|
sample = &conn.samples[conn.current]
|
|
conn.current++
|
|
if sample.nr != nr {
|
|
err = fmt.Errorf("unexpected syscall %d", SYS_SENDMSG)
|
|
return
|
|
}
|
|
if len(sample.files) > 0 {
|
|
wantOOB = UnixRights(sample.files...)
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func (conn *stubUnixConn) ReadMsgUnix(b, oob []byte) (n, oobn, flags int, addr *net.UnixAddr, err error) {
|
|
if conn.samples[conn.current-1].nr == SYS_SENDMSG {
|
|
if err = conn.checkDeadline(); err != nil {
|
|
return
|
|
}
|
|
}
|
|
|
|
var (
|
|
sample *stubUnixConnSample
|
|
wantOOB []byte
|
|
)
|
|
sample, wantOOB, err = conn.nextSample(SYS_RECVMSG)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
if copy(b, sample.iovec) != len(sample.iovec) {
|
|
err = fmt.Errorf("insufficient iovec size %d, want at least %d", len(b), len(sample.iovec))
|
|
}
|
|
if copy(oob, wantOOB) != len(wantOOB) {
|
|
err = fmt.Errorf("insufficient oob size %d, want at least %d", len(oob), len(wantOOB))
|
|
}
|
|
|
|
if sample.errno != 0 && sample.errno != EAGAIN {
|
|
err = sample.errno
|
|
}
|
|
return len(sample.iovec), len(wantOOB), MSG_CMSG_CLOEXEC, nil, nil
|
|
}
|
|
|
|
func (conn *stubUnixConn) WriteMsgUnix(b, oob []byte, addr *net.UnixAddr) (n, oobn int, err error) {
|
|
if addr != nil {
|
|
err = fmt.Errorf("WriteMsgUnix called with non-nil addr: %#v", addr)
|
|
return
|
|
}
|
|
if err = conn.checkDeadline(); err != nil {
|
|
return
|
|
}
|
|
|
|
var (
|
|
sample *stubUnixConnSample
|
|
wantOOB []byte
|
|
)
|
|
sample, wantOOB, err = conn.nextSample(SYS_SENDMSG)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
if string(b) != sample.iovec {
|
|
err = fmt.Errorf("iovec: %#v, want %#v", b, []byte(sample.iovec))
|
|
return
|
|
}
|
|
if string(oob[:len(wantOOB)]) != string(wantOOB) {
|
|
err = fmt.Errorf("oob: %#v, want %#v", oob[:len(wantOOB)], wantOOB)
|
|
return
|
|
}
|
|
return len(sample.iovec), len(wantOOB), nil
|
|
}
|
|
|
|
func (conn *stubUnixConn) SetDeadline(t time.Time) error { conn.deadline = &t; return nil }
|
|
|
|
func (conn *stubUnixConn) Close() error {
|
|
if conn.current != len(conn.samples) {
|
|
return fmt.Errorf("consumed %d samples, want %d", conn.current, len(conn.samples))
|
|
}
|
|
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
|
|
}
|