diff --git a/internal/codec/measurement.go b/internal/codec/measurement.go index c14e45b..3010aa7 100644 --- a/internal/codec/measurement.go +++ b/internal/codec/measurement.go @@ -11,12 +11,15 @@ import ( func MeasureBitRate(r io.Reader, dur time.Duration) (float64, error) { var n, totalBytes int var err error + buf := make([]byte, 1024) start := time.Now() now := start end := now.Add(dur) - for now.Before(end) { + for { n, err = r.Read(buf) + now = time.Now() + if err != nil { if e, ok := err.(*mio.InsufficientBufferError); ok { buf = make([]byte, 2*e.RequiredSize) @@ -24,6 +27,7 @@ func MeasureBitRate(r io.Reader, dur time.Duration) (float64, error) { } if err == io.EOF { + dur = now.Sub(start) totalBytes += n break } @@ -31,11 +35,12 @@ func MeasureBitRate(r io.Reader, dur time.Duration) (float64, error) { return 0, err } - totalBytes += n - now = time.Now() + if now.After(end) { + break + } + totalBytes += n // count bytes if the data arrived within the period } - elapsed := time.Now().Sub(start).Seconds() - avg := float64(totalBytes*8) / elapsed + avg := float64(totalBytes*8) / dur.Seconds() return avg, nil } diff --git a/internal/codec/measurement_test.go b/internal/codec/measurement_test.go index 0b2d711..8796089 100644 --- a/internal/codec/measurement_test.go +++ b/internal/codec/measurement_test.go @@ -9,18 +9,25 @@ import ( func TestMeasureBitRateStatic(t *testing.T) { r, w := io.Pipe() - dur := time.Second * 5 - dataSize := 1000 - var precision float64 = 8 // 1 byte + const ( + dataSize = 1000 + dur = 5 * time.Second + packetInterval = time.Second + precision = 8.0 // 1 byte + ) var wg sync.WaitGroup wg.Add(1) done := make(chan struct{}) go func() { data := make([]byte, dataSize) + ticker := time.NewTicker(packetInterval) + + // Wait half interval + time.Sleep(packetInterval / 2) + // Make sure that this goroutine is synchronized with main goroutine wg.Done() - ticker := time.NewTicker(time.Second) for { select { @@ -48,30 +55,34 @@ func TestMeasureBitRateStatic(t *testing.T) { func TestMeasureBitRateDynamic(t *testing.T) { r, w := io.Pipe() - dur := time.Second * 5 - dataSize := 1000 - var precision float64 = 8 // 1 byte + const ( + dataSize = 1000 + dur = 5 * time.Second + packetInterval = time.Millisecond * 250 + precision = 8.0 // 1 byte + ) var wg sync.WaitGroup wg.Add(1) done := make(chan struct{}) go func() { data := make([]byte, dataSize) - wg.Done() - ticker := time.NewTicker(time.Millisecond * 500) - var count int + ticker := time.NewTicker(packetInterval) + // Wait half interval + time.Sleep(packetInterval / 2) + + wg.Done() + + var count int for { select { case <-ticker.C: - w.Write(data) - count++ - // Wait until 4 slow ticks, which is also equal to 2 seconds - if count == 4 { - ticker.Stop() - // Speed up the tick by 2 times for the rest - ticker = time.NewTicker(time.Millisecond * 250) + // 4 x 500ms ticks and 250ms ticks + if count%2 == 1 || count >= 8 { + w.Write(data) } + count++ case <-done: w.Close() return