105 lines
3.1 KiB
Dart
105 lines
3.1 KiB
Dart
import 'dart:io';
|
|
import 'package:flutter/foundation.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
|
|
import 'package:maibu_satabot_v2/core/domain/entities/user_entity.dart';
|
|
import 'package:maibu_satabot_v2/features/devices/domain/entities/device_entity.dart';
|
|
|
|
class MyVideoPlayer extends StatefulWidget {
|
|
final String deviceIp;
|
|
final DeviceEntity device;
|
|
final UserEntity user;
|
|
|
|
const MyVideoPlayer({
|
|
Key? key,
|
|
required this.deviceIp,
|
|
required this.device,
|
|
required this.user,
|
|
}) : super(key: key);
|
|
|
|
@override
|
|
State<MyVideoPlayer> createState() => _MyVideoPlayerState();
|
|
}
|
|
|
|
class _MyVideoPlayerState extends State<MyVideoPlayer> {
|
|
InAppLocalhostServer? _localServer;
|
|
InAppWebViewController? _webViewController;
|
|
bool _isServerRunning = false;
|
|
int? actualPort;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_startServer();
|
|
}
|
|
|
|
Future<void> _startServer() async {
|
|
int availablePort = 0;
|
|
try {
|
|
var socket = await ServerSocket.bind(InternetAddress.loopbackIPv4, 0);
|
|
availablePort = socket.port;
|
|
await socket.close();
|
|
} catch (e) {
|
|
availablePort = 8080;
|
|
}
|
|
|
|
_localServer = InAppLocalhostServer(port: availablePort);
|
|
await _localServer!.start();
|
|
actualPort = availablePort;
|
|
|
|
if (mounted) {
|
|
setState(() {
|
|
_isServerRunning = true;
|
|
});
|
|
}
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_localServer?.close();
|
|
super.dispose();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
// 防止父级因其他状态 setState 导致视频闪烁
|
|
if (!_isServerRunning) {
|
|
return const Center(child: CircularProgressIndicator(color: Colors.white));
|
|
}
|
|
|
|
// [性能关键] RepaintBoundary 必须包裹渲染密集型的 WebView
|
|
return RepaintBoundary(
|
|
child: InAppWebView(
|
|
initialUrlRequest: URLRequest(
|
|
url: WebUri("http://localhost:$actualPort/assets/www/webrtc/playwebrtc.html"),
|
|
),
|
|
initialSettings: InAppWebViewSettings(
|
|
javaScriptEnabled: true,
|
|
mediaPlaybackRequiresUserGesture: false,
|
|
allowsInlineMediaPlayback: true,
|
|
preferredContentMode: UserPreferredContentMode.MOBILE,
|
|
// 优化性能:禁用滚动,开启硬件加速
|
|
supportZoom: false,
|
|
disableHorizontalScroll: true,
|
|
disableVerticalScroll: true,
|
|
hardwareAcceleration: true,
|
|
),
|
|
onWebViewCreated: (controller) => _webViewController = controller,
|
|
onPermissionRequest: (controller, request) async {
|
|
return PermissionResponse(
|
|
resources: request.resources,
|
|
action: PermissionResponseAction.GRANT,
|
|
);
|
|
},
|
|
onLoadStop: (controller, url) {
|
|
_initWebRTC(widget.deviceIp, widget.device.deviceName, widget.user.token);
|
|
},
|
|
),
|
|
);
|
|
}
|
|
|
|
void _initWebRTC(String deviceIp, String deviceId, String token) {
|
|
final streamUrl = "webrtc://$deviceIp/live/livestream/$deviceId?token=$token";
|
|
_webViewController?.evaluateJavascript(source: "setStreamUrl('$streamUrl')");
|
|
}
|
|
} |