mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-26 11:48:55 +01:00
parent
048a30b4e7
commit
a74c00074e
@ -49,9 +49,7 @@ type context struct {
|
|||||||
context *C.pa_context
|
context *C.pa_context
|
||||||
stream *C.pa_stream
|
stream *C.pa_stream
|
||||||
|
|
||||||
players map[*playerImpl]struct{}
|
players *players
|
||||||
buf []float32
|
|
||||||
cond *sync.Cond
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var theContext *context
|
var theContext *context
|
||||||
@ -66,7 +64,9 @@ func NewContext(sampleRate, channelNum, bitDepthInBytes int) (Context, chan stru
|
|||||||
sampleRate: sampleRate,
|
sampleRate: sampleRate,
|
||||||
channelNum: channelNum,
|
channelNum: channelNum,
|
||||||
bitDepthInBytes: bitDepthInBytes,
|
bitDepthInBytes: bitDepthInBytes,
|
||||||
|
players: &players{
|
||||||
cond: sync.NewCond(&sync.Mutex{}),
|
cond: sync.NewCond(&sync.Mutex{}),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
theContext = c
|
theContext = c
|
||||||
|
|
||||||
@ -160,13 +160,19 @@ func NewContext(sampleRate, channelNum, bitDepthInBytes int) (Context, chan stru
|
|||||||
|
|
||||||
C.pa_stream_cork(c.stream, 0, C.pa_stream_success_cb_t(C.ebiten_readerdriver_streamSuccessCallback), unsafe.Pointer(c.mainloop))
|
C.pa_stream_cork(c.stream, 0, C.pa_stream_success_cb_t(C.ebiten_readerdriver_streamSuccessCallback), unsafe.Pointer(c.mainloop))
|
||||||
|
|
||||||
go c.loop()
|
go c.players.loop()
|
||||||
|
|
||||||
return c, ready, nil
|
return c, ready, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *context) shouldWait() bool {
|
type players struct {
|
||||||
for p := range c.players {
|
players map[*playerImpl]struct{}
|
||||||
|
buf []float32
|
||||||
|
cond *sync.Cond
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ps *players) shouldWait() bool {
|
||||||
|
for p := range ps.players {
|
||||||
if !p.isBufferFull() {
|
if !p.isBufferFull() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -174,26 +180,26 @@ func (c *context) shouldWait() bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *context) wait() {
|
func (ps *players) wait() {
|
||||||
c.cond.L.Lock()
|
ps.cond.L.Lock()
|
||||||
defer c.cond.L.Unlock()
|
defer ps.cond.L.Unlock()
|
||||||
|
|
||||||
for c.shouldWait() {
|
for ps.shouldWait() {
|
||||||
c.cond.Wait()
|
ps.cond.Wait()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *context) loop() {
|
func (ps *players) loop() {
|
||||||
var players []*playerImpl
|
var players []*playerImpl
|
||||||
for {
|
for {
|
||||||
c.wait()
|
ps.wait()
|
||||||
|
|
||||||
c.cond.L.Lock()
|
ps.cond.L.Lock()
|
||||||
players = players[:0]
|
players = players[:0]
|
||||||
for p := range c.players {
|
for p := range ps.players {
|
||||||
players = append(players, p)
|
players = append(players, p)
|
||||||
}
|
}
|
||||||
c.cond.L.Unlock()
|
ps.cond.L.Unlock()
|
||||||
|
|
||||||
for _, p := range players {
|
for _, p := range players {
|
||||||
p.readSourceToBuffer()
|
p.readSourceToBuffer()
|
||||||
@ -211,22 +217,37 @@ func (c *context) Resume() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *context) addPlayer(player *playerImpl) {
|
func (ps *players) addPlayer(player *playerImpl) {
|
||||||
c.cond.L.Lock()
|
ps.cond.L.Lock()
|
||||||
defer c.cond.L.Unlock()
|
defer ps.cond.L.Unlock()
|
||||||
|
|
||||||
if c.players == nil {
|
if ps.players == nil {
|
||||||
c.players = map[*playerImpl]struct{}{}
|
ps.players = map[*playerImpl]struct{}{}
|
||||||
}
|
}
|
||||||
c.players[player] = struct{}{}
|
ps.players[player] = struct{}{}
|
||||||
c.cond.Signal()
|
ps.cond.Signal()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *context) removePlayer(player *playerImpl) {
|
func (ps *players) removePlayer(player *playerImpl) {
|
||||||
c.cond.L.Lock()
|
ps.cond.L.Lock()
|
||||||
defer c.cond.L.Unlock()
|
defer ps.cond.L.Unlock()
|
||||||
delete(c.players, player)
|
|
||||||
c.cond.Signal()
|
delete(ps.players, player)
|
||||||
|
ps.cond.Signal()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ps *players) read(buf []float32) {
|
||||||
|
ps.cond.L.Lock()
|
||||||
|
players := make([]*playerImpl, 0, len(ps.players))
|
||||||
|
for p := range ps.players {
|
||||||
|
players = append(players, p)
|
||||||
|
}
|
||||||
|
ps.cond.L.Unlock()
|
||||||
|
|
||||||
|
for _, p := range players {
|
||||||
|
p.readBufferAndAdd(buf)
|
||||||
|
}
|
||||||
|
ps.cond.Signal()
|
||||||
}
|
}
|
||||||
|
|
||||||
//export ebiten_readerdriver_contextStateCallback
|
//export ebiten_readerdriver_contextStateCallback
|
||||||
@ -250,15 +271,7 @@ func ebiten_readerdriver_streamWriteCallback(stream *C.pa_stream, requestedBytes
|
|||||||
var buf unsafe.Pointer
|
var buf unsafe.Pointer
|
||||||
var buf32 []float32
|
var buf32 []float32
|
||||||
var bytesToFill C.size_t = bufferSize
|
var bytesToFill C.size_t = bufferSize
|
||||||
var players []*playerImpl
|
|
||||||
for n := int(requestedBytes); n > 0; n -= int(bytesToFill) {
|
for n := int(requestedBytes); n > 0; n -= int(bytesToFill) {
|
||||||
c.cond.L.Lock()
|
|
||||||
players = players[:0]
|
|
||||||
for p := range c.players {
|
|
||||||
players = append(players, p)
|
|
||||||
}
|
|
||||||
c.cond.L.Unlock()
|
|
||||||
|
|
||||||
C.pa_stream_begin_write(stream, &buf, &bytesToFill)
|
C.pa_stream_begin_write(stream, &buf, &bytesToFill)
|
||||||
if len(buf32) < int(bytesToFill)/4 {
|
if len(buf32) < int(bytesToFill)/4 {
|
||||||
buf32 = make([]float32, bytesToFill/4)
|
buf32 = make([]float32, bytesToFill/4)
|
||||||
@ -267,10 +280,9 @@ func ebiten_readerdriver_streamWriteCallback(stream *C.pa_stream, requestedBytes
|
|||||||
buf32[i] = 0
|
buf32[i] = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, p := range players {
|
|
||||||
p.readBufferAndAdd(buf32[:bytesToFill/4])
|
c.players.read(buf32[:bytesToFill/4])
|
||||||
}
|
|
||||||
c.cond.Signal()
|
|
||||||
for i := uintptr(0); i < uintptr(bytesToFill/4); i++ {
|
for i := uintptr(0); i < uintptr(bytesToFill/4); i++ {
|
||||||
*(*float32)(unsafe.Pointer(uintptr(buf) + 4*i)) = buf32[i]
|
*(*float32)(unsafe.Pointer(uintptr(buf) + 4*i)) = buf32[i]
|
||||||
}
|
}
|
||||||
@ -285,6 +297,7 @@ type player struct {
|
|||||||
|
|
||||||
type playerImpl struct {
|
type playerImpl struct {
|
||||||
context *context
|
context *context
|
||||||
|
players *players
|
||||||
src io.Reader
|
src io.Reader
|
||||||
volume float64
|
volume float64
|
||||||
err error
|
err error
|
||||||
@ -295,9 +308,14 @@ type playerImpl struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *context) NewPlayer(src io.Reader) Player {
|
func (c *context) NewPlayer(src io.Reader) Player {
|
||||||
|
return newPlayer(c, c.players, src)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newPlayer(context *context, players *players, src io.Reader) *player {
|
||||||
p := &player{
|
p := &player{
|
||||||
p: &playerImpl{
|
p: &playerImpl{
|
||||||
context: c,
|
context: context,
|
||||||
|
players: players,
|
||||||
src: src,
|
src: src,
|
||||||
volume: 1,
|
volume: 1,
|
||||||
},
|
},
|
||||||
@ -351,7 +369,7 @@ func (p *playerImpl) playImpl() {
|
|||||||
p.state = playerPlay
|
p.state = playerPlay
|
||||||
|
|
||||||
p.m.Unlock()
|
p.m.Unlock()
|
||||||
p.context.addPlayer(p)
|
p.players.addPlayer(p)
|
||||||
p.m.Lock()
|
p.m.Lock()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -443,7 +461,7 @@ func (p *playerImpl) Close() error {
|
|||||||
|
|
||||||
func (p *playerImpl) closeImpl() error {
|
func (p *playerImpl) closeImpl() error {
|
||||||
p.m.Unlock()
|
p.m.Unlock()
|
||||||
p.context.removePlayer(p)
|
p.players.removePlayer(p)
|
||||||
p.m.Lock()
|
p.m.Lock()
|
||||||
|
|
||||||
if p.state == playerClosed {
|
if p.state == playerClosed {
|
||||||
|
@ -322,11 +322,6 @@ func (p *playerImpl) playImpl() {
|
|||||||
// Switching goroutines is very inefficient on Windows. Avoid a dedicated goroutine for a player.
|
// Switching goroutines is very inefficient on Windows. Avoid a dedicated goroutine for a player.
|
||||||
}
|
}
|
||||||
|
|
||||||
func volumeForWinAPI(v float64) uint32 {
|
|
||||||
u32 := uint32(0xffff * v)
|
|
||||||
return (u32 << 16) | u32
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *playerImpl) queuedHeadersNum() int {
|
func (p *playerImpl) queuedHeadersNum() int {
|
||||||
var c int
|
var c int
|
||||||
for _, h := range p.headers {
|
for _, h := range p.headers {
|
||||||
|
Loading…
Reference in New Issue
Block a user