001/* 002 * Copyright 2024 Vonage 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package com.vonage.client.video; 017 018import com.fasterxml.jackson.annotation.JsonIgnore; 019import com.fasterxml.jackson.annotation.JsonProperty; 020import com.vonage.client.JsonableBaseObject; 021import java.net.URI; 022import java.util.HashMap; 023import java.util.Map; 024import java.util.Objects; 025 026/** 027 * Represents an outbound SIP dial request's properties. 028 */ 029public class SipDialRequest extends AbstractSessionTokenRequest { 030 @JsonProperty("sip") private Sip sip; 031 032 static class Sip extends JsonableBaseObject { 033 @JsonProperty("uri") String uri; 034 @JsonProperty("from") String from; 035 @JsonProperty("headers") Map<String, String> headers; 036 @JsonProperty("auth") Auth auth; 037 @JsonProperty("secure") Boolean secure; 038 @JsonProperty("video") Boolean video; 039 @JsonProperty("observeForceMute") Boolean observeForceMute; 040 041 static class Auth extends JsonableBaseObject { 042 @JsonProperty("username") String username; 043 @JsonProperty("password") String password; 044 } 045 } 046 047 /** 048 * For tests. 049 */ 050 SipDialRequest() {} 051 052 private SipDialRequest(Builder builder) { 053 super(builder); 054 sip = new Sip(); 055 sip.uri = Objects.requireNonNull(builder.uri, "SIP URI is required."); 056 sip.from = builder.from; 057 sip.secure = builder.secure; 058 sip.video = builder.video; 059 sip.observeForceMute = builder.observeForceMute; 060 if (!builder.headers.isEmpty()) { 061 sip.headers = builder.headers; 062 } 063 if (builder.username != null) { 064 sip.auth = new Sip.Auth(); 065 sip.auth.username = builder.username; 066 if (builder.password != null) { 067 sip.auth.password = builder.password; 068 } 069 } 070 else if (builder.password != null) { 071 throw new IllegalStateException("SIP Auth username is required if password is provided."); 072 } 073 } 074 075 @JsonIgnore 076 public String getUri() { 077 return sip.uri; 078 } 079 080 @JsonIgnore 081 public String getFrom() { 082 return sip.from; 083 } 084 085 @JsonIgnore 086 public Map<String, String> getHeaders() { 087 return sip.headers; 088 } 089 090 @JsonIgnore 091 public String getUsername() { 092 return sip.auth != null ? sip.auth.username : null; 093 } 094 095 @JsonIgnore 096 public String getPassword() { 097 return sip.auth != null ? sip.auth.password : null; 098 } 099 100 @JsonIgnore 101 public Boolean getSecure() { 102 return sip.secure; 103 } 104 105 @JsonIgnore 106 public Boolean getVideo() { 107 return sip.video; 108 } 109 110 @JsonIgnore 111 public Boolean getObserveForceMute() { 112 return sip.observeForceMute; 113 } 114 115 /** 116 * Instantiates a Builder, used to construct this object. 117 * 118 * @return A new {@linkplain Builder}. 119 */ 120 public static Builder builder() { 121 return new Builder(); 122 } 123 124 /** 125 * Used to create an SipDialRequest object. 126 * 127 * @see SipDialRequest 128 */ 129 public static class Builder extends AbstractSessionTokenRequest.Builder<SipDialRequest, Builder> { 130 private final Map<String, String> headers = new HashMap<>(); 131 private String from, uri, username, password; 132 private Boolean secure, video, observeForceMute; 133 134 /** 135 * (REQUIRED) 136 * The SIP URI to be used as destination of the SIP call initiated from Vonage to your SIP platform. 137 * 138 * @param uri The URI as an object. 139 * 140 * @param secure Whether the negotiation between Vonage and the SIP endpoint will be done securely. 141 * Note that this will only apply to the negotiation itself, and not to the transmission of audio. 142 * Setting this to true will append {@code transport=tls} to the URI. 143 * If you also want the audio transmission to be encrypted, set the {@link #secure(boolean)} 144 * property of this builder to true. 145 * 146 * @return This builder. 147 */ 148 public Builder uri(URI uri, boolean secure) { 149 this.uri = uri + (secure ? ";transport=tls" : ""); 150 return this; 151 } 152 153 /** 154 * (OPTIONAL) 155 * The number or string that will be sent to the final SIP number as the caller. It must be a string in 156 * the form of {@code from@example.com}, where from can be a string or a number. If from is set to a number 157 * (for example, "14155550101@example.com"), it will show up as the incoming number on PSTN phones. If from 158 * is undefined or set to a string (for example, "joe@example.com"), +00000000 will show up as the incoming 159 * number on PSTN phones. 160 * 161 * @param from The caller number or email as a string. 162 * 163 * @return This builder. 164 */ 165 public Builder from(String from) { 166 this.from = from; 167 return this; 168 } 169 170 /** 171 * (OPTIONAL, but REQUIRED if {@link #password(String)} is provided) 172 * The username to be used in the SIP INVITE request for HTTP digest authentication, 173 * if it is required by your SIP platform. 174 * 175 * @param username The username as a string. 176 * 177 * @return This builder. 178 * @see #password(String) 179 */ 180 public Builder username(String username) { 181 this.username = username; 182 return this; 183 } 184 185 /** 186 * (OPTIONAL) 187 * The password corresponding to the username for to be used in the SIP INVITE request. 188 * 189 * @param password The password as a string. 190 * 191 * @return This builder. 192 * @see #username(String) 193 */ 194 public Builder password(String password) { 195 this.password = password; 196 return this; 197 } 198 199 /** 200 * (OPTIONAL) 201 * Define a custom header to be added to the SIP INVITE request initiated from Vonage to your SIP platform. 202 * 203 * @param key The header key. 204 * @param value The header value. 205 * 206 * @return This builder. 207 * @see #addHeaders(Map) 208 */ 209 public Builder addHeader(String key, String value) { 210 headers.put(key, value); 211 return this; 212 } 213 214 /** 215 * (OPTIONAL) 216 * Define custom headers (i.e. those starting with "X-") to be added to the SIP INVITE request 217 * initiated from Vonage to your SIP platform. 218 * 219 * @param headers Custom header key-value pairs as strings. 220 * 221 * @return This builder. 222 * @see #addHeader(String, String) 223 */ 224 public Builder addHeaders(Map<String, String> headers) { 225 this.headers.putAll(headers); 226 return this; 227 } 228 229 /** 230 * (OPTIONAL) 231 * Flag that indicates whether the media must be transmitted encrypted (true) or not (false, the default). 232 * 233 * @param secure Whether media should be transmitted securely. 234 * 235 * @return This builder. 236 */ 237 public Builder secure(boolean secure) { 238 this.secure = secure; 239 return this; 240 } 241 242 /** 243 * (OPTIONAL) 244 * Flag that indicates whether the SIP call will include video (true) or not (false, the default). 245 * With video included, the SIP client's video is included in the video stream that is sent to the 246 * Vonage video session. The SIP client will receive a single composed video of the published streams 247 * in the Vonage video session. 248 * 249 * @param video Whether to include video in the SIP call. 250 * 251 * @return This builder. 252 */ 253 public Builder video(boolean video) { 254 this.video = video; 255 return this; 256 } 257 258 /** 259 * (OPTIONAL) 260 * flag that indicates whether the SIP end point observes force mute moderation (true) or not (false, the 261 * default). Also, with observeForceMute set to true, the caller can press "*6" to unmute and mute the 262 * published audio. For the "*6" mute toggle to work, the SIP caller must negotiate RFC2833 DTMFs 263 * (RFC2833/RFC4733 digits). The mute toggle is not supported with SIP INFO or in-band DTMFs. A message 264 * (in English) is played to the caller when the caller mutes and unmutes, or when the SIP client is muted 265 * through a force mute action. 266 * 267 * @param observeForceMute Whether to observe forceMute moderation. 268 * 269 * @return This builder. 270 */ 271 public Builder observeForceMute(boolean observeForceMute) { 272 this.observeForceMute = observeForceMute; 273 return this; 274 } 275 276 /** 277 * Builds the {@linkplain SipDialRequest} object with this builder's settings. 278 * 279 * @return A new {@link SipDialRequest} instance. 280 */ 281 @Override 282 public SipDialRequest build() { 283 return new SipDialRequest(this); 284 } 285 } 286}