feat: support reading recordings, address some warnings
This commit is contained in:
15
src/call.rs
15
src/call.rs
@@ -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!");
|
||||
|
||||
@@ -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),
|
||||
)
|
||||
}))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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),
|
||||
)
|
||||
}))
|
||||
|
||||
@@ -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!();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user