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  }