久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

Android通過(guò)JUV+Red5+Speex實(shí)現(xiàn)網(wǎng)絡(luò)語(yǔ)音聊天(一)

 quasiceo 2016-03-07
2012-12-19 19:38 7928人閱讀 評(píng)論(4) 收藏 舉報(bào)
分類:

先說(shuō)下實(shí)現(xiàn)原理,手機(jī)采集到語(yǔ)音后進(jìn)過(guò)Speex編碼,通過(guò)juv以直播形式發(fā)布自己的語(yǔ)音流到red5,,也是通過(guò)juv播放對(duì)方的直播流,,經(jīng)過(guò)Speex解碼后輸出到揚(yáng)聲器,如下圖:

Android  voip  流程圖
Android端采集編碼和解碼播放Speex,,參考android-recorder,,至于他用的red5客戶端,看了下,,沒(méi)看明白,。。,。
JUV這庫(kù)吧 好上手,,雖然是付費(fèi)的,但是有30天的試用,,可長(zhǎng)期申請(qǐng),。暫時(shí)用下也不錯(cuò)。另外,,國(guó)內(nèi)有破解版,,你懂得

核心代碼如下:

  1. public class AudioCenter extends AbstractMicrophone  


首先,,音頻處理類繼承自JUV庫(kù)中的 AbstractMicrophone,,便可以使用 fireOnAudioData方法向Red5服務(wù)端發(fā)布音頻數(shù)據(jù),。

  1. public void encSpeexAudio() {  
  2.   new Thread(new Runnable() {  
  3.    
  4.     @Override  
  5.     public void run() {  
  6.       int bufferSize = AudioRecord.getMinBufferSize(8000, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT);  
  7.       short[] mAudioRecordBuffer = new short[bufferSize];  
  8.       AudioRecord mAudioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, 8000, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, bufferSize);  
  9.       mAudioRecord.startRecording();  
  10.       int bufferRead = 0;  
  11.       int len;  
  12.       isEncoding = true;  
  13.    
  14.       while (isEncoding) {  
  15.         bufferRead = mAudioRecord.read(mAudioRecordBuffer, 0, frameSize);  
  16.    
  17.         if (bufferRead > 0) {  
  18.           try {  
  19.               len = speex.encode(mAudioRecordBuffer, 0, processedData, frameSize);  
  20.               // LogHelper.d(subTAG, "EncSpeexAudio "+ len);  
  21.             byte[] speexData = new byte[len + 1];  
  22.             System.arraycopy(SpeexRtmpHead, 0, speexData, 01);  
  23.             System.arraycopy(processedData, 0, speexData, 1, len);  
  24.             fireOnAudioData(new MediaDataByteArray(20new ByteArray(speexData)));  
  25.           } catch (Exception e) {  
  26.             e.printStackTrace();  
  27.           }  
  28.         }  
  29.       }  
  30.       mAudioRecord.stop();  
  31.       mAudioRecord.release();  
  32.       mAudioRecord = null;  
  33.     }  
  34.   }, "EncSpeexAudio Thread").start();  
  35. }  


以上是編碼上傳線程,一個(gè)關(guān)鍵技術(shù)點(diǎn):SpeexRtmpHead,曾經(jīng)困擾我很長(zhǎng)一段時(shí)間,,也是因?yàn)樽约簞傞_(kāi)始解除對(duì)RTMP協(xié)議只停留在api調(diào)用層面,。

  1. private byte[] SpeexRtmpHead = new byte[] { (byte0xB2 };  



我們首先要知道“RTMP Packet中封裝的音視頻數(shù)據(jù)流,其實(shí)和FLV封裝音頻和視頻數(shù)據(jù)的方式是相同的,?!?/p>

Audio tag 數(shù)據(jù)區(qū)
audio信息 1byte 前四位bits表示音頻格式:
0 – 未壓縮
1 = ADPCM
2 = MP3
3 = Linear PCM, little endian
4 = Nellymoser 16-kHz mono
5 = Nellymoser 8-kHz mono
6 = Nellymoser
7 = G.711 A-law logarithmic PCM
8 = G.711 mu-law logarithmic PCM
9 = reserved
10 = AAC
11 = Speex
14 = MP3 8-Khz
15 = Device-specific sound
下面兩位bits表示samplerate:
0 – 5.5kHz
1 – 11kHz
2 – 22kHz
3 – 44kHz
下面一位bit表示每個(gè)采樣的長(zhǎng)度:
0 – snd8Bit
1 – snd16Bit
下面一位bit表示類型:
0 – sndMomo
1 – sndStereo
audio數(shù)據(jù)區(qū) 不定   if SoundFormat == 10    AACAUDIODATAelse    Sound data—varies by format

由Flv協(xié)議的AudioTag數(shù)據(jù)區(qū)可查得,在數(shù)據(jù)區(qū)前有一個(gè)字節(jié)的audio信息,,我們采用speex編碼,,8KHz采樣,每個(gè)采樣16bit,,單聲道,。那么 得出的數(shù)據(jù)為10110010 十六進(jìn)制:0xB2,將它拼裝到每個(gè)數(shù)據(jù)區(qū)前,通過(guò)fireOnAudioData發(fā)布,,則為標(biāo)準(zhǔn)的Rtmp數(shù)據(jù)上傳到服務(wù)器,。這時(shí)候可以使用red5-publisher測(cè)試,已經(jīng)能聽(tīng)到聲音了,。不清楚red5-publisher使用的朋友,,可以看我上篇關(guān)于Red5的配置

  1. public void playSpeexAudio() {  
  2.   new Thread(new Runnable() {  
  3.     @Override  
  4.     public void run() {  
  5.       short[] decData = new short[256];  
  6.       AudioTrack audioTrack;  
  7.       int bufferSizeInBytes = AudioTrack.getMinBufferSize(8000, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT);  
  8.       audioTrack = new AudioTrack(AudioManager.STREAM_VOICE_CALL, 8000, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, 2 * bufferSizeInBytes, AudioTrack.MODE_STREAM);  
  9.       audioTrack.play();  
  10.       isPlaying = true;  
  11.       while (isPlaying) {  
  12.         while (encData.size() > 0) {  
  13.           byte[] data = encData.elementAt(0);  
  14.           encData.removeElementAt(0);  
  15.           int dec;  
  16.             dec = speex.decode(data, decData, data.length);  
  17.             // LogHelper.d(subTAG, "playSpeexAudio "+ dec);  
  18.           if (dec > 0) {  
  19.             audioTrack.write(decData, 0, dec);  
  20.           }  
  21.         }  
  22.         try {  
  23.           Thread.sleep(10);  
  24.         } catch (InterruptedException e) {  
  25.           e.printStackTrace();  
  26.         }  
  27.    
  28.       }  
  29.       audioTrack.stop();  
  30.       audioTrack.release();  
  31.       audioTrack = null;  
  32.    
  33.     }  
  34.   }, "PlaySpeexAudio Thread").start();  
  35. }  


以上為音頻解碼線程,,沒(méi)什么難點(diǎn),,只需注意我使用了一個(gè)Vector 來(lái)緩存juv拉下來(lái)的speex語(yǔ)音數(shù)據(jù)

private Vector encData = new Vector();

采集編碼解碼播放先談到這里,下篇講下juv的連接和數(shù)據(jù)傳輸相關(guān),。
如有疑問(wèn),,歡迎與我交流。

原創(chuàng)文章,,轉(zhuǎn)載請(qǐng)注明: 轉(zhuǎn)載自貝殼博客

本文鏈接地址: Android通過(guò)JUV+Red5+Speex實(shí)現(xiàn)網(wǎng)絡(luò)語(yǔ)音聊天(一)

0
0

我的同類文章

猜你在找
查看評(píng)論
3樓 LLz. 2014-01-10 11:19發(fā)表 [回復(fù)]
您好方便把代碼連接發(fā)一下學(xué)習(xí)學(xué)習(xí)嗎
Re: LLz. 2014-01-13 13:56發(fā)表 [回復(fù)]
回復(fù)kongbaidepao:這個(gè)不知道回音怎么解決
2樓 whhpc19891120 2013-04-16 10:34發(fā)表 [回復(fù)]
while(!isRecording){
//從bufferSize中讀取字節(jié),返回讀取的short個(gè)數(shù)
int tmp = record.read(buffer, 0, framesize);
Log.d("tmp:",""+tmp);
if(tmp >0){
final long ctime = System.currentTimeMillis();
//對(duì)data進(jìn)行speex編碼
int len = speex.encode(buffer, 0, data, framesize);
Log.d("len:",len+"");
byte[] speexData = new byte[len + 1];
byte[] SpeexRtmpHead = new byte[] { (byte) 0xB6 };

System.arraycopy(SpeexRtmpHead, 0, speexData, 0, 1);
System.arraycopy(data, 0, speexData, 1, len);

fireOnAudioData(new MediaDataByteArray(20 , new ByteArray(speexData)));
final int spent = (int) (System.currentTimeMillis() - ctime);
Log.d("花費(fèi)時(shí)間"," "+spent);
}
}
1樓 whhpc19891120 2013-04-16 10:34發(fā)表 [回復(fù)]
您好,,我最近也在學(xué)習(xí)流媒體服務(wù),,根據(jù)您的方法沒(méi)有聲音,android 發(fā)送到fms服務(wù)器, 轉(zhuǎn)發(fā)給flex播放,。
//根據(jù)定義好的幾個(gè)配置,,來(lái)獲取合適的緩沖大小
int bufferSize = AudioRecord.getMinBufferSize(frequence, channelConfig, audioEncoding);
Log.d("bufferSize","" + bufferSize);
//實(shí)例化AudioRecord
AudioRecord record = new AudioRecord(source, frequence, channelConfig, audioEncoding, bufferSize);
//定義緩沖
buffer = new short[bufferSize];
data = new byte[size_bufferencode];
//開(kāi)始錄制
Log.d(AUDIO,"開(kāi)始錄制");
record.startRecording();

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn),。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多