Android音频实时传输与播放(三):AMR硬编码与硬解码

分类:Android流媒体 12684人阅读 评论(23) 收藏 举报 android exception buffer null socket

转载请注明出处!

原文链接:http://blog.csdn.net/zgyulongfei/article/details/7753163


在Android中我所知道的音频编解码有两种方式:

(一)使用AudioRecord采集音频,用这种方式采集的是未经压缩的音频流;用AudioTrack播放实时音频流。用这两个类的话,如果需要对音频进行编解码,就需要自己移植编解码库了,比如可以移植ilbc,speex等开源编解码库。

ilbc的编解码实现可以查看这个专栏:http://blog.csdn.net/column/details/media.html

(二)使用MediaRecorder获取编码后的AMR音频,但由于MediaRecorder的特点,只能将流保存到文件中,但通过其他方式是可以获取到实时音频流的,这篇文章将介绍用LocalSocket的方法来实现;使用MediaPlayer来播放AMR音频流,但同样MediaPlayer也只能播放文件流,因此我用缓存的方式来播放音频。

以上两种方式各有利弊,使用方法(一)需移植编解码库,但可以播放实时音频流;使用方法(二)直接硬编硬解码效率高,但是需要对文件进行操作。

PS:这篇文章只是给大家一个参考,仅供学习之用,如果真正用到项目中还有很多地方需要优化。

我强烈推荐播放音频时候用方法(一),方法(二)虽然能够实现功能,但是实现方式不太好。


接下来看代码:

编码器:

[java] view plain copy
  1. packagecn.edu.xmu.zgy.audio.encoder;
  2. importjava.io.DataInputStream;
  3. importjava.io.IOException;
  4. importjava.net.DatagramPacket;
  5. importjava.net.DatagramSocket;
  6. importjava.net.InetAddress;
  7. importcn.edu.xmu.zgy.config.CommonConfig;
  8. importandroid.app.Activity;
  9. importandroid.media.MediaRecorder;
  10. importandroid.net.LocalServerSocket;
  11. importandroid.net.LocalSocket;
  12. importandroid.net.LocalSocketAddress;
  13. importandroid.util.Log;
  14. importandroid.widget.Toast;
  15. //blog.csdn.net/zgyulongfei
  16. //Email:zgyulongfei@gmail.com
  17. publicclassAmrAudioEncoder{
  18. privatestaticfinalStringTAG="ArmAudioEncoder";
  19. privatestaticAmrAudioEncoderamrAudioEncoder=null;
  20. privateActivityactivity;
  21. privateMediaRecorderaudioRecorder;
  22. privatebooleanisAudioRecording;
  23. privateLocalServerSocketlss;
  24. privateLocalSocketsender,receiver;
  25. privateAmrAudioEncoder(){
  26. }
  27. publicstaticAmrAudioEncodergetArmAudioEncoderInstance(){
  28. if(amrAudioEncoder==null){
  29. synchronized(AmrAudioEncoder.class){
  30. if(amrAudioEncoder==null){
  31. amrAudioEncoder=newAmrAudioEncoder();
  32. }
  33. }
  34. }
  35. returnamrAudioEncoder;
  36. }
  37. publicvoidinitArmAudioEncoder(Activityactivity){
  38. this.activity=activity;
  39. isAudioRecording=false;
  40. }
  41. publicvoidstart(){
  42. if(activity==null){
  43. showToastText("音频编码器未初始化,请先执行init方法");
  44. return;
  45. }
  46. if(isAudioRecording){
  47. showToastText("音频已经开始编码,无需再次编码");
  48. return;
  49. }
  50. if(!initLocalSocket()){
  51. showToastText("本地服务开启失败");
  52. releaseAll();
  53. return;
  54. }
  55. if(!initAudioRecorder()){
  56. showToastText("音频编码器初始化失败");
  57. releaseAll();
  58. return;
  59. }
  60. this.isAudioRecording=true;
  61. startAudioRecording();
  62. }
  63. privatebooleaninitLocalSocket(){
  64. booleanret=true;
  65. try{
  66. releaseLocalSocket();
  67. StringserverName="armAudioServer";
  68. finalintbufSize=1024;
  69. lss=newLocalServerSocket(serverName);
  70. receiver=newLocalSocket();
  71. receiver.connect(newLocalSocketAddress(serverName));
  72. receiver.setReceiveBufferSize(bufSize);
  73. receiver.setSendBufferSize(bufSize);
  74. sender=lss.accept();
  75. sender.setReceiveBufferSize(bufSize);
  76. sender.setSendBufferSize(bufSize);
  77. }catch(IOExceptione){
  78. ret=false;
  79. }
  80. returnret;
  81. }
  82. privatebooleaninitAudioRecorder(){
  83. if(audioRecorder!=null){
  84. audioRecorder.reset();
  85. audioRecorder.release();
  86. }
  87. audioRecorder=newMediaRecorder();
  88. audioRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
  89. audioRecorder.setOutputFormat(MediaRecorder.OutputFormat.RAW_AMR);
  90. finalintmono=1;
  91. audioRecorder.setAudioChannels(mono);
  92. audioRecorder.setAudioSamplingRate(8000);
  93. audioRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
  94. audioRecorder.setOutputFile(sender.getFileDescriptor());
  95. booleanret=true;
  96. try{
  97. audioRecorder.prepare();
  98. audioRecorder.start();
  99. }catch(Exceptione){
  100. releaseMediaRecorder();
  101. showToastText("手机不支持录音此功能");
  102. ret=false;
  103. }
  104. returnret;
  105. }
  106. privatevoidstartAudioRecording(){
  107. newThread(newAudioCaptureAndSendThread()).start();
  108. }
  109. publicvoidstop(){
  110. if(isAudioRecording){
  111. isAudioRecording=false;
  112. }
  113. releaseAll();
  114. }
  115. privatevoidreleaseAll(){
  116. releaseMediaRecorder();
  117. releaseLocalSocket();
  118. amrAudioEncoder=null;
  119. }
  120. privatevoidreleaseMediaRecorder(){
  121. try{
  122. if(audioRecorder==null){
  123. return;
  124. }
  125. if(isAudioRecording){
  126. audioRecorder.stop();
  127. isAudioRecording=false;
  128. }
  129. audioRecorder.reset();
  130. audioRecorder.release();
  131. audioRecorder=null;
  132. }catch(Exceptionerr){
  133. Log.d(TAG,err.toString());
  134. }
  135. }
  136. privatevoidreleaseLocalSocket(){
  137. try{
  138. if(sender!=null){
  139. sender.close();
  140. }
  141. if(receiver!=null){
  142. receiver.close();
  143. }
  144. if(lss!=null){
  145. lss.close();
  146. }
  147. }catch(IOExceptione){
  148. e.printStackTrace();
  149. }
  150. sender=null;
  151. receiver=null;
  152. lss=null;
  153. }
  154. privatebooleanisAudioRecording(){
  155. returnisAudioRecording;
  156. }
  157. privatevoidshowToastText(Stringmsg){
  158. Toast.makeText(activity,msg,Toast.LENGTH_SHORT).show();
  159. }
  160. privateclassAudioCaptureAndSendThreadimplementsRunnable{
  161. publicvoidrun(){
  162. try{
  163. sendAmrAudio();
  164. }catch(Exceptione){
  165. Log.e(TAG,"sendAmrAudio()出错");
  166. }
  167. }
  168. privatevoidsendAmrAudio()throwsException{
  169. DatagramSocketudpSocket=newDatagramSocket();
  170. DataInputStreamdataInput=newDataInputStream(receiver.getInputStream());
  171. skipAmrHead(dataInput);
  172. finalintSEND_FRAME_COUNT_ONE_TIME=10;//每次发送10帧的数据,1帧大约32B
  173. //AMR格式见博客:http://blog.csdn.net/dinggo/article/details/1966444
  174. finalintBLOCK_SIZE[]={12,13,15,17,19,20,26,31,5,0,0,0,0,0,0,0};
  175. byte[]sendBuffer=newbyte[1024];
  176. while(isAudioRecording()){
  177. intoffset=0;
  178. for(intindex=0;index<SEND_FRAME_COUNT_ONE_TIME;++index){
  179. if(!isAudioRecording()){
  180. break;
  181. }
  182. dataInput.read(sendBuffer,offset,1);
  183. intblockIndex=(int)(sendBuffer[offset]>>3)&0x0F;
  184. intframeLength=BLOCK_SIZE[blockIndex];
  185. readSomeData(sendBuffer,offset+1,frameLength,dataInput);
  186. offset+=frameLength+1;
  187. }
  188. udpSend(udpSocket,sendBuffer,offset);
  189. }
  190. udpSocket.close();
  191. dataInput.close();
  192. releaseAll();
  193. }
  194. privatevoidskipAmrHead(DataInputStreamdataInput){
  195. finalbyte[]AMR_HEAD=newbyte[]{0x23,0x21,0x41,0x4D,0x52,0x0A};
  196. intresult=-1;
  197. intstate=0;
  198. try{
  199. while(-1!=(result=dataInput.readByte())){
  200. if(AMR_HEAD[0]==result){
  201. state=(0==state)?1:0;
  202. }elseif(AMR_HEAD[1]==result){
  203. state=(1==state)?2:0;
  204. }elseif(AMR_HEAD[2]==result){
  205. state=(2==state)?3:0;
  206. }elseif(AMR_HEAD[3]==result){
  207. state=(3==state)?4:0;
  208. }elseif(AMR_HEAD[4]==result){
  209. state=(4==state)?5:0;
  210. }elseif(AMR_HEAD[5]==result){
  211. state=(5==state)?6:0;
  212. }
  213. if(6==state){
  214. break;
  215. }
  216. }
  217. }catch(Exceptione){
  218. Log.e(TAG,"readmdaterror...");
  219. }
  220. }
  221. privatevoidreadSomeData(byte[]buffer,intoffset,intlength,DataInputStreamdataInput){
  222. intnumOfRead=-1;
  223. while(true){
  224. try{
  225. numOfRead=dataInput.read(buffer,offset,length);
  226. if(numOfRead==-1){
  227. Log.d(TAG,"amr...nodatagetwaitfordatacoming.....");
  228. Thread.sleep(100);
  229. }else{
  230. offset+=numOfRead;
  231. length-=numOfRead;
  232. if(length<=0){
  233. break;
  234. }
  235. }
  236. }catch(Exceptione){
  237. Log.e(TAG,"amr..errorreadSomeData");
  238. break;
  239. }
  240. }
  241. }
  242. privatevoidudpSend(DatagramSocketudpSocket,byte[]buffer,intsendLength){
  243. try{
  244. InetAddressip=InetAddress.getByName(CommonConfig.SERVER_IP_ADDRESS.trim());
  245. intport=CommonConfig.AUDIO_SERVER_UP_PORT;
  246. byte[]sendBuffer=newbyte[sendLength];
  247. System.arraycopy(buffer,0,sendBuffer,0,sendLength);
  248. DatagramPacketpacket=newDatagramPacket(sendBuffer,sendLength);
  249. packet.setAddress(ip);
  250. packet.setPort(port);
  251. udpSocket.send(packet);
  252. }catch(IOExceptione){
  253. e.printStackTrace();
  254. }
  255. }
  256. }
  257. }

关于编码器:前面提到了,MediaRecorder的硬编码的方式只能将码流保存到文件中,这里用了LocalSocket的方式将流保存到内存中,然后从缓冲中读取码流。由于保存的格式RAW_AMR格式的,因此需要对读取到的数据进行解析,从而获得真正的音频流。想了解AMR音频码流格式的,可以查看代码中附上的网页链接。由于压缩过的码流很小,因此我在实现的时候,组合了int SEND_FRAME_COUNT_ONE_TIME = 10帧的码流后才往外发送,这样的方式造成的延迟会加重,大家可以根据自己的需要进行修改。造成延迟的另一因素是LocalSocket缓冲的大小,在这里我设置的大小是final int bufSize = 1024;代码写的很清楚详细,有疑问的可以提出。


播放器:

[java] view plain copy
  1. packagecn.edu.xmu.zgy.audio.player;
  2. importjava.io.BufferedInputStream;
  3. importjava.io.BufferedOutputStream;
  4. importjava.io.File;
  5. importjava.io.FileInputStream;
  6. importjava.io.FileOutputStream;
  7. importjava.io.IOException;
  8. importjava.io.InputStream;
  9. importjava.net.InetAddress;
  10. importjava.net.Socket;
  11. importcn.edu.xmu.zgy.config.CommonConfig;
  12. importandroid.app.Activity;
  13. importandroid.media.MediaPlayer;
  14. importandroid.os.Handler;
  15. importandroid.util.Log;
  16. //blog.csdn.net/zgyulongfei
  17. //Email:zgyulongfei@gmail.com
  18. publicclassAmrAudioPlayer{
  19. privatestaticfinalStringTAG="AmrAudioPlayer";
  20. privatestaticAmrAudioPlayerplayerInstance=null;
  21. privatelongalreadyReadByteCount=0;
  22. privateMediaPlayeraudioPlayer;
  23. privateHandlerhandler=newHandler();
  24. privatefinalStringcacheFileName="audioCacheFile";
  25. privateFilecacheFile;
  26. privateintcacheFileCount=0;
  27. //用来记录是否已经从cacheFile中复制数据到另一个cache中
  28. privatebooleanhasMovedTheCacheFlag;
  29. privatebooleanisPlaying;
  30. privateActivityactivity;
  31. privatebooleanisChaingCacheToAnother;
  32. privateAmrAudioPlayer(){
  33. }
  34. publicstaticAmrAudioPlayergetAmrAudioPlayerInstance(){
  35. if(playerInstance==null){
  36. synchronized(AmrAudioPlayer.class){
  37. if(playerInstance==null){
  38. playerInstance=newAmrAudioPlayer();
  39. }
  40. }
  41. }
  42. returnplayerInstance;
  43. }
  44. publicvoidinitAmrAudioPlayer(Activityactivity){
  45. this.activity=activity;
  46. deleteExistCacheFile();
  47. initCacheFile();
  48. }
  49. privatevoiddeleteExistCacheFile(){
  50. FilecacheDir=activity.getCacheDir();
  51. File[]needDeleteCacheFiles=cacheDir.listFiles();
  52. for(intindex=0;index<needDeleteCacheFiles.length;++index){
  53. Filecache=needDeleteCacheFiles[index];
  54. if(cache.isFile()){
  55. if(cache.getName().contains(cacheFileName.trim())){
  56. Log.e(TAG,"deletecachefile:"+cache.getName());
  57. cache.delete();
  58. }
  59. }
  60. }
  61. needDeleteCacheFiles=null;
  62. }
  63. privatevoidinitCacheFile(){
  64. cacheFile=null;
  65. cacheFile=newFile(activity.getCacheDir(),cacheFileName);
  66. }
  67. publicvoidstart(){
  68. isPlaying=true;
  69. isChaingCacheToAnother=false;
  70. setHasMovedTheCacheToAnotherCache(false);
  71. newThread(newNetAudioPlayerThread()).start();
  72. }
  73. publicvoidstop(){
  74. isPlaying=false;
  75. isChaingCacheToAnother=false;
  76. setHasMovedTheCacheToAnotherCache(false);
  77. releaseAudioPlayer();
  78. deleteExistCacheFile();
  79. cacheFile=null;
  80. handler=null;
  81. }
  82. privatevoidreleaseAudioPlayer(){
  83. playerInstance=null;
  84. if(audioPlayer!=null){
  85. try{
  86. if(audioPlayer.isPlaying()){
  87. audioPlayer.pause();
  88. }
  89. audioPlayer.release();
  90. audioPlayer=null;
  91. }catch(Exceptione){
  92. }
  93. }
  94. }
  95. privatebooleanhasMovedTheCacheToAnotherCache(){
  96. returnhasMovedTheCacheFlag;
  97. }
  98. privatevoidsetHasMovedTheCacheToAnotherCache(booleanresult){
  99. hasMovedTheCacheFlag=result;
  100. }
  101. privateclassNetAudioPlayerThreadimplementsRunnable{
  102. //从接受数据开始计算,当缓存大于INIT_BUFFER_SIZE时候开始播放
  103. privatefinalintINIT_AUDIO_BUFFER=2*1024;
  104. //剩1秒的时候播放新的缓存的音乐
  105. privatefinalintCHANGE_CACHE_TIME=1000;
  106. publicvoidrun(){
  107. try{
  108. Socketsocket=createSocketConnectToServer();
  109. receiveNetAudioThenPlay(socket);
  110. }catch(Exceptione){
  111. Log.e(TAG,e.getMessage()+"从服务端接受音频失败。。。");
  112. }
  113. }
  114. privateSocketcreateSocketConnectToServer()throwsException{
  115. StringhostName=CommonConfig.SERVER_IP_ADDRESS;
  116. InetAddressipAddress=InetAddress.getByName(hostName);
  117. intport=CommonConfig.AUDIO_SERVER_DOWN_PORT;
  118. Socketsocket=newSocket(ipAddress,port);
  119. returnsocket;
  120. }
  121. privatevoidreceiveNetAudioThenPlay(Socketsocket)throwsException{
  122. InputStreaminputStream=socket.getInputStream();
  123. FileOutputStreamoutputStream=newFileOutputStream(cacheFile);
  124. finalintBUFFER_SIZE=100*1024;//100kbbuffersize
  125. byte[]buffer=newbyte[BUFFER_SIZE];
  126. //收集了10*350b了之后才开始更换缓存
  127. inttestTime=10;
  128. try{
  129. alreadyReadByteCount=0;
  130. while(isPlaying){
  131. intnumOfRead=inputStream.read(buffer);
  132. if(numOfRead<=0){
  133. break;
  134. }
  135. alreadyReadByteCount+=numOfRead;
  136. outputStream.write(buffer,0,numOfRead);
  137. outputStream.flush();
  138. try{
  139. if(testTime++>=10){
  140. Log.e(TAG,"cacheFile="+cacheFile.length());
  141. testWhetherToChangeCache();
  142. testTime=0;
  143. }
  144. }catch(Exceptione){
  145. //TODO:handleexception
  146. }
  147. //如果复制了接收网络流的cache,则执行此操作
  148. if(hasMovedTheCacheToAnotherCache()&&!isChaingCacheToAnother){
  149. if(outputStream!=null){
  150. outputStream.close();
  151. outputStream=null;
  152. }
  153. //将接收网络流的cache删除,然后重0开始存储
  154. //initCacheFile();
  155. outputStream=newFileOutputStream(cacheFile);
  156. setHasMovedTheCacheToAnotherCache(false);
  157. alreadyReadByteCount=0;
  158. }
  159. }
  160. }catch(Exceptione){
  161. errorOperator();
  162. e.printStackTrace();
  163. Log.e(TAG,"socketdisconnect...:"+e.getMessage());
  164. thrownewException("socketdisconnect....");
  165. }finally{
  166. buffer=null;
  167. if(socket!=null){
  168. socket.close();
  169. }
  170. if(inputStream!=null){
  171. inputStream.close();
  172. inputStream=null;
  173. }
  174. if(outputStream!=null){
  175. outputStream.close();
  176. outputStream=null;
  177. }
  178. stop();
  179. }
  180. }
  181. privatevoidtestWhetherToChangeCache()throwsException{
  182. if(audioPlayer==null){
  183. firstTimeStartPlayer();
  184. }else{
  185. changeAnotherCacheWhenEndOfCurrentCache();
  186. }
  187. }
  188. privatevoidfirstTimeStartPlayer()throwsException{
  189. //当缓存已经大于INIT_AUDIO_BUFFER则开始播放
  190. if(alreadyReadByteCount>=INIT_AUDIO_BUFFER){
  191. Runnabler=newRunnable(){
  192. publicvoidrun(){
  193. try{
  194. FilefirstCacheFile=createFirstCacheFile();
  195. //设置已经从cache中复制数据,然后会删除这个cache
  196. setHasMovedTheCacheToAnotherCache(true);
  197. audioPlayer=createAudioPlayer(firstCacheFile);
  198. audioPlayer.start();
  199. }catch(Exceptione){
  200. Log.e(TAG,e.getMessage()+":infirstTimeStartPlayer()fun");
  201. }finally{
  202. }
  203. }
  204. };
  205. handler.post(r);
  206. }
  207. }
  208. privateFilecreateFirstCacheFile()throwsException{
  209. StringfirstCacheFileName=cacheFileName+(cacheFileCount++);
  210. FilefirstCacheFile=newFile(activity.getCacheDir(),firstCacheFileName);
  211. //为什么不直接播放cacheFile,而要复制cacheFile到一个新的cache,然后播放此新的cache?
  212. //是为了防止潜在的读/写错误,可能在写入cacheFile的时候,
  213. //MediaPlayer正试图读数据,这样可以防止死锁的发生。
  214. moveFile(cacheFile,firstCacheFile);
  215. returnfirstCacheFile;
  216. }
  217. privatevoidmoveFile(FileoldFile,FilenewFile)throwsIOException{
  218. if(!oldFile.exists()){
  219. thrownewIOException("oldFileisnotexists.inmoveFile()fun");
  220. }
  221. if(oldFile.length()<=0){
  222. thrownewIOException("oldFilesize=0.inmoveFile()fun");
  223. }
  224. BufferedInputStreamreader=newBufferedInputStream(newFileInputStream(oldFile));
  225. BufferedOutputStreamwriter=newBufferedOutputStream(newFileOutputStream(newFile,
  226. false));
  227. finalbyte[]AMR_HEAD=newbyte[]{0x23,0x21,0x41,0x4D,0x52,0x0A};
  228. writer.write(AMR_HEAD,0,AMR_HEAD.length);
  229. writer.flush();
  230. try{
  231. byte[]buffer=newbyte[1024];
  232. intnumOfRead=0;
  233. Log.d(TAG,"POS...newFile.length="+newFile.length()+"old="+oldFile.length());
  234. while((numOfRead=reader.read(buffer,0,buffer.length))!=-1){
  235. writer.write(buffer,0,numOfRead);
  236. writer.flush();
  237. }
  238. Log.d(TAG,"POS..AFTER...newFile.length="+newFile.length());
  239. }catch(IOExceptione){
  240. Log.e(TAG,"moveFileerror..inmoveFile()fun."+e.getMessage());
  241. thrownewIOException("moveFileerror..inmoveFile()fun.");
  242. }finally{
  243. if(reader!=null){
  244. reader.close();
  245. reader=null;
  246. }
  247. if(writer!=null){
  248. writer.close();
  249. writer=null;
  250. }
  251. }
  252. }
  253. privateMediaPlayercreateAudioPlayer(FileaudioFile)throwsIOException{
  254. MediaPlayermPlayer=newMediaPlayer();
  255. //Itappearsthatforsecurity/permissionreasons,itisbetterto
  256. //pass
  257. //aFileDescriptorratherthanadirectpathtotheFile.
  258. //AlsoIhaveseenerrorssuchas"PVMFErrNotSupported"and
  259. //"Preparefailed.:status=0x1"ifafilepathStringispassedto
  260. //setDataSource().Sounlessotherwisenoted,weusea
  261. //FileDescriptorhere.
  262. FileInputStreamfis=newFileInputStream(audioFile);
  263. mPlayer.reset();
  264. mPlayer.setDataSource(fis.getFD());
  265. mPlayer.prepare();
  266. returnmPlayer;
  267. }
  268. privatevoidchangeAnotherCacheWhenEndOfCurrentCache()throwsIOException{
  269. //检查当前cache剩余时间
  270. longtheRestTime=audioPlayer.getDuration()-audioPlayer.getCurrentPosition();
  271. Log.e(TAG,"theRestTime="+theRestTime+"isChaingCacheToAnother="
  272. +isChaingCacheToAnother);
  273. if(!isChaingCacheToAnother&&theRestTime<=CHANGE_CACHE_TIME){
  274. isChaingCacheToAnother=true;
  275. Runnabler=newRunnable(){
  276. publicvoidrun(){
  277. try{
  278. FilenewCacheFile=createNewCache();
  279. //设置已经从cache中复制数据,然后会删除这个cache
  280. setHasMovedTheCacheToAnotherCache(true);
  281. transferNewCacheToAudioPlayer(newCacheFile);
  282. }catch(Exceptione){
  283. Log.e(TAG,e.getMessage()
  284. +":changeAnotherCacheWhenEndOfCurrentCache()fun");
  285. }finally{
  286. deleteOldCache();
  287. isChaingCacheToAnother=false;
  288. }
  289. }
  290. };
  291. handler.post(r);
  292. }
  293. }
  294. privateFilecreateNewCache()throwsException{
  295. //将保存网络数据的cache复制到newCache中进行播放
  296. StringnewCacheFileName=cacheFileName+(cacheFileCount++);
  297. FilenewCacheFile=newFile(activity.getCacheDir(),newCacheFileName);
  298. Log.e(TAG,"beforemoveFile............thesize="+cacheFile.length());
  299. moveFile(cacheFile,newCacheFile);
  300. returnnewCacheFile;
  301. }
  302. privatevoidtransferNewCacheToAudioPlayer(FilenewCacheFile)throwsException{
  303. MediaPlayeroldPlayer=audioPlayer;
  304. try{
  305. audioPlayer=createAudioPlayer(newCacheFile);
  306. audioPlayer.start();
  307. }catch(Exceptione){
  308. Log.e(TAG,"filename="+newCacheFile.getName()+"size="+newCacheFile.length());
  309. Log.e(TAG,e.getMessage()+""+e.getCause()+"errorstart..intransfanNer..");
  310. }
  311. try{
  312. oldPlayer.pause();
  313. oldPlayer.reset();
  314. oldPlayer.release();
  315. }catch(Exceptione){
  316. Log.e(TAG,"ERRORreleaseoldPlayer.");
  317. }finally{
  318. oldPlayer=null;
  319. }
  320. }
  321. privatevoiddeleteOldCache(){
  322. intoldCacheFileCount=cacheFileCount-1;
  323. StringoldCacheFileName=cacheFileName+oldCacheFileCount;
  324. FileoldCacheFile=newFile(activity.getCacheDir(),oldCacheFileName);
  325. if(oldCacheFile.exists()){
  326. oldCacheFile.delete();
  327. }
  328. }
  329. privatevoiderrorOperator(){
  330. }
  331. }
  332. }

关于播放器:由于MediaPlayer的限制,我用了cache的方式来实现音频的实时播放。即把获取到的音频流首先保存到文件中,然后当保存到一定大小的时候就播放之,类似于QQ播放器那样有缓存的,只不过我这里的处理得挺粗糙。代码写的也挺详细了,如果有疑问也可以提出来。


注:编码器和播放器的编写,我都是站在巨人的肩膀上完成的,参考了一些其他资料。


在后面一篇文章中,我将附上服务器和客户端的所有代码。

希望朋友们看完能提出意见和建议,也希望看完能有所收获 ^_^


更多相关文章

  1. Android(安卓)Service AIDL 远程调用服务 【简单音乐播放实例】
  2. 优秀的Android音频播放器
  3. android listview继承BaseAdapter,自定义的适配器,getView方法执
  4. Android播放器MediaPlayer与MediaRecorder:录制音频并播放
  5. Android(安卓)Activity四种启动方式
  6. Android中通过耳机按键控制音乐播放的实现
  7. Android使用JDBC连接mysql数据库
  8. Android(安卓)3.0 r1 API中文文档(107) ―― AsyncPlayer
  9. android 开发包的离线安装方式

随机推荐

  1. Android(安卓)Debug: Using Hardware Dev
  2. Android生成和内置一个系统App
  3. android Q(10)发送通知Notification出现
  4. Android系统服务
  5. 点击事件XML里的写法
  6. android helloworld
  7. 安卓中实现两端对齐,中间fill_parent的方
  8. [Android] 获取系统顶部状态栏(Status Ba
  9. Android Manifest.xml中的permission详解
  10. Android(安卓)向桌面添加删除快捷方式