feat: support reading recordings, address some warnings

This commit is contained in:
2026-05-27 01:56:47 -04:00
parent e72633f26a
commit 23f86ace3b
6 changed files with 97 additions and 79 deletions

View File

@@ -1,20 +1,17 @@
use crate::{
OneToManyUniqueBTreeMap, UserDataManager,
option_ext::OptionExt as _,
recording_data::{Clip, Recording, RecordingDataManager},
recording_data::{Clip, Recording, RecordingData, RecordingDataManager},
user_capnp::user::Consent,
user_data::RECORD_IF_CONSENT_UNSPECIFIED,
};
use async_trait::async_trait;
use futures::FutureExt;
use hound::{SampleFormat, WavSpec};
use opendal::Operator;
use songbird::{
CoreEvent, Event, EventContext, EventHandler, Songbird,
driver::{Channels, SampleRate},
};
use std::{
io::Cursor,
sync::{Arc, Mutex},
time::Instant,
};
@@ -137,11 +134,17 @@ impl EventHandler for Handler {
tracing::info!("going to write the audio shortly");
let recording_data_manager = self.recording_data_manager.clone();
let pcm = pcm.clone();
let samples = pcm.clone();
let recording_data = RecordingData {
channels,
sample_rate,
samples,
};
tokio::spawn(async move {
recording_data_manager
.write(&recording, &pcm, sample_rate, channels)
.write(&recording, recording_data)
.await
.expect("TODO");
tracing::info!(?recording, "successfully wrote the audio!");

View File

@@ -49,7 +49,7 @@ impl RecordingDataManager {
.and_then(|entry| {
std::future::ready(
take(entry.name())
.map(|(day, rest)| day)
.map(|(day, _rest)| day)
.context(ParseSnafu),
)
}))

View File

@@ -1,4 +1,6 @@
use futures::TryStream;
use std::{convert::Infallible, io::Cursor};
use hound::{SampleFormat, WavReader, WavSpec};
use opendal::Operator;
use snafu::Snafu;
@@ -40,6 +42,87 @@ impl RecordingDataManager {
}
}
#[derive(Debug)]
pub struct RecordingData {
pub channels: u16,
pub sample_rate: u32,
pub samples: Vec<i16>,
}
impl RecordingDataManager {
pub async fn write(
&self,
recording: &Recording,
RecordingData {
channels,
sample_rate,
samples,
}: RecordingData,
) -> Result<
(),
Infallible, // TODO: a real error type
> {
let wav_spec = WavSpec {
channels,
sample_rate,
bits_per_sample: 16,
sample_format: SampleFormat::Int,
};
let mut buffer = Vec::new();
let writer = Cursor::new(&mut buffer);
let mut wav_writer = hound::WavWriter::new(writer, wav_spec).expect("TODO");
let mut sample_writer = wav_writer.get_i16_writer(samples.len() as u32);
for sample in samples {
sample_writer.write_sample(sample);
}
sample_writer.flush().expect("TODO");
wav_writer.finalize().expect("TODO");
let path = recording.to_string();
self.operator.write(&path, buffer).await.expect("TODO");
Ok(())
}
}
impl RecordingDataManager {
pub async fn read(
&self,
recording: &Recording,
) -> Result<
RecordingData,
Infallible, // TODO: a real error type
> {
let path = recording.to_string();
let buffer = self.operator.read(&path).await.expect("TODO");
let bytes = buffer.to_bytes();
let cursor = Cursor::new(bytes);
let wav_reader = WavReader::new(cursor).expect("TODO");
let wav_spec = wav_reader.spec();
let channels = wav_spec.channels;
let sample_rate = wav_spec.sample_rate;
let samples = wav_reader.into_samples();
let samples = Result::from_iter(samples).expect("TODO");
Ok(RecordingData {
channels,
sample_rate,
samples,
})
}
}
#[derive(Debug, Snafu)]
pub enum ListError {
/// error creating a lister through the storage operator

View File

@@ -47,7 +47,7 @@ impl RecordingDataManager {
.and_then(|entry| {
std::future::ready(
take(entry.name())
.map(|(month, rest)| month)
.map(|(month, _rest)| month)
.context(ParseSnafu),
)
}))

View File

@@ -1,17 +1,7 @@
use futures::{TryStream, TryStreamExt as _};
use hound::{SampleFormat, WavSpec};
use snafu::{ResultExt as _, Snafu};
use std::{convert::Infallible, fmt::Display, io::Cursor, str::FromStr};
use time::UtcDateTime;
use twilight_model::id::{
Id,
marker::{ChannelMarker, GuildMarker},
};
use std::{fmt::Display, str::FromStr};
use super::{
Clip, Day, Hour, ListError, Minute, Month, RecordingDataManager, Year, clip, day, hour, minute,
month, year,
};
use super::{Clip, Day, Hour, Minute, Month, Year, clip, day, hour, minute, month, year};
#[derive(Debug, Clone)]
pub struct Recording {
@@ -84,60 +74,3 @@ impl Display for Recording {
write!(f, "{year}/{month}/{day}/{hour}/{minute}/{clip}")
}
}
impl RecordingDataManager {
pub async fn write(
&self,
recording: &Recording,
samples: &[i16],
sample_rate: u32,
channels: u16,
) -> Result<
(),
Infallible, // TODO: a real error type
> {
let wav_spec = WavSpec {
channels,
sample_rate,
bits_per_sample: 16,
sample_format: SampleFormat::Int,
};
let mut buffer = Vec::new();
let writer = Cursor::new(&mut buffer);
let mut wav_writer = hound::WavWriter::new(writer, wav_spec).expect("TODO");
let mut sample_writer = wav_writer.get_i16_writer(samples.len() as u32);
for sample in samples {
sample_writer.write_sample(*sample);
}
sample_writer.flush().expect("TODO");
wav_writer.finalize().expect("TODO");
let path = recording.to_string();
self.operator.write(&path, buffer).await.expect("TODO");
Ok(())
}
}
impl RecordingDataManager {
pub async fn read(&self, recording: &Recording, sample_rate: u32, channels: u16) -> Vec<i16> {
let path = recording.to_string();
let buffer = self.operator.read(&path).await.expect("TODO");
let wav_spec = WavSpec {
channels,
sample_rate,
bits_per_sample: 16,
sample_format: SampleFormat::Int,
};
todo!();
}
}

View File

@@ -1,5 +1,4 @@
use snafu::{OptionExt as _, ResultExt as _, Snafu};
use std::num::ParseIntError;
use std::str::FromStr;
use twilight_model::id::Id;
use twilight_model::id::marker::ChannelMarker;