@@ -85,9 +85,8 @@ func NewSwitchWriter(sampleRate int) *SwitchWriter {
8585}
8686
8787type SwitchWriter struct {
88- ptr atomic.Pointer [PCM16Writer ]
89- sampleRate atomic.Int32
90- disabled atomic.Bool
88+ WriteCloserSwitch [PCM16Sample ]
89+ disabled atomic.Bool
9190}
9291
9392func (s * SwitchWriter ) Enable () {
@@ -99,29 +98,26 @@ func (s *SwitchWriter) Disable() {
9998}
10099
101100func (s * SwitchWriter ) Get () PCM16Writer {
102- ptr := s .ptr . Load ()
101+ ptr := s .WriteCloserSwitch . Get ()
103102 if ptr == nil {
104- return nil
103+ return nil // Untyped nil
105104 }
106- return * ptr
105+ return ptr
107106}
108107
109108// Swap sets an underlying writer and returns the old one.
110109// Caller is responsible for closing the old writer.
111110func (s * SwitchWriter ) Swap (w PCM16Writer ) PCM16Writer {
112- var old * PCM16Writer
113- if w == nil {
114- old = s .ptr .Swap (nil )
115- } else {
111+ if w != nil {
116112 if rate := s .SampleRate (); rate != w .SampleRate () {
117113 w = ResampleWriter (w , rate )
118114 }
119- old = s .ptr .Swap (& w )
120115 }
116+ old := s .WriteCloserSwitch .Swap (w )
121117 if old == nil {
122- return nil
118+ return nil // Untyped nil
123119 }
124- return * old
120+ return old
125121}
126122
127123func (s * SwitchWriter ) String () string {
@@ -135,14 +131,14 @@ func (s *SwitchWriter) SetSampleRate(rate int) {
135131 if rate <= 0 {
136132 panic ("invalid sample rate" )
137133 }
138- if ! s .sampleRate .CompareAndSwap (- 1 , int32 (rate )) {
134+ if ! s .WriteCloserSwitch . sampleRate .CompareAndSwap (- 1 , int32 (rate )) {
139135 panic ("sample rate can only be changed once" )
140136 }
141137}
142138
143139// SampleRate returns an expected sample rate for this writer. It panics if the sample rate is not specified.
144140func (s * SwitchWriter ) SampleRate () int {
145- rate := int ( s . sampleRate . Load () )
141+ rate := s . WriteCloserSwitch . SampleRate ( )
146142 if rate == 0 {
147143 panic ("switch writer not initialized" )
148144 } else if rate < 0 {
@@ -151,23 +147,94 @@ func (s *SwitchWriter) SampleRate() int {
151147 return rate
152148}
153149
154- func (s * SwitchWriter ) Close () error {
155- ptr := s .ptr .Swap (nil )
156- if ptr == nil {
150+ func (s * SwitchWriter ) WriteSample (sample PCM16Sample ) error {
151+ if s .disabled .Load () {
157152 return nil
158153 }
159- return ( * ptr ). Close ( )
154+ return s . WriteCloserSwitch . WriteSample ( sample )
160155}
161156
162- func (s * SwitchWriter ) WriteSample (sample PCM16Sample ) error {
163- if s .disabled .Load () {
157+ // NewWriteCloserSwitch creates a switch that expects writers with the given sample rate.
158+ // If a positive sample rate is provided, it is locked in at the start.
159+ // If a zero or negative sample rate is provided, the real rate will be taken
160+ // from the first downstream writer, and locked to that rate at that time.
161+ func NewWriteCloserSwitch [T any ](sampleRate int ) * WriteCloserSwitch [T ] {
162+ s := & WriteCloserSwitch [T ]{}
163+ if sampleRate > 0 {
164+ s .sampleRate .Store (int32 (sampleRate ))
165+ }
166+ return s
167+ }
168+
169+ // WriteCloserSwitch is a WriteCloser that forwards samples to an underlying writer,
170+ // which can be replaced atomically with Swap. Writes are dropped while no writer is attached.
171+ // All writers must agree on the sample rate.
172+ type WriteCloserSwitch [T any ] struct { // msdk.WriteCloser[T]
173+ sampleRate atomic.Int32 // Prevents changing sample rate after the switch is created
174+ w atomic.Pointer [WriteCloser [T ]]
175+ }
176+
177+ func (s * WriteCloserSwitch [T ]) String () string {
178+ w := s .w .Load ()
179+ if w == nil {
180+ return "WriteCloserSwitch(nil)"
181+ }
182+ return fmt .Sprintf ("WriteCloserSwitch(%d) -> %v" , s .SampleRate (), * w )
183+ }
184+
185+ // SampleRate returns the sample rate expected from the underlying writers,
186+ // or -1 if it is still unset.
187+ func (s * WriteCloserSwitch [T ]) SampleRate () int {
188+ if rate := s .sampleRate .Load (); rate > 0 {
189+ return int (rate )
190+ }
191+ return - 1
192+ }
193+
194+ func (s * WriteCloserSwitch [T ]) WriteSample (sample T ) error {
195+ w := s .w .Load ()
196+ if w == nil {
164197 return nil
165198 }
166- w := s .Get ()
199+ return (* w ).WriteSample (sample )
200+ }
201+
202+ func (s * WriteCloserSwitch [T ]) Close () error {
203+ w := s .w .Load ()
167204 if w == nil {
168205 return nil
169206 }
170- return w .WriteSample (sample )
207+ return (* w ).Close ()
208+ }
209+
210+ func (s * WriteCloserSwitch [T ]) Get () WriteCloser [T ] {
211+ ptr := s .w .Load ()
212+ if ptr == nil {
213+ return nil
214+ }
215+ return * ptr
216+ }
217+
218+ // Swap sets an underlying writer and returns the old one.
219+ // Caller is responsible for closing the old writer.
220+ // When switch sample rate is unset, it is set to the new writer's sample rate.
221+ // If sample rate is already set, this method panics on sample rate mismatch.
222+ func (s * WriteCloserSwitch [T ]) Swap (w WriteCloser [T ]) WriteCloser [T ] {
223+ var old * WriteCloser [T ]
224+ if w != nil {
225+ newRate := int32 (w .SampleRate ())
226+ oldRate := s .sampleRate .Swap (newRate )
227+ if oldRate > 0 && oldRate != newRate {
228+ panic (fmt .Sprintf ("sample rate mismatch: newRate %d, oldRate %d" , newRate , oldRate ))
229+ }
230+ old = s .w .Swap (& w )
231+ } else {
232+ old = s .w .Swap (nil )
233+ }
234+ if old == nil {
235+ return nil
236+ }
237+ return * old
171238}
172239
173240type MultiWriter [T any ] []WriteCloser [T ]
0 commit comments