diff --git a/lib/src/events.dart b/lib/src/events.dart index 9f1db806..8b2f7975 100644 --- a/lib/src/events.dart +++ b/lib/src/events.dart @@ -115,6 +115,21 @@ class RoomMetadataChangedEvent with RoomEvent { String toString() => '${runtimeType}()'; } +/// Participant's attributes have changed. +/// Emitted by [Room]. +class ParticipantAttributesChanged with RoomEvent, ParticipantEvent { + final Participant participant; + final Map attributes; + + const ParticipantAttributesChanged({ + required this.participant, + required this.attributes, + }); + + @override + String toString() => '${runtimeType}(participant: ${participant})'; +} + /// Room recording status has changed. /// Emitted by [Room]. class RoomRecordingStatusChanged with RoomEvent { diff --git a/lib/src/participant/local.dart b/lib/src/participant/local.dart index 66a27713..3703d27d 100644 --- a/lib/src/participant/local.dart +++ b/lib/src/participant/local.dart @@ -466,6 +466,15 @@ class LocalParticipant extends Participant { )); } + /// Sets and updates the attributes of the local participant. + /// @attributes key-value pairs to set + void setAttributes(Map attributes) { + room.engine.signalClient + .sendUpdateLocalMetadata(lk_rtc.UpdateParticipantMetadata( + attributes: attributes, + )); + } + /// Sets and updates the name of the local participant. /// Note: this requires `CanUpdateOwnMetadata` permission encoded in the token. /// @param name diff --git a/lib/src/participant/participant.dart b/lib/src/participant/participant.dart index 4e2676fd..33e5501f 100644 --- a/lib/src/participant/participant.dart +++ b/lib/src/participant/participant.dart @@ -26,6 +26,7 @@ import '../publication/track_publication.dart'; import '../support/disposable.dart'; import '../types/other.dart'; import '../types/participant_permissions.dart'; +import '../utils.dart'; /// Represents a Participant in the room, notifies changes via delegates as /// well as ChangeNotifier/providers. @@ -78,6 +79,11 @@ abstract class Participant ParticipantPermissions _permissions = const ParticipantPermissions(); ParticipantPermissions get permissions => _permissions; + /// Attributes associated with the participant + UnmodifiableMapView get attributes => + UnmodifiableMapView(_attributes); + Map _attributes = {}; + /// when the participant joined the room DateTime get joinedAt { final pi = _participantInfo; @@ -170,6 +176,18 @@ abstract class Participant } } + void _setAttributes(Map attrs) { + final diff = mapDiff(_attributes, attrs) + .map((k, v) => MapEntry(k as String, v as String)); + _attributes = attrs; + if (diff.isNotEmpty) { + [ + events, + room.events + ].emit(ParticipantAttributesChanged(participant: this, attributes: diff)); + } + } + @internal void updateConnectionQuality(ConnectionQuality quality) { if (_connectionQuality == quality) return; @@ -196,6 +214,8 @@ abstract class Participant if (info.metadata.isNotEmpty) { _setMetadata(info.metadata); } + + _setAttributes(info.attributes); _participantInfo = info; setPermissions(info.permission.toLKType()); diff --git a/lib/src/proto/livekit_models.pb.dart b/lib/src/proto/livekit_models.pb.dart index 35de7544..cf1719b7 100644 --- a/lib/src/proto/livekit_models.pb.dart +++ b/lib/src/proto/livekit_models.pb.dart @@ -459,10 +459,10 @@ class ParticipantPermission extends $pb.GeneratedMessage { $core.bool? canPublish, $core.bool? canPublishData, $core.bool? hidden, - $core.bool? recorder, + @$core.Deprecated('This field is deprecated.') $core.bool? recorder, $core.Iterable? canPublishSources, $core.bool? canUpdateMetadata, - $core.bool? agent, + @$core.Deprecated('This field is deprecated.') $core.bool? agent, }) { final $result = create(); if (canSubscribe != null) { @@ -478,6 +478,7 @@ class ParticipantPermission extends $pb.GeneratedMessage { $result.hidden = hidden; } if (recorder != null) { + // ignore: deprecated_member_use_from_same_package $result.recorder = recorder; } if (canPublishSources != null) { @@ -487,6 +488,7 @@ class ParticipantPermission extends $pb.GeneratedMessage { $result.canUpdateMetadata = canUpdateMetadata; } if (agent != null) { + // ignore: deprecated_member_use_from_same_package $result.agent = agent; } return $result; @@ -595,15 +597,20 @@ class ParticipantPermission extends $pb.GeneratedMessage { void clearHidden() => clearField(7); /// indicates it's a recorder instance + /// deprecated: use ParticipantInfo.kind instead + @$core.Deprecated('This field is deprecated.') @$pb.TagNumber(8) $core.bool get recorder => $_getBF(4); + @$core.Deprecated('This field is deprecated.') @$pb.TagNumber(8) set recorder($core.bool v) { $_setBool(4, v); } + @$core.Deprecated('This field is deprecated.') @$pb.TagNumber(8) $core.bool hasRecorder() => $_has(4); + @$core.Deprecated('This field is deprecated.') @$pb.TagNumber(8) void clearRecorder() => clearField(8); @@ -611,7 +618,7 @@ class ParticipantPermission extends $pb.GeneratedMessage { @$pb.TagNumber(9) $core.List get canPublishSources => $_getList(5); - /// indicates that participant can update own metadata + /// indicates that participant can update own metadata and attributes @$pb.TagNumber(10) $core.bool get canUpdateMetadata => $_getBF(6); @$pb.TagNumber(10) @@ -625,15 +632,20 @@ class ParticipantPermission extends $pb.GeneratedMessage { void clearCanUpdateMetadata() => clearField(10); /// indicates that participant is an agent + /// deprecated: use ParticipantInfo.kind instead + @$core.Deprecated('This field is deprecated.') @$pb.TagNumber(11) $core.bool get agent => $_getBF(7); + @$core.Deprecated('This field is deprecated.') @$pb.TagNumber(11) set agent($core.bool v) { $_setBool(7, v); } + @$core.Deprecated('This field is deprecated.') @$pb.TagNumber(11) $core.bool hasAgent() => $_has(7); + @$core.Deprecated('This field is deprecated.') @$pb.TagNumber(11) void clearAgent() => clearField(11); } @@ -652,6 +664,7 @@ class ParticipantInfo extends $pb.GeneratedMessage { $core.String? region, $core.bool? isPublisher, ParticipantInfo_Kind? kind, + $core.Map<$core.String, $core.String>? attributes, }) { final $result = create(); if (sid != null) { @@ -690,6 +703,9 @@ class ParticipantInfo extends $pb.GeneratedMessage { if (kind != null) { $result.kind = kind; } + if (attributes != null) { + $result.attributes.addAll(attributes); + } return $result; } ParticipantInfo._() : super(); @@ -726,6 +742,11 @@ class ParticipantInfo extends $pb.GeneratedMessage { defaultOrMaker: ParticipantInfo_Kind.STANDARD, valueOf: ParticipantInfo_Kind.valueOf, enumValues: ParticipantInfo_Kind.values) + ..m<$core.String, $core.String>(15, _omitFieldNames ? '' : 'attributes', + entryClassName: 'ParticipantInfo.AttributesEntry', + keyFieldType: $pb.PbFieldType.OS, + valueFieldType: $pb.PbFieldType.OS, + packageName: const $pb.PackageName('livekit')) ..hasRequiredFields = false; @$core.Deprecated('Using this can add significant overhead to your binary. ' @@ -890,6 +911,9 @@ class ParticipantInfo extends $pb.GeneratedMessage { $core.bool hasKind() => $_has(11); @$pb.TagNumber(14) void clearKind() => clearField(14); + + @$pb.TagNumber(15) + $core.Map<$core.String, $core.String> get attributes => $_getMap(12); } class Encryption extends $pb.GeneratedMessage { diff --git a/lib/src/proto/livekit_models.pbjson.dart b/lib/src/proto/livekit_models.pbjson.dart index 97f045d7..854b6a21 100644 --- a/lib/src/proto/livekit_models.pbjson.dart +++ b/lib/src/proto/livekit_models.pbjson.dart @@ -308,7 +308,14 @@ const ParticipantPermission$json = { '10': 'canPublishSources' }, {'1': 'hidden', '3': 7, '4': 1, '5': 8, '10': 'hidden'}, - {'1': 'recorder', '3': 8, '4': 1, '5': 8, '10': 'recorder'}, + { + '1': 'recorder', + '3': 8, + '4': 1, + '5': 8, + '8': {'3': true}, + '10': 'recorder', + }, { '1': 'can_update_metadata', '3': 10, @@ -316,7 +323,14 @@ const ParticipantPermission$json = { '5': 8, '10': 'canUpdateMetadata' }, - {'1': 'agent', '3': 11, '4': 1, '5': 8, '10': 'agent'}, + { + '1': 'agent', + '3': 11, + '4': 1, + '5': 8, + '8': {'3': true}, + '10': 'agent', + }, ], }; @@ -326,8 +340,9 @@ final $typed_data.Uint8List participantPermissionDescriptor = $convert.base64Dec 'NyaWJlEh8KC2Nhbl9wdWJsaXNoGAIgASgIUgpjYW5QdWJsaXNoEigKEGNhbl9wdWJsaXNoX2Rh' 'dGEYAyABKAhSDmNhblB1Ymxpc2hEYXRhEkQKE2Nhbl9wdWJsaXNoX3NvdXJjZXMYCSADKA4yFC' '5saXZla2l0LlRyYWNrU291cmNlUhFjYW5QdWJsaXNoU291cmNlcxIWCgZoaWRkZW4YByABKAhS' - 'BmhpZGRlbhIaCghyZWNvcmRlchgIIAEoCFIIcmVjb3JkZXISLgoTY2FuX3VwZGF0ZV9tZXRhZG' - 'F0YRgKIAEoCFIRY2FuVXBkYXRlTWV0YWRhdGESFAoFYWdlbnQYCyABKAhSBWFnZW50'); + 'BmhpZGRlbhIeCghyZWNvcmRlchgIIAEoCEICGAFSCHJlY29yZGVyEi4KE2Nhbl91cGRhdGVfbW' + 'V0YWRhdGEYCiABKAhSEWNhblVwZGF0ZU1ldGFkYXRhEhgKBWFnZW50GAsgASgIQgIYAVIFYWdl' + 'bnQ='); @$core.Deprecated('Use participantInfoDescriptor instead') const ParticipantInfo$json = { @@ -373,10 +388,29 @@ const ParticipantInfo$json = { '6': '.livekit.ParticipantInfo.Kind', '10': 'kind' }, + { + '1': 'attributes', + '3': 15, + '4': 3, + '5': 11, + '6': '.livekit.ParticipantInfo.AttributesEntry', + '10': 'attributes' + }, ], + '3': [ParticipantInfo_AttributesEntry$json], '4': [ParticipantInfo_State$json, ParticipantInfo_Kind$json], }; +@$core.Deprecated('Use participantInfoDescriptor instead') +const ParticipantInfo_AttributesEntry$json = { + '1': 'AttributesEntry', + '2': [ + {'1': 'key', '3': 1, '4': 1, '5': 9, '10': 'key'}, + {'1': 'value', '3': 2, '4': 1, '5': 9, '10': 'value'}, + ], + '7': {'7': true}, +}; + @$core.Deprecated('Use participantInfoDescriptor instead') const ParticipantInfo_State$json = { '1': 'State', @@ -409,10 +443,12 @@ final $typed_data.Uint8List participantInfoDescriptor = $convert.base64Decode( 'bmFtZRgJIAEoCVIEbmFtZRIYCgd2ZXJzaW9uGAogASgNUgd2ZXJzaW9uEj4KCnBlcm1pc3Npb2' '4YCyABKAsyHi5saXZla2l0LlBhcnRpY2lwYW50UGVybWlzc2lvblIKcGVybWlzc2lvbhIWCgZy' 'ZWdpb24YDCABKAlSBnJlZ2lvbhIhCgxpc19wdWJsaXNoZXIYDSABKAhSC2lzUHVibGlzaGVyEj' - 'EKBGtpbmQYDiABKA4yHS5saXZla2l0LlBhcnRpY2lwYW50SW5mby5LaW5kUgRraW5kIj4KBVN0' - 'YXRlEgsKB0pPSU5JTkcQABIKCgZKT0lORUQQARIKCgZBQ1RJVkUQAhIQCgxESVNDT05ORUNURU' - 'QQAyJBCgRLaW5kEgwKCFNUQU5EQVJEEAASCwoHSU5HUkVTUxABEgoKBkVHUkVTUxACEgcKA1NJ' - 'UBADEgkKBUFHRU5UEAQ='); + 'EKBGtpbmQYDiABKA4yHS5saXZla2l0LlBhcnRpY2lwYW50SW5mby5LaW5kUgRraW5kEkgKCmF0' + 'dHJpYnV0ZXMYDyADKAsyKC5saXZla2l0LlBhcnRpY2lwYW50SW5mby5BdHRyaWJ1dGVzRW50cn' + 'lSCmF0dHJpYnV0ZXMaPQoPQXR0cmlidXRlc0VudHJ5EhAKA2tleRgBIAEoCVIDa2V5EhQKBXZh' + 'bHVlGAIgASgJUgV2YWx1ZToCOAEiPgoFU3RhdGUSCwoHSk9JTklORxAAEgoKBkpPSU5FRBABEg' + 'oKBkFDVElWRRACEhAKDERJU0NPTk5FQ1RFRBADIkEKBEtpbmQSDAoIU1RBTkRBUkQQABILCgdJ' + 'TkdSRVNTEAESCgoGRUdSRVNTEAISBwoDU0lQEAMSCQoFQUdFTlQQBA=='); @$core.Deprecated('Use encryptionDescriptor instead') const Encryption$json = { diff --git a/lib/src/proto/livekit_rtc.pb.dart b/lib/src/proto/livekit_rtc.pb.dart index 1980f1fc..ddf6ebeb 100644 --- a/lib/src/proto/livekit_rtc.pb.dart +++ b/lib/src/proto/livekit_rtc.pb.dart @@ -410,7 +410,8 @@ class SignalRequest extends $pb.GeneratedMessage { @$pb.TagNumber(14) void clearPing() => clearField(14); - /// update a participant's own metadata and/or name + /// update a participant's own metadata, name, or attributes + /// requires canUpdateOwnParticipantMetadata permission @$pb.TagNumber(15) UpdateParticipantMetadata get updateMetadata => $_getN(13); @$pb.TagNumber(15) @@ -491,6 +492,7 @@ enum SignalResponse_Message { reconnect, pongResp, subscriptionResponse, + errorResponse, notSet } @@ -516,6 +518,7 @@ class SignalResponse extends $pb.GeneratedMessage { ReconnectResponse? reconnect, Pong? pongResp, SubscriptionResponse? subscriptionResponse, + ErrorResponse? errorResponse, }) { final $result = create(); if (join != null) { @@ -578,6 +581,9 @@ class SignalResponse extends $pb.GeneratedMessage { if (subscriptionResponse != null) { $result.subscriptionResponse = subscriptionResponse; } + if (errorResponse != null) { + $result.errorResponse = errorResponse; + } return $result; } SignalResponse._() : super(); @@ -610,6 +616,7 @@ class SignalResponse extends $pb.GeneratedMessage { 19: SignalResponse_Message.reconnect, 20: SignalResponse_Message.pongResp, 21: SignalResponse_Message.subscriptionResponse, + 22: SignalResponse_Message.errorResponse, 0: SignalResponse_Message.notSet }; static final $pb.BuilderInfo _i = $pb.BuilderInfo( @@ -636,7 +643,8 @@ class SignalResponse extends $pb.GeneratedMessage { 18, 19, 20, - 21 + 21, + 22 ]) ..aOM(1, _omitFieldNames ? '' : 'join', subBuilder: JoinResponse.create) @@ -680,6 +688,8 @@ class SignalResponse extends $pb.GeneratedMessage { ..aOM( 21, _omitFieldNames ? '' : 'subscriptionResponse', subBuilder: SubscriptionResponse.create) + ..aOM(22, _omitFieldNames ? '' : 'errorResponse', + subBuilder: ErrorResponse.create) ..hasRequiredFields = false; @$core.Deprecated('Using this can add significant overhead to your binary. ' @@ -1006,6 +1016,21 @@ class SignalResponse extends $pb.GeneratedMessage { void clearSubscriptionResponse() => clearField(21); @$pb.TagNumber(21) SubscriptionResponse ensureSubscriptionResponse() => $_ensure(19); + + /// Errors relating to user inititated requests that carry a `request_id` + @$pb.TagNumber(22) + ErrorResponse get errorResponse => $_getN(20); + @$pb.TagNumber(22) + set errorResponse(ErrorResponse v) { + setField(22, v); + } + + @$pb.TagNumber(22) + $core.bool hasErrorResponse() => $_has(20); + @$pb.TagNumber(22) + void clearErrorResponse() => clearField(22); + @$pb.TagNumber(22) + ErrorResponse ensureErrorResponse() => $_ensure(20); } class SimulcastCodec extends $pb.GeneratedMessage { @@ -2790,6 +2815,8 @@ class UpdateParticipantMetadata extends $pb.GeneratedMessage { factory UpdateParticipantMetadata({ $core.String? metadata, $core.String? name, + $core.Map<$core.String, $core.String>? attributes, + $core.int? requestId, }) { final $result = create(); if (metadata != null) { @@ -2798,6 +2825,12 @@ class UpdateParticipantMetadata extends $pb.GeneratedMessage { if (name != null) { $result.name = name; } + if (attributes != null) { + $result.attributes.addAll(attributes); + } + if (requestId != null) { + $result.requestId = requestId; + } return $result; } UpdateParticipantMetadata._() : super(); @@ -2814,6 +2847,12 @@ class UpdateParticipantMetadata extends $pb.GeneratedMessage { createEmptyInstance: create) ..aOS(1, _omitFieldNames ? '' : 'metadata') ..aOS(2, _omitFieldNames ? '' : 'name') + ..m<$core.String, $core.String>(3, _omitFieldNames ? '' : 'attributes', + entryClassName: 'UpdateParticipantMetadata.AttributesEntry', + keyFieldType: $pb.PbFieldType.OS, + valueFieldType: $pb.PbFieldType.OS, + packageName: const $pb.PackageName('livekit')) + ..a<$core.int>(4, _omitFieldNames ? '' : 'requestId', $pb.PbFieldType.OU3) ..hasRequiredFields = false; @$core.Deprecated('Using this can add significant overhead to your binary. ' @@ -2864,6 +2903,23 @@ class UpdateParticipantMetadata extends $pb.GeneratedMessage { $core.bool hasName() => $_has(1); @$pb.TagNumber(2) void clearName() => clearField(2); + + /// attributes to update. it only updates attributes that have been set + /// to delete attributes, set the value to an empty string + @$pb.TagNumber(3) + $core.Map<$core.String, $core.String> get attributes => $_getMap(2); + + @$pb.TagNumber(4) + $core.int get requestId => $_getIZ(3); + @$pb.TagNumber(4) + set requestId($core.int v) { + $_setUnsignedInt32(3, v); + } + + @$pb.TagNumber(4) + $core.bool hasRequestId() => $_has(3); + @$pb.TagNumber(4) + void clearRequestId() => clearField(4); } class ICEServer extends $pb.GeneratedMessage { @@ -4743,6 +4799,105 @@ class SubscriptionResponse extends $pb.GeneratedMessage { void clearErr() => clearField(2); } +class ErrorResponse extends $pb.GeneratedMessage { + factory ErrorResponse({ + $core.int? requestId, + ErrorResponse_Reason? reason, + $core.String? message, + }) { + final $result = create(); + if (requestId != null) { + $result.requestId = requestId; + } + if (reason != null) { + $result.reason = reason; + } + if (message != null) { + $result.message = message; + } + return $result; + } + ErrorResponse._() : super(); + factory ErrorResponse.fromBuffer($core.List<$core.int> i, + [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(i, r); + factory ErrorResponse.fromJson($core.String i, + [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(i, r); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'ErrorResponse', + package: const $pb.PackageName(_omitMessageNames ? '' : 'livekit'), + createEmptyInstance: create) + ..a<$core.int>(1, _omitFieldNames ? '' : 'requestId', $pb.PbFieldType.OU3) + ..e( + 2, _omitFieldNames ? '' : 'reason', $pb.PbFieldType.OE, + defaultOrMaker: ErrorResponse_Reason.UNKNOWN, + valueOf: ErrorResponse_Reason.valueOf, + enumValues: ErrorResponse_Reason.values) + ..aOS(3, _omitFieldNames ? '' : 'message') + ..hasRequiredFields = false; + + @$core.Deprecated('Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + ErrorResponse clone() => ErrorResponse()..mergeFromMessage(this); + @$core.Deprecated('Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + ErrorResponse copyWith(void Function(ErrorResponse) updates) => + super.copyWith((message) => updates(message as ErrorResponse)) + as ErrorResponse; + + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static ErrorResponse create() => ErrorResponse._(); + ErrorResponse createEmptyInstance() => create(); + static $pb.PbList createRepeated() => + $pb.PbList(); + @$core.pragma('dart2js:noInline') + static ErrorResponse getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static ErrorResponse? _defaultInstance; + + @$pb.TagNumber(1) + $core.int get requestId => $_getIZ(0); + @$pb.TagNumber(1) + set requestId($core.int v) { + $_setUnsignedInt32(0, v); + } + + @$pb.TagNumber(1) + $core.bool hasRequestId() => $_has(0); + @$pb.TagNumber(1) + void clearRequestId() => clearField(1); + + @$pb.TagNumber(2) + ErrorResponse_Reason get reason => $_getN(1); + @$pb.TagNumber(2) + set reason(ErrorResponse_Reason v) { + setField(2, v); + } + + @$pb.TagNumber(2) + $core.bool hasReason() => $_has(1); + @$pb.TagNumber(2) + void clearReason() => clearField(2); + + @$pb.TagNumber(3) + $core.String get message => $_getSZ(2); + @$pb.TagNumber(3) + set message($core.String v) { + $_setString(2, v); + } + + @$pb.TagNumber(3) + $core.bool hasMessage() => $_has(2); + @$pb.TagNumber(3) + void clearMessage() => clearField(3); +} + const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names'); const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names'); diff --git a/lib/src/proto/livekit_rtc.pbenum.dart b/lib/src/proto/livekit_rtc.pbenum.dart index f970e468..33ec6fb9 100644 --- a/lib/src/proto/livekit_rtc.pbenum.dart +++ b/lib/src/proto/livekit_rtc.pbenum.dart @@ -92,4 +92,28 @@ class LeaveRequest_Action extends $pb.ProtobufEnum { const LeaveRequest_Action._($core.int v, $core.String n) : super(v, n); } +class ErrorResponse_Reason extends $pb.ProtobufEnum { + static const ErrorResponse_Reason UNKNOWN = + ErrorResponse_Reason._(0, _omitEnumNames ? '' : 'UNKNOWN'); + static const ErrorResponse_Reason NOT_FOUND = + ErrorResponse_Reason._(1, _omitEnumNames ? '' : 'NOT_FOUND'); + static const ErrorResponse_Reason NOT_ALLOWED = + ErrorResponse_Reason._(2, _omitEnumNames ? '' : 'NOT_ALLOWED'); + static const ErrorResponse_Reason INVALID_ARGUMENT = + ErrorResponse_Reason._(3, _omitEnumNames ? '' : 'INVALID_ARGUMENT'); + + static const $core.List values = [ + UNKNOWN, + NOT_FOUND, + NOT_ALLOWED, + INVALID_ARGUMENT, + ]; + + static final $core.Map<$core.int, ErrorResponse_Reason> _byValue = + $pb.ProtobufEnum.initByValue(values); + static ErrorResponse_Reason? valueOf($core.int value) => _byValue[value]; + + const ErrorResponse_Reason._($core.int v, $core.String n) : super(v, n); +} + const _omitEnumNames = $core.bool.fromEnvironment('protobuf.omit_enum_names'); diff --git a/lib/src/proto/livekit_rtc.pbjson.dart b/lib/src/proto/livekit_rtc.pbjson.dart index 00de12b1..2a0da460 100644 --- a/lib/src/proto/livekit_rtc.pbjson.dart +++ b/lib/src/proto/livekit_rtc.pbjson.dart @@ -407,6 +407,15 @@ const SignalResponse$json = { '9': 0, '10': 'subscriptionResponse' }, + { + '1': 'error_response', + '3': 22, + '4': 1, + '5': 11, + '6': '.livekit.ErrorResponse', + '9': 0, + '10': 'errorResponse' + }, ], '8': [ {'1': 'message'}, @@ -438,7 +447,8 @@ final $typed_data.Uint8List signalResponseDescriptor = $convert.base64Decode( 'dmVraXQuUmVjb25uZWN0UmVzcG9uc2VIAFIJcmVjb25uZWN0EiwKCXBvbmdfcmVzcBgUIAEoCz' 'INLmxpdmVraXQuUG9uZ0gAUghwb25nUmVzcBJUChVzdWJzY3JpcHRpb25fcmVzcG9uc2UYFSAB' 'KAsyHS5saXZla2l0LlN1YnNjcmlwdGlvblJlc3BvbnNlSABSFHN1YnNjcmlwdGlvblJlc3Bvbn' - 'NlQgkKB21lc3NhZ2U='); + 'NlEj8KDmVycm9yX3Jlc3BvbnNlGBYgASgLMhYubGl2ZWtpdC5FcnJvclJlc3BvbnNlSABSDWVy' + 'cm9yUmVzcG9uc2VCCQoHbWVzc2FnZQ=='); @$core.Deprecated('Use simulcastCodecDescriptor instead') const SimulcastCodec$json = { @@ -900,14 +910,36 @@ const UpdateParticipantMetadata$json = { '2': [ {'1': 'metadata', '3': 1, '4': 1, '5': 9, '10': 'metadata'}, {'1': 'name', '3': 2, '4': 1, '5': 9, '10': 'name'}, + { + '1': 'attributes', + '3': 3, + '4': 3, + '5': 11, + '6': '.livekit.UpdateParticipantMetadata.AttributesEntry', + '10': 'attributes' + }, + {'1': 'request_id', '3': 4, '4': 1, '5': 13, '10': 'requestId'}, + ], + '3': [UpdateParticipantMetadata_AttributesEntry$json], +}; + +@$core.Deprecated('Use updateParticipantMetadataDescriptor instead') +const UpdateParticipantMetadata_AttributesEntry$json = { + '1': 'AttributesEntry', + '2': [ + {'1': 'key', '3': 1, '4': 1, '5': 9, '10': 'key'}, + {'1': 'value', '3': 2, '4': 1, '5': 9, '10': 'value'}, ], + '7': {'7': true}, }; /// Descriptor for `UpdateParticipantMetadata`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List updateParticipantMetadataDescriptor = - $convert.base64Decode( - 'ChlVcGRhdGVQYXJ0aWNpcGFudE1ldGFkYXRhEhoKCG1ldGFkYXRhGAEgASgJUghtZXRhZGF0YR' - 'ISCgRuYW1lGAIgASgJUgRuYW1l'); +final $typed_data.Uint8List updateParticipantMetadataDescriptor = $convert.base64Decode( + 'ChlVcGRhdGVQYXJ0aWNpcGFudE1ldGFkYXRhEhoKCG1ldGFkYXRhGAEgASgJUghtZXRhZGF0YR' + 'ISCgRuYW1lGAIgASgJUgRuYW1lElIKCmF0dHJpYnV0ZXMYAyADKAsyMi5saXZla2l0LlVwZGF0' + 'ZVBhcnRpY2lwYW50TWV0YWRhdGEuQXR0cmlidXRlc0VudHJ5UgphdHRyaWJ1dGVzEh0KCnJlcX' + 'Vlc3RfaWQYBCABKA1SCXJlcXVlc3RJZBo9Cg9BdHRyaWJ1dGVzRW50cnkSEAoDa2V5GAEgASgJ' + 'UgNrZXkSFAoFdmFsdWUYAiABKAlSBXZhbHVlOgI4AQ=='); @$core.Deprecated('Use iCEServerDescriptor instead') const ICEServer$json = { @@ -1428,3 +1460,39 @@ const SubscriptionResponse$json = { final $typed_data.Uint8List subscriptionResponseDescriptor = $convert.base64Decode( 'ChRTdWJzY3JpcHRpb25SZXNwb25zZRIbCgl0cmFja19zaWQYASABKAlSCHRyYWNrU2lkEiwKA2' 'VychgCIAEoDjIaLmxpdmVraXQuU3Vic2NyaXB0aW9uRXJyb3JSA2Vycg=='); + +@$core.Deprecated('Use errorResponseDescriptor instead') +const ErrorResponse$json = { + '1': 'ErrorResponse', + '2': [ + {'1': 'request_id', '3': 1, '4': 1, '5': 13, '10': 'requestId'}, + { + '1': 'reason', + '3': 2, + '4': 1, + '5': 14, + '6': '.livekit.ErrorResponse.Reason', + '10': 'reason' + }, + {'1': 'message', '3': 3, '4': 1, '5': 9, '10': 'message'}, + ], + '4': [ErrorResponse_Reason$json], +}; + +@$core.Deprecated('Use errorResponseDescriptor instead') +const ErrorResponse_Reason$json = { + '1': 'Reason', + '2': [ + {'1': 'UNKNOWN', '2': 0}, + {'1': 'NOT_FOUND', '2': 1}, + {'1': 'NOT_ALLOWED', '2': 2}, + {'1': 'INVALID_ARGUMENT', '2': 3}, + ], +}; + +/// Descriptor for `ErrorResponse`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List errorResponseDescriptor = $convert.base64Decode( + 'Cg1FcnJvclJlc3BvbnNlEh0KCnJlcXVlc3RfaWQYASABKA1SCXJlcXVlc3RJZBI1CgZyZWFzb2' + '4YAiABKA4yHS5saXZla2l0LkVycm9yUmVzcG9uc2UuUmVhc29uUgZyZWFzb24SGAoHbWVzc2Fn' + 'ZRgDIAEoCVIHbWVzc2FnZSJLCgZSZWFzb24SCwoHVU5LTk9XThAAEg0KCU5PVF9GT1VORBABEg' + '8KC05PVF9BTExPV0VEEAISFAoQSU5WQUxJRF9BUkdVTUVOVBAD'); diff --git a/lib/src/types/participant_permissions.dart b/lib/src/types/participant_permissions.dart index 07c4ac0c..36d6ce41 100644 --- a/lib/src/types/participant_permissions.dart +++ b/lib/src/types/participant_permissions.dart @@ -14,6 +14,7 @@ import 'package:meta/meta.dart'; +import 'package:livekit_client/src/proto/livekit_models.pbenum.dart'; import '../proto/livekit_models.pb.dart' as lk_models; @immutable @@ -22,14 +23,16 @@ class ParticipantPermissions { final bool canPublish; final bool canPublishData; final bool hidden; - final bool recorder; + final bool canUpdateMetadata; + final List canPublishSources; const ParticipantPermissions({ this.canSubscribe = false, this.canPublish = false, this.canPublishData = false, this.hidden = false, - this.recorder = false, + this.canUpdateMetadata = false, + this.canPublishSources = const [], }); } @@ -39,6 +42,7 @@ extension ParticipantPermissionExt on lk_models.ParticipantPermission { canPublish: canPublish, canPublishData: canPublishData, hidden: hidden, - recorder: recorder, + canUpdateMetadata: canUpdateMetadata, + canPublishSources: canPublishSources, ); } diff --git a/lib/src/utils.dart b/lib/src/utils.dart index 30378358..af1613a1 100644 --- a/lib/src/utils.dart +++ b/lib/src/utils.dart @@ -653,3 +653,41 @@ String? buildStreamId(PublishOptions options, TrackSource source) { } return streamId; } + +/// Compares two maps and returns the differences between them. +/// [left] a map to compare. +/// [right] a map to compare. +Map mapDiff(Map left, Map right) { + final rightCopy = Map.of(right); + final diff = {}; + + left.forEach((leftKey, leftValue) { + if (!right.containsKey(leftKey)) { + diff[leftKey] = leftValue; + return; + } + + final rightValue = right[leftKey]; + + switch ((leftValue, rightValue)) { + case (Map(), Map()): + diff[leftKey] = mapDiff(leftValue, rightValue); + break; + case (List(), List()): + if (!const DeepCollectionEquality().equals(leftValue, rightValue)) { + diff[leftKey] = rightValue; + } + break; + case (_, _): + if (leftValue != rightValue) { + diff[leftKey] = rightValue; + } + break; + } + + rightCopy.remove(leftKey); + }); + + return {...diff, ...rightCopy} + ..removeWhere((key, value) => (value is Map && value.isEmpty)); +}