diff --git a/audio/compositors.go b/audio/compositors.go index d965f0b..78151fb 100644 --- a/audio/compositors.go +++ b/audio/compositors.go @@ -6,6 +6,8 @@ import ( ) // Take returns a Streamer which streams s for at most d duration. +// +// TODO: should Take propagate an error? func Take(d time.Duration, s Streamer) Streamer { currSample := 0 numSamples := int(math.Ceil(d.Seconds() * SampleRate)) @@ -24,6 +26,8 @@ func Take(d time.Duration, s Streamer) Streamer { } // Seq takes zero or more Streamers and returns a Streamer which streams them one by one without pauses. +// +// Seq does not propagate errors from the Streamers. func Seq(s ...Streamer) Streamer { i := 0 return StreamerFunc(func(samples [][2]float64) (n int, ok bool) { @@ -40,6 +44,8 @@ func Seq(s ...Streamer) Streamer { } // Mix takes zero or more Streamers and returns a Streamer which streames them mixed together. +// +// Mix does not propagate errors from the Streamers. func Mix(s ...Streamer) Streamer { return StreamerFunc(func(samples [][2]float64) (n int, ok bool) { var tmp [512][2]float64 diff --git a/audio/ctrl.go b/audio/ctrl.go index bf056fd..fbbe77f 100644 --- a/audio/ctrl.go +++ b/audio/ctrl.go @@ -22,3 +22,10 @@ func (c *Ctrl) Stream(samples [][2]float64) (n int, ok bool) { c.Position += time.Duration(n) * time.Second / time.Duration(SampleRate) return n, ok } + +func (c *Ctrl) Err() error { + if c.Streamer == nil { + return nil + } + return c.Err() +} diff --git a/audio/interface.go b/audio/interface.go index d426beb..4b6d97b 100644 --- a/audio/interface.go +++ b/audio/interface.go @@ -28,13 +28,24 @@ type Streamer interface { // 2. 0 < n && n < len(samples) && ok // // Stream streamed n samples and drained the Streamer. Only case 3 may occur in the - // following calls. + // following calls. If Err return a non-nil error, only this case is valid. // // 3. n == 0 && !ok // // The Streamer is drained and no more samples will come. Only this case may occur in the // following calls. Stream(samples [][2]float64) (n int, ok bool) + + // Err returns an error which occured during streaming. If no error occured, nil is + // returned. + // + // When an error occurs, Streamer must become drained and Stream must return 0, false + // forever. + // + // The reason why Stream doesn't return an error is that it dramatically simplifies + // programming with Streamer. It's not very important to catch the error right when it + // happens. + Err() error } // StreamerFunc is a Streamer created by simply wrapping a streaming function (usually a closure, @@ -55,3 +66,8 @@ type StreamerFunc func(samples [][2]float64) (n int, ok bool) func (sf StreamerFunc) Stream(samples [][2]float64) (n int, ok bool) { return sf(samples) } + +// Err always returns nil. +func (sf StreamerFunc) Err() error { + return nil +} diff --git a/audio/mixer.go b/audio/mixer.go index d427cde..1de0fa5 100644 --- a/audio/mixer.go +++ b/audio/mixer.go @@ -54,3 +54,12 @@ func (m *Mixer) Stream(samples [][2]float64) (n int, ok bool) { return n, true } + +// Err always returns nil for Mixer. +// +// There are two reasons. The first one is that erroring Streamers are immediately drained and +// removed from the Mixer. The second one is that one Streamer shouldn't break the whole Mixer and +// you should handle the errors right where they can happen. +func (m *Mixer) Err() error { + return nil +}