diff --git a/src/io/alsa_io.ml b/src/io/alsa_io.ml index 5c3e25d1ca..080805b3b6 100644 --- a/src/io/alsa_io.ml +++ b/src/io/alsa_io.ml @@ -308,7 +308,8 @@ let () = ("", Lang.source_t k, None, None); ] ) ~return_t:k ~category:Lang.Output ~meth:Output.meth - ~descr:"Output the source's stream to an ALSA output device." + ~descr:"Output the source's stream to an ALSA output device." ~active:true + ~self_sync:true (fun p -> let e f v = f (List.assoc v p) in let bufferize = e Lang.to_bool "bufferize" in @@ -349,7 +350,7 @@ let () = Some "Alsa device to use" ); ] ) ~meth:(Start_stop.meth ()) ~return_t:k ~category:Lang.Input - ~descr:"Stream from an ALSA input device." + ~descr:"Stream from an ALSA input device." ~active:true ~self_sync:true (fun p -> let e f v = f (List.assoc v p) in let bufferize = e Lang.to_bool "bufferize" in diff --git a/src/io/ffmpeg_io.ml b/src/io/ffmpeg_io.ml index d32c3a2a15..413a6f8143 100644 --- a/src/io/ffmpeg_io.ml +++ b/src/io/ffmpeg_io.ml @@ -290,7 +290,8 @@ let register_input is_http = if is_http then ("input.http", "Create a http stream using ffmpeg") else ("input.ffmpeg", "Create a stream using ffmpeg") in - Lang.add_operator name ~descr ~category:Lang.Input + Lang.add_operator name ~descr ~category:Lang.Input ~active:true + ~self_sync:false ~clock_safe:false ( List.filter (fun (lbl, _, _, _) -> lbl <> "clock_safe") (Start_stop.active_source_proto ~fallible_opt:`Nope) diff --git a/src/io/gstreamer_io.ml b/src/io/gstreamer_io.ml index 52f690b2b2..916782c00b 100644 --- a/src/io/gstreamer_io.ml +++ b/src/io/gstreamer_io.ml @@ -342,7 +342,7 @@ let () = Lang.add_operator "output.gstreamer.audio" (output_proto ~return_t ~pipeline:"autoaudiosink") ~category:Lang.Output ~descr:"Output stream to a GStreamer pipeline." - ~return_t (fun p -> + ~self_sync:true ~return_t (fun p -> let clock_safe = Lang.to_bool (List.assoc "clock_safe" p) in let pipeline = Lang.to_string (List.assoc "pipeline" p) in let infallible = not (Lang.to_bool (List.assoc "fallible" p)) in @@ -373,7 +373,7 @@ let () = Lang.add_operator "output.gstreamer.video" (output_proto ~return_t ~pipeline:"videoconvert ! autovideosink") ~category:Lang.Output ~descr:"Output stream to a GStreamer pipeline." - ~return_t (fun p -> + ~self_sync:true ~return_t (fun p -> let clock_safe = Lang.to_bool (List.assoc "clock_safe" p) in let pipeline = Lang.to_string (List.assoc "pipeline" p) in let infallible = not (Lang.to_bool (List.assoc "fallible" p)) in @@ -420,7 +420,7 @@ let () = Some "Pushing buffers is blocking." ); ] ) ~category:Lang.Output ~descr:"Output stream to a GStreamer pipeline." - ~return_t + ~self_sync:true ~return_t (fun p -> let clock_safe = Lang.to_bool (List.assoc "clock_safe" p) in let pipeline = Lang.to_string (List.assoc "pipeline" p) in @@ -700,7 +700,7 @@ let () = ] in Lang.add_operator "input.gstreamer.audio_video" proto ~return_t - ~category:Lang.Input ~flags:[] + ~category:Lang.Input ~flags:[] ~self_sync:true ~meth: [ ( "pause", diff --git a/src/io/oss_io.ml b/src/io/oss_io.ml index bda6febdbd..75f9965fa7 100644 --- a/src/io/oss_io.ml +++ b/src/io/oss_io.ml @@ -146,7 +146,7 @@ let () = ("", Lang.source_t k, None, None); ] ) ~return_t:k ~category:Lang.Output - ~descr:"Output the source's stream to an OSS output device." + ~descr:"Output the source's stream to an OSS output device." ~self_sync:true (fun p -> let e f v = f (List.assoc v p) in let infallible = not (Lang.to_bool (List.assoc "fallible" p)) in @@ -174,8 +174,8 @@ let () = Some (Lang.string "/dev/dsp"), Some "OSS device to use." ); ] ) - ~meth:(Start_stop.meth ()) ~return_t:k ~category:Lang.Input - ~descr:"Stream from an OSS input device." + ~meth:(Start_stop.meth ()) ~return_t:k ~category:Lang.Input ~active:true + ~self_sync:true ~descr:"Stream from an OSS input device." (fun p -> let e f v = f (List.assoc v p) in let clock_safe = e Lang.to_bool "clock_safe" in diff --git a/src/io/portaudio_io.ml b/src/io/portaudio_io.ml index 76d0fd3c78..8266bfd12c 100644 --- a/src/io/portaudio_io.ml +++ b/src/io/portaudio_io.ml @@ -190,7 +190,8 @@ let () = Some "Length of a buffer in samples." ); ("", Lang.source_t k, None, None); ] ) - ~return_t:k ~category:Lang.Output ~meth:Output.meth + ~return_t:k ~category:Lang.Output ~meth:Output.meth ~active:true + ~self_sync:true ~descr:"Output the source's stream to a portaudio output device." (fun p -> let e f v = f (List.assoc v p) in @@ -219,8 +220,8 @@ let () = Some (Lang.int 256), Some "Length of a buffer in samples." ); ] ) - ~return_t:k ~category:Lang.Input ~meth:(Start_stop.meth ()) - ~descr:"Stream from a portaudio input device." + ~return_t:k ~category:Lang.Input ~meth:(Start_stop.meth ()) ~active:true + ~self_sync:true ~descr:"Stream from a portaudio input device." (fun p -> let e f v = f (List.assoc v p) in let buflen = e Lang.to_int "buflen" in diff --git a/src/io/pulseaudio_io.ml b/src/io/pulseaudio_io.ml index c647db305e..35091ad418 100644 --- a/src/io/pulseaudio_io.ml +++ b/src/io/pulseaudio_io.ml @@ -206,8 +206,9 @@ let () = in Lang.add_operator "output.pulseaudio" (Output.proto @ proto @ [("", Lang.source_t k, None, None)]) - ~return_t:k ~category:Lang.Output ~meth:Output.meth - ~descr:"Output the source's stream to a portaudio output device." + ~return_t:k ~category:Lang.Output ~meth:Output.meth ~active:true + ~self_sync:true + ~descr:"Output the source's stream to a Pulseaudio output device." (fun p -> let infallible = not (Lang.to_bool (List.assoc "fallible" p)) in let start = Lang.to_bool (List.assoc "start" p) in @@ -223,8 +224,8 @@ let () = (new output ~infallible ~on_start ~on_stop ~start ~kind p :> Output.output)); Lang.add_operator "input.pulseaudio" (Start_stop.active_source_proto ~fallible_opt:(`Yep false) @ proto) - ~return_t:k ~category:Lang.Input ~meth:(Start_stop.meth ()) - ~descr:"Stream from a portaudio input device." + ~return_t:k ~category:Lang.Input ~meth:(Start_stop.meth ()) ~active:true + ~self_sync:true ~descr:"Stream from a Pulseaudio input device." (fun p -> let kind = Source.Kind.of_kind kind in new input ~kind p) diff --git a/src/io/srt_io.ml b/src/io/srt_io.ml index 178eff0c80..cef90a9dcf 100644 --- a/src/io/srt_io.ml +++ b/src/io/srt_io.ml @@ -901,7 +901,8 @@ class input_caller ~hostname ~port ~kind ~max ~log_overfull ~payload_size let () = let kind = Lang.any in let return_t = Lang.kind_type_of_kind_format kind in - Lang.add_operator "input.srt" ~return_t ~category:Lang.Input + Lang.add_operator "input.srt" ~return_t ~category:Lang.Input ~active:true + ~self_sync:true ~meth:(meth () @ Start_stop.meth ()) ~descr:"Receive a SRT stream from a distant agent." ( common_options ~mode:`Listener diff --git a/src/io/udp_io.ml b/src/io/udp_io.ml index c55425aff6..936840630b 100644 --- a/src/io/udp_io.ml +++ b/src/io/udp_io.ml @@ -249,7 +249,7 @@ let () = let () = let kind = Lang.any in let k = Lang.kind_type_of_kind_format kind in - Lang.add_operator "input.udp" + Lang.add_operator "input.udp" ~active:true ~descr:"Input encoded data from UDP, without any control whatsoever." ~category:Lang.Input ~flags:[Lang.Hidden; Lang.Deprecated; Lang.Experimental] diff --git a/src/lang/lang.ml b/src/lang/lang.ml index 7a9fe21549..e48257f3ad 100644 --- a/src/lang/lang.ml +++ b/src/lang/lang.ml @@ -207,13 +207,29 @@ let doc_of_prototype_item ~generalized t d doc = | Some d -> Doc.trivial (print_value d) ); item -type doc_flag = Hidden | Deprecated | Experimental | Extra +type doc_flag = + | Hidden + | Deprecated + | Experimental + | Extra + | Active of bool + | Fallible of bool + | Clock_safe of bool + | Self_sync of bool let string_of_flag = function | Hidden -> "hidden" | Deprecated -> "deprecated" | Experimental -> "experimental" | Extra -> "extra" + | Active true -> "active" + | Active false -> "passive" + | Fallible true -> "fallible" + | Fallible false -> "infallible" + | Clock_safe true -> "clock-safe" + | Clock_safe false -> "clock-unsafe" + | Self_sync true -> "self-syncing" + | Self_sync false -> "not self-syncing" let builtin_type p t = T.make @@ -866,7 +882,17 @@ type 'a operator_method = string * scheme * string * ('a -> value) let add_operator = let _meth = meth in fun ~category ~descr ?(flags = []) ?(meth = ([] : 'a operator_method list)) - name proto ~return_t f -> + ?(active = false) ?(fallible = true) ?(self_sync = false) + ?(clock_safe = true) name proto ~return_t f -> + let flags = + [ + Active active; + Fallible fallible; + Self_sync self_sync; + Clock_safe clock_safe; + ] + @ flags + in let compare (x, _, _, _) (y, _, _, _) = match (x, y) with | "", "" -> 0 diff --git a/src/lang/lang.mli b/src/lang/lang.mli index 76e60e7811..5a630e960a 100644 --- a/src/lang/lang.mli +++ b/src/lang/lang.mli @@ -110,6 +110,10 @@ type doc_flag = | Deprecated (** The plugin should not be used. *) | Experimental (** The plugin should not considered as stable. *) | Extra (** Anything that is not part of the essential set of plugins. *) + | Active of bool + | Fallible of bool + | Clock_safe of bool + | Self_sync of bool (** Add an builtin to the language, high-level version for functions. *) val add_builtin : @@ -186,6 +190,10 @@ val add_operator : descr:string -> ?flags:doc_flag list -> ?meth:(< Source.source ; .. > as 'a) operator_method list -> + ?active:bool -> + ?fallible:bool -> + ?self_sync:bool -> + ?clock_safe:bool -> string -> proto -> return_t:t -> diff --git a/src/outputs/ao_out.ml b/src/outputs/ao_out.ml index 42c522780d..b630ca27b6 100644 --- a/src/outputs/ao_out.ml +++ b/src/outputs/ao_out.ml @@ -132,7 +132,7 @@ let () = Some "List of parameters, depends on the driver." ); ("", Lang.source_t return_t, None, None); ] ) - ~category:Lang.Output ~meth:Output.meth + ~category:Lang.Output ~meth:Output.meth ~active:true ~self_sync:true ~descr:"Output stream to local sound card using libao." ~return_t (fun p -> let clock_safe = Lang.to_bool (List.assoc "clock_safe" p) in diff --git a/src/outputs/bjack_out.ml b/src/outputs/bjack_out.ml index 0f1f61ab27..f1966a3228 100644 --- a/src/outputs/bjack_out.ml +++ b/src/outputs/bjack_out.ml @@ -128,6 +128,7 @@ let () = ("", Lang.source_t k, None, None); ] ) ~return_t:k ~category:Lang.Output ~descr:"Output stream to jack." + ~active:true ~clock_safe:true (fun p -> let source = List.assoc "" p in let clock_safe = Lang.to_bool (List.assoc "clock_safe" p) in diff --git a/src/outputs/pipe_output.ml b/src/outputs/pipe_output.ml index fc394d712f..e9de52c46f 100644 --- a/src/outputs/pipe_output.ml +++ b/src/outputs/pipe_output.ml @@ -118,7 +118,7 @@ class url_output p = let () = let return_t = Lang.univ_t () in Lang.add_operator "output.url" (url_proto return_t) ~return_t - ~category:Lang.Output + ~category:Lang.Output ~active:true ~descr: "Encode and let encoder handle data output. Useful with encoder with no \ expected output or to encode to files that need full control from the \ @@ -430,7 +430,7 @@ let () = let return_t = Lang.univ_t () in Lang.add_operator "output.external" (pipe_proto return_t "Process to pipe data to.") - ~return_t ~category:Lang.Output + ~return_t ~category:Lang.Output ~active:true ~meth: [ ( "reopen", diff --git a/src/sources/audio_gen.ml b/src/sources/audio_gen.ml index 49626955d4..2e8b80565b 100644 --- a/src/sources/audio_gen.ml +++ b/src/sources/audio_gen.ml @@ -43,7 +43,7 @@ class gen ~kind ~seek name g freq duration ampl = let add name g = let kind = Lang.internal in let return_t = Lang.kind_type_of_kind_format kind in - Lang.add_operator name ~category:Lang.Input + Lang.add_operator name ~category:Lang.Input ~fallible:false ~descr:("Generate a " ^ name ^ " wave.") ~return_t [ diff --git a/src/sources/bjack_in.ml b/src/sources/bjack_in.ml index 0879581aff..d5f70f9f3e 100644 --- a/src/sources/bjack_in.ml +++ b/src/sources/bjack_in.ml @@ -134,7 +134,7 @@ let () = Some "Jack server to connect to." ); ] ) ~meth:(Start_stop.meth ()) ~return_t ~category:Lang.Input - ~descr:"Get stream from jack." + ~descr:"Get stream from jack." ~active:true ~self_sync:true (fun p -> let clock_safe = Lang.to_bool (List.assoc "clock_safe" p) in let fallible = Lang.to_bool (List.assoc "fallible" p) in diff --git a/src/sources/blank.ml b/src/sources/blank.ml index 24046809e1..fc4e9310fb 100644 --- a/src/sources/blank.ml +++ b/src/sources/blank.ml @@ -72,7 +72,7 @@ class blank ~kind duration = let () = let kind = Lang.internal in let return_t = Lang.kind_type_of_kind_format kind in - Lang.add_operator "blank" ~category:Lang.Input + Lang.add_operator "blank" ~category:Lang.Input ~fallible:false ~descr:"Produce silence and blank images." ~return_t [ ( "duration", diff --git a/src/sources/noise.ml b/src/sources/noise.ml index 4a77a4a990..2d6443bfbf 100644 --- a/src/sources/noise.ml +++ b/src/sources/noise.ml @@ -46,7 +46,7 @@ class noise ~kind duration = let () = let kind = Lang.internal in let return_t = Lang.kind_type_of_kind_format kind in - Lang.add_operator "noise" ~category:Lang.Input + Lang.add_operator "noise" ~category:Lang.Input ~fallible:false ~descr:"Generate audio white noise." [ ( "duration", diff --git a/src/sources/request_simple.ml b/src/sources/request_simple.ml index 73b55a5b19..6d277b2c66 100644 --- a/src/sources/request_simple.ml +++ b/src/sources/request_simple.ml @@ -92,7 +92,7 @@ let log = Log.make ["single"] let () = let kind = Lang.any in let return_t = Lang.kind_type_of_kind_format kind in - Lang.add_operator "single" ~category:Lang.Input + Lang.add_operator "single" ~category:Lang.Input ~fallible:false ~descr: "Loop on a request. It never fails if the request is static, meaning \ that it can be fetched once. Typically, http, ftp, say requests are \ @@ -118,7 +118,7 @@ let () = let () = let kind = Lang.any in let t = Lang.kind_type_of_kind_format kind in - Lang.add_operator "single.infallible" ~category:Lang.Input + Lang.add_operator "single.infallible" ~category:Lang.Input ~fallible:false ~flags:[Lang.Hidden] ~descr: "Loops on a request, which has to be ready and should be persistent. \ diff --git a/src/synth/keyboard.ml b/src/synth/keyboard.ml index 0afa47b0a0..48e422b1f7 100644 --- a/src/synth/keyboard.ml +++ b/src/synth/keyboard.ml @@ -54,7 +54,7 @@ let note_of_char c = array_index c + 72 class keyboard ~kind = object (self) - inherit Source.active_source ~name:"input.keyboard" kind + inherit Source.source ~name:"input.keyboard" kind method stype = Source.Infallible @@ -140,7 +140,7 @@ let () = let kind = Lang.midi_n 1 in let return_t = Lang.kind_type_of_kind_format kind in Lang.add_operator "input.keyboard" [] ~return_t ~category:Lang.Input - ~flags:[Lang.Hidden; Lang.Experimental] + ~fallible:false ~flags:[Lang.Hidden; Lang.Experimental] ~descr:"Play notes from the keyboard." (fun _ -> let kind = Source.Kind.of_kind kind in (new keyboard ~kind :> Source.source)) diff --git a/src/synth/keyboard_sdl.ml b/src/synth/keyboard_sdl.ml index f6a7f5f735..2ea1e86cc9 100644 --- a/src/synth/keyboard_sdl.ml +++ b/src/synth/keyboard_sdl.ml @@ -85,8 +85,7 @@ let note_of_char c = class keyboard ~kind velocity = let () = Sdl_utils.init [Sdl.Init.events; Sdl.Init.video] in object (self) - inherit - Source.active_source ~name:"input.keyboard.sdl" (Source.Kind.of_kind kind) + inherit Source.source ~name:"input.keyboard.sdl" (Source.Kind.of_kind kind) method stype = Source.Infallible diff --git a/src/tools/doc.ml b/src/tools/doc.ml index d34079985f..88bf30b620 100644 --- a/src/tools/doc.ml +++ b/src/tools/doc.ml @@ -202,8 +202,15 @@ let print_functions_md ~extra (doc : item) print_string = let s = if s = "" then "" else ": " ^ s in Printf.ksprintf print_string "- `%s` (of type `%s`)%s\n" l t s) methods ); - if List.mem "experimental" flags then - print_string "\nThis function is experimental.\n"; + (let rec concat = function + | [] -> "" + | [x] -> x + | [x; y] -> x ^ " and " ^ y + | x :: l -> x ^ ", " ^ concat l + in + let flags = concat flags in + if flags <> "" then + Printf.ksprintf print_string "\nThis function is %s.\n" flags); print_string "\n" )) ff) by_cat