audio: Refactoring

This commit is contained in:
Hajime Hoshi 2016-03-05 01:52:28 +09:00
parent 136c09cd33
commit 76386213bd
3 changed files with 31 additions and 37 deletions

View File

@ -91,7 +91,6 @@ func (s *mixedPlayersStream) Read(b []byte) (int, error) {
type Context struct {
sampleRate int
stream *mixedPlayersStream
innerPlayer *player
players map[*Player]struct{}
sync.Mutex
}
@ -103,12 +102,9 @@ func NewContext(sampleRate int) *Context {
players: map[*Player]struct{}{},
}
c.stream = &mixedPlayersStream{c}
var err error
c.innerPlayer, err = newPlayer(c.stream, c.sampleRate)
if err != nil {
if err := startPlaying(c.stream, c.sampleRate); err != nil {
panic(fmt.Sprintf("audio: NewContext error: %v", err))
}
c.innerPlayer.play()
return c
}

View File

@ -32,6 +32,8 @@ type player struct {
bufferSource *js.Object
}
var currentPlayer *player
func initialize() bool {
// Do nothing in node.js.
if js.Global.Get("require") != js.Undefined {
@ -49,20 +51,26 @@ func initialize() bool {
return true
}
func newPlayer(src io.Reader, sampleRate int) (*player, error) {
func startPlaying(src io.Reader, sampleRate int) error {
if currentPlayer != nil {
panic("audio: currentPlayer already exists")
}
if context == nil {
if !initialize() {
panic("audio couldn't be initialized")
panic("audio: audio couldn't be initialized")
}
}
p := &player{
currentPlayer = &player{
src: src,
sampleRate: sampleRate,
position: context.Get("currentTime").Float(),
bufferSource: nil,
}
return p, nil
if err := currentPlayer.start(); err != nil {
return err
}
return nil
}
func toLR(data []byte) ([]int16, []int16) {
@ -99,7 +107,7 @@ func (p *player) proceed() error {
return err
}
func (p *player) play() error {
func (p *player) start() error {
// TODO: What if play is already called?
go func() {
defer p.close()

View File

@ -20,7 +20,6 @@ import (
"fmt"
"io"
"runtime"
"sync"
"time"
"golang.org/x/mobile/exp/audio/al"
@ -40,34 +39,35 @@ type player struct {
isClosed bool
}
var m sync.Mutex
func newPlayer(src io.Reader, sampleRate int) (*player, error) {
m.Lock()
defer m.Unlock()
var currentPlayer *player
func startPlaying(src io.Reader, sampleRate int) error {
if currentPlayer != nil {
panic("audio: currentPlayer already exists")
}
if e := al.OpenDevice(); e != nil {
m.Unlock()
return nil, fmt.Errorf("audio: OpenAL initialization failed: %v", e)
return fmt.Errorf("audio: OpenAL initialization failed: %v", e)
}
s := al.GenSources(1)
if err := al.Error(); err != 0 {
panic(fmt.Sprintf("audio: al.GenSources error: %d", err))
}
p := &player{
currentPlayer = &player{
alSource: s[0],
alBuffers: []al.Buffer{},
source: src,
sampleRate: sampleRate,
}
runtime.SetFinalizer(p, (*player).close)
return p, nil
runtime.SetFinalizer(currentPlayer, (*player).close)
if err := currentPlayer.start(); err != nil {
return err
}
return nil
}
const bufferSize = 1024
func (p *player) proceed() error {
m.Lock()
if err := al.Error(); err != 0 {
panic(fmt.Sprintf("audio: before proceed: %d", err))
}
@ -80,13 +80,11 @@ func (p *player) proceed() error {
}
p.alBuffers = append(p.alBuffers, bufs...)
}
m.Unlock()
for 0 < len(p.alBuffers) {
b := make([]byte, bufferSize)
n, err := p.source.Read(b)
if 0 < n {
m.Lock()
buf := p.alBuffers[0]
p.alBuffers = p.alBuffers[1:]
buf.BufferData(al.FormatStereo16, b[:n], int32(p.sampleRate))
@ -94,14 +92,12 @@ func (p *player) proceed() error {
if err := al.Error(); err != 0 {
panic(fmt.Sprintf("audio: Queue in process: %d", err))
}
m.Unlock()
}
if err != nil {
return err
}
}
m.Lock()
if p.alSource.State() == al.Stopped {
al.RewindSources(p.alSource)
al.PlaySources(p.alSource)
@ -109,14 +105,11 @@ func (p *player) proceed() error {
panic(fmt.Sprintf("audio: PlaySource in process: %d", err))
}
}
m.Unlock()
return nil
}
func (p *player) play() error {
// TODO: What if play is already called?
m.Lock()
func (p *player) start() error {
n := maxBufferNum - int(p.alSource.BuffersQueued()) - len(p.alBuffers)
if 0 < n {
p.alBuffers = append(p.alBuffers, al.GenBuffers(n)...)
@ -135,7 +128,6 @@ func (p *player) play() error {
p.alBuffers = []al.Buffer{}
}
al.PlaySources(p.alSource)
m.Unlock()
go func() {
// TODO: Is it OK to close asap?
@ -155,10 +147,8 @@ func (p *player) play() error {
return nil
}
// TODO: When is this called? Can we remove this?
func (p *player) close() error {
m.Lock()
defer m.Unlock()
if err := al.Error(); err != 0 {
panic(fmt.Sprintf("audio: error before closing: %d", err))
}