Chepuhagram/lib/domain/services/webrtc_service.dart

104 lines
3.4 KiB
Dart

import 'package:flutter_webrtc/flutter_webrtc.dart';
import 'package:chepuhagram/data/datasources/ws_client.dart';
class WebRTCService {
RTCPeerConnection? _peerConnection;
MediaStream? _localStream;
// Конфигурация STUN-серверов (Google STUN)
final Map<String, dynamic> _config = {
"iceServers": [
{"urls": "stun:stun.l.google.com:19302"},
{"urls": "stun:stun1.l.google.com:19302"},
]
};
/// Инициализация PeerConnection
Future<void> initPeerConnection(String callId, Function(MediaStream) onRemoteStream) async {
_peerConnection = await createPeerConnection(_config);
// Слушаем удаленный поток
_peerConnection!.onAddStream = (stream) {
onRemoteStream(stream);
};
// Отправляем ICE-кандидаты на сервер через SocketService
_peerConnection!.onIceCandidate = (candidate) {
SocketService().sendMessage({
"type": "ice_candidate",
"call_id": callId,
"candidate": candidate.toMap(),
});
};
// Получаем локальный поток (микрофон + камера)
_localStream = await navigator.mediaDevices.getUserMedia({
'audio': true,
'video': true,
});
// Добавляем треки в соединение
_localStream!.getTracks().forEach((track) {
_peerConnection!.addTrack(track, _localStream!);
});
}
Future<void> handleOffer(String callId, String remoteSdp) async {
// 1. Инициализируем соединение, если оно еще не создано
if (_peerConnection == null) {
await initPeerConnection(callId, (stream) {
// Здесь можно добавить callback для отрисовки видео, если нужно
print("Remote stream received");
});
}
// 2. Создаем ответ (это вызывает ваш метод createAnswer)
await createAnswer(callId, remoteSdp);
}
/// Создание Offer (вызывает инициатор звонка)
Future<void> createOffer(String callId) async {
RTCSessionDescription offer = await _peerConnection!.createOffer();
await _peerConnection!.setLocalDescription(offer);
SocketService().sendMessage({
"type": "offer",
"call_id": callId,
"sdp": offer.sdp,
});
}
/// Создание Answer (вызывает получатель звонка)
Future<void> createAnswer(String callId, String remoteSdp) async {
await _peerConnection!.setRemoteDescription(
RTCSessionDescription(remoteSdp, 'offer'),
);
RTCSessionDescription answer = await _peerConnection!.createAnswer();
await _peerConnection!.setLocalDescription(answer);
SocketService().sendMessage({
"type": "answer",
"call_id": callId,
"sdp": answer.sdp,
});
}
/// Обработка ICE кандидатов от удаленного собеседника
Future<void> addRemoteIceCandidate(Map<String, dynamic> candidateMap) async {
await _peerConnection!.addCandidate(
RTCIceCandidate(
candidateMap['candidate'],
candidateMap['sdpMid'],
candidateMap['sdpMLineIndex'],
),
);
}
/// Очистка ресурсов
void dispose() {
_localStream?.getTracks().forEach((track) => track.stop());
_localStream?.dispose();
_peerConnection?.close();
}
}