Files
Qlyra/lib/core/calls/conversation_params.dart
sevenhill f74057ce9b
Build Android (FCM) / build-android-fcm (push) Canceled after 0s
Build Android / build-android (push) Canceled after 0s
Build iOS / build-ios (push) Canceled after 0s
Build Linux / build-linux (push) Canceled after 0s
Build macOS / build-macos (push) Canceled after 0s
Build Windows / build-windows (push) Canceled after 0s
Release (main) / android (oneme) (push) Canceled after 0s
Release (main) / android (qlyra) (push) Canceled after 0s
Release (main) / windows (push) Canceled after 0s
Release (main) / linux (push) Canceled after 0s
Release (main) / macos (push) Canceled after 0s
Release (main) / ios (push) Canceled after 0s
Release (main) / release (push) Canceled after 0s
Rebrand application as Qlyra
2026-08-30 13:16:17 +03:00

95 lines
3.2 KiB
Dart

import 'package:kusoft/kusoft.dart' as kb;
/// Параметры подключения к звонку (`vcp`), которые сервер присылает в пуше
/// входящего звонка (opcode 137) и в ответе на инициацию исходящего.
///
/// Формат строки: `<rawLen>:<base64(LZ4-block)>`. После распаковки —
/// компактный JSON с короткими ключами. Расшифровка повторяет
/// `ru.ok.android.externcalls.sdk.api.ConversationParams.decode`.
class ConversationParams {
/// Токен авторизации в сигналинге звонка.
final String token;
/// WebSocket сигналинга, напр. `wss://videowebrtc.okcdn.ru/ws2`.
final String wsEndpoint;
final List<String> wsIps;
/// HTTP/3 web-transport fallback, напр. `https://videowebrtc.okcdn.ru:23456/wt`.
final String? wtEndpoint;
final List<String> wtIps;
/// API звонков, напр. `https://calls.okcdn.ru`.
final String? callsApiEndpoint;
final List<String> callsApiIps;
/// Тип клиента, напр. `one_me`.
final String? clientType;
/// Время истечения параметров (unix-секунды).
final int? expiresAt;
final String? stun;
final List<String> turn;
final String? turnUser;
final String? turnPassword;
final bool isVideo;
const ConversationParams({
required this.token,
required this.wsEndpoint,
this.wsIps = const [],
this.wtEndpoint,
this.wtIps = const [],
this.callsApiEndpoint,
this.callsApiIps = const [],
this.clientType,
this.expiresAt,
this.stun,
this.turn = const [],
this.turnUser,
this.turnPassword,
this.isVideo = false,
});
/// ICE-серверы в формате, который ожидает `flutter_webrtc`
/// (`RTCPeerConnection`).
List<Map<String, dynamic>> get iceServers {
final servers = <Map<String, dynamic>>[];
if (stun != null && stun!.isNotEmpty) {
servers.add({'urls': stun});
}
if (turn.isNotEmpty) {
servers.add({
'urls': turn,
if (turnUser != null) 'username': turnUser,
if (turnPassword != null) 'credential': turnPassword,
});
}
return servers;
}
/// `true`, если параметры ещё действительны (с запасом в 5 секунд).
bool get isExpired {
if (expiresAt == null) return false;
final nowSec = DateTime.now().millisecondsSinceEpoch ~/ 1000;
return nowSec >= expiresAt! - 5;
}
/// Распаковывает и парсит строку `vcp` через Rust-ядро (kusoft). Возвращает
/// `null`, если формат не распознан. Требует инициализации `initKusoft()`.
static ConversationParams? decode(String vcp) {
final kb.CallParams? p = kb.decodeVcp(vcp: vcp, conversationId: '');
if (p == null) return null;
return ConversationParams(
token: p.token,
wsEndpoint: p.wsEndpoint,
stun: p.stun,
turn: p.turn,
turnUser: p.turnUser,
turnPassword: p.turnPassword,
isVideo: p.isVideo,
);
}
}