WebRTC - APIs RTCPeerConnection
A API RTCPeerConnection é o núcleo da conexão ponto a ponto entre cada um dos navegadores. Para criar os objetos RTCPeerConnection, basta escrever
var pc = RTCPeerConnection(config);
onde o argumento de configuração contém pelo menos uma chave, iceServers. É uma matriz de objetos de URL que contém informações sobre os servidores STUN e TURN, usados durante a localização dos candidatos ICE. Você pode encontrar uma lista de servidores STUN públicos disponíveis em code.google.com
Dependendo se você é o chamador ou o receptor, o objeto RTCPeerConnection é usado de uma maneira ligeiramente diferente em cada lado da conexão.
Aqui está um exemplo do fluxo do usuário -
Registre o manipulador onicecandidate . Ele envia quaisquer candidatos ICE ao outro par, conforme são recebidos.
Registre o manipulador onaddstream . Ele lida com a exibição do fluxo de vídeo, uma vez que é recebido do par remoto.
Registre o manipulador de mensagens . Seu servidor de sinalização também deve ter um manipulador para mensagens recebidas de outro par. Se a mensagem contiver o objeto RTCSessionDescription , ela deverá ser adicionada ao objeto RTCPeerConnection usando o método setRemoteDescription () . Se a mensagem contiver o objeto RTCIceCandidate , ela deverá ser adicionada ao objeto RTCPeerConnection usando o método addIceCandidate () .
Utilize getUserMedia () para configurar seu fluxo de mídia local e adicioná-lo ao objeto RTCPeerConnection usando o método addStream () .
Inicie o processo de negociação de oferta / resposta. Esta é a única etapa em que o fluxo do chamador é diferente do fluxo do receptor. O chamador inicia a negociação usando o método createOffer () e registra um retorno de chamada que recebe o objeto RTCSessionDescription . Então este callback deve adicionar este RTCSessionDescription objeto para seu RTCPeerConnection objeto usando setLocalDescription () . E, finalmente, o chamador deve enviar esta RTCSessionDescription para o ponto remoto usando o servidor de sinalização. O receptor, por outro lado, registra o mesmo retorno de chamada, mas no método createAnswer () . Observe que o fluxo do receptor é iniciado somente depois que a oferta é recebida do chamador.
API RTCPeerConnection
Propriedades
RTCPeerConnection.iceConnectionState (read only)- Retorna um enum RTCIceConnectionState que descreve o estado da conexão. Um evento iceconnectionstatechange é disparado quando esse valor muda. Os valores possíveis -
new - o agente ICE está esperando por candidatos remotos ou reunindo endereços
checking - o agente ICE tem candidatos remotos, mas ainda não encontrou uma conexão
connected - o agente ICE encontrou uma conexão utilizável, mas ainda está verificando um candidato remoto para uma conexão melhor.
completed - o agente ICE encontrou uma conexão utilizável e parou de testar candidatos remotos.
failed - o agente ICE verificou todos os candidatos remotos, mas não encontrou uma correspondência para pelo menos um componente.
disconnected - pelo menos um componente não está mais ativo.
closed - o agente ICE está fechado.
RTCPeerConnection.iceGatheringState (read only) - Retorna um RTCIceGatheringState enum que descreve o estado de coleta de ICE para a conexão -
new - o objeto acabou de ser criado.
gathering - o agente ICE está em processo de reunir candidatos
complete o agente ICE concluiu a reunião.
RTCPeerConnection.localDescription (read only)- Retorna um RTCSessionDescription que descreve a sessão local. Pode ser nulo se ainda não tiver sido definido.
RTCPeerConnection.peerIdentity (read only)- Retorna um RTCIdentityAssertion. Consiste em um idp (nome de domínio) e um nome que representa a identidade do par remoto.
RTCPeerConnection.remoteDescription (read only)- Retorne um RTCSessionDescription descrevendo a sessão remota. Pode ser nulo se ainda não tiver sido definido.
RTCPeerConnection.signalingState (read only)- Retorna um enum RTCSignalingState que descreve o estado de sinalização da conexão local. Este estado descreve a oferta SDP. Um evento signalingstatechange é disparado quando esse valor muda. Os valores possíveis -
stable- O estado inicial. Não há nenhuma troca de oferta / resposta SDP em andamento.
have-local-offer - o lado local da conexão aplicou localmente uma oferta SDP.
have-remote-offer - o lado remoto da conexão aplicou localmente uma oferta SDP.
have-local-pranswer - uma oferta SDP remota foi aplicada e uma pranswer SDP aplicada localmente.
have-remote-pranswer - um SDP local foi aplicado e uma pranswer SDP aplicada remotamente.
closed - a conexão é fechada.
Manipuladores de eventos
S.No. | Manipuladores de eventos e descrição |
---|---|
1 | RTCPeerConnection.onaddstream Este manipulador é chamado quando o evento addstream é disparado. Este evento é enviado quando um MediaStream é adicionado a esta conexão pelo par remoto. |
2 | RTCPeerConnection.ondatachannel Este manipulador é chamado quando o evento datachannel é disparado. Este evento é enviado quando um RTCDataChannel é adicionado a esta conexão. |
3 | RTCPeerConnection.onicecandidate Este manipulador é chamado quando o evento icecandidate é disparado. Este evento é enviado quando um objeto RTCIceCandidate é adicionado ao script. |
4 | RTCPeerConnection.oniceconnectionstatechange Este manipulador é chamado quando o evento iceconnectionstatechange é disparado. Este evento é enviado quando o valor de iceConnectionState muda. |
5 | RTCPeerConnection.onidentityresult Este manipulador é chamado quando o evento identityresult é disparado. Este evento é enviado quando uma asserção de identidade é gerada durante a criação de uma oferta ou uma resposta de via getIdentityAssertion (). |
6 | RTCPeerConnection.onidpassertionerror Este manipulador é chamado quando o evento idpassertionerror é disparado. Este evento é enviado quando o IdP (Provedor de Identidade) encontra um erro ao gerar uma declaração de identidade. |
7 | RTCPeerConnection.onidpvalidation Este manipulador é chamado quando o evento idpvalidationerror é disparado. Este evento é enviado quando o IdP (Identitry Provider) encontra um erro ao validar uma declaração de identidade. |
8 | RTCPeerConnection.onnegotiationneeded Este manipulador é chamado quando o evento negotiationneeded é disparado. Este evento é enviado pelo navegador para informar que a negociação será necessária em algum momento no futuro. |
9 | RTCPeerConnection.onpeeridentity Este manipulador é chamado quando o evento peeridentity é disparado. Este evento é enviado quando uma identidade de par foi definida e verificada nesta conexão. |
10 | RTCPeerConnection.onremovestream Esse manipulador é chamado quando o evento signalingstatechange é disparado. Este evento é enviado quando o valor de signalingState muda. |
11 | RTCPeerConnection.onsignalingstatechange Este manipulador é chamado quando o evento removestream é disparado. Este evento é enviado quando um MediaStream é removido desta conexão. |
Métodos
S.No. | Métodos e Descrição |
---|---|
1 | RTCPeerConnection() Retorna um novo objeto RTCPeerConnection. |
2 | RTCPeerConnection.createOffer() Cria uma oferta (solicitação) para encontrar um par remoto. Os dois primeiros parâmetros desse método são callbacks de sucesso e erro. O terceiro parâmetro opcional são opções, como habilitar fluxos de áudio ou vídeo. |
3 | RTCPeerConnection.createAnswer() Cria uma resposta à oferta recebida pelo par remoto durante o processo de negociação de oferta / resposta. Os dois primeiros parâmetros desse método são callbacks de sucesso e erro. O terceiro parâmetro opcional são opções para a resposta a ser criada. |
4 | RTCPeerConnection.setLocalDescription() Altera a descrição da conexão local. A descrição define as propriedades da conexão. A conexão deve ser capaz de suportar descrições antigas e novas. O método usa três parâmetros, objeto RTCSessionDescription, retorno de chamada se a alteração da descrição for bem-sucedida, retorno de chamada se a alteração da descrição falhar. |
5 | RTCPeerConnection.setRemoteDescription() Altera a descrição da conexão remota. A descrição define as propriedades da conexão. A conexão deve ser capaz de suportar descrições antigas e novas. O método usa três parâmetros, objeto RTCSessionDescription, retorno de chamada se a alteração da descrição for bem-sucedida, retorno de chamada se a alteração da descrição falhar. |
6 | RTCPeerConnection.updateIce() Atualiza o processo do agente ICE de fazer ping de candidatos remotos e reunir candidatos locais. |
7 | RTCPeerConnection.addIceCandidate() Fornece um candidato remoto para o agente ICE. |
8 | RTCPeerConnection.getConfiguration() Retorna um objeto RTCConfiguration. Ele representa a configuração do objeto RTCPeerConnection. |
9 | RTCPeerConnection.getLocalStreams() Retorna uma matriz de conexão MediaStream local. |
10 | RTCPeerConnection.getRemoteStreams() Retorna uma matriz de conexão MediaStream remota. |
11 | RTCPeerConnection.getStreamById() Retorna MediaStream local ou remoto pelo ID fornecido. |
12 | RTCPeerConnection.addStream() Adiciona um MediaStream como fonte local de vídeo ou áudio. |
13 | RTCPeerConnection.removeStream() Remove um MediaStream como fonte local de vídeo ou áudio. |
14 | RTCPeerConnection.close() Fecha uma conexão. |
15 | RTCPeerConnection.createDataChannel() Cria um novo RTCDataChannel. |
16 | RTCPeerConnection.createDTMFSender() Cria um novo RTCDTMFSender, associado a um MediaStreamTrack específico. Permite enviar sinalização de telefone DTMF (Dual-tone multifrequency) pela conexão. |
17 | RTCPeerConnection.getStats() Cria um novo RTCStatsReport que contém estatísticas sobre a conexão. |
18 | RTCPeerConnection.setIdentityProvider() Define o IdP. Aceita três parâmetros - o nome, o protocolo usado para se comunicar e um nome de usuário opcional. |
19 | RTCPeerConnection.getIdentityAssertion() Reúne uma afirmação de identidade. Não se espera lidar com esse método no aplicativo. Portanto, você pode chamá-lo explicitamente apenas para antecipar a necessidade. |
Estabelecendo uma conexão
Agora vamos criar um aplicativo de exemplo. Em primeiro lugar, execute o servidor de sinalização que criamos no tutorial “servidor de sinalização” via “servidor de nó”.
Haverá duas entradas de texto na página, uma para um login e outra para um nome de usuário ao qual desejamos nos conectar. Crie um arquivo index.html e adicione o seguinte código -
<html lang = "en">
<head>
<meta charset = "utf-8" />
</head>
<body>
<div>
<input type = "text" id = "loginInput" />
<button id = "loginBtn">Login</button>
</div>
<div>
<input type = "text" id = "otherUsernameInput" />
<button id = "connectToOtherUsernameBtn">Establish connection</button>
</div>
<script src = "client2.js"></script>
</body>
</html>
Você pode ver que adicionamos a entrada de texto para um login, o botão de login, a entrada de texto para o outro nome de usuário do par e o botão conectar-se a ele. Agora crie um arquivo client.js e adicione o seguinte código -
var connection = new WebSocket('ws://localhost:9090');
var name = "";
var loginInput = document.querySelector('#loginInput');
var loginBtn = document.querySelector('#loginBtn');
var otherUsernameInput = document.querySelector('#otherUsernameInput');
var connectToOtherUsernameBtn = document.querySelector('#connectToOtherUsernameBtn');
var connectedUser, myConnection;
//when a user clicks the login button
loginBtn.addEventListener("click", function(event){
name = loginInput.value;
if(name.length > 0){
send({
type: "login",
name: name
});
}
});
//handle messages from the server
connection.onmessage = function (message) {
console.log("Got message", message.data);
var data = JSON.parse(message.data);
switch(data.type) {
case "login":
onLogin(data.success);
break;
case "offer":
onOffer(data.offer, data.name);
break;
case "answer":
onAnswer(data.answer);
break;
case "candidate":
onCandidate(data.candidate);
break;
default:
break;
}
};
//when a user logs in
function onLogin(success) {
if (success === false) {
alert("oops...try a different username");
} else {
//creating our RTCPeerConnection object
var configuration = {
"iceServers": [{ "url": "stun:stun.1.google.com:19302" }]
};
myConnection = new webkitRTCPeerConnection(configuration);
console.log("RTCPeerConnection object was created");
console.log(myConnection);
//setup ice handling
//when the browser finds an ice candidate we send it to another peer
myConnection.onicecandidate = function (event) {
if (event.candidate) {
send({
type: "candidate",
candidate: event.candidate
});
}
};
}
};
connection.onopen = function () {
console.log("Connected");
};
connection.onerror = function (err) {
console.log("Got error", err);
};
// Alias for sending messages in JSON format
function send(message) {
if (connectedUser) {
message.name = connectedUser;
}
connection.send(JSON.stringify(message));
};
Você pode ver que estabelecemos uma conexão de socket com nosso servidor de sinalização. Quando um usuário clica no botão de login, o aplicativo envia seu nome de usuário para o servidor. Se o login for bem-sucedido, o aplicativo cria o objeto RTCPeerConnection e configura o manipulador onicecandidate que envia todos os icecandidates encontrados para o outro par. Agora abra a página e tente fazer o login. Você deve ver a seguinte saída do console -
A próxima etapa é criar uma oferta para o outro par. Adicione o seguinte código ao seu arquivo client.js -
//setup a peer connection with another user
connectToOtherUsernameBtn.addEventListener("click", function () {
var otherUsername = otherUsernameInput.value;
connectedUser = otherUsername;
if (otherUsername.length > 0) {
//make an offer
myConnection.createOffer(function (offer) {
console.log();
send({
type: "offer",
offer: offer
});
myConnection.setLocalDescription(offer);
}, function (error) {
alert("An error has occurred.");
});
}
});
//when somebody wants to call us
function onOffer(offer, name) {
connectedUser = name;
myConnection.setRemoteDescription(new RTCSessionDescription(offer));
myConnection.createAnswer(function (answer) {
myConnection.setLocalDescription(answer);
send({
type: "answer",
answer: answer
});
}, function (error) {
alert("oops...error");
});
}
//when another user answers to our offer
function onAnswer(answer) {
myConnection.setRemoteDescription(new RTCSessionDescription(answer));
}
//when we got ice candidate from another user
function onCandidate(candidate) {
myConnection.addIceCandidate(new RTCIceCandidate(candidate));
}
Você pode ver que quando um usuário clica no botão “Estabelecer conexão”, o aplicativo faz uma oferta SDP ao outro par. Nós também definir onAnswer e onCandidate manipuladores. Recarregue a sua página, abra-a em duas abas, faça o login com dois usuários e tente estabelecer uma conexão entre eles. Você deve ver a seguinte saída do console -
Agora a conexão ponto a ponto foi estabelecida. Nos próximos tutoriais, adicionaremos streams de vídeo e áudio, bem como suporte para chat de texto.