首页 > 系统 > Android > 正文

Android实现使用流媒体播放远程mp3文件的方法

2019-12-12 05:37:13
字体:
来源:转载
供稿:网友

本文实例讲述了Android实现使用流媒体播放远程mp3文件的方法。分享给大家供大家参考,具体如下:

package com.shadow.util;import java.io.BufferedInputStream;import java.io.BufferedOutputStream;import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.net.URL;import java.net.URLConnection;import java.util.ArrayList;import java.util.List;import com.shadow.service.AudioPlayService.LocalBinder;import android.app.Service;import android.content.Context;import android.content.Intent;import android.media.MediaPlayer;import android.os.Binder;import android.os.Handler;import android.os.IBinder;import android.util.Log;import android.widget.Button;import android.widget.ImageButton;import android.widget.ProgressBar;import android.widget.TextView;import android.widget.Toast;/** * MediaPlayer does not yet support streaming from external URLs so this class provides a pseudo-streaming function * by downloading the content incrementally & playing as soon as we get enough audio in our temporary storage. */public class StreamingMediaPlayer extends Service{  private static final int INTIAL_KB_BUFFER = 96*10/8;//assume 96kbps*10secs/8bits per byte  private TextView textStreamed;  private ImageButton playButton;  private ProgressBar  progressBar;  // Track for display by progressBar  private long mediaLengthInKb, mediaLengthInSeconds;  private int totalKbRead = 0;  // Create Handler to call View updates on the main UI thread.  private final Handler handler = new Handler();  private MediaPlayer   mediaPlayer;  private File downloadingMediaFile;  private boolean isInterrupted;  private Context context;  private int counter = 0;  private static Runnable r;  private static Thread playerThread;  private LocalBinder localBinder = new LocalBinder();  private MediaPlayer player;  private boolean isPause = false;   //播放器是否处于暂停状态  private boolean isSame = false;   //所点播歌曲是否是当前播放歌曲  private Integer position = -1;    //设置播放标记  private List<String> music_name;   //歌曲列表  private List<String> music_path;   public StreamingMediaPlayer(Context context,TextView textStreamed, ImageButton  playButton, Button  streamButton,ProgressBar  progressBar)   {     this.context = context;    this.textStreamed = textStreamed;    this.playButton = playButton;    this.progressBar = progressBar;  }  /**   * Progressivly download the media to a temporary location and update the MediaPlayer as new content becomes available.   */  public void startStreaming(final String mediaUrl, long  mediaLengthInKb, long  mediaLengthInSeconds) throws IOException {    this.mediaLengthInKb = mediaLengthInKb;    this.mediaLengthInSeconds = mediaLengthInSeconds;    r = new Runnable() {      public void run() {        try {          Log.i("downloadAudioIncrement", "downloadAudioIncrement");          downloadAudioIncrement(mediaUrl);        } catch (IOException e) {          Log.e(getClass().getName(), "Unable to initialize the MediaPlayer for fileUrl=" + mediaUrl, e);          return;        }      }    };    playerThread = new Thread(r);    playerThread.start();    //new Thread(r).start();  }  /**   * Download the url stream to a temporary location and then call the setDataSource   * for that local file   */  public void downloadAudioIncrement(String mediaUrl) throws IOException {    URLConnection cn = new URL(mediaUrl).openConnection();    cn.addRequestProperty("User-Agent","NSPlayer/10.0.0.4072 WMFSDK/10.0");    cn.connect();    InputStream stream = cn.getInputStream();    if (stream == null) {      Log.e(getClass().getName(), "Unable to create InputStream for mediaUrl:" + mediaUrl);    }    downloadingMediaFile = new File(context.getCacheDir(),"downloadingMedia.dat");    // Just in case a prior deletion failed because our code crashed or something, we also delete any previously    // downloaded file to ensure we start fresh. If you use this code, always delete    // no longer used downloads else you'll quickly fill up your hard disk memory. Of course, you can also    // store any previously downloaded file in a separate data cache for instant replay if you wanted as well.    if (downloadingMediaFile.exists()) {      downloadingMediaFile.delete();    }    FileOutputStream out = new FileOutputStream(downloadingMediaFile);    byte buf[] = new byte[16384];    int totalBytesRead = 0, incrementalBytesRead = 0;    do {      int numread = stream.read(buf);      if (numread <= 0)        break;      out.write(buf, 0, numread);      totalBytesRead += numread;      incrementalBytesRead += numread;      totalKbRead = totalBytesRead/1000;      testMediaBuffer();        fireDataLoadUpdate();    } while (validateNotInterrupted());        stream.close();    if (validateNotInterrupted()) {        fireDataFullyLoaded();    }  }  private boolean validateNotInterrupted() {    if (isInterrupted) {      if (mediaPlayer != null) {        mediaPlayer.pause();        //mediaPlayer.release();      }      return false;    } else {      return true;    }  }  /**   * Test whether we need to transfer buffered data to the MediaPlayer.   * Interacting with MediaPlayer on non-main UI thread can causes crashes to so perform this using a Handler.   */  private void testMediaBuffer() {    Runnable updater = new Runnable() {      public void run() {        if (mediaPlayer == null) {          // Only create the MediaPlayer once we have the minimum buffered data          if ( totalKbRead >= INTIAL_KB_BUFFER) {            try {              startMediaPlayer();            } catch (Exception e) {              Log.e(getClass().getName(), "Error copying buffered conent.", e);            }          }        } else if ( mediaPlayer.getDuration() - mediaPlayer.getCurrentPosition() <= 1000 ){          // NOTE: The media player has stopped at the end so transfer any existing buffered data          // We test for < 1second of data because the media player can stop when there is still          // a few milliseconds of data left to play          transferBufferToMediaPlayer();        }      }    };    handler.post(updater);  }  private void startMediaPlayer() {    try {      File bufferedFile = new File(context.getCacheDir(),"playingMedia" + (counter++) + ".dat");      // We double buffer the data to avoid potential read/write errors that could happen if the      // download thread attempted to write at the same time the MediaPlayer was trying to read.      // For example, we can't guarantee that the MediaPlayer won't open a file for playing and leave it locked while      // the media is playing. This would permanently deadlock the file download. To avoid such a deadloack,      // we move the currently loaded data to a temporary buffer file that we start playing while the remaining      // data downloads.      moveFile(downloadingMediaFile,bufferedFile);      Log.e(getClass().getName(),"Buffered File path: " + bufferedFile.getAbsolutePath());      Log.e(getClass().getName(),"Buffered File length: " + bufferedFile.length()+"");      mediaPlayer = createMediaPlayer(bufferedFile);      // We have pre-loaded enough content and started the MediaPlayer so update the buttons & progress meters.      mediaPlayer.start();      startPlayProgressUpdater();      playButton.setEnabled(true);    } catch (IOException e) {      Log.e(getClass().getName(), "Error initializing the MediaPlayer.", e);      return;    }  }  public void pausePlayer(){    try {      getMediaPlayer().pause();    } catch (Exception e) {      e.printStackTrace();    }  }  public void startPlayer(){    getMediaPlayer().start();  }  public void stopPlayer(){    getMediaPlayer().stop();  }  /**   * 根据文件创建一个mediaplayer对象   */  private MediaPlayer createMediaPlayer(File mediaFile)  throws IOException {    MediaPlayer mPlayer = new MediaPlayer();    mPlayer.setOnErrorListener(        new MediaPlayer.OnErrorListener() {          public boolean onError(MediaPlayer mp, int what, int extra) {            Log.e(getClass().getName(), "Error in MediaPlayer: (" + what +") with extra (" +extra +")" );            return false;          }        });    // It appears that for security/permission reasons, it is better to pass a FileDescriptor rather than a direct path to the File.    // Also I have seen errors such as "PVMFErrNotSupported" and "Prepare failed.: status=0x1" if a file path String is passed to    // setDataSource(). So unless otherwise noted, we use a FileDescriptor here.    FileInputStream fis = new FileInputStream(mediaFile);    mPlayer.setDataSource(fis.getFD());    mPlayer.prepare();    return mPlayer;}
package com.shadow.util;import java.io.BufferedInputStream;import java.io.BufferedOutputStream;import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.net.URL;import java.net.URLConnection;import java.util.ArrayList;import java.util.List;import com.shadow.service.AudioPlayService.LocalBinder;import android.app.Service;import android.content.Context;import android.content.Intent;import android.media.MediaPlayer;import android.os.Binder;import android.os.Handler;import android.os.IBinder;import android.util.Log;import android.widget.Button;import android.widget.ImageButton;import android.widget.ProgressBar;import android.widget.TextView;import android.widget.Toast;/** * MediaPlayer does not yet support streaming from external URLs so this class provides a pseudo-streaming function * by downloading the content incrementally & playing as soon as we get enough audio in our temporary storage. */public class StreamingMediaPlayer extends Service{  private static final int INTIAL_KB_BUFFER = 96*10/8;//assume 96kbps*10secs/8bits per byte  private TextView textStreamed;  private ImageButton playButton;  private ProgressBar  progressBar;  // Track for display by progressBar  private long mediaLengthInKb, mediaLengthInSeconds;  private int totalKbRead = 0;  // Create Handler to call View updates on the main UI thread.  private final Handler handler = new Handler();  private MediaPlayer   mediaPlayer;  private File downloadingMediaFile;  private boolean isInterrupted;  private Context context;  private int counter = 0;  private static Runnable r;  private static Thread playerThread;  private LocalBinder localBinder = new LocalBinder();  private MediaPlayer player;  private boolean isPause = false;   //播放器是否处于暂停状态  private boolean isSame = false;   //所点播歌曲是否是当前播放歌曲  private Integer position = -1;    //设置播放标记  private List<String> music_name;   //歌曲列表  private List<String> music_path;   public StreamingMediaPlayer(Context context,TextView textStreamed, ImageButton  playButton, Button  streamButton,ProgressBar  progressBar)   {     this.context = context;    this.textStreamed = textStreamed;    this.playButton = playButton;    this.progressBar = progressBar;  }  /**   * Progressivly download the media to a temporary location and update the MediaPlayer as new content becomes available.   */  public void startStreaming(final String mediaUrl, long  mediaLengthInKb, long  mediaLengthInSeconds) throws IOException {    this.mediaLengthInKb = mediaLengthInKb;    this.mediaLengthInSeconds = mediaLengthInSeconds;    r = new Runnable() {      public void run() {        try {          Log.i("downloadAudioIncrement", "downloadAudioIncrement");          downloadAudioIncrement(mediaUrl);        } catch (IOException e) {          Log.e(getClass().getName(), "Unable to initialize the MediaPlayer for fileUrl=" + mediaUrl, e);          return;        }      }    };    playerThread = new Thread(r);    playerThread.start();    //new Thread(r).start();  }  /**   * Download the url stream to a temporary location and then call the setDataSource   * for that local file   */  public void downloadAudioIncrement(String mediaUrl) throws IOException {    URLConnection cn = new URL(mediaUrl).openConnection();    cn.addRequestProperty("User-Agent","NSPlayer/10.0.0.4072 WMFSDK/10.0");    cn.connect();    InputStream stream = cn.getInputStream();    if (stream == null) {      Log.e(getClass().getName(), "Unable to create InputStream for mediaUrl:" + mediaUrl);    }    downloadingMediaFile = new File(context.getCacheDir(),"downloadingMedia.dat");    // Just in case a prior deletion failed because our code crashed or something, we also delete any previously    // downloaded file to ensure we start fresh. If you use this code, always delete    // no longer used downloads else you'll quickly fill up your hard disk memory. Of course, you can also    // store any previously downloaded file in a separate data cache for instant replay if you wanted as well.    if (downloadingMediaFile.exists()) {      downloadingMediaFile.delete();    }    FileOutputStream out = new FileOutputStream(downloadingMediaFile);    byte buf[] = new byte[16384];    int totalBytesRead = 0, incrementalBytesRead = 0;    do {      int numread = stream.read(buf);      if (numread <= 0)        break;      out.write(buf, 0, numread);      totalBytesRead += numread;      incrementalBytesRead += numread;      totalKbRead = totalBytesRead/1000;      testMediaBuffer();        fireDataLoadUpdate();    } while (validateNotInterrupted());        stream.close();    if (validateNotInterrupted()) {        fireDataFullyLoaded();    }  }  private boolean validateNotInterrupted() {    if (isInterrupted) {      if (mediaPlayer != null) {        mediaPlayer.pause();        //mediaPlayer.release();      }      return false;    } else {      return true;    }  }  /**   * Test whether we need to transfer buffered data to the MediaPlayer.   * Interacting with MediaPlayer on non-main UI thread can causes crashes to so perform this using a Handler.   */  private void testMediaBuffer() {    Runnable updater = new Runnable() {      public void run() {        if (mediaPlayer == null) {          // Only create the MediaPlayer once we have the minimum buffered data          if ( totalKbRead >= INTIAL_KB_BUFFER) {            try {              startMediaPlayer();            } catch (Exception e) {              Log.e(getClass().getName(), "Error copying buffered conent.", e);            }          }        } else if ( mediaPlayer.getDuration() - mediaPlayer.getCurrentPosition() <= 1000 ){          // NOTE: The media player has stopped at the end so transfer any existing buffered data          // We test for < 1second of data because the media player can stop when there is still          // a few milliseconds of data left to play          transferBufferToMediaPlayer();        }      }    };    handler.post(updater);  }  private void startMediaPlayer() {    try {      File bufferedFile = new File(context.getCacheDir(),"playingMedia" + (counter++) + ".dat");      // We double buffer the data to avoid potential read/write errors that could happen if the      // download thread attempted to write at the same time the MediaPlayer was trying to read.      // For example, we can't guarantee that the MediaPlayer won't open a file for playing and leave it locked while      // the media is playing. This would permanently deadlock the file download. To avoid such a deadloack,      // we move the currently loaded data to a temporary buffer file that we start playing while the remaining      // data downloads.      moveFile(downloadingMediaFile,bufferedFile);      Log.e(getClass().getName(),"Buffered File path: " + bufferedFile.getAbsolutePath());      Log.e(getClass().getName(),"Buffered File length: " + bufferedFile.length()+"");      mediaPlayer = createMediaPlayer(bufferedFile);      // We have pre-loaded enough content and started the MediaPlayer so update the buttons & progress meters.      mediaPlayer.start();      startPlayProgressUpdater();      playButton.setEnabled(true);    } catch (IOException e) {      Log.e(getClass().getName(), "Error initializing the MediaPlayer.", e);      return;    }  }  public void pausePlayer(){    try {      getMediaPlayer().pause();    } catch (Exception e) {      e.printStackTrace();    }  }  public void startPlayer(){    getMediaPlayer().start();  }  public void stopPlayer(){    getMediaPlayer().stop();  }  /**   * 根据文件创建一个mediaplayer对象   */  private MediaPlayer createMediaPlayer(File mediaFile)  throws IOException {    MediaPlayer mPlayer = new MediaPlayer();    mPlayer.setOnErrorListener(        new MediaPlayer.OnErrorListener() {          public boolean onError(MediaPlayer mp, int what, int extra) {            Log.e(getClass().getName(), "Error in MediaPlayer: (" + what +") with extra (" +extra +")" );            return false;          }        });    // It appears that for security/permission reasons, it is better to pass a FileDescriptor rather than a direct path to the File.    // Also I have seen errors such as "PVMFErrNotSupported" and "Prepare failed.: status=0x1" if a file path String is passed to    // setDataSource(). So unless otherwise noted, we use a FileDescriptor here.    FileInputStream fis = new FileInputStream(mediaFile);    mPlayer.setDataSource(fis.getFD());    mPlayer.prepare();    return mPlayer;  }  /**   * 把缓存转化成mediaplay对象   * Transfer buffered data to the MediaPlayer.   * NOTE: Interacting with a MediaPlayer on a non-main UI thread can cause thread-lock and crashes so   * this method should always be called using a Handler.   */  private void transferBufferToMediaPlayer() {    try {      // First determine if we need to restart the player after transferring data...e.g. perhaps the user pressed pause      boolean wasPlaying = mediaPlayer.isPlaying();      int curPosition = mediaPlayer.getCurrentPosition();      // Copy the currently downloaded content to a new buffered File. Store the old File for deleting later.      File oldBufferedFile = new File(context.getCacheDir(),"playingMedia" + counter + ".dat");      File bufferedFile = new File(context.getCacheDir(),"playingMedia" + (counter++) + ".dat");      // This may be the last buffered File so ask that it be delete on exit. If it's already deleted, then this won't mean anything. If you want to      // keep and track fully downloaded files for later use, write caching code and please send me a copy.      bufferedFile.deleteOnExit();      moveFile(downloadingMediaFile,bufferedFile);      // Pause the current player now as we are about to create and start a new one. So far (Android v1.5),      // this always happens so quickly that the user never realized we've stopped the player and started a new one      mediaPlayer.pause();      // Create a new MediaPlayer rather than try to re-prepare the prior one.      mediaPlayer = createMediaPlayer(bufferedFile);      mediaPlayer.seekTo(curPosition);      // Restart if at end of prior buffered content or mediaPlayer was previously playing.      //  NOTE: We test for < 1second of data because the media player can stop when there is still      // a few milliseconds of data left to play      boolean atEndOfFile = mediaPlayer.getDuration() - mediaPlayer.getCurrentPosition() <= 1000;      if (wasPlaying || atEndOfFile){        mediaPlayer.start();      }      // Lastly delete the previously playing buffered File as it's no longer needed.      oldBufferedFile.delete();    }catch (Exception e) {      Log.e(getClass().getName(), "Error updating to newly loaded content.", e);    }  }  private void fireDataLoadUpdate() {    Runnable updater = new Runnable() {      public void run() {        //textStreamed.setText((totalKbRead + " Kb read"));        float loadProgress = ((float)totalKbRead/(float)mediaLengthInKb);        //progressBar.setSecondaryProgress((int)(loadProgress*100));      }    };    handler.post(updater);  }  private void fireDataFullyLoaded() {    Runnable updater = new Runnable() {      public void run() {          transferBufferToMediaPlayer();          // Delete the downloaded File as it's now been transferred to the currently playing buffer file.          downloadingMediaFile.delete();        //textStreamed.setText(("Audio full loaded: " + totalKbRead + " Kb read"));      }    };    handler.post(updater);  }  //TODO 这个方法应该可以控制歌曲的播放  public MediaPlayer getMediaPlayer() {    return mediaPlayer;  }  public void startPlayProgressUpdater() {    float progress = (((float)mediaPlayer.getCurrentPosition()/1000)/mediaLengthInSeconds);    progressBar.setProgress((int)(progress*100));    if (mediaPlayer.isPlaying()) {      Runnable notification = new Runnable() {        public void run() {          startPlayProgressUpdater();        }      };      handler.postDelayed(notification,1000);    }  }  public void interrupt() {    playButton.setEnabled(false);    isInterrupted = true;    validateNotInterrupted();  }  /**   * Move the file in oldLocation to newLocation.   */  public void moveFile(File  oldLocation, File  newLocation)  throws IOException {    if ( oldLocation.exists( )) {      BufferedInputStream reader = new BufferedInputStream( new FileInputStream(oldLocation) );      BufferedOutputStream writer = new BufferedOutputStream( new FileOutputStream(newLocation, false));      try {        byte[] buff = new byte[8192];        int numChars;        while ( (numChars = reader.read( buff, 0, buff.length ) ) != -1) {          writer.write( buff, 0, numChars );         }      } catch( IOException ex ) {        throw new IOException("IOException when transferring " + oldLocation.getPath() + " to " + newLocation.getPath());      } finally {        try {          if ( reader != null ){            writer.close();            reader.close();          }        } catch( IOException ex ){          Log.e(getClass().getName(),"Error closing files when transferring " + oldLocation.getPath() + " to " + newLocation.getPath() );        }      }    } else {      throw new IOException("Old location does not exist when transferring " + oldLocation.getPath() + " to " + newLocation.getPath() );    }  }  /**   * 取service中的播放器对象   * @return 播放器对象   */  public MediaPlayer getPlayer() {    return this.player;  }  @Override  public void onStart(Intent intent, int startId) {    super.onStart(intent, startId);    /**     * 1.现在需要的就是做从PlayActivity里获取歌曲列表,和歌曲路径,歌曲手名     *    并存放到各个集合里     * 2.之后就是对对这些数组进行处理     */    music_name = new ArrayList<String>();    music_path = new ArrayList<String>();    String info = intent.getStringExtra("info");    //songPath = intent.getStringExtra("songPath");    Toast.makeText(getApplicationContext(), "歌曲播放异常", Toast.LENGTH_SHORT).show();    player = new MediaPlayer();    try {      playMusic(info);    } catch (Exception e) {      Toast.makeText(getApplicationContext(), "歌曲播放异常", Toast.LENGTH_SHORT).show();      e.printStackTrace();    }  }  //播放音乐  private void playMusic(String info) throws Exception {    if ("play".equals(info)) {      if (isPause) {// 暂停后,继续播放        player.start();        isPause = false;      } else if (isSame) {// 如果现在播放和与所点播歌曲时同一首,继续播放所选歌曲        player.start();      } else {// 点播某一首歌曲        play();      }    } else if ("pause".equals(info)) {      player.pause();// 暂停      isPause = true;    } else if ("before".equals(info)) {      playBefore();// 播放上一首    } else if ("after".equals(info)) {      playAfter();// 播放下一首    }  }  private void play() throws Exception {    //TODO 获取歌曲路径    try {      Log.i("playtest", "playtest");    //  myApp.setPlaying_position(position); //设置歌曲 当前的播放标记      player.reset();      //player.setDataSource(songPath);      player.start();      //musicName = music_name.get(position);    } catch (Exception e) {      e.printStackTrace();    }  }  private void playBefore() throws Exception {    if (position == 0) {      position = music_name.size() - 1;    } else {      position--;    }    play();  }  private void playAfter() throws Exception {    if (position == 0) {      position = music_name.size() + 1;    } else {      position++;    }    play();  }  public class LocalBinder extends Binder {    public StreamingMediaPlayer getService() {      return StreamingMediaPlayer.this;    }  }  @Override  public void onDestroy() {    super.onDestroy();  }  @Override  public boolean onUnbind(Intent intent) {    return super.onUnbind(intent);  }  @Override  public IBinder onBind(Intent intent) {    return localBinder;  }}

更多关于Android相关内容感兴趣的读者可查看本站专题:《Android多媒体操作技巧汇总(音频,视频,录音等)》、《Android开发入门与进阶教程》、《Android视图View技巧总结》、《Android编程之activity操作技巧总结》、《Android操作SQLite数据库技巧总结》、《Android操作json格式数据技巧总结》、《Android数据库操作技巧总结》、《Android文件操作技巧汇总》、《Android编程开发之SD卡操作方法汇总》、《Android资源操作技巧汇总》及《Android控件用法总结

希望本文所述对大家Android程序设计有所帮助。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表