detached 330a0fb

feat: replace stub player API with typed config surface

commit
330a0fbc81f8d3294d6df62b7271bee00f713652
author
brice · · 2026-04-09 14:15 UTC
parent
a5a9e72
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
4 files · +207 -0
M .mockery.yml +2 -0
@@ -22,3 +22,5 @@ packages:
2222 interfaces:
2323 Runtime:
2424 MainLoop:
25+ Player:
26+ PlaybackStream:
@@ -22,3 +22,5 @@ packages:
22 interfaces:22 interfaces:
23 Runtime:23 Runtime:
24 MainLoop:24 MainLoop:
25+ Player:
26+ PlaybackStream:
A pipewire/mocks/mock_Player.go +151 -0
@@ -0,0 +1,151 @@
1+// Code generated by mockery; DO NOT EDIT.
2+// github.com/vektra/mockery
3+// template: testify
4+
5+package mocks
6+
7+import (
8+ "context"
9+
10+ "github.com/bnema/purego-pipewire/pipewire"
11+ mock "github.com/stretchr/testify/mock"
12+)
13+
14+// NewMockPlayer creates a new instance of MockPlayer. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
15+// The first argument is typically a *testing.T value.
16+func NewMockPlayer(t interface {
17+ mock.TestingT
18+ Cleanup(func())
19+}) *MockPlayer {
20+ mock := &MockPlayer{}
21+ mock.Mock.Test(t)
22+
23+ t.Cleanup(func() { mock.AssertExpectations(t) })
24+
25+ return mock
26+}
27+
28+// MockPlayer is an autogenerated mock type for the Player type
29+type MockPlayer struct {
30+ mock.Mock
31+}
32+
33+type MockPlayer_Expecter struct {
34+ mock *mock.Mock
35+}
36+
37+func (_m *MockPlayer) EXPECT() *MockPlayer_Expecter {
38+ return &MockPlayer_Expecter{mock: &_m.Mock}
39+}
40+
41+// Close provides a mock function for the type MockPlayer
42+func (_mock *MockPlayer) Close() error {
43+ ret := _mock.Called()
44+
45+ if len(ret) == 0 {
46+ panic("no return value specified for Close")
47+ }
48+
49+ var r0 error
50+ if returnFunc, ok := ret.Get(0).(func() error); ok {
51+ r0 = returnFunc()
52+ } else {
53+ r0 = ret.Error(0)
54+ }
55+ return r0
56+}
57+
58+// MockPlayer_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close'
59+type MockPlayer_Close_Call struct {
60+ *mock.Call
61+}
62+
63+// Close is a helper method to define mock.On call
64+func (_e *MockPlayer_Expecter) Close() *MockPlayer_Close_Call {
65+ return &MockPlayer_Close_Call{Call: _e.mock.On("Close")}
66+}
67+
68+func (_c *MockPlayer_Close_Call) Run(run func()) *MockPlayer_Close_Call {
69+ _c.Call.Run(func(args mock.Arguments) {
70+ run()
71+ })
72+ return _c
73+}
74+
75+func (_c *MockPlayer_Close_Call) Return(err error) *MockPlayer_Close_Call {
76+ _c.Call.Return(err)
77+ return _c
78+}
79+
80+func (_c *MockPlayer_Close_Call) RunAndReturn(run func() error) *MockPlayer_Close_Call {
81+ _c.Call.Return(run)
82+ return _c
83+}
84+
85+// NewStream provides a mock function for the type MockPlayer
86+func (_mock *MockPlayer) NewStream(ctx context.Context, format pipewire.AudioFormat) (pipewire.PlaybackStream, error) {
87+ ret := _mock.Called(ctx, format)
88+
89+ if len(ret) == 0 {
90+ panic("no return value specified for NewStream")
91+ }
92+
93+ var r0 pipewire.PlaybackStream
94+ var r1 error
95+ if returnFunc, ok := ret.Get(0).(func(context.Context, pipewire.AudioFormat) (pipewire.PlaybackStream, error)); ok {
96+ return returnFunc(ctx, format)
97+ }
98+ if returnFunc, ok := ret.Get(0).(func(context.Context, pipewire.AudioFormat) pipewire.PlaybackStream); ok {
99+ r0 = returnFunc(ctx, format)
100+ } else {
101+ if ret.Get(0) != nil {
102+ r0 = ret.Get(0).(pipewire.PlaybackStream)
103+ }
104+ }
105+ if returnFunc, ok := ret.Get(1).(func(context.Context, pipewire.AudioFormat) error); ok {
106+ r1 = returnFunc(ctx, format)
107+ } else {
108+ r1 = ret.Error(1)
109+ }
110+ return r0, r1
111+}
112+
113+// MockPlayer_NewStream_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NewStream'
114+type MockPlayer_NewStream_Call struct {
115+ *mock.Call
116+}
117+
118+// NewStream is a helper method to define mock.On call
119+// - ctx context.Context
120+// - format pipewire.AudioFormat
121+func (_e *MockPlayer_Expecter) NewStream(ctx interface{}, format interface{}) *MockPlayer_NewStream_Call {
122+ return &MockPlayer_NewStream_Call{Call: _e.mock.On("NewStream", ctx, format)}
123+}
124+
125+func (_c *MockPlayer_NewStream_Call) Run(run func(ctx context.Context, format pipewire.AudioFormat)) *MockPlayer_NewStream_Call {
126+ _c.Call.Run(func(args mock.Arguments) {
127+ var arg0 context.Context
128+ if args[0] != nil {
129+ arg0 = args[0].(context.Context)
130+ }
131+ var arg1 pipewire.AudioFormat
132+ if args[1] != nil {
133+ arg1 = args[1].(pipewire.AudioFormat)
134+ }
135+ run(
136+ arg0,
137+ arg1,
138+ )
139+ })
140+ return _c
141+}
142+
143+func (_c *MockPlayer_NewStream_Call) Return(playbackStream pipewire.PlaybackStream, err error) *MockPlayer_NewStream_Call {
144+ _c.Call.Return(playbackStream, err)
145+ return _c
146+}
147+
148+func (_c *MockPlayer_NewStream_Call) RunAndReturn(run func(ctx context.Context, format pipewire.AudioFormat) (pipewire.PlaybackStream, error)) *MockPlayer_NewStream_Call {
149+ _c.Call.Return(run)
150+ return _c
151+}
@@ -0,0 +1,151 @@
1+// Code generated by mockery; DO NOT EDIT.
2+// github.com/vektra/mockery
3+// template: testify
4+
5+package mocks
6+
7+import (
8+ "context"
9+
10+ "github.com/bnema/purego-pipewire/pipewire"
11+ mock "github.com/stretchr/testify/mock"
12+)
13+
14+// NewMockPlayer creates a new instance of MockPlayer. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
15+// The first argument is typically a *testing.T value.
16+func NewMockPlayer(t interface {
17+ mock.TestingT
18+ Cleanup(func())
19+}) *MockPlayer {
20+ mock := &MockPlayer{}
21+ mock.Mock.Test(t)
22+
23+ t.Cleanup(func() { mock.AssertExpectations(t) })
24+
25+ return mock
26+}
27+
28+// MockPlayer is an autogenerated mock type for the Player type
29+type MockPlayer struct {
30+ mock.Mock
31+}
32+
33+type MockPlayer_Expecter struct {
34+ mock *mock.Mock
35+}
36+
37+func (_m *MockPlayer) EXPECT() *MockPlayer_Expecter {
38+ return &MockPlayer_Expecter{mock: &_m.Mock}
39+}
40+
41+// Close provides a mock function for the type MockPlayer
42+func (_mock *MockPlayer) Close() error {
43+ ret := _mock.Called()
44+
45+ if len(ret) == 0 {
46+ panic("no return value specified for Close")
47+ }
48+
49+ var r0 error
50+ if returnFunc, ok := ret.Get(0).(func() error); ok {
51+ r0 = returnFunc()
52+ } else {
53+ r0 = ret.Error(0)
54+ }
55+ return r0
56+}
57+
58+// MockPlayer_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close'
59+type MockPlayer_Close_Call struct {
60+ *mock.Call
61+}
62+
63+// Close is a helper method to define mock.On call
64+func (_e *MockPlayer_Expecter) Close() *MockPlayer_Close_Call {
65+ return &MockPlayer_Close_Call{Call: _e.mock.On("Close")}
66+}
67+
68+func (_c *MockPlayer_Close_Call) Run(run func()) *MockPlayer_Close_Call {
69+ _c.Call.Run(func(args mock.Arguments) {
70+ run()
71+ })
72+ return _c
73+}
74+
75+func (_c *MockPlayer_Close_Call) Return(err error) *MockPlayer_Close_Call {
76+ _c.Call.Return(err)
77+ return _c
78+}
79+
80+func (_c *MockPlayer_Close_Call) RunAndReturn(run func() error) *MockPlayer_Close_Call {
81+ _c.Call.Return(run)
82+ return _c
83+}
84+
85+// NewStream provides a mock function for the type MockPlayer
86+func (_mock *MockPlayer) NewStream(ctx context.Context, format pipewire.AudioFormat) (pipewire.PlaybackStream, error) {
87+ ret := _mock.Called(ctx, format)
88+
89+ if len(ret) == 0 {
90+ panic("no return value specified for NewStream")
91+ }
92+
93+ var r0 pipewire.PlaybackStream
94+ var r1 error
95+ if returnFunc, ok := ret.Get(0).(func(context.Context, pipewire.AudioFormat) (pipewire.PlaybackStream, error)); ok {
96+ return returnFunc(ctx, format)
97+ }
98+ if returnFunc, ok := ret.Get(0).(func(context.Context, pipewire.AudioFormat) pipewire.PlaybackStream); ok {
99+ r0 = returnFunc(ctx, format)
100+ } else {
101+ if ret.Get(0) != nil {
102+ r0 = ret.Get(0).(pipewire.PlaybackStream)
103+ }
104+ }
105+ if returnFunc, ok := ret.Get(1).(func(context.Context, pipewire.AudioFormat) error); ok {
106+ r1 = returnFunc(ctx, format)
107+ } else {
108+ r1 = ret.Error(1)
109+ }
110+ return r0, r1
111+}
112+
113+// MockPlayer_NewStream_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NewStream'
114+type MockPlayer_NewStream_Call struct {
115+ *mock.Call
116+}
117+
118+// NewStream is a helper method to define mock.On call
119+// - ctx context.Context
120+// - format pipewire.AudioFormat
121+func (_e *MockPlayer_Expecter) NewStream(ctx interface{}, format interface{}) *MockPlayer_NewStream_Call {
122+ return &MockPlayer_NewStream_Call{Call: _e.mock.On("NewStream", ctx, format)}
123+}
124+
125+func (_c *MockPlayer_NewStream_Call) Run(run func(ctx context.Context, format pipewire.AudioFormat)) *MockPlayer_NewStream_Call {
126+ _c.Call.Run(func(args mock.Arguments) {
127+ var arg0 context.Context
128+ if args[0] != nil {
129+ arg0 = args[0].(context.Context)
130+ }
131+ var arg1 pipewire.AudioFormat
132+ if args[1] != nil {
133+ arg1 = args[1].(pipewire.AudioFormat)
134+ }
135+ run(
136+ arg0,
137+ arg1,
138+ )
139+ })
140+ return _c
141+}
142+
143+func (_c *MockPlayer_NewStream_Call) Return(playbackStream pipewire.PlaybackStream, err error) *MockPlayer_NewStream_Call {
144+ _c.Call.Return(playbackStream, err)
145+ return _c
146+}
147+
148+func (_c *MockPlayer_NewStream_Call) RunAndReturn(run func(ctx context.Context, format pipewire.AudioFormat) (pipewire.PlaybackStream, error)) *MockPlayer_NewStream_Call {
149+ _c.Call.Return(run)
150+ return _c
151+}
A pipewire/player.go +34 -0
@@ -0,0 +1,34 @@
1+package pipewire
2+
3+import (
4+ "context"
5+ "errors"
6+)
7+
8+// ErrNotImplemented is returned by stub functions that are not yet implemented.
9+var ErrNotImplemented = errors.New("not implemented")
10+
11+// AudioFormat describes the audio format for a playback stream.
12+type AudioFormat struct {
13+ SampleRate int
14+ Channels int
15+ FramesPerBuffer int
16+}
17+
18+// PlaybackStream is the public interface for writing audio samples to PipeWire.
19+type PlaybackStream interface {
20+ Write(samples [][]float32) error
21+ Close() error
22+}
23+
24+// Player is the public interface for creating audio playback streams.
25+type Player interface {
26+ NewStream(ctx context.Context, format AudioFormat) (PlaybackStream, error)
27+ Close() error
28+}
29+
30+// NewPlayer creates a new Player for audio playback.
31+// This is currently a stub and returns ErrNotImplemented.
32+func NewPlayer() (Player, error) {
33+ return nil, ErrNotImplemented
34+}
@@ -0,0 +1,34 @@
1+package pipewire
2+
3+import (
4+ "context"
5+ "errors"
6+)
7+
8+// ErrNotImplemented is returned by stub functions that are not yet implemented.
9+var ErrNotImplemented = errors.New("not implemented")
10+
11+// AudioFormat describes the audio format for a playback stream.
12+type AudioFormat struct {
13+ SampleRate int
14+ Channels int
15+ FramesPerBuffer int
16+}
17+
18+// PlaybackStream is the public interface for writing audio samples to PipeWire.
19+type PlaybackStream interface {
20+ Write(samples [][]float32) error
21+ Close() error
22+}
23+
24+// Player is the public interface for creating audio playback streams.
25+type Player interface {
26+ NewStream(ctx context.Context, format AudioFormat) (PlaybackStream, error)
27+ Close() error
28+}
29+
30+// NewPlayer creates a new Player for audio playback.
31+// This is currently a stub and returns ErrNotImplemented.
32+func NewPlayer() (Player, error) {
33+ return nil, ErrNotImplemented
34+}
A pipewire/player_test.go +20 -0
@@ -0,0 +1,20 @@
1+package pipewire
2+
3+import (
4+ "errors"
5+ "testing"
6+)
7+
8+func TestNewPlayerReturnsError(t *testing.T) {
9+ p, err := NewPlayer()
10+ if err == nil {
11+ t.Fatal("expected NewPlayer to return an error (not yet implemented)")
12+ }
13+ if p != nil {
14+ t.Fatal("expected NewPlayer to return nil player when erroring")
15+ }
16+ // Verify the error message indicates not-implemented.
17+ if !errors.Is(err, ErrNotImplemented) {
18+ t.Fatalf("expected ErrNotImplemented, got: %v", err)
19+ }
20+}
@@ -0,0 +1,20 @@
1+package pipewire
2+
3+import (
4+ "errors"
5+ "testing"
6+)
7+
8+func TestNewPlayerReturnsError(t *testing.T) {
9+ p, err := NewPlayer()
10+ if err == nil {
11+ t.Fatal("expected NewPlayer to return an error (not yet implemented)")
12+ }
13+ if p != nil {
14+ t.Fatal("expected NewPlayer to return nil player when erroring")
15+ }
16+ // Verify the error message indicates not-implemented.
17+ if !errors.Is(err, ErrNotImplemented) {
18+ t.Fatalf("expected ErrNotImplemented, got: %v", err)
19+ }
20+}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 1

Tags 8

↑↓ moveenter openesc close