This commit is contained in:
@@ -304,6 +304,7 @@ export const useChatStore = defineStore('chat', () => {
|
|||||||
if (!navigator.mediaDevices?.getUserMedia) return null;
|
if (!navigator.mediaDevices?.getUserMedia) return null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
console.log('[video] getUserMedia:start');
|
||||||
const stream = await navigator.mediaDevices.getUserMedia({
|
const stream = await navigator.mediaDevices.getUserMedia({
|
||||||
video: {
|
video: {
|
||||||
facingMode: 'user',
|
facingMode: 'user',
|
||||||
@@ -312,12 +313,20 @@ export const useChatStore = defineStore('chat', () => {
|
|||||||
},
|
},
|
||||||
audio: true
|
audio: true
|
||||||
});
|
});
|
||||||
|
console.log('[video] getUserMedia:success', {
|
||||||
|
audioTracks: stream.getAudioTracks().length,
|
||||||
|
videoTracks: stream.getVideoTracks().length
|
||||||
|
});
|
||||||
selfPreviewStream.value = stream;
|
selfPreviewStream.value = stream;
|
||||||
selfMuted.value = false;
|
selfMuted.value = false;
|
||||||
selfCameraEnabled.value = true;
|
selfCameraEnabled.value = true;
|
||||||
return stream;
|
return stream;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Lokale Video-Vorschau konnte nicht gestartet werden:', error);
|
console.error('Lokale Video-Vorschau konnte nicht gestartet werden:', error);
|
||||||
|
console.error('[video] getUserMedia:error', {
|
||||||
|
name: error?.name,
|
||||||
|
message: error?.message
|
||||||
|
});
|
||||||
setTemporaryError('Lokale Kamera/Vorschau konnte nicht gestartet werden.');
|
setTemporaryError('Lokale Kamera/Vorschau konnte nicht gestartet werden.');
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -360,6 +369,12 @@ export const useChatStore = defineStore('chat', () => {
|
|||||||
bundlePolicy: 'max-bundle',
|
bundlePolicy: 'max-bundle',
|
||||||
rtcpMuxPolicy: 'require'
|
rtcpMuxPolicy: 'require'
|
||||||
});
|
});
|
||||||
|
console.log('[video] peer:create', {
|
||||||
|
callId: session.callId,
|
||||||
|
isCaller: !!session.media?.isCaller,
|
||||||
|
iceServers: session.media.iceServers || [],
|
||||||
|
iceTransportPolicy: session.media.iceTransportPolicy || 'relay'
|
||||||
|
});
|
||||||
|
|
||||||
const runtime = {
|
const runtime = {
|
||||||
pc,
|
pc,
|
||||||
@@ -374,6 +389,11 @@ export const useChatStore = defineStore('chat', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pc.ontrack = (event) => {
|
pc.ontrack = (event) => {
|
||||||
|
console.log('[video] peer:track', {
|
||||||
|
callId: session.callId,
|
||||||
|
streamCount: event.streams?.length || 0,
|
||||||
|
trackKind: event.track?.kind
|
||||||
|
});
|
||||||
const [stream] = event.streams || [];
|
const [stream] = event.streams || [];
|
||||||
if (stream) {
|
if (stream) {
|
||||||
setRemoteStream(session.callId, stream);
|
setRemoteStream(session.callId, stream);
|
||||||
@@ -389,6 +409,11 @@ export const useChatStore = defineStore('chat', () => {
|
|||||||
|
|
||||||
pc.onicecandidate = (event) => {
|
pc.onicecandidate = (event) => {
|
||||||
if (!event.candidate) return;
|
if (!event.candidate) return;
|
||||||
|
console.log('[video] peer:icecandidate', {
|
||||||
|
callId: session.callId,
|
||||||
|
type: event.candidate.type,
|
||||||
|
candidate: String(event.candidate.candidate || '').slice(0, 140)
|
||||||
|
});
|
||||||
emitVideoSignal(session.callId, 'candidate', {
|
emitVideoSignal(session.callId, 'candidate', {
|
||||||
candidate: event.candidate.toJSON()
|
candidate: event.candidate.toJSON()
|
||||||
});
|
});
|
||||||
@@ -396,6 +421,10 @@ export const useChatStore = defineStore('chat', () => {
|
|||||||
|
|
||||||
pc.onconnectionstatechange = () => {
|
pc.onconnectionstatechange = () => {
|
||||||
const state = pc.connectionState;
|
const state = pc.connectionState;
|
||||||
|
console.log('[video] peer:connectionstate', {
|
||||||
|
callId: session.callId,
|
||||||
|
state
|
||||||
|
});
|
||||||
if (state === 'connected' && runtime.connectTimeoutId) {
|
if (state === 'connected' && runtime.connectTimeoutId) {
|
||||||
window.clearTimeout(runtime.connectTimeoutId);
|
window.clearTimeout(runtime.connectTimeoutId);
|
||||||
runtime.connectTimeoutId = null;
|
runtime.connectTimeoutId = null;
|
||||||
@@ -406,6 +435,10 @@ export const useChatStore = defineStore('chat', () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
pc.oniceconnectionstatechange = () => {
|
pc.oniceconnectionstatechange = () => {
|
||||||
|
console.log('[video] peer:iceconnectionstate', {
|
||||||
|
callId: session.callId,
|
||||||
|
state: pc.iceConnectionState
|
||||||
|
});
|
||||||
if (pc.iceConnectionState === 'failed') {
|
if (pc.iceConnectionState === 'failed') {
|
||||||
emitConnectionState(session.callId, 'failed');
|
emitConnectionState(session.callId, 'failed');
|
||||||
}
|
}
|
||||||
@@ -435,11 +468,17 @@ export const useChatStore = defineStore('chat', () => {
|
|||||||
if (!runtime || runtime.offerCreated) return;
|
if (!runtime || runtime.offerCreated) return;
|
||||||
|
|
||||||
runtime.offerCreated = true;
|
runtime.offerCreated = true;
|
||||||
|
console.log('[video] offer:create', { callId: session.callId });
|
||||||
const offer = await runtime.pc.createOffer({
|
const offer = await runtime.pc.createOffer({
|
||||||
offerToReceiveAudio: true,
|
offerToReceiveAudio: true,
|
||||||
offerToReceiveVideo: true
|
offerToReceiveVideo: true
|
||||||
});
|
});
|
||||||
await runtime.pc.setLocalDescription(offer);
|
await runtime.pc.setLocalDescription(offer);
|
||||||
|
console.log('[video] offer:local-description-set', {
|
||||||
|
callId: session.callId,
|
||||||
|
type: offer.type,
|
||||||
|
sdpLength: String(offer.sdp || '').length
|
||||||
|
});
|
||||||
emitVideoSignal(session.callId, 'description', {
|
emitVideoSignal(session.callId, 'description', {
|
||||||
description: {
|
description: {
|
||||||
type: offer.type,
|
type: offer.type,
|
||||||
@@ -451,6 +490,11 @@ export const useChatStore = defineStore('chat', () => {
|
|||||||
async function startVideoMediaForSession(session) {
|
async function startVideoMediaForSession(session) {
|
||||||
if (!session?.media) return;
|
if (!session?.media) return;
|
||||||
try {
|
try {
|
||||||
|
console.log('[video] media:start', {
|
||||||
|
callId: session.callId,
|
||||||
|
status: session.status,
|
||||||
|
isCaller: !!session.media?.isCaller
|
||||||
|
});
|
||||||
const runtime = await ensurePeerConnectionForSession(session);
|
const runtime = await ensurePeerConnectionForSession(session);
|
||||||
if (runtime && !runtime.connectTimeoutId) {
|
if (runtime && !runtime.connectTimeoutId) {
|
||||||
runtime.connectTimeoutId = window.setTimeout(() => {
|
runtime.connectTimeoutId = window.setTimeout(() => {
|
||||||
@@ -479,16 +523,33 @@ export const useChatStore = defineStore('chat', () => {
|
|||||||
if (!session || !session.media) return;
|
if (!session || !session.media) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
console.log('[video] signal:incoming', {
|
||||||
|
callId,
|
||||||
|
signalType,
|
||||||
|
descriptionType: data.description?.type || null,
|
||||||
|
candidateType: data.candidate?.type || null
|
||||||
|
});
|
||||||
const runtime = await ensurePeerConnectionForSession(session);
|
const runtime = await ensurePeerConnectionForSession(session);
|
||||||
if (!runtime) return;
|
if (!runtime) return;
|
||||||
|
|
||||||
if (signalType === 'description' && data.description?.type && data.description?.sdp) {
|
if (signalType === 'description' && data.description?.type && data.description?.sdp) {
|
||||||
await runtime.pc.setRemoteDescription(new RTCSessionDescription(data.description));
|
await runtime.pc.setRemoteDescription(new RTCSessionDescription(data.description));
|
||||||
|
console.log('[video] signal:remote-description-set', {
|
||||||
|
callId,
|
||||||
|
type: data.description.type,
|
||||||
|
sdpLength: String(data.description.sdp || '').length
|
||||||
|
});
|
||||||
await flushPendingRemoteCandidates(runtime);
|
await flushPendingRemoteCandidates(runtime);
|
||||||
|
|
||||||
if (data.description.type === 'offer') {
|
if (data.description.type === 'offer') {
|
||||||
|
console.log('[video] answer:create', { callId });
|
||||||
const answer = await runtime.pc.createAnswer();
|
const answer = await runtime.pc.createAnswer();
|
||||||
await runtime.pc.setLocalDescription(answer);
|
await runtime.pc.setLocalDescription(answer);
|
||||||
|
console.log('[video] answer:local-description-set', {
|
||||||
|
callId,
|
||||||
|
type: answer.type,
|
||||||
|
sdpLength: String(answer.sdp || '').length
|
||||||
|
});
|
||||||
emitVideoSignal(callId, 'description', {
|
emitVideoSignal(callId, 'description', {
|
||||||
description: {
|
description: {
|
||||||
type: answer.type,
|
type: answer.type,
|
||||||
@@ -501,8 +562,17 @@ export const useChatStore = defineStore('chat', () => {
|
|||||||
|
|
||||||
if (signalType === 'candidate' && data.candidate) {
|
if (signalType === 'candidate' && data.candidate) {
|
||||||
if (runtime.pc.remoteDescription) {
|
if (runtime.pc.remoteDescription) {
|
||||||
|
console.log('[video] candidate:add', {
|
||||||
|
callId,
|
||||||
|
type: data.candidate.type,
|
||||||
|
candidate: String(data.candidate.candidate || '').slice(0, 140)
|
||||||
|
});
|
||||||
await runtime.pc.addIceCandidate(new RTCIceCandidate(data.candidate));
|
await runtime.pc.addIceCandidate(new RTCIceCandidate(data.candidate));
|
||||||
} else {
|
} else {
|
||||||
|
console.log('[video] candidate:queue', {
|
||||||
|
callId,
|
||||||
|
type: data.candidate.type
|
||||||
|
});
|
||||||
runtime.pendingCandidates.push(data.candidate);
|
runtime.pendingCandidates.push(data.candidate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1006,6 +1076,7 @@ export const useChatStore = defineStore('chat', () => {
|
|||||||
|
|
||||||
async function inviteVideoCall() {
|
async function inviteVideoCall() {
|
||||||
if (!socket.value?.connected || !currentConversation.value || !canStartVideoCall.value) return;
|
if (!socket.value?.connected || !currentConversation.value || !canStartVideoCall.value) return;
|
||||||
|
console.log('[video] invite:client', { withUserName: currentConversation.value });
|
||||||
const stream = await ensureLocalPreviewStream();
|
const stream = await ensureLocalPreviewStream();
|
||||||
if (!stream) {
|
if (!stream) {
|
||||||
setTemporaryError('Kamera/Mikrofon konnten nicht für den Videochat gestartet werden.');
|
setTemporaryError('Kamera/Mikrofon konnten nicht für den Videochat gestartet werden.');
|
||||||
@@ -1016,11 +1087,13 @@ export const useChatStore = defineStore('chat', () => {
|
|||||||
|
|
||||||
async function acceptVideoCall(callId) {
|
async function acceptVideoCall(callId) {
|
||||||
if (!socket.value?.connected || !callId) return;
|
if (!socket.value?.connected || !callId) return;
|
||||||
|
console.log('[video] accept:client:start', { callId });
|
||||||
const stream = await ensureLocalPreviewStream();
|
const stream = await ensureLocalPreviewStream();
|
||||||
if (!stream) {
|
if (!stream) {
|
||||||
setTemporaryError('Kamera/Mikrofon konnten nicht für den Videochat gestartet werden.');
|
setTemporaryError('Kamera/Mikrofon konnten nicht für den Videochat gestartet werden.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
console.log('[video] accept:client:emit', { callId });
|
||||||
socket.value.emit('videoCall:accept', { callId });
|
socket.value.emit('videoCall:accept', { callId });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user