当前位置: 移动技术网 > IT编程>移动开发>Android > Android实现使用流媒体播放远程mp3文件的方法

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

2019年07月24日  | 移动技术网IT编程  | 我要评论

clc,涂改网,计算机培训学校

本文实例讲述了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程序设计有所帮助。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网