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}