SHOUTcastについて調べてみる

このページの趣旨

 SecondLife内で、今聴いているネットラジオの曲情報(曲名やアーティスト名)を取得する方法を模索することです。現在1)、LSLとPHPを連携させ取得することには成功していますが、外部サーバにかかる負荷が大きく実用的ではないことから、もっと別の方法があるのではないかと試行錯誤中です。

 このページでは、「ネットラジオ = SHOUTcast」という前提で話を進めています。ちなみに、SHOUTcastとは、世界中で最も広く使われているオンデマンド・ライブストリーミング配信アプリケーションの1つです。

 SHOUTcastに関する日本語情報は「あたまにきたどっとこむ-超図解!誰でも始められるネットラジオ SHOUTcast編」が解りやすいと思いますのでそちらを参考にしてください(arz NitelyはSHOUTcastを導入したことはありませんので質問にはお答えできません…)。

SHOUTcastにおけるメタデータ送受信

メタデータとは?

 一言で言うと「データについてのデータ」ということになります。そのデータがどういうものであるのかを表すインデックス的な情報で、データの作者、作成日時、ファイル形式などであることが一般的です。ココで言うメタデータとは、「今聴いているネットラジオの曲名(とアーティスト名)」を指します。

メタデータを受信するには?

 メタデータを受信するには「Icy-MetaData: 1」という値をHTTPリクエストヘッダーで送信する必要があります。

メタデータはどうやって送信される?

 曲データ(MP3データ)の間に割り込む形でメタデータが送信されてきます。前述の「Icy-MetaData: 1」を受け、ホストは「icy-metaint: ※※※」という値をレスポンスヘッダで送り返してきます。例えば「icy-metaint: 8192」であれば、8192byteごとにメタデータが割り込んで送られるわけです。

 通常のMP3ファイルにはID3タグによるメタ情報が埋め込まれているのですが、ストリーミング配信においてはID3情報は欠落するということです。従って、PHPのID3関数などを使ってメタ情報を取得する方法は使えません。

 また、曲と曲の境目に特別な信号が送られることがないため、厳密に曲が変わる瞬間に曲名を切り替えることは不可能です。経験的に言うと、曲の境目より前に、既に次の曲のメタ情報の送信が開始されているようです。

ホストへの接続

HTTPリクエストヘッダー

ホストへの接続はHTTP/1.0でOK。User-Agentは何であっても問題ないようです。

GET / HTTP/1.0
Host: (ホスト名)
User-Agent: (ソフト名など)
Accept: */*
Icy-MetaData:1

PHPでの接続例

$sc_host = "192.168.0.1";  // <- Modify as you need
$sc_port = "8080";  // <- Modify as you need
 
$server = fsockopen($sc_host, $sc_port, $errorno, $errormsg, 20);
 
if (is_resource($server)){
    $out = "GET / HTTP/1.0\r\n";
    $out .= "Host: gw\r\n";
    $out .= "Accept: */*\r\n";
    $out .= "User-Agent: PHP-".phpversion()."\r\n";
    $out .= "Icy-MetaData: 1\r\n";
    $out .= "Connection: close\r\n\r\n";
    fwrite($server, $out);
}

レスポンスヘッダー

 下記は実際にPHPで接続したときに受信したレスポンスヘッダーです。

ICY 200 OK
icy-notice1: <BR>This stream requires <a href="http://www.winamp.com/">Winamp</a><BR>
icy-notice2: Firehose Ultravox/SHOUTcast Relay Server/Linux v2.6.0<BR>
icy-name: S K Y . F M - Absolutely Smooth Jazz - the world's smoothest jazz 24 hours a day
icy-genre: Soft Smooth Jazz
icy-url: http://www.sky.fm/smoothjazz/
content-type: audio/mpeg
icy-pub: 1
icy-metaint: 16384
icy-br: 96

メタデータだけを取得したい場合

 上記「ホストへの接続」で接続した場合は、レスポンスヘッダーの後、実際にMP3データの受信が始まります。これをPHPで受けつつ、icy-metaintごとにメタデータを抽出しようとすると、かなりの無駄が生じてしまいます…(これが負荷増大の原因ですね)。また、LSLから直接接続したとしても、受け取れるレスポンスボディーのサイズが大きすぎて処理不能となってしまいます…(しかも、LSLからではIcy-MetaData: 1を送信できないし…)。そこで、今流れている曲名だけを取得する方法を紹介します。

7.htmlに接続

 7.htmlに接続すると、今流れている曲名だけを取得することが可能です。メタデータを取得し、整形し、LSLに返すには、この方法が最も有効だと言えます。また、現在はまだ成功していませんが、もっと研究を続けるとPHPを使わずにLSLから直接メタデータを抽出できるかもしれません。

 PHPからの接続は次のようにすると可能です。

$sc_host = "192.168.0.1";  // <- Modify as you need
$sc_port = "8080";  // <- Modify as you need
 
$server = fsockopen($sc_host, $sc_port, $errorno, $errormsg, 20);
 
if (is_resource($server)){
    $out = "GET /7.html HTTP/1.0\r\n";
    $out .= "Host: \r\n";
    $out .= "User-Agent: Mozilla\r\n";
    $out .= "Connection: close\r\n\r\n";
    fwrite($server, $out);
}

 さて、お気づきと思いますが、「ホストへの接続」のときと異なり、「User-Agent」は「Mozilla」になっています。今のところ「Mozilla」以外では成功していません。具体的に言いますと、Mozilla以外のUAで接続すると、「method = HEAD」として接続したと見なされるようで、「ホストへの接続」のときと同じレスポンスヘッダーが返されてしまいます(HEAD接続なので、もちろんBODYは空っぽです)。

 LSLから直接UAを偽装して接続する方法が現在のところわかりませんので(…というか、あるの??)、そこでつまずいているわけです…。

 さてさて、PHPから7.htmlに接続すると、次のようなレスポンスが返ってきます。

HTTP/1.0 200 OK
content-type:text/html
 
<HTML><meta http-equiv="Pragma" content="no-cache"></head><body>178,1,265,300,175,96,Miles Davis - The Ghetto Walk</body></html>

 はじめの2行はレスポンスヘッダで、3行目は空白、4行目のレスポンスボディーはHTMLとして返ってきていますね。body内部は左から順番に次のような情報を表しているようです。

レスポンスボディーの内容

  1. 現在のリスナー数
  2. (不明…)
  3. これまでのリスナー数の最大値
  4. 同時接続可能数
  5. (不明…)
  6. ビットレート
  7. アーティスト名 - 曲名

 というわけで…

PHPを用いた処理例

  1. PHPで7.htmlに接続
  2. レスポンスの4行目からHTMLタグを削除し変数に代入
  3. その値を半角コンマで分割
  4. 7番目の値をLSLに返す

 でOKですよねw

played.htmlに接続

 played.htmlに接続すると、最近流れた曲リストを取得することができます。これは、ウェブブラウザでストリーミングホストに接続しようとした場合に表示されるページと同じものです。HTMLソースが「7.html」に比べて複雑なので、こちらにアクセスしても処理が面倒なだけですね…。

 接続方法は7.htmlのときと同じです。「7.html」のところを「played.html」に変えるとPHPからアクセスすることが可能です。

現時点での問題点と今後の課題

LSL単独で可能か?

 LSLとPHPを連携させ、7.htmlからメタデータを取得し、それをSecondLife内で表示させることには成功しましたが、できればLSL単独で取得できた方が何かと無駄がありません。しかし、LSLから「UserAgentをMozillaと偽装」して接続することができないため、今のところ成功には至っていません。

URLの表記型によってはNG...

 SHOUTcastのホストに接続するためのURLの表記型には2種類あるようです。

URL表記型の種類

  1. http://192.168.0.1:8080
  2. http://example.com:80/path/to/stream/file/stream-ID

 1の型であれば、7.htmlに接続しメタデータを取得できるのですが、2の型ではどうも7.htmlに接続できないようです。今のところやったことは…

  1. 2の型のまま直接7.htmlにアクセス … NG
  2. ドメインからホストIP情報を取得 → 2の型を1の型に変換して7.htmlにアクセス … NG

 という感じです…。ポート番号とstream-IDのあたりが謎です…。このあたりをさらに研究し、まずは、両方のURL型において、PHPから7.htmlにアクセスし、メタデータを取得できるようになりたいものです(そのあと、LSL単独に挑戦かな〜w)。

1) 2008年11月のこと
最終更新: 2010年11月11日 04 : 05 by arz Nitely
http://arzNitely.com/lsl/study/shoutcast.html

Copyright 2007-2010 ©arzNitely.com all right reserved

www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0