github.com/livekit/protocol@v1.39.3/rpc/sip.go (about)

     1  package rpc
     2  
     3  import (
     4  	"errors"
     5  	"maps"
     6  	"math/rand/v2"
     7  	"net"
     8  	"strings"
     9  
    10  	"github.com/livekit/protocol/livekit"
    11  )
    12  
    13  func (p *GetSIPTrunkAuthenticationRequest) SIPCall() *SIPCall {
    14  	if p == nil {
    15  		return nil
    16  	}
    17  	if p.Call != nil {
    18  		return p.Call
    19  	}
    20  	ip := p.SrcAddress
    21  	if addr, _, err := net.SplitHostPort(ip); err == nil {
    22  		ip = addr
    23  	}
    24  	c := &SIPCall{
    25  		LkCallId: p.SipCallId,
    26  		SourceIp: ip,
    27  		From: &livekit.SIPUri{
    28  			User: p.From,
    29  			Host: p.FromHost,
    30  		},
    31  		To: &livekit.SIPUri{
    32  			User: p.To,
    33  			Host: p.ToHost,
    34  		},
    35  	}
    36  	c.Address = c.To
    37  	return c
    38  }
    39  
    40  func (p *EvaluateSIPDispatchRulesRequest) SIPCall() *SIPCall {
    41  	if p == nil {
    42  		return nil
    43  	}
    44  	if p.Call != nil {
    45  		return p.Call
    46  	}
    47  	ip := p.SrcAddress
    48  	if addr, _, err := net.SplitHostPort(ip); err == nil {
    49  		ip = addr
    50  	}
    51  	c := &SIPCall{
    52  		LkCallId: p.SipCallId,
    53  		SourceIp: ip,
    54  		From: &livekit.SIPUri{
    55  			User: p.CallingNumber,
    56  			Host: p.CallingHost,
    57  		},
    58  		To: &livekit.SIPUri{
    59  			User: p.CalledNumber,
    60  			Host: p.CalledHost,
    61  		},
    62  	}
    63  	c.Address = c.To
    64  	return c
    65  }
    66  
    67  // NewCreateSIPParticipantRequest fills InternalCreateSIPParticipantRequest from
    68  // livekit.CreateSIPParticipantRequest and livekit.SIPTrunkInfo.
    69  func NewCreateSIPParticipantRequest(
    70  	projectID, callID, ownHostname, wsUrl, token string,
    71  	req *livekit.CreateSIPParticipantRequest,
    72  	trunk *livekit.SIPOutboundTrunkInfo,
    73  ) (*InternalCreateSIPParticipantRequest, error) {
    74  	var (
    75  		hostname           string
    76  		enc                livekit.SIPMediaEncryption
    77  		headers            map[string]string
    78  		includeHeaders     livekit.SIPHeaderOptions
    79  		transport          livekit.SIPTransport
    80  		destinationCountry string
    81  		authUser           string
    82  		authPass           string
    83  		hdrToAttr          map[string]string
    84  		attrToHdr          map[string]string
    85  	)
    86  	if trunk != nil {
    87  		hostname = trunk.Address
    88  		enc = trunk.MediaEncryption
    89  		headers = trunk.Headers
    90  		includeHeaders = trunk.IncludeHeaders
    91  		transport = trunk.Transport
    92  		destinationCountry = trunk.DestinationCountry
    93  		authUser = trunk.AuthUsername
    94  		authPass = trunk.AuthPassword
    95  		hdrToAttr = trunk.HeadersToAttributes
    96  		attrToHdr = trunk.AttributesToHeaders
    97  	} else if t := req.Trunk; t != nil {
    98  		hostname = t.Hostname
    99  		transport = t.Transport
   100  		destinationCountry = t.DestinationCountry
   101  		authUser = t.AuthUsername
   102  		authPass = t.AuthPassword
   103  		hdrToAttr = t.HeadersToAttributes
   104  		attrToHdr = t.AttributesToHeaders
   105  	}
   106  
   107  	outboundNumber := req.SipNumber
   108  	if outboundNumber == "" {
   109  		if trunk == nil || len(trunk.Numbers) == 0 {
   110  			return nil, errors.New("no numbers on outbound trunk")
   111  		}
   112  		outboundNumber = trunk.Numbers[rand.IntN(len(trunk.Numbers))]
   113  	}
   114  	// A sanity check for the number format for well-known providers.
   115  	switch {
   116  	case strings.HasSuffix(hostname, "twilio.com"):
   117  		// Twilio requires leading '+'.
   118  		if !strings.HasPrefix(outboundNumber, "+") {
   119  			outboundNumber = "+" + outboundNumber
   120  		}
   121  	}
   122  	attrs := maps.Clone(req.ParticipantAttributes)
   123  	if attrs == nil {
   124  		attrs = make(map[string]string)
   125  	}
   126  	attrs[livekit.AttrSIPCallID] = callID
   127  	trunkID := req.SipTrunkId
   128  	if trunkID == "" && trunk != nil {
   129  		trunkID = trunk.SipTrunkId
   130  	}
   131  	attrs[livekit.AttrSIPTrunkID] = trunkID
   132  	if !req.HidePhoneNumber {
   133  		attrs[livekit.AttrSIPPhoneNumber] = req.SipCallTo
   134  		attrs[livekit.AttrSIPHostName] = hostname
   135  		attrs[livekit.AttrSIPTrunkNumber] = outboundNumber
   136  	}
   137  
   138  	var features []livekit.SIPFeature
   139  	if req.KrispEnabled {
   140  		features = append(features, livekit.SIPFeature_KRISP_ENABLED)
   141  	}
   142  	if req.MediaEncryption != 0 {
   143  		enc = req.MediaEncryption
   144  	}
   145  
   146  	if len(req.Headers) != 0 {
   147  		headers = maps.Clone(headers)
   148  		if headers == nil {
   149  			headers = make(map[string]string)
   150  		}
   151  		for k, v := range req.Headers {
   152  			headers[k] = v
   153  		}
   154  	}
   155  	if req.IncludeHeaders != 0 {
   156  		includeHeaders = req.IncludeHeaders
   157  	}
   158  	participantIdentity := req.ParticipantIdentity
   159  	if participantIdentity == "" {
   160  		participantIdentity = "sip_" + req.SipCallTo
   161  	}
   162  
   163  	return &InternalCreateSIPParticipantRequest{
   164  		ProjectId:             projectID,
   165  		SipCallId:             callID,
   166  		SipTrunkId:            trunkID,
   167  		DestinationCountry:    destinationCountry,
   168  		Address:               hostname,
   169  		Hostname:              ownHostname,
   170  		Transport:             transport,
   171  		Number:                outboundNumber,
   172  		Username:              authUser,
   173  		Password:              authPass,
   174  		CallTo:                req.SipCallTo,
   175  		WsUrl:                 wsUrl,
   176  		Token:                 token,
   177  		RoomName:              req.RoomName,
   178  		ParticipantIdentity:   participantIdentity,
   179  		ParticipantName:       req.ParticipantName,
   180  		ParticipantMetadata:   req.ParticipantMetadata,
   181  		ParticipantAttributes: attrs,
   182  		Dtmf:                  req.Dtmf,
   183  		PlayDialtone:          req.PlayRingtone || req.PlayDialtone,
   184  		Headers:               headers,
   185  		HeadersToAttributes:   hdrToAttr,
   186  		AttributesToHeaders:   attrToHdr,
   187  		IncludeHeaders:        includeHeaders,
   188  		EnabledFeatures:       features,
   189  		RingingTimeout:        req.RingingTimeout,
   190  		MaxCallDuration:       req.MaxCallDuration,
   191  		MediaEncryption:       enc,
   192  		WaitUntilAnswered:     req.WaitUntilAnswered,
   193  	}, nil
   194  }
   195  
   196  // NewTransferSIPParticipantRequest fills InternalTransferSIPParticipantRequest from
   197  // livekit.TransferSIPParticipantRequest.
   198  func NewTransferSIPParticipantRequest(
   199  	callID string,
   200  	req *livekit.TransferSIPParticipantRequest,
   201  ) (*InternalTransferSIPParticipantRequest, error) {
   202  	return &InternalTransferSIPParticipantRequest{
   203  		SipCallId:      callID,
   204  		TransferTo:     req.TransferTo,
   205  		PlayDialtone:   req.PlayDialtone,
   206  		Headers:        req.Headers,
   207  		RingingTimeout: req.RingingTimeout,
   208  	}, nil
   209  }