summaryrefslogtreecommitdiff
path: root/player
diff options
context:
space:
mode:
authorChristian Pointner <equinox@spreadspace.org>2016-01-29 00:19:16 (GMT)
committerChristian Pointner <equinox@spreadspace.org>2016-01-29 00:19:16 (GMT)
commitd17040c8af01f54f055234837da7abeeaceea044 (patch)
tree3039550a08a4d9c0feaf1dded3074b2d961c9d2c /player
parentad7712e6d2add324c6dbdffb319b989a32a668b5 (diff)
implemented play-pause and state change callbacks
Diffstat (limited to 'player')
-rw-r--r--player/player.go169
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