2016-05-31 11 views
8

Ho creato un'app radio che funziona perfettamente. Sono in grado di riprodurre il flusso radio e recuperare anche i metadati. Il servizio di streaming è da shoutcast.Come faccio a separare i metadati e la traccia da un flusso di shoutcast senza effettuare una richiesta separata per i metadati e lo streaming

L'unico problema è che sto aggiungendo l'url come origine dati al lettore multimediale e quindi recuperando il titolo e l'artista ogni 5 secondi.

C'è un modo, posso solo fare una richiesta http e quindi dividere l'audio e i metadati e quindi inviarlo al lettore multimediale?

Codice per il recupero dei metadati.

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; 
} 

E passando l'url all'origine dati del lettore multimediale

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

Sì, è sufficiente demule i metadati dallo streaming. Vedi questa risposta per maggiori dettagli: http://stackoverflow.com/questions/4911062/pulling-track-info-from-an-audio-stream-using-php/4914538#4914538 Se vuoi una risposta specifica per Java su Android , dovresti mostrare il tuo codice su come stai attualmente ricevendo i dati del flusso. – Brad

+0

@Brad Vedi la mia risposta aggiornata. Grazie. – Searock

risposta

1

Il compito si tenta di ottenere non è qualcosa che è facile da fare. (Anche se non è impossibile.) I metadati del flusso vengono "scaricati" solo all'inizio dello stream, quindi cambiandolo in seguito non avrebbe alcun effetto leggendo le metainformazioni "memorizzate nella cache" dallo stream. Per leggere le nuove proprietà è necessario riavviare il flusso, questo preleverà le nuove intestazioni ecc. (Ma potrebbe causare un'interruzione nello stream, quindi non è consigliabile.)

Nella tecnologia audio è comune utilizzare watermarking. È un processo in cui arricchisci il tuo suono con alcuni tipi di dati nel modo non distruttivo (di qualità). (Usage on youtube.) Altogh è difficile da fare, ci sono alcuni modi per nascondere le tue informazioni nello stream. Raccomando di leggere this per raggiungere l'obiettivo che si desidera raggiungere.

Poiché l'hardware è un telefono cellulare e non tutti i dispositivi Android sono abbastanza potenti, è necessario prendere in considerazione alcune nuove richieste HTTP. L'elaborazione audio non è una cosa economica che parla in termini di CPU, memoria, ecc. Ci sono altre opzioni da considerare se lo fai. I cinque secondi di polling non sono il modo migliore per ottenere le informazioni, perché è possibile visualizzare informazioni false all'utente e le informazioni false sono peggio di niente. Raccomando un push lato server basato su mqtt. Here è un bell'esempio di utilizzo. Una soluzione basata su questo metodo di polling utilizza meno traffico ed è più accurata.

Problemi correlati