sipgox

package module
v0.0.0-...-19815f3 Latest Latest
Warning

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

Go to latest
Published: Apr 7, 2024 License: BSD-2-Clause Imports: 22 Imported by: 0

README

sipgox

is experimental/extra area to add more functionality on top sipgo lib, more specifically fill gap for building user agents with media.

If use it in your projects consider that this repo will not have stable code until it is considered merging to sipgo stack

If you find useful, support/sponsor sipgo lib, open issue etc...

Here you can find GO Documentation

Tools using this lib:

Features:

  • Simple API for UA/phone build with dial answer register actions
  • Dialog setup and small SDP with alaw and ulaw codec
  • RTP/RTCP receiving and logging
  • Extendable MediaSession handling for RTP/RTCP handling (ex microphone,speaker)
  • Hangup control on caller
  • Timeouts handling
  • Digest auth
  • DTMF encoder, decoder via RFC4733
  • Transfers on phone answer, dial
  • SDP codec fields manipulating
  • SDP negotiation fail

Checkout echome example to see more.

Phone

Phone is wrapper that can make you to build fast phone, create/receive SIP call, handle RTP/RTCP. It uses sipgo.Dialog and adds media handling on top.

It has specific design, and it can not be used for full softphone build.

Dialer
ua, _ := sipgo.NewUA()
defer ua.Close()

// Create a phone
phone := sipgox.NewPhone(ua) 

// Run dial
ctx, _ := context.WithTimeout(context.Background(), 60*time.Second)

// Blocks until call is answered
dialog, err := phone.Dial(ctx, sip.Uri{User:"bob", Host: "localhost", Port:5060}, sipgox.DialOptions{})
if err != nil {
    // handle error
    return
}
defer dialog.Close() // Close dialog for cleanup

select {
case <-dialog.Done():
    return
case <-time.After(5 *time.Second):
    dialog.Hangup(context.TODO())
}
Receiver
ctx, _ := context.WithCancel(context.Background())

ua, _ := sipgo.NewUA()
defer ua.Close()

// Create a phone
phone := sipgox.NewPhone(ua)

// Blocks until call is answered
dialog, err := phone.Answer(ctx, sipgox.AnswerOptions{
    Ringtime:  5* time.Second,
})
if err != nil {
    //handle error
    return
}
defer dialog.Close() // Close dialog for cleanup

select {
case <-dialog.Done():
    return
case <-time.After(10 *time.Second):
    dialog.Hangup(context.TODO())
}
Reading/Writing RTP/RTCP on dialog

After you Answer or Dial on phone, you receive dialog.

RTP

pkt, err := dialog.ReadRTP()

err := dialog.WriteRTP(pkt)

similar is for RTCP

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	// RTPPortStart and RTPPortEnd allows defining rtp port range for media
	RTPPortStart = 0
	RTPPortEnd   = 0

	RTPDebug  = false
	RTCPDebug = false
)
View Source
var (
	ErrRegisterFail        = fmt.Errorf("register failed")
	ErrRegisterUnathorized = fmt.Errorf("register unathorized")
)
View Source
var (
	// You can use this key with AnswerReadyCtxValue to get signal when
	// Answer is ready to receive traffic
	AnswerReadyCtxKey = "AnswerReadyCtxKey"
)
View Source
var (
	// Value must be zerolog.Logger
	ContextLoggerKey = "logger"
)

Functions

func CheckLazySipUri

func CheckLazySipUri(target string, destOverwrite string) string

We are lazy to write full sip uris

func DTMFDecode

func DTMFDecode(payload []byte, d *DTMFEvent) error

DecodeRTPPayload decodes an RTP payload into a DTMF event

func DTMFEncode

func DTMFEncode(d DTMFEvent) []byte

func FindFreeInterfaceHostPort

func FindFreeInterfaceHostPort(network string, targetAddr string) (ip net.IP, port int, err error)

func GetCurrentNTPTimestamp

func GetCurrentNTPTimestamp() uint64

func SDPGenerateForAudio

func SDPGenerateForAudio(originIP net.IP, connectionIP net.IP, rtpPort int, mode SDPMode, fmts sdp.Formats) []byte

func SendDummyRTP

func SendDummyRTP(rtpConn *net.UDPConn, raddr net.Addr)

Types

type AnswerOptions

type AnswerOptions struct {
	Ringtime   time.Duration
	SipHeaders []sip.Header

	// For authorizing INVITE unless RegisterAddr is defined
	Username string
	Password string
	Realm    string //default sipgo

	RegisterAddr string //If defined it will keep registration in background

	// For SDP codec manipulating
	Formats sdp.Formats

	// OnCall is just INVITE request handler that you can use to notify about incoming call
	// After this dialog should be created and you can watch your changes with dialog.State
	// -1 == Cancel
	// 0 == continue
	// >0 different response
	OnCall func(inviteRequest *sip.Request) int

	ByeChan chan struct{}

	// Default is 200 (answer a call)
	AnswerCode   sip.StatusCode
	AnswerReason string
}

type AnswerReadyCtxValue

type AnswerReadyCtxValue chan struct{}

type DTMFEvent

type DTMFEvent struct {
	Event      uint8
	EndOfEvent bool
	Volume     uint8
	Duration   uint16
}

DTMFEvent represents a DTMF event

func RTPDTMFEncode

func RTPDTMFEncode(char rune) []DTMFEvent

RTPDTMFEncode creates series of DTMF redudant events which should be encoded as payload It is currently only 8000 sample rate considered for telophone event

func (*DTMFEvent) String

func (ev *DTMFEvent) String() string

type DialOptions

type DialOptions struct {
	// Authentication via digest challenge
	Username string
	Password string

	// Custom headers passed on INVITE
	SipHeaders []sip.Header

	// SDP Formats to customize. NOTE: Only ulaw and alaw are fully supported
	Formats sdp.Formats

	// OnResponse is just callback called after INVITE is sent and all responses before final one
	// Useful for tracking call state
	OnResponse func(inviteResp *sip.Response)
}

type DialResponseError

type DialResponseError struct {
	InviteReq  *sip.Request
	InviteResp *sip.Response

	Msg string
}

func (DialResponseError) Error

func (e DialResponseError) Error() string

func (*DialResponseError) StatusCode

func (e *DialResponseError) StatusCode() sip.StatusCode

type DialogClientSession

type DialogClientSession struct {
	*MediaSession

	*sipgo.DialogClientSession
	// contains filtered or unexported fields
}

func (*DialogClientSession) Bye

func (*DialogClientSession) Close

func (d *DialogClientSession) Close() error

func (*DialogClientSession) DumpMedia

func (d *DialogClientSession) DumpMedia()

Deprecated. Use MediaStream

func (*DialogClientSession) Echo

func (d *DialogClientSession) Echo()

func (*DialogClientSession) Hangup

func (d *DialogClientSession) Hangup(ctx context.Context) error

Hangup is alias for Bye

func (*DialogClientSession) MediaStream

func (d *DialogClientSession) MediaStream(s MediaStreamer) error

type DialogServerSession

type DialogServerSession struct {
	*MediaSession

	*sipgo.DialogServerSession
	// contains filtered or unexported fields
}

func (*DialogServerSession) Bye

func (*DialogServerSession) Close

func (d *DialogServerSession) Close() error

func (*DialogServerSession) DumpMedia

func (d *DialogServerSession) DumpMedia()

Deprecated. Use MediaStream

func (*DialogServerSession) Echo

func (d *DialogServerSession) Echo()

func (*DialogServerSession) Hangup

func (d *DialogServerSession) Hangup(ctx context.Context) error

Hangup is alias for Bye

func (*DialogServerSession) MediaStream

func (d *DialogServerSession) MediaStream(s MediaStreamer) error

type ListenAddr

type ListenAddr struct {
	Network string
	Addr    string
	TLSConf *tls.Config
}

type Listener

type Listener struct {
	ListenAddr
	io.Closer
	Listen func() error
}

type MediaSession

type MediaSession struct {
	Raddr *net.UDPAddr
	Laddr *net.UDPAddr

	// Depending of negotiation this can change
	// Not thread safe
	Formats sdp.Formats
	// contains filtered or unexported fields
}

func NewMediaSession

func NewMediaSession(laddr *net.UDPAddr) (s *MediaSession, e error)

func (*MediaSession) Close

func (s *MediaSession) Close()

func (*MediaSession) LocalSDP

func (s *MediaSession) LocalSDP() []byte

func (*MediaSession) ReadRTCP

func (m *MediaSession) ReadRTCP() ([]rtcp.Packet, error)

func (*MediaSession) ReadRTCPRaw

func (m *MediaSession) ReadRTCPRaw(buf []byte) (int, error)

func (*MediaSession) ReadRTP

func (m *MediaSession) ReadRTP() (rtp.Packet, error)

func (*MediaSession) ReadRTPRaw

func (m *MediaSession) ReadRTPRaw(buf []byte) (int, error)

func (*MediaSession) ReadRTPWithDeadline

func (m *MediaSession) ReadRTPWithDeadline(t time.Time) (rtp.Packet, error)

func (*MediaSession) RemoteSDP

func (s *MediaSession) RemoteSDP(sdpReceived []byte) error

func (*MediaSession) SetLogger

func (s *MediaSession) SetLogger(log zerolog.Logger)

func (*MediaSession) UpdateDestinationSDP

func (s *MediaSession) UpdateDestinationSDP(sdpReceived []byte) error

func (*MediaSession) WriteRTCP

func (m *MediaSession) WriteRTCP(p rtcp.Packet) error

func (*MediaSession) WriteRTCPs

func (m *MediaSession) WriteRTCPs(pkts []rtcp.Packet) error

Use this to write Multi RTCP packets if they can fit in MTU=1500

func (*MediaSession) WriteRTP

func (m *MediaSession) WriteRTP(p *rtp.Packet) error

type MediaStreamFunc

type MediaStreamFunc func(s *MediaSession) error

func (MediaStreamFunc) MediaStream

func (f MediaStreamFunc) MediaStream(s *MediaSession) error

type MediaStreamer

type MediaStreamer interface {
	MediaStream(s *MediaSession) error
}

func MediaStreamLogger

func MediaStreamLogger(log zerolog.Logger) MediaStreamer

type Phone

type Phone struct {
	UA *sipgo.UserAgent
	// contains filtered or unexported fields
}

func NewPhone

func NewPhone(ua *sipgo.UserAgent, options ...PhoneOption) *Phone

func (*Phone) Answer

func (p *Phone) Answer(ansCtx context.Context, opts AnswerOptions) (*DialogServerSession, error)

Answer will answer call Closing ansCtx will close listeners or it will be closed on BYE TODO: reusing listener

func (*Phone) AnswerWithCode

func (p *Phone) AnswerWithCode(ansCtx context.Context, code sip.StatusCode, reason string, opts AnswerOptions) (*DialogServerSession, error)

AnswerWithCode will answer with custom code Dialog object is created but it is immediately closed Deprecated: Use Answer with options

func (*Phone) Close

func (p *Phone) Close()

func (*Phone) Dial

func (p *Phone) Dial(dialCtx context.Context, recipient sip.Uri, o DialOptions) (*DialogClientSession, error)

Dial creates dialog with recipient

return DialResponseError in case non 200 responses

func (*Phone) Register

func (p *Phone) Register(ctx context.Context, recipient sip.Uri, opts RegisterOptions) error

type PhoneOption

type PhoneOption func(p *Phone)

func WithPhoneListenAddr

func WithPhoneListenAddr(addr ListenAddr) PhoneOption

WithPhoneListenAddrs NOT TLS supported

func WithPhoneLogger

func WithPhoneLogger(l zerolog.Logger) PhoneOption

type RTPReader

type RTPReader struct {
	Sess *MediaSession

	OnRTP       func(pkt *rtp.Packet)
	LastPacket  rtp.Packet // After calling Read this will be stored before returning
	PayloadType uint8
	// contains filtered or unexported fields
}

RTP Writer packetize any payload before pushing to active media session

func NewRTPReader

func NewRTPReader(sess *MediaSession) *RTPReader

RTP reader consumes samples of audio from session TODO should it also decode ?

func (*RTPReader) Read

func (r *RTPReader) Read(b []byte) (int, error)

Read Implements io.Reader and extracts Payload from RTP packet has no input queue or sorting control of packets

type RTPWriter

type RTPWriter struct {
	Sess *MediaSession

	PayloadType uint8
	SSRC        uint32
	ClockRate   uint32

	// After each write this is set as packet.
	LastPacket rtp.Packet
	OnRTP      func(pkt *rtp.Packet)
	// contains filtered or unexported fields
}

RTP Writer packetize any payload before pushing to active media session

func NewRTPWriter

func NewRTPWriter(sess *MediaSession) *RTPWriter

RTP writer packetize payload in RTP packet before passing on media session Not having: - random SSRC - random Timestamp - allow different clock rate - CSRC contribution source - Silence detection and marker set - Padding and encryyption

func (*RTPWriter) Write

func (p *RTPWriter) Write(b []byte) (int, error)

Write implements io.Writer and does payload RTP packetization Media clock rate is determined For more control or dynamic payload rate check WriteSamples It is not thread safe and order of payload frames is required Has no capabilities (yet): - MTU UDP limit handling - Media clock rate of payload is consistent - Packet loss detection - RTCP generating

func (*RTPWriter) WriteSamples

func (p *RTPWriter) WriteSamples(b []byte, timestampRateIncrease uint32, marker bool, payloadType uint8) (int, error)

type RegisterOptions

type RegisterOptions struct {
	Username string
	Password string

	Expiry        int
	AllowHeaders  []string
	UnregisterAll bool
}

Register the phone by sip uri. Pass username and password via opts NOTE: this will block and keep periodic registration. Use context to cancel

type RegisterResponseError

type RegisterResponseError struct {
	RegisterReq *sip.Request
	RegisterRes *sip.Response

	Msg string
}

func (RegisterResponseError) Error

func (e RegisterResponseError) Error() string

func (*RegisterResponseError) StatusCode

func (e *RegisterResponseError) StatusCode() sip.StatusCode

type RegisterTransaction

type RegisterTransaction struct {
	Origin *sip.Request
	// contains filtered or unexported fields
}

func NewRegisterTransaction

func NewRegisterTransaction(log zerolog.Logger, client *sipgo.Client, recipient sip.Uri, contact sip.ContactHeader, opts RegisterOptions) *RegisterTransaction

func (*RegisterTransaction) QualifyLoop

func (t *RegisterTransaction) QualifyLoop(ctx context.Context) error

func (*RegisterTransaction) Register

func (p *RegisterTransaction) Register(ctx context.Context, recipient sip.Uri) error

func (*RegisterTransaction) Terminate

func (t *RegisterTransaction) Terminate() error

func (*RegisterTransaction) Unregister

func (t *RegisterTransaction) Unregister(ctx context.Context) error

type SDPMode

type SDPMode string
const (
	// https://datatracker.ietf.org/doc/html/rfc4566#section-6
	SDPModeRecvonly SDPMode = "recvonly"
	SDPModeSendrecv SDPMode = "sendrecv"
	SDPModeSendonly SDPMode = "sendonly"
)

Directories

Path Synopsis
echome
echouac command
echouas command

Jump to

Keyboard shortcuts

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