Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New streaming model #3577

Merged
merged 135 commits into from
Dec 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
135 commits
Select commit Hold shift + click to select a range
300b239
Convert frame to immutable.
toots Nov 15, 2023
c5b95dd
Progress.
toots Nov 29, 2023
b442424
More progress.
toots Nov 29, 2023
b1f90bc
Add track mark.
toots Nov 29, 2023
ffd8181
Tentatively migrate amplify.
toots Nov 30, 2023
8fcbf19
Convert muxer.
toots Nov 30, 2023
c225c88
Cleanup
toots Nov 30, 2023
547f6d0
Convert blank!
toots Nov 30, 2023
0bb5c85
Convert more.
toots Nov 30, 2023
70a5716
Port accelerate.
toots Nov 30, 2023
6974af3
Convert add.
toots Dec 1, 2023
fcc4e54
Convert generated.
toots Dec 1, 2023
8484bd2
Convert input.harbor
toots Dec 1, 2023
d70d726
Convert available.
toots Dec 1, 2023
c9bc816
Restore more.
toots Dec 1, 2023
232e845
Restore switch and sequence!
toots Dec 1, 2023
ba62ffb
More
toots Dec 2, 2023
0bfe909
More conversion.
toots Dec 3, 2023
14f528f
Remove content blit.
toots Dec 3, 2023
50450e3
More
toots Dec 3, 2023
b955b76
Rename frame to empty frame.
toots Dec 3, 2023
81ec278
Be smarter about mutable content.
toots Dec 4, 2023
8ef3449
Convert.
toots Dec 4, 2023
d42bc4b
Convert.
toots Dec 4, 2023
a628480
bunch more
toots Dec 4, 2023
50d9745
Some work on cross.
toots Dec 4, 2023
b8e361f
Fix on_end.
toots Dec 6, 2023
2479491
Factor, cleanup up cross.
toots Dec 6, 2023
951ff23
Rework logic around expected cross duration.
toots Dec 6, 2023
5cd7cb8
Convert.
toots Dec 6, 2023
804d873
Convert cue_point and ffmpeg.
toots Dec 6, 2023
3a94114
More conversion.
toots Dec 6, 2023
d799a23
Harden stuff.
toots Dec 6, 2023
301d14e
More hardening.
toots Dec 6, 2023
3fb8b83
Fix this.
toots Dec 6, 2023
74470b2
More
toots Dec 7, 2023
ab2eab2
More
toots Dec 7, 2023
ac67a8a
More
toots Dec 8, 2023
05de19f
Getting there
toots Dec 8, 2023
04362ee
Almost there!
toots Dec 8, 2023
ec05a04
Add this.
toots Dec 8, 2023
20007cd
Fix this.
toots Dec 8, 2023
6b4283f
Fix.
toots Dec 8, 2023
0463fe0
Try this.
toots Dec 8, 2023
a703d75
Cleanup core tests.
toots Dec 8, 2023
6b141c3
Fix blank implementation.
toots Dec 8, 2023
81aa950
Fix this.
toots Dec 9, 2023
afb461f
Adapt to new API
toots Dec 9, 2023
7f2d067
Remove deduplicate option in cross: does not seem needed anymore!
toots Dec 9, 2023
f44a0bb
Fix this test.
toots Dec 9, 2023
17563e5
Update.
toots Dec 9, 2023
77b93b5
Remaining in sequence,
toots Dec 9, 2023
9ce2c8d
More fix.
toots Dec 9, 2023
3a93750
Fix source.{dump,drop}
toots Dec 9, 2023
95717ef
Fix merge metadata
toots Dec 9, 2023
b687c92
More fixes.
toots Dec 9, 2023
0100403
Enhance remaining for the ffmpeg decoder, don't rely on remaining for
toots Dec 10, 2023
6782927
optimise get_mutable_field.
toots Dec 10, 2023
758709e
Fix compress.
toots Dec 11, 2023
58294da
Cleanup map_metadata, remove use of is_partial.
toots Dec 11, 2023
3075539
Simplify
toots Dec 11, 2023
3697d9d
More fixes.
toots Dec 11, 2023
f919bd2
Fix
toots Dec 11, 2023
fb16cbd
More fixes.
toots Dec 11, 2023
b75aab4
Fix blank logic.
toots Dec 12, 2023
409fd7d
Swap the queue implementation.
toots Dec 14, 2023
5a78bd8
Cleanup add.
toots Dec 14, 2023
0a6563b
Disable optimized content mutation for now.
toots Dec 15, 2023
828028f
Add initial track mark when switching from buffering.
toots Dec 15, 2023
bf62f04
Revert this.
toots Dec 15, 2023
a71d868
Cleanup is_ready/can_generate_frame with Start_stop.active_source.
toots Dec 15, 2023
a440db1
Don't do anything in has_ticked if close is not ready.
toots Dec 15, 2023
ca75614
Better code.
toots Dec 16, 2023
bf2d118
Tighten up.
toots Dec 16, 2023
37a978e
More cleanup.
toots Dec 17, 2023
ebe5f86
Fix image decoder.
toots Dec 17, 2023
2fe13ed
Fix rotate test.
toots Dec 17, 2023
e10b5b3
Properly call on track.
toots Dec 17, 2023
3fd59c1
Fix remainder and initial generation.
toots Dec 18, 2023
c14c610
Rewrite test.
toots Dec 18, 2023
0f0fd96
Fix.
toots Dec 18, 2023
da53dd2
Fix logic
toots Dec 18, 2023
fe667f0
Recheck predicate in switch
toots Dec 19, 2023
37cd045
Fix this one.
toots Dec 19, 2023
f15414d
Revert on track.
toots Dec 19, 2023
3eff316
Properly kill timed out processes.
toots Dec 19, 2023
7d0036d
Better.
toots Dec 19, 2023
165513f
Better.
toots Dec 19, 2023
a960c19
Manual track mark for now.
toots Dec 19, 2023
24ca3db
Explicit end of track, wait until at least one source has started to
toots Dec 19, 2023
1c4e9f9
No more -1
toots Dec 19, 2023
6034afc
Better stacktrace.
toots Dec 19, 2023
9a6ee4a
Cleanup on_end
toots Dec 19, 2023
79f5b70
Fix before/after frame type.
toots Dec 19, 2023
385ac78
More stuff.
toots Dec 19, 2023
79772e7
Don't trigger on_end on initial track.
toots Dec 19, 2023
6dcf980
Fix.
toots Dec 19, 2023
cd94d0a
Fix dyn source null case.
toots Dec 19, 2023
dbe3a5d
More fix.
toots Dec 20, 2023
f3d3454
Be specific that we want a reselect after a given position.
toots Dec 20, 2023
f9b44dc
-1 is back..
toots Dec 20, 2023
3d80ed6
Better.
toots Dec 20, 2023
98722da
Force reselect in seq.
toots Dec 20, 2023
bb9b938
This is legit
toots Dec 20, 2023
54eae6d
Fix
toots Dec 20, 2023
e4c36c6
Fix this one too.
toots Dec 20, 2023
2f8d40c
Add windows deps.
toots Dec 21, 2023
f6a22f5
Some doc.
toots Dec 22, 2023
f36c4d9
Fix
toots Dec 22, 2023
d904414
Make sure input clock ticks at least once per output clock tick to cl…
toots Dec 23, 2023
b4c3bbc
Merge remote-tracking branch 'origin' into new-streaming
toots Dec 24, 2023
0b0f0ff
Revert this.
toots Dec 24, 2023
7029369
Bring this back.
toots Dec 24, 2023
ce84853
Cleanup
toots Dec 24, 2023
9eb56ee
Cleanup
toots Dec 24, 2023
ecc4602
Cleanup
toots Dec 24, 2023
6074162
Cleanup
toots Dec 24, 2023
2459aab
Revert this.
toots Dec 24, 2023
1d6d2df
Cleanup
toots Dec 24, 2023
ac49428
Don't instantiate a new frame in merge_metadata.
toots Dec 25, 2023
164fc06
Rename.
toots Dec 25, 2023
1f93980
Simplify alsa in
toots Dec 25, 2023
f4ae337
Cleanup.
toots Dec 25, 2023
f953d6f
Merge branch 'main' into new-streaming
toots Dec 25, 2023
e8fa095
Merge branch 'main' into new-streaming
toots Dec 25, 2023
1a49565
Unify source preparation, make proposed source be taken in priority.
toots Dec 26, 2023
63e2be7
No lock.
toots Dec 26, 2023
283819a
Don't force reselection after reselection has been tried.
toots Dec 26, 2023
0cd2c78
Exchange.
toots Dec 26, 2023
37ecade
Get rid of frame_video_length.
toots Dec 26, 2023
f2834f6
Don't reselect on new track.
toots Dec 26, 2023
d7f0854
Better logic.
toots Dec 26, 2023
37bbf8b
On wake up.
toots Dec 26, 2023
d8fa44c
Doc.
toots Dec 27, 2023
1ba157a
Not ready until this.
toots Dec 27, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/opam/liquidsoap-core-windows.opam
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ depends: [
"mm-windows" {>= "0.8.4"}
"re-windows" {>= "1.11.0"}
"cry-windows" {>= "1.0.1"}
"saturn_lockfree-windows" {>= "0.4.1"}
"sedlex" {>= "3.2"}
"sedlex-windows" {>= "3.2"}
"menhir"
Expand Down
3 changes: 3 additions & 0 deletions .github/scripts/build-posix.sh
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ cd /tmp/liquidsoap-full/liquidsoap

./.github/scripts/checkout-deps.sh

opam update
opam install -y saturn_lockfree

cd /tmp/liquidsoap-full

sed -e 's@ocaml-gstreamer@#ocaml-gstreamer@' -i PACKAGES
Expand Down
8 changes: 2 additions & 6 deletions doc/content/liq/radiopi.liq
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,6 @@ def crossfade(
~medium=-32.,
~margin=4.,
~width=2.,
~conservative=false,
s
) =
fade_out = fun (s) -> fade.out(type="sin", duration=fade_out, s)
Expand Down Expand Up @@ -280,9 +279,7 @@ def crossfade(
end
end

cross(
width=width, duration=start_next, conservative=conservative, transition, s
)
cross(width=width, duration=start_next, transition, s)
end

# Create a radiopilote-driven source
Expand Down Expand Up @@ -311,8 +308,7 @@ def channel_radiopilote(~skip=true, name) =
request.create(ret)
end

# Create the dynamic source. Set conservative to true to queue several songs
# in advance.
# Create the dynamic source.
s = request.dynamic(id="dyn_" ^ name, req, timeout=60.)

# Apply normalization using replaygain information.
Expand Down
1 change: 1 addition & 0 deletions dune-project
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
uri
fileutils
menhirLib
(saturn_lockfree (>= 0.4.1))
(metadata (>= 0.2.0))
dune-build-info
(liquidsoap-lang (= :version))
Expand Down
1 change: 1 addition & 0 deletions liquidsoap-core.opam
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ depends: [
"uri"
"fileutils"
"menhirLib"
"saturn_lockfree" {>= "0.4.1"}
"metadata" {>= "0.2.0"}
"dune-build-info"
"liquidsoap-lang" {= version}
Expand Down
2 changes: 1 addition & 1 deletion src/core/builtins/builtins_ffmpeg_bitstream_filters.ml
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ let register_filters () =
(fun pos -> Generator.add_track_mark ~pos generator)
(List.filter
(fun x -> x < Lazy.force Frame.size)
(Frame.breaks frame));
(Frame.track_marks frame));
process frame
| `Flush -> flush ()
in
Expand Down
2 changes: 1 addition & 1 deletion src/core/builtins/builtins_ffmpeg_decoder.ml
Original file line number Diff line number Diff line change
Expand Up @@ -460,7 +460,7 @@ let mk_decoder mode =
(Frame.get_all_metadata frame);
List.iter
(fun pos -> Generator.add_track_mark ~pos generator)
(List.filter (fun x -> x < size) (Frame.breaks frame));
(List.filter (fun x -> x < size) (Frame.track_marks frame));
decode_frame (`Frame frame)
| `Flush -> decode_frame `Flush
in
Expand Down
2 changes: 1 addition & 1 deletion src/core/builtins/builtins_ffmpeg_encoder.ml
Original file line number Diff line number Diff line change
Expand Up @@ -512,7 +512,7 @@ let mk_encoder mode =
(Frame.get_all_metadata frame);
List.iter
(fun pos -> Generator.add_track_mark ~pos generator)
(List.filter (fun x -> x < size) (Frame.breaks frame));
(List.filter (fun x -> x < size) (Frame.track_marks frame));
encode_frame (`Frame frame)
| `Flush -> encode_frame `Flush
in
Expand Down
2 changes: 1 addition & 1 deletion src/core/builtins/builtins_ffmpeg_filters.ml
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ let is_ready graph =
| _ -> ());
(not graph.failed)
&& Queue.fold
(fun cur (s : Source.source) -> cur && s#is_ready ())
(fun cur (s : Source.source) -> cur && s#is_ready)
true graph.graph_inputs

let pull graph =
Expand Down
8 changes: 4 additions & 4 deletions src/core/builtins/builtins_prometheus.ml
Original file line number Diff line number Diff line change
Expand Up @@ -170,12 +170,12 @@ let source_monitor ~prefix ~label_names ~labels ~window s =
()
in
let sleep () = () in
let get_frame ~start_time ~end_time ~start_position ~end_position
~is_partial:_ ~metadata:_ =
let generate_frame ~start_time ~end_time ~length ~has_track_mark:_ ~metadata:_
=
last_start_time := start_time;
last_end_time := end_time;
Prometheus.Gauge.set last_data end_time;
let encoded_time = Frame.seconds_of_main (end_position - start_position) in
let encoded_time = Frame.seconds_of_main length in
let latency = (end_time -. start_time) /. encoded_time in
add_input_latency latency
in
Expand All @@ -188,7 +188,7 @@ let source_monitor ~prefix ~label_names ~labels ~window s =
{
Source.wake_up;
sleep;
get_frame;
generate_frame;
before_output = (fun _ -> ());
after_output;
}
Expand Down
24 changes: 17 additions & 7 deletions src/core/builtins/builtins_source.ml
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ let _ =
available), or currently streaming."
[("", Lang.source_t (Lang.univ_t ()), None, None)]
Lang.bool_t
(fun p -> Lang.bool ((Lang.to_source (List.assoc "" p))#is_ready ()))
(fun p -> Lang.bool (Lang.to_source (List.assoc "" p))#is_ready)

let _ =
Lang.add_builtin ~base:source "is_up" ~category:`System
Expand Down Expand Up @@ -138,8 +138,7 @@ let _ =
else 0
in
let frame_position = Lazy.force Frame.duration *. float ticks in
let in_frame_position = Frame.seconds_of_main (Frame.position s#memo) in
Lang.float (frame_position +. in_frame_position))
Lang.float frame_position)

let _ =
Lang.add_builtin ~base:source "on_shutdown" ~category:(`Source `Liquidsoap)
Expand Down Expand Up @@ -200,9 +199,19 @@ let _ =
(fun p ->
let module Time = (val Clock.time_implementation () : Liq_time.T) in
let open Time in
let stopped = ref false in
let proto =
let p = Pipe_output.file_proto (Lang.univ_t ()) in
List.filter_map (fun (l, _, v, _) -> Option.map (fun v -> (l, v)) v) p
List.filter_map
(fun (l, _, v, _) ->
if l <> "on_stop" then Option.map (fun v -> (l, v)) v
else
Some
( "on_stop",
Lang.val_fun [] (fun _ ->
stopped := true;
Lang.unit) ))
p
in
let proto = ("fallible", Lang.bool true) :: proto in
let s = Lang.to_source (Lang.assoc "" 3 p) in
Expand All @@ -214,7 +223,7 @@ let _ =
Clock.unify ~pos:fo#pos fo#clock (Clock.create_known clock);
ignore (clock#start_outputs (fun _ -> true) ());
log#info "Start dumping source (ratio: %.02fx)" ratio;
while (not (Atomic.get should_stop)) && fo#is_ready () do
while (not (Atomic.get should_stop)) && not !stopped do
let start_time = Time.time () in
clock#end_tick;
sleep_until (start_time |+| latency)
Expand Down Expand Up @@ -242,11 +251,12 @@ let _ =
let module Time = (val Clock.time_implementation () : Liq_time.T) in
let open Time in
let s = List.assoc "" p |> Lang.to_source in
let stopped = ref false in
let o =
new Output.dummy
~infallible:false
~on_start:(fun () -> ())
~on_stop:(fun () -> ())
~on_stop:(fun () -> stopped := true)
~register_telnet:false ~autostart:true (Lang.source s)
in
let ratio = Lang.to_float (List.assoc "ratio" p) in
Expand All @@ -255,7 +265,7 @@ let _ =
Clock.unify ~pos:o#pos o#clock (Clock.create_known clock);
ignore (clock#start_outputs (fun _ -> true) ());
log#info "Start dropping source (ratio: %.02fx)" ratio;
while (not (Atomic.get should_stop)) && o#is_ready () do
while (not (Atomic.get should_stop)) && not !stopped do
let start_time = Time.time () in
clock#end_tick;
sleep_until (start_time |+| latency)
Expand Down
2 changes: 1 addition & 1 deletion src/core/clock.ml
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ module MkClock (Time : Liq_time.T) = struct
| `Auto ->
List.exists
(fun (state, (s : Source.active_source)) ->
state = `Active && snd s#self_sync && s#is_ready ())
state = `Active && snd s#self_sync && s#is_ready)
outputs
| `CPU -> false
| `None -> true
Expand Down
42 changes: 4 additions & 38 deletions src/core/conversions/conversion.ml
Original file line number Diff line number Diff line change
Expand Up @@ -20,47 +20,13 @@

*****************************************************************************)

(* Conversion base class. contents marked as [true] are modified
* by the converter using this class. Other contents are untouched. *)
class base ?(audio = false) ?(video = false) ?(midi = false) ~converter
(source : Source.source) =
object (self)
class base ~converter (source : Source.source) =
object
method stype = source#stype
method private _is_ready = source#is_ready
method private can_generate_frame = source#is_ready
method abort_track = source#abort_track
method remaining = source#remaining
method seek_source = source#seek_source
method self_sync = source#self_sync
val mutable tmp_frame = None

(* The tmp_frame is intended to be filled by the underlying source. Content
untouched by the converter are replaced by by content from the calling
frame. Touched content get their own layer. *)
method private tmp_frame =
match tmp_frame with
| Some tmp_frame -> tmp_frame
| None ->
(* We need to delay the creation of the frame in order not to evaluate
the kind too early (the user has to have a chance of setting the
default number of channels). *)
let frame = Frame.create source#content_type in
tmp_frame <- Some frame;
frame

method private copy_frame src dst =
Frame.set_breaks dst (Frame.breaks src);
Frame.set_all_metadata dst (Frame.get_all_metadata src);
if not audio then (
try Frame.set_audio dst (Frame.audio src) with Not_found -> ());
if not video then (
try Frame.set_video dst (Frame.video src) with Not_found -> ());
if not midi then (
try Frame.set_video dst (Frame.midi src) with Not_found -> ())

method private get_frame frame =
let tmp_frame = self#tmp_frame in
self#copy_frame frame tmp_frame;
source#get tmp_frame;
converter ~frame tmp_frame;
self#copy_frame tmp_frame frame
method private generate_frame = converter source#get_frame
end
26 changes: 12 additions & 14 deletions src/core/conversions/mean.ml
Original file line number Diff line number Diff line change
Expand Up @@ -21,31 +21,29 @@
*****************************************************************************)

open Source
open Mm

class mean ~field ~normalize source =
object
inherit operator [source] ~name:"mean"

inherit
Conversion.base
~audio:true source
~converter:(fun ~frame tmp_frame ->
~converter:(fun frame ->
(* Compute the mean of audio channels *)
let start = Frame.position frame in
let len = Frame.position tmp_frame - start in
let content = Content.Audio.get_data (Frame.get frame field) in
let tmp_content =
Content.Audio.get_data (Frame.get tmp_frame field)
in
let len = Frame.position frame in
let alen = Frame.audio_of_main len in
let src_content = Content.Audio.get_data (Frame.get frame field) in
let dst_content = Audio.Mono.create alen in
let amp =
if normalize then 1. /. float (Array.length tmp_content) else 1.
if normalize then 1. /. float (Array.length src_content) else 1.
in
let ( ! ) = Frame.audio_of_main in
for i = !start to !(start + len) - 1 do
content.(0).(i) <-
Array.fold_left (fun m b -> m +. b.(i)) 0. tmp_content *. amp
for i = 0 to alen - 1 do
dst_content.(i) <-
Array.fold_left (fun m b -> m +. b.(i)) 0. src_content *. amp
done;
Frame.set frame field (Content.Audio.lift_data content))
Frame.set_data frame field Content.Audio.lift_data [| dst_content |])
source
end

let _ =
Expand Down
8 changes: 4 additions & 4 deletions src/core/conversions/stereo.ml
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,10 @@ class basic ~field source =

inherit
Conversion.base
~audio:true source
~converter:(fun ~frame tmp_frame ->
~converter:(fun frame ->
(* Set audio layer. *)
let audio =
match Content.Audio.get_data (Frame.get tmp_frame field) with
match Content.Audio.get_data (Frame.get frame field) with
| [||] ->
let len = AFrame.size () in
let buf = Audio.Mono.create len in
Expand All @@ -51,7 +50,8 @@ class basic ~field source =
| [| chan |] -> [| chan; chan |]
| audio -> Array.sub audio 0 2
in
Frame.set frame field (Content.Audio.lift_data audio))
Frame.set_data frame field Content.Audio.lift_data audio)
source
end

let stereo =
Expand Down
31 changes: 8 additions & 23 deletions src/core/conversions/swap.ml
Original file line number Diff line number Diff line change
Expand Up @@ -25,29 +25,14 @@ open Source
class swap ~field (source : source) =
object
inherit operator [source] ~name:"swap"
method stype = source#stype
method private _is_ready = source#is_ready
method remaining = source#remaining
method abort_track = source#abort_track
method seek_source = source#seek_source
method self_sync = source#self_sync

method private get_frame buf =
let offset = AFrame.position buf in
let buffer =
source#get buf;
Content.Audio.get_data (Frame.get buf field)
in
if offset = 0 then (
let tmp = buffer.(1) in
buffer.(1) <- buffer.(2);
buffer.(2) <- tmp)
else
for i = offset to AFrame.position buf - 1 do
let tmp = buffer.(0).(i) in
buffer.(0).(i) <- buffer.(1).(i);
buffer.(1).(i) <- tmp
done

inherit
Conversion.base
~converter:(fun frame ->
let buffer = Content.Audio.get_data (Frame.get frame field) in
Frame.set_data frame field Content.Audio.lift_data
[| buffer.(1); buffer.(0) |])
source
end

let _ =
Expand Down
Loading
Loading