MediaPlayer를 사용하여 Android의 URL에서 오디오를 스트리밍합니까?


86

Android의 내장 MediaPlayer 클래스를 사용하여 http를 통해 mp3를 스트리밍하려고했습니다. 문서는 이것이 다음과 같이 쉬워야한다고 제안합니다.

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)

많은 도움을 주셔서 감사합니다.


몇 가지 질문 : (1) 어떤 SDK 버전을 사용하고 있습니까? (2) 어떤 장치에서 테스트하고 있습니까? 이것은 Droid에서 테스트하는 SDK 2.0.1에서 잘 작동합니다.
Roman Nurik

안녕로만, 시간을 내 주셔서 감사합니다. 1.6에 대해 이것을 시도하고 있으며 HTC Hero를 사용하고 있습니다. 나는 당신의 의견에 비추어 2.01에서 그것을 시도 할 것이지만 이것이 2.x 이상 장치에서만 작동한다면 말도 안되는 결과가 될 것입니다.
Pandalover 2009

2.01 에뮬레이터에서 시도했습니다. 불행히도 작동하지 않습니다. 실제 1.6 장치와 실제 2.01 장치에 대해 이것을 시도하는 것이 흥미 롭습니다. 저는 4 일에 Google 테스트 중입니다. 그때까지 기다려야 할지도 몰라요. 그래도 그럴 필요가 없습니다.
Pandalover 2009

2.0과 2.0.1이 차이를 만들 것이라고 생각하지는 않지만 에뮬레이터와 라이브 장치가 차이를 만들 수 있습니다. 이것이 Hero에서 작동하지 않는다는 것에 놀랐습니다. 나는 그것을 조사하고 더 나은 답을 얻을 수 있는지 볼 것입니다. 또한 온 전성 검사와 마찬가지로 매니페스트에서 INTERNET 권한을 요청했는지 확인해야합니다.
Roman Nurik

이봐 그냥 토론에서 나에게 질문이 있습니다. mp.setDataSource (URL_OF_FILE); 오디오 스트리밍을 위해 파일을 저장할 필요가 없습니다. 그렇지 않나요? 따라서 모든 위치에서 오디오를 스트리밍하는 가장 좋은 방법입니다. 어떤 아이디어?
Bohemian

답변:


78

스트리밍 예제가있는 간단한 미디어 플레이어. xml 부분의 경우 id 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
onPause ()에서 "mediaPlayer.release ()"줄을 주석 처리해 보았습니다. 이제 잠금 해제시 내 앱이 충돌하지 않습니다.
CiaranC94

@PiyushMishra이 기능은 개발자 콘솔에서 허용됩니까? 내 앱이 거부됨에 따라 Vitamio 4.x 버전을 사용했습니다
Pallavi

35

Android MediaPlayer는 2.2까지 기본적으로 MP3 스트리밍을 지원하지 않습니다. 이전 버전의 OS에서는 기본적으로 3GP 만 스트리밍하는 것으로 보입니다. pocketjourney 코드가 오래되었지만 ( 여기에 새 버전이 있습니다 ) 사용해 볼 수 있습니다. 끈적하게 만드는 데 어려움이있었습니다. 버퍼를 다시 채울 때마다 끊김이 발생했습니다.

Android 용 NPR News 앱은 오픈 소스이며 로컬 프록시 서버를 사용하여 2.2 이전 OS 버전에서 MP3 스트리밍을 처리합니다. 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)"가 ​​발생합니다. 스레딩 문제 또는 네트워크 변경 문제 일 수 있습니다. 이슈 트래커에서 업데이트를 확인하십시오 .


당신은 이것에 대해 절대적으로 확신합니까? 내 이해는 마임 유형과 관련이 있다는 것입니다. t가 2.1 이전의 올바른 MIME 유형에서 작동하는지 확인할 수 있습니까? 지금 다른 작업을하고 있는데 한동안 확인할 수 없었습니다.
Pandalover

1
2.2 릴리스 노트 ( developer.android.com/sdk/android-2.2-highlights.html ) 에 따르면 "로컬 파일 재생 및 HTTP 점진적 스트리밍을 지원하는 새로운 미디어 프레임 워크 (Stagefright)"가 포함되어 있습니다. 내 모든 테스트에서 나는 shoutcast 서버에서 직접 스트리밍 할 2.1 장치를 얻을 수 없었습니다. 문제는 shoutcast 서버가 HTTP / 1.1이 아닌 ICY / 1.1 프로토콜을 반환하고 미디어 플레이어가 해당 콘텐츠에 응답하는 방법을 모르기 때문에이 문제를 해결한다는 것입니다.
jwadsack

@jwadsack 오디오 파일을 한 번 다운로드하고 사용자보다 오프라인에서도 파일을 재생할 수 있다면 어떨까요?
Devendra Singh

@DevendraSingh 현재 미디어 플레이어 구현으로 스트리밍하는 동안 파일을 저장할 수 있는지 모르겠습니다 (이 답변은 거의 5 년이되었으며 2.2 이후로 많이 변경되었습니다). 다른 것이 없다면이 예제에 따라 프록시를 빌드하고 프록시를 통과하는 동안 파일을 스토리지에 쓸 수 있습니다.
jwadsack 2015

11

나는 당신이 .pls를 직접 또는 비슷한 것을 재생하려고 시도하고 있다고 생각합니다.

이것을 시도하십시오 :

1 : 코드

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

2 : .pls 파일

이 URL은 예를 들어 BBC에서 가져온 것입니다. Linux에서 다운로드 한 .pls 파일이었습니다.

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

그런 다음 vim (좋아하는 편집기 사용;)으로 열었고이 파일 내부의 실제 URL을 보았습니다. 불행히도 모든 .pls가 그런 일반 텍스트는 아닙니다.

1.6이 http를 통한 mp3 스트리밍을 지원하지 않는다고 읽었지만 Android 1.6 및 2.2에서 obove 코드를 테스트했으며 문제가 없었습니다.

행운을 빕니다!


7
음악을 스트리밍하려면 mediaplayer.prepare가 아닌 mediaplayer.prepareAsync를 사용해야합니다. 따라서 .create () 함수 중 하나가 Media Player 개체를 Prepared 상태로 직접 가져 가기 때문에 mediaplayer.create ()를 사용할 수 없습니다. developer.android.com/reference/android/media/MediaPlayer.html
marienke 2013 년

4

사용하다

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

2

나는 당신과 같은 오류가 있었고 코드에 아무런 문제가 없다는 것이 밝혀졌습니다. 문제는 웹 서버가 잘못된 Content-Type 헤더를 보내고 있다는 것입니다.

wireshark 또는 이와 유사한 것을 시도하여 웹 서버가 보내는 콘텐츠 유형을 확인하십시오.


mp3 파일의 경우 콘텐츠 유형 : 오디오 / mpeg 내 문제를 해결했습니다. :)
doep

1
그 파일을 어떻게 스트리밍 했습니까?
Nauman Khalid


1

로그에서 0 상태를 피하기 위해 OnPreparedListener로 mp.start를 호출하지 않습니다.


난 여전히 로그 줄 05-22 20 : 26 : 13.625 : E / MediaPlayer (23818) : 준비된 () 함수에서 내 미디어 플레이어를 시작하더라도 상태 0에서 호출됩니다. Media Player 개체를 재설정하는 onError 함수도 있습니다. 스트림 재생을 시작하는 데 여전히 최대 2 분이 걸립니다. 여기 내 질문을 참조하십시오 : stackoverflow.com/questions/16672568/…
marienke
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.