欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

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

程序员文章站 2024-03-06 16:00:20
本文实例讲述了android实现使用流媒体播放远程mp3文件的方法。分享给大家供大家参考,具体如下: package com.shadow.util; impo...

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