|
- package recorder
-
- import (
- "sync"
- "time"
- )
-
- type iqBlock struct {
- t0 time.Time
- samples []complex64
- }
-
- // Ring keeps recent IQ blocks for preroll capture.
- type Ring struct {
- mu sync.RWMutex
- blocks []iqBlock
- maxBlocks int
- sampleRate int
- blockSize int
- }
-
- func NewRing(sampleRate int, blockSize int, seconds int) *Ring {
- if seconds <= 0 {
- seconds = 5
- }
- if sampleRate <= 0 {
- sampleRate = 2_048_000
- }
- if blockSize <= 0 {
- blockSize = 2048
- }
- blocksPerSec := sampleRate / blockSize
- if blocksPerSec <= 0 {
- blocksPerSec = 1
- }
- maxBlocks := blocksPerSec * seconds
- if maxBlocks < 2 {
- maxBlocks = 2
- }
- return &Ring{maxBlocks: maxBlocks, sampleRate: sampleRate, blockSize: blockSize}
- }
-
- func (r *Ring) Reset(sampleRate int, blockSize int, seconds int) {
- *r = *NewRing(sampleRate, blockSize, seconds)
- }
-
- func (r *Ring) Push(t0 time.Time, samples []complex64) {
- if r == nil || len(samples) == 0 {
- return
- }
- r.mu.Lock()
- defer r.mu.Unlock()
- r.blocks = append(r.blocks, iqBlock{t0: t0, samples: append([]complex64(nil), samples...)})
- if len(r.blocks) > r.maxBlocks {
- drop := len(r.blocks) - r.maxBlocks
- r.blocks = r.blocks[drop:]
- }
- }
-
- // Slice returns IQ samples between [start,end] (best-effort).
- func (r *Ring) Slice(start, end time.Time) []complex64 {
- if r == nil || end.Before(start) {
- return nil
- }
- r.mu.RLock()
- defer r.mu.RUnlock()
- var out []complex64
- for _, b := range r.blocks {
- blockDur := time.Duration(float64(len(b.samples)) / float64(r.sampleRate) * float64(time.Second))
- bEnd := b.t0.Add(blockDur)
- if bEnd.Before(start) || b.t0.After(end) {
- continue
- }
- // compute overlap
- oStart := maxTime(start, b.t0)
- oEnd := minTime(end, bEnd)
- if oEnd.Before(oStart) {
- continue
- }
- startIdx := int(float64(oStart.Sub(b.t0)) / float64(time.Second) * float64(r.sampleRate))
- endIdx := int(float64(oEnd.Sub(b.t0)) / float64(time.Second) * float64(r.sampleRate))
- if startIdx < 0 {
- startIdx = 0
- }
- if endIdx > len(b.samples) {
- endIdx = len(b.samples)
- }
- if endIdx > startIdx {
- out = append(out, b.samples[startIdx:endIdx]...)
- }
- }
- return out
- }
-
- func minTime(a, b time.Time) time.Time {
- if a.Before(b) {
- return a
- }
- return b
- }
-
- func maxTime(a, b time.Time) time.Time {
- if a.After(b) {
- return a
- }
- return b
- }
|