+ tnc.set_data_carrier_detect(demodulator.data_carrier_detect());
+ }
+ SoundmodemEvent::Start => {
+ input.start(event_tx.clone());
+ output.start(event_tx.clone(), out_buffer.clone());
+ }
+ SoundmodemEvent::Close => {
+ ptt_driver.ptt_off();
+ break;
+ }
+ SoundmodemEvent::DidReadFromOutputBuffer { len, timestamp } => {
+ let (occupied, internal_latency) = {
+ let out_buffer = out_buffer.read().unwrap();
+ (out_buffer.samples.len(), out_buffer.latency)
+ };
+ let internal_latency = (internal_latency.as_secs_f32() * 48000.0) as usize;
+ let dynamic_latency =
+ len.saturating_sub((timestamp.elapsed().as_secs_f32() * 48000.0) as usize);
+ modulator.update_output_buffer(
+ occupied,
+ 48000,
+ internal_latency + dynamic_latency,
+ );
+ }
+ SoundmodemEvent::OutputUnderrun => {
+ // TODO: cancel transmission, send empty data frame to host
+ }
+ }
+
+ // Update PTT state
+ let new_ptt = tnc.ptt();
+ if new_ptt != ptt {
+ if new_ptt {
+ ptt_driver.ptt_on();
+ } else {
+ ptt_driver.ptt_off();
+ }
+ }
+ ptt = new_ptt;
+
+ // Let the modulator do what it wants
+ while let Some(action) = modulator.run() {
+ match action {
+ ModulatorAction::SetIdle(idling) => {
+ out_buffer.write().unwrap().idling = idling;
+ }
+ ModulatorAction::GetNextFrame => {
+ modulator.provide_next_frame(tnc.read_tx_frame());
+ }
+ ModulatorAction::ReadOutput => loop {
+ let n = modulator.read_output_samples(&mut out_samples);
+ if n == 0 {
+ break;
+ }
+ let mut out_buffer = out_buffer.write().unwrap();
+ for s in &out_samples[0..n] {
+ out_buffer.samples.push_back(*s);
+ }
+ },
+ ModulatorAction::TransmissionWillEnd(in_samples) => {
+ tnc.set_tx_end_time(in_samples);
+ }