Anrufverlauf
Verwenden Sie Lebenszyklus-Callbacks, um die Benutzeroberfläche des Anrufs mit dem aktuellen Anrufverlauf zu synchronisieren. Die folgenden Diagramme veranschaulichen die beiden wichtigsten Perspektiven: das Tätigen und das Entgegennehmen eines Anrufs.
Ausgehender Anruf (aus Sicht des Anrufers)
Wenn Ihre App aufruft serverCall(), durchläuft der aufgerufene Teil die von … gemeldeten Statusaktualisierungen onLegStatusUpdate.
Eingehender Anruf (aus Sicht des Angerufenen)
Wenn Ihre App eine Anrufeinladung erhält, wird der lokale Anruf über die Einladungsverarbeitung in einen aktiven Anruf umgewandelt.
Callback-Quellen
onLegStatusUpdategibt den Fortschritt des Angerufenen an:Ringing,Answered,Completed. Verwenden Sie dies, um die Benutzeroberfläche für ausgehende Anrufe zu aktualisieren (z. B. „Ruft an...“ anzeigen, dann „Verbunden“).onCallInvite/onCallInviteCancelden Lebenszyklus eingehender Einladungen verwalten. Siehe Einen eingehenden Anruf erhalten für Einzelheiten zum Stornierungsgrund.onCallHangupwird ausgelöst, wenn der Anruf aus irgendeinem Grund beendet wird, sowohl bei ausgehenden als auch bei eingehenden Anrufen. Verwenden Sie dies stets als letzten Auslöser für die Aufräumphase.onCallMediaDisconnect/onCallMediaReconnecting/onCallMediaReconnectionUnterbrechungen auf Medienebene melden. Siehe Wiederverbindung für Einzelheiten.
Status-Updates
onLegStatusUpdate Stellt den Verlauf der Angerufenen-Seite bereit (zum Beispiel: klingelt -> angenommen -> abgeschlossen). Dies ist vor allem bei ausgehenden Anrufen relevant, bei denen Sie den Status des Angerufenen in Ihrer Benutzeroberfläche anzeigen möchten.
client.on('legStatusUpdate', (callId, legId, legStatus) => {
if (legStatus === LegStatus.Answered) {
console.log(`Call ${callId} was answered by ${legId}`);
} else if (legStatus === LegStatus.Completed) {
console.log(`Call ${callId} was completed`);
} else if (legStatus === LegStatus.Ringing) {
console.log(`Call ${callId} is ringing`);
}
});
client.setOnLegStatusUpdate { call, legId, status ->
when(status) {
LegStatus.ringing -> println("Leg $legId for call $call is ringing")
LegStatus.answered -> println("Leg $legId for call $call was answered")
LegStatus.completed -> println("Leg $legId for call $call was completed")
}
}
client.setOnLegStatusUpdate((call, legId, status) -> {
switch (status) {
case ringing:
System.out.println("Leg " + legId + " for call " + call + " is ringing");
break;
case answered:
System.out.println("Leg " + legId + " for call " + call + " was answered");
break;
case completed:
System.out.println("Leg " + legId + " for call " + call + " was completed");
break;
}
return null;
});
class CallStatusExampleDelegate: NSObject, VGVoiceClientDelegate {
func voiceClient(_ client: VGVoiceClient, didReceiveLegStatusUpdateForCall callId: VGCallId, withLegId legId: VGCallId, andStatus status: VGLegStatus) {
switch(status){
case .ringing:
print("Leg \(legId) is ringing")
case .answered:
print("Leg \(legId) has answered")
case .completed:
print("Leg \(legId) has completed")
default:
print("Leg has entered the Unknown")
}
}
func voiceClient(_ client: VGVoiceClient, didReceiveInviteForCall callId: VGCallId, from caller: String, with type: VGVoiceChannelType) {}
func voiceClient(_ client: VGVoiceClient, didReceiveHangupForCall callId: VGCallId, withQuality callQuality: VGRTCQuality, reason: VGHangupReason) {}
func voiceClient(_ client: VGVoiceClient, didReceiveInviteCancelForCall callId: VGCallId, with reason: VGVoiceInviteCancelReason) {}
func client(_ client: VGBaseClient, didReceiveSessionErrorWith reason: VGSessionErrorReason) {}
}
- (void) voiceClient:(VGVoiceClient *)client didReceiveLegStatusUpdateForCall:(VGCallId)callId withLegId:(NSString *)legId andStatus:(VGLegStatus)status {
switch (status) {
case VGLegStatusRinging:
NSLog(@"Leg %@ is ringing", legId);
break;
case VGLegStatusAnswered:
NSLog(@"Leg %@ has answered", legId);
break;
case VGLegStatusCompleted:
NSLog(@"Leg %@ has completed", legId);
break;
case VGLegStatusUnknown:
NSLog(@"Leg has entered the Unknown");
break;
}
}
Anruf aufbauen, Auflegen
Verwenden Sie hangup um das Gespräch zu beenden.
const callId = 'callId';
await client.hangup(callId);
// Callback
client.hangup("callId") {
it?.let { err ->
// Handle Error hanging up call
println("Error hanging up call: $err")
}
}
// Coroutine
try {
client.hangup("callId")
} catch (e: Error) {
// Handle Error hanging up call
}
client.hangup("callId", err -> {
if (err != null) {
// Handle Error hanging up call
System.out.println("Error hanging up call: " + err);
}
return null;
});
// Callback
client.hangup("someCallId") { error in
guard let error = error else {
print("Call hangup successful")
return
}
print("Failed to hangup \(error.localizedDescription)")
}
// Async Await
Task.detached {
do {
// Simple Case
try await client.hangup("someCallId")
// Fully Parameter list
try await client.hangup("someCallId", reason: "reason-text", code: "reason-code")
}
catch {
print("Failed to say hangup' \(error.localizedDescription)")
}
}
[client hangup:@"someCallid" callback:^(NSError * _Nullable error) {
if(error){
NSLog(@"Failed to hangup: %@", error);
}
}];
Behandlung von Verbindungsabbrüchen
hangup() kann fehlschlagen, wenn der Anruf bereits beendet wurde, die Sitzung abgelaufen ist oder ein Netzwerkproblem vorliegt. Behandeln Sie den Fehler stets, um sicherzustellen, dass Ihre Benutzeroberfläche in jedem Fall in den Status „beendet“ wechselt:
try {
await client.hangup(callId);
} catch (error) {
console.error("Hangup error:", error.type, error.message);
} finally {
// Always clean up — if hangup failed locally, the server will
// eventually terminate the call via mediaTimeout
showCallEndedUI();
}
client.hangup(callId) { error ->
if (error != null) {
// Hangup request failed — but the call may still end via server-side timeout.
// Clean up local UI anyway to avoid a stuck call screen.
println("Hangup error: ${error.message}")
}
// Always transition to end-of-call UI
showCallEndedUI()
}
client.hangup(callId) { error in
if let error = error {
print("Hangup error: \(error.localizedDescription)")
}
self.showCallEndedUI()
}
Selbst wenn hangup() Sollte der Vorgang fehlschlagen, löschen Sie stets den lokalen Anrufstatus und die Benutzeroberfläche. Der Server beendet den Anruf unabhängig davon über ein Timeout, falls die Auflegemeldung vom Client ihn nicht erreicht hat. Warten auf onCallHangup Dies dient als zusätzliche Bestätigung und ist eine bewährte Vorgehensweise.
Empfangen von Auflegeereignissen
Verwenden Sie onCallHangup um den Abbau des letzten Aufrufs und die Bereinigung der Benutzeroberfläche zu übernehmen.
client.on(
'callHangup',
(callId: string, callQuality: RTCQuality, reason: HangupReason) => {
if (reason == 'LOCAL_HANGUP') {
console.log(`Call ${callId} was hung up locally`);
} else if (reason == 'REMOTE_HANGUP') {
console.log(`Call ${callId} was hung up remotely`);
} else if (reason == 'REMOTE_REJECT') {
console.log(`Call ${callId} was rejected remotely`);
} else if (reason == 'REMOTE_NO_ANSWER_TIMEOUT') {
console.log(`Call ${callId} timed out`);
} else if (reason == 'MEDIA_TIMEOUT') {
console.log(`Call ${callId} timed out`);
} else {
exhaustiveCheck(reason);
}
}
);
client.setOnCallHangupListener { call, callQuality, reason ->
println("Received $reason callQuality: $callQuality for Call $call")
}
client.setOnCallHangupListener((call, legId, reason) -> {
System.out.println("Leg " + legId + " for call " + call + " was hung up for reason " + reason);
return null;
});
class HangupExampleDelegate: NSObject, VGVoiceClientDelegate {
func voiceClient(_ client: VGVoiceClient, didReceiveHangupForCall callId: VGCallId, withQuality callQuality: VGRTCQuality, reason: VGHangupReason) {
print("call: \(callId) has finished")
}
func voiceClient(_ client: VGVoiceClient, didReceiveInviteForCall callId: VGCallId, from caller: String, with type: VGVoiceChannelType) {}
func voiceClient(_ client: VGVoiceClient, didReceiveInviteCancelForCall callId: VGCallId, with reason: VGVoiceInviteCancelReason) {}
func client(_ client: VGBaseClient, didReceiveSessionErrorWith reason: VGSessionErrorReason) {}
}
- (void)voiceClient:(VGVoiceClient *)client didReceiveHangupForCall:(VGCallId)callId withQuality:(VGRTCQuality *)callQuality andReason:(VGHangupReason)reason {
NSLog(@"Call %@ has finished with reason: %ld and quality: %@", callId, reason, callQuality);
}
Debugging von Lebenszyklusereignissen
Falls Aufrufereignisse nicht wie erwartet eintreffen, aktivieren Sie während der Entwicklung die ausführliche Protokollierung, um Lebenszyklusübergänge nachzuverfolgen. Siehe Protokollierung und Diagnose für alle Konfigurationsoptionen, einschließlich benutzerdefinierter Logger und Themenfilterung.
NCCO-Absturzverhalten
connectNCCO funktioniert wie ein normales Zweiparteiengespräch – wenn eine Partei auflegt, wird die Punkt-zu-Punkt-Verbindung beendet und beide Verbindungsstränge werden getrennt.conversationNCCO Dieses Verhalten ist auf die Konversation beschränkt – durch das Auflegen wird lediglich der Teilnehmer aus dem gemeinsamen Raum entfernt. Die anderen Teilnehmer bleiben verbunden, bis sie den Raum einzeln verlassen.