Skip to content
Draft
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: 1 addition & 1 deletion .version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2.8.0
2.8.1
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# CHANGELOG

## 2.8.1

* Added: Add agent deployment targeting to token source options
* Fixed: Android plugin compatibility with AGP 9 built-in Kotlin
* Fixed: Use maintain-resolution as the default video degradation preference for local video publishing

## 2.8.0

* Added: Session API support for simpler E2EE setup
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ Include this package to your `pubspec.yaml`
```yaml
---
dependencies:
livekit_client: ^2.8.0
livekit_client: ^2.8.1
```

### iOS
Expand Down
35 changes: 29 additions & 6 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ group = "io.livekit.plugin"
version = "1.0-SNAPSHOT"

buildscript {
ext.kotlin_version = "1.8.22"
ext.kotlin_version = "2.1.0"
repositories {
google()
mavenCentral()
Expand All @@ -22,7 +22,18 @@ allprojects {
}

apply plugin: "com.android.library"
apply plugin: "kotlin-android"

// AGP 9's built-in Kotlin compiles Kotlin itself and rejects the Kotlin Gradle
// Plugin. Apply KGP only when built-in Kotlin is NOT active: that means AGP < 9,
// or AGP 9 with android.builtInKotlin=false (the configuration Flutter currently
// ships by default while the ecosystem migrates).
def agpMajor = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION.tokenize(".")[0] as int
def builtInKotlinActive = agpMajor >= 9 &&
(!project.hasProperty("android.builtInKotlin") ||
Boolean.parseBoolean(project.property("android.builtInKotlin").toString()))
if (!builtInKotlinActive) {
apply plugin: "kotlin-android"
}

android {
if (project.android.hasProperty("namespace")) {
Expand All @@ -36,10 +47,6 @@ android {
targetCompatibility = JavaVersion.VERSION_1_8
}

kotlinOptions {
jvmTarget = JavaVersion.VERSION_1_8
}

sourceSets {
main.java.srcDirs += "src/main/kotlin"
test.java.srcDirs += "src/test/kotlin"
Expand Down Expand Up @@ -68,3 +75,19 @@ android {
}
}
}

// Configure the Kotlin JVM target. The compilerOptions DSL requires KGP 1.9+ or
// AGP 9 built-in Kotlin; older Flutter app templates ship KGP 1.8.x, which only
// supports the legacy kotlinOptions DSL.
def kotlinExt = project.extensions.findByName("kotlin")
if (kotlinExt?.hasProperty("compilerOptions")) {
kotlin {
compilerOptions {
jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_1_8
}
}
} else {
android.kotlinOptions {
jvmTarget = JavaVersion.VERSION_1_8.toString()
}
}
2 changes: 1 addition & 1 deletion ios/livekit_client.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'livekit_client'
s.version = '2.8.0'
s.version = '2.8.1'
s.summary = 'Open source platform for real-time audio and video.'
s.description = 'Open source platform for real-time audio and video.'
s.homepage = 'https://livekit.io/'
Expand Down
2 changes: 1 addition & 1 deletion lib/src/livekit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import 'support/platform.dart' show lkPlatformIsMobile;
/// Main entry point to connect to a room.
/// {@category Room}
class LiveKitClient {
static const version = '2.8.0';
static const version = '2.8.1';

/// Initialize the WebRTC plugin. If this is not manually called, will be
/// initialized with default settings.
Expand Down
21 changes: 2 additions & 19 deletions lib/src/participant/local.dart
Original file line number Diff line number Diff line change
Expand Up @@ -386,10 +386,7 @@ class LocalParticipant extends Participant<LocalTrackPublication> {
}

if ([TrackSource.camera, TrackSource.screenShareVideo].contains(track.source)) {
final degradationPreference = publishOptions.degradationPreference ??
getDefaultDegradationPreference(
track,
);
final degradationPreference = publishOptions.degradationPreference ?? DegradationPreference.maintainResolution;
await track.setDegradationPreference(degradationPreference);
}

Expand Down Expand Up @@ -487,10 +484,7 @@ class LocalParticipant extends Participant<LocalTrackPublication> {
}

if ([TrackSource.camera, TrackSource.screenShareVideo].contains(track.source)) {
final degradationPreference = publishOptions.degradationPreference ??
getDefaultDegradationPreference(
track,
);
final degradationPreference = publishOptions.degradationPreference ?? DegradationPreference.maintainResolution;
await track.setDegradationPreference(degradationPreference);
}

Expand Down Expand Up @@ -593,17 +587,6 @@ class LocalParticipant extends Participant<LocalTrackPublication> {
await pub.dispose();
}

DegradationPreference getDefaultDegradationPreference(LocalVideoTrack track) {
// a few of reasons we have different default paths:
// 1. without this, Chrome seems to aggressively resize the SVC video stating `quality-limitation: bandwidth` even when BW isn't an issue
// 2. since we are overriding contentHint to motion (to workaround L1T3 publishing), it overrides the default degradationPreference to `balanced`
final VideoDimensions dimensions = track.currentOptions.params.dimensions;
if (track.source == TrackSource.screenShareVideo || dimensions.height >= 1080) {
return DegradationPreference.maintainResolution;
}
return DegradationPreference.balanced;
}

/// Convenience method to unpublish all tracks.
Future<void> unpublishAllTracks({bool notify = true, bool? stopOnUnpublish}) async {
final trackSids = trackPublications.keys.toSet();
Expand Down
4 changes: 4 additions & 0 deletions lib/src/token_source/room_configuration.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,13 @@ class RoomAgentDispatch {
/// Metadata for the agent.
final String? metadata;

/// Optional deployment to target. Leave empty to target the production deployment.
final String? deployment;

const RoomAgentDispatch({
this.agentName,
this.metadata,
this.deployment,
});

factory RoomAgentDispatch.fromJson(Map<String, dynamic> json) => _$RoomAgentDispatchFromJson(json);
Expand Down
2 changes: 2 additions & 0 deletions lib/src/token_source/room_configuration.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 8 additions & 2 deletions lib/src/token_source/token_source.dart
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ class TokenRequestOptions {
/// Metadata passed to the agent job.
final String? agentMetadata;

/// Optional deployment to target. Leave empty to target the production deployment.
final String? agentDeployment;

const TokenRequestOptions({
this.roomName,
this.participantName,
Expand All @@ -51,15 +54,16 @@ class TokenRequestOptions {
this.participantAttributes,
this.agentName,
this.agentMetadata,
this.agentDeployment,
});

factory TokenRequestOptions.fromJson(Map<String, dynamic> json) => _$TokenRequestOptionsFromJson(json);
Map<String, dynamic> toJson() => _$TokenRequestOptionsToJson(this);

/// Converts this options object to a wire-format request.
TokenSourceRequest toRequest() {
final List<RoomAgentDispatch>? agents = (agentName != null || agentMetadata != null)
? [RoomAgentDispatch(agentName: agentName, metadata: agentMetadata)]
final List<RoomAgentDispatch>? agents = (agentName != null || agentMetadata != null || agentDeployment != null)
? [RoomAgentDispatch(agentName: agentName, metadata: agentMetadata, deployment: agentDeployment)]
: null;

return TokenSourceRequest(
Expand All @@ -83,6 +87,7 @@ class TokenRequestOptions {
other.participantMetadata == participantMetadata &&
other.agentName == agentName &&
other.agentMetadata == agentMetadata &&
other.agentDeployment == agentDeployment &&
const MapEquality().equals(other.participantAttributes, participantAttributes);
}

Expand All @@ -95,6 +100,7 @@ class TokenRequestOptions {
participantMetadata,
agentName,
agentMetadata,
agentDeployment,
const MapEquality().hash(participantAttributes),
);
}
Expand Down
2 changes: 2 additions & 0 deletions lib/src/token_source/token_source.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion macos/livekit_client.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'livekit_client'
s.version = '2.8.0'
s.version = '2.8.1'
s.summary = 'Open source platform for real-time audio and video.'
s.description = 'Open source platform for real-time audio and video.'
s.homepage = 'https://livekit.io/'
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
name: livekit_client
description: Flutter Client SDK for LiveKit. Build real-time video and audio
into your apps. Supports iOS, Android, and Web.
version: 2.8.0
version: 2.8.1
homepage: https://github.com/livekit/client-sdk-flutter

environment:
Expand Down
Loading