Files
go-sip/internal/callflow/recording.go
T

82 lines
2.1 KiB
Go

package callflow
import (
"context"
"errors"
"fmt"
"sync"
"git.ipao.vip/rogee/go-sip/internal/media"
)
// RecordingSession records only PCM16 frames the approved callflow actually
// reads or successfully sends. It never writes a business file or encodes RTP.
// Capture failure is retained and returned by WAV; the call can still finish.
type RecordingSession struct {
MediaSession
mu sync.Mutex
pcm []byte
maxBytes int64
failure error
}
func NewRecordingSession(session MediaSession, maxWAVBytes int64) (*RecordingSession, error) {
if session == nil || maxWAVBytes <= 44 {
return nil, errors.New("recording requires a media session and a positive bounded WAV allowance")
}
return &RecordingSession{MediaSession: session, maxBytes: maxWAVBytes}, nil
}
func (r *RecordingSession) ReadPayload(ctx context.Context) ([]byte, error) {
payload, err := r.MediaSession.ReadPayload(ctx)
if err == nil {
r.capture(payload)
}
return payload, err
}
func (r *RecordingSession) SendPCM16(ctx context.Context, pcm []byte, sampleRateHz int) error {
if sampleRateHz != 16000 {
return fmt.Errorf("recording requires 16-kHz PCM16, received %d Hz", sampleRateHz)
}
if err := r.MediaSession.SendPCM16(ctx, pcm, sampleRateHz); err != nil {
return err
}
r.capture(pcm)
return nil
}
func (r *RecordingSession) capture(pcm []byte) {
if len(pcm) == 0 {
return
}
r.mu.Lock()
defer r.mu.Unlock()
if r.failure != nil {
return
}
if len(pcm)%2 != 0 {
r.failure = media.ErrWAVInvalidPCM
r.pcm = nil
return
}
if int64(len(pcm)) > r.maxBytes-44-int64(len(r.pcm)) {
r.failure = media.ErrWAVTooLarge
r.pcm = nil
return
}
r.pcm = append(r.pcm, pcm...)
}
// WAV returns an in-memory 16-kHz mono recording and its duration. The caller
// must inspect its error after the call; a failed capture must not be reported
// as a successful upload or a healthy no-recording outcome.
func (r *RecordingSession) WAV() ([]byte, int64, error) {
r.mu.Lock()
defer r.mu.Unlock()
if r.failure != nil {
return nil, 0, r.failure
}
return media.EncodeMonoWAV(r.pcm, r.maxBytes)
}