Skip to content

Commit

Permalink
chore: Refactoring control buttons.
Browse files Browse the repository at this point in the history
  • Loading branch information
cloudwebrtc committed Oct 10, 2024
1 parent 2e4804c commit ed7b2c2
Show file tree
Hide file tree
Showing 34 changed files with 633 additions and 715 deletions.
1 change: 1 addition & 0 deletions analysis_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ include: package:flutter_lints/flutter.yaml
analyzer:
errors:
constant_identifier_names: ignore
must_be_immutable: ignore
no_wildcard_variable_uses: ignore
use_super_parameters: ignore

Expand Down
19 changes: 4 additions & 15 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ void main() {
// configure logs for debugging
Logger.root.level = Level.FINE;
Logger.root.onRecord.listen((record) {
//print('${format.format(record.time)}: ${record.message}');
if (kDebugMode) {
print('${format.format(record.time)}: ${record.message}');
}
});

WidgetsFlutterBinding.ensureInitialized();
Expand Down Expand Up @@ -62,23 +64,10 @@ class MyHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return LivekitRoom(
roomContext: RoomContext(
/*url: 'ws://192.168.2.241:7880',
token:
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3Mjc5MjM2MjIsImlzcyI6IkFQSXJramtRYVZRSjVERSIsIm5hbWUiOiJmZiIsIm5iZiI6MTcyNjEyMzYyMiwic3ViIjoiZmYiLCJ2aWRlbyI6eyJyb29tIjoibGl2ZSIsInJvb21Kb2luIjp0cnVlfX0.dFzRZA88EeVIgb99f304NxcjsfL-16W9dbf05V6rOvQ',*/
),
roomContext: RoomContext(),
builder: (context) {
return Consumer<RoomContext>(
builder: (context, roomCtx, child) => Scaffold(
/*appBar: AppBar(
title: Selector<RoomContext, String>(
selector: (context, roomCtx) => roomCtx.roomName ?? '',
builder: (context, roomName, child) => Text(
'Room: $roomName Connected: ${roomCtx.connectState}',
style: Theme.of(context).textTheme.bodyLarge,
),
),
),*/
body: !roomCtx.connected
? Prejoin(
onJoinPressed: (name, roomName) =>
Expand Down
10 changes: 1 addition & 9 deletions example/lib/src/prejoin.dart
Original file line number Diff line number Diff line change
Expand Up @@ -80,16 +80,8 @@ class Prejoin extends StatelessWidget {
height: 64,
child: Container(
padding: const EdgeInsets.all(8.0),
child: TextButton(
child: JoinButton(
onPressed: () => _handleJoinPressed(context),
style: ButtonStyle(
backgroundColor:
WidgetStateProperty.all(LKColors.lkBlue),
),
child: const Text(
'Join Room',
style: TextStyle(color: Colors.white, fontSize: 16),
),
),
),
),
Expand Down
9 changes: 3 additions & 6 deletions lib/livekit_components.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,11 @@ export 'src/context/participant.dart';
export 'src/context/permission.dart';
export 'src/types/theme.dart';
export 'src/types/types.dart';
export 'src/ui/mediadevice/camera_preview.dart';
export 'src/ui/mediadevice/camera_select_button.dart';
export 'src/ui/mediadevice/microphone_select_button.dart';
export 'src/ui/buttons/microphone_toggle.dart';
export 'src/ui/buttons/camera_toggle.dart';
export 'src/ui/room/camera_preview.dart';
export 'src/ui/buttons/camera_select_button.dart';
export 'src/ui/buttons/microphone_select_button.dart';
export 'src/ui/buttons/chat_toggle.dart';
export 'src/ui/buttons/join_button.dart';
export 'src/ui/buttons/disconnect_button.dart';
export 'src/ui/buttons/screenshare_toggle.dart';
export 'src/ui/chat/chat.dart';
export 'src/ui/room/room.dart';
Expand Down
25 changes: 15 additions & 10 deletions lib/src/context/chat.dart
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import 'dart:convert';
import 'dart:typed_data';

import 'package:flutter/material.dart';

import 'package:livekit_client/livekit_client.dart';
import 'package:livekit_components/src/ui/debug/logger.dart';

// topic: lk-chat-topic
class ChatMessage {
Expand Down Expand Up @@ -49,19 +48,25 @@ class ChatMessage {

mixin ChatContextMixin on ChangeNotifier {
final List<ChatMessage> _messages = [];

List<ChatMessage> get messages => _messages;

LocalParticipant? _localParticipant;
EventsListener<RoomEvent>? _listener;

void chatContextSetup(
EventsListener<RoomEvent> listener, LocalParticipant localParticipant) {
listener.on<DataReceivedEvent>((event) {
var str = utf8.decode(Uint8List.fromList(event.data));
Debug.log('DataReceivedEvent $str');
addMessageFromMap(str, event.participant);
});
EventsListener<RoomEvent>? listener, LocalParticipant? localParticipant) {
_listener = listener;
_localParticipant = localParticipant;
if (listener != null) {
_listener!.on<DataReceivedEvent>((event) {
if (event.topic == 'lk-chat-topic') {
addMessageFromMap(
const Utf8Decoder().convert(event.data), event.participant);
}
});
} else {
_listener = null;
_messages.clear();
}
}

void sendMessage(String message) {
Expand Down
221 changes: 187 additions & 34 deletions lib/src/context/media_device.dart
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
import 'dart:async';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

import 'package:flutter_background/flutter_background.dart';
import 'package:flutter_webrtc/flutter_webrtc.dart' as rtc;
import 'package:livekit_client/livekit_client.dart';

import '../ui/debug/logger.dart';

mixin MediaDeviceContextMixin on ChangeNotifier {
Room? _room;

CameraPosition position = CameraPosition.front;

List<MediaDevice>? _audioInputs;
Expand All @@ -31,71 +37,218 @@ mixin MediaDeviceContextMixin on ChangeNotifier {
notifyListeners();
}

void setRoom(Room? room) {
_room = room;
}

LocalVideoTrack? _localVideoTrack;

LocalVideoTrack? get localVideoTrack => _localVideoTrack;

bool get cameraOpened => _localVideoTrack != null;
bool get cameraOpened =>
_room != null ? isCameraEnabled : _localVideoTrack != null;

Future<void> setLocalVideoTrack(bool enabled) async {
if (enabled) {
_localVideoTrack ??= await LocalVideoTrack.createCameraTrack(
CameraCaptureOptions(
cameraPosition: position,
deviceId: selectedVideoInputDeviceId,
Future<void> resetLocalTracks() async {
_localAudioTrack = null;
_localVideoTrack = null;
notifyListeners();
}

LocalAudioTrack? _localAudioTrack;

LocalAudioTrack? get localAudioTrack => _localAudioTrack;

bool get microphoneOpened =>
_room != null ? isMicrophoneEnabled : _localAudioTrack != null;

void selectAudioInput(MediaDevice device) async {
selectedAudioInputDeviceId = device.deviceId;
if (_room != null) {
await _room!.setAudioInputDevice(device);
} else {
await _localAudioTrack?.dispose();
_localAudioTrack = await LocalAudioTrack.create(
AudioCaptureOptions(
deviceId: selectedAudioInputDeviceId,
),
);
}
notifyListeners();
}

Future<void> selectVideoInput(MediaDevice device) async {
selectedVideoInputDeviceId = device.deviceId;
if (_room != null) {
await _room!.setVideoInputDevice(device);
} else {
await _localVideoTrack?.stop();
await _localVideoTrack?.dispose();
_localVideoTrack = null;
_localVideoTrack = await LocalVideoTrack.createCameraTrack(
CameraCaptureOptions(
cameraPosition: position,
deviceId: device.deviceId,
),
);
}
notifyListeners();
}

LocalAudioTrack? _localAudioTrack;
bool get isMicrophoneEnabled =>
_room?.localParticipant?.isMicrophoneEnabled() ?? false;

LocalAudioTrack? get localAudioTrack => _localAudioTrack;

bool get microphoneOpened => _localAudioTrack != null;

Future<void> setLocalAudioTrack(bool enabled) async {
if (enabled) {
void enableMicrophone() async {
if (microphoneOpened) {
return;
}
if (_room?.localParticipant != null) {
await _room?.localParticipant?.setMicrophoneEnabled(true);
} else {
_localAudioTrack ??= await LocalAudioTrack.create(
AudioCaptureOptions(
deviceId: selectedAudioInputDeviceId,
),
);
}
notifyListeners();
}

void disableMicrophone() async {
if (!microphoneOpened) {
return;
}
if (_room != null) {
await _room?.localParticipant?.setMicrophoneEnabled(false);
} else {
await _localAudioTrack?.dispose();
_localAudioTrack = null;
}
notifyListeners();
}

void selectAudioInput(MediaDevice device) async {
selectedAudioInputDeviceId = device.deviceId;
await _localAudioTrack?.dispose();
bool get isCameraEnabled =>
_room?.localParticipant?.isCameraEnabled() ?? false;

void enableCamera() async {
if (cameraOpened) {
return;
}
if (_room != null) {
await _room?.localParticipant?.setCameraEnabled(true,
cameraCaptureOptions: CameraCaptureOptions(
deviceId: selectedVideoInputDeviceId,
));
} else {
_localVideoTrack ??= await LocalVideoTrack.createCameraTrack(
CameraCaptureOptions(
cameraPosition: position,
deviceId: selectedVideoInputDeviceId,
),
);
}

notifyListeners();
_localAudioTrack = await LocalAudioTrack.create(
AudioCaptureOptions(
deviceId: device.deviceId,
),
);
}

void disableCamera() async {
if (!cameraOpened) {
return;
}
if (_room != null) {
await _room?.localParticipant?.setCameraEnabled(false);
} else {
await _localVideoTrack?.dispose();
_localVideoTrack = null;
}
notifyListeners();
}

Future<void> selectVideoInput(MediaDevice device) async {
selectedVideoInputDeviceId = device.deviceId;
await _localVideoTrack?.dispose();
bool get isScreenShareEnabled =>
_room?.localParticipant?.isScreenShareEnabled() ?? false;

Future<void> enableScreenShare(context) async {
if (lkPlatformIsDesktop()) {
try {
final source = await showDialog<rtc.DesktopCapturerSource>(
context: context,
builder: (context) => ScreenSelectDialog(),
);
if (source == null) {
Debug.log('cancelled screenshare');
return;
}
Debug.log('DesktopCapturerSource: ${source.id}');
var track = await LocalVideoTrack.createScreenShareTrack(
ScreenShareCaptureOptions(
sourceId: source.id,
maxFrameRate: 15.0,
),
);
await _room?.localParticipant?.publishVideoTrack(track);
} catch (e) {
Debug.log('could not publish video: $e');
}
return;
}
if (lkPlatformIs(PlatformType.android)) {
// Android specific
bool hasCapturePermission = await rtc.Helper.requestCapturePermission();
if (!hasCapturePermission) {
return;
}

requestBackgroundPermission([bool isRetry = false]) async {
// Required for android screenshare.
try {
bool hasPermissions = await FlutterBackground.hasPermissions;
if (!isRetry) {
const androidConfig = FlutterBackgroundAndroidConfig(
notificationTitle: 'Screen Sharing',
notificationText: 'LiveKit Example is sharing the screen.',
notificationImportance: AndroidNotificationImportance.normal,
notificationIcon: AndroidResource(
name: 'livekit_ic_launcher', defType: 'mipmap'),
);
hasPermissions = await FlutterBackground.initialize(
androidConfig: androidConfig);
}
if (hasPermissions &&
!FlutterBackground.isBackgroundExecutionEnabled) {
await FlutterBackground.enableBackgroundExecution();
}
} catch (e) {
if (!isRetry) {
return await Future<void>.delayed(const Duration(seconds: 1),
() => requestBackgroundPermission(true));
}
Debug.log('could not publish video: $e');
}
}

await requestBackgroundPermission();
}
if (lkPlatformIs(PlatformType.iOS)) {
var track = await LocalVideoTrack.createScreenShareTrack(
const ScreenShareCaptureOptions(
useiOSBroadcastExtension: true,
maxFrameRate: 15.0,
),
);
await _room?.localParticipant?.publishVideoTrack(track);
return;
}

if (lkPlatformIsWebMobile()) {
await context
.showErrorDialog('Screen share is not supported on mobile web');
return;
}

await _room?.localParticipant
?.setScreenShareEnabled(true, captureScreenAudio: true);
notifyListeners();
_localVideoTrack = await LocalVideoTrack.createCameraTrack(
CameraCaptureOptions(
cameraPosition: position,
deviceId: device.deviceId,
),
);
}

Future<void> disableScreenShare() async {
await _room?.localParticipant?.setScreenShareEnabled(false);
notifyListeners();
}
}
Loading

0 comments on commit ed7b2c2

Please sign in to comment.