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

release v1.2.0 #123

Merged
merged 6 commits into from
Mar 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/pub-score.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ on:
pull_request:
branches:
- "main"
push:
branches: ["main"]

jobs:

Expand Down
9 changes: 8 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
# 1.1.2
## 1.2.0

- Added screen sharing for Android/iOS
- Added layout for one to one video calling
- Fixes issue [#122](https://github.com/AgoraIO-Community/VideoUIKit-Flutter/issues/122)


## 1.1.2

- Fixes issue [#115](https://github.com/AgoraIO-Community/VideoUIKit-Flutter/issues/115)
- Fixes view of remote user with a disabled video
Expand Down
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
<a href="https://pub.dev/packages/agora_uikit"><img src="https://img.shields.io/pub/popularity/agora_uikit?logo=dart"/></a>
<a href="https://pub.dev/packages/agora_uikit"><img src="https://img.shields.io/pub/points/agora_uikit?logo=dart"/></a><br/>
<img src="https://img.shields.io/badge/Platform-iOS%20%7C%20Android-blue?logo=flutter" alt="Platform" />
<img alt="GitHub Workflow Status" src="https://img.shields.io/github/workflow/status/AgoraIO-Community/VideoUIKit-Flutter/Flutter">
<img alt="GitHub Workflow Status" src="https://img.shields.io/github/actions/workflow/status/AgoraIO-Community/VideoUIKit-Flutter/pub-score.yml?branch=main
">
<a href="https://pub.dev/packages/agora_uikit"><img src="https://img.shields.io/pub/v/agora_uikit"/></a>
<img src="https://img.shields.io/github/license/agoraio-community/videouikit-flutter?color=red"
alt="License: MIT" />
Expand All @@ -30,7 +31,8 @@ Instantly integrate Agora video calling or video streaming into your Flutter app
- [ ] Add Usernames
- [x] More Event Callbacks
- [x] Add RTM SDK
- [ ] Screen Sharing
- [x] Screen Sharing (Currently in Beta)
- [x] Layout for One to One Video Call
- [ ] Layout for Voice Calls
- [ ] Re-orderable list view (Floating Layout)
- [ ] Cloud recording
Expand Down Expand Up @@ -137,4 +139,3 @@ Widget build(BuildContext context) {
## VideoUIKits

The plan is to grow this library and have similar offerings across all supported platforms. There are already similar libraries for [Android](https://github.com/AgoraIO-Community/VideoUIKit-Android/), [iOS](https://github.com/AgoraIO-Community/VideoUIKit-iOS/), [React Native](https://github.com/AgoraIO-Community/ReactNative-UIKit), and [Web React](https://github.com/AgoraIO-Community/VideoUIKit-Web-React), so be sure to check them out.

2 changes: 2 additions & 0 deletions example/android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>

<application
android:label="Agora UIKit"
android:icon="@mipmap/ic_launcher">
Expand Down
15 changes: 15 additions & 0 deletions example/ios/Example_ScreenSharing_Extension/Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSExtension</key>
<dict>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.broadcast-services-upload</string>
<key>NSExtensionPrincipalClass</key>
<string>$(PRODUCT_MODULE_NAME).SampleHandler</string>
<key>RPBroadcastProcessMode</key>
<string>RPBroadcastProcessModeSampleBuffer</string>
</dict>
</dict>
</plist>
20 changes: 20 additions & 0 deletions example/ios/Example_ScreenSharing_Extension/SampleHandler.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//
// SampleHandler.swift
// Example_ScreenSharing_Extension
//
// Created by Meherdeep Thakur on 03/02/23.
//

import ReplayKit
import AgoraBroadcastExtensionHelper

class SampleHandler: AgoraBroadcastSampleHandler {
override func getBroadcastData() -> AgoraBroadcastExtData? {
return AgoraBroadcastExtData(
appId: "<#Agora App ID#>",
channel: "<#Channel Name#>",
token: <#Token or nil#>,
uid: 0
)
}
}
8 changes: 8 additions & 0 deletions example/ios/Podfile
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,11 @@ post_install do |installer|
flutter_additional_ios_build_settings(target)
end
end

target 'Example_ScreenSharing_Extension' do
use_frameworks!
use_modular_headers!

# pod 'AgoraRtcEngine_iOS', '4.1.0'
pod 'AgoraBroadcastExtensionHelper_iOS', '4.0.7'
end
290 changes: 276 additions & 14 deletions example/ios/Runner.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

39 changes: 32 additions & 7 deletions example/ios/Runner/AppDelegate.swift
Original file line number Diff line number Diff line change
@@ -1,13 +1,38 @@
import UIKit
import Flutter
import ReplayKit


@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)
}
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {

var controller = window.rootViewController as? FlutterViewController
var screensharingIOSChannel = FlutterMethodChannel(
name: "example_screensharing_ios",
binaryMessenger: controller as! FlutterBinaryMessenger)

screensharingIOSChannel.setMethodCallHandler({
(call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
if #available(iOS 12.0, *) {
DispatchQueue.main.async(execute: {
let systemBroadcastPicker = RPSystemBroadcastPickerView(
frame: CGRect(x: 50, y: 200, width: 60, height: 60))
systemBroadcastPicker.showsMicrophoneButton = true
systemBroadcastPicker.autoresizingMask = [.flexibleBottomMargin, .flexibleRightMargin]
if let url = Bundle.main.url(forResource: "Example_ScreenSharing_Extension", withExtension: "appex", subdirectory: "PlugIns"),
let bundle = Bundle(url: url) {
systemBroadcastPicker.preferredExtension = bundle.bundleIdentifier
}
controller?.view.addSubview(systemBroadcastPicker)
})
}
})

GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
13 changes: 8 additions & 5 deletions example/ios/Runner/Base.lproj/Main.storyboard
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="21507" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
<device id="retina6_12" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21505"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--Flutter View Controller-->
Expand All @@ -14,13 +16,14 @@
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-26" y="-76"/>
</scene>
</scenes>
</document>
9 changes: 9 additions & 0 deletions example/ios/Runner/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,15 @@
<string>The app tries to use your camera</string>
<key>NSMicrophoneUsageDescription</key>
<string>The app tries to use your microphone</string>
<key>UIBackgroundModes</key>
<array>
<string>fetch</string>
<string>audio</string>
<string>processing</string>
<string>voip</string>
</array>
<key>UIFileSharingEnabled</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
Expand Down
1 change: 1 addition & 0 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class _MyAppState extends State<MyApp> {
),
AgoraVideoButtons(
client: client,
addScreenSharing: false, // Add this to enable screen sharing
),
],
),
Expand Down
59 changes: 58 additions & 1 deletion lib/controllers/rtc_buttons.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import 'dart:async';

import 'package:agora_rtc_engine/agora_rtc_engine.dart';
import 'package:agora_uikit/controllers/session_controller.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:permission_handler/permission_handler.dart';

/// Function to mute/unmute the microphone
Expand Down Expand Up @@ -40,12 +43,16 @@ Future<void> switchCamera(

/// Function to dispose the RTC and RTM engine.
Future<void> endCall({required SessionController sessionController}) async {
if (sessionController.value.connectionData!.screenSharingEnabled &&
sessionController.value.isScreenShared) {
await sessionController.value.engine?.stopScreenCapture();
}
await sessionController.value.engine?.stopPreview();
await sessionController.value.engine?.leaveChannel();
if (sessionController.value.connectionData!.rtmEnabled) {
await sessionController.value.agoraRtmChannel?.leave();
await sessionController.value.agoraRtmClient?.logout();
}
await sessionController.value.engine?.stopPreview();
await sessionController.value.engine?.release();
}

Expand All @@ -70,3 +77,53 @@ void toggleVisible({
.copyWith(visible: !(sessionController.value.visible));
}
}

Future<void> shareScreen({required SessionController sessionController}) async {
sessionController.value = sessionController.value.copyWith(
turnOnScreenSharing: !(sessionController.value.turnOnScreenSharing));

if (sessionController.value.turnOnScreenSharing) {
await sessionController.value.engine?.startScreenCapture(
const ScreenCaptureParameters2(
captureAudio: false,
audioParams: ScreenAudioParameters(
sampleRate: 16000,
channels: 2,
captureSignalVolume: 100,
),
captureVideo: true,
videoParams: ScreenVideoParameters(
dimensions: VideoDimensions(height: 1280, width: 720),
frameRate: 15,
bitrate: 600,
),
),
);
await _showRPSystemBroadcastPickerViewIfNeed();
} else {
await sessionController.value.engine?.stopScreenCapture();
}

// Update channel media options to publish camera or screen capture streams
ChannelMediaOptions options = ChannelMediaOptions(
publishCameraTrack: !(sessionController.value.isScreenShared),
publishMicrophoneTrack: !(sessionController.value.isScreenShared),
publishScreenTrack: sessionController.value.isScreenShared,
publishScreenCaptureAudio: sessionController.value.isScreenShared,
publishScreenCaptureVideo: sessionController.value.isScreenShared,
clientRoleType: ClientRoleType.clientRoleBroadcaster,
);

await sessionController.value.engine?.updateChannelMediaOptions(options);
}

Future<void> _showRPSystemBroadcastPickerViewIfNeed() async {
if (defaultTargetPlatform != TargetPlatform.iOS) {
return;
}

final MethodChannel iosScreenShareChannel =
const MethodChannel('example_screensharing_ios');
print("invoking channel method");
await iosScreenShareChannel.invokeMethod('showRPSystemBroadcastPickerView');
}
11 changes: 10 additions & 1 deletion lib/controllers/rtc_event_handlers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -268,9 +268,18 @@ Future<RtcEngineEventHandler> rtcEngineEventHandler(
agoraEventHandlers.onLocalAudioStateChanged?.call(connection, state, error);
}, onLocalVideoStateChanged: (source, state, error) {
final String info =
"Local video state changed state: $state and error: $error";
"Local video state changed, source: $source, state: $state and error: $error";
log(info, name: tag, level: Level.info.value);

if (source == VideoSourceType.videoSourceScreenPrimary &&
state == LocalVideoStreamState.localVideoStreamStateCapturing) {
sessionController.value =
sessionController.value.copyWith(isScreenShared: true);
} else {
sessionController.value =
sessionController.value.copyWith(isScreenShared: false);
}

agoraEventHandlers.onLocalVideoStateChanged?.call(source, state, error);
}, onActiveSpeaker: (connection, uid) {
final String info = "Active speaker: $uid";
Expand Down
3 changes: 2 additions & 1 deletion lib/controllers/session_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ class SessionController extends ValueNotifier<AgoraSettings> {
await value.engine!
.initialize(RtcEngineContext(appId: value.connectionData!.appId));
log("SDK initialized: ${value.engine}", level: Level.error.value);

// Getting SDK versions and assigning them
SDKBuildInfo? rtcVersion = await value.engine?.getVersion();
AgoraVersions.staticRTM = await AgoraRtmClient.getSdkVersion();
Expand Down Expand Up @@ -164,6 +163,8 @@ class SessionController extends ValueNotifier<AgoraSettings> {

/// Function to join the video call.
Future<void> joinVideoChannel() async {
if (value.layoutType == Layout.oneToOne && value.users.length == 1) return;

// [generatedRtmId] is the unique ID for a user generated using the timestamp in milliseconds.
value = value.copyWith(
generatedRtmId: value.connectionData!.rtmUid ??
Expand Down
10 changes: 10 additions & 0 deletions lib/models/agora_connection_data.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ class AgoraConnectionData {
/// Whether you want to enable RTM or not. Enabling RTM adds the host controls which helps you to request a remote user to mute/unmute their video/mic. Host Controls are enabled by default, set this to `false` to disable it.
final bool rtmEnabled;

final int? screenSharingUid;

final bool screenSharingEnabled;

AgoraConnectionData({
required this.appId,
required this.channelName,
Expand All @@ -45,6 +49,8 @@ class AgoraConnectionData {
this.tempRtmToken,
this.areaCode = const [AreaCode.areaCodeGlob],
this.rtmEnabled = true,
this.screenSharingUid = 1000,
this.screenSharingEnabled = true,
});

AgoraConnectionData copyWith({
Expand All @@ -59,6 +65,8 @@ class AgoraConnectionData {
String? tokenUrl,
List<AreaCode>? areaCode,
bool? rtmEnabled,
int? screenSharingUid,
bool? screenSharingEnabled,
}) {
return AgoraConnectionData(
appId: appId ?? this.appId,
Expand All @@ -72,6 +80,8 @@ class AgoraConnectionData {
tokenUrl: tokenUrl ?? this.tokenUrl,
areaCode: areaCode ?? this.areaCode,
rtmEnabled: rtmEnabled ?? this.rtmEnabled,
screenSharingUid: screenSharingUid ?? this.screenSharingUid,
screenSharingEnabled: screenSharingEnabled ?? this.screenSharingEnabled,
);
}
}
2 changes: 1 addition & 1 deletion lib/models/agora_rtm_mute_request.dart
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ class AgoraUIKit {
String platform = platformStr();

String framework = "flutter";
String version = "1.1.2";
String version = "1.2.0";

AgoraUIKit.fromJson(Map<String, dynamic> json)
: platform = json['platform'],
Expand Down
Loading