feat: implement rendering
This commit is contained in:
@@ -1,4 +1,19 @@
|
||||
use std::{convert::Infallible, fmt::Display};
|
||||
|
||||
use opendal::Operator;
|
||||
use opus2::Application;
|
||||
use songbird::driver::SampleRate;
|
||||
use time::{
|
||||
UtcDateTime,
|
||||
format_description::{self, StaticFormatDescription},
|
||||
macros::format_description,
|
||||
};
|
||||
use twilight_model::id::{
|
||||
Id,
|
||||
marker::{ChannelMarker, GuildMarker},
|
||||
};
|
||||
|
||||
use crate::{AudioChannels, AudioSampleRate};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RenderManager {
|
||||
@@ -10,3 +25,65 @@ impl RenderManager {
|
||||
Self { operator }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Render {
|
||||
pub start: UtcDateTime,
|
||||
pub end: UtcDateTime,
|
||||
pub guild_id: Id<GuildMarker>,
|
||||
pub voice_channel_id: Id<ChannelMarker>,
|
||||
}
|
||||
|
||||
const DATE_FORMAT: StaticFormatDescription =
|
||||
format_description!("[year]-[month]-[day]T[hour]-[minute]-[second].[subsecond]Z");
|
||||
|
||||
impl Display for Render {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let Self {
|
||||
start,
|
||||
end,
|
||||
guild_id,
|
||||
voice_channel_id,
|
||||
} = self;
|
||||
|
||||
let start = start.format(&DATE_FORMAT).unwrap();
|
||||
let end = end.format(&DATE_FORMAT).unwrap();
|
||||
|
||||
write!(f, "{guild_id}/{voice_channel_id}/{start}_{end}.opus")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RenderData {
|
||||
pub channels: opus2::Channels,
|
||||
pub sample_rate: u32,
|
||||
pub samples: Vec<i16>,
|
||||
}
|
||||
|
||||
impl RenderManager {
|
||||
pub async fn write(
|
||||
&self,
|
||||
render: &Render,
|
||||
RenderData {
|
||||
channels,
|
||||
sample_rate,
|
||||
samples,
|
||||
}: RenderData,
|
||||
) -> Result<
|
||||
(),
|
||||
Infallible, // TODO: a real error type
|
||||
> {
|
||||
let mut bytes = Vec::new();
|
||||
|
||||
let mut encoder =
|
||||
opus2::Encoder::new(sample_rate, channels, Application::Audio).expect("TODO");
|
||||
|
||||
encoder.encode(&samples, &mut bytes).expect("TODO");
|
||||
|
||||
let path = render.to_string();
|
||||
|
||||
self.operator.write(&path, bytes).await.expect("TODO");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user