part of 'room_bloc.dart';
class RoomState extends Equatable {
final String? activeSpeakerId;
final String? state;
final String? roomId;
const RoomState({this.activeSpeakerId, this.state, this.roomId});
static RoomState newActiveSpeaker(
RoomState old, {
String? activeSpeakerId,
}) {
return RoomState(
roomId: old.roomId, state: old.state, activeSpeakerId: activeSpeakerId);
}
@override
List<Object> get props => [activeSpeakerId!, state!, roomId!];
}
part of 'room_bloc.dart';
abstract class RoomEvent extends Equatable {
const RoomEvent();
}
class RoomSetActiveSpeakerId extends RoomEvent {
final String speakerId;
const RoomSetActiveSpeakerId({required this.speakerId});
@override
List<Object> get props => [speakerId];
}
import 'dart:async';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:huddle01_flutter/huddle01_flutter.dart';
part 'producers_event.dart';
part 'producers_state.dart';
class ProducersBloc extends Bloc<ProducersEvent, ProducersState> {
ProducersBloc() : super(ProducersState());
@override
Stream<ProducersState> mapEventToState(
ProducersEvent event,
) async* {
if (event is ProducerAdd) {
yield* _mapProducerAddToState(event);
} else if (event is ProducerRemove) {
yield* _mapProducerRemoveToState(event);
} else if (event is ProducerResumed) {
yield* _mapProducerResumeToState(event);
} else if (event is ProducerPaused) {
yield* _mapProducerPausedToState(event);
}
}
Stream<ProducersState> _mapProducerAddToState(ProducerAdd event) async* {
switch (event.producer.source) {
case 'mic':
{
yield ProducersState.copy(state, mic: event.producer);
break;
}
case 'webcam':
{
yield ProducersState.copy(state, webcam: event.producer);
break;
}
case 'screen':
{
yield ProducersState.copy(state, screen: event.producer);
break;
}
default:
break;
}
}
Stream<ProducersState> _mapProducerRemoveToState(
ProducerRemove event) async* {
switch (event.source) {
case 'mic':
{
state.mic?.close.call();
yield ProducersState.removeMic(state);
break;
}
case 'webcam':
{
state.webcam?.close.call();
yield ProducersState.removeWebcam(state);
break;
}
case 'screen':
{
state.screen?.close.call();
yield ProducersState.removeScreen(state);
break;
}
default:
break;
}
}
Stream<ProducersState> _mapProducerResumeToState(
ProducerResumed event) async* {
switch (event.source) {
case 'mic':
{
state.mic?.resume.call();
yield ProducersState.copy(state);
break;
}
case 'webcam':
{
state.webcam?.resume.call();
yield ProducersState.copy(state);
break;
}
case 'screen':
{
state.screen?.resume.call();
yield ProducersState.copy(state);
break;
}
default:
break;
}
}
Stream<ProducersState> _mapProducerPausedToState(
ProducerPaused event) async* {
switch (event.source) {
case 'mic':
{
state.mic?.pause.call();
yield ProducersState.copy(state);
break;
}
case 'webcam':
{
state.webcam?.pause.call();
yield ProducersState.copy(state);
break;
}
case 'screen':
{
state.screen?.pause.call();
yield ProducersState.copy(state);
break;
}
default:
break;
}
}
}
part of 'producers_bloc.dart';
abstract class ProducersEvent extends Equatable {
const ProducersEvent();
}
class ProducerAdd extends ProducersEvent {
final Producer producer;
const ProducerAdd({required this.producer});
@override
List<Object> get props => throw UnimplementedError();
}
class ProducerRemove extends ProducersEvent {
final String source;
const ProducerRemove({required this.source});
@override
List<Object> get props => [source];
}
class ProducerPaused extends ProducersEvent {
final String source;
const ProducerPaused({required this.source});
@override
List<Object> get props => [source];
}
class ProducerResumed extends ProducersEvent {
final String source;
const ProducerResumed({required this.source});
@override
List<Object> get props => [source];
}
import 'dart:async';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:huddle01_flutter/huddle01_flutter.dart';
import 'package:huddle01_flutter_example/logic/blocs/consumers/consumers_bloc.dart';
part 'peers_event.dart';
part 'peers_state.dart';
class PeersBloc extends Bloc<dynamic, PeersState> {
final ConsumersBloc consumersBloc;
PeersBloc({required this.consumersBloc}) : super(PeersState());
@override
Stream<PeersState> mapEventToState(
dynamic event,
) async* {
if (event is PeerAdd) {
yield* _mapPeerAddToState(event);
} else if (event is PeerRemove) {
yield* _mapPeerRemoveToState(event);
} else if (event is PeerAddConsumer) {
yield* _mapConsumerAddToState(event);
} else if (event is PeerRemoveConsumer) {
yield* _mapConsumerRemoveToState(event);
}
}
Stream<PeersState> _mapPeerAddToState(PeerAdd event) async* {
final Map<String, Peer> newPeers = Map<String, Peer>.of(state.peers);
final Peer newPeer = Peer.fromMap(event.newPeer);
newPeers[newPeer.id!] = newPeer;
yield PeersState(peers: newPeers);
}
Stream<PeersState> _mapPeerRemoveToState(PeerRemove event) async* {
final Map<String, Peer> newPeers = Map<String, Peer>.of(state.peers);
newPeers.remove(event.peerId);
yield PeersState(peers: newPeers);
}
Stream<PeersState> _mapConsumerAddToState(PeerAddConsumer event) async* {
final Map<String, Peer> newPeers = Map<String, Peer>.of(state.peers);
newPeers[event.peerId] = Peer.copy(newPeers[event.peerId]);
newPeers[event.peerId]!.consumers.add(event.consumerId);
yield PeersState(peers: newPeers);
}
Stream<PeersState> _mapConsumerRemoveToState(
PeerRemoveConsumer event) async* {
final Map<String, Peer> newPeers = Map<String, Peer>.of(state.peers);
newPeers[event.peerId]!
.consumers
.removeWhere
.call((c) => c == event.consumerId);
// final Map<String, Peer> newPeers = state.peers.map((key, value) {
// if (value.consumers.contains(event.consumerId)) {
// return MapEntry(key, Peer.copy(
// value,
// consumers: value
// .consumers
// .where((c) => c != event.consumerId)
// .toList(),
// ));
// }
// return MapEntry(key, value);
// });
yield PeersState(peers: newPeers);
}
}
part of 'peers_bloc.dart';
class PeersState extends Equatable {
final Map<String, Peer> peers;
const PeersState({this.peers = const <String, Peer>{}});
@override
List<Object> get props => [peers];
}
part of 'peers_bloc.dart';
abstract class PeersEvent extends Equatable {
const PeersEvent();
}
class PeerAdd extends PeersEvent {
final Map<String, dynamic> newPeer;
const PeerAdd({required this.newPeer});
@override
List<Object> get props => [newPeer];
}
class PeerAddConsumer extends PeersEvent {
final String consumerId;
final String peerId;
const PeerAddConsumer({required this.consumerId, required this.peerId});
@override
List<Object> get props => [consumerId, peerId];
}
class PeerRemoveConsumer extends PeersEvent {
final String consumerId;
final String peerId;
const PeerRemoveConsumer({required this.consumerId, required this.peerId});
@override
List<Object> get props => [consumerId, peerId];
}
class PeerRemove extends PeersEvent {
final String peerId;
const PeerRemove({required this.peerId});
@override
List<Object> get props => [peerId];
}
import 'dart:async';
import 'dart:developer';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:huddle01_flutter/huddle01_flutter.dart';
part 'media_devices_event.dart';
part 'media_devices_state.dart';
class MediaDevicesBloc extends Bloc<MediaDevicesEvent, MediaDevicesState> {
MediaDevicesBloc() : super(MediaDevicesState());
@override
Stream<MediaDevicesState> mapEventToState(
MediaDevicesEvent event,
) async* {
if (event is MediaDeviceLoadDevices) {
yield* _mapLoadDevicesToState(event);
} else if (event is MediaDeviceSelectAudioInput) {
yield* _mapSelectAudioInputToState(event);
} else if (event is MediaDeviceSelectAudioOutput) {
yield* _mapSelectAudioOutputToState(event);
} else if (event is MediaDeviceSelectVideoInput) {
yield* _mapSelectVideoInputToState(event);
}
}
Stream<MediaDevicesState> _mapSelectAudioInputToState(
MediaDeviceSelectAudioInput event) async* {
yield state.copyWith(
selectedAudioInput: event.device,
);
}
Stream<MediaDevicesState> _mapSelectAudioOutputToState(
MediaDeviceSelectAudioOutput event) async* {
yield state.copyWith(
selectedAudioOutput: event.device,
);
}
Stream<MediaDevicesState> _mapSelectVideoInputToState(
MediaDeviceSelectVideoInput event) async* {
yield state.copyWith(
selectedVideoInput: event.device,
);
}
Stream<MediaDevicesState> _mapLoadDevicesToState(
MediaDeviceLoadDevices event) async* {
try {
final List<MediaDeviceInfo> devices =
await navigator.mediaDevices.enumerateDevices();
final List<MediaDeviceInfo> audioInputs = [];
final List<MediaDeviceInfo> audioOutputs = [];
final List<MediaDeviceInfo> videoInputs = [];
devices.forEach((device) {
switch (device.kind) {
case 'audioinput':
audioInputs.add(device);
break;
case 'audiooutput':
audioOutputs.add(device);
break;
case 'videoinput':
videoInputs.add(device);
break;
default:
break;
}
});
MediaDeviceInfo? selectedAudioInput;
MediaDeviceInfo? selectedAudioOutput;
MediaDeviceInfo? selectedVideoInput;
if (audioInputs.isNotEmpty) {
selectedAudioInput = audioInputs.first;
}
if (audioOutputs.isNotEmpty) {
selectedAudioOutput = audioOutputs.first;
}
if (videoInputs.isNotEmpty) {
selectedVideoInput = videoInputs.first;
}
yield MediaDevicesState(
audioInputs: audioInputs,
audioOutputs: audioOutputs,
videoInputs: videoInputs,
selectedAudioInput: selectedAudioInput,
selectedAudioOutput: selectedAudioOutput,
selectedVideoInput: selectedVideoInput,
);
} catch (e) {
log(e.toString());
}
}
}
part of 'me_bloc.dart';
class MeState extends Equatable {
final String displayName;
final String id;
final bool shareInProgress;
final bool webcamInProgress;
const MeState({
required this.displayName,
required this.id,
required this.shareInProgress,
required this.webcamInProgress,
});
static MeState copy(
MeState old, {
String? displayName,
String? id,
bool? shareInProgress,
bool? webcamInProgress,
}) {
return MeState(
displayName: displayName ?? old.displayName,
id: id ?? old.id,
shareInProgress:
shareInProgress != null ? shareInProgress : old.shareInProgress,
webcamInProgress:
webcamInProgress != null ? webcamInProgress : old.webcamInProgress,
);
}
@override
List<Object> get props => [
displayName,
id,
shareInProgress,
webcamInProgress,
];
}
part of 'me_bloc.dart';
abstract class MeEvent extends Equatable {
const MeEvent();
}
class MeSetWebcamInProgress extends MeEvent {
final bool progress;
const MeSetWebcamInProgress({required this.progress});
@override
List<Object> get props => [];
}
import 'dart:async';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:huddle01_flutter/huddle01_flutter.dart';
part 'consumers_event.dart';
part 'consumers_state.dart';
class ConsumersBloc extends Bloc<ConsumersEvent, ConsumersState> {
StreamController<ConsumersEvent>? subs;
ConsumersBloc() : super(ConsumersState()) {
subs = StreamController<ConsumersEvent>();
}
@override
Stream<ConsumersState> mapEventToState(
ConsumersEvent event,
) async* {
if (event is ConsumerAdd) {
yield* _mapConsumersAddToState(event);
subs?.add(event);
} else if (event is ConsumerRemove) {
yield* _mapConsumersRemoveToState(event);
subs?.add(event);
} else if (event is ConsumerResumed) {
yield* _mapConsumerResumedToState(event);
} else if (event is ConsumerPaused) {
yield* _mapConsumerPausedToState(event);
}
}
Stream<ConsumersState> _mapConsumersAddToState(ConsumerAdd event) async* {
final Map<String, Consumer> newConsumers =
Map<String, Consumer>.of(state.consumers);
final Map<String, RTCVideoRenderer> newRenderers =
Map<String, RTCVideoRenderer>.of(state.renderers);
newConsumers[event.consumer.id] = event.consumer;
if (event.consumer.kind == 'video') {
newRenderers[event.consumer.id] = RTCVideoRenderer();
await newRenderers[event.consumer.id]!.initialize();
newRenderers[event.consumer.id]!.srcObject =
newConsumers[event.consumer.id]!.stream;
}
yield ConsumersState(consumers: newConsumers, renderers: newRenderers);
}
Stream<ConsumersState> _mapConsumersRemoveToState(
ConsumerRemove event) async* {
final Map<String, Consumer> newConsumers =
Map<String, Consumer>.of(state.consumers);
final Map<String, RTCVideoRenderer> newRenderers =
Map<String, RTCVideoRenderer>.of(state.renderers);
newConsumers.remove(event.consumerId);
await newRenderers[event.consumerId]?.dispose();
newRenderers.remove(event.consumerId);
yield ConsumersState(consumers: newConsumers, renderers: newRenderers);
}
Stream<ConsumersState> _mapConsumerResumedToState(
ConsumerResumed event) async* {
final Map<String, Consumer> newConsumers =
Map<String, Consumer>.of(state.consumers);
newConsumers[event.consumerId]?.resume();
yield ConsumersState(consumers: newConsumers, renderers: state.renderers);
}
Stream<ConsumersState> _mapConsumerPausedToState(
ConsumerPaused event) async* {
final Map<String, Consumer> newConsumers =
Map<String, Consumer>.of(state.consumers);
newConsumers[event.consumerId]?.pause();
yield ConsumersState(consumers: newConsumers, renderers: state.renderers);
}
@override
Future<void> close() async {
await subs?.close();
for (var r in state.renderers.values) {
await r.dispose();
}
return super.close();
}
}