68 lines
2.0 KiB
Go
68 lines
2.0 KiB
Go
package asterisk
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/CyCoreSystems/ari/v5"
|
|
)
|
|
|
|
// awaitStasisStart only marks the exact originated channel answered after it
|
|
// enters our ARI application. A generic Up event is not proof of media setup.
|
|
func awaitStasisStart(ctx context.Context, subscription ari.Subscription, channelID string) error {
|
|
if ctx == nil || subscription == nil || channelID == "" {
|
|
return errors.New("ARI answer subscription and channel identity required")
|
|
}
|
|
recent := make([]string, 0, 8)
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
return fmt.Errorf("ARI answer deadline or cancellation (recent_events=%s): %w", strings.Join(recent, ","), ctx.Err())
|
|
case event, open := <-subscription.Events():
|
|
if !open {
|
|
return errors.New("ARI event subscription closed before answer")
|
|
}
|
|
if event == nil {
|
|
return errors.New("ARI answer subscription delivered an empty event")
|
|
}
|
|
typ := event.GetType()
|
|
if len(recent) == cap(recent) {
|
|
recent = recent[1:]
|
|
}
|
|
recent = append(recent, typ)
|
|
if !eventBelongsToChannel(event, channelID) {
|
|
continue
|
|
}
|
|
switch typ {
|
|
case "StasisStart":
|
|
if _, ok := event.(*ari.StasisStart); ok {
|
|
return nil
|
|
}
|
|
case "StasisEnd":
|
|
return errors.New("ARI channel left the application before StasisStart")
|
|
case "ChannelHangupRequest":
|
|
if hangup, ok := event.(*ari.ChannelHangupRequest); ok {
|
|
return fmt.Errorf("ARI channel ended before StasisStart: hangup_cause=%d", hangup.Cause)
|
|
}
|
|
return errors.New("ARI channel ended before StasisStart: hangup request")
|
|
case "ChannelDestroyed":
|
|
if destroyed, ok := event.(*ari.ChannelDestroyed); ok {
|
|
return fmt.Errorf("ARI channel ended before StasisStart: destroy_cause=%d", destroyed.Cause)
|
|
}
|
|
return errors.New("ARI channel ended before StasisStart: destroyed")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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
|
|
}
|