package asterisk import ( "context" "errors" "fmt" "github.com/CyCoreSystems/ari/v5" ) // awaitDialUp only runs after Dial was submitted. Create enters Stasis before // any SIP request is sent, so StasisStart alone can never prove an answer. func awaitDialUp(ctx context.Context, sub ari.Subscription, channelID string) error { if ctx == nil || sub == nil || channelID == "" { return errors.New("native answer wait has no channel subscription") } stasis, up := false, false for { select { case <-ctx.Done(): return ctx.Err() case event, ok := <-sub.Events(): if !ok { return errors.New("native answer subscription closed before confirmed answer") } if event == nil { continue } switch e := event.(type) { case *ari.StasisStart: if e.Channel.ID == channelID { stasis = true } case *ari.ChannelStateChange: if e.Channel.ID == channelID && e.Channel.State == "Up" { up = true } case *ari.ChannelDestroyed: if e.Channel.ID == channelID { return fmt.Errorf("native outbound channel destroyed before verified answer: cause=%d", e.Cause) } case *ari.ChannelHangupRequest: if e.Channel.ID == channelID { return fmt.Errorf("native outbound channel requested hangup before verified answer: cause=%d", e.Cause) } case *ari.StasisEnd: if e.Channel.ID == channelID { return errors.New("native outbound channel left Stasis before verified answer") } } if stasis && up { return nil } } } } func eventBelongsToChannel(event ari.Event, channelID string) bool { for _, key := range event.Keys() { if key != nil && key.Kind == "channel" && key.ID == channelID { return true } } return false }