Skip to content

Commit

Permalink
fix(screensharing): set setScreenShareEnabled when detect replaykit s…
Browse files Browse the repository at this point in the history
…tate changed (#398)

Co-authored-by: CloudWebRTC <[email protected]>
  • Loading branch information
lambiengcode and cloudwebrtc authored Dec 12, 2023
1 parent f5c681d commit 7f5c0ba
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 7 deletions.
16 changes: 16 additions & 0 deletions example/ios/LiveKit Broadcast Extension/SampleHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ class SampleHandler: RPBroadcastSampleHandler {

DarwinNotificationCenter.shared.postNotification(.broadcastStarted)
openConnection()
startReplayKit()
}

override func broadcastPaused() {
Expand All @@ -57,6 +58,8 @@ class SampleHandler: RPBroadcastSampleHandler {
// User has requested to finish the broadcast.
DarwinNotificationCenter.shared.postNotification(.broadcastStopped)
clientConnection?.close()
closeReplayKit()

}

override func processSampleBuffer(_ sampleBuffer: CMSampleBuffer, with sampleBufferType: RPSampleBufferType) {
Expand Down Expand Up @@ -100,4 +103,17 @@ private extension SampleHandler {

timer.resume()
}

func startReplayKit() {
let group=UserDefaults(suiteName: Constants.appGroupIdentifier)
group!.set(false, forKey: "closeReplayKitFromNative")
group!.set(false, forKey: "closeReplayKitFromFlutter")
group!.set(true, forKey: "hasSampleBroadcast")
}

func closeReplayKit() {
let group = UserDefaults(suiteName: Constants.appGroupIdentifier)
group!.set(true, forKey:"closeReplayKitFromNative")
group!.set(false, forKey: "hasSampleBroadcast")
}
}
71 changes: 64 additions & 7 deletions example/ios/Runner/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,68 @@ import Flutter

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}

var replayKitChannel: FlutterMethodChannel! = nil
var observeTimer: Timer?
var hasEmittedFirstSample = false;

override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
guard let controller = window?.rootViewController as? FlutterViewController else {
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}

replayKitChannel = FlutterMethodChannel(name: "io.livekit.example.flutter/replaykit-channel",binaryMessenger: controller.binaryMessenger)

replayKitChannel.setMethodCallHandler({
(call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
self.handleReplayKitFromFlutter(result: result, call:call)
})

GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}

func handleReplayKitFromFlutter(result:FlutterResult, call: FlutterMethodCall){
switch (call.method) {
case "startReplayKit":
self.hasEmittedFirstSample = false
let group=UserDefaults(suiteName: "group.io.livekit.example.flutter")
group!.set(false, forKey: "closeReplayKitFromNative")
group!.set(false, forKey: "closeReplayKitFromFlutter")
self.observeReplayKitStateChanged()
break
case "closeReplayKit":
let group=UserDefaults(suiteName: "group.io.livekit.example.flutter")
group!.set(true,forKey: "closeReplayKitFromFlutter")
result(true)
break
default:
return result(FlutterMethodNotImplemented)
}
}

func observeReplayKitStateChanged(){
if (self.observeTimer != nil) {
return
}

let group=UserDefaults(suiteName: "group.io.livekit.example.flutter")
self.observeTimer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { (timer) in
let closeReplayKitFromNative=group!.bool(forKey: "closeReplayKitFromNative")
let hasSampleBroadcast=group!.bool(forKey: "hasSampleBroadcast")

if (closeReplayKitFromNative) {
self.hasEmittedFirstSample = false
self.replayKitChannel.invokeMethod("closeReplayKitFromNative", arguments: true)
} else if (hasSampleBroadcast) {
if (!self.hasEmittedFirstSample) {
self.hasEmittedFirstSample = true
self.replayKitChannel.invokeMethod("hasSampleBroadcast", arguments: true)
}
}
}
}
}
40 changes: 40 additions & 0 deletions example/lib/method_channels/replay_kit_channel.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Dart imports:
import 'dart:io';

// Flutter imports:
import 'package:flutter/services.dart';
import 'package:livekit_client/livekit_client.dart';

class ReplayKitChannel {
static const String kReplayKitChannel =
'io.livekit.example.flutter/replaykit-channel';

static const MethodChannel _replayKitChannel =
MethodChannel(kReplayKitChannel);

static void listenMethodChannel(Room room) {
_replayKitChannel.setMethodCallHandler((call) async {
if (call.method == 'closeReplayKitFromNative') {
if (!(room.localParticipant?.isScreenShareEnabled() ?? false)) return;

await room.localParticipant?.setScreenShareEnabled(false);
} else if (call.method == 'hasSampleBroadcast') {
if (room.localParticipant?.isScreenShareEnabled() ?? true) return;

await room.localParticipant?.setScreenShareEnabled(true);
}
});
}

static void startReplayKit() {
if (!Platform.isIOS) return;

_replayKitChannel.invokeMethod('startReplayKit');
}

static void closeReplayKit() {
if (!Platform.isIOS) return;

_replayKitChannel.invokeMethod('closeReplayKit');
}
}
17 changes: 17 additions & 0 deletions example/lib/pages/room.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'dart:math' as math;

import 'package:flutter/material.dart';
import 'package:livekit_client/livekit_client.dart';
import 'package:livekit_example/method_channels/replay_kit_channel.dart';

import '../exts.dart';
import '../utils.dart';
Expand All @@ -30,6 +31,7 @@ class _RoomPageState extends State<RoomPage> {
List<ParticipantTrack> participantTracks = [];
EventsListener<RoomEvent> get _listener => widget.listener;
bool get fastConnection => widget.room.engine.fastConnectOptions != null;
bool _flagStartedReplayKit = false;
@override
void initState() {
super.initState();
Expand All @@ -48,6 +50,8 @@ class _RoomPageState extends State<RoomPage> {
Hardware.instance.setSpeakerphoneOn(true);
}

ReplayKitChannel.listenMethodChannel(widget.room);

if (lkPlatformIsDesktop()) {
onWindowShouldClose = () async {
unawaited(widget.room.disconnect());
Expand All @@ -61,6 +65,7 @@ class _RoomPageState extends State<RoomPage> {
void dispose() {
// always dispose listener
(() async {
ReplayKitChannel.closeReplayKit();
widget.room.removeListener(_onRoomDidUpdate);
await _listener.dispose();
await widget.room.dispose();
Expand Down Expand Up @@ -199,12 +204,24 @@ class _RoomPageState extends State<RoomPage> {
if (localParticipantTracks != null) {
for (var t in localParticipantTracks) {
if (t.isScreenShare) {
if (!_flagStartedReplayKit) {
_flagStartedReplayKit = true;

ReplayKitChannel.startReplayKit();
}

screenTracks.add(ParticipantTrack(
participant: widget.room.localParticipant!,
videoTrack: t.track,
isScreenShare: true,
));
} else {
if (_flagStartedReplayKit) {
_flagStartedReplayKit = false;

ReplayKitChannel.closeReplayKit();
}

userMediaTracks.add(ParticipantTrack(
participant: widget.room.localParticipant!,
videoTrack: t.track,
Expand Down

0 comments on commit 7f5c0ba

Please sign in to comment.