Cycle de vie d'un appel
Utilisez les callbacks de cycle de vie pour synchroniser l'interface utilisateur de l'appel avec la progression de celui-ci en temps réel. Les schémas ci-dessous illustrent les deux cas de figure principaux : passer un appel et en recevoir un.
Appel sortant (du point de vue de l'appelant)
Lorsque votre application appelle serverCall(), la branche appelée passe par les mises à jour d'état signalées par onLegStatusUpdate.
Appel entrant (du point de vue de la personne appelée)
Lorsque votre application reçoit une invitation à un appel, l'appel local passe par la phase de gestion de l'invitation avant de devenir un appel actif.
Sources de rappel
onLegStatusUpdateaffiche la progression de la branche « callee » :Ringing,Answered,Completed. Utilisez cette fonction pour mettre à jour l'interface utilisateur des appels sortants (par exemple, afficher « En cours de sonnerie… », puis « Connecté »).onCallInvite/onCallInviteCancelGérer le cycle de vie des invitations reçues. Voir Recevoir un appel entrant pour obtenir des précisions sur le motif de l'annulation.onCallHangupse déclenche lorsque l'appel prend fin, quelle qu'en soit la raison, tant pour les appels sortants que pour les appels entrants. Utilisez toujours cet événement comme dernier déclencheur de nettoyage.onCallMediaDisconnect/onCallMediaReconnecting/onCallMediaReconnectionsignaler les interruptions au niveau de la couche média. Voir Reconnexion pour plus de détails.
Mises à jour de statut
onLegStatusUpdate fournit le suivi du parcours de l'appelé (par exemple : sonnerie -> réponse -> appel abouti). Cette fonctionnalité est particulièrement utile pour les appels sortants, lorsque vous souhaitez afficher l'état de l'appelé dans votre interface utilisateur.
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;
}
}
Lancement de la coupure d'appel
Utilisation hangup pour mettre fin à votre appel.
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);
}
}];
Gestion des erreurs de déconnexion
hangup() peut échouer si l'appel est déjà terminé, si la session a expiré ou s'il y a un problème de réseau. Veillez toujours à gérer l'erreur afin de garantir que votre interface utilisateur passe à l'état « terminé » quoi qu'il arrive :
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()
}
Même si hangup() En cas d'échec, veillez à toujours réinitialiser l'état de l'appel local et l'interface utilisateur. Le serveur mettra fin à l'appel de manière autonome par délai d'expiration si la fermeture de la communication côté client ne lui a pas été signalée. En attente de onCallHangup Il est recommandé de procéder à une confirmation secondaire.
Réception d'événements de raccrochage
Utilisation onCallHangup pour gérer la fermeture définitive de l'appel et le nettoyage de l'interface utilisateur.
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);
}
Débogage des événements du cycle de vie
Si les événements d'appel ne se produisent pas comme prévu, activez la journalisation détaillée pendant le développement afin de suivre les transitions du cycle de vie. Voir Journalisation et diagnostics pour découvrir toutes les options de configuration, y compris les enregistreurs personnalisés et le filtrage des sujets.
Comportement de blocage du NCCO
connectBCN Cela fonctionne comme un appel classique entre deux interlocuteurs : lorsqu'un des deux raccroche, la connexion point à point prend fin et les deux liaisons sont interrompues.conversationBCN Ce comportement s'applique au niveau de la conversation : raccrocher ne fait que retirer le « pied » de ce participant de la salle partagée. Les autres participants restent connectés jusqu'à ce qu'ils quittent la salle individuellement.