1+ use  std:: { 
2+     io:: { Read ,  Seek } , 
3+     marker:: PhantomData , 
4+     sync:: Arc , 
5+     time:: Duration , 
6+ } ; 
7+ 
8+ use  crate :: { 
9+     common:: { ChannelCount ,  SampleRate } , 
10+     math:: nz, 
11+     source:: { SeekError ,  Source } , 
12+     BitDepth ,  Sample , 
13+ } ; 
14+ 
15+ use  super :: { builder:: Settings ,  DecoderError ,  DecoderImpl } ; 
16+ 
17+ #[ cfg( feature = "claxon" ) ]  
18+ use  super :: flac; 
19+ #[ cfg( feature = "minimp3" ) ]  
20+ use  super :: mp3; 
21+ #[ cfg( feature = "symphonia" ) ]  
22+ use  super :: symphonia; 
23+ #[ cfg( feature = "lewton" ) ]  
24+ use  super :: vorbis; 
25+ #[ cfg( feature = "hound" ) ]  
26+ use  super :: wav; 
27+ 
28+ /// Decoder that loops indefinitely by seeking back to the start when reaching the end. 
29+ /// 
30+ /// Uses fast seeking for seekable sources with gapless playback, otherwise recreates the 
31+ /// decoder while caching metadata to avoid expensive file scanning. 
32+ pub  struct  LoopedDecoder < R :  Read  + Seek >  { 
33+     pub ( super )  inner :  Option < DecoderImpl < R > > , 
34+     pub ( super )  settings :  Settings , 
35+     cached_duration :  Option < Duration > , 
36+ } 
37+ 
38+ impl < R >  LoopedDecoder < R > 
39+ where 
40+     R :  Read  + Seek , 
41+ { 
42+     pub ( super )  fn  new ( decoder :  DecoderImpl < R > ,  settings :  Settings )  -> Self  { 
43+         Self  { 
44+             inner :  Some ( decoder) , 
45+             settings, 
46+             cached_duration :  None , 
47+         } 
48+     } 
49+ 
50+     /// Recreates decoder with cached metadata to avoid expensive file scanning. 
51+      fn  recreate_decoder_with_cache ( 
52+         & mut  self , 
53+         decoder :  DecoderImpl < R > , 
54+     )  -> Option < ( DecoderImpl < R > ,  Option < Sample > ) >  { 
55+         let  mut  fast_settings = self . settings . clone ( ) ; 
56+         fast_settings. total_duration  = self . cached_duration ; 
57+ 
58+         let  ( new_decoder,  sample)  = match  decoder { 
59+             #[ cfg( feature = "hound" ) ]  
60+             DecoderImpl :: Wav ( source)  => { 
61+                 let  mut  reader = source. into_inner ( ) ; 
62+                 reader. rewind ( ) . ok ( ) ?; 
63+                 let  mut  source = wav:: WavDecoder :: new_with_settings ( reader,  & fast_settings) . ok ( ) ?; 
64+                 let  sample = source. next ( ) ; 
65+                 ( DecoderImpl :: Wav ( source) ,  sample) 
66+             } 
67+             #[ cfg( feature = "lewton" ) ]  
68+             DecoderImpl :: Vorbis ( source)  => { 
69+                 let  mut  reader = source. into_inner ( ) . into_inner ( ) . into_inner ( ) ; 
70+                 reader. rewind ( ) . ok ( ) ?; 
71+                 let  mut  source =
72+                     vorbis:: VorbisDecoder :: new_with_settings ( reader,  & fast_settings) . ok ( ) ?; 
73+                 let  sample = source. next ( ) ; 
74+                 ( DecoderImpl :: Vorbis ( source) ,  sample) 
75+             } 
76+             #[ cfg( feature = "claxon" ) ]  
77+             DecoderImpl :: Flac ( source)  => { 
78+                 let  mut  reader = source. into_inner ( ) ; 
79+                 reader. rewind ( ) . ok ( ) ?; 
80+                 let  mut  source =
81+                     flac:: FlacDecoder :: new_with_settings ( reader,  & fast_settings) . ok ( ) ?; 
82+                 let  sample = source. next ( ) ; 
83+                 ( DecoderImpl :: Flac ( source) ,  sample) 
84+             } 
85+             #[ cfg( feature = "minimp3" ) ]  
86+             DecoderImpl :: Mp3 ( source)  => { 
87+                 let  mut  reader = source. into_inner ( ) ; 
88+                 reader. rewind ( ) . ok ( ) ?; 
89+                 let  mut  source = mp3:: Mp3Decoder :: new_with_settings ( reader,  & fast_settings) . ok ( ) ?; 
90+                 let  sample = source. next ( ) ; 
91+                 ( DecoderImpl :: Mp3 ( source) ,  sample) 
92+             } 
93+             #[ cfg( feature = "symphonia" ) ]  
94+             DecoderImpl :: Symphonia ( source,  PhantomData )  => { 
95+                 let  mut  reader = source. into_inner ( ) ; 
96+                 reader. rewind ( ) . ok ( ) ?; 
97+                 let  mut  source =
98+                     symphonia:: SymphoniaDecoder :: new_with_settings ( reader,  & fast_settings) . ok ( ) ?; 
99+                 let  sample = source. next ( ) ; 
100+                 ( DecoderImpl :: Symphonia ( source,  PhantomData ) ,  sample) 
101+             } 
102+             DecoderImpl :: None ( _,  _)  => return  None , 
103+         } ; 
104+         Some ( ( new_decoder,  sample) ) 
105+     } 
106+ } 
107+ 
108+ impl < R >  Iterator  for  LoopedDecoder < R > 
109+ where 
110+     R :  Read  + Seek , 
111+ { 
112+     type  Item  = Sample ; 
113+ 
114+     fn  next ( & mut  self )  -> Option < Self :: Item >  { 
115+         if  let  Some ( inner)  = & mut  self . inner  { 
116+             if  let  Some ( sample)  = inner. next ( )  { 
117+                 return  Some ( sample) ; 
118+             } 
119+ 
120+             // Cache duration on first loop to avoid recalculation 
121+             if  self . cached_duration . is_none ( )  { 
122+                 self . cached_duration  = inner. total_duration ( ) ; 
123+             } 
124+ 
125+             // Fast gapless seeking when available 
126+             if  self . settings . gapless 
127+                 && self . settings . is_seekable 
128+                 && inner. try_seek ( Duration :: ZERO ) . is_ok ( ) 
129+             { 
130+                 return  inner. next ( ) ; 
131+             } 
132+ 
133+             // Recreation fallback with cached metadata 
134+             let  decoder = self . inner . take ( ) ?; 
135+             let  ( new_decoder,  sample)  = self . recreate_decoder_with_cache ( decoder) ?; 
136+             self . inner  = Some ( new_decoder) ; 
137+             sample
138+         }  else  { 
139+             None 
140+         } 
141+     } 
142+ 
143+     fn  size_hint ( & self )  -> ( usize ,  Option < usize > )  { 
144+         ( 
145+             self . inner . as_ref ( ) . map_or ( 0 ,  |inner| inner. size_hint ( ) . 0 ) , 
146+             None ,  // Infinite 
147+         ) 
148+     } 
149+ } 
150+ 
151+ impl < R >  Source  for  LoopedDecoder < R > 
152+ where 
153+     R :  Read  + Seek , 
154+ { 
155+     fn  current_span_len ( & self )  -> Option < usize >  { 
156+         self . inner . as_ref ( ) ?. current_span_len ( ) 
157+     } 
158+ 
159+     fn  channels ( & self )  -> ChannelCount  { 
160+         self . inner . as_ref ( ) . map_or ( nz ! ( 1 ) ,  |inner| inner. channels ( ) ) 
161+     } 
162+ 
163+     fn  sample_rate ( & self )  -> SampleRate  { 
164+         self . inner 
165+             . as_ref ( ) 
166+             . map_or ( nz ! ( 44100 ) ,  |inner| inner. sample_rate ( ) ) 
167+     } 
168+ 
169+     /// Always returns `None` since looped decoders have no fixed end. 
170+      fn  total_duration ( & self )  -> Option < Duration >  { 
171+         None 
172+     } 
173+ 
174+     fn  bits_per_sample ( & self )  -> Option < BitDepth >  { 
175+         self . inner . as_ref ( ) ?. bits_per_sample ( ) 
176+     } 
177+ 
178+     fn  try_seek ( & mut  self ,  pos :  Duration )  -> Result < ( ) ,  SeekError >  { 
179+         match  & mut  self . inner  { 
180+             Some ( inner)  => inner. try_seek ( pos) , 
181+             None  => Err ( SeekError :: Other ( Arc :: new ( DecoderError :: IoError ( 
182+                 "Looped source ended when it failed to loop back" . to_string ( ) , 
183+             ) ) ) ) , 
184+         } 
185+     } 
186+ } 
0 commit comments