import { OpenViduStreams } from './media-streams.js';
/**
Simple screen sharing component. Creates two planes:
one (screenShareMesh) to start/stop sharing,
and the other one (videoMesh) to display the video stream.
Properties of created meshes (position etc) are safe to be changed after creation.
Creates and deletes a server-side object for synchronization.
*/
export class Screencast {
/**
* 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) {
/** 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;
this.screenShareMesh = BABYLON.MeshBuilder.CreatePlane('screencast-button', {width:1, height:.5}, this.scene);
this.screenShareMesh.position = new BABYLON.Vector3(0, 1, 0);
this.screenShareMesh.rotation = new BABYLON.Vector3(0, Math.PI, 0);
this.screenShareMesh.material = new BABYLON.StandardMaterial('shareScreen', this.scene);;
this.screenShareMesh.material.emissiveColor = BABYLON.Color3.White();
this.screenShareMesh.material.backFaceCulling = false;
this.screenShareMesh.material.diffuseTexture = new BABYLON.DynamicTexture("screenShareTexture", {width:128, height:64}, this.scene);
this.writeText(this.text);
this.screenShareMesh.setEnabled(false);
// HD resolution 16:9
this.videoMesh = BABYLON.MeshBuilder.CreatePlane('screencast-videoScreen', {width:16/3, height:9/3}, this.scene);
this.videoMesh.position = new BABYLON.Vector3(0, 3, 0);
this.videoMesh.rotation = new BABYLON.Vector3(0, Math.PI, 0);
this.videoMesh.material = new BABYLON.StandardMaterial('screencast-video', this.scene);
this.videoMesh.material.emissiveColor = BABYLON.Color3.White();
this.videoMesh.setEnabled(false);
}
/**
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;
var client = this.worldManager.VRSPACE.me;
this.screenShareMesh.setEnabled(true);
if ( ! this.worldManager.mediaStreams ) {
this.worldManager.mediaStreams = new OpenViduStreams(this.scene, 'videos');
this.worldManager.pubSub(client, false); // audio only
}
this.worldManager.mediaStreams.playStream = ( client, mediaStream ) => {
console.log('mapping incoming screen share of '+client.id+" to ",this.screenShare);
if ( this.screenShare && client.id == this.screenShare.properties.clientId ) {
this.showVideo(mediaStream);
}
}
//this.worldManager.debug = true;
this.scene.onPointerPick = (e,p) => {
console.log("Picked ", p.pickedMesh.name);
if ( p.pickedMesh.name === this.screenShareMesh.name) {
if ( ! this.screenShare ) {
console.log('start sharing screen');
var screenName = this.name;
if ( ! screenName ) {
if ( client.name ) {
screenName = client.name;
} else {
screenName = 'u'+client.id;
}
}
this.worldManager.VRSPACE.createSharedObject({
properties:{ screenName:screenName, clientId: client.id },
active:true
}, (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);
this.showVideo(mediaStream);
}).catch((e) => {
console.log('sharing denied', e);
this.deleteSharedObject();
});
});
} else {
console.log('stop sharing screen');
this.worldManager.mediaStreams.stopSharingScreen();
this.deleteSharedObject();
}
}
}
// this gets triggers whenever any client receives any new VRobject
this.worldManager.VRSPACE.addSceneListener( (sceneEvent) => {
console.log(sceneEvent);
// identify the object
if ( sceneEvent.added && sceneEvent.added.properties && sceneEvent.added.properties.screenName) {
// keep the reference, share the event when touched on
this.screenShare = sceneEvent.added;
this.writeText('Sharing: '+sceneEvent.added.properties.screenName);
this.showNoise();
} else if ( sceneEvent.removed && this.screenShare && sceneEvent.removed.id == this.screenShare.id) {
console.log("Screen share removed");
this.screenShare = null;
this.removeScreen();
this.writeText(this.text);
}
});
}
// internal methods
writeText( text, where ) {
if ( ! where ) {
where = this.screenShareMesh;
}
var material = where.material;
material.diffuseTexture.drawText(text,
null,
null,
'bold 12px monospace',
'black',
'white',
true,
true
);
}
showVideo( mediaStream ) {
BABYLON.VideoTexture.CreateFromStreamAsync(this.scene, mediaStream).then( (texture) => {
if ( this.videoMesh.material.diffuseTexture ) {
this.videoMesh.material.diffuseTexture.dispose();
}
this.videoMesh.material.diffuseTexture = texture;
this.videoMesh.material.diffuseTexture.vScale = -1
this.videoMesh.setEnabled(true);
});
}
showNoise() {
if ( this.videoMesh.material.diffuseTexture ) {
this.videoMesh.material.diffuseTexture.dispose();
}
var noiseTexture = new BABYLON.NoiseProceduralTexture(this.name+"-perlin", 256, this.scene);
this.videoMesh.material.diffuseTexture = noiseTexture;
noiseTexture.octaves = 8;
noiseTexture.persistence = 2;
noiseTexture.animationSpeedFactor = 10;
this.videoMesh.setEnabled(true);
}
removeScreen() {
if ( this.videoMesh.material.diffuseTexture ) {
this.videoMesh.material.diffuseTexture.dispose();
}
this.videoMesh.setEnabled(false);
}
deleteSharedObject() {
if ( this.screenShare ) {
this.worldManager.VRSPACE.deleteSharedObject(this.screenShare);
}
}
}