mirror of https://github.com/OpenVidu/openvidu.git
Broadcast SDKs. Broadcast tests in OpenViduProTestaAppE2eTest
parent
ca5887ac06
commit
bd23cfcd71
|
@ -86,6 +86,9 @@ public class OpenVidu {
|
|||
protected final static String API_RECORDINGS = API_PATH + "/recordings";
|
||||
protected final static String API_RECORDINGS_START = API_RECORDINGS + "/start";
|
||||
protected final static String API_RECORDINGS_STOP = API_RECORDINGS + "/stop";
|
||||
protected final static String API_BROADCAST = API_PATH + "/broadcast";
|
||||
protected final static String API_BROADCAST_START = API_BROADCAST + "/start";
|
||||
protected final static String API_BROADCAST_STOP = API_BROADCAST + "/stop";
|
||||
|
||||
/**
|
||||
* @param hostname URL where your OpenVidu deployment is up an running. It must
|
||||
|
@ -515,6 +518,140 @@ public class OpenVidu {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the broadcast of a {@link io.openvidu.java.client.Session}
|
||||
*
|
||||
* @param sessionId The sessionId of the session you want to start
|
||||
* broadcasting
|
||||
* @param broadcastUrl The URL where to broadcast
|
||||
*
|
||||
* @throws OpenViduJavaClientException
|
||||
* @throws OpenViduHttpException The status code carries a specific
|
||||
* meaning
|
||||
* {@link io.openvidu.java.client.OpenViduHttpException#getStatus()}
|
||||
* (see <a href=
|
||||
* "/en/stable/reference-docs/REST-API/#start-broadcast">REST
|
||||
* API</a>)
|
||||
*/
|
||||
public void startBroadcast(String sessionId, String broadcastUrl)
|
||||
throws OpenViduJavaClientException, OpenViduHttpException {
|
||||
this.startBroadcast(sessionId, broadcastUrl, new RecordingProperties.Builder().build());
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the broadcast of a {@link io.openvidu.java.client.Session}
|
||||
*
|
||||
* @param sessionId The sessionId of the session you want to start
|
||||
* broadcasting
|
||||
* @param broadcastUrl The URL where to broadcast
|
||||
* @param properties The configuration for this broadcast. It uses a subset of
|
||||
* the {@link io.openvidu.java.client.RecordingProperties}:
|
||||
* <ul>
|
||||
* <li>{@link RecordingProperties.Builder#hasAudio(boolean)}</li>
|
||||
* <li>{@link RecordingProperties.Builder#resolution(String)}</li>
|
||||
* <li>{@link RecordingProperties.Builder#frameRate(int)}</li>
|
||||
* <li>{@link RecordingProperties.Builder#recordingLayout(RecordingLayout)}</li>
|
||||
* <li>{@link RecordingProperties.Builder#customLayout(String)}</li>
|
||||
* <li>{@link RecordingProperties.Builder#shmSize(long)}</li>
|
||||
* <li>{@link RecordingProperties.Builder#mediaNode(String)}</li>
|
||||
* </ul>
|
||||
*
|
||||
*
|
||||
* @throws OpenViduJavaClientException
|
||||
* @throws OpenViduHttpException The status code carries a specific
|
||||
* meaning
|
||||
* {@link io.openvidu.java.client.OpenViduHttpException#getStatus()}
|
||||
* (see <a href=
|
||||
* "/en/stable/reference-docs/REST-API/#start-broadcast">REST
|
||||
* API</a>)
|
||||
*/
|
||||
public void startBroadcast(String sessionId, String broadcastUrl, RecordingProperties properties)
|
||||
throws OpenViduJavaClientException, OpenViduHttpException {
|
||||
final HttpClientResponseHandler<Void> responseHandler = new HttpClientResponseHandler<Void>() {
|
||||
@Override
|
||||
public Void handleResponse(final ClassicHttpResponse response) throws IOException, HttpException {
|
||||
final int status = response.getCode();
|
||||
if (status == HttpStatus.SC_OK) {
|
||||
Session activeSession = activeSessions.get(sessionId);
|
||||
if (activeSession != null) {
|
||||
activeSession.setIsBeingBroadcasted(true);
|
||||
} else {
|
||||
log.warn(
|
||||
"No active session found for sessionId '{}'. This instance of OpenVidu Java Client didn't create this session",
|
||||
sessionId);
|
||||
}
|
||||
} else {
|
||||
throw openViduHttpException(status);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
JsonObject json = properties.toJson();
|
||||
json.addProperty("session", sessionId);
|
||||
json.addProperty("broadcastUrl", broadcastUrl);
|
||||
StringEntity params = new StringEntity(json.toString(), StandardCharsets.UTF_8);
|
||||
|
||||
HttpPost request = new HttpPost(this.hostname + API_BROADCAST_START);
|
||||
request.setHeader(HttpHeaders.CONTENT_TYPE, "application/json");
|
||||
request.setEntity(params);
|
||||
|
||||
try {
|
||||
this.httpClient.execute(request, responseHandler);
|
||||
} catch (IOException e) {
|
||||
throw ioExceptionToOpenViduHttpException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the broadcast of a {@link io.openvidu.java.client.Session}
|
||||
*
|
||||
* @param sessionId The sessionId of the session you want to stop broadcasting
|
||||
*
|
||||
* @throws OpenViduJavaClientException
|
||||
* @throws OpenViduHttpException The status code carries a specific
|
||||
* meaning
|
||||
* {@link io.openvidu.java.client.OpenViduHttpException#getStatus()}
|
||||
* (see <a href=
|
||||
* "/en/stable/reference-docs/REST-API/#stop-broadcast">REST
|
||||
* API</a>)
|
||||
*/
|
||||
public void stopBroadcast(String sessionId) throws OpenViduJavaClientException, OpenViduHttpException {
|
||||
final HttpClientResponseHandler<Void> responseHandler = new HttpClientResponseHandler<Void>() {
|
||||
@Override
|
||||
public Void handleResponse(final ClassicHttpResponse response) throws IOException, HttpException {
|
||||
final int status = response.getCode();
|
||||
if (status == HttpStatus.SC_OK) {
|
||||
Session activeSession = activeSessions.get(sessionId);
|
||||
if (activeSession != null) {
|
||||
activeSession.setIsBeingBroadcasted(false);
|
||||
} else {
|
||||
log.warn(
|
||||
"No active session found for sessionId '{}'. This instance of OpenVidu Java Client didn't create this session",
|
||||
sessionId);
|
||||
}
|
||||
return null;
|
||||
} else {
|
||||
throw openViduHttpException(status);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
JsonObject json = new JsonObject();
|
||||
json.addProperty("session", sessionId);
|
||||
StringEntity params = new StringEntity(json.toString(), StandardCharsets.UTF_8);
|
||||
|
||||
HttpPost request = new HttpPost(this.hostname + API_BROADCAST_STOP);
|
||||
request.setHeader(HttpHeaders.CONTENT_TYPE, "application/json");
|
||||
request.setEntity(params);
|
||||
|
||||
try {
|
||||
this.httpClient.execute(request, responseHandler);
|
||||
} catch (IOException e) {
|
||||
throw ioExceptionToOpenViduHttpException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of active sessions. <strong>This value will remain unchanged
|
||||
* since the last time method {@link io.openvidu.java.client.OpenVidu#fetch()}
|
||||
|
|
|
@ -65,7 +65,18 @@ export class OpenVidu {
|
|||
* @hidden
|
||||
*/
|
||||
static readonly API_RECORDINGS_STOP: string = OpenVidu.API_RECORDINGS + '/stop';
|
||||
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
static readonly API_BROADCAST: string = OpenVidu.API_PATH + '/broadcast';
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
static readonly API_BROADCAST_START: string = OpenVidu.API_BROADCAST + '/start';
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
static readonly API_BROADCAST_STOP: string = OpenVidu.API_BROADCAST + '/stop';
|
||||
|
||||
|
||||
|
||||
|
@ -359,6 +370,124 @@ export class OpenVidu {
|
|||
});
|
||||
}
|
||||
|
||||
public startBroadcast(sessionId: string, broadcastUrl: string): Promise<void>;
|
||||
public startBroadcast(sessionId: string, broadcastUrl: string, properties: RecordingProperties): Promise<void>;
|
||||
|
||||
/**
|
||||
* Starts the broadcast of a {@link Session}
|
||||
*
|
||||
* @param sessionId The `sessionId` of the {@link Session} you want to start broadcasting
|
||||
* @param broadcastUrl The URL where to broadcast
|
||||
* @param properties The configuration for this broadcast. It uses a subset of the {@link RecordingProperties}:
|
||||
* - {@link RecordingProperties.hasAudio}
|
||||
* - {@link RecordingProperties.resolution}
|
||||
* - {@link RecordingProperties.frameRate}
|
||||
* - {@link RecordingProperties.recordingLayout}
|
||||
* - {@link RecordingProperties.customLayout}
|
||||
* - {@link RecordingProperties.shmSize}
|
||||
* - {@link RecordingProperties.mediaNode}
|
||||
*
|
||||
* @returns A Promise that is resolved if the broadcast successfully started and rejected with an
|
||||
* [Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error) object if not.
|
||||
* This Error object has as `message` property with a status code carrying a specific meaning
|
||||
* (see [REST API](/en/stable/reference-docs/REST-API/#start-broadcast)).
|
||||
*/
|
||||
public startBroadcast(sessionId: string, broadcastUrl: string, properties?: RecordingProperties): Promise<void> {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
|
||||
let data;
|
||||
|
||||
if (properties != undefined) {
|
||||
data = {
|
||||
session: sessionId,
|
||||
broadcastUrl,
|
||||
recordingLayout: properties.recordingLayout,
|
||||
customLayout: properties.customLayout,
|
||||
resolution: properties.resolution,
|
||||
frameRate: properties.frameRate,
|
||||
hasAudio: properties.hasAudio,
|
||||
shmSize: properties.shmSize,
|
||||
mediaNode: properties.mediaNode
|
||||
};
|
||||
data = JSON.stringify(data);
|
||||
} else {
|
||||
data = {
|
||||
session: sessionId,
|
||||
broadcastUrl
|
||||
}
|
||||
}
|
||||
|
||||
axios.post(
|
||||
this.host + OpenVidu.API_BROADCAST_START,
|
||||
data,
|
||||
{
|
||||
headers: {
|
||||
'Authorization': this.basicAuth,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}
|
||||
)
|
||||
.then(res => {
|
||||
if (res.status === 200) {
|
||||
const activeSession = this.activeSessions.find(s => s.sessionId === sessionId);
|
||||
if (!!activeSession) {
|
||||
activeSession.broadcasting = true;
|
||||
} else {
|
||||
console.warn("No active session found for sessionId '" + sessionId + "'. This instance of OpenVidu Node Client didn't create this session");
|
||||
}
|
||||
resolve();
|
||||
} else {
|
||||
// ERROR response from openvidu-server. Resolve HTTP status
|
||||
reject(new Error(res.status.toString()));
|
||||
}
|
||||
}).catch(error => {
|
||||
this.handleError(error, reject);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the broadcast of a {@link Session}
|
||||
*
|
||||
* @param sessionId The `sessionId` of the {@link Session} you want to stop broadcasting
|
||||
*
|
||||
* @returns A Promise that is resolved if the broadcast successfully stopped and rejected with an
|
||||
* [Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error) object if not.
|
||||
* This Error object has as `message` property with a status code carrying a specific meaning
|
||||
* (see [REST API](/en/stable/reference-docs/REST-API/#stop-broadcast)).
|
||||
*/
|
||||
public stopBroadcst(sessionId: string): Promise<void> {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
axios.post(
|
||||
this.host + OpenVidu.API_BROADCAST_STOP,
|
||||
{ session: sessionId },
|
||||
{
|
||||
headers: {
|
||||
'Authorization': this.basicAuth,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}
|
||||
)
|
||||
.then(res => {
|
||||
if (res.status === 200) {
|
||||
// SUCCESS response from openvidu-server
|
||||
const activeSession = this.activeSessions.find(s => s.sessionId === sessionId);
|
||||
if (!!activeSession) {
|
||||
activeSession.broadcasting = false;
|
||||
} else {
|
||||
console.warn("No active session found for sessionId '" + sessionId + "'. This instance of OpenVidu Node Client didn't create this session");
|
||||
}
|
||||
resolve();
|
||||
} else {
|
||||
// ERROR response from openvidu-server. Resolve HTTP status
|
||||
reject(new Error(res.status.toString()));
|
||||
}
|
||||
}).catch(error => {
|
||||
this.handleError(error, reject);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates every property of every active Session with the current status they have in OpenVidu Server.
|
||||
* After calling this method you can access the updated array of active sessions in {@link activeSessions}
|
||||
|
|
|
@ -292,8 +292,8 @@ public class SessionRestController {
|
|||
case IPCAM:
|
||||
return this.newIpcamConnection(session, connectionProperties);
|
||||
default:
|
||||
return SessionRestController.generateErrorResponse("Wrong type parameter", "/sessions/" + sessionId + "/connection",
|
||||
HttpStatus.BAD_REQUEST);
|
||||
return SessionRestController.generateErrorResponse("Wrong type parameter",
|
||||
"/sessions/" + sessionId + "/connection", HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -371,8 +371,8 @@ public class SessionRestController {
|
|||
public ResponseEntity<?> startRecording(@RequestBody Map<String, ?> params) {
|
||||
|
||||
if (params == null) {
|
||||
return SessionRestController.generateErrorResponse("Error in body parameters. Cannot be empty", "/recordings/start",
|
||||
HttpStatus.BAD_REQUEST);
|
||||
return SessionRestController.generateErrorResponse("Error in body parameters. Cannot be empty",
|
||||
"/recordings/start", HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
|
||||
log.info("REST API: POST {}/recordings/start {}", RequestMappings.API, params.toString());
|
||||
|
@ -386,14 +386,14 @@ public class SessionRestController {
|
|||
try {
|
||||
sessionId = (String) params.get("session");
|
||||
} catch (Exception e) {
|
||||
return SessionRestController.generateErrorResponse("Type error in parameter \"session\"", "/recordings/start",
|
||||
HttpStatus.BAD_REQUEST);
|
||||
return SessionRestController.generateErrorResponse("Type error in parameter \"session\"",
|
||||
"/recordings/start", HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
|
||||
if (sessionId == null) {
|
||||
// "session" parameter not found
|
||||
return SessionRestController.generateErrorResponse("\"session\" parameter is mandatory", "/recordings/start",
|
||||
HttpStatus.BAD_REQUEST);
|
||||
return SessionRestController.generateErrorResponse("\"session\" parameter is mandatory",
|
||||
"/recordings/start", HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
|
||||
Session session = sessionManager.getSession(sessionId);
|
||||
|
@ -426,7 +426,8 @@ public class SessionRestController {
|
|||
try {
|
||||
recordingProperties = getRecordingPropertiesFromParams(params, session).build();
|
||||
} catch (IllegalStateException e) {
|
||||
return SessionRestController.generateErrorResponse(e.getMessage(), "/sessions", HttpStatus.UNPROCESSABLE_ENTITY);
|
||||
return SessionRestController.generateErrorResponse(e.getMessage(), "/sessions",
|
||||
HttpStatus.UNPROCESSABLE_ENTITY);
|
||||
} catch (RuntimeException e) {
|
||||
return SessionRestController.generateErrorResponse(e.getMessage(), "/sessions", HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
|
@ -566,11 +567,13 @@ public class SessionRestController {
|
|||
try {
|
||||
sessionId = (String) params.get("session");
|
||||
} catch (ClassCastException e) {
|
||||
return SessionRestController.generateErrorResponse("Type error in some parameter", "/tokens", HttpStatus.BAD_REQUEST);
|
||||
return SessionRestController.generateErrorResponse("Type error in some parameter", "/tokens",
|
||||
HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
|
||||
if (sessionId == null) {
|
||||
return SessionRestController.generateErrorResponse("\"session\" parameter is mandatory", "/tokens", HttpStatus.BAD_REQUEST);
|
||||
return SessionRestController.generateErrorResponse("\"session\" parameter is mandatory", "/tokens",
|
||||
HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
|
||||
log.warn("Token API is deprecated. Use Connection API instead (POST {}/sessions/{}/connection)",
|
||||
|
@ -578,7 +581,8 @@ public class SessionRestController {
|
|||
|
||||
final Session session = this.sessionManager.getSessionWithNotActive(sessionId);
|
||||
if (session == null) {
|
||||
return SessionRestController.generateErrorResponse("Session " + sessionId + " not found", "/tokens", HttpStatus.NOT_FOUND);
|
||||
return SessionRestController.generateErrorResponse("Session " + sessionId + " not found", "/tokens",
|
||||
HttpStatus.NOT_FOUND);
|
||||
}
|
||||
|
||||
ConnectionProperties connectionProperties;
|
||||
|
@ -655,14 +659,16 @@ public class SessionRestController {
|
|||
type = (String) params.get("type");
|
||||
data = (String) params.get("data");
|
||||
} catch (ClassCastException e) {
|
||||
return SessionRestController.generateErrorResponse("Type error in some parameter", "/signal", HttpStatus.BAD_REQUEST);
|
||||
return SessionRestController.generateErrorResponse("Type error in some parameter", "/signal",
|
||||
HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
|
||||
JsonObject completeMessage = new JsonObject();
|
||||
|
||||
if (sessionId == null) {
|
||||
// "session" parameter not found
|
||||
return SessionRestController.generateErrorResponse("\"session\" parameter is mandatory", "/signal", HttpStatus.BAD_REQUEST);
|
||||
return SessionRestController.generateErrorResponse("\"session\" parameter is mandatory", "/signal",
|
||||
HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
Session session = sessionManager.getSession(sessionId);
|
||||
if (session == null) {
|
||||
|
@ -689,16 +695,16 @@ public class SessionRestController {
|
|||
JsonArray toArray = gson.toJsonTree(to).getAsJsonArray();
|
||||
completeMessage.add("to", toArray);
|
||||
} catch (IllegalStateException exception) {
|
||||
return SessionRestController.generateErrorResponse("\"to\" parameter is not a valid JSON array", "/signal",
|
||||
HttpStatus.BAD_REQUEST);
|
||||
return SessionRestController.generateErrorResponse("\"to\" parameter is not a valid JSON array",
|
||||
"/signal", HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
sessionManager.sendMessage(completeMessage.toString(), session);
|
||||
} catch (OpenViduException e) {
|
||||
return SessionRestController.generateErrorResponse("\"to\" array has no valid connection identifiers", "/signal",
|
||||
HttpStatus.NOT_ACCEPTABLE);
|
||||
return SessionRestController.generateErrorResponse("\"to\" array has no valid connection identifiers",
|
||||
"/signal", HttpStatus.NOT_ACCEPTABLE);
|
||||
}
|
||||
|
||||
return new ResponseEntity<>(HttpStatus.OK);
|
||||
|
@ -729,8 +735,8 @@ public class SessionRestController {
|
|||
} else {
|
||||
log.error("Session {} is in the process of closing. Connection couldn't be created",
|
||||
session.getSessionId());
|
||||
return SessionRestController.generateErrorResponse("Session " + session.getSessionId() + " not found", REQUEST_PATH,
|
||||
HttpStatus.NOT_FOUND);
|
||||
return SessionRestController.generateErrorResponse("Session " + session.getSessionId() + " not found",
|
||||
REQUEST_PATH, HttpStatus.NOT_FOUND);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -761,10 +767,11 @@ public class SessionRestController {
|
|||
return new ResponseEntity<>(ipcamParticipant.toJson().toString(), RestUtils.getResponseHeaders(),
|
||||
HttpStatus.OK);
|
||||
} catch (MalformedURLException e) {
|
||||
return SessionRestController.generateErrorResponse("\"rtspUri\" parameter is not a valid rtsp uri", REQUEST_PATH,
|
||||
HttpStatus.BAD_REQUEST);
|
||||
return SessionRestController.generateErrorResponse("\"rtspUri\" parameter is not a valid rtsp uri",
|
||||
REQUEST_PATH, HttpStatus.BAD_REQUEST);
|
||||
} catch (Exception e) {
|
||||
return SessionRestController.generateErrorResponse(e.getMessage(), REQUEST_PATH, HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
return SessionRestController.generateErrorResponse(e.getMessage(), REQUEST_PATH,
|
||||
HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
} finally {
|
||||
session.closingLock.readLock().unlock();
|
||||
}
|
||||
|
|
|
@ -283,7 +283,7 @@ public class CustomHttpClient {
|
|||
return json;
|
||||
}
|
||||
|
||||
private String commonRestString(HttpMethod method, String path, String body, int status) throws Exception {
|
||||
public String commonRestString(HttpMethod method, String path, String body, int status) throws Exception {
|
||||
path = openviduUrl + (path.startsWith("/") ? path : ("/" + path));
|
||||
|
||||
HttpRequest.Builder builder = HttpRequest.newBuilder().uri(new URI(path));
|
||||
|
|
|
@ -4,6 +4,7 @@ import static org.junit.jupiter.api.Assertions.fail;
|
|||
|
||||
import java.awt.Point;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.nio.file.Files;
|
||||
|
@ -37,6 +38,7 @@ import org.openqa.selenium.Keys;
|
|||
import org.openqa.selenium.WebElement;
|
||||
import org.openqa.selenium.support.ui.ExpectedConditions;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.util.ResourceUtils;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonArray;
|
||||
|
@ -54,8 +56,10 @@ import io.openvidu.java.client.OpenVidu;
|
|||
import io.openvidu.java.client.OpenViduHttpException;
|
||||
import io.openvidu.java.client.OpenViduRole;
|
||||
import io.openvidu.java.client.Recording;
|
||||
import io.openvidu.java.client.RecordingProperties;
|
||||
import io.openvidu.java.client.Session;
|
||||
import io.openvidu.test.browsers.utils.CustomHttpClient;
|
||||
import io.openvidu.test.browsers.utils.RecordingUtils;
|
||||
import io.openvidu.test.browsers.utils.Unzipper;
|
||||
import io.openvidu.test.browsers.utils.webhook.CustomWebhook;
|
||||
|
||||
|
@ -228,6 +232,7 @@ public class OpenViduProTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
|
|||
io.openvidu.test.browsers.utils.webhook.CustomWebhook.main(new String[0], initLatch);
|
||||
|
||||
try {
|
||||
startRtmpServer();
|
||||
|
||||
if (!initLatch.await(30, TimeUnit.SECONDS)) {
|
||||
Assertions.fail("Timeout waiting for webhook springboot app to start");
|
||||
|
@ -250,8 +255,10 @@ public class OpenViduProTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
|
|||
|
||||
try {
|
||||
|
||||
Map<String, Object> newConfig = Map.of("OPENVIDU_WEBHOOK", true, "OPENVIDU_WEBHOOK_ENDPOINT",
|
||||
"http://127.0.0.1:7777/webhook", "OPENVIDU_RECORDING_AUTOSTOP_TIMEOUT", 0);
|
||||
Map<String, Object> newConfig = Map.of("OPENVIDU_PRO_NETWORK_QUALITY", false,
|
||||
"OPENVIDU_PRO_SPEECH_TO_TEXT", "disabled", "OPENVIDU_WEBHOOK", true,
|
||||
"OPENVIDU_WEBHOOK_ENDPOINT", "http://127.0.0.1:7777/webhook",
|
||||
"OPENVIDU_RECORDING_AUTOSTOP_TIMEOUT", 0);
|
||||
restartOpenViduServer(newConfig);
|
||||
|
||||
OpenViduTestappUser user = setupBrowserAndConnectToOpenViduTestapp("chrome");
|
||||
|
@ -274,7 +281,7 @@ public class OpenViduProTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
|
|||
|
||||
// disconnect: webrtcConnectionDestroyed, participantLeft (and subsequent
|
||||
// lastParticipantLeft triggered events for sessionDestroyed,
|
||||
// recordingStatusChanged, [broadcastStopped])
|
||||
// recordingStatusChanged, broadcastStopped)
|
||||
this.connectTwoUsers(user, restClient, false, true, true);
|
||||
// First user out
|
||||
user.getDriver().findElement(By.cssSelector("#openvidu-instance-0 .leave-btn")).click();
|
||||
|
@ -294,6 +301,8 @@ public class OpenViduProTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
|
|||
Assertions.assertEquals("lastParticipantLeft",
|
||||
CustomWebhook.waitForEvent("recordingStatusChanged", 2).get("reason").getAsString());
|
||||
}
|
||||
Assertions.assertEquals("lastParticipantLeft",
|
||||
CustomWebhook.waitForEvent("broadcastStopped", 2).get("reason").getAsString());
|
||||
Assertions.assertEquals("lastParticipantLeft",
|
||||
CustomWebhook.waitForEvent("sessionDestroyed", 2).get("reason").getAsString());
|
||||
CustomWebhook.events.values().forEach(collection -> Assertions.assertTrue(collection.isEmpty()));
|
||||
|
@ -324,7 +333,7 @@ public class OpenViduProTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
|
|||
CustomWebhook.events.values().forEach(collection -> Assertions.assertTrue(collection.isEmpty()));
|
||||
|
||||
// forceDisconnectByUser: webrtcConnectionDestroyed, participantLeft
|
||||
this.connectTwoUsers(user, restClient, true, true, true);
|
||||
this.connectTwoUsers(user, restClient, true, false, false);
|
||||
user.getDriver().findElement(By.cssSelector("#openvidu-instance-0 .force-disconnect-btn")).click();
|
||||
for (int i = 0; i < 3; i++) {
|
||||
Assertions.assertEquals("forceDisconnectByUser",
|
||||
|
@ -336,7 +345,7 @@ public class OpenViduProTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
|
|||
|
||||
// forceDisconnectByServer: webrtcConnectionDestroyed, participantLeft (and
|
||||
// subsequent lastParticipantLeft triggered events for sessionDestroyed,
|
||||
// recordingStatusChanged, [broadcastStopped])
|
||||
// recordingStatusChanged, broadcastStopped)
|
||||
this.connectTwoUsers(user, restClient, false, true, true);
|
||||
String[] connectionIds = restClient
|
||||
.rest(HttpMethod.GET, "/openvidu/api/sessions/TestSession", HttpURLConnection.HTTP_OK)
|
||||
|
@ -362,12 +371,14 @@ public class OpenViduProTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
|
|||
Assertions.assertEquals("lastParticipantLeft",
|
||||
CustomWebhook.waitForEvent("recordingStatusChanged", 2).get("reason").getAsString());
|
||||
}
|
||||
Assertions.assertEquals("lastParticipantLeft",
|
||||
CustomWebhook.waitForEvent("broadcastStopped", 2).get("reason").getAsString());
|
||||
Assertions.assertEquals("lastParticipantLeft",
|
||||
CustomWebhook.waitForEvent("sessionDestroyed", 2).get("reason").getAsString());
|
||||
CustomWebhook.events.values().forEach(collection -> Assertions.assertTrue(collection.isEmpty()));
|
||||
|
||||
// sessionClosedByServer: webrtcConnectionDestroyed, participantLeft,
|
||||
// sessionDestroyed, recordingStatusChanged
|
||||
// sessionDestroyed, recordingStatusChanged, broadcastStopped
|
||||
this.connectTwoUsers(user, restClient, false, true, true);
|
||||
restClient.rest(HttpMethod.DELETE, "/openvidu/api/sessions/TestSession",
|
||||
HttpURLConnection.HTTP_NO_CONTENT);
|
||||
|
@ -383,13 +394,15 @@ public class OpenViduProTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
|
|||
Assertions.assertEquals("sessionClosedByServer",
|
||||
CustomWebhook.waitForEvent("recordingStatusChanged", 2).get("reason").getAsString());
|
||||
}
|
||||
Assertions.assertEquals("sessionClosedByServer",
|
||||
CustomWebhook.waitForEvent("broadcastStopped", 2).get("reason").getAsString());
|
||||
Assertions.assertEquals("sessionClosedByServer",
|
||||
CustomWebhook.waitForEvent("sessionDestroyed", 2).get("reason").getAsString());
|
||||
CustomWebhook.events.values().forEach(collection -> Assertions.assertTrue(collection.isEmpty()));
|
||||
|
||||
// networkDisconnect: webrtcConnectionDestroyed, participantLeft (and
|
||||
// subsequent lastParticipantLeft triggered events for sessionDestroyed,
|
||||
// recordingStatusChanged, [broadcastStopped])
|
||||
// recordingStatusChanged, broadcastStopped)
|
||||
this.connectTwoUsers(user, restClient, false, true, true);
|
||||
// First user out
|
||||
user.getDriver().findElement(By.cssSelector("#openvidu-instance-0 .network-drop-btn")).click();
|
||||
|
@ -409,12 +422,14 @@ public class OpenViduProTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
|
|||
Assertions.assertEquals("lastParticipantLeft",
|
||||
CustomWebhook.waitForEvent("recordingStatusChanged", 2).get("reason").getAsString());
|
||||
}
|
||||
Assertions.assertEquals("lastParticipantLeft",
|
||||
CustomWebhook.waitForEvent("broadcastStopped", 2).get("reason").getAsString());
|
||||
Assertions.assertEquals("lastParticipantLeft",
|
||||
CustomWebhook.waitForEvent("sessionDestroyed", 2).get("reason").getAsString());
|
||||
CustomWebhook.events.values().forEach(collection -> Assertions.assertTrue(collection.isEmpty()));
|
||||
|
||||
// mediaServerDisconnect: webrtcConnectionDestroyed, participantLeft,
|
||||
// sessionDestroyed, recordingStatusChanged, [broadcastStopped]
|
||||
// sessionDestroyed, recordingStatusChanged, broadcastStopped
|
||||
this.connectTwoUsers(user, restClient, false, true, true);
|
||||
String mediaNodeId = restClient
|
||||
.rest(HttpMethod.GET, "/openvidu/api/media-nodes", HttpURLConnection.HTTP_OK).get("content")
|
||||
|
@ -435,6 +450,8 @@ public class OpenViduProTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
|
|||
Assertions.assertEquals("mediaServerDisconnect",
|
||||
CustomWebhook.waitForEvent("recordingStatusChanged", 4).get("reason").getAsString());
|
||||
}
|
||||
Assertions.assertEquals("mediaServerDisconnect",
|
||||
CustomWebhook.waitForEvent("broadcastStopped", 2).get("reason").getAsString());
|
||||
Assertions.assertEquals("mediaServerDisconnect",
|
||||
CustomWebhook.waitForEvent("sessionDestroyed", 2).get("reason").getAsString());
|
||||
CustomWebhook.waitForEvent("mediaNodeStatusChanged", 5);
|
||||
|
@ -449,7 +466,7 @@ public class OpenViduProTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
|
|||
MediaNodeDockerUtils.stopMediaServerInsideMediaNodeAndRecover(containerId, 400);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
Assertions.assertEquals("mediaServerReconnect",
|
||||
CustomWebhook.waitForEvent("webrtcConnectionDestroyed", 2).get("reason").getAsString());
|
||||
CustomWebhook.waitForEvent("webrtcConnectionDestroyed", 6).get("reason").getAsString());
|
||||
}
|
||||
for (int i = 0; i < 2; i++) {
|
||||
Assertions.assertEquals("mediaServerReconnect",
|
||||
|
@ -458,7 +475,7 @@ public class OpenViduProTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
|
|||
CustomWebhook.events.values().forEach(collection -> Assertions.assertTrue(collection.isEmpty()));
|
||||
|
||||
// nodeCrashed: webrtcConnectionDestroyed, participantLeft, sessionDestroyed,
|
||||
// recordingStatusChanged, [broadcastStopped]
|
||||
// recordingStatusChanged, broadcastStopped
|
||||
this.connectTwoUsers(user, restClient, false, true, true);
|
||||
containerId = restClient.rest(HttpMethod.GET, "/openvidu/api/media-nodes", HttpURLConnection.HTTP_OK)
|
||||
.get("content").getAsJsonArray().get(0).getAsJsonObject().get("environmentId").getAsString();
|
||||
|
@ -475,7 +492,9 @@ public class OpenViduProTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
|
|||
}
|
||||
// Only status "stopped" for recording. Not "ready" if node crash
|
||||
Assertions.assertEquals("nodeCrashed",
|
||||
CustomWebhook.waitForEvent("recordingStatusChanged", 2).get("reason").getAsString());
|
||||
CustomWebhook.waitForEvent("recordingStatusChanged", 10).get("reason").getAsString());
|
||||
Assertions.assertEquals("nodeCrashed",
|
||||
CustomWebhook.waitForEvent("broadcastStopped", 10).get("reason").getAsString());
|
||||
Assertions.assertEquals("nodeCrashed",
|
||||
CustomWebhook.waitForEvent("sessionDestroyed", 2).get("reason").getAsString());
|
||||
CustomWebhook.waitForEvent("mediaNodeStatusChanged", 2);
|
||||
|
@ -483,7 +502,7 @@ public class OpenViduProTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
|
|||
restartOpenViduServer(new HashMap<>(), true, HttpURLConnection.HTTP_OK);
|
||||
|
||||
// openviduServerStopped: webrtcConnectionDestroyed, participantLeft,
|
||||
// sessionDestroyed, recordingStatusChanged, [broadcastStopped]
|
||||
// sessionDestroyed, recordingStatusChanged, broadcastStopped
|
||||
this.connectTwoUsers(user, restClient, false, true, true);
|
||||
restartOpenViduServer(new HashMap<>(), true, HttpURLConnection.HTTP_OK);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
|
@ -498,6 +517,8 @@ public class OpenViduProTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
|
|||
Assertions.assertEquals("openviduServerStopped",
|
||||
CustomWebhook.waitForEvent("recordingStatusChanged", 4).get("reason").getAsString());
|
||||
}
|
||||
Assertions.assertEquals("openviduServerStopped",
|
||||
CustomWebhook.waitForEvent("broadcastStopped", 2).get("reason").getAsString());
|
||||
Assertions.assertEquals("openviduServerStopped",
|
||||
CustomWebhook.waitForEvent("sessionDestroyed", 2).get("reason").getAsString());
|
||||
for (int i = 0; i < 2; i++) {
|
||||
|
@ -523,11 +544,13 @@ public class OpenViduProTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
|
|||
Assertions.assertEquals("automaticStop",
|
||||
CustomWebhook.waitForEvent("recordingStatusChanged", 4).get("reason").getAsString());
|
||||
}
|
||||
Assertions.assertEquals("lastParticipantLeft",
|
||||
CustomWebhook.waitForEvent("broadcastStopped", 2).get("reason").getAsString());
|
||||
Assertions.assertEquals("automaticStop",
|
||||
CustomWebhook.waitForEvent("sessionDestroyed", 2).get("reason").getAsString());
|
||||
CustomWebhook.events.values().forEach(collection -> Assertions.assertTrue(collection.isEmpty()));
|
||||
|
||||
// recordingStoppedByServer
|
||||
// recordingStoppedByServer: recordingStatusChanged
|
||||
this.connectTwoUsers(user, restClient, false, true, true);
|
||||
String recordingId = restClient
|
||||
.rest(HttpMethod.GET, "/openvidu/api/recordings", HttpURLConnection.HTTP_OK).get("items")
|
||||
|
@ -541,8 +564,15 @@ public class OpenViduProTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
|
|||
Assertions.assertEquals("recordingStoppedByServer",
|
||||
CustomWebhook.waitForEvent("recordingStatusChanged", 4).get("reason").getAsString());
|
||||
}
|
||||
CustomWebhook.events.values().forEach(collection -> Assertions.assertTrue(collection.isEmpty()));
|
||||
|
||||
// [broadcastStoppedByServer]
|
||||
// broadcastStoppedByServer: broadcastStopped
|
||||
this.connectTwoUsers(user, restClient, false, true, true);
|
||||
restClient.rest(HttpMethod.POST, "/openvidu/api/broadcast/stop", "{'session':'TestSession'}",
|
||||
HttpURLConnection.HTTP_OK);
|
||||
Assertions.assertEquals("broadcastStoppedByServer",
|
||||
CustomWebhook.waitForEvent("broadcastStopped", 5).get("reason").getAsString());
|
||||
CustomWebhook.events.values().forEach(collection -> Assertions.assertTrue(collection.isEmpty()));
|
||||
|
||||
} finally {
|
||||
Map<String, Object> oldConfig = new HashMap<>();
|
||||
|
@ -557,6 +587,7 @@ public class OpenViduProTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
|
|||
}
|
||||
|
||||
} finally {
|
||||
stopRtmpServer();
|
||||
CustomWebhook.shutDown();
|
||||
}
|
||||
}
|
||||
|
@ -1053,6 +1084,54 @@ public class OpenViduProTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
|
|||
Assertions.assertTrue(connection.adaptativeBitrate() == null, "Wrong adaptativeBitrate property");
|
||||
Assertions.assertTrue(connection.onlyPlayWithSubscribers() == null, "Wrong onlyPlayWithSubscribers property");
|
||||
Assertions.assertTrue(connection.getNetworkCache() == null, "Wrong networkCache property");
|
||||
|
||||
try {
|
||||
startRtmpServer();
|
||||
// Start broadcast
|
||||
try {
|
||||
OV.startBroadcast("NOT_EXISTS", "rtmp://172.17.0.1/live");
|
||||
Assertions.fail("Expected OpenViduHttpException exception");
|
||||
} catch (OpenViduHttpException exception) {
|
||||
Assertions.assertEquals(HttpURLConnection.HTTP_NOT_FOUND, exception.getStatus(), "Wrong HTTP status");
|
||||
}
|
||||
try {
|
||||
OV.startBroadcast(session.getSessionId(), "rtmp://172.17.0.1/live");
|
||||
Assertions.fail("Expected OpenViduHttpException exception");
|
||||
} catch (OpenViduHttpException exception) {
|
||||
Assertions.assertEquals(HttpURLConnection.HTTP_NOT_ACCEPTABLE, exception.getStatus(),
|
||||
"Wrong HTTP status");
|
||||
}
|
||||
OpenViduTestappUser user = setupBrowserAndConnectToOpenViduTestapp("chrome");
|
||||
user.getDriver().findElement(By.id("add-user-btn")).click();
|
||||
user.getDriver().findElement(By.className("join-btn")).click();
|
||||
user.getEventManager().waitUntilEventReaches("streamCreated", 1);
|
||||
user.getEventManager().waitUntilEventReaches("streamPlaying", 1);
|
||||
|
||||
Assertions.assertTrue(OV.fetch());
|
||||
session = OV.getActiveSession("TestSession");
|
||||
Assertions.assertFalse(session.fetch());
|
||||
|
||||
OV.startBroadcast("TestSession", "rtmp://172.17.0.1/live",
|
||||
new RecordingProperties.Builder().resolution("1280x800").build());
|
||||
user.getEventManager().waitUntilEventReaches("broadcastStarted", 1);
|
||||
Assertions.assertFalse(session.fetch());
|
||||
Assertions.assertTrue(session.isBeingBroadcasted());
|
||||
|
||||
// Stop broadcast
|
||||
try {
|
||||
OV.stopBroadcast("NOT_EXISTS");
|
||||
Assertions.fail("Expected OpenViduHttpException exception");
|
||||
} catch (OpenViduHttpException exception) {
|
||||
Assertions.assertEquals(HttpURLConnection.HTTP_NOT_FOUND, exception.getStatus(), "Wrong HTTP status");
|
||||
}
|
||||
OV.stopBroadcast("TestSession");
|
||||
user.getEventManager().waitUntilEventReaches("broadcastStopped", 1);
|
||||
Assertions.assertFalse(session.fetch());
|
||||
Assertions.assertFalse(session.isBeingBroadcasted());
|
||||
|
||||
} finally {
|
||||
stopRtmpServer();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -1068,8 +1147,7 @@ public class OpenViduProTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
|
|||
OpenViduTestappUser user = setupBrowserAndConnectToOpenViduTestapp("chrome");
|
||||
user.getDriver().findElement(By.id("add-user-btn")).click();
|
||||
user.getDriver().findElement(By.className("join-btn")).click();
|
||||
|
||||
user.getEventManager().waitUntilEventReaches("connectionCreated", 1);
|
||||
user.getEventManager().waitUntilEventReaches("streamCreated", 1);
|
||||
user.getEventManager().waitUntilEventReaches("streamPlaying", 1);
|
||||
|
||||
CustomHttpClient restClient = new CustomHttpClient(OPENVIDU_URL, "OPENVIDUAPP", OPENVIDU_SECRET);
|
||||
|
@ -2721,6 +2799,240 @@ public class OpenViduProTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Successfull broadcast Test")
|
||||
void sucessfullBroadcastTest() throws Exception {
|
||||
|
||||
log.info("Successfull broadcast Test");
|
||||
|
||||
try {
|
||||
startRtmpServer();
|
||||
|
||||
OpenViduTestappUser user = setupBrowserAndConnectToOpenViduTestapp("chrome");
|
||||
user.getDriver().findElement(By.id("add-user-btn")).click();
|
||||
|
||||
user.getDriver().findElement(By.id("session-api-btn-0")).click();
|
||||
Thread.sleep(750);
|
||||
WebElement broadcastUrlField = user.getDriver().findElement(By.id("broadcasturl-id-field"));
|
||||
broadcastUrlField.clear();
|
||||
broadcastUrlField.sendKeys("rtmp://172.17.0.1/live");
|
||||
user.getDriver().findElement(By.id("start-broadcast-btn")).click();
|
||||
user.getWaiter()
|
||||
.until(ExpectedConditions.attributeToBe(By.id("api-response-text-area"), "value", "Error [404]"));
|
||||
|
||||
user.getDriver().findElement(By.id("list-sessions-btn")).click();
|
||||
user.getWaiter().until(ExpectedConditions.attributeContains(By.id("api-response-text-area"), "value",
|
||||
"Number: 0. Changes: false"));
|
||||
|
||||
user.getDriver().findElement(By.className("join-btn")).sendKeys(Keys.ENTER);
|
||||
user.getEventManager().waitUntilEventReaches("streamCreated", 1);
|
||||
user.getEventManager().waitUntilEventReaches("streamPlaying", 1);
|
||||
|
||||
user.getDriver().findElement(By.id("list-sessions-btn")).click();
|
||||
user.getWaiter().until(ExpectedConditions.attributeContains(By.id("api-response-text-area"), "value",
|
||||
"Number: 1. Changes: true"));
|
||||
|
||||
user.getDriver().findElement(By.id("start-broadcast-btn")).click();
|
||||
user.getWaiter().until(
|
||||
ExpectedConditions.attributeToBe(By.id("api-response-text-area"), "value", "Broadcast started"));
|
||||
user.getEventManager().waitUntilEventReaches("broadcastStarted", 1);
|
||||
|
||||
user.getDriver().findElement(By.id("list-sessions-btn")).click();
|
||||
user.getWaiter().until(ExpectedConditions.attributeContains(By.id("api-response-text-area"), "value",
|
||||
"Number: 1. Changes: false"));
|
||||
|
||||
checkRtmpRecordingIsFine(30);
|
||||
|
||||
user.getDriver().findElement(By.id("stop-broadcast-btn")).click();
|
||||
user.getWaiter().until(
|
||||
ExpectedConditions.attributeToBe(By.id("api-response-text-area"), "value", "Broadcast stopped"));
|
||||
user.getEventManager().waitUntilEventReaches("broadcastStopped", 1);
|
||||
|
||||
user.getDriver().findElement(By.id("list-sessions-btn")).click();
|
||||
user.getWaiter().until(ExpectedConditions.attributeContains(By.id("api-response-text-area"), "value",
|
||||
"Number: 1. Changes: false"));
|
||||
|
||||
gracefullyLeaveParticipants(user, 1);
|
||||
|
||||
} finally {
|
||||
stopRtmpServer();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Wrong broadcast Test")
|
||||
void wrongBroadcastTest() throws Exception {
|
||||
|
||||
log.info("Wrong broadcast Test");
|
||||
|
||||
try {
|
||||
startRtmpServer();
|
||||
|
||||
OpenViduTestappUser user = setupBrowserAndConnectToOpenViduTestapp("chrome");
|
||||
user.getDriver().findElement(By.id("add-user-btn")).click();
|
||||
user.getDriver().findElement(By.className("join-btn")).click();
|
||||
user.getEventManager().waitUntilEventReaches("streamCreated", 1);
|
||||
user.getEventManager().waitUntilEventReaches("streamPlaying", 1);
|
||||
|
||||
/** Start broadcast **/
|
||||
CustomHttpClient restClient = new CustomHttpClient(OPENVIDU_URL, "OPENVIDUAPP", OPENVIDU_SECRET);
|
||||
// 400
|
||||
String body = "{}";
|
||||
restClient.rest(HttpMethod.POST, "/openvidu/api/broadcast/start", body, HttpURLConnection.HTTP_BAD_REQUEST);
|
||||
body = "{'session':'TestSession'}";
|
||||
restClient.rest(HttpMethod.POST, "/openvidu/api/broadcast/start", body, HttpURLConnection.HTTP_BAD_REQUEST);
|
||||
body = "{'broadcastUrl':'rtmp://172.17.0.1/live'}";
|
||||
restClient.rest(HttpMethod.POST, "/openvidu/api/broadcast/start", body, HttpURLConnection.HTTP_BAD_REQUEST);
|
||||
body = "{'session':false,'broadcastUrl':'rtmp://172.17.0.1/live'}";
|
||||
restClient.rest(HttpMethod.POST, "/openvidu/api/broadcast/start", body, HttpURLConnection.HTTP_BAD_REQUEST);
|
||||
body = "{'session':'TestSession','broadcastUrl':123}";
|
||||
restClient.rest(HttpMethod.POST, "/openvidu/api/broadcast/start", body, HttpURLConnection.HTTP_BAD_REQUEST);
|
||||
body = "{'session':'TestSession','broadcastUrl':'NOT_A_URL'}";
|
||||
restClient.commonRestString(HttpMethod.POST, "/openvidu/api/broadcast/start", body,
|
||||
HttpURLConnection.HTTP_BAD_REQUEST);
|
||||
// 404
|
||||
body = "{'session':'NOT_EXISTS','broadcastUrl':'rtmp://172.17.0.1/live'}";
|
||||
restClient.rest(HttpMethod.POST, "/openvidu/api/broadcast/start", body, HttpURLConnection.HTTP_NOT_FOUND);
|
||||
// 406
|
||||
String notActiveSessionId = restClient
|
||||
.rest(HttpMethod.POST, "/openvidu/api/sessions", body, HttpURLConnection.HTTP_OK).get("id")
|
||||
.getAsString();
|
||||
body = "{'session':'" + notActiveSessionId + "','broadcastUrl':'rtmp://172.17.0.1/live'}";
|
||||
restClient.rest(HttpMethod.POST, "/openvidu/api/broadcast/start", body,
|
||||
HttpURLConnection.HTTP_NOT_ACCEPTABLE);
|
||||
// 422
|
||||
body = "{'session':'TestSession','broadcastUrl':'rtmp://172.17.0.1/live','resolution':'99x1280'}";
|
||||
restClient.rest(HttpMethod.POST, "/openvidu/api/broadcast/start", body, 422);
|
||||
// 500 (Connection refused)
|
||||
body = "{'session':'TestSession','broadcastUrl':'rtmps://172.17.0.1/live'}";
|
||||
String errorResponse = restClient.commonRestString(HttpMethod.POST, "/openvidu/api/broadcast/start", body,
|
||||
HttpURLConnection.HTTP_INTERNAL_ERROR);
|
||||
Assertions.assertTrue(
|
||||
errorResponse.contains("Cannot open connection")
|
||||
&& errorResponse.contains("rtmps://172.17.0.1/live: Connection refused"),
|
||||
"Broadcast error message does not contain expected message");
|
||||
// 500 (Input/output error)
|
||||
body = "{'session':'TestSession','broadcastUrl':'rtmp://not.exists'}";
|
||||
errorResponse = restClient.commonRestString(HttpMethod.POST, "/openvidu/api/broadcast/start", body,
|
||||
HttpURLConnection.HTTP_INTERNAL_ERROR);
|
||||
Assertions.assertTrue(errorResponse.contains("rtmp://not.exists: Input/output error"),
|
||||
"Broadcast error message does not contain expected message");
|
||||
// 500 (Protocol not found)
|
||||
body = "{'session':'TestSession','broadcastUrl':'schemefail://172.17.0.1/live'}";
|
||||
errorResponse = restClient.commonRestString(HttpMethod.POST, "/openvidu/api/broadcast/start", body,
|
||||
HttpURLConnection.HTTP_INTERNAL_ERROR);
|
||||
Assertions.assertTrue(errorResponse.contains("schemefail://172.17.0.1/live: Protocol not found"),
|
||||
"Broadcast error message does not contain expected message");
|
||||
// Concurrent broadcast
|
||||
final int PETITIONS = 10;
|
||||
List<String> responses = new ArrayList<>();
|
||||
List<Exception> exception = new ArrayList<>();
|
||||
CountDownLatch latch = new CountDownLatch(PETITIONS);
|
||||
body = "{'session':'TestSession','broadcastUrl':'rtmp://172.17.0.1/live'}";
|
||||
for (int i = 0; i < PETITIONS; i++) {
|
||||
new Thread(() -> {
|
||||
try {
|
||||
String response = restClient.commonRestString(HttpMethod.POST, "/openvidu/api/broadcast/start",
|
||||
"{'session':'TestSession','broadcastUrl':'rtmp://172.17.0.1/live'}",
|
||||
HttpURLConnection.HTTP_OK);
|
||||
responses.add(response);
|
||||
} catch (Exception e) {
|
||||
// 409
|
||||
exception.add(e);
|
||||
}
|
||||
latch.countDown();
|
||||
}).start();
|
||||
}
|
||||
if (!latch.await(30, TimeUnit.SECONDS)) {
|
||||
Assertions.fail("Concurrent start of broadcasts did not return in timeout");
|
||||
}
|
||||
Assertions.assertEquals(PETITIONS - 1, exception.size(), "Wrong number of councurrent started broadcasts");
|
||||
// 409
|
||||
restClient.commonRestString(HttpMethod.POST, "/openvidu/api/broadcast/start", body,
|
||||
HttpURLConnection.HTTP_CONFLICT);
|
||||
|
||||
user.getEventManager().waitUntilEventReaches("broadcastStarted", 1);
|
||||
checkRtmpRecordingIsFine(30);
|
||||
|
||||
/** Stop broadcast **/
|
||||
// 400
|
||||
body = "{}";
|
||||
restClient.rest(HttpMethod.POST, "/openvidu/api/broadcast/stop", body, HttpURLConnection.HTTP_BAD_REQUEST);
|
||||
body = "{'session':123}";
|
||||
restClient.rest(HttpMethod.POST, "/openvidu/api/broadcast/stop", body, HttpURLConnection.HTTP_BAD_REQUEST);
|
||||
// 404
|
||||
body = "{'session':'NOT_EXISTS'}";
|
||||
restClient.rest(HttpMethod.POST, "/openvidu/api/broadcast/stop", body, HttpURLConnection.HTTP_NOT_FOUND);
|
||||
// 200
|
||||
body = "{'session':'TestSession'}";
|
||||
restClient.rest(HttpMethod.POST, "/openvidu/api/broadcast/stop", body, HttpURLConnection.HTTP_OK);
|
||||
user.getEventManager().waitUntilEventReaches("broadcastStopped", 1);
|
||||
// 409
|
||||
body = "{'session':'TestSession'}";
|
||||
restClient.rest(HttpMethod.POST, "/openvidu/api/broadcast/stop", body, HttpURLConnection.HTTP_CONFLICT);
|
||||
|
||||
gracefullyLeaveParticipants(user, 1);
|
||||
|
||||
} finally {
|
||||
stopRtmpServer();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Broadcast and composed recording test")
|
||||
void broadcastAndComposedRecordingTest() throws Exception {
|
||||
|
||||
log.info("Broadcast and composed recording test");
|
||||
|
||||
try {
|
||||
startRtmpServer();
|
||||
|
||||
} finally {
|
||||
stopRtmpServer();
|
||||
}
|
||||
}
|
||||
|
||||
// https://github.com/tiangolo/nginx-rtmp-docker
|
||||
private void startRtmpServer() throws FileNotFoundException {
|
||||
File file = ResourceUtils.getFile("classpath:broadcast-nginx.conf");
|
||||
String dockerRunCommand = "docker run -d --name broadcast-nginx -p 1935:1935 -v " + file.getAbsolutePath()
|
||||
+ ":/etc/nginx/nginx.conf tiangolo/nginx-rtmp";
|
||||
commandLine.executeCommand(dockerRunCommand, 10);
|
||||
}
|
||||
|
||||
private void stopRtmpServer() {
|
||||
String dockerRemoveCommand = "docker rm -f broadcast-nginx";
|
||||
commandLine.executeCommand(dockerRemoveCommand, 10);
|
||||
}
|
||||
|
||||
private void checkRtmpRecordingIsFine(long secondsTimeout) throws InterruptedException {
|
||||
final String broadcastRecordingPath = "/opt/openvidu/recordings";
|
||||
final String cleanBroadcastPath = "rm -rf " + broadcastRecordingPath + "/tmp";
|
||||
try {
|
||||
final long startTime = System.currentTimeMillis();
|
||||
while (false || ((System.currentTimeMillis() - startTime) < (secondsTimeout * 1000))) {
|
||||
commandLine.executeCommand(cleanBroadcastPath, 10);
|
||||
commandLine.executeCommand("docker cp broadcast-nginx:/tmp " + broadcastRecordingPath, 30);
|
||||
commandLine.executeCommand("ffmpeg -i " + broadcastRecordingPath + "/tmp/*.flv -vframes 1 "
|
||||
+ broadcastRecordingPath + "/tmp/rtmp-screenshot.jpg", 30);
|
||||
File screenshot = new File(broadcastRecordingPath + "/tmp/rtmp-screenshot.jpg");
|
||||
if (screenshot.exists() && screenshot.isFile() && screenshot.length() > 0 && screenshot.canRead()) {
|
||||
Assertions.assertTrue(
|
||||
this.recordingUtils.thumbnailIsFine(screenshot, RecordingUtils::checkVideoAverageRgbGreen),
|
||||
"RTMP screenshot " + screenshot.getAbsolutePath() + " is not fine");
|
||||
break;
|
||||
}
|
||||
log.info("RTMP screenshot could not be generated yet. Trying again");
|
||||
Thread.sleep(1000);
|
||||
}
|
||||
if ((System.currentTimeMillis() - startTime) >= (secondsTimeout * 1000)) {
|
||||
Assertions.fail("Timeout of " + secondsTimeout + " seconds elapsed waiting for RTMP sreenshot");
|
||||
}
|
||||
} finally {
|
||||
commandLine.executeCommand(cleanBroadcastPath, 10);
|
||||
}
|
||||
}
|
||||
|
||||
private String getOwnConnectionId(OpenViduTestappUser user, int numberOfUser) {
|
||||
return user.getWaiter().until(d -> {
|
||||
List<WebElement> firstOpenviduEvent = d.findElements(By.cssSelector(
|
||||
|
@ -2935,7 +3247,10 @@ public class OpenViduProTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
|
|||
CustomWebhook.waitForEvent("recordingStatusChanged", 3).get("status").getAsString());
|
||||
}
|
||||
if (startBroadcast) {
|
||||
|
||||
restClient.rest(HttpMethod.POST, "/openvidu/api/broadcast/start",
|
||||
"{'session':'TestSession','broadcastUrl':'rtmp://172.17.0.1/live'}", HttpURLConnection.HTTP_OK);
|
||||
user.getEventManager().waitUntilEventReaches("broadcastStarted", 2);
|
||||
CustomWebhook.waitForEvent("broadcastStarted", 3);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
worker_processes auto;
|
||||
rtmp_auto_push on;
|
||||
events {}
|
||||
rtmp {
|
||||
server {
|
||||
listen 1935;
|
||||
listen [::]:1935 ipv6only=on;
|
||||
application live {
|
||||
live on;
|
||||
recorder all {
|
||||
record video;
|
||||
record_path /tmp;
|
||||
record_max_size 100000K;
|
||||
record_unique on;
|
||||
record_suffix rtmp.flv;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue