2011-04-16 15 views
20

Me gustaría implementar un servidor en Python que transmita música en formato MP3 a través de HTTP. Me gustaría transmitir la música de modo que un cliente pueda conectarse a la transmisión y comenzar a escuchar lo que esté sonando actualmente, al igual que una estación de radio.Escribiendo un Python Music Streamer

Anteriormente, he implementado mi propio servidor HTTP en Python usando SocketServer.TCPServer (sí, sé que existe BaseHTTervidor, solo quería escribir una mini pila HTTP), entonces, ¿cómo sería un streamer musical diferente arquitectónicamente? ¿Qué bibliotecas necesitaría ver en el lado de la red y en el lado de MP3?

+0

¿Desea que cosas como VLC se puedan vincular a la transmisión o simplemente codifique su propio cliente? – thenoviceoof

+0

@thenoviceoof - gran pregunta, sí, me gustaría que los clientes "convencionales" puedan conectarse. iTunes, Winamp, VLC, etc. –

+0

¿Está comprimiendo el audio en tiempo real o reproduciendo archivos MP3 pre-creados? – rakslice

Respuesta

26

El formato mp3 fue diseñado para la transmisión, lo que hace que algunas cosas sean más simples de lo que podría haber esperado. La información es esencialmente una secuencia de audio frames con marcadores de límites incorporados, en lugar de un encabezado de archivo seguido de datos brutos. Esto significa que una vez que un cliente espera recibir datos de audio, puede comenzar a enviar bytes desde cualquier punto de una fuente mp3 existente, ya sea en vivo o en un archivo, y el cliente sincronizará hasta el siguiente cuadro que encuentre y comienza a reproducir audio ¡Hurra!

Por supuesto, tendrá que dar a los clientes una forma de configurar la conexión. El estándar de facto es el protocolo SHOUTcast (ICY). Esto es muy parecido a HTTP, pero con campos de estado y encabezado lo suficientemente diferentes como para que no sea directamente compatible con las bibliotecas de servidor http integradas de Python.Es posible que pueda hacer que esas bibliotecas hagan parte del trabajo por usted, pero sus interfaces documentadas no serán suficientes para hacerlo; Tendrás que leer su código para entender cómo hacer que hablen SHOUTcast.

Éstos son algunos enlaces para empezar:

http://forums.winamp.com/showthread.php?threadid=70403

http://forums.radiotoolbox.com/viewtopic.php?t=74

http://www.smackfu.com/stuff/programming/shoutcast.html

http://en.wikipedia.org/wiki/Shoutcast

Sugiero comenzar con un único archivo MP3 como origen de datos , obteniendo la configuración de conexión cliente-servidor yp layback trabajando, y luego pasando a temas como fuentes en vivo, múltiples tasas de bits de codificación, metadatos en banda y listas de reproducción.

Las listas de reproducción son generalmente archivos .pls o .m3u, y esencialmente solo archivos de texto estáticos que apuntan a la URL de su transmisión en vivo. No son difíciles y ni siquiera son estrictamente necesarios, ya que muchos (¿la mayoría?) Clientes de transmisión de mp3 aceptarán una URL de transmisión en vivo sin lista de reproducción en absoluto.

En cuanto a la arquitectura, el campo está bastante abierto. Tiene tantas opciones como hay para servidores HTTP. ¿Roscado? Procesos de trabajo? ¿Evento conducido? Tu decides. Para mí, la pregunta más interesante es cómo compartir los datos de una sola transmisión de entrada (la emisora) con los manejadores de red que sirven múltiples flujos de salida (los reproductores). Para evitar las complicaciones de IPC y sincronización, probablemente comenzaría con un diseño basado en eventos de un único subproceso. En python 2, una biblioteca como gevent le dará very good I/O performance y le permitirá estructurar su código de una manera muy comprensible. En python 3, preferiría asyncio coroutines.

+0

¿se transmitirían dinámicamente los datos .mp3 generados que requieren una programación avanzada de python? – MikeiLL

0

Querrá consultar los archivos m3u o pls. Eso debería darle un formato de archivo que los jugadores entienden lo suficientemente bien como para llegar a su servidor http en busca de archivos mp3.

Un archivo m3u mínimo sería simplemente un archivo de texto simple con una url de canción por línea. Asumiendo que usted tiene las siguientes URL disponible en el servidor:

/playlists/<playlist_name/playlist_id> 
/songs/<song_name/song_id> 

Se podría servir a una lista de reproducción desde la url:

/playlists/myfirstplaylist 

Y el contenido del recurso sería simplemente:

/songs/1 
/songs/mysong.mp3 

Un jugador (como Winamp) podrá abrir la URL del archivo m3u en su servidor HTTP y luego comenzará a transmitir la primera canción en la lista de reproducción. Todo lo que tendrá que hacer para respaldar esto es servir el archivo mp3 tal como lo haría con cualquier otro contenido estático.

Según la cantidad de clientes que desee admitir, es posible que desee buscar en IO asíncrono utilizando una biblioteca como Twisted para admitir toneladas de transmisiones simultáneas.

+4

Esto suena similar a SHOUTcast (http://en.wikipedia.org/wiki/SHOUTcast) que me gusta. Mi pregunta es: ¿cómo hago que funcione para que el archivo "playlist" sea solo una URL genérica que apunta a "transmitir" en lugar de a un archivo mp3 específico? Incluso si la URL es "/somefile.mp3", no quiero tener que generar una lista de reproducción con ** cada canción **.Más bien, quiero que sea un flujo continuo de canciones/comerciales, etc., al igual que una estación de radio. De hecho, ese es un gran ejemplo. ¿Cómo hacen las estaciones de radio desde sus sitios web, donde puede escuchar su transmisión en vivo allí? –

+0

Supongo que simplemente continúan escribiendo contenido de audio en la conexión http de los clientes. No hay ninguna razón para que una URL dada no pueda representar una secuencia infinita de datos. Si no cierra la conexión, el cliente seguirá escuchando para que, cuando termine de transmitir un archivo de canción, simplemente comience a escribir su comercial en el zócalo, y luego otra canción. ¿Puedes compartir algún código para que podamos echar un vistazo a tu servidor HTTP simple y tal vez hablar más concretamente sobre lo que tendrías que hacer? – stderr

+1

Esta respuesta no se refiere a "comenzar a escuchar lo que se está reproduciendo actualmente, al igual que una estación de radio". –

0

Usted querrá tener un archivo .m3u o .pls que apunta a un URI estática (por ejemplo, http://example.com/now_playing.mp3) y luego darles los datos mp3 comenzando dondequiera que estés en la canción cuando soliciten ese archivo. Probablemente hay un montón de problemas menores que estoy pasando por alto aquí ... Sin embargo, al menos como señala forest, puedes simplemente comenzar a transmitir los datos mp3 de cualquier byte.

+0

En realidad, prácticamente ** puede ** simplemente comenzar a transmitir datos mp3 a un cliente tan pronto como el cliente lo solicite. La codificación MP3 no usa un encabezado de archivo. –

+0

Hmm, interesante. Tienes razón, es cabecera/datos intercalados en todo el archivo. Sin embargo, eso haría perder cualquier etiqueta ID3, y mi punto principal es que probablemente no deberías simplemente comenzar en cualquier posición de byte para nada, tendrás que comenzar en uno de los encabezados. – mike

+0

Debería simplemente comenzar en cualquier posición de byte. El formato fue diseñado para eso exactamente. Los bits de sincronización están presentes en cada cuadro específicamente para ese propósito. –

1

Como usted ya tiene buena experiencia pitón (dado que ya ha escrito un servidor HTTP) sólo puedo ofrecer algunas sugerencias sobre cómo ampliar los trabajos de base que ya has hecho:

  • Prepare su servidor para que trata con Encabezados de solicitud como: Accept-Encoding, Range, TE (Transfer Encoding), etc. Un reproductor de MP3 sobre HTTP (es decir, VLC) no es más que un reproductor de mp3 que sabe cómo "hablar" HTTP y "buscar" diferentes posiciones en el archivo.

  • Uso de Wireshark o tcpdump para peticiones HTTP reales sniff realizados por VLC cuando se reproduce un archivo MP3 a través de HTTP, para que sepa cómo lo encabezados solicitud usted recibirá y ponerlas en práctica.

¡Buena suerte con su proyecto!