code cleanup, grid for videos, automatic video resize to max possible, rename of user triggers rearrange of uservideo, volume knobs for each video

This commit is contained in:
Henne 2020-04-23 17:40:39 +02:00
parent 3b5764e275
commit 01e14b2e81
4 changed files with 254 additions and 185 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
.idea

View File

@ -1,72 +1,42 @@
/* global $, JitsiMeetJS */
/*
const options = {
serviceUrl: 'https://meet.theater.digital/http-bind',
hosts: {
domain: 'jitsi-meet.example.com',
muc: 'conference.jitsi-meet.example.com' // FIXME: use XEP-0030
},
bosh: '//jitsi-meet.example.com/http-bind', // FIXME: use xep-0156 for that
// The name of client node advertised in XEP-0115 'c' stanza
clientNode: 'http://jitsi.org/jitsimeet'
}; */
/*
const options = {
hosts: {
domain: 'beta.meet.jit.si',
muc: 'conference.beta.meet.jit.si' // FIXME: use XEP-0030
},
bosh: 'https://beta.meet.jit.si/http-bind', // FIXME: use xep-0156 for that
// The name of client node advertised in XEP-0115 'c' stanza
clientNode: 'http://jitsi.org/jitsimeet'
};*/
const options = {
hosts: {
domain: 'meet.theater.digital',
muc: 'conference.meet.theater.digital' // FIXME: use XEP-0030
},
bosh: 'https://meet.theater.digital/http-bind', // FIXME: use xep-0156 for that
// The name of client node advertised in XEP-0115 'c' stanza
clientNode: 'http://jitsi.org/jitsimeet'
muc: 'conference.meet.theater.digital'
}
};
const confOptions = {
openBridgeChannel: true
};
const videoSize = {
width: 640,
height: 360
};
const roomName = 'tt-test2';
let connection = null;
let isJoined = false;
let room = null;
let localTracks = [];
const remoteTracks = {};
// zu mappende namen.
let remoteMappingName = [
'alpha', 'beta', 'henne',
'delta', 'soeren', 'klaus'
];
// track mapping participant id -> position
let trackMapping = {};
// alle verfügbaren tracks mit participant id -> {audio: track, video: track}
let tracks = {};
/**
* Handles local tracks.
* @param tracks Array with JitsiTrack objects
* Hinzufügen der Lokalen Tracks zum Stream, wobei ich immernoch meine, das ist überflüssig.
* @param tracks
*/
function onLocalTracks(tracks) {
localTracks = tracks;
for (let i = 0; i < localTracks.length; i++) {
localTracks[i].addEventListener(
JitsiMeetJS.events.track.TRACK_AUDIO_LEVEL_CHANGED,
audioLevel => console.log(`Audio Level local: ${audioLevel}`));
localTracks[i].addEventListener(
JitsiMeetJS.events.track.TRACK_MUTE_CHANGED,
() => console.log('local track muted'));
localTracks[i].addEventListener(
JitsiMeetJS.events.track.LOCAL_TRACK_STOPPED,
() => console.log('local track stoped'));
localTracks[i].addEventListener(
JitsiMeetJS.events.track.TRACK_AUDIO_OUTPUT_CHANGED,
deviceId =>
console.log(
`track audio output device was changed to ${deviceId}`));
if (localTracks[i].getType() === 'video') {
$('body').append(`<video autoplay='1' id='localVideo${i}' />`);
localTracks[i].attach($(`#localVideo${i}`)[0]);
@ -81,6 +51,27 @@ function onLocalTracks(tracks) {
}
}
/**
*
* @param participant
* @param track
* @param type
*/
function setRemoteTrack(participant, track, type) {
if (trackMapping[participant] == null)
return;
console.log(`attaching ${type} track from ${participant}`);
if (type === 'video') {
let elemID = `.video-${trackMapping[participant]} video`;
track.attach($(elemID)[0]);
tracks[participant].video = track;
} else {
let elemID = `.video-${trackMapping[participant]} audio`;
track.attach($(elemID)[0]);
tracks[participant].audio = track;
}
}
/**
* Handles remote tracks
* @param track JitsiTrack object
@ -90,35 +81,30 @@ function onRemoteTrack(track) {
return;
}
const participant = track.getParticipantId();
if (!remoteTracks[participant]) {
remoteTracks[participant] = [];
if(!tracks[participant]) {
tracks[participant] = {};
}
const idx = remoteTracks[participant].push(track);
tracks[participant][track.getType()] = track;
setRemoteTrack(participant, track, track.getType());
}
track.addEventListener(
JitsiMeetJS.events.track.TRACK_AUDIO_LEVEL_CHANGED,
audioLevel => console.log(`Audio Level remote: ${audioLevel}`));
track.addEventListener(
JitsiMeetJS.events.track.TRACK_MUTE_CHANGED,
() => console.log('remote track muted'));
track.addEventListener(
JitsiMeetJS.events.track.LOCAL_TRACK_STOPPED,
() => console.log('remote track stoped'));
track.addEventListener(JitsiMeetJS.events.track.TRACK_AUDIO_OUTPUT_CHANGED,
deviceId =>
console.log(
`track audio output device was changed to ${deviceId}`));
const id = participant + track.getType() + idx;
if (track.getType() === 'video') {
$('body').append(
`<video autoplay='1' id='${participant}video${idx}' />`);
/**
* Event wenn ein Mediastream entfernt wurde.
* Räumt die Track tracker objekte auf und entfernt - wenn vorhanden - die entsprechende zuordnung zum media element
* @param track
*/
function onRemoteTrackRemove(track) {
const participant = track.getParticipantId();
const type = track.getType();
if(trackMapping[participant] != null && tracks[participant][type]) {
console.log(`detaching ${type} track from ${participant}`);
tracks[participant][type].detach($(`.video-${trackMapping[participant]} ${type}`)[0]);
}
if(!tracks[participant].audio && !tracks[participant].video) {
delete tracks[participant]
} else {
$('body').append(
`<audio autoplay='1' id='${participant}audio${idx}' />`);
delete tracks[participant][type];
}
track.attach($(`#${id}`)[0]);
}
/**
@ -127,24 +113,73 @@ function onRemoteTrack(track) {
function onConferenceJoined() {
console.log('conference joined!');
isJoined = true;
for (let i = 0; i < localTracks.length; i++) {
room.addTrack(localTracks[i]);
}
}
/**
*
* @param id
* @param user
*/
function onUserJoin(id, user) {
console.log(`user join - ${user.getDisplayName()}`);
let position = remoteMappingName.indexOf(user.getDisplayName());
if(position >= 0) {
console.log("user found");
trackMapping[id] = position
}
}
/**
* Event für Namensänderungen, ordnet den user korrekt an.
* @param participant
* @param displayName
*/
function onNameChange(participant, displayName) {
// detach this user from current position
detachUser(participant);
let position = remoteMappingName.indexOf(displayName);
if(position >= 0 && tracks[participant]) {
// detach user in the new position
for(let i in trackMapping) {
if(trackMapping[i] === position) {
detachUser(i);
}
}
trackMapping[participant] = position;
if (tracks[participant].video) {
let elemID = `.video-${position} video`;
tracks[participant].video.attach($(elemID)[0]);
}
if(tracks[participant].audio) {
let elemID = `.video-${position} audio`;
tracks[participant].audio.attach($(elemID)[0]);
}
}
}
/**
* Event wenn ein User den Raum verlässt
* Entfernt die Verbindung der Tracks mit den Mediaelementen wenn vorhanden und räumt die Track tracker objekte auf.
* @param id
*/
function onUserLeft(id) {
console.log('user left');
if (!remoteTracks[id]) {
return;
}
const tracks = remoteTracks[id];
detachUser(id);
delete tracks[id];
}
for (let i = 0; i < tracks.length; i++) {
tracks[i].detach($(`#${id}${tracks[i].getType()}`));
function detachUser(id) {
if (trackMapping[id] != null) {
console.log("detaching user " + id);
if(tracks[id].video) {
tracks[id].video.detach($(`.video-${trackMapping[id].position} video`)[0]);
}
if(tracks[id].audio) {
tracks[id].audio.detach($(`.video-${trackMapping[id].position} audio`)[0]);
}
delete trackMapping[id]
}
}
@ -152,47 +187,56 @@ function onUserLeft(id) {
* That function is called when connection is established successfully
*/
function onConnectionSuccess() {
room = connection.initJitsiConference('tt-test1', confOptions);
room = connection.initJitsiConference(roomName, confOptions);
room.setDisplayName("Streamer");
room.on(JitsiMeetJS.events.conference.TRACK_ADDED, onRemoteTrack);
room.on(JitsiMeetJS.events.conference.TRACK_REMOVED, track => {
console.log(`track removed!!!${track}`);
});
room.on(
JitsiMeetJS.events.conference.CONFERENCE_JOINED,
onConferenceJoined);
room.on(JitsiMeetJS.events.conference.USER_JOINED, id => {
console.log('user join');
remoteTracks[id] = [];
});
room.on(JitsiMeetJS.events.conference.TRACK_REMOVED, onRemoteTrackRemove);
room.on(JitsiMeetJS.events.conference.CONFERENCE_JOINED, onConferenceJoined);
room.on(JitsiMeetJS.events.conference.USER_JOINED, onUserJoin);
room.on(JitsiMeetJS.events.conference.USER_LEFT, onUserLeft);
room.on(JitsiMeetJS.events.conference.TRACK_MUTE_CHANGED, track => {
console.log(`${track.getType()} - ${track.isMuted()}`);
});
room.on(
JitsiMeetJS.events.conference.DISPLAY_NAME_CHANGED,
(userID, displayName) => console.log(`${userID} - ${displayName}`));
room.on(
JitsiMeetJS.events.conference.TRACK_AUDIO_LEVEL_CHANGED,
(userID, audioLevel) => console.log(`${userID} - ${audioLevel}`));
room.on(
JitsiMeetJS.events.conference.PHONE_NUMBER_CHANGED,
() => console.log(`${room.getPhoneNumber()} - ${room.getPhonePin()}`));
room.on(JitsiMeetJS.events.conference.DISPLAY_NAME_CHANGED, onNameChange);
room.join();
}
/**
* This function is called when the connection fail.
*
*/
function onConnectionFailed() {
console.error('Connection Failed!');
function onVideoResize(event) {
const video = $(event.target)[0];
const width = video.videoWidth;
const height = video.videoHeight;
const aspectRatio = width/height;
console.log(`${aspectRatio} is the aspect ratio`);
let targetWidth = 640;
let targetHeight = 360;
if(width > videoSize.width) {
targetHeight *= videoSize.width / width
}
if(height > targetHeight) {
targetWidth *= targetHeight / height
}
video.width = targetWidth;
video.height = targetHeight;
}
/**
* This function is called when the connection fail.
*/
function onDeviceListChanged(devices) {
console.info('current devices', devices);
}
$(document).ready(function() {
let audio = $('audio');
for(let i in audio) {
if(!audio.hasOwnProperty(i)) {
continue;
}
audio[i].volume = 0.7;
}
let video = $('.video');
for(let i in video) {
if(!video.hasOwnProperty(i)) {
continue;
}
$(video[i]).find('span').text(remoteMappingName[i]);
$(video[i]).find('video').on('resize', onVideoResize);
}
});
/**
* This function is called when we disconnect.
@ -202,9 +246,6 @@ function disconnect() {
connection.removeEventListener(
JitsiMeetJS.events.connection.CONNECTION_ESTABLISHED,
onConnectionSuccess);
connection.removeEventListener(
JitsiMeetJS.events.connection.CONNECTION_FAILED,
onConnectionFailed);
connection.removeEventListener(
JitsiMeetJS.events.connection.CONNECTION_DISCONNECTED,
disconnect);
@ -214,41 +255,15 @@ function disconnect() {
*
*/
function unload() {
for (let i = 0; i < localTracks.length; i++) {
localTracks[i].dispose();
}
room.leave();
connection.disconnect();
}
let isVideo = true;
/**
*
*/
function switchVideo() { // eslint-disable-line no-unused-vars
isVideo = !isVideo;
if (localTracks[1]) {
localTracks[1].dispose();
localTracks.pop();
}
JitsiMeetJS.createLocalTracks({
devices: [ isVideo ? 'video' : 'desktop' ]
})
.then(tracks => {
localTracks.push(tracks[0]);
localTracks[1].addEventListener(
JitsiMeetJS.events.track.TRACK_MUTE_CHANGED,
() => console.log('local track muted'));
localTracks[1].addEventListener(
JitsiMeetJS.events.track.LOCAL_TRACK_STOPPED,
() => console.log('local track stoped'));
localTracks[1].attach($('#localVideo1')[0]);
room.addTrack(localTracks[1]);
})
.catch(error => console.log(error));
function setLevel(id, level) {
let track = $(`#audio-${id}`)[0];
track.volume = level;
}
/**
*
* @param selected
@ -260,26 +275,8 @@ function changeAudioOutput(selected) { // eslint-disable-line no-unused-vars
$(window).bind('beforeunload', unload);
$(window).bind('unload', unload);
// JitsiMeetJS.setLogLevel(JitsiMeetJS.logLevels.ERROR);
const initOptions = {
disableAudioLevels: true,
// The ID of the jidesha extension for Chrome.
desktopSharingChromeExtId: 'mbocklcggfhnbahlnepmldehdhpjfcjp',
// Whether desktop sharing should be disabled on Chrome.
desktopSharingChromeDisabled: false,
// The media sources to use when using screen sharing with the Chrome
// extension.
desktopSharingChromeSources: [ 'screen', 'window' ],
// Required version of Chrome extension
desktopSharingChromeMinExtVersion: '0.1',
// Whether desktop sharing should be disabled on Firefox.
desktopSharingFirefoxDisabled: true
};
JitsiMeetJS.setLogLevel(JitsiMeetJS.logLevels.ERROR);
const initOptions = {};
JitsiMeetJS.init(initOptions);
@ -288,17 +285,10 @@ connection = new JitsiMeetJS.JitsiConnection(null, null, options);
connection.addEventListener(
JitsiMeetJS.events.connection.CONNECTION_ESTABLISHED,
onConnectionSuccess);
connection.addEventListener(
JitsiMeetJS.events.connection.CONNECTION_FAILED,
onConnectionFailed);
connection.addEventListener(
JitsiMeetJS.events.connection.CONNECTION_DISCONNECTED,
disconnect);
JitsiMeetJS.mediaDevices.addEventListener(
JitsiMeetJS.events.mediaDevices.DEVICE_LIST_CHANGED,
onDeviceListChanged);
connection.connect();
JitsiMeetJS.createLocalTracks({ devices: [ 'audio', 'video' ] })

View File

@ -6,18 +6,79 @@
<script src="libs/jquery-2.1.1.min.js"></script>
<script src="libs/strophe/strophe.js"></script>
<script src="libs/strophe/strophe.disco.min.js?v=1"></script>
<!-- <script src="https://meet.jit.si/libs/lib-jitsi-meet.min.js"></script> -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
<script src="libs/lib-jitsi-meet.min.js"></script>
<script src="example.js" ></script>
<style type="text/css">
body {
padding: 12px;
}
video {
display: block;
margin: 0 auto;
}
.col-md-4 {
padding: 0 !important;
margin: 0 !important;
}
.row {
padding: 0 !important;
margin: 0 !important;
}
.video {
height: 384px;
text-align: center;
}
</style>
</head>
<body>
<a href="#" onclick="unload()">Unload</a>
<a href="#" onclick="switchVideo()">switchVideo</a>
<div class="container-fluid">
<div class="row">
<div class="col-md-4 video video-0">
<video autoplay='autoplay' width="640" height="360"></video>
<audio autoplay='autoplay'></audio>
<span></span>
</div>
<div class="col-md-4 video video-1">
<video autoplay='autoplay' width="640" height="360"></video>
<audio autoplay='autoplay'></audio>
<span></span>
</div>
<div class="col-md-4 video video-2">
<video autoplay='autoplay' width="640" height="360"></video>
<audio autoplay='autoplay'></audio>
<span></span>
</div>
</div>
<div class="row">
<div class="col-md-4 video video-3">
<video autoplay='autoplay' width="640" height="360"></video>
<audio autoplay='autoplay'></audio>
<span></span>
</div>
<div class="col-md-4 video video-4">
<video autoplay='autoplay' width="640" height="360"></video>
<audio autoplay='autoplay'></audio>
<span></span>
</div>
<div class="col-md-4 video video-5">
<video autoplay='autoplay' width="640" height="360"></video>
<audio autoplay='autoplay'></audio>
<span></span>
</div>
</div>
</div>
<input type="range" min="0" max="1" step="0.01" value="0.7" onchange="setLevel(0, this.value)">
<input type="range" min="0" max="1" step="0.01" value="0.7" onchange="setLevel(1, this.value)">
<input type="range" min="0" max="1" step="0.01" value="0.7" onchange="setLevel(2, this.value)">
<input type="range" min="0" max="1" step="0.01" value="0.7" onchange="setLevel(3, this.value)">
<input type="range" min="0" max="1" step="0.01" value="0.7" onchange="setLevel(4, this.value)">
<input type="range" min="0" max="1" step="0.01" value="0.7" onchange="setLevel(5, this.value)">
<div id="audioOutputSelectWrapper" style="display: none;">
Change audio output device
<select id="audioOutputSelect" onchange="changeAudioOutput(this)"></select>
</div>
<!-- <video id="localVideo" autoplay="true"></video> -->
<!--<audio id="localAudio" autoplay="true" muted="true"></audio>-->
</body>
</html>

File diff suppressed because one or more lines are too long