detached 07c742c

feat: replace stub player API with typed config surface

commit
07c742c945beae9d662a5c6076d2dc893a52bbf0
author
brice · · 2026-04-09 14:16 UTC
parent
a5a9e72
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
4 files · +404 -0
M .mockery.yml +1 -0
@@ -22,3 +22,4 @@ packages:
2222 interfaces:
2323 Runtime:
2424 MainLoop:
25+ Player:
@@ -22,3 +22,4 @@ packages:
22 interfaces:22 interfaces:
23 Runtime:23 Runtime:
24 MainLoop:24 MainLoop:
25+ Player:
A pipewire/mocks/mock_Player.go +257 -0
@@ -0,0 +1,257 @@
1+// Code generated by mockery; DO NOT EDIT.
2+// github.com/vektra/mockery
3+// template: testify
4+
5+package mocks
6+
7+import (
8+ "github.com/bnema/purego-pipewire/pipewire"
9+ mock "github.com/stretchr/testify/mock"
10+)
11+
12+// 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.
13+// The first argument is typically a *testing.T value.
14+func NewMockPlayer(t interface {
15+ mock.TestingT
16+ Cleanup(func())
17+}) *MockPlayer {
18+ mock := &MockPlayer{}
19+ mock.Mock.Test(t)
20+
21+ t.Cleanup(func() { mock.AssertExpectations(t) })
22+
23+ return mock
24+}
25+
26+// MockPlayer is an autogenerated mock type for the Player type
27+type MockPlayer struct {
28+ mock.Mock
29+}
30+
31+type MockPlayer_Expecter struct {
32+ mock *mock.Mock
33+}
34+
35+func (_m *MockPlayer) EXPECT() *MockPlayer_Expecter {
36+ return &MockPlayer_Expecter{mock: &_m.Mock}
37+}
38+
39+// Close provides a mock function for the type MockPlayer
40+func (_mock *MockPlayer) Close() error {
41+ ret := _mock.Called()
42+
43+ if len(ret) == 0 {
44+ panic("no return value specified for Close")
45+ }
46+
47+ var r0 error
48+ if returnFunc, ok := ret.Get(0).(func() error); ok {
49+ r0 = returnFunc()
50+ } else {
51+ r0 = ret.Error(0)
52+ }
53+ return r0
54+}
55+
56+// MockPlayer_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close'
57+type MockPlayer_Close_Call struct {
58+ *mock.Call
59+}
60+
61+// Close is a helper method to define mock.On call
62+func (_e *MockPlayer_Expecter) Close() *MockPlayer_Close_Call {
63+ return &MockPlayer_Close_Call{Call: _e.mock.On("Close")}
64+}
65+
66+func (_c *MockPlayer_Close_Call) Run(run func()) *MockPlayer_Close_Call {
67+ _c.Call.Run(func(args mock.Arguments) {
68+ run()
69+ })
70+ return _c
71+}
72+
73+func (_c *MockPlayer_Close_Call) Return(err error) *MockPlayer_Close_Call {
74+ _c.Call.Return(err)
75+ return _c
76+}
77+
78+func (_c *MockPlayer_Close_Call) RunAndReturn(run func() error) *MockPlayer_Close_Call {
79+ _c.Call.Return(run)
80+ return _c
81+}
82+
83+// Pause provides a mock function for the type MockPlayer
84+func (_mock *MockPlayer) Pause() error {
85+ ret := _mock.Called()
86+
87+ if len(ret) == 0 {
88+ panic("no return value specified for Pause")
89+ }
90+
91+ var r0 error
92+ if returnFunc, ok := ret.Get(0).(func() error); ok {
93+ r0 = returnFunc()
94+ } else {
95+ r0 = ret.Error(0)
96+ }
97+ return r0
98+}
99+
100+// MockPlayer_Pause_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Pause'
101+type MockPlayer_Pause_Call struct {
102+ *mock.Call
103+}
104+
105+// Pause is a helper method to define mock.On call
106+func (_e *MockPlayer_Expecter) Pause() *MockPlayer_Pause_Call {
107+ return &MockPlayer_Pause_Call{Call: _e.mock.On("Pause")}
108+}
109+
110+func (_c *MockPlayer_Pause_Call) Run(run func()) *MockPlayer_Pause_Call {
111+ _c.Call.Run(func(args mock.Arguments) {
112+ run()
113+ })
114+ return _c
115+}
116+
117+func (_c *MockPlayer_Pause_Call) Return(err error) *MockPlayer_Pause_Call {
118+ _c.Call.Return(err)
119+ return _c
120+}
121+
122+func (_c *MockPlayer_Pause_Call) RunAndReturn(run func() error) *MockPlayer_Pause_Call {
123+ _c.Call.Return(run)
124+ return _c
125+}
126+
127+// Start provides a mock function for the type MockPlayer
128+func (_mock *MockPlayer) Start() error {
129+ ret := _mock.Called()
130+
131+ if len(ret) == 0 {
132+ panic("no return value specified for Start")
133+ }
134+
135+ var r0 error
136+ if returnFunc, ok := ret.Get(0).(func() error); ok {
137+ r0 = returnFunc()
138+ } else {
139+ r0 = ret.Error(0)
140+ }
141+ return r0
142+}
143+
144+// MockPlayer_Start_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Start'
145+type MockPlayer_Start_Call struct {
146+ *mock.Call
147+}
148+
149+// Start is a helper method to define mock.On call
150+func (_e *MockPlayer_Expecter) Start() *MockPlayer_Start_Call {
151+ return &MockPlayer_Start_Call{Call: _e.mock.On("Start")}
152+}
153+
154+func (_c *MockPlayer_Start_Call) Run(run func()) *MockPlayer_Start_Call {
155+ _c.Call.Run(func(args mock.Arguments) {
156+ run()
157+ })
158+ return _c
159+}
160+
161+func (_c *MockPlayer_Start_Call) Return(err error) *MockPlayer_Start_Call {
162+ _c.Call.Return(err)
163+ return _c
164+}
165+
166+func (_c *MockPlayer_Start_Call) RunAndReturn(run func() error) *MockPlayer_Start_Call {
167+ _c.Call.Return(run)
168+ return _c
169+}
170+
171+// State provides a mock function for the type MockPlayer
172+func (_mock *MockPlayer) State() pipewire.PlayerState {
173+ ret := _mock.Called()
174+
175+ if len(ret) == 0 {
176+ panic("no return value specified for State")
177+ }
178+
179+ var r0 pipewire.PlayerState
180+ if returnFunc, ok := ret.Get(0).(func() pipewire.PlayerState); ok {
181+ r0 = returnFunc()
182+ } else {
183+ r0 = ret.Get(0).(pipewire.PlayerState)
184+ }
185+ return r0
186+}
187+
188+// MockPlayer_State_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'State'
189+type MockPlayer_State_Call struct {
190+ *mock.Call
191+}
192+
193+// State is a helper method to define mock.On call
194+func (_e *MockPlayer_Expecter) State() *MockPlayer_State_Call {
195+ return &MockPlayer_State_Call{Call: _e.mock.On("State")}
196+}
197+
198+func (_c *MockPlayer_State_Call) Run(run func()) *MockPlayer_State_Call {
199+ _c.Call.Run(func(args mock.Arguments) {
200+ run()
201+ })
202+ return _c
203+}
204+
205+func (_c *MockPlayer_State_Call) Return(playerState pipewire.PlayerState) *MockPlayer_State_Call {
206+ _c.Call.Return(playerState)
207+ return _c
208+}
209+
210+func (_c *MockPlayer_State_Call) RunAndReturn(run func() pipewire.PlayerState) *MockPlayer_State_Call {
211+ _c.Call.Return(run)
212+ return _c
213+}
214+
215+// Stop provides a mock function for the type MockPlayer
216+func (_mock *MockPlayer) Stop() error {
217+ ret := _mock.Called()
218+
219+ if len(ret) == 0 {
220+ panic("no return value specified for Stop")
221+ }
222+
223+ var r0 error
224+ if returnFunc, ok := ret.Get(0).(func() error); ok {
225+ r0 = returnFunc()
226+ } else {
227+ r0 = ret.Error(0)
228+ }
229+ return r0
230+}
231+
232+// MockPlayer_Stop_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Stop'
233+type MockPlayer_Stop_Call struct {
234+ *mock.Call
235+}
236+
237+// Stop is a helper method to define mock.On call
238+func (_e *MockPlayer_Expecter) Stop() *MockPlayer_Stop_Call {
239+ return &MockPlayer_Stop_Call{Call: _e.mock.On("Stop")}
240+}
241+
242+func (_c *MockPlayer_Stop_Call) Run(run func()) *MockPlayer_Stop_Call {
243+ _c.Call.Run(func(args mock.Arguments) {
244+ run()
245+ })
246+ return _c
247+}
248+
249+func (_c *MockPlayer_Stop_Call) Return(err error) *MockPlayer_Stop_Call {
250+ _c.Call.Return(err)
251+ return _c
252+}
253+
254+func (_c *MockPlayer_Stop_Call) RunAndReturn(run func() error) *MockPlayer_Stop_Call {
255+ _c.Call.Return(run)
256+ return _c
257+}
@@ -0,0 +1,257 @@
1+// Code generated by mockery; DO NOT EDIT.
2+// github.com/vektra/mockery
3+// template: testify
4+
5+package mocks
6+
7+import (
8+ "github.com/bnema/purego-pipewire/pipewire"
9+ mock "github.com/stretchr/testify/mock"
10+)
11+
12+// 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.
13+// The first argument is typically a *testing.T value.
14+func NewMockPlayer(t interface {
15+ mock.TestingT
16+ Cleanup(func())
17+}) *MockPlayer {
18+ mock := &MockPlayer{}
19+ mock.Mock.Test(t)
20+
21+ t.Cleanup(func() { mock.AssertExpectations(t) })
22+
23+ return mock
24+}
25+
26+// MockPlayer is an autogenerated mock type for the Player type
27+type MockPlayer struct {
28+ mock.Mock
29+}
30+
31+type MockPlayer_Expecter struct {
32+ mock *mock.Mock
33+}
34+
35+func (_m *MockPlayer) EXPECT() *MockPlayer_Expecter {
36+ return &MockPlayer_Expecter{mock: &_m.Mock}
37+}
38+
39+// Close provides a mock function for the type MockPlayer
40+func (_mock *MockPlayer) Close() error {
41+ ret := _mock.Called()
42+
43+ if len(ret) == 0 {
44+ panic("no return value specified for Close")
45+ }
46+
47+ var r0 error
48+ if returnFunc, ok := ret.Get(0).(func() error); ok {
49+ r0 = returnFunc()
50+ } else {
51+ r0 = ret.Error(0)
52+ }
53+ return r0
54+}
55+
56+// MockPlayer_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close'
57+type MockPlayer_Close_Call struct {
58+ *mock.Call
59+}
60+
61+// Close is a helper method to define mock.On call
62+func (_e *MockPlayer_Expecter) Close() *MockPlayer_Close_Call {
63+ return &MockPlayer_Close_Call{Call: _e.mock.On("Close")}
64+}
65+
66+func (_c *MockPlayer_Close_Call) Run(run func()) *MockPlayer_Close_Call {
67+ _c.Call.Run(func(args mock.Arguments) {
68+ run()
69+ })
70+ return _c
71+}
72+
73+func (_c *MockPlayer_Close_Call) Return(err error) *MockPlayer_Close_Call {
74+ _c.Call.Return(err)
75+ return _c
76+}
77+
78+func (_c *MockPlayer_Close_Call) RunAndReturn(run func() error) *MockPlayer_Close_Call {
79+ _c.Call.Return(run)
80+ return _c
81+}
82+
83+// Pause provides a mock function for the type MockPlayer
84+func (_mock *MockPlayer) Pause() error {
85+ ret := _mock.Called()
86+
87+ if len(ret) == 0 {
88+ panic("no return value specified for Pause")
89+ }
90+
91+ var r0 error
92+ if returnFunc, ok := ret.Get(0).(func() error); ok {
93+ r0 = returnFunc()
94+ } else {
95+ r0 = ret.Error(0)
96+ }
97+ return r0
98+}
99+
100+// MockPlayer_Pause_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Pause'
101+type MockPlayer_Pause_Call struct {
102+ *mock.Call
103+}
104+
105+// Pause is a helper method to define mock.On call
106+func (_e *MockPlayer_Expecter) Pause() *MockPlayer_Pause_Call {
107+ return &MockPlayer_Pause_Call{Call: _e.mock.On("Pause")}
108+}
109+
110+func (_c *MockPlayer_Pause_Call) Run(run func()) *MockPlayer_Pause_Call {
111+ _c.Call.Run(func(args mock.Arguments) {
112+ run()
113+ })
114+ return _c
115+}
116+
117+func (_c *MockPlayer_Pause_Call) Return(err error) *MockPlayer_Pause_Call {
118+ _c.Call.Return(err)
119+ return _c
120+}
121+
122+func (_c *MockPlayer_Pause_Call) RunAndReturn(run func() error) *MockPlayer_Pause_Call {
123+ _c.Call.Return(run)
124+ return _c
125+}
126+
127+// Start provides a mock function for the type MockPlayer
128+func (_mock *MockPlayer) Start() error {
129+ ret := _mock.Called()
130+
131+ if len(ret) == 0 {
132+ panic("no return value specified for Start")
133+ }
134+
135+ var r0 error
136+ if returnFunc, ok := ret.Get(0).(func() error); ok {
137+ r0 = returnFunc()
138+ } else {
139+ r0 = ret.Error(0)
140+ }
141+ return r0
142+}
143+
144+// MockPlayer_Start_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Start'
145+type MockPlayer_Start_Call struct {
146+ *mock.Call
147+}
148+
149+// Start is a helper method to define mock.On call
150+func (_e *MockPlayer_Expecter) Start() *MockPlayer_Start_Call {
151+ return &MockPlayer_Start_Call{Call: _e.mock.On("Start")}
152+}
153+
154+func (_c *MockPlayer_Start_Call) Run(run func()) *MockPlayer_Start_Call {
155+ _c.Call.Run(func(args mock.Arguments) {
156+ run()
157+ })
158+ return _c
159+}
160+
161+func (_c *MockPlayer_Start_Call) Return(err error) *MockPlayer_Start_Call {
162+ _c.Call.Return(err)
163+ return _c
164+}
165+
166+func (_c *MockPlayer_Start_Call) RunAndReturn(run func() error) *MockPlayer_Start_Call {
167+ _c.Call.Return(run)
168+ return _c
169+}
170+
171+// State provides a mock function for the type MockPlayer
172+func (_mock *MockPlayer) State() pipewire.PlayerState {
173+ ret := _mock.Called()
174+
175+ if len(ret) == 0 {
176+ panic("no return value specified for State")
177+ }
178+
179+ var r0 pipewire.PlayerState
180+ if returnFunc, ok := ret.Get(0).(func() pipewire.PlayerState); ok {
181+ r0 = returnFunc()
182+ } else {
183+ r0 = ret.Get(0).(pipewire.PlayerState)
184+ }
185+ return r0
186+}
187+
188+// MockPlayer_State_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'State'
189+type MockPlayer_State_Call struct {
190+ *mock.Call
191+}
192+
193+// State is a helper method to define mock.On call
194+func (_e *MockPlayer_Expecter) State() *MockPlayer_State_Call {
195+ return &MockPlayer_State_Call{Call: _e.mock.On("State")}
196+}
197+
198+func (_c *MockPlayer_State_Call) Run(run func()) *MockPlayer_State_Call {
199+ _c.Call.Run(func(args mock.Arguments) {
200+ run()
201+ })
202+ return _c
203+}
204+
205+func (_c *MockPlayer_State_Call) Return(playerState pipewire.PlayerState) *MockPlayer_State_Call {
206+ _c.Call.Return(playerState)
207+ return _c
208+}
209+
210+func (_c *MockPlayer_State_Call) RunAndReturn(run func() pipewire.PlayerState) *MockPlayer_State_Call {
211+ _c.Call.Return(run)
212+ return _c
213+}
214+
215+// Stop provides a mock function for the type MockPlayer
216+func (_mock *MockPlayer) Stop() error {
217+ ret := _mock.Called()
218+
219+ if len(ret) == 0 {
220+ panic("no return value specified for Stop")
221+ }
222+
223+ var r0 error
224+ if returnFunc, ok := ret.Get(0).(func() error); ok {
225+ r0 = returnFunc()
226+ } else {
227+ r0 = ret.Error(0)
228+ }
229+ return r0
230+}
231+
232+// MockPlayer_Stop_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Stop'
233+type MockPlayer_Stop_Call struct {
234+ *mock.Call
235+}
236+
237+// Stop is a helper method to define mock.On call
238+func (_e *MockPlayer_Expecter) Stop() *MockPlayer_Stop_Call {
239+ return &MockPlayer_Stop_Call{Call: _e.mock.On("Stop")}
240+}
241+
242+func (_c *MockPlayer_Stop_Call) Run(run func()) *MockPlayer_Stop_Call {
243+ _c.Call.Run(func(args mock.Arguments) {
244+ run()
245+ })
246+ return _c
247+}
248+
249+func (_c *MockPlayer_Stop_Call) Return(err error) *MockPlayer_Stop_Call {
250+ _c.Call.Return(err)
251+ return _c
252+}
253+
254+func (_c *MockPlayer_Stop_Call) RunAndReturn(run func() error) *MockPlayer_Stop_Call {
255+ _c.Call.Return(run)
256+ return _c
257+}
A pipewire/player.go +134 -0
@@ -0,0 +1,134 @@
1+package pipewire
2+
3+import (
4+ "errors"
5+)
6+
7+// SampleFormat represents the audio sample format type.
8+type SampleFormat int
9+
10+const (
11+ // SampleFormatF32 is the 32-bit floating point sample format.
12+ SampleFormatF32 SampleFormat = iota
13+)
14+
15+// UnderrunPolicy defines the behavior when a buffer underrun occurs.
16+type UnderrunPolicy int
17+
18+const (
19+ // UnderrunFillSilence fills the buffer with silence on underrun.
20+ UnderrunFillSilence UnderrunPolicy = iota
21+ // UnderrunFail fails playback on underrun.
22+ UnderrunFail
23+)
24+
25+// PlayerState represents the current state of the audio player.
26+type PlayerState int
27+
28+const (
29+ // Idle is the initial state before the player is started.
30+ Idle PlayerState = iota
31+ // Starting indicates the player is initializing.
32+ Starting
33+ // Playing indicates the player is actively outputting audio.
34+ Playing
35+ // Paused indicates the player is temporarily stopped.
36+ Paused
37+ // Stopped indicates the player has been stopped.
38+ Stopped
39+ // Closing indicates the player is shutting down.
40+ Closing
41+ // Closed indicates the player has been fully closed.
42+ Closed
43+ // Error indicates the player encountered an error.
44+ Error
45+)
46+
47+// PlayerConfig holds the configuration for a new audio player.
48+type PlayerConfig struct {
49+ SampleRate int
50+ Channels int
51+ FramesPerBuffer int
52+ SampleFormat SampleFormat
53+ UnderrunPolicy UnderrunPolicy
54+}
55+
56+// PCMBuffer represents a buffer of PCM audio data.
57+type PCMBuffer struct {
58+ Frames int
59+ Channels int
60+ Stride int
61+ Samples [][]float32
62+}
63+
64+// PlayerCallbacks contains all callback functions for player events.
65+type PlayerCallbacks struct {
66+ Fill func(*PCMBuffer) (int, error)
67+ OnUnderrun func(int)
68+ OnDrain func()
69+ OnError func(error)
70+ OnStateChange func(PlayerState)
71+}
72+
73+// Player is the public interface for audio playback.
74+type Player interface {
75+ Start() error
76+ Pause() error
77+ Stop() error
78+ Close() error
79+ State() PlayerState
80+}
81+
82+// ErrInvalidPlayerConfig is returned when the player configuration is invalid.
83+var ErrInvalidPlayerConfig = errors.New("invalid player config")
84+
85+// playerImpl is a placeholder implementation of the Player interface.
86+// Full implementation will be added in subsequent tasks.
87+type playerImpl struct {
88+ config PlayerConfig
89+ callbacks PlayerCallbacks
90+ state PlayerState
91+}
92+
93+func (p *playerImpl) Start() error {
94+ return nil
95+}
96+
97+func (p *playerImpl) Pause() error {
98+ return nil
99+}
100+
101+func (p *playerImpl) Stop() error {
102+ return nil
103+}
104+
105+func (p *playerImpl) Close() error {
106+ return nil
107+}
108+
109+func (p *playerImpl) State() PlayerState {
110+ return p.state
111+}
112+
113+// NewPlayer creates a new audio player with the given configuration and callbacks.
114+// Returns ErrInvalidPlayerConfig if the configuration is invalid.
115+func NewPlayer(config PlayerConfig, callbacks PlayerCallbacks) (Player, error) {
116+ if config.SampleRate <= 0 {
117+ return nil, ErrInvalidPlayerConfig
118+ }
119+ if config.Channels <= 0 {
120+ return nil, ErrInvalidPlayerConfig
121+ }
122+ if config.FramesPerBuffer <= 0 {
123+ return nil, ErrInvalidPlayerConfig
124+ }
125+ if config.SampleFormat != SampleFormatF32 {
126+ return nil, ErrInvalidPlayerConfig
127+ }
128+
129+ return &playerImpl{
130+ config: config,
131+ callbacks: callbacks,
132+ state: Idle,
133+ }, nil
134+}
@@ -0,0 +1,134 @@
1+package pipewire
2+
3+import (
4+ "errors"
5+)
6+
7+// SampleFormat represents the audio sample format type.
8+type SampleFormat int
9+
10+const (
11+ // SampleFormatF32 is the 32-bit floating point sample format.
12+ SampleFormatF32 SampleFormat = iota
13+)
14+
15+// UnderrunPolicy defines the behavior when a buffer underrun occurs.
16+type UnderrunPolicy int
17+
18+const (
19+ // UnderrunFillSilence fills the buffer with silence on underrun.
20+ UnderrunFillSilence UnderrunPolicy = iota
21+ // UnderrunFail fails playback on underrun.
22+ UnderrunFail
23+)
24+
25+// PlayerState represents the current state of the audio player.
26+type PlayerState int
27+
28+const (
29+ // Idle is the initial state before the player is started.
30+ Idle PlayerState = iota
31+ // Starting indicates the player is initializing.
32+ Starting
33+ // Playing indicates the player is actively outputting audio.
34+ Playing
35+ // Paused indicates the player is temporarily stopped.
36+ Paused
37+ // Stopped indicates the player has been stopped.
38+ Stopped
39+ // Closing indicates the player is shutting down.
40+ Closing
41+ // Closed indicates the player has been fully closed.
42+ Closed
43+ // Error indicates the player encountered an error.
44+ Error
45+)
46+
47+// PlayerConfig holds the configuration for a new audio player.
48+type PlayerConfig struct {
49+ SampleRate int
50+ Channels int
51+ FramesPerBuffer int
52+ SampleFormat SampleFormat
53+ UnderrunPolicy UnderrunPolicy
54+}
55+
56+// PCMBuffer represents a buffer of PCM audio data.
57+type PCMBuffer struct {
58+ Frames int
59+ Channels int
60+ Stride int
61+ Samples [][]float32
62+}
63+
64+// PlayerCallbacks contains all callback functions for player events.
65+type PlayerCallbacks struct {
66+ Fill func(*PCMBuffer) (int, error)
67+ OnUnderrun func(int)
68+ OnDrain func()
69+ OnError func(error)
70+ OnStateChange func(PlayerState)
71+}
72+
73+// Player is the public interface for audio playback.
74+type Player interface {
75+ Start() error
76+ Pause() error
77+ Stop() error
78+ Close() error
79+ State() PlayerState
80+}
81+
82+// ErrInvalidPlayerConfig is returned when the player configuration is invalid.
83+var ErrInvalidPlayerConfig = errors.New("invalid player config")
84+
85+// playerImpl is a placeholder implementation of the Player interface.
86+// Full implementation will be added in subsequent tasks.
87+type playerImpl struct {
88+ config PlayerConfig
89+ callbacks PlayerCallbacks
90+ state PlayerState
91+}
92+
93+func (p *playerImpl) Start() error {
94+ return nil
95+}
96+
97+func (p *playerImpl) Pause() error {
98+ return nil
99+}
100+
101+func (p *playerImpl) Stop() error {
102+ return nil
103+}
104+
105+func (p *playerImpl) Close() error {
106+ return nil
107+}
108+
109+func (p *playerImpl) State() PlayerState {
110+ return p.state
111+}
112+
113+// NewPlayer creates a new audio player with the given configuration and callbacks.
114+// Returns ErrInvalidPlayerConfig if the configuration is invalid.
115+func NewPlayer(config PlayerConfig, callbacks PlayerCallbacks) (Player, error) {
116+ if config.SampleRate <= 0 {
117+ return nil, ErrInvalidPlayerConfig
118+ }
119+ if config.Channels <= 0 {
120+ return nil, ErrInvalidPlayerConfig
121+ }
122+ if config.FramesPerBuffer <= 0 {
123+ return nil, ErrInvalidPlayerConfig
124+ }
125+ if config.SampleFormat != SampleFormatF32 {
126+ return nil, ErrInvalidPlayerConfig
127+ }
128+
129+ return &playerImpl{
130+ config: config,
131+ callbacks: callbacks,
132+ state: Idle,
133+ }, nil
134+}
A pipewire/player_test.go +12 -0
@@ -0,0 +1,12 @@
1+package pipewire
2+
3+import (
4+ "testing"
5+)
6+
7+func TestNewPlayerRejectsInvalidConfig(t *testing.T) {
8+ _, err := NewPlayer(PlayerConfig{}, PlayerCallbacks{})
9+ if err == nil {
10+ t.Fatal("NewPlayer returned nil error for invalid config")
11+ }
12+}
@@ -0,0 +1,12 @@
1+package pipewire
2+
3+import (
4+ "testing"
5+)
6+
7+func TestNewPlayerRejectsInvalidConfig(t *testing.T) {
8+ _, err := NewPlayer(PlayerConfig{}, PlayerCallbacks{})
9+ if err == nil {
10+ t.Fatal("NewPlayer returned nil error for invalid config")
11+ }
12+}

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