mediasoup-client
Advanced tools
Comparing version 0.6.4 to 0.6.5
@@ -176,9 +176,6 @@ import sdpTransform from 'sdp-transform'; | ||
// NOTE: If there are no sending tracks, setLocalDescription() will cause | ||
// Firefox to close DTLS. So for now, let's avoid such a SDP O/A and leave | ||
// at least a fake-active sending track. | ||
// NOTE: This does not fix the problem. | ||
// Firefox to close DTLS. This is fixed for the receiving PeerConnection | ||
// (by adding a fake DataChannel) but not for the sending one. | ||
// | ||
// ISSUE: https://github.com/versatica/mediasoup-client/issues/2 | ||
// if (this._stream.getTracks().length === 0) | ||
// return; | ||
return Promise.resolve() | ||
@@ -190,7 +187,2 @@ .then(() => this._pc.createOffer()) | ||
{ | ||
// TODO: This may be removed. | ||
// ISSUE: https://github.com/versatica/mediasoup-client/issues/2 | ||
// if (this._pc.signalingState === 'stable') | ||
// return; | ||
const localSdpObj = sdpTransform.parse(this._pc.localDescription.sdp); | ||
@@ -319,2 +311,17 @@ const remoteSdp = this._remoteSdp.createAnswerSdp(localSdpObj); | ||
this._consumerInfos = new Map(); | ||
// Add an entry into consumers info to hold a fake DataChannel, so | ||
// the first m= section of the remote SDP is always "active" and Firefox | ||
// does not close the transport when there is no remote audio/video Consumers. | ||
// | ||
// ISSUE: https://github.com/versatica/mediasoup-client/issues/2 | ||
const fakeDataChannelConsumerInfo = | ||
{ | ||
mid : 'fake-datachannel-consumer', | ||
kind : 'application', | ||
closed : false, | ||
cname : null | ||
}; | ||
this._consumerInfos.set(555, fakeDataChannelConsumerInfo); | ||
} | ||
@@ -396,5 +403,2 @@ | ||
{ | ||
// TODO: If this is the last active Consumer, Firefox will close the DTLS. | ||
// This is noted in the TODO.md file. | ||
logger.debug( | ||
@@ -401,0 +405,0 @@ 'removeConsumer() [id:%s, kind:%s]', consumer.id, consumer.kind); |
@@ -355,12 +355,30 @@ import sdpTransform from 'sdp-transform'; | ||
const kind = info.kind; | ||
const codecs = this._rtpParametersByKind[kind].codecs; | ||
const headerExtensions = this._rtpParametersByKind[kind].headerExtensions; | ||
let codecs; | ||
let headerExtensions; | ||
if (info.kind !== 'application') | ||
{ | ||
codecs = this._rtpParametersByKind[kind].codecs; | ||
headerExtensions = this._rtpParametersByKind[kind].headerExtensions; | ||
} | ||
const remoteMediaObj = {}; | ||
remoteMediaObj.type = kind; | ||
remoteMediaObj.port = 7; | ||
remoteMediaObj.protocol = 'RTP/SAVPF'; | ||
remoteMediaObj.connection = { ip: '127.0.0.1', version: 4 }; | ||
remoteMediaObj.mid = info.mid; | ||
remoteMediaObj.msid = `${this._streamId} ${info.trackId}`; | ||
if (info.kind !== 'application') | ||
{ | ||
remoteMediaObj.type = kind; | ||
remoteMediaObj.port = 7; | ||
remoteMediaObj.protocol = 'RTP/SAVPF'; | ||
remoteMediaObj.connection = { ip: '127.0.0.1', version: 4 }; | ||
remoteMediaObj.mid = info.mid; | ||
remoteMediaObj.msid = `${this._streamId} ${info.trackId}`; | ||
} | ||
else | ||
{ | ||
remoteMediaObj.type = kind; | ||
remoteMediaObj.port = 9; | ||
remoteMediaObj.protocol = 'DTLS/SCTP'; | ||
remoteMediaObj.connection = { ip: '127.0.0.1', version: 4 }; | ||
remoteMediaObj.mid = info.mid; | ||
} | ||
@@ -398,98 +416,91 @@ remoteMediaObj.iceUfrag = remoteIceParameters.usernameFragment; | ||
if (!closed) | ||
remoteMediaObj.direction = 'sendonly'; | ||
else | ||
remoteMediaObj.direction = 'inactive'; | ||
remoteMediaObj.rtp = []; | ||
remoteMediaObj.rtcpFb = []; | ||
remoteMediaObj.fmtp = []; | ||
for (const codec of codecs) | ||
if (info.kind !== 'application') | ||
{ | ||
const rtp = | ||
{ | ||
payload : codec.payloadType, | ||
codec : codec.name, | ||
rate : codec.clockRate | ||
}; | ||
if (!closed) | ||
remoteMediaObj.direction = 'sendonly'; | ||
else | ||
remoteMediaObj.direction = 'inactive'; | ||
if (codec.channels > 1) | ||
rtp.encoding = codec.channels; | ||
remoteMediaObj.rtp = []; | ||
remoteMediaObj.rtcpFb = []; | ||
remoteMediaObj.fmtp = []; | ||
remoteMediaObj.rtp.push(rtp); | ||
if (codec.parameters) | ||
for (const codec of codecs) | ||
{ | ||
const paramFmtp = | ||
const rtp = | ||
{ | ||
payload : codec.payloadType, | ||
config : '' | ||
codec : codec.name, | ||
rate : codec.clockRate | ||
}; | ||
for (const key of Object.keys(codec.parameters)) | ||
if (codec.channels > 1) | ||
rtp.encoding = codec.channels; | ||
remoteMediaObj.rtp.push(rtp); | ||
if (codec.parameters) | ||
{ | ||
const paramFmtp = | ||
{ | ||
payload : codec.payloadType, | ||
config : '' | ||
}; | ||
for (const key of Object.keys(codec.parameters)) | ||
{ | ||
if (paramFmtp.config) | ||
paramFmtp.config += ';'; | ||
paramFmtp.config += `${key}=${codec.parameters[key]}`; | ||
} | ||
if (paramFmtp.config) | ||
paramFmtp.config += ';'; | ||
remoteMediaObj.fmtp.push(paramFmtp); | ||
} | ||
paramFmtp.config += `${key}=${codec.parameters[key]}`; | ||
if (codec.rtcpFeedback) | ||
{ | ||
for (const fb of codec.rtcpFeedback) | ||
{ | ||
remoteMediaObj.rtcpFb.push( | ||
{ | ||
payload : codec.payloadType, | ||
type : fb.type, | ||
subtype : fb.parameter || '' | ||
}); | ||
} | ||
} | ||
if (paramFmtp.config) | ||
remoteMediaObj.fmtp.push(paramFmtp); | ||
} | ||
if (codec.rtcpFeedback) | ||
remoteMediaObj.payloads = codecs | ||
.map((codec) => codec.payloadType) | ||
.join(' '); | ||
// NOTE: Firefox does not like a=extmap lines if a=inactive. | ||
if (!closed) | ||
{ | ||
for (const fb of codec.rtcpFeedback) | ||
remoteMediaObj.ext = []; | ||
for (const ext of headerExtensions) | ||
{ | ||
remoteMediaObj.rtcpFb.push( | ||
remoteMediaObj.ext.push( | ||
{ | ||
payload : codec.payloadType, | ||
type : fb.type, | ||
subtype : fb.parameter || '' | ||
uri : ext.uri, | ||
value : ext.id | ||
}); | ||
} | ||
} | ||
} | ||
remoteMediaObj.payloads = codecs | ||
.map((codec) => codec.payloadType) | ||
.join(' '); | ||
remoteMediaObj.rtcpMux = 'rtcp-mux'; | ||
remoteMediaObj.rtcpRsize = 'rtcp-rsize'; | ||
// NOTE: Firefox does not like a=extmap lines if a=inactive. | ||
if (!closed) | ||
{ | ||
remoteMediaObj.ext = []; | ||
for (const ext of headerExtensions) | ||
if (!closed) | ||
{ | ||
remoteMediaObj.ext.push( | ||
{ | ||
uri : ext.uri, | ||
value : ext.id | ||
}); | ||
} | ||
} | ||
remoteMediaObj.ssrcs = []; | ||
remoteMediaObj.ssrcGroups = []; | ||
remoteMediaObj.rtcpMux = 'rtcp-mux'; | ||
remoteMediaObj.rtcpRsize = 'rtcp-rsize'; | ||
if (!closed) | ||
{ | ||
remoteMediaObj.ssrcs = []; | ||
remoteMediaObj.ssrcGroups = []; | ||
remoteMediaObj.ssrcs.push( | ||
{ | ||
id : info.ssrc, | ||
attribute : 'cname', | ||
value : info.cname | ||
}); | ||
if (info.rtxSsrc) | ||
{ | ||
remoteMediaObj.ssrcs.push( | ||
{ | ||
id : info.rtxSsrc, | ||
id : info.ssrc, | ||
attribute : 'cname', | ||
@@ -499,10 +510,30 @@ value : info.cname | ||
// Associate original and retransmission SSRC. | ||
remoteMediaObj.ssrcGroups.push( | ||
{ | ||
semantics : 'FID', | ||
ssrcs : `${info.ssrc} ${info.rtxSsrc}` | ||
}); | ||
if (info.rtxSsrc) | ||
{ | ||
remoteMediaObj.ssrcs.push( | ||
{ | ||
id : info.rtxSsrc, | ||
attribute : 'cname', | ||
value : info.cname | ||
}); | ||
// Associate original and retransmission SSRC. | ||
remoteMediaObj.ssrcGroups.push( | ||
{ | ||
semantics : 'FID', | ||
ssrcs : `${info.ssrc} ${info.rtxSsrc}` | ||
}); | ||
} | ||
} | ||
} | ||
else | ||
{ | ||
remoteMediaObj.payloads = 5000; | ||
remoteMediaObj.sctpmap = | ||
{ | ||
app : 'webrtc-datachannel', | ||
maxMessageSize : 256, | ||
sctpmapNumber : 5000 | ||
}; | ||
} | ||
@@ -509,0 +540,0 @@ // Push it. |
{ | ||
"name": "mediasoup-client", | ||
"version": "0.6.4", | ||
"version": "0.6.5", | ||
"description": "mediasoup client SDK for mediasoup >= 2.0.0", | ||
@@ -5,0 +5,0 @@ "author": "Iñaki Baz Castillo <ibc@aliax.net> (https://inakibaz.me)", |
@@ -5,3 +5,3 @@ # mediasoup-client | ||
**NOTE:** Work in progress. See the roadmap for [mediasoup 2.0.0](https://github.com/versatica/mediasoup/milestone/2). | ||
**NOTE:** Work in progress. See the roadmap for [mediasoup v2](https://github.com/versatica/mediasoup/milestone/2). | ||
@@ -8,0 +8,0 @@ |
181528
6361