openvidu-server: allow only-audio broadcasting. Add new test

pull/803/head
pabloFuente 2023-04-26 18:46:35 +02:00
parent f5e18fc11d
commit b40f120efa
8 changed files with 95 additions and 25 deletions

View File

@ -716,8 +716,7 @@ public class RecordingProperties {
* @hidden
*/
public final static Map<String, ?> removeNonBroadcastProperties(Map<String, ?> params) {
List<String> nonBroadcastProps = Arrays
.asList(new String[] { "outputMode", "name", "hasVideo", "ignoreFailedStreams" });
List<String> nonBroadcastProps = Arrays.asList(new String[] { "outputMode", "name", "ignoreFailedStreams" });
nonBroadcastProps.forEach(p -> params.remove(p));
return params;
}

View File

@ -2867,6 +2867,67 @@ public class OpenViduProTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
}
}
@Test
@DisplayName("Successfull only video only audio broadcast Test")
void sucessfullBroadcastOnlyVideoOnlyAudioTest() throws Exception {
log.info("Successfull only video only audio broadcast Test");
try {
String BROADCAST_IP = TestUtils.startRtmpServer();
OpenViduTestappUser user = setupBrowserAndConnectToOpenViduTestapp("chrome");
user.getDriver().findElement(By.id("add-user-btn")).click();
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("session-api-btn-0")).click();
Thread.sleep(750);
WebElement broadcastUrlField = user.getDriver().findElement(By.id("broadcasturl-id-field"));
broadcastUrlField.clear();
broadcastUrlField.sendKeys("rtmp://" + BROADCAST_IP + "/live");
user.getDriver().findElement(By.id("broadcast-properties-btn")).click();
Thread.sleep(500);
// Only video
user.getDriver().findElement(By.id("rec-hasaudio-checkbox")).click();
Thread.sleep(500);
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);
checkRtmpRecordingIsFine(30, RecordingUtils::checkVideoAverageRgbGreen);
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);
// Only audio
user.getDriver().findElement(By.id("rec-hasaudio-checkbox")).click();
user.getDriver().findElement(By.id("rec-hasvideo-checkbox")).click();
Thread.sleep(500);
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("stop-broadcast-btn")).click();
user.getWaiter().until(
ExpectedConditions.attributeToBe(By.id("api-response-text-area"), "value", "Broadcast stopped"));
user.getEventManager().waitUntilEventReaches("broadcastStopped", 1);
gracefullyLeaveParticipants(user, 1);
} finally {
TestUtils.stopRtmpServer();
}
}
@Test
@DisplayName("Wrong broadcast Test")
void wrongBroadcastTest() throws Exception {
@ -2911,6 +2972,9 @@ public class OpenViduProTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
// 422
body = "{'session':'TestSession','broadcastUrl':'rtmp://" + BROADCAST_IP + "/live','resolution':'99x1280'}";
restClient.rest(HttpMethod.POST, "/openvidu/api/broadcast/start", body, 422);
body = "{'session':'TestSession','broadcastUrl':'rtmp://" + BROADCAST_IP
+ "/live','hasAudio':false,'hasVideo':false}";
restClient.rest(HttpMethod.POST, "/openvidu/api/broadcast/start", body, 422);
// 500 (Connection refused)
body = "{'session':'TestSession','broadcastUrl':'rtmps://" + BROADCAST_IP + "/live'}";
String errorResponse = restClient.commonRestString(HttpMethod.POST, "/openvidu/api/broadcast/start", body,
@ -3085,7 +3149,16 @@ public class OpenViduProTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
// Analyze most recent file (there can be more than one in the path)
File[] files = new File(broadcastRecordingPath + "/tmp").listFiles();
Arrays.sort(files, Comparator.comparingLong(File::lastModified).reversed());
commandLine.executeCommand("ffmpeg -i " + files[0].getAbsolutePath() + " -vframes 1 "
// This fixes corrupted video files
String fixedFile = broadcastRecordingPath + "/tmp/test.flv";
commandLine.executeCommand(
"ffmpeg -i " + files[0].getAbsolutePath() + " -acodec copy -vcodec copy " + fixedFile, 10);
// This obtains the middle duration of the video
String videoDuration = commandLine.executeCommand(
"ffprobe -loglevel error -of csv=p=0 -show_entries format=duration " + fixedFile, 3);
float halfDuration = (float) (Float.parseFloat(videoDuration) * 0.5);
// This retrieves the frame from the middle of the video
commandLine.executeCommand("ffmpeg -ss " + halfDuration + " -i " + fixedFile + " -vframes 1 "
+ broadcastRecordingPath + "/tmp/rtmp-screenshot.jpg", 3);
File screenshot = new File(broadcastRecordingPath + "/tmp/rtmp-screenshot.jpg");
if (screenshot.exists() && screenshot.isFile() && screenshot.length() > 0 && screenshot.canRead()) {

View File

@ -17,8 +17,7 @@
</mat-form-field>
<div class="inner-text-input mat-form-field">
<mat-checkbox id="rec-hasaudio-checkbox" [(ngModel)]="recordingProperties.hasAudio">Has audio</mat-checkbox>
<mat-checkbox *ngIf="!isBroadcast" id="rec-hasvideo-checkbox" [(ngModel)]="recordingProperties.hasVideo">Has
video</mat-checkbox>
<mat-checkbox id="rec-hasvideo-checkbox" [(ngModel)]="recordingProperties.hasVideo">Has video</mat-checkbox>
<mat-checkbox *ngIf="recordingProperties.outputMode === 'INDIVIDUAL'" id="rec-ignorefailedstreams-checkbox"
[(ngModel)]="recordingProperties.ignoreFailedStreams">Ignore failed streams</mat-checkbox>
</div>

View File

@ -11,22 +11,12 @@ export class RecordingPropertiesComponent {
@Input()
isBroadcast = false;
@Input()
recordingProperties: RecordingProperties;
recMode = Recording.OutputMode;
recLayouts = RecordingLayout;
getRecordingProperties: RecordingProperties;
@Output() recordingPropertiesChange: EventEmitter<RecordingProperties> = new EventEmitter<RecordingProperties>();
@Input()
get recordingProperties(): RecordingProperties {
return this.getRecordingProperties;
}
set recordingProperties(value: RecordingProperties) {
this.getRecordingProperties = value;
this.recordingPropertiesChange.emit(this.getRecordingProperties);
}
enumToArray(enumerator: any) {
return Object.keys(enumerator);
}

View File

@ -77,7 +77,8 @@
aria-label="Recording properties">
{{recPropertiesIcon}}</mat-icon>
</button>
<app-recording-properties *ngIf="showRecProperties" [(recordingProperties)]="recordingProperties">
<app-recording-properties *ngIf="showRecProperties" [isBroadcast]="false"
[recordingProperties]="recordingProperties">
</app-recording-properties>
</div>
<div>
@ -106,7 +107,8 @@
<mat-icon style="font-size: 18px; line-height: 18px; width: 18px; height: 18px"
aria-label="Broadcast properties">{{broadcastPropertiesIcon}}</mat-icon>
</button>
<app-recording-properties *ngIf="showBroadcastProperties" [isBroadcast]="true" [(recordingProperties)]="broadcastProperties">
<app-recording-properties *ngIf="showBroadcastProperties" [isBroadcast]="true"
[recordingProperties]="broadcastProperties">
</app-recording-properties>
</div>
@ -120,6 +122,6 @@
</mat-dialog-content>
<mat-dialog-actions>
<button mat-button id="close-dialog-btn"
[mat-dialog-close]="{session: session, recordingProperties: recordingProperties}">CLOSE</button>
[mat-dialog-close]="{session: session, recordingProperties: recordingProperties, broadcastProperties: broadcastProperties}">CLOSE</button>
</mat-dialog-actions>
</div>

View File

@ -248,11 +248,15 @@ export class SessionApiDialogComponent {
toggleRecProperties() {
this.showRecProperties = !this.showRecProperties;
this.recPropertiesIcon = this.showRecProperties ? 'remove_circle' : 'add_circle';
this.showBroadcastProperties = false;
this.broadcastPropertiesIcon = 'add_circle';
}
toggleBroadcastProperties() {
this.showBroadcastProperties = !this.showBroadcastProperties;
this.broadcastPropertiesIcon = this.showBroadcastProperties ? 'remove_circle' : 'add_circle';
this.showRecProperties = false;
this.recPropertiesIcon = 'add_circle';
}
changedNumIceServers(numIceServers: number) {

View File

@ -20,7 +20,7 @@
</mat-select>
</mat-form-field>
<app-recording-properties [(recordingProperties)]="sessionProperties.defaultRecordingProperties">
<app-recording-properties [recordingProperties]="sessionProperties.defaultRecordingProperties">
</app-recording-properties>
<div id="allow-transcoding-checkbox-div">

View File

@ -649,13 +649,15 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
}
openSessionApiDialog() {
const defaultRecordingProperties = JSON.parse(JSON.stringify(this.sessionProperties.defaultRecordingProperties));
const defaultBroadcastProperties = JSON.parse(JSON.stringify(this.sessionProperties.defaultRecordingProperties));
const dialogRef = this.dialog.open(SessionApiDialogComponent, {
data: {
openVidu: !!this.OV_NodeClient ? this.OV_NodeClient : new OpenViduAPI(this.openviduUrl, this.openviduSecret),
session: this.sessionAPI,
sessionId: !!this.session ? this.session.sessionId : this.sessionName,
recordingProperties: !!this.recordingProperties ? this.recordingProperties : this.sessionProperties.defaultRecordingProperties,
broadcastProperties: !!this.broadcastProperties ? this.broadcastProperties : this.sessionProperties.defaultRecordingProperties
recordingProperties: !!this.recordingProperties ? this.recordingProperties : defaultRecordingProperties,
broadcastProperties: !!this.broadcastProperties ? this.broadcastProperties : defaultBroadcastProperties
},
disableClose: true
});
@ -665,6 +667,7 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
delete this.sessionAPI;
}
this.recordingProperties = result.recordingProperties;
this.broadcastProperties = result.broadcastProperties;
document.getElementById('session-api-btn-' + this.index).classList.remove('cdk-program-focused');
});
}