Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Auto archive resolution & name #241

Merged
merged 4 commits into from
Jun 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 72 additions & 0 deletions src/main/java/com/opentok/Resolution.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/**
* OpenTok Java SDK
* Copyright (C) 2023 Vonage.
* http://www.tokbox.com
*
* Licensed under The MIT License (MIT). See LICENSE file for more information.
*/
package com.opentok;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
import java.util.Arrays;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
* Defines valid video resolutions.
*/
public enum Resolution {
/**
* 480p landscape (640x480)
*/
SD_HORIZONTAL("640x480"),

/**
* 480p portrait (480x640)
*/
SD_VERTICAL("480x640"),

/**
* 720p landscape (1280x720)
*/
HD_HORIZONTAL("1280x720"),

/**
* 720p portrait (720x1280)
*/
HD_VERTICAL("720x1280"),

/**
* 1080p landscape (1920x1080)
*/
FHD_HORIZONTAL("1920x1080"),

/**
* 1080p portrait (1080x1920)
*/
FHD_VERTICAL("1080x1920");

private static final Map<String, Resolution> RESOLUTION_INDEX =
Arrays.stream(Resolution.values()).collect(Collectors.toMap(
Resolution::toString, Function.identity()
));

private final String value;

Resolution(String value) {
this.value = value;
}

@JsonValue
@Override
public String toString() {
return value;
}

@JsonCreator
public static Resolution fromString(String resolution) {
return RESOLUTION_INDEX.getOrDefault(resolution, null);
}
}
114 changes: 94 additions & 20 deletions src/main/java/com/opentok/SessionProperties.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,19 @@
* @see OpenTok#createSession(com.opentok.SessionProperties properties)
*/
public class SessionProperties {
private String location;
private String location, archiveName;
private MediaMode mediaMode;
private ArchiveMode archiveMode;
private Resolution archiveResolution;
private boolean e2ee;

private SessionProperties(Builder builder) {
this.location = builder.location;
this.mediaMode = builder.mediaMode;
this.archiveMode = builder.archiveMode;
this.e2ee = builder.e2ee;
location = builder.location;
mediaMode = builder.mediaMode;
archiveMode = builder.archiveMode;
e2ee = builder.e2ee;
archiveName = builder.archiveName;
archiveResolution = builder.archiveResolution;
}

/**
Expand All @@ -38,9 +41,10 @@ private SessionProperties(Builder builder) {
* @see SessionProperties
*/
public static class Builder {
private String location;
private String location, archiveName;
private MediaMode mediaMode = MediaMode.RELAYED;
private ArchiveMode archiveMode = ArchiveMode.MANUAL;
private Resolution archiveResolution;
private boolean e2ee = false;

/**
Expand Down Expand Up @@ -117,6 +121,32 @@ public Builder archiveMode(ArchiveMode archiveMode) {
return this;
}

/**
* Indicates the archive resolution for all the archives in auto archived session. A session that begins with
* archive mode {@link ArchiveMode#ALWAYS} will use this resolution for all archives of that session.
*
* @param archiveResolution The auto archive resolution as an enum.
*
* @return The SessionProperties.Builder object with the archive resolution setting.
*/
public Builder archiveResolution(Resolution archiveResolution) {
this.archiveResolution = archiveResolution;
return this;
}

/**
* Indicates the archive name for all the archives in auto archived session. A session that begins with
* archive mode {@link ArchiveMode#ALWAYS} will use this archive name for all archives of that session.
*
* @param archiveName The archive name, maximum 80 characters in length.
*
* @return The SessionProperties.Builder object with the archive name setting.
*/
public Builder archiveName(String archiveName) {
this.archiveName = archiveName;
return this;
}

/**
* Enables <a href="https://tokbox.com/developer/guides/end-to-end-encryption">end-to-end encryption</a> for a routed session.
* You must also set {@link #mediaMode(MediaMode)} to {@linkplain MediaMode#ROUTED} when
Expand All @@ -135,7 +165,7 @@ public Builder endToEndEncryption() {
* @return The SessionProperties object.
*/
public SessionProperties build() {
if (this.archiveMode == ArchiveMode.ALWAYS && this.mediaMode != MediaMode.ROUTED) {
if (archiveMode == ArchiveMode.ALWAYS && mediaMode != MediaMode.ROUTED) {
throw new IllegalStateException(
"A session with ALWAYS archive mode must also have the ROUTED media mode."
);
Expand All @@ -150,6 +180,17 @@ public SessionProperties build() {
"A session with ALWAYS archive mode cannot have end-to-end encryption enabled."
);
}
if (archiveMode == ArchiveMode.MANUAL) {
if (archiveResolution != null) {
throw new IllegalStateException("Resolution cannot be set for manual archives.");
}
if (archiveName != null) {
throw new IllegalStateException("Name cannot be set for manual archives.");
}
}
if (archiveName != null && (archiveName.trim().length() < 1 || archiveName.length() > 80)) {
throw new IllegalArgumentException("Archive name must be between 1 and 80 characters.");
}
return new SessionProperties(this);
}
}
Expand Down Expand Up @@ -179,11 +220,30 @@ public ArchiveMode archiveMode() {
return archiveMode;
}

/**
* Indicates the archive resolution for all the archives in auto archived session. A session that begins with
* archive mode {@link ArchiveMode#ALWAYS} will use this resolution for all archives of that session.
*
* @return The archive name, or {@code null} if not set (the default).
*/
public String archiveName() {
return archiveName;
}

/**
* Indicates the archive resolution for all the archives in auto archived session. A session that begins with
* archive mode {@link ArchiveMode#ALWAYS} will use this resolution for all archives of that session.
*
* @return The archive resolution enum, or {@code null} if not set (the default).
*/
public Resolution archiveResolution() {
return archiveResolution;
}

/**
* Defines whether the session will use
* <a href="https://tokbox.com/developer/guides/end-to-end-encryption">end-to-end encryption</a>.
* See {@link com.opentok.SessionProperties.Builder#endToEndEncryption()}.
*
*
* @return {@code true} if end-to-end encryption is enabled, {@code false} otherwise.
*/
Expand All @@ -192,27 +252,41 @@ public boolean isEndToEndEncrypted() {
}

/**
* Returns the session properties as a Map.
* Serializes the properties for making a request.
*
* @return The session properties as a Map.
*/
public Map<String, List<String>> toMap() {
Map<String, List<String>> params = new HashMap<>();
if (null != location) {

if (location != null) {
ArrayList<String> valueList = new ArrayList<>(1);
valueList.add(location);
params.put("location", valueList);
}

ArrayList<String> mediaModeValueList = new ArrayList<>(1);
mediaModeValueList.add(mediaMode.toString());
params.put("p2p.preference", mediaModeValueList);

ArrayList<String> archiveModeValueList = new ArrayList<>(1);
archiveModeValueList.add(archiveMode.toString());
params.put("archiveMode", archiveModeValueList);

if (mediaMode != null) {
ArrayList<String> mediaModeValueList = new ArrayList<>(1);
mediaModeValueList.add(mediaMode.toString());
params.put("p2p.preference", mediaModeValueList);
}
if (archiveMode != null) {
ArrayList<String> archiveModeValueList = new ArrayList<>(1);
archiveModeValueList.add(archiveMode.toString());
params.put("archiveMode", archiveModeValueList);
}
if (archiveResolution != null) {
ArrayList<String> archiveResolutionValueList = new ArrayList<>(1);
archiveResolutionValueList.add(archiveResolution.toString());
params.put("archiveResolution", archiveResolutionValueList);
}
if (archiveName != null) {
ArrayList<String> archiveNameValueList = new ArrayList<>(1);
archiveNameValueList.add(archiveName);
params.put("archiveName", archiveNameValueList);
}
if (e2ee) {
ArrayList<String> e2eeValueList = new ArrayList<>(1);
e2eeValueList.add("" + e2ee);
e2eeValueList.add(String.valueOf(e2ee));
params.put("e2ee", e2eeValueList);
}

Expand Down
40 changes: 37 additions & 3 deletions src/test/java/com/opentok/test/OpenTokTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.github.tomakehurst.wiremock.WireMockServer;
import com.github.tomakehurst.wiremock.client.WireMock;
import static com.github.tomakehurst.wiremock.client.WireMock.matching;
import com.github.tomakehurst.wiremock.core.WireMockConfiguration;
import com.github.tomakehurst.wiremock.junit.WireMockRule;
import com.opentok.*;
Expand All @@ -20,7 +21,6 @@
import com.opentok.exception.OpenTokException;
import com.opentok.exception.RequestException;
import org.apache.commons.lang.StringUtils;
import org.checkerframework.common.returnsreceiver.qual.This;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
Expand Down Expand Up @@ -373,23 +373,57 @@ public void testCreateAlwaysArchivedSession() throws OpenTokException {
SessionProperties properties = new SessionProperties.Builder()
.archiveMode(ArchiveMode.ALWAYS)
.mediaMode(MediaMode.ROUTED)
.archiveResolution(Resolution.HD_VERTICAL)
.archiveName("720pTest")
.build();
Session session = sdk.createSession(properties);

assertNotNull(session);
assertEquals(apiKey, session.getApiKey());
assertEquals(sessionId, session.getSessionId());
assertEquals(ArchiveMode.ALWAYS, session.getProperties().archiveMode());

assertEquals(Resolution.HD_VERTICAL, session.getProperties().archiveResolution());

verify(postRequestedFor(urlMatching(SESSION_CREATE))
// TODO: this is a pretty bad way to verify, ideally we can decode the body and then query the object
.withRequestBody(matching(".*archiveMode=always.*")));
.withRequestBody(matching(".*archiveMode=always.*"))
.withRequestBody(matching(".*archiveResolution=720x1280.*"))
.withRequestBody(matching(".*archiveName=720pTest.*")));
assertTrue(Helpers.verifyTokenAuth(apiKey, apiSecret,
findAll(postRequestedFor(urlMatching(SESSION_CREATE)))));
Helpers.verifyUserAgent();
}

@Test
public void testAutoArchiveSessionValidation() {
SessionProperties.Builder builder = new SessionProperties.Builder()
.archiveMode(ArchiveMode.ALWAYS)
.mediaMode(MediaMode.ROUTED);

SessionProperties plain = builder.build();
assertNull(plain.archiveName());
assertNull(plain.archiveResolution());

assertEquals(1, builder.archiveName("A").build().archiveName().length());
assertThrows(IllegalArgumentException.class, () -> builder.archiveName("").build());
StringBuilder sb = new StringBuilder(80);
for (int i = 0; i < 10; sb.append("Archive").append(i++));
assertEquals(80, builder.archiveName(sb.toString()).build().archiveName().length());
assertThrows(IllegalArgumentException.class, () -> builder.archiveName(sb.append("N").toString()).build());

builder.archiveName("Test").archiveMode(ArchiveMode.MANUAL);
assertThrows(IllegalStateException.class, builder::build);

SessionProperties fhd = builder
.archiveMode(ArchiveMode.ALWAYS)
.archiveResolution(Resolution.FHD_HORIZONTAL)
.archiveName(null).build();
assertEquals("1920x1080", fhd.archiveResolution().toString());
assertNull(fhd.archiveName());

assertThrows(IllegalStateException.class, () -> builder.archiveMode(ArchiveMode.MANUAL).build());
}

@Test(expected = InvalidArgumentException.class)
public void testCreateBadSession() throws OpenTokException {
SessionProperties properties = new SessionProperties.Builder()
Expand Down