Optionally automatically mutes the local video if it is not in any "last N".
This commit is contained in:
parent
4c95921b06
commit
ae4dafb06d
68
app.js
68
app.js
|
@ -1035,26 +1035,60 @@ function getConferenceHandler() {
|
|||
return activecall;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mutes/unmutes the local video.
|
||||
*
|
||||
* @param mute <tt>true</tt> to mute the local video; otherwise, <tt>false</tt>
|
||||
* @param options an object which specifies optional arguments such as the
|
||||
* <tt>boolean</tt> key <tt>byUser</tt> with default value <tt>true</tt> which
|
||||
* specifies whether the method was initiated in response to a user command (in
|
||||
* contrast to an automatic decision taken by the application logic)
|
||||
*/
|
||||
function setVideoMute(mute, options) {
|
||||
if (connection && connection.jingle.localVideo) {
|
||||
var session = getConferenceHandler();
|
||||
|
||||
if (session) {
|
||||
session.setVideoMute(
|
||||
mute,
|
||||
function (mute) {
|
||||
var video = $('#video');
|
||||
var communicativeClass = "icon-camera";
|
||||
var muteClass = "icon-camera icon-camera-disabled";
|
||||
|
||||
if (mute) {
|
||||
video.removeClass(communicativeClass);
|
||||
video.addClass(muteClass);
|
||||
} else {
|
||||
video.removeClass(muteClass);
|
||||
video.addClass(communicativeClass);
|
||||
}
|
||||
connection.emuc.addVideoInfoToPresence(mute);
|
||||
connection.emuc.sendPresence();
|
||||
},
|
||||
options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$(document).on('inlastnchanged', function (event, oldValue, newValue) {
|
||||
if (config.muteLocalVideoIfNotInLastN) {
|
||||
setVideoMute(!newValue, { 'byUser': false });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Mutes/unmutes the local video.
|
||||
*/
|
||||
function toggleVideo() {
|
||||
buttonClick("#video", "icon-camera icon-camera-disabled");
|
||||
if (!(connection && connection.jingle.localVideo))
|
||||
return;
|
||||
|
||||
var sess = getConferenceHandler();
|
||||
if (sess) {
|
||||
sess.toggleVideoMute(
|
||||
function (isMuted) {
|
||||
if (isMuted) {
|
||||
$('#video').removeClass("icon-camera");
|
||||
$('#video').addClass("icon-camera icon-camera-disabled");
|
||||
} else {
|
||||
$('#video').removeClass("icon-camera icon-camera-disabled");
|
||||
$('#video').addClass("icon-camera");
|
||||
}
|
||||
connection.emuc.addVideoInfoToPresence(isMuted);
|
||||
connection.emuc.sendPresence();
|
||||
}
|
||||
);
|
||||
if (connection && connection.jingle.localVideo) {
|
||||
var session = getConferenceHandler();
|
||||
|
||||
if (session) {
|
||||
setVideoMute(!session.isVideoMute());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -70,46 +70,65 @@ function onDataChannel(event)
|
|||
'dominantspeakerchanged',
|
||||
[dominantSpeakerEndpoint]);
|
||||
}
|
||||
else if ("InLastNChangeEvent" === colibriClass)
|
||||
{
|
||||
var oldValue = obj.oldValue;
|
||||
var newValue = obj.newValue;
|
||||
// Make sure that oldValue and newValue are of type boolean.
|
||||
var type;
|
||||
|
||||
if ((type = typeof oldValue) !== 'boolean') {
|
||||
if (type === 'string') {
|
||||
oldValue = (oldValue == "true");
|
||||
} else {
|
||||
oldValue = new Boolean(oldValue).valueOf();
|
||||
}
|
||||
}
|
||||
if ((type = typeof newValue) !== 'boolean') {
|
||||
if (type === 'string') {
|
||||
newValue = (newValue == "true");
|
||||
} else {
|
||||
newValue = new Boolean(newValue).valueOf();
|
||||
}
|
||||
}
|
||||
$(document).trigger('inlastnchanged', [oldValue, newValue]);
|
||||
}
|
||||
else if ("LastNEndpointsChangeEvent" === colibriClass)
|
||||
{
|
||||
// The new/latest list of last-n endpoint IDs.
|
||||
var lastNEndpoints = obj.lastNEndpoints;
|
||||
/*
|
||||
* The list of endpoint IDs which are entering the list of
|
||||
* last-n at this time i.e. were not in the old list of last-n
|
||||
* endpoint IDs.
|
||||
*/
|
||||
// The list of endpoint IDs which are entering the list of
|
||||
// last-n at this time i.e. were not in the old list of last-n
|
||||
// endpoint IDs.
|
||||
var endpointsEnteringLastN = obj.endpointsEnteringLastN;
|
||||
|
||||
var stream = obj.stream;
|
||||
|
||||
console.log(
|
||||
"Data channel new last-n event: ",
|
||||
lastNEndpoints, endpointsEnteringLastN, obj);
|
||||
|
||||
$(document).trigger(
|
||||
'lastnchanged',
|
||||
[lastNEndpoints, endpointsEnteringLastN, stream]);
|
||||
'lastnchanged',
|
||||
[lastNEndpoints, endpointsEnteringLastN, stream]);
|
||||
}
|
||||
else if ("SimulcastLayersChangedEvent" === colibriClass)
|
||||
{
|
||||
var endpointSimulcastLayers = obj.endpointSimulcastLayers;
|
||||
$(document).trigger('simulcastlayerschanged', [endpointSimulcastLayers]);
|
||||
$(document).trigger(
|
||||
'simulcastlayerschanged',
|
||||
[obj.endpointSimulcastLayers]);
|
||||
}
|
||||
else if ("SimulcastLayersChangingEvent" === colibriClass)
|
||||
{
|
||||
var endpointSimulcastLayers = obj.endpointSimulcastLayers;
|
||||
$(document).trigger('simulcastlayerschanging', [endpointSimulcastLayers]);
|
||||
$(document).trigger(
|
||||
'simulcastlayerschanging',
|
||||
[obj.endpointSimulcastLayers]);
|
||||
}
|
||||
else if ("StartSimulcastLayerEvent" === colibriClass)
|
||||
{
|
||||
var simulcastLayer = obj.simulcastLayer;
|
||||
$(document).trigger('startsimulcastlayer', simulcastLayer);
|
||||
$(document).trigger('startsimulcastlayer', obj.simulcastLayer);
|
||||
}
|
||||
else if ("StopSimulcastLayerEvent" === colibriClass)
|
||||
{
|
||||
var simulcastLayer = obj.simulcastLayer;
|
||||
$(document).trigger('stopsimulcastlayer', simulcastLayer);
|
||||
$(document).trigger('stopsimulcastlayer', obj.simulcastLayer);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -141,10 +160,8 @@ function bindDataChannelListener(peerConnection)
|
|||
// and peer as single channel can be used for sending and receiving data.
|
||||
// So either channel opened by the bridge or the one opened here is enough
|
||||
// for communication with the bridge.
|
||||
/*var dataChannelOptions =
|
||||
{
|
||||
reliable: true
|
||||
};
|
||||
/*
|
||||
var dataChannelOptions = { reliable: true };
|
||||
var dataChannel
|
||||
= peerConnection.createDataChannel("myChannel", dataChannelOptions);
|
||||
|
||||
|
@ -157,6 +174,7 @@ function bindDataChannelListener(peerConnection)
|
|||
{
|
||||
var msgData = event.data;
|
||||
console.info("Got My Data Channel Message:", msgData, dataChannel);
|
||||
};*/
|
||||
};
|
||||
*/
|
||||
}
|
||||
|
||||
|
|
|
@ -4,10 +4,16 @@
|
|||
* @param sid my session identifier(resource)
|
||||
* @constructor
|
||||
*/
|
||||
function SessionBase(connection, sid){
|
||||
|
||||
function SessionBase(connection, sid) {
|
||||
this.connection = connection;
|
||||
this.sid = sid;
|
||||
|
||||
/**
|
||||
* The indicator which determines whether the (local) video has been muted
|
||||
* in response to a user command in contrast to an automatic decision made
|
||||
* by the application logic.
|
||||
*/
|
||||
this.muteByUser = true;
|
||||
}
|
||||
|
||||
|
||||
|
@ -63,6 +69,7 @@ SessionBase.prototype.removeSource = function (elem, fromJid) {
|
|||
|
||||
this.modifySources();
|
||||
};
|
||||
|
||||
/**
|
||||
* Switches video streams.
|
||||
* @param new_stream new stream that will be used as video of this session.
|
||||
|
@ -230,20 +237,85 @@ SessionBase.prototype.sendSSRCUpdateIq = function(sdpMediaSsrcs, sid, initiator,
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Determines whether the (local) video is mute i.e. all video tracks are
|
||||
* disabled.
|
||||
*
|
||||
* @return <tt>true</tt> if the (local) video is mute i.e. all video tracks are
|
||||
* disabled; otherwise, <tt>false</tt>
|
||||
*/
|
||||
SessionBase.prototype.isVideoMute = function () {
|
||||
var tracks = connection.jingle.localVideo.getVideoTracks();
|
||||
var mute = true;
|
||||
|
||||
for (var i = 0; i < tracks.length; ++i) {
|
||||
if (tracks[i].enabled) {
|
||||
mute = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return mute;
|
||||
};
|
||||
|
||||
/**
|
||||
* Mutes/unmutes the (local) video i.e. enables/disables all video tracks.
|
||||
*
|
||||
* @param mute <tt>true</tt> to mute the (local) video i.e. to disable all video
|
||||
* tracks; otherwise, <tt>false</tt>
|
||||
* @param callback a function to be invoked with <tt>mute</tt> after all video
|
||||
* tracks have been enabled/disabled. The function may, optionally, return
|
||||
* another function which is to be invoked after the whole mute/unmute operation
|
||||
* has completed successfully.
|
||||
* @param options an object which specifies optional arguments such as the
|
||||
* <tt>boolean</tt> key <tt>byUser</tt> with default value <tt>true</tt> which
|
||||
* specifies whether the method was initiated in response to a user command (in
|
||||
* contrast to an automatic decision made by the application logic)
|
||||
*/
|
||||
SessionBase.prototype.setVideoMute = function (mute, callback, options) {
|
||||
var byUser;
|
||||
|
||||
if (options) {
|
||||
byUser = options.byUser;
|
||||
if (typeof byUser === 'undefined') {
|
||||
byUser = true;
|
||||
}
|
||||
} else {
|
||||
byUser = true;
|
||||
}
|
||||
// The user's command to mute the (local) video takes precedence over any
|
||||
// automatic decision made by the application logic.
|
||||
if (byUser) {
|
||||
this.muteByUser = mute;
|
||||
} else if (this.muteByUser) {
|
||||
return;
|
||||
}
|
||||
if (mute == this.isVideoMute())
|
||||
{
|
||||
// Even if no change occurs, the specified callback is to be executed.
|
||||
// The specified callback may, optionally, return a successCallback
|
||||
// which is to be executed as well.
|
||||
var successCallback = callback(mute);
|
||||
|
||||
if (successCallback) {
|
||||
successCallback();
|
||||
}
|
||||
} else {
|
||||
var tracks = connection.jingle.localVideo.getVideoTracks();
|
||||
|
||||
for (var i = 0; i < tracks.length; ++i) {
|
||||
tracks[i].enabled = !mute;
|
||||
}
|
||||
|
||||
if (this.peerconnection) {
|
||||
this.peerconnection.hardMuteVideo(mute);
|
||||
}
|
||||
|
||||
this.modifySources(callback(mute));
|
||||
}
|
||||
};
|
||||
|
||||
// SDP-based mute by going recvonly/sendrecv
|
||||
// FIXME: should probably black out the screen as well
|
||||
SessionBase.prototype.toggleVideoMute = function (callback) {
|
||||
|
||||
var ismuted = false;
|
||||
var localVideo = connection.jingle.localVideo;
|
||||
for (var idx = 0; idx < localVideo.getVideoTracks().length; idx++) {
|
||||
ismuted = !localVideo.getVideoTracks()[idx].enabled;
|
||||
}
|
||||
for (var idx = 0; idx < localVideo.getVideoTracks().length; idx++) {
|
||||
localVideo.getVideoTracks()[idx].enabled = !localVideo.getVideoTracks()[idx].enabled;
|
||||
}
|
||||
|
||||
if(this.peerconnection)
|
||||
this.peerconnection.hardMuteVideo(!ismuted);
|
||||
this.modifySources(callback(!ismuted));
|
||||
setVideoMute(isVideoMute(), callback);
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue