Skip to content

Commit

Permalink
Improvements for example app. (#515)
Browse files Browse the repository at this point in the history
* Improvements for example app.

* update.
  • Loading branch information
cloudwebrtc authored May 20, 2024
1 parent 1d6ee2a commit 1fc66a8
Show file tree
Hide file tree
Showing 7 changed files with 95 additions and 73 deletions.
2 changes: 0 additions & 2 deletions example/lib/pages/prejoin.dart
Original file line number Diff line number Diff line change
Expand Up @@ -187,10 +187,8 @@ class _PreJoinPageState extends State<PreJoinPage> {
dynacast: args.dynacast,
defaultAudioPublishOptions: const AudioPublishOptions(
name: 'custom_audio_track_name',
stream: 'custom_sync_stream_id',
),
defaultVideoPublishOptions: VideoPublishOptions(
stream: 'custom_sync_stream_id',
simulcast: args.simulcast,
videoCodec: args.preferredCodec,
backupVideoCodec: BackupVideoCodec(
Expand Down
19 changes: 5 additions & 14 deletions example/lib/pages/room.dart
Original file line number Diff line number Diff line change
Expand Up @@ -169,15 +169,10 @@ class _RoomPageState extends State<RoomPage> {
if (t.isScreenShare) {
screenTracks.add(ParticipantTrack(
participant: participant,
videoTrack: t.track,
isScreenShare: true,
type: ParticipantTrackType.kScreenShare,
));
} else {
userMediaTracks.add(ParticipantTrack(
participant: participant,
videoTrack: t.track,
isScreenShare: false,
));
userMediaTracks.add(ParticipantTrack(participant: participant));
}
}
}
Expand Down Expand Up @@ -224,8 +219,7 @@ class _RoomPageState extends State<RoomPage> {
}
screenTracks.add(ParticipantTrack(
participant: widget.room.localParticipant!,
videoTrack: t.track,
isScreenShare: true,
type: ParticipantTrackType.kScreenShare,
));
} else {
if (lkPlatformIs(PlatformType.iOS)) {
Expand All @@ -236,11 +230,8 @@ class _RoomPageState extends State<RoomPage> {
}
}

userMediaTracks.add(ParticipantTrack(
participant: widget.room.localParticipant!,
videoTrack: t.track,
isScreenShare: false,
));
userMediaTracks.add(
ParticipantTrack(participant: widget.room.localParticipant!));
}
}
}
Expand Down
28 changes: 14 additions & 14 deletions example/lib/theme.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,36 +33,36 @@ class LiveKitTheme {
elevatedButtonTheme: ElevatedButtonThemeData(
style: ButtonStyle(
textStyle:
MaterialStateProperty.all<TextStyle>(GoogleFonts.montserrat(
WidgetStateProperty.all<TextStyle>(GoogleFonts.montserrat(
fontSize: 15,
)),
padding: MaterialStateProperty.all<EdgeInsets>(
padding: WidgetStateProperty.all<EdgeInsets>(
const EdgeInsets.symmetric(vertical: 20, horizontal: 25)),
shape: MaterialStateProperty.all<OutlinedBorder>(
shape: WidgetStateProperty.all<OutlinedBorder>(
RoundedRectangleBorder(borderRadius: BorderRadius.circular(8))),
foregroundColor: MaterialStateProperty.all<Color>(Colors.white),
// backgroundColor: MaterialStateProperty.all<Color>(accentColor),
backgroundColor: MaterialStateProperty.resolveWith((states) {
if (states.contains(MaterialState.disabled)) {
foregroundColor: WidgetStateProperty.all<Color>(Colors.white),
// backgroundColor: WidgetStateProperty.all<Color>(accentColor),
backgroundColor: WidgetStateProperty.resolveWith((states) {
if (states.contains(WidgetState.disabled)) {
return accentColor.withOpacity(0.5);
}
return accentColor;
}),
),
),
checkboxTheme: CheckboxThemeData(
checkColor: MaterialStateProperty.all(Colors.white),
fillColor: MaterialStateProperty.all(accentColor),
checkColor: WidgetStateProperty.all(Colors.white),
fillColor: WidgetStateProperty.all(accentColor),
),
switchTheme: SwitchThemeData(
trackColor: MaterialStateProperty.resolveWith((states) {
if (states.contains(MaterialState.selected)) {
trackColor: WidgetStateProperty.resolveWith((states) {
if (states.contains(WidgetState.selected)) {
return accentColor;
}
return accentColor.withOpacity(0.3);
}),
thumbColor: MaterialStateProperty.resolveWith((states) {
if (states.contains(MaterialState.selected)) {
thumbColor: WidgetStateProperty.resolveWith((states) {
if (states.contains(WidgetState.selected)) {
return Colors.white;
}
return Colors.white.withOpacity(0.3);
Expand Down Expand Up @@ -94,7 +94,7 @@ class LiveKitTheme {
),
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.white,
background: bgColor,
surface: bgColor,
),
);
}
68 changes: 35 additions & 33 deletions example/lib/widgets/participant.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,20 @@ abstract class ParticipantWidget extends StatefulWidget {
if (participantTrack.participant is LocalParticipant) {
return LocalParticipantWidget(
participantTrack.participant as LocalParticipant,
participantTrack.videoTrack,
participantTrack.isScreenShare,
participantTrack.type,
showStatsLayer);
} else if (participantTrack.participant is RemoteParticipant) {
return RemoteParticipantWidget(
participantTrack.participant as RemoteParticipant,
participantTrack.videoTrack,
participantTrack.isScreenShare,
participantTrack.type,
showStatsLayer);
}
throw UnimplementedError('Unknown participant type');
}

// Must be implemented by child class
abstract final Participant participant;
abstract final VideoTrack? videoTrack;
abstract final bool isScreenShare;
abstract final ParticipantTrackType type;
abstract final bool showStatsLayer;
final VideoQuality quality;

Expand All @@ -45,16 +42,13 @@ class LocalParticipantWidget extends ParticipantWidget {
@override
final LocalParticipant participant;
@override
final VideoTrack? videoTrack;
@override
final bool isScreenShare;
final ParticipantTrackType type;
@override
final bool showStatsLayer;

const LocalParticipantWidget(
this.participant,
this.videoTrack,
this.isScreenShare,
this.type,
this.showStatsLayer, {
super.key,
});
Expand All @@ -67,16 +61,13 @@ class RemoteParticipantWidget extends ParticipantWidget {
@override
final RemoteParticipant participant;
@override
final VideoTrack? videoTrack;
@override
final bool isScreenShare;
final ParticipantTrackType type;
@override
final bool showStatsLayer;

const RemoteParticipantWidget(
this.participant,
this.videoTrack,
this.isScreenShare,
this.type,
this.showStatsLayer, {
super.key,
});
Expand All @@ -87,11 +78,12 @@ class RemoteParticipantWidget extends ParticipantWidget {

abstract class _ParticipantWidgetState<T extends ParticipantWidget>
extends State<T> {
//
bool _visible = true;
VideoTrack? get activeVideoTrack;
AudioTrack? get activeAudioTrack;
TrackPublication? get videoPublication;
TrackPublication? get firstAudioPublication;
TrackPublication? get audioPublication;
bool get isScreenShare => widget.type == ParticipantTrackType.kScreenShare;

@override
void initState() {
Expand Down Expand Up @@ -124,7 +116,7 @@ abstract class _ParticipantWidgetState<T extends ParticipantWidget>
@override
Widget build(BuildContext ctx) => Container(
foregroundDecoration: BoxDecoration(
border: widget.participant.isSpeaking && !widget.isScreenShare
border: widget.participant.isSpeaking && !isScreenShare
? Border.all(
width: 5,
color: LKColors.lkBlue,
Expand Down Expand Up @@ -160,15 +152,15 @@ abstract class _ParticipantWidgetState<T extends ParticipantWidget>
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisSize: MainAxisSize.min,
children: [
...extraWidgets(widget.isScreenShare),
...extraWidgets(isScreenShare),
ParticipantInfoWidget(
title: widget.participant.name.isNotEmpty
? '${widget.participant.name} (${widget.participant.identity})'
: widget.participant.identity,
audioAvailable: firstAudioPublication?.muted == false &&
firstAudioPublication?.subscribed == true,
audioAvailable: audioPublication?.muted == false &&
audioPublication?.subscribed == true,
connectionQuality: widget.participant.connectionQuality,
isScreenShare: widget.isScreenShare,
isScreenShare: isScreenShare,
enabledE2EE: widget.participant.isEncrypted,
),
],
Expand All @@ -184,31 +176,41 @@ class _LocalParticipantWidgetState
@override
LocalTrackPublication<LocalVideoTrack>? get videoPublication =>
widget.participant.videoTrackPublications
.where((element) => element.sid == widget.videoTrack?.sid)
.where((element) => element.source == widget.type.lkVideoSourceType)
.firstOrNull;

@override
LocalTrackPublication<LocalAudioTrack>? get audioPublication =>
widget.participant.audioTrackPublications
.where((element) => element.source == widget.type.lkAudioSourceType)
.firstOrNull;

@override
LocalTrackPublication<LocalAudioTrack>? get firstAudioPublication =>
widget.participant.audioTrackPublications.firstOrNull;
VideoTrack? get activeVideoTrack => videoPublication?.track;

@override
VideoTrack? get activeVideoTrack => widget.videoTrack;
AudioTrack? get activeAudioTrack => audioPublication?.track;
}

class _RemoteParticipantWidgetState
extends _ParticipantWidgetState<RemoteParticipantWidget> {
@override
RemoteTrackPublication<RemoteVideoTrack>? get videoPublication =>
widget.participant.videoTrackPublications
.where((element) => element.sid == widget.videoTrack?.sid)
.where((element) => element.source == widget.type.lkVideoSourceType)
.firstOrNull;

@override
RemoteTrackPublication<RemoteAudioTrack>? get audioPublication =>
widget.participant.audioTrackPublications
.where((element) => element.source == widget.type.lkAudioSourceType)
.firstOrNull;

@override
RemoteTrackPublication<RemoteAudioTrack>? get firstAudioPublication =>
widget.participant.audioTrackPublications.firstOrNull;
VideoTrack? get activeVideoTrack => videoPublication?.track;

@override
VideoTrack? get activeVideoTrack => widget.videoTrack;
AudioTrack? get activeAudioTrack => audioPublication?.track;

@override
List<Widget> extraWidgets(bool isScreenShare) => [
Expand All @@ -217,9 +219,9 @@ class _RemoteParticipantWidgetState
mainAxisAlignment: MainAxisAlignment.end,
children: [
// Menu for RemoteTrackPublication<RemoteAudioTrack>
if (firstAudioPublication != null && !isScreenShare)
if (audioPublication != null)
RemoteTrackPublicationMenuWidget(
pub: firstAudioPublication!,
pub: audioPublication!,
icon: Icons.volume_up,
),
// Menu for RemoteTrackPublication<RemoteVideoTrack>
Expand Down
25 changes: 19 additions & 6 deletions example/lib/widgets/participant_info.dart
Original file line number Diff line number Diff line change
@@ -1,18 +1,31 @@
import 'package:flutter/material.dart';
import 'package:livekit_client/livekit_client.dart';

enum ParticipantTrackType {
kUserMedia,
kScreenShare,
}

extension ParticipantTrackTypeExt on ParticipantTrackType {
TrackSource get lkVideoSourceType => {
ParticipantTrackType.kUserMedia: TrackSource.camera,
ParticipantTrackType.kScreenShare: TrackSource.screenShareVideo,
}[this]!;

TrackSource get lkAudioSourceType => {
ParticipantTrackType.kUserMedia: TrackSource.microphone,
ParticipantTrackType.kScreenShare: TrackSource.screenShareAudio,
}[this]!;
}

class ParticipantTrack {
ParticipantTrack(
{required this.participant,
required this.videoTrack,
required this.isScreenShare});
VideoTrack? videoTrack;
{required this.participant, this.type = ParticipantTrackType.kUserMedia});
Participant participant;
final bool isScreenShare;
final ParticipantTrackType type;
}

class ParticipantInfoWidget extends StatelessWidget {
//
final String? title;
final bool audioAvailable;
final ConnectionQuality connectionQuality;
Expand Down
8 changes: 4 additions & 4 deletions lib/src/participant/local.dart
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ class LocalParticipant extends Participant<LocalTrackPublication> {
final trackInfo = await room.engine.addTrack(
cid: track.getCid(),
name: publishOptions.name ?? AudioPublishOptions.defaultMicrophoneName,
stream: publishOptions.stream,
stream: buildStreamId(publishOptions, track.source),
kind: track.kind.toPBType(),
source: track.source.toPBType(),
dtx: publishOptions.dtx,
Expand Down Expand Up @@ -235,7 +235,7 @@ class LocalParticipant extends Participant<LocalTrackPublication> {
(track.source == TrackSource.screenShareVideo
? VideoPublishOptions.defaultScreenShareName
: VideoPublishOptions.defaultCameraName),
stream: publishOptions.stream,
stream: buildStreamId(publishOptions, track.source),
kind: track.kind.toPBType(),
source: track.source.toPBType(),
dimensions: dimensions,
Expand Down Expand Up @@ -724,15 +724,15 @@ class LocalParticipant extends Participant<LocalTrackPublication> {
backupCodec,
);

var cid = simulcastTrack.sender!.senderId;
final cid = simulcastTrack.sender!.senderId;

final trackInfo = await room.engine.addTrack(
cid: cid,
name: options.name ??
(track.source == TrackSource.screenShareVideo
? VideoPublishOptions.defaultScreenShareName
: VideoPublishOptions.defaultCameraName),
stream: options.stream,
stream: buildStreamId(options, track.source),
kind: track.kind.toPBType(),
source: track.source.toPBType(),
dimensions: dimensions,
Expand Down
18 changes: 18 additions & 0 deletions lib/src/utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -635,3 +635,21 @@ List<String> unpackStreamId(String packed) {
}
return [packed, ''];
}

String? buildStreamId(PublishOptions options, TrackSource source) {
if (options.stream == null) {
return null;
}
var streamId = options.stream!;
switch (source) {
case TrackSource.unknown:
break;
case TrackSource.camera:
case TrackSource.microphone:
case TrackSource.screenShareVideo:
streamId += 'screenshare_video';
case TrackSource.screenShareAudio:
streamId += 'screenshare_audio';
}
return streamId;
}

0 comments on commit 1fc66a8

Please sign in to comment.