mirror of
https://github.com/jech/galene.git
synced 2024-11-09 18:25:58 +01:00
Rework the up connection state machine.
It is now more similar to the down connection, using the onclose callback for resource management.
This commit is contained in:
parent
10ebe0e433
commit
8168c2a9e6
3 changed files with 63 additions and 70 deletions
|
@ -40,11 +40,10 @@ serverConnection.ondownstream = ...;
|
||||||
```
|
```
|
||||||
|
|
||||||
The `onconnected` callback is called when we connect to the server. The
|
The `onconnected` callback is called when we connect to the server. The
|
||||||
`onclose` callback is called when the socket is closed; you should use it
|
`onclose` callback is called when the socket is closed; all streams will
|
||||||
to close all your up streams (down streams will be closed by the server).
|
have been closed by the time it is called. The `onusermessage` callback
|
||||||
The `onusermessage` callback indicates an application-specific message,
|
indicates an application-specific message, either from another user or
|
||||||
either from another user or from the server; the field `kind` indicates
|
from the server; the field `kind` indicates the kind of message.
|
||||||
the kind of message.
|
|
||||||
|
|
||||||
Once you have joined a group (see below), the remaining callbacks may
|
Once you have joined a group (see below), the remaining callbacks may
|
||||||
trigger. The `onuser` callback is used to indicate that a user has joined
|
trigger. The `onuser` callback is used to indicate that a user has joined
|
||||||
|
@ -126,8 +125,8 @@ a change in the status of the stream; states `connected` and `complete`
|
||||||
indicate a functioning stream; other states indicate that the stream is
|
indicate a functioning stream; other states indicate that the stream is
|
||||||
not working right now but might recover in the future.
|
not working right now but might recover in the future.
|
||||||
|
|
||||||
The `onclose` callback is called when the stream is destroyed by the
|
The `onclose` callback is called when the stream is destroyed, either by
|
||||||
server.
|
the server or in response to a call to the `close` method.
|
||||||
|
|
||||||
## Pushing outgoing video streams
|
## Pushing outgoing video streams
|
||||||
|
|
||||||
|
|
|
@ -309,7 +309,6 @@ function gotConnected() {
|
||||||
* @param {string} reason
|
* @param {string} reason
|
||||||
*/
|
*/
|
||||||
function gotClose(code, reason) {
|
function gotClose(code, reason) {
|
||||||
delUpMediaKind(null);
|
|
||||||
setConnected(false);
|
setConnected(false);
|
||||||
if(code != 1000) {
|
if(code != 1000) {
|
||||||
console.warn('Socket close', code, reason);
|
console.warn('Socket close', code, reason);
|
||||||
|
@ -374,7 +373,7 @@ getButtonElement('presentbutton').onclick = async function(e) {
|
||||||
|
|
||||||
getButtonElement('unpresentbutton').onclick = function(e) {
|
getButtonElement('unpresentbutton').onclick = function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
delUpMediaKind('local');
|
closeUpMediaKind('local');
|
||||||
resizePeers();
|
resizePeers();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -482,13 +481,13 @@ document.getElementById('sharebutton').onclick = function(e) {
|
||||||
|
|
||||||
document.getElementById('unsharebutton').onclick = function(e) {
|
document.getElementById('unsharebutton').onclick = function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
delUpMediaKind('screenshare');
|
closeUpMediaKind('screenshare');
|
||||||
resizePeers();
|
resizePeers();
|
||||||
};
|
};
|
||||||
|
|
||||||
document.getElementById('stopvideobutton').onclick = function(e) {
|
document.getElementById('stopvideobutton').onclick = function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
delUpMediaKind('video');
|
closeUpMediaKind('video');
|
||||||
resizePeers();
|
resizePeers();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -757,10 +756,6 @@ function newUpStream(id) {
|
||||||
c.onerror = function(e) {
|
c.onerror = function(e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
displayError(e);
|
displayError(e);
|
||||||
delUpMedia(c);
|
|
||||||
};
|
|
||||||
c.onabort = function() {
|
|
||||||
delUpMedia(c);
|
|
||||||
};
|
};
|
||||||
c.onnegotiationcompleted = function() {
|
c.onnegotiationcompleted = function() {
|
||||||
setMaxVideoThroughput(c, getMaxVideoThroughput());
|
setMaxVideoThroughput(c, getMaxVideoThroughput());
|
||||||
|
@ -928,23 +923,16 @@ function setFilter(c, f) {
|
||||||
c.userdata.filter.stop();
|
c.userdata.filter.stop();
|
||||||
c.userdata.filter = null;
|
c.userdata.filter = null;
|
||||||
}
|
}
|
||||||
if(!c.onclose) {
|
|
||||||
console.warn("onclose not set, this shouldn't happen");
|
|
||||||
c.onclose = null;
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if(c.userdata.filter)
|
if(c.userdata.filter)
|
||||||
setFilter(c, null);
|
setFilter(c, null);
|
||||||
|
|
||||||
if(c.onclose)
|
|
||||||
throw new Error('onclose already taken');
|
|
||||||
if(f.inputStream != c.stream)
|
if(f.inputStream != c.stream)
|
||||||
throw new Error('Setting filter for wrong stream');
|
throw new Error('Setting filter for wrong stream');
|
||||||
c.stream = f.outputStream;
|
c.stream = f.outputStream;
|
||||||
c.userdata.filter = f;
|
c.userdata.filter = f;
|
||||||
c.onclose = () => setFilter(c, null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1028,13 +1016,10 @@ async function addLocalMedia(id) {
|
||||||
|
|
||||||
if(!audio && !video) {
|
if(!audio && !video) {
|
||||||
if(old)
|
if(old)
|
||||||
delUpMedia(old);
|
old.close();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(old)
|
|
||||||
stopUpMedia(old);
|
|
||||||
|
|
||||||
let constraints = {audio: audio, video: video};
|
let constraints = {audio: audio, video: video};
|
||||||
/** @type {MediaStream} */
|
/** @type {MediaStream} */
|
||||||
let stream = null;
|
let stream = null;
|
||||||
|
@ -1043,7 +1028,7 @@ async function addLocalMedia(id) {
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
displayError(e);
|
displayError(e);
|
||||||
if(old)
|
if(old)
|
||||||
delUpMedia(old);
|
old.close();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1058,8 +1043,22 @@ async function addLocalMedia(id) {
|
||||||
try {
|
try {
|
||||||
let f = new Filter(stream, filter);
|
let f = new Filter(stream, filter);
|
||||||
setFilter(c, f);
|
setFilter(c, f);
|
||||||
|
c.onclose = () => {
|
||||||
|
stopStream(stream);
|
||||||
|
setFilter(c, null);
|
||||||
|
delMedia(c.id);
|
||||||
|
}
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
displayWarning(e);
|
displayWarning(e);
|
||||||
|
c.onclose = () => {
|
||||||
|
stopStream(c.stream);
|
||||||
|
delMedia(c.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
c.onclose = () => {
|
||||||
|
stopStream(c.stream);
|
||||||
|
delMedia(c.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1110,11 +1109,13 @@ async function addShareMedia() {
|
||||||
let c = newUpStream();
|
let c = newUpStream();
|
||||||
c.kind = 'screenshare';
|
c.kind = 'screenshare';
|
||||||
c.stream = stream;
|
c.stream = stream;
|
||||||
|
c.onclose = () => {
|
||||||
|
stopStream(stream);
|
||||||
|
delMedia(c.id);
|
||||||
|
}
|
||||||
stream.getTracks().forEach(t => {
|
stream.getTracks().forEach(t => {
|
||||||
c.pc.addTrack(t, stream);
|
c.pc.addTrack(t, stream);
|
||||||
t.onended = e => {
|
t.onended = e => c.close();
|
||||||
delUpMedia(c);
|
|
||||||
};
|
|
||||||
c.labels[t.id] = 'screenshare';
|
c.labels[t.id] = 'screenshare';
|
||||||
});
|
});
|
||||||
c.onstats = gotUpStats;
|
c.onstats = gotUpStats;
|
||||||
|
@ -1144,12 +1145,14 @@ async function addFileMedia(file) {
|
||||||
c.kind = 'video';
|
c.kind = 'video';
|
||||||
c.stream = stream;
|
c.stream = stream;
|
||||||
c.onclose = function() {
|
c.onclose = function() {
|
||||||
|
stopStream(c.stream);
|
||||||
let media = /** @type{HTMLVideoElement} */
|
let media = /** @type{HTMLVideoElement} */
|
||||||
(document.getElementById('media-' + this.id));
|
(document.getElementById('media-' + this.id));
|
||||||
if(media && media.src) {
|
if(media && media.src) {
|
||||||
URL.revokeObjectURL(media.src);
|
URL.revokeObjectURL(media.src);
|
||||||
media.src = null;
|
media.src = null;
|
||||||
}
|
}
|
||||||
|
delMedia(c.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
stream.onaddtrack = function(e) {
|
stream.onaddtrack = function(e) {
|
||||||
|
@ -1186,7 +1189,7 @@ async function addFileMedia(file) {
|
||||||
if(Object.keys(c.labels).length === 0) {
|
if(Object.keys(c.labels).length === 0) {
|
||||||
stream.onaddtrack = null;
|
stream.onaddtrack = null;
|
||||||
stream.onremovetrack = null;
|
stream.onremovetrack = null;
|
||||||
delUpMedia(c);
|
c.close();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
await setMedia(c, true, false, video);
|
await setMedia(c, true, false, video);
|
||||||
|
@ -1195,13 +1198,10 @@ async function addFileMedia(file) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Stream} c
|
* @param {MediaStream} s
|
||||||
*/
|
*/
|
||||||
function stopUpMedia(c) {
|
function stopStream(s) {
|
||||||
setFilter(c, null);
|
s.getTracks().forEach(t => {
|
||||||
if(!c.stream)
|
|
||||||
return;
|
|
||||||
c.stream.getTracks().forEach(t => {
|
|
||||||
try {
|
try {
|
||||||
t.stop();
|
t.stop();
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
|
@ -1211,31 +1211,18 @@ function stopUpMedia(c) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Stream} c
|
* closeUpMediaKind closes all up connections that correspond to a given
|
||||||
*/
|
* kind of media. If kind is null, it closes all up connections.
|
||||||
function delUpMedia(c) {
|
*
|
||||||
stopUpMedia(c);
|
|
||||||
c.close();
|
|
||||||
delMedia(c.id);
|
|
||||||
delete(serverConnection.up[c.id]);
|
|
||||||
setButtonsVisibility();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* delUpMediaKind reoves all up media of the given kind. If kind is
|
|
||||||
* falseish, it removes all up media.
|
|
||||||
* @param {string} kind
|
* @param {string} kind
|
||||||
*/
|
*/
|
||||||
function delUpMediaKind(kind) {
|
function closeUpMediaKind(kind) {
|
||||||
for(let id in serverConnection.up) {
|
for(let id in serverConnection.up) {
|
||||||
let c = serverConnection.up[id];
|
let c = serverConnection.up[id];
|
||||||
if(kind && c.kind != kind)
|
if(kind && c.kind != kind)
|
||||||
continue
|
continue
|
||||||
delUpMedia(c);
|
c.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
setButtonsVisibility();
|
|
||||||
hideVideo();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1501,6 +1488,7 @@ function delMedia(id) {
|
||||||
media.srcObject = null;
|
media.srcObject = null;
|
||||||
mediadiv.removeChild(peer);
|
mediadiv.removeChild(peer);
|
||||||
|
|
||||||
|
setButtonsVisibility();
|
||||||
resizePeers();
|
resizePeers();
|
||||||
hideVideo();
|
hideVideo();
|
||||||
}
|
}
|
||||||
|
|
|
@ -238,12 +238,10 @@ ServerConnection.prototype.connect = async function(url) {
|
||||||
sc.permissions = {};
|
sc.permissions = {};
|
||||||
for(let id in sc.up) {
|
for(let id in sc.up) {
|
||||||
let c = sc.up[id];
|
let c = sc.up[id];
|
||||||
delete(sc.up[id]);
|
|
||||||
c.close();
|
c.close();
|
||||||
}
|
}
|
||||||
for(let id in sc.down) {
|
for(let id in sc.down) {
|
||||||
let c = sc.down[id];
|
let c = sc.down[id];
|
||||||
delete(sc.down[id]);
|
|
||||||
c.close();
|
c.close();
|
||||||
}
|
}
|
||||||
if(sc.group && sc.onjoined)
|
if(sc.group && sc.onjoined)
|
||||||
|
@ -408,9 +406,9 @@ ServerConnection.prototype.newUpStream = function(id) {
|
||||||
let pc = new RTCPeerConnection(sc.rtcConfiguration);
|
let pc = new RTCPeerConnection(sc.rtcConfiguration);
|
||||||
if(!pc)
|
if(!pc)
|
||||||
throw new Error("Couldn't create peer connection");
|
throw new Error("Couldn't create peer connection");
|
||||||
if(sc.up[id]) {
|
if(sc.up[id])
|
||||||
sc.up[id].close();
|
sc.up[id].close();
|
||||||
}
|
|
||||||
let c = new Stream(this, id, pc, true);
|
let c = new Stream(this, id, pc, true);
|
||||||
sc.up[id] = c;
|
sc.up[id] = c;
|
||||||
|
|
||||||
|
@ -530,7 +528,6 @@ ServerConnection.prototype.gotOffer = async function(id, labels, source, usernam
|
||||||
// SDP is rather inflexible as to what can be renegotiated.
|
// SDP is rather inflexible as to what can be renegotiated.
|
||||||
// Unless the server indicates that this is a renegotiation with
|
// Unless the server indicates that this is a renegotiation with
|
||||||
// all parameters unchanged, tear down the existing connection.
|
// all parameters unchanged, tear down the existing connection.
|
||||||
delete(sc.down[id]);
|
|
||||||
c.close(true);
|
c.close(true);
|
||||||
c = null;
|
c = null;
|
||||||
}
|
}
|
||||||
|
@ -669,7 +666,6 @@ ServerConnection.prototype.gotClose = function(id) {
|
||||||
let c = this.down[id];
|
let c = this.down[id];
|
||||||
if(!c)
|
if(!c)
|
||||||
throw new Error('unknown down stream');
|
throw new Error('unknown down stream');
|
||||||
delete(this.down[id]);
|
|
||||||
c.close();
|
c.close();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -888,19 +884,17 @@ function Stream(sc, id, pc, up) {
|
||||||
*/
|
*/
|
||||||
Stream.prototype.close = function(nocallback) {
|
Stream.prototype.close = function(nocallback) {
|
||||||
let c = this;
|
let c = this;
|
||||||
|
|
||||||
|
if(!c.sc) {
|
||||||
|
console.warn('Closing closed stream');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if(c.statsHandler) {
|
if(c.statsHandler) {
|
||||||
clearInterval(c.statsHandler);
|
clearInterval(c.statsHandler);
|
||||||
c.statsHandler = null;
|
c.statsHandler = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(c.stream) {
|
|
||||||
c.stream.getTracks().forEach(t => {
|
|
||||||
try {
|
|
||||||
t.stop();
|
|
||||||
} catch(e) {
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
c.pc.close();
|
c.pc.close();
|
||||||
|
|
||||||
if(c.up && c.localDescriptionSent) {
|
if(c.up && c.localDescriptionSent) {
|
||||||
|
@ -913,9 +907,21 @@ Stream.prototype.close = function(nocallback) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(c.up) {
|
||||||
|
if(c.sc.up[c.id] === c)
|
||||||
|
delete(c.sc.up[c.id]);
|
||||||
|
else
|
||||||
|
console.warn('Closing unknown stream');
|
||||||
|
} else {
|
||||||
|
if(c.sc.down[c.id] === c)
|
||||||
|
delete(c.sc.down[c.id]);
|
||||||
|
else
|
||||||
|
console.warn('Closing unknown stream');
|
||||||
|
}
|
||||||
|
c.sc = null;
|
||||||
|
|
||||||
if(!nocallback && c.onclose)
|
if(!nocallback && c.onclose)
|
||||||
c.onclose.call(c);
|
c.onclose.call(c);
|
||||||
c.sc = null;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in a new issue