9

完全に正常に動作するラジオアプリを作成しました。ラジオ ストリームを再生し、メタデータも取得できます。ストリーミング サービスは、shoutcast によるものです。

唯一の問題は、URL をデータ ソースとしてメディア プレーヤーに追加し、タイトルとアーティストを 5 秒ごとに取得していることです。

1 つの HTTP リクエストを作成して、オーディオとメタデータを分割し、メディア プレーヤーに送信する方法はありますか?

メタデータを取得するためのコード。

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

そして、URLをメディアプレーヤーのデータソースに渡します

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();
}
4

1 に答える 1

2

あなたが達成しようとする仕事は、簡単にできるものではありません。(不可能ではありません。)ストリームのメタデータは、ストリームの開始時にのみ「ダウンロード」されるため、後で変更しても、ストリームから「キャッシュ」されたメタ情報を読み取ることはできません。新しいプロパティを読み取るには、ストリームを再起動する必要があります。これにより、新しいヘッダーなどが取得されます (ただし、ストリームが中断される可能性があるため、あまりお勧めしません)。

サウンド技術では、透かしを使用するのが一般的です。これは、(品質を)破壊しない方法で、ある種のデータを使用してサウンドを豊かにするプロセスです。( YouTube での使用。 ) 難しいことですが、ストリーム内で自分の情報を非表示にする方法がいくつかあります。達成したい目標を達成するために、これを読むことをお勧めします。

ハードウェアは携帯電話であり、すべての Android デバイスが十分に強力であるとは限らないため、いくつかの新しい HTTP リクエストを検討する必要があります。オーディオ処理は、CPU、メモリなどの点で言えば安価なものではありません。そうする場合、考慮すべき他のオプションがいくつかあります。5 秒間のポーリングは、情報を取得するための最良の方法ではありません。ユーザーに虚偽の情報を表示する可能性があり、虚偽の情報は何もないよりも悪いからです。mqtt に基づくサーバー側のプッシュをお勧めします。これはかなり良い使用例ですポーリングの代わりにこの方法に基づくソリューションは、使用するトラフィックが少なく、より正確です。

于 2016-06-16T07:29:42.933 に答える