41 lines
1.2 KiB
Python
41 lines
1.2 KiB
Python
"""PCM format contracts shared by application, transports, and providers.
|
|
|
|
The canonical input is mono PCM S16LE at 16 kHz. Output uses the format
|
|
explicitly declared by the TTS provider. Declaring a sample rate does not
|
|
convert or resample audio; provider adapters own any required conversion.
|
|
"""
|
|
|
|
from typing import Literal
|
|
|
|
from pydantic import BaseModel, ConfigDict, Field
|
|
|
|
|
|
class AudioFormat(BaseModel):
|
|
"""An immutable PCM format; a frame contains one sample per channel."""
|
|
|
|
model_config = ConfigDict(frozen=True)
|
|
|
|
encoding: Literal["pcm_s16le"]
|
|
sample_rate: int = Field(gt=0, strict=True)
|
|
channels: int = Field(gt=0, strict=True)
|
|
|
|
@property
|
|
def frame_size_bytes(self) -> int:
|
|
return 2 * self.channels
|
|
|
|
def validate_chunk(self, audio: bytes) -> None:
|
|
if not audio:
|
|
raise ValueError("Audio chunk cannot be empty.")
|
|
if len(audio) % self.frame_size_bytes:
|
|
raise ValueError(
|
|
"PCM chunk must contain complete frames of "
|
|
f"{self.frame_size_bytes} bytes."
|
|
)
|
|
|
|
|
|
CANONICAL_AUDIO_FORMAT = AudioFormat(
|
|
encoding="pcm_s16le",
|
|
sample_rate=16000,
|
|
channels=1,
|
|
)
|