diago

package module
v0.13.0 Latest Latest
Warning

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

Go to latest
Published: Jan 20, 2025 License: MPL-2.0 Imports: 27 Imported by: 1

README

DIAGO

Go Report Card Coverage GitHub go.mod Go version

Short of dialog + GO.
Library for building VOIP solutions in GO!

Built on top of optimized SIPgo library!
In short it allows developing fast and easy testable VOIP apps to handle calls, registrations and more...

Diago is mainly project driven lib, so lot of API design will/should be challenged with real working apps needs

For more information and documentation visit the website

Quick links:

If you find this project useful and you want to support/sponzor or need help with your projects, you can contact me more on mail.

Follow me on X/Twitter for regular updates

Contributions

Please open first issues instead PRs. Library is under development and could not have latest code pushed.

Usage

Checkout more on Getting started, but for quick view here is echotest (hello world) example.

ua, _ := sipgo.NewUA()
dg := diago.NewDiago(ua)

dg.Serve(ctx, func(inDialog *diago.DialogServerSession) {
	inDialog.Progress() // Progress -> 100 Trying
	inDialog.Answer(); // Answer

	// Make sure file below exists in work dir
	playfile, err := os.Open("demo-echotest.wav")
	if err != nil {
		fmt.Println("Failed to open file", err)
		return
	}
	defer playfile.Close()

	// Create playback and play file.
	pb, _ := inDialog.PlaybackCreate()
	if err := pb.Play(playfile, "audio/wav"); err != nil {
		fmt.Println("Playing failed", err)
	}
}

See more examples in this repo

Tracing SIP, RTP

While openning issue, consider having some traces enabled.

sip.SIPDebug = true // Enables SIP tracing
media.RTCPDebug = true // Enables RTCP tracing
media.RTPDebug = true // Enables RTP tracing. NOTE: It will dump every RTP Packet

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrDigestAuthNoChallenge = errors.New("no challenge")
	ErrDigestAuthBadCreds    = errors.New("bad credentials")
)
View Source
var (
	HTTPDebug = os.Getenv("HTTP_DEBUG") == "true"
)
View Source
var (
	PlaybackBufferSize = 3840 // For now largest we support. 48000 sample rate with 2 channels
)

Functions

func NewConnRecorder added in v0.3.0

func NewConnRecorder() *connRecorder

Types

type AnswerOptions added in v0.4.0

type AnswerOptions struct {
	OnRTPSession func(rtpSess *media.RTPSession)
}

type AudioPlayback

type AudioPlayback struct {

	// Read only values
	// This will influence playout sampling buffer
	BitDepth    int
	NumChannels int
	// contains filtered or unexported fields
}

func NewAudioPlayback

func NewAudioPlayback(writer io.Writer, codec media.Codec) AudioPlayback

NewAudioPlayback creates a playback where writer is encoder/streamer to media codec Use dialog.PlaybackCreate() instead creating manually playback

func (*AudioPlayback) Play

func (p *AudioPlayback) Play(reader io.Reader, mimeType string) (int64, error)

Play is generic approach to play supported audio contents Empty mimeType will stream reader as buffer. Make sure that bitdepth and numchannels is set correctly

func (*AudioPlayback) PlayFile

func (p *AudioPlayback) PlayFile(filename string) (int64, error)

PlayFile will play file and close file when finished playing If you need to play same file multiple times, that use generic Play function

func (*AudioPlayback) PlayURL

func (p *AudioPlayback) PlayURL(urlStr string) (int64, error)

type AudioPlaybackControl

type AudioPlaybackControl struct {
	AudioPlayback
	// contains filtered or unexported fields
}

func (*AudioPlaybackControl) Mute

func (p *AudioPlaybackControl) Mute(mute bool)

func (*AudioPlaybackControl) Stop

func (p *AudioPlaybackControl) Stop()

type AudioReaderOption

type AudioReaderOption func(d *DialogMedia) error

func WithAudioReaderMediaProps

func WithAudioReaderMediaProps(p *MediaProps) AudioReaderOption

func WithAudioReaderRTPStats added in v0.10.0

func WithAudioReaderRTPStats(hook media.OnRTPReadStats) AudioReaderOption

WithAudioReaderRTPStats creates RTP Statistics interceptor on audio reader

type AudioWriterOption

type AudioWriterOption func(d *DialogMedia) error

func WithAudioWriterMediaProps

func WithAudioWriterMediaProps(p *MediaProps) AudioWriterOption

func WithAudioWriterRTPStats added in v0.10.0

func WithAudioWriterRTPStats(hook media.OnRTPWriteStats) AudioWriterOption

WithAudioReaderRTPStats creates RTP Statistics interceptor on audio reader

type Bridge

type Bridge struct {
	// Originator is dialog session that created bridge
	Originator DialogSession
	// contains filtered or unexported fields
}

func NewBridge

func NewBridge() Bridge

func (*Bridge) AddDialogSession

func (b *Bridge) AddDialogSession(d DialogSession) error

func (*Bridge) GetDialogs

func (b *Bridge) GetDialogs() []DialogSession

type Bridger

type Bridger interface {
	AddDialogSession(d DialogSession) error
}

type DTMFReader

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

func (*DTMFReader) Listen

func (d *DTMFReader) Listen(onDTMF func(dtmf rune) error, dur time.Duration) error

func (*DTMFReader) OnDTMF added in v0.8.0

func (d *DTMFReader) OnDTMF(onDTMF func(dtmf rune) error)

OnDTMF must be called before audio reading

func (*DTMFReader) Read added in v0.8.0

func (d *DTMFReader) Read(buf []byte) (n int, err error)

Read exposes io.Reader that can be used as AudioReader

type DTMFWriter

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

func (*DTMFWriter) AudioWriter added in v0.8.0

func (w *DTMFWriter) AudioWriter() *media.RTPDtmfWriter

AudioReader exposes DTMF audio writer. You should use this for parallel audio processing

func (*DTMFWriter) Write added in v0.8.0

func (w *DTMFWriter) Write(buf []byte) (n int, err error)

Write exposes as io.Writer that can be used as AudioWriter

func (*DTMFWriter) WriteDTMF

func (w *DTMFWriter) WriteDTMF(dtmf rune) error

type Diago

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

func NewDiago

func NewDiago(ua *sipgo.UserAgent, opts ...DiagoOption) *Diago

NewDiago construct b2b user agent that will act as server and client

func (*Diago) HandleFunc added in v0.5.0

func (dg *Diago) HandleFunc(f ServeDialogFunc)

HandleFunc registers you handler function for dialog. Must be called before serving request

func (*Diago) Invite

func (dg *Diago) Invite(ctx context.Context, recipient sip.Uri, opts InviteOptions) (d *DialogClientSession, err error)

Invite makes outgoing call leg and waits for answer. If you want to bridge call then use helper InviteBridge

func (*Diago) InviteBridge

func (dg *Diago) InviteBridge(ctx context.Context, recipient sip.Uri, bridge *Bridge, opts InviteOptions) (d *DialogClientSession, err error)

InviteBridge makes outgoing call leg and does bridging. Outgoing session will be added into bridge on answer If bridge has Originator (first participant) it will be used for creating outgoing call leg as in B2BUA When bridge is provided then this call will be bridged with any participant already present in bridge

func (*Diago) Register added in v0.2.0

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

Register will create register transaction and keep registration ongoing until error is hit. For more granular control over registraions user RegisterTransaction

func (*Diago) RegisterTransaction added in v0.3.0

func (dg *Diago) RegisterTransaction(ctx context.Context, recipient sip.Uri, opts RegisterOptions) (*RegisterTransaction, error)

Register transaction creates register transaction object that can be used for Register Unregister requests

func (*Diago) Serve

func (dg *Diago) Serve(ctx context.Context, f ServeDialogFunc) error

func (*Diago) ServeBackground

func (dg *Diago) ServeBackground(ctx context.Context, f ServeDialogFunc) error

Serve starts serving in background but waits server listener started before returning

type DiagoOption

type DiagoOption func(dg *Diago)

func WithAuth

func WithAuth(auth sipgo.DigestAuth) DiagoOption

func WithClient added in v0.3.0

func WithClient(client *sipgo.Client) DiagoOption

WithClient allows providing custom client handle. Consider still it needs to use same UA as diago

func WithLogger added in v0.8.0

func WithLogger(l zerolog.Logger) DiagoOption

func WithMediaConfig

func WithMediaConfig(conf MediaConfig) DiagoOption

func WithServer

func WithServer(srv *sipgo.Server) DiagoOption

WithServer allows providing custom server handle. Consider still it needs to use same UA as diago

func WithTransport

func WithTransport(t Transport) DiagoOption

type DialogCache

type DialogCache[T DialogSession] interface {
	DialogStore(ctx context.Context, id string, v T) error
	DialogLoad(ctx context.Context, id string) (T, error)
	DialogDelete(ctx context.Context, id string) error
	DialogRange(ctx context.Context, f func(id string, d T) bool) error
}
var (
	// TODO, replace with typed versions
	DialogsClientCache DialogCache[*DialogClientSession] = &dialogCacheMap[*DialogClientSession]{sync.Map{}}
	DialogsServerCache DialogCache[*DialogServerSession] = &dialogCacheMap[*DialogServerSession]{sync.Map{}}
)

type DialogClientSession

type DialogClientSession struct {
	*sipgo.DialogClientSession

	DialogMedia
	// contains filtered or unexported fields
}

DialogClientSession represents outbound channel

func MatchDialogClient

func MatchDialogClient(req *sip.Request) (*DialogClientSession, error)

func (*DialogClientSession) Close

func (d *DialogClientSession) Close()

func (*DialogClientSession) DialogSIP

func (d *DialogClientSession) DialogSIP() *sipgo.Dialog

func (*DialogClientSession) FromUser

func (d *DialogClientSession) FromUser() string

func (*DialogClientSession) Hangup

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

func (*DialogClientSession) Id

func (d *DialogClientSession) Id() string

func (*DialogClientSession) ReInvite

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

ReInvite sends new invite based on current media session

func (*DialogClientSession) RemoteContact

func (d *DialogClientSession) RemoteContact() *sip.ContactHeader

func (*DialogClientSession) ToUser

func (d *DialogClientSession) ToUser() string

type DialogData

type DialogData struct {
	InviteRequest sip.Request
	State         sip.DialogState
}

type DialogMedia

type DialogMedia struct {

	// Packet reader is default reader for RTP audio stream
	// Use always AudioReader to get current Audio reader
	// Use this only as read only
	// It MUST be always created on Media Session Init
	// Only safe to use after dialog Answered (Completed state)
	RTPPacketReader *media.RTPPacketReader

	// Packet writer is default writer for RTP audio stream
	// Use always AudioWriter to get current Audio reader
	// Use this only as read only
	RTPPacketWriter *media.RTPPacketWriter
	// contains filtered or unexported fields
}

DialogMedia is common struct for server and client session and it shares same functionality which is mostly arround media

func (*DialogMedia) AudioReader

func (d *DialogMedia) AudioReader(opts ...AudioReaderOption) (io.Reader, error)

AudioReader gets current audio reader. It MUST be called after Answer. Use AuidioListen for optimized reading. Reading buffer should be equal or bigger of media.RTPBufSize

func (*DialogMedia) AudioReaderDTMF

func (m *DialogMedia) AudioReaderDTMF() *DTMFReader

AudioReaderDTMF is DTMF over RTP. It reads audio and provides hook for dtmf while listening for audio Use Listen or OnDTMF after this call

func (*DialogMedia) AudioWriter

func (d *DialogMedia) AudioWriter(opts ...AudioWriterOption) (io.Writer, error)

func (*DialogMedia) AudioWriterDTMF

func (m *DialogMedia) AudioWriterDTMF() *DTMFWriter

func (*DialogMedia) Close

func (d *DialogMedia) Close()

func (*DialogMedia) Echo added in v0.13.0

func (d *DialogMedia) Echo() error

Echo does audio echo for you

func (*DialogMedia) InitMediaSession

func (d *DialogMedia) InitMediaSession(m *media.MediaSession, r *media.RTPPacketReader, w *media.RTPPacketWriter)

func (*DialogMedia) Listen

func (d *DialogMedia) Listen() error

func (*DialogMedia) ListenContext

func (d *DialogMedia) ListenContext(ctx context.Context) error

func (*DialogMedia) ListenUntil

func (d *DialogMedia) ListenUntil(dur time.Duration) error

func (*DialogMedia) Media

func (d *DialogMedia) Media() *DialogMedia

func (*DialogMedia) OnClose

func (d *DialogMedia) OnClose(f func())

func (*DialogMedia) PlaybackControlCreate

func (d *DialogMedia) PlaybackControlCreate() (AudioPlaybackControl, error)

PlaybackControlCreate creates playback for audio with controls like mute unmute

func (*DialogMedia) PlaybackCreate

func (d *DialogMedia) PlaybackCreate() (AudioPlayback, error)

PlaybackCreate creates playback for audio

func (*DialogMedia) RTPSession added in v0.8.0

func (d *DialogMedia) RTPSession() *media.RTPSession

RTPSession returns underhood rtp session NOTE: this can be nil

func (*DialogMedia) SetAudioReader

func (d *DialogMedia) SetAudioReader(r io.Reader)

SetAudioReader adds/changes audio reader. Use this when you want to have interceptors of your audio

func (*DialogMedia) SetAudioWriter

func (d *DialogMedia) SetAudioWriter(r io.Writer)

SetAudioWriter adds/changes audio reader. Use this when you want to have interceptors of your audio

func (*DialogMedia) StartRTP added in v0.13.0

func (d *DialogMedia) StartRTP(rw int8, dur time.Duration)

func (*DialogMedia) StopRTP added in v0.13.0

func (d *DialogMedia) StopRTP(rw int8, dur time.Duration)

type DialogServerSession

type DialogServerSession struct {
	*sipgo.DialogServerSession

	// MediaSession *media.MediaSession
	DialogMedia
	// contains filtered or unexported fields
}

DialogServerSession represents inbound channel

func MatchDialogServer

func MatchDialogServer(req *sip.Request) (*DialogServerSession, error)

func (*DialogServerSession) Answer

func (d *DialogServerSession) Answer() error

Answer creates media session and answers NOTE: Not final API

func (*DialogServerSession) AnswerLate added in v0.11.0

func (d *DialogServerSession) AnswerLate() error

AnswerLate does answer with Late offer.

func (*DialogServerSession) AnswerOptions added in v0.4.0

func (d *DialogServerSession) AnswerOptions(opt AnswerOptions) error

Experimental

NOTE: API may change

func (*DialogServerSession) Close

func (d *DialogServerSession) Close()

func (*DialogServerSession) DialogSIP

func (d *DialogServerSession) DialogSIP() *sipgo.Dialog

func (*DialogServerSession) FromUser

func (d *DialogServerSession) FromUser() string

func (*DialogServerSession) Hangup

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

func (*DialogServerSession) Id

func (d *DialogServerSession) Id() string

func (*DialogServerSession) Progress

func (d *DialogServerSession) Progress() error

func (*DialogServerSession) ReInvite

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

func (*DialogServerSession) ReadAck added in v0.11.0

func (*DialogServerSession) Refer added in v0.3.0

func (d *DialogServerSession) Refer(ctx context.Context, referTo sip.Uri) error

Refer tries todo refer (blind transfer) on call

func (*DialogServerSession) RemoteContact

func (d *DialogServerSession) RemoteContact() *sip.ContactHeader

func (*DialogServerSession) Respond

func (d *DialogServerSession) Respond(statusCode sip.StatusCode, reason string, body []byte, headers ...sip.Header) error

func (*DialogServerSession) RespondSDP

func (d *DialogServerSession) RespondSDP(body []byte) error

func (*DialogServerSession) Ringing

func (d *DialogServerSession) Ringing() error

func (*DialogServerSession) ToUser

func (d *DialogServerSession) ToUser() string

User that was dialed

func (*DialogServerSession) Transport

func (d *DialogServerSession) Transport() string

type DialogSession

type DialogSession interface {
	Id() string
	Context() context.Context
	Hangup(ctx context.Context) error
	Media() *DialogMedia
	DialogSIP() *sipgo.Dialog
}

type DigestAuth added in v0.9.0

type DigestAuth struct {
	Username string
	Password string
	Realm    string
	Expire   time.Duration
}

type DigestAuthServer added in v0.9.0

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

func NewDigestServer added in v0.9.0

func NewDigestServer() *DigestAuthServer

func (*DigestAuthServer) AuthorizeDialog added in v0.9.0

func (s *DigestAuthServer) AuthorizeDialog(d *DialogServerSession, auth DigestAuth) error

func (*DigestAuthServer) AuthorizeRequest added in v0.9.0

func (s *DigestAuthServer) AuthorizeRequest(req *sip.Request, auth DigestAuth) (res *sip.Response, err error)

AuthorizeRequest authorizes request. Returns SIP response that can be passed with error

type InviteOptions

type InviteOptions struct {
	OnResponse   func(res *sip.Response) error
	OnRTPSession func(rtpSess *media.RTPSession)
	// For digest authentication
	Username string
	Password string

	// Custom headers to pass. DO NOT SET THIS to nil
	Headers     []sip.Header
	TransportID string
}

func (*InviteOptions) SetAnonymousCaller added in v0.5.0

func (o *InviteOptions) SetAnonymousCaller()

Sets from user to RFC anonymous

func (*InviteOptions) SetCaller added in v0.5.0

func (o *InviteOptions) SetCaller(displayName string, callerID string)

type MediaConfig

type MediaConfig struct {
	Formats sdp.Formats
	// contains filtered or unexported fields
}

type MediaProps

type MediaProps struct {
	Codec media.Codec
	Laddr string
	Raddr string
}

type RegisterOptions added in v0.2.0

type RegisterOptions struct {
	// Digest auth
	Username  string
	Password  string
	ProxyHost string

	// Expiry is for Expire header
	Expiry time.Duration
	// Retry interval is interval before next Register is sent
	RetryInterval time.Duration
	AllowHeaders  []string
}

type RegisterResponseError added in v0.2.0

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

	Msg string
}

func (RegisterResponseError) Error added in v0.2.0

func (e RegisterResponseError) Error() string

func (*RegisterResponseError) StatusCode added in v0.2.0

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

type RegisterTransaction added in v0.2.0

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

func (*RegisterTransaction) QualifyLoop added in v0.2.0

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

func (*RegisterTransaction) Register added in v0.2.0

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

func (*RegisterTransaction) Unregister added in v0.2.0

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

type ServeDialogFunc

type ServeDialogFunc func(d *DialogServerSession)

type Transport

type Transport struct {
	ID string

	// Transport must be udp,tcp or ws.
	Transport string
	BindHost  string
	BindPort  int

	ExternalHost string // SIP signaling and media external addr
	ExternalPort int

	// MediaExternalIP changes SDP IP, by default it tries to use external host if it is IP defined
	MediaExternalIP net.IP

	// In case TLS protocol
	TLSConf *tls.Config

	RewriteContact bool
	// contains filtered or unexported fields
}

Directories

Path Synopsis
examples
sdp

Jump to

Keyboard shortcuts

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