twilio

package
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 22, 2026 License: MIT Imports: 21 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ComputeSignature

func ComputeSignature(authToken, rawURL string, params url.Values) string

ComputeSignature returns the base64-encoded HMAC-SHA1 signature Twilio expects for a webhook request: the raw URL followed by each sorted POST param key and value, keyed with authToken. See https://www.twilio.com/docs/usage/webhooks/webhooks-security

func DefaultHandleStream

func DefaultHandleStream(ctx context.Context, conn *websocket.Conn, start Frame) error

DefaultHandleStream is the default session handler. It drives a live telephony.Session for the call: media frames are pumped into the session for VAD processing, and the session is closed exactly once when the call ends (a stop frame, a read error, or context cancellation).

func EncodeClear

func EncodeClear(streamSID string) ([]byte, error)

EncodeClear encodes a Twilio clear event (flushes Twilio's audio buffer).

func EncodeConnected

func EncodeConnected() ([]byte, error)

EncodeConnected encodes a Twilio connected event (sent by client to acknowledge connection).

func EncodeDTMF

func EncodeDTMF(streamSID, digit string) ([]byte, error)

EncodeDTMF is a panic-stub for DTMF encoding (not yet implemented).

func EncodeMark

func EncodeMark(streamSID, name string) ([]byte, error)

func EncodeMedia

func EncodeMedia(streamSID string, payload []byte) ([]byte, error)

func EncodeMediaWithMetadata

func EncodeMediaWithMetadata(streamSID string, payload []byte, chunk, seqNum int) ([]byte, error)

EncodeMediaWithMetadata encodes an outgoing media frame with monotonic chunk numbering and its ms-offset timestamp from stream start. chunk is 1-based; timestamp is the frame's start offset, so chunk 1 → "0", chunk 2 → "20", etc. (frames are muLawFrame20ms wide). seqNum is the per-message sequence number for this Media Streams WebSocket session. Per the Twilio spec, sequenceNumber, chunk, and timestamp are all emitted as JSON strings.

func EncodeStart

func EncodeStart(streamSID, callSID, accountSID string, seqNum int) ([]byte, error)

EncodeStart encodes the Twilio start event that a client sends at the beginning of a Media Streams WebSocket session. seqNum is the per-message sequence number for this session, emitted as a JSON string.

func EncodeStop

func EncodeStop(streamSID, callSID, accountSID string, seqNum int) ([]byte, error)

EncodeStop encodes the Twilio stop event that a client sends at the end of a Media Streams WebSocket session. seqNum is the per-message sequence number for this Media Streams WebSocket session, emitted as a JSON string.

func HandleStreamWithOpts

func HandleStreamWithOpts(ctx context.Context, conn *websocket.Conn, start Frame, extraOpts ...telephony.SessionOption) error

HandleStreamWithOpts is like DefaultHandleStream but accepts additional SessionOptions to be passed to the session factory.

func ValidateSignature

func ValidateSignature(authToken, rawURL string, params url.Values, signature string) bool

params should be the parsed POST body (r.PostForm); pass nil for GET requests. See https://www.twilio.com/docs/usage/webhooks/webhooks-security

Types

type Demux

type Demux struct {
	Data    TwilioDataPlaneInput
	Control TwilioControlPlaneInput
	// contains filtered or unexported fields
}

Demux is a single WebSocket-reading goroutine's decode-and-route point: it decodes Twilio Media Streams frames and routes them by event type — EventMedia to the data plane, everything else to the control plane — while detecting gaps in the media chunk sequence. session.go integration (wiring these planes into a live session) is deferred to SOP-115/F.

func NewDemux

func NewDemux() *Demux

NewDemux builds a Demux with production buffer depths: the data plane sized per SOP-116's ComputeDepth(DataPlaneBufferMS, MuLawFrameMS), and a depth-16 control plane.

func NewDemuxWithPlanes

func NewDemuxWithPlanes(data TwilioDataPlaneInput, control TwilioControlPlaneInput) *Demux

NewDemuxWithPlanes builds a Demux from existing data/control planes — used by tests that need non-default buffer depths.

func (*Demux) CloseData

func (d *Demux) CloseData()

CloseData closes the data plane if its concrete type supports it, marking the teardown boundary so the data pump drains and terminates on the resulting errPlaneClosed rather than on context cancellation. A no-op for a data plane that is not a closer.

func (*Demux) Route

func (d *Demux) Route(ctx context.Context, raw []byte) error

Route decodes raw and routes the resulting Frame to the correct plane. Called once per inbound WebSocket message from the demux's single reading goroutine.

func (*Demux) RouteFrame

func (d *Demux) RouteFrame(ctx context.Context, f Frame) error

RouteFrame routes a decoded Frame to the correct plane, checking for chunk-sequence gaps on media frames first.

type EventType

type EventType string

EventType is the Twilio Media Streams WebSocket event type.

const (
	EventStart     EventType = "start"
	EventMedia     EventType = "media"
	EventStop      EventType = "stop"
	EventMark      EventType = "mark"
	EventClear     EventType = "clear"
	EventConnected EventType = "connected"
)

type Frame

type Frame struct {
	Event     EventType
	StreamSID string
	Payload   []byte // decoded μ-law audio; non-nil only for EventMedia
	Chunk     int    // monotonic frame sequence number; only set for EventMedia
	Timestamp string // ms offset from stream start; only set for EventMedia
	MarkName  string // non-empty only for EventMark
	CallSID   string // non-empty only for EventStart
}

Frame is a decoded Twilio Media Streams WebSocket message.

func DecodeFrame

func DecodeFrame(raw []byte) (Frame, error)

type InboundSMS

type InboundSMS struct {
	MessageSID string // Twilio MessageSid
	From       string // sender, E.164
	To         string // the Twilio number that received it, E.164
	Body       string // message text
}

InboundSMS is the parsed subset of a Twilio inbound-message webhook. Additional fields (NumMedia, MediaUrl0…, NumSegments, …) remain available on the raw form if a consumer needs them later.

type SMSHandler

type SMSHandler func(ctx context.Context, msg InboundSMS)

SMSHandler is called by ServeSMS for each validated inbound-SMS webhook. It is fire-and-forget: ServeSMS always answers Twilio with empty TwiML regardless, so a synchronous reply is not modeled here (a future reply path is a separate change).

type Server

type Server struct {
	AuthToken    string
	HandleStream StreamHandler
	HandleSMS    SMSHandler

	// StreamScheme selects the scheme advertised in the TwiML <Stream url>
	// and, correspondingly, the scheme used to reconstruct the URL for
	// signature validation. "ws" advertises/validates over ws/http; "wss"
	// or the zero value "" advertise/validate over wss/https (secure by
	// default — a directly-constructed Server{} is never accidentally
	// insecure).
	StreamScheme string
}

Server handles Twilio HTTP webhook requests and WebSocket Media Streams connections. Set AuthToken to the Twilio auth token for the account; every inbound webhook request is validated against the X-Twilio-Signature header before processing. Set HandleStream to handle incoming Media Streams WebSocket connections, and HandleSMS to handle inbound SMS webhooks.

func (*Server) ServeHTTP

func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP implements http.Handler for the Twilio call webhook. It validates the request signature (403 on failure, including an empty AuthToken), then validates the caller's E.164 From number (403 on failure), logs From and CallSid, and responds with TwiML instructing Twilio to open the Media Streams WebSocket at /streams.

func (*Server) ServeSMS

func (s *Server) ServeSMS(w http.ResponseWriter, r *http.Request)

ServeSMS handles a Twilio inbound-SMS webhook. It validates the request signature (403 on failure, including an empty AuthToken), parses the message fields into InboundSMS, hands them to HandleSMS if set, and answers with empty TwiML so Twilio sends no automatic reply.

func (*Server) ServeStreams

func (s *Server) ServeStreams(w http.ResponseWriter, r *http.Request)

ServeStreams handles a Twilio Media Streams WebSocket connection. It upgrades the HTTP connection to WebSocket, reads the mandatory start frame (optionally preceded by a connected frame), then calls HandleStream. If HandleStream is nil, inbound frames are read and discarded until the client disconnects.

type StreamHandler

type StreamHandler func(ctx context.Context, conn *websocket.Conn, start Frame) error

StreamHandler is called by ServeStreams for each accepted Twilio Media Streams WebSocket connection, after the mandatory start frame has been decoded. The handler owns the connection for the duration of the call and returns when done.

type Tap

type Tap struct {
	// contains filtered or unexported fields
}

func NewTap

func NewTap(dir, streamSID, callSID, label string, startedAt time.Time) *Tap

func (*Tap) Close

func (t *Tap) Close()

func (*Tap) DrainOut

func (t *Tap) DrainOut()

func (*Tap) WriteIn

func (t *Tap) WriteIn(payload []byte)

func (*Tap) WriteOut

func (t *Tap) WriteOut(payload []byte)

type TeardownSignaler

type TeardownSignaler interface {
	// Teardown returns a channel that is closed exactly once, when the
	// control plane overflows.
	Teardown() <-chan struct{}
}

TeardownSignaler is implemented by control-plane inputs that can signal a fatal, unrecoverable overflow requiring the call to be torn down.

type TwilioControlPlaneInput

type TwilioControlPlaneInput = telephony.ServiceInput[Frame]

TwilioControlPlaneInput is the SOP-116 ServiceInput pattern specialized to Frame for the Twilio control plane (start/stop/mark/clear events). Its concrete implementation (controlPlaneInput) treats a full buffer as fatal rather than dropping or blocking indefinitely.

func NewControlPlane

func NewControlPlane(depth int) TwilioControlPlaneInput

NewControlPlane returns a new TwilioControlPlaneInput with the given buffer depth. Sending into a full control plane is fatal — see Send.

type TwilioControlPlaneOutput

type TwilioControlPlaneOutput = telephony.ServiceOutput[telephony.ControlOutMessage]

TwilioControlPlaneOutput is the send side of the channel a Session writes outbound control-plane messages to (mark/clear) (SOP-125).

func NewControlPlaneOutput

func NewControlPlaneOutput(conn *websocket.Conn, streamSID string) TwilioControlPlaneOutput

NewControlPlaneOutput builds a TwilioControlPlaneOutput that writes outbound control-plane messages for streamSID to conn.

type TwilioDataPlaneInput

type TwilioDataPlaneInput = telephony.ServiceInput[Frame]

TwilioDataPlaneInput is the SOP-116 ServiceInput pattern specialized to Frame for the Twilio data plane (audio media frames). Its concrete implementation (dropOldestPlane) evicts the oldest buffered frame rather than blocking when full.

func NewDataPlane

func NewDataPlane(depth int) TwilioDataPlaneInput

NewDataPlane returns a new drop-oldest TwilioDataPlaneInput with the given buffer depth: once full, Send evicts the oldest buffered frame to make room for the newest one.

This is the one place the data plane's clock is read. Everything below it takes the reading, which is what lets a test assert a drop episode's reported duration exactly rather than sleeping and hoping.

type TwilioDataPlaneOutput

type TwilioDataPlaneOutput = telephony.ServiceOutput[[]byte]

TwilioDataPlaneOutput is the send side of the channel a Session writes outbound media frames to (SOP-125). Twilio-package-local alias, following the same cross-package-alias-with-different-T pattern as TwilioDataPlaneInput above (avoids an import cycle: this package already imports telephony, so telephony cannot import it back).

func NewDataPlaneOutput

func NewDataPlaneOutput(conn *websocket.Conn, streamSID string, tap *Tap) TwilioDataPlaneOutput

NewDataPlaneOutput builds a TwilioDataPlaneOutput that writes outbound media frames for streamSID to conn. tap may be nil (capture disabled), which is a no-op on the WriteOut call in Send below.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL