2016-05-31 26 views
8

Ich habe eine Radio-App gemacht, die ganz gut funktioniert. Ich kann den Radio-Stream abspielen und die Metadaten auch abrufen. Der Streaming-Dienst ist von Shoutcast.Wie kann ich die Metadaten und den Track von einem Shoutcast-Stream trennen, ohne separate Anfrage für Metadaten und das Streaming

Das einzige Problem ist, dass ich die URL als Datenquelle zum Media Player hinzufügen und dann den Titel und den Künstler alle 5 Sekunden holen.

Gibt es eine Möglichkeit, kann ich nur eine http-Anfrage machen und dann teilen Sie die Audio-und Metadaten und dann an den Media-Player senden?

Code zum Abrufen von Metadaten.

private void retreiveMetadata() throws IOException { 

    int metaDataOffset = 0; 

    OkHttpClient client = new OkHttpClient(); 
    Request request = new Request.Builder() 
     .addHeader("Icy-MetaData", "1") 
     .addHeader("Connection", "close") 
     .addHeader("Accept", "") 
     .url(streamUrl) 
     .build(); 

    request.headers(""); 


    Response response = client.newCall(request).execute(); 
    InputStream stream = response.body().byteStream(); 

    //Map<String, List<String>> headers = response..getHeaderFields(); 

    if (!response.headers("icy-metaint").equals("")) { 
     // Headers are sent via HTTP 

     String icyMetaInt = response.headers("icy-metaint").toString(); 
     icyMetaInt = icyMetaInt.replace("[", ""); 
     icyMetaInt = icyMetaInt.replace("]", ""); 

     metaDataOffset = Integer.parseInt(icyMetaInt); 
    } 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 static Map<String, String> parseMetadata(String metaString) { 
    Map<String, String> metadata = new HashMap(); 
    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; 
} 

Und die URL der Datenquelle des Spielers Medien vorbei

String url = "http://68.68.109.106:8356/"; 
mp = new MediaPlayer(); 
mp.setAudioStreamType(AudioManager.STREAM_MUSIC); 
try { 

    mp.setDataSource(url); 
    mp.prepare(); 

} catch (IllegalArgumentException e) { 
    // TODO Auto-generated catch block 
    e.printStackTrace(); 
    Toast.makeText(context, e.toString(), Toast.LENGTH_SHORT).show(); 
} catch (SecurityException e) { 
    // TODO Auto-generated catch block 
    Log.e(TAG, "SecurityException"); 
    Toast.makeText(context, e.toString(), Toast.LENGTH_SHORT).show(); 
} catch (IllegalStateException e) { 
    // TODO Auto-generated catch block 
    Log.e(TAG, "IllegalStateException"); 
    Toast.makeText(context, e.toString(), Toast.LENGTH_SHORT).show(); 
} catch (IOException e) { 
    // TODO Auto-generated catch block 
    Log.e(TAG, "IOException"); 
    Toast.makeText(context, e.toString(), Toast.LENGTH_SHORT).show(); 
} 
+0

Ja, Sie müssen nur die Metadaten aus dem Stream demuxen. Siehe diese Antwort für weitere Details: http://stackoverflow.com/questions/4911062/pulling-track-info-from-an-audio-stream-using-php/4914538#4914538 Wenn Sie eine spezifische Antwort für Java auf Android wollen , sollten Sie Ihren Code zeigen, wie Sie die Stream-Daten derzeit erhalten. – Brad

+0

@Brad Siehe meine aktualisierte Antwort. Vielen Dank. – Searock

Antwort

1

Die Aufgabe, die Sie versuchen zu erreichen ist nicht etwas, das einfach zu tun ist. (Das ist nicht unmöglich.) Die Metadaten des Streams werden nur beim Start des Streams "heruntergeladen", so dass ein späteres Ändern der Metainformationen "zwischengespeichert" aus dem Stream keinen Effekt hätte. Um die neuen Eigenschaften zu lesen, muss der Stream neu gestartet werden, damit die neuen Header usw. geladen werden (aber es könnte eine Unterbrechung im Stream verursachen, daher ist es nicht wirklich empfehlenswert.)

In Sound-Technologie ist es üblich zu verwenden watermarking. Es ist ein Prozess, bei dem Sie Ihren Sound mit einer Art von Daten auf nicht zerstörende Art und Weise anreichern. (Usage on youtube.) Altogh es ist schwer zu tun, es gibt einige Möglichkeiten, um Ihre Informationen im Stream zu verstecken. Ich empfehle, this zu lesen, um das Ziel zu erreichen, das Sie erreichen möchten.

Da Ihre Hardware ein Mobiltelefon ist und nicht alle Android-Geräte stark genug sind, sollten Sie einige neue http-Anfragen berücksichtigen. Die Audioverarbeitung ist keine billige Sache, die hinsichtlich CPU, Speicher usw. spricht. Es gibt einige andere Optionen, die in Betracht gezogen werden sollten, wenn Sie dies tun. Die fünf Sekunden Abfrage ist nicht der beste Weg, um die Informationen zu erhalten, weil Sie falsche Informationen für den Benutzer anzeigen können und falsche Informationen schlechter als nichts sind. Ich empfehle einen serverseitigen Push basierend auf mqtt. Here ist ein schönes Beispiel für die Verwendung. Eine Lösung, die auf dieser Methode basiert, verwendet weniger Verkehr und ist genauer.