diff --git a/.changes/degradation-preference-disabled-mapping b/.changes/degradation-preference-disabled-mapping new file mode 100644 index 000000000..16e74b29d --- /dev/null +++ b/.changes/degradation-preference-disabled-mapping @@ -0,0 +1 @@ +patch type="fixed" "DegradationPreference.disabled now maps to maintainFramerateAndResolution, as WebRTC defines it" diff --git a/.changes/enum-conversion-fallbacks b/.changes/enum-conversion-fallbacks new file mode 100644 index 000000000..07c236fe6 --- /dev/null +++ b/.changes/enum-conversion-fallbacks @@ -0,0 +1 @@ +patch type="changed" "Unrecognized protobuf enum values from newer servers now fall back to safe defaults, for example a new DisconnectReason maps to unknown" diff --git a/lib/src/extensions.dart b/lib/src/extensions.dart index 11ecc28fe..a2886aedd 100644 --- a/lib/src/extensions.dart +++ b/lib/src/extensions.dart @@ -27,10 +27,11 @@ import 'proto/livekit_rtc.pb.dart' as lk_rtc; import 'types/other.dart'; extension DataPacketKindExt on lk_models.DataPacket_Kind { - Reliability toSDKType() => { - lk_models.DataPacket_Kind.RELIABLE: Reliability.reliable, - lk_models.DataPacket_Kind.LOSSY: Reliability.lossy, - }[this]!; + Reliability toSDKType() => switch (this) { + lk_models.DataPacket_Kind.RELIABLE => Reliability.reliable, + lk_models.DataPacket_Kind.LOSSY => Reliability.lossy, + _ => Reliability.lossy, + }; } extension LiveKitEventExt on Iterable> { @@ -54,23 +55,23 @@ extension ObjectExt on Object { } extension ProtocolVersionExt on ProtocolVersion { - String toStringValue() => { - ProtocolVersion.v2: '2', - ProtocolVersion.v3: '3', - ProtocolVersion.v4: '4', - ProtocolVersion.v5: '5', - ProtocolVersion.v6: '6', - ProtocolVersion.v7: '7', - ProtocolVersion.v8: '8', - ProtocolVersion.v9: '9', - ProtocolVersion.v10: '10', - ProtocolVersion.v11: '11', - ProtocolVersion.v12: '12', - ProtocolVersion.v13: '13', - ProtocolVersion.v14: '14', - ProtocolVersion.v15: '15', - ProtocolVersion.v16: '16', - }[this]!; + String toStringValue() => switch (this) { + ProtocolVersion.v2 => '2', + ProtocolVersion.v3 => '3', + ProtocolVersion.v4 => '4', + ProtocolVersion.v5 => '5', + ProtocolVersion.v6 => '6', + ProtocolVersion.v7 => '7', + ProtocolVersion.v8 => '8', + ProtocolVersion.v9 => '9', + ProtocolVersion.v10 => '10', + ProtocolVersion.v11 => '11', + ProtocolVersion.v12 => '12', + ProtocolVersion.v13 => '13', + ProtocolVersion.v14 => '14', + ProtocolVersion.v15 => '15', + ProtocolVersion.v16 => '16', + }; } extension ClientProtocolVersionExt on ClientProtocolVersion { @@ -80,10 +81,10 @@ extension ClientProtocolVersionExt on ClientProtocolVersion { } extension ReliabilityExt on Reliability { - lk_models.DataPacket_Kind toPBType() => { - Reliability.reliable: lk_models.DataPacket_Kind.RELIABLE, - Reliability.lossy: lk_models.DataPacket_Kind.LOSSY, - }[this]!; + lk_models.DataPacket_Kind toPBType() => switch (this) { + Reliability.reliable => lk_models.DataPacket_Kind.RELIABLE, + Reliability.lossy => lk_models.DataPacket_Kind.LOSSY, + }; } extension RTCDataChannelExt on rtc.RTCDataChannel { @@ -118,10 +119,10 @@ extension RTCPeerConnectionStateExt on rtc.RTCPeerConnectionState { } extension RTCIceTransportPolicyExt on RTCIceTransportPolicy { - String toStringValue() => { - RTCIceTransportPolicy.all: 'all', - RTCIceTransportPolicy.relay: 'relay', - }[this]!; + String toStringValue() => switch (this) { + RTCIceTransportPolicy.all => 'all', + RTCIceTransportPolicy.relay => 'relay', + }; } // not so neat to directly expose protobuf types so we @@ -139,86 +140,74 @@ extension SessionDescriptionExt on lk_rtc.SessionDescription { } extension ConnectionQualityExt on lk_models.ConnectionQuality { - ConnectionQuality toLKType() => - { - lk_models.ConnectionQuality.LOST: ConnectionQuality.lost, - lk_models.ConnectionQuality.POOR: ConnectionQuality.poor, - lk_models.ConnectionQuality.GOOD: ConnectionQuality.good, - lk_models.ConnectionQuality.EXCELLENT: ConnectionQuality.excellent, - }[this] ?? - ConnectionQuality.unknown; + ConnectionQuality toLKType() => switch (this) { + lk_models.ConnectionQuality.LOST => ConnectionQuality.lost, + lk_models.ConnectionQuality.POOR => ConnectionQuality.poor, + lk_models.ConnectionQuality.GOOD => ConnectionQuality.good, + lk_models.ConnectionQuality.EXCELLENT => ConnectionQuality.excellent, + _ => ConnectionQuality.unknown, + }; } extension VideoQualityExt on lk_models.VideoQuality { - VideoQuality toLKType() => - { - lk_models.VideoQuality.HIGH: VideoQuality.HIGH, - lk_models.VideoQuality.MEDIUM: VideoQuality.MEDIUM, - lk_models.VideoQuality.LOW: VideoQuality.LOW, - }[this] ?? - VideoQuality.LOW; - - String toRid() => { - lk_models.VideoQuality.HIGH: 'f', - lk_models.VideoQuality.MEDIUM: 'h', - lk_models.VideoQuality.LOW: 'q', - }[this]!; + VideoQuality toLKType() => switch (this) { + lk_models.VideoQuality.HIGH => VideoQuality.HIGH, + lk_models.VideoQuality.MEDIUM => VideoQuality.MEDIUM, + lk_models.VideoQuality.LOW => VideoQuality.LOW, + _ => VideoQuality.LOW, + }; } extension PBVideoQualityExt on VideoQuality { - lk_models.VideoQuality toPBType() => { - VideoQuality.HIGH: lk_models.VideoQuality.HIGH, - VideoQuality.MEDIUM: lk_models.VideoQuality.MEDIUM, - VideoQuality.LOW: lk_models.VideoQuality.LOW, - }[this]!; + lk_models.VideoQuality toPBType() => switch (this) { + VideoQuality.HIGH => lk_models.VideoQuality.HIGH, + VideoQuality.MEDIUM => lk_models.VideoQuality.MEDIUM, + VideoQuality.LOW => lk_models.VideoQuality.LOW, + }; } extension TrackTypeExt on lk_models.TrackType { - TrackType toLKType() => - { - lk_models.TrackType.AUDIO: TrackType.AUDIO, - lk_models.TrackType.VIDEO: TrackType.VIDEO, - lk_models.TrackType.DATA: TrackType.DATA, - }[this] ?? - TrackType.AUDIO; + TrackType toLKType() => switch (this) { + lk_models.TrackType.AUDIO => TrackType.AUDIO, + lk_models.TrackType.VIDEO => TrackType.VIDEO, + lk_models.TrackType.DATA => TrackType.DATA, + _ => TrackType.AUDIO, + }; } extension PBTrackTypeExt on TrackType { - lk_models.TrackType toPBType() => { - TrackType.AUDIO: lk_models.TrackType.AUDIO, - TrackType.VIDEO: lk_models.TrackType.VIDEO, - TrackType.DATA: lk_models.TrackType.DATA, - }[this]!; + lk_models.TrackType toPBType() => switch (this) { + TrackType.AUDIO => lk_models.TrackType.AUDIO, + TrackType.VIDEO => lk_models.TrackType.VIDEO, + TrackType.DATA => lk_models.TrackType.DATA, + }; } extension PBTrackSourceExt on lk_models.TrackSource { - TrackSource toLKType() => - { - lk_models.TrackSource.CAMERA: TrackSource.camera, - lk_models.TrackSource.MICROPHONE: TrackSource.microphone, - lk_models.TrackSource.SCREEN_SHARE: TrackSource.screenShareVideo, - lk_models.TrackSource.SCREEN_SHARE_AUDIO: TrackSource.screenShareAudio, - }[this] ?? - TrackSource.unknown; + TrackSource toLKType() => switch (this) { + lk_models.TrackSource.CAMERA => TrackSource.camera, + lk_models.TrackSource.MICROPHONE => TrackSource.microphone, + lk_models.TrackSource.SCREEN_SHARE => TrackSource.screenShareVideo, + lk_models.TrackSource.SCREEN_SHARE_AUDIO => TrackSource.screenShareAudio, + _ => TrackSource.unknown, + }; } extension LKTrackSourceExt on TrackSource { - lk_models.TrackSource toPBType() => - { - TrackSource.camera: lk_models.TrackSource.CAMERA, - TrackSource.microphone: lk_models.TrackSource.MICROPHONE, - TrackSource.screenShareVideo: lk_models.TrackSource.SCREEN_SHARE, - TrackSource.screenShareAudio: lk_models.TrackSource.SCREEN_SHARE_AUDIO, - }[this] ?? - lk_models.TrackSource.UNKNOWN; + lk_models.TrackSource toPBType() => switch (this) { + TrackSource.camera => lk_models.TrackSource.CAMERA, + TrackSource.microphone => lk_models.TrackSource.MICROPHONE, + TrackSource.screenShareVideo => lk_models.TrackSource.SCREEN_SHARE, + TrackSource.screenShareAudio => lk_models.TrackSource.SCREEN_SHARE_AUDIO, + TrackSource.unknown => lk_models.TrackSource.UNKNOWN, + }; } extension PBStreamStateExt on lk_rtc.StreamState { - StreamState toLKType() => - { - lk_rtc.StreamState.ACTIVE: StreamState.active, - }[this] ?? - StreamState.paused; + StreamState toLKType() => switch (this) { + lk_rtc.StreamState.ACTIVE => StreamState.active, + _ => StreamState.paused, + }; } extension ParticipantTrackPermissionExt on ParticipantTrackPermission { @@ -235,56 +224,60 @@ extension WidgetsBindingCompatible on WidgetsBinding { } extension EncryptionTypeExt on lk_models.Encryption_Type { - EncryptionType toLkType() => { - lk_models.Encryption_Type.NONE: EncryptionType.kNone, - lk_models.Encryption_Type.GCM: EncryptionType.kGcm, - lk_models.Encryption_Type.CUSTOM: EncryptionType.kCustom, - }[this]!; + EncryptionType toLkType() => switch (this) { + lk_models.Encryption_Type.NONE => EncryptionType.kNone, + lk_models.Encryption_Type.GCM => EncryptionType.kGcm, + lk_models.Encryption_Type.CUSTOM => EncryptionType.kCustom, + _ => EncryptionType.kNone, + }; } extension DisconnectReasonExt on lk_models.DisconnectReason { - DisconnectReason toSDKType() => { - lk_models.DisconnectReason.UNKNOWN_REASON: DisconnectReason.unknown, - lk_models.DisconnectReason.CLIENT_INITIATED: DisconnectReason.clientInitiated, - lk_models.DisconnectReason.DUPLICATE_IDENTITY: DisconnectReason.duplicateIdentity, - lk_models.DisconnectReason.SERVER_SHUTDOWN: DisconnectReason.serverShutdown, - lk_models.DisconnectReason.PARTICIPANT_REMOVED: DisconnectReason.participantRemoved, - lk_models.DisconnectReason.ROOM_DELETED: DisconnectReason.roomDeleted, - lk_models.DisconnectReason.STATE_MISMATCH: DisconnectReason.stateMismatch, - lk_models.DisconnectReason.JOIN_FAILURE: DisconnectReason.joinFailure, - }[this]!; + DisconnectReason toSDKType() => switch (this) { + lk_models.DisconnectReason.UNKNOWN_REASON => DisconnectReason.unknown, + lk_models.DisconnectReason.CLIENT_INITIATED => DisconnectReason.clientInitiated, + lk_models.DisconnectReason.DUPLICATE_IDENTITY => DisconnectReason.duplicateIdentity, + lk_models.DisconnectReason.SERVER_SHUTDOWN => DisconnectReason.serverShutdown, + lk_models.DisconnectReason.PARTICIPANT_REMOVED => DisconnectReason.participantRemoved, + lk_models.DisconnectReason.ROOM_DELETED => DisconnectReason.roomDeleted, + lk_models.DisconnectReason.STATE_MISMATCH => DisconnectReason.stateMismatch, + lk_models.DisconnectReason.JOIN_FAILURE => DisconnectReason.joinFailure, + _ => DisconnectReason.unknown, + }; } extension ParticipantTypeExt on lk_models.ParticipantInfo_Kind { - ParticipantKind toLKType() => { - lk_models.ParticipantInfo_Kind.STANDARD: ParticipantKind.STANDARD, - lk_models.ParticipantInfo_Kind.INGRESS: ParticipantKind.INGRESS, - lk_models.ParticipantInfo_Kind.EGRESS: ParticipantKind.EGRESS, - lk_models.ParticipantInfo_Kind.SIP: ParticipantKind.SIP, - lk_models.ParticipantInfo_Kind.AGENT: ParticipantKind.AGENT, - }[this]!; + ParticipantKind toLKType() => switch (this) { + lk_models.ParticipantInfo_Kind.STANDARD => ParticipantKind.STANDARD, + lk_models.ParticipantInfo_Kind.INGRESS => ParticipantKind.INGRESS, + lk_models.ParticipantInfo_Kind.EGRESS => ParticipantKind.EGRESS, + lk_models.ParticipantInfo_Kind.SIP => ParticipantKind.SIP, + lk_models.ParticipantInfo_Kind.AGENT => ParticipantKind.AGENT, + _ => ParticipantKind.STANDARD, + }; } extension DegradationPreferenceExt on DegradationPreference { - rtc.RTCDegradationPreference toRTCType() => { - DegradationPreference.maintainFramerate: rtc.RTCDegradationPreference.MAINTAIN_FRAMERATE, - DegradationPreference.maintainResolution: rtc.RTCDegradationPreference.MAINTAIN_RESOLUTION, - DegradationPreference.balanced: rtc.RTCDegradationPreference.BALANCED, - DegradationPreference.maintainFramerateAndResolution: - rtc.RTCDegradationPreference.MAINTAIN_FRAMERATE_AND_RESOLUTION, - }[this]!; + rtc.RTCDegradationPreference toRTCType() => switch (this) { + // WebRTC defines DISABLED as an alias for MAINTAIN_FRAMERATE_AND_RESOLUTION + // ignore: deprecated_member_use_from_same_package + DegradationPreference.disabled => rtc.RTCDegradationPreference.MAINTAIN_FRAMERATE_AND_RESOLUTION, + DegradationPreference.maintainFramerate => rtc.RTCDegradationPreference.MAINTAIN_FRAMERATE, + DegradationPreference.maintainResolution => rtc.RTCDegradationPreference.MAINTAIN_RESOLUTION, + DegradationPreference.balanced => rtc.RTCDegradationPreference.BALANCED, + DegradationPreference.maintainFramerateAndResolution => + rtc.RTCDegradationPreference.MAINTAIN_FRAMERATE_AND_RESOLUTION, + }; } extension RoomOptionsEx on RoomOptions { lk_models.Encryption_Type get lkEncryptionType { // ignore: deprecated_member_use_from_same_package final e2ee = encryption ?? e2eeOptions; - return (e2ee != null) - ? { - EncryptionType.kNone: lk_models.Encryption_Type.NONE, - EncryptionType.kGcm: lk_models.Encryption_Type.GCM, - EncryptionType.kCustom: lk_models.Encryption_Type.CUSTOM, - }[e2ee.encryptionType]! - : lk_models.Encryption_Type.NONE; + return switch (e2ee?.encryptionType) { + EncryptionType.kNone || null => lk_models.Encryption_Type.NONE, + EncryptionType.kGcm => lk_models.Encryption_Type.GCM, + EncryptionType.kCustom => lk_models.Encryption_Type.CUSTOM, + }; } } diff --git a/lib/src/options.dart b/lib/src/options.dart index 25b807eed..448fe6bbf 100644 --- a/lib/src/options.dart +++ b/lib/src/options.dart @@ -340,7 +340,7 @@ class RoomOptions { } enum DegradationPreference { - @Deprecated('DISABLED is Deprecated for DegradationPreference') + @Deprecated('Use maintainFramerateAndResolution instead, WebRTC defines disabled as an alias for it') disabled, maintainFramerate, maintainResolution, diff --git a/lib/src/support/native_audio.dart b/lib/src/support/native_audio.dart index 0cce554f0..e09fa8e08 100644 --- a/lib/src/support/native_audio.dart +++ b/lib/src/support/native_audio.dart @@ -16,39 +16,39 @@ import '../audio/audio_session.dart' show AppleAudioCategory, AppleAudioCategory import 'value_or_absent.dart'; extension AppleAudioCategoryExt on AppleAudioCategory { - String toStringValue() => { - AppleAudioCategory.soloAmbient: 'soloAmbient', - AppleAudioCategory.playback: 'playback', - AppleAudioCategory.record: 'record', - AppleAudioCategory.playAndRecord: 'playAndRecord', - AppleAudioCategory.multiRoute: 'multiRoute', - }[this]!; + String toStringValue() => switch (this) { + AppleAudioCategory.soloAmbient => 'soloAmbient', + AppleAudioCategory.playback => 'playback', + AppleAudioCategory.record => 'record', + AppleAudioCategory.playAndRecord => 'playAndRecord', + AppleAudioCategory.multiRoute => 'multiRoute', + }; } extension AppleAudioCategoryOptionExt on AppleAudioCategoryOption { - String toStringValue() => { - AppleAudioCategoryOption.mixWithOthers: 'mixWithOthers', - AppleAudioCategoryOption.duckOthers: 'duckOthers', - AppleAudioCategoryOption.interruptSpokenAudioAndMixWithOthers: 'interruptSpokenAudioAndMixWithOthers', - AppleAudioCategoryOption.allowBluetooth: 'allowBluetooth', - AppleAudioCategoryOption.allowBluetoothA2DP: 'allowBluetoothA2DP', - AppleAudioCategoryOption.allowAirPlay: 'allowAirPlay', - AppleAudioCategoryOption.defaultToSpeaker: 'defaultToSpeaker', - }[this]!; + String toStringValue() => switch (this) { + AppleAudioCategoryOption.mixWithOthers => 'mixWithOthers', + AppleAudioCategoryOption.duckOthers => 'duckOthers', + AppleAudioCategoryOption.interruptSpokenAudioAndMixWithOthers => 'interruptSpokenAudioAndMixWithOthers', + AppleAudioCategoryOption.allowBluetooth => 'allowBluetooth', + AppleAudioCategoryOption.allowBluetoothA2DP => 'allowBluetoothA2DP', + AppleAudioCategoryOption.allowAirPlay => 'allowAirPlay', + AppleAudioCategoryOption.defaultToSpeaker => 'defaultToSpeaker', + }; } extension AppleAudioModeExt on AppleAudioMode { - String toStringValue() => { - AppleAudioMode.default_: 'default', - AppleAudioMode.gameChat: 'gameChat', - AppleAudioMode.measurement: 'measurement', - AppleAudioMode.moviePlayback: 'moviePlayback', - AppleAudioMode.spokenAudio: 'spokenAudio', - AppleAudioMode.videoChat: 'videoChat', - AppleAudioMode.videoRecording: 'videoRecording', - AppleAudioMode.voiceChat: 'voiceChat', - AppleAudioMode.voicePrompt: 'voicePrompt', - }[this]!; + String toStringValue() => switch (this) { + AppleAudioMode.default_ => 'default', + AppleAudioMode.gameChat => 'gameChat', + AppleAudioMode.measurement => 'measurement', + AppleAudioMode.moviePlayback => 'moviePlayback', + AppleAudioMode.spokenAudio => 'spokenAudio', + AppleAudioMode.videoChat => 'videoChat', + AppleAudioMode.videoRecording => 'videoRecording', + AppleAudioMode.voiceChat => 'voiceChat', + AppleAudioMode.voicePrompt => 'voicePrompt', + }; } class NativeAudioConfiguration { diff --git a/lib/src/track/options.dart b/lib/src/track/options.dart index 7ada778a0..3b1b8f0e7 100644 --- a/lib/src/track/options.dart +++ b/lib/src/track/options.dart @@ -37,10 +37,10 @@ enum CameraExposureMode { auto, locked } /// Convenience extension for [CameraPosition]. extension CameraPositionExt on CameraPosition { /// Return a [CameraPosition] which front and back is switched. - CameraPosition switched() => { - CameraPosition.front: CameraPosition.back, - CameraPosition.back: CameraPosition.front, - }[this]!; + CameraPosition switched() => switch (this) { + CameraPosition.front => CameraPosition.back, + CameraPosition.back => CameraPosition.front, + }; } /// Options used when creating a [LocalVideoTrack] that captures the camera. diff --git a/test/types/degradation_preference_rtc_test.dart b/test/types/degradation_preference_rtc_test.dart new file mode 100644 index 000000000..afd4f0400 --- /dev/null +++ b/test/types/degradation_preference_rtc_test.dart @@ -0,0 +1,38 @@ +// Copyright 2026 LiveKit, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import 'package:flutter_test/flutter_test.dart'; +import 'package:flutter_webrtc/flutter_webrtc.dart' as rtc; + +import 'package:livekit_client/src/extensions.dart'; +import 'package:livekit_client/src/options.dart'; + +void main() { + group('DegradationPreference.toRTCType', () { + test('converts every value without throwing', () { + for (final preference in DegradationPreference.values) { + expect(() => preference.toRTCType(), returnsNormally); + } + }); + + test('deprecated disabled maps to maintain framerate and resolution', () { + // WebRTC defines DISABLED as an alias for MAINTAIN_FRAMERATE_AND_RESOLUTION + expect( + // ignore: deprecated_member_use_from_same_package + DegradationPreference.disabled.toRTCType(), + rtc.RTCDegradationPreference.MAINTAIN_FRAMERATE_AND_RESOLUTION, + ); + }); + }); +} diff --git a/test/types/proto_enum_conversion_test.dart b/test/types/proto_enum_conversion_test.dart new file mode 100644 index 000000000..320cf0838 --- /dev/null +++ b/test/types/proto_enum_conversion_test.dart @@ -0,0 +1,109 @@ +// Copyright 2026 LiveKit, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import 'package:flutter_test/flutter_test.dart'; + +import 'package:livekit_client/src/e2ee/options.dart'; +import 'package:livekit_client/src/extensions.dart'; +import 'package:livekit_client/src/proto/livekit_models.pb.dart' as lk_models; +import 'package:livekit_client/src/proto/livekit_rtc.pb.dart' as lk_rtc; +import 'package:livekit_client/src/types/other.dart'; + +// The switches converting protobuf enums in extensions.dart cannot be compile +// time exhaustive, protobuf enums are classes rather than Dart enums, so new +// proto values silently take the wildcard arm. These tests pin the value count +// of each converted proto enum. When a count assertion fails after a proto +// regen, decide how the new value should convert in extensions.dart, then +// update the count and expectations here. +const countHint = 'proto enum gained a value, update the conversion in extensions.dart'; + +void main() { + group('protobuf enum conversions cover every proto value', () { + test('DataPacket_Kind', () { + expect(lk_models.DataPacket_Kind.values, hasLength(2), reason: countHint); + expect(lk_models.DataPacket_Kind.RELIABLE.toSDKType(), Reliability.reliable); + expect(lk_models.DataPacket_Kind.LOSSY.toSDKType(), Reliability.lossy); + }); + + test('ConnectionQuality', () { + expect(lk_models.ConnectionQuality.values, hasLength(4), reason: countHint); + expect(lk_models.ConnectionQuality.LOST.toLKType(), ConnectionQuality.lost); + expect(lk_models.ConnectionQuality.POOR.toLKType(), ConnectionQuality.poor); + expect(lk_models.ConnectionQuality.GOOD.toLKType(), ConnectionQuality.good); + expect(lk_models.ConnectionQuality.EXCELLENT.toLKType(), ConnectionQuality.excellent); + }); + + test('VideoQuality', () { + expect(lk_models.VideoQuality.values, hasLength(4), reason: countHint); + expect(lk_models.VideoQuality.LOW.toLKType(), VideoQuality.LOW); + expect(lk_models.VideoQuality.MEDIUM.toLKType(), VideoQuality.MEDIUM); + expect(lk_models.VideoQuality.HIGH.toLKType(), VideoQuality.HIGH); + // the SDK enum has no OFF member, collapsing to LOW is intentional + expect(lk_models.VideoQuality.OFF.toLKType(), VideoQuality.LOW); + }); + + test('TrackType', () { + expect(lk_models.TrackType.values, hasLength(3), reason: countHint); + expect(lk_models.TrackType.AUDIO.toLKType(), TrackType.AUDIO); + expect(lk_models.TrackType.VIDEO.toLKType(), TrackType.VIDEO); + expect(lk_models.TrackType.DATA.toLKType(), TrackType.DATA); + }); + + test('TrackSource', () { + expect(lk_models.TrackSource.values, hasLength(5), reason: countHint); + expect(lk_models.TrackSource.UNKNOWN.toLKType(), TrackSource.unknown); + expect(lk_models.TrackSource.CAMERA.toLKType(), TrackSource.camera); + expect(lk_models.TrackSource.MICROPHONE.toLKType(), TrackSource.microphone); + expect(lk_models.TrackSource.SCREEN_SHARE.toLKType(), TrackSource.screenShareVideo); + expect(lk_models.TrackSource.SCREEN_SHARE_AUDIO.toLKType(), TrackSource.screenShareAudio); + }); + + test('StreamState', () { + expect(lk_rtc.StreamState.values, hasLength(2), reason: countHint); + expect(lk_rtc.StreamState.ACTIVE.toLKType(), StreamState.active); + expect(lk_rtc.StreamState.PAUSED.toLKType(), StreamState.paused); + }); + + test('Encryption_Type', () { + expect(lk_models.Encryption_Type.values, hasLength(3), reason: countHint); + expect(lk_models.Encryption_Type.NONE.toLkType(), EncryptionType.kNone); + expect(lk_models.Encryption_Type.GCM.toLkType(), EncryptionType.kGcm); + expect(lk_models.Encryption_Type.CUSTOM.toLkType(), EncryptionType.kCustom); + }); + + test('ParticipantInfo_Kind', () { + expect(lk_models.ParticipantInfo_Kind.values, hasLength(7), reason: countHint); + expect(lk_models.ParticipantInfo_Kind.STANDARD.toLKType(), ParticipantKind.STANDARD); + expect(lk_models.ParticipantInfo_Kind.INGRESS.toLKType(), ParticipantKind.INGRESS); + expect(lk_models.ParticipantInfo_Kind.EGRESS.toLKType(), ParticipantKind.EGRESS); + expect(lk_models.ParticipantInfo_Kind.SIP.toLKType(), ParticipantKind.SIP); + expect(lk_models.ParticipantInfo_Kind.AGENT.toLKType(), ParticipantKind.AGENT); + // the SDK enum has no members for these yet, they collapse to STANDARD + expect(lk_models.ParticipantInfo_Kind.CONNECTOR.toLKType(), ParticipantKind.STANDARD); + expect(lk_models.ParticipantInfo_Kind.BRIDGE.toLKType(), ParticipantKind.STANDARD); + }); + + test('DisconnectReason', () { + expect(lk_models.DisconnectReason.values, hasLength(17), reason: countHint); + expect(lk_models.DisconnectReason.UNKNOWN_REASON.toSDKType(), DisconnectReason.unknown); + expect(lk_models.DisconnectReason.CLIENT_INITIATED.toSDKType(), DisconnectReason.clientInitiated); + expect(lk_models.DisconnectReason.DUPLICATE_IDENTITY.toSDKType(), DisconnectReason.duplicateIdentity); + expect(lk_models.DisconnectReason.SERVER_SHUTDOWN.toSDKType(), DisconnectReason.serverShutdown); + expect(lk_models.DisconnectReason.PARTICIPANT_REMOVED.toSDKType(), DisconnectReason.participantRemoved); + expect(lk_models.DisconnectReason.ROOM_DELETED.toSDKType(), DisconnectReason.roomDeleted); + expect(lk_models.DisconnectReason.STATE_MISMATCH.toSDKType(), DisconnectReason.stateMismatch); + expect(lk_models.DisconnectReason.JOIN_FAILURE.toSDKType(), DisconnectReason.joinFailure); + }); + }); +}