Administración del Audio con LiquidSoap

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.

Script Inicial

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)))

Investigación

Aporte de Hector

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.

Soluciones Propuesta por Hackers de LiquidSoap

(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.

Más de una fuente de audio en VIVO

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:

  1. Primera prioridad: suena “vivo.ogg” y cada vez que aparezca el punto de montaje sobreescribirá a los demás
  2. Segunda prioridad: suena “vivo2.ogg” y si aparece “vivo.ogg” será relevado.
  3. Tercera prioridad: suena el playlist y será relevado por “vivo.ogg” o “vivo2.ogg” apenas aparezcan. Se espera 10 segundos hasta que suene de nuevo

Metadata en los programas

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.

Script Actual

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)

¡ Y funcionó !

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.

Programación de Programas en Diferido (Pendiente)

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…!!!

 
liquidsoap.txt · Last modified: 2010/08/18 18:51 by tr0n
 
Except where otherwise noted, content on this wiki is licensed under the following license:CC Attribution-Noncommercial-Share Alike 3.0 Unported
Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki