import math
import audioop
from array import array

def pcm_duration_ms(pcm: bytes, sample_rate: int, channels: int) -> float:
    # PCM16LE => 2 bytes por sample por canal
    if not pcm:
        return 0.0
    samples_total = len(pcm) // 2  # total de int16 (inclui canais)
    samples_per_channel = samples_total / max(1, channels)
    return (samples_per_channel / sample_rate) * 1000.0

def dbfs_pcm16le(pcm: bytes) -> float:
    """
    dBFS aproximado do PCM16LE.
    0 dBFS = full scale, silêncio tende a -inf (aqui clamp em -120).
    """
    if not pcm:
        return -120.0
    rms = audioop.rms(pcm, 2)  # width=2 bytes (int16)
    if rms <= 0:
        return -120.0
    return 20.0 * math.log10(rms / 32768.0)

def pcm16_dbfs(frame_bytes: bytes) -> float:
    # frame_bytes: PCM16LE mono
    if not frame_bytes:
        return -120.0
    samples = array("h")
    samples.frombytes(frame_bytes)
    if len(samples) == 0:
        return -120.0
    s2 = 0.0
    for x in samples:
        s2 += float(x) * float(x)
    rms = math.sqrt(s2 / len(samples)) if s2 > 0 else 0.0
    if rms <= 1e-9:
        return -120.0
    return 20.0 * math.log10(rms / 32768.0)

def is_silence(frame_bytes: bytes, *, threshold_dbfs: float = -50.0) -> bool:
    return pcm16_dbfs(frame_bytes) < threshold_dbfs