12/08/2018, 00:06

Giới thiệu về WebRTC

WebRTC là một tập hợp các API viết bằng javascript, cho phép các trình duyệt giao tiếp với nhau theo thời gian thực. Các lập trình viên mặc dù rất thích thú với khả năng đáng kinh ngạc của WebRTC , họ vẫn cảm thấy khó khăn trong việc làm quen với nó, ngay cả trong việc nắm bắt những kiến thức cơ ...

WebRTC là một tập hợp các API viết bằng javascript, cho phép các trình duyệt giao tiếp với nhau theo thời gian thực. Các lập trình viên mặc dù rất thích thú với khả năng đáng kinh ngạc của WebRTC, họ vẫn cảm thấy khó khăn trong việc làm quen với nó, ngay cả trong việc nắm bắt những kiến thức cơ bản, bởi vì nó đưa ra một lượng hàm APIs và giao thức mới rất đa dạng. Bài viết này sẽ giải thích và giúp bạn tạo ra một ứng dụng WebRTC đơn giản (có thể coi là WebRTC helloworld).

Các khái niệm cơ bản

Trước khi bắt tay vào code, chúng ta sẽ nhìn qua những hàm APIs làm lên WebRTC. Mặc dù chúng hơi trừu tượng, nhưng chúng ta sẽ nhanh chóng chuyển qua ví dụ cụ thể.

MediaStream

Một MediaStream là một stream dữ liệu âm thanh và/hoặc hình ảnh. Khi làm việc cục bộ, stream này được khởi tạo bằng cách gọi hàm getUserMedia. Sau khi một kết nối WebRTC tới một máy tính khác được thiết lập, chúng ta có khả năng truy cập vào stream của máy tính đó.

Đây là một ví dụ đơn giản của hàm getUserMedia

 <!DOCTYPE html>
<html>
  <head><title>getUserMedia</title></head>
  <body>
    <video autoplay></video>

    <script>
      navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;

      var constraints = { audio: false, video: true };
      var video = document.querySelector("video");

      function successCallback(stream) {
        video.src = window.URL.createObjectURL(stream);
      }

      function errorCallback(error){
        console.log("getUserMedia error: ", error);
      }

      navigator.getUserMedia(constraints, successCallback, errorCallback);
    </script>
  </body>
</html>

RTCDataChannel

RTCDataChannel là một kênh hai chiều để gửi dữ liệu bất kỳ qua kết nối WebRTC. Nó hoạt động tương tự web sockets,nhưng dữ liệu được truyền tải trực tiếp giữa hai trình duyệt, và nó cho phép trao đổi thông tin nhanh và đáng tin cậy (giống như giữa UDPTCP). Đây là một ví dụ đơn giản.

RTCPeerConnection

RTCPeerConnection là API đóng vai trò kết nối Media StreamRTCDataChannel để trở thành WebRTC. RTCPeerConnection cung cấp một hàm API làm nhiệm vụ hoàn thành giao ước giữa hai trình duyệt. Trong suốt quá trình giao ước này, các trình duyệt cung cấp các thông tin cần thiết để thiết lập kết nối: mô tả của phiên làm việc (những tính năng của trình duyệt) và các ứng viên ICE (thông tin về cổng và địa chỉ IP công cộng). Cần lưu ý rằng mô tả của WebRTC không nói gì về cách thức những thông tin này được trao đổi.

Các bước cơ bản là:

  1. Trình duyệt nguồn tạo ra một yêu cầu cùng với đặc tả về phiên làm việc.
  2. Trình duyệt đích nhận yêu cầu và tạo ra một hồi đáp cùng với đặc tả về phiên làm việc.
  3. Trình duyệt nguồn nhận hồi đáp.
  4. Cả hai trình duyệt trao đổi các ứng viên ICE.
  5. Khi một lượng ứng viên được trao đổi đủ cho một kết nối trực tiếp thì kết nối ngang hàng được thiết lập.

Một ví dụ đơn giản

Chúng ta sẽ xây dựng một ứng dụng video chat với backend là Rails framework, nhưng bởi vì vai trò của thành phần backend trong hệ thống của chúng ta không đáng kể nên bạn có thể dùng bất cứ framework nào khác.

Chúng ta sẽ tạo kết nối với ai?

Chúng ta cần có một trình duyệt đích để tạo kết nối đến. May mắn thay, Pusher's presence channels sẽ giúp ta điều đó. Bước đầu tiên là đăng ký một tài khoản Pusher. Gói Pusher miễn phí cũng đủ để ứng dụng của ta chạy. Khi bạn đăng ký xong, hãy lưu lại id, key và secret của bạn. Và tại trang settings của Pusher app, bạn hãy chắc chắn là đã bật client events, chúng ta sẽ cần đến nó sau này.

Để sử dụng presence channels, Pusher yêu cầu chứng thực từ các clients. Chúng ta sẽ sử dụng id và các thông tin cần thiết dể Pusher xác minh identity của client. Quá trình này chỉ nằm ở bên backend của hệ thống:

#pusher_controller.rb
class PusherController < ApplicationController
  protect_from_forgery except: :auth

  def auth
    response = Pusher[params[:channel_name]].authenticate params[:socket_id],
      user_id: params[:id],
      user_info: { name: params[:name] }

    render json: response
  end
end
#pusher_initializer.rb
Pusher.app_id = 'YOUR_APP_ID'
Pusher.key = 'YOUR_APP_KEY'
Pusher.secret = 'YOUR_APP_SECRET'
#routes.rb
match '/pusher/auth' => 'pusher#auth', via: :post
//whos_there.js
var currentUser = {
  name: 'Tommy',
  id: 42
};

var pusher = new Pusher('YOUR_PUSHER_KEY', {
  authEndpoint: '/pusher/auth',
  auth: {
    params: currentUser
  }
});

var channel = pusher.subscribe('presence-chat');

channel.bind('pusher:subscription_succeeded', function() {
  console.log('Channel members:', channel.members);
});

Để cho đơn giản, chúng ta cho phép client thiết lập tên và user id. Trong hệ thống thực, ta nên sử dụng các chứng thư đã được xác thực. Lý do là Pusher secret chỉ tồn tại trên server (và đã được chứng thực) nên client không thể giả mạo identity của nó.

Tạo ra yêu cầu

Sau khi đã thiết lập đối tượng kết nối đến, chúng ta cần thiết lập RTCPeerConnection để tạo một lời gọi. Thay vì sử dụng các hàm APIs trực tiếp, chúng ta sẽ sử dụng simple-peer. SimplerPeer giúp quản lý quá trình thiết lập giao ước. Đây là một ví dụ, hai đối tượng kết nối với nhau trong cùng một trình duyệt.

//local-peer.js
var peer1 = new SimplePeer({ initiator: true });
var peer2 = new SimplePeer();

peer1.on('signal', function (data) {
  // when peer1 has signaling data, give it to peer2
  peer2.signal(data);
});

peer2.on('signal', function (data) {
  // same as above, but in reverse
  peer1.signal(data);
});

peer1.on('ready', function () {
  // wait for 'ready' event before using the data channel
  peer1.send('hey peer2, how is it going?')
});

peer2.on('message', function (data) {
  // got a data channel message
  console.log('got a message from peer1: ' + data);
});

Chúng ta tạo ra hai đối tượng và chỉ rõ rằng một trong số đó là đối tượng khởi tạo (đối tượng sẽ tạo ra yêu cầu trong bước 1 của quá trình giao ước). Sau đó, chúng ta chờ tín hiệu của các đối tượng. Khi có tín hiệu, chúng ta truyền các tín hiệu đó cho đối tượng còn lại. Khi kết nối ngang hàng sẵn sàng chúng ta có thể gửi dữ liệu qua lại giữa các đối tượng.

Để áp dụng ví dụ trên vào hệ thống, chúng ta cần cách để gửi các tin nhắn tín hiệu đến đối tượng từ xa. Chúng ta có thể nâng cấp Pusher channel hiện tại để làm điều đó. Mỗi client sẽ lắng nghe các sự kiện được kích hoạt đến user id của nó, và khi cần gửi các tin nhắn tín hiệu, chúng ta sẽ sử dụng sự kiện thích hợp:

//remote-peer-initiator.js
var peer = new SimplePeer({ initiator: true });

peer.on('signal', function (data) {
  channel.trigger('client-signal-' + peerUserId, { userId: currentUser.id, data: data });
});

peer.on('ready', function () {
  peer.send('hey peer, how is it going?')
});
//remote-peer-recipient.js
var peer = undefined;
channel.bind('client-signal-' + currentUser.id, function(signal) {
  if (peer === undefined) {
    peer = new SimplePeer();

    peer.on('signal', function (data) {
      channel.trigger('client-signal-' + signal.userId, { userId: currentUser.id, data: data });
    });

    peer.on('message', function (data) {
      console.log('got a message from remote peer: ' + data);
    });
  }

  peer.signal(signal.data)
});

Đối tượng khởi tạo của lời gọi thiết lập một SimplePeer mới và gửi tin nhắn tín hiệu thông qua channel dùng chung đến địa chỉ mong muốn. Đối tượng nhận lời gọi khi nhận được tín hiệu đầu tiên sẽ thiếp lập một SimplePeer mới và bắt đầu việc gửi các tin nhắn tín hiệu trả lại cho đối tượng khởi tạo.

Thêm kết nối video

//video.js
navigator.getUserMedia({ video: true, audio: true }, function(stream) {
  currentUser.stream = stream;
}, function() {});

// ...

peer = new SimplePeer({ stream: currentUser.stream });

peer.on('stream', function(stream) {
  var video = document.querySelector("video");
  video.src = window.URL.createObjectURL(stream);
});

Chúng ta gọi getUserMedia và lưu stream nó trả về. Khi chúng ta khởi tạo SimplePeer, chúng ta truyền cho nó local stream, và sau đó là thiết lập xử lý cho sự kiện stream, nó sẽ được gọi khi nó nhận được remote stream.

Chúng ta vừa mới thực hiện hầu hết những phần quan trọng của WebRTC. Đây là demo được xây dựng từ những ví dụ trên thành một ứng dụng như là một phòng Google Hangout (đây là mã nguồn trên GitHub)

Một vài suy nghĩ

WebRTC là một công nghệ mạnh mẽ, mở ra hướng giải quyết cho rất nhiều ứng dụng mà trước đây không thể thực hiện được. WebRTC thực sự là công nghệ mang tính chất thay đổi cuộc chơi. Mặc dù hiện tại chỉ có Chrome, Firefox và Opera trên desktop , và Chrome cho Android trên di động hỗ trợ WebRTC, nhưng Microsoft đã tuyên bố họ sẽ mang WebRTC lên IE trong tương lai.

nguồn:

http://blog.carbonfive.com/2014/10/16/webrtc-made-simple/ http://www.theinquirer.net/inquirer/news/2378113/microsoft-confirms-it-will-bring-skype-webrtc-to-internet-explorer http://www.html5rocks.com/en/tutorials/webrtc/basics/

0