➕ Add flutter webrtc
⬇️ Downgrade analyzer & custom lint for fix flutter new version related bugs
This commit is contained in:
94
lib/pods/call.dart
Normal file
94
lib/pods/call.dart
Normal file
@ -0,0 +1,94 @@
|
||||
import 'package:flutter_webrtc/flutter_webrtc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:island/pods/network.dart';
|
||||
|
||||
part 'call.g.dart';
|
||||
part 'call.freezed.dart';
|
||||
|
||||
@freezed
|
||||
sealed class CallState with _$CallState {
|
||||
const factory CallState({
|
||||
required bool isMuted,
|
||||
required bool isConnected,
|
||||
String? error,
|
||||
}) = _CallState;
|
||||
}
|
||||
|
||||
@riverpod
|
||||
class CallNotifier extends _$CallNotifier {
|
||||
RTCPeerConnection? _peerConnection;
|
||||
MediaStream? _localStream;
|
||||
final _localRenderer = RTCVideoRenderer();
|
||||
|
||||
@override
|
||||
CallState build() {
|
||||
return const CallState(isMuted: false, isConnected: false);
|
||||
}
|
||||
|
||||
Future<void> initialize() async {
|
||||
try {
|
||||
await _localRenderer.initialize();
|
||||
|
||||
// Get user media (audio)
|
||||
_localStream = await navigator.mediaDevices.getUserMedia({
|
||||
'audio': true,
|
||||
'video': false,
|
||||
});
|
||||
|
||||
// Create peer connection
|
||||
_peerConnection = await createPeerConnection({
|
||||
'iceServers': [
|
||||
{'urls': 'stun:stun.l.google.com:19302'},
|
||||
// Add your Cloudflare TURN servers here
|
||||
],
|
||||
});
|
||||
|
||||
// Add local stream to peer connection
|
||||
_localStream!.getTracks().forEach((track) {
|
||||
_peerConnection!.addTrack(track, _localStream!);
|
||||
});
|
||||
|
||||
// Handle incoming tracks
|
||||
_peerConnection!.onTrack = (RTCTrackEvent event) {
|
||||
if (event.track.kind == 'audio') {
|
||||
// Handle remote audio track
|
||||
}
|
||||
};
|
||||
|
||||
state = state.copyWith(isConnected: true);
|
||||
} catch (e) {
|
||||
state = state.copyWith(error: e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> createSession() async {
|
||||
try {
|
||||
final apiClient = ref.read(apiClientProvider);
|
||||
final response = await apiClient.post(
|
||||
'YOUR_CLOUDFLARE_CALLS_ENDPOINT/sessions',
|
||||
options: Options(headers: {'Content-Type': 'application/json'}),
|
||||
);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
// Handle session creation
|
||||
}
|
||||
} catch (e) {
|
||||
state = state.copyWith(error: e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
void toggleMute() {
|
||||
state = state.copyWith(isMuted: !state.isMuted);
|
||||
_localStream?.getAudioTracks().forEach((track) {
|
||||
track.enabled = !state.isMuted;
|
||||
});
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
_localStream?.dispose();
|
||||
_peerConnection?.dispose();
|
||||
_localRenderer.dispose();
|
||||
}
|
||||
}
|
148
lib/pods/call.freezed.dart
Normal file
148
lib/pods/call.freezed.dart
Normal file
@ -0,0 +1,148 @@
|
||||
// dart format width=80
|
||||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||
|
||||
part of 'call.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// dart format off
|
||||
T _$identity<T>(T value) => value;
|
||||
/// @nodoc
|
||||
mixin _$CallState {
|
||||
|
||||
bool get isMuted; bool get isConnected; String? get error;
|
||||
/// Create a copy of CallState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
$CallStateCopyWith<CallState> get copyWith => _$CallStateCopyWithImpl<CallState>(this as CallState, _$identity);
|
||||
|
||||
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is CallState&&(identical(other.isMuted, isMuted) || other.isMuted == isMuted)&&(identical(other.isConnected, isConnected) || other.isConnected == isConnected)&&(identical(other.error, error) || other.error == error));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,isMuted,isConnected,error);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'CallState(isMuted: $isMuted, isConnected: $isConnected, error: $error)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class $CallStateCopyWith<$Res> {
|
||||
factory $CallStateCopyWith(CallState value, $Res Function(CallState) _then) = _$CallStateCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
bool isMuted, bool isConnected, String? error
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class _$CallStateCopyWithImpl<$Res>
|
||||
implements $CallStateCopyWith<$Res> {
|
||||
_$CallStateCopyWithImpl(this._self, this._then);
|
||||
|
||||
final CallState _self;
|
||||
final $Res Function(CallState) _then;
|
||||
|
||||
/// Create a copy of CallState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? isMuted = null,Object? isConnected = null,Object? error = freezed,}) {
|
||||
return _then(_self.copyWith(
|
||||
isMuted: null == isMuted ? _self.isMuted : isMuted // ignore: cast_nullable_to_non_nullable
|
||||
as bool,isConnected: null == isConnected ? _self.isConnected : isConnected // ignore: cast_nullable_to_non_nullable
|
||||
as bool,error: freezed == error ? _self.error : error // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// @nodoc
|
||||
|
||||
|
||||
class _CallState implements CallState {
|
||||
const _CallState({required this.isMuted, required this.isConnected, this.error});
|
||||
|
||||
|
||||
@override final bool isMuted;
|
||||
@override final bool isConnected;
|
||||
@override final String? error;
|
||||
|
||||
/// Create a copy of CallState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
_$CallStateCopyWith<_CallState> get copyWith => __$CallStateCopyWithImpl<_CallState>(this, _$identity);
|
||||
|
||||
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _CallState&&(identical(other.isMuted, isMuted) || other.isMuted == isMuted)&&(identical(other.isConnected, isConnected) || other.isConnected == isConnected)&&(identical(other.error, error) || other.error == error));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,isMuted,isConnected,error);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'CallState(isMuted: $isMuted, isConnected: $isConnected, error: $error)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class _$CallStateCopyWith<$Res> implements $CallStateCopyWith<$Res> {
|
||||
factory _$CallStateCopyWith(_CallState value, $Res Function(_CallState) _then) = __$CallStateCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
bool isMuted, bool isConnected, String? error
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class __$CallStateCopyWithImpl<$Res>
|
||||
implements _$CallStateCopyWith<$Res> {
|
||||
__$CallStateCopyWithImpl(this._self, this._then);
|
||||
|
||||
final _CallState _self;
|
||||
final $Res Function(_CallState) _then;
|
||||
|
||||
/// Create a copy of CallState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? isMuted = null,Object? isConnected = null,Object? error = freezed,}) {
|
||||
return _then(_CallState(
|
||||
isMuted: null == isMuted ? _self.isMuted : isMuted // ignore: cast_nullable_to_non_nullable
|
||||
as bool,isConnected: null == isConnected ? _self.isConnected : isConnected // ignore: cast_nullable_to_non_nullable
|
||||
as bool,error: freezed == error ? _self.error : error // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// dart format on
|
27
lib/pods/call.g.dart
Normal file
27
lib/pods/call.g.dart
Normal file
@ -0,0 +1,27 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'call.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$callNotifierHash() => r'a910dfa778c42888f8b8e5ab199b25ce8a74392b';
|
||||
|
||||
/// See also [CallNotifier].
|
||||
@ProviderFor(CallNotifier)
|
||||
final callNotifierProvider =
|
||||
AutoDisposeNotifierProvider<CallNotifier, CallState>.internal(
|
||||
CallNotifier.new,
|
||||
name: r'callNotifierProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$callNotifierHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef _$CallNotifier = AutoDisposeNotifier<CallState>;
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
Reference in New Issue
Block a user