#!/usr/bin/python3
"""Exercise the installed encoder/decoder with normal and Skeleton streams."""
import math
import os
from pathlib import Path
import struct
import subprocess
import tempfile
import wave

with tempfile.TemporaryDirectory(prefix="speex-cli-", dir=os.environ.get("AUTOPKGTEST_TMP")) as tmp:
    root = Path(tmp)
    for rate in (8000, 16000, 32000):
        for channels in (1, 2):
            samples = rate // 5
            pcm = b"".join(
                struct.pack("<h", round(12000 * math.sin(2 * math.pi * 440 * i / rate))) * channels
                for i in range(samples)
            )
            wav = root / "input.wav"
            with wave.open(str(wav), "wb") as stream:
                stream.setparams((channels, 2, rate, samples, "NONE", "not compressed"))
                stream.writeframes(pcm)
            ordinary_audio = None
            for skeleton in (False, True):
                encoded, decoded = root / "output.spx", root / "decoded.wav"
                args = ["speexenc", "--vbr", "--quality", "8"]
                if skeleton:
                    args.append("--skeleton")
                subprocess.run(args + [str(wav), str(encoded)], check=True)
                subprocess.run(["speexdec", str(encoded), str(decoded)], check=True)
                with wave.open(str(decoded), "rb") as stream:
                    assert stream.getnchannels() == channels
                    assert stream.getframerate() == rate
                    assert stream.getsampwidth() == 2
                    frames = stream.getnframes()
                    # The CLI flushes codec lookahead as trailing frame padding.
                    assert samples <= frames <= samples + rate // 50
                    audio = stream.readframes(frames)
                    assert any(audio)
                    if skeleton:
                        assert audio == ordinary_audio
                    else:
                        ordinary_audio = audio
                print(f"PASS rate={rate} channels={channels} skeleton={skeleton}", flush=True)
