mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-24 18:58:54 +01:00
audio: Simplify player's Read/Seek
This commit is contained in:
parent
3cac19d1b8
commit
5fd8fe839b
@ -337,8 +337,6 @@ type Player struct {
|
||||
players *players
|
||||
src ReadSeekCloser
|
||||
sampleRate int
|
||||
readingCh chan readingResult
|
||||
seekCh chan int64
|
||||
|
||||
buf []uint8
|
||||
pos int64
|
||||
@ -366,7 +364,6 @@ func NewPlayer(context *Context, src ReadSeekCloser) (*Player, error) {
|
||||
players: context.players,
|
||||
src: src,
|
||||
sampleRate: context.sampleRate,
|
||||
seekCh: make(chan int64, 1),
|
||||
buf: []uint8{},
|
||||
volume: 1,
|
||||
}
|
||||
@ -415,52 +412,21 @@ func (p *Player) Close() error {
|
||||
}
|
||||
|
||||
func (p *Player) readToBuffer(length int) (int, error) {
|
||||
if p.readingCh == nil {
|
||||
p.readingCh = make(chan readingResult)
|
||||
go func() {
|
||||
b := make([]uint8, length)
|
||||
p.srcM.Lock()
|
||||
n, err := p.src.Read(b)
|
||||
p.srcM.Unlock()
|
||||
if err != nil {
|
||||
p.readingCh <- readingResult{
|
||||
err: err,
|
||||
}
|
||||
return
|
||||
}
|
||||
p.readingCh <- readingResult{
|
||||
data: b[:n],
|
||||
}
|
||||
}()
|
||||
}
|
||||
select {
|
||||
case pos := <-p.seekCh:
|
||||
p.buf = []uint8{}
|
||||
p.pos = pos
|
||||
case r := <-p.readingCh:
|
||||
close(p.readingCh)
|
||||
p.readingCh = nil
|
||||
if r.err != nil {
|
||||
return 0, r.err
|
||||
}
|
||||
if len(r.data) > 0 {
|
||||
p.buf = append(p.buf, r.data...)
|
||||
}
|
||||
case <-timeoutIfPossible(10 * time.Millisecond):
|
||||
if l := length - len(p.buf); l > 0 {
|
||||
empty := make([]uint8, l)
|
||||
p.buf = append(p.buf, empty...)
|
||||
}
|
||||
b := make([]uint8, length)
|
||||
p.srcM.Lock()
|
||||
n, err := p.src.Read(b)
|
||||
p.srcM.Unlock()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
p.buf = append(p.buf, b[:n]...)
|
||||
b = b[:n]
|
||||
return len(p.buf), nil
|
||||
}
|
||||
|
||||
func (p *Player) bufferToInt16(lengthInBytes int) []int16 {
|
||||
r := make([]int16, lengthInBytes/2)
|
||||
// This function must be called on the same goruotine of readToBuffer.
|
||||
if p.readingCh != nil {
|
||||
return r
|
||||
}
|
||||
p.m.RLock()
|
||||
for i := 0; i < lengthInBytes/2; i++ {
|
||||
r[i] = int16(p.buf[2*i]) | (int16(p.buf[2*i+1]) << 8)
|
||||
@ -472,9 +438,6 @@ func (p *Player) bufferToInt16(lengthInBytes int) []int16 {
|
||||
|
||||
func (p *Player) proceed(length int) {
|
||||
// This function must be called on the same goruotine of readToBuffer.
|
||||
if p.readingCh != nil {
|
||||
return
|
||||
}
|
||||
p.buf = p.buf[length:]
|
||||
p.pos += int64(length)
|
||||
}
|
||||
@ -519,16 +482,8 @@ func (p *Player) Seek(offset time.Duration) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// When the player p is not playing, as readToBuffer is never called,
|
||||
// seekCh will never solved.
|
||||
// Solve the current seeking here if necessary.
|
||||
select {
|
||||
case pos := <-p.seekCh:
|
||||
p.buf = []uint8{}
|
||||
p.pos = pos
|
||||
default:
|
||||
}
|
||||
p.seekCh <- pos
|
||||
p.buf = []uint8{}
|
||||
p.pos = pos
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,8 @@ import (
|
||||
)
|
||||
|
||||
func (c *Context) bufferSize() int {
|
||||
// TODO: examples/audio doesn't work well with 1/30[s],
|
||||
// the other examples work though. Fix this.
|
||||
n := 20
|
||||
if web.IsMobileBrowser() {
|
||||
n = 10
|
||||
|
@ -1,27 +0,0 @@
|
||||
// Copyright 2017 The Ebiten Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +build js
|
||||
|
||||
package audio
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
func timeoutIfPossible(t time.Duration) <-chan time.Time {
|
||||
// time.After uses setTimeout and causes performance problems.
|
||||
// This function returns nil and blocks forever.
|
||||
return nil
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
// Copyright 2017 The Ebiten Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +build !js
|
||||
|
||||
package audio
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
func timeoutIfPossible(t time.Duration) <-chan time.Time {
|
||||
return time.After(t)
|
||||
}
|
Loading…
Reference in New Issue
Block a user