startScreenCapture method

Future<void> startScreenCapture({
  1. bool? autoAdjustNetworkQuality,
  2. bool forcePermissionCheck = false,
})

Implementation

Future<void> startScreenCapture({
  bool? autoAdjustNetworkQuality,
  bool forcePermissionCheck = false,
}) async {
  if (_isDisposed) {
    log('⚠️ Intento de iniciar captura en instancia disposed');
    return;
  }

  if (_isInitializingStream) {
    log('⏳ Inicialización de captura ya en progreso, ignorando llamada');
    return;
  }

  if (_isStreaming) {
    log('ℹ️ Captura de pantalla WebRTC ya activa');
    return;
  }

  _isInitializingStream = true;

  try {
    _markActivity();

    // 0. Ajuste dinámico de calidad según el tipo de red (WiFi, 4G, 3G, 2G)
    if (autoAdjustNetworkQuality ?? autoAdjustQuality) {
      await autoAdjustQualityForCurrentNetwork();
    }

    // 1. Verificación controlada de permisos
    final perms = await ensurePermissions(
      forceRefresh: forcePermissionCheck,
      requestNotifications: true,
    );

    if (!perms.notifications) {
      log('⚠️ Permiso de notificaciones no disponible, continuando intento de captura...');
    }

    // 2. Comprobar / solicitar MediaProjection
    final isRunning = await NativeBridge.isScreenCaptureRunning();
    if (!isRunning) {
      final granted = await NativeBridge.requestMediaProjection();
      if (!granted) {
        log('❌ Permiso de captura de pantalla denegado por el usuario');
        return;
      }
      await Future.delayed(const Duration(milliseconds: 200));
    }

    // 3. Iniciar servicio nativo foreground si no está corriendo
    final isServiceRunning = await NativeBridge.isScreenCaptureRunning();
    if (!isServiceRunning) {
      final started = await NativeBridge.startScreenCapture();
      if (!started) {
        log('❌ No se pudo iniciar el servicio de captura');
        return;
      }
    }

    // 4. Crear PeerConnection si aún no existe
    if (_peerConnection == null) {
      if (turnServerIP != null && turnServerPort != null) {
        await _testTurnConnectivity(turnServerIP!, turnServerPort!);
      }

      _peerConnection = await createPeerConnection(
        {
          'iceServers': [
            if (turnServerIP != null && turnServerPort != null)
              {
                'urls': 'turn:$turnServerIP:$turnServerPort',
                if (turnServerUsername != null) 'username': turnServerUsername,
                if (turnServerCredential != null) 'credential': turnServerCredential,
              },
            {'urls': 'stun:stun.l.google.com:19302'},
            {'urls': 'stun:stun1.l.google.com:19302'},
          ],
          'iceTransportPolicy': 'all',
          'bundlePolicy': 'max-bundle',
          'rtcpMuxPolicy': 'require',
          'sdpSemantics': 'unified-plan',
        },
        {
          'mandatory': {},
          'optional': [
            {'DtlsSrtpKeyAgreement': true},
          ],
        },
      );

      _peerConnection!.onIceCandidate = (candidate) {
        if (candidate.candidate == null || candidate.candidate!.isEmpty) return;
        _markActivity();
        _sendMessage({'type': 'ice-candidate', 'candidate': candidate.toMap()});
      };

      _peerConnection!.onConnectionState = (state) {
        log('🔗 Estado WebRTC: $state');
        if (state == RTCPeerConnectionState.RTCPeerConnectionStateFailed) {
          _handleConnectionFailure();
        } else if (state == RTCPeerConnectionState.RTCPeerConnectionStateConnected) {
          _markActivity();
        }
      };
    }

    // 5. Capturar pantalla con constraints parametrizados
    _localStream = await navigator.mediaDevices.getDisplayMedia({
      'video': {
        'width': videoWidth,
        'height': videoHeight,
        'frameRate': videoFrameRate,
      },
      'audio': false,
    });

    // 6. Agregar tracks al PeerConnection
    for (final track in _localStream!.getTracks()) {
      _peerConnection!.addTrack(track, _localStream!);
    }

    // 7. Crear y enviar oferta WebRTC
    final offer = await _peerConnection!.createOffer({
      'offerToReceiveAudio': false,
      'offerToReceiveVideo': true,
    });
    await _peerConnection!.setLocalDescription(offer);

    _sendMessage({'type': 'webrtc-offer', 'sdp': offer.toMap()});
    _markActivity();

    _isStreaming = true;
    log('✅ Captura de pantalla y oferta WebRTC iniciadas exitosamente');
  } catch (e) {
    log('❌ Error al iniciar captura: $e');
    await stopScreenCapture();
  } finally {
    _isInitializingStream = false;
  }
}