|
1 | 1 | use std::iter::Iterator; |
2 | | -use std::sync::{mpsc, Arc, RwLock}; |
3 | | -use std::time::Duration; |
4 | 2 |
|
5 | 3 | use symphonia::core::audio::SampleBuffer; |
6 | 4 | use symphonia::core::codecs::Decoder; |
7 | 5 | use symphonia::core::errors::Error as SymphoniaError; |
8 | 6 | use symphonia::core::formats::{FormatReader, Packet}; |
9 | 7 |
|
10 | | -use cpal::traits::{DeviceTrait, StreamTrait}; |
11 | | -use cpal::{Stream, StreamConfig}; |
12 | | - |
13 | 8 | use dizi::error::{DiziError, DiziResult}; |
14 | | -use symphonia::core::units::TimeBase; |
15 | | - |
16 | | -use crate::audio::request::PlayerRequest; |
17 | | - |
18 | | -use super::stream::StreamEvent; |
19 | 9 |
|
20 | 10 | pub struct PacketReader { |
21 | 11 | format: Box<dyn FormatReader>, |
@@ -91,135 +81,9 @@ impl PacketDecoder { |
91 | 81 | Err(SymphoniaError::IoError(_)) => Ok(vec![]), |
92 | 82 | Err(SymphoniaError::DecodeError(_)) => Ok(vec![]), |
93 | 83 | Err(err) => { |
94 | | - tracing::error!("Unhandled symphonia error: {}", err); |
| 84 | + tracing::error!(?err, "Symphonia error"); |
95 | 85 | Err(DiziError::from(err)) |
96 | 86 | } |
97 | 87 | } |
98 | 88 | } |
99 | 89 | } |
100 | | - |
101 | | -pub fn stream_loop<T>( |
102 | | - stream_tx: mpsc::Sender<StreamEvent>, |
103 | | - device: &cpal::Device, |
104 | | - config: &StreamConfig, |
105 | | - samples: Vec<T>, |
106 | | - volume: f32, |
107 | | - volume_change: fn(T, f32) -> T, |
108 | | -) -> DiziResult<(Stream, mpsc::Sender<PlayerRequest>)> |
109 | | -where |
110 | | - T: symphonia::core::sample::Sample |
111 | | - + cpal::Sample |
112 | | - + cpal::SizedSample |
113 | | - + std::marker::Send |
114 | | - + 'static |
115 | | - + symphonia::core::conv::FromSample<i8> |
116 | | - + symphonia::core::conv::FromSample<i16> |
117 | | - + symphonia::core::conv::FromSample<i32> |
118 | | - + symphonia::core::conv::FromSample<u8> |
119 | | - + symphonia::core::conv::FromSample<u16> |
120 | | - + symphonia::core::conv::FromSample<u32> |
121 | | - + symphonia::core::conv::FromSample<f32> |
122 | | - + symphonia::core::conv::FromSample<f64> |
123 | | - + symphonia::core::conv::FromSample<symphonia::core::sample::i24> |
124 | | - + symphonia::core::conv::FromSample<symphonia::core::sample::u24>, |
125 | | -{ |
126 | | - let err_fn = |err| { |
127 | | - tracing::error!("A playback error has occured! {}", err); |
128 | | - }; |
129 | | - |
130 | | - let time_base = TimeBase { |
131 | | - numer: 1, |
132 | | - denom: config.sample_rate.0 * config.channels as u32, |
133 | | - }; |
134 | | - |
135 | | - let samples_count = samples.len(); |
136 | | - |
137 | | - // all vars that the stream will update while its streaming |
138 | | - let frame_index = Arc::new(RwLock::new(0_usize)); |
139 | | - let volume = Arc::new(RwLock::new(volume)); |
140 | | - let playback_duration = Arc::new(RwLock::new(0)); |
141 | | - |
142 | | - let _ = stream_tx.send(StreamEvent::Progress(Duration::from_secs(0))); |
143 | | - |
144 | | - // if stream_tx is None, then we've already sent a StreamEnded message |
145 | | - // and we don't need to send another one |
146 | | - let mut stream_tx = Some(stream_tx); |
147 | | - |
148 | | - let (playback_loop_tx, playback_loop_rx) = mpsc::channel(); |
149 | | - |
150 | | - let stream = device.build_output_stream( |
151 | | - config, |
152 | | - move |data: &mut [T], _: &cpal::OutputCallbackInfo| { |
153 | | - let process_message = |msg: PlayerRequest| match msg { |
154 | | - PlayerRequest::SetVolume { volume: new_volume } => { |
155 | | - let mut current_volume = volume.write().unwrap(); |
156 | | - *current_volume = new_volume; |
157 | | - } |
158 | | - PlayerRequest::FastForward { offset } => { |
159 | | - let mut sample_offset = frame_index.write().unwrap(); |
160 | | - *sample_offset += time_base.denom as usize * offset.as_secs() as usize; |
161 | | - if *sample_offset >= samples_count { |
162 | | - *sample_offset = samples_count - time_base.denom as usize; |
163 | | - } |
164 | | - } |
165 | | - PlayerRequest::Rewind { offset } => { |
166 | | - let mut sample_offset = frame_index.write().unwrap(); |
167 | | - if *sample_offset < time_base.denom as usize * offset.as_secs() as usize { |
168 | | - *sample_offset = 0; |
169 | | - } else { |
170 | | - *sample_offset -= time_base.denom as usize * offset.as_secs() as usize; |
171 | | - } |
172 | | - } |
173 | | - _ => {} |
174 | | - }; |
175 | | - |
176 | | - if let Ok(msg) = playback_loop_rx.try_recv() { |
177 | | - process_message(msg); |
178 | | - } |
179 | | - |
180 | | - // if sample_offset is greater than samples_count, then we've reached the end |
181 | | - let sample_offset = { *frame_index.read().unwrap() }; |
182 | | - if sample_offset >= samples_count { |
183 | | - if let Some(stream_tx) = stream_tx.take() { |
184 | | - let _ = stream_tx.send(StreamEvent::StreamEnded); |
185 | | - } |
186 | | - return; |
187 | | - } |
188 | | - |
189 | | - let current_volume = { *volume.read().unwrap() }; |
190 | | - let mut i = 0; |
191 | | - for d in data.iter_mut() { |
192 | | - if sample_offset + i >= samples_count { |
193 | | - let mut offset = frame_index.write().unwrap(); |
194 | | - *offset = samples_count + 1; |
195 | | - break; |
196 | | - } |
197 | | - *d = volume_change(samples[sample_offset + i], current_volume); |
198 | | - i += 1; |
199 | | - } |
200 | | - // new offset |
201 | | - let new_sample_offset = { |
202 | | - let mut sample_offset = frame_index.write().unwrap(); |
203 | | - *sample_offset += i; |
204 | | - *sample_offset |
205 | | - }; |
206 | | - // new duration |
207 | | - let next_duration = time_base.calc_time(new_sample_offset as u64).seconds; |
208 | | - let prev_duration = { *playback_duration.read().unwrap() }; |
209 | | - |
210 | | - // update duration if seconds changed |
211 | | - if prev_duration != next_duration { |
212 | | - let new_duration = Duration::from_secs(next_duration); |
213 | | - if let Some(stream_tx) = stream_tx.as_ref() { |
214 | | - let _ = stream_tx.send(StreamEvent::Progress(new_duration)); |
215 | | - } |
216 | | - let mut duration = playback_duration.write().unwrap(); |
217 | | - *duration = new_duration.as_secs(); |
218 | | - } |
219 | | - }, |
220 | | - err_fn, |
221 | | - None, |
222 | | - )?; |
223 | | - stream.play()?; |
224 | | - Ok((stream, playback_loop_tx)) |
225 | | -} |
0 commit comments