diff --git a/musikr/src/main/jni/shim/file_shim.cpp b/musikr/src/main/jni/shim/file_shim.cpp index 617e14c63..3303782c5 100644 --- a/musikr/src/main/jni/shim/file_shim.cpp +++ b/musikr/src/main/jni/shim/file_shim.cpp @@ -2,37 +2,37 @@ namespace taglib_shim { -// File type checking functions -bool File_isMPEG(TagLib::File* file) { - return dynamic_cast(file) != nullptr; +// File conversion functions +TagLib::Ogg::Vorbis::File* File_asVorbis(TagLib::File* file) { + return dynamic_cast(file); } -bool File_isFLAC(TagLib::File* file) { - return dynamic_cast(file) != nullptr; +TagLib::Ogg::Opus::File* File_asOpus(TagLib::File* file) { + return dynamic_cast(file); } -bool File_isMP4(TagLib::File* file) { - return dynamic_cast(file) != nullptr; +TagLib::MPEG::File* File_asMPEG(TagLib::File* file) { + return dynamic_cast(file); } -bool File_isOgg(TagLib::File* file) { - return dynamic_cast(file) != nullptr; +TagLib::FLAC::File* File_asFLAC(TagLib::File* file) { + return dynamic_cast(file); } -bool File_isOpus(TagLib::File* file) { - return dynamic_cast(file) != nullptr; +TagLib::MP4::File* File_asMP4(TagLib::File* file) { + return dynamic_cast(file); } -bool File_isWAV(TagLib::File* file) { - return dynamic_cast(file) != nullptr; +TagLib::RIFF::WAV::File* File_asWAV(TagLib::File* file) { + return dynamic_cast(file); } -bool File_isWavPack(TagLib::File* file) { - return dynamic_cast(file) != nullptr; +TagLib::WavPack::File* File_asWavPack(TagLib::File* file) { + return dynamic_cast(file); } -bool File_isAPE(TagLib::File* file) { - return dynamic_cast(file) != nullptr; +TagLib::APE::File* File_asAPE(TagLib::File* file) { + return dynamic_cast(file); } } // namespace taglib_shim \ No newline at end of file diff --git a/musikr/src/main/jni/shim/file_shim.hpp b/musikr/src/main/jni/shim/file_shim.hpp index 463a72da0..1624b967f 100644 --- a/musikr/src/main/jni/shim/file_shim.hpp +++ b/musikr/src/main/jni/shim/file_shim.hpp @@ -12,18 +12,18 @@ #include #include #include +#include namespace taglib_shim { -// File type checking functions -bool File_isMPEG(TagLib::File* file); -bool File_isFLAC(TagLib::File* file); -bool File_isMP4(TagLib::File* file); -bool File_isOgg(TagLib::File* file); -bool File_isOpus(TagLib::File* file); -bool File_isWAV(TagLib::File* file); -bool File_isWavPack(TagLib::File* file); -bool File_isAPE(TagLib::File* file); - +// File conversion functions +TagLib::Ogg::Vorbis::File* File_asVorbis(TagLib::File* file); +TagLib::Ogg::Opus::File* File_asOpus(TagLib::File* file); +TagLib::MPEG::File* File_asMPEG(TagLib::File* file); +TagLib::FLAC::File* File_asFLAC(TagLib::File* file); +TagLib::MP4::File* File_asMP4(TagLib::File* file); +TagLib::RIFF::WAV::File* File_asWAV(TagLib::File* file); +TagLib::WavPack::File* File_asWavPack(TagLib::File* file); +TagLib::APE::File* File_asAPE(TagLib::File* file); } // namespace taglib_shim \ No newline at end of file diff --git a/musikr/src/main/jni/src/lib.rs b/musikr/src/main/jni/src/lib.rs index cc18f3224..f6378b13a 100644 --- a/musikr/src/main/jni/src/lib.rs +++ b/musikr/src/main/jni/src/lib.rs @@ -28,7 +28,7 @@ pub extern "C" fn Java_org_oxycblt_musikr_metadata_MetadataJNI_openFile<'local>( let file_ref = match FileRef::from_stream(stream) { Some(file_ref) => file_ref, None => { - let error = "Failed to create FileRef"; + let error = "Failed to create File"; let error_str = env.new_string(error).expect("Couldn't create error string!"); return error_str.into_raw(); } diff --git a/musikr/src/main/jni/src/taglib/ffi.rs b/musikr/src/main/jni/src/taglib/ffi.rs index 956171880..7471b3a2b 100644 --- a/musikr/src/main/jni/src/taglib/ffi.rs +++ b/musikr/src/main/jni/src/taglib/ffi.rs @@ -3,61 +3,100 @@ pub(crate) mod bindings { unsafe extern "C++" { include!("taglib/taglib.h"); include!("taglib/tstring.h"); + include!("taglib/vorbisfile.h"); + include!("taglib/xiphcomment.h"); include!("shim/iostream_shim.hpp"); include!("shim/file_shim.hpp"); #[namespace = "TagLib"] type FileRef; - #[namespace = "TagLib"] - type File; - #[namespace = "TagLib"] - #[cxx_name = "String"] - type TagString; - #[namespace = "TagLib"] - type AudioProperties; - - #[namespace = "taglib_shim"] - type RustIOStream; - #[namespace = "taglib_shim"] - type RustStream; - - // Create a FileRef from an iostream - #[namespace = "taglib_shim"] - unsafe fn new_rust_iostream(stream: *mut RustStream) -> UniquePtr; - #[namespace = "taglib_shim"] - fn new_FileRef_from_stream(stream: UniquePtr) -> UniquePtr; - - // FileRef helper functions fn isNull(self: Pin<&FileRef>) -> bool; fn file(self: Pin<&FileRef>) -> *mut File; + #[namespace = "taglib_shim"] + type RustIOStream; + // Create a FileRef from an iostream + #[namespace = "taglib_shim"] + unsafe fn new_rust_iostream(stream: *mut RustStream) -> UniquePtr; + + #[namespace = "taglib_shim"] + type RustStream; + #[namespace = "taglib_shim"] + fn new_FileRef_from_stream(stream: UniquePtr) -> UniquePtr; + + #[namespace = "TagLib"] + type File; fn audioProperties(self: Pin<&File>) -> *mut AudioProperties; - // File type checking functions - #[namespace = "taglib_shim"] - unsafe fn File_isMPEG(file: *mut File) -> bool; - #[namespace = "taglib_shim"] - unsafe fn File_isFLAC(file: *mut File) -> bool; - #[namespace = "taglib_shim"] - unsafe fn File_isMP4(file: *mut File) -> bool; - #[namespace = "taglib_shim"] - unsafe fn File_isOgg(file: *mut File) -> bool; - #[namespace = "taglib_shim"] - unsafe fn File_isOpus(file: *mut File) -> bool; - #[namespace = "taglib_shim"] - unsafe fn File_isWAV(file: *mut File) -> bool; - #[namespace = "taglib_shim"] - unsafe fn File_isWavPack(file: *mut File) -> bool; - #[namespace = "taglib_shim"] - unsafe fn File_isAPE(file: *mut File) -> bool; - - // AudioProperties methods + #[namespace = "TagLib"] + type AudioProperties; fn lengthInMilliseconds(self: Pin<&AudioProperties>) -> i32; fn bitrate(self: Pin<&AudioProperties>) -> i32; fn sampleRate(self: Pin<&AudioProperties>) -> i32; fn channels(self: Pin<&AudioProperties>) -> i32; - // String conversion utilities + #[namespace = "TagLib::Ogg::Vorbis"] + #[cxx_name = "File"] + type VorbisFile; + unsafe fn tag(self: Pin<&VorbisFile>) -> *mut XiphComment; + + #[namespace = "TagLib::FLAC"] + #[cxx_name = "File"] + type FLACFile; + + #[namespace = "TagLib::Ogg::Opus"] + #[cxx_name = "File"] + type OpusFile; + + #[namespace = "TagLib::Ogg"] + type XiphComment; + unsafe fn fieldListMap(self: Pin<&XiphComment>) -> &FieldListMap; + + #[namespace = "TagLib::Ogg"] + type FieldListMap; + + #[namespace = "TagLib::MPEG"] + #[cxx_name = "File"] + type MPEGFile; + + + #[namespace = "TagLib::MP4"] + #[cxx_name = "File"] + type MP4File; + + #[namespace = "TagLib::RIFF::WAV"] + #[cxx_name = "File"] + type WAVFile; + + #[namespace = "TagLib::WavPack"] + #[cxx_name = "File"] + type WavPackFile; + + #[namespace = "TagLib::APE"] + #[cxx_name = "File"] + type APEFile; + + // File conversion functions + #[namespace = "taglib_shim"] + unsafe fn File_asVorbis(file: *mut File) -> *mut VorbisFile; + #[namespace = "taglib_shim"] + unsafe fn File_asOpus(file: *mut File) -> *mut OpusFile; + #[namespace = "taglib_shim"] + unsafe fn File_asMPEG(file: *mut File) -> *mut MPEGFile; + #[namespace = "taglib_shim"] + unsafe fn File_asFLAC(file: *mut File) -> *mut FLACFile; + #[namespace = "taglib_shim"] + unsafe fn File_asMP4(file: *mut File) -> *mut MP4File; + #[namespace = "taglib_shim"] + unsafe fn File_asWAV(file: *mut File) -> *mut WAVFile; + #[namespace = "taglib_shim"] + unsafe fn File_asWavPack(file: *mut File) -> *mut WavPackFile; + #[namespace = "taglib_shim"] + unsafe fn File_asAPE(file: *mut File) -> *mut APEFile; + + #[namespace = "TagLib"] + #[cxx_name = "String"] + type TagString; #[namespace = "taglib_shim"] unsafe fn toCString(self: Pin<&TagString>, unicode: bool) -> *const c_char; #[namespace = "taglib_shim"] diff --git a/musikr/src/main/jni/src/taglib/mod.rs b/musikr/src/main/jni/src/taglib/mod.rs index ecab3413f..265b37756 100644 --- a/musikr/src/main/jni/src/taglib/mod.rs +++ b/musikr/src/main/jni/src/taglib/mod.rs @@ -1,20 +1,9 @@ mod ffi; mod stream; -use std::pin::{pin, Pin}; - -use cxx::UniquePtr; -pub use stream::{RustStream, TagLibStream}; use ffi::bindings; - -/// Audio properties of a media file -#[derive(Default)] -pub struct AudioProperties { - pub length_in_milliseconds: i32, - pub bitrate_in_kilobits_per_second: i32, - pub sample_rate_in_hz: i32, - pub number_of_channels: i32, -} +use std::pin::Pin; +pub use stream::{RustStream, TagLibStream}; pub enum File { Unknown { @@ -46,29 +35,13 @@ pub enum File { }, } -impl Default for File { - fn default() -> Self { - File::Unknown { - audio_properties: None, - } - } -} - -impl File { - /// Get the audio properties of the file, if available - pub fn audio_properties(&self) -> Option<&AudioProperties> { - match self { - File::Unknown { audio_properties, .. } | - File::MP3 { audio_properties, .. } | - File::FLAC { audio_properties, .. } | - File::MP4 { audio_properties, .. } | - File::OGG { audio_properties, .. } | - File::Opus { audio_properties, .. } | - File::WAV { audio_properties, .. } | - File::WavPack { audio_properties, .. } | - File::APE { audio_properties, .. } => audio_properties.as_ref() - } - } +/// Audio properties of a media file +#[derive(Default)] +pub struct AudioProperties { + pub length_in_milliseconds: i32, + pub bitrate_in_kilobits_per_second: i32, + pub sample_rate_in_hz: i32, + pub number_of_channels: i32, } // Safe wrapper for FileRef that owns extracted data @@ -81,13 +54,13 @@ impl FileRef { pub fn from_stream<'a, T: TagLibStream + 'a>(stream: T) -> Option { // Create the RustStream wrapper let rust_stream = stream::RustStream::new(stream); - + // Convert to raw pointer for FFI let raw_stream = Box::into_raw(Box::new(rust_stream)) as *mut bindings::RustStream; - + // Create the RustIOStream C++ wrapper let iostream = unsafe { ffi::bindings::new_rust_iostream(raw_stream) }; - + // Create FileRef from iostream let file_ref = ffi::bindings::new_FileRef_from_stream(iostream); if file_ref.is_null() { @@ -117,25 +90,63 @@ impl FileRef { // Determine file type and create appropriate variant let file = unsafe { - if ffi::bindings::File_isMPEG(file_ptr) { - File::MP3 { audio_properties } - } else if ffi::bindings::File_isFLAC(file_ptr) { - File::FLAC { audio_properties } - } else if ffi::bindings::File_isMP4(file_ptr) { - File::MP4 { audio_properties } - } else if ffi::bindings::File_isOpus(file_ptr) { - File::Opus { audio_properties } - } else if ffi::bindings::File_isOgg(file_ptr) { - File::OGG { audio_properties } - } else if ffi::bindings::File_isWAV(file_ptr) { - File::WAV { audio_properties } - } else if ffi::bindings::File_isWavPack(file_ptr) { - File::WavPack { audio_properties } - } else if ffi::bindings::File_isAPE(file_ptr) { - File::APE { audio_properties } - } else { - File::Unknown { audio_properties } + let mpeg_file = ffi::bindings::File_asMPEG(file_ptr); + if !mpeg_file.is_null() { + return Some(FileRef { + file: File::MP3 { audio_properties } + }); } + + let flac_file = ffi::bindings::File_asFLAC(file_ptr); + if !flac_file.is_null() { + return Some(FileRef { + file: File::FLAC { audio_properties } + }); + } + + let mp4_file = ffi::bindings::File_asMP4(file_ptr); + if !mp4_file.is_null() { + return Some(FileRef { + file: File::MP4 { audio_properties } + }); + } + + let wav_file = ffi::bindings::File_asWAV(file_ptr); + if !wav_file.is_null() { + return Some(FileRef { + file: File::WAV { audio_properties } + }); + } + + let wavpack_file = ffi::bindings::File_asWavPack(file_ptr); + if !wavpack_file.is_null() { + return Some(FileRef { + file: File::WavPack { audio_properties } + }); + } + + let ape_file = ffi::bindings::File_asAPE(file_ptr); + if !ape_file.is_null() { + return Some(FileRef { + file: File::APE { audio_properties } + }); + } + + let vorbis_file = ffi::bindings::File_asVorbis(file_ptr); + if !vorbis_file.is_null() { + return Some(FileRef { + file: File::OGG { audio_properties } + }); + } + + let opus_file = ffi::bindings::File_asOpus(file_ptr); + if !opus_file.is_null() { + return Some(FileRef { + file: File::Opus { audio_properties } + }); + } + + File::Unknown { audio_properties } }; // Clean up C++ objects - they will be dropped when file_ref is dropped @@ -147,4 +158,4 @@ impl FileRef { pub fn file(&self) -> &File { &self.file } -} \ No newline at end of file +}