Capture client info (#71)

This commit is contained in:
Hiroshi Horie
2022-01-18 16:16:05 +07:00
committed by GitHub
parent 068876dc9c
commit 56aeacc291
14 changed files with 306 additions and 41 deletions
+6
View File
@@ -1,4 +1,6 @@
PODS: PODS:
- device_info_plus (0.0.1):
- Flutter
- Flutter (1.0.0) - Flutter (1.0.0)
- flutter_webrtc (0.7.1): - flutter_webrtc (0.7.1):
- Flutter - Flutter
@@ -15,6 +17,7 @@ PODS:
- WebRTC-SDK (93.4577.01) - WebRTC-SDK (93.4577.01)
DEPENDENCIES: DEPENDENCIES:
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
- Flutter (from `Flutter`) - Flutter (from `Flutter`)
- flutter_webrtc (from `.symlinks/plugins/flutter_webrtc/ios`) - flutter_webrtc (from `.symlinks/plugins/flutter_webrtc/ios`)
- livekit_client (from `.symlinks/plugins/livekit_client/ios`) - livekit_client (from `.symlinks/plugins/livekit_client/ios`)
@@ -27,6 +30,8 @@ SPEC REPOS:
- WebRTC-SDK - WebRTC-SDK
EXTERNAL SOURCES: EXTERNAL SOURCES:
device_info_plus:
:path: ".symlinks/plugins/device_info_plus/ios"
Flutter: Flutter:
:path: Flutter :path: Flutter
flutter_webrtc: flutter_webrtc:
@@ -39,6 +44,7 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/shared_preferences_ios/ios" :path: ".symlinks/plugins/shared_preferences_ios/ios"
SPEC CHECKSUMS: SPEC CHECKSUMS:
device_info_plus: e5c5da33f982a436e103237c0c85f9031142abed
Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a
flutter_webrtc: 611cab01a48b1d20e2b2409783c182134b8729e5 flutter_webrtc: 611cab01a48b1d20e2b2409783c182134b8729e5
Libyuv: 5f79ced0ee66e60a612ca97de1e6ccacd187a437 Libyuv: 5f79ced0ee66e60a612ca97de1e6ccacd187a437
@@ -5,12 +5,14 @@
import FlutterMacOS import FlutterMacOS
import Foundation import Foundation
import device_info_plus_macos
import flutter_webrtc import flutter_webrtc
import livekit_client import livekit_client
import path_provider_macos import path_provider_macos
import shared_preferences_macos import shared_preferences_macos
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
FlutterWebRTCPlugin.register(with: registry.registrar(forPlugin: "FlutterWebRTCPlugin")) FlutterWebRTCPlugin.register(with: registry.registrar(forPlugin: "FlutterWebRTCPlugin"))
LiveKitPlugin.register(with: registry.registrar(forPlugin: "LiveKitPlugin")) LiveKitPlugin.register(with: registry.registrar(forPlugin: "LiveKitPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
+6
View File
@@ -1,4 +1,6 @@
PODS: PODS:
- device_info_plus_macos (0.0.1):
- FlutterMacOS
- flutter_webrtc (0.7.1): - flutter_webrtc (0.7.1):
- FlutterMacOS - FlutterMacOS
- WebRTC-SDK (= 93.4577.01) - WebRTC-SDK (= 93.4577.01)
@@ -13,6 +15,7 @@ PODS:
- WebRTC-SDK (93.4577.01) - WebRTC-SDK (93.4577.01)
DEPENDENCIES: DEPENDENCIES:
- device_info_plus_macos (from `Flutter/ephemeral/.symlinks/plugins/device_info_plus_macos/macos`)
- flutter_webrtc (from `Flutter/ephemeral/.symlinks/plugins/flutter_webrtc/macos`) - flutter_webrtc (from `Flutter/ephemeral/.symlinks/plugins/flutter_webrtc/macos`)
- FlutterMacOS (from `Flutter/ephemeral`) - FlutterMacOS (from `Flutter/ephemeral`)
- livekit_client (from `Flutter/ephemeral/.symlinks/plugins/livekit_client/macos`) - livekit_client (from `Flutter/ephemeral/.symlinks/plugins/livekit_client/macos`)
@@ -24,6 +27,8 @@ SPEC REPOS:
- WebRTC-SDK - WebRTC-SDK
EXTERNAL SOURCES: EXTERNAL SOURCES:
device_info_plus_macos:
:path: Flutter/ephemeral/.symlinks/plugins/device_info_plus_macos/macos
flutter_webrtc: flutter_webrtc:
:path: Flutter/ephemeral/.symlinks/plugins/flutter_webrtc/macos :path: Flutter/ephemeral/.symlinks/plugins/flutter_webrtc/macos
FlutterMacOS: FlutterMacOS:
@@ -36,6 +41,7 @@ EXTERNAL SOURCES:
:path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_macos/macos :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_macos/macos
SPEC CHECKSUMS: SPEC CHECKSUMS:
device_info_plus_macos: 1ad388a1ef433505c4038e7dd9605aadd1e2e9c7
flutter_webrtc: b5a65d35686e113195a2da282dfe11fa827c5e6b flutter_webrtc: b5a65d35686e113195a2da282dfe11fa827c5e6b
FlutterMacOS: 57701585bf7de1b3fc2bb61f6378d73bbdea8424 FlutterMacOS: 57701585bf7de1b3fc2bb61f6378d73bbdea8424
livekit_client: d6920cc9a77586581b1109dd57a3b2b39d630e49 livekit_client: d6920cc9a77586581b1109dd57a3b2b39d630e49
+56
View File
@@ -57,6 +57,48 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.3" version: "1.0.3"
device_info_plus:
dependency: transitive
description:
name: device_info_plus
url: "https://pub.dartlang.org"
source: hosted
version: "3.2.1"
device_info_plus_linux:
dependency: transitive
description:
name: device_info_plus_linux
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.1"
device_info_plus_macos:
dependency: transitive
description:
name: device_info_plus_macos
url: "https://pub.dartlang.org"
source: hosted
version: "2.2.1"
device_info_plus_platform_interface:
dependency: transitive
description:
name: device_info_plus_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "2.3.0"
device_info_plus_web:
dependency: transitive
description:
name: device_info_plus_web
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
device_info_plus_windows:
dependency: transitive
description:
name: device_info_plus_windows
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.1"
eva_icons_flutter: eva_icons_flutter:
dependency: "direct main" dependency: "direct main"
description: description:
@@ -296,6 +338,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "3.1.0" version: "3.1.0"
platform_detect:
dependency: transitive
description:
name: platform_detect
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.3"
plugin_platform_interface: plugin_platform_interface:
dependency: transitive dependency: transitive
description: description:
@@ -324,6 +373,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "6.0.2" version: "6.0.2"
pub_semver:
dependency: transitive
description:
name: pub_semver
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
shared_preferences: shared_preferences:
dependency: "direct main" dependency: "direct main"
description: description:
+13 -7
View File
@@ -1,14 +1,13 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter/services.dart';
import 'package:flutter_web_plugins/flutter_web_plugins.dart';
// In order to *not* need this ignore, consider extracting the "web" version // In order to *not* need this ignore, consider extracting the "web" version
// of your plugin as a separate package, instead of inlining it in the same // of your plugin as a separate package, instead of inlining it in the same
// package as the core of your plugin. // package as the core of your plugin.
// ignore: avoid_web_libraries_in_flutter
// import 'dart:html' as html show window; // ignore: unused_import
import 'dart:html' as html show document, ScriptElement;
import 'package:flutter/services.dart';
import 'package:flutter_web_plugins/flutter_web_plugins.dart';
/// A web implementation of the Livekit plugin. /// A web implementation of the Livekit plugin.
class LiveKitWebPlugin { class LiveKitWebPlugin {
@@ -21,6 +20,13 @@ class LiveKitWebPlugin {
final pluginInstance = LiveKitWebPlugin(); final pluginInstance = LiveKitWebPlugin();
channel.setMethodCallHandler(pluginInstance.handleMethodCall); channel.setMethodCallHandler(pluginInstance.handleMethodCall);
// Unofficial method load js as flutter assets (unreliable)
// html.document.head!.append(html.ScriptElement()
// ..src = 'assets/packages/livekit_client/assets/ua-parser.min.js'
// ..type = 'application/javascript'
// ..defer = true
// );
} }
/// Handles method calls over the MethodChannel of this plugin. /// Handles method calls over the MethodChannel of this plugin.
+5 -3
View File
@@ -39,12 +39,14 @@ class SignalClient extends Disposable with EventsEmittable<SignalEvent> {
String token, { String token, {
ConnectOptions? connectOptions, ConnectOptions? connectOptions,
}) async { }) async {
final rtcUri = Utils.buildUri( final rtcUri = await Utils.buildUri(
uriString, uriString,
token: token, token: token,
connectOptions: connectOptions, connectOptions: connectOptions,
); );
logger.fine('SignalClient connecting with url: $rtcUri');
try { try {
_ws = await LiveKitWebSocket.connect( _ws = await LiveKitWebSocket.connect(
rtcUri, rtcUri,
@@ -56,7 +58,7 @@ class SignalClient extends Disposable with EventsEmittable<SignalEvent> {
); );
} catch (socketError) { } catch (socketError) {
// Re-build same uri for validate mode // Re-build same uri for validate mode
final validateUri = Utils.buildUri( final validateUri = await Utils.buildUri(
uriString, uriString,
token: token, token: token,
connectOptions: connectOptions, connectOptions: connectOptions,
@@ -90,7 +92,7 @@ class SignalClient extends Disposable with EventsEmittable<SignalEvent> {
await _ws?.dispose(); await _ws?.dispose();
_ws = null; _ws = null;
final rtcUri = Utils.buildUri( final rtcUri = await Utils.buildUri(
uriString, uriString,
token: token, token: token,
reconnect: true, reconnect: true,
+40
View File
@@ -0,0 +1,40 @@
import 'package:flutter/services.dart';
import 'package:meta/meta.dart';
import '../logger.dart';
import 'native_audio.dart';
// Method channel methods to call native code.
class Native {
@internal
static const channel = MethodChannel('livekit_client');
@internal
static Future<bool> configureAudio(
NativeAudioConfiguration configuration) async {
try {
final result = await channel.invokeMethod<bool>(
'configureNativeAudio',
configuration.toMap(),
);
return result == true;
} catch (error) {
logger.warning('configureNativeAudio did throw $error');
return false;
}
}
/// Returns OS's version as a string
/// Currently only for iOS, macOS
@internal
static Future<String?> osVersionString() async {
try {
return await channel.invokeMethod<String>(
'osVersionString',
<String, dynamic>{},
);
} catch (error) {
logger.warning('appleOSVersionString did throw error: ${error}');
}
}
}
-21
View File
@@ -1,9 +1,4 @@
// https://developer.apple.com/documentation/avfaudio/avaudiosession/category // https://developer.apple.com/documentation/avfaudio/avaudiosession/category
import 'package:flutter/services.dart';
import '../logger.dart';
enum AppleAudioCategory { enum AppleAudioCategory {
soloAmbient, soloAmbient,
playback, playback,
@@ -109,19 +104,3 @@ class NativeAudioConfiguration {
appleAudioMode: appleAudioMode ?? this.appleAudioMode, appleAudioMode: appleAudioMode ?? this.appleAudioMode,
); );
} }
const _lkMethodChannel = MethodChannel('livekit_client');
Future<bool> configureNativeAudio(
NativeAudioConfiguration configuration) async {
try {
final result = await _lkMethodChannel.invokeMethod<bool>(
'configureNativeAudio',
configuration.toMap(),
);
return result == true;
} catch (_) {
logger.warning('configureAudioSession did throw $_');
return false;
}
}
+2 -1
View File
@@ -8,5 +8,6 @@ PlatformType lkPlatformImplementation() {
if (Platform.isMacOS) return PlatformType.macOS; if (Platform.isMacOS) return PlatformType.macOS;
if (Platform.isLinux) return PlatformType.linux; if (Platform.isLinux) return PlatformType.linux;
if (Platform.isIOS) return PlatformType.iOS; if (Platform.isIOS) return PlatformType.iOS;
return PlatformType.android; if (Platform.isAndroid) return PlatformType.android;
throw UnsupportedError('Unknown Platform');
} }
+2 -1
View File
@@ -1,6 +1,7 @@
import 'package:synchronized/synchronized.dart' as sync; import 'package:synchronized/synchronized.dart' as sync;
import '../logger.dart'; import '../logger.dart';
import '../support/native.dart';
import '../support/native_audio.dart'; import '../support/native_audio.dart';
import '../support/platform.dart'; import '../support/platform.dart';
import 'local/audio.dart'; import 'local/audio.dart';
@@ -83,7 +84,7 @@ mixin AudioManagementMixin on AudioTrack {
logger.fine( logger.fine(
'[$runtimeType] configuring for ${audioTrackState} using ${config}...'); '[$runtimeType] configuring for ${audioTrackState} using ${config}...');
try { try {
await configureNativeAudio(config); await Native.configureAudio(config);
} catch (error) { } catch (error) {
logger.warning('[$runtimeType] Failed to configure ${error}'); logger.warning('[$runtimeType] Failed to configure ${error}');
} }
+92 -2
View File
@@ -1,30 +1,103 @@
import 'dart:async'; import 'dart:async';
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:flutter_webrtc/flutter_webrtc.dart' as rtc; import 'package:flutter_webrtc/flutter_webrtc.dart' as rtc;
import 'package:meta/meta.dart';
import 'package:platform_detect/platform_detect.dart' as pd;
import './proto/livekit_models.pb.dart' as lk_models; import './proto/livekit_models.pb.dart' as lk_models;
import './support/native.dart';
import 'extensions.dart'; import 'extensions.dart';
import 'livekit.dart'; import 'livekit.dart';
import 'logger.dart'; import 'logger.dart';
import 'options.dart'; import 'options.dart';
import 'support/platform.dart';
import 'track/options.dart'; import 'track/options.dart';
import 'types.dart'; import 'types.dart';
extension UriExt on Uri { extension UriExt on Uri {
@internal
bool get isSecureScheme => ['https', 'wss'].contains(scheme); bool get isSecureScheme => ['https', 'wss'].contains(scheme);
} }
// Collection of state-less static methods // Collection of state-less static methods
class Utils { class Utils {
static Uri buildUri( // DeviceInfoPlugin caches internally
static final _deviceInfoPlugin = DeviceInfoPlugin();
static Future<lk_models.ClientInfo?> _clientInfo() async {
switch (lkPlatform()) {
case PlatformType.web:
return lk_models.ClientInfo(
os: pd.operatingSystem.name.toLowerCase(),
browser: pd.browser.name.toLowerCase(),
browserVersion: pd.browser.version.canonicalizedVersion,
);
case PlatformType.windows:
return lk_models.ClientInfo(
os: 'windows',
/// [WindowsDeviceInfo] does not provide details...
);
case PlatformType.macOS:
final info = await _deviceInfoPlugin.macOsInfo;
/// [MacOsDeviceInfo.osRelease] returns Darwin version instead of macOS version
/// So call native code to get os version
String? osVersionString = await Native.osVersionString();
return lk_models.ClientInfo(
os: 'macOS',
osVersion: osVersionString,
// Confirmed
deviceModel: info.model,
);
case PlatformType.android:
final info = await _deviceInfoPlugin.androidInfo;
return lk_models.ClientInfo(
os: 'android',
osVersion: info.version.release,
deviceModel: info.model,
);
case PlatformType.iOS:
final info = await _deviceInfoPlugin.iosInfo;
String? model = info.utsname.machine;
if (model != null && ['i386', 'x86_64', 'arm64'].contains(model)) {
model = 'iOSSimulator,${model}';
}
return lk_models.ClientInfo(
os: 'iOS',
// Confirmed
osVersion: info.systemVersion,
deviceModel: model,
);
case PlatformType.linux:
final info = await _deviceInfoPlugin.linuxInfo;
return lk_models.ClientInfo(
os: 'linux',
osVersion: info.versionId,
deviceModel: info.machineId,
);
default:
// case PlatformType.fuchsia:
}
}
@internal
static Future<Uri> buildUri(
String uriString, { String uriString, {
required String token, required String token,
ConnectOptions? connectOptions, ConnectOptions? connectOptions,
bool reconnect = false, bool reconnect = false,
bool validate = false, bool validate = false,
bool forceSecure = false, bool forceSecure = false,
}) { }) async {
connectOptions ??= const ConnectOptions(); connectOptions ??= const ConnectOptions();
final Uri uri = Uri.parse(uriString); final Uri uri = Uri.parse(uriString);
@@ -44,6 +117,8 @@ class Utils {
} }
pathSegments.add(lastSegment); pathSegments.add(lastSegment);
final clientInfo = await _clientInfo();
return uri.replace( return uri.replace(
scheme: validate ? httpScheme : wsScheme, scheme: validate ? httpScheme : wsScheme,
pathSegments: pathSegments, pathSegments: pathSegments,
@@ -54,6 +129,16 @@ class Utils {
'protocol': connectOptions.protocolVersion.toStringValue(), 'protocol': connectOptions.protocolVersion.toStringValue(),
'sdk': 'flutter', 'sdk': 'flutter',
'version': LiveKitClient.version, 'version': LiveKitClient.version,
// client info
if (clientInfo != null) ...{
if (clientInfo.hasOs()) 'os': clientInfo.os,
if (clientInfo.hasOsVersion()) 'os_version': clientInfo.osVersion,
if (clientInfo.hasDeviceModel())
'device_model': clientInfo.deviceModel,
if (clientInfo.hasBrowser()) 'browser': clientInfo.browser,
if (clientInfo.hasBrowserVersion())
'browser_version': clientInfo.browserVersion,
},
}, },
); );
} }
@@ -94,6 +179,7 @@ class Utils {
static final videoRids = ['q', 'h', 'f']; static final videoRids = ['q', 'h', 'f'];
@internal
static List<rtc.RTCRtpEncoding> encodingsFromPresets( static List<rtc.RTCRtpEncoding> encodingsFromPresets(
VideoDimensions dimensions, { VideoDimensions dimensions, {
required List<VideoParameters> presets, required List<VideoParameters> presets,
@@ -113,6 +199,7 @@ class Utils {
return result; return result;
} }
@internal
static List<rtc.RTCRtpEncoding>? computeVideoEncodings({ static List<rtc.RTCRtpEncoding>? computeVideoEncodings({
required bool isScreenShare, required bool isScreenShare,
VideoDimensions? dimensions, VideoDimensions? dimensions,
@@ -173,6 +260,7 @@ class Utils {
); );
} }
@internal
static List<lk_models.VideoLayer> computeVideoLayers( static List<lk_models.VideoLayer> computeVideoLayers(
VideoDimensions dimensions, VideoDimensions dimensions,
List<rtc.RTCRtpEncoding>? encodings, List<rtc.RTCRtpEncoding>? encodings,
@@ -204,6 +292,7 @@ class Utils {
}).toList(); }).toList();
} }
@internal
static lk_models.VideoQuality? videoQualityForRid(String? rid) => { static lk_models.VideoQuality? videoQualityForRid(String? rid) => {
'f': lk_models.VideoQuality.HIGH, 'f': lk_models.VideoQuality.HIGH,
'h': lk_models.VideoQuality.MEDIUM, 'h': lk_models.VideoQuality.MEDIUM,
@@ -211,6 +300,7 @@ class Utils {
}[rid]; }[rid];
// makes a debounce func, with 1 param // makes a debounce func, with 1 param
@internal
static Function(T) createDebounceFunc<T>( static Function(T) createDebounceFunc<T>(
Function(T) f, { Function(T) f, {
Function(Function)? cancelFunc, Function(Function)? cancelFunc,
+62 -6
View File
@@ -64,6 +64,48 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.3" version: "1.0.3"
device_info_plus:
dependency: "direct main"
description:
name: device_info_plus
url: "https://pub.dartlang.org"
source: hosted
version: "3.2.1"
device_info_plus_linux:
dependency: transitive
description:
name: device_info_plus_linux
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.1"
device_info_plus_macos:
dependency: transitive
description:
name: device_info_plus_macos
url: "https://pub.dartlang.org"
source: hosted
version: "2.2.1"
device_info_plus_platform_interface:
dependency: transitive
description:
name: device_info_plus_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "2.3.0+1"
device_info_plus_web:
dependency: transitive
description:
name: device_info_plus_web
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
device_info_plus_windows:
dependency: transitive
description:
name: device_info_plus_windows
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.1"
fake_async: fake_async:
dependency: transitive dependency: transitive
description: description:
@@ -211,28 +253,28 @@ packages:
name: path_provider_linux name: path_provider_linux
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.1.4" version: "2.1.5"
path_provider_macos: path_provider_macos:
dependency: transitive dependency: transitive
description: description:
name: path_provider_macos name: path_provider_macos
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.0.4" version: "2.0.5"
path_provider_platform_interface: path_provider_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: path_provider_platform_interface name: path_provider_platform_interface
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.0.1" version: "2.0.3"
path_provider_windows: path_provider_windows:
dependency: transitive dependency: transitive
description: description:
name: path_provider_windows name: path_provider_windows
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.0.4" version: "2.0.5"
platform: platform:
dependency: transitive dependency: transitive
description: description:
@@ -240,13 +282,20 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "3.1.0" version: "3.1.0"
platform_detect:
dependency: "direct main"
description:
name: platform_detect
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.3"
plugin_platform_interface: plugin_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: plugin_platform_interface name: plugin_platform_interface
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.0.2" version: "2.1.2"
process: process:
dependency: transitive dependency: transitive
description: description:
@@ -261,6 +310,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.0.1" version: "2.0.1"
pub_semver:
dependency: transitive
description:
name: pub_semver
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
sky_engine: sky_engine:
dependency: transitive dependency: transitive
description: flutter description: flutter
@@ -356,7 +412,7 @@ packages:
name: win32 name: win32
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.3.3" version: "2.3.4"
xdg_directories: xdg_directories:
dependency: transitive dependency: transitive
description: description:
+2
View File
@@ -24,6 +24,8 @@ dependencies:
protobuf: ^2.0.1 protobuf: ^2.0.1
flutter_webrtc: ^0.8.1 flutter_webrtc: ^0.8.1
dart_webrtc: ^1.0.3 dart_webrtc: ^1.0.3
device_info_plus: ^3.2.1
platform_detect: ^2.0.3
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
+18
View File
@@ -140,6 +140,22 @@ public class LiveKitPlugin: NSObject, FlutterPlugin {
#endif #endif
} }
private static let processInfo = ProcessInfo()
/// Returns os version as a string.
/// format: `12.1`, `15.3.1`, `15.0.1`
private static func osVersionString() -> String {
let osVersion = processInfo.operatingSystemVersion
var versions = [osVersion.majorVersion]
if osVersion.minorVersion != 0 || osVersion.patchVersion != 0 {
versions.append(osVersion.minorVersion)
}
if osVersion.patchVersion != 0 {
versions.append(osVersion.patchVersion)
}
return versions.map({ String($0) }).joined(separator: ".")
}
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
guard let args = call.arguments as? [String: Any?] else { guard let args = call.arguments as? [String: Any?] else {
@@ -151,6 +167,8 @@ public class LiveKitPlugin: NSObject, FlutterPlugin {
switch call.method { switch call.method {
case "configureNativeAudio": case "configureNativeAudio":
handleConfigureNativeAudio(args: args, result: result) handleConfigureNativeAudio(args: args, result: result)
case "osVersionString":
result(LiveKitPlugin.osVersionString())
default: default:
print("[LiveKit] method not found: ", call.method) print("[LiveKit] method not found: ", call.method)
result(FlutterMethodNotImplemented) result(FlutterMethodNotImplemented)