久久精品精选,精品九九视频,www久久只有这里有精品,亚洲熟女乱色综合一区
    分享

    Android通過JUV+Red5+Speex實現網絡語音聊天(一)

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

    先說下實現原理,手機采集到語音后進過Speex編碼,通過juv以直播形式發布自己的語音流到red5,也是通過juv播放對方的直播流,經過Speex解碼后輸出到揚聲器,如下圖:

    Android  voip  流程圖
    Android端采集編碼和解碼播放Speex,參考android-recorder,至于他用的red5客戶端,看了下,沒看明白。。。
    JUV這庫吧 好上手,雖然是付費的,但是有30天的試用,可長期申請。暫時用下也不錯。另外,國內有破解版,你懂得

    核心代碼如下:

    1. public class AudioCenter extends AbstractMicrophone  


    首先,音頻處理類繼承自JUV庫中的 AbstractMicrophone,便可以使用 fireOnAudioData方法向Red5服務端發布音頻數據。

    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. }  


    以上是編碼上傳線程,一個關鍵技術點:SpeexRtmpHead,曾經困擾我很長一段時間,也是因為自己剛開始解除對RTMP協議只停留在api調用層面。

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



    我們首先要知道“RTMP Packet中封裝的音視頻數據流,其實和FLV封裝音頻和視頻數據的方式是相同的。”

    Audio tag 數據區
    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表示每個采樣的長度:
    0 – snd8Bit
    1 – snd16Bit
    下面一位bit表示類型:
    0 – sndMomo
    1 – sndStereo
    audio數據區 不定   if SoundFormat == 10    AACAUDIODATAelse    Sound data—varies by format

    由Flv協議的AudioTag數據區可查得,在數據區前有一個字節的audio信息,我們采用speex編碼,8KHz采樣,每個采樣16bit,單聲道。那么 得出的數據為10110010 十六進制:0xB2,將它拼裝到每個數據區前,通過fireOnAudioData發布,則為標準的Rtmp數據上傳到服務器。這時候可以使用red5-publisher測試,已經能聽到聲音了。不清楚red5-publisher使用的朋友,可以看我上篇關于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. }  


    以上為音頻解碼線程,沒什么難點,只需注意我使用了一個Vector 來緩存juv拉下來的speex語音數據

    private Vector encData = new Vector();

    采集編碼解碼播放先談到這里,下篇講下juv的連接和數據傳輸相關。
    如有疑問,歡迎與我交流。

    原創文章,轉載請注明: 轉載自貝殼博客

    本文鏈接地址: Android通過JUV+Red5+Speex實現網絡語音聊天(一)

    0
    0

    我的同類文章

    猜你在找
    查看評論
    3樓 LLz. 2014-01-10 11:19發表 [回復]
    您好方便把代碼連接發一下學習學習嗎
    Re: LLz. 2014-01-13 13:56發表 [回復]
    回復kongbaidepao:這個不知道回音怎么解決
    2樓 whhpc19891120 2013-04-16 10:34發表 [回復]
    while(!isRecording){
    //從bufferSize中讀取字節,返回讀取的short個數
    int tmp = record.read(buffer, 0, framesize);
    Log.d("tmp:",""+tmp);
    if(tmp >0){
    final long ctime = System.currentTimeMillis();
    //對data進行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("花費時間"," "+spent);
    }
    }
    1樓 whhpc19891120 2013-04-16 10:34發表 [回復]
    您好,我最近也在學習流媒體服務,根據您的方法沒有聲音,android 發送到fms服務器, 轉發給flex播放。
    //根據定義好的幾個配置,來獲取合適的緩沖大小
    int bufferSize = AudioRecord.getMinBufferSize(frequence, channelConfig, audioEncoding);
    Log.d("bufferSize","" + bufferSize);
    //實例化AudioRecord
    AudioRecord record = new AudioRecord(source, frequence, channelConfig, audioEncoding, bufferSize);
    //定義緩沖
    buffer = new short[bufferSize];
    data = new byte[size_bufferencode];
    //開始錄制
    Log.d(AUDIO,"開始錄制");
    record.startRecording();

      本站是提供個人知識管理的網絡存儲空間,所有內容均由用戶發布,不代表本站觀點。請注意甄別內容中的聯系方式、誘導購買等信息,謹防詐騙。如發現有害或侵權內容,請點擊一鍵舉報。
      轉藏 分享 獻花(0

      0條評論

      發表

      請遵守用戶 評論公約

      類似文章 更多

      主站蜘蛛池模板: 国产精品大片中文字幕| 国产99视频精品免费专区| 人人妻人人澡人人爽人人DVD| 奇米四色7777中文字幕| 最新国产AV最新国产在钱| 成在线人视频免费视频| 国产福利社区一区二区| 波多野结衣久久一区二区| 亚洲AV综合色区无码二区偷拍| 国产小受被做到哭咬床单GV| 亚洲综合无码一区二区| 丰满无码人妻热妇无码区| 午夜亚洲AV日韩AV无码大全| 中文字幕国产在线精品| 狠狠色噜噜狠狠狠狠7777米奇| 国产一区二区三区美女| 国产亚洲欧美在线观看三区| 亚洲人成无码网站18禁| 国产精品成人影院在线观看| 中文字幕人妻系列人妻有码| 美日韩在线视频一区二区三区| 久久婷婷国产综合精品| 亚洲色大成网站WWW永久网站| 又爽又黄又无遮挡的激情视频| 宅男噜噜噜66网站高清| 国产在线播放专区av| 亚洲高清揄拍自拍| 毛片大全真人在线| 国产四虎永久免费观看| 欧美精品亚洲精品日韩专区| 麻豆国产成人AV在线播放| 国产日产久久高清欧美一区| 亚洲自偷自拍另类小说| 日韩中文字幕国产精品| 无码AV动漫精品专区| 搡女人真爽免费视频大全| 中国熟妇毛多多裸交视频| 亚洲欧美牲交| 日本边添边摸边做边爱的视频 | 午夜男女爽爽影院在线| 久久精品国产亚洲AV高清热|