1pub(crate) mod bits;
4mod chunk;
5pub(crate) mod codebook;
6mod endianness;
7pub(crate) mod header;
8pub(crate) mod math;
9mod packet;
10
11use symphonia_core::{
12 codecs::{
13 CodecParameters,
14 audio::{AudioCodecParameters, well_known::CODEC_ID_VORBIS},
15 },
16 common::FourCc,
17 errors::{Error, Result, SeekErrorKind},
18 formats::{
19 FormatId, FormatInfo, FormatOptions, FormatReader, MediaInfo, SeekMode, SeekTo, SeekedTo,
20 Track,
21 probe::{ProbeableFormat, Score, Scoreable},
22 },
23 io::{MediaSourceStream, ReadBytes as _, ScopedStream},
24 meta::{Metadata, MetadataLog},
25 packet::Packet,
26};
27
28use crate::{
29 chunk::{Chunk, ChunkReader},
30 header::{IdentHeader, SetupHeader},
31 packet::{PacketInfo, PacketReader},
32};
33
34const FORMAT_INFO: FormatInfo = FormatInfo {
36 format: FormatId::new(FourCc::new(*b"wem ")),
37 short_name: "wem",
38 long_name: "Wwise Encoded Media",
39};
40
41pub struct WemReader<'s> {
43 mss: MediaSourceStream<'s>,
45 media_info: MediaInfo,
47 metadata: MetadataLog,
49 tracks: Vec<Track>,
51 packet_reader: PacketReader,
53}
54
55impl<'s> WemReader<'s> {
56 pub fn try_new(mut mss: MediaSourceStream<'s>) -> Result<Self> {
62 let riff_marker = mss.read_quad_bytes()?;
64 let endianness = match &riff_marker {
65 b"RIFF" => endianness::Endianness::Little,
66 b"RIFX" => endianness::Endianness::Big,
67 _ => {
68 return symphonia_core::errors::unsupported_error(
69 "wem: missing RIFF stream marker",
70 );
71 }
72 };
73
74 let _riff_size = endianness.u32(&mut mss)?;
76
77 let riff_form = mss.read_quad_bytes()?;
79 if riff_form != *b"WAVE" {
80 return symphonia_core::errors::unsupported_error("wem: RIFF form is not WAVE");
82 }
83 let mut format = None;
84
85 loop {
87 let chunk = ChunkReader::read(endianness, &mut mss)?;
88
89 match chunk {
90 Chunk::Fmt(fmt) => {
91 format = Some(fmt);
93 }
94 Chunk::Data(last_offset) => {
95 let Some(format) = format.as_ref() else {
97 return symphonia_core::errors::decode_error("wem: missing format chunk");
98 };
99
100 let channels =
102 symphonia_common::xiph::audio::vorbis::vorbis_channels_to_channels(
103 u8::try_from(format.channels.get())
104 .map_err(|_| Error::LimitError("wem: too many channels"))?,
105 )
106 .ok_or(Error::LimitError("wem: too many channels"))?;
107
108 let ident_packet = IdentHeader::new(format)?;
110 let setup_packet = SetupHeader::new(format, &mut mss)?;
111
112 let packet_info = format.packet_info(&setup_packet, last_offset);
114
115 let mut extra_data = ident_packet.into_inner().to_vec();
117 extra_data.append(&mut setup_packet.into_inner());
118
119 let mut codec_params = AudioCodecParameters::new();
121 codec_params
122 .for_codec(CODEC_ID_VORBIS)
123 .with_sample_rate(format.sample_rate.get())
124 .with_channels(channels)
125 .with_extra_data(extra_data.into_boxed_slice());
127
128 let mut track = Track::new(0);
130 track.with_codec_params(CodecParameters::Audio(codec_params));
131 let tracks = vec![track];
132
133 let media_info = MediaInfo::new();
135 let metadata = MetadataLog::default();
136
137 let mut packet_reader = PacketReader::new(packet_info);
139 packet_reader.read_first(&mut mss)?;
141
142 return Ok(Self {
144 mss,
145 media_info,
146 metadata,
147 tracks,
148 packet_reader,
149 });
150 }
151 Chunk::Hash => {
152 return symphonia_core::errors::unsupported_error(
153 "wem: can't handle hash chunks",
154 );
155 }
156 }
157 }
158 }
159}
160
161impl ProbeableFormat<'_> for WemReader<'_> {
162 fn try_probe_new(
163 mss: MediaSourceStream<'_>,
164 _opts: FormatOptions,
165 ) -> Result<Box<dyn FormatReader + '_>> {
166 Ok(Box::new(WemReader::try_new(mss)?))
167 }
168
169 fn probe_data() -> &'static [symphonia_core::formats::probe::ProbeFormatData] {
170 &[symphonia_core::support_format!(
171 FORMAT_INFO,
172 &["wem"],
173 &["application/octet-stream"],
174 &[b"RIFF", b"RIFX"]
175 )]
176 }
177}
178
179impl Scoreable for WemReader<'_> {
180 fn score(mut src: ScopedStream<&mut MediaSourceStream<'_>>) -> Result<Score> {
181 let riff_marker = src.read_quad_bytes()?;
183 if riff_marker != *b"RIFF" && riff_marker != *b"RIFX" {
184 return Ok(Score::Unsupported);
185 }
186
187 src.ignore_bytes(4)?;
189
190 let riff_form = src.read_quad_bytes()?;
192 if riff_form != *b"WAVE" {
193 return Ok(Score::Unsupported);
194 }
195
196 Ok(Score::Supported(255))
197 }
198}
199
200impl FormatReader for WemReader<'_> {
201 fn format_info(&self) -> &FormatInfo {
202 &FORMAT_INFO
203 }
204
205 fn media_info(&self) -> &MediaInfo {
206 &self.media_info
207 }
208
209 fn metadata(&mut self) -> Metadata<'_> {
210 self.metadata.metadata()
211 }
212
213 fn seek(&mut self, _mode: SeekMode, _to: SeekTo) -> Result<SeekedTo> {
214 if self.tracks.is_empty() {
216 return symphonia_core::errors::seek_error(SeekErrorKind::Unseekable);
217 }
218
219 todo!()
220 }
221
222 fn tracks(&self) -> &[Track] {
223 &self.tracks
224 }
225
226 fn next_packet(&mut self) -> Result<Option<Packet>> {
227 self.packet_reader.read(&mut self.mss, self.tracks[0].id)
229 }
230
231 fn into_inner<'s>(self: Box<Self>) -> MediaSourceStream<'s>
232 where
233 Self: 's,
234 {
235 self.mss
236 }
237}