Refactor the imp/gui bondary to use real traits #18
+9
-9
@@ -6,7 +6,7 @@ use mumble_web2_common::{ClientConfig, ServerStatus};
|
||||
use ordermap::OrderSet;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
use crate::imp;
|
||||
use crate::imp::{Platform, PlatformInterface as _};
|
||||
|
||||
pub type ChannelId = u32;
|
||||
pub type UserId = u32;
|
||||
@@ -690,12 +690,12 @@ pub fn LoginView(config: Resource<ClientConfig>) -> Element {
|
||||
use_resource(move || async move {
|
||||
let client = reqwest::Client::new();
|
||||
loop {
|
||||
*last_status.write_unchecked() = Some(imp::get_status(&client).await);
|
||||
imp::sleep(std::time::Duration::from_secs_f32(1.0)).await;
|
||||
*last_status.write_unchecked() = Some(Platform::get_status(&client).await);
|
||||
Platform::sleep(std::time::Duration::from_secs_f32(1.0)).await;
|
||||
}
|
||||
});
|
||||
|
||||
let mut address_input = use_signal(|| imp::load_server_url());
|
||||
let mut address_input = use_signal(|| Platform::load_server_url());
|
||||
let address = use_memo(move || {
|
||||
if let Some(addr) = address_input() {
|
||||
addr.clone()
|
||||
@@ -706,14 +706,14 @@ pub fn LoginView(config: Resource<ClientConfig>) -> Element {
|
||||
}
|
||||
});
|
||||
|
||||
let previous_username = imp::load_username();
|
||||
let previous_username = Platform::load_username();
|
||||
let mut username = use_signal(|| previous_username.unwrap_or(String::new()));
|
||||
|
||||
let do_connect = move |_| {
|
||||
//let _ = set_default_username(&username.read());
|
||||
let _ = imp::set_default_username(&username.read());
|
||||
let _ = Platform::set_default_username(&username.read());
|
||||
if config.read().as_ref().is_some_and(|cfg| cfg.any_server) {
|
||||
imp::set_default_server(&address.read());
|
||||
Platform::set_default_server(&address.read());
|
||||
}
|
||||
net.send(Connect {
|
||||
address: address.read().clone(),
|
||||
@@ -860,13 +860,13 @@ pub fn app() -> Element {
|
||||
|
||||
use_coroutine(|rx: UnboundedReceiver<Command>| super::network_entrypoint(rx));
|
||||
let config = use_resource(|| async move {
|
||||
match imp::load_config().await {
|
||||
match Platform::load_config().await {
|
||||
Ok(config) => config,
|
||||
Err(_) => ClientConfig::default(),
|
||||
}
|
||||
});
|
||||
|
||||
imp::request_permissions();
|
||||
Platform::request_permissions();
|
||||
|
||||
rsx!(
|
||||
document::Link{ rel: "stylesheet", href: "https://fonts.googleapis.com/css2?family=Nunito:ital,wght@0,200..1000;1,200..1000&display=swap" }
|
||||
|
||||
+8
-9
@@ -7,10 +7,7 @@ use std::cell::RefCell;
|
||||
use std::sync::Arc;
|
||||
use tracing::{error, info};
|
||||
|
||||
use crate::imp::{CurrentPlatform, PlatformRuntime, SpawnHandleTrait};
|
||||
|
||||
/// The spawn handle type for the current platform.
|
||||
type SpawnHandle = <CurrentPlatform as PlatformRuntime>::SpawnHandle;
|
||||
use crate::imp::{SpawnHandle, SpawnHandleInterface as _};
|
||||
|
||||
static DF_MODEL: Asset = asset!("/assets/DeepFilterNet3_ll_onnx.tar.gz");
|
||||
// TODO: make this user configurable.
|
||||
@@ -35,10 +32,7 @@ enum DenoisingModelState {
|
||||
Availible(Box<DfTract>),
|
||||
}
|
||||
|
||||
fn with_denoising_model<O>(
|
||||
spawn: &SpawnHandle,
|
||||
func: impl FnOnce(&mut DfTract) -> O,
|
||||
) -> Option<O> {
|
||||
fn with_denoising_model<O>(spawn: &SpawnHandle, func: impl FnOnce(&mut DfTract) -> O) -> Option<O> {
|
||||
// Using a thread local is super gross, but DfTract is not Send (so it can never leave the current
|
||||
// thread) while AudioProcessing itself might change threads whenever.
|
||||
thread_local! {
|
||||
@@ -126,7 +120,12 @@ impl AudioProcessor {
|
||||
}
|
||||
|
||||
impl AudioProcessor {
|
||||
pub fn process(&mut self, audio: &[f32], channels: usize, output: &mut Vec<f32>) -> TransmitState {
|
||||
pub fn process(
|
||||
&mut self,
|
||||
audio: &[f32],
|
||||
channels: usize,
|
||||
output: &mut Vec<f32>,
|
||||
) -> TransmitState {
|
||||
let mut include_raw = true;
|
||||
if self.denoise {
|
||||
with_denoising_model(&self.spawn, |df| {
|
||||
|
||||
@@ -7,7 +7,10 @@ use std::collections::HashMap;
|
||||
use std::future::Future;
|
||||
use std::time::Duration;
|
||||
|
||||
|
liamwarfield marked this conversation as resolved
Outdated
|
||||
use super::{Platform, PlatformConfig, PlatformInit, PlatformNetwork, PlatformRuntime, SpawnHandleTrait};
|
||||
use super::{
|
||||
PlatformConfig, PlatformInit, PlatformInterface, PlatformNetwork, PlatformRuntime,
|
||||
SpawnHandleTrait,
|
||||
};
|
||||
|
||||
pub use super::connect::*;
|
||||
pub use super::native_audio::*;
|
||||
@@ -107,7 +110,7 @@ impl PlatformInit for DesktopPlatform {
|
||||
}
|
||||
}
|
||||
|
||||
impl Platform for DesktopPlatform {}
|
||||
impl PlatformInterface for DesktopPlatform {}
|
||||
|
||||
fn get_config_path() -> std::path::PathBuf {
|
||||
let strategy = choose_app_strategy(AppStrategyArgs {
|
||||
|
||||
@@ -7,7 +7,7 @@ use mumble_web2_common::{ClientConfig, ServerStatus};
|
||||
use std::future::Future;
|
||||
use std::time::Duration;
|
||||
|
||||
use super::{Platform, PlatformConfig, PlatformInit, PlatformNetwork, PlatformRuntime, SpawnHandleTrait};
|
||||
use super::{PlatformInterface, PlatformConfig, PlatformInit, PlatformNetwork, PlatformRuntime, SpawnHandleTrait};
|
||||
|
||||
pub use super::connect::*;
|
||||
pub use super::native_audio::*;
|
||||
@@ -107,7 +107,7 @@ impl PlatformInit for MobilePlatform {
|
||||
}
|
||||
}
|
||||
|
||||
impl Platform for MobilePlatform {}
|
||||
impl PlatformInterface for MobilePlatform {}
|
||||
|
||||
pub fn set_default_username(_username: &str) -> Option<()> {
|
||||
None
|
||||
|
||||
+45
-96
@@ -15,8 +15,7 @@ use std::time::Duration;
|
||||
// ============================================================================
|
||||
|
||||
/// Trait for spawn handles that can be stored and used to spawn tasks later.
|
||||
#[cfg(feature = "web")]
|
||||
pub trait SpawnHandleTrait: Clone + 'static {
|
||||
pub trait SpawnHandleInterface: Clone + 'static {
|
||||
|
liamwarfield marked this conversation as resolved
Outdated
liamwarfield
commented
We need to add a doc comment for the overall trait here. We need to add a doc comment for the overall trait here.
liamwarfield
commented
Done Done
|
||||
/// Spawn an async task using this handle.
|
||||
fn spawn<F>(&self, future: F)
|
||||
where
|
||||
@@ -26,51 +25,39 @@ pub trait SpawnHandleTrait: Clone + 'static {
|
||||
fn current() -> Self;
|
||||
}
|
||||
|
||||
/// Trait for spawn handles that can be stored and used to spawn tasks later.
|
||||
#[cfg(any(feature = "desktop", feature = "mobile"))]
|
||||
pub trait SpawnHandleTrait: Clone + 'static {
|
||||
/// Spawn an async task using this handle.
|
||||
fn spawn<F>(&self, future: F)
|
||||
where
|
||||
F: Future<Output = ()> + Send + 'static;
|
||||
|
||||
/// Get a spawn handle for the current context.
|
||||
fn current() -> Self;
|
||||
pub trait AudioSystemInterface {
|
||||
type AudioPlayer: AudioPlayerInterface;
|
||||
}
|
||||
|
||||
/// Runtime primitives: task spawning and async sleep.
|
||||
#[cfg(feature = "web")]
|
||||
pub trait PlatformRuntime {
|
||||
/// The spawn handle type for this platform.
|
||||
type SpawnHandle: SpawnHandleTrait;
|
||||
pub trait AudioPlayerInterface {}
|
||||
|
||||
/// Spawn an async task.
|
||||
fn spawn<F>(future: F)
|
||||
where
|
||||
F: Future<Output = ()> + 'static;
|
||||
/// This is the main trait that each platform must implement. It combines all
|
||||
/// platform-specific functionality into a single interface, providing compile-time
|
||||
/// verification that all platforms implement the required functionality.
|
||||
pub trait PlatformInterface {
|
||||
type AudioSystem: AudioSystemInterface;
|
||||
type SpawnHandle: SpawnHandleInterface;
|
||||
|
||||
/// Async sleep for the given duration.
|
||||
fn sleep(duration: Duration) -> impl Future<Output = ()>;
|
||||
}
|
||||
/// Initialize logging for the platform.
|
||||
fn init_logging();
|
||||
|
||||
/// Runtime primitives: task spawning and async sleep.
|
||||
#[cfg(any(feature = "desktop", feature = "mobile"))]
|
||||
pub trait PlatformRuntime {
|
||||
/// The spawn handle type for this platform.
|
||||
type SpawnHandle: SpawnHandleTrait;
|
||||
/// Request runtime permissions (Android audio recording, etc.).
|
||||
fn request_permissions();
|
||||
|
||||
/// Spawn an async task.
|
||||
fn spawn<F>(future: F)
|
||||
where
|
||||
F: Future<Output = ()> + Send + 'static;
|
||||
/// Establish a connection to the Mumble server and run the network loop.
|
||||
fn network_connect(
|
||||
address: String,
|
||||
username: String,
|
||||
event_rx: &mut UnboundedReceiver<Command>,
|
||||
gui_config: &ClientConfig,
|
||||
) -> impl Future<Output = Result<(), Error>>;
|
||||
|
||||
/// Async sleep for the given duration.
|
||||
fn sleep(duration: Duration) -> impl Future<Output = ()>;
|
||||
}
|
||||
/// Get server status (user count, version, etc.).
|
||||
fn get_status(
|
||||
client: &reqwest::Client,
|
||||
) -> impl Future<Output = color_eyre::Result<ServerStatus>>;
|
||||
|
||||
/// Configuration persistence: loading and saving user preferences.
|
||||
pub trait PlatformConfig {
|
||||
/// Load the client configuration (proxy URL, cert hash, etc.).
|
||||
/// Load the proxy overrides (proxy URL, cert hash, etc.).
|
||||
fn load_config() -> impl Future<Output = color_eyre::Result<ClientConfig>>;
|
||||
|
||||
/// Load saved username.
|
||||
@@ -84,39 +71,16 @@ pub trait PlatformConfig {
|
||||
|
||||
/// Save the default server URL.
|
||||
fn set_default_server(server: &str) -> Option<()>;
|
||||
|
||||
/// Spawn an async task.
|
||||
fn spawn<F>(future: F)
|
||||
where
|
||||
F: Future<Output = ()> + 'static;
|
||||
|
||||
/// Async sleep for the given duration.
|
||||
fn sleep(duration: Duration) -> impl Future<Output = ()>;
|
||||
}
|
||||
|
||||
/// Network operations: connecting to servers.
|
||||
pub trait PlatformNetwork {
|
||||
/// Establish a connection to the Mumble server and run the network loop.
|
||||
fn network_connect(
|
||||
address: String,
|
||||
username: String,
|
||||
event_rx: &mut UnboundedReceiver<Command>,
|
||||
gui_config: &ClientConfig,
|
||||
) -> impl Future<Output = Result<(), Error>>;
|
||||
|
||||
/// Get server status (user count, version, etc.).
|
||||
fn get_status(client: &reqwest::Client)
|
||||
-> impl Future<Output = color_eyre::Result<ServerStatus>>;
|
||||
}
|
||||
|
||||
/// Platform initialization.
|
||||
pub trait PlatformInit {
|
||||
/// Initialize logging for the platform.
|
||||
fn init_logging();
|
||||
|
||||
/// Request runtime permissions (Android audio recording, etc.).
|
||||
fn request_permissions();
|
||||
}
|
||||
|
||||
/// Combined platform trait.
|
||||
///
|
||||
/// This is the main trait that each platform must implement. It combines all
|
||||
/// platform-specific functionality into a single interface, providing compile-time
|
||||
/// verification that all platforms implement the required functionality.
|
||||
pub trait Platform: PlatformRuntime + PlatformConfig + PlatformNetwork + PlatformInit {}
|
||||
|
||||
// ============================================================================
|
||||
// Platform Modules
|
||||
// ============================================================================
|
||||
@@ -138,36 +102,21 @@ mod mobile;
|
||||
// Platform Type Alias
|
||||
// ============================================================================
|
||||
|
||||
/// The current platform type, selected at compile time based on features.
|
||||
#[cfg(feature = "web")]
|
||||
pub type CurrentPlatform = web::WebPlatform;
|
||||
pub type Platform = web::WebPlatform;
|
||||
|
||||
#[cfg(feature = "desktop")]
|
||||
pub type CurrentPlatform = desktop::DesktopPlatform;
|
||||
#[cfg(all(feature = "desktop", not(feature = "web")))]
|
||||
pub type Platform = desktop::DesktopPlatform;
|
||||
|
||||
#[cfg(feature = "mobile")]
|
||||
pub type CurrentPlatform = mobile::MobilePlatform;
|
||||
#[cfg(all(feature = "mobile", not(feature = "web"), not(feature = "desktop")))]
|
||||
pub type Platform = mobile::MobilePlatform;
|
||||
|
||||
pub type AudioSystem = <Platform as PlatformInterface>::AudioSystem;
|
||||
pub type AudioPlayer = <AudioSystem as AudioSystemInterface>::AudioPlayer;
|
||||
pub type SpawnHandle = <Platform as PlatformInterface>::SpawnHandle;
|
||||
|
||||
/// Compile-time assertion that CurrentPlatform implements Platform.
|
||||
const _: () = {
|
||||
fn assert_platform<T: Platform>() {}
|
||||
let _ = assert_platform::<CurrentPlatform>;
|
||||
fn assert_platform<T: PlatformInterface>() {}
|
||||
let _ = assert_platform::<Platform>;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// Platform Re-exports
|
||||
// ============================================================================
|
||||
|
||||
#[cfg(feature = "desktop")]
|
||||
pub use desktop::*;
|
||||
#[cfg(feature = "mobile")]
|
||||
pub use mobile::*;
|
||||
|
||||
#[cfg(feature = "mobile")]
|
||||
pub use mobile::request_permissions;
|
||||
|
||||
#[cfg(any(feature = "desktop", feature = "web"))]
|
||||
pub fn request_permissions() {}
|
||||
|
||||
#[cfg(all(feature = "web", not(any(feature = "desktop", feature = "mobile"))))]
|
||||
pub use web::*;
|
||||
|
||||
@@ -124,7 +124,8 @@ impl AudioSystem {
|
||||
if let Some(new_processor) = processors.take() {
|
||||
current_processor = new_processor;
|
||||
}
|
||||
let state = current_processor.process(frame, config.channels as usize, &mut output_buffer);
|
||||
let state =
|
||||
current_processor.process(frame, config.channels as usize, &mut output_buffer);
|
||||
encode_and_send(state, &mut output_buffer, &mut encoder, &mut each);
|
||||
};
|
||||
|
||||
|
||||
+33
-53
@@ -38,8 +38,6 @@ use web_sys::WorkletOptions;
|
||||
use web_sys::{console, window};
|
||||
use web_sys::{AudioContext, AudioDataCopyToOptions};
|
||||
|
||||
use super::{Platform, PlatformConfig, PlatformInit, PlatformNetwork, PlatformRuntime, SpawnHandleTrait};
|
||||
|
||||
pub use wasm_bindgen_futures::spawn_local as spawn;
|
||||
|
||||
pub trait ImpRead: AsyncRead + Unpin + 'static {}
|
||||
@@ -55,15 +53,14 @@ impl<T: AsyncWrite + Unpin + 'static> ImpWrite for T {}
|
||||
/// Web platform implementation using WebTransport and Web Audio API.
|
||||
pub struct WebPlatform;
|
||||
|
||||
pub async fn sleep(d: Duration) {
|
||||
TimeoutFuture::new(d.as_millis() as u32).await
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Trait Implementations
|
||||
// ============================================================================
|
||||
|
||||
impl SpawnHandleTrait for SpawnHandle {
|
||||
#[derive(Clone)]
|
||||
pub struct WebSpawnHandle;
|
||||
|
||||
impl super::SpawnHandleInterface for WebSpawnHandle {
|
||||
fn spawn<F>(&self, future: F)
|
||||
where
|
||||
F: Future<Output = ()> + 'static,
|
||||
@@ -72,26 +69,22 @@ impl SpawnHandleTrait for SpawnHandle {
|
||||
}
|
||||
|
||||
fn current() -> Self {
|
||||
SpawnHandle
|
||||
WebSpawnHandle
|
||||
}
|
||||
}
|
||||
|
||||
impl PlatformRuntime for WebPlatform {
|
||||
type SpawnHandle = SpawnHandle;
|
||||
impl super::PlatformInterface for WebPlatform {
|
||||
type AudioSystem = WebAudioSystem;
|
||||
type SpawnHandle = WebSpawnHandle;
|
||||
|
||||
fn spawn<F>(future: F)
|
||||
where
|
||||
F: Future<Output = ()> + 'static,
|
||||
{
|
||||
wasm_bindgen_futures::spawn_local(future);
|
||||
fn init_logging() {
|
||||
init_logging();
|
||||
}
|
||||
|
||||
async fn sleep(duration: Duration) {
|
||||
TimeoutFuture::new(duration.as_millis() as u32).await;
|
||||
}
|
||||
fn request_permissions() {
|
||||
// No-op on web
|
||||
}
|
||||
|
||||
impl PlatformConfig for WebPlatform {
|
||||
async fn load_config() -> color_eyre::Result<ClientConfig> {
|
||||
load_config().await
|
||||
}
|
||||
@@ -111,9 +104,7 @@ impl PlatformConfig for WebPlatform {
|
||||
fn set_default_server(server: &str) -> Option<()> {
|
||||
set_default_server(server)
|
||||
}
|
||||
}
|
||||
|
||||
impl PlatformNetwork for WebPlatform {
|
||||
async fn network_connect(
|
||||
address: String,
|
||||
username: String,
|
||||
@@ -126,20 +117,19 @@ impl PlatformNetwork for WebPlatform {
|
||||
async fn get_status(client: &reqwest::Client) -> color_eyre::Result<ServerStatus> {
|
||||
get_status(client).await
|
||||
}
|
||||
|
||||
fn spawn<F>(future: F)
|
||||
where
|
||||
F: Future<Output = ()> + 'static,
|
||||
{
|
||||
wasm_bindgen_futures::spawn_local(future);
|
||||
}
|
||||
|
||||
impl PlatformInit for WebPlatform {
|
||||
fn init_logging() {
|
||||
init_logging();
|
||||
}
|
||||
|
||||
fn request_permissions() {
|
||||
// No-op on web
|
||||
async fn sleep(duration: Duration) {
|
||||
TimeoutFuture::new(duration.as_millis() as u32).await;
|
||||
}
|
||||
}
|
||||
|
||||
impl Platform for WebPlatform {}
|
||||
|
||||
trait ResultExt<T> {
|
||||
fn ey(self) -> Result<T, Error>;
|
||||
}
|
||||
@@ -162,7 +152,7 @@ impl<T> ResultExt<T> for Result<T, JsError> {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AudioSystem {
|
||||
pub struct WebAudioSystem {
|
||||
webctx: AudioContext,
|
||||
processors: AudioProcessorSender,
|
||||
}
|
||||
@@ -193,7 +183,11 @@ async fn attach_worklet(audio_context: &AudioContext) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl AudioSystem {
|
||||
impl super::AudioSystemInterface for WebAudioSystem {
|
||||
type AudioPlayer = WebAudioPlayer;
|
||||
}
|
||||
|
||||
impl WebAudioSystem {
|
||||
pub async fn new() -> Result<Self, Error> {
|
||||
// Create MediaStreams to playback decoded audio
|
||||
// The audio context is used to reproduce audio.
|
||||
@@ -202,7 +196,7 @@ impl AudioSystem {
|
||||
|
||||
let processors = AudioProcessorSender::default();
|
||||
|
||||
Ok(AudioSystem { webctx, processors })
|
||||
Ok(WebAudioSystem { webctx, processors })
|
||||
}
|
||||
|
||||
pub fn set_processor(&self, processor: AudioProcessor) {
|
||||
@@ -224,7 +218,7 @@ impl AudioSystem {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn create_player(&mut self) -> Result<AudioPlayer, Error> {
|
||||
pub fn create_player(&mut self) -> Result<WebAudioPlayer, Error> {
|
||||
let sink_node = AudioWorkletNode::new(&self.webctx, "rust_speaker_worklet").ey()?;
|
||||
|
||||
// Connect worklet to destination
|
||||
@@ -277,13 +271,15 @@ impl AudioSystem {
|
||||
decoder_error.forget();
|
||||
output.forget();
|
||||
|
||||
Ok(AudioPlayer(audio_decoder))
|
||||
Ok(WebAudioPlayer(audio_decoder))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AudioPlayer(AudioDecoder);
|
||||
pub struct WebAudioPlayer(AudioDecoder);
|
||||
|
||||
impl AudioPlayer {
|
||||
impl super::AudioPlayerInterface for WebAudioPlayer {}
|
||||
|
||||
impl WebAudioPlayer {
|
||||
pub fn play_opus(&mut self, payload: &[u8]) {
|
||||
let js_audio_payload = Uint8Array::from(payload);
|
||||
let _ = self.0.decode(
|
||||
@@ -583,19 +579,3 @@ pub fn init_logging() {
|
||||
|
||||
info!("logging initiated");
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct SpawnHandle;
|
||||
|
||||
impl SpawnHandle {
|
||||
pub fn current() -> Self {
|
||||
SpawnHandle
|
||||
}
|
||||
|
||||
pub fn spawn<F>(&self, future: F)
|
||||
where
|
||||
F: Future<Output = ()> + 'static,
|
||||
{
|
||||
spawn(future);
|
||||
}
|
||||
}
|
||||
|
||||
+13
-8
@@ -7,11 +7,12 @@ use asynchronous_codec::FramedWrite;
|
||||
use color_eyre::eyre::{bail, Error};
|
||||
use dioxus::prelude::*;
|
||||
use futures::select;
|
||||
use futures::AsyncRead;
|
||||
use futures::AsyncWrite;
|
||||
use futures::FutureExt as _;
|
||||
use futures::SinkExt as _;
|
||||
use futures::StreamExt as _;
|
||||
use futures_channel::mpsc::UnboundedSender;
|
||||
pub use imp::spawn;
|
||||
use msghtml::process_message_html;
|
||||
use mumble_protocol::control::msgs;
|
||||
use mumble_protocol::control::ControlCodec;
|
||||
@@ -27,7 +28,9 @@ use tracing::error;
|
||||
use tracing::info;
|
||||
|
||||
use crate::effects::AudioProcessor;
|
||||
use crate::imp::{AudioSystem, CurrentPlatform, Platform, PlatformNetwork, PlatformRuntime};
|
||||
use crate::imp::{
|
||||
AudioPlayer, AudioSystem, AudioSystemInterface as _, Platform, PlatformInterface as _,
|
||||
};
|
||||
|
||||
pub mod app;
|
||||
mod effects;
|
||||
@@ -47,7 +50,9 @@ pub async fn network_entrypoint(mut event_rx: UnboundedReceiver<Command>) {
|
||||
|
||||
*STATE.server.write() = Default::default();
|
||||
*STATE.status.write() = ConnectionState::Connecting;
|
||||
if let Err(error) = CurrentPlatform::network_connect(address, username, &mut event_rx, &config).await {
|
||||
if let Err(error) =
|
||||
Platform::network_connect(address, username, &mut event_rx, &config).await
|
||||
{
|
||||
error!("could not connect {:?}", error);
|
||||
*STATE.status.write() = ConnectionState::Failed(error.to_string());
|
||||
} else {
|
||||
@@ -56,7 +61,7 @@ pub async fn network_entrypoint(mut event_rx: UnboundedReceiver<Command>) {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn network_loop<R: imp::ImpRead, W: imp::ImpWrite>(
|
||||
pub async fn network_loop<R: AsyncRead + Unpin + 'static, W: AsyncWrite + Unpin + 'static>(
|
||||
username: String,
|
||||
event_rx: &mut UnboundedReceiver<Command>,
|
||||
mut reader: FramedRead<R, ControlCodec<Serverbound, Clientbound>>,
|
||||
@@ -105,12 +110,12 @@ pub async fn network_loop<R: imp::ImpRead, W: imp::ImpWrite>(
|
||||
break;
|
||||
}
|
||||
|
||||
CurrentPlatform::sleep(Duration::from_millis(3000)).await;
|
||||
Platform::sleep(Duration::from_millis(3000)).await;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let mut audio = imp::AudioSystem::new().await?;
|
||||
let mut audio = AudioSystem::new().await?;
|
||||
{
|
||||
let send_chan = send_chan.clone();
|
||||
let mut sequence_num = 0;
|
||||
@@ -296,8 +301,8 @@ fn accept_command(
|
||||
|
||||
fn accept_packet(
|
||||
msg: ControlPacket<mumble_protocol::Clientbound>,
|
||||
audio_context: &mut imp::AudioSystem,
|
||||
player_map: &mut HashMap<u32, imp::AudioPlayer>,
|
||||
audio_context: &mut AudioSystem,
|
||||
player_map: &mut HashMap<u32, AudioPlayer>,
|
||||
) -> Result<(), Error> {
|
||||
match msg {
|
||||
ControlPacket::UDPTunnel(u) => {
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
use mumble_web2_gui::{app, imp};
|
||||
use mumble_web2_gui::{app, imp::Platform, imp::PlatformInterface as _};
|
||||
|
||||
pub fn main() {
|
||||
imp::init_logging();
|
||||
Platform::init_logging();
|
||||
dioxus::launch(app::app);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user
Delete this bar