diff options
author | Christian Pointner <equinox@spreadspace.org> | 2016-01-29 00:19:16 (GMT) |
---|---|---|
committer | Christian Pointner <equinox@spreadspace.org> | 2016-01-29 00:19:16 (GMT) |
commit | d17040c8af01f54f055234837da7abeeaceea044 (patch) | |
tree | 3039550a08a4d9c0feaf1dded3074b2d961c9d2c | |
parent | ad7712e6d2add324c6dbdffb319b989a32a668b5 (diff) |
implemented play-pause and state change callbacks
-rw-r--r-- | player/player.go | 169 |
1 files changed, 137 insertions, 32 deletions
diff --git a/player/player.go b/player/player.go index c3465c0..bf0bc1f 100644 --- a/player/player.go +++ b/player/player.go @@ -65,6 +65,14 @@ type pauseRequest struct { response chan<- pauseResult } +type playPauseResult struct { + err error +} + +type playPauseRequest struct { + response chan<- playPauseResult +} + type stopResult struct { err error } @@ -92,6 +100,16 @@ type addUpdateHandlerRequest struct { response chan<- addUpdateHandlerResult } +type addStateChangeHandlerResult struct { + err error +} + +type addStateChangeHandlerRequest struct { + userdata interface{} + callback StateChangeCB + response chan<- addStateChangeHandlerResult +} + type MeterChannel struct { Peak float64 Decay float64 @@ -116,24 +134,39 @@ const ( PLAYING ) +type StateChangeCB func(state State, userdata interface{}) bool +type pStateChangeCB struct { + cb StateChangeCB + userdata interface{} +} + type Player struct { - pipe *gst.Pipeline - src *gst.Element - level *gst.Element - bus *gst.Bus - basepath string - stdlog *log.Logger - dbglog *log.Logger - state State - duration time.Duration - loadChan chan loadRequest - playChan chan playRequest - pauseChan chan pauseRequest - stopChan chan stopRequest - seekChan chan seekRequest - updateChan chan updateData - addUpdateHandlerChan chan addUpdateHandlerRequest - updateCBs []*pUpdateCB + pipe *gst.Pipeline + src *gst.Element + level *gst.Element + bus *gst.Bus + basepath string + stdlog *log.Logger + dbglog *log.Logger + state State + duration time.Duration + loadChan chan loadRequest + playChan chan playRequest + pauseChan chan pauseRequest + playPauseChan chan playPauseRequest + stopChan chan stopRequest + seekChan chan seekRequest + addUpdateHandlerChan chan addUpdateHandlerRequest + updateCBs []*pUpdateCB + updateChan chan updateData + addStateChangeHandlerChan chan addStateChangeHandlerRequest + stateChangeCBs []*pStateChangeCB + stateChangeChan chan State +} + +func (p *Player) changeState(new State) { + p.state = new + p.stateChangeChan <- new } func (p *Player) onMessage(bus *gst.Bus, msg *gst.Message) { @@ -141,14 +174,14 @@ func (p *Player) onMessage(bus *gst.Bus, msg *gst.Message) { case gst.MESSAGE_EOS: p.pipe.SetState(gst.STATE_NULL) p.pipe.SetState(gst.STATE_PAUSED) - p.state = PAUSED + p.changeState(PAUSED) p.duration = 0 case gst.MESSAGE_WARNING: warn, _ := msg.ParseWarning() p.stdlog.Printf("GStreamer Pipeline Warning: %s", warn) case gst.MESSAGE_ERROR: p.pipe.SetState(gst.STATE_NULL) - p.state = IDLE + p.changeState(IDLE) p.duration = 0 p.updateChan <- updateData{duration: p.duration} err, _ := msg.ParseError() @@ -211,11 +244,11 @@ func (p *Player) load(cart, cut uint) (resp loadResult) { if p.state != IDLE { p.pipe.SetState(gst.STATE_NULL) - p.state = IDLE + p.changeState(IDLE) } p.src.SetProperty("uri", "file://"+filename) p.pipe.SetState(gst.STATE_PAUSED) - p.state = PAUSED + p.changeState(PAUSED) return } @@ -225,7 +258,7 @@ func (p *Player) play() (resp playResult) { return } p.pipe.SetState(gst.STATE_PLAYING) - p.state = PLAYING + p.changeState(PLAYING) return } @@ -235,7 +268,21 @@ func (p *Player) pause() (resp pauseResult) { return } p.pipe.SetState(gst.STATE_PAUSED) - p.state = PAUSED + p.changeState(PAUSED) + return +} + +func (p *Player) playPause() (resp playPauseResult) { + switch p.state { + case IDLE: + fallthrough + case PAUSED: + p.pipe.SetState(gst.STATE_PLAYING) + p.changeState(PLAYING) + case PLAYING: + p.pipe.SetState(gst.STATE_PAUSED) + p.changeState(PAUSED) + } return } @@ -243,13 +290,13 @@ func (p *Player) stop() (resp stopResult) { switch p.state { case IDLE: p.pipe.SetState(gst.STATE_NULL) - p.state = IDLE + p.changeState(IDLE) case PLAYING: fallthrough case PAUSED: p.pipe.SetState(gst.STATE_NULL) p.pipe.SetState(gst.STATE_PAUSED) - p.state = PAUSED + p.changeState(PAUSED) } return } @@ -281,6 +328,22 @@ func (p *Player) sendUpdate(duration time.Duration, pos time.Duration, meter Met return } +func (p *Player) addStateChangeHandler(callback StateChangeCB, userdata interface{}) (resp addStateChangeHandlerResult) { + p.stateChangeCBs = append(p.stateChangeCBs, &pStateChangeCB{callback, userdata}) + return +} + +func (p *Player) sendStateChange(s State) { + for _, cb := range p.stateChangeCBs { + if cb.cb != nil { + if keep := cb.cb(s, cb.userdata); !keep { + cb.cb = nil + } + } + } + return +} + func (p *Player) dispatchRequests() { p.bus.AddSignalWatch() p.bus.Connect("message", func(bus *gst.Bus, msg *gst.Message) { p.onMessage(bus, msg) }) @@ -293,6 +356,8 @@ func (p *Player) dispatchRequests() { req.response <- p.play() case req := <-p.pauseChan: req.response <- p.pause() + case req := <-p.playPauseChan: + req.response <- p.playPause() case req := <-p.stopChan: req.response <- p.stop() case req := <-p.seekChan: @@ -301,6 +366,10 @@ func (p *Player) dispatchRequests() { req.response <- p.addUpdateHandler(req.callback, req.userdata) case u := <-p.updateChan: p.sendUpdate(u.duration, u.pos, u.meter) + case req := <-p.addStateChangeHandlerChan: + req.response <- p.addStateChangeHandler(req.callback, req.userdata) + case s := <-p.stateChangeChan: + p.sendStateChange(s) } } } @@ -361,12 +430,14 @@ func (p *Player) createPipeline() (err error) { // Public Interface type PlayerChan struct { - load chan<- loadRequest - play chan<- playRequest - pause chan<- pauseRequest - stop chan<- stopRequest - seek chan<- seekRequest - addUpdateHandler chan addUpdateHandlerRequest + load chan<- loadRequest + play chan<- playRequest + playPause chan<- playPauseRequest + pause chan<- pauseRequest + stop chan<- stopRequest + seek chan<- seekRequest + addUpdateHandler chan<- addUpdateHandlerRequest + addStateChangeHandler chan<- addStateChangeHandlerRequest } func (p *PlayerChan) Load(cart, cut uint) error { @@ -410,6 +481,19 @@ func (p *PlayerChan) Pause() error { return nil } +func (p *PlayerChan) PlayPause() error { + resCh := make(chan playPauseResult) + req := playPauseRequest{} + req.response = resCh + p.playPause <- req + + res := <-resCh + if res.err != nil { + return res.err + } + return nil +} + func (p *PlayerChan) Stop() error { resCh := make(chan stopResult) req := stopRequest{} @@ -452,20 +536,38 @@ func (p *PlayerChan) AddUpdateHandler(callback UpdateCB, userdata interface{}) e return nil } +func (p *PlayerChan) AddStateChangeHandler(callback StateChangeCB, userdata interface{}) error { + resCh := make(chan addStateChangeHandlerResult) + req := addStateChangeHandlerRequest{} + req.callback = callback + req.userdata = userdata + req.response = resCh + p.addStateChangeHandler <- req + + res := <-resCh + if res.err != nil { + return res.err + } + return nil +} + func (p *Player) GetInterface() *PlayerChan { ch := &PlayerChan{} ch.load = p.loadChan ch.play = p.playChan ch.pause = p.pauseChan + ch.playPause = p.playPauseChan ch.stop = p.stopChan ch.seek = p.seekChan ch.addUpdateHandler = p.addUpdateHandlerChan + ch.addStateChangeHandler = p.addStateChangeHandlerChan return ch } func NewPlayer(basepath string, stdlog *log.Logger, dbglog *log.Logger) (p *Player, err error) { p = &Player{} p.basepath = path.Clean(basepath) + p.state = IDLE p.duration = 0 if stdlog != nil { p.stdlog = stdlog @@ -480,10 +582,13 @@ func NewPlayer(basepath string, stdlog *log.Logger, dbglog *log.Logger) (p *Play p.loadChan = make(chan loadRequest) p.playChan = make(chan playRequest) p.pauseChan = make(chan pauseRequest) + p.playPauseChan = make(chan playPauseRequest) p.stopChan = make(chan stopRequest) p.seekChan = make(chan seekRequest) - p.updateChan = make(chan updateData, 20) p.addUpdateHandlerChan = make(chan addUpdateHandlerRequest) + p.updateChan = make(chan updateData, 20) + p.addStateChangeHandlerChan = make(chan addStateChangeHandlerRequest) + p.stateChangeChan = make(chan State, 10) if err = p.createPipeline(); err != nil { return |