github.com/CyCoreSystems/ari@v4.8.4+incompatible/_examples/bridge/main.go (about)

     1  package main
     2  
     3  import (
     4  	"context"
     5  	"sync"
     6  
     7  	"github.com/inconshreveable/log15"
     8  
     9  	"github.com/CyCoreSystems/ari"
    10  	"github.com/CyCoreSystems/ari/client/native"
    11  	"github.com/CyCoreSystems/ari/ext/play"
    12  	"github.com/CyCoreSystems/ari/rid"
    13  	"github.com/pkg/errors"
    14  )
    15  
    16  var ariApp = "test"
    17  
    18  var log = log15.New()
    19  
    20  var bridge *ari.BridgeHandle
    21  
    22  func main() {
    23  	ctx, cancel := context.WithCancel(context.Background())
    24  	defer cancel()
    25  
    26  	// connect
    27  	log.Info("Connecting to ARI")
    28  	cl, err := native.Connect(&native.Options{
    29  		Application:  "test",
    30  		Username:     "admin",
    31  		Password:     "admin",
    32  		URL:          "http://localhost:8088/ari",
    33  		WebsocketURL: "ws://localhost:8088/ari/events",
    34  	})
    35  	if err != nil {
    36  		log.Error("Failed to build ARI client", "error", err)
    37  		return
    38  	}
    39  
    40  	// setup app
    41  
    42  	log.Info("Starting listener app")
    43  
    44  	log.Info("Listening for new calls")
    45  	sub := cl.Bus().Subscribe(nil, "StasisStart")
    46  
    47  	for {
    48  		select {
    49  		case e := <-sub.Events():
    50  			v := e.(*ari.StasisStart)
    51  			log.Info("Got stasis start", "channel", v.Channel.ID)
    52  			go app(ctx, cl, cl.Channel().Get(v.Key(ari.ChannelKey, v.Channel.ID)))
    53  		case <-ctx.Done():
    54  			return
    55  		}
    56  	}
    57  }
    58  
    59  func app(ctx context.Context, cl ari.Client, h *ari.ChannelHandle) {
    60  	log.Info("running app", "channel", h.Key().ID)
    61  
    62  	if err := h.Answer(); err != nil {
    63  		log.Error("failed to answer call", "error", err)
    64  		//return
    65  	}
    66  
    67  	if err := ensureBridge(ctx, cl, h.Key()); err != nil {
    68  		log.Error("failed to manage bridge", "error", err)
    69  		return
    70  	}
    71  
    72  	if err := bridge.AddChannel(h.Key().ID); err != nil {
    73  		log.Error("failed to add channel to bridge", "error", err)
    74  		return
    75  	}
    76  
    77  	log.Info("channel added to bridge")
    78  	return
    79  }
    80  
    81  type bridgeManager struct {
    82  	h *ari.BridgeHandle
    83  }
    84  
    85  func ensureBridge(ctx context.Context, cl ari.Client, src *ari.Key) (err error) {
    86  	if bridge != nil {
    87  		log.Debug("Bridge already exists")
    88  		return nil
    89  	}
    90  
    91  	key := src.New(ari.BridgeKey, rid.New(rid.Bridge))
    92  	bridge, err = cl.Bridge().Create(key, "mixing", key.ID)
    93  	if err != nil {
    94  		bridge = nil
    95  		return errors.Wrap(err, "failed to create bridge")
    96  	}
    97  
    98  	wg := new(sync.WaitGroup)
    99  	wg.Add(1)
   100  	go manageBridge(ctx, bridge, wg)
   101  	wg.Wait()
   102  
   103  	return nil
   104  }
   105  
   106  func manageBridge(ctx context.Context, h *ari.BridgeHandle, wg *sync.WaitGroup) {
   107  	// Delete the bridge when we exit
   108  	defer h.Delete()
   109  
   110  	destroySub := h.Subscribe(ari.Events.BridgeDestroyed)
   111  	defer destroySub.Cancel()
   112  
   113  	enterSub := h.Subscribe(ari.Events.ChannelEnteredBridge)
   114  	defer enterSub.Cancel()
   115  
   116  	leaveSub := h.Subscribe(ari.Events.ChannelLeftBridge)
   117  	defer leaveSub.Cancel()
   118  
   119  	wg.Done()
   120  	for {
   121  		select {
   122  		case <-ctx.Done():
   123  			return
   124  		case <-destroySub.Events():
   125  			log.Debug("bridge destroyed")
   126  			return
   127  		case e, ok := <-enterSub.Events():
   128  			if !ok {
   129  				log.Error("channel entered subscription closed")
   130  				return
   131  			}
   132  			v := e.(*ari.ChannelEnteredBridge)
   133  			log.Debug("channel entered bridge", "channel", v.Channel.Name)
   134  			go func() {
   135  				if err := play.Play(ctx, h, play.URI("sound:confbridge-join")).Err(); err != nil {
   136  					log.Error("failed to play join sound", "error", err)
   137  				}
   138  			}()
   139  		case e, ok := <-leaveSub.Events():
   140  			if !ok {
   141  				log.Error("channel left subscription closed")
   142  				return
   143  			}
   144  			v := e.(*ari.ChannelLeftBridge)
   145  			log.Debug("channel left bridge", "channel", v.Channel.Name)
   146  			go func() {
   147  				if err := play.Play(ctx, h, play.URI("sound:confbridge-leave")).Err(); err != nil {
   148  					log.Error("failed to play leave sound", "error", err)
   149  				}
   150  			}()
   151  		}
   152  	}
   153  }