Aller au contenu

[TUTO] Récupération d'informations depuis un serveur Shoutcast/Winamp


emulienfou

Recommended Posts

Bonjour,

actuellement en cour de développement d'application pour une webradio, je partage avec toute la communauté FrAndroid mes sources qui pourront surement servir à d'autres personnes, je l'espère, permettant de lire un flux audio depuis un serveur de type IceCast et Shoutcast(utilisé par Winamp).

Fichier source PulsDroidScanner.java : Permet de gérer les TexView ainsi que l'url qui sera passée en paramètre

package com.test;

/**
* Copyright (C) 2011 <David SANCHEZ>
* 
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* 
* You should have received a copy of the GNU General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
* 
* Sources 	: http://uniqueculture.net/2010/11/stream-metadata-plain-java/
* 			: http://www.smackfu.com/stuff/programming/shoutcast.html
* 
* Test		: 2.1U1 	WORKING !
* 			: 2.2		WORKING !
* 			: 2.3		WORKING !
* 
*/

import java.net.MalformedURLException;
import java.net.URL;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
import android.widget.Toast;

public class PulsDroid_Scanner extends Activity {

static TextView tv1;
static TextView tv2;
static TextView tv3;
static TextView tv4;
static TextView tv5;
static TextView tv6;
static TextView tv7;
static TextView tv8;
static TextView tv9;
static TextView tv10;

static Toast toast;

   /** Called when the activity is first created. */
   @Override
   public void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.main);

       URL url = null;
	try {
		url = new URL ("http://stream8.pulsradio.com:6000/");

		 // inflate views
		tv1 = (TextView) this.findViewById(R.id.TextView01);
		tv2 = (TextView) this.findViewById(R.id.TextView02);
		tv3 = (TextView) this.findViewById(R.id.TextView03);
		tv4 = (TextView) this.findViewById(R.id.TextView04);
		tv5 = (TextView) this.findViewById(R.id.TextView05);
		tv6 = (TextView) this.findViewById(R.id.TextView06);
		tv7 = (TextView) this.findViewById(R.id.TextView07);
		tv8 = (TextView) this.findViewById(R.id.TextView08);
		tv9 = (TextView) this.findViewById(R.id.TextView09);
		tv10 = (TextView) this.findViewById(R.id.TextView10);

		// call asynchronous task classes
		new IcyAsyncMeta().execute(url);
		new IcyAsyncTitle().execute(url);

	} catch(MalformedURLException mue) {
	    Log.e("ERR", "Bad URL: " + mue.getMessage());
	} catch(Exception e) {
	    Log.e("ERR", "Read error: " + e.getMessage());
	}
   }

}

Fichier source IcyAsyncMeta.java : Permet de récupérer toutes les informations sur le flux audio(sauf le titre de la musique en cour)

package com.test;

import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;

import android.os.AsyncTask;
import android.util.Log;

public class IcyAsyncMeta extends AsyncTask<URL, Integer, Long> {

private URLConnection conn;

protected void onPreExecute() {
	Log.i("LOGGER", "onPreExecute");

}	

/**
 * Connection to stream
 * Using URL
 */
@Override
protected Long doInBackground(URL... urls) {
	// TODO Auto-generated method stub
	Log.i("IcyAsyncMeta", "doInBackground");

	try {
		conn = urls[0].openConnection();
		conn.setRequestProperty ("Icy-Metadata", "1");
        conn.setRequestProperty("Connection", "close");
		conn.setRequestProperty("Accept", null);
		conn.connect();

		Log.i("IcyAsyncMeta", conn.getHeaderField("icy-name"));
	} catch (IOException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}

	publishProgress();

       return null;
}

protected void onProgressUpdate(Integer... progress) {
	Log.i("IcyAsyncMeta", "onProgressUpdate");
	PulsDroid_Scanner.tv1.setText(conn.getHeaderField("icy-notice1"));
	PulsDroid_Scanner.tv2.setText(conn.getHeaderField("icy-notice2"));
	PulsDroid_Scanner.tv3.setText(conn.getHeaderField("icy-name"));
	PulsDroid_Scanner.tv4.setText(conn.getHeaderField("icy-genre"));
	PulsDroid_Scanner.tv5.setText(conn.getHeaderField("icy-url"));
	PulsDroid_Scanner.tv6.setText(conn.getHeaderField("content-type"));
	PulsDroid_Scanner.tv7.setText(conn.getHeaderField("icy-pub"));
	PulsDroid_Scanner.tv8.setText(conn.getHeaderField("icy-metaint"));
	PulsDroid_Scanner.tv9.setText(conn.getHeaderField("icy-br") + "kbps");
   }

@Override
protected void onPostExecute(Long result) {
	Log.i("IcyAsyncMeta", "onPostExecute");

   }

}

Fichier source IcyAsyncTitle.java : Permet de récupérer le titre de la musique en cour uniquement

package com.test;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import android.os.AsyncTask;
import android.util.Log;

public class IcyAsyncTitle extends AsyncTask<URL, Integer, Long> {

private URLConnection conn;
private Map<String, String> metadata;

@Override
protected Long doInBackground(URL... urls) {
	// TODO Auto-generated method stub
	Log.i("IcyAsyncTitle", "doInBackground");

	try {
		conn = urls[0].openConnection();
		conn.setRequestProperty ("Icy-Metadata", "1");
        conn.setRequestProperty("Connection", "close");
		conn.setRequestProperty("Accept", null);
		conn.connect();

		// Step 1
		publishProgress(retreiveMetadata());

		// Step 2
		if (metadata == null) {
			publishProgress(retreiveMetadata());
		}

		// Step 3
		publishProgress(Integer.getInteger(metadata.get("StreamTitle")));

	} catch (IOException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}

	return null;
}

protected void onProgressUpdate(Integer... params) {
	Log.i("IcyAsyncTitle", "onProgressUpdate");	

	if (metadata.containsKey("StreamTitle")) {
		PulsDroid_Scanner.tv10.setText(metadata.get("StreamTitle"));
	}
   }

@Override
protected void onPostExecute(Long result) {
	Log.i("IcyAsyncTitle", "onPostExecute");

   }

private Integer retreiveMetadata() throws IOException {
	try {
		int metaDataOffset = 0;
		Map<String, List<String>> headers = conn.getHeaderFields();
		InputStream stream;

		stream = conn.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));
			}
		}

		// 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 = this.parseMetadata(metaData.toString());

		// Close
		stream.close();

	} catch (IOException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
	return null;
}

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

Fichier source main.xml :

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:orientation="vertical"
   android:layout_width="fill_parent"
   android:layout_height="fill_parent"
   >
   <TextView android:id="@+id/TextView01" android:text="@string/hello" android:layout_height="wrap_content" android:layout_width="fill_parent"></TextView>
   <TextView android:id="@+id/TextView02" android:text="@string/hello" android:layout_height="wrap_content" android:layout_width="fill_parent"></TextView>
   <TextView android:id="@+id/TextView03" android:text="@string/hello" android:layout_height="wrap_content" android:layout_width="fill_parent"></TextView>
   <TextView android:id="@+id/TextView04" android:text="@string/hello" android:layout_height="wrap_content" android:layout_width="fill_parent"></TextView>
   <TextView android:id="@+id/TextView05" android:text="@string/hello" android:layout_height="wrap_content" android:layout_width="fill_parent"></TextView>
   <TextView android:id="@+id/TextView06" android:text="@string/hello" android:layout_height="wrap_content" android:layout_width="fill_parent"></TextView>
   <TextView android:id="@+id/TextView07" android:text="@string/hello" android:layout_height="wrap_content" android:layout_width="fill_parent"></TextView>
   <TextView android:id="@+id/TextView08" android:text="@string/hello" android:layout_height="wrap_content" android:layout_width="fill_parent"></TextView>
   <TextView android:id="@+id/TextView09" android:text="@string/hello" android:layout_height="wrap_content" android:layout_width="fill_parent"></TextView>
   <TextView android:id="@+id/TextView10" android:text="@string/hello" android:layout_height="wrap_content" android:layout_width="fill_parent"></TextView>
</LinearLayout>

Je me permet aussi de vous demander de l'aide pour mettre ajour le titre de la musique dès que celle-ci se met à changer, je suppose qu'il faut utiliser un thread mais je ne voie pas trop comment faire ?

cordialement

Lien vers le commentaire
Partager sur d’autres sites

Archivé

Ce sujet est désormais archivé et ne peut plus recevoir de nouvelles réponses.

×
×
  • Créer...