Fazendo streaming de áudio de uma URL no Android usando o MediaPlayer?


86

Tenho tentado transmitir mp3 em http usando a classe MediaPlayer do Android. A documentação sugere que isso deve ser tão fácil quanto:

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

No entanto, estou recebendo o seguinte repetidamente. Também tentei URLs diferentes. Por favor, não me diga que o streaming não funciona em 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)

Qualquer ajuda muito apreciada, obrigado S


Algumas perguntas: (1) qual versão do SDK você está usando? (2) Em qual (is) dispositivo (s) você está testando? Isso funciona bem no SDK 2.0.1, testando em um Droid.
— Roman Nurik

Oi Roman, obrigado por dedicar seu tempo. Estou tentando fazer isso contra o 1.6 e estou usando um HTC Hero. Vou testá-lo no 2.01 à luz dos seus comentários, mas seria um resultado ridículo se isso só funcionasse em dispositivos 2.xe posteriores prontos para uso.
— Pandalover

Apenas tentei em um emulador 2.01. Não funciona, infelizmente. Estou intrigado em tentar isso contra um dispositivo real 1.6 e um dispositivo real 2.01. Estou no Google testando no dia 4. Talvez tenha que esperar até então. Eu prefiro não ter que fazer isso.
— Pandalover

Não suspeito que 2.0 vs. 2.0.1 fará alguma diferença, mas o emulador vs. um dispositivo ao vivo pode fazer a diferença. Estou surpreso que isso não funcionou no Herói. Vou dar uma olhada e ver se consigo uma resposta melhor. Além disso, apenas para verificar a integridade, você deve se certificar de que solicitou a permissão INTERNET no manifesto.
— Roman Nurik

Ei, acabei de sair da discussão, tenho uma pergunta. Se eu usar mp.setDataSource (URL_OF_FILE); Não precisamos salvar nenhum arquivo para o streaming de áudio. Não é? Portanto, é a melhor maneira de transmitir áudio de qualquer local. Alguma ideia?
— Bohemian

Respostas:


78

Media Player simples com exemplo de streaming. Para a parte xml, você precisa de um botão com id button1 e duas imagens em sua pasta drawable com o nome button_pause e button_play e não se esqueça de adicionar a permissão de internet em seu manifesto.

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

Há um pequeno problema com isso, se eu bloquear meu telefone enquanto o MediaPlayer estiver em execução, meu aplicativo trava ao desbloqueá-lo.
— CiaranC94

3
Acabei de tentar comentar a linha "mediaPlayer.release ()" em onPause () e agora meu aplicativo não trava ao desbloquear.
— CiaranC94 de

@PiyushMishra esse recurso é aceito pelo console do desenvolvedor? Como meu aplicativo foi rejeitado b'coz, usei a versão do Vitamio 4.x
— Pallavi

35

O Android MediaPlayer não suporta streaming de MP3 nativamente até a versão 2.2. Em versões mais antigas do sistema operacional, ele parece apenas transmitir 3GP nativamente. Você pode tentar o código pocketjourney, embora seja antigo (há uma nova versão aqui ) e eu tive problemas para torná-lo pegajoso - ele gaguejava sempre que recarregava o buffer.

O aplicativo NPR News para Android é de código aberto e usa um servidor proxy local para lidar com streaming de MP3 em versões do sistema operacional anteriores a 2.2. Você pode ver o código relevante nas linhas 199-216 (r94) aqui: http://code.google.com/p/npr-android-app/source/browse/Npr/src/org/npr/android/news/ PlaybackService.java?r=7cf2352b5c3c0fbcdc18a5a8c67d836577e7e8e3

E esta é a classe StreamProxy: http://code.google.com/p/npr-android-app/source/browse/Npr/src/org/npr/android/news/StreamProxy.java?r=e4984187f45c39a54ea6c88f71197762dbe10e72

O aplicativo NPR também ainda está recebendo o "erro (-38, 0)" às vezes durante a transmissão. Isso pode ser um problema de threading ou de mudança de rede. Verifique o rastreador de problemas para atualizações .


Você tem certeza absoluta disso? Meu entendimento é que tinha a ver com o tipo de mímica. Você poderia verificar se t funciona com o tipo MIME certo pré 2.1? Estou trabalhando em outra coisa agora e não pude verificar por um tempo.
— Pandalover

1
De acordo com as notas de versão 2.2 ( developer.android.com/sdk/android-2.2-highlights.html ), inclui uma "nova estrutura de mídia (Stagefright) que suporta reprodução de arquivo local e streaming progressivo de HTTP". Em todos os meus testes, não consegui fazer com que um dispositivo 2.1 transmitisse diretamente de um servidor shoutcast. Eu acredito que o problema é que os servidores shoutcast retornam um protocolo de ICY / 1.1 em vez de HTTP / 1.1 e o reprodutor de mídia tropeça nisso, pois não sabe como responder a esse conteúdo.
— jwadsack

@jwadsack e se os arquivos de áudio precisassem ser baixados uma vez e o usuário também pudesse reproduzi-los offline?
— Devendra Singh

@DevendraSingh Não sei se você pode salvar o arquivo durante o streaming com a implementação do media player atual (esta resposta tem quase cinco anos e muita coisa mudou desde 2.2). No mínimo, você pode construir um proxy seguindo este exemplo e gravar o arquivo no armazenamento enquanto o passa pelo proxy.
— jwadsack

11

Acho que você está tentando reproduzir um .pls diretamente ou algo semelhante.

experimente isto:

1: o código

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

2: o arquivo .pls

Este URL é da BBC apenas como exemplo. Era um arquivo .pls que baixei no linux com

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

e então abri com o vim (use seu editor favorito;) e vi os URLs reais dentro deste arquivo. Infelizmente, nem todos os .pls são texto simples como esse.

Eu li que 1.6 não suportaria streaming de mp3 em http, mas acabei de testar o código obove com android 1.6 e 2.2 e não tive nenhum problema.

boa sorte!


7
Lembre-se de que, se quiser transmitir música, você deve usar mediaplayer.prepareAsync e não mediaplayer.prepare. Portanto, você não pode usar mediaplayer.create () porque qualquer uma das funções .create () leva seu objeto Media Player diretamente para o estado Preparado, a partir do qual você não pode chamar prepareAsync, que é necessário para transmitir. developer.android.com/reference/android/media/MediaPlayer.html
— marienke

4

Usar

 mediaplayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
 mediaplayer.prepareAsync();
 mediaplayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
      @Override
      public void onPrepared(MediaPlayer mp) {
          mediaplayer.start();
      }
 });

2

Eu tive o mesmo erro que você e descobri que não havia nada de errado com o código. O problema era que o servidor da web estava enviando o cabeçalho Content-Type errado.

Tente WireShark ou algo semelhante para ver que tipo de conteúdo o servidor está enviando.


para arquivos mp3, deve ser Content-Type: audio / mpeg Isso resolveu meu problema :)
— doep

1
Como você transmitiu esse arquivo?
— Nauman Khalid,


1

Não chame mp.start com um OnPreparedListener para evitar o estado zero no log.


Ainda recebo a linha de log 05-22 20: 26: 13.625: E / MediaPlayer (23818): parar chamado no estado 0, embora eu inicie meu Media Player na função preparada (). Também tenho uma função onError em que redefino o objeto Media Player. Ainda leva até 2 minutos para meu stream começar a tocar. Veja minha pergunta aqui: stackoverflow.com/questions/16672568/…
— marienke
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.