github.com/CyCoreSystems/ari@v4.8.4+incompatible/ext/play/sequence.go (about) 1 package play 2 3 import ( 4 "context" 5 "time" 6 7 "github.com/CyCoreSystems/ari" 8 "github.com/CyCoreSystems/ari/rid" 9 "github.com/pkg/errors" 10 ) 11 12 // sequence represents an audio sequence playback session 13 type sequence struct { 14 cancel context.CancelFunc 15 s *playSession 16 17 done chan struct{} 18 } 19 20 func (s *sequence) Done() <-chan struct{} { 21 return s.done 22 } 23 24 func (s *sequence) Stop() { 25 if s.cancel != nil { 26 s.cancel() 27 } 28 } 29 30 func newSequence(s *playSession) *sequence { 31 return &sequence{ 32 s: s, 33 done: make(chan struct{}), 34 } 35 } 36 37 func (s *sequence) Play(ctx context.Context, p ari.Player) { 38 ctx, cancel := context.WithCancel(ctx) 39 s.cancel = cancel 40 defer cancel() 41 defer close(s.done) 42 43 for u := s.s.o.uriList.First(); u != ""; u = s.s.o.uriList.Next() { 44 pb, err := p.StagePlay(rid.New(rid.Playback), u) 45 if err != nil { 46 s.s.result.Status = Failed 47 s.s.result.Error = errors.Wrap(err, "failed to stage playback") 48 return 49 } 50 51 s.s.result.Status, err = playStaged(ctx, pb, s.s.o.playbackStartTimeout) 52 if err != nil { 53 s.s.result.Error = errors.Wrap(err, "failure in playback") 54 return 55 } 56 } 57 } 58 59 // playStaged executes a staged playback, waiting for its completion 60 func playStaged(ctx context.Context, h *ari.PlaybackHandle, timeout time.Duration) (Status, error) { 61 started := h.Subscribe(ari.Events.PlaybackStarted) 62 defer started.Cancel() 63 finished := h.Subscribe(ari.Events.PlaybackFinished) 64 defer finished.Cancel() 65 66 err := h.Exec() 67 if err != nil { 68 return Failed, errors.Wrap(err, "failed to start playback") 69 } 70 defer h.Stop() // nolint: errcheck 71 72 select { 73 case <-ctx.Done(): 74 return Cancelled, nil 75 case <-started.Events(): 76 case <-finished.Events(): 77 return Finished, nil 78 case <-time.After(timeout): 79 return Timeout, errors.New("timeout waiting for playback to start") 80 } 81 82 // Wait for playback to complete 83 select { 84 case <-ctx.Done(): 85 return Cancelled, nil 86 case <-finished.Events(): 87 return Finished, nil 88 } 89 }