Skip to content
Merged
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,6 @@ doc/api/
*.js_
*.js.deps
*.js.map

.DS_Store
.flutter-plugins
59 changes: 34 additions & 25 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import 'package:logging/logging.dart';
import 'package:intl/intl.dart';
import 'package:responsive_builder/responsive_builder.dart';

import 'src/utils.dart';

void main() {
final format = DateFormat('HH:mm:ss');
// configure logs for debugging
Expand Down Expand Up @@ -48,9 +46,6 @@ class MyHomePage extends StatelessWidget {
print('Joining room: name=$name, roomName=$roomName');
}
try {
final details = await fetchConnectionDetails(name, roomName);
await roomCtx.connect(
url: details.serverUrl, token: details.participantToken);
await roomCtx.connect(
url: url,
token: token,
Expand All @@ -65,7 +60,11 @@ class MyHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return LivekitRoom(
roomContext: RoomContext(),
roomContext: RoomContext(
url: url,
token: token,
enableAudioVisulizer: true,
),
builder: (context, roomCtx) {
var deviceScreenType = getDeviceType(MediaQuery.of(context).size);
return Scaffold(
Expand All @@ -85,7 +84,7 @@ class MyHomePage extends StatelessWidget {
? Prejoin(
token: token,
url: url,
//onJoinPressed: _onJoinPressed,
onJoinPressed: _onJoinPressed,
)
:

Expand Down Expand Up @@ -116,8 +115,9 @@ class MyHomePage extends StatelessWidget {
children: <Widget>[
/// show participant loop
ParticipantLoop(
showAudioTracks: false,
showAudioTracks: true,
showVideoTracks: true,
showParticipantPlaceholder: true,

/// layout builder
layoutBuilder:
Expand All @@ -126,28 +126,32 @@ class MyHomePage extends StatelessWidget {
: const GridLayoutBuilder(),

/// participant builder
participantBuilder: (context) {
participantTrackBuilder:
(context, identifier) {
// build participant widget for each Track
return Padding(
padding: const EdgeInsets.all(2.0),
child: Stack(
children: [
/// video track widget in the background

IsSpeakingIndicator(
builder: (context, isSpeaking) {
return isSpeaking != null
? IsSpeakingIndicatorWidget(
isSpeaking:
isSpeaking,
child:
const VideoTrackWidget(),
)
: const VideoTrackWidget();
},
),

/// TODO: Add AudioTrackWidget or AgentVisualizerWidget later
identifier.isAudio &&
roomCtx
.enableAudioVisulizer
? const AudioVisualizerWidget()
: IsSpeakingIndicator(
builder: (context,
isSpeaking) {
return isSpeaking !=
null
? IsSpeakingIndicatorWidget(
isSpeaking:
isSpeaking,
child:
const VideoTrackWidget(),
)
: const VideoTrackWidget();
},
),

/// focus toggle button at the top right
const Positioned(
Expand All @@ -164,7 +168,12 @@ class MyHomePage extends StatelessWidget {
),

/// status bar at the bottom
const ParticipantStatusBar(),
const Positioned(
bottom: 0,
left: 0,
right: 0,
child: ParticipantStatusBar(),
),
],
),
);
Expand Down
37 changes: 0 additions & 37 deletions example/lib/src/utils.dart

This file was deleted.

1 change: 1 addition & 0 deletions lib/livekit_components.dart
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ export 'src/ui/widgets/room/disconnect_button.dart';
export 'src/ui/widgets/room/screenshare_toggle.dart';
export 'src/ui/widgets/room/clear_pin_button.dart';

export 'src/ui/widgets/track/audio_visualizer_widget.dart';
export 'src/ui/widgets/track/focus_toggle.dart';
export 'src/ui/widgets/track/no_track_widget.dart';
export 'src/ui/widgets/track/video_track_widget.dart';
Expand Down
2 changes: 2 additions & 0 deletions lib/src/context/media_device_context.dart
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ class MediaDeviceContext extends ChangeNotifier {
AudioCaptureOptions(
deviceId: selectedAudioInputDeviceId,
),
_roomCtx.enableAudioVisulizer,
);
}
selectedAudioInputDeviceId = device.deviceId;
Expand Down Expand Up @@ -137,6 +138,7 @@ class MediaDeviceContext extends ChangeNotifier {
AudioCaptureOptions(
deviceId: selectedAudioInputDeviceId,
),
_roomCtx.enableAudioVisulizer,
);
}
notifyListeners();
Expand Down
7 changes: 7 additions & 0 deletions lib/src/context/room_context.dart
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class RoomContext extends ChangeNotifier with ChatContextMixin {
bool connect = false,
RoomOptions roomOptions = const RoomOptions(),
ConnectOptions? connectOptions,
this.enableAudioVisulizer = false,
this.onConnected,
this.onDisconnected,
this.onError,
Expand Down Expand Up @@ -198,6 +199,12 @@ class RoomContext extends ChangeNotifier with ChatContextMixin {
/// Get the [Room] instance.
Room get room => _room;

/// enable audio visualizer, default is false
/// if true, the audio visualizer will be enabled in the room.
/// you can use the [AudioVisualizerWidget] widget to show the
/// audio visualizer.
final bool enableAudioVisulizer;
Comment thread
cloudwebrtc marked this conversation as resolved.

String? _roomName;

/// Get the room name.
Expand Down
15 changes: 15 additions & 0 deletions lib/src/context/track_reference_context.dart
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,20 @@ class TrackReferenceContext extends ChangeNotifier {
notifyListeners();
}
})
..on<LocalTrackPublishedEvent>((event) {
if (event.publication.sid == pub?.sid) {
Debug.event(
'TrackContext: LocalTrackPublishedEvent for ${_participant.sid}');
notifyListeners();
}
})
..on<TrackSubscribedEvent>((event) {
if (event.publication.sid == pub?.sid) {
Debug.event(
'TrackContext: TrackSubscribedEvent for ${_participant.sid}');
notifyListeners();
}
})
..on<TrackStreamStateUpdatedEvent>((event) {
if (event.publication.sid == pub?.sid) {
Debug.event(
Expand All @@ -56,6 +70,7 @@ class TrackReferenceContext extends ChangeNotifier {
@override
void dispose() {
super.dispose();
_listener.cancelAll();
_listener.dispose();
if (_statsListener != null) {
_statsListener!.dispose();
Expand Down
10 changes: 10 additions & 0 deletions lib/src/types/track_identifier.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,14 @@ class TrackIdentifier {
final TrackPublication? track;

String? get identifier => track?.sid ?? participant.sid;

TrackSource get source => track?.source ?? TrackSource.unknown;

bool get isAudio =>
source == TrackSource.microphone ||
source == TrackSource.screenShareAudio;
bool get isVideo =>
source == TrackSource.camera || source == TrackSource.camera;

bool get hasTrack => track != null;
}
21 changes: 14 additions & 7 deletions lib/src/ui/builder/participant/participant_loop.dart
Original file line number Diff line number Diff line change
Expand Up @@ -25,22 +25,27 @@ import '../../layout/layouts.dart';
import '../../layout/sorting.dart';
import 'participant_track.dart';

typedef PaticipantTrackBuilder = Widget Function(
BuildContext context, TrackIdentifier identifier);

class ParticipantLoop extends StatelessWidget {
const ParticipantLoop({
super.key,
required this.participantBuilder,
required this.participantTrackBuilder,
this.layoutBuilder = const GridLayoutBuilder(),
this.sorting = defaultSorting,
this.showAudioTracks = false,
this.showVideoTracks = true,
this.showParticipantPlaceholder = true,
});

final WidgetBuilder participantBuilder;
final PaticipantTrackBuilder participantTrackBuilder;
final List<TrackWidget> Function(List<TrackWidget> tracks)? sorting;
final ParticipantLayoutBuilder layoutBuilder;

final bool showAudioTracks;
final bool showVideoTracks;
final bool showParticipantPlaceholder;

List<MapEntry<TrackIdentifier, TrackPublication?>> buildTracksMap(
bool audio, bool video, List<Participant> participants) {
Expand Down Expand Up @@ -93,24 +98,26 @@ class ParticipantLoop extends StatelessWidget {
for (var item in trackMap) {
var identifier = item.key;
var track = item.value;
if (track == null) {
if (track != null) {
trackWidgets.add(
TrackWidget(
identifier,
ParticipantTrack(
participant: identifier.participant,
builder: (context) => participantBuilder(context),
track: track,
builder: (context) =>
participantTrackBuilder(context, identifier),
),
),
);
} else {
} else if (showParticipantPlaceholder) {
trackWidgets.add(
TrackWidget(
identifier,
ParticipantTrack(
participant: identifier.participant,
track: track,
builder: (context) => participantBuilder(context),
builder: (context) =>
participantTrackBuilder(context, identifier),
),
),
);
Expand Down
Loading