diff --git a/examples/play-from-disk-renegotation/main.go b/examples/play-from-disk-renegotation/main.go index 50b79ac..36ac584 100644 --- a/examples/play-from-disk-renegotation/main.go +++ b/examples/play-from-disk-renegotation/main.go @@ -167,15 +167,18 @@ func writeVideoToTrack(t *webrtc.TrackLocalStaticSample) { // Send our video file frame at a time. Pace our sending so we send it at the same speed it should be played back as. // This isn't required since the video is timestamped, but we will such much higher loss if we send all at once. - sleepTime := time.Millisecond * time.Duration((float32(header.TimebaseNumerator)/float32(header.TimebaseDenominator))*1000) - for { + // + // It is important to use a time.Ticker instead of time.Sleep because + // * avoids accumulating skew, just calling time.Sleep didn't compensate for the time spent parsing the data + // * works around latency issues with Sleep (see https://github.com/golang/go/issues/44343) + ticker := time.NewTicker(time.Millisecond * time.Duration((float32(header.TimebaseNumerator)/float32(header.TimebaseDenominator))*1000)) + for ; true; <-ticker.C { frame, _, err := ivf.ParseNextFrame() if err != nil { fmt.Printf("Finish writing video track: %s ", err) return } - time.Sleep(sleepTime) if err = t.WriteSample(media.Sample{Data: frame, Duration: time.Second}); err != nil { fmt.Printf("Finish writing video track: %s ", err) return diff --git a/examples/play-from-disk/README.md b/examples/play-from-disk/README.md index d033fad..dd9f971 100644 --- a/examples/play-from-disk/README.md +++ b/examples/play-from-disk/README.md @@ -1,6 +1,8 @@ # play-from-disk play-from-disk demonstrates how to send video and/or audio to your browser from files saved to disk. +For an example of playing H264 from disk see [play-from-disk-h264](https://github.com/pion/example-webrtc-applications/tree/master/play-from-disk-h264) + ## Instructions ### Create IVF named `output.ivf` that contains a VP8 track and/or `output.ogg` that contains a Opus track ``` diff --git a/examples/play-from-disk/main.go b/examples/play-from-disk/main.go index f6be66e..ad9ac0d 100644 --- a/examples/play-from-disk/main.go +++ b/examples/play-from-disk/main.go @@ -17,8 +17,9 @@ import ( ) const ( - audioFileName = "output.ogg" - videoFileName = "output.ivf" + audioFileName = "output.ogg" + videoFileName = "output.ivf" + oggPageDuration = time.Millisecond * 20 ) func main() { @@ -93,8 +94,12 @@ func main() { // Send our video file frame at a time. Pace our sending so we send it at the same speed it should be played back as. // This isn't required since the video is timestamped, but we will such much higher loss if we send all at once. - sleepTime := time.Millisecond * time.Duration((float32(header.TimebaseNumerator)/float32(header.TimebaseDenominator))*1000) - for { + // + // It is important to use a time.Ticker instead of time.Sleep because + // * avoids accumulating skew, just calling time.Sleep didn't compensate for the time spent parsing the data + // * works around latency issues with Sleep (see https://github.com/golang/go/issues/44343) + ticker := time.NewTicker(time.Millisecond * time.Duration((float32(header.TimebaseNumerator)/float32(header.TimebaseDenominator))*1000)) + for ; true; <-ticker.C { frame, _, ivfErr := ivf.ParseNextFrame() if ivfErr == io.EOF { fmt.Printf("All video frames parsed and sent") @@ -105,7 +110,6 @@ func main() { panic(ivfErr) } - time.Sleep(sleepTime) if ivfErr = videoTrack.WriteSample(media.Sample{Data: frame, Duration: time.Second}); ivfErr != nil { panic(ivfErr) } @@ -155,7 +159,12 @@ func main() { // Keep track of last granule, the difference is the amount of samples in the buffer var lastGranule uint64 - for { + + // It is important to use a time.Ticker instead of time.Sleep because + // * avoids accumulating skew, just calling time.Sleep didn't compensate for the time spent parsing the data + // * works around latency issues with Sleep (see https://github.com/golang/go/issues/44343) + ticker := time.NewTicker(oggPageDuration) + for ; true; <-ticker.C { pageData, pageHeader, oggErr := ogg.ParseNextPage() if oggErr == io.EOF { fmt.Printf("All audio pages parsed and sent") @@ -174,8 +183,6 @@ func main() { if oggErr = audioTrack.WriteSample(media.Sample{Data: pageData, Duration: sampleDuration}); oggErr != nil { panic(oggErr) } - - time.Sleep(sampleDuration) } }() }