openvidu-components: Refactored participant and openvidu service

- Moved publishVideo from openviduService to participantService
- Mark old openviduService methods as deprecated
pull/809/head
Carlos Santos 2023-03-01 10:55:45 +01:00
parent d83604b92a
commit b74ae7a6ab
8 changed files with 252 additions and 162 deletions

View File

@ -167,10 +167,10 @@ export class RecordingActivityComponent implements OnInit {
*/ */
deleteRecording(id: string) { deleteRecording(id: string) {
const succsessCallback = () => { const succsessCallback = async () => {
this.onDeleteRecordingClicked.emit(id); this.onDeleteRecordingClicked.emit(id);
// Sending signal to all participants with the aim of updating their recordings list // Sending signal to all participants with the aim of updating their recordings list
this.openviduService.sendSignal(Signal.RECORDING_DELETED, this.openviduService.getRemoteConnections()); await this.openviduService.sendSignal(Signal.RECORDING_DELETED, this.openviduService.getRemoteConnections());
}; };
this.actionService.openDeleteRecordingDialog(succsessCallback.bind(this)); this.actionService.openDeleteRecordingDialog(succsessCallback.bind(this));
} }

View File

@ -253,20 +253,28 @@ export class SessionComponent implements OnInit, OnDestroy {
private async connectToSession(): Promise<void> { private async connectToSession(): Promise<void> {
try { try {
const webcamToken = this.openviduService.getWebcamToken(); const nickname = this.participantService.getMyNickname();
const screenToken = this.openviduService.getScreenToken(); const participantId = this.participantService.getLocalParticipant().id;
const screenPublisher = this.participantService.getMyScreenPublisher();
const cameraPublisher = this.participantService.getMyCameraPublisher();
if (this.participantService.haveICameraAndScreenActive()) { if (this.participantService.haveICameraAndScreenActive()) {
await this.openviduService.connectSession(this.openviduService.getWebcamSession(), webcamToken);
await this.openviduService.connectSession(this.openviduService.getScreenSession(), screenToken); const webcamSessionId = await this.openviduService.connectWebcamSession(participantId, nickname);
await this.openviduService.publish(this.participantService.getMyCameraPublisher()); if (webcamSessionId) this.participantService.setMyCameraConnectionId(webcamSessionId);
await this.openviduService.publish(this.participantService.getMyScreenPublisher());
const screenSessionId = await this.openviduService.connectScreenSession(participantId, nickname);
if (screenSessionId) this.participantService.setMyScreenConnectionId(screenSessionId);
await this.openviduService.publishCamera(cameraPublisher);
await this.openviduService.publishScreen(screenPublisher);
} else if (this.participantService.isOnlyMyScreenActive()) { } else if (this.participantService.isOnlyMyScreenActive()) {
await this.openviduService.connectSession(this.openviduService.getScreenSession(), screenToken); await this.openviduService.connectScreenSession(participantId, nickname);
await this.openviduService.publish(this.participantService.getMyScreenPublisher()); await this.openviduService.publishScreen(screenPublisher);
} else { } else {
await this.openviduService.connectSession(this.openviduService.getWebcamSession(), webcamToken); await this.openviduService.connectWebcamSession(participantId, nickname);
await this.openviduService.publish(this.participantService.getMyCameraPublisher()); await this.openviduService.publishCamera(cameraPublisher);
} }
} catch (error) { } catch (error) {
// this._error.emit({ error: error.error, messgae: error.message, code: error.code, status: error.status }); // this._error.emit({ error: error.error, messgae: error.message, code: error.code, status: error.status });
@ -289,7 +297,7 @@ export class SessionComponent implements OnInit, OnDestroy {
} }
private subscribeToConnectionCreatedAndDestroyed() { private subscribeToConnectionCreatedAndDestroyed() {
this.session.on('connectionCreated', (event: ConnectionEvent) => { this.session.on('connectionCreated', async (event: ConnectionEvent) => {
const connectionId = event.connection?.connectionId; const connectionId = event.connection?.connectionId;
const nickname: string = this.participantService.getNicknameFromConnectionData(event.connection.data); const nickname: string = this.participantService.getNicknameFromConnectionData(event.connection.data);
const isRemoteConnection: boolean = !this.openviduService.isMyOwnConnection(connectionId); const isRemoteConnection: boolean = !this.openviduService.isMyOwnConnection(connectionId);
@ -303,7 +311,7 @@ export class SessionComponent implements OnInit, OnDestroy {
//Sending nicnkanme signal to new participants //Sending nicnkanme signal to new participants
if (this.openviduService.needSendNicknameSignal()) { if (this.openviduService.needSendNicknameSignal()) {
const data = { clientData: this.participantService.getMyNickname() }; const data = { clientData: this.participantService.getMyNickname() };
this.openviduService.sendSignal(Signal.NICKNAME_CHANGED, [event.connection], data); await this.openviduService.sendSignal(Signal.NICKNAME_CHANGED, [event.connection], data);
} }
} }
}); });

View File

@ -67,7 +67,7 @@ export class VideoDevicesComponent implements OnInit, OnDestroy {
async toggleCam() { async toggleCam() {
this.videoMuteChanging = true; this.videoMuteChanging = true;
const publish = this.isVideoMuted; const publish = this.isVideoMuted;
await this.openviduService.publishVideo(publish); await this.participantService.publishVideo(publish);
if (this.isVideoMuted && this.panelService.isExternalPanelOpened()) { if (this.isVideoMuted && this.panelService.isExternalPanelOpened()) {
this.panelService.togglePanel(PanelType.BACKGROUND_EFFECTS); this.panelService.togglePanel(PanelType.BACKGROUND_EFFECTS);
} }

View File

@ -521,7 +521,7 @@ export class ToolbarComponent implements OnInit, OnDestroy, AfterViewInit {
if (this.panelService.isExternalPanelOpened() && !publishVideo) { if (this.panelService.isExternalPanelOpened() && !publishVideo) {
this.panelService.togglePanel(PanelType.BACKGROUND_EFFECTS); this.panelService.togglePanel(PanelType.BACKGROUND_EFFECTS);
} }
await this.openviduService.publishVideo(publishVideo); await this.participantService.publishVideo(publishVideo);
} catch (error) { } catch (error) {
this.log.e('There was an error toggling camera:', error.code, error.message); this.log.e('There was an error toggling camera:', error.code, error.message);
this.actionService.openDialog(this.translateService.translate('ERRORS.TOGGLE_CAMERA'), error?.error || error?.message || error); this.actionService.openDialog(this.translateService.translate('ERRORS.TOGGLE_CAMERA'), error?.error || error?.message || error);

View File

@ -25,7 +25,7 @@ import { Directive, TemplateRef, ViewContainerRef } from '@angular/core';
* publishVideo = true; * publishVideo = true;
* publishAudio = true; * publishAudio = true;
* *
* constructor(private httpClient: HttpClient, private openviduService: OpenViduService) { } * constructor(private httpClient: HttpClient, private participantService: ParticipantService) { }
* *
* async ngOnInit() { * async ngOnInit() {
* this.tokens = { * this.tokens = {
@ -36,12 +36,12 @@ import { Directive, TemplateRef, ViewContainerRef } from '@angular/core';
* *
* toggleVideo() { * toggleVideo() {
* this.publishVideo = !this.publishVideo; * this.publishVideo = !this.publishVideo;
* this.openviduService.publishVideo(this.publishVideo); * this.participantService.publishVideo(this.publishVideo);
* } * }
* *
* toggleAudio() { * toggleAudio() {
* this.publishAudio = !this.publishAudio; * this.publishAudio = !this.publishAudio;
* this.openviduService.publishAudio(this.publishAudio); * this.participantService.publishAudio(this.publishAudio);
* } * }
* *
* async getToken(): Promise<string> { * async getToken(): Promise<string> {
@ -94,7 +94,6 @@ export class ToolbarDirective {
* *
* constructor( * constructor(
* private httpClient: HttpClient, * private httpClient: HttpClient,
* private openviduService: OpenViduService,
* private participantService: ParticipantService * private participantService: ParticipantService
* ) { } * ) { }
* *
@ -107,12 +106,12 @@ export class ToolbarDirective {
* *
* toggleVideo() { * toggleVideo() {
* const publishVideo = !this.participantService.isMyVideoActive(); * const publishVideo = !this.participantService.isMyVideoActive();
* this.openviduService.publishVideo(publishVideo); * this.participantService.publishVideo(publishVideo);
* } * }
* *
* toggleAudio() { * toggleAudio() {
* const publishAudio = !this.participantService.isMyAudioActive(); * const publishAudio = !this.participantService.isMyAudioActive();
* this.openviduService.publishAudio(publishAudio); * this.participantService.publishAudio(publishAudio);
* } * }
* *
* async getToken(): Promise<string> { * async getToken(): Promise<string> {

View File

@ -64,7 +64,7 @@ export class ChatService {
}); });
} }
sendMessage(message: string) { async sendMessage(message: string) {
message = message.replace(/ +(?= )/g, ''); message = message.replace(/ +(?= )/g, '');
if (message !== '' && message !== ' ') { if (message !== '' && message !== ' ') {
const data = { const data = {
@ -72,7 +72,7 @@ export class ChatService {
nickname: this.participantService.getMyNickname() nickname: this.participantService.getMyNickname()
}; };
this.openviduService.sendSignal(Signal.CHAT, undefined, data); await this.openviduService.sendSignal(Signal.CHAT, undefined, data);
} }
} }

View File

@ -1,4 +1,4 @@
import { Injectable } from '@angular/core'; import { Injectable, Injector } from '@angular/core';
import { import {
Connection, Connection,
OpenVidu, OpenVidu,
@ -53,7 +53,7 @@ export class OpenViduService {
protected openviduAngularConfigSrv: OpenViduAngularConfigService, protected openviduAngularConfigSrv: OpenViduAngularConfigService,
protected platformService: PlatformService, protected platformService: PlatformService,
protected loggerSrv: LoggerService, protected loggerSrv: LoggerService,
private participantService: ParticipantService, private injector: Injector,
protected deviceService: DeviceService protected deviceService: DeviceService
) { ) {
this.log = this.loggerSrv.get('OpenViduService'); this.log = this.loggerSrv.get('OpenViduService');
@ -140,8 +140,6 @@ export class OpenViduService {
async clear() { async clear() {
this.videoSource = undefined; this.videoSource = undefined;
this.audioSource = undefined; this.audioSource = undefined;
// await this.participantService.getMyCameraPublisher()?.stream?.disposeMediaStream();
// await this.participantService.getMyScreenPublisher()?.stream?.disposeMediaStream();
} }
/** /**
@ -201,30 +199,43 @@ export class OpenViduService {
/** /**
* @internal * @internal
* Connects to webcam session using webcam token.
*/ */
async connectSession(session: Session, token: string): Promise<void> { async connectWebcamSession(participantId: string, nickname: string): Promise<string | undefined> {
if (!!token && session) { if (this.isWebcamSessionConnected()) {
const nickname = this.participantService.getMyNickname(); this.log.d('Webcam session is already connected');
const participantId = this.participantService.getLocalParticipant().id; return undefined;
if (session === this.webcamSession) { }
this.log.d('Connecting webcam session'); this.log.d('Connecting webcam session');
await this.webcamSession.connect(token, { await this.webcamSession.connect(this.getWebcamToken(), {
clientData: nickname, clientData: nickname,
participantId, participantId,
type: VideoType.CAMERA type: VideoType.CAMERA
}); });
this.participantService.setMyCameraConnectionId(this.webcamSession.connection.connectionId);
} else if (session === this.screenSession) { return this.webcamSession.connection.connectionId;
// this.participantService.setMyCameraConnectionId(this.webcamSession.connection.connectionId);
}
/**
* @internal
* Connects to screen session using screen token.
*/
async connectScreenSession(participantId: string, nickname: string): Promise<string | undefined> {
if (this.isScreenSessionConnected()) {
this.log.d('Screen session is already connected');
return undefined;
}
this.log.d('Connecting screen session'); this.log.d('Connecting screen session');
await this.screenSession.connect(token, { await this.screenSession.connect(this.getScreenToken(), {
clientData: `${nickname}_${VideoType.SCREEN}`, clientData: `${nickname}_${VideoType.SCREEN}`,
participantId, participantId,
type: VideoType.SCREEN type: VideoType.SCREEN
}); });
this.participantService.setMyScreenConnectionId(this.screenSession.connection.connectionId); return this.screenSession.connection.connectionId;
}
}
} }
/** /**
@ -286,103 +297,86 @@ export class OpenViduService {
} }
/** /**
* @internal * Publishes the publisher to the webcam Session
* @param publisher
*/ */
async publish(publisher: Publisher): Promise<void> { async publishCamera(publisher: Publisher): Promise<void> {
if (!!publisher) { if (!publisher) return;
if (publisher === this.participantService.getMyCameraPublisher()) {
if (this.webcamSession?.capabilities?.publish) { if (this.webcamSession?.capabilities?.publish) {
return await this.webcamSession.publish(publisher); return this.webcamSession.publish(publisher);
} }
this.log.e('Webcam publisher cannot be published'); this.log.e('Webcam publisher cannot be published');
} else if (publisher === this.participantService.getMyScreenPublisher()) {
if (this.screenSession?.capabilities?.publish) {
return await this.screenSession.publish(publisher);
}
this.log.e('Screen publisher cannot be published');
}
}
} }
/** /**
* @internal * Publishes the publisher to the screen Session
* @param publisher
*/ */
private async unpublish(publisher: Publisher): Promise<void> { async publishScreen(publisher: Publisher): Promise<void> {
if (!!publisher) { if (!publisher) return;
if (publisher === this.participantService.getMyCameraPublisher()) {
this.publishAudioAux(this.participantService.getMyScreenPublisher(), this.participantService.isMyAudioActive()); if (this.screenSession?.capabilities?.publish) {
await this.webcamSession.unpublish(publisher); return this.screenSession.publish(publisher);
} else if (publisher === this.participantService.getMyScreenPublisher()) {
await this.screenSession.unpublish(publisher);
} }
this.log.e('Screen publisher cannot be published');
} }
/**
* Unpublishes the publisher of the webcam Session
* @param publisher
*/
async unpublishCamera(publisher: Publisher): Promise<void> {
if (!publisher) return;
return this.webcamSession.unpublish(publisher);
}
/**
* Unpublishes the publisher of the screen Session
* @param publisher
*/
async unpublishScreen(publisher: Publisher): Promise<void> {
if (!publisher) return;
return this.screenSession.unpublish(publisher);
} }
/** /**
* Publish or unpublish the video stream (if available). * Publish or unpublish the video stream (if available).
* It hides the camera muted stream if screen is sharing. * It hides the camera muted stream if screen is sharing.
* See openvidu-browser {@link https://docs.openvidu.io/en/stable/api/openvidu-browser/classes/Publisher.html#publishVideo publishVideo} * See openvidu-browser {@link https://docs.openvidu.io/en/stable/api/openvidu-browser/classes/Publisher.html#publishVideo publishVideo}
*
* @deprecated This method has been moved to ParticipantService
*
* TODO: Remove this method in release 2.28.0
*/ */
async publishVideo(publish: boolean): Promise<void> { async publishVideo(publish: boolean): Promise<void> {
const publishAudio = this.participantService.isMyAudioActive(); const participantService = this.injector.get(ParticipantService);
participantService.publishVideo(publish);
// Disabling webcam
if (this.participantService.haveICameraAndScreenActive()) {
await this.publishVideoAux(this.participantService.getMyCameraPublisher(), publish);
await this.unpublish(this.participantService.getMyCameraPublisher());
this.publishAudioAux(this.participantService.getMyScreenPublisher(), publishAudio);
this.participantService.disableWebcamStream();
} else if (this.participantService.isOnlyMyScreenActive()) {
// Enabling webcam
const hasAudio = this.participantService.hasScreenAudioActive();
if (!this.isWebcamSessionConnected()) {
await this.connectSession(this.getWebcamSession(), this.getWebcamToken());
}
await this.publish(this.participantService.getMyCameraPublisher());
await this.publishVideoAux(this.participantService.getMyCameraPublisher(), true);
this.publishAudioAux(this.participantService.getMyScreenPublisher(), false);
this.publishAudioAux(this.participantService.getMyCameraPublisher(), hasAudio);
this.participantService.enableWebcamStream();
} else {
// Muting/unmuting webcam
await this.publishVideoAux(this.participantService.getMyCameraPublisher(), publish);
}
}
/**
* @internal
*/
private async publishVideoAux(publisher: Publisher, publish: boolean): Promise<void> {
if (!!publisher) {
let resource: boolean | MediaStreamTrack = true;
if (publish) {
// Forcing restoration with a custom media stream (the older one instead the default)
const currentDeviceId = this.deviceService.getCameraSelected()?.device;
const mediaStream = await this.createMediaStream({ videoSource: currentDeviceId, audioSource: false });
resource = mediaStream.getVideoTracks()[0];
}
await publisher.publishVideo(publish, resource);
this.participantService.updateLocalParticipant();
}
} }
/** /**
* Share or unshare the screen. * Share or unshare the screen.
* Hide the camera muted stream when screen is sharing. * Hide the camera muted stream when screen is sharing.
* @deprecated This method has been moved to ParticipantService
* *
* TODO: This method should be in participant service * TODO: Remove this method in release 2.28.0
*/ */
async toggleScreenshare() { async toggleScreenshare() {
if (this.participantService.haveICameraAndScreenActive()) { const participantService = this.injector.get(ParticipantService);
const screenPublisher = participantService.getMyScreenPublisher();
const cameraPublisher = participantService.getMyCameraPublisher();
const participantNickname = participantService.getMyNickname();
const participantId = participantService.getLocalParticipant().id;
if (participantService.haveICameraAndScreenActive()) {
// Disabling screenShare // Disabling screenShare
this.participantService.disableScreenStream(); participantService.disableScreenStream();
await this.unpublish(this.participantService.getMyScreenPublisher()); this.unpublishScreen(screenPublisher);
} else if (this.participantService.isOnlyMyCameraActive()) { } else if (participantService.isOnlyMyCameraActive()) {
// I only have the camera published // I only have the camera published
const hasAudioDevicesAvailable = this.deviceService.hasAudioDeviceAvailable(); const hasAudioDevicesAvailable = this.deviceService.hasAudioDeviceAvailable();
const willWebcamBePresent = this.participantService.isMyCameraActive() && this.participantService.isMyVideoActive(); const willWebcamBePresent = participantService.isMyCameraActive() && participantService.isMyVideoActive();
const hasAudio = willWebcamBePresent ? false : hasAudioDevicesAvailable && this.participantService.isMyAudioActive(); const hasAudio = willWebcamBePresent ? false : hasAudioDevicesAvailable && participantService.isMyAudioActive();
const properties: PublisherProperties = { const properties: PublisherProperties = {
videoSource: ScreenType.SCREEN, videoSource: ScreenType.SCREEN,
@ -404,16 +398,16 @@ export class OpenViduService {
}); });
// Enabling screenShare // Enabling screenShare
this.participantService.activeMyScreenShare(screenPublisher); participantService.activeMyScreenShare(screenPublisher);
if (!this.isScreenSessionConnected()) { if (!this.isScreenSessionConnected()) {
await this.connectSession(this.getScreenSession(), this.getScreenToken()); await this.connectScreenSession(participantId, participantNickname);
} }
await this.publish(this.participantService.getMyScreenPublisher()); await this.publishScreen(screenPublisher);
if (!this.participantService.isMyVideoActive()) { if (!participantService.isMyVideoActive()) {
// Disabling webcam // Disabling webcam
this.participantService.disableWebcamStream(); participantService.disableWebcamStream();
await this.unpublish(this.participantService.getMyCameraPublisher()); this.unpublishCamera(cameraPublisher);
} }
}); });
@ -422,52 +416,71 @@ export class OpenViduService {
}); });
} else { } else {
// I only have my screenshare active and I have no camera or it is muted // I only have my screenshare active and I have no camera or it is muted
const hasAudio = this.participantService.hasScreenAudioActive(); const hasAudio = participantService.hasScreenAudioActive();
// Enable webcam // Enable webcam
if (!this.isWebcamSessionConnected()) { if (!this.isWebcamSessionConnected()) {
await this.connectSession(this.getWebcamSession(), this.getWebcamToken()); await this.connectWebcamSession(participantId, participantNickname);
} }
await this.publish(this.participantService.getMyCameraPublisher()); await this.publishCamera(cameraPublisher);
this.publishAudioAux(this.participantService.getMyCameraPublisher(), hasAudio); this.publishAudioAux(cameraPublisher, hasAudio);
this.participantService.enableWebcamStream(); participantService.enableWebcamStream();
// Disabling screenshare // Disabling screenshare
this.participantService.disableScreenStream(); participantService.disableScreenStream();
await this.unpublish(this.participantService.getMyScreenPublisher()); this.unpublishScreen(screenPublisher);
} }
} }
/** /**
* @internal * @internal
* TODO: Remove when it is in participant service * @deprecated
*
* TODO: Remove this method in release 2.28.0
*/ */
private publishAudioAux(publisher: Publisher, value: boolean): void { private publishAudioAux(publisher: Publisher, value: boolean): void {
const participantService = this.injector.get(ParticipantService);
if (!!publisher) { if (!!publisher) {
publisher.publishAudio(value); publisher.publishAudio(value);
this.participantService.updateLocalParticipant(); participantService.updateLocalParticipant();
} }
} }
/**
*
* Publish or unpublish the audio stream (if available).
* See openvidu-browser {@link https://docs.openvidu.io/en/stable/api/openvidu-browser/classes/Publisher.html#publishAudio publishAudio}.
* @deprecated This method has been moved to ParticipantService
*/
publishAudio(publish: boolean): void {
const participantService = this.injector.get(ParticipantService);
participantService.publishAudio(publish);
}
/** /**
* @internal * @internal
* *
* @param type: type of signal * @param type: type of signal
* @param connections: if undefined, the signal will be sent to all participants * @param connections: if undefined, the signal will be sent to all participants
*/ */
sendSignal(type: Signal, connections?: Connection[], data?: any): void { sendSignal(type: Signal, connections?: Connection[], data?: any): Promise<void> {
const signalOptions: SignalOptions = { const signalOptions: SignalOptions = {
data: JSON.stringify(data), data: JSON.stringify(data),
type, type,
to: connections && connections.length > 0 ? connections : undefined to: connections && connections.length > 0 ? connections : undefined
}; };
this.webcamSession.signal(signalOptions); return this.webcamSession.signal(signalOptions);
} }
/** /**
* @internal * @internal
*/ */
async replaceTrack(videoType: VideoType, props: PublisherProperties) { async replaceTrack(videoType: VideoType, props: PublisherProperties) {
const participantService = this.injector.get(ParticipantService);
const screenPublisher = participantService.getMyScreenPublisher();
const cameraPublisher = participantService.getMyCameraPublisher();
try { try {
this.log.d(`Replacing ${videoType} track`, props); this.log.d(`Replacing ${videoType} track`, props);
@ -480,18 +493,18 @@ export class OpenViduService {
mediaStream = await this.createMediaStream(props); mediaStream = await this.createMediaStream(props);
// Replace video track // Replace video track
const videoTrack: MediaStreamTrack = mediaStream.getVideoTracks()[0]; const videoTrack: MediaStreamTrack = mediaStream.getVideoTracks()[0];
await this.participantService.getMyCameraPublisher().replaceTrack(videoTrack); await cameraPublisher.replaceTrack(videoTrack);
} else if (isReplacingAudio) { } else if (isReplacingAudio) {
mediaStream = await this.createMediaStream(props); mediaStream = await this.createMediaStream(props);
// Replace audio track // Replace audio track
const audioTrack: MediaStreamTrack = mediaStream.getAudioTracks()[0]; const audioTrack: MediaStreamTrack = mediaStream.getAudioTracks()[0];
await this.participantService.getMyCameraPublisher().replaceTrack(audioTrack); await cameraPublisher.replaceTrack(audioTrack);
} }
} else if (videoType === VideoType.SCREEN) { } else if (videoType === VideoType.SCREEN) {
try { try {
let newScreenMediaStream = await this.OVScreen.getUserMedia(props); let newScreenMediaStream = await this.OVScreen.getUserMedia(props);
this.participantService.getMyScreenPublisher().stream.getMediaStream().getVideoTracks()[0].stop(); screenPublisher.stream.getMediaStream().getVideoTracks()[0].stop();
await this.participantService.getMyScreenPublisher().replaceTrack(newScreenMediaStream.getVideoTracks()[0]); await screenPublisher.replaceTrack(newScreenMediaStream.getVideoTracks()[0]);
} catch (error) { } catch (error) {
this.log.w('Cannot create the new MediaStream', error); this.log.w('Cannot create the new MediaStream', error);
} }
@ -509,7 +522,9 @@ export class OpenViduService {
* @param lang The language of the Stream's audio track. * @param lang The language of the Stream's audio track.
*/ */
async subscribeRemotesToSTT(lang: string): Promise<void> { async subscribeRemotesToSTT(lang: string): Promise<void> {
const remoteParticipants = this.participantService.getRemoteParticipants(); const participantService = this.injector.get(ParticipantService);
const remoteParticipants = participantService.getRemoteParticipants();
let successNumber = 0; let successNumber = 0;
for (const p of remoteParticipants) { for (const p of remoteParticipants) {
@ -548,9 +563,11 @@ export class OpenViduService {
* Unsubscribe to all `CAMERA` stream types to speech-to-text if STT is up(ready) * Unsubscribe to all `CAMERA` stream types to speech-to-text if STT is up(ready)
*/ */
async unsubscribeRemotesFromSTT(): Promise<void> { async unsubscribeRemotesFromSTT(): Promise<void> {
const participantService = this.injector.get(ParticipantService);
clearTimeout(this.sttReconnectionTimeout); clearTimeout(this.sttReconnectionTimeout);
if (this.isSttReady()) { if (this.isSttReady()) {
for (const p of this.participantService.getRemoteParticipants()) { for (const p of participantService.getRemoteParticipants()) {
const stream = p.getCameraConnection().streamManager.stream; const stream = p.getCameraConnection().streamManager.stream;
if (stream) { if (stream) {
try { try {
@ -563,7 +580,14 @@ export class OpenViduService {
} }
} }
private async createMediaStream(pp: PublisherProperties): Promise<MediaStream> {
/**
* @internal
* @param pp {@link PublisherProperties}
* @returns Promise<MediaStream>
*/
async createMediaStream(pp: PublisherProperties): Promise<MediaStream> {
const participantService = this.injector.get(ParticipantService);
const currentCameraSelected = this.deviceService.getCameraSelected(); const currentCameraSelected = this.deviceService.getCameraSelected();
const currentMicSelected = this.deviceService.getMicrophoneSelected(); const currentMicSelected = this.deviceService.getMicrophoneSelected();
const isReplacingAudio = Boolean(pp.audioSource); const isReplacingAudio = Boolean(pp.audioSource);
@ -571,7 +595,7 @@ export class OpenViduService {
try { try {
const trackType = isReplacingAudio ? 'audio' : 'video'; const trackType = isReplacingAudio ? 'audio' : 'video';
this.forceStopMediaTracks(this.participantService.getMyCameraPublisher().stream.getMediaStream(), trackType); this.forceStopMediaTracks(participantService.getMyCameraPublisher().stream.getMediaStream(), trackType);
return this.OV.getUserMedia(pp); return this.OV.getUserMedia(pp);
} catch (error) { } catch (error) {
console.warn('Error creating MediaStream', error); console.warn('Error creating MediaStream', error);
@ -594,6 +618,7 @@ export class OpenViduService {
* @internal * @internal
*/ */
needSendNicknameSignal(): boolean { needSendNicknameSignal(): boolean {
const participantService = this.injector.get(ParticipantService);
let oldNickname: string = ""; let oldNickname: string = "";
try { try {
const connData = JSON.parse(this.cleanConnectionData(this.webcamSession.connection.data)); const connData = JSON.parse(this.cleanConnectionData(this.webcamSession.connection.data));
@ -601,7 +626,7 @@ export class OpenViduService {
} catch (error) { } catch (error) {
this.log.e(error); this.log.e(error);
} finally { } finally {
return oldNickname !== this.participantService.getMyNickname(); return oldNickname !== participantService.getMyNickname();
} }
} }

View File

@ -11,7 +11,9 @@ import {
} from '../../models/participant.model'; } from '../../models/participant.model';
import { VideoType } from '../../models/video-type.model'; import { VideoType } from '../../models/video-type.model';
import { OpenViduAngularConfigService } from '../config/openvidu-angular.config.service'; import { OpenViduAngularConfigService } from '../config/openvidu-angular.config.service';
import { DeviceService } from '../device/device.service';
import { LoggerService } from '../logger/logger.service'; import { LoggerService } from '../logger/logger.service';
import { OpenViduService } from '../openvidu/openvidu.service';
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
@ -39,7 +41,12 @@ export class ParticipantService {
/** /**
* @internal * @internal
*/ */
constructor(protected openviduAngularConfigSrv: OpenViduAngularConfigService, protected loggerSrv: LoggerService) { constructor(
protected openviduAngularConfigSrv: OpenViduAngularConfigService,
private openviduService: OpenViduService,
private deviceService: DeviceService,
protected loggerSrv: LoggerService
) {
this.log = this.loggerSrv.get('ParticipantService'); this.log = this.loggerSrv.get('ParticipantService');
this.localParticipantObs = this._localParticipant.asObservable(); this.localParticipantObs = this._localParticipant.asObservable();
this.remoteParticipantsObs = this._remoteParticipants.asObservable(); this.remoteParticipantsObs = this._remoteParticipants.asObservable();
@ -58,7 +65,40 @@ export class ParticipantService {
} }
/** /**
* Publish or unpublish the audio stream (if available). * Publish or unpublish the local participant video stream (if available).
* It hides the camera stream (while muted) if screen is sharing.
* See openvidu-browser {@link https://docs.openvidu.io/en/stable/api/openvidu-browser/classes/Publisher.html#publishVideo publishVideo}
*
*/
async publishVideo(publish: boolean): Promise<void> {
const publishAudio = this.isMyAudioActive();
const cameraPublisher = this.getMyCameraPublisher();
const screenPublisher = this.getMyScreenPublisher();
// Disabling webcam
if (this.haveICameraAndScreenActive()) {
await this.publishVideoAux(cameraPublisher, publish);
this.disableWebcamStream();
this.openviduService.unpublishCamera(cameraPublisher);
this.publishAudioAux(screenPublisher, publishAudio);
} else if (this.isOnlyMyScreenActive()) {
// Enabling webcam
const hasAudio = this.hasScreenAudioActive();
const sessionId = await this.openviduService.connectWebcamSession(this.getMyNickname(), this.getLocalParticipant().id);
if (sessionId) this.setMyCameraConnectionId(sessionId);
await this.openviduService.publishCamera(cameraPublisher);
await this.publishVideoAux(cameraPublisher, true);
this.publishAudioAux(screenPublisher, false);
this.publishAudioAux(cameraPublisher, hasAudio);
this.enableWebcamStream();
} else {
// Muting/unmuting webcam
await this.publishVideoAux(cameraPublisher, publish);
}
}
/**
* Publish or unpublish the local participant audio stream (if available).
* See openvidu-browser {@link https://docs.openvidu.io/en/stable/api/openvidu-browser/classes/Publisher.html#publishAudio publishAudio}. * See openvidu-browser {@link https://docs.openvidu.io/en/stable/api/openvidu-browser/classes/Publisher.html#publishAudio publishAudio}.
* *
*/ */
@ -277,6 +317,24 @@ export class ParticipantService {
} }
} }
/**
* @internal
*/
private async publishVideoAux(publisher: Publisher, publish: boolean): Promise<void> {
if (!!publisher) {
let resource: boolean | MediaStreamTrack = true;
if (publish) {
// Forcing restoration with a custom media stream (the older one instead the default)
const currentDeviceId = this.deviceService.getCameraSelected()?.device;
const mediaStream = await this.openviduService.createMediaStream({ videoSource: currentDeviceId, audioSource: false });
resource = mediaStream.getVideoTracks()[0];
}
await publisher.publishVideo(publish, resource);
this.updateLocalParticipant();
}
}
/** /**
* REMOTE USERS * REMOTE USERS
*/ */