Получение метаданных из потока Shoutcast Android

Я разрабатываю приложение Radio для устройств Android, которое должно получать потоковую передачу с сервера Shoutcast.

Звук работает нормально, но я также хочу получить метаданные, чтобы я мог показать название текущей воспроизводимой песни, исполнителя, а также изображение альбома.

Я использовал MediaMetaDataRetriever, но, похоже, он вообще не работает!

Это код, который я использовал:

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

}

Спасибо за вашу помощь!


person user1885868    schedule 10.05.2013    source источник


Ответы (2)


Поскольку класс в ответе @ William-Seemann больше не используется. Вот альтернатива (с тем преимуществом, что она не требует никаких библиотек):

Добавьте следующий класс в свой проект. Теперь вы можете использовать его, как показано здесь. Вы также можете использовать это так:

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

Полная заслуга dazza5000 за создание проекта.

person Mdlc    schedule 06.07.2016
comment
Но как я могу прослушать событие atrack changed, например, чтобы обновить метку? - person johnnyshrewd; 30.01.2018
comment
@johnnyshrewd У этого класса нет слушателя. Возможно, создайте свой собственный «прослушиватель событий», запуская приведенный выше фрагмент каждые x секунд, пока не будет обнаружено изменение в заголовке, по которому вы сможете вызвать свой слушатель. - person Mdlc; 01.02.2018

Я создал свой собственный класс для получения метаданных на основе модифицированной версии streamscraper. Используйте эту банку (streamscraper), этот jar (jsoup) и этот класс для получения метаданных. Интерфейс похож на 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);

Я не верю, что метаданные SHOUTcast поддерживают обложки альбомов, поэтому вы не сможете их получить.

person William Seemann    schedule 10.05.2013
comment
SHOUTcast v1 даже не поддерживает исполнителя или название. Это всего лишь одна строка, которая обычно форматируется как artist - title. SHOUTcast v2 предоставляет обложку альбома, если она доступна в кодировщике. - person Brad; 11.05.2013
comment
Теперь вы противоречите себе. В вашем сообщении говорится, что обложки альбома нет. Цитата, которую вы взяли из опубликованной мной ссылки, говорит о том, что данные находятся в потоке. - person Brad; 13.05.2013
comment
Отлично работает @WilliamSeeman, спасибо! Ему просто нужна была jsoup jar отсюда sourceforge.net/p/servestream/code/HEAD/tree/trunk/libs/ - person user1885868; 13.05.2013
comment
@WilliamSeeman, так что теперь у нас будет 2 setDataSources (путь)? Один для медиаплеера, а другой для метаданных? всякий раз, когда я вызываю setDataSources на smr, я получаю net.moraleboost.streamscraper.ScrapeException. идеи? - person tony9099; 17.07.2013
comment
Это исключение генерируется, если метаданные не могут быть получены по какой-либо причине (их нет или произошла какая-то ошибка). С какого URL вы пытаетесь получить метаданные SHOUTcast / Icecast? - person William Seemann; 17.07.2013
comment
@williamSeemann Я использую этот URL: streaming-live.es:8188 и тоже получаю ScrapeException - person Aracem; 11.11.2013
comment
Привет, Уильям Зееманн, не могли бы вы снова добавить ссылку в свой класс ShoutCastMetadataRetriever, потому что ссылка мертва. Спасибо - person pavol.franek; 31.07.2014
comment
Павел, я больше не использую этот класс, я создал библиотеку для извлечения метаданных. См .: github.com/wseemann/FFmpegMediaMetadataRetriever - person William Seemann; 31.07.2014