Skip to content
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
6 changes: 6 additions & 0 deletions packages/stream_video/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## Upcoming

### ⚡ Performance

* Improved `call.join()` performance - reduced join time by optimizing WebRTC setup and deferring non-critical operations.

## 1.0.2

🐞 Fixed
Expand Down
5 changes: 5 additions & 0 deletions packages/stream_video/lib/globals.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import 'package:meta/meta.dart';
import 'package:stream_webrtc_flutter/stream_webrtc_flutter.dart' as webrtc;

import 'protobuf/video/sfu/models/models.pb.dart';

const String streamSdkName = 'stream-flutter';
const String streamVideoVersion = '1.0.2';
const String openapiModelsVersion = '202.0.0';
Expand All @@ -15,3 +17,6 @@ final xStreamClientHeader = '$streamDefaultUserAgent|$clientVersionDetails';
/// Details regarding app name, version, os and device. Is set during initialization of StreamVideo instance.
@internal
String? clientVersionDetails;

@internal
ClientDetails? clientDetails;
47 changes: 35 additions & 12 deletions packages/stream_video/lib/src/call/call.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1045,9 +1045,11 @@ class Call {
// make sure we only track connection timing if we are not calling this method as part of a migration flow
connectionTimeStopwatch.stop();
if (!performingMigration) {
await _sfuStatsReporter?.sendSfuStats(
reconnectionStrategy: _reconnectStrategy,
connectionTimeMs: connectionTimeStopwatch.elapsedMilliseconds,
unawaited(
_sfuStatsReporter?.sendSfuStats(
reconnectionStrategy: _reconnectStrategy,
connectionTimeMs: connectionTimeStopwatch.elapsedMilliseconds,
),
);
}

Expand Down Expand Up @@ -1305,7 +1307,17 @@ class Call {
capabilities: _sfuClientCapabilities,
onRtcManagerCreatedCallback: (_) async {
_logger.v(() => '[startSession] applying connect options');
await _applyConnectOptions();
unawaited(
_applyConnectOptions().catchError((
dynamic error,
StackTrace stackTrace,
) {
_logger.e(
() =>
'[startSession] failed to apply connect options: $error, stackTrace: $stackTrace',
);
}),
);
},
isAnonymousUser:
_streamVideo.state.currentUser.type == UserType.anonymous,
Expand All @@ -1331,7 +1343,7 @@ class Call {
}

if (_sfuStatsOptions != null) {
await _sfuStatsReporter?.sendSfuStats();
unawaited(_sfuStatsReporter?.sendSfuStats());
_sfuStatsReporter =
SfuStatsReporter(
callSession: session,
Expand Down Expand Up @@ -1381,7 +1393,7 @@ class Call {
anonymousCount: sfuEvent.participantCount.anonymous,
);
} else if (sfuEvent is SfuCallEndedEvent) {
await _sfuStatsReporter?.sendSfuStats();
unawaited(_sfuStatsReporter?.sendSfuStats());
_stateManager.sfuCallEnded(sfuEvent);
}

Expand Down Expand Up @@ -1517,7 +1529,7 @@ class Call {
return;
}

await _sfuStatsReporter?.sendSfuStats();
unawaited(_sfuStatsReporter?.sendSfuStats());

switch (_reconnectStrategy) {
case SfuReconnectionStrategy.unspecified:
Expand Down Expand Up @@ -1638,9 +1650,11 @@ class Call {

if (migrationResult.isSuccess) {
migrateTimeStopwatch.stop();
await _sfuStatsReporter?.sendSfuStats(
connectionTimeMs: migrateTimeStopwatch.elapsedMilliseconds,
reconnectionStrategy: _reconnectStrategy,
unawaited(
_sfuStatsReporter?.sendSfuStats(
connectionTimeMs: migrateTimeStopwatch.elapsedMilliseconds,
reconnectionStrategy: _reconnectStrategy,
),
);
}
}
Expand Down Expand Up @@ -2238,8 +2252,17 @@ class Call {
_logger.v(() => '[performGetOperation] success: $success');

final callMetadata = onSuccess(success.data);
await _applyCallSettingsToConnectOptions(
callMetadata.settings,
unawaited(
_applyCallSettingsToConnectOptions(
callMetadata.settings,
).catchError(
(dynamic error, StackTrace stackTrace) {
_logger.e(
() =>
'[performGetOperation] failed to apply call settings: $error, stackTrace: $stackTrace',
);
},
),
);

return success;
Expand Down
97 changes: 4 additions & 93 deletions packages/stream_video/lib/src/call/session/call_session.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,10 @@ import 'dart:async';
import 'dart:convert';

import 'package:collection/collection.dart';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:internet_connection_checker_plus/internet_connection_checker_plus.dart';
import 'package:rxdart/rxdart.dart';
import 'package:stream_webrtc_flutter/stream_webrtc_flutter.dart' as rtc;
import 'package:synchronized/synchronized.dart';
import 'package:system_info2/system_info2.dart';

import '../../../globals.dart';
import '../../../protobuf/video/sfu/event/events.pb.dart' as sfu_events;
Expand Down Expand Up @@ -124,8 +122,6 @@ class CallSession extends Disposable {
Timer? _peerConnectionCheckTimer;
bool _isLeavingOrClosed = false;

sfu_models.ClientDetails? _clientDetails;

SharedEmitter<SfuEvent> get events => sfuWS.events;

late final _vvBuffer = DebounceBuffer<VisibilityChange, Result<None>>(
Expand Down Expand Up @@ -153,87 +149,6 @@ class CallSession extends Disposable {
});
}

Future<void> _ensureClientDetails() async {
if (_clientDetails != null) return;

try {
sfu_models.Device? device;
sfu_models.Browser? browser;

var os = sfu_models.OS(
name: CurrentPlatform.name,
);

if (CurrentPlatform.isAndroid) {
final deviceInfo = await DeviceInfoPlugin().androidInfo;
os = sfu_models.OS(
name: CurrentPlatform.name,
version: deviceInfo.version.release,
architecture: SysInfo.rawKernelArchitecture,
);
device = sfu_models.Device(
name: '${deviceInfo.manufacturer} : ${deviceInfo.model}',
);
} else if (CurrentPlatform.isIos) {
final deviceInfo = await DeviceInfoPlugin().iosInfo;
os = sfu_models.OS(
name: CurrentPlatform.name,
version: deviceInfo.systemVersion,
);
device = sfu_models.Device(
name: deviceInfo.utsname.machine,
);
} else if (CurrentPlatform.isWeb) {
final browserInfo = await DeviceInfoPlugin().webBrowserInfo;
browser = sfu_models.Browser(
name: browserInfo.browserName.name,
version: browserInfo.vendorSub,
);
} else if (CurrentPlatform.isMacOS) {
final deviceInfo = await DeviceInfoPlugin().macOsInfo;
os = sfu_models.OS(
name: CurrentPlatform.name,
version:
'${deviceInfo.majorVersion}.${deviceInfo.minorVersion}.${deviceInfo.patchVersion}',
architecture: deviceInfo.arch,
);
device = sfu_models.Device(
name: deviceInfo.model,
version: deviceInfo.osRelease,
);
} else if (CurrentPlatform.isWindows) {
final deviceInfo = await DeviceInfoPlugin().windowsInfo;
os = sfu_models.OS(
name: CurrentPlatform.name,
version:
'${deviceInfo.majorVersion}.${deviceInfo.minorVersion}.${deviceInfo.buildNumber}',
architecture: deviceInfo.buildLabEx,
);
} else if (CurrentPlatform.isLinux) {
final deviceInfo = await DeviceInfoPlugin().linuxInfo;
os = sfu_models.OS(
name: CurrentPlatform.name,
version: '${deviceInfo.name} ${deviceInfo.version}',
);
}

final versionSplit = streamVideoVersion.split('.');
_clientDetails = sfu_models.ClientDetails(
sdk: sfu_models.Sdk(
type: sfu_models.SdkType.SDK_TYPE_FLUTTER,
major: versionSplit.first,
minor: versionSplit.skip(1).first,
patch: versionSplit.last,
),
os: os,
device: device,
browser: browser,
);
} catch (e) {
_logger.e(() => '[_ensureClientDetails] failed: $e');
}
}

Future<sfu_events.ReconnectDetails> getReconnectDetails(
SfuReconnectionStrategy strategy, {
String? migratingFromSfuId,
Expand Down Expand Up @@ -274,8 +189,6 @@ class CallSession extends Disposable {
'isAnonymousUser: $isAnonymousUser',
);

await _ensureClientDetails();

await _eventsSubscription?.cancel();
await _rtcManagerSubject?.close();

Expand Down Expand Up @@ -338,7 +251,7 @@ class CallSession extends Disposable {
: clientPublishOptions?.getPreferredSubscriberOptions();

final joinRequest = sfu_events.JoinRequest(
clientDetails: _clientDetails,
clientDetails: clientDetails,
token: config.sfuToken,
sessionId: sessionId,
subscriberSdp: subscriberSdp,
Expand Down Expand Up @@ -384,7 +297,7 @@ class CallSession extends Disposable {
rtcManager =
await rtcManagerFactory.makeRtcManager(
sfuClient: sfuClient,
clientDetails: _clientDetails,
clientDetails: clientDetails,
sessionSequence: sessionSeq,
statsOptions: statsOptions,
)
Expand All @@ -407,7 +320,7 @@ class CallSession extends Disposable {
sfuClient: sfuClient,
publisherId: localTrackId,
publishOptions: joinResponseEvent.publishOptions,
clientDetails: _clientDetails,
clientDetails: clientDetails,
sessionSequence: sessionSeq,
statsOptions: statsOptions,
callSessionConfig: config,
Expand Down Expand Up @@ -511,8 +424,6 @@ class CallSession extends Disposable {
rtc.TransceiverDirection.SendOnly,
);

await _ensureClientDetails();

Result<({SfuCallState callState, Duration fastReconnectDeadline})?>?
result;

Expand All @@ -523,7 +434,7 @@ class CallSession extends Disposable {
sfuWS.send(
sfu_events.SfuRequest(
joinRequest: sfu_events.JoinRequest(
clientDetails: _clientDetails,
clientDetails: clientDetails,
token: config.sfuToken,
sessionId: sessionId,
subscriberSdp: subscriberSdp,
Expand Down
Loading