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 }