mirror of https://github.com/OpenVidu/openvidu.git
openvidu-browser: move Transceiver creation in createOffer/createAnswer
parent
84a5683b56
commit
60b24fd412
|
@ -806,20 +806,6 @@ export class Stream {
|
||||||
this.initHarkEvents(); // Init hark events for the local stream
|
this.initHarkEvents(); // Init hark events for the local stream
|
||||||
}
|
}
|
||||||
|
|
||||||
const userMediaConstraints = {
|
|
||||||
audio: this.isSendAudio(),
|
|
||||||
video: this.isSendVideo()
|
|
||||||
};
|
|
||||||
|
|
||||||
const options: WebRtcPeerConfiguration = {
|
|
||||||
mediaStream: this.mediaStream,
|
|
||||||
mediaConstraints: userMediaConstraints,
|
|
||||||
onicecandidate: this.connection.sendIceCandidate.bind(this.connection),
|
|
||||||
onexception: (exceptionName: ExceptionEventName, message: string, data?: any) => { this.session.emitEvent('exception', [new ExceptionEvent(this.session, exceptionName, this, message, data)]) },
|
|
||||||
iceServers: this.getIceServersConf(),
|
|
||||||
simulcast: false
|
|
||||||
};
|
|
||||||
|
|
||||||
const successOfferCallback = (sdpOfferParam) => {
|
const successOfferCallback = (sdpOfferParam) => {
|
||||||
logger.debug('Sending SDP offer to publish as '
|
logger.debug('Sending SDP offer to publish as '
|
||||||
+ this.streamId, sdpOfferParam);
|
+ this.streamId, sdpOfferParam);
|
||||||
|
@ -884,13 +870,25 @@ export class Stream {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const config: WebRtcPeerConfiguration = {
|
||||||
|
mediaConstraints: {
|
||||||
|
audio: this.hasAudio,
|
||||||
|
video: this.hasVideo,
|
||||||
|
},
|
||||||
|
simulcast: false,
|
||||||
|
onicecandidate: this.connection.sendIceCandidate.bind(this.connection),
|
||||||
|
onexception: (exceptionName: ExceptionEventName, message: string, data?: any) => { this.session.emitEvent('exception', [new ExceptionEvent(this.session, exceptionName, this, message, data)]) },
|
||||||
|
iceServers: this.getIceServersConf(),
|
||||||
|
mediaStream: this.mediaStream,
|
||||||
|
};
|
||||||
|
|
||||||
if (reconnect) {
|
if (reconnect) {
|
||||||
this.disposeWebRtcPeer();
|
this.disposeWebRtcPeer();
|
||||||
}
|
}
|
||||||
if (this.displayMyRemote()) {
|
if (this.displayMyRemote()) {
|
||||||
this.webRtcPeer = new WebRtcPeerSendrecv(options);
|
this.webRtcPeer = new WebRtcPeerSendrecv(config);
|
||||||
} else {
|
} else {
|
||||||
this.webRtcPeer = new WebRtcPeerSendonly(options);
|
this.webRtcPeer = new WebRtcPeerSendonly(config);
|
||||||
}
|
}
|
||||||
this.webRtcPeer.addIceConnectionStateChangeListener('publisher of ' + this.connection.connectionId);
|
this.webRtcPeer.addIceConnectionStateChangeListener('publisher of ' + this.connection.connectionId);
|
||||||
this.webRtcPeer.createOffer().then(sdpOffer => {
|
this.webRtcPeer.createOffer().then(sdpOffer => {
|
||||||
|
@ -936,19 +934,7 @@ export class Stream {
|
||||||
completeWebRtcPeerReceive(sdpOffer: string, reconnect: boolean): Promise<void> {
|
completeWebRtcPeerReceive(sdpOffer: string, reconnect: boolean): Promise<void> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
|
||||||
const offerConstraints = {
|
logger.debug("'Session.subscribe(Stream)' called");
|
||||||
audio: this.inboundStreamOpts.hasAudio,
|
|
||||||
video: this.inboundStreamOpts.hasVideo
|
|
||||||
};
|
|
||||||
logger.debug("'Session.subscribe(Stream)' called. Constraints of generate SDP offer",
|
|
||||||
offerConstraints);
|
|
||||||
const options = {
|
|
||||||
onicecandidate: this.connection.sendIceCandidate.bind(this.connection),
|
|
||||||
onexception: (exceptionName: ExceptionEventName, message: string, data?: any) => { this.session.emitEvent('exception', [new ExceptionEvent(this.session, exceptionName, this, message, data)]) },
|
|
||||||
mediaConstraints: offerConstraints,
|
|
||||||
iceServers: this.getIceServersConf(),
|
|
||||||
simulcast: false
|
|
||||||
};
|
|
||||||
|
|
||||||
const successAnswerCallback = (sdpAnswer) => {
|
const successAnswerCallback = (sdpAnswer) => {
|
||||||
logger.debug('Sending SDP answer to subscribe to '
|
logger.debug('Sending SDP answer to subscribe to '
|
||||||
|
@ -968,7 +954,18 @@ export class Stream {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
this.webRtcPeer = new WebRtcPeerRecvonly(options);
|
const config: WebRtcPeerConfiguration = {
|
||||||
|
mediaConstraints: {
|
||||||
|
audio: this.hasAudio,
|
||||||
|
video: this.hasVideo,
|
||||||
|
},
|
||||||
|
simulcast: false,
|
||||||
|
onicecandidate: this.connection.sendIceCandidate.bind(this.connection),
|
||||||
|
onexception: (exceptionName: ExceptionEventName, message: string, data?: any) => { this.session.emitEvent('exception', [new ExceptionEvent(this.session, exceptionName, this, message, data)]) },
|
||||||
|
iceServers: this.getIceServersConf(),
|
||||||
|
};
|
||||||
|
|
||||||
|
this.webRtcPeer = new WebRtcPeerRecvonly(config);
|
||||||
this.webRtcPeer.addIceConnectionStateChangeListener(this.streamId);
|
this.webRtcPeer.addIceConnectionStateChangeListener(this.streamId);
|
||||||
this.webRtcPeer.processRemoteOffer(sdpOffer)
|
this.webRtcPeer.processRemoteOffer(sdpOffer)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
@ -1227,4 +1224,4 @@ export class Stream {
|
||||||
(report.type === 'candidate-pair' && report.nominated && report.bytesSent > 0);
|
(report.type === 'candidate-pair' && report.nominated && report.bytesSent > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,112 +111,49 @@ export class WebRtcPeer {
|
||||||
* Only if the negotiation was initiated by the this peer
|
* Only if the negotiation was initiated by the this peer
|
||||||
*/
|
*/
|
||||||
createOffer(): Promise<RTCSessionDescriptionInit> {
|
createOffer(): Promise<RTCSessionDescriptionInit> {
|
||||||
return new Promise((resolve, reject) => {
|
const hasAudio = this.configuration.mediaConstraints.audio;
|
||||||
const hasAudio = this.configuration.mediaConstraints.audio;
|
const hasVideo = this.configuration.mediaConstraints.video;
|
||||||
const hasVideo = this.configuration.mediaConstraints.video;
|
|
||||||
|
|
||||||
let offerPromise: Promise<RTCSessionDescriptionInit>;
|
let promise: Promise<RTCSessionDescriptionInit>;
|
||||||
|
|
||||||
// TODO: Delete this conditional when all supported browsers are
|
// TODO: Delete this conditional when all supported browsers are
|
||||||
// modern enough to implement the Transceiver methods.
|
// modern enough to implement the Transceiver methods.
|
||||||
if ("addTransceiver" in this.pc) {
|
if ("addTransceiver" in this.pc) {
|
||||||
logger.debug("[createOffer] Method RTCPeerConnection.addTransceiver() is available; using it");
|
logger.debug("[createOffer] Method RTCPeerConnection.addTransceiver() is available; using it");
|
||||||
|
|
||||||
// At this point, all "send" audio/video tracks have been added
|
if (this.configuration.mediaStream) {
|
||||||
// with pc.addTrack(), which in modern versions of libwebrtc
|
for (const track of this.configuration.mediaStream.getTracks()) {
|
||||||
// will have created Transceivers with "sendrecv" direction.
|
this.pc.addTransceiver(track, {
|
||||||
// Source: [addTrack/9.3](https://www.w3.org/TR/2020/CRD-webrtc-20201203/#dom-rtcpeerconnection-addtrack).
|
direction: this.configuration.mode,
|
||||||
//
|
streams: [this.configuration.mediaStream],
|
||||||
// Here we just need to enforce that those Transceivers have the
|
sendEncodings: [],
|
||||||
// correct direction, either "sendrecv" or "sendonly".
|
});
|
||||||
//
|
|
||||||
// Otherwise, if the tracks are "recv", no Transceiver should
|
|
||||||
// have been added yet.
|
|
||||||
|
|
||||||
const tcs = this.pc.getTransceivers();
|
|
||||||
|
|
||||||
if (tcs.length > 0) {
|
|
||||||
// Assert correct mode.
|
|
||||||
if (
|
|
||||||
this.configuration.mode !== "sendrecv" &&
|
|
||||||
this.configuration.mode !== "sendonly"
|
|
||||||
) {
|
|
||||||
throw new Error(
|
|
||||||
"BUG: Transceivers added, but direction is not send"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const tc of tcs) {
|
|
||||||
tc.direction = this.configuration.mode;
|
|
||||||
logger.debug(
|
|
||||||
`RTCRtpTransceiver direction: ${tc.direction}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (this.configuration.mode !== "recvonly") {
|
|
||||||
throw new Error(
|
|
||||||
"BUG: Transceivers missing, but direction is not recv"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasAudio) {
|
|
||||||
this.pc.addTransceiver("audio", {
|
|
||||||
direction: this.configuration.mode,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasVideo) {
|
|
||||||
this.pc.addTransceiver("video", {
|
|
||||||
direction: this.configuration.mode,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
offerPromise = this.pc.createOffer();
|
|
||||||
} else {
|
|
||||||
logger.debug("[generateOffer] Method pc.getTransceivers() NOT available; using LEGACY offerToReceive{Audio,Video}");
|
|
||||||
|
|
||||||
// DEPRECATED: LEGACY METHOD: Old WebRTC versions don't implement
|
|
||||||
// Transceivers, and instead depend on the deprecated
|
|
||||||
// "offerToReceiveAudio" and "offerToReceiveVideo".
|
|
||||||
|
|
||||||
const constraints: RTCOfferOptions = {
|
|
||||||
offerToReceiveAudio:
|
|
||||||
this.configuration.mode !== "sendonly" && hasAudio,
|
|
||||||
offerToReceiveVideo:
|
|
||||||
this.configuration.mode !== "sendonly" && hasVideo,
|
|
||||||
};
|
|
||||||
|
|
||||||
logger.debug(
|
|
||||||
"RTCPeerConnection constraints: " +
|
|
||||||
JSON.stringify(constraints)
|
|
||||||
);
|
|
||||||
|
|
||||||
// @ts-ignore: Compiler is too clever and thinks this branch
|
|
||||||
// will never execute.
|
|
||||||
offerPromise = this.pc.createOffer(constraints);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
offerPromise
|
promise = this.pc.createOffer();
|
||||||
.then((offer) => {
|
} else {
|
||||||
logger.debug("Created SDP offer");
|
logger.debug("[createOffer] Method RTCPeerConnection.addTransceiver() is NOT available; using LEGACY offerToReceive{Audio,Video}");
|
||||||
return this.pc.setLocalDescription(offer);
|
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
const localDescription = this.pc.localDescription;
|
|
||||||
|
|
||||||
if (!!localDescription) {
|
// DEPRECATED: LEGACY METHOD: Old WebRTC versions don't implement
|
||||||
logger.debug(
|
// Transceivers, and instead depend on the deprecated
|
||||||
"Local description set:",
|
// "offerToReceiveAudio" and "offerToReceiveVideo".
|
||||||
localDescription.sdp
|
|
||||||
);
|
const options: RTCOfferOptions = {
|
||||||
resolve(localDescription.sdp);
|
offerToReceiveAudio:
|
||||||
} else {
|
this.configuration.mode !== "sendonly" && hasAudio,
|
||||||
reject("Local description is not defined");
|
offerToReceiveVideo:
|
||||||
}
|
this.configuration.mode !== "sendonly" && hasVideo,
|
||||||
})
|
};
|
||||||
.catch((error) => reject(error));
|
|
||||||
});
|
logger.debug("RTCPeerConnection.createOffer() options:", JSON.stringify(options));
|
||||||
|
|
||||||
|
// @ts-ignore: Compiler is too clever and thinks this branch
|
||||||
|
// will never execute.
|
||||||
|
promise = this.pc.createOffer(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
return promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -224,24 +161,32 @@ export class WebRtcPeer {
|
||||||
* Only if the negotiation was initiated by the other peer
|
* Only if the negotiation was initiated by the other peer
|
||||||
*/
|
*/
|
||||||
createAnswer(): Promise<RTCSessionDescriptionInit> {
|
createAnswer(): Promise<RTCSessionDescriptionInit> {
|
||||||
return new Promise((resolve, reject) => {
|
const hasAudio = this.configuration.mediaConstraints.audio;
|
||||||
let offerAudio, offerVideo = true;
|
const hasVideo = this.configuration.mediaConstraints.video;
|
||||||
if (!!this.configuration.mediaConstraints) {
|
|
||||||
offerAudio = (typeof this.configuration.mediaConstraints.audio === 'boolean') ?
|
let promise: Promise<RTCSessionDescriptionInit>;
|
||||||
this.configuration.mediaConstraints.audio : true;
|
|
||||||
offerVideo = (typeof this.configuration.mediaConstraints.video === 'boolean') ?
|
// TODO: Delete this conditional when all supported browsers are
|
||||||
this.configuration.mediaConstraints.video : true;
|
// modern enough to implement the Transceiver methods.
|
||||||
|
if ("addTransceiver" in this.pc) {
|
||||||
|
logger.debug("[createAnswer] Method RTCPeerConnection.addTransceiver() is available; using it");
|
||||||
|
|
||||||
|
if (hasAudio) {
|
||||||
|
this.pc.addTransceiver("audio", {
|
||||||
|
direction: this.configuration.mode,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
const constraints: RTCOfferOptions = {
|
if (hasVideo) {
|
||||||
offerToReceiveAudio: offerAudio,
|
this.pc.addTransceiver("video", {
|
||||||
offerToReceiveVideo: offerVideo
|
direction: this.configuration.mode,
|
||||||
};
|
});
|
||||||
this.pc.createAnswer(constraints).then(sdpAnswer => {
|
}
|
||||||
resolve(sdpAnswer);
|
}
|
||||||
}).catch(error => {
|
|
||||||
reject(error);
|
// else, there is nothing to do; the legacy createAnswer() options do
|
||||||
});
|
// not offer any control over what tracks are included in the answer.
|
||||||
});
|
|
||||||
|
return this.pc.createAnswer();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -363,12 +308,12 @@ export class WebRtcPeer {
|
||||||
switch (iceConnectionState) {
|
switch (iceConnectionState) {
|
||||||
case 'disconnected':
|
case 'disconnected':
|
||||||
// Possible network disconnection
|
// Possible network disconnection
|
||||||
const msg1 = 'IceConnectionState of RTCPeerConnection ' + this.id + ' (' + otherId + ') change to "disconnected". Possible network disconnection';
|
const msg1 = 'IceConnectionState of RTCPeerConnection ' + this.configuration.id + ' (' + otherId + ') change to "disconnected". Possible network disconnection';
|
||||||
logger.warn(msg1);
|
logger.warn(msg1);
|
||||||
this.configuration.onexception(ExceptionEventName.ICE_CONNECTION_DISCONNECTED, msg1);
|
this.configuration.onexception(ExceptionEventName.ICE_CONNECTION_DISCONNECTED, msg1);
|
||||||
break;
|
break;
|
||||||
case 'failed':
|
case 'failed':
|
||||||
const msg2 = 'IceConnectionState of RTCPeerConnection ' + this.id + ' (' + otherId + ') to "failed"';
|
const msg2 = 'IceConnectionState of RTCPeerConnection ' + this.configuration.id + ' (' + otherId + ') to "failed"';
|
||||||
logger.error(msg2);
|
logger.error(msg2);
|
||||||
this.configuration.onexception(ExceptionEventName.ICE_CONNECTION_FAILED, msg2);
|
this.configuration.onexception(ExceptionEventName.ICE_CONNECTION_FAILED, msg2);
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in New Issue