mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-25 11:18:54 +01:00
internal/hooks: Enable to return error at suspend/resume audio
This commit is contained in:
parent
bcf8ef85b6
commit
58843b68f9
@ -125,17 +125,19 @@ func NewContext(sampleRate int) *Context {
|
|||||||
theContext = c
|
theContext = c
|
||||||
|
|
||||||
h := getHook()
|
h := getHook()
|
||||||
h.OnSuspendAudio(func() {
|
h.OnSuspendAudio(func() error {
|
||||||
c.semaphore <- struct{}{}
|
c.semaphore <- struct{}{}
|
||||||
if s, ok := np.(interface{ suspend() }); ok {
|
if s, ok := np.(interface{ suspend() }); ok {
|
||||||
s.suspend()
|
s.suspend()
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
})
|
})
|
||||||
h.OnResumeAudio(func() {
|
h.OnResumeAudio(func() error {
|
||||||
<-c.semaphore
|
<-c.semaphore
|
||||||
if s, ok := np.(interface{ resume() }); ok {
|
if s, ok := np.(interface{ resume() }); ok {
|
||||||
s.resume()
|
s.resume()
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
h.AppendHookOnBeforeUpdate(func() error {
|
h.AppendHookOnBeforeUpdate(func() error {
|
||||||
@ -423,8 +425,8 @@ func (p *Player) SetVolume(volume float64) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type hook interface {
|
type hook interface {
|
||||||
OnSuspendAudio(f func())
|
OnSuspendAudio(f func() error)
|
||||||
OnResumeAudio(f func())
|
OnResumeAudio(f func() error)
|
||||||
AppendHookOnBeforeUpdate(f func() error)
|
AppendHookOnBeforeUpdate(f func() error)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -439,11 +441,11 @@ func getHook() hook {
|
|||||||
|
|
||||||
type hookImpl struct{}
|
type hookImpl struct{}
|
||||||
|
|
||||||
func (h *hookImpl) OnSuspendAudio(f func()) {
|
func (h *hookImpl) OnSuspendAudio(f func() error) {
|
||||||
hooks.OnSuspendAudio(f)
|
hooks.OnSuspendAudio(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *hookImpl) OnResumeAudio(f func()) {
|
func (h *hookImpl) OnResumeAudio(f func() error) {
|
||||||
hooks.OnResumeAudio(f)
|
hooks.OnResumeAudio(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,10 +141,10 @@ type dummyHook struct {
|
|||||||
updates []func() error
|
updates []func() error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *dummyHook) OnSuspendAudio(f func()) {
|
func (h *dummyHook) OnSuspendAudio(f func() error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *dummyHook) OnResumeAudio(f func()) {
|
func (h *dummyHook) OnResumeAudio(f func() error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *dummyHook) AppendHookOnBeforeUpdate(f func() error) {
|
func (h *dummyHook) AppendHookOnBeforeUpdate(f func() error) {
|
||||||
|
@ -313,7 +313,11 @@ const objcM = `// Code generated by ebitenmobile. DO NOT EDIT.
|
|||||||
|
|
||||||
@synchronized(self) {
|
@synchronized(self) {
|
||||||
active_ = false;
|
active_ = false;
|
||||||
EbitenmobileviewSuspend();
|
NSError* err = nil;
|
||||||
|
EbitenmobileviewSuspend(&err);
|
||||||
|
if (err != nil) {
|
||||||
|
[self onErrorOnGameUpdate:err];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -322,7 +326,11 @@ const objcM = `// Code generated by ebitenmobile. DO NOT EDIT.
|
|||||||
|
|
||||||
@synchronized(self) {
|
@synchronized(self) {
|
||||||
active_ = true;
|
active_ = true;
|
||||||
EbitenmobileviewResume();
|
NSError* err = nil;
|
||||||
|
EbitenmobileviewResume(&err);
|
||||||
|
if (err != nil) {
|
||||||
|
[self onErrorOnGameUpdate:err];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -689,7 +697,11 @@ public class EbitenView extends ViewGroup implements InputManager.InputDeviceLis
|
|||||||
public void suspendGame() {
|
public void suspendGame() {
|
||||||
this.inputManager.unregisterInputDeviceListener(this);
|
this.inputManager.unregisterInputDeviceListener(this);
|
||||||
this.ebitenSurfaceView.onPause();
|
this.ebitenSurfaceView.onPause();
|
||||||
|
try {
|
||||||
Ebitenmobileview.suspend();
|
Ebitenmobileview.suspend();
|
||||||
|
} catch (final Exception e) {
|
||||||
|
onErrorOnGameUpdate(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// resumeGame resumes the game.
|
// resumeGame resumes the game.
|
||||||
@ -698,7 +710,11 @@ public class EbitenView extends ViewGroup implements InputManager.InputDeviceLis
|
|||||||
public void resumeGame() {
|
public void resumeGame() {
|
||||||
this.inputManager.registerInputDeviceListener(this, null);
|
this.inputManager.registerInputDeviceListener(this, null);
|
||||||
this.ebitenSurfaceView.onResume();
|
this.ebitenSurfaceView.onResume();
|
||||||
|
try {
|
||||||
Ebitenmobileview.resume();
|
Ebitenmobileview.resume();
|
||||||
|
} catch (final Exception e) {
|
||||||
|
onErrorOnGameUpdate(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// onErrorOnGameUpdate is called on the main thread when an error happens when updating a game.
|
// onErrorOnGameUpdate is called on the main thread when an error happens when updating a game.
|
||||||
|
File diff suppressed because one or more lines are too long
@ -44,42 +44,44 @@ func RunBeforeUpdateHooks() error {
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
audioSuspended bool
|
audioSuspended bool
|
||||||
onSuspendAudio func()
|
onSuspendAudio func() error
|
||||||
onResumeAudio func()
|
onResumeAudio func() error
|
||||||
)
|
)
|
||||||
|
|
||||||
func OnSuspendAudio(f func()) {
|
func OnSuspendAudio(f func() error) {
|
||||||
m.Lock()
|
m.Lock()
|
||||||
onSuspendAudio = f
|
onSuspendAudio = f
|
||||||
m.Unlock()
|
m.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func OnResumeAudio(f func()) {
|
func OnResumeAudio(f func() error) {
|
||||||
m.Lock()
|
m.Lock()
|
||||||
onResumeAudio = f
|
onResumeAudio = f
|
||||||
m.Unlock()
|
m.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func SuspendAudio() {
|
func SuspendAudio() error {
|
||||||
m.Lock()
|
m.Lock()
|
||||||
defer m.Unlock()
|
defer m.Unlock()
|
||||||
if audioSuspended {
|
if audioSuspended {
|
||||||
return
|
return nil
|
||||||
}
|
}
|
||||||
audioSuspended = true
|
audioSuspended = true
|
||||||
if onSuspendAudio != nil {
|
if onSuspendAudio != nil {
|
||||||
onSuspendAudio()
|
return onSuspendAudio()
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func ResumeAudio() {
|
func ResumeAudio() error {
|
||||||
m.Lock()
|
m.Lock()
|
||||||
defer m.Unlock()
|
defer m.Unlock()
|
||||||
if !audioSuspended {
|
if !audioSuspended {
|
||||||
return
|
return nil
|
||||||
}
|
}
|
||||||
audioSuspended = false
|
audioSuspended = false
|
||||||
if onResumeAudio != nil {
|
if onResumeAudio != nil {
|
||||||
onResumeAudio()
|
return onResumeAudio()
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -916,12 +916,16 @@ func (u *UserInterface) update() (float64, float64, bool, error) {
|
|||||||
u.input.update(u.window, u.context)
|
u.input.update(u.window, u.context)
|
||||||
|
|
||||||
for !u.isRunnableOnUnfocused() && u.window.GetAttrib(glfw.Focused) == 0 && !u.window.ShouldClose() {
|
for !u.isRunnableOnUnfocused() && u.window.GetAttrib(glfw.Focused) == 0 && !u.window.ShouldClose() {
|
||||||
hooks.SuspendAudio()
|
if err := hooks.SuspendAudio(); err != nil {
|
||||||
|
return 0, 0, false, err
|
||||||
|
}
|
||||||
// Wait for an arbitrary period to avoid busy loop.
|
// Wait for an arbitrary period to avoid busy loop.
|
||||||
time.Sleep(time.Second / 60)
|
time.Sleep(time.Second / 60)
|
||||||
glfw.PollEvents()
|
glfw.PollEvents()
|
||||||
}
|
}
|
||||||
hooks.ResumeAudio()
|
if err := hooks.ResumeAudio(); err != nil {
|
||||||
|
return 0, 0, false, err
|
||||||
|
}
|
||||||
|
|
||||||
return outsideWidth, outsideHeight, outsideSizeChanged, nil
|
return outsideWidth, outsideHeight, outsideSizeChanged, nil
|
||||||
}
|
}
|
||||||
|
@ -258,10 +258,11 @@ func (u *UserInterface) isFocused() bool {
|
|||||||
|
|
||||||
func (u *UserInterface) update() error {
|
func (u *UserInterface) update() error {
|
||||||
if u.suspended() {
|
if u.suspended() {
|
||||||
hooks.SuspendAudio()
|
return hooks.SuspendAudio()
|
||||||
return nil
|
}
|
||||||
|
if err := hooks.ResumeAudio(); err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
hooks.ResumeAudio()
|
|
||||||
return u.updateImpl(false)
|
return u.updateImpl(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -284,7 +285,7 @@ func (u *UserInterface) updateImpl(force bool) error {
|
|||||||
func (u *UserInterface) loop(context driver.UIContext) <-chan error {
|
func (u *UserInterface) loop(context driver.UIContext) <-chan error {
|
||||||
u.context = context
|
u.context = context
|
||||||
|
|
||||||
errCh := make(chan error)
|
errCh := make(chan error, 1)
|
||||||
reqStopAudioCh := make(chan struct{})
|
reqStopAudioCh := make(chan struct{})
|
||||||
resStopAudioCh := make(chan struct{})
|
resStopAudioCh := make(chan struct{})
|
||||||
|
|
||||||
@ -300,7 +301,6 @@ func (u *UserInterface) loop(context driver.UIContext) <-chan error {
|
|||||||
<-resStopAudioCh
|
<-resStopAudioCh
|
||||||
|
|
||||||
errCh <- err
|
errCh <- err
|
||||||
close(errCh)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if u.vsync {
|
if u.vsync {
|
||||||
@ -344,9 +344,15 @@ func (u *UserInterface) loop(context driver.UIContext) <-chan error {
|
|||||||
select {
|
select {
|
||||||
case <-t.C:
|
case <-t.C:
|
||||||
if u.suspended() {
|
if u.suspended() {
|
||||||
hooks.SuspendAudio()
|
if err := hooks.SuspendAudio(); err != nil {
|
||||||
|
errCh <- err
|
||||||
|
return
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
hooks.ResumeAudio()
|
if err := hooks.ResumeAudio(); err != nil {
|
||||||
|
errCh <- err
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case <-reqStopAudioCh:
|
case <-reqStopAudioCh:
|
||||||
return
|
return
|
||||||
|
@ -136,7 +136,10 @@ func (u *UserInterface) appMain(a app.App) {
|
|||||||
case lifecycle.Event:
|
case lifecycle.Event:
|
||||||
switch e.Crosses(lifecycle.StageVisible) {
|
switch e.Crosses(lifecycle.StageVisible) {
|
||||||
case lifecycle.CrossOn:
|
case lifecycle.CrossOn:
|
||||||
u.SetForeground(true)
|
if err := u.SetForeground(true); err != nil {
|
||||||
|
// There are no other ways than panicking here.
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
restorable.OnContextLost()
|
restorable.OnContextLost()
|
||||||
glctx, _ = e.DrawContext.(gl.Context)
|
glctx, _ = e.DrawContext.(gl.Context)
|
||||||
// Assume that glctx is always a same instance.
|
// Assume that glctx is always a same instance.
|
||||||
@ -147,7 +150,10 @@ func (u *UserInterface) appMain(a app.App) {
|
|||||||
}
|
}
|
||||||
a.Send(paint.Event{})
|
a.Send(paint.Event{})
|
||||||
case lifecycle.CrossOff:
|
case lifecycle.CrossOff:
|
||||||
u.SetForeground(false)
|
if err := u.SetForeground(false); err != nil {
|
||||||
|
// There are no other ways than panicking here.
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
glctx = nil
|
glctx = nil
|
||||||
}
|
}
|
||||||
case size.Event:
|
case size.Event:
|
||||||
@ -213,7 +219,7 @@ func (u *UserInterface) appMain(a app.App) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *UserInterface) SetForeground(foreground bool) {
|
func (u *UserInterface) SetForeground(foreground bool) error {
|
||||||
var v int32
|
var v int32
|
||||||
if foreground {
|
if foreground {
|
||||||
v = 1
|
v = 1
|
||||||
@ -221,9 +227,9 @@ func (u *UserInterface) SetForeground(foreground bool) {
|
|||||||
atomic.StoreInt32(&u.foreground, v)
|
atomic.StoreInt32(&u.foreground, v)
|
||||||
|
|
||||||
if foreground {
|
if foreground {
|
||||||
hooks.ResumeAudio()
|
return hooks.ResumeAudio()
|
||||||
} else {
|
} else {
|
||||||
hooks.SuspendAudio()
|
return hooks.SuspendAudio()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,12 +75,12 @@ func Update() error {
|
|||||||
return mobile.Get().Update()
|
return mobile.Get().Update()
|
||||||
}
|
}
|
||||||
|
|
||||||
func Suspend() {
|
func Suspend() error {
|
||||||
mobile.Get().SetForeground(false)
|
return mobile.Get().SetForeground(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Resume() {
|
func Resume() error {
|
||||||
mobile.Get().SetForeground(true)
|
return mobile.Get().SetForeground(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func OnContextLost() {
|
func OnContextLost() {
|
||||||
|
Loading…
Reference in New Issue
Block a user