feat: adapt for the latest renderer plugin
This commit is contained in:
parent
ea07b9690e
commit
d3455f3ce2
@ -19,6 +19,7 @@ import 'package:flutter_hbb/utils/multi_window_manager.dart';
|
|||||||
import 'package:flutter_hbb/utils/platform_channel.dart';
|
import 'package:flutter_hbb/utils/platform_channel.dart';
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
import 'package:texture_rgba_renderer/texture_rgba_renderer.dart';
|
||||||
import 'package:uni_links/uni_links.dart';
|
import 'package:uni_links/uni_links.dart';
|
||||||
import 'package:uni_links_desktop/uni_links_desktop.dart';
|
import 'package:uni_links_desktop/uni_links_desktop.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
@ -44,6 +45,10 @@ var isWeb = false;
|
|||||||
var isWebDesktop = false;
|
var isWebDesktop = false;
|
||||||
var version = "";
|
var version = "";
|
||||||
int androidVersion = 0;
|
int androidVersion = 0;
|
||||||
|
/// Incriment count for textureId.
|
||||||
|
int _textureId = 0;
|
||||||
|
int get newTextureId => _textureId ++;
|
||||||
|
final textureRenderer = TextureRgbaRenderer();
|
||||||
|
|
||||||
/// only available for Windows target
|
/// only available for Windows target
|
||||||
int windowsBuildNumber = 0;
|
int windowsBuildNumber = 0;
|
||||||
|
@ -63,6 +63,8 @@ class _RemotePageState extends State<RemotePage>
|
|||||||
late RxBool _zoomCursor;
|
late RxBool _zoomCursor;
|
||||||
late RxBool _remoteCursorMoved;
|
late RxBool _remoteCursorMoved;
|
||||||
late RxBool _keyboardEnabled;
|
late RxBool _keyboardEnabled;
|
||||||
|
late RxInt _textureId;
|
||||||
|
late int _textureKey;
|
||||||
|
|
||||||
final _blockableOverlayState = BlockableOverlayState();
|
final _blockableOverlayState = BlockableOverlayState();
|
||||||
|
|
||||||
@ -85,6 +87,8 @@ class _RemotePageState extends State<RemotePage>
|
|||||||
_showRemoteCursor = ShowRemoteCursorState.find(id);
|
_showRemoteCursor = ShowRemoteCursorState.find(id);
|
||||||
_keyboardEnabled = KeyboardEnabledState.find(id);
|
_keyboardEnabled = KeyboardEnabledState.find(id);
|
||||||
_remoteCursorMoved = RemoteCursorMovedState.find(id);
|
_remoteCursorMoved = RemoteCursorMovedState.find(id);
|
||||||
|
_textureKey = newTextureId;
|
||||||
|
_textureId = RxInt(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _removeStates(String id) {
|
void _removeStates(String id) {
|
||||||
@ -119,6 +123,16 @@ class _RemotePageState extends State<RemotePage>
|
|||||||
if (!Platform.isLinux) {
|
if (!Platform.isLinux) {
|
||||||
Wakelock.enable();
|
Wakelock.enable();
|
||||||
}
|
}
|
||||||
|
// Register texture.
|
||||||
|
_textureId.value = -1;
|
||||||
|
textureRenderer.createTexture(_textureKey).then((id) async {
|
||||||
|
if (id != -1) {
|
||||||
|
final ptr = await textureRenderer.getTexturePtr(_textureKey);
|
||||||
|
debugPrint("id: $id, texture_key: $_textureKey");
|
||||||
|
platformFFI.registerTexture(widget.id, ptr);
|
||||||
|
_textureId.value = id;
|
||||||
|
}
|
||||||
|
});
|
||||||
_ffi.ffiModel.updateEventListener(widget.id);
|
_ffi.ffiModel.updateEventListener(widget.id);
|
||||||
_ffi.qualityMonitorModel.checkShowQualityMonitor(widget.id);
|
_ffi.qualityMonitorModel.checkShowQualityMonitor(widget.id);
|
||||||
// Session option should be set after models.dart/FFI.start
|
// Session option should be set after models.dart/FFI.start
|
||||||
@ -198,6 +212,7 @@ class _RemotePageState extends State<RemotePage>
|
|||||||
Wakelock.disable();
|
Wakelock.disable();
|
||||||
}
|
}
|
||||||
Get.delete<FFI>(tag: widget.id);
|
Get.delete<FFI>(tag: widget.id);
|
||||||
|
textureRenderer.closeTexture(_textureKey);
|
||||||
super.dispose();
|
super.dispose();
|
||||||
_removeStates(widget.id);
|
_removeStates(widget.id);
|
||||||
}
|
}
|
||||||
@ -346,6 +361,7 @@ class _RemotePageState extends State<RemotePage>
|
|||||||
cursorOverImage: _cursorOverImage,
|
cursorOverImage: _cursorOverImage,
|
||||||
keyboardEnabled: _keyboardEnabled,
|
keyboardEnabled: _keyboardEnabled,
|
||||||
remoteCursorMoved: _remoteCursorMoved,
|
remoteCursorMoved: _remoteCursorMoved,
|
||||||
|
textureId: _textureId,
|
||||||
listenerBuilder: (child) =>
|
listenerBuilder: (child) =>
|
||||||
_buildRawPointerMouseRegion(child, enterView, leaveView),
|
_buildRawPointerMouseRegion(child, enterView, leaveView),
|
||||||
);
|
);
|
||||||
@ -383,6 +399,7 @@ class ImagePaint extends StatefulWidget {
|
|||||||
final RxBool cursorOverImage;
|
final RxBool cursorOverImage;
|
||||||
final RxBool keyboardEnabled;
|
final RxBool keyboardEnabled;
|
||||||
final RxBool remoteCursorMoved;
|
final RxBool remoteCursorMoved;
|
||||||
|
final RxInt textureId;
|
||||||
final Widget Function(Widget)? listenerBuilder;
|
final Widget Function(Widget)? listenerBuilder;
|
||||||
|
|
||||||
ImagePaint(
|
ImagePaint(
|
||||||
@ -392,6 +409,7 @@ class ImagePaint extends StatefulWidget {
|
|||||||
required this.cursorOverImage,
|
required this.cursorOverImage,
|
||||||
required this.keyboardEnabled,
|
required this.keyboardEnabled,
|
||||||
required this.remoteCursorMoved,
|
required this.remoteCursorMoved,
|
||||||
|
required this.textureId,
|
||||||
this.listenerBuilder})
|
this.listenerBuilder})
|
||||||
: super(key: key);
|
: super(key: key);
|
||||||
|
|
||||||
@ -466,9 +484,15 @@ class _ImagePaintState extends State<ImagePaint> {
|
|||||||
final imageWidth = c.getDisplayWidth() * s;
|
final imageWidth = c.getDisplayWidth() * s;
|
||||||
final imageHeight = c.getDisplayHeight() * s;
|
final imageHeight = c.getDisplayHeight() * s;
|
||||||
final imageSize = Size(imageWidth, imageHeight);
|
final imageSize = Size(imageWidth, imageHeight);
|
||||||
final imageWidget = CustomPaint(
|
print("width: $imageWidth/$imageHeight");
|
||||||
size: imageSize,
|
// final imageWidget = CustomPaint(
|
||||||
painter: ImagePainter(image: m.image, x: 0, y: 0, scale: s),
|
// size: imageSize,
|
||||||
|
// painter: ImagePainter(image: m.image, x: 0, y: 0, scale: s),
|
||||||
|
// );
|
||||||
|
final imageWidget = SizedBox(
|
||||||
|
width: imageHeight,
|
||||||
|
height: imageHeight,
|
||||||
|
child: Obx(() => Texture(textureId: widget.textureId.value)),
|
||||||
);
|
);
|
||||||
|
|
||||||
return NotificationListener<ScrollNotification>(
|
return NotificationListener<ScrollNotification>(
|
||||||
@ -493,9 +517,15 @@ class _ImagePaintState extends State<ImagePaint> {
|
|||||||
context, _buildListener(imageWidget), c.size, imageSize)),
|
context, _buildListener(imageWidget), c.size, imageSize)),
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
final imageWidget = CustomPaint(
|
// final imageWidget = CustomPaint(
|
||||||
size: Size(c.size.width, c.size.height),
|
// size: Size(c.size.width, c.size.height),
|
||||||
painter: ImagePainter(image: m.image, x: c.x / s, y: c.y / s, scale: s),
|
// painter: ImagePainter(image: m.image, x: c.x / s, y: c.y / s, scale: s),
|
||||||
|
// );
|
||||||
|
final imageWidget = Center(
|
||||||
|
child: AspectRatio(
|
||||||
|
aspectRatio: c.size.width / c.size.height,
|
||||||
|
child: Obx(() => Texture(textureId: widget.textureId.value)),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
return mouseRegion(child: _buildListener(imageWidget));
|
return mouseRegion(child: _buildListener(imageWidget));
|
||||||
}
|
}
|
||||||
|
@ -1446,14 +1446,15 @@ class FFI {
|
|||||||
}
|
}
|
||||||
} else if (message is EventToUI_Rgba) {
|
} else if (message is EventToUI_Rgba) {
|
||||||
// Fetch the image buffer from rust codes.
|
// Fetch the image buffer from rust codes.
|
||||||
final sz = platformFFI.getRgbaSize(id);
|
// final sz = platformFFI.getRgbaSize(id);
|
||||||
if (sz == null || sz == 0) {
|
// if (sz == null || sz == 0) {
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
final rgba = platformFFI.getRgba(id, sz);
|
// final rgba = platformFFI.getRgba(id, sz);
|
||||||
if (rgba != null) {
|
// if (rgba != null) {
|
||||||
imageModel.onRgba(rgba);
|
// imageModel.onRgba(rgba);
|
||||||
}
|
// }
|
||||||
|
// imageModel.onRgba(rgba);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
debugPrint('Exit session event loop');
|
debugPrint('Exit session event loop');
|
||||||
|
@ -30,6 +30,9 @@ typedef F4Dart = int Function(Pointer<Utf8>);
|
|||||||
typedef F5 = Void Function(Pointer<Utf8>);
|
typedef F5 = Void Function(Pointer<Utf8>);
|
||||||
typedef F5Dart = void Function(Pointer<Utf8>);
|
typedef F5Dart = void Function(Pointer<Utf8>);
|
||||||
typedef HandleEvent = Future<void> Function(Map<String, dynamic> evt);
|
typedef HandleEvent = Future<void> Function(Map<String, dynamic> evt);
|
||||||
|
// pub fn session_register_texture(id: *const char, ptr: usize)
|
||||||
|
typedef F6 = Void Function(Pointer<Utf8>, Uint64);
|
||||||
|
typedef F6Dart = void Function(Pointer<Utf8>, int);
|
||||||
|
|
||||||
/// FFI wrapper around the native Rust core.
|
/// FFI wrapper around the native Rust core.
|
||||||
/// Hides the platform differences.
|
/// Hides the platform differences.
|
||||||
@ -52,6 +55,8 @@ class PlatformFFI {
|
|||||||
F3? _session_get_rgba;
|
F3? _session_get_rgba;
|
||||||
F4Dart? _session_get_rgba_size;
|
F4Dart? _session_get_rgba_size;
|
||||||
F5Dart? _session_next_rgba;
|
F5Dart? _session_next_rgba;
|
||||||
|
F6Dart? _session_register_texture;
|
||||||
|
|
||||||
|
|
||||||
static get localeName => Platform.localeName;
|
static get localeName => Platform.localeName;
|
||||||
|
|
||||||
@ -130,6 +135,13 @@ class PlatformFFI {
|
|||||||
malloc.free(a);
|
malloc.free(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void registerTexture(String id, int ptr) {
|
||||||
|
if (_session_register_texture == null) return;
|
||||||
|
final a = id.toNativeUtf8();
|
||||||
|
_session_register_texture!(a, ptr);
|
||||||
|
malloc.free(a);
|
||||||
|
}
|
||||||
|
|
||||||
/// Init the FFI class, loads the native Rust core library.
|
/// Init the FFI class, loads the native Rust core library.
|
||||||
Future<void> init(String appType) async {
|
Future<void> init(String appType) async {
|
||||||
_appType = appType;
|
_appType = appType;
|
||||||
@ -150,6 +162,7 @@ class PlatformFFI {
|
|||||||
dylib.lookupFunction<F4, F4Dart>("session_get_rgba_size");
|
dylib.lookupFunction<F4, F4Dart>("session_get_rgba_size");
|
||||||
_session_next_rgba =
|
_session_next_rgba =
|
||||||
dylib.lookupFunction<F5, F5Dart>("session_next_rgba");
|
dylib.lookupFunction<F5, F5Dart>("session_next_rgba");
|
||||||
|
_session_register_texture = dylib.lookupFunction<F6, F6Dart>("session_register_texture");
|
||||||
try {
|
try {
|
||||||
// SYSTEM user failed
|
// SYSTEM user failed
|
||||||
_dir = (await getApplicationDocumentsDirectory()).path;
|
_dir = (await getApplicationDocumentsDirectory()).path;
|
||||||
|
@ -8,7 +8,7 @@ use hbb_common::{
|
|||||||
bail, config::LocalConfig, get_version_number, message_proto::*, rendezvous_proto::ConnType,
|
bail, config::LocalConfig, get_version_number, message_proto::*, rendezvous_proto::ConnType,
|
||||||
ResultType,
|
ResultType,
|
||||||
};
|
};
|
||||||
use libc::c_void;
|
use libc::{c_void};
|
||||||
use libloading::{Library, Symbol};
|
use libloading::{Library, Symbol};
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
@ -37,7 +37,7 @@ lazy_static::lazy_static! {
|
|||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
let lib = Library::new("texture_rgba_renderer_plugin.dylib");
|
let lib = Library::new("texture_rgba_renderer_plugin.dylib");
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
let lib = Library::new("texture_rgba_renderer_plugin.so");
|
let lib = Library::new("libtexture_rgba_renderer_plugin.so");
|
||||||
lib.expect("`libtexture_rgba_renderer_plugin` not found, please add `texture_rgba_renderer` in your flutter project")
|
lib.expect("`libtexture_rgba_renderer_plugin` not found, please add `texture_rgba_renderer` in your flutter project")
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -129,7 +129,8 @@ pub struct FlutterHandler {
|
|||||||
// We must check the `rgba_valid` before reading [rgba].
|
// We must check the `rgba_valid` before reading [rgba].
|
||||||
pub rgba: Arc<RwLock<Vec<u8>>>,
|
pub rgba: Arc<RwLock<Vec<u8>>>,
|
||||||
pub rgba_valid: Arc<AtomicBool>,
|
pub rgba_valid: Arc<AtomicBool>,
|
||||||
pub renderer: VideoRenderer,
|
pub renderer: Arc<RwLock<VideoRenderer>>,
|
||||||
|
peer_info: Arc<RwLock<PeerInfo>>
|
||||||
}
|
}
|
||||||
pub type FlutterRgbaRendererPluginOnRgba =
|
pub type FlutterRgbaRendererPluginOnRgba =
|
||||||
unsafe extern "C" fn(texture_rgba: *mut c_void, buffer: *const u8, width: c_int, height: c_int);
|
unsafe extern "C" fn(texture_rgba: *mut c_void, buffer: *const u8, width: c_int, height: c_int);
|
||||||
@ -148,10 +149,12 @@ impl Default for VideoRenderer {
|
|||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
unsafe {
|
unsafe {
|
||||||
Self {
|
Self {
|
||||||
|
ptr: 0,
|
||||||
|
width: 0,
|
||||||
|
height: 0,
|
||||||
on_rgba_func: TEXURE_RGBA_RENDERER_PLUGIN
|
on_rgba_func: TEXURE_RGBA_RENDERER_PLUGIN
|
||||||
.get::<FlutterRgbaRendererPluginOnRgba>(b"FlutterRgbaRendererPluginOnRgba")
|
.get::<FlutterRgbaRendererPluginOnRgba>(b"FlutterRgbaRendererPluginOnRgba")
|
||||||
.expect("Symbol FlutterRgbaRendererPluginOnRgba not found."),
|
.expect("Symbol FlutterRgbaRendererPluginOnRgba not found."),
|
||||||
..Default::default()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -220,7 +223,7 @@ impl FlutterHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn register_texture(&mut self, ptr: usize) {
|
pub fn register_texture(&mut self, ptr: usize) {
|
||||||
self.renderer.ptr = ptr;
|
self.renderer.write().unwrap().ptr = ptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -381,6 +384,7 @@ impl InvokeUiSession for FlutterHandler {
|
|||||||
// unused in flutter
|
// unused in flutter
|
||||||
fn adapt_size(&self) {}
|
fn adapt_size(&self) {}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
fn on_rgba(&self, data: &mut Vec<u8>) {
|
fn on_rgba(&self, data: &mut Vec<u8>) {
|
||||||
// If the current rgba is not fetched by flutter, i.e., is valid.
|
// If the current rgba is not fetched by flutter, i.e., is valid.
|
||||||
// We give up sending a new event to flutter.
|
// We give up sending a new event to flutter.
|
||||||
@ -390,13 +394,15 @@ impl InvokeUiSession for FlutterHandler {
|
|||||||
self.rgba_valid.store(true, Ordering::Relaxed);
|
self.rgba_valid.store(true, Ordering::Relaxed);
|
||||||
// Return the rgba buffer to the video handler for reusing allocated rgba buffer.
|
// Return the rgba buffer to the video handler for reusing allocated rgba buffer.
|
||||||
std::mem::swap::<Vec<u8>>(data, &mut *self.rgba.write().unwrap());
|
std::mem::swap::<Vec<u8>>(data, &mut *self.rgba.write().unwrap());
|
||||||
#[cfg(any(target_os = "android", target_os = "ios"))]
|
|
||||||
if let Some(stream) = &*self.event_stream.read().unwrap() {
|
if let Some(stream) = &*self.event_stream.read().unwrap() {
|
||||||
stream.add(EventToUI::Rgba);
|
stream.add(EventToUI::Rgba);
|
||||||
}
|
}
|
||||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||||
self.renderer
|
{
|
||||||
|
self.renderer.read().unwrap()
|
||||||
.on_rgba(self.rgba.read().unwrap().as_ptr());
|
.on_rgba(self.rgba.read().unwrap().as_ptr());
|
||||||
|
self.next_rgba();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_peer_info(&self, pi: &PeerInfo) {
|
fn set_peer_info(&self, pi: &PeerInfo) {
|
||||||
@ -410,6 +416,9 @@ impl InvokeUiSession for FlutterHandler {
|
|||||||
features.insert("privacy_mode", 0);
|
features.insert("privacy_mode", 0);
|
||||||
}
|
}
|
||||||
let features = serde_json::ser::to_string(&features).unwrap_or("".to_owned());
|
let features = serde_json::ser::to_string(&features).unwrap_or("".to_owned());
|
||||||
|
*self.peer_info.write().unwrap() = pi.clone();
|
||||||
|
let curr_display = &pi.displays[pi.current_display as usize];
|
||||||
|
self.renderer.write().unwrap().set_size(curr_display.width, curr_display.height);
|
||||||
self.push_event(
|
self.push_event(
|
||||||
"peer_info",
|
"peer_info",
|
||||||
vec![
|
vec![
|
||||||
@ -426,6 +435,7 @@ impl InvokeUiSession for FlutterHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn set_displays(&self, displays: &Vec<DisplayInfo>) {
|
fn set_displays(&self, displays: &Vec<DisplayInfo>) {
|
||||||
|
self.peer_info.write().unwrap().displays = displays.clone();
|
||||||
self.push_event(
|
self.push_event(
|
||||||
"sync_peer_info",
|
"sync_peer_info",
|
||||||
vec![("displays", &Self::make_displays_msg(displays))],
|
vec![("displays", &Self::make_displays_msg(displays))],
|
||||||
@ -457,6 +467,8 @@ impl InvokeUiSession for FlutterHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn switch_display(&self, display: &SwitchDisplay) {
|
fn switch_display(&self, display: &SwitchDisplay) {
|
||||||
|
let curr_display = &self.peer_info.read().unwrap().displays[display.display as usize];
|
||||||
|
self.renderer.write().unwrap().set_size(curr_display.width, curr_display.height);
|
||||||
self.push_event(
|
self.push_event(
|
||||||
"switch_display",
|
"switch_display",
|
||||||
vec![
|
vec![
|
||||||
@ -521,7 +533,7 @@ impl InvokeUiSession for FlutterHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn next_rgba(&mut self) {
|
fn next_rgba(&self) {
|
||||||
self.rgba_valid.store(false, Ordering::Relaxed);
|
self.rgba_valid.store(false, Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -298,7 +298,7 @@ impl InvokeUiSession for SciterHandler {
|
|||||||
std::ptr::null()
|
std::ptr::null()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next_rgba(&mut self) {}
|
fn next_rgba(&self) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SciterSession(Session<SciterHandler>);
|
pub struct SciterSession(Session<SciterHandler>);
|
||||||
|
@ -798,7 +798,7 @@ pub trait InvokeUiSession: Send + Sync + Clone + 'static + Sized + Default {
|
|||||||
fn on_voice_call_waiting(&self);
|
fn on_voice_call_waiting(&self);
|
||||||
fn on_voice_call_incoming(&self);
|
fn on_voice_call_incoming(&self);
|
||||||
fn get_rgba(&self) -> *const u8;
|
fn get_rgba(&self) -> *const u8;
|
||||||
fn next_rgba(&mut self);
|
fn next_rgba(&self);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: InvokeUiSession> Deref for Session<T> {
|
impl<T: InvokeUiSession> Deref for Session<T> {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user