openvidu-test-e2e: add reliable and lossy data packet tests

pull/894/head
pabloFuente 2026-04-21 19:04:51 +02:00
parent 05209f1d97
commit 7907fc40e5
8 changed files with 164 additions and 68 deletions

View File

@ -24,6 +24,7 @@ import java.time.Duration;
import java.util.AbstractMap; import java.util.AbstractMap;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
@ -164,10 +165,26 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
} }
@Test @Test
@DisplayName("Signal") @DisplayName("Signal Reliable DataChannel")
void signalTest() throws Exception { void signalReliableTest() throws Exception {
OpenViduTestappUser user = setupBrowserAndConnectToOpenViduTestapp("chrome"); OpenViduTestappUser user = setupBrowserAndConnectToOpenViduTestapp("chrome");
log.info("Signal"); log.info("Signal Reliable DataChannel");
signalReliableLossyAux(user, true);
}
@Test
@DisplayName("Signal Lossy DataChannel")
void signalLossyTest() throws Exception {
OpenViduTestappUser user = setupBrowserAndConnectToOpenViduTestapp("chrome");
log.info("Signal Lossy DataChannel");
signalReliableLossyAux(user, false);
}
private void signalReliableLossyAux(OpenViduTestappUser user, boolean reliable) throws Exception {
final int expectedKind = reliable ? 0 : 1; // DataPacket_Kind: RELIABLE=0, LOSSY=1
final String expectedKindStr = reliable ? "RELIABLE" : "LOSSY";
final String btnClass = reliable ? ".message-reliable-btn" : ".message-lossy-btn";
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++) {
WebElement addUserBtn = user.getDriver().findElement(By.id("add-user-btn")); WebElement addUserBtn = user.getDriver().findElement(By.id("add-user-btn"));
addUserBtn.click(); addUserBtn.click();
@ -181,129 +198,156 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
user.getEventManager().waitUntilEventReaches("participantConnected", "RoomEvent", 1); user.getEventManager().waitUntilEventReaches("participantConnected", "RoomEvent", 1);
user.getEventManager().waitUntilEventReaches("participantActive", "RoomEvent", 1); user.getEventManager().waitUntilEventReaches("participantActive", "RoomEvent", 1);
// Broadcast signal
Collection<Entry<String, String>> assertions = new ArrayList<>(); Collection<Entry<String, String>> assertions = new ArrayList<>();
List<Integer> kindAssertions = Collections.synchronizedList(new ArrayList<>());
// Broadcast from TestParticipant0 // Broadcast from TestParticipant0
final CountDownLatch signalEventLatch1 = new CountDownLatch(2); final CountDownLatch broadcastLatch0 = new CountDownLatch(2);
user.getEventManager().on(1, "dataReceived", "RoomEvent", json -> { user.getEventManager().on(1, "dataReceived", "RoomEvent", json -> {
assertions.add(new AbstractMap.SimpleEntry<>("Message from TestParticipant0 to all room", assertions.add(new AbstractMap.SimpleEntry<>(
"Message from TestParticipant0 to all room (kind: " + expectedKindStr + ")",
json.getAsJsonObject().get("eventDescription").getAsString())); json.getAsJsonObject().get("eventDescription").getAsString()));
signalEventLatch1.countDown(); kindAssertions.add(json.getAsJsonObject().get("eventContent").getAsJsonObject().get("kind").getAsInt());
broadcastLatch0.countDown();
}); });
user.getEventManager().on(1, "dataReceived", "ParticipantEvent", json -> { user.getEventManager().on(1, "dataReceived", "ParticipantEvent", json -> {
assertions.add(new AbstractMap.SimpleEntry<>("Message from TestParticipant0 to all room", assertions.add(new AbstractMap.SimpleEntry<>(
"Message from TestParticipant0 to all room (kind: " + expectedKindStr + ")",
json.getAsJsonObject().get("eventDescription").getAsString())); json.getAsJsonObject().get("eventDescription").getAsString()));
signalEventLatch1.countDown(); kindAssertions.add(json.getAsJsonObject().get("eventContent").getAsJsonObject().get("kind").getAsInt());
broadcastLatch0.countDown();
}); });
user.getDriver().findElement(By.cssSelector("#openvidu-instance-0 .message-btn")).click(); user.getDriver().findElement(By.cssSelector("#openvidu-instance-0 " + btnClass)).click();
user.getEventManager().waitUntilEventReaches(1, "dataReceived", "RoomEvent", 1); user.getEventManager().waitUntilEventReaches(1, "dataReceived", "RoomEvent", 1);
user.getEventManager().waitUntilEventReaches(1, "dataReceived", "ParticipantEvent", 1); user.getEventManager().waitUntilEventReaches(1, "dataReceived", "ParticipantEvent", 1);
// Do not trigger own signals // Do not trigger own signals
Assertions.assertEquals(0, user.getEventManager().getNumEvents(0, "dataReceived-RoomEvent").get()); Assertions.assertEquals(0, user.getEventManager().getNumEvents(0, "dataReceived-RoomEvent").get());
Assertions.assertEquals(0, user.getEventManager().getNumEvents(0, "dataReceived-ParticipantEvent").get()); Assertions.assertEquals(0, user.getEventManager().getNumEvents(0, "dataReceived-ParticipantEvent").get());
if (!signalEventLatch1.await(3, TimeUnit.SECONDS)) { if (!broadcastLatch0.await(3, TimeUnit.SECONDS)) {
Assertions.fail("Timeout waiting for signal event content check"); Assertions.fail("Timeout waiting for broadcast signal event from TestParticipant0");
} }
assertions.forEach(assertion -> Assertions.assertEquals(assertion.getKey(), assertion.getValue())); assertions.forEach(assertion -> Assertions.assertEquals(assertion.getKey(), assertion.getValue()));
kindAssertions.forEach(
kind -> Assertions.assertEquals(expectedKind, kind, "Expected DataPacket_Kind " + expectedKind));
user.getEventManager().off(1, "dataReceived", "RoomEvent"); user.getEventManager().off(1, "dataReceived", "RoomEvent");
user.getEventManager().off(1, "dataReceived", "ParticipantEvent"); user.getEventManager().off(1, "dataReceived", "ParticipantEvent");
assertions.clear(); assertions.clear();
kindAssertions.clear();
user.getEventManager().clearAllCurrentEvents(); user.getEventManager().clearAllCurrentEvents();
// Broadcast from TestParticipant1 // Broadcast from TestParticipant1
final CountDownLatch signalEventLatch2 = new CountDownLatch(2); final CountDownLatch broadcastLatch1 = new CountDownLatch(2);
user.getEventManager().on(0, "dataReceived", "RoomEvent", json -> { user.getEventManager().on(0, "dataReceived", "RoomEvent", json -> {
assertions.add(new AbstractMap.SimpleEntry<>("Message from TestParticipant1 to all room", assertions.add(new AbstractMap.SimpleEntry<>(
"Message from TestParticipant1 to all room (kind: " + expectedKindStr + ")",
json.getAsJsonObject().get("eventDescription").getAsString())); json.getAsJsonObject().get("eventDescription").getAsString()));
signalEventLatch2.countDown(); kindAssertions.add(json.getAsJsonObject().get("eventContent").getAsJsonObject().get("kind").getAsInt());
broadcastLatch1.countDown();
}); });
user.getEventManager().on(0, "dataReceived", "ParticipantEvent", json -> { user.getEventManager().on(0, "dataReceived", "ParticipantEvent", json -> {
assertions.add(new AbstractMap.SimpleEntry<>("Message from TestParticipant1 to all room", assertions.add(new AbstractMap.SimpleEntry<>(
"Message from TestParticipant1 to all room (kind: " + expectedKindStr + ")",
json.getAsJsonObject().get("eventDescription").getAsString())); json.getAsJsonObject().get("eventDescription").getAsString()));
signalEventLatch2.countDown(); kindAssertions.add(json.getAsJsonObject().get("eventContent").getAsJsonObject().get("kind").getAsInt());
broadcastLatch1.countDown();
}); });
user.getDriver().findElement(By.cssSelector("#openvidu-instance-1 .message-btn")).click(); user.getDriver().findElement(By.cssSelector("#openvidu-instance-1 " + btnClass)).click();
user.getEventManager().waitUntilEventReaches(0, "dataReceived", "RoomEvent", 1); user.getEventManager().waitUntilEventReaches(0, "dataReceived", "RoomEvent", 1);
user.getEventManager().waitUntilEventReaches(0, "dataReceived", "ParticipantEvent", 1); user.getEventManager().waitUntilEventReaches(0, "dataReceived", "ParticipantEvent", 1);
// Do not trigger own signals // Do not trigger own signals
Assertions.assertEquals(1, user.getEventManager().getNumEvents(0, "dataReceived-RoomEvent").get()); Assertions.assertEquals(1, user.getEventManager().getNumEvents(0, "dataReceived-RoomEvent").get());
Assertions.assertEquals(1, user.getEventManager().getNumEvents(0, "dataReceived-ParticipantEvent").get()); Assertions.assertEquals(1, user.getEventManager().getNumEvents(0, "dataReceived-ParticipantEvent").get());
if (!signalEventLatch2.await(3, TimeUnit.SECONDS)) { if (!broadcastLatch1.await(3, TimeUnit.SECONDS)) {
Assertions.fail("Timeout waiting for signal event content check"); Assertions.fail("Timeout waiting for broadcast signal event from TestParticipant1");
} }
assertions.forEach(assertion -> Assertions.assertEquals(assertion.getKey(), assertion.getValue())); assertions.forEach(assertion -> Assertions.assertEquals(assertion.getKey(), assertion.getValue()));
kindAssertions.forEach(
kind -> Assertions.assertEquals(expectedKind, kind, "Expected DataPacket_Kind " + expectedKind));
user.getEventManager().off(0, "dataReceived", "RoomEvent"); user.getEventManager().off(0, "dataReceived", "RoomEvent");
user.getEventManager().off(0, "dataReceived", "ParticipantEvent"); user.getEventManager().off(0, "dataReceived", "ParticipantEvent");
assertions.clear(); assertions.clear();
kindAssertions.clear();
user.getEventManager().clearAllCurrentEvents(); user.getEventManager().clearAllCurrentEvents();
// Signal specific participant // Signal specific participant
// Signal from TestParticipant0 to TestParticipant1 // Signal from TestParticipant0 to TestParticipant1
final CountDownLatch signalEventLatch3 = new CountDownLatch(2); final CountDownLatch directLatch0 = new CountDownLatch(2);
user.getEventManager().on(1, "dataReceived", "RoomEvent", json -> { user.getEventManager().on(1, "dataReceived", "RoomEvent", json -> {
assertions.add(new AbstractMap.SimpleEntry<>("Message from TestParticipant0 to TestParticipant1", assertions.add(new AbstractMap.SimpleEntry<>(
"Message from TestParticipant0 to TestParticipant1 (kind: " + expectedKindStr + ")",
json.getAsJsonObject().get("eventDescription").getAsString())); json.getAsJsonObject().get("eventDescription").getAsString()));
signalEventLatch3.countDown(); kindAssertions.add(json.getAsJsonObject().get("eventContent").getAsJsonObject().get("kind").getAsInt());
directLatch0.countDown();
}); });
user.getEventManager().on(1, "dataReceived", "ParticipantEvent", json -> { user.getEventManager().on(1, "dataReceived", "ParticipantEvent", json -> {
assertions.add(new AbstractMap.SimpleEntry<>("Message from TestParticipant0 to TestParticipant1", assertions.add(new AbstractMap.SimpleEntry<>(
"Message from TestParticipant0 to TestParticipant1 (kind: " + expectedKindStr + ")",
json.getAsJsonObject().get("eventDescription").getAsString())); json.getAsJsonObject().get("eventDescription").getAsString()));
signalEventLatch3.countDown(); kindAssertions.add(json.getAsJsonObject().get("eventContent").getAsJsonObject().get("kind").getAsInt());
directLatch0.countDown();
}); });
user.getDriver() user.getDriver()
.findElement(By.cssSelector("#openvidu-instance-0 app-participant.remote-participant .message-btn")) .findElement(
By.cssSelector("#openvidu-instance-0 app-participant.remote-participant " + btnClass))
.click(); .click();
user.getEventManager().waitUntilEventReaches(1, "dataReceived", "RoomEvent", 1); user.getEventManager().waitUntilEventReaches(1, "dataReceived", "RoomEvent", 1);
user.getEventManager().waitUntilEventReaches(1, "dataReceived", "ParticipantEvent", 1); user.getEventManager().waitUntilEventReaches(1, "dataReceived", "ParticipantEvent", 1);
// Do not trigger own signals // Do not trigger own signals
Assertions.assertEquals(0, user.getEventManager().getNumEvents(0, "dataReceived-RoomEvent").get()); Assertions.assertEquals(0, user.getEventManager().getNumEvents(0, "dataReceived-RoomEvent").get());
Assertions.assertEquals(0, user.getEventManager().getNumEvents(0, "dataReceived-ParticipantEvent").get()); Assertions.assertEquals(0, user.getEventManager().getNumEvents(0, "dataReceived-ParticipantEvent").get());
if (!signalEventLatch3.await(3, TimeUnit.SECONDS)) { if (!directLatch0.await(3, TimeUnit.SECONDS)) {
Assertions.fail("Timeout waiting for signal event content check"); Assertions.fail("Timeout waiting for direct signal event from TestParticipant0");
} }
assertions.forEach(assertion -> Assertions.assertEquals(assertion.getKey(), assertion.getValue())); assertions.forEach(assertion -> Assertions.assertEquals(assertion.getKey(), assertion.getValue()));
kindAssertions.forEach(
kind -> Assertions.assertEquals(expectedKind, kind, "Expected DataPacket_Kind " + expectedKind));
user.getEventManager().off(1, "dataReceived", "RoomEvent"); user.getEventManager().off(1, "dataReceived", "RoomEvent");
user.getEventManager().off(1, "dataReceived", "ParticipantEvent"); user.getEventManager().off(1, "dataReceived", "ParticipantEvent");
assertions.clear(); assertions.clear();
kindAssertions.clear();
user.getEventManager().clearAllCurrentEvents(); user.getEventManager().clearAllCurrentEvents();
// Signal from TestParticipant1 to TestParticipant0 // Signal from TestParticipant1 to TestParticipant0
final CountDownLatch signalEventLatch4 = new CountDownLatch(2); final CountDownLatch directLatch1 = new CountDownLatch(2);
user.getEventManager().on(0, "dataReceived", "RoomEvent", json -> { user.getEventManager().on(0, "dataReceived", "RoomEvent", json -> {
assertions.add(new AbstractMap.SimpleEntry<>("Message from TestParticipant1 to TestParticipant0", assertions.add(new AbstractMap.SimpleEntry<>(
"Message from TestParticipant1 to TestParticipant0 (kind: " + expectedKindStr + ")",
json.getAsJsonObject().get("eventDescription").getAsString())); json.getAsJsonObject().get("eventDescription").getAsString()));
signalEventLatch4.countDown(); kindAssertions.add(json.getAsJsonObject().get("eventContent").getAsJsonObject().get("kind").getAsInt());
directLatch1.countDown();
}); });
user.getEventManager().on(0, "dataReceived", "ParticipantEvent", json -> { user.getEventManager().on(0, "dataReceived", "ParticipantEvent", json -> {
assertions.add(new AbstractMap.SimpleEntry<>("Message from TestParticipant1 to TestParticipant0", assertions.add(new AbstractMap.SimpleEntry<>(
"Message from TestParticipant1 to TestParticipant0 (kind: " + expectedKindStr + ")",
json.getAsJsonObject().get("eventDescription").getAsString())); json.getAsJsonObject().get("eventDescription").getAsString()));
signalEventLatch4.countDown(); kindAssertions.add(json.getAsJsonObject().get("eventContent").getAsJsonObject().get("kind").getAsInt());
directLatch1.countDown();
}); });
user.getDriver() user.getDriver()
.findElement(By.cssSelector("#openvidu-instance-1 app-participant.remote-participant .message-btn")) .findElement(
By.cssSelector("#openvidu-instance-1 app-participant.remote-participant " + btnClass))
.click(); .click();
user.getEventManager().waitUntilEventReaches(0, "dataReceived", "RoomEvent", 1); user.getEventManager().waitUntilEventReaches(0, "dataReceived", "RoomEvent", 1);
user.getEventManager().waitUntilEventReaches(0, "dataReceived", "ParticipantEvent", 1); user.getEventManager().waitUntilEventReaches(0, "dataReceived", "ParticipantEvent", 1);
// Do not trigger own signals // Do not trigger own signals
Assertions.assertEquals(0, user.getEventManager().getNumEvents(1, "dataReceived-RoomEvent").get()); Assertions.assertEquals(0, user.getEventManager().getNumEvents(1, "dataReceived-RoomEvent").get());
Assertions.assertEquals(0, user.getEventManager().getNumEvents(1, "dataReceived-ParticipantEvent").get()); Assertions.assertEquals(0, user.getEventManager().getNumEvents(1, "dataReceived-ParticipantEvent").get());
if (!signalEventLatch4.await(3, TimeUnit.SECONDS)) { if (!directLatch1.await(3, TimeUnit.SECONDS)) {
Assertions.fail("Timeout waiting for signal event content check"); Assertions.fail("Timeout waiting for direct signal event from TestParticipant1");
} }
assertions.forEach(assertion -> Assertions.assertEquals(assertion.getKey(), assertion.getValue())); assertions.forEach(assertion -> Assertions.assertEquals(assertion.getKey(), assertion.getValue()));
kindAssertions.forEach(
kind -> Assertions.assertEquals(expectedKind, kind, "Expected DataPacket_Kind " + expectedKind));
gracefullyLeaveParticipants(user, 2); gracefullyLeaveParticipants(user, 2);
} }
@ -2819,7 +2863,8 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
Thread.sleep(retryIntervalMillis); Thread.sleep(retryIntervalMillis);
} catch (InterruptedException e) { } catch (InterruptedException e) {
// Print screenshot // Print screenshot
String screenshot = "data:image/png;base64," + ((TakesScreenshot) user.getDriver()).getScreenshotAs(BASE64); String screenshot = "data:image/png;base64,"
+ ((TakesScreenshot) user.getDriver()).getScreenshotAs(BASE64);
System.out.println("INTERRUPTED EXCEPTION WHILE WAITING FOR ELEMENT TO BE CLICKABLE: " + cssSelector); System.out.println("INTERRUPTED EXCEPTION WHILE WAITING FOR ELEMENT TO BE CLICKABLE: " + cssSelector);
System.out.println(screenshot); System.out.println(screenshot);
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
@ -2836,25 +2881,28 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
+ "' to be clickable without backdrop interference after " + timeoutMillis + "ms"); + "' to be clickable without backdrop interference after " + timeoutMillis + "ms");
} }
public boolean assertAllElementsHaveTracks(OpenViduTestappUser user, String selector, boolean hasAudio, boolean hasVideo) { public boolean assertAllElementsHaveTracks(OpenViduTestappUser user, String selector, boolean hasAudio,
boolean hasVideo) {
org.openqa.selenium.JavascriptExecutor js = (org.openqa.selenium.JavascriptExecutor) user.getDriver(); org.openqa.selenium.JavascriptExecutor js = (org.openqa.selenium.JavascriptExecutor) user.getDriver();
String script = String script = "var elements = document.querySelectorAll(arguments[0]);" +
"var elements = document.querySelectorAll(arguments[0]);" + "for (var i = 0; i < elements.length; i++) {" +
"for (var i = 0; i < elements.length; i++) {" + " var el = elements[i];" +
" var el = elements[i];" + " if (!el.srcObject) return false;" +
" if (!el.srcObject) return false;" + " if (arguments[1] && el.srcObject.getAudioTracks().length === 0) return false;" +
" if (arguments[1] && el.srcObject.getAudioTracks().length === 0) return false;" + " if (!arguments[1] && el.srcObject.getAudioTracks().length > 0) return false;" +
" if (!arguments[1] && el.srcObject.getAudioTracks().length > 0) return false;" + " if (arguments[2] && el.srcObject.getVideoTracks().length === 0) return false;" +
" if (arguments[2] && el.srcObject.getVideoTracks().length === 0) return false;" + " if (!arguments[2] && el.srcObject.getVideoTracks().length > 0) return false;" +
" if (!arguments[2] && el.srcObject.getVideoTracks().length > 0) return false;" + "}" +
"}" + "return true;";
"return true;";
return (Boolean) js.executeScript(script, selector, hasAudio, hasVideo); return (Boolean) js.executeScript(script, selector, hasAudio, hasVideo);
} }
public void changeElementSize(OpenViduTestappUser user, org.openqa.selenium.WebElement element, int width, int height) { public void changeElementSize(OpenViduTestappUser user, org.openqa.selenium.WebElement element, int width,
int height) {
org.openqa.selenium.JavascriptExecutor js = (org.openqa.selenium.JavascriptExecutor) user.getDriver(); org.openqa.selenium.JavascriptExecutor js = (org.openqa.selenium.JavascriptExecutor) user.getDriver();
js.executeScript("arguments[0].style.width = '" + width + "px'; arguments[0].style.height = '" + height + "px';", element); js.executeScript(
"arguments[0].style.width = '" + width + "px'; arguments[0].style.height = '" + height + "px';",
element);
} }
} }

View File

@ -38,6 +38,7 @@ mat-card.room-card {
cursor: pointer; cursor: pointer;
padding: 0; padding: 0;
margin-right: 4px; margin-right: 4px;
font-size: 22px;
} }
.room-actions button:hover { .room-actions button:hover {

View File

@ -58,8 +58,14 @@
<button class="peer-info-btn" (click)="openInfoDialog()" title="PCTransports info"> <button class="peer-info-btn" (click)="openInfoDialog()" title="PCTransports info">
<mat-icon aria-label="PCTransports info button">info</mat-icon> <mat-icon aria-label="PCTransports info button">info</mat-icon>
</button> </button>
<button class="message-btn" (click)="sendData()" title="Broadcast message to room"> <button class="message-reliable-btn" (click)="sendDataReliable()" title="Broadcast reliable message to room">
<mat-icon aria-label="Send message button">chat</mat-icon> <mat-icon aria-label="Send reliable message button">chat_bubble</mat-icon>
</button>
<button class="message-lossy-btn" (click)="sendDataLossy()" title="Broadcast lossy message to room">
<mat-icon aria-label="Send lossy message button">chat_dashed</mat-icon>
</button>
<button class="message-lossy-burst-btn" (click)="sendDataLossyBurst()" title="Broadcast 500 lossy messages in burst">
<mat-icon aria-label="Send lossy burst button">fast_forward</mat-icon>
</button> </button>
<button class="disconnect-btn" (click)="disconnectRoom()" title="Disconnect room"> <button class="disconnect-btn" (click)="disconnectRoom()" title="Disconnect room">
<mat-icon aria-label="Disconnect button">clear</mat-icon> <mat-icon aria-label="Disconnect button">clear</mat-icon>
@ -89,7 +95,9 @@
[index]="index"></app-participant> [index]="index"></app-participant>
@for (participant of room.remoteParticipants | keyvalue; track participant) { @for (participant of room.remoteParticipants | keyvalue; track participant) {
<app-participant class="remote-participant" <app-participant class="remote-participant"
[participant]="participant.value" [room]="room" [index]="index" (sendDataToOneParticipant)="sendData($event)"></app-participant> [participant]="participant.value" [room]="room" [index]="index"
(sendReliableDataToOneParticipant)="sendDataReliable($event)"
(sendLossyDataToOneParticipant)="sendDataLossy($event)"></app-participant>
} }
</div> </div>
</mat-card-content> </mat-card-content>

View File

@ -770,7 +770,8 @@ export class OpenviduInstanceComponent {
kind?: DataPacket_Kind, kind?: DataPacket_Kind,
topic?: string topic?: string
) => { ) => {
const decodedPayload = this.decoder.decode(payload); let decodedPayload = this.decoder.decode(payload);
decodedPayload += ` (kind: ${DataPacket_Kind[kind!]})`;
this.updateEventList( this.updateEventList(
RoomEvent.DataReceived, RoomEvent.DataReceived,
{ payload: decodedPayload, participant, kind, topic }, { payload: decodedPayload, participant, kind, topic },
@ -1195,14 +1196,14 @@ export class OpenviduInstanceComponent {
}); });
} }
sendData(destinationIdentity?: string) { sendData(destinationIdentity?: string, reliable: boolean = true) {
let strData = `Message from ${this.room?.localParticipant.identity}`; let strData = `Message from ${this.room?.localParticipant.identity}`;
strData += destinationIdentity strData += destinationIdentity
? ` to ${destinationIdentity}` ? ` to ${destinationIdentity}`
: ' to all room'; : ' to all room';
const data = new TextEncoder().encode(strData); const data = new TextEncoder().encode(strData);
let options: DataPublishOptions = { let options: DataPublishOptions = {
reliable: true, reliable,
}; };
if (destinationIdentity) { if (destinationIdentity) {
options.destinationIdentities = [destinationIdentity]; options.destinationIdentities = [destinationIdentity];
@ -1210,6 +1211,22 @@ export class OpenviduInstanceComponent {
this.room?.localParticipant.publishData(data, options); this.room?.localParticipant.publishData(data, options);
} }
sendDataReliable(destinationIdentity?: string) {
this.sendData(destinationIdentity, true);
}
sendDataLossy(destinationIdentity?: string) {
this.sendData(destinationIdentity, false);
}
sendDataLossyBurst(count: number = 500) {
for (let i = 0; i < count; i++) {
const strData = `Lossy burst ${i + 1}/${count} from ${this.room?.localParticipant.identity}`;
const data = new TextEncoder().encode(strData);
this.room?.localParticipant.publishData(data, { reliable: false });
}
}
openInfoDialog() { openInfoDialog() {
const updateFunction = async (): Promise<string> => { const updateFunction = async (): Promise<string> => {
const pub: PCTransport = this.getPublisherPC()!; const pub: PCTransport = this.getPublisherPC()!;

View File

@ -46,8 +46,11 @@
</button> </button>
} }
@if (!participant.isLocal) { @if (!participant.isLocal) {
<button class="message-btn" (click)="sendData()" title="Send message to this participant"> <button class="message-reliable-btn" (click)="sendDataReliable()" title="Send reliable message to this participant">
<mat-icon aria-label="Send message button">chat</mat-icon> <mat-icon aria-label="Send reliable message button">chat_bubble</mat-icon>
</button>
<button class="message-lossy-btn" (click)="sendDataLossy()" title="Send lossy message to this participant">
<mat-icon aria-label="Send lossy message button">chat_dashed</mat-icon>
</button> </button>
} }
</div> </div>

View File

@ -57,7 +57,10 @@ export class ParticipantComponent {
index: number; index: number;
@Output() @Output()
sendDataToOneParticipant = new EventEmitter<string>(); sendReliableDataToOneParticipant = new EventEmitter<string>();
@Output()
sendLossyDataToOneParticipant = new EventEmitter<string>();
localParticipant: LocalParticipant | undefined; localParticipant: LocalParticipant | undefined;
@ -340,7 +343,8 @@ export class ParticipantComponent {
.on( .on(
ParticipantEvent.DataReceived, ParticipantEvent.DataReceived,
(payload: Uint8Array, kind: DataPacket_Kind) => { (payload: Uint8Array, kind: DataPacket_Kind) => {
const decodedPayload = this.decoder.decode(payload); let decodedPayload = this.decoder.decode(payload);
decodedPayload += ` (kind: ${DataPacket_Kind[kind]})`;
this.updateEventList( this.updateEventList(
ParticipantEvent.DataReceived, ParticipantEvent.DataReceived,
'ParticipantEvent', 'ParticipantEvent',
@ -468,7 +472,11 @@ export class ParticipantComponent {
this.testFeedService.pushNewEvent({ user: this.index, event }); this.testFeedService.pushNewEvent({ user: this.index, event });
} }
sendData() { sendDataReliable() {
this.sendDataToOneParticipant.emit(this.participant.identity); this.sendReliableDataToOneParticipant.emit(this.participant.identity);
}
sendDataLossy() {
this.sendLossyDataToOneParticipant.emit(this.participant.identity);
} }
} }

View File

@ -9,7 +9,7 @@
<link rel="icon" type="image/x-icon" href="favicon.ico"> <link rel="icon" type="image/x-icon" href="favicon.ico">
<link rel="preconnect" href="https://fonts.gstatic.com"> <link rel="preconnect" href="https://fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500&display=swap" rel="stylesheet"> <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"> <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Sharp:opsz,wght,FILL,GRAD@24,500,1,-25"/>
</head> </head>
<body class="mat-typography"> <body class="mat-typography">

View File

@ -1,4 +1,9 @@
/* You can add global styles to this file, and also import other style files */ /* You can add global styles to this file, and also import other style files */
.mat-icon {
font-family: "Material Symbols Sharp" !important;
}
html, html,
body { body {
height: 100%; height: 100%;
@ -8,8 +13,14 @@ body {
} }
body { body {
font-family: Roboto, Helvetica Neue Light, Helvetica Neue, Helvetica, Arial, font-family:
Lucida Grande, sans-serif; Roboto,
Helvetica Neue Light,
Helvetica Neue,
Helvetica,
Arial,
Lucida Grande,
sans-serif;
} }
a { a {