2011-02-06 10 views
17

¿Es posible extraer información de la pista de una transmisión de audio mediante PHP? He hecho algunas excavaciones y la función más cercana que puedo encontrar es stream_get_transports, pero mi host no admite transportes http a través de fsockopen(), así que tendré que hacer algunos retoques para ver qué más devuelve esa función.Extracción de la información de la pista de una secuencia de audio mediante PHP

Actualmente, intento sacar al artista y rastrear los metadatos de una transmisión de AOL.

+0

¿Qué tipo de flujo de audio? –

+0

http://scfire-dtc-aa01.stream.aol.com:80/stream/1003. Esa URL específicamente, pero estoy extrayendo mis datos de una lista de reproducción importada digitalmente (archivo pls). –

+1

Creo que vi algunas clases de procesamiento de audio para metaetiquetas de etiquetas mp3 y similares en phpclasses.org. Echar un vistazo. Hay muchas cosas buenas y, sin saber más sobre qué datos quieres, es difícil recomendar algo específico. –

Respuesta

44

Esta es una transmisión SHOUTcast, y sí es posible. No tiene absolutamente nada que ver con las etiquetas ID3. Hace un tiempo escribí un guión para hacer esto, pero ya no lo puedo encontrar. La semana pasada, ayudé a otro chico que tenía un guión bastante completo a hacer lo mismo, pero no puedo simplemente publicar la fuente, ya que no es mío. Sin embargo, lo pondré en contacto con él, si me envía un correo electrónico al [email protected].

De todos modos, aquí está cómo hacerlo usted mismo:

Lo primero que hay que hacer es conectarse al servidor directamente. No use HTTP. Bueno, probablemente puedas usar cURL, pero es probable que sea mucho más complicado de lo que vale. Se conecta a él con fsockopen() (doc). Asegúrate de usar el puerto correcto. También tenga en cuenta que muchos servidores web bloquearán muchos puertos, pero generalmente puede usar el puerto 80. Afortunadamente, todas las transmisiones SHOUTcast alojadas en AOL usan el puerto 80.

Ahora haga su pedido como lo haría su cliente.

GET /whatever HTTP/1.0

Pero, antes de enviar <CrLf><CrLf>, incluyen esta nueva cabecera!

Icy-MetaData:1

que le dice al servidor que desea metadatos. Ahora, envíe su par de <CrLf>.

Ok, el servidor responderá con un montón de encabezados y luego comenzará a enviarle datos. En esos encabezados habrá un icy-metaint:8192 o similar. Ese 8192 es el meta intervalo. Esto es importante, y realmente el único valor que necesitas. Por lo general es 8192, pero no siempre, así que ¡asegúrese de leer este valor!

Básicamente significa que obtendrá 8192 bytes de datos MP3 y luego un trozo de meta, seguido de 8192 bytes de datos MP3, seguidos de un trozo de meta.

Lea 8192 bytes de datos (asegúrese de no incluir el encabezado en este recuento), deséchelos y luego lea el siguiente byte. Este byte es el primer byte de metadatos e indica cuánto tiempo son los metadatos. Tome el valor de este byte (el byte real con ord() (doc)) y multiplíquelo por 16. El resultado es el número de bytes para leer para los metadatos. Lee esa cantidad de bytes en una variable de cadena para que puedas trabajar.

A continuación, recorte el valor de esta variable. ¿Por qué? Debido a que la cadena está acolchada con 0x0 al final (para que se ajuste uniformemente en un múltiplo de 16 bytes), y trim() (doc) se encarga de eso para nosotros.

se le dejó con algo como esto:

StreamTitle='Awesome Trance Mix - DI.fm';StreamUrl=''

te dejaré escoger su método de elección para analizar esto. Personalmente, probablemente solo me dividiría con un límite de 2 en ;, pero ten cuidado con los títulos que contienen ;. No estoy seguro de cuál es el método del personaje de escape. Un poco de experimentación debería ayudarte.

¡No olvide desconectarse del servidor cuando haya terminado con él!

Hay muchas referencias de metadatos SHOUTcast por ahí. Esta es una buena: http://www.smackfu.com/stuff/programming/shoutcast.html

+2

Maravilloso relato. +1 más la respuesta de crédito –

+0

realmente genial, ¡gracias! – 23tux

+0

realmente agradable, gracias! – EnrageDev

13

mira esto: https://gist.github.com/fracasula/5781710

Es un poco lo esencial con una función de PHP que le permite extraer metadatos MP3 (StreamTitle) a partir de una URL de transmisión.

Normalmente, el servidor de transmisión pone un encabezado icy-metaint en la respuesta, que nos dice con qué frecuencia se envían los metadatos en la transmisión. La función busca ese encabezado de respuesta y, si está presente, reemplaza el parámetro de intervalo con él.

De lo contrario, la función llama al URL de transmisión respetando su intervalo y, si no hay metadatos presentes, intenta nuevamente a través de la recursión a partir del parámetro de desplazamiento.

<?php 

/** 
* Please be aware. This gist requires at least PHP 5.4 to run correctly. 
* Otherwise consider downgrading the $opts array code to the classic "array" syntax. 
*/ 
function getMp3StreamTitle($streamingUrl, $interval, $offset = 0, $headers = true) 
{ 
    $needle = 'StreamTitle='; 
    $ua = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.110 Safari/537.36'; 

    $opts = [ 
      'http' => [ 
      'method' => 'GET', 
      'header' => 'Icy-MetaData: 1', 
      'user_agent' => $ua 
     ] 
    ]; 

    if (($headers = get_headers($streamingUrl))) { 
     foreach ($headers as $h) { 
      if (strpos(strtolower($h), 'icy-metaint') !== false && ($interval = explode(':', $h)[1])) { 
       break; 
      } 
     } 
    } 

    $context = stream_context_create($opts); 

    if ($stream = fopen($streamingUrl, 'r', false, $context)) { 
     $buffer = stream_get_contents($stream, $interval, $offset); 
     fclose($stream); 

     if (strpos($buffer, $needle) !== false) { 
      $title = explode($needle, $buffer)[1]; 
      return substr($title, 1, strpos($title, ';') - 2); 
     } else { 
      return getMp3StreamTitle($streamingUrl, $interval, $offset + $interval, false); 
     } 
    } else { 
     throw new Exception("Unable to open stream [{$streamingUrl}]"); 
    } 
} 

var_dump(getMp3StreamTitle('http://str30.creacast.com/r101_thema6', 19200)); 

Espero que esto ayude!

+0

Error de análisis: error de sintaxis, inesperado '[' en C: \ wamp \ www \ stream \ index.php en la línea 8 – AtanuCSE

+2

Tiene que usar al menos PHP 5.4. De lo contrario, intente convertir la matriz '$ opts' utilizando la sintaxis clásica' array'. –

+0

Excelente trabajo! – Zl3n

0

Muchas gracias por el código fra_casula. Aquí hay una versión ligeramente simplificada que se ejecuta en PHP < = 5.3 (el original está dirigido a 5.4). También reutiliza el mismo recurso de conexión.

He eliminado la excepción debido a mis propias necesidades, devolviendo el valor falso si no se encuentra nada.

private function getMp3StreamTitle($steam_url) 
    { 
     $result = false; 
     $icy_metaint = -1; 
     $needle = 'StreamTitle='; 
     $ua = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.110 Safari/537.36'; 

     $opts = array(
      'http' => array(
       'method' => 'GET', 
       'header' => 'Icy-MetaData: 1', 
       'user_agent' => $ua 
      ) 
     ); 

     $default = stream_context_set_default($opts); 

     $stream = fopen($steam_url, 'r'); 

     if($stream && ($meta_data = stream_get_meta_data($stream)) && isset($meta_data['wrapper_data'])){ 
      foreach ($meta_data['wrapper_data'] as $header){ 
       if (strpos(strtolower($header), 'icy-metaint') !== false){ 
        $tmp = explode(":", $header); 
        $icy_metaint = trim($tmp[1]); 
        break; 
       } 
      } 
     } 

     if($icy_metaint != -1) 
     { 
      $buffer = stream_get_contents($stream, 300, $icy_metaint); 

      if(strpos($buffer, $needle) !== false) 
      { 
       $title = explode($needle, $buffer); 
       $title = trim($title[1]); 
       $result = substr($title, 1, strpos($title, ';') - 2); 
      } 
     } 

     if($stream) 
      fclose($stream);     

     return $result; 
    } 
0

Este es el código C# para obtener los metadatos utilizando HttpClient:

public async Task<string> GetMetaDataFromIceCastStream(string url) 
    { 
     m_httpClient.DefaultRequestHeaders.Add("Icy-MetaData", "1"); 
     var response = await m_httpClient.GetAsync(url, HttpCompletionOption.ResponseHeadersRead); 
     m_httpClient.DefaultRequestHeaders.Remove("Icy-MetaData"); 
     if (response.IsSuccessStatusCode) 
     { 
      IEnumerable<string> headerValues; 
      if (response.Headers.TryGetValues("icy-metaint", out headerValues)) 
      { 
       string metaIntString = headerValues.First(); 
       if (!string.IsNullOrEmpty(metaIntString)) 
       { 
        int metadataInterval = int.Parse(metaIntString); 
        byte[] buffer = new byte[metadataInterval]; 
        using (var stream = await response.Content.ReadAsStreamAsync()) 
        { 
         int numBytesRead = 0; 
         int numBytesToRead = metadataInterval; 
         do 
         { 
          int n = stream.Read(buffer, numBytesRead, 10); 
          numBytesRead += n; 
          numBytesToRead -= n; 
         } while (numBytesToRead > 0); 

         int lengthOfMetaData = stream.ReadByte(); 
         int metaBytesToRead = lengthOfMetaData * 16; 
         byte[] metadataBytes = new byte[metaBytesToRead]; 
         var bytesRead = await stream.ReadAsync(metadataBytes, 0, metaBytesToRead); 
         var metaDataString = System.Text.Encoding.UTF8.GetString(metadataBytes); 
         return metaDataString; 
        } 
       } 
      } 
     } 

     return null; 
    } 
Cuestiones relacionadas