mirror of https://github.com/OpenVidu/openvidu.git
openvidu-components: Fixed replace tracks in session
parent
ea3f16778e
commit
eaed1b3692
|
@ -1,11 +1,9 @@
|
||||||
import { Component, Input, OnDestroy, OnInit } from '@angular/core';
|
import { Component, Input, OnDestroy, OnInit } from '@angular/core';
|
||||||
|
import { PublisherSpeakingEvent, StreamManager, StreamPropertyChangedEvent } from 'openvidu-browser';
|
||||||
import { PublisherSpeakingEvent, StreamManager } from 'openvidu-browser';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ov-audio-wave',
|
selector: 'ov-audio-wave',
|
||||||
templateUrl: './audio-wave.component.html',
|
templateUrl: './audio-wave.component.html',
|
||||||
|
@ -13,40 +11,49 @@ import { PublisherSpeakingEvent, StreamManager } from 'openvidu-browser';
|
||||||
})
|
})
|
||||||
export class AudioWaveComponent implements OnInit, OnDestroy {
|
export class AudioWaveComponent implements OnInit, OnDestroy {
|
||||||
isSpeaking: boolean = false;
|
isSpeaking: boolean = false;
|
||||||
// audioVolume: number = 0;
|
|
||||||
|
|
||||||
private _streamManager: StreamManager;
|
@Input() 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);
|
|
||||||
// });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor() {}
|
constructor() {}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.subscribeSpeakingEvents();
|
||||||
|
this.subscribeToStreamPropertyChanged();
|
||||||
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
if (this._streamManager) {
|
this.unsubscribeSpeakingEvents();
|
||||||
this._streamManager.off('publisherStartSpeaking');
|
this.unsubscribePropertyChangedEvents();
|
||||||
this._streamManager.off('publisherStopSpeaking');
|
}
|
||||||
|
|
||||||
|
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');
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import { CustomDevice } from '../../../models/device.model';
|
||||||
import { ParticipantAbstractModel } from '../../../models/participant.model';
|
import { ParticipantAbstractModel } from '../../../models/participant.model';
|
||||||
import { ParticipantService } from '../../../services/participant/participant.service';
|
import { ParticipantService } from '../../../services/participant/participant.service';
|
||||||
import { Subscription } from 'rxjs';
|
import { Subscription } from 'rxjs';
|
||||||
|
import { VideoType } from '../../../models/video-type.model';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
|
@ -59,14 +60,8 @@ export class AudioDevicesComponent implements OnInit, OnDestroy {
|
||||||
async onMicrophoneSelected(event: any) {
|
async onMicrophoneSelected(event: any) {
|
||||||
const audioSource = event?.value;
|
const audioSource = event?.value;
|
||||||
if (this.deviceSrv.needUpdateAudioTrack(audioSource)) {
|
if (this.deviceSrv.needUpdateAudioTrack(audioSource)) {
|
||||||
//TODO: Uncomment this when replaceTrack issue is fixed
|
const pp: PublisherProperties = { audioSource, videoSource: false };
|
||||||
// const pp: PublisherProperties = { audioSource, videoSource: false };
|
await this.openviduService.replaceTrack(VideoType.CAMERA, pp);
|
||||||
// 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);
|
|
||||||
|
|
||||||
this.deviceSrv.setMicSelected(audioSource);
|
this.deviceSrv.setMicSelected(audioSource);
|
||||||
this.microphoneSelected = this.deviceSrv.getMicrophoneSelected();
|
this.microphoneSelected = this.deviceSrv.getMicrophoneSelected();
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { Subscription } from 'rxjs';
|
||||||
import { CustomDevice } from '../../../models/device.model';
|
import { CustomDevice } from '../../../models/device.model';
|
||||||
import { PanelType } from '../../../models/panel.model';
|
import { PanelType } from '../../../models/panel.model';
|
||||||
import { ParticipantAbstractModel } from '../../../models/participant.model';
|
import { ParticipantAbstractModel } from '../../../models/participant.model';
|
||||||
|
import { VideoType } from '../../../models/video-type.model';
|
||||||
import { DeviceService } from '../../../services/device/device.service';
|
import { DeviceService } from '../../../services/device/device.service';
|
||||||
import { OpenViduService } from '../../../services/openvidu/openvidu.service';
|
import { OpenViduService } from '../../../services/openvidu/openvidu.service';
|
||||||
import { PanelService } from '../../../services/panel/panel.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?
|
// Is New deviceId different from the old one?
|
||||||
if (this.deviceSrv.needUpdateVideoTrack(videoSource)) {
|
if (this.deviceSrv.needUpdateVideoTrack(videoSource)) {
|
||||||
const mirror = this.deviceSrv.cameraNeedsMirror(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
|
// Reapply Virtual Background to new Publisher if necessary
|
||||||
const backgroundSelected = this.backgroundService.backgroundSelected.getValue();
|
const backgroundSelected = this.backgroundService.backgroundSelected.getValue();
|
||||||
if (this.backgroundService.isBackgroundApplied()) {
|
if (this.backgroundService.isBackgroundApplied()) {
|
||||||
await this.backgroundService.removeBackground();
|
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()) {
|
if (this.backgroundService.isBackgroundApplied()) {
|
||||||
const bgSelected = this.backgroundService.backgrounds.find((b) => b.id === backgroundSelected);
|
const bgSelected = this.backgroundService.backgrounds.find((b) => b.id === backgroundSelected);
|
||||||
if (bgSelected) {
|
if (bgSelected) {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { Injectable } from '@angular/core';
|
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';
|
import { LoggerService } from '../logger/logger.service';
|
||||||
|
|
||||||
|
@ -323,7 +323,6 @@ export class OpenViduService {
|
||||||
const willWebcamBePresent = this.participantService.isMyCameraActive() && this.participantService.isMyVideoActive();
|
const willWebcamBePresent = this.participantService.isMyCameraActive() && this.participantService.isMyVideoActive();
|
||||||
const hasAudio = willWebcamBePresent ? false : hasAudioDevicesAvailable && this.participantService.isMyAudioActive();
|
const hasAudio = willWebcamBePresent ? false : hasAudioDevicesAvailable && this.participantService.isMyAudioActive();
|
||||||
|
|
||||||
console.warn('will be audio active', hasAudio);
|
|
||||||
const properties: PublisherProperties = {
|
const properties: PublisherProperties = {
|
||||||
videoSource: ScreenType.SCREEN,
|
videoSource: ScreenType.SCREEN,
|
||||||
audioSource: hasAudioDevicesAvailable ? this.deviceService.getMicrophoneSelected().device : null,
|
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
|
* @internal
|
||||||
*/
|
*/
|
||||||
|
@ -437,12 +397,6 @@ export class OpenViduService {
|
||||||
to: connections && connections.length > 0 ? connections : undefined
|
to: connections && connections.length > 0 ? connections : undefined
|
||||||
};
|
};
|
||||||
this.webcamSession.signal(signalOptions);
|
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);
|
this.log.d(`Replacing ${videoType} track`, props);
|
||||||
|
|
||||||
if (videoType === VideoType.CAMERA) {
|
if (videoType === VideoType.CAMERA) {
|
||||||
//TODO: Uncomment this section when replaceTrack issue is fixed
|
let mediaStream: MediaStream;
|
||||||
// https://github.com/OpenVidu/openvidu/pull/700
|
const isReplacingAudio = !!props.audioSource;
|
||||||
throw 'Replace track feature has a bug. We are trying to fix it';
|
const isReplacingVideo = !!props.videoSource;
|
||||||
// let mediaStream: MediaStream;
|
|
||||||
// const oldMediaStream = this.participantService.getMyCameraPublisher().stream.getMediaStream();
|
|
||||||
// const isFirefoxPlatform = this.platformService.isFirefox();
|
|
||||||
// const isReplacingAudio = !!props.audioSource;
|
|
||||||
// const isReplacingVideo = !!props.videoSource;
|
|
||||||
|
|
||||||
// if (isReplacingVideo) {
|
if (isReplacingVideo) {
|
||||||
// if (isFirefoxPlatform) {
|
mediaStream = await this.createMediaStream(props);
|
||||||
// // Firefox throw an exception trying to get a new MediaStreamTrack if the older one is not stopped
|
// Replace video track
|
||||||
// // NotReadableError: Concurrent mic process limit. Stopping tracks before call to getUserMedia
|
const videoTrack: MediaStreamTrack = mediaStream.getVideoTracks()[0];
|
||||||
// oldMediaStream.getVideoTracks()[0].stop();
|
await this.participantService.getMyCameraPublisher().replaceTrack(videoTrack);
|
||||||
// }
|
} else if (isReplacingAudio) {
|
||||||
// mediaStream = await this.createMediaStream(props);
|
mediaStream = await this.createMediaStream(props);
|
||||||
// // Replace video track
|
// Replace audio track
|
||||||
// const videoTrack: MediaStreamTrack = mediaStream.getVideoTracks()[0];
|
const audioTrack: MediaStreamTrack = mediaStream.getAudioTracks()[0];
|
||||||
// await this.participantService.getMyCameraPublisher().replaceTrack(videoTrack);
|
await this.participantService.getMyCameraPublisher().replaceTrack(audioTrack);
|
||||||
// } 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);
|
|
||||||
// }
|
|
||||||
} else if (videoType === VideoType.SCREEN) {
|
} else if (videoType === VideoType.SCREEN) {
|
||||||
let newScreenMediaStream;
|
|
||||||
try {
|
try {
|
||||||
newScreenMediaStream = await this.OVScreen.getUserMedia(props);
|
let newScreenMediaStream = await this.OVScreen.getUserMedia(props);
|
||||||
this.participantService.getMyScreenPublisher().stream.getMediaStream().getVideoTracks()[0].stop();
|
this.participantService.getMyScreenPublisher().stream.getMediaStream().getVideoTracks()[0].stop();
|
||||||
await this.participantService.getMyScreenPublisher().replaceTrack(newScreenMediaStream.getVideoTracks()[0]);
|
await this.participantService.getMyScreenPublisher().replaceTrack(newScreenMediaStream.getVideoTracks()[0]);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -513,32 +451,32 @@ export class OpenViduService {
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: Uncomment this section when replaceTrack issue is fixed
|
//TODO: Uncomment this section when replaceTrack issue is fixed
|
||||||
// private async createMediaStream(pp: PublisherProperties): Promise<MediaStream> {
|
private async createMediaStream(pp: PublisherProperties): Promise<MediaStream> {
|
||||||
// let mediaStream: MediaStream;
|
let mediaStream: MediaStream;
|
||||||
// const isFirefoxPlatform = this.platformService.isFirefox();
|
const isFirefoxPlatform = this.platformService.isFirefox();
|
||||||
// const isReplacingAudio = !!pp.audioSource;
|
const isReplacingAudio = !!pp.audioSource;
|
||||||
// const isReplacingVideo = !!pp.videoSource;
|
const isReplacingVideo = !!pp.videoSource;
|
||||||
|
|
||||||
// try {
|
try {
|
||||||
// mediaStream = await this.OV.getUserMedia(pp);
|
mediaStream = await this.OV.getUserMedia(pp);
|
||||||
// } catch (error) {
|
} catch (error) {
|
||||||
// if ((<OpenViduError>error).name === OpenViduErrorName.DEVICE_ACCESS_DENIED) {
|
if ((<OpenViduError>error).name === OpenViduErrorName.DEVICE_ACCESS_DENIED) {
|
||||||
// if (isFirefoxPlatform) {
|
if (isFirefoxPlatform) {
|
||||||
// this.log.w('The device requested is not available. Restoring the older one');
|
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
|
// The track requested is not available so we are getting the old tracks ids for recovering the track
|
||||||
// if (isReplacingVideo) {
|
if (isReplacingVideo) {
|
||||||
// pp.videoSource = this.deviceService.getCameraSelected().device;
|
pp.videoSource = this.deviceService.getCameraSelected().device;
|
||||||
// } else if (isReplacingAudio) {
|
} else if (isReplacingAudio) {
|
||||||
// pp.audioSource = this.deviceService.getMicrophoneSelected().device;
|
pp.audioSource = this.deviceService.getMicrophoneSelected().device;
|
||||||
// }
|
}
|
||||||
// mediaStream = await this.OV.getUserMedia(pp);
|
mediaStream = await this.OV.getUserMedia(pp);
|
||||||
// // TODO show error alert informing that the new device is not available
|
// TODO show error alert informing that the new device is not available
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// } finally {
|
} finally {
|
||||||
// return mediaStream;
|
return mediaStream;
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
|
|
Loading…
Reference in New Issue