web技术分享| WebRTC记录音视频流

Posted anyRTC

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了web技术分享| WebRTC记录音视频流相关的知识,希望对你有一定的参考价值。

监听开始事件

  • EventTarget.addEventListener() 方法将指定的监听器注册到 EventTarget 上,当该对象触发指定的事件时,指定的回调函数就会被执行。 事件目标可以是一个文档上的元素 Element,DocumentWindow或者任何其他支持事件的对象 (比如 XMLHttpRequest)

  • addEventListener()的工作原理是将实现EventListener的函数或对象添加到调用它的EventTarget上的指定事件类型的事件侦听器列表中。

document.querySelector('button#start').addEventListener('click', async () => 
    document.querySelector('button#start').disabled = true;
    const constraints = 
        audio: ,
        video: 
            width: 1280, height: 720
        
    ;
    await init(constraints);
);

获取音视频轨道

  • MediaDevices.getUserMedia() 会提示用户给予使用媒体输入的许可,媒体输入会产生一个MediaStream,里面包含了请求的媒体类型的轨道。此流可以包含一个视频轨道(来自硬件或者虚拟视频源,比如相机、视频采集设备和屏幕共享服务等等)、一个音频轨道(同样来自硬件或虚拟音频源,比如麦克风、A/D转换器等等),也可能是其它轨道类型。

  • 它返回一个 Promise 对象,成功后会resolve回调一个 MediaStream 对象。若用户拒绝了使用权限,或者需要的媒体源不可用,promisereject回调一个 PermissionDeniedError 或者 NotFoundError

async function init(constraints) 
    try 
        const stream = await navigator.mediaDevices.getUserMedia(constraints);
        handleSuccess(stream);
     catch (e) 
        console.error('navigator.getUserMedia error:', e);
    

  • htmlMediaElement 接口的 srcObject 属性设定或返回一个对象,这个对象提供了一个与HTMLMediaElement关联的媒体源,这个对象通常是 MediaStream ,但根据规范可以是 MediaSourceBlob 或者 File
function handleSuccess(stream) 
    recordButton.disabled = false;
    window.stream = stream;
    const gumVideo = document.querySelector('video#gum');
    gumVideo.srcObject = stream;

录制媒体流

  • MediaRecorder() 构造函数会创建一个对指定的 MediaStream 进行录制的 MediaRecorder 对象

  • MediaRecorder.ondataavailable 事件处理程序API处理dataavailable事件,在响应运行代码Blob数据被提供使用。

  • dataavailable当MediaRecorder将媒体数据传递到您的应用程序以供使用时,将触发该事件。数据在包含数据的Blob对象中提供。这在四种情况下发生:

    • 媒体流结束时,所有尚未传递到ondataavailable处理程序的媒体数据都将在单个Blob中传递。

    • 当调用MediaRecorder.stop() (en-US)时,自记录开始或dataavailable事件最后一次发生以来已捕 获的所有媒体数据都将传递到Blob中;此后,捕获结束。

    • 调用MediaRecorder.requestData() (en-US) dataavailable时,将传递自记录开始或事件最后一次发生以来捕获的所有媒体数据;然后Blob创建一个新文件,并将媒体捕获继续到该blob中。

    • 如果将timeslice属性传递到开始媒体捕获的MediaRecorder.start() (en-US)方法中,dataavailable则每timeslice毫秒触发一次事件。这意味着每个Blob都有特定的持续时间(最后一个Blob除外,后者可能更短,因为它将是自上次事件以来剩下的所有东西)。

let mediaRecorder;
const recordButton = document.querySelector('button#record');

recordButton.addEventListener('click', () => 
    if (recordButton.textContent === '开始记录') 
        startRecording();
     else 
        stopRecording();
        recordButton.textContent = '开始记录';
        playButton.disabled = false;
    
);

function startRecording() 
    recordedBlobs = [];
    try 
        mediaRecorder = new MediaRecorder(window.stream);
     catch (e) 
        console.error('创建MediaRecorder时异常:', e);
    
    recordButton.textContent = '停止记录';
    playButton.disabled = true;
    mediaRecorder.ondataavailable = handleDataAvailable;
    mediaRecorder.start();


function stopRecording() 
    mediaRecorder.stop();


function handleDataAvailable(event) 
    if (event.data && event.data.size > 0) 
        recordedBlobs.push(event.data);
    

播放媒体流

  • URL.createObjectURL() 静态方法会创建一个 DOMString,其中包含一个表示参数中给出的对象的URL。这个 URL 的生命周期和创建它的窗口中的 document 绑定。这个新的URL 对象表示指定的 File 对象或 Blob 对象。
let recordedBlobs;
const recordedVideo = document.querySelector('video#recorded');
const playButton = document.querySelector('button#play');

playButton.addEventListener('click', () => 
    const superBuffer = new Blob(recordedBlobs,  type: 'video/webm' );
    recordedVideo.src = null;
    recordedVideo.srcObject = null;
    recordedVideo.src = window.URL.createObjectURL(superBuffer);
    recordedVideo.controls = true;
    recordedVideo.play();
);

HTML

<link rel="stylesheet" href="./index.css">

<video id="gum" autoplay></video>
<video id="recorded"></video>
<div>
    <button id="start">开始</button>
    <button id="record" disabled>开始记录</button>
    <button id="play" disabled>Play</button>
</div>

<script src="./index.js"></script>

CSS

button 
    margin: 0 3px 10px 0;
    padding-left: 2px;
    padding-right: 2px;
    width: 99px;

  
button:last-of-type 
    margin: 0;

  
video 
    vertical-align: top;
    --width: 25vw;
    width: var(--width);
    height: calc(var(--width) * 0.5625);

  
video:last-of-type 
    margin: 0 0 20px 0;

  
video#gumVideo 
    margin: 0 20px 20px 0;

javascript

let mediaRecorder;
let recordedBlobs;

const recordedVideo = document.querySelector('video#recorded');
const recordButton = document.querySelector('button#record');
recordButton.addEventListener('click', () => 
    if (recordButton.textContent === '开始记录') 
        startRecording();
     else 
        stopRecording();
        recordButton.textContent = '开始记录';
        playButton.disabled = false;
    
);

const playButton = document.querySelector('button#play');
playButton.addEventListener('click', () => 
    const superBuffer = new Blob(recordedBlobs,  type: 'video/webm' );
    recordedVideo.src = null;
    recordedVideo.srcObject = null;
    recordedVideo.src = window.URL.createObjectURL(superBuffer);
    recordedVideo.controls = true;
    recordedVideo.play();
);

function handleDataAvailable(event) 
    if (event.data && event.data.size > 0) 
        recordedBlobs.push(event.data);
    


function startRecording() 
    recordedBlobs = [];
    try 
        mediaRecorder = new MediaRecorder(window.stream);
     catch (e) 
        console.error('创建MediaRecorder时异常:', e);
    
    recordButton.textContent = '停止记录';
    playButton.disabled = true;
    mediaRecorder.ondataavailable = handleDataAvailable;
    mediaRecorder.start();


function stopRecording() 
    mediaRecorder.stop();


function handleSuccess(stream) 
    recordButton.disabled = false;
    window.stream = stream;
    const gumVideo = document.querySelector('video#gum');
    gumVideo.srcObject = stream;


async function init(constraints) 
    try 
        const stream = await navigator.mediaDevices.getUserMedia(constraints);
        handleSuccess(stream);
     catch (e) 
        console.error('navigator.getUserMedia error:', e);
    


document.querySelector('button#start').addEventListener('click', async () => 
    document.querySelector('button#start').disabled = true;
    const constraints = 
        audio: ,
        video: 
            width: 1280, height: 720
        
    ;
    await init(constraints);
);

以上是关于web技术分享| WebRTC记录音视频流的主要内容,如果未能解决你的问题,请参考以下文章

web技术分享| WebRTC记录音视频流

web技术分享| webRTC 媒体流录制

web技术分享| webRTC 媒体流录制

web技术分享| 实现WebRTC多个对等连接

web技术分享| 实现WebRTC多个对等连接

谈谈MediaStream