|
- package aoiprxkit
-
- import (
- "encoding/binary"
- "fmt"
- "io"
- )
-
- const (
- streamMagic = "ARX1"
-
- StreamCodecPCM_S32LE uint8 = 1
- StreamCodecOpus uint8 = 2 // reserved for later phases
- )
-
- type StreamHeader struct {
- Codec uint8
- Channels uint8
- SampleRateHz uint32
- FrameSamples uint32
- Sequence uint32
- Timestamp uint64
- PayloadBytes uint32
- }
-
- func ReadStreamHeader(r io.Reader) (StreamHeader, error) {
- var raw [26]byte
- if _, err := io.ReadFull(r, raw[:]); err != nil {
- return StreamHeader{}, err
- }
- if string(raw[0:4]) != streamMagic {
- return StreamHeader{}, fmt.Errorf("invalid stream magic %q", string(raw[0:4]))
- }
- h := StreamHeader{
- Codec: raw[4],
- Channels: raw[5],
- SampleRateHz: binary.BigEndian.Uint32(raw[6:10]),
- FrameSamples: binary.BigEndian.Uint32(raw[10:14]),
- Sequence: binary.BigEndian.Uint32(raw[14:18]),
- Timestamp: binary.BigEndian.Uint64(raw[18:26]),
- }
- var payloadLenRaw [4]byte
- if _, err := io.ReadFull(r, payloadLenRaw[:]); err != nil {
- return StreamHeader{}, err
- }
- h.PayloadBytes = binary.BigEndian.Uint32(payloadLenRaw[:])
- return h, nil
- }
-
- func WritePCM32Packet(w io.Writer, channels int, sampleRateHz int, frameSamples int, sequence uint32, timestamp uint64, samples []int32) error {
- if channels < 1 || channels > 2 {
- return fmt.Errorf("channels must be 1 or 2")
- }
- if frameSamples < 0 {
- return fmt.Errorf("frameSamples must be >= 0")
- }
- if len(samples) != frameSamples*channels {
- return fmt.Errorf("sample length mismatch: got=%d want=%d", len(samples), frameSamples*channels)
- }
-
- payloadBytes := len(samples) * 4
- var hdr [30]byte
- copy(hdr[0:4], []byte(streamMagic))
- hdr[4] = StreamCodecPCM_S32LE
- hdr[5] = byte(channels)
- binary.BigEndian.PutUint32(hdr[6:10], uint32(sampleRateHz))
- binary.BigEndian.PutUint32(hdr[10:14], uint32(frameSamples))
- binary.BigEndian.PutUint32(hdr[14:18], sequence)
- binary.BigEndian.PutUint64(hdr[18:26], timestamp)
- binary.BigEndian.PutUint32(hdr[26:30], uint32(payloadBytes))
- if _, err := w.Write(hdr[:]); err != nil {
- return err
- }
-
- payload := make([]byte, payloadBytes)
- for i, s := range samples {
- binary.LittleEndian.PutUint32(payload[i*4:i*4+4], uint32(s))
- }
- _, err := w.Write(payload)
- return err
- }
|