fix(calls): VoIP push + ring logging; call-DM gets proper preview

- ring.post: log [ring] when triggered
- voip-push: log [voip-push] sent on success with env (prod/sandbox) + callId
- chat.ts sendDirectMessage: when attachmentType=='call' parse audio:<state>:<sec>
  into proper preview (Verpasster Anruf, Anruf abgelehnt, Anruf (m:ss), \u2026)
  so post-call push has body text instead of empty.
- callkit.startOutgoingCall: skip on Android (telecomManager opens dialer UI \u2014
  wrong for in-app WebRTC; iOS-CallKit only for audio-session mgmt).
This commit is contained in:
chahinebrini 2026-06-04 19:54:51 +02:00
parent 6a907cf89b
commit 43eeeb3716
4 changed files with 34 additions and 5 deletions

View File

@ -100,6 +100,13 @@ export function displayIncomingCall(callId: string, callerName: string): void {
} }
export function startOutgoingCall(callId: string, calleeName: string): void { export function startOutgoingCall(callId: string, calleeName: string): void {
// Android: NICHT aufrufen \u2014 `RNCallKeep.startCall` triggert
// `telecomManager.placeCall` was die System-Telefon-Wahl-UI \u00f6ffnet. F\u00fcr
// In-App-WebRTC-Calls v\u00f6llig falsch (User sieht "Telefon w\u00e4hlt\u2026" statt
// unserem /call-Screen). iOS-CallKit macht das richtig (Audio-Session
// setup, keine native UI weil supportsHolding=false und wir keine
// CXEndCallAction triggern bis User auflegt).
if (Platform.OS !== 'ios') return;
try { try {
const uuid = callIdToUuid(callId); const uuid = callIdToUuid(callId);
RNCallKeep.startCall(uuid, calleeName, calleeName, 'generic', false); RNCallKeep.startCall(uuid, calleeName, calleeName, 'generic', false);

View File

@ -39,6 +39,8 @@ export default defineEventHandler(async (event) => {
const callerName = me.nickname || me.username || "Jemand"; const callerName = me.nickname || me.username || "Jemand";
console.log(`[ring] from=${me.id.slice(0,8)} (${callerName}) → to=${peerId.slice(0,8)} callId=${callId}`);
// Fire-and-forget — auch wenn der Push fehlschlägt soll der Caller // Fire-and-forget — auch wenn der Push fehlschlägt soll der Caller
// keine Verzögerung sehen. Der Realtime-Ring läuft parallel. // keine Verzögerung sehen. Der Realtime-Ring läuft parallel.
void sendCallRingPush({ void sendCallRingPush({

View File

@ -66,11 +66,30 @@ export async function sendDirectMessage(
"../services/push" "../services/push"
); );
const senderName = await getDisplayName(senderId); const senderName = await getDisplayName(senderId);
const preview = truncatePreview( // Call-DM-Eintrag (attachmentType='call', attachmentName='<kind>:<state>:<durSec>')
content || // → schöne Preview statt leeren String. Bei verpassten/abgelehnten Calls
(opts?.attachmentType === "audio" ? "🎤 Sprachnachricht" : // ist content immer "".
opts?.attachmentType === "image" || opts?.attachmentUrl ? "📷 Foto" : "") let basePreview = content;
); if (opts?.attachmentType === "call" && opts.attachmentName) {
const [, state, durSecStr] = opts.attachmentName.split(":");
const durSec = parseInt(durSecStr ?? "0", 10) || 0;
if (state === "unanswered") basePreview = "📞 Verpasster Anruf";
else if (state === "declined") basePreview = "📞 Anruf abgelehnt";
else if (state === "failed") basePreview = "📞 Anruf fehlgeschlagen";
else if (state === "busy") basePreview = "📞 Besetzt";
else if (state === "ended") {
const mm = Math.floor(durSec / 60);
const ss = String(durSec % 60).padStart(2, "0");
basePreview = `📞 Anruf (${mm}:${ss})`;
} else {
basePreview = "📞 Anruf";
}
} else if (!basePreview) {
basePreview =
opts?.attachmentType === "audio" ? "🎤 Sprachnachricht" :
(opts?.attachmentType === "image" || opts?.attachmentUrl) ? "📷 Foto" : "";
}
const preview = truncatePreview(basePreview);
console.log(`[dm-push] sender=${senderId} receiver=${receiverId} preview="${preview.slice(0, 30)}"`); console.log(`[dm-push] sender=${senderId} receiver=${receiverId} preview="${preview.slice(0, 30)}"`);
await sendChatPush({ await sendChatPush({
receiverId, receiverId,

View File

@ -138,6 +138,7 @@ export async function sendVoIPPush(payload: VoIPCallPayload): Promise<boolean> {
const result = await prov.send(note, payload.voipToken); const result = await prov.send(note, payload.voipToken);
if (result.failed.length === 0) { if (result.failed.length === 0) {
tokenEnvCache.set(payload.voipToken, env); tokenEnvCache.set(payload.voipToken, env);
console.log(`[voip-push] sent token=${payload.voipToken.slice(0, 8)}… env=${env} callId=${payload.callId}`);
return true; return true;
} }
const f = result.failed[0]; const f = result.failed[0];