externals.liq 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. # Decoders, enabled when the binary is detected and the os is not Win32.
  2. %ifdef add_decoder
  3. # Enable external Musepack decoder. Requires the
  4. # mpcdec binary in the path. Does not work on
  5. # Win32.
  6. # @category Liquidsoap
  7. def enable_external_mpc_decoder() =
  8. # A list of know extensions and content-type for Musepack.
  9. # Values from http://en.wikipedia.org/wiki/Musepack
  10. mpc_mimes = [ "audio/x-musepack", "audio/musepack" ]
  11. mpc_filexts = [ "mpc", "mp+", "mpp" ]
  12. def test_mpc(file) =
  13. def get_channels(file) =
  14. int_of_string(
  15. list.hd(
  16. get_process_lines("mpcdec -i #{quote(file)} 2>&1 \
  17. | grep channels | cut -d' ' -f 2")))
  18. end
  19. # Get the file's mime
  20. mime = get_mime(file)
  21. # Test mime
  22. if list.mem(mime,mpc_mimes) then
  23. get_channels(file)
  24. else
  25. # Otherwise test file extension
  26. ret = string.extract(pattern='\.(.+)$',file)
  27. if list.length(ret) != 0 then
  28. ext = ret["1"]
  29. if list.mem(ext,mpc_filexts) then
  30. get_channels(file)
  31. else
  32. 0
  33. end
  34. else
  35. get_channels(file)
  36. end
  37. end
  38. end
  39. if test_process("which mpcdec") then
  40. log(level=3,"Found mpcdec binary: enabling musepack external decoder.")
  41. mpcdec_p = fun(f) -> "mpcdec #{quote(f)} - 2>/dev/null"
  42. add_oblivious_decoder(name="MPCDEC",description="Decode files using the mpcdec \
  43. musepack decoder binary",test=test_mpc,mpcdec_p)
  44. else
  45. log(level=3,"Did not find mpcdec binary: musepack decoder disabled.")
  46. end
  47. end
  48. # Enable external FLAC decoders. Requires flac binary
  49. # in the path for audio decoding and metaflac binary for
  50. # metadata. Does not work on Win32. Default: disabled.
  51. # Please note that built-in support for FLAC is available
  52. # in liquidsoap if compiled and should be preferred over
  53. # the external decoder.
  54. # @category Liquidsoap
  55. def enable_external_flac_decoder() =
  56. if test_process("which flac") then
  57. log(level=3,"Found flac binary: enabling flac external decoder.")
  58. flac_p = "flac -d -c - 2>/dev/null"
  59. def test_flac(file) =
  60. if test_process("which metaflac") then
  61. channels = list.hd(get_process_lines("metaflac \
  62. --show-channels #{quote(file)} \
  63. 2>/dev/null"))
  64. # If the value is not an int, this returns 0 and we are ok :)
  65. int_of_string(channels)
  66. else
  67. if string.match(pattern="flac",file) then
  68. # We do not know the number of audio channels
  69. # so setting to -1
  70. (-1)
  71. else
  72. # All tests failed: no audio decodable using flac..
  73. 0
  74. end
  75. end
  76. end
  77. add_decoder(name="EXTERNAL_FLAC",description="Decode files using the flac \
  78. decoder binary.", test=test_flac,flac_p)
  79. else
  80. log(level=3,"Did not find flac binary: flac decoder disabled.")
  81. end
  82. if test_process("which metaflac") then
  83. log(level=3,"Found metaflac binary: enabling flac external metadata \
  84. resolver.")
  85. def flac_meta(file)
  86. ret = get_process_lines("metaflac --export-tags-to=- \
  87. #{quote(file)} 2>/dev/null")
  88. ret = list.map(string.split(separator="="),ret)
  89. # Could be made better..
  90. def f(l',l)=
  91. if list.length(l) >= 2 then
  92. list.append([(list.hd(l),list.nth(l,1))],l')
  93. else
  94. if list.length(l) >= 1 then
  95. list.append([(list.hd(l),"")],l')
  96. else
  97. l'
  98. end
  99. end
  100. end
  101. list.fold(f,[],ret)
  102. end
  103. add_metadata_resolver("EXTERNAL_FLAC",flac_meta)
  104. else
  105. log(level=3,"Did not find metaflac binary: flac metadata resolver disabled.")
  106. end
  107. end
  108. %endif
  109. %ifdef add_oblivious_decoder
  110. # Enable or disable external FAAD (AAC/AAC+/M4A) decoders.
  111. # Requires faad binary in the path for audio decoding and
  112. # metaflac binary for metadata. Does not work on Win32.
  113. # Please note that built-in support for faad is available
  114. # in liquidsoap if compiled and should be preferred over
  115. # the external decoder.
  116. # @category Liquidsoap
  117. def enable_external_faad_decoder() =
  118. # A list of know extensions and content-type for AAC.
  119. # Values from http://en.wikipedia.org/wiki/Advanced_Audio_Coding
  120. # TODO: can we register a setting for that ??
  121. aac_mimes =
  122. ["audio/aac", "audio/aacp", "audio/3gpp", "audio/3gpp2", "audio/mp4",
  123. "audio/MP4A-LATM", "audio/mpeg4-generic", "audio/x-hx-aac-adts"]
  124. aac_filexts = ["m4a", "m4b", "m4p", "m4v",
  125. "m4r", "3gp", "mp4", "aac"]
  126. # Faad is not very selective so
  127. # We are checking only file that
  128. # end with a known extension or mime type
  129. def faad_test(file) =
  130. # Get the file's mime
  131. mime = get_mime(file)
  132. # Test mime
  133. if list.mem(mime,aac_mimes) then
  134. true
  135. else
  136. # Otherwise test file extension
  137. ret = string.extract(pattern='\.(.+)$',file)
  138. if list.length(ret) != 0 then
  139. ext = ret["1"]
  140. list.mem(ext,aac_filexts)
  141. else
  142. false
  143. end
  144. end
  145. end
  146. if test_process("which faad") then
  147. log(level=3,"Found faad binary: enabling external faad decoder and \
  148. metadata resolver.")
  149. faad_p = (fun (f) -> "faad -w #{quote(f)} 2>/dev/null")
  150. def test_faad(file) =
  151. if faad_test(file) then
  152. channels = list.hd(get_process_lines("faad -i #{quote(file)} 2>&1 | \
  153. grep 'ch,'"))
  154. ret = string.extract(pattern=", (\d) ch,",channels)
  155. ret =
  156. if list.length(ret) == 0 then
  157. # If we pass the faad_test, chances are
  158. # high that the file will contain aac audio data..
  159. "-1"
  160. else
  161. ret["1"]
  162. end
  163. int_of_string(default=(-1),ret)
  164. else
  165. 0
  166. end
  167. end
  168. add_oblivious_decoder(name="EXTERNAL_FAAD",description="Decode files using \
  169. the faad binary.", test=test_faad, faad_p)
  170. def faad_meta(file) =
  171. if faad_test(file) then
  172. ret = get_process_lines("faad -i \
  173. #{quote(file)} 2>&1")
  174. # Yea, this is ugly programming (again) !
  175. def get_meta(l,s)=
  176. ret = string.extract(pattern="^(\w+):\s(.+)$",s)
  177. if list.length(ret) > 0 then
  178. list.append([(ret["1"],ret["2"])],l)
  179. else
  180. l
  181. end
  182. end
  183. list.fold(get_meta,[],ret)
  184. else
  185. []
  186. end
  187. end
  188. add_metadata_resolver("EXTERNAL_FAAD",faad_meta)
  189. else
  190. log(level=3,"Did not find faad binary: faad decoder disabled.")
  191. end
  192. end
  193. %endif
  194. # Standard function for displaying metadata.
  195. # Shows artist and title, using "Unknown" when a field is empty.
  196. # @param m Metadata packet to be displayed.
  197. # @category String
  198. def string_of_metadata(m)
  199. artist = m["artist"]
  200. title = m["title"]
  201. artist = if ""==artist then "Unknown" else artist end
  202. title = if ""==title then "Unknown" else title end
  203. "#{artist} -- #{title}"
  204. end
  205. # Use X On Screen Display to display metadata info.
  206. # @param ~color Color of the text.
  207. # @param ~position Position of the text (top|middle|bottom).
  208. # @param ~font Font used (xfontsel is your friend...)
  209. # @param ~display Function used to display a metadata packet.
  210. # @category Source / Track Processing
  211. def osd_metadata(~color="green",~position="top",
  212. ~font="-*-courier-*-r-*-*-*-240-*-*-*-*-*-*",
  213. ~display=string_of_metadata,
  214. s)
  215. osd = 'osd_cat -p #{position} --font #{quote(font)}'
  216. ^ ' --color #{color}'
  217. def feedback(m)
  218. system("echo #{quote(display(m))} | #{osd} &")
  219. end
  220. on_metadata(feedback,s)
  221. end
  222. # Use notify to display metadata info.
  223. # @param ~urgency Urgency (low|normal|critical).
  224. # @param ~icon Icon filename or stock icon to display.
  225. # @param ~time Timeout in milliseconds.
  226. # @param ~display Function used to display a metadata packet.
  227. # @param ~title Title of the notification message.
  228. # @category Source / Track Processing
  229. def notify_metadata(~urgency="low",~icon="stock_smiley-22",~time=3000,
  230. ~display=string_of_metadata,
  231. ~title="Liquidsoap: new track",s)
  232. send = 'notify-send -i #{icon} -u #{urgency}'
  233. ^ ' -t #{time} #{quote(title)} '
  234. on_metadata(fun (m) -> system(send^quote(display(m))),s)
  235. end
  236. %ifdef input.external
  237. # Stream data from mplayer
  238. # @category Source / Input
  239. # @param s data URI.
  240. # @param ~restart restart on exit.
  241. # @param ~restart_on_error restart on exit with error.
  242. # @param ~buffer Duration of the pre-buffered data.
  243. # @param ~max Maximum duration of the buffered data.
  244. # @category Source / Input
  245. def input.mplayer(~id="input.mplayer",
  246. ~restart=true,~restart_on_error=false,
  247. ~buffer=0.2,~max=10.,s) =
  248. input.external(id=id,restart=restart,
  249. restart_on_error=restart_on_error,
  250. buffer=buffer,max=max,
  251. "mplayer -really-quiet -ao pcm:file=/dev/stdout \
  252. -vc null -vo null #{quote(s)} 2>/dev/null")
  253. end
  254. %endif