//! Audio playback/loopback stream.
//!
//! Uses `cpal` to output audio samples from a ringbuffer to the default
//! output device. This is primarily used for the "Loopback" feature
//! where a user can hear their own processed voice.

use anyhow::{Result, anyhow};
use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
use ringbuf::HeapCons;
use ringbuf::traits::Consumer;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use tracing::{info, warn};

use super::SAMPLE_RATE;

/// Starts the audio playback stream.
///
/// Pulls samples from the provided ringbuffer consumer and writes them
/// to the default output device. Only outputs non-zero samples if the
/// `loopback_flag` is true.
pub fn start_audio_playback(
    mut consumer: HeapCons<f32>,
    loopback_flag: Arc<AtomicBool>,
) -> Result<cpal::Stream> {
    let host = cpal::default_host();
    let device = host
        .default_output_device()
        .ok_or_else(|| anyhow!("No output device found"))?;

    info!("Using output device: {}", device.name()?);

    let config = cpal::StreamConfig {
        channels: 1, // Mono playback for loopback
        sample_rate: SAMPLE_RATE,
        buffer_size: cpal::BufferSize::Default,
    };

    let stream = device.build_output_stream(
        &config,
        move |data: &mut [f32], _: &cpal::OutputCallbackInfo| {
            let enabled = loopback_flag.load(Ordering::Relaxed);
            
            for sample in data.iter_mut() {
                if enabled {
                    *sample = consumer.try_pop().unwrap_or(0.0);
                } else {
                    // Drain the ringbuffer even if loopback is disabled
                    // to prevent old audio from playing when toggled on.
                    let _ = consumer.try_pop();
                    *sample = 0.0;
                }
            }
        },
        move |err| {
            warn!("Playback stream error: {}", err);
        },
        None,
    )?;

    stream.play()?;
    Ok(stream)
}
