Skip to content

Commit 81bdcac

Browse files
committed
Update CHANGELOG
1 parent 3088364 commit 81bdcac

File tree

2 files changed

+103
-1
lines changed

2 files changed

+103
-1
lines changed

CHANGELOG.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,22 @@ All notable changes to this project will be documented in this file. This change
88
- [Silero Voice Activity Detection model](./src/simulflow/vad/silero.clj) running through Onnx Runtime
99
- parameter `:vad/analyser` to all transport-in processor params to pass a VAD analyser like Silero to be ran on each new audio chunk. This is useful for logic that handles AI interruptions and improves turn taking.
1010
- Added malli schema for `audio-output-raw` frames
11+
- Added `simulflow.frame/send` helper function that outputs frames based on their appropriate direction - used now in most processors
12+
- **Twilio Integration**: Twilio serializer with `make-twilio-serializer` for WebSocket communication
13+
- **Audio Resampler Processor**: New processor for real-time sample rate conversion
14+
- **System Frame Router**: New `system-frame-router` processor for handling system message routing in complex flows
15+
- **Interruption Support**: New frame types for bot interruption handling: `control-interrupt-start`, `control-interrupt-stop`, `bot-interrupt`
1116

1217
### Changed
13-
- Made 16kHz PCM mono audio be the default audio that runs through the pipeline. All `audio-input-raw` frames that come through pe pipeline are expected to be this way.
18+
- Made **16kHz signed PCM mono** audio be the default audio that runs through the pipeline. All `audio-input-raw` frames that come through pe pipeline are expected to be this way.
1419
- **POTENTIAL BREAKING** `frame/audio-output-raw` are now expected to contain the sample-rate of the audio. The sample rate will be used for chunking and final output conversion. If you have custom Text to speech generators, you need to update them to use it.
20+
- Changed examples to use silero vad model for VAD instead of relying on Deepgram
21+
- **BREAKING** Processors that outputted `system-frames` (see [frame/system-frames](./src/simulflow/frame.clj) set for a list of system frames) will output them exclusively on `:sys-out` channel and normal frames on `:out` channel.
22+
- **Audio Processing**: Enhanced audio conversion with improved µ-law/PCM support and step-by-step conversion planning
1523

24+
### Fixed
25+
- **Audio Conversion**: Fixed critical bug in PCM 16kHz to Twilio µ-law 8kHz conversion where downsampling must occur before encoding conversion
26+
- **Transport**: Removed duplicate system frame passthrough that was causing duplicate frames
1627

1728
## [0.1.5-alpha] - 2025-07-24
1829

test/simulflow/frame_test.clj

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,3 +381,94 @@
381381
(let [frames (doall (repeatedly 100 #(frame/llm-text-chunk "test")))]
382382
(is (= 100 (count frames)))
383383
(is (every? frame/llm-text-chunk? frames))))))
384+
385+
(deftest test-send-function
386+
"Test the frame/send function for routing frames to appropriate channels"
387+
(testing "empty input"
388+
(is (= {} (frame/send))))
389+
390+
(testing "single regular frame"
391+
(let [audio-frame (frame/audio-input-raw test-audio-data)]
392+
(is (= {:out [audio-frame]}
393+
(frame/send audio-frame)))))
394+
395+
(testing "single system frame"
396+
(let [start-frame (frame/system-start true)]
397+
(is (= {:sys-out [start-frame]}
398+
(frame/send start-frame)))))
399+
400+
(testing "mixed frame types"
401+
(let [audio-frame (frame/audio-input-raw test-audio-data)
402+
start-frame (frame/system-start true)
403+
text-frame (frame/text-input {:text "hello"})]
404+
(is (= {:out [audio-frame text-frame]
405+
:sys-out [start-frame]}
406+
(frame/send audio-frame start-frame text-frame)))))
407+
408+
(testing "multiple system frames"
409+
(let [start-frame (frame/system-start true)
410+
stop-frame (frame/system-stop true)]
411+
(is (= {:sys-out [start-frame stop-frame]}
412+
(frame/send start-frame stop-frame)))))
413+
414+
(testing "multiple regular frames"
415+
(let [audio-frame (frame/audio-input-raw test-audio-data)
416+
text-frame (frame/text-input {:text "hello"})
417+
transcription-frame (frame/transcription {:text "world"})]
418+
(is (= {:out [audio-frame text-frame transcription-frame]}
419+
(frame/send audio-frame text-frame transcription-frame)))))
420+
421+
(testing "nil frames are filtered out"
422+
(let [audio-frame (frame/audio-input-raw test-audio-data)
423+
start-frame (frame/system-start true)]
424+
(is (= {:out [audio-frame]
425+
:sys-out [start-frame]}
426+
(frame/send nil audio-frame nil start-frame nil)))))
427+
428+
(testing "all nil frames"
429+
(is (= {} (frame/send nil nil nil))))
430+
431+
(testing "all system frame types are routed to sys-out"
432+
(let [frames [(frame/system-start true)
433+
(frame/system-stop true)
434+
(frame/system-config-change {:config {}})
435+
(frame/user-speech-start true)
436+
(frame/user-speech-stop true)
437+
(frame/bot-speech-start true)
438+
(frame/bot-speech-stop true)
439+
(frame/vad-user-speech-start true)
440+
(frame/vad-user-speech-stop true)
441+
(frame/bot-interrupt true)
442+
(frame/control-interrupt-start true)
443+
(frame/control-interrupt-stop true)]]
444+
(is (= {:sys-out frames}
445+
(apply frame/send frames)))))
446+
447+
(testing "all regular frame types are routed to out"
448+
(let [frames [(frame/audio-input-raw test-audio-data)
449+
(frame/audio-output-raw {:audio test-audio-data :sample-rate 16000})
450+
(frame/audio-tts-raw test-audio-data)
451+
(frame/transcription {:text "hello"})
452+
(frame/transcription-interim {:text "hello"})
453+
(frame/llm-context {:messages []})
454+
(frame/llm-text-chunk {:text "chunk"})
455+
(frame/text-input {:text "input"})]]
456+
(is (= {:out frames}
457+
(apply frame/send frames)))))
458+
459+
(testing "preserves frame order within channels"
460+
(let [frame1 (frame/audio-input-raw test-audio-data)
461+
frame2 (frame/text-input {:text "hello"})
462+
frame3 (frame/transcription {:text "world"})
463+
sys-frame1 (frame/system-start true)
464+
sys-frame2 (frame/system-stop true)]
465+
(is (= {:out [frame1 frame2 frame3]
466+
:sys-out [sys-frame1 sys-frame2]}
467+
(frame/send frame1 sys-frame1 frame2 sys-frame2 frame3)))))
468+
469+
(testing "large number of frames"
470+
(let [regular-frames (repeatedly 100 #(frame/text-input {:text (str "message-" (rand-int 1000))}))
471+
system-frames (repeatedly 50 #(frame/system-start true))]
472+
(let [result (apply frame/send (concat regular-frames system-frames))]
473+
(is (= 100 (count (:out result))))
474+
(is (= 50 (count (:sys-out result))))))))

0 commit comments

Comments
 (0)