Skip to content

🐛 Screen Sharing status always false #1755

@AndreLiu1225

Description

@AndreLiu1225

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 -->

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions