| Index: third_party/go/src/golang.org/x/mobile/audio/audio.go
|
| diff --git a/third_party/go/src/golang.org/x/mobile/audio/audio.go b/third_party/go/src/golang.org/x/mobile/audio/audio.go
|
| deleted file mode 100644
|
| index 904968cab5f319e5029317d6f5823bab3306852a..0000000000000000000000000000000000000000
|
| --- a/third_party/go/src/golang.org/x/mobile/audio/audio.go
|
| +++ /dev/null
|
| @@ -1,295 +0,0 @@
|
| -// Copyright 2015 The Go Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style
|
| -// license that can be found in the LICENSE file.
|
| -
|
| -// +build darwin
|
| -
|
| -// Package audio provides a basic audio player.
|
| -package audio
|
| -
|
| -import (
|
| - "fmt"
|
| - "io"
|
| - "sync"
|
| - "time"
|
| -
|
| - "golang.org/x/mobile/audio/al"
|
| - "golang.org/x/mobile/audio/alc"
|
| -)
|
| -
|
| -// Format represents an audio file format.
|
| -type Format string
|
| -
|
| -const (
|
| - Mono8 = Format("mono8")
|
| - Mono16 = Format("mono16")
|
| - Stereo8 = Format("stereo8")
|
| - Stereo16 = Format("stereo16")
|
| -)
|
| -
|
| -var formatToCode = map[Format]int32{
|
| - Mono8: 0x1100,
|
| - Mono16: 0x1101,
|
| - Stereo8: 0x1102,
|
| - Stereo16: 0x1103,
|
| -}
|
| -
|
| -// State indicates the current playing state of the player.
|
| -type State string
|
| -
|
| -const (
|
| - Unknown = State("unknown")
|
| - Initial = State("initial")
|
| - Playing = State("playing")
|
| - Paused = State("paused")
|
| - Stopped = State("stopped")
|
| -)
|
| -
|
| -var codeToState = map[int32]State{
|
| - 0: Unknown,
|
| - 0x1011: Initial,
|
| - 0x1012: Playing,
|
| - 0x1013: Paused,
|
| - 0x1014: Stopped,
|
| -}
|
| -
|
| -var device struct {
|
| - sync.Mutex
|
| - d *alc.Device
|
| -}
|
| -
|
| -type track struct {
|
| - format Format
|
| - rate int64 // sample rate
|
| - src io.ReadSeeker
|
| -}
|
| -
|
| -// Player is a basic audio player that plays PCM data.
|
| -// Operations on a nil *Player are no-op, a nil *Player can
|
| -// be used for testing purposes.
|
| -type Player struct {
|
| - t *track
|
| - source al.Source
|
| -
|
| - muPrep sync.Mutex // guards prep and bufs
|
| - prep bool
|
| - bufs []al.Buffer
|
| - size int64 // size of the audio source
|
| -}
|
| -
|
| -// NewPlayer returns a new Player.
|
| -// It initializes the underlying audio devices and the related resources.
|
| -func NewPlayer(src io.ReadSeeker, format Format, sampleRate int64) (*Player, error) {
|
| - device.Lock()
|
| - defer device.Unlock()
|
| -
|
| - if device.d == nil {
|
| - device.d = alc.Open("")
|
| - c := device.d.CreateContext(nil)
|
| - if !alc.MakeContextCurrent(c) {
|
| - return nil, fmt.Errorf("player: cannot initiate a new player")
|
| - }
|
| - }
|
| - s := al.GenSources(1)
|
| - if code := al.Error(); code != 0 {
|
| - return nil, fmt.Errorf("player: cannot generate an audio source [err=%x]", code)
|
| - }
|
| - bufs := al.GenBuffers(2)
|
| - if err := lastErr(); err != nil {
|
| - return nil, err
|
| - }
|
| - return &Player{
|
| - t: &track{format: format, src: src, rate: sampleRate},
|
| - source: s[0],
|
| - bufs: bufs,
|
| - }, nil
|
| -}
|
| -
|
| -func (p *Player) prepare(offset int64, force bool) error {
|
| - p.muPrep.Lock()
|
| - defer p.muPrep.Unlock()
|
| - if !force && p.prep {
|
| - return nil
|
| - }
|
| - if len(p.bufs) > 0 {
|
| - p.source.UnqueueBuffers(p.bufs)
|
| - al.DeleteBuffers(p.bufs)
|
| - }
|
| - if _, err := p.t.src.Seek(offset, 0); err != nil {
|
| - return err
|
| - }
|
| - p.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(uint32(formatToCode[p.t.format]), buf[:n], int32(p.t.rate))
|
| - p.bufs = append(p.bufs, b[0])
|
| - }
|
| - if err == io.EOF {
|
| - break
|
| - }
|
| - if err != nil {
|
| - return err
|
| - }
|
| - }
|
| - p.size = size
|
| - if len(p.bufs) > 0 {
|
| - p.source.QueueBuffers(p.bufs)
|
| - }
|
| - p.prep = true
|
| - return nil
|
| -}
|
| -
|
| -// Play buffers the source audio to the audio device and starts
|
| -// to play the source.
|
| -// If the player paused or stopped, it reuses the previously buffered
|
| -// resources to keep playing from the time it has paused or stopped.
|
| -func (p *Player) Play() error {
|
| - if p == nil {
|
| - return nil
|
| - }
|
| - // Prepares if the track hasn't been buffered before.
|
| - if err := p.prepare(0, false); err != nil {
|
| - return err
|
| - }
|
| - al.PlaySources(p.source)
|
| - return lastErr()
|
| -}
|
| -
|
| -// Pause pauses the player.
|
| -func (p *Player) Pause() error {
|
| - if p == nil {
|
| - return nil
|
| - }
|
| - al.PauseSources(p.source)
|
| - return lastErr()
|
| -}
|
| -
|
| -// Stop stops the player.
|
| -func (p *Player) Stop() error {
|
| - if p == nil {
|
| - return nil
|
| - }
|
| - al.StopSources(p.source)
|
| - return lastErr()
|
| -}
|
| -
|
| -// Seek moves the play head to the given offset relative to the start of the source.
|
| -func (p *Player) Seek(offset time.Duration) error {
|
| - if p == nil {
|
| - return nil
|
| - }
|
| - if err := p.Stop(); err != nil {
|
| - return err
|
| - }
|
| - size := durToByteOffset(p.t, offset)
|
| - if err := p.prepare(size, true); err != nil {
|
| - return err
|
| - }
|
| - al.PlaySources(p.source)
|
| - return lastErr()
|
| -}
|
| -
|
| -// Current returns the current playback position of the audio that is being played.
|
| -func (p *Player) Current() time.Duration {
|
| - if p == nil {
|
| - return time.Duration(0)
|
| - }
|
| - // TODO(jbd): Current never returns the Total when the playing is finished.
|
| - // OpenAL may be returning the last buffer's start point as an OffsetByte.
|
| - return byteOffsetToDur(p.t, int64(p.source.OffsetByte()))
|
| -}
|
| -
|
| -// Total returns the total duration of the audio source.
|
| -func (p *Player) Total() time.Duration {
|
| - if p == nil {
|
| - return 0
|
| - }
|
| - // Prepare is required to determine the length of the source.
|
| - // We need to read the entire source to calculate the length.
|
| - p.prepare(0, false)
|
| - return byteOffsetToDur(p.t, p.size)
|
| -}
|
| -
|
| -// Volume returns the current player volume. The range of the volume is [0, 1].
|
| -func (p *Player) Volume() float64 {
|
| - if p == nil {
|
| - return 0
|
| - }
|
| - return float64(p.source.Gain())
|
| -}
|
| -
|
| -// SetVolume sets the volume of the player. The range of the volume is [0, 1].
|
| -func (p *Player) SetVolume(vol float64) {
|
| - if p == nil {
|
| - return
|
| - }
|
| - p.source.SetGain(float32(vol))
|
| -}
|
| -
|
| -// State returns the player's current state.
|
| -func (p *Player) State() State {
|
| - if p == nil {
|
| - return Unknown
|
| - }
|
| - return codeToState[p.source.State()]
|
| -}
|
| -
|
| -// Destroy 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) Destroy() {
|
| - if p == nil {
|
| - return
|
| - }
|
| - if p.source != 0 {
|
| - al.DeleteSources(p.source)
|
| - }
|
| - p.muPrep.Lock()
|
| - if len(p.bufs) > 0 {
|
| - al.DeleteBuffers(p.bufs)
|
| - }
|
| - p.muPrep.Unlock()
|
| -}
|
| -
|
| -func byteOffsetToDur(t *track, offset int64) time.Duration {
|
| - size := float64(offset)
|
| - if t.format == Mono16 || t.format == Stereo16 {
|
| - size /= 2
|
| - }
|
| - if t.format == Stereo8 || t.format == Stereo16 {
|
| - size /= 2
|
| - }
|
| - size /= float64(t.rate)
|
| - // Casting size back to int64. Work in milliseconds,
|
| - // so that size doesn't get rounded excessively.
|
| - return time.Duration(size*1000) * time.Duration(time.Millisecond)
|
| -}
|
| -
|
| -func durToByteOffset(t *track, dur time.Duration) int64 {
|
| - size := int64(dur/time.Second) * t.rate
|
| - // Each sample is represented by 16-bits. Move twice further.
|
| - if t.format == Mono16 || t.format == Stereo16 {
|
| - size *= 2
|
| - }
|
| - if t.format == Stereo8 || t.format == Stereo16 {
|
| - size *= 2
|
| - }
|
| - return size
|
| -}
|
| -
|
| -// lastErr returns the last error or nil if the last operation
|
| -// has been succesful.
|
| -func lastErr() error {
|
| - if code := al.Error(); code != 0 {
|
| - return fmt.Errorf("audio: openal failed with %x", code)
|
| - }
|
| - return nil
|
| -}
|
| -
|
| -// TODO(jbd): Destroy context, close the device.
|
|
|