Skip to content

Commit

Permalink
feat: audio visualizer. (#6)
Browse files Browse the repository at this point in the history
* release: 1.0.1.

* feat: audio visualizer.

* fix.

* fix.

* cleanup.

* update.

* update.

* cleanup.

* update.

* import sorter.
  • Loading branch information
cloudwebrtc authored Dec 9, 2024
1 parent 254b208 commit 5b970a5
Show file tree
Hide file tree
Showing 12 changed files with 244 additions and 72 deletions.
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;

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

0 comments on commit 5b970a5

Please sign in to comment.