Abir Ahsan
Abir Ahsan

Reputation: 3059

Flutter : Issue with Toggling video in WebRTC and PeerDart Video Calling App

I'm developing a video calling app using WebRTC and PeerDart in Flutter. The application is working fine for initiating and receiving calls, but I'm encountering an issue with toggling the video.

Here is the relevant part of my code:

Call Initiation and Listening for Room Join

final RTCVideoRenderer? localRenderer = RTCVideoRenderer();
final List<ProfileModel> remoteRenderers = [];

void listenRoomJoined() {
  SocketIOHelper.socket?.on(Constants.socketListenJoinRoom, (data) async {
    BaseClient.handleApiError(
        ApiException(url: "url", message: data['data']['type']));
    await createCall(
        userData: ProfileModel(
      id: data['data']['user']['id'],
      peerId: data['data']['peerId'],
      name: data['data']['user']['name'],
      avatar: data['data']['user']['avatar'],
      type: data['data']['type'],
    ));
  });
}

Future<void> createCall({required ProfileModel userData}) async {
  try {
    final mediaStream = await getUserMedia();

    final conn = peer.call(userData.peerId!, mediaStream);

    conn.on("close").listen((event) {
      inCall.value = false;
    });

    final dataConn = peer.connect(userData.peerId!);

    dataConn.on("open").listen((event) {
      ProfileModel? ownData = ProfileModel(
          id: MySharedPref.getUserId(),
          peerId: peer.id,
          type: arguments[1]['joinType'],
          name: MySharedPref.getUserName(),
          avatar: MySharedPref.getUserImage());
      String jsonString = jsonEncode(ownData.toJson());
      dataConn.send(jsonString);
    });

    conn.on<MediaStream>("stream").listen((event) {
      localRenderer?.srcObject = mediaStream;
      addRemoteRenderer(stream: event, userData: userData);

      inCall.value = true;
      update();
      for (var profile in remoteRenderers) {
        if (profile.peerId == userData.peerId) {
          if (userData.type != null) profile.type = userData.type;
          if (userData.id != null) profile.id = userData.id;
          if (userData.name != null) profile.name = userData.name;
          if (userData.avatar != null) profile.avatar = userData.avatar;
          update();
          break;
        }
      }
    });
    update();
  } catch (error) {
    Logger().e(error);
  }
}

Answering Calls

void joinAsRoomViewer() {
  String? userId = MySharedPref.getUserId();
  SocketIOHelper.socket?.emitWithAck(
      'STREAM_JOIN_ROOM_VIEWER',
      {
        "roomId": roomId,
        "userId": userId,
        "peerId": peer.id,
      },
      ack: (data) {});
  answerCall();
}

Future<void> answerCall() async {
  try {
    peer.on<MediaConnection>("call").listen((call) async {
      final mediaStream = await getUserMedia();

      call.answer(mediaStream);

      call.on("close").listen((event) {
        inCall.value = false;
      });

      call.on<MediaStream>("stream").listen((event) {
        localRenderer?.srcObject = mediaStream;
        addRemoteRenderer(
            stream: event,
            userData: ProfileModel(
              peerId: call.peer,
            ));
        inCall.value = true;
        update();
      });
    });
  } catch (error) {
    Logger().e(error);
  }
}

Getting User Media

Future<MediaStream> getUserMedia() async {
  await _stopMediaStream();

  Map<String, dynamic>? videoConstraints;
  if (useFrontCamera) {
    videoConstraints = {'facingMode': 'user'};
  } else {
    videoConstraints = {
      'facingMode': {'exact': 'environment'}
    };
  }

  final Map<String, dynamic> constraints = {
    'audio': isMicEnabled,
    'video': isVideoEnabled ? videoConstraints : false,
  };

  try {
    MediaStream? localStream =
        await navigator.mediaDevices.getUserMedia(constraints);

    if (localStream != null) {
      localRenderer?.srcObject = localStream;
      localStream.getVideoTracks().forEach((track) {
        track.enabled = isVideoEnabled;
      });
      localStream.getAudioTracks().forEach((track) {
        track.enabled = true;
      });
    } else {
      print('Failed to get user media');
    }
  } catch (e) {
    print('Error accessing user media: $e');
  }

  return localRenderer!.srcObject!;
}

Future<void> _stopMediaStream() async {
  if (localRenderer?.srcObject != null) {
    localRenderer?.srcObject!.getTracks().forEach((track) {
      track.stop();
    });
    localRenderer?.srcObject = null;
  }
}

Toggle Video Function

void toggleVideo() async {
  isVideoEnabled = !isVideoEnabled;
  await getUserMedia();
  update();

  await SocketIOHelper.emit(
    Constants.socketToggleVideo,
    {
      "roomId": roomId,
      "userId": MySharedPref.getUserId(),
      "peerId": peer.id,
      "status": isVideoEnabled,
    },
  );
}

Problem

The video toggle works partially. When I turn off the video, the stream stops as expected. However, when I try to turn the video back on, the stream does not restart for other users in the room How can I modify my code to ensure that when the video is toggled back on, the stream starts correctly for other users?

Any suggestions or pointers would be greatly appreciated. Thank you!

Upvotes: 1

Views: 157

Answers (0)

Related Questions