Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

5.3.1 Flutter Web Screen Sharing #1212

Closed
Sypzer opened this issue Jul 12, 2023 · 3 comments
Closed

5.3.1 Flutter Web Screen Sharing #1212

Sypzer opened this issue Jul 12, 2023 · 3 comments
Labels
waiting for customer response waiting for customer response, or closed by no-reponse bot

Comments

@Sypzer
Copy link

Sypzer commented Jul 12, 2023

I am using the version 5.3.1 specially for the feature of screen sharing on flutter web. I understand if this version is not supported anymore. However, maybe you could provide me with some intel. The video calling works great! I am not facing any issues with that. The only problem appears on screen sharing. 'CAN_NOT_PUBLISH_MULTIPLE_VIDEO_TRACKS'.

The app opens on using the camera and microphone. During the call the user can start screen sharing.
I tried muting the local video, start screen sharing then unmute the local video, but this does not seem to affect it.
5 months ago I could make it work, but I do not have that code, and I am pretty sure I did not do it differently.


import 'dart:async';
import 'dart:developer';
import 'dart:html' as html;

import 'package:agora_rtc_engine/rtc_engine.dart';
import 'package:agora_rtc_engine/rtc_local_view.dart' as RtcLocalView;
import 'package:agora_rtc_engine/rtc_remote_view.dart' as RtcRemoteView;
import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';



class VideoCallRoom extends StatefulWidget {
  const VideoCallRoom({super.key});

  @override
  VideoCallRoomState createState() => VideoCallRoomState();
}

class VideoCallRoomState extends State<VideoCallRoom> {
  late final RtcEngine _engine;

  bool isJoined = false,
      enabledAudio = true,
      enableCamera = true,
      shareScreen = false;
  int? _remoteUid;

  @override
  void initState() {
    super.initState();
    _initEngine();
  }

  @override
  void dispose() {
    super.dispose();
    _dispose();
  }

  Future<void> _dispose() async {
    await _engine.stopScreenCapture();
    await _engine.leaveChannel();
    await _engine.destroy();
  }

  Future<void> _startScreenShare() async {
    if (!shareScreen) {
      if (_engine != null) {
        await _engine.startScreenCaptureByDisplayId(0);

        setState(() {
          shareScreen = true;
        });
      }
    } else {
      if (_engine != null) {
        await _engine!.stopScreenCapture();
        // Potentially restart the camera feed here
        setState(() {
          shareScreen = false;
        });
      }
    }
  }

  Future<void> _initEngine() async {
    await html.window.navigator.getUserMedia(audio: true, video: true);
    //await <Permission>[Permission.microphone, Permission.camera].request();
    _engine =
        await RtcEngine.create(......);
    await _engine.enableVideo();

    _engine.setEventHandler(
      RtcEngineEventHandler(
        joinChannelSuccess: (String channelName, int uid, int elapsed) {
          setState(() {
            isJoined = true;
          });
        },
        userJoined: (int uid, int elapsed) {
          print("remote user $uid joined");
          setState(() {
            _remoteUid = uid;
          });
        },
        userOffline: (int uid, UserOfflineReason reason) {
          print("remote user $uid left channel");
          setState(() {
            _remoteUid = null;
          });
        },
      ),
    );

    _joinChannel();
  }

  Future<void> _joinChannel() async {
    log('joined channed: _engine.joinChannel(' ', ....., null, 0)');
    await _engine.joinChannel('', ..... , null, 232);
  }

  Future<void> _toggleMicrophone() async {
    await _engine.enableLocalAudio(!enabledAudio);
    setState(() {
      enabledAudio = !enabledAudio;
    });
  }

  Future<void> _toggleCamera() async {
    await _engine.enableLocalVideo(!enableCamera);
    setState(() {
      enableCamera = !enableCamera;
    });
  }

  Future<void> _leaveChannel() async {
    await _engine.stopScreenCapture();
    await _engine.leaveChannel();
    Navigator.of(context).pop();
  }

  Widget _remoteVideo() {
    if (_remoteUid != null) {
      return RtcRemoteView.SurfaceView(
        uid: _remoteUid!,
        channelId: '.......',
      );
    } else {
      return Text(
        'Please wait for remote user to join',
        textAlign: TextAlign.center,
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: WillPopScope(
        onWillPop: () async {
          return false;
        },
        child: Scaffold(
          body: Stack(
            children: <Widget>[
              Container(
                color: Colors.red,
                child: Center(child: _remoteVideo()),
              ),
              Positioned(
                bottom: 90,
                right: 0,
                child: Container(
                  height: 240,
                  width: 400,
                  color: Colors.black,
                  child: isJoined
                      ? const RtcLocalView.SurfaceView()
                      : const Center(
                          child: CircularProgressIndicator(),
                        ),
                ),
              ),
              Positioned(
                  bottom: 0,
                  child: Container(
                    height: 90,
                    color: Colors.black.withOpacity(0.3),
                    width: MediaQuery.of(context).size.width,
                    child: Row(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: <Widget>[
                        MouseRegion(
                          cursor: SystemMouseCursors.click,
                          child: GestureDetector(
                            onTap: () {
                              _toggleMicrophone();
                            },
                            child: Container(
                              height: 48,
                              width: 48,
                              decoration: BoxDecoration(
                                borderRadius: BorderRadius.circular(24),
                                color: Colors.white,
                              ),
                              child: Center(
                                child: Icon(
                                  enabledAudio ? Icons.mic : Icons.mic_off_rounded,
                                  color: Colors.black,
                                ),
                              ),
                            ),
                          ),
                        ),
                        const SizedBox(
                          width: 16,
                        ),
                        MouseRegion(
                          cursor: SystemMouseCursors.click,
                          child: GestureDetector(
                            onTap: () {
                              _leaveChannel();
                            },
                            child: Container(
                              height: 48,
                              width: 48,
                              decoration: BoxDecoration(
                                borderRadius: BorderRadius.circular(24),
                                color: Colors.red,
                              ),
                              child: const Center(
                                child: Icon(
                                  Icons.call_end,
                                  color: Colors.white,
                                ),
                              ),
                            ),
                          ),
                        ),
                        const SizedBox(
                          width: 16,
                        ),
                        MouseRegion(
                          cursor: SystemMouseCursors.click,
                          child: GestureDetector(
                            onTap: () {
                              _toggleCamera();
                            },
                            child: Container(
                              height: 48,
                              width: 48,
                              decoration: BoxDecoration(
                                borderRadius: BorderRadius.circular(24),
                                color: Colors.white,
                              ),
                              child: Stack(
                                children: <Widget>[
                                  const Center(
                                    child: Icon(
                                      Icons.video_camera_front_outlined,
                                      color: Colors.black,
                                    ),
                                  ),
                                  if (!enableCamera)
                                    const Center(
                                      child: Icon(
                                        Icons.cancel_outlined,
                                        size: 38,
                                      ),
                                    )
                                ],
                              ),
                            ),
                          ),
                        ),
                        SizedBox(
                          width: 16,
                        ),
                        MouseRegion(
                          cursor: SystemMouseCursors.click,
                          child: GestureDetector(
                            onTap: () {
                              _startScreenShare();
                            },
                            child: Container(
                              height: 48,
                              width: 48,
                              decoration: BoxDecoration(
                                borderRadius: BorderRadius.circular(24),
                                color: Colors.white,
                              ),
                              child: Center(
                                child: Icon(
                                  shareScreen ? Icons.stop_circle : Icons.screen_share,
                                  color: Colors.black,
                                ),
                              ),
                            ),
                          ),
                        )
                      ],
                    ),
                  )),
            ],
          ),
        ),
      ),
    );
    // if (!_isInit) return Container();
  }
}
  • Browser [chrome]
@Sypzer
Copy link
Author

Sypzer commented Jul 12, 2023

by changing the startShareScreen function to:

`  
Future _startScreenShare() async {
    if (!shareScreen) {
      if (_engine != null) {
        await _engine.muteLocalVideoStream(true);  // stop the camera feed
        await _engine.startScreenCaptureByDisplayId(0);
        await _engine.muteLocalVideoStream(false);  // stop the camera feed

        setState(() {
          shareScreen = true;
        });
      }
    } else {
      if (_engine != null) {
        await _engine.stopScreenCapture();
        //await _engine.muteLocalVideoStream(false);  // restart the camera feed
        setState(() {
          shareScreen = false;
        });
      }
    }
  }
`

The error is not shown anymore, but the remote only seems to retrieve upon the mute, the last camera frame, but the share screen is not visible,

Also, upon await _engine.stopScreenCapture();, the remote view that was stuck on the last camera frame does not start to retrieve the and remains stuck on the last frame.

@littleGnAl
Copy link
Collaborator

I think you may need to use a subprocess to start screen sharing with 5.x

@littleGnAl littleGnAl added the waiting for customer response waiting for customer response, or closed by no-reponse bot label Jul 13, 2023
@Sypzer Sypzer closed this as completed Jul 27, 2023
@github-actions
Copy link
Contributor

github-actions bot commented Aug 3, 2023

This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please raise a new issue.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 3, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
waiting for customer response waiting for customer response, or closed by no-reponse bot
Projects
None yet
Development

No branches or pull requests

2 participants