# # Aura Engine (https://gitlab.servus.at/aura/engine) # # Copyright (C) 2017-2020 - The Aura Engine Team. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by # the Free Software Foundation, either version 3 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 Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. # READ INI FILE default_config = "../config/engine-core.yaml" config_file = list.hd( default=default_config, process.read.lines( "ls /etc/aura/engine-core.yaml" ) ) print( "\tConfig file: '#{config_file}'" ) let yaml.parse (config : { general: { engine_id: string, socket_dir: string, log_dir: string, log_level: string, liquidsoap_as_root: bool, liquidsoap_min_version: string, api_url_playlog: string }, telnet: { server_enable: bool, server_timeout: float, server_host: string, server_port: float }, fallback: { music_folder: string, show_name: string, show_id: string, type: string, music_playlist: string, music_folder_reload: float, max_blank: float, min_noise: float, threshold: float }, stream: [ { enabled: bool, encoding: string, bitrate: string, channels: string, host: string, port: float, mountpoint: string, user: string, password: string, url: string, name: string, genre: string, description: string } ], audio: { soundsystem: string, devices: {output: [{name: string}], input: [{name: string}]} } } ) = file.contents(config_file) engine_config_folder = string.split(separator="/engine-core.yaml", config_file) engine_config_folder = list.nth(default="../config/", engine_config_folder, 0) print( "\tengine_config_folder = '#{engine_config_folder}'" ) # Retrieve a setting either bei 1.) environment variable or 2.) config property. # If none is available the default value is returned. # def get_setting(default_value, config_prop, env_var) = # dv = list.assoc(default=default_value, config_prop, ini) # environment.get(default=dv, env_var) # end # FIXME: env vars are always strings, we would have to guess the type here # since the config_value might not be a string. Maybe we can extract the type # from config_value? def get_setting(config_value, env_var) = environment.get(default=config_value, env_var) end # VERSION CHECK if not liquidsoap.version.at_least(config.general.liquidsoap_min_version) then print( "AURA Engine Core requires at least Liquidsoap v#{ config.general.liquidsoap_min_version }" ) exit(1) end # ALLOW LIQUIDSOAP RUN AS ROOT if # get_setting(config.general.liquidsoap_as_root, "AURA_ENGINE_RUN_AS_ROOT") config.general.liquidsoap_as_root then print( "\tAllow Liquidsoap running as root user: true" ) settings.init.allow_root.set(true) else print( "\tAllow Liquidsoap running as root user: false" ) settings.init.allow_root.set(false) end # SERVER SETTINGS # server_timeout = # float_of_string( # get_setting("16380.", "server_timeout", "AURA_ENGINE_SERVER_TIMEOUT") # ) settings.server.timeout.set(config.telnet.server_timeout) # telnet_server_enable = # get_setting("true", "telnet_server_enable", "AURA_ENGINE_TELNET_ENABLE") # telnet_server_host = # get_setting("127.0.0.1", "telnet_server_host", "AURA_ENGINE_TELNET_HOST") # telnet_server_port = # int_of_string( # get_setting("1234", "telnet_server_port", "AURA_ENGINE_TELNET_PORT") # ) if not config.telnet.server_enable then print( "\tLiquidsoap Telnet Server: disabled" ) settings.server.telnet.set(false) else print( "\tLiquidsoap Telnet Server at " ^ config.telnet.server_host ^ ":" ^ string.float(config.telnet.server_port) ^ " (" ^ string.float(config.telnet.server_timeout) ^ "s timeout)" ) settings.server.telnet.bind_addr.set(config.telnet.server_host) settings.server.telnet.port.set(int_of_float(config.telnet.server_port)) settings.server.telnet.set(true) end # BASICS settings.console.colorize.set("always") #settings.request.grace_time.set(2.) # LOG SETTINGS engine_version = process.read( "cat ../VERSION" ) log( "######################################################################################" ) log( "AURA Engine:Core v#{engine_version} starting ..." ) log( "######################################################################################" ) log( "System Settings:" ) # LOGGING SETTINGS settings.log.stdout.set(true) settings.log.file.set(true) log_level = if config.general.log_level == "DEBUG" then 5 elsif config.general.log_level == "INFO" then 3 elsif config.general.log_level == "WARNING" then 2 elsif config.general.log_level == "ERROR" then 1 else 3 end # log_level = get_setting("3", "log_level", "AURA_ENGINE_CORE_LOG_LEVEL") settings.log.level.set(log_level) # log_dir = get_setting("../logs", "log_dir", "AURA_ENGINE_CORE_LOG_DIR") log_file = "#{config.general.log_dir}/engine-core.log" settings.log.file.path.set(log_file) print( "\tLogging to '#{log_file}' with log level #{log_level}" ) log( "\tLog level #{log_level}" ) # CONFIGURATION FILE log( "\tConfig file: '#{config_file}'" ) # SOCKET SETTINGS # socket_dir = get_setting("../socket", "socket_dir", "AURA_ENGINE_SOCKET_DIR") socket_file = "#{config.general.socket_dir}/engine.sock" if config.general.socket_dir != "" then log( "\tSocket location: '#{socket_file}'" ) settings.server.socket.path.set(socket_file) settings.server.socket.set(true) else log( "\tCRITICAL: No socket directory set!" ) end # SOUND CARD SETTINGS # settings.audio.converter.samplerate.converters.set(["ffmpeg","libsamplerate","native"]) # settings.decoder.decoders.set(["META","WAV","AIFF","FLAC","AAC","MP4","OGG","MAD"]) # TODO: This needs refactoring # we save the device name in the corresponding variable name # I guess the variable name is then later used to create the in- and outputs # a0_in = get_setting("", "input_device_0", "AURA_ENGINE_INPUT_DEVICE") # a0_out = get_setting("", "output_device_0", "AURA_ENGINE_OUTPUT_DEVICE") # ALSA / pulse settings # soundsystem = get_setting("alsa", "soundsystem", "AURA_ENGINE_SOUNDSYSTEM") soundsystem = config.audio.soundsystem use_alsa = soundsystem == "alsa" use_jack = soundsystem == "jack" log( "\nAudio Settings:" ) def print_device(device) = log( "\t\t- #{device.name}" ) end log( "\tOutput Devices:" ) list.iter(print_device, config.audio.devices.output) log( "\tInput Devices:" ) list.iter(print_device, config.audio.devices.input) # ReplayGain Settings # enable_replaygain_resolver = # bool_of_string( # get_setting( # "false", # "enable_replaygain_resolver", # "AURA_ENGINE_ENABLE_REPLAYGAIN_RESOLVER" # ) # ) # FIXME: read this from the config file? enable_replaygain_resolver = false if enable_replaygain_resolver == true then enable_replaygain_metadata() log( "\tReplayGain resolver enabled" ) end # Frame Settings # TODO: due to the switch to jack these settings are not needed anymore. Maybe if we # enable ALSA in some point in the future again. # frame_audio_sample_rate = # int_of_string( # get_setting("0", "frame_audio_sample_rate", "AURA_ENGINE_FRAME_SAMPLERATE") # ) frame_audio_sample_rate = 0 # frame_duration = # float_of_string( # get_setting("0.0", "frame_duration", "AURA_ENGINE_FRAME_DURATION") # ) frame_duration = 0.0 # frame_audio_size = # int_of_string(get_setting("0", "frame_audio_size", "AURA_ENGINE_FRAME_SIZE")) frame_audio_size = 0 if frame_audio_sample_rate > 0 then log( "\tframe.audio.samplerate = #{frame_audio_sample_rate} Hz" ) settings.frame.audio.samplerate.set(frame_audio_sample_rate) end if frame_duration > 0.0 then log( "\tframe.duration = #{frame_duration} seconds" ) settings.frame.duration.set(frame_duration) end if frame_audio_size > 0 then log( "\tframe.audio.size = #{frame_audio_size} ticks" ) settings.frame.audio.size.set(frame_audio_size) end alsa_buffered_input = ref(true) alsa_buffered_output = ref(true) # TODO: same question, do we want to keep this code? # if # use_alsa # then # log( # "\nALSA Settings:" # ) # alsa_buffered_input := # bool_of_string( # get_setting( # "true", "alsa_buffered_input", "AURA_ENGINE_ALSA_BUFFERED_INPUT" # ) # ) # alsa_buffered_output := # bool_of_string( # get_setting( # "true", "alsa_buffered_output", "AURA_ENGINE_ALSA_BUFFERED_OUTPUT" # ) # ) # alsa_buffer = # int_of_string(get_setting("0", "alsa_buffer", "AURA_ENGINE_ALSA_BUFFER")) # alsa_buffer_length = # int_of_string( # get_setting("0", "alsa_buffer_length", "AURA_ENGINE_ALSA_BUFFER_LENGTH") # ) # alsa_periods = # int_of_string(get_setting("0", "alsa_periods", "AURA_ENGINE_ALSA_PERIODS")) # log( # "\talsa_buffered_input = #{alsa_buffered_input()}" # ) # log( # "\talsa_buffered_output = #{alsa_buffered_output()}" # ) # if # alsa_buffer > 0 # then # log( # "\tInternal buffer size (alsa.alsa_buffer) = #{alsa_buffer}" # ) # settings.alsa.alsa_buffer.set(alsa_buffer) # end # if # alsa_buffer_length > 0 # then # log( # "\tBuffer size, in frames (alsa.buffer_length) = #{alsa_buffer_length}" # ) # settings.alsa.buffer_length.set(alsa_buffer_length) # end # if # alsa_periods > 0 # then # log( # "\tPeriods (alsa.periods) = #{alsa_periods}" # ) # settings.alsa.periods.set(alsa_periods) # end # end log( "\nStream Settings:" ) # TODO: read this from the config file # INPUT STREAM SETTINGS # input_stream_max_buffer = # float_of_string( # get_setting( # "5.0", "input_stream_max_buffer", "AURA_ENGINE_STREAM_INPUT_MAX_BUFFER" # ) # ) input_stream_max_buffer = 5.0 # input_stream_timeout = # float_of_string( # get_setting( # "10.0", "input_stream_timeout", "AURA_ENGINE_STREAM_INPUT_TIMEOUT" # ) # ) input_stream_timeout = 10.0 log( "\tInput stream max buffer: #{input_stream_max_buffer}" ) log( "\tInput stream timeout: #{input_stream_timeout}" ) # OUTPUT STREAM # TODO: refactor this to use the list of streams # s0_enable = # get_setting("false", "stream_0", "AURA_ENGINE_STREAM_OUTPUT_ENABLE") == "true" s0_enable = list.hd(config.stream).enabled # s1_enable = list.assoc(default="false", "stream_1", ini) == "true" # s2_enable = list.assoc(default="false", "stream_2", ini) == "true" # s3_enable = list.assoc(default="false", "stream_3", ini) == "true" # s4_enable = list.assoc(default="false", "stream_4", ini) == "true" log( "\tOutput stream enabled: #{s0_enable}" ) log( "\nOther Settings:" ) # AUDIO AND PLAYLIST SOURCES # TODO: read this from config # audio_playlist_folder = # get_setting( # "../audio/playlists", "audio_playlist_folder", "AURA_ENGINE_PLAYLIST_FOLDER" # ) audio_playlist_folder = "../audio/playlists" # FALLBACK SETTINGS # fallback_show_name = # ref( # get_setting( # "Station Fallback", # "fallback_show_name", # "AURA_ENGINE_FALLBACK_SHOW_NAME" # ) # ) fallback_show_name = ref(config.fallback.show_name) # fallback_show_id = # ref(get_setting("-1", "fallback_show_id", "AURA_ENGINE_FALLBACK_SHOW_ID")) fallback_show_id = ref(config.fallback.show_id) # fallback_type = # get_setting("folder", "fallback_type", "AURA_ENGINE_FALLBACK_TYPE") fallback_type = config.fallback.type # fallback_station_playlist_name = # get_setting( # "station-fallback-playlist.m3u", # "fallback_music_playlist", # "AURA_ENGINE_FALLBACK_PLAYLIST" # ) fallback_station_playlist_name = config.fallback.music_playlist fallback_station_playlist_path = "#{audio_playlist_folder}/#{fallback_station_playlist_name}" # fallback_station_dir = # get_setting( # "../audio/fallback", "fallback_music_folder", "AURA_ENGINE_FALLBACK_FOLDER" # ) fallback_station_dir = config.fallback.music_folder # fallback_station_dir_reload = # int_of_string( # get_setting( # "300", # "fallback_music_folder_reload", # "AURA_ENGINE_FALLBACK_FOLDER_RELOAD" # ) # ) fallback_station_dir_reload = int_of_float(config.fallback.music_folder_reload) # fallback_max_blank = # float_of_string( # get_setting("15.", "fallback_max_blank", "AURA_ENGINE_FALLBACK_MAX_BLANK") # ) fallback_max_blank = config.fallback.max_blank # fallback_min_noise = # float_of_string( # get_setting("0.", "fallback_min_noise", "AURA_ENGINE_FALLBACK_MIN_NOISE") # ) fallback_min_noise = config.fallback.min_noise # fallback_threshold = # float_of_string( # get_setting("-80.", "fallback_threshold", "AURA_ENGINE_FALLBACK_THRESHOLD") # ) fallback_threshold = config.fallback.threshold log( "\tfallback_station_playlist_path = '#{fallback_station_playlist_path}'" ) log( "\tfallback_station_dir = '#{fallback_station_dir}'" ) # FADING SETTINGS # fade_in_time = list.assoc(default="", "fade_in_time", ini) #int_of_string(list.assoc(default="", "fade_in_time", ini)) # fade_out_time = list.assoc(default="", "fade_out_time", ini) #int_of_string(list.assoc(default="", "fade_out_time", ini)) # Metadata Configuration # FIXME: whats this? Move into config file # engine_meta_key_show_id = # get_setting("show_id", "meta_key_show_id", "AURA_ENGINE_META_KEY_SHOW_ID") engine_meta_key_show_id = "show_id" # engine_default_track_type = # get_setting("0", "default_track_type", "AURA_ENGINE_DEFAULT_TRACK_TYPE") engine_default_track_type = "0" # engine_api_playlog = # get_setting( # "http://127.0.0.1:8008/api/v1/playlog", # "api_url_playlog", # "AURA_ENGINE_API_URL_PLAYLOG" # ) engine_api_playlog = config.general.api_url_playlog # "1" or "2" used for HA setups # engine_id = get_setting("1", "engine_id", "AURA_ENGINE_ID") engine_id = config.general.engine_id log( "\n######################################################################################" )