|
19 | 19 | (is (= current-time (::sut/last-send-time new-state))) |
20 | 20 | (is (= 1 (count (:sys-out output)))) |
21 | 21 | (is (frame/bot-speech-start? (first (:sys-out output)))) |
22 | | - (is (= 1 (count (:audio-write output)))) |
23 | | - (is (= 16000 (:sample-rate (first (:audio-write output))))))) |
| 22 | + (is (= 1 (count (::sut/audio-write output)))) |
| 23 | + (is (= 16000 (:sample-rate (first (::sut/audio-write output))))))) |
24 | 24 |
|
25 | 25 | (testing "process-realtime-out-audio-frame with different sample rate" |
26 | 26 | (let [state {::sut/speaking? false |
|
29 | 29 | frame (frame/audio-output-raw {:audio (byte-array [1 2 3]) :sample-rate 24000}) |
30 | 30 | current-time 2000 |
31 | 31 | [new-state output] (sut/process-realtime-out-audio-frame state frame current-time) |
32 | | - command (first (:audio-write output))] |
33 | | - (is (= (update command :data vec) {:command :write-audio |
| 32 | + command (first (::sut/audio-write output))] |
| 33 | + (is (= (update command :data vec) {:command/kind :command/write-audio |
34 | 34 | :data [1, 2, 3] |
35 | 35 | :delay-until 2000 |
36 | 36 | :sample-rate 24000})) |
37 | 37 |
|
38 | 38 | (is (true? (::sut/speaking? new-state))) |
39 | | - (is (= 1 (count (:audio-write output)))) |
40 | | - (is (= 24000 (:sample-rate (first (:audio-write output)))))))) |
| 39 | + (is (= 1 (count (::sut/audio-write output)))) |
| 40 | + (is (= 24000 (:sample-rate (first (::sut/audio-write output)))))))) |
41 | 41 |
|
42 | 42 | (deftest realtime-out-transform-test |
43 | 43 | (testing "transform with audio frame" |
|
48 | 48 | (is (true? (::sut/speaking? new-state))) |
49 | 49 | (is (= 1 (count (:sys-out output)))) |
50 | 50 | (is (frame/bot-speech-start? (first (:sys-out output)))) |
51 | | - (is (= 1 (count (:audio-write output)))))) |
| 51 | + (is (= 1 (count (::sut/audio-write output)))))) |
52 | 52 |
|
53 | 53 | (testing "transform with timer tick (stop speaking)" |
54 | 54 | (let [state {::sut/speaking? true |
55 | 55 | ::sut/last-send-time 1000 |
56 | 56 | :activity-detection/silence-threshold-ms 200} |
57 | 57 | timer-frame {:timer/tick true :timer/timestamp 1300} |
58 | | - [new-state output] (sut/base-realtime-out-transform state :timer-out timer-frame)] |
| 58 | + [new-state output] (sut/base-realtime-out-transform state ::sut/timer-out timer-frame)] |
59 | 59 |
|
60 | 60 | (is (false? (::sut/speaking? new-state))) |
61 | 61 | (is (= 1 (count (:sys-out output)))) |
62 | | - (is (frame/bot-speech-stop? (first (:sys-out output))))))) |
| 62 | + (is (frame/bot-speech-stop? (first (:sys-out output)))))) |
| 63 | + (testing "Handling of interruptions" |
| 64 | + (testing "Sends drain-queue command when an interruption starts" |
| 65 | + (let [state {::sut/speaking? true |
| 66 | + ::sut/last-send-time 1000 |
| 67 | + :activity-detection/silence-threshold-ms 200} |
| 68 | + [new-state output] (sut/base-realtime-out-transform state :sys-in (frame/control-interrupt-start true))] |
| 69 | + (is (true? (:pipeline/interrupted? new-state))) |
| 70 | + (is (= (first (::sut/command output)) {:command/kind :command/drain-queue})))) |
| 71 | + |
| 72 | + (testing "Sends drain-queue command when an interruption starts" |
| 73 | + (let [state {::sut/speaking? false |
| 74 | + ::sut/last-send-time 1000 |
| 75 | + :pipeline/interrupted? true |
| 76 | + :activity-detection/silence-threshold-ms 200} |
| 77 | + [new-state output] (sut/base-realtime-out-transform state :sys-in (frame/control-interrupt-stop true))] |
| 78 | + (is (false? (:pipeline/interrupted? new-state))) |
| 79 | + (is (nil? output)))) |
| 80 | + |
| 81 | + (testing "audio-output frames are dropped when the pipeline is interrupted" |
| 82 | + (let [state {::sut/speaking? false :audio.out/sending-interval 25 :pipeline/interrupted? true} |
| 83 | + frame (frame/audio-output-raw {:audio (byte-array [1 2 3]) :sample-rate 16000}) |
| 84 | + [new-state output] (sut/base-realtime-out-transform state :in frame)] |
| 85 | + |
| 86 | + (is (= state new-state)) |
| 87 | + (is (nil? output)))))) |
63 | 88 |
|
64 | 89 | (deftest test-realtime-speakers-out-describe |
65 | 90 | (testing "describe function returns correct structure" |
|
104 | 129 | ::sut/last-send-time 1000 |
105 | 130 | :activity-detection/silence-threshold-ms 200} |
106 | 131 | timer-frame {:timer/tick true :timer/timestamp 1300} ; 300ms silence > 200ms threshold |
107 | | - [new-state output] (sut/base-realtime-out-transform state :timer-out timer-frame)] |
| 132 | + [new-state output] (sut/base-realtime-out-transform state ::sut/timer-out timer-frame)] |
108 | 133 |
|
109 | 134 | (is (false? (::sut/speaking? new-state))) |
110 | 135 | (is (= 1 (count (:sys-out output)))) |
|
142 | 167 | frame (frame/audio-output-raw {:audio (byte-array [1 2 3]) :sample-rate 16000})] |
143 | 168 | (with-redefs [u/mono-time (constantly 1000)] |
144 | 169 | (let [[_ output] (sut/base-realtime-out-transform state :in frame) |
145 | | - audio-write (first (:audio-write output))] |
146 | | - (is (= :write-audio (:command audio-write))) |
| 170 | + audio-write (first (::sut/audio-write output))] |
| 171 | + (is (= :command/write-audio (:command/kind audio-write))) |
147 | 172 | (is (= [99 99 99] (:frame/data (:data audio-write)))))))) ; Should use serialized data |
148 | 173 |
|
149 | 174 | (testing "transform without serializer" |
|
154 | 179 | frame (frame/audio-output-raw {:audio (byte-array [1 2 3]) :sample-rate 16000})] |
155 | 180 | (with-redefs [u/mono-time (constantly 1000)] |
156 | 181 | (let [[_ output] (sut/base-realtime-out-transform state :in frame) |
157 | | - audio-write (first (:audio-write output))] |
158 | | - (is (= :write-audio (:command audio-write))) |
| 182 | + audio-write (first (::sut/audio-write output))] |
| 183 | + (is (= :command/write-audio (:command/kind audio-write))) |
159 | 184 | (is (= [1 2 3] (vec (:data audio-write))))))))) |
160 | 185 |
|
161 | 186 | (deftest test-realtime-speakers-out-edge-cases |
|
225 | 250 | :timer/timestamp (+ (::sut/last-send-time state2) 1000)} |
226 | 251 | [state3 output3] (sut/base-realtime-out-transform |
227 | 252 | (assoc state2 :activity-detection/silence-threshold-ms 500) |
228 | | - :timer-out timer-frame)] |
| 253 | + ::sut/timer-out timer-frame)] |
229 | 254 |
|
230 | 255 | ;; Verify state progression |
231 | 256 | (is (false? (::sut/speaking? initial-state))) |
|
249 | 274 | ::sut/now current-time} |
250 | 275 | frame (frame/audio-output-raw {:audio (byte-array [1 2 3]) :sample-rate 16000}) |
251 | 276 | [new-state output] (sut/base-realtime-out-transform state :in frame) |
252 | | - audio-write (first (:audio-write output)) |
| 277 | + audio-write (first (::sut/audio-write output)) |
253 | 278 | [next-state] (sut/base-realtime-out-transform (assoc new-state ::sut/now 1020) :in frame) |
254 | 279 | [next-state2] (sut/base-realtime-out-transform (assoc next-state ::sut/now 1025) :in frame)] |
255 | 280 |
|
|
278 | 303 |
|
279 | 304 | ;; Timer tick over threshold |
280 | 305 | timer-frame-over {:timer/tick true :timer/timestamp (+ base-time 350)} |
281 | | - [state-over output-over] (sut/base-realtime-out-transform state :timer-out timer-frame-over)] |
| 306 | + [state-over output-over] (sut/base-realtime-out-transform state ::sut/timer-out timer-frame-over)] |
282 | 307 |
|
283 | 308 | ;; Under threshold: still speaking |
284 | 309 | (is (true? (::sut/speaking? state-under))) |
|
0 commit comments