diff --git a/CHANGES.md b/CHANGES.md index 41dde46b9b..356d6d52b4 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -79,6 +79,7 @@ Changed: - Added `settings.protocol.youtube_dl.timeout` to specify timeout when using `youtube-dl` protocol (#2827). Use `yt-dlp` as default binary for the protocol. +- The `sleeper` operator is now scripted (#2899). Fixed: diff --git a/src/core/dune b/src/core/dune index bd0a3d3599..5133c8f385 100644 --- a/src/core/dune +++ b/src/core/dune @@ -216,7 +216,6 @@ sha1 shebang shine_format - sleeper source speex_format srt_decoder diff --git a/src/core/operators/sleeper.ml b/src/core/operators/sleeper.ml deleted file mode 100644 index 59c5254822..0000000000 --- a/src/core/operators/sleeper.ml +++ /dev/null @@ -1,87 +0,0 @@ -(***************************************************************************** - - Liquidsoap, a programmable audio stream generator. - Copyright 2003-2023 Savonet team - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details, fully stated in the COPYING - file at the root of the liquidsoap distribution. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - - *****************************************************************************) - -open Source - -class sleeper source delay random = - let dt = AFrame.duration () in - object - inherit operator [source] - val mutable lived = 0. - method stype = source#stype - method remaining = source#remaining - method seek = source#seek - method is_ready = source#is_ready - method abort_track = source#abort_track - method self_sync = source#self_sync - val mutable freeze = false - method freeze = freeze <- true - - method private get_frame buf = - source#get buf; - let delay = delay +. Random.float random in - Thread.delay delay; - lived <- lived +. max dt delay; - if freeze then - while true do - Thread.delay 60. - done - end - -let _ = - let freeze s = - Lang.val_fun [] (fun _ -> - s#freeze; - Lang.unit) - in - let frame_t = Lang.frame_t (Lang.univ_t ()) Frame.Fields.empty in - Lang.add_operator "sleeper" - [ - ( "delay", - Lang.float_t, - Some (Lang.float 1.), - Some - "Amount of time to sleep, in seconds per second of produced audio \ - data." ); - ( "random", - Lang.float_t, - Some (Lang.float 0.), - Some "Maximal amount of time randomly added to the delay parameter." ); - ("", Lang.source_t frame_t, None, None); - ] - ~return_t:frame_t - ~descr:"Sleep at each frame. Useful for emulating network delays, etc." - ~category:`Testing ~flags:[`Experimental] - ~meth: - [ - ( "freeze", - ([], Lang.fun_t [] Lang.unit_t), - "Freeze the main thread.", - freeze ); - ] - (fun p -> - let delay = Lang.to_float (List.assoc "delay" p) in - let delay = AFrame.duration () *. delay in - let random = Lang.to_float (List.assoc "random" p) in - let random = AFrame.duration () *. random in - let src = Lang.to_source (List.assoc "" p) in - new sleeper src delay random) diff --git a/src/libs/stdlib.liq b/src/libs/stdlib.liq index 5979f1b4e7..ef44250190 100644 --- a/src/libs/stdlib.liq +++ b/src/libs/stdlib.liq @@ -42,6 +42,7 @@ %include "profiler.liq" %include "io.liq" %include "runtime.liq" +%include "testing.liq" %include "liquidsoap.liq" set_settings_ref(settings) diff --git a/src/libs/testing.liq b/src/libs/testing.liq new file mode 100644 index 0000000000..c0fec6d013 --- /dev/null +++ b/src/libs/testing.liq @@ -0,0 +1,24 @@ +# Sleep regularly, thus inducing delays in the sound production. This is mainly +# useful for emulating network delays or sources which are slow to produce data, +# and thus test bufferization and robustness of scripts. +# @category Source / Testing +# @flag experimental +# @param ~every How often we should sleep (in seconds, 0 means every frame). +# @param ~delay Delay introduced (in seconds). +# @param ~delay_random Maximum amount of time randomly added to the delay (in seconds). +# @param s Source in which the delays should be introduced. +# @method frozen The stream production is frozen while set to `true`. +def sleeper(~every=0.5, ~delay=0.1, ~delay_random=0., s) + last = ref(0.) + frozen = ref(false) + def f() + now = source.time(s) + while frozen() do sleep(0.1) end + if now + every >= last() then + last := now + sleep(delay + random.float(max=delay_random)) + end + end + s = source.on_frame(s,f) + s.{frozen = frozen} +end