100mslive/100ms-flutter

๐Ÿ› Screen Sharing status always false

AndreLiu1225 opened this issue ยท 7 comments

Description

Hello! I am unable to display a screen share on my Iphone (not simulator) that I am using for debugging. isScreenShareActive() always returns false and a screen share tile does not show.

Following the steps in this documentation https://www.100ms.live/docs/flutter/v2/how-to-guides/set-up-video-conferencing/screen-share#how-to-startstop-screenshare-from-the-app. I have done the following:

  • Implemented startScreenShare() and stopScreenShare() override methods
  • Added in switch cases in onSucces(), onTrackUpdate, and onException() for screenSharing

100ms Flutter Version

1.9.13

Steps to reproduce

Run Debug Mode in main.dart
Press Join Button
Press ScreenShare button

Expected results

I expected a screen sharing tile to pop up and the screen sharing button color to change to green.

Code example, screenshot, or link to a repository

meetingPage.dart

import 'package:flutter/material.dart';
import 'package:hmssdk_flutter/hmssdk_flutter.dart';
import 'package:translator/pages/homePage.dart';
import 'package:translator/widgets/peerTileWidget.dart';

class MeetingPage extends StatefulWidget {
  const MeetingPage({super.key});
  @override
  State<MeetingPage> createState() => _MeetingPageState();
}

class _MeetingPageState extends State<MeetingPage>
    implements HMSUpdateListener, HMSActionResultListener {
  //SDK
  late HMSSDK hmsSDK;

  // Variables required for joining a room
  String authToken =
      "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2ZXJzaW9uIjoyLCJ0eXBlIjoiYXBwIiwiYXBwX2RhdGEiOm51bGwsImFjY2Vzc19rZXkiOiI2NjA3YTcwOGJhYmMzM2YwMGU0YWI4OTIiLCJyb2xlIjoiaG9zdCIsInJvb21faWQiOiI2NjA3YTcxZmNiMWIxZjA2M2FjZmMwYmQiLCJ1c2VyX2lkIjoiZGQ3ZDA0MmEtNzRiOC00MThkLTg1NzktNmEyMDBiZDc2NGM1IiwiZXhwIjoxNzExODkzOTIwLCJqdGkiOiJmZDFiMTkyNC05NjQ3LTRlMTEtYTlhMi04ZmZiZjFlOTliMmMiLCJpYXQiOjE3MTE4MDc1MjAsImlzcyI6IjY2MDdhNzA4YmFiYzMzZjAwZTRhYjg5MCIsIm5iZiI6MTcxMTgwNzUyMCwic3ViIjoiYXBpIn0.hvEpCMJLXGBfPRRWtQlLrrX553ulDL1GwsOi-udD4XU";
  String userName = "test_user";

  // Variables required for rendering video and peer info
  HMSPeer? localPeer, remotePeer;
  HMSVideoTrack? localPeerVideoTrack,
      remotePeerVideoTrack,
      localScreenShareTrack,
      remoteScreenShareTrack;

  // Pass the correct App Group & Preferred Extension Parameters in HMSScreenShareConfig class for screen share on IOS devices
  HMSIOSScreenshareConfig iOSScreenshareConfig = HMSIOSScreenshareConfig(
      appGroup: "group.com.example.translator",
      preferredExtension: "flutterBroadCast");

  // Screen sharing bool
  bool isScreenSharing = false;

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

  void initHMSSDK() async {
    hmsSDK = HMSSDK(iOSScreenshareConfig: iOSScreenshareConfig);
    await hmsSDK.build();
    hmsSDK.addUpdateListener(listener: this);
    hmsSDK.join(config: HMSConfig(authToken: authToken, userName: userName));
    checkScreenShareStatus();
  }

  @override
  void dispose() {
    remotePeer = null;
    remotePeerVideoTrack = null;
    localPeer = null;
    localPeerVideoTrack = null;
    localScreenShareTrack = null;
    remoteScreenShareTrack = null;
    super.dispose();
  }

  // Called when peer joined the room - get current state of room by using HMSRoom obj
  @override
  void onJoin({required HMSRoom room}) {
    room.peers?.forEach((peer) {
      if (peer.isLocal) {
        localPeer = peer;
        if (peer.videoTrack != null) {
          localPeerVideoTrack = peer.videoTrack;
        }
        if (mounted) {
          setState(() {});
        }
      }
    });
  }

  // Called when there's a peer update - use to update local & remote peer variables
  @override
  void onPeerUpdate({required HMSPeer peer, required HMSPeerUpdate update}) {
    switch (update) {
      case HMSPeerUpdate.peerJoined:
        if (!peer.isLocal) {
          if (mounted) {
            setState(() {
              remotePeer = peer;
            });
          }
        }
        break;
      case HMSPeerUpdate.peerLeft:
        if (!peer.isLocal) {
          if (mounted) {
            setState(() {
              remotePeer = null;
            });
          }
        }
        break;
      case HMSPeerUpdate.networkQualityUpdated:
        return;
      default:
        if (mounted) {
          setState(() {
            localPeer = null;
          });
        }
    }
  }

  // Called when there's a track update - use to update local & remtoe track variable
  @override
  void onTrackUpdate(
      {required HMSTrack track,
      required HMSTrackUpdate trackUpdate,
      required HMSPeer peer}) {
    if (track.kind == HMSTrackKind.kHMSTrackKindVideo) {
      switch (trackUpdate) {
        case HMSTrackUpdate.trackRemoved:
          if (mounted) {
            setState(() {
              peer.isLocal
                  ? localPeerVideoTrack = null
                  : remotePeerVideoTrack = null;
            });
          }
          return;
        default:
          if (mounted) {
            setState(() {
              peer.isLocal
                  ? localPeerVideoTrack = track as HMSVideoTrack
                  : remotePeerVideoTrack = track as HMSVideoTrack;
            });
          }
      }
    }
    if (track.source == "SCREEN") {
      switch (trackUpdate) {
        case HMSTrackUpdate.trackAdded:
          if (mounted) {
            setState(() {
              peer.isLocal
                  ? localScreenShareTrack = track as HMSVideoTrack
                  : remoteScreenShareTrack = track as HMSVideoTrack;
              isScreenSharing = true;
            });
          }
          break;
        case HMSTrackUpdate.trackRemoved:
          if (mounted) {
            setState(() {
              peer.isLocal
                  ? localScreenShareTrack = null
                  : remoteScreenShareTrack = null;
              isScreenSharing = false;
            });
          }
          break;
        default:
          break;
      }
    }
  }

  // More callbacks - no need to implement for quickstart
  @override
  void onAudioDeviceChanged(
      {HMSAudioDevice? currentAudioDevice,
      List<HMSAudioDevice>? availableAudioDevice}) {}

  @override
  void onSessionStoreAvailable({HMSSessionStore? hmsSessionStore}) {}

  @override
  void onChangeTrackStateRequest(
      {required HMSTrackChangeRequest hmsTrackChangeRequest}) {}

  @override
  void onHMSError({required HMSException error}) {}

  @override
  void onMessage({required HMSMessage message}) {}

  @override
  void onReconnected() {}

  @override
  void onReconnecting() {}

  @override
  void onRemovedFromRoom(
      {required HMSPeerRemovedFromPeer hmsPeerRemovedFromPeer}) {}

  @override
  void onRoleChangeRequest({required HMSRoleChangeRequest roleChangeRequest}) {}

  @override
  void onRoomUpdate({required HMSRoom room, required HMSRoomUpdate update}) {}

  @override
  void onUpdateSpeakers({required List<HMSSpeaker> updateSpeakers}) {}

  @override
  void onPeerListUpdate(
      {required List<HMSPeer> addedPeers,
      required List<HMSPeer> removedPeers}) {
    // TODO: implement onPeerListUpdate
  }

  /*----------------------------Screen Sharing Implementation-----------------------------*/
  void checkScreenShareStatus() {
    hmsSDK.isScreenShareActive().then((screenShareStatus) {
      print("Screen sharing status: $screenShareStatus");
    });
  }

  void startScreenShare() {
    ///[hmsActionResultListener]: an instance of a class that implements HMSActionResultListener
    //Here this is an instance of a class that implements HMSActionResultListener, that is, Meeting
    hmsSDK.startScreenShare(hmsActionResultListener: this);
    checkScreenShareStatus();
  }

  void stopScreenShare() {
    ///[hmsActionResultListener]: an instance of a class that implements HMSActionResultListener
    //Here this is an instance of a class that implements HMSActionResultListener, that is, Meeting
    hmsSDK.stopScreenShare(hmsActionResultListener: this);
    checkScreenShareStatus();
  }

  @override
  void onSuccess(
      {HMSActionResultListenerMethod methodType =
          HMSActionResultListenerMethod.unknown,
      Map<String, dynamic>? arguments}) {
    switch (methodType) {
      case HMSActionResultListenerMethod.startScreenShare:
        //Screen share started successfully
        isScreenSharing = true;
        break;

      case HMSActionResultListenerMethod.stopScreenShare:
        //Screen share stopped successfully
        isScreenSharing = false;
        break;

      case HMSActionResultListenerMethod.leave:
        return;
      default:
        break;
    }
  }

  @override
  void onException(
      {HMSActionResultListenerMethod methodType =
          HMSActionResultListenerMethod.unknown,
      Map<String, dynamic>? arguments,
      required HMSException hmsException}) {
    switch (methodType) {
      case HMSActionResultListenerMethod.startScreenShare:
        // Check the HMSException object for details about the error
        break;

      case HMSActionResultListenerMethod.stopScreenShare:
        // Check the HMSException object for details about the error
        break;

      case HMSActionResultListenerMethod.leave:
        return;
      default:
        break;
    }
  }

  @override
  Widget build(BuildContext context) {
    return PopScope(
      canPop: true,
      onPopInvoked: (didPop) async {
        hmsSDK.leave();
        WidgetsBinding.instance.addPostFrameCallback((_) {
          Navigator.pushReplacement(
              context, MaterialPageRoute(builder: (_) => HomePage()));
        });
      },
      child: SafeArea(
        child: Scaffold(
          backgroundColor: Colors.black,
          body: Stack(
            children: [
              // Grid of peer tiles
              Container(
                height: MediaQuery.of(context).size.height,
                child: GridView(
                  gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                      mainAxisExtent: (remotePeerVideoTrack == null)
                          ? MediaQuery.of(context).size.height
                          : MediaQuery.of(context).size.height / 2,
                      crossAxisCount: 1),
                  children: [
                    if (remotePeerVideoTrack != null && remotePeer != null)
                      peerTile(
                          Key(remotePeerVideoTrack?.trackId ?? "" "mainVideo"),
                          remotePeerVideoTrack,
                          remoteScreenShareTrack,
                          remotePeer),
                    peerTile(
                        Key(localPeerVideoTrack?.trackId ?? "" "mainVideo"),
                        localPeerVideoTrack,
                        localScreenShareTrack,
                        localPeer),
                  ],
                ),
              ),
              // End button to leave the room
              Align(
                alignment: Alignment.bottomCenter,
                child: RawMaterialButton(
                  onPressed: () {
                    hmsSDK.leave();
                    Navigator.pop(context);
                  },
                  elevation: 2.0,
                  fillColor: Colors.red,
                  padding: const EdgeInsets.all(15.0),
                  shape: const CircleBorder(),
                  child: const Icon(
                    Icons.call_end,
                    size: 25.0,
                    color: Colors.white,
                  ),
                ),
              ),
              // End button to leave the room
              Align(
                alignment: Alignment.bottomRight,
                child: RawMaterialButton(
                  onPressed: () {
                    if (!isScreenSharing) {
                      startScreenShare();
                    } else {
                      stopScreenShare();
                    }
                  },
                  elevation: 2.0,
                  fillColor: isScreenSharing ? Colors.green : Colors.grey[850],
                  padding: const EdgeInsets.all(15.0),
                  shape: const CircleBorder(),
                  child: const Icon(
                    Icons.screen_share_outlined,
                    size: 25.0,
                    color: Colors.white,
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

peerTileWidget.dart

import 'package:flutter/material.dart';
import 'package:hmssdk_flutter/hmssdk_flutter.dart';

Widget peerTile(Key key, HMSVideoTrack? regularVideoTrack,
    HMSVideoTrack? screenShareTrack, HMSPeer? peer) {
  return Container(
    key: key,
    child: (screenShareTrack != null)
        ? HMSVideoView(
            track: screenShareTrack,
            scaleType: ScaleType.SCALE_ASPECT_FIT,
            key: key,
          )
        : (regularVideoTrack != null && !(regularVideoTrack.isMute))
            ? HMSVideoView(
                track: regularVideoTrack,
                scaleType: ScaleType.SCALE_ASPECT_FILL,
                key: key,
              )
            : Center(
                child: Container(
                  decoration: BoxDecoration(
                    color: Colors.blue.withAlpha(4),
                    shape: BoxShape.circle,
                    boxShadow: const [
                      BoxShadow(
                        color: Colors.blue,
                        blurRadius: 20.0,
                        spreadRadius: 5.0,
                      ),
                    ],
                  ),
                  child: Text(
                    peer?.name.substring(0, 1) ?? "Translate",
                    style: const TextStyle(
                      fontFamily: "Sans-serif",
                      color: Colors.white,
                      fontSize: 24,
                      fontWeight: FontWeight.w600,
                    ),
                  ),
                ),
              ),
  );
}


Logs

Logs
<!-- Paste your logs here -->

Flutter Doctor output

Doctor output
<!-- Paste your output here -->

Hello! Thank you for filing an issue.

Please include relevant logs or detailed description for faster resolutions.

We really appreciate your contribution!

ygit commented

hey @AndreLiu1225
Can you try reproducing this on the latest version of hmssdk_flutter which is 1.9.14?
The version you mentioned - 1.0.0 is very old.

hey @AndreLiu1225 Can you try reproducing this on the latest version of hmssdk_flutter which is 1.9.14? The version you mentioned - 1.0.0 is very old.

Hi there! Im so sorry! It's a typo, the version I;m using is 1.9.13

@AndreLiu1225 are you able to see screenshare on the other end ?

Nope, the screen share is just not active. I'm guessing that the screenShareTrack is null

@AndreLiu1225 are you able to see screenshare on the other end ?

If I'm not wrong upon pressing the screen sharing button, a screen broadcast pop up would appear and u could choose the app's broadcast extension, but nothing pops up.

Upon closer inspection, I realised the auth token was updated and that I was using an outdated one. @ygit @Decoder07 Thank u so much for ur time!