func (s *Server) VoiceCalls() chan *VoiceCall {
	return s.callCh
}
VoiceCalls will return a channel that will be fed VoiceCalls as they arrive.
package mocktwilio
import (
	"bytes"
	"encoding/json"
	"encoding/xml"
	"fmt"
	"net/http"
	"net/url"
	"path"
	"strconv"
	"strings"
	"sync"
	"time"
	"github.com/pkg/errors"
	"github.com/target/goalert/notification/twilio"
	"github.com/target/goalert/validation/validate"
)
type VoiceCall struct {
	s *Server
	mx sync.Mutex
	call twilio.Call
	acceptCh chan struct{}
	rejectCh chan struct{}
	messageCh chan string
	pressCh   chan string
	hangupCh  chan struct{}
	doneCh    chan struct{}
	start time.Time
	callStart      time.Time
	url            string
	callbackURL    string
	lastMessage    string
	callbackEvents []string
	hangup         bool
}
func (vc *VoiceCall) process() {
	defer vc.s.workers.Done()
	defer close(vc.doneCh)
	if vc.s.wait(vc.s.cfg.MinQueueTime) {
		return
	}
	vc.updateStatus(twilio.CallStatusInitiated)
	if vc.s.wait(vc.s.cfg.MinQueueTime) {
		return
	}
	vc.updateStatus(twilio.CallStatusRinging)
	var err error
	vc.lastMessage, err = vc.fetchMessage("")
	if err != nil {
		vc.s.errs <- fmt.Errorf("fetch message: %w", err)
		return
	}
	select {
	case vc.s.callCh <- vc:
	case <-vc.s.shutdown:
		return
	}
waitForAccept:
	for {
		select {
		case vc.messageCh <- vc.lastMessage:
		case <-vc.acceptCh:
			break waitForAccept
		case <-vc.rejectCh:
			vc.updateStatus(twilio.CallStatusFailed)
			return
		case <-vc.s.shutdown:
			return
		}
	}
	vc.updateStatus(twilio.CallStatusInProgress)
	vc.callStart = time.Now()
	for {
		select {
		case <-vc.rejectCh:
			vc.updateStatus(twilio.CallStatusFailed)
			return
		case <-vc.s.shutdown:
			return
		case <-vc.hangupCh:
			vc.updateStatus(twilio.CallStatusCompleted)
			return
		case vc.messageCh <- vc.lastMessage:
		case digits := <-vc.pressCh:
			vc.lastMessage, err = vc.fetchMessage(digits)
			if err != nil {
				vc.s.errs <- fmt.Errorf("fetch message: %w", err)
				return
			}
			if vc.hangup {
				vc.updateStatus(twilio.CallStatusCompleted)
				return
			}
		}
	}
}
func (s *Server) serveCallStatus(w http.ResponseWriter, req *http.Request) {
	id := strings.TrimSuffix(path.Base(req.URL.Path), ".json")
	vc := s.call(id)
	if vc == nil {
		http.NotFound(w, req)
		return
	}
	err := json.NewEncoder(w).Encode(vc.cloneCall())
	if err != nil {
		panic(err)
	}
}
func (s *Server) call(id string) *VoiceCall {
	s.mx.RLock()
	defer s.mx.RUnlock()
	return s.calls[id]
}
func (s *Server) serveNewCall(w http.ResponseWriter, req *http.Request) {
	if req.Method != "POST" {
		http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
		return
	}
	vc := VoiceCall{
		acceptCh:  make(chan struct{}),
		doneCh:    make(chan struct{}),
		rejectCh:  make(chan struct{}),
		messageCh: make(chan string),
		pressCh:   make(chan string),
		hangupCh:  make(chan struct{}),
	}
	fromValue := req.FormValue("From")
	s.mx.RLock()
	_, hasCallback := s.callbacks["VOICE:"+fromValue]
	s.mx.RUnlock()
	if !hasCallback {
		apiError(400, w, &twilio.Exception{
			Message: "Wrong from number.",
		})
		return
	}
	vc.s = s
	vc.call.To = req.FormValue("To")
	vc.call.From = fromValue
	vc.call.SID = s.id("CA")
	vc.call.SequenceNumber = new(int)
	vc.callbackURL = req.FormValue("StatusCallback")
	err := validate.URL("StatusCallback", vc.callbackURL)
	if err != nil {
		apiError(400, w, &twilio.Exception{
			Code:    11100,
			Message: err.Error(),
		})
		return
	}
	vc.url = req.FormValue("Url")
	err = validate.URL("StatusCallback", vc.url)
	if err != nil {
		apiError(400, w, &twilio.Exception{
			Code:    11100,
			Message: err.Error(),
		})
		return
	}
	vc.callbackEvents = map[string][]string(req.Form)["StatusCallbackEvent"]
	vc.callbackEvents = append(vc.callbackEvents, "completed", "failed")  
	vc.start = time.Now()
	vc.call.Status = twilio.CallStatusQueued
	s.mx.Lock()
	s.calls[vc.call.SID] = &vc
	s.mx.Unlock()
	s.callInCh <- &vc
	data, err := json.Marshal(vc.cloneCall())
	if err != nil {
		panic(err)
	}
	w.WriteHeader(201)
	_, err = w.Write(data)
	if err != nil {
		panic(err)
	}
}
func (vc *VoiceCall) updateStatus(stat twilio.CallStatus) {
	vc.mx.Lock()
	vc.call.Status = stat
	switch stat {
	case twilio.CallStatusInProgress:
		vc.callStart = time.Now()
	case twilio.CallStatusCompleted:
		vc.call.CallDuration = time.Since(vc.callStart)
	}
	*vc.call.SequenceNumber++
	vc.mx.Unlock()
	var sendEvent bool
	evtName := string(stat)
	if evtName == "in-progres" {
		evtName = "answered"
	}
	for _, e := range vc.callbackEvents {
		if e == evtName {
			sendEvent = true
			break
		}
	}
	if !sendEvent {
		return
	}
	_, err := vc.s.post(vc.callbackURL, vc.values(""))
	if err != nil {
		vc.s.errs <- errors.Wrap(err, "post to call status callback")
	}
}
func (vc *VoiceCall) values(digits string) url.Values {
	call := vc.cloneCall()
	v := make(url.Values)
	v.Set("CallSid", call.SID)
	v.Set("CallStatus", string(call.Status))
	v.Set("To", call.To)
	v.Set("From", call.From)
	v.Set("Direction", "outbound-api")
	v.Set("SequenceNumber", strconv.Itoa(*call.SequenceNumber))
	if call.Status == twilio.CallStatusCompleted {
		v.Set("CallDuration", strconv.FormatFloat(call.CallDuration.Seconds(), 'f', 1, 64))
	}
	if digits != "" {
		v.Set("Digits", digits)
	}
	return v
}