From 72a2601d7461c0e2e24a3f97f19392dc30ee4c68 Mon Sep 17 00:00:00 2001 From: Ophestra Date: Fri, 28 Nov 2025 00:34:32 +0900 Subject: [PATCH] internal/pipewire: store sample iovec continuously This removes the need for manual splitting. The understanding of the format is robust enough to allow this to happen anyway. Signed-off-by: Ophestra --- internal/pipewire/client_test.go | 8 +- internal/pipewire/core_test.go | 16 +-- internal/pipewire/header_test.go | 20 ++-- internal/pipewire/pipewire_test.go | 102 +++++++++--------- internal/pipewire/testdata/c0s0p0 | Bin 16 -> 0 bytes internal/pipewire/testdata/c0s0p1 | Bin 24 -> 0 bytes internal/pipewire/testdata/c0s1p0 | Bin 16 -> 0 bytes internal/pipewire/testdata/c0s2p0 | Bin 16 -> 0 bytes internal/pipewire/testdata/c0s2p1 | Bin 40 -> 0 bytes internal/pipewire/testdata/c0s3p0 | Bin 16 -> 0 bytes internal/pipewire/testdata/c0s3p1 | Bin 40 -> 0 bytes internal/pipewire/testdata/c1r0p0 | Bin 16 -> 0 bytes internal/pipewire/testdata/c1r0p1 | Bin 1672 -> 0 bytes internal/pipewire/testdata/c1r0p2 | Bin 48 -> 0 bytes internal/pipewire/testdata/c1r1p0 | Bin 16 -> 0 bytes internal/pipewire/testdata/c1r1p1 | Bin 408 -> 0 bytes internal/pipewire/testdata/c1r2p0 | Bin 16 -> 0 bytes internal/pipewire/testdata/c1r2p1 | Bin 496 -> 0 bytes internal/pipewire/testdata/c1r3p0 | Bin 16 -> 0 bytes internal/pipewire/testdata/c1r3p1 | Bin 1952 -> 0 bytes internal/pipewire/testdata/c1r4p0 | Bin 16 -> 0 bytes internal/pipewire/testdata/c1r4p1 | Bin 2000 -> 0 bytes internal/pipewire/testdata/c1r5p0 | Bin 16 -> 0 bytes internal/pipewire/testdata/c1r5p1 | Bin 40 -> 0 bytes internal/pipewire/testdata/c1r5p2 | Bin 48 -> 0 bytes .../{c0s1p1 => pw-container-00-sendmsg} | Bin 1536 -> 1704 bytes .../pipewire/testdata/pw-container-01-recvmsg | Bin 0 -> 18064 bytes .../pipewire/testdata/pw-container-03-sendmsg | Bin 0 -> 168 bytes .../pipewire/testdata/pw-container-04-recvmsg | Bin 0 -> 120 bytes .../pipewire/testdata/pw-container-06-sendmsg | Bin 0 -> 288 bytes .../pipewire/testdata/pw-container-07-recvmsg | Bin 0 -> 56 bytes 31 files changed, 72 insertions(+), 74 deletions(-) delete mode 100644 internal/pipewire/testdata/c0s0p0 delete mode 100644 internal/pipewire/testdata/c0s0p1 delete mode 100644 internal/pipewire/testdata/c0s1p0 delete mode 100644 internal/pipewire/testdata/c0s2p0 delete mode 100644 internal/pipewire/testdata/c0s2p1 delete mode 100644 internal/pipewire/testdata/c0s3p0 delete mode 100644 internal/pipewire/testdata/c0s3p1 delete mode 100644 internal/pipewire/testdata/c1r0p0 delete mode 100644 internal/pipewire/testdata/c1r0p1 delete mode 100644 internal/pipewire/testdata/c1r0p2 delete mode 100644 internal/pipewire/testdata/c1r1p0 delete mode 100644 internal/pipewire/testdata/c1r1p1 delete mode 100644 internal/pipewire/testdata/c1r2p0 delete mode 100644 internal/pipewire/testdata/c1r2p1 delete mode 100644 internal/pipewire/testdata/c1r3p0 delete mode 100644 internal/pipewire/testdata/c1r3p1 delete mode 100644 internal/pipewire/testdata/c1r4p0 delete mode 100644 internal/pipewire/testdata/c1r4p1 delete mode 100644 internal/pipewire/testdata/c1r5p0 delete mode 100644 internal/pipewire/testdata/c1r5p1 delete mode 100644 internal/pipewire/testdata/c1r5p2 rename internal/pipewire/testdata/{c0s1p1 => pw-container-00-sendmsg} (53%) create mode 100644 internal/pipewire/testdata/pw-container-01-recvmsg create mode 100644 internal/pipewire/testdata/pw-container-03-sendmsg create mode 100644 internal/pipewire/testdata/pw-container-04-recvmsg create mode 100644 internal/pipewire/testdata/pw-container-06-sendmsg create mode 100644 internal/pipewire/testdata/pw-container-07-recvmsg diff --git a/internal/pipewire/client_test.go b/internal/pipewire/client_test.go index 3eb8962..5ba2ff9 100644 --- a/internal/pipewire/client_test.go +++ b/internal/pipewire/client_test.go @@ -10,7 +10,7 @@ func TestClientInfo(t *testing.T) { t.Parallel() encodingTestCases[pipewire.ClientInfo, *pipewire.ClientInfo]{ - {"sample", []byte(c1r2pod), pipewire.ClientInfo{ + {"sample", samplePWContainer[1][2][1], pipewire.ClientInfo{ ID: 34, ChangeMask: pipewire.PW_CLIENT_CHANGE_MASK_PROPS, Props: &pipewire.SPADict{NItems: 9, Items: []pipewire.SPADictItem{ @@ -25,7 +25,7 @@ func TestClientInfo(t *testing.T) { {Key: "object.serial", Value: "34"}, }}}, nil}, - {"sample*", []byte(c1r3pod), pipewire.ClientInfo{ + {"sample*", samplePWContainer[1][3][1], pipewire.ClientInfo{ ID: 34, ChangeMask: pipewire.PW_CLIENT_CHANGE_MASK_PROPS, Props: &pipewire.SPADict{NItems: 38, Items: []pipewire.SPADictItem{ @@ -69,7 +69,7 @@ func TestClientInfo(t *testing.T) { {Key: "core.version", Value: "1.4.7"}, }}}, nil}, - {"sample**", []byte(c1r4pod), pipewire.ClientInfo{ + {"sample**", samplePWContainer[1][4][1], pipewire.ClientInfo{ ID: 34, ChangeMask: pipewire.PW_CLIENT_CHANGE_MASK_PROPS, Props: &pipewire.SPADict{NItems: 39, Items: []pipewire.SPADictItem{ @@ -120,7 +120,7 @@ func TestClientUpdateProperties(t *testing.T) { t.Parallel() encodingTestCases[pipewire.ClientUpdateProperties, *pipewire.ClientUpdateProperties]{ - {"sample", []byte(c0s1pod), pipewire.ClientUpdateProperties{Props: &pipewire.SPADict{NItems: 0x1e, Items: []pipewire.SPADictItem{ + {"sample", samplePWContainer[0][1][1], pipewire.ClientUpdateProperties{Props: &pipewire.SPADict{NItems: 0x1e, Items: []pipewire.SPADictItem{ {Key: "remote.intention", Value: "manager"}, {Key: "application.name", Value: "pw-container"}, {Key: "application.process.binary", Value: "pw-container"}, diff --git a/internal/pipewire/core_test.go b/internal/pipewire/core_test.go index a08d454..5b2f6c2 100644 --- a/internal/pipewire/core_test.go +++ b/internal/pipewire/core_test.go @@ -10,12 +10,12 @@ func TestFooterCoreGeneration(t *testing.T) { t.Parallel() encodingTestCases[pipewire.Footer[pipewire.FooterCoreGeneration], *pipewire.Footer[pipewire.FooterCoreGeneration]]{ - {"sample", []byte(c1r0footer), pipewire.Footer[pipewire.FooterCoreGeneration]{ + {"sample", samplePWContainer[1][0][2], pipewire.Footer[pipewire.FooterCoreGeneration]{ Opcode: pipewire.FOOTER_CORE_OPCODE_GENERATION, Payload: pipewire.FooterCoreGeneration{RegistryGeneration: 0x22}, }, nil}, - {"sample*", []byte(c1r5footer), pipewire.Footer[pipewire.FooterCoreGeneration]{ + {"sample*", samplePWContainer[1][5][2], pipewire.Footer[pipewire.FooterCoreGeneration]{ Opcode: pipewire.FOOTER_CORE_OPCODE_GENERATION, Payload: pipewire.FooterCoreGeneration{RegistryGeneration: 0x23}, }, nil}, @@ -26,7 +26,7 @@ func TestCoreInfo(t *testing.T) { t.Parallel() encodingTestCases[pipewire.CoreInfo, *pipewire.CoreInfo]{ - {"sample", []byte(c1r0pod), pipewire.CoreInfo{ + {"sample", samplePWContainer[1][0][1], pipewire.CoreInfo{ ID: 0, Cookie: -2069267610, UserName: "alice", @@ -74,7 +74,7 @@ func TestCoreDone(t *testing.T) { t.Parallel() encodingTestCases[pipewire.CoreDone, *pipewire.CoreDone]{ - {"sample", []byte(c1r5pod), pipewire.CoreDone{ + {"sample", samplePWContainer[1][5][1], pipewire.CoreDone{ ID: -1, Sequence: 0, }, nil}, @@ -85,7 +85,7 @@ func TestCoreBoundProps(t *testing.T) { t.Parallel() encodingTestCases[pipewire.CoreBoundProps, *pipewire.CoreBoundProps]{ - {"sample", []byte(c1r1pod), pipewire.CoreBoundProps{ + {"sample", samplePWContainer[1][1][1], pipewire.CoreBoundProps{ ID: pipewire.PW_ID_CLIENT, GlobalID: 34, Props: &pipewire.SPADict{NItems: 7, Items: []pipewire.SPADictItem{ @@ -104,7 +104,7 @@ func TestCoreHello(t *testing.T) { t.Parallel() encodingTestCases[pipewire.CoreHello, *pipewire.CoreHello]{ - {"sample", []byte(c0s0pod), pipewire.CoreHello{ + {"sample", samplePWContainer[0][0][1], pipewire.CoreHello{ Version: pipewire.PW_VERSION_CORE, }, nil}, }.run(t) @@ -114,7 +114,7 @@ func TestCoreSync(t *testing.T) { t.Parallel() encodingTestCases[pipewire.CoreSync, *pipewire.CoreSync]{ - {"sample", []byte(c0s3pod), pipewire.CoreSync{ + {"sample", samplePWContainer[0][3][1], pipewire.CoreSync{ ID: pipewire.PW_ID_CORE, Sequence: pipewire.CoreSyncSequenceOffset + 3, }, nil}, @@ -125,7 +125,7 @@ func TestCoreGetRegistry(t *testing.T) { t.Parallel() encodingTestCases[pipewire.CoreGetRegistry, *pipewire.CoreGetRegistry]{ - {"sample", []byte(c0s2pod), pipewire.CoreGetRegistry{ + {"sample", samplePWContainer[0][2][1], pipewire.CoreGetRegistry{ Version: pipewire.PW_VERSION_REGISTRY, NewID: 2, }, nil}, diff --git a/internal/pipewire/header_test.go b/internal/pipewire/header_test.go index a555ab2..b7b1065 100644 --- a/internal/pipewire/header_test.go +++ b/internal/pipewire/header_test.go @@ -11,61 +11,61 @@ func TestHeader(t *testing.T) { t.Parallel() encodingTestCases[pipewire.Header, *pipewire.Header]{ - {"PW_CORE_METHOD_HELLO", []byte(c0s0header), pipewire.Header{ + {"PW_CORE_METHOD_HELLO", samplePWContainer[0][0][0], pipewire.Header{ ID: pipewire.PW_ID_CORE, Opcode: pipewire.PW_CORE_METHOD_HELLO, Size: 0x18, Sequence: 0, FileCount: 0, }, nil}, - {"PW_CLIENT_METHOD_UPDATE_PROPERTIES", []byte(c0s1header), pipewire.Header{ + {"PW_CLIENT_METHOD_UPDATE_PROPERTIES", samplePWContainer[0][1][0], pipewire.Header{ ID: pipewire.PW_ID_CLIENT, Opcode: pipewire.PW_CLIENT_METHOD_UPDATE_PROPERTIES, Size: 0x600, Sequence: 1, FileCount: 0, }, nil}, - {"PW_CORE_METHOD_GET_REGISTRY", []byte(c0s2header), pipewire.Header{ + {"PW_CORE_METHOD_GET_REGISTRY", samplePWContainer[0][2][0], pipewire.Header{ ID: pipewire.PW_ID_CORE, Opcode: pipewire.PW_CORE_METHOD_GET_REGISTRY, Size: 0x28, Sequence: 2, FileCount: 0, }, nil}, - {"PW_CORE_METHOD_SYNC", []byte(c0s3header), pipewire.Header{ + {"PW_CORE_METHOD_SYNC", samplePWContainer[0][3][0], pipewire.Header{ ID: pipewire.PW_ID_CORE, Opcode: pipewire.PW_CORE_METHOD_SYNC, Size: 0x28, Sequence: 3, FileCount: 0, }, nil}, - {"PW_CORE_EVENT_INFO", []byte(c1r0header), pipewire.Header{ + {"PW_CORE_EVENT_INFO", samplePWContainer[1][0][0], pipewire.Header{ ID: pipewire.PW_ID_CORE, Opcode: pipewire.PW_CORE_EVENT_INFO, Size: 0x6b8, Sequence: 0, FileCount: 0, }, nil}, - {"PW_CORE_EVENT_BOUND_PROPS", []byte(c1r1header), pipewire.Header{ + {"PW_CORE_EVENT_BOUND_PROPS", samplePWContainer[1][1][0], pipewire.Header{ ID: pipewire.PW_ID_CORE, Opcode: pipewire.PW_CORE_EVENT_BOUND_PROPS, Size: 0x198, Sequence: 1, FileCount: 0, }, nil}, - {"PW_CLIENT_EVENT_INFO", []byte(c1r2header), pipewire.Header{ + {"PW_CLIENT_EVENT_INFO", samplePWContainer[1][2][0], pipewire.Header{ ID: pipewire.PW_ID_CLIENT, Opcode: pipewire.PW_CLIENT_EVENT_INFO, Size: 0x1f0, Sequence: 2, FileCount: 0, }, nil}, - {"PW_CLIENT_EVENT_INFO*", []byte(c1r3header), pipewire.Header{ + {"PW_CLIENT_EVENT_INFO*", samplePWContainer[1][3][0], pipewire.Header{ ID: pipewire.PW_ID_CLIENT, Opcode: pipewire.PW_CLIENT_EVENT_INFO, Size: 0x7a0, Sequence: 3, FileCount: 0, }, nil}, - {"PW_CLIENT_EVENT_INFO**", []byte(c1r4header), pipewire.Header{ + {"PW_CLIENT_EVENT_INFO**", samplePWContainer[1][4][0], pipewire.Header{ ID: pipewire.PW_ID_CLIENT, Opcode: pipewire.PW_CLIENT_EVENT_INFO, Size: 0x7d0, Sequence: 4, FileCount: 0, }, nil}, - {"PW_CORE_EVENT_DONE", []byte(c1r5header), pipewire.Header{ + {"PW_CORE_EVENT_DONE", samplePWContainer[1][5][0], pipewire.Header{ ID: pipewire.PW_ID_CORE, Opcode: pipewire.PW_CORE_EVENT_DONE, Size: 0x58, Sequence: 5, FileCount: 0, diff --git a/internal/pipewire/pipewire_test.go b/internal/pipewire/pipewire_test.go index 586e5f6..63b5f4f 100644 --- a/internal/pipewire/pipewire_test.go +++ b/internal/pipewire/pipewire_test.go @@ -2,60 +2,58 @@ package pipewire_test import ( _ "embed" + "encoding/binary" + + "hakurei.app/internal/pipewire" ) var ( - //go:embed testdata/c0s0p0 - c0s0header string - //go:embed testdata/c0s0p1 - c0s0pod string + //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 - //go:embed testdata/c0s1p0 - c0s1header string - //go:embed testdata/c0s1p1 - c0s1pod string - - //go:embed testdata/c0s2p0 - c0s2header string - //go:embed testdata/c0s2p1 - c0s2pod string - - //go:embed testdata/c0s3p0 - c0s3header string - //go:embed testdata/c0s3p1 - c0s3pod string - - //go:embed testdata/c1r0p0 - c1r0header string - //go:embed testdata/c1r0p1 - c1r0pod string - //go:embed testdata/c1r0p2 - c1r0footer string - - //go:embed testdata/c1r1p0 - c1r1header string - //go:embed testdata/c1r1p1 - c1r1pod string - - //go:embed testdata/c1r2p0 - c1r2header string - //go:embed testdata/c1r2p1 - c1r2pod string - - //go:embed testdata/c1r3p0 - c1r3header string - //go:embed testdata/c1r3p1 - c1r3pod string - - //go:embed testdata/c1r4p0 - c1r4header string - //go:embed testdata/c1r4p1 - c1r4pod string - - //go:embed testdata/c1r5p0 - c1r5header string - //go:embed testdata/c1r5p1 - c1r5pod string - //go:embed testdata/c1r5p2 - c1r5footer 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 +} diff --git a/internal/pipewire/testdata/c0s0p0 b/internal/pipewire/testdata/c0s0p0 deleted file mode 100644 index 601b8fe6c25696c3e78f8320a69b8415a84748a8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16 ScmZQzU|^77U|KoH0mu}H8LSKp42%#i*dS#4<)Pv{Q2ojId1;yHdU=VtAX_1B z1-S!et{zAM0|SE~RDEJWK~83JVo7Fx9zqiX0|O^i9;Od!4TCgP99dsMQGRl2aj{-f zW?o`ZB}64I{i0a(=OpH(mnNoz9SrkFYF>P3uwH10o2~`eKyfVkVD@IFFff3^2;@&g z6B9F#21z{XON&#BKx#l37B8@P!ly4IzqkaX2ZUkzVDTvowXZxgFD1WRufot!FD0|M zASV$T9?VdAD`>pJ{Fz)(s#lha2zr=53R81SLH5AnDJL^8TQ4`ULN}>2EiJVOl!QRi z3@~#I!MTG7b8=!bquilfJJ>uYF<7p z+8JQ}FobAhfTgdT{B*sX)UwnZs5nd=IFJ|^;N=Mm_HT zCTAnu0L$+%b7Ap>rXCcKV4tF^hlNLeQdVkmi5{rP0;_|C2PAe7e!*;AiW$63=H{6S*gh-dc~!u3NMg< p4I#=IM4PxYxH!uLZ z5UcuhgnCf;g3X60hx|vQm>v5bBtr>Wobw3PEuQ RG9Rk0IJGD<5flgL>Hul2NBRH& diff --git a/internal/pipewire/testdata/c1r3p0 b/internal/pipewire/testdata/c1r3p0 deleted file mode 100644 index 0964c8a09addcbcdeceda518aa249269a0f3046e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16 ScmZQ%U|?9l&cMLT009691pur7 diff --git a/internal/pipewire/testdata/c1r3p1 b/internal/pipewire/testdata/c1r3p1 deleted file mode 100644 index be7157ce5e5906c20f96295131027cf3012f67db..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1952 zcmbQi&cMLOz`(!)#Yzkiz`?-4z{J=2_ zm*gks=RoBJVDeC5-Mqw-%(7GlE~t2Neo?AkUSe)4RJ{mP9A=(wVoqjqs;;4li7{9O zy1ZU-YO-E&esXqd30PhjUB7{DZem_ydTJ3^nn4gv9<0A0GX)|G@iWLjFblD&FU6wX zz`y`x23Gay2=$_?E zoCs2i9BmA|Pn7*tl_X~7K|)*_DvqqLpeR2%wYXR>DKjszs1jl$F8!id^yehz zrI#kAgOdyoR6aE?J~UV_G{jBU0&Ji-R2-YVpg;ztZIJ(9@hpi)eQ7boFCc^2VCq20 zl7WE%pT3OzVo0K7U|@jh%ge0DFJ@q1kcXLr6rQkfDNZde&dkr#1-TQJ4h%t-GcYi~ z(sy}gUP^wsUWK8dUP@+hK~5qx9AWWn1x}3&46yJ?E-2M2%SA*P%>RX{xuqbZVfis9 zKV2^;wJa5sW-tbWoy!*=r0lG!IfMX329wru$j3WjO4^;JqrHOeZrMb|u2xPCJfe|>ROJP-?o0+GJ&;xQmy1Q`b zORPZC2MZq~0~2t9lEG>p)Gpne%-l>!RKxUH7+Qiu0>8erocw%9!2}Cuu;&;U7+~cb zEIi6GQ&RKw$}>|+GC)`1ei~5w*ynIj;ffd610ZXs2{11u$g8cH-BHjEn-IDTr)BuNtTS-wV zIEBEi8;j} zgJJa%NL^x1PJTI5A-esr@F`9$Dap)BFV;)WNKMX0xEYq8Vdlc(3r#&JK*8=sR}U-i Z!1Z5QY7r>IgA~Hl8S0tnnKLjj003%AT%!O0 diff --git a/internal/pipewire/testdata/c1r4p0 b/internal/pipewire/testdata/c1r4p0 deleted file mode 100644 index 4c4b0f7541adc5506c04d95c0c54c0d3bf4e4bce..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16 ScmZQ%U|_hw&cMLJ0096BO#s~h diff --git a/internal/pipewire/testdata/c1r4p1 b/internal/pipewire/testdata/c1r4p1 deleted file mode 100644 index bb28d8248055412314a08e81bedb819bd9434591..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2000 zcmX@X&cMLOz`(!)#Yzkiz`?-4z{0IkUy4P& zfq?3?^=+8;a zOD|1K2PYXGsC;T(d}y#7Yadv)34!U}5e|Nli;E%_-4K&dE>C z)+A`Y*1^*`7WFBqdHJ9y0xN|11D0N4`5zMh1^MNvMY{QEx+UfLr~wWOx00e# za0-EyH#wPk*?ORamQqCr@Ifq{XKfq{Vq34_GJ3fLH!z%&B`!veMfkgx^=11l4V n!N9m!N9--lSkJFk_Ta!K4u062M`|s={p1c delta 7 OcmZ3%+rYEXf(-x(_5vXQ diff --git a/internal/pipewire/testdata/pw-container-01-recvmsg b/internal/pipewire/testdata/pw-container-01-recvmsg new file mode 100644 index 0000000000000000000000000000000000000000..fca410df662ada1457b24532f03a139235890248 GIT binary patch literal 18064 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 literal 0 HcmV?d00001 diff --git a/internal/pipewire/testdata/pw-container-03-sendmsg b/internal/pipewire/testdata/pw-container-03-sendmsg new file mode 100644 index 0000000000000000000000000000000000000000..f25feb0e8c3fd72507ecd08e33b4522e37b7ac10 GIT binary patch literal 168 zcmZQ#U|^WRz`)4D009XM3=Dh>3=AMX2s1;38I&0q7&sUh7y>d2Qo}QgQms7mN>Yo` z5|dM{f>V=Ai!w_po%8cbQY%Uz8bEqM7^WY@24NUq1IZqk7)Yl8R2*a%D+2@AUXVBd DJ-`o4 literal 0 HcmV?d00001 diff --git a/internal/pipewire/testdata/pw-container-04-recvmsg b/internal/pipewire/testdata/pw-container-04-recvmsg new file mode 100644 index 0000000000000000000000000000000000000000..299da9adc6968eec5d5e94428f5e94c9e53c96c1 GIT binary patch literal 120 zcmZQzU|`5#VBpXOF&G#a5*Qd5_!t-%SfH30Dvr*#KvTyERR_|`!N9u