in src/task/ReceiveVideoInputTask.ts [18:101]
async run(): Promise<void> {
// TODO: move videoDuplexMode and videoCaptureAndEncodeParameters to video tile controller
const receiveEnabled =
this.context.videoDuplexMode === SdkStreamServiceType.RX ||
this.context.videoDuplexMode === SdkStreamServiceType.DUPLEX;
if (this.context.videoTileController.hasStartedLocalVideoTile()) {
this.context.videoDuplexMode = receiveEnabled
? SdkStreamServiceType.DUPLEX
: SdkStreamServiceType.TX;
} else {
this.context.videoDuplexMode = receiveEnabled ? SdkStreamServiceType.RX : 0;
}
this.context.videoCaptureAndEncodeParameter = this.context.videoUplinkBandwidthPolicy.chooseCaptureAndEncodeParameters();
if (!this.context.videoTileController.hasStartedLocalVideoTile()) {
this.context.logger.info('has not started local video tile');
if (this.context.activeVideoInput) {
this.stopVideoInput();
// Indicate to the stream index that we are no longer sending video. We will
// no longer be tracking irrelevant local sending bitrates sent via received Bitrate message, nor will
// we track any spurious allocated stream IDs from the backend.
this.context.videoStreamIndex.integrateUplinkPolicyDecision([]);
}
return;
}
// TODO: bind after ICE connection started in case of a failure to resubscribe
// or perform error handling to unbind video stream.
const localTile = this.context.videoTileController.getLocalVideoTile();
let videoInput: MediaStream | null = null;
try {
videoInput = await this.context.mediaStreamBroker.acquireVideoInputStream();
} catch (error) {
this.context.logger.warn('could not acquire video input from current device');
}
if (this.context.enableSimulcast) {
const encodingParams = this.context.videoUplinkBandwidthPolicy.chooseEncodingParameters();
this.context.videoStreamIndex.integrateUplinkPolicyDecision(
Array.from(encodingParams.values())
);
}
this.context.activeVideoInput = videoInput;
if (videoInput) {
const videoTracks = videoInput.getVideoTracks();
// There can be a race condition when there are several audioVideo.update calls (e.g., calling
// startLocalVideoTile and stopLocalVideoTile at the same time)
// that causes the video stream to not contain any video track.
// This should recovers in the next update call.
if (!videoTracks || videoTracks.length === 0) {
return;
}
const attendeeId = this.context.meetingSessionConfiguration.credentials.attendeeId;
const trackSettings = videoTracks[0].getSettings();
if (this.context.enableSimulcast) {
const constraint = this.context.videoUplinkBandwidthPolicy.chooseMediaTrackConstraints();
this.context.logger.info(`simulcast: choose constraint ${JSON.stringify(constraint)}`);
try {
await videoTracks[0].applyConstraints(constraint);
} catch (error) {
this.context.logger.info('simulcast: pass video without more constraint');
}
}
const externalUserId = this.context.audioVideoController.configuration.credentials
.externalUserId;
localTile.bindVideoStream(
attendeeId,
true,
videoInput,
trackSettings.width,
trackSettings.height,
null,
externalUserId
);
for (let i = 0; i < videoTracks.length; i++) {
const track = videoTracks[i];
this.logger.info(`using video device label=${track.label} id=${track.id}`);
this.context.videoDeviceInformation['current_camera_name'] = track.label;
this.context.videoDeviceInformation['current_camera_id'] = track.id;
}
}
}