2011-02-06 17 views
17

Czy można pobrać informacje o ścieżce ze strumienia audio za pomocą PHP? Zrobiłem trochę kopania i najbliższą funkcją jaką mogę znaleźć jest stream_get_transports, ale mój host nie obsługuje transportu http przez fsockopen(), więc będę musiał zrobić więcej majstrowania, aby zobaczyć, co jeszcze ta funkcja zwraca.Pobieranie informacji o ścieżce ze strumienia audio przy użyciu PHP

Obecnie próbuję pobrać artystę i śledzić metadane ze strumienia AOL.

+0

Jakie strumień audio? –

+0

http://scfire-dtc-aa01.stream.aol.com:80/stream/1003. Ten adres URL jest konkretny, ale pobieram moje dane z listy odtwarzania w formacie Digitally Imported (plik pls). –

+1

Myślę, że widziałem niektóre klasy przetwarzania dźwięku dla tagów mp3 meta info i tym podobne na phpclasses.org. Spójrz. Istnieje wiele dobrych rzeczy i nie wiedząc więcej o tym, jakie dane chcesz, trudno jest polecić coś konkretnego. –

Odpowiedz

44

To jest strumień SHOUTcast, i tak jest to możliwe. Nie ma absolutnie nic wspólnego z tagami ID3. Napisałem skrypt jakiś czas temu, aby to zrobić, ale nie mogę go już znaleźć. W ubiegłym tygodniu pomogłem innemu facetowi, który miał dość kompletny scenariusz, zrobić to samo, ale nie mogę po prostu opublikować źródła, ponieważ nie jest moje. Jednak skontaktuję się z Tobą, jeśli wyślesz mi e-mail pod numer [email protected].

W każdym razie, oto jak to zrobić samemu:

Pierwszą rzeczą, którą trzeba zrobić, to podłączyć bezpośrednio do serwera. Nie używaj protokołu HTTP. Prawdopodobnie możesz użyć cURL, ale prawdopodobnie będzie to o wiele trudniejsze niż jego wartość. Połącz się z nim za pomocą fsockopen() (doc). Upewnij się, że używasz właściwego portu. Zauważ też, że wiele hostów internetowych blokuje wiele portów, ale zazwyczaj możesz użyć portu 80. Na szczęście wszystkie strumienie SHOUTcast hostowane przez AOL używają portu 80.

Teraz, zrób swoją prośbę tak, jak zrobiłby to twój klient.

GET /whatever HTTP/1.0

Jednak przed wysłaniem <CrLf><CrLf>, to ten następny nagłówek!

Icy-MetaData:1

To informuje serwer, który chcesz metadanych. Teraz wyślij swoją parę <CrLf>.

OK, serwer odpowie grupą nagłówków, a następnie rozpocznie przesyłanie danych. W tych nagłówkach będzie icy-metaint:8192 lub podobny. To 8192 jest przedziałem meta przedział. Jest to ważne i naprawdę jedyna wartość, której potrzebujesz. Zwykle jest to 8192, ale nie zawsze, więc koniecznie przeczytaj tę wartość!

Zasadniczo oznacza to, że otrzymasz 8192 bajtów danych MP3, a następnie fragment meta, a następnie 8192 bajtów danych MP3, a następnie fragment meta.

Odczytaj 8192 bajtów danych (upewnij się, że nagłówek nie zawiera nagłówka), odrzuć je, a następnie odczytaj następny bajt. Ten bajt jest pierwszym bajtem metadanych i wskazuje, jak długie są dane meta. Pobierz wartość tego bajtu (rzeczywisty bajt z ord() (doc)) i pomnóż go przez 16. Wynik jest liczbą bajtów do odczytania dla metadanych. Odczytaj tę liczbę bajtów w zmiennej łańcuchowej, abyś mógł z nią pracować.

Następnie przycinaj wartość tej zmiennej. Czemu? Ponieważ ciąg jest dopełniany na końcu pod 0x0 (aby zmieścił się równomiernie w wielokrotności 16 bajtów), i trim() (doc) zajmuje się tym dla nas.

Będziesz lewo z czegoś takiego:

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

dam wybrać metodę z wyboru w celu analizowania tego. Osobiście prawdopodobnie po prostu podzieliłbym limit na 2 na ;, ale uważaj na tytuły, które zawierają ;. Nie jestem pewien, jaka jest metoda znaku ucieczki. Trzeba trochę eksperymentować.

Nie zapomnij rozłączyć się z serwerem, gdy skończysz!

Istnieje wiele referencji SHOUTcast MetaData tam. To jest dobry: http://www.smackfu.com/stuff/programming/shoutcast.html

+2

Cudowny zapis. +1 plus odpowiedź: –

+0

Naprawdę fajnie, thx! – 23tux

+0

Naprawdę ładne, dzięki! – EnrageDev

13

to sprawdzić: https://gist.github.com/fracasula/5781710

To trochę Istota z funkcji PHP, który pozwala wyodrębnić metadanych MP3 (StreamTitle) z adresem URL streamingu.

Zazwyczaj serwer przesyłania strumieniowego umieszcza nagłówek icy-metaint w odpowiedzi, informujący o częstotliwości wysyłania metadanych do strumienia. Funkcja sprawdza nagłówek odpowiedzi i, jeśli jest obecny, zastępuje go parametrem interwału.

W przeciwnym razie funkcja wywoła adres URL strumienia z uwzględnieniem interwału, a jeśli nie ma żadnych metadanych, próbuje ponownie od rekursji rozpoczynając od parametru przesunięcia.

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

Mam nadzieję, że to pomoże!

+0

Błąd analizy składni: błąd składni, nieoczekiwane "[" w C: \ wampie \ www \ stream \ index.php na linii 8 – AtanuCSE

+2

Musisz użyć co najmniej PHP 5.4. W przeciwnym razie spróbuj przekonwertować tablicę '$ opts' używając klasycznej składni' array'. –

+0

Doskonała robota! – Zl3n

0

Wielkie dzięki za kod fra_casula. Oto nieco uproszczona wersja działająca pod PHP < = 5,3 (oryginał jest ukierunkowany na 5.4). Wykorzystuje także ten sam zasób połączenia.

Usunąłem wyjątek ze względu na moje własne potrzeby, zwracając wartość false, jeśli nic nie zostanie znalezione.

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

Jest to kod C# dla uzyskania metadane przy użyciu 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; 
    } 
Powiązane problemy