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程序设计有所帮助。
上一篇: Java连接六类数据库技巧全攻略
下一篇: java实现检测是否字符串中包含中文
推荐阅读
-
Android实现使用流媒体播放远程mp3文件的方法
-
Android使用SharedPreferences存储XML文件的实现方法
-
Android使用SharedPreferences存储XML文件的实现方法
-
详解Android App中使用VideoView来实现视频播放的方法
-
详解Android App中使用VideoView来实现视频播放的方法
-
Android编程实现使用SoundPool播放音乐的方法
-
python使用win32com库播放mp3文件的方法
-
python使用PyGame播放Midi和Mp3文件的方法
-
Android编程实现使用SoundPool播放音乐的方法
-
Android编程实现使用webView打开本地html文件的方法