2013-05-06 18 views
8

원격 서버에서 오디오를 재생하는 응용 프로그램을 작성하고 있습니다. 스트리밍 오디오를 구현하는 데 몇 가지 방법을 시도했지만 모두 나를 위해 충분하지 않습니다. 그건 내가 무엇을 시도했다입니다 :오디오 스트리밍을위한 유용한 정보

나이브 MediaPlayer를의 사용

뭔가 같은 :

MediaPlayer player = new MediaPlayer(); 
player.setDataSource(context, Uri.parse("http://whatever.com/track.mp3")); 
player.prepare(); 
player.start(); 

(또는 prepareAsync에 상관없이)

그러나 원격 연주 할 때 표준 MediaPlayer은 매우 불안정 함유량. 종종 떨어지거나 재생이 멈추며 처리 할 수 ​​없습니다. 다른 측면에서, 저는 미디어 캐싱을 구현하려고합니다. 하지만 MediaPlayer에서 버퍼링 된 콘텐츠를 가져와 장치의 어딘가에 저장하는 방법을 찾지 못했습니다. 사용자 정의 버퍼링

을 구현

그런 다음 덩어리로 미디어 파일을 다운로드 한 로컬 파일로 결합하고이 파일을 재생하는 생각이되었다. 전체 파일을 다운로드하는 것은 연결 불량으로 인해 느려질 수 있으므로 초기 조각을 충분히 다운로드 한 다음 재생을 시작하고 로컬 파일을 계속 다운로드하고 추가하는 것이 좋습니다. 게다가 우리는 캐싱 기능을 얻습니다.

계획과 비슷하지만 항상 작동하지는 않습니다. 그것은 HTC Sensation XE에서 완벽하게 작동하지만 초기 조각을 마친 후에는 4.1 타블렛 재생을 중지하지 않았습니다. 모르겠어, 왜 그렇게. 나는 이것에 대해 question에게 물어 보았지만 답변을받지 못했습니다. 이 Mediaplayers에

나는 두 MediaPlayer를 인스턴스를 생성하고 서로를 변경하기 위해 노력했습니다

를 사용

. 논리는 다음입니다 :

  • 시작
  • 가 다운로드
  • , currentMediaPlayer를 통해 재생을 시작 미디어의 초기 조각을 다운로드. 미디어의 나머지 부분은 (가 재생 중에 추가되면서), 같은 소스 파일 currentMediaPlayer의 마무리 전에
  • 261 밀리 secondaryMediaPlayer을 준비
  • 다운로드 조각이 거의 재생
  • (마감 전 1 초) 다운로드 를 계속 - 일시 중지 , 보조 시작, 보조 보조 설정, 다음 보조 플레이어 준비 일정.

소스 :

private static final String FILE_NAME="local.mp3"; 
private static final String URL = ...; 
private static final long FILE_SIZE = 7084032; 

private static final long PREPARE_NEXT_PLAYER_OFFSET = 1000; 
private static final int START_NEXT_OFFSET = 261; 

private static final int INIT_PERCENTAGE = 3; 

private MediaPlayer mPlayer; 
private MediaPlayer mSecondaryPlayer; 

private Handler mHandler = new Handler(); 

public void startDownload() { 
    mDownloader = new Mp3Downloader(FILE_NAME, URL, getExternalCacheDir()); 
    mDownloader.setDownloadListener(mInitDownloadListener); 
    mDownloader.startDownload(); 
} 


private Mp3Downloader.DownloadListener mInitDownloadListener = new Mp3Downloader.DownloadListener() { 
    public void onDownloaded(long bytes) { 
     int percentage = Math.round(bytes * 100f/FILE_SIZE); 

     // Start playback when appropriate piece of media downloaded 
     if (percentage >= INIT_PERCENTAGE) { 
      mPlayer = new MediaPlayer(); 
      try { 
       mPlayer.setDataSource(mDownloader.getDownloadingFile().getAbsolutePath()); 
       mPlayer.prepare(); 
       mPlayer.start(); 

       mHandler.postDelayed(prepareSecondaryPlayerRunnable, mPlayer.getDuration() - PREPARE_NEXT_PLAYER_OFFSET); 
       mHandler.postDelayed(startNextPlayerRunnable, mPlayer.getDuration() - START_NEXT_OFFSET); 

      } catch (IOException e) { 
       Log.e(e); 
      } 

      mDownloader.setDownloadListener(null); 
     } 
    } 
}; 

// Starting to prepare secondary MediaPlayer 
private Runnable prepareSecondaryPlayerRunnable = new Runnable() { 
    public void run() { 
     mSecondaryPlayer = new MediaPlayer(); 
     try { 
      mSecondaryPlayer.setDataSource(mDownloader.getDownloadingFile().getAbsolutePath()); 
      mSecondaryPlayer.prepare(); 
      mSecondaryPlayer.seekTo(mPlayer.getDuration() - START_NEXT_OFFSET); 

     } catch (IOException e) { 
      Log.e(e); 
     } 
    } 
}; 

// Starting secondary MediaPlayer playback, scheduling creating next MediaPlayer 
private Runnable startNextPlayerRunnable = new Runnable() { 
    public void run() { 
     mSecondaryPlayer.start(); 

     mHandler.postDelayed(prepareSecondaryPlayerRunnable, mSecondaryPlayer.getDuration() - mPlayer.getCurrentPosition() - PREPARE_NEXT_PLAYER_OFFSET); 
     mHandler.postDelayed(startNextPlayerRunnable, mSecondaryPlayer.getDuration() - mPlayer.getCurrentPosition() - START_NEXT_OFFSET); 

     mPlayer.pause(); 
     mPlayer.release(); 

     mPlayer = mSecondaryPlayer; 

    } 
}; 

다시 - 소리, 계획 같은,하지만 완벽하지 작동합니다. MediaPlayers를 전환하는 순간은 충분히 이해할 수 있습니다. 여기에 나는 정반대의 상황이있다. 4.1 타블렛에서는 괜찮지 만, HTC Sensation에는 분명히 뒤 떨어진 것이있다.

다른 다운로드 기술을 구현하려고 시도했습니다. 나는 10Kb의 청크와 MP3 프레임으로 다운로드를 구현했다. 정확히 모르겠지만 MP3 프레임 seekTo의 경우에는 더 잘 작동합니다. 그러나 그것은 단지 느낌이며, 나는 설명을 모른다.

StreamingMediaPlayer는

나는 인터넷 검색을하는 동안이 말씀을 여러 번 보았고,이 구현 발견 : https://code.google.com/p/mynpr/source/browse/trunk/mynpr/src/com/webeclubbin/mynpr/StreamingMediaPlayer.java?r=18

그것은 솔루션 모두가 사용된다?

그렇다면 너무 좋지 않기 때문에 슬픈 일입니다. 그리고 구현에 새로운 아이디어가 보이지 않습니다. 그래서

질문

어떻게 너희들은 응용 프로그램에서 오디오 스트리밍을 구현합니까? 나는이 같은 문제에 직면 한 유일한 사람입니다. 좋은 습관이 있어야합니다.

+0

아주 좋은 질문 ... 지난 2 주 동안 저를 괴롭혔습니다 ...하지만 한 장치에서 다른 장치로 스트리밍하는 비디오가 필요합니다 ... 오디오 스트리밍을위한 –

+0

당신은 안드로이드 서비스로 자신 만의 사용자 지정 플레이어를 사용해야합니다 –

+0

큰 질문 ... 안타깝게도 Android의 MediaPlayer는 지금까지 작성된 최악의 소프트웨어 중 하나입니다. – StackOverflowed

답변

1

제 경우에는 OpenSL ES에서 FFMPEG를 사용합니다. 단점은 복잡합니다. JNI, OpenSL, FFMPEG와 같은 많은 것들에 익숙해야합니다. 또한 디버깅하기가 어렵습니다 (순수 자바 안드로이드 앱과 비교). 귀하의 경우에는 낮은 수준 Media API을 시도하도록 권합니다. 유일한 것은 예제의 부족입니다. 그러나 unit test은 오디오 처리 방법을 보여줍니다 (InputStream 참조 - 82 행을 변경해야 함).

+1

필자는 FFMPEG에 대해 생각해 보았지만, 사용하기가 매우 어렵 기 때문에 내가 시도 할 가장 마지막 일이 될 것입니다. Media API에 대해 알려 주셔서 감사합니다. – darja

관련 문제