@@ -154,6 +154,10 @@ func (s *SwitchWriter) WriteSample(sample PCM16Sample) error {
154154 return s .WriteCloserSwitch .WriteSample (sample )
155155}
156156
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.
157161func NewWriteCloserSwitch [T any ](sampleRate int ) * WriteCloserSwitch [T ] {
158162 s := & WriteCloserSwitch [T ]{}
159163 if sampleRate > 0 {
@@ -162,6 +166,9 @@ func NewWriteCloserSwitch[T any](sampleRate int) *WriteCloserSwitch[T] {
162166 return s
163167}
164168
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.
165172type WriteCloserSwitch [T any ] struct { // msdk.WriteCloser[T]
166173 sampleRate atomic.Int32 // Prevents changing sample rate after the switch is created
167174 w atomic.Pointer [WriteCloser [T ]]
@@ -170,11 +177,13 @@ type WriteCloserSwitch[T any] struct { // msdk.WriteCloser[T]
170177func (s * WriteCloserSwitch [T ]) String () string {
171178 w := s .w .Load ()
172179 if w == nil {
173- return "Switch (nil)"
180+ return "WriteCloserSwitch (nil)"
174181 }
175- return fmt .Sprintf ("Switch (%d) -> %v" , s .SampleRate (), * w )
182+ return fmt .Sprintf ("WriteCloserSwitch (%d) -> %v" , s .SampleRate (), * w )
176183}
177184
185+ // SampleRate returns the sample rate expected from the underlying writers,
186+ // or -1 if it is still unset.
178187func (s * WriteCloserSwitch [T ]) SampleRate () int {
179188 if rate := s .sampleRate .Load (); rate > 0 {
180189 return int (rate )
@@ -206,13 +215,18 @@ func (s *WriteCloserSwitch[T]) Get() WriteCloser[T] {
206215 return * ptr
207216}
208217
218+ // Swap sets an underlying writer and returns the old one.
219+ // Caller is responsible for closing the old writer.
220+ // If switch sample rate is unset, this locks the sample rate.
221+ // If sample rate is already locked, and the new writer does not
222+ // match it the code panics.
209223func (s * WriteCloserSwitch [T ]) Swap (w WriteCloser [T ]) WriteCloser [T ] {
210224 var old * WriteCloser [T ]
211225 if w != nil {
212226 newRate := int32 (w .SampleRate ())
213227 oldRate := s .sampleRate .Swap (newRate )
214228 if oldRate > 0 && oldRate != newRate {
215- panic (fmt .Sprintf ("sample rate mismatch: expected %d, actual %d" , newRate , oldRate ))
229+ panic (fmt .Sprintf ("sample rate mismatch: newRate %d, oldRate %d" , newRate , oldRate ))
216230 }
217231 old = s .w .Swap (& w )
218232 } else {
0 commit comments