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 com.vonage.client.JsonableBaseObject; 022import java.time.Duration; 023import java.time.Instant; 024import java.util.ArrayList; 025import java.util.Collection; 026import java.util.List; 027import java.util.Objects; 028 029/** 030 * Represents properties of a live-streaming broadcast. 031 */ 032public class Broadcast extends StreamComposition { 033 private String multiBroadcastTag; 034 @JsonProperty("updatedAt") private Long updatedAt; 035 @JsonProperty("maxDuration") private Integer maxDuration; 036 private BroadcastStatus status; 037 private BroadcastUrls broadcastUrls; 038 private Settings settings; 039 private Outputs outputs; 040 041 protected Broadcast() { 042 } 043 044 protected Broadcast(Builder builder) { 045 super(builder); 046 outputs = new Outputs(); 047 outputs.rtmp = builder.rtmps.isEmpty() ? null : builder.rtmps; 048 if ((outputs.hls = builder.hls) == null && outputs.rtmp == null) { 049 throw new IllegalStateException("At least one output stream (RTMP or HLS) must be specified."); 050 } 051 if ((maxDuration = builder.maxDuration) != null && (maxDuration < 60 || maxDuration > 36000)) { 052 throw new IllegalArgumentException("maxDuration must be between 60 seconds and 10 hours."); 053 } 054 multiBroadcastTag = builder.multiBroadcastTag; 055 } 056 057 static class Settings extends JsonableBaseObject { 058 @JsonProperty("hls") private Hls hls; 059 } 060 061 static class Outputs extends JsonableBaseObject { 062 @JsonProperty("rtmp") private List<Rtmp> rtmp; 063 @JsonProperty("hls") private Hls hls; 064 } 065 066 @JsonProperty("outputs") 067 Outputs getOutputs() { 068 return outputs; 069 } 070 071 @JsonProperty("settings") 072 Settings getSettings() { 073 return settings; 074 } 075 076 /** 077 * The unique tag for simultaneous broadcasts (if one was set). 078 * 079 * @return The multi broadcast tag, or {@code null} if unset. 080 */ 081 @JsonProperty("multiBroadcastTag") 082 public String getMultiBroadcastTag() { 083 return multiBroadcastTag; 084 } 085 086 /** 087 * For this start method, this timestamp matches the {@link #getCreatedAtMillis()} timestamp. 088 * 089 * @return The update time in milliseconds since the Unix epoch. 090 */ 091 @JsonProperty("updatedAt") 092 public Long getUpdatedAtMillis() { 093 return updatedAt; 094 } 095 096 /** 097 * For this start method, this timestamp matches the {@link #getCreatedAt()} timestamp. 098 * 099 * @return The updatedAt time as an Instant, or {@code null} if unset / not applicable. 100 */ 101 @JsonIgnore 102 public Instant getUpdatedAt() { 103 return updatedAt != null ? Instant.ofEpochMilli(updatedAt) : null; 104 } 105 106 /** 107 * The maximum duration for the broadcast (if one was set), in seconds. 108 * 109 * @return The maximum duration of this broadcast in seconds as an integer, or {@code null} if unset. 110 */ 111 @JsonProperty("maxDuration") 112 public Integer getMaxDurationSeconds() { 113 return maxDuration; 114 } 115 116 /** 117 * The maximum duration for the broadcast (if one was set). 118 * 119 * @return The maximum duration (precision in seconds), or {@code null} if unset. 120 */ 121 @JsonIgnore 122 public Duration getMaxDuration() { 123 return maxDuration != null ? Duration.ofSeconds(maxDuration) : null; 124 } 125 126 /** 127 * The status of the broadcast at the time this object was created. 128 * 129 * @return Current status of the broadcast as an enum. 130 */ 131 @JsonProperty("status") 132 public BroadcastStatus getStatus() { 133 return status; 134 } 135 136 /** 137 * Details on the HLS and RTMP broadcast streams. For an HLS stream, the URL is provided. 138 * 139 * @return The URLs for this broadcast, or {@code null} if unknown. 140 */ 141 @JsonProperty("broadcastUrls") 142 public BroadcastUrls getBroadcastUrls() { 143 return broadcastUrls; 144 } 145 146 /** 147 * @return Further details on the HLS broadcast stream, or {@code null} if not applicable. 148 */ 149 @JsonIgnore 150 public Hls getHlsSettings() { 151 return settings != null ? settings.hls : null; 152 } 153 154 /** 155 * Creates an instance of this class from a JSON payload. 156 * 157 * @param json The JSON string to parse. 158 * @return An instance of this class with the fields populated, if present. 159 */ 160 public static Broadcast fromJson(String json) { 161 return Jsonable.fromJson(json); 162 } 163 164 /** 165 * Instantiates a Builder, used to construct this object. 166 * Note that you must specify at least one RTMP stream or HLS properties. 167 * 168 * @param sessionId ID of the Vonage Video session to broadcast. 169 * 170 * @return A new {@linkplain Builder}. 171 */ 172 public static Builder builder(String sessionId) { 173 return new Builder(sessionId); 174 } 175 176 /** 177 * Used to construct a Broadcast object. 178 */ 179 public static class Builder extends StreamComposition.Builder { 180 private final List<Rtmp> rtmps = new ArrayList<>(); 181 private Hls hls; 182 private Integer maxDuration; 183 private String multiBroadcastTag; 184 185 Builder(String sessionId) { 186 this.sessionId = sessionId; 187 } 188 189 /** 190 * (OPTIONAL) 191 * Whether streams included in the broadcast are selected automatically ("auto", the default) or manually 192 * ("manual"). When streams are selected automatically ("auto"), all streams in the session can be included 193 * in the broadcast. When streams are selected manually ("manual"), you specify which streams to include 194 * based on calls to {@link VideoClient#addBroadcastStream(String, String, Boolean, Boolean)}. 195 * For both automatic and manual modes, the broadcast composer includes streams based on 196 * <a href=https://tokbox.com/developer/guides/archive-broadcast-layout/#stream-prioritization-rules> 197 * stream prioritization rules</a>. 198 * 199 * @param streamMode The streaming mode as an enum. 200 * 201 * @return This builder. 202 */ 203 public Builder streamMode(StreamMode streamMode) { 204 this.streamMode = streamMode; 205 return this; 206 } 207 208 /** 209 * (OPTIONAL) 210 * The resolution of the broadcast: either "640x480" (SD landscape, the default), "1280x720" (HD landscape), 211 * "1920x1080" (FHD landscape), "480x640" (SD portrait), "720x1280" (HD portrait), or "1080x1920" 212 * (FHD portrait). You may want to use a portrait aspect ratio for broadcasts that include video streams 213 * from mobile devices (which often use the portrait aspect ratio). 214 * 215 * @param resolution The video resolution as an enum. 216 * 217 * @return This builder. 218 */ 219 public Builder resolution(Resolution resolution) { 220 this.resolution = resolution; 221 return this; 222 } 223 224 /** 225 * (OPTIONAL) 226 * Specify this to assign the initial layout type for the broadcast. 227 * If you do not specify an initial layout type, the broadcast stream uses the Best Fit layout type. 228 * 229 * @param layout The broadcast's initial layout properties. 230 * 231 * @return This builder. 232 */ 233 public Builder layout(StreamCompositionLayout layout) { 234 this.layout = layout; 235 return this; 236 } 237 238 /** 239 * (OPTIONAL, but REQUIRED if HLS is unspecified) 240 * You can specify up to five target RTMP streams (or just one). 241 * For each RTMP stream, specify serverUrl (the RTMP server URL), streamName 242 * (the stream name, such as the YouTube Live stream name or the Facebook stream key), and 243 * (optionally) id (a unique ID for the stream). If you specify an ID, it will be included in the REST call 244 * response and the REST method for getting information about a live-streaming broadcast. Vonage streams 245 * the session to each RTMP URL you specify. Note that Vonage live-streaming supports RTMP and RTMPS. 246 * 247 * @param rtmp The RTMP stream to include in the broadcast. 248 * 249 * @return This builder. 250 */ 251 public Builder addRtmpStream(Rtmp rtmp) { 252 rtmps.add(Objects.requireNonNull(rtmp, "Rtmp cannot be null.")); 253 return this; 254 } 255 256 /** 257 * (OPTIONAL, but REQUIRED if HLS is unspecified) 258 * You can specify up to five target RTMP streams (or just one). 259 * For each RTMP stream, specify serverUrl (the RTMP server URL), streamName 260 * (the stream name, such as the YouTube Live stream name or the Facebook stream key), and 261 * (optionally) id (a unique ID for the stream). If you specify an ID, it will be included in the REST call 262 * response and the REST method for getting information about a live-streaming broadcast. Vonage streams 263 * the session to each RTMP URL you specify. Note that Vonage live-streaming supports RTMP and RTMPS. 264 * 265 * @param rtmps The RTMP streams to include in the broadcast. 266 * 267 * @return This builder. 268 * @see #addRtmpStream(Rtmp) 269 */ 270 public Builder rtmpStreams(Collection<Rtmp> rtmps) { 271 for (Rtmp rtmp : Objects.requireNonNull(rtmps, "Rtmps cannot be null.")) { 272 addRtmpStream(rtmp); 273 } 274 return this; 275 } 276 277 /** 278 * (OPTIONAL, but REQUIRED if no RTMP URLs are set) 279 * Sets the HTTP Live Streaming (HLS) output of the broadcast. 280 * 281 * @param hls The HLS broadcast properties. 282 * 283 * @return This builder. 284 */ 285 public Builder hls(Hls hls) { 286 this.hls = hls; 287 return this; 288 } 289 290 /** 291 * (OPTIONAL) The maximum bitrate for the broadcast, in bits per second. 292 * 293 * @param maxBitrate The maximum bitrate as an integer. 294 * 295 * @return This builder. 296 */ 297 public Builder maxBitrate(int maxBitrate) { 298 this.maxBitrate = maxBitrate; 299 return this; 300 } 301 302 /** 303 * (OPTIONAL) 304 * The maximum duration for the broadcast, in seconds. The broadcast will automatically stop when the 305 * maximum duration is reached. You can set the maximum duration to a value from 60 (60 seconds) to 36000 306 * (10 hours). The default maximum duration is 4 hours (14400 seconds). 307 * 308 * @param maxDuration The maximum duration as an integer. 309 * 310 * @return This builder. 311 */ 312 public Builder maxDuration(int maxDuration) { 313 this.maxDuration = maxDuration; 314 return this; 315 } 316 317 /** 318 * (OPTIONAL) 319 * The maximum duration for the broadcast. The broadcast will automatically stop when the 320 * maximum duration is reached. You can set the maximum duration to a value from 60 seconds to 10 hours. 321 * The default maximum duration is 4 hours. 322 * 323 * @param maxDuration The maximum duration. 324 * 325 * @return This builder. 326 */ 327 public Builder maxDuration(Duration maxDuration) { 328 return maxDuration((int) maxDuration.getSeconds()); 329 } 330 331 /** 332 * (OPTIONAL) 333 * Set this to support multiple broadcasts for the same session simultaneously. 334 * Set this to a unique string for each simultaneous broadcast of an ongoing session. 335 * 336 * @param multiBroadcastTag The tag for this broadcast. 337 * 338 * @return This builder. 339 */ 340 public Builder multiBroadcastTag(String multiBroadcastTag) { 341 this.multiBroadcastTag = multiBroadcastTag; 342 return this; 343 } 344 345 /** 346 * Builds the {@linkplain Broadcast} object with this builder's settings. 347 * 348 * @return A new {@link Broadcast} instance. 349 */ 350 public Broadcast build() { 351 return new Broadcast(this); 352 } 353 } 354}