func (p *Player) prepare(offset int64, force bool) error { p.mu.Lock() if !force && p.prep { p.mu.Unlock() return nil } p.mu.Unlock() if p.t.hasHeader { offset += headerSize } if _, err := p.t.src.Seek(offset, 0); err != nil { return err } var bufs []al.Buffer // TODO(jbd): Limit the number of buffers in use, unqueue and reuse // the existing buffers as buffers are processed. buf := make([]byte, 128*1024) size := offset for { n, err := p.t.src.Read(buf) if n > 0 { size += int64(n) b := al.GenBuffers(1) b[0].BufferData(formatCodes[p.t.format], buf[:n], int32(p.t.samplesPerSecond)) bufs = append(bufs, b[0]) } if err == io.EOF { break } if err != nil { return err } } p.mu.Lock() if len(p.bufs) > 0 { p.source.UnqueueBuffers(p.bufs) al.DeleteBuffers(p.bufs) } p.sizeBytes = size p.bufs = bufs p.prep = true if len(bufs) > 0 { p.source.QueueBuffers(bufs) } p.mu.Unlock() return nil }
// Close closes the device and frees the underlying resources // used by the player. // It should be called as soon as the player is not in-use anymore. func (p *Player) Close() error { if p == nil { return nil } if p.source != 0 { al.DeleteSources(p.source) } p.mu.Lock() if len(p.bufs) > 0 { al.DeleteBuffers(p.bufs) } p.mu.Unlock() p.t.src.Close() return nil }