Ciclo de vida de una llamada
Utiliza las funciones de llamada de ciclo de vida para mantener la interfaz de usuario de la llamada sincronizada con el progreso de la misma en tiempo real. Los diagramas siguientes muestran las dos perspectivas principales: realizar una llamada y recibirla.
Llamada saliente (desde el punto de vista del llamante)
Cuando tu aplicación llama a serverCall(), la parte receptora avanza a través de las actualizaciones de estado comunicadas por onLegStatusUpdate.
Llamada entrante (desde el punto de vista del destinatario)
Cuando tu aplicación recibe una invitación de llamada, la llamada local pasa, tras el proceso de gestión de la invitación, a convertirse en una llamada activa.
Fuentes de devolución de llamada
onLegStatusUpdateinforma sobre la progresión de la pata del receptor:Ringing,Answered,Completed. Utiliza esto para actualizar la interfaz de usuario de las llamadas salientes (por ejemplo, mostrar «Sonando...» y luego «Conectado»).onCallInvite/onCallInviteCancelGestionar el ciclo de vida de las invitaciones recibidas. Véase Recibir una llamada entrante para consultar los detalles del motivo de la cancelación.onCallHangupse ejecuta cuando finaliza la llamada por cualquier motivo, tanto en llamadas salientes como entrantes. Utilízalo siempre como el desencadenante final de limpieza.onCallMediaDisconnect/onCallMediaReconnecting/onCallMediaReconnectionNotificar interrupciones en la capa de medios. Véase Reconexión Para más información.
Actualizaciones de estado
onLegStatusUpdate Proporciona información sobre el estado de la llamada del destinatario (por ejemplo: sonando → contestada → finalizada). Esto resulta especialmente relevante en las llamadas salientes, en las que se desea reflejar el estado del destinatario en la interfaz de usuario.
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;
}
}
Iniciar la llamada y colgar
Uso hangup para finalizar la llamada.
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);
}
}];
Gestión de errores de desconexión
hangup() Puede fallar si la llamada ya ha finalizado, la sesión ha caducado o hay un problema de red. Gestiona siempre el error para garantizar que tu interfaz de usuario pase al estado «finalizado» en cualquier caso:
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()
}
Aunque hangup() Si falla, limpia siempre el estado de la llamada local y la interfaz de usuario. El servidor cortará la llamada de forma independiente por tiempo de espera si no ha recibido la señal de colgar del lado del cliente. A la espera de onCallHangup utilizarla como confirmación secundaria es una buena práctica.
Recepción de eventos de colgado
Uso onCallHangup para gestionar el cierre definitivo de la llamada y la limpieza de la interfaz de usuario.
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);
}
Depuración de eventos del ciclo de vida
Si las llamadas no se reciben como se esperaba, activa el registro detallado durante el desarrollo para rastrear las transiciones del ciclo de vida. Consulta Registro y diagnóstico para ver todas las opciones de configuración, incluidos los registradores personalizados y el filtrado de temas.
Comportamiento de bloqueo de NCCO
connectNCCO funciona como una llamada normal entre dos interlocutores: cuando uno de ellos cuelga, la conexión punto a punto se interrumpe y se cortan ambas líneas.conversationNCCO Esta acción tiene un alcance limitado a la conversación: al colgar, solo se retira a ese participante de la sala compartida. El resto de participantes permanecen conectados hasta que se marchan por su cuenta.