mirror of https://github.com/OpenVidu/openvidu.git
openvidu-browser: filter support
parent
95a078b14a
commit
ccd8d7a8b9
|
@ -129,7 +129,8 @@ export class Connection {
|
||||||
videoActive: opts.videoActive,
|
videoActive: opts.videoActive,
|
||||||
typeOfVideo: opts.typeOfVideo,
|
typeOfVideo: opts.typeOfVideo,
|
||||||
frameRate: opts.frameRate,
|
frameRate: opts.frameRate,
|
||||||
videoDimensions: !!opts.videoDimensions ? JSON.parse(opts.videoDimensions) : undefined
|
videoDimensions: !!opts.videoDimensions ? JSON.parse(opts.videoDimensions) : undefined,
|
||||||
|
filter: !!opts.filter ? opts.filter : {}
|
||||||
};
|
};
|
||||||
const stream = new Stream(this.session, streamOptions);
|
const stream = new Stream(this.session, streamOptions);
|
||||||
|
|
||||||
|
|
|
@ -188,7 +188,8 @@ export class OpenVidu {
|
||||||
publishAudio: (typeof properties.publishAudio !== 'undefined') ? properties.publishAudio : true,
|
publishAudio: (typeof properties.publishAudio !== 'undefined') ? properties.publishAudio : true,
|
||||||
publishVideo: (typeof properties.publishVideo !== 'undefined') ? properties.publishVideo : true,
|
publishVideo: (typeof properties.publishVideo !== 'undefined') ? properties.publishVideo : true,
|
||||||
resolution: this.isMediaStreamTrack(properties.videoSource) ? undefined : ((typeof properties.resolution !== 'undefined') ? properties.resolution : '640x480'),
|
resolution: this.isMediaStreamTrack(properties.videoSource) ? undefined : ((typeof properties.resolution !== 'undefined') ? properties.resolution : '640x480'),
|
||||||
videoSource: (typeof properties.videoSource !== 'undefined') ? properties.videoSource : undefined
|
videoSource: (typeof properties.videoSource !== 'undefined') ? properties.videoSource : undefined,
|
||||||
|
filter: properties.filter
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
|
|
@ -492,6 +492,99 @@ export class Session implements EventDispatcher {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
applyFilter(stream: Stream, type: string, options: string): Promise<any> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
console.info('Applying filter to stream ' + stream.streamId);
|
||||||
|
this.openvidu.sendRequest(
|
||||||
|
'applyFilter',
|
||||||
|
{ streamId: stream.streamId, type, options },
|
||||||
|
(error, response) => {
|
||||||
|
if (error) {
|
||||||
|
console.error('Error applying filter for Stream ' + stream.streamId, error);
|
||||||
|
if (error.code === 401) {
|
||||||
|
reject(new OpenViduError(OpenViduErrorName.OPENVIDU_PERMISSION_DENIED, "You don't have permissions to apply a filter"));
|
||||||
|
} else {
|
||||||
|
reject(error);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.info('Filter successfully applied on Stream ' + stream.streamId);
|
||||||
|
const oldValue = JSON.parse(JSON.stringify(stream.filter));
|
||||||
|
stream.filter = { type, options };
|
||||||
|
this.emitEvent('streamPropertyChanged', [new StreamPropertyChangedEvent(this, stream, 'filter', stream.filter, oldValue, 'applyFilter')]);
|
||||||
|
stream.streamManager.emitEvent('streamPropertyChanged', [new StreamPropertyChangedEvent(stream.streamManager, stream, 'filter', stream.filter, oldValue, 'applyFilter')]);
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
execFilterMethod(stream: Stream, method: string, params: Object): Promise<any> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
console.info('Executing filter method to stream ' + stream.streamId);
|
||||||
|
let stringParams;
|
||||||
|
if (typeof params !== 'string') {
|
||||||
|
try {
|
||||||
|
stringParams = JSON.stringify(params);
|
||||||
|
} catch (error) {
|
||||||
|
const errorMsg = "'params' property must be a JSON formatted object";
|
||||||
|
console.error(errorMsg);
|
||||||
|
reject(errorMsg);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
stringParams = <string>params;
|
||||||
|
}
|
||||||
|
this.openvidu.sendRequest(
|
||||||
|
'execFilterMethod',
|
||||||
|
{ streamId: stream.streamId, method, params: stringParams },
|
||||||
|
(error, response) => {
|
||||||
|
if (error) {
|
||||||
|
console.error('Error executing filter method for Stream ' + stream.streamId, error);
|
||||||
|
if (error.code === 401) {
|
||||||
|
reject(new OpenViduError(OpenViduErrorName.OPENVIDU_PERMISSION_DENIED, "You don't have permissions to execute a filter method"));
|
||||||
|
} else {
|
||||||
|
reject(error);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.info('Filter method successfully executed on Stream ' + stream.streamId);
|
||||||
|
const oldValue = JSON.parse(JSON.stringify(stream.filter));
|
||||||
|
stream.filter.lastExecMethod = { method, params: JSON.parse(stringParams) };
|
||||||
|
this.emitEvent('streamPropertyChanged', [new StreamPropertyChangedEvent(this, stream, 'filter', stream.filter, oldValue, 'execFilterMethod')]);
|
||||||
|
stream.streamManager.emitEvent('streamPropertyChanged', [new StreamPropertyChangedEvent(stream.streamManager, stream, 'filter', stream.filter, oldValue, 'execFilterMethod')]);
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
removeFilter(stream: Stream): Promise<any> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
console.info('Removing filter of stream ' + stream.streamId);
|
||||||
|
this.openvidu.sendRequest(
|
||||||
|
'removeFilter',
|
||||||
|
{ streamId: stream.streamId },
|
||||||
|
(error, response) => {
|
||||||
|
if (error) {
|
||||||
|
console.error('Error removing filter for Stream ' + stream.streamId, error);
|
||||||
|
if (error.code === 401) {
|
||||||
|
reject(new OpenViduError(OpenViduErrorName.OPENVIDU_PERMISSION_DENIED, "You don't have permissions to remove a filter"));
|
||||||
|
} else {
|
||||||
|
reject(error);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.info('Filter successfully removed from Stream ' + stream.streamId);
|
||||||
|
const oldValue = JSON.parse(JSON.stringify(stream.filter));
|
||||||
|
stream.filter = new Object();
|
||||||
|
this.emitEvent('streamPropertyChanged', [new StreamPropertyChangedEvent(this, stream, 'filter', stream.filter, oldValue, 'applyFilter')]);
|
||||||
|
stream.streamManager.emitEvent('streamPropertyChanged', [new StreamPropertyChangedEvent(stream.streamManager, stream, 'filter', stream.filter, oldValue, 'applyFilter')]);
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends one signal. `signal` object has the following optional properties:
|
* Sends one signal. `signal` object has the following optional properties:
|
||||||
|
@ -792,6 +885,10 @@ export class Session implements EventDispatcher {
|
||||||
msg.newValue = JSON.parse(JSON.parse(msg.newValue));
|
msg.newValue = JSON.parse(JSON.parse(msg.newValue));
|
||||||
stream.videoDimensions = msg.newValue;
|
stream.videoDimensions = msg.newValue;
|
||||||
break;
|
break;
|
||||||
|
case 'filter':
|
||||||
|
oldValue = stream.filter;
|
||||||
|
stream.filter = msg.newValue;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.ee.emitEvent('streamPropertyChanged', [new StreamPropertyChangedEvent(this, stream, msg.property, msg.newValue, oldValue, msg.reason)]);
|
this.ee.emitEvent('streamPropertyChanged', [new StreamPropertyChangedEvent(this, stream, msg.property, msg.newValue, oldValue, msg.reason)]);
|
||||||
|
|
|
@ -100,6 +100,21 @@ export class Stream {
|
||||||
*/
|
*/
|
||||||
videoDimensions: { width: number, height: number };
|
videoDimensions: { width: number, height: number };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* **WARNING**: experimental option. This interface may change in the near future
|
||||||
|
*
|
||||||
|
* Filter applied to the Stream. You can apply filters by calling [[Session.applyFilter]], execute methods of the applied filter with
|
||||||
|
* [[Session.execFilterMethod]] and remove it with [[Session.removeFilter]]. Be aware that the client calling this methods must have the
|
||||||
|
* necessary permissions: the token owned by the client must have been initialized with the appropriated `allowedFilters` array.
|
||||||
|
*/
|
||||||
|
filter: {
|
||||||
|
type?: string,
|
||||||
|
options?: Object,
|
||||||
|
lastExecMethod?: {
|
||||||
|
method: string, params: Object
|
||||||
|
}
|
||||||
|
} = {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @hidden
|
* @hidden
|
||||||
*/
|
*/
|
||||||
|
@ -163,6 +178,12 @@ export class Stream {
|
||||||
this.frameRate = (this.inboundStreamOpts.frameRate === -1) ? undefined : this.inboundStreamOpts.frameRate;
|
this.frameRate = (this.inboundStreamOpts.frameRate === -1) ? undefined : this.inboundStreamOpts.frameRate;
|
||||||
this.videoDimensions = this.inboundStreamOpts.videoDimensions;
|
this.videoDimensions = this.inboundStreamOpts.videoDimensions;
|
||||||
}
|
}
|
||||||
|
if (!!this.inboundStreamOpts.filter) {
|
||||||
|
if (!!this.inboundStreamOpts.filter.lastExecMethod && Object.keys(this.inboundStreamOpts.filter.lastExecMethod).length === 0) {
|
||||||
|
delete this.inboundStreamOpts.filter.lastExecMethod;
|
||||||
|
}
|
||||||
|
this.filter = this.inboundStreamOpts.filter;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// OutboundStreamOptions: stream belongs to a Publisher
|
// OutboundStreamOptions: stream belongs to a Publisher
|
||||||
this.outboundStreamOpts = <OutboundStreamOptions>options;
|
this.outboundStreamOpts = <OutboundStreamOptions>options;
|
||||||
|
@ -182,6 +203,9 @@ export class Stream {
|
||||||
this.typeOfVideo = this.isSendScreen() ? 'SCREEN' : 'CAMERA';
|
this.typeOfVideo = this.isSendScreen() ? 'SCREEN' : 'CAMERA';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!!this.outboundStreamOpts.publisherProperties.filter) {
|
||||||
|
this.filter = this.outboundStreamOpts.publisherProperties.filter;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.ee.on('mediastream-updated', () => {
|
this.ee.on('mediastream-updated', () => {
|
||||||
|
@ -467,7 +491,8 @@ export class Stream {
|
||||||
videoActive: this.videoActive,
|
videoActive: this.videoActive,
|
||||||
typeOfVideo,
|
typeOfVideo,
|
||||||
frameRate: !!this.frameRate ? this.frameRate : -1,
|
frameRate: !!this.frameRate ? this.frameRate : -1,
|
||||||
videoDimensions: JSON.stringify(this.videoDimensions)
|
videoDimensions: JSON.stringify(this.videoDimensions),
|
||||||
|
filter: this.outboundStreamOpts.publisherProperties.filter
|
||||||
}, (error, response) => {
|
}, (error, response) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
if (error.code === 401) {
|
if (error.code === 401) {
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Connection } from '../../../OpenVidu/Connection';
|
import { Connection } from '../../../OpenVidu/Connection';
|
||||||
|
import { Filter } from '../Public/Filter';
|
||||||
|
|
||||||
export interface InboundStreamOptions {
|
export interface InboundStreamOptions {
|
||||||
id: string;
|
id: string;
|
||||||
|
@ -27,4 +28,5 @@ export interface InboundStreamOptions {
|
||||||
typeOfVideo: string;
|
typeOfVideo: string;
|
||||||
frameRate: number;
|
frameRate: number;
|
||||||
videoDimensions: { width: number, height: number };
|
videoDimensions: { width: number, height: number };
|
||||||
|
filter: Filter;
|
||||||
}
|
}
|
|
@ -15,6 +15,8 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { Filter } from '../Public/Filter';
|
||||||
|
|
||||||
export interface StreamOptionsServer {
|
export interface StreamOptionsServer {
|
||||||
id: string;
|
id: string;
|
||||||
hasAudio: boolean;
|
hasAudio: boolean;
|
||||||
|
@ -24,4 +26,5 @@ export interface StreamOptionsServer {
|
||||||
typeOfVideo: string;
|
typeOfVideo: string;
|
||||||
frameRate: number;
|
frameRate: number;
|
||||||
videoDimensions: string;
|
videoDimensions: string;
|
||||||
|
filter: Filter;
|
||||||
}
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
* (C) Copyright 2017-2018 OpenVidu (https://openvidu.io/)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* **WARNING**: experimental option. This interface may change in the near future. See [[Stream.filter]]
|
||||||
|
*/
|
||||||
|
export interface Filter {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type of filter applied. This is the name of the remote class identifying the filter to apply in Kurento Media Server.
|
||||||
|
* For example: `"FaceOverlayFilter"`, `"GStreamerFilter"`. If `undefined` no filter is applied to the Stream
|
||||||
|
*/
|
||||||
|
type?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parameters used to initialized the filter.
|
||||||
|
* These correspond to the constructor parameters used in the filter in Kurento Media Server.
|
||||||
|
* For example: for `filter.type = "GStreamerFilter"` could be `filter.options = "pitch pitch=0.8 tempo=1.0"`
|
||||||
|
*/
|
||||||
|
options?: Object;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Value passed the last time [[Session.execFilterMethod]] or [[Session.forceExecFilterMethod]] were called
|
||||||
|
* for the Stream owning this filter. If `undefined` those methods have not been called yet.
|
||||||
|
*
|
||||||
|
* You can use this value to know the current status of any applied filter
|
||||||
|
*/
|
||||||
|
lastExecMethod?: {
|
||||||
|
method: string,
|
||||||
|
params: Object
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -15,6 +15,7 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { Filter } from './Filter';
|
||||||
import { VideoInsertMode } from '../../Enums/VideoInsertMode';
|
import { VideoInsertMode } from '../../Enums/VideoInsertMode';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -80,4 +81,11 @@ export interface PublisherProperties {
|
||||||
*/
|
*/
|
||||||
videoSource?: string | MediaStreamTrack | boolean;
|
videoSource?: string | MediaStreamTrack | boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* **WARNING**: experimental option. This property may change in the near future
|
||||||
|
*
|
||||||
|
* Define a filter to apply in the Publisher's stream
|
||||||
|
*/
|
||||||
|
filter?: Filter;
|
||||||
|
|
||||||
}
|
}
|
|
@ -25,6 +25,7 @@ export { StreamPropertyChangedEvent } from './OpenViduInternal/Events/StreamProp
|
||||||
export { Capabilities } from './OpenViduInternal/Interfaces/Public/Capabilities';
|
export { Capabilities } from './OpenViduInternal/Interfaces/Public/Capabilities';
|
||||||
export { Device } from './OpenViduInternal/Interfaces/Public/Device';
|
export { Device } from './OpenViduInternal/Interfaces/Public/Device';
|
||||||
export { EventDispatcher } from './OpenViduInternal/Interfaces/Public/EventDispatcher';
|
export { EventDispatcher } from './OpenViduInternal/Interfaces/Public/EventDispatcher';
|
||||||
|
export { Filter } from './OpenViduInternal/Interfaces/Public/Filter';
|
||||||
export { OpenViduAdvancedConfiguration } from './OpenViduInternal/Interfaces/Public/OpenViduAdvancedConfiguration';
|
export { OpenViduAdvancedConfiguration } from './OpenViduInternal/Interfaces/Public/OpenViduAdvancedConfiguration';
|
||||||
export { PublisherProperties } from './OpenViduInternal/Interfaces/Public/PublisherProperties';
|
export { PublisherProperties } from './OpenViduInternal/Interfaces/Public/PublisherProperties';
|
||||||
export { SignalOptions } from './OpenViduInternal/Interfaces/Public/SignalOptions';
|
export { SignalOptions } from './OpenViduInternal/Interfaces/Public/SignalOptions';
|
||||||
|
|
Loading…
Reference in New Issue