Подготовить обычный звонок к позднему апгрейду в видео

This commit is contained in:
AidarKC
2026-08-11 12:43:17 +04:00
parent 3fdd3d22e2
commit e047c2d54e
2 changed files with 52 additions and 9 deletions
+51 -8
View File
@@ -57,6 +57,7 @@ const CALL_MODE_AUDIO = 'audio';
const CALL_MODE_VIDEO = 'video';
const CALL_MODE_INSTANT_VIDEO = 'instant_video';
const VIDEO_TRANSPORT_NONE = 'none';
const VIDEO_TRANSPORT_RESERVED = 'reserved';
const VIDEO_TRANSPORT_SLOT = 'slot';
function nowMs() {
@@ -116,7 +117,7 @@ function normalizeCallMode(mode) {
}
function getVideoTransportModeForCallMode(mode) {
return normalizeCallMode(mode) === CALL_MODE_AUDIO ? VIDEO_TRANSPORT_NONE : VIDEO_TRANSPORT_SLOT;
return normalizeCallMode(mode) === CALL_MODE_AUDIO ? VIDEO_TRANSPORT_RESERVED : VIDEO_TRANSPORT_SLOT;
}
function isInstantVideoMode(mode) {
@@ -1756,6 +1757,8 @@ async function ensurePeerConnection(call) {
} else {
ensureReservedVideoTransceiver(call);
}
} else if (call.videoTransportMode === VIDEO_TRANSPORT_RESERVED) {
ensureReservedVideoTransceiver(call);
}
} catch (e) {
setStatus(call, `Нет доступа к микрофону: ${e?.message || 'unknown'}`, 'failed');
@@ -1857,7 +1860,7 @@ async function onAccept(call) {
try {
await notifyPeerSessionsAboutConnectStart(call);
const pc = await ensurePeerConnection(call);
if (call.videoTransportMode === VIDEO_TRANSPORT_SLOT) {
if (call.videoTransportMode === VIDEO_TRANSPORT_SLOT || call.videoTransportMode === VIDEO_TRANSPORT_RESERVED) {
ensureReservedVideoTransceiver(call);
}
if (call.autoEnableCameraOnConnect && call.cameraEnabled) {
@@ -2176,6 +2179,7 @@ async function applyCameraState(call) {
if (!call?.pc) return false;
const pc = call.pc;
const hadSlotBefore = call.videoTransportMode === VIDEO_TRANSPORT_SLOT;
const hadReservedBefore = call.videoTransportMode === VIDEO_TRANSPORT_RESERVED;
let videoTransceiver = call.videoTransceiver || null;
if (!videoTransceiver) {
const transceivers = pc.getTransceivers?.() || [];
@@ -2208,6 +2212,31 @@ async function applyCameraState(call) {
await applyVideoSenderEncodingProfile(sender, 'camera');
}
videoTrack.enabled = true;
} else if (hadReservedBefore) {
const videoTrack = await ensureCameraTrack(call);
if (!videoTransceiver) {
videoTransceiver = ensureReservedVideoTransceiver(call);
call.videoTransceiver = videoTransceiver;
call.videoSender = videoTransceiver?.sender || call.videoSender || null;
}
try {
if (videoTransceiver && videoTransceiver.direction !== 'sendrecv') {
videoTransceiver.direction = 'sendrecv';
}
} catch {}
if (videoTransceiver?.sender) {
await videoTransceiver.sender.replaceTrack(videoTrack);
call.videoSender = videoTransceiver.sender;
bindVideoSenderStream(call, videoTransceiver.sender);
await applyVideoSenderEncodingProfile(videoTransceiver.sender, 'camera');
} else {
const sender = pc.addTrack(videoTrack, call.localStream);
call.videoSender = sender;
bindVideoSenderStream(call, sender);
await applyVideoSenderEncodingProfile(sender, 'camera');
}
call.videoTransportMode = VIDEO_TRANSPORT_SLOT;
videoTrack.enabled = true;
} else {
call.videoTransportMode = VIDEO_TRANSPORT_SLOT;
const videoTrack = await ensureCameraTrack(call);
@@ -2254,14 +2283,17 @@ async function applyCameraState(call) {
videoTransceiver.direction = 'sendrecv';
}
} catch {}
if (call.videoTransportMode === VIDEO_TRANSPORT_SLOT && blackTrack) {
if (hadReservedBefore && videoTransceiver?.sender) {
try { await videoTransceiver.sender.replaceTrack(null); } catch {}
call.videoSender = videoTransceiver.sender;
} else if (call.videoTransportMode === VIDEO_TRANSPORT_SLOT && blackTrack) {
await ensureVideoSenderSlot(call, { sourceTrack: blackTrack, profile: 'placeholder' });
}
}
await disableCameraTrack(call);
}
notifyCallState();
if (!hadSlotBefore && call.videoTransportMode === VIDEO_TRANSPORT_SLOT && !refreshVideoSlotReady(call)) {
if (!hadSlotBefore && !hadReservedBefore && call.videoTransportMode === VIDEO_TRANSPORT_SLOT && !refreshVideoSlotReady(call)) {
await renegotiateCall(call, 'upgrade_to_video_slot');
}
return true;
@@ -2784,9 +2816,18 @@ export async function handleIncomingCallSignal(evt) {
}
await pc.setRemoteDescription(incomingOffer);
if (hasVideoSectionInSdp(incomingOffer?.sdp || '')) {
call.videoTransportMode = VIDEO_TRANSPORT_SLOT;
ensureReservedVideoTransceiver(call);
if (!call.videoSender) {
if (call.videoTransportMode === VIDEO_TRANSPORT_SLOT) {
ensureReservedVideoTransceiver(call);
if (!call.videoSender) {
await ensureVideoSenderSlot(call, { sourceTrack: ensureBlackVideoTrack(call), profile: 'placeholder' });
}
} else if (call.videoTransportMode === VIDEO_TRANSPORT_RESERVED) {
ensureReservedVideoTransceiver(call);
} else {
call.videoTransportMode = VIDEO_TRANSPORT_RESERVED;
ensureReservedVideoTransceiver(call);
}
if (call.videoTransportMode === VIDEO_TRANSPORT_SLOT && !call.videoSender) {
await ensureVideoSenderSlot(call, { sourceTrack: ensureBlackVideoTrack(call), profile: 'placeholder' });
}
if (call.autoEnableCameraOnConnect && call.cameraEnabled) {
@@ -2833,7 +2874,9 @@ export async function handleIncomingCallSignal(evt) {
}
await pc.setRemoteDescription(new RTCSessionDescription(JSON.parse(data)));
if (hasVideoSectionInSdp(pc.remoteDescription?.sdp || '')) {
call.videoTransportMode = VIDEO_TRANSPORT_SLOT;
if (!call.videoTransportMode || call.videoTransportMode === VIDEO_TRANSPORT_NONE) {
call.videoTransportMode = VIDEO_TRANSPORT_RESERVED;
}
ensureReservedVideoTransceiver(call);
}
syncRemoteReceiverVideoTracks(call);