Ciclo de vida da chamada
Use callbacks do ciclo de vida para manter a interface do usuário da chamada sincronizada com o andamento da chamada em tempo real. Os diagramas abaixo mostram as duas perspectivas principais: fazer uma chamada e receber uma.
Chamada de saída (perspectiva do chamador)
Quando seu aplicativo chamar serverCall(), a parte do chamador avança por meio das atualizações de status relatadas por onLegStatusUpdate.
Chamada recebida (do ponto de vista do destinatário)
Quando seu aplicativo recebe um convite para uma chamada, a chamada local passa pela etapa de tratamento do convite e se transforma em uma chamada ativa.
Fontes de retorno de chamada
onLegStatusUpdaterelata a progressão da etapa do destinatário da chamada:Ringing,Answered,Completed. Use isso para atualizar a interface do usuário das chamadas efetuadas (por exemplo, exibir “Toque...” e, em seguida, “Conectado”).onCallInvite/onCallInviteCancelgerenciar o ciclo de vida dos convites recebidos. Consulte Receber uma chamada para obter detalhes sobre o motivo do cancelamento.onCallHangupé acionado quando a chamada é encerrada por qualquer motivo, tanto em chamadas efetuadas quanto recebidas. Sempre utilize isso como o gatilho final de limpeza.onCallMediaDisconnect/onCallMediaReconnecting/onCallMediaReconnectionrelatar interrupções na camada de mídia. Consulte Reconexão para mais detalhes.
Atualizações de status
onLegStatusUpdate fornece o andamento da ligação do destinatário (por exemplo: tocando -> atendida -> concluída). Isso é mais relevante para chamadas de saída, nas quais você deseja refletir o status do destinatário na sua interface de usuário.
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;
}
}
Iniciando o desligamento
Uso hangup para encerrar sua ligação.
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);
}
}];
Tratamento de erros de desligamento
hangup() pode falhar se a chamada já tiver terminado, se a sessão tiver expirado ou se houver um problema de rede. Sempre trate o erro para garantir que sua interface de usuário faça a transição para o estado “encerrado”, independentemente do que aconteça:
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()
}
Mesmo que hangup() Se houver falha, sempre limpe o estado da chamada local e a interface do usuário. O servidor encerrará a chamada automaticamente por tempo limite, caso o desligamento do lado do cliente não tenha chegado até ele. Aguardando onCallHangup como uma confirmação secundária é uma boa prática.
Recebimento de eventos de desligamento
Uso onCallHangup para lidar com o encerramento da chamada e a limpeza da interface do usuário.
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);
}
Depuração de eventos do ciclo de vida
Se os eventos de chamada não estiverem ocorrendo conforme o esperado, ative o registro detalhado durante o desenvolvimento para rastrear as transições do ciclo de vida. Consulte Registros e diagnósticos para ver todas as opções de configuração, incluindo registradores personalizados e filtragem de tópicos.
Comportamento de travamento do NCCO
connectNCCO funciona como uma chamada padrão entre duas partes — quando uma das partes desliga, a conexão ponto a ponto é encerrada e ambas as ligações são encerradas.conversationNCCO Esse comportamento tem escopo de conversa — desligar o telefone apenas remove a presença desse participante da sala compartilhada. Os demais participantes permanecem conectados até que saiam individualmente.