package playlist import ( "fmt" "segmento/internal/segment" "time" ) const DefaultPlaylistDuration = 20 * time.Second type PlaylistListener interface { OnUpdate(p *Playlist) } type Playlist interface { // These could be moved to an interface? Duration() time.Duration TargetDuration() time.Duration AddSegment(s *segment.Segment) error Render() string //AddListener(l PlaylistListener) } type MediaPlaylist struct { Segments []*segment.Segment } func NewMediaPlaylist() *MediaPlaylist { return &MediaPlaylist{ Segments: make([]*segment.Segment, 0, 10), } } func (p *MediaPlaylist) Duration() time.Duration { return p.durationOf(p.Segments) } func (p *MediaPlaylist) TargetDuration() time.Duration { return DefaultPlaylistDuration } func (p *MediaPlaylist) AddSegment(s *segment.Segment) error { p.Segments = append(p.Segments, s) if len(p.Segments) == 1 { return nil } for { if p.durationOf(p.Segments[1:]) > p.TargetDuration() { p.Segments = p.Segments[1:] } break } return nil } func (p *MediaPlaylist) durationOf(ss []*segment.Segment) time.Duration { var t time.Duration for _, s := range ss { t += s.Duration() } return t } func (p *MediaPlaylist) Render() string { var r string r += "#EXTM3U\n" r += "#EXT-X-VERSION:3\n" r += "#EXT-X-TARGETDURATION:3\n" // TODO for _, s := range p.Segments { r += fmt.Sprintf("#EXTINF:%.05f\n", float32(s.Duration())/float32(time.Second)) r += "http://www.example.com/x.mp3\n" } r += "#EXT-X-ENDLIST" return r } func (p *MediaPlaylist) Run() error { for { // TODO block here and listen to the channel of incoming segments. // As the reader is Read and segments are produced, update the Playlist // struct and possibly notify consumers. // What would actually be a useful API and/or Go best practices? } }