Skip to content

Commit

Permalink
Add support for participant attributes (#558)
Browse files Browse the repository at this point in the history
* upgrade protocol to v1.19.1.

* Add Attributes for Participant.

* change attributes to UnmodifiableMapView.

* update ParticipantPermissions.

* dart run import_sorter:main.

* fix.
  • Loading branch information
cloudwebrtc authored Jul 23, 2024
1 parent 76973a3 commit 5b11500
Show file tree
Hide file tree
Showing 10 changed files with 414 additions and 21 deletions.
15 changes: 15 additions & 0 deletions lib/src/events.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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<String, String> 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 {
Expand Down
9 changes: 9 additions & 0 deletions lib/src/participant/local.dart
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,15 @@ class LocalParticipant extends Participant<LocalTrackPublication> {
));
}

/// Sets and updates the attributes of the local participant.
/// @attributes key-value pairs to set
void setAttributes(Map<String, String> 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
Expand Down
20 changes: 20 additions & 0 deletions lib/src/participant/participant.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -78,6 +79,11 @@ abstract class Participant<T extends TrackPublication>
ParticipantPermissions _permissions = const ParticipantPermissions();
ParticipantPermissions get permissions => _permissions;

/// Attributes associated with the participant
UnmodifiableMapView<String, String> get attributes =>
UnmodifiableMapView(_attributes);
Map<String, String> _attributes = {};

/// when the participant joined the room
DateTime get joinedAt {
final pi = _participantInfo;
Expand Down Expand Up @@ -170,6 +176,18 @@ abstract class Participant<T extends TrackPublication>
}
}

void _setAttributes(Map<String, String> 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;
Expand All @@ -196,6 +214,8 @@ abstract class Participant<T extends TrackPublication>
if (info.metadata.isNotEmpty) {
_setMetadata(info.metadata);
}

_setAttributes(info.attributes);
_participantInfo = info;
setPermissions(info.permission.toLKType());

Expand Down
30 changes: 27 additions & 3 deletions lib/src/proto/livekit_models.pb.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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<TrackSource>? canPublishSources,
$core.bool? canUpdateMetadata,
$core.bool? agent,
@$core.Deprecated('This field is deprecated.') $core.bool? agent,
}) {
final $result = create();
if (canSubscribe != null) {
Expand All @@ -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) {
Expand All @@ -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;
Expand Down Expand Up @@ -595,23 +597,28 @@ 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);

/// sources that are allowed to be published
@$pb.TagNumber(9)
$core.List<TrackSource> 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)
Expand All @@ -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);
}
Expand All @@ -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) {
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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. '
Expand Down Expand Up @@ -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 {
Expand Down
52 changes: 44 additions & 8 deletions lib/src/proto/livekit_models.pbjson.dart
Original file line number Diff line number Diff line change
Expand Up @@ -308,15 +308,29 @@ 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,
'4': 1,
'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',
},
],
};

Expand All @@ -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 = {
Expand Down Expand Up @@ -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',
Expand Down Expand Up @@ -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 = {
Expand Down
Loading

0 comments on commit 5b11500

Please sign in to comment.