desktop: Recreate Player for each movie, and don't start with a Player unless a movie has been specified

This commit is contained in:
Nathan Adams 2023-05-21 22:23:43 +02:00
parent df51531de6
commit e97d32dbc7
2 changed files with 103 additions and 70 deletions

View File

@ -6,7 +6,6 @@ use crate::util::{
get_screen_size, parse_url, pick_file, winit_key_to_char, winit_to_ruffle_key_code,
winit_to_ruffle_text_control,
};
use crate::{CALLSTACK, SWF_INFO};
use anyhow::{Context, Error};
use ruffle_core::{PlayerEvent, StageDisplayState};
use ruffle_render::backend::ViewportDimensions;
@ -14,17 +13,15 @@ use ruffle_render_wgpu::backend::WgpuRenderBackend;
use std::rc::Rc;
use std::sync::{Arc, Mutex};
use std::time::Instant;
use url::Url;
use winit::dpi::{LogicalSize, PhysicalPosition, PhysicalSize, Size};
use winit::event::{ElementState, KeyboardInput, ModifiersState, VirtualKeyCode, WindowEvent};
use winit::event_loop::{ControlFlow, EventLoop, EventLoopBuilder, EventLoopProxy};
use winit::event_loop::{ControlFlow, EventLoop, EventLoopBuilder};
use winit::window::{Fullscreen, Icon, Window, WindowBuilder};
pub struct App {
opt: Opt,
window: Rc<Window>,
event_loop: Option<EventLoop<RuffleEvent>>,
event_loop_proxy: EventLoopProxy<RuffleEvent>,
gui: Arc<Mutex<GuiController>>,
player: PlayerController,
min_window_size: LogicalSize<u32>,
@ -65,61 +62,25 @@ impl App {
opt.power.into(),
)?;
let player = PlayerController::new(
&opt,
let mut player = PlayerController::new(
event_loop.create_proxy(),
movie_url.clone(),
window.clone(),
gui.descriptors().clone(),
gui.create_movie_view(),
);
let mut app = Self {
if let Some(movie_url) = movie_url {
player.create(&opt, movie_url, gui.create_movie_view());
}
Ok(Self {
opt,
window,
event_loop_proxy: event_loop.create_proxy(),
event_loop: Some(event_loop),
gui: Arc::new(Mutex::new(gui)),
player,
min_window_size,
max_window_size,
};
if let Some(movie_url) = movie_url {
app.load_swf(movie_url)?;
}
Ok(app)
}
fn load_swf(&mut self, url: Url) -> Result<(), Error> {
let filename = url
.path_segments()
.and_then(|segments| segments.last())
.unwrap_or_else(|| url.as_str());
let title = format!("Ruffle - {filename}");
self.window.set_title(&title);
SWF_INFO.with(|i| *i.borrow_mut() = Some(filename.to_string()));
let event_loop_proxy = self.event_loop_proxy.clone();
let on_metadata = move |swf_header: &ruffle_core::swf::HeaderExt| {
let _ = event_loop_proxy.send_event(RuffleEvent::OnMetadata(swf_header.clone()));
};
let mut parameters: Vec<(String, String)> = url.query_pairs().into_owned().collect();
parameters.extend(self.opt.parameters());
if let Some(mut player) = self.player.get() {
CALLSTACK.with(|callstack| {
*callstack.borrow_mut() = Some(player.callstack());
});
player.fetch_root_movie(url.to_string(), parameters, Box::new(on_metadata));
} else {
unimplemented!("TODO: get_or_create player");
}
Ok(())
})
}
pub fn run(mut self) -> ! {
@ -457,13 +418,21 @@ impl App {
if let Some(path) = pick_file() {
// TODO: Show dialog on error.
let url = parse_url(&path).expect("Couldn't load specified path");
let _ = self.load_swf(url);
self.player.create(
&self.opt,
url,
self.gui.lock().expect("Gui lock").create_movie_view(),
);
self.gui.lock().expect("Gui lock").set_ui_visible(false);
}
}
winit::event::Event::UserEvent(RuffleEvent::OpenURL(url)) => {
let _ = self.load_swf(url);
self.player.create(
&self.opt,
url,
self.gui.lock().expect("Gui lock").create_movie_view(),
);
self.gui.lock().expect("Gui lock").set_ui_visible(false);
}

View File

@ -2,7 +2,7 @@ use crate::cli::Opt;
use crate::custom_event::RuffleEvent;
use crate::executor::GlutinAsyncExecutor;
use crate::gui::MovieView;
use crate::RENDER_INFO;
use crate::{CALLSTACK, RENDER_INFO, SWF_INFO};
use anyhow::anyhow;
use ruffle_core::backend::audio::AudioBackend;
use ruffle_core::{Player, PlayerBuilder};
@ -16,16 +16,16 @@ use url::Url;
use winit::event_loop::EventLoopProxy;
use winit::window::Window;
pub struct PlayerController {
struct ActivePlayer {
player: Arc<Mutex<Player>>,
executor: Arc<Mutex<GlutinAsyncExecutor>>,
}
impl PlayerController {
impl ActivePlayer {
pub fn new(
opt: &Opt,
event_loop: EventLoopProxy<RuffleEvent>,
movie_url: Option<Url>,
movie_url: Url,
window: Rc<Window>,
descriptors: Arc<Descriptors>,
movie_view: MovieView,
@ -44,11 +44,9 @@ impl PlayerController {
let (executor, channel) = GlutinAsyncExecutor::new(event_loop.clone());
let navigator = crate::navigator::ExternalNavigatorBackend::new(
opt.base.to_owned().unwrap_or(
movie_url.unwrap_or_else(|| Url::parse("file:///empty").expect("Dummy Url")),
),
opt.base.to_owned().unwrap_or_else(|| movie_url.clone()),
channel,
event_loop,
event_loop.clone(),
opt.proxy.clone(),
opt.upgrade_to_https,
opt.open_url_mode,
@ -70,7 +68,10 @@ impl PlayerController {
.with_storage(
crate::storage::DiskStorageBackend::new().expect("Couldn't create storage backend"),
)
.with_ui(crate::ui::DesktopUiBackend::new(window).expect("Couldn't create ui backend"))
.with_ui(
crate::ui::DesktopUiBackend::new(window.clone())
.expect("Couldn't create ui backend"),
)
.with_autoplay(true)
.with_letterbox(opt.letterbox)
.with_max_execution_duration(Duration::from_secs_f64(opt.max_execution_duration))
@ -82,26 +83,89 @@ impl PlayerController {
.with_spoofed_url(opt.spoof_url.clone().map(|url| url.to_string()))
.with_player_version(opt.player_version)
.with_frame_rate(opt.frame_rate);
let player = builder.build();
Self {
player: builder.build(),
executor,
let name = movie_url
.path_segments()
.and_then(|segments| segments.last())
.unwrap_or_else(|| movie_url.as_str())
.to_string();
window.set_title(&format!("Ruffle - {name}"));
SWF_INFO.with(|i| *i.borrow_mut() = Some(name.clone()));
let on_metadata = move |swf_header: &ruffle_core::swf::HeaderExt| {
let _ = event_loop.send_event(RuffleEvent::OnMetadata(swf_header.clone()));
};
let mut parameters: Vec<(String, String)> = movie_url.query_pairs().into_owned().collect();
parameters.extend(opt.parameters());
{
let mut player_lock = player.lock().expect("Player lock must be available");
CALLSTACK.with(|callstack| {
*callstack.borrow_mut() = Some(player_lock.callstack());
});
player_lock.fetch_root_movie(movie_url.to_string(), parameters, Box::new(on_metadata));
}
Self { player, executor }
}
}
pub struct PlayerController {
player: Option<ActivePlayer>,
event_loop: EventLoopProxy<RuffleEvent>,
window: Rc<Window>,
descriptors: Arc<Descriptors>,
}
impl PlayerController {
pub fn new(
event_loop: EventLoopProxy<RuffleEvent>,
window: Rc<Window>,
descriptors: Arc<Descriptors>,
) -> Self {
Self {
player: None,
event_loop,
window,
descriptors,
}
}
pub fn create(&mut self, opt: &Opt, movie_url: Url, movie_view: MovieView) {
self.player = Some(ActivePlayer::new(
opt,
self.event_loop.clone(),
movie_url,
self.window.clone(),
self.descriptors.clone(),
movie_view,
));
}
pub fn get(&self) -> Option<MutexGuard<Player>> {
match &self.player {
None => None,
// We don't want to return None when the lock fails to grab as that's a fatal error, not a lack of player
Some(
self.player
Some(player) => Some(
player
.player
.try_lock()
.expect("Player lock must be available"),
)
),
}
}
pub fn poll(&self) {
self.executor
if let Some(player) = &self.player {
player
.executor
.lock()
.expect("active executor reference")
.expect("Executor lock must be available")
.poll_all()
}
}
}