2012-02-11 14 views
5

私は、SHOUTcastのmp3ストリームからメタデータを取得するAndroid用のアプリケーションを作成しています。私は私が少し修正したオンラインで見つけたかわいいクラスを使用していますが、私はまだ2つの問題があります。SHOUTcastからIcyStreamMetaを使用してメタデータを取得

1)TimerTaskを使用してメタデータを更新するためにサーバーにpingを継続しなければなりません。私はこのアプローチが好きではありませんが、それは私が考えることができるすべてでした。

2)私のアプリケーションの実行中にガベージコレクションのメトリックトンがあります。 TimerTaskを削除するとガベージコレクションの問題が解消されたので、間違っているのか、それとも正常であるのか分かりません。

public class IcyStreamMeta { 
    protected URL streamUrl; 
    private Map<String, String> metadata; 
    private boolean isError; 

public IcyStreamMeta(URL streamUrl) { 
    setStreamUrl(streamUrl); 

    isError = false; 
} 

/** 
* Get artist using stream's title 
* 
* @return String 
* @throws IOException 
*/ 
public String getArtist() throws IOException { 
    Map<String, String> data = getMetadata(); 

    if (!data.containsKey("StreamTitle")) 
     return ""; 

    try { 
     String streamTitle = data.get("StreamTitle"); 
     String title = streamTitle.substring(0, streamTitle.indexOf("-")); 
     return title.trim(); 
    }catch (StringIndexOutOfBoundsException e) { 
     return ""; 
    } 
} 

/** 
* Get title using stream's title 
* 
* @return String 
* @throws IOException 
*/ 
public String getTitle() throws IOException { 
    Map<String, String> data = getMetadata(); 

    if (!data.containsKey("StreamTitle")) 
     return ""; 

    try { 
     String streamTitle = data.get("StreamTitle"); 
     String artist = streamTitle.substring(streamTitle.indexOf("-")+1); 
     return artist.trim(); 
    } catch (StringIndexOutOfBoundsException e) { 
     return ""; 
    } 
} 

public Map<String, String> getMetadata() throws IOException { 
    if (metadata == null) { 
     refreshMeta(); 
    } 

    return metadata; 
} 

public void refreshMeta() throws IOException { 
    retreiveMetadata(); 
} 

private void retreiveMetadata() throws IOException { 
    URLConnection con = streamUrl.openConnection(); 
    con.setRequestProperty("Icy-MetaData", "1"); 
    con.setRequestProperty("Connection", "close"); 
    //con.setRequestProperty("Accept", null); 
    con.connect(); 

    int metaDataOffset = 0; 
    Map<String, List<String>> headers = con.getHeaderFields(); 
    InputStream stream = con.getInputStream(); 

    if (headers.containsKey("icy-metaint")) { 
     // Headers are sent via HTTP 
     metaDataOffset = Integer.parseInt(headers.get("icy-metaint").get(0)); 
    } else { 
     // Headers are sent within a stream 
     StringBuilder strHeaders = new StringBuilder(); 
     char c; 
     while ((c = (char)stream.read()) != -1) { 
      strHeaders.append(c); 
      if (strHeaders.length() > 5 && (strHeaders.substring((strHeaders.length() - 4), strHeaders.length()).equals("\r\n\r\n"))) { 
       // end of headers 
       break; 
      } 
     } 

     // Match headers to get metadata offset within a stream 
     Pattern p = Pattern.compile("\\r\\n(icy-metaint):\\s*(.*)\\r\\n"); 
     Matcher m = p.matcher(strHeaders.toString()); 
     if (m.find()) { 
      metaDataOffset = Integer.parseInt(m.group(2)); 
     } 
    } 

    // In case no data was sent 
    if (metaDataOffset == 0) { 
     isError = true; 
     return; 
    } 

    // Read metadata 
    int b; 
    int count = 0; 
    int metaDataLength = 4080; // 4080 is the max length 
    boolean inData = false; 
    StringBuilder metaData = new StringBuilder(); 
    // Stream position should be either at the beginning or right after headers 
    while ((b = stream.read()) != -1) { 
     count++; 

     // Length of the metadata 
     if (count == metaDataOffset + 1) { 
      metaDataLength = b * 16; 
     } 

     if (count > metaDataOffset + 1 && count < (metaDataOffset + metaDataLength)) {    
      inData = true; 
     } else {     
      inData = false;    
     }    
     if (inData) {    
      if (b != 0) {     
       metaData.append((char)b);    
      }   
     }    
     if (count > (metaDataOffset + metaDataLength)) { 
      break; 
     } 

    } 

    // Set the data 
    metadata = IcyStreamMeta.parseMetadata(metaData.toString()); 

    // Close 
    stream.close(); 
} 

public boolean isError() { 
    return isError; 
} 

public URL getStreamUrl() { 
    return streamUrl; 
} 

public void setStreamUrl(URL streamUrl) { 
    this.metadata = null; 
    this.streamUrl = streamUrl; 
    this.isError = false; 
} 

public static Map<String, String> parseMetadata(String metaString) { 
    Map<String, String> metadata = new HashMap<String, String>(); 
    String[] metaParts = metaString.split(";"); 
    Pattern p = Pattern.compile("^([a-zA-Z]+)=\\'([^\\']*)\\'$"); 
    Matcher m; 
    for (int i = 0; i < metaParts.length; i++) { 
     m = p.matcher(metaParts[i]); 
     if (m.find()) { 
      metadata.put((String)m.group(1), (String)m.group(2)); 
     } 
    } 

    return metadata; 
} 

}

そして、ここでは私のタイマーです:どのような援助のための

private void getMeta() { 
    timer.schedule(new TimerTask() { 
     public void run() { 
      try { 
       icy = new IcyStreamMeta(new URL(stationUrl)); 

       runOnUiThread(new Runnable() { 
        public void run() { 
         try { 
          artist.setText(icy.getArtist()); 
          title.setText(icy.getTitle()); 
         } catch (IOException e) { 
          e.printStackTrace(); 
         } catch (StringIndexOutOfBoundsException e) { 
          e.printStackTrace(); 
         } 
        } 
       }); 
      } catch (MalformedURLException e) { 
       e.printStackTrace(); 
      } 

     } 
    },0,5000); 

} 

多くの感謝の気持ちをここで

は、私が使用していたクラスです!

+0

私は 'icy = new IcyStreamMeta(新しいURL(stationUrl));'行を 'onCreate()'メソッドに移動し、ガベージコレクションの問題を修正しました。しかし、私のメタデータは更新されていません... – Karai17

+0

私は 'setText()'の前に 'icy.refreshMeta()'を呼んでいて、メタデータが再びリフレッシュされていますが、リフレッシュ間隔ごとにガベージコレクションがあります。これは悪いことですか?バッテリー寿命を延ばしますか? – Karai17

+0

http://pastie.org/3362717 – Karai17

答えて

3

プログラムのIcyStreamMetaクラスを置き換え、SHOUTcast仕様の一部である7.htmlファイルからメタデータを取得しています。データの使用量がそれほど少なくなくても、それはより良い選択肢だと感じています。

私はまだTimerTaskを使用していますが、それは受け入れられます。これ以上のGCは実質的になく、私は7.htmlと少し正規表現を使用して満足しています。 :)

+1

+1の7.html :) –

+2

関連項目:http://wiki.winamp.com/wiki/SHOUTcast_DNAS_Server_2_XML_Reponses –

+0

XMLレスポンスの問題は、それらにアクセスする管理モードでは、それらは公開されていません。これを直接使用するには、私のアプリにユーザー名とパスワードを埋め込む必要があります。これはセキュリティの問題だけでなく、近視眼的なものです。最終的に私がやったことは、JSON文字列として目的のXMLデータを公開するPHPスクリプトを設定し、15秒ごとにそれをポーリングしました。 – Karai17

関連する問題