4

I am developing a Radio App for Android devices that is supposed to get streaming from a Shoutcast Server.

The sound is working fine but I want to retrieve the MetaData as well so I might be able to show the currently played song's Title, artist, as well as the Album Picture.

I used the MediaMetaDataRetriever but it doesn't seem to be working at all!

This is the code I used:

public class MainActivity extends FragmentActivity {

private ImageView bannerView;
private int[] pub = {R.drawable.banner, R.drawable.pubnautic, R.drawable.pubquad};
private int i = 0;

private ImageView play;
private ImageView pause;
private TextView title;
private MediaPlayer mediaPlayer;
private MediaMetadataRetriever retriever;
private String out;
private String url = "http://streamplus8.leonex.de:14910";
//adele-someonelikeyou
//Accordossie
//http://support.k-designed.net/test-z/music/adele-someonelikeyou.mp3
private ImageView albumpic; 
private byte[] image;
private boolean paused = false;

private ImageView exit;

private ImageView wish;

private ImageView reservation;

private ImageView contact;

private ImageView facebook;

private ImageView twitter;

@Override
protected void onCreate(final Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    bannerView = (ImageView) findViewById(R.id.banner);

    play = (ImageView) findViewById(R.id.play);
    pause = (ImageView) findViewById(R.id.pause);
    exit = (ImageView) findViewById(R.id.exit);
    albumpic = (ImageView) findViewById(R.id.artist);
    title = (TextView) findViewById(R.id.title);
    retriever = new MediaMetadataRetriever();
    mediaPlayer = new MediaPlayer();

    wish = (ImageView) findViewById(R.id.wish);

    reservation = (ImageView) findViewById(R.id.shop);

    contact = (ImageView) findViewById(R.id.contact);

    facebook = (ImageView) findViewById(R.id.facebook);

    twitter = (ImageView) findViewById(R.id.twitter);

    this.setVolumeControlStream(AudioManager.STREAM_MUSIC);  

    try {
        mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
        mediaPlayer.setDataSource(url);
        retriever.setDataSource(url);
        mediaPlayer.prepareAsync();
    } catch (Exception e) {
        Toast.makeText(getApplicationContext(), "Please check your connection!", Toast.LENGTH_LONG).show();
        e.printStackTrace();
    }

    play.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            try {
                if(paused == true) {
                    mediaPlayer.start();
                } else {
                    mediaPlayer.setOnPreparedListener(new OnPreparedListener() {

                        @Override
                        public void onPrepared(MediaPlayer mp) {
                            mediaPlayer.start();

                        }
                    });
                }
                paused = false;
                image = retriever.getEmbeddedPicture();
                if(image != null) {
                    albumpic.setImageBitmap(BitmapFactory.decodeByteArray(image, 0, image.length));
                }
                out =  "Title: " + retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE) + " \nArtist: " + retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ARTIST);
                title.setText(out);
                play.setVisibility(ImageView.GONE);
                pause.setVisibility(ImageView.VISIBLE);

            } catch(Exception e) {
                e.printStackTrace();
            }
        }
    });

    pause.setClickable(true);

    pause.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            pause.setVisibility(ImageView.GONE);
            play.setVisibility(ImageView.VISIBLE);
            mediaPlayer.pause();
            paused = true;
        }
    });

    wish.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            Intent wishIntent = new Intent(MainActivity.this, Wish.class);
            startActivity(wishIntent);

        }
    });

    reservation.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            Intent reservIntent = new Intent(MainActivity.this, Reservation.class);
            startActivity(reservIntent);
        }
    });

    contact.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            Intent contactIntent = new Intent(MainActivity.this, Contact.class);
            startActivity(contactIntent);
        }
    });

    facebook.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {

            Intent facebookIntent = new Intent(MainActivity.this, FacebookActivity.class);
            facebookIntent.putExtra("name", "Just now listening to: " + retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE) + " by " + retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ARTIST));
            facebookIntent.putExtra("caption", "On AgadirAdventure Radio");
            facebookIntent.putExtra("description", "A Radio App for Android Devices by K-Designed");
            facebookIntent.putExtra("link", "http://www.agadiradventure.com/");
            facebookIntent.putExtra("picture", "http://agadiradventure.com/images/logo/logo1.png");
            startActivity(facebookIntent);

        }
    });

    twitter.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            initShareIntent("twi");

        }
    });

    exit.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            mediaPlayer.stop();
            onBackPressed();
        }
    });

    bannerView.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            Uri uri = Uri.parse("http://www.agadiradventure.com");
            Intent launchBrowser = new Intent(Intent.ACTION_VIEW, uri);
            startActivity(launchBrowser);
        }
    });

    Runnable r = new Runnable() {

        @Override
        public void run() {
            bannerView.setImageResource(pub[i]);
            i++;
            if(i >= pub.length) {
                i = 0;
            }
            bannerView.postDelayed(this, 3000);
        }
    }; 
    bannerView.postDelayed(r, 3000);

}

private void initShareIntent(String type) {
    boolean found = false;
    Intent share = new Intent(android.content.Intent.ACTION_SEND);
    share.setType("text/plain");

    // gets the list of intents that can be loaded.
    List<ResolveInfo> resInfo = getPackageManager().queryIntentActivities(share, 0);
    if (!resInfo.isEmpty()){
        for (ResolveInfo info : resInfo) {
            if (info.activityInfo.packageName.toLowerCase().contains(type) || 
                    info.activityInfo.name.toLowerCase().contains(type) ) {
                String sharedText = "Just now listening to: " + retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE) + " by " + retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ARTIST) + "\nOn AgadirAdventure\nwww.agadiradventure.com";
                share.putExtra(Intent.EXTRA_TEXT, sharedText);
                share.setPackage(info.activityInfo.packageName);
                found = true;
                break;
            }
        }
        if (!found)
            return;

        startActivity(Intent.createChooser(share, "Select"));
    }
}

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
    if (keyCode == KeyEvent.KEYCODE_BACK) {
        moveTaskToBack(true);
        return true;
    }
    return super.onKeyDown(keyCode, event);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.activity_main, menu);
    return true;
}

}

Thanks for your help!

user1885868
  • 1,063
  • 3
  • 17
  • 31

2 Answers2

6

I created my own class to retrieve the metadata based on a modified version of streamscraper. Use this jar (streamscraper), this jar (jsoup) and this class to retrieve the metadata. The interface is similar to MediaMetadataRetriever:

ShoutCastMetadataRetriever smr = new ShoutCastMetadataRetriever();
smr.setDataSource(<some url>);
String artist = smr.extractMetadata(ShoutCastMetadataRetriever.METADATA_KEY_ARTIST);
String title = smr.extractMetadata(ShoutCastMetadataRetriever.METADATA_KEY_TITLE);

I don't believe SHOUTcast metadata supports album art so you won't be able to retrieve that.

William Seemann
  • 3,440
  • 10
  • 44
  • 78
  • SHOUTcast v1 doesn't even support artist or title. It's just one string that is commonly formatted as `artist - title`. SHOUTcast v2 does provide the album art, if it is available from the encoder. – Brad May 11 '13 at 14:28
  • 1
    Now you are contradicting yourself. Your post says the album art isn't there. The quote you take from the link I posted says that data is in-stream. – Brad May 13 '13 at 03:40
  • 1
    Works Perfectly @WilliamSeeman thanks! It just needed the jsoup jar from here http://sourceforge.net/p/servestream/code/HEAD/tree/trunk/libs/jsoup-1.7.2.jar – user1885868 May 13 '13 at 08:45
  • 1
    @WilliamSeeman , so now we will be having 2 setDataSources(path)? One for the media player and the other one for the metadata ? whenever I call the setDataSources on smr, I am getting an net.moraleboost.streamscraper.ScrapeException. ideas? – tony9099 Jul 17 '13 at 09:46
  • That exception is thrown if metadata couldn't be retrieved for whatever reason (it's not present or there was an error of some sort). What URL are you trying to retrieve SHOUTcast/Icecast metadata from? – William Seemann Jul 17 '13 at 13:50
  • @williamSeemann I using this url: http://streaming-live.es:8188 and get the ScrapeException too – Aracem Nov 11 '13 at 18:15
  • 2
    Hi William Seemann, can you add again link to your ShoutCastMetadataRetriever class because link are dead. Thx – pavol.franek Jul 31 '14 at 15:24
  • Pavel, I no longer use this class, I created a library to retrieve the metadata. See: https://github.com/wseemann/FFmpegMediaMetadataRetriever – William Seemann Jul 31 '14 at 15:52
5

Since the class in the Answer of @William-Seemann is not usable anymore. Here's an alternative (with the benefit that it does not require any libraries):

Add the following class to your project. You can now use it as shown here. You can also use it like this:

    String title = "";
    IcyStreamMeta meta = new IcyStreamMeta();
    try {
        meta.setStreamUrl(new URL(YOURURL));
        title = meta.getStreamTitle();
    } catch (MalformedURLException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }

Full credit to dazza5000 for creating the project.

Mdlc
  • 7,128
  • 12
  • 55
  • 98
  • But how can I listen for a"track changed" event to update a label for example? – johnnyshrewd Jan 30 '18 at 14:02
  • @johnnyshrewd This class doesn't have a listener. Possibly create your own 'event listener' by running the above snippet every x seconds until a change has been detected in the title upon which you can call your listener. – Mdlc Feb 01 '18 at 09:59