摘要:前言經(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
摘要:前言音頻流轉(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ā),...
摘要:概述是一個(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...
閱讀 1089·2021-11-19 09:40
閱讀 2227·2021-11-15 18:00
閱讀 1278·2021-10-18 13:34
閱讀 2258·2021-09-02 15:40
閱讀 1543·2019-08-30 14:01
閱讀 1122·2019-08-30 11:11
閱讀 2489·2019-08-29 15:26
閱讀 735·2019-08-29 14:15