2016-05-31 16 views
8

Zrobiłem aplikację radiową, która działa idealnie dobrze. Mogę odtwarzać strumień radiowy i pobrać metadane. Usługa przesyłania strumieniowego jest z shoutcast.W jaki sposób oddzielić metadane od ścieżki od strumienia shoutcast bez składania osobnego wniosku o metadane i przesyłanie strumieniowe

Jedynym problemem jest to, że dodaję URL jako źródło danych do odtwarzacza multimedialnego, a następnie co 5 sekund ściągam tytuł i wykonawcę.

Czy jest jakiś sposób, mogę po prostu złożyć jedno zapytanie http, a następnie podzielić audio i metadane, a następnie wysłać je do odtwarzacza multimedialnego?

Kod do pobierania metadanych.

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

i przechodzącej url do źródła danych odtwarzacza multimedialnego

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

Tak, wystarczy usunąć demultipleksowanie metadanych ze strumienia. Zobacz tę odpowiedź, aby uzyskać więcej informacji: http://stackoverflow.com/questions/4911062/pulling-track-info-from-an-audio-stream-using-php/4914538#4914538 Jeśli potrzebujesz konkretnej odpowiedzi dla Javy na Androida , powinieneś pokazać swój kod, w jaki sposób otrzymujesz obecnie dane strumienia. – Brad

+0

@Brad Zobacz moją zaktualizowaną odpowiedź. Dzięki. – Searock

Odpowiedz

1

zadanie, które starają się osiągnąć nie jest czymś, co jest łatwe do zrobienia. (Nie jest to niemożliwe.) Metadane strumienia są "pobierane" tylko na początku strumienia, więc zmiana ich później nie miałaby wpływu na odczyt metainformacji "buforowanych" ze strumienia. Aby odczytać nowe właściwości, musisz ponownie uruchomić strumień, spowoduje to pobranie nowych nagłówków itp. (Ale może to spowodować przerwę w strumieniu, więc nie jest to zalecane).

W technologii dźwięku jest powszechne stosowanie watermarking. Jest to proces, w którym wzbogacasz swój dźwięk o jakieś dane w sposób niszczący (nie). (Usage on youtube.) Altogh trudno jest zrobić, jest kilka sposobów na ukrycie informacji w strumieniu. Polecam przeczytać this, aby osiągnąć cel, do którego chcesz dotrzeć.

Ponieważ twój sprzęt to telefon komórkowy, a nie wszystkie urządzenia z Androidem są wystarczająco silne, powinieneś rozważyć kilka nowych żądań http. Przetwarzanie dźwięku nie jest tanią rzeczą mówiącą o procesorze, pamięci itp. Istnieje kilka innych opcji, które należy rozważyć, jeśli to zrobisz. Pięciosekundowy sondowanie nie jest najlepszym sposobem uzyskania informacji, ponieważ możesz wyświetlać fałszywe informacje użytkownikowi, a fałszywe informacje są gorsze niż nic. Polecam push po stronie serwera oparty na mqtt. Here to całkiem ładny przykład użycia. Rozwiązanie oparte na tej metodzie, w której zastosowano polling, wykorzystuje mniejszy ruch i jest bardziej dokładne.