import { OpenViduStreams } from '../../core/media-streams.js';
import { WorldListener } from '../../world/world-listener.js';
/**
* Base screen sharing class, sending side.
* Using should be simple - construct and init. All methods except startSharing/stopSharing are internally called,
* intended to be overridden by subclasses.
* Receiving side of the screen is implemented by RemoteScreen script.
*/
export class Screencast extends WorldListener {
/**
* Creates but hides meshes.
*
* @param world the world
* @param name screen share name, displayed when sharing. Defaults to user name or id.
*/
constructor(world, name="Shared screen") {
super();
/** text to display on the share screen button, by default Share screen */
this.text = 'Share screen';
this.world = world;
this.scene = world.scene;
this.name = name;
/** Screen size, default 3. Height is fixed, width may scale accordingly. */
this.size = 3;
/** Add manupulation handles? Default true. */
this.addHandles = true;
/** Screen position, default 0,3,0 */
this.position = new BABYLON.Vector3(0, 3, 0);
/** Screen rotation, default Math.PI - away from presenter */
this.rotation = new BABYLON.Vector3(0, Math.PI, 0);
/** Contains VRObject used to exchange screens share messages, exists only on the sending side */
this.screenShare = null;
/** Callback executed when sharing state changes, passed true/false */
this.callback = null;
}
/**
Initialize the sharing component. Requires functional WorldManager attached to the world,
so is safe to call from World.entered() method, or after it has been called.
*/
init() {
this.worldManager = this.world.worldManager;
this.world.addListener(this);
this.setupStreaming();
}
/**
* Called from init(). Attaches itself to MediaStreams, creates new MediaStreams if required.
* Registers handleSceneEvent() as a SceneListener with WorldManager.
*/
setupStreaming() {
this.client = this.worldManager.VRSPACE.me;
if ( ! this.worldManager.mediaStreams ) {
this.worldManager.mediaStreams = new OpenViduStreams(this.scene, 'videos');
this.worldManager.pubSub(this.client, false); // audio only
}
}
/**
* Starts the screencast: creates new shared VRObject, and calls MediaStreams.shareScreen().
*/
startSharing() {
let screenName = this.name;
if ( ! screenName ) {
if ( this.client.name ) {
screenName = this.client.name;
} else {
screenName = 'u'+this.client.id;
}
}
this.worldManager.VRSPACE.createScriptedObject({
properties:{ screenName:screenName, type: "Screencast", clientId: this.client.id, size:this.size, addHandles:this.addHandles },
active:true,
script:'/babylon/js/scripts/remote-screen.js',
position: {x: this.position.x, y: this.position.y, z: this.position.z},
rotation: {x: this.rotation.x, y: this.rotation.y, z: this.rotation.z}
}).then(obj=>{
this.screenShare = obj;
console.log("Created new VRObject", obj);
this.worldManager.mediaStreams.shareScreen(()=>{
// end callback, executed when user presses browser stop share button
this.deleteSharedObject();
}).then((mediaStream)=>{
console.log("streaming",mediaStream);
// imageArea is created by scene event handler
//this.imageArea.loadStream(mediaStream);
obj.attachedScript.playStream(mediaStream, true);
}).catch((e) => {
console.log('sharing denied', e);
this.deleteSharedObject();
});
});
}
/**
* Stop sharing and delete shared object.
*/
stopSharing() {
this.deleteSharedObject();
this.worldManager.mediaStreams.stopSharingScreen();
}
/**
* Internally used to delete the shared object.
*/
deleteSharedObject() {
if ( this.screenShare ) {
this.worldManager.VRSPACE.deleteSharedObject(this.screenShare);
this.screenShare = null;
}
}
/**
* Clean up.
*/
dispose() {
this.stopSharing();
}
/** WorldListener interface */
added(vrObject){
if ( vrObject.properties && vrObject.properties.screenName ) {
this.sharing(true);
}
}
/** WorldListener interface */
removed(vrObject){
if ( vrObject.properties && vrObject.properties.screenName ) {
this.sharing(false);
}
}
/** Called when sharing starts/stops (shared object is added/removed), executes callback */
sharing(state) {
if ( this.callback ) {
this.callback(state);
}
}
}