openvidu-browser: Session.forceUnpublish and Session.forceDisconnect

pull/88/merge
pabloFuente 2018-07-09 15:45:20 +02:00
parent e615ff7ec4
commit d5958ec906
10 changed files with 126 additions and 31 deletions

View File

@ -77,6 +77,7 @@ export class Publisher extends StreamManager {
this.openvidu = openvidu;
this.stream.ee.on('local-stream-destroyed', (reason: string) => {
this.stream.isLocalStreamPublished = false;
const streamEvent = new StreamEvent(true, this, 'streamDestroyed', this.stream, reason);
this.emitEvent('streamDestroyed', [streamEvent]);
streamEvent.callDefaultBehavior();

View File

@ -330,7 +330,7 @@ export class Session implements EventDispatcher {
publisher.session = this;
publisher.stream.session = this;
if (!publisher.stream.isLocalStreamPublished) {
if (!publisher.stream.publishedOnce) {
// 'Session.unpublish(Publisher)' has NOT been called
this.connection.addStream(publisher.stream);
publisher.stream.publish()
@ -413,6 +413,88 @@ export class Session implements EventDispatcher {
}
/**
* Forces some user to leave the session
*
* #### Events dispatched
*
* The behavior is the same as when some user calls [[Session.disconnect]], but `reason` property in all events will be `"forceDisconnectByUser"`.
*
* The local [[Session]] object will dispatch:
* - A `streamDestroyed` event if the evicted user was publishing a stream, with property `reason` set to `"forceDisconnectByUser"`
* - A `connectionDestroyed` event for the evicted user, with property `reason` set to `"forceDisconnectByUser"`
*
* The remote [[Session]] object of every other participant will dispatch:
* - A `streamDestroyed` event if the evicted user was publishing a stream, with property `reason` set to `"forceDisconnectByUser"`
* - A `connectionDestroyed` event for the evicted user, with property `reason` set to `"forceDisconnectByUser"`
*
* If any, the [[Publisher]] object of the evicted participant will also dispatch a `streamDestroyed` event with property `reason` set to `"forceDisconnectByUser"`
*
* @returns A Promise (to which you can optionally subscribe to) that is resolved only after the participant has been successfully evicted from the session and rejected with an Error object if not
*/
forceDisconnect(connection: Connection): Promise<any> {
return new Promise((resolve, reject) => {
console.info('Forcing disconnect for connection ' + connection.connectionId);
this.openvidu.sendRequest(
'forceDisconnect',
{ connectionId: connection.connectionId },
(error, response) => {
if (error) {
console.error('Error forcing disconnect for Connection ' + connection.connectionId, error);
if (error.code === 401) {
reject(new OpenViduError(OpenViduErrorName.OPENVIDU_PERMISSION_DENIED, "You don't have permissions to force a disconnection"));
} else {
reject(error);
}
} else {
console.info('Forcing disconnect correctly for Connection ' + connection.connectionId);
resolve();
}
}
);
});
}
/**
* Forces some user to unpublish a Stream
*
* #### Events dispatched
*
* The behavior is the same as when some user calls [[Session.unpublish]], but `reason` property in all events will be `"forceUnpublishByUser"`.
*
* The local [[Session]] object will dispatch a `streamDestroyed` event with property `reason` set to `"forceUnpublishByUser"`
*
* The remote [[Session]] object of every other participant will dispatch a `streamDestroyed` event with property `reason` set to `"forceDisconnectByUser"`
*
* The [[Publisher]] object of the affected participant will also dispatch a `streamDestroyed` event with property `reason` set to `"forceDisconnectByUser"`
*
* @returns A Promise (to which you can optionally subscribe to) that is resolved only after the remote Stream has been successfully unpublished from the session and rejected with an Error object if not
*/
forceUnpublish(stream: Stream): Promise<any> {
return new Promise((resolve, reject) => {
console.info('Forcing unpublish for stream ' + stream.streamId);
this.openvidu.sendRequest(
'forceUnpublish',
{ streamId: stream.streamId },
(error, response) => {
if (error) {
console.error('Error forcing unpublish for Stream ' + stream.streamId, error);
if (error.code === 401) {
reject(new OpenViduError(OpenViduErrorName.OPENVIDU_PERMISSION_DENIED, "You don't have permissions to force an unpublishing"));
} else {
reject(error);
}
} else {
console.info('Forcing unpublish correctly for Stream ' + stream.streamId);
resolve();
}
}
);
});
}
/**
* Sends one signal. `signal` object has the following optional properties:
* ```json
@ -663,27 +745,6 @@ export class Session implements EventDispatcher {
if (!!this.sessionId && !this.connection.disposed) {
this.leave(true, msg.reason);
}
} else {
// Other user has been evicted from the session
this.getRemoteConnection(msg.connectionId, 'Remote connection ' + msg.connectionId + " unknown when 'onParticipantEvicted'. " +
'Existing remote connections: ' + JSON.stringify(Object.keys(this.remoteConnections)))
.then(connection => {
if (!!connection.stream) {
const stream = connection.stream;
const streamEvent = new StreamEvent(true, this, 'streamDestroyed', stream, msg.reason);
this.ee.emitEvent('streamDestroyed', [streamEvent]);
streamEvent.callDefaultBehavior();
delete this.remoteStreamsCreated[stream.streamId];
}
delete this.remoteConnections[connection.connectionId];
this.ee.emitEvent('connectionDestroyed', [new ConnectionEvent(false, this, 'connectionDestroyed', connection, msg.reason)]);
})
.catch(openViduError => {
console.error(openViduError);
});
}
}
@ -904,7 +965,9 @@ export class Session implements EventDispatcher {
// Initialize capabilities object with the role
this.capabilities = {
subscribe: true,
publish: this.openvidu.role !== 'SUBSCRIBER'
publish: this.openvidu.role !== 'SUBSCRIBER',
forceUnpublish: this.openvidu.role === 'MODERATOR',
forceDisconnect: this.openvidu.role === 'MODERATOR'
};
// Initialize local Connection object with values returned by openvidu-server

View File

@ -26,6 +26,7 @@ import { PublisherSpeakingEvent } from '../OpenViduInternal/Events/PublisherSpea
import EventEmitter = require('wolfy87-eventemitter');
import hark = require('hark');
import { OpenViduError, OpenViduErrorName } from '../OpenViduInternal/Enums/OpenViduError';
/**
@ -118,6 +119,10 @@ export class Stream {
* @hidden
*/
isLocalStreamPublished = false;
/**
* @hidden
*/
publishedOnce = false;
/**
* @hidden
*/
@ -465,12 +470,17 @@ export class Stream {
videoDimensions: JSON.stringify(this.videoDimensions)
}, (error, response) => {
if (error) {
reject('Error on publishVideo: ' + JSON.stringify(error));
if (error.code === 401) {
reject(new OpenViduError(OpenViduErrorName.OPENVIDU_PERMISSION_DENIED, "You don't have permissions to publish"));
} else {
reject('Error on publishVideo: ' + JSON.stringify(error));
}
} else {
this.webRtcPeer.processAnswer(response.sdpAnswer)
.then(() => {
this.streamId = response.id;
this.isLocalStreamPublished = true;
this.publishedOnce = true;
if (this.displayMyRemote()) {
this.remotePeerSuccessfullyEstablished();
}

View File

@ -82,7 +82,8 @@ export enum OpenViduErrorName {
PUBLISHER_PROPERTIES_ERROR = 'PUBLISHER_PROPERTIES_ERROR',
/**
* _Not in use yet_
* The client tried to call a method without the required permissions. This can occur for methods [[Session.publish]],
* [[Session.forceUnpublish]] and [[Session.forceDisconnect]]
*/
OPENVIDU_PERMISSION_DENIED = 'OPENVIDU_PERMISSION_DENIED',

View File

@ -35,6 +35,8 @@ export class ConnectionEvent extends Event {
/**
* For 'connectionDestroyed' event:
* - "disconnect": the remote user has called `Session.disconnect()`
* - "forceDisconnectByUser": the remote user has been evicted from the Session by other user calling `Session.forceDisconnect()`
* - "forceDisconnectByServer": the remote user has been evicted from the Session by the application
* - "networkDisconnect": the remote user network connection has dropped
*
* For 'connectionCreated' empty string

View File

@ -34,8 +34,8 @@ export class RecordingEvent extends Event {
/**
* The recording name you supplied to openvidu-server. For example, to name your recording file MY_RECORDING:
* - With **API REST**: POST to `/api/recordings/start` passing JSON body `{"session":"sessionId","name":"MY_RECORDING"}`
* - With **openvidu-java-client**: `OpenVidu.startRecording(sessionId, MY_RECORDING)` or `OpenVidu.startRecording(sessionId, new RecordingProperties.Builder().name(MY_RECORDING).build())`
* - With **openvidu-node-client**: `OpenVidu.startRecording(sessionId, MY_RECORDING)` or `OpenVidu.startRecording(sessionId, new RecordingProperties.Builder().name(MY_RECORDING).build())`
* - With **openvidu-java-client**: `OpenVidu.startRecording(sessionId, "MY_RECORDING")` or `OpenVidu.startRecording(sessionId, new RecordingProperties.Builder().name("MY_RECORDING").build())`
* - With **openvidu-node-client**: `OpenVidu.startRecording(sessionId, "MY_RECORDING")` or `OpenVidu.startRecording(sessionId, {name: "MY_RECORDING"})`
*
* If no name is supplied, this property will be undefined and the recorded file will be named after property [[id]]
*/

View File

@ -26,6 +26,9 @@ export class SessionDisconnectedEvent extends Event {
/**
* - "disconnect": you have called `Session.disconnect()`
* - "forceDisconnectByUser": you have been evicted from the Session by other user calling `Session.forceDisconnect()`
* - "forceDisconnectByServer": you have been evicted from the Session by the application
* - "sessionClosedByServer": the Session has been closed by the application
* - "networkDisconnect": your network connection has dropped
*/
reason: string;

View File

@ -37,6 +37,11 @@ export class StreamEvent extends Event {
* For 'streamDestroyed' event:
* - "unpublish": method `Session.unpublish()` has been called
* - "disconnect": method `Session.disconnect()` has been called
* - "forceUnpublishByUser": some user has called `Session.forceUnpublish()` over the Stream
* - "forceDisconnectByUser": some user has called `Session.forceDisconnect()` over the Stream
* - "forceUnpublishByServer": the user's stream has been unpublished from the Session by the application
* - "forceDisconnectByServer": the user has been evicted from the Session by the application
* - "sessionClosedByServer": the Session has been closed by the application
* - "networkDisconnect": the user's network connection has dropped
*
* For 'streamCreated' empty string

View File

@ -20,6 +20,16 @@
*/
export interface Capabilities {
/**
* `true` if the client can call [[Session.forceDisconnect]], `false` if not
*/
forceDisconnect: boolean;
/**
* `true` if the client can call [[Session.forceUnpublish]], `false` if not
*/
forceUnpublish: boolean;
/**
* `true` if the client can call [[Session.publish]], `false` if not
*/

View File

@ -35,22 +35,22 @@ export interface StreamManagerVideo {
/**
* The DOM HTMLElement assigned as target element when creating a video for the StreamManager. This property is defined when:
* - [[OpenVidu.initPublisher]] or [[Session.subscribe]] methods have been called passing a valid `targetElement` parameter.
* - [[SessionManager.createVideoElement]] has been called.
* - [[StreamManager.createVideoElement]] has been called.
*
* This property is undefined when:
* - [[OpenVidu.initPublisher]] or [[Session.subscribe]] methods have been called passing *null* or *undefined* as `targetElement` parameter.
* - [[SessionManager.addVideoElement]] has been called.
* - [[StreamManager.addVideoElement]] has been called.
*/
targetElement?: HTMLElement;
/**
* How the DOM video element should be inserted with respect to `targetElement`. This property is defined when:
* - [[OpenVidu.initPublisher]] or [[Session.subscribe]] methods have been called passing a valid `targetElement` parameter.
* - [[SessionManager.createVideoElement]] has been called.
* - [[StreamManager.createVideoElement]] has been called.
*
* This property is undefined when:
* - [[OpenVidu.initPublisher]] or [[Session.subscribe]] methods have been called passing *null* or *undefined* as `targetElement` parameter.
* - [[SessionManager.addVideoElement]] has been called.
* - [[StreamManager.addVideoElement]] has been called.
*/
insertMode?: VideoInsertMode;