openvidu-components: Added screensharing E2E

pull/713/head
csantosm 2022-04-01 12:05:58 +02:00
parent e252b84740
commit 9888154a02
43 changed files with 836 additions and 4 deletions

View File

@ -0,0 +1,5 @@
* https://docs.google.com/document/d/1IUwdlxyCp3j88hBuf-2JOgp_DZOTDoZ_36ifR6JeKjg/edit#heading=h.hgzr1bwt9mj5
* https://docs.google.com/document/d/1C4q9T1VNL26Am-14uqt19zrovQ6QdIYD-JQntOV2eHs/edit#heading=h.hgzr1bwt9mj5
* https://docs.google.com/document/d/1yXD2Sqz4qbH1Q0pHMOmpKymsEYvSKNkyzy5MZl-7Mkc/edit#heading=h.amfwrsbwplqk
* https://docs.google.com/document/d/1atuocV-Skv5ymU7BsEPhXQk9INmEyqfFkMQ7C2Sg8RA/edit#heading=h.20jqupqw4tve
* https://docs.google.com/document/d/1ugQR_HA0JBVomjm-v3cOhEocxsCkcBtthUQYkdcI-Jk/edit

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

@ -5,7 +5,7 @@ import { WebComponentConfig } from './selenium.conf';
const url = WebComponentConfig.appUrl;
const TIMEOUT = 5000;
describe('Checkout localhost app', () => {
describe('Testing API Directives', () => {
let browser: WebDriver;
async function createChromeBrowser(): Promise<WebDriver> {
@ -25,8 +25,6 @@ describe('Checkout localhost app', () => {
await browser.quit();
});
// ** API Directives
it('should set the MINIMAL UI', async () => {
let element;
await browser.get(`${url}?minimal=true`);
@ -398,8 +396,27 @@ describe('Checkout localhost app', () => {
element = await browser.findElements(By.id('mute-btn'));
expect(element.length).equals(0);
});
});
//* ---- Webcomponent events ----
describe('Testing videoconference EVENTS', () => {
let browser: WebDriver;
async function createChromeBrowser(): Promise<WebDriver> {
return await new Builder()
.forBrowser(WebComponentConfig.browserName)
.withCapabilities(WebComponentConfig.browserCapabilities)
.setChromeOptions(WebComponentConfig.browserOptions)
.usingServer(WebComponentConfig.seleniumAddress)
.build();
}
beforeEach(async () => {
browser = await createChromeBrowser();
});
afterEach(async () => {
await browser.quit();
});
it('should receive the onJoinButtonClicked event', async () => {
let element;
@ -569,4 +586,213 @@ describe('Checkout localhost app', () => {
element = await browser.wait(until.elementLocated(By.id(`${participantName}-sessionDisconnected`)), TIMEOUT);
expect(await element.isDisplayed()).to.be.true;
});
});
describe('Testing screenshare features', () => {
let browser: WebDriver;
async function createChromeBrowser(): Promise<WebDriver> {
return await new Builder()
.forBrowser(WebComponentConfig.browserName)
.withCapabilities(WebComponentConfig.browserCapabilities)
.setChromeOptions(WebComponentConfig.browserOptions)
.usingServer(WebComponentConfig.seleniumAddress)
.build();
}
beforeEach(async () => {
browser = await createChromeBrowser();
});
afterEach(async () => {
await browser.quit();
});
it('should toggle screensharing', async () => {
let element;
await browser.get(`${url}?prejoin=false`);
element = await browser.wait(until.elementLocated(By.id('layout')), TIMEOUT);
expect(await element.isDisplayed()).to.be.true;
// Clicking to screensharing button
const screenshareButton = await browser.findElement(By.id('screenshare-btn'));
expect(await screenshareButton.isDisplayed()).to.be.true;
await screenshareButton.click();
element = await browser.wait(until.elementLocated(By.className('OV_big')), TIMEOUT);
element = await browser.findElements(By.css('video'));
expect(element.length).equals(2);
// Clicking to screensharing button
await screenshareButton.click();
element = await browser.findElements(By.css('video'));
expect(element.length).equals(1);
});
it('should screensharing with audio muted', async () => {
let element, isAudioEnabled;
const getAudioScript = (className: string) => {
return `return document.getElementsByClassName('${className}')[0].srcObject.getAudioTracks()[0].enabled;`;
};
await browser.get(`${url}?prejoin=false`);
element = await browser.wait(until.elementLocated(By.id('layout')), TIMEOUT);
expect(await element.isDisplayed()).to.be.true;
await browser.wait(until.elementLocated(By.id('layout')), TIMEOUT);
const micButton = await browser.findElement(By.id('mic-btn'));
expect(await micButton.isDisplayed()).to.be.true;
await micButton.click();
// Clicking to screensharing button
const screenshareButton = await browser.findElement(By.id('screenshare-btn'));
expect(await screenshareButton.isDisplayed()).to.be.true;
await screenshareButton.click();
element = await browser.wait(until.elementLocated(By.className('screen-type')), TIMEOUT);
element = await browser.findElements(By.css('video'));
expect(element.length).equals(2);
isAudioEnabled = await browser.executeScript(getAudioScript('screen-type'));
expect(isAudioEnabled).to.be.false;
await browser.wait(until.elementLocated(By.id('statusMic')), TIMEOUT);
element = await browser.findElements(By.id('statusMic'));
expect(element.length).equals(2);
// Clicking to screensharing button
await screenshareButton.click();
element = await browser.findElements(By.css('video'));
expect(element.length).equals(1);
});
it('should show and hide CAMERA stream when muting video with screensharing', async () => {
let element;
await browser.get(`${url}?prejoin=false`);
element = await browser.wait(until.elementLocated(By.id('layout')), TIMEOUT);
expect(await element.isDisplayed()).to.be.true;
// Clicking to screensharing button
const screenshareButton = await browser.findElement(By.id('screenshare-btn'));
expect(await screenshareButton.isDisplayed()).to.be.true;
await screenshareButton.click();
element = await browser.wait(until.elementLocated(By.className('OV_big')), TIMEOUT);
element = await browser.findElements(By.css('video'));
expect(element.length).equals(2);
const muteVideoButton = await browser.findElement(By.id('camera-btn'));
await muteVideoButton.click();
element = await browser.findElements(By.css('video'));
expect(element.length).equals(1);
});
it('should screenshare has audio active when camera is muted', async () => {
let element, isAudioEnabled;
const audioEnableScript = 'return document.getElementsByTagName("video")[0].srcObject.getAudioTracks()[0].enabled;';
await browser.get(`${url}?prejoin=false`);
element = await browser.wait(until.elementLocated(By.id('layout')), TIMEOUT);
expect(await element.isDisplayed()).to.be.true;
// Clicking to screensharing button
const screenshareButton = await browser.findElement(By.id('screenshare-btn'));
expect(await screenshareButton.isDisplayed()).to.be.true;
await screenshareButton.click();
element = await browser.wait(until.elementLocated(By.className('OV_big')), TIMEOUT);
element = await browser.findElements(By.css('video'));
expect(element.length).equals(2);
element = await browser.findElements(By.id('statusMic'));
expect(element.length).equals(1);
// Muting camera video
const muteVideoButton = await browser.findElement(By.id('camera-btn'));
await muteVideoButton.click();
element = await browser.findElements(By.css('video'));
expect(element.length).equals(1);
await browser.sleep(500);
element = await browser.findElements(By.id('statusMic'));
expect(element.length).equals(0);
// Checking if audio is muted after join the room
isAudioEnabled = await browser.executeScript(audioEnableScript);
expect(isAudioEnabled).to.be.true;
// Unmuting camera
await muteVideoButton.click();
element = await browser.wait(until.elementLocated(By.className('camera-type')), TIMEOUT);
element = await browser.findElements(By.css('video'));
expect(element.length).equals(2);
element = await browser.findElements(By.id('statusMic'));
expect(element.length).equals(1);
});
it('should camera come back with audio muted when screensharing', async () => {
let element, isAudioEnabled;
const getAudioScript = (className: string) => {
return `return document.getElementsByClassName('${className}')[0].srcObject.getAudioTracks()[0].enabled;`;
};
await browser.get(`${url}?prejoin=false`);
element = await browser.wait(until.elementLocated(By.id('layout')), TIMEOUT);
expect(await element.isDisplayed()).to.be.true;
// Clicking to screensharing button
const screenshareButton = await browser.findElement(By.id('screenshare-btn'));
expect(await screenshareButton.isDisplayed()).to.be.true;
await screenshareButton.click();
element = await browser.wait(until.elementLocated(By.className('screen-type')), TIMEOUT);
element = await browser.findElements(By.css('video'));
expect(element.length).equals(2);
element = await browser.findElements(By.id('statusMic'));
expect(element.length).equals(1);
// Mute camera
const muteVideoButton = await browser.findElement(By.id('camera-btn'));
await muteVideoButton.click();
element = await browser.findElements(By.css('video'));
expect(element.length).equals(1);
element = await browser.findElements(By.id('statusMic'));
expect(element.length).equals(0);
// Checking if audio is muted after join the room
isAudioEnabled = await browser.executeScript(getAudioScript('screen-type'));
expect(isAudioEnabled).to.be.true;
// Mute audio
const muteAudioButton = await browser.findElement(By.id('mic-btn'));
await muteAudioButton.click();
await browser.wait(until.elementLocated(By.id('statusMic')), TIMEOUT);
element = await browser.findElements(By.id('statusMic'));
expect(element.length).equals(1);
isAudioEnabled = await browser.executeScript(getAudioScript('screen-type'));
expect(isAudioEnabled).to.be.false;
// Unmute camera
await muteVideoButton.click();
element = await browser.wait(until.elementLocated(By.className('camera-type')), TIMEOUT);
element = await browser.findElements(By.css('video'));
expect(element.length).equals(2);
element = await browser.findElements(By.id('statusMic'));
expect(element.length).equals(2);
isAudioEnabled = await browser.executeScript(getAudioScript('camera-type'));
expect(isAudioEnabled).to.be.false;
});
});

View File

@ -0,0 +1,126 @@
## OpenVidu Components API
### STRUCTURAL DIRECTIVES
- ovParticipantPanelItemElements
```javascript
<div *ovParticipantPanelItemElements>
<p>EXTRA INFO</p>
</div>
```
```javascript
<div *ovParticipantPanelItemElements="let participant">
<p>N: {{participant?.nickname}}</p>
</div>
```
### Videoconference component
#### Parameters:
- sessionName: The session id of your custom session
- participantName
- tokens: The webcam and screen tokens
#### UI Params
#### Videoconference Component
| **Parameter** | **Description** | **Value** |
|:-----------------------: |:------------------------------------------------------------------------------: |:------------------------------------: |
| minimal | Applies a minimal UI. Hide all controls except for cam and mic. | true \| fase<br>Default value: _**false**_ |
| prejoin | Show/hide the prejoin page for selecting media devices. | true \| fase<br>Default value: _**true**_ |
| videoMuted | Participant joins the session with camera muted/unmuted. | true \| fase<br>Default value: _**false**_ |
| audioMuted | Participant joins the session with microphone muted/unmuted. | true \| fase<br>Default value: _**false**_ |
| toolbarScreenshareButton | Show/hide the screenshare button. | true \| fase<br>Default value: _**true**_ |
| toolbarFullscreenButton | Show/hide the fullscreen button. | true \| fase<br>Default value: _**true**_ |
| toolbarLeaveButton | Show/hide the leave button. | true \| fase<br>Default value: _**true**_ |
toolbarChatPanelButton | Show/hide the chat panel button. It also applies to chat panel | true \| fase<br>Default value: _**true**_ |
| toolbarParticipantsPanelButton | Show/hide the participants panel button. It also applies to participants panel | true \| fase<br>Default value: _**true**_ |
| toolbarDisplayLogo | Set display toolbar logo | true \| fase<br>Default value: _**true**_ |
| toolbarDisplaySessionName | Set display session name | true \| fase<br>Default value: _**true**_ |
| streamDisplayParticipantName | Show/hide the participants name in stream component | true \| fase<br>Default value: true |
| streamDisplayAudioDetection | Show/hide the participant audio detection in stream component | true \| fase<br>Default value: true |
| streamSettingsButton | Show/hide the participant settings button in stream component | true \| fase<br>Default value: true |
| participantPanelItemMuteButton | Show/hide the mute button in participants panel item | true \| fase<br>Default value: true |
#### Toolbar Component
| **Parameter** | **Description** | **Value** |
|:-----------------------: |:------------------------------------------------------------------------------: |:------------------------------------: |
| screenshareButton | Show/hide the screenshare button. | true \| fase<br>Default value: _**true**_ |
| fullscreenButton | Show/hide the fullscreen button. | true \| fase<br>Default value: _**true**_ |
| leaveButton | Show/hide the leave button. | true \| fase<br>Default value: _**true**_ |
| chatPanelButton | Show/hide the chat panel button. It also applies to chat panel | true \| fase<br>Default value: _**true**_ |
| participantsPanelButton | Show/hide the participants panel button. It also applies to participants panel | true \| fase<br>Default value: _**true**_ |
| displayLogo | Set display toolbar logo | true \| fase<br>Default value: _**true**_ |
| displaySessionName | Set display session name | true \| fase<br>Default value: _**true**_ |
#### Stream Component
| **Parameter** | **Description** | **Value** |
|:-----------------------: |:------------------------------------------------------------------------------: |:------------------------------------: |
| displayParticipantName | Show/hide the participants name in stream component | true \| fase<br>Default value: true |
| displayAudioDetection | Show/hide the participant audio detection in stream component | true \| fase<br>Default value: true |
| settingsButton | Show/hide the participant settings button in stream component | true \| fase<br>Default value: true |
#### Participant Panel Item Component
| **Parameter** | **Description** | **Value** |
|:-----------------------: |:------------------------------------------------------------------------------: |:------------------------------------: |
| muteButton | Show/hide the mute button in participants panel item | true \| fase<br>Default value: true |
#### Events:
- onJoinButtonClicked
- onToolbarLeaveButtonClicked
- onToolbarCameraButtonClicked
- onToolbarMicrophoneButtonClicked
- onToolbarScreenshareButtonClicked
- onToolbarParticipantsPanelButtonClicked
- onToolbarChatPanelButtonClicked
- onToolbarFullscreenButtonClicked
- onSessionCreated => Session
#### How can I replace the OpenVidu logo?
If you want to customize and replace the OpenVidu Logo you only have to add under `assets/images` directory your logo file. The name must be `logo.png` and it must be a .png image.
#### How can I customize the styles?
You only have to add the following css code on your css app root file and modify customize all you want:
```scss
// Custom openvidu-components styles
:root {
--ov-primary-color: #303030;
--ov-secondary-color: #586063;
--ov-tertiary-color: #598eff;
--ov-warn-color: #EB5144;
--ov-accent-color: #ffae35;
--ov-dark-color: #1d1d1d;
--ov-dark-light-color: #43484A;
--ov-light-color: #ffffff;
--ov-light-dark-color: #f1f1f1;
--ov-buttons-radius: 50%; // border-radius property
--ov-leave-button-radius: 10px;
--ov-video-radius: 5px;
--ov-panel-radius: 5px;
}
```

View File

@ -53,8 +53,10 @@ export class VideoComponent implements AfterViewInit {
this.type = <VideoType>this._streamManager?.stream?.typeOfVideo;
if (this.type === VideoType.SCREEN) {
this._videoElement.nativeElement.style.objectFit = 'contain';
this._videoElement.nativeElement.classList.add('screen-type');
} else {
this._videoElement.nativeElement.style.objectFit = 'cover';
this._videoElement.nativeElement.classList.add('camera-type');
}
}

View File

@ -0,0 +1,7 @@
{
"Chat": "Chat",
"Close": "Close",
"You": "You",
"Send": "Send",
"Chat_warn_message": "Messages will be removed at the end of the session",
}

View File

@ -0,0 +1,12 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-chatPanel-directive',
template: ` <p>toolbar-directive works!</p> `,
styleUrls: ['./chatPanel-directive.component.scss']
})
export class ChatPanelDirectiveComponent implements OnInit {
constructor() {}
ngOnInit(): void {}
}

View File

@ -0,0 +1,47 @@
<div class="content" role="main">
<div class="card-container">
<div class="card card-small" (click)="goTo('toolbarDirective')" tabindex="0">
<span>ToolbarDirective</span>
</div>
<div class="card card-small" (click)="goTo('toolbarAdditionalButtonsDirective')" tabindex="0">
<span>ToolbarAdditionalButtonsDirective</span>
</div>
</div>
<div class="card-container">
<div class="card card-small" (click)="goTo('layoutDirective')" tabindex="0">
<span>LayoutDirective</span>
</div>
<div class="card card-small" (click)="goTo('streamDirective')" tabindex="0">
<span>StreamDirective</span>
</div>
</div>
<div class="card-container">
<div class="card card-small" (click)="goTo('panelDirective')" tabindex="0">
<span>PanelDirective</span>
</div>
<div class="card card-small" (click)="goTo('participantsPanelDirective')" tabindex="0">
<span>ParticipantsPanelDirective</span>
</div>
<div class="card card-small" (click)="goTo('chatPanelDirective')" tabindex="0">
<span>ChatPanelDirective</span>
</div>
<div class="card card-small" (click)="goTo('participantPanelItemElementsDirective')" tabindex="0">
<span>ParticipantPanelItemElementsDirective</span>
</div>
<div class="card card-small" (click)="goTo('participantPanelItemDirective')" tabindex="0">
<span>ParticipantPanelItemDirective</span>
</div>
</div>
</div>

View File

@ -0,0 +1,291 @@
:host {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
font-size: 14px;
color: #333;
box-sizing: border-box;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
h1,
h2,
h3,
h4,
h5,
h6 {
margin: 8px 0;
}
p {
margin: 0;
}
.toolbar {
position: absolute;
top: 0;
left: 0;
right: 0;
height: 60px;
display: flex;
align-items: center;
background-color: #3c3f3e;
color: white;
font-weight: 600;
}
.content {
display: flex;
margin: 62px auto;
padding: 0px;
max-width: 960px;
flex-direction: column;
align-items: center;
}
.dashboard-section {
height: 45%; width: 100%; text-align: center;
}
#call-app, #testing-app {
height: 95%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
#call-app {
border-bottom: 3px solid;
}
#call-app-btn {
background-color: #0088AA;
color: #ffffff;
font-weight: bold;
}
#testing-app-btn {
background-color: #FFCC00;
color: #080808;
font-weight: bold;
}
svg.material-icons {
height: 24px;
width: auto;
}
svg.material-icons:not(:last-child) {
margin-right: 8px;
}
.card svg.material-icons path {
fill: #888;
}
.card-container {
display: flex;
flex-wrap: wrap;
justify-content: center;
margin-top: 16px;
}
.card {
width: fit-content !important;
border-radius: 4px;
border: 1px solid #eee;
background-color: #fafafa;
height: 40px;
width: 200px;
margin: 0 8px 16px;
padding: 16px;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
transition: all 0.2s ease-in-out;
line-height: 24px;
}
.card-container .card:not(:last-child) {
margin-right: 0;
}
.card.card-small {
height: 16px;
width: 168px;
}
.card-container .card:not(.highlight-card) {
cursor: pointer;
}
.card-container .card:not(.highlight-card):hover {
transform: translateY(-3px);
box-shadow: 0 4px 17px rgba(0, 0, 0, 0.35);
}
.card-container .card:not(.highlight-card):hover .material-icons path {
fill: rgb(105, 103, 103);
}
.card.highlight-card {
background-color: #1976d2;
color: white;
font-weight: 600;
border: none;
width: auto;
min-width: 30%;
position: relative;
}
.card.card.highlight-card span {
margin-left: 60px;
}
svg#rocket {
width: 80px;
position: absolute;
left: -10px;
top: -24px;
}
svg#rocket-smoke {
height: calc(100vh - 95px);
position: absolute;
top: 10px;
right: 180px;
z-index: -10;
}
a,
a:visited,
a:hover {
color: #1976d2;
text-decoration: none;
}
a:hover {
color: #125699;
}
.terminal {
position: relative;
width: 80%;
max-width: 600px;
border-radius: 6px;
padding-top: 45px;
margin-top: 8px;
overflow: hidden;
background-color: rgb(15, 15, 16);
}
.terminal::before {
content: "\2022 \2022 \2022";
position: absolute;
top: 0;
left: 0;
height: 4px;
background: rgb(58, 58, 58);
color: #c2c3c4;
width: 100%;
font-size: 2rem;
line-height: 0;
padding: 14px 0;
text-indent: 4px;
}
.terminal pre {
font-family: SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace;
color: white;
padding: 0 1rem 1rem;
margin: 0;
}
.circle-link {
height: 40px;
width: 40px;
border-radius: 40px;
margin: 8px;
background-color: white;
border: 1px solid #eeeeee;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
transition: 1s ease-out;
}
.circle-link:hover {
transform: translateY(-0.25rem);
box-shadow: 0px 3px 15px rgba(0, 0, 0, 0.2);
}
.github-star-badge {
color: #24292e;
display: flex;
align-items: center;
font-size: 12px;
padding: 3px 10px;
border: 1px solid rgba(27,31,35,.2);
border-radius: 3px;
background-image: linear-gradient(-180deg,#fafbfc,#eff3f6 90%);
margin-left: 4px;
font-weight: 600;
font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol;
}
.github-star-badge:hover {
background-image: linear-gradient(-180deg,#f0f3f6,#e6ebf1 90%);
border-color: rgba(27,31,35,.35);
background-position: -.5em;
}
.github-star-badge .material-icons {
height: 16px;
width: 16px;
margin-right: 4px;
}
svg#clouds {
position: fixed;
bottom: -160px;
left: -230px;
z-index: -10;
width: 1920px;
}
/* Responsive Styles */
@media screen and (max-width: 767px) {
.card-container > *:not(.circle-link) ,
.terminal {
width: 100%;
}
.card:not(.highlight-card) {
height: 16px;
margin: 8px 0;
}
.card.highlight-card span {
margin-left: 72px;
}
svg#rocket-smoke {
right: 120px;
transform: rotate(-5deg);
}
}
@media screen and (max-width: 575px) {
svg#rocket-smoke {
display: none;
visibility: hidden;
}
}

View File

@ -0,0 +1,19 @@
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
@Component({
selector: 'app-examples-dashboard',
templateUrl: './examples-dashboard.component.html',
styleUrls: ['./examples-dashboard.component.scss']
})
export class ExamplesDashboardComponent implements OnInit {
constructor(private router: Router) { }
ngOnInit(): void {}
goTo(path: string) {
this.router.navigate([`/${path}`]);
}
}

View File

@ -0,0 +1,11 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-layout-directive',
template: ` <p>layout-directive works!</p> `,
})
export class LayoutDirectiveComponent implements OnInit {
constructor() {}
ngOnInit(): void {}
}

View File

@ -0,0 +1,12 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-panel-directive',
template: ` <p>toolbar-directive works!</p> `,
styleUrls: ['./panel-directive.component.scss']
})
export class PanelDirectiveComponent implements OnInit {
constructor() {}
ngOnInit(): void {}
}

View File

@ -0,0 +1,12 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-participantsPanel-directive',
template: ` <p>participantsPanel-directive works!</p> `,
styleUrls: ['./participantsPanel-directive.component.scss']
})
export class ParticipantsPanelDirectiveComponent implements OnInit {
constructor() {}
ngOnInit(): void {}
}

View File

@ -0,0 +1,11 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-stream-directive',
template: ` <p>stream-directive works!</p> `,
})
export class StreamDirectiveComponent implements OnInit {
constructor() {}
ngOnInit(): void {}
}

View File

@ -0,0 +1,40 @@
import { Component, OnInit } from '@angular/core';
import { OpenViduService, ParticipantService, TokenModel } from 'openvidu-angular';
import { RestService } from 'src/app/services/rest.service';
@Component({
selector: 'app-toolbar-directive',
template: `
<ov-videoconference (onJoinButtonClicked)="onJoinButtonClicked()" [tokens]="tokens">
<div *ovToolbar style="text-align: center;">
<button (click)="toggleVideo()">Mute Video</button>
<button>Mute Audio</button>
</div>
</ov-videoconference>
`
})
export class ToolbarDirectiveComponent implements OnInit {
tokens: TokenModel;
sessionId = 'toolbar-directive-example';
OPENVIDU_URL = 'https://localhost:4443';
OPENVIDU_SECRET = 'MY_SECRET';
constructor(
private restService: RestService,
private participantService: ParticipantService,
private openviduService: OpenViduService
) {}
ngOnInit(): void {}
async onJoinButtonClicked() {
this.tokens = {
webcam: await this.restService.getToken(this.sessionId, this.OPENVIDU_URL, this.OPENVIDU_SECRET),
screen: await this.restService.getToken(this.sessionId, this.OPENVIDU_URL, this.OPENVIDU_SECRET)
};
}
toggleVideo() {
const publishVideo = !this.participantService.hasCameraVideoActive();
// this.openviduService.publishVideo(this.participantService.getMyCameraPublisher(), publishVideo);
}
}

View File

@ -0,0 +1,11 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-toolbarAdditionalButtons-directive',
template: ` <p>toolbar-directive works!</p> `,
})
export class ToolbarAdditionalButtonsDirectiveComponent implements OnInit {
constructor() {}
ngOnInit(): void {}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.