diff --git a/src/main.rs b/src/main.rs index bbe5c48..9a13066 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,10 +3,10 @@ use std::{fs::File, io::BufReader}; use log::*; use serde::{Deserialize, Serialize}; -use telegram_bot::CanReplySendMessage; use telegram_bot::{ Api, CanGetFile, CanReplySendAudio, InputFileUpload, MessageKind, UpdateKind, Voice, }; +use telegram_bot::{CanDeleteMessage, CanReplySendMessage}; use thiserror::Error; use tokio_stream::StreamExt; @@ -43,6 +43,8 @@ enum RuntimeError { FileDecodeError(#[source] ogg_opus::Error), #[error("Cannot encode audio file")] FileEncodeError(#[source] ogg_opus::Error), + #[error("The voice message does not contain any audio data")] + FileAudioEmpty, #[error("Internal error")] IOError(#[from] std::io::Error), } @@ -70,21 +72,39 @@ async fn main() -> Result<(), UnresolvableError> { // If the received update contains a new message... let update = update?; if let UpdateKind::Message(message) = update.kind { - if let MessageKind::Voice { data } = &message.kind { - let result = handle_voice_message(&config, &api, data).await; - match result { - Ok(audio) => { - api.send( - message.audio_reply(InputFileUpload::with_data(audio, "amplified.ogg")), - ) + match &message.kind { + MessageKind::Voice { data } => { + let progress_message = api + .send(message.text_reply("On it, give me a sec...")) .await?; - } - Err(err) => { - error!("{:?}", err); - api.send(message.text_reply(format!("Error: {}", err))) + let result = handle_voice_message(&config, &api, data).await; + match result { + Ok(audio) => { + api.send( + message.audio_reply(InputFileUpload::with_data( + audio, + "amplified.ogg", + )), + ) .await?; + } + Err(err) => { + match err { + RuntimeError::FileAudioEmpty => {} + _ => error!("{:?}", err), + } + api.send(message.text_reply(format!("Error: {}", err))) + .await?; + } + } + api.send(progress_message.delete()).await?; + } + MessageKind::Text { data, .. } => { + if data.starts_with("/") { + api.send(message.text_reply("Send or forward voicemessages to me and I'll amplify them for you. Currently, I don't understand any commands.")).await?; } } + _ => {} } } } @@ -125,7 +145,7 @@ async fn handle_voice_message( let mut last_audio = audio.clone(); let mut amplification_factor = 2; loop { - let (current_audio, clipping_rate) = amplify_audio(&audio, amplification_factor); + let (current_audio, clipping_rate) = amplify_audio(&audio, amplification_factor)?; if clipping_rate > 1.0 / (48000.0 * 10.0) { break; } @@ -141,17 +161,26 @@ async fn handle_voice_message( Ok(ogg_data_out) } -fn amplify_audio(original: &[i16], factor: i16) -> (Vec, f64) { +fn amplify_audio(original: &[i16], factor: i16) -> Result<(Vec, f64), RuntimeError> { + let mut is_empty = true; let mut modified_audio = original.to_owned(); let mut clipping_samples = 0; for sample in modified_audio.iter_mut() { + if *sample == 0 { + continue; + } + is_empty = false; *sample = sample.checked_mul(factor).unwrap_or_else(|| { clipping_samples += 1; sample.saturating_mul(factor) }); } + if is_empty { + return Err(RuntimeError::FileAudioEmpty); + } + let clipping_rate = clipping_samples as f64 / modified_audio.len() as f64; - info!("samples: {} rate: {}", clipping_samples, clipping_rate); - (modified_audio, clipping_rate) + trace!("samples: {} rate: {}", clipping_samples, clipping_rate); + Ok((modified_audio, clipping_rate)) }