1"use strict";(self.webpackChunksite=self.webpackChunksite||[]).push([["18924"],{61517(e,t,s){s.r(t),s.d(t,{metadata:()=>n,default:()=>u,frontMatter:()=>a,contentTitle:()=>o,toc:()=>l,assets:()=>c});var n=JSON.parse('{"id":"dynamic_sources","title":"Dynamic sources","description":"Liquidsoap supports dynamic creation and destruction of sources during the execution of a script. The following gives an example of this.","source":"@site/docs/dynamic_sources.md","sourceDirName":".","slug":"/dynamic_sources","permalink":"/doc-dev/dynamic_sources","draft":false,"unlisted":false,"tags":[],"version":"current","frontMatter":{"title":"Dynamic sources","description":"Liquidsoap supports dynamic creation and destruction of sources during the execution of a script. The following gives an example of this."},"sidebar":"docs","previous":{"title":"Request-based sources","permalink":"/doc-dev/request_sources"},"next":{"title":"Playlist parsers","permalink":"/doc-dev/playlist_parsers"}}'),r=s(74848),i=s(28453);let a={title:"Dynamic sources",description:"Liquidsoap supports dynamic creation and destruction of sources during the execution of a script. The following gives an example of this."},o,c={},l=[];function d(e){let t={a:"a",code:"code",li:"li",p:"p",pre:"pre",ul:"ul",...(0,i.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.p,{children:"Liquidsoap supports dynamic creation and destruction of sources\nduring the execution of a script. The following gives an example\nof this."}),"\n",(0,r.jsx)(t.p,{children:"First some outlines:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:"This example is meant to create a new source and outputs. It is not easy currently to change a source being streamed"}),"\n",(0,r.jsx)(t.li,{children:"The idea is to create a new output using a telnet/server command."}),"\n",(0,r.jsxs)(t.li,{children:["In order for a Liquidsoap script to run without an active source at startup, it is necessary to include ",(0,r.jsx)(t.code,{children:"settings.init.force_start := true"})," at the start of the script."]}),"\n"]}),"\n",(0,r.jsx)(t.p,{children:"In this example, we will register a command that dynamically create a new output based on an encoded stream\nand output it to an arbitrary url, as supported by the ffmpeg copy encoder. This script can be used to create\na dynamic restreaming platform."}),"\n",(0,r.jsx)(t.p,{children:"Here's the code:"}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-liquidsoap",metastring:'title="dynamic-source.liq"',children:'settings.init.force_start := true\nsettings.server.telnet := true\n\n# Replace the path here with a path to some video files:\ns = playlist("/path/to/files")\n\nstreams = ref([])\ncount = ref(0)\n\nenc = %ffmpeg(format = "flv", %audio.copy, %video.copy)\n\ndef create_stream(url) =\n if\n list.assoc.mem(url, streams())\n then\n "Stream for url #{url} already exists!"\n else\n out = output.url(id="restream-#{count()}", fallible=true, url=url, enc, s)\n count := count() + 1\n streams := [...streams(), (url, out.shutdown)]\n "OK!"\n end\nend\n\ndef delete_stream(url) =\n if\n not list.assoc.mem(url, streams())\n then\n "Stream for url #{url} does not exists!"\n else\n shutdown = list.assoc(url, streams())\n shutdown()\n streams := list.filter((fun (el) -> fst(el) != url), streams())\n "OK!"\n end\nend\n\nserver.register(\n namespace="restream",\n description="Redirect a stream.",\n usage="start <url>",\n "start",\n create_stream\n)\nserver.register(\n namespace="restream",\n description="Stop a dynamic playlist.",\n usage="stop <url>",\n "stop",\n delete_stream\n)\n'})}),"\n",(0,r.jsx)(t.p,{children:"After executing this script, you should see two telnet commands:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:(0,r.jsx)(t.code,{children:"restream.start <uri>"})}),"\n",(0,r.jsx)(t.li,{children:(0,r.jsx)(t.code,{children:"restream.stop <uri>"})}),"\n"]}),"\n",(0,r.jsx)(t.p,{children:"which you can use to create/destroy dynamically your sources."}),"\n",(0,r.jsxs)(t.p,{children:["Note that ",(0,r.jsx)(t.code,{children:"create_stream"})," reuses ",(0,r.jsx)(t.code,{children:"s"}),", which lives for as long as the script\ndoes. Any callback it registers on ",(0,r.jsx)(t.code,{children:"s"})," \u2014 directly, or through an operator such\nas ",(0,r.jsx)(t.code,{children:"fade.in"})," \u2014 stays there once the stream is deleted, and one is added on every\ncall. See ",(0,r.jsx)(t.a,{href:"/doc-dev/callbacks",children:"source callbacks"})," for how to release them."]})]})}function u(e={}){let{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(d,{...e})}):d(e)}},28453(e,t,s){s.d(t,{R:()=>a,x:()=>o});var n=s(96540);let r={},i=n.createContext(r);function a(e){let t=n.useContext(i);return n.useMemo(function(){return"function"==typeof e?e(t):{...t,...e}},[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:a(e.components),n.createElement(i.Provider,{value:t},e.children)}}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.