Потоковое аудио с URL-адреса в Android с помощью MediaPlayer?

86

Я пытался передавать mp3 через http, используя Android, встроенный в класс MediaPlayer. Документация подсказывает мне, что это должно быть так же просто, как:

MediaPlayer mp = new MediaPlayer();
mp.setDataSource(URL_OF_FILE);
mp.prepare();
mp.start();

Однако я постоянно получаю следующее. Я также пробовал разные URL-адреса. Пожалуйста, не говорите мне, что потоковая передача не работает с mp3.

E/PlayerDriver(   31): Command PLAYER_SET_DATA_SOURCE completed with an error or info PVMFErrNotSupported
W/PlayerDriver(   31): PVMFInfoErrorHandlingComplete
E/MediaPlayer(  198): error (1, -4)
E/MediaPlayer(  198): start called in state 0
E/MediaPlayer(  198): error (-38, 0)
E/MediaPlayer(  198): Error (1,-4)
E/MediaPlayer(  198): Error (-38,0)

Любая помощь очень ценится, спасибо S

Пандаловер
источник
Несколько вопросов: (1) какую версию SDK вы используете? (2) На каких устройствах вы тестируете? Это отлично работает с SDK 2.0.1, тестируется на Droid.
Роман Нурик
Привет, Роман, спасибо, что нашли время. Я пробую это против 1.6 и использую HTC Hero. Я попробую его на 2.01 в свете ваших комментариев, но было бы нелепо, если бы он работал только на устройствах 2.x и выше из коробки.
Pandalover
Только что попробовал на эмуляторе 2.01. К сожалению, не работает. Я заинтригован попробовать это на реальном устройстве 1.6 и реальном устройстве 2.01. Я в гугле тестирую 4го числа. Может, мне придется подождать до тех пор. Но я бы предпочел не делать этого.
Pandalover
Я не подозреваю, что версии 2.0 и 2.0.1 будут иметь какое-либо значение, но эмулятор и живое устройство могут иметь значение. Я удивлен, что это не сработало с героем. Я изучу его и посмотрю, смогу ли я получить лучший ответ. Кроме того, в качестве проверки работоспособности вы должны убедиться, что запросили разрешение INTERNET в манифесте.
Роман Нурик
Привет, просто закончил обсуждение. У меня вопрос. Если я использую mp.setDataSource (URL_OF_FILE); Нам не нужно сохранять какие-либо файлы для потоковой передачи звука. Не так ли? Таким образом, это лучший способ транслировать аудио из любого места. Любые идеи?
Bohemian

Ответы:

78

простой медиаплеер с примером потоковой передачи. Для части xml вам понадобится одна кнопка с идентификатором button1 и два изображения в вашей папке с возможностью рисования с именами button_pause и button_play, и, пожалуйста, не забудьте добавить разрешение в Интернете в свой манифест.

public class MainActivity extends Activity {
private Button btn;
/**
 * help to toggle between play and pause.
 */
private boolean playPause;
private MediaPlayer mediaPlayer;
/**
 * remain false till media is not completed, inside OnCompletionListener make it true.
 */
private boolean intialStage = true;


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    btn = (Button) findViewById(R.id.button1);
    mediaPlayer = new MediaPlayer();
    mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
    btn.setOnClickListener(pausePlay);

}

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

private OnClickListener pausePlay = new OnClickListener() {

    @Override
    public void onClick(View v) {
        // TODO Auto-generated method stub
        // TODO Auto-generated method stub

        if (!playPause) {
            btn.setBackgroundResource(R.drawable.button_pause);
            if (intialStage)
                new Player()
                        .execute("http://www.virginmegastore.me/Library/Music/CD_001214/Tracks/Track1.mp3");
            else {
                if (!mediaPlayer.isPlaying())
                    mediaPlayer.start();
            }
            playPause = true;
        } else {
            btn.setBackgroundResource(R.drawable.button_play);
            if (mediaPlayer.isPlaying())
                mediaPlayer.pause();
            playPause = false;
        }
    }
};
/**
 * preparing mediaplayer will take sometime to buffer the content so prepare it inside the background thread and starting it on UI thread.
 * @author piyush
 *
 */

class Player extends AsyncTask<String, Void, Boolean> {
    private ProgressDialog progress;

    @Override
    protected Boolean doInBackground(String... params) {
        // TODO Auto-generated method stub
        Boolean prepared;
        try {

            mediaPlayer.setDataSource(params[0]);

            mediaPlayer.setOnCompletionListener(new OnCompletionListener() {

                @Override
                public void onCompletion(MediaPlayer mp) {
                    // TODO Auto-generated method stub
                    intialStage = true;
                    playPause=false;
                    btn.setBackgroundResource(R.drawable.button_play);
                    mediaPlayer.stop();
                    mediaPlayer.reset();
                }
            });
            mediaPlayer.prepare();
            prepared = true;
        } catch (IllegalArgumentException e) {
            // TODO Auto-generated catch block
            Log.d("IllegarArgument", e.getMessage());
            prepared = false;
            e.printStackTrace();
        } catch (SecurityException e) {
            // TODO Auto-generated catch block
            prepared = false;
            e.printStackTrace();
        } catch (IllegalStateException e) {
            // TODO Auto-generated catch block
            prepared = false;
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            prepared = false;
            e.printStackTrace();
        }
        return prepared;
    }

    @Override
    protected void onPostExecute(Boolean result) {
        // TODO Auto-generated method stub
        super.onPostExecute(result);
        if (progress.isShowing()) {
            progress.cancel();
        }
        Log.d("Prepared", "//" + result);
        mediaPlayer.start();

        intialStage = false;
    }

    public Player() {
        progress = new ProgressDialog(MainActivity.this);
    }

    @Override
    protected void onPreExecute() {
        // TODO Auto-generated method stub
        super.onPreExecute();
        this.progress.setMessage("Buffering...");
        this.progress.show();

    }
}

@Override
protected void onPause() {
    // TODO Auto-generated method stub
    super.onPause();
    if (mediaPlayer != null) {
        mediaPlayer.reset();
        mediaPlayer.release();
        mediaPlayer = null;
    }
}
ПиюшМишра
источник
С этим есть небольшая проблема: если я заблокирую свой телефон во время воспроизведения MediaPlayer, мое приложение выйдет из строя, когда я его разблокирую.
CiaranC94
3
Я только что пробовал закомментировать строку «mediaPlayer.release ()» в onPause (), и теперь мое приложение не вылетает при разблокировке.
CiaranC94
@PiyushMishra эта функция принята консолью разработчика? Поскольку мое приложение отклоняется, я использовал версию Vitamio 4.x
Паллави
35

Android MediaPlayer не поддерживает потоковую передачу MP3 до версии 2.2. В более старых версиях ОС он, по-видимому, поддерживает только потоковую передачу 3GP. Вы можете попробовать код pocketjourney, хотя он старый (здесь есть новая версия ), и у меня возникли проблемы с его закреплением - он заикался всякий раз, когда пополнял буфер.

Приложение NPR News для Android имеет открытый исходный код и использует локальный прокси-сервер для обработки потоковой передачи MP3 в версиях ОС до 2.2. Вы можете увидеть соответствующий код в строках 199-216 (r94) здесь: http://code.google.com/p/npr-android-app/source/browse/Npr/src/org/npr/android/news/ PlaybackService.java?r=7cf2352b5c3c0fbcdc18a5a8c67d836577e7e8e3

А это класс StreamProxy: http://code.google.com/p/npr-android-app/source/browse/Npr/src/org/npr/android/news/StreamProxy.java?r=e4984187f45c39a54ea6c88f71197762dbe10e72

Приложение NPR также иногда выдает «ошибку (-38, 0)» во время потоковой передачи. Это может быть проблема потоковой передачи или проблема изменения сети. Следите за обновлениями в системе отслеживания проблем .

jwadsack
источник
Вы абсолютно уверены в этом? Насколько я понимаю, это было связано с пантомимой. Не могли бы вы проверить, работает ли t с правильным типом MIME до 2.1? Я сейчас работаю над чем-то другим и какое-то время не мог проверить.
Pandalover
1
Согласно примечаниям к выпуску 2.2 ( developer.android.com/sdk/android-2.2-highlights.html ), он включает «новую среду мультимедиа (Stagefright), которая поддерживает локальное воспроизведение файлов и прогрессивную потоковую передачу HTTP». Во время всего моего тестирования мне не удавалось заставить устройство 2.1 транслировать напрямую с сервера shoutcast. Я считаю, что проблема в том, что серверы shoutcast возвращают протокол ICY / 1.1, а не HTTP / 1.1, и медиаплеер срабатывает при этом, поскольку не знает, как реагировать на этот контент.
jwadsack
@jwadsack что делать, если аудиофайлы нужно загружать один раз, и тогда пользователь может воспроизводить файлы в автономном режиме?
Devendra Singh
@DevendraSingh Я не знаю, можете ли вы сохранить файл во время потоковой передачи с текущей реализацией медиаплеера (этому ответу почти пять лет, и с момента 2.2 многое изменилось). По крайней мере, вы можете создать прокси, следуя этому примеру, и записать файл в хранилище, пока вы передаете его через прокси.
jwadsack
11

Я предполагаю, что вы пытаетесь воспроизвести .pls напрямую или что-то подобное.

попробуйте это:

1: код

mediaPlayer = MediaPlayer.create(this, Uri.parse("http://vprbbc.streamguys.net:80/vprbbc24.mp3"));
mediaPlayer.start();

2: файл .pls

Этот URL-адрес взят из BBC в качестве примера. Это был файл .pls, который в Linux я скачал с

wget http://foo.bar/file.pls

а затем я открыл с помощью vim (используйте ваш любимый редактор;), и я увидел настоящие URL-адреса внутри этого файла. К сожалению, не все .pls представляют собой такой обычный текст.

Я читал, что 1.6 не поддерживает потоковую передачу mp3 через http, но я только что протестировал код obove с Android 1.6 и 2.2 и не имел никаких проблем.

удачи!

Pabluez
источник
7
Помните, что если вы хотите транслировать музыку, вы должны использовать mediaplayer.prepareAsync, а не mediaplayer.prepare. Следовательно, вы не можете использовать mediaplayer.create (), потому что любая из функций .create () переводит ваш объект Media Player непосредственно в состояние Prepared, из которого вы не можете вызвать prepareAsync, который вам необходимо для потоковой передачи. developer.android.com/reference/android/media/MediaPlayer.html
мариенке
4

Использовать

 mediaplayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
 mediaplayer.prepareAsync();
 mediaplayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
      @Override
      public void onPrepared(MediaPlayer mp) {
          mediaplayer.start();
      }
 });
Шшанк Бхонг
источник
2

У меня была такая же ошибка, как и у вас, и оказалось, что с кодом все в порядке. Проблема заключалась в том, что веб-сервер отправлял неправильный заголовок Content-Type.

Попробуйте wirehark или что-то подобное, чтобы узнать, какой тип контента отправляет веб-сервер.

пьяный
источник
для mp3-файлов это должно быть Content-Type: audio / mpeg Это решило мою проблему :)
doep
1
Как вы транслировали этот файл?
Науман Халид
2

Смотрю мои проекты:

  1. https://github.com/master255/ImmortalPlayer Поддержка http / FTP, один поток для чтения, отправки и сохранения данных в кеш. Самый простой способ и самая быстрая работа. Сложная логика - лучший способ!
  2. https://github.com/master255/VideoViewCache Простой видеопросмотр с кешем. Два потока для воспроизведения и сохранения данных. Плохая логика, но если нужно, воспользуйтесь этим.
Мастер
источник
1

Нет вызова mp.start с OnPreparedListener, чтобы избежать нулевого состояния в журнале.

Фред Гротт
источник
Я все еще получаю строку журнала 05-22 20: 26: 13.625: E / MediaPlayer (23818): stop, вызываемую в состоянии 0, даже если я запускаю свой медиаплеер в функции prepare (). У меня также есть функция onError, в которой я сбрасываю объект Media Player. Для начала воспроизведения моего стрима по-прежнему требуется до 2 минут. См. Мой вопрос здесь: stackoverflow.com/questions/16672568/…
marienke