成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

web音頻流轉(zhuǎn)發(fā)之音視頻直播

鄒強(qiáng) / 1126人閱讀

摘要:前言經(jīng)過(guò)前面兩篇文章的講解,大家已經(jīng)了解了的基本使用方法,下面我們就根據(jù)我們了解的做一個(gè)直播。因?yàn)闆](méi)有做回音消除,和破音處理,這樣聽(tīng)上去會(huì)很爽。

前言

經(jīng)過(guò)前面兩篇文章的講解,大家已經(jīng)了解了audio的基本使用方法,下面我們就根據(jù)我們了解的api做一個(gè)直播。
web音頻流轉(zhuǎn)發(fā)之AudioNode
web音頻流轉(zhuǎn)發(fā)之音頻源

原理

視頻直播:采集一幀一幀的視頻,轉(zhuǎn)換為base64轉(zhuǎn)發(fā),接收到base64后,設(shè)置為img的src,然后不停的修改img的src形成視頻

音頻直播:采集一幀一幀的音頻二進(jìn)制數(shù)據(jù),轉(zhuǎn)發(fā)2進(jìn)制數(shù)據(jù),在接收端對(duì)2進(jìn)制原始音頻數(shù)據(jù)進(jìn)行播放

采集和推流

獲取攝像頭,和麥克風(fēng)需要https

navigator.getUserMedia已經(jīng)廢棄,使用navigator.mediaDevices.getUserMedia,當(dāng)然需要做兼容

//獲取音頻視頻流數(shù)據(jù)
mediaDevices = navigator.mediaDevices.getUserMedia({audio: true,video: { width: 320, height: 240 }});
mediaDevices.then(stream => {
    //視頻流轉(zhuǎn)換到video標(biāo)簽播放
    video.srcObject = stream;
    video.play();
    //音頻流轉(zhuǎn)換到AudioNode做數(shù)據(jù)采集
    let source = audioCtx.createMediaStreamSource(stream);
    recorder = audioCtx.createScriptProcessor(2048, 1, 1);
    source.connect(recorder);
    recorder.connect(audioCtx.destination);
    recorder.onaudioprocess = function(ev){
    //采集單聲道數(shù)據(jù)
    let inputBuffer = ev.inputBuffer.getChannelData(0);
    //將視頻畫(huà)面轉(zhuǎn)換成base64發(fā)送
    ws.send(canvas.toDataURL("image/jpeg"));
    //發(fā)送音頻pcm數(shù)據(jù)
    ws.send(inputBuffer.buffer);
    };
});
video.onplay = function(){
    //將video繪制到canvas上
    interval = setInterval(function(){
        ctx.drawImage(video, 0, 0);
    },30);
    };
接收流文件

對(duì)接收的文件進(jìn)行一個(gè)緩存,以達(dá)到一個(gè)好的用戶體驗(yàn)

let ws = new WebSocket("wss://192.168.3.102"),
    imgChuncks = [],
    audioChuncks = [],
    img = null;
    //如何處理二進(jìn)制數(shù)據(jù),默認(rèn)是Blob
    ws.binaryType = "arraybuffer",
    ws.onmessage = function(evt) { 
        if(evt.data.byteLength === undefined) {
            //收到的base64圖片
            imgChuncks.push(evt.data);
        }else{
            //收到的音頻二進(jìn)制pcm數(shù)據(jù)
            audioChuncks.push(new Float32Array(evt.data));
        }
        //緩存2幀的數(shù)據(jù)后開(kāi)始播放
        if(!img && audioChuncks.length > 2){
            myplay();
        }
    };
處理流
//創(chuàng)建播放音頻視頻函數(shù)
    function myplay(){
        //創(chuàng)建img標(biāo)簽來(lái)播放base64圖片
        img = new Image();
        document.body.appendChild(img);
        //創(chuàng)建播放音頻對(duì)象
        let    myBuffer = audioCtx.createBuffer(1, 2048, audioCtx.sampleRate),
               source = audioCtx.createBufferSource(),
               recorder = audioCtx.createScriptProcessor(2048, 1, 1);
           source.connect(recorder);
           recorder.connect(audioCtx.destination);
           recorder.onaudioprocess = function(ev){
               //修改img的src達(dá)到視頻的效果
               img.src = imgChuncks.shift();
               //播放audioChuncks里面真正的二進(jìn)制數(shù)據(jù)
            ev.outputBuffer.copyToChannel(audioChuncks.shift() || new Float32Array(2048), 0, 0);
        };
    }
注意

這只是一個(gè)實(shí)例程序,為進(jìn)行任何優(yōu)化

在測(cè)試時(shí)請(qǐng)給揚(yáng)聲器插上耳機(jī)收聽(tīng),或者讓揚(yáng)聲器和麥克風(fēng)放置到不同的房間。因?yàn)闆](méi)有做回音消除,和破音處理,這樣聽(tīng)上去會(huì)很爽。

自己生成一個(gè)https文件做測(cè)試

完整代碼

index.html




    
     
    
    
    
    


    
    
    
    
    


servers.js

let https = require("https"),
    fs = require("fs"),
    WebSocket = require("ws"),
    options = {
        key: fs.readFileSync("./key.pem"),
        cert:fs.readFileSync("./key-cert.pem")
    },
    server = https.createServer(options, function(req, res){
        fs.readFile("./index.html", function(err, data){
            res.writeHead(200,{"Content-Type": "text/html"});
            res.end(data);
        });
    }).listen(443, function(){
        console.log("服務(wù)啟動(dòng)成功")
    });
const wss = new WebSocket.Server({server});
    wss.binaryType = "arraybuffer";
    wss.on("connection", (ws) => {
        ws.on("message", function(data) {  
      wss.clients.forEach(function each(client) {
            if (client.readyState === WebSocket.OPEN && client !== ws) {
              client.send(data);
            }
          });
      }); 
    });
    

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/51362.html

相關(guān)文章

  • web音頻轉(zhuǎn)發(fā)音頻

    摘要:前言音頻流轉(zhuǎn)發(fā)之音視頻直播音頻流轉(zhuǎn)發(fā)之能直播為什么不可以看完本系列文章,你就能做一個(gè)直播,真正的直播,包括音頻流的轉(zhuǎn)發(fā),這也是我最近查看發(fā)現(xiàn)有相關(guān)能實(shí)現(xiàn)音頻流的轉(zhuǎn)發(fā),所有打算分享系列文章供大家交流,如有不對(duì)之處請(qǐng)指正。 前言 web音頻流轉(zhuǎn)發(fā)之音視頻直播web音頻流轉(zhuǎn)發(fā)之AudioNodeapp能直播,web為什么不可以?看完本系列文章,你就能做一個(gè)直播,真正的直播,包括音頻流的轉(zhuǎn)發(fā),...

    FingerLiu 評(píng)論0 收藏0
  • web音頻轉(zhuǎn)發(fā)之AudioNode

    摘要:概述是一個(gè)處理音頻的通用模塊比如一個(gè)音頻源一個(gè)元素一個(gè)音頻地址或者一個(gè)中間處理模塊一個(gè)過(guò)濾器如或一個(gè)音量控制器如一個(gè)既有輸入也有輸出。下面一章就開(kāi)始介紹音頻流的轉(zhuǎn)發(fā)了。 前言 上一章地址: web音頻流轉(zhuǎn)發(fā)之音頻源下一張地址:web音頻流轉(zhuǎn)發(fā)之音視頻直播在這一章我說(shuō)幾個(gè)我們需要用到的音頻處理模塊也就3個(gè)吧,包括我們轉(zhuǎn)發(fā)流是需要用到的核心模塊。更多模塊請(qǐng)看MDN,或者看HTML5音頻AP...

    twohappy 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<