Premisas para el Script:
En primer lugar se tienen los programas en vivo. Lo ideal es que estos se transmitan permanentemente. En lo que no exista un programa en vivo se transmitirá música o programas en diferido, pero bajo los siguientes conceptos:
Si un programa en vivo deja de transmitir porque se ha desconectado, se espera a ver si hay reconexiones, con un silencio de 10 segundos. En caso de que se cumplan estos 10 segundos y no regrese el flujo de datos en vivo, se procede a tomar audio de una fuente. Actualmente de Podcasts en diferido.
En el script propuesto se incluye un canal para transmitir contínuamente podcasts diferidos de los locutores.
Como estaba al principio, el LS administra el punto de montaje /vivo.ogg y lo retransmite en /radiognu.ogg
De no existir /vivo.ogg (nadie está transmitiendo), envía al punto de montaje /radiognu.ogg, audio de una lista de podcasts. Los usuarios no son ya notificados de los cambios en el track, al igual que cuando regresa la señal, pero la metadata está vacía. En esta configuración la metadata está fija con un solo texto y los clientes no se caen nunca por envío de metadata. En esas caídas suenan cambios bruscos de una fuenta a otra.
#!/usr/bin/liquidsoap
# registro
set("log.file.path","/home/radiognu/liquidsoap/liquidsoap.log")
set("log.level",3)
# fuentes de sonido
podcasts =playlist("/home/radiognu/liquidsoap/musica.txt")
vivo =input.http("http://radiognu.org:8000/vivo.ogg")
radio=fallback(track_sensitive=false, [vivo, podcasts])
# Salida al ICECAST
output.icecast.vorbis(mount="radiognu.ogg",
samplerate=32000,
stereo=false,
password="--------",
port=8000,
name="RadioGNU",
description="La emisora del GNU que te da nota",
genre="Live Libre :-)",
url="http://radiognu.org:8000/radiognu.ogg",
quality=3.0,
mksafe(clear_metadata(radio)))
Curiosamente la siguiente línea…
mksafe(clear_metadata(radio)))
… hace que el flujo de audio sea ininterrumpido, luego del cambio a
rewrite_metadata([("artist","RadioGNU"),("title","El ñu que te da nota")],clear_metadata(radio)))
Propuesto por BreadMaker, cada canción envía metadata, el tema es que vuelve a enviar la misma metadata, junto con un mensaje de cambio de canción, que es lo que queremos evitar que suceda.
Cuando fueron eliminados (con clear_metadata), aparecía “unknown” en los navegadores.
Esto es mejor que producir caídas en los navegadores. Al intentarlo con map_metadata enviaba el texto, pero al cambiar la canción también enviaba el mismo texto como información de cambio, tumbando a los clientes con problemas para interpretar estos datos.
(traducidos del inglés)
toots@rastageeks.org
El problema viende del hecho de que LiquidSoap tiene una noción de track que es mantenido incluso si se remueve la metadata. Entonces, rewrite_metadata agrega nueva data por cada track (parametro: inser_missing). Lo que hace falta es remover todos los marcadores de track antes de reescribir la metadata. El siguiente código puede lograr eso:
s = add([blank(),s])
s = rewrite_metadata([("title","test")], s)
La primera línea agrega una fuente en blanco a “s”.
El comportamiento de add es relevar (relay) tracks y metadata de la primera fuente solamente, por lo cual la fuente resultate tendrá será un track vacío y sin metadata.
Entonces la segunda línea agrega la metadata encima.
Se debe poner ese código justo antes del output. En muchos casos los marcadores de track son útiles, por ejemplo cuando se usa el fallback con track_sensitive, así que mejor quitarlos en el último momento.
Además, esto hace que la fuente sea infalible (pero dará silencio si la fuente real no está disponible), así que cuando se usa esto se pueden remover los mksafe()
david.baelde@ens-lyon.org
Nos dice lo siguiente respecto a esa forma de quitar metadata:
This is probably not the best way to merge tracks (remove track limits). As you point out it makes the source infallible, playing silence when there's no track. Also, it divides the volume by two (but setting normalize=false will fix that) and removes metadata (but changing the order of s and blank() will fix that.
Lo cual hace resultar nuestro código de esa línea así:
radio =add(normalize=false,[blank(),radio])
Respecto a la transición del audio y el añadido de 10 segundos:
def to_live(music,live) # directly play live live end def to_playlist(live,music) sequence(merge=true,[blank(duration=10.),music]) end radio =fallback(track_sensitive=true,transitions=[to_live,to_playlist],[live,music])
Pero en otro correo posterior escribe:
I confirm that I have tested the following solution:
def delay_fallback(a,b)
def immediate(a,b)
b
end
def delayed(a,b)
sequence([blank(duration=10.),b])
end
fallback(track_sensitive=false,[a,b],transitions=[immediate,delayed])
end
I ran delay_fallback(request.queue(...),playlist(...)) and after the
queue empties, there is ten seconds of silence, giving me a chance to
refill it before that the playlist turns on again.
Si bien añadiendo las sugerencias anteriores la radio funcionó mejor, se hacía necesario tener más de una fuente de audio en vivo, de manera de poder tener más de una transmisión en vivo y poder alternar entre ellas, dando paso a una u otra, permitiendo hacer relevos entre más de un locutor a la vez. Esto será ideal para transmisiones de eventos simultáneos como el FLISOL, SFD y demás ocasiones similares.
Al preguntar nos respondieron con algo tan simple como:
live = fallback(track_sensitive=false, [input.http("http://foo/live.ogg"), input.http("http://bar/live2.ogg")]
Lo cual en nuestro caso quedaría:
fallback(track_sensitive=false,[vivo,vivo2,podcasts],transitions=[immediate,immediate,delayed])
Lo probamos y funcionó bien. De hecho el resultado es el siguiente:
Aún no estamos satisfechos con el comportamiento de la Metadata. Aunque funciona no enviarla y sustituirla, a veces hay quienes pueden escuchar la radio con metadata sin problemas. Por otra parte los programas que se transmiten en diferido deben ser identificados.
Solución: dos emisoras: una CON metadata y una SIN metadata. Se sustituye el script para que quede así:
# la radio es un conjunto de relevos de puntos de montaje
radio = transicion(vivo,podcasts)
# la que tiene metadata es simplemente, la radio infalible (mksafe)
radio_metadata = mksafe(radio);
# la que no lleva metadata necesita ser limpiada
radio =add(normalize=false,[blank(),radio])
radio = rewrite_metadata([("title","Lee los títulos de las canciones en irc.radiognu.org")],radio)
y se transmiten dos radios. En el Script Actual se ve el resultado.
Por lo anteriormente mencionado y de acuerdo con el acuerdo notariado de las partes afectadas, se declara el siguiente Script:
#!/usr/bin/liquidsoap
# Realizado para RadioGNU
# ---- CONFIGURACIONES
set("log.file.path","/home/radiognu/liquidsoap/liquidsoap.log")
set("log.level",3)
# Lista de programas en diferido, se cargan al azar y cada "ronda"
podcasts=playlist("/home/radiognu/liquidsoap/podcasts.txt")
# Audio proveniente de los (presuntos) locutores, es decir, transmisiones en vivo
vivo =input.http("http://radiognu.org:8000/vivo.ogg")
vivo2 =input.http("http://radiognu.org:8000/vivo2.ogg")
#vivo = input.http("http://ctmcorp.no-ip.org/live.ogg")
#identif=single("estas_escuchando.ogg")
# Transicion. Con esto pasan inadvertidas las interrupciones instantáneas de los programas en vivo.
def transicion(vivo,podcasts)
def immediate(vivo,podcasts)
podcasts
end
def delayed(vivo,podcasts)
sequence([blank(duration=10.),podcasts])
end
fallback(track_sensitive=false,[vivo,vivo2,podcasts],transitions=[immediate,immediate,delayed])
end
# definimos la radio
radio=transicion(vivo,podcasts)
# una radio con metadata se transmitirá en "/radiognu_metadata.ogg"
radio_metadata=mksafe(radio);
# limpiamos correctamente la metadata
radio =add(normalize=false,[blank(),radio])
radio = rewrite_metadata([("title","Lee los títulos de las canciones en irc.radiognu.org")],radio)
# Salidas al ICECAST
# Salida general al publico: radiognu.ogg
output.icecast.vorbis(mount="radiognu.ogg",
samplerate=44100,
stereo=false,
password="",
port=8000,
name="RadioGNU",
description="La emisora del GNU que te da nota",
genre="Live Libre :-)",
url="http://radiognu.org:8000/radiognu.ogg",
quality=3.0,
radio)
# RadioGNU CON METADATA
output.icecast.vorbis(mount="radiognu_metadata.ogg",
samplerate=44100,
stereo=false,
password="",
port=8000,
name="RadioGNU",
description="La emisora del GNU que te da nota",
genre="Live Libre :-)",
url="http://radiognu.org:8000/radiognu.ogg",
quality=3.0,
radio_metadata)
# Segunda Salida al publico con menos ancho de banda (sin metadata): radiognu2.ogg
output.icecast.vorbis(mount="radiognu2.ogg",
samplerate=22050,
stereo=false,
password="",
port=8000,
name="RadioGNU Descremado (para poco ancho de banda)",
description="La emisora del GNU que te da nota (version para poco ancho de banda)",
genre="Live Libre :-)",
url="http://radiognu.org:8000/radiognu2.ogg",
quality=0.0,
radio)
El script anterior da el resultado deseado: permite que mientras se transmite en vivo haya un tiempo prudencial de espera antes de que se haga el cambio hacia los PODCASTS en diferido. Esto hace que las interrupciones menores por conexión de los locutores pase totalmente inadvertida, salvo por un par de segundos en silencio. En total son 7 segundos de espera antes de dar comienzo a los podcasts en diferido.
Ya que están cubiertos ciertos detalles en nuestro script, ahora debemos enfocarnos a otro pendiente: la programación automática de la Radio, es decir, mientras no haya una transmisión en vivo, debe estar sonando un PODCAST, pero no al azar como está ahora, sino con una programación, ya establecida por Héctor… A aportar para el script…!!!