ansible-role-varnish icon indicating copy to clipboard operation
ansible-role-varnish copied to clipboard

Intermittent issues in conference calls

Open waleedqaefi opened this issue 9 months ago • 1 comments

Specify the sample to which the issue belongs (use [x]): [] Conference Calls sample

Platform (use [x]) [] Android [] iOS

Describe the bug:

We are currently getting intermittent issues in some calls , both primary and minor streams shows blank white screen. I am adding our conversation_call_screen code . Can you please have a look if there is something wrong in our implementation?

Additional info

import 'dart:async';
import 'dart:io';

import 'package:connectycube_sdk/connectycube_sdk.dart';
import 'package:customer_io/customer_io.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:wakelock/wakelock.dart';

import '../../../../config/video_call_managers/call_manager.dart';
import '../../../../config/video_call_utils/connectycube_local_storage_manager.dart';
import '../../../../config/video_call_utils/consts.dart';
import '../../../../config/video_call_utils/duration_timer.dart';
import '../../../../config/video_call_utils/media_utils.dart';
import '../../../../config/video_call_utils/platform_utils.dart';
import '../../../../config/video_call_utils/waiting_timer.dart';
import '../../../../core/app/video_call_navigation_manager.dart';
import '../../../../core/general/services/service_locator.dart';
import '../../../../core/general/theme/app_colors.dart';
import '../../../chat_v2/presentation/bloc/chat_v2_bloc.dart';
import '../../../find_for_me/domain/entities/find_for_me_request_entity.dart';
import '../../../find_for_me/domain/params/change_find_for_me_request_params.dart';
import '../../../find_for_me/presentation/bloc/find_for_me_bloc.dart';
import '../../domain/entities/call_request_entity.dart';
import '../../domain/params/conversation_call_view_params.dart';
import '../../domain/params/save_session_params.dart';
import '../bloc/video_call_bloc.dart';
import '../widgets/call_controls_widget.dart';
import '../widgets/hide_call_view_button.dart';
import '../widgets/notifications/taaly_bot_notification/taaly_bot_notifications.dart';
import '../widgets/private_call_widget.dart';
import '../widgets/video_call_camera_off_view.dart';
import '../widgets/video_call_mini_bar.dart';

class ConversationCallView extends StatefulWidget {
  static const String routeName = "call_conversation_view";
  static const String path = "/call_conversation_view";

  final ConversationsCallViewParams conversationParams;

  const ConversationCallView({super.key, required this.conversationParams});

  @override
  State<StatefulWidget> createState() {
    return _ConversationCallViewState();
  }

  static Widget addBlocProviderAndBuild(
    ConversationsCallViewParams conversationParams,
  ) {
    return MultiBlocProvider(
      providers: [
        BlocProvider(
          create: (context) => sl<ChatV2Bloc>(),
        ),
        BlocProvider(
          create: (context) => sl<FindForMeBloc>(),
        ),
      ],
      child: ConversationCallView(conversationParams: conversationParams),
    );
  }
}

class _ConversationCallViewState extends State<ConversationCallView> {
  static const String tag = "_ConversationCallScreenState";
  final CallManager _callManager = CallManager.instance;
  late StreamSubscription<int> timerStream;
  late DurationTimer _callTimer;
  late CubeUser _currentUser;
  late ConferenceSession _callSession;
  late String _callName;
  late bool _isIncoming;
  late String _meetingId;
  late List<int> _opponents;
  late int currentUserId;
  final _statsReportsManager = CubeStatsReportsManager();
  MediaStream? initialLocalMediaStream;

  String _callStatus = 'Waiting...';
  bool _isCameraEnabled = true;
  bool _isSpeakerEnabled = true;
  bool _isMicMute = false;
  bool _isFrontCameraUsed = true;
  RTCVideoViewObjectFit primaryVideoFit =
      RTCVideoViewObjectFit.RTCVideoViewObjectFitCover;
  MapEntry<int, RTCVideoRenderer>? primaryRenderer;
  Map<int, RTCVideoRenderer> minorRenderers = {};
  Map<int, Map<String, bool>> participantsMediaConfigs = {};
  WidgetPosition _minorWidgetPosition = WidgetPosition.bottomRight;

  DateTime? startDate;
  DateTime? meetingStartDate;
  String? bookingId;
  String? findForMeRequestId;

  _setUpCallManagerMethods() {
    _callManager.onCallRejected = _onCallRejected;
    _callManager.onReceiveRejectCall = _onReceiveRejectCall;
    _callManager.onReceiveAcceptCall = _onReceiveAcceptCall;
    _callManager.onCloseCall = _onCloseCall;
    _callManager.onCallMuted = _onCallMuted;
    _callManager.getMediaState = _getMediaState;
    _callManager.onParticipantMediaUpdated = _onParticipantMediaUpdated;

    _callSession.onLocalStreamReceived = _addLocalMediaStream;
    _callSession.onRemoteStreamTrackReceived = _addRemoteMediaStream;
    _callSession.onSessionClosed = _onSessionClosed;
    _callSession.onPublishersReceived = onPublishersReceived;
    _callSession.onPublisherLeft = onPublisherLeft;
    _callSession.onError = onError;
    _callSession.onSubStreamChanged = onSubStreamChanged;
    _callSession.onLayerChanged = onLayerChanged;
  }

  void _initParams() {
    _currentUser = widget.conversationParams.currentUser;
    _callSession = widget.conversationParams.callSession;
    _callName = widget.conversationParams.callName;
    _isIncoming = widget.conversationParams.isIncoming;
    _meetingId = widget.conversationParams.meetingId;
    _opponents = widget.conversationParams.opponents;
    currentUserId = _currentUser.id!;
    _isCameraEnabled = _callSession.callType == CallType.VIDEO_CALL;
    findForMeRequestId = widget.conversationParams.findForMeRequestId;
    _opponentName = widget.conversationParams.opponentName ?? "";
    _opponentImage = widget.conversationParams.opponentImageUrl;
  }

  late String _opponentName;
  String? _opponentImage;

  @override
  void initState() {
    super.initState();
    CustomerIO.screen(name: ConversationCallView.routeName);
    if (Platform.isIOS) {
      Helper.setAppleAudioConfiguration(
        AppleAudioConfiguration(
          appleAudioMode: AppleAudioMode.videoChat,
        ),
      );
    }
    Wakelock.enable();

    _initParams();
    _statsReportsManager.init(_callSession);

    _callTimer = DurationTimer(
      onZeroSecond: () {},
    );

    if (!_isIncoming) {
      waitingTimer.start();
    }

    if (widget.conversationParams.isIncoming == true) {
      _startCallTimer();
      startDate = DateTime.now();
    }
    meetingStartDate = widget.conversationParams.startDate;
    bookingId = widget.conversationParams.bookingId;

    timerStream = _callTimer.durationStream.listen((second) {
      if (second == 0) {
        // IF INCOMING IS FALSE, THIS MEAN HE IS THE CALLER
        if (widget.conversationParams.isIncoming == false) _endCall();
      }
    });

    if (initialLocalMediaStream != null) {
      _isMicMute =
          (initialLocalMediaStream?.getAudioTracks().firstOrNull?.enabled ??
              false);

      _isCameraEnabled =
          initialLocalMediaStream?.getVideoTracks().firstOrNull?.enabled ??
              false;
    }

    participantsMediaConfigs[currentUserId] = {
      PARAM_IS_MIC_ENABLED: !_isMicMute,
      PARAM_IS_CAMERA_ENABLED: _isCameraEnabled
    };
    _setUpCallManagerMethods();

    context.read<VideoCallBloc>().add(GetVideoChatsEvent(
          meetingId: _meetingId,
        ));

    if (initialLocalMediaStream != null) {
      _callSession.localStream = initialLocalMediaStream;
      _addLocalMediaStream(initialLocalMediaStream!);
    }

    // TO FIX MIC MUTING INITIAL STATE
    _callSession.setMicrophoneMute(_isMicMute);

    _callSession.joinDialog(
      _meetingId,
      ((publishers) {
        log("join session= $publishers", tag);

        _callManager.requestParticipantsMediaConfig(publishers);

        _callSession.setMaxBandwidth(0);

        if (!_isIncoming) {
          _callManager.startNewOutgoingCall(
            _meetingId,
            _opponents,
            _callSession.currentUserId,
            _callSession.callType,
            _callName,
            _currentUser.avatar,
            widget.conversationParams.startDate,
          );
        } else {
          setState(() {
            _callStatus = 'Connected';
            _startCallTimer();
          });
        }
      }),
      conferenceRole: ConferenceRole.PUBLISHER,
    );
  }

  @override
  void dispose() {
    _statsReportsManager.dispose();
    Wakelock.disable();

    stopBackgroundExecution();

    minorRenderers.forEach((opponentId, renderer) {
      log("[dispose] dispose renderer for $opponentId", tag);
      try {
        renderer.srcObject = null;
        renderer.dispose();
      } catch (e) {
        log('Error On [minorRenderers.forEach] $e');
      }
    });
    //! NEW ADDS TO CLEAR VIDEO CALL
    minorRenderers.clear();
    primaryRenderer?.value.dispose();
    //! END HERE
    _stopCallTimer();

    super.dispose();
  }

  @override
  deactivate() {
    context.read<VideoCallBloc>().cancelAllSubscriptions();
    super.deactivate();
  }

  Future<void> viewRatingBottomSheet() async {
    if (startDate == null) return;
    if (isMinimized == true) {
      setState(() {
        isMinimized = false;
        isWasMinimized = true;
      });
    }
    int counter = 0;
    while (VideoCallNavigationManager.navigatorKey.currentContext == null &&
        counter < 15) {
      await Future.delayed(const Duration(milliseconds: 300));
      counter++;
    }
    if (VideoCallNavigationManager.navigatorKey.currentContext == null) return;
    await context.read<VideoCallBloc>().showRatingDialog(
          _meetingId,
          VideoCallNavigationManager.navigatorKey.currentContext!,
        );
  }

  bool isMinimized = false;
  bool isWasMinimized = false;
  final WaitingTimer waitingTimer = WaitingTimer();

  @override
  Widget build(BuildContext context) {
    VideoCallNavigationManager.instance.context = context;
    return WillPopScope(
      onWillPop: () => _onBackPressed(context),
      child: BlocListener<VideoCallBloc, VideoCallState>(
        listener: (context, state) {
          if (state is UpdateChatSuccess && meetingStartDate == null) {
            if (widget.conversationParams.isIncoming == false) return;
            meetingStartDate = state.chat.meetingStartDate;
            if (meetingStartDate == null) return;
            _callTimer.modifyDurationSecBasedOnStartDate(meetingStartDate!);
          }
          if (state is UpdateChatSuccess && bookingId == null) {
            if (widget.conversationParams.isIncoming == false) return;
            bookingId = state.chat.bookingId;
            findForMeRequestId = state.chat.findForMeRequestId;
            if (_isIncoming) {
              _saveSessionData();
            }
          }
        },
        child: !isMinimized
            ? MaterialApp(
                navigatorKey: VideoCallNavigationManager.navigatorKey,
                debugShowCheckedModeBanner: false,
                home: Scaffold(
                  backgroundColor: AppColors.deactivatedColor,
                  body: !isWasMinimized
                      ? Stack(
                          children: [
                            _buildBody(),
                            HideCallViewBtn(
                              onPressed: () {
                                setState(() => isMinimized = true);
                              },
                            ),
                          ],
                        )
                      : VideoCallCameraOffView(
                          opponentName: _opponentName,
                          opponentImage: _opponentImage,
                          timerStream: _callTimer.durationStream,
                        ),
                ),
              )
            : VideoCallMiniBar(
                timerStream: _callTimer.durationSec != 30 * 60
                    ? _callTimer.durationStream
                    : waitingTimer.durationStream,
                opponentName: _opponentName,
                onPressed: () {
                  setState(() => isMinimized = false);
                },
                isInWaiting: _callTimer.durationSec == 30 * 60,
              ),
      ),
    );
  }

  Widget _buildBody() {
    return Stack(
      children: [
        OrientationBuilder(
          builder: (context, orientation) => _buildPrivateCallLayout(
            orientation,
          ),
        ),
        Align(
          alignment: Alignment.bottomCenter,
          child: _getActionsPanel(),
        ),
        const TaalyBotNotifications(
          addTopMarginForFirstMessage: true,
        ),
      ],
    );
  }

  Widget _buildPrivateCallLayout(Orientation orientation) {
    return PrivateCallLayout(
      currentUserId: currentUserId,
      primaryRenderer: primaryRenderer,
      primaryVideoFit: primaryVideoFit,
      minorRenderers: minorRenderers,
      callName: _getCallName(),
      callStatus: _callStatus,
      callTimer: _callTimer,
      minorWidgetInitialPosition: _minorWidgetPosition,
      isFrontCameraUsed: _isFrontCameraUsed,
      participantsMediaConfigs: participantsMediaConfigs,
      onMinorVideoPositionChanged: (newPosition) {
        _minorWidgetPosition = newPosition;
      },
      onPrimaryVideoFitChanged: (newObjectFit) {
        primaryVideoFit = newObjectFit;
      },
      onRenderersChanged: _updateRenderers,
      opponentImageUrl: _opponentImage,
      opponentName: _opponentName,
      viewWaitingView: _callTimer.durationSec == 30 * 60,
      waitingTimer: waitingTimer,
    );
  }

  Widget _getActionsPanel() {
    return CallControls(
      isMicMuted: _isMicMute,
      onMute: _muteMic,
      isCameraButtonVisible: true,
      isCameraEnabled: _isVideoEnabled(),
      onToggleCamera: _toggleCamera,
      isSpeakerEnabled: _isSpeakerEnabled,
      onSwitchSpeaker: _switchSpeaker,
      isSwitchCameraButtonVisible: true,
      onSwitchCamera: _switchCamera,
      onEndCall: _endCall,
      meetingId: widget.conversationParams.meetingId,
    );
  }

  Future<bool> _onBackPressed(BuildContext context) {
    return Future.value(false);
  }

  void _onCloseCall() async {
    log("_onCloseCall", tag);
    if (startDate != null) {
      _stopCallTimer();
    }
    _callSession.leave();
  }

  void _onReceiveRejectCall(String meetingId, int participantId, bool isBusy) {
    log("_onReceiveRejectCall got reject from user $participantId", tag);
    final callRequestId = widget.conversationParams.callRequestId;
    if (callRequestId != null) {
      context.read<VideoCallBloc>().add(
            UpdateCallRequestEvent(
              requestId: widget.conversationParams.callRequestId!,
              callRequestStatus: CallRequestStatus.rejected,
            ),
          );
    }

    VideoCallNavigationManager.instance.disposeVideoCall(
      popPreviousRoute: false,
    );
  }

  void _changeStatus({String? studentId, String? tutorId}) {
    context.read<FindForMeBloc>().add(
          ChangeFindForMeRequestEvent(
            changeFindForMeRequestParams: ChangeFindForMeRequestParams(
              requestId: widget.conversationParams.findForMeRequestId!,
              status: FindMeRequestStatus.accepted,
              studentId: studentId,
              tutorId: tutorId,
            ),
          ),
        );
  }

  void _onReceiveAcceptCall(int participantId) {
    log('[_onReceiveAcceptCall] from user $participantId', tag);
    if (!_isIncoming) _saveSessionData();

    final videoCallBloc = context.read<VideoCallBloc>();

    final callRequestId = widget.conversationParams.callRequestId;
    if (callRequestId != null) {
      videoCallBloc.add(
        UpdateCallRequestEvent(
          requestId: widget.conversationParams.callRequestId!,
          callRequestStatus: CallRequestStatus.accepted,
        ),
      );
    }

    videoCallBloc.add(CreateNewCallChatEvent(
      meetingId: widget.conversationParams.meetingId,
      meetingStartDate: widget.conversationParams.startDate,
      bookingId: bookingId,
      findForMeRequestId: findForMeRequestId,
    ));

    if (widget.conversationParams.findForMeRequestId != null) {
      _changeStatus(
        studentId: videoCallBloc.studentId,
        tutorId: videoCallBloc.tutorId,
      );
    }

    setState(() {
      _callStatus = 'Connected';
      _startCallTimer();
      startDate = DateTime.now();
    });
  }

  _saveSessionData() async {
    if (bookingId != null) return;
    final videoCallBloc = context.read<VideoCallBloc>();

    await ConnectycubeLocalStorageManager.saveLastSessionData(
      tutorId: videoCallBloc.tutorId!,
      studentId: videoCallBloc.studentId!,
      meetingId: _meetingId,
      bookingId: bookingId,
      findForMeRequestId: findForMeRequestId,
    );
  }

  Future<void> _addLocalMediaStream(MediaStream stream) async {
    log("_addLocalMediaStream", tag);

    _addMediaStream(currentUserId, true, stream);
  }

  void _addRemoteMediaStream(session, int userId, MediaStream stream,
      {String? trackId}) {
    log("_addRemoteMediaStream for user $userId", tag);

    _addMediaStream(userId, false, stream, trackId: trackId);
  }

  void _removeMediaStream(callSession, int userId) {
    log("_removeMediaStream for user $userId", tag);
    RTCVideoRenderer? videoRenderer = minorRenderers[userId];
    if (videoRenderer != null) {
      videoRenderer.srcObject = null;
      videoRenderer.dispose();

      setState(() {
        minorRenderers.remove(userId);
      });
    } else if (primaryRenderer?.key == userId) {
      var rendererToRemove = primaryRenderer?.value;

      if (rendererToRemove != null) {
        rendererToRemove.srcObject = null;
        rendererToRemove.dispose();
      }

      if (minorRenderers.isNotEmpty) {
        setState(() {
          var userIdToRemoveRenderer = minorRenderers.keys.firstWhere(
              (key) => key != currentUserId,
              orElse: () => minorRenderers.keys.first);

          primaryRenderer = MapEntry(userIdToRemoveRenderer,
              minorRenderers.remove(userIdToRemoveRenderer)!);
          chooseOpponentsStreamsQuality(_callSession, currentUserId,
              {userIdToRemoveRenderer: StreamType.high});
        });
      }
    }
  }

  void _closeSessionIfLast() {
    log("[_closeSessionIfLast]", tag);
    if (_callSession.allActivePublishers.isEmpty) {
      log("[_closeSessionIfLast] 1", tag);
      _callSession.leave();
    }
  }

  void _onSessionClosed(session) async {
    log("[_onSessionClosed]", tag);
    if (startDate != null && !_isIncoming) {
      await _sendDataToCloud();
    }
    _statsReportsManager.dispose();
    _callManager.stopCall(_currentUser);

    try {
      await viewRatingBottomSheet();
    } catch (e) {
      log(e.toString());
    }

    if (startDate != null && _isIncoming) {
      await _sendDataToCloud();
    }

    log("[_onSessionClosed] 2", tag);

    if (!context.mounted) return;

    VideoCallNavigationManager.instance.disposeVideoCall(
      popPreviousRoute: true,
    );
  }

  void onPublishersReceived(publishers) {
    log("onPublishersReceived", tag);
    handlePublisherReceived(publishers);
  }

  void onPublisherLeft(publisher) {
    log("onPublisherLeft $publisher", tag);
    _removeMediaStream(_callSession, publisher);
    _closeSessionIfLast();
  }

  void onError(ex) => log("onError $ex", tag);

  void onSubStreamChanged(int userId, StreamType streamType) {
    log("onSubStreamChanged userId: $userId, streamType: $streamType", tag);
  }

  void onLayerChanged(int userId, int layer) {
    log("onLayerChanged userId: $userId, layer: $layer", tag);
  }

  Future<void> _addMediaStream(
      int userId, bool isLocalStream, MediaStream stream,
      {String? trackId}) async {
    log('[_addMediaStream] userId: $userId, isLocalStream: $isLocalStream',
        tag);

    if (primaryRenderer == null) {
      primaryRenderer = MapEntry(userId, RTCVideoRenderer());
      await primaryRenderer!.value.initialize();

      setState(() {
        _setSourceForRenderer(primaryRenderer!.value, stream, isLocalStream,
            trackId: trackId);

        chooseOpponentsStreamsQuality(_callSession, currentUserId, {
          userId: StreamType.high,
        });
      });

      return;
    }

    if (primaryRenderer?.key == userId) {
      _setSourceForRenderer(primaryRenderer!.value, stream, isLocalStream,
          trackId: trackId);

      chooseOpponentsStreamsQuality(_callSession, currentUserId, {
        userId: StreamType.high,
      });

      return;
    }

    if (minorRenderers[userId] == null) {
      minorRenderers[userId] = RTCVideoRenderer();
      await minorRenderers[userId]?.initialize();
    }

    setState(() {
      _setSourceForRenderer(minorRenderers[userId]!, stream, isLocalStream,
          trackId: trackId);

      if (primaryRenderer?.key == currentUserId ||
          primaryRenderer?.key == userId ||
          ((primaryRenderer?.value.srcObject?.getVideoTracks().isEmpty ??
                  false) &&
              stream.getVideoTracks().isNotEmpty)) {
        _updatePrimaryUser(userId, true);
      }
    });
  }

  _setSourceForRenderer(
      RTCVideoRenderer renderer, MediaStream stream, bool isLocalStream,
      {String? trackId}) {
    isLocalStream || kIsWeb
        ? renderer.srcObject = stream
        : renderer.setSrcObject(stream: stream, trackId: trackId);
  }

  void handlePublisherReceived(List<int?> publishers) {
    if (!_isIncoming) {
      for (var id in publishers) {
        if (id != null) {
          _callManager.handleAcceptCall(id);
        }
      }
    }

    if (publishers.isNotEmpty) {
      _callManager.requestParticipantsMediaConfig(publishers);
    }
  }

  void _updatePrimaryUser(int userId, bool force) {
    log("[_updatePrimaryUser] userId: $userId, force: $force", tag);

    log("[_updatePrimaryUser] 2", tag);
    updatePrimaryUser(
      userId,
      force,
      currentUserId,
      primaryRenderer,
      minorRenderers,
      participantsMediaConfigs,
      onRenderersUpdated: _updateRenderers,
    );
    log("[_updatePrimaryUser] 3", tag);
  }

  _updateRenderers(MapEntry<int, RTCVideoRenderer>? updatedPrimaryRenderer,
      Map<int, RTCVideoRenderer> updatedMinorRenderers) {
    if (updatedPrimaryRenderer?.key != primaryRenderer?.key) {
      chooseOpponentsStreamsQuality(_callSession, currentUserId, {
        if (updatedPrimaryRenderer?.key != null)
          updatedPrimaryRenderer!.key: StreamType.high,
        if (primaryRenderer?.key != null) primaryRenderer!.key: StreamType.low,
      });
    }

    primaryRenderer = updatedPrimaryRenderer;
    minorRenderers = updatedMinorRenderers;
  }

  _endCall() {
    _callManager.stopCall(_currentUser);
    _callSession.leave();
  }

  Future<void> _sendDataToCloud() async {
    final videoCallBloc = context.read<VideoCallBloc>();

    if (videoCallBloc.tutorId == null || videoCallBloc.studentId == null) {
      return;
    }

    context.read<VideoCallBloc>().add(
          SaveSessionToCloudEvent(
            saveSessionParams: SaveSessionParams(
              tutorId: videoCallBloc.tutorId!,
              studentId: videoCallBloc.studentId!,
              startDate: startDate!,
              meetingId: _meetingId,
              endDate: DateTime.now(),
              bookingId: bookingId,
              findForMeRequestId: findForMeRequestId,
              isIncoming: _isIncoming,
            ),
          ),
        );
  }

  _muteMic() {
    setState(() {
      _isMicMute = !_isMicMute;
      _callSession.setMicrophoneMute(_isMicMute);
      _callManager.muteMic(_meetingId, _isMicMute);
      notifyParticipantsMediaUpdated();
    });
  }

  _switchCamera() {
    if (!_isVideoEnabled()) return;
    _callSession.switchCamera().then((isFrontCameraUsed) {
      setState(() {
        _isFrontCameraUsed = isFrontCameraUsed;
      });
    });
  }

  _toggleCamera() {
    setState(() {
      _isCameraEnabled = !_isCameraEnabled;
      _callSession.setVideoEnabled(_isCameraEnabled);
      notifyParticipantsMediaUpdated();
    });
  }

  bool _isVideoEnabled() => _isVideoCall() && _isCameraEnabled;

  bool _isVideoCall() => CallType.VIDEO_CALL == _callSession.callType;

  _switchSpeaker() {
    setState(() {
      _isSpeakerEnabled = !_isSpeakerEnabled;
      _callSession.enableSpeakerphone(_isSpeakerEnabled);
    });
  }

  String _getCallName() => _callName;

  _startCallTimer() {
    return _callTimer.start(widget.conversationParams.startDate);
  }

  _stopCallTimer() => _callTimer.stop();

  void _onCallMuted(String meetingId, bool isMuted) {
    if (meetingId == _meetingId) {
      setState(() {
        _isMicMute = isMuted;
        _callSession.setMicrophoneMute(isMuted);
      });
    }
  }

  Map<String, bool> _getMediaState() => {
        PARAM_IS_MIC_ENABLED: !_isMicMute,
        PARAM_IS_CAMERA_ENABLED: _isCameraEnabled
      };

  void _onParticipantMediaUpdated(int userId, Map<String, bool> mediaConfig) {
    setState(() => participantsMediaConfigs[userId] = mediaConfig);
  }

  void notifyParticipantsMediaUpdated() {
    participantsMediaConfigs[currentUserId] = {
      PARAM_IS_MIC_ENABLED: !_isMicMute,
      PARAM_IS_CAMERA_ENABLED: _isCameraEnabled
    };

    _callManager.notifyParticipantsMediaUpdated({
      PARAM_IS_MIC_ENABLED: !_isMicMute,
      PARAM_IS_CAMERA_ENABLED: _isCameraEnabled
    });
  }

  void _onCallRejected(String meetingId) {
    final callRequestId = widget.conversationParams.callRequestId;
    if (callRequestId != null) {
      context.read<VideoCallBloc>().add(
            UpdateCallRequestEvent(
              requestId: widget.conversationParams.callRequestId!,
              callRequestStatus: CallRequestStatus.rejected,
            ),
          );
    }
    VideoCallNavigationManager.instance.disposeVideoCall(
      popPreviousRoute: false,
    );
  }
}

waleedqaefi avatar Apr 30 '24 22:04 waleedqaefi

Yesterday we had some updates related to the conference calls on our server. Could you try to reproduce your issue today? Can you reproduce your issue in our sample? Do you have similar issues there?

TatankaConCube avatar May 01 '24 07:05 TatankaConCube