Wideband autonomous SDR analysis engine forked from sdr-visual-suite
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

120 lines
2.6KB

  1. package recorder
  2. import (
  3. "bufio"
  4. "encoding/json"
  5. "os"
  6. "path/filepath"
  7. "sync"
  8. "time"
  9. )
  10. const (
  11. audioStutterDebugDir = "debug/audio-stutter"
  12. serverStreamSummaryFile = "server_stream_summary.jsonl"
  13. browserAudioSummaryFile = "browser_audio_summary.jsonl"
  14. )
  15. type audioStutterDebugLogger struct {
  16. mu sync.Mutex
  17. serverFile *os.File
  18. serverWriter *bufio.Writer
  19. browserFile *os.File
  20. browserWriter *bufio.Writer
  21. }
  22. func newAudioStutterDebugLogger() *audioStutterDebugLogger {
  23. return &audioStutterDebugLogger{}
  24. }
  25. func (l *audioStutterDebugLogger) WriteServerSummary(v any) error {
  26. l.mu.Lock()
  27. defer l.mu.Unlock()
  28. if err := l.ensureServerWriterLocked(); err != nil {
  29. return err
  30. }
  31. return writeJSONLLineLocked(l.serverWriter, v)
  32. }
  33. func (l *audioStutterDebugLogger) WriteBrowserSummary(v any) error {
  34. l.mu.Lock()
  35. defer l.mu.Unlock()
  36. if err := l.ensureBrowserWriterLocked(); err != nil {
  37. return err
  38. }
  39. envelope := map[string]any{
  40. "ts_server": time.Now().UTC().Format(time.RFC3339Nano),
  41. "payload": v,
  42. }
  43. return writeJSONLLineLocked(l.browserWriter, envelope)
  44. }
  45. func (l *audioStutterDebugLogger) Close() {
  46. l.mu.Lock()
  47. defer l.mu.Unlock()
  48. if l.serverWriter != nil {
  49. _ = l.serverWriter.Flush()
  50. }
  51. if l.serverFile != nil {
  52. _ = l.serverFile.Close()
  53. }
  54. if l.browserWriter != nil {
  55. _ = l.browserWriter.Flush()
  56. }
  57. if l.browserFile != nil {
  58. _ = l.browserFile.Close()
  59. }
  60. l.serverWriter = nil
  61. l.serverFile = nil
  62. l.browserWriter = nil
  63. l.browserFile = nil
  64. }
  65. func (l *audioStutterDebugLogger) ensureServerWriterLocked() error {
  66. if l.serverWriter != nil {
  67. return nil
  68. }
  69. if err := os.MkdirAll(audioStutterDebugDir, 0o755); err != nil {
  70. return err
  71. }
  72. path := filepath.Join(audioStutterDebugDir, serverStreamSummaryFile)
  73. f, err := os.OpenFile(path, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0o644)
  74. if err != nil {
  75. return err
  76. }
  77. l.serverFile = f
  78. l.serverWriter = bufio.NewWriterSize(f, 16*1024)
  79. return nil
  80. }
  81. func (l *audioStutterDebugLogger) ensureBrowserWriterLocked() error {
  82. if l.browserWriter != nil {
  83. return nil
  84. }
  85. if err := os.MkdirAll(audioStutterDebugDir, 0o755); err != nil {
  86. return err
  87. }
  88. path := filepath.Join(audioStutterDebugDir, browserAudioSummaryFile)
  89. f, err := os.OpenFile(path, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0o644)
  90. if err != nil {
  91. return err
  92. }
  93. l.browserFile = f
  94. l.browserWriter = bufio.NewWriterSize(f, 16*1024)
  95. return nil
  96. }
  97. func writeJSONLLineLocked(w *bufio.Writer, v any) error {
  98. b, err := json.Marshal(v)
  99. if err != nil {
  100. return err
  101. }
  102. if _, err := w.Write(b); err != nil {
  103. return err
  104. }
  105. if err := w.WriteByte('\n'); err != nil {
  106. return err
  107. }
  108. return w.Flush()
  109. }