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.Jsonable; 021import java.net.URI; 022import java.time.Duration; 023 024/** 025* Represents an archive of a video session. 026*/ 027public class Archive extends StreamComposition { 028 private Long size; 029 @JsonProperty("duration") private Integer duration; 030 private String name, reason, multiArchiveTag; 031 private URI url; 032 private ArchiveStatus status; 033 private OutputMode outputMode; 034 035 protected Archive() { 036 } 037 038 protected Archive(Builder builder) { 039 if ((sessionId = builder.sessionId) == null || sessionId.isEmpty()) { 040 throw new IllegalArgumentException("Session ID is required."); 041 } 042 layout = builder.layout; 043 if ((outputMode = builder.outputMode) != OutputMode.COMPOSED && layout != null) { 044 throw new IllegalStateException("Layout can only be applied to composed archives."); 045 } 046 name = builder.name; 047 multiArchiveTag = builder.multiArchiveTag; 048 hasAudio = builder.hasAudio; 049 hasVideo = builder.hasVideo; 050 resolution = builder.resolution; 051 streamMode = builder.streamMode; 052 if ((maxBitrate = builder.maxBitrate) != null && (maxBitrate < 100000 || maxBitrate > 6000000)) { 053 throw new IllegalArgumentException("Maximum bitrate must be between 100000 and 6000000."); 054 } 055 } 056 057 /** 058 * The duration of the recording, in seconds. 059 * 060 * @return The duration as an integer. 061 */ 062 @JsonProperty("duration") 063 public Integer getDurationSeconds() { 064 return duration; 065 } 066 067 /** 068 * The duration of the recording (precision in seconds). 069 * 070 * @return The duration. 071 */ 072 @JsonIgnore 073 public Duration getDuration() { 074 return duration != null ? Duration.ofSeconds(duration) : null; 075 } 076 077 /** 078 * The name of the archive. 079 * 080 * @return The archive name. 081 */ 082 @JsonProperty("name") 083 public String getName() { 084 return name; 085 } 086 087 /** 088 * For archives with {@link ArchiveStatus#STOPPED} or {@link ArchiveStatus#FAILED}, this string 089 * describes the reason the archive stopped (such as "maximum duration exceeded") or failed. 090 * 091 * @return The failure reason text, or {@code null} if not applicable. 092 */ 093 @JsonProperty("reason") 094 public String getReason() { 095 return reason; 096 } 097 098 /** 099 * The size of the MP4 file. For archives that have not been generated, this value is set to 0. 100 * 101 * @return The size as a long, or {@code null} if unset. 102 */ 103 @JsonProperty("size") 104 public Long getSize() { 105 return size; 106 } 107 108 /** 109 * The status of the archive, as defined by the {@link ArchiveStatus} enum. 110 * 111 * @return The status. 112 */ 113 @JsonProperty("status") 114 public ArchiveStatus getStatus() { 115 return status; 116 } 117 118 /** 119 * The download URL of the available MP4 file. This is only set for an archive with the status 120 * set to {@link ArchiveStatus#AVAILABLE}; for other archives (including those with the status of 121 * {@link ArchiveStatus#UPLOADED}) this method returns null. The download URL is obfuscated, and the file 122 * is only available from the URL for 10 minutes. To generate a new URL, call the 123 * {@link VideoClient#listArchives()} or {@link VideoClient#getArchive(String)} method. 124 * 125 * @return The download URL. 126 */ 127 @JsonProperty("url") 128 public URI getUrl() { 129 return url; 130 } 131 132 /** 133 * The output mode to be generated for this archive: {@code composed} or {@code individual}. 134 * 135 * @return The {@linkplain OutputMode}. 136 */ 137 @JsonProperty("outputMode") 138 public OutputMode getOutputMode() { 139 return outputMode; 140 } 141 142 /** 143 * Returns the multiArchiveTag if set for the Archive. 144 * 145 * @return The multiArchiveTag, or {@code null} if not applicable. 146 */ 147 @JsonProperty("multiArchiveTag") 148 public String getMultiArchiveTag() { 149 return multiArchiveTag; 150 } 151 152 /** 153 * Creates an instance of this class from a JSON payload. 154 * 155 * @param json The JSON string to parse. 156 * @return An instance of this class with the fields populated, if present. 157 */ 158 public static Archive fromJson(String json) { 159 return Jsonable.fromJson(json); 160 } 161 162 163 /** 164 * Instantiates a Builder, used to construct this object. 165 * 166 * @param sessionId The ID of the Vonage Video session you are working with. 167 * 168 * @return A new {@linkplain Archive.Builder}. 169 */ 170 public static Builder builder(String sessionId) { 171 return new Builder(sessionId); 172 } 173 174 /** 175 * Used to construct an Archive object. 176 * 177 * @see Archive 178 */ 179 public static class Builder extends StreamComposition.Builder { 180 private String name, multiArchiveTag; 181 private OutputMode outputMode; 182 183 Builder(String sessionId) { 184 this.sessionId = sessionId; 185 } 186 187 /** 188 * Sets a name for the archive. 189 * 190 * @param name The name of the archive. You can use this name to identify the archive. It is a property 191 * of the Archive object, and it is a property of archive-related events in the SDK. 192 * 193 * @return This Builder with the name setting. 194 */ 195 public Builder name(String name) { 196 this.name = name; 197 return this; 198 } 199 200 /** 201 * Sets the resolution of the archive. 202 * 203 * @param resolution The resolution of the archive, either "640x480" (SD, the default) or 204 * "1280x720" (HD). This property only applies to composed archives. If you set this 205 * and set the outputMode property to "individual", the call in the API method results in 206 * an error. 207 * 208 * @return This Builder with the resolution setting. 209 */ 210 public Builder resolution(Resolution resolution) { 211 this.resolution = resolution; 212 return this; 213 } 214 215 /** 216 * Call this method to include an audio track ({@code true}, the default) 217 * or not {@code false}). 218 * 219 * @param hasAudio Whether the archive will include an audio track. 220 * 221 * @return This Builder with the hasAudio setting. 222 */ 223 public Builder hasAudio(boolean hasAudio) { 224 this.hasAudio = hasAudio; 225 return this; 226 } 227 228 /** 229 * Call this method to include a video track ({@code true}, the default) 230 * or not {@code false}). 231 * 232 * @param hasVideo Whether the archive will include a video track. 233 * 234 * @return This Builder with the hasVideo setting. 235 */ 236 public Builder hasVideo(boolean hasVideo) { 237 this.hasVideo = hasVideo; 238 return this; 239 } 240 241 /** 242 * Sets the output mode for this archive. 243 * 244 * @param outputMode Set to a value defined in the {@link OutputMode} enum. 245 * 246 * @return This Builder with the output mode setting. 247 */ 248 public Builder outputMode(OutputMode outputMode) { 249 this.outputMode = outputMode; 250 return this; 251 } 252 253 /** 254 * Sets the stream mode for this archive. 255 * <p> 256 * When streams are selected automatically ({@code StreamMode.AUTO}, the default), all 257 * streams in the session can be included in the archive. When streams are selected manually 258 * ({@code StreamMode.MANUAL}), you specify streams to be included based on calls 259 * to the {@link VideoClient#addArchiveStream(String, String, Boolean, Boolean)} and 260 * {@link VideoClient#removeArchiveStream(String, String)} methods. With 261 * {@code StreamMode.MANUAL}, you can specify whether a stream's audio, video, or both 262 * are included in the archive. In both automatic and manual modes, the archive composer 263 * includes streams based on 264 * <a href="https://tokbox.com/developer/guides/archive-broadcast-layout/#stream-prioritization-rules">stream 265 * prioritization rules</a>. 266 * 267 * @param streamMode Set to a value defined in the {@link StreamMode} enum. 268 * 269 * @return This Builder with the stream mode setting. 270 */ 271 public Builder streamMode(StreamMode streamMode) { 272 this.streamMode = streamMode; 273 return this; 274 } 275 276 /** 277 * Sets the layout for a composed archive. If this option is specified, 278 * {@linkplain Builder#outputMode(OutputMode)} must be {@linkplain OutputMode#COMPOSED}. 279 * 280 * @param layout The layout type to use. 281 * 282 * @return This Builder with the layout setting. 283 */ 284 public Builder layout(StreamCompositionLayout layout) { 285 this.layout = layout; 286 return this; 287 } 288 289 /** 290 * Set this to support recording multiple archives for the same session simultaneously. 291 * Set this to a unique string for each simultaneous archive of an ongoing session. You must also set this 292 * option when manually starting an archive that is automatically archived. If you do 293 * not specify a unique multiArchiveTag, you can only record one archive at a time for a given session. See 294 * <a href="https://tokbox.com/developer/guides/archiving/#simultaneous-archives"> 295 * Simultaneous Archives documentation</a>. 296 * 297 * @param multiArchiveTag A unique archive tag. 298 * 299 * @return This Builder with the MultiArchiveTag setting. 300 */ 301 public Builder multiArchiveTag(String multiArchiveTag) { 302 this.multiArchiveTag = multiArchiveTag; 303 return this; 304 } 305 306 /** 307 * (OPTIONAL) The maximum bitrate for the archive, in bits per second. 308 * This must be between 100000 and 6000000. 309 * 310 * @param maxBitrate The maximum bitrate as an int. 311 * 312 * @return This builder. 313 * @since 8.14.0 314 */ 315 public Builder maxBitrate(int maxBitrate) { 316 this.maxBitrate = maxBitrate; 317 return this; 318 } 319 320 /** 321 * Builds the {@linkplain Archive} object with this builder's settings. 322 * 323 * @return A new {@link Archive} instance. 324 */ 325 public Archive build() { 326 return new Archive(this); 327 } 328 } 329}