WebRTC API :

概述:

1)媒体捕获设备包括摄像机和麦克风,还包括屏幕捕获“设备”。对于相机和麦克风,我们使用navigator.mediaDevices.getUserMedia()捕获MediaStreams 。对于屏幕录制,我们改用navigator.mediaDevices.getDisplayMedia() 。

const constraints = {
    'video': true,
    'audio': true
}
navigator.mediaDevices.getUserMedia(constraints)
    .then(stream => {
        console.log('Got MediaStream:', stream);
    })
    .catch(error => {
        console.error('Error accessing media devices.', error);
    });
function getConnectedDevices(type, callback) {
    navigator.mediaDevices.enumerateDevices()
        .then(devices => {
            const filtered = devices.filter(device => device.kind === type);
            callback(filtered);
        });
}

getConnectedDevices('videoinput', cameras => console.log('Cameras found', cameras));

2)确定某个媒体流的特定轨道的实际配置,我们可以调用MediaStreamTrack.getSettings()来返回当前应用的MediaTrackSettings 

3)getDisplayMedia()的约束与用于常规视频或音频输入的约束不同:

{
    video: {
        cursor: 'always' | 'motion' | 'never',
        displaySurface: 'application' | 'browser' | 'monitor' | 'window'
    }
}

4)启动对等连接:

async function makeCall() {
    const configuration = {'iceServers': [{'urls': 'stun:stun.l.google.com:19302'}]}
    const peerConnection = new RTCPeerConnection(configuration);
    signalingChannel.addEventListener('message', async message => {
        if (message.answer) {
            const remoteDesc = new RTCSessionDescription(message.answer);
            await peerConnection.setRemoteDescription(remoteDesc);
        }
    });
    const offer = await peerConnection.createOffer();
    await peerConnection.setLocalDescription(offer);
    signalingChannel.send({'offer': offer});
const peerConnection = new RTCPeerConnection(configuration);
signalingChannel.addEventListener('message', async message => {
    if (message.offer) {
        peerConnection.setRemoteDescription(new RTCSessionDescription(message.offer));
        const answer = await peerConnection.createAnswer();
        await peerConnection.setLocalDescription(answer);
        signalingChannel.send({'answer': answer});
    }
});

5)ICE candidate 操作:

peerConnection.addEventListener('icecandidate', event => {
    if (event.candidate) {
        signalingChannel.send({'new-ice-candidate': event.candidate});
    }
});

// Listen for remote ICE candidates and add them to the local RTCPeerConnection
signalingChannel.addEventListener('message', async message => {
    if (message.iceCandidate) {
        try {
            await peerConnection.addIceCandidate(message.iceCandidate);
        } catch (e) {
            console.error('Error adding received ice candidate', e);
        }
    }
});

RTCPeerConnection 接口代表一个由本地计算机到远端的WebRTC连接。该接口提供了创建,保持,监控,关闭连接的方法的实现。

var PeerConnection = window.RTCPeerConnection  || window.webkitRTCPeerConnection;
var SessionDescription = window.RTCSessionDescription 
var GET_USER_MEDIA = navigator.getUserMedia

一旦收到ICE候选者,我们应该期望对等连接的状态最终将变为已连接状态。为了检测到这一点,我们在RTCPeerConnection中添加了一个侦听器,在此我们侦听connectionstatechange事件。

// Listen for connectionstatechange on the local RTCPeerConnection
peerConnection.addEventListener('connectionstatechange', event => {
    if (peerConnection.connectionState === 'connected') {
        // Peers connected!
    }
});

远程流:

6)我们在本地RTCPeerConnection上注册了一个侦听器,以监听track事件。由于回放是在MediaStream对象上完成的,因此我们首先创建一个空实例,然后在接收到它们时使用来自远程对等方的轨道进行填充。 

const remoteStream = MediaStream();
const remoteVideo = document.querySelector('#remoteVideo');
remoteVideo.srcObject = remoteStream;

peerConnection.addEventListener('track', async (event) => {
    remoteStream.addTrack(event.track, remoteStream);
});

7)数据通道:

远程对等方可以通过侦听RTCPeerConnection对象上的datachannel事件来接收数据通道。接收到的事件的类型为RTCDataChannelEvent并包含一个channel属性,该属性表示对等体之间连接的RTCDataChannel 。

const peerConnection = new RTCPeerConnection(configuration);
const dataChannel = peerConnection.createDataChannel();

远程对等方可以通过侦听RTCPeerConnection对象上的datachannel事件来接收数据通道。接收到的事件的类型为RTCDataChannelEvent并包含一个channel属性,该属性表示对等体之间连接的RTCDataChannel。

const peerConnection = new RTCPeerConnection(configuration);
peerConnection.addEventListener('datachannel', event => {
    const dataChannel = event.channel;
});

8)打开和关闭事件: 

const messageBox = document.querySelector('#messageBox');
const sendButton = document.querySelector('#sendButton');
const peerConnection = new RTCPeerConnection(configuration);
const dataChannel = peerConnection.createDataChannel();

// Enable textarea and button when opened
dataChannel.addEventListener('open', event => {
    messageBox.disabled = false;
    messageBox.focus();
    sendButton.disabled = false;
});

// Disable input when closed
dataChannel.addEventListener('close', event => {
    messageBox.disabled = false;
    sendButton.disabled = false;
});

9)留言内容:

const messageBox = document.querySelector('#messageBox');
const sendButton = document.querySelector('#sendButton');

// Send a simple text message when we click the button
sendButton.addEventListener('click', event => {
    const message = messageBox.textContent;
    dataChannel.send(message);
}

远程对等方将通过侦听message事件来接收在RTCDataChannelmessage :

const incomingMessages = document.querySelector('#incomingMessages');

const peerConnection = new RTCPeerConnection(configuration);
const dataChannel = peerConnection.createDataChannel();

// Append new messages to the box of incoming messages
dataChannel.addEventListener('message', event => {
    const message = event.data;
    incomingMessages.textContent += message + '\n';
});

10)TURN服务器 

需要服务器来中继对等方之间的流量,因为在客户端之间通常不可能使用直接套接字(除非它们驻留在同一本地网络上):

const iceConfiguration = {
    iceServers: [
        {
            urls: 'turn:my-turn-server.mycompany.com:19403',
            username: 'optional-username',
            credentials: 'auth-token'
        }
    ]
}

const peerConnection = new RTCPeerConnection(iceConfiguration);

https://github.com/webrtc 

https://developer.mozilla.org/zh-CN/docs/Web/API/WebRTC_API

https://webrtc.org/getting-started/data-channels

猜你喜欢

转载自blog.csdn.net/abc1231987/article/details/118707212