diff --git a/.idea/dictionaries/bt.xml b/.idea/dictionaries/bt.xml
index 562630d84e..beefee1473 100644
--- a/.idea/dictionaries/bt.xml
+++ b/.idea/dictionaries/bt.xml
@@ -10,6 +10,7 @@
hifigan
scrollback
softvc
+ symphonia
tacotron
transcoded
transcodings
diff --git a/Cargo.lock b/Cargo.lock
index edca6e1420..95074fe1b5 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2868,6 +2868,7 @@ name = "media"
version = "0.0.1"
dependencies = [
"errors",
+ "log",
"symphonia",
]
@@ -4722,9 +4723,13 @@ checksum = "17033fe05e4f7f10a6ad602c272bafd2520b2e5cdd9feb61494d9cdce08e002f"
dependencies = [
"lazy_static",
"symphonia-bundle-flac",
+ "symphonia-bundle-mp3",
+ "symphonia-codec-aac",
+ "symphonia-codec-alac",
"symphonia-codec-pcm",
"symphonia-codec-vorbis",
"symphonia-core",
+ "symphonia-format-isomp4",
"symphonia-format-mkv",
"symphonia-format-ogg",
"symphonia-format-wav",
@@ -4743,6 +4748,40 @@ dependencies = [
"symphonia-utils-xiph",
]
+[[package]]
+name = "symphonia-bundle-mp3"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db5d3d53535ae2b7d0e39e82f683cac5398a6c8baca25ff1183e107d13959d3e"
+dependencies = [
+ "bitflags",
+ "lazy_static",
+ "log",
+ "symphonia-core",
+ "symphonia-metadata",
+]
+
+[[package]]
+name = "symphonia-codec-aac"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e9431b89428c31b01428563df18e52b1aff7c49e71fb80b2fa8e85632094776"
+dependencies = [
+ "lazy_static",
+ "log",
+ "symphonia-core",
+]
+
+[[package]]
+name = "symphonia-codec-alac"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "452438d6f32bf07f2f55f35371c3c8e9cce4a028a08b47fb301001f85a950f02"
+dependencies = [
+ "log",
+ "symphonia-core",
+]
+
[[package]]
name = "symphonia-codec-pcm"
version = "0.5.1"
@@ -4777,6 +4816,19 @@ dependencies = [
"log",
]
+[[package]]
+name = "symphonia-format-isomp4"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1dce84cea63247dfcc43e12edf2d19406fbb62ebc24bac1b8e6c49f1ba67b890"
+dependencies = [
+ "encoding_rs",
+ "log",
+ "symphonia-core",
+ "symphonia-metadata",
+ "symphonia-utils-xiph",
+]
+
[[package]]
name = "symphonia-format-mkv"
version = "0.5.1"
diff --git a/crates/lib/database_queries/src/queries/media_uploads/insert_media_upload.rs b/crates/lib/database_queries/src/queries/media_uploads/insert_media_upload.rs
index 747ebe8aa3..9145110069 100644
--- a/crates/lib/database_queries/src/queries/media_uploads/insert_media_upload.rs
+++ b/crates/lib/database_queries/src/queries/media_uploads/insert_media_upload.rs
@@ -70,7 +70,7 @@ SET
args.media_type,
args.maybe_original_filename,
args.original_file_size_bytes,
- args.maybe_original_duration_millis,
+ args.maybe_original_duration_millis.unwrap_or(0),
args.maybe_original_mime_type,
args.maybe_original_audio_encoding,
args.maybe_original_video_encoding,
diff --git a/crates/lib/media/Cargo.toml b/crates/lib/media/Cargo.toml
index ed5a46ae05..fc36b15be5 100644
--- a/crates/lib/media/Cargo.toml
+++ b/crates/lib/media/Cargo.toml
@@ -18,7 +18,8 @@ path = "src/lib.rs"
errors = { path = "../errors" }
# External
-symphonia = "0.5.1" # Powerful audio decoder and demuxer
+log = "0.4.14"
+symphonia = { version = "0.5.1", features = ["aac", "alac", "mp3", "isomp4"] } # Powerful audio decoder and demuxer
[dev-dependencies]
# None yet
diff --git a/crates/lib/media/src/decode_basic_audio_info.rs b/crates/lib/media/src/decode_basic_audio_info.rs
index aa879d3533..2135efd6af 100644
--- a/crates/lib/media/src/decode_basic_audio_info.rs
+++ b/crates/lib/media/src/decode_basic_audio_info.rs
@@ -69,3 +69,69 @@ pub fn decode_basic_audio_info(
codec_name: maybe_codec_name,
})
}
+
+#[cfg(test)]
+mod tests {
+ use std::path::PathBuf;
+ use errors::AnyhowResult;
+ use crate::decode_basic_audio_info::decode_basic_audio_info;
+
+ fn test_file(root_file_path: &str) -> PathBuf {
+ // https://doc.rust-lang.org/cargo/reference/environment-variables.html
+ let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
+ path.push(format!("../../../{}", root_file_path));
+ path
+ }
+
+ #[test]
+ fn decode_flac_info() -> AnyhowResult<()> {
+ let path = test_file("test_data/audio/flac/zelda_ocarina_small_item.flac");
+ let bytes = std::fs::read(path)?;
+ let info = decode_basic_audio_info(&bytes, None, None)?;
+ assert_eq!(info.codec_name, Some("flac".to_string()));
+ assert_eq!(info.duration_millis, Some(5120));
+ Ok(())
+ }
+
+ // NB: Requires symphonia 'aac' and 'isomp4' feature flags
+ #[test]
+ fn decode_m4a_alac_info() -> AnyhowResult<()> {
+ let path = test_file("test_data/audio/m4a/super_mario_bros_lost_life.m4a");
+ let bytes = std::fs::read(path)?;
+ let info = decode_basic_audio_info(&bytes, None, None)?;
+ assert_eq!(info.codec_name, Some("alac".to_string()));
+ assert_eq!(info.duration_millis, Some(5493));
+ Ok(())
+ }
+
+ // NB: Requires symphonia 'mp3' feature flag
+ #[test]
+ fn decode_mp3_info() -> AnyhowResult<()> {
+ let path = test_file("test_data/audio/mp3/super_mario_rpg_beware_the_forests_mushrooms.mp3");
+ let bytes = std::fs::read(path)?;
+ let info = decode_basic_audio_info(&bytes, None, None)?;
+ assert_eq!(info.codec_name, Some("mp3".to_string()));
+ assert_eq!(info.duration_millis, Some(15023));
+ Ok(())
+ }
+
+ #[test]
+ fn decode_ogg_info() -> AnyhowResult<()> {
+ let path = test_file("test_data/audio/ogg/banjo-kazooie_jiggy_appearance.ogg");
+ let bytes = std::fs::read(path)?;
+ let info = decode_basic_audio_info(&bytes, None, None)?;
+ assert_eq!(info.codec_name, Some("vorbis".to_string()));
+ // assert_eq!(info.duration_millis, Some(5120)); // TODO/FIXME: No duration reported.
+ Ok(())
+ }
+
+ #[test]
+ fn decode_wav_info_pcm_s16le() -> AnyhowResult<()> {
+ let path = test_file("test_data/audio/wav/sm64_mario_its_me.wav");
+ let bytes = std::fs::read(path)?;
+ let info = decode_basic_audio_info(&bytes, None, None)?;
+ assert_eq!(info.codec_name, Some("pcm_s16le".to_string()));
+ assert_eq!(info.duration_millis, Some(1891));
+ Ok(())
+ }
+}
diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/media_uploads/upload_audio.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/media_uploads/upload_audio.rs
index 1cb2dd7284..955d7be1ad 100644
--- a/crates/service/web/storyteller_web/src/http_server/endpoints/media_uploads/upload_audio.rs
+++ b/crates/service/web/storyteller_web/src/http_server/endpoints/media_uploads/upload_audio.rs
@@ -172,45 +172,11 @@ pub async fn upload_audio_handler(
if let Some(mimetype) = maybe_mimetype.as_deref() {
match mimetype {
- "audio/x-wav" => {
- // FIXME(bt, 2022-12-21): Ugh.
- /*
- let bytes = bytes.to_vec();
- let reader = Cursor::new(bytes);
- let source = ReadOnlySource::new(reader);
- let mss = MediaSourceStream::new(Box::new(source), Default::default());
-
- // Create a probe hint using the file's extension. [Optional]
- let mut hint = Hint::new();
- hint.mime_type(mimetype);
-
- // Use the default options for metadata and format readers.
- let meta_opts: MetadataOptions = Default::default();
- let fmt_opts: FormatOptions = Default::default();
-
- // Probe the media source.
- let probed = symphonia::default::get_probe()
- .format(&hint, mss, &fmt_opts, &meta_opts)
- .map_err(|e| {
- warn!("Invalid format: {:?}", e);
- UploadAudioError::BadInput("bad file".to_string())
- })?;
-
- let format = probed.format;
-
- let duration = format.default_track()
- .map(|track| {
- let timebase= track.codec_params.time_base.unwrap();
- let n_frames = track.codec_params.n_frames.unwrap();
- timebase.calc_time(n_frames)
- })
- .unwrap();
-
- let duration_millis = duration.seconds * 1000;
- let frac_millis = (duration.frac * 1000.0).trunc() as u64;
- let duration_millis = duration_millis + frac_millis;
- */
-
+ "video/x-msvideo" => {
+ // .avi
+ },
+ "audio/x-wav" | "audio/ogg" => {
+ // .wav, .ogg
let basic_info = decode_basic_audio_info(bytes.as_ref(), Some(mimetype), None)
.map_err(|e| {
warn!("file decoding error: {:?}", e);
diff --git a/test_data/audio/flac/zelda_ocarina_small_item.flac b/test_data/audio/flac/zelda_ocarina_small_item.flac
new file mode 100644
index 0000000000..87885640cd
Binary files /dev/null and b/test_data/audio/flac/zelda_ocarina_small_item.flac differ
diff --git a/test_data/audio/m4a/super_mario_bros_lost_life.m4a b/test_data/audio/m4a/super_mario_bros_lost_life.m4a
new file mode 100644
index 0000000000..7e736c7eac
Binary files /dev/null and b/test_data/audio/m4a/super_mario_bros_lost_life.m4a differ
diff --git a/test_data/audio/mp3/super_mario_rpg_beware_the_forests_mushrooms.mp3 b/test_data/audio/mp3/super_mario_rpg_beware_the_forests_mushrooms.mp3
new file mode 100644
index 0000000000..41b9209122
Binary files /dev/null and b/test_data/audio/mp3/super_mario_rpg_beware_the_forests_mushrooms.mp3 differ
diff --git a/test_data/audio/ogg/banjo-kazooie_jiggy_appearance.ogg b/test_data/audio/ogg/banjo-kazooie_jiggy_appearance.ogg
new file mode 100644
index 0000000000..50a3b5b724
Binary files /dev/null and b/test_data/audio/ogg/banjo-kazooie_jiggy_appearance.ogg differ
diff --git a/test_data/audio/wav/sm64_mario_its_me.wav b/test_data/audio/wav/sm64_mario_its_me.wav
new file mode 100644
index 0000000000..d5385f85cf
Binary files /dev/null and b/test_data/audio/wav/sm64_mario_its_me.wav differ