openvidu-components: Fixed replace tracks in session

pull/743/head
csantosm 2022-06-24 16:12:36 +02:00
parent ea3f16778e
commit eaed1b3692
4 changed files with 87 additions and 150 deletions

View File

@ -1,11 +1,9 @@
import { Component, Input, OnDestroy, OnInit } from '@angular/core';
import { PublisherSpeakingEvent, StreamManager } from 'openvidu-browser';
import { PublisherSpeakingEvent, StreamManager, StreamPropertyChangedEvent } from 'openvidu-browser';
/**
* @internal
*/
@Component({
selector: 'ov-audio-wave',
templateUrl: './audio-wave.component.html',
@ -13,40 +11,49 @@ import { PublisherSpeakingEvent, StreamManager } from 'openvidu-browser';
})
export class AudioWaveComponent implements OnInit, OnDestroy {
isSpeaking: boolean = false;
// audioVolume: number = 0;
private _streamManager: StreamManager;
@Input()
set streamManager(streamManager: StreamManager) {
this._streamManager = streamManager;
if (this._streamManager) {
this._streamManager.on('publisherStartSpeaking', (event: PublisherSpeakingEvent) => {
this.isSpeaking = true;
});
this._streamManager.on('publisherStopSpeaking', (event: PublisherSpeakingEvent) => {
this.isSpeaking = false;
});
// streamManager.on('streamAudioVolumeChange', (event: any) => {
// // The loudest sounds on your system will be at 0dB
// // and silence in webaudio is -100dB.
// this.audioVolume = 100 + event.value.newValue;
// console.log('Publisher audio volume change from ' + event.value.oldValue + ' to' + event.value.newValue);
// console.log('AUDIO VOLUME', this.audioVolume);
// });
}
}
@Input() streamManager: StreamManager;
constructor() {}
ngOnInit(): void {
this.subscribeSpeakingEvents();
this.subscribeToStreamPropertyChanged();
}
ngOnDestroy(): void {
if (this._streamManager) {
this._streamManager.off('publisherStartSpeaking');
this._streamManager.off('publisherStopSpeaking');
this.unsubscribeSpeakingEvents();
this.unsubscribePropertyChangedEvents();
}
private subscribeToStreamPropertyChanged() {
if (this.streamManager) {
this.streamManager.on('streamPropertyChanged', (event: StreamPropertyChangedEvent) => {
if (event.reason === 'trackReplaced' && event.changedProperty === 'audioActive') {
// FIXUP: When the audio track is replaced, the startSpeakingEvents is not fired by openvidu-browser
this.unsubscribeSpeakingEvents();
this.subscribeSpeakingEvents();
}
});
}
}
ngOnInit(): void {}
private subscribeSpeakingEvents() {
if (this.streamManager) {
this.streamManager.on('publisherStartSpeaking', (event: PublisherSpeakingEvent) => (this.isSpeaking = true));
this.streamManager.on('publisherStopSpeaking', (event: PublisherSpeakingEvent) => (this.isSpeaking = false));
}
}
private unsubscribeSpeakingEvents() {
if (this.streamManager) {
this.streamManager.off('publisherStartSpeaking');
this.streamManager.off('publisherStopSpeaking');
}
}
private unsubscribePropertyChangedEvents() {
if (this.streamManager) {
this.streamManager.off('streamPropertyChanged');
}
}
}

View File

@ -7,6 +7,7 @@ import { CustomDevice } from '../../../models/device.model';
import { ParticipantAbstractModel } from '../../../models/participant.model';
import { ParticipantService } from '../../../services/participant/participant.service';
import { Subscription } from 'rxjs';
import { VideoType } from '../../../models/video-type.model';
/**
* @internal
@ -59,14 +60,8 @@ export class AudioDevicesComponent implements OnInit, OnDestroy {
async onMicrophoneSelected(event: any) {
const audioSource = event?.value;
if (this.deviceSrv.needUpdateAudioTrack(audioSource)) {
//TODO: Uncomment this when replaceTrack issue is fixed
// const pp: PublisherProperties = { audioSource, videoSource: false };
// await this.openviduService.replaceTrack(VideoType.CAMERA, pp);
// TODO: Remove this when replaceTrack issue is fixed
const mirror = this.deviceSrv.cameraNeedsMirror(this.deviceSrv.getCameraSelected().device);
const pp: PublisherProperties = { videoSource: this.deviceSrv.getCameraSelected().device, audioSource, mirror };
await this.openviduService.republishTrack(pp);
const pp: PublisherProperties = { audioSource, videoSource: false };
await this.openviduService.replaceTrack(VideoType.CAMERA, pp);
this.deviceSrv.setMicSelected(audioSource);
this.microphoneSelected = this.deviceSrv.getMicrophoneSelected();
}

View File

@ -4,6 +4,7 @@ import { Subscription } from 'rxjs';
import { CustomDevice } from '../../../models/device.model';
import { PanelType } from '../../../models/panel.model';
import { ParticipantAbstractModel } from '../../../models/participant.model';
import { VideoType } from '../../../models/video-type.model';
import { DeviceService } from '../../../services/device/device.service';
import { OpenViduService } from '../../../services/openvidu/openvidu.service';
import { PanelService } from '../../../services/panel/panel.service';
@ -72,18 +73,14 @@ export class VideoDevicesComponent implements OnInit, OnDestroy {
// Is New deviceId different from the old one?
if (this.deviceSrv.needUpdateVideoTrack(videoSource)) {
const mirror = this.deviceSrv.cameraNeedsMirror(videoSource);
//TODO: Uncomment this when replaceTrack issue is fixed
// const pp: PublisherProperties = { videoSource, audioSource: false, mirror };
// await this.openviduService.replaceTrack(VideoType.CAMERA, pp);
// TODO: Remove this when replaceTrack issue is fixed
const pp: PublisherProperties = { videoSource, audioSource: this.deviceSrv.getMicrophoneSelected().device, mirror };
// Reapply Virtual Background to new Publisher if necessary
const backgroundSelected = this.backgroundService.backgroundSelected.getValue();
if (this.backgroundService.isBackgroundApplied()) {
await this.backgroundService.removeBackground();
}
await this.openviduService.republishTrack(pp);
const pp: PublisherProperties = { videoSource, audioSource: false, mirror };
await this.openviduService.replaceTrack(VideoType.CAMERA, pp);
if (this.backgroundService.isBackgroundApplied()) {
const bgSelected = this.backgroundService.backgrounds.find((b) => b.id === backgroundSelected);
if (bgSelected) {

View File

@ -1,5 +1,5 @@
import { Injectable } from '@angular/core';
import { Connection, OpenVidu, Publisher, PublisherProperties, Session, SignalOptions, Stream } from 'openvidu-browser';
import { Connection, OpenVidu, OpenViduError, OpenViduErrorName, Publisher, PublisherProperties, Session, SignalOptions, Stream } from 'openvidu-browser';
import { LoggerService } from '../logger/logger.service';
@ -323,7 +323,6 @@ export class OpenViduService {
const willWebcamBePresent = this.participantService.isMyCameraActive() && this.participantService.isMyVideoActive();
const hasAudio = willWebcamBePresent ? false : hasAudioDevicesAvailable && this.participantService.isMyAudioActive();
console.warn('will be audio active', hasAudio);
const properties: PublisherProperties = {
videoSource: ScreenType.SCREEN,
audioSource: hasAudioDevicesAvailable ? this.deviceService.getMicrophoneSelected().device : null,
@ -388,45 +387,6 @@ export class OpenViduService {
}
}
/**
* TODO: Remove this method when replaceTrack issue is fixed
* https://github.com/OpenVidu/openvidu/pull/700
* @internal
*/
republishTrack(properties: PublisherProperties): Promise<void> {
const { videoSource, audioSource, mirror } = properties;
return new Promise(async (resolve, reject) => {
if (!!videoSource) {
this.log.d('Replacing video track ' + videoSource);
this.videoSource = videoSource;
}
if (!!audioSource) {
this.log.d('Replacing audio track ' + audioSource);
this.audioSource = audioSource;
}
this.destroyPublisher(this.participantService.getMyCameraPublisher());
const properties: PublisherProperties = {
videoSource: this.videoSource,
audioSource: this.audioSource,
publishVideo: this.participantService.isMyVideoActive(),
publishAudio: this.participantService.isMyAudioActive(),
mirror
};
const publisher = await this.initPublisher(undefined, properties);
this.participantService.setMyCameraPublisher(publisher);
publisher.once('streamPlaying', () => {
this.participantService.setMyCameraPublisher(publisher);
resolve();
});
publisher.once('accessDenied', () => {
reject();
});
});
}
/**
* @internal
*/
@ -437,12 +397,6 @@ export class OpenViduService {
to: connections && connections.length > 0 ? connections : undefined
};
this.webcamSession.signal(signalOptions);
// TODO: Check if it is necessary
// if (type === Signal.NICKNAME_CHANGED && !!this.getScreenSession().connection) {
// signalOptions.data = JSON.stringify({ clientData: this.participantService.getScreenNickname() });
// this.getScreenSession()?.signal(signalOptions);
// }
}
/**
@ -453,40 +407,24 @@ export class OpenViduService {
this.log.d(`Replacing ${videoType} track`, props);
if (videoType === VideoType.CAMERA) {
//TODO: Uncomment this section when replaceTrack issue is fixed
// https://github.com/OpenVidu/openvidu/pull/700
throw 'Replace track feature has a bug. We are trying to fix it';
// let mediaStream: MediaStream;
// const oldMediaStream = this.participantService.getMyCameraPublisher().stream.getMediaStream();
// const isFirefoxPlatform = this.platformService.isFirefox();
// const isReplacingAudio = !!props.audioSource;
// const isReplacingVideo = !!props.videoSource;
let mediaStream: MediaStream;
const isReplacingAudio = !!props.audioSource;
const isReplacingVideo = !!props.videoSource;
// if (isReplacingVideo) {
// if (isFirefoxPlatform) {
// // Firefox throw an exception trying to get a new MediaStreamTrack if the older one is not stopped
// // NotReadableError: Concurrent mic process limit. Stopping tracks before call to getUserMedia
// oldMediaStream.getVideoTracks()[0].stop();
// }
// mediaStream = await this.createMediaStream(props);
// // Replace video track
// const videoTrack: MediaStreamTrack = mediaStream.getVideoTracks()[0];
// await this.participantService.getMyCameraPublisher().replaceTrack(videoTrack);
// } else if (isReplacingAudio) {
// if (isFirefoxPlatform) {
// // Firefox throw an exception trying to get a new MediaStreamTrack if the older one is not stopped
// // NotReadableError: Concurrent mic process limit. Stopping tracks before call to getUserMedia
// oldMediaStream.getAudioTracks()[0].stop();
// }
// mediaStream = await this.createMediaStream(props);
// // Replace audio track
// const audioTrack: MediaStreamTrack = mediaStream.getAudioTracks()[0];
// await this.participantService.getMyCameraPublisher().replaceTrack(audioTrack);
// }
if (isReplacingVideo) {
mediaStream = await this.createMediaStream(props);
// Replace video track
const videoTrack: MediaStreamTrack = mediaStream.getVideoTracks()[0];
await this.participantService.getMyCameraPublisher().replaceTrack(videoTrack);
} else if (isReplacingAudio) {
mediaStream = await this.createMediaStream(props);
// Replace audio track
const audioTrack: MediaStreamTrack = mediaStream.getAudioTracks()[0];
await this.participantService.getMyCameraPublisher().replaceTrack(audioTrack);
}
} else if (videoType === VideoType.SCREEN) {
let newScreenMediaStream;
try {
newScreenMediaStream = await this.OVScreen.getUserMedia(props);
let newScreenMediaStream = await this.OVScreen.getUserMedia(props);
this.participantService.getMyScreenPublisher().stream.getMediaStream().getVideoTracks()[0].stop();
await this.participantService.getMyScreenPublisher().replaceTrack(newScreenMediaStream.getVideoTracks()[0]);
} catch (error) {
@ -513,32 +451,32 @@ export class OpenViduService {
}
//TODO: Uncomment this section when replaceTrack issue is fixed
// private async createMediaStream(pp: PublisherProperties): Promise<MediaStream> {
// let mediaStream: MediaStream;
// const isFirefoxPlatform = this.platformService.isFirefox();
// const isReplacingAudio = !!pp.audioSource;
// const isReplacingVideo = !!pp.videoSource;
private async createMediaStream(pp: PublisherProperties): Promise<MediaStream> {
let mediaStream: MediaStream;
const isFirefoxPlatform = this.platformService.isFirefox();
const isReplacingAudio = !!pp.audioSource;
const isReplacingVideo = !!pp.videoSource;
// try {
// mediaStream = await this.OV.getUserMedia(pp);
// } catch (error) {
// if ((<OpenViduError>error).name === OpenViduErrorName.DEVICE_ACCESS_DENIED) {
// if (isFirefoxPlatform) {
// this.log.w('The device requested is not available. Restoring the older one');
// // The track requested is not available so we are getting the old tracks ids for recovering the track
// if (isReplacingVideo) {
// pp.videoSource = this.deviceService.getCameraSelected().device;
// } else if (isReplacingAudio) {
// pp.audioSource = this.deviceService.getMicrophoneSelected().device;
// }
// mediaStream = await this.OV.getUserMedia(pp);
// // TODO show error alert informing that the new device is not available
// }
// }
// } finally {
// return mediaStream;
// }
// }
try {
mediaStream = await this.OV.getUserMedia(pp);
} catch (error) {
if ((<OpenViduError>error).name === OpenViduErrorName.DEVICE_ACCESS_DENIED) {
if (isFirefoxPlatform) {
this.log.w('The device requested is not available. Restoring the older one');
// The track requested is not available so we are getting the old tracks ids for recovering the track
if (isReplacingVideo) {
pp.videoSource = this.deviceService.getCameraSelected().device;
} else if (isReplacingAudio) {
pp.audioSource = this.deviceService.getMicrophoneSelected().device;
}
mediaStream = await this.OV.getUserMedia(pp);
// TODO show error alert informing that the new device is not available
}
}
} finally {
return mediaStream;
}
}
/**
* @internal