texture paint
Signed-off-by: fufesou <shuanglongchen@yeah.net>
This commit is contained in:
parent
d3455f3ce2
commit
5acedecf0c
@ -126,9 +126,9 @@ class _RemotePageState extends State<RemotePage>
|
|||||||
// Register texture.
|
// Register texture.
|
||||||
_textureId.value = -1;
|
_textureId.value = -1;
|
||||||
textureRenderer.createTexture(_textureKey).then((id) async {
|
textureRenderer.createTexture(_textureKey).then((id) async {
|
||||||
|
debugPrint("id: $id, texture_key: $_textureKey");
|
||||||
if (id != -1) {
|
if (id != -1) {
|
||||||
final ptr = await textureRenderer.getTexturePtr(_textureKey);
|
final ptr = await textureRenderer.getTexturePtr(_textureKey);
|
||||||
debugPrint("id: $id, texture_key: $_textureKey");
|
|
||||||
platformFFI.registerTexture(widget.id, ptr);
|
platformFFI.registerTexture(widget.id, ptr);
|
||||||
_textureId.value = id;
|
_textureId.value = id;
|
||||||
}
|
}
|
||||||
@ -197,6 +197,8 @@ class _RemotePageState extends State<RemotePage>
|
|||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
debugPrint("REMOTE PAGE dispose ${widget.id}");
|
debugPrint("REMOTE PAGE dispose ${widget.id}");
|
||||||
|
platformFFI.registerTexture(widget.id, 0);
|
||||||
|
textureRenderer.closeTexture(_textureKey);
|
||||||
// ensure we leave this session, this is a double check
|
// ensure we leave this session, this is a double check
|
||||||
bind.sessionEnterOrLeave(id: widget.id, enter: false);
|
bind.sessionEnterOrLeave(id: widget.id, enter: false);
|
||||||
DesktopMultiWindow.removeListener(this);
|
DesktopMultiWindow.removeListener(this);
|
||||||
@ -212,7 +214,6 @@ 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);
|
||||||
}
|
}
|
||||||
@ -484,13 +485,12 @@ 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);
|
||||||
print("width: $imageWidth/$imageHeight");
|
|
||||||
// final imageWidget = CustomPaint(
|
// final imageWidget = CustomPaint(
|
||||||
// size: imageSize,
|
// size: imageSize,
|
||||||
// painter: ImagePainter(image: m.image, x: 0, y: 0, scale: s),
|
// painter: ImagePainter(image: m.image, x: 0, y: 0, scale: s),
|
||||||
// );
|
// );
|
||||||
final imageWidget = SizedBox(
|
final imageWidget = SizedBox(
|
||||||
width: imageHeight,
|
width: imageWidth,
|
||||||
height: imageHeight,
|
height: imageHeight,
|
||||||
child: Obx(() => Texture(textureId: widget.textureId.value)),
|
child: Obx(() => Texture(textureId: widget.textureId.value)),
|
||||||
);
|
);
|
||||||
@ -521,13 +521,22 @@ class _ImagePaintState extends State<ImagePaint> {
|
|||||||
// 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(
|
if (c.size.width > 0 && c.size.height > 0) {
|
||||||
child: AspectRatio(
|
final imageWidget = Stack(
|
||||||
aspectRatio: c.size.width / c.size.height,
|
children: [
|
||||||
child: Obx(() => Texture(textureId: widget.textureId.value)),
|
Positioned(
|
||||||
),
|
left: c.x,
|
||||||
|
top: c.y,
|
||||||
|
width: c.getDisplayWidth() * s,
|
||||||
|
height: c.getDisplayHeight() * s,
|
||||||
|
child: Texture(textureId: widget.textureId.value),
|
||||||
|
)
|
||||||
|
],
|
||||||
);
|
);
|
||||||
return mouseRegion(child: _buildListener(imageWidget));
|
return mouseRegion(child: _buildListener(imageWidget));
|
||||||
|
} else {
|
||||||
|
return Container();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -252,6 +252,8 @@ class FfiModel with ChangeNotifier {
|
|||||||
parent.target?.cursorModel.updateDisplayOrigin(_display.x, _display.y);
|
parent.target?.cursorModel.updateDisplayOrigin(_display.x, _display.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_updateSessionWidthHeight(peerId, display.width, display.height);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
CurrentDisplayState.find(peerId).value = _pi.currentDisplay;
|
CurrentDisplayState.find(peerId).value = _pi.currentDisplay;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -367,6 +369,10 @@ class FfiModel with ChangeNotifier {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_updateSessionWidthHeight(String id, int width, int height) {
|
||||||
|
bind.sessionSetSize(id: id, width: display.width, height: display.height);
|
||||||
|
}
|
||||||
|
|
||||||
/// Handle the peer info event based on [evt].
|
/// Handle the peer info event based on [evt].
|
||||||
handlePeerInfo(Map<String, dynamic> evt, String peerId) async {
|
handlePeerInfo(Map<String, dynamic> evt, String peerId) async {
|
||||||
// recent peer updated by handle_peer_info(ui_session_interface.rs) --> handle_peer_info(client.rs) --> save_config(client.rs)
|
// recent peer updated by handle_peer_info(ui_session_interface.rs) --> handle_peer_info(client.rs) --> save_config(client.rs)
|
||||||
@ -420,6 +426,7 @@ class FfiModel with ChangeNotifier {
|
|||||||
stateGlobal.displaysCount.value = _pi.displays.length;
|
stateGlobal.displaysCount.value = _pi.displays.length;
|
||||||
if (_pi.currentDisplay < _pi.displays.length) {
|
if (_pi.currentDisplay < _pi.displays.length) {
|
||||||
_display = _pi.displays[_pi.currentDisplay];
|
_display = _pi.displays[_pi.currentDisplay];
|
||||||
|
_updateSessionWidthHeight(peerId, display.width, display.height);
|
||||||
}
|
}
|
||||||
if (displays.isNotEmpty) {
|
if (displays.isNotEmpty) {
|
||||||
parent.target?.dialogManager.showLoading(
|
parent.target?.dialogManager.showLoading(
|
||||||
@ -485,19 +492,18 @@ class ImageModel with ChangeNotifier {
|
|||||||
|
|
||||||
WeakReference<FFI> parent;
|
WeakReference<FFI> parent;
|
||||||
|
|
||||||
final List<Function(String)> _callbacksOnFirstImage = [];
|
final List<Function(String)> callbacksOnFirstImage = [];
|
||||||
|
|
||||||
ImageModel(this.parent);
|
ImageModel(this.parent);
|
||||||
|
|
||||||
addCallbackOnFirstImage(Function(String) cb) =>
|
addCallbackOnFirstImage(Function(String) cb) => callbacksOnFirstImage.add(cb);
|
||||||
_callbacksOnFirstImage.add(cb);
|
|
||||||
|
|
||||||
onRgba(Uint8List rgba) {
|
onRgba(Uint8List rgba) {
|
||||||
if (_waitForImage[id]!) {
|
if (_waitForImage[id]!) {
|
||||||
_waitForImage[id] = false;
|
_waitForImage[id] = false;
|
||||||
parent.target?.dialogManager.dismissAll();
|
parent.target?.dialogManager.dismissAll();
|
||||||
if (isDesktop) {
|
if (isDesktop) {
|
||||||
for (final cb in _callbacksOnFirstImage) {
|
for (final cb in callbacksOnFirstImage) {
|
||||||
cb(id);
|
cb(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1445,16 +1451,27 @@ class FFI {
|
|||||||
debugPrint('json.decode fail1(): $e, ${message.field0}');
|
debugPrint('json.decode fail1(): $e, ${message.field0}');
|
||||||
}
|
}
|
||||||
} else if (message is EventToUI_Rgba) {
|
} else if (message is EventToUI_Rgba) {
|
||||||
|
if (Platform.isAndroid || Platform.isIOS) {
|
||||||
// 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);
|
} else {
|
||||||
|
if (_waitForImage[id]!) {
|
||||||
|
_waitForImage[id] = false;
|
||||||
|
dialogManager.dismissAll();
|
||||||
|
for (final cb in imageModel.callbacksOnFirstImage) {
|
||||||
|
cb(id);
|
||||||
|
}
|
||||||
|
await canvasModel.updateViewStyle();
|
||||||
|
await canvasModel.updateScrollStyle();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
debugPrint('Exit session event loop');
|
debugPrint('Exit session event loop');
|
||||||
|
@ -5,12 +5,13 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use flutter_rust_bridge::StreamSink;
|
use flutter_rust_bridge::StreamSink;
|
||||||
use hbb_common::{
|
use hbb_common::{
|
||||||
bail, config::LocalConfig, get_version_number, message_proto::*, rendezvous_proto::ConnType,
|
bail, config::LocalConfig, get_version_number, libc::c_void, message_proto::*,
|
||||||
ResultType,
|
rendezvous_proto::ConnType, ResultType,
|
||||||
};
|
};
|
||||||
use libc::{c_void};
|
|
||||||
use libloading::{Library, Symbol};
|
use libloading::{Library, Symbol};
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
|
|
||||||
|
#[cfg(any(target_os = "android", target_os = "ios"))]
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
@ -30,7 +31,7 @@ lazy_static::lazy_static! {
|
|||||||
pub static ref SESSIONS: RwLock<HashMap<String, Session<FlutterHandler>>> = Default::default();
|
pub static ref SESSIONS: RwLock<HashMap<String, Session<FlutterHandler>>> = Default::default();
|
||||||
pub static ref GLOBAL_EVENT_STREAM: RwLock<HashMap<String, StreamSink<String>>> = Default::default(); // rust to dart event channel
|
pub static ref GLOBAL_EVENT_STREAM: RwLock<HashMap<String, StreamSink<String>>> = Default::default(); // rust to dart event channel
|
||||||
#[cfg(not(any(target_os = "ios", target_os = "android")))]
|
#[cfg(not(any(target_os = "ios", target_os = "android")))]
|
||||||
pub static ref TEXURE_RGBA_RENDERER_PLUGIN: Library = {
|
pub static ref TEXTURE_RGBA_RENDERER_PLUGIN: Library = {
|
||||||
unsafe {
|
unsafe {
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
let lib = Library::new("texture_rgba_renderer_plugin.dll");
|
let lib = Library::new("texture_rgba_renderer_plugin.dll");
|
||||||
@ -127,21 +128,26 @@ pub struct FlutterHandler {
|
|||||||
pub event_stream: Arc<RwLock<Option<StreamSink<EventToUI>>>>,
|
pub event_stream: Arc<RwLock<Option<StreamSink<EventToUI>>>>,
|
||||||
// SAFETY: [rgba] is guarded by [rgba_valid], and it's safe to reach [rgba] with `rgba_valid == true`.
|
// SAFETY: [rgba] is guarded by [rgba_valid], and it's safe to reach [rgba] with `rgba_valid == true`.
|
||||||
// We must check the `rgba_valid` before reading [rgba].
|
// We must check the `rgba_valid` before reading [rgba].
|
||||||
|
#[cfg(any(target_os = "android", target_os = "ios"))]
|
||||||
pub rgba: Arc<RwLock<Vec<u8>>>,
|
pub rgba: Arc<RwLock<Vec<u8>>>,
|
||||||
|
#[cfg(any(target_os = "android", target_os = "ios"))]
|
||||||
pub rgba_valid: Arc<AtomicBool>,
|
pub rgba_valid: Arc<AtomicBool>,
|
||||||
pub renderer: Arc<RwLock<VideoRenderer>>,
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||||
peer_info: Arc<RwLock<PeerInfo>>
|
notify_rendered: Arc<RwLock<bool>>,
|
||||||
|
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);
|
||||||
|
|
||||||
// Video Texture Renderer in Flutter
|
// Video Texture Renderer in Flutter
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct VideoRenderer {
|
struct VideoRenderer {
|
||||||
// TextureRgba pointer in flutter native.
|
// TextureRgba pointer in flutter native.
|
||||||
ptr: usize,
|
ptr: usize,
|
||||||
width: i32,
|
width: i32,
|
||||||
height: i32,
|
height: i32,
|
||||||
|
data_len: usize,
|
||||||
on_rgba_func: Symbol<'static, FlutterRgbaRendererPluginOnRgba>,
|
on_rgba_func: Symbol<'static, FlutterRgbaRendererPluginOnRgba>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,7 +158,8 @@ impl Default for VideoRenderer {
|
|||||||
ptr: 0,
|
ptr: 0,
|
||||||
width: 0,
|
width: 0,
|
||||||
height: 0,
|
height: 0,
|
||||||
on_rgba_func: TEXURE_RGBA_RENDERER_PLUGIN
|
data_len: 0,
|
||||||
|
on_rgba_func: TEXTURE_RGBA_RENDERER_PLUGIN
|
||||||
.get::<FlutterRgbaRendererPluginOnRgba>(b"FlutterRgbaRendererPluginOnRgba")
|
.get::<FlutterRgbaRendererPluginOnRgba>(b"FlutterRgbaRendererPluginOnRgba")
|
||||||
.expect("Symbol FlutterRgbaRendererPluginOnRgba not found."),
|
.expect("Symbol FlutterRgbaRendererPluginOnRgba not found."),
|
||||||
}
|
}
|
||||||
@ -161,24 +168,30 @@ impl Default for VideoRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl VideoRenderer {
|
impl VideoRenderer {
|
||||||
pub fn new(ptr: usize) -> Self {
|
#[inline]
|
||||||
Self {
|
|
||||||
ptr,
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_size(&mut self, width: i32, height: i32) {
|
pub fn set_size(&mut self, width: i32, height: i32) {
|
||||||
self.width = width;
|
self.width = width;
|
||||||
self.height = height;
|
self.height = height;
|
||||||
|
self.data_len = if width > 0 && height > 0 {
|
||||||
|
(width * height * 4) as usize
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_rgba(&self, rgba: *const u8) {
|
pub fn on_rgba(&self, rgba: &Vec<u8>) {
|
||||||
if self.ptr == usize::default() {
|
if self.ptr == usize::default() || rgba.len() != self.data_len {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let func = self.on_rgba_func.clone();
|
let func = self.on_rgba_func.clone();
|
||||||
unsafe {func(self.ptr as _, rgba, self.width as _, self.height as _)};
|
unsafe {
|
||||||
|
func(
|
||||||
|
self.ptr as _,
|
||||||
|
rgba.as_ptr() as _,
|
||||||
|
self.width as _,
|
||||||
|
self.height as _,
|
||||||
|
)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -222,9 +235,16 @@ impl FlutterHandler {
|
|||||||
serde_json::ser::to_string(&msg_vec).unwrap_or("".to_owned())
|
serde_json::ser::to_string(&msg_vec).unwrap_or("".to_owned())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn register_texture(&mut self, ptr: usize) {
|
pub fn register_texture(&mut self, ptr: usize) {
|
||||||
self.renderer.write().unwrap().ptr = ptr;
|
self.renderer.write().unwrap().ptr = ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_size(&mut self, width: i32, height: i32) {
|
||||||
|
*self.notify_rendered.write().unwrap() = false;
|
||||||
|
self.renderer.write().unwrap().set_size(width, height);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InvokeUiSession for FlutterHandler {
|
impl InvokeUiSession for FlutterHandler {
|
||||||
@ -385,6 +405,7 @@ impl InvokeUiSession for FlutterHandler {
|
|||||||
fn adapt_size(&self) {}
|
fn adapt_size(&self) {}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[cfg(any(target_os = "android", target_os = "ios"))]
|
||||||
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.
|
||||||
@ -397,11 +418,18 @@ impl InvokeUiSession for FlutterHandler {
|
|||||||
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);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||||
{
|
fn on_rgba(&self, data: &mut Vec<u8>) {
|
||||||
self.renderer.read().unwrap()
|
self.renderer.read().unwrap().on_rgba(data);
|
||||||
.on_rgba(self.rgba.read().unwrap().as_ptr());
|
if *self.notify_rendered.read().unwrap() {
|
||||||
self.next_rgba();
|
return;
|
||||||
|
}
|
||||||
|
if let Some(stream) = &*self.event_stream.read().unwrap() {
|
||||||
|
stream.add(EventToUI::Rgba);
|
||||||
|
*self.notify_rendered.write().unwrap() = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -417,8 +445,6 @@ impl InvokeUiSession for FlutterHandler {
|
|||||||
}
|
}
|
||||||
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();
|
*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![
|
||||||
@ -467,8 +493,6 @@ 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![
|
||||||
@ -526,6 +550,7 @@ impl InvokeUiSession for FlutterHandler {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn get_rgba(&self) -> *const u8 {
|
fn get_rgba(&self) -> *const u8 {
|
||||||
|
#[cfg(any(target_os = "android", target_os = "ios"))]
|
||||||
if self.rgba_valid.load(Ordering::Relaxed) {
|
if self.rgba_valid.load(Ordering::Relaxed) {
|
||||||
return self.rgba.read().unwrap().as_ptr();
|
return self.rgba.read().unwrap().as_ptr();
|
||||||
}
|
}
|
||||||
@ -534,6 +559,7 @@ impl InvokeUiSession for FlutterHandler {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn next_rgba(&self) {
|
fn next_rgba(&self) {
|
||||||
|
#[cfg(any(target_os = "android", target_os = "ios"))]
|
||||||
self.rgba_valid.store(false, Ordering::Relaxed);
|
self.rgba_valid.store(false, Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -793,8 +819,10 @@ pub fn set_cur_session_id(id: String) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub fn session_get_rgba_size(id: *const char) -> usize {
|
pub fn session_get_rgba_size(_id: *const char) -> usize {
|
||||||
let id = unsafe { std::ffi::CStr::from_ptr(id as _) };
|
#[cfg(any(target_os = "android", target_os = "ios"))]
|
||||||
|
let id = unsafe { std::ffi::CStr::from_ptr(_id as _) };
|
||||||
|
#[cfg(any(target_os = "android", target_os = "ios"))]
|
||||||
if let Ok(id) = id.to_str() {
|
if let Ok(id) = id.to_str() {
|
||||||
if let Some(session) = SESSIONS.write().unwrap().get_mut(id) {
|
if let Some(session) = SESSIONS.write().unwrap().get_mut(id) {
|
||||||
return session.rgba.read().unwrap().len();
|
return session.rgba.read().unwrap().len();
|
||||||
|
@ -529,6 +529,12 @@ pub fn session_switch_sides(id: String) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn session_set_size(id: String, width: i32, height: i32) {
|
||||||
|
if let Some(session) = SESSIONS.write().unwrap().get_mut(&id) {
|
||||||
|
session.set_size(width, height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn main_get_sound_inputs() -> Vec<String> {
|
pub fn main_get_sound_inputs() -> Vec<String> {
|
||||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||||
return get_sound_inputs();
|
return get_sound_inputs();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user