Fix simulcast
parent
7a884edcdd
commit
c424ffc17c
|
|
@ -83,11 +83,28 @@ const VIDEO_CONSTRAINS =
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const VIDEO_ENCODINGS =
|
const PC_PROPRIETARY_CONSTRAINTS =
|
||||||
|
{
|
||||||
|
optional : [ { googDscp: true } ]
|
||||||
|
};
|
||||||
|
|
||||||
|
const VIDEO_SIMULCAST_ENCODINGS =
|
||||||
[
|
[
|
||||||
{ maxBitrate: 180000, scaleResolutionDownBy: 4 },
|
{ scaleResolutionDownBy: 4 },
|
||||||
{ maxBitrate: 360000, scaleResolutionDownBy: 2 },
|
{ scaleResolutionDownBy: 2 },
|
||||||
{ maxBitrate: 1500000, scaleResolutionDownBy: 1 }
|
{ scaleResolutionDownBy: 1 }
|
||||||
|
];
|
||||||
|
|
||||||
|
// Used for VP9 webcam video.
|
||||||
|
const VIDEO_KSVC_ENCODINGS =
|
||||||
|
[
|
||||||
|
{ scalabilityMode: 'S3T3_KEY' }
|
||||||
|
];
|
||||||
|
|
||||||
|
// Used for VP9 desktop sharing.
|
||||||
|
const VIDEO_SVC_ENCODINGS =
|
||||||
|
[
|
||||||
|
{ scalabilityMode: 'S3T3', dtx: true }
|
||||||
];
|
];
|
||||||
|
|
||||||
let store;
|
let store;
|
||||||
|
|
@ -108,7 +125,7 @@ export default class RoomClient
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
{ peerId, accessCode, device, useSimulcast, produce, forceTcp, displayName, muted } = {})
|
{ peerId, accessCode, device, useSimulcast, useSharingSimulcast, produce, forceTcp, displayName, muted } = {})
|
||||||
{
|
{
|
||||||
if (!peerId)
|
if (!peerId)
|
||||||
throw new Error('Missing peerId');
|
throw new Error('Missing peerId');
|
||||||
|
|
@ -140,6 +157,9 @@ export default class RoomClient
|
||||||
// Whether simulcast should be used.
|
// Whether simulcast should be used.
|
||||||
this._useSimulcast = useSimulcast;
|
this._useSimulcast = useSimulcast;
|
||||||
|
|
||||||
|
// Whether simulcast should be used for sharing
|
||||||
|
this._useSharingSimulcast = useSharingSimulcast;
|
||||||
|
|
||||||
this._muted = muted;
|
this._muted = muted;
|
||||||
|
|
||||||
// This device
|
// This device
|
||||||
|
|
@ -1235,7 +1255,7 @@ export default class RoomClient
|
||||||
{
|
{
|
||||||
if (this._webcamProducer)
|
if (this._webcamProducer)
|
||||||
await this._webcamProducer.setMaxSpatialLayer(spatialLayer);
|
await this._webcamProducer.setMaxSpatialLayer(spatialLayer);
|
||||||
else if (this._screenSharingProducer)
|
if (this._screenSharingProducer)
|
||||||
await this._screenSharingProducer.setMaxSpatialLayer(spatialLayer);
|
await this._screenSharingProducer.setMaxSpatialLayer(spatialLayer);
|
||||||
}
|
}
|
||||||
catch (error)
|
catch (error)
|
||||||
|
|
@ -1264,6 +1284,38 @@ export default class RoomClient
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async setConsumerPriority(consumerId, priority)
|
||||||
|
{
|
||||||
|
logger.debug(
|
||||||
|
'setConsumerPriority() [consumerId:%s, priority:%d]',
|
||||||
|
consumerId, priority);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await this.sendRequest('setConsumerPriority', { consumerId, priority });
|
||||||
|
|
||||||
|
store.dispatch(consumerActions.setConsumerPriority(consumerId, priority));
|
||||||
|
}
|
||||||
|
catch (error)
|
||||||
|
{
|
||||||
|
logger.error('setConsumerPriority() | failed:%o', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async requestConsumerKeyFrame(consumerId)
|
||||||
|
{
|
||||||
|
logger.debug('requestConsumerKeyFrame() [consumerId:%s]', consumerId);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await this.sendRequest('requestConsumerKeyFrame', { consumerId });
|
||||||
|
}
|
||||||
|
catch (error)
|
||||||
|
{
|
||||||
|
logger.error('requestConsumerKeyFrame() | failed:%o', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async _loadDynamicImports()
|
async _loadDynamicImports()
|
||||||
{
|
{
|
||||||
({ default: WebTorrent } = await import(
|
({ default: WebTorrent } = await import(
|
||||||
|
|
@ -1481,6 +1533,7 @@ export default class RoomClient
|
||||||
temporalLayers : temporalLayers,
|
temporalLayers : temporalLayers,
|
||||||
preferredSpatialLayer : spatialLayers - 1,
|
preferredSpatialLayer : spatialLayers - 1,
|
||||||
preferredTemporalLayer : temporalLayers - 1,
|
preferredTemporalLayer : temporalLayers - 1,
|
||||||
|
priority : 1,
|
||||||
codec : consumer.rtpParameters.codecs[0].mimeType.split('/')[1],
|
codec : consumer.rtpParameters.codecs[0].mimeType.split('/')[1],
|
||||||
track : consumer.track
|
track : consumer.track
|
||||||
},
|
},
|
||||||
|
|
@ -1849,10 +1902,10 @@ export default class RoomClient
|
||||||
|
|
||||||
case 'newPeer':
|
case 'newPeer':
|
||||||
{
|
{
|
||||||
const { id, displayName, picture, device } = notification.data;
|
const { id, displayName, picture } = notification.data;
|
||||||
|
|
||||||
store.dispatch(
|
store.dispatch(
|
||||||
peerActions.addPeer({ id, displayName, picture, device, consumers: [] }));
|
peerActions.addPeer({ id, displayName, picture, consumers: [] }));
|
||||||
|
|
||||||
store.dispatch(requestActions.notify(
|
store.dispatch(requestActions.notify(
|
||||||
{
|
{
|
||||||
|
|
@ -2017,7 +2070,8 @@ export default class RoomClient
|
||||||
iceParameters,
|
iceParameters,
|
||||||
iceCandidates,
|
iceCandidates,
|
||||||
dtlsParameters,
|
dtlsParameters,
|
||||||
iceServers : ROOM_OPTIONS.turnServers
|
iceServers : ROOM_OPTIONS.turnServers,
|
||||||
|
proprietaryConstraints : PC_PROPRIETARY_CONSTRAINTS
|
||||||
});
|
});
|
||||||
|
|
||||||
this._sendTransport.on(
|
this._sendTransport.on(
|
||||||
|
|
@ -2034,18 +2088,26 @@ export default class RoomClient
|
||||||
});
|
});
|
||||||
|
|
||||||
this._sendTransport.on(
|
this._sendTransport.on(
|
||||||
'produce', ({ kind, rtpParameters, appData }, callback, errback) =>
|
'produce', async ({ kind, rtpParameters, appData }, callback, errback) =>
|
||||||
{
|
{
|
||||||
this.sendRequest(
|
try
|
||||||
'produce',
|
{
|
||||||
{
|
// eslint-disable-next-line no-shadow
|
||||||
transportId : this._sendTransport.id,
|
const { id } = await this.sendRequest(
|
||||||
kind,
|
'produce',
|
||||||
rtpParameters,
|
{
|
||||||
appData
|
transportId : this._sendTransport.id,
|
||||||
})
|
kind,
|
||||||
.then(callback)
|
rtpParameters,
|
||||||
.catch(errback);
|
appData
|
||||||
|
});
|
||||||
|
|
||||||
|
callback({ id });
|
||||||
|
}
|
||||||
|
catch (error)
|
||||||
|
{
|
||||||
|
errback(error);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2496,12 +2558,30 @@ export default class RoomClient
|
||||||
|
|
||||||
track = stream.getVideoTracks()[0];
|
track = stream.getVideoTracks()[0];
|
||||||
|
|
||||||
if (this._useSimulcast)
|
if (this._useSharingSimulcast)
|
||||||
{
|
{
|
||||||
|
// If VP9 is the only available video codec then use SVC.
|
||||||
|
const firstVideoCodec = this._mediasoupDevice
|
||||||
|
.rtpCapabilities
|
||||||
|
.codecs
|
||||||
|
.find((c) => c.kind === 'video');
|
||||||
|
|
||||||
|
let encodings;
|
||||||
|
|
||||||
|
if (firstVideoCodec.mimeType.toLowerCase() === 'video/vp9')
|
||||||
|
{
|
||||||
|
encodings = VIDEO_SVC_ENCODINGS;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
encodings = VIDEO_SIMULCAST_ENCODINGS
|
||||||
|
.map((encoding) => ({ ...encoding, dtx: true }));
|
||||||
|
}
|
||||||
|
|
||||||
this._screenSharingProducer = await this._sendTransport.produce(
|
this._screenSharingProducer = await this._sendTransport.produce(
|
||||||
{
|
{
|
||||||
track,
|
track,
|
||||||
encodings : VIDEO_ENCODINGS,
|
encodings,
|
||||||
codecOptions :
|
codecOptions :
|
||||||
{
|
{
|
||||||
videoGoogleStartBitrate : 1000
|
videoGoogleStartBitrate : 1000
|
||||||
|
|
@ -2652,10 +2732,23 @@ export default class RoomClient
|
||||||
|
|
||||||
if (this._useSimulcast)
|
if (this._useSimulcast)
|
||||||
{
|
{
|
||||||
|
// If VP9 is the only available video codec then use SVC.
|
||||||
|
const firstVideoCodec = this._mediasoupDevice
|
||||||
|
.rtpCapabilities
|
||||||
|
.codecs
|
||||||
|
.find((c) => c.kind === 'video');
|
||||||
|
|
||||||
|
let encodings;
|
||||||
|
|
||||||
|
if (firstVideoCodec.mimeType.toLowerCase() === 'video/vp9')
|
||||||
|
encodings = VIDEO_KSVC_ENCODINGS;
|
||||||
|
else
|
||||||
|
encodings = VIDEO_SIMULCAST_ENCODINGS;
|
||||||
|
|
||||||
this._webcamProducer = await this._sendTransport.produce(
|
this._webcamProducer = await this._sendTransport.produce(
|
||||||
{
|
{
|
||||||
track,
|
track,
|
||||||
encodings : VIDEO_ENCODINGS,
|
encodings,
|
||||||
codecOptions :
|
codecOptions :
|
||||||
{
|
{
|
||||||
videoGoogleStartBitrate : 1000
|
videoGoogleStartBitrate : 1000
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,14 @@ export const setConsumerPreferredLayers = (consumerId, spatialLayer, temporalLay
|
||||||
payload : { consumerId, spatialLayer, temporalLayer }
|
payload : { consumerId, spatialLayer, temporalLayer }
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const setConsumerPriority = (consumerId, priority) =>
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
type : 'SET_CONSUMER_PRIORITY',
|
||||||
|
payload : { consumerId, priority }
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export const setConsumerTrack = (consumerId, track) =>
|
export const setConsumerTrack = (consumerId, track) =>
|
||||||
({
|
({
|
||||||
type : 'SET_CONSUMER_TRACK',
|
type : 'SET_CONSUMER_TRACK',
|
||||||
|
|
|
||||||
|
|
@ -102,7 +102,8 @@ function run()
|
||||||
|
|
||||||
const accessCode = parameters.get('code');
|
const accessCode = parameters.get('code');
|
||||||
const produce = parameters.get('produce') !== 'false';
|
const produce = parameters.get('produce') !== 'false';
|
||||||
const useSimulcast = parameters.get('simulcast') === 'true';
|
const useSimulcast = parameters.get('simulcast') !== 'false';
|
||||||
|
const useSharingSimulcast = parameters.get('sharingSimulcast') === 'true';
|
||||||
const forceTcp = parameters.get('forceTcp') === 'true';
|
const forceTcp = parameters.get('forceTcp') === 'true';
|
||||||
const displayName = parameters.get('displayName');
|
const displayName = parameters.get('displayName');
|
||||||
const muted = parameters.get('muted') === 'true';
|
const muted = parameters.get('muted') === 'true';
|
||||||
|
|
@ -118,7 +119,17 @@ function run()
|
||||||
);
|
);
|
||||||
|
|
||||||
roomClient = new RoomClient(
|
roomClient = new RoomClient(
|
||||||
{ peerId, accessCode, device, useSimulcast, produce, forceTcp, displayName, muted });
|
{
|
||||||
|
peerId,
|
||||||
|
accessCode,
|
||||||
|
device,
|
||||||
|
useSimulcast,
|
||||||
|
useSharingSimulcast,
|
||||||
|
produce,
|
||||||
|
forceTcp,
|
||||||
|
displayName,
|
||||||
|
muted
|
||||||
|
});
|
||||||
|
|
||||||
global.CLIENT = roomClient;
|
global.CLIENT = roomClient;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -79,6 +79,15 @@ const consumers = (state = initialState, action) =>
|
||||||
return { ...state, [consumerId]: newConsumer };
|
return { ...state, [consumerId]: newConsumer };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case 'SET_CONSUMER_PRIORITY':
|
||||||
|
{
|
||||||
|
const { consumerId, priority } = action.payload;
|
||||||
|
const consumer = state[consumerId];
|
||||||
|
const newConsumer = { ...consumer, priority };
|
||||||
|
|
||||||
|
return { ...state, [consumerId]: newConsumer };
|
||||||
|
}
|
||||||
|
|
||||||
case 'SET_CONSUMER_TRACK':
|
case 'SET_CONSUMER_TRACK':
|
||||||
{
|
{
|
||||||
const { consumerId, track } = action.payload;
|
const { consumerId, track } = action.payload;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue