Merge pull request #15 from Tahinli/dev

Dev
This commit is contained in:
Ahmet Kaan GÜMÜŞ 2024-03-21 21:02:17 +00:00 committed by GitHub
commit 63100dc2bb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 140 additions and 8 deletions

1
.gitignore vendored
View file

@ -5,6 +5,7 @@ target/
.vscode/ .vscode/
dist/ dist/
certificates/ certificates/
audios/
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html

View file

@ -12,4 +12,6 @@ rand = "0.8.5"
serde = { version = "1.0.197", features = ["derive"] } serde = { version = "1.0.197", features = ["derive"] }
serde_json = "1.0.114" serde_json = "1.0.114"
tokio = { version = "1.36.0", features = ["full"] } tokio = { version = "1.36.0", features = ["full"] }
#tokio-stream = { version = "0.1.15", features = ["full"] }
tokio-util = { version = "0.7.10", features = ["full"] }
tower-http = { version = "0.5.2", features = ["full"] } tower-http = { version = "0.5.2", features = ["full"] }

View file

@ -1,7 +1,6 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
pub mod routing; pub mod routing;
pub mod read;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct AppState{ pub struct AppState{

View file

@ -1,5 +1,7 @@
use crate::{AppState, ServerStatus, CoinStatus}; use crate::{AppState, ServerStatus, CoinStatus};
use axum::{extract::State, http::StatusCode, response::IntoResponse, routing::get, Json, Router}; use axum::{body::Body, extract::State, http::StatusCode, response::IntoResponse, routing::get, Json, Router};
use tokio::fs::File;
use tokio_util::io::ReaderStream;
use tower_http::cors::CorsLayer; use tower_http::cors::CorsLayer;
use rand::prelude::*; use rand::prelude::*;
@ -7,6 +9,7 @@ pub async fn routing(State(state): State<AppState>) -> Router {
Router::new() Router::new()
.route("/", get(alive)) .route("/", get(alive))
.route("/coin", get(flip_coin)) .route("/coin", get(flip_coin))
.route("/stream", get(stream))
.layer(CorsLayer::permissive()) .layer(CorsLayer::permissive())
.with_state(state.clone()) .with_state(state.clone())
} }
@ -32,3 +35,9 @@ async fn flip_coin() -> impl IntoResponse {
println!("{}", coin_json); println!("{}", coin_json);
(StatusCode::OK, Json(coin_json)) (StatusCode::OK, Json(coin_json))
} }
async fn stream() -> impl IntoResponse {
let file = File::open("audios/audio.mp3").await.unwrap();
let stream = ReaderStream::new(file);
Body::from_stream(stream)
}

View file

@ -6,9 +6,11 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
async-std = "1.12.0" anyhow = "1.0.81"
cpal = { version = "0.15.3", features = ["wasm-bindgen"] }
dioxus = { version = "0.5.0-alpha.0", features = ["web"] } dioxus = { version = "0.5.0-alpha.0", features = ["web"] }
log = "0.4.21" log = "0.4.21"
reqwest = { version = "0.11.24", features = ["json"] } reqwest = { version = "0.11.24", features = ["json"] }
serde = { version = "1.0.197", features = ["derive"] } serde = { version = "1.0.197", features = ["derive"] }
tokio_with_wasm = "0.4.3"
wasm-logger = "0.2.0" wasm-logger = "0.2.0"

View file

@ -1,8 +1,11 @@
use std::time::Duration; use std::time::Duration;
use async_std::task; use tokio_with_wasm::tokio;
use dioxus::prelude::*; use dioxus::prelude::*;
use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
use cpal::{FromSample, Sample, SizedSample};
use serde::Deserialize; use serde::Deserialize;
const SERVER_ADDRESS: &str = "https://localhost:2323";
const SERVER_ADDRESS: &str = "https://tahinli.com.tr:2323";
#[derive(Debug, Clone, PartialEq, Deserialize)] #[derive(Debug, Clone, PartialEq, Deserialize)]
enum Server{ enum Server{
@ -75,6 +78,14 @@ async fn coin_status_check() -> Result<CoinStatus, reqwest::Error> {
fn app() -> Element { fn app() -> Element {
rsx! { rsx! {
page_base {} page_base {}
audio_stream_renderer {}
div {
button {
onclick: move |_| record(),
"style":"width: 80px; height: 50px;",
"Sinusoidal"
}
}
coin_status_renderer {} coin_status_renderer {}
server_status_renderer {} server_status_renderer {}
} }
@ -95,6 +106,101 @@ fn page_base() ->Element {
} }
} }
} }
pub async fn run<T>(device: &cpal::Device, config: &cpal::StreamConfig) -> Result<(), anyhow::Error>
where
T: SizedSample + FromSample<f32>,
{
let sample_rate = config.sample_rate.0 as f32;
let channels = config.channels as usize;
// Produce a sinusoid of maximum amplitude.
let mut sample_clock = 0f32;
let mut next_value = move || {
sample_clock = (sample_clock + 1.0) % sample_rate;
(sample_clock * 440.0 * 2.0 * std::f32::consts::PI / sample_rate).sin()
};
let err_fn = |err| eprintln!("an error occurred on stream: {}", err);
let stream = device.build_output_stream(
config,
move |data: &mut [T], _: &cpal::OutputCallbackInfo| {
write_data(data, channels, &mut next_value)
},
err_fn,
None,
)?;
stream.play()?;
tokio::time::sleep(Duration::from_secs(3)).await;
Ok(())
}
fn write_data<T>(output: &mut [T], channels: usize, next_sample: &mut dyn FnMut() -> f32)
where
T: Sample + FromSample<f32>,
{
for frame in output.chunks_mut(channels) {
let value: T = T::from_sample(next_sample());
for sample in frame.iter_mut() {
*sample = value;
}
}
}
pub async fn record() {
log::info!("mic");
let host = cpal::default_host();
let devices = host.devices().unwrap();
for (_derive_index, device) in devices.enumerate() {
log::info!("{:?}", device.name());
}
let device = host.default_output_device().unwrap();
let mut supported_config = device.supported_output_configs().unwrap();
let config = supported_config.next().unwrap().with_max_sample_rate();
log::info!("{:?}", config);
match config.sample_format() {
cpal::SampleFormat::I8 => {log::info!("i8")},
cpal::SampleFormat::I16 => {log::info!("i16")},
//cpal::SampleFormat::I24 => {log::info!("i24")},
cpal::SampleFormat::I32 => {log::info!("i32")},
//cpal::SampleFormat::I48 => {log::info!("i48")},
cpal::SampleFormat::I64 => {log::info!("i64")},
cpal::SampleFormat::U8 => {log::info!("u8")},
cpal::SampleFormat::U16 => {log::info!("u16")},
//cpal::SampleFormat::U24 => {log::info!("u24")},
cpal::SampleFormat::U32 => {log::info!("u32")},
//cpal::SampleFormat::U48 => {log::info!("u48")},
cpal::SampleFormat::U64 => {log::info!("u64")},
cpal::SampleFormat::F32 => {log::info!("f32");
run::<f32>(&device, &config.clone().into()).await.unwrap();},
cpal::SampleFormat::F64 => {log::info!("f64")},
sample_format => panic!("Unsupported sample format '{sample_format}'"),
}
/*let config:StreamConfig = config.into();
let stream = device.build_output_stream(
&config,
move |data: &mut [f32], _: &cpal::OutputCallbackInfo| {
log::info!("{:?}", data);
//I need to do something here, I think
},
move |_err| {
},
None).unwrap();
stream.play().unwrap();
tokio::time::sleep(Duration::from_secs(10)).await;
stream.pause().unwrap();*/
}
fn server_status_renderer() -> Element { fn server_status_renderer() -> Element {
let server_check_time = 1_u64; let server_check_time = 1_u64;
let mut server_status = use_signal(move || ServerStatus{status:Server::Unstable,}); let mut server_status = use_signal(move || ServerStatus{status:Server::Unstable,});
@ -102,7 +208,7 @@ fn server_status_renderer() -> Element {
let mut server_status_unstable = use_signal(move|| false); let mut server_status_unstable = use_signal(move|| false);
let _server_status_task:Coroutine<()> = use_coroutine(|_| async move { let _server_status_task:Coroutine<()> = use_coroutine(|_| async move {
loop { loop {
task::sleep(Duration::from_secs(server_check_time)).await; tokio::time::sleep(Duration::from_secs(server_check_time)).await;
*server_status_watchdog.write() = true; *server_status_watchdog.write() = true;
*server_status.write() = server_status_check(server_status).await; *server_status.write() = server_status_check(server_status).await;
*server_status_watchdog.write() = false; *server_status_watchdog.write() = false;
@ -111,13 +217,13 @@ fn server_status_renderer() -> Element {
let _server_status_watchdog_timer:Coroutine<()> = use_coroutine(|_| async move { let _server_status_watchdog_timer:Coroutine<()> = use_coroutine(|_| async move {
let mut watchdog_counter = 0_i8; let mut watchdog_counter = 0_i8;
loop { loop {
task::sleep(Duration::from_secs(2*server_check_time+1)).await; tokio::time::sleep(Duration::from_secs(2*server_check_time+1)).await;
if !server_status_watchdog() { if !server_status_watchdog() {
*server_status_unstable.write() = false; *server_status_unstable.write() = false;
} }
if server_status_watchdog() { if server_status_watchdog() {
for _i in 0..5 { for _i in 0..5 {
task::sleep(Duration::from_secs(1)).await; tokio::time::sleep(Duration::from_secs(1)).await;
if server_status_watchdog() { if server_status_watchdog() {
watchdog_counter += 1; watchdog_counter += 1;
} }
@ -179,6 +285,19 @@ fn coin_status_renderer() -> Element {
} }
} }
} }
fn audio_stream_renderer() -> Element {
rsx! {
div {
audio{
src:"https://tahinli.com.tr:2323/stream",
controls:true,
autoplay: true,
muted:false,
r#loop:true,
}
}
}
}
#[component] #[component]
fn ShowServerStatus(server_status: ServerStatus) -> Element { fn ShowServerStatus(server_status: ServerStatus) -> Element {
rsx! { rsx! {