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 }