-
Notifications
You must be signed in to change notification settings - Fork 431
Open
Description
- Followed the instructions 100% given in the (https://docs.agora.io/en/video-calling/advanced-features/screen-sharing?platform=flutter)
- All the features are working except the Screen Sharing Feature for IOS. For Android, it's working fine
The Issue I am facing right now:
- I press the Shere Screen button
- RPSystemBroadcastPickerView appears with the Broadcast Upload Extension Name
- I press on it and the countdown starts (3 - 2 -1)
- Count down stops, and there is no broadcasting happening
I have been working on this issue for the last 3 weeks and still can't find a working solution.
Solutions I have tried:
- I used AgoraReplayKitHandler (according to the documentation) (not working)
- I used SampleHandler with the required configuration and tried different code, and used sample code from different sources, including the sample projects from Agora. (Not working)
- I tried to create an Extension several times and failed
- I changed Dart(Flutter) code many times based on different samples from Agora and AI (failed)
- I tried decreasing the resolution of the video to the lowest didn't work out.
Here is the code sample:
AppDelegate.swift:
import Flutter
import UIKit
import ReplayKit
@main
@objc class AppDelegate: FlutterAppDelegate {
// private var videoRawDataController: VideoRawDataController?
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
// On low power mode, the system force keep the screen on for 30s only,
// we keep the screen on to help internal testing.
application.isIdleTimerDisabled = true
let controller = window?.rootViewController as! FlutterViewController
let screensharingIOSChannel = FlutterMethodChannel(
name: "com.example.adHocc/screen_sharing",
binaryMessenger: controller.binaryMessenger
)
screensharingIOSChannel.setMethodCallHandler { (call: FlutterMethodCall, result: @escaping FlutterResult) in
if #available(iOS 12.0, *) {
DispatchQueue.main.async {
if let url = Bundle.main.url(forResource: nil, withExtension: "appex", subdirectory: "PlugIns"),
let bundle = Bundle(url: url) {
let picker = RPSystemBroadcastPickerView(frame: CGRect(x: 0, y: 0, width: 100, height: 200))
picker.showsMicrophoneButton = true
picker.preferredExtension = bundle.bundleIdentifier
for view in picker.subviews {
if let button = view as? UIButton {
button.sendActions(for: .allTouchEvents)
}
}
}
}
}
}
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
ScreenShare Logic:
import 'dart:async';
import 'package:ad_hoc/services/implementations/platform_screen_sharing_service.dart';
import 'package:agora_rtc_engine/agora_rtc_engine.dart';
import 'package:flutter/foundation.dart';
import '../../../models/models.dart';
import '../../../modules/live_learning/utils/constants.dart'
show AgoraConstants;
import '../../../utils/logger_helper.dart';
import '../../service_locator.dart';
class AgoraScreenSharingService {
// Static class-level constants
static const bool _captureAudio = true;
static const bool _captureVideo = true;
RtcEngine? _rtcEngine;
bool _isScreenSharing = false;
UserRole? _userRole;
// Getters
bool get isScreenSharing => _isScreenSharing;
RtcEngine? get rtcEngine => _rtcEngine;
void initialize(RtcEngine rtcEngine, UserRole userRole, int localUid) {
_rtcEngine = rtcEngine;
_userRole = userRole;
}
Future<void> initializeScreenSharing() async {
if (_rtcEngine == null) return;
try {
// Load screen capture extension for Android
if (defaultTargetPlatform == TargetPlatform.android) {
await _rtcEngine!.loadExtensionProvider(
path: l10n.screen_capture_extension_name,
);
appLogMessage(
l10n.screen_capture_extension_loaded,
name: 'AgoraScreenSharingService',
);
}
} catch (e) {
appLogMessage(
'${l10n.screen_capture_extension_load_failed}: $e',
name: 'AgoraScreenSharingService',
);
}
}
Future<void> toggleScreenSharing() async {
if (_rtcEngine == null || _userRole != UserRole.instructor) return;
try {
if (_isScreenSharing) {
await _stopScreenSharing();
} else {
await _startScreenSharing();
}
} catch (e) {
appLogMessage(
'${l10n.screen_sharing_toggle_failed}: $e',
name: 'AgoraScreenSharingService',
);
_updateScreenSharingState(false);
}
}
Future<void> _startScreenSharing() async {
if (_rtcEngine == null) return;
try {
await _rtcEngine!.setClientRole(
role: ClientRoleType.clientRoleBroadcaster,
);
// Set very low video encoder configuration
await _rtcEngine!.setVideoEncoderConfiguration(
const VideoEncoderConfiguration(
dimensions: VideoDimensions(width: 320, height: 240),
frameRate: 5,
bitrate: 100,
),
);
if (defaultTargetPlatform == TargetPlatform.android) {
await _startScreenCapture();
} else if (defaultTargetPlatform == TargetPlatform.iOS) {
await PlatformScreenSharingService.showBroadcastPicker();
await _startScreenCapture();
}
_updateScreenSharingState(true);
await _updateChannelMediaOptions(true);
} catch (e) {
_updateScreenSharingState(false);
rethrow;
}
}
Future<void> _stopScreenSharing() async {
if (_rtcEngine == null) return;
try {
await _rtcEngine!.stopScreenCapture();
await _updateChannelMediaOptions(false);
_updateScreenSharingState(false);
} catch (e) {
rethrow;
}
}
Future<void> _startScreenCapture() async {
if (_rtcEngine == null) return;
await _rtcEngine!.startScreenCapture(
const ScreenCaptureParameters2(
captureAudio: _captureAudio,
// audioParams: ScreenAudioParameters(
// sampleRate: _defaultSampleRate,
// channels: _defaultChannels,
// captureSignalVolume: _defaultCaptureSignalVolume,
// ),
captureVideo: _captureVideo,
videoParams: ScreenVideoParameters(
dimensions: VideoDimensions(
width: 320, // Very low resolution
height: 240,
),
frameRate: 5, // Very low frame rate
bitrate: 100, // Very low bitrate
),
),
);
}
Future<void> _updateChannelMediaOptions(bool isScreenSharing) async {
if (_rtcEngine == null) return;
await _rtcEngine!.updateChannelMediaOptions(
ChannelMediaOptions(
publishScreenTrack: isScreenSharing,
publishSecondaryScreenTrack: isScreenSharing,
publishCameraTrack: !isScreenSharing,
publishMicrophoneTrack: !isScreenSharing,
publishScreenCaptureAudio: isScreenSharing,
publishScreenCaptureVideo: isScreenSharing,
clientRoleType: ClientRoleType.clientRoleBroadcaster,
),
);
}
void _updateScreenSharingState(bool isSharing) {
_isScreenSharing = isSharing;
}
/// Force stop screen sharing - used when session ends
Future<void> forceStopScreenSharing() async {
if (_rtcEngine == null) return;
try {
if (_isScreenSharing) {
await _rtcEngine!.stopScreenCapture();
await _updateChannelMediaOptions(false);
_updateScreenSharingState(false);
}
} catch (e) {
rethrow;
}
}
void dispose() {
// Force stop screen sharing before disposing
forceStopScreenSharing();
// Clear references
_rtcEngine = null;
_userRole = null;
_isScreenSharing = false;
appLogMessage(
'Screen sharing service disposed',
name: 'AgoraScreenSharingService',
);
}
}
I would really appreciate any help that you offer. Thank you so much.
Metadata
Metadata
Assignees
Labels
No labels